summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yml2
-rw-r--r--runtime/doc/builtin.txt4
-rw-r--r--runtime/doc/editing.txt9
-rw-r--r--runtime/doc/tags6
-rw-r--r--runtime/doc/various.txt3
-rwxr-xr-xsrc/auto/configure28
-rw-r--r--src/bufwrite.c15
-rw-r--r--src/config.h.in1
-rw-r--r--src/configure.ac12
-rw-r--r--src/errors.h10
-rw-r--r--src/evalfunc.c7
-rw-r--r--src/feature.h10
-rw-r--r--src/os_unix.c95
-rw-r--r--src/proto/os_unix.pro1
-rw-r--r--src/testdir/test_writefile.vim23
-rw-r--r--src/version.c7
16 files changed, 227 insertions, 6 deletions
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 8c2e5396b7..cd1615f9f4 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -110,6 +110,8 @@ jobs:
tcl-dev \
cscope \
libsodium-dev \
+ attr \
+ libattr1-dev
)
fi
sudo apt-get update && sudo apt-get install -y "${PKGS[@]}"
diff --git a/runtime/doc/builtin.txt b/runtime/doc/builtin.txt
index 8a92ff6ecf..b4ea216f31 100644
--- a/runtime/doc/builtin.txt
+++ b/runtime/doc/builtin.txt
@@ -1,4 +1,4 @@
-*builtin.txt* For Vim version 9.0. Last change: 2023 Aug 09
+*builtin.txt* For Vim version 9.0. Last change: 2023 Sep 27
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -11082,6 +11082,8 @@ winaltkeys Compiled with 'winaltkeys' option.
windows Compiled with support for more than one window.
(always true)
writebackup Compiled with 'writebackup' default on.
+xattr Compiled with extended attributes support |xattr|
+ (currently only supported on Linux).
xfontset Compiled with X fontset support |xfontset|.
xim Compiled with X input method support |xim|.
xpm Compiled with pixmap support.
diff --git a/runtime/doc/editing.txt b/runtime/doc/editing.txt
index 46279110a7..a015c8462a 100644
--- a/runtime/doc/editing.txt
+++ b/runtime/doc/editing.txt
@@ -1,4 +1,4 @@
-*editing.txt* For Vim version 9.0. Last change: 2023 Sep 22
+*editing.txt* For Vim version 9.0. Last change: 2023 Sep 27
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -1097,6 +1097,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
diff --git a/runtime/doc/tags b/runtime/doc/tags
index 1df34d3a3d..249800fd29 100644
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -1483,6 +1483,7 @@ $quote eval.txt /*$quote*
+wildmenu various.txt /*+wildmenu*
+windows various.txt /*+windows*
+writebackup various.txt /*+writebackup*
++xattr various.txt /*+xattr*
+xfontset various.txt /*+xfontset*
+xim various.txt /*+xim*
+xpm various.txt /*+xpm*
@@ -4506,6 +4507,10 @@ E1502 builtin.txt /*E1502*
E1503 builtin.txt /*E1503*
E1504 builtin.txt /*E1504*
E1505 builtin.txt /*E1505*
+E1506 editing.txt /*E1506*
+E1507 editing.txt /*E1507*
+E1508 editing.txt /*E1508*
+E1509 editing.txt /*E1509*
E151 helphelp.txt /*E151*
E152 helphelp.txt /*E152*
E153 helphelp.txt /*E153*
@@ -11224,6 +11229,7 @@ x-resources version5.txt /*x-resources*
x11-clientserver remote.txt /*x11-clientserver*
x11-cut-buffer gui_x11.txt /*x11-cut-buffer*
x11-selection gui_x11.txt /*x11-selection*
+xattr editing.txt /*xattr*
xf86conf.vim syntax.txt /*xf86conf.vim*
xfontset mbyte.txt /*xfontset*
xfree-xterm syntax.txt /*xfree-xterm*
diff --git a/runtime/doc/various.txt b/runtime/doc/various.txt
index e478c8266e..b2b7903935 100644
--- a/runtime/doc/various.txt
+++ b/runtime/doc/various.txt
@@ -1,4 +1,4 @@
-*various.txt* For Vim version 9.0. Last change: 2022 Dec 13
+*various.txt* For Vim version 9.0. Last change: 2023 Sep 27
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -503,6 +503,7 @@ T *+windows* more than one window; Always enabled since 8.0.1118.
m *+writebackup* |'writebackup'| is default on
m *+xim* X input method |xim|
*+xfontset* X fontset support |xfontset|
+N *+xattr* compiled with extended attribute support (Linux only)
*+xpm* pixmap support
m *+xpm_w32* Win32 GUI only: pixmap support |w32-xpm-support|
*+xsmp* XSMP (X session management) support
diff --git a/src/auto/configure b/src/auto/configure
index 34e9f449aa..54c1aa8159 100755
--- a/src/auto/configure
+++ b/src/auto/configure
@@ -825,6 +825,7 @@ with_global_runtime
with_modified_by
enable_smack
enable_selinux
+enable_xattr
with_features
with_compiledby
enable_xsmp
@@ -1514,6 +1515,7 @@ Optional Features:
--disable-darwin Disable Darwin (Mac OS X) support.
--disable-smack Do not check for Smack support.
--disable-selinux Do not check for SELinux support.
+ --disable-xattr Do not check for XATTR support.
--disable-xsmp Disable XSMP session management
--disable-xsmp-interact Disable XSMP interaction
--enable-luainterp=OPTS Include Lua interpreter. default=no OPTS=no/yes/dynamic
@@ -5419,6 +5421,32 @@ printf "%s\n" "yes" >&6; }
fi
fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking --enable-xattr argument" >&5
+printf %s "checking --enable-xattr argument... " >&6; }
+# Check whether --enable-xattr was given.
+if test ${enable_xattr+y}
+then :
+ enableval=$enable_xattr;
+else $as_nop
+ enable_xattr="yes"
+fi
+
+if test "$enable_xattr" = "yes"; then
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+printf "%s\n" "yes" >&6; }
+ ac_fn_c_check_header_compile "$LINENO" "attr/xattr.h" "ac_cv_header_attr_xattr_h" "$ac_includes_default"
+if test "x$ac_cv_header_attr_xattr_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_XATTR 1" >>confdefs.h
+
+fi
+
+else
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
+printf "%s\n" "no" >&6; }
+fi
+
+
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking --with-features argument" >&5
printf %s "checking --with-features argument... " >&6; }
diff --git a/src/bufwrite.c b/src/bufwrite.c
index 03a83b569a..bf79ad5bf3 100644
--- a/src/bufwrite.c
+++ b/src/bufwrite.c
@@ -1471,6 +1471,9 @@ buf_write(
# if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
mch_copy_sec(fname, backup);
# endif
+# ifdef FEAT_XATTR
+ mch_copy_xattr(fname, backup);
+# endif
#endif
// copy the file.
@@ -1506,6 +1509,9 @@ buf_write(
#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
mch_copy_sec(fname, backup);
#endif
+#ifdef FEAT_XATTR
+ mch_copy_xattr(fname, backup);
+#endif
#ifdef MSWIN
(void)mch_copy_file_attribute(fname, backup);
#endif
@@ -2196,11 +2202,18 @@ restore_backup:
}
#endif
-#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
+#if defined(HAVE_SELINUX) || defined(HAVE_SMACK) || defined(FEAT_XATTR)
// Probably need to set the security context.
if (!backup_copy)
+ {
+#if defined(HAVE_SELINUX) || defined(HAVE_SMACK)
mch_copy_sec(backup, wfname);
#endif
+#ifdef FEAT_XATTR
+ mch_copy_xattr(backup, wfname);
+#endif
+ }
+#endif
#ifdef UNIX
// When creating a new file, set its owner/group to that of the
diff --git a/src/config.h.in b/src/config.h.in
index 93972ca0cc..8ad9f03136 100644
--- a/src/config.h.in
+++ b/src/config.h.in
@@ -226,6 +226,7 @@
#undef HAVE_MBLEN
#undef HAVE_TIMER_CREATE
#undef HAVE_CLOCK_GETTIME
+#undef HAVE_XATTR
/* Define, if needed, for accessing large files. */
#undef _LARGE_FILES
diff --git a/src/configure.ac b/src/configure.ac
index bfdcfea4d2..e21e23490a 100644
--- a/src/configure.ac
+++ b/src/configure.ac
@@ -513,6 +513,18 @@ if test "x$found_smack" = "x"; then
fi
fi
+dnl enable xattr support
+AC_MSG_CHECKING(--enable-xattr argument)
+AC_ARG_ENABLE(xattr,
+ [ --disable-xattr Do not check for XATTR support.],
+ , enable_xattr="yes")
+if test "$enable_xattr" = "yes"; then
+ AC_MSG_RESULT(yes)
+ AC_CHECK_HEADER([attr/xattr.h], [AC_DEFINE(HAVE_XATTR)])
+else
+ AC_MSG_RESULT(no)
+fi
+
dnl Check user requested features.
AC_MSG_CHECKING(--with-features argument)
diff --git a/src/errors.h b/src/errors.h
index 6b4416963a..16b38cf99a 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -3552,6 +3552,14 @@ EXTERN char e_positional_arg_num_type_inconsistent_str_str[]
INIT(= N_("E1504: Positional argument %d type used inconsistently: %s/%s"));
EXTERN char e_invalid_format_specifier_str[]
INIT(= N_("E1505: Invalid format specifier: %s"));
-// E1506 - E1519 unused
+EXTERN char e_xattr_erange[]
+ INIT(= N_("E1506: Buffer too small to copy xattr value or key"));
+EXTERN char e_xattr_enotsup[]
+ INIT(= N_("E1507: Extended attributes are not supported by the filesystem"));
+EXTERN char e_xattr_e2big[]
+ INIT(= N_("E1508: size of the extended attribute value is larger than the maximum size allowed"));
+EXTERN char e_xattr_other[]
+ INIT(= N_("E1509: error occured when reading or writing extended attribute"));
+// E1509 - E1519 unused
EXTERN char e_aptypes_is_null_nr_str[]
INIT(= "E1520: Internal error: ap_types or ap_types[idx] is NULL: %d: %s");
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 2cd1985a06..501ee03582 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -6464,6 +6464,13 @@ f_has(typval_T *argvars, typval_T *rettv)
0
#endif
},
+ {"xattr",
+#ifdef FEAT_XATTR
+ 1
+#else
+ 0
+#endif
+ },
{"xim",
#ifdef FEAT_XIM
1
diff --git a/src/feature.h b/src/feature.h
index ca180dd1f0..b26dc6ccf1 100644
--- a/src/feature.h
+++ b/src/feature.h
@@ -22,7 +22,7 @@
* - Add a #define below.
* - Add a message in the table above ex_version().
* - Add a string to f_has().
- * - Add a feature to ":help feature-list" in doc/eval.txt.
+ * - Add a feature to ":help feature-list" in doc/builtin.txt.
* - Add feature to ":help +feature-list" in doc/various.txt.
* - Add comment for the documentation of commands that use the feature.
*/
@@ -1175,3 +1175,11 @@
|| defined(FEAT_TERMINAL)
# define USING_LOAD_LIBRARY
#endif
+
+/*
+ * XATTR support
+ */
+
+#if defined(FEAT_NORMAL) && defined(HAVE_XATTR)
+# define FEAT_XATTR
+#endif
diff --git a/src/os_unix.c b/src/os_unix.c
index c5a54e419e..674dd96666 100644
--- a/src/os_unix.c
+++ b/src/os_unix.c
@@ -35,6 +35,11 @@
static int selinux_enabled = -1;
#endif
+#ifdef FEAT_XATTR
+# include <attr/xattr.h>
+# define XATTR_VAL_LEN 1024
+#endif
+
#ifdef HAVE_SMACK
# include <attr/xattr.h>
# include <linux/xattr.h>
@@ -3096,6 +3101,96 @@ mch_copy_sec(char_u *from_file, char_u *to_file)
}
#endif // HAVE_SMACK
+#ifdef FEAT_XATTR
+/*
+ * Copy extended attributes from_file to to_file
+ */
+ void
+mch_copy_xattr(char_u *from_file, char_u *to_file)
+{
+ char *xattr_buf;
+ size_t size;
+ size_t tsize;
+ ssize_t keylen, vallen, max_vallen = 0;
+ char *key;
+ char *val = NULL;
+ char *errmsg = NULL;
+
+ if (from_file == NULL)
+ return;
+
+ // get the length of the extended attributes
+ size = listxattr((char *)from_file, NULL, 0);
+ // not supported or no attributes to copy
+ if (errno == ENOTSUP || size == 0)
+ return;
+ xattr_buf = (char*)alloc(size);
+ if (xattr_buf == NULL)
+ return;
+ size = listxattr((char *)from_file, xattr_buf, size);
+ tsize = size;
+
+ errno = 0;
+
+ for (int round = 0; round < 2; round++)
+ {
+
+ key = xattr_buf;
+ if (round == 1)
+ size = tsize;
+
+ while (size > 0)
+ {
+ vallen = getxattr((char *)from_file, key,
+ val, round ? max_vallen : 0);
+ // only set the attribute in the second round
+ if (vallen >= 0 && round &&
+ setxattr((char *)to_file, key, val, 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
+ keylen = STRLEN(key) + 1;
+ size -= keylen;
+ key += keylen;
+ }
+ if (round)
+ break;
+
+ val = (char*)alloc(max_vallen + 1);
+ if (val == NULL)
+ goto error_exit;
+
+ }
+error_exit:
+ vim_free(xattr_buf);
+ vim_free(val);
+
+ if (errmsg != NULL)
+ emsg((char *)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.
diff --git a/src/proto/os_unix.pro b/src/proto/os_unix.pro
index c3a8483f87..6e13de6caa 100644
--- a/src/proto/os_unix.pro
+++ b/src/proto/os_unix.pro
@@ -37,6 +37,7 @@ long mch_getperm(char_u *name);
int mch_setperm(char_u *name, long perm);
int mch_fsetperm(int fd, long perm);
void mch_copy_sec(char_u *from_file, char_u *to_file);
+void mch_copy_xattr(char_u *from_file, char_u *to_file);
vim_acl_T mch_get_acl(char_u *fname);
void mch_set_acl(char_u *fname, vim_acl_T aclent);
void mch_free_acl(vim_acl_T aclent);
diff --git a/src/testdir/test_writefile.vim b/src/testdir/test_writefile.vim
index 140b2ee037..a54efa7cf9 100644
--- a/src/testdir/test_writefile.vim
+++ b/src/testdir/test_writefile.vim
@@ -977,4 +977,27 @@ func Test_wq_quitpre_autocommand()
call delete('Xsomefile')
endfunc
+func Test_write_with_xattr_support()
+ CheckLinux
+ 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
diff --git a/src/version.c b/src/version.c
index 5404c02b0e..ffa5afcb57 100644
--- a/src/version.c
+++ b/src/version.c
@@ -654,6 +654,11 @@ static char *(features[]) =
"-X11",
# endif
#endif
+# ifdef FEAT_XATTR
+ "+xattr",
+# else
+ "-xattr",
+# endif
#ifdef FEAT_XFONTSET
"+xfontset",
#else
@@ -700,6 +705,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1962,
+/**/
1961,
/**/
1960,