add getopt for "--" capability
[unix-history] / usr / src / bin / cp / cp.c
index 0a13c4c..98872f0 100644 (file)
@@ -1,6 +1,18 @@
+/*
+ * Copyright (c) 1983 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif not lint
+
 #ifndef lint
 #ifndef lint
-static char *sccsid = "@(#)cp.c        4.7 83/06/20";
-#endif
+static char sccsid[] = "@(#)cp.c       4.14 (Berkeley) %G%";
+#endif not lint
 
 /*
  * cp
 
 /*
  * cp
@@ -8,13 +20,13 @@ static char *sccsid = "@(#)cp.c      4.7 83/06/20";
 #include <stdio.h>
 #include <sys/param.h>
 #include <sys/stat.h>
 #include <stdio.h>
 #include <sys/param.h>
 #include <sys/stat.h>
-#include <dir.h>
-
-#define        BSIZE   8192
+#include <sys/dir.h>
+#include <sys/time.h>
 
 int    iflag;
 int    rflag;
 
 int    iflag;
 int    rflag;
-char   *rindex(), *sprintf();
+int    pflag;
+char   *rindex();
 
 main(argc, argv)
        int argc;
 
 main(argc, argv)
        int argc;
@@ -31,9 +43,15 @@ main(argc, argv)
                case 'i':
                        iflag++; break;
 
                case 'i':
                        iflag++; break;
 
+               case 'R':
                case 'r':
                        rflag++; break;
 
                case 'r':
                        rflag++; break;
 
+               case 'p':       /* preserve mtimes, atimes, and modes */
+                       pflag++;
+                       (void) umask(0);
+                       break;
+
                default:
                        goto usage;
                }
                default:
                        goto usage;
                }
@@ -41,7 +59,7 @@ main(argc, argv)
        }
        if (argc < 2) 
                goto usage;
        }
        if (argc < 2) 
                goto usage;
-       if (argc > 2 || rflag) {
+       if (argc > 2) {
                if (stat(argv[argc-1], &stb) < 0)
                        goto usage;
                if ((stb.st_mode&S_IFMT) != S_IFDIR) 
                if (stat(argv[argc-1], &stb) < 0)
                        goto usage;
                if ((stb.st_mode&S_IFMT) != S_IFDIR) 
@@ -53,15 +71,18 @@ main(argc, argv)
        exit(rc);
 usage:
        fprintf(stderr,
        exit(rc);
 usage:
        fprintf(stderr,
-           "Usage: cp f1 f2; or cp [ -r ] f1 ... fn d2\n");
+           "Usage: cp [-ip] f1 f2; or: cp [-irp] f1 ... fn d2\n");
        exit(1);
 }
 
        exit(1);
 }
 
+                       /* I/O buffer; guarantee long-word alignment */
+static char    buf[MAXBSIZE];
+
 copy(from, to)
        char *from, *to;
 {
 copy(from, to)
        char *from, *to;
 {
-       int fold, fnew, n;
-       char *last, destname[BSIZE], buf[BSIZE];
+       int fold, fnew, n, exists;
+       char *last, destname[MAXPATHLEN + 1];
        struct stat stfrom, stto;
 
        fold = open(from, 0);
        struct stat stfrom, stto;
 
        fold = open(from, 0);
@@ -78,7 +99,7 @@ copy(from, to)
           (stto.st_mode&S_IFMT) == S_IFDIR) {
                last = rindex(from, '/');
                if (last) last++; else last = from;
           (stto.st_mode&S_IFMT) == S_IFDIR) {
                last = rindex(from, '/');
                if (last) last++; else last = from;
-               if (strlen(to) + strlen(last) >= BSIZE - 1) {
+               if (strlen(to) + strlen(last) >= sizeof destname - 1) {
                        fprintf(stderr, "cp: %s/%s: Name too long", to, last);
                        (void) close(fold);
                        return(1);
                        fprintf(stderr, "cp: %s/%s: Name too long", to, last);
                        (void) close(fold);
                        return(1);
@@ -87,26 +108,42 @@ copy(from, to)
                to = destname;
        }
        if (rflag && (stfrom.st_mode&S_IFMT) == S_IFDIR) {
                to = destname;
        }
        if (rflag && (stfrom.st_mode&S_IFMT) == S_IFDIR) {
+               int fixmode = 0;        /* cleanup mode after rcopy */
+
                (void) close(fold);
                if (stat(to, &stto) < 0) {
                (void) close(fold);
                if (stat(to, &stto) < 0) {
-                       if (mkdir(to, (int)stfrom.st_mode) < 0) {
+                       if (mkdir(to, (stfrom.st_mode & 07777) | 0700) < 0) {
                                Perror(to);
                                return (1);
                        }
                                Perror(to);
                                return (1);
                        }
+                       fixmode = 1;
                } else if ((stto.st_mode&S_IFMT) != S_IFDIR) {
                        fprintf(stderr, "cp: %s: Not a directory.\n", to);
                        return (1);
                } else if ((stto.st_mode&S_IFMT) != S_IFDIR) {
                        fprintf(stderr, "cp: %s: Not a directory.\n", to);
                        return (1);
-               }
-               return (rcopy(from, to));
+               } else if (pflag)
+                       fixmode = 1;
+               n = rcopy(from, to);
+               if (fixmode)
+                       (void) chmod(to, stfrom.st_mode & 07777);
+               return (n);
        }
        }
-       if (stat(to, &stto) >= 0) {
+
+       if ((stfrom.st_mode&S_IFMT) == S_IFDIR)
+               fprintf(stderr,
+                       "cp: %s: Is a directory (copying as plain file).\n",
+                               from);
+
+       exists = stat(to, &stto) == 0;
+       if (exists) {
                if (stfrom.st_dev == stto.st_dev &&
                   stfrom.st_ino == stto.st_ino) {
                if (stfrom.st_dev == stto.st_dev &&
                   stfrom.st_ino == stto.st_ino) {
-                       fprintf(stderr, "cp: Cannot copy file to itself.\n");
+                       fprintf(stderr,
+                               "cp: %s and %s are identical (not copied).\n",
+                                       from, to);
                        (void) close(fold);
                        return (1);
                }
                        (void) close(fold);
                        return (1);
                }
-               if (iflag) {
+               if (iflag && isatty(fileno(stdin))) {
                        int i, c;
 
                        fprintf (stderr, "overwrite %s? ", to);
                        int i, c;
 
                        fprintf (stderr, "overwrite %s? ", to);
@@ -119,13 +156,16 @@ copy(from, to)
                        }
                }
        }
                        }
                }
        }
