1 /* vi: set sw=4 ts=4: */ 2 /* 3 * Mini copy_file implementation for busybox 4 * 5 * 6 * Copyright (C) 2001 by Matt Kraai <kraai@alumni.carnegiemellon.edu> 7 * 8 * This program is free software; you can redistribute it and/or modify 9 * it under the terms of the GNU General Public License as published by 10 * the Free Software Foundation; either version 2 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * General Public License for more details. 17 * 18 * You should have received a copy of the GNU General Public License 19 * along with this program; if not, write to the Free Software 20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 21 * 22 */ 23 24 #include <sys/types.h> 25 #include <sys/stat.h> 26 #include <unistd.h> 27 #include <fcntl.h> 28 #include <utime.h> 29 #include <errno.h> 30 #include <dirent.h> 31 #include <stdlib.h> 32 #include <string.h> 33 34 #include "libbb.h" 35 36 int copy_file(const char *source, const char *dest, int flags) 37 { 38 struct stat source_stat; 39 struct stat dest_stat; 40 int dest_exists = 1; 41 int status = 0; 42 43 if (((flags & FILEUTILS_PRESERVE_SYMLINKS) && 44 lstat(source, &source_stat) < 0) || 45 (!(flags & FILEUTILS_PRESERVE_SYMLINKS) && 46 stat(source, &source_stat) < 0)) { 47 perror_msg("%s", source); 48 return -1; 49 } 50 51 if (stat(dest, &dest_stat) < 0) { 52 if (errno != ENOENT) { 53 perror_msg("unable to stat `%s'", dest); 54 return -1; 55 } 56 dest_exists = 0; 57 } 58 59 if (dest_exists && source_stat.st_rdev == dest_stat.st_rdev && 60 source_stat.st_ino == dest_stat.st_ino) { 61 error_msg("`%s' and `%s' are the same file", source, dest); 62 return -1; 63 } 64 65 if (S_ISDIR(source_stat.st_mode)) { 66 DIR *dp; 67 struct dirent *d; 68 mode_t saved_umask = 0; 69 70 if (!(flags & FILEUTILS_RECUR)) { 71 error_msg("%s: omitting directory", source); 72 return -1; 73 } 74 75 /* Create DEST. */ 76 if (dest_exists) { 77 if (!S_ISDIR(dest_stat.st_mode)) { 78 error_msg("`%s' is not a directory", dest); 79 return -1; 80 } 81 } else { 82 mode_t mode; 83 saved_umask = umask(0); 84 85 mode = source_stat.st_mode; 86 if (!(flags & FILEUTILS_PRESERVE_STATUS)) 87 mode = source_stat.st_mode & ~saved_umask; 88 mode |= S_IRWXU; 89 90 if (mkdir(dest, mode) < 0) { 91 umask(saved_umask); 92 perror_msg("cannot create directory `%s'", 93 dest); 94 return -1; 95 } 96 97 umask(saved_umask); 98 } 99 100 /* Recursively copy files in SOURCE. */ 101 if ((dp = opendir(source)) == NULL) { 102 perror_msg("unable to open directory `%s'", source); 103 status = -1; 104 goto end; 105 } 106 107 while ((d = readdir(dp)) != NULL) { 108 char *new_source, *new_dest; 109 110 if (strcmp(d->d_name, ".") == 0 || 111 strcmp(d->d_name, "..") == 0) 112 continue; 113 114 new_source = concat_path_file(source, d->d_name); 115 new_dest = concat_path_file(dest, d->d_name); 116 if (copy_file(new_source, new_dest, flags) < 0) 117 status = -1; 118 free(new_source); 119 free(new_dest); 120 } 121 122 /* ??? What if an error occurs in readdir? */ 123 124 if (closedir(dp) < 0) { 125 perror_msg("unable to close directory `%s'", source); 126 status = -1; 127 } 128 129 if (!dest_exists && 130 chmod(dest, source_stat.st_mode & ~saved_umask) < 0) { 131 perror_msg("unable to change permissions of `%s'", 132 dest); 133 status = -1; 134 } 135 } else if (S_ISREG(source_stat.st_mode)) { 136 FILE *sfp, *dfp; 137 138 if (dest_exists) { 139 if ((dfp = fopen(dest, "w")) == NULL) { 140 if (!(flags & FILEUTILS_FORCE)) { 141 perror_msg("unable to open `%s'", dest); 142 return -1; 143 } 144 145 if (unlink(dest) < 0) { 146 perror_msg("unable to remove `%s'", 147 dest); 148 return -1; 149 } 150 151 dest_exists = 0; 152 } 153 } 154 155 if (!dest_exists) { 156 int fd; 157 158 if ((fd = 159 open(dest, O_WRONLY | O_CREAT, 160 source_stat.st_mode)) < 0 161 || (dfp = fdopen(fd, "w")) == NULL) { 162 if (fd >= 0) 163 close(fd); 164 perror_msg("unable to open `%s'", dest); 165 return -1; 166 } 167 } 168 169 if ((sfp = fopen(source, "r")) == NULL) { 170 fclose(dfp); 171 perror_msg("unable to open `%s'", source); 172 status = -1; 173 goto end; 174 } 175 176 if (copy_file_chunk(sfp, dfp, -1) < 0) 177 status = -1; 178 179 if (fclose(dfp) < 0) { 180 perror_msg("unable to close `%s'", dest); 181 status = -1; 182 } 183 184 if (fclose(sfp) < 0) { 185 perror_msg("unable to close `%s'", source); 186 status = -1; 187 } 188 } else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) 189 || S_ISSOCK(source_stat.st_mode)) { 190 if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) { 191 perror_msg("unable to create `%s'", dest); 192 return -1; 193 } 194 } else if (S_ISFIFO(source_stat.st_mode)) { 195 if (mkfifo(dest, source_stat.st_mode) < 0) { 196 perror_msg("cannot create fifo `%s'", dest); 197 return -1; 198 } 199 } else if (S_ISLNK(source_stat.st_mode)) { 200 char *lpath = xreadlink(source); 201 if (symlink(lpath, dest) < 0) { 202 perror_msg("cannot create symlink `%s'", dest); 203 return -1; 204 } 205 free(lpath); 206 207 #if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) 208 if (flags & FILEUTILS_PRESERVE_STATUS) 209 if (lchown(dest, source_stat.st_uid, source_stat.st_gid) 210 < 0) 211 perror_msg 212 ("unable to preserve ownership of `%s'", 213 dest); 214 #endif 215 return 0; 216 } else { 217 error_msg("internal error: unrecognized file type"); 218 return -1; 219 } 220 221 end: 222 223 if (flags & FILEUTILS_PRESERVE_STATUS) { 224 struct utimbuf times; 225 226 times.actime = source_stat.st_atime; 227 times.modtime = source_stat.st_mtime; 228 if (utime(dest, ×) < 0) 229 perror_msg("unable to preserve times of `%s'", dest); 230 if (chown(dest, source_stat.st_uid, source_stat.st_gid) < 0) { 231 source_stat.st_mode &= ~(S_ISUID | S_ISGID); 232 perror_msg("unable to preserve ownership of `%s'", 233 dest); 234 } 235 if (chmod(dest, source_stat.st_mode) < 0) 236 perror_msg("unable to preserve permissions of `%s'", 237 dest); 238 } 239 240 return status; 241 } 242
This page was automatically generated by LXR 0.3.1. • OpenWrt