-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Hi Paul,
It's a bug in nfdump. The file selection required for the second file name the 
full sub directory 
hierarchy to work correctly. Find appended a fixed version of flist.c, which 
understands both 
versions of the file names.
 Recompile and reinstall nfdump and it should work afterwards.

    - Peter

- --On April 24, 2007 16:54:55 +0000 Paul Vlaar <[EMAIL PROTECTED]> wrote:

| Hi all.
|
| In nfsen, I have $SUBDIRLAYOUT = 1;, and so I have a directory structure
| that consists of <profile>/<source>/<year>/<month>/<day>/nfcapd.<timestamp>
|
| I would like to get some netflow statistics that spans multiple days, so
| first of all I try this using the nfsen web interface, by selecting a
| time window and then running the Stat TopN function over it.  The time
| window selected is 2007-04-21-15-05 to 2007-04-24-15-10 but what I see
| is that the result of the "process" only makes it to roughly 00:00 on
| 2007-04-21, no further:
|
| nfdump -R
| 
/opt/netflow/nfsen/profiles/./live/myrouter/2007/04/21/nfcapd.200704211505:nfcapd.200704241510
 -n
| 10 -s dstport/packets
|
| Top 10    Dst Port ordered by packets:
| Date first seen          Duration Proto         Dst Port    Flows  Packets    
Bytes      pps
| bps   bpp 2007-04-21 15:04:48.819 32103.274 any                 25    37326   
 39102    4.1 M
| 1     1067   109 2007-04-21 15:04:59.815 32081.786 any                 53     
3895     3977
| 284750        0       71    71 2007-04-21 17:20:26.063 23566.947 any          
     3102       17
| 224   304763        0      103  1360 2007-04-21 15:08:43.187 31285.996 any    
            113
| 150      153     6969        0        1    45 2007-04-21 15:36:10.204 
27374.256 any
| 2378       13      149   209089        0       61  1403 2007-04-21 
15:31:14.003 30067.599 any
| 2321       14      145   198457        0       52  1368 2007-04-21 
15:19:01.806 26485.057 any
| 2444       10      143   197758        0       59  1382 2007-04-21 
15:29:25.617 25955.168 any
| 1574       19      123   167863        0       51  1364 2007-04-21 
15:17:21.832 30593.236 any
| 80      113      123    11232        0        2    91 2007-04-21 15:41:44.725 
10058.798 any
| 49427        6      104   140648        0      111  1352
|
| Summary: total flows: 131499, total bytes: 96.2 M, total packets: 152557, avg 
bps: 25100, avg
| pps: 4, avg bpp: 660 Time window: 2007-04-21 15:03:58 - 2007-04-21 23:59:57
| Total flows processed: 2461470, skipped: 0, Bytes read: 127999008
| Sys: 0.480s flows/second: 5127218.6  Wall: 8.955s flows/second: 274866.4
|
|
| I want more than just that limited time window, so I try this using nfdump
| directly, and I think I need to use a -M / -R combination according to the
| man page:
|
| $ nfdump -M /opt/netflow/nfsen/profiles/./live/myrouter/2007/04/21:22:23:24 -R
| nfcapd.200704211505:nfcapd.200704241510 -n 10 -s dstport/packets
|
| Top 10    Dst Port ordered by packets:
| Date first seen          Duration Proto         Dst Port    Flows  Packets    
Bytes      pps
| bps   bpp 2007-04-21 15:04:00.499 259843.564 any                 53    5.9 M  
  7.2 M  648.8 M
| 29    20946    89 2007-04-21 15:04:32.775 259810.220 any                123   
 4.4 M    4.6 M
| 345.8 M       18    11166    75 2007-04-21 15:04:08.707 259848.148 any        
         80    1.2
| M    1.8 M  159.6 M        7     5152    86 2007-04-21 15:04:25.447 
259819.592 any
| 22   238196    1.1 M  266.9 M        4     8617   240 2007-04-21 15:04:32.007 
259810.712 any
| 2048   670209   706080   31.9 M        2     1030    47 2007-04-21 
15:04:44.947 259808.244 any
| 25   427251   476236  107.1 M        1     3458   235 2007-04-21 15:04:22.339 
259820.848 any
| 32768   343978   418339   40.9 M        1     1322   102 2007-04-21 
15:04:44.311 259798.812 any
| 2816   206620   228431   14.3 M        0      462    65 2007-04-21 
15:04:24.715 259807.524 any
| 873     8918   191816   11.6 M        0      374    63 2007-04-21 
15:07:00.917 259201.426 any
| 5432     2746   186060    9.6 M        0      309    53
|
| Summary: total flows: 22286340, total bytes: 9.9 G, total packets: 31.1 M, 
avg bps: 326373, avg
| pps: 125, avg bpp: 325 Time window: 2007-04-21 15:03:58 - 2007-04-24 15:14:58
| Total flows processed: 22286340, skipped: 0, Bytes read: 1158912336
| Sys: 5.536s flows/second: 4025618.6  Wall: 46.991s flows/second: 474265.1
|
|
| The latter try works, so my guess is that nfsen is buggy in it's call to
| nfdump for when the directory layout is not flat.  I am running version
| snapshot-20070208.
|
|
| Paul Vlaar
|
| --
| [EMAIL PROTECTED] - ISC Operations - PGP 0x294EC062
|
| -------------------------------------------------------------------------
| This SF.net email is sponsored by DB2 Express
| Download DB2 Express C - the FREE version of DB2 express and take
| control of your XML. No limits. Just data. Click to get it now.
| http://sourceforge.net/powerbar/db2/
| _______________________________________________
| Nfsen-discuss mailing list
| Nfsen-discuss@lists.sourceforge.net
| https://lists.sourceforge.net/lists/listinfo/nfsen-discuss



