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