summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorPaul Eggert <eggert@cs.ucla.edu>2006-01-09 23:13:56 +0000
committerPaul Eggert <eggert@cs.ucla.edu>2006-01-09 23:13:56 +0000
commit14bf04a59fbfa9ae7a9b55f7885ed96a5f0341ac (patch)
treeaee1a932fb64449db082aa48f63609a9f37a7984 /lib
parent3b0c1fab1c5c2e7a38ca9ab8d213db44d553ea0f (diff)
downloadgnulib-14bf04a59fbfa9ae7a9b55f7885ed96a5f0341ac.tar.gz
Sync from coreutils.
* doc/getdate.texi (General date syntax): Invalid dates are rejected. (Time of day items): Mention the possibility of leap seconds. Problem reported by Dr. David Alan Gilbert. * lib/chdir-long.c (cdb_free): Don't bother trying to open directory for write access: POSIX says that must fail. * lib/fts.c (diropen): Likewise. * lib/save-cwd.c (save_cwd): Likewise. * lib/chdir-long.c (cdb_free): Open with O_NOCTTY | O_NONBLOCK as well, for minor improvements on hosts that lack O_DIRECTORY. * lib/gettime.c (gettime) [!defined OK_TO_USE_1S_CLOCK]: Report an error at compile-time if only a 1-second nominal clock resolution is found. * lib/lchmod.h: New file. * lib/mkdir-p.c: Include lchmod.h, lchown.h. (make_dir_parents): Use lchown rather than chown, and lchmod rather than chmod. * lib/mountlist.c (ME_DUMMY): "none" and "proc" file systems are dummies too. Problem with "none" reported by Bob Proulx. Problem with "proc" reported by n0dalus. * lib/mountlist.c: Include <limits.h>. (dev_from_mount_options) [defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2]: New function. It no longer assumes "dev=" has the System V meaning on Linux (since it doesn't). It also parses "dev=" more carefully. (read_file_system_list) [defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2]: Use it. MOUNTED_GETMNTENT2 is new here; the code didn't used to look for dev= in that case. * lib/posixtm.h (PDS_PRE_2000): New macro. * lib/posixtm.c (year): Arg is now syntax_bits rather than allow_century. All usages changed. Reject dates outside the range 1969-1999 if PDS_PRE_2000 is used. * modules/mkdir-p (Files): Add chdir-safer.c, chdir-safer.h, lchmod.h, chdir-safer.m4, lchmod.m4. * modules/openat: Add mkdirat.c, openat-priv.h. * modules/lib-ignore: New file. * lib/version-etc.c (COPYRIGHT_YEAR): Update to 2006. Rewrite fts.c not to change the current working directory, by using openat, fstatat, fdopendir, etc.. * lib/fts.c [! _LIBC]: Include "openat.h", "unistd--.h", and "fcntl--.h". [_LIBC] (fchdir): Don't undef or define; no longer used. (FCHDIR): Define in terms of cwd_advance_fd rather than fchdir. Now, this `function' always succeeds, and consumes its file descriptor parameter -- so callers must not close such FDs. Update callers. (diropen_fd, opendirat, cwd_advance_fd): New functions. (diropen): Add parameter, SP. Adjust all callers. Implement using diropen_fd, rather than open. (fts_open): Initialize new member, fts_cwd_fd. Remove fts_rft-setting code. (fts_close): Close fts_cwd_fd, if necessary. (__opendir2): Define in terms of opendir or opendirat, depending on whether the FST_NOCHDIR flag is set. (fts_build): Since fts_safe_changedir consumes its FD, and since this code must do `closedir(dirp)', dup the dirfd(dirp) argument, and close the dup'd file descriptor upon failure. (fts_stat): Use fstatat(...AT_SYMLINK_NOFOLLOW) in place of lstat. (fts_safe_changedir): Tweak semantics to reflect that this function now calls cwd_advance_fd and hence consumes its FD argument. * lib/fts_.h [struct FTS] (fts_cwd_fd): New member. (fts_rft): Remove now-unused member. * lib/openat.c (fchownat): New function. * lib/openat.h (fchmodat, fchownat): Declare. (chmodat, lchmodat): Define convenience functions. (chownat, lchownat): Likewise. * lib/chdir-safer.h, chdir-safer.c: New files. * lib/modechange.c (mode_compile): Reject an invalid mode string that starts with an octal digit. From Andreas Gruenbacher. * lib/openat.c: Include "fcntl--.h" and "unistd--.h", to map open and dup to open_safer and dup_safer, respectively. (openat_permissive): Fix typo in comment. * lib/openat.c: Don't include <stdlib.h>, <unistd.h>, <fcntl.h>, "gettext.h"; either no longer needed or are guaranteed by openat.h. (_): Remove; no longer needed. (openat): Renamed from rpl_openat; no need for rpl_openat since openat.h renames openat for us. Replace most of the body with a call to openat_permissive, to avoid duplicate code. Port to (probably hypothetical) environments were mode_t is wider than int. (openat_permissive): Require mode arg, so that we can check types better. Put it just after flags. Change cwd failure indicator from pointer-to-bool to pointer-to-errno-value. All callers changed. Invoke openat_save_fail and/or openat_restore_fail if cwd_errno is null, so that openat can call us. (openat_permissive, fdopendir, fstatat, unlinkat): Simplify errno handling to avoid some duplicate code, as it's OK to set errno on success. * lib/openat.h: Revamp code so that function macros depend on __OPENAT_PREFIX only, not also on AT_FDCWD. (openat_ro): Remove. Caller changed to use openat_permissive. (openat_permissive): Now a macro, if not a function. (openat_restore_fail, openat_save_fail): Now always functions, since mkdirat needs them even if __OPENAT_PREFIX is defined. * lib/openat-priv.h: New file, defining macros used by mkdirat.c and openat.c. * lib/mkdirat.c: Include openat-priv.h. Remove definitions of macros defined therein. * lib/openat.c: Likewise. * lib/mkdirat.c (mkdirat): New file and function. * lib/openat.h (mkdirat): Declare. * lib/openat.c (fdopendir): Don't change errno when returning non-NULL. * lib/openat.h (openat_permissive): Declare. (openat_ro): Define. * lib/openat.c (EXPECTED_ERRNO): New macro. (openat_permissive): New function -- used in remove.c rewrite. (all functions): Set errno just before returning, only if there was an actual failure. Use EXPECTED_ERRNO rather than comparing against only ENOTDIR. Emulate openat-family functions using Linux's procfs, if possible. Idea and some code based on Ulrich Drepper's glibc changes. * lib/openat.c: (BUILD_PROC_NAME): New macro. Include <stdio.h>, <string.h>, "alloca.h" and "intprops.h". (rpl_openat): Emulate by trying to open /proc/self/fd/%d/%s, before falling back on save_cwd and restore_cwd. (fdopendir, fstatat, unlinkat): Likewise. * lib/openat.c (fstatat, unlinkat): Perform the syscall directly, skipping the save_cwd...restore_cwd overhead, if FILE is absolute. * lib/openat.c (rpl_openat): Use the promoted type (int), not mode_t, as second argument to va_arg. Otherwise, some versions of gcc warn that `if this code is reached, the program will abort'. Add POSIX ACL support * lib/acl.h (copy_acl, set_acl): Add declarations. * lib/acl.c (acl_entries): Add fallback implementation for POSIX ACL systems other than Linux. (chmod_or_fchmod): New function: use fchmod when possible, and chmod otherwise. (file_has_acl): Add a POSIX ACL implementation, with a Linux-specific subcase. (copy_acl): Add: copy an acl and S_ISUID, S_ISGID, and S_ISVTX from one file to another. Fall back to fchmod/chmod when acls are unsupported. (set_acl): Add: set a file's acl and S_ISUID, S_ISGID, and S_ISVTX to a defined value. Fall back to fchmod/chmod when acls are unsupported. * m4/lib-ignore.m4: New file. * m4/lchmod.m4: New file. * m4/chdir-safer.m4: New file. * m4/openat.m4 (gl_FUNC_OPENAT): Require and compile mkdirat.c. Require openat-priv.h. * m4/acl.m4 (AC_FUNC_ACL): Add POSIX ACL and Linux-specific acl tests.
Diffstat (limited to 'lib')
-rw-r--r--lib/ChangeLog163
-rw-r--r--lib/acl.c374
-rw-r--r--lib/acl.h7
-rw-r--r--lib/chdir-long.c9
-rw-r--r--lib/chdir-safer.c87
-rw-r--r--lib/chdir-safer.h21
-rw-r--r--lib/chown.c37
-rw-r--r--lib/fts.c10
-rw-r--r--lib/gettime.c6
-rw-r--r--lib/lchmod.h35
-rw-r--r--lib/mkdir-p.c93
-rw-r--r--lib/mkdirat.c88
-rw-r--r--lib/modechange.c3
-rw-r--r--lib/mountlist.c54
-rw-r--r--lib/openat-priv.h52
-rw-r--r--lib/openat.c202
-rw-r--r--lib/openat.h50
-rw-r--r--lib/posixtm.c18
-rw-r--r--lib/posixtm.h3
-rw-r--r--lib/save-cwd.c8
-rw-r--r--lib/version-etc.c4
21 files changed, 1136 insertions, 188 deletions
diff --git a/lib/ChangeLog b/lib/ChangeLog
index fc10381d13..bf74701f4a 100644
--- a/lib/ChangeLog
+++ b/lib/ChangeLog
@@ -1,3 +1,166 @@
+2006-01-09 Paul Eggert <eggert@cs.ucla.edu>
+
+ Sync from coreutils.
+ * chdir-long.c (cdb_free): Don't bother trying to open directory
+ for write access: POSIX says that must fail.
+ * fts.c (diropen): Likewise.
+ * save-cwd.c (save_cwd): Likewise.
+ * chdir-long.c (cdb_free): Open with O_NOCTTY | O_NONBLOCK as
+ well, for minor improvements on hosts that lack O_DIRECTORY.
+
+ * gettime.c (gettime) [!defined OK_TO_USE_1S_CLOCK]:
+ Report an error at compile-time if only a 1-second nominal clock
+ resolution is found.
+
+ * lchmod.h: New file.
+ * mkdir-p.c: Include lchmod.h, lchown.h.
+ (make_dir_parents): Use lchown rather than chown, and
+ lchmod rather than chmod.
+
+ * mountlist.c (ME_DUMMY): "none" and "proc" file systems are dummies
+ too. Problem with "none" reported by Bob Proulx. Problem with
+ "proc" reported by n0dalus.
+
+ * mountlist.c: Include <limits.h>.
+ (dev_from_mount_options)
+ [defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2]:
+ New function. It no longer assumes "dev=" has the System V meaning
+ on Linux (since it doesn't). It also parses "dev=" more carefully.
+ (read_file_system_list)
+ [defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2]: Use it.
+ MOUNTED_GETMNTENT2 is new here; the code didn't used to look for
+ dev= in that case.
+
+ * posixtm.h (PDS_PRE_2000): New macro.
+ * posixtm.c (year): Arg is now syntax_bits rather than allow_century.
+ All usages changed. Reject dates outside the range 1969-1999 if
+ PDS_PRE_2000 is used.
+
+2006-01-09 Jim Meyering <jim@meyering.net>
+
+ Sync from coreutils.
+
+ * version-etc.c (COPYRIGHT_YEAR): Update to 2006.
+
+ Rewrite fts.c not to change the current working directory,
+ by using openat, fstatat, fdopendir, etc..
+
+ * fts.c [! _LIBC]: Include "openat.h", "unistd--.h", and "fcntl--.h".
+ [_LIBC] (fchdir): Don't undef or define; no longer used.
+ (FCHDIR): Define in terms of cwd_advance_fd rather than fchdir.
+ Now, this `function' always succeeds, and consumes its file descriptor
+ parameter -- so callers must not close such FDs. Update callers.
+ (diropen_fd, opendirat, cwd_advance_fd): New functions.
+ (diropen): Add parameter, SP. Adjust all callers.
+ Implement using diropen_fd, rather than open.
+ (fts_open): Initialize new member, fts_cwd_fd.
+ Remove fts_rft-setting code.
+ (fts_close): Close fts_cwd_fd, if necessary.
+ (__opendir2): Define in terms of opendir or opendirat,
+ depending on whether the FST_NOCHDIR flag is set.
+ (fts_build): Since fts_safe_changedir consumes its FD, and since
+ this code must do `closedir(dirp)', dup the dirfd(dirp) argument,
+ and close the dup'd file descriptor upon failure.
+ (fts_stat): Use fstatat(...AT_SYMLINK_NOFOLLOW) in place of lstat.
+ (fts_safe_changedir): Tweak semantics to reflect that this function
+ now calls cwd_advance_fd and hence consumes its FD argument.
+ * fts_.h [struct FTS] (fts_cwd_fd): New member.
+ (fts_rft): Remove now-unused member.
+
+ * openat.c (fchownat): New function.
+ * openat.h (fchmodat, fchownat): Declare.
+ (chmodat, lchmodat): Define convenience functions.
+ (chownat, lchownat): Likewise.
+
+ * chdir-safer.h, chdir-safer.c: New files.
+
+ * modechange.c (mode_compile): Reject an invalid mode string
+ that starts with an octal digit. From Andreas Gruenbacher.
+
+ * openat.c: Include "fcntl--.h" and "unistd--.h", to map open
+ and dup to open_safer and dup_safer, respectively.
+ (openat_permissive): Fix typo in comment.
+
+ * openat.c: Don't include <stdlib.h>, <unistd.h>, <fcntl.h>,
+ "gettext.h"; either no longer needed or are guaranteed by openat.h.
+ (_): Remove; no longer needed.
+ (openat): Renamed from rpl_openat; no need for rpl_openat
+ since openat.h renames openat for us.
+ Replace most of the body with a call to openat_permissive,
+ to avoid duplicate code.
+ Port to (probably hypothetical) environments were mode_t is
+ wider than int.
+ (openat_permissive): Require mode arg, so that we can check
+ types better. Put it just after flags. Change cwd failure
+ indicator from pointer-to-bool to pointer-to-errno-value.
+ All callers changed.
+ Invoke openat_save_fail and/or openat_restore_fail if
+ cwd_errno is null, so that openat can call us.
+ (openat_permissive, fdopendir, fstatat, unlinkat):
+ Simplify errno handling to avoid some duplicate code,
+ as it's OK to set errno on success.
+ * openat.h: Revamp code so that function macros depend on
+ __OPENAT_PREFIX only, not also on AT_FDCWD.
+ (openat_ro): Remove. Caller changed to use openat_permissive.
+ (openat_permissive): Now a macro, if not a function.
+ (openat_restore_fail, openat_save_fail): Now always functions,
+ since mkdirat needs them even if __OPENAT_PREFIX is defined.
+
+ * openat-priv.h: New file, defining macros used by mkdirat.c
+ and openat.c.
+ * mkdirat.c: Include openat-priv.h.
+ Remove definitions of macros defined therein.
+ * openat.c: Likewise.
+
+ * mkdirat.c (mkdirat): New file and function.
+ * openat.h (mkdirat): Declare.
+
+ * openat.c (fdopendir): Don't change errno when returning non-NULL.
+
+ * openat.h (openat_permissive): Declare.
+ (openat_ro): Define.
+
+ * openat.c (EXPECTED_ERRNO): New macro.
+ (openat_permissive): New function -- used in remove.c rewrite.
+ (all functions): Set errno just before returning, only if there
+ was an actual failure.
+ Use EXPECTED_ERRNO rather than comparing against only ENOTDIR.
+
+ Emulate openat-family functions using Linux's procfs, if possible.
+ Idea and some code based on Ulrich Drepper's glibc changes.
+
+ * openat.c: (BUILD_PROC_NAME): New macro.
+ Include <stdio.h>, <string.h>, "alloca.h" and "intprops.h".
+ (rpl_openat): Emulate by trying to open /proc/self/fd/%d/%s,
+ before falling back on save_cwd and restore_cwd.
+ (fdopendir, fstatat, unlinkat): Likewise.
+
+ * openat.c (fstatat, unlinkat): Perform the syscall directly,
+ skipping the save_cwd...restore_cwd overhead, if FILE is absolute.
+
+ * openat.c (rpl_openat): Use the promoted type (int), not mode_t,
+ as second argument to va_arg. Otherwise, some versions of gcc
+ warn that `if this code is reached, the program will abort'.
+
+2006-01-09 Andreas Gruenbacher <agruen@suse.de>
+
+ Sync from coreutils.
+
+ Add POSIX ACL support
+ * acl.h (copy_acl, set_acl): Add declarations.
+ * acl.c (acl_entries): Add fallback implementation for POSIX ACL
+ systems other than Linux.
+ (chmod_or_fchmod): New function: use fchmod when possible,
+ and chmod otherwise.
+ (file_has_acl): Add a POSIX ACL implementation, with a
+ Linux-specific subcase.
+ (copy_acl): Add: copy an acl and S_ISUID, S_ISGID, and
+ S_ISVTX from one file to another. Fall back to fchmod/chmod when
+ acls are unsupported.
+ (set_acl): Add: set a file's acl and S_ISUID, S_ISGID, and
+ S_ISVTX to a defined value. Fall back to fchmod/chmod when acls
+ are unsupported.
+
2006-01-09 Bruno Haible <bruno@clisp.org>
* sysexit_.h (EX_OK): New macro.
diff --git a/lib/acl.c b/lib/acl.c
index 293582514e..b5c1ee9449 100644
--- a/lib/acl.c
+++ b/lib/acl.c
@@ -16,48 +16,394 @@
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. */
+ Written by Paul Eggert and Andreas Gruenbacher. */
#ifdef HAVE_CONFIG_H
# include <config.h>
#endif
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef S_ISLNK
# define S_ISLNK(Mode) 0
#endif
+#ifdef HAVE_ACL_LIBACL_H
+# include <acl/libacl.h>
+#endif
+
#include "acl.h"
+#include "error.h"
+#include "quote.h"
#include <errno.h>
#ifndef ENOSYS
# define ENOSYS (-1)
#endif
+#ifndef ENOTSUP
+# define ENOTSUP (-1)
+#endif
-#ifndef MIN_ACL_ENTRIES
-# define MIN_ACL_ENTRIES 4
+#if ENABLE_NLS
+# include <libintl.h>
+# define _(Text) gettext (Text)
+#else
+# define _(Text) Text
#endif
-/* Return 1 if FILE has a nontrivial access control list, 0 if not,
- and -1 (setting errno) if an error is encountered. */
+#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
+
+/* We detect 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
-file_has_acl (char const *file, struct stat const *filestat)
+chmod_or_fchmod (const char *name, int desc, mode_t mode)
{
- /* FIXME: This implementation should work on recent-enough versions
- of HP-UX, Solaris, and Unixware, but it simply returns 0 with
- POSIX 1003.1e (draft 17 -- abandoned), AIX, GNU/Linux, Irix, and
- Tru64. Please see Samba's source/lib/sysacls.c file for
- fix-related ideas. */
+ if (HAVE_FCHMOD && desc != -1)
+ return fchmod (desc, mode);
+ else
+ return chmod (name, mode);
+}
-#if HAVE_ACL && defined GETACLCNT
- if (! S_ISLNK (filestat->st_mode))
+/* 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 (file, GETACLCNT, 0, NULL);
+ 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 = (3 < acl_entries (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 (errno == ENOSYS || errno == ENOTSUP) ? 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 (errno == ENOSYS || errno == ENOTSUP)
+ 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 (errno == ENOSYS || errno == ENOTSUP)
+ {
+ int n = acl_entries (acl);
+
+ acl_free (acl);
+ if (n == 3)
+ {
+ 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 (errno == ENOTSUP || errno == ENOSYS)
+ {
+ 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/lib/acl.h b/lib/acl.h
index c9bb3c7df1..a7b4f9eecb 100644
--- a/lib/acl.h
+++ b/lib/acl.h
@@ -18,11 +18,14 @@
Written by Paul Eggert. */
-#if HAVE_SYS_ACL_H && HAVE_ACL
+#if HAVE_SYS_ACL_H
# include <sys/acl.h>
#endif
-#if ! defined GETACLCNT && defined ACL_CNT
+#if defined HAVE_ACL && ! defined GETACLCNT && defined ACL_CNT
# define GETACLCNT ACL_CNT
#endif
int file_has_acl (char const *, struct stat const *);
+int copy_acl (char const *, int, char const *, int, mode_t);
+int set_acl (char const *, int, mode_t);
+int chmod_or_fchmod (char const *, int, mode_t);
diff --git a/lib/chdir-long.c b/lib/chdir-long.c
index a727817251..8c15d06d2a 100644
--- a/lib/chdir-long.c
+++ b/lib/chdir-long.c
@@ -77,13 +77,10 @@ cdb_free (struct cd_buf const *cdb)
static int
cdb_advance_fd (struct cd_buf *cdb, char const *dir)
{
- int new_fd = openat (cdb->fd, dir, O_RDONLY | O_DIRECTORY);
+ int new_fd = openat (cdb->fd, dir,
+ O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK);
if (new_fd < 0)
- {
- new_fd = openat (cdb->fd, dir, O_WRONLY | O_DIRECTORY);
- if (new_fd < 0)
- return -1;
- }
+ return -1;
cdb_free (cdb);
cdb->fd = new_fd;
diff --git a/lib/chdir-safer.c b/lib/chdir-safer.c
new file mode 100644
index 0000000000..b41123014c
--- /dev/null
+++ b/lib/chdir-safer.c
@@ -0,0 +1,87 @@
+/* much like chdir(2), but safer
+
+ Copyright (C) 2005, 2006 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 Jim Meyering */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "chdir-safer.h"
+
+#include <stdbool.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef O_DIRECTORY
+# define O_DIRECTORY 0
+#endif
+
+#ifndef O_NOFOLLOW
+# define O_NOFOLLOW 0
+#endif
+
+#define SAME_INODE(Stat_buf_1, Stat_buf_2) \
+ ((Stat_buf_1).st_ino == (Stat_buf_2).st_ino \
+ && (Stat_buf_1).st_dev == (Stat_buf_2).st_dev)
+
+/* Like chdir, but fail if DIR is a symbolic link to a directory (or
+ similar funny business), or if DIR is not readable. This avoids a
+ minor race condition between when a directory is created or statted
+ and when the process chdirs into it. */
+int
+chdir_no_follow (char const *dir)
+{
+ int result = 0;
+ int saved_errno;
+ int fd = open (dir,
+ O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NOFOLLOW | O_NONBLOCK);
+ if (fd < 0)
+ return -1;
+
+ /* If open follows symlinks, lstat DIR and fstat FD to ensure that
+ they are the same file; if they are different files, set errno to
+ ELOOP (the same value that open uses for symlinks with
+ O_NOFOLLOW) so the caller can report a failure. */
+ if (! O_NOFOLLOW)
+ {
+ struct stat sb1;
+ result = lstat (dir, &sb1);
+ if (result == 0)
+ {
+ struct stat sb2;
+ result = fstat (fd, &sb2);
+ if (result == 0 && ! SAME_INODE (sb1, sb2))
+ {
+ errno = ELOOP;
+ result = -1;
+ }
+ }
+ }
+
+ if (result == 0)
+ result = fchdir (fd);
+
+ saved_errno = errno;
+ close (fd);
+ errno = saved_errno;
+ return result;
+}
diff --git a/lib/chdir-safer.h b/lib/chdir-safer.h
new file mode 100644
index 0000000000..554485a831
--- /dev/null
+++ b/lib/chdir-safer.h
@@ -0,0 +1,21 @@
+/* much like chdir(2), but safer
+
+ Copyright (C) 2005 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 Jim Meyering. */
+
+int chdir_no_follow (char const *file);
diff --git a/lib/chown.c b/lib/chown.c
index 729dd3b0bc..2a7bba1a6c 100644
--- a/lib/chown.c
+++ b/lib/chown.c
@@ -27,12 +27,15 @@
most systems. */
#undef chown
+#include <stdbool.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
+#include "stat-macros.h"
+
/* Provide a more-closely POSIX-conforming version of chown on
systems with one or both of the following problems:
- chown doesn't treat an ID of -1 as meaning
@@ -66,20 +69,34 @@ rpl_chown (const char *file, uid_t uid, gid_t gid)
on the symlink itself. To work around that, we open the
file (but this can fail due to lack of read or write permission) and
use fchown on the resulting descriptor. */
- int fd = open (file, O_RDONLY | O_NONBLOCK | O_NOCTTY);
- if (fd < 0
- && (fd = open (file, O_WRONLY | O_NONBLOCK | O_NOCTTY)) < 0)
- return -1;
- if (fchown (fd, uid, gid))
+ int open_flags = O_NONBLOCK | O_NOCTTY;
+ int fd = open (file, O_RDONLY | open_flags);
+ if (0 <= fd
+ || (errno == EACCES
+ && 0 <= (fd = open (file, O_WRONLY | open_flags))))
{
+ int result = fchown (fd, uid, gid);
int saved_errno = errno;
+
+ /* POSIX says fchown can fail with errno == EINVAL on sockets,
+ so fall back on chown in that case. */
+ struct stat sb;
+ bool fchown_socket_failure =
+ (result != 0 && saved_errno == EINVAL
+ && fstat (fd, &sb) == 0 && S_ISFIFO (sb.st_mode));
+
close (fd);
- errno = saved_errno;
- return -1;
+
+ if (! fchown_socket_failure)
+ {
+ errno = saved_errno;
+ return result;
+ }
}
- return close (fd);
+ else if (errno != EACCES)
+ return -1;
}
-#else
- return chown (file, uid, gid);
#endif
+
+ return chown (file, uid, gid);
}
diff --git a/lib/fts.c b/lib/fts.c
index eb24b9862c..ed09697e05 100644
--- a/lib/fts.c
+++ b/lib/fts.c
@@ -1,6 +1,6 @@
/* Traverse a file hierarchy.
- Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005, 2006 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
@@ -203,10 +203,7 @@ static int
internal_function
diropen (char const *dir)
{
- int fd = open (dir, O_RDONLY | O_DIRECTORY);
- if (fd < 0)
- fd = open (dir, O_WRONLY | O_DIRECTORY);
- return fd;
+ return open (dir, O_RDONLY | O_DIRECTORY | O_NOCTTY | O_NONBLOCK);
}
FTS *
@@ -244,7 +241,8 @@ fts_open (char * const *argv,
#ifndef MAXPATHLEN
# define MAXPATHLEN 1024
#endif
- if (! fts_palloc(sp, MAX(fts_maxarglen(argv), MAXPATHLEN)))
+ size_t maxarglen = fts_maxarglen(argv);
+ if (! fts_palloc(sp, MAX(maxarglen, MAXPATHLEN)))
goto mem1;
/* Allocate/initialize root's parent. */
diff --git a/lib/gettime.c b/lib/gettime.c
index 0f94297da8..d60711b533 100644
--- a/lib/gettime.c
+++ b/lib/gettime.c
@@ -45,8 +45,14 @@ gettime (struct timespec *ts)
ts->tv_nsec = tv.tv_usec * 1000;
}
# else
+
+# ifndef OK_TO_USE_1S_CLOCK
+# error "Only 1-second nominal clock resolution found. Is that intended?" \
+ "If so, compile with the -DOK_TO_USE_1S_CLOCK option."
+# endif
ts->tv_sec = time (NULL);
ts->tv_nsec = 0;
+
# endif
#endif
diff --git a/lib/lchmod.h b/lib/lchmod.h
new file mode 100644
index 0000000000..d12f94abf4
--- /dev/null
+++ b/lib/lchmod.h
@@ -0,0 +1,35 @@
+/* Provide a replacement for lchmod on hosts that lack it.
+
+ Copyright (C) 2005 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 <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef HAVE_LCHMOD
+
+/* The lchmod replacement follows symbolic links. Callers should take
+ this into account; lchmod should be applied only to arguments that
+ are known to not be symbolic links. On hosts that lack lchmod,
+ this can lead to race conditions between the check and the
+ invocation of lchmod, but we know of no workarounds that are
+ reliable in general. You might try requesting support for lchmod
+ from your operating system supplier. */
+
+# define lchmod chmod
+#endif
diff --git a/lib/mkdir-p.c b/lib/mkdir-p.c
index b074c0aa78..dd42b6ca55 100644
--- a/lib/mkdir-p.c
+++ b/lib/mkdir-p.c
@@ -1,6 +1,6 @@
/* mkdir-p.c -- Ensure that a directory and its parents exist.
- Copyright (C) 1990, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005
+ Copyright (C) 1990, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
@@ -39,18 +39,15 @@
#include "gettext.h"
#define _(msgid) gettext (msgid)
-#include "save-cwd.h"
+#include "chdir-safer.h"
#include "dirname.h"
#include "error.h"
+#include "lchmod.h"
+#include "lchown.h"
#include "quote.h"
+#include "save-cwd.h"
#include "stat-macros.h"
-#ifndef ENOSYS
-# define ENOSYS EEXIST
-#endif
-
-#define WX_USR (S_IWUSR | S_IXUSR)
-
/* Ensure that the directory ARG exists.
Create any leading directories that don't already exist, with
@@ -127,15 +124,15 @@ make_dir_parents (char const *arg,
mode_t oldmask = umask (0);
/* Make a copy of ARG that we can scribble NULs on. */
- dir = (char *) alloca (strlen (arg) + 1);
+ dir = alloca (strlen (arg) + 1);
strcpy (dir, arg);
strip_trailing_slashes (dir);
full_dir = dir;
- /* If leading directories shouldn't be writable or executable,
+ /* If leading directories shouldn't be readable, writable or executable,
or should have set[ug]id or sticky bits set and we are setting
their owners, we need to fix their permissions after making them. */
- if (((parent_mode & WX_USR) != WX_USR)
+ if (((parent_mode & S_IRWXU) != S_IRWXU)
|| ((owner != (uid_t) -1 || group != (gid_t) -1)
&& (parent_mode & (S_ISUID | S_ISGID | S_ISVTX)) != 0))
{
@@ -175,6 +172,9 @@ make_dir_parents (char const *arg,
while (true)
{
+ bool dir_known_to_exist;
+ int mkdir_errno;
+
/* slash points to the leftmost unprocessed component of dir. */
basename_dir = slash;
@@ -188,13 +188,16 @@ make_dir_parents (char const *arg,
basename_dir = dir;
*slash = '\0';
- if (mkdir (basename_dir, tmp_mode) == 0)
+ dir_known_to_exist = (mkdir (basename_dir, tmp_mode) == 0);
+ mkdir_errno = errno;
+
+ if (dir_known_to_exist)
{
if (verbose_fmt_string)
error (0, 0, verbose_fmt_string, quote (dir));
if ((owner != (uid_t) -1 || group != (gid_t) -1)
- && chown (basename_dir, owner, group)
+ && lchown (basename_dir, owner, group)
#if defined AFS && defined EPERM
&& errno != EPERM
#endif
@@ -208,36 +211,43 @@ make_dir_parents (char const *arg,
if (re_protect)
{
- struct ptr_list *new = (struct ptr_list *)
- alloca (sizeof *new);
+ struct ptr_list *new = alloca (sizeof *new);
new->dirname_end = slash;
new->next = leading_dirs;
leading_dirs = new;
}
}
- else if (errno == EEXIST || errno == ENOSYS)
- {
- /* A file is already there. Perhaps it is a directory.
- If not, it will be diagnosed later.
-
- The ENOSYS is for Solaris 8 NFS clients, which can
- fail with errno == ENOSYS if mkdir is invoked on an
- NFS mount point. */
- }
- else
- {
- error (0, errno, _("cannot create directory %s"), quote (dir));
- retval = false;
- break;
- }
/* If we were able to save the initial working directory,
then we can use chdir to change into each directory before
creating an entry in that directory. This avoids making
mkdir process O(n^2) file name components. */
- if (do_chdir && chdir (basename_dir) < 0)
+ if (do_chdir)
+ {
+ /* If we know that basename_dir is a directory (because we've
+ just created it), then ensure that when we change to it,
+ that final component is not a symlink. Otherwise, we must
+ accept the possibility that basename_dir is a preexisting
+ symlink-to-directory and chdir through the symlink. */
+ if ((dir_known_to_exist
+ ? chdir_no_follow (basename_dir)
+ : chdir (basename_dir)) == 0)
+ dir_known_to_exist = true;
+ else if (dir_known_to_exist)
+ {
+ error (0, errno, _("cannot chdir to directory %s"),
+ quote (dir));
+ retval = false;
+ break;
+ }
+ }
+ else if (!dir_known_to_exist)
+ dir_known_to_exist = (stat (basename_dir, &stats) == 0
+ && S_ISDIR (stats.st_mode));
+
+ if (!dir_known_to_exist)
{
- error (0, errno, _("cannot chdir to directory %s"),
+ error (0, mkdir_errno, _("cannot create directory %s"),
quote (dir));
retval = false;
break;
@@ -261,9 +271,18 @@ make_dir_parents (char const *arg,
Create the final component of the file name. */
if (retval)
{
- if (mkdir (basename_dir, mode) != 0)
+ bool dir_known_to_exist = (mkdir (basename_dir, mode) == 0);
+ int mkdir_errno = errno;
+ struct stat sbuf;
+
+ if ( ! dir_known_to_exist)
+ dir_known_to_exist = (stat (basename_dir, &sbuf) == 0
+ && S_ISDIR (sbuf.st_mode));
+
+ if ( ! dir_known_to_exist)
{
- error (0, errno, _("cannot create directory %s"), quote (dir));
+ error (0, mkdir_errno,
+ _("cannot create directory %s"), quote (dir));
retval = false;
}
else
@@ -285,7 +304,7 @@ make_dir_parents (char const *arg,
if (owner != (uid_t) -1 || group != (gid_t) -1)
{
- if (chown (fixup_permissions_dir, owner, group) != 0
+ if (lchown (fixup_permissions_dir, owner, group) != 0
#ifdef AFS
&& errno != EPERM
#endif
@@ -302,7 +321,7 @@ make_dir_parents (char const *arg,
required to honor only the file permission bits. In particular,
it need not honor the `special' bits, so if MODE includes any
special bits, set them here. */
- if ((mode & ~S_IRWXUGO) && chmod (fixup_permissions_dir, mode) != 0)
+ if ((mode & ~S_IRWXUGO) && lchmod (fixup_permissions_dir, mode) != 0)
{
error (0, errno, _("cannot change permissions of %s"),
quote (full_dir));
@@ -326,7 +345,7 @@ make_dir_parents (char const *arg,
{
leading_dirs->dirname_end[0] = '\0';
if ((cwd_problem && *full_dir != '/')
- || chmod (full_dir, parent_mode) != 0)
+ || lchmod (full_dir, parent_mode) != 0)
{
error (0, (cwd_problem ? 0 : errno),
_("cannot change permissions of %s"), quote (full_dir));
diff --git a/lib/mkdirat.c b/lib/mkdirat.c
new file mode 100644
index 0000000000..6103c6f157
--- /dev/null
+++ b/lib/mkdirat.c
@@ -0,0 +1,88 @@
+/* fd-relative mkdir
+ Copyright (C) 2005, 2006 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 Jim Meyering */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include "openat.h"
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "dirname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
+#include "save-cwd.h"
+
+#include "gettext.h"
+#define _(msgid) gettext (msgid)
+
+#include "openat-priv.h"
+
+/* Solaris 10 has no function like this.
+ Create a subdirectory, FILE, with mode MODE, in the directory
+ open on descriptor FD. If possible, do it without changing the
+ working directory. Otherwise, resort to using save_cwd/fchdir,
+ then mkdir/restore_cwd. If either the save_cwd or the restore_cwd
+ fails, then give a diagnostic and exit nonzero. */
+int
+mkdirat (int fd, char const *file, mode_t mode)
+{
+ struct saved_cwd saved_cwd;
+ int saved_errno;
+ int err;
+
+ if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
+ return mkdir (file, mode);
+
+ {
+ char *proc_file;
+ BUILD_PROC_NAME (proc_file, fd, file);
+ err = mkdir (proc_file, mode);
+ /* If the syscall succeeds, or if it fails with an unexpected
+ errno value, then return right away. Otherwise, fall through
+ and resort to using save_cwd/restore_cwd. */
+ if (0 <= err || ! EXPECTED_ERRNO (errno))
+ return err;
+ }
+
+ 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 = mkdir (file, mode);
+ saved_errno = (err < 0 ? errno : 0);
+
+ if (restore_cwd (&saved_cwd) != 0)
+ openat_restore_fail (errno);
+
+ free_cwd (&saved_cwd);
+
+ if (saved_errno)
+ errno = saved_errno;
+ return err;
+}
diff --git a/lib/modechange.c b/lib/modechange.c
index 6ab9cb6fdd..52c5debca3 100644
--- a/lib/modechange.c
+++ b/lib/modechange.c
@@ -124,6 +124,9 @@ mode_compile (char const *mode_string)
}
while ('0' <= *mode_string && *mode_string < '8');
+ if (*mode_string)
+ return NULL;
+
/* Help the compiler optimize the usual case where mode_t uses
the traditional octal representation. */
mode = ((S_ISUID == SUID && S_ISGID == SGID && S_ISVTX == SVTX
diff --git a/lib/mountlist.c b/lib/mountlist.c
index 6c4e2b9d39..b957a973fd 100644
--- a/lib/mountlist.c
+++ b/lib/mountlist.c
@@ -23,6 +23,7 @@
#include "mountlist.h"
+#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -143,6 +144,8 @@ char *strstr ();
#ifndef ME_DUMMY
# define ME_DUMMY(Fs_name, Fs_type) \
(strcmp (Fs_type, "autofs") == 0 \
+ || strcmp (Fs_type, "none") == 0 \
+ || strcmp (Fs_type, "proc") == 0 \
|| strcmp (Fs_type, "subfs") == 0 \
/* for Irix 6.5 */ \
|| strcmp (Fs_type, "ignore") == 0)
@@ -283,6 +286,44 @@ fstype_to_string (int t)
}
#endif /* MOUNTED_VMOUNT */
+
+#if defined MOUNTED_GETMNTENT1 || defined MOUNTED_GETMNTENT2
+
+/* Return the device number from MOUNT_OPTIONS, if possible.
+ Otherwise return (dev_t) -1. */
+
+static dev_t
+dev_from_mount_options (char const *mount_options)
+{
+ /* GNU/Linux allows file system implementations to define their own
+ meaning for "dev=" mount options, so don't trust the meaning
+ here. */
+# ifndef __linux__
+
+ static char const dev_pattern[] = ",dev=";
+ char const *devopt = strstr (mount_options, dev_pattern);
+
+ if (devopt)
+ {
+ char const *optval = devopt + sizeof dev_pattern - 1;
+ char *optvalend;
+ unsigned long int dev;
+ errno = 0;
+ dev = strtoul (optval, &optvalend, 16);
+ if (optval != optvalend
+ && (*optvalend == '\0' || *optvalend == ',')
+ && ! (dev == ULONG_MAX && errno == ERANGE)
+ && dev == (dev_t) dev)
+ return dev;
+ }
+
+# endif
+
+ return -1;
+}
+
+#endif
+
/* Return a list of the currently mounted file systems, or NULL on error.
Add each entry to the tail of the list so that they stay in order.
If NEED_FS_TYPE is true, ensure that the file system type fields in
@@ -325,12 +366,11 @@ read_file_system_list (bool need_fs_type)
}
#endif
-#ifdef MOUNTED_GETMNTENT1 /* 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
+#ifdef MOUNTED_GETMNTENT1 /* GNU/Linux, 4.3BSD, SunOS, HP-UX, Dynix, Irix. */
{
struct mntent *mnt;
char *table = MOUNTED;
FILE *fp;
- char *devopt;
fp = setmntent (table, "r");
if (fp == NULL)
@@ -345,11 +385,7 @@ read_file_system_list (bool need_fs_type)
me->me_type_malloced = 1;
me->me_dummy = ME_DUMMY (me->me_devname, me->me_type);
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
- devopt = strstr (mnt->mnt_opts, "dev=");
- if (devopt)
- me->me_dev = strtoul (devopt + 4, NULL, 16);
- else
- me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
+ me->me_dev = dev_from_mount_options (mnt->mnt_opts);
/* Add to the linked list. */
*mtail = me;
@@ -623,7 +659,7 @@ read_file_system_list (bool need_fs_type)
}
#endif /* MOUNTED_FREAD || MOUNTED_FREAD_FSTYP. */
-#ifdef MOUNTED_GETMNTTBL /* DolphinOS goes it's own way */
+#ifdef MOUNTED_GETMNTTBL /* DolphinOS goes its own way. */
{
struct mntent **mnttbl = getmnttbl (), **ent;
for (ent=mnttbl;*ent;ent++)
@@ -697,7 +733,7 @@ read_file_system_list (bool need_fs_type)
me->me_type_malloced = 1;
me->me_dummy = MNT_IGNORE (&mnt) != 0;
me->me_remote = ME_REMOTE (me->me_devname, me->me_type);
- me->me_dev = (dev_t) -1; /* Magic; means not known yet. */
+ me->me_dev = dev_from_mount_options (mnt.mnt_mntopts);
/* Add to the linked list. */
*mtail = me;
diff --git a/lib/openat-priv.h b/lib/openat-priv.h
new file mode 100644
index 0000000000..2b4780eecf
--- /dev/null
+++ b/lib/openat-priv.h
@@ -0,0 +1,52 @@
+/* macros used by openat-like functions
+ Copyright (C) 2005 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 Jim Meyering */
+
+#include <stdio.h>
+#include <string.h>
+#include "alloca.h"
+#include "intprops.h"
+
+/* Set PROC_FD_FILENAME to the expansion of "/proc/self/fd/%d/%s" in
+ alloca'd memory, using FD and FILE, respectively for %d and %s. */
+#define BUILD_PROC_NAME(Proc_fd_filename, Fd, File) \
+ do \
+ { \
+ size_t filelen = strlen (File); \
+ static const char procfd[] = "/proc/self/fd/%d/%s"; \
+ /* Buffer for the file name we are going to use. It consists of \
+ - the string /proc/self/fd/ \
+ - the file descriptor number \
+ - the file name provided. \
+ The final NUL is included in the sizeof. \
+ Subtract 4 to account for %d and %s. */ \
+ size_t buflen = sizeof (procfd) - 4 + INT_STRLEN_BOUND (Fd) + filelen; \
+ (Proc_fd_filename) = alloca (buflen); \
+ snprintf ((Proc_fd_filename), buflen, procfd, (Fd), (File)); \
+ } \
+ while (0)
+
+/* Trying to access a BUILD_PROC_NAME file will fail on systems without
+ /proc support, and even on systems *with* ProcFS support. Return
+ nonzero if the failure may be legitimate, e.g., because /proc is not
+ readable, or the particular .../fd/N directory is not present. */
+#define EXPECTED_ERRNO(Errno) \
+ ((Errno) == ENOTDIR || (Errno) == ENOENT \
+ || (Errno) == EPERM || (Errno) == EACCES \
+ || (Errno) == ENOSYS /* Solaris 8 */ \
+ || (Errno) == EOPNOTSUPP /* FreeBSD */)
diff --git a/lib/openat.c b/lib/openat.c
index 929d264924..69d4c23f9a 100644
--- a/lib/openat.c
+++ b/lib/openat.c
@@ -23,17 +23,15 @@
#include "openat.h"
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <errno.h>
-#include <fcntl.h>
-
#include "dirname.h" /* solely for definition of IS_ABSOLUTE_FILE_NAME */
+#include "fcntl--.h"
+#include "openat-priv.h"
#include "save-cwd.h"
+#include "unistd--.h"
-#include "gettext.h"
-#define _(msgid) gettext (msgid)
+#include <stdarg.h>
+#include <stddef.h>
+#include <errno.h>
/* Replacement for Solaris' openat function.
<http://www.google.com/search?q=openat+site:docs.sun.com>
@@ -44,11 +42,8 @@
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 *file, int flags, ...)
+openat (int fd, char const *file, int flags, ...)
{
- struct saved_cwd saved_cwd;
- int saved_errno;
- int new_fd;
mode_t mode = 0;
if (flags & O_CREAT)
@@ -56,37 +51,80 @@ rpl_openat (int fd, char const *file, int flags, ...)
va_list arg;
va_start (arg, flags);
- /* Assume that mode_t is passed compatibly with mode_t's type
- after argument promotion. */
- mode = va_arg (arg, mode_t);
+ /* If mode_t is narrower than int, use the promoted type (int),
+ not mode_t. Use sizeof to guess whether mode_t is nerrower;
+ we don't know of any practical counterexamples. */
+ if (sizeof (mode_t) < sizeof (int))
+ mode = va_arg (arg, int);
+ else
+ mode = va_arg (arg, mode_t);
va_end (arg);
}
+ return openat_permissive (fd, file, flags, mode, NULL);
+}
+
+/* Like openat (FD, FILE, FLAGS, MODE), but if CWD_ERRNO is
+ nonnull, set *CWD_ERRNO to an errno value if unable to save
+ or restore the initial working directory. This is needed only
+ the first time remove.c's remove_dir opens a command-line
+ directory argument.
+
+ If a previous attempt to restore the current working directory
+ failed, then we must not even try to access a `.'-relative name.
+ It is the caller's responsibility not to call this function
+ in that case. */
+
+int
+openat_permissive (int fd, char const *file, int flags, mode_t mode,
+ int *cwd_errno)
+{
+ struct saved_cwd saved_cwd;
+ int saved_errno;
+ int err;
+ bool save_ok;
+
if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
return open (file, flags, mode);
- if (save_cwd (&saved_cwd) != 0)
- openat_save_fail (errno);
-
- if (fchdir (fd) != 0)
+ {
+ char *proc_file;
+ BUILD_PROC_NAME (proc_file, fd, file);
+ err = open (proc_file, flags, mode);
+ /* If the syscall succeeds, or if it fails with an unexpected
+ errno value, then return right away. Otherwise, fall through
+ and resort to using save_cwd/restore_cwd. */
+ if (0 <= err || ! EXPECTED_ERRNO (errno))
+ return err;
+ }
+
+ save_ok = (save_cwd (&saved_cwd) == 0);
+ if (! save_ok)
{
- saved_errno = errno;
- free_cwd (&saved_cwd);
- errno = saved_errno;
- return -1;
+ if (! cwd_errno)
+ openat_save_fail (errno);
+ *cwd_errno = errno;
}
- new_fd = open (file, flags, mode);
+ err = fchdir (fd);
saved_errno = errno;
- if (restore_cwd (&saved_cwd) != 0)
- openat_restore_fail (errno);
+ if (! err)
+ {
+ err = open (file, flags, mode);
+ saved_errno = errno;
+ if (save_ok && restore_cwd (&saved_cwd) != 0)
+ {
+ if (! cwd_errno)
+ openat_restore_fail (errno);
+ *cwd_errno = errno;
+ }
+ }
free_cwd (&saved_cwd);
-
errno = saved_errno;
- return new_fd;
+ return err;
}
#if !HAVE_FDOPENDIR
@@ -110,27 +148,37 @@ fdopendir (int fd)
int saved_errno;
DIR *dir;
- if (save_cwd (&saved_cwd) != 0)
- openat_save_fail (errno);
+ char *proc_file;
+ BUILD_PROC_NAME (proc_file, fd, ".");
+ dir = opendir (proc_file);
+ saved_errno = errno;
- if (fchdir (fd) != 0)
+ /* If the syscall fails with an expected errno value, resort to
+ save_cwd/restore_cwd. */
+ if (! dir && EXPECTED_ERRNO (saved_errno))
{
- saved_errno = 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);
- errno = saved_errno;
- return NULL;
}
- dir = opendir (".");
- saved_errno = errno;
-
- if (restore_cwd (&saved_cwd) != 0)
- openat_restore_fail (errno);
-
- free_cwd (&saved_cwd);
if (dir)
close (fd);
-
errno = saved_errno;
return dir;
}
@@ -151,32 +199,42 @@ fstatat (int fd, char const *file, struct stat *st, int flag)
int saved_errno;
int err;
- if (fd == AT_FDCWD)
+ if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
return (flag == AT_SYMLINK_NOFOLLOW
? lstat (file, st)
: stat (file, st));
+ {
+ char *proc_file;
+ BUILD_PROC_NAME (proc_file, fd, file);
+ err = (flag == AT_SYMLINK_NOFOLLOW
+ ? lstat (proc_file, st)
+ : stat (proc_file, st));
+ /* If the syscall succeeds, or if it fails with an unexpected
+ errno value, then return right away. Otherwise, fall through
+ and resort to using save_cwd/restore_cwd. */
+ if (0 <= err || ! EXPECTED_ERRNO (errno))
+ return err;
+ }
+
if (save_cwd (&saved_cwd) != 0)
openat_save_fail (errno);
- if (fchdir (fd) != 0)
+ err = fchdir (fd);
+ saved_errno = errno;
+
+ if (! err)
{
+ err = (flag == AT_SYMLINK_NOFOLLOW
+ ? lstat (file, st)
+ : stat (file, st));
saved_errno = errno;
- free_cwd (&saved_cwd);
- errno = saved_errno;
- return -1;
- }
- err = (flag == AT_SYMLINK_NOFOLLOW
- ? lstat (file, st)
- : stat (file, st));
- saved_errno = errno;
-
- if (restore_cwd (&saved_cwd) != 0)
- openat_restore_fail (errno);
+ if (restore_cwd (&saved_cwd) != 0)
+ openat_restore_fail (errno);
+ }
free_cwd (&saved_cwd);
-
errno = saved_errno;
return err;
}
@@ -195,28 +253,36 @@ unlinkat (int fd, char const *file, int flag)
int saved_errno;
int err;
- if (fd == AT_FDCWD)
+ if (fd == AT_FDCWD || IS_ABSOLUTE_FILE_NAME (file))
return (flag == AT_REMOVEDIR ? rmdir (file) : unlink (file));
+ {
+ char *proc_file;
+ BUILD_PROC_NAME (proc_file, fd, file);
+ err = (flag == AT_REMOVEDIR ? rmdir (proc_file) : unlink (proc_file));
+ /* If the syscall succeeds, or if it fails with an unexpected
+ errno value, then return right away. Otherwise, fall through
+ and resort to using save_cwd/restore_cwd. */
+ if (0 <= err || ! EXPECTED_ERRNO (errno))
+ return err;
+ }
+
if (save_cwd (&saved_cwd) != 0)
openat_save_fail (errno);
- if (fchdir (fd) != 0)
+ err = fchdir (fd);
+ saved_errno = errno;
+
+ if (! err)
{
+ err = (flag == AT_REMOVEDIR ? rmdir (file) : unlink (file));
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)
- openat_restore_fail (errno);
+ if (restore_cwd (&saved_cwd) != 0)
+ openat_restore_fail (errno);
+ }
free_cwd (&saved_cwd);
-
errno = saved_errno;
return err;
}
diff --git a/lib/openat.h b/lib/openat.h
index 4c2a2e0b77..15b1d9df8f 100644
--- a/lib/openat.h
+++ b/lib/openat.h
@@ -23,6 +23,7 @@
#include <sys/stat.h>
#include <dirent.h>
#include <unistd.h>
+#include <stdbool.h>
#ifndef __attribute__
# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 8) || __STRICT_ANSI__
@@ -35,30 +36,39 @@
#endif
#ifndef AT_FDCWD
-# define AT_FDCWD (-3041965) /* same value as Solaris 9 */
-# define AT_SYMLINK_NOFOLLOW 4096 /* same value as Solaris 9 */
-# define AT_REMOVEDIR (0x1) /* same value as Solaris 9 */
+/* Use the same values as Solaris 9. This shouldn't matter, but
+ there's no real reason to differ. */
+# define AT_FDCWD (-3041965)
+# define AT_SYMLINK_NOFOLLOW 4096
+# define AT_REMOVEDIR 1
+#endif
+
+#ifdef __OPENAT_PREFIX
-# ifdef __OPENAT_PREFIX
-# undef openat
-# define __OPENAT_CONCAT(x, y) x ## y
-# define __OPENAT_XCONCAT(x, y) __OPENAT_CONCAT (x, y)
-# define __OPENAT_ID(y) __OPENAT_XCONCAT (__OPENAT_PREFIX, y)
-# define openat __OPENAT_ID (openat)
+# undef openat
+# define __OPENAT_CONCAT(x, y) x ## y
+# define __OPENAT_XCONCAT(x, y) __OPENAT_CONCAT (x, y)
+# define __OPENAT_ID(y) __OPENAT_XCONCAT (__OPENAT_PREFIX, y)
+# define openat __OPENAT_ID (openat)
int openat (int fd, char const *file, int flags, /* mode_t mode */ ...);
-# if ! HAVE_FDOPENDIR
-# define fdopendir __OPENAT_ID (fdopendir)
-# endif
+int openat_permissive (int fd, char const *file, int flags, mode_t mode,
+ int *cwd_errno);
+# if ! HAVE_FDOPENDIR
+# define fdopendir __OPENAT_ID (fdopendir)
+# endif
DIR *fdopendir (int fd);
-# define fstatat __OPENAT_ID (fstatat)
+# define fstatat __OPENAT_ID (fstatat)
int fstatat (int fd, char const *file, struct stat *st, int flag);
-# define unlinkat __OPENAT_ID (unlinkat)
+# define unlinkat __OPENAT_ID (unlinkat)
int unlinkat (int fd, char const *file, int flag);
-void openat_restore_fail (int) ATTRIBUTE_NORETURN;
-void openat_save_fail (int) ATTRIBUTE_NORETURN;
-# else
-# define openat_restore_fail(Errno) /* empty */
-# define openat_save_fail(Errno) /* empty */
-# endif
+
+#else
+
+# define openat_permissive(Fd, File, Flags, Mode, Cwd_errno) \
+ openat (Fd, File, Flags, Mode)
#endif
+
+int mkdirat (int fd, char const *file, mode_t mode);
+void openat_restore_fail (int) ATTRIBUTE_NORETURN;
+void openat_save_fail (int) ATTRIBUTE_NORETURN;
diff --git a/lib/posixtm.c b/lib/posixtm.c
index 85936f3c6b..5023c3442e 100644
--- a/lib/posixtm.c
+++ b/lib/posixtm.c
@@ -62,8 +62,8 @@ time_t mktime ();
(PDS_LEADING_YEAR | PDS_CENTURY | PDS_SECONDS)
touch mmddhhmm[YY] FILE... (obsoleted by POSIX 1003.1-2001)
- 8 or 10 digits
- (PDS_TRAILING_YEAR)
+ 8 or 10 digits, YY (if present) must be in the range 69-99
+ (PDS_TRAILING_YEAR | PDS_PRE_2000)
date mmddhhmm[[CC]YY]
8, 10, or 12 digits
@@ -72,7 +72,7 @@ time_t mktime ();
*/
static int
-year (struct tm *tm, const int *digit_pair, size_t n, int allow_century)
+year (struct tm *tm, const int *digit_pair, size_t n, unsigned int syntax_bits)
{
switch (n)
{
@@ -82,11 +82,15 @@ year (struct tm *tm, const int *digit_pair, size_t n, int allow_century)
POSIX requires that 00-68 be interpreted as 2000-2068,
and that 69-99 be interpreted as 1969-1999. */
if (digit_pair[0] <= 68)
- tm->tm_year += 100;
+ {
+ if (syntax_bits & PDS_PRE_2000)
+ return 1;
+ tm->tm_year += 100;
+ }
break;
case 2:
- if (!allow_century)
+ if (! (syntax_bits & PDS_CENTURY))
return 1;
tm->tm_year = digit_pair[0] * 100 + digit_pair[1] - 1900;
break;
@@ -148,7 +152,7 @@ posix_time_parse (struct tm *tm, const char *s, unsigned int syntax_bits)
p = pair;
if (syntax_bits & PDS_LEADING_YEAR)
{
- if (year (tm, p, len - 4, syntax_bits & PDS_CENTURY))
+ if (year (tm, p, len - 4, syntax_bits))
return 1;
p += len - 4;
len = 4;
@@ -164,7 +168,7 @@ posix_time_parse (struct tm *tm, const char *s, unsigned int syntax_bits)
/* Handle any trailing year. */
if (syntax_bits & PDS_TRAILING_YEAR)
{
- if (year (tm, p, len, syntax_bits & PDS_CENTURY))
+ if (year (tm, p, len, syntax_bits))
return 1;
}
diff --git a/lib/posixtm.h b/lib/posixtm.h
index 252d268db5..c17b31851a 100644
--- a/lib/posixtm.h
+++ b/lib/posixtm.h
@@ -1,6 +1,6 @@
/* Parse dates for touch and date.
- Copyright (C) 1998, 2003 Free Software Foundation Inc.
+ Copyright (C) 1998, 2003, 2005 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
@@ -27,6 +27,7 @@
# define PDS_TRAILING_YEAR 2
# define PDS_CENTURY 4
# define PDS_SECONDS 8
+# define PDS_PRE_2000 16
bool posixtime (time_t *p, const char *s, unsigned int syntax_bits);
diff --git a/lib/save-cwd.c b/lib/save-cwd.c
index 4ff600e58a..f842ccafc7 100644
--- a/lib/save-cwd.c
+++ b/lib/save-cwd.c
@@ -75,12 +75,8 @@ save_cwd (struct saved_cwd *cwd)
cwd->desc = open (".", O_RDONLY);
if (cwd->desc < 0)
{
- cwd->desc = open (".", O_WRONLY);
- if (cwd->desc < 0)
- {
- cwd->name = xgetcwd ();
- return cwd->name ? 0 : -1;
- }
+ cwd->name = xgetcwd ();
+ return cwd->name ? 0 : -1;
}
return 0;
diff --git a/lib/version-etc.c b/lib/version-etc.c
index 05bc3ad255..cb9e4c2f01 100644
--- a/lib/version-etc.c
+++ b/lib/version-etc.c
@@ -1,5 +1,5 @@
/* Utility to help print --version output in a consistent format.
- Copyright (C) 1999-2005 Free Software Foundation, Inc.
+ Copyright (C) 1999-2006 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,7 +35,7 @@
#include "gettext.h"
#define _(msgid) gettext (msgid)
-enum { COPYRIGHT_YEAR = 2005 };
+enum { COPYRIGHT_YEAR = 2006 };
/* Like version_etc, below, but with the NULL-terminated author list
provided via a variable of type va_list. */