LCOV - code coverage report
Current view: top level - src/libavformat - file.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 61 138 44.2 %
Date: 2017-08-17 10:06:07 Functions: 7 13 53.8 %

          Line data    Source code
       1             : /*
       2             :  * buffered file I/O
       3             :  * Copyright (c) 2001 Fabrice Bellard
       4             :  *
       5             :  * This file is part of FFmpeg.
       6             :  *
       7             :  * FFmpeg is free software; you can redistribute it and/or
       8             :  * modify it under the terms of the GNU Lesser General Public
       9             :  * License as published by the Free Software Foundation; either
      10             :  * version 2.1 of the License, or (at your option) any later version.
      11             :  *
      12             :  * FFmpeg is distributed in the hope that it will be useful,
      13             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :  * Lesser General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU Lesser General Public
      18             :  * License along with FFmpeg; if not, write to the Free Software
      19             :  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
      20             :  */
      21             : 
      22             : #include "libavutil/avstring.h"
      23             : #include "libavutil/internal.h"
      24             : #include "libavutil/opt.h"
      25             : #include "avformat.h"
      26             : #if HAVE_DIRENT_H
      27             : #include <dirent.h>
      28             : #endif
      29             : #include <fcntl.h>
      30             : #if HAVE_IO_H
      31             : #include <io.h>
      32             : #endif
      33             : #if HAVE_UNISTD_H
      34             : #include <unistd.h>
      35             : #endif
      36             : #include <sys/stat.h>
      37             : #include <stdlib.h>
      38             : #include "os_support.h"
      39             : #include "url.h"
      40             : 
      41             : /* Some systems may not have S_ISFIFO */
      42             : #ifndef S_ISFIFO
      43             : #  ifdef S_IFIFO
      44             : #    define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
      45             : #  else
      46             : #    define S_ISFIFO(m) 0
      47             : #  endif
      48             : #endif
      49             : 
      50             : /* Not available in POSIX.1-1996 */
      51             : #ifndef S_ISLNK
      52             : #  ifdef S_IFLNK
      53             : #    define S_ISLNK(m) (((m) & S_IFLNK) == S_IFLNK)
      54             : #  else
      55             : #    define S_ISLNK(m) 0
      56             : #  endif
      57             : #endif
      58             : 
      59             : /* Not available in POSIX.1-1996 */
      60             : #ifndef S_ISSOCK
      61             : #  ifdef S_IFSOCK
      62             : #    define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
      63             : #  else
      64             : #    define S_ISSOCK(m) 0
      65             : #  endif
      66             : #endif
      67             : 
      68             : /* standard file protocol */
      69             : 
      70             : typedef struct FileContext {
      71             :     const AVClass *class;
      72             :     int fd;
      73             :     int trunc;
      74             :     int blocksize;
      75             :     int follow;
      76             : #if HAVE_DIRENT_H
      77             :     DIR *dir;
      78             : #endif
      79             : } FileContext;
      80             : 
      81             : static const AVOption file_options[] = {
      82             :     { "truncate", "truncate existing files on write", offsetof(FileContext, trunc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
      83             :     { "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 },
      84             :     { "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 },
      85             :     { NULL }
      86             : };
      87             : 
      88             : static const AVOption pipe_options[] = {
      89             :     { "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 },
      90             :     { NULL }
      91             : };
      92             : 
      93             : static const AVClass file_class = {
      94             :     .class_name = "file",
      95             :     .item_name  = av_default_item_name,
      96             :     .option     = file_options,
      97             :     .version    = LIBAVUTIL_VERSION_INT,
      98             : };
      99             : 
     100             : static const AVClass pipe_class = {
     101             :     .class_name = "pipe",
     102             :     .item_name  = av_default_item_name,
     103             :     .option     = pipe_options,
     104             :     .version    = LIBAVUTIL_VERSION_INT,
     105             : };
     106             : 
     107      158663 : static int file_read(URLContext *h, unsigned char *buf, int size)
     108             : {
     109      158663 :     FileContext *c = h->priv_data;
     110             :     int ret;
     111      158663 :     size = FFMIN(size, c->blocksize);
     112      158663 :     ret = read(c->fd, buf, size);
     113      158663 :     if (ret == 0 && c->follow)
     114           0 :         return AVERROR(EAGAIN);
     115      158663 :     if (ret == 0)
     116       10402 :         return AVERROR_EOF;
     117      148261 :     return (ret == -1) ? AVERROR(errno) : ret;
     118             : }
     119             : 
     120      214392 : static int file_write(URLContext *h, const unsigned char *buf, int size)
     121             : {
     122      214392 :     FileContext *c = h->priv_data;
     123             :     int ret;
     124      214392 :     size = FFMIN(size, c->blocksize);
     125      214392 :     ret = write(c->fd, buf, size);
     126      214392 :     return (ret == -1) ? AVERROR(errno) : ret;
     127             : }
     128             : 
     129           0 : static int file_get_handle(URLContext *h)
     130             : {
     131           0 :     FileContext *c = h->priv_data;
     132           0 :     return c->fd;
     133             : }
     134             : 
     135       33016 : static int file_check(URLContext *h, int mask)
     136             : {
     137       33016 :     int ret = 0;
     138       33016 :     const char *filename = h->filename;
     139       33016 :     av_strstart(filename, "file:", &filename);
     140             : 
     141             :     {
     142             : #if HAVE_ACCESS && defined(R_OK)
     143       33016 :     if (access(filename, F_OK) < 0)
     144        7911 :         return AVERROR(errno);
     145       25105 :     if (mask&AVIO_FLAG_READ)
     146       25105 :         if (access(filename, R_OK) >= 0)
     147       25105 :             ret |= AVIO_FLAG_READ;
     148       25105 :     if (mask&AVIO_FLAG_WRITE)
     149           0 :         if (access(filename, W_OK) >= 0)
     150           0 :             ret |= AVIO_FLAG_WRITE;
     151             : #else
     152             :     struct stat st;
     153             : #   ifndef _WIN32
     154             :     ret = stat(filename, &st);
     155             : #   else
     156             :     ret = win32_stat(filename, &st);
     157             : #   endif
     158             :     if (ret < 0)
     159             :         return AVERROR(errno);
     160             : 
     161             :     ret |= st.st_mode&S_IRUSR ? mask&AVIO_FLAG_READ  : 0;
     162             :     ret |= st.st_mode&S_IWUSR ? mask&AVIO_FLAG_WRITE : 0;
     163             : #endif
     164             :     }
     165       25105 :     return ret;
     166             : }
     167             : 
     168           0 : static int file_delete(URLContext *h)
     169             : {
     170             : #if HAVE_UNISTD_H
     171             :     int ret;
     172           0 :     const char *filename = h->filename;
     173           0 :     av_strstart(filename, "file:", &filename);
     174             : 
     175           0 :     ret = rmdir(filename);
     176           0 :     if (ret < 0 && errno == ENOTDIR)
     177           0 :         ret = unlink(filename);
     178           0 :     if (ret < 0)
     179           0 :         return AVERROR(errno);
     180             : 
     181           0 :     return ret;
     182             : #else
     183             :     return AVERROR(ENOSYS);
     184             : #endif /* HAVE_UNISTD_H */
     185             : }
     186             : 
     187           0 : static int file_move(URLContext *h_src, URLContext *h_dst)
     188             : {
     189           0 :     const char *filename_src = h_src->filename;
     190           0 :     const char *filename_dst = h_dst->filename;
     191           0 :     av_strstart(filename_src, "file:", &filename_src);
     192           0 :     av_strstart(filename_dst, "file:", &filename_dst);
     193             : 
     194           0 :     if (rename(filename_src, filename_dst) < 0)
     195           0 :         return AVERROR(errno);
     196             : 
     197           0 :     return 0;
     198             : }
     199             : 
     200             : #if CONFIG_FILE_PROTOCOL
     201             : 
     202       69502 : static int file_open(URLContext *h, const char *filename, int flags)
     203             : {
     204       69502 :     FileContext *c = h->priv_data;
     205             :     int access;
     206             :     int fd;
     207             :     struct stat st;
     208             : 
     209       69502 :     av_strstart(filename, "file:", &filename);
     210             : 
     211       69502 :     if (flags & AVIO_FLAG_WRITE && flags & AVIO_FLAG_READ) {
     212           0 :         access = O_CREAT | O_RDWR;
     213           0 :         if (c->trunc)
     214           0 :             access |= O_TRUNC;
     215       69502 :     } else if (flags & AVIO_FLAG_WRITE) {
     216        1884 :         access = O_CREAT | O_WRONLY;
     217        1884 :         if (c->trunc)
     218        1884 :             access |= O_TRUNC;
     219             :     } else {
     220       67618 :         access = O_RDONLY;
     221             :     }
     222             : #ifdef O_BINARY
     223             :     access |= O_BINARY;
     224             : #endif
     225       69502 :     fd = avpriv_open(filename, access, 0666);
     226       69502 :     if (fd == -1)
     227           1 :         return AVERROR(errno);
     228       69501 :     c->fd = fd;
     229             : 
     230       69501 :     h->is_streamed = !fstat(fd, &st) && S_ISFIFO(st.st_mode);
     231             : 
     232             :     /* Buffer writes more than the default 32k to improve throughput especially
     233             :      * with networked file systems */
     234       69501 :     if (!h->is_streamed && flags & AVIO_FLAG_WRITE)
     235        1884 :         h->min_packet_size = h->max_packet_size = 262144;
     236             : 
     237       69501 :     return 0;
     238             : }
     239             : 
     240             : /* XXX: use llseek */
     241      160347 : static int64_t file_seek(URLContext *h, int64_t pos, int whence)
     242             : {
     243      160347 :     FileContext *c = h->priv_data;
     244             :     int64_t ret;
     245             : 
     246      160347 :     if (whence == AVSEEK_SIZE) {
     247             :         struct stat st;
     248       79030 :         ret = fstat(c->fd, &st);
     249       79030 :         return ret < 0 ? AVERROR(errno) : (S_ISFIFO(st.st_mode) ? 0 : st.st_size);
     250             :     }
     251             : 
     252       81317 :     ret = lseek(c->fd, pos, whence);
     253             : 
     254       81317 :     return ret < 0 ? AVERROR(errno) : ret;
     255             : }
     256             : 
     257       69501 : static int file_close(URLContext *h)
     258             : {
     259       69501 :     FileContext *c = h->priv_data;
     260       69501 :     return close(c->fd);
     261             : }
     262             : 
     263           0 : static int file_open_dir(URLContext *h)
     264             : {
     265             : #if HAVE_LSTAT
     266           0 :     FileContext *c = h->priv_data;
     267             : 
     268           0 :     c->dir = opendir(h->filename);
     269           0 :     if (!c->dir)
     270           0 :         return AVERROR(errno);
     271             : 
     272           0 :     return 0;
     273             : #else
     274             :     return AVERROR(ENOSYS);
     275             : #endif /* HAVE_LSTAT */
     276             : }
     277             : 
     278           0 : static int file_read_dir(URLContext *h, AVIODirEntry **next)
     279             : {
     280             : #if HAVE_LSTAT
     281           0 :     FileContext *c = h->priv_data;
     282             :     struct dirent *dir;
     283           0 :     char *fullpath = NULL;
     284             : 
     285           0 :     *next = ff_alloc_dir_entry();
     286           0 :     if (!*next)
     287           0 :         return AVERROR(ENOMEM);
     288             :     do {
     289           0 :         errno = 0;
     290           0 :         dir = readdir(c->dir);
     291           0 :         if (!dir) {
     292           0 :             av_freep(next);
     293           0 :             return AVERROR(errno);
     294             :         }
     295           0 :     } while (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."));
     296             : 
     297           0 :     fullpath = av_append_path_component(h->filename, dir->d_name);
     298           0 :     if (fullpath) {
     299             :         struct stat st;
     300           0 :         if (!lstat(fullpath, &st)) {
     301           0 :             if (S_ISDIR(st.st_mode))
     302           0 :                 (*next)->type = AVIO_ENTRY_DIRECTORY;
     303           0 :             else if (S_ISFIFO(st.st_mode))
     304           0 :                 (*next)->type = AVIO_ENTRY_NAMED_PIPE;
     305           0 :             else if (S_ISCHR(st.st_mode))
     306           0 :                 (*next)->type = AVIO_ENTRY_CHARACTER_DEVICE;
     307           0 :             else if (S_ISBLK(st.st_mode))
     308           0 :                 (*next)->type = AVIO_ENTRY_BLOCK_DEVICE;
     309           0 :             else if (S_ISLNK(st.st_mode))
     310           0 :                 (*next)->type = AVIO_ENTRY_SYMBOLIC_LINK;
     311           0 :             else if (S_ISSOCK(st.st_mode))
     312           0 :                 (*next)->type = AVIO_ENTRY_SOCKET;
     313           0 :             else if (S_ISREG(st.st_mode))
     314           0 :                 (*next)->type = AVIO_ENTRY_FILE;
     315             :             else
     316           0 :                 (*next)->type = AVIO_ENTRY_UNKNOWN;
     317             : 
     318           0 :             (*next)->group_id = st.st_gid;
     319           0 :             (*next)->user_id = st.st_uid;
     320           0 :             (*next)->size = st.st_size;
     321           0 :             (*next)->filemode = st.st_mode & 0777;
     322           0 :             (*next)->modification_timestamp = INT64_C(1000000) * st.st_mtime;
     323           0 :             (*next)->access_timestamp =  INT64_C(1000000) * st.st_atime;
     324           0 :             (*next)->status_change_timestamp = INT64_C(1000000) * st.st_ctime;
     325             :         }
     326           0 :         av_free(fullpath);
     327             :     }
     328             : 
     329           0 :     (*next)->name = av_strdup(dir->d_name);
     330           0 :     return 0;
     331             : #else
     332             :     return AVERROR(ENOSYS);
     333             : #endif /* HAVE_LSTAT */
     334             : }
     335             : 
     336           0 : static int file_close_dir(URLContext *h)
     337             : {
     338             : #if HAVE_LSTAT
     339           0 :     FileContext *c = h->priv_data;
     340           0 :     closedir(c->dir);
     341           0 :     return 0;
     342             : #else
     343             :     return AVERROR(ENOSYS);
     344             : #endif /* HAVE_LSTAT */
     345             : }
     346             : 
     347             : const URLProtocol ff_file_protocol = {
     348             :     .name                = "file",
     349             :     .url_open            = file_open,
     350             :     .url_read            = file_read,
     351             :     .url_write           = file_write,
     352             :     .url_seek            = file_seek,
     353             :     .url_close           = file_close,
     354             :     .url_get_file_handle = file_get_handle,
     355             :     .url_check           = file_check,
     356             :     .url_delete          = file_delete,
     357             :     .url_move            = file_move,
     358             :     .priv_data_size      = sizeof(FileContext),
     359             :     .priv_data_class     = &file_class,
     360             :     .url_open_dir        = file_open_dir,
     361             :     .url_read_dir        = file_read_dir,
     362             :     .url_close_dir       = file_close_dir,
     363             :     .default_whitelist   = "file,crypto"
     364             : };
     365             : 
     366             : #endif /* CONFIG_FILE_PROTOCOL */
     367             : 
     368             : #if CONFIG_PIPE_PROTOCOL
     369             : 
     370        2060 : static int pipe_open(URLContext *h, const char *filename, int flags)
     371             : {
     372        2060 :     FileContext *c = h->priv_data;
     373             :     int fd;
     374             :     char *final;
     375        2060 :     av_strstart(filename, "pipe:", &filename);
     376             : 
     377        2060 :     fd = strtol(filename, &final, 10);
     378        2060 :     if((filename == final) || *final ) {/* No digits found, or something like 10ab */
     379        2059 :         if (flags & AVIO_FLAG_WRITE) {
     380        2059 :             fd = 1;
     381             :         } else {
     382           0 :             fd = 0;
     383             :         }
     384             :     }
     385             : #if HAVE_SETMODE
     386             :     setmode(fd, O_BINARY);
     387             : #endif
     388        2060 :     c->fd = fd;
     389        2060 :     h->is_streamed = 1;
     390        2060 :     return 0;
     391             : }
     392             : 
     393             : const URLProtocol ff_pipe_protocol = {
     394             :     .name                = "pipe",
     395             :     .url_open            = pipe_open,
     396             :     .url_read            = file_read,
     397             :     .url_write           = file_write,
     398             :     .url_get_file_handle = file_get_handle,
     399             :     .url_check           = file_check,
     400             :     .priv_data_size      = sizeof(FileContext),
     401             :     .priv_data_class     = &pipe_class,
     402             :     .default_whitelist   = "crypto"
     403             : };
     404             : 
     405             : #endif /* CONFIG_PIPE_PROTOCOL */

Generated by: LCOV version 1.13