aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/lib.c49
-rw-r--r--lib/lib.h2
-rw-r--r--lib/xwrap.c28
-rw-r--r--toys/posix/mkdir.c49
-rw-r--r--toys/posix/patch.c8
5 files changed, 52 insertions, 84 deletions
diff --git a/lib/lib.c b/lib/lib.c
index 7a3ada4a..1efb642f 100644
--- a/lib/lib.c
+++ b/lib/lib.c
@@ -116,6 +116,55 @@ off_t lskip(int fd, off_t offset)
return offset;
}
+// flags: 1=make last dir (with mode lastmode, otherwise skips last component)
+// 2=make path (already exists is ok)
+// 4=verbose
+// returns 0 = path ok, 1 = error
+int mkpathat(int atfd, char *dir, mode_t lastmode, int flags)
+{
+ struct stat buf;
+ char *s;
+
+ // mkdir -p one/two/three is not an error if the path already exists,
+ // but is if "three" is a file. The others we dereference and catch
+ // not-a-directory along the way, but the last one we must explicitly
+ // test for. Might as well do it up front.
+
+ if (!fstatat(atfd, dir, &buf, 0) && !S_ISDIR(buf.st_mode)) {
+ errno = EEXIST;
+ return 1;
+ }
+
+ // Skip leading / of absolute paths
+ while (*dir == '/') dir++;
+
+ for (s=dir; ;s++) {
+ char save = 0;
+ mode_t mode = (0777&~toys.old_umask)|0300;
+
+ // Skip leading / of absolute paths.
+ if (*s == '/' && (flags&2)) {
+ save = *s;
+ *s = 0;
+ } else if (*s) continue;
+
+ // Use the mode from the -m option only for the last directory.
+ if (!save) {
+ if (flags&1) mode = lastmode;
+ else break;
+ }
+
+ if (mkdirat(atfd, dir, mode)) {
+ if (!(flags&2) || errno != EEXIST) return 1;
+ } else if (flags&4)
+ fprintf(stderr, "%s: created directory '%s'\n", toys.which->name, dir);
+
+ if (!(*s = save)) break;
+ }
+
+ return 0;
+}
+
// Split a path into linked list of components, tracking head and tail of list.
// Filters out // entries with no contents.
struct string_list **splitpath(char *path, struct string_list **list)
diff --git a/lib/lib.h b/lib/lib.h
index 6355b3e1..56927b8b 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -110,7 +110,6 @@ char *xabspath(char *path, int exact);
char *xrealpath(char *path);
void xchdir(char *path);
void xchroot(char *path);
-void xmkpath(char *path, int mode);
struct passwd *xgetpwuid(uid_t uid);
struct group *xgetgrgid(gid_t gid);
struct passwd *xgetpwnam(char *name);
@@ -128,6 +127,7 @@ void perror_exit(char *msg, ...) noreturn;
ssize_t readall(int fd, void *buf, size_t len);
ssize_t writeall(int fd, void *buf, size_t len);
off_t lskip(int fd, off_t offset);
+int mkpathat(int atfd, char *dir, mode_t lastmode, int flags);
struct string_list **splitpath(char *path, struct string_list **list);
char *readfile(char *name, char *buf, off_t len);
void msleep(long miliseconds);
diff --git a/lib/xwrap.c b/lib/xwrap.c
index 2ecffaad..51bd2b43 100644
--- a/lib/xwrap.c
+++ b/lib/xwrap.c
@@ -369,34 +369,6 @@ void xchroot(char *path)
xchdir("/");
}
-// Ensure entire path exists.
-// If mode != -1 set permissions on newly created dirs.
-// Requires that path string be writable (for temporary null terminators).
-void xmkpath(char *path, int mode)
-{
- char *p, old;
- mode_t mask;
- int rc;
- struct stat st;
-
- for (p = path; ; p++) {
- if (!*p || *p == '/') {
- old = *p;
- *p = rc = 0;
- if (stat(path, &st) || !S_ISDIR(st.st_mode)) {
- if (mode != -1) {
- mask=umask(0);
- rc = mkdir(path, mode);
- umask(mask);
- } else rc = mkdir(path, 0777);
- }
- *p = old;
- if(rc) perror_exit("mkpath '%s'", path);
- }
- if (!*p) break;
- }
-}
-
struct passwd *xgetpwuid(uid_t uid)
{
struct passwd *pwd = getpwuid(uid);
diff --git a/toys/posix/mkdir.c b/toys/posix/mkdir.c
index 25dfb0de..5cbc28db 100644
--- a/toys/posix/mkdir.c
+++ b/toys/posix/mkdir.c
@@ -25,55 +25,6 @@ GLOBALS(
char *arg_mode;
)
-// flags: 1=make last dir (with mode lastmode, otherwise skips last component)
-// 2=make path (already exists is ok)
-// 4=verbose
-// returns 0 = path ok, 1 = error
-int mkpathat(int atfd, char *dir, mode_t lastmode, int flags)
-{
- struct stat buf;
- char *s;
-
- // mkdir -p one/two/three is not an error if the path already exists,
- // but is if "three" is a file. The others we dereference and catch
- // not-a-directory along the way, but the last one we must explicitly
- // test for. Might as well do it up front.
-
- if (!fstatat(atfd, dir, &buf, 0) && !S_ISDIR(buf.st_mode)) {
- errno = EEXIST;
- return 1;
- }
-
- // Skip leading / of absolute paths
- while (*dir == '/') dir++;
-
- for (s=dir; ;s++) {
- char save = 0;
- mode_t mode = (0777&~toys.old_umask)|0300;
-
- // Skip leading / of absolute paths.
- if (*s == '/' && (flags&2)) {
- save = *s;
- *s = 0;
- } else if (*s) continue;
-
- // Use the mode from the -m option only for the last directory.
- if (!save) {
- if (flags&1) mode = lastmode;
- else break;
- }
-
- if (mkdirat(atfd, dir, mode)) {
- if (!(flags&2) || errno != EEXIST) return 1;
- } else if (flags&4)
- fprintf(stderr, "%s: created directory '%s'\n", toys.which->name, dir);
-
- if (!(*s = save)) break;
- }
-
- return 0;
-}
-
void mkdir_main(void)
{
char **s;
diff --git a/toys/posix/patch.c b/toys/posix/patch.c
index ae24ff94..27828015 100644
--- a/toys/posix/patch.c
+++ b/toys/posix/patch.c
@@ -385,12 +385,8 @@ void patch_main(void)
if ((!strcmp(oldname, "/dev/null") || !oldsum) && access(name, F_OK))
{
printf("creating %s\n", name);
- s = strrchr(name, '/');
- if (s) {
- *s = 0;
- xmkpath(name, -1);
- *s = '/';
- }
+ if (mkpathat(AT_FDCWD, name, 0, 2))
+ perror_exit("mkpath %s", name);
TT.filein = xcreate(name, O_CREAT|O_EXCL|O_RDWR, 0666);
} else {
printf("patching %s\n", name);