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
60 #include "bacula.h" /* define 64bit file usage */
66 static int dbglevel = 100;
67 #define FILE_OFFSET 30
68 faketape *ftape_list[FTAPE_MAX_DRIVE];
70 static faketape *get_tape(int fd)
74 if (fd >= FTAPE_MAX_DRIVE) {
79 return ftape_list[fd];
82 static bool put_tape(faketape *ftape)
84 ASSERT(ftape != NULL);
86 int fd = ftape->get_fd();
87 if (fd >= FTAPE_MAX_DRIVE) {
91 ftape_list[fd] = ftape;
95 void faketape_debug(int level)
100 /****************************************************************/
101 /* theses function will replace open/read/write/close/ioctl
104 int faketape_open(const char *pathname, int flags, ...)
106 ASSERT(pathname != NULL);
109 faketape *tape = new faketape();
110 fd = tape->open(pathname, flags);
117 int faketape_read(int fd, void *buffer, unsigned int count)
119 faketape *tape = get_tape(fd);
120 ASSERT(tape != NULL);
121 return tape->read(buffer, count);
124 int faketape_write(int fd, const void *buffer, unsigned int count)
126 faketape *tape = get_tape(fd);
127 ASSERT(tape != NULL);
128 return tape->write(buffer, count);
131 int faketape_close(int fd)
133 faketape *tape = get_tape(fd);
134 ASSERT(tape != NULL);
140 int faketape_ioctl(int fd, unsigned long int request, ...)
145 faketape *t = get_tape(fd);
151 va_start(argp, request);
153 if (request == MTIOCTOP) {
154 result = t->tape_op(va_arg(argp, mtop *));
155 } else if (request == MTIOCGET) {
156 result = t->tape_get(va_arg(argp, mtget *));
157 } else if (request == MTIOCPOS) {
158 result = t->tape_pos(va_arg(argp, mtpos *));
168 /****************************************************************/
170 int faketape::tape_op(struct mtop *mt_com)
173 int count = mt_com->mt_count;
180 switch (mt_com->mt_op)
196 case MTFSF: /* Forward space over mt_count filemarks. */
199 } while (--count > 0 && result == 0);
202 case MTBSF: /* Backward space over mt_count filemarks. */
205 } while (--count > 0 && result == 0);
208 case MTFSR: /* Forward space over mt_count records (tape blocks). */
216 mt: /dev/lto2: Erreur d'entree/sortie
221 /* tester si on se trouve a la fin du fichier */
222 result = fsr(mt_com->mt_count);
225 case MTBSR: /* Backward space over mt_count records (tape blocks). */
226 result = bsr(mt_com->mt_count);
229 case MTWEOF: /* Write mt_count filemarks. */
232 } while (result == 0 && --count > 0);
235 case MTREW: /* Rewind. */
236 Dmsg0(dbglevel, "rewind faketape\n");
238 atEOF = atEOD = false;
242 lseek(fd, 0, SEEK_SET);
243 read_fm(FT_READ_EOF);
246 case MTOFFL: /* put tape offline */
250 case MTRETEN: /* Re-tension tape. */
254 case MTBSFM: /* not used by bacula */
259 case MTFSFM: /* not used by bacula */
264 case MTEOM:/* Go to the end of the recorded media (for appending files). */
266 lseek(fd, next_FM, SEEK_SET);
267 if (read_fm(FT_READ_EOF)) {
272 while (::read(fd, &l, sizeof(l)) > 0) {
274 lseek(fd, l, SEEK_CUR);
278 Dmsg0(dbglevel, "skip 1 block\n");
291 case MTERASE: /* not used by bacula */
298 lseek(fd, 0, SEEK_SET);
299 read_fm(FT_READ_EOF);
343 return result == 0 ? 0 : -1;
346 int faketape::tape_get(struct mtget *mt_get)
349 int block_size = 1024;
351 mt_get->mt_type = MT_ISSCSI2;
352 mt_get->mt_blkno = current_block;
353 mt_get->mt_fileno = current_file;
355 mt_get->mt_resid = -1;
356 // pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
360 ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
361 ((block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
364 mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
367 mt_get->mt_gstat |= 0x80000000; // GMT_EOF
371 mt_get->mt_gstat |= 0x40000000; // GMT_BOT
374 mt_get->mt_gstat |= 0x20000000; // GMT_EOT
378 mt_get->mt_gstat |= 0x08000000; // GMT_EOD
381 if (0) { //WriteProtected) {
382 mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
386 mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
388 mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
390 mt_get->mt_erreg = 0;
395 int faketape::tape_pos(struct mtpos *mt_pos)
397 if (current_block >= 0) {
398 mt_pos->mt_blkno = current_block;
406 * This function try to emulate the append only behavior
407 * of a tape. When you wrote something, data after the
408 * current position are discarded.
410 int faketape::truncate_file()
412 Dmsg2(dbglevel, "truncate %i:%i\n", current_file, current_block);
413 ftruncate(fd, lseek(fd, 0, SEEK_CUR));
414 last_file = current_file;
436 max_block = 2*1024*2048; /* 2GB */
439 faketape::~faketape()
443 int faketape::get_fd()
449 * TODO: check if after a write op, and other tape op put a EOF
451 int faketape::write(const void *buffer, unsigned int count)
454 ASSERT(current_file >= 0);
459 Dmsg3(dbglevel*2, "write len=%i %i:%i\n",
460 count, current_file,current_block);
463 Dmsg0(dbglevel, "write nothing, EOT !\n");
468 if (!atEOD) { /* if not at the end of the data */
472 if (current_block != -1) {
478 atEOD = true; /* End of data */
480 needEOF = true; /* next operation need EOF mark */
482 uint32_t size = count;
483 ::write(fd, &size, sizeof(uint32_t));
484 nb = ::write(fd, buffer, count);
489 "Not enough space writing only %i of %i requested\n",
499 * +---+---------+---+------------------+---+-------------------+
500 * |00N| DATA |0LN| DATA |0LC| DATA |
501 * +---+---------+---+------------------+---+-------------------+
504 * L : Last FileMark offset
505 * N : Next FileMark offset
506 * C : Current FileMark Offset
511 ASSERT(current_file >= 0);
520 truncate_file(); /* nothing after this point */
524 cur_FM = lseek(fd, 0, SEEK_CUR); // current position
526 /* update previous next_FM */
527 lseek(fd, last_FM + sizeof(uint32_t)+sizeof(off_t), SEEK_SET);
528 ::write(fd, &cur_FM, sizeof(off_t));
529 lseek(fd, cur_FM, SEEK_SET);
534 ::write(fd, &c, sizeof(uint32_t)); // EOF
535 ::write(fd, &last_FM, sizeof(last_FM)); // F-1
536 ::write(fd, &next_FM, sizeof(next_FM)); // F (will be updated next time)
546 last_file = MAX(current_file, last_file);
548 Dmsg4(dbglevel, "Writing EOF %i:%i last=%lli cur=%lli next=0\n",
549 current_file, current_block, last_FM, cur_FM);
560 ASSERT(current_file >= 0);
563 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
567 if (atEOT || atEOD) {
574 Dmsg2(dbglevel+1, "fsf %i <= %i\n", current_file, last_file);
576 if (next_FM > cur_FM) { /* not the last file */
577 lseek(fd, next_FM, SEEK_SET);
578 read_fm(FT_READ_EOF);
583 } else if (atEOF) { /* last file mark */
589 } else { /* last file, but no at the end */
592 Dmsg0(dbglevel, "Try to FSF after EOT\n");
594 current_file = last_file ;
602 /* /------------\ /---------------\
603 * +---+------+---+---------------+-+
605 * +---+------+---+---------------+-+
608 bool faketape::read_fm(FT_READ_FM_MODE read_all)
612 if (read_all == FT_READ_EOF) {
613 ::read(fd, &c, sizeof(c));
615 lseek(fd, cur_FM, SEEK_SET);
620 cur_FM = lseek(fd, 0, SEEK_CUR) - sizeof(c);
622 ::read(fd, &last_FM, sizeof(last_FM));
623 ret = ::read(fd, &next_FM, sizeof(next_FM));
627 Dmsg3(dbglevel, "Read FM cur=%lli last=%lli next=%lli\n",
628 cur_FM, last_FM, next_FM);
630 return (ret == sizeof(next_FM));
634 * TODO: Check fsr with EOF
636 int faketape::fsr(int count)
639 ASSERT(current_file >= 0);
645 Dmsg4(dbglevel, "fsr %i:%i EOF=%i c=%i\n",
646 current_file,current_block,atEOF,count);
661 atBOT = atEOF = false;
663 /* check all block record */
664 for(i=0; (i < count) && !atEOF ; i++) {
665 nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
666 if (nb == sizeof(uint32_t) && s) {
668 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
670 Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
671 current_file, current_block, nb,s);
676 read_fm(FT_SKIP_EOF);
678 atEOF = true; /* stop the loop */
686 * BSR + EOF => begin of EOF + EIO
687 * BSR + BSR + EOF => last block
690 int faketape::bsr(int count)
693 ASSERT(current_file >= 0);
707 off_t last=-1, last2=-1;
708 off_t orig = lseek(fd, 0, SEEK_CUR);
709 int orig_f = current_file;
710 int orig_b = current_block;
712 Dmsg4(dbglevel, "bsr(%i) cur_blk=%i orig=%lli cur_FM=%lli\n",
713 count, current_block, orig, cur_FM);
715 /* begin of tape, do nothing */
721 /* at EOF 0:-1 BOT=0 EOD=0 EOF=0 ERR: Input/output error */
723 lseek(fd, cur_FM, SEEK_SET);
725 if (current_file > 0) {
734 * First, go to cur/last_FM and read all blocks to find the good one
736 if (cur_FM == orig) { /* already just before EOF */
737 lseek(fd, last_FM, SEEK_SET);
740 lseek(fd, cur_FM, SEEK_SET);
743 ret = read_fm(FT_READ_EOF);
747 last2 = last; /* keep track of the 2 last blocs position */
748 last = lseek(fd, 0, SEEK_CUR);
749 last_f = current_file;
750 last_b = current_block;
751 Dmsg6(dbglevel, "EOF=%i last2=%lli last=%lli < orig=%lli %i:%i\n",
752 atEOF, last2, last, orig, current_file, current_block);
755 } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
757 if (last2 > 0 && atEOF) { /* we take the previous position */
758 lseek(fd, last2, SEEK_SET);
759 current_file = last_f;
760 current_block = last_b - 1;
761 Dmsg3(dbglevel, "1 set offset2=%lli %i:%i\n",
762 last, current_file, current_block);
764 } else if (last > 0) {
765 lseek(fd, last, SEEK_SET);
766 current_file = last_f;
767 current_block = last_b;
768 Dmsg3(dbglevel, "2 set offset=%lli %i:%i\n",
769 last, current_file, current_block);
771 lseek(fd, orig, SEEK_SET);
772 current_file = orig_f;
773 current_block = orig_b;
777 Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
779 atEOT = atEOF = atEOD = false;
780 atBOT = (lseek(fd, 0, SEEK_CUR) - (sizeof(uint32_t)+2*sizeof(off_t))) == 0;
783 current_block = orig_b;
789 /* BSF => just before last EOF
790 * EOF + BSF => just before EOF
791 * file 0 + BSF => BOT + errno
796 ASSERT(current_file >= 0);
797 Dmsg2(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block);
802 atBOT = atEOF = atEOT = atEOD = false;
804 if (current_file == 0) {/* BOT + errno */
805 lseek(fd, 0, SEEK_SET);
806 read_fm(FT_READ_EOF);
813 Dmsg1(dbglevel, "bsf last=%lli\n", last_FM);
814 lseek(fd, cur_FM, SEEK_SET);
822 * Put faketape in offline mode
824 int faketape::offline()
828 atEOF = false; /* End of file */
829 atEOT = false; /* End of tape */
830 atEOD = false; /* End of data */
831 atBOT = false; /* Begin of tape */
841 /* A filemark is automatically written to tape if the last tape operation
842 * before close was a write.
844 int faketape::close()
853 * When a filemark is encountered while reading, the following happens. If
854 * there are data remaining in the buffer when the filemark is found, the
855 * buffered data is returned. The next read returns zero bytes. The following
856 * read returns data from the next file. The end of recorded data is sig‐
857 * naled by returning zero bytes for two consecutive read calls. The third
858 * read returns an error.
860 int faketape::read(void *buffer, unsigned int count)
863 ASSERT(current_file >= 0);
867 Dmsg2(dbglevel*2, "read %i:%i\n", current_file, current_block);
869 if (atEOT || atEOD) {
886 atEOD = atBOT = false;
888 /* reading size of data */
889 nb = ::read(fd, &s, sizeof(uint32_t));
891 atEOF = true; /* TODO: check this */
895 if (s > count) { /* not enough buffer to read block */
896 Dmsg2(dbglevel, "Need more buffer to read next block %i > %i\n",s,count);
897 lseek(fd, s, SEEK_CUR);
904 if (read_fm(FT_SKIP_EOF)) {
911 /* reading data itself */
912 nb = ::read(fd, buffer, s);
913 if (s != nb) { /* read error */
917 Dmsg0(dbglevel, "EOT during reading\n");
921 if (current_block >= 0) {
928 int faketape::open(const char *pathname, int uflags)
930 Dmsg2(dbglevel, "faketape::open(%s, %i)\n", pathname, uflags);
932 online = true; /* assume that drive contains a tape */
935 if (stat(pathname, &statp) != 0) {
936 Dmsg1(dbglevel, "Can't stat on %s\n", pathname);
937 if (uflags & O_NONBLOCK) {
939 fd = ::open("/dev/null", O_CREAT | O_RDWR | O_LARGEFILE, 0600);
942 fd = ::open(pathname, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
953 cur_FM = next_FM = last_FM = 0;
956 atEOT = atEOD = false;
958 /* If the faketape is empty, start by writing a EOF */
959 if (online && !read_fm(FT_READ_EOF)) {
961 last_file = current_file=0;
967 /* use this to track file usage */
968 void faketape::update_pos()
972 if (fstat(fd, &statp) == 0) {
973 file_block = statp.st_blocks;
976 Dmsg1(dbglevel+1, "update_pos=%i\n", file_block);
978 if (file_block > max_block) {
985 void faketape::dump()
987 Dmsg0(dbglevel+1, "===================\n");
988 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
989 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
990 Dmsg1(dbglevel+1, "file_block=%i\n", file_block);
991 Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n",
992 atEOF, atEOT, atEOD, atBOT);
995 #endif /* USE_FAKETAPE */