X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fsavewd.c;h=728bc8a7c8c7b2b5c8a1000f4ca13d11c09b38bc;hb=43fd1e7b5a01623bc59fcf68254ce5be8e0b8d42;hp=bd3d118452ea38d2bc4c97510b6a06e4964606b0;hpb=68aa9462de8a606c435c416a2a0ef94e0f0c40b1;p=gnulib.git diff --git a/lib/savewd.c b/lib/savewd.c index bd3d11845..728bc8a7c 100644 --- a/lib/savewd.c +++ b/lib/savewd.c @@ -1,11 +1,11 @@ /* Save and restore the working directory, possibly using a child process. - Copyright (C) 2006 Free Software Foundation, Inc. + Copyright (C) 2006-2007, 2009-2013 Free Software Foundation, Inc. - This program is free software; you can redistribute it and/or modify + 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 2, or (at your option) - any later version. + 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 @@ -13,13 +13,14 @@ 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, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + along with this program. If not, see . */ /* Written by Paul Eggert. */ #include +#define SAVEWD_INLINE _GL_EXTERN_INLINE + #include "savewd.h" #include @@ -27,15 +28,14 @@ #include #include #include +#include #include #include #include -#include "exit.h" -#include "dirname.h" +#include "dosname.h" #include "fcntl-safer.h" - /* Save the working directory into *WD, if it hasn't been saved already. Return true if a child has been forked to do the real work. */ @@ -47,38 +47,38 @@ savewd_save (struct savewd *wd) case INITIAL_STATE: /* Save the working directory, or prepare to fall back if possible. */ { - int fd = open_safer (".", O_RDONLY); - if (0 <= fd) - { - wd->state = FD_STATE; - wd->val.fd = fd; - break; - } - if (errno != EACCES) - { - wd->state = ERROR_STATE; - wd->val.errnum = errno; - break; - } + int fd = open_safer (".", O_SEARCH); + if (0 <= fd) + { + wd->state = FD_STATE; + wd->val.fd = fd; + break; + } + if (errno != EACCES && errno != ESTALE) + { + wd->state = ERROR_STATE; + wd->val.errnum = errno; + break; + } } wd->state = FORKING_STATE; wd->val.child = -1; /* Fall through. */ case FORKING_STATE: if (wd->val.child < 0) - { - /* "Save" the initial working directory by forking a new - subprocess that will attempt all the work from the chdir - until until the next savewd_restore. */ - wd->val.child = fork (); - if (wd->val.child != 0) - { - if (0 < wd->val.child) - return true; - wd->state = ERROR_STATE; - wd->val.errnum = errno; - } - } + { + /* "Save" the initial working directory by forking a new + subprocess that will attempt all the work from the chdir + until until the next savewd_restore. */ + wd->val.child = fork (); + if (wd->val.child != 0) + { + if (0 < wd->val.child) + return true; + wd->state = ERROR_STATE; + wd->val.errnum = errno; + } + } break; case FD_STATE: @@ -96,60 +96,61 @@ savewd_save (struct savewd *wd) int savewd_chdir (struct savewd *wd, char const *dir, int options, - int open_result[2]) + int open_result[2]) { int fd = -1; int result = 0; /* Open the directory if requested, or if avoiding a race condition is requested and possible. */ - if (open_result || (options & (O_NOFOLLOW ? SAVEWD_CHDIR_NOFOLLOW : 0))) + if (open_result + || (options & (HAVE_WORKING_O_NOFOLLOW ? SAVEWD_CHDIR_NOFOLLOW : 0))) { fd = open (dir, - (O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK - | (options & SAVEWD_CHDIR_NOFOLLOW ? O_NOFOLLOW : 0))); + (O_SEARCH | O_DIRECTORY | O_NOCTTY | O_NONBLOCK + | (options & SAVEWD_CHDIR_NOFOLLOW ? O_NOFOLLOW : 0))); if (open_result) - { - open_result[0] = fd; - open_result[1] = errno; - } + { + open_result[0] = fd; + open_result[1] = errno; + } if (fd < 0 && (errno != EACCES || (options & SAVEWD_CHDIR_READABLE))) - result = -1; + result = -1; } if (result == 0 && ! (0 <= fd && options & SAVEWD_CHDIR_SKIP_READABLE)) { if (savewd_save (wd)) - { - open_result = NULL; - result = -2; - } + { + open_result = NULL; + result = -2; + } else - { - result = (fd < 0 ? chdir (dir) : fchdir (fd)); - - if (result == 0) - switch (wd->state) - { - case FD_STATE: - wd->state = FD_POST_CHDIR_STATE; - break; - - case ERROR_STATE: - case FD_POST_CHDIR_STATE: - case FINAL_STATE: - break; - - case FORKING_STATE: - assert (wd->val.child == 0); - break; - - default: - assert (false); - } - } + { + result = (fd < 0 ? chdir (dir) : fchdir (fd)); + + if (result == 0) + switch (wd->state) + { + case FD_STATE: + wd->state = FD_POST_CHDIR_STATE; + break; + + case ERROR_STATE: + case FD_POST_CHDIR_STATE: + case FINAL_STATE: + break; + + case FORKING_STATE: + assert (wd->val.child == 0); + break; + + default: + assert (false); + } + } } if (0 <= fd && ! open_result) @@ -170,23 +171,23 @@ savewd_restore (struct savewd *wd, int status) case INITIAL_STATE: case FD_STATE: /* The working directory is the desired directory, so there's no - work to do. */ + work to do. */ break; case FD_POST_CHDIR_STATE: /* Restore the working directory using fchdir. */ if (fchdir (wd->val.fd) == 0) - { - wd->state = FD_STATE; - break; - } + { + wd->state = FD_STATE; + break; + } else - { - int chdir_errno = errno; - close (wd->val.fd); - wd->state = ERROR_STATE; - wd->val.errnum = chdir_errno; - } + { + int chdir_errno = errno; + close (wd->val.fd); + wd->state = ERROR_STATE; + wd->val.errnum = chdir_errno; + } /* Fall through. */ case ERROR_STATE: /* Report an error if asked to restore the working directory. */ @@ -195,21 +196,21 @@ savewd_restore (struct savewd *wd, int status) case FORKING_STATE: /* "Restore" the working directory by waiting for the subprocess - to finish. */ + to finish. */ { - pid_t child = wd->val.child; - if (child == 0) - _exit (status); - if (0 < child) - { - int child_status; - while (waitpid (child, &child_status, 0) < 0) - assert (errno == EINTR); - wd->val.child = -1; - if (! WIFEXITED (child_status)) - raise (WTERMSIG (child_status)); - return WEXITSTATUS (child_status); - } + pid_t child = wd->val.child; + if (child == 0) + _exit (status); + if (0 < child) + { + int child_status; + while (waitpid (child, &child_status, 0) < 0) + assert (errno == EINTR); + wd->val.child = -1; + if (! WIFEXITED (child_status)) + raise (WTERMSIG (child_status)); + return WEXITSTATUS (child_status); + } } break; @@ -255,7 +256,7 @@ savewd_finish (struct savewd *wd) This is why savewd_chdir is broken out into another function; savewd_chdir's callers _can_ inspect the file system to decide whether to call savewd_chdir. */ -static inline bool +static bool savewd_delegating (struct savewd const *wd) { return wd->state == FORKING_STATE && 0 < wd->val.child; @@ -263,8 +264,8 @@ savewd_delegating (struct savewd const *wd) int savewd_process_files (int n_files, char **file, - int (*act) (char *, struct savewd *, void *), - void *options) + int (*act) (char *, struct savewd *, void *), + void *options) { int i = 0; int last_relative; @@ -279,18 +280,18 @@ savewd_process_files (int n_files, char **file, for (; i < last_relative; i++) { if (! savewd_delegating (&wd)) - { - int s = act (file[i], &wd, options); - if (exit_status < s) - exit_status = s; - } + { + int s = act (file[i], &wd, options); + if (exit_status < s) + exit_status = s; + } if (! IS_ABSOLUTE_FILE_NAME (file[i + 1])) - { - int r = savewd_restore (&wd, exit_status); - if (exit_status < r) - exit_status = r; - } + { + int r = savewd_restore (&wd, exit_status); + if (exit_status < r) + exit_status = r; + } } savewd_finish (&wd); @@ -299,7 +300,7 @@ savewd_process_files (int n_files, char **file, { int s = act (file[i], &wd, options); if (exit_status < s) - exit_status = s; + exit_status = s; } return exit_status;