OSDN Git Service

* errno.cc (errmap): Handle ERROR_BUS_RESET.
authorcorinna <corinna>
Sat, 13 Mar 2004 18:15:06 +0000 (18:15 +0000)
committercorinna <corinna>
Sat, 13 Mar 2004 18:15:06 +0000 (18:15 +0000)
* fhandler.h (fhandler_dev_raw::write_file): New method, created
from former static function.
(fhandler_dev_raw::read_file): Ditto.
(reset_devbuf): New inline method.
(class fhandler_dev_tape): Add TAPE_GET_DRIVE_PARAMETERS
member `dp'.
(fhandler_dev_tape::write_file): New method.
(fhandler_dev_tape::read_file): Ditto.
(fhandler_dev_tape::tape_get_feature): Convert to inline method.
(fhandler_dev_tape::tape_error): New method, created from former
static function.
(fhandler_dev_tape::tape_get_blocksize): Remove declaration.
* fhandler_raw.cc (fhandler_dev_raw::write_file): New method, created
from former static function.
(fhandler_dev_raw::read_file): Ditto.
(fhandler_dev_raw::writebuf): Accomodate the fact that no devbuf
exists under variable block size condition.
(fhandler_dev_raw::raw_read): Ditto. Add local p pointer to simplify
pointer arithmetic.
(fhandler_dev_raw::raw_write): Always set devbufend to 0 when starting
with writing. Accomodate the fact that no devbuf exists under
variable block size condition.
* fhandler_tape.cc: Various formatting changes.
(TAPE_FUNC): New macro. Use throughout as tape function loop.
(get_ll): Convert into macro.
(IS_EOM): New macro.
(IS_EOF): New macro.
(fhandler_dev_tape::is_eom): Use IS_EOM macro.
(fhandler_dev_tape::is_eof): Use IS_EOF macro.
(fhandler_dev_tape::write_file): New method.
(fhandler_dev_tape::read_file): New method.
(fhandler_dev_tape::open): Get drive information block here once.
(fhandler_dev_tape::lseek): Remove unneeded duplicate code.
(fhandler_dev_tape::dup): Duplicate drive information block.
(fhandler_dev_tape::ioctl): Remove drvbuf in variable block size mode.
Return ERROR_INVALID_BLOCK_LENGTH instead of ERROR_MORE_DATA if
buffer contains data which would get lost on buffer size changing.
Use absolute tape positioning also if drive only supports logical
block positioning.
(fhandler_dev_tape::tape_error): New method, created from former
static function.
(fhandler_dev_tape::tape_get_pos): Allow logical block reporting.
Workaround tape driver bug.
(fhandler_dev_tape::_tape_set_pos): Reset device buffer and flags
after successful repositioning.
(fhandler_dev_tape::tape_set_pos): Allow logical block positioning.
Workaround tape driver bug.
(fhandler_dev_tape::tape_erase): Use dp instead of calling
GetTapeParameters.
(fhandler_dev_tape::tape_prepare): Ditto.
(fhandler_dev_tape::tape_get_blocksize): Remove.
(fhandler_dev_tape::tape_set_blocksize): Don't call tape_get_blocksize.
Error handling already done in fhandler_dev_tape::ioctl.
(fhandler_dev_tape::tape_status): Remove local `dp' variable.
Accomodate logical tape reporting.  Call tape_get_feature instead
of accessing feature words directly.
(fhandler_dev_tape::tape_compression): Use dp instead of calling
GetTapeParameters.  Fix resetting datcompression.

winsup/cygwin/ChangeLog
winsup/cygwin/errno.cc
winsup/cygwin/fhandler.h
winsup/cygwin/fhandler_raw.cc
winsup/cygwin/fhandler_tape.cc

index 264acd5..f2686bd 100644 (file)
@@ -1,3 +1,65 @@
+2004-03-12  Corinna Vinschen  <corinna@vinschen.de>
+
+       * errno.cc (errmap): Handle ERROR_BUS_RESET.
+       * fhandler.h (fhandler_dev_raw::write_file): New method, created
+       from former static function.
+       (fhandler_dev_raw::read_file): Ditto.
+       (reset_devbuf): New inline method.
+       (class fhandler_dev_tape): Add TAPE_GET_DRIVE_PARAMETERS
+       member `dp'.
+       (fhandler_dev_tape::write_file): New method.
+       (fhandler_dev_tape::read_file): Ditto.
+       (fhandler_dev_tape::tape_get_feature): Convert to inline method.
+       (fhandler_dev_tape::tape_error): New method, created from former
+       static function. 
+       (fhandler_dev_tape::tape_get_blocksize): Remove declaration.
+       * fhandler_raw.cc (fhandler_dev_raw::write_file): New method, created
+       from former static function.
+       (fhandler_dev_raw::read_file): Ditto.
+       (fhandler_dev_raw::writebuf): Accomodate the fact that no devbuf
+       exists under variable block size condition.
+       (fhandler_dev_raw::raw_read): Ditto. Add local p pointer to simplify
+       pointer arithmetic.
+       (fhandler_dev_raw::raw_write): Always set devbufend to 0 when starting
+       with writing. Accomodate the fact that no devbuf exists under
+       variable block size condition.
+       * fhandler_tape.cc: Various formatting changes.
+       (TAPE_FUNC): New macro. Use throughout as tape function loop.
+       (get_ll): Convert into macro.
+       (IS_EOM): New macro.
+       (IS_EOF): New macro.
+       (fhandler_dev_tape::is_eom): Use IS_EOM macro.
+       (fhandler_dev_tape::is_eof): Use IS_EOF macro.
+       (fhandler_dev_tape::write_file): New method.
+       (fhandler_dev_tape::read_file): New method.
+       (fhandler_dev_tape::open): Get drive information block here once.
+       (fhandler_dev_tape::lseek): Remove unneeded duplicate code.
+       (fhandler_dev_tape::dup): Duplicate drive information block.
+       (fhandler_dev_tape::ioctl): Remove drvbuf in variable block size mode.
+       Return ERROR_INVALID_BLOCK_LENGTH instead of ERROR_MORE_DATA if
+       buffer contains data which would get lost on buffer size changing.
+       Use absolute tape positioning also if drive only supports logical
+       block positioning.
+       (fhandler_dev_tape::tape_error): New method, created from former
+       static function.
+       (fhandler_dev_tape::tape_get_pos): Allow logical block reporting.
+       Workaround tape driver bug.
+       (fhandler_dev_tape::_tape_set_pos): Reset device buffer and flags
+       after successful repositioning.
+       (fhandler_dev_tape::tape_set_pos): Allow logical block positioning.
+       Workaround tape driver bug.
+       (fhandler_dev_tape::tape_erase): Use dp instead of calling
+       GetTapeParameters.
+       (fhandler_dev_tape::tape_prepare): Ditto.
+       (fhandler_dev_tape::tape_get_blocksize): Remove.
+       (fhandler_dev_tape::tape_set_blocksize): Don't call tape_get_blocksize.
+       Error handling already done in fhandler_dev_tape::ioctl.
+       (fhandler_dev_tape::tape_status): Remove local `dp' variable.
+       Accomodate logical tape reporting.  Call tape_get_feature instead
+       of accessing feature words directly.
+       (fhandler_dev_tape::tape_compression): Use dp instead of calling
+       GetTapeParameters.  Fix resetting datcompression.
+
 2004-03-12  Christopher Faylor  <cgf@redhat.com>
 
        * wait.cc (wait4): Initialize pointer on entry.  Avoid calling
