Imported Upstream version 2.4.5
[debian/amanda] / client-src / calcsize.c
index 97a032adc3125d6a5ccb643957742fe0e314e539..aa95bb2371911591daa5937f9cd880ebf97f4fec 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.24.2.3.6.1.2.3 2005/02/09 17:56:52 martinea Exp $
  *
  * traverse directory tree to get backup size estimates
  */
 #include "amanda.h"
 #include "statfs.h"
+#include "sl.h"
 
 #define ROUND(n,x)     ((x) + (n) - 1 - (((x) + (n) - 1) % (n)))
 
@@ -44,7 +45,7 @@ unsigned long n, x;
 }
 */
 
-# define ST_BLOCKS(s)  ((s).st_size / 512 + (((s).st_size % 512) ? 1 : 0))
+#define ST_BLOCKS(s)   ((((s).st_blocks * 512) <= (s).st_size) ? (s).st_blocks+1 : ((s).st_size / 512 + (((s).st_size % 512) ? 1 : 0)))
 
 #define        FILETYPES       (S_IFREG|S_IFLNK|S_IFDIR)
 
@@ -62,34 +63,39 @@ struct {
     int total_dirs;
     int total_files;
     long total_size;
+    long total_size_name;
 } dumpstats[MAXDUMPS];
 
 time_t dumpdate[MAXDUMPS];
 int  dumplevel[MAXDUMPS];
 int ndumps;
 
+void (*add_file_name) P((int, char *));
 void (*add_file) P((int, struct stat *));
 long (*final_size) P((int, char *));
 
 
 int main P((int, char **));
-void traverse_dirs P((char *));
+void traverse_dirs P((char *, char *));
 
 
+void add_file_name_dump P((int, char *));
 void add_file_dump P((int, struct stat *));
 long final_size_dump P((int, char *));
 
+void add_file_name_gnutar P((int, char *));
 void add_file_gnutar P((int, struct stat *));
 long final_size_gnutar P((int, char *));
 
+void add_file_name_unknown P((int, char *));
 void add_file_unknown P((int, struct stat *));
 long final_size_unknown P((int, char *));
 
-#ifdef BUILTIN_EXCLUDE_SUPPORT
+sl_t *calc_load_file P((char *filename));
+int calc_check_exclude P((char *filename));
+
 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;
@@ -135,7 +141,7 @@ char **argv;
     return 0;
 #else
     int i;
-    char *dirname=NULL, *amname=NULL;
+    char *dirname=NULL, *amname=NULL, *filename=NULL;
     int fd;
     unsigned long malloc_hist_1, malloc_size_1;
     unsigned long malloc_hist_2, malloc_size_2;
@@ -165,17 +171,8 @@ 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
-             );
+       error("Usage: %s [DUMP|GNUTAR%s] name dir [-X exclude-file] [-I include-file] [level date]*",
+             get_pname());
        return 1;
     }
 
@@ -186,6 +183,7 @@ char **argv;
        error("dump not available on this system");
        return 1;
 #else
+       add_file_name = add_file_name_dump;
        add_file = add_file_dump;
        final_size = final_size_dump;
 #endif
@@ -195,53 +193,18 @@ char **argv;
        error("gnutar not available on this system");
        return 1;
 #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 */
 
@@ -258,6 +221,42 @@ char **argv;
     } else
        error("missing <dir>");
 
+    if ((argc > 1) && strcmp(*argv,"-X") == 0) {
+       argv++;
+
+       if (!use_gtar_excl) {
+         error("exclusion specification not supported");
+         return 1;
+       }
+       
+       filename = stralloc(*argv);
+       if (access(filename, R_OK) != 0) {
+           fprintf(stderr,"Cannot open exclude file %s\n",filename);
+           use_gtar_excl = 0;
+       } else {
+         exclude_sl = calc_load_file(filename);
+       }
+       amfree(filename);
+       argc -= 2;
+       argv++;
+    } else
+       use_gtar_excl = 0;
+
+    if ((argc > 1) && strcmp(*argv,"-I") == 0) {
+       argv++;
+       
+       filename = stralloc(*argv);
+       if (access(filename, R_OK) != 0) {
+           fprintf(stderr,"Cannot open include file %s\n",filename);
+           use_gtar_excl = 0;
+       } else {
+         include_sl = calc_load_file(filename);
+       }
+       amfree(filename);
+       argc -= 2;
+       argv++;
+    }
+
     /* the dump levels to calculate sizes for */
 
     ndumps = 0;
