2 diff -ru ../../ibiblio/mt-st-0.9b/Makefile ./Makefile
3 --- ../../ibiblio/mt-st-0.9b/Makefile Tue Aug 16 12:16:28 2005
4 +++ ./Makefile Sun Jul 30 05:59:14 2006
10 -MANDIR= /usr/share/man
12 +SBINDIR= $(PREFIX)/sbin
13 +BINDIR= $(PREFIX)/bin
14 +MANDIR= $(PREFIX)/man
20 - $(CC) $(CFLAGS) -o mt mt.c
22 + $(CC) $(CFLAGS) -o mt.exe mt.c mtops.c
26 $(CC) $(CFLAGS) -o stinit stinit.c
29 - install -s mt $(BINDIR)
31 + install -s mt.exe $(BINDIR)
32 install -c -m 444 mt.1 $(MANDIR)/man1
33 (if [ -f $(MANDIR)/man1/mt.1.gz ] ; then \
34 rm -f $(MANDIR)/man1/mt.1.gz; gzip $(MANDIR)/man1/mt.1; fi)
35 - install -s stinit $(SBINDIR)
36 - install -c -m 444 stinit.8 $(MANDIR)/man8
37 - (if [ -f $(MANDIR)/man8/stinit.8.gz ] ; then \
38 - rm -f $(MANDIR)/man8/stinit.8.gz; gzip $(MANDIR)/man8/stinit.8; fi)
41 (mydir=`basename \`pwd\``;\
42 cd .. && tar cvvf - $$mydir | gzip -9 > $${mydir}.tar.gz)
45 - rm -f *~ \#*\# *.o mt stinit
46 + rm -f *~ \#*\# *.o mt.exe stinit.exe
49 diff -ru ../../ibiblio/mt-st-0.9b/mt.1 ./mt.1
50 --- ../../ibiblio/mt-st-0.9b/mt.1 Sun Aug 21 11:53:50 2005
51 +++ ./mt.1 Sun Jul 30 05:16:07 2006
54 The tape is positioned on the first block of the next file.
60 -The tape is positioned on the last block of the previous file.
61 +file marks, then backward space one file record.
62 +This leaves the tape positioned on the last block of the file that is count-1
63 +files past the current file.
68 The tape is positioned on the last block of the previous file.
74 -The tape is positioned on the first block of the next file.
75 +file marks, then forward space one file record.
76 +This leaves the tape positioned on the first block of the file that is count-1
77 +files before the current file.
79 The tape is positioned at the beginning of the
81 diff -ru ../../ibiblio/mt-st-0.9b/mt.c ./mt.c
82 --- ../../ibiblio/mt-st-0.9b/mt.c Sun Aug 21 11:48:06 2005
83 +++ ./mt.c Sun Jul 30 06:04:13 2006
85 Last Modified: Sun Aug 21 21:48:06 2005 by kai.makisara
89 +#include <winioctl.h>
100 #include <sys/types.h>
101 -#include <sys/ioctl.h>
106 +#define ioctl tape_ioctl
109 -#define DEFTAPE "/dev/tape" /* default tape device */
110 +#define DEFTAPE "Tape0" /* default tape device */
113 -#define VERSION "0.9b"
114 +#define VERSION "0.9b-bacula"
116 typedef int (* cmdfunc)(/* int, struct cmdef_tr *, int, char ** */);
118 @@ -143,12 +151,14 @@
119 FD_RDONLY, ONE_ARG, 0},
120 { "defcompression", MTSETDRVBUFFER, do_drvbuffer, MT_ST_DEF_COMPRESSION,
121 FD_RDONLY, ONE_ARG, 0},
123 { "stsetcln", MTSETDRVBUFFER, do_drvbuffer, MT_ST_SET_CLN,
124 FD_RDONLY, ONE_ARG, 0},
125 { "sttimeout", MTSETDRVBUFFER, do_drvbuffer, MT_ST_SET_TIMEOUT,
126 FD_RDONLY, ONE_ARG, 0},
127 { "stlongtimeout", MTSETDRVBUFFER, do_drvbuffer, MT_ST_SET_LONG_TIMEOUT,
128 FD_RDONLY, ONE_ARG, 0},
130 { "densities", 0, print_densities, 0, NO_FD, NO_ARGS,
132 { "setpartition", MTSETPART, do_standard, 0, FD_RDONLY, ONE_ARG,
133 @@ -211,13 +221,19 @@
134 {0x30, "AIT-1 or MLR3"},
138 + {0x33, "AIT-4 or SLR6"},
140 + {0x38, "AIT-E Turbo"},
141 + {0x39, "AIT-1 Turbo"},
142 + {0x3A, "AIT-2 Turbo"},
144 {0x40, "DLT1 40 GB, or Ultrium"},
145 {0x41, "DLT 40GB, or Ultrium2"},
147 {0x45, "QIC-3095-MC (TR-4)"},
149 + {0x48, "Quantum SDLT220"},
150 + {0x49, "Quantum SDLT320"},
151 {0x80, "DLT 15GB uncomp. or Ecrix"},
152 {0x81, "DLT 15GB compressed"},
153 {0x82, "DLT 20GB uncompressed"},
154 @@ -254,20 +270,25 @@
155 {"no-blklimits", MT_ST_NO_BLKLIMS, "drive doesn't support read block limits"},
156 {"can-partitions",MT_ST_CAN_PARTITIONS,"drive can handle partitioned tapes"},
157 {"scsi2logical", MT_ST_SCSI2LOGICAL, "logical block addresses used with SCSI-2"},
159 {"no-wait", MT_ST_NOWAIT, "immediate mode for rewind, etc."},
162 {"sysv", MT_ST_SYSV, "enable the SystemV semantics"},
165 {"cleaning", MT_ST_SET_CLN, "set the cleaning bit location and mask"},
169 static char *tape_name; /* The tape name for messages */
174 main(int argc, char **argv)
176 - int mtfd, cmd_code, i, argn, len, oflags;
177 + int mtfd, cmd_code, i, argn, oflags;
180 cmdef_tr *comp, *comp2;
183 oflags = comp->cmd_fdtype == FD_RDONLY ? O_RDONLY : O_RDWR;
184 if ((comp->error_tests & ET_ONLINE) == 0)
185 oflags |= O_NONBLOCK;
186 - if ((mtfd = open(tape_name, oflags)) < 0) {
187 + if ((mtfd = tape_open(tape_name, oflags, 0)) < 0) {
201 do_standard(int mtfd, cmdef_tr *cmd, int argc, char **argv)
207 - mt_com.mt_op = cmd->cmd_code;
208 + mt_com.mt_op = (short)cmd->cmd_code;
209 mt_com.mt_count = (argc > 0 ? strtol(*argv, &endp, 0) : 1);
210 if (argc > 0 && endp != *argv) {
214 do_options(int mtfd, cmdef_tr *cmd, int argc, char **argv)
221 mt_com.mt_op = MTSETDRVBUFFER;
224 else if (status.mt_type == MT_ISSCSI2)
227 else if (status.mt_type == MT_ISONSTREAM_SC)
228 type = "OnStream SC-, DI-, DP-, or USB";
234 printf("IDE-Tape (type code 0) ?\n");
236 printf("Unknown tape drive type (type code %ld)\n", status.mt_type);
237 - printf("File number=%d, block number=%d.\n",
238 + printf("File number=%ld, block number=%ld.\n",
239 status.mt_fileno, status.mt_blkno);
240 printf("mt_resid: %ld, mt_erreg: 0x%lx\n",
241 status.mt_resid, status.mt_erreg);
242 @@ -617,14 +641,17 @@
244 printf("%s tape drive:\n", type);
245 if (status.mt_type == MT_ISSCSI2)
246 - printf("File number=%d, block number=%d, partition=%ld.\n",
247 + printf("File number=%ld, block number=%ld, partition=%ld.\n",
248 status.mt_fileno, status.mt_blkno, (status.mt_resid & 0xff));
250 - printf("File number=%d, block number=%d.\n",
251 + printf("File number=%ld, block number=%ld.\n",
252 status.mt_fileno, status.mt_blkno);
253 - if (status.mt_type == MT_ISSCSI1 ||
254 - status.mt_type == MT_ISSCSI2 ||
255 - status.mt_type == MT_ISONSTREAM_SC) {
256 + if (status.mt_type == MT_ISSCSI1
257 + || status.mt_type == MT_ISSCSI2
259 + || status.mt_type == MT_ISONSTREAM_SC
262 dens = (status.mt_dsreg & MT_ST_DENSITY_MASK) >> MT_ST_DENSITY_SHIFT;
263 density = "no translation";
264 for (i=0; i < NBR_DENSITIES; i++)
267 if (GMT_IM_REP_EN(status.mt_gstat))
268 printf(" IM_REP_EN");
270 if (GMT_CLN(status.mt_gstat))
278 diff -ru ../../ibiblio/mt-st-0.9b/mtio.h ./mtio.h
279 --- ../../ibiblio/mt-st-0.9b/mtio.h Tue Aug 16 12:16:28 2005
280 +++ ./mtio.h Sun Jul 30 06:06:13 2006
282 #ifndef _LINUX_MTIO_H
283 #define _LINUX_MTIO_H
285 -#include <linux/types.h>
286 -#include <linux/ioctl.h>
287 -#include <linux/qic117.h>
288 +#include <sys/types.h>
291 * Structures and definitions for mag tape io control commands
297 /* structure for MTIOCGETCONFIG/MTIOCSETCONFIG primarily intended
298 * as an interim solution for QIC-02 until DDI is fully implemented.
306 /* mag tape io control commands */
307 #define MTIOCTOP _IOW('m', 1, struct mtop) /* do a mag tape op */
310 diff -ru ../../ibiblio/mt-st-0.9b/stinit.def.examples ./stinit.def.examples
311 --- ../../ibiblio/mt-st-0.9b/stinit.def.examples Tue Aug 16 12:16:28 2005
312 +++ ./stinit.def.examples Sun Jul 30 05:15:43 2006
314 mode3 blocksize=0 density=1 # 800 bpi
318 +manufacturer="QUANTUM" model = "DLT2000" {
330 +# If your stinit supports the timeouts:
331 +timeout=3600 # 1 hour
332 +long-timeout=14400 # 4 hours
334 +mode1 blocksize=0 density=0x81 # 10GB + compression on DLTtape III, 15+ with DLTtape IIIXT in 2000XT
335 +mode2 blocksize=0 density=0x80 # 10GB, no compression on DLTtape III, 15 with DLTtape IIIXT in 2000XT
336 +mode3 blocksize=0 density=0x18 # 6GB, compression not available, on DLTtape III
337 +mode4 blocksize=0 density=0x17 #2.6GB, compression not available, on DLTtape III
341 +manufacturer="QUANTUM" model = "DLT4000" {
353 +# If your stinit supports the timeouts:
354 +timeout=3600 # 1 hour
355 +long-timeout=14400 # 4 hours
357 +# Drive is backwards compatible, use older modes (e.g. from above) as required
358 +mode1 blocksize=0 density=0x83 # 20GB + compression
359 +mode2 blocksize=0 density=0x82 # 20GB, no compression
360 +mode3 blocksize=0 density=0x81 # 10GB + compression (DLT2000 mode) with DLTtape III, 15+ with DLTtape IIIXT in 2000XT
361 +mode4 blocksize=0 density=0x80 # 10GB, no compression (DLT2000 mode) with DLTtape III, 15 with DLTtape IIIXT in 2000XT
365 +manufacturer="QUANTUM" model = "DLT7000" {
377 +# If your stinit supports the timeouts:
378 +timeout=3600 # 1 hour
379 +long-timeout=14400 # 4 hours
381 +# Drive is backwards compatible, use older modes (e.g. from above) as required.
382 +mode1 blocksize=0 density=0x85 # 35GB + compression
383 +mode2 blocksize=0 density=0x84 # 35GB, no compression
384 +mode3 blocksize=0 density=0x83 # 20GB + compression (DLT4000 mode)
385 +mode4 blocksize=0 density=0x82 # 20GB, no compression (DLT4000 mode)
389 +manufacturer="QUANTUM" model = "DLT8000" {
401 +# If your stinit supports the timeouts:
402 +timeout=3600 # 1 hour
403 +long-timeout=14400 # 4 hours
405 +# Drive is backwards compatible to DLT7000, use older modes (e.g. from above) as required. Modes <10GB (<0x19) not supported!
406 +mode1 blocksize=0 density=0x89 # 40GB + compression
407 +mode2 blocksize=0 density=0x88 # 40GB, no compression
408 +mode3 blocksize=0 density=0x85 # 35GB + compression (DLT7000 mode)
409 +mode4 blocksize=0 density=0x84 # 35GB, no compression (DLT7000 mode)
414 +manufacturer="QUANTUM" model = "SuperDLT1" {
426 +# If your stinit supports the timeouts:
427 +timeout=3600 # 1 hour
428 +long-timeout=14400 # 4 hours
430 +# 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.
431 +mode1 blocksize=0 density=0x48 compression=1 # 110 GB + compression
432 +mode2 blocksize=0 density=0x48 compression=0 # 110 GB, no ompression
436 +manufacturer="QUANTUM" model = "SDLT320" {
448 +# If your stinit supports the timeouts:
449 +timeout=3600 # 1 hour
450 +long-timeout=14400 # 4 hours
452 +# 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
453 +mode1 blocksize=0 density=0x49 compression=1 # 160 GB + compression
454 +mode2 blocksize=0 density=0x49 compression=0 # 160 GB, no ompression
455 +mode3 blocksize=0 density=0x48 compression=1 # 110 GB + compression
456 +mode4 blocksize=0 density=0x48 compression=0 # 110 GB, no ompression
460 +manufacturer="QUANTUM" model = "SDLT600" {
472 +# If your stinit supports the timeouts:
473 +timeout=3600 # 1 hour
474 +long-timeout=14400 # 4 hours
476 +# 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.
477 +mode1 blocksize=0 density=0x4a compression=1 # 300 GB + compression
478 +mode2 blocksize=0 density=0x4a compression=0 # 300 GB, no ompression
479 +mode3 blocksize=0 density=0x4a compression=1 # 300 GB + compression
480 +mode4 blocksize=0 density=0x4a compression=0 # 300 GB, no ompression
483 --- /dev/null Sun Jul 30 06:23:05 2006
484 +++ mtops.h Sun Jul 30 05:50:17 2006
486 +int tape_open(const char *file, int flags, int mode);
487 +int tape_read(int fd, void *buffer, unsigned int count);
488 +int tape_write(int fd, const void *buffer, unsigned int count);
489 +int tape_ioctl(int fd, unsigned long int request, ...);
490 +int tape_close(int fd);
492 +typedef unsigned long __kernel_daddr_t;
495 +#define ENOMEDIUM 123
499 +#define PATH_MAX 1024
501 --- /dev/null Sun Jul 30 06:23:10 2006
502 +++ mtops.c Sun Jul 30 05:46:08 2006
505 + * mtops.cpp - Emulate the Linux st (scsi tape) driver on Microsoft Windows.
507 + * Author: Robert Nelson, May, 2006 <robertn@the-nelsons.org>
511 + * Copyright (C) 2006 Kern Sibbald
513 + * This file was contributed to the Bacula project by Robert Nelson.
515 + * Robert Nelson has been granted a perpetual, worldwide,
516 + * non-exclusive, no-charge, royalty-free, irrevocable copyright
517 + * license to reproduce, prepare derivative works of, publicly
518 + * display, publicly perform, sublicense, and distribute the original
519 + * work contributed by Robert Nelson to the Bacula project in source
522 + * If you wish to license contributions from Robert Nelson
523 + * under an alternate open source license please contact
524 + * Robert Nelson <robertn@the-nelsons.org>.
527 + Copyright (C) 2006 Kern Sibbald
529 + This program is free software; you can redistribute it and/or
530 + modify it under the terms of the GNU General Public License
531 + version 2 as amended with additional clauses defined in the
532 + file LICENSE in the main source directory.
534 + This program is distributed in the hope that it will be useful,
535 + but WITHOUT ANY WARRANTY; without even the implied warranty of
536 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
537 + the file LICENSE for additional details.
544 +#include <windows.h>
549 +#include <ddk/ntddstor.h>
550 +#include <ddk/ntddscsi.h>
552 +#ifndef __CPLUS_PLUS
559 +// SCSI bus status codes.
562 +#define SCSISTAT_GOOD 0x00
563 +#define SCSISTAT_CHECK_CONDITION 0x02
564 +#define SCSISTAT_CONDITION_MET 0x04
565 +#define SCSISTAT_BUSY 0x08
566 +#define SCSISTAT_INTERMEDIATE 0x10
567 +#define SCSISTAT_INTERMEDIATE_COND_MET 0x14
568 +#define SCSISTAT_RESERVATION_CONFLICT 0x18
569 +#define SCSISTAT_COMMAND_TERMINATED 0x22
570 +#define SCSISTAT_QUEUE_FULL 0x28
572 +/* Forward referenced functions */
574 +extern char my_name[];
575 +extern int debug_level;
577 +inline SHORT Read16BitSigned(const unsigned char *pValue)
579 + return (SHORT)(((USHORT)pValue[0] << 8) | (USHORT)pValue[1]);
582 +inline USHORT Read16BitUnsigned(const unsigned char *pValue)
584 + return (((USHORT)pValue[0] << 8) | (USHORT)pValue[1]);
587 +inline LONG Read24BitSigned(const unsigned char *pValue)
589 + return ((LONG)(((ULONG)pValue[0] << 16) | ((ULONG)pValue[1] << 8) |
590 + (ULONG)pValue[2])) << 8 >> 8;
593 +inline ULONG Read24BitUnsigned(const unsigned char *pValue)
595 + return ((ULONG)pValue[0] << 16) | ((ULONG)pValue[1] << 8) | (ULONG)pValue[2];
598 +inline LONG Read32BitSigned(const unsigned char *pValue)
600 + return (LONG)(((ULONG)pValue[0] << 24) | ((ULONG)pValue[1] << 16) |
601 + ((ULONG)pValue[2] << 8) | (ULONG)pValue[3]);
604 +inline ULONG Read32BitUnsigned(const unsigned char *pValue)
606 + return (((ULONG)pValue[0] << 24) | ((ULONG)pValue[1] << 16) |
607 + ((ULONG)pValue[2] << 8) | (ULONG)pValue[3]);
610 +inline LONGLONG Read64BitSigned(const unsigned char *pValue)
612 + return (LONGLONG)(((ULONGLONG)pValue[0] << 56) | ((ULONGLONG)pValue[1] << 48) |
613 + ((ULONGLONG)pValue[2] << 40) | ((ULONGLONG)pValue[3] << 32) |
614 + ((ULONGLONG)pValue[4] << 24) | ((ULONGLONG)pValue[5] << 16) |
615 + ((ULONGLONG)pValue[6] << 8) | (ULONGLONG)pValue[7]);
618 +inline ULONGLONG Read64BitUnsigned(const unsigned char *pValue)
620 + return (LONGLONG)(((ULONGLONG)pValue[0] << 56) | ((ULONGLONG)pValue[1] << 48) |
621 + ((ULONGLONG)pValue[2] << 40) | ((ULONGLONG)pValue[3] << 32) |
622 + ((ULONGLONG)pValue[4] << 24) | ((ULONGLONG)pValue[5] << 16) |
623 + ((ULONGLONG)pValue[6] << 8) | (ULONGLONG)pValue[7]);
626 +typedef struct _TAPE_POSITION_INFO
628 + UCHAR AtPartitionStart:1;
629 + UCHAR AtPartitionEnd:1;
630 + UCHAR PartitionBlockValid:1;
631 + UCHAR FileSetValid:1;
633 + UCHAR Reserved1[3];
635 + ULONGLONG BlockNumber;
636 + ULONGLONG FileNumber;
637 + ULONGLONG SetNumber;
638 +} TAPE_POSITION_INFO, *PTAPE_POSITION_INFO;
640 +typedef struct _TAPE_HANDLE_INFO
648 + ULONG FeaturesHigh;
650 + ULONGLONG ullFileStart;
652 +} TAPE_HANDLE_INFO, *PTAPE_HANDLE_INFO;
654 +TAPE_HANDLE_INFO TapeHandleTable[] =
656 + { INVALID_HANDLE_VALUE },
657 + { INVALID_HANDLE_VALUE },
658 + { INVALID_HANDLE_VALUE },
659 + { INVALID_HANDLE_VALUE },
660 + { INVALID_HANDLE_VALUE },
661 + { INVALID_HANDLE_VALUE },
662 + { INVALID_HANDLE_VALUE },
663 + { INVALID_HANDLE_VALUE },
664 + { INVALID_HANDLE_VALUE },
665 + { INVALID_HANDLE_VALUE },
666 + { INVALID_HANDLE_VALUE },
667 + { INVALID_HANDLE_VALUE },
668 + { INVALID_HANDLE_VALUE },
669 + { INVALID_HANDLE_VALUE },
670 + { INVALID_HANDLE_VALUE },
671 + { INVALID_HANDLE_VALUE }
674 +#define NUMBER_HANDLE_ENTRIES (sizeof(TapeHandleTable) / sizeof(TapeHandleTable[0]))
676 +DWORD GetTapePositionInfo(HANDLE hDevice, PTAPE_POSITION_INFO TapePositionInfo);
677 +DWORD GetDensityBlockSize(HANDLE hDevice, DWORD *pdwDensity, DWORD *pdwBlockSize);
679 +int tape_get(int fd, struct mtget *mt_get);
680 +int tape_op(int fd, struct mtop *mt_com);
681 +int tape_pos(int fd, struct mtpos *mt_pos);
684 +tape_open(const char *file, int flags, int mode)
686 + HANDLE hDevice = INVALID_HANDLE_VALUE;
687 + char szDeviceName[256] = "\\\\.\\";
691 + for (idxFile = 0; idxFile < (int)NUMBER_HANDLE_ENTRIES; idxFile++) {
692 + if (TapeHandleTable[idxFile].OSHandle == INVALID_HANDLE_VALUE) {
697 + if (idxFile >= (int)NUMBER_HANDLE_ENTRIES) {
701 + memset(&TapeHandleTable[idxFile], 0, sizeof(TapeHandleTable[idxFile]));
703 + if (file[0] != '\\' && file[0] != '/') {
704 + strncpy(&szDeviceName[4], file, sizeof(szDeviceName) - 4);
706 + strncpy(&szDeviceName[0], file, sizeof(szDeviceName));
709 + szDeviceName[sizeof(szDeviceName) - 1] = '\0';
711 + hDevice = CreateFile(szDeviceName, FILE_ALL_ACCESS, 0, NULL, OPEN_EXISTING, 0, NULL);
713 + if (hDevice != INVALID_HANDLE_VALUE) {
714 + PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[idxFile];
716 + memset(pHandleInfo, 0, sizeof(*pHandleInfo));
718 + pHandleInfo->OSHandle = hDevice;
720 + TAPE_GET_DRIVE_PARAMETERS TapeDriveParameters;
721 + DWORD dwSize = sizeof(TapeDriveParameters);
723 + dwResult = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &dwSize, &TapeDriveParameters);
724 + if (dwResult == NO_ERROR) {
725 + pHandleInfo->FeaturesLow = TapeDriveParameters.FeaturesLow;
726 + pHandleInfo->FeaturesHigh = TapeDriveParameters.FeaturesHigh;
729 + TAPE_POSITION_INFO TapePositionInfo;
731 + dwResult = GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo);
733 + if (dwResult == NO_ERROR) {
734 + if (TapePositionInfo.AtPartitionStart || TapePositionInfo.AtPartitionEnd ||
735 + (TapePositionInfo.PartitionBlockValid && TapePositionInfo.BlockNumber == 0)) {
736 + pHandleInfo->ulFile = 0;
737 + pHandleInfo->bBlockValid = true;
738 + pHandleInfo->ullFileStart = 0;
739 + } else if (TapePositionInfo.FileSetValid) {
740 + pHandleInfo->ulFile = (ULONG)TapePositionInfo.FileNumber;
744 + DWORD dwError = GetLastError();
747 + case ERROR_FILE_NOT_FOUND:
748 + case ERROR_PATH_NOT_FOUND:
752 + case ERROR_TOO_MANY_OPEN_FILES:
757 + case ERROR_ACCESS_DENIED:
758 + case ERROR_SHARING_VIOLATION:
759 + case ERROR_LOCK_VIOLATION:
760 + case ERROR_INVALID_NAME:
764 + case ERROR_FILE_EXISTS:
768 + case ERROR_INVALID_PARAMETER:
776 + return (int)idxFile + 3;
780 +tape_read(int fd, void *buffer, unsigned int count)
782 + if (buffer == NULL) {
787 + if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) ||
788 + TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE)
794 + PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[fd - 3];
799 + bResult = ReadFile(pHandleInfo->OSHandle, buffer, count, &bytes_read, NULL);
802 + pHandleInfo->bEOF = false;
803 + pHandleInfo->bEOT = false;
804 + pHandleInfo->bEOD = false;
807 + int iReturnValue = 0;
808 + DWORD last_error = GetLastError();
810 + switch (last_error) {
812 + case ERROR_FILEMARK_DETECTED:
813 + pHandleInfo->bEOF = true;
816 + case ERROR_END_OF_MEDIA:
817 + pHandleInfo->bEOT = true;
820 + case ERROR_NO_MEDIA_IN_DRIVE:
821 + pHandleInfo->bEOF = false;
822 + pHandleInfo->bEOT = false;
823 + pHandleInfo->bEOD = false;
828 + case ERROR_NO_DATA_DETECTED:
829 + pHandleInfo->bEOD = true;
832 + case ERROR_INVALID_HANDLE:
833 + case ERROR_ACCESS_DENIED:
834 + case ERROR_LOCK_VIOLATION:
840 + pHandleInfo->bEOF = false;
841 + pHandleInfo->bEOT = false;
842 + pHandleInfo->bEOD = false;
847 + return iReturnValue;
852 +tape_write(int fd, const void *buffer, unsigned int count)
854 + if (buffer == NULL) {
859 + if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) || TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE)
865 + PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[fd - 3];
867 + DWORD bytes_written;
870 + bResult = WriteFile(pHandleInfo->OSHandle, buffer, count, &bytes_written, NULL);
873 + pHandleInfo->bEOF = false;
874 + pHandleInfo->bEOT = false;
875 + return bytes_written;
877 + DWORD last_error = GetLastError();
879 + switch (last_error) {
880 + case ERROR_END_OF_MEDIA:
881 + case ERROR_DISK_FULL:
882 + pHandleInfo->bEOT = true;
886 + case ERROR_NO_MEDIA_IN_DRIVE:
887 + pHandleInfo->bEOF = false;
888 + pHandleInfo->bEOT = false;
889 + pHandleInfo->bEOD = false;
893 + case ERROR_INVALID_HANDLE:
894 + case ERROR_ACCESS_DENIED:
899 + pHandleInfo->bEOF = false;
900 + pHandleInfo->bEOT = false;
901 + pHandleInfo->bEOD = false;
912 + if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) ||
913 + TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) {
918 + PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[fd - 3];
920 + if (!CloseHandle(pHandleInfo->OSHandle)) {
921 + pHandleInfo->OSHandle = INVALID_HANDLE_VALUE;
926 + pHandleInfo->OSHandle = INVALID_HANDLE_VALUE;
932 +tape_ioctl(int fd, unsigned long int request, ...)
937 + va_start(argp, request);
941 + result = tape_op(fd, va_arg(argp, struct mtop *));
945 + result = tape_get(fd, va_arg(argp, struct mtget *));
949 + result = tape_pos(fd, va_arg(argp, struct mtpos *));
963 +int tape_op(int fd, struct mtop *mt_com)
965 + DWORD result = NO_ERROR;
968 + if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) ||
969 + TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE)
975 + PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[fd - 3];
977 + switch (mt_com->mt_op)
981 + case MTSETDRVBUFFER:
990 + result = (DWORD)-1;
994 + for (index = 0; index < mt_com->mt_count; index++) {
995 + result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE);
996 + if (result == NO_ERROR) {
997 + pHandleInfo->ulFile++;
998 + pHandleInfo->bEOF = true;
999 + pHandleInfo->bEOT = false;
1005 + for (index = 0; index < mt_com->mt_count; index++) {
1006 + result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE);
1007 + if (result == NO_ERROR) {
1008 + pHandleInfo->ulFile--;
1009 + pHandleInfo->bBlockValid = false;
1010 + pHandleInfo->bEOD = false;
1011 + pHandleInfo->bEOF = false;
1012 + pHandleInfo->bEOT = false;
1018 + result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_RELATIVE_BLOCKS, 0, mt_com->mt_count, 0, FALSE);
1019 + if (result == NO_ERROR) {
1020 + pHandleInfo->bEOD = false;
1021 + pHandleInfo->bEOF = false;
1022 + pHandleInfo->bEOT = false;
1023 + } else if (result == ERROR_FILEMARK_DETECTED) {
1024 + pHandleInfo->bEOF = true;
1029 + result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_RELATIVE_BLOCKS, 0, -mt_com->mt_count, ~0, FALSE);
1030 + if (result == NO_ERROR) {
1031 + pHandleInfo->bEOD = false;
1032 + pHandleInfo->bEOF = false;
1033 + pHandleInfo->bEOT = false;
1034 + } else if (result == ERROR_FILEMARK_DETECTED) {
1035 + pHandleInfo->ulFile--;
1036 + pHandleInfo->bBlockValid = false;
1037 + pHandleInfo->bEOD = false;
1038 + pHandleInfo->bEOF = false;
1039 + pHandleInfo->bEOT = false;
1044 + result = WriteTapemark(pHandleInfo->OSHandle, TAPE_FILEMARKS, mt_com->mt_count, FALSE);
1045 + if (result == NO_ERROR) {
1046 + pHandleInfo->bEOF = true;
1047 + pHandleInfo->bEOT = false;
1048 + pHandleInfo->ulFile += mt_com->mt_count;
1049 + pHandleInfo->bBlockValid = true;
1050 + pHandleInfo->ullFileStart = 0;
1055 + result = SetTapePosition(pHandleInfo->OSHandle, TAPE_REWIND, 0, 0, 0, FALSE);
1056 + if (result == NO_ERROR) {
1057 + pHandleInfo->bEOD = false;
1058 + pHandleInfo->bEOF = false;
1059 + pHandleInfo->bEOT = false;
1060 + pHandleInfo->ulFile = 0;
1061 + pHandleInfo->bBlockValid = true;
1062 + pHandleInfo->ullFileStart = 0;
1067 + result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOAD, FALSE);
1068 + if (result == NO_ERROR) {
1069 + pHandleInfo->bEOD = false;
1070 + pHandleInfo->bEOF = false;
1071 + pHandleInfo->bEOT = false;
1072 + pHandleInfo->ulFile = 0;
1073 + pHandleInfo->ullFileStart = 0;
1078 + result = PrepareTape(pHandleInfo->OSHandle, TAPE_TENSION, FALSE);
1079 + if (result == NO_ERROR) {
1080 + pHandleInfo->bEOD = false;
1081 + pHandleInfo->bEOF = false;
1082 + pHandleInfo->bEOT = false;
1083 + pHandleInfo->ulFile = 0;
1084 + pHandleInfo->bBlockValid = true;
1085 + pHandleInfo->ullFileStart = 0;
1090 + for (index = 0; index < mt_com->mt_count; index++) {
1091 + result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE);
1092 + if (result == NO_ERROR) {
1093 + result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE);
1094 + pHandleInfo->bEOD = false;
1095 + pHandleInfo->bEOF = false;
1096 + pHandleInfo->bEOT = false;
1102 + for (index = 0; index < mt_com->mt_count; index++) {
1103 + result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, mt_com->mt_count, 0, FALSE);
1104 + if (result == NO_ERROR) {
1105 + result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, (DWORD)-1, ~0, FALSE);
1106 + pHandleInfo->bEOD = false;
1107 + pHandleInfo->bEOF = false;
1108 + pHandleInfo->bEOT = false;
1115 + result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE);
1116 + if (result != NO_ERROR) {
1117 + pHandleInfo->bEOF = false;
1119 + if (result == ERROR_END_OF_MEDIA) {
1120 + pHandleInfo->bEOD = true;
1121 + pHandleInfo->bEOT = true;
1124 + if (result == ERROR_NO_DATA_DETECTED) {
1125 + pHandleInfo->bEOD = true;
1126 + pHandleInfo->bEOT = false;
1131 + pHandleInfo->bEOF = true;
1132 + pHandleInfo->ulFile++;
1138 + result = EraseTape(pHandleInfo->OSHandle, TAPE_ERASE_LONG, FALSE);
1139 + if (result == NO_ERROR) {
1140 + pHandleInfo->bEOD = true;
1141 + pHandleInfo->bEOF = false;
1142 + pHandleInfo->bEOT = false;
1143 + pHandleInfo->ulFile = 0;
1144 + pHandleInfo->bBlockValid = true;
1145 + pHandleInfo->ullFileStart = 0;
1151 + TAPE_SET_MEDIA_PARAMETERS SetMediaParameters;
1153 + SetMediaParameters.BlockSize = mt_com->mt_count;
1154 + result = SetTapeParameters(pHandleInfo->OSHandle, SET_TAPE_MEDIA_INFORMATION, &SetMediaParameters);
1160 + TAPE_POSITION_INFO TapePositionInfo;
1162 + result = SetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, 0, mt_com->mt_count, 0, FALSE);
1164 + memset(&TapePositionInfo, 0, sizeof(TapePositionInfo));
1165 + DWORD dwPosResult = GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo);
1166 + if (dwPosResult == NO_ERROR && TapePositionInfo.FileSetValid) {
1167 + pHandleInfo->ulFile = (ULONG)TapePositionInfo.FileNumber;
1169 + pHandleInfo->ulFile = ~0U;
1180 + result = GetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, &partition, &offset, &offsetHi);
1181 + if (result == NO_ERROR) {
1188 + result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_SETMARKS, 0, mt_com->mt_count, 0, FALSE);
1192 + result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_SETMARKS, 0, -mt_com->mt_count, ~0, FALSE);
1196 + result = WriteTapemark(pHandleInfo->OSHandle, TAPE_SETMARKS, mt_com->mt_count, FALSE);
1200 + result = PrepareTape(pHandleInfo->OSHandle, TAPE_LOCK, FALSE);
1204 + result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOCK, FALSE);
1208 + result = PrepareTape(pHandleInfo->OSHandle, TAPE_LOAD, FALSE);
1212 + result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOAD, FALSE);
1215 + case MTCOMPRESSION:
1217 + TAPE_GET_DRIVE_PARAMETERS GetDriveParameters;
1218 + TAPE_SET_DRIVE_PARAMETERS SetDriveParameters;
1221 + size = sizeof(GetDriveParameters);
1223 + result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &size, &GetDriveParameters);
1225 + if (result == NO_ERROR)
1227 + SetDriveParameters.ECC = GetDriveParameters.ECC;
1228 + SetDriveParameters.Compression = (BOOLEAN)mt_com->mt_count;
1229 + SetDriveParameters.DataPadding = GetDriveParameters.DataPadding;
1230 + SetDriveParameters.ReportSetmarks = GetDriveParameters.ReportSetmarks;
1231 + SetDriveParameters.EOTWarningZoneSize = GetDriveParameters.EOTWarningZoneSize;
1233 + result = SetTapeParameters(pHandleInfo->OSHandle, SET_TAPE_DRIVE_INFORMATION, &SetDriveParameters);
1239 + result = SetTapePosition(pHandleInfo->OSHandle, TAPE_LOGICAL_BLOCK, mt_com->mt_count, 0, 0, FALSE);
1243 + if (mt_com->mt_count == 0)
1245 + result = CreateTapePartition(pHandleInfo->OSHandle, TAPE_INITIATOR_PARTITIONS, 1, 0);
1249 + result = CreateTapePartition(pHandleInfo->OSHandle, TAPE_INITIATOR_PARTITIONS, 2, mt_com->mt_count);
1254 + if ((result == NO_ERROR && pHandleInfo->bEOF) ||
1255 + (result == ERROR_FILEMARK_DETECTED && mt_com->mt_op == MTFSR)) {
1257 + TAPE_POSITION_INFO TapePositionInfo;
1259 + if (GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo) == NO_ERROR) {
1260 + pHandleInfo->bBlockValid = true;
1261 + pHandleInfo->ullFileStart = TapePositionInfo.BlockNumber;
1267 + case (DWORD)-1: /* Error has already been translated into errno */
1271 + case ERROR_FILEMARK_DETECTED:
1275 + case ERROR_END_OF_MEDIA:
1276 + pHandleInfo->bEOT = true;
1280 + case ERROR_NO_DATA_DETECTED:
1281 + pHandleInfo->bEOD = true;
1285 + case ERROR_NO_MEDIA_IN_DRIVE:
1286 + pHandleInfo->bEOF = false;
1287 + pHandleInfo->bEOT = false;
1288 + pHandleInfo->bEOD = false;
1289 + errno = ENOMEDIUM;
1292 + case ERROR_INVALID_HANDLE:
1293 + case ERROR_ACCESS_DENIED:
1294 + case ERROR_LOCK_VIOLATION:
1299 + return result == NO_ERROR ? 0 : -1;
1302 +int tape_get(int fd, struct mtget *mt_get)
1304 + TAPE_POSITION_INFO pos_info;
1307 + if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) ||
1308 + TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) {
1313 + PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[fd - 3];
1315 + if (GetTapePositionInfo(pHandleInfo->OSHandle, &pos_info) != NO_ERROR) {
1319 + DWORD density = 0;
1320 + DWORD blocksize = 0;
1322 + result = GetDensityBlockSize(pHandleInfo->OSHandle, &density, &blocksize);
1324 + if (result != NO_ERROR) {
1325 + TAPE_GET_DRIVE_PARAMETERS drive_params;
1328 + size = sizeof(drive_params);
1330 + result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &size, &drive_params);
1332 + if (result == NO_ERROR) {
1333 + blocksize = drive_params.DefaultBlockSize;
1337 + mt_get->mt_type = MT_ISSCSI2;
1340 + mt_get->mt_resid = pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
1342 + // Density / Block Size
1343 + mt_get->mt_dsreg = ((density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK) |
1344 + ((blocksize << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK);
1346 + mt_get->mt_gstat = 0x00010000; /* Immediate report mode.*/
1348 + if (pHandleInfo->bEOF) {
1349 + mt_get->mt_gstat |= 0x80000000; // GMT_EOF
1352 + if (pos_info.PartitionBlockValid && pos_info.BlockNumber == 0) {
1353 + mt_get->mt_gstat |= 0x40000000; // GMT_BOT
1356 + if (pHandleInfo->bEOT) {
1357 + mt_get->mt_gstat |= 0x20000000; // GMT_EOT
1360 + if (pHandleInfo->bEOD) {
1361 + mt_get->mt_gstat |= 0x08000000; // GMT_EOD
1364 + TAPE_GET_MEDIA_PARAMETERS media_params;
1365 + DWORD size = sizeof(media_params);
1367 + result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_MEDIA_INFORMATION, &size, &media_params);
1369 + if (result == NO_ERROR && media_params.WriteProtected) {
1370 + mt_get->mt_gstat |= 0x04000000; // GMT_WR_PROT
1373 + result = GetTapeStatus(pHandleInfo->OSHandle);
1375 + if (result != NO_ERROR) {
1376 + if (result == ERROR_NO_MEDIA_IN_DRIVE) {
1377 + mt_get->mt_gstat |= 0x00040000; // GMT_DR_OPEN
1380 + mt_get->mt_gstat |= 0x01000000; // GMT_ONLINE
1383 + // Recovered Error Count
1384 + mt_get->mt_erreg = 0;
1387 + mt_get->mt_fileno = (__kernel_daddr_t)pHandleInfo->ulFile;
1390 + mt_get->mt_blkno = (__kernel_daddr_t)(pHandleInfo->bBlockValid ? pos_info.BlockNumber - pHandleInfo->ullFileStart : (ULONGLONG)-1);
1395 +#define SERVICEACTION_SHORT_FORM_BLOCKID 0
1396 +#define SERVICEACTION_SHORT_FORM_VENDOR_SPECIFIC 1
1397 +#define SERVICEACTION_LONG_FORM 6
1398 +#define SERVICEACTION_EXTENDED_FORM 8
1401 +typedef struct _SCSI_READ_POSITION_SHORT_BUFFER
1412 + UCHAR Reserved1[2];
1413 + UCHAR FirstBlock[4];
1414 + UCHAR LastBlock[4];
1416 + UCHAR NumberBufferBlocks[3];
1417 + UCHAR NumberBufferBytes[4];
1418 +} SCSI_READ_POSITION_SHORT_BUFFER, *PSCSI_READ_POSITION_SHORT_BUFFER;
1420 +typedef struct _SCSI_READ_POSITION_LONG_BUFFER
1428 + UCHAR Reserved3[3];
1429 + UCHAR Partition[4];
1430 + UCHAR BlockNumber[8];
1431 + UCHAR FileNumber[8];
1432 + UCHAR SetNumber[8];
1433 +} SCSI_READ_POSITION_LONG_BUFFER, *PSCSI_READ_POSITION_LONG_BUFFER;
1435 +typedef struct _SCSI_READ_POSITION_EXTENDED_BUFFER
1446 + UCHAR AdditionalLength[2];
1448 + UCHAR NumberBufferObjects[3];
1449 + UCHAR FirstLogicalObject[8];
1450 + UCHAR LastLogicalObject[8];
1451 + UCHAR NumberBufferObjectBytes[8];
1452 +} SCSI_READ_POSITION_EXTENDED_BUFFER, *PSCSI_READ_POSITION_EXTENDED_BUFFER;
1454 +typedef union _READ_POSITION_RESULT {
1455 + SCSI_READ_POSITION_SHORT_BUFFER ShortBuffer;
1456 + SCSI_READ_POSITION_LONG_BUFFER LongBuffer;
1457 + SCSI_READ_POSITION_EXTENDED_BUFFER ExtendedBuffer;
1458 +} READ_POSITION_RESULT, *PREAD_POSITION_RESULT;
1460 +DWORD GetTapePositionInfo(HANDLE hDevice, PTAPE_POSITION_INFO TapePositionInfo)
1462 + PSCSI_PASS_THROUGH ScsiPassThrough;
1464 + DWORD dwBytesReturned;
1467 + const DWORD dwBufferSize = sizeof(SCSI_PASS_THROUGH) + sizeof(READ_POSITION_RESULT) + 28;
1469 + memset(TapePositionInfo, 0, sizeof(*TapePositionInfo));
1471 + ScsiPassThrough = (PSCSI_PASS_THROUGH)malloc(dwBufferSize);
1473 + for (pass = 0; pass < 2; pass++)
1475 + memset(ScsiPassThrough, 0, dwBufferSize);
1477 + ScsiPassThrough->Length = sizeof(SCSI_PASS_THROUGH);
1479 + ScsiPassThrough->CdbLength = 10;
1480 + ScsiPassThrough->SenseInfoLength = 28;
1481 + ScsiPassThrough->DataIn = 1;
1482 + ScsiPassThrough->DataTransferLength = sizeof(SCSI_READ_POSITION_LONG_BUFFER);
1483 + ScsiPassThrough->TimeOutValue = 1000;
1484 + ScsiPassThrough->DataBufferOffset = sizeof(SCSI_PASS_THROUGH) + 28;
1485 + ScsiPassThrough->SenseInfoOffset = sizeof(SCSI_PASS_THROUGH);
1487 + ScsiPassThrough->Cdb[0] = 0x34; // READ POSITION
1492 + ScsiPassThrough->Cdb[1] = SERVICEACTION_LONG_FORM;
1496 + ScsiPassThrough->Cdb[1] = SERVICEACTION_SHORT_FORM_BLOCKID;
1500 + bResult = DeviceIoControl( hDevice,
1501 + IOCTL_SCSI_PASS_THROUGH,
1502 + ScsiPassThrough, sizeof(SCSI_PASS_THROUGH),
1503 + ScsiPassThrough, dwBufferSize,
1507 + if (bResult && dwBytesReturned >= (offsetof(SCSI_PASS_THROUGH, ScsiStatus) + sizeof(ScsiPassThrough->ScsiStatus))) {
1508 + if (ScsiPassThrough->ScsiStatus == SCSISTAT_GOOD) {
1509 + PREAD_POSITION_RESULT pPosResult = (PREAD_POSITION_RESULT)((PUCHAR)ScsiPassThrough + ScsiPassThrough->DataBufferOffset);
1513 + case 0: // SERVICEACTION_LONG_FORM
1515 + TapePositionInfo->AtPartitionStart = pPosResult->LongBuffer.BOP;
1516 + TapePositionInfo->AtPartitionEnd = pPosResult->LongBuffer.EOP;
1518 + if (!TapePositionInfo->PartitionBlockValid) {
1519 + TapePositionInfo->PartitionBlockValid = !pPosResult->LongBuffer.BPU;
1521 + if (TapePositionInfo->PartitionBlockValid) {
1522 + TapePositionInfo->Partition = Read32BitUnsigned(pPosResult->LongBuffer.Partition);
1523 + TapePositionInfo->BlockNumber = Read64BitUnsigned(pPosResult->LongBuffer.BlockNumber);
1527 + TapePositionInfo->FileSetValid = !pPosResult->LongBuffer.MPU;
1528 + if (TapePositionInfo->FileSetValid) {
1529 + TapePositionInfo->FileNumber = Read64BitUnsigned(pPosResult->LongBuffer.FileNumber);
1530 + TapePositionInfo->SetNumber = Read64BitUnsigned(pPosResult->LongBuffer.SetNumber);
1535 + case 1: // SERVICEACTION_SHORT_FORM_BLOCKID
1537 + // pPosResult->ShortBuffer.PERR;
1538 + // pPosResult->ShortBuffer.BYCU;
1539 + // pPosResult->ShortBuffer.BCU;
1540 + TapePositionInfo->AtPartitionStart = pPosResult->ShortBuffer.BOP;
1541 + TapePositionInfo->AtPartitionEnd = pPosResult->ShortBuffer.EOP;
1543 + if (!TapePositionInfo->PartitionBlockValid) {
1544 + TapePositionInfo->PartitionBlockValid = !pPosResult->ShortBuffer.BPU;
1546 + if (TapePositionInfo->PartitionBlockValid) {
1547 + TapePositionInfo->Partition = pPosResult->ShortBuffer.Partition;
1548 + TapePositionInfo->BlockNumber = Read32BitUnsigned(pPosResult->ShortBuffer.FirstBlock);
1551 + // Read32BitsUnsigned(pPosResult->ShortBuffer.LastBlock);
1552 + // Read24BitsUnsigned(pPosResult->ShortBuffer.NumberBufferBlocks);
1553 + // Read32BitsUnsigned(pPosResult->ShortBuffer.NumberBufferBytes);
1560 + free(ScsiPassThrough);
1565 +DWORD GetDensityBlockSize(HANDLE hDevice, DWORD *pdwDensity, DWORD *pdwBlockSize)
1567 + DWORD dwBufferSize = sizeof(GET_MEDIA_TYPES) + 5 * sizeof(DEVICE_MEDIA_INFO);
1568 + GET_MEDIA_TYPES * pGetMediaTypes = (GET_MEDIA_TYPES *)malloc(dwBufferSize);
1573 + if (pGetMediaTypes == NULL) {
1574 + return ERROR_OUTOFMEMORY;
1578 + DWORD dwBytesReturned;
1580 + bResult = DeviceIoControl( hDevice,
1581 + IOCTL_STORAGE_GET_MEDIA_TYPES_EX,
1583 + (LPVOID)pGetMediaTypes, dwBufferSize,
1588 + dwResult = GetLastError();
1590 + if (dwResult != ERROR_INSUFFICIENT_BUFFER) {
1591 + free(pGetMediaTypes);
1595 + dwBufferSize += 6 * sizeof(DEVICE_MEDIA_INFO);
1597 + GET_MEDIA_TYPES * pNewBuffer = (GET_MEDIA_TYPES *)realloc(pGetMediaTypes, dwBufferSize);
1599 + if (pNewBuffer != pGetMediaTypes) {
1600 + free(pGetMediaTypes);
1602 + if (pNewBuffer == NULL) {
1603 + return ERROR_OUTOFMEMORY;
1606 + pGetMediaTypes = pNewBuffer;
1609 + } while (!bResult);
1611 + if (pGetMediaTypes->DeviceType != FILE_DEVICE_TAPE) {
1612 + free(pGetMediaTypes);
1613 + return ERROR_BAD_DEVICE;
1616 + for (idxMedia = 0; idxMedia < pGetMediaTypes->MediaInfoCount; idxMedia++) {
1618 + if (pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.MediaCharacteristics & MEDIA_CURRENTLY_MOUNTED) {
1620 + if (pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.BusType == BusTypeScsi) {
1621 + *pdwDensity = pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.BusSpecificData.ScsiInformation.DensityCode;
1626 + *pdwBlockSize = pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.CurrentBlockSize;
1628 + free(pGetMediaTypes);
1634 + free(pGetMediaTypes);
1636 + return ERROR_NO_MEDIA_IN_DRIVE;
1639 +int tape_pos(int fd, struct mtpos *mt_pos)
1646 + if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) ||
1647 + TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) {
1652 + PTAPE_HANDLE_INFO pHandleInfo = &TapeHandleTable[fd - 3];
1654 + result = GetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, &partition, &offset, &offsetHi);
1655 + if (result == NO_ERROR) {
1656 + mt_pos->mt_blkno = offset;