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