]> git.sur5r.net Git - bacula/bacula/commitdiff
Merge branch 'master' into basejobv3
authorEric Bollengier <eric@eb.homelinux.org>
Mon, 7 Sep 2009 13:24:26 +0000 (15:24 +0200)
committerEric Bollengier <eric@eb.homelinux.org>
Mon, 7 Sep 2009 13:24:26 +0000 (15:24 +0200)
34 files changed:
bacula/patches/3.0.2-accurate.patch [new file with mode: 0644]
bacula/patches/3.0.2-bug-1365.patch [new file with mode: 0644]
bacula/patches/3.0.2-bug-1366.patch [new file with mode: 0644]
bacula/patches/3.0.2-mac-path-len.patch [new file with mode: 0644]
bacula/src/cats/sqlite.c
bacula/src/filed/acl.h
bacula/src/filed/backup.c
bacula/src/filed/restore.c
bacula/src/filed/restore.h [new file with mode: 0644]
bacula/src/filed/verify.c
bacula/src/filed/xattr.h
bacula/src/findlib/bfile.c
bacula/src/findlib/bfile.h
bacula/src/findlib/find.c
bacula/src/findlib/find.h
bacula/src/lib/crc32.c
bacula/src/stored/bextract.c
bacula/src/stored/block.c
bacula/src/stored/btape.c
bacula/src/stored/dev.h
bacula/src/stored/stored_conf.c
bacula/src/version.h
bacula/technotes
regress/.gitignore
regress/full-tape-tests [deleted file]
regress/scripts/bacula-sd-btape.conf.in
regress/tests/acl-xattr-test
regress/tests/btape-fill-full-changer
regress/tests/btape-fill-full-tape
regress/tests/btape-test-changer
regress/tests/btape-test-tape
regress/tests/certify-changer [new file with mode: 0755]
regress/tests/full-tape-tests [new file with mode: 0755]
regress/tests/next-vol-test

