Fix comment end after SPDX identifier
[gd/wireshark/.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
22 #include <epan/packet_info.h>
23 #include <epan/packet.h>
24 #include <epan/export_object.h>
25 #include <ui/export_object_ui.h>
26 #include "tap-exportobject.h"
27
28 /* XXX - This is effectively a copy of eo_save_entry with the "GUI alerts"
29  * removed to accomodate tshark
30  */
31 static gboolean
32 local_eo_save_entry(const gchar *save_as_filename, export_object_entry_t *entry)
33 {
34     int to_fd;
35     gint64 bytes_left;
36     int bytes_to_write;
37     ssize_t bytes_written;
38     guint8 *ptr;
39
40     to_fd = ws_open(save_as_filename, O_WRONLY | O_CREAT | O_EXCL | O_BINARY, 0644);
41     if(to_fd == -1) { /* An error occurred */
42         return FALSE;
43     }
44
45     /*
46      * The third argument to _write() on Windows is an unsigned int,
47      * so, on Windows, that's the size of the third argument to
48      * ws_write().
49      *
50      * The third argument to write() on UN*X is a size_t, although
51      * the return value is an ssize_t, so one probably shouldn't
52      * write more than the max value of an ssize_t.
53      *
54      * In either case, there's no guarantee that a gint64 such as
55      * payload_len can be passed to ws_write(), so we write in
56      * chunks of, at most 2^31 bytes.
57      */
58     ptr = entry->payload_data;
59     bytes_left = entry->payload_len;
60     while (bytes_left != 0) {
61         if (bytes_left > 0x40000000)
62             bytes_to_write = 0x40000000;
63         else
64             bytes_to_write = (int)bytes_left;
65         bytes_written = ws_write(to_fd, ptr, bytes_to_write);
66         if(bytes_written <= 0) {
67             ws_close(to_fd);
68             return FALSE;
69         }
70         bytes_left -= bytes_written;
71         ptr += bytes_written;
72     }
73     if (ws_close(to_fd) < 0) {
74         return FALSE;
75     }
76
77     return TRUE;
78 }
79
80 typedef struct _export_object_list_gui_t {
81     GSList *entries;
82     register_eo_t* eo;
83 } export_object_list_gui_t;
84
85 static GHashTable* eo_opts = NULL;
86
87 static gboolean
88 list_exportobject_protocol(const void *key, void *value _U_, void *userdata _U_)
89 {
90     fprintf(stderr, "     %s\n", (const gchar*)key);
91     return FALSE;
92 }
93
94 void eo_list_object_types(void)
95 {
96     eo_iterate_tables(list_exportobject_protocol, NULL);
97 }
98
99 gboolean eo_tap_opt_add(const char *option_string)
100 {
101     gchar** splitted;
102
103     if (!eo_opts)
104         eo_opts = g_hash_table_new(g_str_hash,g_str_equal);
105
106     splitted = g_strsplit(option_string, ",", 2);
107
108     if ((splitted[0] == NULL) || (splitted[1] == NULL) || (get_eo_by_name(splitted[0]) == NULL))
109     {
110         fprintf(stderr, "tshark: \"--export-objects\" are specified as: <protocol>,<destdir>\n");
111         fprintf(stderr, "tshark: The available export object types for the \"--export-objects\" option are:\n");
112         eo_list_object_types();
113     }
114     else
115     {
116         gchar* dir = (gchar*)g_hash_table_lookup(eo_opts, splitted[0]);
117
118         /* Since we're saving all objects from a protocol,
119             it can only be listed once */
120         if (dir == NULL) {
121             g_hash_table_insert(eo_opts, splitted[0], splitted[1]);
122
123             g_free(splitted);
124             return TRUE;
125         }
126         else
127         {
128             fprintf(stderr, "tshark: \"--export-objects\" already specified protocol '%s'\n", splitted[0]);
129         }
130     }
131
132     g_strfreev(splitted);
133     return FALSE;
134 }
135
136 static void
137 object_list_add_entry(void *gui_data, export_object_entry_t *entry)
138 {
139     export_object_list_gui_t *object_list = (export_object_list_gui_t*)gui_data;
140
141     object_list->entries = g_slist_append(object_list->entries, entry);
142 }
143
144 static export_object_entry_t*
145 object_list_get_entry(void *gui_data, int row) {
146     export_object_list_gui_t *object_list = (export_object_list_gui_t*)gui_data;
147
148     return (export_object_entry_t *)g_slist_nth_data(object_list->entries, row);
149 }
150
151 /* This is just for writing Exported Objects to a file */
152 static void
153 eo_draw(void *tapdata)
154 {
155     export_object_list_t *tap_object = (export_object_list_t *)tapdata;
156     export_object_list_gui_t *object_list = (export_object_list_gui_t*)tap_object->gui_data;
157     GSList *slist = object_list->entries;
158     export_object_entry_t *entry;
159     gboolean all_saved = TRUE;
160     gchar* save_in_path = (gchar*)g_hash_table_lookup(eo_opts, proto_get_protocol_filter_name(get_eo_proto_id(object_list->eo)));
161     GString *safe_filename = NULL;
162     gchar *save_as_fullpath = NULL;
163     int count = 0;
164
165     if (!g_file_test(save_in_path, G_FILE_TEST_IS_DIR)) {
166         /* If the destination directory (or its parents) do not exist, create them. */
167         if (g_mkdir_with_parents(save_in_path, 0755) == -1) {
168             fprintf(stderr, "Failed to create export objects output directory \"%s\": %s\n",
169                     save_in_path, g_strerror(errno));
170             return;
171         }
172     }
173
174     if ((strlen(save_in_path) < EXPORT_OBJECT_MAXFILELEN)) {
175         while (slist) {
176             entry = (export_object_entry_t *)slist->data;
177             do {
178                 g_free(save_as_fullpath);
179                 if (entry->filename) {
180                     safe_filename = eo_massage_str(entry->filename,
181                         EXPORT_OBJECT_MAXFILELEN - strlen(save_in_path), count);
182                 } else {
183                     char generic_name[EXPORT_OBJECT_MAXFILELEN+1];
184                     const char *ext;
185                     ext = eo_ct2ext(entry->content_type);
186                     g_snprintf(generic_name, sizeof(generic_name),
187                         "object%u%s%s", entry->pkt_num, ext ? "." : "", ext ? ext : "");
188                     safe_filename = eo_massage_str(generic_name,
189                         EXPORT_OBJECT_MAXFILELEN - strlen(save_in_path), count);
190                 }
191                 save_as_fullpath = g_build_filename(save_in_path, safe_filename->str, NULL);
192                 g_string_free(safe_filename, TRUE);
193             } while (g_file_test(save_as_fullpath, G_FILE_TEST_EXISTS) && ++count < 1000);
194             count = 0;
195             if (!local_eo_save_entry(save_as_fullpath, entry))
196                 all_saved = FALSE;
197             g_free(save_as_fullpath);
198             save_as_fullpath = NULL;
199             slist = slist->next;
200         }
201     }
202     else
203     {
204         all_saved = FALSE;
205     }
206
207     if (!all_saved)
208         fprintf(stderr, "Export objects (%s): Some files could not be saved.\n",
209                     proto_get_protocol_filter_name(get_eo_proto_id(object_list->eo)));
210 }
211
212 static void
213 exportobject_handler(gpointer key, gpointer value _U_, gpointer user_data _U_)
214 {
215     GString *error_msg;
216     export_object_list_t *tap_data;
217     export_object_list_gui_t *object_list;
218     register_eo_t* eo;
219
220     eo = get_eo_by_name((const char*)key);
221     if (eo == NULL)
222     {
223         fprintf(stderr, "tshark: \"--export-objects\" INTERNAL ERROR '%s' protocol not found\n", (const char*)key);
224         return;
225     }
226
227     tap_data = g_new0(export_object_list_t,1);
228     object_list = g_new0(export_object_list_gui_t,1);
229
230     tap_data->add_entry = object_list_add_entry;
231     tap_data->get_entry = object_list_get_entry;
232     tap_data->gui_data = (void*)object_list;
233
234     object_list->eo = eo;
235
236     /* Data will be gathered via a tap callback */
237     error_msg = register_tap_listener(get_eo_tap_listener_name(eo), tap_data, NULL, 0,
238                       NULL, get_eo_packet_func(eo), eo_draw);
239
240     if (error_msg) {
241         fprintf(stderr, "tshark: Can't register %s tap: %s\n", (const char*)key, error_msg->str);
242         g_string_free(error_msg, TRUE);
243         g_free(tap_data);
244         g_free(object_list);
245         return;
246     }
247 }
248
249 void start_exportobjects(void)
250 {
251     if (eo_opts != NULL)
252         g_hash_table_foreach(eo_opts, exportobject_handler, NULL);
253 }
254
255 /*
256  * Editor modelines  -  https://www.wireshark.org/tools/modelines.html
257  *
258  * Local variables:
259  * c-basic-offset: 4
260  * tab-width: 8
261  * indent-tabs-mode: nil
262  * End:
263  *
264  * vi: set shiftwidth=4 tabstop=8 expandtab:
265  * :indentSize=4:tabSize=8:noTabs=true:
266  */