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 = 1000;
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)
179 switch (mt_com->mt_op)
195 case MTFSF: /* Forward space over mt_count filemarks. */
196 result = fsf(mt_com->mt_count);
199 case MTBSF: /* Backward space over mt_count filemarks. */
200 result = bsf(mt_com->mt_count);
203 case MTFSR: /* Forward space over mt_count records (tape blocks). */
211 mt: /dev/lto2: Erreur d'entree/sortie
216 /* tester si on se trouve a la fin du fichier */
217 result = fsr(mt_com->mt_count);
220 case MTBSR: /* Backward space over mt_count records (tape blocks). */
221 result = bsr(mt_com->mt_count);
224 case MTWEOF: /* Write mt_count filemarks. */
225 result = weof(mt_com->mt_count);
228 case MTREW: /* Rewind. */
229 Dmsg0(dbglevel, "rewind faketape\n");
230 atEOF = atEOD = false;
237 case MTOFFL: /* put tape offline */
241 case MTRETEN: /* Re-tension tape. */
245 case MTBSFM: /* not used by bacula */
250 case MTFSFM: /* not used by bacula */
255 case MTEOM:/* Go to the end of the recorded media (for appending files). */
266 current_file = last_file;
271 case MTERASE: /* not used by bacula */
322 return result == 0 ? 0 : -1;
325 int faketape::tape_get(struct mtget *mt_get)
328 int block_size = 1024;
330 mt_get->mt_type = MT_ISSCSI2;
331 mt_get->mt_blkno = current_block;
332 mt_get->mt_fileno = current_file;
334 mt_get->mt_resid = -1;
335 // pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
339 ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
340 ((block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
343 mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
346 mt_get->mt_gstat |= 0x80000000; // GMT_EOF
350 mt_get->mt_gstat |= 0x40000000; // GMT_BOT
353 mt_get->mt_gstat |= 0x20000000; // GMT_EOT
357 mt_get->mt_gstat |= 0x08000000; // GMT_EOD
360 if (0) { //WriteProtected) {
361 mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
365 mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
367 mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
369 mt_get->mt_erreg = 0;
374 int faketape::tape_pos(struct mtpos *mt_pos)
376 if (current_block >= 0) {
377 mt_pos->mt_blkno = current_block;
385 * This function try to emulate the append only behavior
386 * of a tape. When you wrote something, data after the
387 * current position are discarded.
389 int faketape::truncate_file()
391 Dmsg2(dbglevel, "truncate %i:%i\n", current_file, current_block);
392 ftruncate(fd, lseek(fd, 0, SEEK_CUR));
393 last_file = current_file;
416 max_block = 2*1024*2048; /* 2GB */
419 faketape::~faketape()
423 int faketape::get_fd()
429 * TODO: check if after a write op, and other tape op put a EOF
431 int faketape::write(const void *buffer, unsigned int count)
434 ASSERT(current_file >= 0);
439 Dmsg3(dbglevel, "write len=%i %i:%i\n", count, current_file,current_block);
442 Dmsg0(dbglevel, "write nothing, EOT !\n");
447 Dmsg1(dbglevel, "write inplace=%i\n", inplace);
450 if (!atEOD) { /* if not at the end of the data */
454 if (current_block != -1) {
460 atEOD = true; /* End of data */
462 needEOF = true; /* next operation need EOF mark */
464 // if ((count + file_size) > max_size) {
466 // "EOT writing only %i of %i requested\n",
467 // max_size - file_size, count);
468 // count = max_size - file_size;
472 uint32_t size = count;
473 ::write(fd, &size, sizeof(uint32_t));
474 nb = ::write(fd, buffer, count);
479 "Not enough space writing only %i of %i requested\n",
488 int faketape::weof(int count)
491 ASSERT(current_file >= 0);
492 Dmsg3(dbglevel, "Writing EOF %i:%i last=%i\n",
493 current_file, current_block,last_file);
502 truncate_file(); /* nothing after this point */
505 ::write(fd, &c, sizeof(uint32_t));
507 current_file += count;
512 ::write(fd, &c, sizeof(uint32_t));
513 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
524 int faketape::fsf(int count)
527 ASSERT(current_file >= 0);
530 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
536 if (atEOT || atEOD) {
542 atBOT = atEOF = false;
543 Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
545 if ((current_file + count) <= last_file) {
546 current_file += count;
550 Dmsg0(dbglevel, "Try to FSF after EOT\n");
552 current_file = last_file ;
561 int faketape::fsr(int count)
564 ASSERT(current_file >= 0);
570 Dmsg3(dbglevel, "fsr %i:%i count=%i\n", current_file,current_block, count);
586 atBOT = atEOF = false;
588 /* check all block record */
589 for(i=0; (i < count) && !atEOF ; i++) {
590 nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
591 if (nb == sizeof(uint32_t) && s) {
593 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
595 Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
596 current_file, current_block, nb,s);
599 if (current_file < last_file) {
604 atEOF = true; /* stop the loop */
608 find_maxfile(); /* refresh stats */
613 int faketape::bsr(int count)
615 Dmsg2(dbglevel, "bsr current_block=%i count=%i\n",
616 current_block, count);
619 ASSERT(current_file >= 0);
634 off_t last=-1, last2=-1;
635 off_t orig = lseek(fd, 0, SEEK_CUR);
636 int orig_f = current_file;
637 int orig_b = current_block;
645 last = lseek(fd, 0, SEEK_CUR);
646 last_f = current_file;
647 last_b = current_block;
648 Dmsg5(dbglevel, "EOF=%i last=%lli orig=%lli %i:%i\n",
649 atEOF, last, orig, current_file, current_block);
652 } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
654 if (last2 > 0 && atEOF) { /* we take the previous position */
655 lseek(fd, last2, SEEK_SET);
656 current_file = last_f;
657 current_block = last_b - 1;
658 Dmsg3(dbglevel, "set offset2=%lli %i:%i\n",
659 last, current_file, current_block);
661 } else if (last > 0) {
662 lseek(fd, last, SEEK_SET);
663 current_file = last_f;
664 current_block = last_b;
665 Dmsg3(dbglevel, "set offset=%lli %i:%i\n",
666 last, current_file, current_block);
668 lseek(fd, orig, SEEK_SET);
669 current_file = orig_f;
670 current_block = orig_b;
674 Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
675 atEOT = atEOF = atEOD = false;
680 int faketape::bsf(int count)
683 ASSERT(current_file >= 0);
684 Dmsg3(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block, count);
690 atBOT = atEOF = atEOT = atEOD = false;
692 if (current_file - count < 0) {
699 current_file = current_file - count + 1;
703 /* go just before last EOF */
704 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
710 * Put faketape in offline mode
712 int faketape::offline()
716 atEOF = false; /* End of file */
717 atEOT = false; /* End of tape */
718 atEOD = false; /* End of data */
719 atBOT = false; /* Begin of tape */
729 int faketape::close()
739 * EOF Bacula status: file=2 block=0
740 * Device status: EOF ONLINE IM_REP_EN file=2 block=0
743 * EOD EOF Bacula status: file=2 block=0
744 * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
748 int faketape::read(void *buffer, unsigned int count)
751 ASSERT(current_file >= 0);
755 Dmsg2(dbglevel, "read %i:%i\n", current_file, current_block);
757 if (atEOT || atEOD) {
763 if (current_file >= last_file) {
775 atEOD = atBOT = false;
777 /* reading size of data */
778 nb = ::read(fd, &s, sizeof(uint32_t));
780 atEOF = true; /* TODO: check this */
784 if (s > count) { /* not enough buffer to read block */
785 Dmsg2(dbglevel, "Need more buffer to read next block %i > %i\n",s,count);
786 lseek(fd, s, SEEK_CUR);
793 if (current_file < last_file) { /* move to next file if possible */
801 /* reading data itself */
802 nb = ::read(fd, buffer, s);
803 if (s != nb) { /* read error */
807 Dmsg0(dbglevel, "EOT during reading\n");
816 int faketape::open(const char *pathname, int uflags)
818 Dmsg2(dbglevel, "faketape::open(%s, %i)\n", pathname, uflags);
820 online = true; /* assume that drive contains a tape */
823 if (stat(pathname, &statp) != 0) {
824 Dmsg1(dbglevel, "Can't stat on %s\n", pathname);
825 if (uflags & O_NONBLOCK) {
827 fd = ::open("/dev/null", O_CREAT | O_RDWR | O_LARGEFILE, 0600);
830 fd = ::open(pathname, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
838 /* open volume descriptor and get this->fd */
847 atEOT = atEOD = false;
853 * read volume to get the last file number
855 int faketape::find_maxfile()
858 if (fstat(fd, &statp) != 0) {
861 last_file = statp.st_size>>FILE_OFFSET;
863 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
868 void faketape::update_pos()
872 if (fstat(fd, &statp) == 0) {
873 file_block = statp.st_blocks;
876 Dmsg1(dbglevel+1, "update_pos=%i\n", file_block);
878 if (file_block > max_block) {
885 int faketape::seek_file()
888 ASSERT(current_file >= 0);
889 Dmsg2(dbglevel, "seek_file %i:%i\n", current_file, current_block);
892 off_t pos = ((off_t)current_file)<<FILE_OFFSET;
893 if(lseek(fd, pos, SEEK_SET) == -1) {
897 last_file = MAX(last_file, current_file);
898 if (current_block > 0) {
905 void faketape::dump()
907 Dmsg0(dbglevel+1, "===================\n");
908 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
909 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
910 Dmsg1(dbglevel+1, "file_block=%i\n", file_block);
911 Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n",
912 atEOF, atEOT, atEOD, atBOT);
915 #endif /* USE_FAKETAPE */