diff --git a/bacula/patches/3.0.2-accurate.patch b/bacula/patches/3.0.2-accurate.patch
new file mode 100644 (file)
index 0000000..18225ad
--- /dev/null
@@ -0,0 +1,341 @@
+
+ This patch can be applied to version 3.0.2 and fixes
+ bug #1355 'bacula director crashes with double free
+ in Accurate SQL query'
+
+ Apply it to version 3.0.2 with:
+
+ cd <bacula-source>
+ patch -p2 <3.0.2-accurate.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+
+diff --git a/bacula/src/cats/cats.h b/bacula/src/cats/cats.h
+index 2ff803f..be07e84 100644
+--- a/bacula/src/cats/cats.h
++++ b/bacula/src/cats/cats.h
+@@ -1037,6 +1037,16 @@ struct db_int64_ctx {
+    int count;                         /* number of values seen */
+ };
++/* Call back context for getting a list of comma separated strings from the database */
++class db_list_ctx {
++public:
++   POOLMEM *list;                     /* list */
++   int count;                         /* number of values seen */
++
++   db_list_ctx() { list = get_pool_memory(PM_FNAME); *list = 0; count = 0; }
++   ~db_list_ctx() { free_pool_memory(list); list = NULL; }
++};
++
+ #include "protos.h"
+ #include "jcr.h"
+diff --git a/bacula/src/cats/protos.h b/bacula/src/cats/protos.h
+index ea03a3c..565526a 100644
+--- a/bacula/src/cats/protos.h
++++ b/bacula/src/cats/protos.h
+@@ -1,7 +1,7 @@
+ /*
+    Bacula® - The Network Backup Solution
+-   Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
++   Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
+    The main author of Bacula is Kern Sibbald, with contributions from
+    many others, a complete list can be found in the file AUTHORS.
+@@ -57,6 +57,7 @@ bool db_sql_query(B_DB *mdb, const char *cmd, DB_RESULT_HANDLER *result_handler,
+ void db_start_transaction(JCR *jcr, B_DB *mdb);
+ void db_end_transaction(JCR *jcr, B_DB *mdb);
+ int db_int64_handler(void *ctx, int num_fields, char **row);
++int db_list_handler(void *ctx, int num_fields, char **row);
+ void db_thread_cleanup();
+ void _dbg_print_db(JCR *jcr, FILE *fp);
+@@ -106,8 +107,8 @@ int db_get_client_record(JCR *jcr, B_DB *mdb, CLIENT_DBR *cdbr);
+ int db_get_counter_record(JCR *jcr, B_DB *mdb, COUNTER_DBR *cr);
+ bool db_get_query_dbids(JCR *jcr, B_DB *mdb, POOL_MEM &query, dbid_list &ids);
+ bool db_get_file_list(JCR *jcr, B_DB *mdb, char *jobids, DB_RESULT_HANDLER *result_handler, void *ctx);
+-bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb, JOB_DBR *jr, POOLMEM *jobids);
+-int db_get_int_handler(void *ctx, int num_fields, char **row);
++bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb, JOB_DBR *jr, db_list_ctx *jobids);
++int db_get_int_handler(void *list, int num_fields, char **row);
+ /* sql_list.c */
+diff --git a/bacula/src/cats/sql.c b/bacula/src/cats/sql.c
+index 324d017..e698b5a 100644
+--- a/bacula/src/cats/sql.c
++++ b/bacula/src/cats/sql.c
+@@ -144,7 +144,21 @@ int db_int64_handler(void *ctx, int num_fields, char **row)
+    return 0;
+ }
+-
++/*
++ * Use to build a comma separated list of values from a query. "10,20,30"
++ */
++int db_list_handler(void *ctx, int num_fields, char **row)
++{
++   db_list_ctx *lctx = (db_list_ctx *)ctx;
++   if (num_fields == 1 && row[0]) {
++      if (lctx->list[0]) {
++         pm_strcat(lctx->list, ",");
++      }
++      pm_strcat(lctx->list, row[0]);
++      lctx->count++;
++   }
++   return 0;
++}
+ /* NOTE!!! The following routines expect that the
+  *  calling subroutine sets and clears the mutex
+diff --git a/bacula/src/cats/sql_get.c b/bacula/src/cats/sql_get.c
+index b9d25bb..62cd07c 100644
+--- a/bacula/src/cats/sql_get.c
++++ b/bacula/src/cats/sql_get.c
+@@ -1,7 +1,7 @@
+ /*
+    Bacula® - The Network Backup Solution
+-   Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
++   Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
+    The main author of Bacula is Kern Sibbald, with contributions from
+    many others, a complete list can be found in the file AUTHORS.
+@@ -1100,7 +1100,7 @@ bool db_get_file_list(JCR *jcr, B_DB *mdb, char *jobids,
+  * TODO: look and merge from ua_restore.c
+  */
+ bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb, 
+-                            JOB_DBR *jr, POOLMEM *jobids)
++                            JOB_DBR *jr, db_list_ctx *jobids)
+ {
+    bool ret=false;
+    char clientid[50], jobid[50], filesetid[50];
+@@ -1111,7 +1111,8 @@ bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb,
+    time_t StartTime = (jr->StartTime)?jr->StartTime:time(NULL);
+    bstrutime(date, sizeof(date),  StartTime + 1);
+-   jobids[0]='\0';
++   jobids->list[0] = 0;
++   jobids->count = 0;
+    /* First, find the last good Full backup for this job/client/fileset */
+    Mmsg(query, 
+@@ -1177,8 +1178,8 @@ bool db_accurate_get_jobids(JCR *jcr, B_DB *mdb,
+    /* build a jobid list ie: 1,2,3,4 */
+    Mmsg(query, "SELECT JobId FROM btemp3%s ORDER by JobTDate", jobid);
+-   db_sql_query(mdb, query.c_str(), db_get_int_handler, jobids);
+-   Dmsg1(1, "db_accurate_get_jobids=%s\n", jobids);
++   db_sql_query(mdb, query.c_str(), db_list_handler, jobids);
++   Dmsg1(1, "db_accurate_get_jobids=%s\n", jobids->list);
+    ret = true;
+ bail_out:
+@@ -1188,19 +1189,4 @@ bail_out:
+    return ret;
+ }
+-/*
+- * Use to build a string of int list from a query. "10,20,30"
+- */
+-int db_get_int_handler(void *ctx, int num_fields, char **row)
+-{
+-   POOLMEM *ret = (POOLMEM *)ctx;
+-   if (num_fields == 1) {
+-      if (ret[0]) {
+-         pm_strcat(ret, ",");
+-      }
+-      pm_strcat(ret, row[0]);
+-   }
+-   return 0;
+-}
+-
+ #endif /* HAVE_SQLITE3 || HAVE_MYSQL || HAVE_SQLITE || HAVE_POSTGRESQL || HAVE_DBI */
+diff --git a/bacula/src/dird/backup.c b/bacula/src/dird/backup.c
+index 029dfa0..1837a6b 100644
+--- a/bacula/src/dird/backup.c
++++ b/bacula/src/dird/backup.c
+@@ -131,42 +131,37 @@ static int accurate_list_handler(void *ctx, int num_fields, char **row)
+ bool send_accurate_current_files(JCR *jcr)
+ {
+    POOL_MEM buf;
++   db_list_ctx jobids;
++   db_list_ctx nb;
+    if (!jcr->accurate || job_canceled(jcr) || jcr->get_JobLevel()==L_FULL) {
+       return true;
+    }
+-   POOLMEM *jobids = get_pool_memory(PM_FNAME);
+-   db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, jobids);
+-
+-   if (*jobids == 0) {
+-      free_pool_memory(jobids);
++   db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, &jobids);
++   if (jobids.count == 0) {
+       Jmsg(jcr, M_FATAL, 0, _("Cannot find previous jobids.\n"));
+       return false;
+    }
++
+    if (jcr->JobId) {            /* display the message only for real jobs */
+       Jmsg(jcr, M_INFO, 0, _("Sending Accurate information.\n"));
+    }
+    /* to be able to allocate the right size for htable */
+-   POOLMEM *nb = get_pool_memory(PM_FNAME);
+-   *nb = 0;                           /* clear buffer */
+-   Mmsg(buf, "SELECT sum(JobFiles) FROM Job WHERE JobId IN (%s)",jobids);
+-   db_sql_query(jcr->db, buf.c_str(), db_get_int_handler, nb);
+-   Dmsg2(200, "jobids=%s nb=%s\n", jobids, nb);
+-   jcr->file_bsock->fsend("accurate files=%s\n", nb); 
++   Mmsg(buf, "SELECT sum(JobFiles) FROM Job WHERE JobId IN (%s)",jobids.list);
++   db_sql_query(jcr->db, buf.c_str(), db_list_handler, &nb);
++   Dmsg2(200, "jobids=%s nb=%s\n", jobids.list, nb.list);
++   jcr->file_bsock->fsend("accurate files=%s\n", nb.list); 
+    if (!db_open_batch_connexion(jcr, jcr->db)) {
+       Jmsg0(jcr, M_FATAL, 0, "Can't get dedicate sql connexion");
+       return false;
+    }
+-   db_get_file_list(jcr, jcr->db_batch, jobids, accurate_list_handler, (void *)jcr);
++   db_get_file_list(jcr, jcr->db_batch, jobids.list, accurate_list_handler, (void *)jcr);
+    /* TODO: close the batch connexion ? (can be used very soon) */
+-   free_pool_memory(jobids);
+-   free_pool_memory(nb);
+-
+    jcr->file_bsock->signal(BNET_EOD);
+    return true;
+diff --git a/bacula/src/dird/ua_output.c b/bacula/src/dird/ua_output.c
+index 3d5fc1d..028be52 100644
+--- a/bacula/src/dird/ua_output.c
++++ b/bacula/src/dird/ua_output.c
+@@ -456,7 +456,7 @@ static int do_list_cmd(UAContext *ua, const char *cmd, e_list_type llist)
+          }
+          list_nextvol(ua, n);
+       } else if (strcasecmp(ua->argk[i], NT_("copies")) == 0) {
+-         char *jobids=NULL;
++         char *jobids = NULL;
+          uint32_t limit=0;
+          for (j=i+1; j<ua->argc; j++) {
+             if (strcasecmp(ua->argk[j], NT_("jobid")) == 0 && ua->argv[j]) {
+diff --git a/bacula/src/dird/ua_restore.c b/bacula/src/dird/ua_restore.c
+index 366d9ed..16f5215 100644
+--- a/bacula/src/dird/ua_restore.c
++++ b/bacula/src/dird/ua_restore.c
+@@ -1,7 +1,7 @@
+ /*
+    Bacula® - The Network Backup Solution
+-   Copyright (C) 2002-2008 Free Software Foundation Europe e.V.
++   Copyright (C) 2002-2009 Free Software Foundation Europe e.V.
+    The main author of Bacula is Kern Sibbald, with contributions from
+    many others, a complete list can be found in the file AUTHORS.
+@@ -556,6 +556,7 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
+       char *fname;
+       int len;
+       bool gui_save;
++      db_list_ctx jobids;
+       start_prompt(ua, _("To select the JobIds, you have the following choices:\n"));
+       for (int i=0; list[i]; i++) {
+@@ -752,9 +753,10 @@ static int user_select_jobids_or_files(UAContext *ua, RESTORE_CTX *rx)
+             return 0;
+          }
+          jr.JobLevel = L_INCREMENTAL; /* Take Full+Diff+Incr */
+-         if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, rx->JobIds)) {
++         if (!db_accurate_get_jobids(ua->jcr, ua->db, &jr, &jobids)) {
+             return 0;
+          }
++         pm_strcpy(rx->JobIds, jobids.list);
+          Dmsg1(30, "Item 12: jobids = %s\n", rx->JobIds);
+          break;
+       case 12:                        /* Cancel or quit */
+diff --git a/bacula/src/dird/vbackup.c b/bacula/src/dird/vbackup.c
+index 45a1f7e..e75d08d 100644
+--- a/bacula/src/dird/vbackup.c
++++ b/bacula/src/dird/vbackup.c
+@@ -50,7 +50,7 @@
+ static const int dbglevel = 10;
+-static bool create_bootstrap_file(JCR *jcr, POOLMEM *jobids);
++static bool create_bootstrap_file(JCR *jcr, char *jobids);
+ void vbackup_cleanup(JCR *jcr, int TermCode);
+ /* 
+@@ -135,6 +135,7 @@ bool do_vbackup(JCR *jcr)
+    char ed1[100];
+    BSOCK *sd;
+    char *p;
++   db_list_ctx jobids;
+    Dmsg2(100, "rstorage=%p wstorage=%p\n", jcr->rstorage, jcr->wstorage);
+    Dmsg2(100, "Read store=%s, write store=%s\n", 
+@@ -157,28 +158,27 @@ bool do_vbackup(JCR *jcr)
+ _("This Job is not an Accurate backup so is not equivalent to a Full backup.\n"));
+    }
+-   POOLMEM *jobids = get_pool_memory(PM_FNAME);
+    jcr->jr.JobLevel = L_VIRTUAL_FULL;
+-   db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, jobids);
+-   jcr->jr.JobLevel = L_FULL;
+-   Dmsg1(10, "Accurate jobids=%s\n", jobids);
+-   if (*jobids == 0) {
+-      free_pool_memory(jobids);
++   db_accurate_get_jobids(jcr, jcr->db, &jcr->jr, &jobids);
++   Dmsg1(10, "Accurate jobids=%s\n", jobids.list);
++   if (jobids.count == 0) {
+       Jmsg(jcr, M_FATAL, 0, _("No previous Jobs found.\n"));
+       return false;
+    }
++   jcr->jr.JobLevel = L_FULL;
++
+    /*
+     * Now we find the last job that ran and store it's info in
+     *  the previous_jr record.  We will set our times to the
+     *  values from that job so that anything changed after that
+     *  time will be picked up on the next backup.
+     */
+-   p = strrchr(jobids, ',');              /* find last jobid */
++   p = strrchr(jobids.list, ',');           /* find last jobid */
+    if (p != NULL) {
+       p++;
+    } else {
+-      p = jobids;
++      p = jobids.list;
+    }
+    memset(&jcr->previous_jr, 0, sizeof(jcr->previous_jr));
+    jcr->previous_jr.JobId = str_to_int64(p);
+@@ -189,12 +189,10 @@ _("This Job is not an Accurate backup so is not equivalent to a Full backup.\n")
+       return false;
+    }
+-   if (!create_bootstrap_file(jcr, jobids)) {
++   if (!create_bootstrap_file(jcr, jobids.list)) {
+       Jmsg(jcr, M_FATAL, 0, _("Could not get or create the FileSet record.\n"));
+-      free_pool_memory(jobids);
+       return false;
+    }
+-   free_pool_memory(jobids);
+    /*
+     * Open a message channel connection with the Storage
+@@ -476,7 +474,7 @@ int insert_bootstrap_handler(void *ctx, int num_fields, char **row)
+ }
+-static bool create_bootstrap_file(JCR *jcr, POOLMEM *jobids)
++static bool create_bootstrap_file(JCR *jcr, char *jobids)
+ {
+    RESTORE_CTX rx;
+    UAContext *ua;
diff --git a/bacula/patches/3.0.2-bug-1365.patch b/bacula/patches/3.0.2-bug-1365.patch
new file mode 100644 (file)
index 0000000..785d33e
--- /dev/null
@@ -0,0 +1,70 @@
+>From f182fe49fca2b2e3009f26fbf6197f8c046835ad Mon Sep 17 00:00:00 2001
+From: Marco van Wieringen <mvw@planets.elm.net>
+Date: Sun, 6 Sep 2009 17:56:20 +0200
+Subject: [PATCH] This patch should fix bug #1365
+
+---
+ bacula/src/filed/restore.c |   15 +++++++--------
+ 1 files changed, 7 insertions(+), 8 deletions(-)
+
+diff --git a/bacula/src/filed/restore.c b/bacula/src/filed/restore.c
+index a4ee03a..4400e14 100644
+--- a/bacula/src/filed/restore.c
++++ b/bacula/src/filed/restore.c
+@@ -120,7 +120,7 @@ static void close_previous_stream(r_ctx &rctx);
+ static bool verify_signature(JCR *jcr, r_ctx &rctx);
+-int32_t extract_data(JCR *jcr, r_ctx &rctx, POOLMEM *buf, int32_t buflen,
++int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
+                      uint64_t *addr, int flags, RESTORE_CIPHER_CTX *cipher_ctx);
+ bool flush_cipher(JCR *jcr, BFILE *bfd, uint64_t *addr, int flags, 
+                   RESTORE_CIPHER_CTX *cipher_ctx);
+@@ -508,8 +508,9 @@ void do_restore(JCR *jcr)
+                rctx.flags |= FO_WIN32DECOMP;    /* "decompose" BackupWrite data */
+             }
+-            if (extract_data(jcr, rctx, sd->msg, sd->msglen, &rctx.fileAddr, 
++            if (extract_data(jcr, &rctx.bfd, sd->msg, sd->msglen, &rctx.fileAddr,
+                              rctx.flags, &rctx.cipher_ctx) < 0) {
++               rctx.extract = false;
+                bclose(&rctx.bfd);
+                continue;
+             }
+@@ -558,8 +559,9 @@ void do_restore(JCR *jcr)
+                Dmsg0(130, "Restoring resource fork\n");
+             }
+-            if (extract_data(jcr, rctx, sd->msg, sd->msglen, &rctx.fork_addr, rctx.fork_flags, 
++            if (extract_data(jcr, &rctx.forkbfd, sd->msg, sd->msglen, &rctx.fork_addr, rctx.fork_flags,
+                              &rctx.fork_cipher_ctx) < 0) {
++               rctx.extract = false;
+                bclose(&rctx.forkbfd);
+                continue;
+             }
+@@ -1069,10 +1071,9 @@ bool store_data(JCR *jcr, BFILE *bfd, char *data, const int32_t length, bool win
+  * The flags specify whether to use sparse files or compression.
+  * Return value is the number of bytes written, or -1 on errors.
+  */
+-int32_t extract_data(JCR *jcr, r_ctx &rctx, POOLMEM *buf, int32_t buflen,
+-      uint64_t *addr, int flags, RESTORE_CIPHER_CTX *cipher_ctx)
++int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
++                     uint64_t *addr, int flags, RESTORE_CIPHER_CTX *cipher_ctx)
+ {
+-   BFILE *bfd = &rctx.bfd;
+    char *wbuf;                        /* write buffer */
+    uint32_t wsize;                    /* write size */
+    uint32_t rsize;                    /* read size */
+@@ -1172,9 +1173,7 @@ int32_t extract_data(JCR *jcr, r_ctx &rctx, POOLMEM *buf, int32_t buflen,
+    return wsize;
+ bail_out:
+-   rctx.extract = false;
+    return -1;
+-
+ }
+-- 
+1.5.6.5
+
diff --git a/bacula/patches/3.0.2-bug-1366.patch b/bacula/patches/3.0.2-bug-1366.patch
new file mode 100644 (file)
index 0000000..8222a85
--- /dev/null
@@ -0,0 +1,42 @@
+>From 297ec720cf512a6b5045c962bfb8a2f134ac77b0 Mon Sep 17 00:00:00 2001
+From: Marco van Wieringen <mvw@planets.elm.net>
+Date: Sun, 6 Sep 2009 18:06:48 +0200
+Subject: [PATCH] This patch should fix bug #1366
+
+---
+ bacula/src/filed/restore.c |   11 ++++++++++-
+ 1 files changed, 10 insertions(+), 1 deletions(-)
+
+diff --git a/bacula/src/filed/restore.c b/bacula/src/filed/restore.c
+index 4400e14..cbb0889 100644
+--- a/bacula/src/filed/restore.c
++++ b/bacula/src/filed/restore.c
+@@ -367,7 +367,6 @@ void do_restore(JCR *jcr)
+             rctx.extract = true;
+             /* FALLTHROUGH */
+          case CF_CREATED:        /* File created, but there is no content */
+-            jcr->JobFiles++;
+             rctx.fileAddr = 0;
+             print_ls_output(jcr, attr);
+@@ -377,7 +376,17 @@ void do_restore(JCR *jcr)
+                if (attr->type == FT_REG && rsrc_len > 0) {
+                   rctx.extract = true;
+                }
++
++               /*
++                * Count the resource forks not as regular files being restored.
++                */
++               if (rsrc_len == 0) {
++                  jcr->JobFiles++;
++               }
++            } else {
++               jcr->JobFiles++;
+             }
++
+             if (!rctx.extract) {
+                /* set attributes now because file will not be extracted */
+                if (jcr->plugin) {
+-- 
+1.5.6.5
+
diff --git a/bacula/patches/3.0.2-mac-path-len.patch b/bacula/patches/3.0.2-mac-path-len.patch
new file mode 100644 (file)
index 0000000..1755ad6
--- /dev/null
@@ -0,0 +1,38 @@
+ This patch can be applied to version 3.0.2 and fixes
+ bug #1368 ASSERT Failure on MacOS. Unfortunately,
+ MacOS programmers do not respect/implement POSIX
+ pathconf().
+
+ Apply it to version 3.0.2 with:
+
+ cd <bacula-source>
+ patch -p2 <3.0.2-mac-path-len.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+
+
+diff --git a/bacula/src/findlib/find.c b/bacula/src/findlib/find.c
+index ac9e4ce..81e887a 100644
+--- a/bacula/src/findlib/find.c
++++ b/bacula/src/findlib/find.c
+@@ -67,13 +67,13 @@ FF_PKT *init_find_files()
+    /* Get system path and filename maximum lengths */
+    path_max = pathconf(".", _PC_PATH_MAX);
+-   if (path_max < 1024) {
+-      path_max = 1024;
++   if (path_max < 2048) {
++      path_max = 2048;
+    }
+    name_max = pathconf(".", _PC_NAME_MAX);
+-   if (name_max < 1024) {
+-      name_max = 1024;
++   if (name_max < 2048) {
++      name_max = 2048;
+    }
+    path_max++;                        /* add for EOS */
+    name_max++;                        /* add for EOS */
index ae618c7e29cfb43099fcaf8a2ee6e473bb746e19..003036647ad80cae773829e8782a318b7a64d4af 100644 (file)
@@ -403,12 +403,12 @@ void my_sqlite_free_table(B_DB *mdb)
 
    if (mdb->fields_defined) {
       for (i=0; i < sql_num_fields(mdb); i++) {
-         if (mdb->fileds[i]) {
+         if (mdb->fields[i]) {
             free(mdb->fields[i]);
             mdb->fields[i] = NULL;
          }
       }
-      if (mbd->fields) {
+      if (mdb->fields) {
          free(mdb->fields);
          mdb->fields = NULL;
       }
index dc60ce41ec239f9146faf54ac99d382f6955e796..fe389734fd4ba18ba7ca457e9f38a54fc1061e8e 100644 (file)
@@ -29,8 +29,8 @@
  * Properties we use for getting and setting ACLs.
  */
 
-#ifndef _BACULA_ACL_
-#define _BACULA_ACL_
+#ifndef __ACL_H
+#define __ACL_H
 
 /* For shorter ACL strings when possible, define BACL_WANT_SHORT_ACLS */
 /* #define BACL_WANT_SHORT_ACLS */
index ff8265aea77d6f2894b20bdb6c7ebf3570c95bd3..d1e5a030abf02aff655643691036db6c27394aa4 100644 (file)
 #include "bacula.h"
 #include "filed.h"
 
+#ifdef HAVE_DARWIN_OS
+const bool have_darwin_os = true;
+#else
+const bool have_darwin_os = false;
+#endif
+
 #if defined(HAVE_ACL)
 const bool have_acl = true;
 #else
@@ -564,54 +570,54 @@ int save_file(JCR *jcr, FF_PKT *ff_pkt, bool top_level)
       }
    }
 
-#ifdef HAVE_DARWIN_OS
-   /* Regular files can have resource forks and Finder Info */
-   if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
-            ff_pkt->flags & FO_HFSPLUS)) {
-      if (ff_pkt->hfsinfo.rsrclength > 0) {
-         int flags;
-         int rsrc_stream;
-         if (!bopen_rsrc(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
-            ff_pkt->ff_errno = errno;
-            berrno be;
-            Jmsg(jcr, M_NOTSAVED, -1, _("     Cannot open resource fork for \"%s\": ERR=%s.\n"), 
-                 ff_pkt->fname, be.bstrerror());
-            jcr->JobErrors++;
-            if (is_bopen(&ff_pkt->bfd)) {
-               bclose(&ff_pkt->bfd);
+   if (have_darwin_os) {
+      /* Regular files can have resource forks and Finder Info */
+      if (ff_pkt->type != FT_LNKSAVED && (S_ISREG(ff_pkt->statp.st_mode) &&
+          ff_pkt->flags & FO_HFSPLUS)) {
+         if (ff_pkt->hfsinfo.rsrclength > 0) {
+            int flags;
+            int rsrc_stream;
+            if (!bopen_rsrc(&ff_pkt->bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
+               ff_pkt->ff_errno = errno;
+               berrno be;
+               Jmsg(jcr, M_NOTSAVED, -1, _("     Cannot open resource fork for \"%s\": ERR=%s.\n"),
+                    ff_pkt->fname, be.bstrerror());
+               jcr->JobErrors++;
+               if (is_bopen(&ff_pkt->bfd)) {
+                  bclose(&ff_pkt->bfd);
+               }
+               goto good_rtn;
+            }
+            flags = ff_pkt->flags;
+            ff_pkt->flags &= ~(FO_GZIP|FO_SPARSE);
+            if (flags & FO_ENCRYPT) {
+               rsrc_stream = STREAM_ENCRYPTED_MACOS_FORK_DATA;
+            } else {
+               rsrc_stream = STREAM_MACOS_FORK_DATA;
+            }
+            stat = send_data(jcr, rsrc_stream, ff_pkt, digest, signing_digest);
+            ff_pkt->flags = flags;
+            bclose(&ff_pkt->bfd);
+            if (!stat) {
+               goto bail_out;
             }
-            goto good_rtn;
          }
-         flags = ff_pkt->flags;
-         ff_pkt->flags &= ~(FO_GZIP|FO_SPARSE);
-         if (flags & FO_ENCRYPT) {
-            rsrc_stream = STREAM_ENCRYPTED_MACOS_FORK_DATA;
-         } else {
-            rsrc_stream = STREAM_MACOS_FORK_DATA;
+
+         Dmsg1(300, "Saving Finder Info for \"%s\"\n", ff_pkt->fname);
+         sd->fsend("%ld %d 0", jcr->JobFiles, STREAM_HFSPLUS_ATTRIBUTES);
+         Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
+         pm_memcpy(sd->msg, ff_pkt->hfsinfo.fndrinfo, 32);
+         sd->msglen = 32;
+         if (digest) {
+            crypto_digest_update(digest, (uint8_t *)sd->msg, sd->msglen);
          }
-         stat = send_data(jcr, rsrc_stream, ff_pkt, digest, signing_digest);
-         ff_pkt->flags = flags;
-         bclose(&ff_pkt->bfd);
-         if (!stat) {
-            goto bail_out;
+         if (signing_digest) {
+            crypto_digest_update(signing_digest, (uint8_t *)sd->msg, sd->msglen);
          }
+         sd->send();
+         sd->signal(BNET_EOD);
       }
-
-      Dmsg1(300, "Saving Finder Info for \"%s\"\n", ff_pkt->fname);
-      sd->fsend("%ld %d 0", jcr->JobFiles, STREAM_HFSPLUS_ATTRIBUTES);
-      Dmsg1(300, "bfiled>stored:header %s\n", sd->msg);
-      pm_memcpy(sd->msg, ff_pkt->hfsinfo.fndrinfo, 32);
-      sd->msglen = 32;
-      if (digest) {
-         crypto_digest_update(digest, (uint8_t *)sd->msg, sd->msglen);
-      }
-      if (signing_digest) {
-         crypto_digest_update(signing_digest, (uint8_t *)sd->msg, sd->msglen);
-      }
-      sd->send();
-      sd->signal(BNET_EOD);
    }
-#endif
 
    /*
     * Save ACLs when requested and available for anything not being a symlink and not being a plugin.
index 808daec84b14a4f5b3867cf85888134df2d57b68..a9e072975b5acacb285996575209ae9332daf692 100644 (file)
  *
  *    Kern Sibbald, November MM
  *
- *   Version $Id$
- *
  */
 
 #include "bacula.h"
 #include "filed.h"
+#include "restore.h"
 
 #ifdef HAVE_DARWIN_OS
 #include <sys/attr.h>
@@ -68,42 +67,14 @@ const bool have_xattr = true;
 const bool have_xattr = false;
 #endif
 
-/* Data received from Storage Daemon */
+/*
+ * Data received from Storage Daemon
+ */
 static char rec_header[] = "rechdr %ld %ld %ld %ld %ld";
 
-typedef struct restore_cipher_ctx {
-   CIPHER_CONTEXT *cipher;
-   uint32_t block_size;
-
-   POOLMEM *buf;       /* Pointer to descryption buffer */
-   int32_t buf_len;    /* Count of bytes currently in buf */ 
-   int32_t packet_len; /* Total bytes in packet */
-} RESTORE_CIPHER_CTX;
-
-struct r_ctx {
-   JCR *jcr;
-   int32_t stream;
-   int32_t prev_stream;
-   BFILE bfd;                          /* File content */
-   uint64_t fileAddr;                  /* file write address */
-   uint32_t size;                      /* Size of file */
-   int flags;                          /* Options for extract_data() */
-   BFILE forkbfd;                      /* Alternative data stream */
-   uint64_t fork_addr;                 /* Write address for alternative stream */
-   intmax_t fork_size;                 /* Size of alternate stream */
-   int fork_flags;                     /* Options for extract_data() */
-   int32_t type;                       /* file type FT_ */
-   ATTR *attr;                         /* Pointer to attributes */
-   bool extract;                       /* set when extracting */
-
-   SIGNATURE *sig;                     /* Cryptographic signature (if any) for file */
-   CRYPTO_SESSION *cs;                 /* Cryptographic session data (if any) for file */
-   RESTORE_CIPHER_CTX cipher_ctx;      /* Cryptographic restore context (if any) for file */
-   RESTORE_CIPHER_CTX fork_cipher_ctx; /* Cryptographic restore context (if any) for alternative stream */
-};
-
-
-/* Forward referenced functions */
+/*
+ * Forward referenced functions
+ */
 #if   defined(HAVE_LIBZ)
 static const char *zlib_strerror(int stat);
 const bool have_libz = true;
@@ -117,15 +88,12 @@ static void free_signature(r_ctx &rctx);
 static void free_session(r_ctx &rctx);
 static void close_previous_stream(r_ctx &rctx);
 
-
-
 static bool verify_signature(JCR *jcr, r_ctx &rctx);
-int32_t extract_data(JCR *jcr, r_ctx &rctx, POOLMEM *buf, int32_t buflen,
+int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
                      uint64_t *addr, int flags, RESTORE_CIPHER_CTX *cipher_ctx);
 bool flush_cipher(JCR *jcr, BFILE *bfd, uint64_t *addr, int flags, 
                   RESTORE_CIPHER_CTX *cipher_ctx);
 
-
 /*
  * Close a bfd check that we are at the expected file offset.
  * Makes use of some code from set_attributes().
@@ -136,7 +104,7 @@ static int bclose_chksize(JCR *jcr, BFILE *bfd, boffset_t osize)
    boffset_t fsize;
 
    fsize = blseek(bfd, 0, SEEK_CUR);
-   bclose(bfd);                              /* first close file */
+   bclose(bfd);
    if (fsize > 0 && fsize != osize) {
       Qmsg3(jcr, M_ERROR, 0, _("Size of data or stream of %s not correct. Original %s, restored %s.\n"),
             jcr->last_fname, edit_uint64(osize, ec1),
@@ -146,18 +114,46 @@ static int bclose_chksize(JCR *jcr, BFILE *bfd, boffset_t osize)
    return 0;
 }
 
+#ifdef HAVE_DARWIN_OS
+bool restore_finderinfo(JCR *jcr, POOLMEM *buf, int32_t buflen)
+{
+   struct attrlist attrList;
+
+   memset(&attrList, 0, sizeof(attrList));
+   attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
+   attrList.commonattr = ATTR_CMN_FNDRINFO;
+
+   Dmsg0(130, "Restoring Finder Info\n");
+   jcr->ff->flags |= FO_HFSPLUS;
+   if (buflen != 32) {
+      Jmsg(jcr, M_ERROR, 0, _("Invalid length of Finder Info (got %d, not 32)\n"), sd->msglen);
+      return false;
+   }
+
+   if (setattrlist(jcr->last_fname, &attrList, buf, buflen, 0) != 0) {
+      Jmsg(jcr, M_ERROR, 0, _("Could not set Finder Info on %s\n"), jcr->last_fname);
+      return false;
+   }
+
+   return true;
+}
+#else
+bool restore_finderinfo(JCR *jcr, POOLMEM *buf, int32_t buflen)
+{
+   return true;
+}
+#endif
 
 /*
  * Restore the requested files.
- *
  */
 void do_restore(JCR *jcr)
 {
    BSOCK *sd;
    uint32_t VolSessionId, VolSessionTime;
    int32_t file_index;
-   char ec1[50];                       /* Buffer printing huge values */
-   uint32_t buf_size;                  /* client buffer size */
+   char ec1[50];                      /* Buffer printing huge values */
+   uint32_t buf_size;                 /* client buffer size */
    int stat;
    intmax_t rsrc_len = 0;             /* Original length of resource fork */
    r_ctx rctx;
@@ -168,7 +164,9 @@ void do_restore(JCR *jcr)
    memset(&rctx, 0, sizeof(rctx));
    rctx.jcr = jcr;
 
-   /* The following variables keep track of "known unknowns" */
+   /*
+    * The following variables keep track of "known unknowns"
+    */
    int non_support_data = 0;
    int non_support_attr = 0;
    int non_support_rsrc = 0;
@@ -178,14 +176,6 @@ void do_restore(JCR *jcr)
    int non_support_crypto = 0;
    int non_support_xattr = 0;
 
-#ifdef HAVE_DARWIN_OS
-   struct attrlist attrList;
-   memset(&attrList, 0, sizeof(attrList));
-   attrList.bitmapcount = ATTR_BIT_MAP_COUNT;
-   attrList.commonattr = ATTR_CMN_FNDRINFO;
-#endif
-
-
    sd = jcr->store_bsock;
    set_jcr_job_status(jcr, JS_Running);
 
@@ -203,11 +193,13 @@ void do_restore(JCR *jcr)
    }
    jcr->buf_size = sd->msglen;
 
-   /* St Bernard code goes here if implemented -- see end of file */
+   /*
+    * St Bernard code goes here if implemented -- see end of file
+    */
 
    if (have_libz) {
       uint32_t compress_buf_size = jcr->buf_size + 12 + ((jcr->buf_size+999) / 1000) + 100;
-      jcr->compress_buf = (char *)bmalloc(compress_buf_size);
+      jcr->compress_buf = get_memory(compress_buf_size);
       jcr->compress_buf_size = compress_buf_size;
    }
 
@@ -262,10 +254,14 @@ void do_restore(JCR *jcr)
    }
 
    while (bget_msg(sd) >= 0 && !job_canceled(jcr)) {
-      /* Remember previous stream type */
+      /*
+       * Remember previous stream type
+       */
       rctx.prev_stream = rctx.stream;
 
-      /* First we expect a Stream Record Header */
+      /*
+       * First we expect a Stream Record Header
+       */
       if (sscanf(sd->msg, rec_header, &VolSessionId, &VolSessionTime, &file_index,
           &rctx.stream, &rctx.size) != 5) {
          Jmsg1(jcr, M_FATAL, 0, _("Record header scan error: %s\n"), sd->msg);
@@ -274,7 +270,9 @@ void do_restore(JCR *jcr)
       Dmsg5(50, "Got hdr: Files=%d FilInx=%d size=%d Stream=%d, %s.\n", 
             jcr->JobFiles, file_index, rctx.size, rctx.stream, stream_to_ascii(rctx.stream));
 
-      /* * Now we expect the Stream Data */
+      /*
+       * Now we expect the Stream Data
+       */
       if (bget_msg(sd) < 0) {
          Jmsg1(jcr, M_FATAL, 0, _("Data record error. ERR=%s\n"), sd->bstrerror());
          goto bail_out;
@@ -289,24 +287,35 @@ void do_restore(JCR *jcr)
       Dmsg3(130, "Got stream: %s len=%d extract=%d\n", stream_to_ascii(rctx.stream), 
             sd->msglen, rctx.extract);
 
-      /* If we change streams, close and reset alternate data streams */
+      /*
+       * If we change streams, close and reset alternate data streams
+       */
       if (rctx.prev_stream != rctx.stream) {
          if (is_bopen(&rctx.forkbfd)) {
             deallocate_fork_cipher(rctx);
             bclose_chksize(jcr, &rctx.forkbfd, rctx.fork_size);
          }
-         rctx.fork_size = -1; /* Use an impossible value and set a proper one below */
+         /*
+          * Use an impossible value and set a proper one below
+          */
+         rctx.fork_size = -1;
          rctx.fork_addr = 0;
       }
 
-      /* File Attributes stream */
+      /*
+       * File Attributes stream
+       */
       switch (rctx.stream) {
       case STREAM_UNIX_ATTRIBUTES:
       case STREAM_UNIX_ATTRIBUTES_EX:
-         close_previous_stream(rctx);     /* if any previous stream open, close it */
-
+         /*
+          * if any previous stream open, close it
+          */
+         close_previous_stream(rctx);
 
-         /* TODO: manage deleted files */
+         /*
+          * TODO: manage deleted files
+          */
          if (rctx.type == FT_DELETED) { /* deleted file */
             continue;
          }
@@ -343,7 +352,7 @@ void do_restore(JCR *jcr)
 
          /*
           * Try to actually create the file, which returns a status telling
-          *  us if we need to extract or not.
+          * us if we need to extract or not.
           */
          jcr->num_files_examined++;
          rctx.extract = false;
@@ -363,23 +372,44 @@ void do_restore(JCR *jcr)
             pm_strcpy(jcr->last_fname, attr->ofname);
             jcr->last_type = attr->type;
             break;
-         case CF_EXTRACT:        /* File created and we expect file data */
+         case CF_EXTRACT:
+            /*
+             * File created and we expect file data
+             */
             rctx.extract = true;
-            /* FALLTHROUGH */
-         case CF_CREATED:        /* File created, but there is no content */
-            jcr->JobFiles++;
+            /*
+             * FALLTHROUGH
+             */
+         case CF_CREATED:
+            /*
+             * File created, but there is no content
+             */
             rctx.fileAddr = 0;
             print_ls_output(jcr, attr);
 
             if (have_darwin_os) {
-               /* Only restore the resource fork for regular files */
+               /*
+                * Only restore the resource fork for regular files
+                */
                from_base64(&rsrc_len, attr->attrEx);
                if (attr->type == FT_REG && rsrc_len > 0) {
                   rctx.extract = true;
                }
+
+               /*
+                * Count the resource forks not as regular files being restored.
+                */
+               if (rsrc_len == 0) {
+                  jcr->JobFiles++;
+               }
+            } else {
+               jcr->JobFiles++;
             }
+
             if (!rctx.extract) {
-               /* set attributes now because file will not be extracted */
+               /*
+                * set attributes now because file will not be extracted
+                */
                if (jcr->plugin) {
                   plugin_set_attributes(jcr, attr, &rctx.bfd);
                } else {
@@ -390,11 +420,15 @@ void do_restore(JCR *jcr)
          }
          break;
 
-      /* Data stream */
+      /*
+       * Data stream
+       */
       case STREAM_ENCRYPTED_SESSION_DATA:
          crypto_error_t cryptoerr;
 
-         /* Is this an unexpected session data entry? */
+         /*
+          * Is this an unexpected session data entry?
+          */
          if (rctx.cs) {
             Jmsg0(jcr, M_ERROR, 0, _("Unexpected cryptographic session data stream.\n"));
             rctx.extract = false;
@@ -402,7 +436,9 @@ void do_restore(JCR *jcr)
             continue;
          }
 
-         /* Do we have any keys at all? */
+         /*
+          * Do we have any keys at all?
+          */
          if (!jcr->crypto.pki_recipients) {
             Jmsg(jcr, M_ERROR, 0, _("No private decryption keys have been defined to decrypt encrypted backup data.\n"));
             rctx.extract = false;
@@ -421,12 +457,16 @@ void do_restore(JCR *jcr)
             break;
          }
 
-         /* Decode and save session keys. */
+         /*
+          * Decode and save session keys.
+          */
          cryptoerr = crypto_session_decode((uint8_t *)sd->msg, (uint32_t)sd->msglen, 
                         jcr->crypto.pki_recipients, &rctx.cs);
          switch(cryptoerr) {
          case CRYPTO_ERROR_NONE:
-            /* Success */
+            /*
+             * Success
+             */
             break;
          case CRYPTO_ERROR_NORECIPIENT:
             Jmsg(jcr, M_ERROR, 0, _("Missing private key required to decrypt encrypted backup data.\n"));
@@ -435,7 +475,9 @@ void do_restore(JCR *jcr)
             Jmsg(jcr, M_ERROR, 0, _("Decrypt of the session key failed.\n"));
             break;
          default:
-            /* Shouldn't happen */
+            /*
+             * Shouldn't happen
+             */
             Jmsg1(jcr, M_ERROR, 0, _("An error occurred while decoding encrypted session data stream: %s\n"), crypto_strerror(cryptoerr));
             break;
          }
@@ -458,7 +500,9 @@ void do_restore(JCR *jcr)
       case STREAM_ENCRYPTED_WIN32_DATA:
       case STREAM_ENCRYPTED_FILE_GZIP_DATA:
       case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
-         /* Force an expected, consistent stream type here */
+         /*
+          * Force an expected, consistent stream type here
+          */
          if (rctx.extract && (rctx.prev_stream == rctx.stream 
                          || rctx.prev_stream == STREAM_UNIX_ATTRIBUTES
                          || rctx.prev_stream == STREAM_UNIX_ATTRIBUTES_EX
@@ -482,7 +526,9 @@ void do_restore(JCR *jcr)
                   || rctx.stream == STREAM_ENCRYPTED_FILE_GZIP_DATA
                   || rctx.stream == STREAM_ENCRYPTED_WIN32_DATA
                   || rctx.stream == STREAM_ENCRYPTED_WIN32_GZIP_DATA) {               
-               /* Set up a decryption context */
+               /*
+                * Set up a decryption context
+                */
                if (!rctx.cipher_ctx.cipher) {
                   if (!rctx.cs) {
                      Jmsg1(jcr, M_ERROR, 0, _("Missing encryption session data stream for %s\n"), jcr->last_fname);
@@ -505,85 +551,87 @@ void do_restore(JCR *jcr)
 
             if (is_win32_stream(rctx.stream) && !have_win32_api()) {
                set_portable_backup(&rctx.bfd);
-               rctx.flags |= FO_WIN32DECOMP;    /* "decompose" BackupWrite data */
+               /*
+                * "decompose" BackupWrite data
+                */
+               rctx.flags |= FO_WIN32DECOMP;
             }
 
-            if (extract_data(jcr, rctx, sd->msg, sd->msglen, &rctx.fileAddr, 
+            if (extract_data(jcr, &rctx.bfd, sd->msg, sd->msglen, &rctx.fileAddr,
                              rctx.flags, &rctx.cipher_ctx) < 0) {
+               rctx.extract = false;
                bclose(&rctx.bfd);
                continue;
             }
          }
          break;
 
-      /* Resource fork stream - only recorded after a file to be restored */
-      /* Silently ignore if we cannot write - we already reported that */
+      /*
+       * Resource fork stream - only recorded after a file to be restored
+       * Silently ignore if we cannot write - we already reported that
+       */
       case STREAM_ENCRYPTED_MACOS_FORK_DATA:
       case STREAM_MACOS_FORK_DATA:
-#ifdef HAVE_DARWIN_OS
-         rctx.fork_flags = 0;
-         jcr->ff->flags |= FO_HFSPLUS;
+         if (have_darwin_os) {
+            rctx.fork_flags = 0;
+            jcr->ff->flags |= FO_HFSPLUS;
 
-         if (rctx.stream == STREAM_ENCRYPTED_MACOS_FORK_DATA) {
-            rctx.fork_flags |= FO_ENCRYPT;
+            if (rctx.stream == STREAM_ENCRYPTED_MACOS_FORK_DATA) {
+               rctx.fork_flags |= FO_ENCRYPT;
 
-            /* Set up a decryption context */
-            if (rctx.extract && !rctx.fork_cipher_ctx.cipher) {
-               if (!rctx.cs) {
-                  Jmsg1(jcr, M_ERROR, 0, _("Missing encryption session data stream for %s\n"), jcr->last_fname);
-                  rctx.extract = false;
-                  bclose(&rctx.bfd);
-                  continue;
-               }
+               /*
+                * Set up a decryption context
+                */
+               if (rctx.extract && !rctx.fork_cipher_ctx.cipher) {
+                  if (!rctx.cs) {
+                     Jmsg1(jcr, M_ERROR, 0, _("Missing encryption session data stream for %s\n"), jcr->last_fname);
+                     rctx.extract = false;
+                     bclose(&rctx.bfd);
+                     continue;
+                  }
 
-               if ((rctx.fork_cipher_ctx.cipher = crypto_cipher_new(rctx.cs, false, &rctx.fork_cipher_ctx.block_size)) == NULL) {
-                  Jmsg1(jcr, M_ERROR, 0, _("Failed to initialize decryption context for %s\n"), jcr->last_fname);
-                  free_session(rctx);
-                  rctx.extract = false;
-                  bclose(&rctx.bfd);
-                  continue;
+                  if ((rctx.fork_cipher_ctx.cipher = crypto_cipher_new(rctx.cs, false, &rctx.fork_cipher_ctx.block_size)) == NULL) {
+                     Jmsg1(jcr, M_ERROR, 0, _("Failed to initialize decryption context for %s\n"), jcr->last_fname);
+                     free_session(rctx);
+                     rctx.extract = false;
+                     bclose(&rctx.bfd);
+                     continue;
+                  }
                }
             }
-         }
 
-         if (rctx.extract) {
-            if (rctx.prev_stream != rctx.stream) {
-               if (bopen_rsrc(&rctx.forkbfd, jcr->last_fname, O_WRONLY | O_TRUNC | O_BINARY, 0) < 0) {
-                  Jmsg(jcr, M_ERROR, 0, _("     Cannot open resource fork for %s.\n"), jcr->last_fname);
+            if (rctx.extract) {
+               if (rctx.prev_stream != rctx.stream) {
+                  if (bopen_rsrc(&rctx.forkbfd, jcr->last_fname, O_WRONLY | O_TRUNC | O_BINARY, 0) < 0) {
+                     Jmsg(jcr, M_ERROR, 0, _("Cannot open resource fork for %s.\n"), jcr->last_fname);
+                     rctx.extract = false;
+                     continue;
+                  }
+
+                  rctx.fork_size = rsrc_len;
+                  Dmsg0(130, "Restoring resource fork\n");
+               }
+
+               if (extract_data(jcr, &rctx.forkbfd, sd->msg, sd->msglen, &rctx.fork_addr, rctx.fork_flags,
+                                &rctx.fork_cipher_ctx) < 0) {
                   rctx.extract = false;
+                  bclose(&rctx.forkbfd);
                   continue;
                }
-
-               rctx.fork_size = rsrc_len;
-               Dmsg0(130, "Restoring resource fork\n");
-            }
-
-            if (extract_data(jcr, rctx, sd->msg, sd->msglen, &rctx.fork_addr, rctx.fork_flags, 
-                             &rctx.fork_cipher_ctx) < 0) {
-               bclose(&rctx.forkbfd);
-               continue;
             }
+         } else {
+            non_support_rsrc++;
          }
-#else
-         non_support_rsrc++;
-#endif
          break;
 
       case STREAM_HFSPLUS_ATTRIBUTES:
-#ifdef HAVE_DARWIN_OS
-         Dmsg0(130, "Restoring Finder Info\n");
-         jcr->ff->flags |= FO_HFSPLUS;
-         if (sd->msglen != 32) {
-            Jmsg(jcr, M_ERROR, 0, _("     Invalid length of Finder Info (got %d, not 32)\n"), sd->msglen);
-            continue;
-         }
-         if (setattrlist(jcr->last_fname, &attrList, sd->msg, sd->msglen, 0) != 0) {
-            Jmsg(jcr, M_ERROR, 0, _("     Could not set Finder Info on %s\n"), jcr->last_fname);
-            continue;
+         if (have_darwin_os) {
+            if (!restore_finderinfo(jcr, sd->msg, sd->msglen)) {
+               continue;
+            }
+         } else {
+            non_support_finfo++;
          }
-#else
-         non_support_finfo++;
-#endif
          break;
 
       case STREAM_UNIX_ACCESS_ACL:
@@ -675,13 +723,17 @@ void do_restore(JCR *jcr)
          break;
 
       case STREAM_SIGNED_DIGEST:
-         /* Is this an unexpected signature? */
+         /*
+          * Is this an unexpected signature?
+          */
          if (rctx.sig) {
             Jmsg0(jcr, M_ERROR, 0, _("Unexpected cryptographic signature data stream.\n"));
             free_signature(rctx);
             continue;
          }
-         /* Save signature. */
+         /*
+          * Save signature.
+          */
          if (rctx.extract && (rctx.sig = crypto_sign_decode(jcr, (uint8_t *)sd->msg, (uint32_t)sd->msglen)) == NULL) {
             Jmsg1(jcr, M_ERROR, 0, _("Failed to decode message signature for %s\n"), jcr->last_fname);
          }
@@ -714,7 +766,6 @@ void do_restore(JCR *jcr)
          Dmsg2(0, "Unknown stream=%d data=%s\n", rctx.stream, sd->msg);
          break;
       } /* end switch(stream) */
-
    } /* end while get_msg() */
 
    /*
@@ -802,7 +853,7 @@ ok_out:
    }
 
    if (jcr->compress_buf) {
-      free(jcr->compress_buf);
+      free_pool_memory(jcr->compress_buf);
       jcr->compress_buf = NULL;
       jcr->compress_buf_size = 0;
    }
@@ -878,7 +929,10 @@ static bool verify_signature(JCR *jcr, r_ctx &rctx)
 
 
    if (!jcr->crypto.pki_sign) {
-      return true;                    /* no signature OK */
+      /*
+       * no signature OK
+       */
+      return true;
    }
    if (!sig) {
       if (rctx.type == FT_REGE || rctx.type == FT_REG || rctx.type == FT_RAW) { 
@@ -889,7 +943,9 @@ static bool verify_signature(JCR *jcr, r_ctx &rctx)
       return true;
    }
 
-   /* Iterate through the trusted signers */
+   /*
+    * Iterate through the trusted signers
+    */
    foreach_alist(keypair, jcr->crypto.pki_signers) {
       err = crypto_sign_get_digest(sig, jcr->crypto.pki_keypair, algorithm, &digest);
       switch (err) {
@@ -908,7 +964,9 @@ static bool verify_signature(JCR *jcr, r_ctx &rctx)
             }  
          }
          if (jcr->crypto.digest) {
-             /* Use digest computed while writing the file to verify the signature */
+             /*
+              * Use digest computed while writing the file to verify the signature
+              */
             if ((err = crypto_sign_verify(sig, keypair, jcr->crypto.digest)) != CRYPTO_ERROR_NONE) {
                Dmsg1(50, "Bad signature on %s\n", jcr->last_fname);
                Jmsg2(jcr, M_ERROR, 0, _("Signature validation failed for file %s: ERR=%s\n"), 
@@ -916,13 +974,16 @@ static bool verify_signature(JCR *jcr, r_ctx &rctx)
                goto bail_out;
             }
          } else {   
-            /* Signature found, digest allocated.  Old method, 
+            /*
+             * Signature found, digest allocated.  Old method, 
              * re-read the file and compute the digest
              */
             jcr->crypto.digest = digest;
 
-            /* Checksum the entire file */
-            /* Make sure we don't modify JobBytes by saving and restoring it */
+            /*
+             * Checksum the entire file
+             * Make sure we don't modify JobBytes by saving and restoring it
+             */
             saved_bytes = jcr->JobBytes;                     
             if (find_one_file(jcr, jcr->ff, do_file_digest, jcr->last_fname, (dev_t)-1, 1) != 0) {
                Jmsg(jcr, M_ERROR, 0, _("Digest one file failed for file: %s\n"), 
@@ -932,7 +993,9 @@ static bool verify_signature(JCR *jcr, r_ctx &rctx)
             }
             jcr->JobBytes = saved_bytes;
 
-            /* Verify the signature */
+            /*
+             * Verify the signature
+             */
             if ((err = crypto_sign_verify(sig, keypair, digest)) != CRYPTO_ERROR_NONE) {
                Dmsg1(50, "Bad signature on %s\n", jcr->last_fname);
                Jmsg2(jcr, M_ERROR, 0, _("Signature validation failed for file %s: ERR=%s\n"), 
@@ -942,26 +1005,34 @@ static bool verify_signature(JCR *jcr, r_ctx &rctx)
             jcr->crypto.digest = NULL;
          }
 
-         /* Valid signature */
+         /*
+          * Valid signature
+          */
          Dmsg1(50, "Signature good on %s\n", jcr->last_fname);
          crypto_digest_free(digest);
          return true;
 
       case CRYPTO_ERROR_NOSIGNER:
-         /* Signature not found, try again */
+         /*
+          * Signature not found, try again
+          */
          if (digest) {
             crypto_digest_free(digest);
             digest = NULL;
          }
          continue;
       default:
-         /* Something strange happened (that shouldn't happen!)... */
+         /*
+          * Something strange happened (that shouldn't happen!)...
+          */
          Qmsg2(jcr, M_ERROR, 0, _("Signature validation failed for %s: %s\n"), jcr->last_fname, crypto_strerror(err));
          goto bail_out;
       }
    }
 
-   /* No signer */
+   /*
+    * No signer
+    */
    Dmsg1(50, "Could not find a valid public key for signature on %s\n", jcr->last_fname);
 
 bail_out:
@@ -998,19 +1069,29 @@ bool decompress_data(JCR *jcr, char **data, uint32_t *length)
 #ifdef HAVE_LIBZ
    uLong compress_len;
    int stat;
-   char ec1[50];                      /* Buffer printing huge values */
+   char ec1[50]; /* Buffer printing huge values */
 
    /* 
     * NOTE! We only use uLong and Byte because they are
-    *  needed by the zlib routines, they should not otherwise
-    *  be used in Bacula.
+    * needed by the zlib routines, they should not otherwise
+    * be used in Bacula.
     */
    compress_len = jcr->compress_buf_size;
    Dmsg2(200, "Comp_len=%d msglen=%d\n", compress_len, *length);
-   if ((stat=uncompress((Byte *)jcr->compress_buf, &compress_len,
-               (const Byte *)*data, (uLong)*length)) != Z_OK) {
+   while ((stat=uncompress((Byte *)jcr->compress_buf, &compress_len,
+                           (const Byte *)*data, (uLong)*length)) == Z_BUF_ERROR)
+   {
+      /*
+       * The buffer size is too small, try with a bigger one
+       */
+      compress_len = jcr->compress_buf_size = jcr->compress_buf_size + jcr->compress_buf_size >> 1;
+      Dmsg2(200, "Comp_len=%d msglen=%d\n", compress_len, *length);
+      jcr->compress_buf = check_pool_memory_size(jcr->compress_buf,
+                                                 compress_len);
+   }
+   if (stat != Z_OK) {
       Qmsg(jcr, M_ERROR, 0, _("Uncompression error on file %s. ERR=%s\n"),
-            jcr->last_fname, zlib_strerror(stat));
+           jcr->last_fname, zlib_strerror(stat));
       return false;
    }
    *data = jcr->compress_buf;
@@ -1061,15 +1142,14 @@ bool store_data(JCR *jcr, BFILE *bfd, char *data, const int32_t length, bool win
  * The flags specify whether to use sparse files or compression.
  * Return value is the number of bytes written, or -1 on errors.
  */
-int32_t extract_data(JCR *jcr, r_ctx &rctx, POOLMEM *buf, int32_t buflen,
-      uint64_t *addr, int flags, RESTORE_CIPHER_CTX *cipher_ctx)
+int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
+                     uint64_t *addr, int flags, RESTORE_CIPHER_CTX *cipher_ctx)
 {
-   BFILE *bfd = &rctx.bfd;
-   char *wbuf;                        /* write buffer */
-   uint32_t wsize;                    /* write size */
-   uint32_t rsize;                    /* read size */
-   uint32_t decrypted_len = 0;        /* Decryption output length */
-   char ec1[50];                      /* Buffer printing huge values */
+   char *wbuf;                 /* write buffer */
+   uint32_t wsize;             /* write size */
+   uint32_t rsize;             /* read size */
+   uint32_t decrypted_len = 0; /* Decryption output length */
+   char ec1[50];               /* Buffer printing huge values */
 
    rsize = buflen;
    jcr->ReadBytes += rsize;
@@ -1079,10 +1159,10 @@ int32_t extract_data(JCR *jcr, r_ctx &rctx, POOLMEM *buf, int32_t buflen,
    if (flags & FO_ENCRYPT) {
       ASSERT(cipher_ctx->cipher);
 
-      /* NOTE: We must implement block preserving semantics for the
-       * non-streaming compression and sparse code. */
-
       /*
+       * NOTE: We must implement block preserving semantics for the
+       * non-streaming compression and sparse code.
+       *
        * Grow the crypto buffer, if necessary.
        * crypto_cipher_update() will process only whole blocks,
        * buffering the remaining input.
@@ -1090,19 +1170,25 @@ int32_t extract_data(JCR *jcr, r_ctx &rctx, POOLMEM *buf, int32_t buflen,
       cipher_ctx->buf = check_pool_memory_size(cipher_ctx->buf, 
                         cipher_ctx->buf_len + wsize + cipher_ctx->block_size);
 
-      /* Decrypt the input block */
+      /*
+       * Decrypt the input block
+       */
       if (!crypto_cipher_update(cipher_ctx->cipher, 
                                 (const u_int8_t *)wbuf, 
                                 wsize, 
                                 (u_int8_t *)&cipher_ctx->buf[cipher_ctx->buf_len], 
                                 &decrypted_len)) {
-         /* Decryption failed. Shouldn't happen. */
+         /*
+          * Decryption failed. Shouldn't happen.
+          */
          Jmsg(jcr, M_FATAL, 0, _("Decryption error\n"));
          goto bail_out;
       }
 
       if (decrypted_len == 0) {
-         /* No full block of encrypted data available, write more data */
+         /*
+          * No full block of encrypted data available, write more data
+          */
          return 0;
       }
 
@@ -1111,19 +1197,25 @@ int32_t extract_data(JCR *jcr, r_ctx &rctx, POOLMEM *buf, int32_t buflen,
       cipher_ctx->buf_len += decrypted_len;
       wbuf = cipher_ctx->buf;
 
-      /* If one full preserved block is available, write it to disk,
+      /*
+       * If one full preserved block is available, write it to disk,
        * and then buffer any remaining data. This should be effecient
        * as long as Bacula's block size is not significantly smaller than the
-       * encryption block size (extremely unlikely!) */
+       * encryption block size (extremely unlikely!)
+       */
       unser_crypto_packet_len(cipher_ctx);
       Dmsg1(500, "Crypto unser block size=%d\n", cipher_ctx->packet_len - CRYPTO_LEN_SIZE);
 
       if (cipher_ctx->packet_len == 0 || cipher_ctx->buf_len < cipher_ctx->packet_len) {
-         /* No full preserved block is available. */
+         /*
+          * No full preserved block is available.
+          */
          return 0;
       }
 
-      /* We have one full block, set up the filter input buffers */
+      /*
+       * We have one full block, set up the filter input buffers
+       */
       wsize = cipher_ctx->packet_len - CRYPTO_LEN_SIZE;
       wbuf = &wbuf[CRYPTO_LEN_SIZE]; /* Skip the block length header */
       cipher_ctx->buf_len -= cipher_ctx->packet_len;
@@ -1149,7 +1241,9 @@ int32_t extract_data(JCR *jcr, r_ctx &rctx, POOLMEM *buf, int32_t buflen,
    *addr += wsize;
    Dmsg2(130, "Write %u bytes, JobBytes=%s\n", wsize, edit_uint64(jcr->JobBytes, ec1));
 
-   /* Clean up crypto buffers */
+   /*
+    * Clean up crypto buffers
+    */
    if (flags & FO_ENCRYPT) {
       /* Move any remaining data to start of buffer */
       if (cipher_ctx->buf_len > 0) {
@@ -1157,16 +1251,16 @@ int32_t extract_data(JCR *jcr, r_ctx &rctx, POOLMEM *buf, int32_t buflen,
          memmove(cipher_ctx->buf, &cipher_ctx->buf[cipher_ctx->packet_len], 
             cipher_ctx->buf_len);
       }
-      /* The packet was successfully written, reset the length so that the next
-       * packet length may be re-read by unser_crypto_packet_len() */
+      /*
+       * The packet was successfully written, reset the length so that the next
+       * packet length may be re-read by unser_crypto_packet_len()
+       */
       cipher_ctx->packet_len = 0;
    }
    return wsize;
 
 bail_out:
-   rctx.extract = false;
    return -1;
-
 }
 
 
@@ -1198,11 +1292,15 @@ static void close_previous_stream(r_ctx &rctx)
       }
       rctx.extract = false;
 
-      /* Verify the cryptographic signature, if any */
+      /*
+       * Verify the cryptographic signature, if any
+       */
       rctx.type = rctx.attr->type;
       verify_signature(rctx.jcr, rctx);
 
-      /* Free Signature */
+      /*
+       * Free Signature
+       */
       free_signature(rctx);
       free_session(rctx);
       rctx.jcr->ff->flags = 0;
@@ -1230,19 +1328,25 @@ bool flush_cipher(JCR *jcr, BFILE *bfd, uint64_t *addr, int flags,
    bool second_pass = false;
 
 again:
-   /* Write out the remaining block and free the cipher context */
+   /*
+    * Write out the remaining block and free the cipher context
+    */
    cipher_ctx->buf = check_pool_memory_size(cipher_ctx->buf, cipher_ctx->buf_len + 
-                     cipher_ctx->block_size);
+                                            cipher_ctx->block_size);
 
    if (!crypto_cipher_finalize(cipher_ctx->cipher, (uint8_t *)&cipher_ctx->buf[cipher_ctx->buf_len],
         &decrypted_len)) {
-      /* Writing out the final, buffered block failed. Shouldn't happen. */
+      /*
+       * Writing out the final, buffered block failed. Shouldn't happen.
+       */
       Jmsg3(jcr, M_ERROR, 0, _("Decryption error. buf_len=%d decrypt_len=%d on file %s\n"), 
             cipher_ctx->buf_len, decrypted_len, jcr->last_fname);
    }
 
    Dmsg2(130, "Flush decrypt len=%d buf_len=%d\n", decrypted_len, cipher_ctx->buf_len);
-   /* If nothing new was decrypted, and our output buffer is empty, return */
+   /*
+    * If nothing new was decrypted, and our output buffer is empty, return
+    */
    if (decrypted_len == 0 && cipher_ctx->buf_len == 0) {
       return true;
    }
@@ -1252,7 +1356,10 @@ again:
    unser_crypto_packet_len(cipher_ctx);
    Dmsg1(500, "Crypto unser block size=%d\n", cipher_ctx->packet_len - CRYPTO_LEN_SIZE);
    wsize = cipher_ctx->packet_len - CRYPTO_LEN_SIZE;
-   wbuf = &cipher_ctx->buf[CRYPTO_LEN_SIZE]; /* Decrypted, possibly decompressed output here. */
+   /*
+    * Decrypted, possibly decompressed output here.
+    */
+   wbuf = &cipher_ctx->buf[CRYPTO_LEN_SIZE];
    cipher_ctx->buf_len -= cipher_ctx->packet_len;
    Dmsg2(130, "Encryption writing full block, %u bytes, remaining %u bytes in buffer\n", wsize, cipher_ctx->buf_len);
 
@@ -1275,14 +1382,18 @@ again:
    jcr->JobBytes += wsize;
    Dmsg2(130, "Flush write %u bytes, JobBytes=%s\n", wsize, edit_uint64(jcr->JobBytes, ec1));
 
-   /* Move any remaining data to start of buffer */
+   /*
+    * Move any remaining data to start of buffer
+    */
    if (cipher_ctx->buf_len > 0) {
       Dmsg1(130, "Moving %u buffered bytes to start of buffer\n", cipher_ctx->buf_len);
       memmove(cipher_ctx->buf, &cipher_ctx->buf[cipher_ctx->packet_len], 
          cipher_ctx->buf_len);
    }
-   /* The packet was successfully written, reset the length so that the next
-    * packet length may be re-read by unser_crypto_packet_len() */
+   /*
+    * The packet was successfully written, reset the length so that the next
+    * packet length may be re-read by unser_crypto_packet_len()
+    */
    cipher_ctx->packet_len = 0;
 
    if (cipher_ctx->buf_len >0 && !second_pass) {
@@ -1290,7 +1401,9 @@ again:
       goto again;
    }
 
-   /* Stop decryption */
+   /*
+    * Stop decryption
+    */
    cipher_ctx->buf_len = 0;
    cipher_ctx->packet_len = 0;
 
@@ -1299,7 +1412,9 @@ again:
 
 static void deallocate_cipher(r_ctx &rctx)
 {
-   /* Flush and deallocate previous stream's cipher context */
+   /*
+    * Flush and deallocate previous stream's cipher context
+    */
    if (rctx.cipher_ctx.cipher) {
       flush_cipher(rctx.jcr, &rctx.bfd, &rctx.fileAddr, rctx.flags, &rctx.cipher_ctx);
       crypto_cipher_free(rctx.cipher_ctx.cipher);
@@ -1310,7 +1425,9 @@ static void deallocate_cipher(r_ctx &rctx)
 static void deallocate_fork_cipher(r_ctx &rctx)
 {
 
-   /* Flush and deallocate previous stream's fork cipher context */
+   /*
+    * Flush and deallocate previous stream's fork cipher context
+    */
    if (rctx.fork_cipher_ctx.cipher) {
       flush_cipher(rctx.jcr, &rctx.forkbfd, &rctx.fork_addr, rctx.fork_flags, &rctx.fork_cipher_ctx);
       crypto_cipher_free(rctx.fork_cipher_ctx.cipher);
@@ -1335,7 +1452,9 @@ static void free_session(r_ctx &rctx)
 }
 
 
-/* This code if implemented goes above */
+/*
+ * This code if implemented goes above
+ */
 #ifdef stbernard_implemented
 /  #if defined(HAVE_WIN32)
    bool        bResumeOfmOnExit = FALSE;
diff --git a/bacula/src/filed/restore.h b/bacula/src/filed/restore.h
new file mode 100644 (file)
index 0000000..76d18db
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2009 Free Software Foundation Europe e.V.
+
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation and included
+   in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of Kern Sibbald.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+   Switzerland, email:ftf@fsfeurope.org.
+*/
+
+#ifndef __RESTORE_H
+#define __RESTORE_H
+
+struct RESTORE_CIPHER_CTX {
+   CIPHER_CONTEXT *cipher;
+   uint32_t block_size;
+
+   POOLMEM *buf;       /* Pointer to descryption buffer */
+   int32_t buf_len;    /* Count of bytes currently in buf */ 
+   int32_t packet_len; /* Total bytes in packet */
+};
+
+struct r_ctx {
+   JCR *jcr;
+   int32_t stream;
+   int32_t prev_stream;
+   BFILE bfd;                          /* File content */
+   uint64_t fileAddr;                  /* file write address */
+   uint32_t size;                      /* Size of file */
+   int flags;                          /* Options for extract_data() */
+   BFILE forkbfd;                      /* Alternative data stream */
+   uint64_t fork_addr;                 /* Write address for alternative stream */
+   intmax_t fork_size;                 /* Size of alternate stream */
+   int fork_flags;                     /* Options for extract_data() */
+   int32_t type;                       /* file type FT_ */
+   ATTR *attr;                         /* Pointer to attributes */
+   bool extract;                       /* set when extracting */
+
+   SIGNATURE *sig;                     /* Cryptographic signature (if any) for file */
+   CRYPTO_SESSION *cs;                 /* Cryptographic session data (if any) for file */
+   RESTORE_CIPHER_CTX cipher_ctx;      /* Cryptographic restore context (if any) for file */
+   RESTORE_CIPHER_CTX fork_cipher_ctx; /* Cryptographic restore context (if any) for alternative stream */
+};
+
+#endif
index a4f273723078496e3dc8eab7350d5a833ae456f9..12fbe282ff1677a729a9ea0244d50c3a7f1cbdbf 100644 (file)
 #include "bacula.h"
 #include "filed.h"
 
+#ifdef HAVE_DARWIN_OS
+const bool have_darwin_os = true;
+#else
+const bool have_darwin_os = false;
+#endif
+
 static int verify_file(JCR *jcr, FF_PKT *ff_pkt, bool);
 static int read_digest(BFILE *bfd, DIGEST *digest, JCR *jcr);
 
@@ -288,8 +294,9 @@ int digest_file(JCR *jcr, FF_PKT *ff_pkt, DIGEST *digest)
    Dmsg0(50, "=== digest_file\n");
    binit(&bfd);
 
-   if (ff_pkt->statp.st_size > 0 || ff_pkt->type == FT_RAW
-         || ff_pkt->type == FT_FIFO) {
+   if (ff_pkt->statp.st_size > 0 ||
+       ff_pkt->type == FT_RAW ||
+       ff_pkt->type == FT_FIFO) {
       int noatime = ff_pkt->flags & FO_NOATIME ? O_NOATIME : 0;
       if ((bopen(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY | noatime, 0)) < 0) {
          ff_pkt->ff_errno = errno;
@@ -304,29 +311,29 @@ int digest_file(JCR *jcr, FF_PKT *ff_pkt, DIGEST *digest)
       bclose(&bfd);
    }
 
-#ifdef HAVE_DARWIN_OS
+   if (have_darwin_os) {
       /* Open resource fork if necessary */
-   if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->hfsinfo.rsrclength > 0) {
-      if (bopen_rsrc(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
-         ff_pkt->ff_errno = errno;
-         berrno be;
-         Jmsg(jcr, M_ERROR, -1, _("     Cannot open resource fork for %s: ERR=%s.\n"),
-               ff_pkt->fname, be.bstrerror());
-         if (is_bopen(&ff_pkt->bfd)) {
-            bclose(&ff_pkt->bfd);
+      if (ff_pkt->flags & FO_HFSPLUS && ff_pkt->hfsinfo.rsrclength > 0) {
+         if (bopen_rsrc(&bfd, ff_pkt->fname, O_RDONLY | O_BINARY, 0) < 0) {
+            ff_pkt->ff_errno = errno;
+            berrno be;
+            Jmsg(jcr, M_ERROR, -1, _("     Cannot open resource fork for %s: ERR=%s.\n"),
+                  ff_pkt->fname, be.bstrerror());
+            if (is_bopen(&ff_pkt->bfd)) {
+               bclose(&ff_pkt->bfd);
+            }
+            return 1;
          }
-         return 1;
+         read_digest(&bfd, digest, jcr);
+         bclose(&bfd);
       }
-      read_digest(&bfd, digest, jcr);
-      bclose(&bfd);
-   }
 
-   if (digest && ff_pkt->flags & FO_HFSPLUS) {
-      crypto_digest_update(digest, (uint8_t *)ff_pkt->hfsinfo.fndrinfo, 32);
-   }
-#endif
+      if (digest && ff_pkt->flags & FO_HFSPLUS) {
+         crypto_digest_update(digest, (uint8_t *)ff_pkt->hfsinfo.fndrinfo, 32);
+      }
 
-   return 0;
+      return 0;
+   }
 }
 
 /*
index 90800a038539f0ba2937d4da78cf77654291d163..329c32dec0a1995fba9e2ccf27bdb905d3c53bb5 100644 (file)
@@ -26,8 +26,8 @@
    Switzerland, email:ftf@fsfeurope.org.
 */
 
-#ifndef _BACULA_XATTR_
-#define _BACULA_XATTR_
+#ifndef __XATTR_H
+#define __XATTR_H
 
 /*
  * Magic used in the magic field of the xattr struct.
index 20999d935ad04a704b6a2cae64808b1c45a42914..7ba1fca33040371678ff4b12aa8e4e1721bcd007 100644 (file)
@@ -950,6 +950,11 @@ int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
    free_pool_memory(rsrc_fname);
    return bfd->fid;
 }
+#else
+int bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode)
+{
+   return -1;
+}
 #endif
 
 
index 6355217743e081cb34ab56a5a40aaee68c4c8ddd..b22d50cc4e48b628928be3a4a31543320e3ea28f 100644 (file)
@@ -129,9 +129,7 @@ bool    is_restore_stream_supported(int stream);
 bool    is_win32_stream(int stream);
 char   *xberror(BFILE *bfd);          /* DO NOT USE  -- use berrno class */
 int     bopen(BFILE *bfd, const char *fname, int flags, mode_t mode);
-#ifdef HAVE_DARWIN_OS
 int     bopen_rsrc(BFILE *bfd, const char *fname, int flags, mode_t mode);
-#endif
 int     bclose(BFILE *bfd);
 ssize_t bread(BFILE *bfd, void *buf, size_t count);
 ssize_t bwrite(BFILE *bfd, void *buf, size_t count);
index 258e4b198802edf5d3d4a65a98b1d8288ea55abd..a24e1bb274976c9486714efab48c55c4a8bd192e 100644 (file)
@@ -67,13 +67,13 @@ FF_PKT *init_find_files()
 
    /* Get system path and filename maximum lengths */
    path_max = pathconf(".", _PC_PATH_MAX);
-   if (path_max < 1024) {
-      path_max = 1024;
+   if (path_max < 2048) {
+      path_max = 2048;
    }
 
    name_max = pathconf(".", _PC_NAME_MAX);
-   if (name_max < 1024) {
-      name_max = 1024;
+   if (name_max < 2048) {
+      name_max = 2048;
    }
    path_max++;                        /* add for EOS */
    name_max++;                        /* add for EOS */
index 5f15769133f3fc38ecb3a61644b0f8036d5ff00f..ebd3d06d38289e624b1d090cd7b16c28db63e916 100644 (file)
@@ -175,13 +175,11 @@ struct findFILESET {
    alist exclude_list;
 };
 
-#ifdef HAVE_DARWIN_OS
 struct HFSPLUS_INFO {
    unsigned long length;              /* Mandatory field */
    char fndrinfo[32];                 /* Finder Info */
    off_t rsrclength;                  /* Size of resource fork */
 };
-#endif
 
 /*
  * Definition of the find_files packet passed as the
@@ -232,9 +230,7 @@ struct FF_PKT {
     * To avoid clutter, we always include rsrc_bfd and volhas_attrlist */
    BFILE rsrc_bfd;                    /* fd for resource forks */
    bool volhas_attrlist;              /* Volume supports getattrlist() */
-#ifdef HAVE_DARWIN_OS
    struct HFSPLUS_INFO hfsinfo;       /* Finder Info and resource fork size */
-#endif
 };
 
 
index f464efb5be50bd507913b7d40096f51ff5325320..a9c18a9dfa1822da3de8d89592759363bd3e1c1d 100644 (file)
@@ -1,15 +1,7 @@
-/*
- *  32 bit CRC.  Algorithm from RFC 2083 (png format)
- *
- *   By Kern Sibbald, January 2001
- *
- *   Version $Id$
- *
- */
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2006 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2009 Free Software Foundation Europe e.V.
 
    The main author of Bacula is Kern Sibbald, with contributions from
    many others, a complete list can be found in the file AUTHORS.
    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
    Switzerland, email:ftf@fsfeurope.org.
 */
+/*
+ *  32 bit CRC.  Algorithm from RFC 2083 (png format)
+ *
+ *   By Kern Sibbald, January 2001
+ *
+ */
+
 
 #ifdef GENERATE_STATIC_CRC_TABLE
 /*
index 1a8c67f542fdc861f9c84c87a9cfbd6bb9de001b..5786a4c133d26b45c19a1749bc9013d760a47759 100644 (file)
@@ -438,9 +438,16 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec)
             wbuf = rec->data;
             wsize = rec->data_len;
          }
-         compress_len = compress_buf_size;
-         if ((stat=uncompress((Bytef *)compress_buf, &compress_len,
-               (const Bytef *)wbuf, (uLong)wsize) != Z_OK)) {
+
+         while ((stat=uncompress((Byte *)compress_buf, &compress_len,
+                                 (const Byte *)wbuf, (uLong)wsize)) == Z_BUF_ERROR)
+         {
+            /* The buffer size is too small, try with a bigger one */
+            compress_len = compress_len + compress_len >> 1;
+            compress_buf = check_pool_memory_size(compress_buf,
+                                                  compress_len);
+         }
+         if (stat != Z_OK) {
             Emsg1(M_ERROR, 0, _("Uncompression error. ERR=%d\n"), stat);
             extract = false;
             return true;
index abb53c25c37489e26826ef2cfc79330325a9f9e5..7899621399baae42242e1b392e32105c8688d650 100644 (file)
@@ -189,7 +189,7 @@ void empty_block(DEV_BLOCK *block)
  * in the buffer should have already been reserved by
  * init_block.
  */
-void ser_block_header(DEV_BLOCK *block)
+static void ser_block_header(DEV_BLOCK *block, bool do_checksum)
 {
    ser_declare;
    uint32_t CheckSum = 0;
@@ -207,8 +207,10 @@ void ser_block_header(DEV_BLOCK *block)
    }
 
    /* Checksum whole block except for the checksum */
-   CheckSum = bcrc32((uint8_t *)block->buf+BLKHDR_CS_LENGTH,
-                 block_len-BLKHDR_CS_LENGTH);
+   if (do_checksum) {
+      CheckSum = bcrc32((uint8_t *)block->buf+BLKHDR_CS_LENGTH,
+                    block_len-BLKHDR_CS_LENGTH);
+   }
    Dmsg1(1390, "ser_bloc_header: checksum=%x\n", CheckSum);
    ser_begin(block->buf, BLKHDR2_LENGTH);
    ser_uint32(CheckSum);              /* now add checksum to block header */
@@ -307,7 +309,7 @@ static bool unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
    block->BlockNumber = BlockNumber;
    Dmsg3(390, "Read binbuf = %d %d block_len=%d\n", block->binbuf,
       bhl, block_len);
-   if (block_len <= block->read_len) {
+   if (block_len <= block->read_len && dev->do_checksum()) {
       BlockCheckSum = bcrc32((uint8_t *)block->buf+BLKHDR_CS_LENGTH,
                          block_len-BLKHDR_CS_LENGTH);
       if (BlockCheckSum != CheckSum) {
@@ -466,7 +468,7 @@ bool write_block_to_dev(DCR *dcr)
       }
    }
 
-   ser_block_header(block);
+   ser_block_header(block, dev->do_checksum());
 
    /* Limit maximum Volume size to value specified by user */
    hit_max1 = (dev->max_volume_size > 0) &&
index 66f1f846b1dec4545e52e002cbf6123004e04665..ace8d8ffd0cbbc62c703cafe1ef168a2d01516f1 100644 (file)
@@ -37,8 +37,6 @@
  *   Note, this program reads stored.conf, and will only
  *     talk to devices that are configured.
  *
- *   Version $Id$
- *
  */
 
 #include "bacula.h"
@@ -76,6 +74,7 @@ DCR *dcr;
 DEVRES *device = NULL;
 int exit_code = 0;
 
+#define REC_SIZE 32768
 
 /* Forward referenced subroutines */
 static void do_tape_cmds();
@@ -100,7 +99,7 @@ static void set_volume_name(const char *VolName, int volnum);
 static void rawfill_cmd();
 static bool open_the_device();
 static void autochangercmd();
-static void do_unfill();
+static bool do_unfill();
 
 
 /* Static variables */
@@ -124,7 +123,6 @@ static int stop = 0;
 static uint64_t vol_size;
 static uint64_t VolBytes;
 static time_t now;
-static double kbs;
 static int32_t file_index;
 static int end_of_tape = 0;
 static uint32_t LastBlock = 0;
@@ -312,7 +310,6 @@ int main(int margc, char *margv[])
    Dmsg0(200, "Do tape commands\n");
    do_tape_cmds();
 
-terminate:
    terminate_btape(exit_code);
 }
 
@@ -367,6 +364,101 @@ static void terminate_btape(int stat)
    exit(stat);
 }
 
+
+btime_t total_time=0;
+uint64_t total_size=0;
+
+static void init_total_speed()
+{
+   total_size = 0;
+   total_time = 0;
+}
+
+static void print_total_speed()
+{
+   char ec1[50], ec2[50];
+   uint64_t rate = total_size / total_time;
+   Pmsg2(000, _("Total Volume bytes=%sB. Total Write rate = %sB/s\n"),
+         edit_uint64_with_suffix(total_size, ec1), 
+         edit_uint64_with_suffix(rate, ec2));
+}
+
+static void init_speed()
+{
+   time(&jcr->run_time);              /* start counting time for rates */
+   jcr->JobBytes=0;
+}
+
+static void print_speed(uint64_t bytes)
+{
+   char ec1[50], ec2[50];
+   uint64_t rate;
+
+   now = time(NULL);
+   now -= jcr->run_time;
+   if (now <= 0) {
+      now = 1;                     /* don't divide by zero */
+   }
+
+   total_time += now;
+   total_size += bytes;
+
+   rate = bytes / now;
+   Pmsg2(000, _("Volume bytes=%sB. Write rate = %sB/s\n"),
+         edit_uint64_with_suffix(bytes, ec1),
+         edit_uint64_with_suffix(rate, ec2));
+}
+
+/*
+ * Helper that fill a buffer with random data or not
+ */
+typedef enum {
+   FILL_RANDOM,
+   FILL_ZERO
+} fill_mode_t;
+
+static void fill_buffer(fill_mode_t mode, char *buf, uint32_t len)
+{
+   int fd;
+   switch (mode) {
+   case FILL_RANDOM:
+      fd = open("/dev/urandom", O_RDONLY);
+      if (fd != -1) {
+         read(fd, buf, len);
+         close(fd);
+      } else {
+         uint32_t *p = (uint32_t *)buf;
+         srandom(time(NULL));
+         for (uint32_t i=0; i<len/sizeof(uint32_t); i++) {
+            p[i] = random();
+         }
+      }
+      break;
+
+   case FILL_ZERO:
+      memset(buf, 0xFF, len);
+      break;
+
+   default:
+      ASSERT(0);
+   }
+}
+
+static void mix_buffer(fill_mode_t mode, char *data, uint32_t len)
+{
+   uint32_t i;
+   uint32_t *lp = (uint32_t *)data;
+
+   if (mode == FILL_ZERO) {
+      return;
+   }
+
+   lp[0] += lp[13];
+   for (i=1; i < (len-sizeof(uint32_t))/sizeof(uint32_t)-1; i+=100) {
+      lp[i] += lp[0];
+   }
+}
+
 static bool open_the_device()
 {
    DEV_BLOCK *block;
@@ -796,6 +888,220 @@ bail_out:
    return rc;
 }
 
+static bool speed_test_raw(fill_mode_t mode, uint64_t nb_gb, uint32_t nb)
+{
+   DEV_BLOCK *block = dcr->block;
+   int stat;
+   uint32_t block_num = 0;
+   int my_errno;
+   char ed1[200];
+   nb_gb *= 1024*1024*1024;      /* convert size from nb to GB */
+
+   init_total_speed();
+   fill_buffer(mode, block->buf, block->buf_len);
+
+   Pmsg3(0, _("Begin writing %i files of %sB with raw blocks of %u bytes.\n"), 
+         nb, edit_uint64_with_suffix(nb_gb, ed1), block->buf_len);
+
+   for (uint32_t j=0; j<nb; j++) {
+      init_speed();
+      for ( ;jcr->JobBytes < nb_gb; ) {
+         stat = dev->d_write(dev->fd(), block->buf, block->buf_len);
+         if (stat == (int)block->buf_len) {
+            if ((block_num++ % 500) == 0) {
+               printf("+");
+               fflush(stdout);
+            }
+
+            mix_buffer(mode, block->buf, block->buf_len);
+
+            jcr->JobBytes += stat;
+
+         } else {
+            my_errno = errno;
+            printf("\n");
+            berrno be;
+            printf(_("Write failed at block %u. stat=%d ERR=%s\n"), block_num,
+                   stat, be.bstrerror(my_errno));
+            return false;
+         }
+      }
+      printf("\n");
+      weofcmd();
+      print_speed(jcr->JobBytes);
+   }
+   print_total_speed();
+   printf("\n");
+   return true;
+}
+
+
+static bool speed_test_bacula(fill_mode_t mode, uint64_t nb_gb, uint32_t nb)
+{
+   DEV_BLOCK *block = dcr->block;
+   char ed1[200];
+   DEV_RECORD *rec;
+   uint64_t last_bytes = dev->VolCatInfo.VolCatBytes;
+   uint64_t written=0;
+
+   nb_gb *= 1024*1024*1024;      /* convert size from nb to GB */
+
+   init_total_speed();
+
+   empty_block(block);
+   rec = new_record();
+   rec->data = check_pool_memory_size(rec->data, block->buf_len);
+   rec->data_len = block->buf_len-100;
+
+   fill_buffer(mode, rec->data, rec->data_len);
+
+   Pmsg3(0, _("Begin writing %i files of %sB with blocks of %u bytes.\n"), 
+         nb, edit_uint64_with_suffix(nb_gb, ed1), block->buf_len);
+
+   for (uint32_t j=0; j<nb; j++) {
+      written = 0;
+      init_speed();
+      for ( ; written < nb_gb; ) {
+
+         if (!write_record_to_block(block, rec)) {
+            Pmsg0(0, _("\nError writing record to block.\n"));
+            goto bail_out;
+         }
+         if (!write_block_to_dev(dcr)) {
+            Pmsg0(0, _("\nError writing block to device.\n"));
+            goto bail_out;
+         }
+
+         if ((block->BlockNumber % 500) == 0) {
+            printf("+");
+            fflush(stdout);
+         }
+         written += dev->VolCatInfo.VolCatBytes - last_bytes;
+         last_bytes = dev->VolCatInfo.VolCatBytes;
+         mix_buffer(mode, rec->data, rec->data_len);
+      }
+      printf("\n");
+      weofcmd();
+      print_speed(written);
+   }
+   print_total_speed();
+   printf("\n");
+   free_record(rec);
+   return true;
+
+bail_out:
+   free_record(rec);
+   return false;
+}
+
+/* TODO: use UAContext */
+static int btape_find_arg(const char *keyword)
+{
+   for (int i=1; i<argc; i++) {
+      if (strcasecmp(keyword, argk[i]) == 0) {
+         return i;
+      }
+   }
+   return -1;
+}
+
+#define ok(a)    if (!(a)) return
+
+/*
+ * For file (/dev/zero, /dev/urandom, normal?) 
+ *    use raw mode to write a suite of 3 files of 1, 2, 4, 8 GB
+ *    use qfill mode to write the same
+ * 
+ */
+static void speed_test()
+{
+   bool do_zero=true, do_random=true, do_block=true, do_raw=true;
+   uint32_t file_size=0, nb_file=3;
+   int32_t i;
+
+   i = btape_find_arg("file_size");
+   if (i > 0) {
+      file_size = atoi(argv[i]);
+      if (file_size > 100) {
+         Pmsg0(0, _("The file_size is too big, stop this test with Ctrl-c.\n"));
+      }
+   }
+
+   i = btape_find_arg("nb_file");
+   if (i > 0) {
+      nb_file = atoi(argv[i]);
+   }
+
+   if (btape_find_arg("skip_zero") > 0) {
+      do_zero = false;
+   }
+
+   if (btape_find_arg("skip_random") > 0) {
+      do_random = false;
+   }
+
+   if (btape_find_arg("skip_raw") > 0) {
+      do_raw = false;
+   }
+
+   if (btape_find_arg("skip_block") > 0) {
+      do_block = false;
+   }
+
+   if (do_raw) {
+      dev->rewind(dcr);
+      if (do_zero) { 
+         Pmsg0(0, _("Test with zero data, should give the "
+                    "maximum throughput.\n"));
+         if (file_size) {
+            ok(speed_test_raw(FILL_ZERO, file_size, nb_file));
+         } else {
+            ok(speed_test_raw(FILL_ZERO, 1, nb_file));
+            ok(speed_test_raw(FILL_ZERO, 2, nb_file));
+            ok(speed_test_raw(FILL_ZERO, 4, nb_file));
+         }
+      }
+
+      if (do_random) { 
+         Pmsg0(0, _("Test with random data, should give the minimum "
+                    "throughput.\n"));
+         if (file_size) {
+            ok(speed_test_raw(FILL_RANDOM, file_size, nb_file));
+         } else {
+            ok(speed_test_raw(FILL_RANDOM, 1, nb_file));
+            ok(speed_test_raw(FILL_RANDOM, 2, nb_file));
+            ok(speed_test_raw(FILL_RANDOM, 4, nb_file));
+         }
+      }
+   }
+
+   if (do_block) {
+      dev->rewind(dcr);
+      if (do_zero) {
+         Pmsg0(0, _("Test with zero data and bacula block structure.\n"));
+         if (file_size) {
+            ok(speed_test_bacula(FILL_ZERO, file_size, nb_file));
+         } else { 
+            ok(speed_test_bacula(FILL_ZERO, 1, nb_file));
+            ok(speed_test_bacula(FILL_ZERO, 2, nb_file));
+               ok(speed_test_bacula(FILL_ZERO, 4, nb_file));
+         }
+      }
+   
+      if (do_random) { 
+         Pmsg0(0, _("Test with random data, should give the minimum "
+                    "throughput.\n"));
+         if (file_size) {
+            ok(speed_test_bacula(FILL_RANDOM, file_size, nb_file));
+         } else {
+            ok(speed_test_bacula(FILL_RANDOM, 1, nb_file));
+            ok(speed_test_bacula(FILL_RANDOM, 2, nb_file));
+            ok(speed_test_bacula(FILL_RANDOM, 4, nb_file));
+         }
+      }
+   }
+}
+
 const int num_recs = 10000;
 
 static bool write_two_files()
@@ -1795,14 +2101,14 @@ static void scan_blocks()
       blocks++;
       tot_blocks++;
       bytes += block->block_len;
-      Dmsg6(100, "Blk_blk=%u dev_blk=%u blen=%u bVer=%d SessId=%u SessTim=%u\n",
-         block->BlockNumber, dev->block_num, block->block_len, block->BlockVer,
+      Dmsg7(100, "Blk_blk=%u file,blk=%u,%u blen=%u bVer=%d SessId=%u SessTim=%u\n",
+         block->BlockNumber, dev->file, dev->block_num, block->block_len, block->BlockVer,
          block->VolSessionId, block->VolSessionTime);
       if (verbose == 1) {
          DEV_RECORD *rec = new_record();
          read_record_from_block(dcr, block, rec);
-         Pmsg8(-1, _("Blk_block: %u dev_blk=%u blen=%u First rec FI=%s SessId=%u SessTim=%u Strm=%s rlen=%d\n"),
-              block->BlockNumber, dev->block_num, block->block_len,
+         Pmsg9(-1, _("Block=%u file,blk=%u,%u blen=%u First rec FI=%s SessId=%u SessTim=%u Strm=%s rlen=%d\n"),
+              block->BlockNumber, dev->file, dev->block_num, block->block_len,
               FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId, rec->VolSessionTime,
               stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
          rec->remainder = 0;
@@ -1839,11 +2145,12 @@ static void fillcmd()
 {
    DEV_RECORD rec;
    DEV_BLOCK  *block = dcr->block;
-   char ec1[50];
+   char ec1[50], ec2[50];
    char buf1[100], buf2[100];
-   int fd;
-   uint32_t i;
+   uint64_t write_eof;
+   uint64_t rate;
    uint32_t min_block_size;
+   int fd;
    struct tm tm;
 
    ok = true;
@@ -1852,8 +2159,9 @@ static void fillcmd()
    last_file = 0;
    last_block_num = 0;
    BlockNumber = 0;
+   exit_code = 0;
 
-   Pmsg0(-1, _("\n"
+   Pmsg1(-1, _("\n"
 "This command simulates Bacula writing to a tape.\n"
 "It requires either one or two blank tapes, which it\n"
 "will label and write.\n\n"
@@ -1861,14 +2169,15 @@ static void fillcmd()
 "the tapes that are in slots 1 and 2, otherwise, you will\n"
 "be prompted to insert the tapes when necessary.\n\n"
 "It will print a status approximately\n"
-"every 322 MB, and write an EOF every 3.2 GB.  If you have\n"
+"every 322 MB, and write an EOF every %s.  If you have\n"
 "selected the simple test option, after writing the first tape\n"
 "it will rewind it and re-read the last block written.\n\n"
 "If you have selected the multiple tape test, when the first tape\n"
 "fills, it will ask for a second, and after writing a few more \n"
 "blocks, it will stop.  Then it will begin re-reading the\n"
 "two tapes.\n\n"
-"This may take a long time -- hours! ...\n\n"));
+"This may take a long time -- hours! ...\n\n"),
+         edit_uint64_with_suffix(dev->max_file_size, buf1));
 
    get_cmd(_("Do you want to run the simplified test (s) with one tape\n"
            "or the complete multiple tape (m) test: (s/m) "));
@@ -1880,6 +2189,7 @@ static void fillcmd()
       simple = false;
    } else {
       Pmsg0(000, _("Command aborted.\n"));
+      exit_code = 1;
       return;
    }
 
@@ -1889,6 +2199,7 @@ static void fillcmd()
    /* Use fixed block size to simplify read back */
    min_block_size = dev->min_block_size;
    dev->min_block_size = dev->max_block_size;
+   write_eof = dev->max_file_size / REC_SIZE; /*compute when we add EOF*/
    set_volume_name("TestVolume1", 1);
    dir_ask_sysop_to_create_appendable_volume(dcr);
    dev->set_append();                 /* force volume to be relabeled */
@@ -1901,6 +2212,7 @@ static void fillcmd()
    Dmsg0(100, "just before acquire_device\n");
    if (!acquire_device_for_append(dcr)) {
       set_jcr_job_status(jcr, JS_ErrorTerminated);
+      exit_code = 1;
       return;
    }
    block = jcr->dcr->block;
@@ -1919,24 +2231,12 @@ static void fillcmd()
 
    memset(&rec, 0, sizeof(rec));
    rec.data = get_memory(100000);     /* max record size */
-
-#define REC_SIZE 32768
    rec.data_len = REC_SIZE;
 
    /*
     * Put some random data in the record
     */
-   fd = open("/dev/urandom", O_RDONLY);
-   if (fd != -1) {
-      read(fd, rec.data, rec.data_len);
-      close(fd);
-   } else {
-      uint32_t *p = (uint32_t *)rec.data;
-      srandom(time(NULL));
-      for (i=0; i<rec.data_len/sizeof(uint32_t); i++) {
-         p[i] = random();
-      }
-   }
+   fill_buffer(FILL_RANDOM, rec.data, rec.data_len);
 
    /*
     * Generate data as if from File daemon, write to device
@@ -1957,11 +2257,7 @@ static void fillcmd()
       rec.Stream = STREAM_FILE_DATA;
 
       /* Mix up the data just a bit */
-      uint32_t *lp = (uint32_t *)rec.data;
-      lp[0] += lp[13];
-      for (i=1; i < (rec.data_len-sizeof(uint32_t))/sizeof(uint32_t)-1; i++) {
-         lp[i] += lp[i-1];
-      }
+      mix_buffer(FILL_RANDOM, rec.data, rec.data_len);
 
       Dmsg4(250, "before write_rec FI=%d SessId=%d Strm=%s len=%d\n",
          rec.FileIndex, rec.VolSessionId, 
@@ -1977,6 +2273,8 @@ static void fillcmd()
 
          /* Write block to tape */
          if (!flush_block(block, 1)) {
+            Pmsg0(000, _("Flush block failed.\n"));
+            exit_code = 1;
             break;
          }
 
@@ -1988,29 +2286,34 @@ static void fillcmd()
             if (now <= 0) {
                now = 1;          /* prevent divide error */
             }
-            kbs = (double)dev->VolCatInfo.VolCatBytes / (1000.0 * (double)now);
-            Pmsg4(-1, _("Wrote blk_block=%u, dev_blk_num=%u VolBytes=%s rate=%.1f KB/s\n"),
-               block->BlockNumber, dev->block_num,
-               edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1), (float)kbs);
+            rate = dev->VolCatInfo.VolCatBytes / now;
+            Pmsg5(-1, _("Wrote block=%u, file,blk=%u,%u VolBytes=%s rate=%sB/s\n"),
+               block->BlockNumber, dev->file, dev->block_num,
+               edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1),
+               edit_uint64_with_suffix(rate, ec2));
          }
-         /* Every 32000 blocks (approx 2GB) write an EOF.
+         /* Every X blocks (dev->max_file_size) write an EOF.
           */
-         if ((block->BlockNumber % 32000) == 0) {
+         if ((block->BlockNumber % write_eof) == 0) {
             now = time(NULL);
             (void)localtime_r(&now, &tm);
             strftime(buf1, sizeof(buf1), "%H:%M:%S", &tm);
             Pmsg1(-1, _("%s Flush block, write EOF\n"), buf1);
             flush_block(block, 0);
+#ifdef needed_xxx
             dev->weof(1);
+#endif
          }
 
-         /* Get out after writing 10 blocks to the second tape */
-         if (++BlockNumber > 10 && stop != 0) {      /* get out */
+         /* Get out after writing 1000 blocks to the second tape */
+         if (++BlockNumber > 1000 && stop != 0) {      /* get out */
+            Pmsg0(000, _("Wrote 1000 blocks on second tape. Done.\n"));
             break;
          }
       }
       if (!ok) {
          Pmsg0(000, _("Not OK\n"));
+         exit_code = 1;
          break;
       }
       jcr->JobBytes += rec.data_len;   /* increment bytes this job */
@@ -2018,30 +2321,35 @@ static void fillcmd()
          FI_to_ascii(buf1, rec.FileIndex), rec.VolSessionId,
          stream_to_ascii(buf2, rec.Stream, rec.FileIndex), rec.data_len);
 
-      /* Get out after writing 10 blocks to the second tape */
-      if (BlockNumber > 10 && stop != 0) {      /* get out */
+      /* Get out after writing 1000 blocks to the second tape */
+      if (BlockNumber > 1000 && stop != 0) {      /* get out */
          char ed1[50];
          Pmsg1(-1, "Done writing %s records ...\n", 
              edit_uint64_with_commas(write_count, ed1));
          break;
       }
-   }
+   } /* end big for loop */
+
    if (vol_num > 1) {
       Dmsg0(100, "Write_end_session_label()\n");
       /* Create Job status for end of session label */
       if (!job_canceled(jcr) && ok) {
          set_jcr_job_status(jcr, JS_Terminated);
       } else if (!ok) {
+         Pmsg0(000, _("Job canceled.\n"));
          set_jcr_job_status(jcr, JS_ErrorTerminated);
+         exit_code = 1;
       }
       if (!write_session_label(dcr, EOS_LABEL)) {
          Pmsg1(000, _("Error writing end session label. ERR=%s\n"), dev->bstrerror());
          ok = false;
+         exit_code = 1;
       }
       /* Write out final block of this session */
       if (!write_block_to_device(dcr)) {
          Pmsg0(-1, _("Set ok=false after write_block_to_device.\n"));
          ok = false;
+         exit_code = 1;
       }
       Pmsg0(-1, _("Wrote End of Session label.\n"));
 
@@ -2067,29 +2375,37 @@ static void fillcmd()
       write(fd, last_block2->buf, last_block2->buf_len);
       write(fd, first_block->buf, first_block->buf_len);
       close(fd);
-      Pmsg2(-1, _("Wrote state file last_block_num1=%d last_block_num2=%d\n"),
+      Pmsg2(0, _("Wrote state file last_block_num1=%d last_block_num2=%d\n"),
          last_block_num1, last_block_num2);
    } else {
       berrno be;
-      Pmsg2(-1, _("Could not create state file: %s ERR=%s\n"), buf,
+      Pmsg2(0, _("Could not create state file: %s ERR=%s\n"), buf,
                  be.bstrerror());
+      exit_code = 1;
+      ok = false;
    }
 
    now = time(NULL);
    (void)localtime_r(&now, &tm);
    strftime(buf1, sizeof(buf1), "%H:%M:%S", &tm);
-   if (simple) {
-      Pmsg3(-1, _("\n\n%s Done filling tape at %d:%d. Now beginning re-read of tape ...\n"),
-         buf1, jcr->dcr->dev->file, jcr->dcr->dev->block_num);
-   }
-   else {
-      Pmsg3(-1, _("\n\n%s Done filling tapes at %d:%d. Now beginning re-read of first tape ...\n"),
-         buf1, jcr->dcr->dev->file, jcr->dcr->dev->block_num);
-   }
-
-   jcr->dcr->block = block;
-   do_unfill();
+   if (ok) {
+      if (simple) {
+         Pmsg3(0, _("\n\n%s Done filling tape at %d:%d. Now beginning re-read of tape ...\n"),
+               buf1, jcr->dcr->dev->file, jcr->dcr->dev->block_num);
+      } else {
+         Pmsg3(0, _("\n\n%s Done filling tapes at %d:%d. Now beginning re-read of first tape ...\n"),
+               buf1, jcr->dcr->dev->file, jcr->dcr->dev->block_num);
+      }
 
+      jcr->dcr->block = block;
+      if (!do_unfill()) {
+         Pmsg0(000, _("do_unfill failed.\n"));
+         exit_code = 1;
+         ok = false;
+      }
+   } else {
+      Pmsg1(000, _("%s: Error during test.\n"), buf1);
+   }
    dev->min_block_size = min_block_size;
    free_memory(rec.data);
 }
@@ -2104,6 +2420,7 @@ static void unfillcmd()
 {
    int fd;
 
+   exit_code = 0;
    last_block1 = new_block(dev);
    last_block2 = new_block(dev);
    first_block = new_block(dev);
@@ -2124,28 +2441,38 @@ static void unfillcmd()
       if (state_level != btape_state_level) {
           Pmsg0(-1, _("\nThe state file level has changed. You must redo\n"
                   "the fill command.\n"));
+          exit_code = 1;
           return;
        }
    } else {
       berrno be;
       Pmsg2(-1, _("\nCould not find the state file: %s ERR=%s\n"
              "You must redo the fill command.\n"), buf, be.bstrerror());
+      exit_code = 1;
       return;
    }
-   do_unfill();
+   if (!do_unfill()) {
+      exit_code = 1;
+   }
    this_block = NULL;
 }
 
-static void do_unfill()
+/*
+ * This is the second part of the fill command. After the tape or
+ *  tapes are written, we are called here to reread parts, particularly
+ *  the last block.
+ */
+static bool do_unfill()
 {
    DEV_BLOCK *block = dcr->block;
    int autochanger;
+   bool rc = false;
 
    dumped = 0;
    VolBytes = 0;
    LastBlock = 0;
 
-   Dmsg0(20, "Enter do_unfill\n");
+   Pmsg0(000, "Enter do_unfill\n");
    dev->set_cap(CAP_ANONVOLS);        /* allow reading any volume */
    dev->clear_cap(CAP_LABEL);         /* don't label anything here */
 
@@ -2183,8 +2510,10 @@ static void do_unfill()
       }
       autochanger = autoload_device(dcr, 1, NULL);
       if (autochanger != 1) {
+         Pmsg1(100, "Autochanger returned: %d\n", autochanger);
          dev->close();
          get_cmd(_("Mount first tape. Press enter when ready: "));
+         Pmsg0(000, "\n");
       }
    }
 
@@ -2245,8 +2574,10 @@ static void do_unfill()
 
    autochanger = autoload_device(dcr, 1, NULL);
    if (autochanger != 1) {
+      Pmsg1(100, "Autochanger returned: %d\n", autochanger);
       dev->close();
       get_cmd(_("Mount second tape. Press enter when ready: "));
+      Pmsg0(000, "\n");
    }
 
    dev->clear_read();
@@ -2286,12 +2617,14 @@ static void do_unfill()
    }
    if (compare_blocks(last_block, block)) {
       Pmsg0(-1, _("\nThe last block on the second tape matches. Test succeeded.\n\n"));
+      rc = true;
    }
 
 bail_out:
    free_block(last_block1);
    free_block(last_block2);
    free_block(first_block);
+   return rc;
 }
 
 /* Read 10000 records then stop */
@@ -2340,10 +2673,6 @@ static bool compare_blocks(DEV_BLOCK *last_block, DEV_BLOCK *block)
    return true;
 }
 
-
-
-
-
 /*
  * Write current block to tape regardless of whether or
  *   not it is full. If the tape fills, attempt to
@@ -2351,7 +2680,8 @@ static bool compare_blocks(DEV_BLOCK *last_block, DEV_BLOCK *block)
  */
 static int flush_block(DEV_BLOCK *block, int dump)
 {
-   char ec1[50];
+   char ec1[50], ec2[50];
+   uint64_t rate;
    DEV_BLOCK *tblock;
    uint32_t this_file, this_block_num;
 
@@ -2397,11 +2727,12 @@ static int flush_block(DEV_BLOCK *block, int dump)
       if (now <= 0) {
          now = 1;                     /* don't divide by zero */
       }
-      kbs = (double)dev->VolCatInfo.VolCatBytes / (1000 * now);
+      rate = dev->VolCatInfo.VolCatBytes / now;
       vol_size = dev->VolCatInfo.VolCatBytes;
-      Pmsg4(000, _("End of tape %d:%d. VolumeCapacity=%s. Write rate = %.1f KB/s\n"),
+      Pmsg4(000, _("End of tape %d:%d. Volume Bytes=%s. Write rate = %sB/s\n"),
          dev->file, dev->block_num,
-         edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1), kbs);
+         edit_uint64_with_commas(dev->VolCatInfo.VolCatBytes, ec1), 
+         edit_uint64_with_suffix(rate, ec2));
 
       if (simple) {
          stop = -1;                   /* stop, but do simplified test */
@@ -2466,6 +2797,8 @@ static void qfillcmd()
    memset(rec->data, i & 0xFF, i);
    rec->data_len = i;
    rewindcmd();
+   init_speed();
+
    Pmsg1(0, _("Begin writing %d Bacula blocks to tape ...\n"), count);
    for (i=0; i < count; i++) {
       if (i % 100 == 0) {
@@ -2482,6 +2815,7 @@ static void qfillcmd()
       }
    }
    printf("\n");
+   print_speed(dev->VolCatInfo.VolCatBytes);
    weofcmd();
    if (dev->has_cap(CAP_TWOEOF)) {
       weofcmd();
@@ -2500,23 +2834,13 @@ static void rawfill_cmd()
 {
    DEV_BLOCK *block = dcr->block;
    int stat;
-   int fd;
    uint32_t block_num = 0;
    uint32_t *p;
    int my_errno;
-   uint32_t i;
 
-   fd = open("/dev/urandom", O_RDONLY);
-   if (fd) {
-      read(fd, block->buf, block->buf_len);
-      close(fd);
-   } else {
-      uint32_t *p = (uint32_t *)block->buf;
-      srandom(time(NULL));
-      for (i=0; i<block->buf_len/sizeof(uint32_t); i++) {
-         p[i] = random();
-      }
-   }
+   fill_buffer(FILL_RANDOM, block->buf, block->buf_len);
+   init_speed();
+
    p = (uint32_t *)block->buf;
    Pmsg1(0, _("Begin writing raw blocks of %u bytes.\n"), block->buf_len);
    for ( ;; ) {
@@ -2527,10 +2851,10 @@ static void rawfill_cmd()
             printf("+");
             fflush(stdout);
          }
-         p[0] += p[13];
-         for (i=1; i<(block->buf_len-sizeof(uint32_t))/sizeof(uint32_t)-1; i++) {
-            p[i] += p[i-1];
-         }
+
+         mix_buffer(FILL_RANDOM, block->buf, block->buf_len);
+
+         jcr->JobBytes += stat;
          continue;
       }
       break;
@@ -2540,6 +2864,8 @@ static void rawfill_cmd()
    berrno be;
    printf(_("Write failed at block %u. stat=%d ERR=%s\n"), block_num, stat,
       be.bstrerror(my_errno));
+   
+   print_speed(jcr->JobBytes);
    weofcmd();
 }
 
@@ -2568,6 +2894,7 @@ static struct cmdstruct commands[] = {
  {NT_("rewind"),    rewindcmd,    _("rewind the tape")},
  {NT_("scan"),      scancmd,      _("read() tape block by block to EOT and report")},
  {NT_("scanblocks"),scan_blocks,  _("Bacula read block by block to EOT and report")},
+ {NT_("speed"),     speed_test,   _("[file_size=n(GB)|nb_file=3|skip_zero|skip_random|skip_raw|skip_block] report drive speed")},
  {NT_("status"),    statcmd,      _("print tape status")},
  {NT_("test"),      testcmd,      _("General test Bacula tape functions")},
  {NT_("weof"),      weofcmd,      _("write an EOF on the tape")},
@@ -2730,10 +3057,12 @@ bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
    }
    autochanger = autoload_device(dcr, 1, NULL);
    if (autochanger != 1) {
+      Pmsg1(100, "Autochanger returned: %d\n", autochanger);
       fprintf(stderr, _("Mount blank Volume on device %s and press return when ready: "),
          dev->print_name());
       dev->close();
       getchar();
+      Pmsg0(000, "\n");
    }
    labelcmd();
    VolumeName = NULL;
@@ -2743,7 +3072,8 @@ bool dir_ask_sysop_to_create_appendable_volume(DCR *dcr)
 
 static bool my_mount_next_read_volume(DCR *dcr)
 {
-   char ec1[50];
+   char ec1[50], ec2[50];
+   uint64_t rate;
    JCR *jcr = dcr->jcr;
    DEV_BLOCK *block = dcr->block;
 
@@ -2761,9 +3091,10 @@ static bool my_mount_next_read_volume(DCR *dcr)
    if (now <= 0) {
       now = 1;
    }
-   kbs = (double)VolBytes / (1000.0 * (double)now);
-   Pmsg3(-1, _("Read block=%u, VolBytes=%s rate=%.1f KB/s\n"), block->BlockNumber,
-            edit_uint64_with_commas(VolBytes, ec1), (float)kbs);
+   rate = VolBytes / now;
+   Pmsg3(-1, _("Read block=%u, VolBytes=%s rate=%sB/s\n"), block->BlockNumber,
+            edit_uint64_with_commas(VolBytes, ec1), 
+            edit_uint64_with_suffix(rate, ec2));
 
    if (strcmp(dcr->VolumeName, "TestVolume2") == 0) {
       end_of_tape = 1;
index 22734bb8052d8e80aada2fc22cc1d5ca1342278d..f77c18f0d325faee31d562a31a83b438675ca9c4 100644 (file)
@@ -136,6 +136,7 @@ enum {
 #define CAP_MTIOCGET       (1<<20)    /* Basic support for fileno and blkno */
 #define CAP_REQMOUNT       (1<<21)    /* Require mount to read files back (typically: DVD) */
 #define CAP_CHECKLABELS    (1<<22)    /* Check for ANSI/IBM labels */
+#define CAP_BLOCKCHECKSUM  (1<<23)    /* Create/test block checksum */
 
 /* Test state */
 #define dev_state(dev, st_state) ((dev)->state & (st_state))
@@ -307,6 +308,7 @@ public:
    int has_cap(int cap) const { return capabilities & cap; }
    void clear_cap(int cap) { capabilities &= ~cap; }
    void set_cap(int cap) { capabilities |= cap; }
+   bool do_checksum() const { return (capabilities & CAP_BLOCKCHECKSUM) != 0; }
    int is_autochanger() const { return capabilities & CAP_AUTOCHANGER; }
    int requires_mount() const { return capabilities & CAP_REQMOUNT; }
    int is_removable() const { return capabilities & CAP_REM; }
index 19bfec3720c47f68fdcb8a881c4b432766fca315..a2080234a84587c4f112ac9f9303f7fbd98a03ab 100644 (file)
@@ -29,8 +29,6 @@
  * Configuration file parser for Bacula Storage daemon
  *
  *     Kern Sibbald, March MM
- *
- *   Version $Id$
  */
 
 #include "bacula.h"
@@ -142,6 +140,7 @@ static RES_ITEM dev_items[] = {
    {"checklabels",           store_bit,  ITEM(res_dev.cap_bits), CAP_CHECKLABELS, ITEM_DEFAULT, 0},
    {"requiresmount",         store_bit,  ITEM(res_dev.cap_bits), CAP_REQMOUNT, ITEM_DEFAULT, 0},
    {"offlineonunmount",      store_bit,  ITEM(res_dev.cap_bits), CAP_OFFLINEUNMOUNT, ITEM_DEFAULT, 0},
+   {"blockchecksum",         store_bit,  ITEM(res_dev.cap_bits), CAP_BLOCKCHECKSUM, ITEM_DEFAULT, 1},
    {"autoselect",            store_bool, ITEM(res_dev.autoselect), 1, ITEM_DEFAULT, 1},
    {"changerdevice",         store_strname,ITEM(res_dev.changer_name), 0, 0, 0},
    {"changercommand",        store_strname,ITEM(res_dev.changer_command), 0, 0, 0},
index 2dcac1e48ccb882bf09ce184df3fb24649c9b7df..7e1fa231404a0eec20103d89ebad45f67987cb89 100644 (file)
@@ -3,9 +3,9 @@
  */
 
 #undef  VERSION
-#define VERSION "3.0.3"
-#define BDATE   "28 August 2009"
-#define LSMDATE "28Aug09"
+#define VERSION "3.1.3"
+#define BDATE   "06 September 2009"
+#define LSMDATE "06Sep09"
 
 #define PROG_COPYRIGHT "Copyright (C) %d-2009 Free Software Foundation Europe e.V.\n"
 #define BYEAR "2009"       /* year for copyright messages in progs */
index 718907cb19e7c14a18547ca09b229ad2f161163f..0de62c00af1c9a51fd729ea646782a7715d81051 100644 (file)
@@ -2,6 +2,21 @@
           
 General:
 
+07Sep09
+kes  Apply Marco's git format-patch patches for bugs #1365 and #1366
+06Sep09
+kes  Increment minor version to avoid future conflict.
+kes  Increase default path/file length to 2048. This should fix
+     bug #1368.  Too bad Mac OS programmers don't respect POSIX
+     standards.
+04Sep09
+kes  Implement BlockChecksum in Device to be able to turn off checksum
+       for performance reasons
+ebl  btape: Add speed command and test drive speed with Bacula blocks
+03Sep09
+ebl  Use MaxFileSize device configuration in btape
+ebl  Make less tweaks in random buffer in btape
+ebl  Fix #1364 and #1363 about compression buffer error.
 01Sep09
 kes  Many debug code fixes in regression scripts
 kes  Update tape tests for hardware certification
index ae606e1895cf644bb972ac3df6f2ad8dc04e39ae..875f2092cf177d28215005b9121325bf457bad6f 100644 (file)
@@ -1,3 +1,4 @@
+cert.out
 diff
 time.out
 1
diff --git a/regress/full-tape-tests b/regress/full-tape-tests
deleted file mode 100755 (executable)
index 378b214..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-#!/bin/sh
-#
-# Run full tape tests assumes you have an autochanger
-#
-. ./config
-
-# 
-# If we have an autoloader, load the tape in slot1
-if test ! x$AUTOCHANGER = x/dev/null ; then
-   a=`bin/mtx-changer $AUTOCHANGER loaded $SLOT1 $TAPE_DRIVE $DRIVE1`
-   if test $a = 0 ; then
-      bin/mtx-changer $AUTOCHANGER load $SLOT1 $TAPE_DRIVE $DRIVE1
-   fi
-fi
-echo " "
-echo " " >>test.out
-echo "Start full tape tests"
-echo "Start full tape tests" >>test.out
-
-# Non-autochanger tests
-nice tests/ansi-label-tape
-nice tests/backup-bacula-tape
-nice tests/bscan-tape
-nice tests/eighty-simultaneous-jobs-tape
-nice tests/eot-fail-tape
-nice tests/fixed-block-size-tape
-nice tests/four-concurrent-jobs-tape
-nice tests/four-jobs-tape
-nice tests/incremental-2media-tape
-nice tests/incremental-tape
-nice tests/memory-bug-tape
-nice tests/relabel-tape
-nice tests/restore-by-file-tape
-nice tests/restore-seek-tape
-nice tests/small-file-size-tape
-nice tests/truncate-bug-tape
-nice tests/verify-vol-tape
-
-# Autochanger tests
-nice tests/2drive-incremental-changer
-nice tests/bad-label-changer
-nice tests/incremental-changer
-nice tests/two-pool-changer
-nice tests/two-volume-changer
-nice tests/vol-duration-changer
-
-# very long
-# nice tests/btape-fill-full-tape
-
-# requires manual intervention
-# nice tests/manual-two-vol-tape
-
-echo "End full non-root tape tests"
-echo "End full non-root tape tests" >>test.out
index 08ea47ae74d888deed1408b6f1eec4388336b063..0b05ecc587e8beb433ec7f8d010288f220858ec9 100644 (file)
@@ -33,18 +33,29 @@ Director {
 #  same Name and MediaType. 
 #
 
+Autochanger {
+  Name = tape
+  Changer Device = @autochanger@
+  Changer Command ="@scriptdir@/@changer_script@ %c %o %S %a %d"
+  Device = Drive-0
+}
+
+
 Device {
-  Name = tape                      # 
+  Name = Drive-0                   # 
   Media Type = Tape
   Archive Device = @tape_drive@
   AutomaticMount = yes;               # when device opened, read it
   AlwaysOpen = yes;
+  Autochanger = yes;
   RemovableMedia = yes;
   @@sbindir@/tape_options
   Maximum Block Size = 64512
   Minimum Block Size = 64512
   Maximum File Size = 5G 
 # MaximumVolumeSize = 400M
+  Maximum Rewind Wait = 6000
+  Maximum Changer Wait = 6000
 }
 
 # 
index 6e1c89f122bc6cd186a9666ebdce02c54394992b..162238f382c13479a31634eb5dfaa6ff5dd7e76c 100755 (executable)
@@ -14,21 +14,34 @@ TestName="acl-xattr-test"
 JobName=backup
 . scripts/functions
 
-require_linux
-
-# Require getfacl to be installed
-getfacl Makefile 2>&1 >/dev/null
-if test  $? -ne 0; then
-  echo "$TestName skipped: getfacl not installed"
-  exit 0
-fi
-
-# Require attr to be installed
-attr -l Makefile 2>&1 >/dev/null
-if test $? -ne 0; then
-  echo "$TestName skipped: attr not installed"
-  exit 0
-fi
+#
+# See if the right software is installed.
+#
+case `uname -s` in
+   Linux)
+      # Require getfacl to be installed
+      getfacl Makefile 2>&1 >/dev/null
+      if test  $? -ne 0; then
+        echo "$TestName skipped: getfacl not installed"
+        exit 0
+      fi
+
+      # Require attr to be installed
+      attr -l Makefile 2>&1 >/dev/null
+      if test $? -ne 0; then
+        echo "$TestName skipped: attr not installed"
+        exit 0
+      fi
+      ;;
+   Darwin)
+      ;;
+   SunOS)
+      ;;
+   *)
+      echo "Unsupported OS"
+      exit 0
+      ;;
+esac
 
 scripts/cleanup
 scripts/copy-confs
@@ -50,19 +63,65 @@ rm -rf $d
 mkdir $d
 mkdir $d/testdir
 cp ${cwd}/bin/bconsole $d
-setfacl -m d:user:$uid:r-x $d/testdir
-setfacl -m d:user:root:-wx $d/testdir
-setfacl -m user:nobody:--- $d/testdir
-setfacl -m user:nobody:--- $d/bconsole
-setfacl -m group:nogroup:--x $d/bconsole
-cp ${cwd}/bin/bconsole $d/testdir
-cp ${cwd}/bin/bconsole $d/other
-attr -s bacula.test -V rulez $d/other 2>/dev/null 1>/dev/null
-
-( cd $cwd/build
-  getfacl -R acl > $cwd/tmp/org
-  attr -g bacula.test $d/other > $cwd/tmp/attr.org
-)
+
+case `uname -s` in
+   Linux)
+      setfacl -m d:user:$uid:r-x $d/testdir
+      setfacl -m d:user:root:-wx $d/testdir
+      setfacl -m user:nobody:--- $d/testdir
+      setfacl -m user:nobody:--- $d/bconsole
+      setfacl -m group:nogroup:--x $d/bconsole
+      cp ${cwd}/bin/bconsole $d/testdir
+      cp ${cwd}/bin/bconsole $d/other
+      attr -s bacula.test -V rulez $d/other 2>/dev/null 1>/dev/null
+
+      ( cd $cwd/build
+        getfacl -R acl > $cwd/tmp/org
+        attr -g bacula.test $d/other > $cwd/tmp/attr.org
+      )
+      ;;
+   Darwin)
+      chmod +a "user:$uid allow read execute" $d/testdir
+      chmod +a "user:root allow write execute" $d/testdir
+      chmod +a "user:nobody deny read write execute" $d/testdir
+      chmod +a "user:nobody deny read write execute" $d/bconsole
+      chmod +a "group:nogroup allow execute" $d/bconsole
+      cp ${cwd}/bin/bconsole $d/testdir
+      cp ${cwd}/bin/bconsole $d/other
+      xattr -w  bacula.test "rulez" $d/other 2>/dev/null 1>/dev/null
+
+      ( cd $cwd/build
+        ls -lde -R acl > $cwd/tmp/org
+        xattr -p bacula.test $d/other > $cwd/tmp/attr.org
+      )
+      ;;
+   SunOS)
+      #
+      # See if we need to set ZFS or POSIX acls
+      #
+      df -F zfs $d > /dev/null 2>&1
+      if [ $? = 0 ]; then
+         chmod A+user:$uid:rx:allow $d/testdir
+         chmod A+user:root:wx:allow $d/testdir
+         chmod A+user:nobody:rwx:deny $d/testdir
+         chmod A+user:nobody:rwx:deny $d/bconsole
+         chmod A+group:nogroup:x:allow $d/bconsole
+      else
+         chmod A+user:$uid:r-x $d/testdir
+         chmod A+user:root:-wx $d/testdir
+         chmod A+user:nobody:--- $d/testdir
+         chmod A+user:nobody:--- $d/bconsole
+         chmod A+group:nogroup:--x $d/bconsole
+      fi
+      runat $d/other 'cat > bacula.test' << EOF
+rulez
+EOF
+      ( cd $cwd/build
+        ls -ldv -R acl > $cwd/tmp/org
+        runat $d/other 'cat bacula.test' > $cwd/tmp/attr.org
+      )
+      ;;
+esac
 
 change_jobname BackupClient1 $JobName
 start_test
@@ -93,10 +152,26 @@ run_bacula
 check_for_zombie_jobs storage=File
 stop_bacula
 
-( cd $cwd/tmp/bacula-restores/$cwd/build
-  getfacl -R acl > $cwd/tmp/new
-  attr -g bacula.test $d/other > $cwd/tmp/attr.new
-)
+case `uname -s` in
+   Linux)
+      ( cd $cwd/tmp/bacula-restores/$cwd/build
+        getfacl -R acl > $cwd/tmp/new
+        attr -g bacula.test $d/other > $cwd/tmp/attr.new
+      )
+      ;;
+   Darwin)
+      ( cd $cwd/tmp/bacula-restores/$cwd/build
+        ls -lde -R acl > $cwd/tmp/new
+        xattr -p bacula.test $d/other > $cwd/tmp/attr.new
+      )
+      ;;
+   SunOS)
+      ( cd $cwd/tmp/bacula-restores/$cwd/build
+        ls -ldv -R acl > $cwd/tmp/new
+        runat $d/other 'cat bacula.test' > $cwd/tmp/attr.new
+      )
+      ;;
+esac
 
 diff -u $cwd/tmp/org $cwd/tmp/new
 if [ $? -ne 0 ]; then
index b93505d46bd86a4133eb0ee05140bd03a4b46ffa..e778c68fb28f6b6882e7a4e45f5ef0143ade65e1 100755 (executable)
@@ -10,7 +10,7 @@ require_tape_drive
 require_autochanger
 
 scripts/cleanup
-scripts/copy-2tape-confs
+scripts/copy-btape-confs
 
 change_jobname $JobName
 start_test
@@ -20,17 +20,21 @@ start_test
 #
 cp ${cwd}/bin/bacula-sd.conf ${cwd}/tmp/1
 sed -e 's%64512%262144%' ${cwd}/tmp/1 >${cwd}/bin/bacula-sd.conf
-
+#
+# Limit Volume size for debugging without waiting too long
+#
+# cp ${cwd}/bin/bacula-sd.conf ${cwd}/tmp/1
+# sed -e 's%# MaximumVolumeSize = 400M%  MaximumVolumeSize = 400M%' ${cwd}/tmp/1 >${cwd}/bin/bacula-sd.conf
 
 if test "$debug" -eq 1 ; then
-   $bin/btape -c bin/bacula-sd.conf tape <<END_OF_DATA | tee ${cwd}/tmp/log1.out
+   $bin/btape -c bin/bacula-sd.conf Drive-0 <<END_OF_DATA | tee ${cwd}/tmp/log1.out
 fill
 m
 
 quit
 END_OF_DATA
 else
-   $bin/btape -c bin/bacula-sd.conf tape <<END_OF_DATA >${cwd}/tmp/log1.out 2>&1
+   $bin/btape -c bin/bacula-sd.conf Drive-0 <<END_OF_DATA >${cwd}/tmp/log1.out 2>&1
 fill
 m
 
@@ -38,7 +42,7 @@ quit
 END_OF_DATA
 fi
 
-grep "^The last block on the tape matches\. Test succeeded\." ${cwd}/tmp/log1.out >/dev/null 2>&1
+grep "^The last block on the second tape matches\. Test succeeded\." ${cwd}/tmp/log1.out >/dev/null 2>&1
 if [ $? != 0 ] ; then
    echo " "
    echo " "
index 87b803269923d9b60613bb79898998e90f0b927b..bfa0b0d463c4bc1e07ffc5de11a1d4b745e02ded 100755 (executable)
@@ -22,14 +22,14 @@ sed -e 's%64512%262144%' ${cwd}/tmp/1 >${cwd}/bin/bacula-sd.conf
 
 
 if test "$debug" -eq 1 ; then
-   $bin/btape -c bin/bacula-sd.conf tape <<END_OF_DATA | tee ${cwd}/tmp/log1.out
+   $bin/btape -c bin/bacula-sd.conf Drive-0 <<END_OF_DATA | tee ${cwd}/tmp/log1.out
 fill
 s
 
 quit
 END_OF_DATA
 else
-   $bin/btape -c bin/bacula-sd.conf tape <<END_OF_DATA >${cwd}/tmp/log1.out 2>&1
+   $bin/btape -c bin/bacula-sd.conf Drive-0 <<END_OF_DATA >${cwd}/tmp/log1.out 2>&1
 fill
 s
 
index 1388559ecc18ccaf61fe29bfa19bc9bc5d0c5c32..fe240ed6e9ca2edd02bd8e7b31c238a1a389e3f8 100755 (executable)
@@ -17,13 +17,17 @@ change_jobname $JobName
 start_test
 
 if test "$debug" -eq 1 ; then
-  $bin/btape -c bin/bacula-sd.conf tape <<END_OF_DATA | tee ${cwd}/tmp/log1.out
+  $bin/btape -c bin/bacula-sd.conf Drive-0 <<END_OF_DATA | tee ${cwd}/tmp/log1.out
+capcmd
+speed
 test
 yes
 quit
 END_OF_DATA
 else
-  $bin/btape -c bin/bacula-sd.conf tape <<END_OF_DATA >${cwd}/tmp/log1.out 2>&1
+  $bin/btape -c bin/bacula-sd.conf Drive-0 <<END_OF_DATA | tee ${cwd}/tmp/log1.out
+capcmd
+speed
 test
 yes
 quit
@@ -46,13 +50,13 @@ cp ${cwd}/bin/bacula-sd.conf ${cwd}/tmp/1
 sed -e 's%64512%262144%' ${cwd}/tmp/1 >${cwd}/bin/bacula-sd.conf
 
 if test "$debug" -eq 1 ; then
-  $bin/btape -c bin/bacula-sd.conf tape <<END_OF_DATA | tee ${cwd}/tmp/log2.out
+  $bin/btape -c bin/bacula-sd.conf Drive-0 <<END_OF_DATA | tee ${cwd}/tmp/log2.out
 test
 yes
 quit
 END_OF_DATA
 else
-  $bin/btape -c bin/bacula-sd.conf tape <<END_OF_DATA >${cwd}/tmp/log2.out 2>&1
+  $bin/btape -c bin/bacula-sd.conf Drive-0 <<END_OF_DATA >${cwd}/tmp/log2.out 2>&1
 test
 yes
 quit
index 6afb786ef94a4044e247efa74d59129f67cb85a6..5e91e61f2021105d10bd873f9b7680995b6f838b 100755 (executable)
@@ -15,12 +15,12 @@ change_jobname $JobName
 start_test
 
 if test "$debug" -eq 1 ; then
-  $bin/btape -c bin/bacula-sd.conf tape <<END_OF_DATA | tee ${cwd}/tmp/log1.out
+  $bin/btape -c bin/bacula-sd.conf Drive-0 <<END_OF_DATA | tee ${cwd}/tmp/log1.out
 test
 quit
 END_OF_DATA
 else
-  $bin/btape -c bin/bacula-sd.conf tape <<END_OF_DATA >${cwd}/tmp/log1.out 2>&1
+  $bin/btape -c bin/bacula-sd.conf Drive-0 <<END_OF_DATA >${cwd}/tmp/log1.out 2>&1
 test
 quit
 END_OF_DATA
@@ -42,12 +42,12 @@ cp ${cwd}/bin/bacula-sd.conf ${cwd}/tmp/1
 sed -e 's%64512%262144%' ${cwd}/tmp/1 >${cwd}/bin/bacula-sd.conf
 
 if test "$debug" -eq 1 ; then
-  $bin/btape -c bin/bacula-sd.conf tape <<END_OF_DATA | tee ${cwd}/tmp/log2.out
+  $bin/btape -c bin/bacula-sd.conf Drive-0 <<END_OF_DATA | tee ${cwd}/tmp/log2.out
 test
 quit
 END_OF_DATA
 else
-  $bin/btape -c bin/bacula-sd.conf tape <<END_OF_DATA >${cwd}/tmp/log2.out 2>&1
+  $bin/btape -c bin/bacula-sd.conf Drive-0 <<END_OF_DATA >${cwd}/tmp/log2.out 2>&1
 test
 quit
 END_OF_DATA
diff --git a/regress/tests/certify-changer b/regress/tests/certify-changer
new file mode 100755 (executable)
index 0000000..f330776
--- /dev/null
@@ -0,0 +1,89 @@
+#!/bin/sh 
+#
+# Script to automate hardware certification
+# This script assumes that everything is in regress/bin and that
+# you have an autochanger
+#
+# This script was designed for Linux. For other systems, you may
+#  need to edit it.
+#
+outf=cert.out
+. scripts/functions
+
+
+echo " " >${outf}
+echo "=== Start hardware certification tests at `date +%R:%S` ===" >>${outf}
+echo " " >>${outf}
+uname -a >>${outf}
+echo " " >>${outf}
+bin/bacula-dir -t -? >>${outf} 2>>${outf}
+echo " " >>${outf}
+echo "lsscsi:" >>${outf}
+lsscsi >>${outf}
+echo " " >>${outf}
+echo "Changer=${AUTOCHANGER}" >>${outf}
+echo "Drive=${TAPE_DRIVE}" >>${outf}
+echo " " >>${outf}
+echo "tapeinfo: " >>${outf}
+tapeinfo -f ${AUTOCHANGER} >>${outf}
+echo " " >>${outf}
+echo "loaderinfo: " >>${outf}
+loaderinfo -f ${AUTOCHANGER} >>${outf}
+echo " " >>${outf}
+echo "mtx: " >>${outf}
+mtx -f ${AUTOCHANGER} status >>${outf}
+echo " " >>${outf}
+echo "lspci:" >>${outf}
+lspci -vv >>${outf}
+
+
+# If we have an autoloader, load the tape in slot1
+if test ! x$AUTOCHANGER = x/dev/null ; then
+   a=`bin/mtx-changer $AUTOCHANGER loaded $SLOT1 $TAPE_DRIVE $DRIVE1`
+   if test $a = 0 ; then
+      bin/mtx-changer $AUTOCHANGER load $SLOT1 $TAPE_DRIVE $DRIVE1
+   fi
+fi
+
+# Autochanger tests
+REGRESS_DEBUG=1 tests/btape-test-changer >>${outf}
+nice tests/2drive-incremental-changer >>${outf}
+nice tests/bad-label-changer >>${outf}
+nice tests/incremental-changer >>${outf}
+nice tests/two-pool-changer >>${outf}
+nice tests/two-volume-changer >>${outf}
+nice tests/vol-duration-changer >>${outf}
+
+
+
+# Non-autochanger tests
+REGRESS_DEBUG=1 tests/btape-test-tape >>${outf}
+nice tests/ansi-label-tape >>${outf}
+nice tests/backup-bacula-tape >>${outf}
+nice tests/bscan-tape >>${outf}
+nice tests/eighty-simultaneous-jobs-tape >>${outf}
+nice tests/eot-fail-tape >>${outf}
+nice tests/fixed-block-size-tape >>${outf}
+nice tests/four-concurrent-jobs-tape >>${outf}
+nice tests/four-jobs-tape >>${outf}
+nice tests/incremental-2media-tape >>${outf}
+nice tests/incremental-tape >>${outf}
+nice tests/memory-bug-tape >>${outf}
+nice tests/relabel-tape >>${outf}
+nice tests/restore-by-file-tape >>${outf}
+nice tests/restore-seek-tape >>${outf}
+nice tests/small-file-size-tape >>${outf}
+nice tests/truncate-bug-tape >>${outf}
+nice tests/verify-vol-tape >>${outf}
+
+# Autochanger tests
+REGRESS_DEBUG=1 tests/btape-test-changer >>${outf}
+nice tests/2drive-incremental-changer >>${outf}
+nice tests/bad-label-changer >>${outf}
+nice tests/incremental-changer >>${outf}
+nice tests/two-pool-changer >>${outf}
+nice tests/two-volume-changer >>${outf}
+nice tests/vol-duration-changer >>${outf}
+
+
+echo "=== End hardware certification tests at `date +%R:%S` ===" >>${outf}
diff --git a/regress/tests/full-tape-tests b/regress/tests/full-tape-tests
new file mode 100755 (executable)
index 0000000..493ce0f
--- /dev/null
@@ -0,0 +1,57 @@
+#!/bin/sh
+#
+# Run full tape tests assumes you have an autochanger
+#
+. ./config
+
+# 
+# If we have an autoloader, load the tape in slot1
+if test ! x$AUTOCHANGER = x/dev/null ; then
+   a=`bin/mtx-changer $AUTOCHANGER loaded $SLOT1 $TAPE_DRIVE $DRIVE1`
+   if test $a = 0 ; then
+      bin/mtx-changer $AUTOCHANGER load $SLOT1 $TAPE_DRIVE $DRIVE1
+   fi
+fi
+echo " "
+echo " " >>test.out
+echo "Start full tape tests"
+echo "Start full tape tests" >>test.out
+
+# Non-autochanger tests
+nicd tests/btest-test-tape
+nice tests/ansi-label-tape
+nice tests/backup-bacula-tape
+nice tests/bscan-tape
+nice tests/eighty-simultaneous-jobs-tape
+nice tests/eot-fail-tape
+nice tests/fixed-block-size-tape
+nice tests/four-concurrent-jobs-tape
+nice tests/four-jobs-tape
+nice tests/incremental-2media-tape
+nice tests/incremental-tape
+nice tests/memory-bug-tape
+nice tests/relabel-tape
+nice tests/restore-by-file-tape
+nice tests/restore-seek-tape
+nice tests/small-file-size-tape
+nice tests/truncate-bug-tape
+nice tests/verify-vol-tape
+
+# Autochanger tests
+nice tests/btest-test-changer
+nice tests/2drive-incremental-changer
+nice tests/bad-label-changer
+nice tests/incremental-changer
+nice tests/two-pool-changer
+nice tests/two-volume-changer
+nice tests/vol-duration-changer
+
+# very long
+# nice tests/btape-fill-full-tape
+# nice tests/btape-fill-full-changer
+
+# requires manual intervention
+# nice tests/manual-two-vol-tape
+
+echo "End full non-root tape tests"
+echo "End full non-root tape tests" >>test.out
index c6402b949a15603a848185f864fbca59f6a69c90..5ce035252c3d51ef8d558239b26fc42284581d0b 100755 (executable)
@@ -54,7 +54,9 @@ update Media SET VolJobs=1 WHERE VolumeName='vol52';
 update Media SET LastWritten='2006-01-01 01:00:01' WHERE VolumeName='vol57';
 update Media SET LastWritten='2006-01-01 01:00:02' WHERE VolumeName='vol53';
 
-list volume
+list volumes
+wait
+quit
 EOF
 
 run_bacula
@@ -68,7 +70,7 @@ cat <<EOF > ${cwd}/tmp/bconcmds
 run level=full pool=Test NightlySave yes
 wait
 message
-list volume
+list volumes
 @# Must choose vol58
 @# Pool + Recycled + Enabled + InChanger
 run level=full pool=Test NightlySave yes
@@ -80,13 +82,13 @@ list volume
 run level=full pool=Test NightlySave yes
 wait
 message
-list volume
+list volumes
 @# Must choose vol55
 @# Pool + Full + Recycle + Enabled + InChanger
 run level=full pool=Test NightlySave yes
 wait
 message
-list volume
+list volumes
 @# Must choose vol54
 @# No more in Test pool, get from scratch
 @# vol52 is Append, but have 1 job and MaxJob
@@ -106,13 +108,13 @@ list volume
 run level=full pool=Test NightlySave yes
 wait
 message
-list volume
+list volumes
 @# Must choose vol53
 @# Scratch + Purged + Enabled + InChanger + LastW
 run level=full pool=Test NightlySave yes
 wait
-message
-list volume
+messages
+list volumes
 restore fileset="Full Set" pool=Test where=${cwd}/tmp/bacula-restores select all done
 yes
 wait
@@ -124,6 +126,7 @@ messages
 @#wait
 @#message
 @#list volume
+quit
 EOF
 
 run_bconsole
@@ -252,6 +255,7 @@ run level=full pool=Test storage=File NightlySave yes
 wait
 message
 list volume
+wait
 quit
 EOF