diff -ru ..\release\mt-st-0.9b/Makefile ./Makefile
--- ..\release\mt-st-0.9b/Makefile 2005-08-16 12:16:28.000000000 -0700
+++ ./Makefile 2006-08-09 03:26:58.292856500 -0700
@@ -1,29 +1,27 @@
+CC= mingw32-gcc
CFLAGS= -Wall -O2
-SBINDIR= /sbin
-BINDIR= /bin
-MANDIR= /usr/share/man
+PREFIX=
+SBINDIR= $(PREFIX)/sbin
+BINDIR= $(PREFIX)/bin
+MANDIR= $(PREFIX)/man
-all: mt stinit
+all: mt.exe
-mt: mt.c
- $(CC) $(CFLAGS) -o mt mt.c
+mt.exe: mt.c
+ $(CC) $(CFLAGS) -o mt.exe mt.c mtops.c
-stinit: stinit.c
+stinit.exe: stinit.c
$(CC) $(CFLAGS) -o stinit stinit.c
-install: mt stinit
- install -s mt $(BINDIR)
+install: mt.exe
+ install mt.exe $(BINDIR)
install -c -m 444 mt.1 $(MANDIR)/man1
(if [ -f $(MANDIR)/man1/mt.1.gz ] ; then \
rm -f $(MANDIR)/man1/mt.1.gz; gzip $(MANDIR)/man1/mt.1; fi)
- install -s stinit $(SBINDIR)
- install -c -m 444 stinit.8 $(MANDIR)/man8
- (if [ -f $(MANDIR)/man8/stinit.8.gz ] ; then \
- rm -f $(MANDIR)/man8/stinit.8.gz; gzip $(MANDIR)/man8/stinit.8; fi)
dist: clean
(mydir=`basename \`pwd\``;\
cd .. && tar cvvf - $$mydir | gzip -9 > $${mydir}.tar.gz)
clean:
- rm -f *~ \#*\# *.o mt stinit
+ rm -f *~ \#*\# *.o mt.exe stinit.exe
diff -ru ..\release\mt-st-0.9b/mt.1 ./mt.1
--- ..\release\mt-st-0.9b/mt.1 2005-08-21 11:53:50.000000000 -0700
+++ ./mt.1 2006-08-09 03:26:58.302871100 -0700
@@ -48,20 +48,22 @@
files.
The tape is positioned on the first block of the next file.
.IP fsfm
-Forward space
+Forward space past
.I count
-files.
-The tape is positioned on the last block of the previous file.
+file marks, then backward space one file record.
+This leaves the tape positioned on the last block of the file that is count-1
+files past the current file.
.IP bsf
Backward space
.I count
files.
The tape is positioned on the last block of the previous file.
.IP bsfm
-Backward space
+Backward space past
.I count
-files.
-The tape is positioned on the first block of the next file.
+file marks, then forward space one file record.
+This leaves the tape positioned on the first block of the file that is count-1
+files before the current file.
.IP asf
The tape is positioned at the beginning of the
.I count
diff -ru ..\release\mt-st-0.9b/mt.c ./mt.c
--- ..\release\mt-st-0.9b/mt.c 2005-08-21 11:48:06.000000000 -0700
+++ ./mt.c 2006-08-09 04:00:01.093525100 -0700
@@ -11,25 +11,35 @@
Last Modified: Sun Aug 21 21:48:06 2005 by kai.makisara
*/
+#include <windows.h>
+#include <winioctl.h>
+#include <winsock.h>
+
+#define O_NONBLOCK 0
+
#include <stdio.h>
+#if !defined(_MSC_VER)
#include <unistd.h>
+#endif
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
-#include <sys/ioctl.h>
+#include "mtops.h"
#include "mtio.h"
+#define ioctl tape_ioctl
+
#ifndef DEFTAPE
-#define DEFTAPE "/dev/tape" /* default tape device */
+#define DEFTAPE "Tape0" /* default tape device */
#endif /* DEFTAPE */
-#define VERSION "0.9b"
+#define VERSION "0.9b-bacula"
-typedef int (* cmdfunc)(/* int, struct cmdef_tr *, int, char ** */);
+typedef int (* cmdfunc)(int, struct cmdef_tr *, int, char **);
typedef struct cmdef_tr {
char *cmd_name;
@@ -143,12 +153,14 @@
FD_RDONLY, ONE_ARG, 0},
{ "defcompression", MTSETDRVBUFFER, do_drvbuffer, MT_ST_DEF_COMPRESSION,
FD_RDONLY, ONE_ARG, 0},
+#if 0
{ "stsetcln", MTSETDRVBUFFER, do_drvbuffer, MT_ST_SET_CLN,
FD_RDONLY, ONE_ARG, 0},
{ "sttimeout", MTSETDRVBUFFER, do_drvbuffer, MT_ST_SET_TIMEOUT,
FD_RDONLY, ONE_ARG, 0},
{ "stlongtimeout", MTSETDRVBUFFER, do_drvbuffer, MT_ST_SET_LONG_TIMEOUT,
FD_RDONLY, ONE_ARG, 0},
+#endif
{ "densities", 0, print_densities, 0, NO_FD, NO_ARGS,
0 },
{ "setpartition", MTSETPART, do_standard, 0, FD_RDONLY, ONE_ARG,
@@ -211,13 +223,19 @@
{0x30, "AIT-1 or MLR3"},
{0x31, "AIT-2"},
{0x32, "AIT-3"},
- {0x33, "SLR6"},
+ {0x33, "AIT-4 or SLR6"},
{0x34, "SLR100"},
+ {0x38, "AIT-E Turbo"},
+ {0x39, "AIT-1 Turbo"},
+ {0x3A, "AIT-2 Turbo"},
+ {0x3B, "AIT-3Ex"},
{0x40, "DLT1 40 GB, or Ultrium"},
{0x41, "DLT 40GB, or Ultrium2"},
{0x42, "LTO-2"},
{0x45, "QIC-3095-MC (TR-4)"},
{0x47, "TR-5"},
+ {0x48, "Quantum SDLT220"},
+ {0x49, "Quantum SDLT320"},
{0x80, "DLT 15GB uncomp. or Ecrix"},
{0x81, "DLT 15GB compressed"},
{0x82, "DLT 20GB uncompressed"},
@@ -254,20 +272,25 @@
{"no-blklimits", MT_ST_NO_BLKLIMS, "drive doesn't support read block limits"},
{"can-partitions",MT_ST_CAN_PARTITIONS,"drive can handle partitioned tapes"},
{"scsi2logical", MT_ST_SCSI2LOGICAL, "logical block addresses used with SCSI-2"},
+#if 0
{"no-wait", MT_ST_NOWAIT, "immediate mode for rewind, etc."},
+#endif
#ifdef MT_ST_SYSV
{"sysv", MT_ST_SYSV, "enable the SystemV semantics"},
#endif
+#if 0
{"cleaning", MT_ST_SET_CLN, "set the cleaning bit location and mask"},
+#endif
{NULL, 0}};
static char *tape_name; /* The tape name for messages */
- int
+int
main(int argc, char **argv)
{
- int mtfd, cmd_code, i, argn, len, oflags;
+ int mtfd, cmd_code, i, argn, oflags;
+ unsigned int len;
char *cmdstr;
cmdef_tr *comp, *comp2;
@@ -344,7 +367,7 @@
oflags = comp->cmd_fdtype == FD_RDONLY ? O_RDONLY : O_RDWR;
if ((comp->error_tests & ET_ONLINE) == 0)
oflags |= O_NONBLOCK;
- if ((mtfd = open(tape_name, oflags)) < 0) {
+ if ((mtfd = tape_open(tape_name, oflags, 0)) < 0) {
perror(tape_name);
exit(1);
}
@@ -368,7 +391,7 @@
}
if (mtfd >= 0)
- close(mtfd);
+ tape_close(mtfd);
return i;
}
@@ -409,9 +432,9 @@
do_standard(int mtfd, cmdef_tr *cmd, int argc, char **argv)
{
struct mtop mt_com;
- char *endp;
+ char *endp = NULL;
- mt_com.mt_op = cmd->cmd_code;
+ mt_com.mt_op = (short)cmd->cmd_code;
mt_com.mt_count = (argc > 0 ? strtol(*argv, &endp, 0) : 1);
if (argc > 0 && endp != *argv) {
if (*endp == 'k')
@@ -464,7 +487,8 @@
static int
do_options(int mtfd, cmdef_tr *cmd, int argc, char **argv)
{
- int i, an, len;
+ int i, an;
+ unsigned int len;
struct mtop mt_com;
mt_com.mt_op = MTSETDRVBUFFER;
@@ -596,8 +620,10 @@
type = "SCSI 1";
else if (status.mt_type == MT_ISSCSI2)
type = "SCSI 2";
+#if 0
else if (status.mt_type == MT_ISONSTREAM_SC)
type = "OnStream SC-, DI-, DP-, or USB";
+#endif
else
type = NULL;
if (type == NULL) {
@@ -607,7 +633,7 @@
printf("IDE-Tape (type code 0) ?\n");
else
printf("Unknown tape drive type (type code %ld)\n", status.mt_type);
- printf("File number=%d, block number=%d.\n",
+ printf("File number=%ld, block number=%ld.\n",
status.mt_fileno, status.mt_blkno);
printf("mt_resid: %ld, mt_erreg: 0x%lx\n",
status.mt_resid, status.mt_erreg);
@@ -617,14 +643,17 @@
else {
printf("%s tape drive:\n", type);
if (status.mt_type == MT_ISSCSI2)
- printf("File number=%d, block number=%d, partition=%ld.\n",
+ printf("File number=%ld, block number=%ld, partition=%ld.\n",
status.mt_fileno, status.mt_blkno, (status.mt_resid & 0xff));
else
- printf("File number=%d, block number=%d.\n",
+ printf("File number=%ld, block number=%ld.\n",
status.mt_fileno, status.mt_blkno);
- if (status.mt_type == MT_ISSCSI1 ||
- status.mt_type == MT_ISSCSI2 ||
- status.mt_type == MT_ISONSTREAM_SC) {
+ if (status.mt_type == MT_ISSCSI1
+ || status.mt_type == MT_ISSCSI2
+#if 0
+ || status.mt_type == MT_ISONSTREAM_SC
+#endif
+ ) {
dens = (status.mt_dsreg & MT_ST_DENSITY_MASK) >> MT_ST_DENSITY_SHIFT;
density = "no translation";
for (i=0; i < NBR_DENSITIES; i++)
@@ -666,8 +695,10 @@
printf(" DR_OPEN");
if (GMT_IM_REP_EN(status.mt_gstat))
printf(" IM_REP_EN");
+#if 0
if (GMT_CLN(status.mt_gstat))
printf(" CLN");
+#endif
printf("\n");
return 0;
}
diff -ru ..\release\mt-st-0.9b/mtio.h ./mtio.h
--- ..\release\mt-st-0.9b/mtio.h 2005-08-16 12:16:28.000000000 -0700
+++ ./mtio.h 2006-08-09 03:26:58.352944100 -0700
@@ -8,9 +8,7 @@
#ifndef _LINUX_MTIO_H
#define _LINUX_MTIO_H
-#include <linux/types.h>
-#include <linux/ioctl.h>
-#include <linux/qic117.h>
+#include <sys/types.h>
/*
* Structures and definitions for mag tape io control commands
@@ -150,6 +148,7 @@
};
+#ifdef USE_QIC02
/* structure for MTIOCGETCONFIG/MTIOCSETCONFIG primarily intended
* as an interim solution for QIC-02 until DDI is fully implemented.
*/
@@ -281,6 +280,7 @@
* command
*/
};
+#endif
/* mag tape io control commands */
#define MTIOCTOP _IOW('m', 1, struct mtop) /* do a mag tape op */
diff -ru ..\release\mt-st-0.9b/stinit.def.examples ./stinit.def.examples
--- ..\release\mt-st-0.9b/stinit.def.examples 2005-08-16 12:16:28.000000000 -0700
+++ ./stinit.def.examples 2006-08-09 03:26:58.362958700 -0700
@@ -56,3 +56,169 @@
mode3 blocksize=0 density=1 # 800 bpi
}
+# DLT2000 / 2000XT
+manufacturer="QUANTUM" model = "DLT2000" {
+scsi2logical=1
+can-bsr
+auto-lock=0
+two-fms=0
+drive-buffering=1
+buffer-writes
+read-ahead=1
+async-writes=1
+can-partitions=0
+fast-mteom=1
+#
+# If your stinit supports the timeouts:
+timeout=3600 # 1 hour
+long-timeout=14400 # 4 hours
+#
+mode1 blocksize=0 density=0x81 # 10GB + compression on DLTtape III, 15+ with DLTtape IIIXT in 2000XT
+mode2 blocksize=0 density=0x80 # 10GB, no compression on DLTtape III, 15 with DLTtape IIIXT in 2000XT
+mode3 blocksize=0 density=0x18 # 6GB, compression not available, on DLTtape III
+mode4 blocksize=0 density=0x17 #2.6GB, compression not available, on DLTtape III
+}
+
+# DLT4000
+manufacturer="QUANTUM" model = "DLT4000" {
+scsi2logical=1
+can-bsr
+auto-lock=0
+two-fms=0
+drive-buffering=1
+buffer-writes
+read-ahead=1
+async-writes=1
+can-partitions=0
+fast-mteom=1
+#
+# If your stinit supports the timeouts:
+timeout=3600 # 1 hour
+long-timeout=14400 # 4 hours
+#
+# Drive is backwards compatible, use older modes (e.g. from above) as required
+mode1 blocksize=0 density=0x83 # 20GB + compression
+mode2 blocksize=0 density=0x82 # 20GB, no compression
+mode3 blocksize=0 density=0x81 # 10GB + compression (DLT2000 mode) with DLTtape III, 15+ with DLTtape IIIXT in 2000XT
+mode4 blocksize=0 density=0x80 # 10GB, no compression (DLT2000 mode) with DLTtape III, 15 with DLTtape IIIXT in 2000XT
+}
+
+# DLT7000
+manufacturer="QUANTUM" model = "DLT7000" {
+scsi2logical=1
+can-bsr
+auto-lock=0
+two-fms=0
+drive-buffering=1
+buffer-writes
+read-ahead=1
+async-writes=1
+can-partitions=0
+fast-mteom=1
+#
+# If your stinit supports the timeouts:
+timeout=3600 # 1 hour
+long-timeout=14400 # 4 hours
+#
+# Drive is backwards compatible, use older modes (e.g. from above) as required.
+mode1 blocksize=0 density=0x85 # 35GB + compression
+mode2 blocksize=0 density=0x84 # 35GB, no compression
+mode3 blocksize=0 density=0x83 # 20GB + compression (DLT4000 mode)
+mode4 blocksize=0 density=0x82 # 20GB, no compression (DLT4000 mode)
+}
+
+# DLT8000
+manufacturer="QUANTUM" model = "DLT8000" {
+scsi2logical=1
+can-bsr=1
+auto-lock=0
+two-fms=0
+drive-buffering=1
+buffer-writes
+read-ahead=1
+async-writes=1
+can-partitions=0
+fast-mteom=1
+#
+# If your stinit supports the timeouts:
+timeout=3600 # 1 hour
+long-timeout=14400 # 4 hours
+#
+# Drive is backwards compatible to DLT7000, use older modes (e.g. from above) as required. Modes <10GB (<0x19) not supported!
+mode1 blocksize=0 density=0x89 # 40GB + compression
+mode2 blocksize=0 density=0x88 # 40GB, no compression
+mode3 blocksize=0 density=0x85 # 35GB + compression (DLT7000 mode)
+mode4 blocksize=0 density=0x84 # 35GB, no compression (DLT7000 mode)
+}
+
+
+# SDLT220
+manufacturer="QUANTUM" model = "SuperDLT1" {
+scsi2logical=1
+can-bsr=1
+auto-lock=0
+two-fms=0
+drive-buffering=1
+buffer-writes
+read-ahead=1
+async-writes=1
+can-partitions=0
+fast-mteom=1
+#
+# If your stinit supports the timeouts:
+timeout=3600 # 1 hour
+long-timeout=14400 # 4 hours
+#
+# Drive is backwards read compatible to DLT4000/7000/8000. Mode settings are only required for writing, so no need to define any other modes here.
+mode1 blocksize=0 density=0x48 compression=1 # 110 GB + compression
+mode2 blocksize=0 density=0x48 compression=0 # 110 GB, no ompression
+}
+
+# SDLT320
+manufacturer="QUANTUM" model = "SDLT320" {
+scsi2logical=1
+can-bsr=1
+auto-lock=0
+two-fms=0
+drive-buffering=1
+buffer-writes
+read-ahead=1
+async-writes=1
+can-partitions=0
+fast-mteom=1
+#
+# If your stinit supports the timeouts:
+timeout=3600 # 1 hour
+long-timeout=14400 # 4 hours
+#
+# Drive is backwards write compatible to SDLT220 and read compatible to DLT4000/7000/8000. Mode settings are only required for writing, so we need only the SDL220/320 modes here
+mode1 blocksize=0 density=0x49 compression=1 # 160 GB + compression
+mode2 blocksize=0 density=0x49 compression=0 # 160 GB, no ompression
+mode3 blocksize=0 density=0x48 compression=1 # 110 GB + compression
+mode4 blocksize=0 density=0x48 compression=0 # 110 GB, no ompression
+}
+
+# SDLT600
+manufacturer="QUANTUM" model = "SDLT600" {
+scsi2logical=1
+can-bsr=1
+auto-lock=0
+two-fms=0
+drive-buffering=1
+buffer-writes
+read-ahead=1
+async-writes=1
+can-partitions=0
+fast-mteom=1
+#
+# If your stinit supports the timeouts:
+timeout=3600 # 1 hour
+long-timeout=14400 # 4 hours
+#
+# Drive is backwards read compatible to SDLT220/320 and VS160. Mode settings are only required for writing, so we need only the native SDLT600 mode here.
+mode1 blocksize=0 density=0x4a compression=1 # 300 GB + compression
+mode2 blocksize=0 density=0x4a compression=0 # 300 GB, no ompression
+mode3 blocksize=0 density=0x4a compression=1 # 300 GB + compression
+mode4 blocksize=0 density=0x4a compression=0 # 300 GB, no ompression
+}
+
--- /dev/null 1969-12-31 16:00:00.000000000 -0800
+++ mtops.c 2006-08-09 04:03:09.307917500 -0700
@@ -0,0 +1,1163 @@
+/*
+ * mtops.cpp - Emulate the Linux st (scsi tape) driver on Microsoft Windows.
+ *
+ * Author: Robert Nelson, May, 2006 <robertn@the-nelsons.org>
+ *
+ * Version $Id: mt.patch 3802 2006-12-14 11:41:02Z kerns $
+ *
+ * Copyright (C) 2006 Free Software Foundation Europe e.V.
+ *
+ * This file was contributed to the Bacula project by Robert Nelson.
+ *
+ * Robert Nelson has been granted a perpetual, worldwide,
+ * non-exclusive, no-charge, royalty-free, irrevocable copyright
+ * license to reproduce, prepare derivative works of, publicly
+ * display, publicly perform, sublicense, and distribute the original
+ * work contributed by Robert Nelson to the Bacula project in source
+ * or object form.
+ *
+ * If you wish to license contributions from Robert Nelson
+ * under an alternate open source license please contact
+ * Robert Nelson <robertn@the-nelsons.org>.
+ */
+/*
+ Copyright (C) 2006 Free Software Foundation Europe e.V.
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ version 2 as amended with additional clauses defined in the
+ file LICENSE in the main source directory.
+
+ 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
+ the file LICENSE for additional details.
+
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#include <windows.h>
+#include <errno.h>
+
+#include "mtops.h"
+#include "mtio.h"
+#if defined(_MSC_VER)
+#include <winioctl.h>
+#include <ntddscsi.h>
+#else
+#include <ddk/ntddstor.h>
+#include <ddk/ntddscsi.h>
+#endif
+
+#ifndef __cplusplus
+typedef char bool;
+#define true 1
+#define false 0
+#endif
+
+//
+// SCSI bus status codes.
+//
+
+#define SCSISTAT_GOOD 0x00
+#define SCSISTAT_CHECK_CONDITION 0x02
+#define SCSISTAT_CONDITION_MET 0x04
+#define SCSISTAT_BUSY 0x08
+#define SCSISTAT_INTERMEDIATE 0x10
+#define SCSISTAT_INTERMEDIATE_COND_MET 0x14
+#define SCSISTAT_RESERVATION_CONFLICT 0x18
+#define SCSISTAT_COMMAND_TERMINATED 0x22
+#define SCSISTAT_QUEUE_FULL 0x28
+
+/* Forward referenced functions */
+
+extern char my_name[];
+extern int debug_level;
+
+inline SHORT Read16BitSigned(const unsigned char *pValue)
+{
+ return (SHORT)(((USHORT)pValue[0] << 8) | (USHORT)pValue[1]);
+}
+
+inline USHORT Read16BitUnsigned(const unsigned char *pValue)
+{
+ return (((USHORT)pValue[0] << 8) | (USHORT)pValue[1]);
+}
+
+inline LONG Read24BitSigned(const unsigned char *pValue)
+{
+ return ((LONG)(((ULONG)pValue[0] << 16) | ((ULONG)pValue[1] << 8) |
+ (ULONG)pValue[2])) << 8 >> 8;
+}
+
+inline ULONG Read24BitUnsigned(const unsigned char *pValue)
+{
+ return ((ULONG)pValue[0] << 16) | ((ULONG)pValue[1] << 8) | (ULONG)pValue[2];
+}
+
+inline LONG Read32BitSigned(const unsigned char *pValue)
+{
+ return (LONG)(((ULONG)pValue[0] << 24) | ((ULONG)pValue[1] << 16) |
+ ((ULONG)pValue[2] << 8) | (ULONG)pValue[3]);
+}
+
+inline ULONG Read32BitUnsigned(const unsigned char *pValue)
+{
+ return (((ULONG)pValue[0] << 24) | ((ULONG)pValue[1] << 16) |
+ ((ULONG)pValue[2] << 8) | (ULONG)pValue[3]);
+}
+
+inline LONGLONG Read64BitSigned(const unsigned char *pValue)
+{
+ return (LONGLONG)(((ULONGLONG)pValue[0] << 56) | ((ULONGLONG)pValue[1] << 48) |
+ ((ULONGLONG)pValue[2] << 40) | ((ULONGLONG)pValue[3] << 32) |
+ ((ULONGLONG)pValue[4] << 24) | ((ULONGLONG)pValue[5] << 16) |
+ ((ULONGLONG)pValue[6] << 8) | (ULONGLONG)pValue[7]);
+}
+
+inline ULONGLONG Read64BitUnsigned(const unsigned char *pValue)
+{
+ return (LONGLONG)(((ULONGLONG)pValue[0] << 56) | ((ULONGLONG)pValue[1] << 48) |
+ ((ULONGLONG)pValue[2] << 40) | ((ULONGLONG)pValue[3] << 32) |
+ ((ULONGLONG)pValue[4] << 24) | ((ULONGLONG)pValue[5] << 16) |
+ ((ULONGLONG)pValue[6] << 8) | (ULONGLONG)pValue[7]);
+}
+
+typedef struct _TAPE_POSITION_INFO
+{
+ UCHAR AtPartitionStart:1;
+ UCHAR AtPartitionEnd:1;
+ UCHAR PartitionBlockValid:1;
+ UCHAR FileSetValid:1;
+ UCHAR :4;
+ UCHAR Reserved1[3];
+ ULONG Partition;
+ ULONGLONG BlockNumber;
+ ULONGLONG FileNumber;
+ ULONGLONG SetNumber;
+} TAPE_POSITION_INFO, *PTAPE_POSITION_INFO;
+
+typedef struct _TAPE_HANDLE_INFO
+{
+ HANDLE OSHandle;
+ bool bEOD;
+ bool bEOF;
+ bool bEOT;
+ bool bBlockValid;
+ ULONG FeaturesLow;
+ ULONG FeaturesHigh;
+ ULONG ulFile;
+ ULONGLONG ullFileStart;
+
+} TAPE_HANDLE_INFO, *PTAPE_HANDLE_INFO;
+
+TAPE_HANDLE_INFO TapeHandleTable[] =
+{
+ { INVALID_HANDLE_VALUE },
+ { INVALID_HANDLE_VALUE },
+ { INVALID_HANDLE_VALUE },
+ { INVALID_HANDLE_VALUE },
+ { INVALID_HANDLE_VALUE },
+ { INVALID_HANDLE_VALUE },
+ { INVALID_HANDLE_VALUE },
+ { INVALID_HANDLE_VALUE },
+ { INVALID_HANDLE_VALUE },
+ { INVALID_HANDLE_VALUE },
+ { INVALID_HANDLE_VALUE },
+ { INVALID_HANDLE_VALUE },
+ { INVALID_HANDLE_VALUE },
+ { INVALID_HANDLE_VALUE },
+ { INVALID_HANDLE_VALUE },
+ { INVALID_HANDLE_VALUE }
+};
+
+#define NUMBER_HANDLE_ENTRIES (sizeof(TapeHandleTable) / sizeof(TapeHandleTable[0]))
+
+DWORD GetTapePositionInfo(HANDLE hDevice, PTAPE_POSITION_INFO TapePositionInfo);
+DWORD GetDensityBlockSize(HANDLE hDevice, DWORD *pdwDensity, DWORD *pdwBlockSize);
+
+int tape_get(int fd, struct mtget *mt_get);
+int tape_op(int fd, struct mtop *mt_com);
+int tape_pos(int fd, struct mtpos *mt_pos);
+
+int
+tape_open(const char *file, int flags, int mode)
+{
+ HANDLE hDevice = INVALID_HANDLE_VALUE;
+ char szDeviceName[256] = "\\\\.\\";
+ int idxFile;
+ DWORD dwResult;
+
+ for (idxFile = 0; idxFile < (int)NUMBER_HANDLE_ENTRIES; idxFile++) {
+ if (TapeHandleTable[idxFile].OSHandle == INVALID_HANDLE_VALUE) {
+ break;
+ }
+ }
+
+ if (idxFile >= (int)NUMBER_HANDLE_ENTRIES) {
+ return EMFILE;
+ }
+
+ memset(&TapeHandleTable[idxFile], 0, sizeof(TapeHandleTable[idxFile]));
+
+ if (file[0] != '\\' && file[0] != '/') {
+ strncpy(&szDeviceName[4], file, sizeof(szDeviceName) - 4);
+ } else {
+ strncpy(&szDeviceName[0], file, sizeof(szDeviceName));
+ }
+
+ szDeviceName[sizeof(szDeviceName) - 1] = '\0';
+
+ hDevice = CreateFile(szDeviceName, FILE_ALL_ACCESS, 0, NULL, OPEN_EXISTING, 0, NULL);
+
+ if (hDevice != INVALID_HANDLE_VALUE) {
+ PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[idxFile];
+
+ memset(pHandleInfo, 0, sizeof(*pHandleInfo));
+
+ pHandleInfo->OSHandle = hDevice;
+
+ TAPE_GET_DRIVE_PARAMETERS TapeDriveParameters;
+ DWORD dwSize = sizeof(TapeDriveParameters);
+
+ dwResult = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &dwSize, &TapeDriveParameters);
+ if (dwResult == NO_ERROR) {
+ pHandleInfo->FeaturesLow = TapeDriveParameters.FeaturesLow;
+ pHandleInfo->FeaturesHigh = TapeDriveParameters.FeaturesHigh;
+ }
+
+ TAPE_POSITION_INFO TapePositionInfo;
+
+ dwResult = GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo);
+
+ if (dwResult == NO_ERROR) {
+ if (TapePositionInfo.AtPartitionStart || TapePositionInfo.AtPartitionEnd ||
+ (TapePositionInfo.PartitionBlockValid && TapePositionInfo.BlockNumber == 0)) {
+ pHandleInfo->ulFile = 0;
+ pHandleInfo->bBlockValid = true;
+ pHandleInfo->ullFileStart = 0;
+ } else if (TapePositionInfo.FileSetValid) {
+ pHandleInfo->ulFile = (ULONG)TapePositionInfo.FileNumber;
+ }
+ }
+ } else {
+ DWORD dwError = GetLastError();
+
+ switch (dwError) {
+ case ERROR_FILE_NOT_FOUND:
+ case ERROR_PATH_NOT_FOUND:
+ errno = ENOENT;
+ break;
+
+ case ERROR_TOO_MANY_OPEN_FILES:
+ errno = EMFILE;
+ break;
+
+ default:
+ case ERROR_ACCESS_DENIED:
+ case ERROR_SHARING_VIOLATION:
+ case ERROR_LOCK_VIOLATION:
+ case ERROR_INVALID_NAME:
+ errno = EACCES;
+ break;
+
+ case ERROR_FILE_EXISTS:
+ errno = EEXIST;
+ break;
+
+ case ERROR_INVALID_PARAMETER:
+ errno = EINVAL;
+ break;
+ }
+
+ return(int) -1;
+ }
+
+ return (int)idxFile + 3;
+}
+
+int
+tape_read(int fd, void *buffer, unsigned int count)
+{
+ if (buffer == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) ||
+ TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[fd - 3];
+
+ DWORD bytes_read;
+ BOOL bResult;
+
+ bResult = ReadFile(pHandleInfo->OSHandle, buffer, count, &bytes_read, NULL);
+
+ if (bResult) {
+ pHandleInfo->bEOF = false;
+ pHandleInfo->bEOT = false;
+ pHandleInfo->bEOD = false;
+ return bytes_read;
+ } else {
+ int iReturnValue = 0;
+ DWORD last_error = GetLastError();
+
+ switch (last_error) {
+
+ case ERROR_FILEMARK_DETECTED:
+ pHandleInfo->bEOF = true;
+ break;
+
+ case ERROR_END_OF_MEDIA:
+ pHandleInfo->bEOT = true;
+ break;
+
+ case ERROR_NO_MEDIA_IN_DRIVE:
+ pHandleInfo->bEOF = false;
+ pHandleInfo->bEOT = false;
+ pHandleInfo->bEOD = false;
+ errno = ENOMEDIUM;
+ iReturnValue = -1;
+ break;
+
+ case ERROR_NO_DATA_DETECTED:
+ pHandleInfo->bEOD = true;
+ break;
+
+ case ERROR_INVALID_HANDLE:
+ case ERROR_ACCESS_DENIED:
+ case ERROR_LOCK_VIOLATION:
+ errno = EBADF;
+ iReturnValue = -1;
+ break;
+
+ default:
+ pHandleInfo->bEOF = false;
+ pHandleInfo->bEOT = false;
+ pHandleInfo->bEOD = false;
+ errno = EIO;
+ iReturnValue = -1;
+ }
+
+ return iReturnValue;
+ }
+}
+
+int
+tape_write(int fd, const void *buffer, unsigned int count)
+{
+ if (buffer == NULL) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) || TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[fd - 3];
+
+ DWORD bytes_written;
+ BOOL bResult;
+
+ bResult = WriteFile(pHandleInfo->OSHandle, buffer, count, &bytes_written, NULL);
+
+ if (bResult) {
+ pHandleInfo->bEOF = false;
+ pHandleInfo->bEOT = false;
+ return bytes_written;
+ } else {
+ DWORD last_error = GetLastError();
+
+ switch (last_error) {
+ case ERROR_END_OF_MEDIA:
+ case ERROR_DISK_FULL:
+ pHandleInfo->bEOT = true;
+ errno = ENOSPC;
+ break;
+
+ case ERROR_NO_MEDIA_IN_DRIVE:
+ pHandleInfo->bEOF = false;
+ pHandleInfo->bEOT = false;
+ pHandleInfo->bEOD = false;
+ errno = ENOMEDIUM;
+ break;
+
+ case ERROR_INVALID_HANDLE:
+ case ERROR_ACCESS_DENIED:
+ errno = EBADF;
+ break;
+
+ default:
+ pHandleInfo->bEOF = false;
+ pHandleInfo->bEOT = false;
+ pHandleInfo->bEOD = false;
+ errno = EIO;
+ break;
+ }
+ return -1;
+ }
+}
+
+int
+tape_close(int fd)
+{
+ if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) ||
+ TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) {
+ errno = EBADF;
+ return -1;
+ }
+
+ PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[fd - 3];
+
+ if (!CloseHandle(pHandleInfo->OSHandle)) {
+ pHandleInfo->OSHandle = INVALID_HANDLE_VALUE;
+ errno = EBADF;
+ return -1;
+ }
+
+ pHandleInfo->OSHandle = INVALID_HANDLE_VALUE;
+
+ return 0;
+}
+
+int
+tape_ioctl(int fd, unsigned long int request, ...)
+{
+ va_list argp;
+ int result;
+
+ va_start(argp, request);
+
+ switch (request) {
+ case MTIOCTOP:
+ result = tape_op(fd, va_arg(argp, struct mtop *));
+ break;
+
+ case MTIOCGET:
+ result = tape_get(fd, va_arg(argp, struct mtget *));
+ break;
+
+ case MTIOCPOS:
+ result = tape_pos(fd, va_arg(argp, struct mtpos *));
+ break;
+
+ default:
+ errno = ENOTTY;
+ result = -1;
+ break;
+ }
+
+ va_end(argp);
+
+ return result;
+}
+
+int tape_op(int fd, struct mtop *mt_com)
+{
+ DWORD result = NO_ERROR;
+ int index;
+
+ if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) ||
+ TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE)
+ {
+ errno = EBADF;
+ return -1;
+ }
+
+ PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[fd - 3];
+
+ switch (mt_com->mt_op)
+ {
+ case MTRESET:
+ case MTNOP:
+ case MTSETDRVBUFFER:
+ break;
+
+ default:
+ case MTRAS1:
+ case MTRAS2:
+ case MTRAS3:
+ case MTSETDENSITY:
+ errno = ENOTTY;
+ result = (DWORD)-1;
+ break;
+
+ case MTFSF:
+ for (index = 0; index < mt_com->mt_count; index++) {
+ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE);
+ if (result == NO_ERROR) {
+ pHandleInfo->ulFile++;
+ pHandleInfo->bEOF = true;
+ pHandleInfo->bEOT = false;
+ }
+ }
+ break;
+
+ case MTBSF:
+ for (index = 0; index < mt_com->mt_count; index++) {
+ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE);
+ if (result == NO_ERROR) {
+ pHandleInfo->ulFile--;
+ pHandleInfo->bBlockValid = false;
+ pHandleInfo->bEOD = false;
+ pHandleInfo->bEOF = false;
+ pHandleInfo->bEOT = false;
+ }
+ }
+ break;
+
+ case MTFSR:
+ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_RELATIVE_BLOCKS, 0, mt_com->mt_count, 0, FALSE);
+ if (result == NO_ERROR) {
+ pHandleInfo->bEOD = false;
+ pHandleInfo->bEOF = false;
+ pHandleInfo->bEOT = false;
+ } else if (result == ERROR_FILEMARK_DETECTED) {
+ pHandleInfo->bEOF = true;
+ }
+ break;
+
+ case MTBSR:
+ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_RELATIVE_BLOCKS, 0, -mt_com->mt_count, ~0, FALSE);
+ if (result == NO_ERROR) {
+ pHandleInfo->bEOD = false;
+ pHandleInfo->bEOF = false;
+ pHandleInfo->bEOT = false;
+ } else if (result == ERROR_FILEMARK_DETECTED) {
+ pHandleInfo->ulFile--;
+ pHandleInfo->bBlockValid = false;
+ pHandleInfo->bEOD = false;
+ pHandleInfo->bEOF = false;
+ pHandleInfo->bEOT = false;
+ }
+ break;
+
+ case MTWEOF:
+ result = WriteTapemark(pHandleInfo->OSHandle, TAPE_FILEMARKS, mt_com->mt_count, FALSE);
+ if (result == NO_ERROR) {
+ pHandleInfo->bEOF = true;
+ pHandleInfo->bEOT = false;
+ pHandleInfo->ulFile += mt_com->mt_count;
+ pHandleInfo->bBlockValid = true;
+ pHandleInfo->ullFileStart = 0;
+ }
+ break;
+
+ case MTREW:
+ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_REWIND, 0, 0, 0, FALSE);
+ if (result == NO_ERROR) {
+ pHandleInfo->bEOD = false;
+ pHandleInfo->bEOF = false;
+ pHandleInfo->bEOT = false;
+ pHandleInfo->ulFile = 0;
+ pHandleInfo->bBlockValid = true;
+ pHandleInfo->ullFileStart = 0;
+ }
+ break;
+
+ case MTOFFL:
+ result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOAD, FALSE);
+ if (result == NO_ERROR) {
+ pHandleInfo->bEOD = false;
+ pHandleInfo->bEOF = false;
+ pHandleInfo->bEOT = false;
+ pHandleInfo->ulFile = 0;
+ pHandleInfo->ullFileStart = 0;
+ }
+ break;
+
+ case MTRETEN:
+ result = PrepareTape(pHandleInfo->OSHandle, TAPE_TENSION, FALSE);
+ if (result == NO_ERROR) {
+ pHandleInfo->bEOD = false;
+ pHandleInfo->bEOF = false;
+ pHandleInfo->bEOT = false;
+ pHandleInfo->ulFile = 0;
+ pHandleInfo->bBlockValid = true;
+ pHandleInfo->ullFileStart = 0;
+ }
+ break;
+
+ case MTBSFM:
+ for (index = 0; index < mt_com->mt_count; index++) {
+ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE);
+ if (result == NO_ERROR) {
+ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE);
+ pHandleInfo->bEOD = false;
+ pHandleInfo->bEOF = false;
+ pHandleInfo->bEOT = false;
+ }
+ }
+ break;
+
+ case MTFSFM:
+ for (index = 0; index < mt_com->mt_count; index++) {
+ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, mt_com->mt_count, 0, FALSE);
+ if (result == NO_ERROR) {
+ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE);
+ pHandleInfo->bEOD = false;
+ pHandleInfo->bEOF = false;
+ pHandleInfo->bEOT = false;
+ }
+ }
+ break;
+
+ case MTEOM:
+ for ( ; ; ) {
+ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE);
+ if (result != NO_ERROR) {
+ pHandleInfo->bEOF = false;
+
+ if (result == ERROR_END_OF_MEDIA) {
+ pHandleInfo->bEOD = true;
+ pHandleInfo->bEOT = true;
+ return 0;
+ }
+ if (result == ERROR_NO_DATA_DETECTED) {
+ pHandleInfo->bEOD = true;
+ pHandleInfo->bEOT = false;
+ return 0;
+ }
+ break;
+ } else {
+ pHandleInfo->bEOF = true;
+ pHandleInfo->ulFile++;
+ }
+ }
+ break;
+
+ case MTERASE:
+ result = EraseTape(pHandleInfo->OSHandle, TAPE_ERASE_LONG, FALSE);
+ if (result == NO_ERROR) {
+ pHandleInfo->bEOD = true;
+ pHandleInfo->bEOF = false;
+ pHandleInfo->bEOT = false;
+ pHandleInfo->ulFile = 0;
+ pHandleInfo->bBlockValid = true;
+ pHandleInfo->ullFileStart = 0;
+ }
+ break;
+
+ case MTSETBLK:
+ {
+ TAPE_SET_MEDIA_PARAMETERS SetMediaParameters;
+
+ SetMediaParameters.BlockSize = mt_com->mt_count;
+ result = SetTapeParameters(pHandleInfo->OSHandle, SET_TAPE_MEDIA_INFORMATION, &SetMediaParameters);
+ }
+ break;
+
+ case MTSEEK:
+ {
+ TAPE_POSITION_INFO TapePositionInfo;
+
+ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, 0, mt_com->mt_count, 0, FALSE);
+
+ memset(&TapePositionInfo, 0, sizeof(TapePositionInfo));
+ DWORD dwPosResult = GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo);
+ if (dwPosResult == NO_ERROR && TapePositionInfo.FileSetValid) {
+ pHandleInfo->ulFile = (ULONG)TapePositionInfo.FileNumber;
+ } else {
+ pHandleInfo->ulFile = ~0U;
+ }
+ }
+ break;
+
+ case MTTELL:
+ {
+ DWORD partition;
+ DWORD offset;
+ DWORD offsetHi;
+
+ result = GetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, &partition, &offset, &offsetHi);
+ if (result == NO_ERROR) {
+ return offset;
+ }
+ }
+ break;
+
+ case MTFSS:
+ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_SETMARKS, 0, mt_com->mt_count, 0, FALSE);
+ break;
+
+ case MTBSS:
+ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_SETMARKS, 0, -mt_com->mt_count, ~0, FALSE);
+ break;
+
+ case MTWSM:
+ result = WriteTapemark(pHandleInfo->OSHandle, TAPE_SETMARKS, mt_com->mt_count, FALSE);
+ break;
+
+ case MTLOCK:
+ result = PrepareTape(pHandleInfo->OSHandle, TAPE_LOCK, FALSE);
+ break;
+
+ case MTUNLOCK:
+ result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOCK, FALSE);
+ break;
+
+ case MTLOAD:
+ result = PrepareTape(pHandleInfo->OSHandle, TAPE_LOAD, FALSE);
+ break;
+
+ case MTUNLOAD:
+ result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOAD, FALSE);
+ break;
+
+ case MTCOMPRESSION:
+ {
+ TAPE_GET_DRIVE_PARAMETERS GetDriveParameters;
+ TAPE_SET_DRIVE_PARAMETERS SetDriveParameters;
+ DWORD size;
+
+ size = sizeof(GetDriveParameters);
+
+ result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &size, &GetDriveParameters);
+
+ if (result == NO_ERROR)
+ {
+ SetDriveParameters.ECC = GetDriveParameters.ECC;
+ SetDriveParameters.Compression = (BOOLEAN)mt_com->mt_count;
+ SetDriveParameters.DataPadding = GetDriveParameters.DataPadding;
+ SetDriveParameters.ReportSetmarks = GetDriveParameters.ReportSetmarks;
+ SetDriveParameters.EOTWarningZoneSize = GetDriveParameters.EOTWarningZoneSize;
+
+ result = SetTapeParameters(pHandleInfo->OSHandle, SET_TAPE_DRIVE_INFORMATION, &SetDriveParameters);
+ }
+ }
+ break;
+
+ case MTSETPART:
+ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_LOGICAL_BLOCK, mt_com->mt_count, 0, 0, FALSE);
+ break;
+
+ case MTMKPART:
+ if (mt_com->mt_count == 0)
+ {
+ result = CreateTapePartition(pHandleInfo->OSHandle, TAPE_INITIATOR_PARTITIONS, 1, 0);
+ }
+ else
+ {
+ result = CreateTapePartition(pHandleInfo->OSHandle, TAPE_INITIATOR_PARTITIONS, 2, mt_com->mt_count);
+ }
+ break;
+ }
+
+ if ((result == NO_ERROR && pHandleInfo->bEOF) ||
+ (result == ERROR_FILEMARK_DETECTED && mt_com->mt_op == MTFSR)) {
+
+ TAPE_POSITION_INFO TapePositionInfo;
+
+ if (GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo) == NO_ERROR) {
+ pHandleInfo->bBlockValid = true;
+ pHandleInfo->ullFileStart = TapePositionInfo.BlockNumber;
+ }
+ }
+
+ switch (result) {
+ case NO_ERROR:
+ case (DWORD)-1: /* Error has already been translated into errno */
+ break;
+
+ default:
+ case ERROR_FILEMARK_DETECTED:
+ errno = EIO;
+ break;
+
+ case ERROR_END_OF_MEDIA:
+ pHandleInfo->bEOT = true;
+ errno = EIO;
+ break;
+
+ case ERROR_NO_DATA_DETECTED:
+ pHandleInfo->bEOD = true;
+ errno = EIO;
+ break;
+
+ case ERROR_NO_MEDIA_IN_DRIVE:
+ pHandleInfo->bEOF = false;
+ pHandleInfo->bEOT = false;
+ pHandleInfo->bEOD = false;
+ errno = ENOMEDIUM;
+ break;
+
+ case ERROR_INVALID_HANDLE:
+ case ERROR_ACCESS_DENIED:
+ case ERROR_LOCK_VIOLATION:
+ errno = EBADF;
+ break;
+ }
+
+ return result == NO_ERROR ? 0 : -1;
+}
+
+int tape_get(int fd, struct mtget *mt_get)
+{
+ TAPE_POSITION_INFO pos_info;
+ BOOL result;
+
+ if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) ||
+ TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) {
+ errno = EBADF;
+ return -1;
+ }
+
+ PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[fd - 3];
+
+ if (GetTapePositionInfo(pHandleInfo->OSHandle, &pos_info) != NO_ERROR) {
+ return -1;
+ }
+
+ DWORD density = 0;
+ DWORD blocksize = 0;
+
+ result = GetDensityBlockSize(pHandleInfo->OSHandle, &density, &blocksize);
+
+ if (result != NO_ERROR) {
+ TAPE_GET_DRIVE_PARAMETERS drive_params;
+ DWORD size;
+
+ size = sizeof(drive_params);
+
+ result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &size, &drive_params);
+
+ if (result == NO_ERROR) {
+ blocksize = drive_params.DefaultBlockSize;
+ }
+ }
+
+ mt_get->mt_type = MT_ISSCSI2;
+
+ // Partition #
+ mt_get->mt_resid = pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
+
+ // Density / Block Size
+ mt_get->mt_dsreg = ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
+ ((blocksize << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
+
+ mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
+
+ if (pHandleInfo->bEOF) {
+ mt_get->mt_gstat |= 0x80000000; // GMT_EOF
+ }
+
+ if (pos_info.PartitionBlockValid && pos_info.BlockNumber == 0) {
+ mt_get->mt_gstat |= 0x40000000; // GMT_BOT
+ }
+
+ if (pHandleInfo->bEOT) {
+ mt_get->mt_gstat |= 0x20000000; // GMT_EOT
+ }
+
+ if (pHandleInfo->bEOD) {
+ mt_get->mt_gstat |= 0x08000000; // GMT_EOD
+ }
+
+ TAPE_GET_MEDIA_PARAMETERS media_params;
+ DWORD size = sizeof(media_params);
+
+ result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_MEDIA_INFORMATION, &size, &media_params);
+
+ if (result == NO_ERROR && media_params.WriteProtected) {
+ mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
+ }
+
+ result = GetTapeStatus(pHandleInfo->OSHandle);
+
+ if (result != NO_ERROR) {
+ if (result == ERROR_NO_MEDIA_IN_DRIVE) {
+ mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
+ }
+ } else {
+ mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
+ }
+
+ // Recovered Error Count
+ mt_get->mt_erreg = 0;
+
+ // File Number
+ mt_get->mt_fileno = (__kernel_daddr_t)pHandleInfo->ulFile;
+
+ // Block Number
+ mt_get->mt_blkno = (__kernel_daddr_t)(pHandleInfo->bBlockValid ? pos_info.BlockNumber - pHandleInfo->ullFileStart : (ULONGLONG)-1);
+
+ return 0;
+}
+
+#define SERVICEACTION_SHORT_FORM_BLOCKID 0
+#define SERVICEACTION_SHORT_FORM_VENDOR_SPECIFIC 1
+#define SERVICEACTION_LONG_FORM 6
+#define SERVICEACTION_EXTENDED_FORM 8
+
+
+typedef struct _SCSI_READ_POSITION_SHORT_BUFFER
+{
+ UCHAR :1;
+ UCHAR PERR:1;
+ UCHAR BPU:1;
+ UCHAR :1;
+ UCHAR BYCU:1;
+ UCHAR BCU:1;
+ UCHAR EOP:1;
+ UCHAR BOP:1;
+ UCHAR Partition;
+ UCHAR Reserved1[2];
+ UCHAR FirstBlock[4];
+ UCHAR LastBlock[4];
+ UCHAR Reserved2;
+ UCHAR NumberBufferBlocks[3];
+ UCHAR NumberBufferBytes[4];
+} SCSI_READ_POSITION_SHORT_BUFFER, *PSCSI_READ_POSITION_SHORT_BUFFER;
+
+typedef struct _SCSI_READ_POSITION_LONG_BUFFER
+{
+ UCHAR :2;
+ UCHAR BPU:1;
+ UCHAR MPU:1;
+ UCHAR :2;
+ UCHAR EOP:1;
+ UCHAR BOP:1;
+ UCHAR Reserved3[3];
+ UCHAR Partition[4];
+ UCHAR BlockNumber[8];
+ UCHAR FileNumber[8];
+ UCHAR SetNumber[8];
+} SCSI_READ_POSITION_LONG_BUFFER, *PSCSI_READ_POSITION_LONG_BUFFER;
+
+typedef struct _SCSI_READ_POSITION_EXTENDED_BUFFER
+{
+ UCHAR :1;
+ UCHAR PERR:1;
+ UCHAR LOPU:1;
+ UCHAR :1;
+ UCHAR BYCU:1;
+ UCHAR LOCU:1;
+ UCHAR EOP:1;
+ UCHAR BOP:1;
+ UCHAR Partition;
+ UCHAR AdditionalLength[2];
+ UCHAR Reserved1;
+ UCHAR NumberBufferObjects[3];
+ UCHAR FirstLogicalObject[8];
+ UCHAR LastLogicalObject[8];
+ UCHAR NumberBufferObjectBytes[8];
+} SCSI_READ_POSITION_EXTENDED_BUFFER, *PSCSI_READ_POSITION_EXTENDED_BUFFER;
+
+typedef union _READ_POSITION_RESULT {
+ SCSI_READ_POSITION_SHORT_BUFFER ShortBuffer;
+ SCSI_READ_POSITION_LONG_BUFFER LongBuffer;
+ SCSI_READ_POSITION_EXTENDED_BUFFER ExtendedBuffer;
+} READ_POSITION_RESULT, *PREAD_POSITION_RESULT;
+
+DWORD GetTapePositionInfo(HANDLE hDevice, PTAPE_POSITION_INFO TapePositionInfo)
+{
+ PSCSI_PASS_THROUGH ScsiPassThrough;
+ BOOL bResult;
+ DWORD dwBytesReturned;
+ int pass;
+
+ const DWORD dwBufferSize = sizeof(SCSI_PASS_THROUGH) + sizeof(READ_POSITION_RESULT) + 28;
+
+ memset(TapePositionInfo, 0, sizeof(*TapePositionInfo));
+
+ ScsiPassThrough = (PSCSI_PASS_THROUGH)malloc(dwBufferSize);
+
+ for (pass = 0; pass < 2; pass++)
+ {
+ memset(ScsiPassThrough, 0, dwBufferSize);
+
+ ScsiPassThrough->Length = sizeof(SCSI_PASS_THROUGH);
+
+ ScsiPassThrough->CdbLength = 10;
+ ScsiPassThrough->SenseInfoLength = 28;
+ ScsiPassThrough->DataIn = 1;
+ ScsiPassThrough->DataTransferLength = sizeof(SCSI_READ_POSITION_LONG_BUFFER);
+ ScsiPassThrough->TimeOutValue = 1000;
+ ScsiPassThrough->DataBufferOffset = sizeof(SCSI_PASS_THROUGH) + 28;
+ ScsiPassThrough->SenseInfoOffset = sizeof(SCSI_PASS_THROUGH);
+
+ ScsiPassThrough->Cdb[0] = 0x34; // READ POSITION
+
+ switch (pass)
+ {
+ case 0:
+ ScsiPassThrough->Cdb[1] = SERVICEACTION_LONG_FORM;
+ break;
+
+ case 1:
+ ScsiPassThrough->Cdb[1] = SERVICEACTION_SHORT_FORM_BLOCKID;
+ break;
+ }
+
+ bResult = DeviceIoControl( hDevice,
+ IOCTL_SCSI_PASS_THROUGH,
+ ScsiPassThrough, sizeof(SCSI_PASS_THROUGH),
+ ScsiPassThrough, dwBufferSize,
+ &dwBytesReturned,
+ NULL);
+
+ if (bResult && dwBytesReturned >= (offsetof(SCSI_PASS_THROUGH, ScsiStatus) + sizeof(ScsiPassThrough->ScsiStatus))) {
+ if (ScsiPassThrough->ScsiStatus == SCSISTAT_GOOD) {
+ PREAD_POSITION_RESULT pPosResult = (PREAD_POSITION_RESULT)((PUCHAR)ScsiPassThrough + ScsiPassThrough->DataBufferOffset);
+
+ switch (pass)
+ {
+ case 0: // SERVICEACTION_LONG_FORM
+ {
+ TapePositionInfo->AtPartitionStart = pPosResult->LongBuffer.BOP;
+ TapePositionInfo->AtPartitionEnd = pPosResult->LongBuffer.EOP;
+
+ if (!TapePositionInfo->PartitionBlockValid) {
+ TapePositionInfo->PartitionBlockValid = !pPosResult->LongBuffer.BPU;
+
+ if (TapePositionInfo->PartitionBlockValid) {
+ TapePositionInfo->Partition = Read32BitUnsigned(pPosResult->LongBuffer.Partition);
+ TapePositionInfo->BlockNumber = Read64BitUnsigned(pPosResult->LongBuffer.BlockNumber);
+ }
+ }
+
+ TapePositionInfo->FileSetValid = !pPosResult->LongBuffer.MPU;
+ if (TapePositionInfo->FileSetValid) {
+ TapePositionInfo->FileNumber = Read64BitUnsigned(pPosResult->LongBuffer.FileNumber);
+ TapePositionInfo->SetNumber = Read64BitUnsigned(pPosResult->LongBuffer.SetNumber);
+ }
+ }
+ break;
+
+ case 1: // SERVICEACTION_SHORT_FORM_BLOCKID
+ {
+ // pPosResult->ShortBuffer.PERR;
+ // pPosResult->ShortBuffer.BYCU;
+ // pPosResult->ShortBuffer.BCU;
+ TapePositionInfo->AtPartitionStart = pPosResult->ShortBuffer.BOP;
+ TapePositionInfo->AtPartitionEnd = pPosResult->ShortBuffer.EOP;
+
+ if (!TapePositionInfo->PartitionBlockValid) {
+ TapePositionInfo->PartitionBlockValid = !pPosResult->ShortBuffer.BPU;
+
+ if (TapePositionInfo->PartitionBlockValid) {
+ TapePositionInfo->Partition = pPosResult->ShortBuffer.Partition;
+ TapePositionInfo->BlockNumber = Read32BitUnsigned(pPosResult->ShortBuffer.FirstBlock);
+ }
+ }
+ // Read32BitsUnsigned(pPosResult->ShortBuffer.LastBlock);
+ // Read24BitsUnsigned(pPosResult->ShortBuffer.NumberBufferBlocks);
+ // Read32BitsUnsigned(pPosResult->ShortBuffer.NumberBufferBytes);
+ }
+ break;
+ }
+ }
+ }
+ }
+ free(ScsiPassThrough);
+
+ return NO_ERROR;
+}
+
+DWORD GetDensityBlockSize(HANDLE hDevice, DWORD *pdwDensity, DWORD *pdwBlockSize)
+{
+ DWORD dwBufferSize = sizeof(GET_MEDIA_TYPES) + 5 * sizeof(DEVICE_MEDIA_INFO);
+ GET_MEDIA_TYPES * pGetMediaTypes = (GET_MEDIA_TYPES *)malloc(dwBufferSize);
+ BOOL bResult;
+ DWORD dwResult;
+ DWORD idxMedia;
+
+ if (pGetMediaTypes == NULL) {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ do {
+ DWORD dwBytesReturned;
+
+ bResult = DeviceIoControl( hDevice,
+ IOCTL_STORAGE_GET_MEDIA_TYPES_EX,
+ NULL, 0,
+ (LPVOID)pGetMediaTypes, dwBufferSize,
+ &dwBytesReturned,
+ NULL);
+
+ if (!bResult) {
+ dwResult = GetLastError();
+
+ if (dwResult != ERROR_INSUFFICIENT_BUFFER) {
+ free(pGetMediaTypes);
+ return dwResult;
+ }
+
+ dwBufferSize += 6 * sizeof(DEVICE_MEDIA_INFO);
+
+ GET_MEDIA_TYPES * pNewBuffer = (GET_MEDIA_TYPES *)realloc(pGetMediaTypes, dwBufferSize);
+
+ if (pNewBuffer != pGetMediaTypes) {
+ free(pGetMediaTypes);
+
+ if (pNewBuffer == NULL) {
+ return ERROR_OUTOFMEMORY;
+ }
+
+ pGetMediaTypes = pNewBuffer;
+ }
+ }
+ } while (!bResult);
+
+ if (pGetMediaTypes->DeviceType != FILE_DEVICE_TAPE) {
+ free(pGetMediaTypes);
+ return ERROR_BAD_DEVICE;
+ }
+
+ for (idxMedia = 0; idxMedia < pGetMediaTypes->MediaInfoCount; idxMedia++) {
+
+ if (pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.MediaCharacteristics & MEDIA_CURRENTLY_MOUNTED) {
+
+ if (pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.BusType == BusTypeScsi) {
+ *pdwDensity = pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.BusSpecificData.ScsiInformation.DensityCode;
+ } else {
+ *pdwDensity = 0;
+ }
+
+ *pdwBlockSize = pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.CurrentBlockSize;
+
+ free(pGetMediaTypes);
+
+ return NO_ERROR;
+ }
+ }
+
+ free(pGetMediaTypes);
+
+ return ERROR_NO_MEDIA_IN_DRIVE;
+}
+
+int tape_pos(int fd, struct mtpos *mt_pos)
+{
+ DWORD partition;
+ DWORD offset;
+ DWORD offsetHi;
+ BOOL result;
+
+ if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) ||
+ TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) {
+ errno = EBADF;
+ return -1;
+ }
+
+ PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[fd - 3];
+
+ result = GetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, &partition, &offset, &offsetHi);
+ if (result == NO_ERROR) {
+ mt_pos->mt_blkno = offset;
+ return 0;
+ }
+
+ return -1;
+}
--- /dev/null 1969-12-31 16:00:00.000000000 -0800
+++ mtops.h 2006-08-09 03:26:58.372973300 -0700
@@ -0,0 +1,15 @@
+int tape_open(const char *file, int flags, int mode);
+int tape_read(int fd, void *buffer, unsigned int count);
+int tape_write(int fd, const void *buffer, unsigned int count);
+int tape_ioctl(int fd, unsigned long int request, ...);
+int tape_close(int fd);
+
+typedef unsigned long __kernel_daddr_t;
+
+#ifndef ENOMEDIUM
+#define ENOMEDIUM 123
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024
+#endif
--- /dev/null 1969-12-31 16:00:00.000000000 -0800
+++ Makefile.msc 2006-08-09 04:00:53.970613100 -0700
@@ -0,0 +1,20 @@
+CC= cl
+CFLAGS= /nologo /Ox /Gy /Zi /W3 /TP \
+ /D_CRT_SECURE_NO_DEPRECATE
+LDFLAGS= /link /DEBUG /INCREMENTAL:NO /OPT:NOREF /PDB:$*.pdb /OUT:$@
+PREFIX= C:\
+
+all: mt.exe
+
+mt.exe: mt.c
+ $(CC) $(CFLAGS) mt.c mtops.c $(LDFLAGS)
+
+stinit.exe: stinit.c
+ $(CC) $(CFLAGS) stinit.c $(LDFLAGS)
+
+install: mt.exe
+ if not exist $(PREFIX)\bin\nul mkdir $(PREFIX)\bin
+ !copy /y $** $(PREFIX)\bin
+
+clean:
+ del /f *~ *.obj mt.exe stinit.exe
syntax highlighted by Code2HTML, v. 0.9.1