aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuy Harris <guy@alum.mit.edu>2018-12-17 10:57:20 -0800
committerGuy Harris <guy@alum.mit.edu>2018-12-17 21:55:23 +0000
commit5953756305388724545f0df46d286be2f02c048a (patch)
tree092b7a2e0b064faa81c3c3ee7bb95ee0c302d4f4
parent0ba97f9a45614f18e71f1e5bb816c823c9a74c1c (diff)
Add routines to load Lua programs that assume the path is UTF-8 on Windows.
Add ws_dofile() and ws_loadfile(), which are like the substitute dofile() and loadfile() we provide, but that, on Windows, take a UTF-8 path rather than a path in the local code page. Use that to load console.lua. This means we can load console.lua on Windows even if the full path to it includes non-ASCII characters. Bug: 15118 Change-Id: Iaa00639563fe53a34e1e24e42022f3886a38e7c5 Reviewed-on: https://code.wireshark.org/review/31075 Petri-Dish: Guy Harris <guy@alum.mit.edu> Tested-by: Petri Dish Buildbot Reviewed-by: Guy Harris <guy@alum.mit.edu>
-rw-r--r--epan/wslua/template-init.lua6
-rw-r--r--epan/wslua/wslua_util.c162
2 files changed, 166 insertions, 2 deletions
diff --git a/epan/wslua/template-init.lua b/epan/wslua/template-init.lua
index a06f62265e..fe0ca3fe05 100644
--- a/epan/wslua/template-init.lua
+++ b/epan/wslua/template-init.lua
@@ -30,7 +30,9 @@ if running_superuser then
setmetatable(disabled_lib,{ __index = function() error("this package ".. hint) end } );
dofile = function() error("dofile " .. hint) end
+ ws_dofile = function() error("ws_dofile " .. hint) end
loadfile = function() error("loadfile " .. hint) end
+ ws_loadfile = function() error("ws_loadfile " .. hint) end
loadlib = function() error("loadlib " .. hint) end
require = function() error("require " .. hint) end
os = disabled_lib
@@ -130,5 +132,5 @@ datafile_path = Dir.global_config_path
persconffile_path = Dir.personal_config_path
-dofile(DATA_DIR.."console.lua")
---dofile(DATA_DIR.."dtd_gen.lua")
+ws_dofile(DATA_DIR.."console.lua")
+--ws_dofile(DATA_DIR.."dtd_gen.lua")
diff --git a/epan/wslua/wslua_util.c b/epan/wslua/wslua_util.c
index de30b5df81..69845024c1 100644
--- a/epan/wslua/wslua_util.c
+++ b/epan/wslua/wslua_util.c
@@ -17,6 +17,7 @@
#include "wslua.h"
#include <math.h>
#include <epan/stat_tap_ui.h>
+#include <wsutil/file_util.h>
WSLUA_FUNCTION wslua_get_version(lua_State* L) { /* Gets a string of the Wireshark version. */
@@ -218,6 +219,167 @@ WSLUA_FUNCTION wslua_dofile(lua_State* L) {
return lua_gettop(L) - n;
}
+/*
+ * These routines here are based on code from:
+ * lbaselib.c,v 1.276.1.1 2013/04/12 18:48:47 roberto
+ * lauxlib.c,v 1.248.1.1 2013/04/12 18:48:47 roberto
+ * See Copyright Notice in lua.h
+ *
+ * All we did was 1) rename luaL_loadfilex to loadfilex, 2) make it
+ * static, and 3) make it call ws_fopen() so that, on Windows, it takes
+ * a UTF-8 pathname, rather than a pathname in the local code page, as
+ * the file name argument.
+ */
+
+typedef struct LoadF {
+ int n; /* number of pre-read characters */
+ FILE *f; /* file being read */
+ char buff[LUAL_BUFFERSIZE]; /* area for reading file */
+} LoadF;
+
+static const char *getF(lua_State *L, void *ud, size_t *size) {
+ LoadF *lf = (LoadF *)ud;
+ (void)L; /* not used */
+ if (lf->n > 0) { /* are there pre-read characters to be read? */
+ *size = lf->n; /* return them (chars already in buffer) */
+ lf->n = 0; /* no more pre-read characters */
+ }
+ else { /* read a block from file */
+ /* 'fread' can return > 0 *and* set the EOF flag. If next call to
+ 'getF' called 'fread', it might still wait for user input.
+ The next check avoids this problem. */
+ if (feof(lf->f)) return NULL;
+ *size = fread(lf->buff, 1, sizeof(lf->buff), lf->f); /* read block */
+ }
+ return lf->buff;
+}
+
+static int errfile(lua_State *L, const char *what, int fnameindex) {
+ const char *serr = g_strerror(errno);
+ const char *filename = lua_tostring(L, fnameindex) + 1;
+ lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr);
+ lua_remove(L, fnameindex);
+ return LUA_ERRFILE;
+}
+
+static int skipBOM(LoadF *lf) {
+ const char *p = "\xEF\xBB\xBF"; /* Utf8 BOM mark */
+ int c;
+ lf->n = 0;
+ do {
+ c = getc(lf->f);
+ if (c == EOF || c != *(const unsigned char *)p++) return c;
+ lf->buff[lf->n++] = c; /* to be read by the parser */
+ } while (*p != '\0');
+ lf->n = 0; /* prefix matched; discard it */
+ return getc(lf->f); /* return next character */
+}
+
+/*
+** reads the first character of file 'f' and skips an optional BOM mark
+** in its beginning plus its first line if it starts with '#'. Returns
+** true if it skipped the first line. In any case, '*cp' has the
+** first "valid" character of the file (after the optional BOM and
+** a first-line comment).
+*/
+static int skipcomment(LoadF *lf, int *cp) {
+ int c = *cp = skipBOM(lf);
+ if (c == '#') { /* first line is a comment (Unix exec. file)? */
+ do { /* skip first line */
+ c = getc(lf->f);
+ } while (c != EOF && c != '\n') ;
+ *cp = getc(lf->f); /* skip end-of-line, if present */
+ return 1; /* there was a comment */
+ }
+ else return 0; /* no comment */
+}
+
+static int our_loadfilex(lua_State *L, const char *filename, const char *mode) {
+ LoadF lf;
+ int status, readstatus;
+ int c;
+ int fnameindex = lua_gettop(L) + 1; /* index of filename on the stack */
+ if (filename == NULL) {
+ lua_pushliteral(L, "=stdin");
+ lf.f = stdin;
+ }
+ else {
+ lua_pushfstring(L, "@%s", filename);
+ lf.f = ws_fopen(filename, "r");
+ if (lf.f == NULL) return errfile(L, "open", fnameindex);
+ }
+ if (skipcomment(&lf, &c)) /* read initial portion */
+ lf.buff[lf.n++] = '\n'; /* add line to correct line numbers */
+ if (c == LUA_SIGNATURE[0] && filename) { /* binary file? */
+ lf.f = ws_freopen(filename, "rb", lf.f); /* reopen in binary mode */
+ if (lf.f == NULL) return errfile(L, "reopen", fnameindex);
+ skipcomment(&lf, &c); /* re-read initial portion */
+ }
+ if (c != EOF)
+ lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */
+ status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode);
+ readstatus = ferror(lf.f);
+ if (filename) fclose(lf.f); /* close file (even in case of errors) */
+ if (readstatus) {
+ lua_settop(L, fnameindex); /* ignore results from `lua_load' */
+ return errfile(L, "read", fnameindex);
+ }
+ lua_remove(L, fnameindex);
+ return status;
+}
+
+#define our_loadfile(L,f) our_loadfilex(L,f,NULL)
+
+WSLUA_FUNCTION wslua_ws_loadfile(lua_State* L) {
+ /* This is like Lua's loadfile(), except that 1) if a file does not
+ exist in the current directory it will look for it in Wireshark's
+ user and system directories and 2) pathnames are, on Windows, treated
+ as UTF-8 strings rather than strings in the current code page. */
+#define WSLUA_ARG_loadfile_FILENAME 1 /* Name of the file to be loaded. */
+ const char *given_fname = luaL_checkstring(L, WSLUA_ARG_loadfile_FILENAME);
+ char* filename;
+
+ filename = wslua_get_actual_filename(given_fname);
+
+ if (!filename) {
+ WSLUA_ARG_ERROR(loadfile,FILENAME,"file does not exist");
+ return 0;
+ }
+
+ /* Use our loadfile, so that, on Windows, we handle UTF-8 file names. */
+ if (our_loadfile(L, filename) == 0) {
+ g_free(filename);
+ return 1;
+ } else {
+ g_free(filename);
+ lua_pushnil(L);
+ lua_insert(L, -2);
+ return 2;
+ }
+}
+
+WSLUA_FUNCTION wslua_ws_dofile(lua_State* L) {
+ /* This is like Lua's dofile(), except that 1) if a file does not
+ exist in the current directory it will look for it in Wireshark's
+ user and system directories and 2) pathnames are, on Windows, treated
+ as UTF-8 strings rather than strings in the current code page. */
+#define WSLUA_ARG_dofile_FILENAME 1 /* Name of the file to be run. */
+ const char *given_fname = luaL_checkstring(L, WSLUA_ARG_dofile_FILENAME);
+ char* filename = wslua_get_actual_filename(given_fname);
+ int n;
+
+ if (!filename) {
+ WSLUA_ARG_ERROR(dofile,FILENAME,"file does not exist");
+ return 0;
+ }
+
+ n = lua_gettop(L);
+ /* Use our loadfile, so that, on Windows, we handle UTF-8 file names. */
+ if (our_loadfile(L, filename) != 0) lua_error(L);
+ g_free(filename);
+ lua_call(L, 0, LUA_MULTRET);
+ return lua_gettop(L) - n;
+}
typedef struct _statcmd_t {
lua_State* L;