mirror of
https://github.com/neovim/neovim.git
synced 2025-02-25 18:55:25 -06:00
Merge pull request #25442 from zeertzjq/vim-9.0.1962
vim-patch:9.0.{1962,1963}: extended attributes
This commit is contained in:
commit
386bc23e43
2
.github/scripts/install_deps.sh
vendored
2
.github/scripts/install_deps.sh
vendored
@ -12,7 +12,7 @@ done
|
||||
os=$(uname -s)
|
||||
if [[ $os == Linux ]]; then
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential cmake curl gettext ninja-build unzip
|
||||
sudo apt-get install -y attr build-essential cmake curl gettext libattr1-dev ninja-build unzip
|
||||
if [[ -n $TEST ]]; then
|
||||
sudo apt-get install -y locales-all cpanminus
|
||||
fi
|
||||
|
@ -40,6 +40,9 @@ check_include_files(sys/utsname.h HAVE_SYS_UTSNAME_H)
|
||||
check_include_files(termios.h HAVE_TERMIOS_H)
|
||||
check_include_files(sys/uio.h HAVE_SYS_UIO_H)
|
||||
check_include_files(sys/sdt.h HAVE_SYS_SDT_H)
|
||||
if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
|
||||
check_include_files(sys/xattr.h HAVE_XATTR)
|
||||
endif()
|
||||
|
||||
# Functions
|
||||
check_function_exists(fseeko HAVE_FSEEKO)
|
||||
|
@ -27,6 +27,7 @@
|
||||
#cmakedefine HAVE_STRINGS_H
|
||||
#cmakedefine HAVE_STRNCASECMP
|
||||
#cmakedefine HAVE_STRPTIME
|
||||
#cmakedefine HAVE_XATTR
|
||||
#cmakedefine HAVE_SYS_SDT_H
|
||||
#cmakedefine HAVE_SYS_UTSNAME_H
|
||||
#cmakedefine HAVE_SYS_WAIT_H
|
||||
|
@ -1078,6 +1078,13 @@ will get the ACL info of the original file.
|
||||
The ACL info is also used to check if a file is read-only (when opening the
|
||||
file).
|
||||
|
||||
*xattr* *E1506* *E1507* *E1508* *E1509*
|
||||
xattr stands for Extended Attributes It is an advanced way to save metadata
|
||||
alongside the file in the filesystem. It depends on the actual filesystem
|
||||
being used and Vim supports it only on a Linux system.
|
||||
Vim attempts to preserve the extended attribute info when writing a file.
|
||||
The backup file will get the extended attribute of the original file.
|
||||
|
||||
*read-only-share*
|
||||
When MS-Windows shares a drive on the network it can be marked as read-only.
|
||||
This means that even if the file read-only attribute is absent, and the ACL
|
||||
|
@ -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.
|
||||
|
@ -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",
|
||||
};
|
||||
|
||||
|
@ -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 <sys/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)
|
||||
|
@ -990,4 +990,28 @@ func Test_wq_quitpre_autocommand()
|
||||
call delete('Xsomefile')
|
||||
endfunc
|
||||
|
||||
func Test_write_with_xattr_support()
|
||||
CheckLinux
|
||||
CheckFeature xattr
|
||||
CheckExecutable setfattr
|
||||
|
||||
let contents = ["file with xattrs", "line two"]
|
||||
call writefile(contents, 'Xwattr.txt', 'D')
|
||||
" write a couple of xattr
|
||||
call system('setfattr -n user.cookie -v chocolate Xwattr.txt')
|
||||
call system('setfattr -n user.frieda -v bar Xwattr.txt')
|
||||
call system('setfattr -n user.empty Xwattr.txt')
|
||||
|
||||
set backupcopy=no writebackup& backup&
|
||||
sp Xwattr.txt
|
||||
w
|
||||
$r! getfattr -d %
|
||||
let expected = ['file with xattrs', 'line two', '# file: Xwattr.txt', 'user.cookie="chocolate"', 'user.empty=""', 'user.frieda="bar"', '']
|
||||
call assert_equal(expected, getline(1,'$'))
|
||||
|
||||
set backupcopy&
|
||||
bw!
|
||||
|
||||
endfunc
|
||||
|
||||
" vim: shiftwidth=2 sts=2 expandtab
|
||||
|
Loading…
Reference in New Issue
Block a user