Imported Upstream version 2.6.0
[debian/amanda] / client-src / calcsize.c
index 97a032adc3125d6a5ccb643957742fe0e314e539..1336d8d1e553c0296d04c3ec04444d9da719c3ab 100644 (file)
  * file named AUTHORS, in the root directory of this distribution.
  */
 /* 
- * $Id: calcsize.c,v 1.24.2.3.6.1 2002/03/31 21:01:32 jrjackson Exp $
+ * $Id: calcsize.c,v 1.44 2006/07/25 18:27:56 martinea Exp $
  *
  * traverse directory tree to get backup size estimates
+ *
+ * argv[0] is the calcsize program name
+ * argv[1] is the config name or NOCONFIG
  */
 #include "amanda.h"
-#include "statfs.h"
+#include "fsusage.h"
+#include "version.h"
+#include "sl.h"
+#include "util.h"
 
 #define ROUND(n,x)     ((x) + (n) - 1 - (((x) + (n) - 1) % (n)))
 
 /*
-static unsigned long round_function(n, x)
-unsigned long n, x;
+static off_t
+round_function(n, x)
+    off_t      n,
+    off_t      x)
 {
   unsigned long remainder = x % n;
   if (remainder)
-    x += n-remainder;
+    x += n - remainder;
   return x;
 }
 */
 
-# define ST_BLOCKS(s)  ((s).st_size / 512 + (((s).st_size % 512) ? 1 : 0))
+#define ST_BLOCKS(s)                                                          \
+           (((((off_t)(s).st_blocks * (off_t)512) <= (s).st_size)) ?          \
+             ((off_t)(s).st_blocks + (off_t)1) :                              \
+             ((s).st_size / (off_t)512 +                                      \
+               (off_t)((((s).st_size % (off_t)512) != (off_t)0) ?             \
+               (off_t)1 : (off_t)0)))
 
 #define        FILETYPES       (S_IFREG|S_IFLNK|S_IFDIR)
 
@@ -61,100 +74,115 @@ struct {
     int max_inode;
     int total_dirs;
     int total_files;
-    long total_size;
+    off_t total_size;
+    off_t total_size_name;
 } dumpstats[MAXDUMPS];
 
 time_t dumpdate[MAXDUMPS];
 int  dumplevel[MAXDUMPS];
 int ndumps;
 
-void (*add_file) P((int, struct stat *));
-long (*final_size) P((int, char *));
+void (*add_file_name)(int, char *);
+void (*add_file)(int, struct stat *);
+off_t (*final_size)(int, char *);
+
 
+int main(int, char **);
+void traverse_dirs(char *, char *);
 
-int main P((int, char **));
-void traverse_dirs P((char *));
 
+void add_file_name_dump(int, char *);
+void add_file_dump(int, struct stat *);
+off_t final_size_dump(int, char *);
 
-void add_file_dump P((int, struct stat *));
-long final_size_dump P((int, char *));
+void add_file_name_star(int, char *);
+void add_file_star(int, struct stat *);
+off_t final_size_star(int, char *);
 
-void add_file_gnutar P((int, struct stat *));
-long final_size_gnutar P((int, char *));
+void add_file_name_gnutar(int, char *);
+void add_file_gnutar(int, struct stat *);
+off_t final_size_gnutar(int, char *);
 
-void add_file_unknown P((int, struct stat *));
-long final_size_unknown P((int, char *));
+void add_file_name_unknown(int, char *);
+void add_file_unknown(int, struct stat *);
+off_t final_size_unknown(int, char *);
 
-#ifdef BUILTIN_EXCLUDE_SUPPORT
+sl_t *calc_load_file(char *filename);
+int calc_check_exclude(char *filename);
+
+int use_star_excl = 0;
 int use_gtar_excl = 0;
-char exclude_string[] = "--exclude=";
-char exclude_list_string[] = "--exclude-list=";
-#endif
+sl_t *include_sl=NULL, *exclude_sl=NULL;
 
