Beispiel #1
0
/* 
 * Do an lseek on a DVD handling all the different parts
 */
boffset_t lseek_dvd(DCR *dcr, boffset_t offset, int whence)
{
   DEVICE *dev;
   boffset_t pos;
   char ed1[50], ed2[50];

   if (!dcr) {                  /* can be NULL when called from rewind(NULL) */
      return -1;
   }
   dev = dcr->dev;
   
   Dmsg5(400, "Enter lseek_dvd fd=%d off=%s w=%d part=%d nparts=%d\n", dev->fd(),
      edit_int64(offset, ed1), whence, dev->part, dev->num_dvd_parts);

   switch(whence) {
   case SEEK_SET:
      Dmsg2(400, "lseek_dvd SEEK_SET to %s (part_start=%s)\n",
         edit_int64(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) {
            /* We are staying in the current part, just seek */
#if defined(HAVE_WIN32)
            pos = _lseeki64(dev->fd(), offset-dev->part_start, SEEK_SET);
#else
            pos = lseek(dev->fd(), offset-dev->part_start, SEEK_SET);
#endif
            if (pos < 0) {
               return pos;
            } else {
               return pos + dev->part_start;
            }
         } else {
            /* Load next part, and start again */
            Dmsg0(100, "lseek open next part\n");
            if (dvd_open_next_part(dcr) < 0) {
               Dmsg0(400, "lseek_dvd 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_dvd(dcr, offset, SEEK_SET);
         }
      } else {
         /*
          * pos < dev->part_start :
          * We need to access a previous part, 
          * 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)) {
            Dmsg0(400, "lseek_dvd 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_dvd(dcr, offset, SEEK_SET); /* system lseek */
      }
      break;
   case SEEK_CUR:
      Dmsg1(400, "lseek_dvd SEEK_CUR to %s\n", edit_int64(offset, ed1));
      if ((pos = lseek(dev->fd(), 0, SEEK_CUR)) < 0) {
         Dmsg0(400, "Seek error.\n");
         return pos;                  
      }
      pos += dev->part_start;
      if (offset == 0) {
         Dmsg1(400, "lseek_dvd SEEK_CUR returns %s\n", edit_uint64(pos, ed1));
         return pos;
      } else { 
         Dmsg1(400, "do lseek_dvd SEEK_SET %s\n", edit_uint64(pos, ed1));
         return lseek_dvd(dcr, pos, SEEK_SET);
      }
      break;
   case SEEK_END:
      Dmsg1(400, "lseek_dvd SEEK_END to %s\n", edit_int64(offset, ed1));
      /*
       * Bacula does not use offsets for SEEK_END
       *  Also, Bacula uses seek_end only when it wants to
       *  append to the volume, so for a dvd that means
       *  that the volume must be spooled since the DVD
       *  itself is read-only (as currently implemented).
       */
      if (offset > 0) { /* Not used by bacula */
         Dmsg1(400, "lseek_dvd SEEK_END called with an invalid offset %s\n", 
            edit_uint64(offset, ed1));
         errno = EINVAL;
         return -1;
      }
      /* 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_dvd_parts) {
         if ((pos = lseek(dev->fd(), 0, SEEK_END)) < 0) {
            return pos;   
         } else {
            Dmsg1(400, "lseek_dvd SEEK_END returns %s\n", 
                  edit_uint64(pos + dev->part_start, ed1));
            return pos + dev->part_start;
         }
      } else {
         /*
          * Load the first part, then load the next until we reach the last one.
          * This is the only way to be sure we compute the right file address.
          *
          * Save previous openmode, and open all but last part read-only 
          * (useful for DVDs) 
          */
         int modesave = dev->openmode;
         if (!dvd_open_first_part(dcr, OPEN_READ_ONLY)) {
            Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
            return -1;
         }
         if (dev->num_dvd_parts > 0) {
            while (dev->part < dev->num_dvd_parts) {
               if (dvd_open_next_part(dcr) < 0) {
                  Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
                  return -1;
               }
            }
            dev->openmode = modesave;
            if (dvd_open_next_part(dcr) < 0) {
               Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
               return -1;
            }
         }
         return lseek_dvd(dcr, 0, SEEK_END);
      }
      break;
   default:
      Dmsg0(400, "Seek call error.\n");
      errno = EINVAL;
      return -1;
   }
}
Beispiel #2
0
bool truncate_dvd(DCR *dcr) 
{
   DEVICE* dev = dcr->dev;

   dev->clear_freespace_ok();             /* need to update freespace */
   dev->close_part(dcr);

   if (!dev->unmount(1)) {
      Dmsg0(400, "truncate_dvd: Failed to unmount DVD\n");
      return false;
   }

   /* If necessary, delete its spool file. */
   if (dev->is_part_spooled()) {
      POOL_MEM archive_name(PM_FNAME);
      /* Delete spool file */
      make_spooled_dvd_filename(dev, archive_name);
      unlink(archive_name.c_str());
      dev->set_part_spooled(false);
   }

   /* Set num_dvd_parts to zero (on disk) */
   dev->part = 0;
   dev->num_dvd_parts = 0;
   dcr->VolCatInfo.VolCatParts = 0;
   dev->VolCatInfo.VolCatParts = 0;
   
   Dmsg0(400, "truncate_dvd: Opening first part (1)...\n");
   
   dev->truncating = true;
   /* This creates a zero length spool file and sets part=1 */
   if (!dvd_open_first_part(dcr, CREATE_READ_WRITE)) {
      Dmsg0(400, "truncate_dvd: Error while opening first part (1).\n");
      dev->truncating = false;
      return false;
   }

   dev->close_part(dcr);
   
   Dmsg0(400, "truncate_dvd: Opening first part (2)...\n");
   
   /* 
    * Now actually truncate the DVD which is done by writing
    *  a zero length part to the DVD/
    */
   if (!dvd_write_part(dcr)) {
      Dmsg0(400, "truncate_dvd: Error while writing to DVD.\n");
      dev->truncating = false;
      return false;
   }
   dev->truncating = false;
   
   /* Set num_dvd_parts to zero (on disk) */
   dev->part = 0;
   dev->num_dvd_parts = 0;
   dcr->VolCatInfo.VolCatParts = 0;
   dev->VolCatInfo.VolCatParts = 0;
   /* Clear the size of the volume */
   dev->VolCatInfo.VolCatBytes = 0;
   dcr->VolCatInfo.VolCatBytes = 0;

   /* Update catalog */
   if (!dir_update_volume_info(dcr, false, true)) {
      return false;
   }
   
   return true;
}
Beispiel #3
0
/*
 * Open the next part file.
 *  - Close the fd
 *  - Increment part number 
 *  - Reopen the device
 */
int dvd_open_next_part(DCR *dcr)
{
   DEVICE *dev = dcr->dev;

   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->getVolCatName(), dev->openmode, dev->file_addr);
   if (!dev->is_dvd()) {
      Dmsg1(100, "Device %s is not dvd!!!!\n", dev->print_name()); 
      return -1;
   }
   
   /* When appending, do not open a new part if the current is empty */
   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();
   }

   dev->close_part(dcr);               /* close current part */
   
   /*
    * If we have a spooled part open, write it to the
    *  DVD before opening the next part.
    */
   if (dev->is_part_spooled()) {
      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;
      }
   }
     
   dev->part_start += dev->part_size;
   dev->part++;
   Dmsg2(29, "Inc part=%d num_dvd_parts=%d\n", dev->part, dev->num_dvd_parts);

   /* Are we working on a part past what is written in the DVD? */
   if (dev->num_dvd_parts < dev->part) {
      POOL_MEM archive_name(PM_FNAME);
      struct stat buf;
      /* 
       * First check what is on DVD.  If our part is there, we
       *   are in trouble, so bail out.
       * NB: This is however not a problem if we are writing the first part.
       * It simply means that we are over writing an existing volume...
       */
      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 */
            dev->set_part_spooled(false);
            Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
               archive_name.c_str());
            return -1;
         }
      }

#ifdef neeeded
      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, "======= 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;
            dev->set_part_spooled(false);
            dev->dev_errno = errno;
            Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"), 
                   archive_name.c_str(), be.bstrerror());
            return -1;
         }
      }
#endif
   }

   Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->getVolCatName(), 
         dev->openmode);

   /* 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" */
   
   return dev->fd();
}