Imported Upstream version 6.1
[platform/upstream/ffmpeg.git] / libavformat / file.c
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 "config_components.h"
23
24 #include "libavutil/avstring.h"
25 #include "libavutil/file_open.h"
26 #include "libavutil/internal.h"
27 #include "libavutil/opt.h"
28 #include "avio.h"
29 #if HAVE_DIRENT_H
30 #include <dirent.h>
31 #endif
32 #include <fcntl.h>
33 #if HAVE_IO_H
34 #include <io.h>
35 #endif
36 #if HAVE_UNISTD_H
37 #include <unistd.h>
38 #endif
39 #include <sys/stat.h>
40 #include <stdlib.h>
41 #include "os_support.h"
42 #include "url.h"
43
44 /* Some systems may not have S_ISFIFO */
45 #ifndef S_ISFIFO
46 #  ifdef S_IFIFO
47 #    define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
48 #  else
49 #    define S_ISFIFO(m) 0
50 #  endif
51 #endif
52
53 /* Not available in POSIX.1-1996 */
54 #ifndef S_ISLNK
55 #  ifdef S_IFLNK
56 #    define S_ISLNK(m) (((m) & S_IFLNK) == S_IFLNK)
57 #  else
58 #    define S_ISLNK(m) 0
59 #  endif
60 #endif
61
62 /* Not available in POSIX.1-1996 */
63 #ifndef S_ISSOCK
64 #  ifdef S_IFSOCK
65 #    define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
66 #  else
67 #    define S_ISSOCK(m) 0
68 #  endif
69 #endif
70
71 /* S_ISREG not available on Windows */
72 #ifndef S_ISREG
73 #  ifdef S_IFREG
74 #    define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
75 #  else
76 #    define S_ISREG(m) 0
77 #  endif
78 #endif
79
80 /* S_ISBLK not available on Windows */
81 #ifndef S_ISBLK
82 #  ifdef S_IFBLK
83 #    define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
84 #  else
85 #    define S_ISBLK(m) 0
86 #  endif
87 #endif
88
89 /* standard file protocol */
90
91 typedef struct FileContext {
92     const AVClass *class;
93     int fd;
94     int trunc;
95     int blocksize;
96     int follow;
97     int seekable;
98 #if HAVE_DIRENT_H
99     DIR *dir;
100 #endif
101 } FileContext;
102
103 static const AVOption file_options[] = {
104     { "truncate", "truncate existing files on write", offsetof(FileContext, trunc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
105     { "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 },
106     { "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 },
107     { "seekable", "Sets if the file is seekable", offsetof(FileContext, seekable), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, 0, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_ENCODING_PARAM },
108     { NULL }
109 };
110
111 static const AVOption pipe_options[] = {
112     { "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 },
113     { "fd", "set file descriptor", offsetof(FileContext, fd), AV_OPT_TYPE_INT, { .i64 = -1 }, -1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
114     { NULL }
115 };
116
117 static const AVClass file_class = {
118     .class_name = "file",
119     .item_name  = av_default_item_name,
120     .option     = file_options,
121     .version    = LIBAVUTIL_VERSION_INT,
122 };
123
124 static const AVClass pipe_class = {
125     .class_name = "pipe",
126     .item_name  = av_default_item_name,
127     .option     = pipe_options,
128     .version    = LIBAVUTIL_VERSION_INT,
129 };
130
131 static const AVClass fd_class = {
132     .class_name = "fd",
133     .item_name  = av_default_item_name,
134     .option     = pipe_options,
135     .version    = LIBAVUTIL_VERSION_INT,
136 };
137
138 static int file_read(URLContext *h, unsigned char *buf, int size)
139 {
140     FileContext *c = h->priv_data;
141     int ret;
142     size = FFMIN(size, c->blocksize);
143     ret = read(c->fd, buf, size);
144     if (ret == 0 && c->follow)
145         return AVERROR(EAGAIN);
146     if (ret == 0)
147         return AVERROR_EOF;
148     return (ret == -1) ? AVERROR(errno) : ret;
149 }
150
151 static int file_write(URLContext *h, const unsigned char *buf, int size)
152 {
153     FileContext *c = h->priv_data;
154     int ret;
155     size = FFMIN(size, c->blocksize);
156     ret = write(c->fd, buf, size);
157     return (ret == -1) ? AVERROR(errno) : ret;
158 }
159
160 static int file_get_handle(URLContext *h)
161 {
162     FileContext *c = h->priv_data;
163     return c->fd;
164 }
165
166 static int file_check(URLContext *h, int mask)
167 {
168     int ret = 0;
169     const char *filename = h->filename;
170     av_strstart(filename, "file:", &filename);
171
172     {
173 #if HAVE_ACCESS && defined(R_OK)
174     if (access(filename, F_OK) < 0)
175         return AVERROR(errno);
176     if (mask&AVIO_FLAG_READ)
177         if (access(filename, R_OK) >= 0)
178             ret |= AVIO_FLAG_READ;
179     if (mask&AVIO_FLAG_WRITE)
180         if (access(filename, W_OK) >= 0)
181             ret |= AVIO_FLAG_WRITE;
182 #else
183     struct stat st;
184     ret = stat(filename, &st);
185     if (ret < 0)
186         return AVERROR(errno);
187
188     ret |= st.st_mode&S_IRUSR ? mask&AVIO_FLAG_READ  : 0;
189     ret |= st.st_mode&S_IWUSR ? mask&AVIO_FLAG_WRITE : 0;
190 #endif
191     }
192     return ret;
193 }
194
195 static int fd_dup(URLContext *h, int oldfd)
196 {
197     int newfd;
198
199 #ifdef F_DUPFD_CLOEXEC
200     newfd = fcntl(oldfd, F_DUPFD_CLOEXEC, 0);
201 #else
202     newfd = dup(oldfd);
203 #endif
204     if (newfd == -1)
205         return newfd;
206
207 #if HAVE_FCNTL
208     if (fcntl(newfd, F_SETFD, FD_CLOEXEC) == -1)
209         av_log(h, AV_LOG_DEBUG, "Failed to set close on exec\n");
210 #endif
211
212 #if HAVE_SETMODE
213     setmode(newfd, O_BINARY);
214 #endif
215     return newfd;
216 }
217
218 static int file_close(URLContext *h)
219 {
220     FileContext *c = h->priv_data;
221     int ret = close(c->fd);
222     return (ret == -1) ? AVERROR(errno) : 0;
223 }
224
225 /* XXX: use llseek */
226 static int64_t file_seek(URLContext *h, int64_t pos, int whence)
227 {
228     FileContext *c = h->priv_data;
229     int64_t ret;
230
231     if (whence == AVSEEK_SIZE) {
232         struct stat st;
233         ret = fstat(c->fd, &st);
234         return ret < 0 ? AVERROR(errno) : (S_ISFIFO(st.st_mode) ? 0 : st.st_size);
235     }
236
237     ret = lseek(c->fd, pos, whence);
238
239     return ret < 0 ? AVERROR(errno) : ret;
240 }
241
242 #if CONFIG_FILE_PROTOCOL
243
244 static int file_delete(URLContext *h)
245 {
246 #if HAVE_UNISTD_H
247     int ret;
248     const char *filename = h->filename;
249     av_strstart(filename, "file:", &filename);
250
251     ret = rmdir(filename);
252     if (ret < 0 && (errno == ENOTDIR
253 #   ifdef _WIN32
254         || errno == EINVAL
255 #   endif
256         ))
257         ret = unlink(filename);
258     if (ret < 0)
259         return AVERROR(errno);
260
261     return ret;
262 #else
263     return AVERROR(ENOSYS);
264 #endif /* HAVE_UNISTD_H */
265 }
266
267 static int file_move(URLContext *h_src, URLContext *h_dst)
268 {
269     const char *filename_src = h_src->filename;
270     const char *filename_dst = h_dst->filename;
271     av_strstart(filename_src, "file:", &filename_src);
272     av_strstart(filename_dst, "file:", &filename_dst);
273
274     if (rename(filename_src, filename_dst) < 0)
275         return AVERROR(errno);
276
277     return 0;
278 }
279
280 static int file_open(URLContext *h, const char *filename, int flags)
281 {
282     FileContext *c = h->priv_data;
283     int access;
284     int fd;
285     struct stat st;
286
287     av_strstart(filename, "file:", &filename);
288
289     if (flags & AVIO_FLAG_WRITE && flags & AVIO_FLAG_READ) {
290         access = O_CREAT | O_RDWR;
291         if (c->trunc)
292             access |= O_TRUNC;
293     } else if (flags & AVIO_FLAG_WRITE) {
294         access = O_CREAT | O_WRONLY;
295         if (c->trunc)
296             access |= O_TRUNC;
297     } else {
298         access = O_RDONLY;
299     }
300 #ifdef O_BINARY
301     access |= O_BINARY;
302 #endif
303     fd = avpriv_open(filename, access, 0666);
304     if (fd == -1)
305         return AVERROR(errno);
306     c->fd = fd;
307
308     h->is_streamed = !fstat(fd, &st) && S_ISFIFO(st.st_mode);
309
310     /* Buffer writes more than the default 32k to improve throughput especially
311      * with networked file systems */
312     if (!h->is_streamed && flags & AVIO_FLAG_WRITE)
313         h->min_packet_size = h->max_packet_size = 262144;
314
315     if (c->seekable >= 0)
316         h->is_streamed = !c->seekable;
317
318     return 0;
319 }
320
321 static int file_open_dir(URLContext *h)
322 {
323 #if HAVE_LSTAT
324     FileContext *c = h->priv_data;
325
326     c->dir = opendir(h->filename);
327     if (!c->dir)
328         return AVERROR(errno);
329
330     return 0;
331 #else
332     return AVERROR(ENOSYS);
333 #endif /* HAVE_LSTAT */
334 }
335
336 static int file_read_dir(URLContext *h, AVIODirEntry **next)
337 {
338 #if HAVE_LSTAT
339     FileContext *c = h->priv_data;
340     struct dirent *dir;
341     char *fullpath = NULL;
342
343     *next = ff_alloc_dir_entry();
344     if (!*next)
345         return AVERROR(ENOMEM);
346     do {
347         errno = 0;
348         dir = readdir(c->dir);
349         if (!dir) {
350             av_freep(next);
351             return AVERROR(errno);
352         }
353     } while (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."));
354
355     fullpath = av_append_path_component(h->filename, dir->d_name);
356     if (fullpath) {
357         struct stat st;
358         if (!lstat(fullpath, &st)) {
359             if (S_ISDIR(st.st_mode))
360                 (*next)->type = AVIO_ENTRY_DIRECTORY;
361             else if (S_ISFIFO(st.st_mode))
362                 (*next)->type = AVIO_ENTRY_NAMED_PIPE;
363             else if (S_ISCHR(st.st_mode))
364                 (*next)->type = AVIO_ENTRY_CHARACTER_DEVICE;
365             else if (S_ISBLK(st.st_mode))
366                 (*next)->type = AVIO_ENTRY_BLOCK_DEVICE;
367             else if (S_ISLNK(st.st_mode))
368                 (*next)->type = AVIO_ENTRY_SYMBOLIC_LINK;
369             else if (S_ISSOCK(st.st_mode))
370                 (*next)->type = AVIO_ENTRY_SOCKET;
371             else if (S_ISREG(st.st_mode))
372                 (*next)->type = AVIO_ENTRY_FILE;
373             else
374                 (*next)->type = AVIO_ENTRY_UNKNOWN;
375
376             (*next)->group_id = st.st_gid;
377             (*next)->user_id = st.st_uid;
378             (*next)->size = st.st_size;
379             (*next)->filemode = st.st_mode & 0777;
380             (*next)->modification_timestamp = INT64_C(1000000) * st.st_mtime;
381             (*next)->access_timestamp =  INT64_C(1000000) * st.st_atime;
382             (*next)->status_change_timestamp = INT64_C(1000000) * st.st_ctime;
383         }
384         av_free(fullpath);
385     }
386
387     (*next)->name = av_strdup(dir->d_name);
388     return 0;
389 #else
390     return AVERROR(ENOSYS);
391 #endif /* HAVE_LSTAT */
392 }
393
394 static int file_close_dir(URLContext *h)
395 {
396 #if HAVE_LSTAT
397     FileContext *c = h->priv_data;
398     closedir(c->dir);
399     return 0;
400 #else
401     return AVERROR(ENOSYS);
402 #endif /* HAVE_LSTAT */
403 }
404
405 const URLProtocol ff_file_protocol = {
406     .name                = "file",
407     .url_open            = file_open,
408     .url_read            = file_read,
409     .url_write           = file_write,
410     .url_seek            = file_seek,
411     .url_close           = file_close,
412     .url_get_file_handle = file_get_handle,
413     .url_check           = file_check,
414     .url_delete          = file_delete,
415     .url_move            = file_move,
416     .priv_data_size      = sizeof(FileContext),
417     .priv_data_class     = &file_class,
418     .url_open_dir        = file_open_dir,
419     .url_read_dir        = file_read_dir,
420     .url_close_dir       = file_close_dir,
421     .default_whitelist   = "file,crypto,data"
422 };
423
424 #endif /* CONFIG_FILE_PROTOCOL */
425
426 #if CONFIG_PIPE_PROTOCOL
427
428 static int pipe_open(URLContext *h, const char *filename, int flags)
429 {
430     FileContext *c = h->priv_data;
431     int fd;
432     char *final;
433
434     if (c->fd < 0) {
435         av_strstart(filename, "pipe:", &filename);
436
437         fd = strtol(filename, &final, 10);
438         if((filename == final) || *final ) {/* No digits found, or something like 10ab */
439             if (flags & AVIO_FLAG_WRITE) {
440                 fd = 1;
441             } else {
442                 fd = 0;
443             }
444         }
445         c->fd = fd;
446     }
447
448     c->fd = fd_dup(h, c->fd);
449     if (c->fd == -1)
450         return AVERROR(errno);
451     h->is_streamed = 1;
452     return 0;
453 }
454
455 const URLProtocol ff_pipe_protocol = {
456     .name                = "pipe",
457     .url_open            = pipe_open,
458     .url_read            = file_read,
459     .url_write           = file_write,
460     .url_close           = file_close,
461     .url_get_file_handle = file_get_handle,
462     .url_check           = file_check,
463     .priv_data_size      = sizeof(FileContext),
464     .priv_data_class     = &pipe_class,
465     .default_whitelist   = "crypto,data"
466 };
467
468 #endif /* CONFIG_PIPE_PROTOCOL */
469
470 #if CONFIG_FD_PROTOCOL
471
472 static int fd_open(URLContext *h, const char *filename, int flags)
473 {
474     FileContext *c = h->priv_data;
475     struct stat st;
476
477     if (strcmp(filename, "fd:") != 0) {
478         av_log(h, AV_LOG_ERROR, "Doesn't support pass file descriptor via URL,"
479                                 " please set it via -fd {num}\n");
480         return AVERROR(EINVAL);
481     }
482
483     if (c->fd < 0) {
484         if (flags & AVIO_FLAG_WRITE) {
485             c->fd = 1;
486         } else {
487             c->fd = 0;
488         }
489     }
490     if (fstat(c->fd, &st) < 0)
491         return AVERROR(errno);
492     h->is_streamed = !(S_ISREG(st.st_mode) || S_ISBLK(st.st_mode));
493     c->fd = fd_dup(h, c->fd);
494     if (c->fd == -1)
495         return AVERROR(errno);
496
497     return 0;
498 }
499
500 const URLProtocol ff_fd_protocol = {
501     .name                = "fd",
502     .url_open            = fd_open,
503     .url_read            = file_read,
504     .url_write           = file_write,
505     .url_seek            = file_seek,
506     .url_close           = file_close,
507     .url_get_file_handle = file_get_handle,
508     .url_check           = file_check,
509     .priv_data_size      = sizeof(FileContext),
510     .priv_data_class     = &fd_class,
511     .default_whitelist   = "crypto,data"
512 };
513
514 #endif /* CONFIG_FD_PROTOCOL */