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