3 * dvd.c -- Routines specific to DVD devices (and
4 * possibly other removable hard media).
11 Bacula® - The Network Backup Solution
13 Copyright (C) 2005-2006 Free Software Foundation Europe e.V.
15 The main author of Bacula is Kern Sibbald, with contributions from
16 many others, a complete list can be found in the file AUTHORS.
17 This program is Free Software; you can redistribute it and/or
18 modify it under the terms of version two of the GNU General Public
19 License as published by the Free Software Foundation and included
22 This program is distributed in the hope that it will be useful, but
23 WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
25 General Public License for more details.
27 You should have received a copy of the GNU General Public License
28 along with this program; if not, write to the Free Software
29 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
32 Bacula® is a registered trademark of John Walker.
33 The licensor of Bacula is the Free Software Foundation Europe
34 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
35 Switzerland, email:ftf@fsfeurope.org.
41 /* Forward referenced functions */
42 static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name);
45 * Write the current volume/part filename to archive_name.
47 void make_mounted_dvd_filename(DEVICE *dev, POOL_MEM &archive_name)
49 pm_strcpy(archive_name, dev->device->mount_point);
50 add_file_and_part_name(dev, archive_name);
53 void make_spooled_dvd_filename(DEVICE *dev, POOL_MEM &archive_name)
55 /* Use the working directory if spool directory is not defined */
56 if (dev->device->spool_directory) {
57 pm_strcpy(archive_name, dev->device->spool_directory);
59 pm_strcpy(archive_name, working_directory);
61 add_file_and_part_name(dev, archive_name);
64 static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name)
68 if (!IsPathSeparator(archive_name.c_str()[strlen(archive_name.c_str())-1])) {
69 pm_strcat(archive_name, "/");
72 pm_strcat(archive_name, dev->VolCatInfo.VolCatName);
73 /* if part > 1, append .# to the filename (where # is the part number) */
75 pm_strcat(archive_name, ".");
76 bsnprintf(partnumber, sizeof(partnumber), "%d", dev->part);
77 pm_strcat(archive_name, partnumber);
79 Dmsg2(400, "Exit add_file_part_name: arch=%s, part=%d\n",
80 archive_name.c_str(), dev->part);
83 /* Update the free space on the device */
84 bool DEVICE::update_freespace()
86 POOL_MEM ocmd(PM_FNAME);
95 if (!is_dvd() || is_freespace_ok()) {
99 /* The device must be mounted in order to dvd-freespace to work */
102 sm_check(__FILE__, __LINE__, false);
103 icmd = device->free_space_command;
107 free_space_errno = 0;
108 clear_freespace_ok(); /* No valid freespace */
110 Dmsg2(29, "ERROR: update_free_space_dev: free_space=%s, free_space_errno=%d (!icmd)\n",
111 edit_uint64(free_space, ed1), free_space_errno);
112 Mmsg(errmsg, _("No FreeSpace command defined.\n"));
116 edit_mount_codes(ocmd, icmd);
118 Dmsg1(29, "update_freespace: cmd=%s\n", ocmd.c_str());
120 results = get_pool_memory(PM_MESSAGE);
122 /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */
127 Dmsg1(20, "Run freespace prog=%s\n", ocmd.c_str());
128 status = run_program_full_output(ocmd.c_str(), max_open_wait/2, results);
129 Dmsg2(500, "Freespace status=%d result=%s\n", status, results);
131 free = str_to_int64(results);
132 Dmsg1(400, "Free space program run: Freespace=%s\n", results);
135 free_space_errno = 0;
136 set_freespace_ok(); /* have valid freespace */
144 free_space_errno = EPIPE;
145 clear_freespace_ok(); /* no valid freespace */
146 Mmsg2(errmsg, _("Cannot run free space command. Results=%s ERR=%s\n"),
147 results, be.bstrerror(status));
150 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
151 "free_space_errno=%d ERR=%s\n", print_name(),
152 edit_uint64(free_space, ed1), free_space_errno,
158 dev_errno = free_space_errno;
159 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
160 "free_space_errno=%d ERR=%s\n",
161 print_name(), edit_uint64(free_space, ed1),
162 free_space_errno, errmsg);
166 free_pool_memory(results);
167 Dmsg4(29, "leave update_freespace: free_space=%s freespace_ok=%d free_space_errno=%d have_media=%d\n",
168 edit_uint64(free_space, ed1), !!is_freespace_ok(), free_space_errno, !!have_media());
169 sm_check(__FILE__, __LINE__, false);
174 * Note!!!! Part numbers now begin at 1. The part number is
175 * suppressed from the first part, which is just the Volume
176 * name. Each subsequent part is the Volumename.partnumber.
178 * Write a part (Vol, Vol.2, ...) from the spool to the DVD
179 * This routine does not update the part number, so normally, you
180 * should call open_next_part()
182 * It is also called from truncate_dvd to "blank" the medium, as
183 * well as from block.c when the DVD is full to write the last part.
185 bool dvd_write_part(DCR *dcr)
187 DEVICE *dev = dcr->dev;
188 POOL_MEM archive_name(PM_FNAME);
191 * Don't write empty part files.
192 * This is only useful when growisofs does not support write beyond
195 * - 3.9 GB on the volume, dvd-freespace reports 0.4 GB free
196 * - Write 0.2 GB on the volume, Bacula thinks it could still
197 * append data, it creates a new empty part.
198 * - dvd-freespace reports 0 GB free, as the 4GB boundary has
200 * - Bacula thinks he must finish to write to the device, so it
201 * tries to write the last part (0-byte), but dvd-writepart fails...
203 * There is one exception: when recycling a volume, we write a blank part
204 * file, so, then, we need to accept to write it.
206 if (dev->part_size == 0 && !dev->truncating) {
207 Dmsg2(29, "dvd_write_part: device is %s, won't write blank part %d\n", dev->print_name(), dev->part);
208 /* Delete spool file */
209 make_spooled_dvd_filename(dev, archive_name);
210 unlink(archive_name.c_str());
211 dev->set_part_spooled(false);
212 Dmsg1(29, "========= unlink(%s)\n", archive_name.c_str());
213 sm_check(__FILE__, __LINE__, false);
217 POOL_MEM ocmd(PM_FNAME);
218 POOL_MEM results(PM_MESSAGE);
224 dev->clear_freespace_ok(); /* need to update freespace */
226 sm_check(__FILE__, __LINE__, false);
227 Dmsg3(29, "dvd_write_part: device is %s, part is %d, is_mounted=%d\n", dev->print_name(), dev->part, dev->is_mounted());
228 icmd = dev->device->write_part_command;
230 dev->edit_mount_codes(ocmd, icmd);
233 * original line follows
234 * timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
235 * I modified this for a longer timeout; pre-formatting, blanking and
236 * writing can take quite a while
239 /* Explanation of the timeout value, when writing the first part,
241 * 9 GB, write speed 1x: 6990 seconds (almost 2 hours...)
242 * Overhead: 900 seconds (starting, initializing, finalizing,probably
243 * reloading 15 minutes)
245 * A reasonable last-exit timeout would be 16000 seconds. Quite long -
246 * almost 4.5 hours, but hopefully, that timeout will only ever be needed
247 * in case of a serious emergency.
250 if (dev->part == 1) {
253 timeout = dev->max_open_wait + (dev->part_size/(1350*1024/4));
256 Dmsg2(20, "Write part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
257 status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
258 Dmsg2(20, "Write part status=%d result=%s\n", status, results.c_str());
260 dev->blank_dvd = false;
262 Jmsg2(dcr->jcr, M_FATAL, 0, _("Error writing part %d to the DVD: ERR=%s\n"),
263 dev->part, results.c_str());
264 Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"),
266 Dmsg1(100, "%s\n", dev->errmsg);
267 dev->dev_errno = EIO;
268 if (!dev->truncating) {
269 mark_volume_in_error(dcr);
271 sm_check(__FILE__, __LINE__, false);
274 Jmsg(dcr->jcr, M_INFO, 0, _("Part %d (%lld bytes) written to DVD.\n"), dev->part, dev->part_size);
275 Dmsg3(400, "dvd_write_part: Part %d (%lld bytes) written to DVD\nResults: %s\n",
276 dev->part, dev->part_size, results.c_str());
278 dev->num_dvd_parts++; /* there is now one more part on DVD */
279 dev->VolCatInfo.VolCatParts = dev->num_dvd_parts;
280 dcr->VolCatInfo.VolCatParts = dev->num_dvd_parts;
281 Dmsg1(100, "Update num_parts=%d\n", dev->num_dvd_parts);
283 /* Delete spool file */
284 make_spooled_dvd_filename(dev, archive_name);
285 unlink(archive_name.c_str());
286 dev->set_part_spooled(false);
287 Dmsg1(29, "========= unlink(%s)\n", archive_name.c_str());
288 sm_check(__FILE__, __LINE__, false);
290 /* growisofs umounted the device, so remount it (it will update the free space) */
291 dev->clear_mounted();
293 Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"),
294 edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
295 sm_check(__FILE__, __LINE__, false);
300 * Open the next part file.
302 * - Increment part number
303 * - Reopen the device
305 int dvd_open_next_part(DCR *dcr)
307 DEVICE *dev = dcr->dev;
309 Dmsg6(29, "Enter: == open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n",
310 dev->part, dev->num_dvd_parts, dev->print_name(),
311 dev->VolCatInfo.VolCatName, dev->openmode, dev->file_addr);
312 if (!dev->is_dvd()) {
313 Dmsg1(100, "Device %s is not dvd!!!!\n", dev->print_name());
317 /* When appending, do not open a new part if the current is empty */
318 if (dev->can_append() && (dev->part > dev->num_dvd_parts) &&
319 (dev->part_size == 0)) {
320 Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
324 dev->close_part(dcr); /* close current part */
327 * If we have a spooled part open, write it to the
328 * DVD before opening the next part.
330 if (dev->is_part_spooled()) {
331 Dmsg2(100, "Before open next write previous. part=%d num_parts=%d\n",
332 dev->part, dev->num_dvd_parts);
333 if (!dvd_write_part(dcr)) {
334 Dmsg0(29, "Error in dvd_write part.\n");
339 dev->part_start += dev->part_size;
341 Dmsg2(29, "Inc part=%d num_dvd_parts=%d\n", dev->part, dev->num_dvd_parts);
343 /* Are we working on a part past what is written in the DVD? */
344 if (dev->num_dvd_parts < dev->part) {
345 POOL_MEM archive_name(PM_FNAME);
348 * First check what is on DVD. If our part is there, we
349 * are in trouble, so bail out.
350 * NB: This is however not a problem if we are writing the first part.
351 * It simply means that we are over writing an existing volume...
353 if (dev->num_dvd_parts > 0) {
354 make_mounted_dvd_filename(dev, archive_name); /* makes dvd name */
355 Dmsg1(100, "Check if part on DVD: %s\n", archive_name.c_str());
356 if (stat(archive_name.c_str(), &buf) == 0) {
357 /* bad news bail out */
358 dev->set_part_spooled(false);
359 Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
360 archive_name.c_str());
366 Dmsg2(400, "num_dvd_parts=%d part=%d\n", dev->num_dvd_parts, dev->part);
367 make_spooled_dvd_filename(dev, archive_name); /* makes spool name */
369 /* Check if the next part exists in spool directory . */
370 Dmsg1(100, "Check if part on spool: %s\n", archive_name.c_str());
371 if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
372 Dmsg1(29, "======= Part %s is in the way, deleting it...\n", archive_name.c_str());
373 /* Then try to unlink it */
374 if (unlink(archive_name.c_str()) < 0) {
376 dev->set_part_spooled(false);
377 dev->dev_errno = errno;
378 Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"),
379 archive_name.c_str(), be.bstrerror());
386 Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName,
389 /* Open next part. Note, this sets part_size for part opened. */
390 if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
393 dev->set_labeled(); /* all next parts are "labeled" */
399 * Open the first part file.
401 * - Reopen the device
403 static bool dvd_open_first_part(DCR *dcr, int mode)
405 DEVICE *dev = dcr->dev;
407 Dmsg5(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_dvd_parts=%d append=%d\n", dev->print_name(),
408 dev->VolCatInfo.VolCatName, dev->openmode, dev->num_dvd_parts, dev->can_append());
411 dev->close_part(dcr);
413 Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName,
415 Dmsg0(100, "Set part=1\n");
419 if (dev->open(dcr, mode) < 0) {
420 Dmsg0(400, "open dev() failed\n");
423 Dmsg2(400, "Leave open_first_part state=%s append=%d\n", dev->is_open()?"open":"not open", dev->can_append());
430 * Do an lseek on a DVD handling all the different parts
432 boffset_t lseek_dvd(DCR *dcr, boffset_t offset, int whence)
434 DEVICE *dev = dcr->dev;
436 char ed1[50], ed2[50];
438 Dmsg5(400, "Enter lseek_dvd fd=%d off=%s w=%d part=%d nparts=%d\n", dev->fd(),
439 edit_int64(offset, ed1), whence, dev->part, dev->num_dvd_parts);
443 Dmsg2(400, "lseek_dvd SEEK_SET to %s (part_start=%s)\n",
444 edit_int64(offset, ed1), edit_uint64(dev->part_start, ed2));
445 if ((uint64_t)offset >= dev->part_start) {
446 if ((uint64_t)offset == dev->part_start ||
447 (uint64_t)offset < dev->part_start+dev->part_size) {
448 /* We are staying in the current part, just seek */
449 #if defined(HAVE_WIN32)
450 pos = _lseeki64(dev->fd(), offset-dev->part_start, SEEK_SET);
452 pos = lseek(dev->fd(), offset-dev->part_start, SEEK_SET);
457 return pos + dev->part_start;
460 /* Load next part, and start again */
461 Dmsg0(100, "lseek open next part\n");
462 if (dvd_open_next_part(dcr) < 0) {
463 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
466 Dmsg2(100, "Recurse lseek after open next part=%d num_part=%d\n",
467 dev->part, dev->num_dvd_parts);
468 return lseek_dvd(dcr, offset, SEEK_SET);
472 * pos < dev->part_start :
473 * We need to access a previous part,
474 * so just load the first one, and seek again
475 * until the right one is loaded
477 Dmsg0(100, "lseek open first part\n");
478 if (!dvd_open_first_part(dcr, dev->openmode)) {
479 Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
482 Dmsg2(100, "Recurse lseek after open first part=%d num_part=%d\n",
483 dev->part, dev->num_dvd_parts);
484 return lseek_dvd(dcr, offset, SEEK_SET); /* system lseek */
488 Dmsg1(400, "lseek_dvd SEEK_CUR to %s\n", edit_int64(offset, ed1));
489 if ((pos = lseek(dev->fd(), (off_t)0, SEEK_CUR)) < 0) {
490 Dmsg0(400, "Seek error.\n");
493 pos += dev->part_start;
495 Dmsg1(400, "lseek_dvd SEEK_CUR returns %s\n", edit_uint64(pos, ed1));
498 Dmsg1(400, "do lseek_dvd SEEK_SET %s\n", edit_uint64(pos, ed1));
499 return lseek_dvd(dcr, pos, SEEK_SET);
503 Dmsg1(400, "lseek_dvd SEEK_END to %s\n", edit_int64(offset, ed1));
505 * Bacula does not use offsets for SEEK_END
506 * Also, Bacula uses seek_end only when it wants to
507 * append to the volume, so for a dvd that means
508 * that the volume must be spooled since the DVD
509 * itself is read-only (as currently implemented).
511 if (offset > 0) { /* Not used by bacula */
512 Dmsg1(400, "lseek_dvd SEEK_END called with an invalid offset %s\n",
513 edit_uint64(offset, ed1));
517 /* If we are already on a spooled part and have the
518 * right part number, simply seek
520 if (dev->is_part_spooled() && dev->part > dev->num_dvd_parts) {
521 if ((pos = lseek(dev->fd(), (off_t)0, SEEK_END)) < 0) {
524 Dmsg1(400, "lseek_dvd SEEK_END returns %s\n",
525 edit_uint64(pos + dev->part_start, ed1));
526 return pos + dev->part_start;
530 * Load the first part, then load the next until we reach the last one.
531 * This is the only way to be sure we compute the right file address.
533 * Save previous openmode, and open all but last part read-only
536 int modesave = dev->openmode;
537 if (!dvd_open_first_part(dcr, OPEN_READ_ONLY)) {
538 Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
541 if (dev->num_dvd_parts > 0) {
542 while (dev->part < dev->num_dvd_parts) {
543 if (dvd_open_next_part(dcr) < 0) {
544 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
548 dev->openmode = modesave;
549 if (dvd_open_next_part(dcr) < 0) {
550 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
554 return lseek_dvd(dcr, 0, SEEK_END);
558 Dmsg0(400, "Seek call error.\n");
564 bool dvd_close_job(DCR *dcr)
566 DEVICE *dev = dcr->dev;
571 * If the device is a dvd and WritePartAfterJob
572 * is set to yes, open the next part, so, in case of a device
573 * that requires mount, it will be written to the device.
575 if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
576 Dmsg1(400, "Writing last part=%d write_partafter_job is set.\n",
578 if (dev->part < dev->num_dvd_parts+1) {
579 Jmsg3(jcr, M_FATAL, 0, _("Error writing. Current part less than total number of parts (%d/%d, device=%s)\n"),
580 dev->part, dev->num_dvd_parts, dev->print_name());
581 dev->dev_errno = EIO;
585 if (ok && !dvd_write_part(dcr)) {
586 Jmsg2(jcr, M_FATAL, 0, _("Unable to write last on %s: ERR=%s\n"),
587 dev->print_name(), dev->bstrerror());
588 dev->dev_errno = EIO;
595 void dvd_remove_empty_part(DCR *dcr)
597 DEVICE *dev = dcr->dev;
599 /* Remove the last part file if it is empty */
600 if (dev->is_dvd() && dev->num_dvd_parts > 0) {
602 uint32_t part_save = dev->part;
603 POOL_MEM archive_name(PM_FNAME);
606 dev->part = dev->num_dvd_parts;
607 make_spooled_dvd_filename(dev, archive_name);
608 /* Check that the part file is empty */
609 status = stat(archive_name.c_str(), &statp);
610 if (status == 0 && statp.st_size == 0) {
611 Dmsg3(100, "Unlink empty part in close call make_dvd_filename. part=%d num=%d vol=%s\n",
612 part_save, dev->num_dvd_parts, dev->VolCatInfo.VolCatName);
613 Dmsg1(100, "unlink(%s)\n", archive_name.c_str());
614 unlink(archive_name.c_str());
615 if (part_save == dev->part) {
616 dev->set_part_spooled(false); /* no spooled part left */
618 } else if (status < 0) {
619 if (part_save == dev->part) {
620 dev->set_part_spooled(false); /* spool doesn't exit */
623 dev->part = part_save; /* restore part number */
627 bool truncate_dvd(DCR *dcr)
629 DEVICE* dev = dcr->dev;
631 dev->clear_freespace_ok(); /* need to update freespace */
632 dev->close_part(dcr);
634 if (!dev->unmount(1)) {
635 Dmsg0(400, "truncate_dvd: Failed to unmount DVD\n");
639 /* If necessary, delete its spool file. */
640 if (dev->is_part_spooled()) {
641 POOL_MEM archive_name(PM_FNAME);
642 /* Delete spool file */
643 make_spooled_dvd_filename(dev, archive_name);
644 unlink(archive_name.c_str());
645 dev->set_part_spooled(false);
648 /* Set num_dvd_parts to zero (on disk) */
650 dev->num_dvd_parts = 0;
651 dcr->VolCatInfo.VolCatParts = 0;
652 dev->VolCatInfo.VolCatParts = 0;
654 Dmsg0(400, "truncate_dvd: Opening first part (1)...\n");
656 dev->truncating = true;
657 /* This creates a zero length spool file and sets part=1 */
658 if (!dvd_open_first_part(dcr, CREATE_READ_WRITE)) {
659 Dmsg0(400, "truncate_dvd: Error while opening first part (1).\n");
660 dev->truncating = false;
664 dev->close_part(dcr);
666 Dmsg0(400, "truncate_dvd: Opening first part (2)...\n");
669 * Now actually truncate the DVD which is done by writing
670 * a zero length part to the DVD/
672 if (!dvd_write_part(dcr)) {
673 Dmsg0(400, "truncate_dvd: Error while writing to DVD.\n");
674 dev->truncating = false;
677 dev->truncating = false;
679 /* Set num_dvd_parts to zero (on disk) */
681 dev->num_dvd_parts = 0;
682 dcr->VolCatInfo.VolCatParts = 0;
683 dev->VolCatInfo.VolCatParts = 0;
684 /* Clear the size of the volume */
685 dev->VolCatInfo.VolCatBytes = 0;
686 dcr->VolCatInfo.VolCatBytes = 0;
689 if (!dir_update_volume_info(dcr, false)) {
697 * Checks if we can write on a non-blank DVD: meaning that it just have been
698 * truncated (there is only one zero-sized file on the DVD).
700 * Note! Normally if we can mount the device, which should be the case
701 * when we get here, it is not a blank DVD. Hence we check if
702 * if all files are of zero length (i.e. no data), in which case we allow it.
705 bool check_can_write_on_non_blank_dvd(DCR *dcr)
707 DEVICE* dev = dcr->dev;
709 struct dirent *entry, *result;
711 struct stat filestat;
714 name_max = pathconf(".", _PC_NAME_MAX);
715 if (name_max < 1024) {
719 if (!(dp = opendir(dev->device->mount_point))) {
721 dev->dev_errno = errno;
722 Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n",
723 dev->device->mount_point, dev->print_name(), be.bstrerror());
727 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
729 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
730 dev->dev_errno = EIO;
731 Dmsg2(129, "check_can_write_on_non_blank_dvd: no more files in dir %s (dev=%s)\n",
732 dev->device->mount_point, dev->print_name());
735 Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n",
736 result->d_name, dev->VolCatInfo.VolCatName);
737 if (strcmp(result->d_name, ".") && strcmp(result->d_name, "..") &&
738 strcmp(result->d_name, ".keep")) {
739 /* Found a file, checking it is empty */
740 POOL_MEM filename(PM_FNAME);
741 pm_strcpy(filename, dev->device->mount_point);
742 if (!IsPathSeparator(filename.c_str()[strlen(filename.c_str())-1])) {
743 pm_strcat(filename, "/");
745 pm_strcat(filename, result->d_name);
746 if (stat(filename.c_str(), &filestat) < 0) {
748 dev->dev_errno = errno;
749 Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n",
750 filename.c_str(), be.bstrerror());
754 Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %lld\n",
755 filename.c_str(), filestat.st_size);
756 if (filestat.st_size != 0) {
766 Dmsg1(29, "OK can_write_on_non_blank_dvd: OK=%d\n", ok);
771 * Mount a DVD device, then scan to find out how many parts
774 int find_num_dvd_parts(DCR *dcr)
776 DEVICE *dev = dcr->dev;
779 if (!dev->is_dvd()) {
785 struct dirent *entry, *result;
787 int len = strlen(dcr->VolCatInfo.VolCatName);
789 /* Now count the number of parts */
790 name_max = pathconf(".", _PC_NAME_MAX);
791 if (name_max < 1024) {
795 if (!(dp = opendir(dev->device->mount_point))) {
797 dev->dev_errno = errno;
798 Dmsg3(29, "find_num_dvd_parts: failed to open dir %s (dev=%s), ERR=%s\n",
799 dev->device->mount_point, dev->print_name(), be.bstrerror());
803 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
805 Dmsg1(100, "Looking for Vol=%s\n", dcr->VolCatInfo.VolCatName);
809 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
810 dev->dev_errno = EIO;
811 Dmsg2(129, "find_num_dvd_parts: failed to find suitable file in dir %s (dev=%s)\n",
812 dev->device->mount_point, dev->print_name());
815 flen = strlen(result->d_name);
818 result->d_name[len] = 0;
819 if (strcmp(dcr->VolCatInfo.VolCatName, result->d_name) == 0) {
821 Dmsg1(100, "find_num_dvd_parts: found part: %s\n", result->d_name);
826 Dmsg2(129, "find_num_dvd_parts: ignoring %s in %s\n",
827 result->d_name, dev->device->mount_point);
832 Dmsg1(29, "find_num_dvd_parts = %d\n", num_parts);
836 dev->set_freespace_ok();
837 if (dev->is_mounted()) {