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