Allow UTF-8 paths on Windows

A paths trouble appears on Windows OS when program which uses luajit is placed in a path which contains non-ASCII characters.
Usually on Linux, OS X and other posix and unix-like platforms paths are encoded as UTF-8, therefore no troubles with fopen() function.
On modern Windows versions all paths are encoded as UTF-16LE and also fopen() function on Windows always accepts ANSI-encoded paths,
therefore because a codepage mismatch, fopen() think that file is not exists.
To resolve this trouble need to convert accepted path into UTF-16 from UTF-8 and use _wfopen() which accepts UTF-16 paths.

_lua_fopen() and _lua_freopen() functions are made to allow support of UTF-8 paths
on Windows, on any other platforms there are a macros over standard fopen/freopen functions.
This commit is contained in:
Wohlstand 2016-03-24 19:15:06 +03:00
parent 713e34054f
commit 7115753e47
8 changed files with 72 additions and 7 deletions

View File

@ -486,7 +486,7 @@ LJCORE_O= lj_gc.o lj_err.o lj_char.o lj_bc.o lj_obj.o lj_buf.o \
lj_asm.o lj_trace.o lj_gdbjit.o \ lj_asm.o lj_trace.o lj_gdbjit.o \
lj_ctype.o lj_cdata.o lj_cconv.o lj_ccall.o lj_ccallback.o \ lj_ctype.o lj_cdata.o lj_cconv.o lj_ccall.o lj_ccallback.o \
lj_carith.o lj_clib.o lj_cparse.o \ lj_carith.o lj_clib.o lj_cparse.o \
lj_lib.o lj_alloc.o lib_aux.o \ lj_lib.o lj_alloc.o lib_aux.o lj_fopen.o \
$(LJLIB_O) lib_init.o $(LJLIB_O) lib_init.o
LJVMCORE_O= $(LJVM_O) $(LJCORE_O) LJVMCORE_O= $(LJVM_O) $(LJCORE_O)

View File

