all: prefer https: URLs
[gnulib.git] / lib / linkat.c
blob481717777f8d42aca89b49ad0324bde1cc5e448e
1 /* Create a hard link relative to open directories.
2 Copyright (C) 2009-2017 Free Software Foundation, Inc.
4 This program is free software: you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3 of the License, or
7 (at your option) any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
17 /* written by Eric Blake */
19 #include <config.h>
21 #include <unistd.h>
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>
30 #include "areadlink.h"
31 #include "dirname.h"
32 #include "filenamecat.h"
33 #include "openat-priv.h"
35 #if HAVE_SYS_PARAM_H
36 # include <sys/param.h>
37 #endif
38 #ifndef MAXSYMLINKS
39 # ifdef SYMLOOP_MAX
40 # define MAXSYMLINKS SYMLOOP_MAX
41 # else
42 # define MAXSYMLINKS 20
43 # endif
44 #endif
46 #if !HAVE_LINKAT || LINKAT_SYMLINK_NOTSUP
48 /* Create a link. If FILE1 is a symlink, either create a hardlink to
49 that symlink, or fake it by creating an identical symlink. */
50 # if LINK_FOLLOWS_SYMLINKS == 0
51 # define link_immediate link
52 # else
53 static int
54 link_immediate (char const *file1, char const *file2)
56 char *target = areadlink (file1);
57 if (target)
59 /* A symlink cannot be modified in-place. Therefore, creating
60 an identical symlink behaves like a hard link to a symlink,
61 except for incorrect st_ino and st_nlink. However, we must
62 be careful of EXDEV. */
63 struct stat st1;
64 struct stat st2;
65 char *dir = mdir_name (file2);
66 if (!dir)
68 free (target);
69 errno = ENOMEM;
70 return -1;
72 if (lstat (file1, &st1) == 0 && stat (dir, &st2) == 0)
74 if (st1.st_dev == st2.st_dev)
76 int result = symlink (target, file2);
77 int saved_errno = errno;
78 free (target);
79 free (dir);
80 errno = saved_errno;
81 return result;
83 free (target);
84 free (dir);
85 errno = EXDEV;
86 return -1;
88 free (target);
89 free (dir);
91 if (errno == ENOMEM)
92 return -1;
93 return link (file1, file2);
95 # endif /* LINK_FOLLOWS_SYMLINKS == 0 */
97 /* Create a link. If FILE1 is a symlink, create a hardlink to the
98 canonicalized file. */
99 # if 0 < LINK_FOLLOWS_SYMLINKS
100 # define link_follow link
101 # else
102 static int
103 link_follow (char const *file1, char const *file2)
105 char *name = (char *) file1;
106 char *target;
107 int result;
108 int i = MAXSYMLINKS;
110 /* Using realpath or canonicalize_file_name is too heavy-handed: we
111 don't need an absolute name, and we don't need to resolve
112 intermediate symlinks, just the basename of each iteration. */
113 while (i-- && (target = areadlink (name)))
115 if (IS_ABSOLUTE_FILE_NAME (target))
117 if (name != file1)
118 free (name);
119 name = target;
121 else
123 char *dir = mdir_name (name);
124 if (name != file1)
125 free (name);
126 if (!dir)
128 free (target);
129 errno = ENOMEM;
130 return -1;
132 name = mfile_name_concat (dir, target, NULL);
133 free (dir);
134 free (target);
135 if (!name)
137 errno = ENOMEM;
138 return -1;
142 if (i < 0)
144 target = NULL;
145 errno = ELOOP;
147 if (!target && errno != EINVAL)
149 if (name != file1)
151 int saved_errno = errno;
152 free (name);
153 errno = saved_errno;
155 return -1;
157 result = link (name, file2);
158 if (name != file1)
160 int saved_errno = errno;
161 free (name);
162 errno = saved_errno;
164 return result;
166 # endif /* 0 < LINK_FOLLOWS_SYMLINKS */
168 /* On Solaris, link() doesn't follow symlinks by default, but does so as soon
169 as a library or executable takes part in the program that has been compiled
170 with "c99" or "cc -xc99=all" or "cc ... /usr/lib/values-xpg4.o ...". */
171 # if LINK_FOLLOWS_SYMLINKS == -1
173 /* Reduce the penalty of link_immediate and link_follow by incorporating the
174 knowledge that link()'s behaviour depends on the __xpg4 variable. */
175 extern int __xpg4;
177 static int
178 solaris_optimized_link_immediate (char const *file1, char const *file2)
180 if (__xpg4 == 0)
181 return link (file1, file2);
182 return link_immediate (file1, file2);
185 static int
186 solaris_optimized_link_follow (char const *file1, char const *file2)
188 if (__xpg4 != 0)
189 return link (file1, file2);
190 return link_follow (file1, file2);
193 # define link_immediate solaris_optimized_link_immediate
194 # define link_follow solaris_optimized_link_follow
196 # endif
198 #endif /* !HAVE_LINKAT || LINKAT_SYMLINK_NOTSUP */
200 #if !HAVE_LINKAT
202 /* Create a link to FILE1, in the directory open on descriptor FD1, to FILE2,
203 in the directory open on descriptor FD2. If FILE1 is a symlink, FLAG
204 controls whether to dereference FILE1 first. If possible, do it without
205 changing the working directory. Otherwise, resort to using
206 save_cwd/fchdir, then rename/restore_cwd. If either the save_cwd or
207 the restore_cwd fails, then give a diagnostic and exit nonzero. */
210 linkat (int fd1, char const *file1, int fd2, char const *file2, int flag)
212 if (flag & ~AT_SYMLINK_FOLLOW)
214 errno = EINVAL;
215 return -1;
217 return at_func2 (fd1, file1, fd2, file2,
218 flag ? link_follow : link_immediate);
221 #else /* HAVE_LINKAT */
223 # undef linkat
225 /* Create a link. If FILE1 is a symlink, create a hardlink to the
226 canonicalized file. */
228 static int
229 linkat_follow (int fd1, char const *file1, int fd2, char const *file2)
231 char *name = (char *) file1;
232 char *target;
233 int result;
234 int i = MAXSYMLINKS;
236 /* There is no realpathat. */
237 while (i-- && (target = areadlinkat (fd1, name)))
239 if (IS_ABSOLUTE_FILE_NAME (target))
241 if (name != file1)
242 free (name);
243 name = target;
245 else
247 char *dir = mdir_name (name);
248 if (name != file1)
249 free (name);
250 if (!dir)
252 free (target);
253 errno = ENOMEM;
254 return -1;
256 name = mfile_name_concat (dir, target, NULL);
257 free (dir);
258 free (target);
259 if (!name)
261 errno = ENOMEM;
262 return -1;
266 if (i < 0)
268 target = NULL;
269 errno = ELOOP;
271 if (!target && errno != EINVAL)
273 if (name != file1)
275 int saved_errno = errno;
276 free (name);
277 errno = saved_errno;
279 return -1;
281 result = linkat (fd1, name, fd2, file2, 0);
282 if (name != file1)
284 int saved_errno = errno;
285 free (name);
286 errno = saved_errno;
288 return result;
292 /* Like linkat, but guarantee that AT_SYMLINK_FOLLOW works even on
293 older Linux kernels. */
296 rpl_linkat (int fd1, char const *file1, int fd2, char const *file2, int flag)
298 if (flag & ~AT_SYMLINK_FOLLOW)
300 errno = EINVAL;
301 return -1;
304 # if LINKAT_TRAILING_SLASH_BUG
305 /* Reject trailing slashes on non-directories. */
307 size_t len1 = strlen (file1);
308 size_t len2 = strlen (file2);
309 if ((len1 && file1[len1 - 1] == '/')
310 || (len2 && file2[len2 - 1] == '/'))
312 /* Let linkat() decide whether hard-linking directories is legal.
313 If fstatat() fails, then linkat() should fail for the same reason;
314 if fstatat() succeeds, require a directory. */
315 struct stat st;
316 if (fstatat (fd1, file1, &st, flag ? 0 : AT_SYMLINK_NOFOLLOW))
317 return -1;
318 if (!S_ISDIR (st.st_mode))
320 errno = ENOTDIR;
321 return -1;
325 # endif
327 if (!flag)
329 int result = linkat (fd1, file1, fd2, file2, flag);
330 # if LINKAT_SYMLINK_NOTSUP
331 /* OS X 10.10 has linkat() but it doesn't support
332 hardlinks to symlinks. Fallback to our emulation
333 in that case. */
334 if (result == -1 && (errno == ENOTSUP || errno == EOPNOTSUPP))
335 return at_func2 (fd1, file1, fd2, file2, link_immediate);
336 # endif
337 return result;
340 /* Cache the information on whether the system call really works. */
342 static int have_follow_really; /* 0 = unknown, 1 = yes, -1 = no */
343 if (0 <= have_follow_really)
345 int result = linkat (fd1, file1, fd2, file2, flag);
346 if (!(result == -1 && errno == EINVAL))
348 have_follow_really = 1;
349 return result;
351 have_follow_really = -1;
354 return linkat_follow (fd1, file1, fd2, file2);
357 #endif /* HAVE_LINKAT */