home *** CD-ROM | disk | FTP | other *** search
/ minnie.tuhs.org / unixen.tar / unixen / PDP-11 / Trees / V7 / usr / src / cmd / mv.c < prev    next >
Encoding:
C/C++ Source or Header  |  1979-01-10  |  6.1 KB  |  298 lines

  1. /*
  2.  * mv file1 file2
  3.  */
  4.  
  5. #include <stdio.h>
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <sys/dir.h>
  9. #include <signal.h>
  10.  
  11. #define    DOT    "."
  12. #define    DOTDOT    ".."
  13. #define    DELIM    '/'
  14. #define SDELIM "/"
  15. #define    MAXN    100
  16. #define MODEBITS 07777
  17. #define ROOTINO 2
  18.  
  19. char    *pname();
  20. char    *sprintf();
  21. char    *dname();
  22. struct    stat s1, s2;
  23.  
  24. main(argc, argv)
  25. register char *argv[];
  26. {
  27.     register i, r;
  28.  
  29.     if (argc < 3)
  30.         goto usage;
  31.     if (stat(argv[1], &s1) < 0) {
  32.         fprintf(stderr, "mv: cannot access %s\n", argv[1]);
  33.         return(1);
  34.     }
  35.     if ((s1.st_mode & S_IFMT) == S_IFDIR) {
  36.         if (argc != 3)
  37.             goto usage;
  38.         return mvdir(argv[1], argv[2]);
  39.     }
  40.     setuid(getuid());
  41.     if (argc > 3)
  42.         if (stat(argv[argc-1], &s2) < 0 || (s2.st_mode & S_IFMT) != S_IFDIR)
  43.             goto usage;
  44.     r = 0;
  45.     for (i=1; i<argc-1; i++)
  46.         r |= move(argv[i], argv[argc-1]);
  47.     return(r);
  48. usage:
  49.     fprintf(stderr, "usage: mv f1 f2; or mv d1 d2; or mv f1 ... fn d1\n");
  50.     return(1);
  51. }
  52.  
  53. move(source, target)
  54. char *source, *target;
  55. {
  56.     register c, i;
  57.     int    status;
  58.     char    buf[MAXN];
  59.  
  60.     if (stat(source, &s1) < 0) {
  61.         fprintf(stderr, "mv: cannot access %s\n", source);
  62.         return(1);
  63.     }
  64.     if ((s1.st_mode & S_IFMT) == S_IFDIR) {
  65.         fprintf(stderr, "mv: directory rename only\n");
  66.         return(1);
  67.     }
  68.     if (stat(target, &s2) >= 0) {
  69.         if ((s2.st_mode & S_IFMT) == S_IFDIR) {
  70.             sprintf(buf, "%s/%s", target, dname(source));
  71.             target = buf;
  72.         }
  73.         if (stat(target, &s2) >= 0) {
  74.             if ((s2.st_mode & S_IFMT) == S_IFDIR) {
  75.                 fprintf(stderr, "mv: %s is a directory\n", target);
  76.                 return(1);
  77.             }
  78.             if (s1.st_dev==s2.st_dev && s1.st_ino==s2.st_ino) {
  79.                 fprintf(stderr, "mv: %s and %s are identical\n",
  80.                         source, target);
  81.                 return(1);
  82.             }
  83.             if (access(target, 2) < 0 && isatty(fileno(stdin))) {
  84.                 fprintf(stderr, "mv: %s: %o mode ", target,
  85.                     s2.st_mode & MODEBITS);
  86.                 i = c = getchar();
  87.                 while (c != '\n' && c != EOF)
  88.                     c = getchar();
  89.                 if (i != 'y')
  90.                     return(1);
  91.             }
  92.             if (unlink(target) < 0) {
  93.                 fprintf(stderr, "mv: cannot unlink %s\n", target);
  94.                 return(1);
  95.             }
  96.         }
  97.     }
  98.     if (link(source, target) < 0) {
  99.         i = fork();
  100.         if (i == -1) {
  101.             fprintf(stderr, "mv: try again\n");
  102.             return(1);
  103.         }
  104.         if (i == 0) {
  105.             execl("/bin/cp", "cp", source, target, 0);
  106.             fprintf(stderr, "mv: cannot exec cp\n");
  107.             exit(1);
  108.         }
  109.         while ((c = wait(&status)) != i && c != -1)
  110.             ;
  111.         if (status != 0)
  112.             return(1);
  113.         utime(target, &s1.st_atime);
  114.     }
  115.     if (unlink(source) < 0) {
  116.         fprintf(stderr, "mv: cannot unlink %s\n", source);
  117.         return(1);
  118.     }
  119.     return(0);
  120. }
  121.  
  122. mvdir(source, target)
  123. char *source, *target;
  124. {
  125.     register char *p;
  126.     register i;
  127.     char buf[MAXN];
  128.  
  129.     if (stat(target, &s2) >= 0) {
  130.         if ((s2.st_mode&S_IFMT) != S_IFDIR) {
  131.             fprintf(stderr, "mv: %s exists\n", target);
  132.             return(1);
  133.         }
  134.         if (strlen(target) > MAXN-DIRSIZ-2) {
  135.             fprintf(stderr, "mv :target name too long\n");
  136.             return(1);
  137.         }
  138.         strcpy(buf, target);
  139.         target = buf;
  140.         strcat(buf, SDELIM);
  141.         strcat(buf, dname(source));
  142.         if (stat(target, &s2) >= 0) {
  143.             fprintf(stderr, "mv: %s exists\n", buf);
  144.             return(1);
  145.         }
  146.     }
  147.     if (strcmp(source, target) == 0) {
  148.         fprintf(stderr, "mv: ?? source == target, source exists and target doesnt\n");
  149.         return(1);
  150.     }
  151.     p = dname(source);
  152.     if (!strcmp(p, DOT) || !strcmp(p, DOTDOT) || !strcmp(p, "") || p[strlen(p)-1]=='/') {
  153.         fprintf(stderr, "mv: cannot rename %s\n", p);
  154.         return(1);
  155.     }
  156.     if (stat(pname(source), &s1) < 0 || stat(pname(target), &s2) < 0) {
  157.         fprintf(stderr, "mv: cannot locate parent\n");
  158.         return(1);
  159.     }
  160.     if (access(pname(target), 2) < 0) {
  161.         fprintf(stderr, "mv: no write access to %s\n", pname(target));
  162.         return(1);
  163.     }
  164.     if (access(pname(source), 2) < 0) {
  165.         fprintf(stderr, "mv: no write access to %s\n", pname(source));
  166.         return(1);
  167.     }
  168.     if (access(source, 2) < 0) {
  169.         fprintf(stderr, "mv: no write access to %s\n", source);
  170.         return(1);
  171.     }
  172.     if (s1.st_dev != s2.st_dev) {
  173.         fprintf(stderr, "mv: cannot move directories across devices\n");
  174.         return(1);
  175.     }
  176.     if (s1.st_ino != s2.st_ino) {
  177.         char dst[MAXN+5];
  178.  
  179.         if (chkdot(source) || chkdot(target)) {
  180.             fprintf(stderr, "mv: Sorry, path names including %s aren't allowed\n", DOTDOT);
  181.             return(1);
  182.         }
  183.         stat(source, &s1);
  184.         if (check(pname(target), s1.st_ino))
  185.             return(1);
  186.         for (i = 1; i <= NSIG; i++)
  187.             signal(i, SIG_IGN);
  188.         if (link(source, target) < 0) {
  189.             fprintf(stderr, "mv: cannot link %s to %s\n", target, source);
  190.             return(1);
  191.         }
  192.         if (unlink(source) < 0) {
  193.             fprintf(stderr, "mv: %s: cannot unlink\n", source);
  194.             unlink(target);
  195.             return(1);
  196.         }
  197.         strcat(dst, target);
  198.         strcat(dst, "/");
  199.         strcat(dst, DOTDOT);
  200.         if (unlink(dst) < 0) {
  201.             fprintf(stderr, "mv: %s: cannot unlink\n", dst);
  202.             if (link(target, source) >= 0)
  203.                 unlink(target);
  204.             return(1);
  205.         }
  206.         if (link(pname(target), dst) < 0) {
  207.             fprintf(stderr, "mv: cannot link %s to %s\n",
  208.                 dst, pname(target));
  209.             if (link(pname(source), dst) >= 0)
  210.                 if (link(target, source) >= 0)
  211.                     unlink(target);
  212.             return(1);
  213.         }
  214.         return(0);
  215.     }
  216.     if (link(source, target) < 0) {
  217.         fprintf(stderr, "mv: cannot link %s and %s\n",
  218.             source, target);
  219.         return(1);
  220.     }
  221.     if (unlink(source) < 0) {
  222.         fprintf(stderr, "mv: ?? cannot unlink %s\n", source);
  223.         return(1);
  224.     }
  225.     return(0);
  226. }
  227.  
  228. char *
  229. pname(name)
  230. register char *name;
  231. {
  232.     register c;
  233.     register char *p, *q;
  234.     static    char buf[MAXN];
  235.  
  236.     p = q = buf;
  237.     while (c = *p++ = *name++)
  238.         if (c == DELIM)
  239.             q = p-1;
  240.     if (q == buf && *q == DELIM)
  241.         q++;
  242.     *q = 0;
  243.     return buf[0]? buf : DOT;
  244. }
  245.  
  246. char *
  247. dname(name)
  248. register char *name;
  249. {
  250.     register char *p;
  251.  
  252.     p = name;
  253.     while (*p)
  254.         if (*p++ == DELIM && *p)
  255.             name = p;
  256.     return name;
  257. }
  258.  
  259. check(spth, dinode)
  260. char *spth;
  261. ino_t dinode;
  262. {
  263.     char nspth[MAXN];
  264.     struct stat sbuf;
  265.  
  266.     sbuf.st_ino = 0;
  267.  
  268.     strcpy(nspth, spth);
  269.     while (sbuf.st_ino != ROOTINO) {
  270.         if (stat(nspth, &sbuf) < 0) {
  271.             fprintf(stderr, "mv: cannot access %s\n", nspth);
  272.             return(1);
  273.         }
  274.         if (sbuf.st_ino == dinode) {
  275.             fprintf(stderr, "mv: cannot move a directory into itself\n");
  276.             return(1);
  277.         }
  278.         if (strlen(nspth) > MAXN-2-sizeof(DOTDOT)) {
  279.             fprintf(stderr, "mv: name too long\n");
  280.             return(1);
  281.         }
  282.         strcat(nspth, SDELIM);
  283.         strcat(nspth, DOTDOT);
  284.     }
  285.     return(0);
  286. }
  287.  
  288. chkdot(s)
  289. register char *s;
  290. {
  291.     do {
  292.         if (strcmp(dname(s), DOTDOT) == 0)
  293.             return(1);
  294.         s = pname(s);
  295.     } while (strcmp(s, DOT) != 0 && strcmp(s, SDELIM) != 0);
  296.     return(0);
  297. }
  298.