date and time created 88/10/18 22:07:11 by bostic
[unix-history] / usr / src / bin / mv / mv.c
index 8198014..69801c4 100644 (file)
@@ -1,17 +1,28 @@
+/*
+ * Copyright (c) 1980 Regents of the University of California.
+ * All rights reserved.  The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ */
+
 #ifndef lint
 #ifndef lint
-static char *sccsid = "@(#)mv.c        4.8 (Berkeley) 83/01/03";
-#endif
+char copyright[] =
+"@(#) Copyright (c) 1980 Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)mv.c       5.7 (Berkeley) %G%";
+#endif /* not lint */
 
 /*
  * mv file1 file2
  */
 #include <sys/param.h>
 #include <sys/stat.h>
 
 /*
  * mv file1 file2
  */
 #include <sys/param.h>
 #include <sys/stat.h>
-
+#include <sys/time.h>
+#include <sys/file.h>
 #include <stdio.h>
 #include <stdio.h>
-#include <dir.h>
 #include <errno.h>
 #include <errno.h>
-#include <signal.h>
 
 #define        DELIM   '/'
 #define MODEBITS 07777
 
 #define        DELIM   '/'
 #define MODEBITS 07777
@@ -22,73 +33,49 @@ static      char *sccsid = "@(#)mv.c        4.8 (Berkeley) 83/01/03";
 #define        ISDEV(st) \
        (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK)
 
 #define        ISDEV(st) \
        (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK)
 
-char   *sprintf();
 char   *dname();
 char   *dname();
-struct stat s1, s2;
 int    iflag = 0;      /* interactive mode */
 int    fflag = 0;      /* force overwriting */
 extern unsigned errno;
 
 main(argc, argv)
 int    iflag = 0;      /* interactive mode */
 int    fflag = 0;      /* force overwriting */
 extern unsigned errno;
 
 main(argc, argv)
-       register char *argv[];
+       register int argc;
+       register char **argv;
 {
 {
-       register i, r;
-       register char *arg;
+       extern int optind;
+       struct stat st;
+       int ch, r;
+       char *dest;
 
 
-       if (argc < 2)
-               goto usage;
-       while (argc > 1 && *argv[1] == '-') {
-               argc--;
-               arg = *++argv;
-
-               /*
-                * all files following a null option
-                * are considered file names
-                */
-               if (*(arg+1) == '\0')
+       while ((ch = getopt(argc, argv, "-fi")) != EOF)
+               switch((char)ch) {
+               case '-':
+                       goto endarg;
+               case 'f':
+                       fflag++;
                        break;
                        break;
-               while (*++arg != '\0') switch (*arg) {
-
                case 'i':
                        iflag++;
                        break;
                case 'i':
                        iflag++;
                        break;
-
-               case 'f':
-                       fflag++;
-                       break;
-
+               case '?':
                default:
                default:
-                       goto usage;
+                       usage();
                }
                }
-       }
-       if (argc < 3)
-               goto usage;
-       if (argc > 3) {
-               register char *dest;
-
-               dest = argv[argc-1];
-               if (stat(dest, &s2) < 0 || !ISDIR(s2))
-                       goto usage;
-               r = 0;
-               for (i = 1; i < argc-1; i++)
-                       r |= movewithshortname(argv[i], dest);
+endarg:        argv += optind;
+       argc -= optind;
+
+       if (argc < 2)
+               usage();
+       dest = argv[argc - 1];
+       if (stat(dest, &st) >= 0 && ISDIR(st)) {
+               for (r = 0; --argc; ++argv)
+                       r |= movewithshortname(*argv, dest);
                exit(r);
        }
                exit(r);
        }
-       if (lstat(argv[2], &s2) >= 0 && ISDIR(s2)) {
-               struct stat s1;
-
-               if (lstat(argv[1], &s1) >= 0 && ISDIR(s1))
-                       r = move(argv[1], argv[2]);
-               else
-                       r = movewithshortname(argv[1], argv[2]);
-       } else
-               r = move(argv[1], argv[2]);
+       if (argc != 2)
+               usage();
+       r = move(argv[0], argv[1]);
        exit(r);
        exit(r);
-       /*NOTREACHED*/
-usage:
-       fprintf(stderr,
-"usage: mv [-if] f1 ... fn d1 (where `fn' is a file or directory)\n");
-       return (1);
 }
 
 movewithshortname(src, dest)
 }
 
 movewithshortname(src, dest)
