diff options
author | srs5694 <srs5694@users.sourceforge.net> | 2010-01-26 15:59:58 -0500 |
---|---|---|
committer | srs5694 <srs5694@users.sourceforge.net> | 2010-01-26 15:59:58 -0500 |
commit | add79a6e1b3a1af1305f02d51eb3aa148f580caa (patch) | |
tree | 760dc4c9625f089621724bba5922394eb3427993 /diskio.cc | |
parent | 7dbb932233c77cc91ea202ddf5a6198034558ae2 (diff) | |
download | sgdisk-add79a6e1b3a1af1305f02d51eb3aa148f580caa.tar.gz |
New files to support I/O restructuring and (currently broken) Windows
version.
Diffstat (limited to 'diskio.cc')
-rw-r--r-- | diskio.cc | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/diskio.cc b/diskio.cc new file mode 100644 index 0000000..3fc3726 --- /dev/null +++ b/diskio.cc @@ -0,0 +1,164 @@ +// +// C++ Interface: diskio (platform-independent components) +// +// Description: Class to handle low-level disk I/O for GPT fdisk +// +// +// Author: Rod Smith <rodsmith@rodsbooks.com>, (C) 2009 +// +// Copyright: See COPYING file that comes with this distribution +// +// +// This program is copyright (c) 2009 by Roderick W. Smith. It is distributed +// under the terms of the GNU GPL version 2, as detailed in the COPYING file. + +#define __STDC_LIMIT_MACROS +#define __STDC_CONSTANT_MACROS + +#ifdef MINGW +#include <windows.h> +#include <winioctl.h> +#define fstat64 fstat +#define stat64 stat +#define S_IRGRP 0 +#define S_IROTH 0 +#else +#include <sys/ioctl.h> +#endif +#include <stdio.h> +#include <string> +#include <stdint.h> +#include <errno.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <iostream> + +#include "support.h" +#include "diskio.h" + +using namespace std; + +DiskIO::DiskIO(void) { + userFilename = ""; + realFilename = ""; + isOpen = 0; + openForWrite = 0; + sectorData = NULL; +} // constructor + +DiskIO::~DiskIO(void) { + Close(); + free(sectorData); +} // destructor + +// Open a disk device for reading. Returns 1 on success, 0 on failure. +int DiskIO::OpenForRead(string filename) { + int shouldOpen = 1; + + if (isOpen) { // file is already open + if (((realFilename != filename) && (userFilename != filename)) || (openForWrite)) { + Close(); + } else { + shouldOpen = 0; + } // if/else + } // if + + if (shouldOpen) { + userFilename = filename; + MakeRealName(); + OpenForRead(); + } // if + + return isOpen; +} // 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 retval = 0; + + if ((isOpen) && (openForWrite) && ((filename == realFilename) || (filename == userFilename))) { + retval = 1; + } else { + userFilename = filename; + MakeRealName(); + retval = OpenForWrite(); + if (retval == 0) { + realFilename = userFilename = ""; + } // if + } // if/else + return retval; +} // DiskIO::OpenForWrite(string filename) + +// 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 DiskIO::FindAlignment(void) { + int err, result; + + if ((GetBlockSize() == 512) && (DiskSize(&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; +} // DiskIO::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 DiskIO::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; +} // DiskIO::FindAlignment(int) */ + +// The same as FindAlignment(int), but opens and closes a device by filename +int DiskIO::FindAlignment(string filename) { + int fd; + int retval = 1; + + if (!isOpen) + OpenForRead(filename); + if (isOpen) { + retval = FindAlignment(); + } // if + return retval; +} // DiskIO::FindAlignment(char) |