]> git.sur5r.net Git - bacula/bacula/commitdiff
kes Rework many features of DVD writing and reading. Added many error
authorKern Sibbald <kern@sibbald.com>
Sun, 27 Aug 2006 18:30:57 +0000 (18:30 +0000)
committerKern Sibbald <kern@sibbald.com>
Sun, 27 Aug 2006 18:30:57 +0000 (18:30 +0000)
     messages.  Most importantly changed part to represent the current
     part number base zero. This makes current DVD writing incompatible
     with previous version.
26Aug06
kes  Add host:port to connect failure messages to FD and SD from Dir.
kes  Add WhereACL to console ACL list.  If nothing is specified, only
     the default is permitted for restore. Otherwise, *all* allows any
     path, or you can specify permitted paths. This should allow control
     over where users can restore files. This is untested.
kes  Modified message to add a ? (as in loaded?) when querying the autochanger
     for what Slot is loaded.
kes  Fixed the use of Slot, so that is more correctly maintained, thus
     eliminating unneeded duplicate calls to determine what Slot is loaded.

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

12 files changed:
bacula/manpages/Makefile.in
bacula/scripts/dvd-handler.in
bacula/src/stored/block.c
bacula/src/stored/dev.c
bacula/src/stored/dev.h
bacula/src/stored/dircmd.c
bacula/src/stored/dvd.c
bacula/src/stored/match_bsr.c
bacula/src/stored/protos.h
bacula/src/stored/read_record.c
bacula/src/version.h
bacula/technotes-1.39

index 3bea3bb23ebeb9e268d88e8f1a8f7164d169020d..2e0d4c58fb375576155bcf8f5e51d2b7cfb994eb 100644 (file)
@@ -11,6 +11,8 @@ MAN8 = bacula.8 bacula-dir.8 bacula-fd.8 bacula-sd.8 \
 MAN1 = bacula-console-gnome.1 bacula-tray-monitor.1 \
        bacula-wxconsole.1 bsmtp.1
       
+all:
+
 nothing:
 
 depend:
index f51e9473d0d4331ad0945ba82acd3c65bfa89237..66e258c5f3641a8dac5dc618550df41fea317e39 100644 (file)
@@ -430,7 +430,7 @@ if "free" == sys.argv[2]:
         print free
         print "No Error reported."
    else:
-      print "Wrong number of arguments for free operation."
+      print "Wrong number of arguments for free operation. Wanted 3 got", len(sys.argv)
       usage()
 elif "prepare" == sys.argv[2]:
    if len(sys.argv) == 3:
@@ -445,7 +445,7 @@ elif "prepare" == sys.argv[2]:
       else:
         print "Medium prepared successfully."
    else:
-      print "Wrong number of arguments for prepare operation."
+      print "Wrong number of arguments for prepare operation. Wanted 3 got", len(sys.argv)
       usage()
 elif "test" == sys.argv[2]:
    try:
@@ -467,7 +467,7 @@ elif "write" == sys.argv[2]:
       else:
         print "Part file " + sys.argv[4] + " successfully written to disk."
    else:
-      print "Wrong number of arguments for write operation."
+      print "Wrong number of arguments for write operation. Wanted 5 got", len(sys.argv)
       usage()
       sys.exit(1)
 else:
index 75a86fd8be840873842fb529a672c89fc9734d30..136175601a1c40a5e6865eafda430992b734691e 100644 (file)
@@ -710,8 +710,10 @@ static bool terminate_writing_volume(DCR *dcr)
    dev->VolCatInfo.VolCatJobs++;              /* increment number of jobs */
    
    if (dev->is_dvd()) {
-      dvd_write_part(dcr);                 /* write last part */
-      dev->VolCatInfo.VolCatParts = dev->num_parts;
+      if (!dvd_write_part(dcr)) {             /* write last part */
+         ok = false;
+      }
+      dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
    }
    
    if (!dir_update_volume_info(dcr, false)) {
@@ -806,10 +808,10 @@ static bool do_dvd_size_checks(DCR *dcr)
    /* Limit maximum part size to value specified by user 
     */
    if (dev->max_part_size > 0 && ((dev->part_size + block->binbuf) >= dev->max_part_size)) {
-      if (dev->part < dev->num_parts) {
+      if (dev->part < dev->num_dvd_parts) {
          Jmsg3(dcr->jcr, M_FATAL, 0, _("Error while writing, current part number"
                " is less than the total number of parts (%d/%d, device=%s)\n"),
-               dev->part, dev->num_parts, dev->print_name());
+               dev->part, dev->num_dvd_parts, dev->print_name());
          dev->dev_errno = EIO;
          return false;
       }
@@ -821,7 +823,7 @@ static bool do_dvd_size_checks(DCR *dcr)
          return false;
       }
       
-      dev->VolCatInfo.VolCatParts = dev->num_parts;
+      dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
             
       if (!dir_update_volume_info(dcr, false)) {
          Dmsg0(190, "Error from update_vol_info.\n");
@@ -915,14 +917,14 @@ reread:
    Dmsg1(100, "dev->file_size-dev->part_start=%u\n",(unsigned int)dev->file_size-dev->part_start);
    Dmsg1(100, "dev->part_size=%u\n", (unsigned int)dev->part_size);
    Dmsg1(100, "dev->part=%u\n", (unsigned int)dev->part);
-   Dmsg1(100, "dev->num_parts=%u\n", (unsigned int)dev->num_parts);
+   Dmsg1(100, "dev->num_dvd_parts=%u\n", (unsigned int)dev->num_dvd_parts);
    Dmsg1(100, "dev->VolCatInfo.VolCatParts=%u\n", (unsigned int)dev->VolCatInfo.VolCatParts);
    Dmsg3(100, "Tests : %d %d %d\n", (dev->VolCatInfo.VolCatParts > 0), 
          ((dev->file_addr-dev->part_start) == dev->part_size), 
          (dev->part <= dev->VolCatInfo.VolCatParts));*/
    /* Check for DVD part file end */
-   if (dev->at_eof() && dev->is_dvd() && dev->num_parts > 0 &&
-        dev->part < dev->num_parts) {
+   if (dev->at_eof() && dev->is_dvd() && dev->num_dvd_parts > 0 &&
+        dev->part < dev->num_dvd_parts) {
       if (dvd_open_next_part(dcr) < 0) {
          Jmsg3(dcr->jcr, M_FATAL, 0, _("Unable to open device part=%d %s: ERR=%s\n"),
                dev->part, dev->print_name(), dev->bstrerror());
index 43eec74d982e92cdbad5168043b51a73b686563e..4dc9352d14538f639ffdc0c2eb3a0f33e0b51e45 100644 (file)
@@ -294,7 +294,7 @@ DEVICE::open(DCR *dcr, int omode)
       open_file_device(dcr, omode);
    }
    state |= preserve;                 /* reset any important state info */
-   Dmsg1(100, "preserve=0x%x\n", preserve);
+   Dmsg2(100, "preserve=0x%x fd=%d\n", preserve, fd);
    return fd;
 }
 
@@ -341,7 +341,7 @@ void DEVICE::open_tape_device(DCR *dcr, int omode)
       mode_to_str(omode), nonblocking);
    /* Use system open() */
 
-#ifdef HAVE_WIN32
+#if defined(HAVE_WIN32)
    if ((fd = tape_open(dev_name, mode)) < 0) {
       berrno be;
       dev_errno = errno;
@@ -469,7 +469,7 @@ void DEVICE::open_file_device(DCR *dcr, int omode)
       update_pos_dev(this);                /* update position */
    }
    Dmsg4(29, "open dev: disk fd=%d opened, part=%d/%d, part_size=%u\n", 
-      fd, part, num_parts, part_size);
+      fd, part, num_dvd_parts, part_size);
 }
 
 /*
@@ -489,6 +489,17 @@ void DEVICE::open_dvd_device(DCR *dcr, int omode)
    Dmsg3(29, "Enter: open_dvd_dev: %s dev=%s mode=%s\n", is_dvd()?"DVD":"disk",
          archive_name.c_str(), mode_to_str(omode));
 
+   /*
+    * For a DVD we must alway pull the state info from dcr->VolCatInfo
+    *  This is a bit ugly, but is necessary because we need to open/close/re-open
+    *  the dvd file in order to properly mount/unmount and access the
+    *  DVD. So we store the state of the DVD as far as is known in the 
+    *  catalog in dcr->VolCatInfo, and thus we refresh the dev->VolCatInfo
+    *  copy here, when opening.
+    */
+   memcpy(&VolCatInfo, &dcr->VolCatInfo, sizeof(VolCatInfo));
+   Dmsg1(100, "Volume=%s\n", VolCatInfo.VolCatName);
+
    if (VolCatInfo.VolCatName[0] == 0) {
       Dmsg1(10,  "Could not open file device %s. No Volume name given.\n",
          print_name());
@@ -499,25 +510,29 @@ void DEVICE::open_dvd_device(DCR *dcr, int omode)
    }
 
    if (part == 0) {
+      Dmsg0(100, "Set part=1\n");
+      part = 1;                       /* count from 1 */
       file_size = 0;
    }
    part_size = 0;
