mirror of
https://git.savannah.gnu.org/git/coreutils.git
synced 2025-09-10 07:59:52 +02:00
cp/mv: add xattr support
This patch was originally written by Andreas Grünbacher, nowadays available at http://www.suse.de/~agruen/coreutils/5.91/coreutils-xattr.diff * bootstrap.conf: Add gnulib module verror. * po/POTFILES.in: Add lib/verror.c. * m4/xattr.m4: Check for libattr availability, new configure option --disable-xattr. * m4/prereq.m4: Require gl_FUNC_XATTR. * src/Makefile.am: Link cp, mv and ginstall with libattr. * src/copy.h: Add preserve_xattr and require_preserve_xattr to cp_options. * src/copy.c (copy_attr_error): New function to handle errors during xattr copying. (copy_attr_quote): New function to quote file name in error messages printed by libattr. (copy_attr_free): Empty function requested by libattr to free quoted string. (copy_attr_by_fd): New fd-oriented function to copy xattr. (copy_attr_by_name): New name-oriented function to copy xattr. (copy_reg, copy_internal): Call copy_extended_attributes function. * src/cp.c (usage): Mention new --preserve=xattr option. (decode_preserve_arg): Handle new --preserve=xattr option. * src/mv.c: Always attempt to preserve xattr. * src/install.c: Never attempt to preserve xattr. * tests/misc/xattr: New test for xattr support in cp, mv and install. * tests/Makefile.am: Add the new test to list. * doc/coreutils.texi: Mention xattr support, new --preserve=xattr option. * NEWS: Mention the change.
This commit is contained in:
committed by
Jim Meyering
parent
1bdf77ad52
commit
0889381cbf
6
NEWS
6
NEWS
@@ -4,6 +4,12 @@ GNU coreutils NEWS -*- outline -*-
|
||||
|
||||
** New features
|
||||
|
||||
Add extended attribute support available on certain filesystems like ext2
|
||||
and XFS.
|
||||
cp: Tries to copy xattrs when --preserve=xattr specified
|
||||
mv: Always tries to copy xattrs
|
||||
install: Never copies xattrs
|
||||
|
||||
cp and mv accept a new option, --no-clobber (-n): silently refrain
|
||||
from overwriting any existing destination file
|
||||
|
||||
|
||||
@@ -102,7 +102,7 @@ gnulib_modules="
|
||||
userspec utimecmp utimens
|
||||
vasprintf-posix
|
||||
vc-list-files
|
||||
verify version-etc-fsf
|
||||
verify version-etc-fsf verror
|
||||
warnings
|
||||
wcwidth winsz-ioctl winsz-termios write-any-file
|
||||
xalloc
|
||||
|
||||
@@ -7365,7 +7365,7 @@ symbolic links in the destination are always followed if possible.
|
||||
@itemx @w{@kbd{--preserve}[=@var{attribute_list}]}
|
||||
@opindex -p
|
||||
@opindex --preserve
|
||||
@cindex file information, preserving
|
||||
@cindex file information, preserving, extended attributes, xattr
|
||||
Preserve the specified attributes of the original files.
|
||||
If specified, the @var{attribute_list} must be a comma-separated list
|
||||
of one or more of the following strings:
|
||||
@@ -7392,6 +7392,11 @@ Preserve in the destination files
|
||||
any links between corresponding source files.
|
||||
@c Give examples illustrating how hard links are preserved.
|
||||
@c Also, show how soft links map to hard links with -L and -H.
|
||||
@itemx xattr
|
||||
Preserve extended attributes if @command{cp} is built with xattr support,
|
||||
and xattrs are supported and enabled on your file system.
|
||||
If SELinux context and/or ACLs are implemented using xattrs,
|
||||
they are preserved by this option as well.
|
||||
@itemx all
|
||||
Preserve all file attributes.
|
||||
Equivalent to specifying all of the above.
|
||||
@@ -7935,6 +7940,9 @@ attributes of destination files. It is typically used in Makefiles to
|
||||
copy programs into their destination directories. It refuses to copy
|
||||
files onto themselves.
|
||||
|
||||
@cindex extended attributes, xattr
|
||||
@command{install} never preserves extended attributes (xattr).
|
||||
|
||||
The program accepts the following options. Also see @ref{Common options}.
|
||||
|
||||
@table @samp
|
||||
@@ -8083,6 +8091,9 @@ directory succeeded, but the second didn't, the first would be left on
|
||||
the destination partition and the second and third would be left on the
|
||||
original partition.
|
||||
|
||||
@cindex extended attributes, xattr
|
||||
@command{mv} always tries to copy extended attributes (xattr).
|
||||
|
||||
@cindex prompting, and @command{mv}
|
||||
If a destination file exists but is normally unwritable, standard input
|
||||
is a terminal, and the @option{-f} or @option{--force} option is not given,
|
||||
|
||||
@@ -38,6 +38,7 @@ AC_DEFUN([gl_PREREQ],
|
||||
# handles that; see ../bootstrap.conf.
|
||||
AC_REQUIRE([gl_EUIDACCESS_STAT])
|
||||
AC_REQUIRE([gl_FD_REOPEN])
|
||||
AC_REQUIRE([gl_FUNC_XATTR])
|
||||
AC_REQUIRE([gl_FUNC_XFTS])
|
||||
AC_REQUIRE([gl_MEMXFRM])
|
||||
AC_REQUIRE([gl_STRINTCMP])
|
||||
|
||||
36
m4/xattr.m4
Normal file
36
m4/xattr.m4
Normal file
@@ -0,0 +1,36 @@
|
||||
# xattr.m4 - check for Extended Attributes (Linux)
|
||||
|
||||
# Copyright (C) 2003, 2008 Free Software Foundation, Inc.
|
||||
# This file is free software; the Free Software Foundation
|
||||
# gives unlimited permission to copy and/or distribute it,
|
||||
# with or without modifications, as long as this notice is preserved.
|
||||
|
||||
# Originally written by Andreas Gruenbacher.
|
||||
# http://www.suse.de/~agruen/coreutils/5.91/coreutils-xattr.diff
|
||||
|
||||
AC_DEFUN([gl_FUNC_XATTR],
|
||||
[
|
||||
AC_ARG_ENABLE([xattr],
|
||||
AC_HELP_STRING([--disable-xattr],
|
||||
[do not support extended attributes]),
|
||||
[use_xattr=$enableval], [use_xattr=yes])
|
||||
|
||||
if test "$use_xattr" = "yes"; then
|
||||
AC_CHECK_HEADERS([attr/error_context.h attr/libattr.h])
|
||||
if test $ac_cv_header_attr_libattr_h = yes \
|
||||
&& test $ac_cv_header_attr_error_context_h = yes; then
|
||||
use_xattr=1
|
||||
else
|
||||
use_xattr=0
|
||||
fi
|
||||
AC_DEFINE_UNQUOTED([USE_XATTR], [$use_xattr],
|
||||
[Define if you want extended attribute support.])
|
||||
xattr_saved_LIBS=$LIBS
|
||||
AC_SEARCH_LIBS([attr_copy_file], [attr],
|
||||
[test "$ac_cv_search_attr_copy_file" = "none required" ||
|
||||
LIB_XATTR=$ac_cv_search_attr_copy_file])
|
||||
AC_CHECK_FUNCS([attr_copy_file])
|
||||
LIBS=$xattr_saved_LIBS
|
||||
AC_SUBST([LIB_XATTR])
|
||||
fi
|
||||
])
|
||||
@@ -1,5 +1,5 @@
|
||||
# List of files which contain translatable strings.
|
||||
# Copyright (C) 1996-2008 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1996-2009 Free Software Foundation, Inc.
|
||||
|
||||
# These are nominally temporary...
|
||||
lib/argmatch.c
|
||||
@@ -22,6 +22,7 @@ lib/rpmatch.c
|
||||
lib/set-mode-acl.c
|
||||
lib/unicodeio.c
|
||||
lib/userspec.c
|
||||
lib/verror.c
|
||||
lib/version-etc.c
|
||||
lib/xalloc-die.c
|
||||
lib/xfreopen.c
|
||||
|
||||
@@ -152,9 +152,9 @@ su_LDADD = $(LDADD) $(LIB_CRYPT)
|
||||
dir_LDADD += $(LIB_ACL)
|
||||
ls_LDADD += $(LIB_ACL)
|
||||
vdir_LDADD += $(LIB_ACL)
|
||||
cp_LDADD += $(LIB_ACL)
|
||||
mv_LDADD += $(LIB_ACL)
|
||||
ginstall_LDADD += $(LIB_ACL)
|
||||
cp_LDADD += $(LIB_ACL) $(LIB_XATTR)
|
||||
mv_LDADD += $(LIB_ACL) $(LIB_XATTR)
|
||||
ginstall_LDADD += $(LIB_ACL) $(LIB_XATTR)
|
||||
|
||||
stat_LDADD = $(LDADD) $(LIB_SELINUX)
|
||||
|
||||
|
||||
84
src/copy.c
84
src/copy.c
@@ -1,5 +1,5 @@
|
||||
/* copy.c -- core functions for copying files and directories
|
||||
Copyright (C) 89, 90, 91, 1995-2008 Free Software Foundation, Inc.
|
||||
Copyright (C) 89, 90, 91, 1995-2009 Free Software Foundation, Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
@@ -54,6 +54,13 @@
|
||||
#include "areadlink.h"
|
||||
#include "yesno.h"
|
||||
|
||||
#if USE_XATTR
|
||||
# include <attr/error_context.h>
|
||||
# include <attr/libattr.h>
|
||||
# include <stdarg.h>
|
||||
# include "verror.h"
|
||||
#endif
|
||||
|
||||
#ifndef HAVE_FCHOWN
|
||||
# define HAVE_FCHOWN false
|
||||
# define fchown(fd, uid, gid) (-1)
|
||||
@@ -123,6 +130,72 @@ is_ancestor (const struct stat *sb, const struct dir_list *ancestors)
|
||||
return false;
|
||||
}
|
||||
|
||||
#if USE_XATTR
|
||||
static void
|
||||
copy_attr_error (struct error_context *ctx ATTRIBUTE_UNUSED,
|
||||
char const *fmt, ...)
|
||||
{
|
||||
int err = errno;
|
||||
va_list ap;
|
||||
|
||||
/* use verror module to print error message */
|
||||
va_start (ap, fmt);
|
||||
verror (0, err, fmt, ap);
|
||||
va_end (ap);
|
||||
}
|
||||
|
||||
static char const *
|
||||
copy_attr_quote (struct error_context *ctx ATTRIBUTE_UNUSED, char const *str)
|
||||
{
|
||||
return quote (str);
|
||||
}
|
||||
|
||||
static void
|
||||
copy_attr_free (struct error_context *ctx ATTRIBUTE_UNUSED,
|
||||
char const *str ATTRIBUTE_UNUSED)
|
||||
{
|
||||
}
|
||||
|
||||
static bool
|
||||
copy_attr_by_fd (char const *src_path, int src_fd,
|
||||
char const *dst_path, int dst_fd)
|
||||
{
|
||||
struct error_context ctx =
|
||||
{
|
||||
.error = copy_attr_error,
|
||||
.quote = copy_attr_quote,
|
||||
.quote_free = copy_attr_free
|
||||
};
|
||||
return 0 == attr_copy_fd (src_path, src_fd, dst_path, dst_fd, 0, &ctx);
|
||||
}
|
||||
|
||||
static bool
|
||||
copy_attr_by_name (char const *src_path, char const *dst_path)
|
||||
{
|
||||
struct error_context ctx =
|
||||
{
|
||||
.error = copy_attr_error,
|
||||
.quote = copy_attr_quote,
|
||||
.quote_free = copy_attr_free
|
||||
};
|
||||
return 0 == attr_copy_file (src_path, dst_path, 0, &ctx);
|
||||
}
|
||||
#else /* USE_XATTR */
|
||||
|
||||
static bool
|
||||
copy_attr_by_fd (char const *src_path, int src_fd,
|
||||
char const *dst_path, int dst_fd)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
copy_attr_by_name (char const *src_path, char const *dst_path)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
#endif /* USE_XATTR */
|
||||
|
||||
/* Read the contents of the directory SRC_NAME_IN, and recursively
|
||||
copy the contents to DST_NAME_IN. NEW_DST is true if
|
||||
DST_NAME_IN is a directory that was created previously in the
|
||||
@@ -681,6 +754,11 @@ copy_reg (char const *src_name, char const *dst_name,
|
||||
|
||||
set_author (dst_name, dest_desc, src_sb);
|
||||
|
||||
if (x->preserve_xattr && ! copy_attr_by_fd (src_name, source_desc,
|
||||
dst_name, dest_desc)
|
||||
&& x->require_preserve_xattr)
|
||||
return false;
|
||||
|
||||
if (x->preserve_mode || x->move_mode)
|
||||
{
|
||||
if (copy_acl (src_name, source_desc, dst_name, dest_desc, src_mode) != 0
|
||||
@@ -1985,6 +2063,10 @@ copy_internal (char const *src_name, char const *dst_name,
|
||||
|
||||
set_author (dst_name, -1, &src_sb);
|
||||
|
||||
if (x->preserve_xattr && ! copy_attr_by_name (src_name, dst_name)
|
||||
&& x->require_preserve_xattr)
|
||||
return false;
|
||||
|
||||
if (x->preserve_mode || x->move_mode)
|
||||
{
|
||||
if (copy_acl (src_name, -1, dst_name, -1, src_mode) != 0
|
||||
|
||||
13
src/copy.h
13
src/copy.h
@@ -173,6 +173,19 @@ struct cp_options
|
||||
fail if it is unable to do so. */
|
||||
bool require_preserve_context;
|
||||
|
||||
/* If true, attempt to preserve extended attributes using libattr.
|
||||
Ignored if coreutils are compiled without xattr support. */
|
||||
bool preserve_xattr;
|
||||
|
||||
/* Useful only when preserve_xattr is true.
|
||||
If true, a failed attempt to preserve file's extended attributes
|
||||
propagates failure "out" to the caller. If false, a failure to
|
||||
preserve file's extended attributes does not change the invoking
|
||||
application's exit status. Give diagnostics for failed syscalls
|
||||
regardless of this setting. For example, with "cp --preserve=xattr"
|
||||
this flag is "true", while with "cp --preserve=all", it is false. */
|
||||
bool require_preserve_xattr;
|
||||
|
||||
/* If true, copy directories recursively and copy special files
|
||||
as themselves rather than copying their contents. */
|
||||
bool recursive;
|
||||
|
||||
23
src/cp.c
23
src/cp.c
@@ -187,7 +187,8 @@ Mandatory arguments to long options are mandatory for short options too.\n\
|
||||
-p same as --preserve=mode,ownership,timestamps\n\
|
||||
--preserve[=ATTR_LIST] preserve the specified attributes (default:\n\
|
||||
mode,ownership,timestamps), if possible\n\
|
||||
additional attributes: context, links, all\n\
|
||||
additional attributes: context, links, xattr,\n\
|
||||
all\n\
|
||||
"), stdout);
|
||||
fputs (_("\
|
||||
--no-preserve=ATTR_LIST don't preserve the specified attributes\n\
|
||||
@@ -764,6 +765,8 @@ cp_option_init (struct cp_options *x)
|
||||
x->preserve_timestamps = false;
|
||||
x->preserve_security_context = false;
|
||||
x->require_preserve_context = false;
|
||||
x->preserve_xattr = false;
|
||||
x->require_preserve_xattr = false;
|
||||
|
||||
x->require_preserve = false;
|
||||
x->recursive = false;
|
||||
@@ -800,18 +803,20 @@ decode_preserve_arg (char const *arg, struct cp_options *x, bool on_off)
|
||||
PRESERVE_OWNERSHIP,
|
||||
PRESERVE_LINK,
|
||||
PRESERVE_CONTEXT,
|
||||
PRESERVE_XATTR,
|
||||
PRESERVE_ALL
|
||||
};
|
||||
static enum File_attribute const preserve_vals[] =
|
||||
{
|
||||
PRESERVE_MODE, PRESERVE_TIMESTAMPS,
|
||||
PRESERVE_OWNERSHIP, PRESERVE_LINK, PRESERVE_CONTEXT, PRESERVE_ALL
|
||||
PRESERVE_OWNERSHIP, PRESERVE_LINK, PRESERVE_CONTEXT, PRESERVE_XATTR,
|
||||
PRESERVE_ALL
|
||||
};
|
||||
/* Valid arguments to the `--preserve' option. */
|
||||
static char const* const preserve_args[] =
|
||||
{
|
||||
"mode", "timestamps",
|
||||
"ownership", "links", "context", "all", NULL
|
||||
"ownership", "links", "context", "xattr", "all", NULL
|
||||
};
|
||||
ARGMATCH_VERIFY (preserve_args, preserve_vals);
|
||||
|
||||
@@ -852,6 +857,11 @@ decode_preserve_arg (char const *arg, struct cp_options *x, bool on_off)
|
||||
x->require_preserve_context = on_off;
|
||||
break;
|
||||
|
||||
case PRESERVE_XATTR:
|
||||
x->preserve_xattr = on_off;
|
||||
x->require_preserve_xattr = on_off;
|
||||
break;
|
||||
|
||||
case PRESERVE_ALL:
|
||||
x->preserve_mode = on_off;
|
||||
x->preserve_timestamps = on_off;
|
||||
@@ -859,6 +869,7 @@ decode_preserve_arg (char const *arg, struct cp_options *x, bool on_off)
|
||||
x->preserve_links = on_off;
|
||||
if (selinux_enabled)
|
||||
x->preserve_security_context = on_off;
|
||||
x->preserve_xattr = on_off;
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -1099,6 +1110,12 @@ main (int argc, char **argv)
|
||||
"without an SELinux-enabled kernel"));
|
||||
}
|
||||
|
||||
#if !USE_XATTR
|
||||
if (x.require_preserve_xattr)
|
||||
error (EXIT_FAILURE, 0, _("cannot preserve extended attributes, cp is "
|
||||
"built without xattr support"));
|
||||
#endif
|
||||
|
||||
/* Allocate space for remembering copied and created files. */
|
||||
|
||||
hash_init ();
|
||||
|
||||
@@ -200,6 +200,7 @@ cp_option_init (struct cp_options *x)
|
||||
x->open_dangling_dest_symlink = false;
|
||||
x->update = false;
|
||||
x->preserve_security_context = false;
|
||||
x->preserve_xattr = false;
|
||||
x->verbose = false;
|
||||
x->dest_info = NULL;
|
||||
x->src_info = NULL;
|
||||
|
||||
1
src/mv.c
1
src/mv.c
@@ -124,6 +124,7 @@ cp_option_init (struct cp_options *x)
|
||||
x->preserve_security_context = selinux_enabled;
|
||||
x->require_preserve = false; /* FIXME: maybe make this an option */
|
||||
x->require_preserve_context = false;
|
||||
x->preserve_xattr = true;
|
||||
x->recursive = true;
|
||||
x->sparse_mode = SPARSE_AUTO; /* FIXME: maybe make this an option */
|
||||
x->symbolic_link = false;
|
||||
|
||||
@@ -234,6 +234,7 @@ TESTS = \
|
||||
misc/tty-eof \
|
||||
misc/unexpand \
|
||||
misc/uniq \
|
||||
misc/xattr \
|
||||
chmod/c-option \
|
||||
chmod/equal-x \
|
||||
chmod/equals \
|
||||
|
||||
111
tests/misc/xattr
Executable file
111
tests/misc/xattr
Executable file
@@ -0,0 +1,111 @@
|
||||
#!/bin/sh
|
||||
# Ensure that cp --preserve=xattr and mv preserve extended attributes and
|
||||
# install does not preserve extended attributes.
|
||||
|
||||
# Copyright (C) 2009 Free Software Foundation, Inc.
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
if test "$VERBOSE" = yes; then
|
||||
set -x
|
||||
cp --version
|
||||
mv --version
|
||||
ginstall --version
|
||||
fi
|
||||
|
||||
. $srcdir/test-lib.sh
|
||||
|
||||
# Skip this test if cp was built without xattr support:
|
||||
touch src dest || framework_failure
|
||||
cp --preserve=xattr -n src dest 2>/dev/null \
|
||||
|| skip_test_ "coreutils built without xattr support"
|
||||
|
||||
# this code was taken from test mv/backup-is-src
|
||||
cleanup_() { rm -rf "$other_partition_tmpdir"; }
|
||||
. "$abs_srcdir/other-fs-tmpdir"
|
||||
b_other="$other_partition_tmpdir/b"
|
||||
rm -f $b_other || framework_failure
|
||||
|
||||
# testing xattr name-value pair
|
||||
xattr_name="user.foo"
|
||||
xattr_value="bar"
|
||||
xattr_pair="$xattr_name=\"$xattr_value\""
|
||||
|
||||
# create new file and check its xattrs
|
||||
touch a || framework_failure
|
||||
getfattr -d a >out_a || skip_test_ "failed to get xattr of file"
|
||||
grep -F "$xattr_pair" out_a >/dev/null && framework_failure
|
||||
|
||||
# try to set user xattr on file
|
||||
setfattr -n "$xattr_name" -v "$xattr_value" a >out_a \
|
||||
|| skip_test_ "failed to set xattr of file"
|
||||
getfattr -d a >out_a || skip_test_ "failed to get xattr of file"
|
||||
grep -F "$xattr_pair" out_a >/dev/null \
|
||||
|| skip_test_ "failed to set xattr of file"
|
||||
|
||||
fail=0
|
||||
|
||||
# cp should not preserve xattr by default
|
||||
cp a b || fail=1
|
||||
getfattr -d b >out_b || skip_test_ "failed to get xattr of file"
|
||||
grep -F "$xattr_pair" out_b >/dev/null && fail=1
|
||||
|
||||
# test if --preserve=xattr option works
|
||||
cp --preserve=xattr a b || fail=1
|
||||
getfattr -d b >out_b || skip_test_ "failed to get xattr of file"
|
||||
grep -F "$xattr_pair" out_b >/dev/null || fail=1
|
||||
|
||||
rm b || framework_failure
|
||||
|
||||
# install should never preserve xattr
|
||||
ginstall a b || fail=1
|
||||
getfattr -d b >out_b || skip_test_ "failed to get xattr of file"
|
||||
grep -F "$xattr_pair" out_b >/dev/null && fail=1
|
||||
|
||||
# mv should preserve xattr when renaming within a file system.
|
||||
# This is implicitly done by rename () and doesn't need explicit
|
||||
# xattr support in mv.
|
||||
mv a b || fail=1
|
||||
getfattr -d b >out_b || skip_test_ "failed to get xattr of file"
|
||||
grep -F "$xattr_pair" out_b >/dev/null || cat >&2 <<EOF
|
||||
=================================================================
|
||||
$0: WARNING!!!
|
||||
rename () does not preserve extended attributes
|
||||
=================================================================
|
||||
EOF
|
||||
|
||||
# try to set user xattr on file on other partition
|
||||
test_mv=1
|
||||
touch $b_other || framework_failure
|
||||
setfattr -n "$xattr_name" -v "$xattr_value" $b_other >out_a 2>/dev/null \
|
||||
|| test_mv=0
|
||||
getfattr -d $b_other >out_b 2>/dev/null || test_mv=0
|
||||
grep -F "$xattr_pair" out_b >/dev/null || test_mv=0
|
||||
rm -f $b_other || framework_failure
|
||||
|
||||
if test $test_mv -eq 1; then
|
||||
# mv should preserve xattr when copying content from one partition to another
|
||||
mv b $b_other || fail=1
|
||||
getfattr -d $b_other >out_b 2>/dev/null || skip_test_ "failed to get xattr of file"
|
||||
grep -F "$xattr_pair" out_b >/dev/null || fail=1
|
||||
else
|
||||
cat >&2 <<EOF
|
||||
=================================================================
|
||||
$0: WARNING!!!
|
||||
failed to set xattr of file $b_other
|
||||
=================================================================
|
||||
EOF
|
||||
fi
|
||||
|
||||
Exit $fail
|
||||
Reference in New Issue
Block a user