]>
git.saurik.com Git - apple/file_cmds.git/blob - cp/utils.c
5a61282110d88f1f29e7d164aca26fb9c2b24f9b
1 /* $NetBSD: utils.c,v 1.15 1998/08/19 01:29:11 thorpej Exp $ */
4 * Copyright (c) 1991, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 #include <sys/cdefs.h>
39 static char sccsid
[] = "@(#)utils.c 8.3 (Berkeley) 4/1/94";
41 __RCSID("$NetBSD: utils.c,v 1.15 1998/08/19 01:29:11 thorpej Exp $");
45 #include <sys/param.h>
66 static struct timeval tv
[2];
68 TIMESPEC_TO_TIMEVAL(&tv
[0], &fs
->st_atimespec
);
69 TIMESPEC_TO_TIMEVAL(&tv
[1], &fs
->st_mtimespec
);
71 if (utimes(file
, tv
)) {
72 warn("utimes: %s", file
);
83 static char buf
[MAXBSIZE
];
84 struct stat to_stat
, *fs
;
85 int ch
, checkch
, from_fd
, rcount
, rval
, to_fd
, wcount
;
86 #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
90 if ((from_fd
= open(entp
->fts_path
, O_RDONLY
, 0)) == -1) {
91 warn("%s", entp
->fts_path
);
98 * If the file exists and we're interactive, verify with the user.
99 * If the file DNE, set the mode to be the from file, minus setuid
100 * bits, modified by the umask; arguably wrong, but it makes copying
101 * executables work right and it's been that way forever. (The
102 * other choice is 666 or'ed with the execute bits on the from file
103 * modified by the umask.)
107 (void)fprintf(stderr
, "overwrite %s? ", to
.p_path
);
108 checkch
= ch
= getchar();
109 while (ch
!= '\n' && ch
!= EOF
)
111 if (checkch
!= 'y' && checkch
!= 'Y') {
112 (void)close(from_fd
);
116 /* overwrite existing destination file name */
117 to_fd
= open(to
.p_path
, O_WRONLY
| O_TRUNC
, 0);
119 to_fd
= open(to
.p_path
, O_WRONLY
| O_TRUNC
| O_CREAT
,
120 fs
->st_mode
& ~(S_ISUID
| S_ISGID
));
122 if (to_fd
== -1 && fflag
) {
124 * attempt to remove existing destination file name and
127 (void)unlink(to
.p_path
);
128 to_fd
= open(to
.p_path
, O_WRONLY
| O_TRUNC
| O_CREAT
,
129 fs
->st_mode
& ~(S_ISUID
| S_ISGID
));
133 warn("%s", to
.p_path
);
134 (void)close(from_fd
);
141 * There's no reason to do anything other than close the file
142 * now if it's empty, so let's not bother.
144 if (fs
->st_size
> 0) {
146 * Mmap and write if less than 8M (the limit is so we don't totally
147 * trash memory on big files). This is really a minor hack, but it
148 * wins some CPU back.
150 #ifdef VM_AND_BUFFER_CACHE_SYNCHRONIZED
151 if (fs
->st_size
<= 8 * 1048576) {
152 if ((p
= mmap(NULL
, (size_t)fs
->st_size
, PROT_READ
,
153 MAP_FILE
|MAP_SHARED
, from_fd
, (off_t
)0)) == (char *)-1) {
154 warn("%s", entp
->fts_path
);
157 if (write(to_fd
, p
, fs
->st_size
) != fs
->st_size
) {
158 warn("%s", to
.p_path
);
161 /* Some systems don't unmap on close(2). */
162 if (munmap(p
, fs
->st_size
) < 0) {
163 warn("%s", entp
->fts_path
);
170 while ((rcount
= read(from_fd
, buf
, MAXBSIZE
)) > 0) {
171 wcount
= write(to_fd
, buf
, rcount
);
172 if (rcount
!= wcount
|| wcount
== -1) {
173 warn("%s", to
.p_path
);
179 warn("%s", entp
->fts_path
);
186 (void)close(from_fd
);
191 if (pflag
&& setfile(fs
, to_fd
))
194 * If the source was setuid or setgid, lose the bits unless the
195 * copy is owned by the same user and group.
198 (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO)
199 else if (fs
->st_mode
& (S_ISUID
| S_ISGID
) && fs
->st_uid
== myuid
) {
200 if (fstat(to_fd
, &to_stat
)) {
201 warn("%s", to
.p_path
);
203 } else if (fs
->st_gid
== to_stat
.st_gid
&&
204 fchmod(to_fd
, fs
->st_mode
& RETAINBITS
& ~myumask
)) {
205 warn("%s", to
.p_path
);
209 (void)close(from_fd
);
211 warn("%s", to
.p_path
);
214 /* set the mod/access times now after close of the fd */
215 if (pflag
&& set_utimes(to
.p_path
, fs
)) {
227 char target
[MAXPATHLEN
];
229 if ((len
= readlink(p
->fts_path
, target
, sizeof(target
))) == -1) {
230 warn("readlink: %s", p
->fts_path
);
234 if (exists
&& unlink(to
.p_path
)) {
235 warn("unlink: %s", to
.p_path
);
238 if (symlink(target
, to
.p_path
)) {
239 warn("symlink: %s", target
);
242 return (pflag
? setfile(p
->fts_statp
, 0) : 0);
246 copy_fifo(from_stat
, exists
)
247 struct stat
*from_stat
;
250 if (exists
&& unlink(to
.p_path
)) {
251 warn("unlink: %s", to
.p_path
);
254 if (mkfifo(to
.p_path
, from_stat
->st_mode
)) {
255 warn("mkfifo: %s", to
.p_path
);
258 return (pflag
? setfile(from_stat
, 0) : 0);
262 copy_special(from_stat
, exists
)
263 struct stat
*from_stat
;
266 if (exists
&& unlink(to
.p_path
)) {
267 warn("unlink: %s", to
.p_path
);
270 if (mknod(to
.p_path
, from_stat
->st_mode
, from_stat
->st_rdev
)) {
271 warn("mknod: %s", to
.p_path
);
274 return (pflag
? setfile(from_stat
, 0) : 0);
282 * Set the owner/group/permissions for the "to" file to the information
283 * in the stat structure. If fd is zero, also call set_utimes() to set
284 * the mod/access times. If fd is non-zero, the caller must do a utimes
285 * itself after close(fd).
295 islink
= S_ISLNK(fs
->st_mode
);
296 fs
->st_mode
&= S_ISUID
| S_ISGID
| S_IRWXU
| S_IRWXG
| S_IRWXO
;
299 * Changing the ownership probably won't succeed, unless we're root
300 * or POSIX_CHOWN_RESTRICTED is not set. Set uid/gid before setting
301 * the mode; current BSD behavior is to remove all setuid bits on
302 * chown. If chown fails, lose setuid/setgid bits.
304 if (fd
? fchown(fd
, fs
->st_uid
, fs
->st_gid
) :
306 chown(to
.p_path
, fs
->st_uid
, fs
->st_gid
)) {
308 lchown(to
.p_path
, fs
->st_uid
, fs
->st_gid
)) {
310 if (errno
!= EPERM
) {
311 warn("chown: %s", to
.p_path
);
314 fs
->st_mode
&= ~(S_ISUID
| S_ISGID
);
317 if (fd
? fchmod(fd
, fs
->st_mode
) : chmod(to
.p_path
, fs
->st_mode
)) {
319 if (fd
? fchmod(fd
, fs
->st_mode
) : lchmod(to
.p_path
, fs
->st_mode
)) {
321 warn("chmod: %s", to
.p_path
);
328 * NFS doesn't support chflags; ignore errors unless
329 * there's reason to believe we're losing bits.
330 * (Note, this still won't be right if the server
331 * supports flags and we were trying to *remove* flags
332 * on a file that we copied, i.e., that we didn't create.)
335 if (fd
? fchflags(fd
, fs
->st_flags
) :
336 chflags(to
.p_path
, fs
->st_flags
))
337 if (errno
!= EOPNOTSUPP
|| fs
->st_flags
!= 0) {
338 warn("chflags: %s", to
.p_path
);
342 /* if fd is non-zero, caller must call set_utimes() after close() */
343 if (fd
== 0 && set_utimes(to
.p_path
, fs
))
351 (void)fprintf(stderr
, "%s\n%s\n",
352 "usage: cp [-R [-H | -L | -P]] [-f | -i] [-p] src target",
353 " cp [-R [-H | -L | -P]] [-f | -i] [-p] src1 ... srcN directory");