diff options
Diffstat (limited to 'toys/cp.c')
-rw-r--r-- | toys/cp.c | 224 |
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); -} |