Hi!

----

Attached (as "astksh_fsat_emu_tacked_on001.diff.txt") is a _prototype_
patch which tacks the |*at()|-API emulation on ast-ksh...

Notes:
- This is a prototype
- The patch has a switch which selects either the platforms native
|*at()| API or the emulation
- The code has only been "tacked" on and is not properly integrated
(e.g. see lots of warnings about redefined cpp symbols)
- The patch passes the ksh93 test suite with and without |USE_NATIVE_AT_API| set
- The |*at()|-emulation is not complete yet... missing functions are
|readlinkat()|, |sumlinkat()| and |utimensat()| ... I'll add them when
Glenn gives the OK for the general idea (see "goal" below)
- Final goal would be that src/cmd/ksh93 and src/lib/libcmd only use
the |*at()| API... either the native OS version or the emulation if
the underlying OS does not have the |*at()| APIs

----

Bye,
Roland

-- 
  __ .  . __
 (o.\ \/ /.o) roland.ma...@nrubsig.org
  \__\/\/__/  MPEG specialist, C&&JAVA&&Sun&&Unix programmer
  /O /==\ O\  TEL +49 641 3992797
 (;O/ \/ \O;)
diff -N -r -u original/src/cmd/ksh93/include/ast_map_fsat.h 
build_at_emu/src/cmd/ksh93/include/ast_map_fsat.h
--- original/src/cmd/ksh93/include/ast_map_fsat.h       1970-01-01 
01:00:00.000000000 +0100
+++ build_at_emu/src/cmd/ksh93/include/ast_map_fsat.h   2012-08-25 
11:18:34.227957194 +0200
@@ -0,0 +1,92 @@
+#ifndef AST_MAP_FSAT_H
+#define AST_MAP_FSAT_H 1
+/***********************************************************************
+*                                                                      *
+*               This software is part of the ast package               *
+*             Copyright (c) 2012 AT&T Intellectual Property            *
+*                      and is licensed under the                       *
+*                 Eclipse Public License, Version 1.0                  *
+*                    by AT&T Intellectual Property                     *
+*                                                                      *
+*                A copy of the License is available at                 *
+*          http://www.eclipse.org/org/documents/epl-v10.html           *
+*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
+*                                                                      *
+*              Information and Software Systems Research               *
+*                            AT&T Research                             *
+*                           Florham Park NJ                            *
+*                                                                      *
+*               Roland Mainz <roland.ma...@nrubsig.org>                *
+*                                                                      *
+***********************************************************************/
+
+/*
+ * This header defines provide an easy way for legacy applications
+ * to use the new POSIX |*at()|-APIs.
+ *
+ * This is mainly intended for operating systems which already map
+ * the old calls to the new |*at()| calls, therefore the macros
+ * below bypass a lot of wrapper code in libc.
+ * The other usage is _testing_ the code in libc and the |*at())
+ * emulation code in libast
+ */
+
+/*
+ * How should we map these with CPP ? ;-(
+ *
+ * open(path, flag, ...)       openat(sh_getinterp()->pwdfd, (path), (flag), 
...)
+ * creat(path, ...)            openat(sh_getinterp()->pwdfd, (path), 
O_WRONLY|O_CREAT|O_TRUNC, ...)
+ */
+
+#ifndef USE_NATIVE_AT_API
+
+#define        unlink(path)                    
ast_unlinkat(sh_getinterp()->pwdfd, (path), 0)
+#define        rmdir(path)                     
ast_unlinkat(sh_getinterp()->pwdfd, (path), AT_REMOVEDIR)
+#define        chown(path, uid, gid)           
ast_fchownat(sh_getinterp()->pwdfd, (path), (uid), (gid), 0)
+#define        lchown(path, uid, gid)          
ast_fchownat(sh_getinterp()->pwdfd, (path), (uid), (gid), AT_SYMLINK_NOFOLLOW)
+#define        fchown(fd, uid, gid)            ast_fchownat((fd), NULL, (uid), 
(gid), 0)
+#define        stat(path, sb)                  
ast_fstatat(sh_getinterp()->pwdfd, (path), (sb), 0)
+#define        lstat(path, sb)                 
ast_fstatat(sh_getinterp()->pwdfd, (path), (sb), AT_SYMLINK_NOFOLLOW)
+#define        fstat(fd, sb)                   ast_fstatat((fd), NULL, (sb), 0)
+#define        rename(oldname, newname)        
ast_renameat(sh_getinterp()->pwdfd, (oldname), sh_getinterp()->pwdfd, (newname))
+#define        access(path, amode)             
ast_faccessat(sh_getinterp()->pwdfd, (path), (amode), 0)
+#define        eaccess(path, amode)            
ast_faccessat(sh_getinterp()->pwdfd, (path), (amode), AT_EACCESS)
+#define        mkdir(path, amode)              
ast_mkdirat(sh_getinterp()->pwdfd, (path), (amode))
+#define        mkfifo(path, amode)             
ast_mkfifoat(sh_getinterp()->pwdfd, (path), (amode))
+#define        mknod(path, amode, adev)        
ast_mknodat(sh_getinterp()->pwdfd, (path), (amode), (adev))
+#if 0
+#define readlink(path, buf, bufsize)   ast_readlinkat(sh_getinterp()->pwdfd, 
(path), (buf), (bufsize))
+#define symlink(oldpath, newpath)      ast_symlinkat((oldpath), 
sh_getinterp()->pwdfd, (newpath))
+#endif
+
+#else
+
+#define        unlink(path)                    unlinkat(sh_getinterp()->pwdfd, 
(path), 0)
+#define        rmdir(path)                     unlinkat(sh_getinterp()->pwdfd, 
(path), AT_REMOVEDIR)
+#define        chown(path, uid, gid)           fchownat(sh_getinterp()->pwdfd, 
(path), (uid), (gid), 0)
+#define        lchown(path, uid, gid)          fchownat(sh_getinterp()->pwdfd, 
(path), (uid), (gid), AT_SYMLINK_NOFOLLOW)
+#define        fchown(fd, uid, gid)            fchownat((fd), NULL, (uid), 
(gid), 0)
+#define        stat(path, sb)                  fstatat(sh_getinterp()->pwdfd, 
(path), (sb), 0)
+#define        lstat(path, sb)                 fstatat(sh_getinterp()->pwdfd, 
(path), (sb), AT_SYMLINK_NOFOLLOW)
+#ifndef __linux__
+/*
+ * Linux does not allow |path| in |fstatat()| to be |NULL|. To be
+ * honestly it doesn't make much sense anyway since fstat() already
+ * takes a |fd| as input
+ */
+#define        fstat(fd, sb)                   fstatat((fd), NULL, (sb), 0)
+#endif
+#define        rename(oldname, newname)        renameat(sh_getinterp()->pwdfd, 
(oldname), sh_getinterp()->pwdfd, (newname))
+#define        access(path, amode)             
faccessat(sh_getinterp()->pwdfd, (path), (amode), 0)
+#define        eaccess(path, amode)            
faccessat(sh_getinterp()->pwdfd, (path), (amode), AT_EACCESS)
+#define        mkdir(path, amode)              mkdirat(sh_getinterp()->pwdfd, 
(path), (amode))
+#define        mkfifo(path, amode)             mkfifoat(sh_getinterp()->pwdfd, 
(path), (amode))
+#define        mknod(path, amode, adev)        mknodat(sh_getinterp()->pwdfd, 
(path), (amode), (adev))
+#if 0
+#define readlink(path, buf, bufsize)   readlinkat(sh_getinterp()->pwdfd, 
(path), (buf), (bufsize))
+#define symlink(oldpath, newpath)      symlinkat((oldpath), 
sh_getinterp()->pwdfd, (newpath))
+#endif
+
+#endif
+
+#endif /* !AST_MAP_FSAT_H */
diff -N -r -u original/src/cmd/ksh93/include/defs.h 
build_at_emu/src/cmd/ksh93/include/defs.h
--- original/src/cmd/ksh93/include/defs.h       2012-08-20 16:03:07.000000000 
+0200
+++ build_at_emu/src/cmd/ksh93/include/defs.h   2012-08-25 10:08:40.710243078 
+0200
@@ -31,6 +31,9 @@
 #include       <ast.h>
 #include       <sfio.h>
 #include       <error.h>
