f785d091f869d3936e660c817148e069043c5048
[gnulib.git] / lib / linkat.c
1 /* Create a hard link relative to open directories.
2    Copyright (C) 2009 Free Software Foundation, Inc.
3
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.
8
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.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 /* written by Eric Blake */
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 "filenamecat.h"
33 #include "openat-priv.h"
34
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
45
46 #if !HAVE_LINKAT
47
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)
55 {
56   char *target = areadlink (file1);
57   if (target)
58     {
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)
67         {
68           free (target);
69           errno = ENOMEM;
70           return -1;
71         }
72       if (lstat (file1, &st1) == 0 && stat (dir, &st2) == 0)
73         {
74           if (st1.st_dev == st2.st_dev)
75             {
76               int result = symlink (target, file2);
77               int saved_errno = errno;
78               free (target);
79               free (dir);
80               errno = saved_errno;
81               return result;
82             }
83           free (target);
84           free (dir);
85           errno = EXDEV;
86           return -1;
87         }
88       free (target);
89       free (dir);
90     }
91   if (errno == ENOMEM)
92     return -1;
93   return link (file1, file2);
94 }
95 # endif /* LINK_FOLLOWS_SYMLINKS == 0 */
96
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)
104 {
105   char *name = (char *) file1;
106   char *target;
107   int result;
108   int i = MAXSYMLINKS;
109
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)))
114     {
115       if (IS_ABSOLUTE_FILE_NAME (target))
116         {
117           if (name != file1)
118             free (name);
119           name = target;
120         }
121       else
122         {
123           char *dir = mdir_name (name);
124           if (name != file1)
125             free (name);
126           if (!dir)
127             {
128               free (target);
129               errno = ENOMEM;
130               return -1;
131             }
132           name = mfile_name_concat (dir, target, NULL);
133           free (dir);
134           free (target);
135           if (!name)
136             {
137               errno = ENOMEM;
138               return -1;
139             }
140         }
141     }
142   if (i < 0)
143     {
144       target = NULL;
145       errno = ELOOP;
146     }
147   if (!target && errno != EINVAL)
148     {
149       if (name != file1)
150         {
151           int saved_errno = errno;
152           free (name);
153           errno = saved_errno;
154         }
155       return -1;
156     }
157   result = link (name, file2);
158   if (name != file1)
159     {
160       int saved_errno = errno;
161       free (name);
162       errno = saved_errno;
163     }
164   return result;
165 }
166 # endif /* 0 < LINK_FOLLOWS_SYMLINKS */
167
168 /* Create a link to FILE1, in the directory open on descriptor FD1, to FILE2,
169    in the directory open on descriptor FD2.  If FILE1 is a symlink, FLAG
170    controls whether to dereference FILE1 first.  If possible, do it without
171    changing the working directory.  Otherwise, resort to using
172    save_cwd/fchdir, then rename/restore_cwd.  If either the save_cwd or
173    the restore_cwd fails, then give a diagnostic and exit nonzero.  */
174
175 int
176 linkat (int fd1, char const *file1, int fd2, char const *file2, int flag)
177 {
178   if (flag & ~AT_SYMLINK_FOLLOW)
179     {
180       errno = EINVAL;
181       return -1;
182     }
183   return at_func2 (fd1, file1, fd2, file2,
184                    flag ? link_follow : link_immediate);
185 }
186
187 #else /* HAVE_LINKAT */
188
189 # undef linkat
190
191 /* Read a symlink, like areadlink, but relative to FD.  */
192
193 static char *
194 areadlinkat (int fd, char const *filename)
195 {
196   /* The initial buffer size for the link value.  A power of 2
197      detects arithmetic overflow earlier, but is not required.  */
198 # define INITIAL_BUF_SIZE 1024
199
200   /* Allocate the initial buffer on the stack.  This way, in the common
201      case of a symlink of small size, we get away with a single small malloc()
202      instead of a big malloc() followed by a shrinking realloc().  */
203   char initial_buf[INITIAL_BUF_SIZE];
204
205   char *buffer = initial_buf;
206   size_t buf_size = sizeof (initial_buf);
207
208   while (1)
209     {
210       /* Attempt to read the link into the current buffer.  */
211       ssize_t link_length = readlinkat (fd, filename, buffer, buf_size);
212
213       /* On AIX 5L v5.3 and HP-UX 11i v2 04/09, readlink returns -1
214          with errno == ERANGE if the buffer is too small.  */
215       if (link_length < 0 && errno != ERANGE)
216         {
217           if (buffer != initial_buf)
218             {
219               int saved_errno = errno;
220               free (buffer);
221               errno = saved_errno;
222             }
223           return NULL;
224         }
225
226       if ((size_t) link_length < buf_size)
227         {
228           buffer[link_length++] = '\0';
229
230           /* Return it in a chunk of memory as small as possible.  */
231           if (buffer == initial_buf)
232             {
233               buffer = (char *) malloc (link_length);
234               if (buffer == NULL)
235                 /* errno is ENOMEM.  */
236                 return NULL;
237               memcpy (buffer, initial_buf, link_length);
238             }
239           else
240             {
241               /* Shrink buffer before returning it.  */
242               if ((size_t) link_length < buf_size)
243                 {
244                   char *smaller_buffer = (char *) realloc (buffer, link_length);
245
246                   if (smaller_buffer != NULL)
247                     buffer = smaller_buffer;
248                 }
249             }
250           return buffer;
251         }
252
253       if (buffer != initial_buf)
254         free (buffer);
255       buf_size *= 2;
256       if (SSIZE_MAX < buf_size || (SIZE_MAX / 2 < SSIZE_MAX && buf_size == 0))
257         {
258           errno = ENOMEM;
259           return NULL;
260         }
261       buffer = (char *) malloc (buf_size);
262       if (buffer == NULL)
263         /* errno is ENOMEM.  */
264         return NULL;
265     }
266 }
267
268 /* Create a link.  If FILE1 is a symlink, create a hardlink to the
269    canonicalized file.  */
270
271 static int
272 linkat_follow (int fd1, char const *file1, int fd2, char const *file2)
273 {
274   char *name = (char *) file1;
275   char *target;
276   int result;
277   int i = MAXSYMLINKS;
278
279   /* There is no realpathat.  */
280   while (i-- && (target = areadlinkat (fd1, name)))
281     {
282       if (IS_ABSOLUTE_FILE_NAME (target))
283         {
284           if (name != file1)
285             free (name);
286           name = target;
287         }
288       else
289         {
290           char *dir = mdir_name (name);
291           if (name != file1)
292             free (name);
293           if (!dir)
294             {
295               free (target);
296               errno = ENOMEM;
297               return -1;
298             }
299           name = mfile_name_concat (dir, target, NULL);
300           free (dir);
301           free (target);
302           if (!name)
303             {
304               errno = ENOMEM;
305               return -1;
306             }
307         }
308     }
309   if (i < 0)
310     {
311       target = NULL;
312       errno = ELOOP;
313     }
314   if (!target && errno != EINVAL)
315     {
316       if (name != file1)
317         {
318           int saved_errno = errno;
319           free (name);
320           errno = saved_errno;
321         }
322       return -1;
323     }
324   result = linkat (fd1, name, fd2, file2, 0);
325   if (name != file1)
326     {
327       int saved_errno = errno;
328       free (name);
329       errno = saved_errno;
330     }
331   return result;
332 }
333
334
335 /* Like linkat, but guarantee that AT_SYMLINK_FOLLOW works even on
336    older Linux kernels.  */
337
338 int
339 rpl_linkat (int fd1, char const *file1, int fd2, char const *file2, int flag)
340 {
341   if (!flag)
342     return linkat (fd1, file1, fd2, file2, flag);
343   if (flag & ~AT_SYMLINK_FOLLOW)
344     {
345       errno = EINVAL;
346       return -1;
347     }
348
349   /* Cache the information on whether the system call really works.  */
350   {
351     static int have_follow_really; /* 0 = unknown, 1 = yes, -1 = no */
352     if (0 <= have_follow_really)
353     {
354       int result = linkat (fd1, file1, fd2, file2, flag);
355       if (!(result == -1 && errno == EINVAL))
356         {
357           have_follow_really = 1;
358           return result;
359         }
360       have_follow_really = -1;
361     }
362   }
363   return linkat_follow (fd1, file1, fd2, file2);
364 }
365
366 #endif /* HAVE_LINKAT */