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*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");
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);
478 "Not enough space writing only %i of %i requested\n",
487 int faketape::weof(int count)
490 ASSERT(current_file >= 0);
491 Dmsg3(dbglevel, "Writing EOF %i:%i last=%i\n",
492 current_file, current_block,last_file);
501 truncate_file(); /* nothing after this point */
504 ::write(fd, &c, sizeof(uint32_t));
506 current_file += count;
511 ::write(fd, &c, sizeof(uint32_t));
512 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
523 int faketape::fsf(int count)
526 ASSERT(current_file >= 0);
529 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
535 if (atEOT || atEOD) {
541 atBOT = atEOF = false;
542 Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
544 if ((current_file + count) <= last_file) {
545 current_file += count;
549 Dmsg0(dbglevel, "Try to FSF after EOT\n");
551 current_file = last_file ;
560 int faketape::fsr(int count)
563 ASSERT(current_file >= 0);
569 Dmsg3(dbglevel, "fsr %i:%i count=%i\n", current_file,current_block, count);
585 atBOT = atEOF = false;
587 /* check all block record */
588 for(i=0; (i < count) && !atEOF ; i++) {
589 nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
590 if (nb == sizeof(uint32_t) && s) {
592 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
594 Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
595 current_file, current_block, nb,s);
598 if (current_file < last_file) {
603 atEOF = true; /* stop the loop */
607 find_maxfile(); /* refresh stats */
612 int faketape::bsr(int count)
614 Dmsg2(dbglevel, "bsr current_block=%i count=%i\n",
615 current_block, count);
618 ASSERT(current_file >= 0);
633 off_t last=-1, last2=-1;
634 off_t orig = lseek(fd, 0, SEEK_CUR);
635 int orig_f = current_file;
636 int orig_b = current_block;
638 /* begin of tape, do nothing */
645 if (!current_block) {
646 if (current_file > 0) {
664 last = lseek(fd, 0, SEEK_CUR);
665 last_f = current_file;
666 last_b = current_block;
667 Dmsg5(dbglevel, "EOF=%i last=%lli orig=%lli %i:%i\n",
668 atEOF, last, orig, current_file, current_block);
671 } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
673 if (last2 > 0 && atEOF) { /* we take the previous position */
674 lseek(fd, last2, SEEK_SET);
675 current_file = last_f;
676 current_block = last_b - 1;
677 Dmsg3(dbglevel, "set offset2=%lli %i:%i\n",
678 last, current_file, current_block);
680 } else if (last > 0) {
681 lseek(fd, last, SEEK_SET);
682 current_file = last_f;
683 current_block = last_b;
684 Dmsg3(dbglevel, "set offset=%lli %i:%i\n",
685 last, current_file, current_block);
687 lseek(fd, orig, SEEK_SET);
688 current_file = orig_f;
689 current_block = orig_b;
693 Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
695 atEOT = atEOF = atEOD = false;
696 atBOT = (current_block == 0 && current_file == 0);
703 int faketape::bsf(int count)
706 ASSERT(current_file >= 0);
707 Dmsg3(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block, count);
713 atBOT = atEOF = atEOT = atEOD = false;
715 if (current_file - count < 0) {
722 current_file = current_file - count + 1;
726 /* go just before last EOF */
727 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
733 * Put faketape in offline mode
735 int faketape::offline()
739 atEOF = false; /* End of file */
740 atEOT = false; /* End of tape */
741 atEOD = false; /* End of data */
742 atBOT = false; /* Begin of tape */
752 int faketape::close()
762 * EOF Bacula status: file=2 block=0
763 * Device status: EOF ONLINE IM_REP_EN file=2 block=0
766 * EOD EOF Bacula status: file=2 block=0
767 * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
771 int faketape::read(void *buffer, unsigned int count)
774 ASSERT(current_file >= 0);
778 Dmsg2(dbglevel, "read %i:%i\n", current_file, current_block);
780 if (atEOT || atEOD) {
786 if (current_file >= last_file) {
798 atEOD = atBOT = false;
800 /* reading size of data */
801 nb = ::read(fd, &s, sizeof(uint32_t));
803 atEOF = true; /* TODO: check this */
807 if (s > count) { /* not enough buffer to read block */
808 Dmsg2(dbglevel, "Need more buffer to read next block %i > %i\n",s,count);
809 lseek(fd, s, SEEK_CUR);
816 if (current_file < last_file) { /* move to next file if possible */
824 /* reading data itself */
825 nb = ::read(fd, buffer, s);
826 if (s != nb) { /* read error */
830 Dmsg0(dbglevel, "EOT during reading\n");
834 if (current_block >= 0) {
841 int faketape::open(const char *pathname, int uflags)
843 Dmsg2(dbglevel, "faketape::open(%s, %i)\n", pathname, uflags);
845 online = true; /* assume that drive contains a tape */
848 if (stat(pathname, &statp) != 0) {
849 Dmsg1(dbglevel, "Can't stat on %s\n", pathname);
850 if (uflags & O_NONBLOCK) {
852 fd = ::open("/dev/null", O_CREAT | O_RDWR | O_LARGEFILE, 0600);
855 fd = ::open(pathname, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
863 /* open volume descriptor and get this->fd */
872 atEOT = atEOD = false;
878 * read volume to get the last file number
880 int faketape::find_maxfile()
883 if (fstat(fd, &statp) != 0) {
886 last_file = statp.st_size>>FILE_OFFSET;
888 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
893 void faketape::update_pos()
897 if (fstat(fd, &statp) == 0) {
898 file_block = statp.st_blocks;
901 Dmsg1(dbglevel+1, "update_pos=%i\n", file_block);
903 if (file_block > max_block) {
910 int faketape::seek_file()
913 ASSERT(current_file >= 0);
914 Dmsg2(dbglevel, "seek_file %i:%i\n", current_file, current_block);
917 off_t pos = ((off_t)current_file)<<FILE_OFFSET;
918 if(lseek(fd, pos, SEEK_SET) == -1) {
922 last_file = MAX(last_file, current_file);
923 if (current_block > 0) {
930 void faketape::dump()
932 Dmsg0(dbglevel+1, "===================\n");
933 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
934 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
935 Dmsg1(dbglevel+1, "file_block=%i\n", file_block);
936 Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n",
937 atEOF, atEOT, atEOD, atBOT);
940 #endif /* USE_FAKETAPE */