}
/* We successfully wrote the block, now do housekeeping */
- Dmsg2(400, "VolCatBytes=%d newVolCatBytes=%d\n", (int)dev->VolCatInfo.VolCatBytes,
+ Dmsg2(1300, "VolCatBytes=%d newVolCatBytes=%d\n", (int)dev->VolCatInfo.VolCatBytes,
(int)(dev->VolCatInfo.VolCatBytes+wlen));
dev->VolCatInfo.VolCatBytes += wlen;
dev->VolCatInfo.VolCatBlocks++;
return false;
}
- /*Dmsg1(100, "dev->file_size=%u\n",(unsigned int)dev->file_size);
- Dmsg1(100, "dev->file_addr=%u\n",(unsigned int)dev->file_addr);
- Dmsg1(100, "lseek=%u\n",(unsigned int)lseek(dev->fd, 0, SEEK_CUR));
- Dmsg1(100, "dev->part_start=%u\n",(unsigned int)dev->part_start);
- Dmsg1(100, "dev->file_addr-dev->part_start=%u\n",(unsigned int)dev->file_addr-dev->part_start);
- Dmsg1(100, "dev->file_size-dev->part_start=%u\n",(unsigned int)dev->file_size-dev->part_start);
- Dmsg1(100, "dev->part_size=%u\n", (unsigned int)dev->part_size);
- Dmsg1(100, "dev->part=%u\n", (unsigned int)dev->part);
- Dmsg1(100, "dev->num_dvd_parts=%u\n", (unsigned int)dev->num_dvd_parts);
- Dmsg1(100, "dev->VolCatInfo.VolCatParts=%u\n", (unsigned int)dev->VolCatInfo.VolCatParts);
- Dmsg3(100, "Tests : %d %d %d\n", (dev->VolCatInfo.VolCatParts > 0),
+#define lots_of_debug
+#ifdef lots_of_debug
+ if (dev->at_eof() && dev->is_dvd()) {
+ Dmsg1(100, "file_size=%u\n",(unsigned int)dev->file_size);
+ Dmsg1(100, "file_addr=%u\n",(unsigned int)dev->file_addr);
+ Dmsg1(100, "lseek=%u\n",(unsigned int)lseek(dev->fd, 0, SEEK_CUR));
+ Dmsg1(100, "part_start=%u\n",(unsigned int)dev->part_start);
+ Dmsg1(100, "part_size=%u\n", (unsigned int)dev->part_size);
+ Dmsg2(100, "part=%u num_dvd_parts=%u\n", dev->part, dev->num_dvd_parts);
+ Dmsg1(100, "VolCatInfo.VolCatParts=%u\n", (unsigned int)dev->VolCatInfo.VolCatParts);
+ Dmsg3(100, "Tests : %d %d %d\n", (dev->VolCatInfo.VolCatParts > 0),
((dev->file_addr-dev->part_start) == dev->part_size),
- (dev->part <= dev->VolCatInfo.VolCatParts));*/
+ (dev->part <= dev->VolCatInfo.VolCatParts));
+ }
+#endif
/* Check for DVD part file end */
if (dev->at_eof() && dev->is_dvd() && dev->num_dvd_parts > 0 &&
- dev->part < dev->num_dvd_parts) {
+ dev->part <= dev->num_dvd_parts) {
Dmsg0(400, "Call dvd_open_next_part\n");
if (dvd_open_next_part(dcr) < 0) {
Jmsg3(dcr->jcr, M_FATAL, 0, _("Unable to open device part=%d %s: ERR=%s\n"),
}
}
dev->rewind(dcr);
- write_new_volume_label_to_dev(dcr, cmd, "Default", true /* label dvd now */);
+ write_new_volume_label_to_dev(dcr, cmd, "Default", false,/*no relabel*/ true /* label dvd now */);
Pmsg1(-1, _("Wrote Volume label for volume \"%s\".\n"), cmd);
}
archive_name.c_str(), mode_to_str(omode));
/*
- * For a DVD we must alway pull the state info from dcr->VolCatInfo
+ * For a DVD we must always 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
* 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());
+ Mmsg(errmsg, _("The DVD in device %s contains data, please blank it before writing.\n"), print_name());
Emsg0(M_FATAL, 0, errmsg);
unmount_dvd(this, 1); /* Unmount the device, so the operator can change it. */
clear_opened();
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());
+ Mmsg(errmsg, _("There is no valid DVD in device %s.\n"), print_name());
Emsg0(M_FATAL, 0, errmsg);
clear_opened();
return;
}
} else {
- Mmsg(errmsg, _("Could not mount device %s.\n"), print_name());
+ Mmsg(errmsg, _("Could not mount DVD device %s.\n"), print_name());
Emsg0(M_FATAL, 0, errmsg);
clear_opened();
return;
return truncate_dvd(dcr);
}
+ /* ***FIXME*** we really need to unlink() the file so that
+ * its name can be changed for a relabel.
+ */
if (ftruncate(fd, 0) != 0) {
berrno be;
Mmsg2(errmsg, _("Unable to truncate device %s. ERR=%s\n"),
DEVICE *dev = dcr->dev;
int label_status;
int mode;
- const char *volname = (relabel == 0) ? newname : oldname;
+ const char *volname = (relabel == 1) ? oldname : newname;
char ed1[50];
steal_device_lock(dev, &hold, BST_WRITING_LABEL);
Dmsg1(100, "Stole device %s lock, writing label.\n", dev->print_name());
- Dmsg0(90, "try_autoload_device - looking for volume_info\n");
- if (relabel && dev->is_dvd()) {
- /* Fake at least one partition to ensure that we look for the old volume */
- dcr->VolCatInfo.VolCatParts = 1;
- }
+ Dmsg0(90, "try_autoload_device - looking for volume_info\n");
if (!try_autoload_device(dcr->jcr, slot, volname)) {
goto bail_out; /* error */
}
} else {
mode = CREATE_READ_WRITE;
}
- if (dev->is_dvd()) {
- bstrncpy(dcr->VolCatInfo.VolCatName, volname, sizeof(dcr->VolCatInfo.VolCatName));
- }
+ if (relabel) {
+ dev->truncating = true; /* let open() know we will truncate it */
+ }
+ /* Set old volume name for open if relabeling */
+ bstrncpy(dcr->VolCatInfo.VolCatName, volname, sizeof(dcr->VolCatInfo.VolCatName));
if (dev->open(dcr, mode) < 0) {
bnet_fsend(dir, _("3910 Unable to open device %s: ERR=%s\n"),
dev->print_name(), dev->strerror());
/* See what we have for a Volume */
label_status = read_dev_volume_label(dcr);
+ /* Set new volume name */
+ bstrncpy(dcr->VolCatInfo.VolCatName, newname, sizeof(dcr->VolCatInfo.VolCatName));
switch(label_status) {
case VOL_NAME_ERROR:
case VOL_VERSION_ERROR:
bnet_fsend(dir, _("3922 Cannot relabel an ANSI/IBM labeled Volume.\n"));
break;
}
- if (relabel && dev->is_dvd()) {
- /* Save dev VolumeName */
- bstrncpy(dcr->VolumeName, dev->VolCatInfo.VolCatName, sizeof(dcr->VolumeName));
- /* Use new name for DVD truncation */
- bstrncpy(dev->VolCatInfo.VolCatName, newname, sizeof(dev->VolCatInfo.VolCatName));
- if (!dev->truncate(dcr)) {
- bnet_fsend(dir, _("3912 Failed to truncate previous DVD volume.\n"));
- /* Restore device VolName */
- bstrncpy(dev->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dev->VolCatInfo.VolCatName));
- break;
- }
- /* Restore device VolName */
- bstrncpy(dev->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dev->VolCatInfo.VolCatName));
- }
- free_volume(dev); /* release old volume name */
/* Fall through wanted! */
case VOL_IO_ERROR:
case VOL_NO_LABEL:
- if (!write_new_volume_label_to_dev(dcr, newname, poolname, true /* write dvd now */)) {
+ if (!write_new_volume_label_to_dev(dcr, newname, poolname,
+ relabel, true /* write dvd now */)) {
bnet_fsend(dir, _("3912 Failed to label Volume: ERR=%s\n"), dev->bstrerror());
break;
}
icmd = dev->device->unmount_command;
}
+ dev->clear_freespace_ok();
dev->edit_mount_codes(ocmd, icmd);
Dmsg2(200, "do_mount_dvd: cmd=%s mounted=%d\n", ocmd.c_str(), !!dev->is_mounted());
berrno be;
Dmsg1(20, "Run freespace prog=%s\n", ocmd.c_str());
status = run_program_full_output(ocmd.c_str(), dev->max_open_wait/2, results);
- Dmsg2(20, "Freespace status=%d result=%s\n", status, results);
+ Dmsg2(500, "Freespace status=%d result=%s\n", status, results);
if (status == 0) {
free = str_to_int64(results);
Dmsg1(400, "Free space program run: Freespace=%s\n", results);
DEVICE *dev = dcr->dev;
POOL_MEM archive_name(PM_FNAME);
- /* Don't write empty part files.
+ /*
+ * Don't write empty part files.
* This is only useful when growisofs does not support write beyond
* the 4GB boundary.
* Example :
* - Bacula thinks he must finish to write to the device, so it
* tries to write the last part (0-byte), but dvd-writepart fails...
*
- * ***FIXME**** we cannot write a blank part!!!!!!!
* There is one exception: when recycling a volume, we write a blank part
* file, so, then, we need to accept to write it.
*/
make_spooled_dvd_filename(dev, archive_name);
unlink(archive_name.c_str());
dev->set_part_spooled(false);
- Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
+ Dmsg1(29, "========= unlink(%s)\n", archive_name.c_str());
sm_check(__FILE__, __LINE__, false);
return true;
}
make_spooled_dvd_filename(dev, archive_name);
unlink(archive_name.c_str());
dev->set_part_spooled(false);
- Dmsg1(29, "unlink(%s)\n", archive_name.c_str());
+ Dmsg1(29, "========= unlink(%s)\n", archive_name.c_str());
sm_check(__FILE__, __LINE__, false);
/* growisofs umounted the device, so remount it (it will update the free space) */
* - Close the fd
* - Reopen the device
*/
-int dvd_open_first_part(DCR *dcr, int mode)
+static bool dvd_open_first_part(DCR *dcr, int mode)
{
DEVICE *dev = dcr->dev;
if (dev->open(dcr, mode) < 0) {
Dmsg0(400, "open dev() failed\n");
- return -1;
+ return false;
}
Dmsg2(400, "Leave open_first_part state=%s append=%d\n", dev->is_open()?"open":"not open", dev->can_append());
- return dev->fd;
+ return true;
}
* until the right one is loaded
*/
Dmsg0(100, "lseek open first part\n");
- if (dvd_open_first_part(dcr, dev->openmode) < 0) {
+ if (!dvd_open_first_part(dcr, dev->openmode)) {
Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
return -1;
}
* (useful for DVDs)
*/
int modesave = dev->openmode;
- if (dvd_open_first_part(dcr, OPEN_READ_ONLY) < 0) {
+ if (!dvd_open_first_part(dcr, OPEN_READ_ONLY)) {
Dmsg0(400, "lseek_dvd failed while trying to open the first part\n");
return -1;
}
return false;
}
+ /* If necessary, delete its spool file. */
+ if (dev->is_part_spooled()) {
+ POOL_MEM archive_name(PM_FNAME);
+ /* Delete spool file */
+ make_spooled_dvd_filename(dev, archive_name);
+ unlink(archive_name.c_str());
+ dev->set_part_spooled(false);
+ }
+
/* Set num_dvd_parts to zero (on disk) */
+ dev->part = 0;
dev->num_dvd_parts = 0;
dcr->VolCatInfo.VolCatParts = 0;
dev->VolCatInfo.VolCatParts = 0;
Dmsg0(400, "truncate_dvd: Opening first part (1)...\n");
dev->truncating = true;
- if (dvd_open_first_part(dcr, CREATE_READ_WRITE) < 0) {
+ /* This creates a zero length spool file and sets part=1 */
+ if (!dvd_open_first_part(dcr, CREATE_READ_WRITE)) {
Dmsg0(400, "truncate_dvd: Error while opening first part (1).\n");
dev->truncating = false;
return false;
}
- Dmsg0(400, "truncate_dvd: Truncating...\n");
-
- /* If necessary, truncate it spool file. */
- if (ftruncate(dev->fd, 0) != 0) {
- berrno be;
- Mmsg2(dev->errmsg, _("Unable to truncate device %s. ERR=%s\n"),
- dev->print_name(), be.strerror());
- dev->truncating = false;
- return false;
- }
-
dev->close_part(dcr);
Dmsg0(400, "truncate_dvd: Opening first part (2)...\n");
/*
- * Now actually truncate the DVD
- * This is really kludgy, why not an argument or a separate
- * subroutine? KES
+ * Now actually truncate the DVD which is done by writing
+ * a zero length part to the DVD/
*/
if (!dvd_write_part(dcr)) {
Dmsg0(400, "truncate_dvd: Error while writing to DVD.\n");
dev->truncating = false;
/* Set num_dvd_parts to zero (on disk) */
+ dev->part = 0;
dev->num_dvd_parts = 0;
dcr->VolCatInfo.VolCatParts = 0;
dev->VolCatInfo.VolCatParts = 0;
dev->VolCatInfo.VolCatBytes = 0;
dcr->VolCatInfo.VolCatBytes = 0;
-#ifdef xxx
/* Update catalog */
if (!dir_update_volume_info(dcr, false)) {
return false;
}
-#endif
- if (dvd_open_first_part(dcr, OPEN_READ_WRITE) < 0) {
- Dmsg0(400, "truncate_dvd: Error while opening first part (2).\n");
- return false;
- }
-
return true;
}
-/* Checks if we can write on a non-blank DVD: meaning that it just have been
- * truncated (there is only one zero-sized file on the DVD, with the right
- * volume name).
+/*
+ * Checks if we can write on a non-blank DVD: meaning that it just have been
+ * truncated (there is only one zero-sized file on the DVD).
*
* Note! Normally if we can mount the device, which should be the case
* when we get here, it is not a blank DVD. Hence we check if
- * there is a zero length file with the right name, in which case
- * we allow it.
- * This seems terribly kludgie to me. KES
+ * if all files are of zero length (i.e. no data), in which case we allow it.
+ *
*/
bool check_can_write_on_non_blank_dvd(DCR *dcr)
{
DIR* dp;
struct dirent *entry, *result;
int name_max;
- int count = 0;
- bool matched = true;
struct stat filestat;
+ bool ok = true;
name_max = pathconf(".", _PC_NAME_MAX);
if (name_max < 1024) {
}
entry = (struct dirent *)malloc(sizeof(struct dirent) + name_max + 1000);
- while (1) {
+ for ( ;; ) {
if ((readdir_r(dp, entry, &result) != 0) || (result == NULL)) {
dev->dev_errno = EIO;
Dmsg2(129, "check_can_write_on_non_blank_dvd: no more files in dir %s (dev=%s)\n",
} else {
Dmsg2(99, "check_can_write_on_non_blank_dvd: found %s (versus %s)\n",
result->d_name, dev->VolCatInfo.VolCatName);
- if (strcmp(result->d_name, dev->VolCatInfo.VolCatName) == 0) {
- /* Found the file, checking it is empty */
+ if (strcmp(result->d_name, ".") && strcmp(result->d_name, "..") &&
+ strcmp(result->d_name, ".keep")) {
+ /* Found a file, checking it is empty */
POOL_MEM filename(PM_FNAME);
pm_strcpy(filename, dev->device->mount_point);
if (filename.c_str()[strlen(filename.c_str())-1] != '/') {
pm_strcat(filename, "/");
}
- pm_strcat(filename, dev->VolCatInfo.VolCatName);
+ pm_strcat(filename, result->d_name);
if (stat(filename.c_str(), &filestat) < 0) {
berrno be;
dev->dev_errno = errno;
Dmsg2(29, "check_can_write_on_non_blank_dvd: cannot stat file (file=%s), ERR=%s\n",
filename.c_str(), be.strerror());
- return false;
+ ok = false;
+ break;
}
Dmsg2(99, "check_can_write_on_non_blank_dvd: size of %s is %lld\n",
filename.c_str(), filestat.st_size);
- matched = filestat.st_size == 0;
+ if (filestat.st_size != 0) {
+ ok = false;
+ break;
+ }
}
}
- count++;
}
free(entry);
closedir(dp);
- if (count > 3) {
- /* There are more than 3 files (., .., and the volume file) */
- Dmsg1(29, "Cannot write on blank DVD too many files %d greater than 3\n", count);
- return false;
- }
-
- Dmsg2(29, "OK can_write_on_non_blank_dvd: got %d files in the mount point (matched=%d)\n", count, matched);
- return matched;
+ Dmsg1(29, "OK can_write_on_non_blank_dvd: OK=%d\n", ok);
+ return ok;
}
/*
* This routine should be used only when labeling a blank tape.
*/
bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
- const char *PoolName, bool dvdnow)
+ const char *PoolName, bool relabel, bool dvdnow)
{
DEVICE *dev = dcr->dev;
Dmsg0(99, "write_volume_label()\n");
empty_block(dcr->block);
+ /* If relabeling, truncate the device */
+ if (relabel && !dev->truncate(dcr)) {
+ goto bail_out;
+ }
+
+ if (relabel) {
+ dev->close_part(dcr); /* make sure closed for rename */
+ }
+
+ /* Set the new filename for open, ... */
+ bstrncpy(dev->VolCatInfo.VolCatName, VolName, sizeof(dev->VolCatInfo.VolCatName));
+ bstrncpy(dcr->VolCatInfo.VolCatName, VolName, sizeof(dcr->VolCatInfo.VolCatName));
+ Dmsg1(150, "New VolName=%s\n", VolName);
if (dev->open(dcr, OPEN_READ_WRITE) < 0) {
/* If device is not tape, attempt to create it */
if (dev->is_tape() || dev->open(dcr, CREATE_READ_WRITE) < 0) {
/* Now commit block to DVD if we should write now */
if (dev->is_dvd() && dvdnow) {
+ Dmsg1(150, "New VolName=%s\n", dev->VolCatInfo.VolCatName);
if (!dvd_write_part(dcr)) {
Dmsg2(30, "Bad DVD write on %s: ERR=%s\n", dev->print_name(), dev->bstrerror());
goto bail_out;
Dmsg0(150, "Create volume label\n");
/* Create a new Volume label and write it to the device */
if (!write_new_volume_label_to_dev(dcr, dcr->VolumeName,
- dcr->pool_name, false /* defer DVD label */)) {
+ dcr->pool_name, false, /* no relabel */ false /* defer DVD label */)) {
Dmsg0(150, "!write_vol_label\n");
mark_volume_in_error(dcr);
return try_next_vol;
int read_dvd_volume_label(DCR *dcr, bool write);
void create_session_label(DCR *dcr, DEV_RECORD *rec, int label);
void create_volume_label(DEVICE *dev, const char *VolName, const char *PoolName, bool dvdnow);
-bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName, const char *PoolName, bool dvdnow);
+bool write_new_volume_label_to_dev(DCR *dcr, const char *VolName,
+ const char *PoolName, bool relabel, bool dvdnow);
#define ANSI_VOL_LABEL 0
#define ANSI_EOF_LABEL 1
#define ANSI_EOV_LABEL 2
} else if (dev->at_eof()) {
if (verbose) {
- char dvdpart[100];
+ char *fp;
+ uint32_t fp_num;
if (dev->is_dvd()) {
- bsnprintf(dvdpart, sizeof(dvdpart), _("part %d "), dev->part);
+ fp = _("part");
+ fp_num = dev->part;
} else {
- dvdpart[0] = 0;
+ fp = _("file");
+ fp_num = dev->file;
}
- Jmsg(jcr, M_INFO, 0, _("End of file %u %son device %s, Volume \"%s\"\n"),
- dev->file, dvdpart, dev->print_name(), dcr->VolumeName);
+ Jmsg(jcr, M_INFO, 0, _("End of %s %u on device %s, Volume \"%s\"\n"),
+ fp, fp_num, dev->print_name(), dcr->VolumeName);
}
Dmsg3(200, "End of file %u on device %s, Volume \"%s\"\n",
dev->file, dev->print_name(), dcr->VolumeName);
#undef VERSION
#define VERSION "1.39.23"
-#define BDATE "15 September 2006"
-#define LSMDATE "15Sep06"
+#define BDATE "16 September 2006"
+#define LSMDATE "16Sep06"
#define BYEAR "2006" /* year for copyright messages in progs */
/* Debug flags */
Technical notes on version 1.39
General:
+16Sep06
+kes Correct a test in block.c that prevented restore of a DVD from
+ looking at the last part in the spool directory.
+kes Make some error messages clearer mostly by using the word DVD
+ in the message. Improve infor message in read_record for DVDs.
+kes Remove DVD kludges in dircmd.c label/relabel.
+kes Move the dvd relabel code from dircmd.c into
+ write_new_volume_label_to_dvd() adding a relabel argument.
+kes Rewrite the truncate_dvd() code to be much simpler and
+ more logical. First blow away any spool part, then create a
+ new empty part and write to the DVD.
+kes Rewrite the can_write_on_non_blank_dvd() code making it
+ only ensure that no valid data is on the DVD -- i.e. it
+ can be overwritten.
15Sep06
kes Minor Makefile fixes.
kes Put attach_dcr_to_dev in a subroutine.