- --
_______ SWITCH - The Swiss Education and Research Network ______
Peter Haag,  Security Engineer,  Member of SWITCH CERT
PGP fingerprint: D9 31 D5 83 03 95 68 BA  FB 84 CA 94 AB FC 5D D7
SWITCH, Werdstrasse 2, P.O. Box,  CH-8021   Zurich, Switzerland
E-mail: [EMAIL PROTECTED] Web: http://www.switch.ch/
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.3 (Darwin)

iQCVAwUBRjDFkP5AbZRALNr/AQLhIAQAo8balbEiKheO5USU3LuWZOcvkcmAJJTz
ZROGVPqsozOgR9e2JV1YKS7gsfyCYsS+HEqwWJN0bvUeUk2y6FTUX+qXuWzPO83t
zJKOtFBZ9UwxJrfYptWDy4RXbQrrSyMemFJo2w9p2kRkjwSpSjOd4W5H809FX9yq
qaxGmD11/Yw=
=8gPp
-----END PGP SIGNATURE-----
/*
 *  This file is part of the nfdump project.
 *
 *  Copyright (c) 2004, SWITCH - Teleinformatikdienste fuer Lehre und Forschung
 *  All rights reserved.
 *  
 *  Redistribution and use in source and binary forms, with or without 
 *  modification, are permitted provided that the following conditions are met:
 *  
 *   * Redistributions of source code must retain the above copyright notice, 
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright 
notice, 
 *     this list of conditions and the following disclaimer in the 
documentation 
 *     and/or other materials provided with the distribution.
 *   * Neither the name of SWITCH nor the names of its contributors may be 
 *     used to endorse or promote products derived from this software without 
 *     specific prior written permission.
 *  
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 
 *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 
 *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 
 *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE 
 *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 
 *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 *  POSSIBILITY OF SUCH DAMAGE.
 *  
 *  $Author: peter $
 *
 *  $Id: flist.c 88 2007-03-06 08:49:26Z peter $
 *
 *  $LastChangedRevision: 88 $
 *
 */

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
#include <errno.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <fcntl.h>
#include <ctype.h>
#include <netinet/in.h>

#include "config.h"

#ifdef HAVE_STDINT_H
#       include <stdint.h>
#endif

#ifdef HAVE_FTS_H
#       include <fts.h>
#else
#       include "fts_compat.h"
#define fts_children fts_children_compat
#define fts_close fts_close_compat
#define fts_open  fts_open_compat
#define fts_read  fts_read_compat
#define fts_set   fts_set_compat
#endif

#include "nffile.h"
#include "util.h"
#include "flist.h"

/* Global vars */
extern char *CurrentIdent;


/*
 * Select a single file
 * --------------------
 * -r [/]path/to/single_file
 * Select a single file: absolute or relativ path to a single file.
 * Recursive: no
 *
 * Selecting a range of files
 * --------------------------
 * -R [/]path/to/first_file
 *  Select a range of files in directory specified by absolut or relative path 
[/]path/to/
 *  Files are selected in alphabetical order starting with 'first_file' to the 
end of 
 *  the directory.
 *
 * -R [/]path/to/first_file:last_file
 *  Select a range of files in directory specified by absolut or relative path 
[/]path/to/
 *  Files are selected in alphabetical order starting with 'first_file' and 
ending with 
 *  'last_file'.
 *
 * -R [/]path/to/directory
 *      Select all files in alphabetical order in directory specified by 
absolut or relative 
 *      path [/]path/to/directory
 *
 * Selecting files over multiple sources
 * -------------------------------------
 * -M /path/to/multiple/source1:source2[:..:sourceN]
 * It is assumed, that each source directory 'source1', 'source2' etc. exists 
in directory
 * /path/to/multiple. This will expand to multiple directories:
 *      /path/to/multiple/source1
 *      /path/to/multiple/source2
 *      ..
 *      /path/to/multiple/sourceN
 *      Each of these directories contain the same files.
 * Used in combination with -r and -R to prepend file selections.
 *
 * Select a single file from multiple directories
 * ----------------------------------------------
 *  -M /path/to/source1:source2 -r single_file
 *  Select the same file 'single_file' from each source directory: e.g.
 *  /path/to/source1/single_file
 *  /path/to/source2/single_file
 *
 *
 * Select a range of files from multiple directories
 * -------------------------------------------------
 *  -M /path/to/source1:source2[:..] -R first_file
 *  For each expanded directory specified by -M /path/to/source1:source2
 *      select a range of files as described above. Would be identical to
 *      -R /path/to/source1/first_file -R /path/to/source2/first_file
 *
 *  -M /path/to/source1:source2[:..] -R first_file:last_file
 *  For each expanded directory specified by -M /path/to/source1:source2
 *      select a range of files as described above. Would be identical to
 *      -R /path/to/source1/first_file:last_file -R 
/path/to/source2/first_file:last_file [-R .. ]
 *
 *  -M /path/to/source1:source2[:..] -R .
 *  For each expanded directory specified by -M /path/to/source1:source2
 *  select all files of the directory as described above. Would be to
 *      -R /path/to/source1 -R /path/to/source2 [-R ...]
 *
 *
 * Hierarchical file organinisation:
 * For performance reasons, files may be store in various sub directries 
instead of a 
 * single directory. These sub directories are assumed to be created in 
alpabetical order.
 * For example daily sub directories: 2006/04/01 .. 2006/04/30 as created by 
nfcapd with
 * option -S %y/%m/%d 
 *
 * Single file selection is identical to the flat file layout:
 * -r [/]path/to/sub1/sub2/sub3/single_file
 *
 * Selecting a range of files in a hierarchical file layout
 * --------------------------------------------------------
 * -R [/]path/to/sub1/sub2/first_file
 *  Select a range of files in directory specified by absolut or relative path 
 *  [/]path/to/sub1/sub2/. Files are selected in alphabetical order starting 
with 
 *  'first_file' to the end of the directory. The hierarchy has no impact here.
 *
 * -R [/]path/to/first_sub1/first_sub2/first_file:last_sub1/last_sub2/last_file
 *  Select a range of files over multiple sub directories starting at absolut 
or 
 *  relative path [/]path/to/first_sub1/first_sub2/first_file up to and 
including 
 *  [/]path/to/last_sub1/last_sub2/last_file. Files are selected in 
alphabetical 
 *  order by iterating over the required sub directory hierachy
 *      Example:
 *      -R 
/path/to/2006/03/31/nfcapd.200603312300:2006/04/01/nfcapd.200604010600
 *
 * -R [/]path/to/directory
 *      Select all files in alphabetical order in directory specified by 
absolut or relative 
 *      path [/]path/to/directory, identical to flat layout
 *
 * The same methode applies for selecting a range of files over multiple sub 
directories
 * and multiple sources.
 *
 * Example:
 * -M /path/to/source1:source2 -R 
2006/03/31/nfcapd.200603312300:2006/04/01/nfcapd.200604010600
 *
 */

