Board index » cppbuilder » Determining size of a physical device

Determining size of a physical device


2008-03-05 04:41:47 PM
cppbuilder56
I am trying to open a disk drive as a file using CreateFile and then
determining the size of the device. I am using Builder 2007 on XP SP2 and am
logged in as admin.
My code is below
_LARGE_INTEGER li;
fp = CreateFile(\\\\.\\PhysicalDrive0",
GENERIC_READ || GENERIC_WRITE,
FILE_SHARE_READ || FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_RANDOM_ACCESS || FILE_FLAG_NO_BUFFERING,
NULL);
if(fp != INVALID_HANDLE_VALUE)
GetFileSizeEx(fp, &li);
on return li.Quadpart = some random value (although consistent through a
session and for different devices)
I am probably doing something stupid but I cant see it - any ideas?
 
 

Re:Determining size of a physical device

Quote
Re: Determining size of a physical device
Have you tried using a ruler? :-)
"Paul" < XXXX@XXXXX.COM >wrote in message
Quote
I am trying to open a disk drive as a file using CreateFile and then
determining the size of the device. [snip]
if(fp != INVALID_HANDLE_VALUE)
GetFileSizeEx(fp, &li);

on return li.Quadpart = some random value (although consistent through a
session and for different devices)
You can't use GetFileSizeEx to determine the size of a physical device (you
should be checking error codes -- the GetFileSizeEx function is likely
returning a failure code here). Use DeviceIoControl:
msdn2.microsoft.com/en-us/library/aa363216(VS.85).aspx
Specifically, you are interested in IOCTL_DISK_GET_DRIVE_GEOMETRY_EX (the
DiskSize member of the DISK_GEOMETRY_EX structure):
msdn2.microsoft.com/en-us/library/aa363216(VS.85).aspx
Here is a list of some other ioctl codes you can use on physical devices,
FYI:
msdn2.microsoft.com/en-us/library/aa363979(VS.85).aspx
The second way to do it is to use the SMART ATA ID command. This only works
if your drive supports SMART. It's more straightforward to use
IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, but if you happen to be doing SMART stuff
in general, and you want to know how to do this, I'll be happy to post an
example. I'd stick to the non-SMART way though if all you want to do is get
the drive size. The above ioctl's will work just fine.
Jason
 

Re:Determining size of a physical device

"Paul" < XXXX@XXXXX.COM >wrote in message
Quote
I am trying to open a disk drive as a file using CreateFile and then
determining the size of the device.
P.S. I meant to mention this in my last post, but in the future you'll want
to post questions like this (that involve Windows API) in
borland.public.cppbuilder.nativeapi. This one is more for questions about
the C++ language itself.
Jason
 

{smallsort}

Re:Determining size of a physical device

Thanks Jason - I'll give that lot a go.
 

Re:Determining size of a physical device

I'll continue this on this thread as I started here :)
I have implemnted your suggestions but I get an "invalid access to memory
location" error from GetLastError when the code is run, my code is
HANDLE fp=NULL;
PDISK_GEOMETRY_EX pdg;
DWORD sz;
fp = CreateFile("\\\\.\\PhysicalDrive0", GENERIC_READ || GENERIC_WRITE,
FILE_SHARE_READ || FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_RANDOM_ACCESS || FILE_FLAG_NO_BUFFERING,
NULL);
if(fp != INVALID_HANDLE_VALUE)
if(DeviceIoControl(fp,IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0, pdg,
sizeof(*pdg), &sz, NULL)!=0)
FileSize = pdg->DiskSize.QuadPart;
The file handle is obtained OK and I can read valid data from the disk - but
I still cant get the disk size. Again prob something very stupid and any
help appreciated.
 

Re:Determining size of a physical device

Jason
I would be interested in the SMART stuff also.
Cheers
 

Re:Determining size of a physical device

