Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2004-03-27 00:43:49 +0300
committerCorinna Vinschen <corinna@vinschen.de>2004-03-27 00:43:49 +0300
commitdee563095deb2bbdba5d4e04e48c99694061e302 (patch)
treea2134a3b338c171f09e28111b883621f712b3bd1
parent359b6e4c49105718a9ff5341172685d98790dd7e (diff)
* errno.cc (errmap): Map ERROR_SHARING_VIOLATION to EBUSY,
ERROR_EOM_OVERFLOW and ERROR_NO_DATA_DETECTED to EIO. Add mappings for ERROR_NO_MEDIA_IN_DRIVE, ERROR_DEVICE_REQUIRES_CLEANING and ERROR_DEVICE_DOOR_OPEN. * fhandler.h (class fhandler_dev_raw): Drop varblkop member. (fhandler_dev_raw::is_eom): De-virtualize. (fhandler_dev_raw::is_eof): Ditto. (class fhandler_dev_tape): Drop lasterr and dp member. Add mt_mtx member. Drop all private methods formerly used by ioctl. (fhandler_dev_tape::is_rewind_device): Use get_minor for clarity. (fhandler_dev_tape::driveno): New method. (fhandler_dev_tape::drive_init): New method. (fhandler_dev_tape::clear): Remove method. (fhandler_dev_tape::is_eom): Ditto. (fhandler_dev_tape::is_eof): Ditto. (fhandler_dev_tape::write_file): Ditto. (fhandler_dev_tape::read_file): Ditto. (fhandler_dev_tape::_lock): New method. (fhandler_dev_tape::unlock): New method. (fhandler_dev_tape::raw_read): New method. (fhandler_dev_tape::raw_write): New method. * fhandler_raw.cc (fhandler_dev_raw::is_eom): New method. (fhandler_dev_raw::is_eof): New method. (fhandler_dev_raw::open): Allow setting write through option by using the O_TEXT flag as ... flag. (fhandler_dev_raw::writebuf): Remove usage of varblkop and other tape specific code. (fhandler_dev_raw::raw_read): Ditto. (fhandler_dev_raw::dup): Ditto. * fhandler_tape.cc: Rewrite tape operations entirely. Implement new tape driver classes mtinfo, mtinfo_drive and mtinfo_part. Reduce fhandler_dev_tape methods to mostly just calling appropriate mtinfo_drive methods. (mtinfo_init): New function adding the mtinfo shared memory area. * mtinfo.h: New file, containing the definition of the new tape driver classes. * shared.cc: Include mtinfo.h. (offsets): Add entry for mtinfo shared memory area. (memory_init): Call mtinfo_init. * shared_info.h (shared_locations): Add SH_MTINFO shared location. * include/cygwin/mtio.h: Change and add various comments. Add GMT_xxx macros for new generic flags. Add MT_ST_xxx bitfield definitions for MTSETDRVBUFFER ioctl. * include/cygwin/version.h: Bump API minor version number.
-rw-r--r--winsup/cygwin/ChangeLog47
-rw-r--r--winsup/cygwin/errno.cc9
-rw-r--r--winsup/cygwin/fhandler.h45
-rw-r--r--winsup/cygwin/fhandler_raw.cc44
-rw-r--r--winsup/cygwin/fhandler_tape.cc1599
-rw-r--r--winsup/cygwin/include/cygwin/mtio.h56
-rw-r--r--winsup/cygwin/include/cygwin/version.h4
-rw-r--r--winsup/cygwin/mtinfo.h133
-rw-r--r--winsup/cygwin/shared.cc8
-rw-r--r--winsup/cygwin/shared_info.h1
10 files changed, 1388 insertions, 558 deletions
diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index c0f44a17e..e6c6a4bb6 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,50 @@
+2004-03-26 Corinna Vinschen <corinna@vinschen.de>
+
+ * errno.cc (errmap): Map ERROR_SHARING_VIOLATION to EBUSY,
+ ERROR_EOM_OVERFLOW and ERROR_NO_DATA_DETECTED to EIO. Add mappings
+ for ERROR_NO_MEDIA_IN_DRIVE, ERROR_DEVICE_REQUIRES_CLEANING and
+ ERROR_DEVICE_DOOR_OPEN.
+ * fhandler.h (class fhandler_dev_raw): Drop varblkop member.
+ (fhandler_dev_raw::is_eom): De-virtualize.
+ (fhandler_dev_raw::is_eof): Ditto.
+ (class fhandler_dev_tape): Drop lasterr and dp member. Add mt_mtx
+ member. Drop all private methods formerly used by ioctl.
+ (fhandler_dev_tape::is_rewind_device): Use get_minor for clarity.
+ (fhandler_dev_tape::driveno): New method.
+ (fhandler_dev_tape::drive_init): New method.
+ (fhandler_dev_tape::clear): Remove method.
+ (fhandler_dev_tape::is_eom): Ditto.
+ (fhandler_dev_tape::is_eof): Ditto.
+ (fhandler_dev_tape::write_file): Ditto.
+ (fhandler_dev_tape::read_file): Ditto.
+ (fhandler_dev_tape::_lock): New method.
+ (fhandler_dev_tape::unlock): New method.
+ (fhandler_dev_tape::raw_read): New method.
+ (fhandler_dev_tape::raw_write): New method.
+ * fhandler_raw.cc (fhandler_dev_raw::is_eom): New method.
+ (fhandler_dev_raw::is_eof): New method.
+ (fhandler_dev_raw::open): Allow setting write through option by
+ using the O_TEXT flag as ... flag.
+ (fhandler_dev_raw::writebuf): Remove usage of varblkop and other
+ tape specific code.
+ (fhandler_dev_raw::raw_read): Ditto.
+ (fhandler_dev_raw::dup): Ditto.
+ * fhandler_tape.cc: Rewrite tape operations entirely. Implement
+ new tape driver classes mtinfo, mtinfo_drive and mtinfo_part.
+ Reduce fhandler_dev_tape methods to mostly just calling appropriate
+ mtinfo_drive methods.
+ (mtinfo_init): New function adding the mtinfo shared memory area.
+ * mtinfo.h: New file, containing the definition of the new tape
+ driver classes.
+ * shared.cc: Include mtinfo.h.
+ (offsets): Add entry for mtinfo shared memory area.
+ (memory_init): Call mtinfo_init.
+ * shared_info.h (shared_locations): Add SH_MTINFO shared location.
+ * include/cygwin/mtio.h: Change and add various comments. Add GMT_xxx
+ macros for new generic flags. Add MT_ST_xxx bitfield definitions
+ for MTSETDRVBUFFER ioctl.
+ * include/cygwin/version.h: Bump API minor version number.
+
2004-03-26 Christopher Faylor <cgf@redhat.com>
* path.cc (path_conv::check): Use 'strchr' rather than 'strrchr' to
diff --git a/winsup/cygwin/errno.cc b/winsup/cygwin/errno.cc
index 2c7915c59..475164a02 100644
--- a/winsup/cygwin/errno.cc
+++ b/winsup/cygwin/errno.cc
@@ -48,7 +48,7 @@ static NO_COPY struct
X (NO_MORE_FILES, ENMFILE),
X (WRITE_PROTECT, EROFS),
X (BAD_UNIT, ENODEV),
- X (SHARING_VIOLATION, EACCES),
+ X (SHARING_VIOLATION, EBUSY),
X (LOCK_VIOLATION, EACCES),
X (SHARING_BUFFER_EXCEEDED, ENOLCK),
X (HANDLE_EOF, ENODATA),
@@ -101,10 +101,10 @@ static NO_COPY struct
X (IO_DEVICE, EIO),
X (NOT_OWNER, EPERM),
X (END_OF_MEDIA, ENOSPC),
- X (EOM_OVERFLOW, ENOSPC),
+ X (EOM_OVERFLOW, EIO),
X (BEGINNING_OF_MEDIA, EIO),
X (SETMARK_DETECTED, EIO),
- X (NO_DATA_DETECTED, ENOSPC),
+ X (NO_DATA_DETECTED, EIO),
X (POSSIBLE_DEADLOCK, EDEADLOCK),
X (CRC, EIO),
X (NEGATIVE_SEEK, EINVAL),
@@ -116,6 +116,9 @@ static NO_COPY struct
X (INVALID_BLOCK_LENGTH, EIO),
X (BUS_RESET, EIO),
X (FILEMARK_DETECTED, EIO),
+ X (NO_MEDIA_IN_DRIVE, ENOMEDIUM),
+ X (DEVICE_REQUIRES_CLEANING, EIO),
+ X (DEVICE_DOOR_OPEN, EIO),
{ 0, NULL, 0}
};
diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h
index c7d7568ed..0b5c71299 100644
--- a/winsup/cygwin/fhandler.h
+++ b/winsup/cygwin/fhandler.h
@@ -509,7 +509,6 @@ class fhandler_dev_raw: public fhandler_base
int lastblk_to_read : 1;
int is_writing : 1;
int has_written : 1;
- int varblkop : 1;
virtual void clear (void);
virtual BOOL write_file (const void *buf, DWORD to_write,
@@ -518,9 +517,9 @@ class fhandler_dev_raw: public fhandler_base
virtual int writebuf (void);
/* returns not null, if `win_error' determines an end of media condition */
- virtual int is_eom(int win_error) = 0;
+ virtual int is_eom(int win_error);
/* returns not null, if `win_error' determines an end of file condition */
- virtual int is_eof(int win_error) = 0;
+ virtual int is_eof(int win_error);
fhandler_dev_raw ();
@@ -569,18 +568,14 @@ class fhandler_dev_floppy: public fhandler_dev_raw
class fhandler_dev_tape: public fhandler_dev_raw
{
- int lasterr;
- TAPE_GET_DRIVE_PARAMETERS dp;
+ HANDLE mt_mtx;
- bool is_rewind_device () { return get_unit () < 128; }
+ bool is_rewind_device () { return get_minor () < 128; }
+ unsigned int driveno () { return (unsigned int) get_minor () & 0x7f; }
+ void drive_init (void);
- 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);
+ inline bool _lock ();
+ inline int unlock (int ret = 0);
public:
fhandler_dev_tape ();
@@ -588,33 +583,15 @@ class fhandler_dev_tape: public fhandler_dev_raw
virtual int open (int flags, mode_t mode = 0);
virtual int close (void);
+ void raw_read (void *ptr, size_t& ulen);
+ int raw_write (const void *ptr, size_t ulen);
+
virtual _off64_t lseek (_off64_t offset, int whence);
virtual int __stdcall fstat (struct __stat64 *buf) __attribute__ ((regparm (2)));
virtual int dup (fhandler_base *child);
-
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 *block, unsigned long *partition = NULL);
- int tape_set_pos (int mode, long count, bool sfm_func = false);
- int _tape_set_pos (int mode, long count, int partition = 0);
- int tape_erase (int mode);
- int tape_prepare (int action);
- int tape_set_blocksize (long count);
- int tape_status (struct mtget *get);
- int tape_compression (long count);
- int tape_partition (long count);
- int tape_set_partition (long count);
};
/* Standard disk file */
diff --git a/winsup/cygwin/fhandler_raw.cc b/winsup/cygwin/fhandler_raw.cc
index 93356ab26..44c449561 100644
--- a/winsup/cygwin/fhandler_raw.cc
+++ b/winsup/cygwin/fhandler_raw.cc
@@ -37,9 +37,21 @@ fhandler_dev_raw::clear (void)
eom_detected = 0;
eof_detected = 0;
lastblk_to_read = 0;
- varblkop = 0;
}
+int
+fhandler_dev_raw::is_eom (int win_error)
+{
+ return 0;
+}
+
+int
+fhandler_dev_raw::is_eof (int)
+{
+ return 0;
+}
+
+
/* Wrapper functions to allow fhandler_dev_tape to detect and care for
media changes and bus resets. */
@@ -76,16 +88,13 @@ fhandler_dev_raw::writebuf (void)
DWORD written;
int ret = 0;
- if (!varblkop && is_writing && devbuf && devbufend)
+ if (is_writing && devbuf && devbufend)
{
DWORD to_write;
int ret = 0;
memset (devbuf + devbufend, 0, devbufsiz - devbufend);
- if (get_major () != DEV_TAPE_MAJOR)
- to_write = ((devbufend - 1) / 512 + 1) * 512;
- else
- to_write = devbufsiz;
+ to_write = ((devbufend - 1) / 512 + 1) * 512;
if (!write_file (devbuf, to_write, &written, &ret)
&& is_eom (ret))
eom_detected = 1;
@@ -141,7 +150,7 @@ fhandler_dev_raw::open (int flags, mode_t)
}
/* Check for illegal flags. */
- if (flags & (O_APPEND | O_EXCL))
+ if (get_major () != DEV_TAPE_MAJOR && (flags & (O_APPEND | O_EXCL)))
{
set_errno (EINVAL);
return 0;
@@ -162,11 +171,16 @@ fhandler_dev_raw::open (int flags, mode_t)
WCHAR devname[CYG_MAX_PATH + 1];
str2buf2uni (dev, devname, get_win32_name ());
OBJECT_ATTRIBUTES attr;
+ ULONG options = FILE_SYNCHRONOUS_IO_NONALERT;
+ /* The O_TEXT flag is used to indicate write-through on tape devices */
+ if (get_major () == DEV_TAPE_MAJOR && (flags & O_TEXT))
+ options |= FILE_WRITE_THROUGH;
+ flags &= ~O_TEXT;
InitializeObjectAttributes (&attr, &dev, OBJ_CASE_INSENSITIVE, NULL, NULL);
HANDLE h;
IO_STATUS_BLOCK io;
- NTSTATUS status = NtOpenFile (&h, access, &attr, &io, wincap.shared (),
+ NTSTATUS status = NtOpenFile (&h, access, &attr, &io, 0 /* excl. access */,
FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS (status))
{
@@ -234,7 +248,8 @@ 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, devbufend - devbufend);
+ bytes_to_read,
+ devbufend - devbufstart - bytes_to_read);
memcpy (p, devbuf + devbufstart, bytes_to_read);
len -= bytes_to_read;
p += bytes_to_read;
@@ -251,10 +266,7 @@ fhandler_dev_raw::raw_read (void *ptr, size_t& ulen)
{
if (len >= devbufsiz)
{
- if (get_major () == DEV_TAPE_MAJOR)
- bytes_to_read = (len / devbufsiz) * devbufsiz;
- else
- bytes_to_read = (len / 512) * 512;
+ bytes_to_read = (len / 512) * 512;
tgt = p;
debug_printf ("read %d bytes direct from file",bytes_to_read);
}
@@ -310,11 +322,6 @@ fhandler_dev_raw::raw_read (void *ptr, size_t& ulen)
{
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;
}
@@ -470,7 +477,6 @@ fhandler_dev_raw::dup (fhandler_base *child)
fhc->eom_detected = eom_detected;
fhc->eof_detected = eof_detected;
fhc->lastblk_to_read = 0;
- fhc->varblkop = varblkop;
}
return ret;
}
diff --git a/winsup/cygwin/fhandler_tape.cc b/winsup/cygwin/fhandler_tape.cc
index a99e4a2aa..bbcc67063 100644
--- a/winsup/cygwin/fhandler_tape.cc
+++ b/winsup/cygwin/fhandler_tape.cc
@@ -14,6 +14,7 @@ details. */
#include <unistd.h>
#include <stdlib.h>
#include <sys/mtio.h>
+#include <sys/param.h>
#include <ddk/ntddstor.h>
#include "cygerrno.h"
#include "perprocess.h"
@@ -22,742 +23,1358 @@ details. */
#include "fhandler.h"
#include "dtable.h"
#include "cygheap.h"
+#include "shared_info.h"
+#include "sigproc.h"
+#include "mtinfo.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. */
-/* FIXME: Note that this is wrong! The correct behaviour after getting
- an ERROR_BUS_RESET is to raise a flag and then to block any access,
- except for MTREW, MTOFFL, MT_RETEN, MTERASE, MTSEEK and MTEOM, and
- to set errno to EIO in all other cases. */
-#define TAPE_FUNC(func) do { \
- lasterr = (func); \
- } while (lasterr == ERROR_MEDIA_CHANGED \
- || lasterr == ERROR_BUS_RESET)
+#define TAPE_FUNC(func) while ((lasterr = (func)) == ERROR_MEDIA_CHANGED) \
+ { \
+ initialize (drive, false); \
+ part (partition)->initialize (0); \
+ }
/* 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_BOT(err) ((err) == ERROR_BEGINNING_OF_MEDIA)
#define IS_EOF(err) ((err) == ERROR_FILEMARK_DETECTED \
|| (err) == ERROR_SETMARK_DETECTED)
+#define IS_SM(err) ((err) == ERROR_SETMARK_DETECTED)
+
+#define IS_EOD(err) ((err) == ERROR_END_OF_MEDIA \
+ || (err) == ERROR_EOM_OVERFLOW \
+ || (err) == ERROR_NO_DATA_DETECTED)
+
+#define IS_EOM(err) ((err) == ERROR_END_OF_MEDIA \
+ || (err) == ERROR_EOM_OVERFLOW)
+
/**********************************************************************/
-/* fhandler_dev_tape */
+/* mtinfo_part */
void
-fhandler_dev_tape::clear (void)
+mtinfo_part::initialize (long nblock)
{
- lasterr = 0;
- fhandler_dev_raw::clear ();
+ block = nblock;
+ if (block == 0)
+ file = fblock = 0;
+ else
+ file = fblock = -1;
+ smark = false;
+ emark = no_eof;
+}
+
+/**********************************************************************/
+/* mtinfo_drive */
+
+void
+mtinfo_drive::initialize (int num, bool first_time)
+{
+ drive = num;
+ partition = 0;
+ block = -1;
+ lock = unlocked;
+ if (first_time)
+ {
+ buffer_writes = true;
+ two_fm = false;
+ fast_eom = false;
+ auto_lock = false;
+ sysv = false;
+ nowait = false;
+ }
+ for (int i = 0; i < MAX_PARTITION_NUM; ++i)
+ part (i)->initialize ();
}
int
-fhandler_dev_tape::is_eom (int win_error)
+mtinfo_drive::get_dp (HANDLE mt)
{
- int ret = IS_EOM (win_error);
- if (ret)
- debug_printf ("end of medium");
- return ret;
+ DWORD len = sizeof _dp;
+ TAPE_FUNC (GetTapeParameters (mt, GET_TAPE_DRIVE_INFORMATION, &len, &_dp));
+ return error ("get_dp");
}
int
-fhandler_dev_tape::is_eof (int win_error)
+mtinfo_drive::get_mp (HANDLE mt)
{
- int ret = IS_EOF (win_error);
- if (ret)
- debug_printf ("end of file");
- return ret;
+ DWORD len = sizeof _mp;
+ TAPE_FUNC (GetTapeParameters (mt, GET_TAPE_MEDIA_INFORMATION, &len, &_mp));
+ return error ("get_mp");
}
-BOOL
-fhandler_dev_tape::write_file (const void *buf, DWORD to_write,
- DWORD *written, int *err)
+int
+mtinfo_drive::open (HANDLE mt)
{
- BOOL ret;
+ get_dp (mt);
+ get_mp (mt);
+ get_pos (mt);
+ if (partition < MAX_PARTITION_NUM && part (partition)->block != block)
+ part (partition)->initialize (block);
+ /* The following rewind in position 0 solves a problem which appears
+ * in case of multi volume archives (at least on NT4): The last ReadFile
+ * on the previous medium returns ERROR_NO_DATA_DETECTED. After media
+ * change, all subsequent ReadFile calls return ERROR_NO_DATA_DETECTED,
+ * too. The call to set_pos apparently reset some internal flags.
+ * FIXME: Is that really true or based on a misinterpretation? */
+ if (!block)
+ {
+ debug_printf ("rewind in position 0");
+ set_pos (mt, TAPE_REWIND, 0, false);
+ }
+ return error ("open");
+}
- do
+int
+mtinfo_drive::close (HANDLE mt, bool rewind)
+{
+ lasterr = 0;
+ if (GetTapeStatus (mt) == ERROR_NO_MEDIA_IN_DRIVE)
+ dirty = clean;
+ if (dirty == has_written)
{
- *err = 0;
- if (!(ret = WriteFile (get_handle (), buf, to_write, written, 0)))
- *err = GetLastError ();
+ /* if last operation was writing, write a filemark */
+ debug_printf ("writing filemark");
+ write_marks (mt, TAPE_FILEMARKS, two_fm ? 2 : 1);
+ if (two_fm && !lasterr && !rewind) /* Backspace over the 2nd filemark. */
+ {
+ set_pos (mt, TAPE_SPACE_FILEMARKS, -1, false);
+ if (!lasterr)
+ part (partition)->fblock = 0; /* That's obvious, isn't it? */
+ }
}
- 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;
+ else if (dirty == has_read && sysv && !rewind)
+ {
+ if (sysv)
+ {
+ /* Under SYSV semantics, the tape is moved past the next file mark
+ after read. */
+ if (part (partition)->emark == no_eof)
+ set_pos (mt, TAPE_SPACE_FILEMARKS, 1, false);
+ else if (part (partition)->emark == eof_hit)
+ part (partition)->emark = eof;
+ }
+ else
+ {
+ /* Under BSD semantics, we must check if the filemark has been
+ inadvertendly crossed. If so cross the filemark backwards
+ and position the tape right before EOF. */
+ if (part (partition)->emark == eof_hit)
+ set_pos (mt, TAPE_SPACE_FILEMARKS, -1, false);
+ }
+ }
+ if (rewind)
+ {
+ debug_printf ("rewinding");
+ set_pos (mt, TAPE_REWIND, 0, false);
+ }
+ if (auto_lock && lock == auto_locked)
+ prepare (mt, TAPE_UNLOCK);
+ dirty = clean;
+ return error ("close");
}
-BOOL
-fhandler_dev_tape::read_file (void *buf, DWORD to_read, DWORD *read, int *err)
+int
+mtinfo_drive::read (HANDLE mt, void *ptr, size_t &ulen)
{
BOOL ret;
+ DWORD bytes_read = 0;
- do
+ if (GetTapeStatus (mt) == ERROR_NO_MEDIA_IN_DRIVE)
+ return lasterr = ERROR_NO_MEDIA_IN_DRIVE;
+ if (lasterr == ERROR_BUS_RESET)
{
- *err = 0;
- if (!(ret = ReadFile (get_handle (), buf, to_read, read, 0)))
- *err = GetLastError ();
+ ulen = 0;
+ goto out;
}
- 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;
+ dirty = clean;
+ if (part (partition)->emark == eof_hit)
+ {
+ part (partition)->emark = eof;
+ lasterr = ulen = 0;
+ goto out;
+ }
+ else if (part (partition)->emark == eod_hit)
+ {
+ part (partition)->emark = eod;
+ lasterr = ulen = 0;
+ goto out;
+ }
+ else if (part (partition)->emark == eod)
+ {
+ lasterr = ERROR_NO_DATA_DETECTED;
+ ulen = (size_t) -1;
+ goto out;
+ }
+ else if (part (partition)->emark == eom_hit)
+ {
+ part (partition)->emark = eom;
+ lasterr = ulen = 0;
+ goto out;
+ }
+ else if (part (partition)->emark == eom)
+ {
+ lasterr = ERROR_END_OF_MEDIA;
+ ulen = (size_t) -1;
+ goto out;
+ }
+ part (partition)->smark = false;
+ if (auto_lock && lock < auto_locked)
+ prepare (mt, TAPE_LOCK, true);
+ ret = ReadFile (mt, ptr, ulen, &bytes_read, 0);
+ lasterr = ret ? 0 : GetLastError ();
+ ulen = (size_t) bytes_read;
+ if (bytes_read > 0)
+ {
+ long blocks_read = mp ()->BlockSize == 0
+ ? 1 : howmany (bytes_read, mp ()->BlockSize);
+ block += blocks_read;
+ part (partition)->block += blocks_read;
+ if (part (partition)->fblock >= 0)
+ part (partition)->fblock += blocks_read;
+ }
+ if (IS_EOF (lasterr))
+ {
+ block++;
+ part (partition)->block++;
+ if (part (partition)->file >= 0)
+ part (partition)->file++;
+ part (partition)->fblock = 0;
+ part (partition)->smark = IS_SM (lasterr);
+ part (partition)->emark = bytes_read > 0 ? eof_hit : eof;
+ lasterr = 0;
+ }
+ else if (IS_EOD (lasterr))
+ {
+ if (part (partition)->emark == eof)
+ part (partition)->emark = IS_EOM (lasterr) ? eom : eod;
+ else
+ {
+ part (partition)->emark = IS_EOM (lasterr) ? eom_hit : eod_hit;
+ lasterr = 0;
+ }
+ }
+ else
+ {
+ part (partition)->emark = no_eof;
+ /* This happens if the buffer is too small when in variable block
+ size mode. Linux returns ENOMEM here. We're doing the same. */
+ if (lasterr == ERROR_MORE_DATA)
+ lasterr = ERROR_NOT_ENOUGH_MEMORY;
+ }
+ if (!lasterr)
+ dirty = has_read;
+out:
+ return error ("read");
}
-fhandler_dev_tape::fhandler_dev_tape ()
- : fhandler_dev_raw ()
+int
+mtinfo_drive::write (HANDLE mt, const void *ptr, size_t &len)
{
- debug_printf ("unit: %d", dev ().minor);
+ BOOL ret;
+ DWORD bytes_written = 0;
+
+ if (GetTapeStatus (mt) == ERROR_NO_MEDIA_IN_DRIVE)
+ return lasterr = ERROR_NO_MEDIA_IN_DRIVE;
+ if (lasterr == ERROR_BUS_RESET)
+ {
+ len = 0;
+ return error ("write");
+ }
+ dirty = clean;
+ part (partition)->smark = false;
+ if (auto_lock && lock < auto_locked)
+ prepare (mt, TAPE_LOCK, true);
+ ret = WriteFile (mt, ptr, len, &bytes_written, 0);
+ lasterr = ret ? 0: GetLastError ();
+ len = (size_t) bytes_written;
+ if (bytes_written > 0)
+ {
+ long blocks_written = mp ()->BlockSize == 0
+ ? 1 : howmany (bytes_written, mp ()->BlockSize);
+ block += blocks_written;
+ part (partition)->block += blocks_written;
+ if (part (partition)->fblock >= 0)
+ part (partition)->fblock += blocks_written;
+ }
+ if (lasterr == ERROR_EOM_OVERFLOW)
+ part (partition)->emark = eom;
+ else if (lasterr == ERROR_END_OF_MEDIA)
+ ; // FIXME?: part (partition)->emark = eom_hit;
+ else
+ {
+ part (partition)->emark = no_eof;
+ if (!lasterr)
+ dirty = has_written;
+ }
+ return error ("write");
}
int
-fhandler_dev_tape::open (int flags, mode_t)
+mtinfo_drive::get_pos (HANDLE mt, long *ppartition, long *pblock)
{
- int ret;
-
- devbufsiz = 1L;
+ DWORD p, low, high;
- ret = fhandler_dev_raw::open (flags);
- if (ret)
+ TAPE_FUNC (GetTapePosition (mt, TAPE_LOGICAL_POSITION, &p, &low, &high));
+ if (lasterr == ERROR_INVALID_FUNCTION)
+ TAPE_FUNC (GetTapePosition (mt, TAPE_ABSOLUTE_POSITION, &p, &low, &high));
+ if (!lasterr)
+ {
+ partition = (long) (p > 0 ? p - 1 : p);
+ block = (long) low;
+ if (ppartition)
+ *ppartition= partition;
+ if (pblock)
+ *pblock = block;
+ }
+ else
{
- DWORD varlen;
- struct mtget get;
- unsigned long block;
+ partition = 0;
+ block = -1;
+ }
+ return error ("get_pos");
+}
- TAPE_FUNC (GetTapeParameters (get_handle (), GET_TAPE_DRIVE_INFORMATION,
- (varlen = sizeof dp, &varlen), &dp));
+int
+mtinfo_drive::_set_pos (HANDLE mt, int mode, long count,
+ int partition)
+{
+ TAPE_FUNC (SetTapePosition (mt, mode, partition, count,
+ count < 0 ? -1 : 0, FALSE));
+ dirty = clean;
+ return lasterr;
+}
- if (!tape_status (&get))
- {
- long blksize = (get.mt_dsreg & MT_ST_BLKSIZE_MASK)
- >> MT_ST_BLKSIZE_SHIFT;
- /* Tape drive supports and is set to variable block size. */
- if (blksize == 0)
- devbufsiz = get.mt_maxblksize;
- else
- devbufsiz = blksize;
- varblkop = blksize == 0;
- }
+int
+mtinfo_drive::set_pos (HANDLE mt, int mode, long count,
+ bool sfm_func)
+{
+ int err = 0;
+ long undone = count;
+ BOOL dont_wait = FALSE;
- if (devbufsiz > 1L)
- devbuf = new char [devbufsiz];
+ switch (mode)
+ {
+ case TAPE_SPACE_RELATIVE_BLOCKS:
+ case TAPE_SPACE_FILEMARKS:
+ case TAPE_SPACE_SETMARKS:
+ if (!count)
+ {
+ lasterr = 0;
+ goto out;
+ }
+ break;
+ case TAPE_ABSOLUTE_BLOCK:
+ case TAPE_LOGICAL_BLOCK:
+ case TAPE_REWIND:
+ dont_wait = nowait ? TRUE : FALSE;
+ break;
+ }
+ if (mode == TAPE_SPACE_FILEMARKS)
+ {
+ while (!err && undone > 0)
+ if (!(err = _set_pos (mt, mode, 1, 0)) || IS_SM (err))
+ --undone;
+ while (!err && undone < 0)
+ if (!(err = _set_pos (mt, mode, -1, 0)) || IS_SM (err))
+ ++undone;
+ }
+ else
+ err = _set_pos (mt, mode, count, dont_wait);
+ switch (mode)
+ {
+ case TAPE_ABSOLUTE_BLOCK:
+ case TAPE_LOGICAL_BLOCK:
+ get_pos (mt);
+ part (partition)->initialize (block);
+ break;
+ case TAPE_REWIND:
+ if (!err)
+ {
+ block = 0;
+ part (partition)->initialize (0);
+ }
+ else
+ {
+ get_pos (mt);
+ part (partition)->initialize (block);
+ }
+ break;
+ case TAPE_SPACE_END_OF_DATA:
+ get_pos (mt);
+ part (partition)->initialize (block);
+ part (partition)->emark = IS_EOM (err) ? eom : eod;
+ break;
+ case TAPE_SPACE_FILEMARKS:
+ if (!err || IS_SM (err))
+ {
+ get_pos (mt);
+ part (partition)->block = block;
+ if (count > 0)
+ {
+ if (part (partition)->file >= 0)
+ part (partition)->file += count - undone;
+ part (partition)->fblock = 0;
+ part (partition)->smark = IS_SM (err);
+ }
+ else
+ {
+ if (part (partition)->file >= 0)
+ part (partition)->file += count - undone;
+ part (partition)->fblock = -1;
+ part (partition)->smark = false;
+ }
+ if (sfm_func)
+ err = set_pos (mt, mode, count > 0 ? -1 : 1, false);
+ else
+ part (partition)->emark = count > 0 ? eof : no_eof;
+ }
+ else if (IS_EOD (err))
+ {
+ get_pos (mt);
+ part (partition)->block = block;
+ if (part (partition)->file >= 0)
+ part (partition)->file += count - undone;
+ part (partition)->fblock = -1;
+ part (partition)->smark = false;
+ part (partition)->emark = IS_EOM (err) ? eom : eod;
+ }
+ else if (IS_BOT (err))
+ {
+ block = 0;
+ part (partition)->initialize (0);
+ }
+ else
+ {
+ get_pos (mt);
+ part (partition)->initialize (block);
+ }
+ break;
+ case TAPE_SPACE_RELATIVE_BLOCKS:
+ if (!err)
+ {
+ block += count;
+ part (partition)->block += count;
+ if (part (partition)->fblock >= 0)
+ part (partition)->fblock += count;
+ part (partition)->smark = false;
+ part (partition)->emark = no_eof;
+ }
+ else if (IS_EOF (err))
+ {
+ get_pos (mt);
+ part (partition)->block = block;
+ if (part (partition)->file >= 0)
+ part (partition)->file += count > 0 ? 1 : -1;
+ part (partition)->fblock = count > 0 ? 0 : -1;
+ part (partition)->smark = (count > 0 && IS_SM (err));
+ part (partition)->emark = count > 0 ? eof : no_eof;
+ }
+ else if (IS_EOD (err))
+ {
+ get_pos (mt);
+ part (partition)->fblock = block - part (partition)->block;
+ part (partition)->block = block;
+ part (partition)->smark = false;
+ part (partition)->emark = IS_EOM (err) ? eom : eod;
+ }
+ else if (IS_BOT (err))
+ {
+ block = 0;
+ part (partition)->initialize (0);
+ }
+ break;
+ case TAPE_SPACE_SETMARKS:
+ get_pos (mt);
+ part (partition)->block = block;
+ if (!err)
+ {
+ part (partition)->file = -1;
+ part (partition)->fblock = -1;
+ part (partition)->smark = true;
+ }
+ break;
+ }
+ lasterr = err;
+out:
+ return error ("set_pos");
+}
- /* The following rewind in position 0 solves a problem which appears
- * in case of multi volume archives: The last ReadFile on first medium
- * returns ERROR_NO_DATA_DETECTED. After media change, all subsequent
- * ReadFile calls return ERROR_NO_DATA_DETECTED, too.
- * The call to tape_set_pos seems to reset some internal flags. */
- if (!tape_get_pos (&block) && !block)
- {
- debug_printf ("rewinding");
- tape_set_pos (TAPE_REWIND, 0);
- }
+int
+mtinfo_drive::create_partitions (HANDLE mt, long count)
+{
+ if (dp ()->MaximumPartitionCount <= 1)
+ return ERROR_INVALID_PARAMETER;
+ if (set_pos (mt, TAPE_REWIND, 0, false))
+ goto out;
+ debug_printf ("Format tape with %s partition(s)", count <= 0 ? "one" : "two");
+ TAPE_FUNC (CreateTapePartition (mt, TAPE_SELECT_PARTITIONS,
+ count <= 0 ? 1 : 2, 0));
+out:
+ return error ("partition");
+}
- if (flags & O_APPEND)
+int
+mtinfo_drive::set_partition (HANDLE mt, long count)
+{
+ if (count < 0 || (unsigned long) count >= MAX_PARTITION_NUM)
+ lasterr = ERROR_INVALID_PARAMETER;
+ else if ((DWORD) count >= dp ()->MaximumPartitionCount)
+ lasterr = ERROR_IO_DEVICE;
+ else
+ {
+ int part_block = part (count)->block >= 0 ? part (count)->block : 0;
+ int err = _set_pos (mt, TAPE_LOGICAL_BLOCK, part_block, count + 1);
+ if (err)
{
- /* In append mode, seek to beginning of next filemark */
- tape_set_pos (TAPE_SPACE_FILEMARKS, 1, true);
+ int sav_block = block;
+ int sav_partition = partition;
+ get_pos (mt);
+ if (sav_partition != partition)
+ {
+ if (partition < MAX_PARTITION_NUM
+ && part (partition)->block != block)
+ part (partition)->initialize (block);
+ }
+ else if (sav_block != block && partition < MAX_PARTITION_NUM)
+ part (partition)->initialize (block);
+ lasterr = err;
}
+ else
+ partition = count;
}
-
- return ret;
+ return error ("set_partition");
}
int
-fhandler_dev_tape::close (void)
+mtinfo_drive::write_marks (HANDLE mt, int marktype, DWORD count)
{
- struct mtop op;
- int ret = 0;
-
- if (is_writing)
+ if (marktype != TAPE_SETMARKS)
+ dirty = clean;
+ if (marktype == TAPE_FILEMARKS
+ && !get_feature (TAPE_DRIVE_WRITE_FILEMARKS))
{
- ret = writebuf ();
- if (has_written && !eom_detected)
+ if (get_feature (TAPE_DRIVE_WRITE_LONG_FMKS))
+ marktype = TAPE_LONG_FILEMARKS;
+ else
+ marktype = TAPE_SHORT_FILEMARKS;
+ }
+ TAPE_FUNC (WriteTapemark (mt, marktype, count, FALSE));
+ int err = lasterr;
+ if (!err)
+ {
+ block += count;
+ part (partition)->block += count;
+ if (part (partition)->file >= 0)
+ part (partition)->file += count;
+ part (partition)->fblock = 0;
+ part (partition)->emark = eof;
+ part (partition)->smark = (marktype == TAPE_SETMARKS);
+ }
+ else
+ {
+ int sav_block = block;
+ int sav_partition = partition;
+ get_pos (mt);
+ if (sav_partition != partition)
{
- /* if last operation was writing, write a filemark */
- debug_printf ("writing filemark");
- op.mt_op = MTWEOF;
- op.mt_count = 1;
- ioctl (MTIOCTOP, &op);
+ if (partition < MAX_PARTITION_NUM
+ && part (partition)->block != block)
+ part (partition)->initialize (block);
}
+ else if (sav_block != block && partition < MAX_PARTITION_NUM)
+ part (partition)->initialize (block);
+ lasterr = err;
}
+ return error ("write_marks");
+}
- // To protected reads on signaling (e.g. Ctrl-C)
- eof_detected = 1;
-
- if (is_rewind_device ())
+int
+mtinfo_drive::erase (HANDLE mt, int mode)
+{
+ switch (mode)
{
- debug_printf ("rewinding");
- tape_set_pos (TAPE_REWIND, 0);
+ case TAPE_ERASE_SHORT:
+ if (!get_feature (TAPE_DRIVE_ERASE_SHORT))
+ mode = TAPE_ERASE_LONG;
+ break;
+ case TAPE_ERASE_LONG:
+ if (!get_feature (TAPE_DRIVE_ERASE_LONG))
+ mode = TAPE_ERASE_SHORT;
+ break;
}
+ TAPE_FUNC (EraseTape (mt, mode, nowait ? TRUE : FALSE));
+ part (partition)->initialize (0);
+ return error ("erase");
+}
- if (ret)
+int
+mtinfo_drive::prepare (HANDLE mt, int action, bool is_auto)
+{
+ BOOL dont_wait = FALSE;
+
+ dirty = clean;
+ if (action == TAPE_UNLOAD || action == TAPE_LOAD || action == TAPE_TENSION)
+ dont_wait = nowait ? TRUE : FALSE;
+ TAPE_FUNC (PrepareTape (mt, action, dont_wait));
+ /* Reset buffer after all successful preparations but lock and unlock. */
+ switch (action)
{
- fhandler_dev_raw::close ();
- return ret;
+ case TAPE_FORMAT:
+ case TAPE_UNLOAD:
+ case TAPE_LOAD:
+ initialize (drive, false);
+ break;
+ case TAPE_TENSION:
+ part (partition)->initialize (0);
+ break;
+ case TAPE_LOCK:
+ lock = lasterr ? lock_error : is_auto ? auto_locked : locked;
+ break;
+ case TAPE_UNLOCK:
+ lock = lasterr ? lock_error : unlocked;
+ break;
}
-
- return fhandler_dev_raw::close ();
+ return error ("prepare");
}
int
-fhandler_dev_tape::fstat (struct __stat64 *buf)
+mtinfo_drive::set_compression (HANDLE mt, long count)
{
- int ret;
-
- if (!(ret = fhandler_base::fstat (buf)))
+ if (!get_feature (TAPE_DRIVE_SET_COMPRESSION))
+ return ERROR_INVALID_PARAMETER;
+ TAPE_SET_DRIVE_PARAMETERS sdp =
{
- struct mtget get;
-
- if (!ioctl (MTIOCGET, &get))
- buf->st_blocks = get.mt_capacity / buf->st_blksize;
- }
+ dp ()->ECC,
+ count ? TRUE : FALSE,
+ dp ()->DataPadding,
+ dp ()->ReportSetmarks,
+ dp ()->EOTWarningZoneSize
+ };
+ TAPE_FUNC (SetTapeParameters (mt, SET_TAPE_DRIVE_INFORMATION, &sdp));
+ int err = lasterr;
+ if (!err)
+ dp ()->Compression = sdp.Compression;
+ else
+ get_dp (mt);
+ lasterr = err;
+ return error ("set_compression");
+}
- return ret;
+int
+mtinfo_drive::set_blocksize (HANDLE mt, long count)
+{
+ TAPE_SET_MEDIA_PARAMETERS smp = {count};
+ TAPE_FUNC (SetTapeParameters (mt, SET_TAPE_MEDIA_INFORMATION, &smp));
+ return error ("set_blocksize");
}
-_off64_t
-fhandler_dev_tape::lseek (_off64_t offset, int whence)
+int
+mtinfo_drive::status (HANDLE mt, struct mtget *get)
{
- struct mtop op;
- struct mtpos pos;
+ int notape = 0;
+ DWORD tstat;
- debug_printf ("lseek (%s, %d, %d)", get_name (), offset, whence);
+ if (!get)
+ return ERROR_INVALID_PARAMETER;
- writebuf ();
+ if ((tstat = GetTapeStatus (mt)) == ERROR_NO_MEDIA_IN_DRIVE)
+ notape = 1;
- if (ioctl (MTIOCPOS, &pos))
+ memset (get, 0, sizeof *get);
+
+ get->mt_type = MT_ISUNKNOWN;
+
+ if (!notape && get_feature (TAPE_DRIVE_SET_BLOCK_SIZE))
+ get->mt_dsreg = (mp ()->BlockSize << MT_ST_BLKSIZE_SHIFT)
+ & MT_ST_BLKSIZE_MASK;
+ else
+ get->mt_dsreg = (dp ()->DefaultBlockSize << MT_ST_BLKSIZE_SHIFT)
+ & MT_ST_BLKSIZE_MASK;
+
+ if (wincap.has_ioctl_storage_get_media_types_ex ())
{
- return ILLEGAL_SEEK;
+ DWORD size = sizeof (GET_MEDIA_TYPES) + 10 * sizeof (DEVICE_MEDIA_INFO);
+ void *buf = alloca (size);
+ if (DeviceIoControl (mt, IOCTL_STORAGE_GET_MEDIA_TYPES_EX,
+ NULL, 0, buf, size, &size, NULL)
+ || GetLastError () == ERROR_MORE_DATA)
+ {
+ PGET_MEDIA_TYPES gmt = (PGET_MEDIA_TYPES) buf;
+ for (DWORD i = 0; i < gmt->MediaInfoCount; ++i)
+ {
+ PDEVICE_MEDIA_INFO dmi = &gmt->MediaInfo[i];
+ get->mt_type = dmi->DeviceSpecific.TapeInfo.MediaType;
+#define TINFO DeviceSpecific.TapeInfo
+ if (dmi->TINFO.MediaCharacteristics & MEDIA_CURRENTLY_MOUNTED)
+ {
+ get->mt_type = dmi->DeviceSpecific.TapeInfo.MediaType;
+ if (dmi->TINFO.BusType == BusTypeScsi)
+ get->mt_dsreg |=
+ (dmi->TINFO.BusSpecificData.ScsiInformation.DensityCode
+ << MT_ST_DENSITY_SHIFT)
+ & MT_ST_DENSITY_MASK;
+ break;
+ }
+#undef TINFO
+ }
+ }
}
- switch (whence)
+ if (!notape)
{
- case SEEK_END:
- op.mt_op = MTFSF;
- op.mt_count = 1;
- if (ioctl (MTIOCTOP, &op))
- return -1;
- break;
- case SEEK_SET:
- if (whence == SEEK_SET && offset < 0)
- {
- set_errno (EINVAL);
- return -1;
- }
- break;
- case SEEK_CUR:
- break;
- default:
- set_errno (EINVAL);
- return -1;
- }
+ get->mt_fileno = part (partition)->file;
+ get->mt_blkno = part (partition)->fblock;
+
+ if (get->mt_blkno == 0)
+ if (get->mt_fileno == 0)
+ get->mt_gstat |= GMT_BOT (-1);
+ else
+ get->mt_gstat |= GMT_EOF (-1);
+ if (part (partition)->emark >= eod_hit)
+ get->mt_gstat |= GMT_EOD (-1);
+ if (part (partition)->emark >= eom_hit)
+ get->mt_gstat |= GMT_EOT (-1);
+
+ if (part (partition)->smark)
+ get->mt_gstat |= GMT_SM (-1);
- op.mt_op = MTFSR;
- op.mt_count = offset / devbufsiz
- - (whence == SEEK_SET ? pos.mt_blkno : 0);
+ get->mt_gstat |= GMT_ONLINE (-1);
- if (op.mt_count < 0)
- {
- op.mt_op = MTBSR;
- op.mt_count = -op.mt_count;
- }
+ if (mp ()->WriteProtected)
+ get->mt_gstat |= GMT_WR_PROT (-1);
- if (ioctl (MTIOCTOP, &op) || ioctl (MTIOCPOS, &pos))
- return -1;
+ get->mt_capacity = get_ll (mp ()->Capacity);
+ get->mt_remaining = get_ll (mp ()->Remaining);
+ }
- return (pos.mt_blkno * devbufsiz);
+ if (notape)
+ get->mt_gstat |= GMT_DR_OPEN (-1);
+
+ if (buffer_writes)
+ get->mt_gstat |= GMT_IM_REP_EN (-1); /* TODO: Async writes */
+
+ else if (tstat == ERROR_DEVICE_REQUIRES_CLEANING)
+ get->mt_gstat |= GMT_CLN (-1);
+
+ /* Cygwin specials: */
+ if (dp ()->ReportSetmarks)
+ get->mt_gstat |= GMT_REP_SM (-1);
+ if (dp ()->DataPadding)
+ get->mt_gstat |= GMT_PADDING (-1);
+ if (dp ()->ECC)
+ get->mt_gstat |= GMT_HW_ECC (-1);
+ if (dp ()->Compression)
+ get->mt_gstat |= GMT_HW_COMP (-1);
+ if (two_fm)
+ get->mt_gstat |= GMT_TWO_FM (-1);
+ if (fast_eom)
+ get->mt_gstat |= GMT_FAST_MTEOM (-1);
+ if (auto_lock)
+ get->mt_gstat |= GMT_AUTO_LOCK (-1);
+ if (sysv)
+ get->mt_gstat |= GMT_SYSV (-1);
+ if (nowait)
+ get->mt_gstat |= GMT_NOWAIT (-1);
+
+ get->mt_erreg = 0; /* FIXME: No softerr counting */
+
+ get->mt_minblksize = dp ()->MinimumBlockSize;
+ get->mt_maxblksize = dp ()->MaximumBlockSize;
+ get->mt_defblksize = dp ()->DefaultBlockSize;
+ get->mt_featureslow = dp ()->FeaturesLow;
+ get->mt_featureshigh = dp ()->FeaturesHigh;
+ get->mt_eotwarningzonesize = dp ()->EOTWarningZoneSize;
+
+ return 0;
}
int
-fhandler_dev_tape::dup (fhandler_base *child)
+mtinfo_drive::set_options (HANDLE mt, long options)
{
- fhandler_dev_tape *fhc = (fhandler_dev_tape *) child;
+ long what = (options & MT_ST_OPTIONS);
+ bool call_setparams = false;
+ bool set;
+ TAPE_SET_DRIVE_PARAMETERS sdp =
+ {
+ dp ()->ECC,
+ dp ()->Compression,
+ dp ()->DataPadding,
+ dp ()->ReportSetmarks,
+ dp ()->EOTWarningZoneSize
+ };
- fhc->lasterr = lasterr;
- fhc->dp = dp;
- return fhandler_dev_raw::dup (child);
+ lasterr = 0;
+ switch (what)
+ {
+ case 0:
+ if (options == 0 || options == 1)
+ {
+ buffer_writes = (options == 1);
+ }
+ break;
+ case MT_ST_BOOLEANS:
+ buffer_writes = !!(options & MT_ST_BUFFER_WRITES);
+ two_fm = !!(options & MT_ST_TWO_FM);
+ fast_eom = !!(options & MT_ST_FAST_MTEOM);
+ auto_lock = !!(options & MT_ST_AUTO_LOCK);
+ sysv = !!(options & MT_ST_SYSV);
+ nowait = !!(options & MT_ST_NOWAIT);
+ if (get_feature (TAPE_DRIVE_SET_ECC))
+ sdp.ECC = !!(options & MT_ST_ECC);
+ if (get_feature (TAPE_DRIVE_SET_PADDING))
+ sdp.DataPadding = !!(options & MT_ST_PADDING);
+ if (get_feature (TAPE_DRIVE_SET_REPORT_SMKS))
+ sdp.ReportSetmarks = !!(options & MT_ST_REPORT_SM);
+ if (sdp.ECC != dp ()->ECC || sdp.DataPadding != dp ()->DataPadding
+ || sdp.ReportSetmarks != dp ()->ReportSetmarks)
+ call_setparams = true;
+ break;
+ case MT_ST_SETBOOLEANS:
+ case MT_ST_CLEARBOOLEANS:
+ set = (what == MT_ST_SETBOOLEANS);
+ if (options & MT_ST_BUFFER_WRITES)
+ buffer_writes = set;
+ if (options & MT_ST_TWO_FM)
+ two_fm = set;
+ if (options & MT_ST_FAST_MTEOM)
+ fast_eom = set;
+ if (options & MT_ST_AUTO_LOCK)
+ auto_lock = set;
+ if (options & MT_ST_SYSV)
+ sysv = set;
+ if (options & MT_ST_NOWAIT)
+ nowait = set;
+ if (options & MT_ST_ECC)
+ sdp.ECC = set;
+ if (options & MT_ST_PADDING)
+ sdp.DataPadding = set;
+ if (options & MT_ST_REPORT_SM)
+ sdp.ReportSetmarks = set;
+ if (sdp.ECC != dp ()->ECC || sdp.DataPadding != dp ()->DataPadding
+ || sdp.ReportSetmarks != dp ()->ReportSetmarks)
+ call_setparams = true;
+ break;
+ case MT_ST_EOT_WZ_SIZE:
+ if (get_feature (TAPE_DRIVE_SET_EOT_WZ_SIZE))
+ {
+ sdp.EOTWarningZoneSize = (options & ~MT_ST_OPTIONS);
+ if (sdp.EOTWarningZoneSize != dp ()->EOTWarningZoneSize)
+ call_setparams = true;
+ }
+ break;
+ }
+ if (call_setparams)
+ {
+ TAPE_FUNC (SetTapeParameters (mt, SET_TAPE_DRIVE_INFORMATION, &sdp));
+ int err = lasterr;
+ if (!err)
+ {
+ dp ()->ECC = sdp.ECC;
+ dp ()->DataPadding = sdp.DataPadding;
+ dp ()->ReportSetmarks = sdp.ReportSetmarks;
+ }
+ else
+ get_dp (mt);
+ lasterr = err;
+ }
+ return error ("set_options");
}
int
-fhandler_dev_tape::ioctl (unsigned int cmd, void *buf)
+mtinfo_drive::ioctl (HANDLE mt, unsigned int cmd, void *buf)
{
- int ret = NO_ERROR;
- unsigned long block;
-
if (cmd == MTIOCTOP)
{
+ if (__check_invalid_read_ptr (buf, sizeof (struct mtop)))
+ return ERROR_NOACCESS;
struct mtop *op = (struct mtop *) buf;
-
- if (!op)
- ret = ERROR_INVALID_PARAMETER;
- else
- switch (op->mt_op)
- {
+ if (lasterr == ERROR_BUS_RESET)
+ {
+ /* If a bus reset occurs, block further access to this device
+ until the user rewinds, unloads or in any other way tries
+ to maintain a well-known tape position. */
+ if (op->mt_op != MTREW && op->mt_op != MTOFFL
+ && op->mt_op != MTRETEN && op->mt_op != MTERASE
+ && op->mt_op != MTSEEK && op->mt_op != MTEOM)
+ return ERROR_BUS_RESET;
+ /* Try to maintain last lock state after bus reset. */
+ if (lock >= auto_locked && PrepareTape (mt, TAPE_LOCK, FALSE))
+ {
+ debug_printf ("Couldn't relock drive after bus reset.");
+ lock = unlocked;
+ }
+ }
+ switch (op->mt_op)
+ {
case MTRESET:
break;
case MTFSF:
- ret = tape_set_pos (TAPE_SPACE_FILEMARKS, op->mt_count);
+ set_pos (mt, TAPE_SPACE_FILEMARKS, op->mt_count, false);
break;
case MTBSF:
- ret = tape_set_pos (TAPE_SPACE_FILEMARKS, -op->mt_count);
+ set_pos (mt, TAPE_SPACE_FILEMARKS, -op->mt_count, false);
break;
case MTFSR:
- ret = tape_set_pos (TAPE_SPACE_RELATIVE_BLOCKS, op->mt_count);
+ set_pos (mt, TAPE_SPACE_RELATIVE_BLOCKS, op->mt_count, false);
break;
case MTBSR:
- ret = tape_set_pos (TAPE_SPACE_RELATIVE_BLOCKS, -op->mt_count);
+ set_pos (mt, TAPE_SPACE_RELATIVE_BLOCKS, -op->mt_count, false);
break;
case MTWEOF:
- if (tape_get_feature (TAPE_DRIVE_WRITE_FILEMARKS))
- ret = tape_write_marks (TAPE_FILEMARKS, op->mt_count);
- else if (tape_get_feature (TAPE_DRIVE_WRITE_LONG_FMKS))
- ret = tape_write_marks (TAPE_LONG_FILEMARKS, op->mt_count);
- else
- ret = tape_write_marks (TAPE_SHORT_FILEMARKS, op->mt_count);
+ write_marks (mt, TAPE_FILEMARKS, op->mt_count);
break;
case MTREW:
- ret = tape_set_pos (TAPE_REWIND, 0);
+ set_pos (mt, TAPE_REWIND, 0, false);
break;
case MTOFFL:
case MTUNLOAD:
- ret = tape_prepare (TAPE_UNLOAD);
+ prepare (mt, TAPE_UNLOAD);
break;
case MTNOP:
- reset_devbuf ();
+ lasterr = 0;
break;
case MTRETEN:
- if (!tape_get_feature (TAPE_DRIVE_END_OF_DATA))
- ret = ERROR_INVALID_PARAMETER;
- else if (!(ret = tape_set_pos (TAPE_REWIND, 0, false)))
- ret = tape_prepare (TAPE_TENSION);
+ if (!get_feature (TAPE_DRIVE_TENSION))
+ lasterr = ERROR_INVALID_PARAMETER;
+ else if (!set_pos (mt, TAPE_REWIND, 0, false))
+ prepare (mt, TAPE_TENSION);
break;
case MTBSFM:
- ret = tape_set_pos (TAPE_SPACE_FILEMARKS, -op->mt_count, true);
+ set_pos (mt, TAPE_SPACE_FILEMARKS, -op->mt_count, true);
break;
case MTFSFM:
- ret = tape_set_pos (TAPE_SPACE_FILEMARKS, op->mt_count, true);
+ set_pos (mt, TAPE_SPACE_FILEMARKS, op->mt_count, true);
break;
case MTEOM:
- if (tape_get_feature (TAPE_DRIVE_END_OF_DATA))
- ret = tape_set_pos (TAPE_SPACE_END_OF_DATA, 0);
+ if (fast_eom && get_feature (TAPE_DRIVE_END_OF_DATA))
+ set_pos (mt, TAPE_SPACE_END_OF_DATA, 0, false);
else
- ret = tape_set_pos (TAPE_SPACE_FILEMARKS, 32767);
+ set_pos (mt, TAPE_SPACE_FILEMARKS, 32767, false);
break;
case MTERASE:
- ret = tape_erase (TAPE_ERASE_LONG);
+ erase (mt, TAPE_ERASE_LONG);
break;
case MTRAS1:
case MTRAS2:
case MTRAS3:
- ret = ERROR_INVALID_PARAMETER;
+ lasterr = ERROR_INVALID_PARAMETER;
break;
case MTSETBLK:
- if (!tape_get_feature (TAPE_DRIVE_SET_BLOCK_SIZE))
+ if (!get_feature (TAPE_DRIVE_SET_BLOCK_SIZE))
{
- ret = ERROR_INVALID_PARAMETER;
+ lasterr = ERROR_INVALID_PARAMETER;
break;
}
- if ((devbuf && (size_t) op->mt_count == devbufsiz)
- || (!devbuf && op->mt_count == 0))
+ if ((DWORD) op->mt_count == mp ()->BlockSize)
{
/* Nothing has changed. */
- ret = 0;
+ lasterr = 0;
break;
}
- if ((op->mt_count == 0
- && !tape_get_feature (TAPE_DRIVE_VARIABLE_BLOCK))
+ if ((op->mt_count == 0 && !get_feature (TAPE_DRIVE_VARIABLE_BLOCK))
|| (op->mt_count > 0
- && ((DWORD) op->mt_count < dp.MinimumBlockSize
- || (DWORD) op->mt_count > dp.MaximumBlockSize)))
+ && ((DWORD) op->mt_count < dp ()->MinimumBlockSize
+ || (DWORD) op->mt_count > dp ()->MaximumBlockSize)))
{
- ret = ERROR_INVALID_PARAMETER;
+ lasterr = ERROR_INVALID_PARAMETER;
break;
}
- if (devbuf && devbufend - devbufstart > 0
- && (op->mt_count == 0
- || (op->mt_count > 0
- && (size_t) op->mt_count < devbufend - devbufstart)))
- {
- /* Not allowed if still data in devbuf. */
- ret = ERROR_INVALID_BLOCK_LENGTH; /* EIO */
- break;
- }
- if (!(ret = tape_set_blocksize (op->mt_count)))
- {
- char *buf = NULL;
- if (op->mt_count > 1L && !(buf = new char [op->mt_count]))
- {
- ret = ERROR_OUTOFMEMORY;
- break;
- }
- if (devbufsiz > 1L && op->mt_count > 1L)
- {
- memcpy (buf, devbuf + devbufstart,
- devbufend - devbufstart);
- devbufend -= devbufstart;
- }
- else
- devbufend = 0;
- devbufstart = 0;
- delete [] devbuf;
- devbuf = buf;
- devbufsiz = op->mt_count;
- varblkop = op->mt_count == 0;
- }
- reset_devbuf ();
+ if (set_blocksize (mt, op->mt_count)
+ && lasterr == ERROR_INVALID_FUNCTION)
+ lasterr = ERROR_INVALID_BLOCK_LENGTH;
break;
case MTSEEK:
- if (tape_get_feature (TAPE_DRIVE_LOGICAL_BLK))
- ret = tape_set_pos (TAPE_LOGICAL_BLOCK, op->mt_count);
- else if (!(ret = tape_get_pos (&block)))
- ret = tape_set_pos (TAPE_SPACE_RELATIVE_BLOCKS,
- op->mt_count - block);
+ if (get_feature (TAPE_DRIVE_LOGICAL_BLK))
+ set_pos (mt, TAPE_LOGICAL_BLOCK, op->mt_count, false);
+ else if (!get_pos (mt))
+ set_pos (mt, TAPE_SPACE_RELATIVE_BLOCKS,
+ op->mt_count - block, false);
break;
case MTTELL:
- if (!(ret = tape_get_pos (&block)))
+ if (!get_pos (mt))
op->mt_count = block;
break;
case MTFSS:
- ret = tape_set_pos (TAPE_SPACE_SETMARKS, op->mt_count);
+ set_pos (mt, TAPE_SPACE_SETMARKS, op->mt_count, false);
break;
case MTBSS:
- ret = tape_set_pos (TAPE_SPACE_SETMARKS, -op->mt_count);
+ set_pos (mt, TAPE_SPACE_SETMARKS, -op->mt_count, false);
break;
case MTWSM:
- ret = tape_write_marks (TAPE_SETMARKS, op->mt_count);
- reset_devbuf ();
+ write_marks (mt, TAPE_SETMARKS, op->mt_count);
break;
case MTLOCK:
- ret = tape_prepare (TAPE_LOCK);
+ prepare (mt, TAPE_LOCK);
break;
case MTUNLOCK:
- ret = tape_prepare (TAPE_UNLOCK);
+ prepare (mt, TAPE_UNLOCK);
break;
case MTLOAD:
- ret = tape_prepare (TAPE_LOAD);
+ prepare (mt, TAPE_LOAD);
break;
case MTCOMPRESSION:
- ret = tape_compression (op->mt_count);
+ set_compression (mt, op->mt_count);
break;
case MTSETPART:
- ret = tape_set_partition (op->mt_count);
- reset_devbuf ();
+ set_partition (mt, op->mt_count);
break;
case MTMKPART:
- ret = tape_partition (op->mt_count);
- reset_devbuf ();
+ create_partitions (mt, op->mt_count);
break;
- case MTSETDENSITY:
case MTSETDRVBUFFER:
- reset_devbuf ();
+ set_options (mt, op->mt_count);
+ break;
+ case MTSETDENSITY:
default:
- ret = ERROR_INVALID_PARAMETER;
+ lasterr = ERROR_INVALID_PARAMETER;
break;
- }
+ }
}
else if (cmd == MTIOCGET)
- ret = tape_status ((struct mtget *) buf);
- else if (cmd == MTIOCPOS)
{
- ret = ERROR_INVALID_PARAMETER;
- if (buf && (ret = tape_get_pos (&block)))
- ((struct mtpos *) buf)->mt_blkno = block;
+ if (__check_null_invalid_struct (buf, sizeof (struct mtget)))
+ return ERROR_NOACCESS;
+ status (mt, (struct mtget *) buf);
}
- else
- return fhandler_dev_raw::ioctl (cmd, buf);
-
- if (ret != NO_ERROR)
+ else if (cmd == MTIOCPOS)
{
- SetLastError (ret);
- __seterrno ();
- return -1;
+ if (__check_null_invalid_struct (buf, sizeof (struct mtpos)))
+ return ERROR_NOACCESS;
+ if (!get_pos (mt))
+ ((struct mtpos *) buf)->mt_blkno = block;
}
- return 0;
+ return lasterr;
}
-/* ------------------------------------------------------------------ */
-/* Private functions used by `ioctl' */
-/* ------------------------------------------------------------------ */
+/**********************************************************************/
+/* mtinfo */
-int
-fhandler_dev_tape::tape_error (const char *txt)
+void
+mtinfo::initialize (void)
{
- if (lasterr)
- debug_printf ("%s: error: %d", txt, lasterr);
- return lasterr;
+ char name[CYG_MAX_PATH];
+ HANDLE mtx;
+
+ shared_name (name, "mtinfo_mutex", 0);
+ if (!(mtx = CreateMutex (&sec_all_nih, FALSE, name)))
+ api_fatal ("CreateMutex '%s'(%p), %E. Terminating.", name);
+ WaitForSingleObject (mtx, INFINITE);
+ if (!magic)
+ {
+ magic = MTINFO_MAGIC;
+ version = MTINFO_VERSION;
+ for (unsigned i = 0; i < MAX_DRIVE_NUM; ++i)
+ drive (i)->initialize (i, true);
+ ReleaseMutex (mtx);
+ CloseHandle (mtx);
+ }
+ else
+ {
+ ReleaseMutex (mtx);
+ CloseHandle (mtx);
+ if (magic != MTINFO_MAGIC)
+ api_fatal ("MT magic number screwed up: %lu, should be %lu",
+ magic, MTINFO_MAGIC);
+ if (version != MTINFO_VERSION)
+ system_printf ("MT version number mismatch: %lu, should be %lu",
+ version, MTINFO_VERSION);
+ }
}
-int
-fhandler_dev_tape::tape_write_marks (int marktype, DWORD len)
+HANDLE mt_h;
+mtinfo *mt;
+
+void __stdcall
+mtinfo_init ()
{
- syscall_printf ("write_tapemark");
- TAPE_FUNC (WriteTapemark (get_handle (), marktype, len, FALSE));
- return tape_error ("tape_write_marks");
+ mt = (mtinfo *) open_shared ("mtinfo", MTINFO_VERSION, mt_h, sizeof (mtinfo), SH_MTINFO);
+ mt->initialize ();
}
-int
-fhandler_dev_tape::tape_get_pos (unsigned long *block,
- unsigned long *partition)
-{
- DWORD part, low, high;
+/**********************************************************************/
+/* fhandler_dev_tape */
- lasterr = ERROR_INVALID_PARAMETER;
- if (tape_get_feature (TAPE_DRIVE_GET_LOGICAL_BLK))
- TAPE_FUNC (GetTapePosition (get_handle (), TAPE_LOGICAL_POSITION,
- &part, &low, &high));
- else if (tape_get_feature (TAPE_DRIVE_GET_ABSOLUTE_BLK))
- TAPE_FUNC (GetTapePosition (get_handle (), TAPE_ABSOLUTE_POSITION,
- &part, &low, &high));
+#define lock(err_ret_val) if (!_lock ()) return err_ret_val;
- if (!tape_error ("tape_get_pos"))
+inline bool
+fhandler_dev_tape::_lock ()
+{
+ HANDLE obj[2] = { mt_mtx, signal_arrived };
+ BOOL ret = WaitForMultipleObjects (2, obj, FALSE, INFINITE) == WAIT_OBJECT_0;
+ if (!ret)
{
- if (block)
- *block = low;
- if (partition)
- *partition = part > 0 ? part - 1 : part;
+ debug_printf ("signal_arrived"); \
+ set_errno (EINTR);
}
+ return ret;
+}
- return lasterr;
+inline int
+fhandler_dev_tape::unlock (int ret)
+{
+ ReleaseMutex (mt_mtx);
+ return ret;
}
-int
-fhandler_dev_tape::_tape_set_pos (int mode, long count, int partition)
+fhandler_dev_tape::fhandler_dev_tape ()
+ : fhandler_dev_raw ()
{
- TAPE_FUNC (SetTapePosition (get_handle (), mode, partition, 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;
+ debug_printf ("unit: %d", dev ().minor);
}
int
-fhandler_dev_tape::tape_set_pos (int mode, long count, bool sfm_func)
+fhandler_dev_tape::open (int flags, mode_t)
{
- switch (mode)
+ int ret;
+
+ if (driveno () >= MAX_DRIVE_NUM)
{
- case TAPE_SPACE_RELATIVE_BLOCKS:
- case TAPE_SPACE_FILEMARKS:
- if (!count)
- {
- lasterr = 0;
- return tape_error ("tape_set_pos");
- }
- break;
+ set_errno (ENOENT);
+ return 0;
}
- _tape_set_pos (mode, count);
- switch (mode)
+ if (!(mt_mtx = CreateMutex (&sec_all, FALSE, NULL)))
{
- case TAPE_SPACE_FILEMARKS:
- if (!lasterr && sfm_func)
- return tape_set_pos (mode, count > 0 ? -1 : 1, false);
- break;
+ __seterrno ();
+ return 0;
}
- return tape_error ("tape_set_pos");
-}
-
-int
-fhandler_dev_tape::tape_erase (int mode)
-{
- if (tape_set_pos (TAPE_REWIND, 0))
- return lasterr;
- switch (mode)
+ /* The O_TEXT flag is used to indicate write-through (non buffered writes)
+ to the underlying fhandler_dev_raw::open call. */
+ flags &= ~O_TEXT;
+ if (!mt->drive (driveno ())->buffered_writes ())
+ flags |= O_TEXT;
+ ret = fhandler_dev_raw::open (flags);
+ if (ret)
{
- case TAPE_ERASE_SHORT:
- if (!tape_get_feature (TAPE_DRIVE_ERASE_SHORT))
- mode = TAPE_ERASE_LONG;
- break;
- case TAPE_ERASE_LONG:
- if (!tape_get_feature (TAPE_DRIVE_ERASE_LONG))
- mode = TAPE_ERASE_SHORT;
- break;
- }
- TAPE_FUNC (EraseTape (get_handle (), mode, false));
- /* Reset buffer after successful tape erasing. */
- if (!lasterr)
- reset_devbuf ();
- return tape_error ("tape_erase");
-}
+ mt->drive (driveno ())->open (get_handle ());
-int
-fhandler_dev_tape::tape_prepare (int action)
-{
- 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");
+ /* In append mode, seek to beginning of next filemark */
+ if (flags & O_APPEND)
+ mt->drive (driveno ())->set_pos (get_handle (),
+ TAPE_SPACE_FILEMARKS, 1, true);
+
+ devbufsiz = mt->drive (driveno ())->dp ()->MaximumBlockSize;
+ devbuf = new char (devbufsiz);
+ devbufstart = devbufend = 0;
+ }
+ else
+ ReleaseMutex (mt_mtx);
+ return ret;
}
int
-fhandler_dev_tape::tape_set_blocksize (long count)
+fhandler_dev_tape::close (void)
{
- TAPE_SET_MEDIA_PARAMETERS mp;
+ int ret, cret;
- mp.BlockSize = count;
- TAPE_FUNC (SetTapeParameters (get_handle (), SET_TAPE_MEDIA_INFORMATION,
- &mp));
- return tape_error ("tape_set_blocksize");
+ lock (-1);
+ ret = mt->drive (driveno ())->close (get_handle (), is_rewind_device ());
+ if (ret)
+ __seterrno_from_win_error (ret);
+ cret = fhandler_dev_raw::close ();
+ return unlock (ret ? -1 : cret);
}
-int
-fhandler_dev_tape::tape_status (struct mtget *get)
+void
+fhandler_dev_tape::raw_read (void *ptr, size_t &ulen)
{
- DWORD varlen;
- TAPE_GET_MEDIA_PARAMETERS mp;
- int notape = 0;
-
- if (!get)
- return ERROR_INVALID_PARAMETER;
-
- /* 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. */
- 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 && tape_get_feature (TAPE_DRIVE_SET_BLOCK_SIZE))
- get->mt_dsreg = (mp.BlockSize << MT_ST_BLKSIZE_SHIFT)
- & MT_ST_BLKSIZE_MASK;
- else
- get->mt_dsreg = (dp.DefaultBlockSize << MT_ST_BLKSIZE_SHIFT)
- & MT_ST_BLKSIZE_MASK;
+ char *buf = (char *) ptr;
+ size_t len = ulen;
+ size_t block_size;
+ size_t bytes_to_read;
+ size_t bytes_read = 0;
+ int ret = 0;
- if (wincap.has_ioctl_storage_get_media_types_ex ())
+ if (lastblk_to_read)
{
- DWORD size = sizeof (GET_MEDIA_TYPES) + 10 * sizeof (DEVICE_MEDIA_INFO);
- void *buf = alloca (size);
- if (DeviceIoControl (get_handle (), IOCTL_STORAGE_GET_MEDIA_TYPES_EX,
- NULL, 0, buf, size, &size, NULL)
- || GetLastError () == ERROR_MORE_DATA)
- {
- PGET_MEDIA_TYPES gmt = (PGET_MEDIA_TYPES) buf;
- for (DWORD i = 0; i < gmt->MediaInfoCount; ++i)
+ lastblk_to_read = 0;
+ ulen = 0;
+ return;
+ }
+ if (!_lock ())
+ {
+ ulen = (size_t) -1;
+ return;
+ }
+ block_size = mt->drive (driveno ())->mp ()->BlockSize;
+ if (devbufend > devbufstart)
+ {
+ bytes_to_read = min (len, devbufend - devbufstart);
+ debug_printf ("read %d bytes from buffer (rest %d)",
+ bytes_to_read, devbufend - devbufstart - bytes_to_read);
+ memcpy (buf, devbuf + devbufstart, bytes_to_read);
+ len -= bytes_to_read;
+ bytes_read += bytes_to_read;
+ buf += bytes_to_read;
+ devbufstart += bytes_to_read;
+ if (devbufstart == devbufend)
+ devbufstart = devbufend = 0;
+ /* If a switch to variable block_size occured, just return the buffer
+ remains until the buffer is empty, then proceed with usual variable
+ block size handling (one block per read call). */
+ if (!block_size)
+ len = 0;
+ }
+ if (len > 0)
+ {
+ size_t block_fit = !block_size ? len : rounddown(len, block_size);
+ if (block_fit)
+ {
+ debug_printf ("read %d bytes from tape (rest %d)",
+ block_fit, len - block_fit);
+ ret = mt->drive (driveno ())->read (get_handle (), buf, block_fit);
+ if (ret)
+ __seterrno_from_win_error (ret);
+ else if (block_fit)
{
- PDEVICE_MEDIA_INFO dmi = &gmt->MediaInfo[i];
- get->mt_type = dmi->DeviceSpecific.TapeInfo.MediaType;
-#define TINFO DeviceSpecific.TapeInfo
- if (dmi->TINFO.MediaCharacteristics & MEDIA_CURRENTLY_MOUNTED)
- {
- get->mt_type = dmi->DeviceSpecific.TapeInfo.MediaType;
- if (dmi->TINFO.BusType == BusTypeScsi)
- get->mt_dsreg |=
- (dmi->TINFO.BusSpecificData.ScsiInformation.DensityCode
- << MT_ST_DENSITY_SHIFT)
- & MT_ST_DENSITY_MASK;
- break;
- }
-#undef TINFO
+ len -= block_fit;
+ bytes_read += block_fit;
+ buf += block_fit;
+ /* Only one block in each read call, please. */
+ if (!block_size)
+ len = 0;
+ }
+ else {
+ len = 0;
+ if (bytes_read)
+ lastblk_to_read = 1;
+ }
+ }
+ if (!ret && len > 0)
+ {
+ debug_printf ("read %d bytes from tape (one block)", block_size);
+ ret = mt->drive (driveno ())->read (get_handle (), devbuf,
+ block_size);
+ if (ret)
+ __seterrno_from_win_error (ret);
+ else if (block_size)
+ {
+ devbufstart = len;
+ devbufend = block_size;
+ bytes_read += len;
+ memcpy (buf, devbuf, len);
}
+ else if (bytes_read)
+ lastblk_to_read = 1;
}
}
- if (notape)
- get->mt_gstat |= GMT_DR_OPEN (-1);
-
- if (!notape)
- {
- if (tape_get_feature (TAPE_DRIVE_GET_LOGICAL_BLK)
- || tape_get_feature (TAPE_DRIVE_GET_ABSOLUTE_BLK))
- tape_get_pos ((unsigned long *) &get->mt_blkno,
- (unsigned long *) &get->mt_resid);
+ if (ret)
+ ulen = (size_t) -1;
+ else
+ ulen = bytes_read;
+ unlock ();
+}
- if (!get->mt_blkno)
- get->mt_gstat |= GMT_BOT (-1);
+int
+fhandler_dev_tape::raw_write (const void *ptr, size_t len)
+{
+ lock (-1);
+ int ret = mt->drive (driveno ())->write (get_handle (), ptr, len);
+ __seterrno_from_win_error (ret);
+ return unlock (len);
+}
- get->mt_gstat |= GMT_ONLINE (-1);
+_off64_t
+fhandler_dev_tape::lseek (_off64_t offset, int whence)
+{
+ struct mtop op;
+ struct mtpos pos;
+ DWORD block_size;
+ _off64_t ret = ILLEGAL_SEEK;
- if (tape_get_feature (TAPE_DRIVE_WRITE_PROTECT) && mp.WriteProtected)
- get->mt_gstat |= GMT_WR_PROT (-1);
+ lock (ILLEGAL_SEEK);
- if (tape_get_feature (TAPE_DRIVE_TAPE_CAPACITY))
- get->mt_capacity = get_ll (mp.Capacity);
+ debug_printf ("lseek (%s, %d, %d)", get_name (), offset, whence);
- if (tape_get_feature (TAPE_DRIVE_TAPE_REMAINING))
- get->mt_remaining = get_ll (mp.Remaining);
+ block_size = mt->drive (driveno ())->mp ()->BlockSize;
+ if (block_size == 0)
+ {
+ set_errno (EIO);
+ goto out;
}
- if (tape_get_feature (TAPE_DRIVE_COMPRESSION) && dp.Compression)
- get->mt_gstat |= GMT_HW_COMP (-1);
+ if (ioctl (MTIOCPOS, &pos))
+ goto out;
- if (tape_get_feature (TAPE_DRIVE_ECC) && dp.ECC)
- get->mt_gstat |= GMT_HW_ECC (-1);
+ switch (whence)
+ {
+ case SEEK_END:
+ op.mt_op = MTFSF;
+ op.mt_count = 1;
+ if (ioctl (MTIOCTOP, &op))
+ goto out;
+ break;
+ case SEEK_SET:
+ if (whence == SEEK_SET && offset < 0)
+ {
+ set_errno (EINVAL);
+ goto out;
+ }
+ break;
+ case SEEK_CUR:
+ break;
+ default:
+ set_errno (EINVAL);
+ goto out;
+ }
- if (tape_get_feature (TAPE_DRIVE_PADDING) && dp.DataPadding)
- get->mt_gstat |= GMT_PADDING (-1);
+ op.mt_op = MTFSR;
+ op.mt_count = offset / block_size
+ - (whence == SEEK_SET ? pos.mt_blkno : 0);
- if (tape_get_feature (TAPE_DRIVE_REPORT_SMKS) && dp.ReportSetmarks)
- get->mt_gstat |= GMT_IM_REP_EN (-1);
+ if (op.mt_count < 0)
+ {
+ op.mt_op = MTBSR;
+ op.mt_count = -op.mt_count;
+ }
- get->mt_erreg = lasterr;
+ if (ioctl (MTIOCTOP, &op) || ioctl (MTIOCPOS, &pos))
+ goto out;
- get->mt_minblksize = dp.MinimumBlockSize;
- get->mt_maxblksize = dp.MaximumBlockSize;
- get->mt_defblksize = dp.DefaultBlockSize;
- get->mt_featureslow = dp.FeaturesLow;
- get->mt_featureshigh = dp.FeaturesHigh;
- get->mt_eotwarningzonesize = dp.EOTWarningZoneSize;
+ ret = pos.mt_blkno * block_size;
- return 0;
+out:
+ return unlock (ret);
}
int
-fhandler_dev_tape::tape_compression (long count)
+fhandler_dev_tape::fstat (struct __stat64 *buf)
{
- TAPE_SET_DRIVE_PARAMETERS dps;
-
- if (!tape_get_feature (TAPE_DRIVE_COMPRESSION))
- return ERROR_INVALID_PARAMETER;
+ int ret;
- 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");
+ if (driveno () >= MAX_DRIVE_NUM)
+ {
+ set_errno (ENOENT);
+ return -1;
+ }
+ if (!(ret = fhandler_base::fstat (buf)))
+ buf->st_blocks = 0;
+ return ret;
}
int
-fhandler_dev_tape::tape_partition (long count)
+fhandler_dev_tape::dup (fhandler_base *child)
{
- if (dp.MaximumPartitionCount <= 1)
- return ERROR_INVALID_PARAMETER;
- if (tape_set_pos (TAPE_REWIND, 0))
- return lasterr;
- if (count <= 0)
- debug_printf ("Formatting tape with one partition");
- else
- debug_printf ("Formatting tape with two partitions");
- TAPE_FUNC (CreateTapePartition (get_handle (), TAPE_SELECT_PARTITIONS,
- count <= 0 ? 1 : 2, 0));
- return tape_error ("tape_partition");
+ lock (-1);
+ return unlock (fhandler_dev_raw::dup (child));
}
int
-fhandler_dev_tape::tape_set_partition (long count)
+fhandler_dev_tape::ioctl (unsigned int cmd, void *buf)
{
- if (count < 0 || (unsigned long) count >= dp.MaximumPartitionCount)
- lasterr = ERROR_INVALID_PARAMETER;
- else
- lasterr = _tape_set_pos (TAPE_LOGICAL_BLOCK, 0, count + 1);
- return tape_error ("tape_set_partition");
+ int ret = 0;
+ lock (-1);
+ if (cmd == MTIOCTOP || cmd == MTIOCGET || cmd == MTIOCPOS)
+ {
+ ret = mt->drive (driveno ())->ioctl (get_handle (), cmd, buf);
+ if (ret)
+ __seterrno_from_win_error (ret);
+ return unlock (ret ? -1 : 0);
+ }
+ return unlock (fhandler_dev_raw::ioctl (cmd, buf));
}
diff --git a/winsup/cygwin/include/cygwin/mtio.h b/winsup/cygwin/include/cygwin/mtio.h
index 6aab34095..11e09f038 100644
--- a/winsup/cygwin/include/cygwin/mtio.h
+++ b/winsup/cygwin/include/cygwin/mtio.h
@@ -35,7 +35,7 @@ struct mtop {
};
/* Magnetic Tape operations [Not all operations supported by all drivers]: */
-#define MTRESET 0 /* +reset drive in case of problems */
+#define MTRESET 0 /* reset drive in case of problems */
#define MTFSF 1 /* forward space over FileMark,
* position at first record of next file
*/
@@ -80,15 +80,14 @@ struct mtop {
/* structure for MTIOCGET - mag tape get status command */
struct mtget {
- long mt_type; /* type of magtape device
- * Cygwin: MT_ISUNKNOWN */
+ long mt_type; /* type of magtape device */
long mt_resid; /* residual count: (not sure)
* number of bytes ignored, or
* number of files not skipped, or
* number of records not skipped.
* Cygwin: remaining KB until 1.5.7.
- * active partition since 1.5.8,
- * same as on linux.
+ * active partition since 1.5.8
+ * (same as on GNU-Linux).
*/
/* the following registers are device dependent */
long mt_dsreg; /* status register, Contains blocksize and
@@ -133,17 +132,27 @@ struct mtpos {
#define GMT_SM(x) ((x) & 0x10000000) /* DDS setmark */
#define GMT_EOD(x) ((x) & 0x08000000) /* DDS EOD */
#define GMT_WR_PROT(x) ((x) & 0x04000000)
-/* #define GMT_ ? ((x) & 0x02000000) */
+#define GMT_REP_SM(x) ((x) & 0x02000000) /* Cygwin: rep. setmarks */
#define GMT_ONLINE(x) ((x) & 0x01000000)
#define GMT_D_6250(x) ((x) & 0x00800000)
#define GMT_D_1600(x) ((x) & 0x00400000)
#define GMT_D_800(x) ((x) & 0x00200000)
-#define GMT_PADDING(x) ((x) & 0x00100000) /* data padding */
-#define GMT_HW_ECC(x) ((x) & 0x00080000) /* HW error correction */
+#define GMT_PADDING(x) ((x) & 0x00100000) /* Cygwin: data padding */
+#define GMT_HW_ECC(x) ((x) & 0x00080000) /* Cygwin: HW error corr. */
#define GMT_DR_OPEN(x) ((x) & 0x00040000) /* door open (no tape) */
-#define GMT_HW_COMP(x) ((x) & 0x00020000) /* HW compression */
+#define GMT_HW_COMP(x) ((x) & 0x00020000) /* Cygwin: HW compression */
#define GMT_IM_REP_EN(x) ((x) & 0x00010000) /* immediate report mode */
-/* 16 generic status bits unused */
+#define GMT_CLN(x) ((x) & 0x00008000) /* cleaning requested */
+/* 15 generic status bits unused */
+/* Cygwin only: The below settings are also used by the GNU-Linux SCSI tape
+ driver but they aren't usually reported here. Unfortunately, there's no
+ other official method to retrieve the values of these settings and
+ reporting them here apparently doesn't hurt. */
+#define GMT_TWO_FM(x) ((x) & 0x00000080) /* two fm after write */
+#define GMT_FAST_MTEOM(x) ((x) & 0x00000040) /* fast seek to eom */
+#define GMT_AUTO_LOCK(x) ((x) & 0x00000020) /* auto door lock on r/w */
+#define GMT_SYSV(x) ((x) & 0x00000010) /* SYSV read semantics */
+#define GMT_NOWAIT(x) ((x) & 0x00000008) /* don't wait for positioning commands */
/* SCSI-tape specific definitions */
@@ -156,6 +165,33 @@ struct mtpos {
#define MT_ST_SOFTERR_SHIFT 0
#define MT_ST_SOFTERR_MASK 0xffff
+/* Bitfields for the MTSETDRVBUFFER ioctl. */
+#define MT_ST_OPTIONS 0xf0000000
+#define MT_ST_BOOLEANS 0x10000000
+#define MT_ST_SETBOOLEANS 0x30000000
+#define MT_ST_CLEARBOOLEANS 0x40000000
+#define MT_ST_WRITE_THRESHOLD 0x20000000 /* Not supported */
+#define MT_ST_DEF_OPTIONS 0x60000000 /* Not supported */
+#define MT_ST_EOT_WZ_SIZE 0xf0000000 /* Cygwin only */
+
+#define MT_ST_BUFFER_WRITES 0x00000001
+#define MT_ST_ASYNC_WRITES 0x00000002 /* Not supported */
+#define MT_ST_READ_AHEAD 0x00000004 /* Not supported */
+#define MT_ST_DEBUGGING 0x00000008 /* Not supported */
+#define MT_ST_TWO_FM 0x00000010
+#define MT_ST_FAST_MTEOM 0x00000020
+#define MT_ST_AUTO_LOCK 0x00000040
+#define MT_ST_DEF_WRITES 0x00000080 /* Not supported */
+#define MT_ST_CAN_BSR 0x00000100 /* Not supported */
+#define MT_ST_NO_BLKLIMS 0x00000200 /* Not supported */
+#define MT_ST_CAN_PARTITIONS 0x00000400 /* Not supported */
+#define MT_ST_SCSI2LOGICAL 0x00000800 /* Not supported */
+#define MT_ST_SYSV 0x00001000
+#define MT_ST_NOWAIT 0x00002000
+#define MT_ST_ECC 0x00010000 /* Cygwin only */
+#define MT_ST_PADDING 0x00020000 /* Cygwin only */
+#define MT_ST_REPORT_SM 0x00040000 /* Cygwin only */
+
/*
* Constants for mt_type. Not all of these are supported,
* and these are not all of the ones that are supported.
diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h
index 04b7a007d..2db2e9bdc 100644
--- a/winsup/cygwin/include/cygwin/version.h
+++ b/winsup/cygwin/include/cygwin/version.h
@@ -238,12 +238,14 @@ details. */
timer_settime
111: Export sigqueue, sighold.
112: Redefine some mtget fields.
+ 113: Again redefine some mtget fields. Use mt_fileno and mt_blkno as
+ on Linux.
*/
/* Note that we forgot to bump the api for ualarm, strtoll, strtoull */
#define CYGWIN_VERSION_API_MAJOR 0
-#define CYGWIN_VERSION_API_MINOR 112
+#define CYGWIN_VERSION_API_MINOR 113
/* There is also a compatibity version number associated with the
shared memory regions. It is incremented when incompatible
diff --git a/winsup/cygwin/mtinfo.h b/winsup/cygwin/mtinfo.h
new file mode 100644
index 000000000..31260d17f
--- /dev/null
+++ b/winsup/cygwin/mtinfo.h
@@ -0,0 +1,133 @@
+/* mtinfo.h: Defininitions for the Cygwin tape driver class.
+
+ Copyright 2004 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license. Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#define MTINFO_MAGIC 0x179b2af0
+#define MTINFO_VERSION 1
+
+/* Maximum number of supported partitions per drive. */
+#define MAX_PARTITION_NUM 64
+/* Maximum number of supported drives. */
+#define MAX_DRIVE_NUM 8
+
+/* Values for bookkeeping of the tape position relative to filemarks
+ and eod/eom. */
+enum eom_val
+{
+ no_eof,
+ eof_hit,
+ eof,
+ eod_hit,
+ eod,
+ eom_hit,
+ eom
+};
+
+enum dirty_state
+{
+ clean,
+ has_read,
+ has_written
+};
+
+enum lock_state
+{
+ unlocked,
+ lock_error,
+ auto_locked,
+ locked
+};
+
+/* Partition specific information */
+class mtinfo_part
+{
+public:
+ long block; /* logical block no */
+ long file; /* current file no */
+ long fblock; /* relative block no */
+ bool smark; /* At setmark? */
+ eom_val emark; /* "end-of"-mark */
+
+ void initialize (long nblock = -1);
+};
+
+class mtinfo_drive
+{
+ int drive;
+ int lasterr;
+ long partition;
+ long block;
+ dirty_state dirty;
+ lock_state lock;
+ TAPE_GET_DRIVE_PARAMETERS _dp;
+ TAPE_GET_MEDIA_PARAMETERS _mp;
+ bool buffer_writes;
+ bool two_fm;
+ bool fast_eom;
+ bool auto_lock;
+ bool sysv;
+ bool nowait;
+ mtinfo_part _part[MAX_PARTITION_NUM];
+
+ inline int error (const char *str)
+ {
+ if (lasterr)
+ debug_printf ("%s: Win32 error %d", lasterr);
+ return lasterr;
+ }
+ inline bool get_feature (DWORD parm)
+ {
+ return ((parm & TAPE_DRIVE_HIGH_FEATURES)
+ ? ((_dp.FeaturesHigh & parm) != 0)
+ : ((_dp.FeaturesLow & parm) != 0));
+ }
+ int get_pos (HANDLE mt, long *ppartition = NULL, long *pblock = NULL);
+ int _set_pos (HANDLE mt, int mode, long count, int partition);
+ int create_partitions (HANDLE mt, long count);
+ int set_partition (HANDLE mt, long count);
+ int write_marks (HANDLE mt, int marktype, DWORD count);
+ int erase (HANDLE mt, int mode);
+ int prepare (HANDLE mt, int action, bool is_auto = false);
+ int set_compression (HANDLE mt, long count);
+ int set_blocksize (HANDLE mt, long count);
+ int status (HANDLE mt, struct mtget *get);
+ int set_options (HANDLE mt, long options);
+
+public:
+ void initialize (int num, bool first_time);
+ int get_dp (HANDLE mt);
+ int get_mp (HANDLE mt);
+ int open (HANDLE mt);
+ int close (HANDLE mt, bool rewind);
+ int read (HANDLE mt, void *ptr, size_t &ulen);
+ int write (HANDLE mt, const void *ptr, size_t &len);
+ int ioctl (HANDLE mt, unsigned int cmd, void *buf);
+ int set_pos (HANDLE mt, int mode, long count, bool sfm_func);
+
+ inline bool buffered_writes (void) { return buffer_writes; }
+ PTAPE_GET_DRIVE_PARAMETERS dp (void) { return &_dp; }
+ PTAPE_GET_MEDIA_PARAMETERS mp (void) { return &_mp; }
+ mtinfo_part *part (int num) { return &_part[num]; }
+};
+
+class mtinfo
+{
+ DWORD magic;
+ DWORD version;
+ mtinfo_drive _drive[MAX_DRIVE_NUM];
+
+public:
+ void initialize (void);
+ mtinfo_drive *drive (int num) { return &_drive[num]; }
+};
+
+extern HANDLE mt_h;
+extern mtinfo *mt;
+
+extern void __stdcall mtinfo_init ();
diff --git a/winsup/cygwin/shared.cc b/winsup/cygwin/shared.cc
index 9a91a1c08..42beb54f9 100644
--- a/winsup/cygwin/shared.cc
+++ b/winsup/cygwin/shared.cc
@@ -26,6 +26,7 @@ details. */
#include "registry.h"
#include "cygwin_version.h"
#include "child_info.h"
+#include "mtinfo.h"
shared_info NO_COPY *cygwin_shared;
user_info NO_COPY *user_shared;
@@ -62,7 +63,13 @@ static char *offsets[] =
+ pround (sizeof (shared_info))
+ pround (sizeof (user_info))
+ pround (sizeof (console_state))
+ + pround (sizeof (_pinfo)),
+ (char *) cygwin_shared_address
+ + pround (sizeof (shared_info))
+ + pround (sizeof (user_info))
+ + pround (sizeof (console_state))
+ pround (sizeof (_pinfo))
+ + pround (sizeof (mtinfo))
};
void * __stdcall
@@ -243,6 +250,7 @@ memory_init ()
ProtectHandleINH (cygheap->shared_h);
user_shared_initialize (false);
+ mtinfo_init ();
}
unsigned
diff --git a/winsup/cygwin/shared_info.h b/winsup/cygwin/shared_info.h
index 4264d5eeb..114cf0bc6 100644
--- a/winsup/cygwin/shared_info.h
+++ b/winsup/cygwin/shared_info.h
@@ -176,6 +176,7 @@ enum shared_locations
SH_USER_SHARED,
SH_SHARED_CONSOLE,
SH_MYSELF,
+ SH_MTINFO,
SH_TOTAL_SIZE
};
void __stdcall memory_init ();