Skip to content

Commit

Permalink
Moved the path conversion code to lx_loader.c, and use it.
Browse files Browse the repository at this point in the history
Fixes loading "emx.dll" when the loader asked for "EMX.dll", etc.
  • Loading branch information
icculus committed Oct 18, 2016
1 parent 2016af8 commit 60e62a1
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 96 deletions.
106 changes: 106 additions & 0 deletions lx_loader.c
Expand Up @@ -9,6 +9,7 @@
#include <sys/mman.h>
#include <assert.h>
#include <dlfcn.h>
#include <dirent.h>
#include <pthread.h>

// 16-bit selector kernel nonsense...
Expand Down Expand Up @@ -103,6 +104,107 @@ static char *makeOS2Path(const char *fname)
return retval;
} // makeOS2Path

// based on case-insensitive search code from PhysicsFS:
// https://icculus.org/physfs/
// It's also zlib-licensed, plus I wrote it. :) --ryan.
// !!! FIXME: this doesn't work as-is for UTF-8 case folding, since string
// !!! FIXNE: length can change!
static int locateOneElement(char *buf)
{
if (access(buf, F_OK) == 0)
return 1; // quick rejection: exists in current case.

DIR *dirp;
char *ptr = strrchr(buf, '/'); // find entry at end of path.
if (ptr == NULL) {
dirp = opendir(".");
ptr = buf;
} else if (ptr == buf) {
dirp = opendir("/");
} else {
*ptr = '\0';
dirp = opendir(buf);
*ptr = '/';
ptr++; // point past dirsep to entry itself.
} // else

for (struct dirent *dent = readdir(dirp); dent; dent = readdir(dirp)) {
if (strcasecmp(dent->d_name, ptr) == 0) {
strcpy(ptr, dent->d_name); // found a match. Overwrite with this case.
closedir(dirp);
return 1;
} // if
} // for

// no match at all...
closedir(dirp);
return 0;
} // locateOneElement

static int locatePathCaseInsensitive(char *buf)
{
int rc;
char *ptr = buf;

if (*ptr == '\0')
return 0; // Uh...I guess that's success?

if (access(buf, F_OK) == 0)
return 0; // quick rejection: exists in current case.

while ( (ptr = strchr(ptr + 1, '/')) != NULL ) {
*ptr = '\0'; // block this path section off
rc = locateOneElement(buf);
*ptr = '/'; // restore path separator
if (!rc)
return -2; // missing element in path.
} // while

// check final element...
return locateOneElement(buf) ? 0 : -1;
} // locatePathCaseInsensitive

static char *makeUnixPath(const char *os2path, uint32 *err)
{
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'))
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

const size_t len = strlen(os2path);
char *retval = (char *) malloc(len + 1);
if (!retval) {
*err = 8; //ERROR_NOT_ENOUGH_MEMORY;
return NULL;
} // else

strcpy(retval, os2path);

for (char *ptr = strchr(retval, '\\'); ptr; ptr = strchr(ptr + 1, '\\'))
*ptr = '/'; // convert to Unix-style path separators.

locatePathCaseInsensitive(retval);

return retval;
} // makeUnixPath