@ -25,6 +25,7 @@
#include "lj_strfmt.h" #include "lj_strfmt.h"
#include "lj_ff.h" #include "lj_ff.h"
#include "lj_lib.h" #include "lj_lib.h"
#include "lj_fopen.h"
/* Userdata payload for I/O file. */ /* Userdata payload for I/O file. */
typedef struct IOFileUD { typedef struct IOFileUD {
@ -84,7 +85,7 @@ static IOFileUD *io_file_open(lua_State *L, const char *mode)
{ {
const char *fname = strdata(lj_lib_checkstr(L, 1)); const char *fname = strdata(lj_lib_checkstr(L, 1));
IOFileUD *iof = io_file_new(L); IOFileUD *iof = io_file_new(L);
iof->fp = fopen(fname, mode); iof->fp = _lua_fopen(fname, mode);
if (iof->fp == NULL) if (iof->fp == NULL)
luaL_argerror(L, 1, lj_strfmt_pushf(L, "%s: %s", fname, strerror(errno))); luaL_argerror(L, 1, lj_strfmt_pushf(L, "%s: %s", fname, strerror(errno)));
return iof; return iof;
@ -401,7 +402,7 @@ LJLIB_CF(io_open)
GCstr *s = lj_lib_optstr(L, 2); GCstr *s = lj_lib_optstr(L, 2);
const char *mode = s ? strdata(s) : "r"; const char *mode = s ? strdata(s) : "r";
IOFileUD *iof = io_file_new(L); IOFileUD *iof = io_file_new(L);
iof->fp = fopen(fname, mode); iof->fp = _lua_fopen(fname, mode);
return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, fname); return iof->fp != NULL ? 1 : luaL_fileresult(L, 0, fname);
} }

View File

@ -16,6 +16,7 @@
#include "lj_obj.h" #include "lj_obj.h"
#include "lj_err.h" #include "lj_err.h"
#include "lj_lib.h" #include "lj_lib.h"
#include "lj_fopen.h"
/* ------------------------------------------------------------------------ */ /* ------------------------------------------------------------------------ */
@ -270,7 +271,7 @@ static int lj_cf_package_unloadlib(lua_State *L)
static int readable(const char *filename) static int readable(const char *filename)
{ {
FILE *f = fopen(filename, "r"); /* try to open file */ FILE *f = _lua_fopen(filename, "r"); /* try to open file */
if (f == NULL) return 0; /* open failed */ if (f == NULL) return 0; /* open failed */
fclose(f); fclose(f);
return 1; return 1;

View File

@ -17,6 +17,7 @@
#include "lj_cdata.h" #include "lj_cdata.h"
#include "lj_clib.h" #include "lj_clib.h"
#include "lj_strfmt.h" #include "lj_strfmt.h"
#include "lj_fopen.h"
/* -- OS-specific functions ----------------------------------------------- */ /* -- OS-specific functions ----------------------------------------------- */
@ -94,7 +95,7 @@ static const char *clib_check_lds(lua_State *L, const char *buf)
/* Quick and dirty solution to resolve shared library name from ld script. */ /* Quick and dirty solution to resolve shared library name from ld script. */
static const char *clib_resolve_lds(lua_State *L, const char *name) static const char *clib_resolve_lds(lua_State *L, const char *name)
{ {
FILE *fp = fopen(name, "r"); FILE *fp = _lua_fopen(name, "r");
const char *p = NULL; const char *p = NULL;
if (fp) { if (fp) {
char buf[256]; char buf[256];

46
src/lj_fopen.c Normal file
View File

@ -0,0 +1,46 @@
#include "lj_fopen.h"
/*
* Forces to look for unicode paths on Windows
*/
#ifdef _WIN32
#include <windows.h>
FILE *_lua_fopen(const char *filename, const char *mode)
{
int fn_len_s=strlen(filename);
if(fn_len_s==0) return NULL;
int m_len_s=strlen(mode);
if(m_len_s==0) return NULL;
wchar_t path[MAX_PATH];
wchar_t wmode[MAX_PATH];
int new_Len1 = MultiByteToWideChar(CP_UTF8, 0, filename, fn_len_s, path, fn_len_s);
if(new_Len1>=MAX_PATH) return NULL;
path[new_Len1] = L'\0';
int new_Len2 = MultiByteToWideChar(CP_UTF8, 0, mode, m_len_s, wmode, m_len_s);
if(new_Len2>=MAX_PATH) return NULL;
wmode[new_Len2] = L'\0';
FILE *f = _wfopen(path, wmode);
return f;
}
FILE *_lua_freopen(const char *filename, const char *mode, FILE * oldfile)
{
int fn_len_s=strlen(filename);
if(fn_len_s==0) return NULL;
int m_len_s=strlen(filename);
if(m_len_s==0) return NULL;
wchar_t path[MAX_PATH];
wchar_t wmode[MAX_PATH];
int new_Len1 = MultiByteToWideChar(CP_UTF8, 0, filename, fn_len_s, path, fn_len_s);
if(new_Len1>=MAX_PATH) return NULL;
path[new_Len1] = L'\0';
int new_Len2 = MultiByteToWideChar(CP_UTF8, 0, mode, m_len_s, wmode, m_len_s);
if(new_Len2>=MAX_PATH) return NULL;
wmode[new_Len2] = L'\0';
FILE *f = _wfreopen(path, wmode, oldfile);
LocalFree(path);
LocalFree(wmode);
return f;
}
#endif

14
src/lj_fopen.h Normal file
View File

@ -0,0 +1,14 @@
#ifndef LJ_FILE_OPEN_H
#define LJ_FILE_OPEN_H
#include <stdio.h>
#ifdef _WIN32
FILE *_lua_fopen(const char *filename, const char *mode);
FILE *_lua_freopen(const char *filename, const char *mode, FILE *oldfile);
#else
#define _lua_fopen(file, mode) fopen(file, mode)
#define _lua_freopen(file, mode, oldfile) freopen(file, mode, oldfile)
#endif
#endif // LJ_FILE_OPEN_H

View File

@ -22,6 +22,7 @@
#include "lj_lex.h" #include "lj_lex.h"
#include "lj_bcdump.h" #include "lj_bcdump.h"
#include "lj_parse.h" #include "lj_parse.h"
#include "lj_fopen.h"
/* -- Load Lua source code and bytecode ----------------------------------- */ /* -- Load Lua source code and bytecode ----------------------------------- */
@ -88,7 +89,7 @@ LUALIB_API int luaL_loadfilex(lua_State *L, const char *filename,
int status; int status;
const char *chunkname; const char *chunkname;
if (filename) { if (filename) {
ctx.fp = fopen(filename, "rb"); ctx.fp = _lua_fopen(filename, "rb");
if (ctx.fp == NULL) { if (ctx.fp == NULL) {
lua_pushfstring(L, "cannot open %s: %s", filename, strerror(errno)); lua_pushfstring(L, "cannot open %s: %s", filename, strerror(errno));
return LUA_ERRFILE; return LUA_ERRFILE;

View File

@ -30,6 +30,7 @@
#include "lj_vm.h" #include "lj_vm.h"
#include "lj_vmevent.h" #include "lj_vmevent.h"
#include "lj_target.h" #include "lj_target.h"
#include "lj_fopen.h"
/* -- Error handling ------------------------------------------------------ */ /* -- Error handling ------------------------------------------------------ */
@ -109,7 +110,7 @@ static void perftools_addtrace(GCtrace *T)
if (!fp) { if (!fp) {
char fname[40]; char fname[40];
sprintf(fname, "/tmp/perf-%d.map", getpid()); sprintf(fname, "/tmp/perf-%d.map", getpid());
if (!(fp = fopen(fname, "w"))) return; if (!(fp = _lua_fopen(fname, "w"))) return;
setlinebuf(fp); setlinebuf(fp);
} }
fprintf(fp, "%lx %x TRACE_%d::%s:%u\n", fprintf(fp, "%lx %x TRACE_%d::%s:%u\n",