Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Merge pull request #5 from kjokinie/master
Copy extended attributes if -p flag is provided to cp, mv. Contribute…
  • Loading branch information
Kalle Jokiniemi committed Jul 16, 2015
2 parents a679bff + a924da5 commit 69722ed
Show file tree
Hide file tree
Showing 6 changed files with 145 additions and 0 deletions.
3 changes: 3 additions & 0 deletions busybox/include/libbb.h
Expand Up @@ -342,6 +342,9 @@ extern int remove_file(const char *path, int flags) FAST_FUNC;
* This makes "cp /dev/null file" and "install /dev/null file" (!!!)
* work coreutils-compatibly. */
extern int copy_file(const char *source, const char *dest, int flags) FAST_FUNC;
#if ENABLE_XATTR
extern int copy_file_attr(const char *src_path, const char *dst_path) FAST_FUNC;
#endif

enum {
ACTION_RECURSE = (1 << 0),
Expand Down
6 changes: 6 additions & 0 deletions busybox/libbb/Config.src
Expand Up @@ -232,4 +232,10 @@ config FEATURE_HWIB
Support for printing infiniband addresses in
network applets.

config XATTR
bool "Support preserve extended attributes for cp command"
default y
help
Support preserve extended attributes for cp and mv command.

endmenu
1 change: 1 addition & 0 deletions busybox/libbb/Kbuild.src
Expand Up @@ -172,6 +172,7 @@ lib-$(CONFIG_TRACEROUTE6) += inet_cksum.o
lib-$(CONFIG_UDHCPC) += inet_cksum.o
lib-$(CONFIG_UDHCPC6) += inet_cksum.o
lib-$(CONFIG_UDHCPD) += inet_cksum.o
lib-$(CONFIG_XATTR) += copy_file_attr.o

# We shouldn't build xregcomp.c if we don't need it - this ensures we don't
# require regex.h to be in the include dir even if we don't need it thereby
Expand Down
8 changes: 8 additions & 0 deletions busybox/libbb/copy_file.c
Expand Up @@ -314,6 +314,7 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
}
}
#endif

if (bb_copyfd_eof(src_fd, dst_fd) == -1)
retval = -1;
/* Careful with writing... */
Expand Down Expand Up @@ -385,6 +386,13 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags)
source_stat.st_mode &= ~(S_ISUID | S_ISGID);
bb_perror_msg("can't preserve %s of '%s'", "ownership", dest);
}
#if ENABLE_XATTR
/* Preserve extended attributes. We must copy it after chown()
* because it resets capabilities. */
if (copy_file_attr(source, dest) == -1)
bb_perror_msg("can't preserve %s of '%s'",
"extended attributes", dest);
#endif
if (chmod(dest, source_stat.st_mode) < 0)
bb_perror_msg("can't preserve %s of '%s'", "permissions", dest);
}
Expand Down
125 changes: 125 additions & 0 deletions busybox/libbb/copy_file_attr.c
@@ -0,0 +1,125 @@
/* vi: set sw=4 ts=4: */
/*
* Copy extended attributes between files
*
* Copyright (C) 2014 Dmitry Falko <dfalko@digiflak.com>, digiFLAK
* Fixed by Igor Zhbanov <igor.zhbanov@jolla.com>
*
* based on libattr code, original copyright:
* Copyright (C) 1999-2005 by Erik Andersen <andersen@codepoet.org>
*
* Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/

#include <sys/types.h>
#include <sys/xattr.h>

#include "libbb.h"

#if !defined(ENOTSUP)
# define ENOTSUP (-1)
#endif

#if defined(HAVE_ALLOCA)
# define bb_alloc(size) alloca (size)
# define bb_free(ptr) do { } while(0)
#else
# define bb_alloc(size) xmalloc (size)
# define bb_free(ptr) free (ptr)
#endif

/* Copy extended attributes from src_path to dst_path. If the file
* has an extended Access ACL (system.posix_acl_access) and that is
* copied successfully, the file mode permission bits are copied as
* a side effect. This may not always the case, so the file mode
* and/or ownership must be copied separately. */
int FAST_FUNC copy_file_attr(const char *src_path, const char *dst_path)
{
int ret = 0;
ssize_t size;
char *names = NULL, *end_names, *name, *value = NULL;
unsigned int setxattr_ENOTSUP = 0;

if ((size = listxattr(src_path, NULL, 0)) < 0) {
if (errno != ENOSYS && errno != ENOTSUP) {
bb_perror_msg("listing attributes of %s", src_path);
ret = -1;
}

goto getout;
}

if (!(names = (char *)bb_alloc(size + 1))) {
bb_error_msg("cannot allocate buffer");
ret = -1;
goto getout;
}

if ((size = listxattr(src_path, names, size)) < 0) {
bb_error_msg("listing attributes of %s", src_path);
ret = -1;
goto getout;
} else {
names[size] = '\0';
end_names = names + size;
}

for (name = names; name != end_names; name = strchr(name, '\0') + 1) {
void *old_value;

if (!*name)
continue;

if ((size = getxattr(src_path, name, NULL, 0)) < 0) {
bb_error_msg("getting attribute %s of %s",
src_path, name);
ret = -1;
continue;
}

value = (char *)xrealloc(old_value = value, size);
if (size != 0 && !value) {
free(old_value);
bb_error_msg("failed to realloc");
ret = -1;
}

if ((size = getxattr(src_path, name, value, size)) < 0) {
bb_error_msg("getting attribute %s of %s",
src_path, name);
ret = -1;
continue;
}

if (setxattr(dst_path, name, value, size, 0) != 0) {
if (errno == ENOTSUP)
setxattr_ENOTSUP++;
else {
if (errno == ENOSYS) {
bb_error_msg("setting attributes for "
"%s", dst_path);
ret = -1;
/* no hope of getting any further */
break;
} else {
bb_error_msg("setting attribute %s "
"for %s", name,
dst_path);
ret = -1;
}
}
}
}

if (setxattr_ENOTSUP) {
errno = ENOTSUP;
/* ignore this error */
bb_error_msg("setting attributes for %s", dst_path);
ret = 0;
}

getout:
free(value);
bb_free(names);
return ret;
}
2 changes: 2 additions & 0 deletions rpm/busybox-static.config
Expand Up @@ -1011,3 +1011,5 @@ CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING=y
CONFIG_KLOGD=y
CONFIG_FEATURE_KLOGD_KLOGCTL=y
CONFIG_LOGGER=y

CONFIG_XATTR=y

0 comments on commit 69722ed

Please sign in to comment.