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.
34 static int dbglevel = 0;
36 faketape *ftape_list[FTAPE_MAX_DRIVE];
38 static faketape *get_tape(int fd)
42 if (fd >= FTAPE_MAX_DRIVE) {
47 return ftape_list[fd];
50 static bool put_tape(faketape *ftape)
52 ASSERT(ftape != NULL);
54 int fd = ftape->get_fd();
55 if (fd >= FTAPE_MAX_DRIVE) {
59 ftape_list[fd] = ftape;
63 /****************************************************************/
64 /* theses function will replace open/read/write/close/ioctl
67 int faketape_open(const char *pathname, int flags, int mode)
69 ASSERT(pathname != NULL);
72 faketape *tape = new faketape();
73 fd = tape->open(pathname, flags, mode);
80 int faketape_read(int fd, void *buffer, unsigned int count)
82 faketape *tape = get_tape(fd);
84 return tape->read(buffer, count);
87 int faketape_write(int fd, const void *buffer, unsigned int count)
89 faketape *tape = get_tape(fd);
91 return tape->write(buffer, count);
94 int faketape_close(int fd)
96 faketape *tape = get_tape(fd);
103 int faketape_ioctl(int fd, unsigned long int request, ...)
108 faketape *t = get_tape(fd);
114 va_start(argp, request);
116 if (request == MTIOCTOP) {
117 result = t->tape_op(va_arg(argp, mtop *));
118 } else if (request == MTIOCGET) {
119 result = t->tape_get(va_arg(argp, mtget *));
123 // result = tape_pos(fd, va_arg(argp, mtpos *));
135 /****************************************************************/
137 int faketape::tape_op(struct mtop *mt_com)
141 switch (mt_com->mt_op)
157 case MTFSF: /* Forward space over mt_count filemarks. */
158 result = fsf(mt_com->mt_count);
161 case MTBSF: /* Backward space over mt_count filemarks. */
162 current_file = current_file - mt_com->mt_count;
163 if (current_file < 0) {
174 case MTFSR: /* Forward space over mt_count records (tape blocks). */
182 mt: /dev/lto2: Erreur d'entrée/sortie
187 /* tester si on se trouve a la fin du fichier */
188 result = fsr(mt_com->mt_count);
191 case MTBSR: /* Backward space over mt_count records (tape blocks). */
195 case MTWEOF: /* Write mt_count filemarks. */
196 weof(mt_com->mt_count);
199 case MTREW: /* Rewind. */
200 atEOF = atEOD = false;
207 case MTOFFL: /* put tape offline */
211 case MTRETEN: /* Re-tension tape. */
215 case MTBSFM: /* not used by bacula */
220 case MTFSFM: /* not used by bacula */
225 case MTEOM:/* Go to the end of the recorded media (for appending files). */
234 current_file = last_file+1;
237 /* Ne pas creer le fichier si on est a la fin */
241 case MTERASE: /* not used by bacula */
293 // case -1: /* Error has already been translated into errno */
297 // case ERROR_FILEMARK_DETECTED:
301 // case ERROR_END_OF_MEDIA:
305 // case ERROR_NO_DATA_DETECTED:
309 // case ERROR_NO_MEDIA_IN_DRIVE:
310 // errno = ENOMEDIUM;
313 // case ERROR_INVALID_HANDLE:
314 // case ERROR_ACCESS_DENIED:
315 // case ERROR_LOCK_VIOLATION:
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)
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 ftruncate(fd, lseek(fd, 0, SEEK_CUR));
404 max_block = 1024*1024*1024*1024*8;
406 volume = get_pool_memory(PM_NAME);
409 faketape::~faketape()
411 free_pool_memory(volume);
414 int faketape::get_fd()
419 int faketape::write(const void *buffer, unsigned int count)
425 Dmsg2(dbglevel, "write len=%i blocks=%i\n", count, current_block);
428 Dmsg0(dbglevel, "write nothing, EOT !\n");
432 if (!atEOD) { /* if not at the end of the data */
436 } else { /* already writing something */
437 if (current_block != -1) {
445 // if ((count + file_size) > max_size) {
447 // "EOT writing only %i of %i requested\n",
448 // max_size - file_size, count);
449 // count = max_size - file_size;
453 ::write(fd, &count, sizeof(count));
454 nb = ::write(fd, buffer, count);
456 file_size += sizeof(count) + nb;
461 "Not enough space writing only %i of %i requested\n",
468 int faketape::weof(int count)
470 Dmsg2(dbglevel, "Writing EOF %i:%i\n", current_file, current_block);
476 count--; /* end this file */
477 truncate_file(); /* nothing after this point */
494 int faketape::fsf(int count)
497 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
506 Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
508 if ((current_file + count) <= last_file) {
509 current_file += count;
513 Dmsg0(dbglevel, "Try to FSF after EOT\n");
514 current_file = last_file ;
524 int faketape::fsr(int count)
528 Dmsg2(dbglevel, "fsr current_block=%i count=%i\n", current_block, count);
535 /* check all block record */
536 for(i=0; (i < count) && (where != -1) ; i++) {
537 nb = ::read(fd, &s, sizeof(s)); /* get size of block */
538 if (nb == sizeof(s)) {
540 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
550 find_maxfile(); /* refresh stats */
552 if (where == file_size) {
559 int faketape::bsf(int count)
562 atEOT = atEOD = false;
564 if (current_file - count < 0) {
571 current_file = current_file - count;
581 * Put faketape in offline mode
583 int faketape::offline()
598 int faketape::close()
607 * EOF Bacula status: file=2 block=0
608 * Device status: EOF ONLINE IM_REP_EN file=2 block=0
611 * EOD EOF Bacula status: file=2 block=0
612 * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
616 int faketape::read(void *buffer, unsigned int count)
620 if (atEOT || atEOD) {
627 nb = ::read(fd, &s, sizeof(s));
629 lseek(fd, s, SEEK_CUR);
633 nb = ::read(fd, buffer, s);
636 if (current_file == last_file) {
640 Dmsg0(dbglevel, "EOF during reading\n");
645 int faketape::open(const char *pathname, int uflags, int umode)
647 Dmsg3(dbglevel, "faketape::open(%s, %i, %i)\n", pathname, uflags, umode);
648 pm_strcpy(volume, pathname);
651 if (stat(volume, &statp) != 0) {
652 Dmsg1(dbglevel, "Can't stat on %s\n", volume);
656 fd = ::open(pathname, O_CREAT | O_RDWR, 0700);
661 /* open volume descriptor and get this->fd */
662 if (find_maxfile() < 0) {
672 * read volume to get the last file number
674 int faketape::find_maxfile()
678 last_file = statp.st_size % ((off_t)1<<32);
679 file_size = statp.st_size;
681 current_pos = lseek(fd, 0, SEEK_CUR); /* get current position */
686 int faketape::seek_file()
688 Dmsg2(dbglevel, "seek_file %i:%i\n", current_file, current_block);
690 off_t pos = ((off_t)current_file)<<32;
691 if(lseek(fd, pos, SEEK_SET) == -1) {
695 last_file = (last_file > current_file)?last_file:current_file;
699 void faketape::dump()
701 Dmsg0(dbglevel+1, "===================\n");
702 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
703 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
704 Dmsg1(dbglevel+1, "volume=%s\n", volume);
705 Dmsg1(dbglevel+1, "file_size=%i\n", file_size);
706 Dmsg1(dbglevel+1, "EOF=%i\n", atEOF);
707 Dmsg1(dbglevel+1, "EOT=%i\n", atEOT);
708 Dmsg1(dbglevel+1, "EOD=%i\n", atEOD);
711 /****************************************************************
713 #define GMT_EOF(x) ((x) & 0x80000000)
714 #define GMT_BOT(x) ((x) & 0x40000000)
715 #define GMT_EOT(x) ((x) & 0x20000000)
716 #define GMT_SM(x) ((x) & 0x10000000)
717 #define GMT_EOD(x) ((x) & 0x08000000)
720 GMT_EOF(x) : La bande est positionnée juste après une filemark (toujours faux
721 après une opération MTSEEK).
723 GMT_BOT(x) : La bande est positionnée juste au début du premier fichier
724 (toujours faux après une opération MTSEEK).
726 GMT_EOT(x) : Une opération a atteint la fin physique de la bande (End Of
729 GMT_SM(x) : La bande est positionnée sur une setmark (toujours faux après une
732 GMT_EOD(x) : La bande est positionnée à la fin des données enregistrées.
735 blkno = -1 (after MTBSF MTBSS or MTSEEK)
736 fileno = -1 (after MTBSS or MTSEEK)
739 drive type = Generic SCSI-2 tape
745 Tape block size 0 bytes. Density code 0x0 (default).
746 Soft error count since last status=0
747 General status bits on (41010000):
751 dd if=/dev/lto2 of=/tmp/toto count=1
752 dd: lecture de `/dev/lto2': Ne peut allouer de la mémoire
753 0+0 enregistrements lus
754 0+0 enregistrements écrits
755 1 octet (1B) copié, 4,82219 seconde, 0,0 kB/s
761 dd if=/dev/lto2 of=/tmp/toto count=1
762 0+0 enregistrements lus
763 0+0 enregistrements écrits
764 1 octet (1B) copié, 0,167274 seconde, 0,0 kB/s
769 *** write 2 blocks after rewind
770 dd if=/dev/zero of=/dev/lto2 count=2
771 2+0 enregistrements lus
772 2+0 enregistrements écrits
773 1024 octets (1,0 kB) copiés, 6,57402 seconde, 0,2 kB/s
786 *** rewind and 2x fsr (we have just 2 blocks)
791 mt: /dev/lto2: Erreur
796 ****************************************************************/
805 printf("Starting FakeTape\n");
807 mkdir("/tmp/fake", 0700);