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)
55 if (archive_name.c_str()[strlen(archive_name.c_str())-1] != '/') {
56 pm_strcat(archive_name, "/");
59 pm_strcat(archive_name, dev->VolCatInfo.VolCatName);
60 /* if part > 1, append .# to the filename (where # is the part number) */
62 pm_strcat(archive_name, ".");
63 bsnprintf(partnumber, sizeof(partnumber), "%d", dev->part);
64 pm_strcat(archive_name, partnumber);
66 Dmsg2(400, "Exit add_file_part_name: arch=%s, part=%d\n",
67 archive_name.c_str(), dev->part);
71 * If timeout, wait until the mount command returns 0.
72 * If !timeout, try to mount the device only once.
74 bool mount_dvd(DEVICE* dev, int timeout)
76 Dmsg0(90, "Enter mount_dvd\n");
77 if (dev->is_mounted()) {
79 } else if (dev->requires_mount()) {
80 return do_mount_dvd(dev, 1, timeout);
86 * If timeout, wait until the unmount command returns 0.
87 * If !timeout, try to unmount the device only once.
89 bool unmount_dvd(DEVICE *dev, int timeout)
94 Dmsg0(90, "Enter unmount_dvd\n");
95 if (dev->is_mounted()) {
96 return do_mount_dvd(dev, 0, timeout);
101 /* (Un)mount the device */
102 static bool do_mount_dvd(DEVICE* dev, int mount, int dotimeout)
104 POOL_MEM ocmd(PM_FNAME);
109 sm_check(__FILE__, __LINE__, false);
111 if (dev->is_mounted()) {
112 Dmsg0(200, "======= DVD mount=1\n");
115 icmd = dev->device->mount_command;
117 if (!dev->is_mounted()) {
118 Dmsg0(200, "======= DVD mount=0\n");
121 icmd = dev->device->unmount_command;
124 dev->edit_mount_codes(ocmd, icmd);
126 Dmsg2(200, "do_mount_dvd: cmd=%s mounted=%d\n", ocmd.c_str(), !!dev->is_mounted());
129 /* Try at most 1 time to (un)mount the device. This should perhaps be configurable. */
134 results = get_memory(2000);
136 /* If busy retry each second */
137 Dmsg1(20, "Run mount prog=%s\n", ocmd.c_str());
138 while ((status = run_program_full_output(ocmd.c_str(),
139 dev->max_open_wait/2, results)) != 0) {
140 Dmsg2(20, "Mount status=%d result=%s\n", status, results);
141 /* Doesn't work with internationalization (This is not a problem) */
142 if (mount && fnmatch("*is already mounted on*", results, 0) == 0) {
145 if (!mount && fnmatch("* not mounted*", results, 0) == 0) {
149 /* Sometimes the device cannot be mounted because it is already mounted.
150 * Try to unmount it, then remount it */
152 Dmsg1(400, "Trying to unmount the device %s...\n", dev->print_name());
153 do_mount_dvd(dev, 0, 0);
160 Dmsg5(40, "Device %s cannot be %smounted. stat=%d result=%s ERR=%s\n", dev->print_name(),
161 (mount ? "" : "un"), status, results, be.strerror(status));
162 Mmsg(dev->errmsg, _("Device %s cannot be %smounted. ERR=%s\n"),
163 dev->print_name(), (mount ? "" : "un"), be.strerror(status));
165 Dmsg4(40, "Device %s cannot be %smounted. stat=%d ERR=%s\n", dev->print_name(),
166 (mount ? "" : "un"), status, results);
167 Mmsg(dev->errmsg, _("Device %s cannot be %smounted. ERR=%s\n"),
168 dev->print_name(), (mount ? "" : "un"), results);
171 * Now, just to be sure it is not mounted, try to read the
175 struct dirent *entry, *result;
179 name_max = pathconf(".", _PC_NAME_MAX);
180 if (name_max < 1024) {
184 if (!(dp = opendir(dev->device->mount_point))) {
186 dev->dev_errno = errno;
187 Dmsg3(29, "do_mount_dvd: failed to open dir %s (dev=%s), ERR=%s\n",
188 dev->device->mount_point, dev->print_name(), be.strerror());
192 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
195 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
196 dev->dev_errno = EIO;
197 Dmsg2(129, "do_mount_dvd: failed to find suitable file in dir %s (dev=%s)\n",
198 dev->device->mount_point, dev->print_name());
201 if (strcmp(result->d_name, ".") && strcmp(result->d_name, "..") &&
202 strcmp(result->d_name, ".keep")) {
203 count++; /* result->d_name != ., .. or .keep (Gentoo-specific) */
204 Dmsg1(100, "Inc count=%d\n", count);
207 Dmsg2(129, "do_mount_dvd: ignoring %s in %s\n",
208 result->d_name, dev->device->mount_point);
214 Dmsg1(29, "do_mount_dvd: got %d files in the mount point (not counting ., .. and .keep)\n", count);
217 /* If we got more than ., .. and .keep */
218 /* there must be something mounted */
220 Dmsg1(100, "Did Mount by count=%d\n", count);
223 /* An unmount request. We failed to unmount - report an error */
224 dev->set_mounted(true);
225 free_pool_memory(results);
226 Dmsg0(200, "== DVD mount=1\n");
231 dev->set_mounted(false);
232 sm_check(__FILE__, __LINE__, false);
233 free_pool_memory(results);
234 Dmsg0(200, "== DVD mount=0\n");
237 Dmsg0(100, "Out of mount/umount loop\n");
239 dev->set_mounted(mount); /* set/clear mounted flag */
240 free_pool_memory(results);
241 /* Do not check free space when unmounting */
243 Dmsg0(100, "Calling update_free_space\n");
244 if (!update_free_space_dev(dev)) {
248 Dmsg1(200, "== DVD mount=%d\n", mount);
252 /* Update the free space on the device */
253 bool update_free_space_dev(DEVICE* dev)
255 POOL_MEM ocmd(PM_FNAME);
264 if (!dev->is_dvd() || dev->is_freespace_ok()) {
268 /* The device must be mounted in order to dvd-freespace to work */
271 sm_check(__FILE__, __LINE__, false);
272 icmd = dev->device->free_space_command;
276 dev->free_space_errno = 0;
277 dev->clear_freespace_ok(); /* No valid freespace */
279 Dmsg2(29, "ERROR: update_free_space_dev: free_space=%s, free_space_errno=%d (!icmd)\n",
280 edit_uint64(dev->free_space, ed1), dev->free_space_errno);
281 Mmsg(dev->errmsg, _("No FreeSpace command defined.\n"));
285 dev->edit_mount_codes(ocmd, icmd);
287 Dmsg1(29, "update_free_space_dev: cmd=%s\n", ocmd.c_str());
289 results = get_pool_memory(PM_MESSAGE);
291 /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */
296 Dmsg1(20, "Run freespace prog=%s\n", ocmd.c_str());
297 status = run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results);
298 Dmsg2(20, "Freespace status=%d result=%s\n", status, results);
300 free = str_to_int64(results);
301 Dmsg1(400, "Free space program run: Freespace=%s\n", results);
303 dev->free_space = free;
304 dev->free_space_errno = 0;
305 dev->set_freespace_ok(); /* have valid freespace */
307 Mmsg(dev->errmsg, "");
313 dev->free_space_errno = EPIPE;
314 dev->clear_freespace_ok(); /* no valid freespace */
315 Mmsg2(dev->errmsg, _("Cannot run free space command. Results=%s ERR=%s\n"),
316 results, be.strerror(status));
319 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
320 "free_space_errno=%d ERR=%s\n", dev->print_name(),
321 edit_uint64(dev->free_space, ed1), dev->free_space_errno,
327 dev->dev_errno = dev->free_space_errno;
328 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
329 "free_space_errno=%d ERR=%s\n",
330 dev->print_name(), edit_uint64(dev->free_space, ed1),
331 dev->free_space_errno, dev->errmsg);
335 free_pool_memory(results);
336 Dmsg4(29, "leave update_free_space_dev: free_space=%s freespace_ok=%d free_space_errno=%d have_media=%d\n",
337 edit_uint64(dev->free_space, ed1), !!dev->is_freespace_ok(), dev->free_space_errno, !!dev->have_media());
338 sm_check(__FILE__, __LINE__, false);
343 * Note!!!! Part numbers now begin at 1. The part number is
344 * suppressed from the first part, which is just the Volume
345 * name. Each subsequent part is the Volumename.partnumber.
347 * Write a part (Vol, Vol.2, ...) from the spool to the DVD
348 * This routine does not update the part number, so normally, you
349 * should call open_next_part()
351 * It is also called from truncate_dvd to "blank" the medium, as
352 * well as from block.c when the DVD is full to write the last part.
354 bool dvd_write_part(DCR *dcr)
356 DEVICE *dev = dcr->dev;
357 POOL_MEM archive_name(PM_FNAME);
359 dev->clear_freespace_ok(); /* need to update freespace */
361 /* Don't write empty part files.
362 * This is only useful when growisofs does not support write beyond
365 * - 3.9 GB on the volume, dvd-freespace reports 0.4 GB free
366 * - Write 0.2 GB on the volume, Bacula thinks it could still
367 * append data, it creates a new empty part.
368 * - dvd-freespace reports 0 GB free, as the 4GB boundary has
370 * - Bacula thinks he must finish to write to the device, so it
371 * tries to write the last part (0-byte), but dvd-writepart fails...
373 * ***FIXME**** we cannot write a blank part!!!!!!!
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 sm_check(__FILE__, __LINE__, false);
396 Dmsg3(29, "dvd_write_part: device is %s, part is %d, is_mounted=%d\n", dev->print_name(), dev->part, dev->is_mounted());
397 icmd = dev->device->write_part_command;
399 dev->edit_mount_codes(ocmd, icmd);
402 * original line follows
403 * timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
404 * I modified this for a longer timeout; pre-formatting, blanking and
405 * writing can take quite a while
408 /* Explanation of the timeout value, when writing the first part,
410 * 9 GB, write speed 1x: 6990 seconds (almost 2 hours...)
411 * Overhead: 900 seconds (starting, initializing, finalizing,probably
412 * reloading 15 minutes)
414 * A reasonable last-exit timeout would be 16000 seconds. Quite long -
415 * almost 4.5 hours, but hopefully, that timeout will only ever be needed
416 * in case of a serious emergency.
419 if (dev->part == 1) {
422 timeout = dev->max_open_wait + (dev->part_size/(1350*1024/4));
425 Dmsg2(20, "Write part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
426 status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
427 Dmsg2(20, "Write part status=%d result=%s\n", status, results.c_str());
429 dev->blank_dvd = false;
431 Jmsg2(dcr->jcr, M_FATAL, 0, _("Error writing part %d to the DVD: ERR=%s\n"),
432 dev->part, results.c_str());
433 Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"),
435 Dmsg1(000, "%s\n", dev->errmsg);
436 dev->dev_errno = EIO;
437 if (!dev->truncating) {
438 mark_volume_in_error(dcr);
440 sm_check(__FILE__, __LINE__, false);
443 Jmsg(dcr->jcr, M_INFO, 0, _("Part %d (%lld bytes) written to DVD.\n"), dev->part, dev->part_size);
444 Dmsg3(400, "dvd_write_part: Part %d (%lld bytes) written to DVD\nResults: %s\n",
445 dev->part, dev->part_size, results.c_str());
447 dev->num_dvd_parts++; /* there is now one more part on DVD */
448 dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
449 dcr->VolCatInfo.VolCatParts = dev->num_dvd_parts;
450 Dmsg1(000, "Update num_parts=%d\n", dev->num_dvd_parts);
452 /* Delete spool file */
453 make_spooled_dvd_filename(dev, archive_name);
454 unlink(archive_name.c_str());
455 dev->set_part_spooled(false);
456 Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
457 sm_check(__FILE__, __LINE__, false);
459 /* growisofs umounted the device, so remount it (it will update the free space) */
460 dev->clear_mounted();
462 Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"),
463 edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
464 sm_check(__FILE__, __LINE__, false);
469 * Open the next part file.
471 * - Increment part number
472 * - Reopen the device
474 int dvd_open_next_part(DCR *dcr)
476 DEVICE *dev = dcr->dev;
478 Dmsg6(29, "Enter: == open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n",
479 dev->part, dev->num_dvd_parts, dev->print_name(),
480 dev->VolCatInfo.VolCatName, dev->openmode, dev->file_addr);
481 if (!dev->is_dvd()) {
482 Dmsg1(000, "Device %s is not dvd!!!!\n", dev->print_name());
486 /* When appending, do not open a new part if the current is empty */
487 if (dev->can_append() && (dev->part > dev->num_dvd_parts) &&
488 (dev->part_size == 0)) {
489 Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
493 dev->close_part(dcr); /* close current part */
496 * If we have a spooled part open, write it to the
497 * DVD before opening the next part.
499 if (dev->is_part_spooled()) {
500 Dmsg2(100, "Before open next write previous. part=%d num_parts=%d\n",
501 dev->part, dev->num_dvd_parts);
502 if (!dvd_write_part(dcr)) {
503 Dmsg0(29, "Error in dvd_write part.\n");
508 dev->part_start += dev->part_size;
510 Dmsg2(29, "Inc part=%d num_dvd_parts=%d\n", dev->part, dev->num_dvd_parts);
512 /* Are we working on a part past what is written in the DVD? */
513 if (dev->num_dvd_parts < dev->part) {
514 POOL_MEM archive_name(PM_FNAME);
517 * First check what is on DVD. If our part is there, we
518 * are in trouble, so bail out.
519 * NB: This is however not a problem if we are writing the first part.
520 * It simply means that we are over writing an existing volume...
522 if (dev->num_dvd_parts > 0) {
523 make_mounted_dvd_filename(dev, archive_name); /* makes dvd name */
524 Dmsg1(100, "Check if part on DVD: %s\n", archive_name.c_str());
525 if (stat(archive_name.c_str(), &buf) == 0) {
526 /* bad news bail out */
527 dev->set_part_spooled(false);
528 Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
529 archive_name.c_str());
535 Dmsg2(400, "num_dvd_parts=%d part=%d\n", dev->num_dvd_parts, dev->part);
536 make_spooled_dvd_filename(dev, archive_name); /* makes spool name */
538 /* Check if the next part exists in spool directory . */
539 Dmsg1(100, "Check if part on spool: %s\n", archive_name.c_str());
540 if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
541 Dmsg1(29, "======= Part %s is in the way, deleting it...\n", archive_name.c_str());
542 /* Then try to unlink it */
543 if (unlink(archive_name.c_str()) < 0) {
545 dev->set_part_spooled(false);
546 dev->dev_errno = errno;
547 Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"),
548 archive_name.c_str(), be.strerror());
555 Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName,
558 /* Open next part. Note, this sets part_size for part opened. */
559 if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
562 dev->set_labeled(); /* all next parts are "labeled" */
568 * Open the first part file.
570 * - Reopen the device
572 int dvd_open_first_part(DCR *dcr, int mode)
574 DEVICE *dev = dcr->dev;
576 Dmsg5(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_dvd_parts=%d append=%d\n", dev->print_name(),
577 dev->VolCatInfo.VolCatName, dev->openmode, dev->num_dvd_parts, dev->can_append());
580 dev->close_part(dcr);
582 Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName,
584 Dmsg0(100, "Set part=1\n");
588 if (dev->open(dcr, mode) < 0) {
589 Dmsg0(400, "open dev() failed\n");
592 Dmsg2(400, "Leave open_first_part state=%s append=%d\n", dev->is_open()?"open":"not open", dev->can_append());
599 * Do an lseek on a DVD handling all the different parts
601 off_t lseek_dvd(DCR *dcr, off_t offset, int whence)
603 DEVICE *dev = dcr->dev;
605 char ed1[50], ed2[50];
607 Dmsg5(400, "Enter lseek_dvd fd=%d off=%s w=%d part=%d nparts=%d\n", dev->fd,
608 edit_int64(offset, ed1), whence, dev->part, dev->num_dvd_parts);
612 Dmsg2(400, "lseek_dvd SEEK_SET to %s (part_start=%s)\n",
613 edit_int64(offset, ed1), edit_uint64(dev->part_start, ed2));
614 if ((uint64_t)offset >= dev->part_start) {
615 if ((uint64_t)offset == dev->part_start ||
616 (uint64_t)offset < dev->part_start+dev->part_size) {
617 /* We are staying in the current part, just seek */
618 if ((pos = lseek(dev->fd, offset-dev->part_start, SEEK_SET)) < 0) {
621 return pos + dev->part_start;
624 /* Load next part, and start again */
625 Dmsg0(100, "lseek open next part\n");
626 if (dvd_open_next_part(dcr) < 0) {
627 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
630 Dmsg2(100, "Recurse lseek after open next part=%d num_part=%d\n",
631 dev->part, dev->num_dvd_parts);
632 return lseek_dvd(dcr, offset, SEEK_SET);
636 * pos < dev->part_start :
637 * We need to access a previous part,
638 * so just load the first one, and seek again
639 * until the right one is loaded
641 Dmsg0(100, "lseek open first part\n");
642 if (dvd_open_first_part(dcr, dev->openmode) < 0) {
643 Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
646 Dmsg2(100, "Recurse lseek after open first part=%d num_part=%d\n",
647 dev->part, dev->num_dvd_parts);
648 return lseek_dvd(dcr, offset, SEEK_SET); /* system lseek */
652 Dmsg1(400, "lseek_dvd SEEK_CUR to %s\n", edit_int64(offset, ed1));
653 if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) {
654 Dmsg0(400, "Seek error.\n");
657 pos += dev->part_start;
659 Dmsg1(400, "lseek_dvd SEEK_CUR returns %s\n", edit_uint64(pos, ed1));
662 Dmsg1(400, "do lseek_dvd SEEK_SET %s\n", edit_uint64(pos, ed1));
663 return lseek_dvd(dcr, pos, SEEK_SET);
667 Dmsg1(400, "lseek_dvd SEEK_END to %s\n", edit_int64(offset, ed1));
669 * Bacula does not use offsets for SEEK_END
670 * Also, Bacula uses seek_end only when it wants to
671 * append to the volume, so for a dvd that means
672 * that the volume must be spooled since the DVD
673 * itself is read-only (as currently implemented).
675 if (offset > 0) { /* Not used by bacula */
676 Dmsg1(400, "lseek_dvd SEEK_END called with an invalid offset %s\n",
677 edit_uint64(offset, ed1));
681 /* If we are already on a spooled part and have the
682 * right part number, simply seek
684 if (dev->is_part_spooled() && dev->part > dev->num_dvd_parts) {
685 if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
688 Dmsg1(400, "lseek_dvd SEEK_END returns %s\n",
689 edit_uint64(pos + dev->part_start, ed1));
690 return pos + dev->part_start;
694 * Load the first part, then load the next until we reach the last one.
695 * This is the only way to be sure we compute the right file address.
697 * Save previous openmode, and open all but last part read-only
700 int modesave = dev->openmode;
701 if (dvd_open_first_part(dcr, OPEN_READ_ONLY) < 0) {
702 Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
705 if (dev->num_dvd_parts > 0) {
706 while (dev->part < dev->num_dvd_parts) {
707 if (dvd_open_next_part(dcr) < 0) {
708 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
712 dev->openmode = modesave;
713 if (dvd_open_next_part(dcr) < 0) {
714 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
718 return lseek_dvd(dcr, 0, SEEK_END);
722 Dmsg0(400, "Seek call error.\n");
728 bool dvd_close_job(DCR *dcr)
730 DEVICE *dev = dcr->dev;
735 * If the device is a dvd and WritePartAfterJob
736 * is set to yes, open the next part, so, in case of a device
737 * that requires mount, it will be written to the device.
739 if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
740 Dmsg1(400, "Writing last part=%d write_partafter_job is set.\n",
742 if (dev->part < dev->num_dvd_parts+1) {
743 Jmsg3(jcr, M_FATAL, 0, _("Error writing. Current part less than total number of parts (%d/%d, device=%s)\n"),
744 dev->part, dev->num_dvd_parts, dev->print_name());
745 dev->dev_errno = EIO;
749 if (ok && !dvd_write_part(dcr)) {
750 Jmsg2(jcr, M_FATAL, 0, _("Unable to write last on %s: ERR=%s\n"),
751 dev->print_name(), dev->bstrerror());
752 dev->dev_errno = EIO;
759 bool truncate_dvd(DCR *dcr)
761 DEVICE* dev = dcr->dev;
763 dev->close_part(dcr);
765 if (!unmount_dvd(dev, 1)) {
766 Dmsg0(400, "truncate_dvd: Failed to unmount DVD\n");
770 /* Set num_dvd_parts to zero (on disk) */
771 dev->num_dvd_parts = 0;
772 dcr->VolCatInfo.VolCatParts = 0;
773 dev->VolCatInfo.VolCatParts = 0;
775 Dmsg0(400, "truncate_dvd: Opening first part (1)...\n");
777 dev->truncating = true;
778 if (dvd_open_first_part(dcr, CREATE_READ_WRITE) < 0) {
779 Dmsg0(400, "truncate_dvd: Error while opening first part (1).\n");
780 dev->truncating = false;
784 Dmsg0(400, "truncate_dvd: Truncating...\n");
786 /* If necessary, truncate it spool file. */
787 if (ftruncate(dev->fd, 0) != 0) {
789 Mmsg2(dev->errmsg, _("Unable to truncate device %s. ERR=%s\n"),
790 dev->print_name(), be.strerror());
791 dev->truncating = false;
795 dev->close_part(dcr);
797 Dmsg0(400, "truncate_dvd: Opening first part (2)...\n");
800 * Now actually truncate the DVD
801 * This is really kludgy, why not an argument or a separate
804 if (!dvd_write_part(dcr)) {
805 Dmsg0(400, "truncate_dvd: Error while writing to DVD.\n");
806 dev->truncating = false;
809 dev->truncating = false;
811 /* Set num_dvd_parts to zero (on disk) */
812 dev->num_dvd_parts = 0;
813 dcr->VolCatInfo.VolCatParts = 0;
814 dev->VolCatInfo.VolCatParts = 0;
815 /* Clear the size of the volume */
816 dev->VolCatInfo.VolCatBytes = 0;
817 dcr->VolCatInfo.VolCatBytes = 0;
821 if (!dir_update_volume_info(dcr, false)) {
826 if (dvd_open_first_part(dcr, OPEN_READ_WRITE) < 0) {
827 Dmsg0(400, "truncate_dvd: Error while opening first part (2).\n");
834 /* Checks if we can write on a non-blank DVD: meaning that it just have been
835 * truncated (there is only one zero-sized file on the DVD, with the right
838 * Note! Normally if we can mount the device, which should be the case
839 * when we get here, it is not a blank DVD. Hence we check if
840 * there is a zero length file with the right name, in which case
842 * This seems terribly kludgie to me. KES
844 bool check_can_write_on_non_blank_dvd(DCR *dcr)
846 DEVICE* dev = dcr->dev;
848 struct dirent *entry, *result;
852 struct stat filestat;
854 name_max = pathconf(".", _PC_NAME_MAX);
855 if (name_max < 1024) {
859 if (!(dp = opendir(dev->device->mount_point))) {
861 dev->dev_errno = errno;
862 Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n",
863 dev->device->mount_point, dev->print_name(), be.strerror());
867 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
869 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
870 dev->dev_errno = EIO;
871 Dmsg2(129, "check_can_write_on_non_blank_dvd: no more files in dir %s (dev=%s)\n",
872 dev->device->mount_point, dev->print_name());
875 Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n",
876 result->d_name, dev->VolCatInfo.VolCatName);
877 if (strcmp(result->d_name, dev->VolCatInfo.VolCatName) == 0) {
878 /* Found the file, checking it is empty */
879 POOL_MEM filename(PM_FNAME);
880 pm_strcpy(filename, dev->device->mount_point);
881 if (filename.c_str()[strlen(filename.c_str())-1] != '/') {
882 pm_strcat(filename, "/");
884 pm_strcat(filename, dev->VolCatInfo.VolCatName);
885 if (stat(filename.c_str(), &filestat) < 0) {
887 dev->dev_errno = errno;
888 Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n",
889 filename.c_str(), be.strerror());
892 Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %lld\n",
893 filename.c_str(), filestat.st_size);
894 matched = filestat.st_size == 0;
903 /* There are more than 3 files (., .., and the volume file) */
904 Dmsg1(29, "Cannot write on blank DVD too many files %d greater than 3\n", count);
908 Dmsg2(29, "OK can_write_on_non_blank_dvd: got %d files in the mount point (matched=%d)\n", count, matched);
913 * Mount a DVD device, then scan to find out how many parts
916 int find_num_dvd_parts(DCR *dcr)
918 DEVICE *dev = dcr->dev;
921 if (!dev->is_dvd()) {
927 struct dirent *entry, *result;
929 int len = strlen(dcr->VolCatInfo.VolCatName);
931 /* Now count the number of parts */
932 name_max = pathconf(".", _PC_NAME_MAX);
933 if (name_max < 1024) {
937 if (!(dp = opendir(dev->device->mount_point))) {
939 dev->dev_errno = errno;
940 Dmsg3(29, "find_num_dvd_parts: failed to open dir %s (dev=%s), ERR=%s\n",
941 dev->device->mount_point, dev->print_name(), be.strerror());
945 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
947 Dmsg1(100, "Looking for Vol=%s\n", dcr->VolCatInfo.VolCatName);
951 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
952 dev->dev_errno = EIO;
953 Dmsg2(129, "find_num_dvd_parts: failed to find suitable file in dir %s (dev=%s)\n",
954 dev->device->mount_point, dev->print_name());
957 flen = strlen(result->d_name);
960 result->d_name[len] = 0;
961 if (strcmp(dcr->VolCatInfo.VolCatName, result->d_name) == 0) {
963 Dmsg1(100, "find_num_dvd_parts: found part: %s\n", result->d_name);
968 Dmsg2(129, "find_num_dvd_parts: ignoring %s in %s\n",
969 result->d_name, dev->device->mount_point);
974 Dmsg1(29, "find_num_dvd_parts = %d\n", num_parts);
978 dev->set_freespace_ok();
979 if (dev->is_mounted()) {