VirtualBox

source: kBuild/branches/kBuild-0.1.5/src/kmk/kmkbuiltin/cp_utils.c@ 2368

Last change on this file since 2368 was 2192, checked in by bird, 16 years ago

cp.c, cp_utils.c: fixed a couple of warnings.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.8 KB
Line 
1/*-
2 * Copyright (c) 1991, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 4. Neither the name of the University nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30#ifndef lint
31#if 0
32static char sccsid[] = "@(#)utils.c 8.3 (Berkeley) 4/1/94";
33#include <sys/cdefs.h>
34__FBSDID("$FreeBSD: src/bin/cp/utils.c,v 1.43 2004/04/06 20:06:44 markm Exp $");
35#endif
36#endif /* not lint */
37
38#include "config.h"
39#ifndef _MSC_VER
40# include <sys/param.h>
41#endif
42#include <sys/stat.h>
43#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
44# include <sys/mman.h>
45#endif
46
47#include "err.h"
48#include <errno.h>
49#include <fcntl.h>
50#include <fts.h>
51#include <limits.h>
52#include <stdio.h>
53#include <stdlib.h>
54#include <signal.h>
55#include <sysexits.h>
56#include <unistd.h>
57#ifdef __sun__
58# include "solfakes.h"
59#endif
60#ifdef _MSC_VER
61# define MSC_DO_64_BIT_IO
62# include "mscfakes.h"
63#else
64# include <sys/time.h>
65#endif
66#include "cp_extern.h"
67#include "cmp_extern.h"
68
69#define cp_pct(x,y) (int)(100.0 * (double)(x) / (double)(y))
70
71#ifndef MAXBSIZE
72# define MAXBSIZE 0x20000
73#endif
74#ifndef O_BINARY
75# define O_BINARY 0
76#endif
77
78#ifndef S_ISVTX
79# define S_ISVTX 0
80#endif
81
82
83int
84copy_file(const FTSENT *entp, int dne, int changed_only, int *pcopied)
85{
86 static char buf[MAXBSIZE];
87 struct stat *fs;
88 int ch, checkch, from_fd, rcount, rval, to_fd;
89 ssize_t wcount;
90 size_t wresid;
91 size_t wtotal;
92 char *bufp;
93#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
94 char *p;
95#endif
96
97 *pcopied = 0;
98
99 if ((from_fd = open(entp->fts_path, O_RDONLY | O_BINARY, 0)) == -1) {
100 warn("%s", entp->fts_path);
101 return (1);
102 }
103
104 fs = entp->fts_statp;
105
106 /*
107 * If the file exists and we're interactive, verify with the user.
108 * If the file DNE, set the mode to be the from file, minus setuid
109 * bits, modified by the umask; arguably wrong, but it makes copying
110 * executables work right and it's been that way forever. (The
111 * other choice is 666 or'ed with the execute bits on the from file
112 * modified by the umask.)
113 */
114 if (!dne) {
115 /* compare the files first if requested */
116 if (changed_only) {
117 if (cmp_fd_and_file(from_fd, entp->fts_path, to.p_path,
118 1 /* silent */, 0 /* lflag */,
119 0 /* special */) == OK_EXIT) {
120 close(from_fd);
121 return (0);
122 }
123 if (lseek(from_fd, 0, SEEK_SET) != 0) {
124 close(from_fd);
125 if ((from_fd = open(entp->fts_path, O_RDONLY | O_BINARY, 0)) == -1) {
126 warn("%s", entp->fts_path);
127 return (1);
128 }
129 }
130 }
131
132#define YESNO "(y/n [n]) "
133 if (nflag) {
134 if (vflag)
135 printf("%s not overwritten\n", to.p_path);
136 return (0);
137 } else if (iflag) {
138 (void)fprintf(stderr, "overwrite %s? %s",
139 to.p_path, YESNO);
140 checkch = ch = getchar();
141 while (ch != '\n' && ch != EOF)
142 ch = getchar();
143 if (checkch != 'y' && checkch != 'Y') {
144 (void)close(from_fd);
145 (void)fprintf(stderr, "not overwritten\n");
146 return (1);
147 }
148 }
149
150 if (fflag) {
151 /* remove existing destination file name,
152 * create a new file */
153 (void)unlink(to.p_path);
154 to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY,
155 fs->st_mode & ~(S_ISUID | S_ISGID));
156 } else
157 /* overwrite existing destination file name */
158 to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_BINARY, 0);
159 } else
160 to_fd = open(to.p_path, O_WRONLY | O_TRUNC | O_CREAT | O_BINARY,
161 fs->st_mode & ~(S_ISUID | S_ISGID));
162
163 if (to_fd == -1) {
164 warn("%s", to.p_path);
165 (void)close(from_fd);
166 return (1);
167 }
168
169 rval = 0;
170 *pcopied = 1;
171
172 /*
173 * Mmap and write if less than 8M (the limit is so we don't totally
174 * trash memory on big files. This is really a minor hack, but it
175 * wins some CPU back.
176 */
177#ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
178 if (S_ISREG(fs->st_mode) && fs->st_size > 0 &&
179 fs->st_size <= 8 * 1048576) {
180 if ((p = mmap(NULL, (size_t)fs->st_size, PROT_READ,
181 MAP_SHARED, from_fd, (off_t)0)) == MAP_FAILED) {
182 warn("%s", entp->fts_path);
183 rval = 1;
184 } else {
185 wtotal = 0;
186 for (bufp = p, wresid = fs->st_size; ;
187 bufp += wcount, wresid -= (size_t)wcount) {
188 wcount = write(to_fd, bufp, wresid);
189 wtotal += wcount;
190 if (info) {
191 info = 0;
192 (void)fprintf(stderr,
193 "%s -> %s %3d%%\n",
194 entp->fts_path, to.p_path,
195 cp_pct(wtotal, fs->st_size));
196
197 }
198 if (wcount >= (ssize_t)wresid || wcount <= 0)
199 break;
200 }
201 if (wcount != (ssize_t)wresid) {
202 warn("%s", to.p_path);
203 rval = 1;
204 }
205 /* Some systems don't unmap on close(2). */
206 if (munmap(p, fs->st_size) < 0) {
207 warn("%s", entp->fts_path);
208 rval = 1;
209 }
210 }
211 } else
212#endif
213 {
214 wtotal = 0;
215 while ((rcount = read(from_fd, buf, MAXBSIZE)) > 0) {
216 for (bufp = buf, wresid = rcount; ;
217 bufp += wcount, wresid -= wcount) {
218 wcount = write(to_fd, bufp, wresid);
219 wtotal += wcount;
220 if (info) {
221 info = 0;
222 (void)fprintf(stderr,
223 "%s -> %s %3d%%\n",
224 entp->fts_path, to.p_path,
225 cp_pct(wtotal, fs->st_size));
226
227 }
228 if (wcount >= (ssize_t)wresid || wcount <= 0)
229 break;
230 }
231 if (wcount != (ssize_t)wresid) {
232 warn("%s", to.p_path);
233 rval = 1;
234 break;
235 }
236 }
237 if (rcount < 0) {
238 warn("%s", entp->fts_path);
239 rval = 1;
240 }
241 }
242
243 /*
244 * Don't remove the target even after an error. The target might
245 * not be a regular file, or its attributes might be important,
246 * or its contents might be irreplaceable. It would only be safe
247 * to remove it if we created it and its length is 0.
248 */
249
250 if (pflag && setfile(fs, to_fd))
251 rval = 1;
252 (void)close(from_fd);
253 if (close(to_fd)) {
254 warn("%s", to.p_path);
255 rval = 1;
256 }
257 return (rval);
258}
259
260int
261copy_link(const FTSENT *p, int exists)
262{
263 int len;
264 char llink[PATH_MAX];
265
266 if ((len = readlink(p->fts_path, llink, sizeof(llink) - 1)) == -1) {
267 warn("readlink: %s", p->fts_path);
268 return (1);
269 }
270 llink[len] = '\0';
271 if (exists && unlink(to.p_path)) {
272 warn("unlink: %s", to.p_path);
273 return (1);
274 }
275 if (symlink(llink, to.p_path)) {
276 warn("symlink: %s", llink);
277 return (1);
278 }
279 return (pflag ? setfile(p->fts_statp, -1) : 0);
280}
281
282int
283copy_fifo(struct stat *from_stat, int exists)
284{
285 if (exists && unlink(to.p_path)) {
286 warn("unlink: %s", to.p_path);
287 return (1);
288 }
289 if (mkfifo(to.p_path, from_stat->st_mode)) {
290 warn("mkfifo: %s", to.p_path);
291 return (1);
292 }
293 return (pflag ? setfile(from_stat, -1) : 0);
294}
295
296int
297copy_special(struct stat *from_stat, int exists)
298{
299 if (exists && unlink(to.p_path)) {
300 warn("unlink: %s", to.p_path);
301 return (1);
302 }
303 if (mknod(to.p_path, from_stat->st_mode, from_stat->st_rdev)) {
304 warn("mknod: %s", to.p_path);
305 return (1);
306 }
307 return (pflag ? setfile(from_stat, -1) : 0);
308}
309
310int
311setfile(struct stat *fs, int fd)
312{
313 static struct timeval tv[2];
314 struct stat ts;
315 int rval, gotstat, islink, fdval;
316
317 rval = 0;
318 fdval = fd != -1;
319 islink = !fdval && S_ISLNK(fs->st_mode);
320 fs->st_mode &= S_ISUID | S_ISGID | S_ISVTX |
321 S_IRWXU | S_IRWXG | S_IRWXO;
322
323#ifdef HAVE_ST_TIMESPEC
324 TIMESPEC_TO_TIMEVAL(&tv[0], &fs->st_atimespec);
325 TIMESPEC_TO_TIMEVAL(&tv[1], &fs->st_mtimespec);
326#else
327 tv[0].tv_sec = fs->st_atime;
328 tv[1].tv_sec = fs->st_mtime;
329 tv[0].tv_usec = tv[1].tv_usec = 0;
330#endif
331 if (islink ? lutimes(to.p_path, tv) : utimes(to.p_path, tv)) {
332 warn("%sutimes: %s", islink ? "l" : "", to.p_path);
333 rval = 1;
334 }
335 if (fdval ? fstat(fd, &ts) :
336 (islink ? lstat(to.p_path, &ts) : stat(to.p_path, &ts)))
337 gotstat = 0;
338 else {
339 gotstat = 1;
340 ts.st_mode &= S_ISUID | S_ISGID | S_ISVTX |
341 S_IRWXU | S_IRWXG | S_IRWXO;
342 }
343 /*
344 * Changing the ownership probably won't succeed, unless we're root
345 * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting
346 * the mode; current BSD behavior is to remove all setuid bits on
347 * chown. If chown fails, lose setuid/setgid bits.
348 */
349 if (!gotstat || fs->st_uid != ts.st_uid || fs->st_gid != ts.st_gid)
350 if (fdval ? fchown(fd, fs->st_uid, fs->st_gid) :
351 (islink ? lchown(to.p_path, fs->st_uid, fs->st_gid) :
352 chown(to.p_path, fs->st_uid, fs->st_gid))) {
353 if (errno != EPERM) {
354 warn("chown: %s", to.p_path);
355 rval = 1;
356 }
357 fs->st_mode &= ~(S_ISUID | S_ISGID);
358 }
359
360 if (!gotstat || fs->st_mode != ts.st_mode)
361 if (fdval ? fchmod(fd, fs->st_mode) :
362 (islink ? lchmod(to.p_path, fs->st_mode) :
363 chmod(to.p_path, fs->st_mode))) {
364 warn("chmod: %s", to.p_path);
365 rval = 1;
366 }
367
368#ifdef HAVE_ST_FLAGS
369 if (!gotstat || fs->st_flags != ts.st_flags)
370 if (fdval ?
371 fchflags(fd, fs->st_flags) :
372 (islink ? (errno = ENOSYS) :
373 chflags(to.p_path, fs->st_flags))) {
374 warn("chflags: %s", to.p_path);
375 rval = 1;
376 }
377#endif
378
379 return (rval);
380}
381
Note: See TracBrowser for help on using the repository browser.

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