1: /*
   2:  * Copyright (c) 1980 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #ifndef lint
   8: char copyright[] =
   9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\
  10:  All rights reserved.\n";
  11: #endif not lint
  12: 
  13: #ifndef lint
  14: static char sccsid[] = "@(#)mv.c	5.3 (Berkeley) 5/15/86";
  15: #endif not lint
  16: 
  17: /*
  18:  * mv file1 file2
  19:  */
  20: #include <sys/param.h>
  21: #include <sys/stat.h>
  22: #include <sys/time.h>
  23: 
  24: #include <stdio.h>
  25: #include <sys/dir.h>
  26: #include <errno.h>
  27: #include <signal.h>
  28: 
  29: #define DELIM   '/'
  30: #define MODEBITS 07777
  31: 
  32: #define ISDIR(st)   (((st).st_mode&S_IFMT) == S_IFDIR)
  33: #define ISLNK(st)   (((st).st_mode&S_IFMT) == S_IFLNK)
  34: #define ISREG(st)   (((st).st_mode&S_IFMT) == S_IFREG)
  35: #define ISDEV(st) \
  36:     (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK)
  37: 
  38: char    *sprintf();
  39: char    *dname();
  40: struct  stat s1, s2;
  41: int iflag = 0;  /* interactive mode */
  42: int fflag = 0;  /* force overwriting */
  43: extern  unsigned errno;
  44: 
  45: main(argc, argv)
  46:     register char *argv[];
  47: {
  48:     register i, r;
  49:     register char *arg;
  50:     char *dest;
  51: 
  52:     if (argc < 2)
  53:         goto usage;
  54:     while (argc > 1 && *argv[1] == '-') {
  55:         argc--;
  56:         arg = *++argv;
  57: 
  58:         /*
  59: 		 * all files following a null option
  60: 		 * are considered file names
  61: 		 */
  62:         if (*(arg+1) == '\0')
  63:             break;
  64:         while (*++arg != '\0') switch (*arg) {
  65: 
  66:         case 'i':
  67:             iflag++;
  68:             break;
  69: 
  70:         case 'f':
  71:             fflag++;
  72:             break;
  73: 
  74:         default:
  75:             goto usage;
  76:         }
  77:     }
  78:     if (argc < 3)
  79:         goto usage;
  80:     dest = argv[argc-1];
  81:     if (stat(dest, &s2) >= 0 && ISDIR(s2)) {
  82:         r = 0;
  83:         for (i = 1; i < argc-1; i++)
  84:             r |= movewithshortname(argv[i], dest);
  85:         exit(r);
  86:     }
  87:     if (argc > 3)
  88:         goto usage;
  89:     r = move(argv[1], argv[2]);
  90:     exit(r);
  91:     /*NOTREACHED*/
  92: usage:
  93:     fprintf(stderr,
  94: "usage: mv [-if] f1 f2 or mv [-if] f1 ... fn d1 (`fn' is a file or directory)\n");
  95:     return (1);
  96: }
  97: 
  98: movewithshortname(src, dest)
  99:     char *src, *dest;
 100: {
 101:     register char *shortname;
 102:     char target[MAXPATHLEN + 1];
 103: 
 104:     shortname = dname(src);
 105:     if (strlen(dest) + strlen(shortname) > MAXPATHLEN - 1) {
 106:         error("%s/%s: pathname too long", dest,
 107:             shortname);
 108:         return (1);
 109:     }
 110:     sprintf(target, "%s/%s", dest, shortname);
 111:     return (move(src, target));
 112: }
 113: 
 114: move(source, target)
 115:     char *source, *target;
 116: {
 117:     int targetexists;
 118: 
 119:     if (lstat(source, &s1) < 0) {
 120:         Perror2(source, "Cannot access");
 121:         return (1);
 122:     }
 123:     /*
 124: 	 * First, try to rename source to destination.
 125: 	 * The only reason we continue on failure is if
 126: 	 * the move is on a nondirectory and not across
 127: 	 * file systems.
 128: 	 */
 129:     targetexists = lstat(target, &s2) >= 0;
 130:     if (targetexists) {
 131:         if (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino) {
 132:             error("%s and %s are identical", source, target);
 133:             return (1);
 134:         }
 135:         if (iflag && !fflag && isatty(fileno(stdin)) &&
 136:             query("remove %s? ", target) == 0)
 137:             return (1);
 138:         if (access(target, 2) < 0 && !fflag && isatty(fileno(stdin))) {
 139:             if (query("override protection %o for %s? ",
 140:               s2.st_mode & MODEBITS, target) == 0)
 141:                 return (1);
 142:         }
 143:     }
 144:     if (rename(source, target) >= 0)
 145:         return (0);
 146:     if (errno != EXDEV) {
 147:         Perror2(errno == ENOENT && targetexists == 0 ? target : source,
 148:             "rename");
 149:         return (1);
 150:     }
 151:     if (ISDIR(s1)) {
 152:         error("can't mv directories across file systems");
 153:         return (1);
 154:     }
 155:     if (targetexists && unlink(target) < 0) {
 156:         Perror2(target, "Cannot unlink");
 157:         return (1);
 158:     }
 159:     /*
 160: 	 * File can't be renamed, try to recreate the symbolic
 161: 	 * link or special device, or copy the file wholesale
 162: 	 * between file systems.
 163: 	 */
 164:     if (ISLNK(s1)) {
 165:         register m;
 166:         char symln[MAXPATHLEN + 1];
 167: 
 168:         m = readlink(source, symln, sizeof (symln) - 1);
 169:         if (m < 0) {
 170:             Perror(source);
 171:             return (1);
 172:         }
 173:         symln[m] = '\0';
 174: 
 175:         m = umask(~(s1.st_mode & MODEBITS));
 176:         if (symlink(symln, target) < 0) {
 177:             Perror(target);
 178:             return (1);
 179:         }
 180:         (void) umask(m);
 181:         goto cleanup;
 182:     }
 183:     if (ISDEV(s1)) {
 184:         struct timeval tv[2];
 185: 
 186:         if (mknod(target, s1.st_mode, s1.st_rdev) < 0) {
 187:             Perror(target);
 188:             return (1);
 189:         }
 190: 
 191:         tv[0].tv_sec = s1.st_atime;
 192:         tv[0].tv_usec = 0;
 193:         tv[1].tv_sec = s1.st_mtime;
 194:         tv[1].tv_usec = 0;
 195:         (void) utimes(target, tv);
 196:         goto cleanup;
 197:     }
 198:     if (ISREG(s1)) {
 199:         register int fi, fo, n;
 200:         struct timeval tv[2];
 201:         char buf[MAXBSIZE];
 202: 
 203:         fi = open(source, 0);
 204:         if (fi < 0) {
 205:             Perror(source);
 206:             return (1);
 207:         }
 208: 
 209:         fo = creat(target, s1.st_mode & MODEBITS);
 210:         if (fo < 0) {
 211:             Perror(target);
 212:             close(fi);
 213:             return (1);
 214:         }
 215: 
 216:         for (;;) {
 217:             n = read(fi, buf, sizeof buf);
 218:             if (n == 0) {
 219:                 break;
 220:             } else if (n < 0) {
 221:                 Perror2(source, "read");
 222:                 close(fi);
 223:                 close(fo);
 224:                 return (1);
 225:             } else if (write(fo, buf, n) != n) {
 226:                 Perror2(target, "write");
 227:                 close(fi);
 228:                 close(fo);
 229:                 return (1);
 230:             }
 231:         }
 232: 
 233:         close(fi);
 234:         close(fo);
 235: 
 236:         tv[0].tv_sec = s1.st_atime;
 237:         tv[0].tv_usec = 0;
 238:         tv[1].tv_sec = s1.st_mtime;
 239:         tv[1].tv_usec = 0;
 240:         (void) utimes(target, tv);
 241:         goto cleanup;
 242:     }
 243:     error("%s: unknown file type %o", source, s1.st_mode);
 244:     return (1);
 245: 
 246: cleanup:
 247:     if (unlink(source) < 0) {
 248:         Perror2(source, "Cannot unlink");
 249:         return (1);
 250:     }
 251:     return (0);
 252: }
 253: 
 254: /*VARARGS*/
 255: query(prompt, a1, a2)
 256:     char *a1;
 257: {
 258:     register int i, c;
 259: 
 260:     fprintf(stderr, prompt, a1, a2);
 261:     i = c = getchar();
 262:     while (c != '\n' && c != EOF)
 263:         c = getchar();
 264:     return (i == 'y');
 265: }
 266: 
 267: char *
 268: dname(name)
 269:     register char *name;
 270: {
 271:     register char *p;
 272: 
 273:     p = name;
 274:     while (*p)
 275:         if (*p++ == DELIM && *p)
 276:             name = p;
 277:     return name;
 278: }
 279: 
 280: /*VARARGS*/
 281: error(fmt, a1, a2)
 282:     char *fmt;
 283: {
 284: 
 285:     fprintf(stderr, "mv: ");
 286:     fprintf(stderr, fmt, a1, a2);
 287:     fprintf(stderr, "\n");
 288: }
 289: 
 290: Perror(s)
 291:     char *s;
 292: {
 293:     char buf[MAXPATHLEN + 10];
 294: 
 295:     sprintf(buf, "mv: %s", s);
 296:     perror(buf);
 297: }
 298: 
 299: Perror2(s1, s2)
 300:     char *s1, *s2;
 301: {
 302:     char buf[MAXPATHLEN + 20];
 303: 
 304:     sprintf(buf, "mv: %s: %s", s1, s2);
 305:     perror(buf);
 306: }

Defined functions

Perror defined in line 290; used 5 times
Perror2 defined in line 299; used 6 times
dname defined in line 267; used 2 times
error defined in line 281; used 4 times
main defined in line 45; never used
move defined in line 114; used 2 times
movewithshortname defined in line 98; used 1 times
  • in line 84
query defined in line 255; used 2 times

Defined variables

copyright defined in line 8; never used
fflag defined in line 42; used 3 times
iflag defined in line 41; used 2 times
s1 defined in line 40; used 19 times
s2 defined in line 40; used 9 times
sccsid defined in line 14; never used

Defined macros

DELIM defined in line 29; used 1 times
ISDEV defined in line 35; used 1 times
ISDIR defined in line 32; used 2 times
ISLNK defined in line 33; used 1 times
ISREG defined in line 34; used 1 times
MODEBITS defined in line 30; used 3 times
Last modified: 1986-05-15
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1537
Valid CSS Valid XHTML 1.0 Strict