diff options
author | Josh Rahm <joshuarahm@gmail.com> | 2023-11-30 20:35:25 +0000 |
---|---|---|
committer | Josh Rahm <joshuarahm@gmail.com> | 2023-11-30 20:35:25 +0000 |
commit | 1b7b916b7631ddf73c38e3a0070d64e4636cb2f3 (patch) | |
tree | cd08258054db80bb9a11b1061bb091c70b76926a /src/nvim/os/fs.c | |
parent | eaa89c11d0f8aefbb512de769c6c82f61a8baca3 (diff) | |
parent | 4a8bf24ac690004aedf5540fa440e788459e5e34 (diff) | |
download | rneovim-aucmd_textputpost.tar.gz rneovim-aucmd_textputpost.tar.bz2 rneovim-aucmd_textputpost.zip |
Merge remote-tracking branch 'upstream/master' into aucmd_textputpostaucmd_textputpost
Diffstat (limited to 'src/nvim/os/fs.c')
-rw-r--r-- | src/nvim/os/fs.c | 239 |
1 files changed, 140 insertions, 99 deletions
diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 6157341ec9..8f939c3b40 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - // fs.c -- filesystem access #include <assert.h> #include <errno.h> @@ -12,79 +9,75 @@ #include <stdlib.h> #include <string.h> #include <sys/stat.h> +#include <sys/types.h> +#include <uv.h> + +#ifdef MSWIN +# include <shlobj.h> +#endif #include "auto/config.h" -#include "nvim/gettext.h" -#include "nvim/globals.h" -#include "nvim/log.h" -#include "nvim/macros.h" -#include "nvim/option_defs.h" -#include "nvim/os/fs_defs.h" -#include "nvim/types.h" -#include "nvim/vim.h" +#include "nvim/func_attr.h" +#include "nvim/os/fs.h" -#ifdef HAVE_SYS_UIO_H -# include <sys/uio.h> +#if defined(HAVE_ACL) +# ifdef HAVE_SYS_ACL_H +# include <sys/acl.h> +# endif +# ifdef HAVE_SYS_ACCESS_H +# include <sys/access.h> +# endif #endif -#include <uv.h> +#ifdef HAVE_XATTR +# include <sys/xattr.h> +#endif -#include "nvim/ascii.h" +#include "nvim/ascii_defs.h" +#include "nvim/gettext.h" +#include "nvim/globals.h" +#include "nvim/log.h" +#include "nvim/macros_defs.h" #include "nvim/memory.h" #include "nvim/message.h" +#include "nvim/option_vars.h" #include "nvim/os/os.h" #include "nvim/path.h" +#include "nvim/types_defs.h" +#include "nvim/vim_defs.h" -struct iovec; +#ifdef HAVE_SYS_UIO_H +# include <sys/uio.h> +#endif #ifdef MSWIN -# include "nvim/mbyte.h" // for utf8_to_utf16, utf16_to_utf8 +# include "nvim/mbyte.h" +# include "nvim/option.h" +# include "nvim/strings.h" #endif #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/fs.c.generated.h" #endif +#ifdef HAVE_XATTR +static const char e_xattr_erange[] + = N_("E1506: Buffer too small to copy xattr value or key"); +static const char e_xattr_e2big[] + = N_("E1508: Size of the extended attribute value is larger than the maximum size allowed"); +static const char e_xattr_other[] + = N_("E1509: Error occurred when reading or writing extended attribute"); +#endif + #define RUN_UV_FS_FUNC(ret, func, ...) \ do { \ - bool did_try_to_free = false; \ -uv_call_start: {} \ uv_fs_t req; \ - fs_loop_lock(); \ - ret = func(&fs_loop, &req, __VA_ARGS__); \ + ret = func(NULL, &req, __VA_ARGS__); \ uv_fs_req_cleanup(&req); \ - fs_loop_unlock(); \ - if (ret == UV_ENOMEM && !did_try_to_free) { \ - try_to_free_memory(); \ - did_try_to_free = true; \ - goto uv_call_start; \ - } \ } while (0) // Many fs functions from libuv return that value on success. static const int kLibuvSuccess = 0; -static uv_loop_t fs_loop; -static uv_mutex_t fs_loop_mutex; - -// Initialize the fs module -void fs_init(void) -{ - uv_loop_init(&fs_loop); - uv_mutex_init_recursive(&fs_loop_mutex); -} - -/// TODO(bfredl): some of these operations should -/// be possible to do the private libuv loop of the -/// thread, instead of contending the global fs loop -void fs_loop_lock(void) -{ - uv_mutex_lock(&fs_loop_mutex); -} - -void fs_loop_unlock(void) -{ - uv_mutex_unlock(&fs_loop_mutex); -} /// Changes the current directory to `path`. /// @@ -94,7 +87,7 @@ int os_chdir(const char *path) { if (p_verbose >= 5) { verbose_enter(); - smsg("chdir(%s)", path); + smsg(0, "chdir(%s)", path); verbose_leave(); } return uv_chdir(path); @@ -123,12 +116,9 @@ bool os_isrealdir(const char *name) FUNC_ATTR_NONNULL_ALL { uv_fs_t request; - fs_loop_lock(); - if (uv_fs_lstat(&fs_loop, &request, name, NULL) != kLibuvSuccess) { - fs_loop_unlock(); + if (uv_fs_lstat(NULL, &request, name, NULL) != kLibuvSuccess) { return false; } - fs_loop_unlock(); if (S_ISLNK(request.statbuf.st_mode)) { return false; } @@ -373,7 +363,7 @@ static bool is_executable_in_path(const char *name, char **abspath) // is an executable file. char *p = path; bool rv = false; - for (;;) { + while (true) { char *e = xstrchrnul(p, ENV_SEPCHAR); // Combine the $PATH segment with `name`. @@ -567,7 +557,6 @@ ptrdiff_t os_read(const int fd, bool *const ret_eof, char *const ret_buf, const return 0; } size_t read_bytes = 0; - bool did_try_to_free = false; while (read_bytes != size) { assert(size >= read_bytes); const ptrdiff_t cur_read_bytes = read(fd, ret_buf + read_bytes, @@ -582,10 +571,6 @@ ptrdiff_t os_read(const int fd, bool *const ret_eof, char *const ret_buf, const break; } else if (error == UV_EINTR || error == UV_EAGAIN) { continue; - } else if (error == UV_ENOMEM && !did_try_to_free) { - try_to_free_memory(); - did_try_to_free = true; - continue; } else { return (ptrdiff_t)error; } @@ -619,7 +604,6 @@ ptrdiff_t os_readv(const int fd, bool *const ret_eof, struct iovec *iov, size_t { *ret_eof = false; size_t read_bytes = 0; - bool did_try_to_free = false; size_t toread = 0; for (size_t i = 0; i < iov_size; i++) { // Overflow, trying to read too much data @@ -651,10 +635,6 @@ ptrdiff_t os_readv(const int fd, bool *const ret_eof, struct iovec *iov, size_t break; } else if (error == UV_EINTR || error == UV_EAGAIN) { continue; - } else if (error == UV_ENOMEM && !did_try_to_free) { - try_to_free_memory(); - did_try_to_free = true; - continue; } else { return (ptrdiff_t)error; } @@ -743,9 +723,7 @@ static int os_stat(const char *name, uv_stat_t *statbuf) return UV_EINVAL; } uv_fs_t request; - fs_loop_lock(); - int result = uv_fs_stat(&fs_loop, &request, name, NULL); - fs_loop_unlock(); + int result = uv_fs_stat(NULL, &request, name, NULL); if (result == kLibuvSuccess) { *statbuf = request.statbuf; } @@ -777,13 +755,84 @@ int os_setperm(const char *const name, int perm) return (r == kLibuvSuccess ? OK : FAIL); } -#if defined(HAVE_ACL) -# ifdef HAVE_SYS_ACL_H -# include <sys/acl.h> -# endif -# ifdef HAVE_SYS_ACCESS_H -# include <sys/access.h> -# endif +#ifdef HAVE_XATTR +/// Copy extended attributes from_file to to_file +void os_copy_xattr(const char *from_file, const char *to_file) +{ + if (from_file == NULL) { + return; + } + + // get the length of the extended attributes + ssize_t size = listxattr((char *)from_file, NULL, 0); + // not supported or no attributes to copy + if (errno == ENOTSUP || size <= 0) { + return; + } + char *xattr_buf = xmalloc((size_t)size); + size = listxattr(from_file, xattr_buf, (size_t)size); + ssize_t tsize = size; + + errno = 0; + + ssize_t max_vallen = 0; + char *val = NULL; + const char *errmsg = NULL; + + for (int round = 0; round < 2; round++) { + char *key = xattr_buf; + if (round == 1) { + size = tsize; + } + + while (size > 0) { + ssize_t vallen = getxattr(from_file, key, val, round ? (size_t)max_vallen : 0); + // only set the attribute in the second round + if (vallen >= 0 && round + && setxattr(to_file, key, val, (size_t)vallen, 0) == 0) { + // + } else if (errno) { + switch (errno) { + case E2BIG: + errmsg = e_xattr_e2big; + goto error_exit; + case ENOTSUP: + case EACCES: + case EPERM: + break; + case ERANGE: + errmsg = e_xattr_erange; + goto error_exit; + default: + errmsg = e_xattr_other; + goto error_exit; + } + } + + if (round == 0 && vallen > max_vallen) { + max_vallen = vallen; + } + + // add one for terminating null + ssize_t keylen = (ssize_t)strlen(key) + 1; + size -= keylen; + key += keylen; + } + if (round) { + break; + } + + val = xmalloc((size_t)max_vallen + 1); + } +error_exit: + xfree(xattr_buf); + xfree(val); + + if (errmsg != NULL) { + emsg(_(errmsg)); + } +} +#endif // Return a pointer to the ACL of file "fname" in allocated memory. // Return NULL if the ACL is not available for whatever reason. @@ -807,7 +856,6 @@ void os_free_acl(vim_acl_T aclent) return; } } -#endif #ifdef UNIX /// Checks if the current user owns a file. @@ -938,10 +986,13 @@ int os_mkdir(const char *path, int32_t mode) /// 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. +/// @param[out] created Set to the full name of the first created directory. +/// It will be NULL until that happens. /// /// @return `0` for success, libuv error code 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 +int os_mkdir_recurse(const char *const dir, int32_t mode, char **const failed_dir, + char **const created) + FUNC_ATTR_NONNULL_ARG(1, 3) FUNC_ATTR_WARN_UNUSED_RESULT { // Get end of directory name in "dir". // We're done when it's "/" or "c:/". @@ -976,6 +1027,8 @@ int os_mkdir_recurse(const char *const dir, int32_t mode, char **const failed_di if ((ret = os_mkdir(curdir, mode)) != 0) { *failed_dir = curdir; return ret; + } else if (created != NULL && *created == NULL) { + *created = FullName_save(curdir, false); } } xfree(curdir); @@ -1003,7 +1056,7 @@ int os_file_mkdir(char *fname, int32_t mode) *tail = NUL; int r; char *failed_dir; - if (((r = os_mkdir_recurse(fname, mode, &failed_dir)) < 0)) { + if (((r = os_mkdir_recurse(fname, mode, &failed_dir, NULL)) < 0)) { semsg(_(e_mkdir), failed_dir, os_strerror(r)); xfree(failed_dir); } @@ -1015,18 +1068,16 @@ int os_file_mkdir(char *fname, int32_t mode) /// Create a unique temporary directory. /// -/// @param[in] template Template of the path to the directory with XXXXXX -/// which would be replaced by random chars. +/// @param[in] templ Template of the path to the directory with XXXXXX +/// which would be replaced by random chars. /// @param[out] path Path to created directory for success, undefined for /// failure. /// @return `0` for success, non-zero for failure. -int os_mkdtemp(const char *template, char *path) +int os_mkdtemp(const char *templ, char *path) FUNC_ATTR_NONNULL_ALL { uv_fs_t request; - fs_loop_lock(); - int result = uv_fs_mkdtemp(&fs_loop, &request, template, NULL); - fs_loop_unlock(); + int result = uv_fs_mkdtemp(NULL, &request, templ, NULL); if (result == kLibuvSuccess) { xstrlcpy(path, request.path, TEMP_FILE_PATH_MAXLEN); } @@ -1053,9 +1104,7 @@ int os_rmdir(const char *path) bool os_scandir(Directory *dir, const char *path) FUNC_ATTR_NONNULL_ALL { - fs_loop_lock(); - int r = uv_fs_scandir(&fs_loop, &dir->request, path, 0, NULL); - fs_loop_unlock(); + int r = uv_fs_scandir(NULL, &dir->request, path, 0, NULL); if (r < 0) { os_closedir(dir); } @@ -1116,9 +1165,7 @@ bool os_fileinfo_link(const char *path, FileInfo *file_info) return false; } uv_fs_t request; - fs_loop_lock(); - bool ok = uv_fs_lstat(&fs_loop, &request, path, NULL) == kLibuvSuccess; - fs_loop_unlock(); + bool ok = uv_fs_lstat(NULL, &request, path, NULL) == kLibuvSuccess; if (ok) { file_info->stat = request.statbuf; } @@ -1136,8 +1183,7 @@ bool os_fileinfo_fd(int file_descriptor, FileInfo *file_info) { uv_fs_t request; CLEAR_POINTER(file_info); - fs_loop_lock(); - bool ok = uv_fs_fstat(&fs_loop, + bool ok = uv_fs_fstat(NULL, &request, file_descriptor, NULL) == kLibuvSuccess; @@ -1145,7 +1191,6 @@ bool os_fileinfo_fd(int file_descriptor, FileInfo *file_info) file_info->stat = request.statbuf; } uv_fs_req_cleanup(&request); - fs_loop_unlock(); return ok; } @@ -1262,8 +1307,7 @@ char *os_realpath(const char *name, char *buf) FUNC_ATTR_NONNULL_ARG(1) { uv_fs_t request; - fs_loop_lock(); - int result = uv_fs_realpath(&fs_loop, &request, name, NULL); + int result = uv_fs_realpath(NULL, &request, name, NULL); if (result == kLibuvSuccess) { if (buf == NULL) { buf = xmallocz(MAXPATHL); @@ -1271,13 +1315,10 @@ char *os_realpath(const char *name, char *buf) xstrlcpy(buf, request.ptr, MAXPATHL + 1); } uv_fs_req_cleanup(&request); - fs_loop_unlock(); return result == kLibuvSuccess ? buf : NULL; } #ifdef MSWIN -# include <shlobj.h> - /// When "fname" is the name of a shortcut (*.lnk) resolve the file it points /// to and return that name in allocated memory. /// Otherwise NULL is returned. |