diff options
author | Hadriel Kaplan <hadrielk@yahoo.com> | 2014-03-26 02:24:51 -0400 |
---|---|---|
committer | Anders Broman <a.broman58@gmail.com> | 2014-03-26 07:37:34 +0000 |
commit | 8c2bb805742c918b933923947a533d098774da75 (patch) | |
tree | b3859068c4fdd09bd26ab01168835a042715644b | |
parent | da1af6e549856c8e213dadc1ec37a41a50246e1d (diff) |
Add various functions for Lua directory handling and path info
This adds new functions to get plugins path info, find out if a directory
exists, make a new one, remove one, etc. It also creates a file environment
for user-supplied Lua scripts, to prevent global variable contamination as
well as supply the script-specific file name. Some other minor cleanup was
done as I found them.
A new testsuite was added to test the existing and new directory functions.
Change-Id: I19bd587b5e8a73d89b8521af73670e023314fb33
Reviewed-on: https://code.wireshark.org/review/832
Reviewed-by: Anders Broman <a.broman58@gmail.com>
-rw-r--r-- | docbook/CMakeLists.txt | 1 | ||||
-rw-r--r-- | docbook/Makefile.common | 1 | ||||
-rw-r--r-- | docbook/user-guide.xml | 1 | ||||
-rw-r--r-- | docbook/wsluarm.xml | 1 | ||||
-rw-r--r-- | epan/wslua/CMakeLists.txt | 1 | ||||
-rw-r--r-- | epan/wslua/Makefile.am | 2 | ||||
-rw-r--r-- | epan/wslua/Makefile.nmake | 2 | ||||
-rw-r--r-- | epan/wslua/init_wslua.c | 65 | ||||
-rw-r--r-- | epan/wslua/template-init.lua | 9 | ||||
-rw-r--r-- | epan/wslua/wslua.h | 2 | ||||
-rw-r--r-- | epan/wslua/wslua_dir.c | 383 | ||||
-rw-r--r-- | epan/wslua/wslua_file.c | 16 | ||||
-rw-r--r-- | epan/wslua/wslua_int64.c | 8 | ||||
-rw-r--r-- | epan/wslua/wslua_util.c | 174 | ||||
-rw-r--r-- | test/lua/dir.lua | 202 | ||||
-rwxr-xr-x | test/suite-wslua.sh | 17 |
16 files changed, 688 insertions, 197 deletions
diff --git a/docbook/CMakeLists.txt b/docbook/CMakeLists.txt index e03076f5aa..2fb6818720 100644 --- a/docbook/CMakeLists.txt +++ b/docbook/CMakeLists.txt @@ -310,6 +310,7 @@ set(WSLUA_MODULES ${CMAKE_SOURCE_DIR}/epan/wslua/wslua_tree.c ${CMAKE_SOURCE_DIR}/epan/wslua/wslua_tvb.c ${CMAKE_SOURCE_DIR}/epan/wslua/wslua_file.c + ${CMAKE_SOURCE_DIR}/epan/wslua/wslua_dir.c ${CMAKE_SOURCE_DIR}/epan/wslua/wslua_util.c ${CMAKE_SOURCE_DIR}/epan/wslua/wslua_struct.c ) diff --git a/docbook/Makefile.common b/docbook/Makefile.common index d0056cc3e3..23b5eae27d 100644 --- a/docbook/Makefile.common +++ b/docbook/Makefile.common @@ -255,4 +255,5 @@ WSLUA_MODULES = \ ../epan/wslua/wslua_tree.c \ ../epan/wslua/wslua_tvb.c \ ../epan/wslua/wslua_file.c \ + ../epan/wslua/wslua_dir.c \ ../epan/wslua/wslua_util.c diff --git a/docbook/user-guide.xml b/docbook/user-guide.xml index 5d5e2548c6..b2555e3bca 100644 --- a/docbook/user-guide.xml +++ b/docbook/user-guide.xml @@ -347,6 +347,7 @@ WSLua Reference Manual <!ENTITY WsLuaTree SYSTEM "wsluarm_src/wslua_tree.xml"> <!ENTITY WsLuaTvb SYSTEM "wsluarm_src/wslua_tvb.xml"> <!ENTITY WsLuaFile SYSTEM "wsluarm_src/wslua_file.xml"> + <!ENTITY WsLuaDir SYSTEM "wsluarm_src/wslua_dir.xml"> <!ENTITY WsLuaUtility SYSTEM "wsluarm_src/wslua_util.xml"> <!ENTITY WsLuaInt64 SYSTEM "wsluarm_src/wslua_int64.xml"> <!ENTITY WsLuaStruct SYSTEM "wsluarm_src/wslua_struct.xml"> diff --git a/docbook/wsluarm.xml b/docbook/wsluarm.xml index fdcae10a1f..2e22d4e280 100644 --- a/docbook/wsluarm.xml +++ b/docbook/wsluarm.xml @@ -169,6 +169,7 @@ register_menu("Test/Packets", menuable_tap, MENU_TOOLS_UNSORTED)</programlisting &WsLuaTree; &WsLuaTvb; &WsLuaFile; + &WsLuaDir; &WsLuaUtility; &WsLuaInt64; &WsLuaStruct; diff --git a/epan/wslua/CMakeLists.txt b/epan/wslua/CMakeLists.txt index ca5dfa3fb9..a9c676ef6b 100644 --- a/epan/wslua/CMakeLists.txt +++ b/epan/wslua/CMakeLists.txt @@ -35,6 +35,7 @@ set(WSLUA_MODULES ${CMAKE_CURRENT_SOURCE_DIR}/wslua/wslua_pinfo.c ${CMAKE_CURRENT_SOURCE_DIR}/wslua/wslua_listener.c ${CMAKE_CURRENT_SOURCE_DIR}/wslua/wslua_gui.c + ${CMAKE_CURRENT_SOURCE_DIR}/wslua/wslua_dir.c ${CMAKE_CURRENT_SOURCE_DIR}/wslua/wslua_util.c ${CMAKE_CURRENT_SOURCE_DIR}/wslua/wslua_field.c ${CMAKE_CURRENT_SOURCE_DIR}/wslua/wslua_file.c diff --git a/epan/wslua/Makefile.am b/epan/wslua/Makefile.am index 96c455e2dc..27dd367e6f 100644 --- a/epan/wslua/Makefile.am +++ b/epan/wslua/Makefile.am @@ -41,6 +41,7 @@ wslua_modules = \ $(srcdir)/wslua_pinfo.c \ $(srcdir)/wslua_listener.c \ $(srcdir)/wslua_gui.c \ + $(srcdir)/wslua_dir.c \ $(srcdir)/wslua_util.c \ $(srcdir)/wslua_field.c \ $(srcdir)/wslua_file.c \ @@ -144,4 +145,5 @@ checkapi: wslua_tree.c \ wslua_tree.c \ wslua_tvb.c \ + wslua_dir.c \ wslua_util.c diff --git a/epan/wslua/Makefile.nmake b/epan/wslua/Makefile.nmake index dc672efe47..b8b96cdf5c 100644 --- a/epan/wslua/Makefile.nmake +++ b/epan/wslua/Makefile.nmake @@ -26,6 +26,7 @@ MODULES = \ wslua_pinfo.c \ wslua_listener.c \ wslua_gui.c \ + wslua_dir.c \ wslua_util.c \ wslua_field.c \ wslua_file.c \ @@ -48,6 +49,7 @@ OBJECTS= \ wslua_pinfo.obj \ wslua_listener.obj \ wslua_gui.obj \ + wslua_dir.obj \ wslua_util.obj \ wslua_field.obj \ wslua_file.obj \ diff --git a/epan/wslua/init_wslua.c b/epan/wslua/init_wslua.c index 4ce2780520..fb1e2e15c7 100644 --- a/epan/wslua/init_wslua.c +++ b/epan/wslua/init_wslua.c @@ -411,10 +411,42 @@ static int lua_script_push_args(const int script_num) { return count; } +#define FILE_NAME_KEY "__FILE__" +#define DIR_NAME_KEY "__DIR__" +/* assumes a loaded chunk's function is on top of stack */ +static void set_file_environment(const gchar* filename, const gchar* dirname) { + lua_newtable(L); /* environment for script (index 3) */ + + lua_pushstring(L, filename); /* tell the script about its filename */ + lua_setfield(L, -2, FILE_NAME_KEY); /* make it accessible at __FILE__ */ + + lua_pushstring(L, dirname); /* tell the script about its dirname */ + lua_setfield(L, -2, DIR_NAME_KEY); /* make it accessible at __DIR__ */ + + lua_newtable(L); /* metatable */ + +#if LUA_VERSION_NUM >= 502 + lua_pushglobaltable(L); +#else + lua_pushvalue(L, LUA_GLOBALSINDEX); +#endif + lua_setfield(L, -2, "__index"); /* __index points to global environment */ + + lua_setmetatable(L, -2); /* pop metatable, set it as metatable of environment */ + +#if LUA_VERSION_NUM >= 502 + lua_setupvalue(L, -2, 1); /* pop environment and assign it to upvalue 1 */ +#else + lua_setfenv(L, -2); /* pop environment and set it as the func's environment */ +#endif +} + /* If file_count > 0 then it's a command-line-added user script, and the count * represents which user script it is (first=1, second=2, etc.). + * If dirname != NULL, then it's a user script and the dirname will get put in a file environment + * If dirname == NULL then it's a wireshark script and no file environment is created */ -static gboolean lua_load_script(const gchar* filename, const int file_count) { +static gboolean lua_load_script(const gchar* filename, const gchar* dirname, const int file_count) { FILE* file; int error; int numargs = 0; @@ -433,8 +465,12 @@ static gboolean lua_load_script(const gchar* filename, const int file_count) { #else error = lua_load(L,getF,file,filename); #endif + switch (error) { case 0: + if (dirname) { + set_file_environment(filename, dirname); + } if (file_count > 0) { numargs = lua_script_push_args(file_count); } @@ -471,7 +507,9 @@ static int wslua_panic(lua_State* LS) { return 0; /* keep gcc happy */ } -static int lua_load_plugins(const char *dirname, register_cb cb, gpointer client_data, gboolean count_only) { +static int lua_load_plugins(const char *dirname, register_cb cb, gpointer client_data, + gboolean count_only, const gboolean is_user) +{ WS_DIR *dir; /* scanned directory */ WS_DIRENT *file; /* current file */ gchar *filename, *dot; @@ -487,7 +525,7 @@ static int lua_load_plugins(const char *dirname, register_cb cb, gpointer client filename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "%s", dirname, name); if (test_for_directory(filename) == EISDIR) { - plugins_counter += lua_load_plugins(filename, cb, client_data, count_only); + plugins_counter += lua_load_plugins(filename, cb, client_data, count_only, is_user); g_free(filename); continue; } @@ -509,7 +547,7 @@ static int lua_load_plugins(const char *dirname, register_cb cb, gpointer client if (!count_only) { if (cb) (*cb)(RA_LUA_PLUGINS, name, client_data); - if (lua_load_script(filename,0)) { + if (lua_load_script(filename, is_user ? dirname : NULL, 0)) { wslua_add_plugin(g_strdup(name), g_strdup(""), g_strdup(filename)); } } @@ -528,7 +566,7 @@ int wslua_count_plugins(void) { int plugins_counter; /* count global scripts */ - plugins_counter = lua_load_plugins(get_plugin_dir(), NULL, NULL, TRUE); + plugins_counter = lua_load_plugins(get_plugin_dir(), NULL, NULL, TRUE, FALSE); /* count users init.lua */ filename = get_persconffile_path("init.lua", FALSE); @@ -539,7 +577,7 @@ int wslua_count_plugins(void) { /* count user scripts */ filename = get_plugins_pers_dir(); - plugins_counter += lua_load_plugins(filename, NULL, NULL, TRUE); + plugins_counter += lua_load_plugins(filename, NULL, NULL, TRUE, TRUE); g_free(filename); /* count scripts from command line */ @@ -734,7 +772,7 @@ int wslua_init(register_cb cb, gpointer client_data) { } if (( file_exists(filename))) { - lua_load_script(filename,0); + lua_load_script(filename, NULL, 0); } g_free(filename); @@ -752,7 +790,7 @@ int wslua_init(register_cb cb, gpointer client_data) { lua_pop(L,1); /* pop the getglobal result */ /* load global scripts */ - lua_load_plugins(get_plugin_dir(), cb, client_data, FALSE); + lua_load_plugins(get_plugin_dir(), cb, client_data, FALSE, FALSE); /* check whether we should run other scripts even if running superuser */ lua_getglobal(L,"run_user_scripts_when_superuser"); @@ -769,21 +807,26 @@ int wslua_init(register_cb cb, gpointer client_data) { if ((file_exists(filename))) { if (cb) (*cb)(RA_LUA_PLUGINS, get_basename(filename), client_data); - lua_load_script(filename,0); + lua_load_script(filename, NULL, 0); } g_free(filename); /* load user scripts */ filename = get_plugins_pers_dir(); - lua_load_plugins(filename, cb, client_data, FALSE); + lua_load_plugins(filename, cb, client_data, FALSE, TRUE); g_free(filename); /* load scripts from command line */ while((script_filename = ex_opt_get_next("lua_script"))) { + char* dirname = g_strdup(script_filename); + char* dname = get_dirname(dirname); + if (cb) (*cb)(RA_LUA_PLUGINS, get_basename(script_filename), client_data); - lua_load_script(script_filename,file_count); + + lua_load_script(script_filename, dname ? dname : "", file_count); file_count++; + g_free(dirname); } } diff --git a/epan/wslua/template-init.lua b/epan/wslua/template-init.lua index 0a9ad0d00d..2f99159b07 100644 --- a/epan/wslua/template-init.lua +++ b/epan/wslua/template-init.lua @@ -94,8 +94,13 @@ end -- other useful constants GUI_ENABLED = gui_enabled() -DATA_DIR = datafile_path() -USER_DIR = persconffile_path() +DATA_DIR = Dir.global_config_path() +USER_DIR = Dir.personal_config_path() + +-- deprecated function names +datafile_path = Dir.global_config_path +persconffile_path = Dir.personal_config_path + dofile(DATA_DIR.."console.lua") --dofile(DATA_DIR.."dtd_gen.lua") diff --git a/epan/wslua/wslua.h b/epan/wslua/wslua.h index d8a2606239..1ec3087233 100644 --- a/epan/wslua/wslua.h +++ b/epan/wslua/wslua.h @@ -714,6 +714,8 @@ extern int wslua_set_tap_enums(lua_State* L); extern int wslua_is_field_available(lua_State* L, const char* field_abbr); +extern char* wslua_get_actual_filename(const char* fname); + extern int wslua_bin2hex(lua_State* L, const guint8* data, const guint len, const gboolean lowercase, const gchar* sep); extern int wslua_hex2bin(lua_State* L, const char* data, const guint len, const gchar* sep); extern int luaopen_rex_glib(lua_State *L); diff --git a/epan/wslua/wslua_dir.c b/epan/wslua/wslua_dir.c new file mode 100644 index 0000000000..d39484df48 --- /dev/null +++ b/epan/wslua/wslua_dir.c @@ -0,0 +1,383 @@ +/* + * wslua_dir.c + * + * (c) 2014, Hadriel Kaplan <hadrielk at yahoo dot com> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include "config.h" + +/* WSLUA_MODULE Dir Directory handling functions */ + +#include "wslua.h" +#include <wsutil/file_util.h> + +WSLUA_CLASS_DEFINE(Dir,FAIL_ON_NULL("Dir"),NOP); /* A Directory object, as well as associated functions. */ + +WSLUA_CONSTRUCTOR Dir_make(lua_State* L) { + /* Creates a directory. + + The created directory is set for permission mode 0755 (octal), meaning it is + read+write+execute by owner, but only read+execute by group and others. + + IF the directory was created successfully, a boolean `true` is returned. + If the directory cannot be made because it already exists, `false` is returned. + If the directory cannot be made because an error occurred, `nil` is returned. + + @since 1.11.3 + */ +#define WSLUA_ARG_Dir_make_NAME 1 /* The name of the directory, possibly including path. */ + + const char *dir_path = luaL_checkstring(L, WSLUA_ARG_Dir_make_NAME); + ws_statb64 s_buf; + int ret; + + if (ws_stat64(dir_path, &s_buf) != 0 && errno == ENOENT) { + ret = ws_mkdir(dir_path, 0755); + if (ret == -1) { + lua_pushnil(L); + } else { + lua_pushboolean(L, 1); + } + } else { + lua_pushboolean(L, 0); + } + + WSLUA_RETURN(1); /* Boolean `true` on success, `false` if already exists, `nil` on error. */ +} + +WSLUA_CONSTRUCTOR Dir_exists(lua_State* L) { + /* Returns true if the given directory name exists. + + If the directory exists, a boolean `true` is returned. + If the path is a file instead, `false` is returned. + If the path does not exist or an error occurred, `nil` is returned. + + @since 1.11.3 + */ +#define WSLUA_ARG_Dir_exists_NAME 1 /* The name of the directory, possibly including path. */ + + const char *dir_path = luaL_checkstring(L, WSLUA_ARG_Dir_exists_NAME); + int ret; + + if ((ret = test_for_directory (dir_path)) == EISDIR) { + lua_pushboolean(L, 1); + } else { + if (ret == 0) { + lua_pushboolean(L, 0); + } else { + lua_pushnil(L); + } + } + + WSLUA_RETURN(1); /* Boolean `true` if the directory exists, `false` if it's a file, `nil` on error/not-exist. */ +} + +WSLUA_CONSTRUCTOR Dir_remove(lua_State* L) { + /* Removes an empty directory. + + If the directory was removed successfully, a boolean `true` is returned. + If the directory cannot be removed because it does not exist, `false` is returned. + If the directory cannot be removed because an error occurred, `nil` is returned. + + This function only removes empty directories. To remove a directory regardless, + use `Dir.remove_all()`. + + @since 1.11.3 + */ +#define WSLUA_ARG_Dir_remove_NAME 1 /* The name of the directory, possibly including path. */ + + const char *dir_path = luaL_checkstring(L, WSLUA_ARG_Dir_remove_NAME); + int ret; + + if (test_for_directory (dir_path) == EISDIR) { + ret = ws_remove(dir_path); + if (ret != 0) { + lua_pushnil(L); + } else { + lua_pushboolean(L, 1); + } + } else { + lua_pushboolean(L, 0); + } + + WSLUA_RETURN(1); /* Boolean `true` on success, `false` if does not exist, `nil` on error. */ +} + +static int delete_directory(const char *directory) { + WS_DIR *dir; + WS_DIRENT *file; + gchar *filename; + int ret = 0; + + /* delete all contents of directory */ + if ((dir = ws_dir_open(directory, 0, NULL)) != NULL) { + while ((file = ws_dir_read_name(dir)) != NULL) { + filename = g_strdup_printf ("%s%s%s", directory, G_DIR_SEPARATOR_S, + ws_dir_get_name(file)); + if (test_for_directory(filename) != EISDIR) { + ret = ws_remove(filename); + } else { + /* recurse */ + ret = delete_directory (filename); + } + if (ret != 0) { + break; + } + g_free (filename); + } + ws_dir_close(dir); + } + + if (ret == 0) { + ret = ws_remove(directory); + } + + return ret; +} + + +WSLUA_CONSTRUCTOR Dir_remove_all(lua_State* L) { + /* Removes an empty or non-empty directory. + + If the directory was removed successfully, a boolean `true` is returned. + If the directory cannot be removed because it does not exist, `false` is returned. + If the directory cannot be removed because an error occurred, `nil` is returned. + + @since 1.11.3 + */ +#define WSLUA_ARG_Dir_remove_all_NAME 1 /* The name of the directory, possibly including path. */ + + const char *dir_path = luaL_checkstring(L, WSLUA_ARG_Dir_remove_all_NAME); + int ret; + + if (test_for_directory (dir_path) == EISDIR) { + ret = delete_directory(dir_path); + if (ret != 0) { + lua_pushnil(L); + } else { + lua_pushboolean(L, 1); + } + } else { + lua_pushboolean(L, 0); + } + + WSLUA_RETURN(1); /* Boolean `true` on success, `false` if does not exist, `nil` on error. */ +} + +WSLUA_CONSTRUCTOR Dir_open(lua_State* L) { + /* Opens a directory and returns a `Dir` object representing the files in the directory. + + @code for filename in Dir.open(path) do ... end @endcode + */ +#define WSLUA_ARG_Dir_open_PATHNAME 1 /* The pathname of the directory. */ +#define WSLUA_OPTARG_Dir_open_EXTENSION 2 /* If given, only files with this extension will be returned. */ + + const char* dirname = luaL_checkstring(L,WSLUA_ARG_Dir_open_PATHNAME); + const char* extension = luaL_optstring(L,WSLUA_OPTARG_Dir_open_EXTENSION,NULL); + Dir dir; + char* dirname_clean; + + if (!dirname) { + WSLUA_ARG_ERROR(Dir_open,PATHNAME,"must be a string"); + return 0; + } + + dirname_clean = wslua_get_actual_filename(dirname); + if (!dirname_clean) { + WSLUA_ARG_ERROR(Dir_open,PATHNAME,"directory does not exist"); + return 0; + } + + if (!test_for_directory(dirname_clean)) { + g_free(dirname_clean); + WSLUA_ARG_ERROR(Dir_open,PATHNAME, "must be a directory"); + return 0; + } + + dir = (Dir)g_malloc(sizeof(struct _wslua_dir)); + dir->dir = g_dir_open(dirname_clean, 0, dir->dummy); + g_free(dirname_clean); + dir->ext = extension ? g_strdup(extension) : NULL; + dir->dummy = (GError **)g_malloc(sizeof(GError *)); + *(dir->dummy) = NULL; + + if (dir->dir == NULL) { + g_free(dir->dummy); + g_free(dir); + + WSLUA_ARG_ERROR(Dir_open,PATHNAME,"could not open directory"); + return 0; + } + + pushDir(L,dir); + WSLUA_RETURN(1); /* the `Dir` object. */ +} + +WSLUA_METAMETHOD Dir__call(lua_State* L) { + /* At every invocation will return one file (nil when done). */ + + Dir dir = checkDir(L,1); + const gchar* file; + const gchar* filename; + const char* ext; + + if (!dir->dir) { + return 0; + } + + if ( ! ( file = g_dir_read_name(dir->dir ) )) { + g_dir_close(dir->dir); + dir->dir = NULL; + return 0; + } + + + if ( ! dir->ext ) { + lua_pushstring(L,file); + return 1; + } + + do { + filename = file; + + /* XXX strstr returns ptr to first match, + this fails ext=".xxx" filename="aaa.xxxz.xxx" */ + if ( ( ext = strstr(filename,dir->ext)) && g_str_equal(ext,dir->ext) ) { + lua_pushstring(L,filename); + return 1; + } + } while(( file = g_dir_read_name(dir->dir) )); + + g_dir_close(dir->dir); + dir->dir = NULL; + return 0; +} + +WSLUA_METHOD Dir_close(lua_State* L) { + /* Closes the directory. */ + Dir dir = checkDir(L,1); + + if (dir->dir) { + g_dir_close(dir->dir); + dir->dir = NULL; + } + + return 0; +} + +WSLUA_CONSTRUCTOR Dir_personal_config_path(lua_State* L) { + /* Gets the personal configuration directory path, with filename if supplied. + + @since 1.11.3 + */ +#define WSLUA_OPTARG_personal_config_path_FILENAME 1 /* A filename. */ + const char *fname = luaL_optstring(L, WSLUA_OPTARG_personal_config_path_FILENAME,""); + char* filename = get_persconffile_path(fname,FALSE); + + lua_pushstring(L,filename); + g_free(filename); + WSLUA_RETURN(1); /* The full pathname for a file in the personal configuration directory. */ +} + +WSLUA_CONSTRUCTOR Dir_global_config_path(lua_State* L) { + /* Gets the global configuration directory path, with filename if supplied. + + @since 1.11.3 + */ +#define WSLUA_OPTARG_global_config_path_FILENAME 1 /* A filename */ + const char *fname = luaL_optstring(L, WSLUA_OPTARG_global_config_path_FILENAME,""); + char* filename; + + if (running_in_build_directory()) { + /* Running in build directory, set datafile_path to wslua source directory */ + filename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "epan" G_DIR_SEPARATOR_S "wslua" + G_DIR_SEPARATOR_S "%s", get_datafile_dir(), fname); + } else { + filename = get_datafile_path(fname); + } + + lua_pushstring(L,filename); + g_free(filename); + WSLUA_RETURN(1); /* The full pathname for a file in wireshark's configuration directory. */ +} + +WSLUA_CONSTRUCTOR Dir_personal_plugins_path(lua_State* L) { + /* Gets the personal plugins directory path. + + @since 1.11.3 + */ + char* filename = get_plugins_pers_dir(); + lua_pushstring(L,filename); + g_free(filename); + WSLUA_RETURN(1); /* The pathname for the personal plugins directory. */ +} + +WSLUA_CONSTRUCTOR Dir_global_plugins_path(lua_State* L) { + /* Gets the global plugins directory path. + + @since 1.11.3 + */ + lua_pushstring(L, get_plugin_dir()); + WSLUA_RETURN(1); /* The pathname for the global plugins directory. */ +} + +/* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */ +static int Dir__gc(lua_State* L) { + Dir dir = toDir(L,1); + + if(!dir) return 0; + + if (dir->dir) { + g_dir_close(dir->dir); + } + + g_free(dir->dummy); + + if (dir->ext) g_free(dir->ext); + + g_free(dir); + + return 0; +} + +WSLUA_METHODS Dir_methods[] = { + WSLUA_CLASS_FNREG(Dir,make), + WSLUA_CLASS_FNREG(Dir,exists), + WSLUA_CLASS_FNREG(Dir,remove), + WSLUA_CLASS_FNREG(Dir,remove_all), + WSLUA_CLASS_FNREG(Dir,open), + WSLUA_CLASS_FNREG(Dir,close), + WSLUA_CLASS_FNREG(Dir,personal_config_path), + WSLUA_CLASS_FNREG(Dir,global_config_path), + WSLUA_CLASS_FNREG(Dir,personal_plugins_path), + WSLUA_CLASS_FNREG(Dir,global_plugins_path), + { NULL, NULL } +}; + +WSLUA_META Dir_meta[] = { + WSLUA_CLASS_MTREG(Dir,call), + { NULL, NULL } +}; + +int Dir_register(lua_State* L) { + WSLUA_REGISTER_CLASS(Dir); + return 0; +} diff --git a/epan/wslua/wslua_file.c b/epan/wslua/wslua_file.c index 6149a8e043..15a7990778 100644 --- a/epan/wslua/wslua_file.c +++ b/epan/wslua/wslua_file.c @@ -938,7 +938,7 @@ WSLUA_ATTRIBUTES CaptureInfo_attributes[] = { }; WSLUA_META CaptureInfo_meta[] = { - {"__tostring", CaptureInfo__tostring}, + WSLUA_CLASS_MTREG(CaptureInfo,tostring), { NULL, NULL } }; @@ -1138,7 +1138,7 @@ WSLUA_ATTRIBUTES CaptureInfoConst_attributes[] = { }; WSLUA_META CaptureInfoConst_meta[] = { - {"__tostring", CaptureInfoConst__tostring}, + WSLUA_CLASS_MTREG(CaptureInfoConst,tostring), { NULL, NULL } }; @@ -1353,12 +1353,12 @@ WSLUA_ATTRIBUTES FrameInfo_attributes[] = { }; WSLUA_METHODS FrameInfo_methods[] = { - {"read_data", FrameInfo_read_data}, + WSLUA_CLASS_FNREG(FrameInfo,read_data), { NULL, NULL } }; WSLUA_META FrameInfo_meta[] = { - {"__tostring", FrameInfo__tostring}, + WSLUA_CLASS_MTREG(FrameInfo,tostring), { NULL, NULL } }; @@ -1495,12 +1495,12 @@ WSLUA_ATTRIBUTES FrameInfoConst_attributes[] = { }; WSLUA_METHODS FrameInfoConst_methods[] = { - {"write_data", FrameInfoConst_write_data}, + WSLUA_CLASS_FNREG(FrameInfoConst,write_data), { NULL, NULL } }; WSLUA_META FrameInfoConst_meta[] = { - {"__tostring", FrameInfoConst__tostring}, + WSLUA_CLASS_MTREG(FrameInfoConst,tostring), { NULL, NULL } }; @@ -2420,12 +2420,12 @@ WSLUA_ATTRIBUTES FileHandler_attributes[] = { }; WSLUA_METHODS FileHandler_methods[] = { - {"new", FileHandler_new}, + WSLUA_CLASS_FNREG(FileHandler,new), { NULL, NULL } }; WSLUA_META FileHandler_meta[] = { - {"__tostring", FileHandler__tostring}, + WSLUA_CLASS_MTREG(FileHandler,tostring), { NULL, NULL } }; diff --git a/epan/wslua/wslua_int64.c b/epan/wslua/wslua_int64.c index ace9280659..d222eee85c 100644 --- a/epan/wslua/wslua_int64.c +++ b/epan/wslua/wslua_int64.c @@ -557,7 +557,7 @@ static int Int64__gc(lua_State* L _U_) { return 0; } -static const luaL_Reg Int64_methods[] = { +WSLUA_METHODS Int64_methods[] = { WSLUA_CLASS_FNREG(Int64,new), WSLUA_CLASS_FNREG(Int64,max), WSLUA_CLASS_FNREG(Int64,min), @@ -581,7 +581,7 @@ static const luaL_Reg Int64_methods[] = { { NULL, NULL } }; -static const luaL_Reg Int64_meta[] = { +WSLUA_META Int64_meta[] = { WSLUA_CLASS_MTREG(Int64,tostring), WSLUA_CLASS_MTREG(Int64,call), WSLUA_CLASS_MTREG(wslua,concat), @@ -1076,7 +1076,7 @@ static int UInt64__gc(lua_State* L _U_) { return 0; } -static const luaL_Reg UInt64_methods[] = { +WSLUA_METHODS UInt64_methods[] = { WSLUA_CLASS_FNREG(UInt64,new), WSLUA_CLASS_FNREG(UInt64,max), WSLUA_CLASS_FNREG(UInt64,min), @@ -1100,7 +1100,7 @@ static const luaL_Reg UInt64_methods[] = { { NULL, NULL } }; -static const luaL_Reg UInt64_meta[] = { +WSLUA_META UInt64_meta[] = { WSLUA_CLASS_MTREG(UInt64,tostring), WSLUA_CLASS_MTREG(UInt64,call), WSLUA_CLASS_MTREG(wslua,concat), diff --git a/epan/wslua/wslua_util.c b/epan/wslua/wslua_util.c index c9098aa980..77d264cc58 100644 --- a/epan/wslua/wslua_util.c +++ b/epan/wslua/wslua_util.c @@ -127,7 +127,7 @@ WSLUA_FUNCTION wslua_debug( lua_State* L ) { /* Will add a log entry with debug /* The returned filename is g_malloc()'d so the caller must free it */ /* except when NULL is returned if file doesn't exist */ -static char* wslua_get_actual_filename(const char* fname) { +char* wslua_get_actual_filename(const char* fname) { char fname_clean[256]; char* f; char* filename; @@ -228,176 +228,6 @@ WSLUA_FUNCTION wslua_dofile(lua_State* L) { } -WSLUA_FUNCTION wslua_persconffile_path(lua_State* L) { -#define WSLUA_OPTARG_persconffile_path_FILENAME 1 /* A filename. */ - const char *fname = luaL_optstring(L, WSLUA_OPTARG_persconffile_path_FILENAME,""); - char* filename = get_persconffile_path(fname,FALSE); - - lua_pushstring(L,filename); - g_free(filename); - WSLUA_RETURN(1); /* The full pathname for a file in the personal configuration directory. */ -} - -WSLUA_FUNCTION wslua_datafile_path(lua_State* L) { -#define WSLUA_OPTARG_datafile_path_FILENAME 1 /* A filename */ - const char *fname = luaL_optstring(L, WSLUA_OPTARG_datafile_path_FILENAME,""); - char* filename; - - if (running_in_build_directory()) { - /* Running in build directory, set datafile_path to wslua source directory */ - filename = g_strdup_printf("%s" G_DIR_SEPARATOR_S "epan" G_DIR_SEPARATOR_S "wslua" - G_DIR_SEPARATOR_S "%s", get_datafile_dir(), fname); - } else { - filename = get_datafile_path(fname); - } - - lua_pushstring(L,filename); - g_free(filename); - WSLUA_RETURN(1); /* The full pathname for a file in wireshark's configuration directory. */ -} - - -WSLUA_CLASS_DEFINE(Dir,FAIL_ON_NULL("Dir"),NOP); /* A Directory */ - -WSLUA_CONSTRUCTOR Dir_open(lua_State* L) { - /* Opens a directory and returns a `Dir` object representing the files in the directory. - - @code for filename in Dir.open(path) do ... end @endcode - */ -#define WSLUA_ARG_Dir_open_PATHNAME 1 /* The pathname of the directory. */ -#define WSLUA_OPTARG_Dir_open_EXTENSION 2 /* If given, only files with this extension will be returned. */ - - const char* dirname = luaL_checkstring(L,WSLUA_ARG_Dir_open_PATHNAME); - const char* extension = luaL_optstring(L,WSLUA_OPTARG_Dir_open_EXTENSION,NULL); - Dir dir; - char* dirname_clean; - - if (!dirname) { - WSLUA_ARG_ERROR(Dir_open,PATHNAME,"must be a string"); - return 0; - } - - dirname_clean = wslua_get_actual_filename(dirname); - if (!dirname_clean) { - WSLUA_ARG_ERROR(Dir_open,PATHNAME,"directory does not exist"); - return 0; - } - - if (!test_for_directory(dirname_clean)) { - g_free(dirname_clean); - WSLUA_ARG_ERROR(Dir_open,PATHNAME, "must be a directory"); - return 0; - } - - dir = (Dir)g_malloc(sizeof(struct _wslua_dir)); - dir->dir = g_dir_open(dirname_clean, 0, dir->dummy); - g_free(dirname_clean); - dir->ext = extension ? g_strdup(extension) : NULL; - dir->dummy = (GError **)g_malloc(sizeof(GError *)); - *(dir->dummy) = NULL; - - if (dir->dir == NULL) { - g_free(dir->dummy); - g_free(dir); - - WSLUA_ARG_ERROR(Dir_open,PATHNAME,"could not open directory"); - return 0; - } - - pushDir(L,dir); - WSLUA_RETURN(1); /* the `Dir` object. */ -} - -WSLUA_METAMETHOD Dir__call(lua_State* L) { - /* At every invocation will return one file (nil when done). */ - - Dir dir = checkDir(L,1); - const gchar* file; - const gchar* filename; - const char* ext; - - if (!dir->dir) { - return 0; - } - - if ( ! ( file = g_dir_read_name(dir->dir ) )) { - g_dir_close(dir->dir); - dir->dir = NULL; - return 0; - } - - - if ( ! dir->ext ) { - lua_pushstring(L,file); - return 1; - } - - do { - filename = file; - - /* XXX strstr returns ptr to first match, - this fails ext=".xxx" filename="aaa.xxxz.xxx" */ - if ( ( ext = strstr(filename,dir->ext)) && g_str_equal(ext,dir->ext) ) { - lua_pushstring(L,filename); - return 1; - } - } while(( file = g_dir_read_name(dir->dir) )); - - g_dir_close(dir->dir); - dir->dir = NULL; - return 0; -} - -WSLUA_METHOD Dir_close(lua_State* L) { - /* Closes the directory. */ - Dir dir = checkDir(L,1); - - if (dir->dir) { - g_dir_close(dir->dir); - dir->dir = NULL; - } - - return 0; -} - -/* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */ -static int Dir__gc(lua_State* L) { - Dir dir = toDir(L,1); - - if(!dir) return 0; - - if (dir->dir) { - g_dir_close(dir->dir); - } - - g_free(dir->dummy); - - if (dir->ext) g_free(dir->ext); - - g_free(dir); - - return 0; -} - -static const luaL_Reg Dir_methods[] = { - {"open", Dir_open}, - {"close", Dir_close}, - { NULL, NULL } -}; - -static const luaL_Reg Dir_meta[] = { - {"__call", Dir__call}, - { NULL, NULL } -}; - -int Dir_register(lua_State* L) { - - WSLUA_REGISTER_CLASS(Dir); - - return 0; -} - - typedef struct _statcmd_t { lua_State* L; int func_ref; @@ -434,7 +264,7 @@ static void statcmd_init(const char *opt_arg, void* userdata) { } WSLUA_FUNCTION wslua_register_stat_cmd_arg(lua_State* L) { - /* Register a function to handle a -z option */ + /* Register a function to handle a `-z` option */ #define WSLUA_ARG_register_stat_cmd_arg_ARGUMENT 1 /* Argument */ #define WSLUA_OPTARG_register_stat_cmd_arg_ACTION 2 /* Action */ const char* arg = luaL_checkstring(L,WSLUA_ARG_register_stat_cmd_arg_ARGUMENT); diff --git a/test/lua/dir.lua b/test/lua/dir.lua new file mode 100644 index 0000000000..88ecbe2ce9 --- /dev/null +++ b/test/lua/dir.lua @@ -0,0 +1,202 @@ +-- test script for wslua Dir functions + +------------- helper funcs ------------ + +local total_tests = 0 + +local function testing(name) + print("---- Testing "..name.." ---- ") +end + +local function test(name, ...) + total_tests = total_tests + 1 + io.stdout:write("test "..name.."-"..total_tests.."...") + if (...) == true then + io.stdout:write("passed\n") + return true + else + io.stdout:write("failed!\n") + error(name.." test failed!") + end +end + +-- the following are so we can use pcall (which needs a function to call) +local function callDirFuncBase(name, t) + t.result = Dir[name]() + return true +end + +local function callDirFunc(name, val, t) + t.result = Dir[name](val) + return true +end + +local function makeFile(filename) + local f = io.open(filename, "w") + if not f then + error ("failed to make file"..filename.." in directory\n".. + "make sure to delete 'temp' directory before running again") + end + f:write("fooobarrloo") + f:close() + return true +end + +-------------------------- + +-- for our called function results +local t = {} + +testing("Dir basics") + +test("global", _G.Dir ~= nil) +test("global", type(Dir.make) == 'function') +test("global", type(Dir.remove) == 'function') +test("global", type(Dir.remove_all) == 'function') +test("global", type(Dir.open) == 'function') +test("global", type(Dir.close) == 'function') +test("global", type(Dir.exists) == 'function') +test("global", type(Dir.personal_config_path) == 'function') +test("global", type(Dir.global_config_path) == 'function') +test("global", type(Dir.personal_plugins_path) == 'function') +test("global", type(Dir.global_plugins_path) == 'function') + +testing("Dir paths/filenames") + +test("Dir.__FILE__", __FILE__ ~= nil) +test("Dir.__DIR__", __DIR__ ~= nil) +test("Dir.exists", pcall(callDirFunc, "exists", "temp", t)) +test("Dir.personal_config_path", pcall(callDirFuncBase, "personal_config_path", t)) +test("Dir.global_config_path", pcall(callDirFuncBase, "global_config_path", t)) +test("Dir.personal_plugins_path", pcall(callDirFuncBase, "personal_plugins_path", t)) +test("Dir.global_plugins_path", pcall(callDirFuncBase, "global_plugins_path", t)) + +print("\nFor your information, I got the following info:\n") +print("__FILE__ = '" .. __FILE__ .. "'") +print("__DIR__ = '" .. __DIR__ .. "'") +print("personal_config_path = '" .. Dir.personal_config_path() .. "'") +print("global_config_path = '" .. Dir.global_config_path() .. "'") +print("personal_plugins_path = '" .. Dir.personal_plugins_path() .. "'") +print("global_plugins_path = '" .. Dir.global_plugins_path() .. "'") +print("\n") + +testing("Directory manipulation") + +test("Dir.exists", pcall(callDirFunc, "exists", "temp", t)) + +if t.result == true or t.result == false then + error("this testsuite requires there be no 'temp' directory or file; please remove it") +end + +testing("Dir.make") + +test("Dir.make", pcall(callDirFunc, "make", "temp", t) and t.result == true) +test("Dir.exists", pcall(callDirFunc, "exists", "temp", t) and t.result == true) +-- make the same dir, should give false +test("Dir.make", pcall(callDirFunc, "make", "temp", t) and t.result == false) + +testing("Dir.remove") + +test("Dir.remove", pcall(callDirFunc, "remove", "temp", t) and t.result == true) +test("Dir.exists", pcall(callDirFunc, "exists", "temp", t) and t.result == nil) +test("Dir.remove", pcall(callDirFunc, "remove", "temp", t) and t.result == false) + +Dir.make("temp") +makeFile("temp/file.txt") + +-- will return nil because temp has a file +test("Dir.remove", pcall(callDirFunc, "remove", "temp", t) and t.result == nil) + +testing("Dir.remove_all") + +test("Dir.remove_all", pcall(callDirFunc, "remove_all", "temp", t) and t.result == true) +test("Dir.remove_all", pcall(callDirFunc, "remove_all", "temp", t) and t.result == false) + +Dir.make("temp") +makeFile("temp/file1.txt") +makeFile("temp/file2.txt") +makeFile("temp/file3.txt") +test("Dir.remove_all", pcall(callDirFunc, "remove_all", "temp", t) and t.result == true) +test("Dir.remove_all", pcall(callDirFunc, "remove_all", "temp", t) and t.result == false) + +testing("Dir.open") + +Dir.make("temp") +makeFile("temp/file1.txt") +makeFile("temp/file2.txt") +makeFile("temp/file3.txt") +test("Dir.open", pcall(callDirFunc, "open", "temp", t)) +test("Dir.open", type(t.result) == 'userdata') +test("Dir.open", typeof(t.result) == 'Dir') + +io.stdout:write("calling Dir object...") +local dir = t.result +local file = dir() +io.stdout:write("passed\n") + +test("Dir.call", file == "file1.txt") +file = dir() +test("Dir.call", file == "file2.txt") +file = dir() +test("Dir.call", file == "file3.txt") +file = dir() +test("Dir.call", file == nil) +file = dir() +test("Dir.call", file == nil) + +testing("Dir.close") + +test("Dir.close", pcall(callDirFunc, "close", dir, t)) +test("Dir.close", pcall(callDirFunc, "close", dir, t)) + +testing("Negative testing 1") +-- now try breaking it +test("Dir.open", pcall(callDirFunc, "open", "temp", t)) +dir = t.result +-- call dir() now +file = dir() +test("Dir.call", file == "file1.txt") + +Dir.remove_all("temp") + +-- call it again +file = dir() +test("Dir.call", file == "file2.txt") +test("Dir.close", pcall(callDirFunc, "close", dir, t)) + +testing("Negative testing 2") +-- do it again, but this time don't do dir() until after removing the files +Dir.make("temp") +makeFile("temp/file1.txt") +makeFile("temp/file2.txt") +makeFile("temp/file3.txt") + +test("Dir.open", pcall(callDirFunc, "open", "temp", t)) +dir = t.result + +Dir.remove_all("temp") +-- now do it +file = dir() +test("Dir.call", file == nil) +test("Dir.close", pcall(callDirFunc, "close", dir, t)) + + +-- negative tests +testing("Negative testing 3") + +-- invalid args +test("Dir.make", not pcall(callDirFunc, "make", {}, t)) +test("Dir.make", not pcall(callDirFunc, "make", nil, t)) +test("Dir.remove", not pcall(callDirFunc, "remove", {}, t)) +test("Dir.remove", not pcall(callDirFunc, "remove", nil, t)) +test("Dir.remove_all", not pcall(callDirFunc, "remove_all", {}, t)) +test("Dir.remove_all", not pcall(callDirFunc, "remove_all", nil, t)) +test("Dir.open", not pcall(callDirFunc, "open", {}, t)) +test("Dir.open", not pcall(callDirFunc, "open", nil, t)) +test("Dir.close", not pcall(callDirFunc, "close", "dir", t)) +test("Dir.close", not pcall(callDirFunc, "close", nil, t)) + + +print("\n-----------------------------\n") + +print("All tests passed!\n\n") diff --git a/test/suite-wslua.sh b/test/suite-wslua.sh index d6c2244746..d4eaa60489 100755 --- a/test/suite-wslua.sh +++ b/test/suite-wslua.sh @@ -22,6 +22,22 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. # +wslua_step_dir_test() { + if [ $HAVE_LUA -ne 0 ]; then + test_step_skipped + return + fi + + # Tshark catches lua script failures, so we have to parse the output. + $TSHARK -r $CAPTURE_DIR/empty.pcap -X lua_script:$TESTS_DIR/lua/dir.lua > testout.txt 2>&1 + if grep -q "All tests passed!" testout.txt; then + test_step_ok + else + cat testout.txt + test_step_failed "didn't find pass marker" + fi +} + wslua_step_dissector_test() { if [ $HAVE_LUA -ne 0 ]; then test_step_skipped @@ -358,6 +374,7 @@ wslua_cleanup_step() { wslua_suite() { test_step_set_pre wslua_cleanup_step test_step_set_post wslua_cleanup_step + test_step_add "wslua dir" wslua_step_dir_test test_step_add "wslua dissector" wslua_step_dissector_test test_step_add "wslua field/fieldinfo" wslua_step_field_test test_step_add "wslua file" wslua_step_file_test |