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 = 800M
39 static int dbglevel = 10;
40 #define FILE_OFFSET 30
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)
79 ASSERT(pathname != NULL);
82 faketape *tape = new faketape();
83 fd = tape->open(pathname, flags);
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). */
193 result = bsr(mt_com->mt_count);
196 case MTWEOF: /* Write mt_count filemarks. */
197 result = weof(mt_com->mt_count);
200 case MTREW: /* Rewind. */
201 Dmsg0(dbglevel, "rewind faketape\n");
202 atEOF = atEOD = false;
209 case MTOFFL: /* put tape offline */
213 case MTRETEN: /* Re-tension tape. */
217 case MTBSFM: /* not used by bacula */
222 case MTFSFM: /* not used by bacula */
227 case MTEOM:/* Go to the end of the recorded media (for appending files). */
238 current_file = last_file;
243 case MTERASE: /* not used by bacula */
296 // case -1: /* Error has already been translated into errno */
300 // case ERROR_FILEMARK_DETECTED:
304 // case ERROR_END_OF_MEDIA:
308 // case ERROR_NO_DATA_DETECTED:
312 // case ERROR_NO_MEDIA_IN_DRIVE:
313 // errno = ENOMEDIUM;
316 // case ERROR_INVALID_HANDLE:
317 // case ERROR_ACCESS_DENIED:
318 // case ERROR_LOCK_VIOLATION:
323 return result == 0 ? 0 : -1;
326 int faketape::tape_get(struct mtget *mt_get)
329 int block_size = 1024;
331 mt_get->mt_type = MT_ISSCSI2;
332 mt_get->mt_blkno = current_block;
333 mt_get->mt_fileno = current_file;
335 mt_get->mt_resid = -1;
336 // pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
340 ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
341 ((block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
344 mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
347 mt_get->mt_gstat |= 0x80000000; // GMT_EOF
351 mt_get->mt_gstat |= 0x40000000; // GMT_BOT
354 mt_get->mt_gstat |= 0x20000000; // GMT_EOT
358 mt_get->mt_gstat |= 0x08000000; // GMT_EOD
361 if (0) { //WriteProtected) {
362 mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
366 mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
368 mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
370 mt_get->mt_erreg = 0;
375 int faketape::tape_pos(struct mtpos *mt_pos)
381 * This function try to emulate the append only behavior
382 * of a tape. When you wrote something, data after the
383 * current position are discarded.
385 int faketape::truncate_file()
387 Dmsg2(dbglevel, "truncate %i:%i\n", current_file, current_block);
388 ftruncate(fd, lseek(fd, 0, SEEK_CUR));
389 last_file = current_file;
412 max_block = 1024*1024*1024*1024*8;
414 volume = get_pool_memory(PM_NAME);
417 faketape::~faketape()
419 free_pool_memory(volume);
422 int faketape::get_fd()
428 * TODO: regarder si apres un write une operation x pose un EOF
430 int faketape::write(const void *buffer, unsigned int count)
432 ASSERT(current_file >= 0);
437 Dmsg3(dbglevel, "write len=%i %i:%i\n", count, current_file,current_block);
440 Dmsg0(dbglevel, "write nothing, EOT !\n");
449 if (!atEOD) { /* if not at the end of the data */
453 if (current_block != -1) {
459 atEOD = true; /* End of data */
461 needEOF = true; /* next operation need EOF mark */
463 // if ((count + file_size) > max_size) {
465 // "EOT writing only %i of %i requested\n",
466 // max_size - file_size, count);
467 // count = max_size - file_size;
472 ::write(fd, &size, sizeof(off_t));
473 nb = ::write(fd, buffer, count);
475 file_size += sizeof(off_t) + nb;
480 "Not enough space writing only %i of %i requested\n",
487 int faketape::weof(int count)
489 ASSERT(current_file >= 0);
490 Dmsg3(dbglevel, "Writing EOF %i:%i last=%i\n",
491 current_file, current_block,last_file);
497 truncate_file(); /* nothing after this point */
499 /* TODO: check this */
500 current_file += count;
505 ::write(fd, &c, sizeof(off_t));
515 int faketape::fsf(int count)
517 ASSERT(current_file >= 0);
520 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
530 atBOT = atEOF = false;
531 Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
533 if ((current_file + count) <= last_file) {
534 current_file += count;
538 Dmsg0(dbglevel, "Try to FSF after EOT\n");
539 current_file = last_file ;
549 int faketape::fsr(int count)
551 ASSERT(current_file >= 0);
556 Dmsg3(dbglevel, "fsr %i:%i count=%i\n", current_file,current_block, count);
571 atBOT = atEOF = false;
573 /* check all block record */
574 for(i=0; (i < count) && !atEOF ; i++) {
575 nb = ::read(fd, &s, sizeof(off_t)); /* get size of next block */
576 if (nb == sizeof(off_t) && s) {
578 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
580 Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
581 current_file, current_block, nb,s);
584 if (current_file < last_file) {
589 atEOF = true; /* stop the loop */
593 find_maxfile(); /* refresh stats */
595 if (where == file_size) {
601 // TODO: Make it working, at this time we get only the EOF position...
602 int faketape::bsr(int count)
604 Dmsg2(dbglevel, "bsr current_block=%i count=%i\n",
605 current_block, count);
607 ASSERT(current_file >= 0);
623 off_t orig = lseek(fd, 0, SEEK_CUR);
630 last = lseek(fd, 0, SEEK_CUR);
631 last_f = current_file;
632 last_b = current_block;
633 Dmsg5(dbglevel, "EOF=%i last=%lli orig=%lli %i:%i\n", atEOF, last, orig, current_file, current_block);
636 } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
639 lseek(fd, last, SEEK_SET);
640 current_file = last_f;
641 current_block = last_b;
642 Dmsg3(dbglevel, "set offset=%lli %i:%i\n",
643 last, current_file, current_block);
646 Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
647 atEOT = atEOF = atEOD = false;
652 //int faketape::read_eof()
655 // off_t old = lseek(fd, 0, SEEK_CUR);
656 // nb = ::read(fd, &s, sizeof(s));
657 // if (nb >= 0 && (nb != sizeof(s) || !s)) { /* EOF */
660 // lseek(fd, old, SEEK_SET);
664 int faketape::bsf(int count)
666 ASSERT(current_file >= 0);
667 Dmsg3(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block, count);
671 atBOT = atEOF = atEOT = atEOD = false;
673 if (current_file - count < 0) {
680 current_file = current_file - count + 1;
684 /* go just before last EOF */
685 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(off_t), SEEK_SET);
691 * Put faketape in offline mode
693 int faketape::offline()
698 atEOF = false; /* End of file */
699 atEOT = false; /* End of tape */
700 atEOD = false; /* End of data */
701 atBOT = false; /* Begin of tape */
709 int faketape::close()
719 * EOF Bacula status: file=2 block=0
720 * Device status: EOF ONLINE IM_REP_EN file=2 block=0
723 * EOD EOF Bacula status: file=2 block=0
724 * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
728 int faketape::read(void *buffer, unsigned int count)
730 ASSERT(current_file >= 0);
734 if (atEOT || atEOD) {
742 Dmsg2(dbglevel, "read %i:%i\n", current_file, current_block);
747 nb = ::read(fd, &s, sizeof(off_t));
752 if (s > count) { /* not enough buffer to read block */
753 lseek(fd, s, SEEK_CUR);
759 lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(off_t), SEEK_SET);
762 nb = ::read(fd, buffer, s);
765 if (current_file == last_file) {
769 Dmsg0(dbglevel, "EOF during reading\n");
774 int faketape::open(const char *pathname, int uflags)
776 Dmsg2(dbglevel, "faketape::open(%s, %i)\n", pathname, uflags);
777 pm_strcpy(volume, pathname);
780 if (stat(volume, &statp) != 0) {
781 Dmsg1(dbglevel, "Can't stat on %s\n", volume);
785 fd = ::open(pathname, O_CREAT | O_RDWR, 0700);
790 /* open volume descriptor and get this->fd */
791 if (find_maxfile() < 0) {
798 online = inplace = true;
800 atEOT = atEOD = false;
806 * read volume to get the last file number
808 int faketape::find_maxfile()
811 if (fstat(fd, &statp) != 0) {
814 last_file = statp.st_size>>FILE_OFFSET;
815 file_size = statp.st_size;
817 current_pos = lseek(fd, 0, SEEK_CUR); /* get current position */
818 Dmsg3(dbglevel+1, "last_file=%i file_size=%u current_pos=%i\n",
819 last_file, file_size, current_pos);
824 int faketape::seek_file()
826 ASSERT(current_file >= 0);
827 Dmsg2(dbglevel, "seek_file %i:%i\n", current_file, current_block);
829 off_t pos = ((off_t)current_file)<<FILE_OFFSET;
830 if(lseek(fd, pos, SEEK_SET) == -1) {
833 if (current_block > 0) {
836 last_file = (last_file > current_file)?last_file:current_file;
842 void faketape::dump()
844 Dmsg0(dbglevel+1, "===================\n");
845 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
846 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
847 Dmsg1(dbglevel+1, "volume=%s\n", volume);
848 Dmsg1(dbglevel+1, "file_size=%i\n", file_size);
849 Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n",
850 atEOF, atEOT, atEOD, atBOT);
853 /****************************************************************
855 #define GMT_EOF(x) ((x) & 0x80000000)
856 #define GMT_BOT(x) ((x) & 0x40000000)
857 #define GMT_EOT(x) ((x) & 0x20000000)
858 #define GMT_SM(x) ((x) & 0x10000000)
859 #define GMT_EOD(x) ((x) & 0x08000000)
862 GMT_EOF(x) : La bande est positionnée juste après une filemark (toujours faux
863 après une opération MTSEEK).
865 GMT_BOT(x) : La bande est positionnée juste au début du premier fichier
866 (toujours faux après une opération MTSEEK).
868 GMT_EOT(x) : Une opération a atteint la fin physique de la bande (End Of
871 GMT_SM(x) : La bande est positionnée sur une setmark (toujours faux après une
874 GMT_EOD(x) : La bande est positionnée à la fin des données enregistrées.
877 blkno = -1 (after MTBSF MTBSS or MTSEEK)
878 fileno = -1 (after MTBSS or MTSEEK)
881 drive type = Generic SCSI-2 tape
887 Tape block size 0 bytes. Density code 0x0 (default).
888 Soft error count since last status=0
889 General status bits on (41010000):
893 dd if=/dev/lto2 of=/tmp/toto count=1
894 dd: lecture de `/dev/lto2': Ne peut allouer de la mémoire
895 0+0 enregistrements lus
896 0+0 enregistrements écrits
897 1 octet (1B) copié, 4,82219 seconde, 0,0 kB/s
903 dd if=/dev/lto2 of=/tmp/toto count=1
904 0+0 enregistrements lus
905 0+0 enregistrements écrits
906 1 octet (1B) copié, 0,167274 seconde, 0,0 kB/s
911 *** write 2 blocks after rewind
912 dd if=/dev/zero of=/dev/lto2 count=2
913 2+0 enregistrements lus
914 2+0 enregistrements écrits
915 1024 octets (1,0 kB) copiés, 6,57402 seconde, 0,2 kB/s
928 *** rewind and 2x fsr (we have just 2 blocks)
933 mt: /dev/lto2: Erreur
938 ****************************************************************/
947 printf("Starting FakeTape\n");
949 mkdir("/tmp/fake", 0700);