mv.c revision 1.1.1.1
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, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37#ifndef lint 38char copyright[] = 39"@(#) Copyright (c) 1989 The Regents of the University of California.\n\ 40 All rights reserved.\n"; 41#endif /* not lint */ 42 43#ifndef lint 44static char sccsid[] = "@(#)mv.c 5.11 (Berkeley) 4/3/91"; 45#endif /* not lint */ 46 47#include <sys/param.h> 48#include <sys/time.h> 49#include <sys/wait.h> 50#include <sys/stat.h> 51#include <fcntl.h> 52#include <errno.h> 53#include <unistd.h> 54#include <stdio.h> 55#include <stdlib.h> 56#include <string.h> 57#include "pathnames.h" 58 59int fflg, iflg; 60 61main(argc, argv) 62 int argc; 63 char **argv; 64{ 65 extern char *optarg; 66 extern int optind; 67 register int baselen, exitval, len; 68 register char *p, *endp; 69 struct stat sb; 70 int ch; 71 char path[MAXPATHLEN + 1]; 72 73 while (((ch = getopt(argc, argv, "-if")) != EOF)) 74 switch((char)ch) { 75 case 'i': 76 iflg = 1; 77 break; 78 case 'f': 79 fflg = 1; 80 break; 81 case '-': /* undocumented; for compatibility */ 82 goto endarg; 83 case '?': 84 default: 85 usage(); 86 } 87endarg: argc -= optind; 88 argv += optind; 89 90 if (argc < 2) 91 usage(); 92 93 /* 94 * If the stat on the target fails or the target isn't a directory, 95 * try the move. More than 2 arguments is an error in this case. 96 */ 97 if (stat(argv[argc - 1], &sb) || !S_ISDIR(sb.st_mode)) { 98 if (argc > 2) 99 usage(); 100 exit(do_move(argv[0], argv[1])); 101 } 102 103 /* It's a directory, move each file into it. */ 104 (void)strcpy(path, argv[argc - 1]); 105 baselen = strlen(path); 106 endp = &path[baselen]; 107 *endp++ = '/'; 108 ++baselen; 109 for (exitval = 0; --argc; ++argv) { 110 if ((p = rindex(*argv, '/')) == NULL) 111 p = *argv; 112 else 113 ++p; 114 if ((baselen + (len = strlen(p))) >= MAXPATHLEN) 115 (void)fprintf(stderr, 116 "mv: %s: destination pathname too long\n", *argv); 117 else { 118 bcopy(p, endp, len + 1); 119 exitval |= do_move(*argv, path); 120 } 121 } 122 exit(exitval); 123} 124 125do_move(from, to) 126 char *from, *to; 127{ 128 struct stat sb; 129 int ask, ch; 130 131 /* 132 * Check access. If interactive and file exists, ask user if it 133 * should be replaced. Otherwise if file exists but isn't writable 134 * make sure the user wants to clobber it. 135 */ 136 if (!fflg && !access(to, F_OK)) { 137 ask = 0; 138 if (iflg) { 139 (void)fprintf(stderr, "overwrite %s? ", to); 140 ask = 1; 141 } 142 else if (access(to, W_OK) && !stat(to, &sb)) { 143 (void)fprintf(stderr, "override mode %o on %s? ", 144 sb.st_mode & 07777, to); 145 ask = 1; 146 } 147 if (ask) { 148 if ((ch = getchar()) != EOF && ch != '\n') 149 while (getchar() != '\n'); 150 if (ch != 'y') 151 return(0); 152 } 153 } 154 if (!rename(from, to)) 155 return(0); 156 157 if (errno != EXDEV) { 158 (void)fprintf(stderr, 159 "mv: rename %s to %s: %s\n", from, to, strerror(errno)); 160 return(1); 161 } 162 163 /* 164 * If rename fails, and it's a regular file, do the copy internally; 165 * otherwise, use cp and rm. 166 */ 167 if (stat(from, &sb)) { 168 (void)fprintf(stderr, "mv: %s: %s\n", from, strerror(errno)); 169 return(1); 170 } 171 return(S_ISREG(sb.st_mode) ? 172 fastcopy(from, to, &sb) : copy(from, to)); 173} 174 175fastcopy(from, to, sbp) 176 char *from, *to; 177 struct stat *sbp; 178{ 179 struct timeval tval[2]; 180 static u_int blen; 181 static char *bp; 182 register int nread, from_fd, to_fd; 183 184 if ((from_fd = open(from, O_RDONLY, 0)) < 0) { 185 error(from); 186 return(1); 187 } 188 if ((to_fd = open(to, O_CREAT|O_TRUNC|O_WRONLY, sbp->st_mode)) < 0) { 189 error(to); 190 (void)close(from_fd); 191 return(1); 192 } 193 if (!blen && !(bp = malloc(blen = sbp->st_blksize))) { 194 error(NULL); 195 return(1); 196 } 197 while ((nread = read(from_fd, bp, blen)) > 0) 198 if (write(to_fd, bp, nread) != nread) { 199 error(to); 200 goto err; 201 } 202 if (nread < 0) { 203 error(from); 204err: (void)unlink(to); 205 (void)close(from_fd); 206 (void)close(to_fd); 207 return(1); 208 } 209 (void)fchown(to_fd, sbp->st_uid, sbp->st_gid); 210 (void)fchmod(to_fd, sbp->st_mode); 211 212 (void)close(from_fd); 213 (void)close(to_fd); 214 215 tval[0].tv_sec = sbp->st_atime; 216 tval[1].tv_sec = sbp->st_mtime; 217 tval[0].tv_usec = tval[1].tv_usec = 0; 218 (void)utimes(to, tval); 219 (void)unlink(from); 220 return(0); 221} 222 223copy(from, to) 224 char *from, *to; 225{ 226 int pid, status; 227 228 if (!(pid = vfork())) { 229 execl(_PATH_CP, "mv", "-pr", from, to, NULL); 230 error(_PATH_CP); 231 _exit(1); 232 } 233 (void)waitpid(pid, &status, 0); 234 if (!WIFEXITED(status) || WEXITSTATUS(status)) 235 return(1); 236 if (!(pid = vfork())) { 237 execl(_PATH_RM, "mv", "-rf", from, NULL); 238 error(_PATH_RM); 239 _exit(1); 240 } 241 (void)waitpid(pid, &status, 0); 242 return(!WIFEXITED(status) || WEXITSTATUS(status)); 243} 244 245error(s) 246 char *s; 247{ 248 if (s) 249 (void)fprintf(stderr, "mv: %s: %s\n", s, strerror(errno)); 250 else 251 (void)fprintf(stderr, "mv: %s\n", strerror(errno)); 252} 253 254usage() 255{ 256 (void)fprintf(stderr, 257"usage: mv [-if] src target;\n or: mv [-if] src1 ... srcN directory\n"); 258 exit(1); 259} 260