From 0894e3d69d5c0c21868e1ec0f6d2aeb412567e91 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Tue, 10 Jul 2018 01:19:37 -0400 Subject: [PATCH] More work on mapping OS/2 drive letters to the Unix filesystem. --- lib2ine.c | 152 ++++++++++++++++++++++++++++++++++++++++++++-------- lib2ine.h | 5 +- lx_loader.c | 49 +++++++++++------ 3 files changed, 167 insertions(+), 39 deletions(-) diff --git a/lib2ine.c b/lib2ine.c index 55f9401..e6447d8 100644 --- a/lib2ine.c +++ b/lib2ine.c @@ -370,7 +370,19 @@ static int cfgIsSymChar(const int ch) return ((ch == '_') || ((ch >= 'a') && (ch <= 'z')) || ((ch >= 'A') && (ch <= 'Z'))); } -static void cfgProcessDrive(const char *fname, const int lineno, const char *var, const char *val) +static void cfgProcessBoolString(const char *fname, const int lineno, int *output, const char *val) +{ + static const char *y[] = { "1", "yes", "y", "true", "t", "on" }; + static const char *n[] = { "0", "no", "n", "false", "f", "off" }; + int i; + for (i = 0; i < (sizeof (y) / sizeof (y[0])); i++) { + if (strcasecmp(val, y[i]) == 0) { *output = 1; return; } + if (strcasecmp(val, n[i]) == 0) { *output = 0; return; } + } + cfgWarn(fname, lineno, "\"%s\" is not valid for this setting. Try 1 or 0.", val); +} + +static void cfgProcessMountPoint(const char *fname, const int lineno, const char *var, const char *val) { char letter = var[0]; if ((letter >= 'a') && (letter <= 'z')) { @@ -378,38 +390,34 @@ static void cfgProcessDrive(const char *fname, const int lineno, const char *var } if ((letter < 'A') || (letter > 'Z') || (var[1] != '\0')) { - cfgWarn(fname, lineno, "Invalid drive \"%s\" (must be between 'A' and 'Z')", var); + cfgWarn(fname, lineno, "Invalid disk \"%s\" (must be between 'A' and 'Z')", var); return; } const int idx = (int) (letter - 'A'); - free(GLoaderState.drives[idx]); // in case we're overriding. - GLoaderState.drives[idx] = NULL; + free(GLoaderState.disks[idx]); // in case we're overriding. + GLoaderState.disks[idx] = NULL; if (*val != '\0') { // val=="" means don't mount + const size_t vallen = strlen(val); struct stat statbuf; if (stat(val, &statbuf) == -1) { cfgWarn(fname, lineno, "Path \"%s\" for drive %c:\\ isn't accessible: %s", val, letter, strerror(errno)); } else if (!S_ISDIR(statbuf.st_mode)) { cfgWarn(fname, lineno, "Path \"%s\" for drive %c:\\ isn't a directory", val, letter); - } else if ((GLoaderState.drives[idx] = strdup(val)) == NULL) { + } else if ((GLoaderState.disks[idx] = (char *) malloc(vallen + 2)) == NULL) { cfgWarn(fname, lineno, "Out of memory!"); + } else { + char *ptr = GLoaderState.disks[idx]; + strcpy(ptr, val); + if (ptr[vallen - 1] != '/') { + ptr[vallen] = '/'; + ptr[vallen+1] = '\0'; + } } } } -static void cfgProcessBoolString(const char *fname, const int lineno, int *output, const char *val) -{ - static const char *y[] = { "1", "yes", "y", "true", "t", "on" }; - static const char *n[] = { "0", "no", "n", "false", "f", "off" }; - int i; - for (i = 0; i < (sizeof (y) / sizeof (y[0])); i++) { - if (strcasecmp(val, y[i]) == 0) { *output = 1; return; } - if (strcasecmp(val, n[i]) == 0) { *output = 0; return; } - } - cfgWarn(fname, lineno, "\"%s\" is not valid for this setting. Try 1 or 0.", val); -} - static void cfgProcessSystem(const char *fname, const int lineno, const char *var, const char *val) { if (strcmp(var, "trace_native") == 0) { @@ -426,8 +434,8 @@ static void cfgProcessLine(const char *fname, const int lineno, const char *cate //printf("CFG: process line cat=%s var=%s, val=%s\n", category, var, val); if ((*category == '\0') || (*var == '\0')) { cfgWarn(fname, lineno, "Invalid configuration line"); - } else if (strcmp(category, "drive") == 0) { - cfgProcessDrive(fname, lineno, var, val); + } else if (strcmp(category, "mountpoint") == 0) { + cfgProcessMountPoint(fname, lineno, var, val); // eventually will map COM1, LPT1, NUL, etc. //} else if (strcmp(category, "device") == 0) { // cfgProcessDevice(fname, lineno, var, val); @@ -533,6 +541,105 @@ static void cfgLoadFiles(void) } } +static void prepOs2Drives(void) +{ + const int drive_c = 'C' - 'A'; + const int total = (sizeof (GLoaderState.disks) / sizeof (GLoaderState.disks[0])); + uint32 diskmap = 0; + int lowestmounted = 0; + int lowestcwd = 0; + int i; + + FIXME("need to pass current dirs and disks to OS/2 subprocesses"); + + char *cwd = getcwd(NULL, 0); + char *rp = cwd ? realpath(cwd, NULL) : NULL; // in case there's a symlink in there. + if ((cwd == NULL) || (rp == NULL)) { + fprintf(stderr, "Can't get cwd (%s), defaulting to \"/\".\n", strerror(errno)); + rp = strdup("/"); + chdir(rp); + } + + free(cwd); + cwd = rp; + + for (i = 0; i < total; i++) { + if (GLoaderState.disks[i] == NULL) { + continue; + } + + rp = realpath(GLoaderState.disks[i], NULL); + if (rp == NULL) { + fprintf(stderr, "Can't realpath \"%s\" (%s), not mounting %c:\\\n", GLoaderState.disks[i], strerror(errno), i + 'A'); + free(GLoaderState.disks[i]); + GLoaderState.disks[i] = NULL; + continue; + } + + if (lowestmounted < 3) { + lowestmounted = i + 1; + } + + diskmap |= (1 << i); + + const size_t rplen = strlen(rp); + assert(rplen > 0); + if ((strncmp(rp, cwd, rplen) == 0) && ((rp[rplen-1] == '/') || (cwd[rplen] == '/') || (cwd[rplen] == '\0'))) { + // our cwd is under this mount point! + const char *d = cwd + rplen; + GLoaderState.current_dir[i] = strdup((*d == '/') ? d + 1 : d); + char *ptr = GLoaderState.current_dir[i]; + while (*ptr) { // make current dir an OS/2-style relative path. + if (*ptr == '/') { + *ptr = '\\'; + } + ptr++; + } + + if (lowestcwd < 3) { + lowestcwd = i + 1; + } + } else { + // current directory isn't under this mount point, just make it the root. + GLoaderState.current_dir[i] = strdup(""); + } + free(rp); + } + + if (!lowestmounted) { + // if no disks are mapped at all, just map the Unix root filesystem to C: + GLoaderState.disks[drive_c] = strdup("/"); + char *ptr = strdup(cwd + 1); // skip the initial '/' + GLoaderState.current_dir[drive_c] = ptr; + while (*ptr) { // make current dir an OS/2-style relative path. + if (*ptr == '/') { + *ptr = '\\'; + } + ptr++; + } + GLoaderState.current_disk = drive_c + 1; + } else if (!lowestcwd) { + // your actual cwd isn't under any mountpoint, so pick the first mounted drive we + // saw, starting with C:\, unless we only have A:\ or B:\, then use one of those. + GLoaderState.current_disk = lowestmounted; + } else { + GLoaderState.current_disk = lowestcwd; + } + + free(cwd); + + GLoaderState.diskmap = diskmap; + + #if 0 + fprintf(stderr, "OS/2 disks:\n"); + for (i = 0; i < total; i++) { + if (GLoaderState.disks[i] == NULL) continue; + fprintf(stderr, " %c: -> mountpoint='%s' cwd='%s' current=%d\n", 'A' + i, GLoaderState.disks[i], GLoaderState.current_dir[i], GLoaderState.current_disk == (i+1)); + } + fprintf(stderr, "\n"); + #endif +} + LX_NATIVE_CONSTRUCTOR(lib2ine) { if (pthread_key_create(&tlskey, NULL) != 0) { @@ -557,6 +664,7 @@ LX_NATIVE_CONSTRUCTOR(lib2ine) GLoaderState.terminate = terminate_lib2ine; cfgLoadFiles(); + prepOs2Drives(); struct rlimit rlim; if (getrlimit(RLIMIT_STACK, &rlim) == -1) { @@ -583,9 +691,9 @@ LX_NATIVE_CONSTRUCTOR(lib2ine) LX_NATIVE_DESTRUCTOR(lib2ine) { - int i; - for (i = 0; i < (sizeof (GLoaderState.drives) / sizeof (GLoaderState.drives[0])); i++) { - free(GLoaderState.drives[i]); + for (int i = 0; i < (sizeof (GLoaderState.disks) / sizeof (GLoaderState.disks[0])); i++) { + free(GLoaderState.disks[i]); + GLoaderState.disks[i] = NULL; } free(GLoaderState.pib.pib_pchenv); memset(&GLoaderState, '\0', sizeof (GLoaderState)); diff --git a/lib2ine.h b/lib2ine.h index 1147553..106f70b 100644 --- a/lib2ine.h +++ b/lib2ine.h @@ -288,7 +288,10 @@ typedef struct LxLoaderState int running; int trace_native; int trace_events; - char *drives[26]; // mount points, A: through Z: ... NULL if unmounted. + char *disks[26]; // mount points, A: through Z: ... NULL if unmounted. + char *current_dir[26]; // current directory, per-disk, A: through Z: ... NULL if unmounted. + int current_disk; // 1==A:\\, 2==B:\\, etc. + uint32 diskmap; // 1<<0==drive A mounted, 1<<1==drive B mounted, etc. uint8 main_tib_selector; uint32 mainstacksize; uint16 original_cs; diff --git a/lx_loader.c b/lx_loader.c index 257159f..4db5e72 100644 --- a/lx_loader.c +++ b/lx_loader.c @@ -200,39 +200,56 @@ static int locatePathCaseInsensitive(char *buf) static char *lxMakeUnixPath(const char *os2path, uint32 *err) { + const char *mountpoint = NULL; + const char *cwd = NULL; + + FIXME("map devices in 2ine.cfg"); if ((strcasecmp(os2path, "NUL") == 0) || (strcasecmp(os2path, "\\DEV\\NUL") == 0)) os2path = "/dev/null"; // !!! FIXME: emulate other OS/2 device names (CON, etc). //else if (strcasecmp(os2path, "CON") == 0) else { char drive = os2path[0]; - if ((drive >= 'a') && (drive <= 'z')) + if ((drive >= 'a') && (drive <= 'z')) { drive += 'A' - 'a'; + } - if ((drive >= 'A') && (drive <= 'Z')) { - if (os2path[1] == ':') { // it's a drive letter. - if (drive == 'C') - os2path += 2; // skip "C:" if it's there. - else { - *err = 26; //ERROR_NOT_DOS_DISK; - return NULL; - } // else - } // if - } // if - } // else + if (((drive >= 'A') && (drive <= 'Z')) && (os2path[1] == ':')) { // it's a drive letter. + os2path += 2; // skip "C:" + } else { + drive = (GLoaderState.current_disk-1) + 'A'; + } + + const int driveidx = drive - 'A'; + mountpoint = GLoaderState.disks[driveidx]; + if (!mountpoint) { + *err = 26; //ERROR_NOT_DOS_DISK; + return NULL; + } + + if (*os2path != '\\') { + cwd = GLoaderState.current_dir[driveidx]; + } + } - const size_t len = strlen(os2path); - char *retval = (char *) malloc(len + 1); + const size_t len = (mountpoint ? strlen(mountpoint) : 0) + (cwd ? strlen(cwd) : 0) + strlen(os2path) + 3; + char *retval = (char *) malloc(len); if (!retval) { *err = 8; //ERROR_NOT_ENOUGH_MEMORY; return NULL; - } // else + } - strcpy(retval, os2path); + snprintf(retval, len, "%s%s%s%s%s", mountpoint ? mountpoint : "", cwd ? "/" : "", cwd ? cwd : "", ((!*os2path) || (*os2path == '/')) ? "" : "/", os2path); for (char *ptr = strchr(retval, '\\'); ptr; ptr = strchr(ptr + 1, '\\')) *ptr = '/'; // convert to Unix-style path separators. + FIXME("this could be more efficient"); + char *ptr = retval; + while ((ptr = strstr(ptr, "//")) != NULL) { + memmove(ptr, ptr + 1, strlen(ptr)); + } + locatePathCaseInsensitive(retval); return retval;