📄 mt.c
字号:
/*
* Copyright (C) 2001-2002 Peter Weston
* peter.weston@holistech.co.uk
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
see end of this file for the full GNU General Public License
MT: windows NT/2000/XP command line tape manipulation
written to format a tape windows-XP backup refused to write or format... and satisfy my curiosity
Can be used for crude data recovery (combine seek and read)
todo: nothing... worked for me.
coulddo: lots if anyone's interested...
absolute position?
set block size
start read at n bytes...
recover/retry errors (maybe reread damaged tape, pad unreadable block, seek over, etc.)
gui
write to tape
fix long int nastyness
change tape block size (read data from tape,
test with other hardware :-)
build with mingw (V3.2)... no makefile just a: gcc -o mt.exe mt.c
changelog:
v0.12 added eject as an alias for unload
v0.13 fixed broken seek number parsing
v0.14 error message tweaks
v0.15 fix for wrong block size during read (from Jason Bingham)
v0.16 add set block size and read variable block lengths
*/
#include <stdio.h>
#include <windows.h>
#define VER "v0.16beta"
#define MAX_ERROR_LINE_LENGTH 80
#define VARIABLE_BUFFER_LENGTH 131073 // 128K +1
enum {
DO_ENDLIST,
DO_LONGERASE,
DO_REWIND,
DO_DRIVESTATUS,
DO_MEDIASTATUS,
DO_FORMAT,
DO_LOAD,
DO_LOCK,
DO_TENSION,
DO_UNLOAD,
DO_UNLOCK,
DO_SHORTERASE,
DO_USAGE,
DO_PARTITION,
DO_FIXEDPARTITION,
DO_INITPARTITION,
DO_SEEK,
DO_READ,
DO_LICENCE,
DO_READPART,
DO_BYTESEEK,
DO_BLOCK,
} DO_ACTIONS;
typedef struct _PARRAY {
char *txt;
DWORD bit;
} PARRAY;
typedef struct _OPTARRAY {
char *txt;
DWORD bit;
int params;
} OPTARRAY;
char licencetext[]={"
Copyright (C) 2001-2002 Peter Weston (peter.weston@holistech.co.uk)
this program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
this program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
"};
char usagetext[]={"
Copyright (C) 2001-2002 Peter Weston (peter.weston@holistech.co.uk)
Usage: mt command <drive> <param1> <param2> ...
eg. mt erase tape0
Command, one of:
block\t\t set block size to param1 bytes (eg. mt block 32K)
drivestatus\t displays the status of the tape drive
eject\t\t unload the tape
format\t format the tape (QIC117 only)
help\t\t display this usage information
licence\t display licence information
load\t\t load the tape
lock\t\t lock the tape
longerase\t long-erase the specified tape (blanks current partition)
mediastatus\t display the status of the media
partition\t (no parameters) create fixed (drive default) partitions
partition\t (1 parameter) create param1 select partitions
partition\t (2 parameters) create param1 partitions of size param2 (MB)
read\t\t (1 parameter) read from tape into file param1
read\t\t (2 parameters) read param 2 bytes from tape to file param1
retension\t retension the tape
rewind\t rewind the tape
seek\t\t move tape to block param1
seekbyte\t move tape to byte param1
shorterase\t short-erase the tape (writes end of tape)
unload\t unload the tape
unlock\t unlock the tape
Drive:
tape0\t\t (default)
tape1 etc...
Most commands fail if the tape is busy, except mediastatus which waits for
the current operation to complete.
Large numbers can be made by suffixing K (1024), M (K*1024) or G (M*1024)
"};
OPTARRAY opts[]={
"longerase",DO_LONGERASE,0,
"rewind",DO_REWIND,0,
"drivestatus", DO_DRIVESTATUS,0,
"mediastatus", DO_MEDIASTATUS,0,
"format", DO_FORMAT,0,
"load", DO_LOAD,0,
"lock", DO_LOCK,0,
"tension", DO_TENSION,0,
"unload", DO_UNLOAD,0,
"eject", DO_UNLOAD,0,
"unlock", DO_UNLOCK,0,
"shorterase", DO_SHORTERASE,0,
"help", DO_USAGE,0,
"partition", DO_FIXEDPARTITION,0,
"partition", DO_PARTITION,1,
"partition", DO_INITPARTITION,2,
"seek", DO_SEEK,1,
"seekbyte", DO_BYTESEEK,1,
"read", DO_READ,1,
"licence",DO_LICENCE,0,
"read", DO_READPART,2,
"block", DO_BLOCK,1,
"",DO_ENDLIST,0
};
PARRAY drivel[]={
"Hardware compression", TAPE_DRIVE_COMPRESSION,
"Report if cleaning required",TAPE_DRIVE_CLEAN_REQUESTS,
"Hardware error correction (ECC)",TAPE_DRIVE_ECC,
"Soft eject physically ejects",TAPE_DRIVE_EJECT_MEDIA,
"Must erase from partition start",TAPE_DRIVE_ERASE_BOP_ONLY,
"Long erase\t\t",TAPE_DRIVE_ERASE_BOP_ONLY,
"Now erase (immediate erase)",TAPE_DRIVE_ERASE_IMMEDIATE,
"Short erase\t\t",TAPE_DRIVE_ERASE_SHORT,
"Creates fixed partitions",TAPE_DRIVE_FIXED,
"Fixed length blocks\t",TAPE_DRIVE_FIXED_BLOCK,
"Initiator defined partitions",TAPE_DRIVE_INITIATOR,
"Data padding\t\t",TAPE_DRIVE_PADDING,
"Provides absolute block number",TAPE_DRIVE_GET_ABSOLUTE_BLK,
"Provides logical block number",TAPE_DRIVE_GET_LOGICAL_BLK,
"Setmark reporting\t",TAPE_DRIVE_REPORT_SMKS,
"Creates select data partitions",TAPE_DRIVE_SELECT,
"Set end of medium warning size",TAPE_DRIVE_SET_EOT_WZ_SIZE,
"Set compression only at partition start",TAPE_DRIVE_SET_CMP_BOP_ONLY,
"Returns maximum capacity of tape",TAPE_DRIVE_TAPE_CAPACITY,
"Returns remaining capacity of tape",TAPE_DRIVE_TAPE_REMAINING,
"Variable length block mode\t",TAPE_DRIVE_VARIABLE_BLOCK,
"Returns error if write protected",TAPE_DRIVE_WRITE_PROTECT,
"",0
};
PARRAY driveh[]={
"Immediate return on absolute seek",TAPE_DRIVE_ABS_BLK_IMMED,
"Absolute seek\t\t\t",TAPE_DRIVE_ABSOLUTE_BLK,
"Goto end of data\t\t",TAPE_DRIVE_END_OF_DATA,
"Seek by filemark count\t\t",TAPE_DRIVE_FILEMARKS,
"Load and unload\t\t\t",TAPE_DRIVE_LOAD_UNLOAD,
"Immediate return on load and unload",TAPE_DRIVE_LOAD_UNLD_IMMED,
"Lock tape in drive\t\t",TAPE_DRIVE_LOCK_UNLOCK,
"Immediate return on lock and unlock",TAPE_DRIVE_LOCK_UNLK_IMMED,
"Immediate return on logical block seek",TAPE_DRIVE_LOG_BLK_IMMED,
"Logical block seek\t",TAPE_DRIVE_LOGICAL_BLK,
"Relative seek\t\t",TAPE_DRIVE_RELATIVE_BLKS,
"Backwards seek\t\t",TAPE_DRIVE_REVERSE_POSITION,
"Immediate rewind\t",TAPE_DRIVE_REWIND_IMMEDIATE,
"Seek to n consecutive filemarks",TAPE_DRIVE_SEQUENTIAL_FMKS,
"Seek to n consecutive setmarks",TAPE_DRIVE_SEQUENTIAL_SMKS,
"Set block size\t\t",TAPE_DRIVE_SET_BLOCK_SIZE,
"Set hardware compression",TAPE_DRIVE_SET_COMPRESSION,
"Set hardware error correction",TAPE_DRIVE_SET_ECC,
"Set data padding\t",TAPE_DRIVE_SET_PADDING,
"Setmark reporting\t",TAPE_DRIVE_SET_REPORT_SMKS,
"Seek over n setmarks\t",TAPE_DRIVE_SETMARKS,
"Immediate spacing\t",TAPE_DRIVE_SPACE_IMMEDIATE,
"Tape tensioning\t\t",TAPE_DRIVE_TENSION,
"Immediate tape tensioning",TAPE_DRIVE_TENSION_IMMED,
"Write filemarks\t\t",TAPE_DRIVE_WRITE_FILEMARKS,
"Write long filemarks\t",TAPE_DRIVE_WRITE_LONG_FMKS,
"Immediate write filemarks",TAPE_DRIVE_WRITE_MARK_IMMED,
"Write setmarks\t\t",TAPE_DRIVE_WRITE_SETMARKS,
"Write short setmarks\t",TAPE_DRIVE_WRITE_SHORT_FMKS,
"",0
};
void usage(void) {
printf("\nMT: command-line tape manipulation similar to the unix mt command %s\n%s",VER,usagetext);
exit(1);
}
void error(char* txt) {
LPVOID buff;
DWORD lasterr;
lasterr = GetLastError();
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS + MAX_ERROR_LINE_LENGTH,
NULL, lasterr, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &buff,0,NULL );
if(buff!=NULL) {
printf("%s While %s (%d)\n", (LPCTSTR)buff, txt ,lasterr);
LocalFree(buff);
} else {
printf("unknown error %d while %s\n", lasterr, txt);
}
}
void printparam(char* txt, BOOLEAN yn) {
printf("%s: %s\n",txt,(yn) ? "Yes" : "No");
}
void prnfeat(char* txt, DWORD result) {
printf("%s\t: %s\n",txt,(result!=0) ? "Yes" : "No");
}
void hexdec(char *txt, DWORD val) {
printf("%s: 0x%.8x (%u)\n",txt,val,val);
}
void hexdeclargeint(char *txt, LARGE_INTEGER val) {
printf("%s: 0x%.8I64x (%I64u)\n",txt,val,val);
}
void printmediaparams(TAPE_GET_MEDIA_PARAMETERS mediaparams) {
hexdeclargeint("Capacity (Bytes)\t",mediaparams.Capacity);
hexdeclargeint("Remaining (Bytes)\t",mediaparams.Remaining);
hexdec("Block Size\t\t",mediaparams.BlockSize);
hexdec("Partition Count\t\t",mediaparams.PartitionCount);
printparam("Write Protected\t\t",mediaparams.WriteProtected);
}
void printdriveparams(TAPE_GET_DRIVE_PARAMETERS driveparams) {
int count;
printparam("Hardware ECC\t\t",driveparams.ECC);
printparam("Compression\t\t",driveparams.Compression);
printparam("Data Padding\t\t",driveparams.DataPadding);
printparam("Report Setmarks\t\t",driveparams.ReportSetmarks);
hexdec("Default Block Size\t",driveparams.DefaultBlockSize);
hexdec("Maximum Block Size\t",driveparams.MaximumBlockSize);
hexdec("Minimum Block Size\t",driveparams.MinimumBlockSize);
hexdec("Maximum Partitions\t",driveparams.MaximumPartitionCount);
hexdec("EOT Warning Zone Size\t",driveparams.EOTWarningZoneSize);
for(count=0;drivel[count].bit!=0;count++) {
prnfeat(drivel[count].txt,drivel[count].bit & driveparams.FeaturesLow);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -