Limit the maximum *file* name length for exported objects.
[metze/wireshark/wip.git] / ui / cli / tap-exportobject.c
1 /* tap-exportobject.c
2  *
3  * Wireshark - Network traffic analyzer
4  * By Gerald Combs <gerald@wireshark.org>
5  * Copyright 1998 Gerald Combs
6  *
7  * SPDX-License-Identifier: GPL-2.0-or-later
8  */
9
10 #include "config.h"
11
12 #include <glib.h>
13
14 #include <errno.h>
15 #include <stdio.h>
16 #include <stdlib.h>
17
18 #include <string.h>
19
20 #include <wsutil/file_util.h>
21 #include <ui/cmdarg_err.h>
22
23 #include <epan/packet_info.h>
24 #include <epan/packet.h>
25 #include <epan/export_object.h>
26 #include <ui/export_object_ui.h>
27 #include "tap-exportobject.h"
28
29 typedef struct _export_object_list_gui_t {
30     GSList *entries;
31     register_eo_t* eo;
32 } export_object_list_gui_t;
33
34 static GHashTable* eo_opts = NULL;
35
36 static gboolean
37 list_exportobject_protocol(const void *key, void *value _U_, void *userdata _U_)
38 {
39     fprintf(stderr, "     %s\n", (const gchar*)key);
40     return FALSE;
41 }
42
43 void eo_list_object_types(void)
44 {
45     eo_iterate_tables(list_exportobject_protocol, NULL);
46 }
47
48 gboolean eo_tap_opt_add(const char *option_string)
49 {
50     gchar** splitted;
51
52     if (!eo_opts)
53         eo_opts = g_hash_table_new(g_str_hash,g_str_equal);
54
55     splitted = g_strsplit(option_string, ",", 2);
56
57     if ((splitted[0] == NULL) || (splitted[1] == NULL) || (get_eo_by_name(splitted[0]) == NULL))
58     {
59         fprintf(stderr, "tshark: \"--export-objects\" are specified as: <protocol>,<destdir>\n");
60         fprintf(stderr, "tshark: The available export object types for the \"--export-objects\" option are:\n");
61         eo_list_object_types();
62     }
63     else
64     {
65         gchar* dir = (gchar*)g_hash_table_lookup(eo_opts, splitted[0]);
66
67         /* Since we're saving all objects from a protocol,
68             it can only be listed once */
69         if (dir == NULL) {
70             g_hash_table_insert(eo_opts, splitted[0], splitted[1]);
71
72             g_free(splitted);
73             return TRUE;
74         }
75         else
76         {
77             cmdarg_err("\"--export-objects\" already specified protocol '%s'", splitted[0]);
78         }
79     }
80
81     g_strfreev(splitted);
82     return FALSE;
83 }
84
85 static void
86 object_list_add_entry(void *gui_data, export_object_entry_t *entry)
87 {
88     export_object_list_gui_t *object_list = (export_object_list_gui_t*)gui_data;
89
90     object_list->entries = g_slist_append(object_list->entries, entry);
91 }
92
93 static export_object_entry_t*
94 object_list_get_entry(void *gui_data, int row) {
95     export_object_list_gui_t *object_list = (export_object_list_gui_t*)gui_data;
96
97     return (export_object_entry_t *)g_slist_nth_data(object_list->entries, row);
98 }
99
100 /* This is just for writing Exported Objects to a file */
101 static void
102 eo_draw(void *tapdata)
103 {
104     export_object_list_t *tap_object = (export_object_list_t *)tapdata;
105     export_object_list_gui_t *object_list = (export_object_list_gui_t*)tap_object->gui_data;
106     GSList *slist = object_list->entries;
107     export_object_entry_t *entry;
108     gboolean all_saved = TRUE;
109     gchar* save_in_path = (gchar*)g_hash_table_lookup(eo_opts, proto_get_protocol_filter_name(get_eo_proto_id(object_list->eo)));
110     GString *safe_filename = NULL;
111     gchar *save_as_fullpath = NULL;
112     int count = 0;
113
114     if (!g_file_test(save_in_path, G_FILE_TEST_IS_DIR)) {
115         /* If the destination directory (or its parents) do not exist, create them. */
116         if (g_mkdir_with_parents(save_in_path, 0755) == -1) {
117             fprintf(stderr, "Failed to create export objects output directory \"%s\": %s\n",
118                     save_in_path, g_strerror(errno));
119             return;
120         }
121     }
122
123     while (slist) {
124         entry = (export_object_entry_t *)slist->data;
125         do {
126             g_free(save_as_fullpath);
127             if (entry->filename) {
128                 safe_filename = eo_massage_str(entry->filename,
129                     EXPORT_OBJECT_MAXFILELEN, count);
130             } else {
131                 char generic_name[EXPORT_OBJECT_MAXFILELEN+1];
132                 const char *ext;
133                 ext = eo_ct2ext(entry->content_type);
134                 g_snprintf(generic_name, sizeof(generic_name),
135                     "object%u%s%s", entry->pkt_num, ext ? "." : "", ext ? ext : "");
136                 safe_filename = eo_massage_str(generic_name,
137                     EXPORT_OBJECT_MAXFILELEN, count);
138             }
139             save_as_fullpath = g_build_filename(save_in_path, safe_filename->str, NULL);
140             g_string_free(safe_filename, TRUE);
141         } while (g_file_test(save_as_fullpath, G_FILE_TEST_EXISTS) && ++count < 1000);
142         count = 0;
143         if (!eo_save_entry(save_as_fullpath, entry, TRUE))
144             all_saved = FALSE;
145         g_free(save_as_fullpath);
146         save_as_fullpath = NULL;
147         slist = slist->next;
148     }
149
150     if (!all_saved)
151         fprintf(stderr, "Export objects (%s): Some files could not be saved.\n",
152                     proto_get_protocol_filter_name(get_eo_proto_id(object_list->eo)));
153 }
154
155 static void
156 exportobject_handler(gpointer key, gpointer value _U_, gpointer user_data _U_)
157 {
158     GString *error_msg;
159     export_object_list_t *tap_data;
160     export_object_list_gui_t *object_list;
161     register_eo_t* eo;
162
163     eo = get_eo_by_name((const char*)key);
164     if (eo == NULL)
165     {
166         cmdarg_err("\"--export-objects\" INTERNAL ERROR '%s' protocol not found", (const char*)key);
167         return;
168     }
169
170     tap_data = g_new0(export_object_list_t,1);
171     object_list = g_new0(export_object_list_gui_t,1);
172
173     tap_data->add_entry = object_list_add_entry;
174     tap_data->get_entry = object_list_get_entry;
175     tap_data->gui_data = (void*)object_list;
176
177     object_list->eo = eo;
178
179     /* Data will be gathered via a tap callback */
180     error_msg = register_tap_listener(get_eo_tap_listener_name(eo), tap_data, NULL, 0,
181                       NULL, get_eo_packet_func(eo), eo_draw, NULL);
182
183     if (error_msg) {
184         cmdarg_err("Can't register %s tap: %s", (const char*)key, error_msg->str);
185         g_string_free(error_msg, TRUE);
186         g_free(tap_data);
187         g_free(object_list);
188         return;
189     }
190 }
191
192 void start_exportobjects(void)
193 {
194     if (eo_opts != NULL)
195         g_hash_table_foreach(eo_opts, exportobject_handler, NULL);
196 }
197
198 /*
199  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
200  *
201  * Local variables:
202  * c-basic-offset: 4
203  * tab-width: 8
204  * indent-tabs-mode: nil
205  * End:
206  *
207  * vi: set shiftwidth=4 tabstop=8 expandtab:
208  * :indentSize=4:tabSize=8:noTabs=true:
209  */