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 * TODO: check if after a write op, and other tape op put a EOF
450 int vtape::write(const void *buffer, unsigned int count)
453 ASSERT(current_file >= 0);
458 Dmsg3(dbglevel*2, "write len=%i %i:%i\n",
459 count, current_file,current_block);
462 Dmsg0(dbglevel, "write nothing, EOT !\n");
467 if (!atEOD) { /* if not at the end of the data */
471 if (current_block != -1) {
477 atEOD = true; /* End of data */
479 needEOF = true; /* next operation need EOF mark */
481 uint32_t size = count;
482 ::write(fd, &size, sizeof(uint32_t));
483 nb = ::write(fd, buffer, count);
488 "Not enough space writing only %i of %i requested\n",
498 * +---+---------+---+------------------+---+-------------------+
499 * |00N| DATA |0LN| DATA |0LC| DATA |
500 * +---+---------+---+------------------+---+-------------------+
503 * L : Last FileMark offset
504 * N : Next FileMark offset
505 * C : Current FileMark Offset
510 ASSERT(current_file >= 0);
519 truncate_file(); /* nothing after this point */
523 cur_FM = lseek(fd, 0, SEEK_CUR); // current position
525 /* update previous next_FM */
526 lseek(fd, last_FM + sizeof(uint32_t)+sizeof(off_t), SEEK_SET);
527 ::write(fd, &cur_FM, sizeof(off_t));
528 lseek(fd, cur_FM, SEEK_SET);
533 ::write(fd, &c, sizeof(uint32_t)); // EOF
534 ::write(fd, &last_FM, sizeof(last_FM)); // F-1
535 ::write(fd, &next_FM, sizeof(next_FM)); // F (will be updated next time)
545 last_file = MAX(current_file, last_file);
547 Dmsg4(dbglevel, "Writing EOF %i:%i last=%lli cur=%lli next=0\n",
548 current_file, current_block, last_FM, cur_FM);
559 ASSERT(current_file >= 0);
562 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
566 if (atEOT || atEOD) {
573 Dmsg2(dbglevel+1, "fsf %i <= %i\n", current_file, last_file);
575 if (next_FM > cur_FM) { /* not the last file */
576 lseek(fd, next_FM, SEEK_SET);
577 read_fm(VT_READ_EOF);
582 } else if (atEOF) { /* last file mark */
588 } else { /* last file, but no at the end */
591 Dmsg0(dbglevel, "Try to FSF after EOT\n");
593 current_file = last_file ;
601 /* /------------\ /---------------\
602 * +---+------+---+---------------+-+
604 * +---+------+---+---------------+-+
607 bool vtape::read_fm(VT_READ_FM_MODE read_all)
611 if (read_all == VT_READ_EOF) {
612 ::read(fd, &c, sizeof(c));
614 lseek(fd, cur_FM, SEEK_SET);
619 cur_FM = lseek(fd, 0, SEEK_CUR) - sizeof(c);
621 ::read(fd, &last_FM, sizeof(last_FM));
622 ret = ::read(fd, &next_FM, sizeof(next_FM));
626 Dmsg3(dbglevel, "Read FM cur=%lli last=%lli next=%lli\n",
627 cur_FM, last_FM, next_FM);
629 return (ret == sizeof(next_FM));
633 * TODO: Check fsr with EOF
635 int vtape::fsr(int count)
638 ASSERT(current_file >= 0);
644 Dmsg4(dbglevel, "fsr %i:%i EOF=%i c=%i\n",
645 current_file,current_block,atEOF,count);
660 atBOT = atEOF = false;
662 /* check all block record */
663 for(i=0; (i < count) && !atEOF ; i++) {
664 nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
665 if (nb == sizeof(uint32_t) && s) {
667 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
669 Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
670 current_file, current_block, nb,s);
675 read_fm(VT_SKIP_EOF);
677 atEOF = true; /* stop the loop */
685 * BSR + EOF => begin of EOF + EIO
686 * BSR + BSR + EOF => last block
689 int vtape::bsr(int count)
692 ASSERT(current_file >= 0);
706 off_t last=-1, last2=-1;
707 off_t orig = lseek(fd, 0, SEEK_CUR);
708 int orig_f = current_file;
709 int orig_b = current_block;
711 Dmsg4(dbglevel, "bsr(%i) cur_blk=%i orig=%lli cur_FM=%lli\n",
712 count, current_block, orig, cur_FM);
714 /* begin of tape, do nothing */
720 /* at EOF 0:-1 BOT=0 EOD=0 EOF=0 ERR: Input/output error */
722 lseek(fd, cur_FM, SEEK_SET);
724 if (current_file > 0) {
733 * First, go to cur/last_FM and read all blocks to find the good one
735 if (cur_FM == orig) { /* already just before EOF */
736 lseek(fd, last_FM, SEEK_SET);
739 lseek(fd, cur_FM, SEEK_SET);
742 ret = read_fm(VT_READ_EOF);
746 last2 = last; /* keep track of the 2 last blocs position */
747 last = lseek(fd, 0, SEEK_CUR);
748 last_f = current_file;
749 last_b = current_block;
750 Dmsg6(dbglevel, "EOF=%i last2=%lli last=%lli < orig=%lli %i:%i\n",
751 atEOF, last2, last, orig, current_file, current_block);
754 } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
756 if (last2 > 0 && atEOF) { /* we take the previous position */
757 lseek(fd, last2, SEEK_SET);
758 current_file = last_f;
759 current_block = last_b - 1;
760 Dmsg3(dbglevel, "1 set offset2=%lli %i:%i\n",
761 last, current_file, current_block);
763 } else if (last > 0) {
764 lseek(fd, last, SEEK_SET);
765 current_file = last_f;
766 current_block = last_b;
767 Dmsg3(dbglevel, "2 set offset=%lli %i:%i\n",
768 last, current_file, current_block);
770 lseek(fd, orig, SEEK_SET);
771 current_file = orig_f;
772 current_block = orig_b;
776 Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
778 atEOT = atEOF = atEOD = false;
779 atBOT = (lseek(fd, 0, SEEK_CUR) - (sizeof(uint32_t)+2*sizeof(off_t))) == 0;
782 current_block = orig_b;
788 /* BSF => just before last EOF
789 * EOF + BSF => just before EOF
790 * file 0 + BSF => BOT + errno
795 ASSERT(current_file >= 0);
796 Dmsg2(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block);
801 atBOT = atEOF = atEOT = atEOD = false;
803 if (current_file == 0) {/* BOT + errno */
804 lseek(fd, 0, SEEK_SET);
805 read_fm(VT_READ_EOF);
812 Dmsg1(dbglevel, "bsf last=%lli\n", last_FM);
813 lseek(fd, cur_FM, SEEK_SET);
821 * Put vtape in offline mode
827 atEOF = false; /* End of file */
828 atEOT = false; /* End of tape */
829 atEOD = false; /* End of data */
830 atBOT = false; /* Begin of tape */
840 /* A filemark is automatically written to tape if the last tape operation
841 * before close was a write.
852 * When a filemark is encountered while reading, the following happens. If
853 * there are data remaining in the buffer when the filemark is found, the
854 * buffered data is returned. The next read returns zero bytes. The following
855 * read returns data from the next file. The end of recorded data is sig‐
856 * naled by returning zero bytes for two consecutive read calls. The third
857 * read returns an error.
859 int vtape::read(void *buffer, unsigned int count)
862 ASSERT(current_file >= 0);
866 Dmsg2(dbglevel*2, "read %i:%i\n", current_file, current_block);
868 if (atEOT || atEOD) {
885 atEOD = atBOT = false;
887 /* reading size of data */
888 nb = ::read(fd, &s, sizeof(uint32_t));
890 atEOF = true; /* TODO: check this */
894 if (s > count) { /* not enough buffer to read block */
895 Dmsg2(dbglevel, "Need more buffer to read next block %i > %i\n",s,count);
896 lseek(fd, s, SEEK_CUR);
903 if (read_fm(VT_SKIP_EOF)) {
910 /* reading data itself */
911 nb = ::read(fd, buffer, s);
912 if (s != nb) { /* read error */
916 Dmsg0(dbglevel, "EOT during reading\n");
920 if (current_block >= 0) {
927 int vtape::open(const char *pathname, int uflags)
929 Dmsg2(dbglevel, "vtape::open(%s, %i)\n", pathname, uflags);
931 online = true; /* assume that drive contains a tape */
934 if (stat(pathname, &statp) != 0) {
935 Dmsg1(dbglevel, "Can't stat on %s\n", pathname);
936 if (uflags & O_NONBLOCK) {
938 fd = ::open("/dev/null", O_CREAT | O_RDWR | O_LARGEFILE, 0600);
941 fd = ::open(pathname, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
952 cur_FM = next_FM = last_FM = 0;
955 atEOT = atEOD = false;
957 /* If the vtape is empty, start by writing a EOF */
958 if (online && !read_fm(VT_READ_EOF)) {
960 last_file = current_file=0;
966 /* use this to track file usage */
967 void vtape::update_pos()
971 if (fstat(fd, &statp) == 0) {
972 file_block = statp.st_blocks;
975 Dmsg1(dbglevel+1, "update_pos=%i\n", file_block);
977 if (file_block > max_block) {
986 Dmsg0(dbglevel+1, "===================\n");
987 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
988 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
989 Dmsg1(dbglevel+1, "file_block=%i\n", file_block);
990 Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n",
991 atEOF, atEOT, atEOD, atBOT);