This patch provides fakeroot-1.5.10 support for *at() in glibc >= 2.4 in
combination with newer versions of GNU coreutils (6.x). This fixes problems
like chown 'operation not permitted' errors.

Error description and discussion:
  - http://www.ip-phone-forum.de/showthread.php?t=133283
  - http://www.diy-linux.org/pipermail/diy-linux-dev/2006-October/000891.html

Debian bug report and patch (link #3 is for wget usage, as #2 causes problems):
  - http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=402688
  - http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=402688;msg=10;filename=froot_1_5_10-atfuncs.patch;att=1
  - http://users.zenwalk.org/user-accounts/tilderb/extra/fakeroot/froot_1_5_10-atfuncs.patch

Note: The patch was modified (leading directory names removed) so it can be
applied by 'patch -p0'

diff -N -r -U5 -p config.h.in config.h.in
--- config.h.in	2006-07-23 00:34:15.000000000 +0200
+++ config.h.in	2006-12-12 16:00:14.000000000 +0100
@@ -17,16 +17,25 @@
 #undef HAVE_DLFCN_H
 
 /* Define to 1 if you have the <endian.h> header file. */
 #undef HAVE_ENDIAN_H
 
+/* Define to 1 if you have the `fchmodat' function. */
+#undef HAVE_FCHMODAT
+
+/* Define to 1 if you have the `fchownat' function. */
+#undef HAVE_FCHOWNAT
+
 /* Define to 1 if you have the <fcntl.h> header file. */
 #undef HAVE_FCNTL_H
 
 /* Define to 1 if you have the <features.h> header file. */
 #undef HAVE_FEATURES_H
 
+/* Define to 1 if you have the `fstatat' function. */
+#undef HAVE_FSTATAT
+
 /* Define to 1 if you have the `getresgid' function. */
 #undef HAVE_GETRESGID
 
 /* Define to 1 if you have the `getresuid' function. */
 #undef HAVE_GETRESUID
@@ -47,16 +56,28 @@
 #undef HAVE_LIBSOCKET
 
 /* Define to 1 if you have the <memory.h> header file. */
 #undef HAVE_MEMORY_H
 
+/* Define to 1 if you have the `mkdirat' function. */
+#undef HAVE_MKDIRAT
+
+/* Define to 1 if you have the `mknodat' function. */
+#undef HAVE_MKNODAT
+
 /* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */
 #undef HAVE_NDIR_H
 
+/* Define to 1 if you have the `openat' function. */
+#undef HAVE_OPENAT
+
 /* Define to 1 if you have the <pthread.h> header file. */
 #undef HAVE_PTHREAD_H
 
+/* Define to 1 if you have the `renameat' function. */
+#undef HAVE_RENAMEAT
+
 /* have the semun union */
 #undef HAVE_SEMUN_DEF
 
 /* Define to 1 if you have the `setfsgid' function. */
 #undef HAVE_SETFSGID
@@ -112,10 +133,13 @@
 #undef HAVE_SYS_TYPES_H
 
 /* Define to 1 if you have the <unistd.h> header file. */
 #undef HAVE_UNISTD_H
 
+/* Define to 1 if you have the `unlinkat' function. */
+#undef HAVE_UNLINKAT
+
 /* second argument of initgroups */
 #undef INITGROUPS_SECOND_ARG
 
 /* path to libc shared object */
 #undef LIBCPATH
@@ -183,10 +207,15 @@
 #define WRAP_FSTAT_QUOTE  __astat 
 #define WRAP_FSTAT  __astat 
 #define TMP_FSTAT  __astat 
 #define NEXT_FSTAT_NOARG  next___astat 
 
+#define WRAP_FSTATAT_QUOTE  __astatat 
+#define WRAP_FSTATAT  __astatat 
+#define TMP_FSTATAT  __astatat 
+#define NEXT_FSTATAT_NOARG  next___astatat 
+
 #define WRAP_STAT64_QUOTE  __astat64 
 #define WRAP_STAT64  __astat64 
 #define TMP_STAT64  __astat64 
 #define NEXT_STAT64_NOARG  next___astat64 
 
@@ -198,15 +227,28 @@
 #define WRAP_FSTAT64_QUOTE  __astat64
 #define WRAP_FSTAT64  __astat64
 #define TMP_FSTAT64  __astat64
 #define NEXT_FSTAT64_NOARG  next___astat64 
 
+#define WRAP_FSTATAT64_QUOTE  __astatat64
+#define WRAP_FSTATAT64  __astatat64
+#define TMP_FSTATAT64  __astatat64
+#define NEXT_FSTATAT64_NOARG  next___astatat64 
+
 #define WRAP_MKNOD_QUOTE  __amknod 
 #define WRAP_MKNOD  __amknod 
 #define TMP_MKNOD  __amknod 
 #define NEXT_MKNOD_NOARG  next___amknod 
 
+#define WRAP_MKNODAT_QUOTE  __amknodat 
+#define WRAP_MKNODAT  __amknodat 
+#define TMP_MKNODAT  __amknodat 
+#define NEXT_MKNODAT_NOARG  next___amknodat 
+
+
+/* fifth argument of __xmknodat */
+#undef XMKNODAT_FIFTH_ARG
 
 /* fourth argument of __xmknod */
 #undef XMKNOD_FRTH_ARG
 
 /* Define to empty if `const' does not conform to ANSI C. */
diff -N -r -U5 -p configure configure
--- configure	2006-07-23 00:33:58.000000000 +0200
+++ configure	2006-12-12 16:00:14.000000000 +0100
@@ -12056,10 +12056,98 @@ fi
 
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
 
 
+{ echo "$as_me:$LINENO: checking for type of arg of __xmknodat" >&5
+echo $ECHO_N "checking for type of arg of __xmknodat... $ECHO_C" >&6; }
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+
+       #include <sys/types.h>
+       #include <sys/stat.h>
+       #include <fcntl.h>
+       #include <unistd.h>
+
+int
+main ()
+{
+
+       int __xmknodat  ( int ver,
+                         inf dirfd,
+                         const char *pathname ,
+                         mode_t  mode ,  dev_t dev);
+
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext
+if { (ac_try="$ac_compile"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_compile") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest.$ac_objext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+
+   cat >>confdefs.h <<\_ACEOF
+#define XMKNODAT_FIFTH_ARG
+_ACEOF
+
+   { echo "$as_me:$LINENO: result: no extra *" >&5
+echo "${ECHO_T}no extra *" >&6; }
+
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+   cat >>confdefs.h <<\_ACEOF
+#define XMKNODAT_FIFTH_ARG *
+_ACEOF
+
+   { echo "$as_me:$LINENO: result: needs *" >&5
+echo "${ECHO_T}needs *" >&6; }
+
+
+fi
+
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+
+
 { echo "$as_me:$LINENO: checking for type of arg of initgroups" >&5
 echo $ECHO_N "checking for type of arg of initgroups... $ECHO_C" >&6; }
   cat >conftest.$ac_ext <<_ACEOF
 /* confdefs.h.  */
 _ACEOF
@@ -12531,13 +12619,131 @@ fi
 
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 done
 
 
+
+
+
+
+
+
+
+for ac_func in fchmodat fchownat fstatat mkdirat mknodat openat renameat unlinkat
+do
+as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh`
+{ echo "$as_me:$LINENO: checking for $ac_func" >&5
+echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; }
+if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then
+  echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+  cat >conftest.$ac_ext <<_ACEOF
+/* confdefs.h.  */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h.  */
+/* Define $ac_func to an innocuous variant, in case <limits.h> declares $ac_func.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $ac_func innocuous_$ac_func
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $ac_func (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $ac_func
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $ac_func ();
+/* The GNU C library defines this for functions which it implements
+    to always fail with ENOSYS.  Some functions are actually named
+    something starting with __ and the normal name is an alias.  */
+#if defined __stub_$ac_func || defined __stub___$ac_func
+choke me
+#endif
+
+int
+main ()
+{
+return $ac_func ();
+  ;
+  return 0;
+}
+_ACEOF
+rm -f conftest.$ac_objext conftest$ac_exeext
+if { (ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_link") 2>conftest.er1
+  ac_status=$?
+  grep -v '^ *+' conftest.er1 >conftest.err
+  rm -f conftest.er1
+  cat conftest.err >&5
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); } &&
+	 { ac_try='test -z "$ac_c_werror_flag" || test ! -s conftest.err'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; } &&
+	 { ac_try='test -s conftest$ac_exeext'
+  { (case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  echo "$as_me:$LINENO: \$? = $ac_status" >&5
+  (exit $ac_status); }; }; then
+  eval "$as_ac_var=yes"
+else
+  echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+	eval "$as_ac_var=no"
+fi
+
+rm -f core conftest.err conftest.$ac_objext \
+      conftest$ac_exeext conftest.$ac_ext
+fi
+ac_res=`eval echo '${'$as_ac_var'}'`
+	       { echo "$as_me:$LINENO: result: $ac_res" >&5
+echo "${ECHO_T}$ac_res" >&6; }
+if test `eval echo '${'$as_ac_var'}'` = yes; then
+  cat >>confdefs.h <<_ACEOF
+#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
 :>fakerootconfig.h.tmp
 
-for SEARCH in %stat f%stat l%stat %stat64 f%stat64 l%stat64 %mknod; do
+for SEARCH in %stat f%stat l%stat f%statat %stat64 f%stat64 l%stat64 f%statat64 %mknod %mknodat; do
   FUNC=`echo $SEARCH|sed -e 's/.*%//'`
   PRE=`echo $SEARCH|sed -e 's/%.*//'`
   FOUND=
   for WRAPPED in __${PRE}x${FUNC} _${PRE}x${FUNC} __${PRE}${FUNC}13 ${PRE}${FUNC}; do
 
@@ -12676,10 +12882,16 @@ _ACEOF
       else
         DEF_BEGIN="a,"
       fi
       if test "${FUNC}" = "mknod"; then
         DEF_END=",d"
+      elif test "${FUNC}" = "mknodat"; then
+        DEF_END=",d,e"
+      elif test "${FUNC}" = "statat"; then
+        DEF_END=",d,e"
+      elif test "${FUNC}" = "statat64"; then
+        DEF_END=",d,e"
       else
         DEF_END=""
       fi
 
                         {
diff -N -r -U5 -p configure.ac configure.ac
--- configure.ac	2006-01-30 04:44:42.000000000 +0100
+++ configure.ac	2006-12-12 16:00:14.000000000 +0100
@@ -142,10 +142,37 @@ AC_MSG_CHECKING([for type of arg of __xm
    AC_DEFINE(XMKNOD_FRTH_ARG,[*])
    AC_MSG_RESULT([needs *])  
   
   ])
 
+dnl Possibly this should only be done if we actually have mknodat
+dnl on the system.  Nothing  breaks by running the test itself though.
+AH_TEMPLATE([XMKNODAT_FIFTH_ARG], [fifth argument of __xmknodat])
+dnl glibc uses `* dev' as fifth argument of __xmknodat.
+dnl Although the test below should probably be more general
+dnl (not just __xmknodat, but also mknod etc), at the moment this
+dnl seems enough, as probably glibc is the only that does this.
+AC_MSG_CHECKING([for type of arg of __xmknodat])
+  AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+       #include <sys/types.h>
+       #include <sys/stat.h>
+       #include <fcntl.h>
+       #include <unistd.h>
+  ]], [[  
+       int __xmknodat  ( int ver, 
+                         inf dirfd,
+                         const char *pathname ,  
+                         mode_t  mode ,  dev_t dev);
+  ]])],[
+   AC_DEFINE(XMKNODAT_FIFTH_ARG,)
+   AC_MSG_RESULT([no extra *])
+  ],[ 
+   AC_DEFINE(XMKNODAT_FIFTH_ARG,[*])
+   AC_MSG_RESULT([needs *])  
+  
+  ])
+
 AH_TEMPLATE([INITGROUPS_SECOND_ARG], [second argument of initgroups])
 dnl FreeBSD 4.7 uses int instead of gid_t
 AC_MSG_CHECKING([for type of arg of initgroups])
   AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
        #include <sys/types.h>
