diff options
author | ZyX <kp-pav@yandex.ru> | 2015-07-12 14:09:26 +0300 |
---|---|---|
committer | ZyX <kp-pav@yandex.ru> | 2015-07-26 02:34:32 +0300 |
commit | 1206ac953f0cf2bc29ac3591fe151ca172863b1a (patch) | |
tree | cf9c9f776cb865d87894f49f2eb296f1c7e16ba2 | |
parent | afd3e69e9f5c6a00b6d2402f94b339c289dad7fc (diff) | |
download | rneovim-1206ac953f0cf2bc29ac3591fe151ca172863b1a.tar.gz rneovim-1206ac953f0cf2bc29ac3591fe151ca172863b1a.tar.bz2 rneovim-1206ac953f0cf2bc29ac3591fe151ca172863b1a.zip |
os/fs: Move mkdir_recurse from eval.c to os/fs.c
-rw-r--r-- | src/nvim/eval.c | 42 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 2 | ||||
-rw-r--r-- | src/nvim/globals.h | 1 | ||||
-rw-r--r-- | src/nvim/os/fs.c | 50 | ||||
-rw-r--r-- | test/unit/os/fs_spec.lua | 63 |
5 files changed, 127 insertions, 31 deletions
diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 0e0ccc67de..18188696b9 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -11684,33 +11684,6 @@ static void f_min(typval_T *argvars, typval_T *rettv) max_min(argvars, rettv, FALSE); } - -/* - * Create the directory in which "dir" is located, and higher levels when - * needed. - */ -static int mkdir_recurse(char_u *dir, int prot) -{ - char_u *p; - char_u *updir; - int r = FAIL; - - /* Get end of directory name in "dir". - * We're done when it's "/" or "c:/". */ - p = path_tail_with_sep(dir); - if (p <= get_past_head(dir)) - return OK; - - /* If the directory exists we're done. Otherwise: create it.*/ - updir = vim_strnsave(dir, (int)(p - dir)); - if (os_isdir(updir)) - r = OK; - else if (mkdir_recurse(updir, prot) == OK) - r = vim_mkdir_emsg(updir, prot); - xfree(updir); - return r; -} - /* * "mkdir()" function */ @@ -11735,8 +11708,19 @@ static void f_mkdir(typval_T *argvars, typval_T *rettv) if (argvars[1].v_type != VAR_UNKNOWN) { if (argvars[2].v_type != VAR_UNKNOWN) prot = get_tv_number_chk(&argvars[2], NULL); - if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0) - mkdir_recurse(dir, prot); + if (prot != -1 && STRCMP(get_tv_string(&argvars[1]), "p") == 0) { + char *failed_dir; + int ret = os_mkdir_recurse((char *) dir, prot, &failed_dir); + if (ret != 0) { + EMSG3(_(e_mkdir), failed_dir, os_strerror(ret)); + xfree(failed_dir); + rettv->vval.v_number = FAIL; + return; + } else { + rettv->vval.v_number = OK; + return; + } + } } rettv->vval.v_number = prot == -1 ? FAIL : vim_mkdir_emsg(dir, prot); } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 4182822dfa..3c57537397 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -7549,7 +7549,7 @@ int vim_mkdir_emsg(char_u *name, int prot) { int ret; if ((ret = os_mkdir((char *)name, prot)) != 0) { - EMSG3(_("E739: Cannot create directory %s: %s"), name, os_strerror(ret)); + EMSG3(_(e_mkdir), name, os_strerror(ret)); return FAIL; } return OK; diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 9c4f9e3642..e4dcad9afb 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -1117,6 +1117,7 @@ EXTERN char_u e_jobtblfull[] INIT(= N_("E901: Job table is full")); EXTERN char_u e_jobexe[] INIT(= N_("E902: \"%s\" is not an executable")); EXTERN char_u e_jobnotpty[] INIT(= N_("E904: Job is not connected to a pty")); EXTERN char_u e_libcall[] INIT(= N_("E364: Library call failed for \"%s()\"")); +EXTERN char_u e_mkdir[] INIT(= N_("E739: Cannot create directory %s: %s")); EXTERN char_u e_markinval[] INIT(= N_("E19: Mark has invalid line number")); EXTERN char_u e_marknotset[] INIT(= N_("E20: Mark not set")); EXTERN char_u e_modifiable[] INIT(= N_( diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 553dda5e88..5eeb275701 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -316,7 +316,7 @@ int os_rename(const char_u *path, const char_u *new_path) /// Make a directory. /// -/// @return `0` for success, non-zero for failure. +/// @return `0` for success, -errno for failure. int os_mkdir(const char *path, int32_t mode) FUNC_ATTR_NONNULL_ALL { @@ -326,6 +326,54 @@ int os_mkdir(const char *path, int32_t mode) return result; } +/// Make a directory, with higher levels when needed +/// +/// @param[in] dir Directory to create. +/// @param[in] mode Permissions for the newly-created directory. +/// @param[out] failed_dir If it failed to create directory, then this +/// argument is set to an allocated string containing +/// the name of the directory which os_mkdir_recurse +/// failed to create. I.e. it will contain dir or any +/// of the higher level directories. +/// +/// @return `0` for success, -errno for failure. +int os_mkdir_recurse(const char *const dir, int32_t mode, + char **const failed_dir) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +{ + // Get end of directory name in "dir". + // We're done when it's "/" or "c:/". + const size_t dirlen = strlen(dir); + char *const curdir = xmemdupz(dir, dirlen); + char *const past_head = (char *) get_past_head((char_u *) curdir); + char *e = curdir + dirlen; + const char *const real_end = e; + const char past_head_save = *past_head; + while (!os_isdir((char_u *) curdir)) { + e = (char *) path_tail_with_sep((char_u *) curdir); + if (e <= past_head) { + *past_head = NUL; + break; + } + *e = NUL; + } + while (e != real_end) { + if (e > past_head) { + *e = '/'; + } else { + *past_head = past_head_save; + } + e += strlen(e); + int ret; + if ((ret = os_mkdir(curdir, mode)) != 0) { + *failed_dir = curdir; + return ret; + } + } + xfree(curdir); + return 0; +} + /// Create a unique temporary directory. /// /// @param[in] template Template of the path to the directory with XXXXXX diff --git a/test/unit/os/fs_spec.lua b/test/unit/os/fs_spec.lua index 2ffffb907f..20aca9109e 100644 --- a/test/unit/os/fs_spec.lua +++ b/test/unit/os/fs_spec.lua @@ -486,6 +486,16 @@ describe('fs function', function() return fs.os_rmdir(to_cstr(path)) end + local function os_mkdir_recurse(path, mode) + local failed_str = ffi.new('char *[1]', {nil}) + local ret = fs.os_mkdir_recurse(path, mode, failed_str) + local str = failed_str[0] + if str ~= nil then + str = ffi.string(str) + end + return ret, str + end + describe('os_mkdir', function() it('returns non-zero when given an already existing directory', function() local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR @@ -501,6 +511,59 @@ describe('fs function', function() end) end) + describe('os_mkdir_recurse', function() + it('returns zero when given an already existing directory', function() + local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR + local ret, failed_str = os_mkdir_recurse('unit-test-directory', mode) + eq(0, ret) + eq(nil, failed_str) + end) + + it('fails to create a directory where there is a file', function() + local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR + local ret, failed_str = os_mkdir_recurse( + 'unit-test-directory/test.file', mode) + neq(0, ret) + eq('unit-test-directory/test.file', failed_str) + end) + + it('fails to create a directory where there is a file in path', function() + local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR + local ret, failed_str = os_mkdir_recurse( + 'unit-test-directory/test.file/test', mode) + neq(0, ret) + eq('unit-test-directory/test.file', failed_str) + end) + + it('succeeds to create a directory', function() + local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR + local ret, failed_str = os_mkdir_recurse( + 'unit-test-directory/new-dir-recurse', mode) + eq(0, ret) + eq(nil, failed_str) + eq(true, os_isdir('unit-test-directory/new-dir-recurse')) + lfs.rmdir('unit-test-directory/new-dir-recurse') + eq(false, os_isdir('unit-test-directory/new-dir-recurse')) + end) + + it('succeeds to create a directory tree', function() + local mode = ffi.C.kS_IRUSR + ffi.C.kS_IWUSR + ffi.C.kS_IXUSR + local ret, failed_str = os_mkdir_recurse( + 'unit-test-directory/new-dir-recurse/1/2/3', mode) + eq(0, ret) + eq(nil, failed_str) + eq(true, os_isdir('unit-test-directory/new-dir-recurse')) + eq(true, os_isdir('unit-test-directory/new-dir-recurse/1')) + eq(true, os_isdir('unit-test-directory/new-dir-recurse/1/2')) + eq(true, os_isdir('unit-test-directory/new-dir-recurse/1/2/3')) + lfs.rmdir('unit-test-directory/new-dir-recurse/1/2/3') + lfs.rmdir('unit-test-directory/new-dir-recurse/1/2') + lfs.rmdir('unit-test-directory/new-dir-recurse/1') + lfs.rmdir('unit-test-directory/new-dir-recurse') + eq(false, os_isdir('unit-test-directory/new-dir-recurse')) + end) + end) + describe('os_rmdir', function() it('returns non_zero when given a non-existing directory', function() neq(0, (os_rmdir('non-existing-directory'))) |