index b04a32c..27284ba 100644 (file)
@@ -114,6 +114,7 @@ static NO_COPY struct
   X (FILE_INVALID,             ENXIO),
   X (INVALID_ADDRESS,          EOVERFLOW),
   X (INVALID_BLOCK_LENGTH,     EIO),
+  X (BUS_RESET,                        EIO),
   { 0, NULL, 0}
 };
 
index 2fde1f7..dbbac2c 100644 (file)
@@ -514,6 +514,9 @@ class fhandler_dev_raw: public fhandler_base
   int varblkop       : 1;
 
   virtual void clear (void);
+  virtual BOOL write_file (const void *buf, DWORD to_write,
+                          DWORD *written, int *err);
+  virtual BOOL read_file (void *buf, DWORD to_read, DWORD *read, int *err);
   virtual int writebuf (void);
 
   /* returns not null, if `win_error' determines an end of media condition */
@@ -523,6 +526,13 @@ class fhandler_dev_raw: public fhandler_base
 
   fhandler_dev_raw ();
 
+  inline void reset_devbuf (void)
+    {
+      devbufstart = devbufend = 0;
+      eom_detected = eof_detected = 0;
+      lastblk_to_read = is_writing = has_written = 0;
+    }
+
  public:
   ~fhandler_dev_raw (void);
 
@@ -562,14 +572,17 @@ class fhandler_dev_floppy: public fhandler_dev_raw
 class fhandler_dev_tape: public fhandler_dev_raw
 {
   int lasterr;
+  TAPE_GET_DRIVE_PARAMETERS dp;
 
   bool is_rewind_device () { return get_unit () < 128; }
 
  protected:
   virtual void clear (void);
-
   virtual int is_eom (int win_error);
   virtual int is_eof (int win_error);
+  virtual BOOL write_file (const void *buf, DWORD to_write,
+                          DWORD *written, int *err);
+  virtual BOOL read_file (void *buf, DWORD to_read, DWORD *read, int *err);
 
  public:
   fhandler_dev_tape ();
@@ -586,13 +599,19 @@ class fhandler_dev_tape: public fhandler_dev_raw
   virtual int ioctl (unsigned int cmd, void *buf);
 
  private:
+  inline bool tape_get_feature (DWORD parm)
+    {
+      return ((parm & TAPE_DRIVE_HIGH_FEATURES)
+             ? ((dp.FeaturesHigh & parm) != 0)
+             : ((dp.FeaturesLow & parm) != 0));
+    }
+  int tape_error (const char *txt);
   int tape_write_marks (int marktype, DWORD len);
   int tape_get_pos (unsigned long *ret);
   int tape_set_pos (int mode, long count, bool sfm_func = false);
+  int _tape_set_pos (int mode, long count);
   int tape_erase (int mode);
   int tape_prepare (int action);
-  bool tape_get_feature (DWORD parm);
-  int tape_get_blocksize (long *min, long *def, long *max, long *cur);
   int tape_set_blocksize (long count);
   int tape_status (struct mtget *get);
   int tape_compression (long count);
index 8baa6ae..93356ab 100644 (file)
 #include "cygheap.h"
 #include "ntdll.h"
 
-/* static wrapper functions to hide the effect of media changes and
-   bus resets which occurs after a new media is inserted. This is
-   also related to the used tape device.  */
+/**********************************************************************/
+/* fhandler_dev_raw */
 
-static BOOL write_file (HANDLE fh, const void *buf, DWORD to_write,
-                       DWORD *written, int *err)
+void
+fhandler_dev_raw::clear (void)
+{
+  devbuf = NULL;
+  devbufsiz = 0;
+  devbufstart = 0;
+  devbufend = 0;
+  eom_detected = 0;
+  eof_detected = 0;
+  lastblk_to_read = 0;
+  varblkop = 0;
+}
+
+/* Wrapper functions to allow fhandler_dev_tape to detect and care for
+   media changes and bus resets. */
+
+BOOL
+fhandler_dev_raw::write_file (const void *buf, DWORD to_write,
+                             DWORD *written, int *err)
 {
   BOOL ret;
 
   *err = 0;
-  if (!(ret = WriteFile (fh, buf, to_write, written, 0)))
-    {
-      if ((*err = GetLastError ()) == ERROR_MEDIA_CHANGED
-         || *err == ERROR_BUS_RESET)
-       {
-         *err = 0;
-         if (!(ret = WriteFile (fh, buf, to_write, written, 0)))
-           *err = GetLastError ();
-       }
-    }
+  if (!(ret = WriteFile (get_handle (), buf, to_write, written, 0)))
+    *err = GetLastError ();
   syscall_printf ("%d (err %d) = WriteFile (%d, %d, write %d, written %d, 0)",
-                 ret, *err, fh, buf, to_write, *written);
+                 ret, *err, get_handle (), buf, to_write, *written);
   return ret;
 }
 