/*
 * syntax for possible sub dir definitions:
 *
 * %Y    is replaced by the year with century as a decimal number.
 * %y    is replaced by the year without century as a decimal number (00-99).
 * %m    is replaced by the month as a decimal number (01-12).
 * %d    is replaced by the day of the month as a decimal number (01-31).
 * %j    is replaced by the day of the year as a decimal number (001-366).
 * %H    is replaced by the hour (24-hour clock) as a decimal number (00-23).
 * %M    is replaced by the minute as a decimal number (00-59).
 * %s    is replaced by the number of seconds since the Epoch, UTC
 * %U    is replaced by the week number of the year (Sunday as the first day
 *       of the week) as a decimal number (00-53).
 * %W    is replaced by the week number of the year (Monday as the first day
 *       of the week) as a decimal number (00-53).
 * %w    is replaced by the weekday (Sunday as the first day of the week) as
 *       a decimal number (0-6).
 * %u    is replaced by the weekday (Monday as the first day of the week) as
 *       a decimal number (1-7).
 * %F    is equivalent to ``%Y-%m-%d''.
 */

// predefined and accpeted formats
static const char *subdir_def[] = {
        "",                             // default index 0 - no subdir hierarchy
        "%Y/%m/%d",
        "%Y/%m/%d/%H",
        "%Y/%W/%u",
        "%Y/%W/%u/%H",
        "%Y/%j",
        "%Y/%j/%H",
        "%F",
        "%F/%H",
        NULL
};


// all accpeted char in a string
#define AcceptedFormatChar "YymdjHMsUWwuF"

static mode_t mode, dir_mode;
static const char *subdir_format;

static struct entry_filter_s {
        char    *first_entry;
        char    *last_entry;
        int             list_files;
} *dir_entry_filter;

#define NUM_PTR 16

static char             *first_file, *last_file, current_file[255];
static uint32_t twin_first, twin_last;
static stringlist_t source_dirs, file_list;

/* Function prototypes */
static inline int CheckTimeWindow(uint32_t t_start, uint32_t t_end, 
stat_record_t *stat_record);

static void GetFileList(char *path);

static void CleanPath(char *entry);

static void Getsource_dirs(char *dirs);

static int mkpath(char *path, mode_t mode, mode_t dir_mode, char *error, size_t 
errlen);

static char *GuessSubDir(char *channeldir, char *filename);

static char *VerifyFileRange(char *path, char *last_file);

/* Functions */

static int compare(const FTSENT **f1, const FTSENT **f2) {
    return strcmp( (*f1)->fts_name, (*f2)->fts_name);
} // End of compare

static void CleanPath(char *entry) {
char *p, *q;
size_t  len;

        // wash out any '//' in entry
        while ( (p = strstr(entry, "//")) != NULL ) {
                p++;
                q = p+1;        // q points to first char after '//'
                while ( *p )
                        *p++ = *q++;
        }

        // remove trailing '/'
        len = strlen(entry);
        if ( entry[len-1] == '/' )
                entry[len-1] = '\0';

        // wash out any '/./' in entry
        while ( (p = strstr(entry, "/./")) != NULL ) {
                p++;
                q = p+2;        // q points to first char after '/./'
                while ( *p )
                        *p++ = *q++;
        }

        // remove leading './' in entry
        if ( strstr(entry, "./") == entry ) {
                p = entry;
                q = p + 2;
                while ( *p )
                        *p++ = *q++;
        }

} // End of CleanPath

static inline int CheckTimeWindow(uint32_t t_start, uint32_t t_end, 
stat_record_t *stat_record) {

/*
        printf("t start %u %s", t_start, ctime(&t_start));
        printf("t end   %u %s", t_end, ctime(&t_end));
        printf("f start %u %s", NetflowStat.first_seen, 
ctime(&NetflowStat.first_seen));
        printf("f end   %u %s", NetflowStat.last_seen, 
ctime(&NetflowStat.last_seen));
*/

        // if no time window is set, return true
        if ( t_start == 0 )
                return 1;

        if ( stat_record->first_seen == 0 )
                return 0;

        if ( t_start >= stat_record->first_seen  && t_start <= 
stat_record->last_seen ) 
                return 1;

        if ( t_end >= stat_record->first_seen  && t_end <= 
stat_record->last_seen ) 
                return 1;

        if ( t_start < stat_record->first_seen  && t_end > 
stat_record->last_seen ) 
                return 1;

        return 0;

} // End of CheckTimeWindow

// file filter for scandir function

static int dirlevels(char *dir) {
int num;

        if ( !dir )
                return 0;

        num = 0;
        if ( dir[0] == '/' )
                dir++;

        while ( *dir ) {
                if ( *dir == '/' )
                        num++;
                dir++;
        }

        return num;

} // End of dirlevels

