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)
172 switch (mt_com->mt_op)
188 case MTFSF: /* Forward space over mt_count filemarks. */
189 result = fsf(mt_com->mt_count);
192 case MTBSF: /* Backward space over mt_count filemarks. */
193 result = bsf(mt_com->mt_count);
196 case MTFSR: /* Forward space over mt_count records (tape blocks). */
204 mt: /dev/lto2: Erreur d'entree/sortie
209 /* tester si on se trouve a la fin du fichier */
210 result = fsr(mt_com->mt_count);
213 case MTBSR: /* Backward space over mt_count records (tape blocks). */
214 result = bsr(mt_com->mt_count);
217 case MTWEOF: /* Write mt_count filemarks. */
218 result = weof(mt_com->mt_count);
221 case MTREW: /* Rewind. */
222 Dmsg0(dbglevel, "rewind faketape\n");
223 atEOF = atEOD = false;
230 case MTOFFL: /* put tape offline */
234 case MTRETEN: /* Re-tension tape. */
238 case MTBSFM: /* not used by bacula */
243 case MTFSFM: /* not used by bacula */
248 case MTEOM:/* Go to the end of the recorded media (for appending files). */
259 current_file = last_file;
264 case MTERASE: /* not used by bacula */
315 return result == 0 ? 0 : -1;
318 int faketape::tape_get(struct mtget *mt_get)
321 int block_size = 1024;
323 mt_get->mt_type = MT_ISSCSI2;
324 mt_get->mt_blkno = current_block;
325 mt_get->mt_fileno = current_file;
327 mt_get->mt_resid = -1;
328 // pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
332 ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
333 ((block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
336 mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
339 mt_get->mt_gstat |= 0x80000000; // GMT_EOF
343 mt_get->mt_gstat |= 0x40000000; // GMT_BOT
346 mt_get->mt_gstat |= 0x20000000; // GMT_EOT
350 mt_get->mt_gstat |= 0x08000000; // GMT_EOD
353 if (0) { //WriteProtected) {
354 mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
358 mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
360 mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
362 mt_get->mt_erreg = 0;
367 int faketape::tape_pos(struct mtpos *mt_pos)
369 if (current_block >= 0) {
370 mt_pos->mt_blkno = current_block;
378 * This function try to emulate the append only behavior
379 * of a tape. When you wrote something, data after the
380 * current position are discarded.
382 int faketape::truncate_file()
384 Dmsg2(dbglevel, "truncate %i:%i\n", current_file, current_block);
385 ftruncate(fd, lseek(fd, 0, SEEK_CUR));
386 last_file = current_file;
409 max_block = 1024*1024*1024*1024*8;
413 faketape::~faketape()
417 int faketape::get_fd()
423 * TODO: check if after a write op, and other tape op put a EOF
425 int faketape::write(const void *buffer, unsigned int count)
427 ASSERT(current_file >= 0);
432 Dmsg3(dbglevel, "write len=%i %i:%i\n", count, current_file,current_block);
435 Dmsg0(dbglevel, "write nothing, EOT !\n");
444 if (!atEOD) { /* if not at the end of the data */
448 if (current_block != -1) {
454 atEOD = true; /* End of data */
456 needEOF = true; /* next operation need EOF mark */
458 // if ((count + file_size) > max_size) {
460 // "EOT writing only %i of %i requested\n",
461 // max_size - file_size, count);
462 // count = max_size - file_size;
466 uint32_t size = count;
467 ::write(fd, &size, sizeof(uint32_t));
468 nb = ::write(fd, buffer, count);
470 file_size += sizeof(uint32_t) + nb;
475 "Not enough space writing only %i of %i requested\n",
482 int faketape::weof(int count)
484 ASSERT(current_file >= 0);
485 Dmsg3(dbglevel, "Writing EOF %i:%i last=%i\n",
486 current_file, current_block,last_file);
493 truncate_file(); /* nothing after this point */
495 /* TODO: check this */
496 current_file += count;
501 ::write(fd, &c, sizeof(uint32_t));
511 int faketape::fsf(int count)
513 ASSERT(current_file >= 0);
516 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
526 atBOT = atEOF = false;
527 Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
529 if ((current_file + count) <= last_file) {
530 current_file += count;
534 Dmsg0(dbglevel, "Try to FSF after EOT\n");
535 current_file = last_file ;
544 int faketape::fsr(int count)
546 ASSERT(current_file >= 0);
552 Dmsg3(dbglevel, "fsr %i:%i count=%i\n", current_file,current_block, count);
567 atBOT = atEOF = false;
569 /* check all block record */
570 for(i=0; (i < count) && !atEOF ; i++) {
571 nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
572 if (nb == sizeof(uint32_t) && s) {
574 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
576 Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
577 current_file, current_block, nb,s);
580 if (current_file < last_file) {
585 atEOF = true; /* stop the loop */
589 find_maxfile(); /* refresh stats */
591 if (where == file_size) {
597 int faketape::bsr(int count)
599 Dmsg2(dbglevel, "bsr current_block=%i count=%i\n",
600 current_block, count);
602 ASSERT(current_file >= 0);
616 off_t last=-1, last2=-1;
617 off_t orig = lseek(fd, 0, SEEK_CUR);
618 int orig_f = current_file;
619 int orig_b = current_block;
627 last = lseek(fd, 0, SEEK_CUR);
628 last_f = current_file;
629 last_b = current_block;
630 Dmsg5(dbglevel, "EOF=%i last=%lli orig=%lli %i:%i\n",
631 atEOF, last, orig, current_file, current_block);
634 } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
636 if (last2 > 0 && atEOF) { /* we take the previous position */
637 lseek(fd, last2, SEEK_SET);
638 current_file = last_f;
639 current_block = last_b - 1;
640 Dmsg3(dbglevel, "set offset2=%lli %i:%i\n",
641 last, current_file, current_block);
643 } else if (last > 0) {
644 lseek(fd, last, SEEK_SET);
645 current_file = last_f;
646 current_block = last_b;
647 Dmsg3(dbglevel, "set offset=%lli %i:%i\n",
648 last, current_file, current_block);
650 lseek(fd, orig, SEEK_SET);
651 current_file = orig_f;
652 current_block = orig_b;
656 Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
657 atEOT = atEOF = atEOD = false;
662 int faketape::bsf(int count)
664 ASSERT(current_file >= 0);
665 Dmsg3(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block, count);
669 atBOT = atEOF = atEOT = atEOD = false;
671 if (current_file - count < 0) {
678 current_file = current_file - count + 1;
682 /* go just before last EOF */
683 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
689 * Put faketape in offline mode
691 int faketape::offline()
695 atEOF = false; /* End of file */
696 atEOT = false; /* End of tape */
697 atEOD = false; /* End of data */
698 atBOT = false; /* Begin of tape */
706 int faketape::close()
716 * EOF Bacula status: file=2 block=0
717 * Device status: EOF ONLINE IM_REP_EN file=2 block=0
720 * EOD EOF Bacula status: file=2 block=0
721 * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
725 int faketape::read(void *buffer, unsigned int count)
727 ASSERT(current_file >= 0);
731 Dmsg2(dbglevel, "read %i:%i\n", current_file, current_block);
733 if (atEOT || atEOD) {
748 atEOD = atBOT = false;
751 nb = ::read(fd, &s, sizeof(uint32_t));
756 if (s > count) { /* not enough buffer to read block */
757 Dmsg2(dbglevel, "Need more buffer to read next block %i > %i\n",s,count);
758 lseek(fd, s, SEEK_CUR);
764 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
767 nb = ::read(fd, buffer, s);
770 if (current_file == last_file) {
774 Dmsg0(dbglevel, "EOF during reading\n");
779 int faketape::open(const char *pathname, int uflags)
781 Dmsg2(dbglevel, "faketape::open(%s, %i)\n", pathname, uflags);
784 if (stat(pathname, &statp) != 0) {
785 Dmsg1(dbglevel, "Can't stat on %s\n", pathname);
789 fd = ::open(pathname, O_CREAT | O_RDWR | O_LARGEFILE, 0700);
794 /* open volume descriptor and get this->fd */
795 if (find_maxfile() < 0) {
802 online = inplace = true;
804 atEOT = atEOD = false;
810 * read volume to get the last file number
812 int faketape::find_maxfile()
815 if (fstat(fd, &statp) != 0) {
818 last_file = statp.st_size>>FILE_OFFSET;
819 file_size = statp.st_size;
821 current_pos = lseek(fd, 0, SEEK_CUR); /* get current position */
822 Dmsg3(dbglevel+1, "last_file=%i file_size=%u current_pos=%i\n",
823 last_file, file_size, current_pos);
828 int faketape::seek_file()
830 ASSERT(current_file >= 0);
831 Dmsg2(dbglevel, "seek_file %i:%i\n", current_file, current_block);
833 off_t pos = ((off_t)current_file)<<FILE_OFFSET;
834 if(lseek(fd, pos, SEEK_SET) == -1) {
837 last_file = (last_file > current_file)?last_file:current_file;
838 if (current_block > 0) {
846 void faketape::dump()
848 Dmsg0(dbglevel+1, "===================\n");
849 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
850 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
851 Dmsg1(dbglevel+1, "file_size=%i\n", file_size);
852 Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n",
853 atEOF, atEOT, atEOD, atBOT);