Libav
file.c
Go to the documentation of this file.
1 /*
2  * buffered file I/O
3  * Copyright (c) 2001 Fabrice Bellard
4  *
5  * This file is part of Libav.
6  *
7  * Libav 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  * Libav 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 Libav; 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 #include <fcntl.h>
27 #if HAVE_IO_H
28 #include <io.h>
29 #endif
30 #if HAVE_UNISTD_H
31 #include <unistd.h>
32 #endif
33 #include <sys/stat.h>
34 #include <stdlib.h>
35 #include "os_support.h"
36 #include "url.h"
37 
38 
39 /* standard file protocol */
40 
41 typedef struct FileContext {
42  const AVClass *class;
43  int fd;
44  int trunc;
45 } FileContext;
46 
47 static const AVOption file_options[] = {
48  { "truncate", "Truncate existing files on write", offsetof(FileContext, trunc), AV_OPT_TYPE_INT, { .i64 = 1 }, 0, 1, AV_OPT_FLAG_ENCODING_PARAM },
49  { NULL }
50 };
51 
52 static const AVClass file_class = {
53  .class_name = "file",
54  .item_name = av_default_item_name,
55  .option = file_options,
56  .version = LIBAVUTIL_VERSION_INT,
57 };
58 
59 static int file_read(URLContext *h, unsigned char *buf, int size)
60 {
61  FileContext *c = h->priv_data;
62  return read(c->fd, buf, size);
63 }
64 
65 static int file_write(URLContext *h, const unsigned char *buf, int size)
66 {
67  FileContext *c = h->priv_data;
68  return write(c->fd, buf, size);
69 }
70 
72 {
73  FileContext *c = h->priv_data;
74  return c->fd;
75 }
76 
77 static int file_check(URLContext *h, int mask)
78 {
79  struct stat st;
80  int ret = stat(h->filename, &st);
81  if (ret < 0)
82  return AVERROR(errno);
83 
84  ret |= st.st_mode&S_IRUSR ? mask&AVIO_FLAG_READ : 0;
85  ret |= st.st_mode&S_IWUSR ? mask&AVIO_FLAG_WRITE : 0;
86 
87  return ret;
88 }
89 
90 #if CONFIG_FILE_PROTOCOL
91 
92 static int file_open(URLContext *h, const char *filename, int flags)
93 {
94  FileContext *c = h->priv_data;
95  int access;
96  int fd;
97 
98  av_strstart(filename, "file:", &filename);
99 
100  if (flags & AVIO_FLAG_WRITE && flags & AVIO_FLAG_READ) {
101  access = O_CREAT | O_RDWR;
102  if (c->trunc)
103  access |= O_TRUNC;
104  } else if (flags & AVIO_FLAG_WRITE) {
105  access = O_CREAT | O_WRONLY;
106  if (c->trunc)
107  access |= O_TRUNC;
108  } else {
109  access = O_RDONLY;
110  }
111 #ifdef O_BINARY
112  access |= O_BINARY;
113 #endif
114  fd = avpriv_open(filename, access, 0666);
115  if (fd == -1)
116  return AVERROR(errno);
117  c->fd = fd;
118  return 0;
119 }
120 
121 /* XXX: use llseek */
122 static int64_t file_seek(URLContext *h, int64_t pos, int whence)
123 {
124  FileContext *c = h->priv_data;
125  int64_t ret;
126 
127  if (whence == AVSEEK_SIZE) {
128  struct stat st;
129 
130  ret = fstat(c->fd, &st);
131  return ret < 0 ? AVERROR(errno) : st.st_size;
132  }
133 
134  ret = lseek(c->fd, pos, whence);
135 
136  return ret < 0 ? AVERROR(errno) : ret;
137 }
138 
139 static int file_close(URLContext *h)
140 {
141  FileContext *c = h->priv_data;
142  return close(c->fd);
143 }
144 
145 URLProtocol ff_file_protocol = {
146  .name = "file",
147  .url_open = file_open,
148  .url_read = file_read,
149  .url_write = file_write,
150  .url_seek = file_seek,
151  .url_close = file_close,
152  .url_get_file_handle = file_get_handle,
153  .url_check = file_check,
154  .priv_data_size = sizeof(FileContext),
155  .priv_data_class = &file_class,
156 };
157 
158 #endif /* CONFIG_FILE_PROTOCOL */
159 
160 #if CONFIG_PIPE_PROTOCOL
161 
162 static int pipe_open(URLContext *h, const char *filename, int flags)
163 {
164  FileContext *c = h->priv_data;
165  int fd;
166  char *final;
167  av_strstart(filename, "pipe:", &filename);
168 
169  fd = strtol(filename, &final, 10);
170  if((filename == final) || *final ) {/* No digits found, or something like 10ab */
171  if (flags & AVIO_FLAG_WRITE) {
172  fd = 1;
173  } else {
174  fd = 0;
175  }
176  }
177 #if HAVE_SETMODE
178  setmode(fd, O_BINARY);
179 #endif
180  c->fd = fd;
181  h->is_streamed = 1;
182  return 0;
183 }
184 
185 URLProtocol ff_pipe_protocol = {
186  .name = "pipe",
187  .url_open = pipe_open,
188  .url_read = file_read,
189  .url_write = file_write,
190  .url_get_file_handle = file_get_handle,
191  .url_check = file_check,
192  .priv_data_size = sizeof(FileContext),
193 };
194 
195 #endif /* CONFIG_PIPE_PROTOCOL */