+   if (num_dvd_parts != VolCatInfo.VolCatParts) {
+      num_dvd_parts = VolCatInfo.VolCatParts;
+   }
    // Clear any previous truncated_dvd status - we will recalculate it here
    truncated_dvd = false;
 
-   Dmsg2(99, "open_dvd_device: num_parts=%d, VolCatInfo.VolCatParts=%d\n",
-      dcr->dev->num_parts, dcr->VolCatInfo.VolCatParts);
-   if (dcr->dev->num_parts < dcr->VolCatInfo.VolCatParts) {
-      Dmsg2(99, "open_dvd_device: num_parts updated to %d (was %d)\n",
-         dcr->VolCatInfo.VolCatParts, dcr->dev->num_parts);
-      dcr->dev->num_parts = dcr->VolCatInfo.VolCatParts;
-   }
-
+   Dmsg3(99, "open_dvd_device: part=%d num_dvd_parts=%d, VolCatInfo.VolCatParts=%d\n",
+      part, num_dvd_parts, dcr->VolCatInfo.VolCatParts);
+     
    if (mount_dvd(this, 1)) {
-      if ((num_parts == 0) && (!truncating)) {
-         /* If we can mount the device, and we are not truncating the DVD, we usually want to abort. */
-         /* There is one exception, if there is only one 0-sized file on the DVD, with the right volume name,
-          * we continue (it's the method used by truncate_dvd to truncate a volume). */
+      Dmsg0(99, "DVD device mounted.\n");
+      if ((num_dvd_parts == 0) && (!truncating)) {
+         /*
+          * If we can mount the device, and we are not truncating the DVD, 
+          * we usually want to abort. There is one exception, if there is 
+          * only one 0-sized file on the DVD, with the right volume name,
+          * we continue (it's the method used by truncate_dvd to truncate a volume).   
+          */
          if (!check_can_write_on_non_blank_dvd(dcr)) {
             Mmsg(errmsg, _("The media in the device %s is not empty, please blank it before writing anything to it.\n"), print_name());
             Emsg0(M_FATAL, 0, errmsg);
@@ -528,21 +543,24 @@ void DEVICE::open_dvd_device(DCR *dcr, int omode)
          truncated_dvd = true;
       }
    } else {
+      Dmsg0(99, "DVD device mount failed.\n");
       /* We cannot mount the device */
-      if (num_parts == 0) {
+      if (num_dvd_parts == 0) {
          /* Run free space, check there is a media. */
-         update_free_space_dev(this);
-         if (have_media()) {
-            Dmsg1(29, "Could not mount device %s, this is not a problem (num_parts == 0), and have media.\n", print_name());
+         if (!update_free_space_dev(this)) {
+            Emsg0(M_FATAL, 0, errmsg);
+            clear_opened();
+            return;
          }
-         else {
+         if (have_media()) {
+            Dmsg1(29, "Could not mount device %s, this is not a problem (num_dvd_parts == 0), and have media.\n", print_name());
+         } else {
             Mmsg(errmsg, _("There is no valid media in the device %s.\n"), print_name());
             Emsg0(M_FATAL, 0, errmsg);
             clear_opened();
             return;
          }
-      }
-      else {
+      }  else {
          Mmsg(errmsg, _("Could not mount device %s.\n"), print_name());
          Emsg0(M_FATAL, 0, errmsg);
          clear_opened();
@@ -550,9 +568,9 @@ void DEVICE::open_dvd_device(DCR *dcr, int omode)
       }
    }
    
-   Dmsg6(29, "open dev: %s dev=%s mode=%s part=%d npart=%d volcatnparts=%d\n", 
-      is_dvd()?"DVD":"disk", archive_name.c_str(), mode_to_str(omode),
-      part, num_parts, dcr->VolCatInfo.VolCatParts);
+   Dmsg5(29, "open dev: DVD dev=%s mode=%s part=%d npart=%d volcatnparts=%d\n", 
+      archive_name.c_str(), mode_to_str(omode),
+      part, num_dvd_parts, dcr->VolCatInfo.VolCatParts);
    openmode = omode;
    Dmsg2(100, "openmode=%d %s\n", openmode, mode_to_str(openmode));
    
@@ -560,11 +578,11 @@ void DEVICE::open_dvd_device(DCR *dcr, int omode)
     * If we are not trying to access the last part, set mode to 
     *   OPEN_READ_ONLY as writing would be an error.
     */
-   if (part < num_parts) {
+   Dmsg2(29, "open DVD part=%d num_dvd_parts=%d\n", part, num_dvd_parts);
+   if (part <= num_dvd_parts) {
       omode = OPEN_READ_ONLY;
       make_mounted_dvd_filename(this, archive_name);
-   }
-   else {
+   } else {
       make_spooled_dvd_filename(this, archive_name);
    }
    set_mode(omode);
@@ -582,13 +600,13 @@ void DEVICE::open_dvd_device(DCR *dcr, int omode)
       Dmsg1(29, "open failed: %s", errmsg);
       
       if ((omode == OPEN_READ_ONLY || omode == OPEN_READ_WRITE) &&
-          (part == num_parts)) {
+          (part > num_dvd_parts)) {
          /* If the last part (on spool), doesn't exists when accessing,
           * create it. In read/write mode a write will be allowed (higher
           * level software thinks that we are extending a pre-existing
           * media. Reads for READ_ONLY will report immediately an EOF 
           * Sometimes it is better to finish with an EOF than with an error. */
-         Dmsg0(29, "Creating last part on spool to make our caller happy\n");
+         Dmsg1(29, "Creating last part on spool: %s\n", archive_name.c_str());
          set_mode(CREATE_READ_WRITE);
          fd = ::open(archive_name.c_str(), mode, 0640);
          set_mode(omode);
@@ -620,15 +638,18 @@ void DEVICE::open_dvd_device(DCR *dcr, int omode)
          /* NB: It seems this code is wrong... part number is incremented in open_next_part, not here */
          
          /* Check if just created Volume  part */
-/*         if (omode == OPEN_READ_WRITE && (part == 0 || part_size == 0)) {
-            part++;
-            num_parts = part;
-            VolCatInfo.VolCatParts = num_parts;
-         } else {
-            if (part == 0) {             // we must have opened the first part
-               part++;
-            }
-         }*/
+/*
+ *         if (omode == OPEN_READ_WRITE && (part == 0 || part_size == 0)) {
+ *          part++;
+ *          num_dvd_parts = part;
+ *          VolCatInfo.VolCatParts = num_dvd_parts;
+ *       } else {
+ *          if (part == 0) {             // we must have opened the first part
+ *             part++;
+ *          }
+ *       }
+ */
+
       }
    }
 }
@@ -1155,7 +1176,6 @@ bool DEVICE::offline()
    block_num = file = 0;
    file_size = 0;
    file_addr = 0;
-   part = 0;
 #ifdef MTUNLOCK
    mt_com.mt_op = MTUNLOCK;
    mt_com.mt_count = 1;
@@ -1772,17 +1792,21 @@ void DEVICE::close()
    }
    
    /* Remove the last part file if it is empty */
-   if (num_parts > 0) {
+   if (num_dvd_parts > 0) {
       struct stat statp;
+      int part_save = part;
       POOL_MEM archive_name(PM_FNAME);
-      part = num_parts;
-      Dmsg1(100, "Call make_dvd_filename. Vol=%s\n", VolCatInfo.VolCatName);
+
+      part = num_dvd_parts;
+      Dmsg3(100, "Remove empty part in close call make_dvd_filename. part=%d num=%d vol=%s\n", 
+         part, num_dvd_parts, VolCatInfo.VolCatName);
       make_spooled_dvd_filename(this, archive_name);
       /* Check that the part file is empty */
       if ((stat(archive_name.c_str(), &statp) == 0) && (statp.st_size == 0)) {
          Dmsg1(100, "unlink(%s)\n", archive_name.c_str());
          unlink(archive_name.c_str());
       }
+      part = part_save;               /* restore part number */
    }
    
    /* Clean up device packet so it can be reused */
@@ -1792,10 +1816,6 @@ void DEVICE::close()
    file = block_num = 0;
    file_size = 0;
    file_addr = 0;
-   part = 0;
-   num_parts = 0;
-   part_size = 0;
-   part_start = 0;
    EndFile = EndBlock = 0;
    Slot = -1;             /* unknown slot */
    free_volume(this);
@@ -2008,7 +2028,7 @@ void DEVICE::edit_mount_codes(POOL_MEM &omsg, const char *imsg)
             str = dev_name;
             break;
          case 'e':
-            if (num_parts == 0) {
+            if (num_dvd_parts == 0) {
                if (truncating || truncated_dvd) {
                   str = "2";
                } else {
@@ -2255,5 +2275,10 @@ static char *modes[] = {
 
 static char *mode_to_str(int mode)  
 {
+   static char buf[100];
+   if (mode < 1 || mode > 4) {
+      bsnprintf(buf, sizeof(buf), "BAD mode=%d", mode);
+      return buf;
+    }
    return modes[mode-1];
 }
index 3f4d13e2239d665001b121a9e68de06e54de175a..af494d5ecdbe7b9fe1ce01b37c6123c4a6487db9 100644 (file)
@@ -241,7 +241,7 @@ public:
    uint64_t part_size;                /* current part size */
    uint32_t part;                     /* current part number (starts at 0) */
    uint64_t part_start;               /* current part start address (relative to the whole volume) */
-   uint32_t num_parts;                /* number of parts WRITTEN on the DVD */
+   uint32_t num_dvd_parts;            /* number of parts WRITTEN on the DVD */
    /* state ST_FREESPACE_OK is set if free_space is valid */
    uint64_t free_space;               /* current free space on medium (without the current part) */
    int free_space_errno;              /* indicates errno getting freespace */
index 7a22f56521a2b83a946c47a13e7f0366c4692280..d1134f140e15a11392d7e0d923b79452bd93852b 100644 (file)
@@ -392,6 +392,7 @@ static void label_volume_if_ok(DCR *dcr, char *oldname,
    DEVICE *dev = dcr->dev;
    int label_status;
    int mode;
+   const char *volname = (relabel == 0) ? newname : oldname;
 
    steal_device_lock(dev, &hold, BST_WRITING_LABEL);
    Dmsg1(100, "Stole device %s lock, writing label.\n", dev->print_name());
@@ -401,7 +402,7 @@ static void label_volume_if_ok(DCR *dcr, char *oldname,
       dcr->VolCatInfo.VolCatParts=1;
    }
 
-   if (!try_autoload_device(dcr->jcr, slot, (relabel == 0) ? newname : oldname)) {
+   if (!try_autoload_device(dcr->jcr, slot, volname)) {
       goto bail_out;                  /* error */
    }
 
@@ -411,6 +412,10 @@ static void label_volume_if_ok(DCR *dcr, char *oldname,
    } else {
       mode = CREATE_READ_WRITE;
    }
+   if (dev->is_dvd()) {
+      bstrncpy(dcr->VolCatInfo.VolCatName, volname, sizeof(dcr->VolCatInfo.VolCatName));
+   }
+
    if (dev->open(dcr, mode) < 0) {
       bnet_fsend(dir, _("3910 Unable to open device %s: ERR=%s\n"),
          dev->print_name(), dev->strerror());
index 3bb1d6733af2cac001e6a3e998c94ca360cbe6e1..9201a4844de3097ad714f2849044efc32a2c6680 100644 (file)
@@ -60,12 +60,12 @@ static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name)
 
    pm_strcat(archive_name, dev->VolCatInfo.VolCatName);
    /* if part > 1, append .# to the filename (where # is the part number) */
-   if (dev->part > 0) {
+   if (dev->part > 1) {
       pm_strcat(archive_name, ".");
       bsnprintf(partnumber, sizeof(partnumber), "%d", dev->part);
       pm_strcat(archive_name, partnumber);
    }
-   Dmsg1(400, "Exit make_dvd_filename: arch=%s\n", archive_name.c_str());
+   Dmsg1(400, "Exit add_file_part_name: arch=%s\n", archive_name.c_str());
 }  
 
 /* Mount the device.
@@ -135,8 +135,10 @@ static bool do_mount_dvd(DEVICE* dev, int mount, int dotimeout)
    results = get_memory(2000);
    results[0] = 0;
    /* If busy retry each second */
+   Dmsg1(100, "Run prog=%s\n", ocmd.c_str());
    while ((status = run_program_full_output(ocmd.c_str(), 
                        dev->max_open_wait/2, results)) != 0) {
+      Dmsg2(99, "Mount status=%d result=%s\n", status, results);
       /* Doesn't work with internationalisation (This is not a problem) */
       if (mount && fnmatch("*is already mounted on*", results, 0) == 0) {
          break;
@@ -154,10 +156,18 @@ static bool do_mount_dvd(DEVICE* dev, int mount, int dotimeout)
          bmicrosleep(1, 0);
          continue;
       }
-      Dmsg3(40, "Device %s cannot be %smounted. ERR=%s\n", dev->print_name(),
-           (mount ? "" : "un"), results);
-      Mmsg(dev->errmsg, _("Device %s cannot be %smounted. ERR=%s\n"), 
-           dev->print_name(), (mount ? "" : "un"), results);
+      if (status != 0) {
+         berrno be;
+         Dmsg5(40, "Device %s cannot be %smounted. stat=%d result=%s ERR=%s\n", dev->print_name(),
+              (mount ? "" : "un"), status, results, be.strerror(status));
+         Mmsg(dev->errmsg, _("Device %s cannot be %smounted. ERR=%s\n"), 
+              dev->print_name(), (mount ? "" : "un"), be.strerror(status));
+      } else {
+         Dmsg4(40, "Device %s cannot be %smounted. stat=%d ERR=%s\n", dev->print_name(),
+              (mount ? "" : "un"), status, results);
+         Mmsg(dev->errmsg, _("Device %s cannot be %smounted. ERR=%s\n"), 
+              dev->print_name(), (mount ? "" : "un"), results);
+      }
       /*
        * Now, just to be sure it is not mounted, try to read the
        *  filesystem.
@@ -192,9 +202,9 @@ static bool do_mount_dvd(DEVICE* dev, int mount, int dotimeout)
          if (strcmp(result->d_name, ".") && strcmp(result->d_name, "..") && 
              strcmp(result->d_name, ".keep")) {
             count++; /* result->d_name != ., .. or .keep (Gentoo-specific) */
+            Dmsg1(100, "Inc count=%d\n", count);
             break;
-         }
-         else {
+         } else {
             Dmsg2(129, "do_mount_dvd: ignoring %s in %s\n", 
                   result->d_name, dev->device->mount_point);
          }
@@ -208,12 +218,13 @@ static bool do_mount_dvd(DEVICE* dev, int mount, int dotimeout)
          /* If we got more than ., .. and .keep */
          /*   there must be something mounted */
          if (mount) {
+            Dmsg1(100, "Did Mount by count=%d\n", count);
             break;
          } else {
             /* An unmount request. We failed to unmount - report an error */
             dev->set_mounted(true);
             free_pool_memory(results);
-            Dmsg0(200, "============ DVD mount=1\n");
+            Dmsg0(200, "== DVD mount=1\n");
             return false;
          }
       }
@@ -221,29 +232,35 @@ get_out:
       dev->set_mounted(false);
       sm_check(__FILE__, __LINE__, false);
       free_pool_memory(results);
-      Dmsg0(200, "============ DVD mount=0\n");
+      Dmsg0(200, "== DVD mount=0\n");
       return false;
    }
+   Dmsg0(100, "Out of mount/umount loop\n");
    
    dev->set_mounted(mount);              /* set/clear mounted flag */
    free_pool_memory(results);
    /* Do not check free space when unmounting */
    if (mount) {
-      update_free_space_dev(dev);
+      Dmsg0(100, "Calling update_free_space\n");
+      if (!update_free_space_dev(dev)) {
+         return false;
+      }
    }
-   Dmsg1(200, "============ DVD mount=%d\n", mount);
+   Dmsg1(200, "== DVD mount=%d\n", mount);
    return true;
 }
 
 /* Update the free space on the device */
-void update_free_space_dev(DEVICE* dev) 
+bool update_free_space_dev(DEVICE* dev) 
 {
    POOL_MEM ocmd(PM_FNAME);
    POOLMEM* results;
    char* icmd;
    int timeout;
-   long long int free;
+   uint64_t free;
    char ed1[50];
+   bool ok = false;
+   int status;
    
    /* The device must be mounted in order to dvd-freespace to work */
    mount_dvd(dev, 1);
@@ -256,9 +273,10 @@ void update_free_space_dev(DEVICE* dev)
       dev->free_space_errno = 0;
       dev->clear_freespace_ok();   /* No valid freespace */
       dev->clear_media();
-      Dmsg2(29, "update_free_space_dev: free_space=%s, free_space_errno=%d (!icmd)\n", 
+      Dmsg2(29, "ERROR: update_free_space_dev: free_space=%s, free_space_errno=%d (!icmd)\n", 
             edit_uint64(dev->free_space, ed1), dev->free_space_errno);
-      return;
+      Mmsg(dev->errmsg, _("No FreeSpace command defined.\n"));
+      return false;
    }
    
    dev->edit_mount_codes(ocmd, icmd);
@@ -271,22 +289,27 @@ void update_free_space_dev(DEVICE* dev)
    timeout = 3;
    
    while (1) {
-      if (run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results) == 0) {
-         Dmsg1(400, "Free space program run : %s\n", results);
+      berrno be;
+      Dmsg1(100, "Run prog=%s\n", ocmd.c_str());
+      status = run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results);
+      if (status == 0) {
          free = str_to_int64(results);
+         Dmsg1(400, "Free space program run: Freespace=%s\n", results);
          if (free >= 0) {
             dev->free_space = free;
             dev->free_space_errno = 0;
             dev->set_freespace_ok();     /* have valid freespace */
             dev->set_media();
-            Mmsg0(dev->errmsg, "");
+            Mmsg(dev->errmsg, "");
+            ok = true;
             break;
          }
       }
       dev->free_space = 0;
       dev->free_space_errno = EPIPE;
       dev->clear_freespace_ok();         /* no valid freespace */
-      Mmsg1(dev->errmsg, _("Cannot run free space command (%s)\n"), results);
+      Mmsg2(dev->errmsg, _("Cannot run free space command. Results=%s ERR=%s\n"), 
+            results, be.strerror(status));
       
       if (--timeout > 0) {
          Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
@@ -306,20 +329,25 @@ void update_free_space_dev(DEVICE* dev)
    }
    
    free_pool_memory(results);
-   Dmsg4(29, "update_free_space_dev: free_space=%s freespace_ok=%d free_space_errno=%d have_media=%d\n", 
+   Dmsg4(29, "leave update_free_space_dev: free_space=%s freespace_ok=%d free_space_errno=%d have_media=%d\n", 
       edit_uint64(dev->free_space, ed1), !!dev->is_freespace_ok(), dev->free_space_errno, !!dev->have_media());
    sm_check(__FILE__, __LINE__, false);
-   return;
+   return ok;
 }
 
 /*
- * Write a part (Vol, Vol.1, ...) from the spool to the DVD   
+ * Note!!!! Part numbers now begin at 1. The part number is
+ *  suppressed from the first part, which is just the Volume
+ *  name. Each subsequent part is the Volumename.partnumber.
+ *
+ * Write a part (Vol, Vol.2, ...) from the spool to the DVD   
  * This routine does not update the part number, so normally, you
  *  should call open_next_part()
+ *
  * It is also called from truncate_dvd to "blank" the medium, as
  *  well as from block.c when the DVD is full to write the last part.
  */
-bool dvd_write_part(DCR *dcr) 
+bool dvd_write_part(DCR *dcr)
 {
    DEVICE *dev = dcr->dev;
    POOL_MEM archive_name(PM_FNAME);
@@ -336,10 +364,11 @@ bool dvd_write_part(DCR *dcr)
     *   - Bacula thinks he must finish to write to the device, so it
     *     tries to write the last part (0-byte), but dvd-writepart fails...
     *
+    *  ***FIXME****  we cannot write a blank part!!!!!!!
     * There is one exception: when recycling a volume, we write a blank part
     * file, so, then, we need to accept to write it.
     */
-   if ((dev->part_size == 0) && (dev->part > 0)) {
+   if (dev->part_size == 0) {
       Dmsg2(29, "dvd_write_part: device is %s, won't write blank part %d\n", dev->print_name(), dev->part);
       /* Delete spool file */
       make_spooled_dvd_filename(dev, archive_name);
@@ -380,7 +409,7 @@ bool dvd_write_part(DCR *dcr)
     * in case of a serious emergency.
     */
 
-   if (dev->part == 0)
+   if (dev->part == 1)
       timeout = 16000;
    else
       timeout = dev->max_open_wait + (dev->part_size/(1350*1024/4));
@@ -388,17 +417,25 @@ bool dvd_write_part(DCR *dcr)
    Dmsg2(29, "dvd_write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
       
    status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
-   dev->truncated_dvd = false; // Clear this status now write has finished
+
    if (status != 0) {
+      Jmsg2(dcr->jcr, M_FATAL, 0, _("Error writing part %d to the DVD: ERR=%s\n"),
+         dev->part, results.c_str());
       Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"), 
             results.c_str());
       Dmsg1(000, "%s\n", dev->errmsg);
       dev->dev_errno = EIO;
       mark_volume_in_error(dcr);
       sm_check(__FILE__, __LINE__, false);
+      dev->truncated_dvd = false;
       return false;
-   } else {
-      dev->num_parts++;            /* there is now one more part on DVD */
+   }
+   Jmsg(dcr->jcr, M_INFO, 0, _("Part %d written to DVD.\n"), dev->part);
+   if (dev->truncated_dvd) {
+      dev->truncated_dvd = false;   /* turn off flag */
+   } else {                         /* DVD part written */
+      dev->num_dvd_parts++;            /* there is now one more part on DVD */
+      dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
    }
 
    /* Delete spool file */
@@ -416,7 +453,8 @@ bool dvd_write_part(DCR *dcr)
    return true;
 }
 
-/* Open the next part file.
+/*
+ * Open the next part file.
  *  - Close the fd
  *  - Increment part number 
  *  - Reopen the device
@@ -424,9 +462,10 @@ bool dvd_write_part(DCR *dcr)
 int dvd_open_next_part(DCR *dcr)
 {
    DEVICE *dev = dcr->dev;
+   VOLUME_LABEL VolHdr;
 
-   Dmsg6(29, "Enter: ==== open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n", 
-      dev->part, dev->num_parts, dev->print_name(),
+   Dmsg6(29, "Enter: == open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n", 
+      dev->part, dev->num_dvd_parts, dev->print_name(),
          dev->VolCatInfo.VolCatName, dev->openmode, dev->file_addr);
    if (!dev->is_dvd()) {
       Dmsg1(000, "Device %s is not dvd!!!!\n", dev->print_name()); 
@@ -434,40 +473,39 @@ int dvd_open_next_part(DCR *dcr)
    }
    
    /* When appending, do not open a new part if the current is empty */
-   if (dev->can_append() && (dev->part >= dev->num_parts) && 
+   if (dev->can_append() && (dev->part > dev->num_dvd_parts) && 
        (dev->part_size == 0)) {
       Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
       return dev->fd;
    }
-   
-   if (dev->fd >= 0) {
-      close(dev->fd);
-   }
-   
-   dev->fd = -1;
-   dev->clear_opened();
+
+   /*              
+    * Note, when we close, the Volume header is zeroed. Since
+    *  we reopen, but are in fact opening the same volume without
+    *  re-reading the Volume header, we simply save and restore it.
+    */
+   memcpy(&VolHdr, &dev->VolHdr, sizeof(VolHdr));
+   dev->close();                      /* close current part */
+   memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
    
    /*
     * If we have a part open for write, then write it to
     *  DVD before opening the next part.
     */
-   if (dev->is_dvd() && (dev->part >= dev->num_parts) && dev->can_append()) {
+   if (dev->part > dev->num_dvd_parts && dev->can_append()) {
+      Dmsg2(100, "Before open next write previous. part=%d num_parts=%d\n",
+         dev->part, dev->num_dvd_parts);
       if (!dvd_write_part(dcr)) {
          Dmsg0(29, "Error in dvd_write part.\n");
          return -1;
       }
    }
      
-   if (dev->part > dev->num_parts) {
-      Dmsg2(000, "In open_next_part: part=%d nump=%d\n", dev->part, dev->num_parts);
-      ASSERT(dev->part <= dev->num_parts);
-   }
    dev->part_start += dev->part_size;
    dev->part++;
-   
-   Dmsg2(29, "part=%d num_parts=%d\n", dev->part, dev->num_parts);
-   /* I think this dev->can_append() should not be there */
-   if ((dev->num_parts < dev->part) && dev->can_append()) {
+   Dmsg2(29, "Inc part=%d num_dvd_parts=%d\n", dev->part, dev->num_dvd_parts);
+
+   if (dev->num_dvd_parts < dev->part) {
       POOL_MEM archive_name(PM_FNAME);
       struct stat buf;
       /* 
@@ -476,8 +514,9 @@ int dvd_open_next_part(DCR *dcr)
        * NB: This is however not a problem if we are writing the first part.
        * It simply means that we are overriding an existing volume...
        */
-      if (dev->num_parts > 0) {
+      if (dev->num_dvd_parts > 0) {
          make_mounted_dvd_filename(dev, archive_name);   /* makes dvd name */
+         Dmsg1(100, "Check if part on DVD: %s\n", archive_name.c_str());
          if (stat(archive_name.c_str(), &buf) == 0) {
             /* bad news bail out */
             Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
@@ -486,13 +525,13 @@ int dvd_open_next_part(DCR *dcr)
          }
       }
 
-      Dmsg2(400, "num_parts=%d part=%d\n", dev->num_parts, dev->part);
-      dev->VolCatInfo.VolCatParts = dev->part;
+      Dmsg2(400, "num_dvd_parts=%d part=%d\n", dev->num_dvd_parts, dev->part);
       make_spooled_dvd_filename(dev, archive_name);   /* makes spool name */
       
       /* Check if the next part exists in spool directory . */
+      Dmsg1(100, "Check if part on spool: $s\n", archive_name.c_str());
       if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
-         Dmsg1(29, "open_next_part %s is in the way, moving it away...\n", archive_name.c_str());
+         Dmsg1(29, "open_next_part %s is in the way, deleting it...\n", archive_name.c_str());
          /* Then try to unlink it */
          if (unlink(archive_name.c_str()) < 0) {
             berrno be;
@@ -503,62 +542,61 @@ int dvd_open_next_part(DCR *dcr)
          }
       }
    }
-   /* KES.  It seems to me that this if should not be
-    *  needed. If num_parts represents what is on the DVD
-    *  we should only need to change it when writing a part
-    *  to the DVD.
-    * NB. As dvd_write_part increments dev->num_parts, I also
-    *  think it is not needed.
-    */
-   if (dev->num_parts < dev->part) {
-      Dmsg2(400, "Set npart=%d to part=%d\n", dev->num_parts, dev->part);
-      dev->num_parts = dev->part;
-      dev->VolCatInfo.VolCatParts = dev->part;
-   }
-   Dmsg2(400, "Call dev->open(vol=%s, mode=%d\n", dev->VolCatInfo.VolCatName, 
+
+   Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName, 
          dev->openmode);
-   /* Open next part */
-   
-   int append = dev->can_append();
-   if (dev->open(dcr, dev->openmode) < 0) {
+
+   /* Open next part.  Note, this sets part_size for part opened. */
+   if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
       return -1;
    } 
-   dev->set_labeled();          /* all next parts are "labeled" */
-   if (append && (dev->part == dev->num_parts)) { /* If needed, set the append flag back */
+   /* Restore Volume header record */
+   memcpy(&dev->VolHdr, &VolHdr, sizeof(dev->VolHdr));
+   dev->set_labeled();                   /* all next parts are "labeled" */
+   if (dev->part > dev->num_dvd_parts) { /* set append if new part created */
       dev->set_append();
    }
    
    return dev->fd;
 }
 
-/* Open the first part file.
+/*
+ * Open the first part file.
  *  - Close the fd
  *  - Reopen the device
  */
 int dvd_open_first_part(DCR *dcr, int mode)
 {
    DEVICE *dev = dcr->dev;
+   VOLUME_LABEL VolHdr;
 
-   Dmsg5(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_parts=%d append=%d\n", dev->print_name(), 
-         dev->VolCatInfo.VolCatName, dev->openmode, dev->num_parts, dev->can_append());
+   Dmsg5(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_dvd_parts=%d append=%d\n", dev->print_name(), 
+         dev->VolCatInfo.VolCatName, dev->openmode, dev->num_dvd_parts, dev->can_append());
+
+
+   /*              
+    * Note, when we close, the Volume header is zeroed. Since
+    *  we reopen, but are in fact opening the same volume without
+    *  re-reading the Volume header, we simply save and restore it.
+    */
+   memcpy(&VolHdr, &dev->VolHdr, sizeof(VolHdr));
+   dev->close();
+   memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
 
-   if (dev->fd >= 0) {
-      close(dev->fd);
-   }
-   dev->fd = -1;
-   dev->clear_opened();
-   
-   dev->part_start = 0;
-   dev->part = 0;
-   
    Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName, 
          mode);
-   int append = dev->can_append();
+   Dmsg0(100, "Set part=1\n");
+   dev->part = 1;
+   dev->part_start = 0;
+
+
+   /* Restore Volume header record */
+   memcpy(&dev->VolHdr, &VolHdr, sizeof(dev->VolHdr));
    if (dev->open(dcr, mode) < 0) {
       Dmsg0(400, "open dev() failed\n");
       return -1;
    }
-   if (append && (dev->part == dev->num_parts)) { /* If needed, set the append flag back */
+   if (dev->part > dev->num_dvd_parts) { /* created new part */
       dev->set_append();
    }
    Dmsg2(400, "Leave open_first_part state=%s append=%d\n", dev->is_open()?"open":"not open", dev->can_append());
@@ -575,11 +613,16 @@ off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
    char ed1[50], ed2[50];
    
    Dmsg3(400, "Enter lseek_dev fd=%d part=%d nparts=%d\n", dev->fd,
-      dev->part, dev->num_parts);
+      dev->part, dev->num_dvd_parts);
    if (!dev->is_dvd()) { 
       Dmsg0(400, "Using sys lseek\n");
       return lseek(dev->fd, offset, whence);
    }
+
+   /* Return I/O error ... no part */  
+   if (dev->part > dev->num_dvd_parts) {
+      return 0;
+   }
       
    dcr = (DCR *)dev->attached_dcrs->first();  /* any dcr will do */
    switch(whence) {
@@ -587,7 +630,7 @@ off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
       Dmsg2(400, "lseek_dev SEEK_SET to %s (part_start=%s)\n",
          edit_uint64(offset, ed1), edit_uint64(dev->part_start, ed2));
       if ((uint64_t)offset >= dev->part_start) {
-         if (((uint64_t)offset == dev->part_start) || ((uint64_t)offset < (dev->part_start+dev->part_size))) {
+         if ((uint64_t)offset < dev->part_start+dev->part_size) {
             /* We are staying in the current part, just seek */
             if ((pos = lseek(dev->fd, offset-dev->part_start, SEEK_SET)) < 0) {
                return pos;
@@ -596,10 +639,13 @@ off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
             }
          } else {
             /* Load next part, and start again */
+            Dmsg0(100, "lseek open next part\n");
             if (dvd_open_next_part(dcr) < 0) {
                Dmsg0(400, "lseek_dev failed while trying to open the next part\n");
                return -1;
             }
+            Dmsg2(100, "Recurse lseek after open next part=%d num_part=%d\n",
+               dev->part, dev->num_dvd_parts);
             return lseek_dev(dev, offset, SEEK_SET);
          }
       } else {
@@ -609,10 +655,13 @@ off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
           * so just load the first one, and seek again
           * until the right one is loaded
           */
+         Dmsg0(100, "lseek open first part\n");
          if (dvd_open_first_part(dcr, dev->openmode) < 0) {
             Dmsg0(400, "lseek_dev failed while trying to open the first part\n");
             return -1;
          }
+         Dmsg2(100, "Recurse lseek after open first part=%d num_part=%d\n",
+               dev->part, dev->num_dvd_parts);
          return lseek_dev(dev, offset, SEEK_SET);
       }
       break;
@@ -647,7 +696,7 @@ off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
       /* If we are already on a spooled part and have the
        *  right part number, simply seek
        */
-      if (dev->is_part_spooled() && dev->part == dev->num_parts) {
+      if (dev->is_part_spooled() && dev->part > dev->num_dvd_parts) {
          if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
             return pos;   
          } else {
@@ -664,13 +713,12 @@ off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
           * (useful for DVDs) 
           */
          int modesave = dev->openmode;
-         /* Works because num_parts > 0. */
          if (dvd_open_first_part(dcr, OPEN_READ_ONLY) < 0) {
             Dmsg0(400, "lseek_dev failed while trying to open the first part\n");
             return -1;
          }
-         if (dev->num_parts > 0) {
-            while (dev->part < (dev->num_parts-1)) {
+         if (dev->num_dvd_parts > 0) {
+            while (dev->part < dev->num_dvd_parts) {
                if (dvd_open_next_part(dcr) < 0) {
                   Dmsg0(400, "lseek_dev failed while trying to open the next part\n");
                   return -1;
@@ -704,26 +752,20 @@ bool dvd_close_job(DCR *dcr)
    if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
       Dmsg1(400, "Writing last part=%d write_partafter_job is set.\n",
          dev->part);
-      if (dev->part < dev->num_parts) {
-         Jmsg3(jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"),
-               dev->part, dev->num_parts, dev->print_name());
+      if (dev->part < dev->num_dvd_parts+1) {
+         Jmsg3(jcr, M_FATAL, 0, _("Error writing. Current part less than total number of parts (%d/%d, device=%s)\n"),
+               dev->part, dev->num_dvd_parts, dev->print_name());
          dev->dev_errno = EIO;
          ok = false;
       }
       
-      /* This should be !dvd_write_part(dcr)
-         NB: No! If you call dvd_write_part, the part number is not updated.
-         You must open the next part, it will automatically write the part and
-         update the part number. */
-      if (ok && (dvd_open_next_part(dcr) < 0)) {
-         Jmsg2(jcr, M_FATAL, 0, _("Unable to write part %s: ERR=%s\n"),
+      if (ok && !dvd_write_part(dcr)) {
+         Jmsg2(jcr, M_FATAL, 0, _("Unable to write last on %s: ERR=%s\n"),
                dev->print_name(), dev->bstrerror());
          dev->dev_errno = EIO;
          ok = false;
       }
    }
-   Dmsg1(200, "Set VolCatParts=%d\n", dev->num_parts);
-   dev->VolCatInfo.VolCatParts = dev->num_parts;
    return ok;
 }
 
@@ -731,19 +773,16 @@ bool truncate_dvd(DCR *dcr)
 {
    DEVICE* dev = dcr->dev;
 
-   if (dev->fd >= 0) {
-      close(dev->fd);
-   }
-   dev->fd = -1;
-   dev->clear_opened();
+   dev->close();
+   memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
 
    if (!unmount_dvd(dev, 1)) {
       Dmsg0(400, "truncate_dvd: Failed to unmount DVD\n");
       return false;
    }
 
-   /* Set num_parts to zero (on disk) */
-   dev->num_parts = 0;
+   /* Set num_dvd_parts to zero (on disk) */
+   dev->num_dvd_parts = 0;
    dcr->VolCatInfo.VolCatParts = 0;
    dev->VolCatInfo.VolCatParts = 0;
    
@@ -758,7 +797,7 @@ bool truncate_dvd(DCR *dcr)
 
    Dmsg0(400, "truncate_dvd: Truncating...\n");
 
-   /* If necessary, truncate it. */
+   /* If necessary, truncate it spool file. */
    if (ftruncate(dev->fd, 0) != 0) {
       berrno be;
       Mmsg2(dev->errmsg, _("Unable to truncate device %s. ERR=%s\n"), 
@@ -767,12 +806,16 @@ bool truncate_dvd(DCR *dcr)
       return false;
    }
    
-   close(dev->fd);
-   dev->fd = -1;
-   dev->clear_opened();
+   dev->close();
+   memcpy(&dev->VolCatInfo, &dcr->VolCatInfo, sizeof(dev->VolCatInfo));
    
    Dmsg0(400, "truncate_dvd: Opening first part (2)...\n");
    
+   /* 
+    * Now actually truncate the DVD
+    *  This is really kludgy, why not an argument or a separate
+    *  subroutine?  KES
+    */
    if (!dvd_write_part(dcr)) {
       Dmsg0(400, "truncate_dvd: Error while writing to DVD.\n");
       dev->truncating = false;
@@ -780,10 +823,15 @@ bool truncate_dvd(DCR *dcr)
    }
    dev->truncating = false;
    
-   /* Set num_parts to zero (on disk) */
-   dev->num_parts = 0;
+   /* Set num_dvd_parts to zero (on disk) */
+   dev->num_dvd_parts = 0;
    dcr->VolCatInfo.VolCatParts = 0;
    dev->VolCatInfo.VolCatParts = 0;
+
+   /* Update catalog */
+   if (!dir_update_volume_info(dcr, false)) {
+      return false;
+   }
    
    if (dvd_open_first_part(dcr, OPEN_READ_WRITE) < 0) {
       Dmsg0(400, "truncate_dvd: Error while opening first part (2).\n");
@@ -795,7 +843,14 @@ bool truncate_dvd(DCR *dcr)
 
 /* Checks if we can write on a non-blank DVD: meaning that it just have been
  * truncated (there is only one zero-sized file on the DVD, with the right
- * volume name). */
+ * volume name).   
+ *  
+ * Note!  Normally if we can mount the device, which should be the case
+ *   when we get here, it is not a blank DVD.  Hence we check if
+ *   there is a zero length file with the right name, in which case
+ *   we allow it.
+ * This seems terribly kludgie to me.  KES
+ */
 bool check_can_write_on_non_blank_dvd(DCR *dcr) 
 {
    DEVICE* dev = dcr->dev;
@@ -803,7 +858,7 @@ bool check_can_write_on_non_blank_dvd(DCR *dcr)
    struct dirent *entry, *result;
    int name_max;
    int count = 0;
-   int matched = 0; /* We found an empty file with the right name. */
+   bool matched = false;
    struct stat filestat;
       
    name_max = pathconf(".", _PC_NAME_MAX);
@@ -823,7 +878,7 @@ bool check_can_write_on_non_blank_dvd(DCR *dcr)
    while (1) {
       if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
          dev->dev_errno = EIO;
-         Dmsg2(129, "check_can_write_on_non_blank_dvd: failed to find suitable file in dir %s (dev=%s)\n", 
+         Dmsg2(129, "check_can_write_on_non_blank_dvd: no more files in dir %s (dev=%s)\n", 
                dev->device->mount_point, dev->print_name());
          break;
       } else {
@@ -854,12 +909,12 @@ bool check_can_write_on_non_blank_dvd(DCR *dcr)
    free(entry);
    closedir(dp);
    
-   Dmsg2(29, "check_can_write_on_non_blank_dvd: got %d files in the mount point (matched=%d)\n", count, matched);
-   
-   if (count != 3) {
+   if (count > 3) {
       /* There are more than 3 files (., .., and the volume file) */
+      Dmsg1(29, "Cannot write on blank DVD too many files %d greater than 3\n", count);
       return false;
    }
    
+   Dmsg2(29, "OK  can_write_on_non_blank_dvd: got %d files in the mount point (matched=%d)\n", count, matched);
    return matched;
 }
index d02d085c9304e7fe9f16318d09fae57f6a8c3586..368ade0acc14221180184d08d6d1943680cb22d0 100755 (executable)
@@ -283,7 +283,8 @@ static int match_all(BSR *bsr, DEV_RECORD *rec, VOLUME_LABEL *volrec,
       goto no_match;
    }
    if (!match_volume(bsr, bsr->volume, volrec, 1)) {
-      Dmsg2(300, "bsr vol=%s != rec vol=%s\n", bsr->volume, volrec);
+      Dmsg2(300, "bsr fail vol=%s != rec vol=%s\n", bsr->volume->VolumeName,
+            volrec->VolumeName);
       goto no_match;
    }
    if (!match_volfile(bsr, bsr->volfile, rec, 1)) {
index 269ba46011c9454dbe603ab49f74048a70e21c39..1b9cf9d078db3f3f3533db02c2f2ad971e5ef4a0 100644 (file)
@@ -114,7 +114,7 @@ bool dvd_write_part(DCR *dcr);
 bool dvd_close_job(DCR *dcr);
 bool mount_dvd(DEVICE* dev, int timeout);
 bool unmount_dvd(DEVICE* dev, int timeout);
-void update_free_space_dev(DEVICE *dev);
+bool update_free_space_dev(DEVICE *dev);
 void make_mounted_dvd_filename(DEVICE *dev, POOL_MEM &archive_name);
 void make_spooled_dvd_filename(DEVICE *dev, POOL_MEM &archive_name);
 bool truncate_dvd(DCR *dcr);
index eeef37547c9dc25ab71b360919fb60e2a2810a40..3fb788987e0d94c8c7da6e7f7a2930024cb134c7 100644 (file)
@@ -246,6 +246,9 @@ bool read_records(DCR *dcr,
                rec->VolSessionId, rec->VolSessionTime, rec->FileIndex);
             break;                    /* read second part of record */
          }
+         Dmsg6(dbglvl, "OK callback. recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record,
+               rec_state_to_str(rec), block->BlockNumber,
+               rec->VolSessionId, rec->VolSessionTime, rec->FileIndex);
          ok = record_cb(dcr, rec);
          /*
           * If we have a digest stream, we check to see if we have 
index 2903b734271acd1e01f59d95dcbf88ab31cb77d2..253ecc0b0759a27c96009169fac63900414ee032 100644 (file)
@@ -4,8 +4,8 @@
 
 #undef  VERSION
 #define VERSION "1.39.21"
-#define BDATE   "26 August 2006"
-#define LSMDATE "26Aug06"
+#define BDATE   "27 August 2006"
+#define LSMDATE "27Aug06"
 #define BYEAR "2006"       /* year for copyright messages in progs */
 
 /* Debug flags */
index aad540623aa211a277dfd47f03134458309416fa..70830cf93b987465c835dff360d84d62589ee651 100644 (file)
@@ -1,6 +1,11 @@
               Technical notes on version 1.39  
 
 General:
+27Aug06
+kes  Rework many features of DVD writing and reading. Added many error
+     messages.  Most importantly changed part to represent the current
+     part number base zero. This makes current DVD writing incompatible
+     with previous version.
 26Aug06
 kes  Add host:port to connect failure messages to FD and SD from Dir.
 kes  Add WhereACL to console ACL list.  If nothing is specified, only