"Paul" < XXXX@XXXXX.COM >wrote in message
Quote
GENERIC_READ || GENERIC_WRITE,
FILE_SHARE_READ || FILE_SHARE_WRITE,
FILE_FLAG_RANDOM_ACCESS || FILE_FLAG_NO_BUFFERING,
You need to use the '|' operator instead of the '||' operator. By using the
'||' operator, you are effectively calling the following instead, which is
quite different than what you intended:
fp = CreateFile("\\\\.\\PhysicalDrive0",
1,
FILE_SHARE_READ,
0,
OPEN_EXISTING,
FILE_ATTRIBUTE_READONLY,
NULL);
Quote
on return li.Quadpart = some random value
You are not checking the return value of GetFileSizeEx() to make sure it
actually succeeded:
if( fp != INVALID_HANDLE_VALUE )
{
if( GetFileSizeEx(fp, &li) )
// use li as needed...
else
// failed, use GetLastError() to find out why...
}
else
// failed, use GetLastError() to find out why...
Gambit
 

Re:Determining size of a physical device

Thanks remy
I had simplified my code forthe list and was calling GetLastError - but
lesson learned.
but still that did not help with the DeviceIoControl of GetFileSizeEx issues
as mentioned in my reply to Jason.
 

Re:Determining size of a physical device

Yep - stooopid sorted - I need to allocate space for the returned data - a
pointer to nowt wont work (embarrassed)
 

Re:Determining size of a physical device

"Paul" < XXXX@XXXXX.COM >wrote in message
Quote
I'll continue this on this thread as I started here :)

I have implemnted your suggestions but I get an "invalid access to memory
location" error from GetLastError when the code is run, my code is
I see by your follow up that you solved this problem by allocating the
memory; but I'll comment on a few things I see anyways:
Quote
fp = CreateFile("\\\\.\\PhysicalDrive0", GENERIC_READ || GENERIC_WRITE,
FILE_SHARE_READ || FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_FLAG_RANDOM_ACCESS || FILE_FLAG_NO_BUFFERING,
NULL);
Like Remy mentioned, make sure you use "|" and not "||". | is bitwise-OR,
that is what you want. || is logical-OR, that is *not* what you want. The ||
operator evaluates to 1 if either of it's operands are non-zero, and 0
otherwise -- this isn't appropriate here. Use | to OR the bits of the flags
together.
Quote
PDISK_GEOMETRY_EX pdg;
[snip]
if(DeviceIoControl(fp,IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, NULL, 0,
pdg, sizeof(*pdg), &sz, NULL)!=0)
FileSize = pdg->DiskSize.QuadPart;
[snip]
You can save yourself some headache if you just put the DISK_GEOMETRY_EX on
the stack; there is no need to dynamically allocate it. Example:
DISK_GEOMETRY_EX dg;
if (DeviceIoControl(...., &dg, sizeof(dg), ....) != 0) ...
That way, you do not need to worry about allocating or freeing the memory.
Quote
I would be interested in the SMART stuff also.
Ok, I will dig up that example and post it later today when I get home.
Jason
 

Re:Determining size of a physical device

"Jason Cipriani" < XXXX@XXXXX.COM >wrote in message
Quote
>I would be interested in the SMART stuff also.

