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
Dir_make(lua_State * L)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
Dir_exists(lua_State * L)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
Dir_remove(lua_State * L)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
delete_directory(const char * directory)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
Dir_remove_all(lua_State * L)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
Dir_open(lua_State * L)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
Dir__call(lua_State * L)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
Dir_close(lua_State * L)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
Dir_personal_config_path(lua_State * L)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
Dir_global_config_path(lua_State * L)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
Dir_personal_plugins_path(lua_State * L)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
Dir_global_plugins_path(lua_State * L)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 */
Dir__gc(lua_State * L)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
Dir_register(lua_State * L)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