-static BOOL read_file (HANDLE fh, void *buf, DWORD to_read,
-                      DWORD *read, int *err)
+BOOL
+fhandler_dev_raw::read_file (void *buf, DWORD to_read, DWORD *read, int *err)
 {
   BOOL ret;
 
   *err = 0;
-  if (!(ret = ReadFile (fh, buf, to_read, read, 0)))
-    {
-      if ((*err = GetLastError ()) == ERROR_MEDIA_CHANGED
-         || *err == ERROR_BUS_RESET)
-       {
-         *err = 0;
-         if (!(ret = ReadFile (fh, buf, to_read, read, 0)))
-           *err = GetLastError ();
-       }
-    }
+  if (!(ret = ReadFile (get_handle (), buf, to_read, read, 0)))
+    *err = GetLastError ();
   syscall_printf ("%d (err %d) = ReadFile (%d, %d, to_read %d, read %d, 0)",
-                 ret, *err, fh, buf, to_read, *read);
+                 ret, *err, get_handle (), buf, to_read, *read);
   return ret;
 }
 
-/**********************************************************************/
-/* fhandler_dev_raw */
-
-void
-fhandler_dev_raw::clear (void)
-{
-  devbuf = NULL;
-  devbufsiz = 0;
-  devbufstart = 0;
-  devbufend = 0;
-  eom_detected = 0;
-  eof_detected = 0;
-  lastblk_to_read = 0;
-  varblkop = 0;
-}
-
 int
 fhandler_dev_raw::writebuf (void)
 {
   DWORD written;
   int ret = 0;
 
-  if (is_writing && devbuf && devbufend)
+  if (!varblkop && is_writing && devbuf && devbufend)
     {
       DWORD to_write;
       int ret = 0;
@@ -100,11 +84,9 @@ fhandler_dev_raw::writebuf (void)
       memset (devbuf + devbufend, 0, devbufsiz - devbufend);
       if (get_major () != DEV_TAPE_MAJOR)
        to_write = ((devbufend - 1) / 512 + 1) * 512;
-      else if (varblkop)
-       to_write = devbufend;
       else
        to_write = devbufsiz;
-      if (!write_file (get_handle (), devbuf, to_write, &written, &ret)
+      if (!write_file (devbuf, to_write, &written, &ret)
          && is_eom (ret))
        eom_detected = 1;
       if (written)
@@ -216,6 +198,7 @@ fhandler_dev_raw::raw_read (void *ptr, size_t& ulen)
   int ret;
   size_t len = ulen;
   char *tgt;
+  char *p = (char *) ptr;
 
   /* In mode O_RDWR the buffer has to be written to device first */
   ret = writebuf ();
@@ -251,10 +234,10 @@ fhandler_dev_raw::raw_read (void *ptr, size_t& ulen)
            {
              bytes_to_read = min (len, devbufend - devbufstart);
              debug_printf ("read %d bytes from buffer (rest %d)",
-                           bytes_to_read, devbufstart - devbufend);
-             memcpy (ptr, devbuf + devbufstart, bytes_to_read);
+                           bytes_to_read, devbufend - devbufend);
+             memcpy (p, devbuf + devbufstart, bytes_to_read);
              len -= bytes_to_read;
-             ptr = (void *) ((char *) ptr + bytes_to_read);
+             p += bytes_to_read;
              bytes_read += bytes_to_read;
              devbufstart += bytes_to_read;
 
@@ -266,21 +249,15 @@ fhandler_dev_raw::raw_read (void *ptr, size_t& ulen)
            }
          if (len > 0)
            {
-             if (!varblkop && len >= devbufsiz)
+             if (len >= devbufsiz)
                {
                  if (get_major () == DEV_TAPE_MAJOR)
                    bytes_to_read = (len / devbufsiz) * devbufsiz;
                  else
                    bytes_to_read = (len / 512) * 512;
-                 tgt = (char *) ptr;
+                 tgt = p;
                  debug_printf ("read %d bytes direct from file",bytes_to_read);
                }
-             else if (varblkop)
-               {
-                 tgt = (char *) ptr;
-                 bytes_to_read = len;
-                 debug_printf ("read variable bytes direct from file");
-               }
              else
                {
                  tgt = devbuf;
@@ -288,16 +265,11 @@ fhandler_dev_raw::raw_read (void *ptr, size_t& ulen)
                  debug_printf ("read %d bytes from file into buffer",
                                bytes_to_read);
                }
-             if (!read_file (get_handle (), tgt, bytes_to_read, &read2, &ret))
+             if (!read_file (tgt, bytes_to_read, &read2, &ret))
                {
                  if (!is_eof (ret) && !is_eom (ret))
                    {
-                     if (varblkop && ret == ERROR_MORE_DATA)
-                       /* *ulen < blocksize.  Linux returns ENOMEM here
-                          when reading with variable blocksize . */
-                       set_errno (ENOMEM);
-                     else
-                       __seterrno ();
+                     __seterrno ();
                      goto err;
                    }
 
@@ -325,26 +297,24 @@ fhandler_dev_raw::raw_read (void *ptr, size_t& ulen)
                  devbufstart = 0;
                  devbufend = read2;
                }
-             else if (varblkop)
-               {
-                 /* When reading tapes with variable block size, we
-                    leave right after reading one block. */
-                 bytes_read = read2;
-                 break;
-               }
              else
                {
                  len -= read2;
-                 ptr = (void *) ((char *) ptr + read2);
+                 p += read2;
                  bytes_read += read2;
                }
            }
        }
     }
-  else if (!read_file (get_handle (), ptr, len, &bytes_read, &ret))
+  else if (!read_file (p, len, &bytes_read, &ret))
     {
       if (!is_eof (ret) && !is_eom (ret))
        {
+         if (varblkop && ret == ERROR_MORE_DATA)
+           /* *ulen < blocksize.  Linux returns ENOMEM here
+              when reading with variable blocksize . */
+           set_errno (ENOMEM);
+         else
          __seterrno ();
          goto err;
        }
@@ -389,18 +359,14 @@ fhandler_dev_raw::raw_write (const void *ptr, size_t len)
     }
 
   if (!is_writing)
