]> git.sur5r.net Git - bacula/bacula/commitdiff
kes Apply libdbi patch from Joao Freitas for regress and for
authorKern Sibbald <kern@sibbald.com>
Fri, 2 May 2008 13:06:54 +0000 (13:06 +0000)
committerKern Sibbald <kern@sibbald.com>
Fri, 2 May 2008 13:06:54 +0000 (13:06 +0000)
     Bacula trunk. Regress now works with libdbi. Nice.
kes  Apply .nobackup patch from bug #1077 submitted by
     Edwin Groothuis.
kes  Apply Bastian Friedrich's patch that adds %p to edit the pool
     name into jobs cloned via the run directive.

git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@6874 91ce42f0-d328-0410-95d8-f526ca767f89

13 files changed:
bacula/AUTHORS
bacula/src/cats/cats.h
bacula/src/cats/dbi.c
bacula/src/dird/dird_conf.h
bacula/src/dird/fd_cmds.c
bacula/src/dird/inc_conf.c
bacula/src/dird/job.c
bacula/src/filed/job.c
bacula/src/findlib/find.c
bacula/src/findlib/find.h
bacula/src/findlib/find_one.c
bacula/src/version.h
bacula/technotes-2.3

index 605ae87e7e2b1ed9176324b9e632de16fa578262..72282f4e960972d9e7f2c1474203d108fba1f7fd 100644 (file)
@@ -36,6 +36,7 @@ D. Scott Barninger
 Devin Reade
 Dirk Bartley
 Eamon Brosnan
+Edwin Groothuis
 Eric Bollengier
 Erich Prinz
 Felix Schwarz
index 52b3841a7aaf9fd20456577cf1cd36577a9a8927..38f8180cc35bbcb9e914553e71a80027ef948093 100644 (file)
@@ -548,6 +548,10 @@ typedef struct dbi_field {
    unsigned int  flags;       // 1 == not null
 } DBI_FIELD;
 
+typedef struct dbi_field_get {
+   BQUEUE bq;
+   char *value;
+} DBI_FIELD_GET;
 
 /*
  * This is the "real" definition that should only be
@@ -562,10 +566,10 @@ struct B_DB {
    dbi_conn *db;
    dbi_result *result;
    dbi_inst instance;
-   // TODO: change dbi_error_flag to int for more compatible with bacula
    dbi_error_flag status;
    DBI_ROW row;
    DBI_FIELD *fields;
+   DBI_FIELD_GET *field_get;
    int num_rows;
    int row_size;                  /* size of malloced rows */
    int num_fields;
index 4582dce4d043a3d715927c2d0ec4c25bc9b78b6c..6cdaf88b2bce8b5f96e9a259fad3befddce5b65b 100644 (file)
@@ -57,6 +57,9 @@
 /* List of open databases */
 static BQUEUE db_list = {&db_list, &db_list};
 
+/* Control allocated fields by my_dbi_getvalue */
+static BQUEUE dbi_getvalue_list = {&dbi_getvalue_list, &dbi_getvalue_list};
+
 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 
 /*
@@ -427,8 +430,9 @@ DBI_ROW my_dbi_fetch_row(B_DB *mdb)
    DBI_ROW row = NULL; // by default, return NULL
 
    Dmsg0(500, "my_dbi_fetch_row start\n");
+   
 
-   if (!mdb->row || mdb->row_size < mdb->num_fields) {
+   if (!mdb->row || mdb->row_size < mdb->num_fields) {   
       int num_fields = mdb->num_fields;
       Dmsg1(500, "we have need space of %d bytes\n", sizeof(char *) * mdb->num_fields);
 
@@ -437,7 +441,7 @@ DBI_ROW my_dbi_fetch_row(B_DB *mdb)
          Dmsg2(500, "my_dbi_free_row row: '%p' num_fields: '%d'\n", mdb->row, mdb->num_fields);
          if (mdb->num_rows != 0) {
             for(j = 0; j < mdb->num_fields; j++) {
-               Dmsg2(500, "my_dbi_free_row row '%p' '%d'\n", mdb->row[j], j);
+               Dmsg2(500, "my_dbi_free_row row '%p' '%d'\n", mdb->row[j], j);               
                   if(mdb->row[j]) {
                      free(mdb->row[j]);
                   }                  
@@ -445,7 +449,7 @@ DBI_ROW my_dbi_fetch_row(B_DB *mdb)
          }
          free(mdb->row);
       }
-      num_fields += 20;                  /* add a bit extra */
+      //num_fields += 20;                  /* add a bit extra */
       mdb->row = (DBI_ROW)malloc(sizeof(char *) * num_fields);
       mdb->row_size = num_fields;
 