+
+#include "ast_map_fsat.h"
+
 #include       "FEATURE/externs"
 #include       "FEATURE/options"
 #include       <cdt.h>
diff -N -r -u original/src/cmd/ksh93/Makefile 
build_at_emu/src/cmd/ksh93/Makefile
--- original/src/cmd/ksh93/Makefile     2012-08-24 22:14:39.000000000 +0200
+++ build_at_emu/src/cmd/ksh93/Makefile 2012-08-25 09:49:09.881548478 +0200
@@ -159,6 +159,7 @@
        arith.c args.c array.c completion.c defs.c edit.c expand.c regress.c \
        fault.c fcin.c history.c init.c io.c jobs.c lex.c macro.c name.c \
        nvtree.c parse.c path.c string.c streval.c subshell.c tdump.c timers.c \
+       openat_emu.c \
        trestore.c waitevent.c xec.c env.c hexpand.c $(DATAFILES) $(FILES_opt) \
        $(SHOPT_COSHELL:+-lcoshell) -lcmd -last -lm
 
diff -N -r -u original/src/cmd/ksh93/Mamfile build_at_emu/src/cmd/ksh93/Mamfile
--- original/src/cmd/ksh93/Mamfile      2012-08-24 23:37:01.000000000 +0200
+++ build_at_emu/src/cmd/ksh93/Mamfile  2012-08-25 10:12:47.490423160 +0200
@@ -1101,6 +1101,7 @@
 prev sh/tdump.c
 exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -Iinclude -I${PACKAGE_ast_INCLUDE} 
-D_BLD_shell -DKSHELL -D_API_ast=20120806 -D_PACKAGE_ast -DSHOPT_SUID_EXEC 
-DSHOPT_BRACEPAT -DSHOPT_STATS -DSHOPT_NAMESPACE -DSHOPT_COSHELL -DSHOPT_PFSH 
-DERROR_CONTEXT_T=Error_context_t -DSHOPT_FIXEDARRAY -DSHOPT_MULTIBYTE -c 
sh/tdump.c
 done tdump.o generated
+
 make timers.o
 make sh/timers.c
 prev FEATURE/time implicit
@@ -1115,6 +1116,22 @@
 prev sh/timers.c
 exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -Iinclude -I${PACKAGE_ast_INCLUDE} 
-D_API_ast=20120806 -D_PACKAGE_ast -DSHOPT_STATS -DSHOPT_NAMESPACE 
-DSHOPT_COSHELL -DSHOPT_PFSH -D_BLD_shell -DERROR_CONTEXT_T=Error_context_t 
-DSHOPT_FIXEDARRAY -DSHOPT_MULTIBYTE -c sh/timers.c
 done timers.o generated
+
+make openat_emu.o
+make sh/openat_emu.c
+prev FEATURE/time implicit
+prev FEATURE/sigfeatures implicit
+prev include/defs.h implicit
+prev include/fault.h implicit
+prev ${PACKAGE_ast_INCLUDE}/error.h implicit
+prev ${PACKAGE_ast_INCLUDE}/sig.h implicit
+prev ${PACKAGE_ast_INCLUDE}/ast.h implicit
+done sh/openat_emu.c
+meta openat_emu.o %.c>%.o sh/openat_emu.c timers
+prev sh/openat_emu.c
+exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -Iinclude -I${PACKAGE_ast_INCLUDE} 
-D_API_ast=20120806 -D_PACKAGE_ast -DSHOPT_STATS -DSHOPT_NAMESPACE 
-DSHOPT_COSHELL -DSHOPT_PFSH -D_BLD_shell -DERROR_CONTEXT_T=Error_context_t 
-DSHOPT_FIXEDARRAY -DSHOPT_MULTIBYTE -c sh/openat_emu.c
+done openat_emu.o generated
+
 make trestore.o
 make sh/trestore.c
 prev ${PACKAGE_ast_INCLUDE}/ccode.h implicit
