This source file includes following definitions.
- link_immediate
- link_follow
- solaris_optimized_link_immediate
- solaris_optimized_link_follow
- linkat
- linkat_follow
- rpl_linkat
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 <unistd.h>
22
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <limits.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <sys/stat.h>
29
30 #include "areadlink.h"
31 #include "dirname.h"
32 #include "eloop-threshold.h"
33 #include "filenamecat.h"
34 #include "openat-priv.h"
35
36 #if !HAVE_LINKAT || LINKAT_SYMLINK_NOTSUP
37
38
39
40 # if LINK_FOLLOWS_SYMLINKS == 0
41 # define link_immediate link
42 # else
43 static int
44 link_immediate (char const *file1, char const *file2)
45 {
46 char *target = areadlink (file1);
47 if (target)
48 {
49
50
51
52
53 struct stat st1;
54 struct stat st2;
55 char *dir = mdir_name (file2);
56 if (!dir)
57 {
58 free (target);
59 errno = ENOMEM;
60 return -1;
61 }
62 if (lstat (file1, &st1) == 0 && stat (dir, &st2) == 0)
63 {
64 if (st1.st_dev == st2.st_dev)
65 {
66 int result = symlink (target, file2);
67 free (target);
68 free (dir);
69 return result;
70 }
71 free (target);
72 free (dir);
73 errno = EXDEV;
74 return -1;
75 }
76 free (target);
77 free (dir);
78 }
79 if (errno == ENOMEM)
80 return -1;
81 return link (file1, file2);
82 }
83 # endif
84
85
86
87 # if 0 < LINK_FOLLOWS_SYMLINKS
88 # define link_follow link
89 # else
90 static int
91 link_follow (char const *file1, char const *file2)
92 {
93 char *name = (char *) file1;
94 char *target;
95 int result;
96 int i = __eloop_threshold ();
97
98
99
100
101 while (i-- && (target = areadlink (name)))
102 {
103 if (IS_ABSOLUTE_FILE_NAME (target))
104 {
105 if (name != file1)
106 free (name);
107 name = target;
108 }
109 else
110 {
111 char *dir = mdir_name (name);
112 if (name != file1)
113 free (name);
114 if (!dir)
115 {
116 free (target);
117 errno = ENOMEM;
118 return -1;
119 }
120 name = mfile_name_concat (dir, target, NULL);
121 free (dir);
122 free (target);
123 if (!name)
124 {
125 errno = ENOMEM;
126 return -1;
127 }
128 }
129 }
130 if (i < 0)
131 {
132 target = NULL;
133 errno = ELOOP;
134 }
135 if (!target && errno != EINVAL)
136 {
137 if (name != file1)
138 free (name);
139 return -1;
140 }
141 result = link (name, file2);
142 if (name != file1)
143 free (name);
144 return result;
145 }
146 # endif
147
148
149
150
151 # if LINK_FOLLOWS_SYMLINKS == -1
152
153
154
155 extern int __xpg4;
156
157 static int
158 solaris_optimized_link_immediate (char const *file1, char const *file2)
159 {
160 if (__xpg4 == 0)
161 return link (file1, file2);
162 return link_immediate (file1, file2);
163 }
164
165 static int
166 solaris_optimized_link_follow (char const *file1, char const *file2)
167 {
168 if (__xpg4 != 0)
169 return link (file1, file2);
170 return link_follow (file1, file2);
171 }
172
173 # define link_immediate solaris_optimized_link_immediate
174 # define link_follow solaris_optimized_link_follow
175
176 # endif
177
178 #endif
179
180 #if !HAVE_LINKAT
181
182
183
184
185
186
187
188
189 int
190 linkat (int fd1, char const *file1, int fd2, char const *file2, int flag)
191 {
192 if (flag & ~AT_SYMLINK_FOLLOW)
193 {
194 errno = EINVAL;
195 return -1;
196 }
197 return at_func2 (fd1, file1, fd2, file2,
198 flag ? link_follow : link_immediate);
199 }
200
201 #else
202
203 # undef linkat
204
205
206
207
208 static int
209 linkat_follow (int fd1, char const *file1, int fd2, char const *file2)
210 {
211 char *name = (char *) file1;
212 char *target;
213 int result;
214 int i = __eloop_threshold ();
215
216
217 while (i-- && (target = areadlinkat (fd1, name)))
218 {
219 if (IS_ABSOLUTE_FILE_NAME (target))
220 {
221 if (name != file1)
222 free (name);
223 name = target;
224 }
225 else
226 {
227 char *dir = mdir_name (name);
228 if (name != file1)
229 free (name);
230 if (!dir)
231 {
232 free (target);
233 errno = ENOMEM;
234 return -1;
235 }
236 name = mfile_name_concat (dir, target, NULL);
237 free (dir);
238 free (target);
239 if (!name)
240 {
241 errno = ENOMEM;
242 return -1;
243 }
244 }
245 }
246 if (i < 0)
247 {
248 target = NULL;
249 errno = ELOOP;
250 }
251 if (!target && errno != EINVAL)
252 {
253 if (name != file1)
254 free (name);
255 return -1;
256 }
257 result = linkat (fd1, name, fd2, file2, 0);
258 if (name != file1)
259 free (name);
260 return result;
261 }
262
263
264
265
266
267 int
268 rpl_linkat (int fd1, char const *file1, int fd2, char const *file2, int flag)
269 {
270 if (flag & ~AT_SYMLINK_FOLLOW)
271 {
272 errno = EINVAL;
273 return -1;
274 }
275
276 # if LINKAT_TRAILING_SLASH_BUG
277
278 {
279 size_t len1 = strlen (file1);
280 size_t len2 = strlen (file2);
281 if ((len1 && file1[len1 - 1] == '/')
282 || (len2 && file2[len2 - 1] == '/'))
283 {
284
285
286
287 struct stat st;
288 if (fstatat (fd1, file1, &st, flag ? 0 : AT_SYMLINK_NOFOLLOW))
289 return -1;
290 if (!S_ISDIR (st.st_mode))
291 {
292 errno = ENOTDIR;
293 return -1;
294 }
295 }
296 }
297 # endif
298
299 if (!flag)
300 {
301 int result = linkat (fd1, file1, fd2, file2, flag);
302 # if LINKAT_SYMLINK_NOTSUP
303
304
305
306 if (result == -1 && (errno == ENOTSUP || errno == EOPNOTSUPP))
307 return at_func2 (fd1, file1, fd2, file2, link_immediate);
308 # endif
309 return result;
310 }
311
312
313 {
314 static int have_follow_really;
315 if (0 <= have_follow_really)
316 {
317 int result = linkat (fd1, file1, fd2, file2, flag);
318 if (!(result == -1 && errno == EINVAL))
319 {
320 have_follow_really = 1;
321 return result;
322 }
323 have_follow_really = -1;
324 }
325 }
326 return linkat_follow (fd1, file1, fd2, file2);
327 }
328
329 #endif