static void CreateDirListFilter(char *first_path, char *last_path, int 
file_list_level) {
int i;
char *p, *q, *first_mark, *last_mark;

//      printf("First Dir: '%s', first_path: '%s', last_path '%s', first_file 
'%s', last_file '%s', list_level: %i\n", 
//                      source_dirs.list[0], first_path, last_path, first_file, 
last_file, file_list_level);

        if ( file_list_level == 0 )
                return;

        if ( file_list_level < 0 ) {
                fprintf(stderr, "software error in %s line %d: %s\n", __FILE__, 
__LINE__, strerror(errno) );
                exit(250);
        }

        dir_entry_filter = (struct entry_filter_s *)malloc((file_list_level+1) 
* sizeof(struct entry_filter_s));
        if ( !dir_entry_filter ) {
                fprintf(stderr, "malloc() error in %s line %d: %s\n", __FILE__, 
__LINE__, strerror(errno) );
                exit(250);
        }

        // first default entry - the directory itself
        dir_entry_filter[0].first_entry = NULL;
        dir_entry_filter[0].last_entry  = NULL;
        dir_entry_filter[0].list_files  = 0;

        first_mark = first_path;
        last_mark  = last_path;
        // intermediate directory level filters
        for ( i=1; i<file_list_level; i++ ) {
                if ( first_mark ) {
                        p = strchr(first_mark, '/');
                        if ( p ) {
                                *p = '\0';
                                dir_entry_filter[i].first_entry = 
strdup(first_path);
                                *p++ = '/';
                                first_mark = p;
                        } else {
                                dir_entry_filter[i].first_entry = 
strdup(first_path);
                                first_mark = NULL;
                        }
                } else {
                        dir_entry_filter[i].first_entry = NULL;
                }
                dir_entry_filter[i].list_files  = 0;

                if ( last_mark ) {
                        q = strchr(last_mark, '/');
                        if ( q ) {
                                *q = '\0';
                                dir_entry_filter[i].last_entry = 
strdup(last_path);
                                *q++ = '/';
                                last_mark = q;
                        } else {
                                dir_entry_filter[i].last_entry = 
strdup(last_path);
                                last_mark = NULL;
                        }
                } else {
                        dir_entry_filter[i].last_entry = NULL;
                }
                if ( dir_entry_filter[i].first_entry && 
dir_entry_filter[i].last_entry &&
                         strcmp(dir_entry_filter[i].first_entry, 
dir_entry_filter[i].last_entry) > 0 )
                        fprintf(stderr, "WARNING: Entry '%s' > '%s'. Will not 
match anything!\n",
                                        dir_entry_filter[i].first_entry, 
dir_entry_filter[i].last_entry);

//              printf("%i first: '%s', last: '%s'\n", 
//                      i, dir_entry_filter[i].first_entry, 
dir_entry_filter[i].last_entry);
        }

        // the last level - files are listed here
        dir_entry_filter[file_list_level].first_entry = first_file;
        dir_entry_filter[file_list_level].last_entry  = last_file;
        dir_entry_filter[file_list_level].list_files  = 1;

        if ( dir_entry_filter[file_list_level].first_entry && 
dir_entry_filter[file_list_level].last_entry &&
                 strcmp(dir_entry_filter[file_list_level].first_entry, 
dir_entry_filter[file_list_level].last_entry) > 0 )
                fprintf(stderr, "WARNING: File '%s' > '%s'. Will not match 
anything!\n",
                                dir_entry_filter[file_list_level].first_entry, 
dir_entry_filter[file_list_level].last_entry);

//      printf("%i first: '%s', last: '%s'\n", 
//              file_list_level, dir_entry_filter[file_list_level].first_entry, 
dir_entry_filter[file_list_level].last_entry);

} // End of CreateDirListFilter

