]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/patches/mt.patch
Make build-win32-cross-tools work on FreeBSD.
[bacula/bacula] / bacula / src / win32 / patches / mt.patch
1 Only in .: .svn
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
5 @@ -1,29 +1,27 @@
6 +CC=    mingw32-gcc
7  CFLAGS=  -Wall -O2
8 -SBINDIR= /sbin
9 -BINDIR=  /bin
10 -MANDIR= /usr/share/man
11 +PREFIX=
12 +SBINDIR= $(PREFIX)/sbin
13 +BINDIR=  $(PREFIX)/bin
14 +MANDIR= $(PREFIX)/man
15  
16 -all:   mt stinit
17 +all:   mt.exe
18  
19 -mt:    mt.c
20 -       $(CC) $(CFLAGS) -o mt mt.c
21 +mt.exe:        mt.c
22 +       $(CC) $(CFLAGS) -o mt.exe mt.c mtops.c
23  
24 -stinit:        stinit.c
25 +stinit.exe:    stinit.c
26         $(CC) $(CFLAGS) -o stinit stinit.c
27  
28 -install: mt stinit
29 -       install -s mt $(BINDIR)
30 +install: mt.exe
31 +       install 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)
39  
40  dist:  clean
41         (mydir=`basename \`pwd\``;\
42         cd .. && tar cvvf - $$mydir | gzip -9 > $${mydir}.tar.gz)
43  
44  clean:
45 -       rm -f *~ \#*\# *.o mt stinit
46 +       rm -f *~ \#*\# *.o mt.exe stinit.exe
47 Only in .: compat.h
48 Only in .: mt
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
52 @@ -48,20 +48,22 @@
53  files.
54  The tape is positioned on the first block of the next file.
55  .IP fsfm
56 -Forward space
57 +Forward space past
58  .I count
59 -files.
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.
64  .IP bsf
65  Backward space
66  .I count
67  files.
68  The tape is positioned on the last block of the previous file.
69  .IP bsfm
70 -Backward space
71 +Backward space past
72  .I count
73 -files.
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.
78  .IP asf
79  The tape is positioned at the beginning of the
80  .I count
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
84 @@ -11,6 +11,12 @@
85         Last Modified: Sun Aug 21 21:48:06 2005 by kai.makisara
86  */
87  
88 +#include <windows.h>
89 +#include <winioctl.h>
90 +#include <winsock.h>
91 +
92 +#define O_NONBLOCK   0
93 +
94  #include <stdio.h>
95  #include <unistd.h>
96  #include <stdlib.h>
97 @@ -19,15 +25,17 @@
98  #include <errno.h>
99  #include <fcntl.h>
100  #include <sys/types.h>
101 -#include <sys/ioctl.h>
102  
103 +#include "mtops.h"
104  #include "mtio.h"
105  
106 +#define ioctl  tape_ioctl
107 +
108  #ifndef DEFTAPE
109 -#define DEFTAPE "/dev/tape"     /* default tape device */
110 +#define DEFTAPE "Tape0"     /* default tape device */
111  #endif /* DEFTAPE */
112  
113 -#define VERSION "0.9b"
114 +#define VERSION "0.9b-bacula"
115  
116  typedef int (* cmdfunc)(/* int, struct cmdef_tr *, int, char ** */);
117  
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},
122 +#if 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},
129 +#endif
130      { "densities",     0, print_densities,     0, NO_FD,     NO_ARGS,
131      0 },
132      { "setpartition",  MTSETPART, do_standard, 0, FD_RDONLY, ONE_ARG,
133 @@ -211,13 +221,19 @@
134      {0x30, "AIT-1 or MLR3"},
135      {0x31, "AIT-2"},
136      {0x32, "AIT-3"},
137 -    {0x33, "SLR6"},
138 +    {0x33, "AIT-4 or SLR6"},
139      {0x34, "SLR100"},
140 +    {0x38, "AIT-E Turbo"},
141 +    {0x39, "AIT-1 Turbo"},
142 +    {0x3A, "AIT-2 Turbo"},
143 +    {0x3B, "AIT-3Ex"},
144      {0x40, "DLT1 40 GB, or Ultrium"},
145      {0x41, "DLT 40GB, or Ultrium2"},
146      {0x42, "LTO-2"},
147      {0x45, "QIC-3095-MC (TR-4)"},
148      {0x47, "TR-5"},
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"},
158 +#if 0
159      {"no-wait",       MT_ST_NOWAIT,        "immediate mode for rewind, etc."},
160 +#endif
161  #ifdef MT_ST_SYSV
162      {"sysv",         MT_ST_SYSV,          "enable the SystemV semantics"},
163  #endif
164 +#if 0
165      {"cleaning",      MT_ST_SET_CLN,      "set the cleaning bit location and mask"},
166 +#endif
167      {NULL, 0}};
168  
169  static char *tape_name;   /* The tape name for messages */
170  
171  
172 -\f      int
173 +int
174  main(int argc, char **argv)
175  {
176 -    int mtfd, cmd_code, i, argn, len, oflags;
177 +    int mtfd, cmd_code, i, argn, oflags;
178 +    unsigned int len;
179      char *cmdstr;
180      cmdef_tr *comp, *comp2;
181  
182 @@ -344,7 +365,7 @@
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) {
188             perror(tape_name);
189             exit(1);
190         }
191 @@ -368,7 +389,7 @@
192      }
193  
194      if (mtfd >= 0)
195 -       close(mtfd);
196 +       tape_close(mtfd);
197      return i;
198  }
199  
200 @@ -409,9 +430,9 @@
201  do_standard(int mtfd, cmdef_tr *cmd, int argc, char **argv)
202  {
203      struct mtop mt_com;
204 -    char *endp;
205 +    char *endp = NULL;
206  
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) {
211         if (*endp == 'k')
212 @@ -464,7 +485,8 @@
213         static int
214  do_options(int mtfd, cmdef_tr *cmd, int argc, char **argv)
215  {
216 -    int i, an, len;
217 +    int i, an;
218 +    unsigned int len;
219      struct mtop mt_com;
220  
221      mt_com.mt_op = MTSETDRVBUFFER;
222 @@ -596,8 +618,10 @@
223         type = "SCSI 1";
224      else if (status.mt_type == MT_ISSCSI2)
225         type = "SCSI 2";
226 +#if 0
227      else if (status.mt_type == MT_ISONSTREAM_SC)
228         type = "OnStream SC-, DI-, DP-, or USB";
229 +#endif
230      else
231         type = NULL;
232      if (type == NULL) {
233 @@ -607,7 +631,7 @@
234             printf("IDE-Tape (type code 0) ?\n");
235         else
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 @@
243      else {
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));
249         else
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
258 +#if 0
259 +            || status.mt_type == MT_ISONSTREAM_SC
260 +#endif
261 +            ) {
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++)
265 @@ -666,8 +693,10 @@
266         printf(" DR_OPEN");       
267      if (GMT_IM_REP_EN(status.mt_gstat))
268         printf(" IM_REP_EN");
269 +#if 0
270      if (GMT_CLN(status.mt_gstat))
271         printf(" CLN");
272 +#endif
273      printf("\n");
274      return 0;
275  }
276 Only in .: mt.exe
277 Only in .: mt.patch
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
281 @@ -8,9 +8,7 @@
282  #ifndef _LINUX_MTIO_H
283  #define _LINUX_MTIO_H
284  
285 -#include <linux/types.h>
286 -#include <linux/ioctl.h>
287 -#include <linux/qic117.h>
288 +#include <sys/types.h>
289  
290  /*
291   * Structures and definitions for mag tape io control commands
292 @@ -150,6 +148,7 @@
293  };
294  
295  
296 +#ifdef USE_QIC02
297  /* structure for MTIOCGETCONFIG/MTIOCSETCONFIG primarily intended
298   * as an interim solution for QIC-02 until DDI is fully implemented.
299   */
300 @@ -281,6 +280,7 @@
301                                       * command
302                                       */
303  };
304 +#endif
305  
306  /* mag tape io control commands */
307  #define        MTIOCTOP        _IOW('m', 1, struct mtop)       /* do a mag tape op */
308 Only in .: mtops.c
309 Only in .: mtops.h
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
313 @@ -56,3 +56,169 @@
314  mode3 blocksize=0 density=1   #  800 bpi
315  }
316  
317 +# DLT2000 / 2000XT
318 +manufacturer="QUANTUM" model = "DLT2000" {
319 +scsi2logical=1
320 +can-bsr
321 +auto-lock=0
322 +two-fms=0
323 +drive-buffering=1
324 +buffer-writes
325 +read-ahead=1
326 +async-writes=1
327 +can-partitions=0
328 +fast-mteom=1
329 +#
330 +# If your stinit supports the timeouts:
331 +timeout=3600 # 1 hour
332 +long-timeout=14400 # 4 hours
333 +#
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
338 +}
339 +
340 +# DLT4000
341 +manufacturer="QUANTUM" model = "DLT4000" {
342 +scsi2logical=1
343 +can-bsr
344 +auto-lock=0
345 +two-fms=0
346 +drive-buffering=1
347 +buffer-writes
348 +read-ahead=1
349 +async-writes=1
350 +can-partitions=0
351 +fast-mteom=1
352 +#
353 +# If your stinit supports the timeouts:
354 +timeout=3600 # 1 hour
355 +long-timeout=14400 # 4 hours
356 +#
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
362 +}
363 +
364 +# DLT7000
365 +manufacturer="QUANTUM" model = "DLT7000" {
366 +scsi2logical=1
367 +can-bsr
368 +auto-lock=0
369 +two-fms=0
370 +drive-buffering=1
371 +buffer-writes
372 +read-ahead=1
373 +async-writes=1
374 +can-partitions=0
375 +fast-mteom=1
376 +#
377 +# If your stinit supports the timeouts:
378 +timeout=3600 # 1 hour
379 +long-timeout=14400 # 4 hours
380 +#
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)
386 +}
387 +
388 +# DLT8000
389 +manufacturer="QUANTUM" model = "DLT8000" {
390 +scsi2logical=1
391 +can-bsr=1
392 +auto-lock=0
393 +two-fms=0
394 +drive-buffering=1
395 +buffer-writes
396 +read-ahead=1
397 +async-writes=1
398 +can-partitions=0
399 +fast-mteom=1
400 +#
401 +# If your stinit supports the timeouts:
402 +timeout=3600 # 1 hour
403 +long-timeout=14400 # 4 hours
404 +#
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)
410 +}
411 +
412 +
413 +# SDLT220
414 +manufacturer="QUANTUM" model = "SuperDLT1" {
415 +scsi2logical=1
416 +can-bsr=1
417 +auto-lock=0
418 +two-fms=0
419 +drive-buffering=1
420 +buffer-writes
421 +read-ahead=1
422 +async-writes=1
423 +can-partitions=0
424 +fast-mteom=1
425 +#
426 +# If your stinit supports the timeouts:
427 +timeout=3600 # 1 hour
428 +long-timeout=14400 # 4 hours
429 +#
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
433 +}
434 +
435 +# SDLT320
436 +manufacturer="QUANTUM" model = "SDLT320" {
437 +scsi2logical=1
438 +can-bsr=1
439 +auto-lock=0
440 +two-fms=0
441 +drive-buffering=1
442 +buffer-writes
443 +read-ahead=1
444 +async-writes=1
445 +can-partitions=0
446 +fast-mteom=1
447 +#
448 +# If your stinit supports the timeouts:
449 +timeout=3600 # 1 hour
450 +long-timeout=14400 # 4 hours
451 +#
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
457 +}
458 +
459 +# SDLT600
460 +manufacturer="QUANTUM" model = "SDLT600" {
461 +scsi2logical=1
462 +can-bsr=1
463 +auto-lock=0
464 +two-fms=0
465 +drive-buffering=1
466 +buffer-writes
467 +read-ahead=1
468 +async-writes=1
469 +can-partitions=0
470 +fast-mteom=1
471 +#
472 +# If your stinit supports the timeouts:
473 +timeout=3600 # 1 hour
474 +long-timeout=14400 # 4 hours
475 +#
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
481 +}
482 +
483 --- /dev/null   Sun Jul 30 06:23:05 2006
484 +++ mtops.h     Sun Jul 30 05:50:17 2006
485 @@ -0,0 +1,15 @@
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);
491 +
492 +typedef unsigned long  __kernel_daddr_t;
493 +
494 +#ifndef ENOMEDIUM
495 +#define ENOMEDIUM      123
496 +#endif
497 +
498 +#ifndef PATH_MAX
499 +#define PATH_MAX       1024
500 +#endif
501 --- /dev/null   Sun Jul 30 06:23:10 2006
502 +++ mtops.c     Sun Jul 30 05:46:08 2006
503 @@ -0,0 +1,1158 @@
504 +/*
505 + * mtops.cpp - Emulate the Linux st (scsi tape) driver on Microsoft Windows.
506 + *
507 + * Author: Robert Nelson, May, 2006 <robertn@the-nelsons.org>
508 + *
509 + * Version $Id$
510 + *
511 + * Copyright (C) 2006 Kern Sibbald
512 + *
513 + * This file was contributed to the Bacula project by Robert Nelson.
514 + *
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 
520 + * or object form.
521 + *
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>.
525 + */
526 +/*
527 +   Copyright (C) 2006 Kern Sibbald
528 +
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.
533 +
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.
538 +
539 + */
540 +
541 +#include <stdarg.h>
542 +#include <stddef.h>
543 +
544 +#include <windows.h>
545 +#include <errno.h>
546 +
547 +#include "mtops.h"
548 +#include "mtio.h"
549 +#include <ddk/ntddstor.h>
550 +#include <ddk/ntddscsi.h>
551 +
552 +#ifndef __CPLUS_PLUS
553 +typedef char bool;
554 +#define true 1
555 +#define false 0
556 +#endif
557 +
558 +//
559 +// SCSI bus status codes.
560 +//
561 +
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
571 +
572 +/* Forward referenced functions */
573 +
574 +extern char my_name[];
575 +extern int debug_level;
576 +
577 +inline   SHORT  Read16BitSigned(const unsigned char *pValue)
578 +{
579 +   return (SHORT)(((USHORT)pValue[0] << 8) | (USHORT)pValue[1]);
580 +}
581 +
582 +inline   USHORT  Read16BitUnsigned(const unsigned char *pValue)
583 +{
584 +   return (((USHORT)pValue[0] << 8) | (USHORT)pValue[1]);
585 +}
586 +
587 +inline   LONG  Read24BitSigned(const unsigned char *pValue)
588 +{
589 +   return ((LONG)(((ULONG)pValue[0] << 16) | ((ULONG)pValue[1] << 8) |
590 +                   (ULONG)pValue[2])) << 8 >> 8;
591 +}
592 +
593 +inline   ULONG  Read24BitUnsigned(const unsigned char *pValue)
594 +{
595 +   return ((ULONG)pValue[0] << 16) | ((ULONG)pValue[1] << 8) | (ULONG)pValue[2];
596 +}
597 +
598 +inline   LONG  Read32BitSigned(const unsigned char *pValue)
599 +{
600 +   return (LONG)(((ULONG)pValue[0] << 24) | ((ULONG)pValue[1] << 16) |
601 +                 ((ULONG)pValue[2] << 8) |   (ULONG)pValue[3]);
602 +}
603 +
604 +inline   ULONG  Read32BitUnsigned(const unsigned char *pValue)
605 +{
606 +   return (((ULONG)pValue[0] << 24) | ((ULONG)pValue[1] << 16) |
607 +           ((ULONG)pValue[2] << 8) | (ULONG)pValue[3]);
608 +}
609 +
610 +inline   LONGLONG  Read64BitSigned(const unsigned char *pValue)
611 +{
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]);
616 +}
617 +
618 +inline   ULONGLONG  Read64BitUnsigned(const unsigned char *pValue)
619 +{
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]);
624 +}
625 +
626 +typedef  struct   _TAPE_POSITION_INFO
627 +{
628 +   UCHAR       AtPartitionStart:1;
629 +   UCHAR       AtPartitionEnd:1;
630 +   UCHAR       PartitionBlockValid:1;
631 +   UCHAR       FileSetValid:1;
632 +   UCHAR       :4;
633 +   UCHAR       Reserved1[3];
634 +   ULONG       Partition;
635 +   ULONGLONG   BlockNumber;
636 +   ULONGLONG   FileNumber;
637 +   ULONGLONG   SetNumber;
638 +}  TAPE_POSITION_INFO, *PTAPE_POSITION_INFO;
639 +
640 +typedef  struct   _TAPE_HANDLE_INFO
641 +{
642 +   HANDLE      OSHandle;
643 +   bool        bEOD;
644 +   bool        bEOF;
645 +   bool        bEOT;
646 +   bool        bBlockValid;
647 +   ULONG       FeaturesLow;
648 +   ULONG       FeaturesHigh;
649 +   ULONG       ulFile;
650 +   ULONGLONG   ullFileStart;
651 +
652 +}  TAPE_HANDLE_INFO, *PTAPE_HANDLE_INFO;
653 +
654 +TAPE_HANDLE_INFO TapeHandleTable[] =
655 +{
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 }
672 +};
673 +
674 +#define  NUMBER_HANDLE_ENTRIES      (sizeof(TapeHandleTable) / sizeof(TapeHandleTable[0]))
675 +
676 +DWORD GetTapePositionInfo(HANDLE hDevice, PTAPE_POSITION_INFO TapePositionInfo);
677 +DWORD GetDensityBlockSize(HANDLE hDevice, DWORD *pdwDensity, DWORD *pdwBlockSize);
678 +
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);
682 +
683 +int
684 +tape_open(const char *file, int flags, int mode)
685 +{
686 +   HANDLE hDevice = INVALID_HANDLE_VALUE;
687 +   char szDeviceName[256] = "\\\\.\\";
688 +   int  idxFile;
689 +   DWORD dwResult;
690 +
691 +   for (idxFile = 0; idxFile < (int)NUMBER_HANDLE_ENTRIES; idxFile++) {
692 +      if (TapeHandleTable[idxFile].OSHandle == INVALID_HANDLE_VALUE) {
693 +         break;
694 +      }
695 +   }
696 +
697 +   if (idxFile >= (int)NUMBER_HANDLE_ENTRIES) {
698 +      return EMFILE;
699 +   }
700 +
701 +   memset(&TapeHandleTable[idxFile], 0, sizeof(TapeHandleTable[idxFile]));
702 +
703 +   if (file[0] != '\\' && file[0] != '/') {
704 +       strncpy(&szDeviceName[4], file, sizeof(szDeviceName) - 4);
705 +   } else {
706 +       strncpy(&szDeviceName[0], file, sizeof(szDeviceName));
707 +   }
708 +
709 +   szDeviceName[sizeof(szDeviceName) - 1] = '\0';
710 +
711 +   hDevice = CreateFile(szDeviceName, FILE_ALL_ACCESS, 0, NULL, OPEN_EXISTING, 0, NULL);
712 +
713 +   if (hDevice != INVALID_HANDLE_VALUE) {
714 +      PTAPE_HANDLE_INFO    pHandleInfo = &TapeHandleTable[idxFile];
715 +
716 +      memset(pHandleInfo, 0, sizeof(*pHandleInfo));
717 +
718 +      pHandleInfo->OSHandle = hDevice;
719 +
720 +      TAPE_GET_DRIVE_PARAMETERS  TapeDriveParameters;
721 +      DWORD    dwSize = sizeof(TapeDriveParameters);
722 +
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;
727 +      }
728 +
729 +      TAPE_POSITION_INFO TapePositionInfo;
730 +
731 +      dwResult =  GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo);
732 +
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;
741 +         }
742 +      }
743 +   } else {
744 +      DWORD dwError = GetLastError();
745 +
746 +      switch (dwError) {
747 +      case ERROR_FILE_NOT_FOUND:
748 +      case ERROR_PATH_NOT_FOUND:
749 +         errno = ENOENT;
750 +         break;
751 +
752 +      case ERROR_TOO_MANY_OPEN_FILES:
753 +         errno = EMFILE;
754 +         break;
755 +
756 +      default:
757 +      case ERROR_ACCESS_DENIED:
758 +      case ERROR_SHARING_VIOLATION:
759 +      case ERROR_LOCK_VIOLATION:
760 +      case ERROR_INVALID_NAME:
761 +         errno = EACCES;
762 +         break;
763 +
764 +      case ERROR_FILE_EXISTS:
765 +         errno = EEXIST;
766 +         break;
767 +
768 +      case ERROR_INVALID_PARAMETER:
769 +         errno = EINVAL;
770 +         break;
771 +      }
772 +
773 +      return(int) -1;
774 +   }
775 +
776 +   return (int)idxFile + 3;
777 +}
778 +
779 +int
780 +tape_read(int fd, void *buffer, unsigned int count)
781 +{
782 +   if (buffer == NULL) {
783 +      errno = EINVAL;
784 +      return -1;
785 +   }
786 +
787 +   if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) || 
788 +       TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE)
789 +   {
790 +      errno = EBADF;
791 +      return -1;
792 +   }
793 +
794 +   PTAPE_HANDLE_INFO    pHandleInfo = &TapeHandleTable[fd - 3];
795 +
796 +   DWORD bytes_read;
797 +   BOOL bResult;
798 +
799 +   bResult = ReadFile(pHandleInfo->OSHandle, buffer, count, &bytes_read, NULL);
800 +
801 +   if (bResult) {
802 +      pHandleInfo->bEOF = false;
803 +      pHandleInfo->bEOT = false;
804 +      pHandleInfo->bEOD = false;
805 +      return bytes_read;
806 +   } else {
807 +      int iReturnValue = 0;
808 +      DWORD last_error = GetLastError();
809 +
810 +      switch (last_error) {
811 +
812 +      case ERROR_FILEMARK_DETECTED:
813 +         pHandleInfo->bEOF = true;
814 +         break;
815 +
816 +      case ERROR_END_OF_MEDIA:
817 +         pHandleInfo->bEOT = true;
818 +         break;
819 +
820 +      case ERROR_NO_MEDIA_IN_DRIVE:
821 +         pHandleInfo->bEOF = false;
822 +         pHandleInfo->bEOT = false;
823 +         pHandleInfo->bEOD = false;
824 +         errno = ENOMEDIUM;
825 +         iReturnValue = -1;
826 +         break;
827 +
828 +      case ERROR_NO_DATA_DETECTED:
829 +         pHandleInfo->bEOD = true;
830 +         break;
831 +
832 +      case ERROR_INVALID_HANDLE:
833 +      case ERROR_ACCESS_DENIED:
834 +      case ERROR_LOCK_VIOLATION:
835 +         errno = EBADF;
836 +         iReturnValue = -1;
837 +         break;
838 +
839 +      default:
840 +         pHandleInfo->bEOF = false;
841 +         pHandleInfo->bEOT = false;
842 +         pHandleInfo->bEOD = false;
843 +         errno = EIO;
844 +         iReturnValue = -1;
845 +      }
846 +
847 +      return iReturnValue;
848 +   }
849 +}
850 +
851 +int
852 +tape_write(int fd, const void *buffer, unsigned int count)
853 +{
854 +   if (buffer == NULL) {
855 +      errno = EINVAL;
856 +      return -1;
857 +   }
858 +
859 +   if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) || TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE)
860 +   {
861 +      errno = EBADF;
862 +      return -1;
863 +   }
864 +
865 +   PTAPE_HANDLE_INFO    pHandleInfo = &TapeHandleTable[fd - 3];
866 +
867 +   DWORD bytes_written;
868 +   BOOL bResult;
869 +
870 +   bResult = WriteFile(pHandleInfo->OSHandle, buffer, count, &bytes_written, NULL);
871 +
872 +   if (bResult) {
873 +      pHandleInfo->bEOF = false;
874 +      pHandleInfo->bEOT = false;
875 +      return bytes_written;
876 +   } else {
877 +      DWORD last_error = GetLastError();
878 +
879 +      switch (last_error) {
880 +      case ERROR_END_OF_MEDIA:
881 +      case ERROR_DISK_FULL:
882 +         pHandleInfo->bEOT = true;
883 +         errno = ENOSPC;
884 +         break;
885 +
886 +      case ERROR_NO_MEDIA_IN_DRIVE:
887 +         pHandleInfo->bEOF = false;
888 +         pHandleInfo->bEOT = false;
889 +         pHandleInfo->bEOD = false;
890 +         errno = ENOMEDIUM;
891 +         break;
892 +
893 +      case ERROR_INVALID_HANDLE:
894 +      case ERROR_ACCESS_DENIED:
895 +         errno = EBADF;
896 +         break;
897 +
898 +      default:
899 +         pHandleInfo->bEOF = false;
900 +         pHandleInfo->bEOT = false;
901 +         pHandleInfo->bEOD = false;
902 +         errno = EIO;
903 +         break;
904 +      }
905 +      return -1;
906 +   }
907 +}
908 +
909 +int
910 +tape_close(int fd)
911 +{
912 +   if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) || 
913 +      TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) {
914 +      errno = EBADF;
915 +      return -1;
916 +   }
917 +
918 +   PTAPE_HANDLE_INFO    pHandleInfo = &TapeHandleTable[fd - 3];
919 +
920 +   if (!CloseHandle(pHandleInfo->OSHandle)) {
921 +      pHandleInfo->OSHandle = INVALID_HANDLE_VALUE;
922 +      errno = EBADF;
923 +      return -1;
924 +   }
925 +
926 +   pHandleInfo->OSHandle = INVALID_HANDLE_VALUE;
927 +
928 +   return 0;
929 +}
930 +
931 +int
932 +tape_ioctl(int fd, unsigned long int request, ...)
933 +{
934 +   va_list argp;
935 +   int result;
936 +
937 +   va_start(argp, request);
938 +
939 +   switch (request) {
940 +   case MTIOCTOP:
941 +      result = tape_op(fd, va_arg(argp, struct mtop *));
942 +      break;
943 +
944 +   case MTIOCGET:
945 +      result = tape_get(fd, va_arg(argp, struct mtget *));
946 +      break;
947 +
948 +   case MTIOCPOS:
949 +      result = tape_pos(fd, va_arg(argp, struct mtpos *));
950 +      break;
951 +
952 +   default:
953 +      errno = ENOTTY;
954 +      result = -1;
955 +      break;
956 +   }
957 +
958 +   va_end(argp);
959 +
960 +   return result;
961 +}
962 +
963 +int tape_op(int fd, struct mtop *mt_com)
964 +{
965 +   DWORD result = NO_ERROR;
966 +   int   index;
967 +
968 +   if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) || 
969 +       TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE)
970 +   {
971 +      errno = EBADF;
972 +      return -1;
973 +   }
974 +
975 +   PTAPE_HANDLE_INFO    pHandleInfo = &TapeHandleTable[fd - 3];
976 +
977 +   switch (mt_com->mt_op)
978 +   {
979 +   case MTRESET:
980 +   case MTNOP:
981 +   case MTSETDRVBUFFER:
982 +      break;
983 +
984 +   default:
985 +   case MTRAS1:
986 +   case MTRAS2:
987 +   case MTRAS3:
988 +   case MTSETDENSITY:
989 +      errno = ENOTTY;
990 +      result = (DWORD)-1;
991 +      break;
992 +
993 +   case MTFSF:
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;
1000 +         }
1001 +      }
1002 +      break;
1003 +
1004 +   case MTBSF:
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;
1013 +         }
1014 +      }
1015 +      break;
1016 +
1017 +   case MTFSR:
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;
1025 +      }
1026 +      break;
1027 +
1028 +   case MTBSR:
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;
1040 +      }
1041 +      break;
1042 +
1043 +   case MTWEOF:
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;
1051 +      }
1052 +      break;
1053 +
1054 +   case MTREW:
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;
1063 +      }
1064 +      break;
1065 +
1066 +   case MTOFFL:
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;
1074 +      }
1075 +      break;
1076 +
1077 +   case MTRETEN:
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;
1086 +      }
1087 +      break;
1088 +
1089 +   case MTBSFM:
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;
1097 +         }
1098 +      }
1099 +      break;
1100 +
1101 +   case MTFSFM:
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;
1109 +         }
1110 +      }
1111 +      break;
1112 +
1113 +   case MTEOM:
1114 +      for ( ; ; ) {
1115 +         result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_FILEMARKS, 0, 1, 0, FALSE);
1116 +         if (result != NO_ERROR) {
1117 +            pHandleInfo->bEOF = false;
1118 +
1119 +            if (result == ERROR_END_OF_MEDIA) {
1120 +               pHandleInfo->bEOD = true;
1121 +               pHandleInfo->bEOT = true;
1122 +               return 0;
1123 +            }
1124 +            if (result == ERROR_NO_DATA_DETECTED) {
1125 +               pHandleInfo->bEOD = true;
1126 +               pHandleInfo->bEOT = false;
1127 +               return 0;
1128 +            }
1129 +            break;
1130 +         } else {
1131 +            pHandleInfo->bEOF = true;
1132 +            pHandleInfo->ulFile++;
1133 +         }
1134 +      }
1135 +      break;
1136 +
1137 +   case MTERASE:
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;
1146 +      }
1147 +      break;
1148 +
1149 +   case MTSETBLK:
1150 +      {
1151 +         TAPE_SET_MEDIA_PARAMETERS  SetMediaParameters;
1152 +
1153 +         SetMediaParameters.BlockSize = mt_com->mt_count;
1154 +         result = SetTapeParameters(pHandleInfo->OSHandle, SET_TAPE_MEDIA_INFORMATION, &SetMediaParameters);
1155 +      }
1156 +      break;
1157 +
1158 +   case MTSEEK:
1159 +      {
1160 +         TAPE_POSITION_INFO   TapePositionInfo;
1161 +
1162 +         result = SetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, 0, mt_com->mt_count, 0, FALSE);
1163 +
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;
1168 +         } else {
1169 +            pHandleInfo->ulFile = ~0U;
1170 +         }
1171 +      }
1172 +      break;
1173 +
1174 +   case MTTELL:
1175 +      {
1176 +         DWORD partition;
1177 +         DWORD offset;
1178 +         DWORD offsetHi;
1179 +
1180 +         result = GetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, &partition, &offset, &offsetHi);
1181 +         if (result == NO_ERROR) {
1182 +            return offset;
1183 +         }
1184 +      }
1185 +      break;
1186 +
1187 +   case MTFSS:
1188 +      result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_SETMARKS, 0, mt_com->mt_count, 0, FALSE);
1189 +      break;
1190 +
1191 +   case MTBSS:
1192 +      result = SetTapePosition(pHandleInfo->OSHandle, TAPE_SPACE_SETMARKS, 0, -mt_com->mt_count, ~0, FALSE);
1193 +      break;
1194 +
1195 +   case MTWSM:
1196 +      result = WriteTapemark(pHandleInfo->OSHandle, TAPE_SETMARKS, mt_com->mt_count, FALSE);
1197 +      break;
1198 +
1199 +   case MTLOCK:
1200 +      result = PrepareTape(pHandleInfo->OSHandle, TAPE_LOCK, FALSE);
1201 +      break;
1202 +
1203 +   case MTUNLOCK:
1204 +      result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOCK, FALSE);
1205 +      break;
1206 +
1207 +   case MTLOAD:
1208 +      result = PrepareTape(pHandleInfo->OSHandle, TAPE_LOAD, FALSE);
1209 +      break;
1210 +
1211 +   case MTUNLOAD:
1212 +      result = PrepareTape(pHandleInfo->OSHandle, TAPE_UNLOAD, FALSE);
1213 +      break;
1214 +
1215 +   case MTCOMPRESSION:
1216 +      {
1217 +         TAPE_GET_DRIVE_PARAMETERS  GetDriveParameters;
1218 +         TAPE_SET_DRIVE_PARAMETERS  SetDriveParameters;
1219 +         DWORD                      size;
1220 +
1221 +         size = sizeof(GetDriveParameters);
1222 +
1223 +         result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &size, &GetDriveParameters);
1224 +
1225 +         if (result == NO_ERROR)
1226 +         {
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;
1232 +
1233 +            result = SetTapeParameters(pHandleInfo->OSHandle, SET_TAPE_DRIVE_INFORMATION, &SetDriveParameters);
1234 +         }
1235 +      }
1236 +      break;
1237 +
1238 +   case MTSETPART:
1239 +      result = SetTapePosition(pHandleInfo->OSHandle, TAPE_LOGICAL_BLOCK, mt_com->mt_count, 0, 0, FALSE);
1240 +      break;
1241 +
1242 +   case MTMKPART:
1243 +      if (mt_com->mt_count == 0)
1244 +      {
1245 +         result = CreateTapePartition(pHandleInfo->OSHandle, TAPE_INITIATOR_PARTITIONS, 1, 0);
1246 +      }
1247 +      else
1248 +      {
1249 +         result = CreateTapePartition(pHandleInfo->OSHandle, TAPE_INITIATOR_PARTITIONS, 2, mt_com->mt_count);
1250 +      }
1251 +      break;
1252 +   }
1253 +
1254 +   if ((result == NO_ERROR && pHandleInfo->bEOF) || 
1255 +       (result == ERROR_FILEMARK_DETECTED && mt_com->mt_op == MTFSR)) {
1256 +
1257 +      TAPE_POSITION_INFO TapePositionInfo;
1258 +
1259 +      if (GetTapePositionInfo(pHandleInfo->OSHandle, &TapePositionInfo) == NO_ERROR) {
1260 +         pHandleInfo->bBlockValid = true;
1261 +         pHandleInfo->ullFileStart = TapePositionInfo.BlockNumber;
1262 +      }
1263 +   }
1264 +
1265 +   switch (result) {
1266 +   case NO_ERROR:
1267 +   case (DWORD)-1:   /* Error has already been translated into errno */
1268 +      break;
1269 +
1270 +   default:
1271 +   case ERROR_FILEMARK_DETECTED:
1272 +      errno = EIO;
1273 +      break;
1274 +
1275 +   case ERROR_END_OF_MEDIA:
1276 +      pHandleInfo->bEOT = true;
1277 +      errno = EIO;
1278 +      break;
1279 +
1280 +   case ERROR_NO_DATA_DETECTED:
1281 +      pHandleInfo->bEOD = true;
1282 +      errno = EIO;
1283 +      break;
1284 +
1285 +   case ERROR_NO_MEDIA_IN_DRIVE:
1286 +      pHandleInfo->bEOF = false;
1287 +      pHandleInfo->bEOT = false;
1288 +      pHandleInfo->bEOD = false;
1289 +      errno = ENOMEDIUM;
1290 +      break;
1291 +
1292 +   case ERROR_INVALID_HANDLE:
1293 +   case ERROR_ACCESS_DENIED:
1294 +   case ERROR_LOCK_VIOLATION:
1295 +      errno = EBADF;
1296 +      break;
1297 +   }
1298 +
1299 +   return result == NO_ERROR ? 0 : -1;
1300 +}
1301 +
1302 +int tape_get(int fd, struct mtget *mt_get)
1303 +{
1304 +   TAPE_POSITION_INFO pos_info;
1305 +   BOOL result;
1306 +
1307 +   if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) || 
1308 +       TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) {
1309 +      errno = EBADF;
1310 +      return -1;
1311 +   }
1312 +
1313 +   PTAPE_HANDLE_INFO    pHandleInfo = &TapeHandleTable[fd - 3];
1314 +
1315 +   if (GetTapePositionInfo(pHandleInfo->OSHandle, &pos_info) != NO_ERROR) {
1316 +      return -1;
1317 +   }
1318 +
1319 +   DWORD density = 0;
1320 +   DWORD blocksize = 0;
1321 +
1322 +   result = GetDensityBlockSize(pHandleInfo->OSHandle, &density, &blocksize);
1323 +
1324 +   if (result != NO_ERROR) {
1325 +      TAPE_GET_DRIVE_PARAMETERS drive_params;
1326 +      DWORD size;
1327 +
1328 +      size = sizeof(drive_params);
1329 +
1330 +      result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_DRIVE_INFORMATION, &size, &drive_params);
1331 +
1332 +      if (result == NO_ERROR) {
1333 +         blocksize = drive_params.DefaultBlockSize;
1334 +      }
1335 +   }
1336 +
1337 +   mt_get->mt_type = MT_ISSCSI2;
1338 +
1339 +   // Partition #
1340 +   mt_get->mt_resid = pos_info.PartitionBlockValid ? pos_info.Partition : (ULONG)-1;
1341 +
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);
1345 +
1346 +   mt_get->mt_gstat = 0x00010000;  /* Immediate report mode.*/
1347 +
1348 +   if (pHandleInfo->bEOF) {
1349 +      mt_get->mt_gstat |= 0x80000000;     // GMT_EOF
1350 +   }
1351 +
1352 +   if (pos_info.PartitionBlockValid && pos_info.BlockNumber == 0) {
1353 +      mt_get->mt_gstat |= 0x40000000;     // GMT_BOT
1354 +   }
1355 +
1356 +   if (pHandleInfo->bEOT) {
1357 +      mt_get->mt_gstat |= 0x20000000;     // GMT_EOT
1358 +   }
1359 +
1360 +   if (pHandleInfo->bEOD) {
1361 +      mt_get->mt_gstat |= 0x08000000;     // GMT_EOD
1362 +   }
1363 +
1364 +   TAPE_GET_MEDIA_PARAMETERS  media_params;
1365 +   DWORD size = sizeof(media_params);
1366 +   
1367 +   result = GetTapeParameters(pHandleInfo->OSHandle, GET_TAPE_MEDIA_INFORMATION, &size, &media_params);
1368 +
1369 +   if (result == NO_ERROR && media_params.WriteProtected) {
1370 +      mt_get->mt_gstat |= 0x04000000;     // GMT_WR_PROT
1371 +   }
1372 +
1373 +   result = GetTapeStatus(pHandleInfo->OSHandle);
1374 +
1375 +   if (result != NO_ERROR) {
1376 +      if (result == ERROR_NO_MEDIA_IN_DRIVE) {
1377 +         mt_get->mt_gstat |= 0x00040000;  // GMT_DR_OPEN
1378 +      }
1379 +   } else {
1380 +      mt_get->mt_gstat |= 0x01000000;     // GMT_ONLINE
1381 +   }
1382 +
1383 +   // Recovered Error Count
1384 +   mt_get->mt_erreg = 0;
1385 +
1386 +   // File Number
1387 +   mt_get->mt_fileno = (__kernel_daddr_t)pHandleInfo->ulFile;
1388 +
1389 +   // Block Number
1390 +   mt_get->mt_blkno = (__kernel_daddr_t)(pHandleInfo->bBlockValid ? pos_info.BlockNumber - pHandleInfo->ullFileStart : (ULONGLONG)-1);
1391 +
1392 +   return 0;
1393 +}
1394 +
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
1399 +
1400 +
1401 +typedef  struct   _SCSI_READ_POSITION_SHORT_BUFFER
1402 +{
1403 +   UCHAR    :1;
1404 +   UCHAR    PERR:1;
1405 +   UCHAR    BPU:1;
1406 +   UCHAR    :1;
1407 +   UCHAR    BYCU:1;
1408 +   UCHAR    BCU:1;
1409 +   UCHAR    EOP:1;
1410 +   UCHAR    BOP:1;
1411 +   UCHAR    Partition;
1412 +   UCHAR    Reserved1[2];
1413 +   UCHAR    FirstBlock[4];
1414 +   UCHAR    LastBlock[4];
1415 +   UCHAR    Reserved2;
1416 +   UCHAR    NumberBufferBlocks[3];
1417 +   UCHAR    NumberBufferBytes[4];
1418 +}  SCSI_READ_POSITION_SHORT_BUFFER, *PSCSI_READ_POSITION_SHORT_BUFFER;
1419 +
1420 +typedef  struct   _SCSI_READ_POSITION_LONG_BUFFER
1421 +{
1422 +   UCHAR    :2;
1423 +   UCHAR    BPU:1;
1424 +   UCHAR    MPU:1;
1425 +   UCHAR    :2;
1426 +   UCHAR    EOP:1;
1427 +   UCHAR    BOP:1;
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;
1434 +
1435 +typedef  struct   _SCSI_READ_POSITION_EXTENDED_BUFFER
1436 +{
1437 +   UCHAR    :1;
1438 +   UCHAR    PERR:1;
1439 +   UCHAR    LOPU:1;
1440 +   UCHAR    :1;
1441 +   UCHAR    BYCU:1;
1442 +   UCHAR    LOCU:1;
1443 +   UCHAR    EOP:1;
1444 +   UCHAR    BOP:1;
1445 +   UCHAR    Partition;
1446 +   UCHAR    AdditionalLength[2];
1447 +   UCHAR    Reserved1;
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;
1453 +
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;
1459 +
1460 +DWORD GetTapePositionInfo(HANDLE hDevice, PTAPE_POSITION_INFO TapePositionInfo)
1461 +{
1462 +   PSCSI_PASS_THROUGH   ScsiPassThrough;
1463 +   BOOL                 bResult;
1464 +   DWORD                dwBytesReturned;
1465 +   int                 pass;
1466 +
1467 +   const DWORD dwBufferSize = sizeof(SCSI_PASS_THROUGH) + sizeof(READ_POSITION_RESULT) + 28;
1468 +
1469 +   memset(TapePositionInfo, 0, sizeof(*TapePositionInfo));
1470 +
1471 +   ScsiPassThrough = (PSCSI_PASS_THROUGH)malloc(dwBufferSize);
1472 +
1473 +   for (pass = 0; pass < 2; pass++)
1474 +   {
1475 +      memset(ScsiPassThrough, 0, dwBufferSize);
1476 +
1477 +      ScsiPassThrough->Length = sizeof(SCSI_PASS_THROUGH);
1478 +
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);
1486 +
1487 +      ScsiPassThrough->Cdb[0] = 0x34;  // READ POSITION
1488 +
1489 +      switch (pass)
1490 +      {
1491 +      case 0:
1492 +         ScsiPassThrough->Cdb[1] = SERVICEACTION_LONG_FORM;
1493 +         break;
1494 +
1495 +      case 1:
1496 +         ScsiPassThrough->Cdb[1] = SERVICEACTION_SHORT_FORM_BLOCKID;
1497 +         break;
1498 +      }
1499 +
1500 +      bResult = DeviceIoControl( hDevice, 
1501 +                                 IOCTL_SCSI_PASS_THROUGH, 
1502 +                                 ScsiPassThrough, sizeof(SCSI_PASS_THROUGH), 
1503 +                                 ScsiPassThrough, dwBufferSize, 
1504 +                                 &dwBytesReturned, 
1505 +                                 NULL);
1506 +
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);
1510 +
1511 +            switch (pass)
1512 +            {
1513 +            case 0:     // SERVICEACTION_LONG_FORM
1514 +               {
1515 +                  TapePositionInfo->AtPartitionStart = pPosResult->LongBuffer.BOP;
1516 +                  TapePositionInfo->AtPartitionEnd = pPosResult->LongBuffer.EOP;
1517 +
1518 +                  if (!TapePositionInfo->PartitionBlockValid) {
1519 +                     TapePositionInfo->PartitionBlockValid = !pPosResult->LongBuffer.BPU;
1520 +
1521 +                     if (TapePositionInfo->PartitionBlockValid) {
1522 +                        TapePositionInfo->Partition =   Read32BitUnsigned(pPosResult->LongBuffer.Partition);
1523 +                        TapePositionInfo->BlockNumber = Read64BitUnsigned(pPosResult->LongBuffer.BlockNumber);
1524 +                     }
1525 +                  }
1526 +
1527 +                  TapePositionInfo->FileSetValid = !pPosResult->LongBuffer.MPU;
1528 +                  if (TapePositionInfo->FileSetValid) {
1529 +                     TapePositionInfo->FileNumber =  Read64BitUnsigned(pPosResult->LongBuffer.FileNumber);
1530 +                     TapePositionInfo->SetNumber =   Read64BitUnsigned(pPosResult->LongBuffer.SetNumber);
1531 +                  }
1532 +               }
1533 +               break;
1534 +
1535 +            case 1:     // SERVICEACTION_SHORT_FORM_BLOCKID
1536 +               {
1537 +                  // pPosResult->ShortBuffer.PERR;
1538 +                  // pPosResult->ShortBuffer.BYCU;
1539 +                  // pPosResult->ShortBuffer.BCU;
1540 +                  TapePositionInfo->AtPartitionStart = pPosResult->ShortBuffer.BOP;
1541 +                  TapePositionInfo->AtPartitionEnd = pPosResult->ShortBuffer.EOP;
1542 +
1543 +                  if (!TapePositionInfo->PartitionBlockValid) {
1544 +                     TapePositionInfo->PartitionBlockValid = !pPosResult->ShortBuffer.BPU;
1545 +
1546 +                     if (TapePositionInfo->PartitionBlockValid) {
1547 +                        TapePositionInfo->Partition =   pPosResult->ShortBuffer.Partition;
1548 +                        TapePositionInfo->BlockNumber = Read32BitUnsigned(pPosResult->ShortBuffer.FirstBlock);
1549 +                     }
1550 +                  }
1551 +                  // Read32BitsUnsigned(pPosResult->ShortBuffer.LastBlock);
1552 +                  // Read24BitsUnsigned(pPosResult->ShortBuffer.NumberBufferBlocks);
1553 +                  // Read32BitsUnsigned(pPosResult->ShortBuffer.NumberBufferBytes);
1554 +               }
1555 +               break;
1556 +            }
1557 +         }
1558 +      }
1559 +   }
1560 +   free(ScsiPassThrough);
1561 +
1562 +   return NO_ERROR;
1563 +}
1564 +
1565 +DWORD GetDensityBlockSize(HANDLE hDevice, DWORD *pdwDensity, DWORD *pdwBlockSize)
1566 +{
1567 +   DWORD             dwBufferSize = sizeof(GET_MEDIA_TYPES) + 5 * sizeof(DEVICE_MEDIA_INFO);
1568 +   GET_MEDIA_TYPES * pGetMediaTypes = (GET_MEDIA_TYPES *)malloc(dwBufferSize);
1569 +   BOOL              bResult;
1570 +   DWORD             dwResult;
1571 +   DWORD             idxMedia;
1572 +
1573 +   if (pGetMediaTypes == NULL) {
1574 +      return ERROR_OUTOFMEMORY;
1575 +   }
1576 +
1577 +   do {
1578 +      DWORD          dwBytesReturned;
1579 +      
1580 +      bResult = DeviceIoControl( hDevice, 
1581 +                                 IOCTL_STORAGE_GET_MEDIA_TYPES_EX, 
1582 +                                 NULL, 0, 
1583 +                                 (LPVOID)pGetMediaTypes, dwBufferSize, 
1584 +                                 &dwBytesReturned, 
1585 +                                 NULL);
1586 +
1587 +      if (!bResult) {
1588 +         dwResult = GetLastError();
1589 +
1590 +         if (dwResult != ERROR_INSUFFICIENT_BUFFER) {
1591 +            free(pGetMediaTypes);
1592 +            return dwResult;
1593 +         }
1594 +
1595 +         dwBufferSize += 6 * sizeof(DEVICE_MEDIA_INFO);
1596 +
1597 +         GET_MEDIA_TYPES * pNewBuffer = (GET_MEDIA_TYPES *)realloc(pGetMediaTypes, dwBufferSize);
1598 +
1599 +         if (pNewBuffer != pGetMediaTypes) {
1600 +            free(pGetMediaTypes);
1601 +
1602 +            if (pNewBuffer == NULL) {
1603 +               return ERROR_OUTOFMEMORY;
1604 +            }
1605 +
1606 +            pGetMediaTypes = pNewBuffer;
1607 +         }
1608 +      }
1609 +   } while (!bResult);
1610 +
1611 +   if (pGetMediaTypes->DeviceType != FILE_DEVICE_TAPE) {
1612 +      free(pGetMediaTypes);
1613 +      return ERROR_BAD_DEVICE;
1614 +   }
1615 +
1616 +   for (idxMedia = 0; idxMedia < pGetMediaTypes->MediaInfoCount; idxMedia++) {
1617 +
1618 +      if (pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.MediaCharacteristics & MEDIA_CURRENTLY_MOUNTED) {
1619 +
1620 +         if (pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.BusType == BusTypeScsi) {
1621 +            *pdwDensity = pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.BusSpecificData.ScsiInformation.DensityCode;
1622 +         } else {
1623 +            *pdwDensity = 0;
1624 +         }
1625 +
1626 +         *pdwBlockSize = pGetMediaTypes->MediaInfo[idxMedia].DeviceSpecific.TapeInfo.CurrentBlockSize;
1627 +
1628 +         free(pGetMediaTypes);
1629 +
1630 +         return NO_ERROR;
1631 +      }
1632 +   }
1633 +
1634 +   free(pGetMediaTypes);
1635 +
1636 +   return ERROR_NO_MEDIA_IN_DRIVE;
1637 +}
1638 +
1639 +int tape_pos(int fd, struct mtpos *mt_pos)
1640 +{
1641 +   DWORD partition;
1642 +   DWORD offset;
1643 +   DWORD offsetHi;
1644 +   BOOL result;
1645 +
1646 +   if (fd < 3 || fd >= (int)(NUMBER_HANDLE_ENTRIES + 3) || 
1647 +       TapeHandleTable[fd - 3].OSHandle == INVALID_HANDLE_VALUE) {
1648 +      errno = EBADF;
1649 +      return -1;
1650 +   }
1651 +
1652 +   PTAPE_HANDLE_INFO    pHandleInfo = &TapeHandleTable[fd - 3];
1653 +
1654 +   result = GetTapePosition(pHandleInfo->OSHandle, TAPE_ABSOLUTE_BLOCK, &partition, &offset, &offsetHi);
1655 +   if (result == NO_ERROR) {
1656 +      mt_pos->mt_blkno = offset;
1657 +      return 0;
1658 +   }
1659 +
1660 +   return -1;
1661 +}