|
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.