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
51 static int dbglevel = 10;
52 #define FILE_OFFSET 30
53 faketape *ftape_list[FTAPE_MAX_DRIVE];
55 static faketape *get_tape(int fd)
59 if (fd >= FTAPE_MAX_DRIVE) {
64 return ftape_list[fd];
67 static bool put_tape(faketape *ftape)
69 ASSERT(ftape != NULL);
71 int fd = ftape->get_fd();
72 if (fd >= FTAPE_MAX_DRIVE) {
76 ftape_list[fd] = ftape;
80 void faketape_debug(int level)
85 /****************************************************************/
86 /* theses function will replace open/read/write/close/ioctl
89 int faketape_open(const char *pathname, int flags)
91 ASSERT(pathname != NULL);
94 faketape *tape = new faketape();
95 fd = tape->open(pathname, flags);
102 int faketape_read(int fd, void *buffer, unsigned int count)
104 faketape *tape = get_tape(fd);
105 ASSERT(tape != NULL);
106 return tape->read(buffer, count);
109 int faketape_write(int fd, const void *buffer, unsigned int count)
111 faketape *tape = get_tape(fd);
112 ASSERT(tape != NULL);
113 return tape->write(buffer, count);
116 int faketape_close(int fd)
118 faketape *tape = get_tape(fd);
119 ASSERT(tape != NULL);
125 int faketape_ioctl(int fd, unsigned long int request, ...)
130 faketape *t = get_tape(fd);
136 va_start(argp, request);
138 if (request == MTIOCTOP) {
139 result = t->tape_op(va_arg(argp, mtop *));
140 } else if (request == MTIOCGET) {
141 result = t->tape_get(va_arg(argp, mtget *));
142 } else if (request == MTIOCPOS) {
143 result = t->tape_pos(va_arg(argp, mtpos *));
153 /****************************************************************/
155 int faketape::tape_op(struct mtop *mt_com)
159 switch (mt_com->mt_op)
175 case MTFSF: /* Forward space over mt_count filemarks. */
176 result = fsf(mt_com->mt_count);
179 case MTBSF: /* Backward space over mt_count filemarks. */
180 result = bsf(mt_com->mt_count);
183 case MTFSR: /* Forward space over mt_count records (tape blocks). */
191 mt: /dev/lto2: Erreur d'entree/sortie
196 /* tester si on se trouve a la fin du fichier */
197 result = fsr(mt_com->mt_count);
200 case MTBSR: /* Backward space over mt_count records (tape blocks). */
201 result = bsr(mt_com->mt_count);
204 case MTWEOF: /* Write mt_count filemarks. */
205 result = weof(mt_com->mt_count);
208 case MTREW: /* Rewind. */
209 Dmsg0(dbglevel, "rewind faketape\n");
210 atEOF = atEOD = false;
217 case MTOFFL: /* put tape offline */
221 case MTRETEN: /* Re-tension tape. */
225 case MTBSFM: /* not used by bacula */
230 case MTFSFM: /* not used by bacula */
235 case MTEOM:/* Go to the end of the recorded media (for appending files). */
246 current_file = last_file;
251 case MTERASE: /* not used by bacula */
302 return result == 0 ? 0 : -1;
305 int faketape::tape_get(struct mtget *mt_get)
308 int block_size = 1024;
310 mt_get->mt_type = MT_ISSCSI2;
311 mt_get->mt_blkno = current_block;
312 mt_get->mt_fileno = current_file;
314 mt_get->mt_resid = -1;
315 // pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
319 ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
320 ((block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
323 mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
326 mt_get->mt_gstat |= 0x80000000; // GMT_EOF
330 mt_get->mt_gstat |= 0x40000000; // GMT_BOT
333 mt_get->mt_gstat |= 0x20000000; // GMT_EOT
337 mt_get->mt_gstat |= 0x08000000; // GMT_EOD
340 if (0) { //WriteProtected) {
341 mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
345 mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
347 mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
349 mt_get->mt_erreg = 0;
354 int faketape::tape_pos(struct mtpos *mt_pos)
356 if (current_block >= 0) {
357 mt_pos->mt_blkno = current_block;
365 * This function try to emulate the append only behavior
366 * of a tape. When you wrote something, data after the
367 * current position are discarded.
369 int faketape::truncate_file()
371 Dmsg2(dbglevel, "truncate %i:%i\n", current_file, current_block);
372 ftruncate(fd, lseek(fd, 0, SEEK_CUR));
373 last_file = current_file;
396 max_block = 1024*1024*1024*1024*8;
398 volume = get_pool_memory(PM_NAME);
401 faketape::~faketape()
403 free_pool_memory(volume);
406 int faketape::get_fd()
412 * TODO: check if after a write op, and other tape op put a EOF
414 int faketape::write(const void *buffer, unsigned int count)
416 ASSERT(current_file >= 0);
421 Dmsg3(dbglevel, "write len=%i %i:%i\n", count, current_file,current_block);
424 Dmsg0(dbglevel, "write nothing, EOT !\n");
433 if (!atEOD) { /* if not at the end of the data */
437 if (current_block != -1) {
443 atEOD = true; /* End of data */
445 needEOF = true; /* next operation need EOF mark */
447 // if ((count + file_size) > max_size) {
449 // "EOT writing only %i of %i requested\n",
450 // max_size - file_size, count);
451 // count = max_size - file_size;
455 uint32_t size = count;
456 ::write(fd, &size, sizeof(uint32_t));
457 nb = ::write(fd, buffer, count);
459 file_size += sizeof(uint32_t) + nb;
464 "Not enough space writing only %i of %i requested\n",
471 int faketape::weof(int count)
473 ASSERT(current_file >= 0);
474 Dmsg3(dbglevel, "Writing EOF %i:%i last=%i\n",
475 current_file, current_block,last_file);
481 truncate_file(); /* nothing after this point */
483 /* TODO: check this */
484 current_file += count;
489 ::write(fd, &c, sizeof(uint32_t));
499 int faketape::fsf(int count)
501 ASSERT(current_file >= 0);
504 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
514 atBOT = atEOF = false;
515 Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
517 if ((current_file + count) <= last_file) {
518 current_file += count;
522 Dmsg0(dbglevel, "Try to FSF after EOT\n");
523 current_file = last_file ;
532 int faketape::fsr(int count)
534 ASSERT(current_file >= 0);
540 Dmsg3(dbglevel, "fsr %i:%i count=%i\n", current_file,current_block, count);
555 atBOT = atEOF = false;
557 /* check all block record */
558 for(i=0; (i < count) && !atEOF ; i++) {
559 nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
560 if (nb == sizeof(uint32_t) && s) {
562 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
564 Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
565 current_file, current_block, nb,s);
568 if (current_file < last_file) {
573 atEOF = true; /* stop the loop */
577 find_maxfile(); /* refresh stats */
579 if (where == file_size) {
585 int faketape::bsr(int count)
587 Dmsg2(dbglevel, "bsr current_block=%i count=%i\n",
588 current_block, count);
590 ASSERT(current_file >= 0);
604 off_t last=-1, last2=-1;
605 off_t orig = lseek(fd, 0, SEEK_CUR);
606 int orig_f = current_file;
607 int orig_b = current_block;
615 last = lseek(fd, 0, SEEK_CUR);
616 last_f = current_file;
617 last_b = current_block;
618 Dmsg5(dbglevel, "EOF=%i last=%lli orig=%lli %i:%i\n",
619 atEOF, last, orig, current_file, current_block);
622 } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
624 if (last2 > 0 && atEOF) { /* we take the previous position */
625 lseek(fd, last2, SEEK_SET);
626 current_file = last_f;
627 current_block = last_b - 1;
628 Dmsg3(dbglevel, "set offset2=%lli %i:%i\n",
629 last, current_file, current_block);
631 } else if (last > 0) {
632 lseek(fd, last, SEEK_SET);
633 current_file = last_f;
634 current_block = last_b;
635 Dmsg3(dbglevel, "set offset=%lli %i:%i\n",
636 last, current_file, current_block);
638 lseek(fd, orig, SEEK_SET);
639 current_file = orig_f;
640 current_block = orig_b;
644 Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
645 atEOT = atEOF = atEOD = false;
650 int faketape::bsf(int count)
652 ASSERT(current_file >= 0);
653 Dmsg3(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block, count);
657 atBOT = atEOF = atEOT = atEOD = false;
659 if (current_file - count < 0) {
666 current_file = current_file - count + 1;
670 /* go just before last EOF */
671 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
677 * Put faketape in offline mode
679 int faketape::offline()
683 atEOF = false; /* End of file */
684 atEOT = false; /* End of tape */
685 atEOD = false; /* End of data */
686 atBOT = false; /* Begin of tape */
694 int faketape::close()
704 * EOF Bacula status: file=2 block=0
705 * Device status: EOF ONLINE IM_REP_EN file=2 block=0
708 * EOD EOF Bacula status: file=2 block=0
709 * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
713 int faketape::read(void *buffer, unsigned int count)
715 ASSERT(current_file >= 0);
719 Dmsg2(dbglevel, "read %i:%i\n", current_file, current_block);
721 if (atEOT || atEOD) {
736 atEOD = atBOT = false;
739 nb = ::read(fd, &s, sizeof(uint32_t));
744 if (s > count) { /* not enough buffer to read block */
745 lseek(fd, s, SEEK_CUR);
751 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(uint32_t), SEEK_SET);
754 nb = ::read(fd, buffer, s);
757 if (current_file == last_file) {
761 Dmsg0(dbglevel, "EOF during reading\n");
766 int faketape::open(const char *pathname, int uflags)
768 Dmsg2(dbglevel, "faketape::open(%s, %i)\n", pathname, uflags);
769 pm_strcpy(volume, pathname);
772 if (stat(volume, &statp) != 0) {
773 Dmsg1(dbglevel, "Can't stat on %s\n", volume);
777 fd = ::open(pathname, O_CREAT | O_RDWR, 0700);
782 /* open volume descriptor and get this->fd */
783 if (find_maxfile() < 0) {
790 online = inplace = true;
792 atEOT = atEOD = false;
798 * read volume to get the last file number
800 int faketape::find_maxfile()
803 if (fstat(fd, &statp) != 0) {
806 last_file = statp.st_size>>FILE_OFFSET;
807 file_size = statp.st_size;
809 current_pos = lseek(fd, 0, SEEK_CUR); /* get current position */
810 Dmsg3(dbglevel+1, "last_file=%i file_size=%u current_pos=%i\n",
811 last_file, file_size, current_pos);
816 int faketape::seek_file()
818 ASSERT(current_file >= 0);
819 Dmsg2(dbglevel, "seek_file %i:%i\n", current_file, current_block);
821 off_t pos = ((off_t)current_file)<<FILE_OFFSET;
822 if(lseek(fd, pos, SEEK_SET) == -1) {
825 if (current_block > 0) {
828 last_file = (last_file > current_file)?last_file:current_file;
834 void faketape::dump()
836 Dmsg0(dbglevel+1, "===================\n");
837 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
838 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
839 Dmsg1(dbglevel+1, "volume=%s\n", volume);
840 Dmsg1(dbglevel+1, "file_size=%i\n", file_size);
841 Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n",
842 atEOF, atEOT, atEOD, atBOT);