1 Index: src/stored/faketape.c
2 ===================================================================
3 --- src/stored/faketape.c (revision 7097)
4 +++ src/stored/faketape.c (working copy)
6 int faketape::tape_op(struct mtop *mt_com)
9 + int count = mt_com->mt_count;
16 case MTFSF: /* Forward space over mt_count filemarks. */
17 - result = fsf(mt_com->mt_count);
20 + } while (--count > 0 && result == 0);
23 case MTBSF: /* Backward space over mt_count filemarks. */
24 - result = bsf(mt_com->mt_count);
27 + } while (--count > 0 && result == 0);
30 case MTFSR: /* Forward space over mt_count records (tape blocks). */
34 case MTWEOF: /* Write mt_count filemarks. */
35 - result = weof(mt_com->mt_count);
38 + } while (result == 0 && --count > 0);
41 case MTREW: /* Rewind. */
42 Dmsg0(dbglevel, "rewind faketape\n");
44 atEOF = atEOD = false;
49 + lseek(fd, 0, SEEK_SET);
53 case MTOFFL: /* put tape offline */
57 case MTEOM:/* Go to the end of the recorded media (for appending files). */
59 + lseek(fd, next_FM, SEEK_SET);
60 + if (read_next_fm(true)) {
65 + while (::read(fd, &l, sizeof(l)) > 0) {
67 + lseek(fd, l, SEEK_CUR);
71 + Dmsg0(dbglevel, "skip 1 block\n");
87 - current_file = last_file;
92 case MTERASE: /* not used by bacula */
98 + lseek(fd, 0, SEEK_SET);
119 if (!atEOD) { /* if not at the end of the data */
124 needEOF = true; /* next operation need EOF mark */
126 -// if ((count + file_size) > max_size) {
128 -// "EOT writing only %i of %i requested\n",
129 -// max_size - file_size, count);
130 -// count = max_size - file_size;
134 uint32_t size = count;
135 ::write(fd, &size, sizeof(uint32_t));
136 nb = ::write(fd, buffer, count);
137 @@ -484,43 +495,67 @@
141 -int faketape::weof(int count)
143 + * +---+---------+---+------------------+---+-------------------+
144 + * |00N| DATA |0LN| DATA |0LC| DATA |
145 + * +---+---------+---+------------------+---+-------------------+
148 + * L : Last FileMark offset
149 + * N : Next FileMark offset
150 + * C : Current FileMark Offset
152 +int faketape::weof()
155 ASSERT(current_file >= 0);
156 Dmsg3(dbglevel, "Writing EOF %i:%i last=%i\n",
157 current_file, current_block,last_file);
169 - truncate_file(); /* nothing after this point */
171 + truncate_file(); /* nothing after this point */
174 + cur_FM = lseek(fd, 0, SEEK_CUR); // current position
176 + /* update previous next_FM */
177 + lseek(fd, last_FM + sizeof(uint32_t)+sizeof(off_t), SEEK_SET);
178 + ::write(fd, &cur_FM, sizeof(off_t));
179 + lseek(fd, cur_FM, SEEK_SET);
185 - ::write(fd, &c, sizeof(uint32_t));
186 + ::write(fd, &c, sizeof(uint32_t)); // EOF
187 + ::write(fd, &last_FM, sizeof(last_FM)); // F-1
188 + ::write(fd, &next_FM, sizeof(next_FM)); // F (will be updated next time)
190 - current_file += count;
196 - ::write(fd, &c, sizeof(uint32_t));
197 - lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
205 + last_file = MAX(current_file, last_file);
210 -int faketape::fsf(int count)
217 ASSERT(current_file >= 0);
218 @@ -528,24 +563,33 @@
220 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
227 if (atEOT || atEOD) {
233 - atBOT = atEOF = false;
234 - Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
236 + Dmsg2(dbglevel+1, "fsf %i <= %i\n", current_file, last_file);
238 - if ((current_file + count) <= last_file) {
239 - current_file += count;
241 + if (next_FM > last_FM) { /* not the last file */
242 + lseek(fd, next_FM, SEEK_SET);
243 + read_next_fm(true);
249 + } else if (atEOF) { /* last file mark */
255 + } else { /* last file, but no at the end */
258 Dmsg0(dbglevel, "Try to FSF after EOT\n");
260 current_file = last_file ;
261 @@ -553,10 +597,43 @@
269 +/* /------------\ /---------------\
270 + * +---+------+---+---------------+-+
272 + * +---+------+---+---------------+-+
274 +bool faketape::read_next_fm(bool read_all /* read the 0 byte */)
276 + return read_fm(read_all);
279 +bool faketape::read_fm(bool read_all /* read the 0 byte */)
284 + ::read(fd, &c, sizeof(c));
286 + lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(c), SEEK_SET);
290 + ::read(fd, &last_FM, sizeof(last_FM));
291 + ret = ::read(fd, &next_FM, sizeof(next_FM));
295 + Dmsg1(dbglevel, "Read FM next=%lli\n", next_FM);
297 + return (ret == sizeof(next_FM));
301 + * TODO: Check fsr with EOF
303 int faketape::fsr(int count)
308 Dmsg3(dbglevel, "fsr %i:%i count=%i\n", current_file,current_block, count);
314 @@ -595,20 +671,22 @@
315 current_file, current_block, nb,s);
318 - if (current_file < last_file) {
324 + read_next_fm(false);
326 atEOF = true; /* stop the loop */
330 - find_maxfile(); /* refresh stats */
336 + * BSR + EOF => begin of EOF + EIO
337 + * BSR + BSR + EOF => last block
338 + * current_block = -1
340 int faketape::bsr(int count)
342 Dmsg2(dbglevel, "bsr current_block=%i count=%i\n",
351 @@ -641,22 +718,21 @@
355 + /* at EOF 0:-1 BOT=0 EOD=0 EOF=0 ERR: Input/output error */
357 - if (!current_block) {
358 - if (current_file > 0) {
368 + lseek(fd, last_FM, SEEK_CUR);
378 + * First, go to last_FM and read all blocks to find the good one
381 + lseek(fd, last_FM, SEEK_CUR);
386 @@ -700,31 +776,34 @@
390 -int faketape::bsf(int count)
391 +/* BSF => just before last EOF
392 + * EOF + BSF => just before EOF
393 + * file 0 + BSF => BOT + errno
398 ASSERT(current_file >= 0);
399 - Dmsg3(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block, count);
400 + Dmsg2(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block);
406 atBOT = atEOF = atEOT = atEOD = false;
408 - if (current_file - count < 0) {
409 + if (current_file == 0) {/* BOT + errno */
410 + lseek(fd, 0, SEEK_SET);
418 - current_file = current_file - count + 1;
419 - current_block = -1;
421 + Dmsg1(dbglevel, "bfs last=%lli\n", last_FM);
422 + lseek(fd, last_FM, SEEK_SET);
424 - /* go just before last EOF */
425 - lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
434 +/* A filemark is automatically written to tape if the last tape operation
435 + * before close was a write.
437 int faketape::close()
440 @@ -756,18 +838,15 @@
448 - * EOF Bacula status: file=2 block=0
449 - * Device status: EOF ONLINE IM_REP_EN file=2 block=0
452 - * EOD EOF Bacula status: file=2 block=0
453 - * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
455 + * When a filemark is encountered while reading, the following happens. If
456 + * there are data remaining in the buffer when the filemark is found, the
457 + * buffered data is returned. The next read returns zero bytes. The following
458 + * read returns data from the next file. The end of recorded data is sig‐
459 + * naled by returning zero bytes for two consecutive read calls. The third
460 + * read returns an error.
463 int faketape::read(void *buffer, unsigned int count)
467 Dmsg2(dbglevel, "read %i:%i\n", current_file, current_block);
469 if (atEOT || atEOD) {
470 + if (eot_count < 2) { // first two reads return 0, after EIO
477 @@ -792,10 +875,10 @@
484 atEOD = atBOT = false;
487 /* reading size of data */
488 nb = ::read(fd, &s, sizeof(uint32_t));
489 @@ -813,11 +896,10 @@
493 - if (current_file < last_file) { /* move to next file if possible */
497 + if (read_next_fm(false)) {
505 nb = ::read(fd, buffer, s);
506 if (s != nb) { /* read error */
511 Dmsg0(dbglevel, "EOT during reading\n");
513 @@ -860,36 +942,25 @@
517 - /* open volume descriptor and get this->fd */
523 + next_FM = last_FM = 0;
528 atEOT = atEOD = false;
534 - * read volume to get the last file number
536 -int faketape::find_maxfile()
539 - if (fstat(fd, &statp) != 0) {
542 + if (!read_fm(true)) {
544 + last_file = current_file=0;
546 - last_file = statp.st_size>>FILE_OFFSET;
548 - Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
554 +/* use this to track file usage */
555 void faketape::update_pos()
558 @@ -901,32 +972,12 @@
559 Dmsg1(dbglevel+1, "update_pos=%i\n", file_block);
561 if (file_block > max_block) {
569 -int faketape::seek_file()
572 - ASSERT(current_file >= 0);
573 - Dmsg2(dbglevel, "seek_file %i:%i\n", current_file, current_block);
576 - off_t pos = ((off_t)current_file)<<FILE_OFFSET;
577 - if(lseek(fd, pos, SEEK_SET) == -1) {
581 - last_file = MAX(last_file, current_file);
582 - if (current_block > 0) {
583 - fsr(current_block);
589 void faketape::dump()
591 Dmsg0(dbglevel+1, "===================\n");
592 Index: src/stored/faketape.h
593 ===================================================================
594 --- src/stored/faketape.h (revision 7097)
595 +++ src/stored/faketape.h (working copy)
598 int fd; /* Our file descriptor */
600 - off_t file_block; /* size */
601 + off_t file_block; /* size */
604 + off_t last_FM; /* last file mark (current file) */
605 + off_t next_FM; /* next file mark (next file) */
607 bool atEOF; /* End of file */
608 bool atEOT; /* End of media */
609 bool atEOD; /* End of data */
610 bool atBOT; /* Begin of tape */
611 bool online; /* volume online */
612 - bool inplace; /* have to seek before writing ? */
613 bool needEOF; /* check if last operation need eof */
615 int32_t last_file; /* last file of the volume */
616 int32_t current_file; /* current position */
617 int32_t current_block; /* current position */
618 + int eot_count; /* count eot reads */
621 - int find_maxfile();
625 - void check_eof() { if(needEOF) weof(1);};
626 - void check_inplace() { if (!inplace) seek_file();};
627 + void check_eof() { if(needEOF) weof();};
629 + bool read_fm(bool readfirst);
630 + bool read_next_fm(bool readfirst);
631 + void set_eot() { eot_count=0; atEOT=true;};
634 - int fsf(int count);
637 - int weof(int count);
638 - int bsf(int count);