wireshark/fileset.c
Jeff Morriss a5cee04fad Move the file utility functions from wiretap to libwsutil so that
libwireshark (and the plugins using those functions) do not depend on
wiretap on Windows.

While doing that, rename the eth_* functions to ws_*.

svn path=/trunk/; revision=25354
2008-05-22 15:46:27 +00:00

392 lines
8.9 KiB
C

/* fileset.c
* Routines for handling file sets
*
* $Id$
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#endif
#ifdef HAVE_SYS_STAT_H
# include <sys/stat.h>
#endif
#ifdef HAVE_SYS_WAIT_H
# include <sys/wait.h>
#endif
#include <string.h>
#include <ctype.h>
#include <glib.h>
#include <wsutil/file_util.h>
#include "globals.h"
#include <epan/filesystem.h>
#include "fileset.h"
typedef struct _fileset {
GList *entries;
const char *dirname;
} fileset;
/* this is the fileset's global data */
fileset set = { NULL, NULL};
/* is this a probable file of a file set (does the naming pattern match)? */
gboolean
fileset_filename_match_pattern(const char *fname)
{
char *pfx;
int baselen;
int minlen = strlen("_00001_20050418010750");
char *filename;
/* d:\dir1\test_00001_20050418010750.cap */
filename = g_strdup(get_basename(fname));
/* test_00001_20050418010750.cap */
pfx = strrchr(filename, '.');
if(pfx == NULL) { /* suffix is optional */
pfx = filename + strlen(filename);
}
/* test_00001_20050418010750 */
*pfx = '\0';
/* filename long enough? */
baselen = strlen(filename);
if(baselen < minlen) {
g_free(filename);
return FALSE;
}
/* there must be two underscores at special places */
if(filename[baselen-minlen] != '_' || filename[baselen-minlen+6] != '_') {
g_free(filename);
return FALSE;
}
/* replace the two underscores by digits */
filename[baselen-minlen] = '0';
filename[baselen-minlen+6] = '0';
/* we should have only digits now */
while(minlen--) {
baselen--;
if(!isdigit( (guchar) filename[baselen])) {
g_free(filename);
return FALSE;
}
}
g_free(filename);
/* ok, seems to be good */
return TRUE;
}
/* test, if both files could be in the same file set */
/* (the filenames must already be in correct shape) */
gboolean
fileset_is_file_in_set(const char *fname1, const char *fname2)
{
char *pfx1;
char *pfx2;
char *dup_f1;
char *dup_f2;
int minlen = strlen("_00001_20050418010750");
/* just to be sure ... */
g_assert(fileset_filename_match_pattern(fname1));
g_assert(fileset_filename_match_pattern(fname2));
dup_f1 = g_strdup(fname1);
dup_f2 = g_strdup(fname2);
pfx1 = strrchr(dup_f1, '.');
pfx2 = strrchr(dup_f2, '.');
/* suffix is optional */
if (!pfx1) pfx1 = dup_f1 + strlen(dup_f1);
if (!pfx2) pfx2 = dup_f2 + strlen(dup_f2);
/* the optional suffix (file extension) must be equal */
if(strcmp(pfx1, pfx2) != 0) {
g_free(dup_f1);
g_free(dup_f2);
return FALSE;
}
*(pfx1-minlen) = '\0';
*(pfx2-minlen) = '\0';
if(strcmp(dup_f1, dup_f2) != 0) {
g_free(dup_f1);
g_free(dup_f2);
return FALSE;
}
g_free(dup_f1);
g_free(dup_f2);
return TRUE;
}
/* we know this file is part of the set, so add it */
static fileset_entry *
fileset_add_file(const char *dirname, const char *fname, gboolean current)
{
int fh, result;
struct stat buf;
char *path;
fileset_entry *entry = NULL;
path = g_strdup_printf("%s%s", dirname, fname);
fh = ws_open( path, O_RDONLY, 0000 /* no creation so don't matter */);
if(fh != -1) {
/* Get statistics */
result = fstat( fh, &buf );
/* Show statistics if they are valid */
if( result == 0 ) {
entry = g_malloc(sizeof(fileset_entry));
entry->fullname = g_strdup(path);
entry->name = g_strdup(fname);
entry->ctime = buf.st_ctime;
entry->mtime = buf.st_mtime;
entry->size = buf.st_size;
entry->current = current;
set.entries = g_list_append(set.entries, entry);
}
ws_close(fh);
}
g_free(path);
return entry;
}
/* compare two list entries by creation date/time (through filename) */
static gint
fileset_sort_compare(gconstpointer a, gconstpointer b)
{
const fileset_entry *entry_a = a;
const fileset_entry *entry_b = b;
return strcmp(entry_a->name, entry_b->name);
}
/* add all file set entries to the dialog */
void fileset_update_dlg(void)
{
GList *le;
/* add all entires to the dialog */
le = g_list_first(set.entries);
while(le) {
fileset_dlg_add_file(le->data);
le = g_list_next(le);
}
}
/* walk through the directory of the loaded file and add every file matching the current file */
void
fileset_add_dir(const char *fname)
{
ETH_DIR *dir; /* scanned directory */
ETH_DIRENT *file; /* current file */
const char *name;
fileset_entry *entry;
GString *dirname;
gchar *fname_dup;
/* get (convert) directory name, but don't touch the given string */
fname_dup = get_dirname(g_strdup(fname));
dirname = g_string_new(fname_dup);
g_free(fname_dup);
set.dirname = g_strdup(dirname->str);
dirname = g_string_append_c(dirname, G_DIR_SEPARATOR);
/* is the current file probably a part of any fileset? */
if(fileset_filename_match_pattern(fname)) {
/* yes, go through the files in the directory and check if the file in question is part of the current file set */
if ((dir = ws_dir_open(dirname->str, 0, NULL)) != NULL) {
while ((file = ws_dir_read_name(dir)) != NULL) {
name = ws_dir_get_name(file);
if(fileset_filename_match_pattern(name) && fileset_is_file_in_set(name, get_basename(fname))) {
fileset_add_file(dirname->str, name, strcmp(name, get_basename(fname))== 0 /* current */);
}
} /* while */
ws_dir_close(dir);
} /* if */
} else {
/* no, this is a "standalone file", just add this one */
entry = fileset_add_file(dirname->str, get_basename(fname), TRUE /* current */);
/* don't add the file to the dialog here, this will be done in fileset_update_dlg() below */
}
g_string_free(dirname, TRUE /* free_segment */);
/* sort entries by creation time */
set.entries = g_list_sort(set.entries, fileset_sort_compare);
fileset_update_dlg();
}
/* get current directory name */
const char *
fileset_get_dirname(void)
{
return set.dirname;
}
/* get the current list entry, or NULL */
static GList *
fileset_get_current(void)
{
GList *le;
fileset_entry *entry;
/* add all entires to the dialog */
le = g_list_first(set.entries);
while(le) {
entry = le->data;
if(entry->current) {
return le;
}
le = g_list_next(le);
}
return NULL;
}
/* get the file set entry after the current one, or NULL */
fileset_entry *
fileset_get_next(void)
{
GList *le;
le = fileset_get_current();
if(le == NULL) {
return NULL;
}
le = g_list_next(le);
if(le == NULL) {
return NULL;
}
return le->data;
}
/* get the file set entry before the current one, or NULL */
fileset_entry *
fileset_get_previous(void)
{
GList *le;
le = fileset_get_current();
if(le == NULL) {
return NULL;
}
le = g_list_previous(le);
if(le == NULL) {
return NULL;
}
return le->data;
}
/* delete a single entry */
static void fileset_entry_delete(gpointer data, gpointer user_data _U_)
{
fileset_entry *entry = data;
g_free( (gpointer) entry->fullname);
entry->fullname = NULL;
g_free( (gpointer) entry->name);
entry->name = NULL;
}
/* delete the whole file set */
void fileset_delete(void)
{
/* free the entry list */
if(set.entries) {
g_list_foreach(set.entries, fileset_entry_delete, NULL);
g_list_free(set.entries);
set.entries = NULL;
}
/* free the rest */
if(set.dirname) {
g_free( (gpointer) set.dirname);
set.dirname = NULL;
}
}