Mercurial > gnulib
annotate lib/mkancesdirs.c @ 40186:8964917f9574
autoupdate
author | Karl Berry <karl@freefriends.org> |
---|---|
date | Mon, 18 Feb 2019 08:02:49 -0800 |
parents | b06060465f09 |
children |
rev | line source |
---|---|
6969 | 1 /* Make a file's ancestor directories. |
2 | |
40057
b06060465f09
maint: Run 'make update-copyright'
Paul Eggert <eggert@cs.ucla.edu>
parents:
19484
diff
changeset
|
3 Copyright (C) 2006, 2009-2019 Free Software Foundation, Inc. |
6969 | 4 |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
7418
diff
changeset
|
5 This program is free software: you can redistribute it and/or modify |
6969 | 6 it under the terms of the GNU General Public License as published by |
9309
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
7418
diff
changeset
|
7 the Free Software Foundation; either version 3 of the License, or |
bbbbbf4cd1c5
Change copyright notice from GPLv2+ to GPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
7418
diff
changeset
|
8 (at your option) any later version. |
6969 | 9 |
10 This program is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
13 GNU General Public License for more details. | |
14 | |
15 You should have received a copy of the GNU General Public License | |
19190 | 16 along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
6969 | 17 |
18 /* Written by Paul Eggert. */ | |
19 | |
7302
8a1a9361108c
* _fpending.c: Include <config.h> unconditionally, since we no
Paul Eggert <eggert@cs.ucla.edu>
parents:
6969
diff
changeset
|
20 #include <config.h> |
6969 | 21 |
22 #include "mkancesdirs.h" | |
23 | |
7312
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
24 #include <sys/types.h> |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
25 #include <sys/stat.h> |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
26 #include <fcntl.h> |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
27 |
6969 | 28 #include <errno.h> |
7312
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
29 #include <unistd.h> |
6969 | 30 |
31 #include "dirname.h" | |
7312
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
32 #include "savewd.h" |
6969 | 33 |
34 /* Ensure that the ancestor directories of FILE exist, using an | |
35 algorithm that should work even if two processes execute this | |
7312
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
36 function in parallel. Modify FILE as necessary to access the |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
37 ancestor directories, but restore FILE to an equivalent value |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
38 if successful. |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
39 |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
40 WD points to the working directory, using the conventions of |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
41 savewd. |
6969 | 42 |
43 Create any ancestor directories that don't already exist, by | |
7418
77a75e20049c
* mkancesdirs.c (mkancesdirs): Pass to MAKE_DIR both the full file
Paul Eggert <eggert@cs.ucla.edu>
parents:
7312
diff
changeset
|
44 invoking MAKE_DIR (FILE, COMPONENT, MAKE_DIR_ARG). This function |
18104
76e10610d806
savewd: remove SAVEWD_CHDIR_READABLE
Paul Eggert <eggert@cs.ucla.edu>
parents:
17848
diff
changeset
|
45 should return 0 if successful, -1 (setting errno) otherwise. If |
76e10610d806
savewd: remove SAVEWD_CHDIR_READABLE
Paul Eggert <eggert@cs.ucla.edu>
parents:
17848
diff
changeset
|
46 COMPONENT is relative, it is relative to the temporary working |
76e10610d806
savewd: remove SAVEWD_CHDIR_READABLE
Paul Eggert <eggert@cs.ucla.edu>
parents:
17848
diff
changeset
|
47 directory, which may differ from *WD. |
6969 | 48 |
7312
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
49 Ordinarily MAKE_DIR is executed with the working directory changed |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
50 to reflect the already-made prefix, and mkancesdirs returns with |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
51 the working directory changed a prefix of FILE. However, if the |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
52 initial working directory cannot be saved in a file descriptor, |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
53 MAKE_DIR is invoked in a subprocess and this function returns in |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
54 both the parent and child process, so the caller should not assume |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
55 any changed state survives other than the EXITMAX component of WD, |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
56 and the caller should take care that the parent does not attempt to |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
57 do the work that the child is doing. |
6969 | 58 |
7312
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
59 If successful and if this process can go ahead and create FILE, |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
60 return the length of the prefix of FILE that has already been made. |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
61 If successful so far but a child process is doing the actual work, |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
62 return -2. If unsuccessful, return -1 and set errno. */ |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
63 |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
64 ptrdiff_t |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
65 mkancesdirs (char *file, struct savewd *wd, |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
66 int (*make_dir) (char const *, char const *, void *), |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
67 void *make_dir_arg) |
6969 | 68 { |
69 /* Address of the previous directory separator that follows an | |
70 ordinary byte in a file name in the left-to-right scan, or NULL | |
71 if no such separator precedes the current location P. */ | |
72 char *sep = NULL; | |
73 | |
7312
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
74 /* Address of the leftmost file name component that has not yet |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
75 been processed. */ |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
76 char *component = file; |
6969 | 77 |
7312
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
78 char *p = file + FILE_SYSTEM_PREFIX_LEN (file); |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
79 char c; |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
80 bool made_dir = false; |
6969 | 81 |
7312
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
82 /* Scan forward through FILE, creating and chdiring into directories |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
83 along the way. Try MAKE_DIR before chdir, so that the procedure |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
84 works even when two or more processes are executing it in |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
85 parallel. Isolate each file name component by having COMPONENT |
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
86 point to its start and SEP point just after its end. */ |
6969 | 87 |
88 while ((c = *p++)) | |
89 if (ISSLASH (*p)) | |
90 { | |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
91 if (! ISSLASH (c)) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
92 sep = p; |
6969 | 93 } |
94 else if (ISSLASH (c) && *p && sep) | |
95 { | |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
96 /* Don't bother to make or test for "." since it does not |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
97 affect the algorithm. */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
98 if (! (sep - component == 1 && component[0] == '.')) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
99 { |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
100 int make_dir_errno = 0; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
101 int savewd_chdir_options = 0; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
102 int chdir_result; |
7312
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
103 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
104 /* Temporarily modify FILE to isolate this file name |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
105 component. */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
106 *sep = '\0'; |
7312
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
107 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
108 /* Invoke MAKE_DIR on this component, except don't bother |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
109 with ".." since it must exist if its "parent" does. */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
110 if (sep - component == 2 |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
111 && component[0] == '.' && component[1] == '.') |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
112 made_dir = false; |
18104
76e10610d806
savewd: remove SAVEWD_CHDIR_READABLE
Paul Eggert <eggert@cs.ucla.edu>
parents:
17848
diff
changeset
|
113 else if (make_dir (file, component, make_dir_arg) < 0) |
76e10610d806
savewd: remove SAVEWD_CHDIR_READABLE
Paul Eggert <eggert@cs.ucla.edu>
parents:
17848
diff
changeset
|
114 make_dir_errno = errno; |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
115 else |
18104
76e10610d806
savewd: remove SAVEWD_CHDIR_READABLE
Paul Eggert <eggert@cs.ucla.edu>
parents:
17848
diff
changeset
|
116 made_dir = true; |
7312
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
117 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
118 if (made_dir) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
119 savewd_chdir_options |= SAVEWD_CHDIR_NOFOLLOW; |
7312
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
120 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
121 chdir_result = |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
122 savewd_chdir (wd, component, savewd_chdir_options, NULL); |
7312
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
123 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
124 /* Undo the temporary modification to FILE, unless there |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
125 was a failure. */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
126 if (chdir_result != -1) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
127 *sep = '/'; |
7312
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
128 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
129 if (chdir_result != 0) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
130 { |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
131 if (make_dir_errno != 0 && errno == ENOENT) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
132 errno = make_dir_errno; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
133 return chdir_result; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
134 } |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
135 } |
7312
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
136 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9309
diff
changeset
|
137 component = p; |
6969 | 138 } |
139 | |
7312
796e1837ac66
* lib/dirchownmod.c: Don't include fcntl.h; no longer needed.
Paul Eggert <eggert@cs.ucla.edu>
parents:
7302
diff
changeset
|
140 return component - file; |
6969 | 141 } |