xref: /original-bsd/bin/cp/cp.c (revision b9d18e58)
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.13 (Berkeley) 10/11/85";
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 copy(from, to)
79 	char *from, *to;
80 {
81 	int fold, fnew, n, exists;
82 	char *last, destname[MAXPATHLEN + 1], buf[MAXBSIZE];
83 	struct stat stfrom, stto;
84 
85 	fold = open(from, 0);
86 	if (fold < 0) {
87 		Perror(from);
88 		return (1);
89 	}
90 	if (fstat(fold, &stfrom) < 0) {
91 		Perror(from);
92 		(void) close(fold);
93 		return (1);
94 	}
95 	if (stat(to, &stto) >= 0 &&
96 	   (stto.st_mode&S_IFMT) == S_IFDIR) {
97 		last = rindex(from, '/');
98 		if (last) last++; else last = from;
99 		if (strlen(to) + strlen(last) >= sizeof destname - 1) {
100 			fprintf(stderr, "cp: %s/%s: Name too long", to, last);
101 			(void) close(fold);
102 			return(1);
103 		}
104 		(void) sprintf(destname, "%s/%s", to, last);
105 		to = destname;
106 	}
107 	if (rflag && (stfrom.st_mode&S_IFMT) == S_IFDIR) {
108 		int fixmode = 0;	/* cleanup mode after rcopy */
109 
110 		(void) close(fold);
111 		if (stat(to, &stto) < 0) {
112 			if (mkdir(to, (stfrom.st_mode & 07777) | 0700) < 0) {
113 				Perror(to);
114 				return (1);
115 			}
116 			fixmode = 1;
117 		} else if ((stto.st_mode&S_IFMT) != S_IFDIR) {
118 			fprintf(stderr, "cp: %s: Not a directory.\n", to);
119 			return (1);
120 		} else if (pflag)
121 			fixmode = 1;
122 		n = rcopy(from, to);
123 		if (fixmode)
124 			(void) chmod(to, stfrom.st_mode & 07777);
125 		return (n);
126 	}
127 
128 	if ((stfrom.st_mode&S_IFMT) == S_IFDIR)
129 		fprintf(stderr,
130 			"cp: %s: Is a directory (copying as plain file).\n",
131 				from);
132 
133 	exists = stat(to, &stto) == 0;
134 	if (exists) {
135 		if (stfrom.st_dev == stto.st_dev &&
136 		   stfrom.st_ino == stto.st_ino) {
137 			fprintf(stderr,
138 				"cp: %s and %s are identical (not copied).\n",
139 					from, to);
140 			(void) close(fold);
141 			return (1);
142 		}
143 		if (iflag && isatty(fileno(stdin))) {
144 			int i, c;
145 
146 			fprintf (stderr, "overwrite %s? ", to);
147 			i = c = getchar();
148 			while (c != '\n' && c != EOF)
149 				c = getchar();
150 			if (i != 'y') {
151 				(void) close(fold);
152 				return(1);
153 			}
154 		}
155 	}
156 	fnew = creat(to, stfrom.st_mode & 07777);
157 	if (fnew < 0) {
158 		Perror(to);
159 		(void) close(fold); return(1);
160 	}
161 	if (exists && pflag)
162 		(void) fchmod(fnew, stfrom.st_mode & 07777);
163 
164 	for (;;) {
165 		n = read(fold, buf, sizeof buf);
166 		if (n == 0)
167 			break;
168 		if (n < 0) {
169 			Perror(from);
170 			(void) close(fold); (void) close(fnew); return (1);
171 		}
172 		if (write(fnew, buf, n) != n) {
173 			Perror(to);
174 			(void) close(fold); (void) close(fnew); return (1);
175 		}
176 	}
177 	(void) close(fold); (void) close(fnew);
178 	if (pflag)
179 		return (setimes(to, &stfrom));
180 	return (0);
181 }
182 
183 rcopy(from, to)
184 	char *from, *to;
185 {
186 	DIR *fold = opendir(from);
187 	struct direct *dp;
188 	struct stat statb;
189 	int errs = 0;
190 	char fromname[MAXPATHLEN + 1];
191 
192 	if (fold == 0 || (pflag && fstat(fold->dd_fd, &statb) < 0)) {
193 		Perror(from);
194 		return (1);
195 	}
196 	for (;;) {
197 		dp = readdir(fold);
198 		if (dp == 0) {
199 			closedir(fold);
200 			if (pflag)
201 				return (setimes(to, &statb) + errs);
202 			return (errs);
203 		}
204 		if (dp->d_ino == 0)
205 			continue;
206 		if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
207 			continue;
208 		if (strlen(from)+1+strlen(dp->d_name) >= sizeof fromname - 1) {
209 			fprintf(stderr, "cp: %s/%s: Name too long.\n",
210 			    from, dp->d_name);
211 			errs++;
212 			continue;
213 		}
214 		(void) sprintf(fromname, "%s/%s", from, dp->d_name);
215 		errs += copy(fromname, to);
216 	}
217 }
218 
219 int
220 setimes(path, statp)
221 	char *path;
222 	struct stat *statp;
223 {
224 	struct timeval tv[2];
225 
226 	tv[0].tv_sec = statp->st_atime;
227 	tv[1].tv_sec = statp->st_mtime;
228 	tv[0].tv_usec = tv[1].tv_usec = 0;
229 	if (utimes(path, tv) < 0) {
230 		Perror(path);
231 		return (1);
232 	}
233 	return (0);
234 }
235 
236 Perror(s)
237 	char *s;
238 {
239 
240 	fprintf(stderr, "cp: ");
241 	perror(s);
242 }
243