@@ -455,18 +459,25 @@ DBI_ROW my_dbi_fetch_row(B_DB *mdb)
 
    // if still within the result set
    if (mdb->row_number <= mdb->num_rows) {
-      Dmsg2(500, "my_dbi_fetch_row row number '%d' is acceptable (0..%d)\n", mdb->row_number, mdb->num_rows);
+      Dmsg2(500, "my_dbi_fetch_row row number '%d' is acceptable (1..%d)\n", mdb->row_number, mdb->num_rows);
       // get each value from this row
       for (j = 0; j < mdb->num_fields; j++) {
-         mdb->row[j] = my_dbi_getvalue(mdb->result, mdb->row_number, j);
-         Dmsg3(500, "my_dbi_fetch_row field '%p' '%d' has value '%s'\n",mdb->row[j], j, mdb->row[j]);
+         mdb->row[j] = my_dbi_getvalue(mdb->result, mdb->row_number, j);         
+         // allocate space to queue row 
+         mdb->field_get = (DBI_FIELD_GET *)malloc(sizeof(DBI_FIELD_GET));
+         // store the pointer in queue
+         mdb->field_get->value = mdb->row[j];  
+         Dmsg4(500, "my_dbi_fetch_row row[%d] field: '%p' in queue: '%p' has value: '%s'\n",
+               j, mdb->row[j], mdb->field_get->value, mdb->row[j]);
+         // insert in queue to future free
+         qinsert(&dbi_getvalue_list, &mdb->field_get->bq);         
       }
       // increment the row number for the next call
       mdb->row_number++;
 
       row = mdb->row;
    } else {
-      Dmsg2(500, "my_dbi_fetch_row row number '%d' is NOT acceptable (0..%d)\n", mdb->row_number, mdb->num_rows);
+      Dmsg2(500, "my_dbi_fetch_row row number '%d' is NOT acceptable (1..%d)\n", mdb->row_number, mdb->num_rows);
    }
 
    Dmsg1(500, "my_dbi_fetch_row finishes returning %p\n", row);
