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