chiark / gitweb /
eglibc (2.11.3-4+deb6u3) squeeze-lts; urgency=medium
[eglibc.git] / sysdeps / unix / sysv / linux / mkdirat.c
1 /* Copyright (C) 2005, 2006, 2009 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 <string.h>
24 #include <sys/stat.h>
25 #include <kernel-features.h>
26 #include <sysdep-cancel.h>
27
28
29 /* Create a new directory with permission bits MODE.  But interpret
30    relative PATH names relative to the directory associated with FD.  */
31 int
32 mkdirat (fd, file, mode)
33      int fd;
34      const char *file;
35      mode_t mode;
36 {
37   int res;
38
39 #ifdef __NR_mkdirat
40 #  ifndef __ASSUME_ATFCTS
41   if (__have_atfcts >= 0)
42 # endif
43     {
44       res = INLINE_SYSCALL (mkdirat, 3, fd, file, mode);
45 # ifndef __ASSUME_ATFCTS
46       if (res == -1 && res == ENOSYS)
47         __have_atfcts = -1;
48       else
49 # endif
50         return res;
51     }
52 #endif
53
54 #ifndef __ASSUME_ATFCTS
55   char *buf = NULL;
56
57   if (fd != AT_FDCWD && file[0] != '/')
58     {
59       size_t filelen = strlen (file);
60       if (__builtin_expect (filelen == 0, 0))
61         {
62           __set_errno (ENOENT);
63           return -1;
64         }
65
66       static const char procfd[] = "/proc/self/fd/%d/%s";
67       /* Buffer for the path name we are going to use.  It consists of
68          - the string /proc/self/fd/
69          - the file descriptor number
70          - the file name provided.
71          The final NUL is included in the sizeof.   A bit of overhead
72          due to the format elements compensates for possible negative
73          numbers.  */
74       size_t buflen = sizeof (procfd) + sizeof (int) * 3 + filelen;
75       buf = alloca (buflen);
76
77       __snprintf (buf, buflen, procfd, fd, file);
78       file = buf;
79     }
80
81   INTERNAL_SYSCALL_DECL (err);
82   res = INTERNAL_SYSCALL (mkdir, err, 2, file, mode);
83
84   if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (res, err), 0))
85     {
86       __atfct_seterrno (INTERNAL_SYSCALL_ERRNO (res, err), fd, buf);
87       res = -1;
88     }
89
90   return res;
91 #endif
92 }