aboutsummaryrefslogtreecommitdiff
path: root/toys/cp.c
diff options
context:
space:
mode:
Diffstat (limited to 'toys/cp.c')
-rw-r--r--toys/cp.c224
1 files changed, 0 insertions, 224 deletions
diff --git a/toys/cp.c b/toys/cp.c
deleted file mode 100644
index bc922b3d..00000000
--- a/toys/cp.c
+++ /dev/null
@@ -1,224 +0,0 @@
-/* vi: set sw=4 ts=4:
- *
- * cp.c - Copy files.
- *
- * Copyright 2008 Rob Landley <rob@landley.net>
- *
- * See http://www.opengroup.org/onlinepubs/009695399/utilities/cp.html
- *
- * "R+ra+d+p+r"
-USE_CP(NEWTOY(cp, "<2vslrRdpaHLPif", TOYFLAG_BIN))
-
-config CP
- bool "cp (broken by dirtree changes)"
- default n
- help
- usage: cp -fiprdal SOURCE... DEST
-
- Copy files from SOURCE to DEST. If more than one SOURCE, DEST must
- be a directory.
-
- -f force copy by deleting destination file
- -i interactive, prompt before overwriting existing DEST
- -p preserve timestamps, ownership, and permissions
- -r recurse into subdirectories (DEST must be a directory)
- -d don't dereference symlinks
- -a same as -dpr
- -l hard link instead of copying
- -v verbose
-*/
-
-#include "toys.h"
-
-#define FLAG_f 1
-#define FLAG_i 2
-#define FLAG_P 4 // todo
-#define FLAG_L 8 // todo
-#define FLAG_H 16 // todo
-#define FLAG_a 32
-#define FLAG_p 64
-#define FLAG_d 128 // todo
-#define FLAG_R 256
-#define FLAG_r 512
-#define FLAG_l 1024 // todo
-#define FLAG_s 2048 // todo
-#define FLAG_v 4098
-
-DEFINE_GLOBALS(
- char *destname;
- int destisdir;
- int destisnew;
- int keep_symlinks;
-)
-
-#define TT this.cp
-
-// Copy an individual file or directory to target.
-
-void cp_file(char *src, char *dst, struct stat *srcst)
-{
- int fdout = -1;
-
- // -i flag is specified and dst file exists.
- if ((toys.optflags&FLAG_i) && !access(dst, R_OK)
- && !yesno("cp: overwrite", 1))
- return;
-
- if (toys.optflags & FLAG_v)
- printf("'%s' -> '%s'\n", src, dst);
-
- // Copy directory or file to destination.
-
- if (S_ISDIR(srcst->st_mode)) {
- struct stat st2;
-
- // Always make directory writeable to us, so we can create files in it.
- //
- // Yes, there's a race window between mkdir() and open() so it's
- // possible that -p can be made to chown a directory other than the one
- // we created. The closest we can do to closing this is make sure
- // that what we open _is_ a directory rather than something else.
-
- if ((mkdir(dst, srcst->st_mode | 0200) && errno != EEXIST)
- || 0>(fdout=open(dst, 0)) || fstat(fdout, &st2)
- || !S_ISDIR(st2.st_mode))
- {
- perror_exit("mkdir '%s'", dst);
- }
- } else if (TT.keep_symlinks && S_ISLNK(srcst->st_mode)) {
- char *link = xreadlink(src);
-
- // Note: -p currently has no effect on symlinks. How do you get a
- // filehandle to them? O_NOFOLLOW causes the open to fail.
- if (!link || symlink(link, dst)) perror_msg("link '%s'", dst);
- free(link);
- return;
- } else if (toys.optflags & FLAG_l) {
- if (link(src, dst)) perror_msg("link '%s'");
- return;
- } else {
- int fdin, i;
-
- fdin = xopen(src, O_RDONLY);
- for (i=2 ; i; i--) {
- fdout = open(dst, O_RDWR|O_CREAT|O_TRUNC, srcst->st_mode);
- if (fdout>=0 || !(toys.optflags & FLAG_f)) break;
- unlink(dst);
- }
- if (fdout<0) perror_exit("%s", dst);
- xsendfile(fdin, fdout);
- close(fdin);
- }
-
- // Inability to set these isn't fatal, some require root access.
- // Can't do fchmod() etc here because -p works on mkdir, too.
-
- if (toys.optflags & (FLAG_p|FLAG_a)) {
- int mask = umask(0);
- struct utimbuf ut;
-
- (void) fchown(fdout,srcst->st_uid, srcst->st_gid);
- ut.actime = srcst->st_atime;
- ut.modtime = srcst->st_mtime;
- utime(dst, &ut);
- umask(mask);
- }
- xclose(fdout);
-}
-
-// Callback from dirtree_read() for each file/directory under a source dir.
-
-int cp_node(struct dirtree *node)
-{
- char *path = dirtree_path(node, 0); // TODO: use openat() instead
- char *s = path+strlen(path);
- struct dirtree *n;
-
- // Find appropriate chunk of path for destination.
-
- n = node;
- if (!TT.destisdir) n = n->parent;
- for (;;n = n->parent) {
- while (s!=path) {
- if (*(--s)=='/') break;
- }
- if (!n) break;
- }
- if (s != path) s++;
-
- s = xmsprintf("%s/%s", TT.destname, s);
- cp_file(path, s, &(node->st));
- free(s);
- free(path); // redo this whole darn function.
-
- return 0;
-}
-
-void cp_main(void)
-{
- struct stat st;
- int i;
-
- // Grab target argument. (Guaranteed to be there due to "<2" above.)
-
- TT.destname = toys.optargs[--toys.optc];
-
- // If destination doesn't exist, are we ok with that?
-
- if (stat(TT.destname, &st)) {
- if (toys.optc>1) goto error_notdir;
- TT.destisnew++;
-
- // If destination exists...
-
- } else {
- if (S_ISDIR(st.st_mode)) TT.destisdir++;
- else if (toys.optc > 1) goto error_notdir;
- }
-
- // Handle sources
-
- for (i=0; i<toys.optc; i++) {
- char *src = toys.optargs[i];
- char *dst;
-
- // Skip src==dest (TODO check inodes to catch "cp blah ./blah").
-
- if (!strcmp(src, TT.destname)) continue;
-
- // Skip nonexistent sources.
-
- TT.keep_symlinks = toys.optflags & (FLAG_d|FLAG_a);
- if (TT.keep_symlinks ? lstat(src, &st) : stat(src, &st))
- {
- perror_msg("'%s'", src);
- toys.exitval = 1;
- continue;
- }
-
- // Copy directory or file.
-
- if (TT.destisdir) {
- dst = strrchr(src, '/');
- if (dst) dst++;
- else dst=src;
- dst = xmsprintf("%s/%s", TT.destname, dst);
- } else dst = TT.destname;
- if (S_ISDIR(st.st_mode)) {
- if (toys.optflags & (FLAG_r|FLAG_R|FLAG_a)) {
- cp_file(src, dst, &st);
-
- TT.keep_symlinks++;
- strncpy(toybuf, src, sizeof(toybuf)-1);
- toybuf[sizeof(toybuf)-1]=0;
- dirtree_read(toybuf, cp_node);
- } else error_msg("Skipped dir '%s'", src);
- } else cp_file(src, dst, &st);
- if (TT.destisdir) free(dst);
- }
-
- return;
-
-error_notdir:
- error_exit("'%s' isn't a directory", TT.destname);
-}