about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog15
-rw-r--r--NEWS4
-rw-r--r--include/fcntl.h3
-rw-r--r--io/Makefile2
-rw-r--r--io/Versions3
-rw-r--r--io/linkat.c51
-rw-r--r--io/readlinkat.c50
-rw-r--r--io/symlinkat.c49
-rw-r--r--posix/unistd.h18
-rw-r--r--sysdeps/unix/sysv/linux/linkat.c87
-rw-r--r--sysdeps/unix/sysv/linux/readlinkat.c69
-rw-r--r--sysdeps/unix/sysv/linux/symlinkat.c67
12 files changed, 415 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index 3ed4698053..6b76452de1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2005-12-15  Ulrich Drepper  <drepper@redhat.com>
+
+	* sysdeps/unix/sysv/linux/renameat.c: Move errno setting code in
+	separate function __atfct_seterrno_2.
+	* include/fcntl.h: Declare __atfct_seterrno_2.
+	* posix/unistd.h: Declare linkat, symlinkat, readlinkat.
+	* io/Makefile (routines): Add linkat, symlinkat, readlinkat.
+	* io/Versions [GLIBC_2.4]: Export linkat, symlinkat, readlinkat.
+	* io/linkat.c: New file.
+	* io/readlinkat.c: New file.
+	* io/symlinkat.c: New file.
+	* sysdeps/unix/sysv/linux/linkat.c: New file.
+	* sysdeps/unix/sysv/linux/readlinkat.c: New file.
+	* sysdeps/unix/sysv/linux/symlinkat.c: New file.
+
 2005-12-15  Roland McGrath  <roland@redhat.com>
 
 	[BZ #1997]
diff --git a/NEWS b/NEWS
index 19c24c23dc..41755c383b 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,4 @@
-GNU C Library NEWS -- history of user-visible changes.  2005-12-02
+GNU C Library NEWS -- history of user-visible changes.  2005-12-15
 Copyright (C) 1992-2002,2003,2004,2005 Free Software Foundation, Inc.
 See the end for copying conditions.
 
@@ -28,7 +28,7 @@ Version 2.4
   recommend using the stable 2.3 branch.
 
 * New interfaces: fdopendir, openat, fstatat, fchownat, futimesat, renameat,
-  unlinkat, mkdirat, mkfifoat, mknodat.
+  unlinkat, mkdirat, mkfifoat, mknodat, linkat, symlinkat, readlinkat.
 
 Version 2.3.6
 
diff --git a/include/fcntl.h b/include/fcntl.h
index 6080faba3e..610e322cfd 100644
--- a/include/fcntl.h
+++ b/include/fcntl.h
@@ -21,5 +21,8 @@ libc_hidden_proto (__fcntl)
 /* Helper functions for the various *at functions.  For Linux.  */
 extern void __atfct_seterrno (int errval, int fd, const char *buf)
   attribute_hidden;
+extern void __atfct_seterrno_2 (int errval, int fd1, const char *buf1,
+				int fd2, const char *buf2)
+  attribute_hidden;
 
 #endif
diff --git a/io/Makefile b/io/Makefile
index 76e6072c4b..4731e24d24 100644
--- a/io/Makefile
+++ b/io/Makefile
@@ -45,7 +45,7 @@ routines :=								\
 	getcwd getwd getdirname						\
 	chown fchown lchown fchownat					\
 	ttyname ttyname_r isatty					\
-	link symlink readlink						\
+	link linkat symlink symlinkat readlink readlinkat		\
 	unlink unlinkat rmdir						\
 	ftw ftw64 fts poll						\
 	posix_fadvise posix_fadvise64					\
diff --git a/io/Versions b/io/Versions
index 05b9bfc185..2f0f94f3bb 100644
--- a/io/Versions
+++ b/io/Versions
@@ -100,8 +100,11 @@ libc {
   GLIBC_2.4 {
     fchownat;
     __fxstatat; __fxstatat64;
+    linkat;
     mkdirat; mkfifoat; __xmknodat;
     openat; openat64;
+    readlinkat;
+    symlinkat;
     unlinkat;
   }
 }
diff --git a/io/linkat.c b/io/linkat.c
new file mode 100644
index 0000000000..6420d50334
--- /dev/null
+++ b/io/linkat.c
@@ -0,0 +1,51 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <unistd.h>
+
+
+/* Make a link to FROM relative to FROMFD called TO relative to TOFD.  */
+int
+linkat (fromfd, from, tofd, to)
+     int fromfd;
+     const char *from;
+     int tofd;
+     const char *to;
+{
+  if (from == NULL || to == NULL)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  if ((tofd != AT_FDCWD && tofd < 0 && *to != '/')
+      || (fromfd != AT_FDCWD && fromfd < 0 && *from != '/'))
+    {
+      __set_errno (EBADF);
+      return -1;
+    }
+
+  __set_errno (ENOSYS);
+  return -1;
+}
+stub_warning (linkat)
+
+#include <stub-tag.h>
diff --git a/io/readlinkat.c b/io/readlinkat.c
new file mode 100644
index 0000000000..c6a032c474
--- /dev/null
+++ b/io/readlinkat.c
@@ -0,0 +1,50 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+/* Read the contents of the symbolic link PATH relative to FD into no
+   more than LEN bytes of BUF.  The contents are not null-terminated.
+   Returns the number of characters read, or -1 for errors.  */
+int
+readlinkat (fd, path, buf, len)
+     int fd;
+     const char *path;
+     char *buf;
+     size_t len;
+{
+  if (path == NULL)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  if (fd != AT_FDCWD && fd < 0 && *path != '/')
+    {
+      __set_errno (EBADF);
+      return -1;
+    }
+
+  __set_errno (ENOSYS);
+  return -1;
+}
+stub_warning (readlinkat)
+
+#include <stub-tag.h>
diff --git a/io/symlinkat.c b/io/symlinkat.c
new file mode 100644
index 0000000000..5c2f3f553a
--- /dev/null
+++ b/io/symlinkat.c
@@ -0,0 +1,49 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <unistd.h>
+
+
+/* Make a link to FROM called TO relative to FD.  */
+int
+symlinkat (from, fd, to)
+     const char *from;
+     int fd;
+     const char *to;
+{
+  if (from == NULL || to == NULL)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  if (fd != AT_FDCWD && fd < 0 && *to != '/')
+    {
+      __set_errno (EBADF);
+      return -1;
+    }
+
+  __set_errno (ENOSYS);
+  return -1;
+}
+stub_warning (symlinkat)
+
+#include <stub-tag.h>
diff --git a/posix/unistd.h b/posix/unistd.h
index 86e0e9e659..9684126eaa 100644
--- a/posix/unistd.h
+++ b/posix/unistd.h
@@ -742,6 +742,13 @@ extern int ttyslot (void) __THROW;
 extern int link (__const char *__from, __const char *__to)
      __THROW __nonnull ((1, 2)) __wur;
 
+#ifdef __USE_GNU
+/* Like link but relative paths in TO and FROM are interpreted relative
+   to FROMFD and TOFD respectively.  */
+extern int linkat (int __fromfd, __const char *__from, int __tofd,
+		   __const char *__to) __THROW __nonnull ((2, 4)) __wur;
+#endif
+
 #if defined __USE_BSD || defined __USE_XOPEN_EXTENDED || defined __USE_XOPEN2K
 /* Make a symbolic link to FROM named TO.  */
 extern int symlink (__const char *__from, __const char *__to)
@@ -754,6 +761,17 @@ extern int readlink (__const char *__restrict __path, char *__restrict __buf,
 		     size_t __len) __THROW __nonnull ((1, 2)) __wur;
 #endif /* Use BSD.  */
 
+#ifdef __USE_GNU
+/* Like symlink but a relative path in TO is interpreted relative to TOFD.  */
+extern int symlinkat (__const char *__from, int __tofd,
+		      __const char *__to) __THROW __nonnull ((1, 3)) __wur;
+
+/* Like readlink but a relative PATH is interpreted relative to FD.  */
+extern int readlinkat (int __fd, __const char *__restrict __path,
+		       char *__restrict __buf, size_t __len)
+     __THROW __nonnull ((2, 3)) __wur;
+#endif
+
 /* Remove the link NAME.  */
 extern int unlink (__const char *__name) __THROW __nonnull ((1));
 
diff --git a/sysdeps/unix/sysv/linux/linkat.c b/sysdeps/unix/sysv/linux/linkat.c
new file mode 100644
index 0000000000..8ebff74215
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/linkat.c
@@ -0,0 +1,87 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdio.h>
+#include <sysdep.h>
+#include <unistd.h>
+
+
+/* Make a link to FROM named TO but relative paths in TO and FROM are
+   interpreted relative to FROMFD and TOFD respectively.  */
+int
+linkat (fromfd, from, tofd, to)
+     int fromfd;
+     const char *from;
+     int tofd;
+     const char *to;
+{
+  static const char procfd[] = "/proc/self/fd/%d/%s";
+  char *buffrom = NULL;
+
+  if (fromfd != AT_FDCWD && from[0] != '/')
+    {
+      size_t filelen = strlen (from);
+      /* Buffer for the path name we are going to use.  It consists of
+	 - the string /proc/self/fd/
+	 - the file descriptor number
+	 - the file name provided.
+	 The final NUL is included in the sizeof.   A bit of overhead
+	 due to the format elements compensates for possible negative
+	 numbers.  */
+      size_t buflen = sizeof (procfd) + sizeof (int) * 3 + filelen;
+      buffrom = alloca (buflen);
+
+      __snprintf (buffrom, buflen, procfd, fromfd, from);
+      from = buffrom;
+    }
+
+  char *bufto = NULL;
+
+  if (tofd != AT_FDCWD && to[0] != '/')
+    {
+      size_t filelen = strlen (to);
+      /* Buffer for the path name we are going to use.  It consists of
+	 - the string /proc/self/fd/
+	 - the file descriptor number
+	 - the file name provided.
+	 The final NUL is included in the sizeof.   A bit of overhead
+	 due to the format elements compensates for possible negative
+	 numbers.  */
+      size_t buflen = sizeof (procfd) + sizeof (int) * 3 + filelen;
+      bufto = alloca (buflen);
+
+      __snprintf (bufto, buflen, procfd, tofd, to);
+      to = bufto;
+    }
+
+  INTERNAL_SYSCALL_DECL (err);
+
+  int result = INTERNAL_SYSCALL (link, err, 2, from,  to);
+
+  if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0))
+    {
+      __atfct_seterrno_2 (INTERNAL_SYSCALL_ERRNO (result, err), tofd, bufto,
+			  fromfd, buffrom);
+      result = -1;
+    }
+
+  return result;
+}
diff --git a/sysdeps/unix/sysv/linux/readlinkat.c b/sysdeps/unix/sysv/linux/readlinkat.c
new file mode 100644
index 0000000000..42c3877bd7
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/readlinkat.c
@@ -0,0 +1,69 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <unistd.h>
+
+
+/* Read the contents of the symbolic link PATH relative to FD into no
+   more than LEN bytes of BUF.  */
+int
+readlinkat (fd, path, buf, len)
+     int fd;
+     const char *path;
+     char *buf;
+     size_t len;
+{
+  char *pathbuf = NULL;
+
+  if (fd != AT_FDCWD && path[0] != '/')
+    {
+      size_t pathlen = strlen (path);
+      static const char procfd[] = "/proc/self/fd/%d/%s";
+      /* Buffer for the path name we are going to use.  It consists of
+	 - the string /proc/self/fd/
+	 - the file descriptor number
+	 - the file name provided.
+	 The final NUL is included in the sizeof.   A bit of overhead
+	 due to the format elements compensates for possible negative
+	 numbers.  */
+      size_t buflen = sizeof (procfd) + sizeof (int) * 3 + pathlen;
+      pathbuf = __alloca (buflen);
+
+      __snprintf (pathbuf, buflen, procfd, fd, path);
+      path = pathbuf;
+    }
+
+  INTERNAL_SYSCALL_DECL (err);
+
+  int result = INTERNAL_SYSCALL (readlink, err, 3, path, buf, len);
+
+  if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0))
+    {
+      __atfct_seterrno (INTERNAL_SYSCALL_ERRNO (result, err), fd, pathbuf);
+      result = -1;
+    }
+
+  return result;
+}
diff --git a/sysdeps/unix/sysv/linux/symlinkat.c b/sysdeps/unix/sysv/linux/symlinkat.c
new file mode 100644
index 0000000000..211b49c299
--- /dev/null
+++ b/sysdeps/unix/sysv/linux/symlinkat.c
@@ -0,0 +1,67 @@
+/* Copyright (C) 2005 Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <unistd.h>
+
+
+/* Make a symbolic link to FROM named TO relative to TOFD.  */
+int
+symlinkat (from, tofd, to)
+     const char *from;
+     int tofd;
+     const char *to;
+{
+  char *buf = NULL;
+
+  if (tofd != AT_FDCWD && to[0] != '/')
+    {
+      size_t tolen = strlen (to);
+      static const char procfd[] = "/proc/self/fd/%d/%s";
+      /* Buffer for the path name we are going to use.  It consists of
+	 - the string /proc/self/fd/
+	 - the file descriptor number
+	 - the file name provided.
+	 The final NUL is included in the sizeof.   A bit of overhead
+	 due to the format elements compensates for possible negative
+	 numbers.  */
+      size_t buflen = sizeof (procfd) + sizeof (int) * 3 + tolen;
+      buf = __alloca (buflen);
+
+      __snprintf (buf, buflen, procfd, tofd, to);
+      to = buf;
+    }
+
+  INTERNAL_SYSCALL_DECL (err);
+
+  int result = INTERNAL_SYSCALL (symlink, err, 2, from, to);
+
+  if (__builtin_expect (INTERNAL_SYSCALL_ERROR_P (result, err), 0))
+    {
+      __atfct_seterrno (INTERNAL_SYSCALL_ERRNO (result, err), tofd, buf);
+      result = -1;
+    }
+
+  return result;
+}