1diff -ru ..\release\mt-st-0.9b/Makefile ./Makefile
2--- ..\release\mt-st-0.9b/Makefile	2005-08-16 12:16:28.000000000 -0700
3+++ ./Makefile	2006-08-09 03:26:58.292856500 -0700
4@@ -1,29 +1,27 @@
5+CC=	mingw32-gcc
6 CFLAGS=  -Wall -O2
7-SBINDIR= /sbin
8-BINDIR=  /bin
9-MANDIR= /usr/share/man
10+PREFIX=
11+SBINDIR= $(PREFIX)/sbin
12+BINDIR=  $(PREFIX)/bin
13+MANDIR= $(PREFIX)/man
14
15-all:	mt stinit
16+all:	mt.exe
17
18-mt:	mt.c
19-	$(CC) $(CFLAGS) -o mt mt.c
20+mt.exe:	mt.c
21+	$(CC) $(CFLAGS) -o mt.exe mt.c mtops.c
22
23-stinit:	stinit.c
24+stinit.exe:	stinit.c
25 	$(CC) $(CFLAGS) -o stinit stinit.c
26
27-install: mt stinit
28-	install -s mt $(BINDIR)
29+install: mt.exe
30+	install mt.exe $(BINDIR)
31 	install -c -m 444 mt.1 $(MANDIR)/man1
32 	(if [ -f $(MANDIR)/man1/mt.1.gz ] ; then \
33 	  rm -f $(MANDIR)/man1/mt.1.gz; gzip $(MANDIR)/man1/mt.1; fi)
34-	install -s stinit $(SBINDIR)
35-	install -c -m 444 stinit.8 $(MANDIR)/man8
36-	(if [ -f $(MANDIR)/man8/stinit.8.gz ] ; then \
37-	  rm -f $(MANDIR)/man8/stinit.8.gz; gzip $(MANDIR)/man8/stinit.8; fi)
38
39 dist:	clean
40 	(mydir=`basename \`pwd\``;\
41 	cd .. && tar cvvf - $$mydir | gzip -9 > $${mydir}.tar.gz)
42
43 clean:
44-	rm -f *~ \#*\# *.o mt stinit
45+	rm -f *~ \#*\# *.o mt.exe stinit.exe
46diff -ru ..\release\mt-st-0.9b/mt.1 ./mt.1
47--- ..\release\mt-st-0.9b/mt.1	2005-08-21 11:53:50.000000000 -0700
48+++ ./mt.1	2006-08-09 03:26:58.302871100 -0700
49@@ -48,20 +48,22 @@
50 files.
51 The tape is positioned on the first block of the next file.
52 .IP fsfm
53-Forward space
54+Forward space past
55 .I count
56-files.
57-The tape is positioned on the last block of the previous file.
58+file marks, then backward space one file record.
59+This leaves the tape positioned on the last block of the file that is count-1
60+files past the current file.
61 .IP bsf
62 Backward space
63 .I count
64 files.
65 The tape is positioned on the last block of the previous file.
66 .IP bsfm
67-Backward space
68+Backward space past
69 .I count
70-files.
71-The tape is positioned on the first block of the next file.
72+file marks, then forward space one file record.
73+This leaves the tape positioned on the first block of the file that is count-1
74+files before the current file.
75 .IP asf
76 The tape is positioned at the beginning of the
77 .I count
78diff -ru ..\release\mt-st-0.9b/mt.c ./mt.c
79--- ..\release\mt-st-0.9b/mt.c	2005-08-21 11:48:06.000000000 -0700
80+++ ./mt.c	2006-08-09 04:00:01.093525100 -0700
81@@ -11,25 +11,35 @@
82 	Last Modified: Sun Aug 21 21:48:06 2005 by kai.makisara
83 */
84
85+#include <windows.h>
86+#include <winioctl.h>
87+#include <winsock.h>
88+
89+#define O_NONBLOCK   0
90+
91 #include <stdio.h>
92+#if !defined(_MSC_VER)
93 #include <unistd.h>
94+#endif
95 #include <stdlib.h>
96 #include <string.h>
97 #include <ctype.h>
98 #include <errno.h>
99 #include <fcntl.h>
100 #include <sys/types.h>
101-#include <sys/ioctl.h>
102
103+#include "mtops.h"
104 #include "mtio.h"
105
106+#define ioctl	tape_ioctl
107+
108 #ifndef DEFTAPE
109-#define DEFTAPE "/dev/tape"     /* default tape device */
110+#define DEFTAPE "Tape0"     /* default tape device */
111 #endif /* DEFTAPE */
112
113-#define VERSION "0.9b"
114+#define VERSION "0.9b-bacula"
115
116-typedef int (* cmdfunc)(/* int, struct cmdef_tr *, int, char ** */);
117+typedef int (* cmdfunc)(int, struct cmdef_tr *, int, char **);
118
119 typedef struct cmdef_tr {
120     char *cmd_name;
121@@ -143,12 +153,14 @@
122       FD_RDONLY, ONE_ARG, 0},
123     { "defcompression", MTSETDRVBUFFER, do_drvbuffer, MT_ST_DEF_COMPRESSION,
124       FD_RDONLY, ONE_ARG, 0},
125+#if 0
126     { "stsetcln",	MTSETDRVBUFFER, do_drvbuffer, MT_ST_SET_CLN,
127       FD_RDONLY, ONE_ARG, 0},
128     { "sttimeout",	MTSETDRVBUFFER, do_drvbuffer, MT_ST_SET_TIMEOUT,
129       FD_RDONLY, ONE_ARG, 0},
130     { "stlongtimeout",	MTSETDRVBUFFER, do_drvbuffer, MT_ST_SET_LONG_TIMEOUT,
131       FD_RDONLY, ONE_ARG, 0},
132+#endif
133     { "densities",	0, print_densities,     0, NO_FD,     NO_ARGS,
134     0 },
135     { "setpartition",	MTSETPART, do_standard, 0, FD_RDONLY, ONE_ARG,
136@@ -211,13 +223,19 @@
137     {0x30, "AIT-1 or MLR3"},
138     {0x31, "AIT-2"},
139     {0x32, "AIT-3"},
140-    {0x33, "SLR6"},
141+    {0x33, "AIT-4 or SLR6"},
142     {0x34, "SLR100"},
143+    {0x38, "AIT-E Turbo"},
144+    {0x39, "AIT-1 Turbo"},
145+    {0x3A, "AIT-2 Turbo"},
146+    {0x3B, "AIT-3Ex"},
147     {0x40, "DLT1 40 GB, or Ultrium"},
148     {0x41, "DLT 40GB, or Ultrium2"},
149     {0x42, "LTO-2"},
150     {0x45, "QIC-3095-MC (TR-4)"},
151     {0x47, "TR-5"},
152+    {0x48, "Quantum SDLT220"},
153+    {0x49, "Quantum SDLT320"},
154     {0x80, "DLT 15GB uncomp. or Ecrix"},
155     {0x81, "DLT 15GB compressed"},
156     {0x82, "DLT 20GB uncompressed"},
157@@ -254,20 +272,25 @@
158     {"no-blklimits",  MT_ST_NO_BLKLIMS,    "drive doesn't support read block limits"},
159     {"can-partitions",MT_ST_CAN_PARTITIONS,"drive can handle partitioned tapes"},
160     {"scsi2logical",  MT_ST_SCSI2LOGICAL,  "logical block addresses used with SCSI-2"},
161+#if 0
162     {"no-wait",       MT_ST_NOWAIT,        "immediate mode for rewind, etc."},
163+#endif
164 #ifdef MT_ST_SYSV
165     {"sysv",	      MT_ST_SYSV,	   "enable the SystemV semantics"},
166 #endif
167+#if 0
168     {"cleaning",      MT_ST_SET_CLN,	   "set the cleaning bit location and mask"},
169+#endif
170     {NULL, 0}};
171
172 static char *tape_name;   /* The tape name for messages */
173
174
175-	int
176+int
177 main(int argc, char **argv)
178 {
179-    int mtfd, cmd_code, i, argn, len, oflags;
180+    int mtfd, cmd_code, i, argn, oflags;
181+    unsigned int len;
182     char *cmdstr;
183     cmdef_tr *comp, *comp2;
184
185@@ -344,7 +367,7 @@
186 	oflags = comp->cmd_fdtype == FD_RDONLY ? O_RDONLY : O_RDWR;
187 	if ((comp->error_tests & ET_ONLINE) == 0)
188 	    oflags |= O_NONBLOCK;
189-	if ((mtfd = open(tape_name, oflags)) < 0) {
190+	if ((mtfd = tape_open(tape_name, oflags, 0)) < 0) {
191 	    perror(tape_name);
192 	    exit(1);
193 	}
194@@ -368,7 +391,7 @@
195     }
196
197     if (mtfd >= 0)
198-	close(mtfd);
199+	tape_close(mtfd);
200     return i;
201 }
202
203@@ -409,9 +432,9 @@
204 do_standard(int mtfd, cmdef_tr *cmd, int argc, char **argv)
205 {
206     struct mtop mt_com;
207-    char *endp;
208+    char *endp = NULL;
209
210-    mt_com.mt_op = cmd->cmd_code;
211+    mt_com.mt_op = (short)cmd->cmd_code;
212     mt_com.mt_count = (argc > 0 ? strtol(*argv, &endp, 0) : 1);
213     if (argc > 0 && endp != *argv) {
214 	if (*endp == 'k')
215@@ -464,7 +487,8 @@
216 	static int
217 do_options(int mtfd, cmdef_tr *cmd, int argc, char **argv)
218 {
219-    int i, an, len;
220+    int i, an;
221+    unsigned int len;
222     struct mtop mt_com;
223
224     mt_com.mt_op = MTSETDRVBUFFER;
225@@ -596,8 +620,10 @@
226 	type = "SCSI 1";
227     else if (status.mt_type == MT_ISSCSI2)
228 	type = "SCSI 2";
229+#if 0
230     else if (status.mt_type == MT_ISONSTREAM_SC)
231 	type = "OnStream SC-, DI-, DP-, or USB";
232+#endif
233     else
234 	type = NULL;
235     if (type == NULL) {
236@@ -607,7 +633,7 @@
237 	    printf("IDE-Tape (type code 0) ?\n");
238 	else
239 	    printf("Unknown tape drive type (type code %ld)\n", status.mt_type);
240-	printf("File number=%d, block number=%d.\n",
241+	printf("File number=%ld, block number=%ld.\n",
242 	       status.mt_fileno, status.mt_blkno);
243 	printf("mt_resid: %ld, mt_erreg: 0x%lx\n",
244 	       status.mt_resid, status.mt_erreg);
245@@ -617,14 +643,17 @@
246     else {
247 	printf("%s tape drive:\n", type);
248 	if (status.mt_type == MT_ISSCSI2)
249-	    printf("File number=%d, block number=%d, partition=%ld.\n",
250+	    printf("File number=%ld, block number=%ld, partition=%ld.\n",
251 		   status.mt_fileno, status.mt_blkno, (status.mt_resid & 0xff));
252 	else
253-	    printf("File number=%d, block number=%d.\n",
254+	    printf("File number=%ld, block number=%ld.\n",
255 		   status.mt_fileno, status.mt_blkno);
256-	if (status.mt_type == MT_ISSCSI1 ||
257-	    status.mt_type == MT_ISSCSI2 ||
258-	    status.mt_type == MT_ISONSTREAM_SC) {
259+	if (status.mt_type == MT_ISSCSI1
260+	    || status.mt_type == MT_ISSCSI2
261+#if 0
262+            || status.mt_type == MT_ISONSTREAM_SC
263+#endif
264+            ) {
265 	    dens = (status.mt_dsreg & MT_ST_DENSITY_MASK) >> MT_ST_DENSITY_SHIFT;
266 	    density = "no translation";
267 	    for (i=0; i < NBR_DENSITIES; i++)
268@@ -666,8 +695,10 @@
269 	printf(" DR_OPEN");
270     if (GMT_IM_REP_EN(status.mt_gstat))
271 	printf(" IM_REP_EN");
272+#if 0
273     if (GMT_CLN(status.mt_gstat))
274 	printf(" CLN");
275+#endif
276     printf("\n");
277     return 0;
278 }
279diff -ru ..\release\mt-st-0.9b/mtio.h ./mtio.h
280--- ..\release\mt-st-0.9b/mtio.h	2005-08-16 12:16:28.000000000 -0700
281+++ ./mtio.h	2006-08-09 03:26:58.352944100 -0700
282@@ -8,9 +8,7 @@
283 #ifndef _LINUX_MTIO_H
284 #define _LINUX_MTIO_H
285
286-#include <linux/types.h>
287-#include <linux/ioctl.h>
288-#include <linux/qic117.h>
289+#include <sys/types.h>
290
291 /*
292  * Structures and definitions for mag tape io control commands
293@@ -150,6 +148,7 @@
294 };
295
296
297+#ifdef USE_QIC02
298 /* structure for MTIOCGETCONFIG/MTIOCSETCONFIG primarily intended
299  * as an interim solution for QIC-02 until DDI is fully implemented.
300  */
301@@ -281,6 +280,7 @@
302 				      * command
303 				      */
304 };
305+#endif
306
307 /* mag tape io control commands */
308 #define	MTIOCTOP	_IOW('m', 1, struct mtop)	/* do a mag tape op */
309diff -ru ..\release\mt-st-0.9b/stinit.def.examples ./stinit.def.examples
310--- ..\release\mt-st-0.9b/stinit.def.examples	2005-08-16 12:16:28.000000000 -0700
311+++ ./stinit.def.examples	2006-08-09 03:26:58.362958700 -0700
312@@ -56,3 +56,169 @@
313 mode3 blocksize=0 density=1   #  800 bpi
314 }
315
316+# DLT2000 / 2000XT
317+manufacturer="QUANTUM" model = "DLT2000" {
318+scsi2logical=1
319+can-bsr
320+auto-lock=0
321+two-fms=0
322+drive-buffering=1
323+buffer-writes
324+read-ahead=1
325+async-writes=1
326+can-partitions=0
327+fast-mteom=1
328+#
329+# If your stinit supports the timeouts:
330+timeout=3600 # 1 hour
331+long-timeout=14400 # 4 hours
332+#
333+mode1 blocksize=0 density=0x81	# 10GB + compression on DLTtape III, 15+ with DLTtape IIIXT in 2000XT
334+mode2 blocksize=0 density=0x80	# 10GB, no compression  on DLTtape III, 15 with DLTtape IIIXT in 2000XT
335+mode3 blocksize=0 density=0x18  #  6GB, compression not available, on DLTtape III
336+mode4 blocksize=0 density=0x17  #2.6GB, compression not available, on DLTtape III
337+}
338+
339+# DLT4000
340+manufacturer="QUANTUM" model = "DLT4000" {
341+scsi2logical=1
342+can-bsr
343+auto-lock=0
344+two-fms=0
345+drive-buffering=1
346+buffer-writes
347+read-ahead=1
348+async-writes=1
349+can-partitions=0
350+fast-mteom=1
351+#
352+# If your stinit supports the timeouts:
353+timeout=3600 # 1 hour
354+long-timeout=14400 # 4 hours
355+#
356+# Drive is backwards compatible, use older modes (e.g. from above) as required
357+mode1 blocksize=0 density=0x83  # 20GB + compression
358+mode2 blocksize=0 density=0x82  # 20GB, no compression
359+mode3 blocksize=0 density=0x81	# 10GB + compression (DLT2000 mode) with DLTtape III, 15+ with DLTtape IIIXT in 2000XT
360+mode4 blocksize=0 density=0x80	# 10GB, no compression  (DLT2000 mode) with DLTtape III, 15 with DLTtape IIIXT in 2000XT
361+}
362+
363+# DLT7000
364+manufacturer="QUANTUM" model = "DLT7000" {
365+scsi2logical=1
366+can-bsr
367+auto-lock=0
368+two-fms=0
369+drive-buffering=1
370+buffer-writes
371+read-ahead=1
372+async-writes=1
373+can-partitions=0
374+fast-mteom=1
375+#
376+# If your stinit supports the timeouts:
377+timeout=3600 # 1 hour
378+long-timeout=14400 # 4 hours
379+#
380+# Drive is backwards compatible, use older modes (e.g. from above) as required.
381+mode1 blocksize=0 density=0x85  # 35GB + compression
382+mode2 blocksize=0 density=0x84  # 35GB, no compression
383+mode3 blocksize=0 density=0x83	# 20GB + compression (DLT4000 mode)
384+mode4 blocksize=0 density=0x82	# 20GB, no compression (DLT4000 mode)
385+}
386+
387+# DLT8000
388+manufacturer="QUANTUM" model = "DLT8000" {
389+scsi2logical=1
390+can-bsr=1
391+auto-lock=0
392+two-fms=0
393+drive-buffering=1
394+buffer-writes
395+read-ahead=1
396+async-writes=1
397+can-partitions=0
398+fast-mteom=1
399+#
400+# If your stinit supports the timeouts:
401+timeout=3600 # 1 hour
402+long-timeout=14400 # 4 hours
403+#
404+# Drive is backwards compatible to DLT7000, use older modes (e.g. from above) as required. Modes <10GB (<0x19) not supported!
405+mode1 blocksize=0 density=0x89	# 40GB + compression
406+mode2 blocksize=0 density=0x88	# 40GB, no compression
407+mode3 blocksize=0 density=0x85  # 35GB + compression (DLT7000 mode)
408+mode4 blocksize=0 density=0x84  # 35GB, no compression (DLT7000 mode)
409+}
410+
411+
412+# SDLT220
413+manufacturer="QUANTUM" model = "SuperDLT1" {
414+scsi2logical=1
415+can-bsr=1
416+auto-lock=0
417+two-fms=0
418+drive-buffering=1
419+buffer-writes
420+read-ahead=1
421+async-writes=1
422+can-partitions=0
423+fast-mteom=1
424+#
425+# If your stinit supports the timeouts:
426+timeout=3600 # 1 hour
427+long-timeout=14400 # 4 hours
428+#
429+# 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.
430+mode1 blocksize=0 density=0x48 compression=1	# 110 GB + compression
431+mode2 blocksize=0 density=0x48 compression=0	# 110 GB, no ompression
432+}
433+
434+# SDLT320
435+manufacturer="QUANTUM" model = "SDLT320" {
436+scsi2logical=1
437+can-bsr=1
438+auto-lock=0
439+two-fms=0
440+drive-buffering=1
441+buffer-writes
442+read-ahead=1
443+async-writes=1
444+can-partitions=0
445+fast-mteom=1
446+#
447+# If your stinit supports the timeouts:
448+timeout=3600 # 1 hour
449+long-timeout=14400 # 4 hours
450+#
451+# 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
452+mode1 blocksize=0 density=0x49 compression=1	# 160 GB + compression
453+mode2 blocksize=0 density=0x49 compression=0	# 160 GB, no ompression
454+mode3 blocksize=0 density=0x48 compression=1	# 110 GB + compression
455+mode4 blocksize=0 density=0x48 compression=0	# 110 GB, no ompression
456+}
457+
458+# SDLT600
459+manufacturer="QUANTUM" model = "SDLT600" {
460+scsi2logical=1
461+can-bsr=1
462+auto-lock=0
463+two-fms=0
464+drive-buffering=1
465+buffer-writes
466+read-ahead=1
467+async-writes=1
468+can-partitions=0
469+fast-mteom=1
470+#
471+# If your stinit supports the timeouts:
472+timeout=3600 # 1 hour
473+long-timeout=14400 # 4 hours
474+#
475+# 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.
476+mode1 blocksize=0 density=0x4a compression=1	# 300 GB + compression
477+mode2 blocksize=0 density=0x4a compression=0	# 300 GB, no ompression
478+mode3 blocksize=0 density=0x4a compression=1	# 300 GB + compression
479+mode4 blocksize=0 density=0x4a compression=0	# 300 GB, no ompression
480+}
481+
482
483--- /dev/null	1969-12-31 16:00:00.000000000 -0800
484+++ mtops.c	2006-08-09 04:03:09.307917500 -0700
485@@ -0,0 +1,1163 @@
486+/*
487+ * mtops.cpp - Emulate the Linux st (scsi tape) driver on Microsoft Windows.
488+ *
489+ * Author: Robert Nelson, May, 2006 <robertn@the-nelsons.org>
490+ *
491+ * Version $Id: mt.patch 3802 2006-12-14 11:41:02Z kerns $
492+ *
493+ * Copyright (C) 2006 Free Software Foundation Europe e.V.
494+ *
495+ * This file was contributed to the Bacula project by Robert Nelson.
496+ *
497+ * Robert Nelson has been granted a perpetual, worldwide,
498+ * non-exclusive, no-charge, royalty-free, irrevocable copyright
499+ * license to reproduce, prepare derivative works of, publicly
500+ * display, publicly perform, sublicense, and distribute the original
501+ * work contributed by Robert Nelson to the Bacula project in source
502+ * or object form.
503+ *
504+ * If you wish to license contributions from Robert Nelson
505+ * under an alternate open source license please contact
506+ * Robert Nelson <robertn@the-nelsons.org>.
507+ */
508+/*
509+   Copyright (C) 2006 Free Software Foundation Europe e.V.
510+
511+   This program is free software; you can redistribute it and/or
512+   modify it under the terms of the GNU General Public License
513+   version 2 as amended with additional clauses defined in the
514+   file LICENSE in the main source directory.
515+
516+   This program is distributed in the hope that it will be useful,
517+   but WITHOUT ANY WARRANTY; without even the implied warranty of
518+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
519+   the file LICENSE for additional details.
520+
521+ */
522+
523+#include <stdarg.h>
524+#include <stddef.h>
525+
526+#include <windows.h>
527+#include <errno.h>
528+
529+#include "mtops.h"
530+#include "mtio.h"
531+#if defined(_MSC_VER)
532+#include <winioctl.h>
533+#include <ntddscsi.h>
534+#else
535+#include <ddk/ntddstor.h>
536+#include <ddk/ntddscsi.h>
537+#endif
538+
539+#ifndef __cplusplus
540+typedef char bool;
541+#define true 1
542+#define false 0
543+#endif
544+
545+//
546+// SCSI bus status codes.
547+//
548+
549+#define SCSISTAT_GOOD                  0x00
550+#define SCSISTAT_CHECK_CONDITION       0x02
551+#define SCSISTAT_CONDITION_MET         0x04
552+#define SCSISTAT_BUSY                  0x08
553+#define SCSISTAT_INTERMEDIATE          0x10
554+#define SCSISTAT_INTERMEDIATE_COND_MET 0x14
555+#define SCSISTAT_RESERVATION_CONFLICT  0x18
556+#define SCSISTAT_COMMAND_TERMINATED    0x22
557+#define SCSISTAT_QUEUE_FULL            0x28
558+
559+/* Forward referenced functions */
560+
561+extern char my_name[];
562+extern int debug_level;
563+
564+inline   SHORT  Read16BitSigned(const unsigned char *pValue)
565+{
566+   return (SHORT)(((USHORT)pValue[0] << 8) | (USHORT)pValue[1]);
567+}
568+
569+inline   USHORT  Read16BitUnsigned(const unsigned char *pValue)
570+{
571+   return (((USHORT)pValue[0] << 8) | (USHORT)pValue[1]);
572+}
573+
574+inline   LONG  Read24BitSigned(const unsigned char *pValue)
575+{
576+   return ((LONG)(((ULONG)pValue[0] << 16) | ((ULONG)pValue[1] << 8) |
577+                   (ULONG)pValue[2])) << 8 >> 8;
578+}
579+
580+inline   ULONG  Read24BitUnsigned(const unsigned char *pValue)
581+{
582+   return ((ULONG)pValue[0] << 16) | ((ULONG)pValue[1] << 8) | (ULONG)pValue[2];
583+}
584+
585+inline   LONG  Read32BitSigned(const unsigned char *pValue)
586+{
587+   return (LONG)(((ULONG)pValue[0] << 24) | ((ULONG)pValue[1] << 16) |
588+                 ((ULONG)pValue[2] << 8) |   (ULONG)pValue[3]);
589+}
590+
591+inline   ULONG  Read32BitUnsigned(const unsigned char *pValue)
592+{
593+   return (((ULONG)pValue[0] << 24) | ((ULONG)pValue[1] << 16) |
594+           ((ULONG)pValue[2] << 8) | (ULONG)pValue[3]);
595+}
596+
597+inline   LONGLONG  Read64BitSigned(const unsigned char *pValue)
598+{
599+   return (LONGLONG)(((ULONGLONG)pValue[0] << 56) | ((ULONGLONG)pValue[1] << 48) |
600+                     ((ULONGLONG)pValue[2] << 40) | ((ULONGLONG)pValue[3] << 32) |
601+                     ((ULONGLONG)pValue[4] << 24) | ((ULONGLONG)pValue[5] << 16) |
602+                     ((ULONGLONG)pValue[6] <<  8) |  (ULONGLONG)pValue[7]);
603+}
604+
605+inline   ULONGLONG  Read64BitUnsigned(const unsigned char *pValue)
606+{
607+   return (LONGLONG)(((ULONGLONG)pValue[0] << 56) | ((ULONGLONG)pValue[1] << 48) |
608+                     ((ULONGLONG)pValue[2] << 40) | ((ULONGLONG)pValue[3] << 32) |
609+                     ((ULONGLONG)pValue[4] << 24) | ((ULONGLONG)pValue[5] << 16) |
610+                     ((ULONGLONG)pValue[6] <<  8) | (ULONGLONG)pValue[7]);
611+}
612+
613+typedef  struct   _TAPE_POSITION_INFO
614+{
615+   UCHAR       AtPartitionStart:1;
616+   UCHAR       AtPartitionEnd:1;
617+   UCHAR       PartitionBlockValid:1;
618+   UCHAR       FileSetValid:1;
619+   UCHAR       :4;
620+   UCHAR       Reserved1[3];
621+   ULONG       Partition;
622+   ULONGLONG   BlockNumber;
623+   ULONGLONG   FileNumber;
624+   ULONGLONG   SetNumber;
625+}  TAPE_POSITION_INFO, *PTAPE_POSITION_INFO;
626+
627+typedef  struct   _TAPE_HANDLE_INFO
628+{
629+   HANDLE      OSHandle;
630+   bool        bEOD;
631+   bool        bEOF;
632+   bool        bEOT;
633+   bool        bBlockValid;
634+   ULONG       FeaturesLow;
635+   ULONG       FeaturesHigh;
636+   ULONG       ulFile;
637+   ULONGLONG   ullFileStart;
638+
639+}  TAPE_HANDLE_INFO, *PTAPE_HANDLE_INFO;
640+
641+TAPE_HANDLE_INFO TapeHandleTable[] =
642+{
643+   { INVALID_HANDLE_VALUE },
644+   { INVALID_HANDLE_VALUE },
645+   { INVALID_HANDLE_VALUE },
646+   { INVALID_HANDLE_VALUE },
647+   { INVALID_HANDLE_VALUE },
648+   { INVALID_HANDLE_VALUE },
649+   { INVALID_HANDLE_VALUE },
650+   { INVALID_HANDLE_VALUE },
651+   { INVALID_HANDLE_VALUE },
652+   { INVALID_HANDLE_VALUE },
653+   { INVALID_HANDLE_VALUE },
654+   { INVALID_HANDLE_VALUE },
655+   { INVALID_HANDLE_VALUE },
656+   { INVALID_HANDLE_VALUE },
657+   { INVALID_HANDLE_VALUE },
658+   { INVALID_HANDLE_VALUE }
659+};
660+
661+#define  NUMBER_HANDLE_ENTRIES      (sizeof(TapeHandleTable) / sizeof(TapeHandleTable[0]))
662+
663+DWORD GetTapePositionInfo(HANDLE hDevice, PTAPE_POSITION_INFO TapePositionInfo);
664+DWORD GetDensityBlockSize(HANDLE hDevice, DWORD *pdwDensity, DWORD *pdwBlockSize);
665+
666+int tape_get(int fd, struct mtget *mt_get);
667+int tape_op(int fd, struct mtop *mt_com);
668+int tape_pos(int fd, struct mtpos *mt_pos);
669+
670+int
671+tape_open(const char *file, int flags, int mode)
672+{
673+   HANDLE hDevice = INVALID_HANDLE_VALUE;
674+   char szDeviceName[256] = "\\\\.\\";
675+   int  idxFile;
676+   DWORD dwResult;
677+
678+   for (idxFile = 0; idxFile < (int)NUMBER_HANDLE_ENTRIES; idxFile++) {
679+      if (TapeHandleTable[idxFile].OSHandle == INVALID_HANDLE_VALUE) {
680+         break;
681+      }
682+   }
683+
684+   if (idxFile >= (int)NUMBER_HANDLE_ENTRIES) {
685+      return EMFILE;
686+   }
687+
688+   memset(&TapeHandleTable[idxFile], 0, sizeof(TapeHandleTable[idxFile]));
689+
690+   if (file[0] != '\\' && file[0] != '/') {
691+       strncpy(&szDeviceName[4], file, sizeof(szDeviceName) - 4);
692+   } else {
693+       strncpy(&szDeviceName[0], file, sizeof(szDeviceName));
694+   }
695+
696+   szDeviceName[sizeof(szDeviceName) - 1] = '\0';
697+
698+   hDevice = CreateFile(szDeviceName, FILE_ALL_ACCESS, 0, NULL, OPEN_EXISTING, 0, NULL);
699+
700+   if (hDevice != INVALID_HANDLE_VALUE) {
701+      PTAPE_HANDLE_INFO    pHandleInfo = &TapeHandleTable[idxFile];
702+
703+      memset(pHandleInfo, 0, sizeof(*pHandleInfo));
704+
705+      pHandleInfo->OSHandle = hDevice;
706+
707+      TAPE_GET_DRIVE_PARAMETERS  TapeDriveParameters;
708+      DWORD    dwSize = sizeof(TapeDriveParameters);
709+
710+      dwResult = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &dwSize, &TapeDriveParameters);
711+      if (dwResult == NO_ERROR) {
712+         pHandleInfo->FeaturesLow = TapeDriveParameters.FeaturesLow;
713+         pHandleInfo->FeaturesHigh = TapeDriveParameters.FeaturesHigh;
714+      }
715+
716+      TAPE_POSITION_INFO TapePositionInfo;
717+
718+      dwResult =  GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo);
719+
720+      if (dwResult == NO_ERROR) {
721+         if (TapePositionInfo.AtPartitionStart || TapePositionInfo.AtPartitionEnd ||
722+             (TapePositionInfo.PartitionBlockValid && TapePositionInfo.BlockNumber == 0)) {
723+            pHandleInfo->ulFile = 0;
724+            pHandleInfo->bBlockValid = true;
725+            pHandleInfo->ullFileStart = 0;
726+         } else if (TapePositionInfo.FileSetValid) {
727+            pHandleInfo->ulFile = (ULONG)TapePositionInfo.FileNumber;
728+         }
729+      }
730+   } else {
731+      DWORD dwError = GetLastError();
732+
733+      switch (dwError) {
734+      case ERROR_FILE_NOT_FOUND:
735+      case ERROR_PATH_NOT_FOUND:
736+         errno = ENOENT;
737+         break;
738+
739+      case ERROR_TOO_MANY_OPEN_FILES:
740+         errno = EMFILE;
741+         break;
742+
743+      default:
744+      case ERROR_ACCESS_DENIED:
745+      case ERROR_SHARING_VIOLATION:
746+      case ERROR_LOCK_VIOLATION:
747+      case ERROR_INVALID_NAME:
748+         errno = EACCES;
749+         break;
750+
751+      case ERROR_FILE_EXISTS:
752+         errno = EEXIST;
753+         break;
754+
755+      case ERROR_INVALID_PARAMETER:
756+         errno = EINVAL;
757+         break;
758+      }
759+
760+      return(int) -1;
761+   }
762+
763+   return (int)idxFile + 3;
764+}
765+
766+int
767+tape_read(int fd, void *buffer, unsigned int count)
768+{
769+   if (buffer == NULL) {
770+      errno = EINVAL;
771+      return -1;
772+   }
773+
774+   if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) ||
775+       TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE)
776+   {
777+      errno = EBADF;
778+      return -1;
779+   }
780+
781+   PTAPE_HANDLE_INFO    pHandleInfo = &TapeHandleTable[fd - 3];
782+
783+   DWORD bytes_read;
784+   BOOL bResult;
785+
786+   bResult = ReadFile(pHandleInfo->OSHandle, buffer, count, &bytes_read, NULL);
787+
788+   if (bResult) {
789+      pHandleInfo->bEOF = false;
790+      pHandleInfo->bEOT = false;
791+      pHandleInfo->bEOD = false;
792+      return bytes_read;
793+   } else {
794+      int iReturnValue = 0;
795+      DWORD last_error = GetLastError();
796+
797+      switch (last_error) {
798+
799+      case ERROR_FILEMARK_DETECTED:
800+         pHandleInfo->bEOF = true;
801+         break;
802+
803+      case ERROR_END_OF_MEDIA:
804+         pHandleInfo->bEOT = true;
805+         break;
806+
807+      case ERROR_NO_MEDIA_IN_DRIVE:
808+         pHandleInfo->bEOF = false;
809+         pHandleInfo->bEOT = false;
810+         pHandleInfo->bEOD = false;
811+         errno = ENOMEDIUM;
812+         iReturnValue = -1;
813+         break;
814+
815+      case ERROR_NO_DATA_DETECTED:
816+         pHandleInfo->bEOD = true;
817+         break;
818+
819+      case ERROR_INVALID_HANDLE:
820+      case ERROR_ACCESS_DENIED:
821+      case ERROR_LOCK_VIOLATION:
822+         errno = EBADF;
823+         iReturnValue = -1;
824+         break;
825+
826+      default:
827+         pHandleInfo->bEOF = false;
828+         pHandleInfo->bEOT = false;
829+         pHandleInfo->bEOD = false;
830+         errno = EIO;
831+         iReturnValue = -1;
832+      }
833+
834+      return iReturnValue;
835+   }
836+}
837+
838+int
839+tape_write(int fd, const void *buffer, unsigned int count)
840+{
841+   if (buffer == NULL) {
842+      errno = EINVAL;
843+      return -1;
844+   }
845+
846+   if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) || TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE)
847+   {
848+      errno = EBADF;
849+      return -1;
850+   }
851+
852+   PTAPE_HANDLE_INFO    pHandleInfo = &TapeHandleTable[fd - 3];
853+
854+   DWORD bytes_written;
855+   BOOL bResult;
856+
857+   bResult = WriteFile(pHandleInfo->OSHandle, buffer, count, &bytes_written, NULL);
858+
859+   if (bResult) {
860+      pHandleInfo->bEOF = false;
861+      pHandleInfo->bEOT = false;
862+      return bytes_written;
863+   } else {
864+      DWORD last_error = GetLastError();
865+
866+      switch (last_error) {
867+      case ERROR_END_OF_MEDIA:
868+      case ERROR_DISK_FULL:
869+         pHandleInfo->bEOT = true;
870+         errno = ENOSPC;
871+         break;
872+
873+      case ERROR_NO_MEDIA_IN_DRIVE:
874+         pHandleInfo->bEOF = false;
875+         pHandleInfo->bEOT = false;
876+         pHandleInfo->bEOD = false;
877+         errno = ENOMEDIUM;
878+         break;
879+
880+      case ERROR_INVALID_HANDLE:
881+      case ERROR_ACCESS_DENIED:
882+         errno = EBADF;
883+         break;
884+
885+      default:
886+         pHandleInfo->bEOF = false;
887+         pHandleInfo->bEOT = false;
888+         pHandleInfo->bEOD = false;
889+         errno = EIO;
890+         break;
891+      }
892+      return -1;
893+   }
894+}
895+
896+int
897+tape_close(int fd)
898+{
899+   if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) ||
900+      TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) {
901+      errno = EBADF;
902+      return -1;
903+   }
904+
905+   PTAPE_HANDLE_INFO    pHandleInfo = &TapeHandleTable[fd - 3];
906+
907+   if (!CloseHandle(pHandleInfo->OSHandle)) {
908+      pHandleInfo->OSHandle = INVALID_HANDLE_VALUE;
909+      errno = EBADF;
910+      return -1;
911+   }
912+
913+   pHandleInfo->OSHandle = INVALID_HANDLE_VALUE;
914+
915+   return 0;
916+}
917+
918+int
919+tape_ioctl(int fd, unsigned long int request, ...)
920+{
921+   va_list argp;
922+   int result;
923+
924+   va_start(argp, request);
925+
926+   switch (request) {
927+   case MTIOCTOP:
928+      result = tape_op(fd, va_arg(argp, struct mtop *));
929+      break;
930+
931+   case MTIOCGET:
932+      result = tape_get(fd, va_arg(argp, struct mtget *));
933+      break;
934+
935+   case MTIOCPOS:
936+      result = tape_pos(fd, va_arg(argp, struct mtpos *));
937+      break;
938+
939+   default:
940+      errno = ENOTTY;
941+      result = -1;
942+      break;
943+   }
944+
945+   va_end(argp);
946+
947+   return result;
948+}
949+
950+int tape_op(int fd, struct mtop *mt_com)
951+{
952+   DWORD result = NO_ERROR;
953+   int   index;
954+
955+   if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) ||
956+       TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE)
957+   {
958+      errno = EBADF;
959+      return -1;
960+   }
961+
962+   PTAPE_HANDLE_INFO    pHandleInfo = &TapeHandleTable[fd - 3];
963+
964+   switch (mt_com->mt_op)
965+   {
966+   case MTRESET:
967+   case MTNOP:
968+   case MTSETDRVBUFFER:
969+      break;
970+
971+   default:
972+   case MTRAS1:
973+   case MTRAS2:
974+   case MTRAS3:
975+   case MTSETDENSITY:
976+      errno = ENOTTY;
977+      result = (DWORD)-1;
978+      break;
979+
980+   case MTFSF:
981+      for (index = 0; index < mt_com->mt_count; index++) {
982+         result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE);
983+         if (result == NO_ERROR) {
984+            pHandleInfo->ulFile++;
985+            pHandleInfo->bEOF = true;
986+            pHandleInfo->bEOT = false;
987+         }
988+      }
989+      break;
990+
991+   case MTBSF:
992+      for (index = 0; index < mt_com->mt_count; index++) {
993+         result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE);
994+         if (result == NO_ERROR) {
995+            pHandleInfo->ulFile--;
996+            pHandleInfo->bBlockValid = false;
997+            pHandleInfo->bEOD = false;
998+            pHandleInfo->bEOF = false;
999+            pHandleInfo->bEOT = false;
1000+         }
1001+      }
1002+      break;
1003+
1004+   case MTFSR:
1005+      result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_RELATIVE_BLOCKS, 0, mt_com->mt_count, 0, FALSE);
1006+      if (result == NO_ERROR) {
1007+         pHandleInfo->bEOD = false;
1008+         pHandleInfo->bEOF = false;
1009+         pHandleInfo->bEOT = false;
1010+      } else if (result == ERROR_FILEMARK_DETECTED) {
1011+         pHandleInfo->bEOF = true;
1012+      }
1013+      break;
1014+
1015+   case MTBSR:
1016+      result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_RELATIVE_BLOCKS, 0, -mt_com->mt_count, ~0, FALSE);
1017+      if (result == NO_ERROR) {
1018+         pHandleInfo->bEOD = false;
1019+         pHandleInfo->bEOF = false;
1020+         pHandleInfo->bEOT = false;
1021+      } else if (result == ERROR_FILEMARK_DETECTED) {
1022+         pHandleInfo->ulFile--;
1023+         pHandleInfo->bBlockValid = false;
1024+         pHandleInfo->bEOD = false;
1025+         pHandleInfo->bEOF = false;
1026+         pHandleInfo->bEOT = false;
1027+      }
1028+      break;
1029+
1030+   case MTWEOF:
1031+      result = WriteTapemark(pHandleInfo->OSHandle, TAPE_FILEMARKS, mt_com->mt_count, FALSE);
1032+      if (result == NO_ERROR) {
1033+         pHandleInfo->bEOF = true;
1034+         pHandleInfo->bEOT = false;
1035+         pHandleInfo->ulFile += mt_com->mt_count;
1036+         pHandleInfo->bBlockValid = true;
1037+         pHandleInfo->ullFileStart = 0;
1038+      }
1039+      break;
1040+
1041+   case MTREW:
1042+      result = SetTapePosition(pHandleInfo->OSHandle, TAPE_REWIND, 0, 0, 0, FALSE);
1043+      if (result == NO_ERROR) {
1044+         pHandleInfo->bEOD = false;
1045+         pHandleInfo->bEOF = false;
1046+         pHandleInfo->bEOT = false;
1047+         pHandleInfo->ulFile = 0;
1048+         pHandleInfo->bBlockValid = true;
1049+         pHandleInfo->ullFileStart = 0;
1050+      }
1051+      break;
1052+
1053+   case MTOFFL:
1054+      result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOAD, FALSE);
1055+      if (result == NO_ERROR) {
1056+         pHandleInfo->bEOD = false;
1057+         pHandleInfo->bEOF = false;
1058+         pHandleInfo->bEOT = false;
1059+         pHandleInfo->ulFile = 0;
1060+         pHandleInfo->ullFileStart = 0;
1061+      }
1062+      break;
1063+
1064+   case MTRETEN:
1065+      result = PrepareTape(pHandleInfo->OSHandle, TAPE_TENSION, FALSE);
1066+      if (result == NO_ERROR) {
1067+         pHandleInfo->bEOD = false;
1068+         pHandleInfo->bEOF = false;
1069+         pHandleInfo->bEOT = false;
1070+         pHandleInfo->ulFile = 0;
1071+         pHandleInfo->bBlockValid = true;
1072+         pHandleInfo->ullFileStart = 0;
1073+      }
1074+      break;
1075+
1076+   case MTBSFM:
1077+      for (index = 0; index < mt_com->mt_count; index++) {
1078+         result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE);
1079+         if (result == NO_ERROR) {
1080+            result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE);
1081+            pHandleInfo->bEOD = false;
1082+            pHandleInfo->bEOF = false;
1083+            pHandleInfo->bEOT = false;
1084+         }
1085+      }
1086+      break;
1087+
1088+   case MTFSFM:
1089+      for (index = 0; index < mt_com->mt_count; index++) {
1090+         result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, mt_com->mt_count, 0, FALSE);
1091+         if (result == NO_ERROR) {
1092+            result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE);
1093+            pHandleInfo->bEOD = false;
1094+            pHandleInfo->bEOF = false;
1095+            pHandleInfo->bEOT = false;
1096+         }
1097+      }
1098+      break;
1099+
1100+   case MTEOM:
1101+      for ( ; ; ) {
1102+         result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE);
1103+         if (result != NO_ERROR) {
1104+            pHandleInfo->bEOF = false;
1105+
1106+            if (result == ERROR_END_OF_MEDIA) {
1107+               pHandleInfo->bEOD = true;
1108+               pHandleInfo->bEOT = true;
1109+               return 0;
1110+            }
1111+            if (result == ERROR_NO_DATA_DETECTED) {
1112+               pHandleInfo->bEOD = true;
1113+               pHandleInfo->bEOT = false;
1114+               return 0;
1115+            }
1116+            break;
1117+         } else {
1118+            pHandleInfo->bEOF = true;
1119+            pHandleInfo->ulFile++;
1120+         }
1121+      }
1122+      break;
1123+
1124+   case MTERASE:
1125+      result = EraseTape(pHandleInfo->OSHandle, TAPE_ERASE_LONG, FALSE);
1126+      if (result == NO_ERROR) {
1127+         pHandleInfo->bEOD = true;
1128+         pHandleInfo->bEOF = false;
1129+         pHandleInfo->bEOT = false;
1130+         pHandleInfo->ulFile = 0;
1131+         pHandleInfo->bBlockValid = true;
1132+         pHandleInfo->ullFileStart = 0;
1133+      }
1134+      break;
1135+
1136+   case MTSETBLK:
1137+      {
1138+         TAPE_SET_MEDIA_PARAMETERS  SetMediaParameters;
1139+
1140+         SetMediaParameters.BlockSize = mt_com->mt_count;
1141+         result = SetTapeParameters(pHandleInfo->OSHandle, SET_TAPE_MEDIA_INFORMATION, &SetMediaParameters);
1142+      }
1143+      break;
1144+
1145+   case MTSEEK:
1146+      {
1147+         TAPE_POSITION_INFO   TapePositionInfo;
1148+
1149+         result = SetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, 0, mt_com->mt_count, 0, FALSE);
1150+
1151+         memset(&TapePositionInfo, 0, sizeof(TapePositionInfo));
1152+         DWORD dwPosResult = GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo);
1153+         if (dwPosResult == NO_ERROR && TapePositionInfo.FileSetValid) {
1154+            pHandleInfo->ulFile = (ULONG)TapePositionInfo.FileNumber;
1155+         } else {
1156+            pHandleInfo->ulFile = ~0U;
1157+         }
1158+      }
1159+      break;
1160+
1161+   case MTTELL:
1162+      {
1163+         DWORD partition;
1164+         DWORD offset;
1165+         DWORD offsetHi;
1166+
1167+         result = GetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, &partition, &offset, &offsetHi);
1168+         if (result == NO_ERROR) {
1169+            return offset;
1170+         }
1171+      }
1172+      break;
1173+
1174+   case MTFSS:
1175+      result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_SETMARKS, 0, mt_com->mt_count, 0, FALSE);
1176+      break;
1177+
1178+   case MTBSS:
1179+      result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_SETMARKS, 0, -mt_com->mt_count, ~0, FALSE);
1180+      break;
1181+
1182+   case MTWSM:
1183+      result = WriteTapemark(pHandleInfo->OSHandle, TAPE_SETMARKS, mt_com->mt_count, FALSE);
1184+      break;
1185+
1186+   case MTLOCK:
1187+      result = PrepareTape(pHandleInfo->OSHandle, TAPE_LOCK, FALSE);
1188+      break;
1189+
1190+   case MTUNLOCK:
1191+      result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOCK, FALSE);
1192+      break;
1193+
1194+   case MTLOAD:
1195+      result = PrepareTape(pHandleInfo->OSHandle, TAPE_LOAD, FALSE);
1196+      break;
1197+
1198+   case MTUNLOAD:
1199+      result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOAD, FALSE);
1200+      break;
1201+
1202+   case MTCOMPRESSION:
1203+      {
1204+         TAPE_GET_DRIVE_PARAMETERS  GetDriveParameters;
1205+         TAPE_SET_DRIVE_PARAMETERS  SetDriveParameters;
1206+         DWORD                      size;
1207+
1208+         size = sizeof(GetDriveParameters);
1209+
1210+         result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &size, &GetDriveParameters);
1211+
1212+         if (result == NO_ERROR)
1213+         {
1214+            SetDriveParameters.ECC = GetDriveParameters.ECC;
1215+            SetDriveParameters.Compression = (BOOLEAN)mt_com->mt_count;
1216+            SetDriveParameters.DataPadding = GetDriveParameters.DataPadding;
1217+            SetDriveParameters.ReportSetmarks = GetDriveParameters.ReportSetmarks;
1218+            SetDriveParameters.EOTWarningZoneSize = GetDriveParameters.EOTWarningZoneSize;
1219+
1220+            result = SetTapeParameters(pHandleInfo->OSHandle, SET_TAPE_DRIVE_INFORMATION, &SetDriveParameters);
1221+         }
1222+      }
1223+      break;
1224+
1225+   case MTSETPART:
1226+      result = SetTapePosition(pHandleInfo->OSHandle, TAPE_LOGICAL_BLOCK, mt_com->mt_count, 0, 0, FALSE);
1227+      break;
1228+
1229+   case MTMKPART:
1230+      if (mt_com->mt_count == 0)
1231+      {
1232+         result = CreateTapePartition(pHandleInfo->OSHandle, TAPE_INITIATOR_PARTITIONS, 1, 0);
1233+      }
1234+      else
1235+      {
1236+         result = CreateTapePartition(pHandleInfo->OSHandle, TAPE_INITIATOR_PARTITIONS, 2, mt_com->mt_count);
1237+      }
1238+      break;
1239+   }
1240+
1241+   if ((result == NO_ERROR && pHandleInfo->bEOF) ||
1242+       (result == ERROR_FILEMARK_DETECTED && mt_com->mt_op == MTFSR)) {
1243+
1244+      TAPE_POSITION_INFO TapePositionInfo;
1245+
1246+      if (GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo) == NO_ERROR) {
1247+         pHandleInfo->bBlockValid = true;
1248+         pHandleInfo->ullFileStart = TapePositionInfo.BlockNumber;
1249+      }
1250+   }
1251+
1252+   switch (result) {
1253+   case NO_ERROR:
1254+   case (DWORD)-1:   /* Error has already been translated into errno */
1255+      break;
1256+
1257+   default:
1258+   case ERROR_FILEMARK_DETECTED:
1259+      errno = EIO;
1260+      break;
1261+
1262+   case ERROR_END_OF_MEDIA:
1263+      pHandleInfo->bEOT = true;
1264+      errno = EIO;
1265+      break;
1266+
1267+   case ERROR_NO_DATA_DETECTED:
1268+      pHandleInfo->bEOD = true;
1269+      errno = EIO;
1270+      break;
1271+
1272+   case ERROR_NO_MEDIA_IN_DRIVE:
1273+      pHandleInfo->bEOF = false;
1274+      pHandleInfo->bEOT = false;
1275+      pHandleInfo->bEOD = false;
1276+      errno = ENOMEDIUM;
1277+      break;
1278+
1279+   case ERROR_INVALID_HANDLE:
1280+   case ERROR_ACCESS_DENIED:
1281+   case ERROR_LOCK_VIOLATION:
1282+      errno = EBADF;
1283+      break;
1284+   }
1285+
1286+   return result == NO_ERROR ? 0 : -1;
1287+}
1288+
1289+int tape_get(int fd, struct mtget *mt_get)
1290+{
1291+   TAPE_POSITION_INFO pos_info;
1292+   BOOL result;
1293+
1294+   if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) ||
1295+       TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) {
1296+      errno = EBADF;
1297+      return -1;
1298+   }
1299+
1300+   PTAPE_HANDLE_INFO    pHandleInfo = &TapeHandleTable[fd - 3];
1301+
1302+   if (GetTapePositionInfo(pHandleInfo->OSHandle, &pos_info) != NO_ERROR) {
1303+      return -1;
1304+   }
1305+
1306+   DWORD density = 0;
1307+   DWORD blocksize = 0;
1308+
1309+   result = GetDensityBlockSize(pHandleInfo->OSHandle, &density, &blocksize);
1310+
1311+   if (result != NO_ERROR) {
1312+      TAPE_GET_DRIVE_PARAMETERS drive_params;
1313+      DWORD size;
1314+
1315+      size = sizeof(drive_params);
1316+
1317+      result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &size, &drive_params);
1318+
1319+      if (result == NO_ERROR) {
1320+         blocksize = drive_params.DefaultBlockSize;
1321+      }
1322+   }
1323+
1324+   mt_get->mt_type = MT_ISSCSI2;
1325+
1326+   // Partition #
1327+   mt_get->mt_resid = pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
1328+
1329+   // Density / Block Size
1330+   mt_get->mt_dsreg = ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
1331+                      ((blocksize << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
1332+
1333+   mt_get->mt_gstat = 0x00010000;  /* Immediate report mode.*/
1334+
1335+   if (pHandleInfo->bEOF) {
1336+      mt_get->mt_gstat |= 0x80000000;     // GMT_EOF
1337+   }
1338+
1339+   if (pos_info.PartitionBlockValid && pos_info.BlockNumber == 0) {
1340+      mt_get->mt_gstat |= 0x40000000;     // GMT_BOT
1341+   }
1342+
1343+   if (pHandleInfo->bEOT) {
1344+      mt_get->mt_gstat |= 0x20000000;     // GMT_EOT
1345+   }
1346+
1347+   if (pHandleInfo->bEOD) {
1348+      mt_get->mt_gstat |= 0x08000000;     // GMT_EOD
1349+   }
1350+
1351+   TAPE_GET_MEDIA_PARAMETERS  media_params;
1352+   DWORD size = sizeof(media_params);
1353+
1354+   result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_MEDIA_INFORMATION, &size, &media_params);
1355+
1356+   if (result == NO_ERROR && media_params.WriteProtected) {
1357+      mt_get->mt_gstat |= 0x04000000;     // GMT_WR_PROT
1358+   }
1359+
1360+   result = GetTapeStatus(pHandleInfo->OSHandle);
1361+
1362+   if (result != NO_ERROR) {
1363+      if (result == ERROR_NO_MEDIA_IN_DRIVE) {
1364+         mt_get->mt_gstat |= 0x00040000;  // GMT_DR_OPEN
1365+      }
1366+   } else {
1367+      mt_get->mt_gstat |= 0x01000000;     // GMT_ONLINE
1368+   }
1369+
1370+   // Recovered Error Count
1371+   mt_get->mt_erreg = 0;
1372+
1373+   // File Number
1374+   mt_get->mt_fileno = (__kernel_daddr_t)pHandleInfo->ulFile;
1375+
1376+   // Block Number
1377+   mt_get->mt_blkno = (__kernel_daddr_t)(pHandleInfo->bBlockValid ? pos_info.BlockNumber - pHandleInfo->ullFileStart : (ULONGLONG)-1);
1378+
1379+   return 0;
1380+}
1381+
1382+#define  SERVICEACTION_SHORT_FORM_BLOCKID             0
1383+#define  SERVICEACTION_SHORT_FORM_VENDOR_SPECIFIC     1
1384+#define  SERVICEACTION_LONG_FORM                      6
1385+#define  SERVICEACTION_EXTENDED_FORM                  8
1386+
1387+
1388+typedef  struct   _SCSI_READ_POSITION_SHORT_BUFFER
1389+{
1390+   UCHAR    :1;
1391+   UCHAR    PERR:1;
1392+   UCHAR    BPU:1;
1393+   UCHAR    :1;
1394+   UCHAR    BYCU:1;
1395+   UCHAR    BCU:1;
1396+   UCHAR    EOP:1;
1397+   UCHAR    BOP:1;
1398+   UCHAR    Partition;
1399+   UCHAR    Reserved1[2];
1400+   UCHAR    FirstBlock[4];
1401+   UCHAR    LastBlock[4];
1402+   UCHAR    Reserved2;
1403+   UCHAR    NumberBufferBlocks[3];
1404+   UCHAR    NumberBufferBytes[4];
1405+}  SCSI_READ_POSITION_SHORT_BUFFER, *PSCSI_READ_POSITION_SHORT_BUFFER;
1406+
1407+typedef  struct   _SCSI_READ_POSITION_LONG_BUFFER
1408+{
1409+   UCHAR    :2;
1410+   UCHAR    BPU:1;
1411+   UCHAR    MPU:1;
1412+   UCHAR    :2;
1413+   UCHAR    EOP:1;
1414+   UCHAR    BOP:1;
1415+   UCHAR    Reserved3[3];
1416+   UCHAR    Partition[4];
1417+   UCHAR    BlockNumber[8];
1418+   UCHAR    FileNumber[8];
1419+   UCHAR    SetNumber[8];
1420+}  SCSI_READ_POSITION_LONG_BUFFER, *PSCSI_READ_POSITION_LONG_BUFFER;
1421+
1422+typedef  struct   _SCSI_READ_POSITION_EXTENDED_BUFFER
1423+{
1424+   UCHAR    :1;
1425+   UCHAR    PERR:1;
1426+   UCHAR    LOPU:1;
1427+   UCHAR    :1;
1428+   UCHAR    BYCU:1;
1429+   UCHAR    LOCU:1;
1430+   UCHAR    EOP:1;
1431+   UCHAR    BOP:1;
1432+   UCHAR    Partition;
1433+   UCHAR    AdditionalLength[2];
1434+   UCHAR    Reserved1;
1435+   UCHAR    NumberBufferObjects[3];
1436+   UCHAR    FirstLogicalObject[8];
1437+   UCHAR    LastLogicalObject[8];
1438+   UCHAR    NumberBufferObjectBytes[8];
1439+}  SCSI_READ_POSITION_EXTENDED_BUFFER, *PSCSI_READ_POSITION_EXTENDED_BUFFER;
1440+
1441+typedef union _READ_POSITION_RESULT {
1442+   SCSI_READ_POSITION_SHORT_BUFFER     ShortBuffer;
1443+   SCSI_READ_POSITION_LONG_BUFFER      LongBuffer;
1444+   SCSI_READ_POSITION_EXTENDED_BUFFER  ExtendedBuffer;
1445+}  READ_POSITION_RESULT, *PREAD_POSITION_RESULT;
1446+
1447+DWORD GetTapePositionInfo(HANDLE hDevice, PTAPE_POSITION_INFO TapePositionInfo)
1448+{
1449+   PSCSI_PASS_THROUGH   ScsiPassThrough;
1450+   BOOL                 bResult;
1451+   DWORD                dwBytesReturned;
1452+   int			pass;
1453+
1454+   const DWORD dwBufferSize = sizeof(SCSI_PASS_THROUGH) + sizeof(READ_POSITION_RESULT) + 28;
1455+
1456+   memset(TapePositionInfo, 0, sizeof(*TapePositionInfo));
1457+
1458+   ScsiPassThrough = (PSCSI_PASS_THROUGH)malloc(dwBufferSize);
1459+
1460+   for (pass = 0; pass < 2; pass++)
1461+   {
1462+      memset(ScsiPassThrough, 0, dwBufferSize);
1463+
1464+      ScsiPassThrough->Length = sizeof(SCSI_PASS_THROUGH);
1465+
1466+      ScsiPassThrough->CdbLength = 10;
1467+      ScsiPassThrough->SenseInfoLength = 28;
1468+      ScsiPassThrough->DataIn = 1;
1469+      ScsiPassThrough->DataTransferLength = sizeof(SCSI_READ_POSITION_LONG_BUFFER);
1470+      ScsiPassThrough->TimeOutValue = 1000;
1471+      ScsiPassThrough->DataBufferOffset = sizeof(SCSI_PASS_THROUGH) + 28;
1472+      ScsiPassThrough->SenseInfoOffset = sizeof(SCSI_PASS_THROUGH);
1473+
1474+      ScsiPassThrough->Cdb[0] = 0x34;  // READ POSITION
1475+
1476+      switch (pass)
1477+      {
1478+      case 0:
1479+         ScsiPassThrough->Cdb[1] = SERVICEACTION_LONG_FORM;
1480+         break;
1481+
1482+      case 1:
1483+         ScsiPassThrough->Cdb[1] = SERVICEACTION_SHORT_FORM_BLOCKID;
1484+         break;
1485+      }
1486+
1487+      bResult = DeviceIoControl( hDevice,
1488+                                 IOCTL_SCSI_PASS_THROUGH,
1489+                                 ScsiPassThrough, sizeof(SCSI_PASS_THROUGH),
1490+                                 ScsiPassThrough, dwBufferSize,
1491+                                 &dwBytesReturned,
1492+                                 NULL);
1493+
1494+      if (bResult && dwBytesReturned >= (offsetof(SCSI_PASS_THROUGH, ScsiStatus) + sizeof(ScsiPassThrough->ScsiStatus))) {
1495+         if (ScsiPassThrough->ScsiStatus == SCSISTAT_GOOD) {
1496+            PREAD_POSITION_RESULT   pPosResult = (PREAD_POSITION_RESULT)((PUCHAR)ScsiPassThrough + ScsiPassThrough->DataBufferOffset);
1497+
1498+            switch (pass)
1499+            {
1500+            case 0:     // SERVICEACTION_LONG_FORM
1501+               {
1502+                  TapePositionInfo->AtPartitionStart = pPosResult->LongBuffer.BOP;
1503+                  TapePositionInfo->AtPartitionEnd = pPosResult->LongBuffer.EOP;
1504+
1505+                  if (!TapePositionInfo->PartitionBlockValid) {
1506+                     TapePositionInfo->PartitionBlockValid = !pPosResult->LongBuffer.BPU;
1507+
1508+                     if (TapePositionInfo->PartitionBlockValid) {
1509+                        TapePositionInfo->Partition =   Read32BitUnsigned(pPosResult->LongBuffer.Partition);
1510+                        TapePositionInfo->BlockNumber = Read64BitUnsigned(pPosResult->LongBuffer.BlockNumber);
1511+                     }
1512+                  }
1513+
1514+                  TapePositionInfo->FileSetValid = !pPosResult->LongBuffer.MPU;
1515+                  if (TapePositionInfo->FileSetValid) {
1516+                     TapePositionInfo->FileNumber =  Read64BitUnsigned(pPosResult->LongBuffer.FileNumber);
1517+                     TapePositionInfo->SetNumber =   Read64BitUnsigned(pPosResult->LongBuffer.SetNumber);
1518+                  }
1519+               }
1520+               break;
1521+
1522+            case 1:     // SERVICEACTION_SHORT_FORM_BLOCKID
1523+               {
1524+                  // pPosResult->ShortBuffer.PERR;
1525+                  // pPosResult->ShortBuffer.BYCU;
1526+                  // pPosResult->ShortBuffer.BCU;
1527+                  TapePositionInfo->AtPartitionStart = pPosResult->ShortBuffer.BOP;
1528+                  TapePositionInfo->AtPartitionEnd = pPosResult->ShortBuffer.EOP;
1529+
1530+                  if (!TapePositionInfo->PartitionBlockValid) {
1531+                     TapePositionInfo->PartitionBlockValid = !pPosResult->ShortBuffer.BPU;
1532+
1533+                     if (TapePositionInfo->PartitionBlockValid) {
1534+                        TapePositionInfo->Partition =   pPosResult->ShortBuffer.Partition;
1535+                        TapePositionInfo->BlockNumber = Read32BitUnsigned(pPosResult->ShortBuffer.FirstBlock);
1536+                     }
1537+                  }
1538+                  // Read32BitsUnsigned(pPosResult->ShortBuffer.LastBlock);
1539+                  // Read24BitsUnsigned(pPosResult->ShortBuffer.NumberBufferBlocks);
1540+                  // Read32BitsUnsigned(pPosResult->ShortBuffer.NumberBufferBytes);
1541+               }
1542+               break;
1543+            }
1544+         }
1545+      }
1546+   }
1547+   free(ScsiPassThrough);
1548+
1549+   return NO_ERROR;
1550+}
1551+
1552+DWORD GetDensityBlockSize(HANDLE hDevice, DWORD *pdwDensity, DWORD *pdwBlockSize)
1553+{
1554+   DWORD             dwBufferSize = sizeof(GET_MEDIA_TYPES) + 5 * sizeof(DEVICE_MEDIA_INFO);
1555+   GET_MEDIA_TYPES * pGetMediaTypes = (GET_MEDIA_TYPES *)malloc(dwBufferSize);
1556+   BOOL              bResult;
1557+   DWORD             dwResult;
1558+   DWORD             idxMedia;
1559+
1560+   if (pGetMediaTypes == NULL) {
1561+      return ERROR_OUTOFMEMORY;
1562+   }
1563+
1564+   do {
1565+      DWORD          dwBytesReturned;
1566+
1567+      bResult = DeviceIoControl( hDevice,
1568+                                 IOCTL_STORAGE_GET_MEDIA_TYPES_EX,
1569+                                 NULL, 0,
1570+                                 (LPVOID)pGetMediaTypes, dwBufferSize,
1571+                                 &dwBytesReturned,
1572+                                 NULL);
1573+
1574+      if (!bResult) {
1575+         dwResult = GetLastError();
1576+
1577+         if (dwResult != ERROR_INSUFFICIENT_BUFFER) {
1578+            free(pGetMediaTypes);
1579+            return dwResult;
1580+         }
1581+
1582+         dwBufferSize += 6 * sizeof(DEVICE_MEDIA_INFO);
1583+
1584+         GET_MEDIA_TYPES * pNewBuffer = (GET_MEDIA_TYPES *)realloc(pGetMediaTypes, dwBufferSize);
1585+
1586+         if (pNewBuffer != pGetMediaTypes) {
1587+            free(pGetMediaTypes);
1588+
1589+            if (pNewBuffer == NULL) {
1590+               return ERROR_OUTOFMEMORY;
1591+            }
1592+
1593+            pGetMediaTypes = pNewBuffer;
1594+         }
1595+      }
1596+   } while (!bResult);
1597+
1598+   if (pGetMediaTypes->DeviceType != FILE_DEVICE_TAPE) {
1599+      free(pGetMediaTypes);
1600+      return ERROR_BAD_DEVICE;
1601+   }
1602+
1603+   for (idxMedia = 0; idxMedia < pGetMediaTypes->MediaInfoCount; idxMedia++) {
1604+
1605+      if (pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.MediaCharacteristics & MEDIA_CURRENTLY_MOUNTED) {
1606+
1607+         if (pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.BusType == BusTypeScsi) {
1608+            *pdwDensity = pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.BusSpecificData.ScsiInformation.DensityCode;
1609+         } else {
1610+            *pdwDensity = 0;
1611+         }
1612+
1613+         *pdwBlockSize = pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.CurrentBlockSize;
1614+
1615+         free(pGetMediaTypes);
1616+
1617+         return NO_ERROR;
1618+      }
1619+   }
1620+
1621+   free(pGetMediaTypes);
1622+
1623+   return ERROR_NO_MEDIA_IN_DRIVE;
1624+}
1625+
1626+int tape_pos(int fd, struct mtpos *mt_pos)
1627+{
1628+   DWORD partition;
1629+   DWORD offset;
1630+   DWORD offsetHi;
1631+   BOOL result;
1632+
1633+   if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) ||
1634+       TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) {
1635+      errno = EBADF;
1636+      return -1;
1637+   }
1638+
1639+   PTAPE_HANDLE_INFO    pHandleInfo = &TapeHandleTable[fd - 3];
1640+
1641+   result = GetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, &partition, &offset, &offsetHi);
1642+   if (result == NO_ERROR) {
1643+      mt_pos->mt_blkno = offset;
1644+      return 0;
1645+   }
1646+
1647+   return -1;
1648+}
1649--- /dev/null	1969-12-31 16:00:00.000000000 -0800
1650+++ mtops.h	2006-08-09 03:26:58.372973300 -0700
1651@@ -0,0 +1,15 @@
1652+int tape_open(const char *file, int flags, int mode);
1653+int tape_read(int fd, void *buffer, unsigned int count);
1654+int tape_write(int fd, const void *buffer, unsigned int count);
1655+int tape_ioctl(int fd, unsigned long int request, ...);
1656+int tape_close(int fd);
1657+
1658+typedef unsigned long	__kernel_daddr_t;
1659+
1660+#ifndef ENOMEDIUM
1661+#define ENOMEDIUM	123
1662+#endif
1663+
1664+#ifndef PATH_MAX
1665+#define PATH_MAX	1024
1666+#endif
1667--- /dev/null	1969-12-31 16:00:00.000000000 -0800
1668+++ Makefile.msc	2006-08-09 04:00:53.970613100 -0700
1669@@ -0,0 +1,20 @@
1670+CC=	cl
1671+CFLAGS=  /nologo /Ox /Gy /Zi /W3 /TP \
1672+	/D_CRT_SECURE_NO_DEPRECATE
1673+LDFLAGS= /link /DEBUG /INCREMENTAL:NO /OPT:NOREF /PDB:$*.pdb /OUT:$@
1674+PREFIX= C:\
1675+
1676+all:	mt.exe
1677+
1678+mt.exe:	mt.c
1679+	$(CC) $(CFLAGS) mt.c mtops.c $(LDFLAGS)
1680+
1681+stinit.exe:	stinit.c
1682+	$(CC) $(CFLAGS) stinit.c $(LDFLAGS)
1683+
1684+install: mt.exe
1685+	if not exist $(PREFIX)\bin\nul mkdir $(PREFIX)\bin
1686+	!copy /y $** $(PREFIX)\bin
1687+
1688+clean:
1689+	del /f *~ *.obj mt.exe stinit.exe
1690