]>
git.saurik.com Git - apple/file_cmds.git/blob - mv/mv.c
a8c08d0708264f31e7c5dbfa442ea1f7196abb6f
1 /* $NetBSD: mv.c,v 1.19 1998/07/28 11:41:49 mycroft Exp $ */
4 * Copyright (c) 1989, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * This code is derived from software contributed to Berkeley by
8 * Ken Smith of The State University of New York at Buffalo.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the University of
21 * California, Berkeley and its contributors.
22 * 4. Neither the name of the University nor the names of its contributors
23 * may be used to endorse or promote products derived from this software
24 * without specific prior written permission.
26 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 #include <sys/cdefs.h>
41 __COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\n\
42 The Regents of the University of California. All rights reserved.\n");
47 static char sccsid
[] = "@(#)mv.c 8.2 (Berkeley) 4/2/94";
49 __RCSID("$NetBSD: mv.c,v 1.19 1998/07/28 11:41:49 mycroft Exp $");
53 #include <sys/param.h>
69 #include "pathnames.h"
74 int copy
__P((char *, char *));
75 int do_move
__P((char *, char *));
76 int fastcopy
__P((char *, char *, struct stat
*));
77 void usage
__P((void));
78 int main
__P((int, char *[]));
85 int baselen
, len
, rval
;
89 char path
[MAXPATHLEN
+ 1];
91 (void)setlocale(LC_ALL
, "");
93 while ((ch
= getopt(argc
, argv
, "if")) != -1)
113 stdin_ok
= isatty(STDIN_FILENO
);
116 * If the stat on the target fails or the target isn't a directory,
117 * try the move. More than 2 arguments is an error in this case.
119 if (stat(argv
[argc
- 1], &sb
) || !S_ISDIR(sb
.st_mode
)) {
122 exit(do_move(argv
[0], argv
[1]));
125 /* It's a directory, move each file into it. */
126 (void)strcpy(path
, argv
[argc
- 1]);
127 baselen
= strlen(path
);
128 endp
= &path
[baselen
];
131 for (rval
= 0; --argc
; ++argv
) {
132 p
= *argv
+ strlen(*argv
) - 1;
133 while (*p
== '/' && p
!= *argv
)
135 if ((p
= strrchr(*argv
, '/')) == NULL
)
140 if ((baselen
+ (len
= strlen(p
))) >= MAXPATHLEN
) {
141 warnx("%s: destination pathname too long", *argv
);
144 memmove(endp
, p
, len
+ 1);
145 if (do_move(*argv
, path
))
161 * (1) If the destination path exists, the -f option is not specified
162 * and either of the following conditions are true:
164 * (a) The perimissions of the destination path do not permit
165 * writing and the standard input is a terminal.
166 * (b) The -i option is specified.
168 * the mv utility shall write a prompt to standard error and
169 * read a line from standard input. If the response is not
170 * affirmative, mv shall do nothing more with the current
173 if (!fflg
&& !access(to
, F_OK
)) {
178 (void)fprintf(stderr
, "overwrite %s? ", to
);
179 } else if (stdin_ok
&& access(to
, W_OK
) && !stat(to
, &sb
)) {
180 strmode(sb
.st_mode
, modep
);
181 (void)fprintf(stderr
, "override %s%s%s/%s for %s? ",
182 modep
+ 1, modep
[9] == ' ' ? "" : " ",
183 user_from_uid(sb
.st_uid
, 0),
184 group_from_gid(sb
.st_gid
, 0), to
);
188 if ((ch
= getchar()) != EOF
&& ch
!= '\n')
189 while (getchar() != '\n');
190 if (ch
!= 'y' && ch
!= 'Y')
196 * (2) If rename() succeeds, mv shall do nothing more with the
197 * current source file. If it fails for any other reason than
198 * EXDEV, mv shall write a diagnostic message to the standard
199 * error and do nothing more with the current source file.
201 * (3) If the destination path exists, and it is a file of type
202 * directory and source_file is not a file of type directory,
203 * or it is a file not of type directory, and source file is
204 * a file of type directory, mv shall write a diagnostic
205 * message to standard error, and do nothing more with the
206 * current source file...
208 if (!rename(from
, to
))
211 if (errno
!= EXDEV
) {
212 warn("rename %s to %s", from
, to
);
217 * (4) If the destination path exists, mv shall attempt to remove it.
218 * If this fails for any reason, mv shall write a diagnostic
219 * message to the standard error and do nothing more with the
220 * current source file...
222 if (!lstat(to
, &sb
)) {
223 if ((S_ISDIR(sb
.st_mode
)) ? rmdir(to
) : unlink(to
)) {
224 warn("can't remove %s", to
);
230 * (5) The file hierarchy rooted in source_file shall be duplicated
231 * as a file hierarchy rooted in the destination path...
233 if (lstat(from
, &sb
)) {
237 return (S_ISREG(sb
.st_mode
) ?
238 fastcopy(from
, to
, &sb
) : copy(from
, to
));
242 fastcopy(from
, to
, sbp
)
246 struct timeval tval
[2];
249 int nread
, from_fd
, to_fd
;
251 if ((from_fd
= open(from
, O_RDONLY
, 0)) < 0) {
256 open(to
, O_CREAT
| O_TRUNC
| O_WRONLY
, sbp
->st_mode
)) < 0) {
258 (void)close(from_fd
);
261 if (!blen
&& !(bp
= malloc(blen
= sbp
->st_blksize
))) {
265 while ((nread
= read(from_fd
, bp
, blen
)) > 0)
266 if (write(to_fd
, bp
, nread
) != nread
) {
273 warn("%s: remove", to
);
274 (void)close(from_fd
);
278 (void)close(from_fd
);
280 TIMESPEC_TO_TIMEVAL(&tval
[0], &sbp
->st_atimespec
);
281 TIMESPEC_TO_TIMEVAL(&tval
[1], &sbp
->st_mtimespec
);
283 if (futimes(to_fd
, tval
))
285 if (utimes(to
, tval
))
287 warn("%s: set times", to
);
288 if (fchown(to_fd
, sbp
->st_uid
, sbp
->st_gid
)) {
290 warn("%s: set owner/group", to
);
291 sbp
->st_mode
&= ~(S_ISUID
| S_ISGID
);
293 if (fchmod(to_fd
, sbp
->st_mode
))
294 warn("%s: set mode", to
);
302 warn("%s: remove", from
);
314 if ((pid
= vfork()) == 0) {
315 execl(_PATH_CP
, "mv", "-PRp", from
, to
, NULL
);
316 warn("%s", _PATH_CP
);
319 if (waitpid(pid
, &status
, 0) == -1) {
320 warn("%s: waitpid", _PATH_CP
);
323 if (!WIFEXITED(status
)) {
324 warn("%s: did not terminate normally", _PATH_CP
);
327 if (WEXITSTATUS(status
)) {
328 warn("%s: terminated with %d (non-zero) status",
329 _PATH_CP
, WEXITSTATUS(status
));
332 if (!(pid
= vfork())) {
333 execl(_PATH_RM
, "mv", "-rf", from
, NULL
);
334 warn("%s", _PATH_RM
);
337 if (waitpid(pid
, &status
, 0) == -1) {
338 warn("%s: waitpid", _PATH_RM
);
341 if (!WIFEXITED(status
)) {
342 warn("%s: did not terminate normally", _PATH_RM
);
345 if (WEXITSTATUS(status
)) {
346 warn("%s: terminated with %d (non-zero) status",
347 _PATH_RM
, WEXITSTATUS(status
));
357 (void)fprintf(stderr
, "usage: mv [-fi] source target\n");
358 (void)fprintf(stderr
, " mv [-fi] source ... directory\n");