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:
M | cp-stub.c | 58 | ++++++++++++++++++++++++++++++++++++++-------------------- |
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;
}
}