]> git.sur5r.net Git - bacula/bacula/blob - bacula/patches/testing/faketape2.patch
732d2f8ff6e77ec10ac4d872e028dcdb640286b7
[bacula/bacula] / bacula / patches / testing / faketape2.patch
1 Index: src/stored/faketape.c
2 ===================================================================
3 --- src/stored/faketape.c       (revision 7097)
4 +++ src/stored/faketape.c       (working copy)
5 @@ -170,6 +170,7 @@
6  int faketape::tape_op(struct mtop *mt_com)
7  {
8     int result=0;
9 +   int count = mt_com->mt_count;
10  
11     if (!online) {
12        errno = ENOMEDIUM;
13 @@ -193,11 +194,15 @@
14        break;
15  
16     case MTFSF:                  /* Forward space over mt_count filemarks. */
17 -      result = fsf(mt_com->mt_count);
18 +      do {
19 +        result = fsf();
20 +      } while (--count > 0 && result == 0);
21        break;
22  
23     case MTBSF:                  /* Backward space over mt_count filemarks. */
24 -      result = bsf(mt_com->mt_count);
25 +      do {
26 +        result = bsf();
27 +      } while (--count > 0 && result == 0);
28        break;
29  
30     case MTFSR:      /* Forward space over mt_count records (tape blocks). */
31 @@ -222,16 +227,20 @@
32        break;
33  
34     case MTWEOF:                 /* Write mt_count filemarks. */
35 -      result = weof(mt_com->mt_count);
36 +      do {
37 +        result = weof();
38 +      } while (result == 0 && --count > 0);
39        break;
40  
41     case MTREW:                  /* Rewind. */
42        Dmsg0(dbglevel, "rewind faketape\n");
43 +      check_eof();
44        atEOF = atEOD = false;
45        atBOT = true;
46        current_file = 0;
47        current_block = 0;
48 -      seek_file();
49 +      lseek(fd, 0, SEEK_SET);
50 +      read_next_fm(true);
51        break;
52  
53     case MTOFFL:                 /* put tape offline */
54 @@ -253,19 +262,30 @@
55        break;
56  
57     case MTEOM:/* Go to the end of the recorded media (for appending files). */
58 +      while (next_FM) {
59 +        lseek(fd, next_FM, SEEK_SET);
60 +        if (read_next_fm(true)) {
61 +           current_file++;
62 +        }
63 +      }
64 +      off_t l;
65 +      while (::read(fd, &l, sizeof(l)) > 0) {
66 +        if (l) {
67 +           lseek(fd, l, SEEK_CUR);
68 +        } else {
69 +           ASSERT(0);
70 +        }
71 +        Dmsg0(dbglevel, "skip 1 block\n");
72 +      }
73 +      current_block = -1;
74 +      atEOF = false;
75 +      atEOD = true;
76 +
77  /*
78     file number = 3
79     block number = -1
80  */
81        /* Can be at EOM */
82 -      atBOT = false;
83 -      atEOF = false;
84 -      atEOD = true;
85 -      atEOT = false;
86 -
87 -      current_file = last_file;
88 -      current_block = -1;
89 -      seek_file();
90        break;
91  
92     case MTERASE:                /* not used by bacula */
93 @@ -275,7 +295,8 @@
94  
95        current_file = 0;
96        current_block = -1;
97 -      seek_file();
98 +      lseek(fd, 0, SEEK_SET);
99 +      read_next_fm(true);
100        truncate_file();
101        break;
102  
103 @@ -405,8 +426,8 @@
104     atEOT = false;
105     atEOD = false;
106     online = false;
107 -   inplace = false;
108     needEOF = false;
109 +   eot_count = 0;
110  
111     file_block = 0;
112     last_file = 0;
113 @@ -444,8 +465,6 @@
114        return -1;
115     }
116  
117 -   check_inplace();
118 -
119     if (!atEOD) {                /* if not at the end of the data */
120        truncate_file();
121     }
122 @@ -460,14 +479,6 @@
123  
124     needEOF = true;              /* next operation need EOF mark */
125  
126 -//   if ((count + file_size) > max_size) {
127 -//      Dmsg2(dbglevel, 
128 -//          "EOT writing only %i of %i requested\n", 
129 -//          max_size - file_size, count);
130 -//      count = max_size - file_size;
131 -//      atEOT = true;
132 -//   }
133 -
134     uint32_t size = count;
135     ::write(fd, &size, sizeof(uint32_t));
136     nb = ::write(fd, buffer, count);
137 @@ -484,43 +495,67 @@
138     return nb;
139  }
140  
141 -int faketape::weof(int count)
142 +/*
143 + *  +---+---------+---+------------------+---+-------------------+
144 + *  |00N|  DATA   |0LN|   DATA           |0LC|     DATA          |
145 + *  +---+---------+---+------------------+---+-------------------+
146 + *
147 + *  0 : zero
148 + *  L : Last FileMark offset
149 + *  N : Next FileMark offset
150 + *  C : Current FileMark Offset
151 + */
152 +int faketape::weof()
153  {
154     ASSERT(online);
155     ASSERT(current_file >= 0);
156     Dmsg3(dbglevel, "Writing EOF %i:%i last=%i\n", 
157           current_file, current_block,last_file);
158 +
159 +   off_t cur_FM;
160 +
161     if (atEOT) {
162        errno = ENOSPC;
163        current_block = -1;
164        return -1;
165     }
166 -   needEOF = false;
167  
168 -   check_inplace();
169 -   truncate_file();             /* nothing after this point */
170 +   if (!atEOD) {
171 +      truncate_file();             /* nothing after this point */
172 +   }
173 +   
174 +   cur_FM = lseek(fd, 0, SEEK_CUR); // current position
175  
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);
180 +
181 +   last_FM = cur_FM;
182 +   next_FM = 0;
183 +
184     uint32_t c=0;
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)
189  
190 -   current_file += count;
191 +   current_file++;
192     current_block = 0;
193 -   seek_file();
194  
195 -   c=0;
196 -   ::write(fd, &c, sizeof(uint32_t));   
197 -   lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
198 -
199 +   needEOF = false;
200     atEOD = false;
201     atBOT = false;
202     atEOF = true;
203  
204 -   update_pos();
205 +   last_file = MAX(current_file, last_file);
206  
207     return 0;
208  }
209  
210 -int faketape::fsf(int count)
211 +/*
212 + * Go to next FM
213 + */
214 +int faketape::fsf()
215  {   
216     ASSERT(online);
217     ASSERT(current_file >= 0);
218 @@ -528,24 +563,33 @@
219  /*
220   * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
221   */
222 -   check_inplace();
223 -   check_eof();
224  
225 -   int ret;
226 +   int ret=0;
227     if (atEOT || atEOD) {
228        errno = EIO;
229        current_block = -1;
230        return -1;
231     }
232  
233 -   atBOT = atEOF = false;
234 -   Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
235 +   atBOT = false;
236 +   Dmsg2(dbglevel+1, "fsf %i <= %i\n", current_file, last_file);
237  
238 -   if ((current_file + count) <= last_file) {
239 -      current_file += count;
240 -      current_block = 0;
241 +   if (next_FM > last_FM) {    /* not the last file */
242 +      lseek(fd, next_FM, SEEK_SET);
243 +      read_next_fm(true);
244 +      current_file++;
245 +      atEOF = true;
246        ret = 0;
247 -   } else {
248 +
249 +   } else if (atEOF) {         /* last file mark */
250 +      current_block=-1;
251 +      errno = EIO;
252 +      atEOF = false;
253 +      atEOD = true;
254 +
255 +   } else {                    /* last file, but no at the end */
256 +      fsr(100000);
257 +
258        Dmsg0(dbglevel, "Try to FSF after EOT\n");
259        errno = EIO;
260        current_file = last_file ;
261 @@ -553,10 +597,43 @@
262        atEOD=true;
263        ret = -1;
264     }
265 -   seek_file();
266     return ret;
267  }
268  
269 +/* /------------\ /---------------\
270 + * +---+------+---+---------------+-+
271 + * |OLN|      |0LN|               | |
272 + * +---+------+---+---------------+-+
273 + */
274 +bool faketape::read_next_fm(bool read_all /* read the 0 byte */)
275 +{
276 +   return read_fm(read_all);
277 +}
278 +
279 +bool faketape::read_fm(bool read_all /* read the 0 byte */)
280 +{
281 +   int ret;
282 +   uint32_t c;
283 +   if (read_all) {
284 +      ::read(fd, &c, sizeof(c));
285 +      if (c != 0) {
286 +        lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(c), SEEK_SET);
287 +        return false;
288 +      }
289 +   }
290 +   ::read(fd, &last_FM, sizeof(last_FM));
291 +   ret = ::read(fd, &next_FM, sizeof(next_FM));
292 +
293 +   current_block=0;
294 +   
295 +   Dmsg1(dbglevel, "Read FM next=%lli\n", next_FM);
296 +
297 +   return (ret == sizeof(next_FM));
298 +}
299 +
300 +/*
301 + * TODO: Check fsr with EOF
302 + */
303  int faketape::fsr(int count)
304  {
305     ASSERT(online);
306 @@ -568,7 +645,6 @@
307     uint32_t s;
308     Dmsg3(dbglevel, "fsr %i:%i count=%i\n", current_file,current_block, count);
309  
310 -   check_inplace();
311     check_eof();
312  
313     if (atEOT) {
314 @@ -595,20 +671,22 @@
315                 current_file, current_block, nb,s);
316           errno = EIO;
317           ret = -1;
318 -         if (current_file < last_file) {
319 -            current_block = 0;
320 +        if (next_FM) {
321              current_file++;
322 -            seek_file();
323 -         }
324 +           read_next_fm(false);
325 +        }
326           atEOF = true;          /* stop the loop */
327        }
328     }
329  
330 -   find_maxfile();              /* refresh stats */
331 -
332     return ret;
333  }
334  
335 +/*
336 + * BSR + EOF => begin of EOF + EIO
337 + * BSR + BSR + EOF => last block
338 + * current_block = -1
339 + */
340  int faketape::bsr(int count)
341  {
342     Dmsg2(dbglevel, "bsr current_block=%i count=%i\n", 
343 @@ -619,7 +697,6 @@
344     ASSERT(count == 1);
345     ASSERT(fd >= 0);
346  
347 -   check_inplace();
348     check_eof();
349  
350     if (!count) {
351 @@ -641,22 +718,21 @@
352        return -1;
353     }
354  
355 +   /* at EOF 0:-1 BOT=0 EOD=0 EOF=0 ERR: Input/output error  */
356     if (atEOF) {
357 -      if (!current_block) {
358 -        if (current_file > 0) {
359 -           current_file--;
360 -        }
361 -        current_block=-1;
362 -        errno = EIO;
363 -        return -1;
364 -
365 -      } else {
366 -        atEOF=false;
367 -      }
368 +      lseek(fd, last_FM, SEEK_CUR);
369 +      atEOF = false;
370 +      current_block=-1;
371 +      errno = EIO;
372 +      return -1;
373     }
374  
375 -   current_block=0;
376 -   seek_file();
377 +   /*
378 +    * First, go to last_FM and read all blocks to find the good one
379 +    */
380 +   
381 +   lseek(fd, last_FM, SEEK_CUR);
382 +   read_fm(true);
383  
384     do {
385        if (!atEOF) {
386 @@ -700,31 +776,34 @@
387     return 0;
388  }
389  
390 -int faketape::bsf(int count)
391 +/* BSF => just before last EOF
392 + * EOF + BSF => just before EOF
393 + * file 0 + BSF => BOT + errno
394 + */
395 +int faketape::bsf()
396  {
397     ASSERT(online);
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);
401     int ret = 0;
402  
403 -   check_inplace();
404     check_eof();
405  
406     atBOT = atEOF = atEOT = atEOD = false;
407  
408 -   if (current_file - count < 0) {
409 +   if (current_file == 0) {/* BOT + errno */      
410 +      lseek(fd, 0, SEEK_SET);
411 +      read_fm(true);
412        current_file = 0;
413        current_block = 0;
414        atBOT = true;
415        errno = EIO;
416        ret = -1;
417     } else {
418 -      current_file = current_file - count + 1;
419 -      current_block = -1;
420 -      seek_file();
421 +      Dmsg1(dbglevel, "bfs last=%lli\n", last_FM);
422 +      lseek(fd, last_FM, SEEK_SET);
423        current_file--;
424 -      /* go just before last EOF */
425 -      lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
426 +      current_block=-1;
427     }
428     return ret;
429  }
430 @@ -749,6 +828,9 @@
431     return 0;
432  }
433  
434 +/* A filemark is automatically written to tape if the last tape operation
435 + * before close was a write.
436 + */
437  int faketape::close()
438  {
439     check_eof();
440 @@ -756,18 +838,15 @@
441     fd = -1;
442     return 0;
443  }
444 +
445  /*
446 - **rb
447 - **status
448 - * EOF Bacula status: file=2 block=0
449 - * Device status: EOF ONLINE IM_REP_EN file=2 block=0
450 - **rb
451 - **status
452 - * EOD EOF Bacula status: file=2 block=0
453 - * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
454 - *
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.
461   */
462 -
463  int faketape::read(void *buffer, unsigned int count)
464  {
465     ASSERT(online);
466 @@ -778,6 +857,10 @@
467     Dmsg2(dbglevel, "read %i:%i\n", current_file, current_block);
468  
469     if (atEOT || atEOD) {
470 +      if (eot_count < 2) {     // first two reads return 0, after EIO
471 +        eot_count++;
472 +        return 0;
473 +      }
474        errno = EIO;
475        return -1;
476     }
477 @@ -792,10 +875,10 @@
478        atEOF=false;
479     }
480  
481 -   check_inplace();
482     check_eof();
483  
484     atEOD = atBOT = false;
485 +   eot_count = 0;
486  
487     /* reading size of data */
488     nb = ::read(fd, &s, sizeof(uint32_t));
489 @@ -813,11 +896,10 @@
490  
491     if (!s) {                    /* EOF */
492        atEOF = true;
493 -      if (current_file < last_file) { /* move to next file if possible */
494 -         current_file++;
495 -         current_block = 0;
496 -         inplace=false;
497 +      if (read_next_fm(false)) {
498 +        current_file++;
499        }
500 +
501        return 0;
502     }
503  
504 @@ -825,7 +907,7 @@
505     nb = ::read(fd, buffer, s);
506     if (s != nb) {              /* read error */
507        errno=EIO;
508 -      atEOT = true;
509 +      set_eot();
510        current_block = -1;
511        Dmsg0(dbglevel, "EOT during reading\n");
512        return -1;
513 @@ -860,36 +942,25 @@
514        return -1;
515     }
516  
517 -   /* open volume descriptor and get this->fd */
518 -   find_maxfile();
519 -
520     file_block = 0;
521     current_block = 0;
522     current_file = 0;
523 +   next_FM = last_FM = 0;
524 +   eot_count = 0;
525     needEOF = false;
526 -   inplace = true;
527     atBOT = true;
528     atEOT = atEOD = false;
529  
530 -   return fd;
531 -}
532 -
533 -/*
534 - * read volume to get the last file number
535 - */
536 -int faketape::find_maxfile()
537 -{
538 -   struct stat statp;
539 -   if (fstat(fd, &statp) != 0) {
540 -      return 0;
541 +   
542 +   if (!read_fm(true)) {
543 +      weof();
544 +      last_file = current_file=0;
545     }
546 -   last_file = statp.st_size>>FILE_OFFSET;
547 -      
548 -   Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
549  
550 -   return last_file;
551 +   return fd;
552  }
553  
554 +/* use this to track file usage */
555  void faketape::update_pos()
556  {
557     ASSERT(online);
558 @@ -901,32 +972,12 @@
559     Dmsg1(dbglevel+1, "update_pos=%i\n", file_block);
560  
561     if (file_block > max_block) {
562 -      atEOT = true;
563 +      set_eot();
564     } else {
565        atEOT = false;
566     }
567  }
568  
569 -int faketape::seek_file()
570 -{
571 -   ASSERT(online);
572 -   ASSERT(current_file >= 0);
573 -   Dmsg2(dbglevel, "seek_file %i:%i\n", current_file, current_block);
574 -   inplace = true;
575 -
576 -   off_t pos = ((off_t)current_file)<<FILE_OFFSET;
577 -   if(lseek(fd, pos, SEEK_SET) == -1) {
578 -      return -1;
579 -   }
580 -
581 -   last_file = MAX(last_file, current_file);
582 -   if (current_block > 0) {
583 -      fsr(current_block);
584 -   }
585 -
586 -   return 0;
587 -}
588 -
589  void faketape::dump()
590  {
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)
596 @@ -56,35 +56,38 @@
597  private:
598     int         fd;              /* Our file descriptor */
599  
600 -   off_t       file_block;       /* size */
601 +   off_t       file_block;     /* size */
602     off_t       max_block;
603  
604 +   off_t       last_FM;                /* last file mark (current file) */
605 +   off_t       next_FM;                /* next file mark (next file) */
606 +
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 */
614  
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 */
619  
620     void destroy();
621 -   int find_maxfile();
622     int offline();
623     int truncate_file();
624 -   int seek_file();
625 -   void check_eof() { if(needEOF) weof(1);};
626 -   void check_inplace() { if (!inplace) seek_file();};
627 +   void check_eof() { if(needEOF) weof();};
628     void update_pos();
629 +   bool read_fm(bool readfirst);
630 +   bool read_next_fm(bool readfirst);
631 +   void set_eot() { eot_count=0; atEOT=true;};
632  
633  public:
634 -   int fsf(int count);
635 +   int fsf();
636     int fsr(int count);
637 -   int weof(int count);
638 -   int bsf(int count);
639 +   int weof();
640 +   int bsf();
641     int bsr(int count);
642  
643     faketape();