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
46 #include "bacula.h" /* define 64bit file usage */
50 static int dbglevel = 10;
51 #define FILE_OFFSET 30
52 faketape *ftape_list[FTAPE_MAX_DRIVE];
54 static faketape *get_tape(int fd)
58 if (fd >= FTAPE_MAX_DRIVE) {
63 return ftape_list[fd];
66 static bool put_tape(faketape *ftape)
68 ASSERT(ftape != NULL);
70 int fd = ftape->get_fd();
71 if (fd >= FTAPE_MAX_DRIVE) {
75 ftape_list[fd] = ftape;
79 void faketape_debug(int level)
84 /****************************************************************/
85 /* theses function will replace open/read/write/close/ioctl
88 int faketape_open(const char *pathname, int flags)
90 ASSERT(pathname != NULL);
93 faketape *tape = new faketape();
94 fd = tape->open(pathname, flags);
101 int faketape_read(int fd, void *buffer, unsigned int count)
103 faketape *tape = get_tape(fd);
104 ASSERT(tape != NULL);
105 return tape->read(buffer, count);
108 int faketape_write(int fd, const void *buffer, unsigned int count)
110 faketape *tape = get_tape(fd);
111 ASSERT(tape != NULL);
112 return tape->write(buffer, count);
115 int faketape_close(int fd)
117 faketape *tape = get_tape(fd);
118 ASSERT(tape != NULL);
124 int faketape_ioctl(int fd, unsigned long int request, ...)
129 faketape *t = get_tape(fd);
135 va_start(argp, request);
137 if (request == MTIOCTOP) {
138 result = t->tape_op(va_arg(argp, mtop *));
139 } else if (request == MTIOCGET) {
140 result = t->tape_get(va_arg(argp, mtget *));
141 } else if (request == MTIOCPOS) {
142 result = t->tape_pos(va_arg(argp, mtpos *));
152 /****************************************************************/
154 int faketape::tape_op(struct mtop *mt_com)
158 switch (mt_com->mt_op)
174 case MTFSF: /* Forward space over mt_count filemarks. */
175 result = fsf(mt_com->mt_count);
178 case MTBSF: /* Backward space over mt_count filemarks. */
179 result = bsf(mt_com->mt_count);
182 case MTFSR: /* Forward space over mt_count records (tape blocks). */
190 mt: /dev/lto2: Erreur d'entree/sortie
195 /* tester si on se trouve a la fin du fichier */
196 result = fsr(mt_com->mt_count);
199 case MTBSR: /* Backward space over mt_count records (tape blocks). */
200 result = bsr(mt_com->mt_count);
203 case MTWEOF: /* Write mt_count filemarks. */
204 result = weof(mt_com->mt_count);
207 case MTREW: /* Rewind. */
208 Dmsg0(dbglevel, "rewind faketape\n");
209 atEOF = atEOD = false;
216 case MTOFFL: /* put tape offline */
220 case MTRETEN: /* Re-tension tape. */
224 case MTBSFM: /* not used by bacula */
229 case MTFSFM: /* not used by bacula */
234 case MTEOM:/* Go to the end of the recorded media (for appending files). */
245 current_file = last_file;
250 case MTERASE: /* not used by bacula */
301 return result == 0 ? 0 : -1;
304 int faketape::tape_get(struct mtget *mt_get)
307 int block_size = 1024;
309 mt_get->mt_type = MT_ISSCSI2;
310 mt_get->mt_blkno = current_block;
311 mt_get->mt_fileno = current_file;
313 mt_get->mt_resid = -1;
314 // pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
318 ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
319 ((block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
322 mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
325 mt_get->mt_gstat |= 0x80000000; // GMT_EOF
329 mt_get->mt_gstat |= 0x40000000; // GMT_BOT
332 mt_get->mt_gstat |= 0x20000000; // GMT_EOT
336 mt_get->mt_gstat |= 0x08000000; // GMT_EOD
339 if (0) { //WriteProtected) {
340 mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
344 mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
346 mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
348 mt_get->mt_erreg = 0;
353 int faketape::tape_pos(struct mtpos *mt_pos)
355 if (current_block >= 0) {
356 mt_pos->mt_blkno = current_block;
364 * This function try to emulate the append only behavior
365 * of a tape. When you wrote something, data after the
366 * current position are discarded.
368 int faketape::truncate_file()
370 Dmsg2(dbglevel, "truncate %i:%i\n", current_file, current_block);
371 ftruncate(fd, lseek(fd, 0, SEEK_CUR));
372 last_file = current_file;
395 max_block = 1024*1024*1024*1024*8;
397 volume = get_pool_memory(PM_NAME);
400 faketape::~faketape()
402 free_pool_memory(volume);
405 int faketape::get_fd()
411 * TODO: check if after a write op, and other tape op put a EOF
413 int faketape::write(const void *buffer, unsigned int count)
415 ASSERT(current_file >= 0);
420 Dmsg3(dbglevel, "write len=%i %i:%i\n", count, current_file,current_block);
423 Dmsg0(dbglevel, "write nothing, EOT !\n");
432 if (!atEOD) { /* if not at the end of the data */
436 if (current_block != -1) {
442 atEOD = true; /* End of data */
444 needEOF = true; /* next operation need EOF mark */
446 // if ((count + file_size) > max_size) {
448 // "EOT writing only %i of %i requested\n",
449 // max_size - file_size, count);
450 // count = max_size - file_size;
454 uint32_t size = count;
455 ::write(fd, &size, sizeof(uint32_t));
456 nb = ::write(fd, buffer, count);
458 file_size += sizeof(uint32_t) + nb;
463 "Not enough space writing only %i of %i requested\n",
470 int faketape::weof(int count)
472 ASSERT(current_file >= 0);
473 Dmsg3(dbglevel, "Writing EOF %i:%i last=%i\n",
474 current_file, current_block,last_file);
480 truncate_file(); /* nothing after this point */
482 /* TODO: check this */
483 current_file += count;
488 ::write(fd, &c, sizeof(uint32_t));
498 int faketape::fsf(int count)
500 ASSERT(current_file >= 0);
503 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
513 atBOT = atEOF = false;
514 Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
516 if ((current_file + count) <= last_file) {
517 current_file += count;
521 Dmsg0(dbglevel, "Try to FSF after EOT\n");
522 current_file = last_file ;
531 int faketape::fsr(int count)
533 ASSERT(current_file >= 0);
539 Dmsg3(dbglevel, "fsr %i:%i count=%i\n", current_file,current_block, count);
554 atBOT = atEOF = false;
556 /* check all block record */
557 for(i=0; (i < count) && !atEOF ; i++) {
558 nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
559 if (nb == sizeof(uint32_t) && s) {
561 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
563 Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
564 current_file, current_block, nb,s);
567 if (current_file < last_file) {
572 atEOF = true; /* stop the loop */
576 find_maxfile(); /* refresh stats */
578 if (where == file_size) {
584 int faketape::bsr(int count)
586 Dmsg2(dbglevel, "bsr current_block=%i count=%i\n",
587 current_block, count);
589 ASSERT(current_file >= 0);
603 off_t last=-1, last2=-1;
604 off_t orig = lseek(fd, 0, SEEK_CUR);
605 int orig_f = current_file;
606 int orig_b = current_block;
614 last = lseek(fd, 0, SEEK_CUR);
615 last_f = current_file;
616 last_b = current_block;
617 Dmsg5(dbglevel, "EOF=%i last=%lli orig=%lli %i:%i\n",
618 atEOF, last, orig, current_file, current_block);
621 } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
623 if (last2 > 0 && atEOF) { /* we take the previous position */
624 lseek(fd, last2, SEEK_SET);
625 current_file = last_f;
626 current_block = last_b - 1;
627 Dmsg3(dbglevel, "set offset2=%lli %i:%i\n",
628 last, current_file, current_block);
630 } else if (last > 0) {
631 lseek(fd, last, SEEK_SET);
632 current_file = last_f;
633 current_block = last_b;
634 Dmsg3(dbglevel, "set offset=%lli %i:%i\n",
635 last, current_file, current_block);
637 lseek(fd, orig, SEEK_SET);
638 current_file = orig_f;
639 current_block = orig_b;
643 Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
644 atEOT = atEOF = atEOD = false;
649 int faketape::bsf(int count)
651 ASSERT(current_file >= 0);
652 Dmsg3(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block, count);
656 atBOT = atEOF = atEOT = atEOD = false;
658 if (current_file - count < 0) {
665 current_file = current_file - count + 1;
669 /* go just before last EOF */
670 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
676 * Put faketape in offline mode
678 int faketape::offline()
682 atEOF = false; /* End of file */
683 atEOT = false; /* End of tape */
684 atEOD = false; /* End of data */
685 atBOT = false; /* Begin of tape */
693 int faketape::close()
703 * EOF Bacula status: file=2 block=0
704 * Device status: EOF ONLINE IM_REP_EN file=2 block=0
707 * EOD EOF Bacula status: file=2 block=0
708 * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
712 int faketape::read(void *buffer, unsigned int count)
714 ASSERT(current_file >= 0);
718 Dmsg2(dbglevel, "read %i:%i\n", current_file, current_block);
720 if (atEOT || atEOD) {
735 atEOD = atBOT = false;
738 nb = ::read(fd, &s, sizeof(uint32_t));
743 if (s > count) { /* not enough buffer to read block */
744 lseek(fd, s, SEEK_CUR);
750 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
753 nb = ::read(fd, buffer, s);
756 if (current_file == last_file) {
760 Dmsg0(dbglevel, "EOF during reading\n");
765 int faketape::open(const char *pathname, int uflags)
767 Dmsg2(dbglevel, "faketape::open(%s, %i)\n", pathname, uflags);
768 pm_strcpy(volume, pathname);
771 if (stat(volume, &statp) != 0) {
772 Dmsg1(dbglevel, "Can't stat on %s\n", volume);
776 fd = ::open(pathname, O_CREAT | O_RDWR | O_LARGEFILE, 0700);
781 /* open volume descriptor and get this->fd */
782 if (find_maxfile() < 0) {
789 online = inplace = true;
791 atEOT = atEOD = false;
797 * read volume to get the last file number
799 int faketape::find_maxfile()
802 if (fstat(fd, &statp) != 0) {
805 last_file = statp.st_size>>FILE_OFFSET;
806 file_size = statp.st_size;
808 current_pos = lseek(fd, 0, SEEK_CUR); /* get current position */
809 Dmsg3(dbglevel+1, "last_file=%i file_size=%u current_pos=%i\n",
810 last_file, file_size, current_pos);
815 int faketape::seek_file()
817 ASSERT(current_file >= 0);
818 Dmsg2(dbglevel, "seek_file %i:%i\n", current_file, current_block);
820 off_t pos = ((off_t)current_file)<<FILE_OFFSET;
821 if(lseek(fd, pos, SEEK_SET) == -1) {
824 last_file = (last_file > current_file)?last_file:current_file;
825 if (current_block > 0) {
833 void faketape::dump()
835 Dmsg0(dbglevel+1, "===================\n");
836 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
837 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
838 Dmsg1(dbglevel+1, "volume=%s\n", volume);
839 Dmsg1(dbglevel+1, "file_size=%i\n", file_size);
840 Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n",
841 atEOF, atEOT, atEOD, atBOT);