2.5-18.1
[jlayton/glibc.git] / sysdeps / unix / sysv / linux / symlinkat.c
1 /* Copyright (C) 2005, 2006 Free Software Foundation, Inc.
2    This file is part of the GNU C Library.
3
4    The GNU C Library is free software; you can redistribute it and/or
5    modify it under the terms of the GNU Lesser General Public
6    License as published by the Free Software Foundation; either
7    version 2.1 of the License, or (at your option) any later version.
8
9    The GNU C Library 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 GNU
12    Lesser General Public License for more details.
13
14    You should have received a copy of the GNU Lesser General Public
15    License along with the GNU C Library; if not, write to the Free
16    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307 USA.  */
18
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <stddef.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sysdep.h>
26 #include <unistd.h>
27 #include <kernel-features.h>
28
29
30 /* Make a symbolic link to FROM named TO relative to TOFD.  */
31 int
32 symlinkat (from, tofd, to)
33      const char *from;
34      int tofd;
35      const char *to;
36 {
37   int result;
38
39 #ifdef __NR_symlinkat
40 # ifndef __ASSUME_ATFCTS
41   if (__have_atfcts >= 0)
42 # endif
43     {
44       result = INLINE_SYSCALL (symlinkat, 3, from, tofd, to);
45 # ifndef __ASSUME_ATFCTS
46       if (result == -1 && errno == ENOSYS)
47         __have_atfcts = -1;
48       else
49 # endif
50         return result;
51     }
52 #endif
53
54 #ifndef __ASSUME_ATFCTS
55   char *buf = NULL;
56
57   if (tofd != AT_FDCWD && to[0] != '/')
58     {
59       size_t tolen = strlen (to);
60       static const char procfd[] = "/proc/self/fd/%d/%s";
61       /* Buffer for the path name we are going to use.  It consists of
62          - the string /proc/self/fd/
63          - the file descriptor number
64          - the file name provided.
65          The final NUL is included in the sizeof.   A bit of overhead
66          due to the format elements compensates for possible negative
67          numbers.  */
68       size_t buflen = sizeof (procfd) + sizeof (int) * 3 + tolen;
69       buf = __alloca (buflen);
70
71       __snprintf (buf, buflen, procfd, tofd, to);
72       to = buf;
73     }
74
75   INTERNAL_SYSCALL_DECL (err);
76
77   result = INTERNAL_SYSCALL (symlink, err, 2, from, to);
78
79   if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0))
80     {
81       __atfct_seterrno (INTERNAL_SYSCALL_ERRNO (result, err), tofd, buf);
82       result = -1;
83     }
84
85   return result;
86 #endif
87 }