|
|
1.1 root 1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: char copyright[] =
9: "@(#) Copyright (c) 1980 Regents of the University of California.\n\
10: All rights reserved.\n";
11: #endif not lint
12:
13: #ifndef lint
14: static char sccsid[] = "@(#)mv.c 5.3 (Berkeley) 5/15/86";
15: #endif not lint
16:
17: /*
18: * mv file1 file2
19: */
20: #include <sys/param.h>
21: #include <sys/stat.h>
22: #include <sys/time.h>
23:
24: #include <stdio.h>
25: #include <sys/dir.h>
26: #include <errno.h>
27: #include <signal.h>
28:
29: #define DELIM '/'
30: #define MODEBITS 07777
31:
32: #define ISDIR(st) (((st).st_mode&S_IFMT) == S_IFDIR)
33: #define ISLNK(st) (((st).st_mode&S_IFMT) == S_IFLNK)
34: #define ISREG(st) (((st).st_mode&S_IFMT) == S_IFREG)
35: #define ISDEV(st) \
36: (((st).st_mode&S_IFMT) == S_IFCHR || ((st).st_mode&S_IFMT) == S_IFBLK)
37:
38: char *sprintf();
39: char *dname();
40: struct stat s1, s2;
41: int iflag = 0; /* interactive mode */
42: int fflag = 0; /* force overwriting */
43: extern unsigned errno;
44:
45: main(argc, argv)
46: register char *argv[];
47: {
48: register i, r;
49: register char *arg;
50: char *dest;
51:
52: if (argc < 2)
53: goto usage;
54: while (argc > 1 && *argv[1] == '-') {
55: argc--;
56: arg = *++argv;
57:
58: /*
59: * all files following a null option
60: * are considered file names
61: */
62: if (*(arg+1) == '\0')
63: break;
64: while (*++arg != '\0') switch (*arg) {
65:
66: case 'i':
67: iflag++;
68: break;
69:
70: case 'f':
71: fflag++;
72: break;
73:
74: default:
75: goto usage;
76: }
77: }
78: if (argc < 3)
79: goto usage;
80: dest = argv[argc-1];
81: if (stat(dest, &s2) >= 0 && ISDIR(s2)) {
82: r = 0;
83: for (i = 1; i < argc-1; i++)
84: r |= movewithshortname(argv[i], dest);
85: exit(r);
86: }
87: if (argc > 3)
88: goto usage;
89: r = move(argv[1], argv[2]);
90: exit(r);
91: /*NOTREACHED*/
92: usage:
93: fprintf(stderr,
94: "usage: mv [-if] f1 f2 or mv [-if] f1 ... fn d1 (`fn' is a file or directory)\n");
95: return (1);
96: }
97:
98: movewithshortname(src, dest)
99: char *src, *dest;
100: {
101: register char *shortname;
102: char target[MAXPATHLEN + 1];
103:
104: shortname = dname(src);
105: if (strlen(dest) + strlen(shortname) > MAXPATHLEN - 1) {
106: error("%s/%s: pathname too long", dest,
107: shortname);
108: return (1);
109: }
110: sprintf(target, "%s/%s", dest, shortname);
111: return (move(src, target));
112: }
113:
114: move(source, target)
115: char *source, *target;
116: {
117: int targetexists;
118:
119: if (lstat(source, &s1) < 0) {
120: Perror2(source, "Cannot access");
121: return (1);
122: }
123: /*
124: * First, try to rename source to destination.
125: * The only reason we continue on failure is if
126: * the move is on a nondirectory and not across
127: * file systems.
128: */
129: targetexists = lstat(target, &s2) >= 0;
130: if (targetexists) {
131: if (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino) {
132: error("%s and %s are identical", source, target);
133: return (1);
134: }
135: if (iflag && !fflag && isatty(fileno(stdin)) &&
136: query("remove %s? ", target) == 0)
137: return (1);
138: if (access(target, 2) < 0 && !fflag && isatty(fileno(stdin))) {
139: if (query("override protection %o for %s? ",
140: s2.st_mode & MODEBITS, target) == 0)
141: return (1);
142: }
143: }
144: if (rename(source, target) >= 0)
145: return (0);
146: if (errno != EXDEV) {
147: Perror2(errno == ENOENT && targetexists == 0 ? target : source,
148: "rename");
149: return (1);
150: }
151: if (ISDIR(s1)) {
152: error("can't mv directories across file systems");
153: return (1);
154: }
155: if (targetexists && unlink(target) < 0) {
156: Perror2(target, "Cannot unlink");
157: return (1);
158: }
159: /*
160: * File can't be renamed, try to recreate the symbolic
161: * link or special device, or copy the file wholesale
162: * between file systems.
163: */
164: if (ISLNK(s1)) {
165: register m;
166: char symln[MAXPATHLEN + 1];
167:
168: m = readlink(source, symln, sizeof (symln) - 1);
169: if (m < 0) {
170: Perror(source);
171: return (1);
172: }
173: symln[m] = '\0';
174:
175: m = umask(~(s1.st_mode & MODEBITS));
176: if (symlink(symln, target) < 0) {
177: Perror(target);
178: return (1);
179: }
180: (void) umask(m);
181: goto cleanup;
182: }
183: if (ISDEV(s1)) {
184: struct timeval tv[2];
185:
186: if (mknod(target, s1.st_mode, s1.st_rdev) < 0) {
187: Perror(target);
188: return (1);
189: }
190:
191: tv[0].tv_sec = s1.st_atime;
192: tv[0].tv_usec = 0;
193: tv[1].tv_sec = s1.st_mtime;
194: tv[1].tv_usec = 0;
195: (void) utimes(target, tv);
196: goto cleanup;
197: }
198: if (ISREG(s1)) {
199: register int fi, fo, n;
200: struct timeval tv[2];
201: char buf[MAXBSIZE];
202:
203: fi = open(source, 0);
204: if (fi < 0) {
205: Perror(source);
206: return (1);
207: }
208:
209: fo = creat(target, s1.st_mode & MODEBITS);
210: if (fo < 0) {
211: Perror(target);
212: close(fi);
213: return (1);
214: }
215:
216: for (;;) {
217: n = read(fi, buf, sizeof buf);
218: if (n == 0) {
219: break;
220: } else if (n < 0) {
221: Perror2(source, "read");
222: close(fi);
223: close(fo);
224: return (1);
225: } else if (write(fo, buf, n) != n) {
226: Perror2(target, "write");
227: close(fi);
228: close(fo);
229: return (1);
230: }
231: }
232:
233: close(fi);
234: close(fo);
235:
236: tv[0].tv_sec = s1.st_atime;
237: tv[0].tv_usec = 0;
238: tv[1].tv_sec = s1.st_mtime;
239: tv[1].tv_usec = 0;
240: (void) utimes(target, tv);
241: goto cleanup;
242: }
243: error("%s: unknown file type %o", source, s1.st_mode);
244: return (1);
245:
246: cleanup:
247: if (unlink(source) < 0) {
248: Perror2(source, "Cannot unlink");
249: return (1);
250: }
251: return (0);
252: }
253:
254: /*VARARGS*/
255: query(prompt, a1, a2)
256: char *a1;
257: {
258: register int i, c;
259:
260: fprintf(stderr, prompt, a1, a2);
261: i = c = getchar();
262: while (c != '\n' && c != EOF)
263: c = getchar();
264: return (i == 'y');
265: }
266:
267: char *
268: dname(name)
269: register char *name;
270: {
271: register char *p;
272:
273: p = name;
274: while (*p)
275: if (*p++ == DELIM && *p)
276: name = p;
277: return name;
278: }
279:
280: /*VARARGS*/
281: error(fmt, a1, a2)
282: char *fmt;
283: {
284:
285: fprintf(stderr, "mv: ");
286: fprintf(stderr, fmt, a1, a2);
287: fprintf(stderr, "\n");
288: }
289:
290: Perror(s)
291: char *s;
292: {
293: char buf[MAXPATHLEN + 10];
294:
295: sprintf(buf, "mv: %s", s);
296: perror(buf);
297: }
298:
299: Perror2(s1, s2)
300: char *s1, *s2;
301: {
302: char buf[MAXPATHLEN + 20];
303:
304: sprintf(buf, "mv: %s: %s", s1, s2);
305: perror(buf);
306: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.