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 void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name);
32 * Write the current volume/part filename to archive_name.
34 void make_mounted_dvd_filename(DEVICE *dev, POOL_MEM &archive_name)
36 pm_strcpy(archive_name, dev->device->mount_point);
37 add_file_and_part_name(dev, archive_name);
40 void make_spooled_dvd_filename(DEVICE *dev, POOL_MEM &archive_name)
42 /* Use the working directory if spool directory is not defined */
43 if (dev->device->spool_directory) {
44 pm_strcpy(archive_name, dev->device->spool_directory);
46 pm_strcpy(archive_name, working_directory);
48 add_file_and_part_name(dev, archive_name);
51 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);
70 /* Update the free space on the device */
71 bool DEVICE::update_freespace()
73 POOL_MEM ocmd(PM_FNAME);
82 if (!is_dvd() || is_freespace_ok()) {
86 /* The device must be mounted in order to dvd-freespace to work */
89 sm_check(__FILE__, __LINE__, false);
90 icmd = device->free_space_command;
95 clear_freespace_ok(); /* No valid freespace */
97 Dmsg2(29, "ERROR: update_free_space_dev: free_space=%s, free_space_errno=%d (!icmd)\n",
98 edit_uint64(free_space, ed1), free_space_errno);
99 Mmsg(errmsg, _("No FreeSpace command defined.\n"));
103 edit_mount_codes(ocmd, icmd);
105 Dmsg1(29, "update_freespace: cmd=%s\n", ocmd.c_str());
107 results = get_pool_memory(PM_MESSAGE);
109 /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */
114 Dmsg1(20, "Run freespace prog=%s\n", ocmd.c_str());
115 status = run_program_full_output(ocmd.c_str(), max_open_wait/2, results);
116 Dmsg2(500, "Freespace status=%d result=%s\n", status, results);
118 free = str_to_int64(results);
119 Dmsg1(400, "Free space program run: Freespace=%s\n", results);
122 free_space_errno = 0;
123 set_freespace_ok(); /* have valid freespace */
131 free_space_errno = EPIPE;
132 clear_freespace_ok(); /* no valid freespace */
133 Mmsg2(errmsg, _("Cannot run free space command. Results=%s ERR=%s\n"),
134 results, be.strerror(status));
137 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
138 "free_space_errno=%d ERR=%s\n", print_name(),
139 edit_uint64(free_space, ed1), free_space_errno,
145 dev_errno = free_space_errno;
146 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
147 "free_space_errno=%d ERR=%s\n",
148 print_name(), edit_uint64(free_space, ed1),
149 free_space_errno, errmsg);
153 free_pool_memory(results);
154 Dmsg4(29, "leave update_freespace: free_space=%s freespace_ok=%d free_space_errno=%d have_media=%d\n",
155 edit_uint64(free_space, ed1), !!is_freespace_ok(), free_space_errno, !!have_media());
156 sm_check(__FILE__, __LINE__, false);
161 * Note!!!! Part numbers now begin at 1. The part number is
162 * suppressed from the first part, which is just the Volume
163 * name. Each subsequent part is the Volumename.partnumber.
165 * Write a part (Vol, Vol.2, ...) from the spool to the DVD
166 * This routine does not update the part number, so normally, you
167 * should call open_next_part()
169 * It is also called from truncate_dvd to "blank" the medium, as
170 * well as from block.c when the DVD is full to write the last part.
172 bool dvd_write_part(DCR *dcr)
174 DEVICE *dev = dcr->dev;
175 POOL_MEM archive_name(PM_FNAME);
178 * Don't write empty part files.
179 * This is only useful when growisofs does not support write beyond
182 * - 3.9 GB on the volume, dvd-freespace reports 0.4 GB free
183 * - Write 0.2 GB on the volume, Bacula thinks it could still
184 * append data, it creates a new empty part.
185 * - dvd-freespace reports 0 GB free, as the 4GB boundary has
187 * - Bacula thinks he must finish to write to the device, so it
188 * tries to write the last part (0-byte), but dvd-writepart fails...
190 * There is one exception: when recycling a volume, we write a blank part
191 * file, so, then, we need to accept to write it.
193 if (dev->part_size == 0 && !dev->truncating) {
194 Dmsg2(29, "dvd_write_part: device is %s, won't write blank part %d\n", dev->print_name(), dev->part);
195 /* Delete spool file */
196 make_spooled_dvd_filename(dev, archive_name);
197 unlink(archive_name.c_str());
198 dev->set_part_spooled(false);
199 Dmsg1(29, "========= unlink(%s)\n", archive_name.c_str());
200 sm_check(__FILE__, __LINE__, false);
204 POOL_MEM ocmd(PM_FNAME);
205 POOL_MEM results(PM_MESSAGE);
211 dev->clear_freespace_ok(); /* need to update freespace */
213 sm_check(__FILE__, __LINE__, false);
214 Dmsg3(29, "dvd_write_part: device is %s, part is %d, is_mounted=%d\n", dev->print_name(), dev->part, dev->is_mounted());
215 icmd = dev->device->write_part_command;
217 dev->edit_mount_codes(ocmd, icmd);
220 * original line follows
221 * timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
222 * I modified this for a longer timeout; pre-formatting, blanking and
223 * writing can take quite a while
226 /* Explanation of the timeout value, when writing the first part,
228 * 9 GB, write speed 1x: 6990 seconds (almost 2 hours...)
229 * Overhead: 900 seconds (starting, initializing, finalizing,probably
230 * reloading 15 minutes)
232 * A reasonable last-exit timeout would be 16000 seconds. Quite long -
233 * almost 4.5 hours, but hopefully, that timeout will only ever be needed
234 * in case of a serious emergency.
237 if (dev->part == 1) {
240 timeout = dev->max_open_wait + (dev->part_size/(1350*1024/4));
243 Dmsg2(20, "Write part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
244 status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
245 Dmsg2(20, "Write part status=%d result=%s\n", status, results.c_str());
247 dev->blank_dvd = false;
249 Jmsg2(dcr->jcr, M_FATAL, 0, _("Error writing part %d to the DVD: ERR=%s\n"),
250 dev->part, results.c_str());
251 Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"),
253 Dmsg1(100, "%s\n", dev->errmsg);
254 dev->dev_errno = EIO;
255 if (!dev->truncating) {
256 mark_volume_in_error(dcr);
258 sm_check(__FILE__, __LINE__, false);
261 Jmsg(dcr->jcr, M_INFO, 0, _("Part %d (%lld bytes) written to DVD.\n"), dev->part, dev->part_size);
262 Dmsg3(400, "dvd_write_part: Part %d (%lld bytes) written to DVD\nResults: %s\n",
263 dev->part, dev->part_size, results.c_str());
265 dev->num_dvd_parts++; /* there is now one more part on DVD */
266 dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
267 dcr->VolCatInfo.VolCatParts = dev->num_dvd_parts;
268 Dmsg1(100, "Update num_parts=%d\n", dev->num_dvd_parts);
270 /* Delete spool file */
271 make_spooled_dvd_filename(dev, archive_name);
272 unlink(archive_name.c_str());
273 dev->set_part_spooled(false);
274 Dmsg1(29, "========= unlink(%s)\n", archive_name.c_str());
275 sm_check(__FILE__, __LINE__, false);
277 /* growisofs umounted the device, so remount it (it will update the free space) */
278 dev->clear_mounted();
280 Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"),
281 edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
282 sm_check(__FILE__, __LINE__, false);
287 * Open the next part file.
289 * - Increment part number
290 * - Reopen the device
292 int dvd_open_next_part(DCR *dcr)
294 DEVICE *dev = dcr->dev;
296 Dmsg6(29, "Enter: == open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n",
297 dev->part, dev->num_dvd_parts, dev->print_name(),
298 dev->VolCatInfo.VolCatName, dev->openmode, dev->file_addr);
299 if (!dev->is_dvd()) {
300 Dmsg1(100, "Device %s is not dvd!!!!\n", dev->print_name());
304 /* When appending, do not open a new part if the current is empty */
305 if (dev->can_append() && (dev->part > dev->num_dvd_parts) &&
306 (dev->part_size == 0)) {
307 Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
311 dev->close_part(dcr); /* close current part */
314 * If we have a spooled part open, write it to the
315 * DVD before opening the next part.
317 if (dev->is_part_spooled()) {
318 Dmsg2(100, "Before open next write previous. part=%d num_parts=%d\n",
319 dev->part, dev->num_dvd_parts);
320 if (!dvd_write_part(dcr)) {
321 Dmsg0(29, "Error in dvd_write part.\n");
326 dev->part_start += dev->part_size;
328 Dmsg2(29, "Inc part=%d num_dvd_parts=%d\n", dev->part, dev->num_dvd_parts);
330 /* Are we working on a part past what is written in the DVD? */
331 if (dev->num_dvd_parts < dev->part) {
332 POOL_MEM archive_name(PM_FNAME);
335 * First check what is on DVD. If our part is there, we
336 * are in trouble, so bail out.
337 * NB: This is however not a problem if we are writing the first part.
338 * It simply means that we are over writing an existing volume...
340 if (dev->num_dvd_parts > 0) {
341 make_mounted_dvd_filename(dev, archive_name); /* makes dvd name */
342 Dmsg1(100, "Check if part on DVD: %s\n", archive_name.c_str());
343 if (stat(archive_name.c_str(), &buf) == 0) {
344 /* bad news bail out */
345 dev->set_part_spooled(false);
346 Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
347 archive_name.c_str());
353 Dmsg2(400, "num_dvd_parts=%d part=%d\n", dev->num_dvd_parts, dev->part);
354 make_spooled_dvd_filename(dev, archive_name); /* makes spool name */
356 /* Check if the next part exists in spool directory . */
357 Dmsg1(100, "Check if part on spool: %s\n", archive_name.c_str());
358 if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
359 Dmsg1(29, "======= Part %s is in the way, deleting it...\n", archive_name.c_str());
360 /* Then try to unlink it */
361 if (unlink(archive_name.c_str()) < 0) {
363 dev->set_part_spooled(false);
364 dev->dev_errno = errno;
365 Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"),
366 archive_name.c_str(), be.strerror());
373 Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName,
376 /* Open next part. Note, this sets part_size for part opened. */
377 if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
380 dev->set_labeled(); /* all next parts are "labeled" */
386 * Open the first part file.
388 * - Reopen the device
390 static bool dvd_open_first_part(DCR *dcr, int mode)
392 DEVICE *dev = dcr->dev;
394 Dmsg5(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_dvd_parts=%d append=%d\n", dev->print_name(),
395 dev->VolCatInfo.VolCatName, dev->openmode, dev->num_dvd_parts, dev->can_append());
398 dev->close_part(dcr);
400 Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName,
402 Dmsg0(100, "Set part=1\n");
406 if (dev->open(dcr, mode) < 0) {
407 Dmsg0(400, "open dev() failed\n");
410 Dmsg2(400, "Leave open_first_part state=%s append=%d\n", dev->is_open()?"open":"not open", dev->can_append());
417 * Do an lseek on a DVD handling all the different parts
419 off_t lseek_dvd(DCR *dcr, off_t offset, int whence)
421 DEVICE *dev = dcr->dev;
423 char ed1[50], ed2[50];
425 Dmsg5(400, "Enter lseek_dvd fd=%d off=%s w=%d part=%d nparts=%d\n", dev->fd,
426 edit_int64(offset, ed1), whence, dev->part, dev->num_dvd_parts);
430 Dmsg2(400, "lseek_dvd SEEK_SET to %s (part_start=%s)\n",
431 edit_int64(offset, ed1), edit_uint64(dev->part_start, ed2));
432 if ((uint64_t)offset >= dev->part_start) {
433 if ((uint64_t)offset == dev->part_start ||
434 (uint64_t)offset < dev->part_start+dev->part_size) {
435 /* We are staying in the current part, just seek */
436 if ((pos = lseek(dev->fd, offset-dev->part_start, SEEK_SET)) < 0) {
439 return pos + dev->part_start;
442 /* Load next part, and start again */
443 Dmsg0(100, "lseek open next part\n");
444 if (dvd_open_next_part(dcr) < 0) {
445 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
448 Dmsg2(100, "Recurse lseek after open next part=%d num_part=%d\n",
449 dev->part, dev->num_dvd_parts);
450 return lseek_dvd(dcr, offset, SEEK_SET);
454 * pos < dev->part_start :
455 * We need to access a previous part,
456 * so just load the first one, and seek again
457 * until the right one is loaded
459 Dmsg0(100, "lseek open first part\n");
460 if (!dvd_open_first_part(dcr, dev->openmode)) {
461 Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
464 Dmsg2(100, "Recurse lseek after open first part=%d num_part=%d\n",
465 dev->part, dev->num_dvd_parts);
466 return lseek_dvd(dcr, offset, SEEK_SET); /* system lseek */
470 Dmsg1(400, "lseek_dvd SEEK_CUR to %s\n", edit_int64(offset, ed1));
471 if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) {
472 Dmsg0(400, "Seek error.\n");
475 pos += dev->part_start;
477 Dmsg1(400, "lseek_dvd SEEK_CUR returns %s\n", edit_uint64(pos, ed1));
480 Dmsg1(400, "do lseek_dvd SEEK_SET %s\n", edit_uint64(pos, ed1));
481 return lseek_dvd(dcr, pos, SEEK_SET);
485 Dmsg1(400, "lseek_dvd SEEK_END to %s\n", edit_int64(offset, ed1));
487 * Bacula does not use offsets for SEEK_END
488 * Also, Bacula uses seek_end only when it wants to
489 * append to the volume, so for a dvd that means
490 * that the volume must be spooled since the DVD
491 * itself is read-only (as currently implemented).
493 if (offset > 0) { /* Not used by bacula */
494 Dmsg1(400, "lseek_dvd SEEK_END called with an invalid offset %s\n",
495 edit_uint64(offset, ed1));
499 /* If we are already on a spooled part and have the
500 * right part number, simply seek
502 if (dev->is_part_spooled() && dev->part > dev->num_dvd_parts) {
503 if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
506 Dmsg1(400, "lseek_dvd SEEK_END returns %s\n",
507 edit_uint64(pos + dev->part_start, ed1));
508 return pos + dev->part_start;
512 * Load the first part, then load the next until we reach the last one.
513 * This is the only way to be sure we compute the right file address.
515 * Save previous openmode, and open all but last part read-only
518 int modesave = dev->openmode;
519 if (!dvd_open_first_part(dcr, OPEN_READ_ONLY)) {
520 Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
523 if (dev->num_dvd_parts > 0) {
524 while (dev->part < dev->num_dvd_parts) {
525 if (dvd_open_next_part(dcr) < 0) {
526 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
530 dev->openmode = modesave;
531 if (dvd_open_next_part(dcr) < 0) {
532 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
536 return lseek_dvd(dcr, 0, SEEK_END);
540 Dmsg0(400, "Seek call error.\n");
546 bool dvd_close_job(DCR *dcr)
548 DEVICE *dev = dcr->dev;
553 * If the device is a dvd and WritePartAfterJob
554 * is set to yes, open the next part, so, in case of a device
555 * that requires mount, it will be written to the device.
557 if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
558 Dmsg1(400, "Writing last part=%d write_partafter_job is set.\n",
560 if (dev->part < dev->num_dvd_parts+1) {
561 Jmsg3(jcr, M_FATAL, 0, _("Error writing. Current part less than total number of parts (%d/%d, device=%s)\n"),
562 dev->part, dev->num_dvd_parts, dev->print_name());
563 dev->dev_errno = EIO;
567 if (ok && !dvd_write_part(dcr)) {
568 Jmsg2(jcr, M_FATAL, 0, _("Unable to write last on %s: ERR=%s\n"),
569 dev->print_name(), dev->bstrerror());
570 dev->dev_errno = EIO;
577 void dvd_remove_empty_part(DCR *dcr)
579 DEVICE *dev = dcr->dev;
581 /* Remove the last part file if it is empty */
582 if (dev->is_dvd() && dev->num_dvd_parts > 0) {
584 uint32_t part_save = dev->part;
585 POOL_MEM archive_name(PM_FNAME);
588 dev->part = dev->num_dvd_parts;
589 make_spooled_dvd_filename(dev, archive_name);
590 /* Check that the part file is empty */
591 status = stat(archive_name.c_str(), &statp);
592 if (status == 0 && statp.st_size == 0) {
593 Dmsg3(100, "Unlink empty part in close call make_dvd_filename. part=%d num=%d vol=%s\n",
594 part_save, dev->num_dvd_parts, dev->VolCatInfo.VolCatName);
595 Dmsg1(100, "unlink(%s)\n", archive_name.c_str());
596 unlink(archive_name.c_str());
597 if (part_save == dev->part) {
598 dev->set_part_spooled(false); /* no spooled part left */
600 } else if (status < 0) {
601 if (part_save == dev->part) {
602 dev->set_part_spooled(false); /* spool doesn't exit */
605 dev->part = part_save; /* restore part number */
609 bool truncate_dvd(DCR *dcr)
611 DEVICE* dev = dcr->dev;
613 dev->clear_freespace_ok(); /* need to update freespace */
614 dev->close_part(dcr);
616 if (!dev->unmount(1)) {
617 Dmsg0(400, "truncate_dvd: Failed to unmount DVD\n");
621 /* If necessary, delete its spool file. */
622 if (dev->is_part_spooled()) {
623 POOL_MEM archive_name(PM_FNAME);
624 /* Delete spool file */
625 make_spooled_dvd_filename(dev, archive_name);
626 unlink(archive_name.c_str());
627 dev->set_part_spooled(false);
630 /* Set num_dvd_parts to zero (on disk) */
632 dev->num_dvd_parts = 0;
633 dcr->VolCatInfo.VolCatParts = 0;
634 dev->VolCatInfo.VolCatParts = 0;
636 Dmsg0(400, "truncate_dvd: Opening first part (1)...\n");
638 dev->truncating = true;
639 /* This creates a zero length spool file and sets part=1 */
640 if (!dvd_open_first_part(dcr, CREATE_READ_WRITE)) {
641 Dmsg0(400, "truncate_dvd: Error while opening first part (1).\n");
642 dev->truncating = false;
646 dev->close_part(dcr);
648 Dmsg0(400, "truncate_dvd: Opening first part (2)...\n");
651 * Now actually truncate the DVD which is done by writing
652 * a zero length part to the DVD/
654 if (!dvd_write_part(dcr)) {
655 Dmsg0(400, "truncate_dvd: Error while writing to DVD.\n");
656 dev->truncating = false;
659 dev->truncating = false;
661 /* Set num_dvd_parts to zero (on disk) */
663 dev->num_dvd_parts = 0;
664 dcr->VolCatInfo.VolCatParts = 0;
665 dev->VolCatInfo.VolCatParts = 0;
666 /* Clear the size of the volume */
667 dev->VolCatInfo.VolCatBytes = 0;
668 dcr->VolCatInfo.VolCatBytes = 0;
671 if (!dir_update_volume_info(dcr, false)) {
679 * Checks if we can write on a non-blank DVD: meaning that it just have been
680 * truncated (there is only one zero-sized file on the DVD).
682 * Note! Normally if we can mount the device, which should be the case
683 * when we get here, it is not a blank DVD. Hence we check if
684 * if all files are of zero length (i.e. no data), in which case we allow it.
687 bool check_can_write_on_non_blank_dvd(DCR *dcr)
689 DEVICE* dev = dcr->dev;
691 struct dirent *entry, *result;
693 struct stat filestat;
696 name_max = pathconf(".", _PC_NAME_MAX);
697 if (name_max < 1024) {
701 if (!(dp = opendir(dev->device->mount_point))) {
703 dev->dev_errno = errno;
704 Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n",
705 dev->device->mount_point, dev->print_name(), be.strerror());
709 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
711 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
712 dev->dev_errno = EIO;
713 Dmsg2(129, "check_can_write_on_non_blank_dvd: no more files in dir %s (dev=%s)\n",
714 dev->device->mount_point, dev->print_name());
717 Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n",
718 result->d_name, dev->VolCatInfo.VolCatName);
719 if (strcmp(result->d_name, ".") && strcmp(result->d_name, "..") &&
720 strcmp(result->d_name, ".keep")) {
721 /* Found a file, checking it is empty */
722 POOL_MEM filename(PM_FNAME);
723 pm_strcpy(filename, dev->device->mount_point);
724 if (filename.c_str()[strlen(filename.c_str())-1] != '/') {
725 pm_strcat(filename, "/");
727 pm_strcat(filename, result->d_name);
728 if (stat(filename.c_str(), &filestat) < 0) {
730 dev->dev_errno = errno;
731 Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n",
732 filename.c_str(), be.strerror());
736 Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %lld\n",
737 filename.c_str(), filestat.st_size);
738 if (filestat.st_size != 0) {
748 Dmsg1(29, "OK can_write_on_non_blank_dvd: OK=%d\n", ok);
753 * Mount a DVD device, then scan to find out how many parts
756 int find_num_dvd_parts(DCR *dcr)
758 DEVICE *dev = dcr->dev;
761 if (!dev->is_dvd()) {
767 struct dirent *entry, *result;
769 int len = strlen(dcr->VolCatInfo.VolCatName);
771 /* Now count the number of parts */
772 name_max = pathconf(".", _PC_NAME_MAX);
773 if (name_max < 1024) {
777 if (!(dp = opendir(dev->device->mount_point))) {
779 dev->dev_errno = errno;
780 Dmsg3(29, "find_num_dvd_parts: failed to open dir %s (dev=%s), ERR=%s\n",
781 dev->device->mount_point, dev->print_name(), be.strerror());
785 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
787 Dmsg1(100, "Looking for Vol=%s\n", dcr->VolCatInfo.VolCatName);
791 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
792 dev->dev_errno = EIO;
793 Dmsg2(129, "find_num_dvd_parts: failed to find suitable file in dir %s (dev=%s)\n",
794 dev->device->mount_point, dev->print_name());
797 flen = strlen(result->d_name);
800 result->d_name[len] = 0;
801 if (strcmp(dcr->VolCatInfo.VolCatName, result->d_name) == 0) {
803 Dmsg1(100, "find_num_dvd_parts: found part: %s\n", result->d_name);
808 Dmsg2(129, "find_num_dvd_parts: ignoring %s in %s\n",
809 result->d_name, dev->device->mount_point);
814 Dmsg1(29, "find_num_dvd_parts = %d\n", num_parts);
818 dev->set_freespace_ok();
819 if (dev->is_mounted()) {