@@ -273,14 +272,28 @@ char **argv;
     if(argc)
        error("leftover arg \"%s\", expected <level> and <date>", *argv);
 
-    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",
+       fprintf(stderr, "%s %d SIZE %ld\n",
               amname, dumplevel[i], final_size(i, dirname));
        fflush(stdout);
 
@@ -316,8 +329,9 @@ char *file;
 void push_name P((char *str));
 char *pop_name P((void));
 
-void traverse_dirs(parent_dir)
+void traverse_dirs(parent_dir, include)
 char *parent_dir;
+char *include;
 {
     DIR *d;
     struct dirent *f;
@@ -327,22 +341,22 @@ char *parent_dir;
     dev_t parent_dev = 0;
     int i;
     int l;
+    int parent_len;
+    int has_exclude = !is_empty_sl(exclude_sl) && use_gtar_excl;
+
+    char *aparent = vstralloc(parent_dir, "/", include, NULL);
 
     if(parent_dir && 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(); dirname; free(dirname), dirname = pop_name()) {
+       if(has_exclude && calc_check_exclude(dirname+parent_len+1)) {
            continue;
-#endif
-
+       }
        if((d = opendir(dirname)) == NULL) {
            perror(dirname);
            continue;
@@ -356,6 +370,9 @@ 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;
            }
@@ -371,31 +388,39 @@ char *parent_dir;
                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 && 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);
+               }
            }
        }
 
@@ -408,6 +433,7 @@ char *parent_dir;
     }
     amfree(newbase);
     amfree(newname);
+    amfree(aparent);
 }
 
 void push_name(str)
@@ -452,6 +478,13 @@ char *pop_name()
  * requirements for files with holes, nor the dumping of directories that
  * are not themselves modified.
  */
+void add_file_name_dump(level, name)
+int level;
+char *name;
+{
+    return;
+}
+
 void add_file_dump(level, sp)
 int level;
 struct stat *sp;
@@ -496,12 +529,20 @@ char *topdir;
  *
  * As with DUMP, we only need a reasonable estimate, not an exact figure.
  */
+void add_file_name_gnutar(level, name)
+int level;
+char *name;
+{
+/*    dumpstats[level].total_size_name += strlen(name) + 64;*/
+      dumpstats[level].total_size += 1;
+}
+
 void add_file_gnutar(level, sp)
 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)
@@ -510,7 +551,7 @@ char *topdir;
 {
     /* divide by two to get kbytes, rounded up */
     /* + 4 blocks for security */
-    return (dumpstats[level].total_size + 5) / 2;
+    return (dumpstats[level].total_size + 5 + (dumpstats[level].total_size_name/512)) / 2;
 }
 
 /*
@@ -520,6 +561,13 @@ char *topdir;
  * Here we'll just add up the file sizes and output that.
  */
 
+void add_file_name_unknown(level, name)
+int level;
+char *name;
+{
+    return;
+}
+
 void add_file_unknown(level, sp)
 int level;
 struct stat *sp;
@@ -536,3 +584,41 @@ char *topdir;
     /* divide by two to get kbytes, rounded up */
     return (dumpstats[level].total_size + 1) / 2;
 }
+
+/*
+ * =========================================================================
+ */
+sl_t *calc_load_file(filename)
+char *filename;
+{
+    char pattern[1025];
+
+    sl_t *sl_list = new_sl();
+
+    FILE *file = fopen(filename, "r");
+
+    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(filename)
+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;
+}