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 = 1024*1024*1024*1024*8;
420 faketape::~faketape()
424 int faketape::get_fd()
430 * TODO: check if after a write op, and other tape op put a EOF
432 int faketape::write(const void *buffer, unsigned int count)
435 ASSERT(current_file >= 0);
440 Dmsg3(dbglevel, "write len=%i %i:%i\n", count, current_file,current_block);
443 Dmsg0(dbglevel, "write nothing, EOT !\n");
452 if (!atEOD) { /* if not at the end of the data */
456 if (current_block != -1) {
462 atEOD = true; /* End of data */
464 needEOF = true; /* next operation need EOF mark */
466 // if ((count + file_size) > max_size) {
468 // "EOT writing only %i of %i requested\n",
469 // max_size - file_size, count);
470 // count = max_size - file_size;
474 uint32_t size = count;
475 ::write(fd, &size, sizeof(uint32_t));
476 nb = ::write(fd, buffer, count);
478 file_size += sizeof(uint32_t) + nb;
483 "Not enough space writing only %i of %i requested\n",
490 int faketape::weof(int count)
493 ASSERT(current_file >= 0);
494 Dmsg3(dbglevel, "Writing EOF %i:%i last=%i\n",
495 current_file, current_block,last_file);
502 truncate_file(); /* nothing after this point */
504 /* TODO: check this */
505 current_file += count;
510 ::write(fd, &c, sizeof(uint32_t));
520 int faketape::fsf(int count)
523 ASSERT(current_file >= 0);
526 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
536 atBOT = atEOF = false;
537 Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
539 if ((current_file + count) <= last_file) {
540 current_file += count;
544 Dmsg0(dbglevel, "Try to FSF after EOT\n");
545 current_file = last_file ;
554 int faketape::fsr(int count)
557 ASSERT(current_file >= 0);
563 Dmsg3(dbglevel, "fsr %i:%i count=%i\n", current_file,current_block, count);
578 atBOT = atEOF = false;
580 /* check all block record */
581 for(i=0; (i < count) && !atEOF ; i++) {
582 nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
583 if (nb == sizeof(uint32_t) && s) {
585 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
587 Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
588 current_file, current_block, nb,s);
591 if (current_file < last_file) {
596 atEOF = true; /* stop the loop */
600 find_maxfile(); /* refresh stats */
602 if (where == file_size) {
608 int faketape::bsr(int count)
610 Dmsg2(dbglevel, "bsr current_block=%i count=%i\n",
611 current_block, count);
614 ASSERT(current_file >= 0);
628 off_t last=-1, last2=-1;
629 off_t orig = lseek(fd, 0, SEEK_CUR);
630 int orig_f = current_file;
631 int orig_b = current_block;
639 last = lseek(fd, 0, SEEK_CUR);
640 last_f = current_file;
641 last_b = current_block;
642 Dmsg5(dbglevel, "EOF=%i last=%lli orig=%lli %i:%i\n",
643 atEOF, last, orig, current_file, current_block);
646 } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
648 if (last2 > 0 && atEOF) { /* we take the previous position */
649 lseek(fd, last2, SEEK_SET);
650 current_file = last_f;
651 current_block = last_b - 1;
652 Dmsg3(dbglevel, "set offset2=%lli %i:%i\n",
653 last, current_file, current_block);
655 } else if (last > 0) {
656 lseek(fd, last, SEEK_SET);
657 current_file = last_f;
658 current_block = last_b;
659 Dmsg3(dbglevel, "set offset=%lli %i:%i\n",
660 last, current_file, current_block);
662 lseek(fd, orig, SEEK_SET);
663 current_file = orig_f;
664 current_block = orig_b;
668 Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
669 atEOT = atEOF = atEOD = false;
674 int faketape::bsf(int count)
677 ASSERT(current_file >= 0);
678 Dmsg3(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block, count);
682 atBOT = atEOF = atEOT = atEOD = false;
684 if (current_file - count < 0) {
691 current_file = current_file - count + 1;
695 /* go just before last EOF */
696 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
702 * Put faketape in offline mode
704 int faketape::offline()
708 atEOF = false; /* End of file */
709 atEOT = false; /* End of tape */
710 atEOD = false; /* End of data */
711 atBOT = false; /* Begin of tape */
720 int faketape::close()
730 * EOF Bacula status: file=2 block=0
731 * Device status: EOF ONLINE IM_REP_EN file=2 block=0
734 * EOD EOF Bacula status: file=2 block=0
735 * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
739 int faketape::read(void *buffer, unsigned int count)
742 ASSERT(current_file >= 0);
746 Dmsg2(dbglevel, "read %i:%i\n", current_file, current_block);
748 if (atEOT || atEOD) {
763 atEOD = atBOT = false;
766 nb = ::read(fd, &s, sizeof(uint32_t));
771 if (s > count) { /* not enough buffer to read block */
772 Dmsg2(dbglevel, "Need more buffer to read next block %i > %i\n",s,count);
773 lseek(fd, s, SEEK_CUR);
779 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
782 nb = ::read(fd, buffer, s);
785 if (current_file == last_file) {
789 Dmsg0(dbglevel, "EOF during reading\n");
794 int faketape::open(const char *pathname, int uflags)
796 Dmsg2(dbglevel, "faketape::open(%s, %i)\n", pathname, uflags);
798 online = true; /* assume that drive contains a tape */
801 if (stat(pathname, &statp) != 0) {
802 Dmsg1(dbglevel, "Can't stat on %s\n", pathname);
803 if (uflags & O_NONBLOCK) {
805 fd = ::open("/dev/null", O_CREAT | O_RDWR | O_LARGEFILE, 0600);
808 fd = ::open(pathname, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
816 /* 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;
839 file_size = statp.st_size;
841 current_pos = lseek(fd, 0, SEEK_CUR); /* get current position */
842 Dmsg3(dbglevel+1, "last_file=%i file_size=%u current_pos=%i\n",
843 last_file, file_size, current_pos);
848 int faketape::seek_file()
851 ASSERT(current_file >= 0);
852 Dmsg2(dbglevel, "seek_file %i:%i\n", current_file, current_block);
854 off_t pos = ((off_t)current_file)<<FILE_OFFSET;
855 if(lseek(fd, pos, SEEK_SET) == -1) {
858 last_file = (last_file > current_file)?last_file:current_file;
859 if (current_block > 0) {
867 void faketape::dump()
869 Dmsg0(dbglevel+1, "===================\n");
870 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
871 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
872 Dmsg1(dbglevel+1, "file_size=%i\n", file_size);
873 Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n",
874 atEOF, atEOT, atEOD, atBOT);
877 #endif /* USE_FAKETAPE */