525 lines
14 KiB
C
525 lines
14 KiB
C
/*++
|
|
|
|
Module Name:
|
|
|
|
mfmt.c
|
|
|
|
Abstract:
|
|
|
|
This program is designed to show how to access a physical floppy
|
|
disk using the Win32 API set.
|
|
|
|
This program has two major functions.
|
|
|
|
- It can be used to display the geometry of a disk
|
|
|
|
mfmt -g a:
|
|
|
|
- It can be used to produce a disk image, or to write a disk
|
|
image to a floppy.
|
|
|
|
mfmt -c a: bootdisk - produce a disk image of a:
|
|
|
|
mfmt -c bootdisk a: - make a: identical to bootdisk image
|
|
|
|
This program is very very simple. Minimal error checking is done. It is
|
|
meant to provide an example of how to:
|
|
|
|
- Open a physical disk
|
|
|
|
- Read a disk's geometry
|
|
|
|
- Perform a low level format operation
|
|
|
|
- read and write physical sectors
|
|
|
|
Author:
|
|
|
|
Some Guy in the NT group (sgitng) 05-Oct-1992
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <windows.h>
|
|
#include <winioctl.h>
|
|
#include <string.h>
|
|
#include <memory.h>
|
|
|
|
DISK_GEOMETRY SupportedGeometry[20];
|
|
DWORD SupportedGeometryCount;
|
|
|
|
BOOL
|
|
GetDiskGeometry(
|
|
HANDLE hDisk,
|
|
PDISK_GEOMETRY lpGeometry
|
|
)
|
|
|
|
{
|
|
DWORD ReturnedByteCount;
|
|
|
|
return DeviceIoControl(
|
|
hDisk,
|
|
IOCTL_DISK_GET_DRIVE_GEOMETRY,
|
|
NULL,
|
|
0,
|
|
lpGeometry,
|
|
sizeof(*lpGeometry),
|
|
&ReturnedByteCount,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
DWORD
|
|
GetSupportedGeometrys(
|
|
HANDLE hDisk
|
|
)
|
|
{
|
|
DWORD ReturnedByteCount;
|
|
BOOL b;
|
|
DWORD NumberSupported;
|
|
|
|
b = DeviceIoControl(
|
|
hDisk,
|
|
IOCTL_DISK_GET_MEDIA_TYPES,
|
|
NULL,
|
|
0,
|
|
SupportedGeometry,
|
|
sizeof(SupportedGeometry),
|
|
&ReturnedByteCount,
|
|
NULL
|
|
);
|
|
if ( b ) {
|
|
NumberSupported = ReturnedByteCount / sizeof(DISK_GEOMETRY);
|
|
}
|
|
else {
|
|
NumberSupported = 0;
|
|
}
|
|
SupportedGeometryCount = NumberSupported;
|
|
|
|
return NumberSupported;
|
|
}
|
|
|
|
VOID
|
|
PrintGeometry(
|
|
LPSTR lpDriveName,
|
|
PDISK_GEOMETRY lpGeometry
|
|
)
|
|
{
|
|
LPSTR MediaType;
|
|
|
|
if (lpDriveName) {
|
|
printf("Geometry for Drive %s\n",lpDriveName);
|
|
}
|
|
|
|
switch ( lpGeometry->MediaType ) {
|
|
case F5_1Pt2_512: MediaType = "5.25, 1.2MB, 512 bytes/sector";break;
|
|
case F3_1Pt44_512: MediaType = "3.5, 1.44MB, 512 bytes/sector";break;
|
|
case F3_2Pt88_512: MediaType = "3.5, 2.88MB, 512 bytes/sector";break;
|
|
case F3_20Pt8_512: MediaType = "3.5, 20.8MB, 512 bytes/sector";break;
|
|
case F3_720_512: MediaType = "3.5, 720KB, 512 bytes/sector";break;
|
|
case F5_360_512: MediaType = "5.25, 360KB, 512 bytes/sector";break;
|
|
case F5_320_512: MediaType = "5.25, 320KB, 512 bytes/sector";break;
|
|
case F5_320_1024: MediaType = "5.25, 320KB, 1024 bytes/sector";break;
|
|
case F5_180_512: MediaType = "5.25, 180KB, 512 bytes/sector";break;
|
|
case F5_160_512: MediaType = "5.25, 160KB, 512 bytes/sector";break;
|
|
case RemovableMedia: MediaType = "Removable media other than floppy";break;
|
|
case FixedMedia: MediaType = "Fixed hard disk media";break;
|
|
default: MediaType = "Unknown";break;
|
|
}
|
|
printf(" Media Type %s\n",MediaType);
|
|
printf(" Cylinders %d Tracks/Cylinder %d Sectors/Track %d\n",
|
|
lpGeometry->Cylinders.LowPart,
|
|
lpGeometry->TracksPerCylinder,
|
|
lpGeometry->SectorsPerTrack
|
|
);
|
|
}
|
|
|
|
BOOL
|
|
LowLevelFormat(
|
|
HANDLE hDisk,
|
|
PDISK_GEOMETRY lpGeometry
|
|
)
|
|
{
|
|
FORMAT_PARAMETERS FormatParameters;
|
|
PBAD_TRACK_NUMBER lpBadTrack;
|
|
UINT i;
|
|
BOOL b;
|
|
DWORD ReturnedByteCount;
|
|
|
|
FormatParameters.MediaType = lpGeometry->MediaType;
|
|
FormatParameters.StartHeadNumber = 0;
|
|
FormatParameters.EndHeadNumber = lpGeometry->TracksPerCylinder - 1;
|
|
lpBadTrack = (PBAD_TRACK_NUMBER) LocalAlloc(LMEM_ZEROINIT,lpGeometry->TracksPerCylinder*sizeof(*lpBadTrack));
|
|
|
|
for (i = 0; i < lpGeometry->Cylinders.LowPart; i++) {
|
|
|
|
FormatParameters.StartCylinderNumber = i;
|
|
FormatParameters.EndCylinderNumber = i;
|
|
|
|
b = DeviceIoControl(
|
|
hDisk,
|
|
IOCTL_DISK_FORMAT_TRACKS,
|
|
&FormatParameters,
|
|
sizeof(FormatParameters),
|
|
lpBadTrack,
|
|
lpGeometry->TracksPerCylinder*sizeof(*lpBadTrack),
|
|
&ReturnedByteCount,
|
|
NULL
|
|
);
|
|
|
|
if (!b ) {
|
|
LocalFree(lpBadTrack);
|
|
return b;
|
|
}
|
|
}
|
|
|
|
LocalFree(lpBadTrack);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
LockVolume(
|
|
HANDLE hDisk
|
|
)
|
|
{
|
|
DWORD ReturnedByteCount;
|
|
|
|
return DeviceIoControl(
|
|
hDisk,
|
|
FSCTL_LOCK_VOLUME,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&ReturnedByteCount,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
BOOL
|
|
UnlockVolume(
|
|
HANDLE hDisk
|
|
)
|
|
{
|
|
DWORD ReturnedByteCount;
|
|
|
|
return DeviceIoControl(
|
|
hDisk,
|
|
FSCTL_UNLOCK_VOLUME,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&ReturnedByteCount,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
BOOL
|
|
DismountVolume(
|
|
HANDLE hDisk
|
|
)
|
|
{
|
|
DWORD ReturnedByteCount;
|
|
|
|
return DeviceIoControl(
|
|
hDisk,
|
|
FSCTL_DISMOUNT_VOLUME,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
0,
|
|
&ReturnedByteCount,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
DWORD
|
|
_cdecl
|
|
main(
|
|
int argc,
|
|
char *argv[],
|
|
char *envp[]
|
|
)
|
|
{
|
|
char Drive[MAX_PATH];
|
|
HANDLE hDrive, hDiskImage;
|
|
DISK_GEOMETRY Geometry;
|
|
UINT i;
|
|
char c, *p;
|
|
LPSTR DriveName;
|
|
BOOL fUsage = TRUE;
|
|
BOOL fShowGeometry = FALSE;
|
|
BOOL fDiskImage = FALSE;
|
|
BOOL SourceIsDrive;
|
|
LPSTR Source, Destination, DiskImage;
|
|
|
|
if ( argc > 1 ) {
|
|
fUsage = FALSE;
|
|
while (--argc) {
|
|
p = *++argv;
|
|
if (*p == '/' || *p == '-') {
|
|
while (c = *++p)
|
|
switch (toupper( c )) {
|
|
case '?':
|
|
fUsage = TRUE;
|
|
break;
|
|
|
|
case 'C':
|
|
fDiskImage = TRUE;
|
|
argc--, argv++;
|
|
Source = *argv;
|
|
argc--, argv++;
|
|
Destination = *argv;
|
|
break;
|
|
|
|
case 'G':
|
|
fShowGeometry = TRUE;
|
|
argc--, argv++;
|
|
DriveName = *argv;
|
|
break;
|
|
|
|
default:
|
|
printf("MFMT: Invalid switch - /%c\n", c );
|
|
fUsage = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if ( fUsage ) {
|
|
printf("usage: MFMT switches \n" );
|
|
printf(" [-?] display this message\n" );
|
|
printf(" [-g drive] shows disk geometry\n" );
|
|
printf(" [-c source destination] produce diskimage\n" );
|
|
ExitProcess(1);
|
|
}
|
|
|
|
if ( fShowGeometry ) {
|
|
sprintf(Drive,"\\\\.\\%s",DriveName);
|
|
hDrive = CreateFile(
|
|
Drive,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL
|
|
);
|
|
if ( hDrive == INVALID_HANDLE_VALUE ) {
|
|
printf("MFMT: Open %s failed %d\n",DriveName,GetLastError());
|
|
ExitProcess(1);
|
|
}
|
|
|
|
LockVolume(hDrive);
|
|
|
|
if ( !GetDiskGeometry(hDrive,&Geometry) ) {
|
|
printf("MFMT: GetDiskGeometry %s failed %d\n",DriveName,GetLastError());
|
|
ExitProcess(1);
|
|
}
|
|
PrintGeometry(DriveName,&Geometry);
|
|
|
|
if ( !GetSupportedGeometrys(hDrive) ) {
|
|
printf("MFMT: GetSupportedGeometrys %s failed %d\n",DriveName,GetLastError());
|
|
ExitProcess(1);
|
|
}
|
|
printf("\nDrive %s supports the following disk geometries\n",DriveName);
|
|
|
|
for(i=0;i<SupportedGeometryCount;i++) {
|
|
printf("\n");
|
|
PrintGeometry(NULL,&SupportedGeometry[i]);
|
|
}
|
|
|
|
printf("\n");
|
|
ExitProcess(0);
|
|
}
|
|
|
|
if ( fDiskImage ) {
|
|
SourceIsDrive = FALSE;
|
|
if ( Source[strlen(Source)-1] == ':' ) {
|
|
SourceIsDrive = TRUE;
|
|
sprintf(Drive,"\\\\.\\%s",Source);
|
|
DiskImage = Destination;
|
|
}
|
|
if ( Destination[strlen(Destination)-1] == ':' ) {
|
|
if ( SourceIsDrive ) {
|
|
printf("MFMT: Source and Destination cannot both be drives\n");
|
|
ExitProcess(1);
|
|
}
|
|
SourceIsDrive = FALSE;
|
|
sprintf(Drive,"\\\\.\\%s",Destination);
|
|
DiskImage = Source;
|
|
}
|
|
else {
|
|
if ( !SourceIsDrive ) {
|
|
printf("MFMT: Either Source or Destination must be a drive\n");
|
|
ExitProcess(1);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Open and Lock the drive
|
|
//
|
|
|
|
hDrive = CreateFile(
|
|
Drive,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
0,
|
|
NULL
|
|
);
|
|
if ( hDrive == INVALID_HANDLE_VALUE ) {
|
|
printf("MFMT: Open %s failed %d\n",DriveName,GetLastError());
|
|
ExitProcess(1);
|
|
}
|
|
LockVolume(hDrive);
|
|
|
|
if ( !GetDiskGeometry(hDrive,&Geometry) ) {
|
|
printf("MFMT: GetDiskGeometry %s failed %d\n",DriveName,GetLastError());
|
|
ExitProcess(1);
|
|
}
|
|
|
|
if ( !GetSupportedGeometrys(hDrive) ) {
|
|
printf("MFMT: GetSupportedGeometrys %s failed %d\n",DriveName,GetLastError());
|
|
ExitProcess(1);
|
|
}
|
|
|
|
//
|
|
// Open the disk image file
|
|
//
|
|
|
|
hDiskImage = CreateFile(
|
|
DiskImage,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
0,
|
|
NULL,
|
|
SourceIsDrive ? CREATE_ALWAYS : OPEN_EXISTING,
|
|
0,
|
|
NULL
|
|
);
|
|
if ( hDiskImage == INVALID_HANDLE_VALUE ) {
|
|
printf("MFMT: Open %s failed %d\n",DiskImage,GetLastError());
|
|
ExitProcess(1);
|
|
}
|
|
|
|
//
|
|
// Now do the copy
|
|
//
|
|
{
|
|
LPVOID IoBuffer;
|
|
BOOL b;
|
|
DWORD BytesRead, BytesWritten;
|
|
DWORD FileSize;
|
|
DWORD GeometrySize;
|
|
|
|
//
|
|
// If we are copying from floppy to file, just do the copy
|
|
// Otherwise, we might have to format the floppy first
|
|
//
|
|
|
|
if ( SourceIsDrive ) {
|
|
|
|
//
|
|
// Device reads must be sector aligned. VirtualAlloc will
|
|
// garuntee alignment
|
|
//
|
|
|
|
GeometrySize = Geometry.Cylinders.LowPart *
|
|
Geometry.TracksPerCylinder *
|
|
Geometry.SectorsPerTrack *
|
|
Geometry.BytesPerSector;
|
|
|
|
IoBuffer = VirtualAlloc(NULL,GeometrySize,MEM_COMMIT,PAGE_READWRITE);
|
|
|
|
if ( !IoBuffer ) {
|
|
printf("MFMT: Buffer Allocation Failed\n");
|
|
ExitProcess(1);
|
|
}
|
|
|
|
b = ReadFile(hDrive,IoBuffer, GeometrySize, &BytesRead, NULL);
|
|
if (b && BytesRead){
|
|
b = WriteFile(hDiskImage,IoBuffer, BytesRead, &BytesWritten, NULL);
|
|
if ( !b || ( BytesRead != BytesWritten ) ) {
|
|
printf("MFMT: Fatal Write Error %d\n",GetLastError());
|
|
ExitProcess(1);
|
|
}
|
|
}
|
|
else {
|
|
printf("MFMT: Fatal Read Error %d\n",GetLastError());
|
|
ExitProcess(1);
|
|
}
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Check to see if the image will fit on the floppy. If it
|
|
// will, then LowLevelFormat the floppy and press on
|
|
//
|
|
|
|
FileSize = GetFileSize(hDiskImage,NULL);
|
|
|
|
b = FALSE;
|
|
for(i=0;i<SupportedGeometryCount;i++) {
|
|
GeometrySize = SupportedGeometry[i].Cylinders.LowPart *
|
|
SupportedGeometry[i].TracksPerCylinder *
|
|
SupportedGeometry[i].SectorsPerTrack *
|
|
SupportedGeometry[i].BytesPerSector;
|
|
if ( GeometrySize >= FileSize ) {
|
|
|
|
IoBuffer = VirtualAlloc(NULL,GeometrySize,MEM_COMMIT,PAGE_READWRITE);
|
|
|
|
if ( !IoBuffer ) {
|
|
printf("MFMT: Buffer Allocation Failed\n");
|
|
ExitProcess(1);
|
|
}
|
|
|
|
//
|
|
// Format the floppy
|
|
//
|
|
|
|
LowLevelFormat(hDrive,&SupportedGeometry[i]);
|
|
|
|
b = ReadFile(hDiskImage,IoBuffer, GeometrySize, &BytesRead, NULL);
|
|
if (b && BytesRead){
|
|
b = WriteFile(hDrive,IoBuffer, BytesRead, &BytesWritten, NULL);
|
|
if ( !b || ( BytesRead != BytesWritten ) ) {
|
|
printf("MFMT: Fatal Write Error %d\n",GetLastError());
|
|
ExitProcess(1);
|
|
}
|
|
}
|
|
else {
|
|
printf("MFMT: Fatal Read Error %d\n",GetLastError());
|
|
ExitProcess(1);
|
|
}
|
|
b = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( !b ) {
|
|
printf("MFMT: FileSize %d is not supported on drive %s\n",FileSize,DriveName);
|
|
ExitProcess(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Dismounting forces the filesystem to re-evaluate the media id
|
|
// and geometry. This is the same as popping the floppy in and out
|
|
// of the disk drive
|
|
//
|
|
|
|
DismountVolume(hDrive);
|
|
UnlockVolume(hDrive);
|
|
|
|
ExitProcess(0);
|
|
}
|
|
}
|