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->edit_mount_codes(ocmd, icmd);
127 Dmsg2(200, "do_mount_dvd: cmd=%s mounted=%d\n", ocmd.c_str(), !!dev->is_mounted());
130 /* Try at most 1 time to (un)mount the device. This should perhaps be configurable. */
135 results = get_memory(2000);
137 /* If busy retry each second */
138 Dmsg1(20, "Run mount prog=%s\n", ocmd.c_str());
139 while ((status = run_program_full_output(ocmd.c_str(),
140 dev->max_open_wait/2, results)) != 0) {
141 Dmsg2(20, "Mount status=%d result=%s\n", status, results);
142 /* Doesn't work with internationalization (This is not a problem) */
143 if (mount && fnmatch("*is already mounted on*", results, 0) == 0) {
146 if (!mount && fnmatch("* not mounted*", results, 0) == 0) {
150 /* Sometimes the device cannot be mounted because it is already mounted.
151 * Try to unmount it, then remount it */
153 Dmsg1(400, "Trying to unmount the device %s...\n", dev->print_name());
154 do_mount_dvd(dev, 0, 0);
161 Dmsg5(40, "Device %s cannot be %smounted. stat=%d result=%s ERR=%s\n", dev->print_name(),
162 (mount ? "" : "un"), status, results, be.strerror(status));
163 Mmsg(dev->errmsg, _("Device %s cannot be %smounted. ERR=%s\n"),
164 dev->print_name(), (mount ? "" : "un"), be.strerror(status));
166 Dmsg4(40, "Device %s cannot be %smounted. stat=%d ERR=%s\n", dev->print_name(),
167 (mount ? "" : "un"), status, results);
168 Mmsg(dev->errmsg, _("Device %s cannot be %smounted. ERR=%s\n"),
169 dev->print_name(), (mount ? "" : "un"), results);
172 * Now, just to be sure it is not mounted, try to read the
176 struct dirent *entry, *result;
180 name_max = pathconf(".", _PC_NAME_MAX);
181 if (name_max < 1024) {
185 if (!(dp = opendir(dev->device->mount_point))) {
187 dev->dev_errno = errno;
188 Dmsg3(29, "do_mount_dvd: failed to open dir %s (dev=%s), ERR=%s\n",
189 dev->device->mount_point, dev->print_name(), be.strerror());
193 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
196 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
197 dev->dev_errno = EIO;
198 Dmsg2(129, "do_mount_dvd: failed to find suitable file in dir %s (dev=%s)\n",
199 dev->device->mount_point, dev->print_name());
202 if (strcmp(result->d_name, ".") && strcmp(result->d_name, "..") &&
203 strcmp(result->d_name, ".keep")) {
204 count++; /* result->d_name != ., .. or .keep (Gentoo-specific) */
205 Dmsg1(100, "Inc count=%d\n", count);
208 Dmsg2(129, "do_mount_dvd: ignoring %s in %s\n",
209 result->d_name, dev->device->mount_point);
215 Dmsg1(29, "do_mount_dvd: got %d files in the mount point (not counting ., .. and .keep)\n", count);
218 /* If we got more than ., .. and .keep */
219 /* there must be something mounted */
221 Dmsg1(100, "Did Mount by count=%d\n", count);
224 /* An unmount request. We failed to unmount - report an error */
225 dev->set_mounted(true);
226 free_pool_memory(results);
227 Dmsg0(200, "== DVD mount=1\n");
232 dev->set_mounted(false);
233 sm_check(__FILE__, __LINE__, false);
234 free_pool_memory(results);
235 Dmsg0(200, "== DVD mount=0\n");
238 Dmsg0(100, "Out of mount/umount loop\n");
240 dev->set_mounted(mount); /* set/clear mounted flag */
241 free_pool_memory(results);
242 /* Do not check free space when unmounting */
244 Dmsg0(100, "Calling update_free_space\n");
245 if (!update_free_space_dev(dev)) {
249 Dmsg1(200, "== DVD mount=%d\n", mount);
253 /* Update the free space on the device */
254 bool update_free_space_dev(DEVICE* dev)
256 POOL_MEM ocmd(PM_FNAME);
265 if (!dev->is_dvd() || dev->is_freespace_ok()) {
269 /* The device must be mounted in order to dvd-freespace to work */
272 sm_check(__FILE__, __LINE__, false);
273 icmd = dev->device->free_space_command;
277 dev->free_space_errno = 0;
278 dev->clear_freespace_ok(); /* No valid freespace */
280 Dmsg2(29, "ERROR: update_free_space_dev: free_space=%s, free_space_errno=%d (!icmd)\n",
281 edit_uint64(dev->free_space, ed1), dev->free_space_errno);
282 Mmsg(dev->errmsg, _("No FreeSpace command defined.\n"));
286 dev->edit_mount_codes(ocmd, icmd);
288 Dmsg1(29, "update_free_space_dev: cmd=%s\n", ocmd.c_str());
290 results = get_pool_memory(PM_MESSAGE);
292 /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */
297 Dmsg1(20, "Run freespace prog=%s\n", ocmd.c_str());
298 status = run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results);
299 Dmsg2(20, "Freespace status=%d result=%s\n", status, results);
301 free = str_to_int64(results);
302 Dmsg1(400, "Free space program run: Freespace=%s\n", results);
304 dev->free_space = free;
305 dev->free_space_errno = 0;
306 dev->set_freespace_ok(); /* have valid freespace */
308 Mmsg(dev->errmsg, "");
314 dev->free_space_errno = EPIPE;
315 dev->clear_freespace_ok(); /* no valid freespace */
316 Mmsg2(dev->errmsg, _("Cannot run free space command. Results=%s ERR=%s\n"),
317 results, be.strerror(status));
320 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
321 "free_space_errno=%d ERR=%s\n", dev->print_name(),
322 edit_uint64(dev->free_space, ed1), dev->free_space_errno,
328 dev->dev_errno = dev->free_space_errno;
329 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
330 "free_space_errno=%d ERR=%s\n",
331 dev->print_name(), edit_uint64(dev->free_space, ed1),
332 dev->free_space_errno, dev->errmsg);
336 free_pool_memory(results);
337 Dmsg4(29, "leave update_free_space_dev: free_space=%s freespace_ok=%d free_space_errno=%d have_media=%d\n",
338 edit_uint64(dev->free_space, ed1), !!dev->is_freespace_ok(), dev->free_space_errno, !!dev->have_media());
339 sm_check(__FILE__, __LINE__, false);
344 * Note!!!! Part numbers now begin at 1. The part number is
345 * suppressed from the first part, which is just the Volume
346 * name. Each subsequent part is the Volumename.partnumber.
348 * Write a part (Vol, Vol.2, ...) from the spool to the DVD
349 * This routine does not update the part number, so normally, you
350 * should call open_next_part()
352 * It is also called from truncate_dvd to "blank" the medium, as
353 * well as from block.c when the DVD is full to write the last part.
355 bool dvd_write_part(DCR *dcr)
357 DEVICE *dev = dcr->dev;
358 POOL_MEM archive_name(PM_FNAME);
360 /* Don't write empty part files.
361 * This is only useful when growisofs does not support write beyond
364 * - 3.9 GB on the volume, dvd-freespace reports 0.4 GB free
365 * - Write 0.2 GB on the volume, Bacula thinks it could still
366 * append data, it creates a new empty part.
367 * - dvd-freespace reports 0 GB free, as the 4GB boundary has
369 * - Bacula thinks he must finish to write to the device, so it
370 * tries to write the last part (0-byte), but dvd-writepart fails...
372 * ***FIXME**** we cannot write a blank part!!!!!!!
373 * There is one exception: when recycling a volume, we write a blank part
374 * file, so, then, we need to accept to write it.
376 if (dev->part_size == 0 && !dev->truncating) {
377 Dmsg2(29, "dvd_write_part: device is %s, won't write blank part %d\n", dev->print_name(), dev->part);
378 /* Delete spool file */
379 make_spooled_dvd_filename(dev, archive_name);
380 unlink(archive_name.c_str());
381 dev->set_part_spooled(false);
382 Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
383 sm_check(__FILE__, __LINE__, false);
387 POOL_MEM ocmd(PM_FNAME);
388 POOL_MEM results(PM_MESSAGE);
394 dev->clear_freespace_ok(); /* need to update freespace */
396 sm_check(__FILE__, __LINE__, false);
397 Dmsg3(29, "dvd_write_part: device is %s, part is %d, is_mounted=%d\n", dev->print_name(), dev->part, dev->is_mounted());
398 icmd = dev->device->write_part_command;
400 dev->edit_mount_codes(ocmd, icmd);
403 * original line follows
404 * timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
405 * I modified this for a longer timeout; pre-formatting, blanking and
406 * writing can take quite a while
409 /* Explanation of the timeout value, when writing the first part,
411 * 9 GB, write speed 1x: 6990 seconds (almost 2 hours...)
412 * Overhead: 900 seconds (starting, initializing, finalizing,probably
413 * reloading 15 minutes)
415 * A reasonable last-exit timeout would be 16000 seconds. Quite long -
416 * almost 4.5 hours, but hopefully, that timeout will only ever be needed
417 * in case of a serious emergency.
420 if (dev->part == 1) {
423 timeout = dev->max_open_wait + (dev->part_size/(1350*1024/4));
426 Dmsg2(20, "Write part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
427 status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
428 Dmsg2(20, "Write part status=%d result=%s\n", status, results.c_str());
430 dev->blank_dvd = false;
432 Jmsg2(dcr->jcr, M_FATAL, 0, _("Error writing part %d to the DVD: ERR=%s\n"),
433 dev->part, results.c_str());
434 Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"),
436 Dmsg1(000, "%s\n", dev->errmsg);
437 dev->dev_errno = EIO;
438 if (!dev->truncating) {
439 mark_volume_in_error(dcr);
441 sm_check(__FILE__, __LINE__, false);
444 Jmsg(dcr->jcr, M_INFO, 0, _("Part %d (%lld bytes) written to DVD.\n"), dev->part, dev->part_size);
445 Dmsg3(400, "dvd_write_part: Part %d (%lld bytes) written to DVD\nResults: %s\n",
446 dev->part, dev->part_size, results.c_str());
448 dev->num_dvd_parts++; /* there is now one more part on DVD */
449 dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
450 dcr->VolCatInfo.VolCatParts = dev->num_dvd_parts;
451 Dmsg1(000, "Update num_parts=%d\n", dev->num_dvd_parts);
453 /* Delete spool file */
454 make_spooled_dvd_filename(dev, archive_name);
455 unlink(archive_name.c_str());
456 dev->set_part_spooled(false);
457 Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
458 sm_check(__FILE__, __LINE__, false);
460 /* growisofs umounted the device, so remount it (it will update the free space) */
461 dev->clear_mounted();
463 Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"),
464 edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
465 sm_check(__FILE__, __LINE__, false);
470 * Open the next part file.
472 * - Increment part number
473 * - Reopen the device
475 int dvd_open_next_part(DCR *dcr)
477 DEVICE *dev = dcr->dev;
479 Dmsg6(29, "Enter: == open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n",
480 dev->part, dev->num_dvd_parts, dev->print_name(),
481 dev->VolCatInfo.VolCatName, dev->openmode, dev->file_addr);
482 if (!dev->is_dvd()) {
483 Dmsg1(000, "Device %s is not dvd!!!!\n", dev->print_name());
487 /* When appending, do not open a new part if the current is empty */
488 if (dev->can_append() && (dev->part > dev->num_dvd_parts) &&
489 (dev->part_size == 0)) {
490 Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
494 dev->close_part(dcr); /* close current part */
497 * If we have a spooled part open, write it to the
498 * DVD before opening the next part.
500 if (dev->is_part_spooled()) {
501 Dmsg2(100, "Before open next write previous. part=%d num_parts=%d\n",
502 dev->part, dev->num_dvd_parts);
503 if (!dvd_write_part(dcr)) {
504 Dmsg0(29, "Error in dvd_write part.\n");
509 dev->part_start += dev->part_size;
511 Dmsg2(29, "Inc part=%d num_dvd_parts=%d\n", dev->part, dev->num_dvd_parts);
513 /* Are we working on a part past what is written in the DVD? */
514 if (dev->num_dvd_parts < dev->part) {
515 POOL_MEM archive_name(PM_FNAME);
518 * First check what is on DVD. If our part is there, we
519 * are in trouble, so bail out.
520 * NB: This is however not a problem if we are writing the first part.
521 * It simply means that we are over writing an existing volume...
523 if (dev->num_dvd_parts > 0) {
524 make_mounted_dvd_filename(dev, archive_name); /* makes dvd name */
525 Dmsg1(100, "Check if part on DVD: %s\n", archive_name.c_str());
526 if (stat(archive_name.c_str(), &buf) == 0) {
527 /* bad news bail out */
528 dev->set_part_spooled(false);
529 Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
530 archive_name.c_str());
536 Dmsg2(400, "num_dvd_parts=%d part=%d\n", dev->num_dvd_parts, dev->part);
537 make_spooled_dvd_filename(dev, archive_name); /* makes spool name */
539 /* Check if the next part exists in spool directory . */
540 Dmsg1(100, "Check if part on spool: %s\n", archive_name.c_str());
541 if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
542 Dmsg1(29, "======= Part %s is in the way, deleting it...\n", archive_name.c_str());
543 /* Then try to unlink it */
544 if (unlink(archive_name.c_str()) < 0) {
546 dev->set_part_spooled(false);
547 dev->dev_errno = errno;
548 Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"),
549 archive_name.c_str(), be.strerror());
556 Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName,
559 /* Open next part. Note, this sets part_size for part opened. */
560 if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
563 dev->set_labeled(); /* all next parts are "labeled" */
569 * Open the first part file.
571 * - Reopen the device
573 int dvd_open_first_part(DCR *dcr, int mode)
575 DEVICE *dev = dcr->dev;
577 Dmsg5(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_dvd_parts=%d append=%d\n", dev->print_name(),
578 dev->VolCatInfo.VolCatName, dev->openmode, dev->num_dvd_parts, dev->can_append());
581 dev->close_part(dcr);
583 Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName,
585 Dmsg0(100, "Set part=1\n");
589 if (dev->open(dcr, mode) < 0) {
590 Dmsg0(400, "open dev() failed\n");
593 Dmsg2(400, "Leave open_first_part state=%s append=%d\n", dev->is_open()?"open":"not open", dev->can_append());
600 * Do an lseek on a DVD handling all the different parts
602 off_t lseek_dvd(DCR *dcr, off_t offset, int whence)
604 DEVICE *dev = dcr->dev;
606 char ed1[50], ed2[50];
608 Dmsg5(400, "Enter lseek_dvd fd=%d off=%s w=%d part=%d nparts=%d\n", dev->fd,
609 edit_int64(offset, ed1), whence, dev->part, dev->num_dvd_parts);
613 Dmsg2(400, "lseek_dvd SEEK_SET to %s (part_start=%s)\n",
614 edit_int64(offset, ed1), edit_uint64(dev->part_start, ed2));
615 if ((uint64_t)offset >= dev->part_start) {
616 if ((uint64_t)offset == dev->part_start ||
617 (uint64_t)offset < dev->part_start+dev->part_size) {
618 /* We are staying in the current part, just seek */
619 if ((pos = lseek(dev->fd, offset-dev->part_start, SEEK_SET)) < 0) {
622 return pos + dev->part_start;
625 /* Load next part, and start again */
626 Dmsg0(100, "lseek open next part\n");
627 if (dvd_open_next_part(dcr) < 0) {
628 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
631 Dmsg2(100, "Recurse lseek after open next part=%d num_part=%d\n",
632 dev->part, dev->num_dvd_parts);
633 return lseek_dvd(dcr, offset, SEEK_SET);
637 * pos < dev->part_start :
638 * We need to access a previous part,
639 * so just load the first one, and seek again
640 * until the right one is loaded
642 Dmsg0(100, "lseek open first part\n");
643 if (dvd_open_first_part(dcr, dev->openmode) < 0) {
644 Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
647 Dmsg2(100, "Recurse lseek after open first part=%d num_part=%d\n",
648 dev->part, dev->num_dvd_parts);
649 return lseek_dvd(dcr, offset, SEEK_SET); /* system lseek */
653 Dmsg1(400, "lseek_dvd SEEK_CUR to %s\n", edit_int64(offset, ed1));
654 if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) {
655 Dmsg0(400, "Seek error.\n");
658 pos += dev->part_start;
660 Dmsg1(400, "lseek_dvd SEEK_CUR returns %s\n", edit_uint64(pos, ed1));
663 Dmsg1(400, "do lseek_dvd SEEK_SET %s\n", edit_uint64(pos, ed1));
664 return lseek_dvd(dcr, pos, SEEK_SET);
668 Dmsg1(400, "lseek_dvd SEEK_END to %s\n", edit_int64(offset, ed1));
670 * Bacula does not use offsets for SEEK_END
671 * Also, Bacula uses seek_end only when it wants to
672 * append to the volume, so for a dvd that means
673 * that the volume must be spooled since the DVD
674 * itself is read-only (as currently implemented).
676 if (offset > 0) { /* Not used by bacula */
677 Dmsg1(400, "lseek_dvd SEEK_END called with an invalid offset %s\n",
678 edit_uint64(offset, ed1));
682 /* If we are already on a spooled part and have the
683 * right part number, simply seek
685 if (dev->is_part_spooled() && dev->part > dev->num_dvd_parts) {
686 if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
689 Dmsg1(400, "lseek_dvd SEEK_END returns %s\n",
690 edit_uint64(pos + dev->part_start, ed1));
691 return pos + dev->part_start;
695 * Load the first part, then load the next until we reach the last one.
696 * This is the only way to be sure we compute the right file address.
698 * Save previous openmode, and open all but last part read-only
701 int modesave = dev->openmode;
702 if (dvd_open_first_part(dcr, OPEN_READ_ONLY) < 0) {
703 Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
706 if (dev->num_dvd_parts > 0) {
707 while (dev->part < dev->num_dvd_parts) {
708 if (dvd_open_next_part(dcr) < 0) {
709 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
713 dev->openmode = modesave;
714 if (dvd_open_next_part(dcr) < 0) {
715 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
719 return lseek_dvd(dcr, 0, SEEK_END);
723 Dmsg0(400, "Seek call error.\n");
729 bool dvd_close_job(DCR *dcr)
731 DEVICE *dev = dcr->dev;
736 * If the device is a dvd and WritePartAfterJob
737 * is set to yes, open the next part, so, in case of a device
738 * that requires mount, it will be written to the device.
740 if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
741 Dmsg1(400, "Writing last part=%d write_partafter_job is set.\n",
743 if (dev->part < dev->num_dvd_parts+1) {
744 Jmsg3(jcr, M_FATAL, 0, _("Error writing. Current part less than total number of parts (%d/%d, device=%s)\n"),
745 dev->part, dev->num_dvd_parts, dev->print_name());
746 dev->dev_errno = EIO;
750 if (ok && !dvd_write_part(dcr)) {
751 Jmsg2(jcr, M_FATAL, 0, _("Unable to write last on %s: ERR=%s\n"),
752 dev->print_name(), dev->bstrerror());
753 dev->dev_errno = EIO;
760 void dvd_remove_empty_part(DCR *dcr)
762 DEVICE *dev = dcr->dev;
764 /* Remove the last part file if it is empty */
765 if (dev->is_dvd() && dev->num_dvd_parts > 0) {
767 uint32_t part_save = dev->part;
768 POOL_MEM archive_name(PM_FNAME);
771 dev->part = dev->num_dvd_parts;
772 make_spooled_dvd_filename(dev, archive_name);
773 /* Check that the part file is empty */
774 status = stat(archive_name.c_str(), &statp);
775 if (status == 0 && statp.st_size == 0) {
776 Dmsg3(100, "Unlink empty part in close call make_dvd_filename. part=%d num=%d vol=%s\n",
777 part_save, dev->num_dvd_parts, dev->VolCatInfo.VolCatName);
778 Dmsg1(100, "unlink(%s)\n", archive_name.c_str());
779 unlink(archive_name.c_str());
780 if (part_save == dev->part) {
781 dev->set_part_spooled(false); /* no spooled part left */
783 } else if (status < 0) {
784 if (part_save == dev->part) {
785 dev->set_part_spooled(false); /* spool doesn't exit */
788 dev->part = part_save; /* restore part number */
792 bool truncate_dvd(DCR *dcr)
794 DEVICE* dev = dcr->dev;
796 dev->clear_freespace_ok(); /* need to update freespace */
797 dev->close_part(dcr);
799 if (!unmount_dvd(dev, 1)) {
800 Dmsg0(400, "truncate_dvd: Failed to unmount DVD\n");
804 /* Set num_dvd_parts to zero (on disk) */
805 dev->num_dvd_parts = 0;
806 dcr->VolCatInfo.VolCatParts = 0;
807 dev->VolCatInfo.VolCatParts = 0;
809 Dmsg0(400, "truncate_dvd: Opening first part (1)...\n");
811 dev->truncating = true;
812 if (dvd_open_first_part(dcr, CREATE_READ_WRITE) < 0) {
813 Dmsg0(400, "truncate_dvd: Error while opening first part (1).\n");
814 dev->truncating = false;
818 Dmsg0(400, "truncate_dvd: Truncating...\n");
820 /* If necessary, truncate it spool file. */
821 if (ftruncate(dev->fd, 0) != 0) {
823 Mmsg2(dev->errmsg, _("Unable to truncate device %s. ERR=%s\n"),
824 dev->print_name(), be.strerror());
825 dev->truncating = false;
829 dev->close_part(dcr);
831 Dmsg0(400, "truncate_dvd: Opening first part (2)...\n");
834 * Now actually truncate the DVD
835 * This is really kludgy, why not an argument or a separate
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) */
846 dev->num_dvd_parts = 0;
847 dcr->VolCatInfo.VolCatParts = 0;
848 dev->VolCatInfo.VolCatParts = 0;
849 /* Clear the size of the volume */
850 dev->VolCatInfo.VolCatBytes = 0;
851 dcr->VolCatInfo.VolCatBytes = 0;
855 if (!dir_update_volume_info(dcr, false)) {
860 if (dvd_open_first_part(dcr, OPEN_READ_WRITE) < 0) {
861 Dmsg0(400, "truncate_dvd: Error while opening first part (2).\n");
868 /* Checks if we can write on a non-blank DVD: meaning that it just have been
869 * truncated (there is only one zero-sized file on the DVD, with the right
872 * Note! Normally if we can mount the device, which should be the case
873 * when we get here, it is not a blank DVD. Hence we check if
874 * there is a zero length file with the right name, in which case
876 * This seems terribly kludgie to me. KES
878 bool check_can_write_on_non_blank_dvd(DCR *dcr)
880 DEVICE* dev = dcr->dev;
882 struct dirent *entry, *result;
886 struct stat filestat;
888 name_max = pathconf(".", _PC_NAME_MAX);
889 if (name_max < 1024) {
893 if (!(dp = opendir(dev->device->mount_point))) {
895 dev->dev_errno = errno;
896 Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n",
897 dev->device->mount_point, dev->print_name(), be.strerror());
901 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
903 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
904 dev->dev_errno = EIO;
905 Dmsg2(129, "check_can_write_on_non_blank_dvd: no more files in dir %s (dev=%s)\n",
906 dev->device->mount_point, dev->print_name());
909 Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n",
910 result->d_name, dev->VolCatInfo.VolCatName);
911 if (strcmp(result->d_name, dev->VolCatInfo.VolCatName) == 0) {
912 /* Found the file, checking it is empty */
913 POOL_MEM filename(PM_FNAME);
914 pm_strcpy(filename, dev->device->mount_point);
915 if (filename.c_str()[strlen(filename.c_str())-1] != '/') {
916 pm_strcat(filename, "/");
918 pm_strcat(filename, dev->VolCatInfo.VolCatName);
919 if (stat(filename.c_str(), &filestat) < 0) {
921 dev->dev_errno = errno;
922 Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n",
923 filename.c_str(), be.strerror());
926 Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %lld\n",
927 filename.c_str(), filestat.st_size);
928 matched = filestat.st_size == 0;
937 /* There are more than 3 files (., .., and the volume file) */
938 Dmsg1(29, "Cannot write on blank DVD too many files %d greater than 3\n", count);
942 Dmsg2(29, "OK can_write_on_non_blank_dvd: got %d files in the mount point (matched=%d)\n", count, matched);
947 * Mount a DVD device, then scan to find out how many parts
950 int find_num_dvd_parts(DCR *dcr)
952 DEVICE *dev = dcr->dev;
955 if (!dev->is_dvd()) {
961 struct dirent *entry, *result;
963 int len = strlen(dcr->VolCatInfo.VolCatName);
965 /* Now count the number of parts */
966 name_max = pathconf(".", _PC_NAME_MAX);
967 if (name_max < 1024) {
971 if (!(dp = opendir(dev->device->mount_point))) {
973 dev->dev_errno = errno;
974 Dmsg3(29, "find_num_dvd_parts: failed to open dir %s (dev=%s), ERR=%s\n",
975 dev->device->mount_point, dev->print_name(), be.strerror());
979 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
981 Dmsg1(100, "Looking for Vol=%s\n", dcr->VolCatInfo.VolCatName);
985 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
986 dev->dev_errno = EIO;
987 Dmsg2(129, "find_num_dvd_parts: failed to find suitable file in dir %s (dev=%s)\n",
988 dev->device->mount_point, dev->print_name());
991 flen = strlen(result->d_name);
994 result->d_name[len] = 0;
995 if (strcmp(dcr->VolCatInfo.VolCatName, result->d_name) == 0) {
997 Dmsg1(100, "find_num_dvd_parts: found part: %s\n", result->d_name);
1002 Dmsg2(129, "find_num_dvd_parts: ignoring %s in %s\n",
1003 result->d_name, dev->device->mount_point);
1008 Dmsg1(29, "find_num_dvd_parts = %d\n", num_parts);
1012 dev->set_freespace_ok();
1013 if (dev->is_mounted()) {