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 two of the GNU 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 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)
433 DEVICE *dev = dcr->dev;
435 char ed1[50], ed2[50];
437 Dmsg5(400, "Enter lseek_dvd fd=%d off=%s w=%d part=%d nparts=%d\n", dev->fd(),
438 edit_int64(offset, ed1), whence, dev->part, dev->num_dvd_parts);
442 Dmsg2(400, "lseek_dvd SEEK_SET to %s (part_start=%s)\n",
443 edit_int64(offset, ed1), edit_uint64(dev->part_start, ed2));
444 if ((uint64_t)offset >= dev->part_start) {
445 if ((uint64_t)offset == dev->part_start ||
446 (uint64_t)offset < dev->part_start+dev->part_size) {
447 /* We are staying in the current part, just seek */
448 #if defined(HAVE_WIN32)
449 pos = _lseeki64(dev->fd(), offset-dev->part_start, SEEK_SET);
451 pos = lseek(dev->fd(), offset-dev->part_start, SEEK_SET);
456 return pos + dev->part_start;
459 /* Load next part, and start again */
460 Dmsg0(100, "lseek open next part\n");
461 if (dvd_open_next_part(dcr) < 0) {
462 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
465 Dmsg2(100, "Recurse lseek after open next part=%d num_part=%d\n",
466 dev->part, dev->num_dvd_parts);
467 return lseek_dvd(dcr, offset, SEEK_SET);
471 * pos < dev->part_start :
472 * We need to access a previous part,
473 * so just load the first one, and seek again
474 * until the right one is loaded
476 Dmsg0(100, "lseek open first part\n");
477 if (!dvd_open_first_part(dcr, dev->openmode)) {
478 Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
481 Dmsg2(100, "Recurse lseek after open first part=%d num_part=%d\n",
482 dev->part, dev->num_dvd_parts);
483 return lseek_dvd(dcr, offset, SEEK_SET); /* system lseek */
487 Dmsg1(400, "lseek_dvd SEEK_CUR to %s\n", edit_int64(offset, ed1));
488 if ((pos = lseek(dev->fd(), 0, SEEK_CUR)) < 0) {
489 Dmsg0(400, "Seek error.\n");
492 pos += dev->part_start;
494 Dmsg1(400, "lseek_dvd SEEK_CUR returns %s\n", edit_uint64(pos, ed1));
497 Dmsg1(400, "do lseek_dvd SEEK_SET %s\n", edit_uint64(pos, ed1));
498 return lseek_dvd(dcr, pos, SEEK_SET);
502 Dmsg1(400, "lseek_dvd SEEK_END to %s\n", edit_int64(offset, ed1));
504 * Bacula does not use offsets for SEEK_END
505 * Also, Bacula uses seek_end only when it wants to
506 * append to the volume, so for a dvd that means
507 * that the volume must be spooled since the DVD
508 * itself is read-only (as currently implemented).
510 if (offset > 0) { /* Not used by bacula */
511 Dmsg1(400, "lseek_dvd SEEK_END called with an invalid offset %s\n",
512 edit_uint64(offset, ed1));
516 /* If we are already on a spooled part and have the
517 * right part number, simply seek
519 if (dev->is_part_spooled() && dev->part > dev->num_dvd_parts) {
520 if ((pos = lseek(dev->fd(), 0, SEEK_END)) < 0) {
523 Dmsg1(400, "lseek_dvd SEEK_END returns %s\n",
524 edit_uint64(pos + dev->part_start, ed1));
525 return pos + dev->part_start;
529 * Load the first part, then load the next until we reach the last one.
530 * This is the only way to be sure we compute the right file address.
532 * Save previous openmode, and open all but last part read-only
535 int modesave = dev->openmode;
536 if (!dvd_open_first_part(dcr, OPEN_READ_ONLY)) {
537 Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
540 if (dev->num_dvd_parts > 0) {
541 while (dev->part < dev->num_dvd_parts) {
542 if (dvd_open_next_part(dcr) < 0) {
543 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
547 dev->openmode = modesave;
548 if (dvd_open_next_part(dcr) < 0) {
549 Dmsg0(400, "lseek_dvd failed while trying to open the next part\n");
553 return lseek_dvd(dcr, 0, SEEK_END);
557 Dmsg0(400, "Seek call error.\n");
563 bool dvd_close_job(DCR *dcr)
565 DEVICE *dev = dcr->dev;
570 * If the device is a dvd and WritePartAfterJob
571 * is set to yes, open the next part, so, in case of a device
572 * that requires mount, it will be written to the device.
574 if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
575 Dmsg1(400, "Writing last part=%d write_partafter_job is set.\n",
577 if (dev->part < dev->num_dvd_parts+1) {
578 Jmsg3(jcr, M_FATAL, 0, _("Error writing. Current part less than total number of parts (%d/%d, device=%s)\n"),
579 dev->part, dev->num_dvd_parts, dev->print_name());
580 dev->dev_errno = EIO;
584 if (ok && !dvd_write_part(dcr)) {
585 Jmsg2(jcr, M_FATAL, 0, _("Unable to write last on %s: ERR=%s\n"),
586 dev->print_name(), dev->bstrerror());
587 dev->dev_errno = EIO;
594 void dvd_remove_empty_part(DCR *dcr)
596 DEVICE *dev = dcr->dev;
598 /* Remove the last part file if it is empty */
599 if (dev->is_dvd() && dev->num_dvd_parts > 0) {
601 uint32_t part_save = dev->part;
602 POOL_MEM archive_name(PM_FNAME);
605 dev->part = dev->num_dvd_parts;
606 make_spooled_dvd_filename(dev, archive_name);
607 /* Check that the part file is empty */
608 status = stat(archive_name.c_str(), &statp);
609 if (status == 0 && statp.st_size == 0) {
610 Dmsg3(100, "Unlink empty part in close call make_dvd_filename. part=%d num=%d vol=%s\n",
611 part_save, dev->num_dvd_parts, dev->getVolCatName());
612 Dmsg1(100, "unlink(%s)\n", archive_name.c_str());
613 unlink(archive_name.c_str());
614 if (part_save == dev->part) {
615 dev->set_part_spooled(false); /* no spooled part left */
617 } else if (status < 0) {
618 if (part_save == dev->part) {
619 dev->set_part_spooled(false); /* spool doesn't exit */
622 dev->part = part_save; /* restore part number */
626 bool truncate_dvd(DCR *dcr)
628 DEVICE* dev = dcr->dev;
630 dev->clear_freespace_ok(); /* need to update freespace */
631 dev->close_part(dcr);
633 if (!dev->unmount(1)) {
634 Dmsg0(400, "truncate_dvd: Failed to unmount DVD\n");
638 /* If necessary, delete its spool file. */
639 if (dev->is_part_spooled()) {
640 POOL_MEM archive_name(PM_FNAME);
641 /* Delete spool file */
642 make_spooled_dvd_filename(dev, archive_name);
643 unlink(archive_name.c_str());
644 dev->set_part_spooled(false);
647 /* Set num_dvd_parts to zero (on disk) */
649 dev->num_dvd_parts = 0;
650 dcr->VolCatInfo.VolCatParts = 0;
651 dev->VolCatInfo.VolCatParts = 0;
653 Dmsg0(400, "truncate_dvd: Opening first part (1)...\n");
655 dev->truncating = true;
656 /* This creates a zero length spool file and sets part=1 */
657 if (!dvd_open_first_part(dcr, CREATE_READ_WRITE)) {
658 Dmsg0(400, "truncate_dvd: Error while opening first part (1).\n");
659 dev->truncating = false;
663 dev->close_part(dcr);
665 Dmsg0(400, "truncate_dvd: Opening first part (2)...\n");
668 * Now actually truncate the DVD which is done by writing
669 * a zero length part to the DVD/
671 if (!dvd_write_part(dcr)) {
672 Dmsg0(400, "truncate_dvd: Error while writing to DVD.\n");
673 dev->truncating = false;
676 dev->truncating = false;
678 /* Set num_dvd_parts to zero (on disk) */
680 dev->num_dvd_parts = 0;
681 dcr->VolCatInfo.VolCatParts = 0;
682 dev->VolCatInfo.VolCatParts = 0;
683 /* Clear the size of the volume */
684 dev->VolCatInfo.VolCatBytes = 0;
685 dcr->VolCatInfo.VolCatBytes = 0;
688 if (!dir_update_volume_info(dcr, false, true)) {
696 * Checks if we can write on a non-blank DVD: meaning that it just have been
697 * truncated (there is only one zero-sized file on the DVD).
699 * Note! Normally if we can mount the device, which should be the case
700 * when we get here, it is not a blank DVD. Hence we check if
701 * if all files are of zero length (i.e. no data), in which case we allow it.
704 bool check_can_write_on_non_blank_dvd(DCR *dcr)
706 DEVICE* dev = dcr->dev;
708 struct dirent *entry, *result;
710 struct stat filestat;
713 name_max = pathconf(".", _PC_NAME_MAX);
714 if (name_max < 1024) {
718 if (!(dp = opendir(dev->device->mount_point))) {
720 dev->dev_errno = errno;
721 Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n",
722 dev->device->mount_point, dev->print_name(), be.bstrerror());
726 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
728 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
729 dev->dev_errno = EIO;
730 Dmsg2(129, "check_can_write_on_non_blank_dvd: no more files in dir %s (dev=%s)\n",
731 dev->device->mount_point, dev->print_name());
734 Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n",
735 result->d_name, dev->getVolCatName());
736 if (strcmp(result->d_name, ".") && strcmp(result->d_name, "..") &&
737 strcmp(result->d_name, ".keep")) {
738 /* Found a file, checking it is empty */
739 POOL_MEM filename(PM_FNAME);
740 pm_strcpy(filename, dev->device->mount_point);
741 if (!IsPathSeparator(filename.c_str()[strlen(filename.c_str())-1])) {
742 pm_strcat(filename, "/");
744 pm_strcat(filename, result->d_name);
745 if (stat(filename.c_str(), &filestat) < 0) {
747 dev->dev_errno = errno;
748 Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n",
749 filename.c_str(), be.bstrerror());
753 Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %lld\n",
754 filename.c_str(), filestat.st_size);
755 if (filestat.st_size != 0) {
765 Dmsg1(29, "OK can_write_on_non_blank_dvd: OK=%d\n", ok);
770 * Mount a DVD device, then scan to find out how many parts
773 int find_num_dvd_parts(DCR *dcr)
775 DEVICE *dev = dcr->dev;
778 if (!dev->is_dvd()) {
784 struct dirent *entry, *result;
786 int len = strlen(dcr->getVolCatName());
788 /* Now count the number of parts */
789 name_max = pathconf(".", _PC_NAME_MAX);
790 if (name_max < 1024) {
794 if (!(dp = opendir(dev->device->mount_point))) {
796 dev->dev_errno = errno;
797 Dmsg3(29, "find_num_dvd_parts: failed to open dir %s (dev=%s), ERR=%s\n",
798 dev->device->mount_point, dev->print_name(), be.bstrerror());
802 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
804 Dmsg1(100, "Looking for Vol=%s\n", dcr->getVolCatName());
808 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
809 dev->dev_errno = EIO;
810 Dmsg2(129, "find_num_dvd_parts: failed to find suitable file in dir %s (dev=%s)\n",
811 dev->device->mount_point, dev->print_name());
814 flen = strlen(result->d_name);
817 result->d_name[len] = 0;
818 if (strcmp(dcr->getVolCatName(), result->d_name) == 0) {
820 Dmsg1(100, "find_num_dvd_parts: found part: %s\n", result->d_name);
825 Dmsg2(129, "find_num_dvd_parts: ignoring %s in %s\n",
826 result->d_name, dev->device->mount_point);
831 Dmsg1(29, "find_num_dvd_parts = %d\n", num_parts);
835 dev->set_freespace_ok();
836 if (dev->is_mounted()) {