xref: /aosp_15_r20/external/gptfdisk/diskio-windows.cc (revision 57696d54d05c64fd1b1787f8371dbcf104911cfb)
1*57696d54SAkhilesh Sanikop //
2*57696d54SAkhilesh Sanikop // C++ Interface: diskio (Windows-specific components)
3*57696d54SAkhilesh Sanikop //
4*57696d54SAkhilesh Sanikop // Description: Class to handle low-level disk I/O for GPT fdisk
5*57696d54SAkhilesh Sanikop //
6*57696d54SAkhilesh Sanikop //
7*57696d54SAkhilesh Sanikop // Author: Rod Smith <[email protected]>, (C) 2009
8*57696d54SAkhilesh Sanikop //
9*57696d54SAkhilesh Sanikop // Copyright: See COPYING file that comes with this distribution
10*57696d54SAkhilesh Sanikop //
11*57696d54SAkhilesh Sanikop //
12*57696d54SAkhilesh Sanikop // This program is copyright (c) 2009, 2010 by Roderick W. Smith. It is distributed
13*57696d54SAkhilesh Sanikop // under the terms of the GNU GPL version 2, as detailed in the COPYING file.
14*57696d54SAkhilesh Sanikop 
15*57696d54SAkhilesh Sanikop #define __STDC_LIMIT_MACROS
16*57696d54SAkhilesh Sanikop #define __STDC_CONSTANT_MACROS
17*57696d54SAkhilesh Sanikop 
18*57696d54SAkhilesh Sanikop #include <windows.h>
19*57696d54SAkhilesh Sanikop #include <winioctl.h>
20*57696d54SAkhilesh Sanikop #define fstat64 fstat
21*57696d54SAkhilesh Sanikop #define stat64 stat
22*57696d54SAkhilesh Sanikop #define S_IRGRP 0
23*57696d54SAkhilesh Sanikop #define S_IROTH 0
24*57696d54SAkhilesh Sanikop #include <stdio.h>
25*57696d54SAkhilesh Sanikop #include <string>
26*57696d54SAkhilesh Sanikop #include <stdint.h>
27*57696d54SAkhilesh Sanikop #include <errno.h>
28*57696d54SAkhilesh Sanikop #include <fcntl.h>
29*57696d54SAkhilesh Sanikop #include <sys/stat.h>
30*57696d54SAkhilesh Sanikop #include <iostream>
31*57696d54SAkhilesh Sanikop 
32*57696d54SAkhilesh Sanikop #include "support.h"
33*57696d54SAkhilesh Sanikop #include "diskio.h"
34*57696d54SAkhilesh Sanikop 
35*57696d54SAkhilesh Sanikop using namespace std;
36*57696d54SAkhilesh Sanikop 
37*57696d54SAkhilesh Sanikop // Returns the official Windows name for a shortened version of same.
MakeRealName(void)38*57696d54SAkhilesh Sanikop void DiskIO::MakeRealName(void) {
39*57696d54SAkhilesh Sanikop    size_t colonPos;
40*57696d54SAkhilesh Sanikop 
41*57696d54SAkhilesh Sanikop    colonPos = userFilename.find(':', 0);
42*57696d54SAkhilesh Sanikop    if ((colonPos != string::npos) && (colonPos <= 3)) {
43*57696d54SAkhilesh Sanikop       realFilename = "\\\\.\\physicaldrive";
44*57696d54SAkhilesh Sanikop       realFilename += userFilename.substr(0, colonPos);
45*57696d54SAkhilesh Sanikop    } else {
46*57696d54SAkhilesh Sanikop       realFilename = userFilename;
47*57696d54SAkhilesh Sanikop    } // if/else
48*57696d54SAkhilesh Sanikop } // DiskIO::MakeRealName()
49*57696d54SAkhilesh Sanikop 
50*57696d54SAkhilesh Sanikop // Open the currently on-record file for reading
OpenForRead(void)51*57696d54SAkhilesh Sanikop int DiskIO::OpenForRead(void) {
52*57696d54SAkhilesh Sanikop    int shouldOpen = 1;
53*57696d54SAkhilesh Sanikop 
54*57696d54SAkhilesh Sanikop    if (isOpen) { // file is already open
55*57696d54SAkhilesh Sanikop       if (openForWrite) {
56*57696d54SAkhilesh Sanikop          Close();
57*57696d54SAkhilesh Sanikop       } else {
58*57696d54SAkhilesh Sanikop          shouldOpen = 0;
59*57696d54SAkhilesh Sanikop       } // if/else
60*57696d54SAkhilesh Sanikop    } // if
61*57696d54SAkhilesh Sanikop 
62*57696d54SAkhilesh Sanikop    if (shouldOpen) {
63*57696d54SAkhilesh Sanikop       fd = CreateFile(realFilename.c_str(),GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
64*57696d54SAkhilesh Sanikop                       NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
65*57696d54SAkhilesh Sanikop       if (fd == INVALID_HANDLE_VALUE) {
66*57696d54SAkhilesh Sanikop          CloseHandle(fd);
67*57696d54SAkhilesh Sanikop          cerr << "Problem opening " << realFilename << " for reading!\n";
68*57696d54SAkhilesh Sanikop          realFilename = "";
69*57696d54SAkhilesh Sanikop          userFilename = "";
70*57696d54SAkhilesh Sanikop          isOpen = 0;
71*57696d54SAkhilesh Sanikop          openForWrite = 0;
72*57696d54SAkhilesh Sanikop       } else {
73*57696d54SAkhilesh Sanikop          isOpen = 1;
74*57696d54SAkhilesh Sanikop          openForWrite = 0;
75*57696d54SAkhilesh Sanikop       } // if/else
76*57696d54SAkhilesh Sanikop    } // if
77*57696d54SAkhilesh Sanikop 
78*57696d54SAkhilesh Sanikop    return isOpen;
79*57696d54SAkhilesh Sanikop } // DiskIO::OpenForRead(void)
80*57696d54SAkhilesh Sanikop 
81*57696d54SAkhilesh Sanikop // An extended file-open function. This includes some system-specific checks.
82*57696d54SAkhilesh Sanikop // Returns 1 if the file is open, 0 otherwise....
OpenForWrite(void)83*57696d54SAkhilesh Sanikop int DiskIO::OpenForWrite(void) {
84*57696d54SAkhilesh Sanikop    if ((isOpen) && (openForWrite))
85*57696d54SAkhilesh Sanikop       return 1;
86*57696d54SAkhilesh Sanikop 
87*57696d54SAkhilesh Sanikop    // Close the disk, in case it's already open for reading only....
88*57696d54SAkhilesh Sanikop    Close();
89*57696d54SAkhilesh Sanikop 
90*57696d54SAkhilesh Sanikop    // try to open the device; may fail....
91*57696d54SAkhilesh Sanikop    fd = CreateFile(realFilename.c_str(), GENERIC_READ | GENERIC_WRITE,
92*57696d54SAkhilesh Sanikop                    FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
93*57696d54SAkhilesh Sanikop                    FILE_ATTRIBUTE_NORMAL, NULL);
94*57696d54SAkhilesh Sanikop    // Preceding call can fail when creating backup files; if so, try
95*57696d54SAkhilesh Sanikop    // again with different option...
96*57696d54SAkhilesh Sanikop    if (fd == INVALID_HANDLE_VALUE) {
97*57696d54SAkhilesh Sanikop       CloseHandle(fd);
98*57696d54SAkhilesh Sanikop       fd = CreateFile(realFilename.c_str(), GENERIC_READ | GENERIC_WRITE,
99*57696d54SAkhilesh Sanikop                       FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
100*57696d54SAkhilesh Sanikop                       FILE_ATTRIBUTE_NORMAL, NULL);
101*57696d54SAkhilesh Sanikop    } // if
102*57696d54SAkhilesh Sanikop    if (fd == INVALID_HANDLE_VALUE) {
103*57696d54SAkhilesh Sanikop       CloseHandle(fd);
104*57696d54SAkhilesh Sanikop       isOpen = 0;
105*57696d54SAkhilesh Sanikop       openForWrite = 0;
106*57696d54SAkhilesh Sanikop       errno = GetLastError();
107*57696d54SAkhilesh Sanikop    } else {
108*57696d54SAkhilesh Sanikop       isOpen = 1;
109*57696d54SAkhilesh Sanikop       openForWrite = 1;
110*57696d54SAkhilesh Sanikop    } // if/else
111*57696d54SAkhilesh Sanikop    return isOpen;
112*57696d54SAkhilesh Sanikop } // DiskIO::OpenForWrite(void)
113*57696d54SAkhilesh Sanikop 
114*57696d54SAkhilesh Sanikop // Close the disk device. Note that this does NOT erase the stored filenames,
115*57696d54SAkhilesh Sanikop // so the file can be re-opened without specifying the filename.
Close(void)116*57696d54SAkhilesh Sanikop void DiskIO::Close(void) {
117*57696d54SAkhilesh Sanikop    if (isOpen)
118*57696d54SAkhilesh Sanikop       CloseHandle(fd);
119*57696d54SAkhilesh Sanikop    isOpen = 0;
120*57696d54SAkhilesh Sanikop    openForWrite = 0;
121*57696d54SAkhilesh Sanikop } // DiskIO::Close()
122*57696d54SAkhilesh Sanikop 
123*57696d54SAkhilesh Sanikop // Returns block size of device pointed to by fd file descriptor. If the ioctl
124*57696d54SAkhilesh Sanikop // returns an error condition, assume it's a disk file and return a value of
125*57696d54SAkhilesh Sanikop // SECTOR_SIZE (512). If the disk can't be opened at all, return a value of 0.
GetBlockSize(void)126*57696d54SAkhilesh Sanikop int DiskIO::GetBlockSize(void) {
127*57696d54SAkhilesh Sanikop    DWORD blockSize = 0, retBytes;
128*57696d54SAkhilesh Sanikop    DISK_GEOMETRY_EX geom;
129*57696d54SAkhilesh Sanikop 
130*57696d54SAkhilesh Sanikop    // If disk isn't open, try to open it....
131*57696d54SAkhilesh Sanikop    if (!isOpen) {
132*57696d54SAkhilesh Sanikop       OpenForRead();
133*57696d54SAkhilesh Sanikop    } // if
134*57696d54SAkhilesh Sanikop 
135*57696d54SAkhilesh Sanikop    if (isOpen) {
136*57696d54SAkhilesh Sanikop       if (DeviceIoControl(fd, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0,
137*57696d54SAkhilesh Sanikop                           &geom, sizeof(geom), &retBytes, NULL)) {
138*57696d54SAkhilesh Sanikop          blockSize = geom.Geometry.BytesPerSector;
139*57696d54SAkhilesh Sanikop       } else { // was probably an ordinary file; set default value....
140*57696d54SAkhilesh Sanikop          blockSize = SECTOR_SIZE;
141*57696d54SAkhilesh Sanikop       } // if/else
142*57696d54SAkhilesh Sanikop    } // if (isOpen)
143*57696d54SAkhilesh Sanikop 
144*57696d54SAkhilesh Sanikop    return (blockSize);
145*57696d54SAkhilesh Sanikop } // DiskIO::GetBlockSize()
146*57696d54SAkhilesh Sanikop 
147*57696d54SAkhilesh Sanikop // In theory, returns the physical block size. In practice, this is only
148*57696d54SAkhilesh Sanikop // supported in Linux, as of yet.
149*57696d54SAkhilesh Sanikop // TODO: Get this working in Windows.
GetPhysBlockSize(void)150*57696d54SAkhilesh Sanikop int DiskIO::GetPhysBlockSize(void) {
151*57696d54SAkhilesh Sanikop    return 0;
152*57696d54SAkhilesh Sanikop } // DiskIO::GetPhysBlockSize()
153*57696d54SAkhilesh Sanikop 
154*57696d54SAkhilesh Sanikop // Returns the number of heads, according to the kernel, or 255 if the
155*57696d54SAkhilesh Sanikop // correct value can't be determined.
GetNumHeads(void)156*57696d54SAkhilesh Sanikop uint32_t DiskIO::GetNumHeads(void) {
157*57696d54SAkhilesh Sanikop    return UINT32_C(255);
158*57696d54SAkhilesh Sanikop } // DiskIO::GetNumHeads();
159*57696d54SAkhilesh Sanikop 
160*57696d54SAkhilesh Sanikop // Returns the number of sectors per track, according to the kernel, or 63
161*57696d54SAkhilesh Sanikop // if the correct value can't be determined.
GetNumSecsPerTrack(void)162*57696d54SAkhilesh Sanikop uint32_t DiskIO::GetNumSecsPerTrack(void) {
163*57696d54SAkhilesh Sanikop    return UINT32_C(63);
164*57696d54SAkhilesh Sanikop } // DiskIO::GetNumSecsPerTrack()
165*57696d54SAkhilesh Sanikop 
166*57696d54SAkhilesh Sanikop // Resync disk caches so the OS uses the new partition table. This code varies
167*57696d54SAkhilesh Sanikop // a lot from one OS to another.
168*57696d54SAkhilesh Sanikop // Returns 1 on success, 0 if the kernel continues to use the old partition table.
DiskSync(void)169*57696d54SAkhilesh Sanikop int DiskIO::DiskSync(void) {
170*57696d54SAkhilesh Sanikop    DWORD i;
171*57696d54SAkhilesh Sanikop    GET_LENGTH_INFORMATION buf;
172*57696d54SAkhilesh Sanikop    int retval = 0;
173*57696d54SAkhilesh Sanikop 
174*57696d54SAkhilesh Sanikop    // If disk isn't open, try to open it....
175*57696d54SAkhilesh Sanikop    if (!openForWrite) {
176*57696d54SAkhilesh Sanikop       OpenForWrite();
177*57696d54SAkhilesh Sanikop    } // if
178*57696d54SAkhilesh Sanikop 
179*57696d54SAkhilesh Sanikop    if (isOpen) {
180*57696d54SAkhilesh Sanikop       if (DeviceIoControl(fd, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, &buf, sizeof(buf), &i, NULL) == 0) {
181*57696d54SAkhilesh Sanikop          cout << "Disk synchronization failed! The computer may use the old partition table\n"
182*57696d54SAkhilesh Sanikop               << "until you reboot or remove and re-insert the disk!\n";
183*57696d54SAkhilesh Sanikop       } else {
184*57696d54SAkhilesh Sanikop          cout << "Disk synchronization succeeded! The computer should now use the new\n"
185*57696d54SAkhilesh Sanikop               << "partition table.\n";
186*57696d54SAkhilesh Sanikop          retval = 1;
187*57696d54SAkhilesh Sanikop       } // if/else
188*57696d54SAkhilesh Sanikop    } else {
189*57696d54SAkhilesh Sanikop       cout << "Unable to open the disk for synchronization operation! The computer will\n"
190*57696d54SAkhilesh Sanikop            << "continue to use the old partition table until you reboot or remove and\n"
191*57696d54SAkhilesh Sanikop            << "re-insert the disk!\n";
192*57696d54SAkhilesh Sanikop    } // if (isOpen)
193*57696d54SAkhilesh Sanikop    return retval;
194*57696d54SAkhilesh Sanikop } // DiskIO::DiskSync()
195*57696d54SAkhilesh Sanikop 
196*57696d54SAkhilesh Sanikop // Seek to the specified sector. Returns 1 on success, 0 on failure.
Seek(uint64_t sector)197*57696d54SAkhilesh Sanikop int DiskIO::Seek(uint64_t sector) {
198*57696d54SAkhilesh Sanikop    int retval = 1;
199*57696d54SAkhilesh Sanikop    LARGE_INTEGER seekTo;
200*57696d54SAkhilesh Sanikop 
201*57696d54SAkhilesh Sanikop    // If disk isn't open, try to open it....
202*57696d54SAkhilesh Sanikop    if (!isOpen) {
203*57696d54SAkhilesh Sanikop       retval = OpenForRead();
204*57696d54SAkhilesh Sanikop    } // if
205*57696d54SAkhilesh Sanikop 
206*57696d54SAkhilesh Sanikop    if (isOpen) {
207*57696d54SAkhilesh Sanikop       seekTo.QuadPart = sector * (uint64_t) GetBlockSize();
208*57696d54SAkhilesh Sanikop       retval = SetFilePointerEx(fd, seekTo, NULL, FILE_BEGIN);
209*57696d54SAkhilesh Sanikop       if (retval == 0) {
210*57696d54SAkhilesh Sanikop          errno = GetLastError();
211*57696d54SAkhilesh Sanikop          cerr << "Error when seeking to " << seekTo.QuadPart << "! Error is " << errno << "\n";
212*57696d54SAkhilesh Sanikop          retval = 0;
213*57696d54SAkhilesh Sanikop       } // if
214*57696d54SAkhilesh Sanikop    } // if
215*57696d54SAkhilesh Sanikop    return retval;
216*57696d54SAkhilesh Sanikop } // DiskIO::Seek()
217*57696d54SAkhilesh Sanikop 
218*57696d54SAkhilesh Sanikop // A variant on the standard read() function. Done to work around
219*57696d54SAkhilesh Sanikop // limitations in FreeBSD concerning the matching of the sector
220*57696d54SAkhilesh Sanikop // size with the number of bytes read.
221*57696d54SAkhilesh Sanikop // Returns the number of bytes read into buffer.
Read(void * buffer,int numBytes)222*57696d54SAkhilesh Sanikop int DiskIO::Read(void* buffer, int numBytes) {
223*57696d54SAkhilesh Sanikop    int blockSize = 512, i, numBlocks;
224*57696d54SAkhilesh Sanikop    char* tempSpace;
225*57696d54SAkhilesh Sanikop    DWORD retval = 0;
226*57696d54SAkhilesh Sanikop 
227*57696d54SAkhilesh Sanikop    // If disk isn't open, try to open it....
228*57696d54SAkhilesh Sanikop    if (!isOpen) {
229*57696d54SAkhilesh Sanikop       OpenForRead();
230*57696d54SAkhilesh Sanikop    } // if
231*57696d54SAkhilesh Sanikop 
232*57696d54SAkhilesh Sanikop    if (isOpen) {
233*57696d54SAkhilesh Sanikop       // Compute required space and allocate memory
234*57696d54SAkhilesh Sanikop       blockSize = GetBlockSize();
235*57696d54SAkhilesh Sanikop       if (numBytes <= blockSize) {
236*57696d54SAkhilesh Sanikop          numBlocks = 1;
237*57696d54SAkhilesh Sanikop          tempSpace = new char [blockSize];
238*57696d54SAkhilesh Sanikop       } else {
239*57696d54SAkhilesh Sanikop          numBlocks = numBytes / blockSize;
240*57696d54SAkhilesh Sanikop          if ((numBytes % blockSize) != 0)
241*57696d54SAkhilesh Sanikop             numBlocks++;
242*57696d54SAkhilesh Sanikop          tempSpace = new char [numBlocks * blockSize];
243*57696d54SAkhilesh Sanikop       } // if/else
244*57696d54SAkhilesh Sanikop       if (tempSpace == NULL) {
245*57696d54SAkhilesh Sanikop          cerr << "Unable to allocate memory in DiskIO::Read()! Terminating!\n";
246*57696d54SAkhilesh Sanikop          exit(1);
247*57696d54SAkhilesh Sanikop       } // if
248*57696d54SAkhilesh Sanikop 
249*57696d54SAkhilesh Sanikop       // Read the data into temporary space, then copy it to buffer
250*57696d54SAkhilesh Sanikop       ReadFile(fd, tempSpace, numBlocks * blockSize, &retval, NULL);
251*57696d54SAkhilesh Sanikop       for (i = 0; i < numBytes; i++) {
252*57696d54SAkhilesh Sanikop          ((char*) buffer)[i] = tempSpace[i];
253*57696d54SAkhilesh Sanikop       } // for
254*57696d54SAkhilesh Sanikop 
255*57696d54SAkhilesh Sanikop       // Adjust the return value, if necessary....
256*57696d54SAkhilesh Sanikop       if (((numBlocks * blockSize) != numBytes) && (retval > 0))
257*57696d54SAkhilesh Sanikop          retval = numBytes;
258*57696d54SAkhilesh Sanikop 
259*57696d54SAkhilesh Sanikop       delete[] tempSpace;
260*57696d54SAkhilesh Sanikop    } // if (isOpen)
261*57696d54SAkhilesh Sanikop    return retval;
262*57696d54SAkhilesh Sanikop } // DiskIO::Read()
263*57696d54SAkhilesh Sanikop 
264*57696d54SAkhilesh Sanikop // A variant on the standard write() function.
265*57696d54SAkhilesh Sanikop // Returns the number of bytes written.
Write(void * buffer,int numBytes)266*57696d54SAkhilesh Sanikop int DiskIO::Write(void* buffer, int numBytes) {
267*57696d54SAkhilesh Sanikop    int blockSize = 512, i, numBlocks, retval = 0;
268*57696d54SAkhilesh Sanikop    char* tempSpace;
269*57696d54SAkhilesh Sanikop    DWORD numWritten;
270*57696d54SAkhilesh Sanikop 
271*57696d54SAkhilesh Sanikop    // If disk isn't open, try to open it....
272*57696d54SAkhilesh Sanikop    if ((!isOpen) || (!openForWrite)) {
273*57696d54SAkhilesh Sanikop       OpenForWrite();
274*57696d54SAkhilesh Sanikop    } // if
275*57696d54SAkhilesh Sanikop 
276*57696d54SAkhilesh Sanikop    if (isOpen) {
277*57696d54SAkhilesh Sanikop       // Compute required space and allocate memory
278*57696d54SAkhilesh Sanikop       blockSize = GetBlockSize();
279*57696d54SAkhilesh Sanikop       if (numBytes <= blockSize) {
280*57696d54SAkhilesh Sanikop          numBlocks = 1;
281*57696d54SAkhilesh Sanikop          tempSpace = new char [blockSize];
282*57696d54SAkhilesh Sanikop       } else {
283*57696d54SAkhilesh Sanikop          numBlocks = numBytes / blockSize;
284*57696d54SAkhilesh Sanikop          if ((numBytes % blockSize) != 0) numBlocks++;
285*57696d54SAkhilesh Sanikop          tempSpace = new char [numBlocks * blockSize];
286*57696d54SAkhilesh Sanikop       } // if/else
287*57696d54SAkhilesh Sanikop       if (tempSpace == NULL) {
288*57696d54SAkhilesh Sanikop          cerr << "Unable to allocate memory in DiskIO::Write()! Terminating!\n";
289*57696d54SAkhilesh Sanikop          exit(1);
290*57696d54SAkhilesh Sanikop       } // if
291*57696d54SAkhilesh Sanikop 
292*57696d54SAkhilesh Sanikop       // Copy the data to my own buffer, then write it
293*57696d54SAkhilesh Sanikop       for (i = 0; i < numBytes; i++) {
294*57696d54SAkhilesh Sanikop          tempSpace[i] = ((char*) buffer)[i];
295*57696d54SAkhilesh Sanikop       } // for
296*57696d54SAkhilesh Sanikop       for (i = numBytes; i < numBlocks * blockSize; i++) {
297*57696d54SAkhilesh Sanikop          tempSpace[i] = 0;
298*57696d54SAkhilesh Sanikop       } // for
299*57696d54SAkhilesh Sanikop       WriteFile(fd, tempSpace, numBlocks * blockSize, &numWritten, NULL);
300*57696d54SAkhilesh Sanikop       retval = (int) numWritten;
301*57696d54SAkhilesh Sanikop 
302*57696d54SAkhilesh Sanikop       // Adjust the return value, if necessary....
303*57696d54SAkhilesh Sanikop       if (((numBlocks * blockSize) != numBytes) && (retval > 0))
304*57696d54SAkhilesh Sanikop          retval = numBytes;
305*57696d54SAkhilesh Sanikop 
306*57696d54SAkhilesh Sanikop       delete[] tempSpace;
307*57696d54SAkhilesh Sanikop    } // if (isOpen)
308*57696d54SAkhilesh Sanikop    return retval;
309*57696d54SAkhilesh Sanikop } // DiskIO:Write()
310*57696d54SAkhilesh Sanikop 
311*57696d54SAkhilesh Sanikop // Returns the size of the disk in blocks.
DiskSize(int * err)312*57696d54SAkhilesh Sanikop uint64_t DiskIO::DiskSize(int *err) {
313*57696d54SAkhilesh Sanikop    uint64_t sectors = 0; // size in sectors
314*57696d54SAkhilesh Sanikop    DWORD bytes, moreBytes; // low- and high-order bytes of file size
315*57696d54SAkhilesh Sanikop    GET_LENGTH_INFORMATION buf;
316*57696d54SAkhilesh Sanikop    DWORD i;
317*57696d54SAkhilesh Sanikop 
318*57696d54SAkhilesh Sanikop    // If disk isn't open, try to open it....
319*57696d54SAkhilesh Sanikop    if (!isOpen) {
320*57696d54SAkhilesh Sanikop       OpenForRead();
321*57696d54SAkhilesh Sanikop    } // if
322*57696d54SAkhilesh Sanikop 
323*57696d54SAkhilesh Sanikop    if (isOpen) {
324*57696d54SAkhilesh Sanikop       // Note to self: I recall testing a simplified version of
325*57696d54SAkhilesh Sanikop       // this code, similar to what's in the __APPLE__ block,
326*57696d54SAkhilesh Sanikop       // on Linux, but I had some problems. IIRC, it ran OK on 32-bit
327*57696d54SAkhilesh Sanikop       // systems but not on 64-bit. Keep this in mind in case of
328*57696d54SAkhilesh Sanikop       // 32/64-bit issues on MacOS....
329*57696d54SAkhilesh Sanikop       if (DeviceIoControl(fd, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &buf, sizeof(buf), &i, NULL)) {
330*57696d54SAkhilesh Sanikop          sectors = (uint64_t) buf.Length.QuadPart / GetBlockSize();
331*57696d54SAkhilesh Sanikop          *err = 0;
332*57696d54SAkhilesh Sanikop       } else { // doesn't seem to be a disk device; assume it's an image file....
333*57696d54SAkhilesh Sanikop          bytes = GetFileSize(fd, &moreBytes);
334*57696d54SAkhilesh Sanikop          sectors = ((uint64_t) bytes + ((uint64_t) moreBytes) * UINT32_MAX) / GetBlockSize();
335*57696d54SAkhilesh Sanikop          *err = 0;
336*57696d54SAkhilesh Sanikop       } // if
337*57696d54SAkhilesh Sanikop    } else {
338*57696d54SAkhilesh Sanikop       *err = -1;
339*57696d54SAkhilesh Sanikop       sectors = 0;
340*57696d54SAkhilesh Sanikop    } // if/else (isOpen)
341*57696d54SAkhilesh Sanikop 
342*57696d54SAkhilesh Sanikop    return sectors;
343*57696d54SAkhilesh Sanikop } // DiskIO::DiskSize()
344