diff options
author | Jim Meyering <jim@meyering.net> | 2007-03-28 23:39:18 +0200 |
---|---|---|
committer | Jim Meyering <jim@meyering.net> | 2007-03-28 23:39:18 +0200 |
commit | 0f63eebd1ea9cce137deef4ac98b85905465f6db (patch) | |
tree | 7dea3df3b627bfb753d702ef13c214f523da2c01 /gl/lib | |
parent | 93ff956de7f4895158a72248fc59840e87df906a (diff) | |
parent | a0faff1a58a96e008f45ab7c00e790dd2c397363 (diff) | |
download | coreutils-0f63eebd1ea9cce137deef4ac98b85905465f6db.tar.xz |
Merge branch 'master' of /cu
Diffstat (limited to 'gl/lib')
-rw-r--r-- | gl/lib/acl.c | 426 | ||||
-rw-r--r-- | gl/lib/savewd.c | 308 |
2 files changed, 0 insertions, 734 deletions
diff --git a/gl/lib/acl.c b/gl/lib/acl.c deleted file mode 100644 index 96153d41c..000000000 --- a/gl/lib/acl.c +++ /dev/null @@ -1,426 +0,0 @@ -/* acl.c - access control lists - - Copyright (C) 2002, 2003, 2005, 2006, 2007 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 2, 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, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - - Written by Paul Eggert and Andreas Gruenbacher. */ - -#include <config.h> - -#include "acl.h" - -#include <stdbool.h> -#include <stdlib.h> -#include <string.h> -#ifndef S_ISLNK -# define S_ISLNK(Mode) 0 -#endif - -#ifdef HAVE_ACL_LIBACL_H -# include <acl/libacl.h> -#endif - -#include "error.h" -#include "quote.h" - -#include <errno.h> -#ifndef ENOSYS -# define ENOSYS (-1) -#endif -#ifndef ENOTSUP -# define ENOTSUP (-1) -#endif - -#if ENABLE_NLS -# include <libintl.h> -# define _(Text) gettext (Text) -#else -# define _(Text) Text -#endif - -#ifndef HAVE_FCHMOD -# define HAVE_FCHMOD false -# define fchmod(fd, mode) (-1) -#endif - -/* POSIX 1003.1e (draft 17) */ -#ifndef HAVE_ACL_GET_FD -# define HAVE_ACL_GET_FD false -# define acl_get_fd(fd) (NULL) -#endif - -/* POSIX 1003.1e (draft 17) */ -#ifndef HAVE_ACL_SET_FD -# define HAVE_ACL_SET_FD false -# define acl_set_fd(fd, acl) (-1) -#endif - -/* Linux-specific */ -#ifndef HAVE_ACL_EXTENDED_FILE -# define HAVE_ACL_EXTENDED_FILE false -# define acl_extended_file(name) (-1) -#endif - -/* Linux-specific */ -#ifndef HAVE_ACL_FROM_MODE -# define HAVE_ACL_FROM_MODE false -# define acl_from_mode(mode) (NULL) -#endif - -#define ACL_NOT_WELL_SUPPORTED(Errno) \ - (Errno == ENOTSUP || Errno == ENOSYS || Errno == EINVAL) - -/* We detect the presence of POSIX 1003.1e (draft 17 -- abandoned) support - by checking for HAVE_ACL_GET_FILE, HAVE_ACL_SET_FILE, and HAVE_ACL_FREE. - Systems that have acl_get_file, acl_set_file, and acl_free must also - have acl_to_text, acl_from_text, and acl_delete_def_file (all defined - in the draft); systems that don't would hit #error statements here. */ - -#if USE_ACL && HAVE_ACL_GET_FILE && !HAVE_ACL_ENTRIES -# ifndef HAVE_ACL_TO_TEXT -# error Must have acl_to_text (see POSIX 1003.1e draft 17). -# endif - -/* Return the number of entries in ACL. Linux implements acl_entries - as a more efficient extension than using this workaround. */ - -static int -acl_entries (acl_t acl) -{ - char *text = acl_to_text (acl, NULL), *t; - int entries; - if (text == NULL) - return -1; - for (entries = 0, t = text; ; t++, entries++) { - t = strchr (t, '\n'); - if (t == NULL) - break; - } - acl_free (text); - return entries; -} -#endif - -/* If DESC is a valid file descriptor use fchmod to change the - file's mode to MODE on systems that have fchown. On systems - that don't have fchown and if DESC is invalid, use chown on - NAME instead. */ - -int -chmod_or_fchmod (const char *name, int desc, mode_t mode) -{ - if (HAVE_FCHMOD && desc != -1) - return fchmod (desc, mode); - else - return chmod (name, mode); -} - -#if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_SET_FILE && HAVE_ACL_FREE -/* FIXME: use acl_trivial instead, once we have a replacement function */ -static bool -is_trivial_acl (acl_t acl) -{ - int n = acl_entries (acl); - if (n <= 3) - return true; - if (5 <= n) - return false; - - /* Here, we know there are exactly 4 entries. - If they are for user, group, mask, and other, then return true; */ - /* FIXME */ - return false; -} -#endif - -/* Return 1 if NAME has a nontrivial access control list, 0 if - NAME only has no or a base access control list, and -1 on - error. SB must be set to the stat buffer of FILE. */ - -int -file_has_acl (char const *name, struct stat const *sb) -{ -#if USE_ACL && HAVE_ACL && defined GETACLCNT - /* This implementation should work on recent-enough versions of HP-UX, - Solaris, and Unixware. */ - -# ifndef MIN_ACL_ENTRIES -# define MIN_ACL_ENTRIES 4 -# endif - - if (! S_ISLNK (sb->st_mode)) - { - int n = acl (name, GETACLCNT, 0, NULL); - return n < 0 ? (errno == ENOSYS ? 0 : -1) : (MIN_ACL_ENTRIES < n); - } -#elif USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_FREE - /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ - - if (! S_ISLNK (sb->st_mode)) - { - int ret; - - if (HAVE_ACL_EXTENDED_FILE) - ret = acl_extended_file (name); - else - { - acl_t acl = acl_get_file (name, ACL_TYPE_ACCESS); - if (acl) - { - ret = !is_trivial_acl (acl); - acl_free (acl); - if (ret == 0 && S_ISDIR (sb->st_mode)) - { - acl = acl_get_file (name, ACL_TYPE_DEFAULT); - if (acl) - { - ret = (0 < acl_entries (acl)); - acl_free (acl); - } - else - ret = -1; - } - } - else - ret = -1; - } - if (ret < 0) - return ACL_NOT_WELL_SUPPORTED (errno) ? 0 : -1; - return ret; - } -#endif - - /* FIXME: Add support for AIX, Irix, and Tru64. Please see Samba's - source/lib/sysacls.c file for fix-related ideas. */ - - return 0; -} - -/* Copy access control lists from one file to another. If SOURCE_DESC is - a valid file descriptor, use file descriptor operations, else use - filename based operations on SRC_NAME. Likewise for DEST_DESC and - DEST_NAME. - If access control lists are not available, fchmod the target file to - MODE. Also sets the non-permission bits of the destination file - (S_ISUID, S_ISGID, S_ISVTX) to those from MODE if any are set. - System call return value semantics. */ - -int -copy_acl (const char *src_name, int source_desc, const char *dst_name, - int dest_desc, mode_t mode) -{ - int ret; - -#if USE_ACL && HAVE_ACL_GET_FILE && HAVE_ACL_SET_FILE && HAVE_ACL_FREE - /* POSIX 1003.1e (draft 17 -- abandoned) specific version. */ - - acl_t acl; - if (HAVE_ACL_GET_FD && source_desc != -1) - acl = acl_get_fd (source_desc); - else - acl = acl_get_file (src_name, ACL_TYPE_ACCESS); - if (acl == NULL) - { - if (ACL_NOT_WELL_SUPPORTED (errno)) - return set_acl (dst_name, dest_desc, mode); - else - { - error (0, errno, "%s", quote (src_name)); - return -1; - } - } - - if (HAVE_ACL_SET_FD && dest_desc != -1) - ret = acl_set_fd (dest_desc, acl); - else - ret = acl_set_file (dst_name, ACL_TYPE_ACCESS, acl); - if (ret != 0) - { - int saved_errno = errno; - - if (ACL_NOT_WELL_SUPPORTED (errno)) - { - bool trivial = is_trivial_acl (acl); - acl_free (acl); - if (trivial) - { - if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) - saved_errno = errno; - else - return 0; - } - else - chmod_or_fchmod (dst_name, dest_desc, mode); - } - else - { - acl_free (acl); - chmod_or_fchmod (dst_name, dest_desc, mode); - } - error (0, saved_errno, _("preserving permissions for %s"), - quote (dst_name)); - return -1; - } - else - acl_free (acl); - - if (mode & (S_ISUID | S_ISGID | S_ISVTX)) - { - /* We did not call chmod so far, so the special bits have not yet - been set. */ - - if (chmod_or_fchmod (dst_name, dest_desc, mode) != 0) - { - error (0, errno, _("preserving permissions for %s"), - quote (dst_name)); - return -1; - } - } - - if (S_ISDIR (mode)) - { - acl = acl_get_file (src_name, ACL_TYPE_DEFAULT); - if (acl == NULL) - { - error (0, errno, "%s", quote (src_name)); - return -1; - } - - if (acl_set_file (dst_name, ACL_TYPE_DEFAULT, acl)) - { - error (0, errno, _("preserving permissions for %s"), - quote (dst_name)); - acl_free (acl); - return -1; - } - else - acl_free (acl); - } - return 0; -#else - ret = chmod_or_fchmod (dst_name, dest_desc, mode); - if (ret != 0) - error (0, errno, _("preserving permissions for %s"), quote (dst_name)); - return ret; -#endif -} - -/* Set the access control lists of a file. If DESC is a valid file - descriptor, use file descriptor operations where available, else use - filename based operations on NAME. If access control lists are not - available, fchmod the target file to MODE. Also sets the - non-permission bits of the destination file (S_ISUID, S_ISGID, S_ISVTX) - to those from MODE if any are set. System call return value - semantics. */ - -int -set_acl (char const *name, int desc, mode_t mode) -{ -#if USE_ACL && HAVE_ACL_SET_FILE && HAVE_ACL_FREE - /* POSIX 1003.1e draft 17 (abandoned) specific version. */ - - /* We must also have have_acl_from_text and acl_delete_def_file. - (acl_delete_def_file could be emulated with acl_init followed - by acl_set_file, but acl_set_file with an empty acl is - unspecified.) */ - -# ifndef HAVE_ACL_FROM_TEXT -# error Must have acl_from_text (see POSIX 1003.1e draft 17). -# endif -# ifndef HAVE_ACL_DELETE_DEF_FILE -# error Must have acl_delete_def_file (see POSIX 1003.1e draft 17). -# endif - - acl_t acl; - int ret; - - if (HAVE_ACL_FROM_MODE) - { - acl = acl_from_mode (mode); - if (!acl) - { - error (0, errno, "%s", quote (name)); - return -1; - } - } - else - { - char acl_text[] = "u::---,g::---,o::---"; - - if (mode & S_IRUSR) acl_text[ 3] = 'r'; - if (mode & S_IWUSR) acl_text[ 4] = 'w'; - if (mode & S_IXUSR) acl_text[ 5] = 'x'; - if (mode & S_IRGRP) acl_text[10] = 'r'; - if (mode & S_IWGRP) acl_text[11] = 'w'; - if (mode & S_IXGRP) acl_text[12] = 'x'; - if (mode & S_IROTH) acl_text[17] = 'r'; - if (mode & S_IWOTH) acl_text[18] = 'w'; - if (mode & S_IXOTH) acl_text[19] = 'x'; - - acl = acl_from_text (acl_text); - if (!acl) - { - error (0, errno, "%s", quote (name)); - return -1; - } - } - if (HAVE_ACL_SET_FD && desc != -1) - ret = acl_set_fd (desc, acl); - else - ret = acl_set_file (name, ACL_TYPE_ACCESS, acl); - if (ret != 0) - { - int saved_errno = errno; - acl_free (acl); - - if (ACL_NOT_WELL_SUPPORTED (errno)) - { - if (chmod_or_fchmod (name, desc, mode) != 0) - saved_errno = errno; - else - return 0; - } - error (0, saved_errno, _("setting permissions for %s"), quote (name)); - return -1; - } - else - acl_free (acl); - - if (S_ISDIR (mode) && acl_delete_def_file (name)) - { - error (0, errno, _("setting permissions for %s"), quote (name)); - return -1; - } - - if (mode & (S_ISUID | S_ISGID | S_ISVTX)) - { - /* We did not call chmod so far, so the special bits have not yet - been set. */ - - if (chmod_or_fchmod (name, desc, mode)) - { - error (0, errno, _("preserving permissions for %s"), quote (name)); - return -1; - } - } - return 0; -#else - int ret = chmod_or_fchmod (name, desc, mode); - if (ret) - error (0, errno, _("setting permissions for %s"), quote (name)); - return ret; -#endif -} diff --git a/gl/lib/savewd.c b/gl/lib/savewd.c deleted file mode 100644 index a6ee23517..000000000 --- a/gl/lib/savewd.c +++ /dev/null @@ -1,308 +0,0 @@ -/* Save and restore the working directory, possibly using a child process. - - Copyright (C) 2006, 2007 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 2, 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, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - -/* Written by Paul Eggert. */ - -#include <config.h> - -#include "savewd.h" - -#include <assert.h> -#include <errno.h> -#include <fcntl.h> -#include <signal.h> -#include <stdbool.h> -#include <stdlib.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> - -#include "dirname.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. */ -static bool -savewd_save (struct savewd *wd) -{ - switch (wd->state) - { - 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 && 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; - } - } - break; - - case FD_STATE: - case FD_POST_CHDIR_STATE: - case ERROR_STATE: - case FINAL_STATE: - break; - - default: - assert (false); - } - - return false; -} - -int -savewd_chdir (struct savewd *wd, char const *dir, int options, - 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 & (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))); - - if (open_result) - { - open_result[0] = fd; - open_result[1] = errno; - } - - if (fd < 0 && ((errno != EACCES && errno != ESTALE) - || (options & SAVEWD_CHDIR_READABLE))) - result = -1; - } - - if (result == 0 && ! (0 <= fd && options & SAVEWD_CHDIR_SKIP_READABLE)) - { - if (savewd_save (wd)) - { - 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); - } - } - } - - if (0 <= fd && ! open_result) - { - int e = errno; - close (fd); - errno = e; - } - - return result; -} - -int -savewd_restore (struct savewd *wd, int status) -{ - switch (wd->state) - { - case INITIAL_STATE: - case FD_STATE: - /* The working directory is the desired directory, so there's no - 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; - } - else - { - 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. */ - errno = wd->val.errnum; - return -1; - - case FORKING_STATE: - /* "Restore" the working directory by waiting for the subprocess - 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); - } - } - break; - - default: - assert (false); - } - - return 0; -} - -void -savewd_finish (struct savewd *wd) -{ - switch (wd->state) - { - case INITIAL_STATE: - case ERROR_STATE: - break; - - case FD_STATE: - case FD_POST_CHDIR_STATE: - close (wd->val.fd); - break; - - case FORKING_STATE: - assert (wd->val.child < 0); - break; - - default: - assert (false); - } - - wd->state = FINAL_STATE; -} - -/* Return true if the actual work is currently being done by a - subprocess. - - A true return means that the caller and the subprocess should - resynchronize later with savewd_restore, using only their own - memory to decide when to resynchronize; they should not consult the - file system to decide, because that might lead to race conditions. - 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 -savewd_delegating (struct savewd const *wd) -{ - return wd->state == FORKING_STATE && 0 < wd->val.child; -} - -int -savewd_process_files (int n_files, char **file, - int (*act) (char *, struct savewd *, void *), - void *options) -{ - int i = 0; - int last_relative; - int exit_status = EXIT_SUCCESS; - struct savewd wd; - savewd_init (&wd); - - for (last_relative = n_files - 1; 0 <= last_relative; last_relative--) - if (! IS_ABSOLUTE_FILE_NAME (file[last_relative])) - break; - - for (; i < last_relative; i++) - { - if (! savewd_delegating (&wd)) - { - 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; - } - } - - savewd_finish (&wd); - - for (; i < n_files; i++) - { - int s = act (file[i], &wd, options); - if (exit_status < s) - exit_status = s; - } - - return exit_status; -} |