[Glibc-bsd-commits] r2559 - trunk/glibc-ports/kfreebsd

Aurelien Jarno aurel32 at alioth.debian.org
Mon Jun 1 23:18:37 UTC 2009


Author: aurel32
Date: 2009-06-01 23:18:37 +0000 (Mon, 01 Jun 2009)
New Revision: 2559

Added:
   trunk/glibc-ports/kfreebsd/faccessat.c
   trunk/glibc-ports/kfreebsd/fchmodat.c
   trunk/glibc-ports/kfreebsd/fchownat.c
   trunk/glibc-ports/kfreebsd/fexecve.c
   trunk/glibc-ports/kfreebsd/futimesat.c
   trunk/glibc-ports/kfreebsd/fxstatat.c
   trunk/glibc-ports/kfreebsd/fxstatat64.c
   trunk/glibc-ports/kfreebsd/linkat.c
   trunk/glibc-ports/kfreebsd/mkdirat.c
   trunk/glibc-ports/kfreebsd/readlinkat.c
   trunk/glibc-ports/kfreebsd/renameat.c
   trunk/glibc-ports/kfreebsd/symlinkat.c
   trunk/glibc-ports/kfreebsd/unlinkat.c
   trunk/glibc-ports/kfreebsd/xmknodat.c
Modified:
   trunk/glibc-ports/kfreebsd/Makefile
   trunk/glibc-ports/kfreebsd/kernel-features.h
   trunk/glibc-ports/kfreebsd/openat.c
   trunk/glibc-ports/kfreebsd/openat64.c
   trunk/glibc-ports/kfreebsd/syscalls.list
Log:
Add *at() syscalls support, part of POSIX.1-2008.



Modified: trunk/glibc-ports/kfreebsd/Makefile
===================================================================
--- trunk/glibc-ports/kfreebsd/Makefile	2009-06-01 12:44:51 UTC (rev 2558)
+++ trunk/glibc-ports/kfreebsd/Makefile	2009-06-01 23:18:37 UTC (rev 2559)
@@ -31,13 +31,17 @@
 
 ifeq ($(subdir),io)
 # For <unistd.h>.
-sysdep_routines += sys_getcwd sys_lseek sys_freebsd6_lseek
+sysdep_routines += sys_fchownat sys_fexecve sys_getcwd sys_linkat sys_lseek sys_freebsd6_lseek sys_readlinkat sys_symlinkat sys_unlinkat
 # For <fcntl.h>.
-sysdep_routines += sys_open open_2
+sysdep_routines += sys_open sys_openat open_2
 # For <sys/stat.h>.
-sysdep_routines += sys_fstat sys_lstat sys_mknod sys_nfstat sys_nlstat sys_nstat sys_stat
+sysdep_routines += sys_fchmodat sys_fstat sys_fstatat sys_lstat sys_mkdirat sys_mkfifoat sys_mknod sys_mknodat sys_nfstat sys_nlstat sys_nstat sys_stat
 # For <sys/statfs.h>.
 sysdep_routines += fstatfs64 statfs64 sys_fstatfs sys_statfs
+# For <stdio.h>
+sysdep_routines += sys_renameat
+# For <sys/times.h>.
+sysdep_routines += sys_futimesat
 # Other.
 sysdep_routines += lchmod
 endif
@@ -51,7 +55,7 @@
 # For <sched.h>.
 sysdep_routines += clone start_thread
 # For <unistd.h>.
-sysdep_routines += sys_ftruncate sys_freebsd6_ftruncate sys_truncate sys_freebsd6_truncate
+sysdep_routines += sys_faccessat sys_ftruncate sys_freebsd6_ftruncate sys_truncate sys_freebsd6_truncate
 # For <sys/acl.h>.
 sysdep_routines += acl_aclcheck_fd acl_aclcheck_file acl_delete_fd acl_delete_file acl_get_fd acl_get_file acl_set_fd acl_set_file
 # For <sys/extattr.h>.

Added: trunk/glibc-ports/kfreebsd/faccessat.c
===================================================================
--- trunk/glibc-ports/kfreebsd/faccessat.c	                        (rev 0)
+++ trunk/glibc-ports/kfreebsd/faccessat.c	2009-06-01 23:18:37 UTC (rev 2559)
@@ -0,0 +1,164 @@
+/* Test for access to file, relative to open directory.  Linux version.
+   Copyright (C) 2006 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 <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <kernel-features.h>
+#include <sysdep.h>
+
+extern int __syscall_faccessat (int fd, const char *path, mode_t mode,
+				int flag);
+libc_hidden_proto (__syscall_faccessat)
+
+int
+faccessat (fd, file, mode, flag)
+     int fd;
+     const char *file;
+     int mode;
+     int flag;
+{
+# ifndef __ASSUME_ATFCTS
+  if (__have_atfcts >= 0)
+# endif
+    {
+      int result = INLINE_SYSCALL (faccessat, 4, fd, file, mode, flag);
+# ifndef __ASSUME_ATFCTS
+      if (result == -1 && errno == ENOSYS)
+	__have_atfcts = -1;
+      else
+# endif
+	return result;
+    }
+
+#ifndef __ASSUME_ATFCTS
+  if (flag & ~(AT_SYMLINK_NOFOLLOW | AT_EACCESS))
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  if ((!(flag & AT_EACCESS) || !__libc_enable_secure)
+      && !(flag & AT_SYMLINK_NOFOLLOW))
+    {
+      /* If we are not set-uid or set-gid, access does the same.  */
+      if (fd != AT_FDCWD && file[0] != '/')
+	{
+	  int mib[4];
+	  size_t kf_len = 0;
+	  char *kf_buf, *kf_bufp;
+
+	  if (fd < 0)
+	    {
+	      __set_errno (EBADF);
+	      return -1;
+	    }
+
+	  mib[0] = CTL_KERN;
+	  mib[1] = KERN_PROC;
+	  mib[2] = KERN_PROC_FILEDESC;
+	  mib[3] = __getpid ();
+
+	  if (sysctl (mib, 4, NULL, &kf_len, NULL, 0) != 0)
+	    {
+	      __set_errno (ENOSYS);
+	      return -1;
+	    }
+
+	  kf_buf = alloca (kf_len + strlen (file));
+	  if (sysctl (mib, 4, kf_buf, &kf_len, NULL, 0) != 0)
+	    {
+	      __set_errno (ENOSYS);
+	      return -1;
+	    }
+
+	  kf_bufp = kf_buf;
+	  while (kf_bufp < kf_buf + kf_len)
+	    {
+	      struct kinfo_file *kf =
+		(struct kinfo_file *) (uintptr_t) kf_bufp;
+
+	      if (kf->kf_fd == fd)
+		{
+		  if (kf->kf_type != KF_TYPE_VNODE ||
+		      kf->kf_vnode_type != KF_VTYPE_VDIR)
+		    {
+		      __set_errno (ENOTDIR);
+		      return -1;
+		    }
+
+		  strcat (kf->kf_path, "/");
+		  strcat (kf->kf_path, file);
+		  file = kf->kf_path;
+		  break;
+		}
+	      kf_bufp += kf->kf_structsize;
+	    }
+
+	  if (kf_bufp >= kf_buf + kf_len)
+	    {
+	      __set_errno (EBADF);
+	      return -1;
+	    }
+	}
+
+      return __access (file, mode);
+    }
+#endif
+
+  struct stat64 stats;
+  if (fstatat64 (fd, file, &stats, flag & AT_SYMLINK_NOFOLLOW))
+    return -1;
+
+  mode &= (X_OK | W_OK | R_OK);	/* Clear any bogus bits. */
+#if R_OK != S_IROTH || W_OK != S_IWOTH || X_OK != S_IXOTH
+# error Oops, portability assumptions incorrect.
+#endif
+
+  if (mode == F_OK)
+    return 0;			/* The file exists. */
+
+  uid_t uid = (flag & AT_EACCESS) ? __geteuid () : __getuid ();
+
+  /* The super-user can read and write any file, and execute any file
+     that anyone can execute. */
+  if (uid == 0 && ((mode & X_OK) == 0
+		   || (stats.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))))
+    return 0;
+
+  int granted = (uid == stats.st_uid
+		 ? (unsigned int) (stats.st_mode & (mode << 6)) >> 6
+		 : (stats.st_gid == ((flag & AT_EACCESS)
+				     ? __getegid () : __getgid ())
+		    || __group_member (stats.st_gid))
+		 ? (unsigned int) (stats.st_mode & (mode << 3)) >> 3
+		 : (stats.st_mode & mode));
+
+  if (granted == mode)
+    return 0;
+
+  __set_errno (EACCES);
+  return -1;
+}

