dev = (DEVICE *)malloc(sizeof(DEVICE));
memset(dev, 0, sizeof(DEVICE));
+ dev->Slot = -1; /* unknown */
/* Copy user supplied device parameters from Resource */
dev->dev_name = get_memory(strlen(device->device_name)+1);
Dmsg4(29, "open dev: type=%d dev_name=%s vol=%s mode=%s\n", dev_type,
print_name(), VolCatInfo.VolCatName, mode_to_str(omode));
state &= ~(ST_LABEL|ST_APPEND|ST_READ|ST_EOT|ST_WEOT|ST_EOF);
+ Slot = -1; /* unknown slot */
label_type = B_BACULA_LABEL;
if (is_tape() || is_fifo()) {
open_tape_device(dcr, omode);
open_file_device(dcr, omode);
}
state |= preserve; /* reset any important state info */
- Dmsg1(100, "preserve=0x%x\n", preserve);
+ Dmsg2(100, "preserve=0x%x fd=%d\n", preserve, fd);
return fd;
}
int nonblocking = O_NONBLOCK;
Dmsg0(29, "open dev: device is tape\n");
- if (is_autochanger()) {
- get_autochanger_loaded_slot(dcr);
- }
+ get_autochanger_loaded_slot(dcr);
set_mode(omode);
timeout = max_open_wait;
mode_to_str(omode), nonblocking);
/* Use system open() */
-#ifdef HAVE_WIN32
+#if defined(HAVE_WIN32)
if ((fd = tape_open(dev_name, mode)) < 0) {
berrno be;
dev_errno = errno;
{
POOL_MEM archive_name(PM_FNAME);
- if (is_autochanger()) {
- get_autochanger_loaded_slot(dcr);
- }
+ get_autochanger_loaded_slot(dcr);
/*
* Handle opening of File Archive (not a tape)
update_pos_dev(this); /* update position */
}
Dmsg4(29, "open dev: disk fd=%d opened, part=%d/%d, part_size=%u\n",
- fd, part, num_parts, part_size);
+ fd, part, num_dvd_parts, part_size);
}
/*
Dmsg3(29, "Enter: open_dvd_dev: %s dev=%s mode=%s\n", is_dvd()?"DVD":"disk",
archive_name.c_str(), mode_to_str(omode));
+ /*
+ * For a DVD we must alway pull the state info from dcr->VolCatInfo
+ * This is a bit ugly, but is necessary because we need to open/close/re-open
+ * the dvd file in order to properly mount/unmount and access the
+ * DVD. So we store the state of the DVD as far as is known in the
+ * catalog in dcr->VolCatInfo, and thus we refresh the dev->VolCatInfo
+ * copy here, when opening.
+ */
+ memcpy(&VolCatInfo, &dcr->VolCatInfo, sizeof(VolCatInfo));
+ Dmsg1(100, "Volume=%s\n", VolCatInfo.VolCatName);
+
if (VolCatInfo.VolCatName[0] == 0) {
Dmsg1(10, "Could not open file device %s. No Volume name given.\n",
print_name());
}
if (part == 0) {
+ Dmsg0(100, "Set part=1\n");
+ part = 1; /* count from 1 */
file_size = 0;
}
part_size = 0;
-
- Dmsg2(99, "open_dvd_device: num_parts=%d, VolCatInfo.VolCatParts=%d\n",
- dcr->dev->num_parts, dcr->VolCatInfo.VolCatParts);
- if (dcr->dev->num_parts < dcr->VolCatInfo.VolCatParts) {
- Dmsg2(99, "open_dvd_device: num_parts updated to %d (was %d)\n",
- dcr->VolCatInfo.VolCatParts, dcr->dev->num_parts);
- dcr->dev->num_parts = dcr->VolCatInfo.VolCatParts;
+ if (num_dvd_parts != VolCatInfo.VolCatParts) {
+ num_dvd_parts = VolCatInfo.VolCatParts;
}
+ // Clear any previous truncated_dvd status - we will recalculate it here
+ truncated_dvd = false;
+ Dmsg3(99, "open_dvd_device: part=%d num_dvd_parts=%d, VolCatInfo.VolCatParts=%d\n",
+ part, num_dvd_parts, dcr->VolCatInfo.VolCatParts);
+
if (mount_dvd(this, 1)) {
- if ((num_parts == 0) && (!truncating)) {
- /* If we can mount the device, and we are not truncating the DVD, we usually want to abort. */
- /* There is one exception, if there is only one 0-sized file on the DVD, with the right volume name,
- * we continue (it's the method used by truncate_dvd to truncate a volume). */
+ Dmsg0(99, "DVD device mounted.\n");
+ if (num_dvd_parts == 0 && !truncating) {
+ /*
+ * If we can mount the device, and we are not truncating the DVD,
+ * we usually want to abort. There is one exception, if there is
+ * only one 0-sized file on the DVD, with the right volume name,
+ * we continue (it's the method used by truncate_dvd to truncate a volume).
+ */
if (!check_can_write_on_non_blank_dvd(dcr)) {
Mmsg(errmsg, _("The media in the device %s is not empty, please blank it before writing anything to it.\n"), print_name());
Emsg0(M_FATAL, 0, errmsg);
clear_opened();
return;
}
+ truncated_dvd = true;
}
} else {
+ Dmsg0(99, "DVD device mount failed.\n");
/* We cannot mount the device */
- if (num_parts == 0) {
+ if (num_dvd_parts == 0) {
/* Run free space, check there is a media. */
- update_free_space_dev(this);
- if (have_media()) {
- Dmsg1(29, "Could not mount device %s, this is not a problem (num_parts == 0), and have media.\n", print_name());
+ if (!update_free_space_dev(this)) {
+ Emsg0(M_FATAL, 0, errmsg);
+ clear_opened();
+ return;
}
- else {
+ if (have_media()) {
+ Dmsg1(29, "Could not mount device %s, this is not a problem (num_dvd_parts == 0), and have media.\n", print_name());
+ } else {
Mmsg(errmsg, _("There is no valid media in the device %s.\n"), print_name());
Emsg0(M_FATAL, 0, errmsg);
clear_opened();
return;
}
- }
- else {
+ } else {
Mmsg(errmsg, _("Could not mount device %s.\n"), print_name());
Emsg0(M_FATAL, 0, errmsg);
clear_opened();
}
}
- Dmsg6(29, "open dev: %s dev=%s mode=%s part=%d npart=%d volcatnparts=%d\n",
- is_dvd()?"DVD":"disk", archive_name.c_str(), mode_to_str(omode),
- part, num_parts, dcr->VolCatInfo.VolCatParts);
+ Dmsg5(29, "open dev: DVD dev=%s mode=%s part=%d npart=%d volcatnparts=%d\n",
+ archive_name.c_str(), mode_to_str(omode),
+ part, num_dvd_parts, dcr->VolCatInfo.VolCatParts);
openmode = omode;
Dmsg2(100, "openmode=%d %s\n", openmode, mode_to_str(openmode));
* If we are not trying to access the last part, set mode to
* OPEN_READ_ONLY as writing would be an error.
*/
- if (part < num_parts) {
+ Dmsg2(29, "open DVD part=%d num_dvd_parts=%d\n", part, num_dvd_parts);
+ if (part <= num_dvd_parts) {
omode = OPEN_READ_ONLY;
make_mounted_dvd_filename(this, archive_name);
- }
- else {
+ } else {
+ omode = OPEN_READ_WRITE;
make_spooled_dvd_filename(this, archive_name);
}
set_mode(omode);
berrno be;
Mmsg2(errmsg, _("Could not open: %s, ERR=%s\n"), archive_name.c_str(),
be.strerror());
+ // Should this be set if we try the create/open below
dev_errno = EIO; /* Interpreted as no device present by acquire.c:acquire_device_for_read(). */
Dmsg1(29, "open failed: %s", errmsg);
- if ((omode == OPEN_READ_ONLY) && (part == num_parts)) {
- /* If the last part (on spool), doesn't exists when reading, create it and read from it
- * (it will report immediately an EOF):
+ /* Previous open failed. See if we can recover */
+ if ((omode == OPEN_READ_ONLY || omode == OPEN_READ_WRITE) &&
+ (part > num_dvd_parts)) {
+ /* If the last part (on spool), doesn't exist when accessing,
+ * create it. In read/write mode a write will be allowed (higher
+ * level software thinks that we are extending a pre-existing
+ * media. Reads for READ_ONLY will report immediately an EOF
* Sometimes it is better to finish with an EOF than with an error. */
- set_mode(OPEN_READ_WRITE);
+ Dmsg1(29, "Creating last part on spool: %s\n", archive_name.c_str());
+ omode = CREATE_READ_WRITE;
+ set_mode(CREATE_READ_WRITE);
fd = ::open(archive_name.c_str(), mode, 0640);
- set_mode(OPEN_READ_ONLY);
+ set_mode(omode);
}
-
- /* We don't need it. Only the last part is on spool */
- /*if (omode == OPEN_READ_ONLY) {
- make_spooled_dvd_filename(this, archive_name);
- fd = ::open(archive_name.c_str(), mode, 0640); // try on spool
- }*/
}
Dmsg1(100, "after open fd=%d\n", fd);
if (fd >= 0) {
+ if (omode == OPEN_READ_WRITE || omode == CREATE_READ_WRITE) {
+ set_append();
+ }
/* Get size of file */
if (fstat(fd, &filestat) < 0) {
berrno be;
part_size = filestat.st_size;
dev_errno = 0;
update_pos_dev(this); /* update position */
-
- /* NB: It seems this code is wrong... part number is incremented in open_next_part, not here */
-
- /* Check if just created Volume part */
-/* if (omode == OPEN_READ_WRITE && (part == 0 || part_size == 0)) {
- part++;
- num_parts = part;
- VolCatInfo.VolCatParts = num_parts;
- } else {
- if (part == 0) { // we must have opened the first part
- part++;
- }
- }*/
}
}
}
bool first = true;
Dmsg3(400, "rewind res=%d fd=%d %s\n", reserved_device, fd, print_name());
+ state &= ~(ST_EOT|ST_EOF|ST_WEOT); /* remove EOF/EOT flags */
+ block_num = file = 0;
+ file_size = 0;
+ file_addr = 0;
if (fd < 0) {
if (!is_dvd()) { /* In case of major error, the fd is not open on DVD, so we don't want to abort. */
dev_errno = EBADF;
}
return false;
}
- state &= ~(ST_EOT|ST_EOF|ST_WEOT); /* remove EOF/EOT flags */
- block_num = file = 0;
- file_size = 0;
- file_addr = 0;
if (is_tape()) {
mt_com.mt_op = MTREW;
mt_com.mt_count = 1;
first = false;
continue;
}
+#ifdef HAVE_SUN_OS
+ if (dev_errno == EIO) {
+ Mmsg1(errmsg, _("No tape loaded or drive offline on %s.\n"), print_name());
+ return false;
+ }
+#else
if (dev_errno == EIO && i > 0) {
Dmsg0(200, "Sleeping 5 seconds.\n");
bmicrosleep(5, 0);
continue;
}
+#endif
Mmsg2(errmsg, _("Rewind error on %s. ERR=%s.\n"),
print_name(), be.strerror());
return false;
block_num = file = 0;
file_size = 0;
file_addr = 0;
- part = 0;
#ifdef MTUNLOCK
mt_com.mt_op = MTUNLOCK;
mt_com.mt_count = 1;
if (errno == ENOTTY || errno == ENOSYS) { /* Function not implemented */
switch (func) {
case -1:
- Emsg0(M_ABORT, 0, _("Got ENOTTY on read/write!\n"));
- break;
+ break; /* ignore message printed later */
case MTWEOF:
msg = "WTWEOF";
capabilities &= ~CAP_EOF; /* turn off feature */
/* Typically on FreeBSD */
#ifdef MTIOCERRSTAT
{
+ berrno be;
/* Read and clear SCSI error status */
union mterrstat mt_errstat;
Dmsg2(200, "Doing MTIOCERRSTAT errno=%d ERR=%s\n", dev_errno,
- strerror(dev_errno));
+ be.strerror(dev_errno));
tape_ioctl(fd, MTIOCERRSTAT, (char *)&mt_errstat);
}
#endif
}
/* Remove the last part file if it is empty */
- if (num_parts > 0) {
+ if (num_dvd_parts > 0) {
struct stat statp;
+ int part_save = part;
POOL_MEM archive_name(PM_FNAME);
- part = num_parts;
- Dmsg1(100, "Call make_dvd_filename. Vol=%s\n", VolCatInfo.VolCatName);
+ int status;
+
+ part = num_dvd_parts;
make_spooled_dvd_filename(this, archive_name);
/* Check that the part file is empty */
- if ((stat(archive_name.c_str(), &statp) == 0) && (statp.st_size == 0)) {
+ status = stat(archive_name.c_str(), &statp);
+ if (status == 0 && statp.st_size == 0) {
+ Dmsg3(100, "Unlink empty part in close call make_dvd_filename. part=%d num=%d vol=%s\n",
+ part, num_dvd_parts, VolCatInfo.VolCatName);
Dmsg1(100, "unlink(%s)\n", archive_name.c_str());
unlink(archive_name.c_str());
- }
+ set_part_spooled(false); /* no spooled part left */
+ } else if (status < 0) {
+ set_part_spooled(false); /* spool doesn't exit */
+ }
+ part = part_save; /* restore part number */
}
/* Clean up device packet so it can be reused */
file = block_num = 0;
file_size = 0;
file_addr = 0;
- part = 0;
- num_parts = 0;
- part_size = 0;
- part_start = 0;
EndFile = EndBlock = 0;
+ Slot = -1; /* unknown slot */
free_volume(this);
memset(&VolCatInfo, 0, sizeof(VolCatInfo));
memset(&VolHdr, 0, sizeof(VolHdr));
}
results = get_memory(2000);
results[0] = 0;
+
/* If busy retry each second */
+ Dmsg1(20, "do_mount run_prog=%s\n", ocmd.c_str());
while ((status = run_program_full_output(ocmd.c_str(),
max_open_wait/2, results)) != 0) {
/* Doesn't work with internationalisation (This is not a problem) */
str = dev_name;
break;
case 'e':
- if (num_parts == 0) {
- str = "1";
+ if (num_dvd_parts == 0) {
+ if (truncating || truncated_dvd) {
+ str = "2";
+ } else {
+ str = "1";
+ }
} else {
str = "0";
}
static char *mode_to_str(int mode)
{
+ static char buf[100];
+ if (mode < 1 || mode > 4) {
+ bsnprintf(buf, sizeof(buf), "BAD mode=%d", mode);
+ return buf;
+ }
return modes[mode-1];
}