X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=gnu%2Ffdopendir.c;h=5c5ac67acda3df647cade44c47f33a5191e1403c;hb=1a44d77d50f4fb37c0410eed04b82303624ea2ec;hp=544bf5d5c2a572b12c37d6526b821805e88d7aa4;hpb=dda6367c9eac71da8f2ab1c60b3df60f19ce4755;p=debian%2Ftar diff --git a/gnu/fdopendir.c b/gnu/fdopendir.c index 544bf5d5..5c5ac67a 100644 --- a/gnu/fdopendir.c +++ b/gnu/fdopendir.c @@ -1,7 +1,7 @@ /* -*- buffer-read-only: t -*- vi: set ro: */ /* DO NOT EDIT! GENERATED AUTOMATICALLY! */ /* provide a replacement fdopendir function - Copyright (C) 2004-2010 Free Software Foundation, Inc. + Copyright (C) 2004-2011 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -35,12 +35,16 @@ # include "dirent--.h" # endif -static DIR *fdopendir_with_dup (int, int); -static DIR *fd_clone_opendir (int); +# ifndef REPLACE_FCHDIR +# define REPLACE_FCHDIR 0 +# endif + +static DIR *fdopendir_with_dup (int, int, struct saved_cwd const *); +static DIR *fd_clone_opendir (int, struct saved_cwd const *); /* Replacement for POSIX fdopendir. - First, try to simulate it via opendir ("/proc/self/fd/FD"). Failing + First, try to simulate it via opendir ("/proc/self/fd/..."). Failing that, simulate it by using fchdir metadata, or by doing save_cwd/fchdir/opendir(".")/restore_cwd. If either the save_cwd or the restore_cwd fails (relatively unlikely), @@ -63,7 +67,24 @@ static DIR *fd_clone_opendir (int); DIR * fdopendir (int fd) { - return fdopendir_with_dup (fd, -1); + DIR *dir = fdopendir_with_dup (fd, -1, NULL); + + if (! REPLACE_FCHDIR && ! dir) + { + int saved_errno = errno; + if (EXPECTED_ERRNO (saved_errno)) + { + struct saved_cwd cwd; + if (save_cwd (&cwd) != 0) + openat_save_fail (errno); + dir = fdopendir_with_dup (fd, -1, &cwd); + saved_errno = errno; + free_cwd (&cwd); + errno = saved_errno; + } + } + + return dir; } /* Like fdopendir, except that if OLDER_DUPFD is not -1, it is known @@ -72,9 +93,13 @@ fdopendir (int fd) function makes sure that FD is closed and all file descriptors less than FD are open, and then calls fd_clone_opendir on a dup of FD. That way, barring race conditions, fd_clone_opendir returns a - stream whose file descriptor is FD. */ + stream whose file descriptor is FD. + + If REPLACE_CHDIR or CWD is null, use opendir ("/proc/self/fd/...", + falling back on fchdir metadata. Otherwise, CWD is a saved version + of the working directory; use fchdir/opendir(".")/restore_cwd(CWD). */ static DIR * -fdopendir_with_dup (int fd, int older_dupfd) +fdopendir_with_dup (int fd, int older_dupfd, struct saved_cwd const *cwd) { int dupfd = dup (fd); if (dupfd < 0 && errno == EMFILE) @@ -87,13 +112,13 @@ fdopendir_with_dup (int fd, int older_dupfd) int saved_errno; if (dupfd < fd - 1 && dupfd != older_dupfd) { - dir = fdopendir_with_dup (fd, dupfd); + dir = fdopendir_with_dup (fd, dupfd, cwd); saved_errno = errno; } else { close (fd); - dir = fd_clone_opendir (dupfd); + dir = fd_clone_opendir (dupfd, cwd); saved_errno = errno; if (! dir) { @@ -114,74 +139,45 @@ fdopendir_with_dup (int fd, int older_dupfd) the caller's responsibility both to close FD and (if the result is not null) to closedir the result. */ static DIR * -fd_clone_opendir (int fd) +fd_clone_opendir (int fd, struct saved_cwd const *cwd) { - int saved_errno; - DIR *dir; - - char buf[OPENAT_BUFFER_SIZE]; - char *proc_file = openat_proc_name (buf, fd, "."); - if (proc_file) - { - dir = opendir (proc_file); - saved_errno = errno; - } - else + if (REPLACE_FCHDIR || ! cwd) { - dir = NULL; - saved_errno = EOPNOTSUPP; - } - - /* If the syscall fails with an expected errno value, resort to - save_cwd/restore_cwd. */ - if (! dir && EXPECTED_ERRNO (saved_errno)) - { -# if REPLACE_FCHDIR - const char *name = _gl_directory_name (fd); - if (name) - dir = opendir (name); - saved_errno = errno; -# else /* !REPLACE_FCHDIR */ - - /* Occupy the destination FD slot, so that save_cwd cannot hijack it. */ - int fd_reserve = dup (fd); - if (fd_reserve < 0) + DIR *dir = NULL; + int saved_errno = EOPNOTSUPP; + char buf[OPENAT_BUFFER_SIZE]; + char *proc_file = openat_proc_name (buf, fd, "."); + if (proc_file) { + dir = opendir (proc_file); saved_errno = errno; - dir = NULL; - goto fail; + if (proc_file != buf) + free (proc_file); } - - struct saved_cwd saved_cwd; - if (save_cwd (&saved_cwd) != 0) - openat_save_fail (errno); - - /* Liberate the target file descriptor, so that opendir uses it. */ - close (fd_reserve); - - if (fchdir (fd) != 0) +# if REPLACE_FCHDIR + if (! dir && EXPECTED_ERRNO (saved_errno)) { - dir = NULL; - saved_errno = errno; + char const *name = _gl_directory_name (fd); + return (name ? opendir (name) : NULL); } +# endif + errno = saved_errno; + return dir; + } + else + { + if (fchdir (fd) != 0) + return NULL; else { - dir = opendir ("."); - saved_errno = errno; - - if (restore_cwd (&saved_cwd) != 0) + DIR *dir = opendir ("."); + int saved_errno = errno; + if (restore_cwd (cwd) != 0) openat_restore_fail (errno); + errno = saved_errno; + return dir; } - - free_cwd (&saved_cwd); -# endif /* !REPLACE_FCHDIR */ } - - fail: - if (proc_file != buf) - free (proc_file); - errno = saved_errno; - return dir; } #else /* HAVE_FDOPENDIR */