# HG changeset patch # User Rob Landley # Date 1206353677 18000 # Node ID 7b3d9594bf9c073dd6beee2073a226cfb9eddbed # Parent 56a29fb3c9f6d5f6bd36f7114ab3df11904a8520 Fix -r logic, it needs both source and dest paths explicitly stated. diff -r 56a29fb3c9f6 -r 7b3d9594bf9c toys/cp.c --- a/toys/cp.c Mon Mar 24 00:32:25 2008 -0500 +++ b/toys/cp.c Mon Mar 24 05:14:37 2008 -0500 @@ -11,9 +11,9 @@ config CP bool "cp" - default n + default y help - usage: cp -fpr SOURCE... DEST + usage: cp -fiprdal SOURCE... DEST Copy files from SOURCE to DEST. If more than one SOURCE, DEST must be a directory. @@ -22,6 +22,9 @@ -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 */ #include "toys.h" @@ -36,35 +39,24 @@ #define FLAG_d 128 // todo #define FLAG_R 256 #define FLAG_r 512 -#define FLAG_s 1024 // todo -#define FLAG_l 2048 // todo +#define FLAG_l 1024 // todo +#define FLAG_s 2048 // todo 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, struct stat *srcst, int depth) +void cp_file(char *src, char *dst, struct stat *srcst) { - char *s = NULL; int fdout = -1; - // Trim path from name if necessary. - - if (!depth) s = strrchr(src, '/'); - if (s) s++; - else s=src; - - // Determine location to create new file/directory at. - - if (TT.destisdir || depth) s = xmsprintf("%s/%s", TT.destname, s); - else s = xstrdup(TT.destname); - // Copy directory or file to destination. if (S_ISDIR(srcst->st_mode)) { @@ -77,31 +69,31 @@ // 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(s, srcst->st_mode | 0200) || 0>(fdout=open(s, 0)) + if (mkdir(dst, srcst->st_mode | 0200) || 0>(fdout=open(dst, 0)) || fstat(fdout, &st2) || !S_ISDIR(st2.st_mode)) { - perror_exit("mkdir '%s'", s); + perror_exit("mkdir '%s'", dst); } - } else if ((depth || (toys.optflags & FLAG_d)) && S_ISLNK(srcst->st_mode)) { - struct stat st2; + } 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, s)) perror_msg("link '%s'",s); + if (!link || symlink(link, dst)) perror_msg("link '%s'", dst); free(link); } else if (toys.optflags & FLAG_l) { - if (link(src, s)) perror_msg("link '%s'"); + 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(s, O_RDWR|O_CREAT|O_TRUNC, srcst->st_mode); + fdout = open(dst, O_RDWR|O_CREAT|O_TRUNC, srcst->st_mode); if (fdout>=0 || !(toys.optflags & FLAG_f)) break; - unlink(s); + unlink(dst); } - if (fdout<0) perror_exit("%s", s); + if (fdout<0) perror_exit("%s", dst); xsendfile(fdin, fdout); close(fdin); } @@ -116,11 +108,10 @@ fchown(fdout,srcst->st_uid, srcst->st_gid); ut.actime = srcst->st_atime; ut.modtime = srcst->st_mtime; - utime(s, &ut); + utime(dst, &ut); umask(mask); } xclose(fdout); - free(s); } // Callback from dirtree_read() for each file/directory under a source dir. @@ -128,21 +119,22 @@ int cp_node(char *path, struct dirtree *node) { char *s = path+strlen(path); - struct dirtree *n = node; - int depth = 0; + struct dirtree *n; // Find appropriate chunk of path for destination. - for (;;) { - if (*(--s) == '/') { - depth++; - if (!n->parent) break; - n = n->parent; + for (n = node;;n = n->parent) { + while (s!=path) { + if (*(--s)=='/') break; } + if (!n) break; } - s++; - - cp_file(s, &(node->st), depth); + if (s != path) s++; + + s = xmsprintf("%s/%s", TT.destname, s); + cp_file(path, s, &(node->st)); + free(s); + return 0; } @@ -172,27 +164,40 @@ for (i=0; i