blob: eb9cb1a16b6bec90458465340ead4b39a80d97dd [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
Glenn L McGrath4949faf2001-04-11 16:23:35 +000044copy_file(const char *src_name, const char *dst_name,
45 int set_modes, int follow_links, int force_flag, int quiet_flag)
Eric Andersenaad1a882001-03-16 22:47:14 +000046{
Glenn L McGrath4949faf2001-04-11 16:23:35 +000047 FILE *src_file = NULL;
48 FILE *dst_file = NULL;
Eric Andersenaad1a882001-03-16 22:47:14 +000049 struct stat srcStatBuf;
50 struct stat dstStatBuf;
51 struct utimbuf times;
Glenn L McGrath4949faf2001-04-11 16:23:35 +000052 int src_status;
53 int dst_status;
Eric Andersenaad1a882001-03-16 22:47:14 +000054
Glenn L McGrath4949faf2001-04-11 16:23:35 +000055 if (follow_links == TRUE) {
56 src_status = stat(src_name, &srcStatBuf);
57 dst_status = stat(dst_name, &dstStatBuf);
58 } else {
59 src_status = lstat(src_name, &srcStatBuf);
60 dst_status = lstat(dst_name, &dstStatBuf);
61 }
Eric Andersenaad1a882001-03-16 22:47:14 +000062
Glenn L McGrath4949faf2001-04-11 16:23:35 +000063 if (src_status < 0) {
64 if (!quiet_flag) {
65 perror_msg("%s", src_name);
66 }
Eric Andersenaad1a882001-03-16 22:47:14 +000067 return FALSE;
68 }
69
Glenn L McGrath4949faf2001-04-11 16:23:35 +000070 if ((dst_status < 0) || force_flag) {
71 unlink(dst_name);
Eric Andersenaad1a882001-03-16 22:47:14 +000072 dstStatBuf.st_ino = -1;
73 dstStatBuf.st_dev = -1;
74 }
75
76 if ((srcStatBuf.st_dev == dstStatBuf.st_dev) &&
77 (srcStatBuf.st_ino == dstStatBuf.st_ino)) {
Glenn L McGrath4949faf2001-04-11 16:23:35 +000078 if (!quiet_flag) {
79 error_msg("Copying file \"%s\" to itself", src_name);
80 }
Eric Andersenaad1a882001-03-16 22:47:14 +000081 return FALSE;
82 }
83
84 if (S_ISDIR(srcStatBuf.st_mode)) {
85 //fprintf(stderr, "copying directory %s to %s\n", srcName, destName);
86 /* Make sure the directory is writable */
Glenn L McGrath4949faf2001-04-11 16:23:35 +000087 dst_status = create_path(dst_name, 0777777 ^ umask(0));
88 if ((dst_status < 0) && (errno != EEXIST)) {
89 if (!quiet_flag) {
90 perror_msg("%s", dst_name);
91 }
Eric Andersenaad1a882001-03-16 22:47:14 +000092 return FALSE;
93 }
94 } else if (S_ISLNK(srcStatBuf.st_mode)) {
95 char link_val[BUFSIZ + 1];
96 int link_size;
97
98 //fprintf(stderr, "copying link %s to %s\n", srcName, destName);
99 /* Warning: This could possibly truncate silently, to BUFSIZ chars */
Glenn L McGrath4949faf2001-04-11 16:23:35 +0000100 link_size = readlink(src_name, &link_val[0], BUFSIZ);
Eric Andersenaad1a882001-03-16 22:47:14 +0000101 if (link_size < 0) {
Glenn L McGrath4949faf2001-04-11 16:23:35 +0000102 if (quiet_flag) {
103 perror_msg("%s", src_name);
104 }
Eric Andersenaad1a882001-03-16 22:47:14 +0000105 return FALSE;
106 }
107 link_val[link_size] = '\0';
Glenn L McGrath4949faf2001-04-11 16:23:35 +0000108 src_status = symlink(link_val, dst_name);
109 if (src_status < 0) {
110 if (!quiet_flag) {
111 perror_msg("%s", dst_name);
112 }
Eric Andersenaad1a882001-03-16 22:47:14 +0000113 return FALSE;
114 }
115#if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1)
Glenn L McGrath4949faf2001-04-11 16:23:35 +0000116 if (set_modes == TRUE) {
Eric Andersenaad1a882001-03-16 22:47:14 +0000117 /* Try to set owner, but fail silently like GNU cp */
Glenn L McGrath4949faf2001-04-11 16:23:35 +0000118 lchown(dst_name, srcStatBuf.st_uid, srcStatBuf.st_gid);
Eric Andersenaad1a882001-03-16 22:47:14 +0000119 }
120#endif
121 return TRUE;
122 } else if (S_ISFIFO(srcStatBuf.st_mode)) {
123 //fprintf(stderr, "copying fifo %s to %s\n", srcName, destName);
Glenn L McGrath4949faf2001-04-11 16:23:35 +0000124 if (mkfifo(dst_name, 0644) < 0) {
125 if (!quiet_flag) {
126 perror_msg("%s", dst_name);
127 }
Eric Andersenaad1a882001-03-16 22:47:14 +0000128 return FALSE;
129 }
130 } else if (S_ISBLK(srcStatBuf.st_mode) || S_ISCHR(srcStatBuf.st_mode)
131 || S_ISSOCK(srcStatBuf.st_mode)) {
132 //fprintf(stderr, "copying soc, blk, or chr %s to %s\n", srcName, destName);
Glenn L McGrath4949faf2001-04-11 16:23:35 +0000133 if (mknod(dst_name, srcStatBuf.st_mode, srcStatBuf.st_rdev) < 0) {
134 if (!quiet_flag) {
135 perror_msg("%s", dst_name);
136 }
Eric Andersenaad1a882001-03-16 22:47:14 +0000137 return FALSE;
138 }
139 } else if (S_ISREG(srcStatBuf.st_mode)) {
140 //fprintf(stderr, "copying regular file %s to %s\n", srcName, destName);
Glenn L McGrath4949faf2001-04-11 16:23:35 +0000141 src_file = fopen(src_name, "r");
142 if (src_file == NULL) {
143 if (!quiet_flag) {
144 perror_msg("%s", src_name);
145 }
Eric Andersenaad1a882001-03-16 22:47:14 +0000146 return FALSE;
147 }
148
Glenn L McGrath4949faf2001-04-11 16:23:35 +0000149 dst_file = fopen(dst_name, "w");
150 if (dst_file == NULL) {
151 if (!quiet_flag) {
152 perror_msg("%s", dst_name);
153 }
154 fclose(src_file);
Eric Andersenaad1a882001-03-16 22:47:14 +0000155 return FALSE;
156 }
157
Glenn L McGrath4949faf2001-04-11 16:23:35 +0000158 if (copy_file_chunk(src_file, dst_file, srcStatBuf.st_size)==FALSE) {
159 goto error_exit;
160 }
161
162 fclose(src_file);
163 if (fclose(dst_file) < 0) {
Eric Andersenaad1a882001-03-16 22:47:14 +0000164 return FALSE;
165 }
166 }
167
Glenn L McGrath4949faf2001-04-11 16:23:35 +0000168 if (set_modes == TRUE) {
Eric Andersenaad1a882001-03-16 22:47:14 +0000169 /* This is fine, since symlinks never get here */
Glenn L McGrath4949faf2001-04-11 16:23:35 +0000170 if (chown(dst_name, srcStatBuf.st_uid, srcStatBuf.st_gid) < 0)
171 perror_msg("%s", dst_name);
172 if (chmod(dst_name, srcStatBuf.st_mode) < 0)
173 perror_msg("%s", dst_name);
Eric Andersenaad1a882001-03-16 22:47:14 +0000174 times.actime = srcStatBuf.st_atime;
175 times.modtime = srcStatBuf.st_mtime;
Glenn L McGrath4949faf2001-04-11 16:23:35 +0000176 if (utime(dst_name, &times) < 0)
177 perror_msg("%s", dst_name);
Eric Andersenaad1a882001-03-16 22:47:14 +0000178 }
179
180 return TRUE;
181
Glenn L McGrath4949faf2001-04-11 16:23:35 +0000182error_exit:
183 perror_msg("%s", dst_name);
184 fclose(src_file);
185 fclose(dst_file);
Eric Andersenaad1a882001-03-16 22:47:14 +0000186
187 return FALSE;
188}
189
190/* END CODE */
191/*
192Local Variables:
193c-file-style: "linux"
194c-basic-offset: 4
195tab-width: 4
196End:
197*/