1 /*
2  * Copyright (c) 2001 Mark Fullmer and The Ohio State University
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  *      $Id: ftfile.c,v 1.24 2003/02/13 02:38:42 maf Exp $
27  */
28 
29 #include "ftconfig.h"
30 #include "ftlib.h"
31 
32 #include <sys/time.h>
33 #include <sys/types.h>
34 #include <sys/uio.h>
35 #include <sys/resource.h>
36 #include <sys/stat.h>
37 #include <dirent.h>
38 #include <errno.h>
39 #include <syslog.h>
40 #include <limits.h>
41 #include <unistd.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <time.h>
45 #include <fcntl.h>
46 
47 #if HAVE_STRINGS_H
48  #include <strings.h>
49 #endif
50 #if HAVE_STRING_H
51   #include <string.h>
52 #endif
53 
54 int load_dir(char *prefix, struct ftfile_entries *fte, int flags, int *depth);
55 
56 #define debug 0
57 
58 /*
59  * function: ftfile_entry_new
60  *
61  * allocate ftfile_entry struct.  see also ftfile_entry_free
62 */
ftfile_entry_new(int len)63 struct ftfile_entry *ftfile_entry_new(int len)
64 {
65   struct ftfile_entry *e;
66 
67   if (!(e = (struct ftfile_entry*)malloc(sizeof (struct ftfile_entry))))
68     return (struct ftfile_entry*)0L;
69 
70   bzero(e, sizeof *e);
71 
72   if (!(e->name = (char*)malloc(len+1))) {
73     free (e);
74     return (struct ftfile_entry*)0L;
75   }
76 
77   return e;
78 
79 } /* ftfile_entry_new */
80 
81 /*
82  * function: ftfile_entry_free
83  *
84  * deallocate ftfile_entry struct allocated by ftfile_entry_new()
85 */
ftfile_entry_free(struct ftfile_entry * entry)86 void ftfile_entry_free(struct ftfile_entry *entry)
87 {
88   free(entry->name);
89   free(entry);
90 } /* ftfile_entry_free */
91 
92 /*
93  * function: ftfile_loadfile
94  *
95  * Load filename into the file entries data structures
96  * Files that do not match the flow-tools naming convention or
97  * do not have the correct magic word in the header are not loaded
98  * to prevent accidental removal.
99  *
100  * returns: < 0 error
101  *          >= 0 ok
102  */
ftfile_loadfile(struct ftfile_entries * fte,char * fname,int flags)103 int ftfile_loadfile(struct ftfile_entries *fte, char *fname, int flags)
104 {
105   struct stat sb;
106   struct ftfile_entry *n1, *n2;
107   struct ftiheader head;
108   int fd, done, len;
109 
110   if (flags & FT_FILE_INIT)
111     FT_TAILQ_INIT(&fte->head);
112 
113   if (fname[0]) {
114 
115     /* skip anything that doesn't begin with "ft" "cf" and "tmp" */
116     if (flags & FT_FILE_CHECKNAMES)
117       if ((strncmp(fname, "ft", 2)) &&
118          (strncmp(fname, "cf", 2)) &&
119          (strncmp(fname, "tmp", 3))) {
120         fterr_warnx("ignoring: %s", fname);
121         return 0;
122       }
123 
124       /* skip tmp files? */
125       if (flags & FT_FILE_SKIPTMP)
126         if (!strncmp(fname, "tmp", 3))
127           return 0;
128 
129     /* make sure the file is actually a flow file */
130     if ((fd = open (fname,  O_RDONLY, 0)) == -1) {
131       fterr_warn("open(%s)", fname);
132       return 0;
133     }
134 
135     if (fstat(fd, &sb) < 0) {
136       fterr_warn("fstat(%s)", fname);
137       close(fd);
138       return -1;
139     }
140 
141     if (ftiheader_read(fd, &head) < 0) {
142       fterr_warnx("ftiheader_read(%s): Failed, ignoring file.", fname);
143       close(fd);
144       return 0;
145     }
146 
147     close (fd);
148 
149   } else { /* empty filename -- stdin */
150 
151     bzero(&head, sizeof head);
152     bzero(&sb, sizeof sb);
153 
154   }
155 
156   len = strlen(fname);
157 
158   /* insert the entry in the list sorted by start time of flow file */
159   done = 0;
160 
161   if (flags & FT_FILE_SORT) {
162 
163     FT_TAILQ_FOREACH(n1, &fte->head, chain) {
164 
165       if (n1->start > head.cap_start) {
166 
167         if (!(n2 = ftfile_entry_new(len))) {
168           fterr_warnx("ftfile_entry_new(): failed");
169           return -1;
170         }
171 
172         n2->size = sb.st_size;
173         n2->start = head.cap_start;
174         strcpy(n2->name, fname);
175 
176         FT_TAILQ_INSERT_BEFORE(n1, n2, chain);
177         done = 1;
178         break;
179       }
180     } /* FT_TAILQ_FOREACH */
181   } /* FT_FILE_SORT */
182 
183   if ((!done) || (!(flags & FT_FILE_SORT))) {
184 
185     if (!(n2 = ftfile_entry_new(len))) {
186       fterr_warnx("ftfile_entry_new(): failed");
187       return -1;
188     }
189 
190     n2->size = sb.st_size;
191     n2->start = head.cap_start;
192     strcpy(n2->name, fname);
193     FT_TAILQ_INSERT_TAIL(&fte->head, n2, chain);
194 
195   } /* !done or !FT_FILE_SORT */
196 
197   fte->num_bytes += sb.st_size;
198   fte->num_files ++;
199 
200   return 0;
201 
202 } /* ftfile_loadfile */
203 
204 /*
205  * function: ftfile_loaddir
206  *
207  * Load directory contents into the file entries data structures
208  * Files that do not match the flow-tools naming convention or
209  * do not have the correct magic word in the header are not loaded
210  * to prevent accidental removal.
211  *
212  * returns: < 0 error
213  *          >= 0 ok
214  */
ftfile_loaddir(struct ftfile_entries * fte,char * dir,int flags)215 int ftfile_loaddir(struct ftfile_entries *fte, char *dir, int flags)
216 {
217   int depth, here;
218   DIR *dirp;
219 
220   depth = 0;
221 
222   if (flags & FT_FILE_INIT)
223     FT_TAILQ_INIT(&fte->head);
224 
225   /* remember current dir */
226   if (!(dirp = opendir("."))) {
227     fterr_warn("opendir(.)");
228     return -1;
229   }
230 
231   if ((here = open(".", O_RDONLY, 0)) < 0) {
232     fterr_warn("open(.)");
233     return -1;
234   }
235 
236   /* go to working dir */
237   if (chdir (dir) < 0) {
238     fterr_warn("chdir(%s)", dir);
239     close(here);
240     closedir(dirp);
241     return -1;
242   }
243 
244   /* load entries */
245   if (load_dir(dir, fte, flags, &depth)) {
246     fterr_warn("load_dir(): failed");
247     fchdir(here);
248     close(here);
249     closedir(dirp);
250     return -1;
251   }
252 
253   if (debug)
254     fterr_info("ftfile_loaddir(): loaded %lu files", fte->num_files);
255 
256   /* return */
257   if (fchdir(here) < 0) {
258     fterr_warn("fchdir()");
259     close(here);
260     closedir(dirp);
261     return -1;
262   }
263 
264   closedir(dirp);
265   close(here);
266   return 0;
267 
268 } /* ftfile_loaddir */
269 
270 /*
271  * function: ftfile_add_tail
272  *
273  * Add a file to the end of the list
274  *
275  * returns: < 0 error
276  *          >= 0 ok
277 */
ftfile_add_tail(struct ftfile_entries * fte,char * fname,off_t size,uint32_t start)278 int ftfile_add_tail(struct ftfile_entries *fte, char *fname, off_t size,
279   uint32_t start)
280 {
281   struct ftfile_entry *n1;
282 
283   if (!(n1 = ftfile_entry_new(strlen(fname)))) {
284     fterr_warnx("ftfile_entry_new(): failed");
285     return -1;
286   }
287 
288   n1->size = size;
289   n1->start = start;
290   strcpy(n1->name, fname);
291 
292   FT_TAILQ_INSERT_TAIL(&fte->head, n1, chain);
293   fte->num_files ++;
294   fte->num_bytes += size;
295 
296   return 0;
297 
298 } /* ftfile_add_tail */
299 
300 /*
301  * function: ftfile_expire
302  *
303  * If doit is set, and the directory has exceeded the maximum size
304  * of files, or maximum storage size remove files until the limits
305  * are under the mark.  curbytes is a hint (fudge factor) to account
306  * for the existing open flow export.
307  *
308  * returns: < 0 error
309  *          >= 0 ok
310 */
ftfile_expire(struct ftfile_entries * fte,int doit,int curbytes)311 int ftfile_expire (struct ftfile_entries *fte, int doit, int curbytes)
312 {
313   unsigned int i;
314   struct ftfile_entry *n1, *n2;
315   uint64_t bytes;
316 
317   /*
318    * if max_files is set, remove files starting at the head of the list until
319    * max_files <= num_files.  update num_files, num_bytes
320    */
321 
322   i = 0;
323   bytes = 0;
324 
325   if (fte->max_files && (fte->num_files > fte->max_files)) {
326     n2 = NULL;
327     FT_TAILQ_FOREACH(n1, &fte->head, chain) {
328       if (n2 != NULL) {
329 	ftfile_entry_free(n2);
330 	n2 = NULL;
331       }
332       fterr_info("remove/1 %s", n1->name);
333       bytes += n1->size;
334       ++i;
335       if (doit) {
336         n2 = n1;
337         FT_TAILQ_REMOVE(&fte->head, n1, chain);
338         if (unlink(n1->name) == -1)
339           fterr_warn("unlink(%s)", n1->name);
340       } /* doit */
341       if ((fte->num_files - i) <= fte->max_files)
342         break;
343     } /* FT_TAILQ_FOREACH */
344     if (doit) {
345       fte->num_files -= i;
346       fte->num_bytes -= bytes;
347     } /* doit */
348     if (n2 != NULL) {
349       ftfile_entry_free(n2);
350       n2 = NULL;
351     }
352   } /* if */
353 
354   if (debug)
355     fterr_info("remove/1 %u files", i);
356 
357   i = 0;
358   bytes = 0;
359 
360   /*
361    * if max_bytes is set, remove files starting at the head of the list until
362    * max_bytes <= num_bytes
363    */
364 
365   if (fte->max_bytes && (fte->num_bytes+curbytes > fte->max_bytes)) {
366     n2 = NULL;
367     FT_TAILQ_FOREACH(n1, &fte->head, chain) {
368       if (n2 != NULL) {
369 	ftfile_entry_free(n2);
370 	n2 = NULL;
371       }
372       fterr_info("remove/2 %s", n1->name);
373       bytes += n1->size;
374       ++i;
375       if (doit) {
376         n2 = n1;
377         FT_TAILQ_REMOVE(&fte->head, n1, chain);
378         if (unlink(n1->name) == -1)
379           fterr_warn("unlink(%s)", n1->name);
380       } /* doit */
381       if ((fte->num_bytes+curbytes - bytes) <= fte->max_bytes)
382         break;
383     } /* FT_TAILQ_FOREACH */
384     if (doit) {
385       fte->num_files -= i;
386       fte->num_bytes -= bytes;
387     } /* doit */
388     if (n2 != NULL) {
389       ftfile_entry_free(n2);
390       n2 = NULL;
391     }
392   } /* if */
393 
394   if (debug)
395     fterr_info("remove/2 %u files", i);
396 
397   return 0;
398 
399 } /* ftfile_expire */
400 
401 /*
402  * function: ftfile_dump
403  *
404  * Dump the contents of the file entries data struct.
405  *
406  * returns: < 0 error
407  *          >= 0 ok
408 */
ftfile_dump(struct ftfile_entries * fte)409 int ftfile_dump(struct ftfile_entries *fte)
410 {
411   struct ftfile_entry *n1;
412 
413   FT_TAILQ_FOREACH(n1, &fte->head, chain) {
414 
415     fterr_info("name=%s  size=%ld  time=%lu", n1->name, (long)n1->size,
416       (unsigned long)n1->start);
417 
418   } /* FT_TAILQ_FOREACH */
419 
420   return 0;
421 
422 } /* ftfile_dump */
423 
424 /*
425  * function: ftfile_pathname
426  *
427  * Generate export file pathname based on ftv, time, nest, and done flag.
428  *
429  */
ftfile_pathname(char * buf,int bsize,int nest,struct ftver ftv,int done,time_t ftime)430 void ftfile_pathname(char *buf, int bsize, int nest, struct ftver ftv,
431  int done, time_t ftime)
432 {
433   struct tm *tm;
434   char *prefix, dbuf[64];
435   long gmt_val;
436   char gmt_sign;
437   int tm_gmtoff;
438 
439   if (!(tm = localtime (&ftime))) {
440     snprintf(buf, bsize, ".");
441   }
442 
443   tm_gmtoff = get_gmtoff(ftime);
444 
445   /* compute GMT offset */
446   if (tm_gmtoff >= 0) {
447     gmt_val = tm_gmtoff;
448     gmt_sign = '+';
449   } else {
450     gmt_val = -tm_gmtoff;
451     gmt_sign = '-';
452   }
453 
454   /* compute directory prefix to pathname */
455   if (nest == 0) {
456     dbuf[0] = 0;
457   } else if (nest == 1) {
458     sprintf(dbuf, "%2.2d/", (int)tm->tm_year+1900);
459   } else if (nest == 2) {
460     sprintf(dbuf, "%2.2d/%2.2d-%2.2d/", (int)tm->tm_year+1900,
461       (int)tm->tm_year+1900, (int)tm->tm_mon+1);
462   } else if ((nest == 3) || (nest == -3)) {
463     sprintf(dbuf, "%2.2d/%2.2d-%2.2d/%2.2d-%2.2d-%2.2d/",
464       (int)tm->tm_year+1900, (int)tm->tm_year+1900,
465       (int)tm->tm_mon+1, (int)tm->tm_year+1900, (int)tm->tm_mon+1,
466       (int)tm->tm_mday);
467   } else if (nest == -2) {
468     sprintf(dbuf, "%2.2d-%2.2d/%2.2d-%2.2d-%2.2d/",
469       (int)tm->tm_year+1900, (int)tm->tm_mon+1,
470       (int)tm->tm_year+1900, (int)tm->tm_mon+1, (int)tm->tm_mday);
471   } else if (nest == -1) {
472     sprintf(dbuf, "%2.2d-%2.2d-%2.2d/",
473       (int)tm->tm_year+1900, (int)tm->tm_mon+1, (int)tm->tm_mday);
474   } else { /* really an error */
475     dbuf[0] = 0;
476   }
477 
478   /* prefix differs if file is active */
479   prefix = (done) ? "ft-v" : "tmp-v";
480 
481   if (ftv.d_version == 8) {
482 
483     /* ft-vNNmNN.YYYY-DD-MM.HHMMSS.+|-NNNN */
484     snprintf(buf, bsize,
485         "%s%s%2.2dm%2.2d.%4.4d-%2.2d-%2.2d.%2.2d%2.2d%2.2d%c%2.2d%2.2d",
486         dbuf, prefix, ftv.d_version, ftv.agg_method,
487         (int)tm->tm_year+1900, (int)tm->tm_mon+1, (int)tm->tm_mday,
488         (int)tm->tm_hour, (int)tm->tm_min, (int)tm->tm_sec,
489         gmt_sign, (int)(gmt_val/3600), (int)((gmt_val %3600) / 60));
490   } else {
491     /* ft-vNN.YYYY-DD-MM.HHMMSS.+|-NNNN */
492       snprintf(buf, bsize,
493         "%s%s%2.2d.%4.4d-%2.2d-%2.2d.%2.2d%2.2d%2.2d%c%2.2d%2.2d",
494         dbuf, prefix, ftv.d_version,
495         (int)tm->tm_year+1900, (int)tm->tm_mon+1, (int)tm->tm_mday,
496         (int)tm->tm_hour, (int)tm->tm_min, (int)tm->tm_sec,
497         gmt_sign, (int)(gmt_val/3600), (int)((gmt_val %3600) / 60));
498 
499   } /* ver != 8 */
500 
501 } /* ftfile_name */
502 
503 /*
504  * function: ftfile_mkpath
505  *
506  * Create directory components for pathname.
507  *
508  * nest controls depth
509  * -3    YYYY/YYYY-MM/YYYY-MM-DD
510  * -2    YYYY-MM/YYYY-MM-DD
511  * -1    YYYY-MM-DD
512  *  0    no directories are created
513  *  1    YYYY
514  *  2    YYYY/YYYY-MM
515  *  3    YYYY/YYYY-MM/YYYY-MM-DD
516  *
517  * returns -1 on error
518  *
519  */
ftfile_mkpath(time_t ftime,int nest)520 int ftfile_mkpath(time_t ftime, int nest)
521 {
522   struct tm *tm;
523   char buf[32];
524 
525   /* no directories */
526   if (nest == 0)
527     return 0;
528 
529   /* illegal */
530   if ((nest > 3) || (nest < -3))
531     return -1;
532 
533   if (!(tm = localtime (&ftime)))
534     return -1;
535 
536   if (nest == -1)
537     /* YYYY-MM-DD */
538     sprintf(buf, "%2.2d-%2.2d-%2.2d",
539       (int)tm->tm_year+1900, (int)tm->tm_mon+1, (int)tm->tm_mday);
540   else if (nest == -2)
541     /* YYYY-MM */
542     sprintf(buf, "%2.2d-%2.2d", (int)tm->tm_year+1900, (int)tm->tm_mon+1);
543   else if ((nest == -3) || (nest > 0))
544     /* YYYY */
545     sprintf(buf, "%2.2d", (int)tm->tm_year+1900);
546   else
547     /* not reached */
548     return -1;
549 
550   if (mkdir(buf, 0755) < 0) {
551     if (errno != EEXIST) {
552       fterr_warn("mkdir(%s)", buf);
553       return -1;
554     }
555   }
556 
557   if ((nest == 1) || (nest == -1))
558     return 0;
559 
560   if (nest == -2)
561     /* YYYY-MM/YYYY-MM-DD */
562     sprintf(buf, "%2.2d-%2.2d/%2.2d-%2.2d-%2.2d",
563       (int)tm->tm_year+1900, (int)tm->tm_mon+1,
564       (int)tm->tm_year+1900, (int)tm->tm_mon+1, (int)tm->tm_mday);
565   else if ((nest == -3) || (nest > 0))
566     /* YYYY/YYYY-MM */
567     sprintf(buf, "%2.2d/%2.2d-%2.2d", (int)tm->tm_year+1900,
568       (int)tm->tm_year+1900, (int)tm->tm_mon+1);
569   else
570     /* not reached */
571     return -1;
572 
573   if (mkdir(buf, 0755) < 0) {
574     if (errno != EEXIST) {
575       fterr_warn("mkdir(%s)", buf);
576       return -1;
577     }
578   }
579 
580   if ((nest == 2) || (nest == -2))
581     return 0;
582 
583   if ((nest == 3) || (nest == -3))
584     /* YYYY/YYYY-MM/YYYY-MM-DD */
585     sprintf(buf, "%2.2d/%2.2d-%2.2d/%2.2d-%2.2d-%2.2d", (int)tm->tm_year+1900,
586       (int)tm->tm_year+1900, (int)tm->tm_mon+1, (int)tm->tm_year+1900,
587       (int)tm->tm_mon+1, (int)tm->tm_mday);
588   else
589     /* not reached */
590     return -1;
591 
592   if (mkdir(buf, 0755) < 0) {
593     if (errno != EEXIST) {
594       fterr_warn("mkdir(%s)", buf);
595       return -1;
596     }
597   }
598 
599   return 0;
600 
601 } /* ftfile_mkpath */
602 
load_dir(char * prefix,struct ftfile_entries * fte,int flags,int * depth)603 int load_dir(char *prefix, struct ftfile_entries *fte, int flags, int *depth)
604 {
605   DIR *dirp;
606   struct dirent *dirent;
607   struct stat sb;
608   struct ftfile_entry *n1, *n2;
609   struct ftiheader head;
610   char *path_new;
611   int fd, done, ret, here;
612   int prefix_len, name_len, path_len;
613 
614   if (++ *depth > 50) {
615     fterr_warnx("Limit of 50 nested directories reached.");
616     return -1;
617   }
618 
619   ret = -1;
620   here = -1;
621 
622   prefix_len = strlen(prefix);
623 
624   dirp = opendir(".");
625 
626   for (dirent = readdir(dirp); dirent; dirent = readdir(dirp)) {
627 
628     /* skip . and .. */
629     if (dirent->d_name[0] == '.')
630       if (!dirent->d_name[1])
631         continue;
632       if (dirent->d_name[1] == '.')
633         if (!dirent->d_name[2])
634           continue;
635 
636     if (stat(dirent->d_name, &sb) < 0) {
637       fterr_warn("stat(%s)", dirent->d_name);
638       goto errout;
639     }
640 
641     name_len = strlen(dirent->d_name);
642 
643     path_len = prefix_len + name_len + 1;
644 
645     if (S_ISDIR(sb.st_mode)) {
646 
647       if (!(path_new = (char*)malloc(path_len+1))) {
648         fterr_warn("malloc()");
649         goto errout;
650       }
651       sprintf(path_new, "%s/%s", prefix, dirent->d_name);
652 
653       /* remember where we are */
654       if ((here = open(".", O_RDONLY, 0)) < 0) {
655         fterr_warn("open(.)");
656         goto errout;
657       }
658 
659       if (chdir(dirent->d_name) < 0) {
660         fterr_warn("chdir(%s)", path_new);
661         free(path_new);
662         goto errout;
663       }
664 
665       if (load_dir(path_new, fte, flags, depth) < 0) {
666         fterr_warnx("load_dir(%s)", path_new);
667         free(path_new);
668         goto errout;
669       }
670 
671       if (fchdir(here) < 0) {
672         fterr_warn("chdir(..)");
673         free(path_new);
674         goto errout;
675       }
676 
677       close (here);
678       here = -1;
679 
680       free (path_new);
681 
682     } else { /* S_ISDIR */
683 
684       /* skip non plain files */
685       if (!S_ISREG(sb.st_mode)) {
686         fterr_warnx("not plain, skipping: %s", dirent->d_name);
687         continue;
688       }
689 
690       /* skip anything that doesn't begin with "ft" "cf" and "tmp" */
691       if (flags & FT_FILE_CHECKNAMES)
692         if ((strncmp(dirent->d_name, "ft", 2)) &&
693            (strncmp(dirent->d_name, "cf", 2)) &&
694            (strncmp(dirent->d_name, "tmp", 3))) {
695           fterr_warnx("ignoring: %s", dirent->d_name);
696           continue;
697         }
698 
699       /* skip tmp files? */
700       if (flags & FT_FILE_SKIPTMP)
701         if (!strncmp(dirent->d_name, "tmp", 3))
702           continue;
703 
704       /* make sure the file is actually a flow file */
705       if ((fd = open (dirent->d_name,  O_RDONLY, 0)) == -1) {
706         fterr_warn("open(%s)", dirent->d_name);
707         continue;
708       }
709 
710       if (ftiheader_read(fd, &head) < 0) {
711         fterr_warnx("ftiheader_read(%s): Failed, ignoring file.", dirent->d_name);
712         close(fd);
713         continue;
714       }
715 
716       close (fd);
717 
718       /* insert the entry in the list sorted by start time of flow file */
719       done = 0;
720 
721       if (flags & FT_FILE_SORT) {
722 
723         FT_TAILQ_FOREACH(n1, &fte->head, chain) {
724 
725           if (n1->start > head.cap_start) {
726 
727             if (!(n2 = ftfile_entry_new(path_len))) {
728               fterr_warnx("ftfile_entry_new(): failed");
729               goto errout;
730             }
731 
732             n2->size = sb.st_size;
733             n2->start = head.cap_start;
734             sprintf(n2->name, "%s/%s", prefix, dirent->d_name);
735 
736             FT_TAILQ_INSERT_BEFORE(n1, n2, chain);
737             done = 1;
738             break;
739           }
740         } /* FT_TAILQ_FOREACH */
741       } /* FT_FILE_SORT */
742 
743       if ((!done) || (!(flags & FT_FILE_SORT))) {
744 
745         if (!(n2 = ftfile_entry_new(path_len))) {
746           fterr_warnx("ftfile_entry_new(): failed");
747           goto errout;
748         }
749 
750         n2->size = sb.st_size;
751         n2->start = head.cap_start;
752         sprintf(n2->name, "%s/%s", prefix, dirent->d_name);
753         FT_TAILQ_INSERT_TAIL(&fte->head, n2, chain);
754 
755       } /* !done or !FT_FILE_SORT */
756 
757       fte->num_bytes += sb.st_size;
758       fte->num_files ++;
759 
760     } /* ! S_ISDIR */
761 
762   } /* for */
763 
764   ret = 0;
765 
766 errout:
767 
768   closedir(dirp);
769 
770   if (here != -1)
771     close (here);
772 
773   -- *depth;
774 
775   return ret;
776 
777 } /* main */
778 
ftfile_free(struct ftfile_entries * fte)779 void ftfile_free(struct ftfile_entries *fte)
780 {
781   struct ftfile_entry *n1, *n2;
782 
783   n2 = NULL;
784   FT_TAILQ_FOREACH(n1, &fte->head, chain) {
785     if (n2 != NULL) {
786       ftfile_entry_free(n2);
787       n2 = NULL;
788     }
789     FT_TAILQ_REMOVE(&fte->head, n1, chain);
790     n2 = n1;
791   }
792 
793   if (n2 != NULL) {
794     ftfile_entry_free(n2);
795     n2 = NULL;
796   }
797 
798 } /* ftfile_free */
799 
800