cp.c revision 14145
197403Sobrien/* 297403Sobrien * Copyright (c) 1988, 1993, 1994 3132720Skan * The Regents of the University of California. All rights reserved. 497403Sobrien * 597403Sobrien * This code is derived from software contributed to Berkeley by 697403Sobrien * David Hitz of Auspex Systems Inc. 797403Sobrien * 897403Sobrien * Redistribution and use in source and binary forms, with or without 997403Sobrien * modification, are permitted provided that the following conditions 1097403Sobrien * are met: 1197403Sobrien * 1. Redistributions of source code must retain the above copyright 1297403Sobrien * notice, this list of conditions and the following disclaimer. 1397403Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1497403Sobrien * notice, this list of conditions and the following disclaimer in the 1597403Sobrien * documentation and/or other materials provided with the distribution. 1697403Sobrien * 3. All advertising materials mentioning features or use of this software 1797403Sobrien * must display the following acknowledgement: 1897403Sobrien * This product includes software developed by the University of 1997403Sobrien * California, Berkeley and its contributors. 2097403Sobrien * 4. Neither the name of the University nor the names of its contributors 2197403Sobrien * may be used to endorse or promote products derived from this software 2297403Sobrien * without specific prior written permission. 2397403Sobrien * 2497403Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2597403Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2697403Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2797403Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2897403Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2997403Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3097403Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3197403Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32132720Skan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3397403Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3497403Sobrien * SUCH DAMAGE. 3597403Sobrien * 3697403Sobrien * $Id: cp.c,v 1.6 1995/05/30 00:06:21 rgrimes Exp $ 3797403Sobrien */ 3897403Sobrien 3997403Sobrien#ifndef lint 40132720Skanstatic char copyright[] = 41132720Skan"@(#) Copyright (c) 1988, 1993, 1994\n\ 4297403Sobrien The Regents of the University of California. All rights reserved.\n"; 4397403Sobrien#endif /* not lint */ 4497403Sobrien 4597403Sobrien#ifndef lint 46117397Skanstatic char sccsid[] = "@(#)cp.c 8.2 (Berkeley) 4/1/94"; 47117397Skan#endif /* not lint */ 4897403Sobrien 4997403Sobrien/* 5097403Sobrien * Cp copies source files to target files. 5197403Sobrien * 5297403Sobrien * The global PATH_T structure "to" always contains the path to the 5397403Sobrien * current target file. Since fts(3) does not change directories, 5497403Sobrien * this path can be either absolute or dot-realative. 55132720Skan * 5697403Sobrien * The basic algorithm is to initialize "to" and use fts(3) to traverse 57132720Skan * the file hierarchy rooted in the argument list. A trivial case is the 5897403Sobrien * case of 'cp file1 file2'. The more interesting case is the case of 5997403Sobrien * 'cp file1 file2 ... fileN dir' where the hierarchy is traversed and the 6097403Sobrien * path (relative to the root of the traversal) is appended to dir (stored 61132720Skan * in "to") to form the final target path. 6297403Sobrien */ 6397403Sobrien 6497403Sobrien#include <sys/param.h> 65132720Skan#include <sys/stat.h> 6697403Sobrien#include <sys/mman.h> 6797403Sobrien#include <sys/time.h> 6897403Sobrien 69132720Skan#include <dirent.h> 7097403Sobrien#include <err.h> 7197403Sobrien#include <errno.h> 7297403Sobrien#include <fcntl.h> 73132720Skan#include <fts.h> 7497403Sobrien#include <stdio.h> 7597403Sobrien#include <stdlib.h> 7697403Sobrien#include <string.h> 77132720Skan#include <unistd.h> 7897403Sobrien 7997403Sobrien#include "extern.h" 8097403Sobrien 81132720Skan#define STRIP_TRAILING_SLASH(p) { \ 8297403Sobrien while ((p).p_end > (p).p_path + 1 && (p).p_end[-1] == '/') \ 8397403Sobrien *--(p).p_end = 0; \ 8497403Sobrien} 8597403Sobrien 86132720SkanPATH_T to = { to.p_path, "" }; 8797403Sobrien 88132720Skanuid_t myuid; 8997403Sobrienint Rflag, iflag, pflag, rflag, fflag; 9097403Sobrienint myumask; 9197403Sobrien 92132720Skanenum op { FILE_TO_FILE, FILE_TO_DIR, DIR_TO_DNE }; 9397403Sobrien 9497403Sobrienint copy __P((char *[], enum op, int)); 9597403Sobrienint mastercmp __P((const FTSENT **, const FTSENT **)); 96132720Skan 9797403Sobrienint 9897403Sobrienmain(argc, argv) 9997403Sobrien int argc; 100132720Skan char *argv[]; 10197403Sobrien{ 10297403Sobrien struct stat to_stat, tmp_stat; 10397403Sobrien enum op type; 104132720Skan int Hflag, Lflag, Pflag, ch, fts_options, r; 10597403Sobrien char *target; 10697403Sobrien 10797403Sobrien Hflag = Lflag = Pflag = Rflag = 0; 108132720Skan fflag = iflag = rflag = pflag = 0; 10997403Sobrien while ((ch = getopt(argc, argv, "HLPRfipr?")) != EOF) 11097403Sobrien switch (ch) { 11197403Sobrien case 'H': 112132720Skan Hflag = 1; 11397403Sobrien Lflag = Pflag = 0; 11497403Sobrien break; 11597403Sobrien case 'L': 11697403Sobrien Lflag = 1; 117132720Skan Hflag = Pflag = 0; 11897403Sobrien break; 119132720Skan case 'P': 12097403Sobrien Pflag = 1; 12197403Sobrien Hflag = Lflag = 0; 12297403Sobrien break; 123132720Skan case 'R': 12497403Sobrien Rflag = 1; 12597403Sobrien break; 12697403Sobrien case 'f': 127132720Skan iflag = 0; 12897403Sobrien fflag = 1; 12997403Sobrien break; 13097403Sobrien case 'i': 131132720Skan iflag = isatty(STDIN_FILENO); 13297403Sobrien fflag = 0; 13397403Sobrien break; 13497403Sobrien case 'p': 135132720Skan pflag = 1; 13697403Sobrien break; 13797403Sobrien case 'r': 13897403Sobrien rflag = 1; 139132720Skan break; 14097403Sobrien case '?': 14197403Sobrien default: 14297403Sobrien usage(); 143132720Skan break; 14497403Sobrien } 14597403Sobrien argc -= optind; 14697403Sobrien argv += optind; 147132720Skan 14897403Sobrien if (argc < 2) 14997403Sobrien usage(); 150117397Skan 151117397Skan fts_options = FTS_NOCHDIR | FTS_PHYSICAL; 152117397Skan if (rflag) { 153117397Skan if (Rflag) 154117397Skan errx(1, 155117397Skan "the -R and -r options may not be specified together."); 156117397Skan if (Hflag || Lflag || Pflag) 157117397Skan errx(1, 15897403Sobrien "the -H, -L, and -P options may not be specified with the -r option."); 15997403Sobrien fts_options &= ~FTS_PHYSICAL; 16097403Sobrien fts_options |= FTS_LOGICAL; 161132720Skan } 16297403Sobrien if (Rflag) { 163117397Skan if (Hflag) 16497403Sobrien fts_options |= FTS_COMFOLLOW; 16597403Sobrien if (Lflag) { 16697403Sobrien fts_options &= ~FTS_PHYSICAL; 167132720Skan fts_options |= FTS_LOGICAL; 168132720Skan } 169132720Skan } else { 17097403Sobrien fts_options &= ~FTS_PHYSICAL; 17197403Sobrien fts_options |= FTS_LOGICAL; 17297403Sobrien } 17397403Sobrien 174132720Skan myuid = getuid(); 17597403Sobrien 17697403Sobrien /* Copy the umask for explicit mode setting. */ 17797403Sobrien myumask = umask(0); 17897403Sobrien (void)umask(myumask); 179132720Skan 18097403Sobrien /* Save the target base in "to". */ 181132720Skan target = argv[--argc]; 18297403Sobrien if (strlen(target) > MAXPATHLEN) 18397403Sobrien errx(1, "%s: name too long", target); 18497403Sobrien (void)strcpy(to.p_path, target); 185117397Skan to.p_end = to.p_path + strlen(to.p_path); 186117397Skan if (to.p_path == to.p_end) { 187117397Skan *to.p_end++ = '.'; 188117397Skan *to.p_end = 0; 189117397Skan } 190117397Skan STRIP_TRAILING_SLASH(to); 191117397Skan to.target_end = to.p_end; 192117397Skan 193117397Skan /* Set end of argument list for fts(3). */ 194117397Skan argv[argc] = NULL; 195117397Skan 196117397Skan /* 197117397Skan * Cp has two distinct cases: 198117397Skan * 199117397Skan * cp [-R] source target 200117397Skan * cp [-R] source1 ... sourceN directory 201117397Skan * 202117397Skan * In both cases, source can be either a file or a directory. 203117397Skan * 204117397Skan * In (1), the target becomes a copy of the source. That is, if the 205117397Skan * source is a file, the target will be a file, and likewise for 206117397Skan * directories. 207117397Skan * 208117397Skan * In (2), the real target is not directory, but "directory/source". 209117397Skan */ 21097403Sobrien r = stat(to.p_path, &to_stat); 211132720Skan if (r == -1 && errno != ENOENT) 212117397Skan err(1, "%s", to.p_path); 21397403Sobrien if (r == -1 || !S_ISDIR(to_stat.st_mode)) { 214132720Skan /* 215117397Skan * Case (1). Target is not a directory. 21697403Sobrien */ 217132720Skan if (argc > 1) { 218117397Skan usage(); 21997403Sobrien exit(1); 220132720Skan } 221117397Skan /* 22297403Sobrien * Need to detect the case: 223132720Skan * cp -R dir foo 224117397Skan * Where dir is a directory and foo does not exist, where 225117397Skan * we want pathname concatenations turned on but not for 226117397Skan * the initial mkdir(). 22797403Sobrien */ 228132720Skan if (r == -1) { 229117397Skan if (rflag || (Rflag && (Lflag || Hflag))) 230117397Skan stat(*argv, &tmp_stat); 23197403Sobrien else 232132720Skan lstat(*argv, &tmp_stat); 233117397Skan 23497403Sobrien if (S_ISDIR(tmp_stat.st_mode) && (Rflag || rflag)) 235132720Skan type = DIR_TO_DNE; 236117397Skan else 237117397Skan type = FILE_TO_FILE; 23897403Sobrien } else 239132720Skan type = FILE_TO_FILE; 240117397Skan } else 24197403Sobrien /* 242132720Skan * Case (2). Target is a directory. 243117397Skan */ 244117397Skan type = FILE_TO_DIR; 24597403Sobrien 246132720Skan exit (copy(argv, type, fts_options)); 247117397Skan} 248117397Skan 24997403Sobrienint 250132720Skancopy(argv, type, fts_options) 251117397Skan char *argv[]; 25297403Sobrien enum op type; 253132720Skan int fts_options; 254117397Skan{ 25597403Sobrien struct stat to_stat; 256132720Skan FTS *ftsp; 257117397Skan FTSENT *curr; 25897403Sobrien int base, dne, nlen, rval; 259132720Skan char *p, *target_mid; 260117397Skan 261117397Skan if ((ftsp = fts_open(argv, fts_options, mastercmp)) == NULL) 26297403Sobrien err(1, NULL); 263132720Skan for (rval = 0; (curr = fts_read(ftsp)) != NULL;) { 264117397Skan switch (curr->fts_info) { 26597403Sobrien case FTS_NS: 266132720Skan case FTS_ERR: 267117397Skan warnx("%s: %s", 26897403Sobrien curr->fts_path, strerror(curr->fts_errno)); 269132720Skan rval = 1; 270117397Skan continue; 27197403Sobrien case FTS_DC: /* Warn, continue. */ 27297403Sobrien warnx("%s: directory causes a cycle", curr->fts_path); 27397403Sobrien rval = 1; 274117397Skan continue; 275117397Skan case FTS_DP: /* Ignore, continue. */ 276117397Skan continue; 277117397Skan } 278117397Skan 279117397Skan /* 280117397Skan * If we are in case (2) or (3) above, we need to append the 281117397Skan * source name to the target name. 282117397Skan */ 283117397Skan if (type != FILE_TO_FILE) { 284117397Skan /* 28597403Sobrien * Need to remember the roots of traversals to create 286132720Skan * correct pathnames. If there's a directory being 287117397Skan * copied to a non-existent directory, e.g. 288117397Skan * cp -R a/dir noexist 289132720Skan * the resulting path name should be noexist/foo, not 290132720Skan * noexist/dir/foo (where foo is a file in dir), which 291117397Skan * is the case where the target exists. 292132720Skan * 293132720Skan * Also, check for "..". This is for correct path 294117397Skan * concatentation for paths ending in "..", e.g. 295117397Skan * cp -R .. /tmp 296117397Skan * Paths ending in ".." are changed to ".". This is 297132720Skan * tricky, but seems the easiest way to fix the problem. 298132720Skan * 299117397Skan * XXX 300132720Skan * Since the first level MUST be FTS_ROOTLEVEL, base 30197403Sobrien * is always initialized. 302117397Skan */ 303117397Skan if (curr->fts_level == FTS_ROOTLEVEL) 304117397Skan if (type != DIR_TO_DNE) { 305117397Skan p = strrchr(curr->fts_path, '/'); 306117397Skan base = (p == NULL) ? 0 : 307117397Skan (int)(p - curr->fts_path + 1); 308117397Skan 309117397Skan if (!strcmp(&curr->fts_path[base], 310117397Skan "..")) 311117397Skan base += 1; 312117397Skan } else 313117397Skan base = curr->fts_pathlen; 314117397Skan 315117397Skan p = &curr->fts_path[base]; 31697403Sobrien nlen = curr->fts_pathlen - base; 317132720Skan target_mid = to.target_end; 318117397Skan if (*p != '/' && target_mid[-1] != '/') 319132720Skan *target_mid++ = '/'; 320132720Skan *target_mid = 0; 321117397Skan if (target_mid - to.p_path + nlen > MAXPATHLEN) { 322132720Skan warnx("%s%s: name too long (not copied)", 323132720Skan to.p_path, p); 324117397Skan rval = 1; 325117397Skan continue; 326117397Skan } 327117397Skan (void)strncat(target_mid, p, nlen); 328132720Skan to.p_end = target_mid + nlen; 329132720Skan *to.p_end = 0; 330117397Skan STRIP_TRAILING_SLASH(to); 331132720Skan } 332132720Skan 333117397Skan /* Not an error but need to remember it happened */ 334132720Skan if (stat(to.p_path, &to_stat) == -1) 335132720Skan dne = 1; 336117397Skan else { 337132720Skan if (to_stat.st_dev == curr->fts_statp->st_dev && 33897403Sobrien to_stat.st_ino == curr->fts_statp->st_ino) { 339117397Skan warnx("%s and %s are identical (not copied).", 340117397Skan to.p_path, curr->fts_path); 341117397Skan rval = 1; 342117397Skan if (S_ISDIR(curr->fts_statp->st_mode)) 343117397Skan (void)fts_set(ftsp, curr, FTS_SKIP); 344117397Skan continue; 345117397Skan } 346117397Skan dne = 0; 347117397Skan } 348117397Skan 34997403Sobrien switch (curr->fts_statp->st_mode & S_IFMT) { 350132720Skan case S_IFLNK: 351117397Skan if (copy_link(curr, !dne)) 352132720Skan rval = 1; 353132720Skan break; 354117397Skan case S_IFDIR: 355132720Skan if (!Rflag && !rflag) { 356132720Skan warnx("%s is a directory (not copied).", 357117397Skan curr->fts_path); 358132720Skan (void)fts_set(ftsp, curr, FTS_SKIP); 35997403Sobrien rval = 1; 360132720Skan break; 361117397Skan } 36297403Sobrien /* 36397403Sobrien * If the directory doesn't exist, create the new 36497403Sobrien * one with the from file mode plus owner RWX bits, 365132720Skan * modified by the umask. Trade-off between being 366107606Sobrien * able to write the directory (if from directory is 367107606Sobrien * 555) and not causing a permissions race. If the 36897403Sobrien * umask blocks owner writes, we fail.. 36997403Sobrien */ 37097403Sobrien if (dne) { 371117397Skan if (mkdir(to.p_path, 372132720Skan curr->fts_statp->st_mode | S_IRWXU) < 0) 373132720Skan err(1, "%s", to.p_path); 374132720Skan } else if (!S_ISDIR(to_stat.st_mode)) { 375132720Skan errno = ENOTDIR; 376117397Skan err(1, "%s", to.p_path); 37797403Sobrien } 37897403Sobrien /* 37997403Sobrien * If not -p and directory didn't exist, set it to be 38097403Sobrien * the same as the from directory, umodified by the 38197403Sobrien * umask; arguably wrong, but it's been that way 38297403Sobrien * forever. 38397403Sobrien */ 384117397Skan if (pflag && setfile(curr->fts_statp, 0)) 385132720Skan rval = 1; 386132720Skan else if (dne) 387132720Skan (void)chmod(to.p_path, 388132720Skan curr->fts_statp->st_mode); 389132720Skan break; 390132720Skan case S_IFBLK: 391132720Skan case S_IFCHR: 392132720Skan if (Rflag) { 393117397Skan if (copy_special(curr->fts_statp, !dne)) 39497403Sobrien rval = 1; 39597403Sobrien } else { 396117397Skan if (copy_file(curr, dne)) 397132720Skan rval = 1; 398132720Skan } 399132720Skan break; 400132720Skan case S_IFIFO: 401132720Skan if (Rflag) { 402132720Skan if (copy_fifo(curr->fts_statp, !dne)) 403132720Skan rval = 1; 404132720Skan } else { 405117397Skan if (copy_file(curr, dne)) 406132720Skan rval = 1; 40797403Sobrien } 40897403Sobrien break; 40997403Sobrien default: 410117397Skan if (copy_file(curr, dne)) 411117397Skan rval = 1; 412117397Skan break; 413117397Skan } 414117397Skan } 415117397Skan if (errno) 416132720Skan err(1, "fts_read"); 417132720Skan return (rval); 418132720Skan} 419132720Skan 420132720Skan/* 421117397Skan * mastercmp -- 42297403Sobrien * The comparison function for the copy order. The order is to copy 42397403Sobrien * non-directory files before directory files. The reason for this 42497403Sobrien * is because files tend to be in the same cylinder group as their 42597403Sobrien * parent directory, whereas directories tend not to be. Copying the 42697403Sobrien * files first reduces seeking. 42797403Sobrien */ 428132720Skanint 429132720Skanmastercmp(a, b) 430132720Skan const FTSENT **a, **b; 43197403Sobrien{ 432132720Skan int a_info, b_info; 433132720Skan 43497403Sobrien a_info = (*a)->fts_info; 43597403Sobrien if (a_info == FTS_ERR || a_info == FTS_NS || a_info == FTS_DNR) 43697403Sobrien return (0); 437132720Skan b_info = (*b)->fts_info; 438132720Skan if (b_info == FTS_ERR || b_info == FTS_NS || b_info == FTS_DNR) 439132720Skan return (0); 44097403Sobrien if (a_info == FTS_D) 441132720Skan return (-1); 442132720Skan if (b_info == FTS_D) 443132720Skan return (1); 44497403Sobrien return (0); 44597403Sobrien} 446132720Skan