annotate lib/mkdir-p.c @ 6527:6b31c8787689

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.
author Paul Eggert <eggert@cs.ucla.edu>
date Mon, 09 Jan 2006 23:13:56 +0000
parents fdd622fe6d47
children bbdf9204a185
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
1 /* mkdir-p.c -- Ensure that a directory and its parents exist.
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
2
6527
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
3 Copyright (C) 1990, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
4 Free Software Foundation, Inc.
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
5
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
6 This program is free software; you can redistribute it and/or modify
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
7 it under the terms of the GNU General Public License as published by
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
8 the Free Software Foundation; either version 2, or (at your option)
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
9 any later version.
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
10
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
11 This program is distributed in the hope that it will be useful,
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
14 GNU General Public License for more details.
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
15
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
16 You should have received a copy of the GNU General Public License
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
17 along with this program; if not, write to the Free Software Foundation,
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
18 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
19
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
20 /* Written by David MacKenzie <djm@gnu.ai.mit.edu> and Jim Meyering. */
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
21
6259
96c32553b4c6 Use a consistent style for including <config.h>.
Paul Eggert <eggert@cs.ucla.edu>
parents: 5948
diff changeset
22 #ifdef HAVE_CONFIG_H
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
23 # include <config.h>
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
24 #endif
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
25
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
26 #include "mkdir-p.h"
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
27
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
28 #include <alloca.h>
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
29
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
30 #include <stdio.h>
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
31 #include <sys/types.h>
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
32 #include <sys/stat.h>
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
33 #include <unistd.h>
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
34
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
35 #include <stdlib.h>
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
36 #include <errno.h>
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
37 #include <string.h>
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
38
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
39 #include "gettext.h"
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
40 #define _(msgid) gettext (msgid)
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
41
6527
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
42 #include "chdir-safer.h"
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
43 #include "dirname.h"
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
44 #include "error.h"
6527
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
45 #include "lchmod.h"
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
46 #include "lchown.h"
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
47 #include "quote.h"
6527
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
48 #include "save-cwd.h"
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
49 #include "stat-macros.h"
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
50
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
51 /* Ensure that the directory ARG exists.
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
52
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
53 Create any leading directories that don't already exist, with
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
54 permissions PARENT_MODE.
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
55 If the last element of ARG does not exist, create it as
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
56 a new directory with permissions MODE.
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
57 If OWNER and GROUP are non-negative, use them to set the UID and GID of
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
58 any created directories.
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
59 If VERBOSE_FMT_STRING is nonzero, use it as a printf format
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
60 string for printing a message after successfully making a directory,
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
61 with the name of the directory that was just made as an argument.
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
62 If PRESERVE_EXISTING is true and ARG is an existing directory,
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
63 then do not attempt to set its permissions and ownership.
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
64
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
65 Set *CWD_ERRNO to a (nonzero) error number if this
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
66 function has changed the current working directory and is unable to
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
67 restore it to its initial state. Do not change
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
68 *CWD_ERRNO otherwise.
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
69
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
70 Return true iff ARG exists as a directory with the proper ownership
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
71 and permissions when done. Note that this function returns true
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
72 even when it fails to return to the initial working directory. */
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
73
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
74 bool
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
75 make_dir_parents (char const *arg,
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
76 mode_t mode,
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
77 mode_t parent_mode,
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
78 uid_t owner,
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
79 gid_t group,
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
80 bool preserve_existing,
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
81 char const *verbose_fmt_string,
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
82 int *cwd_errno)
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
83 {
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
84 struct stat stats;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
85 bool retval = true;
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
86 bool do_chdir = false; /* Whether to chdir before each mkdir. */
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
87 struct saved_cwd cwd;
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
88 bool cwd_problem = false;
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
89 char const *fixup_permissions_dir = NULL;
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
90 char const *full_dir = arg;
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
91
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
92 struct ptr_list
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
93 {
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
94 char *dirname_end;
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
95 struct ptr_list *next;
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
96 };
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
97 struct ptr_list *leading_dirs = NULL;
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
98
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
99 if (stat (arg, &stats) == 0)
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
100 {
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
101 if (! S_ISDIR (stats.st_mode))
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
102 {
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
103 error (0, 0, _("%s exists but is not a directory"), quote (arg));
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
104 return false;
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
105 }
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
106
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
107 if (!preserve_existing)
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
108 fixup_permissions_dir = arg;
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
109 }
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
110 else if (errno != ENOENT || !*arg)
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
111 {
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
112 error (0, errno, "%s", quote (arg));
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
113 return false;
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
114 }
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
115 else
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
116 {
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
117 char *slash;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
118 mode_t tmp_mode; /* Initial perms for leading dirs. */
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
119 bool re_protect; /* Should leading dirs be unwritable? */
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
120 char *basename_dir;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
121 char *dir;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
122
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
123 /* Temporarily relax umask in case it's overly restrictive. */
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
124 mode_t oldmask = umask (0);
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
125
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
126 /* Make a copy of ARG that we can scribble NULs on. */
6527
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
127 dir = alloca (strlen (arg) + 1);
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
128 strcpy (dir, arg);
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
129 strip_trailing_slashes (dir);
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
130 full_dir = dir;
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
131
6527
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
132 /* If leading directories shouldn't be readable, writable or executable,
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
133 or should have set[ug]id or sticky bits set and we are setting
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
134 their owners, we need to fix their permissions after making them. */
6527
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
135 if (((parent_mode & S_IRWXU) != S_IRWXU)
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
136 || ((owner != (uid_t) -1 || group != (gid_t) -1)
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
137 && (parent_mode & (S_ISUID | S_ISGID | S_ISVTX)) != 0))
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
138 {
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
139 tmp_mode = S_IRWXU;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
140 re_protect = true;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
141 }
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
142 else
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
143 {
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
144 tmp_mode = parent_mode;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
145 re_protect = false;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
146 }
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
147
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
148 /* If we can record the current working directory, we may be able
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
149 to do the chdir optimization. */
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
150 do_chdir = (save_cwd (&cwd) == 0);
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
151
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
152 /* If we've saved the cwd and DIR is an absolute file name,
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
153 we must chdir to `/' in order to enable the chdir optimization.
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
154 So if chdir ("/") fails, turn off the optimization. */
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
155 if (do_chdir && dir[0] == '/')
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
156 {
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
157 /* POSIX says "//" might be special, so chdir to "//" if the
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
158 file name starts with exactly two slashes. */
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
159 char const *root = "//" + (dir[1] != '/' || dir[2] == '/');
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
160 if (chdir (root) != 0)
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
161 {
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
162 free_cwd (&cwd);
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
163 do_chdir = false;
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
164 }
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
165 }
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
166
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
167 slash = dir;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
168
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
169 /* Skip over leading slashes. */
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
170 while (*slash == '/')
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
171 slash++;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
172
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
173 while (true)
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
174 {
6527
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
175 bool dir_known_to_exist;
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
176 int mkdir_errno;
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
177
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
178 /* slash points to the leftmost unprocessed component of dir. */
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
179 basename_dir = slash;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
180
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
181 slash = strchr (slash, '/');
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
182 if (slash == NULL)
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
183 break;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
184
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
185 /* If we're *not* doing chdir before each mkdir, then we have to refer
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
186 to the target using the full (multi-component) directory name. */
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
187 if (!do_chdir)
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
188 basename_dir = dir;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
189
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
190 *slash = '\0';
6527
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
191 dir_known_to_exist = (mkdir (basename_dir, tmp_mode) == 0);
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
192 mkdir_errno = errno;
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
193
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
194 if (dir_known_to_exist)
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
195 {
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
196 if (verbose_fmt_string)
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
197 error (0, 0, verbose_fmt_string, quote (dir));
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
198
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
199 if ((owner != (uid_t) -1 || group != (gid_t) -1)
6527
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
200 && lchown (basename_dir, owner, group)
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
201 #if defined AFS && defined EPERM
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
202 && errno != EPERM
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
203 #endif
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
204 )
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
205 {
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
206 error (0, errno, _("cannot change owner and/or group of %s"),
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
207 quote (dir));
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
208 retval = false;
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
209 break;
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
210 }
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
211
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
212 if (re_protect)
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
213 {
6527
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
214 struct ptr_list *new = alloca (sizeof *new);
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
215 new->dirname_end = slash;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
216 new->next = leading_dirs;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
217 leading_dirs = new;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
218 }
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
219 }
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
220
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
221 /* If we were able to save the initial working directory,
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
222 then we can use chdir to change into each directory before
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
223 creating an entry in that directory. This avoids making
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
224 mkdir process O(n^2) file name components. */
6527
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
225 if (do_chdir)
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
226 {
6527
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
227 /* If we know that basename_dir is a directory (because we've
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
228 just created it), then ensure that when we change to it,
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
229 that final component is not a symlink. Otherwise, we must
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
230 accept the possibility that basename_dir is a preexisting
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
231 symlink-to-directory and chdir through the symlink. */
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
232 if ((dir_known_to_exist
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
233 ? chdir_no_follow (basename_dir)
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
234 : chdir (basename_dir)) == 0)
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
235 dir_known_to_exist = true;
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
236 else if (dir_known_to_exist)
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
237 {
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
238 error (0, errno, _("cannot chdir to directory %s"),
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
239 quote (dir));
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
240 retval = false;
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
241 break;
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
242 }
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
243 }
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
244 else if (!dir_known_to_exist)
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
245 dir_known_to_exist = (stat (basename_dir, &stats) == 0
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
246 && S_ISDIR (stats.st_mode));
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
247
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
248 if (!dir_known_to_exist)
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
249 {
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
250 error (0, mkdir_errno, _("cannot create directory %s"),
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
251 quote (dir));
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
252 retval = false;
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
253 break;
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
254 }
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
255
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
256 *slash++ = '/';
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
257
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
258 /* Avoid unnecessary calls to mkdir when given
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
259 file names containing multiple adjacent slashes. */
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
260 while (*slash == '/')
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
261 slash++;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
262 }
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
263
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
264 if (!do_chdir)
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
265 basename_dir = dir;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
266
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
267 /* Done creating leading directories. Restore original umask. */
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
268 umask (oldmask);
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
269
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
270 /* We're done making leading directories.
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
271 Create the final component of the file name. */
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
272 if (retval)
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
273 {
6527
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
274 bool dir_known_to_exist = (mkdir (basename_dir, mode) == 0);
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
275 int mkdir_errno = errno;
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
276 struct stat sbuf;
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
277
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
278 if ( ! dir_known_to_exist)
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
279 dir_known_to_exist = (stat (basename_dir, &sbuf) == 0
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
280 && S_ISDIR (sbuf.st_mode));
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
281
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
282 if ( ! dir_known_to_exist)
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
283 {
6527
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
284 error (0, mkdir_errno,
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
285 _("cannot create directory %s"), quote (dir));
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
286 retval = false;
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
287 }
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
288 else
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
289 {
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
290 if (verbose_fmt_string)
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
291 error (0, 0, verbose_fmt_string, quote (dir));
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
292 fixup_permissions_dir = basename_dir;
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
293 }
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
294 }
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
295 }
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
296
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
297 if (fixup_permissions_dir)
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
298 {
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
299 /* chown must precede chmod because on some systems,
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
300 chown clears the set[ug]id bits for non-superusers,
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
301 resulting in incorrect permissions.
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
302 On System V, users can give away files with chown and then not
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
303 be able to chmod them. So don't give files away. */
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
304
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
305 if (owner != (uid_t) -1 || group != (gid_t) -1)
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
306 {
6527
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
307 if (lchown (fixup_permissions_dir, owner, group) != 0
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
308 #ifdef AFS
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
309 && errno != EPERM
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
310 #endif
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
311 )
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
312 {
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
313 error (0, errno, _("cannot change owner and/or group of %s"),
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
314 quote (full_dir));
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
315 retval = false;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
316 }
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
317 }
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
318
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
319 /* The above chown may have turned off some permission bits in MODE.
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
320 Another reason we may have to use chmod here is that mkdir(2) is
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
321 required to honor only the file permission bits. In particular,
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
322 it need not honor the `special' bits, so if MODE includes any
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
323 special bits, set them here. */
6527
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
324 if ((mode & ~S_IRWXUGO) && lchmod (fixup_permissions_dir, mode) != 0)
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
325 {
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
326 error (0, errno, _("cannot change permissions of %s"),
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
327 quote (full_dir));
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
328 retval = false;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
329 }
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
330 }
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
331
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
332 if (do_chdir)
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
333 {
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
334 if (restore_cwd (&cwd) != 0)
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
335 {
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
336 *cwd_errno = errno;
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
337 cwd_problem = true;
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
338 }
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
339 free_cwd (&cwd);
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
340 }
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
341
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
342 /* If the mode for leading directories didn't include owner "wx"
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
343 privileges, reset their protections to the correct value. */
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
344 for (; leading_dirs != NULL; leading_dirs = leading_dirs->next)
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
345 {
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
346 leading_dirs->dirname_end[0] = '\0';
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
347 if ((cwd_problem && *full_dir != '/')
6527
6b31c8787689 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6271
diff changeset
348 || lchmod (full_dir, parent_mode) != 0)
6271
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
349 {
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
350 error (0, (cwd_problem ? 0 : errno),
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
351 _("cannot change permissions of %s"), quote (full_dir));
fdd622fe6d47 * mkdir-p.c (ENOSYS): Define to EEXIST if not defined.
Paul Eggert <eggert@cs.ucla.edu>
parents: 6259
diff changeset
352 retval = false;
5907
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
353 }
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
354 }
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
355
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
356 return retval;
c47674a83a78 Sync from coreutils.
Paul Eggert <eggert@cs.ucla.edu>
parents:
diff changeset
357 }