VirtualBox

source: kBuild/trunk/src/kmk/kmkbuiltin/mv.c@ 2113

最後變更 在這個檔案從2113是 2113,由 bird 提交於 16 年 前

kmkbuiltin: include config.h

  • 屬性 svn:eol-style 設為 native
檔案大小: 12.1 KB
 
1/*-
2 * Copyright (c) 1989, 1993, 1994
3 * The Regents of the University of California. 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 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33#if 0
34#ifndef lint
35static char const copyright[] =
36"@(#) Copyright (c) 1989, 1993, 1994\n\
37 The Regents of the University of California. All rights reserved.\n";
38#endif /* not lint */
39
40#ifndef lint
41static char sccsid[] = "@(#)mv.c 8.2 (Berkeley) 4/2/94";
42#endif /* not lint */
43#endif
44#if 0
45#include <sys/cdefs.h>
46__FBSDID("$FreeBSD: src/bin/mv/mv.c,v 1.46 2005/09/05 04:36:08 csjp Exp $");
47#endif
48
49#include "config.h"
50#include <sys/types.h>
51#ifndef _MSC_VER
52# ifndef __OS2__
53# include <sys/acl.h>
54# endif
55# include <sys/param.h>
56# include <sys/time.h>
57# include <sys/wait.h>
58# include <sys/mount.h>
59#endif
60#include <sys/stat.h>
61
62#include "err.h"
63#include <errno.h>
64#include <fcntl.h>
65#include <grp.h>
66#include <limits.h>
67#include <paths.h>
68#include <pwd.h>
69#include <stdio.h>
70#include <stdlib.h>
71#include <string.h>
72#include <sysexits.h>
73#include <unistd.h>
74#include "getopt.h"
75#ifdef __sun__
76# include "solfakes.h"
77#endif
78#ifdef _MSC_VER
79# include "mscfakes.h"
80#endif
81#include "kmkbuiltin.h"
82
83
84static int fflg, iflg, nflg, vflg;
85static struct option long_options[] =
86{
87 { "help", no_argument, 0, 261 },
88 { "version", no_argument, 0, 262 },
89 { 0, 0, 0, 0 },
90};
91
92
93static int do_move(char *, char *);
94#ifdef CROSS_DEVICE_MOVE
95static int fastcopy(char *, char *, struct stat *);
96static int copy(char *, char *);
97#endif
98static int usage(FILE *);
99
100extern void bsd_strmode(mode_t mode, char *p);
101
102#if !defined(__FreeBSD__) && !defined(__APPLE__) && !defined(__DragonFly__)
103# ifdef __OS2__
104static
105# endif
106const char *user_from_uid(uid_t id, int x)
107{
108 static char s_buf[64];
109 sprintf(s_buf, "%ld", id);
110 return s_buf;
111}
112# ifdef __OS2__
113static
114# endif
115const char *group_from_gid(gid_t id, int x)
116{
117 static char s_buf[64];
118 sprintf(s_buf, "%ld", id);
119 return s_buf;
120}
121#endif /* 'not in libc' */
122
123
124int
125kmk_builtin_mv(int argc, char *argv[], char **envp)
126{
127 size_t baselen, len;
128 int rval;
129 char *p, *endp;
130 struct stat sb;
131 int ch;
132 char path[PATH_MAX];
133
134 /* kmk: reinitialize globals */
135 fflg = iflg = nflg = vflg = 0;
136
137 /* kmk: reset getopt and set progname */
138 g_progname = argv[0];
139 opterr = 1;
140 optarg = NULL;
141 optopt = 0;
142 optind = 0; /* init */
143
144 while ((ch = getopt_long(argc, argv, "finv", long_options, NULL)) != -1)
145 switch (ch) {
146 case 'i':
147 iflg = 1;
148 fflg = nflg = 0;
149 break;
150 case 'f':
151 fflg = 1;
152 iflg = nflg = 0;
153 break;
154 case 'n':
155 nflg = 1;
156 fflg = iflg = 0;
157 break;
158 case 'v':
159 vflg = 1;
160 break;
161 case 261:
162 usage(stdout);
163 return 0;
164 case 262:
165 return kbuild_version(argv[0]);
166 default:
167 return usage(stderr);
168 }
169 argc -= optind;
170 argv += optind;
171
172 if (argc < 2)
173 return usage(stderr);
174
175 /*
176 * If the stat on the target fails or the target isn't a directory,
177 * try the move. More than 2 arguments is an error in this case.
178 */
179 if (stat(argv[argc - 1], &sb) || !S_ISDIR(sb.st_mode)) {
180 if (argc > 2)
181 return usage(stderr);
182 return do_move(argv[0], argv[1]);
183 }
184
185 /* It's a directory, move each file into it. */
186 if (strlen(argv[argc - 1]) > sizeof(path) - 1)
187 return errx(1, "%s: destination pathname too long", *argv);
188 (void)strcpy(path, argv[argc - 1]);
189 baselen = strlen(path);
190 endp = &path[baselen];
191#if defined(_MSC_VER) || defined(__EMX__)
192 if (!baselen || (*(endp - 1) != '/' && *(endp - 1) != '\\' && *(endp - 1) != ':')) {
193#else
194 if (!baselen || *(endp - 1) != '/') {
195#endif
196 *endp++ = '/';
197 ++baselen;
198 }
199 for (rval = 0; --argc; ++argv) {
200 /*
201 * Find the last component of the source pathname. It
202 * may have trailing slashes.
203 */
204 p = *argv + strlen(*argv);
205#if defined(_MSC_VER) || defined(__EMX__)
206 while (p != *argv && (p[-1] == '/' || p[-1] == '\\'))
207 --p;
208 while (p != *argv && p[-1] != '/' && p[-1] != '/' && p[-1] != ':')
209 --p;
210#else
211 while (p != *argv && p[-1] == '/')
212 --p;
213 while (p != *argv && p[-1] != '/')
214 --p;
215#endif
216
217 if ((baselen + (len = strlen(p))) >= PATH_MAX) {
218 warnx("%s: destination pathname too long", *argv);
219 rval = 1;
220 } else {
221 memmove(endp, p, (size_t)len + 1);
222 if (do_move(*argv, path))
223 rval = 1;
224 }
225 }
226 return rval;
227}
228
229static int
230do_move(char *from, char *to)
231{
232 struct stat sb;
233 int ask, ch, first;
234 char modep[15];
235
236 /*
237 * Check access. If interactive and file exists, ask user if it
238 * should be replaced. Otherwise if file exists but isn't writable
239 * make sure the user wants to clobber it.
240 */
241 if (!fflg && !access(to, F_OK)) {
242
243 /* prompt only if source exist */
244 if (lstat(from, &sb) == -1) {
245 warn("%s", from);
246 return (1);
247 }
248
249#define YESNO "(y/n [n]) "
250 ask = 0;
251 if (nflg) {
252 if (vflg)
253 printf("%s not overwritten\n", to);
254 return (0);
255 } else if (iflg) {
256 (void)fprintf(stderr, "overwrite %s? %s", to, YESNO);
257 ask = 1;
258 } else if (access(to, W_OK) && !stat(to, &sb)) {
259 bsd_strmode(sb.st_mode, modep);
260 (void)fprintf(stderr, "override %s%s%s/%s for %s? %s",
261 modep + 1, modep[9] == ' ' ? "" : " ",
262 user_from_uid((unsigned long)sb.st_uid, 0),
263 group_from_gid((unsigned long)sb.st_gid, 0), to, YESNO);
264 ask = 1;
265 }
266 if (ask) {
267 first = ch = getchar();
268 while (ch != '\n' && ch != EOF)
269 ch = getchar();
270 if (first != 'y' && first != 'Y') {
271 (void)fprintf(stderr, "not overwritten\n");
272 return (0);
273 }
274 }
275 }
276 if (!rename(from, to)) {
277 if (vflg)
278 printf("%s -> %s\n", from, to);
279 return (0);
280 }
281#ifdef _MSC_VER
282 if (errno == EEXIST) {
283 remove(to);
284 if (!rename(from, to)) {
285 if (vflg)
286 printf("%s -> %s\n", from, to);
287 return (0);
288 }
289 }
290#endif
291
292 if (errno == EXDEV) {
293#ifndef CROSS_DEVICE_MOVE
294 warnx("cannot move `%s' to a different device: `%s'", from, to);
295 return (1);
296#else
297 struct statfs sfs;
298 char path[PATH_MAX];
299
300 /*
301 * If the source is a symbolic link and is on another
302 * filesystem, it can be recreated at the destination.
303 */
304 if (lstat(from, &sb) == -1) {
305 warn("%s", from);
306 return (1);
307 }
308 if (!S_ISLNK(sb.st_mode)) {
309 /* Can't mv(1) a mount point. */
310 if (realpath(from, path) == NULL) {
311 warnx("cannot resolve %s: %s", from, path);
312 return (1);
313 }
314 if (!statfs(path, &sfs) &&
315 !strcmp(path, sfs.f_mntonname)) {
316 warnx("cannot rename a mount point");
317 return (1);
318 }
319 }
320#endif
321 } else {
322 warn("rename %s to %s", from, to);
323 return (1);
324 }
325
326#ifdef CROSS_DEVICE_MOVE
327 /*
328 * If rename fails because we're trying to cross devices, and
329 * it's a regular file, do the copy internally; otherwise, use
330 * cp and rm.
331 */
332 if (lstat(from, &sb)) {
333 warn("%s", from);
334 return (1);
335 }
336 return (S_ISREG(sb.st_mode) ?
337 fastcopy(from, to, &sb) : copy(from, to));
338#endif
339}
340
341#ifdef CROSS_DEVICE_MOVE
342int
343static fastcopy(char *from, char *to, struct stat *sbp)
344{
345 struct timeval tval[2];
346 static u_int blen;
347 static char *bp;
348 mode_t oldmode;
349 int nread, from_fd, to_fd;
350 acl_t acl;
351
352 if ((from_fd = open(from, O_RDONLY, 0)) < 0) {
353 warn("%s", from);
354 return (1);
355 }
356 if (blen < sbp->st_blksize) {
357 if (bp != NULL)
358 free(bp);
359 if ((bp = malloc((size_t)sbp->st_blksize)) == NULL) {
360 blen = 0;
361 warnx("malloc failed");
362 return (1);
363 }
364 blen = sbp->st_blksize;
365 }
366 while ((to_fd =
367 open(to, O_CREAT | O_EXCL | O_TRUNC | O_WRONLY, 0)) < 0) {
368 if (errno == EEXIST && unlink(to) == 0)
369 continue;
370 warn("%s", to);
371 (void)close(from_fd);
372 return (1);
373 }
374 while ((nread = read(from_fd, bp, (size_t)blen)) > 0)
375 if (write(to_fd, bp, (size_t)nread) != nread) {
376 warn("%s", to);
377 goto err;
378 }
379 if (nread < 0) {
380 warn("%s", from);
381err: if (unlink(to))
382 warn("%s: remove", to);
383 (void)close(from_fd);
384 (void)close(to_fd);
385 return (1);
386 }
387
388 oldmode = sbp->st_mode & ALLPERMS;
389 if (fchown(to_fd, sbp->st_uid, sbp->st_gid)) {
390 warn("%s: set owner/group (was: %lu/%lu)", to,
391 (u_long)sbp->st_uid, (u_long)sbp->st_gid);
392 if (oldmode & (S_ISUID | S_ISGID)) {
393 warnx(
394"%s: owner/group changed; clearing suid/sgid (mode was 0%03o)",
395 to, oldmode);
396 sbp->st_mode &= ~(S_ISUID | S_ISGID);
397 }
398 }
399 /*
400 * POSIX 1003.2c states that if _POSIX_ACL_EXTENDED is in effect
401 * for dest_file, then it's ACLs shall reflect the ACLs of the
402 * source_file.
403 */
404 if (fpathconf(to_fd, _PC_ACL_EXTENDED) == 1 &&
405 fpathconf(from_fd, _PC_ACL_EXTENDED) == 1) {
406 acl = acl_get_fd(from_fd);
407 if (acl == NULL)
408 warn("failed to get acl entries while setting %s",
409 from);
410 else if (acl_set_fd(to_fd, acl) < 0)
411 warn("failed to set acl entries for %s", to);
412 }
413 (void)close(from_fd);
414 if (fchmod(to_fd, sbp->st_mode))
415 warn("%s: set mode (was: 0%03o)", to, oldmode);
416 /*
417 * XXX
418 * NFS doesn't support chflags; ignore errors unless there's reason
419 * to believe we're losing bits. (Note, this still won't be right
420 * if the server supports flags and we were trying to *remove* flags
421 * on a file that we copied, i.e., that we didn't create.)
422 */
423 errno = 0;
424 if (fchflags(to_fd, (u_long)sbp->st_flags))
425 if (errno != EOPNOTSUPP || sbp->st_flags != 0)
426 warn("%s: set flags (was: 0%07o)", to, sbp->st_flags);
427
428 tval[0].tv_sec = sbp->st_atime;
429 tval[1].tv_sec = sbp->st_mtime;
430 tval[0].tv_usec = tval[1].tv_usec = 0;
431 if (utimes(to, tval))
432 warn("%s: set times", to);
433
434 if (close(to_fd)) {
435 warn("%s", to);
436 return (1);
437 }
438
439 if (unlink(from)) {
440 warn("%s: remove", from);
441 return (1);
442 }
443 if (vflg)
444 printf("%s -> %s\n", from, to);
445 return (0);
446}
447
448int
449copy(char *from, char *to)
450{
451 int pid, status;
452
453 if ((pid = fork()) == 0) {
454 execl(_PATH_CP, "mv", vflg ? "-PRpv" : "-PRp", "--", from, to,
455 (char *)NULL);
456 warn("%s", _PATH_CP);
457 _exit(1);
458 }
459 if (waitpid(pid, &status, 0) == -1) {
460 warn("%s: waitpid", _PATH_CP);
461 return (1);
462 }
463 if (!WIFEXITED(status)) {
464 warnx("%s: did not terminate normally", _PATH_CP);
465 return (1);
466 }
467 if (WEXITSTATUS(status)) {
468 warnx("%s: terminated with %d (non-zero) status",
469 _PATH_CP, WEXITSTATUS(status));
470 return (1);
471 }
472 if (!(pid = vfork())) {
473 execl(_PATH_RM, "mv", "-rf", "--", from, (char *)NULL);
474 warn("%s", _PATH_RM);
475 _exit(1);
476 }
477 if (waitpid(pid, &status, 0) == -1) {
478 warn("%s: waitpid", _PATH_RM);
479 return (1);
480 }
481 if (!WIFEXITED(status)) {
482 warnx("%s: did not terminate normally", _PATH_RM);
483 return (1);
484 }
485 if (WEXITSTATUS(status)) {
486 warnx("%s: terminated with %d (non-zero) status",
487 _PATH_RM, WEXITSTATUS(status));
488 return (1);
489 }
490 return (0);
491}
492#endif /* CROSS_DEVICE_MOVE */
493
494
495static int
496usage(FILE *pf)
497{
498 fprintf(pf, "usage: %s [-f | -i | -n] [-v] source target\n"
499 " or: %s [-f | -i | -n] [-v] source ... directory\n"
500 " or: %s --help\n"
501 " or: %s --version\n",
502 g_progname, g_progname, g_progname, g_progname);
503 return EX_USAGE;
504}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette