On Mon, Sep 17, 2012 at 3:17 PM, Lionel Cons
<lionelcons1...@googlemail.com> wrote:
> On 14 September 2012 06:01, Roland Mainz <roland.ma...@nrubsig.org> wrote:
>> Attached (as "astksh_chroot_cd_devfd_cd_f_20120911_001.diff.txt") is a
>> patch which fixes two issues with "cd":
>> 1. $ cd /dev/fd/$fd # doesn't work in chroot'ed environments when
>> /dev/fd is not mounted (thanks to CERN staff for reporting this).
>> 2. POSIX does not mandate _any_ paths. Since doing a "cd" relative to
>> a directory fd has become very popular the request was made to add an
>> alternative to using /dev/fd which is more or less acceptable for the
>> POSIX people. Based on that and a few discussions I added the option
>> -f to cd that a directory descriptor can be passed and the path given
>> is relative to that file descriptor.
>>
>> Notes:
>> - The code introduces a new function called |pathdevfd2relpathfd()| in
>> libast which can extract the fd number from a /dev/fd/$fd path (even
>> nested)
>> - If files or directories are opened relative to /dev/fd/$fd/$path
>> |sfopen()|/|sfopenat()| will now bypass the /dev/fd filesystem
>> completely (which gives a nice performance boost). The only exception
>> is that this can *NOT* be done for a plain /dev/fd/$fd, e.g.
>> /dev/fd/15. The problem is that there is AFAIK no way to open a file
>> from a file descriptor without using the /dev/fd filesystem or using
>> |dup()| ... but |dup()| rules itself out because the resulting
>> "cloned" fd still shares attributes like the current seek position
>> with the original fd...
>>
>> Glenn: Is it acceptable for |sfopen()| to |dup()| the incoming file fd
>> (see "Notes" above) ?
>
> Roland: Are you going to send your new patch to this list? The
> feedback of Josef's group has been very positive and rigid testing
> didn't show any problems.

Attached (as "astksh_chroot_cd_devfd_cd_f_20120916_002.diff.txt") is
the patch which adds $ cd -f $fd relpath # and the /dev/fd emulation
for chroot environments and older Solaris releases.

