Commit | Line | Data |
---|---|---|
1f978f4c KM |
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 | ||
5f89032b | 13 | #ifndef lint |
ded1b933 | 14 | static char sccsid[] = "@(#)cp.c 4.14 (Berkeley) %G%"; |
1f978f4c | 15 | #endif not lint |
5f89032b | 16 | |
84592a94 | 17 | /* |
5f89032b | 18 | * cp |
84592a94 | 19 | */ |
84592a94 | 20 | #include <stdio.h> |
f4d092e2 | 21 | #include <sys/param.h> |
84592a94 | 22 | #include <sys/stat.h> |
7afd0a98 | 23 | #include <sys/dir.h> |
0908a03a | 24 | #include <sys/time.h> |
5f89032b | 25 | |
5f89032b BJ |
26 | int iflag; |
27 | int rflag; | |
0908a03a JL |
28 | int pflag; |
29 | char *rindex(); | |
84592a94 BJ |
30 | |
31 | main(argc, argv) | |
5f89032b BJ |
32 | int argc; |
33 | char **argv; | |
84592a94 | 34 | { |
5f89032b BJ |
35 | struct stat stb; |
36 | int rc, i; | |
84592a94 | 37 | |
5f89032b BJ |
38 | argc--, argv++; |
39 | while (argc > 0 && **argv == '-') { | |
40 | (*argv)++; | |
41 | while (**argv) switch (*(*argv)++) { | |
84592a94 | 42 | |
5f89032b BJ |
43 | case 'i': |
44 | iflag++; break; | |
84592a94 | 45 | |
685d778a | 46 | case 'R': |
5f89032b BJ |
47 | case 'r': |
48 | rflag++; break; | |
84592a94 | 49 | |
5884fcc2 JL |
50 | case 'p': /* preserve mtimes, atimes, and modes */ |
51 | pflag++; | |
52 | (void) umask(0); | |
53 | break; | |
0908a03a | 54 | |
5f89032b BJ |
55 | default: |
56 | goto usage; | |
57 | } | |
58 | argc--; argv++; | |
84592a94 | 59 | } |
5f89032b | 60 | if (argc < 2) |
84592a94 | 61 | goto usage; |
685d778a | 62 | if (argc > 2) { |
3e9da018 | 63 | if (stat(argv[argc-1], &stb) < 0) |
84592a94 | 64 | goto usage; |
5f89032b | 65 | if ((stb.st_mode&S_IFMT) != S_IFDIR) |
84592a94 BJ |
66 | goto usage; |
67 | } | |
5f89032b BJ |
68 | rc = 0; |
69 | for (i = 0; i < argc-1; i++) | |
70 | rc |= copy(argv[i], argv[argc-1]); | |
71 | exit(rc); | |
84592a94 | 72 | usage: |
5f89032b | 73 | fprintf(stderr, |
5884fcc2 | 74 | "Usage: cp [-ip] f1 f2; or: cp [-irp] f1 ... fn d2\n"); |
84592a94 BJ |
75 | exit(1); |
76 | } | |
77 | ||
ded1b933 KB |
78 | /* I/O buffer; guarantee long-word alignment */ |
79 | static char buf[MAXBSIZE]; | |
80 | ||
84592a94 | 81 | copy(from, to) |
5f89032b | 82 | char *from, *to; |
84592a94 | 83 | { |
5884fcc2 | 84 | int fold, fnew, n, exists; |
ded1b933 | 85 | char *last, destname[MAXPATHLEN + 1]; |
5f89032b BJ |
86 | struct stat stfrom, stto; |
87 | ||
88 | fold = open(from, 0); | |
89 | if (fold < 0) { | |
1a4b831f | 90 | Perror(from); |
5f89032b | 91 | return (1); |
84592a94 | 92 | } |
5f89032b | 93 | if (fstat(fold, &stfrom) < 0) { |
1a4b831f SL |
94 | Perror(from); |
95 | (void) close(fold); | |
5f89032b | 96 | return (1); |
84592a94 | 97 | } |
3e9da018 | 98 | if (stat(to, &stto) >= 0 && |
5f89032b BJ |
99 | (stto.st_mode&S_IFMT) == S_IFDIR) { |
100 | last = rindex(from, '/'); | |
101 | if (last) last++; else last = from; | |
685d778a | 102 | if (strlen(to) + strlen(last) >= sizeof destname - 1) { |
5f89032b | 103 | fprintf(stderr, "cp: %s/%s: Name too long", to, last); |
1a4b831f | 104 | (void) close(fold); |
84592a94 | 105 | return(1); |
5f89032b BJ |
106 | } |
107 | (void) sprintf(destname, "%s/%s", to, last); | |
108 | to = destname; | |
109 | } | |
110 | if (rflag && (stfrom.st_mode&S_IFMT) == S_IFDIR) { | |
2b6d53f3 JB |
111 | int fixmode = 0; /* cleanup mode after rcopy */ |
112 | ||
5f89032b | 113 | (void) close(fold); |
3e9da018 | 114 | if (stat(to, &stto) < 0) { |
2b6d53f3 | 115 | if (mkdir(to, (stfrom.st_mode & 07777) | 0700) < 0) { |
1a4b831f | 116 | Perror(to); |
5f89032b | 117 | return (1); |
e01c32c9 | 118 | } |
2b6d53f3 | 119 | fixmode = 1; |
5f89032b BJ |
120 | } else if ((stto.st_mode&S_IFMT) != S_IFDIR) { |
121 | fprintf(stderr, "cp: %s: Not a directory.\n", to); | |
122 | return (1); | |
5884fcc2 | 123 | } else if (pflag) |
2b6d53f3 JB |
124 | fixmode = 1; |
125 | n = rcopy(from, to); | |
126 | if (fixmode) | |
5884fcc2 | 127 | (void) chmod(to, stfrom.st_mode & 07777); |
2b6d53f3 | 128 | return (n); |
5f89032b | 129 | } |
685d778a S |
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 | ||
5884fcc2 JL |
136 | exists = stat(to, &stto) == 0; |
137 | if (exists) { | |
5f89032b BJ |
138 | if (stfrom.st_dev == stto.st_dev && |
139 | stfrom.st_ino == stto.st_ino) { | |
685d778a S |
140 | fprintf(stderr, |
141 | "cp: %s and %s are identical (not copied).\n", | |
142 | from, to); | |
1a4b831f | 143 | (void) close(fold); |
5f89032b BJ |
144 | return (1); |
145 | } | |
685d778a | 146 | if (iflag && isatty(fileno(stdin))) { |
5f89032b BJ |
147 | int i, c; |
148 | ||
84592a94 BJ |
149 | fprintf (stderr, "overwrite %s? ", to); |
150 | i = c = getchar(); | |
151 | while (c != '\n' && c != EOF) | |
152 | c = getchar(); | |
1a4b831f SL |
153 | if (i != 'y') { |
154 | (void) close(fold); | |
84592a94 | 155 | return(1); |
1a4b831f | 156 | } |
84592a94 BJ |
157 | } |
158 | } | |
685d778a | 159 | fnew = creat(to, stfrom.st_mode & 07777); |
5f89032b | 160 | if (fnew < 0) { |
1a4b831f | 161 | Perror(to); |
5f89032b | 162 | (void) close(fold); return(1); |
84592a94 | 163 | } |
5884fcc2 JL |
164 | if (exists && pflag) |
165 | (void) fchmod(fnew, stfrom.st_mode & 07777); | |
166 | ||
5f89032b | 167 | for (;;) { |
685d778a | 168 | n = read(fold, buf, sizeof buf); |
5f89032b BJ |
169 | if (n == 0) |
170 | break; | |
84592a94 | 171 | if (n < 0) { |
1a4b831f | 172 | Perror(from); |
5f89032b BJ |
173 | (void) close(fold); (void) close(fnew); return (1); |
174 | } | |
175 | if (write(fnew, buf, n) != n) { | |
1a4b831f | 176 | Perror(to); |
5f89032b BJ |
177 | (void) close(fold); (void) close(fnew); return (1); |
178 | } | |
179 | } | |
0908a03a JL |
180 | (void) close(fold); (void) close(fnew); |
181 | if (pflag) | |
182 | return (setimes(to, &stfrom)); | |
183 | return (0); | |
5f89032b BJ |
184 | } |
185 | ||
186 | rcopy(from, to) | |
187 | char *from, *to; | |
188 | { | |
189 | DIR *fold = opendir(from); | |
190 | struct direct *dp; | |
0908a03a | 191 | struct stat statb; |
5f89032b | 192 | int errs = 0; |
685d778a | 193 | char fromname[MAXPATHLEN + 1]; |
5f89032b | 194 | |
0908a03a | 195 | if (fold == 0 || (pflag && fstat(fold->dd_fd, &statb) < 0)) { |
1a4b831f | 196 | Perror(from); |
5f89032b BJ |
197 | return (1); |
198 | } | |
199 | for (;;) { | |
200 | dp = readdir(fold); | |
c4ac082c KM |
201 | if (dp == 0) { |
202 | closedir(fold); | |
0908a03a JL |
203 | if (pflag) |
204 | return (setimes(to, &statb) + errs); | |
5f89032b | 205 | return (errs); |
c4ac082c | 206 | } |
5f89032b BJ |
207 | if (dp->d_ino == 0) |
208 | continue; | |
209 | if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) | |
210 | continue; | |
685d778a | 211 | if (strlen(from)+1+strlen(dp->d_name) >= sizeof fromname - 1) { |
5f89032b BJ |
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 | } | |
1a4b831f | 221 | |
0908a03a JL |
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 | ||
1a4b831f SL |
239 | Perror(s) |
240 | char *s; | |
241 | { | |
242 | ||
243 | fprintf(stderr, "cp: "); | |
244 | perror(s); | |
245 | } |