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