Put all the capture dissector structures into epan/capture_dissectors.h.
[metze/wireshark/wip.git] / fileset.c
1 /* fileset.c
2  * Routines for handling file sets
3  *
4  * Wireshark - Network traffic analyzer
5  * By Gerald Combs <gerald@wireshark.org>
6  * Copyright 1998 Gerald Combs
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  */
22
23 #include <config.h>
24
25 #ifdef HAVE_SYS_WAIT_H
26 # include <sys/wait.h>
27 #endif
28
29 #include <stdio.h>
30 #include <string.h>
31
32 #include <glib.h>
33
34 #include <wsutil/file_util.h>
35 #include <wsutil/filesystem.h>
36 #include "globals.h"
37
38 #include <epan/strutil.h>
39
40 #include "fileset.h"
41
42
43
44 typedef struct _fileset {
45     GList   *entries;
46     char    *dirname;
47 } fileset;
48
49 /* this is the fileset's global data */
50 static fileset set = { NULL, NULL};
51
52 /*
53  * Given a stat structure, get the creation time of the file if available,
54  * or 0 if not.
55  */
56 #ifdef _WIN32
57   /* Microsoft's documentation says this is the creation time */
58   #define ST_CREATE_TIME(statb) ((statb).st_ctime)
59 #else /* _WIN32 */
60   /* UN*X - do we have a creation time? */
61   #if defined(HAVE_STRUCT_STAT_ST_BIRTHTIME)
62     #define ST_CREATE_TIME(statb) ((statb).st_birthtime)
63   #elif defined(HAVE_STRUCT_STAT___ST_BIRTHTIME)
64     #define ST_CREATE_TIME(statb) ((statb).__st_birthtime)
65   #else /* nothing */
66     #define ST_CREATE_TIME(statb) (0)
67   #endif /* creation time on UN*X */
68 #endif /* _WIN32 */
69
70 /* is this a probable file of a file set (does the naming pattern match)? */
71 gboolean
72 fileset_filename_match_pattern(const char *fname)
73 {
74     char        *pfx;
75     size_t       baselen;
76     size_t      minlen = strlen("_00001_20050418010750");
77     char        *filename;
78
79
80     /* d:\dir1\test_00001_20050418010750.cap */
81     filename = g_strdup(get_basename(fname));
82
83     /* test_00001_20050418010750.cap */
84     pfx = strrchr(filename, '.');
85     if(pfx == NULL) {  /* suffix is optional */
86         pfx = filename + strlen(filename);
87     }
88     /* test_00001_20050418010750 */
89     *pfx = '\0';
90
91     /* filename long enough? */
92     baselen = strlen(filename);
93     if(baselen < minlen) {
94         g_free(filename);
95         return FALSE;
96     }
97
98     /* there must be two underscores at special places */
99     if(filename[baselen-minlen] != '_' || filename[baselen-minlen+6] != '_') {
100         g_free(filename);
101         return FALSE;
102     }
103
104     /* replace the two underscores by digits */
105     filename[baselen-minlen] = '0';
106     filename[baselen-minlen+6] = '0';
107
108     /* we should have only digits now */
109     while(minlen--) {
110         baselen--;
111
112         if(!g_ascii_isdigit( filename[baselen])) {
113             g_free(filename);
114             return FALSE;
115         }
116     }
117
118     g_free(filename);
119
120     /* ok, seems to be good */
121     return TRUE;
122 }
123
124
125 /* test, if both files could be in the same file set */
126 /* (the filenames must already be in correct shape) */
127 static gboolean
128 fileset_is_file_in_set(const char *fname1, const char *fname2)
129 {
130     char        *pfx1;
131     char        *pfx2;
132     char        *dup_f1;
133     char        *dup_f2;
134     size_t       minlen = strlen("_00001_20050418010750");
135
136
137     /* just to be sure ... */
138     g_assert(fileset_filename_match_pattern(fname1));
139     g_assert(fileset_filename_match_pattern(fname2));
140
141     dup_f1 = g_strdup(fname1);
142     dup_f2 = g_strdup(fname2);
143
144     pfx1 = strrchr(dup_f1, '.');
145     pfx2 = strrchr(dup_f2, '.');
146     /* suffix is optional */
147     if (!pfx1) pfx1 = dup_f1 + strlen(dup_f1);
148     if (!pfx2) pfx2 = dup_f2 + strlen(dup_f2);
149
150     /* the optional suffix (file extension) must be equal */
151     if(strcmp(pfx1, pfx2) != 0) {
152         g_free(dup_f1);
153         g_free(dup_f2);
154         return FALSE;
155     }
156
157     *(pfx1-minlen) = '\0';
158     *(pfx2-minlen) = '\0';
159
160     if(strcmp(dup_f1, dup_f2) != 0) {
161         g_free(dup_f1);
162         g_free(dup_f2);
163         return FALSE;
164     }
165
166     g_free(dup_f1);
167     g_free(dup_f2);
168     return TRUE;
169 }
170
171 /* GCompareFunc helper for g_list_find_custom() */
172 static gint
173 fileset_find_by_path(gconstpointer a, gconstpointer b)
174 {
175     const fileset_entry *entry;
176     const char *path;
177
178     entry = (const fileset_entry *) a;
179     path  = (const char *) b;
180
181     return g_strcmp0(entry->fullname, path);
182 }
183
184 /* update the time and size of this file in the list */
185 void
186 fileset_update_file(const char *path)
187 {
188     int fh, result;
189     ws_statb64 buf;
190     fileset_entry *entry = NULL;
191     GList *entry_list;
192
193     fh = ws_open( path, O_RDONLY, 0000 /* no creation so don't matter */);
194     if(fh !=  -1) {
195
196         /* Get statistics */
197         result = ws_fstat64( fh, &buf );
198
199         /* Show statistics if they are valid */
200         if( result == 0 ) {
201             entry_list = g_list_find_custom(set.entries, path,
202                                             fileset_find_by_path);
203
204             if (entry_list) {
205                 entry = (fileset_entry *) entry_list->data;
206                 entry->ctime    = ST_CREATE_TIME(buf);
207                 entry->mtime    = buf.st_mtime;
208                 entry->size     = buf.st_size;
209             }
210         }
211
212         ws_close(fh);
213     }
214 }
215
216 /* we know this file is part of the set, so add it */
217 static fileset_entry *
218 fileset_add_file(const char *dirname, const char *fname, gboolean current)
219 {
220     int fh, result;
221     ws_statb64 buf;
222     char *path;
223     fileset_entry *entry = NULL;
224
225
226     path = g_strdup_printf("%s%s", dirname, fname);
227
228     fh = ws_open( path, O_RDONLY, 0000 /* no creation so don't matter */);
229     if(fh !=  -1) {
230
231         /* Get statistics */
232         result = ws_fstat64( fh, &buf );
233
234         /* Show statistics if they are valid */
235         if( result == 0 ) {
236             entry = (fileset_entry *)g_malloc(sizeof(fileset_entry));
237
238             entry->fullname = g_strdup(path);
239             entry->name     = g_strdup(fname);
240             entry->ctime    = ST_CREATE_TIME(buf);
241             entry->mtime    = buf.st_mtime;
242             entry->size     = buf.st_size;
243             entry->current  = current;
244
245             set.entries = g_list_append(set.entries, entry);
246         }
247
248         ws_close(fh);
249     }
250
251     g_free(path);
252
253     return entry;
254 }
255
256
257 /* compare two list entries by creation date/time (through filename) */
258 static gint
259 fileset_sort_compare(gconstpointer a, gconstpointer b)
260 {
261     const fileset_entry *entry_a = (const fileset_entry *)a;
262     const fileset_entry *entry_b = (const fileset_entry *)b;
263
264     return strcmp(entry_a->name, entry_b->name);
265 }
266
267
268 /* add all file set entries to the dialog */
269 void fileset_update_dlg(void *window)
270 {
271     GList         *le;
272
273
274     /* add all entries to the dialog */
275     le = g_list_first(set.entries);
276     while(le) {
277         fileset_dlg_add_file((fileset_entry *)le->data, window);
278         le = g_list_next(le);
279     }
280 }
281
282
283 /* walk through the directory of the loaded file and add every file matching the current file */
284 void
285 fileset_add_dir(const char *fname, void *window)
286 {
287     WS_DIR        *dir;             /* scanned directory */
288     WS_DIRENT     *file;            /* current file */
289     const char    *name;
290     GString       *dirname;
291     gchar         *fname_dup;
292
293
294     /* get (convert) directory name, but don't touch the given string */
295     fname_dup = g_strdup(fname);
296     dirname = g_string_new(get_dirname(fname_dup));
297     g_free(fname_dup);
298
299     set.dirname = g_strdup(dirname->str);
300
301     dirname = g_string_append_c(dirname, G_DIR_SEPARATOR);
302
303     /* is the current file probably a part of any fileset? */
304     if(fileset_filename_match_pattern(fname)) {
305         /* yes, go through the files in the directory and check if the file in question is part of the current file set */
306         if ((dir = ws_dir_open(dirname->str, 0, NULL)) != NULL) {
307             while ((file = ws_dir_read_name(dir)) != NULL) {
308                 name = ws_dir_get_name(file);
309                 if(fileset_filename_match_pattern(name) && fileset_is_file_in_set(name, get_basename(fname))) {
310                     fileset_add_file(dirname->str, name, strcmp(name, get_basename(fname))== 0 /* current */);
311                 }
312             } /* while */
313
314             ws_dir_close(dir);
315         } /* if */
316     } else {
317         /* no, this is a "standalone file", just add this one */
318         fileset_add_file(dirname->str, get_basename(fname), TRUE /* current */);
319         /* don't add the file to the dialog here, this will be done in fileset_update_dlg() below */
320     }
321
322     g_string_free(dirname, TRUE /* free_segment */);
323
324     /* sort entries by creation time */
325     set.entries = g_list_sort(set.entries, fileset_sort_compare);
326
327     fileset_update_dlg(window);
328 }
329
330
331 /* get current directory name */
332 const char *
333 fileset_get_dirname(void)
334 {
335     return set.dirname;
336 }
337
338
339 /* get the current list entry, or NULL */
340 static GList *
341 fileset_get_current(void)
342 {
343     GList         *le;
344     fileset_entry *entry;
345
346
347     /* add all entries to the dialog */
348     le = g_list_first(set.entries);
349     while(le) {
350         entry = (fileset_entry *)le->data;
351         if(entry->current) {
352             return le;
353         }
354         le = g_list_next(le);
355     }
356
357     return NULL;
358 }
359
360
361 /* get the file set entry after the current one, or NULL */
362 fileset_entry *
363 fileset_get_next(void)
364 {
365     GList         *le;
366
367
368     le = fileset_get_current();
369     if(le == NULL) {
370         return NULL;
371     }
372
373     le = g_list_next(le);
374     if(le == NULL) {
375         return NULL;
376     }
377
378     return (fileset_entry *)le->data;
379 }
380
381
382 /* get the file set entry before the current one, or NULL */
383 fileset_entry *
384 fileset_get_previous(void)
385 {
386     GList         *le;
387
388
389     le = fileset_get_current();
390     if(le == NULL) {
391         return NULL;
392     }
393
394     le = g_list_previous(le);
395     if(le == NULL) {
396         return NULL;
397     }
398
399     return (fileset_entry *)le->data;
400 }
401
402
403 /* delete a single entry */
404 static void fileset_entry_delete(gpointer data, gpointer user_data _U_)
405 {
406     fileset_entry *entry = (fileset_entry *)data;
407
408     g_free( (gpointer) entry->fullname);
409     entry->fullname = NULL;
410     g_free( (gpointer) entry->name);
411     entry->name = NULL;
412     g_free(entry);
413 }
414
415
416 /* delete the whole file set */
417 void fileset_delete(void)
418 {
419     /* free the entry list */
420     if(set.entries) {
421         g_list_foreach(set.entries, fileset_entry_delete, NULL);
422         g_list_free(set.entries);
423         set.entries = NULL;
424     }
425
426     /* free the rest */
427     if(set.dirname) {
428         g_free( (gpointer) set.dirname);
429         set.dirname = NULL;
430     }
431 }
432
433 /*
434  * Editor modelines  -  http://www.wireshark.org/tools/modelines.html
435  *
436  * Local variables:
437  * c-basic-offset: 4
438  * tab-width: 8
439  * indent-tabs-mode: nil
440  * End:
441  *
442  * vi: set shiftwidth=4 tabstop=8 expandtab:
443  * :indentSize=4:tabSize=8:noTabs=true:
444  */