2 Bacula® - The Network Backup Solution
4 Copyright (C) 2005-2010 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 */
101 sm_check(__FILE__, __LINE__, false);
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());
168 sm_check(__FILE__, __LINE__, false);
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());
212 sm_check(__FILE__, __LINE__, false);
216 POOL_MEM ocmd(PM_FNAME);
217 POOL_MEM results(PM_MESSAGE);
223 dev->clear_freespace_ok(); /* need to update freespace */
225 sm_check(__FILE__, __LINE__, false);
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();
270 sm_check(__FILE__, __LINE__, false);
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());
287 sm_check(__FILE__, __LINE__, false);
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());
294 sm_check(__FILE__, __LINE__, false);
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, "num_dvd_parts=%d part=%d\n", dev->num_dvd_parts, dev->part);
366 make_spooled_dvd_filename(dev, archive_name); /* makes spool name */
368 /* Check if the next part exists in spool directory . */
369 Dmsg1(100, "Check if part on spool: %s\n", archive_name.c_str());
370 if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
371 Dmsg1(29, "======= Part %s is in the way, deleting it...\n", archive_name.c_str());
372 /* Then try to unlink it */
373 if (unlink(archive_name.c_str()) < 0) {
375 dev->set_part_spooled(false);
376 dev->dev_errno = errno;
377 Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"),
378 archive_name.c_str(), be.bstrerror());
385 Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->getVolCatName(),
388 /* Open next part. Note, this sets part_size for part opened. */
389 if (dev->open(dcr, OPEN_READ_ONLY) < 0) {
392 dev->set_labeled(); /* all next parts are "labeled" */
398 * Open the first part file.
400 * - Reopen the device
402 static bool dvd_open_first_part(DCR *dcr, int mode)
404 DEVICE *dev = dcr->dev;
406 Dmsg5(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_dvd_parts=%d append=%d\n", dev->print_name(),
407 dev->getVolCatName(), dev->openmode, dev->num_dvd_parts, dev->can_append());
410 dev->close_part(dcr);
412 Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->getVolCatName(),
414 Dmsg0(100, "Set part=1\n");
418 if (dev->open(dcr, mode) < 0) {
419 Dmsg0(400, "open dev() failed\n");
422 Dmsg2(400, "Leave open_first_part state=%s append=%d\n", dev->is_open()?"open":"not open", dev->can_append());
429 * Do an lseek on a DVD handling all the different parts
431 boffset_t lseek_dvd(DCR *dcr, boffset_t offset, int whence)
435 char ed1[50], ed2[50];
437 if (!dcr) { /* can be NULL when called from rewind(NULL) */
442 Dmsg5(400, "Enter lseek_dvd fd=%d off=%s w=%d part=%d nparts=%d\n", dev->fd(),
443 edit_int64(offset, ed1), whence, dev->part, dev->num_dvd_parts);
447 Dmsg2(400, "lseek_dvd SEEK_SET to %s (part_start=%s)\n",
448 edit_int64(offset, ed1), edit_uint64(dev->part_start, ed2));
449 if ((uint64_t)offset >= dev->part_start) {
450 if ((uint64_t)offset == dev->part_start ||
451 (uint64_t)offset < dev->part_start+dev->part_size) {
452 /* We are staying in the current part, just seek */
453 #if defined(HAVE_WIN32)
454 pos = _lseeki64(dev->fd(), offset-dev->part_start, SEEK_SET);
456 pos = lseek(dev->fd(), offset-dev->part_start, SEEK_SET);
461 return pos + dev->part_start;
464 /* Load next part, and start again */
465 Dmsg0(100, "lseek open next part\n");
466 if (dvd_open_next_part(dcr) < 0) {
467 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
470 Dmsg2(100, "Recurse lseek after open next part=%d num_part=%d\n",
471 dev->part, dev->num_dvd_parts);
472 return lseek_dvd(dcr, offset, SEEK_SET);
476 * pos < dev->part_start :
477 * We need to access a previous part,
478 * so just load the first one, and seek again
479 * until the right one is loaded
481 Dmsg0(100, "lseek open first part\n");
482 if (!dvd_open_first_part(dcr, dev->openmode)) {
483 Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
486 Dmsg2(100, "Recurse lseek after open first part=%d num_part=%d\n",
487 dev->part, dev->num_dvd_parts);
488 return lseek_dvd(dcr, offset, SEEK_SET); /* system lseek */
492 Dmsg1(400, "lseek_dvd SEEK_CUR to %s\n", edit_int64(offset, ed1));
493 if ((pos = lseek(dev->fd(), 0, SEEK_CUR)) < 0) {
494 Dmsg0(400, "Seek error.\n");
497 pos += dev->part_start;
499 Dmsg1(400, "lseek_dvd SEEK_CUR returns %s\n", edit_uint64(pos, ed1));
502 Dmsg1(400, "do lseek_dvd SEEK_SET %s\n", edit_uint64(pos, ed1));
503 return lseek_dvd(dcr, pos, SEEK_SET);
507 Dmsg1(400, "lseek_dvd SEEK_END to %s\n", edit_int64(offset, ed1));
509 * Bacula does not use offsets for SEEK_END
510 * Also, Bacula uses seek_end only when it wants to
511 * append to the volume, so for a dvd that means
512 * that the volume must be spooled since the DVD
513 * itself is read-only (as currently implemented).
515 if (offset > 0) { /* Not used by bacula */
516 Dmsg1(400, "lseek_dvd SEEK_END called with an invalid offset %s\n",
517 edit_uint64(offset, ed1));
521 /* If we are already on a spooled part and have the
522 * right part number, simply seek
524 if (dev->is_part_spooled() && dev->part > dev->num_dvd_parts) {
525 if ((pos = lseek(dev->fd(), 0, SEEK_END)) < 0) {
528 Dmsg1(400, "lseek_dvd SEEK_END returns %s\n",
529 edit_uint64(pos + dev->part_start, ed1));
530 return pos + dev->part_start;
534 * Load the first part, then load the next until we reach the last one.
535 * This is the only way to be sure we compute the right file address.
537 * Save previous openmode, and open all but last part read-only
540 int modesave = dev->openmode;
541 if (!dvd_open_first_part(dcr, OPEN_READ_ONLY)) {
542 Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
545 if (dev->num_dvd_parts > 0) {
546 while (dev->part < dev->num_dvd_parts) {
547 if (dvd_open_next_part(dcr) < 0) {
548 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
552 dev->openmode = modesave;
553 if (dvd_open_next_part(dcr) < 0) {
554 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
558 return lseek_dvd(dcr, 0, SEEK_END);
562 Dmsg0(400, "Seek call error.\n");
568 bool dvd_close_job(DCR *dcr)
570 DEVICE *dev = dcr->dev;
575 * If the device is a dvd and WritePartAfterJob
576 * is set to yes, open the next part, so, in case of a device
577 * that requires mount, it will be written to the device.
579 if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
580 Dmsg1(400, "Writing last part=%d write_partafter_job is set.\n",
582 if (dev->part < dev->num_dvd_parts+1) {
583 Jmsg3(jcr, M_FATAL, 0, _("Error writing. Current part less than total number of parts (%d/%d, device=%s)\n"),
584 dev->part, dev->num_dvd_parts, dev->print_name());
585 dev->dev_errno = EIO;
589 if (ok && !dvd_write_part(dcr)) {
590 Jmsg2(jcr, M_FATAL, 0, _("Unable to write last on %s: ERR=%s\n"),
591 dev->print_name(), dev->bstrerror());
592 dev->dev_errno = EIO;
599 void dvd_remove_empty_part(DCR *dcr)
601 DEVICE *dev = dcr->dev;
603 /* Remove the last part file if it is empty */
604 if (dev->is_dvd() && dev->num_dvd_parts > 0) {
606 uint32_t part_save = dev->part;
607 POOL_MEM archive_name(PM_FNAME);
610 dev->part = dev->num_dvd_parts;
611 make_spooled_dvd_filename(dev, archive_name);
612 /* Check that the part file is empty */
613 status = stat(archive_name.c_str(), &statp);
614 if (status == 0 && statp.st_size == 0) {
615 Dmsg3(100, "Unlink empty part in close call make_dvd_filename. part=%d num=%d vol=%s\n",
616 part_save, dev->num_dvd_parts, dev->getVolCatName());
617 Dmsg1(100, "unlink(%s)\n", archive_name.c_str());
618 unlink(archive_name.c_str());
619 if (part_save == dev->part) {
620 dev->set_part_spooled(false); /* no spooled part left */
622 } else if (status < 0) {
623 if (part_save == dev->part) {
624 dev->set_part_spooled(false); /* spool doesn't exit */
627 dev->part = part_save; /* restore part number */
631 bool truncate_dvd(DCR *dcr)
633 DEVICE* dev = dcr->dev;
635 dev->clear_freespace_ok(); /* need to update freespace */
636 dev->close_part(dcr);
638 if (!dev->unmount(1)) {
639 Dmsg0(400, "truncate_dvd: Failed to unmount DVD\n");
643 /* If necessary, delete its spool file. */
644 if (dev->is_part_spooled()) {
645 POOL_MEM archive_name(PM_FNAME);
646 /* Delete spool file */
647 make_spooled_dvd_filename(dev, archive_name);
648 unlink(archive_name.c_str());
649 dev->set_part_spooled(false);
652 /* Set num_dvd_parts to zero (on disk) */
654 dev->num_dvd_parts = 0;
655 dcr->VolCatInfo.VolCatParts = 0;
656 dev->VolCatInfo.VolCatParts = 0;
658 Dmsg0(400, "truncate_dvd: Opening first part (1)...\n");
660 dev->truncating = true;
661 /* This creates a zero length spool file and sets part=1 */
662 if (!dvd_open_first_part(dcr, CREATE_READ_WRITE)) {
663 Dmsg0(400, "truncate_dvd: Error while opening first part (1).\n");
664 dev->truncating = false;
668 dev->close_part(dcr);
670 Dmsg0(400, "truncate_dvd: Opening first part (2)...\n");
673 * Now actually truncate the DVD which is done by writing
674 * a zero length part to the DVD/
676 if (!dvd_write_part(dcr)) {
677 Dmsg0(400, "truncate_dvd: Error while writing to DVD.\n");
678 dev->truncating = false;
681 dev->truncating = false;
683 /* Set num_dvd_parts to zero (on disk) */
685 dev->num_dvd_parts = 0;
686 dcr->VolCatInfo.VolCatParts = 0;
687 dev->VolCatInfo.VolCatParts = 0;
688 /* Clear the size of the volume */
689 dev->VolCatInfo.VolCatBytes = 0;
690 dcr->VolCatInfo.VolCatBytes = 0;
693 if (!dir_update_volume_info(dcr, false, true)) {
701 * Checks if we can write on a non-blank DVD: meaning that it just have been
702 * truncated (there is only one zero-sized file on the DVD).
704 * Note! Normally if we can mount the device, which should be the case
705 * when we get here, it is not a blank DVD. Hence we check if
706 * if all files are of zero length (i.e. no data), in which case we allow it.
709 bool check_can_write_on_non_blank_dvd(DCR *dcr)
711 DEVICE* dev = dcr->dev;
713 struct dirent *entry, *result;
715 struct stat filestat;
718 name_max = pathconf(".", _PC_NAME_MAX);
719 if (name_max < 1024) {
723 if (!(dp = opendir(dev->device->mount_point))) {
725 dev->dev_errno = errno;
726 Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n",
727 dev->device->mount_point, dev->print_name(), be.bstrerror());
731 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
733 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
734 dev->dev_errno = EIO;
735 Dmsg2(129, "check_can_write_on_non_blank_dvd: no more files in dir %s (dev=%s)\n",
736 dev->device->mount_point, dev->print_name());
739 Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n",
740 result->d_name, dev->getVolCatName());
741 if (strcmp(result->d_name, ".") && strcmp(result->d_name, "..") &&
742 strcmp(result->d_name, ".keep")) {
743 /* Found a file, checking it is empty */
744 POOL_MEM filename(PM_FNAME);
745 pm_strcpy(filename, dev->device->mount_point);
746 if (!IsPathSeparator(filename.c_str()[strlen(filename.c_str())-1])) {
747 pm_strcat(filename, "/");
749 pm_strcat(filename, result->d_name);
750 if (stat(filename.c_str(), &filestat) < 0) {
752 dev->dev_errno = errno;
753 Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n",
754 filename.c_str(), be.bstrerror());
758 Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %lld\n",
759 filename.c_str(), filestat.st_size);
760 if (filestat.st_size != 0) {
770 Dmsg1(29, "OK can_write_on_non_blank_dvd: OK=%d\n", ok);
775 * Mount a DVD device, then scan to find out how many parts
778 int find_num_dvd_parts(DCR *dcr)
780 DEVICE *dev = dcr->dev;
783 if (!dev->is_dvd()) {
789 struct dirent *entry, *result;
791 int len = strlen(dcr->getVolCatName());
793 /* Now count the number of parts */
794 name_max = pathconf(".", _PC_NAME_MAX);
795 if (name_max < 1024) {
799 if (!(dp = opendir(dev->device->mount_point))) {
801 dev->dev_errno = errno;
802 Dmsg3(29, "find_num_dvd_parts: failed to open dir %s (dev=%s), ERR=%s\n",
803 dev->device->mount_point, dev->print_name(), be.bstrerror());
807 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
809 Dmsg1(100, "Looking for Vol=%s\n", dcr->getVolCatName());
813 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
814 dev->dev_errno = EIO;
815 Dmsg2(129, "find_num_dvd_parts: failed to find suitable file in dir %s (dev=%s)\n",
816 dev->device->mount_point, dev->print_name());
819 flen = strlen(result->d_name);
822 result->d_name[len] = 0;
823 if (strcmp(dcr->getVolCatName(), result->d_name) == 0) {
825 Dmsg1(100, "find_num_dvd_parts: found part: %s\n", result->d_name);
830 Dmsg2(129, "find_num_dvd_parts: ignoring %s in %s\n",
831 result->d_name, dev->device->mount_point);
836 Dmsg1(29, "find_num_dvd_parts = %d\n", num_parts);
840 dev->set_freespace_ok();
841 if (dev->is_mounted()) {