diff options
Diffstat (limited to 'libavformat/file.c')
-rw-r--r-- | libavformat/file.c | 217 |
1 files changed, 207 insertions, 10 deletions
diff --git a/libavformat/file.c b/libavformat/file.c index 8683c1bedd..264542a36a 100644 --- a/libavformat/file.c +++ b/libavformat/file.c @@ -2,20 +2,20 @@ * buffered file I/O * Copyright (c) 2001 Fabrice Bellard * - * This file is part of Libav. + * This file is part of FFmpeg. * - * Libav is free software; you can redistribute it and/or + * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * - * Libav is distributed in the hope that it will be useful, + * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with Libav; if not, write to the Free Software + * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ @@ -23,6 +23,9 @@ #include "libavutil/internal.h" #include "libavutil/opt.h" #include "avformat.h" +#if HAVE_DIRENT_H +#include <dirent.h> +#endif #include <fcntl.h> #if HAVE_IO_H #include <io.h> @@ -35,6 +38,32 @@ #include "os_support.h" #include "url.h" +/* Some systems may not have S_ISFIFO */ +#ifndef S_ISFIFO +# ifdef S_IFIFO +# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +# else +# define S_ISFIFO(m) 0 +# endif +#endif + +/* Not available in POSIX.1-1996 */ +#ifndef S_ISLNK +# ifdef S_IFLNK +# define S_ISLNK(m) (((m) & S_IFLNK) == S_IFLNK) +# else +# define S_ISLNK(m) 0 +# endif +#endif + +/* Not available in POSIX.1-1996 */ +#ifndef S_ISSOCK +# ifdef S_IFSOCK +# define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) +# else +# define S_ISSOCK(m) 0 +# endif +#endif /* standard file protocol */ @@ -42,15 +71,25 @@ typedef struct FileContext { const AVClass *class; int fd; int trunc; + int blocksize; int follow; +#if HAVE_DIRENT_H + DIR *dir; +#endif } FileContext; static const AVOption file_options[] = { - { "truncate", "Truncate existing files on write", offsetof(FileContext, trunc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM }, + { "truncate", "truncate existing files on write", offsetof(FileContext, trunc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM }, + { "blocksize", "set I/O operation maximum block size", offsetof(FileContext, blocksize), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, { "follow", "Follow a file as it is being written", offsetof(FileContext, follow), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_DECODING_PARAM }, { NULL } }; +static const AVOption pipe_options[] = { + { "blocksize", "set I/O operation maximum block size", offsetof(FileContext, blocksize), AV_OPT_TYPE_INT, { .i64 = INT_MAX }, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM }, + { NULL } +}; + static const AVClass file_class = { .class_name = "file", .item_name = av_default_item_name, @@ -58,10 +97,19 @@ static const AVClass file_class = { .version = LIBAVUTIL_VERSION_INT, }; +static const AVClass pipe_class = { + .class_name = "pipe", + .item_name = av_default_item_name, + .option = pipe_options, + .version = LIBAVUTIL_VERSION_INT, +}; + static int file_read(URLContext *h, unsigned char *buf, int size) { FileContext *c = h->priv_data; - int ret = read(c->fd, buf, size); + int ret; + size = FFMIN(size, c->blocksize); + ret = read(c->fd, buf, size); if (ret == 0 && c->follow) return AVERROR(EAGAIN); return (ret == -1) ? AVERROR(errno) : ret; @@ -70,7 +118,9 @@ static int file_read(URLContext *h, unsigned char *buf, int size) static int file_write(URLContext *h, const unsigned char *buf, int size) { FileContext *c = h->priv_data; - int ret = write(c->fd, buf, size); + int ret; + size = FFMIN(size, c->blocksize); + ret = write(c->fd, buf, size); return (ret == -1) ? AVERROR(errno) : ret; } @@ -82,15 +132,67 @@ static int file_get_handle(URLContext *h) static int file_check(URLContext *h, int mask) { + int ret = 0; + const char *filename = h->filename; + av_strstart(filename, "file:", &filename); + + { +#if HAVE_ACCESS && defined(R_OK) + if (access(filename, F_OK) < 0) + return AVERROR(errno); + if (mask&AVIO_FLAG_READ) + if (access(filename, R_OK) >= 0) + ret |= AVIO_FLAG_READ; + if (mask&AVIO_FLAG_WRITE) + if (access(filename, W_OK) >= 0) + ret |= AVIO_FLAG_WRITE; +#else struct stat st; - int ret = stat(h->filename, &st); +# ifndef _WIN32 + ret = stat(filename, &st); +# else + ret = win32_stat(filename, &st); +# endif if (ret < 0) return AVERROR(errno); ret |= st.st_mode&S_IRUSR ? mask&AVIO_FLAG_READ : 0; ret |= st.st_mode&S_IWUSR ? mask&AVIO_FLAG_WRITE : 0; +#endif + } + return ret; +} + +static int file_delete(URLContext *h) +{ +#if HAVE_UNISTD_H + int ret; + const char *filename = h->filename; + av_strstart(filename, "file:", &filename); + + ret = rmdir(filename); + if (ret < 0 && errno == ENOTDIR) + ret = unlink(filename); + if (ret < 0) + return AVERROR(errno); return ret; +#else + return AVERROR(ENOSYS); +#endif /* HAVE_UNISTD_H */ +} + +static int file_move(URLContext *h_src, URLContext *h_dst) +{ + const char *filename_src = h_src->filename; + const char *filename_dst = h_dst->filename; + av_strstart(filename_src, "file:", &filename_src); + av_strstart(filename_dst, "file:", &filename_dst); + + if (rename(filename_src, filename_dst) < 0) + return AVERROR(errno); + + return 0; } #if CONFIG_FILE_PROTOCOL @@ -100,6 +202,7 @@ static int file_open(URLContext *h, const char *filename, int flags) FileContext *c = h->priv_data; int access; int fd; + struct stat st; av_strstart(filename, "file:", &filename); @@ -121,6 +224,9 @@ static int file_open(URLContext *h, const char *filename, int flags) if (fd == -1) return AVERROR(errno); c->fd = fd; + + h->is_streamed = !fstat(fd, &st) && S_ISFIFO(st.st_mode); + return 0; } @@ -132,9 +238,8 @@ static int64_t file_seek(URLContext *h, int64_t pos, int whence) if (whence == AVSEEK_SIZE) { struct stat st; - ret = fstat(c->fd, &st); - return ret < 0 ? AVERROR(errno) : st.st_size; + return ret < 0 ? AVERROR(errno) : (S_ISFIFO(st.st_mode) ? 0 : st.st_size); } ret = lseek(c->fd, pos, whence); @@ -148,6 +253,90 @@ static int file_close(URLContext *h) return close(c->fd); } +static int file_open_dir(URLContext *h) +{ +#if HAVE_LSTAT + FileContext *c = h->priv_data; + + c->dir = opendir(h->filename); + if (!c->dir) + return AVERROR(errno); + + return 0; +#else + return AVERROR(ENOSYS); +#endif /* HAVE_LSTAT */ +} + +static int file_read_dir(URLContext *h, AVIODirEntry **next) +{ +#if HAVE_LSTAT + 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 (!lstat(fullpath, &st)) { + if (S_ISDIR(st.st_mode)) + (*next)->type = AVIO_ENTRY_DIRECTORY; + else if (S_ISFIFO(st.st_mode)) + (*next)->type = AVIO_ENTRY_NAMED_PIPE; + else if (S_ISCHR(st.st_mode)) + (*next)->type = AVIO_ENTRY_CHARACTER_DEVICE; + else if (S_ISBLK(st.st_mode)) + (*next)->type = AVIO_ENTRY_BLOCK_DEVICE; + else if (S_ISLNK(st.st_mode)) + (*next)->type = AVIO_ENTRY_SYMBOLIC_LINK; + else if (S_ISSOCK(st.st_mode)) + (*next)->type = AVIO_ENTRY_SOCKET; + else if (S_ISREG(st.st_mode)) + (*next)->type = AVIO_ENTRY_FILE; + else + (*next)->type = AVIO_ENTRY_UNKNOWN; + + (*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); + return 0; +#else + return AVERROR(ENOSYS); +#endif /* HAVE_LSTAT */ +} + +static int file_close_dir(URLContext *h) +{ +#if HAVE_LSTAT + FileContext *c = h->priv_data; + closedir(c->dir); + return 0; +#else + return AVERROR(ENOSYS); +#endif /* HAVE_LSTAT */ +} + const URLProtocol ff_file_protocol = { .name = "file", .url_open = file_open, @@ -157,8 +346,14 @@ const URLProtocol ff_file_protocol = { .url_close = file_close, .url_get_file_handle = file_get_handle, .url_check = file_check, + .url_delete = file_delete, + .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, + .default_whitelist = "file,crypto" }; #endif /* CONFIG_FILE_PROTOCOL */ @@ -196,6 +391,8 @@ const URLProtocol ff_pipe_protocol = { .url_get_file_handle = file_get_handle, .url_check = file_check, .priv_data_size = sizeof(FileContext), + .priv_data_class = &pipe_class, + .default_whitelist = "crypto" }; #endif /* CONFIG_PIPE_PROTOCOL */ |