- Bug: if a job is manually scheduled to run later, it does not appear
in any status report and cannot be cancelled.
+==== Keeping track of deleted files ====
+ My "trick" for keeping track of deletions is the following.
+ Assuming the user turns on this option, after all the files
+ have been backed up, but before the job has terminated, the
+ FD will make a pass through all the files and send their
+ names to the DIR (*exactly* the same as what a Verify job
+ currently does). This will probably be done at the same
+ time the files are being sent to the SD avoiding a second
+ pass. The DIR will then compare that to what is stored in
+ the catalog. Any files in the catalog but not in what the
+ FD sent will receive a catalog File entry that indicates
+ that at that point in time the file was deleted.
+
+ During a restore, any file initially picked up by some
+ backup (Full, ...) then subsequently having a File entry
+ marked "delete" will be removed from the tree, so will not
+ be restored. If a file with the same name is later OK it
+ will be inserted in the tree -- this already happens. All
+ will be consistent except for possible changes during the
+ running of the FD.
+
+ Since I'm on the subject, some of you may be wondering what
+ the utility of the in memory tree is if you are going to
+ restore everything (at least it comes up from time to time
+ on the list). Well, it is still *very* useful because it
+ allows only the last item found for a particular filename
+ (full path) to be entered into the tree, and thus if a file
+ is backed up 10 times, only the last copy will be restored.
+ I recently (last Friday) restored a complete directory, and
+ the Full and all the Differential and Incremental backups
+ spanned 3 Volumes. The first Volume was not even mounted
+ because all the files had been updated and hence backed up
+ since the Full backup was made. In this case, the tree
+ saved me a *lot* of time.
+
+ Make sure this information is stored on the tape too so
+ that it can be restored directly from the tape.
+=====
+
Regression tests:
- Add Pool/Storage override regression test.
- Add delete JobId to regression.
}
#if defined (__digital__) && defined (__unix__)
- return fsf_dev(dev, dev->VolCatInfo.VolCatFiles);
+ return dev->fsf(dev->VolCatInfo.VolCatFiles);
#endif
Dmsg0(29, "eod_dev\n");
int file_num;
for (file_num=dev->file; !dev->at_eot(); file_num++) {
Dmsg0(200, "eod_dev: doing fsf 1\n");
- if (!fsf_dev(dev, 1)) {
- Dmsg0(200, "fsf_dev error.\n");
+ if (!dev->fsf(1)) {
+ Dmsg0(200, "fsf error.\n");
return false;
}
/*
*/
if (file_num == (int)dev->file) {
struct mtget mt_stat;
- Dmsg1(100, "fsf_dev did not advance from file %d\n", file_num);
+ Dmsg1(100, "fsf did not advance from file %d\n", file_num);
if (dev_get_os_pos(dev, &mt_stat)) {
Dmsg2(100, "Adjust file from %d to %d\n", dev->file , mt_stat.mt_fileno);
dev->set_ateof();
* Returns: true on success
* false on failure
*/
-bool
-fsf_dev(DEVICE *dev, int num)
+bool DEVICE::fsf(int num)
{
struct mtget mt_stat;
struct mtop mt_com;
int stat = 0;
- if (dev->fd < 0) {
- dev->dev_errno = EBADF;
- Mmsg0(dev->errmsg, _("Bad call to fsf_dev. Device not open\n"));
- Emsg0(M_FATAL, 0, dev->errmsg);
+ if (fd < 0) {
+ dev_errno = EBADF;
+ Mmsg0(errmsg, _("Bad call to fsf_dev. Device not open\n"));
+ Emsg0(M_FATAL, 0, errmsg);
return false;
}
- if (!dev->is_tape()) {
+ if (!is_tape()) {
return true;
}
- if (dev->state & ST_EOT) {
- dev->dev_errno = 0;
- Mmsg1(dev->errmsg, _("Device %s at End of Tape.\n"), dev->print_name());
+ if (at_eot()) {
+ dev_errno = 0;
+ Mmsg1(errmsg, _("Device %s at End of Tape.\n"), print_name());
return false;
}
- if (dev->state & ST_EOF) {
+ if (at_eof()) {
Dmsg0(200, "ST_EOF set on entry to FSF\n");
}
- Dmsg0(100, "fsf_dev\n");
- dev->block_num = 0;
+ Dmsg0(100, "fsf\n");
+ block_num = 0;
/*
* If Fast forward space file is set, then we
* use MTFSF to forward space and MTIOCGET
* the SCSI driver will ensure that we do not
* forward space past the end of the medium.
*/
- if (dev_cap(dev, CAP_FSF) && dev_cap(dev, CAP_MTIOCGET) && dev_cap(dev, CAP_FASTFSF)) {
+ if (dev_cap(this, CAP_FSF) && dev_cap(this, CAP_MTIOCGET) && dev_cap(this, CAP_FASTFSF)) {
mt_com.mt_op = MTFSF;
mt_com.mt_count = num;
- stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
- if (stat < 0 || !dev_get_os_pos(dev, &mt_stat)) {
+ stat = ioctl(fd, MTIOCTOP, (char *)&mt_com);
+ if (stat < 0 || !dev_get_os_pos(this, &mt_stat)) {
berrno be;
- dev->state |= ST_EOT;
+ set_eot();
Dmsg0(200, "Set ST_EOT\n");
- clrerror_dev(dev, MTFSF);
- Mmsg2(dev->errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"),
- dev->print_name(), be.strerror());
- Dmsg1(200, "%s", dev->errmsg);
+ clrerror_dev(this, MTFSF);
+ Mmsg2(errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"),
+ print_name(), be.strerror());
+ Dmsg1(200, "%s", errmsg);
return false;
}
Dmsg2(200, "fsf file=%d block=%d\n", mt_stat.mt_fileno, mt_stat.mt_blkno);
- dev->set_ateof();
- dev->file = mt_stat.mt_fileno;
+ set_ateof();
+ file = mt_stat.mt_fileno;
return true;
/*
* is the only way we can be sure that we don't read
* two consecutive EOF marks, which means End of Data.
*/
- } else if (dev_cap(dev, CAP_FSF)) {
+ } else if (dev_cap(this, CAP_FSF)) {
POOLMEM *rbuf;
int rbuf_len;
Dmsg0(200, "FSF has cap_fsf\n");
- if (dev->max_block_size == 0) {
+ if (max_block_size == 0) {
rbuf_len = DEFAULT_BLOCK_SIZE;
} else {
- rbuf_len = dev->max_block_size;
+ rbuf_len = max_block_size;
}
rbuf = get_memory(rbuf_len);
mt_com.mt_op = MTFSF;
mt_com.mt_count = 1;
- while (num-- && !(dev->state & ST_EOT)) {
+ while (num-- && !at_eot()) {
Dmsg0(100, "Doing read before fsf\n");
- if ((stat = read(dev->fd, (char *)rbuf, rbuf_len)) < 0) {
+ if ((stat = read(fd, (char *)rbuf, rbuf_len)) < 0) {
if (errno == ENOMEM) { /* tape record exceeds buf len */
stat = rbuf_len; /* This is OK */
} else {
berrno be;
- dev->state |= ST_EOT;
- clrerror_dev(dev, -1);
- Dmsg2(100, "Set ST_EOT read errno=%d. ERR=%s\n", dev->dev_errno,
+ set_eot();
+ clrerror_dev(this, -1);
+ Dmsg2(100, "Set ST_EOT read errno=%d. ERR=%s\n", dev_errno,
be.strerror());
- Mmsg2(dev->errmsg, _("read error on %s. ERR=%s.\n"),
- dev->print_name(), be.strerror());
- Dmsg1(100, "%s", dev->errmsg);
+ Mmsg2(errmsg, _("read error on %s. ERR=%s.\n"),
+ print_name(), be.strerror());
+ Dmsg1(100, "%s", errmsg);
break;
}
}
if (stat == 0) { /* EOF */
- update_pos_dev(dev);
- Dmsg1(100, "End of File mark from read. File=%d\n", dev->file+1);
+ update_pos_dev(this);
+ Dmsg1(100, "End of File mark from read. File=%d\n", file+1);
/* Two reads of zero means end of tape */
- if (dev->state & ST_EOF) {
- dev->state |= ST_EOT;
+ if (at_eof()) {
+ set_eot();
Dmsg0(100, "Set ST_EOT\n");
break;
} else {
- dev->set_ateof();
+ set_ateof();
continue;
}
} else { /* Got data */
- dev->state &= ~(ST_EOF|ST_EOT);
+ clear_eot();
+ clear_eof();
}
Dmsg0(100, "Doing MTFSF\n");
- stat = ioctl(dev->fd, MTIOCTOP, (char *)&mt_com);
+ stat = ioctl(fd, MTIOCTOP, (char *)&mt_com);
if (stat < 0) { /* error => EOT */
berrno be;
- dev->state |= ST_EOT;
+ set_eot();
Dmsg0(100, "Set ST_EOT\n");
- clrerror_dev(dev, MTFSF);
- Mmsg2(dev->errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"),
- dev->print_name(), be.strerror());
+ clrerror_dev(this, MTFSF);
+ Mmsg2(errmsg, _("ioctl MTFSF error on %s. ERR=%s.\n"),
+ print_name(), be.strerror());
Dmsg0(100, "Got < 0 for MTFSF\n");
- Dmsg1(100, "%s", dev->errmsg);
+ Dmsg1(100, "%s", errmsg);
} else {
- dev->set_ateof();
+ set_ateof();
}
}
free_memory(rbuf);
*/
} else {
Dmsg0(200, "Doing FSR for FSF\n");
- while (num-- && !(dev->state & ST_EOT)) {
- dev->fsr(INT32_MAX); /* returns -1 on EOF or EOT */
+ while (num-- && !at_eot()) {
+ fsr(INT32_MAX); /* returns -1 on EOF or EOT */
}
- if (dev->state & ST_EOT) {
- dev->dev_errno = 0;
- Mmsg1(dev->errmsg, _("Device %s at End of Tape.\n"), dev->print_name());
+ if (at_eot()) {
+ dev_errno = 0;
+ Mmsg1(errmsg, _("Device %s at End of Tape.\n"), print_name());
stat = -1;
} else {
stat = 0;
}
}
- update_pos_dev(dev);
+ update_pos_dev(this);
Dmsg1(200, "Return %d from FSF\n", stat);
- if (dev->state & ST_EOF)
+ if (at_eof())
Dmsg0(200, "ST_EOF set on exit FSF\n");
- if (dev->state & ST_EOT)
+ if (at_eot())
Dmsg0(200, "ST_EOT set on exit FSF\n");
- Dmsg1(200, "Return from FSF file=%d\n", dev->file);
+ Dmsg1(200, "Return from FSF file=%d\n", file);
return stat == 0;
}
}
if (file > dev->file) {
Dmsg1(100, "fsf %d\n", file-dev->file);
- if (!fsf_dev(dev, file-dev->file)) {
+ if (!dev->fsf(file-dev->file)) {
Dmsg1(100, "fsf failed! ERR=%s\n", strerror_dev(dev));
return false;
}
Dmsg0(100, "bsf_dev 1\n");
bsf_dev(dev, 1);
Dmsg0(100, "fsf_dev 1\n");
- fsf_dev(dev, 1);
+ dev->fsf(1);
Dmsg2(100, "wanted_blk=%d at_blk=%d\n", block, dev->block_num);
}
if (dev_cap(dev, CAP_POSITIONBLOCKS) && block > dev->block_num) {