]> git.sur5r.net Git - bacula/bacula/commitdiff
ebl rename faketape to vtape
authorEric Bollengier <eric@eb.homelinux.org>
Mon, 9 Jun 2008 20:50:15 +0000 (20:50 +0000)
committerEric Bollengier <eric@eb.homelinux.org>
Mon, 9 Jun 2008 20:50:15 +0000 (20:50 +0000)
git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@7124 91ce42f0-d328-0410-95d8-f526ca767f89

bacula/src/stored/Makefile.in
bacula/src/stored/btape.c
bacula/src/stored/dev.c
bacula/src/stored/dev.h
bacula/src/stored/faketape.c [deleted file]
bacula/src/stored/faketape.h [deleted file]
bacula/src/stored/stored.h
bacula/src/stored/stored_conf.c
bacula/src/stored/vtape.c [new file with mode: 0644]
bacula/src/stored/vtape.h [new file with mode: 0644]
bacula/technotes-2.5

index d2e7ae8bb159ec778eae84363e937190a85b929f..1b217f7abfaa0c266ca0a4731dac4ae5b433a054 100644 (file)
@@ -20,7 +20,7 @@ first_rule: all
 dummy:
 
 # bacula-sd
-SDOBJS =  stored.o ansi_label.o faketape.o \
+SDOBJS =  stored.o ansi_label.o vtape.o \
          autochanger.o acquire.o append.o \
          askdir.o authenticate.o \
          block.o butil.o dev.o \
@@ -31,33 +31,33 @@ SDOBJS =  stored.o ansi_label.o faketape.o \
          spool.o status.o stored_conf.o wait.o
 
 # btape
-TAPEOBJS = btape.o block.o butil.o dev.o device.o label.o faketape.o \
+TAPEOBJS = btape.o block.o butil.o dev.o device.o label.o vtape.o \
           lock.o ansi_label.o dvd.o ebcdic.o \
           autochanger.o acquire.o mount.o record.o read_record.o \
           reserve.o \
           stored_conf.o match_bsr.o parse_bsr.o scan.o spool.o wait.o
 
 # bls
-BLSOBJS = bls.o block.o butil.o device.o dev.o label.o match_bsr.o faketape.o \
+BLSOBJS = bls.o block.o butil.o device.o dev.o label.o match_bsr.o vtape.o \
          ansi_label.o dvd.o ebcdic.o lock.o \
          autochanger.o acquire.o mount.o parse_bsr.o record.o  \
          read_record.o reserve.o scan.o stored_conf.o spool.o wait.o
 
 # bextract
-BEXTOBJS = bextract.o block.o device.o dev.o label.o record.o faketape.o \
+BEXTOBJS = bextract.o block.o device.o dev.o label.o record.o vtape.o \
           ansi_label.o dvd.o ebcdic.o lock.o \
           autochanger.o acquire.o mount.o match_bsr.o parse_bsr.o butil.o \
           pythonsd.o read_record.o reserve.o \
           scan.o stored_conf.o spool.o wait.o
 
 # bscan
-SCNOBJS = bscan.o block.o device.o dev.o label.o faketape.o \
+SCNOBJS = bscan.o block.o device.o dev.o label.o vtape.o \
          ansi_label.o dvd.o ebcdic.o lock.o \
          autochanger.o acquire.o mount.o record.o match_bsr.o parse_bsr.o \
          butil.o read_record.o scan.o reserve.o stored_conf.o spool.o wait.o
 
 # bcopy
-COPYOBJS = bcopy.o block.o device.o dev.o label.o faketape.o \
+COPYOBJS = bcopy.o block.o device.o dev.o label.o vtape.o \
           ansi_label.o dvd.o ebcdic.o lock.o \
           autochanger.o acquire.o mount.o record.o match_bsr.o parse_bsr.o \
           butil.o read_record.o reserve.o \
index 2aaaad2b58984b663c1d5d3f484648c98b1a0d6a..95ecfc43e175ca4308d15135cad3b4dfae87a969 100644 (file)
@@ -44,8 +44,8 @@
 #include "bacula.h"
 #include "stored.h"
 
-#ifdef USE_FAKETAPE
-#include "faketape.h"
+#ifdef USE_VTAPE
+#include "vtape.h"
 #endif
 
 /* Dummy functions */