static void GetFileList(char *path) {
struct stat stat_buf;
char *last_file_ptr, *first_path, *last_path;
int levels_first_file, levels_last_file, file_list_level;
int     sub_index;

FTS *fts;
FTSENT *ftsent;

        CleanPath(path);

        // Check for last_file option
        last_file_ptr = strchr(path, ':');
        first_path = last_path = NULL;
        levels_first_file =  levels_last_file = 0;
        if ( last_file_ptr ) {
                // make sure we have only a single ':' in path
                if ( strrchr(path, ':') != last_file_ptr ) {
                        fprintf(stderr, "Multiple file separators ':' in path 
not allowed!\n");
                        exit(250);
                }
                *last_file_ptr++ = '\0';
                // last_file_ptr points to last_file

                if ( strlen(last_file_ptr) == 0 ) {
                        fprintf(stderr, "Missing last file option after 
':'!\n");
                        exit(250);
                }

                CleanPath(last_file_ptr);
                // make sure last_file option is not a full path
                if ( last_file_ptr[0] == '/') {
                        fprintf(stderr, "Last file name in -R list must not 
start with '/'\n");
                        exit(250);
                }
                // how may sub dir levels has last_file option?
                levels_last_file  = dirlevels(last_file_ptr);

                // if no subdirs are given for last_file, try to find out, if 
the last_file

                if ( levels_last_file == 0 ) {
                        char s[MAXPATHLEN];
                        char *r = VerifyFileRange(path, last_file_ptr);

                        if ( r != last_file_ptr ) {
                                snprintf(s, MAXPATHLEN-1, "%s/%s", r, 
last_file_ptr);
                                s[MAXPATHLEN-1] = '\0';
                                last_file_ptr = strdup(s);
                                levels_last_file  = dirlevels(last_file_ptr);
                        }
                }

        }

        levels_first_file = dirlevels(path);

        if ( source_dirs.num_strings == 0 ) {
                // No multiple sources option -M

                // path contains the path to a file/directory
                // stat this entry
                if ( stat(path, &stat_buf) ) {
                        fprintf(stderr, "stat() error '%s': %s\n", path, 
strerror(errno));
                        exit(250);
                }
                if ( !S_ISDIR(stat_buf.st_mode) && !S_ISREG(stat_buf.st_mode) ) 
{
                        fprintf(stderr, "Not a file or directory: '%s'\n", 
path);
                        exit(250);
                }

                // Check, how many levels of directory in path
                levels_first_file = dirlevels(path);

                if ( last_file_ptr ) {
                        // path is [/]path/to/any/dir|file:last_file_ptr

                        // make sure first_file is a file
                        if ( S_ISDIR(stat_buf.st_mode) ) {
                                fprintf(stderr, "Not a file: '%s'\n", path);
                                exit(250);
                        }

                        if ( levels_last_file ) {
                                // we have levels_last_file number of sub dirs 

                                // sub dir levels of first_file mus have at 
least the same number of levels as last_file
                                if ( levels_first_file < levels_last_file ) {
                                        fprintf(stderr, "Number of sub dirs for 
sub level hierarchy for file list -R do not match\n");
                                        exit(250);
                                }
                                if ( levels_first_file == levels_last_file ) {
                                        char *p, *q;
                                        // path = 
[/]sub1[/..]/first_file:sub1[/...]/last_file
                                        if ( path[0] == '/' ) {
                                                // this is rather strange, but 
strctly spoken, valid anyway
                                                InsertString(&source_dirs, "/");
                                                path++;
                                        } else {
                                                InsertString(&source_dirs, ".");
                                        }

                                        // path = 
sub_first[/..]/first_file:sub_last[/...]/last_file
                                        p = strrchr(path, '/');
                                        q = strrchr(last_file_ptr, '/');
                                        if ( !p || !q ) {
                                                // this should never happen
                                                fprintf(stderr, "software error 
in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
                                                exit(250);
                                        }
                                        *p++ = '\0';
                                        *q++ = '\0';
                                        first_file = strdup(p);
                                        last_file = strdup(q);
                                        file_list_level = levels_last_file + 1;
                                        first_path = path;
                                        last_path  = last_file_ptr;

                                } else {
                                        // path = 
[/]path/to/sub_first[/..]/first_file:sub_last[/...]/last_file
                                        int i;
                                        char *p, *r, *s;

                                        p = strrchr(path, '/');
                                        // levels_first_file > levels_last_file

                                        // step back the number of sub dirs in 
first_file
                                        for ( i=0; i<levels_last_file; i++ ) {
                                                do {
                                                        p--;
                                                } while ( p >= path && *p != 
'/');
                                        }
                                        *p++ = '\0';

                                        InsertString(&source_dirs, path);

                                        r = strrchr(p, '/');
                                        s = strrchr(last_file_ptr, '/');
                                        if ( !r || !s ) {
                                                // this must never happen
                                                fprintf(stderr, "software error 
in %s line %d: %s\n", __FILE__, __LINE__, strerror(errno) );
                                                exit(250);
                                        }
                                        *r++ = '\0';
                                        *s++ = '\0';
                                        first_file = strdup(r);
                                        last_file = strdup(s);
                                        // files are listed at this sub dir 
level
                                        file_list_level = levels_last_file + 1;
                                        first_path = p;
                                        last_path  = last_file_ptr;

                                }

                        } else {
                                // we have no sub dir levels given

                                // path is [/]path/to/any/file
                                char *p = strrchr(path, '/');

                                if ( p ) {
                                        // path is 
[/]path/to/any/first_file:last_file
                                        *p++ = '\0';
                                        // path is the direcory containing all 
the files
                                        InsertString(&source_dirs, path);
                                        first_file = strdup(p);
                                } else {
                                        // path is first_file:last_file
                                        InsertString(&source_dirs, ".");
                                        first_file = strdup(path);
                                }
                                // set last_file filter
                                last_file  = strdup(last_file_ptr);
                                // in any case we list the files of directory 
level 1
                                file_list_level = 1;
                        }
                } else {
                        // path is [/]path/to/any/dir|file
                        if ( S_ISDIR(stat_buf.st_mode) ) {
                                // path is [/]path/to/any/dir
                                // list all files in this directory
                                InsertString(&source_dirs, path);
                                first_file = NULL;
                                file_list_level = 0;
                        } else {
                                // path is [/]path/to/any/file
                                char *p = strrchr(path, '/');
                                if ( p ) {
                                        // path is [/]path/to/any/file
                                        *p++ = '\0';
                                        // path is the direcory containing all 
the files
                                        InsertString(&source_dirs, path);
                                        first_file = strdup(p);
                                } else {
                                        // path is file
                                        InsertString(&source_dirs, ".");
                                        first_file = strdup(path);
                                }
                                // in any case we list the files of directory 
level 1
                                file_list_level = 1;
                        }
                        // in any case, no last_file filter
                        last_file  = NULL;
                }

        } else {
                char pathbuff[MAXPATHLEN];
                // multiple sources option -M given
                if ( path[0] == '/') {
                        fprintf(stderr, "File list -R must not start with '/' 
when combined with a source list -M\n");
                        exit(250);
                }

                // special case for all files in directory
                if ( strcmp(path, ".") == 0 ) {
                        first_file = NULL;
                        last_file  = NULL;
                        file_list_level = 0;
                } else {
                        // pathbuff contains the path to a file/directory, 
compiled using the first entry
                        // in the source_dirs
                        snprintf(pathbuff, MAXPATHLEN-1, "%s/%s", 
source_dirs.list[0], path);
                        pathbuff[MAXPATHLEN-1] = '\0';

                        // pathbuff must point to a file
                        if ( stat(pathbuff, &stat_buf) ) {
                                if ( errno == ENOENT ) {
                                        // file not found - try to guess a 
possible subdir
                                        char *sub_dir = 
GuessSubDir(source_dirs.list[0], path);
                                        if ( sub_dir ) {        // subdir found
                                                snprintf(pathbuff, 
MAXPATHLEN-1, "%s/%s", sub_dir, path);
                                                pathbuff[MAXPATHLEN-1] = '\0';
                                                // update path
                                                path = strdup(pathbuff);
                                                free(sub_dir);

                                                // need guessing subdir with 
last_file too
                                                if ( last_file_ptr ) {
                                                        sub_dir = 
GuessSubDir(source_dirs.list[0], last_file_ptr);
                                                        if ( sub_dir ) {        
// subdir found
                                                                
snprintf(pathbuff, MAXPATHLEN-1, "%s/%s", sub_dir, last_file_ptr);
                                                                
pathbuff[MAXPATHLEN-1] = '\0';
                                                                last_file_ptr = 
strdup(pathbuff);
                                                                free(sub_dir);

                                                                // update dir 
levels of extended file path
                                                                
levels_last_file  = dirlevels(last_file_ptr);
                                                        } else {
                                                                fprintf(stderr, 
"'%s': %s\n", last_file_ptr, "File not found!");
                                                                exit(250);
                                                        }
                                                }

                                        } else {        // no file in any 
possible subdir found
                                                fprintf(stderr, "stat() error 
'%s': %s\n", pathbuff, "File not found!");
                                                exit(250);
                                        }
                                } else {        // Any other stat error
                                        fprintf(stderr, "stat() error '%s': 
%s\n", pathbuff, strerror(errno));
                                        exit(250);
                                }
                        } else if ( !S_ISREG(stat_buf.st_mode) ) {
                                fprintf(stderr, "Not a file : '%s'\n", 
pathbuff);
                                exit(250);
                        }

                        // Check, how many levels of directory in path
                        levels_first_file = dirlevels(path);

                        if ( last_file_ptr ) {
                                // path is path/to/any/first_file:last_file_ptr
                                char *p, *q;

                                // the number of sub dirs must be eqal for 
first_file and last_file
                                if ( levels_first_file != levels_last_file ) {
                                        fprintf(stderr, "Number of sub dirs 
must agree in '%s' and '%s'\n", path, last_file_ptr);
                                        exit(250);
                                }

                                p = strrchr(path, '/');
                                if ( p ) {
                                        // path is fist_sub/to/any/first_file
                                        // recursive all files in sub dirs
                                        file_list_level = dirlevels(path) + 1;
                                        *p++ = '\0';
                                        first_file = strdup(p);
                                        first_path = path;
                                } else {
                                        // path is first_file
                                        first_file = strdup(path);
                                        file_list_level = 1;
                                }

                                q = strrchr(last_file_ptr, '/');
                                if ( q ) {
                                        *q++ = '\0';
                                        last_file = strdup(q);
                                        last_path  = last_file_ptr;
                                } else {
                                        last_file = strdup(last_file_ptr);
                                }

                        } else {
                                // path is path/to/any/first_file
                                char *p = strrchr(path, '/');
                                if ( p ) {
                                        // path is fist_sub/to/any/first_file
                                        // recursive all files in sub dirs
                                        file_list_level = dirlevels(path) + 1;
                                        *p++ = '\0';
                                        first_file = strdup(p);
                                        first_path = path;
                                } else {
                                        // path is first_file
                                        first_file = strdup(path);
                                        file_list_level = 1;
                                }
                                last_file  = NULL;
                        }
                }
        }

/*
printf("first_file %s\n", first_file ? first_file : "<none>");
printf("last_file %s\n", last_file ? last_file : "<none>");
printf("first_path %s\n", first_path ? first_path : "<none>");
printf("last_path %s\n", last_path ? last_path : "<none>");
printf("file_list_level: %i\n", file_list_level);
*/
        CreateDirListFilter(first_path, last_path, file_list_level );

        // last entry must be NULL
        InsertString(&source_dirs, NULL);
        fts = fts_open(source_dirs.list, FTS_LOGICAL,  compare);
        sub_index = 0;
        while ( (ftsent = fts_read(fts)) != NULL) {
                int fts_level = ftsent->fts_level;
                char *fts_path;

// printf("DBG: %u %i %s %s\n", ftsent->fts_info, ftsent->fts_level, 
ftsent->fts_path, ftsent->fts_name);

                if ( fts_level == 0 ) {
                        sub_index = ftsent->fts_pathlen + 1;
                        continue;
                }

                if ( ftsent->fts_pathlen < sub_index ) {
                        printf("ERROR: fts_pathlen error at %s line %d\n", 
__FILE__, __LINE__);
                        exit(250);
                }
                fts_path = &ftsent->fts_path[sub_index];

/*
if ( file_list_level ) 
printf("DGB: short fts: '%s', filer_first: '%s', filter_last: '%s'\n", 
                                        fts_path, 
dir_entry_filter[fts_level].first_entry , 
dir_entry_filter[fts_level].last_entry);
*/
                switch (ftsent->fts_info) {
                        case FTS_D:
                                // dir entry pre descend
                                if ( file_list_level && file_list_level && (
                                        ( 
dir_entry_filter[fts_level].first_entry &&
                                                ( strcmp(fts_path, 
dir_entry_filter[fts_level].first_entry ) < 0 ) ) ||
                                        ( 
dir_entry_filter[fts_level].last_entry && 
                                                ( strcmp(fts_path, 
dir_entry_filter[fts_level].last_entry ) > 0 ) ) 
                                   ))
                                        fts_set(fts, ftsent, FTS_SKIP );

                                break;
                        case FTS_DP:
                                break;
                        case FTS_F:
                                // file entry
// printf("==> Check: %s\n", ftsent->fts_name);

                                // skip stat file
                                if ( strcmp(ftsent->fts_name, ".nfstat") == 0 ||
                                         strncmp(ftsent->fts_name, 
"nfcapd.current", 14) == 0)
                                        continue;
                                if ( strstr(ftsent->fts_name, ".stat") != NULL )
                                        continue;

                                if ( file_list_level && (
                                        ( fts_level != file_list_level ) ||
                                        ( 
dir_entry_filter[fts_level].first_entry && 
                                                ( strcmp(ftsent->fts_name, 
dir_entry_filter[fts_level].first_entry) < 0 ) ) ||
                                        ( 
dir_entry_filter[fts_level].last_entry &&
                                                ( strcmp(ftsent->fts_name, 
dir_entry_filter[fts_level].last_entry) > 0 ) )
                                   ) )
                                        continue;

// printf("==> Listed: %s\n", ftsent->fts_path);
                                InsertString(&file_list, ftsent->fts_path);

                                break;
                }

        }
    fts_close(fts);

} // End of GetFileList

/*
 * Get the list of directories 
 * dirs: user supplied parameter: /any/path/dir1:dir2:dir3:...
 *              source_dirs must result in 
 *              /any/path/dir1
 *              /any/path/dir2
 *              /any/path/dir3
 *      /any/path is dir prefix, which may be NULL e.g. dir1:dir2:dir3:...
 *      dir1, dir2 etc entrys
 */
void Getsource_dirs(char *dirs) {
struct stat stat_buf;
char    *p, *q, *dirprefix;
char    path[MAXPATHLEN];

        q = strchr(dirs, ':');
        if ( q ) { // we have /path/to/firstdir:dir1:dir2:...
                *q = 0;
                p = strrchr(dirs, '/');
                if ( p ) {
                        *p++ = 0;       // p points now to the first name in 
the dir list
                        dirprefix = dirs;
                } else  { // we have a source_dirs in current directory
                        p = dirs;       // p points now to the first name in 
the dir list
                        dirprefix = ".";        // current directory
                }
                *q = ':';       // restore ':' in source_dirs

                while ( p ) { // iterate over all elements in the dir list
                        q = strchr(p, ':');
                        if ( q ) 
                                *q = 0;

                        // p point to a dir name
                        snprintf(path, 1023, "%s/%s", dirprefix, p);
                        path[MAXPATHLEN-1] = 0;
                        if ( stat(dirs, &stat_buf) ) {
                                fprintf(stderr, "Can't stat '%s': %s\n", path, 
strerror(errno));
                                return;
                        }
                        if ( !S_ISDIR(stat_buf.st_mode) ) {
                                fprintf(stderr, "Not a directory: '%s'\n", 
path);
                                return;
                        }

                        // save path into source_dirs
                        InsertString(&source_dirs, path);

                        p = q ? q + 1 : NULL;
                }

        } else { // we have only one directory
                if ( stat(dirs, &stat_buf) ) {
                        fprintf(stderr, "Can't stat '%s': %s\n", dirs, 
strerror(errno));
                        return;
                }
                if ( !S_ISDIR(stat_buf.st_mode) ) {
                        fprintf(stderr, "Not a directory: '%s'\n", dirs);
                        return;
                }

                // save the path into source_dirs
                InsertString(&source_dirs, dirs);
        }

} // End of Getsource_dirs

void SetupInputFileSequence(char *multiple_dirs, char *single_file, char 
*multiple_files) {
char *error;
int     fd;

        twin_first  = 0;
        twin_last   = 0xffffffff;

        first_file      = NULL;
        last_file       = NULL;

        InitStringlist(&source_dirs, NUM_PTR);
        InitStringlist(&file_list, 64);

        if ( multiple_dirs ) 
                Getsource_dirs(multiple_dirs);

        if ( multiple_files ) {
                // use multiple files
                GetFileList(multiple_files);

                // get time window spanning all the files 
                if ( file_list.num_strings ) {
                        stat_record_t *stat_ptr;

                        fd = OpenFile(file_list.list[0], &stat_ptr, &error);    
// read the stat record
                        if ( error != NULL ) {
                                fprintf(stderr, "%s\n", error);
                                exit(250);
                        }
                        close(fd);
                        twin_first = stat_ptr->first_seen;
                        fd = OpenFile(file_list.list[file_list.num_strings-1], 
&stat_ptr, &error);      // read the stat record of last file
                        if ( error != NULL ) {
                                fprintf(stderr, "%s\n", error);
                                exit(250);
                        }
                        close(fd);
                        twin_last  = stat_ptr->last_seen;
                }

        } else if ( single_file ) {
                CleanPath(single_file);

                if ( source_dirs.num_strings == 0 ) {
                                InsertString(&file_list, single_file);
                } else {
                        int i;

                        if ( single_file[0] == '/' ) {
                                fprintf(stderr, "File -r must not start with 
'/', when combined with a source list -M\n");
                                exit(250);
                        }

                        for ( i=0; i<source_dirs.num_strings; i++ ) {
                                char s[MAXPATHLEN];
                                struct stat stat_buf;

                                snprintf(s, MAXPATHLEN-1, "%s/%s", 
source_dirs.list[i], single_file);
                                s[MAXPATHLEN-1] = '\0';
                                if ( stat(s, &stat_buf) ) {
                                        if ( errno == ENOENT ) {
                                                // file not found - try to 
guess subdir
                                                char *sub_dir = 
GuessSubDir(source_dirs.list[i], single_file);
                                                if ( sub_dir ) {        // 
subdir found
                                                        snprintf(s, 
MAXPATHLEN-1, "%s/%s/%s", source_dirs.list[i], sub_dir, single_file);
                                                        s[MAXPATHLEN-1] = '\0';
                                                        
InsertString(&file_list, s);
                                                } else {        // no subdir 
found
                                                        fprintf(stderr, "stat() 
error '%s': %s\n", s, "File not found!");
                                                }
                                        } else {        // Any other stat error
                                                fprintf(stderr, "stat() error 
'%s': %s\n", s, strerror(errno));
                                                exit(250);
                                        }
                                } else {        // stat() successful
                                        if ( !S_ISREG(stat_buf.st_mode) ) {
                                                fprintf(stderr, "Skip non file 
entry: '%s'\n", s);
                                        } else {
                                                InsertString(&file_list, s);
                                        }
                                }
                        }
                }

        } else // else use stdin
                InsertString(&file_list, NULL);

} // End of SetupInputFileSequence

char *GetCurrentFilename(void) {
        return current_file;
} // End of GetCurrentFilename

int GetNextFile(int current, time_t twin_start, time_t twin_end, stat_record_t 
**stat_record) {
stat_record_t *stat_ptr;
char *error;
int fd;
static int cnt;

        // is it first time init ?
        if ( current < 0 ) {
                cnt  = 0;
        }

        // close current file before open the next one
        // stdin ( current = 0 ) is not closed
        if ( current > 0 ) {
                close(current);
                current_file[0] = '\0';
        }

        // no or no more files available
        if ( file_list.num_strings == cnt ) {
                if ( stat_record )
                        *stat_record = NULL;
                return EMPTY_LIST;
        }

/*
        while ( cnt < file_list.num_strings ) {
                printf("Process: '%s'\n", file_list.list[cnt++]);
        }
*/

        while ( cnt < file_list.num_strings ) {
                fd = OpenFile(file_list.list[cnt], &stat_ptr, &error);  // Open 
the file
                cnt++;

                // stdin
                if ( fd == STDIN_FILENO ) {
                        if ( stat_record )
                                *stat_record = NULL;
                        CurrentIdent = "none";
                        return fd;
                }

                if ( fd > 0 && CheckTimeWindow(twin_start, twin_end, stat_ptr) 
) {
                        // printf("Return file: %s\n", string);
                        if ( stat_record ) 
                                *stat_record = stat_ptr;
                        return fd;
                } 
                close(fd);
                if ( error != NULL ) 
                        fprintf(stderr, "%s\n", error);
        }

        if ( stat_record )
                *stat_record = NULL;

        return EMPTY_LIST;

} // End of GetNextFile


int InitHierPath(int num) {
int i;

        subdir_format = NULL;

        i=0;
        while ( subdir_def[i] != NULL ) {
                if ( i == num )
                        break;
                i++;
        }
        if ( subdir_def[i] == NULL ) {
                fprintf(stderr, "No such subdir level %i\n", num);
                return 0;
        }

        subdir_format = subdir_def[i];

    /*
     * The default file mode is a=rwx (0777) with selected permissions
     * removed in accordance with the file mode creation mask.  For
     * intermediate path name components, the mode is the default modified
     * by u+wx so that the subdirectories can always be created.
     */

        // get umask
        mode = umask(0);
        umask(mode);

    mode = 0777 & ~mode;
    dir_mode = mode | S_IWUSR | S_IXUSR;

        return 1;

} // End of InitHierPath

static char *VerifyFileRange(char *path, char *last_file) {
char *p, *q, *r;

        r = strdup(path);
        p = strrchr(r, '/');
        while ( p ) {
                *p = '\0';

                q = GuessSubDir(r, last_file);
                if ( q ) {
                        free(r);
                        return q;
                }
                p = strrchr(r, '/');
        }

        free(r);
        return last_file;

} // End of VerifyFileRange

static char *GuessSubDir(char *channeldir, char *filename) {
char s[MAXPATHLEN];
struct  tm *t_tm;
int     i;

        if ( strlen(filename) == 19 && (strncmp(filename, "nfcapd.", 7) == 0) ) 
{
                char *p  = &filename[7];
                time_t t = ISO2UNIX(p);
                t_tm = localtime(&t);
        } else
                return NULL;

        i = 0;
        // if the file exists, it must be in any of the possible subdirs
        // so try one after the next - one will match
        while ( subdir_def[i] ) {
                char const *sub_fmt = subdir_def[i];
                char subpath[255];
                struct stat stat_buf;
                strftime(subpath, 254, sub_fmt, t_tm);
                subpath[254] = '\0';

                snprintf(s, MAXPATHLEN-1, "%s/%s/%s", channeldir, subpath, 
filename);
                if ( stat(s, &stat_buf) == 0 && S_ISREG(stat_buf.st_mode) ) {
                        // found file in subdir 
                        return strdup(subpath);
                }
                i++;
        }

        return NULL;

} // End of GuessSubDir

char *SetupSubDir(struct  tm *now, char *error, size_t errlen ) {
static char subpath[255];
struct stat stat_buf;
size_t  len;
int err;

        error[0] = '\0';

        len = strftime(subpath, 254, subdir_format, now);

        if ( len == 0 ) {
                return NULL;
        }

        // our cwd is basedir ( -l ) so test if, dir exists
        if ( stat(subpath, &stat_buf) == 0 ) {
                if ( S_ISDIR(stat_buf.st_mode) ) {
                        // sub directory already exists
                        return subpath;
                } else {
                        // an eentry with this name exists, but it's not a 
directory
                        snprintf(error, errlen, "Path '%s': %s ", subpath, 
strerror(ENOTDIR));
                        return NULL;
                }
        }

        // no such entry exists - try to create the directory, assuming path 
below exists
        err = mkdir(subpath, dir_mode);
        if ( err == 0 ) // success
                return subpath;

        // else errno is set
        if ( errno == ENOENT ) { // we need to create intermediate directories 
as well
                err = mkpath(subpath, mode, dir_mode, error, errlen);
                if ( err == 0 ) // creation was successful
                        return subpath;
        } else {
                snprintf(error, errlen, "mkdir() error for '%s': %s\n", 
subpath, strerror(errno));
        }

        // anything else failed and error string is set
        return NULL;

} // End of SetupSubDir

/*
 * mkpath -- create directories.
 *  path     - path
 *  mode     - file mode of terminal directory
 *  dir_mode - file mode of intermediate directories
 */
static int mkpath(char *path, mode_t mode, mode_t dir_mode, char *error, size_t 
errlen) {
struct stat sb;
char *slash;
int done = 0;

    slash = path;

    while (!done) {
        slash += strspn(slash, "/");
        slash += strcspn(slash, "/");

        done = (*slash == '\0');
        *slash = '\0';

        if (stat(path, &sb)) {
            if (errno != ENOENT || (mkdir(path, done ? mode : dir_mode) && 
errno != EEXIST)) {
                                snprintf(error, errlen, "mkdir() error for 
'%s': %s\n", path, strerror(errno));
                return (-1);
            }
        } else if (!S_ISDIR(sb.st_mode)) {
                        snprintf(error, errlen, "Path '%s': %s ", path, 
strerror(ENOTDIR));
            return (-1);
        }

        *slash = '/';
    }

    return (0);

} // End of mkpath

Attachment: pgpMFeyvtvEjT.pgp
Description: PGP signature

-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
_______________________________________________
Nfsen-discuss mailing list
Nfsen-discuss@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/nfsen-discuss

Reply via email to