-int main(argc, argv)
-int argc;
-char **argv;
+int
+main(
+    int                argc,
+    char **    argv)
 {
 #ifdef TEST
 /* standalone test to ckeck wether the calculated file size is ok */
     struct stat finfo;
     int i;
-    unsigned long dump_total=0, gtar_total=0;
+    off_t dump_total = (off_t)0;
+    off_t gtar_total = (off_t)0;
     char *d;
     int l, w;
-    int fd;
-
-    for(fd = 3; fd < FD_SETSIZE; fd++) {
-       /*
-        * Make sure nobody spoofs us with a lot of extra open files
-        * that would cause an open we do to get a very high file
-        * descriptor, which in turn might be used as an index into
-        * an array (e.g. an fd_set).
-        */
-       close(fd);
-    }
+
+    /*
+     * Configure program for internationalization:
+     *   1) Only set the message locale for now.
+     *   2) Set textdomain for all amanda related programs to "amanda"
+     *      We don't want to be forced to support dozens of message catalogs.
+     */  
+    setlocale(LC_MESSAGES, "C");
+    textdomain("amanda"); 
+
+    safe_fd(-1, 0);
 
     set_pname("calcsize");
 
+    dbopen(NULL);
+
+    /* Don't die when child closes pipe */
+    signal(SIGPIPE, SIG_IGN);
+
     if (argc < 2) {
-       fprintf(stderr,"Usage: %s file[s]\n",argv[0]);
+       g_fprintf(stderr,_("Usage: %s file[s]\n"),argv[0]);
        return 1;
     }
     for(i=1; i<argc; i++) {
        if(lstat(argv[i], &finfo) == -1) {
-           fprintf(stderr, "%s: %s\n", argv[i], strerror(errno));
+           g_fprintf(stderr, "%s: %s\n", argv[i], strerror(errno));
            continue;
        }
-       printf("%s: st_size=%lu", argv[i],(unsigned long)finfo.st_size);
-       printf(": blocks=%lu\n", (unsigned long)ST_BLOCKS(finfo));
-       dump_total += (ST_BLOCKS(finfo) + 1)/2 + 1;
-       gtar_total += ROUND(4,(ST_BLOCKS(finfo) + 1));
+       g_printf("%s: st_size=%lu", argv[i],(unsigned long)finfo.st_size);
+       g_printf(": blocks=%llu\n", ST_BLOCKS(finfo));
+       dump_total += (ST_BLOCKS(finfo) + (off_t)1) / (off_t)2 + (off_t)1;
+       gtar_total += ROUND(4,(ST_BLOCKS(finfo) + (off_t)1));
     }
-    printf("           gtar           dump\n");
-    printf("total      %-9lu         %-9lu\n",gtar_total,dump_total);
+    g_printf("           gtar           dump\n");
+    g_printf("total      %-9lu         %-9lu\n",gtar_total,dump_total);
     return 0;
 #else
     int i;
-    char *dirname=NULL, *amname=NULL;
-    int fd;
-    unsigned long malloc_hist_1, malloc_size_1;
-    unsigned long malloc_hist_2, malloc_size_2;
-
-    for(fd = 3; fd < FD_SETSIZE; fd++) {
-       /*
-        * Make sure nobody spoofs us with a lot of extra open files
-        * that would cause an open we do to get a very high file
-        * descriptor, which in turn might be used as an index into
-        * an array (e.g. an fd_set).
-        */
-       close(fd);
+    char *dirname=NULL;
+    char *amname=NULL, *qamname=NULL;
+    char *filename=NULL, *qfilename = NULL;
+
+    /* drop root privileges; we'll regain them for the required operations */
+#ifdef WANT_SETUID_CLIENT
+    if (!set_root_privs(0)) {
+       error(_("calcsize must be run setuid root"));
     }
+#endif
 
-    set_pname("calcsize");
-
+    safe_fd(-1, 0);
     safe_cd();
 
-    malloc_size_1 = malloc_inuse(&malloc_hist_1);
+    set_pname("calcsize");
+
+    dbopen(DBG_SUBDIR_CLIENT);
+    dbprintf(_("version %s\n"), version());
 
 #if 0
     erroutput_type = (ERR_INTERACTIVE|ERR_SYSLOG);
@@ -164,28 +192,29 @@ char **argv;
 
     /* need at least program, amname, and directory name */
 
-    if(argc < 3) {
-#ifdef BUILTIN_EXCLUDE_SUPPORT
-      usage:
-#endif
-       error("Usage: %s [DUMP|GNUTAR%s] name dir [level date] ...",
-             get_pname(),
-#ifdef BUILTIN_EXCLUDE_SUPPORT
-             " [-X --exclude[-list]=regexp]"
-#else
-             ""
-#endif
-             );
-       return 1;
+    if(argc < 4) {
+       error(_("Usage: %s config [DUMP|STAR|GNUTAR] name dir [-X exclude-file] [-I include-file] [level date]*"),
+             get_pname());
+        /*NOTREACHED*/
+    }
+
+    dbprintf(_("config: %s\n"), *argv);
+    if (strcmp(*argv, "NOCONFIG") != 0) {
+       dbrename(*argv, DBG_SUBDIR_CLIENT);
     }
+    argc--;
+    argv++;
+
+    check_running_as(RUNNING_AS_CLIENT_LOGIN);
 
     /* parse backup program name */
 
     if(strcmp(*argv, "DUMP") == 0) {
 #if !defined(DUMP) && !defined(XFSDUMP)
        error("dump not available on this system");
-       return 1;
+       /*NOTREACHED*/
 #else
+       add_file_name = add_file_name_dump;
        add_file = add_file_dump;
        final_size = final_size_dump;
 #endif
@@ -193,70 +222,91 @@ char **argv;
     else if(strcmp(*argv, "GNUTAR") == 0) {
 #ifndef GNUTAR
        error("gnutar not available on this system");
-       return 1;
+       /*NOTREACHED*/
 #else
+       add_file_name = add_file_name_gnutar;
        add_file = add_file_gnutar;
        final_size = final_size_gnutar;
-#ifdef BUILTIN_EXCLUDE_SUPPORT
        use_gtar_excl++;
-#endif
 #endif
     }
     else {
+       add_file_name = add_file_name_unknown;
        add_file = add_file_unknown;
        final_size = final_size_unknown;
     }
     argc--, argv++;
-#ifdef BUILTIN_EXCLUDE_SUPPORT
-    if ((argc > 1) && strcmp(*argv,"-X") == 0) {
-       char *result = NULL;
-       char *cp = NULL;
-       argv++;
-
-       if (!use_gtar_excl) {
-         error("exclusion specification not supported");
-         return 1;
-       }
-
-       result = stralloc(*argv);
-       if (*result && (cp = strrchr(result,';')))
-           /* delete trailing ; */
-           *cp = 0;
-       if (strncmp(result, exclude_string, sizeof(exclude_string)-1) == 0)
-         add_exclude(result+sizeof(exclude_string)-1);
-       else if (strncmp(result, exclude_list_string,
-                        sizeof(exclude_list_string)-1) == 0) {
-         if (access(result + sizeof(exclude_list_string)-1, R_OK) != 0) {
-           fprintf(stderr,"Cannot open exclude file %s\n",cp+1);
-           use_gtar_excl = 0;
-         } else {
-           add_exclude_file(result + sizeof(exclude_list_string)-1);
-         }
-       } else {
-         amfree(result);
-         goto usage;
-       }
-       amfree(result);
-       argc -= 2;
-       argv++;
-    } else
-       use_gtar_excl = 0;
-#endif
 
     /* the amanda name can be different from the directory name */
 
     if (argc > 0) {
        amname = *argv;
+       qamname = quote_string(amname);
        argc--, argv++;
-    } else
+    } else {
        error("missing <name>");
+       /*NOTREACHED*/
+    }
 
     /* the toplevel directory name to search from */
     if (argc > 0) {
        dirname = *argv;
        argc--, argv++;
-    } else
+    } else {
        error("missing <dir>");
+       /*NOTREACHED*/
+    }
+
+    if ((argc > 1) && strcmp(*argv,"-X") == 0) {
+       argv++;
+
+       if (!(use_gtar_excl || use_star_excl)) {
+         error("exclusion specification not supported");
+         /*NOTREACHED*/
+       }
+       
+       filename = stralloc(*argv);
+       qfilename = quote_string(filename);
+       if (access(filename, R_OK) != 0) {
+           g_fprintf(stderr,"Cannot open exclude file %s\n", qfilename);
+           use_gtar_excl = use_star_excl = 0;
+       } else {
+           exclude_sl = calc_load_file(filename);
+           if (!exclude_sl) {
+               g_fprintf(stderr,"Cannot open exclude file %s: %s\n", qfilename,
+                       strerror(errno));
+               use_gtar_excl = use_star_excl = 0;
+           }
+       }
+       amfree(qfilename);
+       amfree(filename);
+       argc -= 2;
+       argv++;
+    } else {
+       use_gtar_excl = use_star_excl = 0;
+    }
+
+    if ((argc > 1) && strcmp(*argv,"-I") == 0) {
+       argv++;
+       
+       filename = stralloc(*argv);
+       qfilename = quote_string(filename);
+       if (access(filename, R_OK) != 0) {
+           g_fprintf(stderr,"Cannot open include file %s\n", qfilename);
+           use_gtar_excl = use_star_excl = 0;
+       } else {
+           include_sl = calc_load_file(filename);
+           if (!include_sl) {
+               g_fprintf(stderr,"Cannot open include file %s: %s\n", qfilename,
+                       strerror(errno));
+               use_gtar_excl = use_star_excl = 0;
+           }
+       }
+       amfree(qfilename);
+       amfree(filename);
+       argc -= 2;
+       argv++;
+    }
 
     /* the dump levels to calculate sizes for */
 
@@ -270,28 +320,41 @@ char **argv;
        }
     }
 
