/* vi: set sw=4 ts=4: */ /* * Utility routines. * * Copyright (C) tons of folks. Tracking down who wrote what * isn't something I'm going to worry about... If you wrote something * here, please feel free to acknowledge your work. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Based in part on code from sash, Copyright (c) 1999 by David I. Bell * Permission has been granted to redistribute this code under the GPL. * */ #include #include #include #include #include #include #include "libbb.h" /* * Copy one file to another, while possibly preserving its modes, times, and * modes. Returns TRUE if successful, or FALSE on a failure with an error * message output. (Failure is not indicated if attributes cannot be set.) * -Erik Andersen */ int copy_file(const char *src_name, const char *dst_name, int set_modes, int follow_links, int force_flag, int quiet_flag) { FILE *src_file = NULL; FILE *dst_file = NULL; struct stat srcStatBuf; struct stat dstStatBuf; struct utimbuf times; int src_status; int dst_status; if (follow_links == TRUE) { src_status = stat(src_name, &srcStatBuf); dst_status = stat(dst_name, &dstStatBuf); } else { src_status = lstat(src_name, &srcStatBuf); dst_status = lstat(dst_name, &dstStatBuf); } if (src_status < 0) { if (!quiet_flag) { perror_msg("%s", src_name); } return FALSE; } if ((dst_status < 0) || force_flag) { unlink(dst_name); dstStatBuf.st_ino = -1; dstStatBuf.st_dev = -1; } if ((srcStatBuf.st_dev == dstStatBuf.st_dev) && (srcStatBuf.st_ino == dstStatBuf.st_ino)) { if (!quiet_flag) { error_msg("Copying file \"%s\" to itself", src_name); } return FALSE; } if (S_ISDIR(srcStatBuf.st_mode)) { //fprintf(stderr, "copying directory %s to %s\n", srcName, destName); /* Make sure the directory is writable */ dst_status = create_path(dst_name, 0777777 ^ umask(0)); if ((dst_status < 0) && (errno != EEXIST)) { if (!quiet_flag) { perror_msg("%s", dst_name); } return FALSE; } } else if (S_ISLNK(srcStatBuf.st_mode)) { char link_val[BUFSIZ + 1]; int link_size; //fprintf(stderr, "copying link %s to %s\n", srcName, destName); /* Warning: This could possibly truncate silently, to BUFSIZ chars */ link_size = readlink(src_name, &link_val[0], BUFSIZ); if (link_size < 0) { if (quiet_flag) { perror_msg("%s", src_name); } return FALSE; } link_val[link_size] = '\0'; src_status = symlink(link_val, dst_name); if (src_status < 0) { if (!quiet_flag) { perror_msg("%s", dst_name); } return FALSE; } #if (__GLIBC__ >= 2) && (__GLIBC_MINOR__ >= 1) if (set_modes == TRUE) { /* Try to set owner, but fail silently like GNU cp */ lchown(dst_name, srcStatBuf.st_uid, srcStatBuf.st_gid); } #endif return TRUE; } else if (S_ISFIFO(srcStatBuf.st_mode)) { //fprintf(stderr, "copying fifo %s to %s\n", srcName, destName); if (mkfifo(dst_name, 0644) < 0) { if (!quiet_flag) { perror_msg("%s", dst_name); } return FALSE; } } else if (S_ISBLK(srcStatBuf.st_mode) || S_ISCHR(srcStatBuf.st_mode) || S_ISSOCK(srcStatBuf.st_mode)) { //fprintf(stderr, "copying soc, blk, or chr %s to %s\n", srcName, destName); if (mknod(dst_name, srcStatBuf.st_mode, srcStatBuf.st_rdev) < 0) { if (!quiet_flag) { perror_msg("%s", dst_name); } return FALSE; } } else if (S_ISREG(srcStatBuf.st_mode)) { //fprintf(stderr, "copying regular file %s to %s\n", srcName, destName); src_file = fopen(src_name, "r"); if (src_file == NULL) { if (!quiet_flag) { perror_msg("%s", src_name); } return FALSE; } dst_file = fopen(dst_name, "w"); chmod(dst_name, srcStatBuf.st_mode); if (dst_file == NULL) { if (!quiet_flag) { perror_msg("%s", dst_name); } fclose(src_file); return FALSE; } if (copy_file_chunk(src_file, dst_file, srcStatBuf.st_size)==FALSE) { goto error_exit; } fclose(src_file); if (fclose(dst_file) < 0) { return FALSE; } } if (set_modes == TRUE) { /* This is fine, since symlinks never get here */ if (chown(dst_name, srcStatBuf.st_uid, srcStatBuf.st_gid) < 0) perror_msg("%s", dst_name); if (chmod(dst_name, srcStatBuf.st_mode) < 0) perror_msg("%s", dst_name); times.actime = srcStatBuf.st_atime; times.modtime = srcStatBuf.st_mtime; if (utime(dst_name, ×) < 0) perror_msg("%s", dst_name); } return TRUE; error_exit: perror_msg("%s", dst_name); fclose(src_file); fclose(dst_file); return FALSE; } /* END CODE */ /* Local Variables: c-file-style: "linux" c-basic-offset: 4 tab-width: 4 End: */