diff options
author | Eric Blake <ebb9@byu.net> | 2009-08-31 20:37:59 -0600 |
---|---|---|
committer | Eric Blake <ebb9@byu.net> | 2009-09-02 19:14:47 -0600 |
commit | d1aa3e40286ed2b0ad1045b326a37167ac5d8847 (patch) | |
tree | 32d49df867d41bdbf658a777b1198285f50f68eb /lib/fdopendir.c | |
parent | dd66a62cc2d76ab463e1167824ea4ca5fd4ef2ae (diff) | |
download | gnulib-d1aa3e40286ed2b0ad1045b326a37167ac5d8847.tar.gz |
fdopendir: split into its own module
* lib/openat.c (fdopendir): Move...
* lib/fdopendir.c: ...into new file.
* modules/fdopendir: New module.
* m4/fdopendir.m4 (gl_FUNC_FDOPENDIR): New file.
* modules/openat (Depends-on): Add fdopendir.
* m4/openat.m4 (gl_FUNC_OPENAT): No longer need to check for
fdopendir here.
* modules/savedir (Depends-on): Only need fdopendir, not full
openat.
* lib/savedir.c (include): Use <dirent.h>, not "openat.h".
* lib/openat.h (fdopendir): Drop prototype.
* lib/dirent.in.h (fdopendir): Provide prototype.
* m4/dirent_h.m4 (gl_DIRENT_H_DEFAULTS): Add replacements.
* modules/dirent (Makefile.am): Substitute them.
* MODULES.html.sh (File system functions): Mention it.
* doc/posix-functions/fdopendir.texi (fdopendir): Likewise.
* modules/fdopendir-tests: New file.
* tests/test-fdopendir.c: Likewise.
Signed-off-by: Eric Blake <ebb9@byu.net>
Diffstat (limited to 'lib/fdopendir.c')
-rw-r--r-- | lib/fdopendir.c | 95 |
1 files changed, 95 insertions, 0 deletions
diff --git a/lib/fdopendir.c b/lib/fdopendir.c new file mode 100644 index 0000000000..70951562f4 --- /dev/null +++ b/lib/fdopendir.c @@ -0,0 +1,95 @@ +/* provide a replacement fdopendir function + Copyright (C) 2004-2009 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 + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* written by Jim Meyering */ + +#include <config.h> + +#include <dirent.h> + +#include <stdlib.h> +#include <unistd.h> + +#include "openat.h" +#include "openat-priv.h" +#include "save-cwd.h" + +/* Replacement for Solaris' function by the same name. + <http://www.google.com/search?q=fdopendir+site:docs.sun.com> + First, try to simulate it via opendir ("/proc/self/fd/FD"). Failing + that, simulate it by doing save_cwd/fchdir/opendir(".")/restore_cwd. + If either the save_cwd or the restore_cwd fails (relatively unlikely), + then give a diagnostic and exit nonzero. + Otherwise, this function works just like Solaris' fdopendir. + + W A R N I N G: + Unlike other fd-related functions, this one effectively consumes + its FD parameter. The caller should not close or otherwise + manipulate FD if this function returns successfully. Also, this + implementation does not guarantee that dirfd(fdopendir(n))==n; + the open directory stream may use a clone of FD, or have no + associated fd at all. */ +DIR * +fdopendir (int fd) +{ + struct saved_cwd saved_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 + { + 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 (save_cwd (&saved_cwd) != 0) + openat_save_fail (errno); + + if (fchdir (fd) != 0) + { + dir = NULL; + saved_errno = errno; + } + else + { + dir = opendir ("."); + saved_errno = errno; + + if (restore_cwd (&saved_cwd) != 0) + openat_restore_fail (errno); + } + + free_cwd (&saved_cwd); + } + + if (dir) + close (fd); + if (proc_file != buf) + free (proc_file); + errno = saved_errno; + return dir; +} |