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 ssize_t vtape_read(int fd, void *buffer, size_t count)
118 vtape *tape = get_tape(fd);
119 ASSERT(tape != NULL);
120 return tape->read(buffer, count);
123 ssize_t vtape_write(int fd, const void *buffer, size_t 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 #ifdef HAVE_FREEBSD_OS
170 int vtape::tape_op(struct mtop *mt_com)
175 int vtape::tape_get(struct mtget *mt_get)
182 int vtape::tape_op(struct mtop *mt_com)
185 int count = mt_com->mt_count;
192 switch (mt_com->mt_op)
208 case MTFSF: /* Forward space over mt_count filemarks. */
211 } while (--count > 0 && result == 0);
214 case MTBSF: /* Backward space over mt_count filemarks. */
217 } while (--count > 0 && result == 0);
220 case MTFSR: /* Forward space over mt_count records (tape blocks). */
228 mt: /dev/lto2: Erreur d'entree/sortie
233 /* tester si on se trouve a la fin du fichier */
234 result = fsr(mt_com->mt_count);
237 case MTBSR: /* Backward space over mt_count records (tape blocks). */
238 result = bsr(mt_com->mt_count);
241 case MTWEOF: /* Write mt_count filemarks. */
244 } while (result == 0 && --count > 0);
247 case MTREW: /* Rewind. */
248 Dmsg0(dbglevel, "rewind vtape\n");
250 atEOF = atEOD = false;
254 lseek(fd, 0, SEEK_SET);
255 result = !read_fm(VT_READ_EOF);
258 case MTOFFL: /* put tape offline */
262 case MTRETEN: /* Re-tension tape. */
266 case MTBSFM: /* not used by bacula */
271 case MTFSFM: /* not used by bacula */
276 case MTEOM:/* Go to the end of the recorded media (for appending files). */
278 lseek(fd, next_FM, SEEK_SET);
279 if (read_fm(VT_READ_EOF)) {
284 while (::read(fd, &l, sizeof(l)) > 0) {
286 lseek(fd, l, SEEK_CUR);
290 Dmsg0(dbglevel, "skip 1 block\n");
303 case MTERASE: /* not used by bacula */
310 lseek(fd, 0, SEEK_SET);
311 read_fm(VT_READ_EOF);
355 return result == 0 ? 0 : -1;
358 int vtape::tape_get(struct mtget *mt_get)
361 int block_size = 1024;
363 mt_get->mt_type = MT_ISSCSI2;
364 mt_get->mt_blkno = current_block;
365 mt_get->mt_fileno = current_file;
367 mt_get->mt_resid = -1;
368 // pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
372 ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
373 ((block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
376 mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
379 mt_get->mt_gstat |= 0x80000000; // GMT_EOF
383 mt_get->mt_gstat |= 0x40000000; // GMT_BOT
386 mt_get->mt_gstat |= 0x20000000; // GMT_EOT
390 mt_get->mt_gstat |= 0x08000000; // GMT_EOD
393 if (0) { //WriteProtected) {
394 mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
398 mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
400 mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
402 mt_get->mt_erreg = 0;
407 #endif /* ! HAVE_FREEBSD_OS */
409 int vtape::tape_pos(struct mtpos *mt_pos)
411 if (current_block >= 0) {
412 mt_pos->mt_blkno = current_block;
420 * This function try to emulate the append only behavior
421 * of a tape. When you wrote something, data after the
422 * current position are discarded.
424 int vtape::truncate_file()
426 Dmsg2(dbglevel, "truncate %i:%i\n", current_file, current_block);
427 ftruncate(fd, lseek(fd, 0, SEEK_CUR));
428 last_file = current_file;
450 max_block = 2*1024*2048; /* 2GB */
463 * Write a variable block of count size.
464 * block = vtape_header + data
465 * vtape_header = sizeof(data)
466 * if vtape_header == 0, this is a EOF
468 ssize_t vtape::write(const void *buffer, size_t count)
471 ASSERT(current_file >= 0);
476 Dmsg3(dbglevel*2, "write len=%i %i:%i\n",
477 count, current_file,current_block);
480 Dmsg0(dbglevel, "write nothing, EOT !\n");
485 if (!atEOD) { /* if not at the end of the data */
489 if (current_block != -1) {
495 atEOD = true; /* End of data */
497 needEOF = true; /* next operation need EOF mark */
499 uint32_t size = count;
500 ::write(fd, &size, sizeof(uint32_t));
501 nb = ::write(fd, buffer, count);
503 if (nb != (ssize_t)count) {
506 "Not enough space writing only %i of %i requested\n",
516 * +---+---------+---+------------------+---+-------------------+
517 * |00N| DATA |0LN| DATA |0LC| DATA |
518 * +---+---------+---+------------------+---+-------------------+
521 * L : Last FileMark offset
522 * N : Next FileMark offset
523 * C : Current FileMark Offset
528 ASSERT(current_file >= 0);
537 truncate_file(); /* nothing after this point */
541 cur_FM = lseek(fd, 0, SEEK_CUR); // current position
543 /* update previous next_FM */
544 lseek(fd, last_FM + sizeof(uint32_t)+sizeof(off_t), SEEK_SET);
545 ::write(fd, &cur_FM, sizeof(off_t));
546 lseek(fd, cur_FM, SEEK_SET);
551 ::write(fd, &c, sizeof(uint32_t)); // EOF
552 ::write(fd, &last_FM, sizeof(last_FM)); // F-1
553 ::write(fd, &next_FM, sizeof(next_FM)); // F (will be updated next time)
563 last_file = MAX(current_file, last_file);
565 Dmsg4(dbglevel, "Writing EOF %i:%i last=%lli cur=%lli next=0\n",
566 current_file, current_block, last_FM, cur_FM);
577 ASSERT(current_file >= 0);
580 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
584 if (atEOT || atEOD) {
591 Dmsg2(dbglevel+1, "fsf %i <= %i\n", current_file, last_file);
593 if (next_FM > cur_FM) { /* not the last file */
594 lseek(fd, next_FM, SEEK_SET);
595 read_fm(VT_READ_EOF);
600 } else if (atEOF) { /* last file mark */
606 } else { /* last file, but no at the end */
609 Dmsg0(dbglevel, "Try to FSF after EOT\n");
611 current_file = last_file ;
619 /* /------------\ /---------------\
620 * +---+------+---+---------------+-+
622 * +---+------+---+---------------+-+
625 bool vtape::read_fm(VT_READ_FM_MODE read_all)
629 if (read_all == VT_READ_EOF) {
630 ::read(fd, &c, sizeof(c));
632 lseek(fd, cur_FM, SEEK_SET);
637 cur_FM = lseek(fd, 0, SEEK_CUR) - sizeof(c);
639 ::read(fd, &last_FM, sizeof(last_FM));
640 ret = ::read(fd, &next_FM, sizeof(next_FM));
644 Dmsg3(dbglevel, "Read FM cur=%lli last=%lli next=%lli\n",
645 cur_FM, last_FM, next_FM);
647 return (ret == sizeof(next_FM));
651 * TODO: Check fsr with EOF
653 int vtape::fsr(int count)
656 ASSERT(current_file >= 0);
662 Dmsg4(dbglevel, "fsr %i:%i EOF=%i c=%i\n",
663 current_file,current_block,atEOF,count);
678 atBOT = atEOF = false;
680 /* check all block record */
681 for(i=0; (i < count) && !atEOF ; i++) {
682 nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
683 if (nb == sizeof(uint32_t) && s) {
685 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
687 Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
688 current_file, current_block, nb,s);
693 read_fm(VT_SKIP_EOF);
695 atEOF = true; /* stop the loop */
703 * BSR + EOF => begin of EOF + EIO
704 * BSR + BSR + EOF => last block
707 int vtape::bsr(int count)
710 ASSERT(current_file >= 0);
724 off_t last=-1, last2=-1;
725 off_t orig = lseek(fd, 0, SEEK_CUR);
726 int orig_f = current_file;
727 int orig_b = current_block;
729 Dmsg4(dbglevel, "bsr(%i) cur_blk=%i orig=%lli cur_FM=%lli\n",
730 count, current_block, orig, cur_FM);
732 /* begin of tape, do nothing */
738 /* at EOF 0:-1 BOT=0 EOD=0 EOF=0 ERR: Input/output error */
740 lseek(fd, cur_FM, SEEK_SET);
742 if (current_file > 0) {
751 * First, go to cur/last_FM and read all blocks to find the good one
753 if (cur_FM == orig) { /* already just before EOF */
754 lseek(fd, last_FM, SEEK_SET);
757 lseek(fd, cur_FM, SEEK_SET);
760 ret = read_fm(VT_READ_EOF);
764 last2 = last; /* keep track of the 2 last blocs position */
765 last = lseek(fd, 0, SEEK_CUR);
766 last_f = current_file;
767 last_b = current_block;
768 Dmsg6(dbglevel, "EOF=%i last2=%lli last=%lli < orig=%lli %i:%i\n",
769 atEOF, last2, last, orig, current_file, current_block);
772 } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
774 if (last2 > 0 && atEOF) { /* we take the previous position */
775 lseek(fd, last2, SEEK_SET);
776 current_file = last_f;
777 current_block = last_b - 1;
778 Dmsg3(dbglevel, "1 set offset2=%lli %i:%i\n",
779 last, current_file, current_block);
781 } else if (last > 0) {
782 lseek(fd, last, SEEK_SET);
783 current_file = last_f;
784 current_block = last_b;
785 Dmsg3(dbglevel, "2 set offset=%lli %i:%i\n",
786 last, current_file, current_block);
788 lseek(fd, orig, SEEK_SET);
789 current_file = orig_f;
790 current_block = orig_b;
794 Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
796 atEOT = atEOF = atEOD = false;
797 atBOT = (lseek(fd, 0, SEEK_CUR) - (sizeof(uint32_t)+2*sizeof(off_t))) == 0;
800 current_block = orig_b;
806 /* BSF => just before last EOF
807 * EOF + BSF => just before EOF
808 * file 0 + BSF => BOT + errno
813 ASSERT(current_file >= 0);
814 Dmsg2(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block);
819 atBOT = atEOF = atEOT = atEOD = false;
821 if (current_file == 0) {/* BOT + errno */
822 lseek(fd, 0, SEEK_SET);
823 read_fm(VT_READ_EOF);
830 Dmsg1(dbglevel, "bsf last=%lli\n", last_FM);
831 lseek(fd, cur_FM, SEEK_SET);
839 * Put vtape in offline mode
845 atEOF = false; /* End of file */
846 atEOT = false; /* End of tape */
847 atEOD = false; /* End of data */
848 atBOT = false; /* Begin of tape */
858 /* A filemark is automatically written to tape if the last tape operation
859 * before close was a write.
870 * When a filemark is encountered while reading, the following happens. If
871 * there are data remaining in the buffer when the filemark is found, the
872 * buffered data is returned. The next read returns zero bytes. The following
873 * read returns data from the next file. The end of recorded data is signaled
874 * by returning zero bytes for two consecutive read calls. The third read
877 ssize_t vtape::read(void *buffer, size_t count)
880 ASSERT(current_file >= 0);
884 Dmsg2(dbglevel*2, "read %i:%i\n", current_file, current_block);
886 if (atEOT || atEOD) {
903 atEOD = atBOT = false;
905 /* reading size of data */
906 nb = ::read(fd, &s, sizeof(uint32_t));
908 atEOF = true; /* TODO: check this */
912 if (s > count) { /* not enough buffer to read block */
913 Dmsg2(dbglevel, "Need more buffer to read next block %i > %i\n",s,count);
914 lseek(fd, s, SEEK_CUR);
921 if (read_fm(VT_SKIP_EOF)) {
928 /* reading data itself */
929 nb = ::read(fd, buffer, s);
930 if (nb != (ssize_t)s) { /* read error */
934 Dmsg0(dbglevel, "EOT during reading\n");
938 if (current_block >= 0) {
945 int vtape::open(const char *pathname, int uflags)
947 Dmsg2(dbglevel, "vtape::open(%s, %i)\n", pathname, uflags);
949 online = true; /* assume that drive contains a tape */
952 if (stat(pathname, &statp) != 0) {
953 Dmsg1(dbglevel, "Can't stat on %s\n", pathname);
954 if (uflags & O_NONBLOCK) {
956 fd = ::open("/dev/null", O_CREAT | O_RDWR | O_LARGEFILE, 0600);
959 fd = ::open(pathname, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
970 cur_FM = next_FM = last_FM = 0;
973 atEOT = atEOD = false;
975 /* If the vtape is empty, start by writing a EOF */
976 if (online && !read_fm(VT_READ_EOF)) {
978 last_file = current_file=0;
984 /* use this to track file usage */
985 void vtape::update_pos()
989 if (fstat(fd, &statp) == 0) {
990 file_block = statp.st_blocks;
993 Dmsg1(dbglevel*2, "update_pos=%i\n", file_block);
995 if (file_block > max_block) {
1004 Dmsg0(dbglevel+1, "===================\n");
1005 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
1006 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
1007 Dmsg1(dbglevel+1, "file_block=%i\n", file_block);
1008 Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n",
1009 atEOF, atEOT, atEOD, atBOT);