@@ -232,20 +259,22 @@ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
    AC_MSG_RESULT([yes])  
   ],[ AC_MSG_RESULT([no])
   ])
 done
 
+AC_CHECK_FUNCS(fchmodat fchownat fstatat mkdirat mknodat openat renameat unlinkat)
+
 dnl find out how stat() etc are called. On linux systems, we really
 dnl need to wrap (IIRC):
 dnl  Linux       : __xstat
 dnl  Solaris <=9 : _stat
 dnl  Solaris 10  : _xstat
 dnl  Digital Unix: stat
 
 :>fakerootconfig.h.tmp
 
-for SEARCH in %stat f%stat l%stat %stat64 f%stat64 l%stat64 %mknod; do
+for SEARCH in %stat f%stat l%stat f%statat %stat64 f%stat64 l%stat64 f%statat64 %mknod %mknodat; do
   FUNC=`echo $SEARCH|sed -e 's/.*%//'`
   PRE=`echo $SEARCH|sed -e 's/%.*//'`
   FOUND=
   for WRAPPED in __${PRE}x${FUNC} _${PRE}x${FUNC} __${PRE}${FUNC}13 ${PRE}${FUNC}; do
     AC_CHECK_FUNCS($WRAPPED,FOUND=$WRAPPED)
@@ -269,10 +298,16 @@ dnl    FOUND=$WRAPPED
       else
         DEF_BEGIN="a,"
       fi
       if test "${FUNC}" = "mknod"; then
         DEF_END=",d"
