annotate toys/cp.c @ 650:dd82e0b28eda

Fix bug spotted by Avery Pennarun: getusername() and getgroupname() can reuse the utoa buffer when neither is recognized, meaning uid would be shown again instead of gid.
author Rob Landley <rob@landley.net>
date Sat, 18 Aug 2012 21:12:02 -0500
parents 9802b2afbce8
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
1 /* vi: set sw=4 ts=4:
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
2 *
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
3 * cp.c - Copy files.
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
4 *
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
5 * Copyright 2008 Rob Landley <rob@landley.net>
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
6 *
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
7 * See http://www.opengroup.org/onlinepubs/009695399/utilities/cp.html
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
8 *
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
9 * "R+ra+d+p+r"
583
9802b2afbce8 cp doesn't really need the optstring + logic. Still needs to be updated for new dirtree, though.
Rob Landley <rob@landley.net>
parents: 565
diff changeset
10 USE_CP(NEWTOY(cp, "<2vslrRdpaHLPif", TOYFLAG_BIN))
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
11
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
12 config CP
565
44abf4d901f3 Rewrite dirtree so we don't need readdir, scandir, and fts.h. Rewrite ls (from scratch) to use new dirtree infrastructure. (This breaks everything else that currently uses dirtree.)
Rob Landley <rob@landley.net>
parents: 528
diff changeset
13 bool "cp (broken by dirtree changes)"
44abf4d901f3 Rewrite dirtree so we don't need readdir, scandir, and fts.h. Rewrite ls (from scratch) to use new dirtree infrastructure. (This breaks everything else that currently uses dirtree.)
Rob Landley <rob@landley.net>
parents: 528
diff changeset
14 default n
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
15 help
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
16 usage: cp -fiprdal SOURCE... DEST
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
17
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
18 Copy files from SOURCE to DEST. If more than one SOURCE, DEST must
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
19 be a directory.
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
20
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
21 -f force copy by deleting destination file
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
22 -i interactive, prompt before overwriting existing DEST
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
23 -p preserve timestamps, ownership, and permissions
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
24 -r recurse into subdirectories (DEST must be a directory)
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
25 -d don't dereference symlinks
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
26 -a same as -dpr
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
27 -l hard link instead of copying
282
a08f1affe016 Add -v to cp.
Rob Landley <rob@landley.net>
parents: 272
diff changeset
28 -v verbose
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
29 */
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
30
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
31 #include "toys.h"
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
32
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
33 #define FLAG_f 1
497
da73bb464ce8 Implemented -i for cp
Bryce Fricke
parents: 435
diff changeset
34 #define FLAG_i 2
267
784bc9b0d6df Make cp pass the rest of its test suite. Needs a bigger test suite (-lsHPLi
Rob Landley <rob@landley.net>
parents: 263
diff changeset
35 #define FLAG_P 4 // todo
784bc9b0d6df Make cp pass the rest of its test suite. Needs a bigger test suite (-lsHPLi
Rob Landley <rob@landley.net>
parents: 263
diff changeset
36 #define FLAG_L 8 // todo
784bc9b0d6df Make cp pass the rest of its test suite. Needs a bigger test suite (-lsHPLi
Rob Landley <rob@landley.net>
parents: 263
diff changeset
37 #define FLAG_H 16 // todo
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
38 #define FLAG_a 32
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
39 #define FLAG_p 64
267
784bc9b0d6df Make cp pass the rest of its test suite. Needs a bigger test suite (-lsHPLi
Rob Landley <rob@landley.net>
parents: 263
diff changeset
40 #define FLAG_d 128 // todo
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
41 #define FLAG_R 256
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
42 #define FLAG_r 512
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
43 #define FLAG_l 1024 // todo
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
44 #define FLAG_s 2048 // todo
282
a08f1affe016 Add -v to cp.
Rob Landley <rob@landley.net>
parents: 272
diff changeset
45 #define FLAG_v 4098
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
46
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
47 DEFINE_GLOBALS(
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
48 char *destname;
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
49 int destisdir;
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
50 int destisnew;
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
51 int keep_symlinks;
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
52 )
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
53
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
54 #define TT this.cp
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
55
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
56 // Copy an individual file or directory to target.
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
57
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
58 void cp_file(char *src, char *dst, struct stat *srcst)
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
59 {
267
784bc9b0d6df Make cp pass the rest of its test suite. Needs a bigger test suite (-lsHPLi
Rob Landley <rob@landley.net>
parents: 263
diff changeset
60 int fdout = -1;
497
da73bb464ce8 Implemented -i for cp
Bryce Fricke
parents: 435
diff changeset
61
503
3b9dea897dc0 Upgrade yesno() and make cp -i use it.
Rob Landley <rob@landley.net>
parents: 497
diff changeset
62 // -i flag is specified and dst file exists.
3b9dea897dc0 Upgrade yesno() and make cp -i use it.
Rob Landley <rob@landley.net>
parents: 497
diff changeset
63 if ((toys.optflags&FLAG_i) && !access(dst, R_OK)
3b9dea897dc0 Upgrade yesno() and make cp -i use it.
Rob Landley <rob@landley.net>
parents: 497
diff changeset
64 && !yesno("cp: overwrite", 1))
3b9dea897dc0 Upgrade yesno() and make cp -i use it.
Rob Landley <rob@landley.net>
parents: 497
diff changeset
65 return;
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
66
282
a08f1affe016 Add -v to cp.
Rob Landley <rob@landley.net>
parents: 272
diff changeset
67 if (toys.optflags & FLAG_v)
a08f1affe016 Add -v to cp.
Rob Landley <rob@landley.net>
parents: 272
diff changeset
68 printf("'%s' -> '%s'\n", src, dst);
a08f1affe016 Add -v to cp.
Rob Landley <rob@landley.net>
parents: 272
diff changeset
69
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
70 // Copy directory or file to destination.
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
71
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
72 if (S_ISDIR(srcst->st_mode)) {
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
73 struct stat st2;
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
74
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
75 // Always make directory writeable to us, so we can create files in it.
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
76 //
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
77 // Yes, there's a race window between mkdir() and open() so it's
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
78 // possible that -p can be made to chown a directory other than the one
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
79 // we created. The closest we can do to closing this is make sure
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
80 // that what we open _is_ a directory rather than something else.
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
81
272
a5652aa22f38 Another cp -r fix, another test case...
Rob Landley <rob@landley.net>
parents: 271
diff changeset
82 if ((mkdir(dst, srcst->st_mode | 0200) && errno != EEXIST)
a5652aa22f38 Another cp -r fix, another test case...
Rob Landley <rob@landley.net>
parents: 271
diff changeset
83 || 0>(fdout=open(dst, 0)) || fstat(fdout, &st2)
a5652aa22f38 Another cp -r fix, another test case...
Rob Landley <rob@landley.net>
parents: 271
diff changeset
84 || !S_ISDIR(st2.st_mode))
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
85 {
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
86 perror_exit("mkdir '%s'", dst);
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
87 }
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
88 } else if (TT.keep_symlinks && S_ISLNK(srcst->st_mode)) {
267
784bc9b0d6df Make cp pass the rest of its test suite. Needs a bigger test suite (-lsHPLi
Rob Landley <rob@landley.net>
parents: 263
diff changeset
89 char *link = xreadlink(src);
784bc9b0d6df Make cp pass the rest of its test suite. Needs a bigger test suite (-lsHPLi
Rob Landley <rob@landley.net>
parents: 263
diff changeset
90
784bc9b0d6df Make cp pass the rest of its test suite. Needs a bigger test suite (-lsHPLi
Rob Landley <rob@landley.net>
parents: 263
diff changeset
91 // Note: -p currently has no effect on symlinks. How do you get a
784bc9b0d6df Make cp pass the rest of its test suite. Needs a bigger test suite (-lsHPLi
Rob Landley <rob@landley.net>
parents: 263
diff changeset
92 // filehandle to them? O_NOFOLLOW causes the open to fail.
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
93 if (!link || symlink(link, dst)) perror_msg("link '%s'", dst);
267
784bc9b0d6df Make cp pass the rest of its test suite. Needs a bigger test suite (-lsHPLi
Rob Landley <rob@landley.net>
parents: 263
diff changeset
94 free(link);
283
2134fa02ec00 We don't open a destination filehandle for symlinks, so xclose() would barf.
Rob Landley <rob@landley.net>
parents: 282
diff changeset
95 return;
267
784bc9b0d6df Make cp pass the rest of its test suite. Needs a bigger test suite (-lsHPLi
Rob Landley <rob@landley.net>
parents: 263
diff changeset
96 } else if (toys.optflags & FLAG_l) {
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
97 if (link(src, dst)) perror_msg("link '%s'");
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
98 return;
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
99 } else {
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
100 int fdin, i;
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
101
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
102 fdin = xopen(src, O_RDONLY);
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
103 for (i=2 ; i; i--) {
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
104 fdout = open(dst, O_RDWR|O_CREAT|O_TRUNC, srcst->st_mode);
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
105 if (fdout>=0 || !(toys.optflags & FLAG_f)) break;
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
106 unlink(dst);
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
107 }
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
108 if (fdout<0) perror_exit("%s", dst);
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
109 xsendfile(fdin, fdout);
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
110 close(fdin);
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
111 }
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
112
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
113 // Inability to set these isn't fatal, some require root access.
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
114 // Can't do fchmod() etc here because -p works on mkdir, too.
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
115
583
9802b2afbce8 cp doesn't really need the optstring + logic. Still needs to be updated for new dirtree, though.
Rob Landley <rob@landley.net>
parents: 565
diff changeset
116 if (toys.optflags & (FLAG_p|FLAG_a)) {
435
e134aebe79c1 Silence really boring compiler warning.
Luis Felipe Strano Moraes <lfelipe@profusion.mobi>
parents: 329
diff changeset
117 int mask = umask(0);
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
118 struct utimbuf ut;
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
119
435
e134aebe79c1 Silence really boring compiler warning.
Luis Felipe Strano Moraes <lfelipe@profusion.mobi>
parents: 329
diff changeset
120 (void) fchown(fdout,srcst->st_uid, srcst->st_gid);
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
121 ut.actime = srcst->st_atime;
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
122 ut.modtime = srcst->st_mtime;
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
123 utime(dst, &ut);
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
124 umask(mask);
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
125 }
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
126 xclose(fdout);
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
127 }
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
128
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
129 // Callback from dirtree_read() for each file/directory under a source dir.
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
130
565
44abf4d901f3 Rewrite dirtree so we don't need readdir, scandir, and fts.h. Rewrite ls (from scratch) to use new dirtree infrastructure. (This breaks everything else that currently uses dirtree.)
Rob Landley <rob@landley.net>
parents: 528
diff changeset
131 int cp_node(struct dirtree *node)
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
132 {
565
44abf4d901f3 Rewrite dirtree so we don't need readdir, scandir, and fts.h. Rewrite ls (from scratch) to use new dirtree infrastructure. (This breaks everything else that currently uses dirtree.)
Rob Landley <rob@landley.net>
parents: 528
diff changeset
133 char *path = dirtree_path(node, 0); // TODO: use openat() instead
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
134 char *s = path+strlen(path);
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
135 struct dirtree *n;
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
136
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
137 // Find appropriate chunk of path for destination.
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
138
271
7d625cbdde25 Update cp -r to work better, add relevant tests to test suite.
Rob Landley <rob@landley.net>
parents: 269
diff changeset
139 n = node;
7d625cbdde25 Update cp -r to work better, add relevant tests to test suite.
Rob Landley <rob@landley.net>
parents: 269
diff changeset
140 if (!TT.destisdir) n = n->parent;
7d625cbdde25 Update cp -r to work better, add relevant tests to test suite.
Rob Landley <rob@landley.net>
parents: 269
diff changeset
141 for (;;n = n->parent) {
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
142 while (s!=path) {
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
143 if (*(--s)=='/') break;
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
144 }
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
145 if (!n) break;
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
146 }
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
147 if (s != path) s++;
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
148
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
149 s = xmsprintf("%s/%s", TT.destname, s);
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
150 cp_file(path, s, &(node->st));
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
151 free(s);
565
44abf4d901f3 Rewrite dirtree so we don't need readdir, scandir, and fts.h. Rewrite ls (from scratch) to use new dirtree infrastructure. (This breaks everything else that currently uses dirtree.)
Rob Landley <rob@landley.net>
parents: 528
diff changeset
152 free(path); // redo this whole darn function.
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
153
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
154 return 0;
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
155 }
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
156
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
157 void cp_main(void)
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
158 {
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
159 struct stat st;
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
160 int i;
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
161
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
162 // Grab target argument. (Guaranteed to be there due to "<2" above.)
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
163
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
164 TT.destname = toys.optargs[--toys.optc];
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
165
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
166 // If destination doesn't exist, are we ok with that?
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
167
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
168 if (stat(TT.destname, &st)) {
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
169 if (toys.optc>1) goto error_notdir;
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
170 TT.destisnew++;
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
171
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
172 // If destination exists...
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
173
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
174 } else {
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
175 if (S_ISDIR(st.st_mode)) TT.destisdir++;
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
176 else if (toys.optc > 1) goto error_notdir;
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
177 }
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
178
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
179 // Handle sources
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
180
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
181 for (i=0; i<toys.optc; i++) {
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
182 char *src = toys.optargs[i];
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
183 char *dst;
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
184
528
878b94b32866 Comment and whitespace tweaks.
Rob Landley <rob@landley.net>
parents: 503
diff changeset
185 // Skip src==dest (TODO check inodes to catch "cp blah ./blah").
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
186
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
187 if (!strcmp(src, TT.destname)) continue;
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
188
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
189 // Skip nonexistent sources.
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
190
583
9802b2afbce8 cp doesn't really need the optstring + logic. Still needs to be updated for new dirtree, though.
Rob Landley <rob@landley.net>
parents: 565
diff changeset
191 TT.keep_symlinks = toys.optflags & (FLAG_d|FLAG_a);
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
192 if (TT.keep_symlinks ? lstat(src, &st) : stat(src, &st))
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
193 {
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
194 perror_msg("'%s'", src);
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
195 toys.exitval = 1;
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
196 continue;
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
197 }
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
198
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
199 // Copy directory or file.
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
200
271
7d625cbdde25 Update cp -r to work better, add relevant tests to test suite.
Rob Landley <rob@landley.net>
parents: 269
diff changeset
201 if (TT.destisdir) {
7d625cbdde25 Update cp -r to work better, add relevant tests to test suite.
Rob Landley <rob@landley.net>
parents: 269
diff changeset
202 dst = strrchr(src, '/');
7d625cbdde25 Update cp -r to work better, add relevant tests to test suite.
Rob Landley <rob@landley.net>
parents: 269
diff changeset
203 if (dst) dst++;
7d625cbdde25 Update cp -r to work better, add relevant tests to test suite.
Rob Landley <rob@landley.net>
parents: 269
diff changeset
204 else dst=src;
7d625cbdde25 Update cp -r to work better, add relevant tests to test suite.
Rob Landley <rob@landley.net>
parents: 269
diff changeset
205 dst = xmsprintf("%s/%s", TT.destname, dst);
7d625cbdde25 Update cp -r to work better, add relevant tests to test suite.
Rob Landley <rob@landley.net>
parents: 269
diff changeset
206 } else dst = TT.destname;
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
207 if (S_ISDIR(st.st_mode)) {
583
9802b2afbce8 cp doesn't really need the optstring + logic. Still needs to be updated for new dirtree, though.
Rob Landley <rob@landley.net>
parents: 565
diff changeset
208 if (toys.optflags & (FLAG_r|FLAG_R|FLAG_a)) {
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
209 cp_file(src, dst, &st);
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
210
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
211 TT.keep_symlinks++;
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
212 strncpy(toybuf, src, sizeof(toybuf)-1);
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
213 toybuf[sizeof(toybuf)-1]=0;
565
44abf4d901f3 Rewrite dirtree so we don't need readdir, scandir, and fts.h. Rewrite ls (from scratch) to use new dirtree infrastructure. (This breaks everything else that currently uses dirtree.)
Rob Landley <rob@landley.net>
parents: 528
diff changeset
214 dirtree_read(toybuf, cp_node);
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
215 } else error_msg("Skipped dir '%s'", src);
269
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
216 } else cp_file(src, dst, &st);
7b3d9594bf9c Fix -r logic, it needs both source and dest paths explicitly stated.
Rob Landley <rob@landley.net>
parents: 267
diff changeset
217 if (TT.destisdir) free(dst);
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
218 }
263
7c53152a483b Make cp pass most of its test suite. Still need to add symlink support.
Rob Landley <rob@landley.net>
parents: 262
diff changeset
219
262
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
220 return;
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
221
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
222 error_notdir:
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
223 error_exit("'%s' isn't a directory", TT.destname);
70f36d9c5387 Add first pass at cp, totally untested, unlikely to work yet. :)
Rob Landley <rob@landley.net>
parents:
diff changeset
224 }