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