Ok, I will dig up that example and post it later today when I get home.
I'm sorry, I did not forget! I have just been getting swamped and have not
had time to look for this code. :(
Jason
 

Re:Determining size of a physical device

"Paul" < XXXX@XXXXX.COM >wrote in message
Quote
Jason

I would be interested in the SMART stuff also.
Here is all I could find on my machine; some test code that I wrote that
opens a drive, enables SMART, and sends an ATA ID command to query a whole
bunch of information about the drive. I have added some comments to the
source files:
CSMART.h: pastebin.com/f36bcf747
CSMART.cpp: pastebin.com/f2f1285f0
main.cpp: pastebin.com/f6388d4c0
That includes a little tester program that prints info to the console. It
was a console application for VC++; I have not tried to compile it in RAD
Studio yet.
If you wanted to compute the drive size from all that info, you can
theoretically multiply the wBytesPerSector member of that ATA_ID_SECTOR
structure by ulTotalAddressableSectors. However, on my machine,
wBytesPerSector is set to 0. Also I am not sure if bytes per sector is
constant over the entire drive... I may be wrong about that. If it's 0, I
have had some success at using the sector size returned by the Window's
GetDiskFreeSpace function instead.
For example, if the sector size is 512 bytes (determined either by
wBytesPerSector or GetDiskFreeSpace) and ulTotalAddressableSectors is
195371568; then:
512 * 195,371,568 = 100,030,242,816
That's 100030242816 bytes; so in gigabytes:
100030242816 / (1024 * 1024 * 1024) = 93.16 GB
And when I check that against the physical drive size reported by the
Windows Disk Management Utility, I see that it also has the number "93.16
GB", precisely, in the little text box, and that makes me happy.
There is a more full-featured example on CodeProject here:
www.codeproject.com/KB/winsdk/Hard_drive_Information.aspx
I tried to find the original documentation I was looking at but I could not.
It's really frustrating -- I remember having a really great set of
documentation about ATA commands in front of me, that's where a lot of the
values and structures in my code snippet came from. If I find it I will post
it here (and eventually I will find it, the only reason I was doing this to
begin with was a project that I had to put on the back burner that I will
eventually take up again). Microsoft does have some documentation here,
which could be used as a starting point:
msdn2.microsoft.com/en-us/library/ms803645.aspx
Hmm, it looks like some info here, including info about the magic numbers
you have to put in the ATA command structure:
www.dewassoc.com/kbase/hard_drives/smart_technology.htm
Info on smart attribute codes is here:
en.wikipedia.org/wiki/Self-Monitoring,_Analysis,_and_Reporting_Technology
I am sorry I could not be more clear. Also I apologize for not knowing where
the documentation I was referring to was located, I really wish I could
remember. In the sample code I posted, the CSMART class doesn't actually do
anything, but after the constructor is called the drive is open and smart is
enabled so you could theoretically start issuing other smart commands and
reading drive attributes.
In any case, IOCTL_DISK_GET_DRIVE_GEOMETRY_EX is much more straightforward,
especially if you are not trying to issue any other SMART commands.
Hope that is at least somewhat informative, and sorry about the long delay,
Jason
 

Re:Determining size of a physical device

"Jason Cipriani" < XXXX@XXXXX.COM >wrote in message
Quote
Microsoft does have some documentation here, which could be used as a
starting point:

msdn2.microsoft.com/en-us/library/ms803645.aspx

Hmm, it looks like some info here, including info about the magic numbers
you have to put in the ATA command structure:

www.dewassoc.com/kbase/hard_drives/smart_technology.htm

Info on smart attribute codes is here:

en.wikipedia.org/wiki/Self-Monitoring,_Analysis,_and_Reporting_Technology
Also relevant windows headers here:
www.krugle.org/examples/p-nmzNCge1P7Dv9bcA/ntdddisk.h
And you can see all the things you can play with.
 

Re:Determining size of a physical device

"Jason Cipriani" < XXXX@XXXXX.COM >wrote in message
Quote
I am sorry I could not be more clear. Also I apologize for not knowing
where the documentation I was referring to was located, I really wish I
could remember.
Ah, here. This is not what I originally looked at but it does describe a
lot:
www.codeguru.com/forum/archive/index.php/t-250315.html
Ignore everything in that thread except for the very last post. You will
only get confused if you read the rest of the posts -- like most
codeguru.com threads, this one is filled by a bunch of people that have no
idea what they are talking about. Fortunately, here, the original poster
came back and posted a valid solution with a good explanation.
Combine that with the windows header I just linked to (the smart stuff is at
the end), and that should give you all the info you need to figure out what
is going on -- in addition to the sample code I posted.
Jason