+      elif test "${FUNC}" = "mknodat"; then
+        DEF_END=",d,e"
+      elif test "${FUNC}" = "statat"; then
+        DEF_END=",d,e"
+      elif test "${FUNC}" = "statat64"; then
+        DEF_END=",d,e"
       else
         DEF_END=""
       fi
       dnl no matter what I do, the resulting define looks like
       dnl #define macro (a,b,c) (a,b,c)
@@ -370,10 +405,15 @@ AH_VERBATIM([WRAP_STAT],
 #define WRAP_FSTAT_QUOTE  __astat 
 #define WRAP_FSTAT  __astat 
 #define TMP_FSTAT  __astat 
 #define NEXT_FSTAT_NOARG  next___astat 
 
+#define WRAP_FSTATAT_QUOTE  __astatat 
+#define WRAP_FSTATAT  __astatat 
+#define TMP_FSTATAT  __astatat 
+#define NEXT_FSTATAT_NOARG  next___astatat 
+
 #define WRAP_STAT64_QUOTE  __astat64 
 #define WRAP_STAT64  __astat64 
 #define TMP_STAT64  __astat64 
 #define NEXT_STAT64_NOARG  next___astat64 
 
@@ -385,14 +425,24 @@ AH_VERBATIM([WRAP_STAT],
 #define WRAP_FSTAT64_QUOTE  __astat64
 #define WRAP_FSTAT64  __astat64
 #define TMP_FSTAT64  __astat64
 #define NEXT_FSTAT64_NOARG  next___astat64 
 
+#define WRAP_FSTATAT64_QUOTE  __astatat64
+#define WRAP_FSTATAT64  __astatat64
+#define TMP_FSTATAT64  __astatat64
+#define NEXT_FSTATAT64_NOARG  next___astatat64 
+
 #define WRAP_MKNOD_QUOTE  __amknod 
 #define WRAP_MKNOD  __amknod 
 #define TMP_MKNOD  __amknod 
 #define NEXT_MKNOD_NOARG  next___amknod 
+
+#define WRAP_MKNODAT_QUOTE  __amknodat 
+#define WRAP_MKNODAT  __amknodat 
+#define TMP_MKNODAT  __amknodat 
+#define NEXT_MKNODAT_NOARG  next___amknodat 
 ])
 dnl kludge end
 
 dnl check for b0rked Solaris (and other shells) and find one that works
 AC_MSG_CHECKING(for a working shell...)
