Skip to content

Commit

Permalink
More work on mapping OS/2 drive letters to the Unix filesystem.
Browse files Browse the repository at this point in the history
  • Loading branch information
icculus committed Jul 10, 2018
1 parent 8c8f416 commit 0894e3d
Show file tree
Hide file tree
Showing 3 changed files with 167 additions and 39 deletions.
152 changes: 130 additions & 22 deletions lib2ine.c
Expand Up @@ -370,46 +370,54 @@ 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')) {
letter -= 'a' - 'A';
}

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) {
Expand All @@ -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);
Expand Down Expand Up @@ -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) {
Expand All @@ -557,6 +664,7 @@ LX_NATIVE_CONSTRUCTOR(lib2ine)
GLoaderState.terminate = terminate_lib2ine;

cfgLoadFiles();
prepOs2Drives();

struct rlimit rlim;
if (getrlimit(RLIMIT_STACK, &rlim) == -1) {
Expand All @@ -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));
Expand Down
5 changes: 4 additions & 1 deletion lib2ine.h
Expand Up @@ -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;
Expand Down
49 changes: 33 additions & 16 deletions lx_loader.c
Expand Up @@ -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;
Expand Down

0 comments on commit 0894e3d

Please sign in to comment.