From fb62e83995493be5635121c2e54ff11cffdb881c Mon Sep 17 00:00:00 2001 From: Robert Nelson Date: Sun, 30 Jul 2006 13:32:36 +0000 Subject: [PATCH] Add Microsoft Windows port of MT and MTX to depkgs. git-svn-id: https://bacula.svn.sourceforge.net/svnroot/bacula/trunk@3200 91ce42f0-d328-0410-95d8-f526ca767f89 --- bacula/src/win32/README.mingw32 | 2 +- bacula/src/win32/build-dependencies | 36 + bacula/src/win32/patches/mingw-utils.patch | 15 - bacula/src/win32/patches/mt.patch | 1661 ++++++++++++++++++++ bacula/src/win32/patches/mtx.patch | 1576 +++++++++++++++++++ 5 files changed, 3274 insertions(+), 16 deletions(-) create mode 100644 bacula/src/win32/patches/mt.patch create mode 100644 bacula/src/win32/patches/mtx.patch diff --git a/bacula/src/win32/README.mingw32 b/bacula/src/win32/README.mingw32 index 8acccdb405..354f37ef1c 100644 --- a/bacula/src/win32/README.mingw32 +++ b/bacula/src/win32/README.mingw32 @@ -99,7 +99,7 @@ to ensure that you pick up all the new Win32 changes: If one of the patches change in src/win32/patches, you shouldn't need to update the cross-tools or dependencies for it to build. -You can new patches by doing the following (we assume the patch +You can install new patches by doing the following (we assume the patch in question is for openssl): cd diff --git a/bacula/src/win32/build-dependencies b/bacula/src/win32/build-dependencies index 226905945a..1dbca6e7af 100755 --- a/bacula/src/win32/build-dependencies +++ b/bacula/src/win32/build-dependencies @@ -24,6 +24,10 @@ URL_NSIS_BIN=http://superb-west.dl.sourceforge.net/sourceforge/nsis/nsis-2.17.zi DIR_NSIS_BIN= URL_NSIS_SRC=http://superb-west.dl.sourceforge.net/sourceforge/nsis/nsis-2.17-src.tar.bz2 DIR_NSIS_SRC= +URL_MTX=http://superb-west.dl.sourceforge.net/sourceforge/mtx/mtx-1.3.9.tar.gz +DIR_MTX= +URL_MT=ftp://ftp.ibiblio.org/pub/linux/system/backup/mt-st-0.9b.tar.gz +DIR_MT= cwd=`pwd` cd `dirname $0` @@ -338,6 +342,37 @@ process_nsis() cp -p build/release/makensis/makensis ../../nsis } +process_mtx() +{ + if get_source "${URL_MTX}" "${DIR_MTX}" + then + echo Patching mtx + # We can't run configure in a cross-compile environment so we + # patch the files to the correct values + cp -f config.h.in config.h + cp -f Makefile.in Makefile + rm -f configure + do_patch mtx.patch + fi + echo Building mtx + do_make Makefile prefix=${DEPPKG_DIR} all + echo Installing mtx + do_make Makefile prefix=${DEPPKG_DIR} install +} + +process_mt() +{ + if get_source "${URL_MT}" "${DIR_MT}" + then + echo Patching mt + do_patch mt.patch + fi + echo Building mt + do_make Makefile prefix=${DEPPKG_DIR} all + echo Installing mt + do_make Makefile PREFIX=${DEPPKG_DIR} install +} + if [ "$#" -eq 0 ] then process_zlib @@ -350,6 +385,7 @@ then process_wxWidgets process_scons process_nsis + process_mtx else for dependency in "$@" do diff --git a/bacula/src/win32/patches/mingw-utils.patch b/bacula/src/win32/patches/mingw-utils.patch index fc0d649402..48bb6acb52 100644 --- a/bacula/src/win32/patches/mingw-utils.patch +++ b/bacula/src/win32/patches/mingw-utils.patch @@ -25,21 +25,6 @@ diff -u -r1.3 Makefile.am instdir = /tmp/$(PACKAGE)-$(VERSION) -Index: autogen.sh -=================================================================== -RCS file: /cvsroot/mingw/utils/autogen.sh,v -retrieving revision 1.3 -diff -u -r1.3 autogen.sh ---- autogen.sh 6 Oct 2002 09:55:42 -0000 1.3 -+++ autogen.sh 24 Jun 2006 00:31:11 -0000 -@@ -1,6 +1,6 @@ - #! /bin/sh - --export WANT_AUTOMAKE_1_6=1 -+export WANT_AUTOMAKE_1_7=1 - - aclocal \ - && autoheader \ Index: configure.ac =================================================================== RCS file: /cvsroot/mingw/utils/configure.ac,v diff --git a/bacula/src/win32/patches/mt.patch b/bacula/src/win32/patches/mt.patch new file mode 100644 index 0000000000..63a6a51ec9 --- /dev/null +++ b/bacula/src/win32/patches/mt.patch @@ -0,0 +1,1661 @@ +Only in .: .svn +diff -ru ../../ibiblio/mt-st-0.9b/Makefile ./Makefile +--- ../../ibiblio/mt-st-0.9b/Makefile Tue Aug 16 12:16:28 2005 ++++ ./Makefile Sun Jul 30 05:59:14 2006 +@@ -1,29 +1,27 @@ ++CC= mingw32-gcc + CFLAGS= -Wall -O2 +-SBINDIR= /sbin +-BINDIR= /bin +-MANDIR= /usr/share/man ++PREFIX= ++SBINDIR= $(PREFIX)/sbin ++BINDIR= $(PREFIX)/bin ++MANDIR= $(PREFIX)/man + +-all: mt stinit ++all: mt.exe + +-mt: mt.c +- $(CC) $(CFLAGS) -o mt mt.c ++mt.exe: mt.c ++ $(CC) $(CFLAGS) -o mt.exe mt.c mtops.c + +-stinit: stinit.c ++stinit.exe: stinit.c + $(CC) $(CFLAGS) -o stinit stinit.c + +-install: mt stinit +- install -s mt $(BINDIR) ++install: mt.exe ++ install -s mt.exe $(BINDIR) + install -c -m 444 mt.1 $(MANDIR)/man1 + (if [ -f $(MANDIR)/man1/mt.1.gz ] ; then \ + rm -f $(MANDIR)/man1/mt.1.gz; gzip $(MANDIR)/man1/mt.1; fi) +- install -s stinit $(SBINDIR) +- install -c -m 444 stinit.8 $(MANDIR)/man8 +- (if [ -f $(MANDIR)/man8/stinit.8.gz ] ; then \ +- rm -f $(MANDIR)/man8/stinit.8.gz; gzip $(MANDIR)/man8/stinit.8; fi) + + dist: clean + (mydir=`basename \`pwd\``;\ + cd .. && tar cvvf - $$mydir | gzip -9 > $${mydir}.tar.gz) + + clean: +- rm -f *~ \#*\# *.o mt stinit ++ rm -f *~ \#*\# *.o mt.exe stinit.exe +Only in .: compat.h +Only in .: mt +diff -ru ../../ibiblio/mt-st-0.9b/mt.1 ./mt.1 +--- ../../ibiblio/mt-st-0.9b/mt.1 Sun Aug 21 11:53:50 2005 ++++ ./mt.1 Sun Jul 30 05:16:07 2006 +@@ -48,20 +48,22 @@ + files. + The tape is positioned on the first block of the next file. + .IP fsfm +-Forward space ++Forward space past + .I count +-files. +-The tape is positioned on the last block of the previous file. ++file marks, then backward space one file record. ++This leaves the tape positioned on the last block of the file that is count-1 ++files past the current file. + .IP bsf + Backward space + .I count + files. + The tape is positioned on the last block of the previous file. + .IP bsfm +-Backward space ++Backward space past + .I count +-files. +-The tape is positioned on the first block of the next file. ++file marks, then forward space one file record. ++This leaves the tape positioned on the first block of the file that is count-1 ++files before the current file. + .IP asf + The tape is positioned at the beginning of the + .I count +diff -ru ../../ibiblio/mt-st-0.9b/mt.c ./mt.c +--- ../../ibiblio/mt-st-0.9b/mt.c Sun Aug 21 11:48:06 2005 ++++ ./mt.c Sun Jul 30 06:04:13 2006 +@@ -11,6 +11,12 @@ + Last Modified: Sun Aug 21 21:48:06 2005 by kai.makisara + */ + ++#include ++#include ++#include ++ ++#define O_NONBLOCK 0 ++ + #include + #include + #include +@@ -19,15 +25,17 @@ + #include + #include + #include +-#include + ++#include "mtops.h" + #include "mtio.h" + ++#define ioctl tape_ioctl ++ + #ifndef DEFTAPE +-#define DEFTAPE "/dev/tape" /* default tape device */ ++#define DEFTAPE "Tape0" /* default tape device */ + #endif /* DEFTAPE */ + +-#define VERSION "0.9b" ++#define VERSION "0.9b-bacula" + + typedef int (* cmdfunc)(/* int, struct cmdef_tr *, int, char ** */); + +@@ -143,12 +151,14 @@ + FD_RDONLY, ONE_ARG, 0}, + { "defcompression", MTSETDRVBUFFER, do_drvbuffer, MT_ST_DEF_COMPRESSION, + FD_RDONLY, ONE_ARG, 0}, ++#if 0 + { "stsetcln", MTSETDRVBUFFER, do_drvbuffer, MT_ST_SET_CLN, + FD_RDONLY, ONE_ARG, 0}, + { "sttimeout", MTSETDRVBUFFER, do_drvbuffer, MT_ST_SET_TIMEOUT, + FD_RDONLY, ONE_ARG, 0}, + { "stlongtimeout", MTSETDRVBUFFER, do_drvbuffer, MT_ST_SET_LONG_TIMEOUT, + FD_RDONLY, ONE_ARG, 0}, ++#endif + { "densities", 0, print_densities, 0, NO_FD, NO_ARGS, + 0 }, + { "setpartition", MTSETPART, do_standard, 0, FD_RDONLY, ONE_ARG, +@@ -211,13 +221,19 @@ + {0x30, "AIT-1 or MLR3"}, + {0x31, "AIT-2"}, + {0x32, "AIT-3"}, +- {0x33, "SLR6"}, ++ {0x33, "AIT-4 or SLR6"}, + {0x34, "SLR100"}, ++ {0x38, "AIT-E Turbo"}, ++ {0x39, "AIT-1 Turbo"}, ++ {0x3A, "AIT-2 Turbo"}, ++ {0x3B, "AIT-3Ex"}, + {0x40, "DLT1 40 GB, or Ultrium"}, + {0x41, "DLT 40GB, or Ultrium2"}, + {0x42, "LTO-2"}, + {0x45, "QIC-3095-MC (TR-4)"}, + {0x47, "TR-5"}, ++ {0x48, "Quantum SDLT220"}, ++ {0x49, "Quantum SDLT320"}, + {0x80, "DLT 15GB uncomp. or Ecrix"}, + {0x81, "DLT 15GB compressed"}, + {0x82, "DLT 20GB uncompressed"}, +@@ -254,20 +270,25 @@ + {"no-blklimits", MT_ST_NO_BLKLIMS, "drive doesn't support read block limits"}, + {"can-partitions",MT_ST_CAN_PARTITIONS,"drive can handle partitioned tapes"}, + {"scsi2logical", MT_ST_SCSI2LOGICAL, "logical block addresses used with SCSI-2"}, ++#if 0 + {"no-wait", MT_ST_NOWAIT, "immediate mode for rewind, etc."}, ++#endif + #ifdef MT_ST_SYSV + {"sysv", MT_ST_SYSV, "enable the SystemV semantics"}, + #endif ++#if 0 + {"cleaning", MT_ST_SET_CLN, "set the cleaning bit location and mask"}, ++#endif + {NULL, 0}}; + + static char *tape_name; /* The tape name for messages */ + + +- int ++int + main(int argc, char **argv) + { +- int mtfd, cmd_code, i, argn, len, oflags; ++ int mtfd, cmd_code, i, argn, oflags; ++ unsigned int len; + char *cmdstr; + cmdef_tr *comp, *comp2; + +@@ -344,7 +365,7 @@ + oflags = comp->cmd_fdtype == FD_RDONLY ? O_RDONLY : O_RDWR; + if ((comp->error_tests & ET_ONLINE) == 0) + oflags |= O_NONBLOCK; +- if ((mtfd = open(tape_name, oflags)) < 0) { ++ if ((mtfd = tape_open(tape_name, oflags, 0)) < 0) { + perror(tape_name); + exit(1); + } +@@ -368,7 +389,7 @@ + } + + if (mtfd >= 0) +- close(mtfd); ++ tape_close(mtfd); + return i; + } + +@@ -409,9 +430,9 @@ + do_standard(int mtfd, cmdef_tr *cmd, int argc, char **argv) + { + struct mtop mt_com; +- char *endp; ++ char *endp = NULL; + +- mt_com.mt_op = cmd->cmd_code; ++ mt_com.mt_op = (short)cmd->cmd_code; + mt_com.mt_count = (argc > 0 ? strtol(*argv, &endp, 0) : 1); + if (argc > 0 && endp != *argv) { + if (*endp == 'k') +@@ -464,7 +485,8 @@ + static int + do_options(int mtfd, cmdef_tr *cmd, int argc, char **argv) + { +- int i, an, len; ++ int i, an; ++ unsigned int len; + struct mtop mt_com; + + mt_com.mt_op = MTSETDRVBUFFER; +@@ -596,8 +618,10 @@ + type = "SCSI 1"; + else if (status.mt_type == MT_ISSCSI2) + type = "SCSI 2"; ++#if 0 + else if (status.mt_type == MT_ISONSTREAM_SC) + type = "OnStream SC-, DI-, DP-, or USB"; ++#endif + else + type = NULL; + if (type == NULL) { +@@ -607,7 +631,7 @@ + printf("IDE-Tape (type code 0) ?\n"); + else + printf("Unknown tape drive type (type code %ld)\n", status.mt_type); +- printf("File number=%d, block number=%d.\n", ++ printf("File number=%ld, block number=%ld.\n", + status.mt_fileno, status.mt_blkno); + printf("mt_resid: %ld, mt_erreg: 0x%lx\n", + status.mt_resid, status.mt_erreg); +@@ -617,14 +641,17 @@ + else { + printf("%s tape drive:\n", type); + if (status.mt_type == MT_ISSCSI2) +- printf("File number=%d, block number=%d, partition=%ld.\n", ++ printf("File number=%ld, block number=%ld, partition=%ld.\n", + status.mt_fileno, status.mt_blkno, (status.mt_resid & 0xff)); + else +- printf("File number=%d, block number=%d.\n", ++ printf("File number=%ld, block number=%ld.\n", + status.mt_fileno, status.mt_blkno); +- if (status.mt_type == MT_ISSCSI1 || +- status.mt_type == MT_ISSCSI2 || +- status.mt_type == MT_ISONSTREAM_SC) { ++ if (status.mt_type == MT_ISSCSI1 ++ || status.mt_type == MT_ISSCSI2 ++#if 0 ++ || status.mt_type == MT_ISONSTREAM_SC ++#endif ++ ) { + dens = (status.mt_dsreg & MT_ST_DENSITY_MASK) >> MT_ST_DENSITY_SHIFT; + density = "no translation"; + for (i=0; i < NBR_DENSITIES; i++) +@@ -666,8 +693,10 @@ + printf(" DR_OPEN"); + if (GMT_IM_REP_EN(status.mt_gstat)) + printf(" IM_REP_EN"); ++#if 0 + if (GMT_CLN(status.mt_gstat)) + printf(" CLN"); ++#endif + printf("\n"); + return 0; + } +Only in .: mt.exe +Only in .: mt.patch +diff -ru ../../ibiblio/mt-st-0.9b/mtio.h ./mtio.h +--- ../../ibiblio/mt-st-0.9b/mtio.h Tue Aug 16 12:16:28 2005 ++++ ./mtio.h Sun Jul 30 06:06:13 2006 +@@ -8,9 +8,7 @@ + #ifndef _LINUX_MTIO_H + #define _LINUX_MTIO_H + +-#include +-#include +-#include ++#include + + /* + * Structures and definitions for mag tape io control commands +@@ -150,6 +148,7 @@ + }; + + ++#ifdef USE_QIC02 + /* structure for MTIOCGETCONFIG/MTIOCSETCONFIG primarily intended + * as an interim solution for QIC-02 until DDI is fully implemented. + */ +@@ -281,6 +280,7 @@ + * command + */ + }; ++#endif + + /* mag tape io control commands */ + #define MTIOCTOP _IOW('m', 1, struct mtop) /* do a mag tape op */ +Only in .: mtops.c +Only in .: mtops.h +diff -ru ../../ibiblio/mt-st-0.9b/stinit.def.examples ./stinit.def.examples +--- ../../ibiblio/mt-st-0.9b/stinit.def.examples Tue Aug 16 12:16:28 2005 ++++ ./stinit.def.examples Sun Jul 30 05:15:43 2006 +@@ -56,3 +56,169 @@ + mode3 blocksize=0 density=1 # 800 bpi + } + ++# DLT2000 / 2000XT ++manufacturer="QUANTUM" model = "DLT2000" { ++scsi2logical=1 ++can-bsr ++auto-lock=0 ++two-fms=0 ++drive-buffering=1 ++buffer-writes ++read-ahead=1 ++async-writes=1 ++can-partitions=0 ++fast-mteom=1 ++# ++# If your stinit supports the timeouts: ++timeout=3600 # 1 hour ++long-timeout=14400 # 4 hours ++# ++mode1 blocksize=0 density=0x81 # 10GB + compression on DLTtape III, 15+ with DLTtape IIIXT in 2000XT ++mode2 blocksize=0 density=0x80 # 10GB, no compression on DLTtape III, 15 with DLTtape IIIXT in 2000XT ++mode3 blocksize=0 density=0x18 # 6GB, compression not available, on DLTtape III ++mode4 blocksize=0 density=0x17 #2.6GB, compression not available, on DLTtape III ++} ++ ++# DLT4000 ++manufacturer="QUANTUM" model = "DLT4000" { ++scsi2logical=1 ++can-bsr ++auto-lock=0 ++two-fms=0 ++drive-buffering=1 ++buffer-writes ++read-ahead=1 ++async-writes=1 ++can-partitions=0 ++fast-mteom=1 ++# ++# If your stinit supports the timeouts: ++timeout=3600 # 1 hour ++long-timeout=14400 # 4 hours ++# ++# Drive is backwards compatible, use older modes (e.g. from above) as required ++mode1 blocksize=0 density=0x83 # 20GB + compression ++mode2 blocksize=0 density=0x82 # 20GB, no compression ++mode3 blocksize=0 density=0x81 # 10GB + compression (DLT2000 mode) with DLTtape III, 15+ with DLTtape IIIXT in 2000XT ++mode4 blocksize=0 density=0x80 # 10GB, no compression (DLT2000 mode) with DLTtape III, 15 with DLTtape IIIXT in 2000XT ++} ++ ++# DLT7000 ++manufacturer="QUANTUM" model = "DLT7000" { ++scsi2logical=1 ++can-bsr ++auto-lock=0 ++two-fms=0 ++drive-buffering=1 ++buffer-writes ++read-ahead=1 ++async-writes=1 ++can-partitions=0 ++fast-mteom=1 ++# ++# If your stinit supports the timeouts: ++timeout=3600 # 1 hour ++long-timeout=14400 # 4 hours ++# ++# Drive is backwards compatible, use older modes (e.g. from above) as required. ++mode1 blocksize=0 density=0x85 # 35GB + compression ++mode2 blocksize=0 density=0x84 # 35GB, no compression ++mode3 blocksize=0 density=0x83 # 20GB + compression (DLT4000 mode) ++mode4 blocksize=0 density=0x82 # 20GB, no compression (DLT4000 mode) ++} ++ ++# DLT8000 ++manufacturer="QUANTUM" model = "DLT8000" { ++scsi2logical=1 ++can-bsr=1 ++auto-lock=0 ++two-fms=0 ++drive-buffering=1 ++buffer-writes ++read-ahead=1 ++async-writes=1 ++can-partitions=0 ++fast-mteom=1 ++# ++# If your stinit supports the timeouts: ++timeout=3600 # 1 hour ++long-timeout=14400 # 4 hours ++# ++# Drive is backwards compatible to DLT7000, use older modes (e.g. from above) as required. Modes <10GB (<0x19) not supported! ++mode1 blocksize=0 density=0x89 # 40GB + compression ++mode2 blocksize=0 density=0x88 # 40GB, no compression ++mode3 blocksize=0 density=0x85 # 35GB + compression (DLT7000 mode) ++mode4 blocksize=0 density=0x84 # 35GB, no compression (DLT7000 mode) ++} ++ ++ ++# SDLT220 ++manufacturer="QUANTUM" model = "SuperDLT1" { ++scsi2logical=1 ++can-bsr=1 ++auto-lock=0 ++two-fms=0 ++drive-buffering=1 ++buffer-writes ++read-ahead=1 ++async-writes=1 ++can-partitions=0 ++fast-mteom=1 ++# ++# If your stinit supports the timeouts: ++timeout=3600 # 1 hour ++long-timeout=14400 # 4 hours ++# ++# Drive is backwards read compatible to DLT4000/7000/8000. Mode settings are only required for writing, so no need to define any other modes here. ++mode1 blocksize=0 density=0x48 compression=1 # 110 GB + compression ++mode2 blocksize=0 density=0x48 compression=0 # 110 GB, no ompression ++} ++ ++# SDLT320 ++manufacturer="QUANTUM" model = "SDLT320" { ++scsi2logical=1 ++can-bsr=1 ++auto-lock=0 ++two-fms=0 ++drive-buffering=1 ++buffer-writes ++read-ahead=1 ++async-writes=1 ++can-partitions=0 ++fast-mteom=1 ++# ++# If your stinit supports the timeouts: ++timeout=3600 # 1 hour ++long-timeout=14400 # 4 hours ++# ++# Drive is backwards write compatible to SDLT220 and read compatible to DLT4000/7000/8000. Mode settings are only required for writing, so we need only the SDL220/320 modes here ++mode1 blocksize=0 density=0x49 compression=1 # 160 GB + compression ++mode2 blocksize=0 density=0x49 compression=0 # 160 GB, no ompression ++mode3 blocksize=0 density=0x48 compression=1 # 110 GB + compression ++mode4 blocksize=0 density=0x48 compression=0 # 110 GB, no ompression ++} ++ ++# SDLT600 ++manufacturer="QUANTUM" model = "SDLT600" { ++scsi2logical=1 ++can-bsr=1 ++auto-lock=0 ++two-fms=0 ++drive-buffering=1 ++buffer-writes ++read-ahead=1 ++async-writes=1 ++can-partitions=0 ++fast-mteom=1 ++# ++# If your stinit supports the timeouts: ++timeout=3600 # 1 hour ++long-timeout=14400 # 4 hours ++# ++# Drive is backwards read compatible to SDLT220/320 and VS160. Mode settings are only required for writing, so we need only the native SDLT600 mode here. ++mode1 blocksize=0 density=0x4a compression=1 # 300 GB + compression ++mode2 blocksize=0 density=0x4a compression=0 # 300 GB, no ompression ++mode3 blocksize=0 density=0x4a compression=1 # 300 GB + compression ++mode4 blocksize=0 density=0x4a compression=0 # 300 GB, no ompression ++} ++ +--- /dev/null Sun Jul 30 06:23:05 2006 ++++ mtops.h Sun Jul 30 05:50:17 2006 +@@ -0,0 +1,15 @@ ++int tape_open(const char *file, int flags, int mode); ++int tape_read(int fd, void *buffer, unsigned int count); ++int tape_write(int fd, const void *buffer, unsigned int count); ++int tape_ioctl(int fd, unsigned long int request, ...); ++int tape_close(int fd); ++ ++typedef unsigned long __kernel_daddr_t; ++ ++#ifndef ENOMEDIUM ++#define ENOMEDIUM 123 ++#endif ++ ++#ifndef PATH_MAX ++#define PATH_MAX 1024 ++#endif +--- /dev/null Sun Jul 30 06:23:10 2006 ++++ mtops.c Sun Jul 30 05:46:08 2006 +@@ -0,0 +1,1158 @@ ++/* ++ * mtops.cpp - Emulate the Linux st (scsi tape) driver on Microsoft Windows. ++ * ++ * Author: Robert Nelson, May, 2006 ++ * ++ * Version $Id$ ++ * ++ * Copyright (C) 2006 Kern Sibbald ++ * ++ * This file was contributed to the Bacula project by Robert Nelson. ++ * ++ * Robert Nelson has been granted a perpetual, worldwide, ++ * non-exclusive, no-charge, royalty-free, irrevocable copyright ++ * license to reproduce, prepare derivative works of, publicly ++ * display, publicly perform, sublicense, and distribute the original ++ * work contributed by Robert Nelson to the Bacula project in source ++ * or object form. ++ * ++ * If you wish to license contributions from Robert Nelson ++ * under an alternate open source license please contact ++ * Robert Nelson . ++ */ ++/* ++ Copyright (C) 2006 Kern Sibbald ++ ++ This program is free software; you can redistribute it and/or ++ modify it under the terms of the GNU General Public License ++ version 2 as amended with additional clauses defined in the ++ file LICENSE in the main source directory. ++ ++ This program is distributed in the hope that it will be useful, ++ but WITHOUT ANY WARRANTY; without even the implied warranty of ++ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ the file LICENSE for additional details. ++ ++ */ ++ ++#include ++#include ++ ++#include ++#include ++ ++#include "mtops.h" ++#include "mtio.h" ++#include ++#include ++ ++#ifndef __CPLUS_PLUS ++typedef char bool; ++#define true 1 ++#define false 0 ++#endif ++ ++// ++// SCSI bus status codes. ++// ++ ++#define SCSISTAT_GOOD 0x00 ++#define SCSISTAT_CHECK_CONDITION 0x02 ++#define SCSISTAT_CONDITION_MET 0x04 ++#define SCSISTAT_BUSY 0x08 ++#define SCSISTAT_INTERMEDIATE 0x10 ++#define SCSISTAT_INTERMEDIATE_COND_MET 0x14 ++#define SCSISTAT_RESERVATION_CONFLICT 0x18 ++#define SCSISTAT_COMMAND_TERMINATED 0x22 ++#define SCSISTAT_QUEUE_FULL 0x28 ++ ++/* Forward referenced functions */ ++ ++extern char my_name[]; ++extern int debug_level; ++ ++inline SHORT Read16BitSigned(const unsigned char *pValue) ++{ ++ return (SHORT)(((USHORT)pValue[0] << 8) | (USHORT)pValue[1]); ++} ++ ++inline USHORT Read16BitUnsigned(const unsigned char *pValue) ++{ ++ return (((USHORT)pValue[0] << 8) | (USHORT)pValue[1]); ++} ++ ++inline LONG Read24BitSigned(const unsigned char *pValue) ++{ ++ return ((LONG)(((ULONG)pValue[0] << 16) | ((ULONG)pValue[1] << 8) | ++ (ULONG)pValue[2])) << 8 >> 8; ++} ++ ++inline ULONG Read24BitUnsigned(const unsigned char *pValue) ++{ ++ return ((ULONG)pValue[0] << 16) | ((ULONG)pValue[1] << 8) | (ULONG)pValue[2]; ++} ++ ++inline LONG Read32BitSigned(const unsigned char *pValue) ++{ ++ return (LONG)(((ULONG)pValue[0] << 24) | ((ULONG)pValue[1] << 16) | ++ ((ULONG)pValue[2] << 8) | (ULONG)pValue[3]); ++} ++ ++inline ULONG Read32BitUnsigned(const unsigned char *pValue) ++{ ++ return (((ULONG)pValue[0] << 24) | ((ULONG)pValue[1] << 16) | ++ ((ULONG)pValue[2] << 8) | (ULONG)pValue[3]); ++} ++ ++inline LONGLONG Read64BitSigned(const unsigned char *pValue) ++{ ++ return (LONGLONG)(((ULONGLONG)pValue[0] << 56) | ((ULONGLONG)pValue[1] << 48) | ++ ((ULONGLONG)pValue[2] << 40) | ((ULONGLONG)pValue[3] << 32) | ++ ((ULONGLONG)pValue[4] << 24) | ((ULONGLONG)pValue[5] << 16) | ++ ((ULONGLONG)pValue[6] << 8) | (ULONGLONG)pValue[7]); ++} ++ ++inline ULONGLONG Read64BitUnsigned(const unsigned char *pValue) ++{ ++ return (LONGLONG)(((ULONGLONG)pValue[0] << 56) | ((ULONGLONG)pValue[1] << 48) | ++ ((ULONGLONG)pValue[2] << 40) | ((ULONGLONG)pValue[3] << 32) | ++ ((ULONGLONG)pValue[4] << 24) | ((ULONGLONG)pValue[5] << 16) | ++ ((ULONGLONG)pValue[6] << 8) | (ULONGLONG)pValue[7]); ++} ++ ++typedef struct _TAPE_POSITION_INFO ++{ ++ UCHAR AtPartitionStart:1; ++ UCHAR AtPartitionEnd:1; ++ UCHAR PartitionBlockValid:1; ++ UCHAR FileSetValid:1; ++ UCHAR :4; ++ UCHAR Reserved1[3]; ++ ULONG Partition; ++ ULONGLONG BlockNumber; ++ ULONGLONG FileNumber; ++ ULONGLONG SetNumber; ++} TAPE_POSITION_INFO, *PTAPE_POSITION_INFO; ++ ++typedef struct _TAPE_HANDLE_INFO ++{ ++ HANDLE OSHandle; ++ bool bEOD; ++ bool bEOF; ++ bool bEOT; ++ bool bBlockValid; ++ ULONG FeaturesLow; ++ ULONG FeaturesHigh; ++ ULONG ulFile; ++ ULONGLONG ullFileStart; ++ ++} TAPE_HANDLE_INFO, *PTAPE_HANDLE_INFO; ++ ++TAPE_HANDLE_INFO TapeHandleTable[] = ++{ ++ { INVALID_HANDLE_VALUE }, ++ { INVALID_HANDLE_VALUE }, ++ { INVALID_HANDLE_VALUE }, ++ { INVALID_HANDLE_VALUE }, ++ { INVALID_HANDLE_VALUE }, ++ { INVALID_HANDLE_VALUE }, ++ { INVALID_HANDLE_VALUE }, ++ { INVALID_HANDLE_VALUE }, ++ { INVALID_HANDLE_VALUE }, ++ { INVALID_HANDLE_VALUE }, ++ { INVALID_HANDLE_VALUE }, ++ { INVALID_HANDLE_VALUE }, ++ { INVALID_HANDLE_VALUE }, ++ { INVALID_HANDLE_VALUE }, ++ { INVALID_HANDLE_VALUE }, ++ { INVALID_HANDLE_VALUE } ++}; ++ ++#define NUMBER_HANDLE_ENTRIES (sizeof(TapeHandleTable) / sizeof(TapeHandleTable[0])) ++ ++DWORD GetTapePositionInfo(HANDLE hDevice, PTAPE_POSITION_INFO TapePositionInfo); ++DWORD GetDensityBlockSize(HANDLE hDevice, DWORD *pdwDensity, DWORD *pdwBlockSize); ++ ++int tape_get(int fd, struct mtget *mt_get); ++int tape_op(int fd, struct mtop *mt_com); ++int tape_pos(int fd, struct mtpos *mt_pos); ++ ++int ++tape_open(const char *file, int flags, int mode) ++{ ++ HANDLE hDevice = INVALID_HANDLE_VALUE; ++ char szDeviceName[256] = "\\\\.\\"; ++ int idxFile; ++ DWORD dwResult; ++ ++ for (idxFile = 0; idxFile < (int)NUMBER_HANDLE_ENTRIES; idxFile++) { ++ if (TapeHandleTable[idxFile].OSHandle == INVALID_HANDLE_VALUE) { ++ break; ++ } ++ } ++ ++ if (idxFile >= (int)NUMBER_HANDLE_ENTRIES) { ++ return EMFILE; ++ } ++ ++ memset(&TapeHandleTable[idxFile], 0, sizeof(TapeHandleTable[idxFile])); ++ ++ if (file[0] != '\\' && file[0] != '/') { ++ strncpy(&szDeviceName[4], file, sizeof(szDeviceName) - 4); ++ } else { ++ strncpy(&szDeviceName[0], file, sizeof(szDeviceName)); ++ } ++ ++ szDeviceName[sizeof(szDeviceName) - 1] = '\0'; ++ ++ hDevice = CreateFile(szDeviceName, FILE_ALL_ACCESS, 0, NULL, OPEN_EXISTING, 0, NULL); ++ ++ if (hDevice != INVALID_HANDLE_VALUE) { ++ PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[idxFile]; ++ ++ memset(pHandleInfo, 0, sizeof(*pHandleInfo)); ++ ++ pHandleInfo->OSHandle = hDevice; ++ ++ TAPE_GET_DRIVE_PARAMETERS TapeDriveParameters; ++ DWORD dwSize = sizeof(TapeDriveParameters); ++ ++ dwResult = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &dwSize, &TapeDriveParameters); ++ if (dwResult == NO_ERROR) { ++ pHandleInfo->FeaturesLow = TapeDriveParameters.FeaturesLow; ++ pHandleInfo->FeaturesHigh = TapeDriveParameters.FeaturesHigh; ++ } ++ ++ TAPE_POSITION_INFO TapePositionInfo; ++ ++ dwResult = GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo); ++ ++ if (dwResult == NO_ERROR) { ++ if (TapePositionInfo.AtPartitionStart || TapePositionInfo.AtPartitionEnd || ++ (TapePositionInfo.PartitionBlockValid && TapePositionInfo.BlockNumber == 0)) { ++ pHandleInfo->ulFile = 0; ++ pHandleInfo->bBlockValid = true; ++ pHandleInfo->ullFileStart = 0; ++ } else if (TapePositionInfo.FileSetValid) { ++ pHandleInfo->ulFile = (ULONG)TapePositionInfo.FileNumber; ++ } ++ } ++ } else { ++ DWORD dwError = GetLastError(); ++ ++ switch (dwError) { ++ case ERROR_FILE_NOT_FOUND: ++ case ERROR_PATH_NOT_FOUND: ++ errno = ENOENT; ++ break; ++ ++ case ERROR_TOO_MANY_OPEN_FILES: ++ errno = EMFILE; ++ break; ++ ++ default: ++ case ERROR_ACCESS_DENIED: ++ case ERROR_SHARING_VIOLATION: ++ case ERROR_LOCK_VIOLATION: ++ case ERROR_INVALID_NAME: ++ errno = EACCES; ++ break; ++ ++ case ERROR_FILE_EXISTS: ++ errno = EEXIST; ++ break; ++ ++ case ERROR_INVALID_PARAMETER: ++ errno = EINVAL; ++ break; ++ } ++ ++ return(int) -1; ++ } ++ ++ return (int)idxFile + 3; ++} ++ ++int ++tape_read(int fd, void *buffer, unsigned int count) ++{ ++ if (buffer == NULL) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) || ++ TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) ++ { ++ errno = EBADF; ++ return -1; ++ } ++ ++ PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[fd - 3]; ++ ++ DWORD bytes_read; ++ BOOL bResult; ++ ++ bResult = ReadFile(pHandleInfo->OSHandle, buffer, count, &bytes_read, NULL); ++ ++ if (bResult) { ++ pHandleInfo->bEOF = false; ++ pHandleInfo->bEOT = false; ++ pHandleInfo->bEOD = false; ++ return bytes_read; ++ } else { ++ int iReturnValue = 0; ++ DWORD last_error = GetLastError(); ++ ++ switch (last_error) { ++ ++ case ERROR_FILEMARK_DETECTED: ++ pHandleInfo->bEOF = true; ++ break; ++ ++ case ERROR_END_OF_MEDIA: ++ pHandleInfo->bEOT = true; ++ break; ++ ++ case ERROR_NO_MEDIA_IN_DRIVE: ++ pHandleInfo->bEOF = false; ++ pHandleInfo->bEOT = false; ++ pHandleInfo->bEOD = false; ++ errno = ENOMEDIUM; ++ iReturnValue = -1; ++ break; ++ ++ case ERROR_NO_DATA_DETECTED: ++ pHandleInfo->bEOD = true; ++ break; ++ ++ case ERROR_INVALID_HANDLE: ++ case ERROR_ACCESS_DENIED: ++ case ERROR_LOCK_VIOLATION: ++ errno = EBADF; ++ iReturnValue = -1; ++ break; ++ ++ default: ++ pHandleInfo->bEOF = false; ++ pHandleInfo->bEOT = false; ++ pHandleInfo->bEOD = false; ++ errno = EIO; ++ iReturnValue = -1; ++ } ++ ++ return iReturnValue; ++ } ++} ++ ++int ++tape_write(int fd, const void *buffer, unsigned int count) ++{ ++ if (buffer == NULL) { ++ errno = EINVAL; ++ return -1; ++ } ++ ++ if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) || TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) ++ { ++ errno = EBADF; ++ return -1; ++ } ++ ++ PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[fd - 3]; ++ ++ DWORD bytes_written; ++ BOOL bResult; ++ ++ bResult = WriteFile(pHandleInfo->OSHandle, buffer, count, &bytes_written, NULL); ++ ++ if (bResult) { ++ pHandleInfo->bEOF = false; ++ pHandleInfo->bEOT = false; ++ return bytes_written; ++ } else { ++ DWORD last_error = GetLastError(); ++ ++ switch (last_error) { ++ case ERROR_END_OF_MEDIA: ++ case ERROR_DISK_FULL: ++ pHandleInfo->bEOT = true; ++ errno = ENOSPC; ++ break; ++ ++ case ERROR_NO_MEDIA_IN_DRIVE: ++ pHandleInfo->bEOF = false; ++ pHandleInfo->bEOT = false; ++ pHandleInfo->bEOD = false; ++ errno = ENOMEDIUM; ++ break; ++ ++ case ERROR_INVALID_HANDLE: ++ case ERROR_ACCESS_DENIED: ++ errno = EBADF; ++ break; ++ ++ default: ++ pHandleInfo->bEOF = false; ++ pHandleInfo->bEOT = false; ++ pHandleInfo->bEOD = false; ++ errno = EIO; ++ break; ++ } ++ return -1; ++ } ++} ++ ++int ++tape_close(int fd) ++{ ++ if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) || ++ TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) { ++ errno = EBADF; ++ return -1; ++ } ++ ++ PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[fd - 3]; ++ ++ if (!CloseHandle(pHandleInfo->OSHandle)) { ++ pHandleInfo->OSHandle = INVALID_HANDLE_VALUE; ++ errno = EBADF; ++ return -1; ++ } ++ ++ pHandleInfo->OSHandle = INVALID_HANDLE_VALUE; ++ ++ return 0; ++} ++ ++int ++tape_ioctl(int fd, unsigned long int request, ...) ++{ ++ va_list argp; ++ int result; ++ ++ va_start(argp, request); ++ ++ switch (request) { ++ case MTIOCTOP: ++ result = tape_op(fd, va_arg(argp, struct mtop *)); ++ break; ++ ++ case MTIOCGET: ++ result = tape_get(fd, va_arg(argp, struct mtget *)); ++ break; ++ ++ case MTIOCPOS: ++ result = tape_pos(fd, va_arg(argp, struct mtpos *)); ++ break; ++ ++ default: ++ errno = ENOTTY; ++ result = -1; ++ break; ++ } ++ ++ va_end(argp); ++ ++ return result; ++} ++ ++int tape_op(int fd, struct mtop *mt_com) ++{ ++ DWORD result = NO_ERROR; ++ int index; ++ ++ if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) || ++ TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) ++ { ++ errno = EBADF; ++ return -1; ++ } ++ ++ PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[fd - 3]; ++ ++ switch (mt_com->mt_op) ++ { ++ case MTRESET: ++ case MTNOP: ++ case MTSETDRVBUFFER: ++ break; ++ ++ default: ++ case MTRAS1: ++ case MTRAS2: ++ case MTRAS3: ++ case MTSETDENSITY: ++ errno = ENOTTY; ++ result = (DWORD)-1; ++ break; ++ ++ case MTFSF: ++ for (index = 0; index < mt_com->mt_count; index++) { ++ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE); ++ if (result == NO_ERROR) { ++ pHandleInfo->ulFile++; ++ pHandleInfo->bEOF = true; ++ pHandleInfo->bEOT = false; ++ } ++ } ++ break; ++ ++ case MTBSF: ++ for (index = 0; index < mt_com->mt_count; index++) { ++ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE); ++ if (result == NO_ERROR) { ++ pHandleInfo->ulFile--; ++ pHandleInfo->bBlockValid = false; ++ pHandleInfo->bEOD = false; ++ pHandleInfo->bEOF = false; ++ pHandleInfo->bEOT = false; ++ } ++ } ++ break; ++ ++ case MTFSR: ++ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_RELATIVE_BLOCKS, 0, mt_com->mt_count, 0, FALSE); ++ if (result == NO_ERROR) { ++ pHandleInfo->bEOD = false; ++ pHandleInfo->bEOF = false; ++ pHandleInfo->bEOT = false; ++ } else if (result == ERROR_FILEMARK_DETECTED) { ++ pHandleInfo->bEOF = true; ++ } ++ break; ++ ++ case MTBSR: ++ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_RELATIVE_BLOCKS, 0, -mt_com->mt_count, ~0, FALSE); ++ if (result == NO_ERROR) { ++ pHandleInfo->bEOD = false; ++ pHandleInfo->bEOF = false; ++ pHandleInfo->bEOT = false; ++ } else if (result == ERROR_FILEMARK_DETECTED) { ++ pHandleInfo->ulFile--; ++ pHandleInfo->bBlockValid = false; ++ pHandleInfo->bEOD = false; ++ pHandleInfo->bEOF = false; ++ pHandleInfo->bEOT = false; ++ } ++ break; ++ ++ case MTWEOF: ++ result = WriteTapemark(pHandleInfo->OSHandle, TAPE_FILEMARKS, mt_com->mt_count, FALSE); ++ if (result == NO_ERROR) { ++ pHandleInfo->bEOF = true; ++ pHandleInfo->bEOT = false; ++ pHandleInfo->ulFile += mt_com->mt_count; ++ pHandleInfo->bBlockValid = true; ++ pHandleInfo->ullFileStart = 0; ++ } ++ break; ++ ++ case MTREW: ++ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_REWIND, 0, 0, 0, FALSE); ++ if (result == NO_ERROR) { ++ pHandleInfo->bEOD = false; ++ pHandleInfo->bEOF = false; ++ pHandleInfo->bEOT = false; ++ pHandleInfo->ulFile = 0; ++ pHandleInfo->bBlockValid = true; ++ pHandleInfo->ullFileStart = 0; ++ } ++ break; ++ ++ case MTOFFL: ++ result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOAD, FALSE); ++ if (result == NO_ERROR) { ++ pHandleInfo->bEOD = false; ++ pHandleInfo->bEOF = false; ++ pHandleInfo->bEOT = false; ++ pHandleInfo->ulFile = 0; ++ pHandleInfo->ullFileStart = 0; ++ } ++ break; ++ ++ case MTRETEN: ++ result = PrepareTape(pHandleInfo->OSHandle, TAPE_TENSION, FALSE); ++ if (result == NO_ERROR) { ++ pHandleInfo->bEOD = false; ++ pHandleInfo->bEOF = false; ++ pHandleInfo->bEOT = false; ++ pHandleInfo->ulFile = 0; ++ pHandleInfo->bBlockValid = true; ++ pHandleInfo->ullFileStart = 0; ++ } ++ break; ++ ++ case MTBSFM: ++ for (index = 0; index < mt_com->mt_count; index++) { ++ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE); ++ if (result == NO_ERROR) { ++ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE); ++ pHandleInfo->bEOD = false; ++ pHandleInfo->bEOF = false; ++ pHandleInfo->bEOT = false; ++ } ++ } ++ break; ++ ++ case MTFSFM: ++ for (index = 0; index < mt_com->mt_count; index++) { ++ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, mt_com->mt_count, 0, FALSE); ++ if (result == NO_ERROR) { ++ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE); ++ pHandleInfo->bEOD = false; ++ pHandleInfo->bEOF = false; ++ pHandleInfo->bEOT = false; ++ } ++ } ++ break; ++ ++ case MTEOM: ++ for ( ; ; ) { ++ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE); ++ if (result != NO_ERROR) { ++ pHandleInfo->bEOF = false; ++ ++ if (result == ERROR_END_OF_MEDIA) { ++ pHandleInfo->bEOD = true; ++ pHandleInfo->bEOT = true; ++ return 0; ++ } ++ if (result == ERROR_NO_DATA_DETECTED) { ++ pHandleInfo->bEOD = true; ++ pHandleInfo->bEOT = false; ++ return 0; ++ } ++ break; ++ } else { ++ pHandleInfo->bEOF = true; ++ pHandleInfo->ulFile++; ++ } ++ } ++ break; ++ ++ case MTERASE: ++ result = EraseTape(pHandleInfo->OSHandle, TAPE_ERASE_LONG, FALSE); ++ if (result == NO_ERROR) { ++ pHandleInfo->bEOD = true; ++ pHandleInfo->bEOF = false; ++ pHandleInfo->bEOT = false; ++ pHandleInfo->ulFile = 0; ++ pHandleInfo->bBlockValid = true; ++ pHandleInfo->ullFileStart = 0; ++ } ++ break; ++ ++ case MTSETBLK: ++ { ++ TAPE_SET_MEDIA_PARAMETERS SetMediaParameters; ++ ++ SetMediaParameters.BlockSize = mt_com->mt_count; ++ result = SetTapeParameters(pHandleInfo->OSHandle, SET_TAPE_MEDIA_INFORMATION, &SetMediaParameters); ++ } ++ break; ++ ++ case MTSEEK: ++ { ++ TAPE_POSITION_INFO TapePositionInfo; ++ ++ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, 0, mt_com->mt_count, 0, FALSE); ++ ++ memset(&TapePositionInfo, 0, sizeof(TapePositionInfo)); ++ DWORD dwPosResult = GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo); ++ if (dwPosResult == NO_ERROR && TapePositionInfo.FileSetValid) { ++ pHandleInfo->ulFile = (ULONG)TapePositionInfo.FileNumber; ++ } else { ++ pHandleInfo->ulFile = ~0U; ++ } ++ } ++ break; ++ ++ case MTTELL: ++ { ++ DWORD partition; ++ DWORD offset; ++ DWORD offsetHi; ++ ++ result = GetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, &partition, &offset, &offsetHi); ++ if (result == NO_ERROR) { ++ return offset; ++ } ++ } ++ break; ++ ++ case MTFSS: ++ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_SETMARKS, 0, mt_com->mt_count, 0, FALSE); ++ break; ++ ++ case MTBSS: ++ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_SETMARKS, 0, -mt_com->mt_count, ~0, FALSE); ++ break; ++ ++ case MTWSM: ++ result = WriteTapemark(pHandleInfo->OSHandle, TAPE_SETMARKS, mt_com->mt_count, FALSE); ++ break; ++ ++ case MTLOCK: ++ result = PrepareTape(pHandleInfo->OSHandle, TAPE_LOCK, FALSE); ++ break; ++ ++ case MTUNLOCK: ++ result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOCK, FALSE); ++ break; ++ ++ case MTLOAD: ++ result = PrepareTape(pHandleInfo->OSHandle, TAPE_LOAD, FALSE); ++ break; ++ ++ case MTUNLOAD: ++ result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOAD, FALSE); ++ break; ++ ++ case MTCOMPRESSION: ++ { ++ TAPE_GET_DRIVE_PARAMETERS GetDriveParameters; ++ TAPE_SET_DRIVE_PARAMETERS SetDriveParameters; ++ DWORD size; ++ ++ size = sizeof(GetDriveParameters); ++ ++ result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &size, &GetDriveParameters); ++ ++ if (result == NO_ERROR) ++ { ++ SetDriveParameters.ECC = GetDriveParameters.ECC; ++ SetDriveParameters.Compression = (BOOLEAN)mt_com->mt_count; ++ SetDriveParameters.DataPadding = GetDriveParameters.DataPadding; ++ SetDriveParameters.ReportSetmarks = GetDriveParameters.ReportSetmarks; ++ SetDriveParameters.EOTWarningZoneSize = GetDriveParameters.EOTWarningZoneSize; ++ ++ result = SetTapeParameters(pHandleInfo->OSHandle, SET_TAPE_DRIVE_INFORMATION, &SetDriveParameters); ++ } ++ } ++ break; ++ ++ case MTSETPART: ++ result = SetTapePosition(pHandleInfo->OSHandle, TAPE_LOGICAL_BLOCK, mt_com->mt_count, 0, 0, FALSE); ++ break; ++ ++ case MTMKPART: ++ if (mt_com->mt_count == 0) ++ { ++ result = CreateTapePartition(pHandleInfo->OSHandle, TAPE_INITIATOR_PARTITIONS, 1, 0); ++ } ++ else ++ { ++ result = CreateTapePartition(pHandleInfo->OSHandle, TAPE_INITIATOR_PARTITIONS, 2, mt_com->mt_count); ++ } ++ break; ++ } ++ ++ if ((result == NO_ERROR && pHandleInfo->bEOF) || ++ (result == ERROR_FILEMARK_DETECTED && mt_com->mt_op == MTFSR)) { ++ ++ TAPE_POSITION_INFO TapePositionInfo; ++ ++ if (GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo) == NO_ERROR) { ++ pHandleInfo->bBlockValid = true; ++ pHandleInfo->ullFileStart = TapePositionInfo.BlockNumber; ++ } ++ } ++ ++ switch (result) { ++ case NO_ERROR: ++ case (DWORD)-1: /* Error has already been translated into errno */ ++ break; ++ ++ default: ++ case ERROR_FILEMARK_DETECTED: ++ errno = EIO; ++ break; ++ ++ case ERROR_END_OF_MEDIA: ++ pHandleInfo->bEOT = true; ++ errno = EIO; ++ break; ++ ++ case ERROR_NO_DATA_DETECTED: ++ pHandleInfo->bEOD = true; ++ errno = EIO; ++ break; ++ ++ case ERROR_NO_MEDIA_IN_DRIVE: ++ pHandleInfo->bEOF = false; ++ pHandleInfo->bEOT = false; ++ pHandleInfo->bEOD = false; ++ errno = ENOMEDIUM; ++ break; ++ ++ case ERROR_INVALID_HANDLE: ++ case ERROR_ACCESS_DENIED: ++ case ERROR_LOCK_VIOLATION: ++ errno = EBADF; ++ break; ++ } ++ ++ return result == NO_ERROR ? 0 : -1; ++} ++ ++int tape_get(int fd, struct mtget *mt_get) ++{ ++ TAPE_POSITION_INFO pos_info; ++ BOOL result; ++ ++ if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) || ++ TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) { ++ errno = EBADF; ++ return -1; ++ } ++ ++ PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[fd - 3]; ++ ++ if (GetTapePositionInfo(pHandleInfo->OSHandle, &pos_info) != NO_ERROR) { ++ return -1; ++ } ++ ++ DWORD density = 0; ++ DWORD blocksize = 0; ++ ++ result = GetDensityBlockSize(pHandleInfo->OSHandle, &density, &blocksize); ++ ++ if (result != NO_ERROR) { ++ TAPE_GET_DRIVE_PARAMETERS drive_params; ++ DWORD size; ++ ++ size = sizeof(drive_params); ++ ++ result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &size, &drive_params); ++ ++ if (result == NO_ERROR) { ++ blocksize = drive_params.DefaultBlockSize; ++ } ++ } ++ ++ mt_get->mt_type = MT_ISSCSI2; ++ ++ // Partition # ++ mt_get->mt_resid = pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1; ++ ++ // Density / Block Size ++ mt_get->mt_dsreg = ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) | ++ ((blocksize << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK); ++ ++ mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/ ++ ++ if (pHandleInfo->bEOF) { ++ mt_get->mt_gstat |= 0x80000000; // GMT_EOF ++ } ++ ++ if (pos_info.PartitionBlockValid && pos_info.BlockNumber == 0) { ++ mt_get->mt_gstat |= 0x40000000; // GMT_BOT ++ } ++ ++ if (pHandleInfo->bEOT) { ++ mt_get->mt_gstat |= 0x20000000; // GMT_EOT ++ } ++ ++ if (pHandleInfo->bEOD) { ++ mt_get->mt_gstat |= 0x08000000; // GMT_EOD ++ } ++ ++ TAPE_GET_MEDIA_PARAMETERS media_params; ++ DWORD size = sizeof(media_params); ++ ++ result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_MEDIA_INFORMATION, &size, &media_params); ++ ++ if (result == NO_ERROR && media_params.WriteProtected) { ++ mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT ++ } ++ ++ result = GetTapeStatus(pHandleInfo->OSHandle); ++ ++ if (result != NO_ERROR) { ++ if (result == ERROR_NO_MEDIA_IN_DRIVE) { ++ mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN ++ } ++ } else { ++ mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE ++ } ++ ++ // Recovered Error Count ++ mt_get->mt_erreg = 0; ++ ++ // File Number ++ mt_get->mt_fileno = (__kernel_daddr_t)pHandleInfo->ulFile; ++ ++ // Block Number ++ mt_get->mt_blkno = (__kernel_daddr_t)(pHandleInfo->bBlockValid ? pos_info.BlockNumber - pHandleInfo->ullFileStart : (ULONGLONG)-1); ++ ++ return 0; ++} ++ ++#define SERVICEACTION_SHORT_FORM_BLOCKID 0 ++#define SERVICEACTION_SHORT_FORM_VENDOR_SPECIFIC 1 ++#define SERVICEACTION_LONG_FORM 6 ++#define SERVICEACTION_EXTENDED_FORM 8 ++ ++ ++typedef struct _SCSI_READ_POSITION_SHORT_BUFFER ++{ ++ UCHAR :1; ++ UCHAR PERR:1; ++ UCHAR BPU:1; ++ UCHAR :1; ++ UCHAR BYCU:1; ++ UCHAR BCU:1; ++ UCHAR EOP:1; ++ UCHAR BOP:1; ++ UCHAR Partition; ++ UCHAR Reserved1[2]; ++ UCHAR FirstBlock[4]; ++ UCHAR LastBlock[4]; ++ UCHAR Reserved2; ++ UCHAR NumberBufferBlocks[3]; ++ UCHAR NumberBufferBytes[4]; ++} SCSI_READ_POSITION_SHORT_BUFFER, *PSCSI_READ_POSITION_SHORT_BUFFER; ++ ++typedef struct _SCSI_READ_POSITION_LONG_BUFFER ++{ ++ UCHAR :2; ++ UCHAR BPU:1; ++ UCHAR MPU:1; ++ UCHAR :2; ++ UCHAR EOP:1; ++ UCHAR BOP:1; ++ UCHAR Reserved3[3]; ++ UCHAR Partition[4]; ++ UCHAR BlockNumber[8]; ++ UCHAR FileNumber[8]; ++ UCHAR SetNumber[8]; ++} SCSI_READ_POSITION_LONG_BUFFER, *PSCSI_READ_POSITION_LONG_BUFFER; ++ ++typedef struct _SCSI_READ_POSITION_EXTENDED_BUFFER ++{ ++ UCHAR :1; ++ UCHAR PERR:1; ++ UCHAR LOPU:1; ++ UCHAR :1; ++ UCHAR BYCU:1; ++ UCHAR LOCU:1; ++ UCHAR EOP:1; ++ UCHAR BOP:1; ++ UCHAR Partition; ++ UCHAR AdditionalLength[2]; ++ UCHAR Reserved1; ++ UCHAR NumberBufferObjects[3]; ++ UCHAR FirstLogicalObject[8]; ++ UCHAR LastLogicalObject[8]; ++ UCHAR NumberBufferObjectBytes[8]; ++} SCSI_READ_POSITION_EXTENDED_BUFFER, *PSCSI_READ_POSITION_EXTENDED_BUFFER; ++ ++typedef union _READ_POSITION_RESULT { ++ SCSI_READ_POSITION_SHORT_BUFFER ShortBuffer; ++ SCSI_READ_POSITION_LONG_BUFFER LongBuffer; ++ SCSI_READ_POSITION_EXTENDED_BUFFER ExtendedBuffer; ++} READ_POSITION_RESULT, *PREAD_POSITION_RESULT; ++ ++DWORD GetTapePositionInfo(HANDLE hDevice, PTAPE_POSITION_INFO TapePositionInfo) ++{ ++ PSCSI_PASS_THROUGH ScsiPassThrough; ++ BOOL bResult; ++ DWORD dwBytesReturned; ++ int pass; ++ ++ const DWORD dwBufferSize = sizeof(SCSI_PASS_THROUGH) + sizeof(READ_POSITION_RESULT) + 28; ++ ++ memset(TapePositionInfo, 0, sizeof(*TapePositionInfo)); ++ ++ ScsiPassThrough = (PSCSI_PASS_THROUGH)malloc(dwBufferSize); ++ ++ for (pass = 0; pass < 2; pass++) ++ { ++ memset(ScsiPassThrough, 0, dwBufferSize); ++ ++ ScsiPassThrough->Length = sizeof(SCSI_PASS_THROUGH); ++ ++ ScsiPassThrough->CdbLength = 10; ++ ScsiPassThrough->SenseInfoLength = 28; ++ ScsiPassThrough->DataIn = 1; ++ ScsiPassThrough->DataTransferLength = sizeof(SCSI_READ_POSITION_LONG_BUFFER); ++ ScsiPassThrough->TimeOutValue = 1000; ++ ScsiPassThrough->DataBufferOffset = sizeof(SCSI_PASS_THROUGH) + 28; ++ ScsiPassThrough->SenseInfoOffset = sizeof(SCSI_PASS_THROUGH); ++ ++ ScsiPassThrough->Cdb[0] = 0x34; // READ POSITION ++ ++ switch (pass) ++ { ++ case 0: ++ ScsiPassThrough->Cdb[1] = SERVICEACTION_LONG_FORM; ++ break; ++ ++ case 1: ++ ScsiPassThrough->Cdb[1] = SERVICEACTION_SHORT_FORM_BLOCKID; ++ break; ++ } ++ ++ bResult = DeviceIoControl( hDevice, ++ IOCTL_SCSI_PASS_THROUGH, ++ ScsiPassThrough, sizeof(SCSI_PASS_THROUGH), ++ ScsiPassThrough, dwBufferSize, ++ &dwBytesReturned, ++ NULL); ++ ++ if (bResult && dwBytesReturned >= (offsetof(SCSI_PASS_THROUGH, ScsiStatus) + sizeof(ScsiPassThrough->ScsiStatus))) { ++ if (ScsiPassThrough->ScsiStatus == SCSISTAT_GOOD) { ++ PREAD_POSITION_RESULT pPosResult = (PREAD_POSITION_RESULT)((PUCHAR)ScsiPassThrough + ScsiPassThrough->DataBufferOffset); ++ ++ switch (pass) ++ { ++ case 0: // SERVICEACTION_LONG_FORM ++ { ++ TapePositionInfo->AtPartitionStart = pPosResult->LongBuffer.BOP; ++ TapePositionInfo->AtPartitionEnd = pPosResult->LongBuffer.EOP; ++ ++ if (!TapePositionInfo->PartitionBlockValid) { ++ TapePositionInfo->PartitionBlockValid = !pPosResult->LongBuffer.BPU; ++ ++ if (TapePositionInfo->PartitionBlockValid) { ++ TapePositionInfo->Partition = Read32BitUnsigned(pPosResult->LongBuffer.Partition); ++ TapePositionInfo->BlockNumber = Read64BitUnsigned(pPosResult->LongBuffer.BlockNumber); ++ } ++ } ++ ++ TapePositionInfo->FileSetValid = !pPosResult->LongBuffer.MPU; ++ if (TapePositionInfo->FileSetValid) { ++ TapePositionInfo->FileNumber = Read64BitUnsigned(pPosResult->LongBuffer.FileNumber); ++ TapePositionInfo->SetNumber = Read64BitUnsigned(pPosResult->LongBuffer.SetNumber); ++ } ++ } ++ break; ++ ++ case 1: // SERVICEACTION_SHORT_FORM_BLOCKID ++ { ++ // pPosResult->ShortBuffer.PERR; ++ // pPosResult->ShortBuffer.BYCU; ++ // pPosResult->ShortBuffer.BCU; ++ TapePositionInfo->AtPartitionStart = pPosResult->ShortBuffer.BOP; ++ TapePositionInfo->AtPartitionEnd = pPosResult->ShortBuffer.EOP; ++ ++ if (!TapePositionInfo->PartitionBlockValid) { ++ TapePositionInfo->PartitionBlockValid = !pPosResult->ShortBuffer.BPU; ++ ++ if (TapePositionInfo->PartitionBlockValid) { ++ TapePositionInfo->Partition = pPosResult->ShortBuffer.Partition; ++ TapePositionInfo->BlockNumber = Read32BitUnsigned(pPosResult->ShortBuffer.FirstBlock); ++ } ++ } ++ // Read32BitsUnsigned(pPosResult->ShortBuffer.LastBlock); ++ // Read24BitsUnsigned(pPosResult->ShortBuffer.NumberBufferBlocks); ++ // Read32BitsUnsigned(pPosResult->ShortBuffer.NumberBufferBytes); ++ } ++ break; ++ } ++ } ++ } ++ } ++ free(ScsiPassThrough); ++ ++ return NO_ERROR; ++} ++ ++DWORD GetDensityBlockSize(HANDLE hDevice, DWORD *pdwDensity, DWORD *pdwBlockSize) ++{ ++ DWORD dwBufferSize = sizeof(GET_MEDIA_TYPES) + 5 * sizeof(DEVICE_MEDIA_INFO); ++ GET_MEDIA_TYPES * pGetMediaTypes = (GET_MEDIA_TYPES *)malloc(dwBufferSize); ++ BOOL bResult; ++ DWORD dwResult; ++ DWORD idxMedia; ++ ++ if (pGetMediaTypes == NULL) { ++ return ERROR_OUTOFMEMORY; ++ } ++ ++ do { ++ DWORD dwBytesReturned; ++ ++ bResult = DeviceIoControl( hDevice, ++ IOCTL_STORAGE_GET_MEDIA_TYPES_EX, ++ NULL, 0, ++ (LPVOID)pGetMediaTypes, dwBufferSize, ++ &dwBytesReturned, ++ NULL); ++ ++ if (!bResult) { ++ dwResult = GetLastError(); ++ ++ if (dwResult != ERROR_INSUFFICIENT_BUFFER) { ++ free(pGetMediaTypes); ++ return dwResult; ++ } ++ ++ dwBufferSize += 6 * sizeof(DEVICE_MEDIA_INFO); ++ ++ GET_MEDIA_TYPES * pNewBuffer = (GET_MEDIA_TYPES *)realloc(pGetMediaTypes, dwBufferSize); ++ ++ if (pNewBuffer != pGetMediaTypes) { ++ free(pGetMediaTypes); ++ ++ if (pNewBuffer == NULL) { ++ return ERROR_OUTOFMEMORY; ++ } ++ ++ pGetMediaTypes = pNewBuffer; ++ } ++ } ++ } while (!bResult); ++ ++ if (pGetMediaTypes->DeviceType != FILE_DEVICE_TAPE) { ++ free(pGetMediaTypes); ++ return ERROR_BAD_DEVICE; ++ } ++ ++ for (idxMedia = 0; idxMedia < pGetMediaTypes->MediaInfoCount; idxMedia++) { ++ ++ if (pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.MediaCharacteristics & MEDIA_CURRENTLY_MOUNTED) { ++ ++ if (pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.BusType == BusTypeScsi) { ++ *pdwDensity = pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.BusSpecificData.ScsiInformation.DensityCode; ++ } else { ++ *pdwDensity = 0; ++ } ++ ++ *pdwBlockSize = pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.CurrentBlockSize; ++ ++ free(pGetMediaTypes); ++ ++ return NO_ERROR; ++ } ++ } ++ ++ free(pGetMediaTypes); ++ ++ return ERROR_NO_MEDIA_IN_DRIVE; ++} ++ ++int tape_pos(int fd, struct mtpos *mt_pos) ++{ ++ DWORD partition; ++ DWORD offset; ++ DWORD offsetHi; ++ BOOL result; ++ ++ if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) || ++ TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) { ++ errno = EBADF; ++ return -1; ++ } ++ ++ PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[fd - 3]; ++ ++ result = GetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, &partition, &offset, &offsetHi); ++ if (result == NO_ERROR) { ++ mt_pos->mt_blkno = offset; ++ return 0; ++ } ++ ++ return -1; ++} diff --git a/bacula/src/win32/patches/mtx.patch b/bacula/src/win32/patches/mtx.patch new file mode 100644 index 0000000000..35e39f69e4 --- /dev/null +++ b/bacula/src/win32/patches/mtx.patch @@ -0,0 +1,1576 @@ +Index: README.win32 +=================================================================== +--- /dev/null Sat Jul 29 14:54:52 2006 ++++ README.win32 Sat Jul 29 14:46:45 2006 +@@ -0,0 +1,22 @@ ++CHANGES FROM UNIX ++================= ++ ++The only difference is in the naming of devices. On Linux the changer is ++accessed using /dev/sg, on Windows you use Changer. ++ ++On Linux the tape drive is referenced using /dev/nst, on Windows you use ++Tape. ++ ++There is one exception in the case where there isn't a driver loaded for the ++device. This is usually only the case on Windows 2000 or if the Windows XP or ++Windows Server 2003 system supplied driver has been disabled. ++ ++In the case where there is no driver loaded you can access the device directly ++through the SCSI driver using the following notation: ++ ++ ::: ++ ++ Port is the adapter number ++ Bus is the SCSI bus number relative to the adapter ++ Target is the SCSI device's target ID ++ LUN is the SCSI device's logical unit number +Index: scsi_win32.c +=================================================================== +--- /dev/null Sat Jul 29 14:55:00 2006 ++++ scsi_win32.c Sat Jul 29 14:54:08 2006 +@@ -0,0 +1,353 @@ ++/* Copyright 2006 Robert Nelson ++ ++$Date$ ++$Revision$ ++ ++ This program is free software; you may redistribute and/or modify it under ++ the terms of the GNU General Public License Version 2 as published by the ++ Free Software Foundation. ++ ++ This program is distributed in the hope that it will be useful, but ++ WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY ++ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ++ for complete details. ++ ++*/ ++ ++/* These are the SCSI commands for Microsoft Windows. This is derived from ++ * the file scsi_linux.c substituting Windows specific emulation of the Linux ++ * behaviour. ++ */ ++ ++#include ++#include ++ ++#ifdef _MSC_VER ++#include ++#else ++#include ++#endif ++ ++#ifndef HZ ++#define HZ 1000 ++#endif ++ ++/* These are copied out of BRU 16.1, with all the boolean masks changed ++ * to our bitmasks. ++*/ ++#define S_NO_SENSE(s) ((s)->SenseKey == 0x0) ++#define S_RECOVERED_ERROR(s) ((s)->SenseKey == 0x1) ++ ++#define S_NOT_READY(s) ((s)->SenseKey == 0x2) ++#define S_MEDIUM_ERROR(s) ((s)->SenseKey == 0x3) ++#define S_HARDWARE_ERROR(s) ((s)->SenseKey == 0x4) ++#define S_UNIT_ATTENTION(s) ((s)->SenseKey == 0x6) ++#define S_BLANK_CHECK(s) ((s)->SenseKey == 0x8) ++#define S_VOLUME_OVERFLOW(s) ((s)->SenseKey == 0xd) ++ ++#define DEFAULT_TIMEOUT 3 * 60 /* 3 minutes here */ ++ ++/* Sigh, the T-10 SSC spec says all of the following is needed to ++ * detect a short read while in variable block mode, and that even ++ * though we got a BLANK_CHECK or MEDIUM_ERROR, it's still a valid read. ++ */ ++ ++#define HIT_FILEMARK(s) (S_NO_SENSE((s)) && (s)->Filemark && (s)->Valid) ++#define SHORT_READ(s) (S_NO_SENSE((s)) && (s)->ILI && (s)->Valid && (s)->AdditionalSenseCode==0 && (s)->AdditionalSenseCodeQualifier==0) ++#define HIT_EOD(s) (S_BLANK_CHECK((s)) && (s)->Valid) ++#define HIT_EOP(s) (S_MEDIUM_ERROR((s)) && (s)->EOM && (s)->Valid) ++#define HIT_EOM(s) ((s)->EOM && (s)->Valid) ++ ++#define STILL_A_VALID_READ(s) (HIT_FILEMARK(s) || SHORT_READ(s) || HIT_EOD(s) || HIT_EOP(s) || HIT_EOM(s)) ++ ++#define SCSI_DEFAULT_TIMEOUT 60 /* 1 minute */ ++#define SCSI_MAX_TIMEOUT 108 /* 1 minute 48 seconds */ ++ ++typedef struct _HANDLE_ENTRY { ++ HANDLE hDevice; ++ UCHAR PortId; ++ UCHAR PathId; ++ UCHAR TargetId; ++ UCHAR Lun; ++} HANDLE_ENTRY, *PHANDLE_ENTRY; ++ ++PHANDLE_ENTRY HandleTable = NULL; ++int nEntries = 0; ++ ++DEVICE_TYPE SCSI_OpenDevice(char *DeviceName) ++{ ++ int DeviceIndex; ++ TCHAR szDevicePath[256]; ++ ++ int nColons = 0; ++ int index; ++ ++ int port, path, target, lun; ++ ++ for (DeviceIndex = 0; DeviceIndex < nEntries; DeviceIndex++) ++ { ++ if (HandleTable[DeviceIndex].hDevice == INVALID_HANDLE_VALUE) ++ break; ++ } ++ ++ if (DeviceIndex >= nEntries) ++ { ++ PHANDLE_ENTRY pNewTable; ++ ++ nEntries += 4; ++ ++ if (HandleTable == NULL) ++ { ++ pNewTable = (PHANDLE_ENTRY)malloc(nEntries * sizeof(HANDLE_ENTRY)); ++ } ++ else ++ { ++ pNewTable = (PHANDLE_ENTRY)realloc(HandleTable, nEntries * sizeof(HANDLE_ENTRY)); ++ } ++ ++ if (pNewTable == NULL) ++ { ++ FatalError("cannot open SCSI device '%s' - %m\n", DeviceName); ++ } ++ ++ HandleTable = pNewTable; ++ } ++ ++ for (index = 0; DeviceName[index] != '\0'; index++) ++ { ++ if (DeviceName[index] == ':') ++ nColons++; ++ else if (DeviceName[index] < '0' || DeviceName[index] > '9') ++ break; ++ } ++ ++ if (DeviceName[index] == '\0' && nColons == 3 && ++ sscanf(DeviceName, "%d:%d:%d:%d", &port, &path, &target, &lun) == 4) { ++ ++ HandleTable[DeviceIndex].PortId = (UCHAR)port; ++ HandleTable[DeviceIndex].PathId = (UCHAR)path; ++ HandleTable[DeviceIndex].TargetId = (UCHAR)target; ++ HandleTable[DeviceIndex].Lun = (UCHAR)lun; ++ ++ sprintf(szDevicePath, "\\\\.\\scsi%d:", port); ++ } ++ else ++ { ++ int nPrefixLength = 0; ++ ++ if (DeviceName[0] != '\\') { ++ memcpy(szDevicePath, "\\\\.\\", 4 * sizeof(TCHAR)); ++ nPrefixLength = 4; ++ } ++ ++ HandleTable[DeviceIndex].PortId = 0; ++ HandleTable[DeviceIndex].PathId = 0; ++ HandleTable[DeviceIndex].TargetId = 0; ++ HandleTable[DeviceIndex].Lun = 0; ++ ++ strncpy( &szDevicePath[nPrefixLength], ++ DeviceName, ++ sizeof(szDevicePath) / sizeof(TCHAR) - nPrefixLength - 1); ++ ++ szDevicePath[sizeof(szDevicePath) / sizeof(TCHAR) - 1] = '\0'; ++ } ++ ++ HandleTable[DeviceIndex].hDevice = CreateFile(szDevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); ++ ++ if (HandleTable[DeviceIndex].hDevice == INVALID_HANDLE_VALUE) ++ { ++ DWORD dwError = GetLastError(); ++ ++#if DEBUG ++ LPSTR lpszMessage; ++ ++ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, (LPSTR)&lpszMessage, 0, NULL); ++ fputs(lpszMessage, stderr); ++#endif ++ ++ switch (dwError) { ++ case ERROR_FILE_NOT_FOUND: ++ case ERROR_PATH_NOT_FOUND: ++ errno = ENOENT; ++ break; ++ ++ case ERROR_TOO_MANY_OPEN_FILES: ++ errno = EMFILE; ++ break; ++ ++ default: ++ case ERROR_ACCESS_DENIED: ++ case ERROR_SHARING_VIOLATION: ++ case ERROR_LOCK_VIOLATION: ++ case ERROR_INVALID_NAME: ++ errno = EACCES; ++ break; ++ ++ case ERROR_FILE_EXISTS: ++ errno = EEXIST; ++ break; ++ ++ case ERROR_INVALID_PARAMETER: ++ errno = EINVAL; ++ break; ++ } ++ ++ FatalError("cannot open SCSI device '%s' - %m\n", DeviceName); ++ } ++ ++ return DeviceIndex; ++} ++ ++static int scsi_timeout = SCSI_DEFAULT_TIMEOUT; ++ ++void SCSI_Set_Timeout(int secs) ++{ ++ if (secs > SCSI_MAX_TIMEOUT) { ++ secs = SCSI_MAX_TIMEOUT; ++ } ++ scsi_timeout = secs * HZ; ++} ++ ++void SCSI_Default_Timeout(void) ++{ ++ scsi_timeout = SCSI_DEFAULT_TIMEOUT * HZ; ++} ++ ++void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD) ++{ ++ if (DeviceFD < nEntries) ++ { ++ CloseHandle(HandleTable[DeviceFD].hDevice); ++ HandleTable[DeviceFD].hDevice = INVALID_HANDLE_VALUE; ++ } ++ else ++ { ++ errno = EBADF; ++ FatalError("cannot close SCSI device '%s' - %m\n", DeviceName); ++ } ++} ++ ++ ++/* Added by Eric Green to deal with burping ++ * Seagate autoloader (hopefully!). ++ */ ++/* Get the SCSI ID and LUN... */ ++scsi_id_t *SCSI_GetIDLun(DEVICE_TYPE fd) { ++ scsi_id_t * retval; ++ ++ SCSI_ADDRESS ScsiAddress; ++ BOOL bResult; ++ DWORD dwBytesReturned; ++ ++ if (fd < nEntries) { ++ retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t)); ++ retval->id = HandleTable[fd].TargetId; ++ retval->lun = HandleTable[fd].Lun; ++ ++#ifdef DEBUG ++ fprintf(stderr,"SCSI:ID=%d LUN=%d\n", retval->id, retval->lun); ++#endif ++ return retval; ++ } else { ++ errno = EBADF; ++ FatalError("cannot close SCSI device - %m\n"); ++ } ++ ++ memset(&ScsiAddress, 0, sizeof(ScsiAddress)); ++ ++ ScsiAddress.Length = sizeof(ScsiAddress); ++ ++ bResult = DeviceIoControl(HandleTable[fd].hDevice, ++ IOCTL_SCSI_GET_ADDRESS, ++ &ScsiAddress, sizeof(ScsiAddress), ++ &ScsiAddress, sizeof(ScsiAddress), ++ &dwBytesReturned, ++ NULL); ++ ++ if (!bResult) { ++ return NULL; ++ } ++ ++ retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t)); ++ retval->id = ScsiAddress.TargetId; ++ retval->lun = ScsiAddress.Lun; ++ ++#ifdef DEBUG ++ fprintf(stderr,"SCSI:ID=%d LUN=%d\n",retval->id,retval->lun); ++#endif ++ return retval; ++} ++ ++int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD, ++ Direction_T Direction, ++ CDB_T *CDB, ++ int CDB_Length, ++ void *DataBuffer, ++ int DataBufferLength, ++ RequestSense_T *RequestSense) ++{ ++ PSCSI_PASS_THROUGH_DIRECT ScsiPassThrough; ++ ++ const DWORD dwBufferSize = sizeof(SCSI_PASS_THROUGH_DIRECT) + sizeof(RequestSense_T); ++ BOOL bResult; ++ DWORD dwBytesReturned; ++ ++ if (DeviceFD >= nEntries || HandleTable[DeviceFD].hDevice == INVALID_HANDLE_VALUE) ++ { ++ errno = EBADF; ++ return -1; ++ } ++ ++ ScsiPassThrough = (PSCSI_PASS_THROUGH_DIRECT)malloc(dwBufferSize); ++ ++ memset(ScsiPassThrough, 0, dwBufferSize); ++ ++ ScsiPassThrough->Length = sizeof(SCSI_PASS_THROUGH_DIRECT); ++ ++ ScsiPassThrough->PathId = HandleTable[DeviceFD].PathId; ++ ScsiPassThrough->TargetId = HandleTable[DeviceFD].TargetId; ++ ScsiPassThrough->Lun = HandleTable[DeviceFD].Lun; ++ ScsiPassThrough->CdbLength = (UCHAR)CDB_Length; ++ ScsiPassThrough->SenseInfoLength = sizeof(RequestSense_T); ++ ScsiPassThrough->DataIn = Direction == Input; ++ ScsiPassThrough->DataTransferLength = DataBufferLength; ++ ScsiPassThrough->TimeOutValue = scsi_timeout; ++ ScsiPassThrough->DataBuffer = DataBuffer; ++ ScsiPassThrough->SenseInfoOffset = sizeof(SCSI_PASS_THROUGH_DIRECT); ++ ++ memcpy(ScsiPassThrough->Cdb, CDB, CDB_Length); ++ dwBytesReturned = 0; ++ ++ bResult = DeviceIoControl(HandleTable[DeviceFD].hDevice, ++ IOCTL_SCSI_PASS_THROUGH_DIRECT, ++ ScsiPassThrough, sizeof(SCSI_PASS_THROUGH_DIRECT), ++ ScsiPassThrough, dwBufferSize, ++ &dwBytesReturned, ++ NULL); ++ if (bResult) { ++ if (ScsiPassThrough->ScsiStatus != 0) { ++ memcpy(RequestSense, &ScsiPassThrough[1], sizeof(RequestSense_T)); ++#if DEBUG ++ fprintf(stderr, "Command failed - ScsiStatus = %d\n", ScsiPassThrough->ScsiStatus); ++ PrintRequestSense(RequestSense); ++#endif ++ bResult = false; ++ } ++ } ++ else ++ { ++#if DEBUG ++ DWORD dwError = GetLastError(); ++ LPSTR lpszMessage; ++ ++ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, (LPSTR)&lpszMessage, 0, NULL); ++ fputs(lpszMessage, stderr); ++#endif ++ ++ memset(RequestSense, 0, sizeof(RequestSense_T)); ++ } ++ ++ free(ScsiPassThrough); ++ ++ return bResult ? 0 : -1; ++} +Index: tapeinfo.c +=================================================================== +--- tapeinfo.c (revision 139) ++++ tapeinfo.c (revision 147) +@@ -211,25 +211,18 @@ + unsigned int partition1_size; + } TapeCapacity; + ++#if defined(DEBUG) + /* DEBUG */ + static void dump_data(unsigned char *data, int len) { +- int i; + if (!len) { + fprintf(stderr,"**NO DATA**\n"); + return; + } + +- for (i=0;i argument '%d' to 'unload' command\n", + arg2); + } +- if (ElementStatus->DataTransferElementFull[arg2] < 0 ) { ++ if (!ElementStatus->DataTransferElementFull[arg2]) { + FatalError("Data Transfer Element %d is Empty\n", arg2); + } + /* Now see if something already lives where we wanna go... */ +@@ -715,7 +715,7 @@ + } + ElementStatus = ReadElementStatus(MediumChangerFD,&RequestSense,inquiry_info,&SCSI_Flags); + if (!ElementStatus) { +- PrintRequestSense(&RequestSense); ++ PrintRequestSense(&RequestSense); + FatalError("READ ELEMENT STATUS Command Failed\n"); + } + } +@@ -813,9 +813,6 @@ + + argv0=argv[0]; + +- +- +- + parse_args(); /* also executes them as it sees them, sigh. */ + + #ifndef VMS +Index: scsitape.c +=================================================================== +--- scsitape.c (revision 139) ++++ scsitape.c (revision 147) +@@ -41,11 +41,26 @@ + #include "mtx.h" + #include "mtxl.h" + ++#if HAVE_UNISTD_H + #include ++#endif ++ ++#if HAVE_SYS_TYPES_H + #include ++#endif ++ ++#if HAVE_SYS_IOCTL_H + #include ++#endif ++ ++#if HAVE_SYS_MTIO_H + #include /* will try issuing some ioctls for Solaris, sigh. */ ++#endif + ++#ifdef _MSC_VER ++#include ++#endif ++ + void Usage(void) { + FatalError("Usage: scsitape -f where is:\n setblk | fsf | bsf | eod | rewind | eject | mark |\n seek | read [ [] \n"); + } +@@ -54,7 +69,7 @@ + static int arg[4]; /* the argument for the command, sigh. */ + + /* the device handle we're operating upon, sigh. */ +-static unsigned char *device; /* the text of the device thingy. */ ++static char *device; /* the text of the device thingy. */ + static DEVICE_TYPE MediumChangerFD = (DEVICE_TYPE) 0; + + +@@ -96,43 +111,7 @@ + + char *argv0; + +-/* A table for printing out the peripheral device type as ASCII. */ +-static char *PeripheralDeviceType[32] = { +- "Disk Drive", +- "Tape Drive", +- "Printer", +- "Processor", +- "Write-once", +- "CD-ROM", +- "Scanner", +- "Optical", +- "Medium Changer", +- "Communications", +- "ASC IT8", +- "ASC IT8", +- "RAID Array", +- "Enclosure Services", +- "OCR/W", +- "Bridging Expander", /* 0x10 */ +- "Reserved", /* 0x11 */ +- "Reserved", /* 0x12 */ +- "Reserved", /* 0x13 */ +- "Reserved", /* 0x14 */ +- "Reserved", /* 0x15 */ +- "Reserved", /* 0x16 */ +- "Reserved", /* 0x17 */ +- "Reserved", /* 0x18 */ +- "Reserved", /* 0x19 */ +- "Reserved", /* 0x1a */ +- "Reserved", /* 0x1b */ +- "Reserved", /* 0x1c */ +- "Reserved", /* 0x1d */ +- "Reserved", /* 0x1e */ +- "Unknown" /* 0x1f */ +-}; + +- +- + /* open_device() -- set the 'fh' variable.... */ + void open_device(void) { + +@@ -301,7 +280,7 @@ + CDB[5]=0; + + /* we really don't care if this command works or not, sigh. */ +- slow_bzero((unsigned char *)&RequestSense,sizeof(RequestSense_T)); ++ slow_bzero((char *)&RequestSense,sizeof(RequestSense_T)); + if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,buffer,0,&RequestSense)!=0){ + PrintRequestSense(&RequestSense); + return 1; +@@ -324,7 +303,7 @@ + CDB[5]=0; + + /* we really don't care if this command works or not, sigh. */ +- slow_bzero((unsigned char *)&sense,sizeof(RequestSense_T)); ++ slow_bzero((char *)&sense,sizeof(RequestSense_T)); + if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,buffer,0,&sense)!=0){ + PrintRequestSense(&sense); + return 1; +@@ -349,7 +328,7 @@ + CDB[5]=0; + + /* we really don't care if this command works or not, sigh. */ +- slow_bzero((unsigned char *)&sense,sizeof(RequestSense_T)); ++ slow_bzero((char *)&sense,sizeof(RequestSense_T)); + if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,buffer,0,&sense)!=0){ + PrintRequestSense(&sense); + return 1; +@@ -392,7 +371,7 @@ + CDB[5]=0; + + /* we really don't care if this command works or not, sigh. */ +- slow_bzero((unsigned char *)&sense,sizeof(RequestSense_T)); ++ slow_bzero((char *)&sense,sizeof(RequestSense_T)); + if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,6,buffer,0,&sense)!=0){ + PrintRequestSense(&sense); + return 1; +@@ -422,7 +401,7 @@ + CDB[9]=0; + + /* we really don't care if this command works or not, sigh. */ +- slow_bzero((unsigned char *)&sense,sizeof(RequestSense_T)); ++ slow_bzero((char *)&sense,sizeof(RequestSense_T)); + if (SCSI_ExecuteCommand(MediumChangerFD,Input,&CDB,10,buffer,0,&sense)!=0){ + PrintRequestSense(&sense); + return 1; +@@ -462,7 +441,7 @@ + static int S_setblk(void) { + RequestSense_T sense; + CDB_T CDB; +- unsigned char buffer[12]; ++ char buffer[12]; + unsigned int count = (unsigned int) arg1; + + +@@ -473,7 +452,7 @@ + CDB[4]=12; /* length of data */ + CDB[5]=0; + +- slow_bzero((unsigned char *)&sense,sizeof(RequestSense_T)); ++ slow_bzero((char *)&sense,sizeof(RequestSense_T)); + slow_bzero(buffer,12); + + /* Now to set the mode page header: */ +@@ -679,9 +658,9 @@ + + /* S_write is not implemented yet! */ + static int S_write(void) { +- unsigned char *buffer; /* the buffer we're gonna read/write out of. */ ++ char *buffer; /* the buffer we're gonna read/write out of. */ + int buffersize; +- int len; /* the length of the data in the buffer */ ++ unsigned int len; /* the length of the data in the buffer */ + int blocksize=arg[0]; + int numblocks=arg[1]; + int varsize=0; /* variable size block flag */ +@@ -755,9 +734,9 @@ + + + static int S_read(void) { +- unsigned char *buffer; /* the buffer we're going to be reading out of */ ++ char *buffer; /* the buffer we're going to be reading out of */ + int buffersize; +- int len; /* the length of the data in the buffer */ ++ unsigned int len; /* the length of the data in the buffer */ + int blocksize=arg[0]; + int numblocks=arg[1]; + int varsize=0; /* variable size block flag. */ +Index: mtx.h +=================================================================== +--- mtx.h (revision 139) ++++ mtx.h (working copy) +@@ -18,7 +18,11 @@ + #include "[.vms]defs.h" + #else /* all the Unix stuff: */ + ++#ifdef _MSC_VER ++#include "msvc/config.h" /* all the autoconf stuff. */ ++#else + #include "config.h" /* all the autoconf stuff. */ ++#endif + + /* all the general Unix includes: */ + +@@ -59,7 +63,7 @@ + # include + #endif + +-/* Now greately modified to use GNU Autoconf stuff: */ ++/* Now greatly modified to use GNU Autoconf stuff: */ + /* If we use the 'sg' interface, like Linux, do this: */ + #if HAVE_SCSI_SG_H + # include +@@ -69,6 +73,27 @@ + # define HAVE_GET_ID_LUN 1 /* signal that we have it... */ + #endif + ++/* Windows Native programs built using MinGW */ ++#if HAVE_DDK_NTDDSCSI_H ++# include ++# include ++# undef DEVICE_TYPE ++ ++typedef int DEVICE_TYPE; ++# define HAVE_GET_ID_LUN 1 /* signal that we have it... */ ++#endif ++ ++/* Windows Native programs built using Microsoft Visual C */ ++#ifdef _MSC_VER ++# include ++# include ++# include ++# undef DEVICE_TYPE ++ ++typedef int DEVICE_TYPE; ++# define HAVE_GET_ID_LUN 1 /* signal that we have it... */ ++#endif ++ + /* The 'cam' interface, like FreeBSD: */ + #if HAVE_CAMLIB_H + # include /* easy (?) access to the CAM user library. */ +@@ -176,10 +201,23 @@ + unsigned char invert2; /* used for EXCHANGE command, sigh. */ + } SCSI_Flags_T; + ++#ifdef _MSC_VER ++typedef unsigned char boolean; ++ ++#define false 0 ++#define true 1 ++ ++ ++typedef unsigned char Direction_T; ++ ++#define Input 0 ++#define Output 1 ++#else + typedef enum { false, true } boolean; + + + typedef enum { Input, Output } Direction_T; ++#endif + + + typedef unsigned char CDB_T[12]; +@@ -354,6 +392,15 @@ + } ElementModeSense_T; + + ++#ifdef _MSC_VER ++typedef char ElementTypeCode_T; ++ ++#define AllElementTypes 0 ++#define MediumTransportElement 1 ++#define StorageElement 2 ++#define ImportExportElement 3 ++#define DataTransferElement 4 ++#else + typedef enum ElementTypeCode + { + AllElementTypes = 0, +@@ -363,6 +410,7 @@ + DataTransferElement = 4 + } + ElementTypeCode_T; ++#endif + + + typedef struct ElementStatusDataHeader +Index: nsmhack.c +=================================================================== +--- nsmhack.c (revision 139) ++++ nsmhack.c (revision 147) +@@ -33,13 +33,13 @@ + + #include "mtxl.h" /* get the SCSI routines out of the main file */ + +-/***************************************************************** ++/****************************************************************/ + /* Variables: */ + /****************************************************************/ + + /* the device handle we're operating upon, sigh. */ +-static unsigned char *device; /* the text of the device thingy. */ +-static DEVICE_TYPE MediumChangerFD = (DEVICE_TYPE) 0; ++static char *device; /* the text of the device thingy. */ ++static DEVICE_TYPE MediumChangerFD = (DEVICE_TYPE) -1; + char *argv0; + int arg[4]; /* arguments for the command. */ + #define arg1 (arg[0]) /* for backward compatibility, sigh */ +@@ -74,7 +74,7 @@ + /* open_device() -- set the 'fh' variable.... */ + void open_device(void) { + +- if (MediumChangerFD) { ++ if (MediumChangerFD != -1) { + SCSI_CloseDevice("Unknown",MediumChangerFD); /* close it, sigh... new device now! */ + } + +@@ -101,7 +101,7 @@ + /* if the device is not already open, then open it from the + * environment. + */ +- if (!MediumChangerFD) { ++ if (MediumChangerFD == -1) { + /* try to get it from STAPE or TAPE environment variable... */ + device=getenv("STAPE"); + if (device==NULL) { +@@ -302,7 +302,7 @@ + } + + static int S_tongue_in(void) { +- ++ return 0; + } + + /* okay, stick our tongue out. We need a slot ID to grab a caddy from. */ +@@ -326,6 +326,7 @@ + } + + /* Okay, we have element status, so now let's assume that */ ++ return 0; + } + + /* See parse_args for the scoop. parse_args does all. */ +Index: mtxl.h +=================================================================== +--- mtxl.h (revision 139) ++++ mtxl.h (revision 147) +@@ -27,6 +27,9 @@ + + #include "mtx.h" + ++#undef min ++#undef max ++ + void FatalError(char *ErrorMessage, ...); + void *xmalloc(size_t Size); + void *xzmalloc(size_t Size); +Index: config.h +=================================================================== +--- ../release/mtx-1.3.9/config.h.in 2003-09-29 19:43:20.000000000 -0700 ++++ config.h 2006-07-30 00:42:37.000000000 -0700 +@@ -1,3 +1,4 @@ ++/* config.h. Generated by configure. */ + /* Copyright 2001 Enhanced Software Technologies Inc. + * Released under GNU General Public License V2 or Above + * See http://www.gnu.org for more information about the terms of +@@ -10,10 +11,10 @@ + #define CONFIG_H 1 + + /* autoconf changes these. */ +-#define HAVE_STRING_H 0 +-#define HAVE_UNISTD_H 0 +-#define HAVE_STDLIB_H 0 +-#define HAVE_STDARG_H 0 ++#define HAVE_STRING_H 1 ++#define HAVE_UNISTD_H 1 ++#define HAVE_STDLIB_H 1 ++#define HAVE_STDARG_H 1 + #define HAVE_SCSI_SCSI_H 0 + #define HAVE_SCSI_SCSI_IOCTL_H 0 + #define HAVE_SCSI_SG_H 0 +@@ -23,10 +24,12 @@ + #define HAVE_SYS_SCSI_CTL_H 0 + #define HAVE_DSLIB_H 0 + #define HAVE_DU_DEFS_H 0 +-#define HAVE_SYS_STAT_H 0 +-#define HAVE_SYS_TYPES_H 0 +-#define HAVE_FCNTL_H 0 ++#define HAVE_SYS_STAT_H 1 ++#define HAVE_SYS_TYPES_H 1 ++#define HAVE_FCNTL_H 1 + #define HAVE_SYS_IOCTL_H 0 ++#define HAVE_SYS_MTIO_H 0 ++#define HAVE_DDK_NTDDSCSI_H 1 + + #define WORDS_BIGENDIAN 0 + +Index: mtxl.c +=================================================================== +--- ../release/mtx-1.3.9/mtxl.c 2003-10-02 23:03:20.000000000 -0700 ++++ mtxl.c 2006-07-30 00:49:31.000000000 -0700 +@@ -53,6 +53,11 @@ + # include "scsi_linux.c" + #endif + ++/* the IOCTL_SCSI_PASSTHROUGH interface is used on Windows. */ ++#if HAVE_DDK_NTDDSCSI_H || defined(_MSC_VER) ++# include "scsi_win32.c" ++#endif ++ + /* The 'uscsi' interface is used on Solaris. */ + #if HAVE_SYS_SCSI_IMPL_USCSI_H + # include "scsi_sun.c" +@@ -78,6 +83,7 @@ + #include "[.vms]scsi.c" + #endif + ++void PrintHex(int Indent, unsigned char *Buffer, int Length); + extern char *argv0; /* something to let us do good error messages. */ + + /* create a global RequestSenseT value. */ +@@ -104,6 +110,9 @@ + if (SCSI_ExecuteCommand(fd, Input, &CDB, 6, + Inquiry, sizeof(Inquiry_T), RequestSense) != 0) + { ++#ifdef DEBUG ++ fprintf(stderr, "SCSI Inquiry Command failed\n"); ++#endif + free(Inquiry); + return NULL; /* sorry! */ + } +@@ -111,36 +120,27 @@ + } + + ++#if defined(DEBUG_NSM) || defined(DEBUG_EXCHANGE) + /* DEBUG */ + static void dump_cdb(unsigned char *CDB, int len) { +- int i; + fprintf(stderr,"CDB:"); +- for (i=0;iNumStorageHi,sense_page->NumStorageLo, +- sense_page->NumImportExportHi, sense_page->NumImportExportLo); ++ sense_page->NumStorageHi,sense_page->NumStorageLo, ++ sense_page->NumImportExportHi, sense_page->NumImportExportLo); + fprintf(stderr,"rawNumTransport=%d %d rawNumDataTransfer=%d %d\n", +- sense_page->NumMediumTransportHi,sense_page->NumMediumTransportLo, +- sense_page->NumDataTransferHi,sense_page->NumDataTransferLo); ++ sense_page->NumMediumTransportHi,sense_page->NumMediumTransportLo, ++ sense_page->NumDataTransferHi,sense_page->NumDataTransferLo); + fflush(stderr); + #endif + +@@ -620,19 +618,16 @@ + CDB[11] = 0; /* Control */ + + #ifdef DEBUG_BARCODE +- { +- int i; +- fprintf(stderr,"CDB= "); +- for (i=0;i<12;i++) { +- fprintf(stderr,"%x ",CDB[i]); +- } +- fprintf(stderr,"\n"); +- fflush(stderr); +- } ++ fprintf(stderr,"CDB:\n"); ++ PrintHex(2, CDB, 12); + #endif + + if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 12, + DataBuffer,NumBytes, RequestSense) != 0){ ++ ++#ifdef DEBUG ++ fprintf(stderr, "Read Element Status (0x%02X) failed\n", CDB[0]); ++#endif + /* okay, first see if we have sense key of 'illegal request', + additional sense code of '24', additional sense qualfier of + '0', and field in error of '4'. This means that we issued a request +@@ -654,15 +649,8 @@ + CDB[1] &= ~0x10; /* clear bar code flag! */ + + #ifdef DEBUG_BARCODE +- { +- int i; +- fprintf(stderr,"CDB= "); +- for (i=0;i<12;i++) { +- fprintf(stderr,"%x ",CDB[i]); +- } +- fprintf(stderr,"\n"); +- fflush(stderr); +- } ++ fprintf(stderr,"CDB:\n"); ++ PrintHex(2, CDB, 12); + #endif + + if (SCSI_ExecuteCommand(MediumChangerFD, Input, &CDB, 12, +@@ -679,14 +667,8 @@ + #ifdef DEBUG_BARCODE + /* print a bunch of extra debug data :-(. */ + PrintRequestSense(RequestSense); /* see what it sez :-(. */ +- { +- int i; +- fprintf(stderr,"Data:"); +- for (i=0;i<40;i++) { +- fprintf(stderr,"%02x ",DataBuffer[i]); +- } +- fprintf(stderr,"\n"); +- } ++ fprintf(stderr,"Data:\n"); ++ PrintHex(2, DataBuffer, 40); + #endif + return DataBuffer; /* we succeeded! */ + } +@@ -703,7 +685,7 @@ + ) { + + unsigned char *DataBuffer; /* size of data... */ +- unsigned int real_numbytes; ++ int real_numbytes; + + + DataBuffer=SendElementStatusRequestActual(MediumChangerFD, +@@ -950,34 +932,42 @@ + BigEndian16(TransportElementDescriptor + ->SourceStorageElementAddress); + +- if (ElementStatus->DataTransferElementCount >= mode_sense->NumDataTransfer) { +- FatalError("Too many Data Transfer Elements Reported\n"); +- } +- if (ElementStatusPage->VolBits & E2_PVOLTAG) { +- copy_barcode(TransportElementDescriptor->PrimaryVolumeTag, +- ElementStatus->DataTransferPrimaryVolumeTag[ElementStatus->DataTransferElementCount]); +- } else { +- ElementStatus->DataTransferPrimaryVolumeTag[ElementStatus->DataTransferElementCount][0]=0; /* null string */ +- } +- if (ElementStatusPage->VolBits & E2_AVOLTAG) { +- copy_barcode(TransportElementDescriptor->AlternateVolumeTag, +- ElementStatus->DataTransferAlternateVolumeTag[ElementStatus->DataTransferElementCount]); +- } else { +- ElementStatus->DataTransferAlternateVolumeTag[ElementStatus->DataTransferElementCount][0]=0; /* null string */ +- } +- ElementStatus->DataTransferElementCount++; +- /* 0 actually is a usable element address */ +- /* if (DataTransferElementAddress == 0) */ +- /* FatalError( */ +- /* "illegal Data Transfer Element Address %d reported\n", */ +- /* DataTransferElementAddress); */ +- break; +- default: +- FatalError("illegal Element Type Code %d reported\n", +- ElementStatusPage->ElementTypeCode); +- } +- } ++#if DEBUG ++ fprintf(stderr, "%d: ElementAddress = %d, Full = %d, SourceElement = %d\n", ++ ElementStatus->DataTransferElementCount, ++ ElementStatus->DataTransferElementAddress[ElementStatus->DataTransferElementCount], ++ ElementStatus->DataTransferElementFull[ElementStatus->DataTransferElementCount], ++ ElementStatus->DataTransferElementSourceStorageElementNumber[ElementStatus->DataTransferElementCount]); ++#endif ++ if (ElementStatus->DataTransferElementCount >= mode_sense->NumDataTransfer) { ++ FatalError("Too many Data Transfer Elements Reported\n"); ++ } ++ if (ElementStatusPage->VolBits & E2_PVOLTAG) { ++ copy_barcode(TransportElementDescriptor->PrimaryVolumeTag, ++ ElementStatus->DataTransferPrimaryVolumeTag[ElementStatus->DataTransferElementCount]); ++ } else { ++ ElementStatus->DataTransferPrimaryVolumeTag[ElementStatus->DataTransferElementCount][0]=0; /* null string */ ++ } ++ if (ElementStatusPage->VolBits & E2_AVOLTAG) { ++ copy_barcode(TransportElementDescriptor->AlternateVolumeTag, ++ ElementStatus->DataTransferAlternateVolumeTag[ElementStatus->DataTransferElementCount]); ++ } else { ++ ElementStatus->DataTransferAlternateVolumeTag[ElementStatus->DataTransferElementCount][0]=0; /* null string */ ++ } ++ ElementStatus->DataTransferElementCount++; ++ ++ /* 0 actually is a usable element address */ ++ /* if (DataTransferElementAddress == 0) */ ++ /* FatalError( */ ++ /* "illegal Data Transfer Element Address %d reported\n", */ ++ /* DataTransferElementAddress); */ ++ break; ++ default: ++ FatalError("illegal Element Type Code %d reported\n", ++ ElementStatusPage->ElementTypeCode); ++ } + } ++ } + } + + /********************* Real ReadElementStatus ********************* */ +@@ -1008,7 +998,6 @@ + int *EmptyStorageElementAddress; /* [MAX_STORAGE_ELEMENTS]; */ + + int empty_idx=0; +- int invalid_sources=0; + boolean is_attached = false; + int i,j; + +@@ -1049,7 +1038,7 @@ + + EmptyStorageElementAddress=(int *)xzmalloc((mode_sense->NumStorage+1)*sizeof(int)); + for (i=0;iNumStorage;i++) { +- EmptyStorageElementAddress[i]=-1; ++ EmptyStorageElementAddress[i] = -1; + } + + /* Okay, now to send some requests for the various types of stuff: */ +@@ -1076,6 +1065,9 @@ + #endif + /* darn. Free up stuff and return. */ + /****FIXME**** do a free on element data! */ ++#ifdef DEBUG_MODE_SENSE ++ PrintRequestSense(RequestSense); ++#endif + FreeElementData(ElementStatus); + return NULL; + } +@@ -1107,6 +1099,9 @@ + #endif + /* darn. Free up stuff and return. */ + /****FIXME**** do a free on element data! */ ++#ifdef DEBUG_MODE_SENSE ++ PrintRequestSense(RequestSense); ++#endif + FreeElementData(ElementStatus); + return NULL; + } +@@ -1138,6 +1133,9 @@ + #endif + /* darn. Free up stuff and return. */ + /****FIXME**** do a free on element data! */ ++#ifdef DEBUG_MODE_SENSE ++ PrintRequestSense(RequestSense); ++#endif + FreeElementData(ElementStatus); + return NULL; + } +@@ -1172,6 +1170,9 @@ + #endif + /* darn. Free up stuff and return. */ + /****FIXME**** do a free on element data! */ ++#ifdef DEBUG_MODE_SENSE ++ PrintRequestSense(RequestSense); ++#endif + FreeElementData(ElementStatus); + return NULL; + } +@@ -1223,34 +1224,24 @@ + * is obviously defective: + */ + /* pass one: */ +- invalid_sources=0; /* no invalid sources yet! */ + for (i=0;iDataTransferElementCount;i++) { + int elnum; +- int translated_elnum = -1; + /* if we have an element, then ... */ + if (ElementStatus->DataTransferElementFull[i]) { + elnum=ElementStatus->DataTransferElementSourceStorageElementNumber[i]; + /* if we have an element number, then ... */ + if (elnum >= 0) { +- /* Now to translate the elnum: */ +- for (j=0; jStorageElementCount; j++) { +- if (elnum == ElementStatus->StorageElementAddress[j]) { +- translated_elnum=j; +- } +- } +- /* now see if the element # is already occupied: */ +- if (ElementStatus->StorageElementFull[translated_elnum]) { +- invalid_sources=1; +- break; /* break out of the loop! */ +- } else { +- /* properly set the source... */ +- ElementStatus->DataTransferElementSourceStorageElementNumber[i]= +- translated_elnum; +- } +- +- } else { +- /* if element # was not >=0, then we had an invalid source anyhow! */ +- invalid_sources=1; ++ /* Now to translate the elnum: */ ++ ElementStatus->DataTransferElementSourceStorageElementNumber[i] = -1; ++ for (j=0; jStorageElementCount; j++) { ++ if (elnum == ElementStatus->StorageElementAddress[j]) { ++ /* now see if the element # is already occupied:*/ ++ if (!ElementStatus->StorageElementFull[j]) { ++ /* properly set the source... */ ++ ElementStatus->DataTransferElementSourceStorageElementNumber[i]= j; ++ } ++ } ++ } + } + } + } +@@ -1267,21 +1258,19 @@ + * by the user interface. This is an invalid value, but more useful for us + * to have than just crapping out here :-(. + */ +- if (invalid_sources) { +- empty_idx=0; +- for (i=0;iDataTransferElementCount;i++) { +- if (ElementStatus->DataTransferElementFull[i]) { ++ empty_idx=0; ++ for (i = 0; i < ElementStatus->DataTransferElementCount; i++) { ++ if (ElementStatus->DataTransferElementFull[i] && ++ ElementStatus->DataTransferElementSourceStorageElementNumber[i] < 0) { + #ifdef DEBUG_TAPELIST +- fprintf(stderr,"for drive %d, changing source %d to %d (empty slot #%d)\n", +- i, +- ElementStatus->DataTransferElementSourceStorageElementNumber[i], +- EmptyStorageElementAddress[empty_idx], +- empty_idx); ++ fprintf(stderr,"for drive %d, changing to %d (empty slot #%d)\n", ++ i, ++ EmptyStorageElementAddress[empty_idx], ++ empty_idx); + #endif + + ElementStatus->DataTransferElementSourceStorageElementNumber[i]= + EmptyStorageElementAddress[empty_idx++]; +- } + } + } + +@@ -1337,9 +1326,9 @@ + CDB[2] = (ElementStatus->TransportElementAddress >> 8) & 0xFF; /* Transport Element Address MSB */ + CDB[3] = (ElementStatus->TransportElementAddress) & 0xff; /* Transport Element Address LSB */ + CDB[4] = (SourceAddress >> 8) & 0xFF; /* Source Address MSB */ +- CDB[5] = SourceAddress & 0xFF; /* Source Address MSB */ ++ CDB[5] = SourceAddress & 0xFF; /* Source Address LSB */ + CDB[6] = (DestinationAddress >> 8) & 0xFF; /* Destination Address MSB */ +- CDB[7] = DestinationAddress & 0xFF; /* Destination Address MSB */ ++ CDB[7] = DestinationAddress & 0xFF; /* Destination Address LSB */ + CDB[8] = 0; /* Reserved */ + CDB[9] = 0; /* Reserved */ + if (flags->invert) { +@@ -1351,7 +1340,11 @@ + CDB[11] = 0 | (flags->eepos <<6); /* Control */ + + if (SCSI_ExecuteCommand(MediumChangerFD, Output, &CDB, 12, +- NULL, 0, RequestSense) != 0) { ++ NULL, 0, RequestSense) != 0) { ++ ++#ifdef DEBUG ++ fprintf(stderr, "Move Medium (0x%02X) failed\n", CDB[0]); ++#endif + return RequestSense; + } + free(RequestSense); +@@ -1372,9 +1365,9 @@ + CDB[2] = (ElementStatus->TransportElementAddress >> 8) & 0xFF; /* Transport Element Address MSB */ + CDB[3] = (ElementStatus->TransportElementAddress) & 0xff; /* Transport Element Address LSB */ + CDB[4] = (SourceAddress >> 8) & 0xFF; /* Source Address MSB */ +- CDB[5] = SourceAddress & 0xFF; /* Source Address MSB */ ++ CDB[5] = SourceAddress & 0xFF; /* Source Address LSB */ + CDB[6] = (DestinationAddress >> 8) & 0xFF; /* Destination Address MSB */ +- CDB[7] = DestinationAddress & 0xFF; /* Destination Address MSB */ ++ CDB[7] = DestinationAddress & 0xFF; /* Destination Address LSB */ + CDB[8] = (Dest2Address>>8) & 0xFF; /* move destination back to source? */ + CDB[9] = Dest2Address & 0xFF; /* move destination back to source? */ + CDB[10]=0; +@@ -1418,12 +1411,53 @@ + + if (SCSI_ExecuteCommand(MediumChangerFD, Output, &CDB, 6, + NULL, 0, RequestSense) != 0) { ++#ifdef DEBUG ++ fprintf(stderr, "Erase (0x19) failed\n"); ++#endif + return RequestSense; + } + free(RequestSense); + return NULL; /* Success! */ + } + ++static char Spaces[] = " "; ++ ++void PrintHex(int Indent, unsigned char *Buffer, int Length) ++{ ++ int idxBuffer; ++ int idxAscii; ++ int PadLength; ++ char cAscii; ++ ++ for (idxBuffer = 0; idxBuffer < Length; idxBuffer++) { ++ if ((idxBuffer % 16) == 0) { ++ if (idxBuffer > 0) { ++ fputc('\'', stderr); ++ ++ for (idxAscii = idxBuffer - 16; idxAscii < idxBuffer; idxAscii++) { ++ cAscii = Buffer[idxAscii] >= 0x20 && Buffer[idxAscii] < 0x7F ? Buffer[idxAscii] : '.'; ++ fputc(cAscii, stderr); ++ } ++ fputs("'\n", stderr); ++ } ++ fprintf(stderr, "%.*s%04X: ", Indent, Spaces, idxBuffer); ++ } ++ fprintf(stderr, "%02X ", (unsigned char)Buffer[idxBuffer]); ++ } ++ ++ PadLength = 16 - (Length % 16); ++ ++ if (PadLength > 0) { ++ fprintf(stderr, "%.*s'", 3 * PadLength, Spaces); ++ ++ for (idxAscii = idxBuffer - (16 - PadLength); idxAscii < idxBuffer; idxAscii++) { ++ cAscii = Buffer[idxAscii] >= 0x20 && Buffer[idxAscii] < 0x80 ? Buffer[idxAscii] : '.'; ++ fputc(cAscii, stderr); ++ } ++ fputs("'\n", stderr); ++ } ++ fflush(stderr); ++} + + #ifdef LONG_PRINT_REQUEST_SENSE + +@@ -1488,12 +1522,9 @@ + #else + void PrintRequestSense(RequestSense_T *RequestSense) + { +- int i; +- fprintf(stderr, "mtx: Request Sense: %02X", +- ((unsigned char *) RequestSense)[0]); +- for (i = 1; i < sizeof(RequestSense_T); i++) +- fprintf(stderr, " %02X", ((unsigned char *) RequestSense)[i]); +- fprintf(stderr, "\n"); ++ fprintf(stderr, "mtx: Request Sense: %02X\n", ++ ((unsigned char *) RequestSense)[0]); ++ PrintHex(2, (char *)RequestSense, sizeof(RequestSense_T)); + } + + #endif +Index: Makefile +=================================================================== +--- ../release/mtx-1.3.9/Makefile.in 2006-02-20 13:42:10.000000000 -0800 ++++ Makefile 2006-07-30 01:22:00.000000000 -0700 +@@ -11,26 +11,28 @@ + # Version # for 'make dist'... + VERSION=1.3.9 + +-BINS = mtx tapeinfo loaderinfo scsitape nsmhack ++BINS = mtx.exe tapeinfo.exe loaderinfo.exe scsitape.exe nsmhack.exe ++DBGS := $(BINS:%.exe=%.dbg) + +-TARGET = @TARGET@ +-CPU = @CPU@ +-CC = @CC@ +-INSTALL = @INSTALL@ +- +-CFLAGS = @CFLAGS@ +-CPPFLAGS = @CPPFLAGS@ -DVERSION="\"$(VERSION)\"" +-LDFLAGS = @LDFLAGS@ +-LIBS = @LIBS@ ++TARGET = mingw ++CPU = 386 ++CC = mingw32-gcc ++INSTALL = install -c ++ ++CFLAGS = -g -O2 ++CPPFLAGS = -DVERSION="\"$(VERSION)\"" ++LDFLAGS = ++LIBS = ++USE_OBJCOPY = yes + + INSTALL_DOC = $(INSTALL) -m 644 + INSTALL_BIN = $(INSTALL) -m 755 + INSTALL_DIR = $(INSTALL) -m 755 -d + +-prefix = @prefix@ +-exec_prefix = @exec_prefix@ +-sbindir = @sbindir@ +-mandir = @mandir@ ++prefix = dummy ++exec_prefix = ${prefix} ++sbindir = ${exec_prefix}/bin ++mandir = ${prefix}/man + + # + # Linux on x86... +@@ -40,6 +42,11 @@ + CPPFLAGS += -I/usr/src/linux/include -DLONG_PRINT_REQUEST_SENSE=1 + endif + ++ifeq ($(TARGET),mingw) ++CFLAGS += -Wall ++CPPFLAGS += -DLONG_PRINT_REQUEST_SENSE=1 ++endif ++ + # + # FreeBSD on x86... + # +@@ -82,12 +89,22 @@ + See vms/000readme for information. + endif + ++%.dbg : %.exe ++ifeq ($(USE_OBJCOPY),yes) ++ mingw32-objcopy --only-keep-debug $< $@ ++ mingw32-objcopy --strip-debug $< ++ mingw32-objcopy --add-gnu-debuglink=$@ $< ++else ++ strip $< -o $@ ++endif ++ + all: $(BINS) + +-install: $(BINS) ++dbgs: $(DBGS) ++ ++install: $(BINS) $(DBGS) + $(INSTALL_DIR) $(sbindir) + for file in $(BINS); do \ +- strip "$$file" ; \ + $(INSTALL_BIN) "$$file" $(sbindir) ; \ + done + $(INSTALL_DIR) $(mandir) $(mandir)/man1 +@@ -98,7 +115,9 @@ + clean: + rm -f *.o *~ + rm -f $(BINS) +- rm -f mam2debug mam2debug2 ++ rm -f $(DBGS) ++ rm -f mam2debug.exe mam2debug2.exe ++ rm -rf autom4te.cache + + distclean: clean + rm -f Makefile config.log config.cache config.status +@@ -106,27 +125,26 @@ + dist: distclean + ./makedist $(VERSION) + +-loaderinfo: loaderinfo.o mtxl.o mtxl.h mtx.h $(EXTRA) +- $(CC) $(LDFLAGS) -o loaderinfo loaderinfo.o mtxl.o $(EXTRA) $(LIBS) +- ++loaderinfo.exe: loaderinfo.o mtxl.o mtxl.h mtx.h $(EXTRA) ++ $(CC) $(LDFLAGS) -o $@ loaderinfo.o mtxl.o $(EXTRA) $(LIBS) + +-nsmhack: nsmhack.o mtxl.o $(EXTRA) +- $(CC) $(LDFLAGS) -o nsmhack nsmhack.o mtxl.o $(EXTRA) $(LIBS) ++nsmhack.exe: nsmhack.o mtxl.o $(EXTRA) ++ $(CC) $(LDFLAGS) -o $@ nsmhack.o mtxl.o $(EXTRA) $(LIBS) + +-mtx: mtx.o mtxl.o mtxl.h mtx.h $(EXTRA) +- $(CC) $(LDFLAGS) -o mtx mtx.o mtxl.o $(EXTRA) $(LIBS) ++mtx.exe: mtx.o mtxl.o mtxl.h mtx.h $(EXTRA) ++ $(CC) $(LDFLAGS) -o $@ mtx.o mtxl.o $(EXTRA) $(LIBS) + +-mam2debug: mtxl.o mam2debug.o mtx.h $(EXTRA) +- $(CC) $(LDFLAGS) -o mam2debug mtxl.o mam2debug.o $(EXTRA) $(LIBS) ++mam2debug.exe: mtxl.o mam2debug.o mtx.h $(EXTRA) ++ $(CC) $(LDFLAGS) -o $@ mtxl.o mam2debug.o $(EXTRA) $(LIBS) + +-tapeinfo: tapeinfo.o mtxl.o mtx.h mtxl.h $(EXTRA) +- $(CC) $(LDFLAGS) -o tapeinfo tapeinfo.o mtxl.o $(EXTRA) $(LIBS) ++tapeinfo.exe: tapeinfo.o mtxl.o mtx.h mtxl.h $(EXTRA) ++ $(CC) $(LDFLAGS) -o $@ tapeinfo.o mtxl.o $(EXTRA) $(LIBS) + +-mam2debug2: mtxl.o mam2debug2.o mtx.h $(EXTRA) +- $(CC) $(LDFLAGS) -o mam2debug2 mtxl.o mam2debug2.o $(EXTRA) $(LIBS) ++mam2debug2.exe: mtxl.o mam2debug2.o mtx.h $(EXTRA) ++ $(CC) $(LDFLAGS) -o $@ mtxl.o mam2debug2.o $(EXTRA) $(LIBS) + +-scsitape: scsitape.o mtxl.o mtxl.h mtx.h $(EXTRA) +- $(CC) $(LDFLAGS) -o scsitape scsitape.o mtxl.o $(EXTRA) $(LIBS) ++scsitape.exe: scsitape.o mtxl.o mtxl.h mtx.h $(EXTRA) ++ $(CC) $(LDFLAGS) -o $@ scsitape.o mtxl.o $(EXTRA) $(LIBS) + + scsitape.o: scsitape.c mtx.h mtxl.h + +@@ -140,6 +158,6 @@ + + mtx.o: mtx.c mtx.h mtxl.h + +-mtxl.o: mtxl.c mtx.h mtxl.h scsi_linux.c ++mtxl.o: mtxl.c mtx.h mtxl.h scsi_linux.c scsi_win32.c + + nsmhack.o: nsmhack.c mtxl.h mtx.h -- 2.39.5