2 Bacula® - The Network Backup Solution
4 Copyright (C) 2008-2010 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 three of the GNU Affero 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 Affero 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 Kern Sibbald.
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 */
68 static int dbglevel = 100;
69 #define FILE_OFFSET 30
71 void vtape_debug(int level)
76 int vtape::d_ioctl(int fd, ioctl_req_t request, char *op)
80 if (request == MTIOCTOP) {
81 result = tape_op((mtop *)op);
82 } else if (request == MTIOCGET) {
83 result = tape_get((mtget *)op);
84 } else if (request == MTIOCPOS) {
85 result = tape_pos((mtpos *)op);
94 int vtape::tape_op(struct mtop *mt_com)
97 int count = mt_com->mt_count;
104 switch (mt_com->mt_op)
120 case MTFSF: /* Forward space over mt_count filemarks. */
123 } while (--count > 0 && result == 0);
126 case MTBSF: /* Backward space over mt_count filemarks. */
129 } while (--count > 0 && result == 0);
132 case MTFSR: /* Forward space over mt_count records (tape blocks). */
140 mt: /dev/lto2: Erreur d'entree/sortie
145 /* tester si on se trouve a la fin du fichier */
146 result = fsr(mt_com->mt_count);
149 case MTBSR: /* Backward space over mt_count records (tape blocks). */
150 result = bsr(mt_com->mt_count);
153 case MTWEOF: /* Write mt_count filemarks. */
156 } while (result == 0 && --count > 0);
159 case MTREW: /* Rewind. */
160 Dmsg0(dbglevel, "rewind vtape\n");
162 atEOF = atEOD = false;
166 lseek(fd, 0, SEEK_SET);
167 result = !read_fm(VT_READ_EOF);
170 case MTOFFL: /* put tape offline */
174 case MTRETEN: /* Re-tension tape. */
178 case MTBSFM: /* not used by bacula */
183 case MTFSFM: /* not used by bacula */
188 case MTEOM:/* Go to the end of the recorded media (for appending files). */
190 lseek(fd, next_FM, SEEK_SET);
191 if (read_fm(VT_READ_EOF)) {
196 while (::read(fd, &l, sizeof(l)) > 0) {
198 lseek(fd, l, SEEK_CUR);
202 Dmsg0(dbglevel, "skip 1 block\n");
215 case MTERASE: /* not used by bacula */
222 lseek(fd, 0, SEEK_SET);
223 read_fm(VT_READ_EOF);
267 return result == 0 ? 0 : -1;
270 int vtape::tape_get(struct mtget *mt_get)
273 int block_size = 1024;
275 mt_get->mt_type = MT_ISSCSI2;
276 mt_get->mt_blkno = current_block;
277 mt_get->mt_fileno = current_file;
279 mt_get->mt_resid = -1;
280 // pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
284 ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
285 ((block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
288 mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
291 mt_get->mt_gstat |= 0x80000000; // GMT_EOF
295 mt_get->mt_gstat |= 0x40000000; // GMT_BOT
298 mt_get->mt_gstat |= 0x20000000; // GMT_EOT
302 mt_get->mt_gstat |= 0x08000000; // GMT_EOD
305 if (0) { //WriteProtected) {
306 mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
310 mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
312 mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
314 mt_get->mt_erreg = 0;
319 int vtape::tape_pos(struct mtpos *mt_pos)
321 if (current_block >= 0) {
322 mt_pos->mt_blkno = current_block;
330 * This function try to emulate the append only behavior
331 * of a tape. When you wrote something, data after the
332 * current position are discarded.
334 int vtape::truncate_file()
336 Dmsg2(dbglevel, "truncate %i:%i\n", current_file, current_block);
337 ftruncate(fd, lseek(fd, 0, SEEK_CUR));
338 last_file = current_file;
364 max_block = VTAPE_MAX_BLOCK;
373 * Write a variable block of count size.
374 * block = vtape_header + data
375 * vtape_header = sizeof(data)
376 * if vtape_header == 0, this is a EOF
378 ssize_t vtape::d_write(int, const void *buffer, size_t count)
381 ASSERT(current_file >= 0);
386 Dmsg3(dbglevel*2, "write len=%i %i:%i\n",
387 count, current_file,current_block);
390 Dmsg0(dbglevel, "write nothing, EOT !\n");
395 if (!atEOD) { /* if not at the end of the data */
399 if (current_block != -1) {
405 atEOD = true; /* End of data */
407 needEOF = true; /* next operation need EOF mark */
409 uint32_t size = count;
410 ::write(fd, &size, sizeof(uint32_t));
411 nb = ::write(fd, buffer, count);
413 if (nb != (ssize_t)count) {
416 "Not enough space writing only %i of %i requested\n",
426 * +---+---------+---+------------------+---+-------------------+
427 * |00N| DATA |0LN| DATA |0LC| DATA |
428 * +---+---------+---+------------------+---+-------------------+
431 * L : Last FileMark offset
432 * N : Next FileMark offset
433 * C : Current FileMark Offset
438 ASSERT(current_file >= 0);
447 truncate_file(); /* nothing after this point */
451 cur_FM = lseek(fd, 0, SEEK_CUR); // current position
453 /* update previous next_FM */
454 lseek(fd, last_FM + sizeof(uint32_t)+sizeof(boffset_t), SEEK_SET);
455 ::write(fd, &cur_FM, sizeof(boffset_t));
456 lseek(fd, cur_FM, SEEK_SET);
461 ::write(fd, &c, sizeof(uint32_t)); // EOF
462 ::write(fd, &last_FM, sizeof(last_FM)); // F-1
463 ::write(fd, &next_FM, sizeof(next_FM)); // F (will be updated next time)
473 last_file = MAX(current_file, last_file);
475 Dmsg4(dbglevel, "Writing EOF %i:%i last=%lli cur=%lli next=0\n",
476 current_file, current_block, last_FM, cur_FM);
487 ASSERT(current_file >= 0);
490 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
494 if (atEOT || atEOD) {
501 Dmsg2(dbglevel+1, "fsf %i <= %i\n", current_file, last_file);
503 if (next_FM > cur_FM) { /* not the last file */
504 lseek(fd, next_FM, SEEK_SET);
505 read_fm(VT_READ_EOF);
510 } else if (atEOF) { /* last file mark */
516 } else { /* last file, but no at the end */
519 Dmsg0(dbglevel, "Try to FSF after EOT\n");
521 current_file = last_file ;
529 /* /------------\ /---------------\
530 * +---+------+---+---------------+-+
532 * +---+------+---+---------------+-+
535 bool vtape::read_fm(VT_READ_FM_MODE read_all)
539 if (read_all == VT_READ_EOF) {
540 ::read(fd, &c, sizeof(c));
542 lseek(fd, cur_FM, SEEK_SET);
547 cur_FM = lseek(fd, 0, SEEK_CUR) - sizeof(c);
549 ::read(fd, &last_FM, sizeof(last_FM));
550 ret = ::read(fd, &next_FM, sizeof(next_FM));
554 Dmsg3(dbglevel, "Read FM cur=%lli last=%lli next=%lli\n",
555 cur_FM, last_FM, next_FM);
557 return (ret == sizeof(next_FM));
561 * TODO: Check fsr with EOF
563 int vtape::fsr(int count)
566 ASSERT(current_file >= 0);
572 Dmsg4(dbglevel, "fsr %i:%i EOF=%i c=%i\n",
573 current_file,current_block,atEOF,count);
588 atBOT = atEOF = false;
590 /* check all block record */
591 for(i=0; (i < count) && !atEOF ; i++) {
592 nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
593 if (nb == sizeof(uint32_t) && s) {
595 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
597 Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
598 current_file, current_block, nb,s);
603 read_fm(VT_SKIP_EOF);
605 atEOF = true; /* stop the loop */
613 * BSR + EOF => begin of EOF + EIO
614 * BSR + BSR + EOF => last block
617 int vtape::bsr(int count)
620 ASSERT(current_file >= 0);
634 boffset_t last=-1, last2=-1;
635 boffset_t orig = lseek(fd, 0, SEEK_CUR);
636 int orig_f = current_file;
637 int orig_b = current_block;
639 Dmsg4(dbglevel, "bsr(%i) cur_blk=%i orig=%lli cur_FM=%lli\n",
640 count, current_block, orig, cur_FM);
642 /* begin of tape, do nothing */
648 /* at EOF 0:-1 BOT=0 EOD=0 EOF=0 ERR: Input/output error */
650 lseek(fd, cur_FM, SEEK_SET);
652 if (current_file > 0) {
661 * First, go to cur/last_FM and read all blocks to find the good one
663 if (cur_FM == orig) { /* already just before EOF */
664 lseek(fd, last_FM, SEEK_SET);
667 lseek(fd, cur_FM, SEEK_SET);
670 ret = read_fm(VT_READ_EOF);
674 last2 = last; /* keep track of the 2 last blocs position */
675 last = lseek(fd, 0, SEEK_CUR);
676 last_f = current_file;
677 last_b = current_block;
678 Dmsg6(dbglevel, "EOF=%i last2=%lli last=%lli < orig=%lli %i:%i\n",
679 atEOF, last2, last, orig, current_file, current_block);
682 } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
684 if (last2 > 0 && atEOF) { /* we take the previous position */
685 lseek(fd, last2, SEEK_SET);
686 current_file = last_f;
687 current_block = last_b - 1;
688 Dmsg3(dbglevel, "1 set offset2=%lli %i:%i\n",
689 last, current_file, current_block);
691 } else if (last > 0) {
692 lseek(fd, last, SEEK_SET);
693 current_file = last_f;
694 current_block = last_b;
695 Dmsg3(dbglevel, "2 set offset=%lli %i:%i\n",
696 last, current_file, current_block);
698 lseek(fd, orig, SEEK_SET);
699 current_file = orig_f;
700 current_block = orig_b;
704 Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
706 atEOT = atEOF = atEOD = false;
707 atBOT = (lseek(fd, 0, SEEK_CUR) - (sizeof(uint32_t)+2*sizeof(boffset_t))) == 0;
710 current_block = orig_b;
716 boffset_t vtape::lseek(int fd, off_t offset, int whence)
718 return ::lseek(fd, offset, whence);
721 /* BSF => just before last EOF
722 * EOF + BSF => just before EOF
723 * file 0 + BSF => BOT + errno
728 ASSERT(current_file >= 0);
729 Dmsg2(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block);
734 atBOT = atEOF = atEOT = atEOD = false;
736 if (current_file == 0) {/* BOT + errno */
737 lseek(fd, 0, SEEK_SET);
738 read_fm(VT_READ_EOF);
745 Dmsg1(dbglevel, "bsf last=%lli\n", last_FM);
746 lseek(fd, cur_FM, SEEK_SET);
754 * Put vtape in offline mode
760 atEOF = false; /* End of file */
761 atEOT = false; /* End of tape */
762 atEOD = false; /* End of data */
763 atBOT = false; /* Begin of tape */
773 /* A filemark is automatically written to tape if the last tape operation
774 * before close was a write.
776 int vtape::d_close(int)
785 * When a filemark is encountered while reading, the following happens. If
786 * there are data remaining in the buffer when the filemark is found, the
787 * buffered data is returned. The next read returns zero bytes. The following
788 * read returns data from the next file. The end of recorded data is signaled
789 * by returning zero bytes for two consecutive read calls. The third read
792 ssize_t vtape::d_read(int, void *buffer, size_t count)
795 ASSERT(current_file >= 0);
799 Dmsg2(dbglevel*2, "read %i:%i\n", current_file, current_block);
801 if (atEOT || atEOD) {
818 atEOD = atBOT = false;
820 /* reading size of data */
821 nb = ::read(fd, &s, sizeof(uint32_t));
823 atEOF = true; /* TODO: check this */
827 if (s > count) { /* not enough buffer to read block */
828 Dmsg2(dbglevel, "Need more buffer to read next block %i > %i\n",s,count);
829 lseek(fd, s, SEEK_CUR);
836 if (read_fm(VT_SKIP_EOF)) {
843 /* reading data itself */
844 nb = ::read(fd, buffer, s);
845 if (nb != (ssize_t)s) { /* read error */
849 Dmsg0(dbglevel, "EOT during reading\n");
853 if (current_block >= 0) {
860 int vtape::d_open(const char *pathname, int uflags)
862 Dmsg2(dbglevel, "vtape::d_open(%s, %i)\n", pathname, uflags);
864 online = true; /* assume that drive contains a tape */
867 if (stat(pathname, &statp) != 0) {
869 Dmsg1(dbglevel, "Can't stat on %s\n", pathname);
870 if (uflags & O_NONBLOCK) {
872 fd = ::open("/dev/null", O_CREAT | O_RDWR | O_LARGEFILE, 0600);
875 fd = ::open(pathname, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
886 cur_FM = next_FM = last_FM = 0;
889 atEOT = atEOD = false;
891 /* If the vtape is empty, start by writing a EOF */
892 if (online && !read_fm(VT_READ_EOF)) {
893 lseek(fd, 0, SEEK_SET); /* rewind */
894 cur_FM = next_FM = last_FM = 0; /* reset */
895 weof(); /* write the first EOF */
896 last_file = current_file=0;
902 /* use this to track file usage */
903 void vtape::update_pos()
907 if (fstat(fd, &statp) == 0) {
908 file_block = statp.st_blocks;
911 Dmsg1(dbglevel*2, "update_pos=%i\n", file_block);
913 if (file_block > max_block) {
922 Dmsg0(dbglevel+1, "===================\n");
923 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
924 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
925 Dmsg1(dbglevel+1, "file_block=%i\n", file_block);
926 Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n",
927 atEOF, atEOT, atEOD, atBOT);
930 #endif /* ! USE_VTAPE */