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