-    if(argc)
+    if(argc) {
        error("leftover arg \"%s\", expected <level> and <date>", *argv);
+       /*NOTREACHED*/
+    }
 
-    traverse_dirs(dirname);
+    if(is_empty_sl(include_sl)) {
+       traverse_dirs(dirname,".");
+    }
+    else {
+       sle_t *an_include = include_sl->first;
+       while(an_include != NULL) {
+/*
+           char *adirname = stralloc2(dirname, an_include->name+1);
+           traverse_dirs(adirname);
+           amfree(adirname);
+*/
+           traverse_dirs(dirname, an_include->name);
+           an_include = an_include->next;
+       }
+    }
     for(i = 0; i < ndumps; i++) {
 
        amflock(1, "size");
 
-       lseek(1, (off_t)0, SEEK_END);
-
-       printf("%s %d SIZE %ld\n",
-              amname, dumplevel[i], final_size(i, dirname));
-       fflush(stdout);
+       dbprintf("calcsize: %s %d SIZE %lld\n",
+              qamname, dumplevel[i],
+              (long long)final_size(i, dirname));
+       g_fprintf(stderr, "%s %d SIZE %lld\n",
+              qamname, dumplevel[i],
+              (long long)final_size(i, dirname));
+       fflush(stderr);
 
        amfunlock(1, "size");
     }