@@ -1362,7 +1379,7 @@
 exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -Iinclude -I${PACKAGE_ast_INCLUDE} 
-D_API_ast=20120806 -D_PACKAGE_ast -DSHOPT_POLL -D_BLD_shell -DSHOPT_DYNAMIC 
-DSHOPT_MULTIBYTE -DSHOPT_PFSH -DSHOPT_FIXEDARRAY -DKSHELL -DSHOPT_STATS 
-DSHOPT_NAMESPACE -DSHOPT_COSHELL -DERROR_CONTEXT_T=Error_context_t -c 
bltins/poll.c
 done poll.o generated
 exec - ${AR} rc libshell.a alarm.o cd_pwd.o cflow.o deparse.o enum.o getopts.o 
hist.o misc.o print.o read.o sleep.o trap.o test.o typeset.o ulimit.o umask.o 
whence.o main.o nvdisc.o nvtype.o arith.o args.o array.o completion.o defs.o 
edit.o expand.o regress.o fault.o fcin.o
-exec - ${AR} rc libshell.a history.o init.o io.o jobs.o lex.o macro.o name.o 
nvtree.o parse.o path.o string.o streval.o subshell.o tdump.o timers.o 
trestore.o waitevent.o xec.o env.o hexpand.o limits.o msg.o strdata.o testops.o 
keywords.o options.o signals.o aliases.o builtins.o variables.o lexstates.o 
emacs.o vi.o poll.o
+exec - ${AR} rc libshell.a history.o init.o io.o jobs.o lex.o macro.o name.o 
nvtree.o parse.o path.o string.o streval.o subshell.o tdump.o openat_emu.o 
timers.o trestore.o waitevent.o xec.o env.o hexpand.o limits.o msg.o strdata.o 
testops.o keywords.o options.o signals.o aliases.o builtins.o variables.o 
lexstates.o emacs.o vi.o poll.o
 exec - (ranlib libshell.a) >/dev/null 2>&1 || true
 done libshell.a generated
 bind -lshell
