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;
365 Dmsg0(0, "I'm a vtape device\n");
374 * Write a variable block of count size.
375 * block = vtape_header + data
376 * vtape_header = sizeof(data)
377 * if vtape_header == 0, this is a EOF
379 ssize_t vtape::d_write(int, const void *buffer, size_t count)
382 ASSERT(current_file >= 0);
387 Dmsg3(dbglevel*2, "write len=%i %i:%i\n",
388 count, current_file,current_block);
391 Dmsg0(dbglevel, "write nothing, EOT !\n");
396 if (!atEOD) { /* if not at the end of the data */
400 if (current_block != -1) {
406 atEOD = true; /* End of data */
408 needEOF = true; /* next operation need EOF mark */
410 uint32_t size = count;
411 ::write(fd, &size, sizeof(uint32_t));
412 nb = ::write(fd, buffer, count);
414 if (nb != (ssize_t)count) {
417 "Not enough space writing only %i of %i requested\n",
427 * +---+---------+---+------------------+---+-------------------+
428 * |00N| DATA |0LN| DATA |0LC| DATA |
429 * +---+---------+---+------------------+---+-------------------+
432 * L : Last FileMark offset
433 * N : Next FileMark offset
434 * C : Current FileMark Offset
439 ASSERT(current_file >= 0);
448 truncate_file(); /* nothing after this point */
452 cur_FM = lseek(fd, 0, SEEK_CUR); // current position
454 /* update previous next_FM */
455 lseek(fd, last_FM + sizeof(uint32_t)+sizeof(boffset_t), SEEK_SET);
456 ::write(fd, &cur_FM, sizeof(boffset_t));
457 lseek(fd, cur_FM, SEEK_SET);
462 ::write(fd, &c, sizeof(uint32_t)); // EOF
463 ::write(fd, &last_FM, sizeof(last_FM)); // F-1
464 ::write(fd, &next_FM, sizeof(next_FM)); // F (will be updated next time)
474 last_file = MAX(current_file, last_file);
476 Dmsg4(dbglevel, "Writing EOF %i:%i last=%lli cur=%lli next=0\n",
477 current_file, current_block, last_FM, cur_FM);
488 ASSERT(current_file >= 0);
491 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
495 if (atEOT || atEOD) {
502 Dmsg2(dbglevel+1, "fsf %i <= %i\n", current_file, last_file);
504 if (next_FM > cur_FM) { /* not the last file */
505 lseek(fd, next_FM, SEEK_SET);
506 read_fm(VT_READ_EOF);
511 } else if (atEOF) { /* last file mark */
517 } else { /* last file, but no at the end */
520 Dmsg0(dbglevel, "Try to FSF after EOT\n");
522 current_file = last_file ;
530 /* /------------\ /---------------\
531 * +---+------+---+---------------+-+
533 * +---+------+---+---------------+-+
536 bool vtape::read_fm(VT_READ_FM_MODE read_all)
540 if (read_all == VT_READ_EOF) {
541 ::read(fd, &c, sizeof(c));
543 lseek(fd, cur_FM, SEEK_SET);
548 cur_FM = lseek(fd, 0, SEEK_CUR) - sizeof(c);
550 ::read(fd, &last_FM, sizeof(last_FM));
551 ret = ::read(fd, &next_FM, sizeof(next_FM));
555 Dmsg3(dbglevel, "Read FM cur=%lli last=%lli next=%lli\n",
556 cur_FM, last_FM, next_FM);
558 return (ret == sizeof(next_FM));
562 * TODO: Check fsr with EOF
564 int vtape::fsr(int count)
567 ASSERT(current_file >= 0);
573 Dmsg4(dbglevel, "fsr %i:%i EOF=%i c=%i\n",
574 current_file,current_block,atEOF,count);
589 atBOT = atEOF = false;
591 /* check all block record */
592 for(i=0; (i < count) && !atEOF ; i++) {
593 nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
594 if (nb == sizeof(uint32_t) && s) {
596 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
598 Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
599 current_file, current_block, nb,s);
604 read_fm(VT_SKIP_EOF);
606 atEOF = true; /* stop the loop */
614 * BSR + EOF => begin of EOF + EIO
615 * BSR + BSR + EOF => last block
618 int vtape::bsr(int count)
621 ASSERT(current_file >= 0);
635 boffset_t last=-1, last2=-1;
636 boffset_t orig = lseek(fd, 0, SEEK_CUR);
637 int orig_f = current_file;
638 int orig_b = current_block;
640 Dmsg4(dbglevel, "bsr(%i) cur_blk=%i orig=%lli cur_FM=%lli\n",
641 count, current_block, orig, cur_FM);
643 /* begin of tape, do nothing */
649 /* at EOF 0:-1 BOT=0 EOD=0 EOF=0 ERR: Input/output error */
651 lseek(fd, cur_FM, SEEK_SET);
653 if (current_file > 0) {
662 * First, go to cur/last_FM and read all blocks to find the good one
664 if (cur_FM == orig) { /* already just before EOF */
665 lseek(fd, last_FM, SEEK_SET);
668 lseek(fd, cur_FM, SEEK_SET);
671 ret = read_fm(VT_READ_EOF);
675 last2 = last; /* keep track of the 2 last blocs position */
676 last = lseek(fd, 0, SEEK_CUR);
677 last_f = current_file;
678 last_b = current_block;
679 Dmsg6(dbglevel, "EOF=%i last2=%lli last=%lli < orig=%lli %i:%i\n",
680 atEOF, last2, last, orig, current_file, current_block);
683 } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
685 if (last2 > 0 && atEOF) { /* we take the previous position */
686 lseek(fd, last2, SEEK_SET);
687 current_file = last_f;
688 current_block = last_b - 1;
689 Dmsg3(dbglevel, "1 set offset2=%lli %i:%i\n",
690 last, current_file, current_block);
692 } else if (last > 0) {
693 lseek(fd, last, SEEK_SET);
694 current_file = last_f;
695 current_block = last_b;
696 Dmsg3(dbglevel, "2 set offset=%lli %i:%i\n",
697 last, current_file, current_block);
699 lseek(fd, orig, SEEK_SET);
700 current_file = orig_f;
701 current_block = orig_b;
705 Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
707 atEOT = atEOF = atEOD = false;
708 atBOT = (lseek(fd, 0, SEEK_CUR) - (sizeof(uint32_t)+2*sizeof(boffset_t))) == 0;
711 current_block = orig_b;
717 boffset_t vtape::lseek(int fd, off_t offset, int whence)
719 return ::lseek(fd, offset, whence);
722 /* BSF => just before last EOF
723 * EOF + BSF => just before EOF
724 * file 0 + BSF => BOT + errno
729 ASSERT(current_file >= 0);
730 Dmsg2(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block);
735 atBOT = atEOF = atEOT = atEOD = false;
737 if (current_file == 0) {/* BOT + errno */
738 lseek(fd, 0, SEEK_SET);
739 read_fm(VT_READ_EOF);
746 Dmsg1(dbglevel, "bsf last=%lli\n", last_FM);
747 lseek(fd, cur_FM, SEEK_SET);
755 * Put vtape in offline mode
761 atEOF = false; /* End of file */
762 atEOT = false; /* End of tape */
763 atEOD = false; /* End of data */
764 atBOT = false; /* Begin of tape */
774 /* A filemark is automatically written to tape if the last tape operation
775 * before close was a write.
777 int vtape::d_close(int)
786 * When a filemark is encountered while reading, the following happens. If
787 * there are data remaining in the buffer when the filemark is found, the
788 * buffered data is returned. The next read returns zero bytes. The following
789 * read returns data from the next file. The end of recorded data is signaled
790 * by returning zero bytes for two consecutive read calls. The third read
793 ssize_t vtape::d_read(int, void *buffer, size_t count)
796 ASSERT(current_file >= 0);
800 Dmsg2(dbglevel*2, "read %i:%i\n", current_file, current_block);
802 if (atEOT || atEOD) {
819 atEOD = atBOT = false;
821 /* reading size of data */
822 nb = ::read(fd, &s, sizeof(uint32_t));
824 atEOF = true; /* TODO: check this */
828 if (s > count) { /* not enough buffer to read block */
829 Dmsg2(dbglevel, "Need more buffer to read next block %i > %i\n",s,count);
830 lseek(fd, s, SEEK_CUR);
837 if (read_fm(VT_SKIP_EOF)) {
844 /* reading data itself */
845 nb = ::read(fd, buffer, s);
846 if (nb != (ssize_t)s) { /* read error */
850 Dmsg0(dbglevel, "EOT during reading\n");
854 if (current_block >= 0) {
861 int vtape::d_open(const char *pathname, int uflags)
863 Dmsg2(dbglevel, "vtape::d_open(%s, %i)\n", pathname, uflags);
865 online = true; /* assume that drive contains a tape */
868 if (stat(pathname, &statp) != 0) {
870 Dmsg1(dbglevel, "Can't stat on %s\n", pathname);
871 if (uflags & O_NONBLOCK) {
873 fd = ::open("/dev/null", O_CREAT | O_RDWR | O_LARGEFILE, 0600);
876 fd = ::open(pathname, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
887 cur_FM = next_FM = last_FM = 0;
890 atEOT = atEOD = false;
892 /* If the vtape is empty, start by writing a EOF */
893 if (online && !read_fm(VT_READ_EOF)) {
894 lseek(fd, 0, SEEK_SET); /* rewind */
895 cur_FM = next_FM = last_FM = 0; /* reset */
896 weof(); /* write the first EOF */
897 last_file = current_file=0;
903 /* use this to track file usage */
904 void vtape::update_pos()
908 if (fstat(fd, &statp) == 0) {
909 file_block = statp.st_blocks;
912 Dmsg1(dbglevel*2, "update_pos=%i\n", file_block);
914 if (file_block > max_block) {
923 Dmsg0(dbglevel+1, "===================\n");
924 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
925 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
926 Dmsg1(dbglevel+1, "file_block=%i\n", file_block);
927 Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n",
928 atEOF, atEOT, atEOD, atBOT);
931 #endif /* ! USE_VTAPE */