mirror of
https://github.com/sheumann/hush.git
synced 2024-10-27 23:26:30 +00:00
make copy_file() a bit easier to understand, and smaller
function old new delta copy_file 1565 1447 -118 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/1 up/down: 0/-118) Total: -118 bytes text data bss dec hex filename 770938 1063 10788 782789 bf1c5 busybox_old 770814 1063 10788 782665 bf149 busybox_unstripped
This commit is contained in:
parent
737d131e5e
commit
30bab71f7b
@ -69,7 +69,6 @@ int cp_main(int argc, char **argv)
|
|||||||
if (argc == 2) {
|
if (argc == 2) {
|
||||||
s_flags = cp_mv_stat2(*argv, &source_stat,
|
s_flags = cp_mv_stat2(*argv, &source_stat,
|
||||||
(flags & FILEUTILS_DEREFERENCE) ? stat : lstat);
|
(flags & FILEUTILS_DEREFERENCE) ? stat : lstat);
|
||||||
/* TODO: does coreutils cp exit? "cp BAD GOOD dir"... */
|
|
||||||
if (s_flags < 0)
|
if (s_flags < 0)
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
d_flags = cp_mv_stat(last, &dest_stat);
|
d_flags = cp_mv_stat(last, &dest_stat);
|
||||||
|
@ -31,7 +31,8 @@ int cp_mv_stat2(const char *fn, struct stat *fn_stat, stat_func sf)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
} else if (S_ISDIR(fn_stat->st_mode)) {
|
}
|
||||||
|
if (S_ISDIR(fn_stat->st_mode)) {
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -60,9 +60,11 @@ static int ask_and_unlink(const char *dest, int flags)
|
|||||||
*/
|
*/
|
||||||
int copy_file(const char *source, const char *dest, int flags)
|
int copy_file(const char *source, const char *dest, int flags)
|
||||||
{
|
{
|
||||||
|
/* This is a recursive function, try to minimize stack usage */
|
||||||
|
/* NB: each struct stat is ~100 bytes */
|
||||||
struct stat source_stat;
|
struct stat source_stat;
|
||||||
struct stat dest_stat;
|
struct stat dest_stat;
|
||||||
int status = 0;
|
signed char retval = 0;
|
||||||
signed char dest_exists = 0;
|
signed char dest_exists = 0;
|
||||||
signed char ovr;
|
signed char ovr;
|
||||||
|
|
||||||
@ -120,7 +122,7 @@ int copy_file(const char *source, const char *dest, int flags)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create DEST. */
|
/* Create DEST */
|
||||||
if (dest_exists) {
|
if (dest_exists) {
|
||||||
if (!S_ISDIR(dest_stat.st_mode)) {
|
if (!S_ISDIR(dest_stat.st_mode)) {
|
||||||
bb_error_msg("target '%s' is not a directory", dest);
|
bb_error_msg("target '%s' is not a directory", dest);
|
||||||
@ -133,22 +135,21 @@ int copy_file(const char *source, const char *dest, int flags)
|
|||||||
mode = source_stat.st_mode;
|
mode = source_stat.st_mode;
|
||||||
if (!(flags & FILEUTILS_PRESERVE_STATUS))
|
if (!(flags & FILEUTILS_PRESERVE_STATUS))
|
||||||
mode = source_stat.st_mode & ~saved_umask;
|
mode = source_stat.st_mode & ~saved_umask;
|
||||||
|
/* Allow owner to access new dir (at least for now) */
|
||||||
mode |= S_IRWXU;
|
mode |= S_IRWXU;
|
||||||
|
|
||||||
if (mkdir(dest, mode) < 0) {
|
if (mkdir(dest, mode) < 0) {
|
||||||
umask(saved_umask);
|
umask(saved_umask);
|
||||||
bb_perror_msg("cannot create directory '%s'", dest);
|
bb_perror_msg("cannot create directory '%s'", dest);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
umask(saved_umask);
|
umask(saved_umask);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Recursively copy files in SOURCE. */
|
/* Recursively copy files in SOURCE */
|
||||||
dp = opendir(source);
|
dp = opendir(source);
|
||||||
if (dp == NULL) {
|
if (dp == NULL) {
|
||||||
status = -1;
|
retval = -1;
|
||||||
goto preserve_status;
|
goto preserve_mode_ugid_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((d = readdir(dp)) != NULL) {
|
while ((d = readdir(dp)) != NULL) {
|
||||||
@ -159,7 +160,7 @@ int copy_file(const char *source, const char *dest, int flags)
|
|||||||
continue;
|
continue;
|
||||||
new_dest = concat_path_file(dest, d->d_name);
|
new_dest = concat_path_file(dest, d->d_name);
|
||||||
if (copy_file(new_source, new_dest, flags) < 0)
|
if (copy_file(new_source, new_dest, flags) < 0)
|
||||||
status = -1;
|
retval = -1;
|
||||||
free(new_source);
|
free(new_source);
|
||||||
free(new_dest);
|
free(new_dest);
|
||||||
}
|
}
|
||||||
@ -169,10 +170,12 @@ int copy_file(const char *source, const char *dest, int flags)
|
|||||||
&& chmod(dest, source_stat.st_mode & ~saved_umask) < 0
|
&& chmod(dest, source_stat.st_mode & ~saved_umask) < 0
|
||||||
) {
|
) {
|
||||||
bb_perror_msg("cannot change permissions of '%s'", dest);
|
bb_perror_msg("cannot change permissions of '%s'", dest);
|
||||||
status = -1;
|
retval = -1;
|
||||||
|
}
|
||||||
|
goto preserve_mode_ugid_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) {
|
if (flags & (FILEUTILS_MAKE_SOFTLINK|FILEUTILS_MAKE_HARDLINK)) {
|
||||||
int (*lf)(const char *oldpath, const char *newpath);
|
int (*lf)(const char *oldpath, const char *newpath);
|
||||||
make_links:
|
make_links:
|
||||||
// Hmm... maybe
|
// Hmm... maybe
|
||||||
@ -188,18 +191,21 @@ int copy_file(const char *source, const char *dest, int flags)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/* _Not_ jumping to preserve_mode_ugid_time:
|
||||||
|
* hard/softlinks don't have those */
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (S_ISREG(source_stat.st_mode)
|
if (S_ISREG(source_stat.st_mode)
|
||||||
/* Huh? DEREF uses stat, which never returns links! */
|
/* Huh? DEREF uses stat, which never returns links! */
|
||||||
/* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */
|
/* || (FLAGS_DEREF && S_ISLNK(source_stat.st_mode)) */
|
||||||
) {
|
) {
|
||||||
int src_fd;
|
int src_fd;
|
||||||
int dst_fd;
|
int dst_fd;
|
||||||
if (ENABLE_FEATURE_PRESERVE_HARDLINKS) {
|
|
||||||
|
if (ENABLE_FEATURE_PRESERVE_HARDLINKS && !FLAGS_DEREF) {
|
||||||
char *link_target;
|
char *link_target;
|
||||||
|
|
||||||
if (!FLAGS_DEREF) {
|
|
||||||
link_target = is_in_ino_dev_hashtable(&source_stat);
|
link_target = is_in_ino_dev_hashtable(&source_stat);
|
||||||
if (link_target) {
|
if (link_target) {
|
||||||
if (link(link_target, dest) < 0) {
|
if (link(link_target, dest) < 0) {
|
||||||
@ -213,14 +219,12 @@ int copy_file(const char *source, const char *dest, int flags)
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
add_to_ino_dev_hashtable(&source_stat, dest);
|
add_to_ino_dev_hashtable(&source_stat, dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
src_fd = open_or_warn(source, O_RDONLY);
|
src_fd = open_or_warn(source, O_RDONLY);
|
||||||
if (src_fd < 0) {
|
if (src_fd < 0)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
|
||||||
|
|
||||||
#if DO_POSIX_CP /* POSIX way (a security problem versus symlink attacks!): */
|
#if DO_POSIX_CP /* POSIX way (a security problem versus symlink attacks!): */
|
||||||
dst_fd = open(dest, (flags & FILEUTILS_INTERACTIVE)
|
dst_fd = open(dest, (flags & FILEUTILS_INTERACTIVE)
|
||||||
@ -264,33 +268,27 @@ int copy_file(const char *source, const char *dest, int flags)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (bb_copyfd_eof(src_fd, dst_fd) == -1)
|
if (bb_copyfd_eof(src_fd, dst_fd) == -1)
|
||||||
status = -1;
|
retval = -1;
|
||||||
if (close(dst_fd) < 0) {
|
if (close(dst_fd) < 0) {
|
||||||
bb_perror_msg("cannot close '%s'", dest);
|
bb_perror_msg("cannot close '%s'", dest);
|
||||||
status = -1;
|
retval = -1;
|
||||||
}
|
}
|
||||||
if (close(src_fd) < 0) {
|
if (close(src_fd) < 0) {
|
||||||
bb_perror_msg("cannot close '%s'", source);
|
bb_perror_msg("cannot close '%s'", source);
|
||||||
status = -1;
|
retval = -1;
|
||||||
|
}
|
||||||
|
goto preserve_mode_ugid_time;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode)
|
/* Source is a symlink or a special file */
|
||||||
|| S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode)
|
/* We are lazy here, a bit lax with races... */
|
||||||
|| S_ISLNK(source_stat.st_mode)
|
|
||||||
) {
|
|
||||||
// We are lazy here, a bit lax with races...
|
|
||||||
if (dest_exists) {
|
if (dest_exists) {
|
||||||
errno = EEXIST;
|
errno = EEXIST;
|
||||||
ovr = ask_and_unlink(dest, flags);
|
ovr = ask_and_unlink(dest, flags);
|
||||||
if (ovr <= 0)
|
if (ovr <= 0)
|
||||||
return ovr;
|
return ovr;
|
||||||
}
|
}
|
||||||
if (S_ISFIFO(source_stat.st_mode)) {
|
if (S_ISLNK(source_stat.st_mode)) {
|
||||||
if (mkfifo(dest, source_stat.st_mode) < 0) {
|
|
||||||
bb_perror_msg("cannot create fifo '%s'", dest);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
} else if (S_ISLNK(source_stat.st_mode)) {
|
|
||||||
char *lpath;
|
char *lpath;
|
||||||
|
|
||||||
lpath = xmalloc_readlink_or_warn(source);
|
lpath = xmalloc_readlink_or_warn(source);
|
||||||
@ -300,25 +298,26 @@ int copy_file(const char *source, const char *dest, int flags)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
free(lpath);
|
free(lpath);
|
||||||
|
|
||||||
if (flags & FILEUTILS_PRESERVE_STATUS)
|
if (flags & FILEUTILS_PRESERVE_STATUS)
|
||||||
if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
|
if (lchown(dest, source_stat.st_uid, source_stat.st_gid) < 0)
|
||||||
bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest);
|
bb_perror_msg("cannot preserve %s of '%s'", "ownership", dest);
|
||||||
|
/* _Not_ jumping to preserve_mode_ugid_time:
|
||||||
|
* symlinks don't have those */
|
||||||
return 0;
|
return 0;
|
||||||
|
}
|
||||||
} else {
|
if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode)
|
||||||
|
|| S_ISSOCK(source_stat.st_mode) || S_ISFIFO(source_stat.st_mode)
|
||||||
|
) {
|
||||||
if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
|
if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
|
||||||
bb_perror_msg("cannot create '%s'", dest);
|
bb_perror_msg("cannot create '%s'", dest);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
bb_error_msg("internal error: unrecognized file type");
|
bb_error_msg("unrecognized file '%s' with mode %x", source, source_stat.st_mode);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
preserve_status:
|
preserve_mode_ugid_time:
|
||||||
|
|
||||||
if (flags & FILEUTILS_PRESERVE_STATUS
|
if (flags & FILEUTILS_PRESERVE_STATUS
|
||||||
/* Cannot happen: */
|
/* Cannot happen: */
|
||||||
@ -338,5 +337,5 @@ int copy_file(const char *source, const char *dest, int flags)
|
|||||||
bb_perror_msg("cannot preserve %s of '%s'", "permissions", dest);
|
bb_perror_msg("cannot preserve %s of '%s'", "permissions", dest);
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -84,6 +84,4 @@ void reset_ino_dev_hashtable(void)
|
|||||||
free(ino_dev_hashtable);
|
free(ino_dev_hashtable);
|
||||||
ino_dev_hashtable = NULL;
|
ino_dev_hashtable = NULL;
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
void reset_ino_dev_hashtable(void);
|
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user