1 /* vi: set sw=4 ts=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.
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.
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.
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
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.
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.)
44 copy_file(const char *srcName, const char *destName,
45 int setModes, int followLinks, int forceFlag)
50 struct stat srcStatBuf;
51 struct stat dstStatBuf;
54 if (followLinks == TRUE)
55 status = stat(srcName, &srcStatBuf);
57 status = lstat(srcName, &srcStatBuf);
60 perror_msg("%s", srcName);
64 if (followLinks == TRUE)
65 status = stat(destName, &dstStatBuf);
67 status = lstat(destName, &dstStatBuf);
69 if (status < 0 || forceFlag==TRUE) {
71 dstStatBuf.st_ino = -1;
72 dstStatBuf.st_dev = -1;
75 if ((srcStatBuf.st_dev == dstStatBuf.st_dev) &&
76 (srcStatBuf.st_ino == dstStatBuf.st_ino)) {
77 error_msg("Copying file \"%s\" to itself", srcName);
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);
89 } else if (S_ISLNK(srcStatBuf.st_mode)) {
90 char link_val[BUFSIZ + 1];
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);
97 perror_msg("%s", srcName);
100 link_val[link_size] = '\0';
101 status = symlink(link_val, destName);
103 perror_msg("%s", destName);
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);
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);
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);
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);
130 perror_msg("%s", srcName);
134 wfd = open(destName, O_WRONLY | O_CREAT | O_TRUNC,
137 perror_msg("%s", destName);
142 if (copy_file_chunk(rfd, wfd, srcStatBuf.st_size)==FALSE)
146 if (close(wfd) < 0) {
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, ×) < 0)
160 perror_msg_and_die("%s", destName);
166 perror_msg("%s", destName);
176 c-file-style: "linux"