int faketape_open(const char *pathname, int flags, int mode)
{
+ ASSERT(pathname != NULL);
+
int fd;
faketape *tape = new faketape();
fd = tape->open(pathname, flags, mode);
int faketape::tape_op(struct mtop *mt_com)
{
int result=0;
- struct stat statp;
switch (mt_com->mt_op)
{
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;
+ current_file = current_file - mt_com->mt_count;
if (current_file < 0) {
current_file = 0;
errno = EIO;
}
atEOD = false;
atEOF = false;
- atEOM = false;
+ atBOT = false;
open_file();
break;
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);
+ lseek(cur_fd, SEEK_CUR, tape_info.block_size*mt_com->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);
+ result = -1;
break;
case MTWEOF: /* Write mt_count filemarks. */
+ weof(mt_com->mt_count);
break;
case MTREW: /* Rewind. */
- atEOF = atEOD = atEOM = false;
+ close_file();
+ atEOF = atEOD = false;
+ atBOT = true;
current_file = 0;
- open_file();
+ current_block = 0;
break;
case MTOFFL: /* put tape offline */
- // check if can_read/can_write
- result = 0;
+ result = offline();
break;
case MTRETEN: /* Re-tension tape. */
struct dirent *dir;
struct stat statp;
+ Dmsg1(dbglevel, "delete_files %i\n", startfile);
+
fp_dir = opendir(this->volume);
if (!fp_dir) {
- this->max_file=0;
+ this->last_file=0;
this->size = 0;
return -1;
}
this->size = 0;
- /* search for all digit file */
+ /* search for all digit files
+ * and we remove all ones that are greater than
+ * startfile
+ */
while ((dir = readdir (fp_dir)) != NULL)
{
Mmsg(tmp, "%s/%s", this->volume, dir->d_name);
for(p = dir->d_name; *p && isdigit(*p); p++)
{
cur *= 10;
- cur += *p;
+ cur += *p - '0';
}
- if (!*p && cur) {
+ if (!*p && cur > 0) {
if (cur >= startfile) { /* remove it */
- unlink(tmp);
+ unlink(tmp.c_str());
} else {
if (lstat(tmp.c_str(), &statp) == 0) {
this->size += statp.st_size;
}
closedir(fp_dir);
- this->max_file = max;
+ this->last_file = max;
return max;
}
faketape::faketape()
{
- fd = 0;
- atEOF = 0;
- atEOM = 0;
+ fd = -1;
+ cur_fd = -1;
+
+ atEOF = false;
+ atBOT = false;
+ atEOT = false;
+ atEOD = false;
+ online = false;
+
+ size = 0;
+ last_file = 0;
current_file = 0;
- current_block = 0;
- max_file = 0;
+ current_block = -1;
+ max_size = 10000000;
volume = get_pool_memory(PM_NAME);
cur_file = get_pool_memory(PM_NAME);
int faketape::write(const void *buffer, unsigned int count)
{
- ASSERT(cur_fd > 0);
- if (current_block == -1) {
+ unsigned int nb;
+ check_file();
+
+ if (atEOT) {
+ return 0;
+ }
+
+ current_block++;
+
+ atBOT = false;
+
+ /* TODO: remove all files > current_file and
+ * remove blocks > current_block
+ */
+ if (count + size > max_size) {
+ Dmsg2(dbglevel,
+ "EOT writing only %i of %i requested\n",
+ max_size - size, count);
+ count = max_size - size;
+ atEOT = true;
+ }
+
+ nb = ::write(cur_fd, buffer, count);
+
+ if (nb != count) {
+ atEOT = true;
+ Dmsg2(dbglevel,
+ "Not enough space writing only %i of %i requested\n",
+ nb, count);
+ }
+
+ return nb;
+}
+
+int faketape::weof(int count)
+{
+ if (atEOT) {
+ current_block = -1;
+ return -1;
+ }
+
+ count--; /* end this file */
+ ftruncate(cur_fd, lseek(cur_fd, 0, SEEK_CUR));
+ close_file();
+ current_file++;
+
+ /* we erase all previous information */
+ if (last_file > current_file) {
+ delete_files(current_file);
+ }
+
+ for (; count>0 ; count--) {
+ current_file++;
open_file();
}
- /* remove all file > current_file */
- return ::write(cur_fd, buffer, count);
+ current_block=0;
+ atEOF = true;
+ atEOD = false;
+ return 0;
}
-int faketape::close()
+int faketape::fsf(int count)
+{
+
+/*
+ * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
+ */
+
+ if (atEOT) {
+ current_block = -1;
+ return -1;
+ }
+
+ close_file();
+
+ if (current_file + count <= last_file) {
+ current_file += count;
+ current_block = 0;
+ return 0;
+ } else {
+ current_file = last_file;
+ current_block = -1;
+ atEOT=true;
+ return -1;
+ }
+}
+
+int faketape::bsf(int count)
+{
+
+/*
+ * 1 0 -> fsf -> 2 0 -> fsf -> 2 -1
+ */
+ close_file();
+ atEOT = atEOD = false;
+
+ if (current_file - count < 0) {
+ current_file = 0;
+ current_block = 0;
+ atBOT = true;
+ return -1;
+ }
+
+ current_file = current_file - count;
+ current_block = 0;
+ if (!current_file) {
+ atBOT = true;
+ }
+
+ return 1;
+}
+
+/*
+ * Put faketape in offline mode
+ */
+int faketape::offline()
{
ASSERT(cur_fd > 0);
- ::close(cur_fd);
+
+ close_file();
+
+ cur_fd = -1;
+ atEOF = false;
+ atEOT = false;
+ atEOD = false;
+ atBOT = false;
+
+ current_file = -1;
+ current_block = -1;
+ last_file = 0;
+ return 0;
+}
+
+int faketape::close_file()
+{
+ if (cur_fd > 0) {
+ ::close(cur_fd);
+ cur_fd = -1;
+ }
+ return 0;
+}
+
+int faketape::close()
+{
+ close_file();
::close(fd);
return 0;
}
+/*
+ **rb
+ **status
+ * EOF Bacula status: file=2 block=0
+ * Device status: EOF ONLINE IM_REP_EN file=2 block=0
+ **rb
+ **status
+ * EOD EOF Bacula status: file=2 block=0
+ * Device status: EOD ONLINE IM_REP_EN file=2 block=-1
+ *
+ */
int faketape::read(void *buffer, unsigned int count)
{
- ASSERT(cur_fd > 0);
- if (current_block == -1) {
- open_file();
+ unsigned int nb;
+ check_file();
+
+ if (atEOT || atEOD) {
+ return 0;
}
- return ::read(cur_fd, buffer, count);
+
+ atBOT = false;
+
+ nb = ::read(cur_fd, buffer, count);
+ if (count != nb) {
+ atEOF = true;
+ if (current_file == last_file) {
+ atEOD = true;
+ current_block = -1;
+ }
+ Dmsg0(dbglevel, "EOF during reading\n");
+ }
+ return nb;
}
int faketape::read_volinfo()
struct stat statp;
memset(&tape_info, 0, sizeof(FTAPE_FORMAT));
- Dmsg2(0, "Info %p %p\n", cur_info, volume);
+ Dmsg2(0, "read_volinfo %p %p\n", cur_info, volume);
Mmsg(cur_info, "%s/info", volume);
fd = ::open(cur_info, O_CREAT | O_RDWR | O_BINARY, 0640);
return -1;
}
- fstat(cur_info, &statp);
+ fstat(fd, &statp);
/* read volume info */
int nb = ::read(fd, &tape_info, sizeof(FTAPE_FORMAT));
fp_dir = opendir(this->volume);
if (!fp_dir) {
- max_file=0;
+ last_file=0;
return -1;
}
}
closedir(fp_dir);
- this->max_file = max;
+ this->last_file = max;
return max;
}
int faketape::open_file()
{
- if (cur_fd) {
+ ASSERT(current_file >= 0);
+ if (cur_fd > 0) {
::close(cur_fd);
}
return -1;
}
current_block = 0;
- max_file = (max_file > current_file)?max_file:current_file;
+ last_file = (last_file > current_file)?last_file:current_file;
+
+ Dmsg1(dbglevel, "open_file %s %i\n", cur_file);
return cur_fd;
void faketape::dump()
{
- Dmsg1(dbglevel, "max_file=%i\n", max_file);
+ Dmsg0(dbglevel, "===================\n");
+ Dmsg1(dbglevel, "last_file=%i\n", last_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);
+ Dmsg1(dbglevel, "EOF=%i\n", atEOF);
+ Dmsg1(dbglevel, "EOT=%i\n", atEOT);
+ Dmsg1(dbglevel, "EOD=%i\n", atEOD);
}
+/****************************************************************
+
+#define GMT_EOF(x) ((x) & 0x80000000)
+#define GMT_BOT(x) ((x) & 0x40000000)
+#define GMT_EOT(x) ((x) & 0x20000000)
+#define GMT_SM(x) ((x) & 0x10000000)
+#define GMT_EOD(x) ((x) & 0x08000000)
+
+
+ GMT_EOF(x) : La bande est positionnée juste après une filemark (toujours faux
+ après une opération MTSEEK).
+
+ GMT_BOT(x) : La bande est positionnée juste au début du premier fichier
+ (toujours faux après une opération MTSEEK).
+
+ GMT_EOT(x) : Une opération a atteint la fin physique de la bande (End Of
+ Tape).
+
+ GMT_SM(x) : La bande est positionnée sur une setmark (toujours faux après une
+ opération MTSEEK).
+
+ GMT_EOD(x) : La bande est positionnée à la fin des données enregistrées.
+
+
+blkno = -1 (after MTBSF MTBSS or MTSEEK)
+fileno = -1 (after MTBSS or MTSEEK)
+
+*** mtx load
+drive type = Generic SCSI-2 tape
+drive status = 0
+sense key error = 0
+residue count = 0
+file number = 0
+block number = 0
+Tape block size 0 bytes. Density code 0x0 (default).
+Soft error count since last status=0
+General status bits on (41010000):
+ BOT ONLINE IM_REP_EN
+
+*** read empty block
+dd if=/dev/lto2 of=/tmp/toto count=1
+dd: lecture de `/dev/lto2': Ne peut allouer de la mémoire
+0+0 enregistrements lus
+0+0 enregistrements écrits
+1 octet (1B) copié, 4,82219 seconde, 0,0 kB/s
+
+file number = 0
+block number = 1
+
+*** read file mark
+dd if=/dev/lto2 of=/tmp/toto count=1
+0+0 enregistrements lus
+0+0 enregistrements écrits
+1 octet (1B) copié, 0,167274 seconde, 0,0 kB/s
+
+file number = 1
+block number = 0
+
+ *** write 2 blocks after rewind
+dd if=/dev/zero of=/dev/lto2 count=2
+2+0 enregistrements lus
+2+0 enregistrements écrits
+1024 octets (1,0 kB) copiés, 6,57402 seconde, 0,2 kB/s
+
+file number = 1
+block number = 0
+
+*** write 2 blocks
+file number = 2
+block number = 0
+
+*** rewind and fsr
+file number = 0
+block number = 1
+
+*** rewind and 2x fsr (we have just 2 blocks)
+file number = 0
+block number = 2
+
+*** fsr
+mt: /dev/lto2: Erreur
+file number = 1
+block number = 0
+
+
+ ****************************************************************/
+
+
#ifdef TEST
int main()
}
faketape *tape = get_tape(fd);
+ tape->write("test", strlen("test")+1);
+ tape->write("test", strlen("test")+1);
tape->dump();
+ tape->weof(1);
+ tape->write("test", strlen("test")+1);
+ tape->write("test", strlen("test")+1);
+ tape->dump();
+ tape->fsf(2);
+ tape->dump();
faketape_close(fd);
return 0;