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 = 10;
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*100; /* 100MB */
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");
451 if (!atEOD) { /* if not at the end of the data */
455 if (current_block != -1) {
461 atEOD = true; /* End of data */
463 needEOF = true; /* next operation need EOF mark */
465 // if ((count + file_size) > max_size) {
467 // "EOT writing only %i of %i requested\n",
468 // max_size - file_size, count);
469 // count = max_size - file_size;
473 uint32_t size = count;
474 ::write(fd, &size, sizeof(uint32_t));
475 nb = ::write(fd, buffer, count);
480 "Not enough space writing only %i of %i requested\n",
489 int faketape::weof(int count)
492 ASSERT(current_file >= 0);
493 Dmsg3(dbglevel, "Writing EOF %i:%i last=%i\n",
494 current_file, current_block,last_file);
501 truncate_file(); /* nothing after this point */
503 /* TODO: check this */
504 current_file += count;
509 ::write(fd, &c, sizeof(uint32_t));
521 int faketape::fsf(int count)
524 ASSERT(current_file >= 0);
527 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
537 atBOT = atEOF = false;
538 Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
540 if ((current_file + count) <= last_file) {
541 current_file += count;
545 Dmsg0(dbglevel, "Try to FSF after EOT\n");
546 current_file = last_file ;
555 int faketape::fsr(int count)
558 ASSERT(current_file >= 0);
564 Dmsg3(dbglevel, "fsr %i:%i count=%i\n", current_file,current_block, count);
579 atBOT = atEOF = false;
581 /* check all block record */
582 for(i=0; (i < count) && !atEOF ; i++) {
583 nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
584 if (nb == sizeof(uint32_t) && s) {
586 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
588 Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
589 current_file, current_block, nb,s);
592 if (current_file < last_file) {
597 atEOF = true; /* stop the loop */
601 find_maxfile(); /* refresh stats */
606 int faketape::bsr(int count)
608 Dmsg2(dbglevel, "bsr current_block=%i count=%i\n",
609 current_block, count);
612 ASSERT(current_file >= 0);
626 off_t last=-1, last2=-1;
627 off_t orig = lseek(fd, 0, SEEK_CUR);
628 int orig_f = current_file;
629 int orig_b = current_block;
637 last = lseek(fd, 0, SEEK_CUR);
638 last_f = current_file;
639 last_b = current_block;
640 Dmsg5(dbglevel, "EOF=%i last=%lli orig=%lli %i:%i\n",
641 atEOF, last, orig, current_file, current_block);
644 } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
646 if (last2 > 0 && atEOF) { /* we take the previous position */
647 lseek(fd, last2, SEEK_SET);
648 current_file = last_f;
649 current_block = last_b - 1;
650 Dmsg3(dbglevel, "set offset2=%lli %i:%i\n",
651 last, current_file, current_block);
653 } else if (last > 0) {
654 lseek(fd, last, SEEK_SET);
655 current_file = last_f;
656 current_block = last_b;
657 Dmsg3(dbglevel, "set offset=%lli %i:%i\n",
658 last, current_file, current_block);
660 lseek(fd, orig, SEEK_SET);
661 current_file = orig_f;
662 current_block = orig_b;
666 Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
667 atEOT = atEOF = atEOD = false;
672 int faketape::bsf(int count)
675 ASSERT(current_file >= 0);
676 Dmsg3(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block, count);
680 atBOT = atEOF = atEOT = atEOD = false;
682 if (current_file - count < 0) {
689 current_file = current_file - count + 1;
693 /* go just before last EOF */
694 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
700 * Put faketape in offline mode
702 int faketape::offline()
706 atEOF = false; /* End of file */
707 atEOT = false; /* End of tape */
708 atEOD = false; /* End of data */
709 atBOT = false; /* Begin of tape */
719 int faketape::close()
729 * EOF Bacula status: file=2 block=0
730 * Device status: EOF ONLINE IM_REP_EN file=2 block=0
733 * EOD EOF Bacula status: file=2 block=0
734 * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
738 int faketape::read(void *buffer, unsigned int count)
741 ASSERT(current_file >= 0);
745 Dmsg2(dbglevel, "read %i:%i\n", current_file, current_block);
747 if (atEOT || atEOD) {
762 atEOD = atBOT = false;
765 nb = ::read(fd, &s, sizeof(uint32_t));
770 if (s > count) { /* not enough buffer to read block */
771 Dmsg2(dbglevel, "Need more buffer to read next block %i > %i\n",s,count);
772 lseek(fd, s, SEEK_CUR);
778 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
781 nb = ::read(fd, buffer, s);
784 if (current_file == last_file) {
788 Dmsg0(dbglevel, "EOF during reading\n");
793 int faketape::open(const char *pathname, int uflags)
795 Dmsg2(dbglevel, "faketape::open(%s, %i)\n", pathname, uflags);
797 online = true; /* assume that drive contains a tape */
800 if (stat(pathname, &statp) != 0) {
801 Dmsg1(dbglevel, "Can't stat on %s\n", pathname);
802 if (uflags & O_NONBLOCK) {
804 fd = ::open("/dev/null", O_CREAT | O_RDWR | O_LARGEFILE, 0600);
807 fd = ::open(pathname, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
815 /* open volume descriptor and get this->fd */
824 atEOT = atEOD = false;
830 * read volume to get the last file number
832 int faketape::find_maxfile()
835 if (fstat(fd, &statp) != 0) {
838 last_file = statp.st_size>>FILE_OFFSET;
840 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
845 void faketape::update_pos()
849 if (fstat(fd, &statp) == 0) {
850 file_block = statp.st_blocks;
853 Dmsg1(dbglevel+1, "update_pos=%i\n", file_block);
855 if (file_block > max_block) {
862 int faketape::seek_file()
865 ASSERT(current_file >= 0);
866 Dmsg2(dbglevel, "seek_file %i:%i\n", current_file, current_block);
868 off_t pos = ((off_t)current_file)<<FILE_OFFSET;
869 if(lseek(fd, pos, SEEK_SET) == -1) {
872 last_file = MAX(last_file, current_file);
873 if (current_block > 0) {
881 void faketape::dump()
883 Dmsg0(dbglevel+1, "===================\n");
884 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
885 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
886 Dmsg1(dbglevel+1, "file_block=%i\n", file_block);
887 Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n",
888 atEOF, atEOT, atEOD, atBOT);
891 #endif /* USE_FAKETAPE */