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
60 #include "bacula.h" /* define 64bit file usage */
65 static int dbglevel = 100;
66 #define FILE_OFFSET 30
67 vtape *ftape_list[FTAPE_MAX_DRIVE];
69 static vtape *get_tape(int fd)
73 if (fd >= FTAPE_MAX_DRIVE) {
78 return ftape_list[fd];
81 static bool put_tape(vtape *ftape)
83 ASSERT(ftape != NULL);
85 int fd = ftape->get_fd();
86 if (fd >= FTAPE_MAX_DRIVE) {
90 ftape_list[fd] = ftape;
94 void vtape_debug(int level)
99 /****************************************************************/
100 /* theses function will replace open/read/write/close/ioctl
103 int vtape_open(const char *pathname, int flags, ...)
105 ASSERT(pathname != NULL);
108 vtape *tape = new vtape();
109 fd = tape->open(pathname, flags);
116 int vtape_read(int fd, void *buffer, unsigned int count)
118 vtape *tape = get_tape(fd);
119 ASSERT(tape != NULL);
120 return tape->read(buffer, count);
123 int vtape_write(int fd, const void *buffer, unsigned int count)
125 vtape *tape = get_tape(fd);
126 ASSERT(tape != NULL);
127 return tape->write(buffer, count);
130 int vtape_close(int fd)
132 vtape *tape = get_tape(fd);
133 ASSERT(tape != NULL);
139 int vtape_ioctl(int fd, unsigned long int request, ...)
144 vtape *t = get_tape(fd);
150 va_start(argp, request);
152 if (request == MTIOCTOP) {
153 result = t->tape_op(va_arg(argp, mtop *));
154 } else if (request == MTIOCGET) {
155 result = t->tape_get(va_arg(argp, mtget *));
156 } else if (request == MTIOCPOS) {
157 result = t->tape_pos(va_arg(argp, mtpos *));
167 /****************************************************************/
169 int vtape::tape_op(struct mtop *mt_com)
172 int count = mt_com->mt_count;
179 switch (mt_com->mt_op)
195 case MTFSF: /* Forward space over mt_count filemarks. */
198 } while (--count > 0 && result == 0);
201 case MTBSF: /* Backward space over mt_count filemarks. */
204 } while (--count > 0 && result == 0);
207 case MTFSR: /* Forward space over mt_count records (tape blocks). */
215 mt: /dev/lto2: Erreur d'entree/sortie
220 /* tester si on se trouve a la fin du fichier */
221 result = fsr(mt_com->mt_count);
224 case MTBSR: /* Backward space over mt_count records (tape blocks). */
225 result = bsr(mt_com->mt_count);
228 case MTWEOF: /* Write mt_count filemarks. */
231 } while (result == 0 && --count > 0);
234 case MTREW: /* Rewind. */
235 Dmsg0(dbglevel, "rewind vtape\n");
237 atEOF = atEOD = false;
241 lseek(fd, 0, SEEK_SET);
242 result = !read_fm(VT_READ_EOF);
245 case MTOFFL: /* put tape offline */
249 case MTRETEN: /* Re-tension tape. */
253 case MTBSFM: /* not used by bacula */
258 case MTFSFM: /* not used by bacula */
263 case MTEOM:/* Go to the end of the recorded media (for appending files). */
265 lseek(fd, next_FM, SEEK_SET);
266 if (read_fm(VT_READ_EOF)) {
271 while (::read(fd, &l, sizeof(l)) > 0) {
273 lseek(fd, l, SEEK_CUR);
277 Dmsg0(dbglevel, "skip 1 block\n");
290 case MTERASE: /* not used by bacula */
297 lseek(fd, 0, SEEK_SET);
298 read_fm(VT_READ_EOF);
342 return result == 0 ? 0 : -1;
345 int vtape::tape_get(struct mtget *mt_get)
348 int block_size = 1024;
350 mt_get->mt_type = MT_ISSCSI2;
351 mt_get->mt_blkno = current_block;
352 mt_get->mt_fileno = current_file;
354 mt_get->mt_resid = -1;
355 // pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
359 ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
360 ((block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
363 mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
366 mt_get->mt_gstat |= 0x80000000; // GMT_EOF
370 mt_get->mt_gstat |= 0x40000000; // GMT_BOT
373 mt_get->mt_gstat |= 0x20000000; // GMT_EOT
377 mt_get->mt_gstat |= 0x08000000; // GMT_EOD
380 if (0) { //WriteProtected) {
381 mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
385 mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
387 mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
389 mt_get->mt_erreg = 0;
394 int vtape::tape_pos(struct mtpos *mt_pos)
396 if (current_block >= 0) {
397 mt_pos->mt_blkno = current_block;
405 * This function try to emulate the append only behavior
406 * of a tape. When you wrote something, data after the
407 * current position are discarded.
409 int vtape::truncate_file()
411 Dmsg2(dbglevel, "truncate %i:%i\n", current_file, current_block);
412 ftruncate(fd, lseek(fd, 0, SEEK_CUR));
413 last_file = current_file;
435 max_block = 2*1024*2048; /* 2GB */
448 * Write a variable block of count size.
449 * block = vtape_header + data
450 * vtape_header = sizeof(data)
451 * if vtape_header == 0, this is a EOF
453 int vtape::write(const void *buffer, unsigned int count)
456 ASSERT(current_file >= 0);
461 Dmsg3(dbglevel*2, "write len=%i %i:%i\n",
462 count, current_file,current_block);
465 Dmsg0(dbglevel, "write nothing, EOT !\n");
470 if (!atEOD) { /* if not at the end of the data */
474 if (current_block != -1) {
480 atEOD = true; /* End of data */
482 needEOF = true; /* next operation need EOF mark */
484 uint32_t size = count;
485 ::write(fd, &size, sizeof(uint32_t));
486 nb = ::write(fd, buffer, count);
491 "Not enough space writing only %i of %i requested\n",
501 * +---+---------+---+------------------+---+-------------------+
502 * |00N| DATA |0LN| DATA |0LC| DATA |
503 * +---+---------+---+------------------+---+-------------------+
506 * L : Last FileMark offset
507 * N : Next FileMark offset
508 * C : Current FileMark Offset
513 ASSERT(current_file >= 0);
522 truncate_file(); /* nothing after this point */
526 cur_FM = lseek(fd, 0, SEEK_CUR); // current position
528 /* update previous next_FM */
529 lseek(fd, last_FM + sizeof(uint32_t)+sizeof(off_t), SEEK_SET);
530 ::write(fd, &cur_FM, sizeof(off_t));
531 lseek(fd, cur_FM, SEEK_SET);
536 ::write(fd, &c, sizeof(uint32_t)); // EOF
537 ::write(fd, &last_FM, sizeof(last_FM)); // F-1
538 ::write(fd, &next_FM, sizeof(next_FM)); // F (will be updated next time)
548 last_file = MAX(current_file, last_file);
550 Dmsg4(dbglevel, "Writing EOF %i:%i last=%lli cur=%lli next=0\n",
551 current_file, current_block, last_FM, cur_FM);
562 ASSERT(current_file >= 0);
565 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
569 if (atEOT || atEOD) {
576 Dmsg2(dbglevel+1, "fsf %i <= %i\n", current_file, last_file);
578 if (next_FM > cur_FM) { /* not the last file */
579 lseek(fd, next_FM, SEEK_SET);
580 read_fm(VT_READ_EOF);
585 } else if (atEOF) { /* last file mark */
591 } else { /* last file, but no at the end */
594 Dmsg0(dbglevel, "Try to FSF after EOT\n");
596 current_file = last_file ;
604 /* /------------\ /---------------\
605 * +---+------+---+---------------+-+
607 * +---+------+---+---------------+-+
610 bool vtape::read_fm(VT_READ_FM_MODE read_all)
614 if (read_all == VT_READ_EOF) {
615 ::read(fd, &c, sizeof(c));
617 lseek(fd, cur_FM, SEEK_SET);
622 cur_FM = lseek(fd, 0, SEEK_CUR) - sizeof(c);
624 ::read(fd, &last_FM, sizeof(last_FM));
625 ret = ::read(fd, &next_FM, sizeof(next_FM));
629 Dmsg3(dbglevel, "Read FM cur=%lli last=%lli next=%lli\n",
630 cur_FM, last_FM, next_FM);
632 return (ret == sizeof(next_FM));
636 * TODO: Check fsr with EOF
638 int vtape::fsr(int count)
641 ASSERT(current_file >= 0);
647 Dmsg4(dbglevel, "fsr %i:%i EOF=%i c=%i\n",
648 current_file,current_block,atEOF,count);
663 atBOT = atEOF = false;
665 /* check all block record */
666 for(i=0; (i < count) && !atEOF ; i++) {
667 nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
668 if (nb == sizeof(uint32_t) && s) {
670 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
672 Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
673 current_file, current_block, nb,s);
678 read_fm(VT_SKIP_EOF);
680 atEOF = true; /* stop the loop */
688 * BSR + EOF => begin of EOF + EIO
689 * BSR + BSR + EOF => last block
692 int vtape::bsr(int count)
695 ASSERT(current_file >= 0);
709 off_t last=-1, last2=-1;
710 off_t orig = lseek(fd, 0, SEEK_CUR);
711 int orig_f = current_file;
712 int orig_b = current_block;
714 Dmsg4(dbglevel, "bsr(%i) cur_blk=%i orig=%lli cur_FM=%lli\n",
715 count, current_block, orig, cur_FM);
717 /* begin of tape, do nothing */
723 /* at EOF 0:-1 BOT=0 EOD=0 EOF=0 ERR: Input/output error */
725 lseek(fd, cur_FM, SEEK_SET);
727 if (current_file > 0) {
736 * First, go to cur/last_FM and read all blocks to find the good one
738 if (cur_FM == orig) { /* already just before EOF */
739 lseek(fd, last_FM, SEEK_SET);
742 lseek(fd, cur_FM, SEEK_SET);
745 ret = read_fm(VT_READ_EOF);
749 last2 = last; /* keep track of the 2 last blocs position */
750 last = lseek(fd, 0, SEEK_CUR);
751 last_f = current_file;
752 last_b = current_block;
753 Dmsg6(dbglevel, "EOF=%i last2=%lli last=%lli < orig=%lli %i:%i\n",
754 atEOF, last2, last, orig, current_file, current_block);
757 } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
759 if (last2 > 0 && atEOF) { /* we take the previous position */
760 lseek(fd, last2, SEEK_SET);
761 current_file = last_f;
762 current_block = last_b - 1;
763 Dmsg3(dbglevel, "1 set offset2=%lli %i:%i\n",
764 last, current_file, current_block);
766 } else if (last > 0) {
767 lseek(fd, last, SEEK_SET);
768 current_file = last_f;
769 current_block = last_b;
770 Dmsg3(dbglevel, "2 set offset=%lli %i:%i\n",
771 last, current_file, current_block);
773 lseek(fd, orig, SEEK_SET);
774 current_file = orig_f;
775 current_block = orig_b;
779 Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
781 atEOT = atEOF = atEOD = false;
782 atBOT = (lseek(fd, 0, SEEK_CUR) - (sizeof(uint32_t)+2*sizeof(off_t))) == 0;
785 current_block = orig_b;
791 /* BSF => just before last EOF
792 * EOF + BSF => just before EOF
793 * file 0 + BSF => BOT + errno
798 ASSERT(current_file >= 0);
799 Dmsg2(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block);
804 atBOT = atEOF = atEOT = atEOD = false;
806 if (current_file == 0) {/* BOT + errno */
807 lseek(fd, 0, SEEK_SET);
808 read_fm(VT_READ_EOF);
815 Dmsg1(dbglevel, "bsf last=%lli\n", last_FM);
816 lseek(fd, cur_FM, SEEK_SET);
824 * Put vtape in offline mode
830 atEOF = false; /* End of file */
831 atEOT = false; /* End of tape */
832 atEOD = false; /* End of data */
833 atBOT = false; /* Begin of tape */
843 /* A filemark is automatically written to tape if the last tape operation
844 * before close was a write.
855 * When a filemark is encountered while reading, the following happens. If
856 * there are data remaining in the buffer when the filemark is found, the
857 * buffered data is returned. The next read returns zero bytes. The following
858 * read returns data from the next file. The end of recorded data is signaled
859 * by returning zero bytes for two consecutive read calls. The third read
862 int vtape::read(void *buffer, unsigned int count)
865 ASSERT(current_file >= 0);
869 Dmsg2(dbglevel*2, "read %i:%i\n", current_file, current_block);
871 if (atEOT || atEOD) {
888 atEOD = atBOT = false;
890 /* reading size of data */
891 nb = ::read(fd, &s, sizeof(uint32_t));
893 atEOF = true; /* TODO: check this */
897 if (s > count) { /* not enough buffer to read block */
898 Dmsg2(dbglevel, "Need more buffer to read next block %i > %i\n",s,count);
899 lseek(fd, s, SEEK_CUR);
906 if (read_fm(VT_SKIP_EOF)) {
913 /* reading data itself */
914 nb = ::read(fd, buffer, s);
915 if (s != nb) { /* read error */
919 Dmsg0(dbglevel, "EOT during reading\n");
923 if (current_block >= 0) {
930 int vtape::open(const char *pathname, int uflags)
932 Dmsg2(dbglevel, "vtape::open(%s, %i)\n", pathname, uflags);
934 online = true; /* assume that drive contains a tape */
937 if (stat(pathname, &statp) != 0) {
938 Dmsg1(dbglevel, "Can't stat on %s\n", pathname);
939 if (uflags & O_NONBLOCK) {
941 fd = ::open("/dev/null", O_CREAT | O_RDWR | O_LARGEFILE, 0600);
944 fd = ::open(pathname, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
955 cur_FM = next_FM = last_FM = 0;
958 atEOT = atEOD = false;
960 /* If the vtape is empty, start by writing a EOF */
961 if (online && !read_fm(VT_READ_EOF)) {
963 last_file = current_file=0;
969 /* use this to track file usage */
970 void vtape::update_pos()
974 if (fstat(fd, &statp) == 0) {
975 file_block = statp.st_blocks;
978 Dmsg1(dbglevel+1, "update_pos=%i\n", file_block);
980 if (file_block > max_block) {
989 Dmsg0(dbglevel+1, "===================\n");
990 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
991 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
992 Dmsg1(dbglevel+1, "file_block=%i\n", file_block);
993 Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n",
994 atEOF, atEOT, atEOD, atBOT);