index b09c33dbcd45712c1d10a0d562e03e6c15409570..793a7a274095e46d94b657460b9a96ff38b5e73e 100644 (file)
@@ -127,12 +127,12 @@ init_dev(JCR *jcr, DEVRES *device)
          device->dev_type = B_TAPE_DEV;
       } else if (S_ISFIFO(statp.st_mode)) {
          device->dev_type = B_FIFO_DEV;
-#ifdef USE_FAKETAPE
+#ifdef USE_VTAPE
       /* must set DeviceType = Faketape 
        * in normal mode, autodetection is disabled
        */
       } else if (S_ISREG(statp.st_mode)) { 
-         device->dev_type = B_FAKETAPE_DEV;
+         device->dev_type = B_VTAPE_DEV;
 #endif
       } else if (!(device->cap_bits & CAP_REQMOUNT)) {
          Jmsg2(jcr, M_ERROR, 0, _("%s is an unknown device type. Must be tape or directory\n"
@@ -275,12 +275,12 @@ init_dev(JCR *jcr, DEVRES *device)
 /* Choose the right backend */
 void DEVICE::init_backend()
 {
-   if (is_faketape()) {
-      d_open  = faketape_open;
-      d_write = faketape_write;
-      d_close = faketape_close;
-      d_ioctl = faketape_ioctl;
-      d_read  = faketape_read;
+   if (is_vtape()) {
+      d_open  = vtape_open;
+      d_write = vtape_write;
+      d_close = vtape_close;
+      d_ioctl = vtape_ioctl;
+      d_read  = vtape_read;
 
 #ifdef HAVE_WIN32
    } else if (is_tape()) {
@@ -1890,7 +1890,7 @@ void DEVICE::close()
 
    switch (dev_type) {
    case B_VTL_DEV:
-   case B_FAKETAPE_DEV:
+   case B_VTAPE_DEV:
    case B_TAPE_DEV:
       unlock_door(); 
    default:
@@ -1964,7 +1964,7 @@ bool DEVICE::truncate(DCR *dcr) /* We need the DCR for DVD-writing */
    Dmsg1(100, "truncate %s\n", print_name());
    switch (dev_type) {
    case B_VTL_DEV:
-   case B_FAKETAPE_DEV:
+   case B_VTAPE_DEV:
    case B_TAPE_DEV:
       /* maybe we should rewind and write and eof ???? */
       return true;                    /* we don't really truncate tapes */
index 9d022184408efeb35c45561869a163948b5d7f63..0bf6682ca01e4272ba2b7b7989a7ebd8721b8307 100644 (file)
@@ -95,7 +95,7 @@ enum {
    B_TAPE_DEV,
    B_DVD_DEV,
    B_FIFO_DEV,
-   B_FAKETAPE_DEV,             /* change to B_TAPE_DEV after init */
+   B_VTAPE_DEV,                /* change to B_TAPE_DEV after init */
    B_VTL_DEV
 };
 
@@ -309,12 +309,12 @@ public:
    int requires_mount() const { return capabilities & CAP_REQMOUNT; }
    int is_removable() const { return capabilities & CAP_REM; }
    int is_tape() const { return (dev_type == B_TAPE_DEV || 
-                                 dev_type == B_FAKETAPE_DEV); }
+                                 dev_type == B_VTAPE_DEV); }
    int is_file() const { return dev_type == B_FILE_DEV; }
    int is_fifo() const { return dev_type == B_FIFO_DEV; }
    int is_dvd() const  { return dev_type == B_DVD_DEV; }
    int is_vtl() const  { return dev_type == B_VTL_DEV; }
-   int is_faketape() const  { return dev_type == B_FAKETAPE_DEV; }
+   int is_vtape() const  { return dev_type == B_VTAPE_DEV; }
    int is_open() const { return m_fd >= 0; }
    int is_offline() const { return state & ST_OFFLINE; }
    int is_labeled() const { return state & ST_LABEL; }
diff --git a/bacula/src/stored/faketape.c b/bacula/src/stored/faketape.c
deleted file mode 100644 (file)
index e2cef89..0000000
+++ /dev/null
@@ -1,993 +0,0 @@
-/*
-   Bacula® - The Network Backup Solution
-
-   Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
-
-   The main author of Bacula is Kern Sibbald, with contributions from
-   many others, a complete list can be found in the file AUTHORS.
-   This program is Free Software; you can redistribute it and/or
-   modify it under the terms of version two of the GNU General Public
-   License as published by the Free Software Foundation, which is 
-   listed in the file LICENSE.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-   Bacula® is a registered trademark of John Walker.
-   The licensor of Bacula is the Free Software Foundation Europe
-   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
-   Switzerland, email:ftf@fsfeurope.org.
-*/
-
-/*
-
-Device {
-  Name = Drive-1                      #
-  Maximum File Size = 800M
-  Maximum Volume Size = 3G
-  Device Type = TAPE
-  Archive Device = /tmp/fake
-  Media Type = DLT-8000
-  AutomaticMount = yes;               # when device opened, read it
-  AlwaysOpen = yes;
-  RemovableMedia = yes;
-  RandomAccess = no;
-}
-
-  Block description :
-
-  block {
-    int32  size;
-    void   *data;
-  }
-
-  EOF description :
-
-  EOF {
-    int32  size=0;
-  }
-
-
- */
-
-#include "bacula.h"             /* define 64bit file usage */
-#include "stored.h"
-
-#include "vtape.h"
-
-static int dbglevel = 100;
-#define FILE_OFFSET 30
-vtape *ftape_list[FTAPE_MAX_DRIVE];
-
-static vtape *get_tape(int fd)
-{
-   ASSERT(fd >= 0);
-
-   if (fd >= FTAPE_MAX_DRIVE) {
-      /* error */
-      return NULL;
-   }
-
-   return ftape_list[fd];
-}
-
-static bool put_tape(vtape *ftape)
-{
-   ASSERT(ftape != NULL);
-
-   int fd = ftape->get_fd();
-   if (fd >= FTAPE_MAX_DRIVE) {
-      /* error */
-      return false;
-   }
-   ftape_list[fd] = ftape;
-   return true;
-}
-
-void vtape_debug(int level)
-{
-   dbglevel = level;
-}
-
-/****************************************************************/
-/* theses function will replace open/read/write/close/ioctl
- * in bacula core
- */
-int vtape_open(const char *pathname, int flags, ...)
-{
-   ASSERT(pathname != NULL);
-
-   int fd;
-   vtape *tape = new vtape();
-   fd = tape->open(pathname, flags);
-   if (fd > 0) {
-      put_tape(tape);
-   }
-   return fd;
-}
-
-int vtape_read(int fd, void *buffer, unsigned int count)
-{
-   vtape *tape = get_tape(fd);
-   ASSERT(tape != NULL);
-   return tape->read(buffer, count);
-}
-
-int vtape_write(int fd, const void *buffer, unsigned int count)
-{
-   vtape *tape = get_tape(fd);
-   ASSERT(tape != NULL);
-   return tape->write(buffer, count);
-}
-
-int vtape_close(int fd)
-{
-   vtape *tape = get_tape(fd);
-   ASSERT(tape != NULL);
-   tape->close();
-   delete tape;
-   return 0;
-}
-
-int vtape_ioctl(int fd, unsigned long int request, ...)
-{
-   va_list argp;
-   int result=0;
-
-   vtape *t = get_tape(fd);
-   if (!t) {
-      errno = EBADF;
-      return -1;
-   }
-
-   va_start(argp, request);
-
-   if (request == MTIOCTOP) {
-      result = t->tape_op(va_arg(argp, mtop *));
-   } else if (request == MTIOCGET) {
-      result = t->tape_get(va_arg(argp, mtget *));
-   } else if (request == MTIOCPOS) {
-      result = t->tape_pos(va_arg(argp, mtpos *));
-   } else {
-      errno = ENOTTY;
-      result = -1;
-   }
-   va_end(argp);
-
-   return result;
-}
-
-/****************************************************************/
-
-int vtape::tape_op(struct mtop *mt_com)
-{
-   int result=0;
-   int count = mt_com->mt_count;
-
-   if (!online) {
-      errno = ENOMEDIUM;
-      return -1;
-   }
-   
-   switch (mt_com->mt_op)
-   {
-   case MTRESET:
-   case MTNOP:
-   case MTSETDRVBUFFER:
-      break;
-
-   default:
-   case MTRAS1:
-   case MTRAS2:
-   case MTRAS3:
-   case MTSETDENSITY:
-      errno = ENOTTY;
-      result = -1;
-      break;
-
-   case MTFSF:                  /* Forward space over mt_count filemarks. */
-      do {
-        result = fsf();
-      } while (--count > 0 && result == 0);
-      break;
-
-   case MTBSF:                  /* Backward space over mt_count filemarks. */
-      do {
-        result = bsf();
-      } while (--count > 0 && result == 0);
-      break;
-
-   case MTFSR:      /* Forward space over mt_count records (tape blocks). */
-/*
-    file number = 1
-    block number = 0
-   
-    file number = 1
-    block number = 1
-   
-    mt: /dev/lto2: Erreur d'entree/sortie
-   
-    file number = 2
-    block number = 0
-*/
-      /* tester si on se trouve a la fin du fichier */
-      result = fsr(mt_com->mt_count);
-      break;
-
-   case MTBSR:      /* Backward space over mt_count records (tape blocks). */
-      result = bsr(mt_com->mt_count);
-      break;
-
-   case MTWEOF:                 /* Write mt_count filemarks. */
-      do {
-        result = weof();
-      } while (result == 0 && --count > 0);
-      break;
-
-   case MTREW:                  /* Rewind. */
-      Dmsg0(dbglevel, "rewind vtape\n");
-      check_eof();
-      atEOF = atEOD = false;
-      atBOT = true;
-      current_file = 0;
-      current_block = 0;
-      lseek(fd, 0, SEEK_SET);
-      result = !read_fm(VT_READ_EOF);
-      break;
-
-   case MTOFFL:                 /* put tape offline */
-      result = offline();
-      break;
-
-   case MTRETEN:                /* Re-tension tape. */
-      result = 0;
-      break;
-
-   case MTBSFM:                 /* not used by bacula */
-      errno = EIO;
-      result = -1;
-      break;
-
-   case MTFSFM:                 /* not used by bacula */
-      errno = EIO;
-      result = -1;
-      break;
-
-   case MTEOM:/* Go to the end of the recorded media (for appending files). */
-      while (next_FM) {
-        lseek(fd, next_FM, SEEK_SET);
-        if (read_fm(VT_READ_EOF)) {
-           current_file++;
-        }
-      }
-      off_t l;
-      while (::read(fd, &l, sizeof(l)) > 0) {
-        if (l) {
-           lseek(fd, l, SEEK_CUR);
-        } else {
-           ASSERT(0);
-        }
-        Dmsg0(dbglevel, "skip 1 block\n");
-      }
-      current_block = -1;
-      atEOF = false;
-      atEOD = true;
-
-/*
-   file number = 3
-   block number = -1
-*/
-      /* Can be at EOM */
-      break;
-
-   case MTERASE:                /* not used by bacula */
-      atEOD = true;
-      atEOF = false;
-      atEOT = false;
-
-      current_file = 0;
-      current_block = -1;
-      lseek(fd, 0, SEEK_SET);
-      read_fm(VT_READ_EOF);
-      truncate_file();
-      break;
-
-   case MTSETBLK:
-      break;
-
-   case MTSEEK:
-      break;
-
-   case MTTELL:
-      break;
-
-   case MTFSS:
-      break;
-
-   case MTBSS:
-      break;
-
-   case MTWSM:
-      break;
-
-   case MTLOCK:
-      break;
-
-   case MTUNLOCK:
-      break;
-
-   case MTLOAD:
-      break;
-
-   case MTUNLOAD:
-      break;
-
-   case MTCOMPRESSION:
-      break;
-
-   case MTSETPART:
-      break;
-
-   case MTMKPART:
-      break;
-   }
-
-   return result == 0 ? 0 : -1;
-}
-
-int vtape::tape_get(struct mtget *mt_get)
-{
-   int density = 1;
-   int block_size = 1024;
-
-   mt_get->mt_type = MT_ISSCSI2;
-   mt_get->mt_blkno = current_block;
-   mt_get->mt_fileno = current_file;
-
-   mt_get->mt_resid = -1;
-//   pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
-
-   /* TODO */
-   mt_get->mt_dsreg = 
-      ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
-      ((block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
-
-
-   mt_get->mt_gstat = 0x00010000;  /* Immediate report mode.*/
-
-   if (atEOF) {
-      mt_get->mt_gstat |= 0x80000000;     // GMT_EOF
-   }
-
-   if (atBOT) {
-      mt_get->mt_gstat |= 0x40000000;     // GMT_BOT
-   }
-   if (atEOT) {
-      mt_get->mt_gstat |= 0x20000000;     // GMT_EOT
-   }
-
-   if (atEOD) {
-      mt_get->mt_gstat |= 0x08000000;     // GMT_EOD
-   }
-
-   if (0) { //WriteProtected) {
-      mt_get->mt_gstat |= 0x04000000;     // GMT_WR_PROT
-   }
-
-   if (online) {
-      mt_get->mt_gstat |= 0x01000000;     // GMT_ONLINE
-   } else {
-      mt_get->mt_gstat |= 0x00040000;  // GMT_DR_OPEN
-   }
-   mt_get->mt_erreg = 0;
-
-   return 0;
-}
-
-int vtape::tape_pos(struct mtpos *mt_pos)
-{
-   if (current_block >= 0) {
-      mt_pos->mt_blkno = current_block;
-      return 0;
-   }
-
-   return -1;
-}
-
-/*
- * This function try to emulate the append only behavior
- * of a tape. When you wrote something, data after the
- * current position are discarded.
- */
-int vtape::truncate_file()
-{  
-   Dmsg2(dbglevel, "truncate %i:%i\n", current_file, current_block);
-   ftruncate(fd, lseek(fd, 0, SEEK_CUR));
-   last_file = current_file;
-   atEOD=true;
-   update_pos();
-   return 0;
-}
-
-vtape::vtape()
-{
-   fd = -1;
-
-   atEOF = false;
-   atBOT = false;
-   atEOT = false;
-   atEOD = false;
-   online = false;
-   needEOF = false;
-
-   file_block = 0;
-   last_file = 0;
-   current_file = 0;
-   current_block = -1;
-
-   max_block = 2*1024*2048;      /* 2GB */
-}
-
-vtape::~vtape()
-{
-}
-
-int vtape::get_fd()
-{
-   return this->fd;
-}
-
-/*
- * TODO: check if after a write op, and other tape op put a EOF
- */
-int vtape::write(const void *buffer, unsigned int count)
-{
-   ASSERT(online);
-   ASSERT(current_file >= 0);
-   ASSERT(count > 0);
-   ASSERT(buffer);
-
-   unsigned int nb;
-   Dmsg3(dbglevel*2, "write len=%i %i:%i\n", 
-        count, current_file,current_block);
-
-   if (atEOT) {
-      Dmsg0(dbglevel, "write nothing, EOT !\n");
-      errno = ENOSPC;
-      return -1;
-   }
-
-   if (!atEOD) {                /* if not at the end of the data */
-      truncate_file();
-   }
-   if (current_block != -1) {
-      current_block++;
-   }
-
-   atBOT = false;
-   atEOF = false;
-   atEOD = true;                /* End of data */
-
-   needEOF = true;              /* next operation need EOF mark */
-
-   uint32_t size = count;
-   ::write(fd, &size, sizeof(uint32_t));
-   nb = ::write(fd, buffer, count);
-   
-   if (nb != count) {
-      atEOT = true;
-      Dmsg2(dbglevel, 
-            "Not enough space writing only %i of %i requested\n", 
-            nb, count);
-   }
-
-   update_pos();
-
-   return nb;
-}
-
-/*
- *  +---+---------+---+------------------+---+-------------------+
- *  |00N|  DATA   |0LN|   DATA           |0LC|     DATA          |
- *  +---+---------+---+------------------+---+-------------------+
- *
- *  0 : zero
- *  L : Last FileMark offset
- *  N : Next FileMark offset
- *  C : Current FileMark Offset
- */
-int vtape::weof()
-{
-   ASSERT(online);
-   ASSERT(current_file >= 0);
-
-   if (atEOT) {
-      errno = ENOSPC;
-      current_block = -1;
-      return -1;
-   }
-
-   if (!atEOD) {
-      truncate_file();             /* nothing after this point */
-   }
-
-   last_FM = cur_FM;
-   cur_FM = lseek(fd, 0, SEEK_CUR); // current position
-   
-   /* update previous next_FM  */
-   lseek(fd, last_FM + sizeof(uint32_t)+sizeof(off_t), SEEK_SET);
-   ::write(fd, &cur_FM, sizeof(off_t));
-   lseek(fd, cur_FM, SEEK_SET);
-
-   next_FM = 0;
-
-   uint32_t c=0;
-   ::write(fd, &c,       sizeof(uint32_t)); // EOF
-   ::write(fd, &last_FM, sizeof(last_FM));  // F-1
-   ::write(fd, &next_FM, sizeof(next_FM));  // F   (will be updated next time)
-
-   current_file++;
-   current_block = 0;
-
-   needEOF = false;
-   atEOD = false;
-   atBOT = false;
-   atEOF = true;
-
-   last_file = MAX(current_file, last_file);
-
-   Dmsg4(dbglevel, "Writing EOF %i:%i last=%lli cur=%lli next=0\n", 
-         current_file, current_block, last_FM, cur_FM);
-
-   return 0;
-}
-
-/*
- * Go to next FM
- */
-int vtape::fsf()
-{   
-   ASSERT(online);
-   ASSERT(current_file >= 0);
-   ASSERT(fd >= 0);
-/*
- * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
- */
-
-   int ret=0;
-   if (atEOT || atEOD) {
-      errno = EIO;
-      current_block = -1;
-      return -1;
-   }
-
-   atBOT = false;
-   Dmsg2(dbglevel+1, "fsf %i <= %i\n", current_file, last_file);
-
-   if (next_FM > cur_FM) {     /* not the last file */
-      lseek(fd, next_FM, SEEK_SET);
-      read_fm(VT_READ_EOF);
-      current_file++;
-      atEOF = true;
-      ret = 0;
-
-   } else if (atEOF) {         /* last file mark */
-      current_block=-1;
-      errno = EIO;
-      atEOF = false;
-      atEOD = true;
-
-   } else {                    /* last file, but no at the end */
-      fsr(100000);
-
-      Dmsg0(dbglevel, "Try to FSF after EOT\n");
-      errno = EIO;
-      current_file = last_file ;
-      current_block = -1;
-      atEOD=true;
-      ret = -1;
-   }
-   return ret;
-}
-
-/* /------------\ /---------------\
- * +---+------+---+---------------+-+
- * |OLN|      |0LN|               | |
- * +---+------+---+---------------+-+
- */
-
-bool vtape::read_fm(VT_READ_FM_MODE read_all)
-{
-   int ret;
-   uint32_t c;
-   if (read_all == VT_READ_EOF) {
-      ::read(fd, &c, sizeof(c));
-      if (c != 0) {
-        lseek(fd, cur_FM, SEEK_SET);
-        return false;
-      }
-   }
-
-   cur_FM = lseek(fd, 0, SEEK_CUR) - sizeof(c);
-
-   ::read(fd, &last_FM, sizeof(last_FM));
-   ret = ::read(fd, &next_FM, sizeof(next_FM));
-
-   current_block=0;
-   
-   Dmsg3(dbglevel, "Read FM cur=%lli last=%lli next=%lli\n", 
-        cur_FM, last_FM, next_FM);
-
-   return (ret == sizeof(next_FM));
-}
-
-/*
- * TODO: Check fsr with EOF
- */
-int vtape::fsr(int count)
-{
-   ASSERT(online);
-   ASSERT(current_file >= 0);
-   ASSERT(fd >= 0);
-   
-   int i,nb, ret=0;
-   off_t where=0;
-   uint32_t s;
-   Dmsg4(dbglevel, "fsr %i:%i EOF=%i c=%i\n", 
-        current_file,current_block,atEOF,count);
-
-   check_eof();
-
-   if (atEOT) {
-      errno = EIO;
-      current_block = -1;
-      return -1;
-   }
-
-   if (atEOD) {
-      errno = EIO;
-      return -1;
-   }
-
-   atBOT = atEOF = false;   
-
-   /* check all block record */
-   for(i=0; (i < count) && !atEOF ; i++) {
-      nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
-      if (nb == sizeof(uint32_t) && s) {
-         current_block++;
-         where = lseek(fd, s, SEEK_CUR);     /* seek after this block */
-      } else {
-         Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
-               current_file, current_block, nb,s);
-         errno = EIO;
-         ret = -1;
-        if (next_FM) {
-            current_file++;
-           read_fm(VT_SKIP_EOF);
-        }
-         atEOF = true;          /* stop the loop */
-      }
-   }
-
-   return ret;
-}
-
-/*
- * BSR + EOF => begin of EOF + EIO
- * BSR + BSR + EOF => last block
- * current_block = -1
- */
-int vtape::bsr(int count)
-{
-   ASSERT(online);
-   ASSERT(current_file >= 0);
-   ASSERT(count == 1);
-   ASSERT(fd >= 0);
-
-   check_eof();
-
-   if (!count) {
-      return 0;
-   }
-
-   int ret=0;
-   int last_f=0;
-   int last_b=0;
-
-   off_t last=-1, last2=-1;
-   off_t orig = lseek(fd, 0, SEEK_CUR);
-   int orig_f = current_file;
-   int orig_b = current_block;
-
-   Dmsg4(dbglevel, "bsr(%i) cur_blk=%i orig=%lli cur_FM=%lli\n", 
-         count, current_block, orig, cur_FM);
-
-   /* begin of tape, do nothing */
-   if (atBOT) {
-      errno = EIO;
-      return -1;
-   }
-
-   /* at EOF 0:-1 BOT=0 EOD=0 EOF=0 ERR: Input/output error  */
-   if (atEOF) {
-      lseek(fd, cur_FM, SEEK_SET);
-      atEOF = false;
-      if (current_file > 0) {
-        current_file--;
-      }
-      current_block=-1;
-      errno = EIO;
-      return -1;
-   }
-
-   /*
-    * First, go to cur/last_FM and read all blocks to find the good one
-    */
-   if (cur_FM == orig) {       /* already just before  EOF */
-      lseek(fd, last_FM, SEEK_SET);
-
-   } else {
-      lseek(fd, cur_FM, SEEK_SET);
-   }
-
-   ret = read_fm(VT_READ_EOF);
-
-   do {
-      if (!atEOF) {
-         last2 = last;         /* keep track of the 2 last blocs position */
-         last = lseek(fd, 0, SEEK_CUR);
-         last_f = current_file;
-         last_b = current_block;
-         Dmsg6(dbglevel, "EOF=%i last2=%lli last=%lli < orig=%lli %i:%i\n", 
-               atEOF, last2, last, orig, current_file, current_block);
-      }
-      ret = fsr(1);
-   } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
-
-   if (last2 > 0 && atEOF) {    /* we take the previous position */
-      lseek(fd, last2, SEEK_SET);
-      current_file = last_f;
-      current_block = last_b - 1;
-      Dmsg3(dbglevel, "1 set offset2=%lli %i:%i\n", 
-            last, current_file, current_block);
-
-   } else if (last > 0) {
-      lseek(fd, last, SEEK_SET);
-      current_file = last_f;
-      current_block = last_b;
-      Dmsg3(dbglevel, "2 set offset=%lli %i:%i\n", 
-            last, current_file, current_block);
-   } else {
-      lseek(fd, orig, SEEK_SET);
-      current_file = orig_f;
-      current_block = orig_b;
-      return -1;
-   }
-
-   Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
-   errno=0;
-   atEOT = atEOF = atEOD = false;
-   atBOT = (lseek(fd, 0, SEEK_CUR) - (sizeof(uint32_t)+2*sizeof(off_t))) == 0;
-
-   if (orig_b == -1) {
-      current_block = orig_b;
-   }
-
-   return 0;
-}
-
-/* BSF => just before last EOF
- * EOF + BSF => just before EOF
- * file 0 + BSF => BOT + errno
- */
-int vtape::bsf()
-{
-   ASSERT(online);
-   ASSERT(current_file >= 0);
-   Dmsg2(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block);
-   int ret = 0;
-
-   check_eof();
-
-   atBOT = atEOF = atEOT = atEOD = false;
-
-   if (current_file == 0) {/* BOT + errno */      
-      lseek(fd, 0, SEEK_SET);
-      read_fm(VT_READ_EOF);
-      current_file = 0;
-      current_block = 0;
-      atBOT = true;
-      errno = EIO;
-      ret = -1;
-   } else {
-      Dmsg1(dbglevel, "bsf last=%lli\n", last_FM);
-      lseek(fd, cur_FM, SEEK_SET);
-      current_file--;
-      current_block=-1;
-   }
-   return ret;
-}
-
-/* 
- * Put vtape in offline mode
- */
-int vtape::offline()
-{
-   close();
-   
-   atEOF = false;               /* End of file */
-   atEOT = false;               /* End of tape */
-   atEOD = false;               /* End of data */
-   atBOT = false;               /* Begin of tape */
-   online = false;
-
-   file_block = 0;
-   current_file = -1;
-   current_block = -1;
-   last_file = -1;
-   return 0;
-}
-
-/* A filemark is automatically written to tape if the last tape operation
- * before close was a write.
- */
-int vtape::close()
-{
-   check_eof();
-   ::close(fd);
-   fd = -1;
-   return 0;
-}
-
-/*
- * When a filemark is encountered while reading, the following happens.  If
- * there are data remaining in the buffer when the filemark is found, the
- * buffered data is returned.  The next read returns zero bytes.  The following
- * read returns data from the next file.  The end of recorded data is sig‐
- * naled by returning zero bytes for two consecutive read calls.  The third
- * read returns an error.
- */
-int vtape::read(void *buffer, unsigned int count)
-{
-   ASSERT(online);
-   ASSERT(current_file >= 0);
-   unsigned int nb;
-   uint32_t s;
-   
-   Dmsg2(dbglevel*2, "read %i:%i\n", current_file, current_block);
-
-   if (atEOT || atEOD) {
-      errno = EIO;
-      return -1;
-   }
-
-   if (atEOF) {
-      if (!next_FM) {
-         atEOD = true;
-         atEOF = false;
-         current_block=-1;
-         return 0;
-      }
-      atEOF=false;
-   }
-
-   check_eof();
-
-   atEOD = atBOT = false;
-
-   /* reading size of data */
-   nb = ::read(fd, &s, sizeof(uint32_t));
-   if (nb <= 0) {
-      atEOF = true;            /* TODO: check this */
-      return 0;
-   }
-
-   if (s > count) {             /* not enough buffer to read block */
-      Dmsg2(dbglevel, "Need more buffer to read next block %i > %i\n",s,count);
-      lseek(fd, s, SEEK_CUR);
-      errno = ENOMEM;
-      return -1;
-   }
-
-   if (!s) {                    /* EOF */
-      atEOF = true;
-      if (read_fm(VT_SKIP_EOF)) {
-        current_file++;
-      }
-
-      return 0;
-   }
-
-   /* reading data itself */
-   nb = ::read(fd, buffer, s);
-   if (s != nb) {              /* read error */
-      errno=EIO;
-      atEOT=true;
-      current_block = -1;
-      Dmsg0(dbglevel, "EOT during reading\n");
-      return -1;
-   }                   /* read ok */
-
-   if (current_block >= 0) {
-      current_block++;
-   }
-
-   return nb;
-}
-
-int vtape::open(const char *pathname, int uflags)
-{
-   Dmsg2(dbglevel, "vtape::open(%s, %i)\n", pathname, uflags);
-
-   online = true;               /* assume that drive contains a tape */
-
-   struct stat statp;   
-   if (stat(pathname, &statp) != 0) {
-      Dmsg1(dbglevel, "Can't stat on %s\n", pathname);
-      if (uflags & O_NONBLOCK) {
-         online = false;
-         fd = ::open("/dev/null", O_CREAT | O_RDWR | O_LARGEFILE, 0600);
-      }
-   } else {
-      fd = ::open(pathname, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
-   }
-
-   if (fd < 0) {
-      errno = ENOMEDIUM;
-      return -1;
-   }
-
-   file_block = 0;
-   current_block = 0;
-   current_file = 0;
-   cur_FM = next_FM = last_FM = 0;
-   needEOF = false;
-   atBOT = true;
-   atEOT = atEOD = false;
-
-   /* If the vtape is empty, start by writing a EOF */
-   if (online && !read_fm(VT_READ_EOF)) {
-      weof();
-      last_file = current_file=0;
-   }
-
-   return fd;
-}
-
-/* use this to track file usage */
-void vtape::update_pos()
-{
-   ASSERT(online);
-   struct stat statp;
-   if (fstat(fd, &statp) == 0) {
-      file_block = statp.st_blocks;
-   } 
-
-   Dmsg1(dbglevel+1, "update_pos=%i\n", file_block);
-
-   if (file_block > max_block) {
-      atEOT = true;
-   } else {
-      atEOT = false;
-   }
-}
-
-void vtape::dump()
-{
-   Dmsg0(dbglevel+1, "===================\n");
-   Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
-   Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
-   Dmsg1(dbglevel+1, "file_block=%i\n", file_block);  
-   Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n", 
-         atEOF, atEOT, atEOD, atBOT);  
-}
-
diff --git a/bacula/src/stored/faketape.h b/bacula/src/stored/faketape.h
deleted file mode 100644 (file)
index 0bef45f..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
-   Bacula® - The Network Backup Solution
-
-   Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
-
-   The main author of Bacula is Kern Sibbald, with contributions from
-   many others, a complete list can be found in the file AUTHORS.
-   This program is Free Software; you can redistribute it and/or
-   modify it under the terms of version two of the GNU General Public
-   License as published by the Free Software Foundation, which is
-   listed in the file LICENSE.
-
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
-
-   Bacula® is a registered trademark of John Walker.
-   The licensor of Bacula is the Free Software Foundation Europe
-   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
-   Switzerland, email:ftf@fsfeurope.org.
-*/
-/*
- * vtape.h - Emulate the Linux st (scsi tape) driver on file.
- * for regression and bug hunting purpose
- *
- */
-
-#ifndef VTAPE_H
-#define VTAPE_H
-
-#include <stdarg.h>
-#include <stddef.h>
-#include "bacula.h"
-
-#define FTAPE_MAX_DRIVE 50
-
-/* 
- * Theses functions will replace open/read/write
- */
-int vtape_open(const char *pathname, int flags, ...);
-int vtape_read(int fd, void *buffer, unsigned int count);
-int vtape_write(int fd, const void *buffer, unsigned int count);
-int vtape_close(int fd);
-int vtape_ioctl(int fd, unsigned long int request, ...);
-void vtape_debug(int level);
-
-typedef enum {
-   VT_READ_EOF,                        /* Need to read the entire EOF struct */
-   VT_SKIP_EOF                 /* Have already read the EOF byte */
-} VT_READ_FM_MODE;
-
-class vtape {
-private:
-   int         fd;              /* Our file descriptor */
-
-   off_t       file_block;     /* size */
-   off_t       max_block;
-
-   off_t       last_FM;                /* last file mark (last file) */
-   off_t       next_FM;                /* next file mark (next file) */
-   off_t       cur_FM;         /* current file mark */
-
-   bool        atEOF;           /* End of file */
-   bool        atEOT;           /* End of media */
-   bool        atEOD;           /* End of data */
-   bool        atBOT;           /* Begin of tape */
-   bool        online;          /* volume online */
-   bool        needEOF;         /* check if last operation need eof */
-
-   int32_t     last_file;       /* last file of the volume */
-   int32_t     current_file;    /* current position */
-   int32_t     current_block;   /* current position */
-
-   void destroy();
-   int offline();
-   int truncate_file();
-   void check_eof() { if(needEOF) weof();};
-   void update_pos();
-   bool read_fm(VT_READ_FM_MODE readfirst);
-
-public:
-   int fsf();
-   int fsr(int count);
-   int weof();
-   int bsf();
-   int bsr(int count);
-
-   vtape();
-   ~vtape();
-
-   int get_fd();
-   void dump();
-   int open(const char *pathname, int flags);
-   int read(void *buffer, unsigned int count);
-   int write(const void *buffer, unsigned int count);
-   int close();
-
-   int tape_op(struct mtop *mt_com);
-   int tape_get(struct mtget *mt_com);
-   int tape_pos(struct mtpos *mt_com);
-};
-
-#endif /* !VTAPE_H */
index 764b478f5f959a9f5e0b1f967ffeaf201638a33b..edc2bb9944e45a500e7b918b0a164935adba30c6 100644 (file)
@@ -78,7 +78,7 @@ const int sd_dbglvl = 300;
 int readdir_r(DIR *dirp, struct dirent *entry, struct dirent **result);
 #endif
 
-#include "faketape.h"
+#include "vtape.h"
 
 
 /* Daemon globals from stored.c */
index d81fad95f91603dde66f21c12367a85f4ab59d8d..15818e8bd5994a1b242b04fde8c3eaa9aa6dc5a2 100644 (file)
@@ -213,7 +213,7 @@ static s_kw dev_types[] = {
    {"dvd",           B_DVD_DEV},
    {"fifo",          B_FIFO_DEV},
    {"vtl",           B_VTL_DEV},
-   {"faketape",      B_FAKETAPE_DEV},
+   {"vtape",         B_VTAPE_DEV},
    {NULL,            0}
 };
 
diff --git a/bacula/src/stored/vtape.c b/bacula/src/stored/vtape.c
new file mode 100644 (file)
index 0000000..e2cef89
--- /dev/null
@@ -0,0 +1,993 @@
+/*
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
+
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation, which is 
+   listed in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of John Walker.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+   Switzerland, email:ftf@fsfeurope.org.
+*/
+
+/*
+
+Device {
+  Name = Drive-1                      #
+  Maximum File Size = 800M
+  Maximum Volume Size = 3G
+  Device Type = TAPE
+  Archive Device = /tmp/fake
+  Media Type = DLT-8000
+  AutomaticMount = yes;               # when device opened, read it
+  AlwaysOpen = yes;
+  RemovableMedia = yes;
+  RandomAccess = no;
+}
+
+  Block description :
+
+  block {
+    int32  size;
+    void   *data;
+  }
+
+  EOF description :
+
+  EOF {
+    int32  size=0;
+  }
+
+
+ */
+
+#include "bacula.h"             /* define 64bit file usage */
+#include "stored.h"
+
+#include "vtape.h"
+
+static int dbglevel = 100;
+#define FILE_OFFSET 30
+vtape *ftape_list[FTAPE_MAX_DRIVE];
+
+static vtape *get_tape(int fd)
+{
+   ASSERT(fd >= 0);
+
+   if (fd >= FTAPE_MAX_DRIVE) {
+      /* error */
+      return NULL;
+   }
+
+   return ftape_list[fd];
+}
+
+static bool put_tape(vtape *ftape)
+{
+   ASSERT(ftape != NULL);
+
+   int fd = ftape->get_fd();
+   if (fd >= FTAPE_MAX_DRIVE) {
+      /* error */
+      return false;
+   }
+   ftape_list[fd] = ftape;
+   return true;
+}
+
+void vtape_debug(int level)
+{
+   dbglevel = level;
+}
+
+/****************************************************************/
+/* theses function will replace open/read/write/close/ioctl
+ * in bacula core
+ */
+int vtape_open(const char *pathname, int flags, ...)
+{
+   ASSERT(pathname != NULL);
+
+   int fd;
+   vtape *tape = new vtape();
+   fd = tape->open(pathname, flags);
+   if (fd > 0) {
+      put_tape(tape);
+   }
+   return fd;
+}
+
+int vtape_read(int fd, void *buffer, unsigned int count)
+{
+   vtape *tape = get_tape(fd);
+   ASSERT(tape != NULL);
+   return tape->read(buffer, count);
+}
+
+int vtape_write(int fd, const void *buffer, unsigned int count)
+{
+   vtape *tape = get_tape(fd);
+   ASSERT(tape != NULL);
+   return tape->write(buffer, count);
+}
+
+int vtape_close(int fd)
+{
+   vtape *tape = get_tape(fd);
+   ASSERT(tape != NULL);
+   tape->close();
+   delete tape;
+   return 0;
+}
+
+int vtape_ioctl(int fd, unsigned long int request, ...)
+{
+   va_list argp;
+   int result=0;
+
+   vtape *t = get_tape(fd);
+   if (!t) {
+      errno = EBADF;
+      return -1;
+   }
+
+   va_start(argp, request);
+
+   if (request == MTIOCTOP) {
+      result = t->tape_op(va_arg(argp, mtop *));
+   } else if (request == MTIOCGET) {
+      result = t->tape_get(va_arg(argp, mtget *));
+   } else if (request == MTIOCPOS) {
+      result = t->tape_pos(va_arg(argp, mtpos *));
+   } else {
+      errno = ENOTTY;
+      result = -1;
+   }
+   va_end(argp);
+
+   return result;
+}
+
+/****************************************************************/
+
+int vtape::tape_op(struct mtop *mt_com)
+{
+   int result=0;
+   int count = mt_com->mt_count;
+
+   if (!online) {
+      errno = ENOMEDIUM;
+      return -1;
+   }
+   
+   switch (mt_com->mt_op)
+   {
+   case MTRESET:
+   case MTNOP:
+   case MTSETDRVBUFFER:
+      break;
+
+   default:
+   case MTRAS1:
+   case MTRAS2:
+   case MTRAS3:
+   case MTSETDENSITY:
+      errno = ENOTTY;
+      result = -1;
+      break;
+
+   case MTFSF:                  /* Forward space over mt_count filemarks. */
+      do {
+        result = fsf();
+      } while (--count > 0 && result == 0);
+      break;
+
+   case MTBSF:                  /* Backward space over mt_count filemarks. */
+      do {
+        result = bsf();
+      } while (--count > 0 && result == 0);
+      break;
+
+   case MTFSR:      /* Forward space over mt_count records (tape blocks). */
+/*
+    file number = 1
+    block number = 0
+   
+    file number = 1
+    block number = 1
+   
+    mt: /dev/lto2: Erreur d'entree/sortie
+   
+    file number = 2
+    block number = 0
+*/
+      /* tester si on se trouve a la fin du fichier */
+      result = fsr(mt_com->mt_count);
+      break;
+
+   case MTBSR:      /* Backward space over mt_count records (tape blocks). */
+      result = bsr(mt_com->mt_count);
+      break;
+
+   case MTWEOF:                 /* Write mt_count filemarks. */
+      do {
+        result = weof();
+      } while (result == 0 && --count > 0);
+      break;
+
+   case MTREW:                  /* Rewind. */
+      Dmsg0(dbglevel, "rewind vtape\n");
+      check_eof();
+      atEOF = atEOD = false;
+      atBOT = true;
+      current_file = 0;
+      current_block = 0;
+      lseek(fd, 0, SEEK_SET);
+      result = !read_fm(VT_READ_EOF);
+      break;
+
+   case MTOFFL:                 /* put tape offline */
+      result = offline();
+      break;
+
+   case MTRETEN:                /* Re-tension tape. */
+      result = 0;
+      break;
+
+   case MTBSFM:                 /* not used by bacula */
+      errno = EIO;
+      result = -1;
+      break;
+
+   case MTFSFM:                 /* not used by bacula */
+      errno = EIO;
+      result = -1;
+      break;
+
+   case MTEOM:/* Go to the end of the recorded media (for appending files). */
+      while (next_FM) {
+        lseek(fd, next_FM, SEEK_SET);
+        if (read_fm(VT_READ_EOF)) {
+           current_file++;
+        }
+      }
+      off_t l;
+      while (::read(fd, &l, sizeof(l)) > 0) {
+        if (l) {
+           lseek(fd, l, SEEK_CUR);
+        } else {
+           ASSERT(0);
+        }
+        Dmsg0(dbglevel, "skip 1 block\n");
+      }
+      current_block = -1;
+      atEOF = false;
+      atEOD = true;
+
+/*
+   file number = 3
+   block number = -1
+*/
+      /* Can be at EOM */
+      break;
+
+   case MTERASE:                /* not used by bacula */
+      atEOD = true;
+      atEOF = false;
+      atEOT = false;
+
+      current_file = 0;
+      current_block = -1;
+      lseek(fd, 0, SEEK_SET);
+      read_fm(VT_READ_EOF);
+      truncate_file();
+      break;
+
+   case MTSETBLK:
+      break;
+
+   case MTSEEK:
+      break;
+
+   case MTTELL:
+      break;
+
+   case MTFSS:
+      break;
+
+   case MTBSS:
+      break;
+
+   case MTWSM:
+      break;
+
+   case MTLOCK:
+      break;
+
+   case MTUNLOCK:
+      break;
+
+   case MTLOAD:
+      break;
+
+   case MTUNLOAD:
+      break;
+
+   case MTCOMPRESSION:
+      break;
+
+   case MTSETPART:
+      break;
+
+   case MTMKPART:
+      break;
+   }
+
+   return result == 0 ? 0 : -1;
+}
+
+int vtape::tape_get(struct mtget *mt_get)
+{
+   int density = 1;
+   int block_size = 1024;
+
+   mt_get->mt_type = MT_ISSCSI2;
+   mt_get->mt_blkno = current_block;
+   mt_get->mt_fileno = current_file;
+
+   mt_get->mt_resid = -1;
+//   pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
+
+   /* TODO */
+   mt_get->mt_dsreg = 
+      ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
+      ((block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
+
+
+   mt_get->mt_gstat = 0x00010000;  /* Immediate report mode.*/
+
+   if (atEOF) {
+      mt_get->mt_gstat |= 0x80000000;     // GMT_EOF
+   }
+
+   if (atBOT) {
+      mt_get->mt_gstat |= 0x40000000;     // GMT_BOT
+   }
+   if (atEOT) {
+      mt_get->mt_gstat |= 0x20000000;     // GMT_EOT
+   }
+
+   if (atEOD) {
+      mt_get->mt_gstat |= 0x08000000;     // GMT_EOD
+   }
+
+   if (0) { //WriteProtected) {
+      mt_get->mt_gstat |= 0x04000000;     // GMT_WR_PROT
+   }
+
+   if (online) {
+      mt_get->mt_gstat |= 0x01000000;     // GMT_ONLINE
+   } else {
+      mt_get->mt_gstat |= 0x00040000;  // GMT_DR_OPEN
+   }
+   mt_get->mt_erreg = 0;
+
+   return 0;
+}
+
+int vtape::tape_pos(struct mtpos *mt_pos)
+{
+   if (current_block >= 0) {
+      mt_pos->mt_blkno = current_block;
+      return 0;
+   }
+
+   return -1;
+}
+
+/*
+ * This function try to emulate the append only behavior
+ * of a tape. When you wrote something, data after the
+ * current position are discarded.
+ */
+int vtape::truncate_file()
+{  
+   Dmsg2(dbglevel, "truncate %i:%i\n", current_file, current_block);
+   ftruncate(fd, lseek(fd, 0, SEEK_CUR));
+   last_file = current_file;
+   atEOD=true;
+   update_pos();
+   return 0;
+}
+
+vtape::vtape()
+{
+   fd = -1;
+
+   atEOF = false;
+   atBOT = false;
+   atEOT = false;
+   atEOD = false;
+   online = false;
+   needEOF = false;
+
+   file_block = 0;
+   last_file = 0;
+   current_file = 0;
+   current_block = -1;
+
+   max_block = 2*1024*2048;      /* 2GB */
+}
+
+vtape::~vtape()
+{
+}
+
+int vtape::get_fd()
+{
+   return this->fd;
+}
+
+/*
+ * TODO: check if after a write op, and other tape op put a EOF
+ */
+int vtape::write(const void *buffer, unsigned int count)
+{
+   ASSERT(online);
+   ASSERT(current_file >= 0);
+   ASSERT(count > 0);
+   ASSERT(buffer);
+
+   unsigned int nb;
+   Dmsg3(dbglevel*2, "write len=%i %i:%i\n", 
+        count, current_file,current_block);
+
+   if (atEOT) {
+      Dmsg0(dbglevel, "write nothing, EOT !\n");
+      errno = ENOSPC;
+      return -1;
+   }
+
+   if (!atEOD) {                /* if not at the end of the data */
+      truncate_file();
+   }
+   if (current_block != -1) {
+      current_block++;
+   }
+
+   atBOT = false;
+   atEOF = false;
+   atEOD = true;                /* End of data */
+
+   needEOF = true;              /* next operation need EOF mark */
+
+   uint32_t size = count;
+   ::write(fd, &size, sizeof(uint32_t));
+   nb = ::write(fd, buffer, count);
+   
+   if (nb != count) {
+      atEOT = true;
+      Dmsg2(dbglevel, 
+            "Not enough space writing only %i of %i requested\n", 
+            nb, count);
+   }
+
+   update_pos();
+
+   return nb;
+}
+
+/*
+ *  +---+---------+---+------------------+---+-------------------+
+ *  |00N|  DATA   |0LN|   DATA           |0LC|     DATA          |
+ *  +---+---------+---+------------------+---+-------------------+
+ *
+ *  0 : zero
+ *  L : Last FileMark offset
+ *  N : Next FileMark offset
+ *  C : Current FileMark Offset
+ */
+int vtape::weof()
+{
+   ASSERT(online);
+   ASSERT(current_file >= 0);
+
+   if (atEOT) {
+      errno = ENOSPC;
+      current_block = -1;
+      return -1;
+   }
+
+   if (!atEOD) {
+      truncate_file();             /* nothing after this point */
+   }
+
+   last_FM = cur_FM;
+   cur_FM = lseek(fd, 0, SEEK_CUR); // current position
+   
+   /* update previous next_FM  */
+   lseek(fd, last_FM + sizeof(uint32_t)+sizeof(off_t), SEEK_SET);
+   ::write(fd, &cur_FM, sizeof(off_t));
+   lseek(fd, cur_FM, SEEK_SET);
+
+   next_FM = 0;
+
+   uint32_t c=0;
+   ::write(fd, &c,       sizeof(uint32_t)); // EOF
+   ::write(fd, &last_FM, sizeof(last_FM));  // F-1
+   ::write(fd, &next_FM, sizeof(next_FM));  // F   (will be updated next time)
+
+   current_file++;
+   current_block = 0;
+
+   needEOF = false;
+   atEOD = false;
+   atBOT = false;
+   atEOF = true;
+
+   last_file = MAX(current_file, last_file);
+
+   Dmsg4(dbglevel, "Writing EOF %i:%i last=%lli cur=%lli next=0\n", 
+         current_file, current_block, last_FM, cur_FM);
+
+   return 0;
+}
+
+/*
+ * Go to next FM
+ */
+int vtape::fsf()
+{   
+   ASSERT(online);
+   ASSERT(current_file >= 0);
+   ASSERT(fd >= 0);
+/*
+ * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
+ */
+
+   int ret=0;
+   if (atEOT || atEOD) {
+      errno = EIO;
+      current_block = -1;
+      return -1;
+   }
+
+   atBOT = false;
+   Dmsg2(dbglevel+1, "fsf %i <= %i\n", current_file, last_file);
+
+   if (next_FM > cur_FM) {     /* not the last file */
+      lseek(fd, next_FM, SEEK_SET);
+      read_fm(VT_READ_EOF);
+      current_file++;
+      atEOF = true;
+      ret = 0;
+
+   } else if (atEOF) {         /* last file mark */
+      current_block=-1;
+      errno = EIO;
+      atEOF = false;
+      atEOD = true;
+
+   } else {                    /* last file, but no at the end */
+      fsr(100000);
+
+      Dmsg0(dbglevel, "Try to FSF after EOT\n");
+      errno = EIO;
+      current_file = last_file ;
+      current_block = -1;
+      atEOD=true;
+      ret = -1;
+   }
+   return ret;
+}
+
+/* /------------\ /---------------\
+ * +---+------+---+---------------+-+
+ * |OLN|      |0LN|               | |
+ * +---+------+---+---------------+-+
+ */
+
+bool vtape::read_fm(VT_READ_FM_MODE read_all)
+{
+   int ret;
+   uint32_t c;
+   if (read_all == VT_READ_EOF) {
+      ::read(fd, &c, sizeof(c));
+      if (c != 0) {
+        lseek(fd, cur_FM, SEEK_SET);
+        return false;
+      }
+   }
+
+   cur_FM = lseek(fd, 0, SEEK_CUR) - sizeof(c);
+
+   ::read(fd, &last_FM, sizeof(last_FM));
+   ret = ::read(fd, &next_FM, sizeof(next_FM));
+
+   current_block=0;
+   
+   Dmsg3(dbglevel, "Read FM cur=%lli last=%lli next=%lli\n", 
+        cur_FM, last_FM, next_FM);
+
+   return (ret == sizeof(next_FM));
+}
+
+/*
+ * TODO: Check fsr with EOF
+ */
+int vtape::fsr(int count)
+{
+   ASSERT(online);
+   ASSERT(current_file >= 0);
+   ASSERT(fd >= 0);
+   
+   int i,nb, ret=0;
+   off_t where=0;
+   uint32_t s;
+   Dmsg4(dbglevel, "fsr %i:%i EOF=%i c=%i\n", 
+        current_file,current_block,atEOF,count);
+
+   check_eof();
+
+   if (atEOT) {
+      errno = EIO;
+      current_block = -1;
+      return -1;
+   }
+
+   if (atEOD) {
+      errno = EIO;
+      return -1;
+   }
+
+   atBOT = atEOF = false;   
+
+   /* check all block record */
+   for(i=0; (i < count) && !atEOF ; i++) {
+      nb = ::read(fd, &s, sizeof(uint32_t)); /* get size of next block */
+      if (nb == sizeof(uint32_t) && s) {
+         current_block++;
+         where = lseek(fd, s, SEEK_CUR);     /* seek after this block */
+      } else {
+         Dmsg4(dbglevel, "read EOF %i:%i nb=%i s=%i\n",
+               current_file, current_block, nb,s);
+         errno = EIO;
+         ret = -1;
+        if (next_FM) {
+            current_file++;
+           read_fm(VT_SKIP_EOF);
+        }
+         atEOF = true;          /* stop the loop */
+      }
+   }
+
+   return ret;
+}
+
+/*
+ * BSR + EOF => begin of EOF + EIO
+ * BSR + BSR + EOF => last block
+ * current_block = -1
+ */
+int vtape::bsr(int count)
+{
+   ASSERT(online);
+   ASSERT(current_file >= 0);
+   ASSERT(count == 1);
+   ASSERT(fd >= 0);
+
+   check_eof();
+
+   if (!count) {
+      return 0;
+   }
+
+   int ret=0;
+   int last_f=0;
+   int last_b=0;
+
+   off_t last=-1, last2=-1;
+   off_t orig = lseek(fd, 0, SEEK_CUR);
+   int orig_f = current_file;
+   int orig_b = current_block;
+
+   Dmsg4(dbglevel, "bsr(%i) cur_blk=%i orig=%lli cur_FM=%lli\n", 
+         count, current_block, orig, cur_FM);
+
+   /* begin of tape, do nothing */
+   if (atBOT) {
+      errno = EIO;
+      return -1;
+   }
+
+   /* at EOF 0:-1 BOT=0 EOD=0 EOF=0 ERR: Input/output error  */
+   if (atEOF) {
+      lseek(fd, cur_FM, SEEK_SET);
+      atEOF = false;
+      if (current_file > 0) {
+        current_file--;
+      }
+      current_block=-1;
+      errno = EIO;
+      return -1;
+   }
+
+   /*
+    * First, go to cur/last_FM and read all blocks to find the good one
+    */
+   if (cur_FM == orig) {       /* already just before  EOF */
+      lseek(fd, last_FM, SEEK_SET);
+
+   } else {
+      lseek(fd, cur_FM, SEEK_SET);
+   }
+
+   ret = read_fm(VT_READ_EOF);
+
+   do {
+      if (!atEOF) {
+         last2 = last;         /* keep track of the 2 last blocs position */
+         last = lseek(fd, 0, SEEK_CUR);
+         last_f = current_file;
+         last_b = current_block;
+         Dmsg6(dbglevel, "EOF=%i last2=%lli last=%lli < orig=%lli %i:%i\n", 
+               atEOF, last2, last, orig, current_file, current_block);
+      }
+      ret = fsr(1);
+   } while ((lseek(fd, 0, SEEK_CUR) < orig) && (ret == 0));
+
+   if (last2 > 0 && atEOF) {    /* we take the previous position */
+      lseek(fd, last2, SEEK_SET);
+      current_file = last_f;
+      current_block = last_b - 1;
+      Dmsg3(dbglevel, "1 set offset2=%lli %i:%i\n", 
+            last, current_file, current_block);
+
+   } else if (last > 0) {
+      lseek(fd, last, SEEK_SET);
+      current_file = last_f;
+      current_block = last_b;
+      Dmsg3(dbglevel, "2 set offset=%lli %i:%i\n", 
+            last, current_file, current_block);
+   } else {
+      lseek(fd, orig, SEEK_SET);
+      current_file = orig_f;
+      current_block = orig_b;
+      return -1;
+   }
+
+   Dmsg2(dbglevel, "bsr %i:%i\n", current_file, current_block);
+   errno=0;
+   atEOT = atEOF = atEOD = false;
+   atBOT = (lseek(fd, 0, SEEK_CUR) - (sizeof(uint32_t)+2*sizeof(off_t))) == 0;
+
+   if (orig_b == -1) {
+      current_block = orig_b;
+   }
+
+   return 0;
+}
+
+/* BSF => just before last EOF
+ * EOF + BSF => just before EOF
+ * file 0 + BSF => BOT + errno
+ */
+int vtape::bsf()
+{
+   ASSERT(online);
+   ASSERT(current_file >= 0);
+   Dmsg2(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block);
+   int ret = 0;
+
+   check_eof();
+
+   atBOT = atEOF = atEOT = atEOD = false;
+
+   if (current_file == 0) {/* BOT + errno */      
+      lseek(fd, 0, SEEK_SET);
+      read_fm(VT_READ_EOF);
+      current_file = 0;
+      current_block = 0;
+      atBOT = true;
+      errno = EIO;
+      ret = -1;
+   } else {
+      Dmsg1(dbglevel, "bsf last=%lli\n", last_FM);
+      lseek(fd, cur_FM, SEEK_SET);
+      current_file--;
+      current_block=-1;
+   }
+   return ret;
+}
+
+/* 
+ * Put vtape in offline mode
+ */
+int vtape::offline()
+{
+   close();
+   
+   atEOF = false;               /* End of file */
+   atEOT = false;               /* End of tape */
+   atEOD = false;               /* End of data */
+   atBOT = false;               /* Begin of tape */
+   online = false;
+
+   file_block = 0;
+   current_file = -1;
+   current_block = -1;
+   last_file = -1;
+   return 0;
+}
+
+/* A filemark is automatically written to tape if the last tape operation
+ * before close was a write.
+ */
+int vtape::close()
+{
+   check_eof();
+   ::close(fd);
+   fd = -1;
+   return 0;
+}
+
+/*
+ * When a filemark is encountered while reading, the following happens.  If
+ * there are data remaining in the buffer when the filemark is found, the
+ * buffered data is returned.  The next read returns zero bytes.  The following
+ * read returns data from the next file.  The end of recorded data is sig‐
+ * naled by returning zero bytes for two consecutive read calls.  The third
+ * read returns an error.
+ */
+int vtape::read(void *buffer, unsigned int count)
+{
+   ASSERT(online);
+   ASSERT(current_file >= 0);
+   unsigned int nb;
+   uint32_t s;
+   
+   Dmsg2(dbglevel*2, "read %i:%i\n", current_file, current_block);
+
+   if (atEOT || atEOD) {
+      errno = EIO;
+      return -1;
+   }
+
+   if (atEOF) {
+      if (!next_FM) {
+         atEOD = true;
+         atEOF = false;
+         current_block=-1;
+         return 0;
+      }
+      atEOF=false;
+   }
+
+   check_eof();
+
+   atEOD = atBOT = false;
+
+   /* reading size of data */
+   nb = ::read(fd, &s, sizeof(uint32_t));
+   if (nb <= 0) {
+      atEOF = true;            /* TODO: check this */
+      return 0;
+   }
+
+   if (s > count) {             /* not enough buffer to read block */
+      Dmsg2(dbglevel, "Need more buffer to read next block %i > %i\n",s,count);
+      lseek(fd, s, SEEK_CUR);
+      errno = ENOMEM;
+      return -1;
+   }
+
+   if (!s) {                    /* EOF */
+      atEOF = true;
+      if (read_fm(VT_SKIP_EOF)) {
+        current_file++;
+      }
+
+      return 0;
+   }
+
+   /* reading data itself */
+   nb = ::read(fd, buffer, s);
+   if (s != nb) {              /* read error */
+      errno=EIO;
+      atEOT=true;
+      current_block = -1;
+      Dmsg0(dbglevel, "EOT during reading\n");
+      return -1;
+   }                   /* read ok */
+
+   if (current_block >= 0) {
+      current_block++;
+   }
+
+   return nb;
+}
+
+int vtape::open(const char *pathname, int uflags)
+{
+   Dmsg2(dbglevel, "vtape::open(%s, %i)\n", pathname, uflags);
+
+   online = true;               /* assume that drive contains a tape */
+
+   struct stat statp;   
+   if (stat(pathname, &statp) != 0) {
+      Dmsg1(dbglevel, "Can't stat on %s\n", pathname);
+      if (uflags & O_NONBLOCK) {
+         online = false;
+         fd = ::open("/dev/null", O_CREAT | O_RDWR | O_LARGEFILE, 0600);
+      }
+   } else {
+      fd = ::open(pathname, O_CREAT | O_RDWR | O_LARGEFILE, 0600);
+   }
+
+   if (fd < 0) {
+      errno = ENOMEDIUM;
+      return -1;
+   }
+
+   file_block = 0;
+   current_block = 0;
+   current_file = 0;
+   cur_FM = next_FM = last_FM = 0;
+   needEOF = false;
+   atBOT = true;
+   atEOT = atEOD = false;
+
+   /* If the vtape is empty, start by writing a EOF */
+   if (online && !read_fm(VT_READ_EOF)) {
+      weof();
+      last_file = current_file=0;
+   }
+
+   return fd;
+}
+
+/* use this to track file usage */
+void vtape::update_pos()
+{
+   ASSERT(online);
+   struct stat statp;
+   if (fstat(fd, &statp) == 0) {
+      file_block = statp.st_blocks;
+   } 
+
+   Dmsg1(dbglevel+1, "update_pos=%i\n", file_block);
+
+   if (file_block > max_block) {
+      atEOT = true;
+   } else {
+      atEOT = false;
+   }
+}
+
+void vtape::dump()
+{
+   Dmsg0(dbglevel+1, "===================\n");
+   Dmsg2(dbglevel, "file:block = %i:%i\n", current_file, current_block);
+   Dmsg1(dbglevel+1, "last_file=%i\n", last_file);
+   Dmsg1(dbglevel+1, "file_block=%i\n", file_block);  
+   Dmsg4(dbglevel+1, "EOF=%i EOT=%i EOD=%i BOT=%i\n", 
+         atEOF, atEOT, atEOD, atBOT);  
+}
+
diff --git a/bacula/src/stored/vtape.h b/bacula/src/stored/vtape.h
new file mode 100644 (file)
index 0000000..0bef45f
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+   Bacula® - The Network Backup Solution
+
+   Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
+
+   The main author of Bacula is Kern Sibbald, with contributions from
+   many others, a complete list can be found in the file AUTHORS.
+   This program is Free Software; you can redistribute it and/or
+   modify it under the terms of version two of the GNU General Public
+   License as published by the Free Software Foundation, which is
+   listed in the file LICENSE.
+
+   This program is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+   02110-1301, USA.
+
+   Bacula® is a registered trademark of John Walker.
+   The licensor of Bacula is the Free Software Foundation Europe
+   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
+   Switzerland, email:ftf@fsfeurope.org.
+*/
+/*
+ * vtape.h - Emulate the Linux st (scsi tape) driver on file.
+ * for regression and bug hunting purpose
+ *
+ */
+
+#ifndef VTAPE_H
+#define VTAPE_H
+
+#include <stdarg.h>
+#include <stddef.h>
+#include "bacula.h"
+
+#define FTAPE_MAX_DRIVE 50
+
+/* 
+ * Theses functions will replace open/read/write
+ */
+int vtape_open(const char *pathname, int flags, ...);
+int vtape_read(int fd, void *buffer, unsigned int count);
+int vtape_write(int fd, const void *buffer, unsigned int count);
+int vtape_close(int fd);
+int vtape_ioctl(int fd, unsigned long int request, ...);
+void vtape_debug(int level);
+
+typedef enum {
+   VT_READ_EOF,                        /* Need to read the entire EOF struct */
+   VT_SKIP_EOF                 /* Have already read the EOF byte */
+} VT_READ_FM_MODE;
+
+class vtape {
+private:
+   int         fd;              /* Our file descriptor */
+
+   off_t       file_block;     /* size */
+   off_t       max_block;
+
+   off_t       last_FM;                /* last file mark (last file) */
+   off_t       next_FM;                /* next file mark (next file) */
+   off_t       cur_FM;         /* current file mark */
+
+   bool        atEOF;           /* End of file */
+   bool        atEOT;           /* End of media */
+   bool        atEOD;           /* End of data */
+   bool        atBOT;           /* Begin of tape */
+   bool        online;          /* volume online */
+   bool        needEOF;         /* check if last operation need eof */
+
+   int32_t     last_file;       /* last file of the volume */
+   int32_t     current_file;    /* current position */
+   int32_t     current_block;   /* current position */
+
+   void destroy();
+   int offline();
+   int truncate_file();
+   void check_eof() { if(needEOF) weof();};
+   void update_pos();
+   bool read_fm(VT_READ_FM_MODE readfirst);
+
+public:
+   int fsf();
+   int fsr(int count);
+   int weof();
+   int bsf();
+   int bsr(int count);
+
+   vtape();
+   ~vtape();
+
+   int get_fd();
+   void dump();
+   int open(const char *pathname, int flags);
+   int read(void *buffer, unsigned int count);
+   int write(const void *buffer, unsigned int count);
+   int close();
+
+   int tape_op(struct mtop *mt_com);
+   int tape_get(struct mtget *mt_com);
+   int tape_pos(struct mtpos *mt_com);
+};
+
+#endif /* !VTAPE_H */
index 11cd95b8d91d52053f3d0ac3bc9abcce0357d618..fb27fd1124ed6e9525090a857a6d43788997f270 100644 (file)
@@ -25,6 +25,7 @@ Add long term statistics job table
 
 General:
 09Jun08
+ebl  Rename faketape to vtape.
 ebl  Update faketape driver.
 08Jun08
 ebl  Modify faketape driver to avoid sparse file.