X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fopenat.c;h=929d264924c4cf93fe38ec0031044ddc15099ec0;hb=fb84631f1ec8e82d252cbad0b5b7f83a98e74ba9;hp=fe539de164f4f446a2c978e75eb71f4521cee95e;hpb=267a39bafd249d7eb9c37df06dc6defcf41cb343;p=gnulib.git diff --git a/lib/openat.c b/lib/openat.c index fe539de16..929d26492 100644 --- a/lib/openat.c +++ b/lib/openat.c @@ -17,7 +17,9 @@ /* written by Jim Meyering */ -#include +#ifdef HAVE_CONFIG_H +# include +#endif #include "openat.h" @@ -27,8 +29,7 @@ #include #include -#include "error.h" -#include "exitfail.h" +#include "dirname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */ #include "save-cwd.h" #include "gettext.h" @@ -43,7 +44,7 @@ Otherwise, upon failure, set errno and return -1, as openat does. Upon successful completion, return a file descriptor. */ int -rpl_openat (int fd, char const *filename, int flags, ...) +rpl_openat (int fd, char const *file, int flags, ...) { struct saved_cwd saved_cwd; int saved_errno; @@ -62,12 +63,11 @@ rpl_openat (int fd, char const *filename, int flags, ...) va_end (arg); } - if (fd == AT_FDCWD || *filename == '/') - return open (filename, flags, mode); + if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file)) + return open (file, flags, mode); if (save_cwd (&saved_cwd) != 0) - error (exit_failure, errno, - _("openat: unable to record current working directory")); + openat_save_fail (errno); if (fchdir (fd) != 0) { @@ -77,12 +77,11 @@ rpl_openat (int fd, char const *filename, int flags, ...) return -1; } - new_fd = open (filename, flags, mode); + new_fd = open (file, flags, mode); saved_errno = errno; if (restore_cwd (&saved_cwd) != 0) - error (exit_failure, errno, - _("openat: unable to restore working directory")); + openat_restore_fail (errno); free_cwd (&saved_cwd); @@ -90,13 +89,20 @@ rpl_openat (int fd, char const *filename, int flags, ...) return new_fd; } +#if !HAVE_FDOPENDIR + /* Replacement for Solaris' function by the same name. Simulate it by doing save_cwd/fchdir/opendir(".")/restore_cwd. If either the save_cwd or the restore_cwd fails (relatively unlikely, and usually indicative of a problem that deserves close attention), then give a diagnostic and exit nonzero. - Otherwise, this function works just like Solaris' fdopendir. */ + Otherwise, this function works just like Solaris' fdopendir. + + W A R N I N G: + Unlike the other fd-related functions here, this one + effectively consumes its FD parameter. The caller should not + close or otherwise manipulate FD if this function returns successfully. */ DIR * fdopendir (int fd) { @@ -104,12 +110,8 @@ fdopendir (int fd) int saved_errno; DIR *dir; - if (fd == AT_FDCWD) - return opendir ("."); - if (save_cwd (&saved_cwd) != 0) - error (exit_failure, errno, - _("fdopendir: unable to record current working directory")); + openat_save_fail (errno); if (fchdir (fd) != 0) { @@ -123,15 +125,18 @@ fdopendir (int fd) saved_errno = errno; if (restore_cwd (&saved_cwd) != 0) - error (exit_failure, errno, - _("fdopendir: unable to restore working directory")); + openat_restore_fail (errno); free_cwd (&saved_cwd); + if (dir) + close (fd); errno = saved_errno; return dir; } +#endif + /* Replacement for Solaris' function by the same name. Simulate it by doing save_cwd/fchdir/(stat|lstat)/restore_cwd. @@ -140,7 +145,7 @@ fdopendir (int fd) then give a diagnostic and exit nonzero. Otherwise, this function works just like Solaris' fstatat. */ int -fstatat (int fd, char const *filename, struct stat *st, int flag) +fstatat (int fd, char const *file, struct stat *st, int flag) { struct saved_cwd saved_cwd; int saved_errno; @@ -148,12 +153,11 @@ fstatat (int fd, char const *filename, struct stat *st, int flag) if (fd == AT_FDCWD) return (flag == AT_SYMLINK_NOFOLLOW - ? lstat (filename, st) - : stat (filename, st)); + ? lstat (file, st) + : stat (file, st)); if (save_cwd (&saved_cwd) != 0) - error (exit_failure, errno, - _("fstatat: unable to record current working directory")); + openat_save_fail (errno); if (fchdir (fd) != 0) { @@ -164,13 +168,52 @@ fstatat (int fd, char const *filename, struct stat *st, int flag) } err = (flag == AT_SYMLINK_NOFOLLOW - ? lstat (filename, st) - : stat (filename, st)); + ? lstat (file, st) + : stat (file, st)); + saved_errno = errno; + + if (restore_cwd (&saved_cwd) != 0) + openat_restore_fail (errno); + + free_cwd (&saved_cwd); + + errno = saved_errno; + return err; +} + +/* Replacement for Solaris' function by the same name. + + Simulate it by doing save_cwd/fchdir/(unlink|rmdir)/restore_cwd. + If either the save_cwd or the restore_cwd fails (relatively unlikely, + and usually indicative of a problem that deserves close attention), + then give a diagnostic and exit nonzero. + Otherwise, this function works just like Solaris' unlinkat. */ +int +unlinkat (int fd, char const *file, int flag) +{ + struct saved_cwd saved_cwd; + int saved_errno; + int err; + + if (fd == AT_FDCWD) + return (flag == AT_REMOVEDIR ? rmdir (file) : unlink (file)); + + if (save_cwd (&saved_cwd) != 0) + openat_save_fail (errno); + + if (fchdir (fd) != 0) + { + saved_errno = errno; + free_cwd (&saved_cwd); + errno = saved_errno; + return -1; + } + + err = (flag == AT_REMOVEDIR ? rmdir (file) : unlink (file)); saved_errno = errno; if (restore_cwd (&saved_cwd) != 0) - error (exit_failure, errno, - _("fstatat: unable to restore working directory")); + openat_restore_fail (errno); free_cwd (&saved_cwd);