xref: /original-bsd/bin/cp/cp.c (revision a9c19d04)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  */
6 
7 #ifndef lint
8 char copyright[] =
9 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
10  All rights reserved.\n";
11 #endif not lint
12 
13 #ifndef lint
14 static char sccsid[] = "@(#)cp.c	4.14 (Berkeley) 12/02/86";
15 #endif not lint
16 
17 /*
18  * cp
19  */
20 #include <stdio.h>
21 #include <sys/param.h>
22 #include <sys/stat.h>
23 #include <sys/dir.h>
24 #include <sys/time.h>
25 
26 int	iflag;
27 int	rflag;
28 int	pflag;
29 char	*rindex();
30 
31 main(argc, argv)
32 	int argc;
33 	char **argv;
34 {
35 	struct stat stb;
36 	int rc, i;
37 
38 	argc--, argv++;
39 	while (argc > 0 && **argv == '-') {
40 		(*argv)++;
41 		while (**argv) switch (*(*argv)++) {
42 
43 		case 'i':
44 			iflag++; break;
45 
46 		case 'R':
47 		case 'r':
48 			rflag++; break;
49 
50 		case 'p':	/* preserve mtimes, atimes, and modes */
51 			pflag++;
52 			(void) umask(0);
53 			break;
54 
55 		default:
56 			goto usage;
57 		}
58 		argc--; argv++;
59 	}
60 	if (argc < 2)
61 		goto usage;
62 	if (argc > 2) {
63 		if (stat(argv[argc-1], &stb) < 0)
64 			goto usage;
65 		if ((stb.st_mode&S_IFMT) != S_IFDIR)
66 			goto usage;
67 	}
68 	rc = 0;
69 	for (i = 0; i < argc-1; i++)
70 		rc |= copy(argv[i], argv[argc-1]);
71 	exit(rc);
72 usage:
73 	fprintf(stderr,
74 	    "Usage: cp [-ip] f1 f2; or: cp [-irp] f1 ... fn d2\n");
75 	exit(1);
76 }
77 
78 			/* I/O buffer; guarantee long-word alignment */
79 static char	buf[MAXBSIZE];
80 
81 copy(from, to)
82 	char *from, *to;
83 {
84 	int fold, fnew, n, exists;
85 	char *last, destname[MAXPATHLEN + 1];
86 	struct stat stfrom, stto;
87 
88 	fold = open(from, 0);
89 	if (fold < 0) {
90 		Perror(from);
91 		return (1);
92 	}
93 	if (fstat(fold, &stfrom) < 0) {
94 		Perror(from);
95 		(void) close(fold);
96 		return (1);
97 	}
98 	if (stat(to, &stto) >= 0 &&
99 	   (stto.st_mode&S_IFMT) == S_IFDIR) {
100 		last = rindex(from, '/');
101 		if (last) last++; else last = from;
102 		if (strlen(to) + strlen(last) >= sizeof destname - 1) {
103 			fprintf(stderr, "cp: %s/%s: Name too long", to, last);
104 			(void) close(fold);
105 			return(1);
106 		}
107 		(void) sprintf(destname, "%s/%s", to, last);
108 		to = destname;
109 	}
110 	if (rflag && (stfrom.st_mode&S_IFMT) == S_IFDIR) {
111 		int fixmode = 0;	/* cleanup mode after rcopy */
112 
113 		(void) close(fold);
114 		if (stat(to, &stto) < 0) {
115 			if (mkdir(to, (stfrom.st_mode & 07777) | 0700) < 0) {
116 				Perror(to);
117 				return (1);
118 			}
119 			fixmode = 1;
120 		} else if ((stto.st_mode&S_IFMT) != S_IFDIR) {
121 			fprintf(stderr, "cp: %s: Not a directory.\n", to);
122 			return (1);
123 		} else if (pflag)
124 			fixmode = 1;
125 		n = rcopy(from, to);
126 		if (fixmode)
127 			(void) chmod(to, stfrom.st_mode & 07777);
128 		return (n);
129 	}
130 
131 	if ((stfrom.st_mode&S_IFMT) == S_IFDIR)
132 		fprintf(stderr,
133 			"cp: %s: Is a directory (copying as plain file).\n",
134 				from);
135 
136 	exists = stat(to, &stto) == 0;
137 	if (exists) {
138 		if (stfrom.st_dev == stto.st_dev &&
139 		   stfrom.st_ino == stto.st_ino) {
140 			fprintf(stderr,
141 				"cp: %s and %s are identical (not copied).\n",
142 					from, to);
143 			(void) close(fold);
144 			return (1);
145 		}
146 		if (iflag && isatty(fileno(stdin))) {
147 			int i, c;
148 
149 			fprintf (stderr, "overwrite %s? ", to);
150 			i = c = getchar();
151 			while (c != '\n' && c != EOF)
152 				c = getchar();
153 			if (i != 'y') {
154 				(void) close(fold);
155 				return(1);
156 			}
157 		}
158 	}
159 	fnew = creat(to, stfrom.st_mode & 07777);
160 	if (fnew < 0) {
161 		Perror(to);
162 		(void) close(fold); return(1);
163 	}
164 	if (exists && pflag)
165 		(void) fchmod(fnew, stfrom.st_mode & 07777);
166 
167 	for (;;) {
168 		n = read(fold, buf, sizeof buf);
169 		if (n == 0)
170 			break;
171 		if (n < 0) {
172 			Perror(from);
173 			(void) close(fold); (void) close(fnew); return (1);
174 		}
175 		if (write(fnew, buf, n) != n) {
176 			Perror(to);
177 			(void) close(fold); (void) close(fnew); return (1);
178 		}
179 	}
180 	(void) close(fold); (void) close(fnew);
181 	if (pflag)
182 		return (setimes(to, &stfrom));
183 	return (0);
184 }
185 
186 rcopy(from, to)
187 	char *from, *to;
188 {
189 	DIR *fold = opendir(from);
190 	struct direct *dp;
191 	struct stat statb;
192 	int errs = 0;
193 	char fromname[MAXPATHLEN + 1];
194 
195 	if (fold == 0 || (pflag && fstat(fold->dd_fd, &statb) < 0)) {
196 		Perror(from);
197 		return (1);
198 	}
199 	for (;;) {
200 		dp = readdir(fold);
201 		if (dp == 0) {
202 			closedir(fold);
203 			if (pflag)
204 				return (setimes(to, &statb) + errs);
205 			return (errs);
206 		}
207 		if (dp->d_ino == 0)
208 			continue;
209 		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
210 			continue;
211 		if (strlen(from)+1+strlen(dp->d_name) >= sizeof fromname - 1) {
212 			fprintf(stderr, "cp: %s/%s: Name too long.\n",
213 			    from, dp->d_name);
214 			errs++;
215 			continue;
216 		}
217 		(void) sprintf(fromname, "%s/%s", from, dp->d_name);
218 		errs += copy(fromname, to);
219 	}
220 }
221 
222 int
223 setimes(path, statp)
224 	char *path;
225 	struct stat *statp;
226 {
227 	struct timeval tv[2];
228 
229 	tv[0].tv_sec = statp->st_atime;
230 	tv[1].tv_sec = statp->st_mtime;
231 	tv[0].tv_usec = tv[1].tv_usec = 0;
232 	if (utimes(path, tv) < 0) {
233 		Perror(path);
234 		return (1);
235 	}
236 	return (0);
237 }
238 
239 Perror(s)
240 	char *s;
241 {
242 
243 	fprintf(stderr, "cp: ");
244 	perror(s);
245 }
246