aboutsummaryrefslogtreecommitdiff
path: root/0001-Make-cpdir-copy-symlinks.patch
blob: ed8fd025047916c40674c0511481074d7c517035 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
From 64a1cc3f5771187d18725b5fee9cc620e29841a7 Mon Sep 17 00:00:00 2001
From: cyberl0l1 <>
Date: Tue, 23 Jun 2026 00:20:16 +0000
Subject: [PATCH] Make cpdir copy symlinks

---
 src/files.c | 30 +++++++++++++++++++++++++++++-
 1 file changed, 29 insertions(+), 1 deletion(-)

diff --git a/src/files.c b/src/files.c
index 3e5df9f..988b329 100644
--- a/src/files.c
+++ b/src/files.c
@@ -1,6 +1,7 @@
 #include <dirent.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <limits.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
@@ -86,8 +87,35 @@ cleanup0:
   return ret;
 }
 
+#define ERROR_NOT_A_SYMLINK (-2)
+
+static int copy_symlink(int src_dir_fd, const char *src_path, int dst_dir_fd, const char *dst_path) {
+  char symlink_target[PATH_MAX];
+  ssize_t symlink_target_len = readlinkat(src_dir_fd, src_path, symlink_target, sizeof(symlink_target) - 1);
+  if (symlink_target_len >= 0) {
+    symlink_target[symlink_target_len] = '\0';
+
+    if (symlinkat(symlink_target, dst_dir_fd, dst_path) < 0) {
+      perror("symlinkat");
+      return -1;
+    }
+
+    return 0;
+  } else if (errno == EINVAL) {
+    return ERROR_NOT_A_SYMLINK;
+  } else {
+    perror("readlinkat");
+    return -1;
+  }
+}
+
 static int copy_at(int src_dir_fd, const char *src_path, int dst_dir_fd, const char *dst_path) {
-  int ret = -1;
+  int ret = copy_symlink(src_dir_fd, src_path, dst_dir_fd, dst_path);
+  if (ret != ERROR_NOT_A_SYMLINK) {
+    goto cleanup0;
+  }
+
+  ret = -1;
   int src_fd = openat(src_dir_fd, src_path, O_NOFOLLOW | O_RDONLY);
   if (src_fd < 0) {
     perror("openat");
-- 
2.54.0