From b21778b7f432c9c5a9c3e5e442b2305cbcc0d524 Mon Sep 17 00:00:00 2001 From: Kaz Kylheku Date: Sat, 25 Jan 2020 22:49:35 -0800 Subject: ensure-dir: fail if exists and not dir. * sysif.c (do_stat, do_lstat): Functions relocated before mkdir_nothrow_exists. (mkdir_nothrow_exists): In the EEXIST case, call stat on the object. If it's not a directory or a symlink to a directory, then do not suppress the error; propagate it to the caller, where it will become an exception. * txr.1: Specify the behavior of ensure-dir more precisely: that it only supresses the existence error for directories and directory symlinks. --- sysif.c | 50 ++++++++++++++++++++++++++++++-------------------- txr.1 | 5 ++++- 2 files changed, 34 insertions(+), 21 deletions(-) diff --git a/sysif.c b/sysif.c index dbaf8e59..369f1890 100644 --- a/sysif.c +++ b/sysif.c @@ -301,6 +301,28 @@ static val mkdir_wrap(val path, val mode) } #endif +#if HAVE_SYS_STAT +static int do_stat(val wpath, struct stat *buf) +{ + char *path = utf8_dup_to(c_str(wpath)); + int res = stat(path, buf); + free(path); + return res; +} + +#ifdef S_IFLNK +static int do_lstat(val wpath, struct stat *buf) +{ + char *path = utf8_dup_to(c_str(wpath)); + int res = lstat(path, buf); + free(path); + return res; +} +#else +#define do_lstat do_stat +#endif +#endif + #if HAVE_MKDIR || HAVE_WINDOWS_H static val mkdir_nothrow_exists(val path, val mode) { @@ -317,6 +339,14 @@ static val mkdir_nothrow_exists(val path, val mode) ret = num(errno); break; case EEXIST: +#if HAVE_SYS_STAT + { + struct stat st; + int err = do_stat(path, &st); + if (err == 0 && !S_ISDIR(st.st_mode)) + ret = num(EEXIST); + } +#endif break; default: uw_throw(esym, eobj); @@ -797,26 +827,6 @@ static val exit_star_wrap(val status) #endif #if HAVE_SYS_STAT -static int do_stat(val wpath, struct stat *buf) -{ - char *path = utf8_dup_to(c_str(wpath)); - int res = stat(path, buf); - free(path); - return res; -} - -#ifdef S_IFLNK -static int do_lstat(val wpath, struct stat *buf) -{ - char *path = utf8_dup_to(c_str(wpath)); - int res = lstat(path, buf); - free(path); - return res; -} -#else -#define do_lstat do_stat -#endif - static int do_fstat(val stream, struct stat *buf) { val self = lit("fstat"); diff --git a/txr.1 b/txr.1 index 778d9994..ebee463c 100644 --- a/txr.1 +++ b/txr.1 @@ -57497,7 +57497,10 @@ The function is similar to .code mkdir except that it attempts to create all the missing parent directories -as necessary, and does not throw an error if the directory exists. +as necessary, and does not throw an error if +.meta path +refers to an existing object, if that object is a directory or a symbolic +link to a directory. .coNP Function @ chdir .synb -- cgit v1.2.3