Changes:
- It's intentionally no longer possible to mix $ cd -f $fd ... # with
absolute paths. As we figured out this (together with the idea that
multiple /dev/fd/$fd could be stacked (they can... but it's not clear
whether the results would be relative or absolute paths (basically
it's disputed))) will quickly cause breakdown of semantics, logic and
the universe

Notes:
- $ cd -f $fd relpath # more or less creates a "virtual /" at the
directory where $fd points to. Doing a cd .. below that point is NOT
supported and may result in undefined behaviour. This is more or less
a limitation of the underlying technology and semantics... but as we
figured out it should not represent an issue for real-world script
programming

----

Bye,
Roland

-- 
  __ .  . __
 (o.\ \/ /.o) roland.ma...@nrubsig.org
  \__\/\/__/  MPEG specialist, C&&JAVA&&Sun&&Unix programmer
  /O /==\ O\  TEL +49 641 3992797
 (;O/ \/ \O;)
diff -r -u -N original/src/cmd/ksh93/bltins/cd_pwd.c 
build_fd/src/cmd/ksh93/bltins/cd_pwd.c
--- src/cmd/ksh93/bltins/cd_pwd.c       2012-08-09 15:24:15.000000000 +0200
+++ src/cmd/ksh93/bltins/cd_pwd.c       2012-09-17 15:03:29.909089734 +0200
@@ -19,8 +19,8 @@
 ***********************************************************************/
 #pragma prototyped
 /*
- * cd [-LP@]  [dirname]
- * cd [-LP@]  [old] [new]
+ * cd [-LP@f]  [dirname]
+ * cd [-LP@f]  [old] [new]
  * pwd [-LP]
  *
  *   David Korn
@@ -68,6 +68,12 @@
        NOT_USED(xattr);
 #endif
 
+#ifdef AT_FDCWD
+       path = pathdevfd2relpathfd(path, &dir);
+       if (!path)
+               path = e_dot;
+#endif
+
 #ifdef O_XATTR
        if(xattr)
        {
@@ -157,12 +163,23 @@
        int saverrno=0;
        int rval,flag=0,xattr=0;
        char *oldpwd;
+       int dirfd = shp->pwdfd;
        int newdirfd;
        Namval_t *opwdnod, *pwdnod;
        if(sh_isoption(shp,SH_RESTRICTED))
                errormsg(SH_DICT,ERROR_exit(1),e_restricted+4);
        while((rval = optget(argv,sh_optcd))) switch(rval)
        {
+#ifdef AT_FDCWD
+               case 'f':
+               case 'd':
+                       errno = 0;
+                       dirfd = strtol(opt_info.arg, (char **)NULL, 10);        
+                       if ((errno != 0) || (dirfd < 0))
+                               errormsg(SH_DICT, ERROR_exit(1),
+                                       "%s: invalid dir fd", opt_info.arg);
+                       break;
+#endif
                case 'L':
                        flag = 0;
                        break;
@@ -197,6 +214,10 @@
                dir = nv_getval(opwdnod);
        if(!dir || *dir==0)
                errormsg(SH_DICT,ERROR_exit(1),argc==2?e_subst+4:e_direct);
+       if ((shp->pwdfd != dirfd) && (*dir == '/'))
+               errormsg(SH_DICT,ERROR_exit(1),
+                       "Relative directory fd and abolute paths can not be 
used together.");
+
 #if _WINIX
        if(*dir != '/' && (dir[1]!=':'))
 #else
@@ -244,14 +265,18 @@
                        dir = sfstruse(shp->strbuf);
                }
        }
-#ifdef O_XATTR
-       if (xattr)
-#   ifdef PATH_BFPATH
+       if (
+#if defined(O_XATTR) || defined(AT_FDCWD)
+#      ifdef O_XATTR
+               xattr ||
+#      endif
+               (shp->pwdfd != dirfd))
+#      ifdef PATH_BFPATH
                cdpath = NULL;
-#   else
+#      else
                cdpath = "";
-#   endif
-#endif
+#      endif
+#endif /* defined(O_XATTR) || defined(AT_FDCWD) */
 
        rval = -1;
        do
@@ -294,7 +319,7 @@
 #endif /* SHOPT_FS_3D */
                }
                rval = newdirfd = sh_diropenat(shp,
-                       ((shp->pwdfd >= 0)?shp->pwdfd:AT_FDCWD),
+                       ((dirfd >= 0)?dirfd:AT_FDCWD),
                        path_relative(shp,stakptr(PATH_OFFSET)), xattr);
                if(newdirfd >=0)
                {
diff -r -u -N original/src/cmd/ksh93/data/builtins.c 
build_fd/src/cmd/ksh93/data/builtins.c
--- src/cmd/ksh93/data/builtins.c       2012-09-05 23:59:37.000000000 +0200
+++ src/cmd/ksh93/data/builtins.c       2012-09-17 16:43:54.242130278 +0200
@@ -442,7 +442,7 @@
 ;
 
 const char sh_optcd[] =
-"[-1c?\n@(#)$Id: cd (AT&T Research) 2012-07-10 $\n]"
+"[-1c?\n@(#)$Id: cd (AT&T Research) 2012-09-16 $\n]"
 USAGE_LICENSE
 "[+NAME?cd - change working directory ]"
 "[+DESCRIPTION?\bcd\b changes the current working directory of the "
@@ -478,6 +478,11 @@
        "\bPATH_RESOLVE\b.  If \bPATH_RESOLVE\b is \bphysical\b, "
        "then the behavior will be as if \b-P\b were specified.  Otherwise, "
        "the behavior will be as if  \b-L\b were specified.]"
+#ifdef AT_FDCWD
+"[f]#[dirfd?Path is relative to this directory fd. Doing a cd .. below the "
+       "directory defined by the directory fd may result in undefined "
+       "behaviour.]"
+#endif
 "[L?Handle each pathname component \b..\b in a logical fashion by moving "
        "up one level by name in the present working directory.]"
 "[P?The present working directory is first converted to an absolute pathname "
diff -r -u -N original/src/cmd/ksh93/sh/io.c build_fd/src/cmd/ksh93/sh/io.c
--- src/cmd/ksh93/sh/io.c       2012-09-05 23:53:53.000000000 +0200
+++ src/cmd/ksh93/sh/io.c       2012-09-17 13:18:24.393730625 +0200
@@ -755,6 +755,10 @@
        register int            fd = -1;
        mode_t                  mode;
        char                    *e;
+#ifdef AT_FDCWD
+       const char              *apath;
+       int                     dirfd = shp->pwdfd;
+#endif
        va_list                 ap;
        va_start(ap, flags);
        mode = (flags & O_CREAT) ? va_arg(ap, int) : 0;
@@ -770,10 +774,37 @@
                errno = ENOENT;
                return(-1);
        }
+#ifdef AT_FDCWD
+       if (path[0]=='/')
+       {
+               apath = pathdevfd2relpathfd(path, &dirfd);
+               /*
+                * |pathdevfd2relpathfd()| will return |NULL| if
+                * /dev/fd/${num} is not followed by a path.
+                * Question is whether we can use |dup()| in
+                * such a case (warning: |dup()| will cause both
+                * old and new fd to share attributes like the
+                * seek position)
+                */
+               if (apath)
+                       path = apath;
+               else if (path[strlen(path)-1]=='/')
+               {
+                       /*
+                        * If |pathdevfd2relpathfd()| returned |NULL|
+                        * and the input path ends with a '/' (e.g.
+                        * "/dev/fd/89/") we can happily assume it's
+                        * a directory...
+                        */
+                       path = e_dot;
+               }
+       }
+#endif /* AT_FDCWD */
        if (path[0]=='/' && path[1]=='d' && path[2]=='e' && path[3]=='v' && 
path[4]=='/')
        {
                switch (path[5])
                {
+#ifndef AT_FDCWD
                case 'f':
                        if (path[6]=='d' && path[7]=='/')
                        {
@@ -784,6 +815,7 @@
                                        fd = -1;
                        }
                        break;
+#endif
                case 's':
                        if (path[6]=='t' && path[7]=='d')
                                switch (path[8])
@@ -824,13 +856,21 @@
                        struct stat st;
                        if (stat(path,&st) >=0)
                        {
+#ifdef AT_FDCWD
+                               while((nfd = 
openat(dirfd,path,flags,st.st_mode))<0 && errno==EINTR)
+#else
                                while((nfd = open(path,flags,st.st_mode))<0 && 
errno==EINTR)
+#endif
                                        errno = err;
                        }
                }
                else
                {
+#ifdef AT_FDCWD
+                       while((nfd = openat(dirfd,path,flags))<0 && 
errno==EINTR)
+#else
                        while((nfd = open(path,flags))<0 && errno==EINTR)
+#endif
                                errno = err;
                }
                if(nfd>=0)
@@ -858,7 +898,11 @@
                        path = buf;
                }
 #endif
+#ifdef AT_FDCWD
+               while((fd = openat(dirfd, path, flags, mode)) < 0)
+#else
                while((fd = open(path, flags, mode)) < 0)
+#endif
                        if(errno!=EINTR || shp->trapnote)
                                return(-1);
        }
diff -r -u -N original/src/lib/libast/include/ast.h 
build_fd/src/lib/libast/include/ast.h
--- src/lib/libast/include/ast.h        2012-08-09 09:24:49.000000000 +0200
+++ src/lib/libast/include/ast.h        2012-09-17 13:18:24.393730625 +0200
@@ -300,6 +300,7 @@
 extern char*           pathcat_20100601(const char*, int, const char*, const 
char*, char*, size_t);
 extern int             pathcd(const char*, const char*);
 extern int             pathcheck(const char*, const char*, Pathcheck_t*);
+extern const char *    pathdevfd2relpathfd(const char *, int *);
 extern int             pathexists(char*, int);
 extern char*           pathfind(const char*, const char*, const char*, char*, 
size_t);
 extern int             pathgetlink(const char*, char*, int);
diff -r -u -N original/src/lib/libast/Makefile build_fd/src/lib/libast/Makefile
--- src/lib/libast/Makefile     2012-07-31 20:29:26.000000000 +0200
+++ src/lib/libast/Makefile     2012-09-17 13:18:24.394730480 +0200
@@ -79,7 +79,7 @@
        pathexists.c pathfind.c pathkey.c pathprobe.c pathrepl.c \
        pathnative.c pathposix.c pathtemp.c pathtmp.c pathstat.c \
        pathgetlink.c pathsetlink.c pathbin.c pathshell.c pathcd.c \
-       pathprog.c \
+       pathdevfd2relpathfd.c pathprog.c \
        fs3d.c ftwalk.c ftwflags.c fts.c \
        astintercept.c conformance.c getenv.c setenviron.c \
        optget.c optjoin.c optesc.c optctx.c strsort.c struniq.c \
diff -r -u -N original/src/lib/libast/Mamfile build_fd/src/lib/libast/Mamfile
--- src/lib/libast/Mamfile      2012-09-12 06:32:14.000000000 +0200
+++ src/lib/libast/Mamfile      2012-09-17 13:18:24.396730182 +0200
@@ -1197,6 +1197,18 @@
 prev path/pathcd.c
 exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -Icomp -Iinclude -Istd 
-D_PACKAGE_ast -c path/pathcd.c
 done pathcd.o generated
+make pathdevfd2relpathfd.o
+make path/pathdevfd2relpathfd.c
+make include/stk.h implicit
+prev include/sfio.h implicit
+done include/stk.h
+prev include/error.h implicit
+prev include/ast.h implicit
+done path/pathdevfd2relpathfd.c
+meta pathdevfd2relpathfd.o %.c>%.o path/pathdevfd2relpathfd.c 
pathdevfd2relpathfd
+prev path/pathdevfd2relpathfd.c
+exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -Icomp -Iinclude -Istd 
-D_PACKAGE_ast -c path/pathdevfd2relpathfd.c
+done pathdevfd2relpathfd.o generated
 make pathprog.o
 make path/pathprog.c
 make FEATURE/prog implicit
@@ -6115,7 +6127,7 @@
 exec - ${CC} ${mam_cc_FLAGS} ${CCFLAGS} -I. -Icomp -Iinclude -Istd 
-D_PACKAGE_ast -c obsolete/spawn.c
 done spawn.o generated
 exec - ${AR} rc libast.a state.o transition.o opendir.o readdir.o rewinddir.o 
seekdir.o telldir.o getcwd.o fastfind.o hashalloc.o hashdump.o hashfree.o 
hashlast.o hashlook.o hashscan.o hashsize.o hashview.o hashwalk.o memhash.o 
memsum.o strhash.o strkey.o strsum.o stracmp.o strnacmp.o ccmap.o ccmapid.o 
ccnative.o chresc.o chrtoi.o
-exec - ${AR} rc libast.a streval.o strexpr.o strmatch.o strcopy.o modei.o 
modex.o strmode.o strlcat.o strlcpy.o strlook.o strncopy.o strsearch.o 
strpsearch.o stresc.o stropt.o strtape.o strpcmp.o strnpcmp.o strvcmp.o 
strnvcmp.o tok.o tokline.o tokscan.o pathaccess.o pathcat.o pathcanon.o 
pathcheck.o pathpath.o pathexists.o pathfind.o pathkey.o pathprobe.o pathrepl.o 
pathnative.o pathposix.o pathtemp.o pathtmp.o pathstat.o pathgetlink.o 
pathsetlink.o pathbin.o pathshell.o pathcd.o pathprog.o fs3d.o ftwalk.o 
ftwflags.o fts.o astintercept.o conformance.o getenv.o setenviron.o optget.o 
optjoin.o optesc.o optctx.o strsort.o struniq.o magic.o mime.o mimetype.o 
signal.o sigflag.o systrace.o error.o errorf.o errormsg.o errorx.o localeconv.o 
setlocale.o translate.o catopen.o iconv.o lc.o lctab.o mc.o base64.o recfmt.o 
recstr.o reclen.o fmtrec.o fmtbase.o fmtbuf.o fmtclock.o fmtdev.o fmtelapsed.o 
fmterror.o fmtesc.o fmtfmt.o fmtfs.o fmtident.o fmtint.o fmtip4.o fmtip6.o 
fmtls.o fmtmatch.o fmtmode.o fmtnum.o fmtperm.o fmtre.o fmttime.o
+exec - ${AR} rc libast.a streval.o strexpr.o strmatch.o strcopy.o modei.o 
modex.o strmode.o strlcat.o strlcpy.o strlook.o strncopy.o strsearch.o 
strpsearch.o stresc.o stropt.o strtape.o strpcmp.o strnpcmp.o strvcmp.o 
strnvcmp.o tok.o tokline.o tokscan.o pathaccess.o pathcat.o pathcanon.o 
pathcheck.o pathpath.o pathexists.o pathfind.o pathkey.o pathprobe.o pathrepl.o 
pathnative.o pathposix.o pathtemp.o pathtmp.o pathstat.o pathgetlink.o 
pathsetlink.o pathbin.o pathshell.o pathcd.o pathdevfd2relpathfd.o pathprog.o 
fs3d.o ftwalk.o ftwflags.o fts.o astintercept.o conformance.o getenv.o 
setenviron.o optget.o optjoin.o optesc.o optctx.o strsort.o struniq.o magic.o 
mime.o mimetype.o signal.o sigflag.o systrace.o error.o errorf.o errormsg.o 
errorx.o localeconv.o setlocale.o translate.o catopen.o iconv.o lc.o lctab.o 
mc.o base64.o recfmt.o recstr.o reclen.o fmtrec.o fmtbase.o fmtbuf.o fmtclock.o 
fmtdev.o fmtelapsed.o fmterror.o fmtesc.o fmtfmt.o fmtfs.o fmtident.o fmtint.o 
fmtip4.o fmtip6.o fmtls.o fmtmatch.o fmtmode.o fmtnum.o fmtperm.o fmtre.o 
fmttime.o
 exec - ${AR} rc libast.a fmtuid.o fmtgid.o fmtsignal.o fmtscale.o fmttmx.o 
fmttv.o fmtversion.o strelapsed.o strperm.o struid.o strgid.o strtoip4.o 
strtoip6.o stack.o stk.o swapget.o swapmem.o swapop.o swapput.o sigdata.o 
sigcrit.o sigunblock.o procopen.o procclose.o procrun.o procfree.o tmdate.o 
tmequiv.o tmfix.o tmfmt.o tmform.o tmgoff.o tminit.o tmleap.o tmlex.o 
tmlocale.o tmmake.o tmpoff.o tmscan.o tmsleep.o tmtime.o tmtype.o tmweek.o 
tmword.o tmzone.o tmxdate.o tmxduration.o tmxfmt.o tmxgettime.o tmxleap.o 
tmxmake.o tmxscan.o tmxsettime.o tmxsleep.o tmxtime.o tmxtouch.o tvcmp.o 
tvgettime.o tvsettime.o tvsleep.o tvtouch.o cmdarg.o vecargs.o vecfile.o 
vecfree.o vecload.o vecstring.o univdata.o touch.o mnt.o debug.o memccpy.o 
memchr.o memcmp.o memcpy.o memdup.o memmove.o memset.o mkdir.o mkfifo.o mknod.o 
rmdir.o remove.o rename.o link.o unlink.o strdup.o strchr.o strrchr.o strstr.o 
strtod.o strtold.o strtol.o strtoll.o strtoul.o strtoull.o strton.o strtonll.o 
strntod.o strntold.o strnton.o
 exec - ${AR} rc libast.a strntonll.o strntol.o strntoll.o strntoul.o 
strntoull.o strcasecmp.o strncasecmp.o strerror.o mktemp.o tmpnam.o fsync.o 
execlp.o execve.o execvp.o execvpe.o spawnveg.o vfork.o killpg.o hsearch.o 
tsearch.o getlogin.o putenv.o setenv.o unsetenv.o lstat.o statvfs.o eaccess.o 
gross.o omitted.o readlink.o symlink.o getpgrp.o setpgid.o setsid.o waitpid.o 
creat64.o fcntl.o open.o atexit.o getdents.o getwd.o dup2.o errno.o 
getpreroot.o ispreroot.o realopen.o setpreroot.o getgroups.o mount.o system.o 
iblocks.o modedata.o tmdata.o memfatal.o sfkeyprintf.o sfdcdio.o sfdcdos.o 
sfdcfilter.o sfdcseekable.o sfdcslow.o sfdcsubstr.o sfdctee.o sfdcunion.o 
sfdcmore.o sfdcprefix.o wc.o wc2utf8.o basename.o closelog.o dirname.o 
fmtmsglib.o fnmatch.o ftw.o getdate.o getsubopt.o glob.o nftw.o openlog.o 
re_comp.o resolvepath.o realpath.o regcmp.o regexp.o setlogmask.o strftime.o 
strptime.o swab.o syslog.o tempnam.o wordexp.o mktime.o regalloc.o regclass.o 
regcoll.o regcomp.o regcache.o regdecomp.o regerror.o regexec.o regfatal.o 
reginit.o
 exec - ${AR} rc libast.a regnexec.o regsubcomp.o regsubexec.o regsub.o 
regrecord.o regrexec.o regstat.o dtclose.o dtdisc.o dthash.o dtlist.o 
dtmethod.o dtopen.o dtstat.o dtstrhash.o dttree.o dtuser.o dtview.o dtwalk.o 
dtnew.o dtcomp.o sfclose.o sfclrlock.o sfdisc.o sfdlen.o sfexcept.o sfgetl.o 
sfgetu.o sfcvt.o sfecvt.o sffcvt.o sfextern.o sffilbuf.o sfflsbuf.o sfprints.o 
sfgetd.o sfgetr.o sfllen.o sfmode.o sfmove.o sfnew.o sfpkrd.o sfnotify.o 
sfnputc.o sfopen.o sfpeek.o sfpoll.o sfpool.o sfpopen.o sfprintf.o sfputd.o 
sfputl.o sfputr.o sfputu.o sfrd.o sfread.o sfreserve.o sfscanf.o sfseek.o 
sfset.o sfsetbuf.o sfsetfd.o sfsize.o sfsk.o sfstack.o sfstrtod.o sfsync.o 
sfswap.o sftable.o sftell.o sftmp.o sfungetc.o sfvprintf.o sfvscanf.o sfwr.o 
sfwrite.o sfpurge.o sfraise.o sfwalk.o sfgetm.o sfmutex.o sfputm.o sfresize.o 
_sfclrerr.o _sfeof.o _sferror.o _sffileno.o _sfopen.o _sfstacked.o _sfvalue.o 
_sfgetc.o _sfgetl.o _sfgetl2.o _sfgetu.o _sfgetu2.o _sfdlen.o _sfllen.o 
_sfslen.o _sfulen.o _sfputc.o _sfputd.o
diff -r -u -N original/src/lib/libast/path/pathdevfd2relpathfd.c 
build_fd/src/lib/libast/path/pathdevfd2relpathfd.c
--- src/lib/libast/path/pathdevfd2relpathfd.c   1970-01-01 01:00:00.000000000 
+0100
+++ src/lib/libast/path/pathdevfd2relpathfd.c   2012-09-17 15:05:11.977833816 
+0200
@@ -0,0 +1,93 @@
+/***********************************************************************
+*                                                                      *
+*               This software is part of the ast package               *
+*          Copyright (c) 1985-2011 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>                *
+*                                                                      *
+***********************************************************************/
+#pragma prototyped
+
+/*
+ * Strip leading /dev/fd/<num>... from paths and return relative path
+ * to that file descriptor
+ */
+
+#include <ast.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+/*
+ * Extract /dev/fd part and either return the original path
+ * if it does not begin with /dev/fd/<number> or extract
+ * the <number> from /dev/fd/<number>... and return the
+ * remaining path relative to fd <number>.
+ * If nothing is left in the remaining relative path return
+ * |NULL|.
+ *
+ * Examples: 
+ * path=|/dev/fd/| should return |/dev/fd/| and not touch fd_p
+ * path=|/dev/fd/45| should return NULL and *fd_p=45
+ * path=|/dev/fd/45/| should return NULL and *fd_p=45
+ * path=|/dev/fd/45/dev|| should return |dev|, *fd_p=45
+ * path=|//dev/fd/45/dev| should return |//dev/fd/45/dev| and
+ *      not touch fd_p
+ */
+const char *pathdevfd2relpathfd(const char *p, int *fd_p)
+{
+       char            buff[32];
+       char            *b;
+       const char      *s;
+       int             fd;
+
+       /*
+         * We do not use |memcpy()| here since this "manual"
+        * version is faster and uses less code space
+        */
+       if (!(p[0]=='/' && p[1]=='d' && p[2]=='e' && p[3]=='v' && p[4]=='/' &&
+             p[5]=='f' && p[6]=='d' && p[7]=='/' &&
+             isdigit(p[8])))
+               return (p);
+
+       s=p+8;
+       b=buff;
+       while (isdigit(*s) && *s!='\0' && (b < (buff+sizeof(buff)-1)))
+               *b++ = *s++;
+       *b='\0';
+
+       errno=0;
+       fd=strtol(buff, NULL, 10);
+       if ((errno != 0) || (fd < 0))
+               return (p);
+
+       /*
+        * Eat all '/' to make sure the path we return
+        * is really a relative one (relative to the
+        * fd)
+        */
+       while (*s=='/')
+               s++;
+
+       *fd_p=fd;
+
+       /*
+        * Make sure we return a relative path to the fd we returned,
+        * an absolute one would screw things up...
+        */
+       if (*s=='\0')
+               s=NULL;
+       return (s);
+}
+
diff -r -u -N original/src/lib/libast/sfio/_sfopen.c 
build_fd/src/lib/libast/sfio/_sfopen.c
--- src/lib/libast/sfio/_sfopen.c       2012-08-31 23:25:24.000000000 +0200
+++ src/lib/libast/sfio/_sfopen.c       2012-09-17 13:18:24.398729877 +0200
@@ -57,9 +57,30 @@
 {
        int     fd, oldfd, oflags, fflags, sflags;
        SFMTXDECL(f);
+#ifdef AT_FDCWD
+       if (file)
+       {
+               const char *afile;
 
-       if (file && *file == '/')
-               cwd = AT_FDCWD;
+               if (*file == '/')
+               {
+                       cwd = AT_FDCWD;
+                       afile = pathdevfd2relpathfd(file, &cwd);
+                       /*
+                        * |pathdevfd2relpathfd| will return |NULL| if
+                        *  /dev/fd/${num} is not followed by a path.
+                        * Question is whether we can use |dup()| in
+                        * such a case (warning: |dup()| will cause
+                        * both old and new fd to share attributes
+                        * like the seek position)
+                        */
+                       if (afile)
+                               file = afile;
+                       else if (file[strlen(file)-1]=='/')
+                               file = ".";
+               }
+       }
+#endif
 #if !defined(sysopenatf)
        if (cwd != AT_FDCWD)
        {
_______________________________________________
ast-developers mailing list
ast-developers@research.att.com
https://mailman.research.att.com/mailman/listinfo/ast-developers

Reply via email to