logo

bootstrap-initrd

Linux initrd to bootstrap from a small binary seed git clone https://hacktivis.me/git/make-initrd.git
commit: 19d388c6f1b435706d8e86ca02264dd37aba5035
parent 90ca0f51551b0ecf43cd963b07acb9575aeb0baa
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Tue, 30 Apr 2024 10:53:33 +0200

cp-stub.c: Even with only one source, destination can be a dir

Diffstat:

Mcp-stub.c58++++++++++++++++++++++++++++++++++++++--------------------
1 file changed, 38 insertions(+), 20 deletions(-)

diff --git a/cp-stub.c b/cp-stub.c @@ -16,27 +16,56 @@ #include <unistd.h> // getopt, copy_file_range static int -do_copy(char *src, char *dest) +do_copy(char *src, char *dest, bool is_dir) { assert(errno == 0); int src_fd = open(src, O_RDONLY); if(src_fd < 0) { - fprintf(stderr, "cp: Failed opening file '%s' for reading: %s\n", src, strerror(errno)); + fprintf(stderr, "cp: Failed opening source '%s' for reading: %s\n", src, strerror(errno)); return -1; } struct stat src_stat; if(fstat(src_fd, &src_stat) < 0) { - fprintf(stderr, "cp: Failed getting status for target '%s': %s\n", dest, strerror(errno)); + fprintf(stderr, "cp: Failed getting status for source '%s': %s\n", dest, strerror(errno)); return -1; } - int dest_fd = open(dest, O_CREAT | O_WRONLY | O_TRUNC, src_stat.st_mode & 0777); + if(!is_dir) + { + struct stat dest_stat; + if(stat(dest, &dest_stat) < 0) + { + fprintf(stderr, "cp: Failed getting status for target '%s': %s\n", dest, strerror(errno)); + return -1; + } + if(S_ISDIR(dest_stat.st_mode)) is_dir = true; + } + + char *dest_path = dest; + + if(is_dir) + { + char target[PATH_MAX] = ""; + + char *src_sep = strrchr(src, '/'); + char *src_basename = src_sep != NULL ? src_sep + 1 : src; + + if(snprintf(target, PATH_MAX, "%s/%s", dest, src_basename) < 0) + { + fprintf(stderr, "cp: Failed joining destination '%s' and target '%s'\n", dest, src); + return 1; + } + + dest_path = target; + } + + int dest_fd = open(dest_path, O_CREAT | O_WRONLY | O_TRUNC, src_stat.st_mode & 0777); if(dest_fd < 0) { - fprintf(stderr, "cp: Failed create-opening file '%s' for writing: %s\n", dest, strerror(errno)); + fprintf(stderr, "cp: Failed create-opening destination '%s' for writing: %s\n", dest_path, strerror(errno)); return -1; } @@ -50,7 +79,7 @@ do_copy(char *src, char *dest) fprintf(stderr, "cp: Error: Failed copying data from '%s' to '%s': %s\n", src, - dest, + dest_path, strerror(errno)); return -1; } @@ -102,27 +131,16 @@ main(int argc, char *argv[]) if(argc == 2) { - if(do_copy(argv[0], argv[1]) < 0) return 1; + if(do_copy(argv[0], argv[1], false) < 0) return 1; } else { - char *dest = argv[argc - 1]; - char target[PATH_MAX] = ""; + char *dest = argv[argc - 1]; for(int i = 0; i < argc - 1; i++) { char *src = argv[i]; - - char *src_sep = strrchr(src, '/'); - char *src_basename = src_sep != NULL ? src_sep + 1 : src; - - if(snprintf(target, PATH_MAX, "%s/%s", dest, src_basename) < 0) - { - fprintf(stderr, "cp: Failed joining destination '%s' and target '%s'\n", dest, src); - return 1; - } - - if(do_copy(src, target) < 0) return 1; + if(do_copy(src, dest, true) < 0) return 1; } }