This source file includes following definitions.
- errno_fail
- rename_noreplace
- 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
65
66
67
68
69
70
71
72
73
74
75
76 int
77 renameatu (int fd1, char const *src, int fd2, char const *dst,
78 unsigned int flags)
79 {
80 int ret_val = -1;
81 int err = EINVAL;
82
83 #ifdef HAVE_RENAMEAT2
84 ret_val = renameat2 (fd1, src, fd2, dst, flags);
85 err = errno;
86 #elif defined SYS_renameat2
87 ret_val = syscall (SYS_renameat2, fd1, src, fd2, dst, flags);
88 err = errno;
89 #endif
90
91 if (! (ret_val < 0 && (err == EINVAL || err == ENOSYS || err == ENOTSUP)))
92 return ret_val;
93
94 #if HAVE_RENAMEAT
95 {
96 # if defined RENAME_EXCL
97 unsigned int uflags;
98 # endif
99 size_t src_len;
100 size_t dst_len;
101 char *src_temp = (char *) src;
102 char *dst_temp = (char *) dst;
103 bool src_slash;
104 bool dst_slash;
105 int rename_errno = ENOTDIR;
106 struct stat src_st;
107 struct stat dst_st;
108 bool dst_found_nonexistent = false;
109
110
111 # if defined RENAME_EXCL
112
113 if (flags & ~(RENAME_EXCHANGE | RENAME_NOREPLACE))
114 # else
115
116 if (flags & ~RENAME_NOREPLACE)
117 # endif
118 return errno_fail (ENOTSUP);
119
120 # if defined RENAME_EXCL
121 uflags = ((flags & RENAME_EXCHANGE ? RENAME_SWAP : 0)
122 | (flags & RENAME_NOREPLACE ? RENAME_EXCL : 0));
123 # endif
124
125 if ((flags & RENAME_NOREPLACE) != 0)
126 {
127
128
129
130
131
132 if (lstatat (fd2, dst, &dst_st) == 0 || errno == EOVERFLOW)
133 return errno_fail (EEXIST);
134 if (errno != ENOENT)
135 return -1;
136 dst_found_nonexistent = true;
137 }
138
139
140 src_len = strlen (src);
141 dst_len = strlen (dst);
142 if (!src_len || !dst_len)
143 # if defined RENAME_EXCL
144 return renameatx_np (fd1, src, fd2, dst, uflags);
145 # else
146 return renameat (fd1, src, fd2, dst);
147 # endif
148
149 src_slash = src[src_len - 1] == '/';
150 dst_slash = dst[dst_len - 1] == '/';
151 if (!src_slash && !dst_slash)
152 # if defined RENAME_EXCL
153 return renameatx_np (fd1, src, fd2, dst, uflags);
154 # else
155 return renameat (fd1, src, fd2, dst);
156 # endif
157
158
159
160
161
162 if (lstatat (fd1, src, &src_st))
163 return -1;
164 if (dst_found_nonexistent)
165 {
166 if (!S_ISDIR (src_st.st_mode))
167 return errno_fail (ENOENT);
168 }
169 else if (lstatat (fd2, dst, &dst_st))
170 {
171 if (errno != ENOENT || !S_ISDIR (src_st.st_mode))
172 return -1;
173 }
174 else if (!S_ISDIR (dst_st.st_mode))
175 return errno_fail (ENOTDIR);
176 else if (!S_ISDIR (src_st.st_mode))
177 return errno_fail (EISDIR);
178
179 # if RENAME_TRAILING_SLASH_SOURCE_BUG
180
181
182
183 ret_val = -1;
184 if (src_slash)
185 {
186 src_temp = strdup (src);
187 if (!src_temp)
188 {
189
190 rename_errno = ENOMEM;
191 goto out;
192 }
193 strip_trailing_slashes (src_temp);
194 if (lstatat (fd1, src_temp, &src_st))
195 {
196 rename_errno = errno;
197 goto out;
198 }
199 if (S_ISLNK (src_st.st_mode))
200 goto out;
201 }
202 if (dst_slash)
203 {
204 dst_temp = strdup (dst);
205 if (!dst_temp)
206 {
207 rename_errno = ENOMEM;
208 goto out;
209 }
210 strip_trailing_slashes (dst_temp);
211 if (lstatat (fd2, dst_temp, &dst_st))
212 {
213 if (errno != ENOENT)
214 {
215 rename_errno = errno;
216 goto out;
217 }
218 }
219 else if (S_ISLNK (dst_st.st_mode))
220 goto out;
221 }
222 # endif
223
224
225
226
227
228
229 # if defined RENAME_EXCL
230 ret_val = renameatx_np (fd1, src_temp, fd2, dst_temp, uflags);
231 # else
232 ret_val = renameat (fd1, src_temp, fd2, dst_temp);
233 # endif
234 rename_errno = errno;
235 goto out;
236 out:
237 if (src_temp != src)
238 free (src_temp);
239 if (dst_temp != dst)
240 free (dst_temp);
241 errno = rename_errno;
242 return ret_val;
243 }
244 #else
245
246
247 if (flags & ~RENAME_NOREPLACE)
248 return errno_fail (ENOTSUP);
249 return at_func2 (fd1, src, fd2, dst, flags ? rename_noreplace : rename);
250
251 #endif
252 }