acquire.o mount.o record.o stored_conf.o
BLSOBJS = bls.o block.o device.o dev.o label.o match_bsr.o \
- acquire.o mount.o parse_bsr.o record.o butil.o
+ acquire.o mount.o parse_bsr.o record.o butil.o \
+ read_record.o
BEXTOBJS = bextract.o block.o device.o dev.o label.o record.o \
- acquire.o mount.o match_bsr.o parse_bsr.o butil.o
+ acquire.o mount.o match_bsr.o parse_bsr.o butil.o \
+ read_record.o
SCNOBJS = bscan.o block.o device.o dev.o label.o \
acquire.o mount.o record.o match_bsr.o parse_bsr.o \
- butil.o
+ butil.o read_record.o
* the device remains open.
*
*/
-int release_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
+int release_device(JCR *jcr, DEVICE *dev)
{
P(dev->mutex);
Dmsg1(100, "release_device device is %s\n", dev_is_tape(dev)?"tape":"disk");
}
/* Release the device */
- if (!release_device(jcr, dev, block)) {
+ if (!release_device(jcr, dev)) {
Pmsg0(000, "Error in release_device\n");
ok = FALSE;
}
#endif
-static void do_extract(char *fname, char *prefix);
-static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec);
+static void do_extract(char *fname);
+static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec);
static DEVICE *dev = NULL;
static int ofd = -1;
-
static JCR *jcr;
static FF_PKT my_ff;
static FF_PKT *ff = &my_ff;
-
static BSR *bsr = NULL;
-
-static DEV_RECORD *rec;
static DEV_BLOCK *block;
+static int extract = FALSE;
+static long record_file_index;
+static long total = 0;
+static POOLMEM *fname; /* original file name */
+static POOLMEM *ofile; /* output name with prefix */
+static POOLMEM *lname; /* link name */
+static char *where;
+static int wherelen; /* prefix length */
+static uint32_t num_files = 0;
+static struct stat statp;
+static uint32_t compress_buf_size = 70000;
+static POOLMEM *compress_buf;
+static int type;
static void usage()
{
add_fname_to_include_list(ff, 0, "/"); /* include everything */
}
-
- do_extract(argv[0], argv[1]);
+ where = argv[1];
+ do_extract(argv[0]);
if (bsr) {
free_bsr(bsr);
return 0;
}
-/*
- * Device got an error, attempt to analyse it
- */
-static void display_error_status()
+static void do_extract(char *devname)
{
- uint32_t status;
-
- Emsg0(M_ERROR, 0, dev->errmsg);
- status_dev(dev, &status);
- Dmsg1(20, "Device status: %x\n", status);
- if (status & MT_EOD)
- Emsg0(M_ERROR_TERM, 0, "Unexpected End of Data\n");
- else if (status & MT_EOT)
- Emsg0(M_ERROR_TERM, 0, "Unexpected End of Tape\n");
- else if (status & MT_EOF)
- Emsg0(M_ERROR_TERM, 0, "Unexpected End of File\n");
- else if (status & MT_DR_OPEN)
- Emsg0(M_ERROR_TERM, 0, "Tape Door is Open\n");
- else if (!(status & MT_ONLINE))
- Emsg0(M_ERROR_TERM, 0, "Unexpected Tape is Off-line\n");
- else
- Emsg2(M_ERROR_TERM, 0, "Read error on Record Header %s: %s\n", dev_name(dev), strerror(errno));
-}
-
-
-static void do_extract(char *devname, char *where)
-{
- struct stat statp;
- int extract = FALSE;
- int type;
- long record_file_index;
- long total = 0;
- POOLMEM *fname; /* original file name */
- POOLMEM *ofile; /* output name with prefix */
- POOLMEM *lname; /* link name */
- int wherelen; /* prefix length */
- SESSION_LABEL sessrec;
- uint32_t num_files = 0;
jcr = setup_jcr("bextract", devname, bsr);
dev = setup_to_read_device(jcr);
ofile = get_pool_memory(PM_FNAME);
lname = get_pool_memory(PM_FNAME);
- block = new_block(dev);
- rec = new_record();
- free_pool_memory(rec->data);
- rec->data = get_memory(70000); /* get a big block for reading */
- uint32_t compress_buf_size = 70000;
- POOLMEM *compress_buf = get_memory(compress_buf_size);
- for ( ;; ) {
- if (!read_block_from_device(dev, block)) {
- Dmsg1(500, "Main read record failed. rem=%d\n", rec->remainder);
- if (dev->state & ST_EOT) {
- DEV_RECORD *record;
- if (!mount_next_read_volume(jcr, dev, block)) {
- break;
- }
- record = new_record();
- read_block_from_device(dev, block);
- read_record_from_block(block, record);
- get_session_record(dev, record, &sessrec);
- free_record(record);
- goto next_record;
- }
- if (dev->state & ST_EOF) {
- continue; /* try again */
- }
- if (dev->state & ST_SHORT) {
- continue;
- }
- display_error_status();
- }
+ compress_buf = get_memory(compress_buf_size);
-next_record:
- for (rec->state=0; !is_block_empty(rec); ) {
- if (!read_record_from_block(block, rec)) {
- break;
- }
+ read_records(jcr, dev, record_cb, mount_next_read_volume);
+ /* If output file is still open, it was the last one in the
+ * archive since we just hit an end of file, so close the file.
+ */
+ if (ofd >= 0) {
+ close(ofd);
+ set_statp(jcr, fname, ofile, lname, type, &statp);
+ }
+ release_device(jcr, dev);
- if (rec->FileIndex == EOM_LABEL) { /* end of tape? */
- Dmsg0(40, "Get EOM LABEL\n");
- rec->remainder = 0;
- break; /* yes, get out */
- }
+ free_pool_memory(fname);
+ free_pool_memory(ofile);
+ free_pool_memory(lname);
+ free_pool_memory(compress_buf);
+ term_dev(dev);
+ free_jcr(jcr);
+ printf("%u files restored.\n", num_files);
+ return;
+}
+
+/*
+ * Called here for each record from read_records()
+ */
+static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
+{
+ if (rec->FileIndex < 0) {
+ return; /* we don't want labels */
+ }
- /* Some sort of label? */
- if (rec->FileIndex < 0) {
- get_session_record(dev, rec, &sessrec);
- continue;
- } /* end if label record */
+ /* File Attributes stream */
+ if (rec->Stream == STREAM_UNIX_ATTRIBUTES) {
+ char *ap, *lp, *fp;
- /* Is this the file we want? */
- if (bsr && !match_bsr(bsr, rec, &dev->VolHdr, &sessrec)) {
- rec->remainder = 0;
- continue;
- }
- if (is_partial_record(rec)) {
- break;
+ /* If extracting, it was from previous stream, so
+ * close the output file.
+ */
+ if (extract) {
+ if (ofd < 0) {
+ Emsg0(M_ERROR_TERM, 0, "Logic error output file should be open\n");
}
+ close(ofd);
+ ofd = -1;
+ extract = FALSE;
+ set_statp(jcr, fname, ofile, lname, type, &statp);
+ }
- /* File Attributes stream */
- if (rec->Stream == STREAM_UNIX_ATTRIBUTES) {
- char *ap, *lp, *fp;
+ if (sizeof_pool_memory(fname) < rec->data_len) {
+ fname = realloc_pool_memory(fname, rec->data_len + 1);
+ }
+ if (sizeof_pool_memory(ofile) < rec->data_len + wherelen + 1) {
+ ofile = realloc_pool_memory(ofile, rec->data_len + wherelen + 1);
+ }
+ if (sizeof_pool_memory(lname) < rec->data_len) {
+ lname = realloc_pool_memory(lname, rec->data_len + wherelen + 1);
+ }
+ *fname = 0;
+ *lname = 0;
+
+ /*
+ * An Attributes record consists of:
+ * File_index
+ * Type (FT_types)
+ * Filename
+ * Attributes
+ * Link name (if file linked i.e. FT_LNK)
+ *
+ */
+ sscanf(rec->data, "%ld %d", &record_file_index, &type);
+ if (record_file_index != rec->FileIndex)
+ Emsg2(M_ERROR_TERM, 0, "Record header file index %ld not equal record index %ld\n",
+ rec->FileIndex, record_file_index);
+ ap = rec->data;
+ while (*ap++ != ' ') /* skip record file index */
+ ;
+ while (*ap++ != ' ') /* skip type */
+ ;
+ /* Save filename and position to attributes */
+ fp = fname;
+ while (*ap != 0) {
+ *fp++ = *ap++;
+ }
+ *fp = *ap++; /* terminate filename & point to attribs */
- /* If extracting, it was from previous stream, so
- * close the output file.
- */
- if (extract) {
- if (ofd < 0) {
- Emsg0(M_ERROR_TERM, 0, "Logic error output file should be open\n");
- }
- close(ofd);
- ofd = -1;
- extract = FALSE;
- set_statp(jcr, fname, ofile, lname, type, &statp);
- }
+ /* Skip to Link name */
+ if (type == FT_LNK || type == FT_LNKSAVED) {
+ lp = ap;
+ while (*lp++ != 0) {
+ ;
+ }
+ } else {
+ lp = "";
+ }
- if (sizeof_pool_memory(fname) < rec->data_len) {
- fname = realloc_pool_memory(fname, rec->data_len + 1);
- }
- if (sizeof_pool_memory(ofile) < rec->data_len + wherelen + 1) {
- ofile = realloc_pool_memory(ofile, rec->data_len + wherelen + 1);
- }
- if (sizeof_pool_memory(lname) < rec->data_len) {
- lname = realloc_pool_memory(lname, rec->data_len + wherelen + 1);
- }
- *fname = 0;
- *lname = 0;
-
- /*
- * An Attributes record consists of:
- * File_index
- * Type (FT_types)
- * Filename
- * Attributes
- * Link name (if file linked i.e. FT_LNK)
- *
- */
- sscanf(rec->data, "%ld %d", &record_file_index, &type);
- if (record_file_index != rec->FileIndex)
- Emsg2(M_ERROR_TERM, 0, "Record header file index %ld not equal record index %ld\n",
- rec->FileIndex, record_file_index);
- ap = rec->data;
- while (*ap++ != ' ') /* skip record file index */
- ;
- while (*ap++ != ' ') /* skip type */
- ;
- /* Save filename and position to attributes */
- fp = fname;
- while (*ap != 0) {
- *fp++ = *ap++;
+
+ if (file_is_included(ff, fname) && !file_is_excluded(ff, fname)) {
+
+ decode_stat(ap, &statp);
+ /*
+ * Prepend the where directory so that the
+ * files are put where the user wants.
+ *
+ * We do a little jig here to handle Win32 files with
+ * a drive letter.
+ * If where is null and we are running on a win32 client,
+ * change nothing.
+ * Otherwise, if the second character of the filename is a
+ * colon (:), change it into a slash (/) -- this creates
+ * a reasonable pathname on most systems.
+ */
+ if (where[0] == 0 && win32_client) {
+ strcpy(ofile, fname);
+ strcpy(lname, lp);
+ } else {
+ strcpy(ofile, where);
+ if (fname[1] == ':') {
+ fname[1] = '/';
+ strcat(ofile, fname);
+ fname[1] = ':';
+ } else {
+ strcat(ofile, fname);
}
- *fp = *ap++; /* terminate filename & point to attribs */
-
- /* Skip to Link name */
+ /* Fixup link name */
if (type == FT_LNK || type == FT_LNKSAVED) {
- lp = ap;
- while (*lp++ != 0) {
- ;
+ if (lp[0] == '/') { /* if absolute path */
+ strcpy(lname, where);
+ }
+ /* ***FIXME**** we shouldn't have links on Windoz */
+ if (lp[1] == ':') {
+ lp[1] = '/';
+ strcat(lname, lp);
+ lp[1] = ':';
+ } else {
+ strcat(lname, lp);
}
- } else {
- lp = "";
}
+ }
-
- if (file_is_included(ff, fname) && !file_is_excluded(ff, fname)) {
-
- decode_stat(ap, &statp);
- /*
- * Prepend the where directory so that the
- * files are put where the user wants.
- *
- * We do a little jig here to handle Win32 files with
- * a drive letter.
- * If where is null and we are running on a win32 client,
- * change nothing.
- * Otherwise, if the second character of the filename is a
- * colon (:), change it into a slash (/) -- this creates
- * a reasonable pathname on most systems.
- */
- if (where[0] == 0 && win32_client) {
- strcpy(ofile, fname);
- strcpy(lname, lp);
- } else {
- strcpy(ofile, where);
- if (fname[1] == ':') {
- fname[1] = '/';
- strcat(ofile, fname);
- fname[1] = ':';
- } else {
- strcat(ofile, fname);
- }
- /* Fixup link name */
- if (type == FT_LNK || type == FT_LNKSAVED) {
- if (lp[0] == '/') { /* if absolute path */
- strcpy(lname, where);
- }
- /* ***FIXME**** we shouldn't have links on Windoz */
- if (lp[1] == ':') {
- lp[1] = '/';
- strcat(lname, lp);
- lp[1] = ':';
- } else {
- strcat(lname, lp);
- }
- }
- }
+ /* Pmsg1(000, "Restoring: %s\n", ofile); */
- /* Pmsg1(000, "Restoring: %s\n", ofile); */
+ extract = create_file(jcr, fname, ofile, lname, type, &statp, &ofd);
+ num_files++;
- extract = create_file(jcr, fname, ofile, lname, type, &statp, &ofd);
- num_files++;
+ if (extract) {
+ print_ls_output(ofile, lname, type, &statp);
+ }
+ }
- if (extract) {
- print_ls_output(ofile, lname, type, &statp);
- }
- }
+ /* Data stream and extracting */
+ } else if (rec->Stream == STREAM_FILE_DATA) {
+ if (extract) {
+ total += rec->data_len;
+ Dmsg2(8, "Write %ld bytes, total=%ld\n", rec->data_len, total);
+ if ((uint32_t)write(ofd, rec->data, rec->data_len) != rec->data_len) {
+ Emsg1(M_ERROR_TERM, 0, "Write error: %s\n", strerror(errno));
+ }
+ }
- /* Data stream and extracting */
- } else if (rec->Stream == STREAM_FILE_DATA) {
- if (extract) {
- total += rec->data_len;
- Dmsg2(8, "Write %ld bytes, total=%ld\n", rec->data_len, total);
- if ((uint32_t)write(ofd, rec->data, rec->data_len) != rec->data_len) {
- Emsg1(M_ERROR_TERM, 0, "Write error: %s\n", strerror(errno));
- }
- }
-
- } else if (rec->Stream == STREAM_GZIP_DATA) {
+ } else if (rec->Stream == STREAM_GZIP_DATA) {
#ifdef HAVE_LIBZ
- if (extract) {
- uLongf compress_len;
+ if (extract) {
+ uLongf compress_len;
- compress_len = compress_buf_size;
- if (uncompress((Bytef *)compress_buf, &compress_len,
- (const Bytef *)rec->data, (uLong)rec->data_len) != Z_OK) {
- Emsg0(M_ERROR_TERM, 0, _("Uncompression error.\n"));
- }
+ compress_len = compress_buf_size;
+ if (uncompress((Bytef *)compress_buf, &compress_len,
+ (const Bytef *)rec->data, (uLong)rec->data_len) != Z_OK) {
+ Emsg0(M_ERROR_TERM, 0, _("Uncompression error.\n"));
+ }
- Dmsg2(100, "Write uncompressed %d bytes, total before write=%d\n", compress_len, total);
- if ((uLongf)write(ofd, compress_buf, (size_t)compress_len) != compress_len) {
- Pmsg0(0, "===Write error===\n");
- Emsg2(M_ERROR_TERM, 0, "Write error on %s: %s\n", ofile, strerror(errno));
- }
- total += compress_len;
- Dmsg2(100, "Compress len=%d uncompressed=%d\n", rec->data_len,
- compress_len);
- }
+ Dmsg2(100, "Write uncompressed %d bytes, total before write=%d\n", compress_len, total);
+ if ((uLongf)write(ofd, compress_buf, (size_t)compress_len) != compress_len) {
+ Pmsg0(0, "===Write error===\n");
+ Emsg2(M_ERROR_TERM, 0, "Write error on %s: %s\n", ofile, strerror(errno));
+ }
+ total += compress_len;
+ Dmsg2(100, "Compress len=%d uncompressed=%d\n", rec->data_len,
+ compress_len);
+ }
#else
- if (extract) {
- Emsg0(M_ERROR_TERM, 0, "GZIP data stream found, but GZIP not configured!\n");
- }
+ if (extract) {
+ Emsg0(M_ERROR_TERM, 0, "GZIP data stream found, but GZIP not configured!\n");
+ }
#endif
- /* If extracting, wierd stream (not 1 or 2), close output file anyway */
- } else if (extract) {
- if (ofd < 0) {
- Emsg0(M_ERROR_TERM, 0, "Logic error output file should be open\n");
- }
- close(ofd);
- ofd = -1;
- extract = FALSE;
- set_statp(jcr, fname, ofile, lname, type, &statp);
- } else if (rec->Stream != STREAM_MD5_SIGNATURE) {
- Pmsg2(0, "None of above!!! stream=%d data=%s\n", rec->Stream, rec->data);
- }
+ /* If extracting, wierd stream (not 1 or 2), close output file anyway */
+ } else if (extract) {
+ if (ofd < 0) {
+ Emsg0(M_ERROR_TERM, 0, "Logic error output file should be open\n");
}
- }
-
-
- /* If output file is still open, it was the last one in the
- * archive since we just hit an end of file, so close the file.
- */
- if (ofd >= 0) {
close(ofd);
+ ofd = -1;
+ extract = FALSE;
set_statp(jcr, fname, ofile, lname, type, &statp);
+ } else if (rec->Stream != STREAM_MD5_SIGNATURE) {
+ Pmsg2(0, "None of above!!! stream=%d data=%s\n", rec->Stream, rec->data);
}
- release_device(jcr, dev, block);
-
- free_pool_memory(fname);
- free_pool_memory(ofile);
- free_pool_memory(lname);
- free_pool_memory(compress_buf);
- term_dev(dev);
- free_block(block);
- free_record(rec);
- free_jcr(jcr);
- printf("%u files restored.\n", num_files);
- return;
}
-static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec)
-{
- char *rtype;
- memset(sessrec, 0, sizeof(sessrec));
- switch (rec->FileIndex) {
- case PRE_LABEL:
- rtype = "Fresh Volume Label";
- break;
- case VOL_LABEL:
- rtype = "Volume Label";
- unser_volume_label(dev, rec);
- break;
- case SOS_LABEL:
- rtype = "Begin Session";
- unser_session_label(sessrec, rec);
- break;
- case EOS_LABEL:
- rtype = "End Session";
- break;
- case EOM_LABEL:
- rtype = "End of Media";
- break;
- default:
- rtype = "Unknown";
- break;
- }
- Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n",
- rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
-}
+
+
/* Dummies to replace askdir.c */
int dir_get_volume_info(JCR *jcr) { return 1;}
static void do_blocks(char *infname);
static void do_jobs(char *infname);
static void do_ls(char *fname);
-static void do_close();
+static void do_close(JCR *jcr);
static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec);
+static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec);
static DEVICE *dev;
static int default_tape = FALSE;
static DEV_BLOCK *block;
static JCR *jcr;
static SESSION_LABEL sessrec;
-
+static uint32_t num_files = 0;
+static long record_file_index;
extern char BaculaId[];
exit(1);
}
-static char *rec_state_to_str(DEV_RECORD *rec)
-{
- static char buf[200];
- buf[0] = 0;
- if (rec->state & REC_NO_HEADER) {
- strcat(buf, "Nohdr,");
- }
- if (is_partial_record(rec)) {
- strcat(buf, "partial,");
- }
- if (rec->state & REC_BLOCK_EMPTY) {
- strcat(buf, "empty,");
- }
- if (rec->state & REC_NO_MATCH) {
- strcat(buf, "Nomatch,");
- }
- if (rec->state & REC_CONTINUATION) {
- strcat(buf, "cont,");
- }
- if (buf[0]) {
- buf[strlen(buf)-1] = 0;
- }
- return buf;
-}
-
-
int main (int argc, char *argv[])
{
}
rec = new_record();
block = new_block(dev);
+ /*
+ * Assume that we have already read the volume label.
+ * If on second or subsequent volume, adjust buffer pointer
+ */
+ if (dev->VolHdr.PrevVolName[0] != 0) { /* second volume */
+ Pmsg1(0, "\n\
+Warning, this Volume is a continuation of Volume %s\n",
+ dev->VolHdr.PrevVolName);
+ }
+
if (list_blocks) {
do_blocks(argv[i]);
} else if (list_jobs) {
} else {
do_ls(argv[i]);
}
- do_close();
+ do_close(jcr);
}
if (bsr) {
free_bsr(bsr);
}
-static void do_close()
+static void do_close(JCR *jcr)
{
+ release_device(jcr, dev);
term_dev(dev);
free_record(rec);
free_block(block);
}
-/*
- * Device got an error, attempt to analyse it
- */
-static void display_error_status()
-{
- uint32_t status;
-
- Emsg0(M_ERROR, 0, dev->errmsg);
- status_dev(dev, &status);
- Dmsg1(20, "Device status: %x\n", status);
- if (status & MT_EOD)
- Emsg0(M_ERROR_TERM, 0, "Unexpected End of Data\n");
- else if (status & MT_EOT)
- Emsg0(M_ERROR_TERM, 0, "Unexpected End of Tape\n");
- else if (status & MT_EOF)
- Emsg0(M_ERROR_TERM, 0, "Unexpected End of File\n");
- else if (status & MT_DR_OPEN)
- Emsg0(M_ERROR_TERM, 0, "Tape Door is Open\n");
- else if (!(status & MT_ONLINE))
- Emsg0(M_ERROR_TERM, 0, "Unexpected Tape is Off-line\n");
- else
- Emsg2(M_ERROR_TERM, 0, "Read error on Record Header %s: %s\n", dev_name(dev), strerror(errno));
-}
-
-
/* List just block information */
static void do_blocks(char *infname)
{
dump_volume_label(dev);
- /* Assume that we have already read the volume label.
- * If on second or subsequent volume, adjust buffer pointer
- */
- if (dev->VolHdr.PrevVolName[0] != 0) { /* second volume */
- Pmsg1(0, "\n\
-Warning, this Volume is a continuation of Volume %s\n",
- dev->VolHdr.PrevVolName);
- }
-
if (verbose) {
rec = new_record();
}
Emsg0(M_INFO, 0, dev->errmsg);
continue;
}
- display_error_status();
+ display_error_status(dev);
break;
}
return;
}
+/*
+ * We are only looking for labels or in particula Job Session records
+ */
+static void jobs_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
+{
+ if (rec->FileIndex < 0) {
+ dump_label_record(dev, rec, verbose);
+ }
+ rec->remainder = 0;
+}
+
/* Do list job records */
static void do_jobs(char *infname)
{
+ read_records(jcr, dev, jobs_cb, mount_next_read_volume);
+}
- /* Assume that we have already read the volume label.
- * If on second or subsequent volume, adjust buffer pointer
- */
- if (dev->VolHdr.PrevVolName[0] != 0) { /* second volume */
- Pmsg1(0, "\n\
-Warning, this Volume is a continuation of Volume %s\n",
- dev->VolHdr.PrevVolName);
+/* Do an ls type listing of an archive */
+static void do_ls(char *infname)
+{
+ if (dump_label) {
+ dump_volume_label(dev);
+ return;
}
-
- for ( ;; ) {
- if (!read_block_from_device(dev, block)) {
- Dmsg0(20, "!read_block()\n");
- if (dev->state & ST_EOT) {
- DEV_RECORD *record;
- if (!mount_next_read_volume(jcr, dev, block)) {
- printf("Got EOF on device %s\n", dev_name(dev));
- break;
- }
- record = new_record();
- read_block_from_device(dev, block);
- read_record_from_block(block, record);
- get_session_record(dev, record, &sessrec);
- free_record(record);
- printf("Volume %s mounted.\n", jcr->VolumeName);
- continue;
- }
- if (dev->state & ST_EOF) {
- Emsg1(M_INFO, 0, "Got EOF on device %s\n", dev_name(dev));
- Dmsg0(20, "read_record got eof. try again\n");
- continue;
- }
- if (dev->state & ST_SHORT) {
- Pmsg0(000, "Got short block.\n");
- Emsg0(M_INFO, 0, dev->errmsg);
- continue;
- }
- display_error_status();
- break;
- }
- while (read_record_from_block(block, rec)) {
- if (debug_level >= 30) {
- Dmsg4(30, "VolSId=%ld FI=%s Strm=%s Size=%ld\n", rec->VolSessionId,
- FI_to_ascii(rec->FileIndex), stream_to_ascii(rec->Stream),
- rec->data_len);
- }
-
- /*
- * Check for End of File record (all zeros)
- * NOTE: this no longer exists
- */
- if (rec->VolSessionId == 0 && rec->VolSessionTime == 0) {
- Emsg0(M_ERROR_TERM, 0, "Zero VolSessionId and VolSessionTime. This shouldn't happen\n");
- }
-
- /*
- * Check for Start or End of Session Record
- *
- */
- if (rec->FileIndex < 0) {
- dump_label_record(dev, rec, verbose);
- continue;
- }
- }
- rec->remainder = 0;
- }
- return;
+ read_records(jcr, dev, record_cb, mount_next_read_volume);
}
-/* Do an ls type listing of an archive */
-static void do_ls(char *infname)
+/*
+ * Called here for each record from read_records()
+ */
+static void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec)
{
char fname[2000];
struct stat statp;
int type;
- long record_file_index;
- uint32_t num_files = 0;
- int record;
- if (dump_label) {
- dump_volume_label(dev);
+ if (rec->FileIndex < 0) {
+ get_session_record(dev, rec, &sessrec);
return;
}
-
- /* Assume that we have already read the volume label.
- * If on second or subsequent volume, adjust buffer pointer
- */
- if (dev->VolHdr.PrevVolName[0] != 0) { /* second volume */
- Pmsg1(0, "\n\
-Warning, this Volume is a continuation of Volume %s\n",
- dev->VolHdr.PrevVolName);
- }
-
- for ( ;; ) {
-
- if (!read_block_from_device(dev, block)) {
- Dmsg0(20, "!read_record()\n");
- if (dev->state & ST_EOT) {
- DEV_RECORD *record;
- Dmsg3(100, "EOT. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec),
- block->BlockNumber, rec->remainder);
- if (!mount_next_read_volume(jcr, dev, block)) {
- Dmsg3(100, "After mount next vol. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec),
- block->BlockNumber, rec->remainder);
- break;
- }
- Dmsg3(100, "After mount next vol. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec),
- block->BlockNumber, rec->remainder);
- record = new_record();
- read_block_from_device(dev, block);
- read_record_from_block(block, record);
- get_session_record(dev, record, &sessrec);
- free_record(record);
- goto next_record;
- }
- if (dev->state & ST_EOF) {
- Emsg1(M_INFO, 0, "Got EOF on device %s\n", dev_name(dev));
- Dmsg0(20, "read_record got eof. try again\n");
- continue;
- }
- if (dev->state & ST_SHORT) {
- Emsg0(M_INFO, 0, dev->errmsg);
- continue;
- }
- display_error_status();
- break;
+ /* File Attributes stream */
+ if (rec->Stream == STREAM_UNIX_ATTRIBUTES) {
+ char *ap, *fp;
+ sscanf(rec->data, "%ld %d", &record_file_index, &type);
+ if (record_file_index != rec->FileIndex) {
+ Emsg2(M_ERROR_TERM, 0, "Record header file index %ld not equal record index %ld\n",
+ rec->FileIndex, record_file_index);
}
- if (verbose) {
- Dmsg2(10, "Block: %d blen=%d\n", block->BlockNumber, block->block_len);
+ ap = rec->data;
+
+ while (*ap++ != ' ') /* skip record file index */
+ ;
+ while (*ap++ != ' ') /* skip type */
+ ;
+ /* Save filename and position to attributes */
+ fp = fname;
+ while (*ap != 0) {
+ *fp++ = *ap++;
}
-
-next_record:
- record = 0;
- for (rec->state=0; !is_block_empty(rec); ) {
- if (!read_record_from_block(block, rec)) {
- Dmsg3(10, "!read-break. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec),
- block->BlockNumber, rec->remainder);
- break;
- }
- Dmsg3(10, "read-OK. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec),
- block->BlockNumber, rec->remainder);
- /*
- * At this point, we have at least a record header.
- * Now decide if we want this record or not, but remember
- * before accessing the record, we may need to read again to
- * get all the data.
- */
- record++;
- if (verbose) {
- Dmsg6(30, "recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record,
- rec_state_to_str(rec), block->BlockNumber,
- rec->VolSessionId, rec->VolSessionTime, rec->FileIndex);
- }
- if (debug_level >= 30) {
- Dmsg4(30, "VolSId=%ld FI=%s Strm=%s Size=%ld\n", rec->VolSessionId,
- FI_to_ascii(rec->FileIndex), stream_to_ascii(rec->Stream),
- rec->data_len);
- }
-
- if (rec->FileIndex == EOM_LABEL) { /* end of tape? */
- Dmsg0(40, "Get EOM LABEL\n");
- rec->remainder = 0;
- break; /* yes, get out */
- }
-
- /* Some sort of label? */
- if (rec->FileIndex < 0) {
- get_session_record(dev, rec, &sessrec);
- continue;
- } /* end if label record */
-
- /*
- * Apply BSR filter
- */
- if (bsr && !match_bsr(bsr, rec, &dev->VolHdr, &sessrec)) {
- if (verbose) {
- Dmsg5(10, "BSR no match rec=%d block=%d SessId=%d SessTime=%d FI=%d\n",
- record, block->BlockNumber, rec->VolSessionId, rec->VolSessionTime,
- rec->FileIndex);
- }
- rec->remainder = 0;
- continue; /* we don't want record, read next one */
- }
- if (is_partial_record(rec)) {
- Dmsg6(10, "Partial, break. recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record,
- rec_state_to_str(rec), block->BlockNumber,
- rec->VolSessionId, rec->VolSessionTime, rec->FileIndex);
- break; /* read second part of record */
- }
-
- /* File Attributes stream */
- if (rec->Stream == STREAM_UNIX_ATTRIBUTES) {
- char *ap, *fp;
- sscanf(rec->data, "%ld %d", &record_file_index, &type);
- if (record_file_index != rec->FileIndex) {
- Emsg2(M_ERROR_TERM, 0, "Record header file index %ld not equal record index %ld\n",
- rec->FileIndex, record_file_index);
- }
- ap = rec->data;
-
- while (*ap++ != ' ') /* skip record file index */
- ;
- while (*ap++ != ' ') /* skip type */
- ;
- /* Save filename and position to attributes */
- fp = fname;
- while (*ap != 0) {
- *fp++ = *ap++;
- }
- *fp = *ap++; /* terminate filename & point to attribs */
-
- decode_stat(ap, &statp);
- /* Skip to link name */
- while (*ap++ != 0)
- ;
- if (file_is_included(&ff, fname) && !file_is_excluded(&ff, fname)) {
- print_ls_output(fname, ap, type, &statp);
- num_files++;
- }
- }
+ *fp = *ap++; /* terminate filename & point to attribs */
+
+ decode_stat(ap, &statp);
+ /* Skip to link name */
+ while (*ap++ != 0)
+ ;
+ if (file_is_included(&ff, fname) && !file_is_excluded(&ff, fname)) {
+ print_ls_output(fname, ap, type, &statp);
+ num_files++;
}
}
if (verbose) {
}
}
- release_device(jcr, dev, block);
+ release_device(jcr, dev);
free_pool_memory(fname);
free_pool_memory(ofile);
int acquire_device_for_append(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
int acquire_device_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
int ready_dev_for_read(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
-int release_device(JCR *jcr, DEVICE *dev, DEV_BLOCK *block);
+int release_device(JCR *jcr, DEVICE *dev);
/* From askdir.c */
int dir_get_volume_info(JCR *jcr);
void print_ls_output(char *fname, char *link, int type, struct stat *statp);
JCR *setup_jcr(char *name, char *device, BSR *bsr);
DEVICE *setup_to_read_device(JCR *jcr);
+void display_error_status(DEVICE *dev);
/* From dev.c */
int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec);
DEV_RECORD *new_record();
void free_record(DEV_RECORD *rec);
+
+/* From read_record.c */
+int read_records(JCR *jcr, DEVICE *dev,
+ void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec),
+ int mount_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block));
/* Send end of data to FD */
bnet_sig(ds, BNET_EOD);
- if (!release_device(jcr, dev, block)) {
+ if (!release_device(jcr, dev)) {
ok = FALSE;
}
free_pool_memory(hdr);
--- /dev/null
+/*
+ *
+ * This routine provides a routine that will handle all
+ * the gory little details of reading a record from a Bacula
+ * archive. It uses a callback to pass you each record in turn,
+ * as well as a callback for mounting the next tape. It takes
+ * care of reading blocks, applying the bsr, ...
+ *
+ * Version $Id$
+ */
+/*
+ Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 2 of
+ the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the Free
+ Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
+ MA 02111-1307, USA.
+
+ */
+
+#include "bacula.h"
+#include "stored.h"
+
+static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec);
+static char *rec_state_to_str(DEV_RECORD *rec);
+
+
+int read_records(JCR *jcr, DEVICE *dev,
+ void record_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block, DEV_RECORD *rec),
+ int mount_cb(JCR *jcr, DEVICE *dev, DEV_BLOCK *block))
+{
+ DEV_BLOCK *block;
+ DEV_RECORD *rec;
+ uint32_t record, num_files = 0;
+ int verbose = FALSE;
+ int ok = TRUE;
+ SESSION_LABEL sessrec;
+
+ block = new_block(dev);
+ rec = new_record();
+ for ( ;ok; ) {
+ if (job_cancelled(jcr)) {
+ ok = FALSE;
+ break;
+ }
+ if (!read_block_from_device(dev, block)) {
+ Dmsg0(20, "!read_record()\n");
+ if (dev->state & ST_EOT) {
+ DEV_RECORD *record;
+ Dmsg3(100, "EOT. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec),
+ block->BlockNumber, rec->remainder);
+ if (!mount_cb(jcr, dev, block)) {
+ Dmsg3(100, "After mount next vol. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec),
+ block->BlockNumber, rec->remainder);
+ ok = FALSE;
+ break;
+ }
+ Dmsg3(100, "After mount next vol. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec),
+ block->BlockNumber, rec->remainder);
+ record = new_record();
+ read_block_from_device(dev, block);
+ read_record_from_block(block, record);
+ get_session_record(dev, record, &sessrec);
+ record_cb(jcr, dev, block, record);
+ free_record(record);
+ goto next_record;
+ }
+ if (dev->state & ST_EOF) {
+ Emsg1(M_INFO, 0, "Got EOF on device %s\n", dev_name(dev));
+ Dmsg0(20, "read_record got eof. try again\n");
+ continue;
+ }
+ if (dev->state & ST_SHORT) {
+ Emsg0(M_INFO, 0, dev->errmsg);
+ continue;
+ }
+// display_error_status();
+ ok = FALSE;
+ break;
+ }
+ if (verbose) {
+ Dmsg2(10, "Block: %d blen=%d\n", block->BlockNumber, block->block_len);
+ }
+
+next_record:
+ record = 0;
+ for (rec->state=0; !is_block_empty(rec); ) {
+ if (!read_record_from_block(block, rec)) {
+ Dmsg3(10, "!read-break. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec),
+ block->BlockNumber, rec->remainder);
+ break;
+ }
+ Dmsg3(10, "read-OK. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec),
+ block->BlockNumber, rec->remainder);
+ /*
+ * At this point, we have at least a record header.
+ * Now decide if we want this record or not, but remember
+ * before accessing the record, we may need to read again to
+ * get all the data.
+ */
+ record++;
+ if (verbose) {
+ Dmsg6(30, "recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record,
+ rec_state_to_str(rec), block->BlockNumber,
+ rec->VolSessionId, rec->VolSessionTime, rec->FileIndex);
+ }
+ if (debug_level >= 30) {
+ Dmsg4(30, "VolSId=%ld FI=%s Strm=%s Size=%ld\n", rec->VolSessionId,
+ FI_to_ascii(rec->FileIndex), stream_to_ascii(rec->Stream),
+ rec->data_len);
+ }
+
+ if (rec->FileIndex == EOM_LABEL) { /* end of tape? */
+ Dmsg0(40, "Get EOM LABEL\n");
+ rec->remainder = 0;
+ break; /* yes, get out */
+ }
+
+ /* Some sort of label? */
+ if (rec->FileIndex < 0) {
+ get_session_record(dev, rec, &sessrec);
+ record_cb(jcr, dev, block, rec);
+ continue;
+ } /* end if label record */
+
+ /*
+ * Apply BSR filter
+ */
+ if (jcr->bsr && !match_bsr(jcr->bsr, rec, &dev->VolHdr, &sessrec)) {
+ if (verbose) {
+ Dmsg5(10, "BSR no match rec=%d block=%d SessId=%d SessTime=%d FI=%d\n",
+ record, block->BlockNumber, rec->VolSessionId, rec->VolSessionTime,
+ rec->FileIndex);
+ }
+ rec->remainder = 0;
+ continue; /* we don't want record, read next one */
+ }
+ if (is_partial_record(rec)) {
+ Dmsg6(10, "Partial, break. recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record,
+ rec_state_to_str(rec), block->BlockNumber,
+ rec->VolSessionId, rec->VolSessionTime, rec->FileIndex);
+ break; /* read second part of record */
+ }
+ record_cb(jcr, dev, block, rec);
+
+ }
+ }
+ if (verbose) {
+ printf("%u files found.\n", num_files);
+ }
+ free_record(rec);
+ free_block(block);
+ return ok;
+}
+
+
+static void get_session_record(DEVICE *dev, DEV_RECORD *rec, SESSION_LABEL *sessrec)
+{
+ char *rtype;
+ memset(sessrec, 0, sizeof(sessrec));
+ switch (rec->FileIndex) {
+ case PRE_LABEL:
+ rtype = "Fresh Volume Label";
+ break;
+ case VOL_LABEL:
+ rtype = "Volume Label";
+ unser_volume_label(dev, rec);
+ break;
+ case SOS_LABEL:
+ rtype = "Begin Session";
+ unser_session_label(sessrec, rec);
+ break;
+ case EOS_LABEL:
+ rtype = "End Session";
+ break;
+ case EOM_LABEL:
+ rtype = "End of Media";
+ break;
+ default:
+ rtype = "Unknown";
+ break;
+ }
+ Dmsg5(10, "%s Record: VolSessionId=%d VolSessionTime=%d JobId=%d DataLen=%d\n",
+ rtype, rec->VolSessionId, rec->VolSessionTime, rec->Stream, rec->data_len);
+}
+
+static char *rec_state_to_str(DEV_RECORD *rec)
+{
+ static char buf[200];
+ buf[0] = 0;
+ if (rec->state & REC_NO_HEADER) {
+ strcat(buf, "Nohdr,");
+ }
+ if (is_partial_record(rec)) {
+ strcat(buf, "partial,");
+ }
+ if (rec->state & REC_BLOCK_EMPTY) {
+ strcat(buf, "empty,");
+ }
+ if (rec->state & REC_NO_MATCH) {
+ strcat(buf, "Nomatch,");
+ }
+ if (rec->state & REC_CONTINUATION) {
+ strcat(buf, "cont,");
+ }
+ if (buf[0]) {
+ buf[strlen(buf)-1] = 0;
+ }
+ return buf;
+}
+