3 * dvd.c -- Routines specific to DVD devices (and
4 * possibly other removable hard media).
11 Copyright (C) 2005-2006 Kern Sibbald
13 This program is free software; you can redistribute it and/or
14 modify it under the terms of the GNU General Public License
15 version 2 as amended with additional clauses defined in the
16 file LICENSE in the main source directory.
18 This program is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 the file LICENSE for additional details.
28 /* Forward referenced functions */
29 static bool do_mount_dvd(DEVICE* dev, int mount, int dotimeout);
30 static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name);
33 * Write the current volume/part filename to archive_name.
35 void make_mounted_dvd_filename(DEVICE *dev, POOL_MEM &archive_name)
37 pm_strcpy(archive_name, dev->device->mount_point);
38 add_file_and_part_name(dev, archive_name);
41 void make_spooled_dvd_filename(DEVICE *dev, POOL_MEM &archive_name)
43 /* Use the working directory if spool directory is not defined */
44 if (dev->device->spool_directory) {
45 pm_strcpy(archive_name, dev->device->spool_directory);
47 pm_strcpy(archive_name, working_directory);
49 add_file_and_part_name(dev, archive_name);
52 static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name)
56 if (archive_name.c_str()[strlen(archive_name.c_str())-1] != '/') {
57 pm_strcat(archive_name, "/");
60 pm_strcat(archive_name, dev->VolCatInfo.VolCatName);
61 /* if part > 1, append .# to the filename (where # is the part number) */
63 pm_strcat(archive_name, ".");
64 bsnprintf(partnumber, sizeof(partnumber), "%d", dev->part);
65 pm_strcat(archive_name, partnumber);
67 Dmsg2(400, "Exit add_file_part_name: arch=%s, part=%d\n",
68 archive_name.c_str(), dev->part);
72 * If timeout, wait until the mount command returns 0.
73 * If !timeout, try to mount the device only once.
75 bool mount_dvd(DEVICE* dev, int timeout)
77 Dmsg0(90, "Enter mount_dvd\n");
78 if (dev->is_mounted()) {
80 } else if (dev->requires_mount()) {
81 return do_mount_dvd(dev, 1, timeout);
87 * If timeout, wait until the unmount command returns 0.
88 * If !timeout, try to unmount the device only once.
90 bool unmount_dvd(DEVICE *dev, int timeout)
95 Dmsg0(90, "Enter unmount_dvd\n");
96 if (dev->is_mounted()) {
97 return do_mount_dvd(dev, 0, timeout);
102 /* (Un)mount the device */
103 static bool do_mount_dvd(DEVICE* dev, int mount, int dotimeout)
105 POOL_MEM ocmd(PM_FNAME);
110 sm_check(__FILE__, __LINE__, false);
112 if (dev->is_mounted()) {
113 Dmsg0(200, "======= DVD mount=1\n");
116 icmd = dev->device->mount_command;
118 if (!dev->is_mounted()) {
119 Dmsg0(200, "======= DVD mount=0\n");
122 icmd = dev->device->unmount_command;
125 dev->clear_freespace_ok();
126 dev->edit_mount_codes(ocmd, icmd);
128 Dmsg2(200, "do_mount_dvd: cmd=%s mounted=%d\n", ocmd.c_str(), !!dev->is_mounted());
131 /* Try at most 1 time to (un)mount the device. This should perhaps be configurable. */
136 results = get_memory(2000);
138 /* If busy retry each second */
139 Dmsg1(20, "Run mount prog=%s\n", ocmd.c_str());
140 while ((status = run_program_full_output(ocmd.c_str(),
141 dev->max_open_wait/2, results)) != 0) {
142 Dmsg2(20, "Mount status=%d result=%s\n", status, results);
143 /* Doesn't work with internationalization (This is not a problem) */
144 if (mount && fnmatch("*is already mounted on*", results, 0) == 0) {
147 if (!mount && fnmatch("* not mounted*", results, 0) == 0) {
151 /* Sometimes the device cannot be mounted because it is already mounted.
152 * Try to unmount it, then remount it */
154 Dmsg1(400, "Trying to unmount the device %s...\n", dev->print_name());
155 do_mount_dvd(dev, 0, 0);
162 Dmsg5(40, "Device %s cannot be %smounted. stat=%d result=%s ERR=%s\n", dev->print_name(),
163 (mount ? "" : "un"), status, results, be.strerror(status));
164 Mmsg(dev->errmsg, _("Device %s cannot be %smounted. ERR=%s\n"),
165 dev->print_name(), (mount ? "" : "un"), be.strerror(status));
167 Dmsg4(40, "Device %s cannot be %smounted. stat=%d ERR=%s\n", dev->print_name(),
168 (mount ? "" : "un"), status, results);
169 Mmsg(dev->errmsg, _("Device %s cannot be %smounted. ERR=%s\n"),
170 dev->print_name(), (mount ? "" : "un"), results);
173 * Now, just to be sure it is not mounted, try to read the
177 struct dirent *entry, *result;
181 name_max = pathconf(".", _PC_NAME_MAX);
182 if (name_max < 1024) {
186 if (!(dp = opendir(dev->device->mount_point))) {
188 dev->dev_errno = errno;
189 Dmsg3(29, "do_mount_dvd: failed to open dir %s (dev=%s), ERR=%s\n",
190 dev->device->mount_point, dev->print_name(), be.strerror());
194 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
197 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
198 dev->dev_errno = EIO;
199 Dmsg2(129, "do_mount_dvd: failed to find suitable file in dir %s (dev=%s)\n",
200 dev->device->mount_point, dev->print_name());
203 if (strcmp(result->d_name, ".") && strcmp(result->d_name, "..") &&
204 strcmp(result->d_name, ".keep")) {
205 count++; /* result->d_name != ., .. or .keep (Gentoo-specific) */
206 Dmsg1(100, "Inc count=%d\n", count);
209 Dmsg2(129, "do_mount_dvd: ignoring %s in %s\n",
210 result->d_name, dev->device->mount_point);
216 Dmsg1(29, "do_mount_dvd: got %d files in the mount point (not counting ., .. and .keep)\n", count);
219 /* If we got more than ., .. and .keep */
220 /* there must be something mounted */
222 Dmsg1(100, "Did Mount by count=%d\n", count);
225 /* An unmount request. We failed to unmount - report an error */
226 dev->set_mounted(true);
227 free_pool_memory(results);
228 Dmsg0(200, "== DVD mount=1\n");
233 dev->set_mounted(false);
234 sm_check(__FILE__, __LINE__, false);
235 free_pool_memory(results);
236 Dmsg0(200, "== DVD mount=0\n");
239 Dmsg0(100, "Out of mount/umount loop\n");
241 dev->set_mounted(mount); /* set/clear mounted flag */
242 free_pool_memory(results);
243 /* Do not check free space when unmounting */
245 Dmsg0(100, "Calling update_free_space\n");
246 if (!update_free_space_dev(dev)) {
250 Dmsg1(200, "== DVD mount=%d\n", mount);
254 /* Update the free space on the device */
255 bool update_free_space_dev(DEVICE* dev)
257 POOL_MEM ocmd(PM_FNAME);
266 if (!dev->is_dvd() || dev->is_freespace_ok()) {
270 /* The device must be mounted in order to dvd-freespace to work */
273 sm_check(__FILE__, __LINE__, false);
274 icmd = dev->device->free_space_command;
278 dev->free_space_errno = 0;
279 dev->clear_freespace_ok(); /* No valid freespace */
281 Dmsg2(29, "ERROR: update_free_space_dev: free_space=%s, free_space_errno=%d (!icmd)\n",
282 edit_uint64(dev->free_space, ed1), dev->free_space_errno);
283 Mmsg(dev->errmsg, _("No FreeSpace command defined.\n"));
287 dev->edit_mount_codes(ocmd, icmd);
289 Dmsg1(29, "update_free_space_dev: cmd=%s\n", ocmd.c_str());
291 results = get_pool_memory(PM_MESSAGE);
293 /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */
298 Dmsg1(20, "Run freespace prog=%s\n", ocmd.c_str());
299 status = run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results);
300 Dmsg2(500, "Freespace status=%d result=%s\n", status, results);
302 free = str_to_int64(results);
303 Dmsg1(400, "Free space program run: Freespace=%s\n", results);
305 dev->free_space = free;
306 dev->free_space_errno = 0;
307 dev->set_freespace_ok(); /* have valid freespace */
309 Mmsg(dev->errmsg, "");
315 dev->free_space_errno = EPIPE;
316 dev->clear_freespace_ok(); /* no valid freespace */
317 Mmsg2(dev->errmsg, _("Cannot run free space command. Results=%s ERR=%s\n"),
318 results, be.strerror(status));
321 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
322 "free_space_errno=%d ERR=%s\n", dev->print_name(),
323 edit_uint64(dev->free_space, ed1), dev->free_space_errno,
329 dev->dev_errno = dev->free_space_errno;
330 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
331 "free_space_errno=%d ERR=%s\n",
332 dev->print_name(), edit_uint64(dev->free_space, ed1),
333 dev->free_space_errno, dev->errmsg);
337 free_pool_memory(results);
338 Dmsg4(29, "leave update_free_space_dev: free_space=%s freespace_ok=%d free_space_errno=%d have_media=%d\n",
339 edit_uint64(dev->free_space, ed1), !!dev->is_freespace_ok(), dev->free_space_errno, !!dev->have_media());
340 sm_check(__FILE__, __LINE__, false);
345 * Note!!!! Part numbers now begin at 1. The part number is
346 * suppressed from the first part, which is just the Volume
347 * name. Each subsequent part is the Volumename.partnumber.
349 * Write a part (Vol, Vol.2, ...) from the spool to the DVD
350 * This routine does not update the part number, so normally, you
351 * should call open_next_part()
353 * It is also called from truncate_dvd to "blank" the medium, as
354 * well as from block.c when the DVD is full to write the last part.
356 bool dvd_write_part(DCR *dcr)
358 DEVICE *dev = dcr->dev;
359 POOL_MEM archive_name(PM_FNAME);
362 * Don't write empty part files.
363 * This is only useful when growisofs does not support write beyond
366 * - 3.9 GB on the volume, dvd-freespace reports 0.4 GB free
367 * - Write 0.2 GB on the volume, Bacula thinks it could still
368 * append data, it creates a new empty part.
369 * - dvd-freespace reports 0 GB free, as the 4GB boundary has
371 * - Bacula thinks he must finish to write to the device, so it
372 * tries to write the last part (0-byte), but dvd-writepart fails...
374 * There is one exception: when recycling a volume, we write a blank part
375 * file, so, then, we need to accept to write it.
377 if (dev->part_size == 0 && !dev->truncating) {
378 Dmsg2(29, "dvd_write_part: device is %s, won't write blank part %d\n", dev->print_name(), dev->part);
379 /* Delete spool file */
380 make_spooled_dvd_filename(dev, archive_name);
381 unlink(archive_name.c_str());
382 dev->set_part_spooled(false);
383 Dmsg1(29, "========= unlink(%s)\n", archive_name.c_str());
384 sm_check(__FILE__, __LINE__, false);
388 POOL_MEM ocmd(PM_FNAME);
389 POOL_MEM results(PM_MESSAGE);
395 dev->clear_freespace_ok(); /* need to update freespace */
397 sm_check(__FILE__, __LINE__, false);
398 Dmsg3(29, "dvd_write_part: device is %s, part is %d, is_mounted=%d\n", dev->print_name(), dev->part, dev->is_mounted());
399 icmd = dev->device->write_part_command;
401 dev->edit_mount_codes(ocmd, icmd);
404 * original line follows
405 * timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
406 * I modified this for a longer timeout; pre-formatting, blanking and
407 * writing can take quite a while
410 /* Explanation of the timeout value, when writing the first part,
412 * 9 GB, write speed 1x: 6990 seconds (almost 2 hours...)
413 * Overhead: 900 seconds (starting, initializing, finalizing,probably
414 * reloading 15 minutes)
416 * A reasonable last-exit timeout would be 16000 seconds. Quite long -
417 * almost 4.5 hours, but hopefully, that timeout will only ever be needed
418 * in case of a serious emergency.
421 if (dev->part == 1) {
424 timeout = dev->max_open_wait + (dev->part_size/(1350*1024/4));
427 Dmsg2(20, "Write part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
428 status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
429 Dmsg2(20, "Write part status=%d result=%s\n", status, results.c_str());
431 dev->blank_dvd = false;
433 Jmsg2(dcr->jcr, M_FATAL, 0, _("Error writing part %d to the DVD: ERR=%s\n"),
434 dev->part, results.c_str());
435 Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"),
437 Dmsg1(100, "%s\n", dev->errmsg);
438 dev->dev_errno = EIO;
439 if (!dev->truncating) {
440 mark_volume_in_error(dcr);
442 sm_check(__FILE__, __LINE__, false);
445 Jmsg(dcr->jcr, M_INFO, 0, _("Part %d (%lld bytes) written to DVD.\n"), dev->part, dev->part_size);
446 Dmsg3(400, "dvd_write_part: Part %d (%lld bytes) written to DVD\nResults: %s\n",
447 dev->part, dev->part_size, results.c_str());
449 dev->num_dvd_parts++; /* there is now one more part on DVD */
450 dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
451 dcr->VolCatInfo.VolCatParts = dev->num_dvd_parts;
452 Dmsg1(100, "Update num_parts=%d\n", dev->num_dvd_parts);
454 /* Delete spool file */
455 make_spooled_dvd_filename(dev, archive_name);
456 unlink(archive_name.c_str());
457 dev->set_part_spooled(false);
458 Dmsg1(29, "========= unlink(%s)\n", archive_name.c_str());
459 sm_check(__FILE__, __LINE__, false);
461 /* growisofs umounted the device, so remount it (it will update the free space) */
462 dev->clear_mounted();
464 Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"),
465 edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
466 sm_check(__FILE__, __LINE__, false);
471 * Open the next part file.
473 * - Increment part number
474 * - Reopen the device
476 int dvd_open_next_part(DCR *dcr)
478 DEVICE *dev = dcr->dev;
480 Dmsg6(29, "Enter: == open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n",
481 dev->part, dev->num_dvd_parts, dev->print_name(),
482 dev->VolCatInfo.VolCatName, dev->openmode, dev->file_addr);
483 if (!dev->is_dvd()) {
484 Dmsg1(100, "Device %s is not dvd!!!!\n", dev->print_name());
488 /* When appending, do not open a new part if the current is empty */
489 if (dev->can_append() && (dev->part > dev->num_dvd_parts) &&
490 (dev->part_size == 0)) {
491 Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
495 dev->close_part(dcr); /* close current part */
498 * If we have a spooled part open, write it to the
499 * DVD before opening the next part.
501 if (dev->is_part_spooled()) {
502 Dmsg2(100, "Before open next write previous. part=%d num_parts=%d\n",
503 dev->part, dev->num_dvd_parts);
504 if (!dvd_write_part(dcr)) {
505 Dmsg0(29, "Error in dvd_write part.\n");
510 dev->part_start += dev->part_size;
512 Dmsg2(29, "Inc part=%d num_dvd_parts=%d\n", dev->part, dev->num_dvd_parts);
514 /* Are we working on a part past what is written in the DVD? */
515 if (dev->num_dvd_parts < dev->part) {
516 POOL_MEM archive_name(PM_FNAME);
519 * First check what is on DVD. If our part is there, we
520 * are in trouble, so bail out.
521 * NB: This is however not a problem if we are writing the first part.
522 * It simply means that we are over writing an existing volume...
524 if (dev->num_dvd_parts > 0) {
525 make_mounted_dvd_filename(dev, archive_name); /* makes dvd name */
526 Dmsg1(100, "Check if part on DVD: %s\n", archive_name.c_str());
527 if (stat(archive_name.c_str(), &buf) == 0) {
528 /* bad news bail out */
529 dev->set_part_spooled(false);
530 Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
531 archive_name.c_str());
537 Dmsg2(400, "num_dvd_parts=%d part=%d\n", dev->num_dvd_parts, dev->part);
538 make_spooled_dvd_filename(dev, archive_name); /* makes spool name */
540 /* Check if the next part exists in spool directory . */
541 Dmsg1(100, "Check if part on spool: %s\n", archive_name.c_str());
542 if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
543 Dmsg1(29, "======= Part %s is in the way, deleting it...\n", archive_name.c_str());
544 /* Then try to unlink it */
545 if (unlink(archive_name.c_str()) < 0) {
547 dev->set_part_spooled(false);
548 dev->dev_errno = errno;
549 Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"),
550 archive_name.c_str(), be.strerror());
557 Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName,
560 /* Open next part. Note, this sets part_size for part opened. */
561 if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
564 dev->set_labeled(); /* all next parts are "labeled" */
570 * Open the first part file.
572 * - Reopen the device
574 static bool dvd_open_first_part(DCR *dcr, int mode)
576 DEVICE *dev = dcr->dev;
578 Dmsg5(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_dvd_parts=%d append=%d\n", dev->print_name(),
579 dev->VolCatInfo.VolCatName, dev->openmode, dev->num_dvd_parts, dev->can_append());
582 dev->close_part(dcr);
584 Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName,
586 Dmsg0(100, "Set part=1\n");
590 if (dev->open(dcr, mode) < 0) {
591 Dmsg0(400, "open dev() failed\n");
594 Dmsg2(400, "Leave open_first_part state=%s append=%d\n", dev->is_open()?"open":"not open", dev->can_append());
601 * Do an lseek on a DVD handling all the different parts
603 off_t lseek_dvd(DCR *dcr, off_t offset, int whence)
605 DEVICE *dev = dcr->dev;
607 char ed1[50], ed2[50];
609 Dmsg5(400, "Enter lseek_dvd fd=%d off=%s w=%d part=%d nparts=%d\n", dev->fd,
610 edit_int64(offset, ed1), whence, dev->part, dev->num_dvd_parts);
614 Dmsg2(400, "lseek_dvd SEEK_SET to %s (part_start=%s)\n",
615 edit_int64(offset, ed1), edit_uint64(dev->part_start, ed2));
616 if ((uint64_t)offset >= dev->part_start) {
617 if ((uint64_t)offset == dev->part_start ||
618 (uint64_t)offset < dev->part_start+dev->part_size) {
619 /* We are staying in the current part, just seek */
620 if ((pos = lseek(dev->fd, offset-dev->part_start, SEEK_SET)) < 0) {
623 return pos + dev->part_start;
626 /* Load next part, and start again */
627 Dmsg0(100, "lseek open next part\n");
628 if (dvd_open_next_part(dcr) < 0) {
629 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
632 Dmsg2(100, "Recurse lseek after open next part=%d num_part=%d\n",
633 dev->part, dev->num_dvd_parts);
634 return lseek_dvd(dcr, offset, SEEK_SET);
638 * pos < dev->part_start :
639 * We need to access a previous part,
640 * so just load the first one, and seek again
641 * until the right one is loaded
643 Dmsg0(100, "lseek open first part\n");
644 if (!dvd_open_first_part(dcr, dev->openmode)) {
645 Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
648 Dmsg2(100, "Recurse lseek after open first part=%d num_part=%d\n",
649 dev->part, dev->num_dvd_parts);
650 return lseek_dvd(dcr, offset, SEEK_SET); /* system lseek */
654 Dmsg1(400, "lseek_dvd SEEK_CUR to %s\n", edit_int64(offset, ed1));
655 if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) {
656 Dmsg0(400, "Seek error.\n");
659 pos += dev->part_start;
661 Dmsg1(400, "lseek_dvd SEEK_CUR returns %s\n", edit_uint64(pos, ed1));
664 Dmsg1(400, "do lseek_dvd SEEK_SET %s\n", edit_uint64(pos, ed1));
665 return lseek_dvd(dcr, pos, SEEK_SET);
669 Dmsg1(400, "lseek_dvd SEEK_END to %s\n", edit_int64(offset, ed1));
671 * Bacula does not use offsets for SEEK_END
672 * Also, Bacula uses seek_end only when it wants to
673 * append to the volume, so for a dvd that means
674 * that the volume must be spooled since the DVD
675 * itself is read-only (as currently implemented).
677 if (offset > 0) { /* Not used by bacula */
678 Dmsg1(400, "lseek_dvd SEEK_END called with an invalid offset %s\n",
679 edit_uint64(offset, ed1));
683 /* If we are already on a spooled part and have the
684 * right part number, simply seek
686 if (dev->is_part_spooled() && dev->part > dev->num_dvd_parts) {
687 if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
690 Dmsg1(400, "lseek_dvd SEEK_END returns %s\n",
691 edit_uint64(pos + dev->part_start, ed1));
692 return pos + dev->part_start;
696 * Load the first part, then load the next until we reach the last one.
697 * This is the only way to be sure we compute the right file address.
699 * Save previous openmode, and open all but last part read-only
702 int modesave = dev->openmode;
703 if (!dvd_open_first_part(dcr, OPEN_READ_ONLY)) {
704 Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
707 if (dev->num_dvd_parts > 0) {
708 while (dev->part < dev->num_dvd_parts) {
709 if (dvd_open_next_part(dcr) < 0) {
710 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
714 dev->openmode = modesave;
715 if (dvd_open_next_part(dcr) < 0) {
716 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
720 return lseek_dvd(dcr, 0, SEEK_END);
724 Dmsg0(400, "Seek call error.\n");
730 bool dvd_close_job(DCR *dcr)
732 DEVICE *dev = dcr->dev;
737 * If the device is a dvd and WritePartAfterJob
738 * is set to yes, open the next part, so, in case of a device
739 * that requires mount, it will be written to the device.
741 if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
742 Dmsg1(400, "Writing last part=%d write_partafter_job is set.\n",
744 if (dev->part < dev->num_dvd_parts+1) {
745 Jmsg3(jcr, M_FATAL, 0, _("Error writing. Current part less than total number of parts (%d/%d, device=%s)\n"),
746 dev->part, dev->num_dvd_parts, dev->print_name());
747 dev->dev_errno = EIO;
751 if (ok && !dvd_write_part(dcr)) {
752 Jmsg2(jcr, M_FATAL, 0, _("Unable to write last on %s: ERR=%s\n"),
753 dev->print_name(), dev->bstrerror());
754 dev->dev_errno = EIO;
761 void dvd_remove_empty_part(DCR *dcr)
763 DEVICE *dev = dcr->dev;
765 /* Remove the last part file if it is empty */
766 if (dev->is_dvd() && dev->num_dvd_parts > 0) {
768 uint32_t part_save = dev->part;
769 POOL_MEM archive_name(PM_FNAME);
772 dev->part = dev->num_dvd_parts;
773 make_spooled_dvd_filename(dev, archive_name);
774 /* Check that the part file is empty */
775 status = stat(archive_name.c_str(), &statp);
776 if (status == 0 && statp.st_size == 0) {
777 Dmsg3(100, "Unlink empty part in close call make_dvd_filename. part=%d num=%d vol=%s\n",
778 part_save, dev->num_dvd_parts, dev->VolCatInfo.VolCatName);
779 Dmsg1(100, "unlink(%s)\n", archive_name.c_str());
780 unlink(archive_name.c_str());
781 if (part_save == dev->part) {
782 dev->set_part_spooled(false); /* no spooled part left */
784 } else if (status < 0) {
785 if (part_save == dev->part) {
786 dev->set_part_spooled(false); /* spool doesn't exit */
789 dev->part = part_save; /* restore part number */
793 bool truncate_dvd(DCR *dcr)
795 DEVICE* dev = dcr->dev;
797 dev->clear_freespace_ok(); /* need to update freespace */
798 dev->close_part(dcr);
800 if (!unmount_dvd(dev, 1)) {
801 Dmsg0(400, "truncate_dvd: Failed to unmount DVD\n");
805 /* If necessary, delete its spool file. */
806 if (dev->is_part_spooled()) {
807 POOL_MEM archive_name(PM_FNAME);
808 /* Delete spool file */
809 make_spooled_dvd_filename(dev, archive_name);
810 unlink(archive_name.c_str());
811 dev->set_part_spooled(false);
814 /* Set num_dvd_parts to zero (on disk) */
816 dev->num_dvd_parts = 0;
817 dcr->VolCatInfo.VolCatParts = 0;
818 dev->VolCatInfo.VolCatParts = 0;
820 Dmsg0(400, "truncate_dvd: Opening first part (1)...\n");
822 dev->truncating = true;
823 /* This creates a zero length spool file and sets part=1 */
824 if (!dvd_open_first_part(dcr, CREATE_READ_WRITE)) {
825 Dmsg0(400, "truncate_dvd: Error while opening first part (1).\n");
826 dev->truncating = false;
830 dev->close_part(dcr);
832 Dmsg0(400, "truncate_dvd: Opening first part (2)...\n");
835 * Now actually truncate the DVD which is done by writing
836 * a zero length part to the DVD/
838 if (!dvd_write_part(dcr)) {
839 Dmsg0(400, "truncate_dvd: Error while writing to DVD.\n");
840 dev->truncating = false;
843 dev->truncating = false;
845 /* Set num_dvd_parts to zero (on disk) */
847 dev->num_dvd_parts = 0;
848 dcr->VolCatInfo.VolCatParts = 0;
849 dev->VolCatInfo.VolCatParts = 0;
850 /* Clear the size of the volume */
851 dev->VolCatInfo.VolCatBytes = 0;
852 dcr->VolCatInfo.VolCatBytes = 0;
855 if (!dir_update_volume_info(dcr, false)) {
863 * Checks if we can write on a non-blank DVD: meaning that it just have been
864 * truncated (there is only one zero-sized file on the DVD).
866 * Note! Normally if we can mount the device, which should be the case
867 * when we get here, it is not a blank DVD. Hence we check if
868 * if all files are of zero length (i.e. no data), in which case we allow it.
871 bool check_can_write_on_non_blank_dvd(DCR *dcr)
873 DEVICE* dev = dcr->dev;
875 struct dirent *entry, *result;
877 struct stat filestat;
880 name_max = pathconf(".", _PC_NAME_MAX);
881 if (name_max < 1024) {
885 if (!(dp = opendir(dev->device->mount_point))) {
887 dev->dev_errno = errno;
888 Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n",
889 dev->device->mount_point, dev->print_name(), be.strerror());
893 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
895 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
896 dev->dev_errno = EIO;
897 Dmsg2(129, "check_can_write_on_non_blank_dvd: no more files in dir %s (dev=%s)\n",
898 dev->device->mount_point, dev->print_name());
901 Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n",
902 result->d_name, dev->VolCatInfo.VolCatName);
903 if (strcmp(result->d_name, ".") && strcmp(result->d_name, "..") &&
904 strcmp(result->d_name, ".keep")) {
905 /* Found a file, checking it is empty */
906 POOL_MEM filename(PM_FNAME);
907 pm_strcpy(filename, dev->device->mount_point);
908 if (filename.c_str()[strlen(filename.c_str())-1] != '/') {
909 pm_strcat(filename, "/");
911 pm_strcat(filename, result->d_name);
912 if (stat(filename.c_str(), &filestat) < 0) {
914 dev->dev_errno = errno;
915 Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n",
916 filename.c_str(), be.strerror());
920 Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %lld\n",
921 filename.c_str(), filestat.st_size);
922 if (filestat.st_size != 0) {
932 Dmsg1(29, "OK can_write_on_non_blank_dvd: OK=%d\n", ok);
937 * Mount a DVD device, then scan to find out how many parts
940 int find_num_dvd_parts(DCR *dcr)
942 DEVICE *dev = dcr->dev;
945 if (!dev->is_dvd()) {
951 struct dirent *entry, *result;
953 int len = strlen(dcr->VolCatInfo.VolCatName);
955 /* Now count the number of parts */
956 name_max = pathconf(".", _PC_NAME_MAX);
957 if (name_max < 1024) {
961 if (!(dp = opendir(dev->device->mount_point))) {
963 dev->dev_errno = errno;
964 Dmsg3(29, "find_num_dvd_parts: failed to open dir %s (dev=%s), ERR=%s\n",
965 dev->device->mount_point, dev->print_name(), be.strerror());
969 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
971 Dmsg1(100, "Looking for Vol=%s\n", dcr->VolCatInfo.VolCatName);
975 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
976 dev->dev_errno = EIO;
977 Dmsg2(129, "find_num_dvd_parts: failed to find suitable file in dir %s (dev=%s)\n",
978 dev->device->mount_point, dev->print_name());
981 flen = strlen(result->d_name);
984 result->d_name[len] = 0;
985 if (strcmp(dcr->VolCatInfo.VolCatName, result->d_name) == 0) {
987 Dmsg1(100, "find_num_dvd_parts: found part: %s\n", result->d_name);
992 Dmsg2(129, "find_num_dvd_parts: ignoring %s in %s\n",
993 result->d_name, dev->device->mount_point);
998 Dmsg1(29, "find_num_dvd_parts = %d\n", num_parts);
1002 dev->set_freespace_ok();
1003 if (dev->is_mounted()) {