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

Defined functions

Perror defined in line 287; used 5 times
Perror2 defined in line 296; used 6 times
dname defined in line 264; used 2 times
error defined in line 278; used 4 times
main defined in line 42; never used
move defined in line 111; used 2 times
movewithshortname defined in line 95; used 1 times
  • in line 81
query defined in line 252; used 2 times

Defined variables

copyright defined in line 8; never used
fflag defined in line 40; used 3 times
iflag defined in line 39; used 2 times
s1 defined in line 38; used 19 times
s2 defined in line 38; used 9 times
sccsid defined in line 12; never used

Defined macros

DELIM defined in line 27; used 1 times
ISDEV defined in line 33; used 1 times
ISDIR defined in line 30; used 2 times
ISLNK defined in line 31; used 1 times
ISREG defined in line 32; used 1 times
MODEBITS defined in line 28; used 3 times
Last modified: 1996-01-06
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3854
Valid CSS Valid XHTML 1.0 Strict