diff --git a/libavformat/file.c b/libavformat/file.c index c689e04e48..407540c706 100644 --- a/libavformat/file.c +++ b/libavformat/file.c @@ -23,6 +23,7 @@ #include "libavutil/internal.h" #include "libavutil/opt.h" #include "avformat.h" +#include #include #if HAVE_IO_H #include @@ -51,6 +52,7 @@ typedef struct FileContext { int fd; int trunc; int blocksize; + DIR *dir; } FileContext; static const AVOption file_options[] = { @@ -225,6 +227,88 @@ static int file_close(URLContext *h) return close(c->fd); } +static int file_open_dir(URLContext *h) +{ + FileContext *c = h->priv_data; + + c->dir = opendir(h->filename); + if (!c->dir) + return AVERROR(errno); + + return 0; +} + +static int file_read_dir(URLContext *h, AVIODirEntry **next) +{ + FileContext *c = h->priv_data; + struct dirent *dir; + char *fullpath = NULL; + + *next = ff_alloc_dir_entry(); + if (!*next) + return AVERROR(ENOMEM); + do { + errno = 0; + dir = readdir(c->dir); + if (!dir) { + av_freep(next); + return AVERROR(errno); + } + } while (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, "..")); + + fullpath = av_append_path_component(h->filename, dir->d_name); + if (fullpath) { + struct stat st; + if (!stat(fullpath, &st)) { + (*next)->group_id = st.st_gid; + (*next)->user_id = st.st_uid; + (*next)->size = st.st_size; + (*next)->filemode = st.st_mode & 0777; + (*next)->modification_timestamp = INT64_C(1000000) * st.st_mtime; + (*next)->access_timestamp = INT64_C(1000000) * st.st_atime; + (*next)->status_change_timestamp = INT64_C(1000000) * st.st_ctime; + } + av_free(fullpath); + } + + (*next)->name = av_strdup(dir->d_name); + switch (dir->d_type) { + case DT_FIFO: + (*next)->type = AVIO_ENTRY_NAMED_PIPE; + break; + case DT_CHR: + (*next)->type = AVIO_ENTRY_CHARACTER_DEVICE; + break; + case DT_DIR: + (*next)->type = AVIO_ENTRY_DIRECTORY; + break; + case DT_BLK: + (*next)->type = AVIO_ENTRY_BLOCK_DEVICE; + break; + case DT_REG: + (*next)->type = AVIO_ENTRY_FILE; + break; + case DT_LNK: + (*next)->type = AVIO_ENTRY_SYMBOLIC_LINK; + break; + case DT_SOCK: + (*next)->type = AVIO_ENTRY_SOCKET; + break; + case DT_UNKNOWN: + default: + (*next)->type = AVIO_ENTRY_UNKNOWN; + break; + } + return 0; +} + +static int file_close_dir(URLContext *h) +{ + FileContext *c = h->priv_data; + closedir(c->dir); + return 0; +} + URLProtocol ff_file_protocol = { .name = "file", .url_open = file_open, @@ -238,6 +322,9 @@ URLProtocol ff_file_protocol = { .url_move = file_move, .priv_data_size = sizeof(FileContext), .priv_data_class = &file_class, + .url_open_dir = file_open_dir, + .url_read_dir = file_read_dir, + .url_close_dir = file_close_dir, }; #endif /* CONFIG_FILE_PROTOCOL */