1 /*
2 * Copyright (c) 2010, Frank Lahm <franklahm@googlemail.com>
3 * Copyright (c) 1988, 1993, 1994
4 * The Regents of the University of California. All rights reserved.
5 *
6 * This code is derived from software contributed to Berkeley by
7 * David Hitz of Auspex Systems Inc.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
11 * are met:
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 /*
35 * Cp copies source files to target files.
36 *
37 * The global PATH_T structure "to" always contains the path to the
38 * current target file. Since fts(3) does not change directories,
39 * this path can be either absolute or dot-relative.
40 *
41 * The basic algorithm is to initialize "to" and use fts(3) to traverse
42 * the file hierarchy rooted in the argument list. A trivial case is the
43 * case of 'cp file1 file2'. The more interesting case is the case of
44 * 'cp file1 file2 ... fileN dir' where the hierarchy is traversed and the
45 * path (relative to the root of the traversal) is appended to dir (stored
46 * in "to") to form the final target path.
47 */
48
49 #ifdef HAVE_CONFIG_H
50 #include "config.h"
51 #endif /* HAVE_CONFIG_H */
52
53 #include <sys/types.h>
54 #include <sys/stat.h>
55 #include <errno.h>
56 #include <limits.h>
57 #include <signal.h>
58 #include <stdio.h>
59 #include <stdlib.h>
60 #include <string.h>
61 #include <unistd.h>
62 #include <libgen.h>
63
64 #include <atalk/ftw.h>
65 #include <atalk/adouble.h>
66 #include <atalk/vfs.h>
67 #include <atalk/util.h>
68 #include <atalk/unix.h>
69 #include <atalk/volume.h>
70 #include <atalk/bstrlib.h>
71 #include <atalk/bstradd.h>
72 #include <atalk/queue.h>
73
74 #include "ad.h"
75
76 #define STRIP_TRAILING_SLASH(p) { \
77 while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/') \
78 *--(p).p_end = 0; \
79 }
80
81 static char emptystring[] = "";
82
83 PATH_T to = { to.p_path, emptystring, "" };
84 enum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE };
85
86 int fflag, iflag, nflag, pflag, vflag;
87 mode_t mask;
88
89 cnid_t ppdid, pdid, did; /* current dir CNID and parent did*/
90
91 static afpvol_t svolume, dvolume;
92 static enum op type;
93 static int Rflag;
94 static volatile sig_atomic_t alarmed;
95 static int badcp, rval;
96 static int ftw_options = FTW_MOUNT | FTW_PHYS | FTW_ACTIONRETVAL;
97
98 /* Forward declarations */
99 static int copy(const char *fpath, const struct stat *sb, int tflag, struct FTW *ftwbuf);
100 static int ftw_copy_file(const struct FTW *, const char *, const struct stat *, int);
101 static int ftw_copy_link(const struct FTW *, const char *, const struct stat *, int);
102 static int setfile(const struct stat *, int);
103 // static int preserve_dir_acls(const struct stat *, char *, char *);
104 static int preserve_fd_acls(int, int);
105
upfunc(void)106 static void upfunc(void)
107 {
108 did = pdid;
109 pdid = ppdid;
110 }
111
112 /*
113 SIGNAL handling:
114 catch SIGINT and SIGTERM which cause clean exit. Ignore anything else.
115 */
116
sig_handler(int signo)117 static void sig_handler(int signo)
118 {
119 alarmed = 1;
120 return;
121 }
122
set_signal(void)123 static void set_signal(void)
124 {
125 struct sigaction sv;
126
127 sv.sa_handler = sig_handler;
128 sv.sa_flags = SA_RESTART;
129 sigemptyset(&sv.sa_mask);
130 if (sigaction(SIGTERM, &sv, NULL) < 0)
131 ERROR("error in sigaction(SIGTERM): %s", strerror(errno));
132
133 if (sigaction(SIGINT, &sv, NULL) < 0)
134 ERROR("error in sigaction(SIGINT): %s", strerror(errno));
135
136 memset(&sv, 0, sizeof(struct sigaction));
137 sv.sa_handler = SIG_IGN;
138 sigemptyset(&sv.sa_mask);
139
140 if (sigaction(SIGABRT, &sv, NULL) < 0)
141 ERROR("error in sigaction(SIGABRT): %s", strerror(errno));
142
143 if (sigaction(SIGHUP, &sv, NULL) < 0)
144 ERROR("error in sigaction(SIGHUP): %s", strerror(errno));
145
146 if (sigaction(SIGQUIT, &sv, NULL) < 0)
147 ERROR("error in sigaction(SIGQUIT): %s", strerror(errno));
148 }
149
usage_cp(void)150 static void usage_cp(void)
151 {
152 printf(
153 "Usage: ad cp [-R] [-aipvf] <source_file> <target_file>\n"
154 " ad cp [-R] [-aipvfx] <source_file [source_file ...]> <target_directory>\n\n"
155 "In the first synopsis form, the cp utility copies the contents of the source_file to the\n"
156 "target_file. In the second synopsis form, the contents of each named source_file is copied to the\n"
157 "destination target_directory. The names of the files themselves are not changed. If cp detects an\n"
158 "attempt to copy a file to itself, the copy will fail.\n\n"
159 "Netatalk AFP volumes are detected by means of their \".AppleDesktop\" directory\n"
160 "which is located in their volume root. When a copy targetting an AFP volume\n"
161 "is detected, its CNID database daemon is connected and all copies will also\n"
162 "go through the CNID database.\n"
163 "AppleDouble files are also copied and created as needed when the target is\n"
164 "an AFP volume.\n\n"
165 "The following options are available:\n\n"
166 " -a Archive mode. Same as -Rp.\n\n"
167 " -f For each existing destination pathname, remove it and create a new\n"
168 " file, without prompting for confirmation regardless of its permis-\n"
169 " sions. (The -f option overrides any previous -i or -n options.)\n\n"
170 " -i Cause cp to write a prompt to the standard error output before\n"
171 " copying a file that would overwrite an existing file. If the\n"
172 " response from the standard input begins with the character 'y' or\n"
173 " 'Y', the file copy is attempted. (The -i option overrides any pre-\n"
174 " vious -f or -n options.)\n\n"
175 " -n Do not overwrite an existing file. (The -n option overrides any\n"
176 " previous -f or -i options.)\n\n"
177 " -p Cause cp to preserve the following attributes of each source file\n"
178 " in the copy: modification time, access time, file flags, file mode,\n"
179 " user ID, and group ID, as allowed by permissions.\n"
180 " If the user ID and group ID cannot be preserved, no error message\n"
181 " is displayed and the exit value is not altered.\n\n"
182 " -R If source_file designates a directory, cp copies the directory and\n"
183 " the entire subtree connected at that point.If the source_file\n"
184 " ends in a /, the contents of the directory are copied rather than\n"
185 " the directory itself.\n\n"
186 " -v Cause cp to be verbose, showing files as they are copied.\n\n"
187 " -x File system mount points are not traversed.\n\n"
188 );
189 exit(EXIT_FAILURE);
190 }
191
ad_cp(int argc,char * argv[],AFPObj * obj)192 int ad_cp(int argc, char *argv[], AFPObj *obj)
193 {
194 struct stat to_stat, tmp_stat;
195 int r, ch, have_trailing_slash;
196 char *target;
197 #if 0
198 afpvol_t srcvol;
199 afpvol_t dstvol;
200 #endif
201
202 ppdid = pdid = htonl(1);
203 did = htonl(2);
204
205 while ((ch = getopt(argc, argv, "afinpRvx")) != -1)
206 switch (ch) {
207 case 'a':
208 pflag = 1;
209 Rflag = 1;
210 break;
211 case 'f':
212 fflag = 1;
213 iflag = nflag = 0;
214 break;
215 case 'i':
216 iflag = 1;
217 fflag = nflag = 0;
218 break;
219 case 'n':
220 nflag = 1;
221 fflag = iflag = 0;
222 break;
223 case 'p':
224 pflag = 1;
225 break;
226 case 'R':
227 Rflag = 1;
228 break;
229 case 'v':
230 vflag = 1;
231 break;
232 case 'x':
233 ftw_options |= FTW_MOUNT;
234 break;
235 default:
236 usage_cp();
237 break;
238 }
239 argc -= optind;
240 argv += optind;
241
242 if (argc < 2)
243 usage_cp();
244
245 set_signal();
246 cnid_init();
247
248 /* Save the target base in "to". */
249 target = argv[--argc];
250 if ((strlcpy(to.p_path, target, PATH_MAX)) >= PATH_MAX)
251 ERROR("%s: name too long", target);
252
253 to.p_end = to.p_path + strlen(to.p_path);
254 if (to.p_path == to.p_end) {
255 *to.p_end++ = '.';
256 *to.p_end = 0;
257 }
258 have_trailing_slash = (to.p_end[-1] == '/');
259 if (have_trailing_slash)
260 STRIP_TRAILING_SLASH(to);
261 to.target_end = to.p_end;
262
263 /* Set end of argument list */
264 argv[argc] = NULL;
265
266 /*
267 * Cp has two distinct cases:
268 *
269 * cp [-R] source target
270 * cp [-R] source1 ... sourceN directory
271 *
272 * In both cases, source can be either a file or a directory.
273 *
274 * In (1), the target becomes a copy of the source. That is, if the
275 * source is a file, the target will be a file, and likewise for
276 * directories.
277 *
278 * In (2), the real target is not directory, but "directory/source".
279 */
280 r = stat(to.p_path, &to_stat);
281 if (r == -1 && errno != ENOENT)
282 ERROR("%s", to.p_path);
283 if (r == -1 || !S_ISDIR(to_stat.st_mode)) {
284 /*
285 * Case (1). Target is not a directory.
286 */
287 if (argc > 1)
288 ERROR("%s is not a directory", to.p_path);
289
290 /*
291 * Need to detect the case:
292 *cp -R dir foo
293 * Where dir is a directory and foo does not exist, where
294 * we want pathname concatenations turned on but not for
295 * the initial mkdir().
296 */
297 if (r == -1) {
298 lstat(*argv, &tmp_stat);
299
300 if (S_ISDIR(tmp_stat.st_mode) && Rflag)
301 type = DIR_TO_DNE;
302 else
303 type = FILE_TO_FILE;
304 } else
305 type = FILE_TO_FILE;
306
307 if (have_trailing_slash && type == FILE_TO_FILE) {
308 if (r == -1)
309 ERROR("directory %s does not exist", to.p_path);
310 else
311 ERROR("%s is not a directory", to.p_path);
312 }
313 } else
314 /*
315 * Case (2). Target is a directory.
316 */
317 type = FILE_TO_DIR;
318
319 /*
320 * Keep an inverted copy of the umask, for use in correcting
321 * permissions on created directories when not using -p.
322 */
323 mask = ~umask(0777);
324 umask(~mask);
325
326 #if 0
327 /* Inhereting perms in ad_mkdir etc requires this */
328 ad_setfuid(0);
329 #endif
330
331 /* Load .volinfo file for destination*/
332 openvol(obj, to.p_path, &dvolume);
333
334 for (int i = 0; argv[i] != NULL; i++) {
335 /* Load .volinfo file for source */
336 openvol(obj, argv[i], &svolume);
337
338 if (nftw(argv[i], copy, upfunc, 20, ftw_options) == -1) {
339 if (alarmed) {
340 SLOG("...break");
341 } else {
342 SLOG("Error: %s: %s", argv[i], strerror(errno));
343 }
344 closevol(&svolume);
345 closevol(&dvolume);
346 }
347 }
348 return rval;
349 }
350
copy(const char * path,const struct stat * statp,int tflag,struct FTW * ftw)351 static int copy(const char *path,
352 const struct stat *statp,
353 int tflag,
354 struct FTW *ftw)
355 {
356 static int base = 0;
357
358 struct stat to_stat;
359 int dne;
360 size_t nlen;
361 const char *p;
362 char *target_mid;
363
364 if (alarmed)
365 return -1;
366
367 /* This currently doesn't work with "." */
368 if (strcmp(path, ".") == 0) {
369 ERROR("\".\" not supported");
370 }
371 const char *dir = strrchr(path, '/');
372 if (dir == NULL)
373 dir = path;
374 else
375 dir++;
376 if (!dvolume.vol->vfs->vfs_validupath(dvolume.vol, dir))
377 return FTW_SKIP_SUBTREE;
378
379 /*
380 * If we are in case (2) above, we need to append the
381 * source name to the target name.
382 */
383 if (type != FILE_TO_FILE) {
384 /*
385 * Need to remember the roots of traversals to create
386 * correct pathnames. If there's a directory being
387 * copied to a non-existent directory, e.g.
388 * cp -R a/dir noexist
389 * the resulting path name should be noexist/foo, not
390 * noexist/dir/foo (where foo is a file in dir), which
391 * is the case where the target exists.
392 *
393 * Also, check for "..". This is for correct path
394 * concatenation for paths ending in "..", e.g.
395 * cp -R .. /tmp
396 * Paths ending in ".." are changed to ".". This is
397 * tricky, but seems the easiest way to fix the problem.
398 *
399 * XXX
400 * Since the first level MUST be FTS_ROOTLEVEL, base
401 * is always initialized.
402 */
403 if (ftw->level == 0) {
404 if (type != DIR_TO_DNE) {
405 base = ftw->base;
406
407 if (strcmp(&path[base], "..") == 0)
408 base += 1;
409 } else
410 base = strlen(path);
411 }
412
413 p = &path[base];
414 nlen = strlen(path) - base;
415 target_mid = to.target_end;
416 if (*p != '/' && target_mid[-1] != '/')
417 *target_mid++ = '/';
418 *target_mid = 0;
419 if (target_mid - to.p_path + nlen >= PATH_MAX) {
420 SLOG("%s%s: name too long (not copied)", to.p_path, p);
421 badcp = rval = 1;
422 return 0;
423 }
424 (void)strncat(target_mid, p, nlen);
425 to.p_end = target_mid + nlen;
426 *to.p_end = 0;
427 STRIP_TRAILING_SLASH(to);
428 }
429
430 /* Not an error but need to remember it happened */
431 if (stat(to.p_path, &to_stat) == -1)
432 dne = 1;
433 else {
434 if (to_stat.st_dev == statp->st_dev &&
435 to_stat.st_ino == statp->st_ino) {
436 SLOG("%s and %s are identical (not copied).", to.p_path, path);
437 badcp = rval = 1;
438 if (S_ISDIR(statp->st_mode))
439 /* without using glibc extension FTW_ACTIONRETVAL cant handle this */
440 return FTW_SKIP_SUBTREE;
441 return 0;
442 }
443 if (!S_ISDIR(statp->st_mode) &&
444 S_ISDIR(to_stat.st_mode)) {
445 SLOG("cannot overwrite directory %s with "
446 "non-directory %s",
447 to.p_path, path);
448 badcp = rval = 1;
449 return 0;
450 }
451 dne = 0;
452 }
453
454 /* Convert basename to appropriate volume encoding */
455 if (dvolume.vol->v_path) {
456 if ((convert_dots_encoding(&svolume, &dvolume, to.p_path, MAXPATHLEN)) == -1) {
457 SLOG("Error converting name for %s", to.p_path);
458 badcp = rval = 1;
459 return -1;
460 }
461 }
462
463 switch (statp->st_mode & S_IFMT) {
464 case S_IFLNK:
465 if (ftw_copy_link(ftw, path, statp, !dne))
466 badcp = rval = 1;
467 break;
468 case S_IFDIR:
469 if (!Rflag) {
470 SLOG("%s is a directory", path);
471 badcp = rval = 1;
472 return -1;
473 }
474 /*
475 * If the directory doesn't exist, create the new
476 * one with the from file mode plus owner RWX bits,
477 * modified by the umask. Trade-off between being
478 * able to write the directory (if from directory is
479 * 555) and not causing a permissions race. If the
480 * umask blocks owner writes, we fail..
481 */
482 if (dne) {
483 if (mkdir(to.p_path, statp->st_mode | S_IRWXU) < 0)
484 ERROR("mkdir: %s: %s", to.p_path, strerror(errno));
485 } else if (!S_ISDIR(to_stat.st_mode)) {
486 errno = ENOTDIR;
487 ERROR("%s", to.p_path);
488 }
489
490 /* Create ad dir and copy ".Parent" */
491 if (dvolume.vol->v_path && ADVOL_V2_OR_EA(dvolume.vol->v_adouble)) {
492 mode_t omask = umask(0);
493 if (dvolume.vol->v_adouble == AD_VERSION2) {
494 /* Create ".AppleDouble" dir */
495 bstring addir = bfromcstr(to.p_path);
496 bcatcstr(addir, "/.AppleDouble");
497 mkdir(cfrombstr(addir), 02777);
498 bdestroy(addir);
499 }
500
501 if (svolume.vol->v_path && ADVOL_V2_OR_EA(svolume.vol->v_adouble)) {
502 /* copy metadata file */
503 if (dvolume.vol->vfs->vfs_copyfile(dvolume.vol, -1, path, to.p_path)) {
504 SLOG("Error copying adouble for %s -> %s", path, to.p_path);
505 badcp = rval = 1;
506 break;
507 }
508 }
509
510 /* Get CNID of Parent and add new childir to CNID database */
511 ppdid = pdid;
512 if ((did = cnid_for_path(dvolume.vol->v_cdb, dvolume.vol->v_path, to.p_path, &pdid)) == CNID_INVALID) {
513 SLOG("Error resolving CNID for %s", to.p_path);
514 badcp = rval = 1;
515 return -1;
516 }
517
518 struct adouble ad;
519 struct stat st;
520 if (lstat(to.p_path, &st) != 0) {
521 badcp = rval = 1;
522 break;
523 }
524 ad_init(&ad, dvolume.vol);
525 if (ad_open(&ad, to.p_path, ADFLAGS_HF | ADFLAGS_DIR | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) != 0) {
526 ERROR("Error opening adouble for: %s", to.p_path);
527 }
528 ad_setid( &ad, st.st_dev, st.st_ino, did, pdid, dvolume.db_stamp);
529 if (dvolume.vol->v_adouble == AD_VERSION2)
530 ad_setname(&ad, utompath(dvolume.vol, basename(to.p_path)));
531 ad_setdate(&ad, AD_DATE_CREATE | AD_DATE_UNIX, st.st_mtime);
532 ad_setdate(&ad, AD_DATE_MODIFY | AD_DATE_UNIX, st.st_mtime);
533 ad_setdate(&ad, AD_DATE_ACCESS | AD_DATE_UNIX, st.st_mtime);
534 ad_setdate(&ad, AD_DATE_BACKUP, AD_DATE_START);
535 ad_flush(&ad);
536 ad_close(&ad, ADFLAGS_HF);
537
538 umask(omask);
539 }
540
541 if (pflag) {
542 if (setfile(statp, -1))
543 rval = 1;
544 #if 0
545 if (preserve_dir_acls(statp, curr->fts_accpath, to.p_path) != 0)
546 rval = 1;
547 #endif
548 }
549 break;
550
551 case S_IFBLK:
552 case S_IFCHR:
553 SLOG("%s is a device file (not copied).", path);
554 break;
555 case S_IFSOCK:
556 SLOG("%s is a socket (not copied).", path);
557 break;
558 case S_IFIFO:
559 SLOG("%s is a FIFO (not copied).", path);
560 break;
561 default:
562 if (ftw_copy_file(ftw, path, statp, dne))
563 badcp = rval = 1;
564
565 if (dvolume.vol->v_path && ADVOL_V2_OR_EA(dvolume.vol->v_adouble)) {
566
567 mode_t omask = umask(0);
568 if (svolume.vol->v_path && ADVOL_V2_OR_EA(svolume.vol->v_adouble)) {
569 /* copy ad-file */
570 if (dvolume.vol->vfs->vfs_copyfile(dvolume.vol, -1, path, to.p_path)) {
571 SLOG("Error copying adouble for %s -> %s", path, to.p_path);
572 badcp = rval = 1;
573 break;
574 }
575 }
576
577 /* Get CNID of Parent and add new childir to CNID database */
578 pdid = did;
579 cnid_t cnid;
580 if ((cnid = cnid_for_path(dvolume.vol->v_cdb, dvolume.vol->v_path, to.p_path, &did)) == CNID_INVALID) {
581 SLOG("Error resolving CNID for %s", to.p_path);
582 badcp = rval = 1;
583 return -1;
584 }
585
586 struct adouble ad;
587 struct stat st;
588 if (lstat(to.p_path, &st) != 0) {
589 badcp = rval = 1;
590 break;
591 }
592 ad_init(&ad, dvolume.vol);
593 if (ad_open(&ad, to.p_path, ADFLAGS_HF | ADFLAGS_RDWR | ADFLAGS_CREATE, 0666) != 0) {
594 ERROR("Error opening adouble for: %s", to.p_path);
595 }
596 ad_setid( &ad, st.st_dev, st.st_ino, cnid, did, dvolume.db_stamp);
597 if (dvolume.vol->v_adouble == AD_VERSION2)
598 ad_setname(&ad, utompath(dvolume.vol, basename(to.p_path)));
599 ad_setdate(&ad, AD_DATE_CREATE | AD_DATE_UNIX, st.st_mtime);
600 ad_setdate(&ad, AD_DATE_MODIFY | AD_DATE_UNIX, st.st_mtime);
601 ad_setdate(&ad, AD_DATE_ACCESS | AD_DATE_UNIX, st.st_mtime);
602 ad_setdate(&ad, AD_DATE_BACKUP, AD_DATE_START);
603 ad_flush(&ad);
604 ad_close(&ad, ADFLAGS_HF);
605 umask(omask);
606 }
607 break;
608 }
609 if (vflag && !badcp)
610 (void)printf("%s -> %s\n", path, to.p_path);
611
612 return 0;
613 }
614
615 /* Memory strategy threshold, in pages: if physmem is larger then this, use a large buffer */
616 #define PHYSPAGES_THRESHOLD (32*1024)
617
618 /* Maximum buffer size in bytes - do not allow it to grow larger than this */
619 #define BUFSIZE_MAX (2*1024*1024)
620
621 /* Small (default) buffer size in bytes. It's inefficient for this to be smaller than MAXPHYS */
622 #define MAXPHYS (64 * 1024)
623 #define BUFSIZE_SMALL (MAXPHYS)
624
ftw_copy_file(const struct FTW * entp,const char * spath,const struct stat * sp,int dne)625 static int ftw_copy_file(const struct FTW *entp,
626 const char *spath,
627 const struct stat *sp,
628 int dne)
629 {
630 static char *buf = NULL;
631 static size_t bufsize;
632 ssize_t wcount;
633 size_t wresid;
634 off_t wtotal;
635 int ch, checkch, from_fd = 0, rcount, rval, to_fd = 0;
636 char *bufp;
637 char *p;
638
639 if ((from_fd = open(spath, O_RDONLY, 0)) == -1) {
640 SLOG("%s: %s", spath, strerror(errno));
641 return (1);
642 }
643
644 /*
645 * If the file exists and we're interactive, verify with the user.
646 * If the file DNE, set the mode to be the from file, minus setuid
647 * bits, modified by the umask; arguably wrong, but it makes copying
648 * executables work right and it's been that way forever. (The
649 * other choice is 666 or'ed with the execute bits on the from file
650 * modified by the umask.)
651 */
652 if (!dne) {
653 #define YESNO "(y/n [n]) "
654 if (nflag) {
655 if (vflag)
656 printf("%s not overwritten\n", to.p_path);
657 (void)close(from_fd);
658 return (0);
659 } else if (iflag) {
660 (void)fprintf(stderr, "overwrite %s? %s",
661 to.p_path, YESNO);
662 checkch = ch = getchar();
663 while (ch != '\n' && ch != EOF)
664 ch = getchar();
665 if (checkch != 'y' && checkch != 'Y') {
666 (void)close(from_fd);
667 (void)fprintf(stderr, "not overwritten\n");
668 return (1);
669 }
670 }
671
672 if (fflag) {
673 /* remove existing destination file name,
674 * create a new file */
675 (void)unlink(to.p_path);
676 (void)dvolume.vol->vfs->vfs_deletefile(dvolume.vol, -1, to.p_path);
677 to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
678 sp->st_mode & ~(S_ISUID | S_ISGID));
679 } else {
680 /* overwrite existing destination file name */
681 to_fd = open(to.p_path, O_WRONLY | O_TRUNC, 0);
682 }
683 } else {
684 to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT,
685 sp->st_mode & ~(S_ISUID | S_ISGID));
686 }
687
688 if (to_fd == -1) {
689 SLOG("%s: %s", to.p_path, strerror(errno));
690 (void)close(from_fd);
691 return (1);
692 }
693
694 rval = 0;
695
696 /*
697 * Mmap and write if less than 8M (the limit is so we don't totally
698 * trash memory on big files. This is really a minor hack, but it
699 * wins some CPU back.
700 * Some filesystems, such as smbnetfs, don't support mmap,
701 * so this is a best-effort attempt.
702 */
703
704 if (S_ISREG(sp->st_mode) && sp->st_size > 0 &&
705 sp->st_size <= 8 * 1024 * 1024 &&
706 (p = mmap(NULL, (size_t)sp->st_size, PROT_READ,
707 MAP_SHARED, from_fd, (off_t)0)) != MAP_FAILED) {
708 wtotal = 0;
709 for (bufp = p, wresid = sp->st_size; ;
710 bufp += wcount, wresid -= (size_t)wcount) {
711 wcount = write(to_fd, bufp, wresid);
712 if (wcount <= 0)
713 break;
714 wtotal += wcount;
715 if (wcount >= (ssize_t)wresid)
716 break;
717 }
718 if (wcount != (ssize_t)wresid) {
719 SLOG("%s: %s", to.p_path, strerror(errno));
720 rval = 1;
721 }
722 /* Some systems don't unmap on close(2). */
723 if (munmap(p, sp->st_size) < 0) {
724 SLOG("%s: %s", spath, strerror(errno));
725 rval = 1;
726 }
727 } else {
728 if (buf == NULL) {
729 /*
730 * Note that buf and bufsize are static. If
731 * malloc() fails, it will fail at the start
732 * and not copy only some files.
733 */
734 if (sysconf(_SC_PHYS_PAGES) >
735 PHYSPAGES_THRESHOLD)
736 bufsize = MIN(BUFSIZE_MAX, MAXPHYS * 8);
737 else
738 bufsize = BUFSIZE_SMALL;
739 buf = malloc(bufsize);
740 if (buf == NULL)
741 ERROR("Not enough memory");
742
743 }
744 wtotal = 0;
745 while ((rcount = read(from_fd, buf, bufsize)) > 0) {
746 for (bufp = buf, wresid = rcount; ;
747 bufp += wcount, wresid -= wcount) {
748 wcount = write(to_fd, bufp, wresid);
749 if (wcount <= 0)
750 break;
751 wtotal += wcount;
752 if (wcount >= (ssize_t)wresid)
753 break;
754 }
755 if (wcount != (ssize_t)wresid) {
756 SLOG("%s: %s", to.p_path, strerror(errno));
757 rval = 1;
758 break;
759 }
760 }
761 if (rcount < 0) {
762 SLOG("%s: %s", spath, strerror(errno));
763 rval = 1;
764 }
765 }
766
767 /*
768 * Don't remove the target even after an error. The target might
769 * not be a regular file, or its attributes might be important,
770 * or its contents might be irreplaceable. It would only be safe
771 * to remove it if we created it and its length is 0.
772 */
773
774 if (pflag && setfile(sp, to_fd))
775 rval = 1;
776 if (pflag && preserve_fd_acls(from_fd, to_fd) != 0)
777 rval = 1;
778 if (close(to_fd)) {
779 SLOG("%s: %s", to.p_path, strerror(errno));
780 rval = 1;
781 }
782
783 (void)close(from_fd);
784
785 return (rval);
786 }
787
ftw_copy_link(const struct FTW * p,const char * spath,const struct stat * sstp,int exists)788 static int ftw_copy_link(const struct FTW *p,
789 const char *spath,
790 const struct stat *sstp,
791 int exists)
792 {
793 int len;
794 char llink[PATH_MAX];
795
796 if ((len = readlink(spath, llink, sizeof(llink) - 1)) == -1) {
797 SLOG("readlink: %s: %s", spath, strerror(errno));
798 return (1);
799 }
800 llink[len] = '\0';
801 if (exists && unlink(to.p_path)) {
802 SLOG("unlink: %s: %s", to.p_path, strerror(errno));
803 return (1);
804 }
805 if (symlink(llink, to.p_path)) {
806 SLOG("symlink: %s: %s", llink, strerror(errno));
807 return (1);
808 }
809 return (pflag ? setfile(sstp, -1) : 0);
810 }
811
setfile(const struct stat * fs,int fd)812 static int setfile(const struct stat *fs, int fd)
813 {
814 static struct timeval tv[2];
815 struct stat ts;
816 int rval, gotstat, islink, fdval;
817 mode_t mode;
818
819 rval = 0;
820 fdval = fd != -1;
821 islink = !fdval && S_ISLNK(fs->st_mode);
822 mode = fs->st_mode & (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO);
823
824 #if defined(__FreeBSD__) || defined(__DragonFly__)
825 TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec);
826 TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
827 #else
828 TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atim);
829 TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtim);
830 #endif
831
832 if (utimes(to.p_path, tv)) {
833 SLOG("utimes: %s", to.p_path);
834 rval = 1;
835 }
836 if (fdval ? fstat(fd, &ts) :
837 (islink ? lstat(to.p_path, &ts) : stat(to.p_path, &ts)))
838 gotstat = 0;
839 else {
840 gotstat = 1;
841 ts.st_mode &= S_ISUID | S_ISGID | S_ISVTX |
842 S_IRWXU | S_IRWXG | S_IRWXO;
843 }
844 /*
845 * Changing the ownership probably won't succeed, unless we're root
846 * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting
847 * the mode; current BSD behavior is to remove all setuid bits on
848 * chown. If chown fails, lose setuid/setgid bits.
849 */
850 if (!gotstat || fs->st_uid != ts.st_uid || fs->st_gid != ts.st_gid)
851 if (fdval ? fchown(fd, fs->st_uid, fs->st_gid) :
852 (islink ? lchown(to.p_path, fs->st_uid, fs->st_gid) :
853 chown(to.p_path, fs->st_uid, fs->st_gid))) {
854 if (errno != EPERM) {
855 SLOG("chown: %s: %s", to.p_path, strerror(errno));
856 rval = 1;
857 }
858 mode &= ~(S_ISUID | S_ISGID);
859 }
860
861 if (!gotstat || mode != ts.st_mode)
862 if (fdval ? fchmod(fd, mode) : chmod(to.p_path, mode)) {
863 SLOG("chmod: %s: %s", to.p_path, strerror(errno));
864 rval = 1;
865 }
866
867 #ifdef HAVE_ST_FLAGS
868 if (!gotstat || fs->st_flags != ts.st_flags)
869 if (fdval ?
870 fchflags(fd, fs->st_flags) :
871 (islink ? lchflags(to.p_path, fs->st_flags) :
872 chflags(to.p_path, fs->st_flags))) {
873 SLOG("chflags: %s: %s", to.p_path, strerror(errno));
874 rval = 1;
875 }
876 #endif
877
878 return (rval);
879 }
880
preserve_fd_acls(int source_fd,int dest_fd)881 static int preserve_fd_acls(int source_fd, int dest_fd)
882 {
883 #if 0
884 acl_t acl;
885 acl_type_t acl_type;
886 int acl_supported = 0, ret, trivial;
887
888 ret = fpathconf(source_fd, _PC_ACL_NFS4);
889 if (ret > 0 ) {
890 acl_supported = 1;
891 acl_type = ACL_TYPE_NFS4;
892 } else if (ret < 0 && errno != EINVAL) {
893 warn("fpathconf(..., _PC_ACL_NFS4) failed for %s", to.p_path);
894 return (1);
895 }
896 if (acl_supported == 0) {
897 ret = fpathconf(source_fd, _PC_ACL_EXTENDED);
898 if (ret > 0 ) {
899 acl_supported = 1;
900 acl_type = ACL_TYPE_ACCESS;
901 } else if (ret < 0 && errno != EINVAL) {
902 warn("fpathconf(..., _PC_ACL_EXTENDED) failed for %s",
903 to.p_path);
904 return (1);
905 }
906 }
907 if (acl_supported == 0)
908 return (0);
909
910 acl = acl_get_fd_np(source_fd, acl_type);
911 if (acl == NULL) {
912 warn("failed to get acl entries while setting %s", to.p_path);
913 return (1);
914 }
915 if (acl_is_trivial_np(acl, &trivial)) {
916 warn("acl_is_trivial() failed for %s", to.p_path);
917 acl_free(acl);
918 return (1);
919 }
920 if (trivial) {
921 acl_free(acl);
922 return (0);
923 }
924 if (acl_set_fd_np(dest_fd, acl, acl_type) < 0) {
925 warn("failed to set acl entries for %s", to.p_path);
926 acl_free(acl);
927 return (1);
928 }
929 acl_free(acl);
930 #endif
931 return (0);
932 }
933
934 #if 0
935 static int preserve_dir_acls(const struct stat *fs, char *source_dir, char *dest_dir)
936 {
937 acl_t (*aclgetf)(const char *, acl_type_t);
938 int (*aclsetf)(const char *, acl_type_t, acl_t);
939 struct acl *aclp;
940 acl_t acl;
941 acl_type_t acl_type;
942 int acl_supported = 0, ret, trivial;
943
944 ret = pathconf(source_dir, _PC_ACL_NFS4);
945 if (ret > 0) {
946 acl_supported = 1;
947 acl_type = ACL_TYPE_NFS4;
948 } else if (ret < 0 && errno != EINVAL) {
949 warn("fpathconf(..., _PC_ACL_NFS4) failed for %s", source_dir);
950 return (1);
951 }
952 if (acl_supported == 0) {
953 ret = pathconf(source_dir, _PC_ACL_EXTENDED);
954 if (ret > 0) {
955 acl_supported = 1;
956 acl_type = ACL_TYPE_ACCESS;
957 } else if (ret < 0 && errno != EINVAL) {
958 warn("fpathconf(..., _PC_ACL_EXTENDED) failed for %s",
959 source_dir);
960 return (1);
961 }
962 }
963 if (acl_supported == 0)
964 return (0);
965
966 /*
967 * If the file is a link we will not follow it
968 */
969 if (S_ISLNK(fs->st_mode)) {
970 aclgetf = acl_get_link_np;
971 aclsetf = acl_set_link_np;
972 } else {
973 aclgetf = acl_get_file;
974 aclsetf = acl_set_file;
975 }
976 if (acl_type == ACL_TYPE_ACCESS) {
977 /*
978 * Even if there is no ACL_TYPE_DEFAULT entry here, a zero
979 * size ACL will be returned. So it is not safe to simply
980 * check the pointer to see if the default ACL is present.
981 */
982 acl = aclgetf(source_dir, ACL_TYPE_DEFAULT);
983 if (acl == NULL) {
984 warn("failed to get default acl entries on %s",
985 source_dir);
986 return (1);
987 }
988 aclp = &acl->ats_acl;
989 if (aclp->acl_cnt != 0 && aclsetf(dest_dir,
990 ACL_TYPE_DEFAULT, acl) < 0) {
991 warn("failed to set default acl entries on %s",
992 dest_dir);
993 acl_free(acl);
994 return (1);
995 }
996 acl_free(acl);
997 }
998 acl = aclgetf(source_dir, acl_type);
999 if (acl == NULL) {
1000 warn("failed to get acl entries on %s", source_dir);
1001 return (1);
1002 }
1003 if (acl_is_trivial_np(acl, &trivial)) {
1004 warn("acl_is_trivial() failed on %s", source_dir);
1005 acl_free(acl);
1006 return (1);
1007 }
1008 if (trivial) {
1009 acl_free(acl);
1010 return (0);
1011 }
1012 if (aclsetf(dest_dir, acl_type, acl) < 0) {
1013 warn("failed to set acl entries on %s", dest_dir);
1014 acl_free(acl);
1015 return (1);
1016 }
1017 acl_free(acl);
1018 return (0);
1019 }
1020 #endif
1021