diff --git a/misc.c b/misc.c index 1c6eaad..a7c5294 100644 --- a/misc.c +++ b/misc.c @@ -32,7 +32,7 @@ #include #endif -__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.283 2017/10/11 21:49:06 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.284 2017/10/11 23:23:02 tg Exp $"); #define KSH_CHVT_FLAG #ifdef MKSH_SMALL @@ -1661,6 +1661,15 @@ do_realpath(const char *upath) if (mksh_abspath(upath)) { /* upath is an absolute pathname */ strdupx(ipath, upath, ATEMP); +#ifdef MKSH_DOSPATH + } else if (mksh_drvltr(upath)) { + /* upath is a drive-relative pathname */ + if (!getdrvwd(&ldest, ord(*upath))) + return (NULL); + /* A:foo -> A:/cwd/foo; A: -> A:/cwd */ + ipath = shf_smprintf(Tf_sss, ldest, + upath[2] ? "/" : "", upath + 2); +#endif } else { /* upath is a relative pathname, prepend cwd */ if ((tp = ksh_get_wd()) == NULL || !mksh_abspath(tp)) @@ -1762,11 +1771,23 @@ do_realpath(const char *upath) * restart if symlink target is an absolute path, * otherwise continue with currently resolved prefix */ +#ifdef MKSH_DOSPATH + assemble_symlink: +#endif /* append rest of current input path to link target */ tp = shf_smprintf(Tf_sss, ldest, *ip ? "/" : "", ip); afree(ipath, ATEMP); ip = ipath = tp; - if (!mksh_abspath(ldest)) { + if (!mksh_abspath(ipath)) { +#ifdef MKSH_DOSPATH + /* symlink target might be drive-relative */ + if (mksh_drvltr(ipath)) { + if (!getdrvwd(&ldest, ord(*ipath))) + goto notfound; + ip += 2; + goto assemble_symlink; + } +#endif /* symlink target is a relative path */ xp = Xrestpos(xs, xp, pos); } else @@ -1775,7 +1796,7 @@ do_realpath(const char *upath) /* symlink target is an absolute path */ xp = Xstring(xs, xp); beginning_of_a_pathname: - /* assert: mksh_cdirsep((ip == ipath)[0]) */ + /* assert: mksh_abspath(ip == ipath) */ /* assert: xp == xs.beg => start of path */ /* exactly two leading slashes? (SUSv4 3.266) */ @@ -1789,14 +1810,6 @@ do_realpath(const char *upath) /* keep it */ Xput(xs, xp, *ip++); Xput(xs, xp, *ip++); - /* - * XXX if (!mksh_cdirsep(*ip)): we - * XXX must get the cwd on that drive - * XXX and prepend it here as this is - * XXX a drive-qualified relative path - * XXX which we are supposed to convert - * XXX to an absolute (with drive) one - */ } #endif } diff --git a/os2.c b/os2.c index fc27d5a..4c191a6 100644 --- a/os2.c +++ b/os2.c @@ -21,16 +21,19 @@ */ #define INCL_DOS +#define INCL_DOSFILEMGR +#define INCL_DOSMISC #include #include "sh.h" #include +#include #include #include #include -__RCSID("$MirOS: src/bin/mksh/os2.c,v 1.2 2017/04/29 22:04:29 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/os2.c,v 1.3 2017/10/11 23:23:03 tg Exp $"); static char *remove_trailing_dots(char *); static int access_stat_ex(int (*)(), const char *, void *); @@ -557,3 +560,52 @@ cleanup(void) { cleanup_temps(); } + +int +getdrvwd(char **cpp, unsigned int drvltr) +{ + PBYTE *cp; + ULONG sz; + APIRET rc; + ULONG drvno; + + if (DosQuerySysInfo(QSV_MAX_PATH_LENGTH, QSV_MAX_PATH_LENGTH, + &sz, sizeof(sz)) != 0) { + errno = EDOOFUS; + return (-1); + } + + /* allocate 'X:/' plus sz plus NUL */ + checkoktoadd((size_t)sz, (size_t)4); + cp = aresize(*cpp, (size_t)sz + (size_t)4, ATEMP); + cp[0] = drvltr; + cp[1] = ':'; + cp[2] = '/'; + drvno = (rtt2asc(drvltr) | 0x20U) - rtt2asc('a') + 1; + /* NUL is part of space within buffer passed */ + ++sz; + if ((rc = DosQueryCurrentDir(drvno, cp + 3, &sz)) == 0) { + /* success! */ + *cpp = cp; + return (0); + } + afree(cp, ATEMP); + *cpp = NULL; + switch (rc) { + case 15: /* invalid drive */ + errno = ENOTBLK; + break; + case 26: /* not dos disk */ + errno = ENODEV; + break; + case 108: /* drive locked */ + errno = EDEADLK; + break; + case 111: /* buffer overflow */ + errno = ENAMETOOLONG; + break; + default: + errno = EINVAL; + } + return (-1); +} diff --git a/sh.h b/sh.h index b76bd6c..5046408 100644 --- a/sh.h +++ b/sh.h @@ -182,7 +182,7 @@ #endif #ifdef EXTERN -__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.846 2017/10/11 21:52:46 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.847 2017/10/11 23:23:03 tg Exp $"); #endif #define MKSH_VERSION "R56 2017/08/29" @@ -2566,6 +2566,7 @@ void setextlibpath(const char *, const char *); int access_ex(int (*)(const char *, int), const char *, int); int stat_ex(const char *, struct stat *); const char *real_exec_name(const char *); +int getdrvwd(char **, unsigned int); #endif /* shf.c */ struct shf *shf_open(const char *, int, int, int);