diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 264acd599..f2686bdf3 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,65 @@ +2004-03-12 Corinna Vinschen + + * 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 * wait.cc (wait4): Initialize pointer on entry. Avoid calling diff --git a/winsup/cygwin/errno.cc b/winsup/cygwin/errno.cc index b04a32ccd..27284bada 100644 --- a/winsup/cygwin/errno.cc +++ b/winsup/cygwin/errno.cc @@ -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} }; diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 2fde1f77e..dbbac2c12 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -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); diff --git a/winsup/cygwin/fhandler_raw.cc b/winsup/cygwin/fhandler_raw.cc index 8baa6ae09..93356ab26 100644 --- a/winsup/cygwin/fhandler_raw.cc +++ b/winsup/cygwin/fhandler_raw.cc @@ -24,52 +24,6 @@ #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. */ - -static BOOL write_file (HANDLE fh, 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 (); - } - } - syscall_printf ("%d (err %d) = WriteFile (%d, %d, write %d, written %d, 0)", - ret, *err, fh, buf, to_write, *written); - return ret; -} - -static BOOL read_file (HANDLE fh, 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 (); - } - } - syscall_printf ("%d (err %d) = ReadFile (%d, %d, to_read %d, read %d, 0)", - ret, *err, fh, buf, to_read, *read); - return ret; -} - /**********************************************************************/ /* fhandler_dev_raw */ @@ -86,13 +40,43 @@ fhandler_dev_raw::clear (void) 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 (get_handle (), buf, to_write, written, 0))) + *err = GetLastError (); + 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_raw::read_file (void *buf, DWORD to_read, DWORD *read, int *err) +{ + BOOL ret; + + *err = 0; + 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, get_handle (), buf, to_read, *read); + return ret; +} + 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; diff --git a/winsup/cygwin/fhandler_tape.cc b/winsup/cygwin/fhandler_tape.cc index 7d159dc66..0b7452080 100644 --- a/winsup/cygwin/fhandler_tape.cc +++ b/winsup/cygwin/fhandler_tape.cc @@ -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"); }