fix umask manipulation (make it like old cp) -- a little tricky.
[unix-history] / usr / src / bin / cp / cp.c
CommitLineData
1f978f4c 1/*
4d2ae24a
KB
2 * Copyright (c) 1988 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * David Hitz of Auspex Systems Inc.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the University of California, Berkeley. The name of the
14 * University may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 */
20
21#ifndef lint
22char copyright[] =
23"@(#) Copyright (c) 1988 The Regents of the University of California.\n\
24 All rights reserved.\n";
25#endif /* not lint */
26
27#ifndef lint
24e5a125 28static char sccsid[] = "@(#)cp.c 5.6 (Berkeley) %G%";
4d2ae24a
KB
29#endif /* not lint */
30
31/*
32 * cp copies source files to target files.
ae5e5236
KB
33 *
34 * The global path_t structures "to" and "from" always contain paths to the
4d2ae24a
KB
35 * current source and target files, respectively. Since cp does not change
36 * directories, these paths can be either absolute or dot-realative.
ae5e5236
KB
37 *
38 * The basic algorithm is to initialize "to" and "from", and then call the
39 * recursive copy() function to do the actual work. If "from" is a file,
40 * copy copies the data. If "from" is a directory, copy creates the
41 * corresponding "to" directory, and calls itself recursively on all of
42 * the entries in the "from" directory.
1f978f4c
KM
43 */
44
4d2ae24a 45#include <sys/param.h>
84592a94 46#include <sys/stat.h>
ae5e5236 47#include <sys/file.h>
7afd0a98 48#include <sys/dir.h>
0908a03a 49#include <sys/time.h>
5f89032b 50
4d2ae24a
KB
51#include <stdio.h>
52#include <errno.h>
53#include <strings.h>
ae5e5236
KB
54
55typedef struct {
a783899b
KB
56 char *p_path; /* pointer to the start of a path. */
57 char *p_end; /* pointer to NULL at end of path. */
4d2ae24a 58} path_t;
ae5e5236 59
a783899b
KB
60#define type(st) ((st).st_mode&S_IFMT)
61
4d2ae24a
KB
62char *path_append(), *path_basename();
63void path_restore();
ae5e5236 64
24e5a125 65int exit_val, symfollow;
4d2ae24a
KB
66int interactive_flag, preserve_flag, recursive_flag;
67char *buf; /* I/O; malloc for best alignment. */
24e5a125
KB
68char from_buf[MAXPATHLEN + 1], /* source path buffer */
69 to_buf[MAXPATHLEN + 1]; /* target path buffer */
4d2ae24a
KB
70path_t from = {from_buf, from_buf};
71path_t to = {to_buf, to_buf};
84592a94
BJ
72
73main(argc, argv)
4d2ae24a
KB
74 int argc;
75 char **argv;
84592a94 76{
4d2ae24a
KB
77 extern int optind, errno;
78 struct stat to_stat;
79 register int c, r;
a783899b 80 int force_flag;
4d2ae24a
KB
81 char *old_to, *malloc();
82
a783899b
KB
83 force_flag = 0;
84 while ((c = getopt(argc, argv, "Rfhipr")) != EOF) {
85 switch ((char)c) {
86 case 'f':
87 force_flag = 1;
88 break;
0493752e
KB
89 case 'h':
90 symfollow = 1;
91 break;
4d2ae24a
KB
92 case 'i':
93 interactive_flag = isatty(fileno(stdin));
94 break;
95 case 'p':
96 preserve_flag = 1;
97 (void)umask(0);
98 break;
99 case 'r':
100 case 'R':
101 recursive_flag = 1;
102 break;
103 case '?':
104 default:
105 usage();
106 break;
107 }
84592a94 108 }
0493752e
KB
109 argc -= optind;
110 argv += optind;
ae5e5236 111
4d2ae24a
KB
112 if (argc < 2)
113 usage();
ae5e5236 114
a783899b
KB
115 if (force_flag)
116 interactive_flag = 0;
117
4d2ae24a
KB
118 buf = (char *)malloc(MAXBSIZE);
119 if (!buf) {
0493752e 120 (void)fprintf(stderr, "cp: out of space.\n");
4d2ae24a 121 exit(1);
ae5e5236
KB
122 }
123
24e5a125 124 /* consume last argument first. */
4d2ae24a
KB
125 if (!path_set(&to, argv[--argc]))
126 exit(exit_val);
ae5e5236 127
ae5e5236 128 /*
4d2ae24a
KB
129 * Cp has two distinct cases:
130 *
131 * Case (1) $ cp [-rip] source target
132 *
133 * Case (2) $ cp [-rip] source1 ... directory
134 *
135 * In both cases, source can be either a file or a directory.
136 *
137 * In (1), the target becomes a copy of the source. That is, if the
138 * source is a file, the target will be a file, and likewise for
139 * directories.
140 *
141 * In (2), the real target is not directory, but "directory/source".
ae5e5236 142 */
ae5e5236 143
4d2ae24a
KB
144 r = stat(to.p_path, &to_stat);
145 if (r == -1 && errno != ENOENT) {
24e5a125 146 error(to.p_path);
4d2ae24a
KB
147 exit(1);
148 }
a783899b 149 if (r == -1 || type(to_stat) != S_IFDIR) {
4d2ae24a
KB
150 /*
151 * Case (1). Target is not a directory.
152 */
153 if (argc > 1) {
154 usage();
155 exit(1);
156 }
157 if (!path_set(&from, *argv))
158 exit(exit_val);
159 copy();
160 }
161 else {
162 /*
163 * Case (2). Target is a directory.
164 */
24e5a125 165 for (;; ++argv) {
4d2ae24a
KB
166 if (!path_set(&from, *argv))
167 continue;
168 old_to = path_append(&to, path_basename(&from), -1);
169 if (!old_to)
170 continue;
171 copy();
24e5a125
KB
172 if (!--argc)
173 break;
4d2ae24a
KB
174 path_restore(&to, old_to);
175 }
ae5e5236 176 }
4d2ae24a 177 exit(exit_val);
84592a94
BJ
178}
179
a783899b 180/* copy file or directory at "from" to "to". */
ae5e5236 181copy()
84592a94 182{
4d2ae24a 183 struct stat from_stat, to_stat;
24e5a125 184 int dne, statval;
ae5e5236 185
0493752e
KB
186 statval = symfollow || !recursive_flag ?
187 stat(from.p_path, &from_stat) : lstat(from.p_path, &from_stat);
188 if (statval == -1) {
24e5a125 189 error(from.p_path);
4d2ae24a
KB
190 return;
191 }
0493752e
KB
192
193 /* not an error, but need to remember it happened */
4d2ae24a 194 if (stat(to.p_path, &to_stat) == -1)
24e5a125
KB
195 dne = 1;
196 else {
197 if (to_stat.st_dev == from_stat.st_dev &&
198 to_stat.st_ino == from_stat.st_ino) {
199 (void)fprintf(stderr,
200 "cp: %s and %s are identical (not copied).\n",
201 to.p_path, from.p_path);
202 exit_val = 1;
203 return;
204 }
205 dne = 0;
84592a94 206 }
ae5e5236 207
a783899b
KB
208 switch(type(from_stat)) {
209 case S_IFLNK:
24e5a125 210 copy_link(!dne);
0493752e 211 return;
a783899b 212 case S_IFDIR:
4d2ae24a
KB
213 if (!recursive_flag) {
214 (void)fprintf(stderr,
a783899b
KB
215 "cp: %s is a directory (not copied).\n",
216 from.p_path);
4d2ae24a
KB
217 exit_val = 1;
218 return;
219 }
24e5a125
KB
220 if (dne) {
221 /*
222 * If the directory doesn't exist, create the new
223 * one with the from file mode plus owner RWX bits,
224 * modified by the umask. Trade-off between being
225 * able to write the directory (if from directory is
226 * 555) and not causing a permissions race. If the
227 * umask blocks owner writes cp fails.
228 */
229 if (mkdir(to.p_path, from_stat.st_mode|S_IRWXU) < 0) {
230 error(to.p_path);
4d2ae24a
KB
231 return;
232 }
4d2ae24a 233 }
a783899b
KB
234 else if (type(to_stat) != S_IFDIR) {
235 (void)fprintf(stderr, "cp: %s: not a directory.\n",
236 to.p_path);
4d2ae24a
KB
237 return;
238 }
239 copy_dir();
24e5a125
KB
240 /*
241 * If directory didn't exist, set it to be the same as
242 * the from directory, umodified by the umask; arguably
243 * wrong, but it's been that way forever.
244 */
245 if (dne && !preserve_flag)
246 (void)chmod(to.p_path, from_stat.st_mode);
a783899b
KB
247 break;
248 case S_IFCHR:
249 case S_IFBLK:
24e5a125
KB
250 /*
251 * if recursive flag on, try and create the special device
252 * otherwise copy the contents.
253 */
a783899b
KB
254 if (recursive_flag) {
255 copy_special(&from_stat, &to_stat);
256 if (preserve_flag)
24e5a125 257 setfile(&from_stat, 0);
a783899b
KB
258 return;
259 }
260 /* FALLTHROUGH */
261 default:
24e5a125 262 copy_file(&from_stat);
5f89032b 263 }
ae5e5236
KB
264}
265
24e5a125
KB
266copy_file(fs)
267 struct stat *fs;
ae5e5236 268{
a783899b 269 register int from_fd, to_fd, rcount, wcount;
4d2ae24a 270
24e5a125
KB
271 if ((from_fd = open(from.p_path, O_RDONLY, 0)) == -1) {
272 error(from.p_path);
273 return;
4d2ae24a
KB
274 }
275
276 /*
24e5a125
KB
277 * In the interactive case, use O_EXCL to notice existing files.
278 * If the file exists, verify with the user.
279 *
280 * If the file DNE, create it with the mode of the from file modified
281 * by the umask; arguably wrong but it makes copying executables work
282 * right and it's been that way forever. The other choice is 666
283 * or'ed with the execute bits on the from file modified by the umask.
4d2ae24a
KB
284 */
285 to_fd = open(to.p_path,
0493752e 286 (interactive_flag ? O_EXCL : 0) | O_WRONLY | O_CREAT | O_TRUNC,
24e5a125 287 fs->st_mode);
ae5e5236 288
4d2ae24a 289 if (to_fd == -1 && errno == EEXIST && interactive_flag) {
03137eae
KB
290 int checkch, ch;
291
292 (void)fprintf(stderr, "overwrite %s? ", to.p_path);
293 checkch = ch = getchar();
294 while (ch != '\n' && ch != EOF)
295 ch = getchar();
296 if (checkch != 'y')
24e5a125 297 return;
03137eae 298 /* try again. */
24e5a125
KB
299 to_fd = open(to.p_path, O_WRONLY | O_CREAT | O_TRUNC,
300 fs->st_mode);
5f89032b 301 }
ae5e5236 302
4d2ae24a 303 if (to_fd == -1) {
24e5a125 304 error(to.p_path);
4d2ae24a 305 (void)close(from_fd);
24e5a125 306 return;
ae5e5236
KB
307 }
308
4d2ae24a
KB
309 while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
310 wcount = write(to_fd, buf, rcount);
311 if (rcount != wcount || wcount == -1) {
24e5a125 312 error(to.p_path);
4d2ae24a
KB
313 break;
314 }
ae5e5236 315 }
24e5a125
KB
316 if (rcount < 0)
317 error(from.p_path);
318 if (preserve_flag)
319 setfile(fs, to_fd);
4d2ae24a
KB
320 (void)close(from_fd);
321 (void)close(to_fd);
4d2ae24a 322}
ae5e5236 323
4d2ae24a
KB
324copy_dir()
325{
326 struct stat from_stat;
4d2ae24a 327 struct direct *dp, **dir_list;
24e5a125
KB
328 register int dir_cnt, i;
329 char *old_from, *old_to;
4d2ae24a
KB
330
331 dir_cnt = scandir(from.p_path, &dir_list, NULL, NULL);
332 if (dir_cnt == -1) {
03137eae 333 (void)fprintf(stderr, "cp: can't read directory %s.\n",
4d2ae24a
KB
334 from.p_path);
335 exit_val = 1;
ae5e5236
KB
336 }
337
24e5a125
KB
338 /*
339 * Instead of handling directory entries in the order they appear
340 * on disk, do non-directory files before directory files.
341 * There are two reasons to do directories last. The first is
342 * efficiency. Files tend to be in the same cylinder group as
343 * their parent, whereas directories tend not to be. Copying files
344 * all at once reduces seeking. Second, deeply nested tree's
345 * could use up all the file descriptors if we didn't close one
346 * directory before recursivly starting on the next.
347 */
348 /* copy files */
4d2ae24a
KB
349 for (i = 0; i < dir_cnt; ++i) {
350 dp = dir_list[i];
351 if (dp->d_namlen <= 2 && dp->d_name[0] == '.'
24e5a125
KB
352 && (dp->d_name[1] == NULL || dp->d_name[1] == '.'))
353 goto done;
4d2ae24a 354 old_from = path_append(&from, dp->d_name, (int)dp->d_namlen);
24e5a125
KB
355 if (!old_from)
356 goto done;
4d2ae24a
KB
357
358 if (stat(from.p_path, &from_stat) < 0) {
24e5a125
KB
359 error(dp->d_name);
360 path_restore(&from, old_from);
361 goto done;
362 }
363 if (type(from_stat) == S_IFDIR) {
4d2ae24a
KB
364 path_restore(&from, old_from);
365 continue;
366 }
24e5a125
KB
367 old_to = path_append(&to, dp->d_name, (int)dp->d_namlen);
368 if (old_to) {
4d2ae24a
KB
369 copy();
370 path_restore(&to, old_to);
4d2ae24a
KB
371 }
372 path_restore(&from, old_from);
24e5a125
KB
373done: dir_list[i] = NULL;
374 (void)free((char *)dp);
5f89032b 375 }
ae5e5236 376
24e5a125 377 /* copy directories */
4d2ae24a
KB
378 for (i = 0; i < dir_cnt; ++i) {
379 dp = dir_list[i];
380 if (!dp)
381 continue;
382 old_from = path_append(&from, dp->d_name, (int) dp->d_namlen);
383 if (!old_from) {
384 (void)free((char *)dp);
385 continue;
386 }
387 old_to = path_append(&to, dp->d_name, (int) dp->d_namlen);
388 if (!old_to) {
389 (void)free((char *)dp);
390 path_restore(&from, old_from);
391 continue;
392 }
393 copy();
394 free((char *)dp);
395 path_restore(&from, old_from);
396 path_restore(&to, old_to);
5f89032b 397 }
4d2ae24a 398 free((char *)dir_list);
5f89032b 399}
1a4b831f 400
0493752e
KB
401copy_link(exists)
402 int exists;
403{
404 char link[MAXPATHLEN];
405
406 if (readlink(from.p_path, link, sizeof(link)) == -1) {
24e5a125 407 error(from.p_path);
0493752e
KB
408 return;
409 }
410 if (exists && unlink(to.p_path)) {
24e5a125 411 error(to.p_path);
0493752e
KB
412 return;
413 }
414 if (symlink(link, to.p_path)) {
24e5a125 415 error(link);
0493752e
KB
416 return;
417 }
418}
419
a783899b
KB
420copy_special(from_stat, to_stat)
421 struct stat *from_stat, *to_stat;
422{
423 if (to_stat->st_ino != -1 && unlink(to.p_path)) {
24e5a125 424 error(to.p_path);
a783899b
KB
425 return;
426 }
427 if (mknod(to.p_path, from_stat->st_mode, from_stat->st_rdev)) {
24e5a125 428 error(to.p_path);
a783899b
KB
429 return;
430 }
431}
432
24e5a125
KB
433setfile(fs, fd)
434 register struct stat *fs;
435 int fd;
a783899b
KB
436{
437 static struct timeval tv[2];
24e5a125 438 static int dochown = 1;
a783899b 439
a783899b
KB
440 tv[0].tv_sec = fs->st_atime;
441 tv[1].tv_sec = fs->st_mtime;
442 if (utimes(to.p_path, tv))
24e5a125
KB
443 error(to.p_path);
444 /*
445 * Changing the ownership probably won't succeed, unless we're
446 * root or POSIX_CHOWN_RESTRICTED is not set. Try it last so
447 * everything else gets set first.
448 */
449 if (fd) {
450 if (fchmod(fd, fs->st_mode))
451 error(to.p_path);
452 if (dochown && fchown(fd, fs->st_uid, fs->st_gid) == -1)
453 if (errno == EPERM)
454 dochown = 0;
455 else
456 error(to.p_path);
457 } else {
458 if (chmod(to.p_path, fs->st_mode))
459 error(to.p_path);
460 if (dochown && chown(to.p_path, fs->st_uid, fs->st_gid) == -1)
461 if (errno == EPERM)
462 dochown = 0;
463 else
464 error(to.p_path);
465 }
a783899b
KB
466}
467
24e5a125
KB
468error(s)
469 char *s;
0908a03a 470{
4d2ae24a 471 extern int errno;
ae5e5236 472
4d2ae24a 473 exit_val = 1;
24e5a125 474 (void)fprintf(stderr, "cp: %s: %s\n", s, strerror(errno));
4d2ae24a 475}
ae5e5236
KB
476
477/********************************************************************
478 * Path Manipulation Routines.
479 ********************************************************************/
480
481/*
482 * These functions manipulate paths in "path_t" structures.
483 *
484 * They eliminate multiple slashes in paths when they notice them, and keep
485 * the path non-slash terminated.
486 *
4d2ae24a 487 * Both path_set() and path_append() return 0 if the requested name
ae5e5236
KB
488 * would be too long.
489 */
490
4d2ae24a
KB
491#define STRIP_TRAILING_SLASH(p) { \
492 while ((p)->p_end > (p)->p_path && (p)->p_end[-1] == '/') \
493 *--(p)->p_end = 0; \
494 }
ae5e5236
KB
495
496/*
497 * Move specified string into path. Convert "" to "." to handle BSD
498 * semantics for a null path. Strip trailing slashes.
499 */
500path_set(p, string)
4d2ae24a
KB
501 register path_t *p;
502 char *string;
ae5e5236 503{
4d2ae24a 504 if (strlen(string) > MAXPATHLEN) {
24e5a125 505 (void)fprintf(stderr, "cp: %s: name too long.\n", string);
4d2ae24a
KB
506 exit_val = 1;
507 return(0);
508 }
ae5e5236 509
4d2ae24a
KB
510 (void)strcpy(p->p_path, string);
511 p->p_end = p->p_path + strlen(p->p_path);
ae5e5236 512
4d2ae24a
KB
513 if (p->p_path == p->p_end) {
514 *p->p_end++ = '.';
515 *p->p_end = 0;
516 }
ae5e5236 517
4d2ae24a
KB
518 STRIP_TRAILING_SLASH(p);
519 return(1);
ae5e5236
KB
520}
521
522/*
523 * Append specified string to path, inserting '/' if necessary. Return a
524 * pointer to the old end of path for restoration.
525 */
4d2ae24a 526char *
ae5e5236 527path_append(p, name, len)
4d2ae24a
KB
528 register path_t *p;
529 char *name;
530 int len;
1a4b831f 531{
4d2ae24a 532 char *old;
ae5e5236 533
4d2ae24a
KB
534 old = p->p_end;
535 if (len == -1)
536 len = strlen(name);
ae5e5236 537
4d2ae24a
KB
538 /*
539 * The final "+ 1" accounts for the '/' between old path and name.
540 */
541 if ((len + p->p_end - p->p_path + 1) > MAXPATHLEN) {
24e5a125 542 (void)fprintf(stderr,
03137eae 543 "cp: %s/%s: name too long.\n", p->p_path, name);
4d2ae24a
KB
544 exit_val = 1;
545 return(0);
546 }
ae5e5236 547
4d2ae24a
KB
548 /*
549 * This code should always be executed, since paths shouldn't
550 * end in '/'.
551 */
552 if (p->p_end[-1] != '/') {
553 *p->p_end++ = '/';
554 *p->p_end = 0;
555 }
ae5e5236 556
4d2ae24a
KB
557 (void)strncat(p->p_end, name, len);
558 p->p_end += len;
559 *p->p_end = 0;
ae5e5236 560
4d2ae24a
KB
561 STRIP_TRAILING_SLASH(p);
562 return(old);
ae5e5236
KB
563}
564
ae5e5236
KB
565/*
566 * Restore path to previous value. (As returned by path_append.)
567 */
568void
569path_restore(p, old)
4d2ae24a
KB
570 path_t *p;
571 char *old;
ae5e5236 572{
4d2ae24a
KB
573 p->p_end = old;
574 *p->p_end = 0;
ae5e5236
KB
575}
576
ae5e5236
KB
577/*
578 * Return basename of path. (Like basename(1).)
579 */
4d2ae24a 580char *
ae5e5236 581path_basename(p)
4d2ae24a 582 path_t *p;
ae5e5236 583{
4d2ae24a 584 char *basename;
ae5e5236 585
4d2ae24a 586 basename = rindex(p->p_path, '/');
24e5a125 587 return(basename ? ++basename : p->p_path);
4d2ae24a 588}
1a4b831f 589
4d2ae24a
KB
590usage()
591{
592 (void)fprintf(stderr,
593 "usage: cp [-ip] f1 f2; or: cp [-irp] f1 ... fn directory\n");
594 exit(1);
1a4b831f 595}