void dvd_remove_empty_part(DCR *dcr) { DEVICE *dev = dcr->dev; /* Remove the last part file if it is empty */ if (dev->is_dvd() && dev->num_dvd_parts > 0) { struct stat statp; uint32_t part_save = dev->part; POOL_MEM archive_name(PM_FNAME); int status; dev->part = dev->num_dvd_parts; make_spooled_dvd_filename(dev, archive_name); /* Check that the part file is empty */ status = stat(archive_name.c_str(), &statp); if (status == 0 && statp.st_size == 0) { Dmsg3(100, "Unlink empty part in close call make_dvd_filename. part=%d num=%d vol=%s\n", part_save, dev->num_dvd_parts, dev->getVolCatName()); Dmsg1(100, "unlink(%s)\n", archive_name.c_str()); unlink(archive_name.c_str()); if (part_save == dev->part) { dev->set_part_spooled(false); /* no spooled part left */ } } else if (status < 0) { if (part_save == dev->part) { dev->set_part_spooled(false); /* spool doesn't exit */ } } dev->part = part_save; /* restore part number */ } }
bool dvd_close_job(DCR *dcr) { DEVICE *dev = dcr->dev; JCR *jcr = dcr->jcr; bool ok = true; /* * If the device is a dvd and WritePartAfterJob * is set to yes, open the next part, so, in case of a device * that requires mount, it will be written to the device. */ 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_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; } 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; } } return ok; }
/* * Mount a DVD device, then scan to find out how many parts * there are. */ int find_num_dvd_parts(DCR *dcr) { DEVICE *dev = dcr->dev; int num_parts = 0; if (!dev->is_dvd()) { return 0; } if (dev->mount(1)) { DIR* dp; struct dirent *entry, *result; int name_max; int len = strlen(dcr->getVolCatName()); /* Now count the number of parts */ name_max = pathconf(".", _PC_NAME_MAX); if (name_max < 1024) { name_max = 1024; } if (!(dp = opendir(dev->device->mount_point))) { berrno be; dev->dev_errno = errno; Dmsg3(29, "find_num_dvd_parts: failed to open dir %s (dev=%s), ERR=%s\n", dev->device->mount_point, dev->print_name(), be.bstrerror()); goto get_out; } entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000); Dmsg1(100, "Looking for Vol=%s\n", dcr->getVolCatName()); for ( ;; ) { int flen; bool ignore; if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) { dev->dev_errno = EIO; Dmsg2(129, "find_num_dvd_parts: failed to find suitable file in dir %s (dev=%s)\n", dev->device->mount_point, dev->print_name()); break; } flen = strlen(result->d_name); ignore = true; if (flen >= len) { result->d_name[len] = 0; if (strcmp(dcr->getVolCatName(), result->d_name) == 0) { num_parts++; Dmsg1(100, "find_num_dvd_parts: found part: %s\n", result->d_name); ignore = false; } } if (ignore) { Dmsg2(129, "find_num_dvd_parts: ignoring %s in %s\n", result->d_name, dev->device->mount_point); } } free(entry); closedir(dp); Dmsg1(29, "find_num_dvd_parts = %d\n", num_parts); } get_out: dev->set_freespace_ok(); if (dev->is_mounted()) { dev->unmount(0); } return num_parts; }
/* * 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(); }
/* * Acquire device for writing. We permit multiple writers. * If this is the first one, we read the label. * * Returns: NULL if failed for any reason * dcr if successful. * Note, normally reserve_device_for_append() is called * before this routine. */ DCR *acquire_device_for_append(DCR *dcr) { DEVICE *dev = dcr->dev; JCR *jcr = dcr->jcr; bool ok = false; bool have_vol = false; Enter(200); init_device_wait_timers(dcr); dev->Lock_acquire(); /* only one job at a time */ dev->Lock(); Dmsg1(100, "acquire_append device is %s\n", dev->is_tape()?"tape": (dev->is_dvd()?"DVD":"disk")); /* * With the reservation system, this should not happen */ if (dev->can_read()) { Mmsg2(jcr->errmsg, "Want to append but %s device %s is busy reading.\n", dev->print_type(), dev->print_name()); Jmsg(jcr, M_FATAL, 0, jcr->errmsg); Dmsg0(50, jcr->errmsg); goto get_out; } dev->clear_unload(); /* * have_vol defines whether or not mount_next_write_volume should * ask the Director again about what Volume to use. */ if (dev->can_append() && dcr->is_suitable_volume_mounted() && strcmp(dcr->VolCatInfo.VolCatStatus, "Recycle") != 0) { Dmsg0(190, "device already in append.\n"); /* * At this point, the correct tape is already mounted, so * we do not need to do mount_next_write_volume(), unless * we need to recycle the tape. */ if (dev->num_writers == 0) { dev->VolCatInfo = dcr->VolCatInfo; /* structure assignment */ } have_vol = dcr->is_tape_position_ok(); } if (!have_vol) { dev->rLock(true); block_device(dev, BST_DOING_ACQUIRE); dev->Unlock(); Dmsg1(190, "jid=%u Do mount_next_write_vol\n", (uint32_t)jcr->JobId); if (!dcr->mount_next_write_volume()) { if (!job_canceled(jcr)) { /* Reduce "noise" -- don't print if job canceled */ Mmsg2(jcr->errmsg, _("Could not ready %s device %s for append.\n"), dev->print_type(), dev->print_name()); Jmsg(jcr, M_FATAL, 0, jcr->errmsg); Dmsg0(50, jcr->errmsg); } dev->Lock(); unblock_device(dev); goto get_out; } Dmsg2(190, "Output pos=%u:%u\n", dcr->dev->file, dcr->dev->block_num); dev->Lock(); unblock_device(dev); } if (generate_plugin_event(jcr, bsdEventDeviceOpen, dcr) != bRC_OK) { Mmsg0(jcr->errmsg, _("generate_plugin_event(bsdEventDeviceOpen) Failed\n")); Jmsg(jcr, M_FATAL, 0, jcr->errmsg); Dmsg0(50, jcr->errmsg); goto get_out; } dev->num_writers++; /* we are now a writer */ if (jcr->NumWriteVolumes == 0) { jcr->NumWriteVolumes = 1; } dev->VolCatInfo.VolCatJobs++; /* increment number of jobs on vol */ Dmsg4(100, "=== nwriters=%d nres=%d vcatjob=%d dev=%s\n", dev->num_writers, dev->num_reserved(), dev->VolCatInfo.VolCatJobs, dev->print_name()); ok = dir_update_volume_info(dcr, false, false); /* send Volume info to Director */ get_out: /* Don't plugin close here, we might have multiple writers */ dcr->clear_reserved(); dev->Unlock(); dev->Unlock_acquire(); Leave(200); return ok ? dcr : NULL; }