2 Bacula® - The Network Backup Solution
4 Copyright (C) 2005-2012 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
30 * dvd.c -- Routines specific to DVD devices (and
31 * possibly other removable hard media).
33 * Nicolas Boichat, MMV
40 /* Forward referenced functions */
41 static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name);
44 * Write the current volume/part filename to archive_name.
46 void make_mounted_dvd_filename(DEVICE *dev, POOL_MEM &archive_name)
48 pm_strcpy(archive_name, dev->device->mount_point);
49 add_file_and_part_name(dev, archive_name);
52 void make_spooled_dvd_filename(DEVICE *dev, POOL_MEM &archive_name)
54 /* Use the working directory if spool directory is not defined */
55 if (dev->device->spool_directory) {
56 pm_strcpy(archive_name, dev->device->spool_directory);
58 pm_strcpy(archive_name, working_directory);
60 add_file_and_part_name(dev, archive_name);
63 static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name)
67 if (!IsPathSeparator(archive_name.c_str()[strlen(archive_name.c_str())-1])) {
68 pm_strcat(archive_name, "/");
71 pm_strcat(archive_name, dev->getVolCatName());
72 /* if part > 1, append .# to the filename (where # is the part number) */
74 pm_strcat(archive_name, ".");
75 bsnprintf(partnumber, sizeof(partnumber), "%d", dev->part);
76 pm_strcat(archive_name, partnumber);
78 Dmsg2(400, "Exit add_file_part_name: arch=%s, part=%d\n",
79 archive_name.c_str(), dev->part);
82 /* Update the free space on the device */
83 bool DEVICE::update_freespace()
85 POOL_MEM ocmd(PM_FNAME);
94 if (!is_dvd() || is_freespace_ok()) {
98 /* The device must be mounted in order to dvd-freespace to work */
102 icmd = device->free_space_command;
106 free_space_errno = 0;
107 clear_freespace_ok(); /* No valid freespace */
109 Dmsg2(29, "ERROR: update_free_space_dev: free_space=%s, free_space_errno=%d (!icmd)\n",
110 edit_uint64(free_space, ed1), free_space_errno);
111 Mmsg(errmsg, _("No FreeSpace command defined.\n"));
115 edit_mount_codes(ocmd, icmd);
117 Dmsg1(29, "update_freespace: cmd=%s\n", ocmd.c_str());
119 results = get_pool_memory(PM_MESSAGE);
121 /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */
126 Dmsg1(20, "Run freespace prog=%s\n", ocmd.c_str());
127 status = run_program_full_output(ocmd.c_str(), max_open_wait/2, results);
128 Dmsg2(500, "Freespace status=%d result=%s\n", status, results);
130 free = str_to_int64(results);
131 Dmsg1(400, "Free space program run: Freespace=%s\n", results);
134 free_space_errno = 0;
135 set_freespace_ok(); /* have valid freespace */
143 free_space_errno = EPIPE;
144 clear_freespace_ok(); /* no valid freespace */
145 Mmsg2(errmsg, _("Cannot run free space command. Results=%s ERR=%s\n"),
146 results, be.bstrerror(status));
149 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
150 "free_space_errno=%d ERR=%s\n", print_name(),
151 edit_uint64(free_space, ed1), free_space_errno,
157 dev_errno = free_space_errno;
158 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
159 "free_space_errno=%d ERR=%s\n",
160 print_name(), edit_uint64(free_space, ed1),
161 free_space_errno, errmsg);
165 free_pool_memory(results);
166 Dmsg4(29, "leave update_freespace: free_space=%s freespace_ok=%d free_space_errno=%d have_media=%d\n",
167 edit_uint64(free_space, ed1), !!is_freespace_ok(), free_space_errno, !!have_media());
173 * Note!!!! Part numbers now begin at 1. The part number is
174 * suppressed from the first part, which is just the Volume
175 * name. Each subsequent part is the Volumename.partnumber.
177 * Write a part (Vol, Vol.2, ...) from the spool to the DVD
178 * This routine does not update the part number, so normally, you
179 * should call open_next_part()
181 * It is also called from truncate_dvd to "blank" the medium, as
182 * well as from block.c when the DVD is full to write the last part.
184 bool dvd_write_part(DCR *dcr)
186 DEVICE *dev = dcr->dev;
187 POOL_MEM archive_name(PM_FNAME);
190 * Don't write empty part files.
191 * This is only useful when growisofs does not support write beyond
194 * - 3.9 GB on the volume, dvd-freespace reports 0.4 GB free
195 * - Write 0.2 GB on the volume, Bacula thinks it could still
196 * append data, it creates a new empty part.
197 * - dvd-freespace reports 0 GB free, as the 4GB boundary has
199 * - Bacula thinks he must finish to write to the device, so it
200 * tries to write the last part (0-byte), but dvd-writepart fails...
202 * There is one exception: when recycling a volume, we write a blank part
203 * file, so, then, we need to accept to write it.
205 if (dev->part_size == 0 && !dev->truncating) {
206 Dmsg2(29, "dvd_write_part: device is %s, won't write blank part %d\n", dev->print_name(), dev->part);
207 /* Delete spool file */
208 make_spooled_dvd_filename(dev, archive_name);
209 unlink(archive_name.c_str());
210 dev->set_part_spooled(false);
211 Dmsg1(29, "========= unlink(%s)\n", archive_name.c_str());
216 POOL_MEM ocmd(PM_FNAME);
217 POOL_MEM results(PM_MESSAGE);
223 dev->clear_freespace_ok(); /* need to update freespace */
226 Dmsg3(29, "dvd_write_part: device is %s, part is %d, is_mounted=%d\n", dev->print_name(), dev->part, dev->is_mounted());
227 icmd = dev->device->write_part_command;
229 dev->edit_mount_codes(ocmd, icmd);
232 * original line follows
233 * timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
234 * I modified this for a longer timeout; pre-formatting, blanking and
235 * writing can take quite a while
238 /* Explanation of the timeout value, when writing the first part,
240 * 9 GB, write speed 1x: 6990 seconds (almost 2 hours...)
241 * Overhead: 900 seconds (starting, initializing, finalizing,probably
242 * reloading 15 minutes)
244 * A reasonable last-exit timeout would be 16000 seconds. Quite long -
245 * almost 4.5 hours, but hopefully, that timeout will only ever be needed
246 * in case of a serious emergency.
249 if (dev->part == 1) {
252 timeout = dev->max_open_wait + (dev->part_size/(1350*1024/4));
255 Dmsg2(20, "Write part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
256 status = run_program_full_output(ocmd.c_str(), timeout, results.addr());
257 Dmsg2(20, "Write part status=%d result=%s\n", status, results.c_str());
259 dev->blank_dvd = false;
261 Jmsg2(dcr->jcr, M_FATAL, 0, _("Error writing part %d to the DVD: ERR=%s\n"),
262 dev->part, results.c_str());
263 Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"),
265 Dmsg1(100, "%s\n", dev->errmsg);
266 dev->dev_errno = EIO;
267 if (!dev->truncating) {
268 dcr->mark_volume_in_error();
273 Jmsg(dcr->jcr, M_INFO, 0, _("Part %d (%lld bytes) written to DVD.\n"), dev->part, dev->part_size);
274 Dmsg3(400, "dvd_write_part: Part %d (%lld bytes) written to DVD\nResults: %s\n",
275 dev->part, dev->part_size, results.c_str());
277 dev->num_dvd_parts++; /* there is now one more part on DVD */
278 dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
279 dcr->VolCatInfo.VolCatParts = dev->num_dvd_parts;
280 Dmsg1(100, "Update num_parts=%d\n", dev->num_dvd_parts);
282 /* Delete spool file */
283 make_spooled_dvd_filename(dev, archive_name);
284 unlink(archive_name.c_str());
285 dev->set_part_spooled(false);
286 Dmsg1(29, "========= unlink(%s)\n", archive_name.c_str());
289 /* growisofs umounted the device, so remount it (it will update the free space) */
290 dev->clear_mounted();
292 Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"),
293 edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
299 * Open the next part file.
301 * - Increment part number
302 * - Reopen the device
304 int dvd_open_next_part(DCR *dcr)
306 DEVICE *dev = dcr->dev;
308 Dmsg6(29, "Enter: == open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n",
309 dev->part, dev->num_dvd_parts, dev->print_name(),
310 dev->getVolCatName(), dev->openmode, dev->file_addr);
311 if (!dev->is_dvd()) {
312 Dmsg1(100, "Device %s is not dvd!!!!\n", dev->print_name());
316 /* When appending, do not open a new part if the current is empty */
317 if (dev->can_append() && (dev->part > dev->num_dvd_parts) &&
318 (dev->part_size == 0)) {
319 Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
323 dev->close_part(dcr); /* close current part */
326 * If we have a spooled part open, write it to the
327 * DVD before opening the next part.
329 if (dev->is_part_spooled()) {
330 Dmsg2(100, "Before open next write previous. part=%d num_parts=%d\n",
331 dev->part, dev->num_dvd_parts);
332 if (!dvd_write_part(dcr)) {
333 Dmsg0(29, "Error in dvd_write part.\n");
338 dev->part_start += dev->part_size;
340 Dmsg2(29, "Inc part=%d num_dvd_parts=%d\n", dev->part, dev->num_dvd_parts);
342 /* Are we working on a part past what is written in the DVD? */
343 if (dev->num_dvd_parts < dev->part) {
344 POOL_MEM archive_name(PM_FNAME);
347 * First check what is on DVD. If our part is there, we
348 * are in trouble, so bail out.
349 * NB: This is however not a problem if we are writing the first part.
350 * It simply means that we are over writing an existing volume...
352 if (dev->num_dvd_parts > 0) {
353 make_mounted_dvd_filename(dev, archive_name); /* makes dvd name */
354 Dmsg1(100, "Check if part on DVD: %s\n", archive_name.c_str());
355 if (stat(archive_name.c_str(), &buf) == 0) {
356 /* bad news bail out */
357 dev->set_part_spooled(false);
358 Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
359 archive_name.c_str());
365 Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->getVolCatName(),
368 /* Open next part. Note, this sets part_size for part opened. */
369 if (!dev->open(dcr, OPEN_READ_ONLY)) {
372 dev->set_labeled(); /* all next parts are "labeled" */
378 * Open the first part file.
380 * - Reopen the device
382 static bool dvd_open_first_part(DCR *dcr, int mode)
384 DEVICE *dev = dcr->dev;
386 Dmsg5(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_dvd_parts=%d append=%d\n", dev->print_name(),
387 dev->getVolCatName(), dev->openmode, dev->num_dvd_parts, dev->can_append());
390 dev->close_part(dcr);
392 Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->getVolCatName(),
394 Dmsg0(100, "Set part=1\n");
398 if (!dev->open(dcr, mode)) {
399 Dmsg0(400, "open dev() failed\n");
402 Dmsg2(400, "Leave open_first_part state=%s append=%d\n", dev->is_open()?"open":"not open", dev->can_append());
409 * Do an lseek on a DVD handling all the different parts
411 boffset_t lseek_dvd(DCR *dcr, boffset_t offset, int whence)
415 char ed1[50], ed2[50];
417 if (!dcr) { /* can be NULL when called from rewind(NULL) */
422 Dmsg5(400, "Enter lseek_dvd fd=%d off=%s w=%d part=%d nparts=%d\n", dev->fd(),
423 edit_int64(offset, ed1), whence, dev->part, dev->num_dvd_parts);
427 Dmsg2(400, "lseek_dvd SEEK_SET to %s (part_start=%s)\n",
428 edit_int64(offset, ed1), edit_uint64(dev->part_start, ed2));
429 if ((uint64_t)offset >= dev->part_start) {
430 if ((uint64_t)offset == dev->part_start ||
431 (uint64_t)offset < dev->part_start+dev->part_size) {
432 /* We are staying in the current part, just seek */
433 #if defined(HAVE_WIN32)
434 pos = _lseeki64(dev->fd(), offset-dev->part_start, SEEK_SET);
436 pos = lseek(dev->fd(), offset-dev->part_start, SEEK_SET);
441 return pos + dev->part_start;
444 /* Load next part, and start again */
445 Dmsg0(100, "lseek open next part\n");
446 if (dvd_open_next_part(dcr) < 0) {
447 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
450 Dmsg2(100, "Recurse lseek after open next part=%d num_part=%d\n",
451 dev->part, dev->num_dvd_parts);
452 return lseek_dvd(dcr, offset, SEEK_SET);
456 * pos < dev->part_start :
457 * We need to access a previous part,
458 * so just load the first one, and seek again
459 * until the right one is loaded
461 Dmsg0(100, "lseek open first part\n");
462 if (!dvd_open_first_part(dcr, dev->openmode)) {
463 Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
466 Dmsg2(100, "Recurse lseek after open first part=%d num_part=%d\n",
467 dev->part, dev->num_dvd_parts);
468 return lseek_dvd(dcr, offset, SEEK_SET); /* system lseek */
472 Dmsg1(400, "lseek_dvd SEEK_CUR to %s\n", edit_int64(offset, ed1));
473 if ((pos = lseek(dev->fd(), 0, SEEK_CUR)) < 0) {
474 Dmsg0(400, "Seek error.\n");
477 pos += dev->part_start;
479 Dmsg1(400, "lseek_dvd SEEK_CUR returns %s\n", edit_uint64(pos, ed1));
482 Dmsg1(400, "do lseek_dvd SEEK_SET %s\n", edit_uint64(pos, ed1));
483 return lseek_dvd(dcr, pos, SEEK_SET);
487 Dmsg1(400, "lseek_dvd SEEK_END to %s\n", edit_int64(offset, ed1));
489 * Bacula does not use offsets for SEEK_END
490 * Also, Bacula uses seek_end only when it wants to
491 * append to the volume, so for a dvd that means
492 * that the volume must be spooled since the DVD
493 * itself is read-only (as currently implemented).
495 if (offset > 0) { /* Not used by bacula */
496 Dmsg1(400, "lseek_dvd SEEK_END called with an invalid offset %s\n",
497 edit_uint64(offset, ed1));
501 /* If we are already on a spooled part and have the
502 * right part number, simply seek
504 if (dev->is_part_spooled() && dev->part > dev->num_dvd_parts) {
505 if ((pos = lseek(dev->fd(), 0, SEEK_END)) < 0) {
508 Dmsg1(400, "lseek_dvd SEEK_END returns %s\n",
509 edit_uint64(pos + dev->part_start, ed1));
510 return pos + dev->part_start;
514 * Load the first part, then load the next until we reach the last one.
515 * This is the only way to be sure we compute the right file address.
517 * Save previous openmode, and open all but last part read-only
520 int modesave = dev->openmode;
521 if (!dvd_open_first_part(dcr, OPEN_READ_ONLY)) {
522 Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
525 if (dev->num_dvd_parts > 0) {
526 while (dev->part < dev->num_dvd_parts) {
527 if (dvd_open_next_part(dcr) < 0) {
528 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
532 dev->openmode = modesave;
533 if (dvd_open_next_part(dcr) < 0) {
534 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
538 return lseek_dvd(dcr, 0, SEEK_END);
542 Dmsg0(400, "Seek call error.\n");
548 bool dvd_close_job(DCR *dcr)
550 DEVICE *dev = dcr->dev;
555 * If the device is a dvd and WritePartAfterJob
556 * is set to yes, open the next part, so, in case of a device
557 * that requires mount, it will be written to the device.
559 if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
560 Dmsg1(400, "Writing last part=%d write_partafter_job is set.\n",
562 if (dev->part < dev->num_dvd_parts+1) {
563 Jmsg3(jcr, M_FATAL, 0, _("Error writing. Current part less than total number of parts (%d/%d, device=%s)\n"),
564 dev->part, dev->num_dvd_parts, dev->print_name());
565 dev->dev_errno = EIO;
569 if (ok && !dvd_write_part(dcr)) {
570 Jmsg2(jcr, M_FATAL, 0, _("Unable to write last on %s: ERR=%s\n"),
571 dev->print_name(), dev->bstrerror());
572 dev->dev_errno = EIO;
579 void dvd_remove_empty_part(DCR *dcr)
581 DEVICE *dev = dcr->dev;
583 /* Remove the last part file if it is empty */
584 if (dev->is_dvd() && dev->num_dvd_parts > 0) {
586 uint32_t part_save = dev->part;
587 POOL_MEM archive_name(PM_FNAME);
590 dev->part = dev->num_dvd_parts;
591 make_spooled_dvd_filename(dev, archive_name);
592 /* Check that the part file is empty */
593 status = stat(archive_name.c_str(), &statp);
594 if (status == 0 && statp.st_size == 0) {
595 Dmsg3(100, "Unlink empty part in close call make_dvd_filename. part=%d num=%d vol=%s\n",
596 part_save, dev->num_dvd_parts, dev->getVolCatName());
597 Dmsg1(100, "unlink(%s)\n", archive_name.c_str());
598 unlink(archive_name.c_str());
599 if (part_save == dev->part) {
600 dev->set_part_spooled(false); /* no spooled part left */
602 } else if (status < 0) {
603 if (part_save == dev->part) {
604 dev->set_part_spooled(false); /* spool doesn't exit */
607 dev->part = part_save; /* restore part number */
611 bool truncate_dvd(DCR *dcr)
613 DEVICE* dev = dcr->dev;
615 dev->clear_freespace_ok(); /* need to update freespace */
616 dev->close_part(dcr);
618 if (!dev->unmount(1)) {
619 Dmsg0(400, "truncate_dvd: Failed to unmount DVD\n");
623 /* If necessary, delete its spool file. */
624 if (dev->is_part_spooled()) {
625 POOL_MEM archive_name(PM_FNAME);
626 /* Delete spool file */
627 make_spooled_dvd_filename(dev, archive_name);
628 unlink(archive_name.c_str());
629 dev->set_part_spooled(false);
632 /* Set num_dvd_parts to zero (on disk) */
634 dev->num_dvd_parts = 0;
635 dcr->VolCatInfo.VolCatParts = 0;
636 dev->VolCatInfo.VolCatParts = 0;
638 Dmsg0(400, "truncate_dvd: Opening first part (1)...\n");
640 dev->truncating = true;
641 /* This creates a zero length spool file and sets part=1 */
642 if (!dvd_open_first_part(dcr, CREATE_READ_WRITE)) {
643 Dmsg0(400, "truncate_dvd: Error while opening first part (1).\n");
644 dev->truncating = false;
648 dev->close_part(dcr);
650 Dmsg0(400, "truncate_dvd: Opening first part (2)...\n");
653 * Now actually truncate the DVD which is done by writing
654 * a zero length part to the DVD/
656 if (!dvd_write_part(dcr)) {
657 Dmsg0(400, "truncate_dvd: Error while writing to DVD.\n");
658 dev->truncating = false;
661 dev->truncating = false;
663 /* Set num_dvd_parts to zero (on disk) */
665 dev->num_dvd_parts = 0;
666 dcr->VolCatInfo.VolCatParts = 0;
667 dev->VolCatInfo.VolCatParts = 0;
668 /* Clear the size of the volume */
669 dev->VolCatInfo.VolCatBytes = 0;
670 dcr->VolCatInfo.VolCatBytes = 0;
673 if (!dir_update_volume_info(dcr, false, true)) {
681 * Checks if we can write on a non-blank DVD: meaning that it just have been
682 * truncated (there is only one zero-sized file on the DVD).
684 * Note! Normally if we can mount the device, which should be the case
685 * when we get here, it is not a blank DVD. Hence we check if
686 * if all files are of zero length (i.e. no data), in which case we allow it.
689 bool check_can_write_on_non_blank_dvd(DCR *dcr)
691 DEVICE* dev = dcr->dev;
693 struct dirent *entry, *result;
695 struct stat filestat;
698 name_max = pathconf(".", _PC_NAME_MAX);
699 if (name_max < 1024) {
703 if (!(dp = opendir(dev->device->mount_point))) {
705 dev->dev_errno = errno;
706 Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n",
707 dev->device->mount_point, dev->print_name(), be.bstrerror());
711 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
713 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
714 dev->dev_errno = EIO;
715 Dmsg2(129, "check_can_write_on_non_blank_dvd: no more files in dir %s (dev=%s)\n",
716 dev->device->mount_point, dev->print_name());
719 Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n",
720 result->d_name, dev->getVolCatName());
721 if (strcmp(result->d_name, ".") && strcmp(result->d_name, "..") &&
722 strcmp(result->d_name, ".keep")) {
723 /* Found a file, checking it is empty */
724 POOL_MEM filename(PM_FNAME);
725 pm_strcpy(filename, dev->device->mount_point);
726 if (!IsPathSeparator(filename.c_str()[strlen(filename.c_str())-1])) {
727 pm_strcat(filename, "/");
729 pm_strcat(filename, result->d_name);
730 if (stat(filename.c_str(), &filestat) < 0) {
732 dev->dev_errno = errno;
733 Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n",
734 filename.c_str(), be.bstrerror());
738 Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %lld\n",
739 filename.c_str(), filestat.st_size);
740 if (filestat.st_size != 0) {
750 Dmsg1(29, "OK can_write_on_non_blank_dvd: OK=%d\n", ok);
755 * Mount a DVD device, then scan to find out how many parts
758 int find_num_dvd_parts(DCR *dcr)
760 DEVICE *dev = dcr->dev;
763 if (!dev->is_dvd()) {
769 struct dirent *entry, *result;
771 int len = strlen(dcr->getVolCatName());
773 /* Now count the number of parts */
774 name_max = pathconf(".", _PC_NAME_MAX);
775 if (name_max < 1024) {
779 if (!(dp = opendir(dev->device->mount_point))) {
781 dev->dev_errno = errno;
782 Dmsg3(29, "find_num_dvd_parts: failed to open dir %s (dev=%s), ERR=%s\n",
783 dev->device->mount_point, dev->print_name(), be.bstrerror());
787 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
789 Dmsg1(100, "Looking for Vol=%s\n", dcr->getVolCatName());
793 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
794 dev->dev_errno = EIO;
795 Dmsg2(129, "find_num_dvd_parts: failed to find suitable file in dir %s (dev=%s)\n",
796 dev->device->mount_point, dev->print_name());
799 flen = strlen(result->d_name);
802 result->d_name[len] = 0;
803 if (strcmp(dcr->getVolCatName(), result->d_name) == 0) {
805 Dmsg1(100, "find_num_dvd_parts: found part: %s\n", result->d_name);
810 Dmsg2(129, "find_num_dvd_parts: ignoring %s in %s\n",
811 result->d_name, dev->device->mount_point);
816 Dmsg1(29, "find_num_dvd_parts = %d\n", num_parts);
820 dev->set_freespace_ok();
821 if (dev->is_mounted()) {