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