1 /* Make a file's ancestor directories.
3 Copyright (C) 2006 Free Software Foundation, Inc.
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
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.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software Foundation,
17 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
19 /* Written by Paul Eggert. */
25 #include "mkancesdirs.h"
31 #include "stat-macros.h"
33 /* Return 0 if FILE is a directory, otherwise -1 (setting errno). */
36 test_dir (char const *file)
39 if (stat (file, &st) == 0)
41 if (S_ISDIR (st.st_mode))
48 /* Ensure that the ancestor directories of FILE exist, using an
49 algorithm that should work even if two processes execute this
50 function in parallel. Temporarily modify FILE by storing '\0'
51 bytes into it, to access the ancestor directories.
53 Create any ancestor directories that don't already exist, by
54 invoking MAKE_DIR (ANCESTOR, MAKE_DIR_ARG). This function should
55 return zero if successful, -1 (setting errno) otherwise.
57 If successful, return 0 with FILE set back to its original value;
58 otherwise, return -1 (setting errno), storing a '\0' into *FILE so
59 that it names the ancestor directory that had problems. */
62 mkancesdirs (char *file,
63 int (*make_dir) (char const *, void *),
66 /* This algorithm is O(N**2) but in typical practice the fancier
67 O(N) algorithms are slower. */
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. */
74 char const *prefix_end = file + FILE_SYSTEM_PREFIX_LEN (file);
78 /* Search backward through FILE using mkdir to create the
79 furthest-away ancestor that is needed. This loop isn't needed
80 for correctness, but typically ancestors already exist so this
81 loop speeds things up a bit.
83 This loop runs a bit faster if errno initially contains an error
84 number corresponding to a failed access to FILE. However, things
85 work correctly regardless of errno's initial value. */
87 for (p = last_component (file); prefix_end < p; p--)
88 if (ISSLASH (*p) && ! ISSLASH (p[-1]))
92 if (errno == ENOENT && make_dir (file, make_dir_arg) == 0)
100 if (test_dir (file) == 0)
112 /* Scan forward through FILE, creating directories along the way.
113 Try mkdir before stat, so that the procedure works even when two
114 or more processes are executing it in parallel. */
122 else if (ISSLASH (c) && *p && sep)
125 if (make_dir (file, make_dir_arg) != 0 && test_dir (file) != 0)