-
-    malloc_size_2 = malloc_inuse(&malloc_hist_2);
-
-    if(malloc_size_1 != malloc_size_2) {
-       malloc_list(fileno(stderr), malloc_hist_1, malloc_hist_2);
-    }
+    amfree(qamname);
 
     return 0;
 #endif
@@ -301,9 +364,11 @@ char **argv;
  * =========================================================================
  */
 
-#ifndef HAVE_BASENAME
-char *basename(file)
-char *file;
+#if !defined(HAVE_BASENAME) && defined(BUILTIN_EXCLUDE_SUPPORT)
+
+static char *
+basename(
+    char *     file)
 {
     char *cp;
 
@@ -313,36 +378,45 @@ char *file;
 }
 #endif
 
-void push_name P((char *str));
-char *pop_name P((void));
+void push_name(char *str);
+char *pop_name(void);
 
-void traverse_dirs(parent_dir)
-char *parent_dir;
+void
+traverse_dirs(
+    char *     parent_dir,
+    char *     include)
 {
     DIR *d;
     struct dirent *f;
     struct stat finfo;
     char *dirname, *newname = NULL;
     char *newbase = NULL;
-    dev_t parent_dev = 0;
+    dev_t parent_dev = (dev_t)0;
     int i;
-    int l;
+    size_t l;
+    size_t parent_len;
+    int has_exclude;
+    char *aparent;
+
+    if(parent_dir == NULL || include == NULL)
+       return;
 
-    if(parent_dir && stat(parent_dir, &finfo) != -1)
+    has_exclude = !is_empty_sl(exclude_sl) && (use_gtar_excl || use_star_excl);
+    aparent = vstralloc(parent_dir, "/", include, NULL);
+
+    /* We (may) need root privs for the *stat() calls here. */
+    set_root_privs(1);
+    if(stat(parent_dir, &finfo) != -1)
        parent_dev = finfo.st_dev;
 
-    push_name(parent_dir);
+    parent_len = strlen(parent_dir);
 
-    for(dirname = pop_name(); dirname; free(dirname), dirname = pop_name()) {
+    push_name(aparent);
 
-#ifdef BUILTIN_EXCLUDE_SUPPORT
-       if(use_gtar_excl &&
-          (check_exclude(basename(dirname)) ||
-           check_exclude(dirname)))
-           /* will not be added by gnutar */
+    for(; (dirname = pop_name()) != NULL; free(dirname)) {
+       if(has_exclude && calc_check_exclude(dirname+parent_len+1)) {
            continue;
-#endif
-
+       }
        if((d = opendir(dirname)) == NULL) {
            perror(dirname);
            continue;
@@ -356,46 +430,56 @@ char *parent_dir;
        }
 
        while((f = readdir(d)) != NULL) {
+           int is_symlink = 0;
+           int is_dir;
+           int is_file;
            if(is_dot_or_dotdot(f->d_name)) {
                continue;
            }
 
            newname = newstralloc2(newname, newbase, f->d_name);
            if(lstat(newname, &finfo) == -1) {
-               fprintf(stderr, "%s/%s: %s\n",
+               g_fprintf(stderr, "%s/%s: %s\n",
                        dirname, f->d_name, strerror(errno));
                continue;
            }
 
-           if(finfo.st_dev != parent_dev) {
+           if(finfo.st_dev != parent_dev)
                continue;
-           }
 
-           if((finfo.st_mode & S_IFMT) == S_IFDIR) {
-               push_name(newname);
-           }
-
-           for(i = 0; i < ndumps; i++) {
-               if(finfo.st_ctime >= dumpdate[i]) {
-                   int exclude = 0;
-                   int is_symlink = 0;
-
-#ifdef BUILTIN_EXCLUDE_SUPPORT
-                   exclude = check_exclude(f->d_name);
-#endif
 #ifdef S_IFLNK
-                   is_symlink = ((finfo.st_mode & S_IFMT) == S_IFLNK);
+           is_symlink = ((finfo.st_mode & S_IFMT) == S_IFLNK);
 #endif
-                   if (! exclude &&
-                         /* regular files */
-                       ((finfo.st_mode & S_IFMT) == S_IFREG
-                         /* directories */
-                         || (finfo.st_mode & S_IFMT) == S_IFDIR
-                         /* symbolic links */
-                         || is_symlink)) {
+           is_dir = ((finfo.st_mode & S_IFMT) == S_IFDIR);
+           is_file = ((finfo.st_mode & S_IFMT) == S_IFREG);
+
+           if (!(is_file || is_dir || is_symlink)) {
+               continue;
+           }
+
+           {
+               int is_excluded = -1;
+               for(i = 0; i < ndumps; i++) {
+                   add_file_name(i, newname);
+                   if(is_file && (time_t)finfo.st_ctime >= dumpdate[i]) {
+
+                       if(has_exclude) {
+                           if(is_excluded == -1)
+                               is_excluded =
+                                      calc_check_exclude(newname+parent_len+1);
+                           if(is_excluded == 1) {
+                               i = ndumps;
+                               continue;
+                           }
+                       }
                        add_file(i, &finfo);
                    }
                }
+               if(is_dir) {
+                   if(has_exclude && calc_check_exclude(newname+parent_len+1))
+                       continue;
+                   push_name(newname);
+               }
            }
        }
 
@@ -406,23 +490,30 @@ char *parent_dir;
            perror(dirname);
 #endif
     }
+
+    /* drop root privs -- we're done with the permission-sensitive calls */
+    set_root_privs(0);
+
     amfree(newbase);
     amfree(newname);
+    amfree(aparent);
 }
 
-void push_name(str)
-char *str;
+void
+push_name(
+    char *     str)
 {
     Name *newp;
 
-    newp = alloc(sizeof(*newp));
+    newp = alloc(SIZEOF(*newp));
     newp->str = stralloc(str);
 
     newp->next = name_stack;
     name_stack = newp;
 }
 
-char *pop_name()
+char *
+pop_name(void)
 {
     Name *newp = name_stack;
     char *str;
@@ -452,37 +543,52 @@ char *pop_name()
  * requirements for files with holes, nor the dumping of directories that
  * are not themselves modified.
  */
-void add_file_dump(level, sp)
-int level;
-struct stat *sp;
+void
+add_file_name_dump(
+    int                level,
+    char *     name)
+{
+    (void)level;       /* Quiet unused parameter warning */
+    (void)name;                /* Quiet unused parameter warning */
+
+    return;
+}
+
+void
+add_file_dump(
+    int                        level,
+    struct stat *      sp)
 {
     /* keep the size in kbytes, rounded up, plus a 1k header block */
     if((sp->st_mode & S_IFMT) == S_IFREG || (sp->st_mode & S_IFMT) == S_IFDIR)
-       dumpstats[level].total_size += (ST_BLOCKS(*sp) + 1)/2 + 1;
+       dumpstats[level].total_size +=
+                       (ST_BLOCKS(*sp) + (off_t)1) / (off_t)2 + (off_t)1;
 }
 
-long final_size_dump(level, topdir)
-int level;
-char *topdir;
+off_t
+final_size_dump(
+    int                level,
+    char *     topdir)
 {
-    generic_fs_stats_t stats;
-    int mapsize;
+    struct fs_usage fsusage;
+    off_t mapsize;
     char *s;
 
     /* calculate the map sizes */
 
     s = stralloc2(topdir, "/.");
-    if(get_fs_stats(s, &stats) == -1) {
+    if(get_fs_usage(s, NULL, &fsusage) == -1) {
        error("statfs %s: %s", s, strerror(errno));
+       /*NOTREACHED*/
     }
     amfree(s);
 
-    mapsize = (stats.files + 7) / 8;   /* in bytes */
-    mapsize = (mapsize + 1023) / 1024;  /* in kbytes */
+    mapsize = (fsusage.fsu_files + (off_t)7) / (off_t)8;    /* in bytes */
+    mapsize = (mapsize + (off_t)1023) / (off_t)1024;  /* in kbytes */
 
     /* the dump contains three maps plus the files */
 
-    return 3*mapsize + dumpstats[level].total_size;
+    return (mapsize * (off_t)3) + dumpstats[level].total_size;
 }
 
 /*
@@ -496,21 +602,37 @@ char *topdir;
  *
  * As with DUMP, we only need a reasonable estimate, not an exact figure.
  */
-void add_file_gnutar(level, sp)
-int level;
-struct stat *sp;
+void
+add_file_name_gnutar(
+    int                level,
+    char *     name)
+{
+    (void)name;        /* Quiet unused parameter warning */
+
+/*  dumpstats[level].total_size_name += strlen(name) + 64;*/
+    dumpstats[level].total_size += (off_t)1;
+}
+
+void
+add_file_gnutar(
+    int                        level,
+    struct stat *      sp)
 {
     /* the header takes one additional block */
-    dumpstats[level].total_size += ROUND(4,(ST_BLOCKS(*sp) + 1));
+    dumpstats[level].total_size += ST_BLOCKS(*sp);
 }
 
-long final_size_gnutar(level, topdir)
-int level;
-char *topdir;
+off_t
+final_size_gnutar(
+    int                level,
+    char *     topdir)
 {
+    (void)topdir;      /* Quiet unused parameter warning */
+
     /* divide by two to get kbytes, rounded up */
     /* + 4 blocks for security */
-    return (dumpstats[level].total_size + 5) / 2;
+    return (dumpstats[level].total_size + (off_t)5 +
+               (dumpstats[level].total_size_name/(off_t)512)) / (off_t)2;
 }
 
 /*
@@ -520,19 +642,80 @@ char *topdir;
  * Here we'll just add up the file sizes and output that.
  */
 
-void add_file_unknown(level, sp)
-int level;
-struct stat *sp;
+void
+add_file_name_unknown(
+    int                level,
+    char *     name)
+{
+    (void)level;       /* Quiet unused parameter warning */
+    (void)name;                /* Quiet unused parameter warning */
+
+    return;
+}
+
+void
+add_file_unknown(
+    int                        level,
+    struct stat *      sp)
 {
     /* just add up the block counts */
     if((sp->st_mode & S_IFMT) == S_IFREG || (sp->st_mode & S_IFMT) == S_IFDIR)
        dumpstats[level].total_size += ST_BLOCKS(*sp);
 }
 
-long final_size_unknown(level, topdir)
-int level;
-char *topdir;
+off_t
+final_size_unknown(
+    int                level,
+    char *     topdir)
 {
+    (void)topdir;      /* Quiet unused parameter warning */
+
     /* divide by two to get kbytes, rounded up */
-    return (dumpstats[level].total_size + 1) / 2;
+    return (dumpstats[level].total_size + (off_t)1) / (off_t)2;
+}
+
+/*
+ * =========================================================================
+ */
+sl_t *
+calc_load_file(
+    char *     filename)
+{
+    char pattern[1025];
+
+    sl_t *sl_list;
+
+    FILE *file = fopen(filename, "r");
+
+    if (!file) {
+       return NULL;
+    }
+
+    sl_list = new_sl();
+
+    while(fgets(pattern, 1025, file)) {
+       if(strlen(pattern)>0 && pattern[strlen(pattern)-1] == '\n')
+           pattern[strlen(pattern)-1] = '\0';
+       sl_list = append_sl(sl_list, pattern);
+    }  
+    fclose(file);
+
+    return sl_list;
+}
+
+int
+calc_check_exclude(
+    char *     filename)
+{
+    sle_t *an_exclude;
+    if(is_empty_sl(exclude_sl)) return 0;
+
+    an_exclude=exclude_sl->first;
+    while(an_exclude != NULL) {
+       if(match_tar(an_exclude->name, filename)) {
+           return 1;
+       }
+       an_exclude=an_exclude->next;
+    }
+    return 0;
 }