* Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu>
* SELinux support by Yuichi Nakamura <ynakam@hitachisoft.jp>
*
- * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ * Licensed under GPLv2 or later, see file LICENSE in this source tree.
*/
#include "libbb.h"
// (No "opening without O_EXCL", no "unlink only if -f")
// Or else we will end up having 3 open()s!
fprintf(stderr, "%s: overwrite '%s'? ", applet_name, dest);
- if (!bb_ask_confirmation())
+ if (!bb_ask_y_confirmation())
return 0; /* not allowed to overwrite */
}
if (unlink(dest) < 0) {
bb_perror_msg("can't create '%s'", dest);
return -1; /* error */
}
+#if ENABLE_FEATURE_CP_LONG_OPTIONS
+ if (flags & FILEUTILS_RMDEST)
+ if (flags & FILEUTILS_VERBOSE)
+ printf("removed '%s'\n", dest);
+#endif
return 1; /* ok (to try again) */
}
/* NB: each struct stat is ~100 bytes */
struct stat source_stat;
struct stat dest_stat;
- signed char retval = 0;
- signed char dest_exists = 0;
- signed char ovr;
+ smallint retval = 0;
+ smallint dest_exists = 0;
+ smallint ovr;
/* Inverse of cp -d ("cp without -d") */
#define FLAGS_DEREF (flags & (FILEUTILS_DEREFERENCE + FILEUTILS_DEREFERENCE_L0))
return -1;
}
- /* Create DEST */
if (dest_exists) {
if (!S_ISDIR(dest_stat.st_mode)) {
bb_error_msg("target '%s' is not a directory", dest);
/* race here: user can substitute a symlink between
* this check and actual creation of files inside dest */
} else {
+ /* Create DEST */
mode_t mode;
saved_umask = umask(0);
goto preserve_mode_ugid_time;
}
+ if (dest_exists) {
+ if (flags & FILEUTILS_UPDATE) {
+ if (source_stat.st_mtime <= dest_stat.st_mtime) {
+ return 0; /* source file must be newer */
+ }
+ }
+#if ENABLE_FEATURE_CP_LONG_OPTIONS
+ if (flags & FILEUTILS_RMDEST) {
+ ovr = ask_and_unlink(dest, flags);
+ if (ovr <= 0)
+ return ovr;
+ dest_exists = 0;
+ }
+#endif
+ }
+
if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) {
int (*lf)(const char *oldpath, const char *newpath);
make_links:
if (!S_ISREG(source_stat.st_mode))
new_mode = 0666;
- // POSIX way is a security problem versus (sym)link attacks
- if (!ENABLE_FEATURE_NON_POSIX_CP) {
- dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode);
- } else { /* safe way: */
+ if (ENABLE_FEATURE_NON_POSIX_CP || (flags & FILEUTILS_INTERACTIVE)) {
+ /*
+ * O_CREAT|O_EXCL: require that file did not exist before creation
+ */
dst_fd = open(dest, O_WRONLY|O_CREAT|O_EXCL, new_mode);
+ } else { /* POSIX, and not "cp -i" */
+ /*
+ * O_CREAT|O_TRUNC: create, or truncate (security problem versus (sym)link attacks)
+ */
+ dst_fd = open(dest, O_WRONLY|O_CREAT|O_TRUNC, new_mode);
}
if (dst_fd == -1) {
ovr = ask_and_unlink(dest, flags);
) {
security_context_t con;
if (getfscreatecon(&con) == -1) {
- bb_perror_msg("getfscreatecon");
+ bb_simple_perror_msg("getfscreatecon");
return -1;
}
if (con) {
freecon(con);
}
}
+#endif
+#if ENABLE_FEATURE_CP_REFLINK
+# undef BTRFS_IOCTL_MAGIC
+# define BTRFS_IOCTL_MAGIC 0x94
+# undef BTRFS_IOC_CLONE
+# define BTRFS_IOC_CLONE _IOW (BTRFS_IOCTL_MAGIC, 9, int)
+ if (flags & FILEUTILS_REFLINK) {
+ retval = ioctl(dst_fd, BTRFS_IOC_CLONE, src_fd);
+ if (retval == 0)
+ goto do_close;
+ /* reflink did not work */
+ if (flags & FILEUTILS_REFLINK_ALWAYS) {
+ bb_perror_msg("failed to clone '%s' from '%s'", dest, source);
+ goto do_close;
+ }
+ /* fall through to standard copy */
+ retval = 0;
+ }
#endif
if (bb_copyfd_eof(src_fd, dst_fd) == -1)
retval = -1;
+ IF_FEATURE_CP_REFLINK(do_close:)
/* Careful with writing... */
if (close(dst_fd) < 0) {
bb_perror_msg("error writing to '%s'", dest);
char *lpath = xmalloc_readlink_or_warn(source);
if (lpath) {
int r = symlink(lpath, dest);
- free(lpath);
if (r < 0) {
- bb_perror_msg("can't create symlink '%s'", dest);
+ /* shared message */
+ bb_perror_msg("can't create %slink '%s' to '%s'",
+ "sym", dest, lpath
+ );
+ free(lpath);
return -1;
}
+ free(lpath);
if (flags & FILEUTILS_PRESERVE_STATUS)
if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
bb_perror_msg("can't preserve %s of '%s'", "ownership", dest);
}
/* _Not_ jumping to preserve_mode_ugid_time:
* symlinks don't have those */
- return 0;
+ goto verb_and_exit;
}
if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode)
|| S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode)
bb_perror_msg("can't preserve %s of '%s'", "permissions", dest);
}
+ verb_and_exit:
+ if (flags & FILEUTILS_VERBOSE) {
+ printf("'%s' -> '%s'\n", source, dest);
+ }
+
return retval;
}