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.
30 * Maximum File Size = 800G
39 static int dbglevel = 0;
41 faketape *ftape_list[FTAPE_MAX_DRIVE];
43 static faketape *get_tape(int fd)
47 if (fd >= FTAPE_MAX_DRIVE) {
52 return ftape_list[fd];
55 static bool put_tape(faketape *ftape)
57 ASSERT(ftape != NULL);
59 int fd = ftape->get_fd();
60 if (fd >= FTAPE_MAX_DRIVE) {
64 ftape_list[fd] = ftape;
68 void faketape_debug(int level)
73 /****************************************************************/
74 /* theses function will replace open/read/write/close/ioctl
77 int faketape_open(const char *pathname, int flags, int mode)
79 ASSERT(pathname != NULL);
82 faketape *tape = new faketape();
83 fd = tape->open(pathname, flags, mode);
90 int faketape_read(int fd, void *buffer, unsigned int count)
92 faketape *tape = get_tape(fd);
94 return tape->read(buffer, count);
97 int faketape_write(int fd, const void *buffer, unsigned int count)
99 faketape *tape = get_tape(fd);
100 ASSERT(tape != NULL);
101 return tape->write(buffer, count);
104 int faketape_close(int fd)
106 faketape *tape = get_tape(fd);
107 ASSERT(tape != NULL);
113 int faketape_ioctl(int fd, unsigned long int request, ...)
118 faketape *t = get_tape(fd);
124 va_start(argp, request);
126 if (request == MTIOCTOP) {
127 result = t->tape_op(va_arg(argp, mtop *));
128 } else if (request == MTIOCGET) {
129 result = t->tape_get(va_arg(argp, mtget *));
133 // result = tape_pos(fd, va_arg(argp, mtpos *));
145 /****************************************************************/
147 int faketape::tape_op(struct mtop *mt_com)
151 switch (mt_com->mt_op)
167 case MTFSF: /* Forward space over mt_count filemarks. */
168 result = fsf(mt_com->mt_count);
171 case MTBSF: /* Backward space over mt_count filemarks. */
172 result = bsf(mt_com->mt_count);
175 case MTFSR: /* Forward space over mt_count records (tape blocks). */
183 mt: /dev/lto2: Erreur d'entrée/sortie
188 /* tester si on se trouve a la fin du fichier */
189 result = fsr(mt_com->mt_count);
192 case MTBSR: /* Backward space over mt_count records (tape blocks). */
196 case MTWEOF: /* Write mt_count filemarks. */
197 weof(mt_com->mt_count);
200 case MTREW: /* Rewind. */
201 atEOF = atEOD = false;
208 case MTOFFL: /* put tape offline */
212 case MTRETEN: /* Re-tension tape. */
216 case MTBSFM: /* not used by bacula */
221 case MTFSFM: /* not used by bacula */
226 case MTEOM:/* Go to the end of the recorded media (for appending files). */
236 current_file = last_file;
241 case MTERASE: /* not used by bacula */
294 // case -1: /* Error has already been translated into errno */
298 // case ERROR_FILEMARK_DETECTED:
302 // case ERROR_END_OF_MEDIA:
306 // case ERROR_NO_DATA_DETECTED:
310 // case ERROR_NO_MEDIA_IN_DRIVE:
311 // errno = ENOMEDIUM;
314 // case ERROR_INVALID_HANDLE:
315 // case ERROR_ACCESS_DENIED:
316 // case ERROR_LOCK_VIOLATION:
321 return result == 0 ? 0 : -1;
324 int faketape::tape_get(struct mtget *mt_get)
327 int block_size = 1024;
329 mt_get->mt_type = MT_ISSCSI2;
330 mt_get->mt_blkno = current_block;
331 mt_get->mt_fileno = current_file;
333 mt_get->mt_resid = -1;
334 // pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
338 ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
339 ((block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
342 mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
345 mt_get->mt_gstat |= 0x80000000; // GMT_EOF
349 mt_get->mt_gstat |= 0x40000000; // GMT_BOT
352 mt_get->mt_gstat |= 0x20000000; // GMT_EOT
356 mt_get->mt_gstat |= 0x08000000; // GMT_EOD
359 if (0) { //WriteProtected) {
360 mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
364 mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
366 mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
368 mt_get->mt_erreg = 0;
373 int faketape::tape_pos(struct mtpos *mt_pos)
379 * This function try to emulate the append only behavior
380 * of a tape. When you wrote something, data after the
381 * current position are discarded.
383 int faketape::truncate_file()
385 Dmsg2(dbglevel, "truncate %i:%i\n", current_file, current_block);
386 ftruncate(fd, lseek(fd, 0, SEEK_CUR));
387 last_file = current_file;
408 max_block = 1024*1024*1024*1024*8;
410 volume = get_pool_memory(PM_NAME);
413 faketape::~faketape()
415 free_pool_memory(volume);
418 int faketape::get_fd()
424 * TODO: regarder si apres un write une operation x pose un EOF
426 int faketape::write(const void *buffer, unsigned int count)
428 ASSERT(current_file >= 0);
433 Dmsg2(dbglevel, "write len=%i blocks=%i\n", count, current_block);
436 Dmsg0(dbglevel, "write nothing, EOT !\n");
445 if (!atEOD) { /* if not at the end of the data */
449 if (current_block != -1) {
457 // if ((count + file_size) > max_size) {
459 // "EOT writing only %i of %i requested\n",
460 // max_size - file_size, count);
461 // count = max_size - file_size;
465 ::write(fd, &count, sizeof(count));
466 nb = ::write(fd, buffer, count);
468 file_size += sizeof(count) + nb;
473 "Not enough space writing only %i of %i requested\n",
480 int faketape::weof(int count)
483 ASSERT(current_file >= 0);
484 Dmsg3(dbglevel, "Writing EOF %i:%i last=%i\n",
485 current_file, current_block,last_file);
492 truncate_file(); /* nothing after this point */
494 /* TODO: check this */
495 current_file += count;
499 ::write(fd, &c, sizeof(c));
509 int faketape::fsf(int count)
511 ASSERT(current_file >= 0);
514 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
522 atBOT = atEOF = false;
523 Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
525 if ((current_file + count) <= last_file) {
526 current_file += count;
530 Dmsg0(dbglevel, "Try to FSF after EOT\n");
531 current_file = last_file ;
541 int faketape::fsr(int count)
543 ASSERT(current_file >= 0);
547 Dmsg2(dbglevel, "fsr current_block=%i count=%i\n", current_block, count);
549 if (atEOT || atEOF) {
562 if (current_block < 0) {
567 /* check all block record */
568 for(i=0; (i < count) && !atEOF ; i++) {
569 nb = ::read(fd, &s, sizeof(s)); /* get size of next block */
570 if (nb == sizeof(s) && s) {
572 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
576 if (current_file < last_file) {
581 atEOF = true; /* stop the loop */
585 find_maxfile(); /* refresh stats */
591 if (where == file_size) {
597 int faketape::read_eof()
600 off_t old = lseek(fd, 0, SEEK_CUR);
601 nb = ::read(fd, &s, sizeof(s));
602 if (nb >= 0 && (nb != sizeof(s) || !s)) { /* EOF */
605 lseek(fd, old, SEEK_SET);
609 int faketape::bsf(int count)
611 ASSERT(current_file >= 0);
612 Dmsg3(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block, count);
614 atBOT = atEOF = atEOT = atEOD = false;
616 if (current_file - count < 0) {
623 current_file = current_file - count;
634 * Put faketape in offline mode
636 int faketape::offline()
640 atEOF = false; /* End of file */
641 atEOT = false; /* End of tape */
642 atEOD = false; /* End of data */
643 atBOT = false; /* Begin of tape */
651 int faketape::close()
660 * EOF Bacula status: file=2 block=0
661 * Device status: EOF ONLINE IM_REP_EN file=2 block=0
664 * EOD EOF Bacula status: file=2 block=0
665 * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
669 int faketape::read(void *buffer, unsigned int count)
671 ASSERT(current_file >= 0);
674 if (atEOT || atEOD) {
685 nb = ::read(fd, &s, sizeof(s));
687 lseek(fd, s, SEEK_CUR);
693 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(s), SEEK_SET);
697 nb = ::read(fd, buffer, s);
700 if (current_file == last_file) {
704 Dmsg0(dbglevel, "EOF during reading\n");
709 int faketape::open(const char *pathname, int uflags, int umode)
711 Dmsg3(dbglevel, "faketape::open(%s, %i, %i)\n", pathname, uflags, umode);
712 pm_strcpy(volume, pathname);
715 if (stat(volume, &statp) != 0) {
716 Dmsg1(dbglevel, "Can't stat on %s\n", volume);
720 fd = ::open(pathname, O_CREAT | O_RDWR, 0700);
725 /* open volume descriptor and get this->fd */
726 if (find_maxfile() < 0) {
735 atEOT = atEOD = false;
741 * read volume to get the last file number
743 int faketape::find_maxfile()
746 if (fstat(fd, &statp) != 0) {
749 last_file = statp.st_size>>30;
750 file_size = statp.st_size;
752 current_pos = lseek(fd, 0, SEEK_CUR); /* get current position */
753 Dmsg3(dbglevel, "last_file=%i file_size=%u current_pos=%i\n",
754 last_file, file_size, current_pos);
759 int faketape::seek_file()
761 ASSERT(current_file >= 0);
762 Dmsg2(dbglevel, "seek_file %i:%i\n", current_file, current_block);
764 off_t pos = ((off_t)current_file)<<30;
765 if(lseek(fd, pos, SEEK_SET) == -1) {
768 if (current_block > 0) {
771 last_file = (last_file > current_file)?last_file:current_file;
777 void faketape::dump()
779 Dmsg0(dbglevel+1, "===================\n");
780 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
781 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
782 Dmsg1(dbglevel+1, "volume=%s\n", volume);
783 Dmsg1(dbglevel+1, "file_size=%i\n", file_size);
784 Dmsg1(dbglevel+1, "EOF=%i\n", atEOF);
785 Dmsg1(dbglevel+1, "EOT=%i\n", atEOT);
786 Dmsg1(dbglevel+1, "EOD=%i\n", atEOD);
789 /****************************************************************
791 #define GMT_EOF(x) ((x) & 0x80000000)
792 #define GMT_BOT(x) ((x) & 0x40000000)
793 #define GMT_EOT(x) ((x) & 0x20000000)
794 #define GMT_SM(x) ((x) & 0x10000000)
795 #define GMT_EOD(x) ((x) & 0x08000000)
798 GMT_EOF(x) : La bande est positionnée juste après une filemark (toujours faux
799 après une opération MTSEEK).
801 GMT_BOT(x) : La bande est positionnée juste au début du premier fichier
802 (toujours faux après une opération MTSEEK).
804 GMT_EOT(x) : Une opération a atteint la fin physique de la bande (End Of
807 GMT_SM(x) : La bande est positionnée sur une setmark (toujours faux après une
810 GMT_EOD(x) : La bande est positionnée à la fin des données enregistrées.
813 blkno = -1 (after MTBSF MTBSS or MTSEEK)
814 fileno = -1 (after MTBSS or MTSEEK)
817 drive type = Generic SCSI-2 tape
823 Tape block size 0 bytes. Density code 0x0 (default).
824 Soft error count since last status=0
825 General status bits on (41010000):
829 dd if=/dev/lto2 of=/tmp/toto count=1
830 dd: lecture de `/dev/lto2': Ne peut allouer de la mémoire
831 0+0 enregistrements lus
832 0+0 enregistrements écrits
833 1 octet (1B) copié, 4,82219 seconde, 0,0 kB/s
839 dd if=/dev/lto2 of=/tmp/toto count=1
840 0+0 enregistrements lus
841 0+0 enregistrements écrits
842 1 octet (1B) copié, 0,167274 seconde, 0,0 kB/s
847 *** write 2 blocks after rewind
848 dd if=/dev/zero of=/dev/lto2 count=2
849 2+0 enregistrements lus
850 2+0 enregistrements écrits
851 1024 octets (1,0 kB) copiés, 6,57402 seconde, 0,2 kB/s
864 *** rewind and 2x fsr (we have just 2 blocks)
869 mt: /dev/lto2: Erreur
874 ****************************************************************/
883 printf("Starting FakeTape\n");
885 mkdir("/tmp/fake", 0700);