diff options
author | Todd C. Miller <millert@cvs.openbsd.org> | 2008-02-13 14:50:52 +0000 |
---|---|---|
committer | Todd C. Miller <millert@cvs.openbsd.org> | 2008-02-13 14:50:52 +0000 |
commit | 1fade25aa77465c09e8c40896b78c15a89b5bd84 (patch) | |
tree | ecd1c1b353a752e9dfedd8d6faa86c2f51b15eb2 /bin/mkdir/mkdir.c | |
parent | 3c8792186afbd1eaf231282df06c176271789239 (diff) |
Rework the fix in 1.20. The original fix causes problems for systrace
policies since mkdir(2) will be called for each directory in the path,
even things like / or /usr. We now use a hybrid approach uses stat(2)
until either we find something missing or we reach that last component.
Then we switch to calling mkdir(). Tested by bernd@ and chl@
Diffstat (limited to 'bin/mkdir/mkdir.c')
-rw-r--r-- | bin/mkdir/mkdir.c | 20 |
1 files changed, 12 insertions, 8 deletions
diff --git a/bin/mkdir/mkdir.c b/bin/mkdir/mkdir.c index 0a2fe086224..b4e320998c5 100644 --- a/bin/mkdir/mkdir.c +++ b/bin/mkdir/mkdir.c @@ -1,4 +1,4 @@ -/* $OpenBSD: mkdir.c,v 1.20 2008/01/02 09:27:02 chl Exp $ */ +/* $OpenBSD: mkdir.c,v 1.21 2008/02/13 14:50:51 millert Exp $ */ /* $NetBSD: mkdir.c,v 1.14 1995/06/25 21:59:21 mycroft Exp $ */ /* @@ -40,7 +40,7 @@ static char copyright[] = #if 0 static char sccsid[] = "@(#)mkdir.c 8.2 (Berkeley) 1/25/94"; #else -static char rcsid[] = "$OpenBSD: mkdir.c,v 1.20 2008/01/02 09:27:02 chl Exp $"; +static char rcsid[] = "$OpenBSD: mkdir.c,v 1.21 2008/02/13 14:50:51 millert Exp $"; #endif #endif /* not lint */ @@ -143,7 +143,7 @@ mkpath(char *path, mode_t mode, mode_t dir_mode) { struct stat sb; char *slash; - int done; + int done, exists; slash = path; @@ -154,12 +154,16 @@ mkpath(char *path, mode_t mode, mode_t dir_mode) done = (*slash == '\0'); *slash = '\0'; - if (mkdir(path, done ? mode : dir_mode) < 0) { - int mkdir_errno = errno; + /* skip existing path components */ + exists = !stat(path, &sb); + if (!done && exists && S_ISDIR(sb.st_mode)) { + *slash = '/'; + continue; + } - if (stat(path, &sb)) { - /* Not there; use mkdir()s errno */ - errno = mkdir_errno; + if (mkdir(path, done ? mode : dir_mode) < 0) { + if (!exists) { + /* Not there */ warn("%s", path); return (-1); } |