1add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// 2add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// C++ Interface: diskio (Windows-specific components) 3add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// 4add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// Description: Class to handle low-level disk I/O for GPT fdisk 5add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// 6add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// 7add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// Author: Rod Smith <rodsmith@rodsbooks.com>, (C) 2009 8add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// 9add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// Copyright: See COPYING file that comes with this distribution 10add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// 11add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// 12add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// This program is copyright (c) 2009, 2010 by Roderick W. Smith. It is distributed 13add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// under the terms of the GNU GPL version 2, as detailed in the COPYING file. 14add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 15add79a6e1b3a1af1305f02d51eb3aa148f580caasrs#define __STDC_LIMIT_MACROS 16add79a6e1b3a1af1305f02d51eb3aa148f580caasrs#define __STDC_CONSTANT_MACROS 17add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 18add79a6e1b3a1af1305f02d51eb3aa148f580caasrs#include <windows.h> 19add79a6e1b3a1af1305f02d51eb3aa148f580caasrs#include <winioctl.h> 20add79a6e1b3a1af1305f02d51eb3aa148f580caasrs#define fstat64 fstat 21add79a6e1b3a1af1305f02d51eb3aa148f580caasrs#define stat64 stat 2208bb0da07953af605b4918e268272de15ac151aasrs#define S_IRGRP 0 23add79a6e1b3a1af1305f02d51eb3aa148f580caasrs#define S_IROTH 0 24add79a6e1b3a1af1305f02d51eb3aa148f580caasrs#include <stdio.h> 25add79a6e1b3a1af1305f02d51eb3aa148f580caasrs#include <string> 26add79a6e1b3a1af1305f02d51eb3aa148f580caasrs#include <stdint.h> 27add79a6e1b3a1af1305f02d51eb3aa148f580caasrs#include <errno.h> 28add79a6e1b3a1af1305f02d51eb3aa148f580caasrs#include <fcntl.h> 29add79a6e1b3a1af1305f02d51eb3aa148f580caasrs#include <sys/stat.h> 30add79a6e1b3a1af1305f02d51eb3aa148f580caasrs#include <iostream> 31add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 32add79a6e1b3a1af1305f02d51eb3aa148f580caasrs#include "support.h" 33add79a6e1b3a1af1305f02d51eb3aa148f580caasrs#include "diskio.h" 34add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 35add79a6e1b3a1af1305f02d51eb3aa148f580caasrsusing namespace std; 36add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 37add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// Returns the official Windows name for a shortened version of same. 38add79a6e1b3a1af1305f02d51eb3aa148f580caasrsvoid DiskIO::MakeRealName(void) { 39e321d444dcca514cf6b53459e388ddcbaab6176csrs size_t colonPos; 40add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 41add79a6e1b3a1af1305f02d51eb3aa148f580caasrs colonPos = userFilename.find(':', 0); 42add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if ((colonPos != string::npos) && (colonPos <= 3)) { 43add79a6e1b3a1af1305f02d51eb3aa148f580caasrs realFilename = "\\\\.\\physicaldrive"; 44add79a6e1b3a1af1305f02d51eb3aa148f580caasrs realFilename += userFilename.substr(0, colonPos); 450a6973119c9e9984ad47a6da3231e8d16f996c5csrs } else { 460a6973119c9e9984ad47a6da3231e8d16f996c5csrs realFilename = userFilename; 47add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if/else 48add79a6e1b3a1af1305f02d51eb3aa148f580caasrs} // DiskIO::MakeRealName() 49add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 50add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// Open the currently on-record file for reading 51add79a6e1b3a1af1305f02d51eb3aa148f580caasrsint DiskIO::OpenForRead(void) { 52add79a6e1b3a1af1305f02d51eb3aa148f580caasrs int shouldOpen = 1; 53add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 54add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (isOpen) { // file is already open 55add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (openForWrite) { 56add79a6e1b3a1af1305f02d51eb3aa148f580caasrs Close(); 57add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } else { 58add79a6e1b3a1af1305f02d51eb3aa148f580caasrs shouldOpen = 0; 59add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if/else 60add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if 61add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 62add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (shouldOpen) { 63add79a6e1b3a1af1305f02d51eb3aa148f580caasrs fd = CreateFile(realFilename.c_str(),GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 64add79a6e1b3a1af1305f02d51eb3aa148f580caasrs NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); 65add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (fd == INVALID_HANDLE_VALUE) { 66add79a6e1b3a1af1305f02d51eb3aa148f580caasrs CloseHandle(fd); 6755d926192adc984462509b2966e23bc0d1129bbdsrs cerr << "Problem opening " << realFilename << " for reading!\n"; 68add79a6e1b3a1af1305f02d51eb3aa148f580caasrs realFilename = ""; 69add79a6e1b3a1af1305f02d51eb3aa148f580caasrs userFilename = ""; 70add79a6e1b3a1af1305f02d51eb3aa148f580caasrs isOpen = 0; 71add79a6e1b3a1af1305f02d51eb3aa148f580caasrs openForWrite = 0; 72add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } else { 73add79a6e1b3a1af1305f02d51eb3aa148f580caasrs isOpen = 1; 74add79a6e1b3a1af1305f02d51eb3aa148f580caasrs openForWrite = 0; 75add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if/else 76add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if 77add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 78add79a6e1b3a1af1305f02d51eb3aa148f580caasrs return isOpen; 79add79a6e1b3a1af1305f02d51eb3aa148f580caasrs} // DiskIO::OpenForRead(void) 80add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 81add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// An extended file-open function. This includes some system-specific checks. 82add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// Returns 1 if the file is open, 0 otherwise.... 83add79a6e1b3a1af1305f02d51eb3aa148f580caasrsint DiskIO::OpenForWrite(void) { 84add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if ((isOpen) && (openForWrite)) 85add79a6e1b3a1af1305f02d51eb3aa148f580caasrs return 1; 86add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 87add79a6e1b3a1af1305f02d51eb3aa148f580caasrs // Close the disk, in case it's already open for reading only.... 88add79a6e1b3a1af1305f02d51eb3aa148f580caasrs Close(); 89add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 90add79a6e1b3a1af1305f02d51eb3aa148f580caasrs // try to open the device; may fail.... 91add79a6e1b3a1af1305f02d51eb3aa148f580caasrs fd = CreateFile(realFilename.c_str(), GENERIC_READ | GENERIC_WRITE, 92add79a6e1b3a1af1305f02d51eb3aa148f580caasrs FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 93add79a6e1b3a1af1305f02d51eb3aa148f580caasrs FILE_ATTRIBUTE_NORMAL, NULL); 9408bb0da07953af605b4918e268272de15ac151aasrs // Preceding call can fail when creating backup files; if so, try 9508bb0da07953af605b4918e268272de15ac151aasrs // again with different option... 9608bb0da07953af605b4918e268272de15ac151aasrs if (fd == INVALID_HANDLE_VALUE) { 9708bb0da07953af605b4918e268272de15ac151aasrs CloseHandle(fd); 9808bb0da07953af605b4918e268272de15ac151aasrs fd = CreateFile(realFilename.c_str(), GENERIC_READ | GENERIC_WRITE, 9908bb0da07953af605b4918e268272de15ac151aasrs FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS, 10008bb0da07953af605b4918e268272de15ac151aasrs FILE_ATTRIBUTE_NORMAL, NULL); 10108bb0da07953af605b4918e268272de15ac151aasrs } // if 102add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (fd == INVALID_HANDLE_VALUE) { 103add79a6e1b3a1af1305f02d51eb3aa148f580caasrs CloseHandle(fd); 104add79a6e1b3a1af1305f02d51eb3aa148f580caasrs isOpen = 0; 105add79a6e1b3a1af1305f02d51eb3aa148f580caasrs openForWrite = 0; 1060a6973119c9e9984ad47a6da3231e8d16f996c5csrs errno = GetLastError(); 1070a6973119c9e9984ad47a6da3231e8d16f996c5csrs } else { 1080a6973119c9e9984ad47a6da3231e8d16f996c5csrs isOpen = 1; 1090a6973119c9e9984ad47a6da3231e8d16f996c5csrs openForWrite = 1; 110add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if/else 111add79a6e1b3a1af1305f02d51eb3aa148f580caasrs return isOpen; 112add79a6e1b3a1af1305f02d51eb3aa148f580caasrs} // DiskIO::OpenForWrite(void) 113add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 114add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// Close the disk device. Note that this does NOT erase the stored filenames, 115add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// so the file can be re-opened without specifying the filename. 116add79a6e1b3a1af1305f02d51eb3aa148f580caasrsvoid DiskIO::Close(void) { 117add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (isOpen) 118add79a6e1b3a1af1305f02d51eb3aa148f580caasrs CloseHandle(fd); 119add79a6e1b3a1af1305f02d51eb3aa148f580caasrs isOpen = 0; 120add79a6e1b3a1af1305f02d51eb3aa148f580caasrs openForWrite = 0; 121add79a6e1b3a1af1305f02d51eb3aa148f580caasrs} // DiskIO::Close() 122add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 123add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// Returns block size of device pointed to by fd file descriptor. If the ioctl 12455d926192adc984462509b2966e23bc0d1129bbdsrs// returns an error condition, assume it's a disk file and return a value of 12555d926192adc984462509b2966e23bc0d1129bbdsrs// SECTOR_SIZE (512). If the disk can't be opened at all, return a value of 0. 126add79a6e1b3a1af1305f02d51eb3aa148f580caasrsint DiskIO::GetBlockSize(void) { 12755d926192adc984462509b2966e23bc0d1129bbdsrs DWORD blockSize = 0, retBytes; 12855d926192adc984462509b2966e23bc0d1129bbdsrs DISK_GEOMETRY_EX geom; 129add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 130add79a6e1b3a1af1305f02d51eb3aa148f580caasrs // If disk isn't open, try to open it.... 131add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (!isOpen) { 132add79a6e1b3a1af1305f02d51eb3aa148f580caasrs OpenForRead(); 133add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if 134add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 135add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (isOpen) { 136699941e25a1fcf0beec124203747c8ed20842989srs if (DeviceIoControl(fd, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, 137699941e25a1fcf0beec124203747c8ed20842989srs &geom, sizeof(geom), &retBytes, NULL)) { 13855d926192adc984462509b2966e23bc0d1129bbdsrs blockSize = geom.Geometry.BytesPerSector; 139699941e25a1fcf0beec124203747c8ed20842989srs } else { // was probably an ordinary file; set default value.... 140add79a6e1b3a1af1305f02d51eb3aa148f580caasrs blockSize = SECTOR_SIZE; 141699941e25a1fcf0beec124203747c8ed20842989srs } // if/else 142add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if (isOpen) 143add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 144add79a6e1b3a1af1305f02d51eb3aa148f580caasrs return (blockSize); 145add79a6e1b3a1af1305f02d51eb3aa148f580caasrs} // DiskIO::GetBlockSize() 146add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 147bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs// Returns the number of heads, according to the kernel, or 255 if the 148bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs// correct value can't be determined. 149bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrsuint32_t DiskIO::GetNumHeads(void) { 150bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs return UINT32_C(255); 151bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs} // DiskIO::GetNumHeads(); 152bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs 153bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs// Returns the number of sectors per track, according to the kernel, or 63 154bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs// if the correct value can't be determined. 155bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrsuint32_t DiskIO::GetNumSecsPerTrack(void) { 156bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs return UINT32_C(63); 157bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs} // DiskIO::GetNumSecsPerTrack() 158bf8950cad0285ee6ab8a896e8d0a30c5fb62c7afsrs 159add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// Resync disk caches so the OS uses the new partition table. This code varies 160add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// a lot from one OS to another. 161a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs// Returns 1 on success, 0 if the kernel continues to use the old partition table. 162a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srsint DiskIO::DiskSync(void) { 1630a6973119c9e9984ad47a6da3231e8d16f996c5csrs DWORD i; 1640a6973119c9e9984ad47a6da3231e8d16f996c5csrs GET_LENGTH_INFORMATION buf; 165a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs int retval = 0; 166add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 167add79a6e1b3a1af1305f02d51eb3aa148f580caasrs // If disk isn't open, try to open it.... 1680a6973119c9e9984ad47a6da3231e8d16f996c5csrs if (!openForWrite) { 1690a6973119c9e9984ad47a6da3231e8d16f996c5csrs OpenForWrite(); 170add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if 171add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 172add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (isOpen) { 1730a6973119c9e9984ad47a6da3231e8d16f996c5csrs if (DeviceIoControl(fd, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, &buf, sizeof(buf), &i, NULL) == 0) { 1740a6973119c9e9984ad47a6da3231e8d16f996c5csrs cout << "Disk synchronization failed! The computer may use the old partition table\n" 1750a6973119c9e9984ad47a6da3231e8d16f996c5csrs << "until you reboot or remove and re-insert the disk!\n"; 1760a6973119c9e9984ad47a6da3231e8d16f996c5csrs } else { 1770a6973119c9e9984ad47a6da3231e8d16f996c5csrs cout << "Disk synchronization succeeded! The computer should now use the new\n" 1780a6973119c9e9984ad47a6da3231e8d16f996c5csrs << "partition table.\n"; 179a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs retval = 1; 1800a6973119c9e9984ad47a6da3231e8d16f996c5csrs } // if/else 1810a6973119c9e9984ad47a6da3231e8d16f996c5csrs } else { 1820a6973119c9e9984ad47a6da3231e8d16f996c5csrs cout << "Unable to open the disk for synchronization operation! The computer will\n" 1830a6973119c9e9984ad47a6da3231e8d16f996c5csrs << "continue to use the old partition table until you reboot or remove and\n" 1840a6973119c9e9984ad47a6da3231e8d16f996c5csrs << "re-insert the disk!\n"; 185add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if (isOpen) 186a17fe69ec07c93a24894e4c4243f05af2bfc5bd7srs return retval; 187add79a6e1b3a1af1305f02d51eb3aa148f580caasrs} // DiskIO::DiskSync() 188add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 189add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// Seek to the specified sector. Returns 1 on success, 0 on failure. 190add79a6e1b3a1af1305f02d51eb3aa148f580caasrsint DiskIO::Seek(uint64_t sector) { 191add79a6e1b3a1af1305f02d51eb3aa148f580caasrs int retval = 1; 192add79a6e1b3a1af1305f02d51eb3aa148f580caasrs LARGE_INTEGER seekTo; 193add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 194add79a6e1b3a1af1305f02d51eb3aa148f580caasrs // If disk isn't open, try to open it.... 195add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (!isOpen) { 196add79a6e1b3a1af1305f02d51eb3aa148f580caasrs retval = OpenForRead(); 197add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if 198add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 199add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (isOpen) { 2000a6973119c9e9984ad47a6da3231e8d16f996c5csrs seekTo.QuadPart = sector * (uint64_t) GetBlockSize(); 201add79a6e1b3a1af1305f02d51eb3aa148f580caasrs retval = SetFilePointerEx(fd, seekTo, NULL, FILE_BEGIN); 202add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (retval == 0) { 203add79a6e1b3a1af1305f02d51eb3aa148f580caasrs errno = GetLastError(); 2040a6973119c9e9984ad47a6da3231e8d16f996c5csrs cerr << "Error when seeking to " << seekTo.QuadPart << "! Error is " << errno << "\n"; 205add79a6e1b3a1af1305f02d51eb3aa148f580caasrs retval = 0; 206add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if 207add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if 208add79a6e1b3a1af1305f02d51eb3aa148f580caasrs return retval; 209add79a6e1b3a1af1305f02d51eb3aa148f580caasrs} // DiskIO::Seek() 210add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 211add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// A variant on the standard read() function. Done to work around 212add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// limitations in FreeBSD concerning the matching of the sector 213add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// size with the number of bytes read. 214add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// Returns the number of bytes read into buffer. 215add79a6e1b3a1af1305f02d51eb3aa148f580caasrsint DiskIO::Read(void* buffer, int numBytes) { 216add79a6e1b3a1af1305f02d51eb3aa148f580caasrs int blockSize = 512, i, numBlocks; 217add79a6e1b3a1af1305f02d51eb3aa148f580caasrs char* tempSpace; 218add79a6e1b3a1af1305f02d51eb3aa148f580caasrs DWORD retval = 0; 219add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 220add79a6e1b3a1af1305f02d51eb3aa148f580caasrs // If disk isn't open, try to open it.... 221add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (!isOpen) { 222add79a6e1b3a1af1305f02d51eb3aa148f580caasrs OpenForRead(); 223add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if 224add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 225add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (isOpen) { 226add79a6e1b3a1af1305f02d51eb3aa148f580caasrs // Compute required space and allocate memory 227add79a6e1b3a1af1305f02d51eb3aa148f580caasrs blockSize = GetBlockSize(); 228add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (numBytes <= blockSize) { 229add79a6e1b3a1af1305f02d51eb3aa148f580caasrs numBlocks = 1; 230cb76c673eeb84344887715d36d44b799042be5a5srs tempSpace = new char [blockSize]; 231add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } else { 232add79a6e1b3a1af1305f02d51eb3aa148f580caasrs numBlocks = numBytes / blockSize; 233cb76c673eeb84344887715d36d44b799042be5a5srs if ((numBytes % blockSize) != 0) 234cb76c673eeb84344887715d36d44b799042be5a5srs numBlocks++; 235cb76c673eeb84344887715d36d44b799042be5a5srs tempSpace = new char [numBlocks * blockSize]; 236add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if/else 2376aae2a9b70e9f88926baad94c1eea40e0b534f01srs if (tempSpace == NULL) { 2386aae2a9b70e9f88926baad94c1eea40e0b534f01srs cerr << "Unable to allocate memory in DiskIO::Read()! Terminating!\n"; 2396aae2a9b70e9f88926baad94c1eea40e0b534f01srs exit(1); 2406aae2a9b70e9f88926baad94c1eea40e0b534f01srs } // if 2413488294d718a0e8b7f312c80c9e5729671173f6asrs 242add79a6e1b3a1af1305f02d51eb3aa148f580caasrs // Read the data into temporary space, then copy it to buffer 243add79a6e1b3a1af1305f02d51eb3aa148f580caasrs ReadFile(fd, tempSpace, numBlocks * blockSize, &retval, NULL); 244add79a6e1b3a1af1305f02d51eb3aa148f580caasrs for (i = 0; i < numBytes; i++) { 245add79a6e1b3a1af1305f02d51eb3aa148f580caasrs ((char*) buffer)[i] = tempSpace[i]; 246add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // for 247add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 248add79a6e1b3a1af1305f02d51eb3aa148f580caasrs // Adjust the return value, if necessary.... 249add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (((numBlocks * blockSize) != numBytes) && (retval > 0)) 250add79a6e1b3a1af1305f02d51eb3aa148f580caasrs retval = numBytes; 251add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 252cb76c673eeb84344887715d36d44b799042be5a5srs delete[] tempSpace; 253add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if (isOpen) 254add79a6e1b3a1af1305f02d51eb3aa148f580caasrs return retval; 255add79a6e1b3a1af1305f02d51eb3aa148f580caasrs} // DiskIO::Read() 256add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 2574307ef2e863cbec357df56197046c6b679fc5d2dsrs// A variant on the standard write() function. 258add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// Returns the number of bytes written. 259add79a6e1b3a1af1305f02d51eb3aa148f580caasrsint DiskIO::Write(void* buffer, int numBytes) { 260add79a6e1b3a1af1305f02d51eb3aa148f580caasrs int blockSize = 512, i, numBlocks, retval = 0; 261add79a6e1b3a1af1305f02d51eb3aa148f580caasrs char* tempSpace; 262add79a6e1b3a1af1305f02d51eb3aa148f580caasrs DWORD numWritten; 263add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 264add79a6e1b3a1af1305f02d51eb3aa148f580caasrs // If disk isn't open, try to open it.... 265add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if ((!isOpen) || (!openForWrite)) { 266add79a6e1b3a1af1305f02d51eb3aa148f580caasrs OpenForWrite(); 267add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if 268add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 269add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (isOpen) { 270add79a6e1b3a1af1305f02d51eb3aa148f580caasrs // Compute required space and allocate memory 271add79a6e1b3a1af1305f02d51eb3aa148f580caasrs blockSize = GetBlockSize(); 272add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (numBytes <= blockSize) { 273add79a6e1b3a1af1305f02d51eb3aa148f580caasrs numBlocks = 1; 274cb76c673eeb84344887715d36d44b799042be5a5srs tempSpace = new char [blockSize]; 275add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } else { 276add79a6e1b3a1af1305f02d51eb3aa148f580caasrs numBlocks = numBytes / blockSize; 277add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if ((numBytes % blockSize) != 0) numBlocks++; 278cb76c673eeb84344887715d36d44b799042be5a5srs tempSpace = new char [numBlocks * blockSize]; 279add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if/else 2806aae2a9b70e9f88926baad94c1eea40e0b534f01srs if (tempSpace == NULL) { 2816aae2a9b70e9f88926baad94c1eea40e0b534f01srs cerr << "Unable to allocate memory in DiskIO::Write()! Terminating!\n"; 2826aae2a9b70e9f88926baad94c1eea40e0b534f01srs exit(1); 2836aae2a9b70e9f88926baad94c1eea40e0b534f01srs } // if 284add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 285add79a6e1b3a1af1305f02d51eb3aa148f580caasrs // Copy the data to my own buffer, then write it 286add79a6e1b3a1af1305f02d51eb3aa148f580caasrs for (i = 0; i < numBytes; i++) { 287add79a6e1b3a1af1305f02d51eb3aa148f580caasrs tempSpace[i] = ((char*) buffer)[i]; 288add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // for 289add79a6e1b3a1af1305f02d51eb3aa148f580caasrs for (i = numBytes; i < numBlocks * blockSize; i++) { 290add79a6e1b3a1af1305f02d51eb3aa148f580caasrs tempSpace[i] = 0; 291add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // for 292add79a6e1b3a1af1305f02d51eb3aa148f580caasrs WriteFile(fd, tempSpace, numBlocks * blockSize, &numWritten, NULL); 293add79a6e1b3a1af1305f02d51eb3aa148f580caasrs retval = (int) numWritten; 294add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 295add79a6e1b3a1af1305f02d51eb3aa148f580caasrs // Adjust the return value, if necessary.... 296add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (((numBlocks * blockSize) != numBytes) && (retval > 0)) 297add79a6e1b3a1af1305f02d51eb3aa148f580caasrs retval = numBytes; 298add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 299cb76c673eeb84344887715d36d44b799042be5a5srs delete[] tempSpace; 300add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if (isOpen) 301add79a6e1b3a1af1305f02d51eb3aa148f580caasrs return retval; 302add79a6e1b3a1af1305f02d51eb3aa148f580caasrs} // DiskIO:Write() 303add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 304add79a6e1b3a1af1305f02d51eb3aa148f580caasrs// Returns the size of the disk in blocks. 305add79a6e1b3a1af1305f02d51eb3aa148f580caasrsuint64_t DiskIO::DiskSize(int *err) { 306add79a6e1b3a1af1305f02d51eb3aa148f580caasrs uint64_t sectors = 0; // size in sectors 3070a6973119c9e9984ad47a6da3231e8d16f996c5csrs DWORD bytes, moreBytes; // low- and high-order bytes of file size 308add79a6e1b3a1af1305f02d51eb3aa148f580caasrs GET_LENGTH_INFORMATION buf; 309add79a6e1b3a1af1305f02d51eb3aa148f580caasrs DWORD i; 310add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 311add79a6e1b3a1af1305f02d51eb3aa148f580caasrs // If disk isn't open, try to open it.... 312add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (!isOpen) { 313add79a6e1b3a1af1305f02d51eb3aa148f580caasrs OpenForRead(); 314add79a6e1b3a1af1305f02d51eb3aa148f580caasrs } // if 315add79a6e1b3a1af1305f02d51eb3aa148f580caasrs 316add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (isOpen) { 317add79a6e1b3a1af1305f02d51eb3aa148f580caasrs // Note to self: I recall testing a simplified version of 318add79a6e1b3a1af1305f02d51eb3aa148f580caasrs // this code, similar to what's in the __APPLE__ block, 319add79a6e1b3a1af1305f02d51eb3aa148f580caasrs // on Linux, but I had some problems. IIRC, it ran OK on 32-bit 320add79a6e1b3a1af1305f02d51eb3aa148f580caasrs // systems but not on 64-bit. Keep this in mind in case of 321add79a6e1b3a1af1305f02d51eb3aa148f580caasrs // 32/64-bit issues on MacOS.... 322add79a6e1b3a1af1305f02d51eb3aa148f580caasrs if (DeviceIoControl(fd, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &buf, sizeof(buf), &i, NULL)) { 323add79a6e1b3a1af1305f02d51eb3aa148f580caasrs sectors = (uint64_t) buf.Length.QuadPart / GetBlockSize(); 3240a6973119c9e9984ad47a6da3231e8d16f996c5csrs *err = 0; 3250a6973119c9e9984ad47a6da3231e8d16f996c5csrs } else { // doesn't seem to be a disk device; assume it's an image file.... 3260a6973119c9e9984ad47a6da3231e8d16f996c5csrs bytes = GetFileSize(fd, &moreBytes); 3270a6973119c9e9984ad47a6da3231e8d16f996c5csrs sectors = ((uint64_t) bytes + ((uint64_t) moreBytes) * UINT32_MAX) / GetBlockSize(); 3280a6973119c9e9984ad47a6da3231e8d16f996c5csrs *err = 0; 3290a6973119c9e9984ad47a6da3231e8d16f996c5csrs } // if 3300a6973119c9e9984ad47a6da3231e8d16f996c5csrs } else { 3310a6973119c9e9984ad47a6da3231e8d16f996c5csrs *err = -1; 3320a6973119c9e9984ad47a6da3231e8d16f996c5csrs sectors = 0; 3330a6973119c9e9984ad47a6da3231e8d16f996c5csrs } // if/else (isOpen) 3340a6973119c9e9984ad47a6da3231e8d16f996c5csrs 335add79a6e1b3a1af1305f02d51eb3aa148f580caasrs return sectors; 336add79a6e1b3a1af1305f02d51eb3aa148f580caasrs} // DiskIO::DiskSize() 337