1 /* 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 22 char 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 28 static char sccsid[] = "@(#)cp.c 5.5 (Berkeley) 05/19/89"; 29 #endif /* not lint */ 30 31 /* 32 * cp copies source files to target files. 33 * 34 * The global path_t structures "to" and "from" always contain paths to the 35 * current source and target files, respectively. Since cp does not change 36 * directories, these paths can be either absolute or dot-realative. 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. 43 * 44 * Instead of handling directory entries in the order they appear on disk, 45 * copy() does non-directory files before directory files. 46 * 47 * There are two reasons to do directories last. The first is efficiency. 48 * Files tend to be in the same cylinder group as their parent, whereas 49 * directories tend not to be. Copying files all at once reduces seeking. 50 * 51 * Second, deeply nested tree's could use up all the file descriptors if we 52 * didn't close one directory before recursivly starting on the next. 53 */ 54 55 #include <sys/param.h> 56 #include <sys/stat.h> 57 #include <sys/file.h> 58 #include <sys/dir.h> 59 #include <sys/time.h> 60 61 #include <stdio.h> 62 #include <errno.h> 63 #include <strings.h> 64 65 typedef struct { 66 char *p_path; /* pointer to the start of a path. */ 67 char *p_end; /* pointer to NULL at end of path. */ 68 } path_t; 69 70 #define type(st) ((st).st_mode&S_IFMT) 71 72 char *path_append(), *path_basename(); 73 void path_restore(); 74 75 int exit_val, symfollow, my_umask; 76 int interactive_flag, preserve_flag, recursive_flag; 77 char *buf; /* I/O; malloc for best alignment. */ 78 char from_buf[MAXPATHLEN + 1], /* Source path buffer. */ 79 to_buf[MAXPATHLEN + 1]; /* Target path buffer. */ 80 path_t from = {from_buf, from_buf}; 81 path_t to = {to_buf, to_buf}; 82 83 main(argc, argv) 84 int argc; 85 char **argv; 86 { 87 extern int optind, errno; 88 struct stat to_stat; 89 register int c, r; 90 int force_flag; 91 char *old_to, *malloc(); 92 93 force_flag = 0; 94 while ((c = getopt(argc, argv, "Rfhipr")) != EOF) { 95 switch ((char)c) { 96 case 'f': 97 force_flag = 1; 98 break; 99 case 'h': 100 symfollow = 1; 101 break; 102 case 'i': 103 interactive_flag = isatty(fileno(stdin)); 104 break; 105 case 'p': 106 preserve_flag = 1; 107 (void)umask(0); 108 break; 109 case 'r': 110 case 'R': 111 recursive_flag = 1; 112 break; 113 case '?': 114 default: 115 usage(); 116 break; 117 } 118 } 119 argc -= optind; 120 argv += optind; 121 122 if (argc < 2) 123 usage(); 124 125 if (force_flag) 126 interactive_flag = 0; 127 128 my_umask = umask(0); 129 (void)umask(my_umask); 130 131 buf = (char *)malloc(MAXBSIZE); 132 if (!buf) { 133 (void)fprintf(stderr, "cp: out of space.\n"); 134 exit(1); 135 } 136 137 /* Consume last argument first. */ 138 if (!path_set(&to, argv[--argc])) 139 exit(exit_val); 140 141 /* 142 * Cp has two distinct cases: 143 * 144 * Case (1) $ cp [-rip] source target 145 * 146 * Case (2) $ cp [-rip] source1 ... directory 147 * 148 * In both cases, source can be either a file or a directory. 149 * 150 * In (1), the target becomes a copy of the source. That is, if the 151 * source is a file, the target will be a file, and likewise for 152 * directories. 153 * 154 * In (2), the real target is not directory, but "directory/source". 155 */ 156 157 r = stat(to.p_path, &to_stat); 158 if (r == -1 && errno != ENOENT) { 159 error(to.p_path, "stat"); 160 exit(1); 161 } 162 if (r == -1 || type(to_stat) != S_IFDIR) { 163 /* 164 * Case (1). Target is not a directory. 165 */ 166 if (argc > 1) { 167 usage(); 168 exit(1); 169 } 170 if (!path_set(&from, *argv)) 171 exit(exit_val); 172 copy(); 173 } 174 else { 175 /* 176 * Case (2). Target is a directory. 177 */ 178 for (; argc; --argc, ++argv) { 179 if (!path_set(&from, *argv)) 180 continue; 181 old_to = path_append(&to, path_basename(&from), -1); 182 if (!old_to) 183 continue; 184 copy(); 185 path_restore(&to, old_to); 186 } 187 } 188 exit(exit_val); 189 } 190 191 /* copy file or directory at "from" to "to". */ 192 copy() 193 { 194 struct stat from_stat, to_stat; 195 int statval; 196 197 statval = symfollow || !recursive_flag ? 198 stat(from.p_path, &from_stat) : lstat(from.p_path, &from_stat); 199 if (statval == -1) { 200 error(from.p_path, "stat"); 201 return; 202 } 203 204 /* not an error, but need to remember it happened */ 205 if (stat(to.p_path, &to_stat) == -1) 206 to_stat.st_ino = -1; 207 else if (to_stat.st_dev == from_stat.st_dev && 208 to_stat.st_ino == from_stat.st_ino) { 209 (void)fprintf(stderr, 210 "cp: %s and %s are identical (not copied).\n", 211 to.p_path, from.p_path); 212 exit_val = 1; 213 return; 214 } 215 216 switch(type(from_stat)) { 217 case S_IFLNK: 218 copy_link(to_stat.st_ino != -1); 219 return; 220 case S_IFDIR: 221 if (!recursive_flag) { 222 (void)fprintf(stderr, 223 "cp: %s is a directory (not copied).\n", 224 from.p_path); 225 exit_val = 1; 226 return; 227 } 228 if (to_stat.st_ino == -1) { 229 if (mkdir(to.p_path, 0777) < 0) { 230 error(to.p_path, "mkdir"); 231 return; 232 } 233 from_stat.st_mode &= ~my_umask; 234 } 235 else if (type(to_stat) != S_IFDIR) { 236 (void)fprintf(stderr, "cp: %s: not a directory.\n", 237 to.p_path); 238 return; 239 } 240 copy_dir(); 241 break; 242 case S_IFCHR: 243 case S_IFBLK: 244 if (recursive_flag) { 245 copy_special(&from_stat, &to_stat); 246 if (preserve_flag) 247 setfile(&from_stat); 248 return; 249 } 250 /* FALLTHROUGH */ 251 default: 252 if (!copy_file(from_stat.st_mode)) 253 return; 254 } 255 if (preserve_flag) 256 setfile(&from_stat); 257 } 258 259 copy_file(mode) 260 u_short mode; /* permissions for new file. */ 261 { 262 register int from_fd, to_fd, rcount, wcount; 263 264 from_fd = open(from.p_path, O_RDONLY, 0); 265 if (from_fd == -1) { 266 error(from.p_path, "open"); 267 (void)close(from_fd); 268 return(0); 269 } 270 271 /* 272 * In the interactive case, use O_EXCL to notice existing files. If 273 * the file exists, verify with the user. 274 */ 275 to_fd = open(to.p_path, 276 (interactive_flag ? O_EXCL : 0) | O_WRONLY | O_CREAT | O_TRUNC, 277 mode); 278 279 if (to_fd == -1 && errno == EEXIST && interactive_flag) { 280 int checkch, ch; 281 282 (void)fprintf(stderr, "overwrite %s? ", to.p_path); 283 checkch = ch = getchar(); 284 while (ch != '\n' && ch != EOF) 285 ch = getchar(); 286 if (checkch != 'y') 287 return(0); 288 /* try again. */ 289 to_fd = open(to.p_path, O_WRONLY | O_CREAT | O_TRUNC, mode); 290 } 291 292 if (to_fd == -1) { 293 error(to.p_path, "open"); 294 (void)close(from_fd); 295 return(0); 296 } 297 298 while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) { 299 wcount = write(to_fd, buf, rcount); 300 if (rcount != wcount || wcount == -1) { 301 error(from.p_path, "write"); 302 break; 303 } 304 } 305 (void)close(from_fd); 306 (void)close(to_fd); 307 return(1); 308 } 309 310 copy_dir() 311 { 312 struct stat from_stat; 313 char *old_from, *old_to; 314 struct direct *dp, **dir_list; 315 int dir_cnt, i; 316 317 dir_cnt = scandir(from.p_path, &dir_list, NULL, NULL); 318 if (dir_cnt == -1) { 319 (void)fprintf(stderr, "cp: can't read directory %s.\n", 320 from.p_path); 321 exit_val = 1; 322 } 323 324 /* Copy files first. */ 325 for (i = 0; i < dir_cnt; ++i) { 326 dp = dir_list[i]; 327 if (dp->d_namlen <= 2 && dp->d_name[0] == '.' 328 && (dp->d_name[1] == NULL || dp->d_name[1] == '.')) { 329 (void)free((char *)dp); 330 dir_list[i] = NULL; 331 continue; 332 } 333 old_from = path_append(&from, dp->d_name, (int)dp->d_namlen); 334 if (!old_from) { 335 dir_list[i] = NULL; 336 (void)free((char *)dp); 337 continue; 338 } 339 340 if (stat(from.p_path, &from_stat) < 0) { 341 error(dp->d_name, "stat"); 342 path_restore(&from, old_from); 343 continue; 344 } 345 346 if (type(from_stat) != S_IFDIR) { 347 old_to = path_append(&to, dp->d_name, 348 (int)dp->d_namlen); 349 if (!old_to) { 350 dir_list[i] = NULL; 351 (void)free((char *)dp); 352 continue; 353 } 354 copy(); 355 path_restore(&to, old_to); 356 dir_list[i] = NULL; 357 (void)free((char *)dp); 358 } 359 path_restore(&from, old_from); 360 } 361 362 /* then copy directories. */ 363 for (i = 0; i < dir_cnt; ++i) { 364 dp = dir_list[i]; 365 if (!dp) 366 continue; 367 old_from = path_append(&from, dp->d_name, (int) dp->d_namlen); 368 if (!old_from) { 369 (void)free((char *)dp); 370 continue; 371 } 372 old_to = path_append(&to, dp->d_name, (int) dp->d_namlen); 373 if (!old_to) { 374 (void)free((char *)dp); 375 path_restore(&from, old_from); 376 continue; 377 } 378 copy(); 379 free((char *)dp); 380 path_restore(&from, old_from); 381 path_restore(&to, old_to); 382 } 383 free((char *)dir_list); 384 } 385 386 copy_link(exists) 387 int exists; 388 { 389 char link[MAXPATHLEN]; 390 391 if (readlink(from.p_path, link, sizeof(link)) == -1) { 392 error(from.p_path, "readlink"); 393 return; 394 } 395 if (exists && unlink(to.p_path)) { 396 error(to.p_path, "unlink"); 397 return; 398 } 399 if (symlink(link, to.p_path)) { 400 error(link, "symlink"); 401 return; 402 } 403 } 404 405 copy_special(from_stat, to_stat) 406 struct stat *from_stat, *to_stat; 407 { 408 if (to_stat->st_ino != -1 && unlink(to.p_path)) { 409 error(to.p_path, "unlink"); 410 return; 411 } 412 if (mknod(to.p_path, from_stat->st_mode, from_stat->st_rdev)) { 413 error(to.p_path, "mknod"); 414 return; 415 } 416 } 417 418 setfile(fs) 419 struct stat *fs; 420 { 421 static struct timeval tv[2]; 422 423 if (chown(to.p_path, fs->st_uid, fs->st_gid)) 424 error(to.p_path, "chown"); 425 if (chmod(to.p_path, fs->st_mode)) 426 error(to.p_path, "chmod"); 427 tv[0].tv_sec = fs->st_atime; 428 tv[1].tv_sec = fs->st_mtime; 429 if (utimes(to.p_path, tv)) 430 error(to.p_path, "utimes"); 431 } 432 433 error(s, call) 434 char *s, *call; 435 { 436 extern int errno; 437 438 exit_val = 1; 439 (void)fprintf(stderr, "cp: %s: %s: %s\n", call, s, strerror(errno)); 440 } 441 442 /******************************************************************** 443 * Path Manipulation Routines. 444 ********************************************************************/ 445 446 /* 447 * These functions manipulate paths in "path_t" structures. 448 * 449 * They eliminate multiple slashes in paths when they notice them, and keep 450 * the path non-slash terminated. 451 * 452 * Both path_set() and path_append() return 0 if the requested name 453 * would be too long. 454 */ 455 456 #define STRIP_TRAILING_SLASH(p) { \ 457 while ((p)->p_end > (p)->p_path && (p)->p_end[-1] == '/') \ 458 *--(p)->p_end = 0; \ 459 } 460 461 /* 462 * Move specified string into path. Convert "" to "." to handle BSD 463 * semantics for a null path. Strip trailing slashes. 464 */ 465 path_set(p, string) 466 register path_t *p; 467 char *string; 468 { 469 if (strlen(string) > MAXPATHLEN) { 470 fprintf(stderr, "cp: %s: name too long.\n", string); 471 exit_val = 1; 472 return(0); 473 } 474 475 (void)strcpy(p->p_path, string); 476 p->p_end = p->p_path + strlen(p->p_path); 477 478 if (p->p_path == p->p_end) { 479 *p->p_end++ = '.'; 480 *p->p_end = 0; 481 } 482 483 STRIP_TRAILING_SLASH(p); 484 return(1); 485 } 486 487 /* 488 * Append specified string to path, inserting '/' if necessary. Return a 489 * pointer to the old end of path for restoration. 490 */ 491 char * 492 path_append(p, name, len) 493 register path_t *p; 494 char *name; 495 int len; 496 { 497 char *old; 498 499 old = p->p_end; 500 if (len == -1) 501 len = strlen(name); 502 503 /* 504 * The final "+ 1" accounts for the '/' between old path and name. 505 */ 506 if ((len + p->p_end - p->p_path + 1) > MAXPATHLEN) { 507 fprintf(stderr, 508 "cp: %s/%s: name too long.\n", p->p_path, name); 509 exit_val = 1; 510 return(0); 511 } 512 513 /* 514 * This code should always be executed, since paths shouldn't 515 * end in '/'. 516 */ 517 if (p->p_end[-1] != '/') { 518 *p->p_end++ = '/'; 519 *p->p_end = 0; 520 } 521 522 (void)strncat(p->p_end, name, len); 523 p->p_end += len; 524 *p->p_end = 0; 525 526 STRIP_TRAILING_SLASH(p); 527 return(old); 528 } 529 530 /* 531 * Restore path to previous value. (As returned by path_append.) 532 */ 533 void 534 path_restore(p, old) 535 path_t *p; 536 char *old; 537 { 538 p->p_end = old; 539 *p->p_end = 0; 540 } 541 542 /* 543 * Return basename of path. (Like basename(1).) 544 */ 545 char * 546 path_basename(p) 547 path_t *p; 548 { 549 char *basename; 550 551 basename = rindex(p->p_path, '/'); 552 if (!basename) 553 basename = p->p_path; 554 return(basename); 555 } 556 557 usage() 558 { 559 (void)fprintf(stderr, 560 "usage: cp [-ip] f1 f2; or: cp [-irp] f1 ... fn directory\n"); 561 exit(1); 562 } 563