diff --git a/CHANGELOG b/CHANGELOG index a5a7c848a0d076793a4545bf822aa861392b85d8..1a720096d5fe6a68db51ea8cdcc36afe77ea9770 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -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. diff --git a/Makefile b/Makefile index 52ce8ef4a43704cedf2524af255eb57c293f8b34..807d10f45d9fcbf9aed0f8d2e79a3a807f0d3790 100644 --- a/Makefile +++ b/Makefile @@ -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 0976a5a74e76fd3490b3a80e644aac8d9290f103..664fda484a13038052b6724cbfd90f0ecbb7579d 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) diff --git a/bsd.cc b/bsd.cc index 1db68ea89f95fcfc1f679eca6f500e199567d3f5..88c25d0a351e04a7024eb7322549542f6113e583 100644 --- a/bsd.cc +++ b/bsd.cc @@ -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; diff --git a/bsd.h b/bsd.h index 54f5899002aa8c7ce1b37c967f452779bb129bb1..16f3d2c6266fd0304872812bb624fa0ba3e2e084 100644 --- a/bsd.h +++ b/bsd.h @@ -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 84b77eeed6e79534a57b5042f980c4362451c2ef..a060103f10a02aeb4c1accb9311122b3ed36d141 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() diff --git a/diskio.cc b/diskio.cc index d1d0c3c91f4b3c6a8132f76586a3e6e278d4fc20..0f58ab59d95d60ff81d036b8fe7dd803cd3606fc 100644 --- a/diskio.cc +++ b/diskio.cc @@ -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; diff --git a/diskio.h b/diskio.h index 8b752edddf31aa7bfb707ddc9bb44de3f6508949..b27e9777a195a4ec969c0d896313c9eeee6067a1 100644 --- a/diskio.h +++ b/diskio.h @@ -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;} diff --git a/gdisk.8 b/gdisk.8 index b3f4f22020c60b082012254c62d87338d0c20bb5..dad92659732e0736f5b5a611be06e3db7ab2eb57 100644 --- a/gdisk.8 +++ b/gdisk.8 @@ -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 diff --git a/gdisk.cc b/gdisk.cc index 2329fac7296fee9fbf152b5619e2a5a0345874f8..3dddc9e57abfa7ae19730031d79e3abfc3b37a13 100644 --- a/gdisk.cc +++ b/gdisk.cc @@ -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); diff --git a/gpt.cc b/gpt.cc index e5c9852c0bfa6d04da5fde4cea3b074ca7986ad7..3bd56c577d47580be6fac00176e5aa1c8cdf11c1 100644 --- a/gpt.cc +++ b/gpt.cc @@ -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)) { diff --git a/gpt.h b/gpt.h index 76f167878186078bca11641115b1ef46f6a203c2..e1780a11ec74fe737415c93b7f1c34745ca2225f 100644 --- a/gpt.h +++ b/gpt.h @@ -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 diff --git a/gptpart.cc b/gptpart.cc index c6504c11fc2744f91b0890bc871a6aa576b06c87..29b2df9349dba0028230cb11af74da4ff474e664 100644 --- a/gptpart.cc +++ b/gptpart.cc @@ -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 * ***********************************/ diff --git a/gptpart.h b/gptpart.h index dc499b993def0765440a8c90de3252d334e60e7c..d24ed87fba1745377cb3af5d9bdaab1e9fbf8729 100644 --- a/gptpart.h +++ b/gptpart.h @@ -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 diff --git a/mbr.cc b/mbr.cc index 411cae542eeb67c062268d20d94bacf1301d26a3..b1daa3c30ec7a95435b1c154c2c7be249a6b06de 100644 --- a/mbr.cc +++ b/mbr.cc @@ -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) /******************************************** * * diff --git a/mbr.h b/mbr.h index 9fc749bf93cbbf172779b4aadfc56fdbd9c1ffed..e83de7e88a5497690ec604bfbb967d041b5245b9 100644 --- a/mbr.h +++ b/mbr.h @@ -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 d4e4a92bbfb2addb0dcfeceadba72005aea9e2aa..2593caa2098db1f8a897ea36b0c3329ce787c574 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()