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
30 #if HAVE_DIRENT_H
31 #include <dirent.h>
32 #endif
33 #include <fcntl.h>
34 #if HAVE_IO_H
35 #include <io.h>
36 #endif
37 #if HAVE_UNISTD_H
38 #include <unistd.h>
39 #endif
40 #include <sys/stat.h>
41 #include <stdlib.h>
44
45 /* Some systems may not have S_ISFIFO */
46 #ifndef S_ISFIFO
47 # ifdef S_IFIFO
48 # define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO)
49 # else
50 # define S_ISFIFO(m) 0
51 # endif
52 #endif
53
54 /* Not available in POSIX.1-1996 */
55 #ifndef S_ISLNK
56 # ifdef S_IFLNK
57 # define S_ISLNK(m) (((m) & S_IFLNK) == S_IFLNK)
58 # else
60 # endif
61 #endif
62
63 /* Not available in POSIX.1-1996 */
64 #ifndef S_ISSOCK
65 # ifdef S_IFSOCK
66 # define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK)
67 # else
68 # define S_ISSOCK(m) 0
69 # endif
70 #endif
71
72 /* S_ISREG not available on Windows */
73 #ifndef S_ISREG
74 # ifdef S_IFREG
75 # define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
76 # else
78 # endif
79 #endif
80
81 /* S_ISBLK not available on Windows */
82 #ifndef S_ISBLK
83 # ifdef S_IFBLK
84 # define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK)
85 # else
87 # endif
88 #endif
89
90 /* standard file protocol */
91
99 #if HAVE_DIRENT_H
100 DIR *dir;
101 #endif
103
110 };
111
116 };
117
123 };
124
130 };
131
137 };
138
140 {
145 if (
ret == 0 &&
c->follow)
150 }
151
153 {
159 }
160
162 {
165 }
166
168 {
170 const char *filename =
h->filename;
172
173 {
174 #if HAVE_ACCESS && defined(R_OK)
175 if (access(filename, F_OK) < 0)
178 if (access(filename, R_OK) >= 0)
181 if (access(filename, W_OK) >= 0)
183 #else
184 struct stat st;
185 ret = stat(filename, &st);
188
191 #endif
192 }
194 }
195
196 #if CONFIG_FD_PROTOCOL || CONFIG_PIPE_PROTOCOL
198 {
199 int newfd;
200
201 #ifdef F_DUPFD_CLOEXEC
202 newfd = fcntl(oldfd, F_DUPFD_CLOEXEC, 0);
203 #else
204 newfd = dup(oldfd);
205 #endif
206 if (newfd == -1)
207 return newfd;
208
209 #if HAVE_FCNTL
210 if (fcntl(newfd, F_SETFD, FD_CLOEXEC) == -1)
212 #endif
213
214 #if HAVE_SETMODE
216 #endif
217 return newfd;
218 }
219 #endif
220
222 {
224 int ret = close(
c->fd);
226 }
227
228 /* XXX: use llseek */
230 {
233
235 struct stat st;
236 ret = fstat(
c->fd, &st);
238 }
239
240 ret = lseek(
c->fd,
pos, whence);
241
243 }
244
245 #if CONFIG_FILE_PROTOCOL
246
248 {
249 #if HAVE_UNISTD_H
251 const char *filename =
h->filename;
253
254 ret = rmdir(filename);
255 if (
ret < 0 && (errno == ENOTDIR
256 # ifdef _WIN32
257 || errno == EINVAL
258 # endif
259 ))
260 ret = unlink(filename);
263
265 #else
267 #endif /* HAVE_UNISTD_H */
268 }
269
271 {
272 const char *filename_src = h_src->
filename;
273 const char *filename_dst = h_dst->
filename;
276
277 if (rename(filename_src, filename_dst) < 0)
279
280 return 0;
281 }
282
284 {
286 int access;
287 int fd;
288 struct stat st;
289
291
293 access = O_CREAT | O_RDWR;
295 access |= O_TRUNC;
297 access = O_CREAT | O_WRONLY;
299 access |= O_TRUNC;
300 } else {
301 access = O_RDONLY;
302 }
303 #ifdef O_BINARY
305 #endif
307 if (fd == -1)
310
311 h->is_streamed = !fstat(fd, &st) &&
S_ISFIFO(st.st_mode);
312
313 /* Buffer writes more than the default 32k to improve throughput especially
314 * with networked file systems */
316 h->min_packet_size =
h->max_packet_size = 262144;
317
318 if (
c->seekable >= 0)
319 h->is_streamed = !
c->seekable;
320
321 return 0;
322 }
323
325 {
326 #if HAVE_LSTAT
328
329 c->dir = opendir(
h->filename);
332
333 return 0;
334 #else
336 #endif /* HAVE_LSTAT */
337 }
338
340 {
341 #if HAVE_LSTAT
343 struct dirent *dir;
344 char *fullpath =
NULL;
345
347 if (!*next)
349 do {
350 errno = 0;
351 dir = readdir(
c->dir);
352 if (!dir) {
355 }
356 } while (!strcmp(dir->d_name, ".") || !strcmp(dir->d_name, ".."));
357
359 if (fullpath) {
360 struct stat st;
361 if (!lstat(fullpath, &st)) {
362 if (S_ISDIR(st.st_mode))
366 else if (S_ISCHR(st.st_mode))
376 else
378
379 (*next)->group_id = st.st_gid;
380 (*next)->user_id = st.st_uid;
381 (*next)->size = st.st_size;
382 (*next)->filemode = st.st_mode & 0777;
383 (*next)->modification_timestamp = INT64_C(1000000) * st.st_mtime;
384 (*next)->access_timestamp = INT64_C(1000000) * st.st_atime;
385 (*next)->status_change_timestamp = INT64_C(1000000) * st.st_ctime;
386 }
388 }
389
391 return 0;
392 #else
394 #endif /* HAVE_LSTAT */
395 }
396
398 {
399 #if HAVE_LSTAT
402 return 0;
403 #else
405 #endif /* HAVE_LSTAT */
406 }
407
410 .url_open = file_open,
417 .url_delete = file_delete,
418 .url_move = file_move,
421 .url_open_dir = file_open_dir,
422 .url_read_dir = file_read_dir,
423 .url_close_dir = file_close_dir,
424 .default_whitelist = "file,crypto,data"
425 };
426
427 #endif /* CONFIG_FILE_PROTOCOL */
428
429 #if CONFIG_PIPE_PROTOCOL
430
432 {
434 int fd;
435 char *final;
436
439
440 if (!*filename) {
442 fd = 1;
443 } else {
444 fd = 0;
445 }
446 } else {
447 fd = strtol(filename, &final, 10);
448 if (*final) /* No digits found, or something like 10ab */
450 }
452 }
453
454 c->fd = fd_dup(
h,
c->fd);
458 return 0;
459 }
460
463 .url_open = pipe_open,
471 .default_whitelist = "crypto,data"
472 };
473
474 #endif /* CONFIG_PIPE_PROTOCOL */
475
476 #if CONFIG_FD_PROTOCOL
477
479 {
481 struct stat st;
482
483 if (strcmp(filename, "fd:") != 0) {
485 " please set it via -fd {num}\n");
487 }
488
492 } else {
494 }
495 }
496 if (fstat(
c->fd, &st) < 0)
499 c->fd = fd_dup(
h,
c->fd);
502
503 return 0;
504 }
505
508 .url_open = fd_open,
517 .default_whitelist = "crypto,data"
518 };
519
520 #endif /* CONFIG_FD_PROTOCOL */
521
522 #if CONFIG_ANDROID_CONTENT_PROTOCOL
526
527 typedef struct JFields {
528 jclass uri_class;
529 jmethodID parse_id;
530
531 jclass context_class;
532 jmethodID get_content_resolver_id;
533
534 jclass content_resolver_class;
535 jmethodID open_file_descriptor_id;
536
537 jclass parcel_file_descriptor_class;
538 jmethodID detach_fd_id;
539 } JFields;
540
541 #define OFFSET(x) offsetof(JFields, x)
542 static const struct FFJniField jfields_mapping[] = {
545
547 {
"android/content/Context",
"getContentResolver",
"()Landroid/content/ContentResolver;",
FF_JNI_METHOD,
OFFSET(get_content_resolver_id), 1 },
548
550 {
"android/content/ContentResolver",
"openFileDescriptor",
"(Landroid/net/Uri;Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;",
FF_JNI_METHOD,
OFFSET(open_file_descriptor_id), 1 },
551
553 {
"android/os/ParcelFileDescriptor",
"detachFd",
"()I",
FF_JNI_METHOD,
OFFSET(detach_fd_id), 1 },
554
556 };
557 #undef OFFSET
558
559 static int android_content_open(
URLContext *
h,
const char *filename,
int flags)
560 {
563 struct stat st;
564 const char *mode_str = "r";
565
566 JNIEnv *env;
567 JFields jfields = { 0 };
568 jobject application_context =
NULL;
572 jobject content_resolver =
NULL;
573 jobject parcel_file_descriptor =
NULL;
574
576 if (!env) {
578 }
579
584 }
585
587 if (!application_context) {
590 goto done;
591 }
592
594 if (!url) {
596 goto done;
597 }
598
600 mode_str = "rw";
602 mode_str = "w";
603
607 goto done;
608 }
609
610 uri = (*env)->CallStaticObjectMethod(env, jfields.uri_class, jfields.parse_id, url);
613 goto done;
614
615 content_resolver = (*env)->CallObjectMethod(env, application_context, jfields.get_content_resolver_id);
618 goto done;
619
620 parcel_file_descriptor = (*env)->CallObjectMethod(env, content_resolver, jfields.open_file_descriptor_id, uri,
mode);
623 goto done;
624
625 fd = (*env)->CallIntMethod(env, parcel_file_descriptor, jfields.detach_fd_id);
628 goto done;
629
630 if (fstat(fd, &st) < 0) {
631 close(fd);
633 }
634
637
638 done:
639 (*env)->DeleteLocalRef(env, url);
640 (*env)->DeleteLocalRef(env,
mode);
641 (*env)->DeleteLocalRef(env, uri);
642 (*env)->DeleteLocalRef(env, content_resolver);
643 (*env)->DeleteLocalRef(env, parcel_file_descriptor);
645
647 }
648
649 static const AVOption android_content_options[] = {
652 };
653
654 static const AVClass android_content_class = {
657 .option = android_content_options,
659 };
660
663 .url_open = android_content_open,
671 .priv_data_class = &android_content_class,
672 };
673
674 #endif /* CONFIG_ANDROID_CONTENT_PROTOCOL */