BizHawk/waterbox/uzem/dump.c

174 lines
6.9 KiB
C

/*
Copyright (c) 2009 Eric Anderton
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#include <windows.h>
#include <winioctl.h>
#include <stdio.h>
struct SDPartitionEntry{
BYTE state;
BYTE startHead;
WORD startCylinder;
BYTE type;
BYTE endHead;
WORD endCylinder;
DWORD sectorOffset;
DWORD sectorCount;
};
// Partition 1 example
/*
entry.state = 0x00;
entry.startHead = 0x03;
entry.startCylinder = 0x003D;
entry.type = 0x06;
entry.endHead = 0x0D;
entry.endCylinder = 0xDBED;
entry.sectorOffset = 0x000000F9;
entry.sectorCount = 0x001E5F07;
*/
//Code mostly borrowed from: http://support.microsoft.com/kb/138434
#define SECTORS_PER_WRITE 4096
char drivePath[] = "\\\\.\\X:";
int main(int argc,char** argv)
{
HANDLE hCD, hFile;
DWORD dwNotUsed;
if (argc<3){
printf("Disk Image dumper - creates binary images of disks, suitable for SD media.\n");
printf("(c) 2009 Eric Anderton\n");
printf("\nUsage: dump DRIVELETTER FILENAME\n");
exit(1);
}
if(strlen(argv[1]) > 1){
printf("Invalid drive letter.\n");
exit(1);
}
// set the drive letter in the path specification
drivePath[4] = argv[1][0];
hFile = CreateFile (argv[2],GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
hCD = CreateFile (drivePath, GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,NULL);
if (hCD != INVALID_HANDLE_VALUE){
DISK_GEOMETRY disk;
PARTITION_INFORMATION partition;
PARTITION_INFORMATION_MBR mbr;
// Get sector size of compact disc
if (DeviceIoControl (hCD, IOCTL_DISK_GET_DRIVE_GEOMETRY,
NULL, 0, &disk, sizeof(disk),
&dwNotUsed, NULL))
{
LPBYTE lpSector;
DWORD dwSize = disk.BytesPerSector; // 2 sectors
DWORD dwReadSize = dwSize*SECTORS_PER_WRITE;
__int64 cylinders = *((__int64*)&disk);
__int64 sectors = cylinders * disk.TracksPerCylinder * disk.SectorsPerTrack;
__int64 totalSize = sectors*dwSize;
__int64 i;
printf("Cylinders %lld\nTracks Per Cylinder: %d\nSectors Per Track %d\nSector Size: %d\n",cylinders,disk.TracksPerCylinder,disk.SectorsPerTrack,dwSize);
printf("Total Sectors: %lld\n",sectors);
printf("Media Size: %lld\n",totalSize);
// Allocate buffer to hold sectors from compact disc. Note that
// the buffer will be allocated on a sector boundary because the
// allocation granularity is larger than the size of a sector on a
// compact disk.
lpSector = (LPBYTE)VirtualAlloc (NULL, dwReadSize,MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
SDPartitionEntry entry;
// query system about partition and fill out the partition structure
if(DeviceIoControl(hCD, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &partition, sizeof(PARTITION_INFORMATION), &dwNotUsed, NULL)){
entry.state = 0x00;
entry.startCylinder = 0;//(*(__int64*)(&partition.StartingOffset))/dwSize;
entry.startHead = 0x00; //TODO
entry.startCylinder = 0x0000; //TODO
entry.type = partition.PartitionType;
entry.endHead = 0x00; //TODO
entry.endCylinder = 0x0000; //TODO
entry.sectorOffset = partition.HiddenSectors;
entry.sectorCount = (*(__int64*)(&partition.PartitionLength))/dwSize;
printf("----------\n");
printf("state: %0.4X\n",entry.state);
// printf("startHead: %0.4X\n",entry.startHead);
// printf("startCylinder: %0.4X\n",entry.startCylinder);
printf("type: %0.2X\n",entry.type);
// printf("endHead: %0.4X\n",entry.endHead);
// printf("endCylinder: %0.4X\n",entry.endCylinder);
printf("sectorCount: %0.8X\n",entry.sectorCount);
printf("sectorOffset: %0.8X\n",entry.sectorOffset);
}
else{
printf("Error reading parition info.\n");
exit(1);
}
// build a replica of the MBR for a single-partition image (common for SD media)
memset(lpSector,0,dwSize);
memcpy(lpSector + 0x1BE,&entry,sizeof(SDPartitionEntry));
// Executable Marker
lpSector[0x1FE] = 0x55;
lpSector[0x1FF] = 0xAA;
WriteFile (hFile, lpSector, dwSize, &dwNotUsed, NULL);
// write out hidden sectors (empty)
memset(lpSector,0,dwSize);
for(i = 1; i < entry.sectorOffset; i++){
WriteFile (hFile, lpSector, dwSize, &dwNotUsed, NULL);
}
// iteratively read all the sectors for the disk image
printf("Writing...");
for(i = 0; i < sectors/SECTORS_PER_WRITE; i++){
// Read sectors from the disc and write them to a file.
ReadFile (hCD, lpSector, dwReadSize, &dwNotUsed, NULL);
WriteFile (hFile, lpSector, dwReadSize, &dwNotUsed, NULL);
}
DWORD leftovers = sectors-i;
if(leftovers > 0){
dwReadSize = leftovers*dwSize;
ReadFile (hCD, lpSector, dwReadSize, &dwNotUsed, NULL);
WriteFile (hFile, lpSector, dwReadSize, &dwNotUsed, NULL);
}
VirtualFree (lpSector, 0, MEM_RELEASE);
}
CloseHandle (hCD);
CloseHandle (hFile);
}
}