]> git.sur5r.net Git - bacula/bacula/blob - bacula/patches/testing/faketape.c
ebl update
[bacula/bacula] / bacula / patches / testing / faketape.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version two of the GNU General Public
10    License as published by the Free Software Foundation, which is 
11    listed in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of John Walker.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28
29 #include "faketape.h"
30 #include <dirent.h>
31 #include <sys/mtio.h>
32 #include <ctype.h>
33
34 static int tape_get(int fd, struct mtget *mt_get);
35 static int tape_op(int fd, struct mtop *mt_com);
36 static int tape_pos(int fd, struct mtpos *mt_pos);
37
38 static int dbglevel = 0;
39
40
41 faketape *ftape_list[FTAPE_MAX_DRIVE];
42
43 static faketape *get_tape(int fd)
44 {
45    ASSERT(fd >= 0);
46
47    if (fd >= FTAPE_MAX_DRIVE) {
48       /* error */
49       return NULL;
50    }
51
52    return ftape_list[fd];
53 }
54
55 static bool put_tape(faketape *ftape)
56 {
57    ASSERT(ftape != NULL);
58
59    int fd = ftape->get_fd();
60    if (fd >= FTAPE_MAX_DRIVE) {
61       /* error */
62       return false;
63    }
64    ftape_list[fd] = ftape;
65    return true;
66 }
67
68 int faketape_open(const char *pathname, int flags, int mode)
69 {
70    ASSERT(pathname != NULL);
71
72    int fd;
73    faketape *tape = new faketape();
74    fd = tape->open(pathname, flags, mode);
75    if (fd > 0) {
76       put_tape(tape);
77    }
78    return fd;
79 }
80
81 int faketape_read(int fd, void *buffer, unsigned int count)
82 {
83    faketape *tape = get_tape(fd);
84    ASSERT(tape != NULL);
85    return tape->read(buffer, count);
86 }
87
88 int faketape_write(int fd, const void *buffer, unsigned int count)
89 {
90    faketape *tape = get_tape(fd);
91    ASSERT(tape != NULL);
92    return tape->write(buffer, count);
93 }
94
95 int faketape_close(int fd)
96 {
97    faketape *tape = get_tape(fd);
98    ASSERT(tape != NULL);
99    tape->close();
100    delete tape;
101    return 0;
102 }
103
104 int faketape_ioctl(int fd, unsigned long int request, ...)
105 {
106    va_list argp;
107    int result=0;
108
109    faketape *t = get_tape(fd);
110    if (!t) {
111       errno = EBADF;
112       return -1;
113    }
114
115    va_start(argp, request);
116
117 //  switch (request) {
118 //  case MTIOCTOP:
119         result = t->tape_op(va_arg(argp, mtop *));
120 //      break;
121
122 //   case MTIOCGET:
123 //      result = tape_get(fd, va_arg(argp, mtget *));
124 //      break;
125 //
126 //   case MTIOCPOS:
127 //      result = tape_pos(fd, va_arg(argp, mtpos *));
128 //      break;
129 //
130 //   default:
131 //      errno = ENOTTY;
132 //      result = -1;
133 //      break;
134 //   }
135
136    va_end(argp);
137
138    return result;
139 }
140
141 int faketape::tape_op(struct mtop *mt_com)
142 {
143    int result=0;
144    
145    switch (mt_com->mt_op)
146    {
147    case MTRESET:
148    case MTNOP:
149    case MTSETDRVBUFFER:
150       break;
151
152    default:
153    case MTRAS1:
154    case MTRAS2:
155    case MTRAS3:
156    case MTSETDENSITY:
157       errno = ENOTTY;
158       result = -1;
159       break;
160
161    case MTFSF:                  /* Forward space over mt_count filemarks. */
162       break;
163
164    case MTBSF:                  /* Backward space over mt_count filemarks. */
165       current_file = current_file - mt_com->mt_count;
166       if (current_file < 0) {
167          current_file = 0;
168          errno = EIO;
169          result = -1;
170       }
171       atEOD = false;
172       atEOF = false;
173       atBOT = false;
174       open_file();
175       break;
176
177    case MTFSR:      /* Forward space over mt_count records (tape blocks). */
178 /*
179     file number = 1
180     block number = 0
181    
182     file number = 1
183     block number = 1
184    
185     mt: /dev/lto2: Erreur d'entrée/sortie
186    
187     file number = 2
188     block number = 0
189 */
190       /* tester si on se trouve a la fin du fichier */
191       lseek(cur_fd, SEEK_CUR, tape_info.block_size*mt_com->mt_count);
192       break;
193
194    case MTBSR:      /* Backward space over mt_count records (tape blocks). */
195       result = -1;
196       break;
197
198    case MTWEOF:                 /* Write mt_count filemarks. */
199       weof(mt_com->mt_count);
200       break;
201
202    case MTREW:                  /* Rewind. */
203       close_file();
204       atEOF = atEOD = false;
205       atBOT = true;
206       current_file = 0;
207       current_block = 0;
208       break;
209
210    case MTOFFL:                 /* put tape offline */
211       result = offline();
212       break;
213
214    case MTRETEN:                /* Re-tension tape. */
215       result = 0;
216       break;
217
218    case MTBSFM:                 /* not used by bacula */
219       errno = EIO;
220       result = -1;
221       break;
222
223    case MTFSFM:                 /* not used by bacula */
224       errno = EIO;
225       result = -1;
226       break;
227
228    case MTEOM:/* Go to the end of the recorded media (for appending files). */
229 /*
230    file number = 3
231    block number = -1
232 */
233       /* Can be at EOM */
234       atEOF = true;
235       current_block = -1;
236       /* Ne pas creer le fichier si on est a la fin */
237
238       break;
239
240    case MTERASE:
241       atEOD = true;
242       atEOF = false;
243       atEOT = false;
244       current_file = 0;
245       current_block = -1;
246       delete_files(current_file);
247       break;
248
249    case MTSETBLK:
250       break;
251
252    case MTSEEK:
253       break;
254
255    case MTTELL:
256       break;
257
258    case MTFSS:
259       break;
260
261    case MTBSS:
262       break;
263
264    case MTWSM:
265       break;
266
267    case MTLOCK:
268       break;
269
270    case MTUNLOCK:
271       break;
272
273    case MTLOAD:
274       break;
275
276    case MTUNLOAD:
277       break;
278
279    case MTCOMPRESSION:
280       break;
281
282    case MTSETPART:
283       break;
284
285    case MTMKPART:
286       break;
287    }
288 //
289 //   switch (result) {
290 //   case NO_ERROR:
291 //   case -1:   /* Error has already been translated into errno */
292 //      break;
293 //
294 //   default:
295 //   case ERROR_FILEMARK_DETECTED:
296 //      errno = EIO;
297 //      break;
298 //
299 //   case ERROR_END_OF_MEDIA:
300 //      errno = EIO;
301 //      break;
302 //
303 //   case ERROR_NO_DATA_DETECTED:
304 //      errno = EIO;
305 //      break;
306 //
307 //   case ERROR_NO_MEDIA_IN_DRIVE:
308 //      errno = ENOMEDIUM;
309 //      break;
310 //
311 //   case ERROR_INVALID_HANDLE:
312 //   case ERROR_ACCESS_DENIED:
313 //   case ERROR_LOCK_VIOLATION:
314 //      errno = EBADF;
315 //      break;
316 //   }
317 //
318    return result == 0 ? 0 : -1;
319 }
320
321 int faketape::tape_get(struct mtget *mt_get)
322 {
323    return 0;
324 }
325
326 int faketape::tape_pos(struct mtpos *mt_pos)
327 {
328    return 0;
329 }
330
331 int faketape::delete_files(int startfile)
332 {  
333    int cur,max=0;
334    char *p;
335    POOL_MEM tmp;
336    DIR *fp_dir;
337    struct dirent *dir;
338    struct stat statp;
339
340    Dmsg1(dbglevel, "delete_files %i\n", startfile);
341
342    fp_dir = opendir(this->volume);
343    if (!fp_dir) {
344       this->last_file=0;
345       this->size = 0;
346       return -1;
347    }
348
349    this->size = 0;
350
351    /* search for all digit files 
352     * and we remove all ones that are greater than
353     * startfile
354     */
355    while ((dir = readdir (fp_dir)) != NULL)
356    {
357       Mmsg(tmp, "%s/%s", this->volume, dir->d_name);
358       cur = 0;
359       /* check if d_name contains only digits */
360       for(p = dir->d_name; *p && isdigit(*p); p++)
361       {
362          cur *= 10;
363          cur += *p - '0';
364       }
365       if (!*p && cur > 0) {
366          if (cur >= startfile) { /* remove it */
367             unlink(tmp.c_str());
368          } else {
369             if (lstat(tmp.c_str(), &statp) == 0) {
370                this->size += statp.st_size;
371             }
372             max = (max > cur)?max:cur;
373          }
374       }
375    }
376
377    closedir(fp_dir);
378    this->last_file = max;
379    return max;
380 }
381
382 faketape::faketape()
383 {
384    fd = -1;
385    cur_fd = -1;
386
387    atEOF = false;
388    atBOT = false;
389    atEOT = false;
390    atEOD = false;
391    online = false;
392    
393    size = 0;
394    last_file = 0;
395    current_file = 0;
396    current_block = -1;
397    max_size = 10000000;
398
399    volume = get_pool_memory(PM_NAME);
400    cur_file = get_pool_memory(PM_NAME);
401    cur_info = get_pool_memory(PM_NAME);
402 }
403
404 faketape::~faketape()
405 {
406    free_pool_memory(volume);
407    free_pool_memory(cur_file);
408    free_pool_memory(cur_info);
409 }
410
411 int faketape::get_fd()
412 {
413    return this->fd;
414 }
415
416 int faketape::write(const void *buffer, unsigned int count)
417 {
418    unsigned int nb;
419    check_file();
420
421    if (atEOT) {
422       return 0;
423    }
424
425    current_block++;
426
427    atBOT = false;
428
429    /* TODO: remove all files > current_file and 
430     * remove blocks > current_block 
431     */
432    if (count + size > max_size) {
433       Dmsg2(dbglevel, 
434             "EOT writing only %i of %i requested\n", 
435             max_size - size, count);
436       count = max_size - size;
437       atEOT = true;
438    }
439
440    nb = ::write(cur_fd, buffer, count);
441    
442    if (nb != count) {
443       atEOT = true;
444       Dmsg2(dbglevel, 
445             "Not enough space writing only %i of %i requested\n", 
446             nb, count);
447    }
448
449    return nb;
450 }
451
452 int faketape::weof(int count)
453 {
454    if (atEOT) {
455       current_block = -1;
456       return -1;
457    }
458
459    count--;                     /* end this file */
460    ftruncate(cur_fd, lseek(cur_fd, 0, SEEK_CUR));
461    close_file();
462    current_file++;
463
464    /* we erase all previous information */
465    if (last_file > current_file) {
466       delete_files(current_file);
467    }
468
469    for (; count>0 ; count--) {
470       current_file++;
471       open_file();
472    }
473    current_block=0;
474    atEOF = true;
475    atEOD = false;
476    return 0;
477 }
478
479 int faketape::fsf(int count)
480 {
481
482 /*
483  * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
484  */
485
486    if (atEOT) {
487       current_block = -1;
488       return -1;
489    }
490
491    close_file();
492
493    if (current_file + count <= last_file) {
494       current_file += count;
495       current_block = 0;
496       return 0;
497    } else {
498       current_file = last_file;
499       current_block = -1;
500       atEOT=true;
501       return -1;
502    }
503 }
504
505 int faketape::bsf(int count)
506 {
507
508 /*
509  * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
510  */
511    close_file();
512    atEOT = atEOD = false;
513
514    if (current_file - count < 0) {
515       current_file = 0;
516       current_block = 0;
517       atBOT = true;
518       return -1;
519    }
520
521    current_file = current_file - count;
522    current_block = 0;
523    if (!current_file) {
524       atBOT = true;
525    }
526
527    return 1;
528 }
529
530 /* 
531  * Put faketape in offline mode
532  */
533 int faketape::offline()
534 {
535    ASSERT(cur_fd > 0);
536
537    close_file();
538
539    cur_fd = -1;
540    atEOF = false;
541    atEOT = false;
542    atEOD = false;
543    atBOT = false;
544
545    current_file = -1;
546    current_block = -1;
547    last_file = 0;
548    return 0;
549 }
550
551 int faketape::close_file()
552 {
553    if (cur_fd > 0) {
554       ::close(cur_fd);
555       cur_fd = -1;
556    }
557    return 0;
558 }
559
560 int faketape::close()
561 {
562    close_file();
563    ::close(fd);
564
565    return 0;
566 }
567 /*
568  **rb
569  **status
570  * EOF Bacula status: file=2 block=0
571  * Device status: EOF ONLINE IM_REP_EN file=2 block=0
572  **rb
573  **status
574  * EOD EOF Bacula status: file=2 block=0
575  * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
576  *
577  */
578
579 int faketape::read(void *buffer, unsigned int count)
580 {
581    unsigned int nb;
582    check_file();
583
584    if (atEOT || atEOD) {
585       return 0;
586    }
587
588    atBOT = false;
589
590    nb = ::read(cur_fd, buffer, count);
591    if (count != nb) {
592       atEOF = true;
593       if (current_file == last_file) {
594          atEOD = true;
595          current_block = -1;
596       }
597       Dmsg0(dbglevel, "EOF during reading\n");
598    }
599    return nb;
600 }
601
602 int faketape::read_volinfo()
603 {
604    struct stat statp;
605    memset(&tape_info, 0, sizeof(FTAPE_FORMAT));
606
607    Dmsg2(0, "read_volinfo %p %p\n", cur_info, volume);
608    Mmsg(cur_info, "%s/info", volume);
609    fd = ::open(cur_info, O_CREAT | O_RDWR | O_BINARY, 0640);
610    
611    if (fd < 0) {
612       return -1;
613    }
614    
615    fstat(fd, &statp);
616    
617    /* read volume info */
618    int nb = ::read(fd, &tape_info, sizeof(FTAPE_FORMAT));
619    if (nb != sizeof(FTAPE_FORMAT)) { /* new tape ? */
620       Dmsg1(dbglevel, "Initialize %s\n", volume);
621       tape_info.version = 1;
622       tape_info.block_max = 2000000;
623       tape_info.block_size = statp.st_blksize;
624       tape_info.max_file_mark = 2000;
625
626       lseek(fd, SEEK_SET, 0);
627       nb = ::write(fd, &tape_info, sizeof(FTAPE_FORMAT));
628
629       if (nb != sizeof(FTAPE_FORMAT)) {
630          ::close(fd);
631          return -1;
632       }
633    }
634
635    Dmsg0(dbglevel, "read_volinfo OK\n");
636    find_maxfile();
637
638    return fd;
639 }
640
641 int faketape::open(const char *pathname, int uflags, int umode)
642 {
643    Dmsg3(dbglevel, "faketape::open(%s, %i, %i)\n", pathname, uflags, umode);
644    pm_strcpy(volume, pathname);
645
646    struct stat statp;   
647    if (lstat(volume, &statp) != 0) {
648       Dmsg1(dbglevel, "Can't stat on %s\n", volume);
649       return -1;
650    }
651
652    if (!S_ISDIR(statp.st_mode)) {
653       Dmsg1(dbglevel, "%s is not a directory\n", volume);
654       errno = EACCES;
655       return -1;
656    }
657
658    /* open volume descriptor and get this->fd */
659    if (read_volinfo() < 0) {
660       return -1;
661    }
662
663    current_block=-1;
664
665    return fd;
666 }
667
668 int faketape::find_maxfile()
669 {
670    int max=0;
671    int cur;
672    char *p;
673    POOL_MEM tmp;
674    DIR *fp_dir;
675    struct dirent *dir;
676    struct stat statp;
677
678    fp_dir = opendir(this->volume);
679    if (!fp_dir) {
680       last_file=0;
681       return -1;
682    }
683
684    this->size = 0;
685
686    /* search for all digit file */
687    while ((dir = readdir (fp_dir)) != NULL)
688    {
689       Mmsg(tmp, "%s/%s", this->volume, dir->d_name);
690       if (lstat(tmp.c_str(), &statp) == 0) {
691          this->size += statp.st_size;
692       } else {
693          Dmsg1(dbglevel, "Can't stat %s\n", tmp.c_str());
694       }
695       cur = 0;
696       /* TODO: compute size */
697       for(p = dir->d_name; *p && isdigit(*p); p++)
698       {
699          cur *= 10;
700          cur += *p;
701       }
702       if (!*p && cur) {
703          max = (max > cur)?max:cur;
704       }
705    }
706
707    closedir(fp_dir);
708    this->last_file = max;
709    return max;
710 }
711
712 int faketape::open_file() 
713 {
714    ASSERT(current_file >= 0);
715    if (cur_fd > 0) {
716       ::close(cur_fd);
717    }
718
719    Mmsg(cur_file, "%s/%i", volume, current_file);
720    cur_fd = ::open(cur_file, O_CREAT | O_RDWR | O_BINARY, 0640);
721    if (cur_fd < 0) {
722       return -1;
723    }
724    current_block = 0;
725    last_file = (last_file > current_file)?last_file:current_file;
726
727    Dmsg1(dbglevel, "open_file %s %i\n", cur_file);
728
729    return cur_fd;
730
731 }
732
733 void faketape::dump()
734 {
735    Dmsg0(dbglevel, "===================\n");
736    Dmsg1(dbglevel, "last_file=%i\n", last_file);
737    Dmsg1(dbglevel, "current_file=%i\n", current_file);
738    Dmsg1(dbglevel, "volume=%s\n", volume);
739    Dmsg1(dbglevel, "cur_file=%s\n", cur_file);  
740    Dmsg1(dbglevel, "size=%i\n", size);  
741    Dmsg1(dbglevel, "EOF=%i\n", atEOF);  
742    Dmsg1(dbglevel, "EOT=%i\n", atEOT);  
743    Dmsg1(dbglevel, "EOD=%i\n", atEOD);  
744 }
745
746 /****************************************************************
747
748 #define GMT_EOF(x)              ((x) & 0x80000000)
749 #define GMT_BOT(x)              ((x) & 0x40000000)
750 #define GMT_EOT(x)              ((x) & 0x20000000)
751 #define GMT_SM(x)               ((x) & 0x10000000)
752 #define GMT_EOD(x)              ((x) & 0x08000000)
753
754
755  GMT_EOF(x) : La bande est positionnée juste après une filemark (toujours faux
756      après une opération MTSEEK).
757
758  GMT_BOT(x) : La bande est positionnée juste au début du premier fichier
759      (toujours faux après une opération MTSEEK).
760  
761  GMT_EOT(x) : Une opération a atteint la fin physique de la bande (End Of
762  Tape).
763
764  GMT_SM(x) : La bande est positionnée sur une setmark (toujours faux après une
765  opération MTSEEK).
766
767  GMT_EOD(x) : La bande est positionnée à la fin des données enregistrées.
768
769
770 blkno = -1 (after MTBSF MTBSS or MTSEEK)
771 fileno = -1 (after MTBSS or MTSEEK)
772
773 *** mtx load
774 drive type = Generic SCSI-2 tape
775 drive status = 0
776 sense key error = 0
777 residue count = 0
778 file number = 0
779 block number = 0
780 Tape block size 0 bytes. Density code 0x0 (default).
781 Soft error count since last status=0
782 General status bits on (41010000):
783  BOT ONLINE IM_REP_EN
784
785 *** read empty block
786 dd if=/dev/lto2 of=/tmp/toto count=1
787 dd: lecture de `/dev/lto2': Ne peut allouer de la mémoire
788 0+0 enregistrements lus
789 0+0 enregistrements écrits
790 1 octet (1B) copié, 4,82219 seconde, 0,0 kB/s
791
792 file number = 0
793 block number = 1
794
795 *** read file mark
796 dd if=/dev/lto2 of=/tmp/toto count=1
797 0+0 enregistrements lus
798 0+0 enregistrements écrits
799 1 octet (1B) copié, 0,167274 seconde, 0,0 kB/s
800
801 file number = 1
802 block number = 0
803
804  *** write 2 blocks after rewind
805 dd if=/dev/zero of=/dev/lto2 count=2
806 2+0 enregistrements lus
807 2+0 enregistrements écrits
808 1024 octets (1,0 kB) copiés, 6,57402 seconde, 0,2 kB/s
809
810 file number = 1
811 block number = 0
812
813 *** write 2 blocks
814 file number = 2
815 block number = 0
816
817 *** rewind and fsr
818 file number = 0
819 block number = 1
820
821 *** rewind and 2x fsr (we have just 2 blocks)
822 file number = 0
823 block number = 2
824
825 *** fsr
826 mt: /dev/lto2: Erreur
827 file number = 1
828 block number = 0
829
830
831  ****************************************************************/
832
833
834 #ifdef TEST
835
836 int main()
837 {
838    int fd;
839    printf("Starting FakeTape\n");
840
841    mkdir("/tmp/fake", 0777);
842    fd = faketape_open("/tmp/fake", O_CREAT | O_RDWR | O_BINARY, 0666);
843    if (fd < 0) {
844       perror("open ERR");
845       return 1;
846    }
847
848    faketape *tape = get_tape(fd);
849    tape->write("test", strlen("test")+1);
850    tape->write("test", strlen("test")+1);
851    tape->dump();
852
853    tape->weof(1);
854    tape->write("test", strlen("test")+1);
855    tape->write("test", strlen("test")+1);   
856    tape->dump();
857    tape->fsf(2);
858    tape->dump();
859    faketape_close(fd);
860
861    return 0;
862 }
863
864 #endif