1 Index: src/stored/faketape.c
2 ===================================================================
3 --- src/stored/faketape.c (révision 7092)
4 +++ src/stored/faketape.c (copie de travail)
9 -static int dbglevel = 10;
10 +static int dbglevel = 0;
11 #define FILE_OFFSET 30
12 faketape *ftape_list[FTAPE_MAX_DRIVE];
15 int faketape::tape_op(struct mtop *mt_com)
18 + int count = mt_com->mt_count;
25 case MTFSF: /* Forward space over mt_count filemarks. */
26 - result = fsf(mt_com->mt_count);
29 + } while (--count > 0 && result == 0);
32 case MTBSF: /* Backward space over mt_count filemarks. */
33 - result = bsf(mt_com->mt_count);
36 + } while (--count > 0 && result == 0);
39 case MTFSR: /* Forward space over mt_count records (tape blocks). */
43 case MTWEOF: /* Write mt_count filemarks. */
44 - result = weof(mt_com->mt_count);
47 + } while (result == 0 && --count > 0);
50 case MTREW: /* Rewind. */
51 Dmsg0(dbglevel, "rewind faketape\n");
53 atEOF = atEOD = false;
58 + lseek(fd, 0, SEEK_SET);
62 case MTOFFL: /* put tape offline */
66 case MTEOM:/* Go to the end of the recorded media (for appending files). */
68 + lseek(fd, next_FM, SEEK_SET);
69 + if (read_next_fm(true)) {
74 + while (::read(fd, &l, sizeof(l)) > 0) {
76 + lseek(fd, l, SEEK_CUR);
80 + Dmsg0(dbglevel, "skip 1 block\n");
96 - current_file = last_file;
101 case MTERASE: /* not used by bacula */
107 + lseek(fd, 0, SEEK_SET);
108 + read_next_fm(true);
128 if (!atEOD) { /* if not at the end of the data */
133 needEOF = true; /* next operation need EOF mark */
135 -// if ((count + file_size) > max_size) {
137 -// "EOT writing only %i of %i requested\n",
138 -// max_size - file_size, count);
139 -// count = max_size - file_size;
143 uint32_t size = count;
144 ::write(fd, &size, sizeof(uint32_t));
145 nb = ::write(fd, buffer, count);
146 @@ -484,43 +495,68 @@
150 -int faketape::weof(int count)
152 + * +---+---------+---+------------------+---+-------------------+
153 + * |00N| DATA |0LN| DATA |0LC| DATA |
154 + * +---+---------+---+------------------+---+-------------------+
157 + * L : Last FileMark offset
158 + * N : Next FileMark offset
159 + * C : Current FileMark Offset
161 +int faketape::weof()
164 ASSERT(current_file >= 0);
165 Dmsg3(dbglevel, "Writing EOF %i:%i last=%i\n",
166 current_file, current_block,last_file);
178 - truncate_file(); /* nothing after this point */
180 + 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);
195 - ::write(fd, &c, sizeof(uint32_t));
196 + ::write(fd, &c, sizeof(uint32_t)); // EOF
197 + ::write(fd, &last_FM, sizeof(last_FM)); // F-1
198 + ::write(fd, &next_FM, sizeof(next_FM)); // F (will be updated next time)
200 - current_file += count;
206 - ::write(fd, &c, sizeof(uint32_t));
207 - lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
215 + last_file = MAX(current_file, last_file);
220 -int faketape::fsf(int count)
227 ASSERT(current_file >= 0);
228 @@ -528,24 +564,33 @@
230 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
237 if (atEOT || atEOD) {
243 - atBOT = atEOF = false;
244 - Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
246 + Dmsg2(dbglevel+1, "fsf %i <= %i\n", current_file, last_file);
248 - if ((current_file + count) <= last_file) {
249 - current_file += count;
251 + if (next_FM > last_FM) { /* not the last file */
252 + lseek(fd, next_FM, SEEK_SET);
253 + read_next_fm(true);
259 + } else if (atEOF) { /* last file mark */
265 + } else { /* last file, but no at the end */
268 Dmsg0(dbglevel, "Try to FSF after EOT\n");
270 current_file = last_file ;
271 @@ -553,10 +598,44 @@
279 +/* /------------\ /---------------\
280 + * +---+------+---+---------------+-+
282 + * +---+------+---+---------------+-+
284 +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, lseek(fd, 0, SEEK_CUR) - sizeof(c), SEEK_SET);
301 + ::read(fd, &last_FM, sizeof(last_FM));
302 + ret = ::read(fd, &next_FM, sizeof(next_FM));
306 + Dmsg1(dbglevel, "Read FM next=%lli\n", next_FM);
308 + return (ret == sizeof(next_FM));
312 + * TODO: Check fsr with EOF
314 int faketape::fsr(int count)
319 Dmsg3(dbglevel, "fsr %i:%i count=%i\n", current_file,current_block, count);
325 @@ -595,20 +673,23 @@
326 current_file, current_block, nb,s);
329 - if (current_file < last_file) {
335 + read_next_fm(false);
337 atEOF = true; /* stop the loop */
341 - find_maxfile(); /* refresh stats */
347 + * BSR + EOF => begin of EOF + EIO
348 + * BSR + BSR + EOF => last block
349 + * current_block = -1
351 int faketape::bsr(int count)
353 Dmsg2(dbglevel, "bsr current_block=%i count=%i\n",
362 @@ -641,22 +721,21 @@
366 + /* at EOF 0:-1 BOT=0 EOD=0 EOF=0 ERR: Input/output error */
368 - if (!current_block) {
369 - if (current_file > 0) {
379 + lseek(fd, last_FM, SEEK_CUR);
389 + * First, go to last_FM and read all blocks to find the good one
392 + lseek(fd, last_FM, SEEK_CUR);
397 @@ -700,31 +779,35 @@
401 -int faketape::bsf(int count)
402 +/* BSF => just before last EOF
403 + * EOF + BSF => just before EOF
404 + * file 0 + BSF => BOT + errno
409 ASSERT(current_file >= 0);
410 - Dmsg3(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block, count);
411 + Dmsg2(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block);
417 atBOT = atEOF = atEOT = atEOD = false;
419 - if (current_file - count < 0) {
420 + if (current_file == 0) {/* BOT + errno */
421 + lseek(fd, 0, SEEK_SET);
430 - current_file = current_file - count + 1;
431 - current_block = -1;
433 + Dmsg1(dbglevel, "bfs last=%lli\n", last_FM);
434 + lseek(fd, last_FM, SEEK_SET);
436 - /* go just before last EOF */
437 - lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
446 +/* A filemark is automatically written to tape if the last tape operation
447 + * before close was a write.
449 int faketape::close()
452 @@ -756,18 +842,15 @@
460 - * EOF Bacula status: file=2 block=0
461 - * Device status: EOF ONLINE IM_REP_EN file=2 block=0
464 - * EOD EOF Bacula status: file=2 block=0
465 - * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
467 + * When a filemark is encountered while reading, the following happens. If
468 + * there are data remaining in the buffer when the filemark is found, the
469 + * buffered data is returned. The next read returns zero bytes. The following
470 + * read returns data from the next file. The end of recorded data is sig‐
471 + * naled by returning zero bytes for two consecutive read calls. The third
472 + * read returns an error.
475 int faketape::read(void *buffer, unsigned int count)
479 Dmsg2(dbglevel, "read %i:%i\n", current_file, current_block);
481 if (atEOT || atEOD) {
482 + if (eot_count < 2) { // first two reads return 0, after EIO
489 @@ -792,10 +879,10 @@
496 atEOD = atBOT = false;
499 /* reading size of data */
500 nb = ::read(fd, &s, sizeof(uint32_t));
501 @@ -813,11 +900,10 @@
505 - if (current_file < last_file) { /* move to next file if possible */
509 + if (read_next_fm(false)) {
517 nb = ::read(fd, buffer, s);
518 if (s != nb) { /* read error */
523 Dmsg0(dbglevel, "EOT during reading\n");
525 @@ -860,36 +946,25 @@
529 - /* open volume descriptor and get this->fd */
535 + prev_FM = next_FM = last_FM = 0;
540 atEOT = atEOD = false;
546 - * read volume to get the last file number
548 -int faketape::find_maxfile()
551 - if (fstat(fd, &statp) != 0) {
554 + if (!read_fm(true)) {
556 + last_file = current_file=0;
558 - last_file = statp.st_size>>FILE_OFFSET;
560 - Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
566 +/* use this to track file usage */
567 void faketape::update_pos()
570 @@ -901,32 +976,12 @@
571 Dmsg1(dbglevel+1, "update_pos=%i\n", file_block);
573 if (file_block > max_block) {
581 -int faketape::seek_file()
584 - ASSERT(current_file >= 0);
585 - Dmsg2(dbglevel, "seek_file %i:%i\n", current_file, current_block);
588 - off_t pos = ((off_t)current_file)<<FILE_OFFSET;
589 - if(lseek(fd, pos, SEEK_SET) == -1) {
593 - last_file = MAX(last_file, current_file);
594 - if (current_block > 0) {
595 - fsr(current_block);
601 void faketape::dump()
603 Dmsg0(dbglevel+1, "===================\n");
604 Index: src/stored/faketape.h
605 ===================================================================
606 --- src/stored/faketape.h (révision 7084)
607 +++ src/stored/faketape.h (copie de travail)
610 int fd; /* Our file descriptor */
612 - off_t file_block; /* size */
613 + off_t file_block; /* size */
616 + off_t prev_FM; /* previous file mark */
617 + off_t last_FM; /* last file mark (current file) */
620 bool atEOF; /* End of file */
621 bool atEOT; /* End of media */
622 bool atEOD; /* End of data */
623 bool atBOT; /* Begin of tape */
624 bool online; /* volume online */
625 - bool inplace; /* have to seek before writing ? */
626 bool needEOF; /* check if last operation need eof */
628 int32_t last_file; /* last file of the volume */
629 int32_t current_file; /* current position */
630 int32_t current_block; /* current position */
631 + int eot_count; /* count eot reads */
634 - int find_maxfile();
638 - void check_eof() { if(needEOF) weof(1);};
639 - void check_inplace() { if (!inplace) seek_file();};
640 + void check_eof() { if(needEOF) weof();};
642 + bool read_fm(bool readfirst);
643 + bool read_next_fm(bool readfirst);
644 + void set_eot() { eot_count=0; atEOT=true;};
647 - int fsf(int count);
650 - int weof(int count);
651 - int bsf(int count);