-    {
-      devbufend = devbufstart;
-      devbufstart = 0;
-    }
+    devbufstart = devbufend = 0;
   is_writing = 1;
 
   if (devbuf)
     {
       while (len > 0)
        {
-         if (!varblkop &&
-             (len < devbufsiz || devbufend > 0) && devbufend < devbufsiz)
+         if ((len < devbufsiz || devbufend > 0) && devbufend < devbufsiz)
            {
              bytes_to_write = min (len, devbufsiz - devbufend);
              memcpy (devbuf + devbufend, p, bytes_to_write);
@@ -411,12 +377,7 @@ fhandler_dev_raw::raw_write (const void *ptr, size_t len)
            }
          else
            {
-             if (varblkop)
-               {
-                 bytes_to_write = len;
-                 tgt = p;
-               }
-             else if (devbufend == devbufsiz)
+             if (devbufend == devbufsiz)
                {
                  bytes_to_write = devbufsiz;
                  tgt = devbuf;
@@ -428,7 +389,7 @@ fhandler_dev_raw::raw_write (const void *ptr, size_t len)
                }
 
              ret = 0;
-             write_file (get_handle (), tgt, bytes_to_write, &written, &ret);
+             write_file (tgt, bytes_to_write, &written, &ret);
              if (written)
                has_written = 1;
 
@@ -471,7 +432,7 @@ fhandler_dev_raw::raw_write (const void *ptr, size_t len)
     }
   else if (len > 0)
     {
-      if (!write_file (get_handle (), ptr, len, &bytes_written, &ret))
+      if (!write_file (p, len, &bytes_written, &ret))
        {
          if (bytes_written)
            has_written = 1;
index 7d159dc..0b74520 100644 (file)
@@ -21,6 +21,24 @@ details. */
 #include "dtable.h"
 #include "cygheap.h"
 
+/* Media changes and bus resets are sometimes reported and the function
+   hasn't been executed.  We repeat all functions which return with one
+   of these error codes. */
+#define TAPE_FUNC(func) do { \
+                         lasterr = (func); \
+                       } while (lasterr == ERROR_MEDIA_CHANGED \
+                                || lasterr == ERROR_BUS_RESET)
+
+/* Convert LARGE_INTEGER into long long */
+#define get_ll(pl)  (((long long) (pl).HighPart << 32) | (pl).LowPart)
+
+#define IS_EOM(err) ((err) == ERROR_END_OF_MEDIA \
+                    || (err) == ERROR_EOM_OVERFLOW \
+                    || (err) == ERROR_NO_DATA_DETECTED)
+
+#define IS_EOF(err) ((err) == ERROR_FILEMARK_DETECTED \
+                    || (err) == ERROR_SETMARK_DETECTED)
+
 /**********************************************************************/
 /* fhandler_dev_tape */
 
@@ -34,9 +52,7 @@ fhandler_dev_tape::clear (void)
 int
 fhandler_dev_tape::is_eom (int win_error)
 {
-  int ret = ((win_error == ERROR_END_OF_MEDIA)
-         || (win_error == ERROR_EOM_OVERFLOW)
-         || (win_error == ERROR_NO_DATA_DETECTED));
+  int ret = IS_EOM (win_error);
   if (ret)
     debug_printf ("end of medium");
   return ret;
@@ -45,13 +61,47 @@ fhandler_dev_tape::is_eom (int win_error)
 int
 fhandler_dev_tape::is_eof (int win_error)
 {
-  int ret = ((win_error == ERROR_FILEMARK_DETECTED)
-         || (win_error == ERROR_SETMARK_DETECTED));
+  int ret = IS_EOF (win_error);
   if (ret)
     debug_printf ("end of file");
   return ret;
 }
 
+BOOL
+fhandler_dev_tape::write_file (const void *buf, DWORD to_write,
+                              DWORD *written, int *err)
+{
+  BOOL ret;
+
+  do
+    {
+      *err = 0;
+      if (!(ret = WriteFile (get_handle (), buf, to_write, written, 0)))
+       *err = GetLastError ();
+    }
+  while (*err == ERROR_MEDIA_CHANGED || *err == ERROR_BUS_RESET);
+  syscall_printf ("%d (err %d) = WriteFile (%d, %d, write %d, written %d, 0)",
+                 ret, *err, get_handle (), buf, to_write, *written);
+  return ret;
+}
+
+BOOL
+fhandler_dev_tape::read_file (void *buf, DWORD to_read, DWORD *read, int *err)
+{
+  BOOL ret;
+
+  do
+    {
+      *err = 0;
+      if (!(ret = ReadFile (get_handle (), buf, to_read, read, 0)))
+       *err = GetLastError ();
+    }
+  while (*err == ERROR_MEDIA_CHANGED || *err == ERROR_BUS_RESET);
+  syscall_printf ("%d (err %d) = ReadFile (%d, %d, to_read %d, read %d, 0)",
+                 ret, *err, get_handle (), buf, to_read, *read);
+  return ret;
+}
+
 fhandler_dev_tape::fhandler_dev_tape ()
   : fhandler_dev_raw ()
 {
@@ -71,6 +121,10 @@ fhandler_dev_tape::open (int flags, mode_t)
       struct mtget get;
       struct mtop op;
       struct mtpos pos;
+      DWORD varlen;
+
+      TAPE_FUNC (GetTapeParameters (get_handle (), GET_TAPE_DRIVE_INFORMATION,
+                                   (varlen = sizeof dp, &varlen), &dp));
 
       if (!ioctl (MTIOCGET, &get))
        /* Tape drive supports and is set to variable block size. */
@@ -116,7 +170,7 @@ fhandler_dev_tape::close (void)
   if (is_writing)
     {
       ret = writebuf ();
-      if ((has_written) && (! eom_detected))
+      if (has_written && !eom_detected)
        {
          /* if last operation was writing, write a filemark */
          debug_printf ("writing filemark");
@@ -170,9 +224,6 @@ fhandler_dev_tape::lseek (_off64_t offset, int whence)
   debug_printf ("lseek (%s, %d, %d)", get_name (), offset, whence);
 
   writebuf ();
-  eom_detected = eof_detected = 0;
-  lastblk_to_read = 0;
-  devbufstart = devbufend = 0;
 
   if (ioctl (MTIOCPOS, &pos))
     {
@@ -223,6 +274,7 @@ fhandler_dev_tape::dup (fhandler_base *child)
   fhandler_dev_tape *fhc = (fhandler_dev_tape *) child;
 
   fhc->lasterr = lasterr;
+  fhc->dp = dp;
   return fhandler_dev_raw::dup (child);
 }
 
@@ -236,7 +288,7 @@ fhandler_dev_tape::ioctl (unsigned int cmd, void *buf)
     {
       struct mtop *op = (struct mtop *) buf;
 
-      if (! op)
+      if (!op)
        ret = ERROR_INVALID_PARAMETER;
       else
        switch (op->mt_op)
@@ -272,9 +324,9 @@ fhandler_dev_tape::ioctl (unsigned int cmd, void *buf)
          case MTNOP:
            break;
          case MTRETEN:
-           if (! tape_get_feature (TAPE_DRIVE_END_OF_DATA))
+           if (!tape_get_feature (TAPE_DRIVE_END_OF_DATA))
              ret = ERROR_INVALID_PARAMETER;
-           else if (! (ret = tape_set_pos (TAPE_REWIND, 0, false)))
+           else if (!(ret = tape_set_pos (TAPE_REWIND, 0, false)))
              ret = tape_prepare (TAPE_TENSION);
            break;
          case MTBSFM:
@@ -299,53 +351,45 @@ fhandler_dev_tape::ioctl (unsigned int cmd, void *buf)
            break;
          case MTSETBLK:
            {
-             long min, max;
-
-             if (! tape_get_feature (TAPE_DRIVE_SET_BLOCK_SIZE))
+             if (!tape_get_feature (TAPE_DRIVE_SET_BLOCK_SIZE))
                {
                  ret = ERROR_INVALID_PARAMETER;
                  break;
                }
-             ret = tape_get_blocksize (&min, NULL, &max, NULL);
-             if (ret)
-                 break;
-             if (devbuf && (size_t) op->mt_count == devbufsiz && !varblkop)
+             if ((devbuf && (size_t) op->mt_count == devbufsiz)
+                 || (!devbuf && op->mt_count == 0))
                {
+                 /* Nothing has changed. */
                  ret = 0;
                  break;
                }
              if ((op->mt_count == 0
                   && !tape_get_feature (TAPE_DRIVE_VARIABLE_BLOCK))
                  || (op->mt_count > 0
-                     && (op->mt_count < min || op->mt_count > max)))
+                     && ((DWORD) op->mt_count < dp.MinimumBlockSize
+                         || (DWORD) op->mt_count > dp.MaximumBlockSize)))
                {
                  ret = ERROR_INVALID_PARAMETER;
                  break;
                }
-             if (devbuf && op->mt_count > 0
-                 && (size_t) op->mt_count < devbufend - devbufstart)
+             if (devbuf && devbufend - devbufstart > 0
+                 && (op->mt_count == 0
+                     || (op->mt_count > 0
+                         && (size_t) op->mt_count < devbufend - devbufstart)))
                {
-                 ret = ERROR_MORE_DATA;
+                 /* Not allowed if still data in devbuf. */
+                 ret = ERROR_INVALID_BLOCK_LENGTH; /* EIO */
                  break;
                }
-             if (! (ret = tape_set_blocksize (op->mt_count)))
+             if (!(ret = tape_set_blocksize (op->mt_count)))
                {
-                 size_t size = 0;
-                 if (op->mt_count == 0)
-                   {
-                     struct mtget get;
-                     if ((ret = tape_status (&get)) != NO_ERROR)
-                       break;
-                     size = get.mt_maxblksize;
-                     ret = NO_ERROR;
-                   }
                  char *buf = NULL;
-                 if (size > 1L && !(buf = new char [size]))
+                 if (op->mt_count > 1L && !(buf = new char [op->mt_count]))
                    {
                      ret = ERROR_OUTOFMEMORY;
                      break;
                    }
-                 if (devbufsiz > 1L && size > 1L)
+                 if (devbufsiz > 1L && op->mt_count > 1L)
                    {
                      memcpy (buf, devbuf + devbufstart,
                              devbufend - devbufstart);
@@ -353,11 +397,10 @@ fhandler_dev_tape::ioctl (unsigned int cmd, void *buf)
                    }
                  else
                    devbufend = 0;
-                 if (devbufsiz > 1L)
-                   delete [] devbuf;
                  devbufstart = 0;
+                 delete [] devbuf;
                  devbuf = buf;
-                 devbufsiz = size;
+                 devbufsiz = op->mt_count;
                  varblkop = op->mt_count == 0;
                }
            }
@@ -366,19 +409,15 @@ fhandler_dev_tape::ioctl (unsigned int cmd, void *buf)
            ret = ERROR_INVALID_PARAMETER;
            break;
          case MTSEEK:
-           if (tape_get_feature (TAPE_DRIVE_ABSOLUTE_BLK))
-             {
-               ret = tape_set_pos (TAPE_ABSOLUTE_BLOCK, op->mt_count);
-               break;
-             }
-           if (! (ret = tape_get_pos (&block)))
-             {
-               ret = tape_set_pos (TAPE_SPACE_RELATIVE_BLOCKS,
-                                op->mt_count - block);
-             }
+           if (tape_get_feature (TAPE_DRIVE_ABSOLUTE_BLK)
+               || tape_get_feature (TAPE_DRIVE_LOGICAL_BLK))
+             ret = tape_set_pos (TAPE_ABSOLUTE_BLOCK, op->mt_count);
+           else if (!(ret = tape_get_pos (&block)))
+             ret = tape_set_pos (TAPE_SPACE_RELATIVE_BLOCKS,
+                                 op->mt_count - block);
            break;
          case MTTELL:
-           if (! (ret = tape_get_pos (&block)))
+           if (!(ret = tape_get_pos (&block)))
              op->mt_count = block;
            break;
          case MTSETDRVBUFFER:
@@ -440,12 +479,11 @@ fhandler_dev_tape::ioctl (unsigned int cmd, void *buf)
 /*                  Private functions used by `ioctl'                 */
 /* ------------------------------------------------------------------ */
 
-static int
-tape_error (DWORD lasterr, const char *txt)
+int
+fhandler_dev_tape::tape_error (const char *txt)
 {
   if (lasterr)
     debug_printf ("%s: error: %d", txt, lasterr);
-
   return lasterr;
 }
 
@@ -453,14 +491,8 @@ int
 fhandler_dev_tape::tape_write_marks (int marktype, DWORD len)
 {
   syscall_printf ("write_tapemark");
-  while (((lasterr = WriteTapemark (get_handle (),
-                                   marktype,
-                                   len,
-                                   FALSE)) == ERROR_MEDIA_CHANGED)
-        || (lasterr == ERROR_BUS_RESET))
-    ;
-
-  return tape_error (lasterr, "tape_write_marks");
+  TAPE_FUNC (WriteTapemark (get_handle (), marktype, len, FALSE));
+  return tape_error ("tape_write_marks");
 }
 
 int
@@ -468,33 +500,42 @@ fhandler_dev_tape::tape_get_pos (unsigned long *ret)
 {
   DWORD part, low, high;
 
-  while (((lasterr = GetTapePosition (get_handle (),
-                                     TAPE_ABSOLUTE_POSITION,
-                                     &part,
-                                     &low,
-                                     &high)) == ERROR_MEDIA_CHANGED)
-        || (lasterr == ERROR_BUS_RESET))
-    ;
-  if (! tape_error (lasterr, "tape_get_pos") && ret)
+  lasterr = ERROR_INVALID_PARAMETER;
+  if (tape_get_feature (TAPE_DRIVE_GET_ABSOLUTE_BLK))
+    {
+      TAPE_FUNC (GetTapePosition (get_handle (), TAPE_ABSOLUTE_POSITION,
+                                 &part, &low, &high));
+      /* Workaround bug in Tandberg SLR device driver, which pretends
+         to support reporting of absolute blocks but instead returns
+        ERROR_INVALID_FUNCTION. */
+      if (lasterr != ERROR_INVALID_FUNCTION)
+       goto out;
+      dp.FeaturesLow &= ~TAPE_DRIVE_GET_ABSOLUTE_BLK;
+    }
+  if (tape_get_feature (TAPE_DRIVE_GET_LOGICAL_BLK))
+    TAPE_FUNC (GetTapePosition (get_handle (), TAPE_LOGICAL_POSITION,
+                               &part, &low, &high));
+
+out:
+  if (!tape_error ("tape_get_pos") && ret)
     *ret = low;
 
   return lasterr;
 }
 
-static int _tape_set_pos (HANDLE hTape, int mode, long count)
+int
+fhandler_dev_tape::_tape_set_pos (int mode, long count)
 {
-  int err;
-
-  while (((err = SetTapePosition (hTape,
-                                 mode,
-                                 1,
-                                 count,
-                                 count < 0 ? -1 : 0,
-                                 FALSE)) == ERROR_MEDIA_CHANGED)
-        || (err == ERROR_BUS_RESET))
-    ;
-
-  return err;
+  TAPE_FUNC (SetTapePosition (get_handle (), mode, 0, count,
+                             count < 0 ? -1 : 0, FALSE));
+  /* Reset buffer after successful repositioning. */
+  if (!lasterr || IS_EOF (lasterr) || IS_EOM (lasterr))
+    {
+      reset_devbuf ();
+      eof_detected = IS_EOF (lasterr);
+      eom_detected = IS_EOM (lasterr);
+    }
+  return lasterr;
 }
 
 int
@@ -505,25 +546,19 @@ fhandler_dev_tape::tape_set_pos (int mode, long count, bool sfm_func)
   switch (mode)
     {
       case TAPE_SPACE_RELATIVE_BLOCKS:
-       lasterr = tape_get_pos (&pos);
-
-       if (lasterr)
+       if (tape_get_pos (&pos))
          return lasterr;
 
        tgtpos = pos + count;
 
-       while (((lasterr = _tape_set_pos (get_handle (),
-                                         mode,
-                                         count)) == ERROR_FILEMARK_DETECTED)
-              || (lasterr == ERROR_SETMARK_DETECTED))
+       while (count && (_tape_set_pos (mode, count), IS_EOF (lasterr)))
          {
-           lasterr = tape_get_pos (&pos);
-           if (lasterr)
+           if (tape_get_pos (&pos))
              return lasterr;
            count = tgtpos - pos;
          }
 
-       if (lasterr == ERROR_BEGINNING_OF_MEDIA && ! tgtpos)
+       if (lasterr == ERROR_BEGINNING_OF_MEDIA && !tgtpos)
          lasterr = NO_ERROR;
 
        break;
@@ -532,223 +567,132 @@ fhandler_dev_tape::tape_set_pos (int mode, long count, bool sfm_func)
          {
            if (pos > 0)
              {
-               if ((! _tape_set_pos (get_handle (),
-                                 TAPE_SPACE_RELATIVE_BLOCKS,
-                                 -1))
+               if (!_tape_set_pos (TAPE_SPACE_RELATIVE_BLOCKS, -1)
                    || (sfm_func))
                  ++count;
-               _tape_set_pos (get_handle (), TAPE_SPACE_RELATIVE_BLOCKS, 1);
+               _tape_set_pos (TAPE_SPACE_RELATIVE_BLOCKS, 1);
              }
 
-           while (! (lasterr = _tape_set_pos (get_handle (), mode, -1))
-                  && count++ < 0)
+           while (!_tape_set_pos (mode, -1) && count++ < 0)
              ;
 
            if (lasterr == ERROR_BEGINNING_OF_MEDIA)
              {
-               if (! count)
+               if (!count)
                  lasterr = NO_ERROR;
              }
-           else if (! sfm_func)
-             lasterr = _tape_set_pos (get_handle (), mode, 1);
+           else if (!sfm_func)
+             _tape_set_pos (mode, 1);
          }
        else
          {
            if (sfm_func)
              {
-               if (_tape_set_pos (get_handle (),
-                                  TAPE_SPACE_RELATIVE_BLOCKS,
-                                  1) == ERROR_FILEMARK_DETECTED)
+               if (_tape_set_pos (TAPE_SPACE_RELATIVE_BLOCKS, 1)
+                   == ERROR_FILEMARK_DETECTED)
                  ++count;
-               _tape_set_pos (get_handle (), TAPE_SPACE_RELATIVE_BLOCKS, -1);
+               _tape_set_pos (TAPE_SPACE_RELATIVE_BLOCKS, -1);
              }
 
-           if (! (lasterr = _tape_set_pos (get_handle (), mode, count))
-               && sfm_func)
-             lasterr = _tape_set_pos (get_handle (), mode, -1);
+           if (!_tape_set_pos (mode, count) && sfm_func)
+             _tape_set_pos (mode, -1);
          }
        break;
-      case TAPE_SPACE_SETMARKS:
       case TAPE_ABSOLUTE_BLOCK:
+       if (!tape_get_feature (TAPE_DRIVE_ABSOLUTE_BLK))
+         mode = TAPE_LOGICAL_BLOCK;
+       _tape_set_pos (mode, count);
+       /* Workaround bug in Tandberg SLR device driver, which pretends
+          to support absolute block positioning but instead returns
+          ERROR_INVALID_FUNCTION. */
+       if (lasterr == ERROR_INVALID_FUNCTION && mode == TAPE_ABSOLUTE_BLOCK)
+         {
+           dp.FeaturesHigh &= TAPE_DRIVE_HIGH_FEATURES
+                              | ~TAPE_DRIVE_ABSOLUTE_BLK;
+           _tape_set_pos (TAPE_LOGICAL_BLOCK, count);
+         }
+         break;
+      case TAPE_SPACE_SETMARKS:
       case TAPE_SPACE_END_OF_DATA:
       case TAPE_REWIND:
-       lasterr = _tape_set_pos (get_handle (), mode, count);
+       _tape_set_pos (mode, count);
        break;
     }
 
-  return tape_error (lasterr, "tape_set_pos");
+  return tape_error ("tape_set_pos");
 }
 
 int
 fhandler_dev_tape::tape_erase (int mode)
 {
-  DWORD varlen;
-  TAPE_GET_DRIVE_PARAMETERS dp;
-
-  while (((lasterr = GetTapeParameters (get_handle (),
-                                       GET_TAPE_DRIVE_INFORMATION,
-                                       (varlen = sizeof dp, &varlen),
-                                       &dp)) == ERROR_MEDIA_CHANGED)
-        || (lasterr == ERROR_BUS_RESET))
-    ;
-
   switch (mode)
     {
       case TAPE_ERASE_SHORT:
-       if (! lasterr && ! (dp.FeaturesLow & TAPE_DRIVE_ERASE_SHORT))
+       if (!tape_get_feature (TAPE_DRIVE_ERASE_SHORT))
          mode = TAPE_ERASE_LONG;
        break;
       case TAPE_ERASE_LONG:
-       if (! lasterr && ! (dp.FeaturesLow & TAPE_DRIVE_ERASE_LONG))
+       if (!tape_get_feature (TAPE_DRIVE_ERASE_LONG))
          mode = TAPE_ERASE_SHORT;
        break;
     }
-
-  return tape_error (EraseTape (get_handle (), mode, false), "tape_erase");
+  TAPE_FUNC (EraseTape (get_handle (), mode, false));
+  /* Reset buffer after successful tape erasing. */
+  if (!lasterr)
+    reset_devbuf ();
+  return tape_error ("tape_erase");
 }
 
 int
 fhandler_dev_tape::tape_prepare (int action)
 {
-  while (((lasterr = PrepareTape (get_handle (),
-                                 action,
-                                 FALSE)) == ERROR_MEDIA_CHANGED)
-        || (lasterr == ERROR_BUS_RESET))
-    ;
-  return tape_error (lasterr, "tape_prepare");
-}
-
-bool
-fhandler_dev_tape::tape_get_feature (DWORD parm)
-{
-  DWORD varlen;
-  TAPE_GET_DRIVE_PARAMETERS dp;
-
-  while (((lasterr = GetTapeParameters (get_handle (),
-                                       GET_TAPE_DRIVE_INFORMATION,
-                                       (varlen = sizeof dp, &varlen),
-                                       &dp)) == ERROR_MEDIA_CHANGED)
-        || (lasterr == ERROR_BUS_RESET))
-    ;
-
-  if (lasterr)
-    return false;
-
-  return ((parm & TAPE_DRIVE_HIGH_FEATURES)
-         ? ((dp.FeaturesHigh & parm) != 0)
-         : ((dp.FeaturesLow & parm) != 0));
-}
-
-int
-fhandler_dev_tape::tape_get_blocksize (long *min, long *def, long *max, long *cur)
-{
-  DWORD varlen;
-  TAPE_GET_DRIVE_PARAMETERS dp;
-  TAPE_GET_MEDIA_PARAMETERS mp;
-
-  while (((lasterr = GetTapeParameters (get_handle (),
-                                       GET_TAPE_DRIVE_INFORMATION,
-                                       (varlen = sizeof dp, &varlen),
-                                       &dp)) == ERROR_MEDIA_CHANGED)
-        || (lasterr == ERROR_BUS_RESET))
-    ;
-
-  if (lasterr)
-    return tape_error (lasterr, "tape_get_blocksize");
-
-  while (((lasterr = GetTapeParameters (get_handle (),
-                                       GET_TAPE_MEDIA_INFORMATION,
-                                       (varlen = sizeof dp, &varlen),
-                                       &mp)) == ERROR_MEDIA_CHANGED)
-        || (lasterr == ERROR_BUS_RESET))
-    ;
-
-  if (lasterr)
-    return tape_error (lasterr, "tape_get_blocksize");
-
-  if (min)
-    *min = (long) dp.MinimumBlockSize;
-  if (def)
-    *def = (long) dp.DefaultBlockSize;
-  if (max)
-    *max = (long) dp.MaximumBlockSize;
-  if (cur)
-    *cur = (long) mp.BlockSize;
-
-  return tape_error (lasterr, "tape_get_blocksize");
+  TAPE_FUNC (PrepareTape (get_handle (), action, FALSE));
+  /* Reset buffer after all successful preparations but lock and unlock. */
+  if (!lasterr && action != TAPE_LOCK && action != TAPE_UNLOCK)
+    reset_devbuf ();
+  return tape_error ("tape_prepare");
 }
 
 int
 fhandler_dev_tape::tape_set_blocksize (long count)
 {
-  long min, max;
   TAPE_SET_MEDIA_PARAMETERS mp;
 
-  lasterr = tape_get_blocksize (&min, NULL, &max, NULL);
-
-  if (lasterr)
-    return lasterr;
-
-  if (count != 0 && (count < min || count > max))
-    return tape_error (ERROR_INVALID_PARAMETER, "tape_set_blocksize");
-
   mp.BlockSize = count;
-
-  return tape_error (SetTapeParameters (get_handle (),
-                                       SET_TAPE_MEDIA_INFORMATION,
-                                       &mp),
-                    "tape_set_blocksize");
-}
-
-static long long
-get_ll (PLARGE_INTEGER i)
-{
-  long long l = 0;
-
-  l = i->HighPart;
-  l <<= 32;
-  l |= i->LowPart;
-  return l;
+  TAPE_FUNC (SetTapeParameters (get_handle (), SET_TAPE_MEDIA_INFORMATION,
+                               &mp));
+  return tape_error ("tape_set_blocksize");
 }
 
 int
 fhandler_dev_tape::tape_status (struct mtget *get)
 {
   DWORD varlen;
-  TAPE_GET_DRIVE_PARAMETERS dp;
   TAPE_GET_MEDIA_PARAMETERS mp;
   int notape = 0;
 
-  if (! get)
+  if (!get)
     return ERROR_INVALID_PARAMETER;
 
-  while (((lasterr = GetTapeParameters (get_handle (),
-                                       GET_TAPE_DRIVE_INFORMATION,
-                                       (varlen = sizeof dp, &varlen),
-                                       &dp)) == ERROR_MEDIA_CHANGED)
-        || (lasterr == ERROR_BUS_RESET))
-    ;
-
-  /* Setting varlen to sizeof DP is by intention, actually! Never set
+  /* Setting varlen to sizeof DP is by intention, actually!  Never set
      it to sizeof MP which seems to be more correct but results in a
      ERROR_MORE_DATA error at least on W2K. */
-  if ((lasterr) || (lasterr = GetTapeParameters (get_handle (),
-                                                GET_TAPE_MEDIA_INFORMATION,
-                                                (varlen = sizeof dp, &varlen),
-                                                &mp)))
+  TAPE_FUNC (GetTapeParameters (get_handle (), GET_TAPE_MEDIA_INFORMATION,
+                               (varlen = sizeof dp, &varlen), &mp));
+  if (lasterr)
     notape = 1;
 
   memset (get, 0, sizeof *get);
 
   get->mt_type = MT_ISUNKNOWN;
 
-  if (! notape && (dp.FeaturesLow & TAPE_DRIVE_TAPE_REMAINING))
+  if (!notape && tape_get_feature (TAPE_DRIVE_TAPE_REMAINING))
     {
-      get->mt_remaining = get_ll (&mp.Remaining);
+      get->mt_remaining = get_ll (mp.Remaining);
       get->mt_resid = get->mt_remaining >> 10;
     }
 
-  if ((dp.FeaturesHigh & TAPE_DRIVE_SET_BLOCK_SIZE) && ! notape)
+  if (tape_get_feature (TAPE_DRIVE_SET_BLOCK_SIZE) && !notape)
     get->mt_dsreg = mp.BlockSize;
   else
     get->mt_dsreg = dp.DefaultBlockSize;
@@ -756,33 +700,34 @@ fhandler_dev_tape::tape_status (struct mtget *get)
   if (notape)
     get->mt_gstat |= GMT_DR_OPEN (-1);
 
-  if (! notape)
+  if (!notape)
     {
-      if (dp.FeaturesLow & TAPE_DRIVE_GET_ABSOLUTE_BLK)
+      if (tape_get_feature (TAPE_DRIVE_GET_ABSOLUTE_BLK)
+         || tape_get_feature (TAPE_DRIVE_GET_LOGICAL_BLK))
        tape_get_pos ((unsigned long *) &get->mt_blkno);
 
-      if (! get->mt_blkno)
+      if (!get->mt_blkno)
        get->mt_gstat |= GMT_BOT (-1);
 
       get->mt_gstat |= GMT_ONLINE (-1);
 
-      if ((dp.FeaturesLow & TAPE_DRIVE_WRITE_PROTECT) && mp.WriteProtected)
+      if (tape_get_feature (TAPE_DRIVE_WRITE_PROTECT) && mp.WriteProtected)
        get->mt_gstat |= GMT_WR_PROT (-1);
 
-      if (dp.FeaturesLow & TAPE_DRIVE_TAPE_CAPACITY)
-       get->mt_capacity = get_ll (&mp.Capacity);
+      if (tape_get_feature (TAPE_DRIVE_TAPE_CAPACITY))
+       get->mt_capacity = get_ll (mp.Capacity);
     }
 
-  if ((dp.FeaturesLow & TAPE_DRIVE_COMPRESSION) && dp.Compression)
+  if (tape_get_feature (TAPE_DRIVE_COMPRESSION) && dp.Compression)
     get->mt_gstat |= GMT_HW_COMP (-1);
 
-  if ((dp.FeaturesLow & TAPE_DRIVE_ECC) && dp.ECC)
+  if (tape_get_feature (TAPE_DRIVE_ECC) && dp.ECC)
     get->mt_gstat |= GMT_HW_ECC (-1);
 
-  if ((dp.FeaturesLow & TAPE_DRIVE_PADDING) && dp.DataPadding)
+  if (tape_get_feature (TAPE_DRIVE_PADDING) && dp.DataPadding)
     get->mt_gstat |= GMT_PADDING (-1);
 
-  if ((dp.FeaturesLow & TAPE_DRIVE_REPORT_SMKS) && dp.ReportSetmarks)
+  if (tape_get_feature (TAPE_DRIVE_REPORT_SMKS) && dp.ReportSetmarks)
     get->mt_gstat |= GMT_IM_REP_EN (-1);
 
   get->mt_erreg = lasterr;
@@ -800,40 +745,20 @@ fhandler_dev_tape::tape_status (struct mtget *get)
 int
 fhandler_dev_tape::tape_compression (long count)
 {
-  DWORD varlen;
-  TAPE_GET_DRIVE_PARAMETERS dpg;
   TAPE_SET_DRIVE_PARAMETERS dps;
 
-  while (((lasterr = GetTapeParameters (get_handle (),
-                                       GET_TAPE_DRIVE_INFORMATION,
-                                       (varlen = sizeof dpg, &varlen),
-                                       &dpg)) == ERROR_MEDIA_CHANGED)
-        || (lasterr == ERROR_BUS_RESET))
-    ;
-
-  if (lasterr)
-    return tape_error (lasterr, "tape_compression");
-
-  if (! (dpg.FeaturesLow & TAPE_DRIVE_COMPRESSION))
+  if (!tape_get_feature (TAPE_DRIVE_COMPRESSION))
     return ERROR_INVALID_PARAMETER;
 
-  if (count)
-    {
-      dps.ECC = dpg.ECC;
-      dps.Compression = count ? TRUE : FALSE;
-      dps.DataPadding = dpg.DataPadding;
-      dps.ReportSetmarks = dpg.ReportSetmarks;
-      dps.EOTWarningZoneSize = dpg.EOTWarningZoneSize;
-      lasterr = SetTapeParameters (get_handle (),
-                                  SET_TAPE_DRIVE_INFORMATION,
-                                  &dps);
-
-      if (lasterr)
-       return tape_error (lasterr, "tape_compression");
-
-      dpg.Compression = dps.Compression;
-    }
-
-  return 0;
+  dps.ECC = dp.ECC;
+  dps.Compression = count ? TRUE : FALSE;
+  dps.DataPadding = dp.DataPadding;
+  dps.ReportSetmarks = dp.ReportSetmarks;
+  dps.EOTWarningZoneSize = dp.EOTWarningZoneSize;
+  TAPE_FUNC (SetTapeParameters (get_handle (), SET_TAPE_DRIVE_INFORMATION,
+                               &dps));
+  if (!lasterr)
+    dp.Compression = dps.Compression;
+  return tape_error ("tape_compression");
 }