|
|
1.1 root 1: /*
2: * Copyright (c) 1989 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * This code is derived from software contributed to Berkeley by
6: * Ken Smith of The State University of New York at Buffalo.
7: *
8: * Redistribution and use in source and binary forms are permitted provided
9: * that: (1) source distributions retain this entire copyright notice and
10: * comment, and (2) distributions including binaries display the following
11: * acknowledgement: ``This product includes software developed by the
12: * University of California, Berkeley and its contributors'' in the
13: * documentation or other materials provided with the distribution and in
14: * all advertising materials mentioning features or use of this software.
15: * Neither the name of the University nor the names of its contributors may
16: * be used to endorse or promote products derived from this software without
17: * specific prior written permission.
18: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
19: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
20: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
21: */
22:
23: #ifndef lint
24: char copyright[] =
25: "@(#) Copyright (c) 1989 The Regents of the University of California.\n\
26: All rights reserved.\n";
27: #endif /* not lint */
28:
29: #ifndef lint
30: static char sccsid[] = "@(#)mv.c 5.9 (Berkeley) 5/31/90";
31: #endif /* not lint */
32:
33: #include <sys/param.h>
34: #include <sys/time.h>
35: #include <sys/wait.h>
36: #include <sys/stat.h>
37: #include <sys/file.h>
38: #include <sys/errno.h>
39: #include <stdio.h>
40: #include <string.h>
41: #include "pathnames.h"
42:
43: extern int errno;
44: int fflg, iflg;
45:
46: main(argc, argv)
47: int argc;
48: char **argv;
49: {
50: extern char *optarg;
51: extern int optind;
52: register int baselen, exitval, len;
53: register char *p, *endp;
54: struct stat sbuf;
55: int ch;
56: char path[MAXPATHLEN + 1];
57:
58: while (((ch = getopt(argc, argv, "-if")) != EOF))
59: switch((char)ch) {
60: case 'i':
61: ++iflg;
62: break;
63: case 'f':
64: ++fflg;
65: break;
66: case '-': /* undocumented; for compatibility */
67: goto endarg;
68: case '?':
69: default:
70: usage();
71: }
72: endarg: argc -= optind;
73: argv += optind;
74:
75: if (argc < 2)
76: usage();
77:
78: /*
79: * if stat fails on target, it doesn't exist (or can't be accessed
80: * by the user, doesn't matter which) try the move. If target exists,
81: * and isn't a directory, try the move. More than 2 arguments is an
82: * error.
83: */
84: if (stat(argv[argc - 1], &sbuf) || !S_ISDIR(sbuf.st_mode)) {
85: if (argc > 2)
86: usage();
87: exit(do_move(argv[0], argv[1]));
88: }
89:
90: /* got a directory, move each file into it */
91: (void)strcpy(path, argv[argc - 1]);
92: baselen = strlen(path);
93: endp = &path[baselen];
94: *endp++ = '/';
95: ++baselen;
96: for (exitval = 0; --argc; ++argv) {
97: if ((p = rindex(*argv, '/')) == NULL)
98: p = *argv;
99: else
100: ++p;
101: if ((baselen + (len = strlen(p))) >= MAXPATHLEN)
102: (void)fprintf(stderr,
103: "mv: %s: destination pathname too long\n", *argv);
104: else {
105: bcopy(p, endp, len + 1);
106: exitval |= do_move(*argv, path);
107: }
108: }
109: exit(exitval);
110: }
111:
112: do_move(from, to)
113: char *from, *to;
114: {
115: struct stat sbuf;
116: int ask, ch;
117:
118: /*
119: * Check access. If interactive and file exists ask user if it
120: * should be replaced. Otherwise if file exists but isn't writable
121: * make sure the user wants to clobber it.
122: */
123: if (!fflg && !access(to, F_OK)) {
124: ask = 0;
125: if (iflg) {
126: (void)fprintf(stderr, "overwrite %s? ", to);
127: ask = 1;
128: }
129: else if (access(to, W_OK) && !stat(to, &sbuf)) {
130: (void)fprintf(stderr, "override mode %o on %s? ",
131: sbuf.st_mode & 07777, to);
132: ask = 1;
133: }
134: if (ask) {
135: if ((ch = getchar()) != EOF && ch != '\n')
136: while (getchar() != '\n');
137: if (ch != 'y')
138: return(0);
139: }
140: }
141: if (!rename(from, to))
142: return(0);
143: if (errno != EXDEV) {
144: (void)fprintf(stderr,
145: "mv: rename %s to %s: %s\n", from, to, strerror(errno));
146: return(1);
147: }
148: /*
149: * if rename fails, and it's a regular file, do the copy
150: * internally; otherwise, use cp and rm.
151: */
152: if (stat(from, &sbuf)) {
153: (void)fprintf(stderr,
154: "mv: %s: %s\n", from, strerror(errno));
155: return(1);
156: }
157: return(S_ISREG(sbuf.st_mode) ?
158: fastcopy(from, to, &sbuf) : copy(from, to));
159: }
160:
161: fastcopy(from, to, sbp)
162: char *from, *to;
163: struct stat *sbp;
164: {
165: struct timeval tval[2];
166: static u_int blen;
167: static char *bp;
168: register int nread, from_fd, to_fd;
169: char *malloc();
170:
171: if ((from_fd = open(from, O_RDONLY, 0)) < 0) {
172: (void)fprintf(stderr,
173: "mv: %s: %s\n", from, strerror(errno));
174: return(1);
175: }
176: if ((to_fd = open(to, O_WRONLY|O_CREAT|O_TRUNC, sbp->st_mode)) < 0) {
177: (void)fprintf(stderr,
178: "mv: %s: %s\n", to, strerror(errno));
179: (void)close(from_fd);
180: return(1);
181: }
182: if (!blen && !(bp = malloc(blen = sbp->st_blksize))) {
183: (void)fprintf(stderr, "mv: %s: out of memory.\n", from);
184: return(1);
185: }
186: while ((nread = read(from_fd, bp, blen)) > 0)
187: if (write(to_fd, bp, nread) != nread) {
188: (void)fprintf(stderr, "mv: %s: %s\n",
189: to, strerror(errno));
190: goto err;
191: }
192: if (nread < 0) {
193: (void)fprintf(stderr, "mv: %s: %s\n", from, strerror(errno));
194: err: (void)unlink(to);
195: (void)close(from_fd);
196: (void)close(to_fd);
197: return(1);
198: }
199: (void)fchown(to_fd, sbp->st_uid, sbp->st_gid);
200: (void)fchmod(to_fd, sbp->st_mode);
201:
202: (void)close(from_fd);
203: (void)close(to_fd);
204:
205: tval[0].tv_sec = sbp->st_atime;
206: tval[1].tv_sec = sbp->st_mtime;
207: tval[0].tv_usec = tval[1].tv_usec = 0;
208: (void)utimes(to, tval);
209: (void)unlink(from);
210: return(0);
211: }
212:
213: copy(from, to)
214: char *from, *to;
215: {
216: int pid, status;
217:
218: if (!(pid = vfork())) {
219: execlp(_PATH_CP, "mv", "-pr", from, to);
220: (void)fprintf(stderr, "mv: can't exec %s.\n", _PATH_CP);
221: _exit(1);
222: }
223: (void)waitpid(pid, &status, 0);
224: if (!WIFEXITED(status) || WEXITSTATUS(status))
225: return(1);
226: if (!(pid = vfork())) {
227: execlp(_PATH_RM, "mv", "-rf", from);
228: (void)fprintf(stderr, "mv: can't exec %s.\n", _PATH_RM);
229: _exit(1);
230: }
231: (void)waitpid(pid, &status, 0);
232: return(!WIFEXITED(status) || WEXITSTATUS(status));
233: }
234:
235: usage()
236: {
237: (void)fprintf(stderr,
238: "usage: mv [-if] src target;\n or: mv [-if] src1 ... srcN directory\n");
239: exit(1);
240: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.