@@ -103,16 +90,18 @@ movewithshortname(src, dest)
                        shortname);
                return (1);
        }
                        shortname);
                return (1);
        }
-       sprintf(target, "%s/%s", dest, shortname);
+       (void)sprintf(target, "%s/%s", dest, shortname);
        return (move(src, target));
 }
 
 move(source, target)
        char *source, *target;
 {
        return (move(src, target));
 }
 
 move(source, target)
        char *source, *target;
 {
+       int targetexists;
+       struct stat s1, s2;
 
        if (lstat(source, &s1) < 0) {
 
        if (lstat(source, &s1) < 0) {
-               error("cannot access %s", source);
+               Perror2(source, "Cannot access");
                return (1);
        }
        /*
                return (1);
        }
        /*
@@ -121,39 +110,36 @@ move(source, target)
         * the move is on a nondirectory and not across
         * file systems.
         */
         * the move is on a nondirectory and not across
         * file systems.
         */
-       if (lstat(target, &s2) >= 0) {
-               if (iflag && !fflag && query("remove %s? ", target) == 0)
-                       return (1);
+       targetexists = lstat(target, &s2) >= 0;
+       if (targetexists) {
                if (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino) {
                        error("%s and %s are identical", source, target);
                        return (1);
                }
                if (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino) {
                        error("%s and %s are identical", source, target);
                        return (1);
                }
-               if (access(target, 2) < 0 && !fflag && isatty(fileno(stdin))) {
-                       if (query("override protection %o for %s? ",
-                         s2.st_mode & MODEBITS, target) == 0)
+               if (!fflag && isatty(fileno(stdin)))
+                       if (iflag) {
+                               if (!query("remove %s? ", target))
+                                       return (1);
+                       }
+                       else if (access(target, W_OK) < 0 &&
+                           !query("override protection %o for %s? ",
+                           s2.st_mode & MODEBITS, target))
                                return (1);
                                return (1);
-               }
-               if (rename(source, target) >= 0)
-                       return (0);
-               if (errno != EXDEV) {
-                       Perror2(source, "rename");
-                       return (1);
-               }
-               if (ISDIR(s1)) {
-                       error("can't mv directories across file systems");
-                       return (1);
-               }
-               if (unlink(target) < 0) {
-                       error("cannot unlink %s", target);
-                       return (1);
-               }
-       } else {
-               if (rename(source, target) >= 0)
-                       return (0);
-               if (ISDIR(s1)) {
-                       Perror2(source, "rename");
-                       return (1);
-               }
+       }
+       if (rename(source, target) >= 0)
+               return (0);
+       if (errno != EXDEV) {
+               Perror2(errno == ENOENT && targetexists == 0 ? target : source,
+                   "rename");
+               return (1);
+       }
+       if (ISDIR(s1)) {
+               error("can't mv directories across file systems");
+               return (1);
+       }
+       if (targetexists && unlink(target) < 0) {
+               Perror2(target, "Cannot unlink");
+               return (1);
        }
        /*
         * File can't be renamed, try to recreate the symbolic
        }
        /*
         * File can't be renamed, try to recreate the symbolic
@@ -162,46 +148,81 @@ move(source, target)
         */
        if (ISLNK(s1)) {
                register m;
         */
        if (ISLNK(s1)) {
                register m;
-               char symln[MAXPATHLEN];
+               char symln[MAXPATHLEN + 1];
 
 
-               if (readlink(source, symln, sizeof (symln)) < 0) {
+               m = readlink(source, symln, sizeof (symln) - 1);
+               if (m < 0) {
                        Perror(source);
                        return (1);
                }
                        Perror(source);
                        return (1);
                }
-               m = umask(~(s1.st_mode & MODEBITS));
+               symln[m] = '\0';
+
+               (void) umask(~(s1.st_mode & MODEBITS));
                if (symlink(symln, target) < 0) {
                        Perror(target);
                        return (1);
                }
                if (symlink(symln, target) < 0) {
                        Perror(target);
                        return (1);
                }
-               (void) umask(m);
                goto cleanup;
        }
                goto cleanup;
        }
+       (void) umask(0);
        if (ISDEV(s1)) {
        if (ISDEV(s1)) {
+               struct timeval tv[2];
+
                if (mknod(target, s1.st_mode, s1.st_rdev) < 0) {
                        Perror(target);
                        return (1);
                }
                if (mknod(target, s1.st_mode, s1.st_rdev) < 0) {
                        Perror(target);
                        return (1);
                }
-               (void) utime(target, &s1.st_atime);
+
+               tv[0].tv_sec = s1.st_atime;
+               tv[0].tv_usec = 0;
+               tv[1].tv_sec = s1.st_mtime;
+               tv[1].tv_usec = 0;
+               (void) utimes(target, tv);
                goto cleanup;
        }
        if (ISREG(s1)) {
                goto cleanup;
        }
        if (ISREG(s1)) {
-               int i, c, status;
+               register int fi, fo, n;
+               struct timeval tv[2];
+               char buf[MAXBSIZE];
 
 
-               i = fork();
-               if (i == -1) {
-                       error("try again");
+               fi = open(source, 0);
+               if (fi < 0) {
+                       Perror(source);
                        return (1);
                }
                        return (1);
                }
-               if (i == 0) {
-                       execl("/bin/cp", "cp", source, target, 0);
-                       error("cannot exec /bin/cp");
-                       exit(1);
-               }
-               while ((c = wait(&status)) != i && c != -1)
-                       ;
-               if (status != 0)
+
+               fo = creat(target, s1.st_mode & MODEBITS);
+               if (fo < 0) {
+                       Perror(target);
+                       close(fi);
                        return (1);
                        return (1);
-               (void) utime(target, &s1.st_atime);
+               }
+
+               for (;;) {
+                       n = read(fi, buf, sizeof buf);
+                       if (n == 0) {
+                               break;
+                       } else if (n < 0) {
+                               Perror2(source, "read");
+                               close(fi);
+                               close(fo);
+                               return (1);
+                       } else if (write(fo, buf, n) != n) {
+                               Perror2(target, "write");
+                               close(fi);
+                               close(fo);
+                               return (1);
+                       }
+               }
+
+               close(fi);
+               close(fo);
+
+               tv[0].tv_sec = s1.st_atime;
+               tv[0].tv_usec = 0;
+               tv[1].tv_sec = s1.st_mtime;
+               tv[1].tv_usec = 0;
+               (void) utimes(target, tv);
                goto cleanup;
        }
        error("%s: unknown file type %o", source, s1.st_mode);
                goto cleanup;
        }
        error("%s: unknown file type %o", source, s1.st_mode);
@@ -209,7 +230,7 @@ move(source, target)
 
 cleanup:
        if (unlink(source) < 0) {
 
 cleanup:
        if (unlink(source) < 0) {
-               error("cannot unlink %s", source);
+               Perror2(source, "Cannot unlink");
                return (1);
        }
        return (0);
                return (1);
        }
        return (0);
@@ -219,7 +240,7 @@ cleanup:
 query(prompt, a1, a2)
        char *a1;
 {
 query(prompt, a1, a2)
        char *a1;
 {
-       register char i, c;
+       register int i, c;
 
        fprintf(stderr, prompt, a1, a2);
        i = c = getchar();
 
        fprintf(stderr, prompt, a1, a2);
        i = c = getchar();
@@ -255,8 +276,8 @@ Perror(s)
        char *s;
 {
        char buf[MAXPATHLEN + 10];
        char *s;
 {
        char buf[MAXPATHLEN + 10];
-       
-       sprintf(buf, "mv: %s", s);
+
+       (void)sprintf(buf, "mv: %s", s);
        perror(buf);
 }
 
        perror(buf);
 }
 
@@ -265,6 +286,12 @@ Perror2(s1, s2)
 {
        char buf[MAXPATHLEN + 20];
 
 {
        char buf[MAXPATHLEN + 20];
 
-       sprintf(buf, "mv: %s: %s", s1, s2);
+       (void)sprintf(buf, "mv: %s: %s", s1, s2);
        perror(buf);
 }
        perror(buf);
 }
+
+usage()
+{
+       fputs("usage: mv [-if] file1 file2 or mv [-if] file/directory ... directory\n", stderr);
+       exit(1);
+}