Switzerland, email:ftf@fsfeurope.org.
*/
+/*
+ * Maximum File Size = 800G
+ *
+ */
+
#include "faketape.h"
#include <dirent.h>
#include <sys/mtio.h>
return true;
}
+void faketape_debug(int level)
+{
+ dbglevel = level;
+}
+
/****************************************************************/
/* theses function will replace open/read/write/close/ioctl
* in bacula core
break;
case MTBSF: /* Backward space over mt_count filemarks. */
- current_file = current_file - mt_com->mt_count;
- if (current_file < 0) {
- current_file = 0;
- errno = EIO;
- result = -1;
- }
- atEOD = false;
- atEOF = false;
- atBOT = false;
- seek_file();
+ result = bsf(mt_com->mt_count);
break;
case MTFSR: /* Forward space over mt_count records (tape blocks). */
*/
/* Can be at EOM */
atBOT = false;
- atEOF = true;
+ atEOF = false;
atEOD = true;
- current_file = last_file+1;
+
+ current_file = last_file;
current_block = -1;
seek_file();
- /* Ne pas creer le fichier si on est a la fin */
-
break;
case MTERASE: /* not used by bacula */
atEOD = true;
atEOF = false;
atEOT = false;
+
current_file = 0;
current_block = -1;
seek_file();
*/
int faketape::truncate_file()
{
+ Dmsg2(dbglevel, "truncate %i:%i\n", current_file, current_block);
ftruncate(fd, lseek(fd, 0, SEEK_CUR));
+ last_file = current_file;
return 0;
}
atEOT = false;
atEOD = false;
online = false;
+ inplace = false;
file_size = 0;
last_file = 0;
return this->fd;
}
+/*
+ * TODO: regarder si apres un write une operation x pose un EOF
+ */
int faketape::write(const void *buffer, unsigned int count)
{
- ASSERT(count >= 0);
+ ASSERT(current_file >= 0);
+ ASSERT(count > 0);
ASSERT(buffer);
unsigned int nb;
if (atEOT) {
Dmsg0(dbglevel, "write nothing, EOT !\n");
- return 0;
+ errno = ENOSPC;
+ return -1;
+ }
+
+ if (!inplace) {
+ seek_file();
}
if (!atEOD) { /* if not at the end of the data */
truncate_file();
- weof(1);
-
- } else { /* already writing something */
- if (current_block != -1) {
- current_block++;
- }
+ }
+
+ if (current_block != -1) {
+ current_block++;
}
atBOT = false;
- atEOD = true;
+ atEOD = false;
+ atEOF = false;
// if ((count + file_size) > max_size) {
// Dmsg2(dbglevel,
int faketape::weof(int count)
{
- Dmsg2(dbglevel, "Writing EOF %i:%i\n", current_file, current_block);
+ char c=0;
+ ASSERT(current_file >= 0);
+ Dmsg3(dbglevel, "Writing EOF %i:%i last=%i\n",
+ current_file, current_block,last_file);
+
if (atEOT) {
current_block = -1;
return -1;
}
- count--; /* end this file */
truncate_file(); /* nothing after this point */
- current_file++;
- atEOF = true;
- atEOD = false;
+ /* TODO: check this */
+ current_file += count;
+ current_block = 0;
- if (count > 0) {
- current_block = -1;
- return -1;
- } else {
- current_block = 0;
- }
seek_file();
+ ::write(fd, &c, sizeof(c));
+ seek_file();
+
+ atEOD = false;
+ atBOT = false;
+ atEOF = true;
return 0;
}
int faketape::fsf(int count)
{
+ ASSERT(current_file >= 0);
+ ASSERT(fd >= 0);
/*
* 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
*/
return -1;
}
- atEOF=1;
+ atBOT = atEOF = false;
Dmsg3(dbglevel+1, "fsf %i+%i <= %i\n", current_file, count, last_file);
if ((current_file + count) <= last_file) {
atEOD=true;
ret = -1;
}
-
seek_file();
+// read_eof();
return ret;
}
int faketape::fsr(int count)
{
- int i,nb;
+ ASSERT(current_file >= 0);
+ ASSERT(fd >= 0);
+ int i,nb, ret=0;
off_t where=0, s;
Dmsg2(dbglevel, "fsr current_block=%i count=%i\n", current_block, count);
- if (atEOT) {
+ if (atEOT || atEOF) {
+ errno = EIO;
current_block = -1;
return -1;
}
+ if (atEOD) {
+ errno = EIO;
+ return -1;
+ }
+
+ atEOF = false;
+
+ if (current_block < 0) {
+ errno = EIO;
+ return -1;
+ }
+
/* check all block record */
- for(i=0; (i < count) && (where != -1) ; i++) {
- nb = ::read(fd, &s, sizeof(s)); /* get size of block */
- if (nb == sizeof(s)) {
+ for(i=0; (i < count) && !atEOF ; i++) {
+ nb = ::read(fd, &s, sizeof(s)); /* get size of next block */
+ if (nb == sizeof(s) && s) {
current_block++;
where = lseek(fd, s, SEEK_CUR); /* seek after this block */
- if (where == -1) {
- errno = EIO;
- return -1;
- }
} else {
errno = EIO;
- return -1;
+ ret = -1;
+ if (current_file < last_file) {
+ current_block = 0;
+ current_file++;
+ seek_file();
+ }
+ atEOF = true; /* stop the loop */
}
}
+
find_maxfile(); /* refresh stats */
- if (where == file_size) {
+ if (i) {
atBOT = false;
+ }
+
+ if (where == file_size) {
atEOD = true;
}
+ return ret;
+}
+
+int faketape::read_eof()
+{
+ int s, nb;
+ off_t old = lseek(fd, 0, SEEK_CUR);
+ nb = ::read(fd, &s, sizeof(s));
+ if (nb >= 0 && (nb != sizeof(s) || !s)) { /* EOF */
+ atEOF = true;
+ }
+ lseek(fd, old, SEEK_SET);
return 0;
}
int faketape::bsf(int count)
{
- int ret = 1;
- atEOT = atEOD = false;
+ ASSERT(current_file >= 0);
+ Dmsg3(dbglevel, "bsf %i:%i count=%i\n", current_file, current_block, count);
+ int ret = 0;
+ atBOT = atEOF = atEOT = atEOD = false;
if (current_file - count < 0) {
current_file = 0;
current_block = 0;
atBOT = true;
ret = -1;
- }
+ } else {
- current_file = current_file - count;
- current_block = 0;
- if (!current_file) {
- atBOT = true;
+ current_file = current_file - count;
+ current_block = -1;
+ if (!current_file) {
+ atBOT = true;
+ }
}
seek_file();
- return 0;
+ return ret;
}
/*
{
close();
- atEOF = false;
- atEOT = false;
- atEOD = false;
- atBOT = false;
+ atEOF = false; /* End of file */
+ atEOT = false; /* End of tape */
+ atEOD = false; /* End of data */
+ atBOT = false; /* Begin of tape */
current_file = -1;
current_block = -1;
int faketape::read(void *buffer, unsigned int count)
{
+ ASSERT(current_file >= 0);
unsigned int nb, s;
if (atEOT || atEOD) {
return 0;
}
+ if (!inplace) {
+ seek_file();
+ }
+
atBOT = false;
current_block++;
errno = ENOMEM;
return -1;
}
+ if (!s) { /* EOF */
+ atEOF = true;
+ lseek(fd, lseek(fd, 0, SEEK_CUR) - sizeof(s), SEEK_SET);
+ errno = ENOMEM;
+ return -1;
+ }
nb = ::read(fd, buffer, s);
if (s != nb) {
atEOF = true;
return -1;
}
- current_block=-1;
+ current_block = 0;
+ current_file = 0;
+
+ inplace = true;
+ atBOT = true;
+ atEOT = atEOD = false;
return fd;
}
int faketape::find_maxfile()
{
struct stat statp;
- fstat(fd, &statp);
- last_file = statp.st_size % ((off_t)1<<32);
+ if (fstat(fd, &statp) != 0) {
+ return 0;
+ }
+ last_file = statp.st_size>>30;
file_size = statp.st_size;
current_pos = lseek(fd, 0, SEEK_CUR); /* get current position */
+ Dmsg3(dbglevel, "last_file=%i file_size=%u current_pos=%i\n",
+ last_file, file_size, current_pos);
return last_file;
}
int faketape::seek_file()
{
+ ASSERT(current_file >= 0);
Dmsg2(dbglevel, "seek_file %i:%i\n", current_file, current_block);
- off_t pos = ((off_t)current_file)<<32;
+ off_t pos = ((off_t)current_file)<<30;
if(lseek(fd, pos, SEEK_SET) == -1) {
return -1;
}
- fsr(current_block);
+ if (current_block > 0) {
+ fsr(current_block);
+ }
last_file = (last_file > current_file)?last_file:current_file;
+ inplace = true;
+
return 0;
}
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, ...);
+void faketape_debug(int level);
class faketape {
private:
bool atEOD; /* End of data */
bool atBOT; /* Begin of tape */
bool online; /* volume online */
+ bool inplace; /* have to seek before writing ? */
POOLMEM *volume; /* volume name */
- int16_t last_file; /* last file of the volume */
- int16_t current_file; /* max 65000 files */
+ int32_t last_file; /* last file of the volume */
+ int32_t current_file; /* max 65000 files */
int32_t current_block; /* max 4G blocks of 1KB */
off_t current_pos; /* current position in stream */
int offline();
int truncate_file();
int seek_file();
+ int read_eof();
public:
int fsf(int count);
#define read faketape_read
#define close faketape_close
#define ioctl faketape_ioctl
+#define debug(x) faketape_debug(x)
+#else
+#define debug(x)
#endif
static int fd;
{
struct mtget mt_get;
ioctl(fd, MTIOCGET, &mt_get);
- printf("file:block %i:%i\n", mt_get.mt_fileno, mt_get.mt_blkno);
+ printf("*** file:block %i:%i BOT=%u EOD=%u EOF=%u\n",
+ mt_get.mt_fileno, mt_get.mt_blkno,
+ GMT_BOT(mt_get.mt_gstat) != 0,
+ GMT_EOD(mt_get.mt_gstat) != 0,
+ GMT_EOF(mt_get.mt_gstat) != 0
+ );
}
-int main()
+int main(int argc, char **argv)
{
- int r1, r2;
+ int r1;
char c[200];
struct mtop mt_com;
+
+ if (argc > 1) {
+ debug(atoi(argv[1]));
+ }
fd = open("/dev/lto2", O_CREAT | O_RDWR, 0700);
if (fd < 0) {
exit(1);
}
+ print_pos();
+
/* rewind */
+ printf("\n*** rewind\n");
mt_com.mt_count = 1;
mt_com.mt_op = MTREW;
r1 = ioctl(fd, MTIOCTOP, &mt_com);
- printf("rewind\n");
print_pos();
/* write something */
+ printf("\n*** write something (3 writes)\n");
write(fd, "abcdefghijklmnopqrstuvwyz", strlen("abcdefghijklmnopqrstuvwyz")+1);
write(fd, "abcdefghijklmnopqrstuvwyz", strlen("abcdefghijklmnopqrstuvwyz")+1);
write(fd, "abcdefghijklmnopqrstuvwyz", strlen("abcdefghijklmnopqrstuvwyz")+1);
- printf("write something (3 writes)\n");
print_pos();
/* write EOF */
- printf("WEOF\n");
+ printf("\n*** WEOF\n");
mt_com.mt_op = MTWEOF;
mt_com.mt_count = 1;
r1 = ioctl(fd, MTIOCTOP, &mt_com);
print_pos();
/* write a second file */
+ printf("\n*** write something\n");
write(fd, "abcdefghijklmnopqrstuvwyz", strlen("abcdefghijklmnopqrstuvwyz")+1);
- printf("write something\n");
print_pos();
/* rewind */
+ printf("\n*** rewind\n");
mt_com.mt_count = 1;
mt_com.mt_op = MTREW;
r1 = ioctl(fd, MTIOCTOP, &mt_com);
- printf("rewind\n");
/* read something with error */
+ printf("\n*** read c=%s len=%i\n", c, r1);
errno=0;
r1 = read(fd, c, 2);
c[r1] = 0;
- printf("read c=%s len=%i errno=%i\n", c, r1, errno);
perror("");
print_pos();
/* read something */
+ printf("\n*** read c=%s len=%i\n", c, r1);
errno=0;
r1 = read(fd, c, 200);
c[r1] = 0;
- printf("read c=%s len=%i\n", c, r1);
print_pos();
/* write something */
- printf("write something\n");
+ printf("\n*** write something\n");
write(fd, "abcdefghijklmnopqrstuvwyz", strlen("abcdefghijklmnopqrstuvwyz")+1);
print_pos();
/* rewind */
+ printf("\n*** rewind\n");
mt_com.mt_count = 1;
mt_com.mt_op = MTREW;
r1 = ioctl(fd, MTIOCTOP, &mt_com);
r1 = read(fd, c, 200);
c[r1] = '\0';
- printf("read c=%s len=%i\n", c, r1);
+ printf("\n*** read c=%s len=%i\n", c, r1);
r1 = read(fd, c, 200);
c[r1] = '\0';
- printf("read c=%s len=%i\n", c, r1);
+ printf("\n*** read c=%s len=%i\n", c, r1);
/* write EOF */
- printf("WEOF\n");
+ printf("\n*** WEOF");
mt_com.mt_op = MTWEOF;
mt_com.mt_count = 1;
r1 = ioctl(fd, MTIOCTOP, &mt_com);
+ printf(" r=%i\n", r1);
print_pos();
/* FSF */
+ printf("\n*** fsf x1");
mt_com.mt_op = MTFSF;
mt_com.mt_count = 1;
r1 = ioctl(fd, MTIOCTOP, &mt_com);
- printf("fsf r=%i\n", r1);
+ printf(" r=%i\n", r1);
print_pos();
/* write something */
- printf("write something\n");
+ printf("\n*** write something\n");
write(fd, "abcdefghijklmnopqrstuvwyz", strlen("abcdefghijklmnopqrstuvwyz")+1);
print_pos();
/* FSF */
+ printf("\n*** fsf");
mt_com.mt_op = MTFSF;
mt_com.mt_count = 1;
r1 = ioctl(fd, MTIOCTOP, &mt_com);
- printf("fsf r=%i\n", r1);
+ printf(" r=%i\n", r1);
print_pos();
/* WEOF */
+ printf("\n*** weof 3");
mt_com.mt_op = MTWEOF;
mt_com.mt_count = 3;
r1 = ioctl(fd, MTIOCTOP, &mt_com);
- printf("weof 3 r=%i\n", r1);
+ printf(" r=%i\n", r1);
print_pos();
/* rewind */
+ printf("\n*** rewind\n");
mt_com.mt_count = 1;
mt_com.mt_op = MTREW;
r1 = ioctl(fd, MTIOCTOP, &mt_com);
- printf("rewind\n");
print_pos();
/* FSR */
+ printf("\n*** fsr x10");
mt_com.mt_op = MTFSR;
mt_com.mt_count = 10;
r1 = ioctl(fd, MTIOCTOP, &mt_com);
- printf("fsr r=%i\n", r1);
+ printf(" r=%i\n", r1);
print_pos();
/* eom */
+ printf("\n*** goto eom");
mt_com.mt_count = 1;
mt_com.mt_op = MTEOM;
r1 = ioctl(fd, MTIOCTOP, &mt_com);
- printf("goto eom\n");
+ printf(" r=%i\n", r1);
+ print_pos();
+
+ /* fsr */
+ printf("\n*** fsr");
+ mt_com.mt_count = 1;
+ mt_com.mt_op = MTFSR;
+ r1 = ioctl(fd, MTIOCTOP, &mt_com);
+ printf(" r=%i\n", r1);
+ print_pos();
+
+ /* write something */
+ printf("\n*** write something\n");
+ write(fd, "abcdefghijklmnopqrstuvwyz", strlen("abcdefghijklmnopqrstuvwyz")+1);
+ print_pos();
+
+ /* rewind */
+ printf("\n*** rewind");
+ mt_com.mt_count = 1;
+ mt_com.mt_op = MTREW;
+ r1 = ioctl(fd, MTIOCTOP, &mt_com);
+ printf(" r=%i\n", r1);
+
+ /* FSF */
+ printf("\n*** fsf x2");
+ mt_com.mt_op = MTFSF;
+ mt_com.mt_count = 2;
+ r1 = ioctl(fd, MTIOCTOP, &mt_com);
+ printf(" r=%i\n", r1);
+ print_pos();
+
+ printf("\n*** fsr");
+ mt_com.mt_op = MTFSR;
+ mt_com.mt_count = 1;
+ r1 = ioctl(fd, MTIOCTOP, &mt_com);
+ printf(" r=%i\n", r1);
print_pos();
/* write something */
- printf("write something\n");
+ printf("\n*** write something\n");
write(fd, "abcdefghijklmnopqrstuvwyz", strlen("abcdefghijklmnopqrstuvwyz")+1);
print_pos();
+ printf("\n*** bsf x2");
+ mt_com.mt_op = MTBSF;
+ mt_com.mt_count = 2;
+ r1 = ioctl(fd, MTIOCTOP, &mt_com);
+ printf(" r=%i\n", r1);
+ print_pos();
+
+ printf("\n*** bsf x10");
+ mt_com.mt_op = MTBSF;
+ mt_com.mt_count = 10;
+ r1 = ioctl(fd, MTIOCTOP, &mt_com);
+ printf(" r=%i\n", r1);
+ print_pos();
+
+ printf("\n*** eom");
+ mt_com.mt_op = MTEOM;
+ mt_com.mt_count = 1;
+ r1 = ioctl(fd, MTIOCTOP, &mt_com);
+ printf(" r=%i\n", r1);
+ print_pos();
+
+ printf("\n*** bsr x10");
+ mt_com.mt_op = MTBSR;
+ mt_com.mt_count = 10;
+ r1 = ioctl(fd, MTIOCTOP, &mt_com);
+ printf(" r=%i\n", r1);
+ print_pos();
+
+ printf("\n*** eom");
+ mt_com.mt_op = MTEOM;
+ mt_com.mt_count = 1;
+ r1 = ioctl(fd, MTIOCTOP, &mt_com);
+ printf(" r=%i\n", r1);
+ print_pos();
+
+ printf("\n*** fsr");
+ mt_com.mt_op = MTFSR;
+ mt_com.mt_count = 1;
+ r1 = ioctl(fd, MTIOCTOP, &mt_com);
+ printf(" r=%i\n", r1);
+ print_pos();
+
close(fd);
return(0);
}