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 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
70 vtape *ftape_list[FTAPE_MAX_DRIVE];
72 static vtape *get_tape(int fd)
76 if (fd >= FTAPE_MAX_DRIVE) {
81 return ftape_list[fd];
84 static bool put_tape(vtape *ftape)
86 ASSERT(ftape != NULL);
88 int fd = ftape->get_fd();
89 if (fd >= FTAPE_MAX_DRIVE) {
93 ftape_list[fd] = ftape;
97 void vtape_debug(int level)
102 /****************************************************************/
103 /* theses function will replace open/read/write/close/ioctl
106 int vtape_open(const char *pathname, int flags, ...)
108 ASSERT(pathname != NULL);
111 vtape *tape = new vtape();
112 fd = tape->open(pathname, flags);
119 ssize_t vtape_read(int fd, void *buffer, size_t count)
121 vtape *tape = get_tape(fd);
122 ASSERT(tape != NULL);
123 return tape->read(buffer, count);
126 ssize_t vtape_write(int fd, const void *buffer, size_t count)
128 vtape *tape = get_tape(fd);
129 ASSERT(tape != NULL);
130 return tape->write(buffer, count);
133 int vtape_close(int fd)
135 vtape *tape = get_tape(fd);
136 ASSERT(tape != NULL);
142 int vtape_ioctl(int fd, ioctl_req_t request, ...)
147 vtape *t = get_tape(fd);
153 va_start(argp, request);
155 if (request == MTIOCTOP) {
156 result = t->tape_op(va_arg(argp, mtop *));
157 } else if (request == MTIOCGET) {
158 result = t->tape_get(va_arg(argp, mtget *));
159 } else if (request == MTIOCPOS) {
160 result = t->tape_pos(va_arg(argp, mtpos *));
170 int vtape::tape_op(struct mtop *mt_com)
173 int count = mt_com->mt_count;
180 switch (mt_com->mt_op)
196 case MTFSF: /* Forward space over mt_count filemarks. */
199 } while (--count > 0 && result == 0);
202 case MTBSF: /* Backward space over mt_count filemarks. */
205 } while (--count > 0 && result == 0);
208 case MTFSR: /* Forward space over mt_count records (tape blocks). */
216 mt: /dev/lto2: Erreur d'entree/sortie
221 /* tester si on se trouve a la fin du fichier */
222 result = fsr(mt_com->mt_count);
225 case MTBSR: /* Backward space over mt_count records (tape blocks). */
226 result = bsr(mt_com->mt_count);
229 case MTWEOF: /* Write mt_count filemarks. */
232 } while (result == 0 && --count > 0);
235 case MTREW: /* Rewind. */
236 Dmsg0(dbglevel, "rewind vtape\n");
238 atEOF = atEOD = false;
242 lseek(fd, 0, SEEK_SET);
243 result = !read_fm(VT_READ_EOF);
246 case MTOFFL: /* put tape offline */
250 case MTRETEN: /* Re-tension tape. */
254 case MTBSFM: /* not used by bacula */
259 case MTFSFM: /* not used by bacula */
264 case MTEOM:/* Go to the end of the recorded media (for appending files). */
266 lseek(fd, next_FM, SEEK_SET);
267 if (read_fm(VT_READ_EOF)) {
272 while (::read(fd, &l, sizeof(l)) > 0) {
274 lseek(fd, l, SEEK_CUR);
278 Dmsg0(dbglevel, "skip 1 block\n");
291 case MTERASE: /* not used by bacula */
298 lseek(fd, 0, SEEK_SET);
299 read_fm(VT_READ_EOF);
343 return result == 0 ? 0 : -1;
346 int vtape::tape_get(struct mtget *mt_get)
349 int block_size = 1024;
351 mt_get->mt_type = MT_ISSCSI2;
352 mt_get->mt_blkno = current_block;
353 mt_get->mt_fileno = current_file;
355 mt_get->mt_resid = -1;
356 // pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
360 ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
361 ((block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
364 mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
367 mt_get->mt_gstat |= 0x80000000; // GMT_EOF
371 mt_get->mt_gstat |= 0x40000000; // GMT_BOT
374 mt_get->mt_gstat |= 0x20000000; // GMT_EOT
378 mt_get->mt_gstat |= 0x08000000; // GMT_EOD
381 if (0) { //WriteProtected) {
382 mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
386 mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
388 mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
390 mt_get->mt_erreg = 0;
395 int vtape::tape_pos(struct mtpos *mt_pos)
397 if (current_block >= 0) {
398 mt_pos->mt_blkno = current_block;
406 * This function try to emulate the append only behavior
407 * of a tape. When you wrote something, data after the
408 * current position are discarded.
410 int vtape::truncate_file()
412 Dmsg2(dbglevel, "truncate %i:%i\n", current_file, current_block);
413 ftruncate(fd, lseek(fd, 0, SEEK_CUR));
414 last_file = current_file;
436 max_block = VTAPE_MAX_BLOCK;
449 * Write a variable block of count size.
450 * block = vtape_header + data
451 * vtape_header = sizeof(data)
452 * if vtape_header == 0, this is a EOF
454 ssize_t vtape::write(const void *buffer, size_t count)
457 ASSERT(current_file >= 0);
462 Dmsg3(dbglevel*2, "write len=%i %i:%i\n",
463 count, current_file,current_block);
466 Dmsg0(dbglevel, "write nothing, EOT !\n");
471 if (!atEOD) { /* if not at the end of the data */
475 if (current_block != -1) {
481 atEOD = true; /* End of data */
483 needEOF = true; /* next operation need EOF mark */
485 uint32_t size = count;
486 ::write(fd, &size, sizeof(uint32_t));
487 nb = ::write(fd, buffer, count);
489 if (nb != (ssize_t)count) {
492 "Not enough space writing only %i of %i requested\n",
502 * +---+---------+---+------------------+---+-------------------+
503 * |00N| DATA |0LN| DATA |0LC| DATA |
504 * +---+---------+---+------------------+---+-------------------+
507 * L : Last FileMark offset
508 * N : Next FileMark offset
509 * C : Current FileMark Offset
514 ASSERT(current_file >= 0);
523 truncate_file(); /* nothing after this point */
527 cur_FM = lseek(fd, 0, SEEK_CUR); // current position
529 /* update previous next_FM */
530 lseek(fd, last_FM + sizeof(uint32_t)+sizeof(boffset_t), SEEK_SET);
531 ::write(fd, &cur_FM, sizeof(boffset_t));
532 lseek(fd, cur_FM, SEEK_SET);
537 ::write(fd, &c, sizeof(uint32_t)); // EOF
538 ::write(fd, &last_FM, sizeof(last_FM)); // F-1
539 ::write(fd, &next_FM, sizeof(next_FM)); // F (will be updated next time)
549 last_file = MAX(current_file, last_file);
551 Dmsg4(dbglevel, "Writing EOF %i:%i last=%lli cur=%lli next=0\n",
552 current_file, current_block, last_FM, cur_FM);
563 ASSERT(current_file >= 0);
566 * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
570 if (atEOT || atEOD) {
577 Dmsg2(dbglevel+1, "fsf %i <= %i\n", current_file, last_file);
579 if (next_FM > cur_FM) { /* not the last file */
580 lseek(fd, next_FM, SEEK_SET);
581 read_fm(VT_READ_EOF);
586 } else if (atEOF) { /* last file mark */
592 } else { /* last file, but no at the end */
595 Dmsg0(dbglevel, "Try to FSF after EOT\n");
597 current_file = last_file ;
605 /* /------------\ /---------------\
606 * +---+------+---+---------------+-+
608 * +---+------+---+---------------+-+
611 bool vtape::read_fm(VT_READ_FM_MODE read_all)
615 if (read_all == VT_READ_EOF) {
616 ::read(fd, &c, sizeof(c));
618 lseek(fd, cur_FM, SEEK_SET);
623 cur_FM = lseek(fd, 0, SEEK_CUR) - sizeof(c);
625 ::read(fd, &last_FM, sizeof(last_FM));
626 ret = ::read(fd, &next_FM, sizeof(next_FM));
630 Dmsg3(dbglevel, "Read FM cur=%lli last=%lli next=%lli\n",
631 cur_FM, last_FM, next_FM);
633 return (ret == sizeof(next_FM));
637 * TODO: Check fsr with EOF
639 int vtape::fsr(int count)
642 ASSERT(current_file >= 0);
648 Dmsg4(dbglevel, "fsr %i:%i EOF=%i c=%i\n",
649 current_file,current_block,atEOF,count);
664 atBOT = atEOF = false;
666 /* check all block record */
667 for(i=0; (i < count) && !atEOF ; i++) {
668 nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
669 if (nb == sizeof(uint32_t) && s) {
671 where = lseek(fd, s, SEEK_CUR); /* seek after this block */
673 Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
674 current_file, current_block, nb,s);
679 read_fm(VT_SKIP_EOF);
681 atEOF = true; /* stop the loop */
689 * BSR + EOF => begin of EOF + EIO
690 * BSR + BSR + EOF => last block
693 int vtape::bsr(int count)
696 ASSERT(current_file >= 0);
710 boffset_t last=-1, last2=-1;
711 boffset_t orig = lseek(fd, 0, SEEK_CUR);
712 int orig_f = current_file;
713 int orig_b = current_block;
715 Dmsg4(dbglevel, "bsr(%i) cur_blk=%i orig=%lli cur_FM=%lli\n",
716 count, current_block, orig, cur_FM);
718 /* begin of tape, do nothing */
724 /* at EOF 0:-1 BOT=0 EOD=0 EOF=0 ERR: Input/output error */
726 lseek(fd, cur_FM, SEEK_SET);
728 if (current_file > 0) {
737 * First, go to cur/last_FM and read all blocks to find the good one
739 if (cur_FM == orig) { /* already just before EOF */
740 lseek(fd, last_FM, SEEK_SET);
743 lseek(fd, cur_FM, SEEK_SET);
746 ret = read_fm(VT_READ_EOF);
750 last2 = last; /* keep track of the 2 last blocs position */
751 last = lseek(fd, 0, SEEK_CUR);
752 last_f = current_file;
753 last_b = current_block;
754 Dmsg6(dbglevel, "EOF=%i last2=%lli last=%lli < orig=%lli %i:%i\n",
755 atEOF, last2, last, orig, current_file, current_block);
758 } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
760 if (last2 > 0 && atEOF) { /* we take the previous position */
761 lseek(fd, last2, SEEK_SET);
762 current_file = last_f;
763 current_block = last_b - 1;
764 Dmsg3(dbglevel, "1 set offset2=%lli %i:%i\n",
765 last, current_file, current_block);
767 } else if (last > 0) {
768 lseek(fd, last, SEEK_SET);
769 current_file = last_f;
770 current_block = last_b;
771 Dmsg3(dbglevel, "2 set offset=%lli %i:%i\n",
772 last, current_file, current_block);
774 lseek(fd, orig, SEEK_SET);
775 current_file = orig_f;
776 current_block = orig_b;
780 Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
782 atEOT = atEOF = atEOD = false;
783 atBOT = (lseek(fd, 0, SEEK_CUR) - (sizeof(uint32_t)+2*sizeof(boffset_t))) == 0;
786 current_block = orig_b;
792 /* BSF => just before last EOF
793 * EOF + BSF => just before EOF
794 * file 0 + BSF => BOT + errno
799 ASSERT(current_file >= 0);
800 Dmsg2(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block);
805 atBOT = atEOF = atEOT = atEOD = false;
807 if (current_file == 0) {/* BOT + errno */
808 lseek(fd, 0, SEEK_SET);
809 read_fm(VT_READ_EOF);
816 Dmsg1(dbglevel, "bsf last=%lli\n", last_FM);
817 lseek(fd, cur_FM, SEEK_SET);
825 * Put vtape in offline mode
831 atEOF = false; /* End of file */
832 atEOT = false; /* End of tape */
833 atEOD = false; /* End of data */
834 atBOT = false; /* Begin of tape */
844 /* A filemark is automatically written to tape if the last tape operation
845 * before close was a write.
856 * When a filemark is encountered while reading, the following happens. If
857 * there are data remaining in the buffer when the filemark is found, the
858 * buffered data is returned. The next read returns zero bytes. The following
859 * read returns data from the next file. The end of recorded data is signaled
860 * by returning zero bytes for two consecutive read calls. The third read
863 ssize_t vtape::read(void *buffer, size_t count)
866 ASSERT(current_file >= 0);
870 Dmsg2(dbglevel*2, "read %i:%i\n", current_file, current_block);
872 if (atEOT || atEOD) {
889 atEOD = atBOT = false;
891 /* reading size of data */
892 nb = ::read(fd, &s, sizeof(uint32_t));
894 atEOF = true; /* TODO: check this */
898 if (s > count) { /* not enough buffer to read block */
899 Dmsg2(dbglevel, "Need more buffer to read next block %i > %i\n",s,count);
900 lseek(fd, s, SEEK_CUR);
907 if (read_fm(VT_SKIP_EOF)) {
914 /* reading data itself */
915 nb = ::read(fd, buffer, s);
916 if (nb != (ssize_t)s) { /* read error */
920 Dmsg0(dbglevel, "EOT during reading\n");
924 if (current_block >= 0) {
931 int vtape::open(const char *pathname, int uflags)
933 Dmsg2(dbglevel, "vtape::open(%s, %i)\n", pathname, uflags);
935 online = true; /* assume that drive contains a tape */
938 if (stat(pathname, &statp) != 0) {
940 Dmsg1(dbglevel, "Can't stat on %s\n", pathname);
941 if (uflags & O_NONBLOCK) {
943 fd = ::open("/dev/null", O_CREAT | O_RDWR | O_LARGEFILE, 0600);
946 fd = ::open(pathname, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
957 cur_FM = next_FM = last_FM = 0;
960 atEOT = atEOD = false;
962 /* If the vtape is empty, start by writing a EOF */
963 if (online && !read_fm(VT_READ_EOF)) {
964 lseek(fd, 0, SEEK_SET); /* rewind */
965 cur_FM = next_FM = last_FM = 0; /* reset */
966 weof(); /* write the first EOF */
967 last_file = current_file=0;
973 /* use this to track file usage */
974 void vtape::update_pos()
978 if (fstat(fd, &statp) == 0) {
979 file_block = statp.st_blocks;
982 Dmsg1(dbglevel*2, "update_pos=%i\n", file_block);
984 if (file_block > max_block) {
993 Dmsg0(dbglevel+1, "===================\n");
994 Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
995 Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
996 Dmsg1(dbglevel+1, "file_block=%i\n", file_block);
997 Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n",
998 atEOF, atEOT, atEOD, atBOT);
1001 #else /* USE_VTAPE */
1003 int vtape_ioctl(int fd, ioctl_req_t request, ...)
1008 int vtape_open(const char *pathname, int flags, ...)
1013 int vtape_close(int fd)
1018 void vtape_debug(int level)
1022 ssize_t vtape_read(int fd, void *buffer, size_t count)
1027 ssize_t vtape_write(int fd, const void *buffer, size_t count)
1032 #endif /* ! USE_VTAPE */