1 /* 2 * wslua_dir.c 3 * 4 * (c) 2014, Hadriel Kaplan <hadrielk at yahoo dot com> 5 * 6 * Wireshark - Network traffic analyzer 7 * By Gerald Combs <gerald@wireshark.org> 8 * Copyright 1998 Gerald Combs 9 * 10 * SPDX-License-Identifier: GPL-2.0-or-later 11 */ 12 13 #include "config.h" 14 15 /* WSLUA_MODULE Dir Directory Handling Functions */ 16 17 #include "wslua.h" 18 #include <wsutil/file_util.h> 19 20 WSLUA_CLASS_DEFINE(Dir,FAIL_ON_NULL("Dir")); /* A Directory object, as well as associated functions. */ 21 22 WSLUA_CONSTRUCTOR Dir_make(lua_State* L) { 23 /* Creates a directory. 24 25 The created directory is set for permission mode 0755 (octal), meaning it is 26 read+write+execute by owner, but only read+execute by group members and others. 27 28 If the directory was created successfully, a boolean `true` is returned. 29 If the directory cannot be made because it already exists, `false` is returned. 30 If the directory cannot be made because an error occurred, `nil` is returned. 31 32 @since 1.11.3 33 */ 34 #define WSLUA_ARG_Dir_make_NAME 1 /* The name of the directory, possibly including path. */ 35 36 const char *dir_path = luaL_checkstring(L, WSLUA_ARG_Dir_make_NAME); 37 ws_statb64 s_buf; 38 int ret; 39 40 if (ws_stat64(dir_path, &s_buf) != 0 && errno == ENOENT) { 41 ret = ws_mkdir(dir_path, 0755); 42 if (ret == -1) { 43 lua_pushnil(L); 44 } else { 45 lua_pushboolean(L, 1); 46 } 47 } else { 48 lua_pushboolean(L, 0); 49 } 50 51 WSLUA_RETURN(1); /* Boolean `true` on success, `false` if the directory already exists, `nil` on error. */ 52 } 53 54 WSLUA_CONSTRUCTOR Dir_exists(lua_State* L) { 55 /* Returns true if the given directory name exists. 56 57 If the directory exists, a boolean `true` is returned. 58 If the path is a file instead, `false` is returned. 59 If the path does not exist or an error occurred, `nil` is returned. 60 61 @since 1.11.3 62 */ 63 #define WSLUA_ARG_Dir_exists_NAME 1 /* The name of the directory, possibly including path. */ 64 65 const char *dir_path = luaL_checkstring(L, WSLUA_ARG_Dir_exists_NAME); 66 int ret; 67 68 if ((ret = test_for_directory (dir_path)) == EISDIR) { 69 lua_pushboolean(L, 1); 70 } else { 71 if (ret == 0) { 72 lua_pushboolean(L, 0); 73 } else { 74 lua_pushnil(L); 75 } 76 } 77 78 WSLUA_RETURN(1); /* Boolean `true` if the directory exists, `false` if it's a file, `nil` on error or not-exist. */ 79 } 80 81 WSLUA_CONSTRUCTOR Dir_remove(lua_State* L) { 82 /* Removes an empty directory. 83 84 If the directory was removed successfully, a boolean `true` is returned. 85 If the directory cannot be removed because it does not exist, `false` is returned. 86 If the directory cannot be removed because an error occurred, `nil` is returned. 87 88 This function only removes empty directories. To remove a directory regardless, 89 use `Dir.remove_all()`. 90 91 @since 1.11.3 92 */ 93 #define WSLUA_ARG_Dir_remove_NAME 1 /* The name of the directory, possibly including path. */ 94 95 const char *dir_path = luaL_checkstring(L, WSLUA_ARG_Dir_remove_NAME); 96 int ret; 97 98 if (test_for_directory (dir_path) == EISDIR) { 99 ret = ws_remove(dir_path); 100 if (ret != 0) { 101 lua_pushnil(L); 102 } else { 103 lua_pushboolean(L, 1); 104 } 105 } else { 106 lua_pushboolean(L, 0); 107 } 108 109 WSLUA_RETURN(1); /* Boolean `true` on success, `false` if does not exist, `nil` on error. */ 110 } 111 112 static int delete_directory(const char *directory) { 113 WS_DIR *dir; 114 WS_DIRENT *file; 115 gchar *filename; 116 int ret = 0; 117 118 /* delete all contents of directory */ 119 if ((dir = ws_dir_open(directory, 0, NULL)) != NULL) { 120 while ((file = ws_dir_read_name(dir)) != NULL) { 121 filename = g_build_filename(directory, ws_dir_get_name(file), NULL); 122 if (test_for_directory(filename) != EISDIR) { 123 ret = ws_remove(filename); 124 } else { 125 /* recurse */ 126 ret = delete_directory (filename); 127 } 128 g_free(filename); 129 if (ret != 0) { 130 break; 131 } 132 } 133 ws_dir_close(dir); 134 } 135 136 if (ret == 0) { 137 ret = ws_remove(directory); 138 } 139 140 return ret; 141 } 142 143 144 WSLUA_CONSTRUCTOR Dir_remove_all(lua_State* L) { 145 /* Removes an empty or non-empty directory. 146 147 If the directory was removed successfully, a boolean `true` is returned. 148 If the directory cannot be removed because it does not exist, `false` is returned. 149 If the directory cannot be removed because an error occurred, `nil` is returned. 150 151 @since 1.11.3 152 */ 153 #define WSLUA_ARG_Dir_remove_all_NAME 1 /* The name of the directory, possibly including path. */ 154 155 const char *dir_path = luaL_checkstring(L, WSLUA_ARG_Dir_remove_all_NAME); 156 int ret; 157 158 if (test_for_directory (dir_path) == EISDIR) { 159 ret = delete_directory(dir_path); 160 if (ret != 0) { 161 lua_pushnil(L); 162 } else { 163 lua_pushboolean(L, 1); 164 } 165 } else { 166 lua_pushboolean(L, 0); 167 } 168 169 WSLUA_RETURN(1); /* Boolean `true` on success, `false` if does not exist, `nil` on error. */ 170 } 171 172 WSLUA_CONSTRUCTOR Dir_open(lua_State* L) { 173 /* Opens a directory and returns a <<lua_class_Dir,`Dir`>> object representing the files in the directory. 174 175 ==== Example 176 177 [source,lua] 178 ---- 179 -- Print the contents of a directory 180 for filename in Dir.open('/path/to/dir') do 181 print(filename) 182 end 183 ---- 184 */ 185 #define WSLUA_ARG_Dir_open_PATHNAME 1 /* The pathname of the directory. */ 186 #define WSLUA_OPTARG_Dir_open_EXTENSION 2 /* If given, only files with this extension will be returned. */ 187 188 const char* dirname = luaL_checkstring(L,WSLUA_ARG_Dir_open_PATHNAME); 189 const char* extension = luaL_optstring(L,WSLUA_OPTARG_Dir_open_EXTENSION,NULL); 190 Dir dir; 191 char* dirname_clean; 192 193 dirname_clean = wslua_get_actual_filename(dirname); 194 if (!dirname_clean) { 195 WSLUA_ARG_ERROR(Dir_open,PATHNAME,"directory does not exist"); 196 return 0; 197 } 198 199 if (!test_for_directory(dirname_clean)) { 200 g_free(dirname_clean); 201 WSLUA_ARG_ERROR(Dir_open,PATHNAME, "must be a directory"); 202 return 0; 203 } 204 205 dir = (Dir)g_malloc(sizeof(struct _wslua_dir)); 206 dir->dir = g_dir_open(dirname_clean, 0, NULL); 207 g_free(dirname_clean); 208 209 if (dir->dir == NULL) { 210 g_free(dir); 211 212 WSLUA_ARG_ERROR(Dir_open,PATHNAME,"could not open directory"); 213 return 0; 214 } 215 216 dir->ext = g_strdup(extension); 217 218 pushDir(L,dir); 219 WSLUA_RETURN(1); /* The <<lua_class_Dir,`Dir`>> object. */ 220 } 221 222 WSLUA_METAMETHOD Dir__call(lua_State* L) { 223 /* 224 Gets the next file or subdirectory within the directory, or `nil` when done. 225 226 ==== Example 227 228 [source,lua] 229 ---- 230 -- Open a directory and print the name of the first file or subdirectory 231 local dir = Dir.open('/path/to/dir') 232 local first = dir() 233 print(tostring(file)) 234 ---- 235 */ 236 237 Dir dir = checkDir(L,1); 238 const gchar* file; 239 const gchar* filename; 240 const char* ext; 241 242 if (!dir->dir) { 243 return 0; 244 } 245 246 if ( ! ( file = g_dir_read_name(dir->dir ) )) { 247 g_dir_close(dir->dir); 248 dir->dir = NULL; 249 return 0; 250 } 251 252 253 if ( ! dir->ext ) { 254 lua_pushstring(L,file); 255 return 1; 256 } 257 258 do { 259 filename = file; 260 261 /* XXX strstr returns ptr to first match, 262 this fails ext=".xxx" filename="aaa.xxxz.xxx" */ 263 if ( ( ext = strstr(filename,dir->ext)) && g_str_equal(ext,dir->ext) ) { 264 lua_pushstring(L,filename); 265 return 1; 266 } 267 } while(( file = g_dir_read_name(dir->dir) )); 268 269 g_dir_close(dir->dir); 270 dir->dir = NULL; 271 return 0; 272 } 273 274 WSLUA_METHOD Dir_close(lua_State* L) { 275 /* Closes the directory. Called automatically during garbage collection of a <<lua_class_Dir,`Dir`>> object. */ 276 Dir dir = checkDir(L,1); 277 278 if (dir->dir) { 279 g_dir_close(dir->dir); 280 dir->dir = NULL; 281 } 282 283 return 0; 284 } 285 286 WSLUA_CONSTRUCTOR Dir_personal_config_path(lua_State* L) { 287 /* Gets the https://www.wireshark.org/docs/wsug_html_chunked/ChAppFilesConfigurationSection.html[personal configuration] directory path, with filename if supplied. 288 289 @since 1.11.3 290 */ 291 #define WSLUA_OPTARG_personal_config_path_FILENAME 1 /* A filename. */ 292 const char *fname = luaL_optstring(L, WSLUA_OPTARG_personal_config_path_FILENAME,""); 293 char* filename = get_persconffile_path(fname,FALSE); 294 295 lua_pushstring(L,filename); 296 g_free(filename); 297 WSLUA_RETURN(1); /* The full pathname for a file in the personal configuration directory. */ 298 } 299 300 WSLUA_CONSTRUCTOR Dir_global_config_path(lua_State* L) { 301 /* Gets the https://www.wireshark.org/docs/wsug_html_chunked/ChAppFilesConfigurationSection.html[global configuration] directory path, with filename if supplied. 302 303 @since 1.11.3 304 */ 305 #define WSLUA_OPTARG_global_config_path_FILENAME 1 /* A filename */ 306 const char *fname = luaL_optstring(L, WSLUA_OPTARG_global_config_path_FILENAME,""); 307 char* filename; 308 309 filename = get_datafile_path(fname); 310 lua_pushstring(L,filename); 311 g_free(filename); 312 WSLUA_RETURN(1); /* The full pathname for a file in Wireshark's configuration directory. */ 313 } 314 315 WSLUA_CONSTRUCTOR Dir_personal_plugins_path(lua_State* L) { 316 /* Gets the personal plugins directory path. 317 318 @since 1.11.3 319 */ 320 lua_pushstring(L, get_plugins_pers_dir()); 321 WSLUA_RETURN(1); /* The pathname of the https://www.wireshark.org/docs/wsug_html_chunked/ChPluginFolders.html[personal plugins] directory. */ 322 } 323 324 WSLUA_CONSTRUCTOR Dir_global_plugins_path(lua_State* L) { 325 /* Gets the global plugins directory path. 326 327 @since 1.11.3 328 */ 329 lua_pushstring(L, get_plugins_dir()); 330 WSLUA_RETURN(1); /* The pathname of the https://www.wireshark.org/docs/wsug_html_chunked/ChPluginFolders.html[global plugins] directory. */ 331 } 332 333 /* Gets registered as metamethod automatically by WSLUA_REGISTER_CLASS/META */ 334 static int Dir__gc(lua_State* L) { 335 Dir dir = toDir(L,1); 336 337 if(!dir) return 0; 338 339 if (dir->dir) { 340 g_dir_close(dir->dir); 341 } 342 343 g_free(dir->ext); 344 g_free(dir); 345 346 return 0; 347 } 348 349 WSLUA_METHODS Dir_methods[] = { 350 WSLUA_CLASS_FNREG(Dir,make), 351 WSLUA_CLASS_FNREG(Dir,exists), 352 WSLUA_CLASS_FNREG(Dir,remove), 353 WSLUA_CLASS_FNREG(Dir,remove_all), 354 WSLUA_CLASS_FNREG(Dir,open), 355 WSLUA_CLASS_FNREG(Dir,close), 356 WSLUA_CLASS_FNREG(Dir,personal_config_path), 357 WSLUA_CLASS_FNREG(Dir,global_config_path), 358 WSLUA_CLASS_FNREG(Dir,personal_plugins_path), 359 WSLUA_CLASS_FNREG(Dir,global_plugins_path), 360 { NULL, NULL } 361 }; 362 363 WSLUA_META Dir_meta[] = { 364 WSLUA_CLASS_MTREG(Dir,call), 365 { NULL, NULL } 366 }; 367 368 int Dir_register(lua_State* L) { 369 WSLUA_REGISTER_CLASS(Dir); 370 return 0; 371 } 372 373 /* 374 * Editor modelines - https://www.wireshark.org/tools/modelines.html 375 * 376 * Local variables: 377 * c-basic-offset: 4 378 * tab-width: 8 379 * indent-tabs-mode: nil 380 * End: 381 * 382 * vi: set shiftwidth=4 tabstop=8 expandtab: 383 * :indentSize=4:tabSize=8:noTabs=true: 384 */ 385