This source file includes following definitions.
- errno_fail
- rename_noreplace
- renameat2ish
- renameatu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 #include <config.h>
20
21 #include "renameatu.h"
22
23 #include <errno.h>
24 #include <stdio.h>
25 #include <sys/stat.h>
26 #include <unistd.h>
27
28 #ifdef __linux__
29 # include <sys/syscall.h>
30 #endif
31
32 static int
33 errno_fail (int e)
34 {
35 errno = e;
36 return -1;
37 }
38
39 #if HAVE_RENAMEAT
40
41 # include <stdbool.h>
42 # include <stdlib.h>
43 # include <string.h>
44
45 # include "dirname.h"
46 # include "openat.h"
47
48 #else
49 # include "openat-priv.h"
50
51 static int
52 rename_noreplace (char const *src, char const *dst)
53 {
54
55 struct stat st;
56 return (lstat (dst, &st) == 0 || errno == EOVERFLOW ? errno_fail (EEXIST)
57 : errno == ENOENT ? rename (src, dst)
58 : -1);
59 }
60 #endif
61
62 #undef renameat
63
64 #if HAVE_RENAMEAT
65
66
67
68
69
70 static int
71 renameat2ish (int fd1, char const *src, int fd2, char const *dst,
72 unsigned int flags)
73 {
74 # ifdef RENAME_EXCL
75 if (flags)
76 {
77 int r = renameatx_np (fd1, src, fd2, dst, RENAME_EXCL);
78 if (r == 0 || errno != ENOTSUP)
79 return r;
80 }
81 # endif
82
83 return renameat (fd1, src, fd2, dst);
84 }
85 #endif
86
87
88
89
90
91
92
93
94
95
96
97
98
99 int
100 renameatu (int fd1, char const *src, int fd2, char const *dst,
101 unsigned int flags)
102 {
103 int ret_val = -1;
104 int err = EINVAL;
105
106 #ifdef HAVE_RENAMEAT2
107 ret_val = renameat2 (fd1, src, fd2, dst, flags);
108 err = errno;
109 #elif defined SYS_renameat2
110 ret_val = syscall (SYS_renameat2, fd1, src, fd2, dst, flags);
111 err = errno;
112 #endif
113
114 if (! (ret_val < 0 && (err == EINVAL || err == ENOSYS || err == ENOTSUP)))
115 return ret_val;
116
117 #if HAVE_RENAMEAT
118 {
119 size_t src_len;
120 size_t dst_len;
121 char *src_temp = (char *) src;
122 char *dst_temp = (char *) dst;
123 bool src_slash;
124 bool dst_slash;
125 int rename_errno = ENOTDIR;
126 struct stat src_st;
127 struct stat dst_st;
128 bool dst_found_nonexistent = false;
129
130 switch (flags)
131 {
132 case 0:
133 break;
134
135 case RENAME_NOREPLACE:
136
137
138
139
140
141 if (lstatat (fd2, dst, &dst_st) == 0 || errno == EOVERFLOW)
142 return errno_fail (EEXIST);
143 if (errno != ENOENT)
144 return -1;
145 dst_found_nonexistent = true;
146 break;
147
148 default:
149 return errno_fail (ENOTSUP);
150 }
151
152
153 src_len = strlen (src);
154 dst_len = strlen (dst);
155 if (!src_len || !dst_len)
156 return renameat2ish (fd1, src, fd2, dst, flags);
157
158 src_slash = src[src_len - 1] == '/';
159 dst_slash = dst[dst_len - 1] == '/';
160 if (!src_slash && !dst_slash)
161 return renameat2ish (fd1, src, fd2, dst, flags);
162
163
164
165
166
167 if (lstatat (fd1, src, &src_st))
168 return -1;
169 if (dst_found_nonexistent)
170 {
171 if (!S_ISDIR (src_st.st_mode))
172 return errno_fail (ENOENT);
173 }
174 else if (lstatat (fd2, dst, &dst_st))
175 {
176 if (errno != ENOENT || !S_ISDIR (src_st.st_mode))
177 return -1;
178 }
179 else if (!S_ISDIR (dst_st.st_mode))
180 return errno_fail (ENOTDIR);
181 else if (!S_ISDIR (src_st.st_mode))
182 return errno_fail (EISDIR);
183
184 # if RENAME_TRAILING_SLASH_SOURCE_BUG
185
186
187
188 ret_val = -1;
189 if (src_slash)
190 {
191 src_temp = strdup (src);
192 if (!src_temp)
193 {
194
195 rename_errno = ENOMEM;
196 goto out;
197 }
198 strip_trailing_slashes (src_temp);
199 if (lstatat (fd1, src_temp, &src_st))
200 {
201 rename_errno = errno;
202 goto out;
203 }
204 if (S_ISLNK (src_st.st_mode))
205 goto out;
206 }
207 if (dst_slash)
208 {
209 dst_temp = strdup (dst);
210 if (!dst_temp)
211 {
212 rename_errno = ENOMEM;
213 goto out;
214 }
215 strip_trailing_slashes (dst_temp);
216 if (lstatat (fd2, dst_temp, &dst_st))
217 {
218 if (errno != ENOENT)
219 {
220 rename_errno = errno;
221 goto out;
222 }
223 }
224 else if (S_ISLNK (dst_st.st_mode))
225 goto out;
226 }
227 # endif
228
229
230
231
232
233
234 ret_val = renameat2ish (fd1, src_temp, fd2, dst_temp, flags);
235 rename_errno = errno;
236 goto out;
237 out:
238 if (src_temp != src)
239 free (src_temp);
240 if (dst_temp != dst)
241 free (dst_temp);
242 errno = rename_errno;
243 return ret_val;
244 }
245 #else
246
247
248 if (flags & ~RENAME_NOREPLACE)
249 return errno_fail (ENOTSUP);
250 return at_func2 (fd1, src, fd2, dst, flags ? rename_noreplace : rename);
251
252 #endif
253 }