2 Bacula® - The Network Backup Solution
4 Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
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.
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.
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
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.
33 Maximum File Size = 800M
34 Maximum Volume Size = 3G
36 Archive Device = /tmp/fake
38 AutomaticMount = yes; # when device opened, read it
51 static int dbglevel = 10;
52 #define FILE_OFFSET 30
53 faketape *ftape_list[FTAPE_MAX_DRIVE];
55 static faketape *get_tape(int fd)
59 if (fd >= FTAPE_MAX_DRIVE) {
64 return ftape_list[fd];
67 static bool put_tape(faketape *ftape)
69 ASSERT(ftape != NULL);
71 int fd = ftape->get_fd();
72 if (fd >= FTAPE_MAX_DRIVE) {
76 ftape_list[fd] = ftape;
80 void faketape_debug(int level)
85 /****************************************************************/
86 /* theses function will replace open/read/write/close/ioctl
89 int faketape_open(const char *pathname, int flags)
91 ASSERT(pathname != NULL);
94 faketape *tape = new faketape();
95 fd = tape->open(pathname, flags);
102 int faketape_read(int fd, void *buffer, unsigned int count)
104 faketape *tape = get_tape(fd);
105 ASSERT(tape != NULL);
106 return tape->read(buffer, count);
109 int faketape_write(int fd, const void *buffer, unsigned int count)
111 faketape *tape = get_tape(fd);
112 ASSERT(tape != NULL);
113 return tape->write(buffer, count);
116 int faketape_close(int fd)
118 faketape *tape = get_tape(fd);
119 ASSERT(tape != NULL);
125 int faketape_ioctl(int fd, unsigned long int request, ...)
130 faketape *t = get_tape(fd);
136 va_start(argp, request);
138 if (request == MTIOCTOP) {
139 result = t->tape_op(va_arg(argp, mtop *));
140 } else if (request == MTIOCGET) {
141 result = t->tape_get(va_arg(argp, mtget *));
142 } else if (request == MTIOCPOS) {
143 result = t->tape_pos(va_arg(argp, mtpos *));
153 /****************************************************************/
155 int faketape::tape_op(struct mtop *mt_com)
159 switch (mt_com->mt_op)
175 case MTFSF: /* Forward space over mt_count filemarks. */
176 result = fsf(mt_com->mt_count);
179 case MTBSF: /* Backward space over mt_count filemarks. */
180 result = bsf(mt_com->mt_count);
183 case MTFSR: /* Forward space over mt_count records (tape blocks). */
191 mt: /dev/lto2: Erreur d'entrée/sortie
196 /* tester si on se trouve a la fin du fichier */
197 result = fsr(mt_com->mt_count);
200 case MTBSR: /* Backward space over mt_count records (tape blocks). */
201 result = bsr(mt_com->mt_count);
204 case MTWEOF: /* Write mt_count filemarks. */
205 result = weof(mt_com->mt_count);
208 case MTREW: /* Rewind. */
209 Dmsg0(dbglevel, "rewind faketape\n");
210 atEOF = atEOD = false;
217 case MTOFFL: /* put tape offline */
221 case MTRETEN: /* Re-tension tape. */
225 case MTBSFM: /* not used by bacula */
230 case MTFSFM: /* not used by bacula */
235 case MTEOM:/* Go to the end of the recorded media (for appending files). */
246 current_file = last_file;
251 case MTERASE: /* not used by bacula */
304 // case -1: /* Error has already been translated into errno */
308 // case ERROR_FILEMARK_DETECTED:
312 // case ERROR_END_OF_MEDIA:
316 // case ERROR_NO_DATA_DETECTED:
320 // case ERROR_NO_MEDIA_IN_DRIVE:
321 // errno = ENOMEDIUM;
324 // case ERROR_INVALID_HANDLE:
325 // case ERROR_ACCESS_DENIED:
326 // case ERROR_LOCK_VIOLATION:
331 return result == 0 ? 0 : -1;
334 int faketape::tape_get(struct mtget *mt_get)
337 int block_size = 1024;
339 mt_get->mt_type = MT_ISSCSI2;
340 mt_get->mt_blkno = current_block;
341 mt_get->mt_fileno = current_file;
343 mt_get->mt_resid = -1;
344 // pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
348 ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
349 ((block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
352 mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
355 mt_get->mt_gstat |= 0x80000000; // GMT_EOF
359 mt_get->mt_gstat |= 0x40000000; // GMT_BOT
362 mt_get->mt_gstat |= 0x20000000; // GMT_EOT
366 mt_get->mt_gstat |= 0x08000000; // GMT_EOD
369 if (0) { //WriteProtected) {
370 mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
374 mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
376 mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
378 mt_get->mt_erreg = 0;
383 int faketape::tape_pos(struct mtpos *mt_pos)
385 if (current_block >= 0) {
386 mt_pos->mt_blkno = current_block;
394 * This function try to emulate the append only behavior
395 * of a tape. When you wrote something, data after the
396 * current position are discarded.
398 int faketape::truncate_file()
400 Dmsg2(dbglevel, "truncate %i:%i\n", current_file, current_block);
401 ftruncate(fd, lseek(fd, 0, SEEK_CUR));
402 last_file = current_file;
425 max_block = 1024*1024*1024*1024*8;
427 volume = get_pool_memory(PM_NAME);
430 faketape::~faketape()
432 free_pool_memory(volume);
435 int faketape::get_fd()
441 * TODO: regarder si apres un write une operation x pose un EOF
443 int faketape::write(const void *buffer, unsigned int count)
445 ASSERT(current_file >= 0);
450 Dmsg3(dbglevel, "write len=%i %i:%i\n", count, current_file,current_block);
453 Dmsg0(dbglevel, "write nothing, EOT !\n");
462 if (!atEOD) { /* if not at the end of the data */
466 if (current_block != -1) {
472 atEOD = true; /* End of data */
474 needEOF = true; /* next operation need EOF mark */
476 // if ((count + file_size) > max_size) {
478 // "EOT writing only %i of %i requested\n",
479 // max_size - file_size, count);
480 // count = max_size - file_size;
484 uint32_t size = count;
485 ::write(fd, &size, sizeof(uint32_t));
486 nb = ::write(fd, buffer, count);
488 file_size += sizeof(uint32_t) + nb;
493 "Not enough space writing only %i of %i requested\n",
500 int faketape::weof(int count)
502 ASSERT(current_file >= 0);
503 Dmsg3(dbglevel, "Writing EOF %i:%i last=%i\n",
504 current_file, current_block,last_file);
510 truncate_file(); /* nothing after this point */
512 /* TODO: check this */
513 current_file += count;
518 ::write(fd, &c, sizeof(uint32_t));
528 int faketape::fsf(int count)
530 ASSERT(current_file >= 0);
533 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
543 atBOT = atEOF = false;
544 Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
546 if ((current_file + count) <= last_file) {
547 current_file += count;
551 Dmsg0(dbglevel, "Try to FSF after EOT\n");
552 current_file = last_file ;
562 int faketape::fsr(int count)
564 ASSERT(current_file >= 0);
570 Dmsg3(dbglevel, "fsr %i:%i count=%i\n", current_file,current_block, count);
585 atBOT = atEOF = false;
587 /* check all block record */
588 for(i=0; (i < count) && !atEOF ; i++) {
589 nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
590 if (nb == sizeof(uint32_t) && s) {
592 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
594 Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
595 current_file, current_block, nb,s);
598 if (current_file < last_file) {
603 atEOF = true; /* stop the loop */
607 find_maxfile(); /* refresh stats */
609 if (where == file_size) {
615 // TODO: Make it working, at this time we get only the EOF position...
616 int faketape::bsr(int count)
618 Dmsg2(dbglevel, "bsr current_block=%i count=%i\n",
619 current_block, count);
621 ASSERT(current_file >= 0);
636 off_t last=-1, last2=-1;
637 off_t orig = lseek(fd, 0, SEEK_CUR);
638 int orig_f = current_file;
639 int orig_b = current_block;
647 last = lseek(fd, 0, SEEK_CUR);
648 last_f = current_file;
649 last_b = current_block;
650 Dmsg5(dbglevel, "EOF=%i last=%lli orig=%lli %i:%i\n", atEOF, last, orig, current_file, current_block);
653 } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
655 if (last2 > 0 && atEOF) { /* we take the previous position */
656 lseek(fd, last2, SEEK_SET);
657 current_file = last_f;
658 current_block = last_b - 1;
659 Dmsg3(dbglevel, "set offset2=%lli %i:%i\n",
660 last, current_file, current_block);
662 } else if (last > 0) {
663 lseek(fd, last, SEEK_SET);
664 current_file = last_f;
665 current_block = last_b;
666 Dmsg3(dbglevel, "set offset=%lli %i:%i\n",
667 last, current_file, current_block);
669 lseek(fd, orig, SEEK_SET);
670 current_file = orig_f;
671 current_block = orig_b;
675 Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
676 atEOT = atEOF = atEOD = false;
681 //int faketape::read_eof()
684 // off_t old = lseek(fd, 0, SEEK_CUR);
685 // nb = ::read(fd, &s, sizeof(s));
686 // if (nb >= 0 && (nb != sizeof(s) || !s)) { /* EOF */
689 // lseek(fd, old, SEEK_SET);
693 int faketape::bsf(int count)
695 ASSERT(current_file >= 0);
696 Dmsg3(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block, count);
700 atBOT = atEOF = atEOT = atEOD = false;
702 if (current_file - count < 0) {
709 current_file = current_file - count + 1;
713 /* go just before last EOF */
714 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
720 * Put faketape in offline mode
722 int faketape::offline()
727 atEOF = false; /* End of file */
728 atEOT = false; /* End of tape */
729 atEOD = false; /* End of data */
730 atBOT = false; /* Begin of tape */
738 int faketape::close()
748 * EOF Bacula status: file=2 block=0
749 * Device status: EOF ONLINE IM_REP_EN file=2 block=0
752 * EOD EOF Bacula status: file=2 block=0
753 * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
757 int faketape::read(void *buffer, unsigned int count)
759 ASSERT(current_file >= 0);
763 Dmsg2(dbglevel, "read %i:%i\n", current_file, current_block);
765 if (atEOT || atEOD) {
780 atEOD = atBOT = false;
783 nb = ::read(fd, &s, sizeof(uint32_t));
788 if (s > count) { /* not enough buffer to read block */
789 lseek(fd, s, SEEK_CUR);
795 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
798 nb = ::read(fd, buffer, s);
801 if (current_file == last_file) {
805 Dmsg0(dbglevel, "EOF during reading\n");
810 int faketape::open(const char *pathname, int uflags)
812 Dmsg2(dbglevel, "faketape::open(%s, %i)\n", pathname, uflags);
813 pm_strcpy(volume, pathname);
816 if (stat(volume, &statp) != 0) {
817 Dmsg1(dbglevel, "Can't stat on %s\n", volume);
821 fd = ::open(pathname, O_CREAT | O_RDWR, 0700);
826 /* open volume descriptor and get this->fd */
827 if (find_maxfile() < 0) {
834 online = inplace = true;
836 atEOT = atEOD = false;
842 * read volume to get the last file number
844 int faketape::find_maxfile()
847 if (fstat(fd, &statp) != 0) {
850 last_file = statp.st_size>>FILE_OFFSET;
851 file_size = statp.st_size;
853 current_pos = lseek(fd, 0, SEEK_CUR); /* get current position */
854 Dmsg3(dbglevel+1, "last_file=%i file_size=%u current_pos=%i\n",
855 last_file, file_size, current_pos);
860 int faketape::seek_file()
862 ASSERT(current_file >= 0);
863 Dmsg2(dbglevel, "seek_file %i:%i\n", current_file, current_block);
865 off_t pos = ((off_t)current_file)<<FILE_OFFSET;
866 if(lseek(fd, pos, SEEK_SET) == -1) {
869 if (current_block > 0) {
872 last_file = (last_file > current_file)?last_file:current_file;
878 void faketape::dump()
880 Dmsg0(dbglevel+1, "===================\n");
881 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
882 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
883 Dmsg1(dbglevel+1, "volume=%s\n", volume);
884 Dmsg1(dbglevel+1, "file_size=%i\n", file_size);
885 Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n",
886 atEOF, atEOT, atEOD, atBOT);
889 /****************************************************************
891 #define GMT_EOF(x) ((x) & 0x80000000)
892 #define GMT_BOT(x) ((x) & 0x40000000)
893 #define GMT_EOT(x) ((x) & 0x20000000)
894 #define GMT_SM(x) ((x) & 0x10000000)
895 #define GMT_EOD(x) ((x) & 0x08000000)
898 GMT_EOF(x) : La bande est positionnée juste après une filemark (toujours faux
899 après une opération MTSEEK).
901 GMT_BOT(x) : La bande est positionnée juste au début du premier fichier
902 (toujours faux après une opération MTSEEK).
904 GMT_EOT(x) : Une opération a atteint la fin physique de la bande (End Of
907 GMT_SM(x) : La bande est positionnée sur une setmark (toujours faux après une
910 GMT_EOD(x) : La bande est positionnée à la fin des données enregistrées.
913 blkno = -1 (after MTBSF MTBSS or MTSEEK)
914 fileno = -1 (after MTBSS or MTSEEK)
917 drive type = Generic SCSI-2 tape
923 Tape block size 0 bytes. Density code 0x0 (default).
924 Soft error count since last status=0
925 General status bits on (41010000):
929 dd if=/dev/lto2 of=/tmp/toto count=1
930 dd: lecture de `/dev/lto2': Ne peut allouer de la mémoire
931 0+0 enregistrements lus
932 0+0 enregistrements écrits
933 1 octet (1B) copié, 4,82219 seconde, 0,0 kB/s
939 dd if=/dev/lto2 of=/tmp/toto count=1
940 0+0 enregistrements lus
941 0+0 enregistrements écrits
942 1 octet (1B) copié, 0,167274 seconde, 0,0 kB/s
947 *** write 2 blocks after rewind
948 dd if=/dev/zero of=/dev/lto2 count=2
949 2+0 enregistrements lus
950 2+0 enregistrements écrits
951 1024 octets (1,0 kB) copiés, 6,57402 seconde, 0,2 kB/s
964 *** rewind and 2x fsr (we have just 2 blocks)
969 mt: /dev/lto2: Erreur
974 ****************************************************************/
983 printf("Starting FakeTape\n");
985 mkdir("/tmp/fake", 0700);