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 */
64 static int dbglevel = 10;
65 #define FILE_OFFSET 30
66 faketape *ftape_list[FTAPE_MAX_DRIVE];
68 static faketape *get_tape(int fd)
72 if (fd >= FTAPE_MAX_DRIVE) {
77 return ftape_list[fd];
80 static bool put_tape(faketape *ftape)
82 ASSERT(ftape != NULL);
84 int fd = ftape->get_fd();
85 if (fd >= FTAPE_MAX_DRIVE) {
89 ftape_list[fd] = ftape;
93 void faketape_debug(int level)
98 /****************************************************************/
99 /* theses function will replace open/read/write/close/ioctl
102 int faketape_open(const char *pathname, int flags)
104 ASSERT(pathname != NULL);
107 faketape *tape = new faketape();
108 fd = tape->open(pathname, flags);
115 int faketape_read(int fd, void *buffer, unsigned int count)
117 faketape *tape = get_tape(fd);
118 ASSERT(tape != NULL);
119 return tape->read(buffer, count);
122 int faketape_write(int fd, const void *buffer, unsigned int count)
124 faketape *tape = get_tape(fd);
125 ASSERT(tape != NULL);
126 return tape->write(buffer, count);
129 int faketape_close(int fd)
131 faketape *tape = get_tape(fd);
132 ASSERT(tape != NULL);
138 int faketape_ioctl(int fd, unsigned long int request, ...)
143 faketape *t = get_tape(fd);
149 va_start(argp, request);
151 if (request == MTIOCTOP) {
152 result = t->tape_op(va_arg(argp, mtop *));
153 } else if (request == MTIOCGET) {
154 result = t->tape_get(va_arg(argp, mtget *));
155 } else if (request == MTIOCPOS) {
156 result = t->tape_pos(va_arg(argp, mtpos *));
166 /****************************************************************/
168 int faketape::tape_op(struct mtop *mt_com)
177 switch (mt_com->mt_op)
193 case MTFSF: /* Forward space over mt_count filemarks. */
194 result = fsf(mt_com->mt_count);
197 case MTBSF: /* Backward space over mt_count filemarks. */
198 result = bsf(mt_com->mt_count);
201 case MTFSR: /* Forward space over mt_count records (tape blocks). */
209 mt: /dev/lto2: Erreur d'entree/sortie
214 /* tester si on se trouve a la fin du fichier */
215 result = fsr(mt_com->mt_count);
218 case MTBSR: /* Backward space over mt_count records (tape blocks). */
219 result = bsr(mt_com->mt_count);
222 case MTWEOF: /* Write mt_count filemarks. */
223 result = weof(mt_com->mt_count);
226 case MTREW: /* Rewind. */
227 Dmsg0(dbglevel, "rewind faketape\n");
228 atEOF = atEOD = false;
235 case MTOFFL: /* put tape offline */
239 case MTRETEN: /* Re-tension tape. */
243 case MTBSFM: /* not used by bacula */
248 case MTFSFM: /* not used by bacula */
253 case MTEOM:/* Go to the end of the recorded media (for appending files). */
264 current_file = last_file;
269 case MTERASE: /* not used by bacula */
320 return result == 0 ? 0 : -1;
323 int faketape::tape_get(struct mtget *mt_get)
326 int block_size = 1024;
328 mt_get->mt_type = MT_ISSCSI2;
329 mt_get->mt_blkno = current_block;
330 mt_get->mt_fileno = current_file;
332 mt_get->mt_resid = -1;
333 // pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
337 ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
338 ((block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
341 mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
344 mt_get->mt_gstat |= 0x80000000; // GMT_EOF
348 mt_get->mt_gstat |= 0x40000000; // GMT_BOT
351 mt_get->mt_gstat |= 0x20000000; // GMT_EOT
355 mt_get->mt_gstat |= 0x08000000; // GMT_EOD
358 if (0) { //WriteProtected) {
359 mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
363 mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
365 mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
367 mt_get->mt_erreg = 0;
372 int faketape::tape_pos(struct mtpos *mt_pos)
374 if (current_block >= 0) {
375 mt_pos->mt_blkno = current_block;
383 * This function try to emulate the append only behavior
384 * of a tape. When you wrote something, data after the
385 * current position are discarded.
387 int faketape::truncate_file()
389 Dmsg2(dbglevel, "truncate %i:%i\n", current_file, current_block);
390 ftruncate(fd, lseek(fd, 0, SEEK_CUR));
391 last_file = current_file;
414 max_block = 1024*1024*1024*1024*8;
418 faketape::~faketape()
422 int faketape::get_fd()
428 * TODO: check if after a write op, and other tape op put a EOF
430 int faketape::write(const void *buffer, unsigned int count)
433 ASSERT(current_file >= 0);
438 Dmsg3(dbglevel, "write len=%i %i:%i\n", count, current_file,current_block);
441 Dmsg0(dbglevel, "write nothing, EOT !\n");
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);
476 file_size += sizeof(uint32_t) + nb;
481 "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);
500 truncate_file(); /* nothing after this point */
502 /* TODO: check this */
503 current_file += count;
508 ::write(fd, &c, sizeof(uint32_t));
518 int faketape::fsf(int count)
521 ASSERT(current_file >= 0);
524 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
534 atBOT = atEOF = false;
535 Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
537 if ((current_file + count) <= last_file) {
538 current_file += count;
542 Dmsg0(dbglevel, "Try to FSF after EOT\n");
543 current_file = last_file ;
552 int faketape::fsr(int count)
555 ASSERT(current_file >= 0);
561 Dmsg3(dbglevel, "fsr %i:%i count=%i\n", current_file,current_block, count);
576 atBOT = atEOF = false;
578 /* check all block record */
579 for(i=0; (i < count) && !atEOF ; i++) {
580 nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
581 if (nb == sizeof(uint32_t) && s) {
583 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
585 Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
586 current_file, current_block, nb,s);
589 if (current_file < last_file) {
594 atEOF = true; /* stop the loop */
598 find_maxfile(); /* refresh stats */
600 if (where == file_size) {
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 */
718 int faketape::close()
728 * EOF Bacula status: file=2 block=0
729 * Device status: EOF ONLINE IM_REP_EN file=2 block=0
732 * EOD EOF Bacula status: file=2 block=0
733 * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
737 int faketape::read(void *buffer, unsigned int count)
740 ASSERT(current_file >= 0);
744 Dmsg2(dbglevel, "read %i:%i\n", current_file, current_block);
746 if (atEOT || atEOD) {
761 atEOD = atBOT = false;
764 nb = ::read(fd, &s, sizeof(uint32_t));
769 if (s > count) { /* not enough buffer to read block */
770 Dmsg2(dbglevel, "Need more buffer to read next block %i > %i\n",s,count);
771 lseek(fd, s, SEEK_CUR);
777 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
780 nb = ::read(fd, buffer, s);
783 if (current_file == last_file) {
787 Dmsg0(dbglevel, "EOF during reading\n");
792 int faketape::open(const char *pathname, int uflags)
794 Dmsg2(dbglevel, "faketape::open(%s, %i)\n", pathname, uflags);
796 online = true; /* assume that drive contains a tape */
799 if (stat(pathname, &statp) != 0) {
800 Dmsg1(dbglevel, "Can't stat on %s\n", pathname);
801 if (uflags & O_NONBLOCK) {
803 fd = ::open("/dev/null", O_CREAT | O_RDWR | O_LARGEFILE, 0600);
806 fd = ::open(pathname, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
814 /* open volume descriptor and get this->fd */
822 atEOT = atEOD = false;
828 * read volume to get the last file number
830 int faketape::find_maxfile()
833 if (fstat(fd, &statp) != 0) {
836 last_file = statp.st_size>>FILE_OFFSET;
837 file_size = statp.st_size;
839 current_pos = lseek(fd, 0, SEEK_CUR); /* get current position */
840 Dmsg3(dbglevel+1, "last_file=%i file_size=%u current_pos=%i\n",
841 last_file, file_size, current_pos);
846 int faketape::seek_file()
849 ASSERT(current_file >= 0);
850 Dmsg2(dbglevel, "seek_file %i:%i\n", current_file, current_block);
852 off_t pos = ((off_t)current_file)<<FILE_OFFSET;
853 if(lseek(fd, pos, SEEK_SET) == -1) {
856 last_file = (last_file > current_file)?last_file:current_file;
857 if (current_block > 0) {
865 void faketape::dump()
867 Dmsg0(dbglevel+1, "===================\n");
868 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
869 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
870 Dmsg1(dbglevel+1, "file_size=%i\n", file_size);
871 Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n",
872 atEOF, atEOT, atEOD, atBOT);