1 Index: src/stored/faketape.c
2 ===================================================================
3 --- src/stored/faketape.c (révision 7100)
4 +++ src/stored/faketape.c (copie de travail)
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);
117 - Dmsg3(dbglevel, "write len=%i %i:%i\n", count, current_file,current_block);
118 + Dmsg3(dbglevel+1, "write len=%i %i:%i\n",
119 + count, current_file,current_block);
122 Dmsg0(dbglevel, "write nothing, EOT !\n");
129 if (!atEOD) { /* if not at the end of the data */
134 needEOF = true; /* next operation need EOF mark */
136 -// if ((count + file_size) > max_size) {
138 -// "EOT writing only %i of %i requested\n",
139 -// max_size - file_size, count);
140 -// count = max_size - file_size;
144 uint32_t size = count;
145 ::write(fd, &size, sizeof(uint32_t));
146 nb = ::write(fd, buffer, count);
147 @@ -484,43 +496,66 @@
151 -int faketape::weof(int count)
153 + * +---+---------+---+------------------+---+-------------------+
154 + * |00N| DATA |0LN| DATA |0LC| DATA |
155 + * +---+---------+---+------------------+---+-------------------+
158 + * L : Last FileMark offset
159 + * N : Next FileMark offset
160 + * C : Current FileMark Offset
162 +int faketape::weof()
165 ASSERT(current_file >= 0);
166 - Dmsg3(dbglevel, "Writing EOF %i:%i last=%i\n",
167 - current_file, current_block,last_file);
177 - truncate_file(); /* nothing after this point */
179 + truncate_file(); /* nothing after this point */
183 + cur_FM = lseek(fd, 0, SEEK_CUR); // current position
185 + /* update previous next_FM */
186 + lseek(fd, last_FM + sizeof(uint32_t)+sizeof(off_t), SEEK_SET);
187 + ::write(fd, &cur_FM, sizeof(off_t));
188 + lseek(fd, cur_FM, SEEK_SET);
193 - ::write(fd, &c, sizeof(uint32_t));
194 + ::write(fd, &c, sizeof(uint32_t)); // EOF
195 + ::write(fd, &last_FM, sizeof(last_FM)); // F-1
196 + ::write(fd, &next_FM, sizeof(next_FM)); // F (will be updated next time)
198 - current_file += count;
204 - ::write(fd, &c, sizeof(uint32_t));
205 - lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
213 + last_file = MAX(current_file, last_file);
215 + Dmsg4(dbglevel, "Writing EOF %i:%i last=%lli cur=%lli next=0\n",
216 + current_file, current_block, last_FM, cur_FM);
221 -int faketape::fsf(int count)
228 ASSERT(current_file >= 0);
229 @@ -528,24 +563,33 @@
231 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
238 if (atEOT || atEOD) {
244 - atBOT = atEOF = false;
245 - Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
247 + Dmsg2(dbglevel+1, "fsf %i <= %i\n", current_file, last_file);
249 - if ((current_file + count) <= last_file) {
250 - current_file += count;
252 + if (next_FM > cur_FM) { /* not the last file */
253 + lseek(fd, next_FM, SEEK_SET);
254 + read_next_fm(true);
260 + } else if (atEOF) { /* last file mark */
266 + } else { /* last file, but no at the end */
269 Dmsg0(dbglevel, "Try to FSF after EOT\n");
271 current_file = last_file ;
272 @@ -553,10 +597,47 @@
280 +/* /------------\ /---------------\
281 + * +---+------+---+---------------+-+
283 + * +---+------+---+---------------+-+
285 +bool faketape::read_next_fm(bool read_all /* read the 0 byte */)
287 + return read_fm(read_all);
290 +bool faketape::read_fm(bool read_all /* read the 0 byte */)
295 + ::read(fd, &c, sizeof(c));
297 + lseek(fd, cur_FM, SEEK_SET);
302 + cur_FM = lseek(fd, 0, SEEK_CUR) - sizeof(c);
304 + ::read(fd, &last_FM, sizeof(last_FM));
305 + ret = ::read(fd, &next_FM, sizeof(next_FM));
309 + Dmsg3(dbglevel, "Read FM cur=%lli last=%lli next=%lli\n",
310 + cur_FM, last_FM, next_FM);
312 + return (ret == sizeof(next_FM));
316 + * TODO: Check fsr with EOF
318 int faketape::fsr(int count)
325 - Dmsg3(dbglevel, "fsr %i:%i count=%i\n", current_file,current_block, count);
326 + Dmsg4(dbglevel, "fsr %i:%i EOF=%i c=%i\n",
327 + current_file,current_block,atEOF,count);
333 @@ -595,31 +676,29 @@
334 current_file, current_block, nb,s);
337 - if (current_file < last_file) {
343 + read_next_fm(false);
345 atEOF = true; /* stop the loop */
349 - find_maxfile(); /* refresh stats */
355 + * BSR + EOF => begin of EOF + EIO
356 + * BSR + BSR + EOF => last block
357 + * current_block = -1
359 int faketape::bsr(int count)
361 - Dmsg2(dbglevel, "bsr current_block=%i count=%i\n",
362 - current_block, count);
365 ASSERT(current_file >= 0);
373 @@ -635,29 +714,39 @@
374 int orig_f = current_file;
375 int orig_b = current_block;
377 + Dmsg4(dbglevel, "bsr cur_blk=%i count=%i cur=%lli cur_FM=%lli\n",
378 + current_block, count, orig, cur_FM);
380 /* begin of tape, do nothing */
386 + /* at EOF 0:-1 BOT=0 EOD=0 EOF=0 ERR: Input/output error */
388 - if (!current_block) {
389 - if (current_file > 0) {
398 + lseek(fd, cur_FM, SEEK_SET);
400 + if (current_file > 0) {
411 + * First, go to cur/last_FM and read all blocks to find the good one
413 + if (cur_FM == orig) { /* already just before EOF */
414 + lseek(fd, last_FM, SEEK_SET);
417 + lseek(fd, cur_FM, SEEK_SET);
420 + ret = read_fm(true);
425 @@ -674,14 +763,14 @@
426 lseek(fd, last2, SEEK_SET);
427 current_file = last_f;
428 current_block = last_b - 1;
429 - Dmsg3(dbglevel, "set offset2=%lli %i:%i\n",
430 + Dmsg3(dbglevel, "1 set offset2=%lli %i:%i\n",
431 last, current_file, current_block);
433 } else if (last > 0) {
434 lseek(fd, last, SEEK_SET);
435 current_file = last_f;
436 current_block = last_b;
437 - Dmsg3(dbglevel, "set offset=%lli %i:%i\n",
438 + Dmsg3(dbglevel, "2 set offset=%lli %i:%i\n",
439 last, current_file, current_block);
441 lseek(fd, orig, SEEK_SET);
442 @@ -693,38 +782,45 @@
443 Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
445 atEOT = atEOF = atEOD = false;
446 - atBOT = (current_block == 0 && current_file == 0);
447 + atBOT = (lseek(fd, 0, SEEK_CUR) - (sizeof(uint32_t)+2*sizeof(off_t))) == 0;
449 - current_block = -1;
450 + if (orig_b == -1) {
451 + current_block = orig_b;
457 -int faketape::bsf(int count)
458 +/* BSF => just before last EOF
459 + * EOF + BSF => just before EOF
460 + * file 0 + BSF => BOT + errno
465 ASSERT(current_file >= 0);
466 - Dmsg3(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block, count);
467 + Dmsg2(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block);
473 atBOT = atEOF = atEOT = atEOD = false;
475 - if (current_file - count < 0) {
476 + if (current_file == 0) {/* BOT + errno */
477 + lseek(fd, 0, SEEK_SET);
485 - current_file = current_file - count + 1;
486 - current_block = -1;
488 + Dmsg1(dbglevel, "bfs last=%lli\n", last_FM);
489 + lseek(fd, last_FM, SEEK_SET);
490 + read_fm(true); /* update last/cur/next_FM */
491 + lseek(fd, cur_FM, SEEK_SET);
493 - /* go just before last EOF */
494 - lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
503 +/* A filemark is automatically written to tape if the last tape operation
504 + * before close was a write.
506 int faketape::close()
509 @@ -756,18 +855,15 @@
517 - * EOF Bacula status: file=2 block=0
518 - * Device status: EOF ONLINE IM_REP_EN file=2 block=0
521 - * EOD EOF Bacula status: file=2 block=0
522 - * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
524 + * When a filemark is encountered while reading, the following happens. If
525 + * there are data remaining in the buffer when the filemark is found, the
526 + * buffered data is returned. The next read returns zero bytes. The following
527 + * read returns data from the next file. The end of recorded data is sig‐
528 + * naled by returning zero bytes for two consecutive read calls. The third
529 + * read returns an error.
532 int faketape::read(void *buffer, unsigned int count)
539 - Dmsg2(dbglevel, "read %i:%i\n", current_file, current_block);
540 + Dmsg2(dbglevel+1, "read %i:%i\n", current_file, current_block);
542 if (atEOT || atEOD) {
548 - if (current_file >= last_file) {
560 atEOD = atBOT = false;
561 @@ -813,11 +908,10 @@
565 - if (current_file < last_file) { /* move to next file if possible */
569 + if (read_next_fm(false)) {
577 nb = ::read(fd, buffer, s);
578 if (s != nb) { /* read error */
583 Dmsg0(dbglevel, "EOT during reading\n");
585 @@ -860,36 +954,24 @@
589 - /* open volume descriptor and get this->fd */
595 + cur_FM = next_FM = last_FM = 0;
599 atEOT = atEOD = false;
605 - * read volume to get the last file number
607 -int faketape::find_maxfile()
610 - if (fstat(fd, &statp) != 0) {
613 + if (!read_fm(true)) {
615 + last_file = current_file=0;
617 - last_file = statp.st_size>>FILE_OFFSET;
619 - Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
625 +/* use this to track file usage */
626 void faketape::update_pos()
629 @@ -901,32 +983,12 @@
630 Dmsg1(dbglevel+1, "update_pos=%i\n", file_block);
632 if (file_block > max_block) {
640 -int faketape::seek_file()
643 - ASSERT(current_file >= 0);
644 - Dmsg2(dbglevel, "seek_file %i:%i\n", current_file, current_block);
647 - off_t pos = ((off_t)current_file)<<FILE_OFFSET;
648 - if(lseek(fd, pos, SEEK_SET) == -1) {
652 - last_file = MAX(last_file, current_file);
653 - if (current_block > 0) {
654 - fsr(current_block);
660 void faketape::dump()
662 Dmsg0(dbglevel+1, "===================\n");
663 Index: src/stored/faketape.h
664 ===================================================================
665 --- src/stored/faketape.h (révision 7100)
666 +++ src/stored/faketape.h (copie de travail)
669 int fd; /* Our file descriptor */
671 - off_t file_block; /* size */
672 + off_t file_block; /* size */
675 + off_t last_FM; /* last file mark (last file) */
676 + off_t next_FM; /* next file mark (next file) */
677 + off_t cur_FM; /* current file mark */
679 bool atEOF; /* End of file */
680 bool atEOT; /* End of media */
681 bool atEOD; /* End of data */
682 bool atBOT; /* Begin of tape */
683 bool online; /* volume online */
684 - bool inplace; /* have to seek before writing ? */
685 bool needEOF; /* check if last operation need eof */
687 int32_t last_file; /* last file of the volume */
688 int32_t current_file; /* current position */
689 int32_t current_block; /* current position */
690 + int eot_count; /* count eot reads */
693 - int find_maxfile();
697 - void check_eof() { if(needEOF) weof(1);};
698 - void check_inplace() { if (!inplace) seek_file();};
699 + void check_eof() { if(needEOF) weof();};
701 + bool read_fm(bool readfirst);
702 + bool read_next_fm(bool readfirst);
703 + void set_eot() { eot_count=0; atEOT=true;};
706 - int fsf(int count);
709 - int weof(int count);
710 - int bsf(int count);