diff options
author | srs5694 <srs5694@users.sourceforge.net> | 2010-01-26 16:00:26 -0500 |
---|---|---|
committer | srs5694 <srs5694@users.sourceforge.net> | 2010-01-26 16:00:26 -0500 |
commit | 546a9c7c369df465021feecb20f6a8f81b6df6bc (patch) | |
tree | 280a7cd1fda2a5614582f8675e415d4043fe5e93 /support.cc | |
parent | add79a6e1b3a1af1305f02d51eb3aa148f580caa (diff) | |
download | sgdisk-546a9c7c369df465021feecb20f6a8f81b6df6bc.tar.gz |
New files to support disk I/O restructuring and (currently broken)
Windows version.
Diffstat (limited to 'support.cc')
-rw-r--r-- | support.cc | 290 |
1 files changed, 1 insertions, 289 deletions
@@ -9,9 +9,8 @@ #define __STDC_LIMIT_MACROS #define __STDC_CONSTANT_MACROS -#include <sys/ioctl.h> #include <stdio.h> -#include <string.h> +#include <string> #include <stdint.h> #include <errno.h> #include <fcntl.h> @@ -27,10 +26,6 @@ #define BLKPBSZGET _IO(0x12,123) #endif -// Below constant corresponds to an 800GB disk -- a somewhat arbitrary -// cutoff -#define SMALLEST_ADVANCED_FORMAT UINT64_C(1677721600) - using namespace std; // Get a numeric value from the user, between low and high (inclusive). @@ -205,114 +200,6 @@ char* BytesToSI(uint64_t size, char theValue[]) { return theValue; } // BlocksToSI() -// Returns block size of device pointed to by fd file descriptor. If the ioctl -// returns an error condition, print a warning but return a value of SECTOR_SIZE -// (512).. -int GetBlockSize(int fd) { - int err = -1, result; - -#ifdef __APPLE__ - err = ioctl(fd, DKIOCGETBLOCKSIZE, &result); -#endif -#ifdef __FreeBSD__ - err = ioctl(fd, DIOCGSECTORSIZE, &result); -#endif -#ifdef __linux__ - err = ioctl(fd, BLKSSZGET, &result); -#endif - - if (err == -1) { - result = SECTOR_SIZE; - // ENOTTY = inappropriate ioctl; probably being called on a disk image - // 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", - errno, SECTOR_SIZE); - } // if - } // if - -/* if (result != 512) { - printf("\aWARNING! Sector size is not 512 bytes! This program is likely to "); - printf("misbehave!\nProceed at your own risk!\n\n"); - } // if */ - - return (result); -} // GetBlockSize() - -// My original FindAlignment() function (after this one) isn't working, since -// the BLKPBSZGET ioctl() isn't doing what I expected (it returns 512 even on -// a WD Advanced Format drive). Therefore, I'm using a simpler function that -// returns 1-sector alignment for unusual sector sizes and drives smaller than -// a size defined by SMALLEST_ADVANCED_FORMAT, and 8-sector alignment for -// larger drives with 512-byte sectors. -int FindAlignment(int fd) { - int err, result; - - if ((GetBlockSize(fd) == 512) && (disksize(fd, &err) >= SMALLEST_ADVANCED_FORMAT)) { - result = 8; // play it safe; align for 4096-byte sectors - } else { - result = 1; // unusual sector size; assume it's the real physical size - } // if/else - return result; -} // FindAlignment - -// Return the partition alignment value in sectors. Right now this works -// only for Linux 2.6.32 and later, since I can't find equivalent ioctl()s -// for OS X or FreeBSD, and the Linux ioctl is new -/* int FindAlignment(int fd) { - int err = -2, errnum = 0, result = 8, physicalSectorSize = 4096; - uint64_t diskSize; - - printf("Entering FindAlignment()\n"); -#if defined (__linux__) && defined (BLKPBSZGET) - err = ioctl(fd, BLKPBSZGET, &physicalSectorSize); - printf("In FindAlignment(), physicalSectorSize = %d, err = %d\n", physicalSectorSize, err); -// printf("Tried to get hardware alignment; err is %d, sector size is %d\n", err, physicalSectorSize); -#else - err = -1; -#endif - - if (err < 0) { // ioctl didn't work; have to guess.... - if (GetBlockSize(fd) == 512) { - result = 8; // play it safe; align for 4096-byte sectors - } else { - result = 1; // unusual sector size; assume it's the real physical size - } // if/else - } else { // ioctl worked; compute alignment - result = physicalSectorSize / GetBlockSize(fd); - // Disks with larger physical than logical sectors must theoretically - // have a total disk size that's a multiple of the physical sector - // size; however, some such disks have compatibility jumper settings - // meant for one-partition MBR setups, and these reduce the total - // number of sectors by 1. If such a setting is used, it'll result - // in improper alignment, so look for this condition and warn the - // user if it's found.... - diskSize = disksize(fd, &errnum); - if ((diskSize % (uint64_t) result) != 0) { - fprintf(stderr, "\aWarning! Disk size (%llu) is not a multiple of alignment\n" - "size (%d), but it should be! Check disk manual and jumper settings!\n", - (unsigned long long) diskSize, result); - } // if - } // if/else - if (result <= 0) // can happen if physical sector size < logical sector size - result = 1; - return result; -} // FindAlignment(int) */ - -// The same as FindAlignment(int), but opens and closes a device by filename -int FindAlignment(char deviceFilename[]) { - int fd; - int retval = 1; - - if ((fd = open(deviceFilename, O_RDONLY)) != -1) { - retval = FindAlignment(fd); - close(fd); - } // if - return retval; -} // FindAlignment(char) - // Return a plain-text name for a partition type. // Convert a GUID to a string representation, suitable for display // to humans.... @@ -463,178 +350,3 @@ uint64_t PowerOf2(int value) { } else retval = 0; return retval; } // PowerOf2() - -// An extended file-open function. This includes some system-specific checks. -// I want them in a function because I use these calls twice and I don't want -// to forget to change them in one location if I need to change them in -// the other.... -int OpenForWrite(char* deviceFilename) { - int fd; - - fd = open(deviceFilename, O_WRONLY); // try to open the device; may fail.... -#ifdef __APPLE__ - // MacOS X requires a shared lock under some circumstances.... - if (fd < 0) { - fd = open(deviceFilename, O_WRONLY|O_SHLOCK); - } // if -#endif - return fd; -} // OpenForWrite() - -// Resync disk caches so the OS uses the new partition table. This code varies -// a lot from one OS to another. -void DiskSync(int fd) { - int i; - - sync(); -#ifdef __APPLE__ - printf("Warning: The kernel may continue to use old or deleted partitions.\n" - "You should reboot or remove the drive.\n"); - /* don't know if this helps - * it definitely will get things on disk though: - * http://topiks.org/mac-os-x/0321278542/ch12lev1sec8.html */ - i = ioctl(fd, DKIOCSYNCHRONIZECACHE); -#else -#ifdef __FreeBSD__ - sleep(2); - i = ioctl(fd, DIOCGFLUSH); - printf("Warning: The kernel may continue to use old or deleted partitions.\n" - "You should reboot or remove the drive.\n"); -#else - sleep(2); - i = ioctl(fd, BLKRRPART); - if (i) - printf("Warning: The kernel is still using the old partition table.\n" - "The new table will be used at the next reboot.\n"); -#endif -#endif -} // DiskSync() - -// A variant on the standard read() function. Done to work around -// limitations in FreeBSD concerning the matching of the sector -// size with the number of bytes read -int myRead(int fd, char* buffer, int numBytes) { - int blockSize = 512, i, numBlocks, retval; - char* tempSpace; - - // Compute required space and allocate memory - blockSize = GetBlockSize(fd); - if (numBytes <= blockSize) { - numBlocks = 1; - tempSpace = (char*) malloc(blockSize); - } else { - numBlocks = numBytes / blockSize; - if ((numBytes % blockSize) != 0) numBlocks++; - tempSpace = (char*) malloc(numBlocks * blockSize); - } // if/else - - // Read the data into temporary space, then copy it to buffer - retval = read(fd, tempSpace, numBlocks * blockSize); - for (i = 0; i < numBytes; i++) { - buffer[i] = tempSpace[i]; - } // for - - // Adjust the return value, if necessary.... - if (((numBlocks * blockSize) != numBytes) && (retval > 0)) - retval = numBytes; - - free(tempSpace); - return retval; -} // myRead() - -// A variant on the standard write() function. Done to work around -// limitations in FreeBSD concerning the matching of the sector -// size with the number of bytes read -int myWrite(int fd, char* buffer, int numBytes) { - int blockSize = 512, i, numBlocks, retval; - char* tempSpace; - - // Compute required space and allocate memory - blockSize = GetBlockSize(fd); - if (numBytes <= blockSize) { - numBlocks = 1; - tempSpace = (char*) malloc(blockSize); - } else { - numBlocks = numBytes / blockSize; - if ((numBytes % blockSize) != 0) numBlocks++; - tempSpace = (char*) malloc(numBlocks * blockSize); - } // if/else - - // Copy the data to my own buffer, then write it - for (i = 0; i < numBytes; i++) { - tempSpace[i] = buffer[i]; - } // for - for (i = numBytes; i < numBlocks * blockSize; i++) { - tempSpace[i] = 0; - } // for - retval = write(fd, tempSpace, numBlocks * blockSize); - - // Adjust the return value, if necessary.... - if (((numBlocks * blockSize) != numBytes) && (retval > 0)) - retval = numBytes; - - free(tempSpace); - return retval; -} // myRead() - -/************************************************************************************** - * * - * Below functions are lifted from various sources, as documented in comments before * - * each one. * - * * - **************************************************************************************/ - -// The disksize function is taken from the Linux fdisk code and modified -// greatly since then to enable FreeBSD and MacOS support, as well as to -// return correct values for disk image files. -uint64_t disksize(int fd, int *err) { - long sz; // Do not delete; needed for Linux - long long b; // Do not delete; needed for Linux - uint64_t sectors = 0; // size in sectors - off_t bytes = 0; // size in bytes - struct stat64 st; - - // Note to self: I recall testing a simplified version of - // this code, similar to what's in the __APPLE__ block, - // 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.... -#ifdef __APPLE__ - *err = ioctl(fd, DKIOCGETBLOCKCOUNT, §ors); -#else -#ifdef __FreeBSD__ - *err = ioctl(fd, DIOCGMEDIASIZE, &bytes); - b = GetBlockSize(fd); - sectors = bytes / b; -#else - *err = ioctl(fd, BLKGETSIZE, &sz); - if (*err) { - sectors = sz = 0; - } // if - if ((errno == EFBIG) || (!*err)) { - *err = ioctl(fd, BLKGETSIZE64, &b); - if (*err || b == 0 || b == sz) - sectors = sz; - else - sectors = (b >> 9); - } // if - // Unintuitively, the above returns values in 512-byte blocks, no - // matter what the underlying device's block size. Correct for this.... - sectors /= (GetBlockSize(fd) / 512); -#endif -#endif - - // The above methods have failed (or it's a bum filename reference), - // so let's assume it's a regular file (a QEMU image, dd backup, or - // what have you) and see what stat() 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 - return sectors; -} // disksize() |