diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/nvim/bufwrite.c | 12 | ||||
-rw-r--r-- | src/nvim/eval/funcs.c | 3 | ||||
-rw-r--r-- | src/nvim/os/fs.c | 97 |
3 files changed, 111 insertions, 1 deletions
diff --git a/src/nvim/bufwrite.c b/src/nvim/bufwrite.c index 40b95e5790..db813a3ae1 100644 --- a/src/nvim/bufwrite.c +++ b/src/nvim/bufwrite.c @@ -913,6 +913,9 @@ static int buf_write_make_backup(char *fname, bool append, FileInfo *file_info_o && os_chown(*backupp, (uv_uid_t)-1, (uv_gid_t)file_info_old->stat.st_gid) != 0) { os_setperm(*backupp, ((int)perm & 0707) | (((int)perm & 07) << 3)); } +# ifdef HAVE_XATTR + os_copy_xattr(fname, *backupp); +# endif #endif // copy the file @@ -929,6 +932,9 @@ static int buf_write_make_backup(char *fname, bool append, FileInfo *file_info_o (double)file_info_old->stat.st_mtim.tv_sec); #endif os_set_acl(*backupp, acl); +#ifdef HAVE_XATTR + os_copy_xattr(fname, *backupp); +#endif *err = set_err(NULL); break; } @@ -1634,6 +1640,12 @@ restore_backup: end = 0; } + if (!backup_copy) { +#ifdef HAVE_XATTR + os_copy_xattr(backup, wfname); +#endif + } + #ifdef UNIX // When creating a new file, set its owner/group to that of the original // file. Get the new device and inode number. diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 710d9c73a5..5bfce7c272 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -3171,6 +3171,9 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) "windows", "winaltkeys", "writebackup", +#ifdef HAVE_XATTR + "xattr", +#endif "nvim", }; diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index 77c4766419..3efb575039 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -18,6 +18,8 @@ # include <shlobj.h> #endif +#include "auto/config.h" + #if defined(HAVE_ACL) # ifdef HAVE_SYS_ACL_H # include <sys/acl.h> @@ -27,7 +29,11 @@ # endif #endif -#include "auto/config.h" +#ifdef HAVE_XATTR +# include <attr/xattr.h> +# define XATTR_VAL_LEN 1024 +#endif + #include "nvim/ascii.h" #include "nvim/gettext.h" #include "nvim/globals.h" @@ -55,6 +61,17 @@ # 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_enotsup[] + = N_("E1507: Extended attributes are not supported by the filesystem"); +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 occured when reading or writing extended attribute"); +#endif + struct iovec; #define RUN_UV_FS_FUNC(ret, func, ...) \ @@ -743,6 +760,84 @@ int os_setperm(const char *const name, int perm) return (r == kLibuvSuccess ? OK : FAIL); } +#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: + errmsg = e_xattr_enotsup; + goto error_exit; + 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. vim_acl_T os_get_acl(const char *fname) |