@@ -488,9 +499,9 @@ int my_dbi_max_length(B_DB *mdb, int field_num) {
       if (my_dbi_getisnull(mdb->result, i, field_num)) {
           this_length = 4;        // "NULL"
       } else {
-          // TODO: error
          cbuf = my_dbi_getvalue(mdb->result, i, field_num);
          this_length = cstrlen(cbuf);
+         // cbuf is always free
          free(cbuf);
       }
 
@@ -516,8 +527,9 @@ DBI_FIELD * my_dbi_fetch_field(B_DB *mdb)
       Dmsg1(500, "allocating space for %d fields\n", mdb->num_fields);
       mdb->fields = (DBI_FIELD *)malloc(sizeof(DBI_FIELD) * mdb->num_fields);
       mdb->fields_size = mdb->num_fields;
-
+      
       for (i = 0; i < mdb->num_fields; i++) {
+         // num_fileds is starting at 1, increment i by 1
          dbi_index = i + 1;
          Dmsg1(500, "filling field %d\n", i);
          mdb->fields[i].name       = (char *)dbi_result_get_field_name(mdb->result, dbi_index);
@@ -584,9 +596,10 @@ int my_dbi_query(B_DB *mdb, const char *query)
       Dmsg1(500, "we have a result\n", query);
 
       // how many fields in the set?
+      // num_fields starting at 1
       mdb->num_fields = dbi_result_get_numfields(mdb->result);
       Dmsg1(500, "we have %d fields\n", mdb->num_fields);
-
+      // if no result num_rows is 0
       mdb->num_rows = dbi_result_get_numrows(mdb->result);
       Dmsg1(500, "we have %d rows\n", mdb->num_rows);
 
@@ -613,6 +626,7 @@ bail_out:
 void my_dbi_free_result(B_DB *mdb)
 { 
    
+   DBI_FIELD_GET *f;
    db_lock(mdb);  
    int i = 0;
    if (mdb->result) {
@@ -623,25 +637,30 @@ void my_dbi_free_result(B_DB *mdb)
    mdb->result = NULL;
    
    if (mdb->row) {
-      Dmsg2(500, "my_dbi_free_result row: '%p' num_fields: '%d'\n", mdb->row, mdb->num_fields);
-      if (mdb->num_rows != 0) {
-         for(i = 0; i < mdb->num_fields; i++) {
-            Dmsg2(500, "my_dbi_free_result row '%p' '%d'\n", mdb->row[i], i);
-            if(mdb->row[i]) {
-               free(mdb->row[i]);
-            }
-         } 
-      }
       free(mdb->row);
-      mdb->row = NULL;
    }
-
+   
+   /* now is time to free all value return by my_dbi_get_value
+    * this is necessary because libdbi don't free memory return by yours results
+    * and Bacula has some routine wich call more than once time my_dbi_fetch_row
+    * 
+    * Using a queue to store all pointer allocate is a good way to free all things
+    * when necessary
+    */
+   while((f=(DBI_FIELD_GET *)qremove(&dbi_getvalue_list))) {
+      Dmsg2(500, "my_dbi_free_result field value: '%p' in queue: '%p'\n", f->value, f);
+      free(f->value);
+      free(f);
+   }
+      
+   mdb->row = NULL;
+   
    if (mdb->fields) {
       free(mdb->fields);
       mdb->fields = NULL;
    }
    db_unlock(mdb);
-   //Dmsg0(500, "my_dbi_free_result finish\n");
+   Dmsg0(500, "my_dbi_free_result finish\n");
    
 }
 
@@ -1015,13 +1034,11 @@ int my_dbi_getisnull(dbi_result *result, int row_number, int column_number) {
  */
 char *my_dbi_getvalue(dbi_result *result, int row_number, unsigned int column_number) {
 
-   /* TODO: This is very bad, need refactoring */
-   //POOLMEM *buf = get_pool_memory(PM_FNAME);
    char *buf = NULL;
    const char *errmsg;
    const char *field_name;     
    unsigned short dbitype;
-   int32_t field_length = 0;
+   size_t field_length;
    int64_t num;
         
    /* correct the index for dbi interface
@@ -1046,18 +1063,17 @@ char *my_dbi_getvalue(dbi_result *result, int row_number, unsigned int column_nu
       field_length = dbi_result_get_field_length(result, field_name);
       dbitype = dbi_result_get_field_type_idx(result,column_number);
       
+      Dmsg3(500, "my_dbi_getvalue start: type: '%d' "
+            "field_length bytes: '%d' fieldname: '%s'\n", 
+            dbitype, field_length, field_name);
+      
       if(field_length) {
-         //buf = check_pool_memory_size(buf, field_length + 1);
-         buf = (char *)malloc(sizeof(char *) * field_length + 1);
+         //buf = (char *)malloc(sizeof(char *) * field_length + 1);
+         buf = (char *)malloc(field_length + 1);
       } else {
          /* if numbers */
-         //buf = check_pool_memory_size(buf, 50);
          buf = (char *)malloc(sizeof(char *) * 50);
-      }
-      
-      Dmsg4(500, "my_dbi_getvalue result '%p' type '%d' \n\tfield name '%s'\n\t"
-            "field_length '%d'\n", 
-            result, dbitype, field_name, field_length);
+      }           
       
       switch (dbitype) {
       case DBI_TYPE_INTEGER:
@@ -1106,100 +1122,13 @@ char *my_dbi_getvalue(dbi_result *result, int row_number, unsigned int column_nu
       Dmsg1(500, "my_dbi_getvalue error: %s\n", errmsg);
    }
                 
-   Dmsg3(500, "my_dbi_getvalue finish result '%p' num bytes '%d' data '%s'\n", 
-      result, field_length, buf);
-   
+   Dmsg3(500, "my_dbi_getvalue finish buffer: '%p' num bytes: '%d' data: '%s'\n", 
+      buf, field_length, buf);
+      
+   // don't worry about this buf
    return buf;
 }
 
-//int my_dbi_getvalue(dbi_result *result, int row_number, unsigned int column_number, char *value) {
-//   
-//   void *v;
-//   const char *errmsg;
-//   int error = 0;
-//   const char *field_name;     
-//   unsigned short dbitype;
-//   int32_t field_length = 0;
-//   int64_t num;
-//
-//   /* correct the index for dbi interface
-//    * dbi index begins 1
-//    * I prefer do not change others functions
-//    */
-//   Dmsg3(600, "my_dbi_getvalue pre-starting result '%p' row number '%d' column number '%d'\n", 
-//                                result, row_number, column_number);
-//        
-//   column_number++;
-//
-//   if(row_number == 0) {
-//     row_number++;
-//   }
-//      
-//   Dmsg3(600, "my_dbi_getvalue starting result '%p' row number '%d' column number '%d'\n", 
-//                        result, row_number, column_number);
-//   
-//   if(dbi_result_seek_row(result, row_number)) {
-//
-//      field_name = dbi_result_get_field_name(result, column_number);
-//      field_length = dbi_result_get_field_length(result, field_name);
-//      dbitype = dbi_result_get_field_type_idx(result,column_number);
-//
-//      Dmsg4(500, "my_dbi_getvalue result '%p' type '%d' \n\tfield name '%s'\n\t"
-//            "field_length '%d'\n", result, dbitype, field_name, field_length);
-//
-//      switch (dbitype) {
-//      case DBI_TYPE_INTEGER:
-//         v = (int64_t *)malloc(sizeof(int64_t));
-//         error = dbi_result_bind_longlong(result, field_name, (int64_t *)v);
-//         // transform in string
-//         num = *(int64_t *)v;
-//         edit_int64(num, value);
-//         field_length = strlen(value);
-//         break;
-//      case DBI_TYPE_STRING:
-//         if(field_length) {
-//            dbi_result_bind_string(result, field_name, (const char **)v);
-//            value = (char *) v;
-//         } else {
-//            value[0] = 0;
-//         }
-//         break;
-//      case DBI_TYPE_BINARY:
-//         if(field_length) {
-//            dbi_result_bind_binary(result, field_name, (const unsigned char **)v);
-//            value = (char *)v;
-//         } else {
-//            value[0] = 0;
-//         }
-//         break;
-//      case DBI_TYPE_DATETIME:
-//         //time_t last;
-//         struct tm tm;
-//
-//         v = (time_t *)dbi_result_get_datetime(result, field_name);
-//         dbi_result_bind_datetime(result, field_name, (time_t *)v);
-//         if(!v) {
-//                field_length = bsnprintf(value, 20, "0000-00-00 00:00:00"); 
-//         } else {
-//            (void)localtime_r((time_t *)v, &tm);
-//            field_length = bsnprintf(value, 20, "%04d-%02d-%02d %02d:%02d:%02d",
-//                  (tm.tm_year + 1900), (tm.tm_mon + 1), tm.tm_mday,
-//                  tm.tm_hour, tm.tm_min, tm.tm_sec);
-//         }
-//         break;
-//      }
-//
-//   } else {
-//      dbi_conn_error(dbi_result_get_conn(result), &errmsg);
-//      Dmsg1(500, "my_dbi_getvalue error: %s\n", errmsg);
-//   }
-//                
-//   Dmsg2(500, "my_dbi_getvalue finish result '%p' num bytes '%d'\n",
-//      result, field_length);
-//   
-//   return 1;
-//}
-
 int my_dbi_sql_insert_id(B_DB *mdb, char *table_name)
 {
    /*
index 57bc4bc4324327d689042326769e3b6793e22321..031f81eff8d2fa32b85f22007c39b24b6059b558 100644 (file)
@@ -460,6 +460,7 @@ struct FOPTS {
    alist drivetype;                   /* drive type limitation */
    char *reader;                      /* reader program */
    char *writer;                      /* writer program */
+   char *ignoredir;                   /* ignoredir string */
    char *plugin;                      /* plugin program */
 };
 
index 827f6a3378cfc90a7fdcc6aac6ccc24d9508c0f2..2561e70c7891eda35533059ac0df83bfe52c62c8 100644 (file)
@@ -369,6 +369,9 @@ static bool send_fileset(JCR *jcr)
             if (fo->plugin) {
                fd->fsend("G %s\n", fo->plugin);
             }
+            if (fo->ignoredir) {
+               bnet_fsend(fd, "Z %s\n", fo->ignoredir);
+            }
             if (fo->reader) {
                fd->fsend("D %s\n", fo->reader);
             }
index 62837e42bcddaba53ff77602298ce963355e2759..3dc445fd9d3a95cf2bbb09f4527884fe773b307a 100644 (file)
@@ -58,6 +58,7 @@ static void options_res(LEX *lc, RES_ITEM *item, int index, int pass);
 static void store_base(LEX *lc, RES_ITEM *item, int index, int pass);
 static void store_plugin(LEX *lc, RES_ITEM *item, int index, int pass);
 static void store_reader(LEX *lc, RES_ITEM *item, int index, int pass);
+static void store_ignoredir(LEX *lc, RES_ITEM *item, int index, int pass);
 static void store_writer(LEX *lc, RES_ITEM *item, int index, int pass);
 static void setup_current_opts(void);
 
@@ -84,9 +85,10 @@ static INCEXE res_incexe;
  *   name             handler     value    code flags default_value
  */
 static RES_ITEM newinc_items[] = {
-   {"file",            store_fname,   {0},      0, 0, 0},
-   {"plugin",          store_plugin_name,   {0},      0, 0, 0},
-   {"options",         options_res,   {0},      0, 0, 0},
+   {"file",            store_fname,       {0},      0, 0, 0},
+   {"plugin",          store_plugin_name, {0},      0, 0, 0},
+   {"ignoredir",       store_ignoredir,   {0},      0, 0, 0},
+   {"options",         options_res,       {0},      0, 0, 0},
    {NULL, NULL, {0}, 0, 0, 0}
 };
 
@@ -604,6 +606,21 @@ static void store_fstype(LEX *lc, RES_ITEM *item, int index, int pass)
    scan_to_eol(lc);
 }
 
+/* Store ignoredir info */
+static void store_ignoredir(LEX *lc, RES_ITEM *item, int index, int pass)
+{
+   int token;
+
+   token = lex_get_token(lc, T_NAME);
+   if (pass == 1) {
+      /*
+       * Pickup reader command
+       */
+      res_incexe.current_opts->ignoredir = bstrdup(lc->str);
+   }
+   scan_to_eol(lc);
+}
+
 /* Store drivetype info */
 static void store_drivetype(LEX *lc, RES_ITEM *item, int index, int pass)
 {
index 56b15930b98d65c43889f253b5b29a7a76362e7e..cf3c1da50436fc1d4b586a5f2bcefff8eb8aefae 100644 (file)
@@ -567,8 +567,8 @@ static bool job_check_maxruntime(JCR *jcr)
       return false;
    }
    Dmsg6(200, "check_maxruntime %u - %u >= %u|%u|%u|%u\n\n",
-        watchdog_time, jcr->start_time, job->MaxRunTime, job->FullMaxRunTime, 
-        job->IncMaxRunTime, job->DiffMaxRunTime);
+         watchdog_time, jcr->start_time, job->MaxRunTime, job->FullMaxRunTime, 
+         job->IncMaxRunTime, job->DiffMaxRunTime);
 
    if (jcr->JobLevel == L_FULL && job->FullMaxRunTime != 0 &&
          (watchdog_time - jcr->start_time) >= job->FullMaxRunTime) {
@@ -1307,12 +1307,12 @@ void free_wstorage(JCR *jcr)
    jcr->wstore = NULL;
 }
 
-char *job_code_callback_clones(JCR *jcr, const char* param) {
-       if (param[0] == 'p') {
-               return jcr->pool->name();
-       } else {
-               return NULL;
-       }
+char *job_code_callback_clones(JCR *jcr, const char* param) 
+{
+   if (param[0] == 'p') {
+      return jcr->pool->name();
+   }
+   return NULL;
 }
 
 void create_clones(JCR *jcr)
index 1338e4a2f2548d16f2a458b24c3383c2d9d0a26b..6c45c3bb9ad488f1881712b04c190f14b9526d65 100644 (file)
@@ -321,6 +321,9 @@ void *handle_client_request(void *dirp)
             fo->base.destroy();
             fo->fstype.destroy();
             fo->drivetype.destroy();
+            if (fo->ignoredir != NULL) {
+               free(fo->ignoredir);
+            }
          }
          incexe->opts_list.destroy();
          incexe->name_list.destroy();
@@ -680,7 +683,7 @@ static void add_file_to_fileset(JCR *jcr, const char *fname, findFILESET *filese
       }
       break;
    case '<':
-      Dmsg0(100, "Doing < include on client.\n");
+      Dmsg1(100, "Doing < of '%s' include on client.\n", p + 1);
       p++;                      /* skip over < */
       if ((ffd = fopen(p, "rb")) == NULL) {
          berrno be;
@@ -846,6 +849,11 @@ static void add_fileset(JCR *jcr, const char *item)
       set_options(current_opts, item);
       state = state_options;
       break;
+   case 'Z':
+      current_opts = start_options(ff);
+      current_opts->ignoredir = bstrdup(item);
+      state = state_options;
+      break;
    case 'D':
       current_opts = start_options(ff);
 //    current_opts->reader = bstrdup(item);
@@ -907,6 +915,9 @@ static bool term_fileset(JCR *jcr)
          for (k=0; k<fo->drivetype.size(); k++) {
             Dmsg1(400, "XD %s\n", (char *)fo->drivetype.get(k));
          }
+         if (fo->ignoredir) {
+            Dmsg1(400, "Z %s\n", fo->ignoredir);
+         }
       }
       dlistString *node;
       foreach_dlist(node, &incexe->name_list) {
index 7e059e4b2281b5dca5c21a909a55f45e3f3f9b97..3542a5b43ad2c9f62fef70cf518ad288f63155e3 100644 (file)
@@ -280,6 +280,7 @@ static bool accept_file(FF_PKT *ff)
       findFOPTS *fo = (findFOPTS *)incexe->opts_list.get(j);
       ff->flags = fo->flags;
       ff->GZIP_level = fo->GZIP_level;
+      ff->ignoredir = fo->ignoredir;
       ff->fstypes = fo->fstype;
       ff->drivetypes = fo->drivetype;
 
index 040458d5d2cab2e1bc0b997e07883a7584e042cb..4c012f5981fcf6a320bb45f737b4a33f1beb7ced 100644 (file)
@@ -44,6 +44,7 @@
 #endif
 
 #include <sys/file.h>
+#include <sys/param.h>
 #if HAVE_UTIME_H
 #include <utime.h>
 #else
@@ -158,6 +159,7 @@ struct findFOPTS {
    alist base;                        /* list of base names */
    alist fstype;                      /* file system type limitation */
    alist drivetype;                   /* drive type limitation */
+   char *ignoredir;                   /* ignore directories with this file */
 };
 
 
@@ -223,6 +225,7 @@ struct FF_PKT {
    uint32_t flags;                    /* backup options */
    int GZIP_level;                    /* compression level */
    int strip_path;                    /* strip path count */
+   char *ignoredir;                   /* ignore directories with this file */
    bool cmd_plugin;                   /* set if we have a command plugin */
    alist fstypes;                     /* allowed file system types */
    alist drivetypes;                  /* allowed drive types */
index 576d4c6b88dbc0761e6738f93e94988eba7d0b49..7c22ee0a4156957435fdd7ea301c6ed871bb51dd 100644 (file)
@@ -513,6 +513,28 @@ find_one_file(JCR *jcr, FF_PKT *ff_pkt,
          }
       }
 
+      /*
+       * Ignore this directory and everything below if the file .nobackup
+       * (or what is defined for IgnoreDir in this fileset) exists
+       */
+      if (ff_pkt->ignoredir != NULL) {
+        struct stat sb;
+        char fname[MAXPATHLEN];
+
+        if (strlen(ff_pkt->fname) + strlen("/") +
+           strlen(ff_pkt->ignoredir) + 1 > MAXPATHLEN)
+           return 1;   /* Is this wisdom? */
+
+        strcpy(fname, ff_pkt->fname);
+        strcat(fname, "/");
+        strcat(fname, ff_pkt->ignoredir);
+        if (stat(fname, &sb) == 0) {
+            Dmsg2(100, "Directory '%s' ignored (found %s)\n",
+              ff_pkt->fname, ff_pkt->ignoredir);
+            return 1;      /* Just ignore this directory */
+        }
+      }
+
       /* Build a canonical directory name with a trailing slash in link var */
       len = strlen(fname);
       link_len = len + 200;
index 57bdc43f345165cdcf4747fd23f06ffe715cebeb..40e7b9d8bf83637bb5008d5aa92e5089da019573 100644 (file)
@@ -3,9 +3,9 @@
  */
 
 #undef  VERSION
-#define VERSION "2.3.18"
-#define BDATE   "01 May 2008"
-#define LSMDATE "01May08"
+#define VERSION "2.3.19"
+#define BDATE   "02 May 2008"
+#define LSMDATE "02May08"
 
 #define PROG_COPYRIGHT "Copyright (C) %d-2008 Free Software Foundation Europe e.V.\n"
 #define BYEAR "2008"       /* year for copyright messages in progs */
index 7d93b5e0664dcb000aa247cd6825731663476e50..96cdb8b566cde5d0cc074ad3265fd1dd8c329fb8 100644 (file)
@@ -24,6 +24,13 @@ Add long term statistics job table
 
 
 General:
+02May08
+kes  Apply libdbi patch from Joao Freitas for regress and for 
+     Bacula trunk. Regress now works with libdbi. Nice.
+kes  Apply .nobackup patch from bug #1077 submitted by 
+     Edwin Groothuis.
+kes  Apply Bastian Friedrich's patch that adds %p to edit the pool
+     name into jobs cloned via the run directive.
 01May08
 kes  Prevent a Volume that is being swapped from being freed from
      the volume list. This will most likely fix, at least partially,