diff options
Diffstat (limited to 'src/nvim/os/fs.c')
| -rw-r--r-- | src/nvim/os/fs.c | 74 |
1 files changed, 67 insertions, 7 deletions
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 553dda5e88..e4776999e5 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -279,19 +279,31 @@ bool os_file_is_readonly(const char *name) return access(name, W_OK) != 0; } +/// Check if a file is readable. +/// +/// @return true if `name` is readable, otherwise false. +bool os_file_is_readable(const char *name) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT +{ + uv_fs_t req; + int r = uv_fs_access(&fs_loop, &req, name, R_OK, NULL); + uv_fs_req_cleanup(&req); + return (r == 0); +} + /// Check if a file is writable. /// /// @return `0` if `name` is not writable, /// @return `1` if `name` is writable, /// @return `2` for a directory which we have rights to write into. int os_file_is_writable(const char *name) - FUNC_ATTR_NONNULL_ALL + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { - if (access(name, W_OK) == 0) { - if (os_isdir((char_u *)name)) { - return 2; - } - return 1; + uv_fs_t req; + int r = uv_fs_access(&fs_loop, &req, name, W_OK, NULL); + uv_fs_req_cleanup(&req); + if (r == 0) { + return os_isdir((char_u *)name) ? 2 : 1; } return 0; } @@ -316,7 +328,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 +338,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 |