From e041a87b48665e5fbce3582eb20503562ab2b969 Mon Sep 17 00:00:00 2001 From: Eric Bollengier Date: Fri, 2 May 2008 21:03:42 +0000 Subject: [PATCH] ebl Start a new faketape driver. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@6880 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/patches/testing/faketape.c | 615 ++++++++++++++++++++++++++++++ bacula/patches/testing/faketape.h | 104 +++++ 2 files changed, 719 insertions(+) create mode 100644 bacula/patches/testing/faketape.c create mode 100644 bacula/patches/testing/faketape.h diff --git a/bacula/patches/testing/faketape.c b/bacula/patches/testing/faketape.c new file mode 100644 index 0000000000..c9196d9282 --- /dev/null +++ b/bacula/patches/testing/faketape.c @@ -0,0 +1,615 @@ +/* + 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. +*/ + +#include "faketape.h" +#include +#include +#include + +static int tape_get(int fd, struct mtget *mt_get); +static int tape_op(int fd, struct mtop *mt_com); +static int tape_pos(int fd, struct mtpos *mt_pos); + +static int dbglevel = 0; + + +faketape *ftape_list[FTAPE_MAX_DRIVE]; + +static faketape *get_tape(int fd) +{ + ASSERT(fd >= 0); + + if (fd >= FTAPE_MAX_DRIVE) { + /* error */ + return NULL; + } + + return ftape_list[fd]; +} + +static bool put_tape(faketape *ftape) +{ + ASSERT(ftape != NULL); + + int fd = ftape->get_fd(); + if (fd >= FTAPE_MAX_DRIVE) { + /* error */ + return false; + } + ftape_list[fd] = ftape; + return true; +} + +int faketape_open(const char *pathname, int flags, int mode) +{ + int fd; + faketape *tape = new faketape(); + fd = tape->open(pathname, flags, mode); + if (fd > 0) { + put_tape(tape); + } + return fd; +} + +int faketape_read(int fd, void *buffer, unsigned int count) +{ + faketape *tape = get_tape(fd); + ASSERT(tape != NULL); + return tape->read(buffer, count); +} + +int faketape_write(int fd, const void *buffer, unsigned int count) +{ + faketape *tape = get_tape(fd); + ASSERT(tape != NULL); + return tape->write(buffer, count); +} + +int faketape_close(int fd) +{ + faketape *tape = get_tape(fd); + ASSERT(tape != NULL); + tape->close(); + delete tape; + return 0; +} + +int faketape_ioctl(int fd, unsigned long int request, ...) +{ + va_list argp; + int result=0; + + faketape *t = get_tape(fd); + if (!t) { + errno = EBADF; + return -1; + } + + va_start(argp, request); + +// switch (request) { +// case MTIOCTOP: + result = t->tape_op(va_arg(argp, mtop *)); +// break; + +// case MTIOCGET: +// result = tape_get(fd, va_arg(argp, mtget *)); +// break; +// +// case MTIOCPOS: +// result = tape_pos(fd, va_arg(argp, mtpos *)); +// break; +// +// default: +// errno = ENOTTY; +// result = -1; +// break; +// } + + va_end(argp); + + return result; +} + +int faketape::tape_op(struct mtop *mt_com) +{ + int result=0; + struct stat statp; + + 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. */ + /* we are already at EOT */ + if (current_file > max_file) { + atEOF = true; + errno = EIO; + result = -1; + } + + /* we are at the last file */ + if (current_file == max_file) { + current_file++; + atEOF = true; + } + + break; + + case MTBSF: /* Backward space over mt_count filemarks. */ + current_file = current_file - mt_op->mt_count; + if (current_file < 0) { + current_file = 0; + errno = EIO; + result = -1; + } + atEOD = false; + atEOF = false; + atEOM = false; + open_file(); + 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'entrée/sortie + + file number = 2 + block number = 0 +*/ + /* tester si on se trouve a la fin du fichier */ + fseek(cur_fd, SEEK_CUR, tape_info.block_size*mt_op->mt_count); + break; + + case MTBSR: /* Backward space over mt_count records (tape blocks). */ + +/* + file number = 1 + block number = -1 + + mt: /dev/lto2: Erreur d'entrée/sortie + + file number = 0 + block number = -1 +*/ + + fstat(cur_file, &statp); + off_t cur_pos = lseek(cur_fd, 0, SEEK_CUR); + + fseek(cur_fd, SEEK_CUR, tape_info.block_size*mt_op->mt_count); + break; + + case MTWEOF: /* Write mt_count filemarks. */ + break; + + case MTREW: /* Rewind. */ + atEOF = atEOD = atEOM = false; + current_file = 0; + open_file(); + break; + + case MTOFFL: /* put tape offline */ + // check if can_read/can_write + result = 0; + 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). */ +/* + file number = 3 + block number = -1 +*/ + /* Can be at EOM */ + atEOF = true; + current_block = -1; + /* Ne pas creer le fichier si on est a la fin */ + + break; + + case MTERASE: + atEOD = true; + atEOF = false; + atEOT = false; + current_file = 0; + current_block = -1; + delete_files(current_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; + } +// +// switch (result) { +// case NO_ERROR: +// case -1: /* Error has already been translated into errno */ +// break; +// +// default: +// case ERROR_FILEMARK_DETECTED: +// errno = EIO; +// break; +// +// case ERROR_END_OF_MEDIA: +// errno = EIO; +// break; +// +// case ERROR_NO_DATA_DETECTED: +// errno = EIO; +// break; +// +// case ERROR_NO_MEDIA_IN_DRIVE: +// errno = ENOMEDIUM; +// break; +// +// case ERROR_INVALID_HANDLE: +// case ERROR_ACCESS_DENIED: +// case ERROR_LOCK_VIOLATION: +// errno = EBADF; +// break; +// } +// + return result == 0 ? 0 : -1; +} + +int faketape::tape_get(struct mtget *mt_get) +{ + return 0; +} + +int faketape::tape_pos(struct mtpos *mt_pos) +{ + return 0; +} + +int faketape::delete_files(int startfile) +{ + int cur,max=0; + char *p; + POOL_MEM tmp; + DIR *fp_dir; + struct dirent *dir; + struct stat statp; + + fp_dir = opendir(this->volume); + if (!fp_dir) { + this->max_file=0; + this->size = 0; + return -1; + } + + this->size = 0; + + /* search for all digit file */ + while ((dir = readdir (fp_dir)) != NULL) + { + Mmsg(tmp, "%s/%s", this->volume, dir->d_name); + cur = 0; + /* check if d_name contains only digits */ + for(p = dir->d_name; *p && isdigit(*p); p++) + { + cur *= 10; + cur += *p; + } + if (!*p && cur) { + if (cur >= startfile) { /* remove it */ + unlink(tmp); + } else { + if (lstat(tmp.c_str(), &statp) == 0) { + this->size += statp.st_size; + } + max = (max > cur)?max:cur; + } + } + } + + closedir(fp_dir); + this->max_file = max; + return max; +} + +faketape::faketape() +{ + fd = 0; + atEOF = 0; + atEOM = 0; + current_file = 0; + current_block = 0; + max_file = 0; + + volume = get_pool_memory(PM_NAME); + cur_file = get_pool_memory(PM_NAME); + cur_info = get_pool_memory(PM_NAME); +} + +faketape::~faketape() +{ + free_pool_memory(volume); + free_pool_memory(cur_file); + free_pool_memory(cur_info); +} + +int faketape::get_fd() +{ + return this->fd; +} + +int faketape::write(const void *buffer, unsigned int count) +{ + ASSERT(cur_fd > 0); + if (current_block == -1) { + open_file(); + } + /* remove all file > current_file */ + return ::write(cur_fd, buffer, count); +} + +int faketape::close() +{ + ASSERT(cur_fd > 0); + ::close(cur_fd); + ::close(fd); + + return 0; +} + +int faketape::read(void *buffer, unsigned int count) +{ + ASSERT(cur_fd > 0); + if (current_block == -1) { + open_file(); + } + return ::read(cur_fd, buffer, count); +} + +int faketape::read_volinfo() +{ + struct stat statp; + memset(&tape_info, 0, sizeof(FTAPE_FORMAT)); + + Dmsg2(0, "Info %p %p\n", cur_info, volume); + Mmsg(cur_info, "%s/info", volume); + fd = ::open(cur_info, O_CREAT | O_RDWR | O_BINARY, 0640); + + if (fd < 0) { + return -1; + } + + fstat(cur_info, &statp); + + /* read volume info */ + int nb = ::read(fd, &tape_info, sizeof(FTAPE_FORMAT)); + if (nb != sizeof(FTAPE_FORMAT)) { /* new tape ? */ + Dmsg1(dbglevel, "Initialize %s\n", volume); + tape_info.version = 1; + tape_info.block_max = 2000000; + tape_info.block_size = statp.st_blksize; + tape_info.max_file_mark = 2000; + + lseek(fd, SEEK_SET, 0); + nb = ::write(fd, &tape_info, sizeof(FTAPE_FORMAT)); + + if (nb != sizeof(FTAPE_FORMAT)) { + ::close(fd); + return -1; + } + } + + Dmsg0(dbglevel, "read_volinfo OK\n"); + find_maxfile(); + + return fd; +} + +int faketape::open(const char *pathname, int uflags, int umode) +{ + Dmsg3(dbglevel, "faketape::open(%s, %i, %i)\n", pathname, uflags, umode); + pm_strcpy(volume, pathname); + + struct stat statp; + if (lstat(volume, &statp) != 0) { + Dmsg1(dbglevel, "Can't stat on %s\n", volume); + return -1; + } + + if (!S_ISDIR(statp.st_mode)) { + Dmsg1(dbglevel, "%s is not a directory\n", volume); + errno = EACCES; + return -1; + } + + /* open volume descriptor and get this->fd */ + if (read_volinfo() < 0) { + return -1; + } + + current_block=-1; + + return fd; +} + +int faketape::find_maxfile() +{ + int max=0; + int cur; + char *p; + POOL_MEM tmp; + DIR *fp_dir; + struct dirent *dir; + struct stat statp; + + fp_dir = opendir(this->volume); + if (!fp_dir) { + max_file=0; + return -1; + } + + this->size = 0; + + /* search for all digit file */ + while ((dir = readdir (fp_dir)) != NULL) + { + Mmsg(tmp, "%s/%s", this->volume, dir->d_name); + if (lstat(tmp.c_str(), &statp) == 0) { + this->size += statp.st_size; + } else { + Dmsg1(dbglevel, "Can't stat %s\n", tmp.c_str()); + } + cur = 0; + /* TODO: compute size */ + for(p = dir->d_name; *p && isdigit(*p); p++) + { + cur *= 10; + cur += *p; + } + if (!*p && cur) { + max = (max > cur)?max:cur; + } + } + + closedir(fp_dir); + this->max_file = max; + return max; +} + +int faketape::open_file() +{ + if (cur_fd) { + ::close(cur_fd); + } + + Mmsg(cur_file, "%s/%i", volume, current_file); + cur_fd = ::open(cur_file, O_CREAT | O_RDWR | O_BINARY, 0640); + if (cur_fd < 0) { + return -1; + } + current_block = 0; + max_file = (max_file > current_file)?max_file:current_file; + + return cur_fd; + +} + +void faketape::dump() +{ + Dmsg1(dbglevel, "max_file=%i\n", max_file); + Dmsg1(dbglevel, "current_file=%i\n", current_file); + Dmsg1(dbglevel, "volume=%s\n", volume); + Dmsg1(dbglevel, "cur_info=%s\n", cur_info); + Dmsg1(dbglevel, "cur_file=%s\n", cur_file); + Dmsg1(dbglevel, "size=%i\n", size); +} + +#ifdef TEST + +int main() +{ + int fd; + printf("Starting FakeTape\n"); + + mkdir("/tmp/fake", 0777); + fd = faketape_open("/tmp/fake", O_CREAT | O_RDWR | O_BINARY, 0666); + if (fd < 0) { + perror("open ERR"); + return 1; + } + + faketape *tape = get_tape(fd); + tape->dump(); + + faketape_close(fd); + + return 0; +} + +#endif diff --git a/bacula/patches/testing/faketape.h b/bacula/patches/testing/faketape.h new file mode 100644 index 0000000000..47065e530a --- /dev/null +++ b/bacula/patches/testing/faketape.h @@ -0,0 +1,104 @@ +/* + 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. +*/ +/* + * faketape.h - Emulate the Linux st (scsi tape) driver on file. + * for regression and bug hunting purpose + * + */ + +#ifndef FAKETAPE_H +#define FAKETAPE_H + +#include +#include +#include "bacula.h" + +typedef struct +{ + /* format infos */ + int16_t version; + int16_t max_file_mark; + int16_t block_size; + int32_t block_max; +} FTAPE_FORMAT; + +#define FTAPE_MAX_DRIVE 20 + +/* + * Theses functions will replace open/read/write + */ +int faketape_open(const char *pathname, int flags, int mode); +int faketape_read(int fd, void *buffer, unsigned int count); +int faketape_write(int fd, const void *buffer, unsigned int count); +int faketape_close(int fd); +int faketape_ioctl(int fd, unsigned long int request, ...); + +class faketape { +private: + int fd; /* Our file descriptor */ + + int cur_fd; /* OS file descriptor */ + off_t size; /* size */ + + bool atEOF; /* End of file */ + bool atEOM; /* End of media */ + bool atEOD; /* End of data */ + + POOLMEM *volume; /* volume name */ + POOLMEM *cur_info; /* volume info */ + POOLMEM *cur_file; /* current file name */ + + int16_t max_file; + int16_t current_file; /* max 65000 files */ + int32_t current_block; /* max 4G blocks of 1KB */ + + FTAPE_FORMAT tape_info; + + void destroy(); + int read_volinfo(); /* read current volume format */ + int find_maxfile(); + int open_file(); + int delete_files(); + +public: + faketape(); + ~faketape(); + + int get_fd(); + void dump(); + int open(const char *pathname, int flags, int mode); + 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 /* !FAKETAPE_H */ -- 2.39.5