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