2000-02-18 03:38:33 +08:00
|
|
|
/* fhandler_tape.cc. See fhandler.h for a description of the fhandler
|
|
|
|
classes.
|
|
|
|
|
2004-02-09 12:04:24 +08:00
|
|
|
Copyright 1999, 2000, 2001, 2002, 2003, 2004 Red Hat, Inc.
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
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. */
|
|
|
|
|
2000-08-03 00:28:18 +08:00
|
|
|
#include "winsup.h"
|
2000-02-18 03:38:33 +08:00
|
|
|
#include <sys/termios.h>
|
|
|
|
#include <unistd.h>
|
2004-03-15 02:01:45 +08:00
|
|
|
#include <stdlib.h>
|
2000-02-18 03:38:33 +08:00
|
|
|
#include <sys/mtio.h>
|
2004-03-27 05:43:49 +08:00
|
|
|
#include <sys/param.h>
|
2004-03-15 02:01:45 +08:00
|
|
|
#include <ddk/ntddstor.h>
|
2000-08-22 11:58:47 +08:00
|
|
|
#include "cygerrno.h"
|
2001-03-05 14:28:25 +08:00
|
|
|
#include "perprocess.h"
|
2001-07-27 03:22:24 +08:00
|
|
|
#include "security.h"
|
2001-10-01 12:10:07 +08:00
|
|
|
#include "path.h"
|
* devices.cc: New file.
* devices.gperf: New file.
* devices.shilka: New file.
* cygwin-gperf: New file.
* cygwin-shilka: New file.
* fhandler_fifo.cc: New file.
* fhandler_nodevice.cc : New file. Reorganize headers so that path.h precedes
fhandler.h throughout. Remove device argument and unit arguments from fhandler
constructors throughout. Remove pc arguments to fhandler functions and use
internal pc element instead, throughout. Use dev element in pc throughout.
Use major/minor elements rather than units and device numbers previously in
fhandler class. Use correct methods for fhandler file names rather than
directly accessing file name variables, throughout.
* Makefile.in (DLL_OFILES): Add devices.o, fhandler_fifo.o
* dcrt0.cc (dll_crt0_1): Call device::init.
* devices.h: Renumber devices based on more Linux-like major/minor numbers.
Add more devices. Declare standard device storage.
(device): Declare struct.
* dir.cc (opendir): Use new 'build_fh_name' to construct a fhandler_* type.
* dtable.cc (dtable::get_debugger_info): Ditto.
(cygwin_attach_handle_to_fd): Ditto.
(dtable::release): Remove special FH_SOCKET case in favor of generic
"need_fixup_before" test.
(dtable::init_std_file_from_handle): Use either build_fh_dev or build_fh_name
to build standard fhandler.
(dtable::build_fh_name): Renamed from dtable::build_fhandler_from_name. Move
out of dtable class. Don't accept a path_conv argument. Just build it here
and pass it to:
(build_fh_pc): Renamed from dtable::build_fhandler. Move out of dtable class.
Use intrinsic device type in path_conv to create new fhandler.
(build_fh_dev): Renamed from dtable::build_fhandler. Move out of dtable class.
Simplify arguments to just take new 'device' type and a name. Just return
pointer to fhandler rather than trying to insert into dtable.
(dtable::dup_worker): Accommodate above build_fh name changes.
(dtable::find_fifo): New (currently broken) function.
(handle_to_fn): Use strechr for efficiency.
* dtable.h: Reflect above build_fh name changes and argument differences.
(fhandler_base *&operator []): Return self rather than copy of self.
* fhandler.cc (fhandler_base::operator =): Use pc element to set normalized
path.
(fhandler_base::set_name): Ditto.
(fhandler_base::raw_read): Use method to access name.
(fhandler_base::write): Correctly use get_output_handle rather than get_handle.
(handler_base::device_access_denied): New function.
(fhandler_base::open): Eliminate pc argument and use pc element of
fhandler_base throughout.
(fhandler_base::fstat): Detect if device is based in filesystem and use
fstat_fs to calculate stat, if so.
(fhandler_base::fhandler_base): Eliminate handling of file names and, instead,
just free appropriate component from pc.
(fhandler_base::opendir): Remove path_conv parameter.
* fhandler.h: Remove all device flags.
(fhandler_base::pc): New element.
(fhandler_base::set_name): Change argument to path_conv.
(fhandler_base::error): New function.
(fhandler_base::exists): New function.
(fhandler_base::pc_binmode): New function.
(fhandler_base::dev): New function.
(fhandler_base::open_fs): New function.
(fhandler_base::fstat_fs): New function.
(fhandler_base::fstat_by_name): New function.
(fhandler_base::fstat_by_handle): New function.
(fhandler_base::isfifo): New function.
(fhandler_base::is_slow): New function.
(fhandler_base::is_auto_device): New function.
(fhandler_base::is_fs_special): New function.
(fhandler_base::device_access_denied): New function.
(fhandler_base::operator DWORD&): New operator.
(fhandler_base::get_name): Return normalized path from pc.
(fhandler_base::get_win32_name): Return windows path from pc.
(fhandler_base::isdevice): Renamed from is_device.
(fhandler_base::get_native_name): Return device format.
(fhandler_fifo): New class.
(fhandler_nodevice): New class.
(select_stuff::device_specific): Remove array.
(select_stuff::device_specific_pipe): New class element.
(select_stuff::device_specific_socket): New class element.
(select_stuff::device_specific_serial): New class element.
(select_stuff::select_stuff): Initialize new elements.
* fhandler_disk_file.cc (fhandler_base::fstat_by_handle): Move to base class
from fhandler_disk_file.
(fhandler_base::fstat_by_name): Ditto.
(fhandler_base::fstat_by_name): Ditto.
(fhandler_disk_file::open): Move most functionality into
fhandler_base::open_fs.
(fhandler_base::open_fs): New function.
(fhandler_disk_file::close): Move most functionality into
fhandler_base::close_fs.
(fhandler_base::close_fs): New function.
* fhandler_mem.cc (fhandler_dev_mem::open): Use device name in debugging
output.
* fhandler_socket.cc (fhandler_socket::set_connect_secret): Copy standard
urandom device into appropriate place.
(fhandler_socket::accept): Reflect change in fdsock return value.
* fhandler_tty.cc: See "throughouts" above.
* net.cc: Accommodate fdsock change throughout.
(fdsock): Return success or failure, accept fd argument and device argument.
* path.cc (symlink_info::major): New element.
(symlink_info::minor): New element.
(symlink_info::parse_device): Declare new function.
(fs_info::update): Accommodate changes in path_conv class.
(path_conv::fillin): Ditto.
(path_conv::return_and_clear_normalized_path): Eliminate.
(path_conv::set_normalized_path): New function.
(path_conv::path_conv): Set info in dev element. Use path_conv methods Check
for FH_FS rather than FH_BAD to indicate when to fill in filesystem stuff.
where appropriate rather than direct access. Use set_normalized_path to set
normalized path.
(windows_device_names): Eliminate.
(get_dev): Ditto.
(get_raw_device_number): Ditto.
(get_device_number): Ditto.
(win32_device_name): Call new device name parser to do most of the heavy
lifting.
(mount_info::conv_to_win32_path): Fill in dev field as appropriate.
(symlink_worker): Handle new device files.
(symlink_info::check): Ditto.
(symlink_info::parse_device): Define new function.
* path.h (executable_states): Move here from fhandler.h.
(fs_info): Rename variables to *_storage and create methods for accessing same.
(path_conv): Add dev element, remove devn and unit and adjust inline methods to
accommodate.
(set_normalized_path): Declare new function.
* pinfo.cc (_pinfo::commune_recv): Add broken support for handling fifos.
(_pinfo::commune_send): Ditto.
* pipe.cc (fhandler_pipe::close): check for existence of handle before closing
it.
(handler_pipe::create): Rename from make_pipe. Change arguments to accept
fhandler_pipe array. Accommodate fifos.
(pipe): Rework to deal with fhandler_pipe::create changes.
(_pipe): Ditto.
* select.cc: Use individual device_specific types throughout rather than
indexing with obsolete device number.
(set_bits): Use is_socket call rather than checking device number.
* shared_info.h (CURR_MOUNT_MAGIC): Update.
(conv_to_win32_path): Reflect addition of device argument.
* syscalls.cc (mknod_worker): New function.
(open): Use build_fh_name to build fhandler.
(chown_worker): Detect if this is an 'auto' device rather than an on-filesystem
device and handle appropriately.
(chmod_device): New function.
(chmod): Detect if this is an 'auto' device rather than an on-filesystem device
and handle appropriately. Use chmod_device to set mode of in-filesystem
devices.
(stat_worker): Eliminate path_conv argument. Call build_fh_name to construct
fhandler. Use fh->error() rather than pc->error to detect errors in fhandler
construction.
(access_worker): New function pulled from access. Accommodate in-filesystem
devices.
(access): Use access_worker.
(fpathconf): Detect if this is an 'auto' device rather than an on-filesystem
device and handle appropriately.
(mknod_worker): New function.
(mknod32): New function.
(chroot): Free normalized path -- assuming it was actually cmalloced.
* tty.cc (create_tty_master): Tweak for new device class.
(tty::common_init): Ditto.
* winsup.h (stat_worker): Remove.
(symlink_worker): Declare.
* exceptions.cc (set_process_mask): Just call sig_dispatch_pending and don't
worry about pending_signals since sig_dispatch_pending should always do the
right thing now.
(sig_handle): Reorganize SIGCONT handling to more closely conform to SUSv3.
* pinfo.h: Move __SIG enum to sigproc.h.
(PICOM_FIFO): New enum element.
(_pinfo): Remove 'thread2signal' stuff throughout class.
(_pinfo::commune_send): Make varargs.
(_pinfo::sigtodo): Eliminate.
(_pinfo::thread2signal): Ditto.
* signal.cc (kill_worker): Eliminate call to setthread2signal.
* sigproc.cc (local_sigtodo): Eliminate.
(getlocal_sigtodo): Ditto.
(sigelem): New class.
(pending_signals): New class.
(sigqueue): New variable, start of sigqueue linked list.
(sigcatch_nonmain): Eliminate.
(sigcatch_main): Eliminate.
(sigcatch_nosync): Eliminate.
(sigcomplete_nonmain): Eliminate.
(pending_signals): Eliminate.
(sig_clear): Call signal thread to clear pending signals, unless already in
signal thread.
(sigpending): Call signal thread to get pending signals.
(sig_dispatch_pending): Eliminate use of pending_signals and just check
sigqueue.
(sigproc_terminate): Eliminate all of the obsolete semaphore stuff. Close
signal pipe handle.
(sig_send): Eliminate all of the obsolete semaphore stuff and use pipe to send
signals.
(getevent): Eliminate.
(pending_signals::add): New function.
(pending_signals::del): New function.
(pending_signals::next): New function.
(wait_sig): Eliminate all of the obsolete semaphore stuff. Use pipe to
communicate and maintain a linked list of signals.
* sigproc.h: Move __SIG defines here. Add __SIGPENDING.
(sig_dispatch_pending): Remove "C" specifier.
(sig_handle): Accept a mask argument.
* thread.cc: Remove signal handling considerations throughout.
2003-09-25 08:37:18 +08:00
|
|
|
#include "fhandler.h"
|
2001-04-19 05:10:15 +08:00
|
|
|
#include "dtable.h"
|
|
|
|
#include "cygheap.h"
|
2004-03-27 05:43:49 +08:00
|
|
|
#include "shared_info.h"
|
|
|
|
#include "sigproc.h"
|
|
|
|
#include "mtinfo.h"
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-14 02:15:06 +08:00
|
|
|
/* 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. */
|
2004-03-27 05:43:49 +08:00
|
|
|
#define TAPE_FUNC(func) while ((lasterr = (func)) == ERROR_MEDIA_CHANGED) \
|
|
|
|
{ \
|
|
|
|
initialize (drive, false); \
|
|
|
|
part (partition)->initialize (0); \
|
|
|
|
}
|
2004-03-14 02:15:06 +08:00
|
|
|
|
|
|
|
/* Convert LARGE_INTEGER into long long */
|
|
|
|
#define get_ll(pl) (((long long) (pl).HighPart << 32) | (pl).LowPart)
|
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
#define IS_BOT(err) ((err) == ERROR_BEGINNING_OF_MEDIA)
|
2004-03-14 02:15:06 +08:00
|
|
|
|
|
|
|
#define IS_EOF(err) ((err) == ERROR_FILEMARK_DETECTED \
|
|
|
|
|| (err) == ERROR_SETMARK_DETECTED)
|
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
#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)
|
|
|
|
|
2000-02-18 03:38:33 +08:00
|
|
|
/**********************************************************************/
|
2004-03-27 05:43:49 +08:00
|
|
|
/* mtinfo_part */
|
2000-02-18 03:38:33 +08:00
|
|
|
|
|
|
|
void
|
2004-03-27 05:43:49 +08:00
|
|
|
mtinfo_part::initialize (long nblock)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
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 ();
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-03-27 05:43:49 +08:00
|
|
|
mtinfo_drive::get_dp (HANDLE mt)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
DWORD len = sizeof _dp;
|
|
|
|
TAPE_FUNC (GetTapeParameters (mt, GET_TAPE_DRIVE_INFORMATION, &len, &_dp));
|
|
|
|
return error ("get_dp");
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-03-27 05:43:49 +08:00
|
|
|
mtinfo_drive::get_mp (HANDLE mt)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
DWORD len = sizeof _mp;
|
|
|
|
TAPE_FUNC (GetTapeParameters (mt, GET_TAPE_MEDIA_INFORMATION, &len, &_mp));
|
|
|
|
return error ("get_mp");
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
int
|
|
|
|
mtinfo_drive::open (HANDLE mt)
|
2004-03-14 02:15:06 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
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");
|
|
|
|
}
|
2004-03-14 02:15:06 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
int
|
|
|
|
mtinfo_drive::close (HANDLE mt, bool rewind)
|
|
|
|
{
|
|
|
|
lasterr = 0;
|
|
|
|
if (GetTapeStatus (mt) == ERROR_NO_MEDIA_IN_DRIVE)
|
|
|
|
dirty = clean;
|
|
|
|
if (dirty == has_written)
|
2004-03-14 02:15:06 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
/* 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? */
|
|
|
|
}
|
2004-03-14 02:15:06 +08:00
|
|
|
}
|
2004-03-27 05:43:49 +08:00
|
|
|
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");
|
2004-03-14 02:15:06 +08:00
|
|
|
}
|
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
int
|
|
|
|
mtinfo_drive::read (HANDLE mt, void *ptr, size_t &ulen)
|
2004-03-14 02:15:06 +08:00
|
|
|
{
|
|
|
|
BOOL ret;
|
2004-03-27 05:43:49 +08:00
|
|
|
DWORD bytes_read = 0;
|
2004-03-14 02:15:06 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
if (GetTapeStatus (mt) == ERROR_NO_MEDIA_IN_DRIVE)
|
|
|
|
return lasterr = ERROR_NO_MEDIA_IN_DRIVE;
|
|
|
|
if (lasterr == ERROR_BUS_RESET)
|
2004-03-14 02:15:06 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
ulen = 0;
|
|
|
|
goto out;
|
2004-03-14 02:15:06 +08:00
|
|
|
}
|
2004-03-27 05:43:49 +08:00
|
|
|
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");
|
2004-03-14 02:15:06 +08:00
|
|
|
}
|
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
int
|
|
|
|
mtinfo_drive::write (HANDLE mt, const void *ptr, size_t &len)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
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");
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-03-27 05:43:49 +08:00
|
|
|
mtinfo_drive::get_pos (HANDLE mt, long *ppartition, long *pblock)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
DWORD p, low, high;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
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)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
partition = (long) (p > 0 ? p - 1 : p);
|
|
|
|
block = (long) low;
|
|
|
|
if (ppartition)
|
|
|
|
*ppartition= partition;
|
|
|
|
if (pblock)
|
|
|
|
*pblock = block;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
partition = 0;
|
|
|
|
block = -1;
|
|
|
|
}
|
|
|
|
return error ("get_pos");
|
|
|
|
}
|
2004-03-14 02:15:06 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
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;
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
int
|
|
|
|
mtinfo_drive::set_pos (HANDLE mt, int mode, long count,
|
|
|
|
bool sfm_func)
|
|
|
|
{
|
|
|
|
int err = 0;
|
|
|
|
long undone = count;
|
|
|
|
BOOL dont_wait = FALSE;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
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");
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
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");
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
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)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
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;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2004-03-27 05:43:49 +08:00
|
|
|
else
|
|
|
|
partition = count;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2004-03-27 05:43:49 +08:00
|
|
|
return error ("set_partition");
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-03-27 05:43:49 +08:00
|
|
|
mtinfo_drive::write_marks (HANDLE mt, int marktype, DWORD count)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
if (marktype != TAPE_SETMARKS)
|
|
|
|
dirty = clean;
|
|
|
|
if (marktype == TAPE_FILEMARKS
|
|
|
|
&& !get_feature (TAPE_DRIVE_WRITE_FILEMARKS))
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
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)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
if (partition < MAX_PARTITION_NUM
|
|
|
|
&& part (partition)->block != block)
|
|
|
|
part (partition)->initialize (block);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2004-03-27 05:43:49 +08:00
|
|
|
else if (sav_block != block && partition < MAX_PARTITION_NUM)
|
|
|
|
part (partition)->initialize (block);
|
|
|
|
lasterr = err;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2004-03-27 05:43:49 +08:00
|
|
|
return error ("write_marks");
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
int
|
|
|
|
mtinfo_drive::erase (HANDLE mt, int mode)
|
|
|
|
{
|
|
|
|
switch (mode)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
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;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2004-03-27 05:43:49 +08:00
|
|
|
TAPE_FUNC (EraseTape (mt, mode, nowait ? TRUE : FALSE));
|
|
|
|
part (partition)->initialize (0);
|
|
|
|
return error ("erase");
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
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)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
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;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2004-03-27 05:43:49 +08:00
|
|
|
return error ("prepare");
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-03-27 05:43:49 +08:00
|
|
|
mtinfo_drive::set_compression (HANDLE mt, long count)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
if (!get_feature (TAPE_DRIVE_SET_COMPRESSION))
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
|
|
|
TAPE_SET_DRIVE_PARAMETERS sdp =
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
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");
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
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");
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
int
|
|
|
|
mtinfo_drive::status (HANDLE mt, struct mtget *get)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
int notape = 0;
|
|
|
|
DWORD tstat;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
if (!get)
|
|
|
|
return ERROR_INVALID_PARAMETER;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
if ((tstat = GetTapeStatus (mt)) == ERROR_NO_MEDIA_IN_DRIVE)
|
|
|
|
notape = 1;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
memset (get, 0, sizeof *get);
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
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 ())
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
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
|
|
|
|
}
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
if (!notape)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
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);
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
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 */
|
|
|
|
|
|
|
|
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;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
return 0;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-03-27 05:43:49 +08:00
|
|
|
mtinfo_drive::set_options (HANDLE mt, long options)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
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
|
|
|
|
};
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
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");
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-03-27 05:43:49 +08:00
|
|
|
mtinfo_drive::ioctl (HANDLE mt, unsigned int cmd, void *buf)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
|
|
|
if (cmd == MTIOCTOP)
|
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
if (__check_invalid_read_ptr (buf, sizeof (struct mtop)))
|
|
|
|
return ERROR_NOACCESS;
|
2000-02-18 03:38:33 +08:00
|
|
|
struct mtop *op = (struct mtop *) buf;
|
2004-03-27 05:43:49 +08:00
|
|
|
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)
|
|
|
|
{
|
2000-02-18 03:38:33 +08:00
|
|
|
case MTRESET:
|
|
|
|
break;
|
|
|
|
case MTFSF:
|
2004-03-27 05:43:49 +08:00
|
|
|
set_pos (mt, TAPE_SPACE_FILEMARKS, op->mt_count, false);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTBSF:
|
2004-03-27 05:43:49 +08:00
|
|
|
set_pos (mt, TAPE_SPACE_FILEMARKS, -op->mt_count, false);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTFSR:
|
2004-03-27 05:43:49 +08:00
|
|
|
set_pos (mt, TAPE_SPACE_RELATIVE_BLOCKS, op->mt_count, false);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTBSR:
|
2004-03-27 05:43:49 +08:00
|
|
|
set_pos (mt, TAPE_SPACE_RELATIVE_BLOCKS, -op->mt_count, false);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTWEOF:
|
2004-03-27 05:43:49 +08:00
|
|
|
write_marks (mt, TAPE_FILEMARKS, op->mt_count);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTREW:
|
2004-03-27 05:43:49 +08:00
|
|
|
set_pos (mt, TAPE_REWIND, 0, false);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTOFFL:
|
2004-03-15 02:01:45 +08:00
|
|
|
case MTUNLOAD:
|
2004-03-27 05:43:49 +08:00
|
|
|
prepare (mt, TAPE_UNLOAD);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTNOP:
|
2004-03-27 05:43:49 +08:00
|
|
|
lasterr = 0;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTRETEN:
|
2004-03-27 05:43:49 +08:00
|
|
|
if (!get_feature (TAPE_DRIVE_TENSION))
|
|
|
|
lasterr = ERROR_INVALID_PARAMETER;
|
|
|
|
else if (!set_pos (mt, TAPE_REWIND, 0, false))
|
|
|
|
prepare (mt, TAPE_TENSION);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTBSFM:
|
2004-03-27 05:43:49 +08:00
|
|
|
set_pos (mt, TAPE_SPACE_FILEMARKS, -op->mt_count, true);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTFSFM:
|
2004-03-27 05:43:49 +08:00
|
|
|
set_pos (mt, TAPE_SPACE_FILEMARKS, op->mt_count, true);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTEOM:
|
2004-03-27 05:43:49 +08:00
|
|
|
if (fast_eom && get_feature (TAPE_DRIVE_END_OF_DATA))
|
|
|
|
set_pos (mt, TAPE_SPACE_END_OF_DATA, 0, false);
|
2000-02-18 03:38:33 +08:00
|
|
|
else
|
2004-03-27 05:43:49 +08:00
|
|
|
set_pos (mt, TAPE_SPACE_FILEMARKS, 32767, false);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTERASE:
|
2004-03-27 05:43:49 +08:00
|
|
|
erase (mt, TAPE_ERASE_LONG);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTRAS1:
|
|
|
|
case MTRAS2:
|
|
|
|
case MTRAS3:
|
2004-03-27 05:43:49 +08:00
|
|
|
lasterr = ERROR_INVALID_PARAMETER;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTSETBLK:
|
2004-03-27 05:43:49 +08:00
|
|
|
if (!get_feature (TAPE_DRIVE_SET_BLOCK_SIZE))
|
2004-03-15 02:01:45 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
lasterr = ERROR_INVALID_PARAMETER;
|
2004-03-15 02:01:45 +08:00
|
|
|
break;
|
|
|
|
}
|
2004-03-27 05:43:49 +08:00
|
|
|
if ((DWORD) op->mt_count == mp ()->BlockSize)
|
2004-03-15 02:01:45 +08:00
|
|
|
{
|
|
|
|
/* Nothing has changed. */
|
2004-03-27 05:43:49 +08:00
|
|
|
lasterr = 0;
|
2004-03-15 02:01:45 +08:00
|
|
|
break;
|
|
|
|
}
|
2004-03-27 05:43:49 +08:00
|
|
|
if ((op->mt_count == 0 && !get_feature (TAPE_DRIVE_VARIABLE_BLOCK))
|
2004-03-15 02:01:45 +08:00
|
|
|
|| (op->mt_count > 0
|
2004-03-27 05:43:49 +08:00
|
|
|
&& ((DWORD) op->mt_count < dp ()->MinimumBlockSize
|
|
|
|
|| (DWORD) op->mt_count > dp ()->MaximumBlockSize)))
|
2004-03-15 02:01:45 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
lasterr = ERROR_INVALID_PARAMETER;
|
2004-03-15 02:01:45 +08:00
|
|
|
break;
|
|
|
|
}
|
2004-03-27 05:43:49 +08:00
|
|
|
if (set_blocksize (mt, op->mt_count)
|
|
|
|
&& lasterr == ERROR_INVALID_FUNCTION)
|
|
|
|
lasterr = ERROR_INVALID_BLOCK_LENGTH;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTSEEK:
|
2004-03-27 05:43:49 +08:00
|
|
|
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);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTTELL:
|
2004-03-27 05:43:49 +08:00
|
|
|
if (!get_pos (mt))
|
2000-02-18 03:38:33 +08:00
|
|
|
op->mt_count = block;
|
|
|
|
break;
|
|
|
|
case MTFSS:
|
2004-03-27 05:43:49 +08:00
|
|
|
set_pos (mt, TAPE_SPACE_SETMARKS, op->mt_count, false);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTBSS:
|
2004-03-27 05:43:49 +08:00
|
|
|
set_pos (mt, TAPE_SPACE_SETMARKS, -op->mt_count, false);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTWSM:
|
2004-03-27 05:43:49 +08:00
|
|
|
write_marks (mt, TAPE_SETMARKS, op->mt_count);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTLOCK:
|
2004-03-27 05:43:49 +08:00
|
|
|
prepare (mt, TAPE_LOCK);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTUNLOCK:
|
2004-03-27 05:43:49 +08:00
|
|
|
prepare (mt, TAPE_UNLOCK);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTLOAD:
|
2004-03-27 05:43:49 +08:00
|
|
|
prepare (mt, TAPE_LOAD);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTCOMPRESSION:
|
2004-03-27 05:43:49 +08:00
|
|
|
set_compression (mt, op->mt_count);
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
|
|
|
case MTSETPART:
|
2004-03-27 05:43:49 +08:00
|
|
|
set_partition (mt, op->mt_count);
|
2004-03-15 19:37:37 +08:00
|
|
|
break;
|
2000-02-18 03:38:33 +08:00
|
|
|
case MTMKPART:
|
2004-03-27 05:43:49 +08:00
|
|
|
create_partitions (mt, op->mt_count);
|
2004-03-15 19:37:37 +08:00
|
|
|
break;
|
2004-03-15 02:01:45 +08:00
|
|
|
case MTSETDRVBUFFER:
|
2004-03-27 05:43:49 +08:00
|
|
|
set_options (mt, op->mt_count);
|
|
|
|
break;
|
|
|
|
case MTSETDENSITY:
|
2000-02-18 03:38:33 +08:00
|
|
|
default:
|
2004-03-27 05:43:49 +08:00
|
|
|
lasterr = ERROR_INVALID_PARAMETER;
|
2000-02-18 03:38:33 +08:00
|
|
|
break;
|
2004-03-27 05:43:49 +08:00
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
else if (cmd == MTIOCGET)
|
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
if (__check_null_invalid_struct (buf, sizeof (struct mtget)))
|
|
|
|
return ERROR_NOACCESS;
|
|
|
|
status (mt, (struct mtget *) buf);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2004-03-27 05:43:49 +08:00
|
|
|
else if (cmd == MTIOCPOS)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
if (__check_null_invalid_struct (buf, sizeof (struct mtpos)))
|
|
|
|
return ERROR_NOACCESS;
|
|
|
|
if (!get_pos (mt))
|
|
|
|
((struct mtpos *) buf)->mt_blkno = block;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
return lasterr;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
/**********************************************************************/
|
|
|
|
/* mtinfo */
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
void
|
|
|
|
mtinfo::initialize (void)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
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);
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
HANDLE mt_h;
|
|
|
|
mtinfo *mt;
|
|
|
|
|
|
|
|
void __stdcall
|
|
|
|
mtinfo_init ()
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
mt = (mtinfo *) open_shared ("mtinfo", MTINFO_VERSION, mt_h, sizeof (mtinfo), SH_MTINFO);
|
|
|
|
mt->initialize ();
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
/**********************************************************************/
|
|
|
|
/* fhandler_dev_tape */
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
#define lock(err_ret_val) if (!_lock ()) return err_ret_val;
|
2004-03-14 02:15:06 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
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)
|
2004-03-15 19:37:37 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
debug_printf ("signal_arrived"); \
|
|
|
|
set_errno (EINTR);
|
2004-03-15 19:37:37 +08:00
|
|
|
}
|
2004-03-27 05:43:49 +08:00
|
|
|
return ret;
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
inline int
|
|
|
|
fhandler_dev_tape::unlock (int ret)
|
|
|
|
{
|
|
|
|
ReleaseMutex (mt_mtx);
|
|
|
|
return ret;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
fhandler_dev_tape::fhandler_dev_tape ()
|
|
|
|
: fhandler_dev_raw ()
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
debug_printf ("unit: %d", dev ().minor);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-03-27 05:43:49 +08:00
|
|
|
fhandler_dev_tape::open (int flags, mode_t)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
if (driveno () >= MAX_DRIVE_NUM)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
set_errno (ENOENT);
|
|
|
|
return 0;
|
2004-03-15 02:01:45 +08:00
|
|
|
}
|
2004-03-27 05:43:49 +08:00
|
|
|
if (!(mt_mtx = CreateMutex (&sec_all, FALSE, NULL)))
|
2004-03-15 02:01:45 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
__seterrno ();
|
|
|
|
return 0;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
2004-03-27 05:43:49 +08:00
|
|
|
/* 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)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
mt->drive (driveno ())->open (get_handle ());
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
/* 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;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-03-27 05:43:49 +08:00
|
|
|
fhandler_dev_tape::close (void)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
int ret, cret;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
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);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
void
|
|
|
|
fhandler_dev_tape::raw_read (void *ptr, size_t &ulen)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
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;
|
2004-03-15 19:37:37 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
if (lastblk_to_read)
|
2004-03-15 02:01:45 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
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)
|
2004-03-15 02:01:45 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
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);
|
2004-03-15 02:01:45 +08:00
|
|
|
}
|
2004-03-27 05:43:49 +08:00
|
|
|
else if (bytes_read)
|
|
|
|
lastblk_to_read = 1;
|
2004-03-15 02:01:45 +08:00
|
|
|
}
|
|
|
|
}
|
2004-03-27 05:43:49 +08:00
|
|
|
if (ret)
|
|
|
|
ulen = (size_t) -1;
|
|
|
|
else
|
|
|
|
ulen = bytes_read;
|
|
|
|
unlock ();
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
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);
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
_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;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
lock (ILLEGAL_SEEK);
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
debug_printf ("lseek (%s, %d, %d)", get_name (), offset, whence);
|
2004-03-15 19:37:37 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
block_size = mt->drive (driveno ())->mp ()->BlockSize;
|
|
|
|
if (block_size == 0)
|
|
|
|
{
|
|
|
|
set_errno (EIO);
|
|
|
|
goto out;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
if (ioctl (MTIOCPOS, &pos))
|
|
|
|
goto out;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
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;
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
op.mt_op = MTFSR;
|
|
|
|
op.mt_count = offset / block_size
|
|
|
|
- (whence == SEEK_SET ? pos.mt_blkno : 0);
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
if (op.mt_count < 0)
|
|
|
|
{
|
|
|
|
op.mt_op = MTBSR;
|
|
|
|
op.mt_count = -op.mt_count;
|
|
|
|
}
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
if (ioctl (MTIOCTOP, &op) || ioctl (MTIOCPOS, &pos))
|
|
|
|
goto out;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
ret = pos.mt_blkno * block_size;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
out:
|
|
|
|
return unlock (ret);
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-03-27 05:43:49 +08:00
|
|
|
fhandler_dev_tape::fstat (struct __stat64 *buf)
|
2000-02-18 03:38:33 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
int ret;
|
2000-02-18 03:38:33 +08:00
|
|
|
|
2004-03-27 05:43:49 +08:00
|
|
|
if (driveno () >= MAX_DRIVE_NUM)
|
|
|
|
{
|
|
|
|
set_errno (ENOENT);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if (!(ret = fhandler_base::fstat (buf)))
|
|
|
|
buf->st_blocks = 0;
|
|
|
|
return ret;
|
2000-02-18 03:38:33 +08:00
|
|
|
}
|
|
|
|
|
2004-03-15 19:37:37 +08:00
|
|
|
int
|
2004-03-27 05:43:49 +08:00
|
|
|
fhandler_dev_tape::dup (fhandler_base *child)
|
2004-03-15 19:37:37 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
lock (-1);
|
|
|
|
return unlock (fhandler_dev_raw::dup (child));
|
2004-03-15 19:37:37 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2004-03-27 05:43:49 +08:00
|
|
|
fhandler_dev_tape::ioctl (unsigned int cmd, void *buf)
|
2004-03-15 19:37:37 +08:00
|
|
|
{
|
2004-03-27 05:43:49 +08:00
|
|
|
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));
|
2004-03-15 19:37:37 +08:00
|
|
|
}
|