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