mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
490 lines
15 KiB
490 lines
15 KiB
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// dmfimage.c Program for retrieving entire contents of a floppy disk //
|
|
// into an image file, or writing such an image file to //
|
|
// a floppy disk. //
|
|
// //
|
|
// Code is targeted as Win32 console application. //
|
|
// //
|
|
// Author: Tom McGuire (tommcg) //
|
|
// //
|
|
// Original version written May, 1994. //
|
|
// //
|
|
// (C) Copyright 1994-1996, Microsoft Corporation //
|
|
// //
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define DEVICE_TO_FILE 0
|
|
#define FILE_TO_DEVICE 1
|
|
|
|
#define FILE_NO_SHARING 0
|
|
|
|
#define GETLASTERROR 0xFFFFFFFF
|
|
|
|
#define IMAGE_SIZE_DMF 1720320 // 80x2x21x512 (DMF 1.7MB)
|
|
#define IMAGE_SIZE_144 1474560 // 80x2x18x512 (standard 1.44MB)
|
|
#define IMAGE_SIZE_12 1228800 // 80x2x15x512 (standard 1.2MB)
|
|
|
|
void FormatDmf( HANDLE hDevice );
|
|
void FormatHD( HANDLE hDevice, MEDIA_TYPE eMediaType );
|
|
void ErrorExit( DWORD dwGLE, const char *szFormat, ... );
|
|
void Copyright( void );
|
|
|
|
|
|
void __cdecl main( int argc, char *argv[] ) {
|
|
|
|
CHAR chDeviceName[ MAX_PATH ] = "\\\\.\\";
|
|
CHAR chFileName[ MAX_PATH ];
|
|
DWORD dwFileSize = 0;
|
|
DWORD dwMediaSize, dwActual, dwGLE;
|
|
HANDLE hFile, hDevice, hMap;
|
|
PVOID pMappedView;
|
|
DISK_GEOMETRY dg;
|
|
DISK_GEOMETRY dgArray[ 20 ];
|
|
INT fDirection = 0;
|
|
BOOL bFormatTarget = FALSE;
|
|
BOOL b288 = FALSE;
|
|
UINT n, nElements;
|
|
|
|
|
|
Copyright();
|
|
|
|
//
|
|
// Check usage.
|
|
//
|
|
|
|
if ( argc < 3 ) {
|
|
ErrorExit( 0, "\n"
|
|
"Usage: DMFIMAGE source target [-f]\n"
|
|
"\n"
|
|
" Either source or target must be a floppy drive.\n"
|
|
" -f indicates format target media before writing.\n"
|
|
"\n"
|
|
"Examples: DMFIMAGE a: myfile.img\n"
|
|
" DMFIMAGE myfile.img b: -f\n"
|
|
"\n" );
|
|
}
|
|
|
|
|
|
SetErrorMode( SEM_FAILCRITICALERRORS ); // no drive-not-ready popups
|
|
SetFileApisToOEM();
|
|
|
|
|
|
//
|
|
// Determine source and target.
|
|
//
|
|
|
|
if (( argv[ 1 ][ 1 ] == ':' ) && ( argv[ 1 ][ 2 ] == '\0' )) {
|
|
strcat( chDeviceName, argv[ 1 ] );
|
|
strcpy( chFileName, argv[ 2 ] );
|
|
fDirection = DEVICE_TO_FILE;
|
|
if ( ( argv[ 2 ][ 1 ] == ':' ) && ( argv[ 2 ][ 2 ] == '\0' )) {
|
|
ErrorExit( 0, "Either source or destination must be a file\n" );
|
|
}
|
|
}
|
|
else if ( ( argv[ 2 ][ 1 ] == ':' ) && ( argv[ 2 ][ 2 ] == '\0' )) {
|
|
strcat( chDeviceName, argv[ 2 ] );
|
|
strcpy( chFileName, argv[ 1 ] );
|
|
fDirection = FILE_TO_DEVICE;
|
|
}
|
|
else {
|
|
ErrorExit( 0, "Either source or destination must be floppy drive "
|
|
"(like A:)\n" );
|
|
}
|
|
|
|
if (( argc > 3 ) &&
|
|
(( argv[ 3 ][ 0 ] == '/' ) || ( argv[ 3 ][ 0 ] == '-' )) &&
|
|
(( argv[ 3 ][ 1 ] == 'f' ) || ( argv[ 3 ][ 1 ] == 'F' ))) {
|
|
|
|
bFormatTarget = TRUE;
|
|
}
|
|
|
|
//
|
|
// Open device and determine size.
|
|
//
|
|
|
|
hDevice = CreateFile( chDeviceName,
|
|
( fDirection == FILE_TO_DEVICE ) ? GENERIC_READ | GENERIC_WRITE : GENERIC_READ,
|
|
( fDirection == FILE_TO_DEVICE ) ? FILE_NO_SHARING : FILE_SHARE_READ,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_NO_BUFFERING,
|
|
NULL );
|
|
|
|
if ( hDevice == INVALID_HANDLE_VALUE ) {
|
|
ErrorExit( GETLASTERROR, "Could not open device %s\n",
|
|
chDeviceName );
|
|
}
|
|
|
|
if ( ! DeviceIoControl( hDevice,
|
|
IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
|
NULL,
|
|
0,
|
|
&dg,
|
|
sizeof( dg ),
|
|
&dwActual,
|
|
NULL )) {
|
|
ErrorExit( GETLASTERROR, "Unable to query disk information on %s\n",
|
|
chDeviceName );
|
|
}
|
|
|
|
if ( dg.MediaType == Unknown ) {
|
|
dwMediaSize = 0;
|
|
bFormatTarget = TRUE;
|
|
}
|
|
else {
|
|
dwMediaSize = dg.Cylinders.LowPart
|
|
* dg.TracksPerCylinder
|
|
* dg.SectorsPerTrack
|
|
* dg.BytesPerSector;
|
|
}
|
|
|
|
if ( ! DeviceIoControl( hDevice,
|
|
IOCTL_DISK_GET_MEDIA_TYPES,
|
|
NULL,
|
|
0,
|
|
&dgArray,
|
|
sizeof( dgArray ),
|
|
&dwActual,
|
|
NULL )) {
|
|
ErrorExit( GETLASTERROR, "Unable to query disk information on %s\n",
|
|
chDeviceName );
|
|
}
|
|
|
|
nElements = dwActual / sizeof( dgArray[ 0 ] );
|
|
|
|
for ( n = 0; n < nElements; n++ ) {
|
|
switch ( dgArray[ n ].MediaType ) {
|
|
case F5_1Pt2_512:
|
|
if ( dwMediaSize == 0 )
|
|
dwMediaSize = IMAGE_SIZE_12;
|
|
break;
|
|
case F3_1Pt44_512:
|
|
if ( dwMediaSize == 0 )
|
|
dwMediaSize = IMAGE_SIZE_144;
|
|
break;
|
|
case F3_2Pt88_512:
|
|
b288 = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Open file
|
|
//
|
|
|
|
hFile = CreateFile( chFileName,
|
|
( fDirection == FILE_TO_DEVICE ) ? GENERIC_READ : GENERIC_READ | GENERIC_WRITE,
|
|
( fDirection == FILE_TO_DEVICE ) ? FILE_SHARE_READ : FILE_NO_SHARING,
|
|
NULL,
|
|
( fDirection == FILE_TO_DEVICE ) ? OPEN_EXISTING : CREATE_ALWAYS,
|
|
( fDirection == FILE_TO_DEVICE ) ? FILE_FLAG_SEQUENTIAL_SCAN : FILE_ATTRIBUTE_NORMAL |
|
|
FILE_FLAG_NO_BUFFERING,
|
|
NULL );
|
|
|
|
if ( hFile == INVALID_HANDLE_VALUE ) {
|
|
ErrorExit( GETLASTERROR, "Could not open file %s\n",
|
|
chFileName );
|
|
}
|
|
|
|
//
|
|
// If reading from file, make sure file is correct size for media
|
|
//
|
|
|
|
if ( fDirection == FILE_TO_DEVICE ) {
|
|
|
|
dwFileSize = GetFileSize( hFile, NULL );
|
|
|
|
if (( dwFileSize == IMAGE_SIZE_DMF ) &&
|
|
(( dwMediaSize == IMAGE_SIZE_DMF ) ||
|
|
( dwMediaSize == IMAGE_SIZE_144 ))) {
|
|
|
|
if ( b288 ) {
|
|
ErrorExit( 0, "Cannot create DMF diskette in 2.88MB drive\n" );
|
|
}
|
|
|
|
//
|
|
// DMF targets always get formatted
|
|
//
|
|
|
|
bFormatTarget = TRUE;
|
|
dwMediaSize = IMAGE_SIZE_DMF;
|
|
}
|
|
|
|
else if (( dwFileSize == IMAGE_SIZE_144 ) &&
|
|
( dwMediaSize == IMAGE_SIZE_DMF )) {
|
|
|
|
bFormatTarget = TRUE;
|
|
dwMediaSize = IMAGE_SIZE_144;
|
|
}
|
|
|
|
|
|
if ( bFormatTarget ) {
|
|
|
|
if (( dwMediaSize != IMAGE_SIZE_DMF ) &&
|
|
( dwMediaSize != IMAGE_SIZE_144 ) &&
|
|
( dwMediaSize != IMAGE_SIZE_12 )) {
|
|
|
|
ErrorExit( 0, "Only 1.2MB, 1.44MB, and DMF formatting is supported\n" );
|
|
}
|
|
}
|
|
|
|
if ( dwFileSize != dwMediaSize ) {
|
|
ErrorExit( 0, "Source image is not compatible with target media\n"
|
|
"(source size is %d bytes but target media is %d)\n",
|
|
dwFileSize,
|
|
dwMediaSize );
|
|
}
|
|
|
|
if ( bFormatTarget ) {
|
|
|
|
printf( "Formatting..." );
|
|
|
|
switch ( dwMediaSize ) {
|
|
case IMAGE_SIZE_DMF:
|
|
FormatDmf( hDevice );
|
|
break;
|
|
case IMAGE_SIZE_144:
|
|
FormatHD( hDevice, F3_1Pt44_512 );
|
|
break;
|
|
case IMAGE_SIZE_12:
|
|
FormatHD( hDevice, F5_1Pt2_512 );
|
|
}
|
|
|
|
printf( "done\n" );
|
|
|
|
}
|
|
}
|
|
|
|
//
|
|
// Map file for transfer
|
|
//
|
|
|
|
hMap = CreateFileMapping( hFile,
|
|
NULL,
|
|
( fDirection == FILE_TO_DEVICE ) ? PAGE_READONLY : PAGE_READWRITE,
|
|
0,
|
|
( fDirection == FILE_TO_DEVICE ) ? dwFileSize : dwMediaSize,
|
|
NULL );
|
|
|
|
if ( hMap == NULL ) {
|
|
dwGLE = GetLastError();
|
|
if ( fDirection == DEVICE_TO_FILE ) {
|
|
CloseHandle( hFile );
|
|
DeleteFile( chFileName );
|
|
}
|
|
ErrorExit( dwGLE, "Unable to map file %s\n", chFileName );
|
|
}
|
|
|
|
pMappedView = MapViewOfFile( hMap,
|
|
( fDirection == FILE_TO_DEVICE ) ? FILE_MAP_READ : FILE_MAP_WRITE,
|
|
0,
|
|
0,
|
|
0 );
|
|
|
|
if ( pMappedView == NULL ) {
|
|
dwGLE = GetLastError();
|
|
if ( fDirection == DEVICE_TO_FILE ) {
|
|
CloseHandle( hMap );
|
|
CloseHandle( hFile );
|
|
DeleteFile( chFileName );
|
|
}
|
|
ErrorExit( dwGLE, "Unable to map file %s\n", chFileName );
|
|
}
|
|
|
|
|
|
//
|
|
// Now we're ready to transfer.
|
|
//
|
|
|
|
printf( "Copying..." );
|
|
|
|
try { // might take in-page exception from mapped view error
|
|
|
|
if ( fDirection == FILE_TO_DEVICE ) {
|
|
|
|
if ( ! WriteFile( hDevice,
|
|
pMappedView,
|
|
dwFileSize,
|
|
&dwActual,
|
|
NULL )) {
|
|
|
|
ErrorExit( GETLASTERROR, "error while copying\n" );
|
|
}
|
|
}
|
|
|
|
else { // ( fDirection == DEVICE_TO_FILE )
|
|
|
|
if ( ! ReadFile( hDevice,
|
|
pMappedView,
|
|
dwMediaSize,
|
|
&dwActual,
|
|
NULL )) {
|
|
|
|
ErrorExit( GETLASTERROR, "error while copying\n" );
|
|
}
|
|
}
|
|
}
|
|
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
ErrorExit( 0, "exception %08X while copying\n", GetExceptionCode() );
|
|
}
|
|
|
|
printf( "done\n" );
|
|
|
|
//
|
|
// cleanup is free
|
|
//
|
|
|
|
exit( 0 );
|
|
|
|
}
|
|
|
|
|
|
void FormatDmf( HANDLE hDevice ) {
|
|
|
|
#define FORMAT_PARAMETERS_SIZE ( sizeof( FORMAT_EX_PARAMETERS ) \
|
|
+ sizeof( USHORT ) * 20 )
|
|
|
|
CHAR formatParametersBuffer[FORMAT_PARAMETERS_SIZE];
|
|
PFORMAT_EX_PARAMETERS formatParameters;
|
|
ULONG i, next;
|
|
BOOL b;
|
|
DWORD bytesWritten;
|
|
USHORT swapBuffer[3];
|
|
|
|
// Prepare the format parameters.
|
|
|
|
formatParameters = (PFORMAT_EX_PARAMETERS) formatParametersBuffer;
|
|
formatParameters->MediaType = F3_1Pt44_512;
|
|
formatParameters->FormatGapLength = 8;
|
|
formatParameters->SectorsPerTrack = 21;
|
|
|
|
next = 0;
|
|
for (i = 0; i < formatParameters->SectorsPerTrack; i += 2) {
|
|
formatParameters->SectorNumber[i] = (USHORT) (i/2 + 1);
|
|
next++;
|
|
}
|
|
|
|
for (i = 1; i < formatParameters->SectorsPerTrack; i += 2) {
|
|
formatParameters->SectorNumber[i] = (USHORT) (i/2 + next + 1);
|
|
}
|
|
|
|
// Start off by putting the boot sector as the last sector of
|
|
// the first track.
|
|
|
|
MoveMemory(&formatParameters->SectorNumber[0],
|
|
&formatParameters->SectorNumber[1],
|
|
20*sizeof(USHORT));
|
|
formatParameters->SectorNumber[20] = 1;
|
|
|
|
|
|
// Format each track on the floppy.
|
|
|
|
for (i = 0; i < 80; i++) {
|
|
|
|
formatParameters->StartCylinderNumber =
|
|
formatParameters->EndCylinderNumber = i;
|
|
formatParameters->StartHeadNumber = 0;
|
|
formatParameters->EndHeadNumber = 1;
|
|
|
|
b = DeviceIoControl(hDevice, IOCTL_DISK_FORMAT_TRACKS_EX,
|
|
formatParameters, FORMAT_PARAMETERS_SIZE,
|
|
NULL, 0, &bytesWritten, NULL);
|
|
|
|
if ( ! b ) {
|
|
ErrorExit( GETLASTERROR, "DMF format failed\n" );
|
|
}
|
|
|
|
// Skew the next cylinder by 3 sectors from this one.
|
|
|
|
MoveMemory(swapBuffer,
|
|
&formatParameters->SectorNumber[18],
|
|
3*sizeof(USHORT));
|
|
MoveMemory(&formatParameters->SectorNumber[3],
|
|
&formatParameters->SectorNumber[0],
|
|
18*sizeof(USHORT));
|
|
MoveMemory(&formatParameters->SectorNumber[0],
|
|
swapBuffer,
|
|
3*sizeof(USHORT));
|
|
|
|
}
|
|
}
|
|
|
|
|
|
void FormatHD( HANDLE hDevice, MEDIA_TYPE eMediaType ) {
|
|
|
|
FORMAT_PARAMETERS fp;
|
|
DWORD dwActual;
|
|
BOOL bSuccess;
|
|
|
|
if (( eMediaType != F5_1Pt2_512 ) &&
|
|
( eMediaType != F3_1Pt44_512 )) {
|
|
ErrorExit( 0, "Invalid media type for format request\n" );
|
|
}
|
|
|
|
fp.MediaType = eMediaType;
|
|
fp.StartCylinderNumber = 0;
|
|
fp.EndCylinderNumber = 79;
|
|
fp.StartHeadNumber = 0;
|
|
fp.EndHeadNumber = 1;
|
|
|
|
bSuccess = DeviceIoControl( hDevice,
|
|
IOCTL_DISK_FORMAT_TRACKS,
|
|
&fp,
|
|
sizeof( fp ),
|
|
NULL,
|
|
0,
|
|
&dwActual,
|
|
NULL );
|
|
|
|
if ( ! bSuccess ) {
|
|
ErrorExit( GETLASTERROR, "format failed\n" );
|
|
}
|
|
}
|
|
|
|
void ErrorExit( DWORD dwGLE, const char *szFormat, ... ) {
|
|
|
|
CHAR chBuffer[ 256 ];
|
|
va_list vaArgs;
|
|
|
|
if ( dwGLE == GETLASTERROR )
|
|
dwGLE = GetLastError();
|
|
|
|
va_start( vaArgs, szFormat );
|
|
vfprintf( stdout, szFormat, vaArgs );
|
|
va_end( vaArgs );
|
|
|
|
if ( dwGLE ) {
|
|
if ( FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM,
|
|
NULL,
|
|
dwGLE,
|
|
0x409,
|
|
chBuffer,
|
|
sizeof( chBuffer ),
|
|
NULL )) {
|
|
printf( "(%d) %s\n", dwGLE, chBuffer );
|
|
}
|
|
else {
|
|
printf( "Error code %d\n", dwGLE );
|
|
}
|
|
}
|
|
|
|
exit( 1 );
|
|
|
|
}
|
|
|
|
|
|
void Copyright( void ) {
|
|
|
|
printf( "\n"
|
|
"DMFIMAGE Diskette Image Utility Version 1.05\n"
|
|
"Copyright (C) Microsoft, 1994-1996. All rights reserved.\n"
|
|
"For Microsoft internal use only.\n"
|
|
"\n" );
|
|
|
|
}
|