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 bool do_mount_dvd(DEVICE* dev, int mount, int dotimeout);
30 static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name);
33 * Write the current volume/part filename to archive_name.
35 void make_mounted_dvd_filename(DEVICE *dev, POOL_MEM &archive_name)
37 pm_strcpy(archive_name, dev->device->mount_point);
38 add_file_and_part_name(dev, archive_name);
39 dev->set_part_spooled(false);
42 void make_spooled_dvd_filename(DEVICE *dev, POOL_MEM &archive_name)
44 /* Use the working directory if spool directory is not defined */
45 if (dev->device->spool_directory) {
46 pm_strcpy(archive_name, dev->device->spool_directory);
48 pm_strcpy(archive_name, working_directory);
50 add_file_and_part_name(dev, archive_name);
51 dev->set_part_spooled(true);
54 static void add_file_and_part_name(DEVICE *dev, POOL_MEM &archive_name)
57 if (archive_name.c_str()[strlen(archive_name.c_str())-1] != '/') {
58 pm_strcat(archive_name, "/");
61 pm_strcat(archive_name, dev->VolCatInfo.VolCatName);
62 /* if part > 1, append .# to the filename (where # is the part number) */
64 pm_strcat(archive_name, ".");
65 bsnprintf(partnumber, sizeof(partnumber), "%d", dev->part);
66 pm_strcat(archive_name, partnumber);
68 Dmsg1(400, "Exit make_dvd_filename: arch=%s\n", archive_name.c_str());
72 * If timeout, wait until the mount command returns 0.
73 * If !timeout, try to mount the device only once.
75 bool mount_dvd(DEVICE* dev, int timeout)
77 Dmsg0(90, "Enter mount_dvd\n");
78 if (dev->is_mounted()) {
80 } else if (dev->requires_mount()) {
81 return do_mount_dvd(dev, 1, timeout);
87 * If timeout, wait until the unmount command returns 0.
88 * If !timeout, try to unmount the device only once.
90 bool unmount_dvd(DEVICE *dev, int timeout)
95 Dmsg0(90, "Enter unmount_dvd\n");
96 if (dev->is_mounted()) {
97 return do_mount_dvd(dev, 0, timeout);
102 /* (Un)mount the device */
103 static bool do_mount_dvd(DEVICE* dev, int mount, int dotimeout)
105 POOL_MEM ocmd(PM_FNAME);
110 sm_check(__FILE__, __LINE__, false);
112 if (dev->is_mounted()) {
113 Dmsg0(200, "======= DVD mount=1\n");
116 icmd = dev->device->mount_command;
118 if (!dev->is_mounted()) {
119 Dmsg0(200, "======= DVD mount=0\n");
122 icmd = dev->device->unmount_command;
125 dev->edit_mount_codes(ocmd, icmd);
127 Dmsg2(200, "do_mount_dvd: cmd=%s mounted=%d\n", ocmd.c_str(), !!dev->is_mounted());
130 /* Try at most 1 time to (un)mount the device. This should perhaps be configurable. */
135 results = get_memory(2000);
137 /* If busy retry each second */
138 while ((status = run_program_full_output(ocmd.c_str(),
139 dev->max_open_wait/2, results)) != 0) {
140 /* Doesn't work with internationalisation (This is not a problem) */
141 if (mount && fnmatch("*is already mounted on*", results, 0) == 0) {
144 if (!mount && fnmatch("* not mounted*", results, 0) == 0) {
148 /* Sometimes the device cannot be mounted because it is already mounted.
149 * Try to unmount it, then remount it */
151 Dmsg1(400, "Trying to unmount the device %s...\n", dev->print_name());
152 do_mount_dvd(dev, 0, 0);
157 Dmsg3(40, "Device %s cannot be %smounted. ERR=%s\n", dev->print_name(),
158 (mount ? "" : "un"), results);
159 Mmsg(dev->errmsg, _("Device %s cannot be %smounted. ERR=%s\n"),
160 dev->print_name(), (mount ? "" : "un"), results);
162 * Now, just to be sure it is not mounted, try to read the
166 struct dirent *entry, *result;
170 name_max = pathconf(".", _PC_NAME_MAX);
171 if (name_max < 1024) {
175 if (!(dp = opendir(dev->device->mount_point))) {
177 dev->dev_errno = errno;
178 Dmsg3(29, "do_mount_dvd: failed to open dir %s (dev=%s), ERR=%s\n",
179 dev->device->mount_point, dev->print_name(), be.strerror());
183 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
186 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
187 dev->dev_errno = EIO;
188 Dmsg2(129, "do_mount_dvd: failed to find suitable file in dir %s (dev=%s)\n",
189 dev->device->mount_point, dev->print_name());
192 if (strcmp(result->d_name, ".") && strcmp(result->d_name, "..") &&
193 strcmp(result->d_name, ".keep")) {
194 count++; /* result->d_name != ., .. or .keep (Gentoo-specific) */
198 Dmsg2(129, "do_mount_dvd: ignoring %s in %s\n",
199 result->d_name, dev->device->mount_point);
205 Dmsg1(29, "do_mount_dvd: got %d files in the mount point (not counting ., .. and .keep)\n", count);
208 /* If we got more than ., .. and .keep */
209 /* there must be something mounted */
213 /* An unmount request. We failed to unmount - report an error */
214 dev->set_mounted(true);
215 free_pool_memory(results);
216 Dmsg0(200, "============ DVD mount=1\n");
221 dev->set_mounted(false);
222 sm_check(__FILE__, __LINE__, false);
223 free_pool_memory(results);
224 Dmsg0(200, "============ DVD mount=0\n");
228 dev->set_mounted(mount); /* set/clear mounted flag */
229 free_pool_memory(results);
230 /* Do not check free space when unmounting */
232 update_free_space_dev(dev);
234 Dmsg1(200, "============ DVD mount=%d\n", mount);
238 /* Update the free space on the device */
239 void update_free_space_dev(DEVICE* dev)
241 POOL_MEM ocmd(PM_FNAME);
248 /* The device must be mounted in order to dvd-freespace to work */
251 sm_check(__FILE__, __LINE__, false);
252 icmd = dev->device->free_space_command;
256 dev->free_space_errno = 0;
257 dev->clear_freespace_ok(); /* No valid freespace */
259 Dmsg2(29, "update_free_space_dev: free_space=%s, free_space_errno=%d (!icmd)\n",
260 edit_uint64(dev->free_space, ed1), dev->free_space_errno);
264 dev->edit_mount_codes(ocmd, icmd);
266 Dmsg1(29, "update_free_space_dev: cmd=%s\n", ocmd.c_str());
268 results = get_pool_memory(PM_MESSAGE);
270 /* Try at most 3 times to get the free space on the device. This should perhaps be configurable. */
274 if (run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results) == 0) {
275 Dmsg1(400, "Free space program run : %s\n", results);
276 free = str_to_int64(results);
278 dev->free_space = free;
279 dev->free_space_errno = 0;
280 dev->set_freespace_ok(); /* have valid freespace */
282 Mmsg0(dev->errmsg, "");
287 dev->free_space_errno = EPIPE;
288 dev->clear_freespace_ok(); /* no valid freespace */
289 Mmsg1(dev->errmsg, _("Cannot run free space command (%s)\n"), results);
292 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
293 "free_space_errno=%d ERR=%s\n", dev->print_name(),
294 edit_uint64(dev->free_space, ed1), dev->free_space_errno,
300 dev->dev_errno = dev->free_space_errno;
301 Dmsg4(40, "Cannot get free space on device %s. free_space=%s, "
302 "free_space_errno=%d ERR=%s\n",
303 dev->print_name(), edit_uint64(dev->free_space, ed1),
304 dev->free_space_errno, dev->errmsg);
308 free_pool_memory(results);
309 Dmsg4(29, "update_free_space_dev: free_space=%s freespace_ok=%d free_space_errno=%d have_media=%d\n",
310 edit_uint64(dev->free_space, ed1), !!dev->is_freespace_ok(), dev->free_space_errno, !!dev->have_media());
311 sm_check(__FILE__, __LINE__, false);
316 * Write a part (Vol, Vol.1, ...) from the spool to the DVD
317 * This routine does not update the part number, so normally, you
318 * should call open_next_part()
319 * It is also called from truncate_dvd to "blank" the medium, as
320 * well as from block.c when the DVD is full to write the last part.
322 bool dvd_write_part(DCR *dcr)
324 DEVICE *dev = dcr->dev;
325 POOL_MEM archive_name(PM_FNAME);
327 /* Don't write empty part files.
328 * This is only useful when growisofs does not support write beyond
331 * - 3.9 GB on the volume, dvd-freespace reports 0.4 GB free
332 * - Write 0.2 GB on the volume, Bacula thinks it could still
333 * append data, it creates a new empty part.
334 * - dvd-freespace reports 0 GB free, as the 4GB boundary has
336 * - Bacula thinks he must finish to write to the device, so it
337 * tries to write the last part (0-byte), but dvd-writepart fails...
339 * There is one exception: when recycling a volume, we write a blank part
340 * file, so, then, we need to accept to write it.
342 if ((dev->part_size == 0) && (dev->part > 0)) {
343 Dmsg2(29, "dvd_write_part: device is %s, won't write blank part %d\n", dev->print_name(), dev->part);
344 /* Delete spool file */
345 make_spooled_dvd_filename(dev, archive_name);
346 unlink(archive_name.c_str());
347 Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
348 sm_check(__FILE__, __LINE__, false);
352 POOL_MEM ocmd(PM_FNAME);
353 POOL_MEM results(PM_MESSAGE);
359 sm_check(__FILE__, __LINE__, false);
360 Dmsg3(29, "dvd_write_part: device is %s, part is %d, is_mounted=%d\n", dev->print_name(), dev->part, dev->is_mounted());
361 icmd = dev->device->write_part_command;
363 dev->edit_mount_codes(ocmd, icmd);
366 * original line follows
367 * timeout = dev->max_open_wait + (dev->max_part_size/(1350*1024/2));
368 * I modified this for a longer timeout; pre-formatting, blanking and
369 * writing can take quite a while
372 /* Explanation of the timeout value, when writing the first part,
374 * 9 GB, write speed 1x: 6990 seconds (almost 2 hours...)
375 * Overhead: 900 seconds (starting, initializing, finalizing,probably
376 * reloading 15 minutes)
378 * A reasonable last-exit timeout would be 16000 seconds. Quite long -
379 * almost 4.5 hours, but hopefully, that timeout will only ever be needed
380 * in case of a serious emergency.
386 timeout = dev->max_open_wait + (dev->part_size/(1350*1024/4));
388 Dmsg2(29, "dvd_write_part: cmd=%s timeout=%d\n", ocmd.c_str(), timeout);
390 status = run_program_full_output(ocmd.c_str(), timeout, results.c_str());
391 dev->truncated_dvd = false; // Clear this status now write has finished
393 Mmsg1(dev->errmsg, _("Error while writing current part to the DVD: %s"),
395 Dmsg1(000, "%s\n", dev->errmsg);
396 dev->dev_errno = EIO;
397 mark_volume_in_error(dcr);
398 sm_check(__FILE__, __LINE__, false);
401 dev->num_parts++; /* there is now one more part on DVD */
404 /* Delete spool file */
405 make_spooled_dvd_filename(dev, archive_name);
406 unlink(archive_name.c_str());
407 Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
408 sm_check(__FILE__, __LINE__, false);
410 /* growisofs umounted the device, so remount it (it will update the free space) */
411 dev->clear_mounted();
413 Jmsg(dcr->jcr, M_INFO, 0, _("Remaining free space %s on %s\n"),
414 edit_uint64_with_commas(dev->free_space, ed1), dev->print_name());
415 sm_check(__FILE__, __LINE__, false);
419 /* Open the next part file.
421 * - Increment part number
422 * - Reopen the device
424 int dvd_open_next_part(DCR *dcr)
426 DEVICE *dev = dcr->dev;
428 Dmsg6(29, "Enter: ==== open_next_part part=%d npart=%d dev=%s vol=%s mode=%d file_addr=%d\n",
429 dev->part, dev->num_parts, dev->print_name(),
430 dev->VolCatInfo.VolCatName, dev->openmode, dev->file_addr);
431 if (!dev->is_dvd()) {
432 Dmsg1(000, "Device %s is not dvd!!!!\n", dev->print_name());
436 /* When appending, do not open a new part if the current is empty */
437 if (dev->can_append() && (dev->part >= dev->num_parts) &&
438 (dev->part_size == 0)) {
439 Dmsg0(29, "open_next_part exited immediately (dev->part_size == 0).\n");
451 * If we have a part open for write, then write it to
452 * DVD before opening the next part.
454 if (dev->is_dvd() && (dev->part >= dev->num_parts) && dev->can_append()) {
455 if (!dvd_write_part(dcr)) {
456 Dmsg0(29, "Error in dvd_write part.\n");
461 if (dev->part > dev->num_parts) {
462 Dmsg2(000, "In open_next_part: part=%d nump=%d\n", dev->part, dev->num_parts);
463 ASSERT(dev->part <= dev->num_parts);
465 dev->part_start += dev->part_size;
468 Dmsg2(29, "part=%d num_parts=%d\n", dev->part, dev->num_parts);
469 /* I think this dev->can_append() should not be there */
470 if ((dev->num_parts < dev->part) && dev->can_append()) {
471 POOL_MEM archive_name(PM_FNAME);
474 * First check what is on DVD. If our part is there, we
475 * are in trouble, so bail out.
476 * NB: This is however not a problem if we are writing the first part.
477 * It simply means that we are overriding an existing volume...
479 if (dev->num_parts > 0) {
480 make_mounted_dvd_filename(dev, archive_name); /* makes dvd name */
481 if (stat(archive_name.c_str(), &buf) == 0) {
482 /* bad news bail out */
483 Mmsg1(&dev->errmsg, _("Next Volume part already exists on DVD. Cannot continue: %s\n"),
484 archive_name.c_str());
489 Dmsg2(400, "num_parts=%d part=%d\n", dev->num_parts, dev->part);
490 dev->VolCatInfo.VolCatParts = dev->part;
491 make_spooled_dvd_filename(dev, archive_name); /* makes spool name */
493 /* Check if the next part exists in spool directory . */
494 if ((stat(archive_name.c_str(), &buf) == 0) || (errno != ENOENT)) {
495 Dmsg1(29, "open_next_part %s is in the way, moving it away...\n", archive_name.c_str());
496 /* Then try to unlink it */
497 if (unlink(archive_name.c_str()) < 0) {
499 dev->dev_errno = errno;
500 Mmsg2(dev->errmsg, _("open_next_part can't unlink existing part %s, ERR=%s\n"),
501 archive_name.c_str(), be.strerror());
506 /* KES. It seems to me that this if should not be
507 * needed. If num_parts represents what is on the DVD
508 * we should only need to change it when writing a part
510 * NB. As dvd_write_part increments dev->num_parts, I also
511 * think it is not needed.
513 if (dev->num_parts < dev->part) {
514 Dmsg2(400, "Set npart=%d to part=%d\n", dev->num_parts, dev->part);
515 dev->num_parts = dev->part;
516 dev->VolCatInfo.VolCatParts = dev->part;
518 Dmsg2(400, "Call dev->open(vol=%s, mode=%d\n", dev->VolCatInfo.VolCatName,
522 int append = dev->can_append();
523 if (dev->open(dcr, dev->openmode) < 0) {
526 dev->set_labeled(); /* all next parts are "labeled" */
527 if (append && (dev->part == dev->num_parts)) { /* If needed, set the append flag back */
534 /* Open the first part file.
536 * - Reopen the device
538 int dvd_open_first_part(DCR *dcr, int mode)
540 DEVICE *dev = dcr->dev;
542 Dmsg5(29, "Enter: ==== open_first_part dev=%s Vol=%s mode=%d num_parts=%d append=%d\n", dev->print_name(),
543 dev->VolCatInfo.VolCatName, dev->openmode, dev->num_parts, dev->can_append());
554 Dmsg2(400, "Call dev->open(vol=%s, mode=%d)\n", dcr->VolCatInfo.VolCatName,
556 int append = dev->can_append();
557 if (dev->open(dcr, mode) < 0) {
558 Dmsg0(400, "open dev() failed\n");
561 if (append && (dev->part == dev->num_parts)) { /* If needed, set the append flag back */
564 Dmsg2(400, "Leave open_first_part state=%s append=%d\n", dev->is_open()?"open":"not open", dev->can_append());
570 /* Protected version of lseek, which opens the right part if necessary */
571 off_t lseek_dev(DEVICE *dev, off_t offset, int whence)
575 char ed1[50], ed2[50];
577 Dmsg3(400, "Enter lseek_dev fd=%d part=%d nparts=%d\n", dev->fd,
578 dev->part, dev->num_parts);
579 if (!dev->is_dvd()) {
580 Dmsg0(400, "Using sys lseek\n");
581 return lseek(dev->fd, offset, whence);
584 dcr = (DCR *)dev->attached_dcrs->first(); /* any dcr will do */
587 Dmsg2(400, "lseek_dev SEEK_SET to %s (part_start=%s)\n",
588 edit_uint64(offset, ed1), edit_uint64(dev->part_start, ed2));
589 if ((uint64_t)offset >= dev->part_start) {
590 if (((uint64_t)offset == dev->part_start) || ((uint64_t)offset < (dev->part_start+dev->part_size))) {
591 /* We are staying in the current part, just seek */
592 if ((pos = lseek(dev->fd, offset-dev->part_start, SEEK_SET)) < 0) {
595 return pos + dev->part_start;
598 /* Load next part, and start again */
599 if (dvd_open_next_part(dcr) < 0) {
600 Dmsg0(400, "lseek_dev failed while trying to open the next part\n");
603 return lseek_dev(dev, offset, SEEK_SET);
607 * pos < dev->part_start :
608 * We need to access a previous part,
609 * so just load the first one, and seek again
610 * until the right one is loaded
612 if (dvd_open_first_part(dcr, dev->openmode) < 0) {
613 Dmsg0(400, "lseek_dev failed while trying to open the first part\n");
616 return lseek_dev(dev, offset, SEEK_SET);
620 Dmsg1(400, "lseek_dev SEEK_CUR to %s\n", edit_uint64(offset, ed1));
621 if ((pos = lseek(dev->fd, (off_t)0, SEEK_CUR)) < 0) {
624 pos += dev->part_start;
626 Dmsg1(400, "lseek_dev SEEK_CUR returns %s\n", edit_uint64(pos, ed1));
628 } else { /* Not used in Bacula, but should work */
629 return lseek_dev(dev, pos, SEEK_SET);
633 Dmsg1(400, "lseek_dev SEEK_END to %s\n", edit_uint64(offset, ed1));
635 * Bacula does not use offsets for SEEK_END
636 * Also, Bacula uses seek_end only when it wants to
637 * append to the volume, so for a dvd that means
638 * that the volume must be spooled since the DVD
639 * itself is read-only (as currently implemented).
641 if (offset > 0) { /* Not used by bacula */
642 Dmsg1(400, "lseek_dev SEEK_END called with an invalid offset %s\n",
643 edit_uint64(offset, ed1));
647 /* If we are already on a spooled part and have the
648 * right part number, simply seek
650 if (dev->is_part_spooled() && dev->part == dev->num_parts) {
651 if ((pos = lseek(dev->fd, (off_t)0, SEEK_END)) < 0) {
654 Dmsg1(400, "lseek_dev SEEK_END returns %s\n",
655 edit_uint64(pos + dev->part_start, ed1));
656 return pos + dev->part_start;
660 * Load the first part, then load the next until we reach the last one.
661 * This is the only way to be sure we compute the right file address.
663 * Save previous openmode, and open all but last part read-only
666 int modesave = dev->openmode;
667 /* Works because num_parts > 0. */
668 if (dvd_open_first_part(dcr, OPEN_READ_ONLY) < 0) {
669 Dmsg0(400, "lseek_dev failed while trying to open the first part\n");
672 if (dev->num_parts > 0) {
673 while (dev->part < (dev->num_parts-1)) {
674 if (dvd_open_next_part(dcr) < 0) {
675 Dmsg0(400, "lseek_dev failed while trying to open the next part\n");
679 dev->openmode = modesave;
680 if (dvd_open_next_part(dcr) < 0) {
681 Dmsg0(400, "lseek_dev failed while trying to open the next part\n");
685 return lseek_dev(dev, 0, SEEK_END);
694 bool dvd_close_job(DCR *dcr)
696 DEVICE *dev = dcr->dev;
700 /* If the device is a dvd and WritePartAfterJob
701 * is set to yes, open the next part, so, in case of a device
702 * that requires mount, it will be written to the device.
704 if (dev->is_dvd() && jcr->write_part_after_job && (dev->part_size > 0)) {
705 Dmsg1(400, "Writing last part=%d write_partafter_job is set.\n",
707 if (dev->part < dev->num_parts) {
708 Jmsg3(jcr, M_FATAL, 0, _("Error while writing, current part number is less than the total number of parts (%d/%d, device=%s)\n"),
709 dev->part, dev->num_parts, dev->print_name());
710 dev->dev_errno = EIO;
714 /* This should be !dvd_write_part(dcr)
715 NB: No! If you call dvd_write_part, the part number is not updated.
716 You must open the next part, it will automatically write the part and
717 update the part number. */
718 if (ok && (dvd_open_next_part(dcr) < 0)) {
719 Jmsg2(jcr, M_FATAL, 0, _("Unable to write part %s: ERR=%s\n"),
720 dev->print_name(), dev->bstrerror());
721 dev->dev_errno = EIO;
725 Dmsg1(200, "Set VolCatParts=%d\n", dev->num_parts);
726 dev->VolCatInfo.VolCatParts = dev->num_parts;
730 bool truncate_dvd(DCR *dcr)
732 DEVICE* dev = dcr->dev;
740 if (!unmount_dvd(dev, 1)) {
741 Dmsg0(400, "truncate_dvd: Failed to unmount DVD\n");
745 /* Set num_parts to zero (on disk) */
747 dcr->VolCatInfo.VolCatParts = 0;
748 dev->VolCatInfo.VolCatParts = 0;
750 Dmsg0(400, "truncate_dvd: Opening first part (1)...\n");
752 dev->truncating = true;
753 if (dvd_open_first_part(dcr, CREATE_READ_WRITE) < 0) {
754 Dmsg0(400, "truncate_dvd: Error while opening first part (1).\n");
755 dev->truncating = false;
759 Dmsg0(400, "truncate_dvd: Truncating...\n");
761 /* If necessary, truncate it. */
762 if (ftruncate(dev->fd, 0) != 0) {
764 Mmsg2(dev->errmsg, _("Unable to truncate device %s. ERR=%s\n"),
765 dev->print_name(), be.strerror());
766 dev->truncating = false;
774 Dmsg0(400, "truncate_dvd: Opening first part (2)...\n");
776 if (!dvd_write_part(dcr)) {
777 Dmsg0(400, "truncate_dvd: Error while writing to DVD.\n");
778 dev->truncating = false;
781 dev->truncating = false;
783 /* Set num_parts to zero (on disk) */
785 dcr->VolCatInfo.VolCatParts = 0;
786 dev->VolCatInfo.VolCatParts = 0;
788 if (dvd_open_first_part(dcr, OPEN_READ_WRITE) < 0) {
789 Dmsg0(400, "truncate_dvd: Error while opening first part (2).\n");
796 /* Checks if we can write on a non-blank DVD: meaning that it just have been
797 * truncated (there is only one zero-sized file on the DVD, with the right
799 bool check_can_write_on_non_blank_dvd(DCR *dcr)
801 DEVICE* dev = dcr->dev;
803 struct dirent *entry, *result;
806 int matched = 0; /* We found an empty file with the right name. */
807 struct stat filestat;
809 name_max = pathconf(".", _PC_NAME_MAX);
810 if (name_max < 1024) {
814 if (!(dp = opendir(dev->device->mount_point))) {
816 dev->dev_errno = errno;
817 Dmsg3(29, "check_can_write_on_non_blank_dvd: failed to open dir %s (dev=%s), ERR=%s\n",
818 dev->device->mount_point, dev->print_name(), be.strerror());
822 entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
824 if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
825 dev->dev_errno = EIO;
826 Dmsg2(129, "check_can_write_on_non_blank_dvd: failed to find suitable file in dir %s (dev=%s)\n",
827 dev->device->mount_point, dev->print_name());
830 Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n",
831 result->d_name, dev->VolCatInfo.VolCatName);
832 if (strcmp(result->d_name, dev->VolCatInfo.VolCatName) == 0) {
833 /* Found the file, checking it is empty */
834 POOL_MEM filename(PM_FNAME);
835 pm_strcpy(filename, dev->device->mount_point);
836 if (filename.c_str()[strlen(filename.c_str())-1] != '/') {
837 pm_strcat(filename, "/");
839 pm_strcat(filename, dev->VolCatInfo.VolCatName);
840 if (stat(filename.c_str(), &filestat) < 0) {
842 dev->dev_errno = errno;
843 Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n",
844 filename.c_str(), be.strerror());
847 Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %d\n",
848 filename.c_str(), filestat.st_size);
849 matched = filestat.st_size == 0;
857 Dmsg2(29, "check_can_write_on_non_blank_dvd: got %d files in the mount point (matched=%d)\n", count, matched);
860 /* There are more than 3 files (., .., and the volume file) */