Added: trunk/glibc-ports/kfreebsd/fchmodat.c
===================================================================
--- trunk/glibc-ports/kfreebsd/fchmodat.c	                        (rev 0)
+++ trunk/glibc-ports/kfreebsd/fchmodat.c	2009-06-01 23:18:37 UTC (rev 2559)
@@ -0,0 +1,130 @@
+/* Copyright (C) 2009 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <kernel-features.h>
+
+extern int __syscall_fchmodat (int fd, const char *path,
+			       mode_t mode, int flag);
+libc_hidden_proto (__syscall_fchmodat)
+
+/* This is specific to kFreeBSD. */
+extern int __lchmod (__const char *__file, __mode_t __mode);
+
+int
+fchmodat (fd, file, mode, flag)
+     int fd;
+     const char *file;
+     mode_t mode;
+     int flag;
+{
+# ifndef __ASSUME_ATFCTS
+  if (__have_atfcts >= 0)
+# endif
+    {
+      int result = INLINE_SYSCALL (fchmodat, 4, fd, file, mode, flag);
+# ifndef __ASSUME_ATFCTS
+      if (result == -1 && errno == ENOSYS)
+	__have_atfcts = -1;
+      else
+# endif
+	return result;
+    }
+
+#ifndef __ASSUME_ATFCTS
+  if (flag & ~AT_SYMLINK_NOFOLLOW)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  if (fd != AT_FDCWD && file[0] != '/')
+    {
+      int mib[4];
+      size_t kf_len = 0;
+      char *kf_buf, *kf_bufp;
+
+      if (fd < 0)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+
+      mib[0] = CTL_KERN;
+      mib[1] = KERN_PROC;
+      mib[2] = KERN_PROC_FILEDESC;
+      mib[3] = __getpid ();
+
+      if (sysctl (mib, 4, NULL, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_buf = alloca (kf_len + strlen (file));
+      if (sysctl (mib, 4, kf_buf, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_bufp = kf_buf;
+      while (kf_bufp < kf_buf + kf_len)
+	{
+	  struct kinfo_file *kf = (struct kinfo_file *) (uintptr_t) kf_bufp;
+
+	  if (kf->kf_fd == fd)
+	    {
+	      if (kf->kf_type != KF_TYPE_VNODE ||
+		  kf->kf_vnode_type != KF_VTYPE_VDIR)
+		{
+		  __set_errno (ENOTDIR);
+		  return -1;
+		}
+
+	      strcat (kf->kf_path, "/");
+	      strcat (kf->kf_path, file);
+	      file = kf->kf_path;
+	      break;
+	    }
+	  kf_bufp += kf->kf_structsize;
+	}
+
+      if (kf_bufp >= kf_buf + kf_len)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+    }
+
+  if (flag & AT_SYMLINK_NOFOLLOW)
+    return __lchmod(file, mode);
+  else
+    return __chmod(file, mode);
+#endif
+}

Added: trunk/glibc-ports/kfreebsd/fchownat.c
===================================================================
--- trunk/glibc-ports/kfreebsd/fchownat.c	                        (rev 0)
+++ trunk/glibc-ports/kfreebsd/fchownat.c	2009-06-01 23:18:37 UTC (rev 2559)
@@ -0,0 +1,129 @@
+/* Copyright (C) 2009 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <kernel-features.h>
+
+extern int __syscall_fchownat (int fd, const char *path, uid_t uid,
+			       gid_t gid, int flag);
+libc_hidden_proto (__syscall_fchownat)
+
+/* Change the owner and group of FILE.  */
+int
+fchownat (fd, file, owner, group, flag)
+     int fd;
+     const char *file;
+     uid_t owner;
+     gid_t group;
+     int flag;
+{
+# ifndef __ASSUME_ATFCTS
+  if (__have_atfcts >= 0)
+# endif
+    {
+      int result = INLINE_SYSCALL (fchownat, 5, fd, file, owner, group, flag);
+# ifndef __ASSUME_ATFCTS
+      if (result == -1 && errno == ENOSYS)
+	__have_atfcts = -1;
+      else
+# endif
+	return result;
+    }
+
+#ifndef __ASSUME_ATFCTS
+  if (flag & ~AT_SYMLINK_NOFOLLOW)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  if (fd != AT_FDCWD && file[0] != '/')
+    {
+      int mib[4];
+      size_t kf_len = 0;
+      char *kf_buf, *kf_bufp;
+
+      if (fd < 0)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+
+      mib[0] = CTL_KERN;
+      mib[1] = KERN_PROC;
+      mib[2] = KERN_PROC_FILEDESC;
+      mib[3] = __getpid ();
+
+      if (sysctl (mib, 4, NULL, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_buf = alloca (kf_len + strlen (file));
+      if (sysctl (mib, 4, kf_buf, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_bufp = kf_buf;
+      while (kf_bufp < kf_buf + kf_len)
+	{
+	  struct kinfo_file *kf = (struct kinfo_file *) (uintptr_t) kf_bufp;
+
+	  if (kf->kf_fd == fd)
+	    {
+	      if (kf->kf_type != KF_TYPE_VNODE ||
+		  kf->kf_vnode_type != KF_VTYPE_VDIR)
+		{
+		  __set_errno (ENOTDIR);
+		  return -1;
+		}
+
+	      strcat (kf->kf_path, "/");
+	      strcat (kf->kf_path, file);
+	      file = kf->kf_path;
+	      break;
+	    }
+	  kf_bufp += kf->kf_structsize;
+	}
+
+      if (kf_bufp >= kf_buf + kf_len)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+    }
+
+  if (flag & AT_SYMLINK_NOFOLLOW)
+    return __lchown(file, owner, group);
+  else
+    return __chown(file, owner, group);
+#endif
+}

Added: trunk/glibc-ports/kfreebsd/fexecve.c
===================================================================
--- trunk/glibc-ports/kfreebsd/fexecve.c	                        (rev 0)
+++ trunk/glibc-ports/kfreebsd/fexecve.c	2009-06-01 23:18:37 UTC (rev 2559)
@@ -0,0 +1,103 @@
+/* Copyright (C) 2009 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <kernel-features.h>
+
+extern int __syscall_fexecve (int fd, char *const argv[], char *const envp[]);
+libc_hidden_proto (__syscall_fexecve);
+
+/* Execute the file FD refers to, overlaying the running program image.
+   ARGV and ENVP are passed to the new program, as for `execve'.  */
+int
+fexecve (fd, argv, envp)
+     int fd;
+     char *const argv[];
+     char *const envp[];
+{
+# ifndef __ASSUME_ATFCTS
+  if (__have_atfcts >= 0)
+# endif
+    {
+      int result = INLINE_SYSCALL (fexecve, 3, fd, argv, envp);
+# ifndef __ASSUME_ATFCTS
+      if (result == -1 && errno == ENOSYS)
+	__have_atfcts = -1;
+      else
+# endif
+	return result;
+    }
+
+#ifndef __ASSUME_ATFCTS
+  if (fd < 0 || argv == NULL || envp == NULL)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  int mib[4];
+  size_t kf_len = 0;
+  char *kf_buf, *kf_bufp;
+
+  mib[0] = CTL_KERN;
+  mib[1] = KERN_PROC;
+  mib[2] = KERN_PROC_FILEDESC;
+  mib[3] = __getpid ();
+
+  if (sysctl (mib, 4, NULL, &kf_len, NULL, 0) != 0)
+    {
+      __set_errno (ENOSYS);
+      return -1;
+    }
+
+  kf_buf = alloca (kf_len);
+  if (sysctl (mib, 4, kf_buf, &kf_len, NULL, 0) != 0)
+    {
+      __set_errno (ENOSYS);
+      return -1;
+    }
+
+  kf_bufp = kf_buf;
+  while (kf_bufp < kf_buf + kf_len)
+    {
+      struct kinfo_file *kf = (struct kinfo_file *) (uintptr_t) kf_bufp;
+
+      if (kf->kf_fd == fd)
+	{
+	  if (kf->kf_type == KF_TYPE_VNODE &&
+	      kf->kf_vnode_type == KF_VTYPE_VREG)
+	    return __execve (kf->kf_path, argv, envp);
+	  break;
+	}
+      kf_bufp += kf->kf_structsize;
+    }
+
+  __set_errno (EINVAL);
+  return -1;
+#endif
+}

Added: trunk/glibc-ports/kfreebsd/futimesat.c
===================================================================
--- trunk/glibc-ports/kfreebsd/futimesat.c	                        (rev 0)
+++ trunk/glibc-ports/kfreebsd/futimesat.c	2009-06-01 23:18:37 UTC (rev 2559)
@@ -0,0 +1,119 @@
+/* Copyright (C) 2009 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <kernel-features.h>
+
+extern int __syscall_futimesat (int fd, const char *path,
+				struct timeval *times);
+libc_hidden_proto (__syscall_futimesat)
+
+/* Change the access time of FILE relative to FD to TVP[0] and
+   the modification time of FILE to TVP[1].  */
+int
+futimesat (fd, file, tvp)
+     int fd;
+     const char *file;
+     const struct timeval tvp[2];
+{
+# ifndef __ASSUME_ATFCTS
+  if (__have_atfcts >= 0)
+# endif
+    {
+      int result = INLINE_SYSCALL (futimesat, 3, fd, file, tvp);
+# ifndef __ASSUME_ATFCTS
+      if (result == -1 && errno == ENOSYS)
+	__have_atfcts = -1;
+      else
+# endif
+	return result;
+    }
+
+#ifndef __ASSUME_ATFCTS
+  if (fd != AT_FDCWD && file[0] != '/')
+    {
+      int mib[4];
+      size_t kf_len = 0;
+      char *kf_buf, *kf_bufp;
+
+      if (fd < 0)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+
+      mib[0] = CTL_KERN;
+      mib[1] = KERN_PROC;
+      mib[2] = KERN_PROC_FILEDESC;
+      mib[3] = __getpid ();
+
+      if (sysctl (mib, 4, NULL, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_buf = alloca (kf_len + strlen (file));
+      if (sysctl (mib, 4, kf_buf, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_bufp = kf_buf;
+      while (kf_bufp < kf_buf + kf_len)
+	{
+	  struct kinfo_file *kf = (struct kinfo_file *) (uintptr_t) kf_bufp;
+
+	  if (kf->kf_fd == fd)
+	    {
+	      if (kf->kf_type != KF_TYPE_VNODE ||
+		  kf->kf_vnode_type != KF_VTYPE_VDIR)
+		{
+		  __set_errno (ENOTDIR);
+		  return -1;
+		}
+
+	      strcat (kf->kf_path, "/");
+	      strcat (kf->kf_path, file);
+	      file = kf->kf_path;
+	      break;
+	    }
+	  kf_bufp += kf->kf_structsize;
+	}
+
+      if (kf_bufp >= kf_buf + kf_len)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+    }
+
+  return __utimes(file, tvp);
+#endif
+}

Added: trunk/glibc-ports/kfreebsd/fxstatat.c
===================================================================
--- trunk/glibc-ports/kfreebsd/fxstatat.c	                        (rev 0)
+++ trunk/glibc-ports/kfreebsd/fxstatat.c	2009-06-01 23:18:37 UTC (rev 2559)
@@ -0,0 +1,150 @@
+/* Copyright (C) 2009 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <kernel-features.h>
+#include <bp-checks.h>
+
+#include "stat16conv.c"
+
+extern int __syscall_fstatat (int fd, const char *path,
+			      struct stat16 *buf, int flag);
+libc_hidden_proto (__syscall_fstatat)
+
+/* Get information about the file NAME relative to FD in ST.  */
+int
+__fxstatat (int vers, int fd, const char *file, struct stat *st, int flag)
+{
+# ifndef __ASSUME_ATFCTS
+  if (__have_atfcts >= 0)
+# endif
+    {
+      int result;
+
+      if (__builtin_expect (vers == _STAT_VER, 1))
+	{
+	  struct stat16 buf16;
+	  result =
+	    INLINE_SYSCALL (fstatat, 4, fd, CHECK_STRING (file),
+			    __ptrvalue (&buf16), flag);
+	  if (result == 0)
+	    stat16_to_stat (&buf16, st);
+	}
+      else if (__builtin_expect (vers == _STAT_VER_stat, 1))
+	{
+	  result =
+	    INLINE_SYSCALL (fstatat, 4, fd, CHECK_STRING (file),
+			    CHECK_1 ((struct stat16 *) st), flag);
+	}
+      else
+	{
+	  __set_errno (EINVAL);
+	  return -1;
+	}
+# ifndef __ASSUME_ATFCTS
+      if (result == -1 && errno == ENOSYS)
+	__have_atfcts = -1;
+      else
+# endif
+	return result;
+    }
+
+#ifndef __ASSUME_ATFCTS
+  if (flag & ~AT_SYMLINK_NOFOLLOW)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  if (fd != AT_FDCWD && file[0] != '/')
+    {
+      int mib[4];
+      size_t kf_len = 0;
+      char *kf_buf, *kf_bufp;
+
+      if (fd < 0)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+
+      mib[0] = CTL_KERN;
+      mib[1] = KERN_PROC;
+      mib[2] = KERN_PROC_FILEDESC;
+      mib[3] = __getpid ();
+
+      if (sysctl (mib, 4, NULL, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_buf = alloca (kf_len + strlen (file));
+      if (sysctl (mib, 4, kf_buf, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_bufp = kf_buf;
+      while (kf_bufp < kf_buf + kf_len)
+	{
+	  struct kinfo_file *kf = (struct kinfo_file *) (uintptr_t) kf_bufp;
+
+	  if (kf->kf_fd == fd)
+	    {
+	      if (kf->kf_type != KF_TYPE_VNODE ||
+		  kf->kf_vnode_type != KF_VTYPE_VDIR)
+		{
+		  __set_errno (ENOTDIR);
+		  return -1;
+		}
+
+	      strcat (kf->kf_path, "/");
+	      strcat (kf->kf_path, file);
+	      file = kf->kf_path;
+	      break;
+	    }
+	  kf_bufp += kf->kf_structsize;
+	}
+
+      if (kf_bufp >= kf_buf + kf_len)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+    }
+
+  if (flag & AT_SYMLINK_NOFOLLOW)
+    return __lxstat (vers, file, st);
+  else
+    return __xstat (vers, file, st);
+#endif
+}
+
+libc_hidden_def (__fxstatat)

Added: trunk/glibc-ports/kfreebsd/fxstatat64.c
===================================================================
--- trunk/glibc-ports/kfreebsd/fxstatat64.c	                        (rev 0)
+++ trunk/glibc-ports/kfreebsd/fxstatat64.c	2009-06-01 23:18:37 UTC (rev 2559)
@@ -0,0 +1,144 @@
+/* Copyright (C) 2009 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <kernel-features.h>
+#include <bp-checks.h>
+
+#include "stat16conv.c"
+
+extern int __syscall_fstatat (int fd, const char *path,
+			      struct stat16 *buf, int flag);
+libc_hidden_proto (__syscall_fstatat)
+
+/* Get information about the file NAME relative to FD in ST.  */
+int
+__fxstatat64 (int vers, int fd, const char *file, struct stat64 *st, int flag)
+{
+# ifndef __ASSUME_ATFCTS
+  if (__have_atfcts >= 0)
+# endif
+    {
+      int result;
+
+      if (__builtin_expect (vers == _STAT_VER, 1))
+	{
+	  struct stat16 buf16;
+	  result =
+	    INLINE_SYSCALL (fstatat, 4, fd, CHECK_STRING (file),
+			    __ptrvalue (&buf16), flag);
+	  if (result == 0)
+	    stat16_to_stat64 (&buf16, st);
+	}
+      else
+	{
+	  __set_errno (EINVAL);
+	  return -1;
+	}
+# ifndef __ASSUME_ATFCTS
+      if (result == -1 && errno == ENOSYS)
+	__have_atfcts = -1;
+      else
+# endif
+	return result;
+    }
+
+#ifndef __ASSUME_ATFCTS
+  if (flag & ~AT_SYMLINK_NOFOLLOW)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  if (fd != AT_FDCWD && file[0] != '/')
+    {
+      int mib[4];
+      size_t kf_len = 0;
+      char *kf_buf, *kf_bufp;
+
+      if (fd < 0)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+
+      mib[0] = CTL_KERN;
+      mib[1] = KERN_PROC;
+      mib[2] = KERN_PROC_FILEDESC;
+      mib[3] = __getpid ();
+
+      if (sysctl (mib, 4, NULL, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_buf = alloca (kf_len + strlen (file));
+      if (sysctl (mib, 4, kf_buf, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_bufp = kf_buf;
+      while (kf_bufp < kf_buf + kf_len)
+	{
+	  struct kinfo_file *kf = (struct kinfo_file *) (uintptr_t) kf_bufp;
+
+	  if (kf->kf_fd == fd)
+	    {
+	      if (kf->kf_type != KF_TYPE_VNODE ||
+		  kf->kf_vnode_type != KF_VTYPE_VDIR)
+		{
+		  __set_errno (ENOTDIR);
+		  return -1;
+		}
+
+	      strcat (kf->kf_path, "/");
+	      strcat (kf->kf_path, file);
+	      file = kf->kf_path;
+	      break;
+	    }
+	  kf_bufp += kf->kf_structsize;
+	}
+
+      if (kf_bufp >= kf_buf + kf_len)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+    }
+
+  if (flag & AT_SYMLINK_NOFOLLOW)
+    return __lxstat64 (vers, file, st);
+  else
+    return __xstat64 (vers, file, st);
+#endif
+}
+
+libc_hidden_def (__fxstatat64)

Modified: trunk/glibc-ports/kfreebsd/kernel-features.h
===================================================================
--- trunk/glibc-ports/kfreebsd/kernel-features.h	2009-06-01 12:44:51 UTC (rev 2558)
+++ trunk/glibc-ports/kfreebsd/kernel-features.h	2009-06-01 23:18:37 UTC (rev 2559)
@@ -73,3 +73,8 @@
 # define __ASSUME_TRUNCATE_SYSCALL	1
 #endif
 
+/* The `*at' syscalls were introduced in kFreeBSD 8.0. */
+#if __KFREEBSD_KERNEL_VERSION >= 0x80000
+# define __ASSUME_ATFCTS        1
+#endif
+

Added: trunk/glibc-ports/kfreebsd/linkat.c
===================================================================
--- trunk/glibc-ports/kfreebsd/linkat.c	                        (rev 0)
+++ trunk/glibc-ports/kfreebsd/linkat.c	2009-06-01 23:18:37 UTC (rev 2559)
@@ -0,0 +1,171 @@
+/* Copyright (C) 2009 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <stdio.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <kernel-features.h>
+
+extern int __syscall_linkat (int fd1, const char *path1, int fd2,
+			       const char *path2, int flags);
+libc_hidden_proto (__syscall_linkat)
+
+/* 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, flags)
+     int fromfd;
+     const char *from;
+     int tofd;
+     const char *to;
+     int flags;
+{
+# ifndef __ASSUME_ATFCTS
+  if (__have_atfcts >= 0)
+# endif
+    {
+      int result = INLINE_SYSCALL (linkat, 5, fromfd, from, tofd, to, flags);
+# ifndef __ASSUME_ATFCTS
+      if (result == -1 && errno == ENOSYS)
+	__have_atfcts = -1;
+      else
+# endif
+	return result;
+    }
+
+#ifndef __ASSUME_ATFCTS
+  /* Without kernel support we cannot handle AT_SYMLINK_FOLLOW.  */
+  if (flags != 0)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  if ((fromfd != AT_FDCWD && from[0] != '/')
+      || (tofd != AT_FDCWD && to[0] != '/'))
+    {
+      int mib[4];
+      size_t kf_len = 0;
+      char *kf_buf, *kf_bufp;
+
+      if ((fromfd < 0) || (tofd < 0))
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+
+      mib[0] = CTL_KERN;
+      mib[1] = KERN_PROC;
+      mib[2] = KERN_PROC_FILEDESC;
+      mib[3] = __getpid ();
+
+      if (sysctl (mib, 4, NULL, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_buf = alloca (kf_len);
+      if (sysctl (mib, 4, kf_buf, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      if (fromfd != AT_FDCWD && from[0] != '/')
+	{
+	  kf_bufp = kf_buf;
+	  while (kf_bufp < kf_buf + kf_len)
+	    {
+	      struct kinfo_file *kf =
+		(struct kinfo_file *) (uintptr_t) kf_bufp;
+
+	      if (kf->kf_fd == fromfd)
+		{
+		  char *buf;
+		  if (kf->kf_type != KF_TYPE_VNODE ||
+		      kf->kf_vnode_type != KF_VTYPE_VDIR)
+		    {
+		      __set_errno (ENOTDIR);
+		      return -1;
+		    }
+
+		  buf = alloca (strlen (kf->kf_path) + strlen (from) + 2);
+		  strcpy(buf, kf->kf_path);
+		  strcat (buf, "/");
+		  strcat (buf, from);
+		  from = buf;
+		  break;
+		}
+	      kf_bufp += kf->kf_structsize;
+	    }
+
+	  if (kf_bufp >= kf_buf + kf_len)
+	    {
+	      __set_errno (EBADF);
+	      return -1;
+	    }
+	}
+
+      if (tofd != AT_FDCWD && to[0] != '/')
+	{
+	  kf_bufp = kf_buf;
+	  while (kf_bufp < kf_buf + kf_len)
+	    {
+	      struct kinfo_file *kf =
+		(struct kinfo_file *) (uintptr_t) kf_bufp;
+
+	      if (kf->kf_fd == tofd)
+		{
+		  char *buf;
+		  if (kf->kf_type != KF_TYPE_VNODE ||
+		      kf->kf_vnode_type != KF_VTYPE_VDIR)
+		    {
+		      __set_errno (ENOTDIR);
+		      return -1;
+		    }
+
+		  buf = alloca (strlen (kf->kf_path) + strlen (to) + 2);
+		  strcpy(buf, kf->kf_path);
+		  strcat (buf, "/");
+		  strcat (buf, to);
+		  to = buf;
+		  break;
+		}
+	      kf_bufp += kf->kf_structsize;
+	    }
+
+	  if (kf_bufp >= kf_buf + kf_len)
+	    {
+	      __set_errno (EBADF);
+	      return -1;
+	    }
+	}
+    }
+  
+  return __link (from, to);
+#endif
+}

Added: trunk/glibc-ports/kfreebsd/mkdirat.c
===================================================================
--- trunk/glibc-ports/kfreebsd/mkdirat.c	                        (rev 0)
+++ trunk/glibc-ports/kfreebsd/mkdirat.c	2009-06-01 23:18:37 UTC (rev 2559)
@@ -0,0 +1,118 @@
+/* Copyright (C) 2009 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 file the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Bosfilen, MA
+   02111-1307 USA.  */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <kernel-features.h>
+
+extern int __syscall_mkdirat (int fd, const char *path, mode_t mode);
+libc_hidden_proto (__syscall_mkdirat)
+
+/* Create a new direcfilery with permission bits MODE.  But interpret
+   relative PATH names relative file the direcfilery associated with FD.  */
+int
+mkdirat (fd, file, mode)
+     int fd;
+     const char *file;
+     mode_t mode;
+{
+# ifndef __ASSUME_ATFCTS
+  if (__have_atfcts >= 0)
+# endif
+    {
+      int result = INLINE_SYSCALL (mkdirat, 3, fd, file, mode);
+# ifndef __ASSUME_ATFCTS
+      if (result == -1 && errno == ENOSYS)
+	__have_atfcts = -1;
+      else
+# endif
+	return result;
+    }
+
+#ifndef __ASSUME_ATFCTS
+  if (fd != AT_FDCWD && file[0] != '/')
+    {
+      int mib[4];
+      size_t kf_len = 0;
+      char *kf_buf, *kf_bufp;
+
+      if (fd < 0)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+
+      mib[0] = CTL_KERN;
+      mib[1] = KERN_PROC;
+      mib[2] = KERN_PROC_FILEDESC;
+      mib[3] = __getpid ();
+
+      if (sysctl (mib, 4, NULL, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_buf = alloca (kf_len + strlen (file));
+      if (sysctl (mib, 4, kf_buf, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_bufp = kf_buf;
+      while (kf_bufp < kf_buf + kf_len)
+	{
+	  struct kinfo_file *kf = (struct kinfo_file *) (uintptr_t) kf_bufp;
+
+	  if (kf->kf_fd == fd)
+	    {
+	      if (kf->kf_type != KF_TYPE_VNODE ||
+		  kf->kf_vnode_type != KF_VTYPE_VDIR)
+		{
+		  __set_errno (ENOTDIR);
+		  return -1;
+		}
+
+	      strcat (kf->kf_path, "/");
+	      strcat (kf->kf_path, file);
+	      file = kf->kf_path;
+	      break;
+	    }
+	  kf_bufp += kf->kf_structsize;
+	}
+
+      if (kf_bufp >= kf_buf + kf_len)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+    }
+
+  return __mkdir (file, mode);
+#endif
+}

Modified: trunk/glibc-ports/kfreebsd/openat.c
===================================================================
--- trunk/glibc-ports/kfreebsd/openat.c	2009-06-01 12:44:51 UTC (rev 2558)
+++ trunk/glibc-ports/kfreebsd/openat.c	2009-06-01 23:18:37 UTC (rev 2559)
@@ -1,4 +1,4 @@
-/* Copyright (C) 2005, 2006 Free Software Foundation, Inc.
+/* Copyright (C) 2005, 2006, 2007 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
@@ -21,12 +21,26 @@
 #include <stdarg.h>
 #include <stddef.h>
 #include <stdio.h>
-#include <string.h>
+#include <unistd.h>
+#include <sysdep.h>
 #include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
 #include <kernel-features.h>
 #include <sysdep-cancel.h>
 #include <not-cancel.h>
 
+extern int __syscall_openat (int fd, const char *path, int flag, mode_t mode);
+libc_hidden_proto (__syscall_openat)
+
+# ifndef __ASSUME_ATFCTS
+int __have_atfcts = 0;
+#endif
+
+/* Open FILE with access OFLAG.  Interpret relative paths relative to
+   the directory associated with FD.  If OFLAG includes O_CREAT, a
+   third argument is the file protection.  */
 int
 __openat_nocancel (fd, file, oflag, mode)
      int fd;
@@ -34,23 +48,84 @@
      int oflag;
      mode_t mode;
 {
+# ifndef __ASSUME_ATFCTS
+  if (__have_atfcts >= 0)
+# endif
+    {
+      int result = INLINE_SYSCALL (openat, 4, fd, file, oflag, mode);
+# ifndef __ASSUME_ATFCTS
+      if (result == -1 && errno == ENOSYS)
+	__have_atfcts = -1;
+      else
+# endif
+	return result;
+    }
+
+#ifndef __ASSUME_ATFCTS
   if (fd != AT_FDCWD && file[0] != '/')
     {
-      /* Check FD is associated with a directory.  */
-      struct stat64 st;
-      if (__fxstat64 (_STAT_VER, fd, &st) != 0)
-	/* errno is already set correctly.  */
-        return -1;
+      int mib[4];
+      size_t kf_len = 0;
+      char *kf_buf, *kf_bufp;
 
-      if (!S_ISDIR (st.st_mode))
-	__set_errno (ENOTDIR);
-      else
-	__set_errno (ENOSYS);
-      return -1;
+      if (fd < 0)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+
+      mib[0] = CTL_KERN;
+      mib[1] = KERN_PROC;
+      mib[2] = KERN_PROC_FILEDESC;
+      mib[3] = __getpid ();
+
+      if (sysctl (mib, 4, NULL, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_buf = alloca (kf_len + strlen (file));
+      if (sysctl (mib, 4, kf_buf, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_bufp = kf_buf;
+      while (kf_bufp < kf_buf + kf_len)
+	{
+	  struct kinfo_file *kf = (struct kinfo_file *) (uintptr_t) kf_bufp;
+
+	  if (kf->kf_fd == fd)
+	    {
+	      if (kf->kf_type != KF_TYPE_VNODE ||
+		  kf->kf_vnode_type != KF_VTYPE_VDIR)
+		{
+		  __set_errno (ENOTDIR);
+		  return -1;
+		}
+
+	      strcat (kf->kf_path, "/");
+	      strcat (kf->kf_path, file);
+	      file = kf->kf_path;
+	      break;
+	    }
+	  kf_bufp += kf->kf_structsize;
+	}
+
+      if (kf_bufp >= kf_buf + kf_len)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+
     }
   return INLINE_SYSCALL (open, 3, file, oflag, mode);
+#endif
 }
 
+strong_alias (__openat_nocancel, __openat64_nocancel)
 
 /* Open FILE with access OFLAG.  Interpret relative paths relative to
    the directory associated with FD.  If OFLAG includes O_CREAT, a
@@ -61,7 +136,9 @@
      const char *file;
      int oflag;
 {
-  mode_t mode = 0;
+  int mode = 0;
+  int result;
+
   if (oflag & O_CREAT)
     {
       va_list arg;
@@ -70,29 +147,138 @@
       va_end (arg);
     }
 
-  if (SINGLE_THREAD_P)
-    return __openat_nocancel (fd, file, oflag, mode);
+# ifndef __ASSUME_ATFCTS
+  if (__have_atfcts >= 0)
+# endif
+    {
+      if (SINGLE_THREAD_P)
+	{
+	  result = INLINE_SYSCALL (openat, 4, fd, file, oflag, mode);
+	}
+      else
+	{
+	  int oldtype = LIBC_CANCEL_ASYNC ();
+	  result = INLINE_SYSCALL (openat, 4, fd, file, oflag, mode);
+	  LIBC_CANCEL_RESET (oldtype);
+	}
+# ifndef __ASSUME_ATFCTS
+      if (result == -1 && errno == ENOSYS)
+	__have_atfcts = -1;
+# endif
+    }
 
-  int oldtype = LIBC_CANCEL_ASYNC ();
+#ifndef __ASSUME_ATFCTS
+  if (__have_atfcts < 0)
+    {
+      if (fd != AT_FDCWD && file[0] != '/')
+	{
+	  int mib[4];
+	  size_t kf_len = 0;
+	  char *kf_buf, *kf_bufp;
 
-  int res = __openat_nocancel (fd, file, oflag, mode);
+	  if (fd < 0)
+	    {
+	      __set_errno (EBADF);
+	      return -1;
+	    }
 
-  LIBC_CANCEL_RESET (oldtype);
+	  mib[0] = CTL_KERN;
+	  mib[1] = KERN_PROC;
+	  mib[2] = KERN_PROC_FILEDESC;
+	  mib[3] = __getpid ();
 
-  return res;
+	  if (sysctl (mib, 4, NULL, &kf_len, NULL, 0) != 0)
+	    {
+	      __set_errno (ENOSYS);
+	      return -1;
+	    }
+
+	  kf_buf = alloca (kf_len + strlen (file));
+	  if (sysctl (mib, 4, kf_buf, &kf_len, NULL, 0) != 0)
+	    {
+	      __set_errno (ENOSYS);
+	      return -1;
+	    }
+
+	  kf_bufp = kf_buf;
+	  while (kf_bufp < kf_buf + kf_len)
+	    {
+	      struct kinfo_file *kf =
+		(struct kinfo_file *) (uintptr_t) kf_bufp;
+
+	      if (kf->kf_fd == fd)
+		{
+		  if (kf->kf_type != KF_TYPE_VNODE ||
+		      kf->kf_vnode_type != KF_VTYPE_VDIR)
+		    {
+		      __set_errno (ENOTDIR);
+		      return -1;
+		    }
+
+		  strcat (kf->kf_path, "/");
+		  strcat (kf->kf_path, file);
+		  file = kf->kf_path;
+		  break;
+		}
+	      kf_bufp += kf->kf_structsize;
+	    }
+
+	  if (kf_bufp >= kf_buf + kf_len)
+	    {
+	      __set_errno (EBADF);
+	      return -1;
+	    }
+	}
+      if (SINGLE_THREAD_P)
+	{
+	  result = INLINE_SYSCALL (open, 3, file, oflag, mode);
+	}
+      else
+	{
+	  int oldtype = LIBC_CANCEL_ASYNC ();
+	  result = INLINE_SYSCALL (open, 3, file, oflag, mode);
+	  LIBC_CANCEL_RESET (oldtype);
+	}
+
+    }
+#endif
+
+  if (result >= 0 && (oflag & O_TRUNC))
+    {
+      /* Set the modification time.  The kernel ought to do this.  */
+      int saved_errno = errno;
+      struct timeval tv[2];
+
+      if (__gettimeofday (&tv[1], NULL) >= 0)
+	{
+	  struct stat statbuf;
+
+	  if (__fxstat (_STAT_VER, result, &statbuf) >= 0)
+	    {
+	      tv[0].tv_sec = statbuf.st_atime;
+	      tv[0].tv_usec = 0;
+
+#ifdef NOT_IN_libc
+	      futimes (fd, tv);
+#else
+	      __futimes (fd, tv);
+#endif
+	    }
+	}
+      __set_errno (saved_errno);
+    }
+
+  return result;
 }
+
 libc_hidden_def (__openat)
 weak_alias (__openat, openat)
 
-/* openat64 is just the same as openat for us.  */
+/* 'openat64' is the same as 'openat', because __off64_t == __off_t.  */
 strong_alias (__openat, __openat64)
-strong_alias (__openat_nocancel, __openat64_nocancel)
-libc_hidden_weak (__openat64)
+libc_hidden_def (__openat64)
 weak_alias (__openat64, openat64)
 
-stub_warning (openat)
-stub_warning (openat64)
-
 int
 __openat_2 (fd, file, oflag)
      int fd;
@@ -106,5 +292,3 @@
 }
 
 strong_alias (__openat_2, __openat64_2)
-stub_warning (__openat_2)
-stub_warning (__openat64_2)

Modified: trunk/glibc-ports/kfreebsd/openat64.c
===================================================================
--- trunk/glibc-ports/kfreebsd/openat64.c	2009-06-01 12:44:51 UTC (rev 2558)
+++ trunk/glibc-ports/kfreebsd/openat64.c	2009-06-01 23:18:37 UTC (rev 2559)
@@ -1,2 +1,2 @@
-/* 'openat64' is the same as 'open', because __off64_t == __off_t and
+/* 'openat64' is the same as 'openat', because __off64_t == __off_t and
    O_LARGEFILE == 0.  */

Added: trunk/glibc-ports/kfreebsd/readlinkat.c
===================================================================
--- trunk/glibc-ports/kfreebsd/readlinkat.c	                        (rev 0)
+++ trunk/glibc-ports/kfreebsd/readlinkat.c	2009-06-01 23:18:37 UTC (rev 2559)
@@ -0,0 +1,122 @@
+/* Copyright (C) 2009 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <kernel-features.h>
+
+extern int __syscall_readlinkat (int fd, const char *path, char *buf, 
+				 size_t bufsize);
+libc_hidden_proto (__syscall_readlinkat)
+
+/* Read the contents of the symbolic link PATH relative to FD into no
+   more than LEN bytes of BUF.  */
+ssize_t
+readlinkat (fd, path, buf, len)
+     int fd;
+     const char *path;
+     char *buf;
+     size_t len;
+{
+# ifndef __ASSUME_ATFCTS
+  if (__have_atfcts >= 0)
+# endif
+    {
+      int result = INLINE_SYSCALL (readlinkat, 4, fd, path, buf, len);
+# ifndef __ASSUME_ATFCTS
+      if (result == -1 && errno == ENOSYS)
+	__have_atfcts = -1;
+      else
+# endif
+	return result;
+    }
+
+#ifndef __ASSUME_ATFCTS
+  if (fd != AT_FDCWD && path[0] != '/')
+    {
+      int mib[4];
+      size_t kf_len = 0;
+      char *kf_buf, *kf_bufp;
+
+      if (fd < 0)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+
+      mib[0] = CTL_KERN;
+      mib[1] = KERN_PROC;
+      mib[2] = KERN_PROC_FILEDESC;
+      mib[3] = __getpid ();
+
+      if (sysctl (mib, 4, NULL, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_buf = alloca (kf_len + strlen (path));
+      if (sysctl (mib, 4, kf_buf, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_bufp = kf_buf;
+      while (kf_bufp < kf_buf + kf_len)
+	{
+	  struct kinfo_file *kf = (struct kinfo_file *) (uintptr_t) kf_bufp;
+
+	  if (kf->kf_fd == fd)
+	    {
+	      if (kf->kf_type != KF_TYPE_VNODE ||
+		  kf->kf_vnode_type != KF_VTYPE_VDIR)
+		{
+		  __set_errno (ENOTDIR);
+		  return -1;
+		}
+
+	      strcat (kf->kf_path, "/");
+	      strcat (kf->kf_path, path);
+	      path = kf->kf_path;
+	      break;
+	    }
+	  kf_bufp += kf->kf_structsize;
+	}
+
+      if (kf_bufp >= kf_buf + kf_len)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+    }
+
+  return __readlink (path, buf, len);
+#endif
+}
+
+libc_hidden_def (readlinkat)

Added: trunk/glibc-ports/kfreebsd/renameat.c
===================================================================
--- trunk/glibc-ports/kfreebsd/renameat.c	                        (rev 0)
+++ trunk/glibc-ports/kfreebsd/renameat.c	2009-06-01 23:18:37 UTC (rev 2559)
@@ -0,0 +1,161 @@
+/* Copyright (C) 2009 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <stdio.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <kernel-features.h>
+
+extern int __syscall_renameat (int oldfd, const char *old, int newfd,
+			       const char *new);
+libc_hidden_proto (__syscall_renameat)
+
+/* Rename the file OLD relative to OLDFD to NEW relative to NEWFD.  */
+int renameat (oldfd, old, newfd, new)
+     int oldfd;
+     const char *old;
+     int newfd;
+     const char *new;
+{
+# ifndef __ASSUME_ATFCTS
+  if (__have_atfcts >= 0)
+# endif
+    {
+      int result = INLINE_SYSCALL (renameat, 4, oldfd, old, newfd, new);
+# ifndef __ASSUME_ATFCTS
+      if (result == -1 && errno == ENOSYS)
+	__have_atfcts = -1;
+      else
+# endif
+	return result;
+    }
+
+#ifndef __ASSUME_ATFCTS
+  if ((oldfd != AT_FDCWD && old[0] != '/')
+      || (newfd != AT_FDCWD && new[0] != '/'))
+    {
+      int mib[4];
+      size_t kf_len = 0;
+      char *kf_buf, *kf_bufp;
+
+      if ((oldfd < 0) || (newfd < 0))
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+
+      mib[0] = CTL_KERN;
+      mib[1] = KERN_PROC;
+      mib[2] = KERN_PROC_FILEDESC;
+      mib[3] = __getpid ();
+
+      if (sysctl (mib, 4, NULL, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_buf = alloca (kf_len);
+      if (sysctl (mib, 4, kf_buf, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      if (oldfd != AT_FDCWD && old[0] != '/')
+	{
+	  kf_bufp = kf_buf;
+	  while (kf_bufp < kf_buf + kf_len)
+	    {
+	      struct kinfo_file *kf =
+		(struct kinfo_file *) (uintptr_t) kf_bufp;
+
+	      if (kf->kf_fd == oldfd)
+		{
+		  char *buf;
+		  if (kf->kf_type != KF_TYPE_VNODE ||
+		      kf->kf_vnode_type != KF_VTYPE_VDIR)
+		    {
+		      __set_errno (ENOTDIR);
+		      return -1;
+		    }
+
+		  buf = alloca (strlen (kf->kf_path) + strlen (old) + 2);
+		  strcpy(buf, kf->kf_path);
+		  strcat (buf, "/");
+		  strcat (buf, old);
+		  old = buf;
+		  break;
+		}
+	      kf_bufp += kf->kf_structsize;
+	    }
+
+	  if (kf_bufp >= kf_buf + kf_len)
+	    {
+	      __set_errno (EBADF);
+	      return -1;
+	    }
+	}
+
+      if (newfd != AT_FDCWD && new[0] != '/')
+	{
+	  kf_bufp = kf_buf;
+	  while (kf_bufp < kf_buf + kf_len)
+	    {
+	      struct kinfo_file *kf =
+		(struct kinfo_file *) (uintptr_t) kf_bufp;
+
+	      if (kf->kf_fd == newfd)
+		{
+		  char *buf;
+		  if (kf->kf_type != KF_TYPE_VNODE ||
+		      kf->kf_vnode_type != KF_VTYPE_VDIR)
+		    {
+		      __set_errno (ENOTDIR);
+		      return -1;
+		    }
+
+		  buf = alloca (strlen (kf->kf_path) + strlen (new) + 2);
+		  strcpy(buf, kf->kf_path);
+		  strcat (buf, "/");
+		  strcat (buf, new);
+		  new = buf;
+		  break;
+		}
+	      kf_bufp += kf->kf_structsize;
+	    }
+
+	  if (kf_bufp >= kf_buf + kf_len)
+	    {
+	      __set_errno (EBADF);
+	      return -1;
+	    }
+	}
+    }
+  
+  return rename (old, new);
+#endif
+}

Added: trunk/glibc-ports/kfreebsd/symlinkat.c
===================================================================
--- trunk/glibc-ports/kfreebsd/symlinkat.c	                        (rev 0)
+++ trunk/glibc-ports/kfreebsd/symlinkat.c	2009-06-01 23:18:37 UTC (rev 2559)
@@ -0,0 +1,118 @@
+/* Copyright (C) 2009 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <kernel-features.h>
+
+extern int __syscall_symlinkat (const char *path1, int fd,
+				const char *path2);
+libc_hidden_proto (__syscall_symlinkat)
+
+/* Make a symbolic link to FROM named TO relative to TOFD.  */
+int
+symlinkat (from, tofd, to)
+     const char *from;
+     int tofd;
+     const char *to;
+{
+# ifndef __ASSUME_ATFCTS
+  if (__have_atfcts >= 0)
+# endif
+    {
+      int result = INLINE_SYSCALL (symlinkat, 3, from, tofd, to);
+# ifndef __ASSUME_ATFCTS
+      if (result == -1 && errno == ENOSYS)
+	__have_atfcts = -1;
+      else
+# endif
+	return result;
+    }
+
+#ifndef __ASSUME_ATFCTS
+  if (tofd != AT_FDCWD && to[0] != '/')
+    {
+      int mib[4];
+      size_t kf_len = 0;
+      char *kf_buf, *kf_bufp;
+
+      if (tofd < 0)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+
+      mib[0] = CTL_KERN;
+      mib[1] = KERN_PROC;
+      mib[2] = KERN_PROC_FILEDESC;
+      mib[3] = __getpid ();
+
+      if (sysctl (mib, 4, NULL, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_buf = alloca (kf_len + strlen (to));
+      if (sysctl (mib, 4, kf_buf, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_bufp = kf_buf;
+      while (kf_bufp < kf_buf + kf_len)
+	{
+	  struct kinfo_file *kf = (struct kinfo_file *) (uintptr_t) kf_bufp;
+
+	  if (kf->kf_fd == tofd)
+	    {
+	      if (kf->kf_type != KF_TYPE_VNODE ||
+		  kf->kf_vnode_type != KF_VTYPE_VDIR)
+		{
+		  __set_errno (ENOTDIR);
+		  return -1;
+		}
+
+	      strcat (kf->kf_path, "/");
+	      strcat (kf->kf_path, to);
+	      to = kf->kf_path;
+	      break;
+	    }
+	  kf_bufp += kf->kf_structsize;
+	}
+
+      if (kf_bufp >= kf_buf + kf_len)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+    }
+
+  return __symlink (from, to);
+#endif
+}

Modified: trunk/glibc-ports/kfreebsd/syscalls.list
===================================================================
--- trunk/glibc-ports/kfreebsd/syscalls.list	2009-06-01 12:44:51 UTC (rev 2558)
+++ trunk/glibc-ports/kfreebsd/syscalls.list	2009-06-01 23:18:37 UTC (rev 2559)
@@ -55,7 +55,7 @@
 kldunload		-	kldunload		i:i		kldunload
 kldunloadf		-	kldunloadf		i:ii		kldunloadf
 ktrace			-	ktrace			i:siii		ktrace
-lchmod			-	lchmod			i:si		lchmod
+lchmod			-	lchmod			i:si		__lchmod lchmod
 lchown			-	lchown			i:sii		__lchown lchown
 sys_lio_listio		-	lio_listio		i:ibnP		__syscall_lio_listio
 sys_lseek		-	lseek			i:iii		__syscall_lseek
@@ -161,4 +161,18 @@
 sys_umtx		-	_umtx_op		i:piipp		__syscall__umtx_op
 sys_cpuset_getaffinity	-	cpuset_getaffinity	i:iiiip		__syscall_cpuset_getaffinity
 sys_cpuset_setaffinity	-	cpuset_setaffinity	i:iiiip		__syscall_cpuset_setaffinity
-
+sys_faccessat		-	faccessat		i:isii		__syscall_faccessat
+sys_fchmodat		-	fchmodat		i:isii		__syscall_fchmodat
+sys_fchownat		-	fchownat		i:isiii		__syscall_fchownat
+sys_fexecve		-	fexecve			i:ipp		__syscall_fexecve
+sys_fstatat		-	fstatat			i:ispi		__syscall_fstatat
+sys_futimesat		-	futimesat		i:isp		__syscall_futimesat
+sys_linkat		-	linkat			i:isisi		__syscall_linkat
+sys_mkdirat		-	mkdirat			i:isi		__syscall_mkdirat
+sys_mkfifoat		-	mkfifoat		i:isi		__syscall_mkfifoat
+sys_mknodat		-	mknodat			i:isii		__syscall_mknodat
+sys_openat		-	openat			i:isii		__syscall_openat
+sys_readlinkat		-	readlinkat		i:issi		__syscall_readlinkat
+sys_renameat		-	renameat		i:isis		__syscall_renameat
+sys_symlinkat		-	symlinkat		i:sis		__syscall_symlinkat
+sys_unlinkat		-	unlinkat		i:isi		__syscall_unlinkat

Added: trunk/glibc-ports/kfreebsd/unlinkat.c
===================================================================
--- trunk/glibc-ports/kfreebsd/unlinkat.c	                        (rev 0)
+++ trunk/glibc-ports/kfreebsd/unlinkat.c	2009-06-01 23:18:37 UTC (rev 2559)
@@ -0,0 +1,125 @@
+/* Copyright (C) 2009 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <unistd.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <kernel-features.h>
+
+extern int __syscall_unlinkat (int fd, const char *file, int flag);
+libc_hidden_proto (__syscall_unlinkat)
+
+/* Remove the link named NAME.  */
+int
+unlinkat (fd, file, flag)
+     int fd;
+     const char *file;
+     int flag;
+{
+# ifndef __ASSUME_ATFCTS
+  if (__have_atfcts >= 0)
+# endif
+    {
+      int result = INLINE_SYSCALL (unlinkat, 3, fd, file, flag);
+# ifndef __ASSUME_ATFCTS
+      if (result == -1 && errno == ENOSYS)
+	__have_atfcts = -1;
+      else
+# endif
+	return result;
+    }
+
+#ifndef __ASSUME_ATFCTS
+  if (flag & ~AT_REMOVEDIR)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+  if (fd != AT_FDCWD && file[0] != '/')
+    {
+      int mib[4];
+      size_t kf_len = 0;
+      char *kf_buf, *kf_bufp;
+
+      if (fd < 0)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+
+      mib[0] = CTL_KERN;
+      mib[1] = KERN_PROC;
+      mib[2] = KERN_PROC_FILEDESC;
+      mib[3] = __getpid ();
+
+      if (sysctl (mib, 4, NULL, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_buf = alloca (kf_len + strlen (file));
+      if (sysctl (mib, 4, kf_buf, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_bufp = kf_buf;
+      while (kf_bufp < kf_buf + kf_len)
+	{
+	  struct kinfo_file *kf = (struct kinfo_file *) (uintptr_t) kf_bufp;
+
+	  if (kf->kf_fd == fd)
+	    {
+	      if (kf->kf_type != KF_TYPE_VNODE ||
+		  kf->kf_vnode_type != KF_VTYPE_VDIR)
+		{
+		  __set_errno (ENOTDIR);
+		  return -1;
+		}
+
+	      strcat (kf->kf_path, "/");
+	      strcat (kf->kf_path, file);
+	      file = kf->kf_path;
+	      break;
+	    }
+	  kf_bufp += kf->kf_structsize;
+	}
+
+      if (kf_bufp >= kf_buf + kf_len)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+    }
+  if (flag & AT_REMOVEDIR)
+    return __rmdir (file);
+  else
+    return __unlink (file);
+#endif
+}

Added: trunk/glibc-ports/kfreebsd/xmknodat.c
===================================================================
--- trunk/glibc-ports/kfreebsd/xmknodat.c	                        (rev 0)
+++ trunk/glibc-ports/kfreebsd/xmknodat.c	2009-06-01 23:18:37 UTC (rev 2559)
@@ -0,0 +1,137 @@
+/* Copyright (C) 2009 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 <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sysdep.h>
+#include <sys/stat.h>
+#include <sys/sysctl.h>
+#include <sys/user.h>
+#include <kernel-features.h>
+
+extern int __syscall_mknodat (int fd, const char *path,
+			      mode_t mode, dev_t dev);
+libc_hidden_proto (__syscall_mknodat)
+
+extern int __syscall_mkfifoat (int fd, const char *path,
+			       mode_t mode);
+libc_hidden_proto (__syscall_mkfifoat)
+
+/* Create a device file named PATH relative to FD, with permission and
+   special bits MODE and device number DEV (which can be constructed
+   from major and minor device numbers with the `makedev' macro above).  */
+int
+__xmknodat (int vers, int fd, const char *file, mode_t mode, dev_t * dev)
+{
+  if (vers != _MKNOD_VER)
+    {
+      __set_errno (EINVAL);
+      return -1;
+    }
+
+# ifndef __ASSUME_ATFCTS
+  if (__have_atfcts >= 0)
+# endif
+    {
+      int result;
+
+      /* The FreeBSD mknod() system call cannot be used to create FIFOs; we
+         must use the mkfifo() system call for this purpose.  */
+      if (S_ISFIFO (mode))
+	result = INLINE_SYSCALL (mkfifoat, 4, fd, file, mode);
+      else
+	result = INLINE_SYSCALL (mknodat, 4, fd, file, mode, *dev);
+
+# ifndef __ASSUME_ATFCTS
+      if (result == -1 && errno == ENOSYS)
+	__have_atfcts = -1;
+      else
+# endif
+	return result;
+    }
+
+#ifndef __ASSUME_ATFCTS
+  if (fd != AT_FDCWD && file[0] != '/')
+    {
+      int mib[4];
+      size_t kf_len = 0;
+      char *kf_buf, *kf_bufp;
+
+      if (fd < 0)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+
+      mib[0] = CTL_KERN;
+      mib[1] = KERN_PROC;
+      mib[2] = KERN_PROC_FILEDESC;
+      mib[3] = __getpid ();
+
+      if (sysctl (mib, 4, NULL, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_buf = alloca (kf_len + strlen (file));
+      if (sysctl (mib, 4, kf_buf, &kf_len, NULL, 0) != 0)
+	{
+	  __set_errno (ENOSYS);
+	  return -1;
+	}
+
+      kf_bufp = kf_buf;
+      while (kf_bufp < kf_buf + kf_len)
+	{
+	  struct kinfo_file *kf = (struct kinfo_file *) (uintptr_t) kf_bufp;
+
+	  if (kf->kf_fd == fd)
+	    {
+	      if (kf->kf_type != KF_TYPE_VNODE ||
+		  kf->kf_vnode_type != KF_VTYPE_VDIR)
+		{
+		  __set_errno (ENOTDIR);
+		  return -1;
+		}
+
+	      strcat (kf->kf_path, "/");
+	      strcat (kf->kf_path, file);
+	      file = kf->kf_path;
+	      break;
+	    }
+	  kf_bufp += kf->kf_structsize;
+	}
+
+      if (kf_bufp >= kf_buf + kf_len)
+	{
+	  __set_errno (EBADF);
+	  return -1;
+	}
+    }
+
+  return __xmknod (vers, file, mode, dev);
+#endif
+}
+
+libc_hidden_def (__xmknodat)




More information about the Glibc-bsd-commits mailing list