fs: split mkdir's recursive functionality into "mkpath"

This commit is contained in:
Jeremy Baxter 2024-03-24 14:05:24 +13:00
parent 78b55f2205
commit dac9418d8e

52
lfs.c
View file

@ -365,21 +365,32 @@ fs_isfile(lua_State *L)
return ismode(L, S_IFREG); return ismode(L, S_IFREG);
} }
/* /***
* Taken from OpenBSD mkdir(1) * Creates a new directory, creating intermediate directories as required.
* mkpath -- create directories. *
* path - path * On success, returns true. Otherwise returns nil, an error
* mode - file mode of terminal directory * message and a platform-dependent error code.
* dir_mode - file mode of intermediate directories *
* @function mkpath
* @usage fs.mkpath("/usr/local/bin")
* @tparam string path The path to create.
*/ */
static int static int
mkpath(char *path, mode_t mode, mode_t dir_mode) fs_mkpath(lua_State *L)
{ {
/*
* Code derived from OpenBSD mkdir(1)
*/
struct stat sb; struct stat sb;
const char *path; /* path to make */
char *slash; char *slash;
mode_t mode; /* file mode of terminal directory */
mode_t dir_mode; /* file mode of intermediate directories */
int done; int done;
slash = path; path = luaL_checkstring(L, 1);
mode = dir_mode = 0777;
slash = (char *)path;
for (;;) { for (;;) {
slash += strspn(slash, "/"); slash += strspn(slash, "/");
@ -390,19 +401,19 @@ mkpath(char *path, mode_t mode, mode_t dir_mode)
if (mkdir(path, done ? mode : dir_mode) == 0) { if (mkdir(path, done ? mode : dir_mode) == 0) {
if (mode > 0777 && chmod(path, mode) == -1) if (mode > 0777 && chmod(path, mode) == -1)
return -1; return lfail(L);
} else { } else {
int mkdir_errno = errno; int mkdir_errno = errno;
if (stat(path, &sb) == -1) { if (stat(path, &sb) == -1) {
/* Not there; use mkdir()s errno */ /* Not there; use mkdir()s errno */
errno = mkdir_errno; errno = mkdir_errno;
return -1; return lfail(L);
} }
if (!S_ISDIR(sb.st_mode)) { if (!S_ISDIR(sb.st_mode)) {
/* Is there, but isn't a directory */ /* Is there, but isn't a directory */
errno = ENOTDIR; errno = ENOTDIR;
return -1; return lfail(L);
} }
} }
@ -412,15 +423,15 @@ mkpath(char *path, mode_t mode, mode_t dir_mode)
*slash = '/'; *slash = '/';
} }
return 0; lua_pushboolean(L, 1);
return 1;
} }
/*** /***
* Creates a new directory. * Creates a new directory.
* *
* If *recursive* is true, creates intermediate directories * If you need to create multiple directories at once (similar to
* (parent directories) as required; behaves as POSIX * the behaviour of `mkdir -p`), use *fs.mkpath* instead.
* `mkdir -p` would.
* *
* On success, returns true. Otherwise returns nil, an error * On success, returns true. Otherwise returns nil, an error
* message and a platform-dependent error code. * message and a platform-dependent error code.
@ -428,24 +439,14 @@ mkpath(char *path, mode_t mode, mode_t dir_mode)
* @function mkdir * @function mkdir
* @usage fs.mkdir("/usr/local/bin") * @usage fs.mkdir("/usr/local/bin")
* @tparam string dir The path of the directory to create. * @tparam string dir The path of the directory to create.
* @tparam[opt] boolean recursive Whether to create intermediate directories.
*/ */
static int static int
fs_mkdir(lua_State *L) fs_mkdir(lua_State *L)
{ {
char *dir; /* parameter 1 (string) */ char *dir; /* parameter 1 (string) */
int recursive; /* parameter 2 (boolean) */
int ret; int ret;
dir = strdup(luaL_checkstring(L, 1)); dir = strdup(luaL_checkstring(L, 1));
if (!lua_isboolean(L, 2) && !lua_isnoneornil(L, 2))
luaL_typeerror(L, 2, "boolean");
recursive = lua_toboolean(L, 2);
if (recursive)
ret = mkpath(dir, 0777, 0777);
else
ret = mkdir(dir, 0777); ret = mkdir(dir, 0777);
free(dir); free(dir);
@ -694,6 +695,7 @@ static const luaL_Reg fslib[] = {
{"isdirectory", fs_isdirectory}, {"isdirectory", fs_isdirectory},
{"isfile", fs_isfile}, {"isfile", fs_isfile},
{"mkdir", fs_mkdir}, {"mkdir", fs_mkdir},
{"mkpath", fs_mkpath},
{"move", fs_move}, {"move", fs_move},
{"remove", fs_remove}, {"remove", fs_remove},
{"rmdir", fs_rmdir}, {"rmdir", fs_rmdir},