/* this algorithm is from lxlite 138u. */
static int decompressExePack2(uint8 *dst, const uint32 dstlen, const uint8 *src, const uint32 srclen)
{
Expand Down Expand Up @@ -1212,6 +1314,7 @@ static LxModule *loadLxModuleByModuleNameInternal(const char *modname, const int
// !!! FIXME: decide the right path to the file, or if it's a native replacement library.
char fname[256];
snprintf(fname, sizeof (fname), "%s.dll", modname);
locatePathCaseInsensitive(fname);

LxModule *retval = NULL;
if (access(fname, F_OK) == 0)
Expand Down Expand Up @@ -1366,6 +1469,9 @@ int main(int argc, char **argv, char **envp)
GLoaderState->initOs2Tib = initOs2Tib;
GLoaderState->deinitOs2Tib = deinitOs2Tib;
GLoaderState->loadModule = loadLxModuleByModuleName;
GLoaderState->locatePathCaseInsensitive = locatePathCaseInsensitive;
GLoaderState->makeUnixPath = makeUnixPath;
GLoaderState->makeOS2Path = makeOS2Path;

const char *modulename = GLoaderState->subprocess ? envr : argv[1];

Expand Down
3 changes: 3 additions & 0 deletions lx_loader.h
Expand Up @@ -207,6 +207,9 @@ typedef struct LxLoaderState
uint16 (*initOs2Tib)(uint8 *tibspace, void *_topOfStack, const size_t stacklen, const uint32 tid);
void (*deinitOs2Tib)(const uint16 selector);
LxModule *(*loadModule)(const char *modname);
int (*locatePathCaseInsensitive)(char *buf);
char *(*makeUnixPath)(const char *os2path, uint32 *err);
char *(*makeOS2Path)(const char *fname);
} LxLoaderState;

typedef const LxExport *(*LxNativeModuleInitEntryPoint)(LxLoaderState *lx_state, uint32 *lx_num_exports);
Expand Down
97 changes: 1 addition & 96 deletions native/doscalls.c
Expand Up @@ -752,104 +752,9 @@ APIRET DosGetDateTime(PDATETIME pdt)
return NO_ERROR; // never returns failure.
} // DosGetDateTime


// based on case-insensitive search code from PhysicsFS:
// https://icculus.org/physfs/
// It's also zlib-licensed, plus I wrote it. :) --ryan.
// !!! FIXME: this doesn't work as-is for UTF-8 case folding, since string
// !!! FIXNE: length can change!
static int locateOneElement(char *buf)
{
if (access(buf, F_OK) == 0)
return 1; // quick rejection: exists in current case.

DIR *dirp;
char *ptr = strrchr(buf, '/'); // find entry at end of path.
if ((ptr == NULL) || (ptr == buf)) {
dirp = opendir("/");
ptr = buf;
} else {
*ptr = '\0';
dirp = opendir(buf);
*ptr = '/';
ptr++; // point past dirsep to entry itself.
} // else

for (struct dirent *dent = readdir(dirp); dent; dent = readdir(dirp)) {
if (strcasecmp(dent->d_name, ptr) == 0) {
strcpy(ptr, dent->d_name); // found a match. Overwrite with this case.
closedir(dirp);
return 1;
} // if
} // for

// no match at all...
closedir(dirp);
return 0;
} // locateOneElement

static int locatePathCaseInsensitive(char *buf)
{
int rc;
char *ptr = buf;

if (*ptr == '\0')
return 0; // Uh...I guess that's success?

if (access(buf, F_OK) == 0)
return 0; // quick rejection: exists in current case.

while ( (ptr = strchr(ptr + 1, '/')) != NULL ) {
*ptr = '\0'; // block this path section off
rc = locateOneElement(buf);
*ptr = '/'; // restore path separator
if (!rc)
return -2; // missing element in path.
} // while

// check final element...
return locateOneElement(buf) ? 0 : -1;
} // locatePathCaseInsensitive


static char *makeUnixPath(const char *os2path, APIRET *err)
{
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'))
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 = ERROR_NOT_DOS_DISK;
return NULL;
} // else
} // if
} // if
} // else

const size_t len = strlen(os2path);
char *retval = (char *) malloc(len + 1);
if (!retval) {
*err = ERROR_NOT_ENOUGH_MEMORY;
return NULL;
} // else

strcpy(retval, os2path);

for (char *ptr = strchr(retval, '\\'); ptr; ptr = strchr(ptr + 1, '\\'))
*ptr = '/'; // convert to Unix-style path separators.

locatePathCaseInsensitive(retval);

return retval;
return GLoaderState->makeUnixPath(os2path, (uint32 *) err);
} // makeUnixPath

static APIRET doDosOpen(PSZ pszFileName, PHFILE pHf, PULONG pulAction, LONGLONG cbFile, ULONG ulAttribute, ULONG fsOpenFlags, ULONG fsOpenMode, PEAOP2 peaop2)
Expand Down

0 comments on commit 60e62a1

Please sign in to comment.