]> git.sur5r.net Git - bacula/bacula/commitdiff
Move
authorKern Sibbald <kern@sibbald.com>
Wed, 19 Mar 2008 16:32:21 +0000 (16:32 +0000)
committerKern Sibbald <kern@sibbald.com>
Wed, 19 Mar 2008 16:32:21 +0000 (16:32 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/branches/Branch-2.2@6633 91ce42f0-d328-0410-95d8-f526ca767f89

bacula/patches/2.0.x/2.2.7-fpformat.patch [deleted file]
bacula/patches/2.0.x/2.2.7-jobdefs-migtype.patch [deleted file]
bacula/patches/2.0.x/2.2.7-mysql-batch-timeout.patch [deleted file]
bacula/patches/2.0.x/2.2.7-old-postgresql.patch [deleted file]
bacula/patches/2.0.x/2.2.7-reserve.patch [deleted file]
bacula/patches/2.2.x/2.2.7-fpformat.patch [new file with mode: 0644]
bacula/patches/2.2.x/2.2.7-jobdefs-migtype.patch [new file with mode: 0644]
bacula/patches/2.2.x/2.2.7-mysql-batch-timeout.patch [new file with mode: 0644]
bacula/patches/2.2.x/2.2.7-old-postgresql.patch [new file with mode: 0644]
bacula/patches/2.2.x/2.2.7-reserve.patch [new file with mode: 0644]

diff --git a/bacula/patches/2.0.x/2.2.7-fpformat.patch b/bacula/patches/2.0.x/2.2.7-fpformat.patch
deleted file mode 100644 (file)
index c022627..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-
- This patch fixes a float point editing bug introduced in 2.2.7 (I think)
- causing the rate fields to be formated incorrectly (actually trunctated).
- This fixes bug #1036.
-
- Apply it to version 2.2.7 with:
-
- cd <bacula-source>
- patch -p0 <2.2.7-fpformat.patch
- ./configure <your-options>
- make
- ...
- make install
-
-
-Index: src/lib/bsnprintf.c
-===================================================================
---- src/lib/bsnprintf.c        (revision 6183)
-+++ src/lib/bsnprintf.c        (working copy)
-@@ -16,7 +16,7 @@
- /*
-    Bacula® - The Network Backup Solution
--   Copyright (C) 2005-2007 Free Software Foundation Europe e.V.
-+   Copyright (C) 2005-2008 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.
-@@ -566,11 +566,11 @@
-    return result;
- }
--static long round(LDOUBLE value)
-+static int64_t round(LDOUBLE value)
- {
--   long intpart;
-+   int64_t intpart;
--   intpart = (long)value;
-+   intpart = (int64_t)value;
-    value = value - intpart;
-    if (value >= 0.5)
-       intpart++;
-@@ -584,8 +584,8 @@
-    int signvalue = 0;
-    LDOUBLE ufvalue;
- #ifndef HAVE_FCVT
--   char iconvert[25];
--   char fconvert[25];
-+   char iconvert[311];
-+   char fconvert[311];
- #else
-    char iconvert[311];
-    char fconvert[311];
-@@ -602,6 +602,7 @@
-    int caps = 0;
-    int64_t intpart;
-    int64_t fracpart;
-+   const char *cvt_str;
-    /* 
-     * AIX manpage says the default is 0, but Solaris says the default
-@@ -625,7 +626,7 @@
- #endif
- #ifndef HAVE_FCVT
--   intpart = (long)ufvalue;
-+   intpart = (int64_t)ufvalue;
-    /* 
-     * Sorry, we only support 9 digits past the decimal because of our 
-@@ -645,28 +646,30 @@
-    }
- #ifdef DEBUG_SNPRINTF
--   printf("fmtfp: %g %d.%d min=%d max=%d\n",
-+   printf("fmtfp: %g %lld.%lld min=%d max=%d\n",
-           (double)fvalue, intpart, fracpart, min, max);
- #endif
-    /* Convert integer part */
-+   cvt_str = caps ? "0123456789ABCDEF" : "0123456789abcdef";
-    do {
--      iconvert[iplace++] =
--         (caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10];
-+      iconvert[iplace++] = cvt_str[(int)(intpart % 10)];
-       intpart = (intpart / 10);
--   } while (intpart && (iplace < (int)sizeof(iplace)));
--   if (iplace == (int)sizeof(iplace)) {
-+   } while (intpart && (iplace < (int)sizeof(iconvert)));
-+
-+   if (iplace == (int)sizeof(fconvert)) {
-       iplace--;
-    }
-    iconvert[iplace] = 0;
-    /* Convert fractional part */
-+   cvt_str = caps ? "0123456789ABCDEF" : "0123456789abcdef";
-    do {
--      fconvert[fplace++] =
--         (caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart % 10];
-+      fconvert[fplace++] = cvt_str[fracpart % 10];
-       fracpart = (fracpart / 10);
--   } while (fracpart && (fplace < (int)sizeof(fplace)));
--   if (fplace == (int)sizeof(fplace)) {
-+   } while (fracpart && (fplace < (int)sizeof(fconvert)));
-+
-+   if (fplace == (int)sizeof(fconvert)) {
-       fplace--;
-    }
-    fconvert[fplace] = 0;
-@@ -825,7 +828,7 @@
-       NULL
-    };
-    double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
--      0.9996, 1.996, 4.136, 6442452944.1234, 0
-+      0.9996, 1.996, 4.136, 6442452944.1234, 0, 23365.5
-    };
- #endif
-    char *int_fmt[] = {
diff --git a/bacula/patches/2.0.x/2.2.7-jobdefs-migtype.patch b/bacula/patches/2.0.x/2.2.7-jobdefs-migtype.patch
deleted file mode 100644 (file)
index c636dd6..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-
- This patch permits to use migration options with JobDefs.
- This patch fixes bug #1028.
-
- Apply the patch to 2.2.7 (and possibly any 2.2.x version with):
-
- cd <bacula-source>
- patch -p0 <2.2.7-jobdefs-migtype.patch
- ./configure <your-options>
- make
- ...
- make install
-
-Index: src/dird/dird.c
-===================================================================
---- src/dird/dird.c    (revision 6183)
-+++ src/dird/dird.c    (working copy)
-@@ -58,6 +58,7 @@
- void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
- void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
- void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
-+void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
- void init_device_resources();
- static char *runjob = NULL;
-@@ -698,6 +699,7 @@
-                           job_items[i].handler == store_jobtype ||
-                           job_items[i].handler == store_level   ||
-                           job_items[i].handler == store_pint    ||
-+                          job_items[i].handler == store_migtype ||
-                           job_items[i].handler == store_replace) {
-                   def_ivalue = (int *)((char *)(job->jobdefs) + offset);
-                   Dmsg5(400, "Job \"%s\", field \"%s\" def_ivalue=%d item %d offset=%u\n",
-Index: src/dird/dird_conf.c
-===================================================================
---- src/dird/dird_conf.c       (revision 6183)
-+++ src/dird/dird_conf.c       (working copy)
-@@ -74,8 +74,8 @@
- void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
- void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
- void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
-+void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
- static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
--static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
- static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
- static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
- static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
-@@ -1548,7 +1548,7 @@
-  * Store JobType (backup, verify, restore)
-  *
-  */
--static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
-+void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
- {
-    int token, i;
diff --git a/bacula/patches/2.0.x/2.2.7-mysql-batch-timeout.patch b/bacula/patches/2.0.x/2.2.7-mysql-batch-timeout.patch
deleted file mode 100644 (file)
index fafb85d..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-
- This patch fixes bug #1034 about Temporary MySQL table 'batch' 
- disappears if MySQL connection times out.
-
- Apply the patch to 2.2.7 (and possibly any 2.2.x version with):
-
- cd <bacula-source>
- patch -p0 <2.2.7-mysql-batch-timeout.patch
- ./configure <your-options>
- make
- ...
- make install
-
-
-
-Index: src/cats/mysql.c
-===================================================================
---- src/cats/mysql.c   (révision 6192)
-+++ src/cats/mysql.c   (copie de travail)
-@@ -205,6 +205,10 @@
-    Dmsg3(100, "opendb ref=%d connected=%d db=%p\n", mdb->ref_count,
-          mdb->connected, mdb->db);
-+   /* Set connection timeout to 8 days specialy for batch mode */
-+   sql_query(mdb, "SET wait_timeout=691200");
-+   sql_query(mdb, "SET interactive_timeout=691200");
-+
-    V(mutex);
-    return 1;
- }
diff --git a/bacula/patches/2.0.x/2.2.7-old-postgresql.patch b/bacula/patches/2.0.x/2.2.7-old-postgresql.patch
deleted file mode 100644 (file)
index d13b118..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-
- If you have an old version of PostgreSQL, for example,
- version 7.3 or older, it may not properly build with the current
- Bacula release due to incompatible changes in the PostgreSQL
- header files between version.  Only in the case that build fails,
- you might try applying this patch with:
-
- cd <bacula-2.2.7-source>
- patch -p1 <2.2.7-old-postgresql.patch
- ./configure <your-options>
- make
- ...
- make install
-
-
-diff -uNr bacula-2.2.7/src/cats/postgresql.c bacula-2.2.7-fixed/src/cats/postgresql.c
---- bacula-2.2.7/src/cats/postgresql.c 2007-12-08 04:54:55.000000000 -0500
-+++ bacula-2.2.7-fixed/src/cats/postgresql.c   2007-12-29 08:34:10.000000000 -0500
-@@ -47,7 +47,6 @@
- #ifdef HAVE_POSTGRESQL
- #include "postgres_ext.h"       /* needed for NAMEDATALEN */
--#include "pg_config_manual.h"   /* get NAMEDATALEN on version 8.3 or later */
- /* -----------------------------------------------------------------------
-  *
diff --git a/bacula/patches/2.0.x/2.2.7-reserve.patch b/bacula/patches/2.0.x/2.2.7-reserve.patch
deleted file mode 100644 (file)
index 42daad1..0000000
+++ /dev/null
@@ -1,1467 +0,0 @@
-
- This patch has a number of cleanups and improvements to the SD          
- reservations system. It should fix a number of problems with
- dual drive autochangers as well ensure that volume use durations
- and max volume jobs are better respected.
-
- Apply it to version 2.2.7 (possibly some earlier versions) with:
-
- cd <bacula-source>
- patch -p1 <2.2.7-reserve.patch
- ./configure <your options>
- make
- ...
- make install
-
-
-diff -ur k1/src/lib/message.c k3/src/lib/message.c
---- k1/src/lib/message.c       2007-10-19 13:47:58.000000000 +0200
-+++ k3/src/lib/message.c       2007-12-22 19:13:00.000000000 +0100
-@@ -54,6 +54,7 @@
- int verbose = 0;                      /* increase User messages */
- /* Keep debug level set to zero by default */
- int debug_level = 0;                  /* debug level */
-+bool dbg_timestamp = false;           /* print timestamp in debug output */
- time_t daemon_start_time = 0;         /* Daemon start time */
- const char *version = VERSION " (" BDATE ")";
- char my_name[30];                     /* daemon name is stored here */
-diff -ur k1/src/lib/message.h k3/src/lib/message.h
---- k1/src/lib/message.h       2007-10-03 13:36:47.000000000 +0200
-+++ k3/src/lib/message.h       2007-12-22 19:13:06.000000000 +0100
-@@ -154,6 +154,7 @@
- extern DLL_IMP_EXP sql_escape    p_sql_escape;
- extern DLL_IMP_EXP int           debug_level;
-+extern DLL_IMP_EXP bool          dbg_timestamp;            /* print timestamp in debug output */
- extern DLL_IMP_EXP int           verbose;
- extern DLL_IMP_EXP char          my_name[];
- extern DLL_IMP_EXP const char *  working_directory;
-diff -ur k1/src/stored/acquire.c k3/src/stored/acquire.c
---- k1/src/stored/acquire.c    2007-09-14 11:49:06.000000000 +0200
-+++ k3/src/stored/acquire.c    2007-12-22 19:12:23.000000000 +0100
-@@ -30,7 +30,7 @@
-  *
-  *   Kern Sibbald, August MMII
-  *
-- *   Version $Id: acquire.c 5552 2007-09-14 09:49:06Z kerns $
-+ *   Version $Id: acquire.c 6081 2007-12-21 14:11:40Z kerns $
-  */
- #include "bacula.h"                   /* pull in global headers */
-@@ -38,6 +38,7 @@
- /* Forward referenced functions */
- static void attach_dcr_to_dev(DCR *dcr);
-+static bool is_suitable_volume_mounted(DCR *dcr);
- /*********************************************************************
-@@ -316,9 +317,9 @@
-  */
- DCR *acquire_device_for_append(DCR *dcr)
- {
--   bool release = false;
--   bool recycle = false;
-    bool do_mount = false;
-+   bool release = false;
-+   bool have_vol;
-    DEVICE *dev = dcr->dev;
-    JCR *jcr = dcr->jcr;
-@@ -337,6 +338,11 @@
-       goto get_out;
-    }
-+   /*
-+    * have_vol defines whether or not mount_next_write_volume should
-+    *   ask the Director again about what Volume to use.
-+    */
-+   have_vol = is_suitable_volume_mounted(dcr);
-    if (dev->can_append()) {
-       Dmsg0(190, "device already in append.\n");
-       /*
-@@ -351,25 +357,11 @@
-        *  dcr->VolumeName is what we pass into the routines, or
-        *    get back from the subroutines.
-        */
--      bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
--      if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
-+      if (!have_vol &&
-           !(dir_find_next_appendable_volume(dcr) &&
-             strcmp(dev->VolHdr.VolumeName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
--         Dmsg2(190, "Wrong tape mounted: %s. wants:%s\n", dev->VolHdr.VolumeName,
--            dcr->VolumeName);
--         /* Release volume reserved by dir_find_next_appendable_volume() */
--         if (dcr->VolumeName[0]) {
--            volume_unused(dcr);
--         }
--         if (dev->num_writers != 0) {
--            Jmsg3(jcr, M_FATAL, 0, _("Wanted to append to Volume \"%s\", but device %s is busy writing on \"%s\" .\n"), 
--                 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
--            Dmsg3(200, "Wanted to append to Volume \"%s\", but device %s is busy writing on \"%s\" .\n",  
--                 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
--            goto get_out;
--         }
-          /* Wrong tape mounted, release it, then fall through to get correct one */
--         Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
-+         Dmsg0(50, "Wrong tape mounted, release and try mount.\n");
-          release = true;
-          do_mount = true;
-       } else {
-@@ -378,14 +370,17 @@
-           *   we do not need to do mount_next_write_volume(), unless
-           *   we need to recycle the tape.
-           */
--          recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
--          Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
--          if (recycle && dev->num_writers != 0) {
-+          do_mount = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
-+          Dmsg2(190, "jid=%u Correct tape mounted. recycle=%d\n", 
-+                (uint32_t)jcr->JobId, do_mount);
-+#ifdef xxx
-+          if (do_mount && dev->num_writers != 0) {
-              Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
-                   " on device %s because it is in use by another job.\n"),
-                   dev->VolHdr.VolumeName, dev->print_name());
-              goto get_out;
-           }
-+#endif
-           if (dev->num_writers == 0) {
-              memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
-           }
-@@ -415,21 +410,23 @@
-       }
-    } else {
-       /* Not already in append mode, so mount the device */
--      Dmsg0(190, "Not in append mode, try mount.\n");
-+      Dmsg2(190, "jid=%u Not in append mode, try mount have_vol=%d\n", 
-+            (uint32_t)jcr->JobId, have_vol);
-+
-       ASSERT(dev->num_writers == 0);
-       do_mount = true;
-    }
--   if (do_mount || recycle) {
--      Dmsg0(190, "Do mount_next_write_vol\n");
--      bool mounted = mount_next_write_volume(dcr, release);
-+   if (do_mount || !have_vol) {
-+      Dmsg1(190, "jid=%u Do mount_next_write_vol\n", (uint32_t)jcr->JobId);
-+      bool mounted = mount_next_write_volume(dcr, have_vol, release);
-       if (!mounted) {
-          if (!job_canceled(jcr)) {
-             /* Reduce "noise" -- don't print if job canceled */
-             Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
-                dev->print_name());
--            Dmsg1(200, "Could not ready device %s for append.\n", 
--               dev->print_name());
-+            Dmsg2(200, "jid=%u Could not ready device %s for append.\n", 
-+               (uint32_t)jcr->JobId, dev->print_name());
-          }
-          goto get_out;
-       }
-@@ -441,11 +438,12 @@
-       jcr->NumWriteVolumes = 1;
-    }
-    dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs on vol */
--   dir_update_volume_info(dcr, false);        /* send Volume info to Director */
-+   dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
-    dev->dlock();
-    if (dcr->reserved_device) {
-       dev->reserved_device--;
--      Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
-+      Dmsg3(100, "jid=%u Dec reserve=%d dev=%s\n", (uint32_t)jcr->JobId,
-+            dev->reserved_device, dev->print_name());
-       dcr->reserved_device = false;
-    }
-    dev->dunblock(DEV_LOCKED);
-@@ -458,7 +456,8 @@
-    dev->dlock();
-    if (dcr->reserved_device) {
-       dev->reserved_device--;
--      Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
-+      Dmsg3(100, "jid=%u Dec reserve=%d dev=%s\n", (uint32_t)jcr->JobId, 
-+            dev->reserved_device, dev->print_name());
-       dcr->reserved_device = false;
-    }
-    dev->dunblock(DEV_LOCKED);
-@@ -466,6 +465,18 @@
- }
-+static bool is_suitable_volume_mounted(DCR *dcr)
-+{
-+   DEVICE *dev = dcr->dev;
-+
-+   /* Volume mounted? */
-+   if (dev->VolHdr.VolumeName[0] == 0) {
-+      return false;                      /* no */
-+   }
-+   bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
-+   return dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE);
-+}
-+
- /*
-  * This job is done, so release the device. From a Unix standpoint,
-  *  the device remains open.
-@@ -496,7 +507,7 @@
-    if (dev->can_read()) {
-       dev->clear_read();              /* clear read bit */
-       Dmsg0(100, "dir_update_vol_info. Release0\n");
--      dir_update_volume_info(dcr, false); /* send Volume info to Director */
-+      dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
-    } else if (dev->num_writers > 0) {
-       /* 
-@@ -522,7 +533,7 @@
-             dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
-             /* Note! do volume update before close, which zaps VolCatInfo */
-             Dmsg0(100, "dir_update_vol_info. Release0\n");
--            dir_update_volume_info(dcr, false); /* send Volume info to Director */
-+            dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
-          }
-       }
-@@ -621,7 +632,12 @@
-       if (dcr->attached_to_dev) {
-          detach_dcr_from_dev(dcr);
-       }
--      dcr->max_job_spool_size = dev->device->max_job_spool_size;
-+      /* Use job spoolsize prior to device spoolsize */
-+      if (jcr->spool_size) {
-+         dcr->max_job_spool_size = jcr->spool_size;
-+      } else {
-+         dcr->max_job_spool_size = dev->device->max_job_spool_size;
-+      }
-       dcr->device = dev->device;
-       dcr->dev = dev;
-       attach_dcr_to_dev(dcr);
-diff -ur k1/src/stored/askdir.c k3/src/stored/askdir.c
---- k1/src/stored/askdir.c     2007-09-09 12:03:23.000000000 +0200
-+++ k3/src/stored/askdir.c     2007-12-22 19:11:50.000000000 +0100
-@@ -31,7 +31,7 @@
-  *
-  *   Kern Sibbald, December 2000
-  *
-- *   Version $Id: askdir.c 5503 2007-09-09 10:03:23Z kerns $
-+ *   Version $Id: askdir.c 5852 2007-11-04 19:57:42Z kerns $
-  */
- #include "bacula.h"                   /* pull in global headers */
-@@ -42,7 +42,7 @@
- static char Get_Vol_Info[] = "CatReq Job=%s GetVolInfo VolName=%s write=%d\n";
- static char Update_media[] = "CatReq Job=%s UpdateMedia VolName=%s"
-    " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%s VolMounts=%u"
--   " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%d VolStatus=%s"
-+   " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%s VolStatus=%s"
-    " Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s"
-    " VolFirstWritten=%s VolParts=%u\n";
- static char Create_job_media[] = "CatReq Job=%s CreateJobMedia"
-@@ -98,7 +98,7 @@
-    } else {
-       pm_strcpy(ChangerName, "*");
-    }
--   ok =bnet_fsend(dir, Device_update, 
-+   ok = dir->fsend(Device_update, 
-       jcr->Job,
-       dev_name.c_str(),
-       dev->can_append()!=0,
-@@ -125,7 +125,7 @@
-    pm_strcpy(MediaType, device->media_type);
-    bash_spaces(MediaType);
-    /* This is mostly to indicate that we are here */
--   ok = bnet_fsend(dir, Device_update,
-+   ok = dir->fsend(Device_update,
-       jcr->Job,
-       dev_name.c_str(),         /* Changer name */
-       0, 0, 0,                  /* append, read, num_writers */
-@@ -148,7 +148,7 @@
-  */
- bool dir_send_job_status(JCR *jcr)
- {
--   return bnet_fsend(jcr->dir_bsock, Job_status, jcr->Job, jcr->JobStatus);
-+   return jcr->dir_bsock->fsend(Job_status, jcr->Job, jcr->JobStatus);
- }
- /*
-@@ -179,7 +179,7 @@
-        return false;
-     }
-     memset(&vol, 0, sizeof(vol));
--    Dmsg1(100, "<dird %s\n", dir->msg);
-+    Dmsg1(100, "<dird %s", dir->msg);
-     n = sscanf(dir->msg, OK_media, vol.VolCatName,
-                &vol.VolCatJobs, &vol.VolCatFiles,
-                &vol.VolCatBlocks, &vol.VolCatBytes,
-@@ -191,7 +191,8 @@
-                &vol.EndFile, &vol.EndBlock, &vol.VolCatParts,
-                &vol.LabelType, &vol.VolMediaId);
-     if (n != 22) {
--       Dmsg3(100, "Bad response from Dir fields=%d, len=%d: %s", n, dir->msglen, dir->msg);
-+       Dmsg3(100, "Bad response from Dir fields=%d, len=%d: %s", 
-+             n, dir->msglen, dir->msg);
-        Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg);
-        return false;
-     }
-@@ -226,7 +227,7 @@
-     bash_spaces(dcr->VolCatInfo.VolCatName);
-     dir->fsend(Get_Vol_Info, jcr->Job, dcr->VolCatInfo.VolCatName,
-        writing==GET_VOL_INFO_FOR_WRITE?1:0);
--    Dmsg1(100, ">dird: %s\n", dir->msg);
-+    Dmsg1(100, ">dird %s", dir->msg);
-     unbash_spaces(dcr->VolCatInfo.VolCatName);
-     bool ok = do_get_volume_info(dcr);
-     V(vol_info_mutex);
-@@ -253,7 +254,9 @@
-     BSOCK *dir = jcr->dir_bsock;
-     bool found = false;
--    Dmsg0(200, "dir_find_next_appendable_volume\n");
-+    Dmsg2(200, "dir_find_next_appendable_volume: reserved=%d Vol=%s\n", 
-+       dcr->reserved_device, dcr->VolumeName);
-+
-     /*
-      * Try the twenty oldest or most available volumes.  Note,
-      *   the most available could already be mounted on another
-@@ -268,7 +271,7 @@
-        dir->fsend(Find_media, jcr->Job, vol_index, dcr->pool_name, dcr->media_type);
-        unbash_spaces(dcr->media_type);
-        unbash_spaces(dcr->pool_name);
--       Dmsg1(100, ">dird: %s", dir->msg);
-+       Dmsg1(100, ">dird %s", dir->msg);
-        bool ok = do_get_volume_info(dcr);
-        if (ok) {
-           if (!is_volume_in_use(dcr)) {
-@@ -311,14 +314,13 @@
-  * back to the director. The information comes from the
-  * dev record.
-  */
--bool dir_update_volume_info(DCR *dcr, bool label)
-+bool dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten)
- {
-    JCR *jcr = dcr->jcr;
-    BSOCK *dir = jcr->dir_bsock;
-    DEVICE *dev = dcr->dev;
--   time_t LastWritten = time(NULL);
-    VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
--   char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
-+   char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
-    int InChanger;
-    bool ok = false;
-    POOL_MEM VolumeName;
-@@ -341,21 +343,25 @@
-    if (label) {
-       bstrncpy(vol->VolCatStatus, "Append", sizeof(vol->VolCatStatus));
-    }
-+// if (update_LastWritten) {
-+      vol->VolLastWritten = time(NULL);
-+// }
-    pm_strcpy(VolumeName, vol->VolCatName);
-    bash_spaces(VolumeName);
-    InChanger = vol->InChanger;
--   bnet_fsend(dir, Update_media, jcr->Job,
-+   dir->fsend(Update_media, jcr->Job,
-       VolumeName.c_str(), vol->VolCatJobs, vol->VolCatFiles,
-       vol->VolCatBlocks, edit_uint64(vol->VolCatBytes, ed1),
-       vol->VolCatMounts, vol->VolCatErrors,
-       vol->VolCatWrites, edit_uint64(vol->VolCatMaxBytes, ed2),
--      LastWritten, vol->VolCatStatus, vol->Slot, label,
-+      edit_uint64(vol->VolLastWritten, ed6), 
-+      vol->VolCatStatus, vol->Slot, label,
-       InChanger,                      /* bool in structure */
-       edit_int64(vol->VolReadTime, ed3),
-       edit_int64(vol->VolWriteTime, ed4),
-       edit_uint64(vol->VolFirstWritten, ed5),
-       vol->VolCatParts);
--    Dmsg1(100, ">dird: %s", dir->msg);
-+    Dmsg1(100, ">dird %s", dir->msg);
-    /* Do not lock device here because it may be locked from label */
-    if (!do_get_volume_info(dcr)) {
-@@ -364,7 +370,7 @@
-          vol->VolCatName, jcr->errmsg);
-       goto bail_out;
-    }
--   Dmsg1(420, "get_volume_info(): %s", dir->msg);
-+   Dmsg1(420, "get_volume_info() %s", dir->msg);
-    /* Update dev Volume info in case something changed (e.g. expired) */
-    dev->VolCatInfo = dcr->VolCatInfo;
-    ok = true;
-@@ -393,20 +399,20 @@
-    }
-    dcr->WroteVol = false;
--   bnet_fsend(dir, Create_job_media, jcr->Job,
-+   dir->fsend(Create_job_media, jcr->Job,
-       dcr->VolFirstIndex, dcr->VolLastIndex,
-       dcr->StartFile, dcr->EndFile,
-       dcr->StartBlock, dcr->EndBlock, 
-       dcr->Copy, dcr->Stripe, 
-       edit_uint64(dcr->VolMediaId, ed1));
--    Dmsg1(100, ">dird: %s", dir->msg);
-+    Dmsg1(100, ">dird %s", dir->msg);
-    if (bnet_recv(dir) <= 0) {
-       Dmsg0(190, "create_jobmedia error bnet_recv\n");
-       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"),
--           bnet_strerror(dir));
-+           dir->bstrerror());
-       return false;
-    }
--   Dmsg1(100, "<dir: %s", dir->msg);
-+   Dmsg1(100, "<dird %s", dir->msg);
-    if (strcmp(dir->msg, OK_create) != 0) {
-       Dmsg1(130, "Bad response from Dir: %s\n", dir->msg);
-       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg);
-@@ -429,9 +435,10 @@
-    return true;
- #endif
--   dir->msglen = sprintf(dir->msg, FileAttributes, jcr->Job);
--   dir->msg = check_pool_memory_size(dir->msg, dir->msglen +
--                sizeof(DEV_RECORD) + rec->data_len);
-+   dir->msg = check_pool_memory_size(dir->msg, sizeof(FileAttributes) +
-+                MAX_NAME_LENGTH + sizeof(DEV_RECORD) + rec->data_len + 1);
-+   dir->msglen = bsnprintf(dir->msg, sizeof(FileAttributes) +
-+                MAX_NAME_LENGTH + 1, FileAttributes, jcr->Job);
-    ser_begin(dir->msg + dir->msglen, 0);
-    ser_uint32(rec->VolSessionId);
-    ser_uint32(rec->VolSessionTime);
-@@ -440,8 +447,8 @@
-    ser_uint32(rec->data_len);
-    ser_bytes(rec->data, rec->data_len);
-    dir->msglen = ser_length(dir->msg);
--   Dmsg1(1800, ">dird: %s\n", dir->msg);    /* Attributes */
--   return bnet_send(dir);
-+   Dmsg1(1800, ">dird %s\n", dir->msg);    /* Attributes */
-+   return dir->send();
- }
-diff -ur k1/src/stored/bcopy.c k3/src/stored/bcopy.c
---- k1/src/stored/bcopy.c      2007-12-03 20:27:38.000000000 +0100
-+++ k3/src/stored/bcopy.c      2007-12-22 19:10:29.000000000 +0100
-@@ -32,7 +32,7 @@
-  *   Kern E. Sibbald, October 2002
-  *
-  *
-- *   Version $Id: bcopy.c 6017 2007-12-03 19:27:38Z kerns $
-+ *   Version $Id: bcopy.c 6016 2007-12-03 19:27:21Z kerns $
-  */
- #include "bacula.h"
-@@ -42,6 +42,7 @@
- int generate_daemon_event(JCR *jcr, const char *event) { return 1; }
- /* Forward referenced functions */
-+static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec);
- static bool record_cb(DCR *dcr, DEV_RECORD *rec);
-@@ -52,10 +53,11 @@
- static JCR *out_jcr;                   /* output jcr */
- static BSR *bsr = NULL;
- static const char *wd = "/tmp";
--static int list_records = 0;
-+static bool list_records = false;
- static uint32_t records = 0;
- static uint32_t jobs = 0;
- static DEV_BLOCK *out_block;
-+static SESSION_LABEL sessrec;
- #define CONFIG_FILE "bacula-sd.conf"
- char *configfile = NULL;
-@@ -73,7 +75,7 @@
- "Usage: bcopy [-d debug_level] <input-archive> <output-archive>\n"
- "       -b bootstrap      specify a bootstrap file\n"
- "       -c <file>         specify configuration file\n"
--"       -d <nn>           set debug level to nn\n"
-+"       -d <nn>           set debug level to <nn>\n"
- "       -i                specify input Volume names (separated by |)\n"
- "       -o                specify output Volume names (separated by |)\n"
- "       -p                proceed inspite of errors\n"
-@@ -113,9 +115,14 @@
-          break;
-       case 'd':                    /* debug level */
--         debug_level = atoi(optarg);
--         if (debug_level <= 0)
--            debug_level = 1;
-+         if (*optarg == 't') {
-+            dbg_timestamp = true;
-+         } else {
-+            debug_level = atoi(optarg);
-+            if (debug_level <= 0) {
-+               debug_level = 1;
-+            }
-+         }
-          break;
-       case 'i':                    /* input Volume name */
-@@ -201,6 +208,7 @@
-    out_block = out_jcr->dcr->block;
-    ok = read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
-+
-    if (ok || out_dev->can_write()) {
-       if (!write_block_to_device(out_jcr->dcr)) {
-          Pmsg0(000, _("Write of last block failed.\n"));
-@@ -233,6 +241,7 @@
-     *
-     */
-    if (rec->FileIndex < 0) {
-+      get_session_record(in_dcr->dev, rec, &sessrec);
-       if (verbose > 1) {
-          dump_label_record(in_dcr->dev, rec, 1);
-@@ -294,10 +303,46 @@
-    return true;
- }
-+static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec)
-+{
-+   const char *rtype;
-+   memset(sessrec, 0, sizeof(sessrec));
-+   switch (rec->FileIndex) {
-+   case PRE_LABEL:
-+      rtype = _("Fresh Volume Label");
-+      break;
-+   case VOL_LABEL:
-+      rtype = _("Volume Label");
-+      unser_volume_label(dev, rec);
-+      break;
-+   case SOS_LABEL:
-+      rtype = _("Begin Job Session");
-+      unser_session_label(sessrec, rec);
-+      break;
-+   case EOS_LABEL:
-+      rtype = _("End Job Session");
-+      unser_session_label(sessrec, rec);
-+      break;
-+   case 0:
-+   case EOM_LABEL:
-+      rtype = _("End of Medium");
-+      break;
-+   default:
-+      rtype = _("Unknown");
-+      break;
-+   }
-+   Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n",
-+         rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
-+   if (verbose) {
-+      Pmsg5(-1, _("%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n"),
-+            rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
-+   }
-+}
-+
- /* Dummies to replace askdir.c */
- bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
--bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
-+bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
- bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
- bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
- bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
-diff -ur k1/src/stored/bextract.c k3/src/stored/bextract.c
---- k1/src/stored/bextract.c   2007-10-03 13:36:47.000000000 +0200
-+++ k3/src/stored/bextract.c   2007-12-22 19:10:20.000000000 +0100
-@@ -4,7 +4,7 @@
-  *
-  *   Kern E. Sibbald, MM
-  *
-- *   Version $Id: bextract.c 5713 2007-10-03 11:36:47Z kerns $
-+ *   Version $Id: bextract.c 5852 2007-11-04 19:57:42Z kerns $
-  *
-  */
- /*
-@@ -79,7 +79,7 @@
- "Usage: bextract <options> <bacula-archive-device-name> <directory-to-store-files>\n"
- "       -b <file>       specify a bootstrap file\n"
- "       -c <file>       specify a configuration file\n"
--"       -d <nn>         set debug level to nn\n"
-+"       -d <nn>         set debug level to <nn>\n"
- "       -e <file>       exclude list\n"
- "       -i <file>       include list\n"
- "       -p              proceed inspite of I/O errors\n"
-@@ -126,9 +126,14 @@
-          break;
-       case 'd':                    /* debug level */
--         debug_level = atoi(optarg);
--         if (debug_level <= 0)
--            debug_level = 1;
-+         if (*optarg == 't') {
-+            dbg_timestamp = true;
-+         } else {
-+            debug_level = atoi(optarg);
-+            if (debug_level <= 0) {
-+               debug_level = 1;
-+            }
-+         }
-          break;
-       case 'e':                    /* exclude list */
-@@ -476,7 +481,7 @@
- /* Dummies to replace askdir.c */
- bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
--bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
-+bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
- bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
- bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
- bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
-diff -ur k1/src/stored/block.c k3/src/stored/block.c
---- k1/src/stored/block.c      2007-10-03 13:36:47.000000000 +0200
-+++ k3/src/stored/block.c      2007-12-22 19:12:33.000000000 +0100
-@@ -32,7 +32,7 @@
-  *              Kern Sibbald, March MMI
-  *                 added BB02 format October MMII
-  *
-- *   Version $Id: block.c 5713 2007-10-03 11:36:47Z kerns $
-+ *   Version $Id: block.c 5852 2007-11-04 19:57:42Z kerns $
-  *
-  */
-@@ -746,7 +746,7 @@
-       dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
-    }
-    
--   if (!dir_update_volume_info(dcr, false)) {
-+   if (!dir_update_volume_info(dcr, false, true)) {
-       ok = false;
-    }
-    Dmsg1(100, "dir_update_volume_info terminate writing -- %s\n", ok?"OK":"ERROR");
-@@ -798,7 +798,7 @@
-       return false;
-    }
-    dev->VolCatInfo.VolCatFiles = dev->file;
--   if (!dir_update_volume_info(dcr, false)) {
-+   if (!dir_update_volume_info(dcr, false, false)) {
-       Dmsg0(190, "Error from update_vol_info.\n");
-       terminate_writing_volume(dcr);
-       dev->dev_errno = EIO;
-@@ -856,7 +856,7 @@
-       
-       dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
-             
--      if (!dir_update_volume_info(dcr, false)) {
-+      if (!dir_update_volume_info(dcr, false, false)) {
-          Dmsg0(190, "Error from update_vol_info.\n");
-          dev->dev_errno = EIO;
-          return false;
-diff -ur k1/src/stored/bls.c k3/src/stored/bls.c
---- k1/src/stored/bls.c        2007-10-03 13:36:47.000000000 +0200
-+++ k3/src/stored/bls.c        2007-12-22 19:10:57.000000000 +0100
-@@ -31,7 +31,7 @@
-  * 
-  *  Kern Sibbald, MM
-  *
-- *   Version $Id: bls.c 5713 2007-10-03 11:36:47Z kerns $
-+ *   Version $Id: bls.c 5852 2007-11-04 19:57:42Z kerns $
-  */
- #include "bacula.h"
-@@ -79,7 +79,7 @@
- "Usage: bls [options] <device-name>\n"
- "       -b <file>       specify a bootstrap file\n"
- "       -c <file>       specify a config file\n"
--"       -d <level>      specify debug level\n"
-+"       -d <nn>         set debug level to <nn>\n"
- "       -e <file>       exclude list\n"
- "       -i <file>       include list\n"
- "       -j              list jobs\n"
-@@ -130,9 +130,14 @@
-          break;
-       case 'd':                    /* debug level */
--         debug_level = atoi(optarg);
--         if (debug_level <= 0)
--            debug_level = 1;
-+         if (*optarg == 't') {
-+            dbg_timestamp = true;
-+         } else {
-+            debug_level = atoi(optarg);
-+            if (debug_level <= 0) {
-+               debug_level = 1;
-+            }
-+         }
-          break;
-       case 'e':                    /* exclude list */
-@@ -440,7 +445,7 @@
- /* Dummies to replace askdir.c */
- bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
--bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
-+bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
- bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
- bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
- bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
-diff -ur k1/src/stored/bscan.c k3/src/stored/bscan.c
---- k1/src/stored/bscan.c      2007-10-03 13:36:47.000000000 +0200
-+++ k3/src/stored/bscan.c      2007-12-22 19:11:05.000000000 +0100
-@@ -34,7 +34,7 @@
-  *   Kern E. Sibbald, December 2001
-  *
-  *
-- *   Version $Id: bscan.c 5713 2007-10-03 11:36:47Z kerns $
-+ *   Version $Id: bscan.c 5852 2007-11-04 19:57:42Z kerns $
-  */
- #include "bacula.h"
-@@ -116,7 +116,7 @@
- "Usage: bscan [ options ] <bacula-archive>\n"
- "       -b bootstrap      specify a bootstrap file\n"
- "       -c <file>         specify configuration file\n"
--"       -d <nn>           set debug level to nn\n"
-+"       -d <nn>           set debug level to <nn>\n"
- "       -m                update media info in database\n"
- "       -n <name>         specify the database name (default bacula)\n"
- "       -u <user>         specify database user name (default bacula)\n"
-@@ -166,9 +166,14 @@
-          break;
-       case 'd':                    /* debug level */
--         debug_level = atoi(optarg);
--         if (debug_level <= 0)
--            debug_level = 1;
-+         if (*optarg == 't') {
-+            dbg_timestamp = true;
-+         } else {
-+            debug_level = atoi(optarg);
-+            if (debug_level <= 0) {
-+               debug_level = 1;
-+            }
-+         }
-          break;
-       case 'h':
-@@ -1271,7 +1276,7 @@
- /* Dummies to replace askdir.c */
- bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
--bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
-+bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
- bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
- bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
- bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
-diff -ur k1/src/stored/btape.c k3/src/stored/btape.c
---- k1/src/stored/btape.c      2007-06-07 16:46:43.000000000 +0200
-+++ k3/src/stored/btape.c      2007-12-22 19:11:14.000000000 +0100
-@@ -37,7 +37,7 @@
-  *   Note, this program reads stored.conf, and will only
-  *     talk to devices that are configured.
-  *
-- *   Version $Id: btape.c 4992 2007-06-07 14:46:43Z kerns $
-+ *   Version $Id: btape.c 5852 2007-11-04 19:57:42Z kerns $
-  *
-  */
-@@ -220,9 +220,13 @@
-          break;
-       case 'd':                    /* set debug level */
--         debug_level = atoi(optarg);
--         if (debug_level <= 0) {
--            debug_level = 1;
-+         if (*optarg == 't') {
-+            dbg_timestamp = true;
-+         } else {
-+            debug_level = atoi(optarg);
-+            if (debug_level <= 0) {
-+               debug_level = 1;
-+            }
-          }
-          break;
-@@ -2598,7 +2602,7 @@
- "Usage: btape <options> <device_name>\n"
- "       -b <file>   specify bootstrap file\n"
- "       -c <file>   set configuration file to file\n"
--"       -d <nn>     set debug level to nn\n"
-+"       -d <nn>     set debug level to <nn>\n"
- "       -p          proceed inspite of I/O errors\n"
- "       -s          turn off signals\n"
- "       -v          be verbose\n"
-@@ -2644,7 +2648,7 @@
- bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
- bool    dir_send_job_status(JCR *jcr) {return 1;}
--bool dir_update_volume_info(DCR *dcr, bool relabel)
-+bool dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten)
- {
-    return 1;
- }
-diff -ur k1/src/stored/dev.c k3/src/stored/dev.c
---- k1/src/stored/dev.c        2007-12-02 19:03:17.000000000 +0100
-+++ k3/src/stored/dev.c        2007-12-22 19:11:57.000000000 +0100
-@@ -47,7 +47,7 @@
-  *     daemon. More complicated coding (double buffering, writer
-  *     thread, ...) is left for a later version.
-  *
-- *   Version $Id: dev.c 6011 2007-12-02 18:03:17Z kerns $
-+ *   Version $Id: dev.c 5999 2007-11-29 21:36:36Z ricozz $
-  */
- /*
-@@ -89,7 +89,7 @@
- /* Forward referenced functions */
- void set_os_device_parameters(DCR *dcr);   
- static bool dev_get_os_pos(DEVICE *dev, struct mtget *mt_stat);
--static char *mode_to_str(int mode);
-+static const char *mode_to_str(int mode);
- /*
-  * Allocate and initialize the DEVICE structure
-@@ -490,7 +490,7 @@
-       Mmsg2(errmsg, _("Could not open: %s, ERR=%s\n"), archive_name.c_str(), 
-             be.bstrerror());
-       Dmsg1(100, "open failed: %s", errmsg);
--      Emsg0(M_FATAL, 0, errmsg);
-+      Jmsg1(NULL, M_WARNING, 0, "%s", errmsg);
-    } else {
-       dev_errno = 0;
-       file = 0;
-@@ -2468,7 +2468,7 @@
-           mt_stat->mt_fileno >= 0;
- }
--static char *modes[] = {
-+static const char *modes[] = {
-    "CREATE_READ_WRITE",
-    "OPEN_READ_WRITE",
-    "OPEN_READ_ONLY",
-@@ -2476,7 +2476,7 @@
- };
--static char *mode_to_str(int mode)  
-+static const char *mode_to_str(int mode)  
- {
-    static char buf[100];
-    if (mode < 1 || mode > 4) {
-diff -ur k1/src/stored/dev.h k3/src/stored/dev.h
---- k1/src/stored/dev.h        2007-09-09 12:03:23.000000000 +0200
-+++ k3/src/stored/dev.h        2007-12-22 19:12:14.000000000 +0100
-@@ -31,7 +31,7 @@
-  *
-  * Kern Sibbald, MM
-  *
-- *   Version $Id: dev.h 5503 2007-09-09 10:03:23Z kerns $
-+ *   Version $Id: dev.h 5852 2007-11-04 19:57:42Z kerns $
-  *
-  */
-@@ -158,6 +158,7 @@
-    btime_t  VolWriteTime;             /* time spent writing this Volume */
-    int64_t  VolMediaId;               /* MediaId */
-    utime_t  VolFirstWritten;          /* Time of first write */
-+   utime_t  VolLastWritten;           /* Time of last write */
-    bool     InChanger;                /* Set if vol in current magazine */
-    char VolCatStatus[20];             /* Volume status */
-    char VolCatName[MAX_NAME_LENGTH];  /* Desired volume to mount */
-@@ -473,8 +474,9 @@
- class VOLRES { 
- public:
-    dlink link;
--   char *vol_name;
--   DEVICE *dev;
-+   char *vol_name;                    /* Volume name */
-+   DEVICE *dev;                       /* Pointer to device to which we are attached */
-+   bool released;                     /* set when the Volume can be released */
- };
-diff -ur k1/src/stored/device.c k3/src/stored/device.c
---- k1/src/stored/device.c     2007-06-29 14:12:26.000000000 +0200
-+++ k3/src/stored/device.c     2007-12-22 19:11:23.000000000 +0100
-@@ -53,7 +53,7 @@
-  *
-  *   Kern Sibbald, MM, MMI
-  *
-- *   Version $Id: device.c 5114 2007-06-29 12:12:26Z kerns $
-+ *   Version $Id: device.c 5852 2007-11-04 19:57:42Z kerns $
-  */
- #include "bacula.h"                   /* pull in global headers */
-@@ -122,7 +122,8 @@
-         edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2),
-         bstrftime(dt, sizeof(dt), time(NULL)));
--   if (!mount_next_write_volume(dcr, 1)) {
-+   /* Called with have_vol=false, release=true */
-+   if (!mount_next_write_volume(dcr, false, true)) {
-       free_block(label_blk);
-       dcr->block = block;
-       dev->dlock();  
-@@ -131,7 +132,7 @@
-    dev->dlock();                    /* lock again */
-    dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs on vol */
--   dir_update_volume_info(dcr, false);        /* send Volume info to Director */
-+   dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
-    Jmsg(jcr, M_INFO, 0, _("New volume \"%s\" mounted on device %s at %s.\n"),
-       dcr->VolumeName, dev->print_name(), bstrftime(dt, sizeof(dt), time(NULL)));
-diff -ur k1/src/stored/dvd.c k3/src/stored/dvd.c
---- k1/src/stored/dvd.c        2007-06-07 16:46:43.000000000 +0200
-+++ k3/src/stored/dvd.c        2007-12-22 19:26:23.000000000 +0100
-@@ -1,16 +1,7 @@
- /*
-- *
-- *   dvd.c  -- Routines specific to DVD devices (and
-- *             possibly other removable hard media). 
-- *
-- *    Nicolas Boichat, MMV
-- *
-- *   Version $Id: dvd.c 4992 2007-06-07 14:46:43Z kerns $
-- */
--/*
-    Bacula® - The Network Backup Solution
--   Copyright (C) 2005-2006 Free Software Foundation Europe e.V.
-+   Copyright (C) 2005-2007 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.
-@@ -34,6 +25,15 @@
-    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
-    Switzerland, email:ftf@fsfeurope.org.
- */
-+/*
-+ *
-+ *   dvd.c  -- Routines specific to DVD devices (and
-+ *             possibly other removable hard media). 
-+ *
-+ *    Nicolas Boichat, MMV
-+ *
-+ *   Version $Id: dvd.c 5852 2007-11-04 19:57:42Z kerns $
-+ */
- #include "bacula.h"
- #include "stored.h"
-@@ -686,7 +686,7 @@
-    dcr->VolCatInfo.VolCatBytes = 0;
-    /* Update catalog */
--   if (!dir_update_volume_info(dcr, false)) {
-+   if (!dir_update_volume_info(dcr, false, true)) {
-       return false;
-    }
-    
-diff -ur k1/src/stored/job.c k3/src/stored/job.c
---- k1/src/stored/job.c        2007-09-29 00:01:16.000000000 +0200
-+++ k3/src/stored/job.c        2007-12-22 19:11:41.000000000 +0100
-@@ -30,7 +30,7 @@
-  *
-  *   Kern Sibbald, MM
-  *
-- *   Version $Id: job.c 5686 2007-09-28 22:01:16Z kerns $
-+ *   Version $Id: job.c 5697 2007-09-30 17:40:08Z ricozz $
-  *
-  */
-@@ -49,9 +49,13 @@
- /* Requests from the Director daemon */
- static char jobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s "
-       "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s "
-+      "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d SpoolSize=%s\n";
-+static char oldjobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s "
-+      "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s "
-       "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d\n";
-+
- /* Responses sent to Director daemon */
- static char OKjob[]     = "3000 OK Job SDid=%u SDtime=%u Authorization=%s\n";
- static char BAD_job[]   = "3915 Bad Job command. stat=%d CMD: %s\n";
-@@ -73,6 +77,7 @@
- {
-    int JobId;
-    char auth_key[100];
-+   char spool_size[30];
-    char seed[100];
-    BSOCK *dir = jcr->dir_bsock;
-    POOL_MEM job_name, client_name, job, fileset_name, fileset_md5;
-@@ -85,17 +90,26 @@
-     * Get JobId and permissions from Director
-     */
-    Dmsg1(100, "<dird: %s", dir->msg);
-+   bstrncpy(spool_size, "0", sizeof(spool_size));
-    stat = sscanf(dir->msg, jobcmd, &JobId, job.c_str(), job_name.c_str(),
-               client_name.c_str(),
-               &JobType, &level, fileset_name.c_str(), &no_attributes,
--              &spool_attributes, fileset_md5.c_str(), &spool_data, 
-+              &spool_attributes, fileset_md5.c_str(), &spool_data,
-+              &write_part_after_job, &PreferMountedVols, spool_size);
-+   if (stat != 14) {
-+      /* Try old version */
-+      stat = sscanf(dir->msg, oldjobcmd, &JobId, job.c_str(), job_name.c_str(),
-+              client_name.c_str(),
-+              &JobType, &level, fileset_name.c_str(), &no_attributes,
-+              &spool_attributes, fileset_md5.c_str(), &spool_data,
-               &write_part_after_job, &PreferMountedVols);
--   if (stat != 13) {
--      pm_strcpy(jcr->errmsg, dir->msg);
--      dir->fsend(BAD_job, stat, jcr->errmsg);
--      Dmsg1(100, ">dird: %s", dir->msg);
--      set_jcr_job_status(jcr, JS_ErrorTerminated);
--      return false;
-+      if (stat != 13) {
-+         pm_strcpy(jcr->errmsg, dir->msg);
-+         dir->fsend(BAD_job, stat, jcr->errmsg);
-+         Dmsg1(100, ">dird: %s", dir->msg);
-+         set_jcr_job_status(jcr, JS_ErrorTerminated);
-+         return false;
-+      }
-    }
-    /*
-     * Since this job could be rescheduled, we
-@@ -125,6 +139,7 @@
-    jcr->no_attributes = no_attributes;
-    jcr->spool_attributes = spool_attributes;
-    jcr->spool_data = spool_data;
-+   jcr->spool_size = str_to_int64(spool_size);
-    jcr->write_part_after_job = write_part_after_job;
-    jcr->fileset_md5 = get_pool_memory(PM_NAME);
-    pm_strcpy(jcr->fileset_md5, fileset_md5);
-diff -ur k1/src/stored/label.c k3/src/stored/label.c
---- k1/src/stored/label.c      2007-10-03 13:36:47.000000000 +0200
-+++ k3/src/stored/label.c      2007-12-22 19:10:49.000000000 +0100
-@@ -32,7 +32,7 @@
-  *   Kern Sibbald, MM
-  *
-  *
-- *   Version $Id: label.c 5713 2007-10-03 11:36:47Z kerns $
-+ *   Version $Id: label.c 5852 2007-11-04 19:57:42Z kerns $
-  */
- #include "bacula.h"                   /* pull in global headers */
-@@ -505,7 +505,7 @@
-    }
-    Dmsg0(150, "dir_update_vol_info. Set Append\n");
-    bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
--   if (!dir_update_volume_info(dcr, true)) {  /* indicate doing relabel */
-+   if (!dir_update_volume_info(dcr, true, true)) {  /* indicate doing relabel */
-       return false;
-    }
-    if (recycle) {
-@@ -716,7 +716,7 @@
-       }
-       break;
-    default:
--      Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
-+      Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label = %d\n"), label);
-       break;
-    }
-    create_session_label(dcr, rec, label);
-diff -ur k1/src/stored/mount.c k3/src/stored/mount.c
---- k1/src/stored/mount.c      2007-09-14 11:49:06.000000000 +0200
-+++ k3/src/stored/mount.c      2007-12-22 19:11:30.000000000 +0100
-@@ -32,7 +32,7 @@
-  *
-  *   Kern Sibbald, August MMII
-  *
-- *   Version $Id: mount.c 5552 2007-09-14 09:49:06Z kerns $
-+ *   Version $Id: mount.c 5852 2007-11-04 19:57:42Z kerns $
-  */
- #include "bacula.h"                   /* pull in global headers */
-@@ -60,7 +60,7 @@
-  *  impossible to get the requested Volume.
-  *
-  */
--bool mount_next_write_volume(DCR *dcr, bool release)
-+bool mount_next_write_volume(DCR *dcr, bool have_vol, bool release)
- {
-    int retry = 0;
-    bool ask = false, recycle, autochanger;
-@@ -108,12 +108,16 @@
-     *    in dcr->VolCatInfo
-     */
-    Dmsg0(200, "Before dir_find_next_appendable_volume.\n");
--   while (!dir_find_next_appendable_volume(dcr)) {
--       Dmsg0(200, "not dir_find_next\n");
--       if (!dir_ask_sysop_to_create_appendable_volume(dcr)) {
--         return false;
-+   if (!have_vol) {
-+      while (!dir_find_next_appendable_volume(dcr)) {
-+         Dmsg0(200, "not dir_find_next\n");
-+         if (!dir_ask_sysop_to_create_appendable_volume(dcr)) {
-+            return false;
-+          }
-+          Dmsg0(200, "Again dir_find_next_append...\n");
-        }
--       Dmsg0(200, "Again dir_find_next_append...\n");
-+   } else {
-+      have_vol = false;               /* set false for next pass if any */
-    }
-    if (job_canceled(jcr)) {
-       return false;
-@@ -144,7 +148,7 @@
-     * If we autochanged to correct Volume or (we have not just
-     *   released the Volume AND we can automount) we go ahead
-     *   and read the label. If there is no tape in the drive,
--    *   we will err, recurse and ask the operator the next time.
-+    *   we will fail, recurse and ask the operator the next time.
-     */
-    if (!release && dev->is_tape() && dev->has_cap(CAP_AUTOMOUNT)) {
-       Dmsg0(150, "(1)Ask=0\n");
-@@ -432,7 +436,7 @@
-       }
-       dev->VolCatInfo.VolCatMounts++;      /* Update mounts */
-       Dmsg1(150, "update volinfo mounts=%d\n", dev->VolCatInfo.VolCatMounts);
--      if (!dir_update_volume_info(dcr, false)) {
-+      if (!dir_update_volume_info(dcr, false, false)) {
-          return false;
-       }
-       
-@@ -519,7 +523,7 @@
-       Dmsg0(150, "dir_update_vol_info. Set Append\n");
-       /* Copy Director's info into the device info */
-       dev->VolCatInfo = dcr->VolCatInfo;    /* structure assignment */
--      if (!dir_update_volume_info(dcr, true)) {  /* indicate tape labeled */
-+      if (!dir_update_volume_info(dcr, true, true)) {  /* indicate tape labeled */
-          return try_error;
-       }
-       Jmsg(dcr->jcr, M_INFO, 0, _("Labeled new Volume \"%s\" on device %s.\n"),
-@@ -552,7 +556,7 @@
-    dev->VolCatInfo = dcr->VolCatInfo;     /* structure assignment */
-    bstrncpy(dev->VolCatInfo.VolCatStatus, "Error", sizeof(dev->VolCatInfo.VolCatStatus));
-    Dmsg0(150, "dir_update_vol_info. Set Error.\n");
--   dir_update_volume_info(dcr, false);
-+   dir_update_volume_info(dcr, false, false);
- }
- /*
-@@ -570,7 +574,7 @@
-    dcr->VolCatInfo.InChanger = false;
-    dev->VolCatInfo.InChanger = false;
-    Dmsg0(400, "update vol info in mount\n");
--   dir_update_volume_info(dcr, true);  /* set new status */
-+   dir_update_volume_info(dcr, true, false);  /* set new status */
- }
- /*
-@@ -588,6 +592,7 @@
-    /*
-     * First erase all memory of the current volume
-     */
-+   free_volume(dev);
-    dev->block_num = dev->file = 0;
-    dev->EndBlock = dev->EndFile = 0;
-    memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo));
-diff -ur k1/src/stored/protos.h k3/src/stored/protos.h
---- k1/src/stored/protos.h     2007-06-28 13:57:03.000000000 +0200
-+++ k3/src/stored/protos.h     2007-12-22 19:12:43.000000000 +0100
-@@ -28,7 +28,7 @@
- /*
-  * Protypes for stored -- Kern Sibbald MM  
-  *
-- *   Version $Id: protos.h 5112 2007-06-28 11:57:03Z kerns $
-+ *   Version $Id: protos.h 5852 2007-11-04 19:57:42Z kerns $
-  */
- /* From stored.c */
-@@ -49,7 +49,7 @@
- };
- bool    dir_get_volume_info(DCR *dcr, enum get_vol_info_rw);
- bool    dir_find_next_appendable_volume(DCR *dcr);
--bool    dir_update_volume_info(DCR *dcr, bool label);
-+bool    dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten);
- bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr);
- bool    dir_ask_sysop_to_mount_volume(DCR *dcr);
- bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec);
-@@ -182,7 +182,7 @@
- bool     is_this_bsr_done(BSR *bsr, DEV_RECORD *rec);
- /* From mount.c */
--bool     mount_next_write_volume(DCR *dcr, bool release);
-+bool     mount_next_write_volume(DCR *dcr, bool have_vol, bool release);
- bool     mount_next_read_volume(DCR *dcr);
- void     mark_volume_in_error(DCR *dcr);
-diff -ur k1/src/stored/record.c k3/src/stored/record.c
---- k1/src/stored/record.c     2007-06-07 16:46:43.000000000 +0200
-+++ k3/src/stored/record.c     2007-12-22 19:12:06.000000000 +0100
-@@ -1,14 +1,4 @@
- /*
-- *
-- *   record.c -- tape record handling functions
-- *
-- *              Kern Sibbald, April MMI
-- *                added BB02 format October MMII
-- *
-- *   Version $Id: record.c 4992 2007-06-07 14:46:43Z kerns $
-- *
-- */
--/*
-    Bacula® - The Network Backup Solution
-    Copyright (C) 2001-2006 Free Software Foundation Europe e.V.
-@@ -35,6 +25,16 @@
-    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
-    Switzerland, email:ftf@fsfeurope.org.
- */
-+/*
-+ *
-+ *   record.c -- tape record handling functions
-+ *
-+ *              Kern Sibbald, April MMI
-+ *                added BB02 format October MMII
-+ *
-+ *   Version $Id: record.c 6014 2007-12-03 18:14:27Z kerns $
-+ *
-+ */
- #include "bacula.h"
-@@ -254,7 +254,7 @@
-    ASSERT(block->buf_len >= block->binbuf);
-    Dmsg6(890, "write_record_to_block() FI=%s SessId=%d Strm=%s len=%d\n"
--"rem=%d remainder=%d\n",
-+      "rem=%d remainder=%d\n",
-       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
-       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
-       remlen, rec->remainder);
-@@ -365,7 +365,7 @@
-          if (!sm_check_rtn(__FILE__, __LINE__, False)) {
-             /* We damaged a buffer */
-             Dmsg6(0, "Damaged block FI=%s SessId=%d Strm=%s len=%d\n"
--"rem=%d remainder=%d\n",
-+               "rem=%d remainder=%d\n",
-                FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
-                stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
-                remlen, rec->remainder);
-diff -ur k1/src/stored/reserve.c k3/src/stored/reserve.c
---- k1/src/stored/reserve.c    2007-08-04 18:46:32.000000000 +0200
-+++ k3/src/stored/reserve.c    2007-12-22 19:09:56.000000000 +0100
-@@ -212,11 +212,11 @@
-       if (dev) {
-          len = Mmsg(msg, "%s on device %s\n", vol->vol_name, dev->print_name());
-          sendit(msg.c_str(), len, arg);
--         len = Mmsg(msg, "    Reader=%d writers=%d reserved=%d\n", dev->can_read()?1:0,
--            dev->num_writers, dev->reserved_device);
-+         len = Mmsg(msg, "    Reader=%d writers=%d reserved=%d released=%d\n", 
-+            dev->can_read()?1:0, dev->num_writers, dev->reserved_device, vol->released);
-          sendit(msg.c_str(), len, arg);
-       } else {
--         len = Mmsg(msg, "%s no dev\n", vol->vol_name);
-+         len = Mmsg(msg, "%s no device. released=%d\n", vol->vol_name, vol->released);
-          sendit(msg.c_str(), len, arg);
-       }
-    }
-@@ -292,11 +292,11 @@
-  *  already exist and are correctly programmed and will need no changes -- use 
-  *  counts are always very tricky.
-  *
-- *  The old code had a concept of "reserving" a Volume, but it needs to be changed 
-+ *  The old code had a concept of "reserving" a Volume, but was changed 
-  *  to reserving and using a drive.  A volume is must be attached to (owned by) a 
-  *  drive and can move from drive to drive or be unused given certain specific 
-  *  conditions of the drive.  The key is that the drive must "own" the Volume.  
-- *  The old code has the job (dcr) owning the volume (more or less).  The job is 
-+ *  The old code had the job (dcr) owning the volume (more or less).  The job was
-  *  to change the insertion and removal of the volumes from the list to be based 
-  *  on the drive rather than the job.  
-  *
-@@ -329,13 +329,14 @@
-        *  because it was probably inserted by another job.
-        */
-       if (strcmp(vol->vol_name, VolumeName) == 0) {
-+         Dmsg1(dbglvl, "OK, vol=%s on device.\n", VolumeName);
-          goto get_out;                  /* Volume already on this device */
-       } else {
--         Dmsg3(dbglvl, "jid=%u reserve_vol free vol=%s at %p\n", 
-+         Dmsg3(dbglvl, "jid=%u reserve_vol free vol=%s at %p\n",
-                (int)dcr->jcr->JobId, vol->vol_name, vol->vol_name);
--         debug_list_volumes("reserve_vol free");
-          vol_list->remove(vol);
-          free_vol_item(vol);
-+         debug_list_volumes("reserve_vol free");
-       }
-    }
-@@ -378,12 +379,16 @@
-             Dmsg4(dbglvl, "jid=%u Volume busy could not swap vol=%s from dev=%s to %s\n", 
-                jid(), VolumeName, vol->dev->print_name(), dev->print_name());
-             vol = NULL;                /* device busy */
-+            goto get_out;
-          }
-       }
-    }
-    dev->vol = vol;
- get_out:
-+   if (vol) {
-+      vol->released = false;
-+   }
-    debug_list_volumes("end new volume");
-    unlock_volumes();
-    return vol;
-@@ -462,6 +467,7 @@
-     *  explicitly read in this drive. This allows the SD to remember
-     *  where the tapes are or last were.
-     */
-+   dev->vol->released = true;
-    if (dev->is_tape() || dev->is_autochanger()) {
-       return true;
-    } else {
-@@ -837,6 +843,7 @@
-       dlist *temp_vol_list, *save_vol_list;
-       VOLRES *vol = NULL;
-       lock_volumes();
-+      Dmsg0(dbglvl, "lock volumes\n");                           
-       /*  
-        * Create a temporary copy of the volume list.  We do this,
-@@ -1122,6 +1129,26 @@
-              */
-             if (dcr->volume_in_use && !rctx.PreferMountedVols) {
-                rctx.PreferMountedVols = true;
-+               if (dcr->VolumeName[0]) {
-+                  volume_unused(dcr);
-+               }
-+               goto bail_out;
-+            }
-+            /*
-+             * Note. Under some circumstances, the Director can hand us
-+             *  a Volume name that is no the same as the one on the current
-+             *  drive, and in that case, the call above to find the next
-+             *  volume will fail because in attempting to reserve the Volume
-+             *  the code will realize that we already have a tape mounted,
-+             *  and it will fail.  This *should* only happen if there are 
-+             *  writers, thus the following test.  In that case, we simply
-+             *  bail out, and continue waiting, rather than plunging on
-+             *  and hoping that the operator can resolve the problem. 
-+             */
-+            if (dcr->dev->num_writers != 0) {
-+               if (dcr->VolumeName[0]) {
-+                  volume_unused(dcr);
-+               }
-                goto bail_out;
-             }
-          }
-@@ -1270,6 +1297,51 @@
-    return ok;
- }
-+static int is_pool_ok(DCR *dcr)
-+{
-+   DEVICE *dev = dcr->dev;
-+   JCR *jcr = dcr->jcr;
-+
-+   /* Now check if we want the same Pool and pool type */
-+   if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
-+       strcmp(dev->pool_type, dcr->pool_type) == 0) {
-+      /* OK, compatible device */
-+      Dmsg1(dbglvl, "OK dev: %s num_writers=0, reserved, pool matches\n", dev->print_name());
-+      return 1;
-+   } else {
-+      /* Drive Pool not suitable for us */
-+      Mmsg(jcr->errmsg, _(
-+"3608 JobId=%u wants Pool=\"%s\" but have Pool=\"%s\" nreserve=%d on drive %s.\n"), 
-+            (uint32_t)jcr->JobId, dcr->pool_name, dev->pool_name,
-+            dev->reserved_device, dev->print_name());
-+      queue_reserve_message(jcr);
-+      Dmsg2(dbglvl, "failed: busy num_writers=0, reserved, pool=%s wanted=%s\n",
-+         dev->pool_name, dcr->pool_name);
-+   }
-+   return 0;
-+}
-+
-+static bool is_max_jobs_ok(DCR *dcr) 
-+{
-+   DEVICE *dev = dcr->dev;
-+   JCR *jcr = dcr->jcr;
-+
-+   Dmsg4(dbglvl, "MaxJobs=%d Jobs=%d reserves=%d Vol=%s\n",
-+         dcr->VolCatInfo.VolCatMaxJobs,
-+         dcr->VolCatInfo.VolCatJobs, dev->reserved_device,
-+         dcr->VolumeName);
-+   if (dcr->VolCatInfo.VolCatMaxJobs > 0 && dcr->VolCatInfo.VolCatMaxJobs <=
-+        (dcr->VolCatInfo.VolCatJobs + dev->reserved_device)) {
-+      /* Max Job Vols depassed or already reserved */
-+      Mmsg(jcr->errmsg, _("3610 JobId=%u Volume max jobs exceeded on drive %s.\n"), 
-+            (uint32_t)jcr->JobId, dev->print_name());
-+      queue_reserve_message(jcr);
-+      Dmsg1(dbglvl, "reserve dev failed: %s", jcr->errmsg);
-+      return false;                /* wait */
-+   }
-+   return true;
-+}
-+
- /*
-  * Returns: 1 if drive can be reserved
-  *          0 if we should wait
-@@ -1285,6 +1357,11 @@
-          rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
-          rctx.autochanger_only, rctx.any_drive);
-+   /* Check for max jobs on this Volume */
-+   if (!is_max_jobs_ok(dcr)) {
-+      return 0;
-+   }
-+
-    /* setting any_drive overrides PreferMountedVols flag */
-    if (!rctx.any_drive) {
-       /*
-@@ -1374,32 +1451,10 @@
-    if (dev->num_writers == 0) {
-       /* Now check if there are any reservations on the drive */
-       if (dev->reserved_device) {           
--         /* Now check if we want the same Pool and pool type */
--         if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
--             strcmp(dev->pool_type, dcr->pool_type) == 0) {
--            /* OK, compatible device */
--            Dmsg2(dbglvl, "jid=%u OK dev: %s num_writers=0, reserved, pool matches\n",
--               jcr->JobId, dev->print_name());
--            return 1;
--         } else {
--            /* Drive Pool not suitable for us */
--            Mmsg(jcr->errmsg, _(
--"3608 JobId=%u wants Pool=\"%s\" but have Pool=\"%s\" nreserve=%d on drive %s.\n"), 
--                  jcr->JobId, dcr->pool_name, dev->pool_name,
--                  dev->reserved_device, dev->print_name());
--            queue_reserve_message(jcr);
--            Dmsg3(dbglvl, "jid=%u failed: busy num_writers=0, reserved, pool=%s wanted=%s\n",
--               (int)jcr->JobId, dev->pool_name, dcr->pool_name);
--            return 0;                 /* wait */
--         }
-+         return is_pool_ok(dcr);
-       } else if (dev->can_append()) {
--         /* Device in append mode, check if changing pool */
--         if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
--             strcmp(dev->pool_type, dcr->pool_type) == 0) {
--            Dmsg2(dbglvl, "jid=%u OK dev: %s num_writers=0, can_append, pool matches.\n",
--               jcr->JobId, dev->print_name());
--            /* OK, compatible device */
--            return 1;
-+         if (is_pool_ok(dcr)) {
-+            return 1; 
-          } else {
-             /* Changing pool, unload old tape if any in drive */
-             Dmsg1(dbglvl, "jid=%u OK dev: num_writers=0, not reserved, pool change, unload changer\n",
-@@ -1419,22 +1474,7 @@
-     *  available if pool is the same).
-     */
-    if (dev->can_append() || dev->num_writers > 0) {
--      /* Yes, now check if we want the same Pool and pool type */
--      if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
--          strcmp(dev->pool_type, dcr->pool_type) == 0) {
--         Dmsg2(dbglvl, "jid=%u OK dev: %s num_writers>=0, can_append, pool matches.\n",
--            jcr->JobId, dev->print_name());
--         /* OK, compatible device */
--         return 1;
--      } else {
--         /* Drive Pool not suitable for us */
--         Mmsg(jcr->errmsg, _("3609 JobId=%u wants Pool=\"%s\" but has Pool=\"%s\" on drive %s.\n"), 
--               jcr->JobId, dcr->pool_name, dev->pool_name, dev->print_name());
--         queue_reserve_message(jcr);
--         Dmsg3(dbglvl, "jid=%u failed: busy num_writers>0, can_append, pool=%s wanted=%s\n",
--            (int)jcr->JobId, dev->pool_name, dcr->pool_name);
--         return 0;                    /* wait */
--      }
-+      return is_pool_ok(dcr);
-    } else {
-       Pmsg1(000, _("Logic error!!!! JobId=%u Should not get here.\n"), (int)jcr->JobId);
-       Mmsg(jcr->errmsg, _("3910 JobId=%u Logic error!!!! drive %s Should not get here.\n"),
diff --git a/bacula/patches/2.2.x/2.2.7-fpformat.patch b/bacula/patches/2.2.x/2.2.7-fpformat.patch
new file mode 100644 (file)
index 0000000..c022627
--- /dev/null
@@ -0,0 +1,120 @@
+
+ This patch fixes a float point editing bug introduced in 2.2.7 (I think)
+ causing the rate fields to be formated incorrectly (actually trunctated).
+ This fixes bug #1036.
+
+ Apply it to version 2.2.7 with:
+
+ cd <bacula-source>
+ patch -p0 <2.2.7-fpformat.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+
+Index: src/lib/bsnprintf.c
+===================================================================
+--- src/lib/bsnprintf.c        (revision 6183)
++++ src/lib/bsnprintf.c        (working copy)
+@@ -16,7 +16,7 @@
+ /*
+    Bacula® - The Network Backup Solution
+-   Copyright (C) 2005-2007 Free Software Foundation Europe e.V.
++   Copyright (C) 2005-2008 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.
+@@ -566,11 +566,11 @@
+    return result;
+ }
+-static long round(LDOUBLE value)
++static int64_t round(LDOUBLE value)
+ {
+-   long intpart;
++   int64_t intpart;
+-   intpart = (long)value;
++   intpart = (int64_t)value;
+    value = value - intpart;
+    if (value >= 0.5)
+       intpart++;
+@@ -584,8 +584,8 @@
+    int signvalue = 0;
+    LDOUBLE ufvalue;
+ #ifndef HAVE_FCVT
+-   char iconvert[25];
+-   char fconvert[25];
++   char iconvert[311];
++   char fconvert[311];
+ #else
+    char iconvert[311];
+    char fconvert[311];
+@@ -602,6 +602,7 @@
+    int caps = 0;
+    int64_t intpart;
+    int64_t fracpart;
++   const char *cvt_str;
+    /* 
+     * AIX manpage says the default is 0, but Solaris says the default
+@@ -625,7 +626,7 @@
+ #endif
+ #ifndef HAVE_FCVT
+-   intpart = (long)ufvalue;
++   intpart = (int64_t)ufvalue;
+    /* 
+     * Sorry, we only support 9 digits past the decimal because of our 
+@@ -645,28 +646,30 @@
+    }
+ #ifdef DEBUG_SNPRINTF
+-   printf("fmtfp: %g %d.%d min=%d max=%d\n",
++   printf("fmtfp: %g %lld.%lld min=%d max=%d\n",
+           (double)fvalue, intpart, fracpart, min, max);
+ #endif
+    /* Convert integer part */
++   cvt_str = caps ? "0123456789ABCDEF" : "0123456789abcdef";
+    do {
+-      iconvert[iplace++] =
+-         (caps ? "0123456789ABCDEF" : "0123456789abcdef")[intpart % 10];
++      iconvert[iplace++] = cvt_str[(int)(intpart % 10)];
+       intpart = (intpart / 10);
+-   } while (intpart && (iplace < (int)sizeof(iplace)));
+-   if (iplace == (int)sizeof(iplace)) {
++   } while (intpart && (iplace < (int)sizeof(iconvert)));
++
++   if (iplace == (int)sizeof(fconvert)) {
+       iplace--;
+    }
+    iconvert[iplace] = 0;
+    /* Convert fractional part */
++   cvt_str = caps ? "0123456789ABCDEF" : "0123456789abcdef";
+    do {
+-      fconvert[fplace++] =
+-         (caps ? "0123456789ABCDEF" : "0123456789abcdef")[fracpart % 10];
++      fconvert[fplace++] = cvt_str[fracpart % 10];
+       fracpart = (fracpart / 10);
+-   } while (fracpart && (fplace < (int)sizeof(fplace)));
+-   if (fplace == (int)sizeof(fplace)) {
++   } while (fracpart && (fplace < (int)sizeof(fconvert)));
++
++   if (fplace == (int)sizeof(fconvert)) {
+       fplace--;
+    }
+    fconvert[fplace] = 0;
+@@ -825,7 +828,7 @@
+       NULL
+    };
+    double fp_nums[] = { -1.5, 134.21, 91340.2, 341.1234, 0203.9, 0.96, 0.996,
+-      0.9996, 1.996, 4.136, 6442452944.1234, 0
++      0.9996, 1.996, 4.136, 6442452944.1234, 0, 23365.5
+    };
+ #endif
+    char *int_fmt[] = {
diff --git a/bacula/patches/2.2.x/2.2.7-jobdefs-migtype.patch b/bacula/patches/2.2.x/2.2.7-jobdefs-migtype.patch
new file mode 100644 (file)
index 0000000..c636dd6
--- /dev/null
@@ -0,0 +1,56 @@
+
+ This patch permits to use migration options with JobDefs.
+ This patch fixes bug #1028.
+
+ Apply the patch to 2.2.7 (and possibly any 2.2.x version with):
+
+ cd <bacula-source>
+ patch -p0 <2.2.7-jobdefs-migtype.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+Index: src/dird/dird.c
+===================================================================
+--- src/dird/dird.c    (revision 6183)
++++ src/dird/dird.c    (working copy)
+@@ -58,6 +58,7 @@
+ void store_jobtype(LEX *lc, RES_ITEM *item, int index, int pass);
+ void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
+ void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
++void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
+ void init_device_resources();
+ static char *runjob = NULL;
+@@ -698,6 +699,7 @@
+                           job_items[i].handler == store_jobtype ||
+                           job_items[i].handler == store_level   ||
+                           job_items[i].handler == store_pint    ||
++                          job_items[i].handler == store_migtype ||
+                           job_items[i].handler == store_replace) {
+                   def_ivalue = (int *)((char *)(job->jobdefs) + offset);
+                   Dmsg5(400, "Job \"%s\", field \"%s\" def_ivalue=%d item %d offset=%u\n",
+Index: src/dird/dird_conf.c
+===================================================================
+--- src/dird/dird_conf.c       (revision 6183)
++++ src/dird/dird_conf.c       (working copy)
+@@ -74,8 +74,8 @@
+ void store_level(LEX *lc, RES_ITEM *item, int index, int pass);
+ void store_replace(LEX *lc, RES_ITEM *item, int index, int pass);
+ void store_acl(LEX *lc, RES_ITEM *item, int index, int pass);
++void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
+ static void store_device(LEX *lc, RES_ITEM *item, int index, int pass);
+-static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass);
+ static void store_runscript(LEX *lc, RES_ITEM *item, int index, int pass);
+ static void store_runscript_when(LEX *lc, RES_ITEM *item, int index, int pass);
+ static void store_runscript_cmd(LEX *lc, RES_ITEM *item, int index, int pass);
+@@ -1548,7 +1548,7 @@
+  * Store JobType (backup, verify, restore)
+  *
+  */
+-static void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
++void store_migtype(LEX *lc, RES_ITEM *item, int index, int pass)
+ {
+    int token, i;
diff --git a/bacula/patches/2.2.x/2.2.7-mysql-batch-timeout.patch b/bacula/patches/2.2.x/2.2.7-mysql-batch-timeout.patch
new file mode 100644 (file)
index 0000000..fafb85d
--- /dev/null
@@ -0,0 +1,30 @@
+
+ This patch fixes bug #1034 about Temporary MySQL table 'batch' 
+ disappears if MySQL connection times out.
+
+ Apply the patch to 2.2.7 (and possibly any 2.2.x version with):
+
+ cd <bacula-source>
+ patch -p0 <2.2.7-mysql-batch-timeout.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+
+
+Index: src/cats/mysql.c
+===================================================================
+--- src/cats/mysql.c   (révision 6192)
++++ src/cats/mysql.c   (copie de travail)
+@@ -205,6 +205,10 @@
+    Dmsg3(100, "opendb ref=%d connected=%d db=%p\n", mdb->ref_count,
+          mdb->connected, mdb->db);
++   /* Set connection timeout to 8 days specialy for batch mode */
++   sql_query(mdb, "SET wait_timeout=691200");
++   sql_query(mdb, "SET interactive_timeout=691200");
++
+    V(mutex);
+    return 1;
+ }
diff --git a/bacula/patches/2.2.x/2.2.7-old-postgresql.patch b/bacula/patches/2.2.x/2.2.7-old-postgresql.patch
new file mode 100644 (file)
index 0000000..d13b118
--- /dev/null
@@ -0,0 +1,26 @@
+
+ If you have an old version of PostgreSQL, for example,
+ version 7.3 or older, it may not properly build with the current
+ Bacula release due to incompatible changes in the PostgreSQL
+ header files between version.  Only in the case that build fails,
+ you might try applying this patch with:
+
+ cd <bacula-2.2.7-source>
+ patch -p1 <2.2.7-old-postgresql.patch
+ ./configure <your-options>
+ make
+ ...
+ make install
+
+
+diff -uNr bacula-2.2.7/src/cats/postgresql.c bacula-2.2.7-fixed/src/cats/postgresql.c
+--- bacula-2.2.7/src/cats/postgresql.c 2007-12-08 04:54:55.000000000 -0500
++++ bacula-2.2.7-fixed/src/cats/postgresql.c   2007-12-29 08:34:10.000000000 -0500
+@@ -47,7 +47,6 @@
+ #ifdef HAVE_POSTGRESQL
+ #include "postgres_ext.h"       /* needed for NAMEDATALEN */
+-#include "pg_config_manual.h"   /* get NAMEDATALEN on version 8.3 or later */
+ /* -----------------------------------------------------------------------
+  *
diff --git a/bacula/patches/2.2.x/2.2.7-reserve.patch b/bacula/patches/2.2.x/2.2.7-reserve.patch
new file mode 100644 (file)
index 0000000..42daad1
--- /dev/null
@@ -0,0 +1,1467 @@
+
+ This patch has a number of cleanups and improvements to the SD          
+ reservations system. It should fix a number of problems with
+ dual drive autochangers as well ensure that volume use durations
+ and max volume jobs are better respected.
+
+ Apply it to version 2.2.7 (possibly some earlier versions) with:
+
+ cd <bacula-source>
+ patch -p1 <2.2.7-reserve.patch
+ ./configure <your options>
+ make
+ ...
+ make install
+
+
+diff -ur k1/src/lib/message.c k3/src/lib/message.c
+--- k1/src/lib/message.c       2007-10-19 13:47:58.000000000 +0200
++++ k3/src/lib/message.c       2007-12-22 19:13:00.000000000 +0100
+@@ -54,6 +54,7 @@
+ int verbose = 0;                      /* increase User messages */
+ /* Keep debug level set to zero by default */
+ int debug_level = 0;                  /* debug level */
++bool dbg_timestamp = false;           /* print timestamp in debug output */
+ time_t daemon_start_time = 0;         /* Daemon start time */
+ const char *version = VERSION " (" BDATE ")";
+ char my_name[30];                     /* daemon name is stored here */
+diff -ur k1/src/lib/message.h k3/src/lib/message.h
+--- k1/src/lib/message.h       2007-10-03 13:36:47.000000000 +0200
++++ k3/src/lib/message.h       2007-12-22 19:13:06.000000000 +0100
+@@ -154,6 +154,7 @@
+ extern DLL_IMP_EXP sql_escape    p_sql_escape;
+ extern DLL_IMP_EXP int           debug_level;
++extern DLL_IMP_EXP bool          dbg_timestamp;            /* print timestamp in debug output */
+ extern DLL_IMP_EXP int           verbose;
+ extern DLL_IMP_EXP char          my_name[];
+ extern DLL_IMP_EXP const char *  working_directory;
+diff -ur k1/src/stored/acquire.c k3/src/stored/acquire.c
+--- k1/src/stored/acquire.c    2007-09-14 11:49:06.000000000 +0200
++++ k3/src/stored/acquire.c    2007-12-22 19:12:23.000000000 +0100
+@@ -30,7 +30,7 @@
+  *
+  *   Kern Sibbald, August MMII
+  *
+- *   Version $Id: acquire.c 5552 2007-09-14 09:49:06Z kerns $
++ *   Version $Id: acquire.c 6081 2007-12-21 14:11:40Z kerns $
+  */
+ #include "bacula.h"                   /* pull in global headers */
+@@ -38,6 +38,7 @@
+ /* Forward referenced functions */
+ static void attach_dcr_to_dev(DCR *dcr);
++static bool is_suitable_volume_mounted(DCR *dcr);
+ /*********************************************************************
+@@ -316,9 +317,9 @@
+  */
+ DCR *acquire_device_for_append(DCR *dcr)
+ {
+-   bool release = false;
+-   bool recycle = false;
+    bool do_mount = false;
++   bool release = false;
++   bool have_vol;
+    DEVICE *dev = dcr->dev;
+    JCR *jcr = dcr->jcr;
+@@ -337,6 +338,11 @@
+       goto get_out;
+    }
++   /*
++    * have_vol defines whether or not mount_next_write_volume should
++    *   ask the Director again about what Volume to use.
++    */
++   have_vol = is_suitable_volume_mounted(dcr);
+    if (dev->can_append()) {
+       Dmsg0(190, "device already in append.\n");
+       /*
+@@ -351,25 +357,11 @@
+        *  dcr->VolumeName is what we pass into the routines, or
+        *    get back from the subroutines.
+        */
+-      bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
+-      if (!dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE) &&
++      if (!have_vol &&
+           !(dir_find_next_appendable_volume(dcr) &&
+             strcmp(dev->VolHdr.VolumeName, dcr->VolumeName) == 0)) { /* wrong tape mounted */
+-         Dmsg2(190, "Wrong tape mounted: %s. wants:%s\n", dev->VolHdr.VolumeName,
+-            dcr->VolumeName);
+-         /* Release volume reserved by dir_find_next_appendable_volume() */
+-         if (dcr->VolumeName[0]) {
+-            volume_unused(dcr);
+-         }
+-         if (dev->num_writers != 0) {
+-            Jmsg3(jcr, M_FATAL, 0, _("Wanted to append to Volume \"%s\", but device %s is busy writing on \"%s\" .\n"), 
+-                 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
+-            Dmsg3(200, "Wanted to append to Volume \"%s\", but device %s is busy writing on \"%s\" .\n",  
+-                 dcr->VolumeName, dev->print_name(), dev->VolHdr.VolumeName);
+-            goto get_out;
+-         }
+          /* Wrong tape mounted, release it, then fall through to get correct one */
+-         Dmsg0(190, "Wrong tape mounted, release and try mount.\n");
++         Dmsg0(50, "Wrong tape mounted, release and try mount.\n");
+          release = true;
+          do_mount = true;
+       } else {
+@@ -378,14 +370,17 @@
+           *   we do not need to do mount_next_write_volume(), unless
+           *   we need to recycle the tape.
+           */
+-          recycle = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
+-          Dmsg1(190, "Correct tape mounted. recycle=%d\n", recycle);
+-          if (recycle && dev->num_writers != 0) {
++          do_mount = strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") == 0;
++          Dmsg2(190, "jid=%u Correct tape mounted. recycle=%d\n", 
++                (uint32_t)jcr->JobId, do_mount);
++#ifdef xxx
++          if (do_mount && dev->num_writers != 0) {
+              Jmsg(jcr, M_FATAL, 0, _("Cannot recycle volume \"%s\""
+                   " on device %s because it is in use by another job.\n"),
+                   dev->VolHdr.VolumeName, dev->print_name());
+              goto get_out;
+           }
++#endif
+           if (dev->num_writers == 0) {
+              memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
+           }
+@@ -415,21 +410,23 @@
+       }
+    } else {
+       /* Not already in append mode, so mount the device */
+-      Dmsg0(190, "Not in append mode, try mount.\n");
++      Dmsg2(190, "jid=%u Not in append mode, try mount have_vol=%d\n", 
++            (uint32_t)jcr->JobId, have_vol);
++
+       ASSERT(dev->num_writers == 0);
+       do_mount = true;
+    }
+-   if (do_mount || recycle) {
+-      Dmsg0(190, "Do mount_next_write_vol\n");
+-      bool mounted = mount_next_write_volume(dcr, release);
++   if (do_mount || !have_vol) {
++      Dmsg1(190, "jid=%u Do mount_next_write_vol\n", (uint32_t)jcr->JobId);
++      bool mounted = mount_next_write_volume(dcr, have_vol, release);
+       if (!mounted) {
+          if (!job_canceled(jcr)) {
+             /* Reduce "noise" -- don't print if job canceled */
+             Jmsg(jcr, M_FATAL, 0, _("Could not ready device %s for append.\n"),
+                dev->print_name());
+-            Dmsg1(200, "Could not ready device %s for append.\n", 
+-               dev->print_name());
++            Dmsg2(200, "jid=%u Could not ready device %s for append.\n", 
++               (uint32_t)jcr->JobId, dev->print_name());
+          }
+          goto get_out;
+       }
+@@ -441,11 +438,12 @@
+       jcr->NumWriteVolumes = 1;
+    }
+    dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs on vol */
+-   dir_update_volume_info(dcr, false);        /* send Volume info to Director */
++   dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
+    dev->dlock();
+    if (dcr->reserved_device) {
+       dev->reserved_device--;
+-      Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
++      Dmsg3(100, "jid=%u Dec reserve=%d dev=%s\n", (uint32_t)jcr->JobId,
++            dev->reserved_device, dev->print_name());
+       dcr->reserved_device = false;
+    }
+    dev->dunblock(DEV_LOCKED);
+@@ -458,7 +456,8 @@
+    dev->dlock();
+    if (dcr->reserved_device) {
+       dev->reserved_device--;
+-      Dmsg2(100, "Dec reserve=%d dev=%s\n", dev->reserved_device, dev->print_name());
++      Dmsg3(100, "jid=%u Dec reserve=%d dev=%s\n", (uint32_t)jcr->JobId, 
++            dev->reserved_device, dev->print_name());
+       dcr->reserved_device = false;
+    }
+    dev->dunblock(DEV_LOCKED);
+@@ -466,6 +465,18 @@
+ }
++static bool is_suitable_volume_mounted(DCR *dcr)
++{
++   DEVICE *dev = dcr->dev;
++
++   /* Volume mounted? */
++   if (dev->VolHdr.VolumeName[0] == 0) {
++      return false;                      /* no */
++   }
++   bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName));
++   return dir_get_volume_info(dcr, GET_VOL_INFO_FOR_WRITE);
++}
++
+ /*
+  * This job is done, so release the device. From a Unix standpoint,
+  *  the device remains open.
+@@ -496,7 +507,7 @@
+    if (dev->can_read()) {
+       dev->clear_read();              /* clear read bit */
+       Dmsg0(100, "dir_update_vol_info. Release0\n");
+-      dir_update_volume_info(dcr, false); /* send Volume info to Director */
++      dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
+    } else if (dev->num_writers > 0) {
+       /* 
+@@ -522,7 +533,7 @@
+             dev->VolCatInfo.VolCatFiles = dev->file;   /* set number of files */
+             /* Note! do volume update before close, which zaps VolCatInfo */
+             Dmsg0(100, "dir_update_vol_info. Release0\n");
+-            dir_update_volume_info(dcr, false); /* send Volume info to Director */
++            dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
+          }
+       }
+@@ -621,7 +632,12 @@
+       if (dcr->attached_to_dev) {
+          detach_dcr_from_dev(dcr);
+       }
+-      dcr->max_job_spool_size = dev->device->max_job_spool_size;
++      /* Use job spoolsize prior to device spoolsize */
++      if (jcr->spool_size) {
++         dcr->max_job_spool_size = jcr->spool_size;
++      } else {
++         dcr->max_job_spool_size = dev->device->max_job_spool_size;
++      }
+       dcr->device = dev->device;
+       dcr->dev = dev;
+       attach_dcr_to_dev(dcr);
+diff -ur k1/src/stored/askdir.c k3/src/stored/askdir.c
+--- k1/src/stored/askdir.c     2007-09-09 12:03:23.000000000 +0200
++++ k3/src/stored/askdir.c     2007-12-22 19:11:50.000000000 +0100
+@@ -31,7 +31,7 @@
+  *
+  *   Kern Sibbald, December 2000
+  *
+- *   Version $Id: askdir.c 5503 2007-09-09 10:03:23Z kerns $
++ *   Version $Id: askdir.c 5852 2007-11-04 19:57:42Z kerns $
+  */
+ #include "bacula.h"                   /* pull in global headers */
+@@ -42,7 +42,7 @@
+ static char Get_Vol_Info[] = "CatReq Job=%s GetVolInfo VolName=%s write=%d\n";
+ static char Update_media[] = "CatReq Job=%s UpdateMedia VolName=%s"
+    " VolJobs=%u VolFiles=%u VolBlocks=%u VolBytes=%s VolMounts=%u"
+-   " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%d VolStatus=%s"
++   " VolErrors=%u VolWrites=%u MaxVolBytes=%s EndTime=%s VolStatus=%s"
+    " Slot=%d relabel=%d InChanger=%d VolReadTime=%s VolWriteTime=%s"
+    " VolFirstWritten=%s VolParts=%u\n";
+ static char Create_job_media[] = "CatReq Job=%s CreateJobMedia"
+@@ -98,7 +98,7 @@
+    } else {
+       pm_strcpy(ChangerName, "*");
+    }
+-   ok =bnet_fsend(dir, Device_update, 
++   ok = dir->fsend(Device_update, 
+       jcr->Job,
+       dev_name.c_str(),
+       dev->can_append()!=0,
+@@ -125,7 +125,7 @@
+    pm_strcpy(MediaType, device->media_type);
+    bash_spaces(MediaType);
+    /* This is mostly to indicate that we are here */
+-   ok = bnet_fsend(dir, Device_update,
++   ok = dir->fsend(Device_update,
+       jcr->Job,
+       dev_name.c_str(),         /* Changer name */
+       0, 0, 0,                  /* append, read, num_writers */
+@@ -148,7 +148,7 @@
+  */
+ bool dir_send_job_status(JCR *jcr)
+ {
+-   return bnet_fsend(jcr->dir_bsock, Job_status, jcr->Job, jcr->JobStatus);
++   return jcr->dir_bsock->fsend(Job_status, jcr->Job, jcr->JobStatus);
+ }
+ /*
+@@ -179,7 +179,7 @@
+        return false;
+     }
+     memset(&vol, 0, sizeof(vol));
+-    Dmsg1(100, "<dird %s\n", dir->msg);
++    Dmsg1(100, "<dird %s", dir->msg);
+     n = sscanf(dir->msg, OK_media, vol.VolCatName,
+                &vol.VolCatJobs, &vol.VolCatFiles,
+                &vol.VolCatBlocks, &vol.VolCatBytes,
+@@ -191,7 +191,8 @@
+                &vol.EndFile, &vol.EndBlock, &vol.VolCatParts,
+                &vol.LabelType, &vol.VolMediaId);
+     if (n != 22) {
+-       Dmsg3(100, "Bad response from Dir fields=%d, len=%d: %s", n, dir->msglen, dir->msg);
++       Dmsg3(100, "Bad response from Dir fields=%d, len=%d: %s", 
++             n, dir->msglen, dir->msg);
+        Mmsg(jcr->errmsg, _("Error getting Volume info: %s"), dir->msg);
+        return false;
+     }
+@@ -226,7 +227,7 @@
+     bash_spaces(dcr->VolCatInfo.VolCatName);
+     dir->fsend(Get_Vol_Info, jcr->Job, dcr->VolCatInfo.VolCatName,
+        writing==GET_VOL_INFO_FOR_WRITE?1:0);
+-    Dmsg1(100, ">dird: %s\n", dir->msg);
++    Dmsg1(100, ">dird %s", dir->msg);
+     unbash_spaces(dcr->VolCatInfo.VolCatName);
+     bool ok = do_get_volume_info(dcr);
+     V(vol_info_mutex);
+@@ -253,7 +254,9 @@
+     BSOCK *dir = jcr->dir_bsock;
+     bool found = false;
+-    Dmsg0(200, "dir_find_next_appendable_volume\n");
++    Dmsg2(200, "dir_find_next_appendable_volume: reserved=%d Vol=%s\n", 
++       dcr->reserved_device, dcr->VolumeName);
++
+     /*
+      * Try the twenty oldest or most available volumes.  Note,
+      *   the most available could already be mounted on another
+@@ -268,7 +271,7 @@
+        dir->fsend(Find_media, jcr->Job, vol_index, dcr->pool_name, dcr->media_type);
+        unbash_spaces(dcr->media_type);
+        unbash_spaces(dcr->pool_name);
+-       Dmsg1(100, ">dird: %s", dir->msg);
++       Dmsg1(100, ">dird %s", dir->msg);
+        bool ok = do_get_volume_info(dcr);
+        if (ok) {
+           if (!is_volume_in_use(dcr)) {
+@@ -311,14 +314,13 @@
+  * back to the director. The information comes from the
+  * dev record.
+  */
+-bool dir_update_volume_info(DCR *dcr, bool label)
++bool dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten)
+ {
+    JCR *jcr = dcr->jcr;
+    BSOCK *dir = jcr->dir_bsock;
+    DEVICE *dev = dcr->dev;
+-   time_t LastWritten = time(NULL);
+    VOLUME_CAT_INFO *vol = &dev->VolCatInfo;
+-   char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50];
++   char ed1[50], ed2[50], ed3[50], ed4[50], ed5[50], ed6[50];
+    int InChanger;
+    bool ok = false;
+    POOL_MEM VolumeName;
+@@ -341,21 +343,25 @@
+    if (label) {
+       bstrncpy(vol->VolCatStatus, "Append", sizeof(vol->VolCatStatus));
+    }
++// if (update_LastWritten) {
++      vol->VolLastWritten = time(NULL);
++// }
+    pm_strcpy(VolumeName, vol->VolCatName);
+    bash_spaces(VolumeName);
+    InChanger = vol->InChanger;
+-   bnet_fsend(dir, Update_media, jcr->Job,
++   dir->fsend(Update_media, jcr->Job,
+       VolumeName.c_str(), vol->VolCatJobs, vol->VolCatFiles,
+       vol->VolCatBlocks, edit_uint64(vol->VolCatBytes, ed1),
+       vol->VolCatMounts, vol->VolCatErrors,
+       vol->VolCatWrites, edit_uint64(vol->VolCatMaxBytes, ed2),
+-      LastWritten, vol->VolCatStatus, vol->Slot, label,
++      edit_uint64(vol->VolLastWritten, ed6), 
++      vol->VolCatStatus, vol->Slot, label,
+       InChanger,                      /* bool in structure */
+       edit_int64(vol->VolReadTime, ed3),
+       edit_int64(vol->VolWriteTime, ed4),
+       edit_uint64(vol->VolFirstWritten, ed5),
+       vol->VolCatParts);
+-    Dmsg1(100, ">dird: %s", dir->msg);
++    Dmsg1(100, ">dird %s", dir->msg);
+    /* Do not lock device here because it may be locked from label */
+    if (!do_get_volume_info(dcr)) {
+@@ -364,7 +370,7 @@
+          vol->VolCatName, jcr->errmsg);
+       goto bail_out;
+    }
+-   Dmsg1(420, "get_volume_info(): %s", dir->msg);
++   Dmsg1(420, "get_volume_info() %s", dir->msg);
+    /* Update dev Volume info in case something changed (e.g. expired) */
+    dev->VolCatInfo = dcr->VolCatInfo;
+    ok = true;
+@@ -393,20 +399,20 @@
+    }
+    dcr->WroteVol = false;
+-   bnet_fsend(dir, Create_job_media, jcr->Job,
++   dir->fsend(Create_job_media, jcr->Job,
+       dcr->VolFirstIndex, dcr->VolLastIndex,
+       dcr->StartFile, dcr->EndFile,
+       dcr->StartBlock, dcr->EndBlock, 
+       dcr->Copy, dcr->Stripe, 
+       edit_uint64(dcr->VolMediaId, ed1));
+-    Dmsg1(100, ">dird: %s", dir->msg);
++    Dmsg1(100, ">dird %s", dir->msg);
+    if (bnet_recv(dir) <= 0) {
+       Dmsg0(190, "create_jobmedia error bnet_recv\n");
+       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: ERR=%s\n"),
+-           bnet_strerror(dir));
++           dir->bstrerror());
+       return false;
+    }
+-   Dmsg1(100, "<dir: %s", dir->msg);
++   Dmsg1(100, "<dird %s", dir->msg);
+    if (strcmp(dir->msg, OK_create) != 0) {
+       Dmsg1(130, "Bad response from Dir: %s\n", dir->msg);
+       Jmsg(jcr, M_FATAL, 0, _("Error creating JobMedia record: %s\n"), dir->msg);
+@@ -429,9 +435,10 @@
+    return true;
+ #endif
+-   dir->msglen = sprintf(dir->msg, FileAttributes, jcr->Job);
+-   dir->msg = check_pool_memory_size(dir->msg, dir->msglen +
+-                sizeof(DEV_RECORD) + rec->data_len);
++   dir->msg = check_pool_memory_size(dir->msg, sizeof(FileAttributes) +
++                MAX_NAME_LENGTH + sizeof(DEV_RECORD) + rec->data_len + 1);
++   dir->msglen = bsnprintf(dir->msg, sizeof(FileAttributes) +
++                MAX_NAME_LENGTH + 1, FileAttributes, jcr->Job);
+    ser_begin(dir->msg + dir->msglen, 0);
+    ser_uint32(rec->VolSessionId);
+    ser_uint32(rec->VolSessionTime);
+@@ -440,8 +447,8 @@
+    ser_uint32(rec->data_len);
+    ser_bytes(rec->data, rec->data_len);
+    dir->msglen = ser_length(dir->msg);
+-   Dmsg1(1800, ">dird: %s\n", dir->msg);    /* Attributes */
+-   return bnet_send(dir);
++   Dmsg1(1800, ">dird %s\n", dir->msg);    /* Attributes */
++   return dir->send();
+ }
+diff -ur k1/src/stored/bcopy.c k3/src/stored/bcopy.c
+--- k1/src/stored/bcopy.c      2007-12-03 20:27:38.000000000 +0100
++++ k3/src/stored/bcopy.c      2007-12-22 19:10:29.000000000 +0100
+@@ -32,7 +32,7 @@
+  *   Kern E. Sibbald, October 2002
+  *
+  *
+- *   Version $Id: bcopy.c 6017 2007-12-03 19:27:38Z kerns $
++ *   Version $Id: bcopy.c 6016 2007-12-03 19:27:21Z kerns $
+  */
+ #include "bacula.h"
+@@ -42,6 +42,7 @@
+ int generate_daemon_event(JCR *jcr, const char *event) { return 1; }
+ /* Forward referenced functions */
++static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec);
+ static bool record_cb(DCR *dcr, DEV_RECORD *rec);
+@@ -52,10 +53,11 @@
+ static JCR *out_jcr;                   /* output jcr */
+ static BSR *bsr = NULL;
+ static const char *wd = "/tmp";
+-static int list_records = 0;
++static bool list_records = false;
+ static uint32_t records = 0;
+ static uint32_t jobs = 0;
+ static DEV_BLOCK *out_block;
++static SESSION_LABEL sessrec;
+ #define CONFIG_FILE "bacula-sd.conf"
+ char *configfile = NULL;
+@@ -73,7 +75,7 @@
+ "Usage: bcopy [-d debug_level] <input-archive> <output-archive>\n"
+ "       -b bootstrap      specify a bootstrap file\n"
+ "       -c <file>         specify configuration file\n"
+-"       -d <nn>           set debug level to nn\n"
++"       -d <nn>           set debug level to <nn>\n"
+ "       -i                specify input Volume names (separated by |)\n"
+ "       -o                specify output Volume names (separated by |)\n"
+ "       -p                proceed inspite of errors\n"
+@@ -113,9 +115,14 @@
+          break;
+       case 'd':                    /* debug level */
+-         debug_level = atoi(optarg);
+-         if (debug_level <= 0)
+-            debug_level = 1;
++         if (*optarg == 't') {
++            dbg_timestamp = true;
++         } else {
++            debug_level = atoi(optarg);
++            if (debug_level <= 0) {
++               debug_level = 1;
++            }
++         }
+          break;
+       case 'i':                    /* input Volume name */
+@@ -201,6 +208,7 @@
+    out_block = out_jcr->dcr->block;
+    ok = read_records(in_jcr->dcr, record_cb, mount_next_read_volume);
++
+    if (ok || out_dev->can_write()) {
+       if (!write_block_to_device(out_jcr->dcr)) {
+          Pmsg0(000, _("Write of last block failed.\n"));
+@@ -233,6 +241,7 @@
+     *
+     */
+    if (rec->FileIndex < 0) {
++      get_session_record(in_dcr->dev, rec, &sessrec);
+       if (verbose > 1) {
+          dump_label_record(in_dcr->dev, rec, 1);
+@@ -294,10 +303,46 @@
+    return true;
+ }
++static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec)
++{
++   const char *rtype;
++   memset(sessrec, 0, sizeof(sessrec));
++   switch (rec->FileIndex) {
++   case PRE_LABEL:
++      rtype = _("Fresh Volume Label");
++      break;
++   case VOL_LABEL:
++      rtype = _("Volume Label");
++      unser_volume_label(dev, rec);
++      break;
++   case SOS_LABEL:
++      rtype = _("Begin Job Session");
++      unser_session_label(sessrec, rec);
++      break;
++   case EOS_LABEL:
++      rtype = _("End Job Session");
++      unser_session_label(sessrec, rec);
++      break;
++   case 0:
++   case EOM_LABEL:
++      rtype = _("End of Medium");
++      break;
++   default:
++      rtype = _("Unknown");
++      break;
++   }
++   Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n",
++         rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
++   if (verbose) {
++      Pmsg5(-1, _("%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n"),
++            rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
++   }
++}
++
+ /* Dummies to replace askdir.c */
+ bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
+-bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
++bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
+ bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
+ bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
+ bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
+diff -ur k1/src/stored/bextract.c k3/src/stored/bextract.c
+--- k1/src/stored/bextract.c   2007-10-03 13:36:47.000000000 +0200
++++ k3/src/stored/bextract.c   2007-12-22 19:10:20.000000000 +0100
+@@ -4,7 +4,7 @@
+  *
+  *   Kern E. Sibbald, MM
+  *
+- *   Version $Id: bextract.c 5713 2007-10-03 11:36:47Z kerns $
++ *   Version $Id: bextract.c 5852 2007-11-04 19:57:42Z kerns $
+  *
+  */
+ /*
+@@ -79,7 +79,7 @@
+ "Usage: bextract <options> <bacula-archive-device-name> <directory-to-store-files>\n"
+ "       -b <file>       specify a bootstrap file\n"
+ "       -c <file>       specify a configuration file\n"
+-"       -d <nn>         set debug level to nn\n"
++"       -d <nn>         set debug level to <nn>\n"
+ "       -e <file>       exclude list\n"
+ "       -i <file>       include list\n"
+ "       -p              proceed inspite of I/O errors\n"
+@@ -126,9 +126,14 @@
+          break;
+       case 'd':                    /* debug level */
+-         debug_level = atoi(optarg);
+-         if (debug_level <= 0)
+-            debug_level = 1;
++         if (*optarg == 't') {
++            dbg_timestamp = true;
++         } else {
++            debug_level = atoi(optarg);
++            if (debug_level <= 0) {
++               debug_level = 1;
++            }
++         }
+          break;
+       case 'e':                    /* exclude list */
+@@ -476,7 +481,7 @@
+ /* Dummies to replace askdir.c */
+ bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
+-bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
++bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
+ bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
+ bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
+ bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
+diff -ur k1/src/stored/block.c k3/src/stored/block.c
+--- k1/src/stored/block.c      2007-10-03 13:36:47.000000000 +0200
++++ k3/src/stored/block.c      2007-12-22 19:12:33.000000000 +0100
+@@ -32,7 +32,7 @@
+  *              Kern Sibbald, March MMI
+  *                 added BB02 format October MMII
+  *
+- *   Version $Id: block.c 5713 2007-10-03 11:36:47Z kerns $
++ *   Version $Id: block.c 5852 2007-11-04 19:57:42Z kerns $
+  *
+  */
+@@ -746,7 +746,7 @@
+       dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
+    }
+    
+-   if (!dir_update_volume_info(dcr, false)) {
++   if (!dir_update_volume_info(dcr, false, true)) {
+       ok = false;
+    }
+    Dmsg1(100, "dir_update_volume_info terminate writing -- %s\n", ok?"OK":"ERROR");
+@@ -798,7 +798,7 @@
+       return false;
+    }
+    dev->VolCatInfo.VolCatFiles = dev->file;
+-   if (!dir_update_volume_info(dcr, false)) {
++   if (!dir_update_volume_info(dcr, false, false)) {
+       Dmsg0(190, "Error from update_vol_info.\n");
+       terminate_writing_volume(dcr);
+       dev->dev_errno = EIO;
+@@ -856,7 +856,7 @@
+       
+       dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
+             
+-      if (!dir_update_volume_info(dcr, false)) {
++      if (!dir_update_volume_info(dcr, false, false)) {
+          Dmsg0(190, "Error from update_vol_info.\n");
+          dev->dev_errno = EIO;
+          return false;
+diff -ur k1/src/stored/bls.c k3/src/stored/bls.c
+--- k1/src/stored/bls.c        2007-10-03 13:36:47.000000000 +0200
++++ k3/src/stored/bls.c        2007-12-22 19:10:57.000000000 +0100
+@@ -31,7 +31,7 @@
+  * 
+  *  Kern Sibbald, MM
+  *
+- *   Version $Id: bls.c 5713 2007-10-03 11:36:47Z kerns $
++ *   Version $Id: bls.c 5852 2007-11-04 19:57:42Z kerns $
+  */
+ #include "bacula.h"
+@@ -79,7 +79,7 @@
+ "Usage: bls [options] <device-name>\n"
+ "       -b <file>       specify a bootstrap file\n"
+ "       -c <file>       specify a config file\n"
+-"       -d <level>      specify debug level\n"
++"       -d <nn>         set debug level to <nn>\n"
+ "       -e <file>       exclude list\n"
+ "       -i <file>       include list\n"
+ "       -j              list jobs\n"
+@@ -130,9 +130,14 @@
+          break;
+       case 'd':                    /* debug level */
+-         debug_level = atoi(optarg);
+-         if (debug_level <= 0)
+-            debug_level = 1;
++         if (*optarg == 't') {
++            dbg_timestamp = true;
++         } else {
++            debug_level = atoi(optarg);
++            if (debug_level <= 0) {
++               debug_level = 1;
++            }
++         }
+          break;
+       case 'e':                    /* exclude list */
+@@ -440,7 +445,7 @@
+ /* Dummies to replace askdir.c */
+ bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
+-bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
++bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
+ bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
+ bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
+ bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
+diff -ur k1/src/stored/bscan.c k3/src/stored/bscan.c
+--- k1/src/stored/bscan.c      2007-10-03 13:36:47.000000000 +0200
++++ k3/src/stored/bscan.c      2007-12-22 19:11:05.000000000 +0100
+@@ -34,7 +34,7 @@
+  *   Kern E. Sibbald, December 2001
+  *
+  *
+- *   Version $Id: bscan.c 5713 2007-10-03 11:36:47Z kerns $
++ *   Version $Id: bscan.c 5852 2007-11-04 19:57:42Z kerns $
+  */
+ #include "bacula.h"
+@@ -116,7 +116,7 @@
+ "Usage: bscan [ options ] <bacula-archive>\n"
+ "       -b bootstrap      specify a bootstrap file\n"
+ "       -c <file>         specify configuration file\n"
+-"       -d <nn>           set debug level to nn\n"
++"       -d <nn>           set debug level to <nn>\n"
+ "       -m                update media info in database\n"
+ "       -n <name>         specify the database name (default bacula)\n"
+ "       -u <user>         specify database user name (default bacula)\n"
+@@ -166,9 +166,14 @@
+          break;
+       case 'd':                    /* debug level */
+-         debug_level = atoi(optarg);
+-         if (debug_level <= 0)
+-            debug_level = 1;
++         if (*optarg == 't') {
++            dbg_timestamp = true;
++         } else {
++            debug_level = atoi(optarg);
++            if (debug_level <= 0) {
++               debug_level = 1;
++            }
++         }
+          break;
+       case 'h':
+@@ -1271,7 +1276,7 @@
+ /* Dummies to replace askdir.c */
+ bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
+-bool    dir_update_volume_info(DCR *dcr, bool relabel) { return 1; }
++bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
+ bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
+ bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
+ bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
+diff -ur k1/src/stored/btape.c k3/src/stored/btape.c
+--- k1/src/stored/btape.c      2007-06-07 16:46:43.000000000 +0200
++++ k3/src/stored/btape.c      2007-12-22 19:11:14.000000000 +0100
+@@ -37,7 +37,7 @@
+  *   Note, this program reads stored.conf, and will only
+  *     talk to devices that are configured.
+  *
+- *   Version $Id: btape.c 4992 2007-06-07 14:46:43Z kerns $
++ *   Version $Id: btape.c 5852 2007-11-04 19:57:42Z kerns $
+  *
+  */
+@@ -220,9 +220,13 @@
+          break;
+       case 'd':                    /* set debug level */
+-         debug_level = atoi(optarg);
+-         if (debug_level <= 0) {
+-            debug_level = 1;
++         if (*optarg == 't') {
++            dbg_timestamp = true;
++         } else {
++            debug_level = atoi(optarg);
++            if (debug_level <= 0) {
++               debug_level = 1;
++            }
+          }
+          break;
+@@ -2598,7 +2602,7 @@
+ "Usage: btape <options> <device_name>\n"
+ "       -b <file>   specify bootstrap file\n"
+ "       -c <file>   set configuration file to file\n"
+-"       -d <nn>     set debug level to nn\n"
++"       -d <nn>     set debug level to <nn>\n"
+ "       -p          proceed inspite of I/O errors\n"
+ "       -s          turn off signals\n"
+ "       -v          be verbose\n"
+@@ -2644,7 +2648,7 @@
+ bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
+ bool    dir_send_job_status(JCR *jcr) {return 1;}
+-bool dir_update_volume_info(DCR *dcr, bool relabel)
++bool dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten)
+ {
+    return 1;
+ }
+diff -ur k1/src/stored/dev.c k3/src/stored/dev.c
+--- k1/src/stored/dev.c        2007-12-02 19:03:17.000000000 +0100
++++ k3/src/stored/dev.c        2007-12-22 19:11:57.000000000 +0100
+@@ -47,7 +47,7 @@
+  *     daemon. More complicated coding (double buffering, writer
+  *     thread, ...) is left for a later version.
+  *
+- *   Version $Id: dev.c 6011 2007-12-02 18:03:17Z kerns $
++ *   Version $Id: dev.c 5999 2007-11-29 21:36:36Z ricozz $
+  */
+ /*
+@@ -89,7 +89,7 @@
+ /* Forward referenced functions */
+ void set_os_device_parameters(DCR *dcr);   
+ static bool dev_get_os_pos(DEVICE *dev, struct mtget *mt_stat);
+-static char *mode_to_str(int mode);
++static const char *mode_to_str(int mode);
+ /*
+  * Allocate and initialize the DEVICE structure
+@@ -490,7 +490,7 @@
+       Mmsg2(errmsg, _("Could not open: %s, ERR=%s\n"), archive_name.c_str(), 
+             be.bstrerror());
+       Dmsg1(100, "open failed: %s", errmsg);
+-      Emsg0(M_FATAL, 0, errmsg);
++      Jmsg1(NULL, M_WARNING, 0, "%s", errmsg);
+    } else {
+       dev_errno = 0;
+       file = 0;
+@@ -2468,7 +2468,7 @@
+           mt_stat->mt_fileno >= 0;
+ }
+-static char *modes[] = {
++static const char *modes[] = {
+    "CREATE_READ_WRITE",
+    "OPEN_READ_WRITE",
+    "OPEN_READ_ONLY",
+@@ -2476,7 +2476,7 @@
+ };
+-static char *mode_to_str(int mode)  
++static const char *mode_to_str(int mode)  
+ {
+    static char buf[100];
+    if (mode < 1 || mode > 4) {
+diff -ur k1/src/stored/dev.h k3/src/stored/dev.h
+--- k1/src/stored/dev.h        2007-09-09 12:03:23.000000000 +0200
++++ k3/src/stored/dev.h        2007-12-22 19:12:14.000000000 +0100
+@@ -31,7 +31,7 @@
+  *
+  * Kern Sibbald, MM
+  *
+- *   Version $Id: dev.h 5503 2007-09-09 10:03:23Z kerns $
++ *   Version $Id: dev.h 5852 2007-11-04 19:57:42Z kerns $
+  *
+  */
+@@ -158,6 +158,7 @@
+    btime_t  VolWriteTime;             /* time spent writing this Volume */
+    int64_t  VolMediaId;               /* MediaId */
+    utime_t  VolFirstWritten;          /* Time of first write */
++   utime_t  VolLastWritten;           /* Time of last write */
+    bool     InChanger;                /* Set if vol in current magazine */
+    char VolCatStatus[20];             /* Volume status */
+    char VolCatName[MAX_NAME_LENGTH];  /* Desired volume to mount */
+@@ -473,8 +474,9 @@
+ class VOLRES { 
+ public:
+    dlink link;
+-   char *vol_name;
+-   DEVICE *dev;
++   char *vol_name;                    /* Volume name */
++   DEVICE *dev;                       /* Pointer to device to which we are attached */
++   bool released;                     /* set when the Volume can be released */
+ };
+diff -ur k1/src/stored/device.c k3/src/stored/device.c
+--- k1/src/stored/device.c     2007-06-29 14:12:26.000000000 +0200
++++ k3/src/stored/device.c     2007-12-22 19:11:23.000000000 +0100
+@@ -53,7 +53,7 @@
+  *
+  *   Kern Sibbald, MM, MMI
+  *
+- *   Version $Id: device.c 5114 2007-06-29 12:12:26Z kerns $
++ *   Version $Id: device.c 5852 2007-11-04 19:57:42Z kerns $
+  */
+ #include "bacula.h"                   /* pull in global headers */
+@@ -122,7 +122,8 @@
+         edit_uint64_with_commas(dev->VolCatInfo.VolCatBlocks, b2),
+         bstrftime(dt, sizeof(dt), time(NULL)));
+-   if (!mount_next_write_volume(dcr, 1)) {
++   /* Called with have_vol=false, release=true */
++   if (!mount_next_write_volume(dcr, false, true)) {
+       free_block(label_blk);
+       dcr->block = block;
+       dev->dlock();  
+@@ -131,7 +132,7 @@
+    dev->dlock();                    /* lock again */
+    dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs on vol */
+-   dir_update_volume_info(dcr, false);        /* send Volume info to Director */
++   dir_update_volume_info(dcr, false, false); /* send Volume info to Director */
+    Jmsg(jcr, M_INFO, 0, _("New volume \"%s\" mounted on device %s at %s.\n"),
+       dcr->VolumeName, dev->print_name(), bstrftime(dt, sizeof(dt), time(NULL)));
+diff -ur k1/src/stored/dvd.c k3/src/stored/dvd.c
+--- k1/src/stored/dvd.c        2007-06-07 16:46:43.000000000 +0200
++++ k3/src/stored/dvd.c        2007-12-22 19:26:23.000000000 +0100
+@@ -1,16 +1,7 @@
+ /*
+- *
+- *   dvd.c  -- Routines specific to DVD devices (and
+- *             possibly other removable hard media). 
+- *
+- *    Nicolas Boichat, MMV
+- *
+- *   Version $Id: dvd.c 4992 2007-06-07 14:46:43Z kerns $
+- */
+-/*
+    Bacula® - The Network Backup Solution
+-   Copyright (C) 2005-2006 Free Software Foundation Europe e.V.
++   Copyright (C) 2005-2007 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.
+@@ -34,6 +25,15 @@
+    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+    Switzerland, email:ftf@fsfeurope.org.
+ */
++/*
++ *
++ *   dvd.c  -- Routines specific to DVD devices (and
++ *             possibly other removable hard media). 
++ *
++ *    Nicolas Boichat, MMV
++ *
++ *   Version $Id: dvd.c 5852 2007-11-04 19:57:42Z kerns $
++ */
+ #include "bacula.h"
+ #include "stored.h"
+@@ -686,7 +686,7 @@
+    dcr->VolCatInfo.VolCatBytes = 0;
+    /* Update catalog */
+-   if (!dir_update_volume_info(dcr, false)) {
++   if (!dir_update_volume_info(dcr, false, true)) {
+       return false;
+    }
+    
+diff -ur k1/src/stored/job.c k3/src/stored/job.c
+--- k1/src/stored/job.c        2007-09-29 00:01:16.000000000 +0200
++++ k3/src/stored/job.c        2007-12-22 19:11:41.000000000 +0100
+@@ -30,7 +30,7 @@
+  *
+  *   Kern Sibbald, MM
+  *
+- *   Version $Id: job.c 5686 2007-09-28 22:01:16Z kerns $
++ *   Version $Id: job.c 5697 2007-09-30 17:40:08Z ricozz $
+  *
+  */
+@@ -49,9 +49,13 @@
+ /* Requests from the Director daemon */
+ static char jobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s "
+       "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s "
++      "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d SpoolSize=%s\n";
++static char oldjobcmd[] = "JobId=%d job=%127s job_name=%127s client_name=%127s "
++      "type=%d level=%d FileSet=%127s NoAttr=%d SpoolAttr=%d FileSetMD5=%127s "
+       "SpoolData=%d WritePartAfterJob=%d PreferMountedVols=%d\n";
++
+ /* Responses sent to Director daemon */
+ static char OKjob[]     = "3000 OK Job SDid=%u SDtime=%u Authorization=%s\n";
+ static char BAD_job[]   = "3915 Bad Job command. stat=%d CMD: %s\n";
+@@ -73,6 +77,7 @@
+ {
+    int JobId;
+    char auth_key[100];
++   char spool_size[30];
+    char seed[100];
+    BSOCK *dir = jcr->dir_bsock;
+    POOL_MEM job_name, client_name, job, fileset_name, fileset_md5;
+@@ -85,17 +90,26 @@
+     * Get JobId and permissions from Director
+     */
+    Dmsg1(100, "<dird: %s", dir->msg);
++   bstrncpy(spool_size, "0", sizeof(spool_size));
+    stat = sscanf(dir->msg, jobcmd, &JobId, job.c_str(), job_name.c_str(),
+               client_name.c_str(),
+               &JobType, &level, fileset_name.c_str(), &no_attributes,
+-              &spool_attributes, fileset_md5.c_str(), &spool_data, 
++              &spool_attributes, fileset_md5.c_str(), &spool_data,
++              &write_part_after_job, &PreferMountedVols, spool_size);
++   if (stat != 14) {
++      /* Try old version */
++      stat = sscanf(dir->msg, oldjobcmd, &JobId, job.c_str(), job_name.c_str(),
++              client_name.c_str(),
++              &JobType, &level, fileset_name.c_str(), &no_attributes,
++              &spool_attributes, fileset_md5.c_str(), &spool_data,
+               &write_part_after_job, &PreferMountedVols);
+-   if (stat != 13) {
+-      pm_strcpy(jcr->errmsg, dir->msg);
+-      dir->fsend(BAD_job, stat, jcr->errmsg);
+-      Dmsg1(100, ">dird: %s", dir->msg);
+-      set_jcr_job_status(jcr, JS_ErrorTerminated);
+-      return false;
++      if (stat != 13) {
++         pm_strcpy(jcr->errmsg, dir->msg);
++         dir->fsend(BAD_job, stat, jcr->errmsg);
++         Dmsg1(100, ">dird: %s", dir->msg);
++         set_jcr_job_status(jcr, JS_ErrorTerminated);
++         return false;
++      }
+    }
+    /*
+     * Since this job could be rescheduled, we
+@@ -125,6 +139,7 @@
+    jcr->no_attributes = no_attributes;
+    jcr->spool_attributes = spool_attributes;
+    jcr->spool_data = spool_data;
++   jcr->spool_size = str_to_int64(spool_size);
+    jcr->write_part_after_job = write_part_after_job;
+    jcr->fileset_md5 = get_pool_memory(PM_NAME);
+    pm_strcpy(jcr->fileset_md5, fileset_md5);
+diff -ur k1/src/stored/label.c k3/src/stored/label.c
+--- k1/src/stored/label.c      2007-10-03 13:36:47.000000000 +0200
++++ k3/src/stored/label.c      2007-12-22 19:10:49.000000000 +0100
+@@ -32,7 +32,7 @@
+  *   Kern Sibbald, MM
+  *
+  *
+- *   Version $Id: label.c 5713 2007-10-03 11:36:47Z kerns $
++ *   Version $Id: label.c 5852 2007-11-04 19:57:42Z kerns $
+  */
+ #include "bacula.h"                   /* pull in global headers */
+@@ -505,7 +505,7 @@
+    }
+    Dmsg0(150, "dir_update_vol_info. Set Append\n");
+    bstrncpy(dev->VolCatInfo.VolCatStatus, "Append", sizeof(dev->VolCatInfo.VolCatStatus));
+-   if (!dir_update_volume_info(dcr, true)) {  /* indicate doing relabel */
++   if (!dir_update_volume_info(dcr, true, true)) {  /* indicate doing relabel */
+       return false;
+    }
+    if (recycle) {
+@@ -716,7 +716,7 @@
+       }
+       break;
+    default:
+-      Jmsg1(jcr, M_ABORT, 0, _("Bad session label = %d\n"), label);
++      Jmsg1(jcr, M_ABORT, 0, _("Bad Volume session label = %d\n"), label);
+       break;
+    }
+    create_session_label(dcr, rec, label);
+diff -ur k1/src/stored/mount.c k3/src/stored/mount.c
+--- k1/src/stored/mount.c      2007-09-14 11:49:06.000000000 +0200
++++ k3/src/stored/mount.c      2007-12-22 19:11:30.000000000 +0100
+@@ -32,7 +32,7 @@
+  *
+  *   Kern Sibbald, August MMII
+  *
+- *   Version $Id: mount.c 5552 2007-09-14 09:49:06Z kerns $
++ *   Version $Id: mount.c 5852 2007-11-04 19:57:42Z kerns $
+  */
+ #include "bacula.h"                   /* pull in global headers */
+@@ -60,7 +60,7 @@
+  *  impossible to get the requested Volume.
+  *
+  */
+-bool mount_next_write_volume(DCR *dcr, bool release)
++bool mount_next_write_volume(DCR *dcr, bool have_vol, bool release)
+ {
+    int retry = 0;
+    bool ask = false, recycle, autochanger;
+@@ -108,12 +108,16 @@
+     *    in dcr->VolCatInfo
+     */
+    Dmsg0(200, "Before dir_find_next_appendable_volume.\n");
+-   while (!dir_find_next_appendable_volume(dcr)) {
+-       Dmsg0(200, "not dir_find_next\n");
+-       if (!dir_ask_sysop_to_create_appendable_volume(dcr)) {
+-         return false;
++   if (!have_vol) {
++      while (!dir_find_next_appendable_volume(dcr)) {
++         Dmsg0(200, "not dir_find_next\n");
++         if (!dir_ask_sysop_to_create_appendable_volume(dcr)) {
++            return false;
++          }
++          Dmsg0(200, "Again dir_find_next_append...\n");
+        }
+-       Dmsg0(200, "Again dir_find_next_append...\n");
++   } else {
++      have_vol = false;               /* set false for next pass if any */
+    }
+    if (job_canceled(jcr)) {
+       return false;
+@@ -144,7 +148,7 @@
+     * If we autochanged to correct Volume or (we have not just
+     *   released the Volume AND we can automount) we go ahead
+     *   and read the label. If there is no tape in the drive,
+-    *   we will err, recurse and ask the operator the next time.
++    *   we will fail, recurse and ask the operator the next time.
+     */
+    if (!release && dev->is_tape() && dev->has_cap(CAP_AUTOMOUNT)) {
+       Dmsg0(150, "(1)Ask=0\n");
+@@ -432,7 +436,7 @@
+       }
+       dev->VolCatInfo.VolCatMounts++;      /* Update mounts */
+       Dmsg1(150, "update volinfo mounts=%d\n", dev->VolCatInfo.VolCatMounts);
+-      if (!dir_update_volume_info(dcr, false)) {
++      if (!dir_update_volume_info(dcr, false, false)) {
+          return false;
+       }
+       
+@@ -519,7 +523,7 @@
+       Dmsg0(150, "dir_update_vol_info. Set Append\n");
+       /* Copy Director's info into the device info */
+       dev->VolCatInfo = dcr->VolCatInfo;    /* structure assignment */
+-      if (!dir_update_volume_info(dcr, true)) {  /* indicate tape labeled */
++      if (!dir_update_volume_info(dcr, true, true)) {  /* indicate tape labeled */
+          return try_error;
+       }
+       Jmsg(dcr->jcr, M_INFO, 0, _("Labeled new Volume \"%s\" on device %s.\n"),
+@@ -552,7 +556,7 @@
+    dev->VolCatInfo = dcr->VolCatInfo;     /* structure assignment */
+    bstrncpy(dev->VolCatInfo.VolCatStatus, "Error", sizeof(dev->VolCatInfo.VolCatStatus));
+    Dmsg0(150, "dir_update_vol_info. Set Error.\n");
+-   dir_update_volume_info(dcr, false);
++   dir_update_volume_info(dcr, false, false);
+ }
+ /*
+@@ -570,7 +574,7 @@
+    dcr->VolCatInfo.InChanger = false;
+    dev->VolCatInfo.InChanger = false;
+    Dmsg0(400, "update vol info in mount\n");
+-   dir_update_volume_info(dcr, true);  /* set new status */
++   dir_update_volume_info(dcr, true, false);  /* set new status */
+ }
+ /*
+@@ -588,6 +592,7 @@
+    /*
+     * First erase all memory of the current volume
+     */
++   free_volume(dev);
+    dev->block_num = dev->file = 0;
+    dev->EndBlock = dev->EndFile = 0;
+    memset(&dev->VolCatInfo, 0, sizeof(dev->VolCatInfo));
+diff -ur k1/src/stored/protos.h k3/src/stored/protos.h
+--- k1/src/stored/protos.h     2007-06-28 13:57:03.000000000 +0200
++++ k3/src/stored/protos.h     2007-12-22 19:12:43.000000000 +0100
+@@ -28,7 +28,7 @@
+ /*
+  * Protypes for stored -- Kern Sibbald MM  
+  *
+- *   Version $Id: protos.h 5112 2007-06-28 11:57:03Z kerns $
++ *   Version $Id: protos.h 5852 2007-11-04 19:57:42Z kerns $
+  */
+ /* From stored.c */
+@@ -49,7 +49,7 @@
+ };
+ bool    dir_get_volume_info(DCR *dcr, enum get_vol_info_rw);
+ bool    dir_find_next_appendable_volume(DCR *dcr);
+-bool    dir_update_volume_info(DCR *dcr, bool label);
++bool    dir_update_volume_info(DCR *dcr, bool label, bool update_LastWritten);
+ bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr);
+ bool    dir_ask_sysop_to_mount_volume(DCR *dcr);
+ bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec);
+@@ -182,7 +182,7 @@
+ bool     is_this_bsr_done(BSR *bsr, DEV_RECORD *rec);
+ /* From mount.c */
+-bool     mount_next_write_volume(DCR *dcr, bool release);
++bool     mount_next_write_volume(DCR *dcr, bool have_vol, bool release);
+ bool     mount_next_read_volume(DCR *dcr);
+ void     mark_volume_in_error(DCR *dcr);
+diff -ur k1/src/stored/record.c k3/src/stored/record.c
+--- k1/src/stored/record.c     2007-06-07 16:46:43.000000000 +0200
++++ k3/src/stored/record.c     2007-12-22 19:12:06.000000000 +0100
+@@ -1,14 +1,4 @@
+ /*
+- *
+- *   record.c -- tape record handling functions
+- *
+- *              Kern Sibbald, April MMI
+- *                added BB02 format October MMII
+- *
+- *   Version $Id: record.c 4992 2007-06-07 14:46:43Z kerns $
+- *
+- */
+-/*
+    Bacula® - The Network Backup Solution
+    Copyright (C) 2001-2006 Free Software Foundation Europe e.V.
+@@ -35,6 +25,16 @@
+    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+    Switzerland, email:ftf@fsfeurope.org.
+ */
++/*
++ *
++ *   record.c -- tape record handling functions
++ *
++ *              Kern Sibbald, April MMI
++ *                added BB02 format October MMII
++ *
++ *   Version $Id: record.c 6014 2007-12-03 18:14:27Z kerns $
++ *
++ */
+ #include "bacula.h"
+@@ -254,7 +254,7 @@
+    ASSERT(block->buf_len >= block->binbuf);
+    Dmsg6(890, "write_record_to_block() FI=%s SessId=%d Strm=%s len=%d\n"
+-"rem=%d remainder=%d\n",
++      "rem=%d remainder=%d\n",
+       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
+       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
+       remlen, rec->remainder);
+@@ -365,7 +365,7 @@
+          if (!sm_check_rtn(__FILE__, __LINE__, False)) {
+             /* We damaged a buffer */
+             Dmsg6(0, "Damaged block FI=%s SessId=%d Strm=%s len=%d\n"
+-"rem=%d remainder=%d\n",
++               "rem=%d remainder=%d\n",
+                FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
+                stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
+                remlen, rec->remainder);
+diff -ur k1/src/stored/reserve.c k3/src/stored/reserve.c
+--- k1/src/stored/reserve.c    2007-08-04 18:46:32.000000000 +0200
++++ k3/src/stored/reserve.c    2007-12-22 19:09:56.000000000 +0100
+@@ -212,11 +212,11 @@
+       if (dev) {
+          len = Mmsg(msg, "%s on device %s\n", vol->vol_name, dev->print_name());
+          sendit(msg.c_str(), len, arg);
+-         len = Mmsg(msg, "    Reader=%d writers=%d reserved=%d\n", dev->can_read()?1:0,
+-            dev->num_writers, dev->reserved_device);
++         len = Mmsg(msg, "    Reader=%d writers=%d reserved=%d released=%d\n", 
++            dev->can_read()?1:0, dev->num_writers, dev->reserved_device, vol->released);
+          sendit(msg.c_str(), len, arg);
+       } else {
+-         len = Mmsg(msg, "%s no dev\n", vol->vol_name);
++         len = Mmsg(msg, "%s no device. released=%d\n", vol->vol_name, vol->released);
+          sendit(msg.c_str(), len, arg);
+       }
+    }
+@@ -292,11 +292,11 @@
+  *  already exist and are correctly programmed and will need no changes -- use 
+  *  counts are always very tricky.
+  *
+- *  The old code had a concept of "reserving" a Volume, but it needs to be changed 
++ *  The old code had a concept of "reserving" a Volume, but was changed 
+  *  to reserving and using a drive.  A volume is must be attached to (owned by) a 
+  *  drive and can move from drive to drive or be unused given certain specific 
+  *  conditions of the drive.  The key is that the drive must "own" the Volume.  
+- *  The old code has the job (dcr) owning the volume (more or less).  The job is 
++ *  The old code had the job (dcr) owning the volume (more or less).  The job was
+  *  to change the insertion and removal of the volumes from the list to be based 
+  *  on the drive rather than the job.  
+  *
+@@ -329,13 +329,14 @@
+        *  because it was probably inserted by another job.
+        */
+       if (strcmp(vol->vol_name, VolumeName) == 0) {
++         Dmsg1(dbglvl, "OK, vol=%s on device.\n", VolumeName);
+          goto get_out;                  /* Volume already on this device */
+       } else {
+-         Dmsg3(dbglvl, "jid=%u reserve_vol free vol=%s at %p\n", 
++         Dmsg3(dbglvl, "jid=%u reserve_vol free vol=%s at %p\n",
+                (int)dcr->jcr->JobId, vol->vol_name, vol->vol_name);
+-         debug_list_volumes("reserve_vol free");
+          vol_list->remove(vol);
+          free_vol_item(vol);
++         debug_list_volumes("reserve_vol free");
+       }
+    }
+@@ -378,12 +379,16 @@
+             Dmsg4(dbglvl, "jid=%u Volume busy could not swap vol=%s from dev=%s to %s\n", 
+                jid(), VolumeName, vol->dev->print_name(), dev->print_name());
+             vol = NULL;                /* device busy */
++            goto get_out;
+          }
+       }
+    }
+    dev->vol = vol;
+ get_out:
++   if (vol) {
++      vol->released = false;
++   }
+    debug_list_volumes("end new volume");
+    unlock_volumes();
+    return vol;
+@@ -462,6 +467,7 @@
+     *  explicitly read in this drive. This allows the SD to remember
+     *  where the tapes are or last were.
+     */
++   dev->vol->released = true;
+    if (dev->is_tape() || dev->is_autochanger()) {
+       return true;
+    } else {
+@@ -837,6 +843,7 @@
+       dlist *temp_vol_list, *save_vol_list;
+       VOLRES *vol = NULL;
+       lock_volumes();
++      Dmsg0(dbglvl, "lock volumes\n");                           
+       /*  
+        * Create a temporary copy of the volume list.  We do this,
+@@ -1122,6 +1129,26 @@
+              */
+             if (dcr->volume_in_use && !rctx.PreferMountedVols) {
+                rctx.PreferMountedVols = true;
++               if (dcr->VolumeName[0]) {
++                  volume_unused(dcr);
++               }
++               goto bail_out;
++            }
++            /*
++             * Note. Under some circumstances, the Director can hand us
++             *  a Volume name that is no the same as the one on the current
++             *  drive, and in that case, the call above to find the next
++             *  volume will fail because in attempting to reserve the Volume
++             *  the code will realize that we already have a tape mounted,
++             *  and it will fail.  This *should* only happen if there are 
++             *  writers, thus the following test.  In that case, we simply
++             *  bail out, and continue waiting, rather than plunging on
++             *  and hoping that the operator can resolve the problem. 
++             */
++            if (dcr->dev->num_writers != 0) {
++               if (dcr->VolumeName[0]) {
++                  volume_unused(dcr);
++               }
+                goto bail_out;
+             }
+          }
+@@ -1270,6 +1297,51 @@
+    return ok;
+ }
++static int is_pool_ok(DCR *dcr)
++{
++   DEVICE *dev = dcr->dev;
++   JCR *jcr = dcr->jcr;
++
++   /* Now check if we want the same Pool and pool type */
++   if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
++       strcmp(dev->pool_type, dcr->pool_type) == 0) {
++      /* OK, compatible device */
++      Dmsg1(dbglvl, "OK dev: %s num_writers=0, reserved, pool matches\n", dev->print_name());
++      return 1;
++   } else {
++      /* Drive Pool not suitable for us */
++      Mmsg(jcr->errmsg, _(
++"3608 JobId=%u wants Pool=\"%s\" but have Pool=\"%s\" nreserve=%d on drive %s.\n"), 
++            (uint32_t)jcr->JobId, dcr->pool_name, dev->pool_name,
++            dev->reserved_device, dev->print_name());
++      queue_reserve_message(jcr);
++      Dmsg2(dbglvl, "failed: busy num_writers=0, reserved, pool=%s wanted=%s\n",
++         dev->pool_name, dcr->pool_name);
++   }
++   return 0;
++}
++
++static bool is_max_jobs_ok(DCR *dcr) 
++{
++   DEVICE *dev = dcr->dev;
++   JCR *jcr = dcr->jcr;
++
++   Dmsg4(dbglvl, "MaxJobs=%d Jobs=%d reserves=%d Vol=%s\n",
++         dcr->VolCatInfo.VolCatMaxJobs,
++         dcr->VolCatInfo.VolCatJobs, dev->reserved_device,
++         dcr->VolumeName);
++   if (dcr->VolCatInfo.VolCatMaxJobs > 0 && dcr->VolCatInfo.VolCatMaxJobs <=
++        (dcr->VolCatInfo.VolCatJobs + dev->reserved_device)) {
++      /* Max Job Vols depassed or already reserved */
++      Mmsg(jcr->errmsg, _("3610 JobId=%u Volume max jobs exceeded on drive %s.\n"), 
++            (uint32_t)jcr->JobId, dev->print_name());
++      queue_reserve_message(jcr);
++      Dmsg1(dbglvl, "reserve dev failed: %s", jcr->errmsg);
++      return false;                /* wait */
++   }
++   return true;
++}
++
+ /*
+  * Returns: 1 if drive can be reserved
+  *          0 if we should wait
+@@ -1285,6 +1357,11 @@
+          rctx.PreferMountedVols, rctx.exact_match, rctx.suitable_device,
+          rctx.autochanger_only, rctx.any_drive);
++   /* Check for max jobs on this Volume */
++   if (!is_max_jobs_ok(dcr)) {
++      return 0;
++   }
++
+    /* setting any_drive overrides PreferMountedVols flag */
+    if (!rctx.any_drive) {
+       /*
+@@ -1374,32 +1451,10 @@
+    if (dev->num_writers == 0) {
+       /* Now check if there are any reservations on the drive */
+       if (dev->reserved_device) {           
+-         /* Now check if we want the same Pool and pool type */
+-         if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
+-             strcmp(dev->pool_type, dcr->pool_type) == 0) {
+-            /* OK, compatible device */
+-            Dmsg2(dbglvl, "jid=%u OK dev: %s num_writers=0, reserved, pool matches\n",
+-               jcr->JobId, dev->print_name());
+-            return 1;
+-         } else {
+-            /* Drive Pool not suitable for us */
+-            Mmsg(jcr->errmsg, _(
+-"3608 JobId=%u wants Pool=\"%s\" but have Pool=\"%s\" nreserve=%d on drive %s.\n"), 
+-                  jcr->JobId, dcr->pool_name, dev->pool_name,
+-                  dev->reserved_device, dev->print_name());
+-            queue_reserve_message(jcr);
+-            Dmsg3(dbglvl, "jid=%u failed: busy num_writers=0, reserved, pool=%s wanted=%s\n",
+-               (int)jcr->JobId, dev->pool_name, dcr->pool_name);
+-            return 0;                 /* wait */
+-         }
++         return is_pool_ok(dcr);
+       } else if (dev->can_append()) {
+-         /* Device in append mode, check if changing pool */
+-         if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
+-             strcmp(dev->pool_type, dcr->pool_type) == 0) {
+-            Dmsg2(dbglvl, "jid=%u OK dev: %s num_writers=0, can_append, pool matches.\n",
+-               jcr->JobId, dev->print_name());
+-            /* OK, compatible device */
+-            return 1;
++         if (is_pool_ok(dcr)) {
++            return 1; 
+          } else {
+             /* Changing pool, unload old tape if any in drive */
+             Dmsg1(dbglvl, "jid=%u OK dev: num_writers=0, not reserved, pool change, unload changer\n",
+@@ -1419,22 +1474,7 @@
+     *  available if pool is the same).
+     */
+    if (dev->can_append() || dev->num_writers > 0) {
+-      /* Yes, now check if we want the same Pool and pool type */
+-      if (strcmp(dev->pool_name, dcr->pool_name) == 0 &&
+-          strcmp(dev->pool_type, dcr->pool_type) == 0) {
+-         Dmsg2(dbglvl, "jid=%u OK dev: %s num_writers>=0, can_append, pool matches.\n",
+-            jcr->JobId, dev->print_name());
+-         /* OK, compatible device */
+-         return 1;
+-      } else {
+-         /* Drive Pool not suitable for us */
+-         Mmsg(jcr->errmsg, _("3609 JobId=%u wants Pool=\"%s\" but has Pool=\"%s\" on drive %s.\n"), 
+-               jcr->JobId, dcr->pool_name, dev->pool_name, dev->print_name());
+-         queue_reserve_message(jcr);
+-         Dmsg3(dbglvl, "jid=%u failed: busy num_writers>0, can_append, pool=%s wanted=%s\n",
+-            (int)jcr->JobId, dev->pool_name, dcr->pool_name);
+-         return 0;                    /* wait */
+-      }
++      return is_pool_ok(dcr);
+    } else {
+       Pmsg1(000, _("Logic error!!!! JobId=%u Should not get here.\n"), (int)jcr->JobId);
+       Mmsg(jcr->errmsg, _("3910 JobId=%u Logic error!!!! drive %s Should not get here.\n"),