/* * 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; } }
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; }
/* * 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(); }