diff -N -r -u original/src/cmd/ksh93/sh/openat_emu.c 
build_at_emu/src/cmd/ksh93/sh/openat_emu.c
--- original/src/cmd/ksh93/sh/openat_emu.c      1970-01-01 01:00:00.000000000 
+0100
+++ build_at_emu/src/cmd/ksh93/sh/openat_emu.c  2012-08-25 10:19:42.237215721 
+0200
@@ -0,0 +1,1121 @@
+/***********************************************************************
+*                                                                      *
+*               This software is part of the ast package               *
+*             Copyright (c) 2012 AT&T Intellectual Property            *
+*                      and is licensed under the                       *
+*                 Eclipse Public License, Version 1.0                  *
+*                    by AT&T Intellectual Property                     *
+*                                                                      *
+*                A copy of the License is available at                 *
+*          http://www.eclipse.org/org/documents/epl-v10.html           *
+*         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
+*                                                                      *
+*              Information and Software Systems Research               *
+*                            AT&T Research                             *
+*                           Florham Park NJ                            *
+*                                                                      *
+*               Roland Mainz <roland.ma...@nrubsig.org>                *
+*                                                                      *
+***********************************************************************/
+
+/* We need this for |eaccess()| */
+#define _GNU_SOURCE 1
+
+#include <stdbool.h>
+#include <string.h>
+#include <limits.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <assert.h>
+
+#ifdef AST_FSAT_TEST_RECURIVELY
+#include "ast_map_fsat.h"
+#endif
+
+/*
+ * Mappings |*()| call vs. |*at()| call:
+ *
+ * open(path, flag, ...)       openat(AT_FDCWD, path, flag, ...)
+ * creat(path, ...)            openat(AT_FDCWD, path, 
O_WRONLY|O_CREAT|O_TRUNC, ...)
+ * unlink(path)                        unlinkat(AT_FDCWD, path, 0)
+ * rmdir(path)                 unlinkat(AT_FDCWD, path, AT_REMOVEDIR)
+ * chown(path, uid, gid)       fchownat(AT_FDCWD, path, uid, gid, 0)
+ * lchown(path, uid, gid)      fchownat(AT_FDCWD, path, uid, gid, 
AT_SYMLINK_NOFOLLOW)
+ * fchown(fd, uid, gid)                fchownat(fd, NULL, uid, gid, 0)
+ * stat(path, &sb)             fstatat(AT_FDCWD, path, &sb, 0)
+ * lstat(path, &sb)            fstatat(AT_FDCWD, path, &sb, 
AT_SYMLINK_NOFOLLOW)
+ * fstat(fd, &sb)              fstatat(fd, NULL, &sb, 0)
+ * rename(oldname, newname)    renameat(AT_FDCWD, oldname, AT_FDCWD, newname)
+ * access(path, amode)         faccessat(AT_FDCWD, path, amode, 0)
+ * eaccess(path, amode)                faccessat(AT_FDCWD, path, amode, 
AT_EACCESS)
+ * mkdir(path, amode)          mkdirat(AT_FDCWD, path, amode)
+ * mkfifo(path, amode)         mkfifoat(AT_FDCWD, path, amode)
+ * mknod(path, amode, adev)    mknodat(AT_FDCWD, path, amode, adev)
+ * readlink(path, buf, bufsize)        readlinkat(AT_FDCWD, path, buf, bufsize)
+ * symlink(oldpath, newpath)   symlinkat(oldpath, AT_FDCWD, newpath)
+ *
+ * Warning: If we cache the cwd fd globally we must observe |close()|
+ * and |dup2()| usage carefully!
+ */
+
+/*
+ * Note that /dev/fd/ on Solaris can NOT be used reliably to do
+ * something like /dev/fd/$fd/src/hello/world profile
+ *
+ * Use of /dev/fd/$fd/src/hello/world on Linux seems to be 100%
+ * safe, assuming /dev/fd/ is mounted - it may be missing from
+ * chroot'ed environments.
+ */
+#define ASTOPENATEMU_USE_DEVFD 1
+
+/* note: |AT_CWD| must always be a negative number < -256 */
+#define AST_AT_FDCWD           (AT_FDCWD)
+
+/* |open()|-flags */
+#define AST_O_DIRECTORY                (O_DIRECTORY)
+#define AST_O_SEARCH           (O_SEARCH)
+
+/* extra |*at()| flags */
+#define AST_AT_REMOVEDIR       (AT_REMOVEDIR)
+#define AST_AT_SYMLINK_NOFOLLOW        (AT_SYMLINK_NOFOLLOW)
+#define AST_AT_EACCESS         (AT_EACCESS)
+
+
+#define ASTOPENEMU_GLOBALDIR_LOCK
+#define ASTOPENEMU_GLOBALDIR_UNLOCK
+
+struct global_cwd
+{
+       const char      *name;
+       int             fd;
+
+       /* storage for |global_cwd.name|. We made this extra large */
+       char            namebuff[(2*PATH_MAX)+128];
+
+#ifdef ASTOPENATEMU_USE_DEVFD
+       bool            has_devfd;      /* Remember whether we have /dev/fd/ */
+       const char      *devfd_fs;      /* either "/dev/fd" or "/proc/self/fd" 
*/
+#endif
+};
+
+static struct global_cwd global_cwd =
+{
+       NULL,
+       -1,
+       { '\0', },
+#ifdef ASTOPENATEMU_USE_DEVFD
+       true,
+       "/dev/fd"       /* either "/dev/fd" or "/proc/self/fd" */
+#endif
+};
+
+/*
+ * Warning: This accesses |global_cwd| WITHOUT locking (for
+ * performace and therefore without being reliable in threaded
+ * applications. Hurray! ;-/ ()
+ */
+#define ASSERT_GLOBAL_CWD_VALID        assert((global_cwd.fd >= 0) || 
(global_cwd.name != NULL))
+
+/* Repeat syscall in expr each time it gets hit with EINTR */
+#define EINTR_REPEAT(expr) while((expr) && (errno == EINTR)) errno=0;
+
+
+/* must be called inside 
|ASTOPENEMU_GLOBALDIR_LOCK|/ASTOPENEMU_GLOBALDIR_UNLOCK pair!! */
+static
+bool save_cwd_unlocked(void)
+{
+       if (global_cwd.fd<0)
+       {
+               EINTR_REPEAT((global_cwd.fd=open(".", O_RDONLY)) < 0);
+               if (global_cwd.fd < 0)
+               {
+                       global_cwd.name=getcwd(global_cwd.namebuff, 
sizeof(global_cwd.namebuff));
+               }
+       }
+       return (((global_cwd.fd>=0) || (global_cwd.name!=NULL))?true:false);
+}
+
+/* must be called inside 
|ASTOPENEMU_GLOBALDIR_LOCK|/ASTOPENEMU_GLOBALDIR_UNLOCK pair!! */
+static
+void restore_cwd_unlocked(void)
+{
+       ASSERT_GLOBAL_CWD_VALID;
+
+       if (global_cwd.fd >= 0)
+       {
+               EINTR_REPEAT(fchdir(global_cwd.fd) < 0);
+       }
+       else if (global_cwd.name)
+       {
+               EINTR_REPEAT(chdir(global_cwd.name) < 0);
+       }
+       else
+       {
+               /*
+                * this should never happen - |save_cwd_unlocked()|
+                * will only return |true| (and therefore fill
+                * either |global_cwd.fd| or |global_cwd.name|)
+                * if it can save the cwd location somehow.
+                */
+               assert(0);
+       }
+}
+
+/*
+ * intercept for |close()|
+ * we need this to make sure the cached |global_cwd| stays valid
+ */
+int ast_close(int fd)
+{
+       ASSERT_GLOBAL_CWD_VALID;
+
+       ASTOPENEMU_GLOBALDIR_LOCK
+       if (fd == global_cwd.fd)
+       {
+               global_cwd.fd=-1;
+       }
+       ASTOPENEMU_GLOBALDIR_UNLOCK
+       return (close(fd));
+}
+
+/*
+ * intercept for |fchdir()|
+ * we need this to make sure the cached |global_cwd| does not
+ * become "stale"
+ */
+int ast_fchdir(int fd)
+{
+       int retval;
+       int saved_errno;
+
+       ASSERT_GLOBAL_CWD_VALID;
+
+       ASTOPENEMU_GLOBALDIR_LOCK;
+
+       /*
+        * We do not check for |(dirfd != global_cwd.fd)| (to do
+        * optimisations) here since the caller might be interested
+        * in the return code (for example if the directory was
+        * removed (or the "x" permission was removed) after the
+        * |fd| was obtained).
+        */
+       retval=fchdir(fd);
+       saved_errno=errno;
+
+       if (retval >= 0)
+       {
+               global_cwd.fd=fd;
+               global_cwd.name=NULL;
+       }
+
+       ASTOPENEMU_GLOBALDIR_UNLOCK;
+
+       errno=saved_errno;
+       return (retval);
+}
+
+/*
+ * intercept for |chdir()|
+ * we need this to make sure the cached |global_cwd| does not
+ * become "stale"
+ */
+int ast_chdir(const char *path)
+{
+       int retval;
+       int saved_errno;
+       ASSERT_GLOBAL_CWD_VALID;
+
+       ASTOPENEMU_GLOBALDIR_LOCK;
+
+       retval=chdir(path);
+       saved_errno=errno;
+
+       if (retval >= 0)
+       {
+               global_cwd.fd=-1;
+               global_cwd.name=NULL;
+       }
+
+       ASTOPENEMU_GLOBALDIR_UNLOCK;
+
+       errno=saved_errno;
+       return (retval);
+}
+
+int ast_openat(int dirfd, const char *pathname, int flags, mode_t mode)
+{
+       /*
+        * use |open()| for pathname relative to the cwd or
+        * if it is an absolute path name
+        */
+       if ((dirfd == AST_AT_FDCWD) || (pathname[0] == '/'))
+       {
+               return open(pathname, flags, mode);
+       }
+
+#ifdef ASTOPENATEMU_USE_DEVFD
+       if (global_cwd.has_devfd)
+       {
+               char pathbuf[PATH_MAX+256];
+
+               if (flags & AST_O_DIRECTORY)
+               {
+                       sprintf(pathbuf, "%s/%d/%s/.", global_cwd.devfd_fs, 
dirfd, pathname);
+               }
+               else
+               {
+                       sprintf(pathbuf, "%s/%d/%s", global_cwd.devfd_fs, 
dirfd, pathname);
+               }
+               return open(pathbuf, flags, mode);
+       }
+       else
+#endif
+       {
+               int saved_errno;
+               int returned_dir;
+
+               ASTOPENEMU_GLOBALDIR_LOCK
+
+               if (!save_cwd_unlocked())
+               {
+                       saved_errno=errno;
+                       ASTOPENEMU_GLOBALDIR_UNLOCK
+                       errno=saved_errno;
+                       return (-1);
+               }
+
+               if (dirfd != global_cwd.fd)
+               {
+                       if (fchdir(dirfd) < 0)
+                       {
+                               saved_errno=errno;
+                               ASTOPENEMU_GLOBALDIR_UNLOCK
+                               errno=saved_errno;
+                               return (-1);
+                       }
+               }
+
+               returned_dir=open(pathname, flags, mode);
+               saved_errno=errno;
+
+               restore_cwd_unlocked();
+
+               ASTOPENEMU_GLOBALDIR_UNLOCK
+
+               errno=saved_errno;
+
+               return (returned_dir);
+       }
+}
+
+int ast_unlinkat(int dirfd, const char *pathname, int flags)
+{
+       if ((dirfd == AST_AT_FDCWD) || (pathname[0] == '/'))
+       {
+               if (flags & AST_AT_REMOVEDIR)
+               {
+                       flags&=~AST_AT_REMOVEDIR;
+                       /* abort if there are more flags we do not support */
+                       if (flags)
+                       {
+                               errno=ENOSYS;
+                               return (-1);
+                       }
+                       else
+                       {
+                               return rmdir(pathname);
+                       }
+               }
+               if (flags == 0)
+               {
+                       return unlink(pathname);
+               }
+               else
+               {
+                       /* this happes if there are flags we don't know about */
+                       errno=ENOSYS;
+                       return (-1);
+               }
+       }
+
+#ifdef ASTOPENATEMU_USE_DEVFD
+       if (global_cwd.has_devfd)
+       {
+               char pathbuf[PATH_MAX+256];
+
+               sprintf(pathbuf, "%s/%d/%s", global_cwd.devfd_fs, dirfd, 
pathname);
+
+               if (flags & AST_AT_REMOVEDIR)
+               {
+                       flags&=~AST_AT_REMOVEDIR;
+                       /* abort if there are more flags we do not support */
+                       if (flags)
+                       {
+                               errno=ENOSYS;
+                               return (-1);
+                       }
+                       else
+                       {
+                               return rmdir(pathbuf);
+                       }
+               }
+               if (flags == 0)
+               {
+                       return unlink(pathbuf);
+               }
+               else
+               {
+                       /* this happes if there are flags we don't know about */
+                       errno=ENOSYS;
+                       return (-1);
+               }
+       }
+       else
+#endif
+       {
+               int saved_errno;
+               int retval;
+
+               ASTOPENEMU_GLOBALDIR_LOCK
+
+               if (!save_cwd_unlocked())
+               {
+                       saved_errno=errno;
+                       ASTOPENEMU_GLOBALDIR_UNLOCK
+                       errno=saved_errno;
+                       return (-1);
+               }
+
+               if (dirfd != global_cwd.fd)
+               {
+                       if (fchdir(dirfd) < 0)
+                       {
+                               saved_errno=errno;
+                               ASTOPENEMU_GLOBALDIR_UNLOCK
+                               errno=saved_errno;
+                               return (-1);
+                       }
+               }
+
+               if (flags & AST_AT_REMOVEDIR)
+               {
+                       flags&=~AST_AT_REMOVEDIR;
+                       /* abort if there are more flags we do not support */
+                       if (flags)
+                       {
+                               saved_errno=ENOSYS;
+                               retval=-1;
+                       }
+                       else
+                       {
+                               retval=rmdir(pathname);
+                               saved_errno=errno;
+                       }
+               }
+               if (flags == 0)
+               {
+                       retval=unlink(pathname);
+                       saved_errno=errno;
+               }
+               else
+               {
+                       /* this happes if there are flags we don't know about */
+                       saved_errno=ENOSYS;
+                       retval=-1;
+               }
+
+               restore_cwd_unlocked();
+
+               ASTOPENEMU_GLOBALDIR_UNLOCK
+
+               errno=saved_errno;
+
+               return (retval);
+       }
+}
+
+int ast_fchownat(int dirfd, const char *pathname, uid_t owner, gid_t group, 
int flags)
+{
+       if ((dirfd == AST_AT_FDCWD) || (pathname[0] == '/'))
+       {
+               if (flags & AST_AT_SYMLINK_NOFOLLOW)
+               {
+                       flags&=~AST_AT_SYMLINK_NOFOLLOW;
+                       /* abort if there are more flags we do not support */
+                       if (flags)
+                       {
+                               errno=ENOSYS;
+                               return (-1);
+                       }
+                       else
+                       {
+                               return lchown(pathname, owner, group);
+                       }
+               }
+               else if (flags == 0)
+               {
+                       return chown(pathname, owner, group);
+               }
+               else
+               {
+                       /* unsupported flags */
+                       errno=ENOSYS;
+                       return (-1);
+               }
+       }
+
+       if (pathname == NULL)
+       {
+               /* abort if there are any flags */
+               if (flags)
+               {
+                       errno=ENOSYS;
+                       return (-1);
+               }
+               else
+               {
+                       return fchown(dirfd, owner, group);
+               }
+       }
+
+#ifdef ASTOPENATEMU_USE_DEVFD
+       if (global_cwd.has_devfd)
+       {
+               char pathbuf[PATH_MAX+256];
+
+               sprintf(pathbuf, "%s/%d/%s", global_cwd.devfd_fs, dirfd, 
pathname);
+               if (flags & AST_AT_SYMLINK_NOFOLLOW)
+               {
+                       flags&=~AST_AT_SYMLINK_NOFOLLOW;
+                       /* abort if there are more flags we do not support */
+                       if (flags)
+                       {
+                               errno=ENOSYS;
+                               return (-1);
+                       }
+                       else
+                       {
+                               return lchown(pathbuf, owner, group);
+                       }
+               }
+               else if (flags == 0)
+               {
+                       return chown(pathbuf, owner, group);
+               }
+               else
+               {
+                       /* unsupported flags */
+                       errno=ENOSYS;
+                       return (-1);
+               }
+       }
+       else
+#endif
+       {
+               int saved_errno;
+               int retval;
+
+               ASTOPENEMU_GLOBALDIR_LOCK
+
+               if (!save_cwd_unlocked())
+               {
+                       saved_errno=errno;
+                       ASTOPENEMU_GLOBALDIR_UNLOCK
+                       errno=saved_errno;
+                       return (-1);
+               }
+
+               if (dirfd != global_cwd.fd)
+               {
+                       if (fchdir(dirfd) < 0)
+                       {
+                               saved_errno=errno;
+                               ASTOPENEMU_GLOBALDIR_UNLOCK
+                               errno=saved_errno;
+                               return (-1);
+                       }
+               }
+
+               if (flags & AST_AT_SYMLINK_NOFOLLOW)
+               {
+                       flags&=~AST_AT_SYMLINK_NOFOLLOW;
+                       /* abort if there are more flags we do not support */
+                       if (flags)
+                       {
+                               saved_errno=ENOSYS;
+                               retval=-1;
+                       }
+                       else
+                       {
+                               retval=lchown(pathname, owner, group);
+                               saved_errno=errno;
+                       }
+               }
+               else if (flags == 0)
+               {
+                       retval=chown(pathname, owner, group);
+                       saved_errno=errno;
+               }
+               else
+               {
+                       /* unsupported flags */
+                       errno=ENOSYS;
+                       retval=-1;
+               }
+
+               restore_cwd_unlocked();
+
+               ASTOPENEMU_GLOBALDIR_UNLOCK
+
+               errno=saved_errno;
+
+               return (retval);
+       }
+}
+
+int ast_fstatat(int dirfd, const char *pathname, struct stat *buf, int flags)
+{
+       if ((dirfd == AST_AT_FDCWD) || ((pathname != NULL) && (pathname[0] == 
'/')))
+       {
+               if (flags & AST_AT_SYMLINK_NOFOLLOW)
+               {
+                       flags&=~AST_AT_SYMLINK_NOFOLLOW;
+                       /* abort if there are more flags we do not support */
+                       if (flags)
+                       {
+                               errno=ENOSYS;
+                               return (-1);
+                       }
+                       else
+                       {
+                               return lstat(pathname, buf);
+                       }
+               }
+               else if (flags == 0)
+               {
+                       return stat(pathname, buf);
+               }
+
+               /* unsupported flags */
+               errno=ENOSYS;
+               return (-1);
+       }
+
+       if (pathname == NULL)
+       {
+               /* abort if there are any flags */
+               if (flags)
+               {
+                       errno=ENOSYS;
+                       return (-1);
+               }
+               else
+               {
+                       return fstat(dirfd, buf);
+               }
+       }
+
+#ifdef ASTOPENATEMU_USE_DEVFD
+       if (global_cwd.has_devfd)
+       {
+               char pathbuf[PATH_MAX+256];
+
+               sprintf(pathbuf, "%s/%d/%s", global_cwd.devfd_fs, dirfd, 
pathname);
+               if (flags & AST_AT_SYMLINK_NOFOLLOW)
+               {
+                       flags&=~AST_AT_SYMLINK_NOFOLLOW;
+                       /* abort if there are more flags we do not support */
+                       if (flags)
+                       {
+                               errno=ENOSYS;
+                               return (-1);
+                       }
+                       else
+                       {
+                               return lstat(pathbuf, buf);
+                       }
+               }
+               else if (flags == 0)
+               {
+                       return stat(pathbuf, buf);
+               }
+               else
+               {
+                       /* unsupported flags */
+                       errno=ENOSYS;
+                       return (-1);
+               }
+       }
+       else
+#endif
+       {
+               int saved_errno;
+               int retval;
+
+               ASTOPENEMU_GLOBALDIR_LOCK
+
+               if (!save_cwd_unlocked())
+               {
+                       saved_errno=errno;
+                       ASTOPENEMU_GLOBALDIR_UNLOCK
+                       errno=saved_errno;
+                       return (-1);
+               }
+
+               if (dirfd != global_cwd.fd)
+               {
+                       if (fchdir(dirfd) < 0)
+                       {
+                               saved_errno=errno;
+                               ASTOPENEMU_GLOBALDIR_UNLOCK
+                               errno=saved_errno;
+                               return (-1);
+                       }
+               }
+
+               if (flags & AST_AT_SYMLINK_NOFOLLOW)
+               {
+                       flags&=~AST_AT_SYMLINK_NOFOLLOW;
+                       /* abort if there are more flags we do not support */
+                       if (flags)
+                       {
+                               saved_errno=ENOSYS;
+                               retval=-1;
+                       }
+                       else
+                       {
+                               retval=lstat(pathname, buf);
+                               saved_errno=errno;
+                       }
+               }
+               else if (flags == 0)
+               {
+                       retval=stat(pathname, buf);
+                       saved_errno=errno;
+               }
+               else
+               {
+                       /* unsupported flags */
+                       saved_errno=ENOSYS;
+                       retval=-1;
+               }
+
+               restore_cwd_unlocked();
+
+               ASTOPENEMU_GLOBALDIR_UNLOCK
+
+               errno=saved_errno;
+
+               return (retval);
+       }
+}
+
+int ast_renameat(int olddirfd, const char *oldpath, int newdirfd, const char 
*newpath)
+{
+       if (oldpath[0] == '/')
+               olddirfd=AST_AT_FDCWD;
+       if (newpath[0] == '/')
+               newdirfd=AST_AT_FDCWD;
+
+       if ((olddirfd == AST_AT_FDCWD) && (newdirfd == AST_AT_FDCWD))
+       {
+               return rename(oldpath, newpath);
+       }
+
+#ifdef ASTOPENATEMU_USE_DEVFD
+       if (global_cwd.has_devfd)
+       {
+               char oldpathbuf[PATH_MAX+256];
+               char newpathbuf[PATH_MAX+256];
+
+               if (olddirfd != AST_AT_FDCWD)
+               {
+                       sprintf(oldpathbuf, "%s/%d/%s", global_cwd.devfd_fs, 
olddirfd, oldpath);
+                       oldpath=oldpathbuf;
+               }
+               if (newdirfd != AST_AT_FDCWD)
+               {
+                       sprintf(newpathbuf, "%s/%d/%s", global_cwd.devfd_fs, 
newdirfd, newpath);
+                       newpath=newpathbuf;
+               }
+
+               return rename(oldpath, newpath);
+       }
+       else
+#endif /* ASTOPENATEMU_USE_DEVFD */
+       {
+               int saved_errno;
+               int retval;
+               char oldcwdpathbuf[PATH_MAX+256];
+               char oldpathbuf[PATH_MAX+256];
+               char newcwdpathbuf[PATH_MAX+256];
+               char newpathbuf[PATH_MAX+256];
+               char *oldcwdpath;
+               char *newcwdpath;
+
+               ASTOPENEMU_GLOBALDIR_LOCK
+
+               if (!save_cwd_unlocked())
+               {
+                       retval=-1;
+                       goto done;
+               }
+
+               if (olddirfd == AST_AT_FDCWD)
+               {
+                       /*
+                        * Make sure cwd==original cwd
+                        *
+                        * (since we just saved the cwd we can skip the
+                        * |restore_cwd_unlocked();| here).
+                        */
+               }
+               else
+               {
+                       if (fchdir(olddirfd) < 0)
+                       {
+                               retval=-1;
+                               goto done;
+                       }
+               }
+               oldcwdpath=getcwd(oldcwdpathbuf, sizeof(oldcwdpathbuf));
+               if (!oldcwdpath)
+               {
+                       retval=-1;
+                       goto done;
+               }
+
+               if (newdirfd == AST_AT_FDCWD)
+               {
+                       /* make sure cwd==original cwd */
+                       restore_cwd_unlocked();
+               }
+               else
+               {
+                       if (fchdir(newdirfd) < 0)
+                       {
+                               retval=-1;
+                               goto done;
+                       }
+               }
+               newcwdpath=getcwd(newcwdpathbuf, sizeof(newcwdpathbuf));
+               if (!newcwdpath)
+               {
+                       retval=-1;
+                       goto done;
+               }
+
+               sprintf(oldpathbuf, "%s/%s", oldcwdpath, oldpath);
+               sprintf(newpathbuf, "%s/%s", newcwdpath, newpath);
+               retval=rename(oldpathbuf, newpathbuf);
+
+done:
+               saved_errno=errno;
+               restore_cwd_unlocked();
+               ASTOPENEMU_GLOBALDIR_UNLOCK
+               errno=saved_errno;
+               return (retval);
+       }
+}
+
+
+/*
+ * fixme: POSIX |faccessat()| supports |AT_SYMLINK_NOFOLLOW| ... how can this 
be emulated ?
+ */
+int ast_faccessat(int dirfd, const char *pathname, int mode, int flags)
+{
+       if ((dirfd == AST_AT_FDCWD) || (pathname[0] == '/'))
+       {
+               if (flags & AST_AT_EACCESS)
+               {
+                       flags&=~AST_AT_EACCESS;
+                       /* abort if there are more flags we do not support */
+                       if (flags)
+                       {
+                               errno=ENOSYS;
+                               return (-1);
+                       }
+                       else
+                       {
+                               return eaccess(pathname, mode);
+                       }
+               }
+               if (flags == 0)
+               {
+                       return access(pathname, mode);
+               }
+               else
+               {
+                       /* this happes if there are flags we don't know about */
+                       errno=ENOSYS;
+                       return (-1);
+               }
+       }
+
+#ifdef ASTOPENATEMU_USE_DEVFD
+       if (global_cwd.has_devfd)
+       {
+               char pathbuf[PATH_MAX+256];
+
+               sprintf(pathbuf, "%s/%d/%s", global_cwd.devfd_fs, dirfd, 
pathname);
+
+               if (flags & AST_AT_EACCESS)
+               {
+                       flags&=~AST_AT_EACCESS;
+                       /* abort if there are more flags we do not support */
+                       if (flags)
+                       {
+                               errno=ENOSYS;
+                               return (-1);
+                       }
+                       else
+                       {
+                               return eaccess(pathbuf, mode);
+                       }
+               }
+               if (flags == 0)
+               {
+                       return access(pathbuf, mode);
+               }
+               else
+               {
+                       /* this happes if there are flags we don't know about */
+                       errno=ENOSYS;
+                       return (-1);
+               }
+       }
+       else
+#endif
+       {
+               int saved_errno;
+               int retval;
+
+               ASTOPENEMU_GLOBALDIR_LOCK
+
+               if (!save_cwd_unlocked())
+               {
+                       saved_errno=errno;
+                       ASTOPENEMU_GLOBALDIR_UNLOCK
+                       errno=saved_errno;
+                       return (-1);
+               }
+
+               if (dirfd != global_cwd.fd)
+               {
+                       if (fchdir(dirfd) < 0)
+                       {
+                               saved_errno=errno;
+                               ASTOPENEMU_GLOBALDIR_UNLOCK
+                               errno=saved_errno;
+                               return (-1);
+                       }
+               }
+
+               if (flags & AST_AT_EACCESS)
+               {
+                       flags&=~AST_AT_EACCESS;
+                       /* abort if there are more flags we do not support */
+                       if (flags)
+                       {
+                               saved_errno=ENOSYS;
+                               retval=-1;
+                       }
+                       else
+                       {
+                               retval=eaccess(pathname, mode);
+                               saved_errno=errno;
+                       }
+               }
+               if (flags == 0)
+               {
+                       retval=access(pathname, mode);
+                       saved_errno=errno;
+               }
+               else
+               {
+                       /* this happes if there are flags we don't know about */
+                       saved_errno=ENOSYS;
+                       retval=-1;
+               }
+
+               restore_cwd_unlocked();
+
+               ASTOPENEMU_GLOBALDIR_UNLOCK
+
+               errno=saved_errno;
+
+               return (retval);
+       }
+}
+
+int ast_mkdirat(int dirfd, const char *pathname, mode_t mode)
+{
+       if ((dirfd == AST_AT_FDCWD) || (pathname[0] == '/'))
+       {
+               return mkdir(pathname, mode);
+       }
+
+#ifdef ASTOPENATEMU_USE_DEVFD
+       if (global_cwd.has_devfd)
+       {
+               char pathbuf[PATH_MAX+256];
+
+               sprintf(pathbuf, "%s/%d/%s", global_cwd.devfd_fs, dirfd, 
pathname);
+
+               return mkdir(pathbuf, mode);
+       }
+       else
+#endif
+       {
+               int saved_errno;
+               int retval;
+
+               ASTOPENEMU_GLOBALDIR_LOCK
+
+               if (!save_cwd_unlocked())
+               {
+                       saved_errno=errno;
+                       ASTOPENEMU_GLOBALDIR_UNLOCK
+                       errno=saved_errno;
+                       return (-1);
+               }
+
+               if (dirfd != global_cwd.fd)
+               {
+                       if (fchdir(dirfd) < 0)
+                       {
+                               saved_errno=errno;
+                               ASTOPENEMU_GLOBALDIR_UNLOCK
+                               errno=saved_errno;
+                               return (-1);
+                       }
+               }
+
+               retval=mkdir(pathname, mode);
+               saved_errno=errno;
+
+               restore_cwd_unlocked();
+
+               ASTOPENEMU_GLOBALDIR_UNLOCK
+
+               errno=saved_errno;
+
+               return (retval);
+       }
+}
+
+
+int ast_mkfifoat(int dirfd, const char *pathname, mode_t mode)
+{
+       if ((dirfd == AST_AT_FDCWD) || (pathname[0] == '/'))
+       {
+               return mkfifo(pathname, mode);
+       }
+
+#ifdef ASTOPENATEMU_USE_DEVFD
+       if (global_cwd.has_devfd)
+       {
+               char pathbuf[PATH_MAX+256];
+
+               sprintf(pathbuf, "%s/%d/%s", global_cwd.devfd_fs, dirfd, 
pathname);
+
+               return mkfifo(pathbuf, mode);
+       }
+       else
+#endif
+       {
+               int saved_errno;
+               int retval;
+
+               ASTOPENEMU_GLOBALDIR_LOCK
+
+               if (!save_cwd_unlocked())
+               {
+                       saved_errno=errno;
+                       ASTOPENEMU_GLOBALDIR_UNLOCK
+                       errno=saved_errno;
+                       return (-1);
+               }
+
+               if (dirfd != global_cwd.fd)
+               {
+                       if (fchdir(dirfd) < 0)
+                       {
+                               saved_errno=errno;
+                               ASTOPENEMU_GLOBALDIR_UNLOCK
+                               errno=saved_errno;
+                               return (-1);
+                       }
+               }
+
+               retval=mkfifo(pathname, mode);
+               saved_errno=errno;
+
+               restore_cwd_unlocked();
+
+               ASTOPENEMU_GLOBALDIR_UNLOCK
+
+               errno=saved_errno;
+
+               return (retval);
+       }
+}
+
+
+int ast_mkmodat(int dirfd, const char *pathname, mode_t mode, dev_t dev)
+{
+       if ((dirfd == AST_AT_FDCWD) || (pathname[0] == '/'))
+       {
+               return mknod(pathname, mode, dev);
+       }
+
+#ifdef ASTOPENATEMU_USE_DEVFD
+       if (global_cwd.has_devfd)
+       {
+               char pathbuf[PATH_MAX+256];
+
+               sprintf(pathbuf, "%s/%d/%s", global_cwd.devfd_fs, dirfd, 
pathname);
+
+               return mknod(pathbuf, mode, dev);
+       }
+       else
+#endif
+       {
+               int saved_errno;
+               int retval;
+
+               ASTOPENEMU_GLOBALDIR_LOCK
+
+               if (!save_cwd_unlocked())
+               {
+                       saved_errno=errno;
+                       ASTOPENEMU_GLOBALDIR_UNLOCK
+                       errno=saved_errno;
+                       return (-1);
+               }
+
+               if (dirfd != global_cwd.fd)
+               {
+                       if (fchdir(dirfd) < 0)
+                       {
+                               saved_errno=errno;
+                               ASTOPENEMU_GLOBALDIR_UNLOCK
+                               errno=saved_errno;
+                               return (-1);
+                       }
+               }
+
+               retval=mknod(pathname, mode, dev);
+               saved_errno=errno;
+
+               restore_cwd_unlocked();
+
+               ASTOPENEMU_GLOBALDIR_UNLOCK
+
+               errno=saved_errno;
+
+               return (retval);
+       }
+}
_______________________________________________
ast-developers mailing list
ast-developers@research.att.com
https://mailman.research.att.com/mailman/listinfo/ast-developers

Reply via email to