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