diff options
Diffstat (limited to 'winsup/cygwin/fhandler_tape.cc')
-rw-r--r-- | winsup/cygwin/fhandler_tape.cc | 1517 |
1 files changed, 0 insertions, 1517 deletions
diff --git a/winsup/cygwin/fhandler_tape.cc b/winsup/cygwin/fhandler_tape.cc deleted file mode 100644 index 036407685..000000000 --- a/winsup/cygwin/fhandler_tape.cc +++ /dev/null @@ -1,1517 +0,0 @@ -/* fhandler_tape.cc. See fhandler.h for a description of the fhandler - classes. - - Copyright 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006 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. */ - -#include "winsup.h" -#include "cygtls.h" -#include <sys/termios.h> -#include <unistd.h> -#include <stdlib.h> -#include <sys/mtio.h> -#include <sys/param.h> -#include <ddk/ntddstor.h> -#include "cygerrno.h" -#include "perprocess.h" -#include "security.h" -#include "path.h" -#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. */ -#define TAPE_FUNC(func) while ((lasterr = (func)) == ERROR_MEDIA_CHANGED) \ - { \ - initialize (drive, false); \ - part (partition)->initialize (0); \ - } - -#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) - -/**********************************************************************/ -/* mtinfo_part */ - -void -mtinfo_part::initialize (long nblock) -{ - 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); - async_writes (false); - 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 -mtinfo_drive::get_dp (HANDLE mt) -{ - DWORD len = sizeof _dp; - TAPE_FUNC (GetTapeParameters (mt, GET_TAPE_DRIVE_INFORMATION, &len, &_dp)); - return error ("get_dp"); -} - -int -mtinfo_drive::get_mp (HANDLE mt) -{ - DWORD len = sizeof _mp; - TAPE_FUNC (GetTapeParameters (mt, GET_TAPE_MEDIA_INFORMATION, &len, &_mp)); - return error ("get_mp"); -} - -int -mtinfo_drive::open (HANDLE mt) -{ - 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"); -} - -int -mtinfo_drive::close (HANDLE mt, bool rewind) -{ - lasterr = 0; - if (GetTapeStatus (mt) == ERROR_NO_MEDIA_IN_DRIVE) - dirty = clean; - if (dirty >= has_written) - { - /* If an async write is still pending, wait for completion. */ - if (dirty == async_write_pending) - lasterr = async_wait (mt, NULL); - if (!lasterr) - { - /* 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 2nd fmark. */ - { - set_pos (mt, TAPE_SPACE_FILEMARKS, -1, false); - if (!lasterr) - part (partition)->fblock = 0; /* That's obvious, isn't it? */ - } - } - } - else if (dirty == has_read && !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"); -} - -int -mtinfo_drive::read (HANDLE mt, HANDLE mt_evt, void *ptr, size_t &ulen) -{ - BOOL ret; - DWORD bytes_read = 0; - - if (GetTapeStatus (mt) == ERROR_NO_MEDIA_IN_DRIVE) - return lasterr = ERROR_NO_MEDIA_IN_DRIVE; - if (lasterr == ERROR_BUS_RESET) - { - ulen = 0; - goto out; - } - /* If an async write is still pending, wait for completion. */ - if (dirty == async_write_pending) - lasterr = async_wait (mt, NULL); - 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); - ov.Offset = ov.OffsetHigh = 0; - ov.hEvent = mt_evt; - ret = ReadFile (mt, ptr, ulen, &bytes_read, &ov); - lasterr = ret ? 0 : GetLastError (); - if (lasterr == ERROR_IO_PENDING) - lasterr = async_wait (mt, &bytes_read); - 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"); -} - -int -mtinfo_drive::async_wait (HANDLE mt, DWORD *bytes_written) -{ - DWORD written; - - bool ret = GetOverlappedResult (mt, &ov, &written, TRUE); - if (bytes_written) - *bytes_written = written; - return ret ? 0 : GetLastError (); -} - -int -mtinfo_drive::write (HANDLE mt, HANDLE mt_evt, const void *ptr, size_t &len) -{ - BOOL ret; - DWORD bytes_written = 0; - int async_err = 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"); - } - if (dirty == async_write_pending) - async_err = async_wait (mt, &bytes_written); - dirty = clean; - part (partition)->smark = false; - if (auto_lock () && lock < auto_locked) - prepare (mt, TAPE_LOCK, true); - ov.Offset = ov.OffsetHigh = 0; - ov.hEvent = mt_evt; - ret = WriteFile (mt, ptr, len, &bytes_written, &ov); - lasterr = ret ? 0: GetLastError (); - if (lasterr == ERROR_IO_PENDING) - { - if (async_writes () && mp ()->BlockSize == 0) - dirty = async_write_pending; - else - /* Wait for completion if a non-async write. */ - lasterr = async_wait (mt, &bytes_written); - } - 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 && async_err) - lasterr = async_err; - 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; - else if (lasterr == ERROR_IO_PENDING) - dirty = async_write_pending; - } - return error ("write"); -} - -int -mtinfo_drive::get_pos (HANDLE mt, long *ppartition, long *pblock) -{ - DWORD p, low, high; - - 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) - { - if (p > 0) - partition = (long) p - 1; - block = (long) low; - if (ppartition) - *ppartition= partition; - if (pblock) - *pblock = block; - } - else - { - partition = 0; - block = -1; - } - return error ("get_pos"); -} - -int -mtinfo_drive::_set_pos (HANDLE mt, int mode, long count, int partition, - BOOL dont_wait) -{ - /* If an async write is still pending, wait for completion. */ - if (dirty == async_write_pending) - lasterr = async_wait (mt, NULL); - dirty = clean; - TAPE_FUNC (SetTapePosition (mt, mode, partition, count, count < 0 ? -1 : 0, - dont_wait)); - return lasterr; -} - -int -mtinfo_drive::set_pos (HANDLE mt, int mode, long count, - bool sfm_func) -{ - int err = 0; - long undone = count; - BOOL dont_wait = FALSE; - - 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, FALSE)) || IS_SM (err)) - --undone; - while (!err && undone < 0) - if (!(err = _set_pos (mt, mode, -1, 0, FALSE)) || IS_SM (err)) - ++undone; - } - else - err = _set_pos (mt, mode, count, 0, 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"); -} - -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; - partition = 0; - part (partition)->initialize (0); - debug_printf ("Format tape with %s partition(s)", count <= 0 ? "one" : "two"); - if (get_feature (TAPE_DRIVE_INITIATOR)) - { - if (count <= 0) - TAPE_FUNC (CreateTapePartition (mt, TAPE_INITIATOR_PARTITIONS, - count <= 0 ? 0 : 2, (DWORD) count)); - } - else if (get_feature (TAPE_DRIVE_FIXED)) - { - /* This is supposed to work for Tandberg SLR drivers up to version - 1.6 which missed to set the TAPE_DRIVE_INITIATOR flag. According - to Tandberg, CreateTapePartition(TAPE_FIXED_PARTITIONS) apparently - does not ignore the dwCount parameter. Go figure! */ - TAPE_FUNC (CreateTapePartition (mt, TAPE_FIXED_PARTITIONS, - count <= 0 ? 0 : 2, (DWORD) count)); - } - else - lasterr = ERROR_INVALID_PARAMETER; -out: - return error ("partition"); -} - -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, FALSE); - if (err) - { - 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; - if (part (partition)->block == -1) - part (partition)->initialize (0); - } - } - return error ("set_partition"); -} - -int -mtinfo_drive::write_marks (HANDLE mt, int marktype, DWORD count) -{ - /* If an async write is still pending, wait for completion. */ - if (dirty == async_write_pending) - { - lasterr = async_wait (mt, NULL); - dirty = has_written; - } - if (marktype != TAPE_SETMARKS) - dirty = clean; - if (marktype == TAPE_FILEMARKS - && !get_feature (TAPE_DRIVE_WRITE_FILEMARKS)) - { - 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 (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"); -} - -int -mtinfo_drive::erase (HANDLE mt, int mode) -{ - switch (mode) - { - 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"); -} - -int -mtinfo_drive::prepare (HANDLE mt, int action, bool is_auto) -{ - BOOL dont_wait = FALSE; - - /* If an async write is still pending, wait for completion. */ - if (dirty == async_write_pending) - lasterr = async_wait (mt, NULL); - 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) - { - 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 error ("prepare"); -} - -int -mtinfo_drive::set_compression (HANDLE mt, long count) -{ - if (!get_feature (TAPE_DRIVE_SET_COMPRESSION)) - return ERROR_INVALID_PARAMETER; - TAPE_SET_DRIVE_PARAMETERS sdp = - { - 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"); -} - -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"); -} - -int -mtinfo_drive::get_status (HANDLE mt, struct mtget *get) -{ - int notape = 0; - DWORD tstat; - - if (!get) - return ERROR_INVALID_PARAMETER; - - if ((tstat = GetTapeStatus (mt)) == ERROR_NO_MEDIA_IN_DRIVE) - notape = 1; - - 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 ()) - { - 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 - } - } - } - - if (!notape) - { - get->mt_resid = partition; - 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); - - get->mt_gstat |= GMT_ONLINE (-1); - - if (mp ()->WriteProtected) - get->mt_gstat |= GMT_WR_PROT (-1); - - get->mt_capacity = get_ll (mp ()->Capacity); - get->mt_remaining = get_ll (mp ()->Remaining); - } - - if (notape) - get->mt_gstat |= GMT_DR_OPEN (-1); - - if (buffer_writes ()) - get->mt_gstat |= GMT_IM_REP_EN (-1); /* TODO: Async writes */ - - 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); - if (async_writes ()) - get->mt_gstat |= GMT_ASYNC (-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 -mtinfo_drive::set_options (HANDLE mt, long options) -{ - 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 - }; - - 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)); - async_writes (!!(options & MT_ST_ASYNC_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_ASYNC_WRITES) - async_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 -mtinfo_drive::ioctl (HANDLE mt, unsigned int cmd, void *buf) -{ - myfault efault; - if (efault.faulted ()) - return ERROR_NOACCESS; - if (cmd == MTIOCTOP) - { - struct mtop *op = (struct mtop *) buf; - 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: - set_pos (mt, TAPE_SPACE_FILEMARKS, op->mt_count, false); - break; - case MTBSF: - set_pos (mt, TAPE_SPACE_FILEMARKS, -op->mt_count, false); - break; - case MTFSR: - set_pos (mt, TAPE_SPACE_RELATIVE_BLOCKS, op->mt_count, false); - break; - case MTBSR: - set_pos (mt, TAPE_SPACE_RELATIVE_BLOCKS, -op->mt_count, false); - break; - case MTWEOF: - write_marks (mt, TAPE_FILEMARKS, op->mt_count); - break; - case MTREW: - set_pos (mt, TAPE_REWIND, 0, false); - break; - case MTOFFL: - case MTUNLOAD: - prepare (mt, TAPE_UNLOAD); - break; - case MTNOP: - lasterr = 0; - break; - case MTRETEN: - 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: - set_pos (mt, TAPE_SPACE_FILEMARKS, -op->mt_count, true); - break; - case MTFSFM: - set_pos (mt, TAPE_SPACE_FILEMARKS, op->mt_count, true); - break; - case MTEOM: - if (fast_eom () && get_feature (TAPE_DRIVE_END_OF_DATA)) - set_pos (mt, TAPE_SPACE_END_OF_DATA, 0, false); - else - set_pos (mt, TAPE_SPACE_FILEMARKS, 32767, false); - break; - case MTERASE: - erase (mt, TAPE_ERASE_LONG); - break; - case MTRAS1: - case MTRAS2: - case MTRAS3: - lasterr = ERROR_INVALID_PARAMETER; - break; - case MTSETBLK: - if (!get_feature (TAPE_DRIVE_SET_BLOCK_SIZE)) - { - lasterr = ERROR_INVALID_PARAMETER; - break; - } - if ((DWORD) op->mt_count == mp ()->BlockSize) - { - /* Nothing has changed. */ - lasterr = 0; - break; - } - 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))) - { - lasterr = ERROR_INVALID_PARAMETER; - break; - } - if (set_blocksize (mt, op->mt_count) - && lasterr == ERROR_INVALID_FUNCTION) - lasterr = ERROR_INVALID_BLOCK_LENGTH; - break; - case MTSEEK: - 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 (!get_pos (mt)) - op->mt_count = block; - break; - case MTFSS: - set_pos (mt, TAPE_SPACE_SETMARKS, op->mt_count, false); - break; - case MTBSS: - set_pos (mt, TAPE_SPACE_SETMARKS, -op->mt_count, false); - break; - case MTWSM: - write_marks (mt, TAPE_SETMARKS, op->mt_count); - break; - case MTLOCK: - prepare (mt, TAPE_LOCK); - break; - case MTUNLOCK: - prepare (mt, TAPE_UNLOCK); - break; - case MTLOAD: - prepare (mt, TAPE_LOAD); - break; - case MTCOMPRESSION: - set_compression (mt, op->mt_count); - break; - case MTSETPART: - set_partition (mt, op->mt_count); - break; - case MTMKPART: - create_partitions (mt, op->mt_count); - break; - case MTSETDRVBUFFER: - set_options (mt, op->mt_count); - break; - case MTSETDENSITY: - default: - lasterr = ERROR_INVALID_PARAMETER; - break; - } - } - else if (cmd == MTIOCGET) - get_status (mt, (struct mtget *) buf); - else if (cmd == MTIOCPOS && !get_pos (mt)) - ((struct mtpos *) buf)->mt_blkno = block; - - return lasterr; -} - -/**********************************************************************/ -/* mtinfo */ - -void -mtinfo::initialize () -{ - 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', %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); - } -} - -static mtinfo mt __attribute__((section (".cygwin_dll_common"), shared)); - -void __stdcall -mtinfo_init () -{ - mt.initialize (); -} - -/**********************************************************************/ -/* fhandler_dev_tape */ - -#define lock(err_ret_val) if (!_lock ()) return err_ret_val; - -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) - { - debug_printf ("signal_arrived"); \ - set_errno (EINTR); - } - return ret; -} - -inline int -fhandler_dev_tape::unlock (int ret) -{ - ReleaseMutex (mt_mtx); - return ret; -} - -fhandler_dev_tape::fhandler_dev_tape () - : fhandler_dev_raw () -{ - debug_printf ("unit: %d", dev ().minor); -} - -int -fhandler_dev_tape::open (int flags, mode_t) -{ - int ret; - - if (driveno () >= MAX_DRIVE_NUM) - { - set_errno (ENOENT); - return 0; - } - if (!(mt_mtx = CreateMutex (&sec_all, TRUE, NULL))) - { - __seterrno (); - return 0; - } - - /* The O_SYNC flag is not supported by the tape driver. Use the - MT_ST_BUFFER_WRITES and MT_ST_ASYNC_WRITES flags in the drive - settings instead. In turn, the MT_ST_BUFFER_WRITES is translated - into O_SYNC, which controls the FILE_WRITE_THROUGH flag in the - NtCreateFile call in fhandler_base::open. */ - flags &= ~O_SYNC; - if (!mt.drive (driveno ())->buffer_writes ()) - flags |= O_SYNC; - - ret = fhandler_dev_raw::open (flags); - if (ret) - { - mt.drive (driveno ())->open (get_handle ()); - - /* 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); - - if (!(flags & O_DIRECT)) - { - devbufsiz = mt.drive (driveno ())->dp ()->MaximumBlockSize; - devbuf = new char [devbufsiz]; - } - devbufstart = devbufend = 0; - } - else - ReleaseMutex (mt_mtx); - return ret; -} - -int -fhandler_dev_tape::close () -{ - int ret = 0; - int cret = 0; - - if (!hExeced) - { - lock (-1); - ret = mt.drive (driveno ())->close (get_handle (), is_rewind_device ()); - if (ret) - __seterrno_from_win_error (ret); - cret = fhandler_dev_raw::close (); - unlock (0); - } - if (mt_evt) - CloseHandle (mt_evt); - CloseHandle (mt_mtx); - return ret ? -1 : cret; -} - -void -fhandler_dev_tape::raw_read (void *ptr, size_t &ulen) -{ - 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 (lastblk_to_read ()) - { - lastblk_to_read (false); - ulen = 0; - return; - } - if (!_lock ()) - { - ulen = (size_t) -1; - return; - } - block_size = mt.drive (driveno ())->mp ()->BlockSize; - if (devbuf) - { - 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) - { - if (!mt_evt && !(mt_evt = CreateEvent (&sec_none, TRUE, FALSE, NULL))) - debug_printf ("Creating event failed, %E"); - 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 (), mt_evt, buf, - block_fit); - if (ret) - __seterrno_from_win_error (ret); - else if (block_fit) - { - 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 (true); - } - } - if (!ret && len > 0) - { - debug_printf ("read %d bytes from tape (one block)", block_size); - ret = mt.drive (driveno ())->read (get_handle (), mt_evt, 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 (true); - } - } - } - else - { - if (!mt_evt && !(mt_evt = CreateEvent (&sec_none, TRUE, FALSE, NULL))) - debug_printf ("Creating event failed, %E"); - bytes_read = ulen; - ret = mt.drive (driveno ())->read (get_handle (), mt_evt, ptr, - bytes_read); - } - ulen = (ret ? (size_t) -1 : bytes_read); - unlock (); -} - -int -fhandler_dev_tape::raw_write (const void *ptr, size_t len) -{ - lock (-1); - if (!mt_evt && !(mt_evt = CreateEvent (&sec_none, TRUE, FALSE, NULL))) - debug_printf ("Creating event failed, %E"); - int ret = mt.drive (driveno ())->write (get_handle (), mt_evt, ptr, len); - if (ret) - __seterrno_from_win_error (ret); - return unlock (ret ? -1 : (int) len); -} - -_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; - - lock (ILLEGAL_SEEK); - - debug_printf ("lseek (%s, %d, %d)", get_name (), offset, whence); - - block_size = mt.drive (driveno ())->mp ()->BlockSize; - if (block_size == 0) - { - set_errno (EIO); - goto out; - } - - if (ioctl (MTIOCPOS, &pos)) - goto out; - - 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; - } - - op.mt_op = MTFSR; - op.mt_count = offset / block_size - - (whence == SEEK_SET ? pos.mt_blkno : 0); - - if (op.mt_count < 0) - { - op.mt_op = MTBSR; - op.mt_count = -op.mt_count; - } - - if (ioctl (MTIOCTOP, &op) || ioctl (MTIOCPOS, &pos)) - goto out; - - ret = pos.mt_blkno * block_size; - -out: - return unlock (ret); -} - -int -fhandler_dev_tape::fstat (struct __stat64 *buf) -{ - int ret; - - 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::dup (fhandler_base *child) -{ - lock (-1); - fhandler_dev_tape *fh = (fhandler_dev_tape *) child; - if (!DuplicateHandle (hMainProc, mt_mtx, hMainProc, &fh->mt_mtx, 0, TRUE, - DUPLICATE_SAME_ACCESS)) - { - debug_printf ("dup(%s) failed, mutex handle %x, %E", - get_name (), mt_mtx); - __seterrno (); - return unlock (-1); - } - fh->mt_evt = NULL; - if (mt_evt && - !DuplicateHandle (hMainProc, mt_evt, hMainProc, &fh->mt_evt, 0, TRUE, - DUPLICATE_SAME_ACCESS)) - { - debug_printf ("dup(%s) failed, event handle %x, %E", - get_name (), mt_evt); - __seterrno (); - return unlock (-1); - } - return unlock (fhandler_dev_raw::dup (child)); -} - -void -fhandler_dev_tape::fixup_after_fork (HANDLE parent) -{ - fhandler_dev_raw::fixup_after_fork (parent); - fork_fixup (parent, mt_mtx, "mt_mtx"); - if (mt_evt) - fork_fixup (parent, mt_evt, "mt_evt"); -} - -void -fhandler_dev_tape::set_close_on_exec (bool val) -{ - fhandler_dev_raw::set_close_on_exec (val); - set_no_inheritance (mt_mtx, val); - if (mt_evt) - set_no_inheritance (mt_evt, val); -} - -int -fhandler_dev_tape::ioctl (unsigned int cmd, void *buf) -{ - 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)); -} |