diff options
author | rgrimes <rgrimes@FreeBSD.org> | 1994-05-26 06:18:55 +0000 |
---|---|---|
committer | rgrimes <rgrimes@FreeBSD.org> | 1994-05-26 06:18:55 +0000 |
commit | e3cfc8ce61f788739c66445d903f8beacb40c93d (patch) | |
tree | ba7beef9ee9289c4383bad976f88710e44c98b4d /bin/mv/mv.c | |
parent | 862fdf11a2ede45dec0da01ed575525d79468981 (diff) | |
download | FreeBSD-src-e3cfc8ce61f788739c66445d903f8beacb40c93d.zip FreeBSD-src-e3cfc8ce61f788739c66445d903f8beacb40c93d.tar.gz |
BSD 4.4 Lite bin Sources
Diffstat (limited to 'bin/mv/mv.c')
-rw-r--r-- | bin/mv/mv.c | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/bin/mv/mv.c b/bin/mv/mv.c new file mode 100644 index 0000000..01fbc90 --- /dev/null +++ b/bin/mv/mv.c @@ -0,0 +1,300 @@ +/* + * Copyright (c) 1989, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Ken Smith of The State University of New York at Buffalo. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef lint +static char copyright[] = +"@(#) Copyright (c) 1989, 1993, 1994\n\ + The Regents of the University of California. All rights reserved.\n"; +#endif /* not lint */ + +#ifndef lint +static char sccsid[] = "@(#)mv.c 8.2 (Berkeley) 4/2/94"; +#endif /* not lint */ + +#include <sys/param.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <sys/stat.h> + +#include <err.h> +#include <errno.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "pathnames.h" + +int fflg, iflg; + +int copy __P((char *, char *)); +int do_move __P((char *, char *)); +int fastcopy __P((char *, char *, struct stat *)); +void usage __P((void)); + +int +main(argc, argv) + int argc; + char *argv[]; +{ + register int baselen, len, rval; + register char *p, *endp; + struct stat sb; + int ch; + char path[MAXPATHLEN + 1]; + + while ((ch = getopt(argc, argv, "-if")) != EOF) + switch (ch) { + case 'i': + iflg = 1; + break; + case 'f': + fflg = 1; + break; + case '-': /* Undocumented; for compatibility. */ + goto endarg; + case '?': + default: + usage(); + } +endarg: argc -= optind; + argv += optind; + + if (argc < 2) + usage(); + + /* + * If the stat on the target fails or the target isn't a directory, + * try the move. More than 2 arguments is an error in this case. + */ + if (stat(argv[argc - 1], &sb) || !S_ISDIR(sb.st_mode)) { + if (argc > 2) + usage(); + exit(do_move(argv[0], argv[1])); + } + + /* It's a directory, move each file into it. */ + (void)strcpy(path, argv[argc - 1]); + baselen = strlen(path); + endp = &path[baselen]; + *endp++ = '/'; + ++baselen; + for (rval = 0; --argc; ++argv) { + if ((p = strrchr(*argv, '/')) == NULL) + p = *argv; + else + ++p; + if ((baselen + (len = strlen(p))) >= MAXPATHLEN) { + warnx("%s: destination pathname too long", *argv); + rval = 1; + } else { + memmove(endp, p, len + 1); + if (do_move(*argv, path)) + rval = 1; + } + } + exit(rval); +} + +int +do_move(from, to) + char *from, *to; +{ + struct stat sb; + int ask, ch; + char modep[15]; + + /* + * Check access. If interactive and file exists, ask user if it + * should be replaced. Otherwise if file exists but isn't writable + * make sure the user wants to clobber it. + */ + if (!fflg && !access(to, F_OK)) { + ask = 0; + if (iflg) { + (void)fprintf(stderr, "overwrite %s? ", to); + ask = 1; + } else if (access(to, W_OK) && !stat(to, &sb)) { + strmode(sb.st_mode, modep); + (void)fprintf(stderr, "override %s%s%s/%s for %s? ", + modep + 1, modep[9] == ' ' ? "" : " ", + user_from_uid(sb.st_uid, 0), + group_from_gid(sb.st_gid, 0), to); + ask = 1; + } + if (ask) { + if ((ch = getchar()) != EOF && ch != '\n') + while (getchar() != '\n'); + if (ch != 'y') + return (0); + } + } + if (!rename(from, to)) + return (0); + + if (errno != EXDEV) { + warn("rename %s to %s", from, to); + return (1); + } + + /* + * If rename fails because we're trying to cross devices, and + * it's a regular file, do the copy internally; otherwise, use + * cp and rm. + */ + if (stat(from, &sb)) { + warn("%s", from); + return (1); + } + return (S_ISREG(sb.st_mode) ? + fastcopy(from, to, &sb) : copy(from, to)); +} + +int +fastcopy(from, to, sbp) + char *from, *to; + struct stat *sbp; +{ + struct timeval tval[2]; + static u_int blen; + static char *bp; + register int nread, from_fd, to_fd; + + if ((from_fd = open(from, O_RDONLY, 0)) < 0) { + warn("%s", from); + return (1); + } + if ((to_fd = + open(to, O_CREAT | O_TRUNC | O_WRONLY, sbp->st_mode)) < 0) { + warn("%s", to); + (void)close(from_fd); + return (1); + } + if (!blen && !(bp = malloc(blen = sbp->st_blksize))) { + warn(NULL); + return (1); + } + while ((nread = read(from_fd, bp, blen)) > 0) + if (write(to_fd, bp, nread) != nread) { + warn("%s", to); + goto err; + } + if (nread < 0) { + warn("%s", from); +err: if (unlink(to)) + warn("%s: remove", to); + (void)close(from_fd); + (void)close(to_fd); + return (1); + } + (void)close(from_fd); + + if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) + warn("%s: set owner/group", to); + if (fchmod(to_fd, sbp->st_mode)) + warn("%s: set mode", to); + + tval[0].tv_sec = sbp->st_atime; + tval[1].tv_sec = sbp->st_mtime; + tval[0].tv_usec = tval[1].tv_usec = 0; + if (utimes(to, tval)) + warn("%s: set times", to); + + if (close(to_fd)) { + warn("%s", to); + return (1); + } + + if (unlink(from)) { + warn("%s: remove", from); + return (1); + } + return (0); +} + +int +copy(from, to) + char *from, *to; +{ + int pid, status; + + if ((pid = vfork()) == 0) { + execl(_PATH_CP, "mv", "-PRp", from, to, NULL); + warn("%s", _PATH_CP); + _exit(1); + } + if (waitpid(pid, &status, 0) == -1) { + warn("%s: waitpid", _PATH_CP); + return (1); + } + if (!WIFEXITED(status)) { + warn("%s: did not terminate normally", _PATH_CP); + return (1); + } + if (WEXITSTATUS(status)) { + warn("%s: terminated with %d (non-zero) status", + _PATH_CP, WEXITSTATUS(status)); + return (1); + } + if (!(pid = vfork())) { + execl(_PATH_RM, "mv", "-rf", from, NULL); + warn("%s", _PATH_RM); + _exit(1); + } + if (waitpid(pid, &status, 0) == -1) { + warn("%s: waitpid", _PATH_RM); + return (1); + } + if (!WIFEXITED(status)) { + warn("%s: did not terminate normally", _PATH_RM); + return (1); + } + if (WEXITSTATUS(status)) { + warn("%s: terminated with %d (non-zero) status", + _PATH_RM, WEXITSTATUS(status)); + return (1); + } + return (0); +} + +void +usage() +{ + (void)fprintf(stderr, +"usage: mv [-if] src target;\n or: mv [-if] src1 ... srcN directory\n"); + exit(1); +} |