-       fnew = creat(to, (int)stfrom.st_mode);
+       fnew = creat(to, stfrom.st_mode & 07777);
        if (fnew < 0) {
                Perror(to);
                (void) close(fold); return(1);
        }
        if (fnew < 0) {
                Perror(to);
                (void) close(fold); return(1);
        }
+       if (exists && pflag)
+               (void) fchmod(fnew, stfrom.st_mode & 07777);
+                       
        for (;;) {
        for (;;) {
-               n = read(fold, buf, BSIZE);
+               n = read(fold, buf, sizeof buf);
                if (n == 0)
                        break;
                if (n < 0) {
                if (n == 0)
                        break;
                if (n < 0) {
@@ -137,7 +177,10 @@ copy(from, to)
                        (void) close(fold); (void) close(fnew); return (1);
                }
        }
                        (void) close(fold); (void) close(fnew); return (1);
                }
        }
-       (void) close(fold); (void) close(fnew); return (0);
+       (void) close(fold); (void) close(fnew); 
+       if (pflag)
+               return (setimes(to, &stfrom));
+       return (0);
 }
 
 rcopy(from, to)
 }
 
 rcopy(from, to)
@@ -145,10 +188,11 @@ rcopy(from, to)
 {
        DIR *fold = opendir(from);
        struct direct *dp;
 {
        DIR *fold = opendir(from);
        struct direct *dp;
+       struct stat statb;
        int errs = 0;
        int errs = 0;
-       char fromname[BUFSIZ];
+       char fromname[MAXPATHLEN + 1];
 
 
-       if (fold == 0) {
+       if (fold == 0 || (pflag && fstat(fold->dd_fd, &statb) < 0)) {
                Perror(from);
                return (1);
        }
                Perror(from);
                return (1);
        }
@@ -156,13 +200,15 @@ rcopy(from, to)
                dp = readdir(fold);
                if (dp == 0) {
                        closedir(fold);
                dp = readdir(fold);
                if (dp == 0) {
                        closedir(fold);
+                       if (pflag)
+                               return (setimes(to, &statb) + errs);
                        return (errs);
                }
                if (dp->d_ino == 0)
                        continue;
                if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
                        continue;
                        return (errs);
                }
                if (dp->d_ino == 0)
                        continue;
                if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
                        continue;
-               if (strlen(from) + 1 + strlen(dp->d_name) >= BUFSIZ - 1) {
+               if (strlen(from)+1+strlen(dp->d_name) >= sizeof fromname - 1) {
                        fprintf(stderr, "cp: %s/%s: Name too long.\n",
                            from, dp->d_name);
                        errs++;
                        fprintf(stderr, "cp: %s/%s: Name too long.\n",
                            from, dp->d_name);
                        errs++;
@@ -173,6 +219,23 @@ rcopy(from, to)
        }
 }
 
        }
 }
 
+int
+setimes(path, statp)
+       char *path;
+       struct stat *statp;
+{
+       struct timeval tv[2];
+       
+       tv[0].tv_sec = statp->st_atime;
+       tv[1].tv_sec = statp->st_mtime;
+       tv[0].tv_usec = tv[1].tv_usec = 0;
+       if (utimes(path, tv) < 0) {
+               Perror(path);
+               return (1);
+       }
+       return (0);
+}
+
 Perror(s)
        char *s;
 {
 Perror(s)
        char *s;
 {