ensure-directories aka create-directories
Lassi Kortela
(31 Jul 2020 10:47 UTC)
|
||
(missing)
|
||
(missing)
|
||
Re: ensure-directories aka create-directories
Lassi Kortela
(31 Jul 2020 12:32 UTC)
|
||
Re: ensure-directories aka create-directories
John Cowan
(31 Jul 2020 13:03 UTC)
|
||
Re: ensure-directories aka create-directories
John Cowan
(31 Jul 2020 13:10 UTC)
|
||
Re: ensure-directories aka create-directories
Lassi Kortela
(31 Jul 2020 13:14 UTC)
|
||
Re: ensure-directories aka create-directories
John Cowan
(31 Jul 2020 13:19 UTC)
|
||
Re: ensure-directories aka create-directories
Lassi Kortela
(31 Jul 2020 13:31 UTC)
|
||
Re: ensure-directories aka create-directories
Shiro Kawai
(31 Jul 2020 18:03 UTC)
|
||
Re: ensure-directories aka create-directories Lassi Kortela (02 Aug 2020 10:20 UTC)
|
||
Re: ensure-directories aka create-directories
Lassi Kortela
(31 Jul 2020 12:10 UTC)
|
> Gauche took the layered approach, i.e. POSIX.1 calls are mostly > supported as built-in (with sys-* name), and POSIX.2 features are built > on top of it (e.g. file.util module). > > However, I browsed my file.util implementation again, and now I tend to > agree with Lassi that 'mkdir -p' is tricky yet very often used (I now > remember I had wrong implementation with a race condition and fixed it > sometime ago.) > copy-file is another one that requires more code than one naively > thinks, but it is probably less frequently used. > > So yeah, I'm now fine with having 'mkdir -p'. I tried writing it in C, and it's _very_ hard! Now I'm no longer sure that it should be in a fundamental SRFI like 170 :D Maybe it doesn't matter which SRFI it goes in, as long as we have it. I do agree that it's useful much more often than others like it. The code below is wrong because it uses readlink() to normalize the `path` argument, but that fails when it doesn't exist. And looping over a non-normalized pathname would probably be prone to subtle bugs. #include <sys/stat.h> #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> static int ensure_directory(const char *path, mode_t mode) { struct stat st; char *buf; char *limit; char oldc; if (!(buf = realpath(path, NULL))) { return -1; } fprintf(stderr, "real = %s\n", buf); limit = buf; for (;;) { while (*limit == '/') limit++; while (*limit && (*limit != '/')) limit++; oldc = *limit; *limit = '\0'; fprintf(stderr, "making %s\n", buf); if (mkdir(buf, mode) == 0) break; if ((errno != EEXIST) && (errno != EISDIR)) { free(buf); return -1; } *limit = oldc; if (!oldc) break; limit++; } if (lstat(buf, &st) == -1) { free(buf); return -1; } free(buf); if (!S_ISDIR(st.st_mode)) { errno = ENOTDIR; return -1; } return 0; } int main(int argc, char **argv) { const char *path; if (argc != 2) { fprintf(stderr, "usage: path\n"); return 1; } path = argv[1]; if (ensure_directory(path, 0600) == -1) { fprintf(stderr, "%s\n", strerror(errno)); return 1; } printf("ok\n"); return 0; } > OTOH, 'rm -r' doesn't > seem too many pitfalls so probably we won't need it. That's probably right. We only need to make sure we don't follow symlinks at any point. `rm -rf` also probably should stop at file system boundaries (where struct stat.st_dev changes) like `rsync -x`. But trying to rmdir() a mount point probably fails, which accomplishes the same thing.