diff -N -r -U5 -p fake/acinclude.m4 fake/acinclude.m4
--- fake/acinclude.m4	2006-07-23 00:32:46.000000000 +0200
+++ fake/acinclude.m4	1970-01-01 01:00:00.000000000 +0100
@@ -1 +0,0 @@
-define(FAKEROOT_VERSION, 1.5.10)
diff -N -r -U5 -p libfakeroot.c libfakeroot.c
--- libfakeroot.c	2005-10-02 17:35:36.000000000 +0200
+++ libfakeroot.c	2006-12-12 16:00:14.000000000 +0100
@@ -523,10 +523,31 @@ int WRAP_FSTAT FSTAT_ARG(int ver, 
   send_get_stat(st,ver);
 #endif
   return 0;
 }
 
+#ifdef HAVE_FSTATAT
+int WRAP_FSTATAT FSTATAT_ARG(int ver,
+			     int dir_fd,
+			     const char *path,
+			     struct stat *st,
+			     int flags){
+
+
+  int r;
+
+  r=NEXT_FSTATAT(ver, dir_fd, path, st, flags);
+  if(r)
+    return -1;
+#ifndef STUPID_ALPHA_HACK
+  send_get_stat(st);
+#else
+  send_get_stat(st,ver);
+#endif
+  return 0;
+}
+#endif /* HAVE_FSTATAT */
 
 #ifdef STAT64_SUPPORT
 
 int WRAP_LSTAT64 LSTAT64_ARG (int ver, 
 			   const char *file_name, 
@@ -580,11 +601,33 @@ int WRAP_FSTAT64 FSTAT64_ARG(int ver, 
 #endif
 
   return 0;
 }
 
+#ifdef HAVE_FSTATAT
+int WRAP_FSTATAT64 FSTATAT64_ARG(int ver,
+				 int dir_fd,
+				 const char *path,
+				 struct stat64 *st,
+				 int flags){
+
+
+  int r;
+
+  r=NEXT_FSTATAT64(ver, dir_fd, path, st, flags);
+  if(r)
+    return -1;
+#ifndef STUPID_ALPHA_HACK
+  send_get_stat64(st);
+#else
+  send_get_stat64(st,ver);
 #endif
+  return 0;
+}
+#endif /* HAVE_FSTATAT */
+
+#endif /* STAT64_SUPPORT */
 
 
 
 
 /*************************************************************/
@@ -699,10 +742,59 @@ int fchown(int fd, uid_t owner, gid_t gr
     r=0;
   
   return r;
 }
 
+
+
+#ifdef HAVE_FSTATAT
+#ifdef HAVE_FCHOWNAT
+int fchownat(int dir_fd, const char *path, uid_t owner, gid_t group, int flags) {
+  int r;
+  /* If AT_SYMLINK_NOFOLLOW is set in the fchownat call it should
+     be when we stat it. */
+#ifdef STAT64_SUPPORT
+  struct stat64 st;
+  r=NEXT_FSTATAT64(_STAT_VER, dir_fd, path, &st, (flags & AT_SYMLINK_NOFOLLOW));
+#else
+  struct stat st;
+  r=NEXT_FSTATAT(_STAT_VER, dir_fd, path, &st, (flags & AT_SYMLINK_NOFOLLOW));
+#endif
+  
+  if(r)
+    return(r);
+  
+  st.st_uid=owner;
+  st.st_gid=group;
+#ifdef STAT64_SUPPORT
+#ifndef STUPID_ALPHA_HACK
+  send_stat64(&st,chown_func);  
+#else
+  send_stat64(&st,chown_func, _STAT_VER);  
+#endif
+#else
+#ifndef STUPID_ALPHA_HACK
+  send_stat(&st,chown_func);  
+#else
+  send_stat(&st,chown_func, _STAT_VER);  
+#endif
+#endif /* STAT64_SUPPORT */
+  
+  if(!dont_try_chown())
+    r=next_fchownat(dir_fd,path,owner,group,flags);
+  else
+    r=0;
+  
+  if(r&&(errno==EPERM))
+    r=0;
+  
+  return r;
+}
+#endif /* HAVE_FCHOWNAT */
+#endif /* HAVE_FSTATAT */
+
+
 int chmod(const char *path, mode_t mode){
   struct stat st;
   int r;
 
   r=NEXT_STAT(_STAT_VER, path, &st);
@@ -761,10 +853,44 @@ int fchmod(int fd, mode_t mode){
   if(r&&(errno==EPERM))
     r=0;
   return r;
 }
 
+#ifdef HAVE_FSTATAT
+#ifdef HAVE_FCHMODAT
+int fchmodat(int dir_fd, const char *path, mode_t mode, int flags) {
+/*   (int fd, mode_t mode){*/
+  int r;
+  struct stat st;
+
+  /* If AT_SYMLINK_NOFOLLOW is set in the fchownat call it should
+     be when we stat it. */
+  r=NEXT_FSTATAT(_STAT_VER, dir_fd, path, &st, flags & AT_SYMLINK_NOFOLLOW);
+  
+  if(r)
+    return(r);
+  
+  st.st_mode=(mode&ALLPERMS)|(st.st_mode&~ALLPERMS);
+#ifndef STUPID_ALPHA_HACK
+  send_stat(&st,chmod_func);  
+#else
+  send_stat(&st,chmod_func, _STAT_VER);  
+#endif
+  
+  /* see chmod() for comment */
+  mode |= 0600;
+  if(S_ISDIR(st.st_mode))
+    mode |= 0100;
+  
+  r=next_fchmodat(dir_fd, path, mode, flags);
+  if(r&&(errno==EPERM))
+    r=0;
+  return r;
+}
+#endif /* HAVE_FCHMODAT */
+#endif /* HAVE_FSTATAT */
+
 int WRAP_MKNOD MKNOD_ARG(int ver UNUSED,
 			 const char *pathname, 
 			 mode_t mode, dev_t XMKNOD_FRTH_ARG dev)
 {
   struct stat st;
@@ -800,10 +926,58 @@ int WRAP_MKNOD MKNOD_ARG(int ver UNUSED,
 #endif
     
   return 0;
 }
 
+
+#ifdef HAVE_FSTATAT
+#ifdef HAVE_MKNODAT
+int WRAP_MKNODAT MKNODAT_ARG(int ver UNUSED,
+			     int dir_fd,
+			     const char *pathname, 
+			     mode_t mode, dev_t XMKNODAT_FIFTH_ARG dev)
+{
+  struct stat st;
+  mode_t old_mask=umask(022);
+  int fd,r;
+
+  umask(old_mask);
+  
+  /*Don't bother to mknod the file, that probably doesn't work.
+    just create it as normal file, and leave the permissions
+    to the fakemode.*/
+
+  fd=openat(dir_fd, pathname, O_WRONLY|O_CREAT|O_TRUNC, 00644);
+
+  if(fd==-1)
+    return -1;
+  
+  close(fd);
+  /* get the inode, to communicate with faked */
+
+  /* The only known flag is AT_SYMLINK_NOFOLLOW and
+     we don't want that here. */
+  r=NEXT_FSTATAT(_STAT_VER, dir_fd, pathname, &st, 0);
+
+  if(r)
+    return -1;
+  
+  st.st_mode= mode & ~old_mask;
+  st.st_rdev= XMKNODAT_FIFTH_ARG dev;
+  
+#ifndef STUPID_ALPHA_HACK
+  send_stat(&st,mknod_func);
+#else
+  send_stat(&st,mknod_func, _STAT_VER);
+#endif
+    
+  return 0;
+}
+#endif /* HAVE_MKNODAT */
+#endif /* HAVE_FSTATAT */
+
+
 int mkdir(const char *path, mode_t mode){
   struct stat st;
   int r;
   mode_t old_mask=umask(022);
 
@@ -832,10 +1006,46 @@ int mkdir(const char *path, mode_t mode)
 #endif
 
   return 0;
 }
 
+#ifdef HAVE_FSTATAT
+#ifdef HAVE_MKDIRAT
+int mkdirat(int dir_fd, const char *path, mode_t mode){
+  struct stat st;
+  int r;
+  mode_t old_mask=umask(022);
+
+  umask(old_mask);
+
+
+  /* we need to tell the fake deamon the real mode. In order
+     to communicate with faked we need a struct stat, so we now
+     do a stat of the new directory (just for the inode/dev) */
+
+  r=next_mkdirat(dir_fd, path, mode|0700); 
+  /* mode|0700: see comment in the chown() function above */
+  if(r)
+    return -1;
+  r=NEXT_FSTATAT(_STAT_VER, dir_fd, path, &st, 0);
+
+  if(r)
+    return -1;
+  
+  st.st_mode=(mode&~old_mask&ALLPERMS)|(st.st_mode&~ALLPERMS)|S_IFDIR;
+
+#ifndef STUPID_ALPHA_HACK
+  send_stat(&st, chmod_func);
+#else
+  send_stat(&st, chmod_func, _STAT_VER);
+#endif
+
+  return 0;
+}
+#endif /* HAVE_MKDIRAT */
+#endif /* HAVE_FSTATAT */
+
 /* 
    The remove funtions: unlink, rmdir, rename.
    These functions can all remove inodes from the system.
    I need to inform faked about the removal of these inodes because
    of the following:
@@ -877,10 +1087,44 @@ int unlink(const char *pathname){
 #endif
   
   return 0;
 }
 
+#ifdef HAVE_FSTATAT
+#ifdef HAVE_UNLINKAT
+int unlinkat(int dir_fd, const char *pathname, int flags){
+  int r;
+#ifdef STAT64_SUPPORT
+  struct stat64 st;
+  r=NEXT_FSTATAT64(_STAT_VER, dir_fd, pathname, &st, (flags&~AT_REMOVEDIR) | AT_SYMLINK_NOFOLLOW);
+#else
+  struct stat st;
+  r=NEXT_FSTATAT(_STAT_VER, dir_fd, pathname, &st, (flags&~AT_REMOVEDIR) | AT_SYMLINK_NOFOLLOW);
+#endif
+  if(r)
+    return -1;
+
+  r=next_unlinkat(dir_fd, pathname, flags);
+
+  if(r)
+    return -1;
+  
+#ifdef STAT64_SUPPORT
+#ifndef STUPID_ALPHA_HACK
+  send_stat64(&st, unlink_func);
+#else
+  send_stat64(&st, unlink_func, _STAT_VER);
+#endif
+#else
+  send_stat(&st, unlink_func);
+#endif
+  
+  return 0;
+}
+#endif /* HAVE_UNLINKAT */
+#endif /* HAVE_FSTATAT */
+
 /*
   See the `remove funtions:' comments above for more info on
   these remove function wrappers.
 */
 int rmdir(const char *pathname){
@@ -958,10 +1202,41 @@ int rename(const char *oldpath, const ch
 #endif
 
   return 0;
 }
 
+#ifdef HAVE_FSTATAT
+#ifdef HAVE_RENAMEAT
+int renameat(int olddir_fd, const char *oldpath,
+             int newdir_fd, const char *newpath){
+  int r,s;
+  struct stat st;     
+
+  /* If newpath points to an existing file, that file will be 
+     unlinked.   Make sure we tell the faked daemon about this! */
+
+  /* we need the st_new struct in order to inform faked about the
+     (possible) unlink of the file */
+
+  r=NEXT_FSTATAT(_STAT_VER, newdir_fd, newpath, &st, AT_SYMLINK_NOFOLLOW);
+
+  s=next_renameat(olddir_fd, oldpath, newdir_fd, newpath);
+  if(s)
+    return -1;
+  if(!r)
+#ifndef STUPID_ALPHA_HACK
+    send_stat(&st,unlink_func);
+#else
+    send_stat(&st,unlink_func, _STAT_VER);
+#endif
+
+  return 0;
+}
+#endif /* HAVE_RENAMEAT */
+#endif /* HAVE_FSTATAT */
+
+
 #ifdef FAKEROOT_FAKENET
 pid_t fork(void)
 {
   pid_t pid;
 
diff -N -r -U5 -p wrapfunc.inp wrapfunc.inp
--- wrapfunc.inp	2005-11-02 15:59:32.000000000 +0100
+++ wrapfunc.inp	2006-12-12 16:00:14.000000000 +0100
@@ -20,19 +20,31 @@ freopen;FILE *;(const char *pathname, co
 /**/
 
 WRAP_LSTAT;int;LSTAT_ARG(int ver, const char *file_name, struct stat *buf);LSTAT_ARG(ver, file_name, buf);LSTAT
 WRAP_STAT;int;STAT_ARG(int ver, const char *file_name, struct stat *buf);STAT_ARG(ver, file_name, buf);STAT
 WRAP_FSTAT;int;FSTAT_ARG(int ver, int fd, struct stat *buf);FSTAT_ARG(ver, fd, buf);FSTAT
+#ifdef HAVE_FSTATAT
+WRAP_FSTATAT;int;FSTATAT_ARG(int ver, int dir_fd, const char *path, struct stat *buf, int flags);FSTATAT_ARG(ver, dir_fd, path, buf, flags);FSTATAT
+#endif /* HAVE_FSTATAT */
 
 #ifdef STAT64_SUPPORT
 WRAP_LSTAT64;int;LSTAT64_ARG(int ver, const char *file_name, struct stat64 *buf);LSTAT64_ARG(ver, file_name, buf);LSTAT64
 WRAP_STAT64;int;STAT64_ARG(int ver, const char *file_name, struct stat64 *buf);STAT64_ARG(ver, file_name, buf);STAT64
 WRAP_FSTAT64;int;FSTAT64_ARG(int ver, int fd, struct stat64 *buf);FSTAT64_ARG(ver, fd, buf);FSTAT64
-#endif
+#ifdef HAVE_FSTATAT
+WRAP_FSTATAT64;int;FSTATAT64_ARG(int ver, int dir_fd, const char *path, struct stat64 *buf, int flags);FSTATAT64_ARG(ver, dir_fd, path, buf, flags);FSTATAT64
+#endif /* HAVE_FSTATAT */
+#endif /* STAT64_SUPPORT */
 
 WRAP_MKNOD;int;MKNOD_ARG(int ver, const char *pathname, mode_t mode, dev_t XMKNOD_FRTH_ARG dev);MKNOD_ARG(ver, pathname, mode, dev);MKNOD
 
+#ifdef HAVE_FSTATAT
+#ifdef HAVE_MKNODAT
+WRAP_MKNODAT;int;MKNODAT_ARG(int ver, int dir_fd, const char *pathname, mode_t mode, dev_t dev);MKNODAT_ARG(ver, dir_fd, pathname, mode, dev);MKNODAT
+#endif /* HAVE_MKNODAT */
+#endif /* HAVE_FSTATAT */
+
 /*opendir;DIR *;(const char *name);(name)*/
 /*closedir;int;(DIR *dir);(dir)*/
 /*readdir;struct dirent *;(DIR *dir);(dir)*/
 /*readlink;int;(const char *path, READLINK_BUF_TYPE *buf, READLINK_BUFSIZE_TYPE bufsize);(path, buf, bufsize)*/
 /*telldir;off_t;(DIR *dir);(dir)*/
@@ -87,5 +99,28 @@ setfsuid;uid_t;(uid_t fsuid);(fsuid)
 #ifdef HAVE_SETFSGID
 setfsgid;gid_t;(gid_t fsgid);(fsgid)
 #endif /* HAVE_SETFSGID */
 initgroups;int;(const char *user, INITGROUPS_SECOND_ARG group);(user, group)
 setgroups;int;(SETGROUPS_SIZE_TYPE size, const gid_t *list);(size, list)
+
+#ifdef HAVE_FSTATAT
+#ifdef HAVE_FCHMODAT
+fchmodat;int;(int dir_fd, const char *path, mode_t mode, int flags);(dir_fd, path, mode, flags)
+#endif /* HAVE_FCHMODAT */
+#ifdef HAVE_FCHOWNAT
+fchownat;int;(int dir_fd, const char *path, uid_t owner, gid_t group, int flags);(dir_fd, path, owner, group, flags)
+#endif /* HAVE_FCHOWNAT */
+#ifdef HAVE_MKDIRAT
+mkdirat;int;(int dir_fd, const char *pathname, mode_t mode);(dir_fd, pathname, mode)
+#endif /* HAVE_MKDIRAT */
+#ifdef HAVE_OPENAT
+openat;int;(int dir_fd, const char *pathname, int flags);(dir_fd, pathname, flags)
+#endif /* HAVE_OPENAT */
+#ifdef HAVE_RENAMEAT
+renameat;int;(int olddir_fd, const char *oldpath, int newdir_fd, const char *newpath);(olddir_fd, oldpath, newdir_fd, newpath)
+#endif /* HAVE_RENAMEAT */
+#ifdef HAVE_UNLINKAT
+unlinkat;int;(int dir_fd, const char *pathname, int flags);(dir_fd, pathname, flags)
+#endif /* HAVE_UNLINKAT */
+#endif /* HAVE_FSTATAT */
+
+
