Bell 32V release
[unix-history] / usr / src / cmd / mv.c
CommitLineData
19d28555
TL
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
19char *pname();
20char *sprintf();
21char *dname();
22struct stat s1, s2;
23
24main(argc, argv)
25register 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);
48usage:
49 fprintf(stderr, "usage: mv f1 f2; or mv d1 d2; or mv f1 ... fn d1\n");
50 return(1);
51}
52
53move(source, target)
54char *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
122mvdir(source, target)
123char *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
228char *
229pname(name)
230register 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
246char *
247dname(name)
248register 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
259check(spth, dinode)
260char *spth;
261ino_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
288chkdot(s)
289register 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}