blob: 64b65b9faf69a92343bdeb762c151790552d875b [file] [log] [blame]
Eric Andersenaad1a882001-03-16 22:47:14 +00001/* vi: set sw=4 ts=4: */
2/*
3 * Utility routines.
4 *
5 * Copyright (C) tons of folks. Tracking down who wrote what
6 * isn't something I'm going to worry about... If you wrote something
7 * here, please feel free to acknowledge your work.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 *
23 * Based in part on code from sash, Copyright (c) 1999 by David I. Bell
24 * Permission has been granted to redistribute this code under the GPL.
25 *
26 */
27
28#include <stdio.h>
29#include <errno.h>
30#include <utime.h>
31#include <unistd.h>
32#include <fcntl.h>
33#include <sys/stat.h>
34#include "libbb.h"
35
36
37/*
38 * Copy one file to another, while possibly preserving its modes, times, and
39 * modes. Returns TRUE if successful, or FALSE on a failure with an error
40 * message output. (Failure is not indicated if attributes cannot be set.)
41 * -Erik Andersen
42 */
43int
44copy_file(const char *srcName, const char *destName,
45 int setModes, int followLinks, int forceFlag)
46{
47 int rfd;
48 int wfd;
49 int status;
50 struct stat srcStatBuf;
51 struct stat dstStatBuf;
52 struct utimbuf times;
53
54 if (followLinks == TRUE)
55 status = stat(srcName, &srcStatBuf);
56 else
57 status = lstat(srcName, &srcStatBuf);
58
59 if (status < 0) {
60 perror_msg("%s", srcName);
61 return FALSE;
62 }
63
64 if (followLinks == TRUE)
65 status = stat(destName, &dstStatBuf);
66 else
67 status = lstat(destName, &dstStatBuf);
68
69 if (status < 0 || forceFlag==TRUE) {
70 unlink(destName);
71 dstStatBuf.st_ino = -1;
72 dstStatBuf.st_dev = -1;
73 }
74
75 if ((srcStatBuf.st_dev == dstStatBuf.st_dev) &&
76 (srcStatBuf.st_ino == dstStatBuf.st_ino)) {
77 error_msg("Copying file \"%s\" to itself", srcName);
78 return FALSE;
79 }
80
81 if (S_ISDIR(srcStatBuf.st_mode)) {
82 //fprintf(stderr, "copying directory %s to %s\n", srcName, destName);
83 /* Make sure the directory is writable */
84 status = mkdir(destName, 0777777 ^ umask(0));
85 if (status < 0 && errno != EEXIST) {
86 perror_msg("%s", destName);
87 return FALSE;
88 }
89 } else if (S_ISLNK(srcStatBuf.st_mode)) {
90 char link_val[BUFSIZ + 1];
91 int link_size;
92
93 //fprintf(stderr, "copying link %s to %s\n", srcName, destName);
94 /* Warning: This could possibly truncate silently, to BUFSIZ chars */
95 link_size = readlink(srcName, &link_val[0], BUFSIZ);
96 if (link_size < 0) {
97 perror_msg("%s", srcName);
98 return FALSE;
99 }
100 link_val[link_size] = '\0';
101 status = symlink(link_val, destName);
102 if (status < 0) {
103 perror_msg("%s", destName);
104 return FALSE;
105 }
106#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
107 if (setModes == TRUE) {
108 /* Try to set owner, but fail silently like GNU cp */
109 lchown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid);
110 }
111#endif
112 return TRUE;
113 } else if (S_ISFIFO(srcStatBuf.st_mode)) {
114 //fprintf(stderr, "copying fifo %s to %s\n", srcName, destName);
115 if (mkfifo(destName, 0644) < 0) {
116 perror_msg("%s", destName);
117 return FALSE;
118 }
119 } else if (S_ISBLK(srcStatBuf.st_mode) || S_ISCHR(srcStatBuf.st_mode)
120 || S_ISSOCK(srcStatBuf.st_mode)) {
121 //fprintf(stderr, "copying soc, blk, or chr %s to %s\n", srcName, destName);
122 if (mknod(destName, srcStatBuf.st_mode, srcStatBuf.st_rdev) < 0) {
123 perror_msg("%s", destName);
124 return FALSE;
125 }
126 } else if (S_ISREG(srcStatBuf.st_mode)) {
127 //fprintf(stderr, "copying regular file %s to %s\n", srcName, destName);
128 rfd = open(srcName, O_RDONLY);
129 if (rfd < 0) {
130 perror_msg("%s", srcName);
131 return FALSE;
132 }
133
134 wfd = open(destName, O_WRONLY | O_CREAT | O_TRUNC,
135 srcStatBuf.st_mode);
136 if (wfd < 0) {
137 perror_msg("%s", destName);
138 close(rfd);
139 return FALSE;
140 }
141
142 if (copy_file_chunk(rfd, wfd, srcStatBuf.st_size)==FALSE)
143 goto error_exit;
144
145 close(rfd);
146 if (close(wfd) < 0) {
147 return FALSE;
148 }
149 }
150
151 if (setModes == TRUE) {
152 /* This is fine, since symlinks never get here */
153 if (chown(destName, srcStatBuf.st_uid, srcStatBuf.st_gid) < 0)
154 perror_msg_and_die("%s", destName);
155 if (chmod(destName, srcStatBuf.st_mode) < 0)
156 perror_msg_and_die("%s", destName);
157 times.actime = srcStatBuf.st_atime;
158 times.modtime = srcStatBuf.st_mtime;
159 if (utime(destName, &times) < 0)
160 perror_msg_and_die("%s", destName);
161 }
162
163 return TRUE;
164
165 error_exit:
166 perror_msg("%s", destName);
167 close(rfd);
168 close(wfd);
169
170 return FALSE;
171}
172
173/* END CODE */
174/*
175Local Variables:
176c-file-style: "linux"
177c-basic-offset: 4
178tab-width: 4
179End:
180*/