summaryrefslogtreecommitdiff
path: root/bin/mkdir/mkdir.c
diff options
context:
space:
mode:
authorTodd C. Miller <millert@cvs.openbsd.org>2008-02-13 14:50:52 +0000
committerTodd C. Miller <millert@cvs.openbsd.org>2008-02-13 14:50:52 +0000
commit1fade25aa77465c09e8c40896b78c15a89b5bd84 (patch)
treeecd1c1b353a752e9dfedd8d6faa86c2f51b15eb2 /bin/mkdir/mkdir.c
parent3c8792186afbd1eaf231282df06c176271789239 (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.c20
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);
}