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.
30 * Maximum File Size = 800M
39 static int dbglevel = 10;
40 #define FILE_OFFSET 30
41 faketape *ftape_list[FTAPE_MAX_DRIVE];
43 static faketape *get_tape(int fd)
47 if (fd >= FTAPE_MAX_DRIVE) {
52 return ftape_list[fd];
55 static bool put_tape(faketape *ftape)
57 ASSERT(ftape != NULL);
59 int fd = ftape->get_fd();
60 if (fd >= FTAPE_MAX_DRIVE) {
64 ftape_list[fd] = ftape;
68 void faketape_debug(int level)
73 /****************************************************************/
74 /* theses function will replace open/read/write/close/ioctl
77 int faketape_open(const char *pathname, int flags)
79 ASSERT(pathname != NULL);
82 faketape *tape = new faketape();
83 fd = tape->open(pathname, flags);
90 int faketape_read(int fd, void *buffer, unsigned int count)
92 faketape *tape = get_tape(fd);
94 return tape->read(buffer, count);
97 int faketape_write(int fd, const void *buffer, unsigned int count)
99 faketape *tape = get_tape(fd);
100 ASSERT(tape != NULL);
101 return tape->write(buffer, count);
104 int faketape_close(int fd)
106 faketape *tape = get_tape(fd);
107 ASSERT(tape != NULL);
113 int faketape_ioctl(int fd, unsigned long int request, ...)
118 faketape *t = get_tape(fd);
124 va_start(argp, request);
126 if (request == MTIOCTOP) {
127 result = t->tape_op(va_arg(argp, mtop *));
128 } else if (request == MTIOCGET) {
129 result = t->tape_get(va_arg(argp, mtget *));
133 // result = tape_pos(fd, va_arg(argp, mtpos *));
145 /****************************************************************/
147 int faketape::tape_op(struct mtop *mt_com)
151 switch (mt_com->mt_op)
167 case MTFSF: /* Forward space over mt_count filemarks. */
168 result = fsf(mt_com->mt_count);
171 case MTBSF: /* Backward space over mt_count filemarks. */
172 result = bsf(mt_com->mt_count);
175 case MTFSR: /* Forward space over mt_count records (tape blocks). */
183 mt: /dev/lto2: Erreur d'entrée/sortie
188 /* tester si on se trouve a la fin du fichier */
189 result = fsr(mt_com->mt_count);
192 case MTBSR: /* Backward space over mt_count records (tape blocks). */
193 result = bsr(mt_com->mt_count);
196 case MTWEOF: /* Write mt_count filemarks. */
197 result = weof(mt_com->mt_count);
200 case MTREW: /* Rewind. */
201 Dmsg0(dbglevel, "rewind faketape\n");
202 atEOF = atEOD = false;
209 case MTOFFL: /* put tape offline */
213 case MTRETEN: /* Re-tension tape. */
217 case MTBSFM: /* not used by bacula */
222 case MTFSFM: /* not used by bacula */
227 case MTEOM:/* Go to the end of the recorded media (for appending files). */
238 current_file = last_file;
243 case MTERASE: /* not used by bacula */
296 // case -1: /* Error has already been translated into errno */
300 // case ERROR_FILEMARK_DETECTED:
304 // case ERROR_END_OF_MEDIA:
308 // case ERROR_NO_DATA_DETECTED:
312 // case ERROR_NO_MEDIA_IN_DRIVE:
313 // errno = ENOMEDIUM;
316 // case ERROR_INVALID_HANDLE:
317 // case ERROR_ACCESS_DENIED:
318 // case ERROR_LOCK_VIOLATION:
323 return result == 0 ? 0 : -1;
326 int faketape::tape_get(struct mtget *mt_get)
329 int block_size = 1024;
331 mt_get->mt_type = MT_ISSCSI2;
332 mt_get->mt_blkno = current_block;
333 mt_get->mt_fileno = current_file;
335 mt_get->mt_resid = -1;
336 // pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
340 ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
341 ((block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
344 mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
347 mt_get->mt_gstat |= 0x80000000; // GMT_EOF
351 mt_get->mt_gstat |= 0x40000000; // GMT_BOT
354 mt_get->mt_gstat |= 0x20000000; // GMT_EOT
358 mt_get->mt_gstat |= 0x08000000; // GMT_EOD
361 if (0) { //WriteProtected) {
362 mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
366 mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
368 mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
370 mt_get->mt_erreg = 0;
375 int faketape::tape_pos(struct mtpos *mt_pos)
381 * This function try to emulate the append only behavior
382 * of a tape. When you wrote something, data after the
383 * current position are discarded.
385 int faketape::truncate_file()
387 Dmsg2(dbglevel, "truncate %i:%i\n", current_file, current_block);
388 ftruncate(fd, lseek(fd, 0, SEEK_CUR));
389 last_file = current_file;
412 max_block = 1024*1024*1024*1024*8;
414 volume = get_pool_memory(PM_NAME);
417 faketape::~faketape()
419 free_pool_memory(volume);
422 int faketape::get_fd()
428 * TODO: regarder si apres un write une operation x pose un EOF
430 int faketape::write(const void *buffer, unsigned int count)
432 ASSERT(current_file >= 0);
437 Dmsg3(dbglevel, "write len=%i %i:%i\n", count, current_file,current_block);
440 Dmsg0(dbglevel, "write nothing, EOT !\n");
449 if (!atEOD) { /* if not at the end of the data */
453 if (current_block != -1) {
459 atEOD = true; /* End of data */
461 needEOF = true; /* next operation need EOF mark */
463 // if ((count + file_size) > max_size) {
465 // "EOT writing only %i of %i requested\n",
466 // max_size - file_size, count);
467 // count = max_size - file_size;
471 uint32_t size = count;
472 ::write(fd, &size, sizeof(uint32_t));
473 nb = ::write(fd, buffer, count);
475 file_size += sizeof(uint32_t) + nb;
480 "Not enough space writing only %i of %i requested\n",
487 int faketape::weof(int count)
489 ASSERT(current_file >= 0);
490 Dmsg3(dbglevel, "Writing EOF %i:%i last=%i\n",
491 current_file, current_block,last_file);
497 truncate_file(); /* nothing after this point */
499 /* TODO: check this */
500 current_file += count;
505 ::write(fd, &c, sizeof(uint32_t));
515 int faketape::fsf(int count)
517 ASSERT(current_file >= 0);
520 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
530 atBOT = atEOF = false;
531 Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
533 if ((current_file + count) <= last_file) {
534 current_file += count;
538 Dmsg0(dbglevel, "Try to FSF after EOT\n");
539 current_file = last_file ;
549 int faketape::fsr(int count)
551 ASSERT(current_file >= 0);
557 Dmsg3(dbglevel, "fsr %i:%i count=%i\n", current_file,current_block, count);
572 atBOT = atEOF = false;
574 /* check all block record */
575 for(i=0; (i < count) && !atEOF ; i++) {
576 nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
577 if (nb == sizeof(uint32_t) && s) {
579 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
581 Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
582 current_file, current_block, nb,s);
585 if (current_file < last_file) {
590 atEOF = true; /* stop the loop */
594 find_maxfile(); /* refresh stats */
596 if (where == file_size) {
602 // TODO: Make it working, at this time we get only the EOF position...
603 int faketape::bsr(int count)
605 Dmsg2(dbglevel, "bsr current_block=%i count=%i\n",
606 current_block, count);
608 ASSERT(current_file >= 0);
623 off_t last=-1, last2=-1;
624 off_t orig = lseek(fd, 0, SEEK_CUR);
625 int orig_f = current_file;
626 int orig_b = current_block;
634 last = lseek(fd, 0, SEEK_CUR);
635 last_f = current_file;
636 last_b = current_block;
637 Dmsg5(dbglevel, "EOF=%i last=%lli orig=%lli %i:%i\n", atEOF, last, orig, current_file, current_block);
640 } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
642 if (last2 > 0 && atEOF) { /* we take the previous position */
643 lseek(fd, last2, SEEK_SET);
644 current_file = last_f;
645 current_block = last_b - 1;
646 Dmsg3(dbglevel, "set offset2=%lli %i:%i\n",
647 last, current_file, current_block);
649 } else if (last > 0) {
650 lseek(fd, last, SEEK_SET);
651 current_file = last_f;
652 current_block = last_b;
653 Dmsg3(dbglevel, "set offset=%lli %i:%i\n",
654 last, current_file, current_block);
656 lseek(fd, orig, SEEK_SET);
657 current_file = orig_f;
658 current_block = orig_b;
662 Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
663 atEOT = atEOF = atEOD = false;
668 //int faketape::read_eof()
671 // off_t old = lseek(fd, 0, SEEK_CUR);
672 // nb = ::read(fd, &s, sizeof(s));
673 // if (nb >= 0 && (nb != sizeof(s) || !s)) { /* EOF */
676 // lseek(fd, old, SEEK_SET);
680 int faketape::bsf(int count)
682 ASSERT(current_file >= 0);
683 Dmsg3(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block, count);
687 atBOT = atEOF = atEOT = atEOD = false;
689 if (current_file - count < 0) {
696 current_file = current_file - count + 1;
700 /* go just before last EOF */
701 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
707 * Put faketape in offline mode
709 int faketape::offline()
714 atEOF = false; /* End of file */
715 atEOT = false; /* End of tape */
716 atEOD = false; /* End of data */
717 atBOT = false; /* Begin of tape */
725 int faketape::close()
735 * EOF Bacula status: file=2 block=0
736 * Device status: EOF ONLINE IM_REP_EN file=2 block=0
739 * EOD EOF Bacula status: file=2 block=0
740 * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
744 int faketape::read(void *buffer, unsigned int count)
746 ASSERT(current_file >= 0);
750 Dmsg2(dbglevel, "read %i:%i\n", current_file, current_block);
752 if (atEOT || atEOD) {
767 atEOD = atBOT = false;
770 nb = ::read(fd, &s, sizeof(uint32_t));
775 if (s > count) { /* not enough buffer to read block */
776 lseek(fd, s, SEEK_CUR);
782 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
785 nb = ::read(fd, buffer, s);
788 if (current_file == last_file) {
792 Dmsg0(dbglevel, "EOF during reading\n");
797 int faketape::open(const char *pathname, int uflags)
799 Dmsg2(dbglevel, "faketape::open(%s, %i)\n", pathname, uflags);
800 pm_strcpy(volume, pathname);
803 if (stat(volume, &statp) != 0) {
804 Dmsg1(dbglevel, "Can't stat on %s\n", volume);
808 fd = ::open(pathname, O_CREAT | O_RDWR, 0700);
813 /* open volume descriptor and get this->fd */
814 if (find_maxfile() < 0) {
821 online = inplace = true;
823 atEOT = atEOD = false;
829 * read volume to get the last file number
831 int faketape::find_maxfile()
834 if (fstat(fd, &statp) != 0) {
837 last_file = statp.st_size>>FILE_OFFSET;
838 file_size = statp.st_size;
840 current_pos = lseek(fd, 0, SEEK_CUR); /* get current position */
841 Dmsg3(dbglevel+1, "last_file=%i file_size=%u current_pos=%i\n",
842 last_file, file_size, current_pos);
847 int faketape::seek_file()
849 ASSERT(current_file >= 0);
850 Dmsg2(dbglevel, "seek_file %i:%i\n", current_file, current_block);
852 off_t pos = ((off_t)current_file)<<FILE_OFFSET;
853 if(lseek(fd, pos, SEEK_SET) == -1) {
856 if (current_block > 0) {
859 last_file = (last_file > current_file)?last_file:current_file;
865 void faketape::dump()
867 Dmsg0(dbglevel+1, "===================\n");
868 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
869 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
870 Dmsg1(dbglevel+1, "volume=%s\n", volume);
871 Dmsg1(dbglevel+1, "file_size=%i\n", file_size);
872 Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n",
873 atEOF, atEOT, atEOD, atBOT);
876 /****************************************************************
878 #define GMT_EOF(x) ((x) & 0x80000000)
879 #define GMT_BOT(x) ((x) & 0x40000000)
880 #define GMT_EOT(x) ((x) & 0x20000000)
881 #define GMT_SM(x) ((x) & 0x10000000)
882 #define GMT_EOD(x) ((x) & 0x08000000)
885 GMT_EOF(x) : La bande est positionnée juste après une filemark (toujours faux
886 après une opération MTSEEK).
888 GMT_BOT(x) : La bande est positionnée juste au début du premier fichier
889 (toujours faux après une opération MTSEEK).
891 GMT_EOT(x) : Une opération a atteint la fin physique de la bande (End Of
894 GMT_SM(x) : La bande est positionnée sur une setmark (toujours faux après une
897 GMT_EOD(x) : La bande est positionnée à la fin des données enregistrées.
900 blkno = -1 (after MTBSF MTBSS or MTSEEK)
901 fileno = -1 (after MTBSS or MTSEEK)
904 drive type = Generic SCSI-2 tape
910 Tape block size 0 bytes. Density code 0x0 (default).
911 Soft error count since last status=0
912 General status bits on (41010000):
916 dd if=/dev/lto2 of=/tmp/toto count=1
917 dd: lecture de `/dev/lto2': Ne peut allouer de la mémoire
918 0+0 enregistrements lus
919 0+0 enregistrements écrits
920 1 octet (1B) copié, 4,82219 seconde, 0,0 kB/s
926 dd if=/dev/lto2 of=/tmp/toto count=1
927 0+0 enregistrements lus
928 0+0 enregistrements écrits
929 1 octet (1B) copié, 0,167274 seconde, 0,0 kB/s
934 *** write 2 blocks after rewind
935 dd if=/dev/zero of=/dev/lto2 count=2
936 2+0 enregistrements lus
937 2+0 enregistrements écrits
938 1024 octets (1,0 kB) copiés, 6,57402 seconde, 0,2 kB/s
951 *** rewind and 2x fsr (we have just 2 blocks)
956 mt: /dev/lto2: Erreur
961 ****************************************************************/
970 printf("Starting FakeTape\n");
972 mkdir("/tmp/fake", 0700);