/*
Bacula® - The Network Backup Solution
- Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
+ Copyright (C) 2008-2010 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
+ modify it under the terms of version three of the GNU Affero General Public
License as published by the Free Software Foundation, which is
listed in the file LICENSE.
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
+ You should have received a copy of the GNU Affero 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.
/*
Device {
- Name = Drive-1 #
+ 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
+ AutomaticMount = yes; # when device opened, read it
AlwaysOpen = yes;
RemovableMedia = yes;
RandomAccess = no;
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, ...)
+int vtape::d_ioctl(int fd, ioctl_req_t request, char *op)
{
- ASSERT(pathname != NULL);
-
- int fd;
- vtape *tape = new vtape();
- fd = tape->open(pathname, flags);
- if (fd > 0) {
- put_tape(tape);
- }
- return fd;
-}
-
-ssize_t vtape_read(int fd, void *buffer, size_t count)
-{
- vtape *tape = get_tape(fd);
- ASSERT(tape != NULL);
- return tape->read(buffer, count);
-}
-
-ssize_t vtape_write(int fd, const void *buffer, size_t 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, int request, ...)
-{
- va_list argp;
- int result=0;
-
- vtape *t = get_tape(fd);
- if (!t) {
- errno = EBADF;
- return -1;
- }
-
- va_start(argp, request);
+ int result = 0;
if (request == MTIOCTOP) {
- result = t->tape_op(va_arg(argp, mtop *));
+ result = tape_op((mtop *)op);
} else if (request == MTIOCGET) {
- result = t->tape_get(va_arg(argp, mtget *));
+ result = tape_get((mtget *)op);
} else if (request == MTIOCPOS) {
- result = t->tape_pos(va_arg(argp, mtpos *));
+ result = tape_pos((mtpos *)op);
} else {
errno = ENOTTY;
result = -1;
}
- va_end(argp);
return result;
}
result = -1;
break;
- case MTFSF: /* Forward space over mt_count filemarks. */
+ case MTFSF: /* Forward space over mt_count filemarks. */
do {
- result = fsf();
+ result = fsf();
} while (--count > 0 && result == 0);
break;
- case MTBSF: /* Backward space over mt_count filemarks. */
+ case MTBSF: /* Backward space over mt_count filemarks. */
do {
- result = bsf();
+ result = bsf();
} while (--count > 0 && result == 0);
break;
- case MTFSR: /* Forward space over mt_count records (tape blocks). */
+ case MTFSR: /* Forward space over mt_count records (tape blocks). */
/*
file number = 1
block number = 0
result = fsr(mt_com->mt_count);
break;
- case MTBSR: /* Backward space over mt_count records (tape blocks). */
+ case MTBSR: /* Backward space over mt_count records (tape blocks). */
result = bsr(mt_com->mt_count);
break;
- case MTWEOF: /* Write mt_count filemarks. */
+ case MTWEOF: /* Write mt_count filemarks. */
do {
- result = weof();
+ result = weof();
} while (result == 0 && --count > 0);
break;
- case MTREW: /* Rewind. */
+ case MTREW: /* Rewind. */
Dmsg0(dbglevel, "rewind vtape\n");
check_eof();
atEOF = atEOD = false;
result = !read_fm(VT_READ_EOF);
break;
- case MTOFFL: /* put tape offline */
+ case MTOFFL: /* put tape offline */
result = offline();
break;
- case MTRETEN: /* Re-tension tape. */
+ case MTRETEN: /* Re-tension tape. */
result = 0;
break;
- case MTBSFM: /* not used by bacula */
+ case MTBSFM: /* not used by bacula */
errno = EIO;
result = -1;
break;
- case MTFSFM: /* not used by bacula */
+ 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++;
- }
+ lseek(fd, next_FM, SEEK_SET);
+ if (read_fm(VT_READ_EOF)) {
+ current_file++;
+ }
}
- off_t l;
+ boffset_t l;
while (::read(fd, &l, sizeof(l)) > 0) {
- if (l) {
- lseek(fd, l, SEEK_CUR);
- } else {
- ASSERT(0);
- }
+ if (l) {
+ lseek(fd, l, SEEK_CUR);
+ } else {
+ ASSERT(0);
+ }
Dmsg0(dbglevel, "skip 1 block\n");
}
current_block = -1;
/* Can be at EOM */
break;
- case MTERASE: /* not used by bacula */
+ case MTERASE: /* not used by bacula */
atEOD = true;
atEOF = false;
atEOT = false;
mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
if (atEOF) {
- mt_get->mt_gstat |= 0x80000000; // GMT_EOF
+ mt_get->mt_gstat |= 0x80000000; // GMT_EOF
}
if (atBOT) {
- mt_get->mt_gstat |= 0x40000000; // GMT_BOT
+ mt_get->mt_gstat |= 0x40000000; // GMT_BOT
}
if (atEOT) {
- mt_get->mt_gstat |= 0x20000000; // GMT_EOT
+ mt_get->mt_gstat |= 0x20000000; // GMT_EOT
}
if (atEOD) {
- mt_get->mt_gstat |= 0x08000000; // GMT_EOD
+ mt_get->mt_gstat |= 0x08000000; // GMT_EOD
}
if (0) { //WriteProtected) {
- mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
+ mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
}
if (online) {
- mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
+ mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
} else {
mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
}
return 0;
}
+vtape::~vtape()
+{
+}
+
vtape::vtape()
{
fd = -1;
current_file = 0;
current_block = -1;
- max_block = 2*1024*2048; /* 2GB */
-}
-
-vtape::~vtape()
-{
+ max_block = VTAPE_MAX_BLOCK;
+ Dmsg0(0, "I'm a vtape device\n");
}
int vtape::get_fd()
* vtape_header = sizeof(data)
* if vtape_header == 0, this is a EOF
*/
-ssize_t vtape::write(const void *buffer, size_t count)
+ssize_t vtape::d_write(int, const void *buffer, size_t count)
{
ASSERT(online);
ASSERT(current_file >= 0);
ssize_t nb;
Dmsg3(dbglevel*2, "write len=%i %i:%i\n",
- count, current_file,current_block);
+ count, current_file,current_block);
if (atEOT) {
Dmsg0(dbglevel, "write nothing, EOT !\n");
return -1;
}
- if (!atEOD) { /* if not at the end of the data */
+ if (!atEOD) { /* if not at the end of the data */
truncate_file();
}
atBOT = false;
atEOF = false;
- atEOD = true; /* End of data */
+ atEOD = true; /* End of data */
- needEOF = true; /* next operation need EOF mark */
+ needEOF = true; /* next operation need EOF mark */
uint32_t size = count;
::write(fd, &size, sizeof(uint32_t));
atEOT = true;
Dmsg2(dbglevel,
"Not enough space writing only %i of %i requested\n",
- nb, count);
+ nb, count);
}
update_pos();
/*
* +---+---------+---+------------------+---+-------------------+
- * |00N| DATA |0LN| DATA |0LC| DATA |
+ * |00N| DATA |0LN| DATA |0LC| DATA |
* +---+---------+---+------------------+---+-------------------+
*
* 0 : zero
}
if (!atEOD) {
- truncate_file(); /* nothing after this point */
+ 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, last_FM + sizeof(uint32_t)+sizeof(boffset_t), SEEK_SET);
+ ::write(fd, &cur_FM, sizeof(boffset_t));
lseek(fd, cur_FM, SEEK_SET);
next_FM = 0;
uint32_t c=0;
- ::write(fd, &c, sizeof(uint32_t)); // EOF
+ ::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)
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);
+ current_file, current_block, last_FM, cur_FM);
return 0;
}
atBOT = false;
Dmsg2(dbglevel+1, "fsf %i <= %i\n", current_file, last_file);
- if (next_FM > cur_FM) { /* not the 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 */
+ } else if (atEOF) { /* last file mark */
current_block=-1;
errno = EIO;
atEOF = false;
atEOD = true;
- } else { /* last file, but no at the end */
+ } else { /* last file, but no at the end */
fsr(100000);
Dmsg0(dbglevel, "Try to FSF after EOT\n");
/* /------------\ /---------------\
* +---+------+---+---------------+-+
- * |OLN| |0LN| | |
+ * |OLN| |0LN| | |
* +---+------+---+---------------+-+
*/
bool vtape::read_fm(VT_READ_FM_MODE read_all)
{
int ret;
- uint32_t c;
+ uint32_t c = 0;
if (read_all == VT_READ_EOF) {
::read(fd, &c, sizeof(c));
if (c != 0) {
- lseek(fd, cur_FM, SEEK_SET);
- return false;
+ lseek(fd, cur_FM, SEEK_SET);
+ return false;
}
}
current_block=0;
Dmsg3(dbglevel, "Read FM cur=%lli last=%lli next=%lli\n",
- cur_FM, last_FM, next_FM);
+ cur_FM, last_FM, next_FM);
return (ret == sizeof(next_FM));
}
ASSERT(fd >= 0);
int i,nb, ret=0;
- off_t where=0;
+ boffset_t where=0;
uint32_t s;
Dmsg4(dbglevel, "fsr %i:%i EOF=%i c=%i\n",
- current_file,current_block,atEOF,count);
+ current_file,current_block,atEOF,count);
check_eof();
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 */
+ 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 */
+ 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 */
}
}
int last_f=0;
int last_b=0;
- off_t last=-1, last2=-1;
- off_t orig = lseek(fd, 0, SEEK_CUR);
+ boffset_t last=-1, last2=-1;
+ boffset_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);
+ count, current_block, orig, cur_FM);
/* begin of tape, do nothing */
if (atBOT) {
lseek(fd, cur_FM, SEEK_SET);
atEOF = false;
if (current_file > 0) {
- current_file--;
+ current_file--;
}
current_block=-1;
errno = EIO;
/*
* First, go to cur/last_FM and read all blocks to find the good one
*/
- if (cur_FM == orig) { /* already just before EOF */
+ if (cur_FM == orig) { /* already just before EOF */
lseek(fd, last_FM, SEEK_SET);
} else {
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;
+ 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);
+ 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 */
+ 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);
+ 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);
+ last, current_file, current_block);
} else {
lseek(fd, orig, SEEK_SET);
current_file = orig_f;
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;
+ atBOT = (lseek(fd, 0, SEEK_CUR) - (sizeof(uint32_t)+2*sizeof(boffset_t))) == 0;
if (orig_b == -1) {
current_block = orig_b;
return 0;
}
+boffset_t vtape::lseek(int fd, off_t offset, int whence)
+{
+ return ::lseek(fd, offset, whence);
+}
+
/* BSF => just before last EOF
* EOF + BSF => just before EOF
* file 0 + BSF => BOT + errno
atBOT = atEOF = atEOT = atEOD = false;
- if (current_file == 0) {/* BOT + errno */
+ if (current_file == 0) {/* BOT + errno */
lseek(fd, 0, SEEK_SET);
read_fm(VT_READ_EOF);
current_file = 0;
{
close();
- atEOF = false; /* End of file */
- atEOT = false; /* End of tape */
- atEOD = false; /* End of data */
- atBOT = false; /* Begin of tape */
+ 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;
/* A filemark is automatically written to tape if the last tape operation
* before close was a write.
*/
-int vtape::close()
+int vtape::d_close(int)
{
check_eof();
::close(fd);
* by returning zero bytes for two consecutive read calls. The third read
* returns an error.
*/
-ssize_t vtape::read(void *buffer, size_t count)
+ssize_t vtape::d_read(int, void *buffer, size_t count)
{
ASSERT(online);
ASSERT(current_file >= 0);
if (atEOF) {
if (!next_FM) {
- atEOD = true;
- atEOF = false;
- current_block=-1;
- return 0;
+ atEOD = true;
+ atEOF = false;
+ current_block=-1;
+ return 0;
}
atEOF=false;
}
/* reading size of data */
nb = ::read(fd, &s, sizeof(uint32_t));
if (nb <= 0) {
- atEOF = true; /* TODO: check this */
+ atEOF = true; /* TODO: check this */
return 0;
}
- if (s > count) { /* not enough buffer to read block */
+ 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 */
+ if (!s) { /* EOF */
atEOF = true;
if (read_fm(VT_SKIP_EOF)) {
- current_file++;
+ current_file++;
}
return 0;
current_block = -1;
Dmsg0(dbglevel, "EOT during reading\n");
return -1;
- } /* read ok */
+ } /* read ok */
if (current_block >= 0) {
current_block++;
return nb;
}
-int vtape::open(const char *pathname, int uflags)
+int vtape::d_open(const char *pathname, int uflags)
{
- Dmsg2(dbglevel, "vtape::open(%s, %i)\n", pathname, uflags);
+ Dmsg2(dbglevel, "vtape::d_open(%s, %i)\n", pathname, uflags);
- online = true; /* assume that drive contains a tape */
+ online = true; /* assume that drive contains a tape */
- struct stat statp;
+ struct stat statp;
if (stat(pathname, &statp) != 0) {
fd = -1;
Dmsg1(dbglevel, "Can't stat on %s\n", pathname);
if (uflags & O_NONBLOCK) {
- online = false;
+ online = false;
fd = ::open("/dev/null", O_CREAT | O_RDWR | O_LARGEFILE, 0600);
}
} else {
/* If the vtape is empty, start by writing a EOF */
if (online && !read_fm(VT_READ_EOF)) {
- weof();
+ lseek(fd, 0, SEEK_SET); /* rewind */
+ cur_FM = next_FM = last_FM = 0; /* reset */
+ weof(); /* write the first EOF */
last_file = current_file=0;
}
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);
-}
-
-#else /* USE_VTAPE */
-
-int vtape_ioctl(int fd, unsigned long int request, ...)
-{
- return -1;
-}
-
-int vtape_open(const char *pathname, int flags, ...)
-{
- return -1;
-}
-
-int vtape_close(int fd)
-{
- return -1;
-}
-
-void vtape_debug(int level)
-{
-}
-
-ssize_t vtape_read(int fd, void *buffer, size_t count)
-{
- return -1;
-}
-
-ssize_t vtape_write(int fd, const void *buffer, size_t count)
-{
- return -1;
+ atEOF, atEOT, atEOD, atBOT);
}
-#endif /* ! USE_VTAPE */
+#endif /* ! USE_VTAPE */