diff options
author | srs5694 <srs5694@users.sourceforge.net> | 2010-01-28 21:10:52 -0500 |
---|---|---|
committer | srs5694 <srs5694@users.sourceforge.net> | 2010-01-28 21:10:52 -0500 |
commit | 0a6973119c9e9984ad47a6da3231e8d16f996c5c (patch) | |
tree | 456b81b56315eca6ac64688db34cbb0a25a87f41 | |
parent | 91544e13fb56ef339277a8f73f761ff004b2e74f (diff) | |
download | sgdisk-0a6973119c9e9984ad47a6da3231e8d16f996c5c.tar.gz |
Nearing 0.6.2 release; Windows version now works.
-rw-r--r-- | CHANGELOG | 4 | ||||
-rw-r--r-- | Makefile | 3 | ||||
-rw-r--r-- | Makefile.mingw | 13 | ||||
-rw-r--r-- | bsd.cc | 6 | ||||
-rw-r--r-- | bsd.h | 2 | ||||
-rw-r--r-- | diskio-windows.cc | 101 | ||||
-rw-r--r-- | diskio.cc | 8 | ||||
-rw-r--r-- | diskio.h | 10 | ||||
-rw-r--r-- | gdisk.8 | 8 | ||||
-rw-r--r-- | gdisk.cc | 11 | ||||
-rw-r--r-- | gpt.cc | 32 | ||||
-rw-r--r-- | gpt.h | 12 | ||||
-rw-r--r-- | gptpart.cc | 213 | ||||
-rw-r--r-- | gptpart.h | 8 | ||||
-rw-r--r-- | mbr.cc | 40 | ||||
-rw-r--r-- | mbr.h | 4 | ||||
-rw-r--r-- | parttypes.cc | 9 |
17 files changed, 247 insertions, 237 deletions
@@ -1,6 +1,10 @@ 0.6.2 (?/??/2010): ------------------ +- The change-type ('t' on main menu) option now changes the partition's + name *IF* the current name is the generic one for the partition type. + If the current name is not the generic name, it is NOT changed. + - Fixed bug that caused new protective MBR to not be created when the MBR was invalid and the GPT was damaged and the user opts to try to use the GPT data. @@ -19,9 +19,6 @@ gdisk: $(LIB_OBJS) gdisk.o sgdisk: $(LIB_OBJS) sgdisk.o $(CXX) $(LIB_OBJS) sgdisk.o -L/opt/local/lib -L/usr/local/lib -lpopt -o sgdisk -wipegpt: $(LIB_OBJS) wipegpt.o - $(CXX) $(LIB_OBJS) wipegpt.o -o wipegpt - lint: #no pre-reqs lint $(SRCS) diff --git a/Makefile.mingw b/Makefile.mingw index 0976a5a..664fda4 100644 --- a/Makefile.mingw +++ b/Makefile.mingw @@ -1,7 +1,8 @@ CC=/usr/bin/i586-mingw32msvc-gcc CXX=/usr/bin/i586-mingw32msvc-g++ +STRIP=/usr/bin/i586-mingw32msvc-strip CFLAGS=-O2 -D_FILE_OFFSET_BITS=64 -g -CXXFLAGS=-O2 -DMINGW -Wuninitialized -Wreturn-type -D_FILE_OFFSET_BITS=64 -I /usr/local/include -I/opt/local/include -g +CXXFLAGS=-O2 -Wuninitialized -Wreturn-type -D_FILE_OFFSET_BITS=64 -I /usr/local/include -I/opt/local/include -g LIB_NAMES=gptpart bsd parttypes attributes crc32 mbr gpt support diskio diskio-windows LIB_SRCS=$(NAMES:=.cc) LIB_OBJS=$(LIB_NAMES:=.o) @@ -17,16 +18,16 @@ gdisk: $(LIB_OBJS) gdisk.o $(CXX) $(LIB_OBJS) gdisk.o -o gdisk.exe sgdisk: $(LIB_OBJS) sgdisk.o - $(CXX) $(LIB_OBJS) sgdisk.o -L/opt/local/lib -L/usr/local/lib -lpopt -o sgdisk - -wipegpt: $(LIB_OBJS) wipegpt.o - $(CXX) $(LIB_OBJS) wipegpt.o -o wipegpt + $(CXX) $(LIB_OBJS) sgdisk.o -L/opt/local/lib -L/usr/local/lib -lpopt -o sgdisk.exe lint: #no pre-reqs lint $(SRCS) clean: #no pre-reqs - rm -f core *.o *~ gdisk sgdisk + rm -f core *.o *~ gdisk.exe sgdisk.exe + +strip: #no pre-reqs + $(STRIP) gdisk.exe # what are the source dependencies depend: $(SRCS) @@ -43,12 +43,12 @@ BSDData::~BSDData(void) { // Read BSD disklabel data from the specified device filename. This function // just opens the device file and then calls an overloaded function to do // the bulk of the work. Returns 1 on success, 0 on failure. -int BSDData::ReadBSDData(string *device, uint64_t startSector, uint64_t endSector) { +int BSDData::ReadBSDData(const string & device, uint64_t startSector, uint64_t endSector) { int allOK = 1; DiskIO myDisk; - if (*device != "") { - if (myDisk.OpenForRead(*device)) { + if (device != "") { + if (myDisk.OpenForRead(device)) { allOK = ReadBSDData(&myDisk, startSector, endSector); } else { allOK = 0; @@ -72,7 +72,7 @@ class BSDData { public: BSDData(void); ~BSDData(void); - int ReadBSDData(string *deviceFilename, uint64_t startSector, uint64_t endSector); + int ReadBSDData(const string & deviceFilename, uint64_t startSector, uint64_t endSector); int ReadBSDData(DiskIO *myDisk, uint64_t startSector, uint64_t endSector); void ReverseMetaBytes(void); void DisplayBSDData(void); diff --git a/diskio-windows.cc b/diskio-windows.cc index 84b77ee..a060103 100644 --- a/diskio-windows.cc +++ b/diskio-windows.cc @@ -42,9 +42,9 @@ void DiskIO::MakeRealName(void) { if ((colonPos != string::npos) && (colonPos <= 3)) { realFilename = "\\\\.\\physicaldrive"; realFilename += userFilename.substr(0, colonPos); + } else { + realFilename = userFilename; } // if/else - printf("Exiting DiskIO::MakeRealName(); translated '%s' ", userFilename.c_str()); - printf("to '%s'\n", realFilename.c_str()); } // DiskIO::MakeRealName() // Open the currently on-record file for reading @@ -60,12 +60,11 @@ int DiskIO::OpenForRead(void) { } // if if (shouldOpen) { - printf("Opening '%s' for reading.\n", realFilename.c_str()); fd = CreateFile(realFilename.c_str(),GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); if (fd == INVALID_HANDLE_VALUE) { CloseHandle(fd); - fprintf(stderr, "Problem opening %s for reading!\n", realFilename.c_str()); + cerr << "Problem opening " << realFilename << " for reading!\n"; realFilename = ""; userFilename = ""; isOpen = 0; @@ -94,11 +93,12 @@ int DiskIO::OpenForWrite(void) { FILE_ATTRIBUTE_NORMAL, NULL); if (fd == INVALID_HANDLE_VALUE) { CloseHandle(fd); - isOpen = 1; - openForWrite = 1; - } else { isOpen = 0; openForWrite = 0; + errno = GetLastError(); + } else { + isOpen = 1; + openForWrite = 1; } // if/else return isOpen; } // DiskIO::OpenForWrite(void) @@ -133,6 +133,7 @@ int DiskIO::GetBlockSize(void) { __out LPDWORD lpTotalNumberOfClusters ); */ // err = GetDiskFreeSpace(realFilename.c_str(), &junk1, &blockSize, &junk2, &junk3); + // Above call is fubared -- returns weird values for blockSize.... err = 1; blockSize = 512; @@ -142,9 +143,9 @@ int DiskIO::GetBlockSize(void) { // file, so don't display the warning message.... // 32-bit code returns EINVAL, I don't know why. I know I'm treading on // thin ice here, but it should be OK in all but very weird cases.... - if ((errno != ENOTTY) && (errno != EINVAL)) { - printf("\aError %d when determining sector size! Setting sector size to %d\n", - GetLastError(), SECTOR_SIZE); + if (errno != 267) { // 267 is returned on ordinary files + cerr << "\aError " << GetLastError() << " when determining sector size! " + << "Setting sector size to " << SECTOR_SIZE << "\n"; } // if } // if (err == -1) } // if (isOpen) @@ -155,21 +156,26 @@ int DiskIO::GetBlockSize(void) { // Resync disk caches so the OS uses the new partition table. This code varies // a lot from one OS to another. void DiskIO::DiskSync(void) { - int i; + DWORD i; + GET_LENGTH_INFORMATION buf; // If disk isn't open, try to open it.... - if (!isOpen) { - OpenForRead(); + if (!openForWrite) { + OpenForWrite(); } // if if (isOpen) { -#ifndef MINGW - sync(); -#endif -#ifdef MINGW - printf("Warning: I don't know how to sync disks in Windows! The old partition table is\n" - "probably still in use!\n"); -#endif + if (DeviceIoControl(fd, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, &buf, sizeof(buf), &i, NULL) == 0) { + cout << "Disk synchronization failed! The computer may use the old partition table\n" + << "until you reboot or remove and re-insert the disk!\n"; + } else { + cout << "Disk synchronization succeeded! The computer should now use the new\n" + << "partition table.\n"; + } // if/else + } else { + cout << "Unable to open the disk for synchronization operation! The computer will\n" + << "continue to use the old partition table until you reboot or remove and\n" + << "re-insert the disk!\n"; } // if (isOpen) } // DiskIO::DiskSync() @@ -186,22 +192,11 @@ int DiskIO::Seek(uint64_t sector) { } // if if (isOpen) { - bytePos = sector * (uint64_t) GetBlockSize(); - lowBits = (uint32_t) (bytePos / UINT64_C(4294967296)); - highBits = (uint32_t) (bytePos % UINT64_C(4294967296)); - seekTo.LowPart = lowBits; - seekTo.HighPart = highBits; -// seekTo.QuadPart = (LONGLONG) (sector * (uint64_t) GetBlockSize()); -/* printf("In DiskIO::Seek(), sector = %llu, ", sector); - printf("block size = %d, ", GetBlockSize()); - printf("seekTo.QuadPart = %lld\n", seekTo.QuadPart); - printf(" seekTo.LowPart = %lu, ", seekTo.LowPart); - printf("seekTo.HighPart = %lu\n", seekTo.HighPart); */ + seekTo.QuadPart = sector * (uint64_t) GetBlockSize(); retval = SetFilePointerEx(fd, seekTo, NULL, FILE_BEGIN); if (retval == 0) { errno = GetLastError(); - fprintf(stderr, "Error when seeking to %lld! Error is %d\n", - seekTo.QuadPart, errno); + cerr << "Error when seeking to " << seekTo.QuadPart << "! Error is " << errno << "\n"; retval = 0; } // if } // if @@ -235,9 +230,7 @@ int DiskIO::Read(void* buffer, int numBytes) { } // if/else // Read the data into temporary space, then copy it to buffer -// retval = read(fd, tempSpace, numBlocks * blockSize); ReadFile(fd, tempSpace, numBlocks * blockSize, &retval, NULL); - printf("In DiskIO::Read(), have read %d bytes.\n", (int) retval); for (i = 0; i < numBytes; i++) { ((char*) buffer)[i] = tempSpace[i]; } // for @@ -284,7 +277,6 @@ int DiskIO::Write(void* buffer, int numBytes) { for (i = numBytes; i < numBlocks * blockSize; i++) { tempSpace[i] = 0; } // for -// retval = write(fd, tempSpace, numBlocks * blockSize); WriteFile(fd, tempSpace, numBlocks * blockSize, &numWritten, NULL); retval = (int) numWritten; @@ -300,8 +292,7 @@ int DiskIO::Write(void* buffer, int numBytes) { // Returns the size of the disk in blocks. uint64_t DiskIO::DiskSize(int *err) { uint64_t sectors = 0; // size in sectors - off_t bytes = 0; // size in bytes - struct stat64 st; + DWORD bytes, moreBytes; // low- and high-order bytes of file size GET_LENGTH_INFORMATION buf; DWORD i; @@ -316,30 +307,18 @@ uint64_t DiskIO::DiskSize(int *err) { // on Linux, but I had some problems. IIRC, it ran OK on 32-bit // systems but not on 64-bit. Keep this in mind in case of // 32/64-bit issues on MacOS.... -/* HANDLE fin; - fin = CreateFile(realFilename.c_str(), GENERIC_READ, - FILE_SHARE_READ|FILE_SHARE_WRITE, - NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); */ if (DeviceIoControl(fd, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &buf, sizeof(buf), &i, NULL)) { sectors = (uint64_t) buf.Length.QuadPart / GetBlockSize(); -// printf("disk_get_size_win32 IOCTL_DISK_GET_LENGTH_INFO = %llu\n", -// (long long unsigned) sectors); - } else { - fprintf(stderr, "Couldn't determine disk size!\n"); - } - -/* // The above methods have failed, so let's assume it's a regular - // file (a QEMU image, dd backup, or what have you) and see what - // fstat() gives us.... - if ((sectors == 0) || (*err == -1)) { - if (fstat64(fd, &st) == 0) { - bytes = (off_t) st.st_size; - if ((bytes % UINT64_C(512)) != 0) - fprintf(stderr, "Warning: File size is not a multiple of 512 bytes!" - " Misbehavior is likely!\n\a"); - sectors = bytes / UINT64_C(512); - } // if - } // if */ - } // if (isOpen) + *err = 0; + } else { // doesn't seem to be a disk device; assume it's an image file.... + bytes = GetFileSize(fd, &moreBytes); + sectors = ((uint64_t) bytes + ((uint64_t) moreBytes) * UINT32_MAX) / GetBlockSize(); + *err = 0; + } // if + } else { + *err = -1; + sectors = 0; + } // if/else (isOpen) + return sectors; } // DiskIO::DiskSize() @@ -15,7 +15,7 @@ #define __STDC_LIMIT_MACROS #define __STDC_CONSTANT_MACROS -#ifdef MINGW +#ifdef _WIN32 #include <windows.h> #include <winioctl.h> #define fstat64 fstat @@ -52,7 +52,7 @@ DiskIO::~DiskIO(void) { } // destructor // Open a disk device for reading. Returns 1 on success, 0 on failure. -int DiskIO::OpenForRead(string filename) { +int DiskIO::OpenForRead(const string & filename) { int shouldOpen = 1; if (isOpen) { // file is already open @@ -74,7 +74,7 @@ int DiskIO::OpenForRead(string filename) { // Open a disk for reading and writing by filename. // Returns 1 on success, 0 on failure. -int DiskIO::OpenForWrite(string filename) { +int DiskIO::OpenForWrite(const string & filename) { int retval = 0; if ((isOpen) && (openForWrite) && ((filename == realFilename) || (filename == userFilename))) { @@ -151,7 +151,7 @@ int DiskIO::FindAlignment(void) { } // DiskIO::FindAlignment(int) */ // The same as FindAlignment(int), but opens and closes a device by filename -int DiskIO::FindAlignment(string filename) { +int DiskIO::FindAlignment(const string & filename) { int fd; int retval = 1; @@ -18,7 +18,7 @@ #include <string> #include <stdint.h> #include <sys/types.h> -#ifdef MINGW +#ifdef _WIN32 #include <windows.h> #include <winioctl.h> #else @@ -52,7 +52,7 @@ class DiskIO { int isOpen; int openForWrite; uint8_t *sectorData; -#ifdef MINGW +#ifdef _WIN32 HANDLE fd; #else int fd; @@ -62,9 +62,9 @@ class DiskIO { ~DiskIO(void); void MakeRealName(void); - int OpenForRead(string filename); + int OpenForRead(const string & filename); int OpenForRead(void); - int OpenForWrite(string filename); + int OpenForWrite(const string & filename); int OpenForWrite(void); void Close(); int Seek(uint64_t sector); @@ -73,7 +73,7 @@ class DiskIO { void DiskSync(void); // resync disk caches to use new partitions int GetBlockSize(void); int FindAlignment(void); - int FindAlignment(string filename); + int FindAlignment(const string & filename); int IsOpen(void) {return isOpen;} int IsOpenForWrite(void) {return openForWrite;} @@ -2,7 +2,7 @@ .\" May be distributed under the GNU General Public License .TH "GDISK" "8" "0.5.3" "Roderick W. Smith" "GPT fdisk Manual" .SH "NAME" -gdisk \- Interactive GUID partition table (GPT) manipulator for Linux and Unix +gdisk \- Interactive GUID partition table (GPT) manipulator .SH "SYNOPSIS" .BI "gdisk " [ \-l ] @@ -453,10 +453,8 @@ mid-physical-sector, though, performance can suffer on such drives, since important filesystem data structures can span physical sectors on the disk. To minimize such problems, GPT fdisk aligns the start of partitions on the boundary of presumed physical sectors. You can set the number of logical -sectors per physical sector with this option. The default is 8, except on -Linux 2.6.32 and later, in which case it's read from the disk. A value of 8 -will result in a tiny amount of wasted disk space on older disks with true -512-byte sectors but will otherwise be harmless. +sectors per physical sector with this option. The default is 1 on disks +smaller than 800GB and 8 on larger disks. .TP .B m @@ -34,6 +34,17 @@ int main(int argc, char* argv[]) { if (argc == 2) { // basic usage if (SizesOK()) { +#ifdef _WIN32 + cout << "\a************************************************************************\n" + << "Most versions of Windows cannot boot from a GPT disk, and most varieties\n" + << "prior to Vista cannot read GPT disks. Therefore, you should exit now\n" + << "unless you understand the implications of converting MBR to GPT, editing\n" + << "an existing GPT disk, or creating a new GPT disk layout!\n" + << "************************************************************************\n\n"; + cout << "Are you SURE you want to continue? "; + if (GetYN() != 'Y') + exit(0); +#endif doMore = theGPT.LoadPartitions(argv[1]); if (doMore) { MainMenu(argv[1], &theGPT); @@ -239,7 +239,7 @@ int GPTData::Verify(void) { << largestSegment << " (" << BytesToSI(largestSegment * (uint64_t) blockSize) << ") in size\n"; } else { - cout << "\nIdentified %d problems!\n", problems; + cout << "\nIdentified " << problems << " problems!\n"; } // if/else return (problems); @@ -497,7 +497,7 @@ int GPTData::FindOverlaps(void) { for (i = 1; i < mainHeader.numParts; i++) { for (j = 0; j < i; j++) { - if (partitions[i].DoTheyOverlap(&partitions[j])) { + if (partitions[i].DoTheyOverlap(partitions[j])) { problems++; cout << "\nProblem: partitions " << i + 1 << " and " << j + 1 << " overlap:\n"; cout << " Partition " << i + 1 << ": " << partitions[i].GetFirstLBA() @@ -550,7 +550,7 @@ void GPTData::PartitionScan(void) { } // GPTData::PartitionScan() // Read GPT data from a disk. -int GPTData::LoadPartitions(string deviceFilename) { +int GPTData::LoadPartitions(const string & deviceFilename) { int err; int allOK = 1, i; uint64_t firstBlock, lastBlock; @@ -636,7 +636,7 @@ int GPTData::LoadPartitions(string deviceFilename) { // succeeded, 0 if there are obvious problems.... int GPTData::ForceLoadGPTData(void) { int allOK = 1, validHeaders; - off_t seekTo; + uint64_t seekTo; uint8_t* storage; uint32_t newCRC, sizeOfParts; @@ -839,7 +839,7 @@ int GPTData::SaveGPTData(int quiet) { char answer, line[256]; uint64_t secondTable; uint32_t numParts; - off_t offset; + uint64_t offset; if (device == "") { cerr << "Device not defined.\n"; @@ -936,7 +936,7 @@ int GPTData::SaveGPTData(int quiet) { // Now seek to near the end to write the secondary GPT.... if (allOK) { - offset = (off_t) secondTable; + offset = (uint64_t) secondTable; if (myDisk.Seek(offset) != 1) { allOK = 0; cerr << "Unable to seek to end of disk! Perhaps the 'e' option on the experts' menu\n" @@ -998,12 +998,11 @@ int GPTData::SaveGPTData(int quiet) { // the main GPT header, the backup GPT header, and the main partition // table; it discards the backup partition table, since it should be // identical to the main partition table on healthy disks. -int GPTData::SaveGPTBackup(string filename) { - int fd, allOK = 1; +int GPTData::SaveGPTBackup(const string & filename) { + int allOK = 1; uint32_t numParts; DiskIO backupFile; -// if ((fd = open(filename, O_WRONLY | O_CREAT, S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH)) != -1) { if (backupFile.OpenForWrite(filename)) { // Reverse the byte order, if necessary.... numParts = mainHeader.numParts; @@ -1066,13 +1065,12 @@ int GPTData::SaveGPTBackup(string filename) { // does minimal error checking. It returns 1 if it completed successfully, // 0 if there was a problem. In the latter case, it creates a new empty // set of partitions. -int GPTData::LoadGPTBackup(string filename) { - int fd, allOK = 1, val; +int GPTData::LoadGPTBackup(const string & filename) { + int allOK = 1, val; uint32_t numParts, sizeOfEntries, sizeOfParts, newCRC; int littleEndian = 1; DiskIO backupFile; -// if ((fd = open(filename, O_RDONLY)) != -1) { if (backupFile.OpenForRead(filename)) { if (IsLittleEndian() == 0) littleEndian = 0; @@ -1473,7 +1471,7 @@ WhichToUse GPTData::UseWhichPartitions(void) { cout << "\n**********************************************************************\n" << "Found invalid GPT and valid BSD disklabel; converting BSD disklabel\n" << "to GPT format."; - if (!justLooking) { + if ((!justLooking) && (!beQuiet)) { cout << "\a THIS OPERATON IS POTENTIALLY DESTRUCTIVE! Your first\n" << "BSD partition will likely be unusable. Exit by typing 'q' if you don't\n" << "want to convert your BSD partitions to GPT format!"; @@ -1493,10 +1491,9 @@ WhichToUse GPTData::UseWhichPartitions(void) { cout << "Found valid GPT with hybrid MBR; using GPT.\n"; } // if if ((state == gpt_valid) && (mbrState == invalid)) { - cout << "\aFound valid GPT with corrupt MBR; using GPT and will create new\n" + cout << "\aFound valid GPT with corrupt MBR; using GPT and will write new\n" << "protective MBR on save.\n"; which = use_gpt; - protectiveMBR.MakeProtectiveMBR(); } // if if ((state == gpt_valid) && (mbrState == mbr)) { if (!beQuiet) { @@ -1506,7 +1503,6 @@ WhichToUse GPTData::UseWhichPartitions(void) { which = use_mbr; } else if (answer == 2) { which = use_gpt; - protectiveMBR.MakeProtectiveMBR(); cout << "Using GPT and creating fresh protective MBR.\n"; } else which = use_new; } else which = use_abort; @@ -1612,7 +1608,7 @@ int GPTData::XFormDisklabel(int i) { // If all is OK, read the disklabel and convert it. if (goOn) { - goOn = disklabel.ReadBSDData(&myDisk, partitions[partNum].GetFirstLBA(), + goOn = disklabel.ReadBSDData(device, partitions[partNum].GetFirstLBA(), partitions[partNum].GetLastLBA()); if ((goOn) && (disklabel.IsDisklabel())) { numDone = XFormDisklabel(&disklabel, startPart); @@ -2053,7 +2049,7 @@ void GPTData::MoveSecondHeaderToEnd() { secondHeader.partitionEntriesLBA = secondHeader.lastUsableLBA + UINT64_C(1); } // GPTData::FixSecondHeaderLocation() -int GPTData::SetName(uint32_t partNum, string theName) { +int GPTData::SetName(uint32_t partNum, const string & theName) { int retval = 1; if (!IsFreePartNum(partNum)) { @@ -93,15 +93,15 @@ public: int FindOverlaps(void); // Load or save data from/to disk - int LoadMBR(string f) {return protectiveMBR.ReadMBRData(f);} + int LoadMBR(const string & f) {return protectiveMBR.ReadMBRData(f);} void PartitionScan(void); - int LoadPartitions(string deviceFilename); + int LoadPartitions(const string & deviceFilename); int ForceLoadGPTData(void); int LoadMainTable(void); int LoadSecondTableAsMain(void); int SaveGPTData(int quiet = 0); - int SaveGPTBackup(string filename); - int LoadGPTBackup(string filename); + int SaveGPTBackup(const string & filename); + int LoadGPTBackup(const string & filename); // Display data.... void ShowAPMState(void); @@ -137,7 +137,7 @@ public: void SortGPT(void); int ClearGPTData(void); void MoveSecondHeaderToEnd(); - int SetName(uint32_t partNum, string theName = ""); + int SetName(uint32_t partNum, const string & theName = ""); void SetDiskGUID(GUIDData newGUID); int SetPartitionGUID(uint32_t pn, GUIDData theGUID); int ChangePartType(uint32_t pn, uint16_t hexCode); @@ -170,7 +170,7 @@ public: WhichToUse WhichWasUsed(void) {return whichWasUsed;} // Endianness functions - void ReverseHeaderBytes(struct GPTHeader* header); // for endianness + void ReverseHeaderBytes(struct GPTHeader* header); void ReversePartitionBytes(); // for endianness }; // class GPTData @@ -35,17 +35,6 @@ GPTPart::GPTPart(void) { GPTPart::~GPTPart(void) { } // destructor -// Return partition's name field, converted to a C++ ASCII string -string GPTPart::GetName(void) { - string theName; - int i; - - for (i = 0; i < NAME_SIZE; i += 2) { - theName += name[i]; - } // for - return theName; -} // GPTPart::GetName() - // Return the gdisk-specific two-byte hex code for the partition uint16_t GPTPart::GetHexType(void) { return typeHelper.GUIDToID(partitionType); @@ -66,18 +55,30 @@ uint64_t GPTPart::GetLengthLBA(void) { return length; } // GPTPart::GetLengthLBA() -GPTPart & GPTPart::operator=(const GPTPart & orig) { +// Return partition's name field, converted to a C++ ASCII string +string GPTPart::GetName(void) { + string theName; int i; - partitionType = orig.partitionType; - uniqueGUID = orig.uniqueGUID; - firstLBA = orig.firstLBA; - lastLBA = orig.lastLBA; - attributes = orig.attributes; - for (i = 0; i < NAME_SIZE; i++) - name[i] = orig.name[i]; - return *this; -} // assignment operator + theName = ""; + for (i = 0; i < NAME_SIZE; i += 2) { + if (name[i] != '\0') + theName += name[i]; + } // for + return theName; +} // GPTPart::GetName() + +// Set the type code to the specified one. Also changes the partition +// name *IF* the current name is the generic one for the current partition +// type. +void GPTPart::SetType(struct GUIDData t) { + int nameSame = 1, currentLength, i; + + if (GetName() == typeHelper.GUIDToName(partitionType)) { + SetName(typeHelper.GUIDToName(t)); + } // if + partitionType = t; +} // GPTPart::SetType() // Sets the unique GUID to a value of 0 or a random value, // depending on the parameter: 0 = 0, anything else = random @@ -93,47 +94,54 @@ void GPTPart::SetUniqueGUID(int zeroOrRandom) { } } // GPTPart::SetUniqueGUID() -// Blank (delete) a single partition -void GPTPart::BlankPartition(void) { - int j; - GUIDData zeroGUID; +// Set the name for a partition to theName, or prompt for a name if +// theName is empty. Note that theName is a standard C++-style ASCII +// string, although the GUID partition definition requires a UTF-16LE +// string. This function creates a simple-minded copy for this. +void GPTPart::SetName(const string & theName) { + char newName[NAME_SIZE]; // New name + char *junk; + int i; - zeroGUID.data1 = 0; - zeroGUID.data2 = 0; - uniqueGUID = zeroGUID; - partitionType = zeroGUID; - firstLBA = 0; - lastLBA = 0; - attributes = 0; - for (j = 0; j < NAME_SIZE; j++) - name[j] = '\0'; -} // GPTPart::BlankPartition + // Blank out new name string, just to be on the safe side.... + for (i = 0; i < NAME_SIZE; i++) + newName[i] = '\0'; -// Returns 1 if the two partitions overlap, 0 if they don't -int GPTPart::DoTheyOverlap(GPTPart* other) { - int theyDo = 0; + if (theName == "") { // No name specified, so get one from the user + cout << "Enter name: "; + junk = fgets(newName, NAME_SIZE / 2, stdin); - // Don't bother checking unless these are defined (both start and end points - // are 0 for undefined partitions, so just check the start points) - if ((firstLBA != 0) && (other->firstLBA != 0)) { - if ((firstLBA < other->lastLBA) && (lastLBA >= other->firstLBA)) - theyDo = 1; - if ((other->firstLBA < lastLBA) && (other->lastLBA >= firstLBA)) - theyDo = 1; + // Input is likely to include a newline, so remove it.... + i = strlen(newName); + if (newName[i - 1] == '\n') + newName[i - 1] = '\0'; + } else { + strcpy(newName, theName.substr(0, NAME_SIZE / 2).c_str()); } // if - return (theyDo); -} // GPTPart::DoTheyOverlap() -// Reverse the bytes of integral data types; used on big-endian systems. -void GPTPart::ReversePartBytes(void) { - ReverseBytes(&partitionType.data1, 8); - ReverseBytes(&partitionType.data2, 8); - ReverseBytes(&uniqueGUID.data1, 8); - ReverseBytes(&uniqueGUID.data2, 8); - ReverseBytes(&firstLBA, 8); - ReverseBytes(&lastLBA, 8); - ReverseBytes(&attributes, 8); -} // GPTPart::ReverseBytes() + // Copy the C-style ASCII string from newName into a form that the GPT + // table will accept.... + for (i = 0; i < NAME_SIZE; i++) { + if ((i % 2) == 0) { + name[i] = newName[(i / 2)]; + } else { + name[i] = '\0'; + } // if/else + } // for +} // GPTPart::SetName() + +GPTPart & GPTPart::operator=(const GPTPart & orig) { + int i; + + partitionType = orig.partitionType; + uniqueGUID = orig.uniqueGUID; + firstLBA = orig.firstLBA; + lastLBA = orig.lastLBA; + attributes = orig.attributes; + for (i = 0; i < NAME_SIZE; i++) + name[i] = orig.name[i]; + return *this; +} // assignment operator // Display summary information; does nothing if the partition is empty. void GPTPart::ShowSummary(int partNum, uint32_t blockSize) { @@ -155,7 +163,7 @@ void GPTPart::ShowSummary(int partNum, uint32_t blockSize) { cout.setf(ios::uppercase); cout << hex << typeHelper.GUIDToID(partitionType) << " " << dec; cout.fill(' '); - cout.setf(ios::right); +// cout.setf(ios::right); cout << GetName().substr(0, 23) << "\n"; cout.fill(' '); } // if @@ -172,24 +180,65 @@ void GPTPart::ShowDetails(uint32_t blockSize) { cout << "Partition unique GUID: " << GUIDToStr(uniqueGUID) << "\n"; cout << "First sector: " << firstLBA << " (at " - << BytesToSI(firstLBA * blockSize) << ")\n"; + << BytesToSI(firstLBA * blockSize) << ")\n"; cout << "Last sector: " << lastLBA << " (at " - << BytesToSI(lastLBA * blockSize) << ")\n"; + << BytesToSI(lastLBA * blockSize) << ")\n"; size = (lastLBA - firstLBA + 1); cout << "Partition size: " << size << " sectors (" - << BytesToSI(size * ((uint64_t) blockSize)) << ")\n"; + << BytesToSI(size * ((uint64_t) blockSize)) << ")\n"; cout << "Attribute flags: "; cout.fill('0'); cout.width(16); - cout << right; cout << hex; cout << attributes << "\n"; - cout << left; cout << dec; cout << "Partition name: " << GetName() << "\n"; + cout.fill(' '); } // if } // GPTPart::ShowDetails() +// Blank (delete) a single partition +void GPTPart::BlankPartition(void) { + int j; + GUIDData zeroGUID; + + zeroGUID.data1 = 0; + zeroGUID.data2 = 0; + uniqueGUID = zeroGUID; + partitionType = zeroGUID; + firstLBA = 0; + lastLBA = 0; + attributes = 0; + for (j = 0; j < NAME_SIZE; j++) + name[j] = '\0'; +} // GPTPart::BlankPartition + +// Returns 1 if the two partitions overlap, 0 if they don't +int GPTPart::DoTheyOverlap(const GPTPart & other) { + int theyDo = 0; + + // Don't bother checking unless these are defined (both start and end points + // are 0 for undefined partitions, so just check the start points) + if ((firstLBA != 0) && (other.firstLBA != 0)) { + if ((firstLBA < other.lastLBA) && (lastLBA >= other.firstLBA)) + theyDo = 1; + if ((other.firstLBA < lastLBA) && (other.lastLBA >= firstLBA)) + theyDo = 1; + } // if + return (theyDo); +} // GPTPart::DoTheyOverlap() + +// Reverse the bytes of integral data types; used on big-endian systems. +void GPTPart::ReversePartBytes(void) { + ReverseBytes(&partitionType.data1, 8); + ReverseBytes(&partitionType.data2, 8); + ReverseBytes(&uniqueGUID.data1, 8); + ReverseBytes(&uniqueGUID.data2, 8); + ReverseBytes(&firstLBA, 8); + ReverseBytes(&lastLBA, 8); + ReverseBytes(&attributes, 8); +} // GPTPart::ReverseBytes() + /**************************************** * Functions requiring user interaction * ****************************************/ @@ -216,46 +265,10 @@ void GPTPart::ChangeType(void) { newType = typeHelper.IDToGUID((uint16_t) typeNum); else // user wants to enter the GUID directly, so do that newType = GetGUID(); - partitionType = newType; + SetType(newType); cout << "Changed type of partition to '" << typeHelper.GUIDToName(partitionType) << "'\n"; } // GPTPart::ChangeType() -// Set the name for a partition to theName, or prompt for a name if -// theName is empty. Note that theName is a standard C++-style ASCII -// string, although the GUID partition definition requires a UTF-16LE -// string. This function creates a simple-minded copy for this. -void GPTPart::SetName(string theName) { - char newName[NAME_SIZE]; // New name - char *junk; - int i; - - // Blank out new name string, just to be on the safe side.... - for (i = 0; i < NAME_SIZE; i++) - newName[i] = '\0'; - - if (theName == "") { // No name specified, so get one from the user - cout << "Enter name: "; - junk = fgets(newName, NAME_SIZE / 2, stdin); - - // Input is likely to include a newline, so remove it.... - i = strlen(newName); - if (newName[i - 1] == '\n') - newName[i - 1] = '\0'; - } else { - strcpy(newName, theName.substr(0, NAME_SIZE / 2).c_str()); - } // if - - // Copy the C-style ASCII string from newName into a form that the GPT - // table will accept.... - for (i = 0; i < NAME_SIZE; i++) { - if ((i % 2) == 0) { - name[i] = newName[(i / 2)]; - } else { - name[i] = '\0'; - } // if/else - } // for -} // GPTPart::SetName() - /*********************************** * Non-class but related functions * ***********************************/ @@ -62,21 +62,21 @@ class GPTPart { string GetName(void); // Simple data assignment: - void SetType(struct GUIDData t) {partitionType = t;} - void SetType(uint16_t hex) {partitionType = typeHelper.IDToGUID(hex);} + void SetType(struct GUIDData t); + void SetType(uint16_t hex) {SetType(typeHelper.IDToGUID(hex));} void SetUniqueGUID(struct GUIDData u) {uniqueGUID = u;} void SetUniqueGUID(int zeroOrRandom); void SetFirstLBA(uint64_t f) {firstLBA = f;} void SetLastLBA(uint64_t l) {lastLBA = l;} void SetAttributes(uint64_t a) {attributes = a;} - void SetName(string n); + void SetName(const string & n); // Additional functions GPTPart & operator=(const GPTPart & orig); void ShowSummary(int partNum, uint32_t blockSize); // display summary information (1-line) void ShowDetails(uint32_t blockSize); // display detailed information (multi-line) void BlankPartition(void); // empty partition of data - int DoTheyOverlap(GPTPart* other); // returns 1 if there's overlap + int DoTheyOverlap(const GPTPart & other); // returns 1 if there's overlap void ReversePartBytes(void); // reverse byte order of all integer fields // Functions requiring user interaction @@ -38,6 +38,7 @@ MBRData::MBRData(void) { srand((unsigned int) time(NULL)); numHeads = MAX_HEADS; numSecspTrack = MAX_SECSPERTRACK; + myDisk = NULL; EmptyMBR(); } // MBRData default constructor @@ -48,6 +49,7 @@ MBRData::MBRData(string filename) { state = invalid; numHeads = MAX_HEADS; numSecspTrack = MAX_SECSPERTRACK; + myDisk = NULL; srand((unsigned int) time(NULL)); // Try to read the specified partition table, but if it fails.... @@ -55,9 +57,10 @@ MBRData::MBRData(string filename) { EmptyMBR(); device = ""; } // if -} // MBRData(char *filename) constructor +} // MBRData(string filename) constructor MBRData::~MBRData(void) { +// delete myDisk; } // MBRData destructor /********************** @@ -68,9 +71,11 @@ MBRData::~MBRData(void) { // Read data from MBR. Returns 1 if read was successful (even if the // data isn't a valid MBR), 0 if the read failed. -int MBRData::ReadMBRData(string deviceFilename) { +int MBRData::ReadMBRData(const string & deviceFilename) { int fd, allOK = 1; + if (myDisk == NULL) + myDisk = new DiskIO; if (myDisk->OpenForRead(deviceFilename)) { ReadMBRData(myDisk); } else { @@ -81,7 +86,7 @@ int MBRData::ReadMBRData(string deviceFilename) { device = deviceFilename; return allOK; -} // MBRData::ReadMBRData(char* deviceFilename) +} // MBRData::ReadMBRData(const string & deviceFilename) // Read data from MBR. If checkBlockSize == 1 (the default), the block // size is checked; otherwise it's set to the default (512 bytes). @@ -93,6 +98,9 @@ void MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) { int err = 1; TempMBR tempMBR; + if (myDisk != NULL) + delete myDisk; + myDisk = theDisk; // Empty existing MBR data, including the logical partitions... @@ -102,7 +110,7 @@ void MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) { if (myDisk->Read(&tempMBR, 512)) err = 0; if (err) { - cerr << "Problem reading disk in MBRData::ReadMBRData!\n"; + cerr << "Problem reading disk in MBRData::ReadMBRData()!\n"; } else { for (i = 0; i < 440; i++) code[i] = tempMBR.code[i]; @@ -183,7 +191,7 @@ void MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) { } // for } // if (hybrid detection code) } // no initial error -} // MBRData::ReadMBRData(int fd) +} // MBRData::ReadMBRData(DiskIO * theDisk, int checkBlockSize) // This is a recursive function to read all the logical partitions, following the // logical partition linked list from the disk and storing the basic data in the @@ -252,14 +260,16 @@ int MBRData::ReadLogicalPart(uint32_t extendedStart, // Write the MBR data to the default defined device. Note that this writes // ONLY the MBR itself, not the logical partition data. int MBRData::WriteMBRData(void) { - int allOK = 1, fd; + int allOK = 1; - if (myDisk->OpenForWrite(device) != 0) { - allOK = WriteMBRData(myDisk); - } else { - allOK = 0; - } // if/else - myDisk->Close(); + if (myDisk != NULL) { + if (myDisk->OpenForWrite(device) != 0) { + allOK = WriteMBRData(myDisk); + } else { + allOK = 0; + } // if/else + myDisk->Close(); + } else allOK = 0; return allOK; } // MBRData::WriteMBRData(void) @@ -322,12 +332,12 @@ int MBRData::WriteMBRData(DiskIO *theDisk) { } // for }// if return allOK; -} // MBRData::WriteMBRData(DiskIO theDisk) +} // MBRData::WriteMBRData(DiskIO *theDisk) -int MBRData::WriteMBRData(string deviceFilename) { +int MBRData::WriteMBRData(const string & deviceFilename) { device = deviceFilename; return WriteMBRData(); -} // MBRData::WriteMBRData(char* deviceFilename) +} // MBRData::WriteMBRData(const string & deviceFilename) /******************************************** * * @@ -80,7 +80,7 @@ public: ~MBRData(void); // File I/O functions... - int ReadMBRData(string deviceFilename); + int ReadMBRData(const string & deviceFilename); void ReadMBRData(DiskIO * theDisk, int checkBlockSize = 1); // ReadLogicalPart() returns last partition # read to logicals[] array, // or -1 if there was a problem.... @@ -88,7 +88,7 @@ public: int partNum); int WriteMBRData(void); int WriteMBRData(DiskIO *theDisk); - int WriteMBRData(string deviceFilename); + int WriteMBRData(const string & deviceFilename); // Display data for user... void DisplayMBRData(void); diff --git a/parttypes.cc b/parttypes.cc index d4e4a92..2593caa 100644 --- a/parttypes.cc +++ b/parttypes.cc @@ -236,6 +236,7 @@ int PartTypes::AddType(uint16_t mbrType, uint64_t guidData1, uint64_t guidData2, // in an ugly way. void PartTypes::ShowTypes(void) { int colCount = 1; // column count + int i; AType* thisType = allTypes; cout.unsetf(ios::uppercase); @@ -244,17 +245,16 @@ void PartTypes::ShowTypes(void) { cout.fill('0'); cout.width(4); cout << hex << thisType->MBRType << " "; - cout.fill(' '); - cout.setf(ios::left); - cout.width(19); cout << ((string) thisType->name).substr(0, 19) << " "; + for (i = 0; i < (19 - ((string) thisType->name).substr(0, 19).length()); i ++) cout << " "; if ((colCount % 3) == 0) cout << "\n"; colCount++; } // if thisType = thisType->next; } // while - cout << "\n"; + cout.fill(' '); + cout << "\n" << dec; } // PartTypes::ShowTypes() // Returns 1 if code is a valid extended MBR code, 0 if it's not @@ -323,6 +323,7 @@ struct GUIDData PartTypes::IDToGUID(uint16_t ID) { cout << "Exact type match not found for type code "; cout.width(4); cout << hex << ID << "; assigning type code for\n'Linux/Windows data'\n" << dec; + cout.fill(' '); } // if (!found) return theGUID; } // PartTypes::IDToGUID() |