Volume to physical drive - c++

QueryDosDevice(L"E:", DeviceName, MAX_PATH);
(E: is a SD card)
DeviceName is "\Device\HarddiskVolume3"
How do I "convert" it to something like "\\.\PHYSICALDRIVE1"

Volumes are made up of one or more partitions, which reside on disks. So, E: doesn't necessarily map to a single disk in the system (think software RAID).
The way you map volumes to the PhysicalDrive names in Win32 is to first open the volume and then send IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS. This will give you a structure that has one DISK_EXTENT entry for every partition that the volume spans:
typedef struct _VOLUME_DISK_EXTENTS {
DWORD NumberOfDiskExtents;
DISK_EXTENT Extents[ANYSIZE_ARRAY];
} VOLUME_DISK_EXTENTS, *PVOLUME_DISK_EXTENTS;
The extents have a disk number in them:
typedef struct _DISK_EXTENT {
DWORD DiskNumber;
LARGE_INTEGER StartingOffset;
LARGE_INTEGER ExtentLength;
} DISK_EXTENT, *PDISK_EXTENT;
The DiskNumber is what goes into the PhsyicalDriveX link, so you can just sprintf that number with "\\.\PhysicalDrive%d"
-scott

Since you're using WMI anyway, start with Win32_LogicalDiskToPartition. On the Win32_LogicalDisk side, the Caption will be the drive letter. Then use Win32_DiskDriveToDiskPartition to see what physical drive holds that partition.

Related

How to have a unique ID for all files in all disks, using WinApi / USN / MasterFileTable?

I'm using the NTFS MasterFileTable / USN journal of a few disk/partitions (C:, D:, E:, F:, etc), and I'd like to use a unique ID for each file/directory.
While I'm reading the USN_RECORD (also called PUSN_RECORD), there is this int64:
DWORDLONG FileReferenceNumber;
that is a unique file/directory identifier, unique at least in the current partition.
But there could be collisions:
a file in C: could have FileReferenceNumber 1932847
another file in D: could have FileReferenceNumber 1932847 too!
I'd like to avoid having to use such a big thing as an int128 (that would be the 64 bits of FileReferenceNumber + 5 bits for the drive letter C:, D:, E:, ..., Z:).
I also would like to avoid having to use a pair (char DriveLetter, DWORDLONG FileReferenceNumber) to identify a file in the computer.
How to use a 64-bit int to code FileReferenceNumber + drive letter?
Is it possible because FileReferenceNumber has a few free unused bits?
If not, how would you handle this?
You must use a pair of FileReferenceNumber/FileID and "volume something". You can mount a volume in a folder so you cannot really use the drive letter.
Ideally "volume something" is the volume GUID path but you can use the volume serial number if size is important. Note: Not all volumes have a GUID.
For NTFS you can get it from GetFileInformationByHandle and build a 32-bit+64-bit pair. For ReFS you need GetFileInformationByHandleEx and build a 64-bit+128-bit pair.

Get the space of Secondary hard disk - c++

With the below link I am able to get the hard disk space.
Get Hard Disk Space
But if I connect a secondary hard disk it's not showing the details of it.
How can I loop the number of hard disks and retrieve their spaces?
I would like to get that in a loop sector. Get hard disk count and loop for drives in harddisk1 and then loop for drives in harddisk2 like that.
Use Windows API's GetLogicalDriveStrings function.
std::vector< std::basic_string<TCHAR> > drives;
TCHAR szBuffer[1024];
::GetLogicalDriveStrings(1024, szBuffer);
TCHAR *pCurrentDrive = szBuffer;
while (*pCurrentDrive)
{
drives.push_back( pCurrentDrive );
pCurrentDrive = &pCurrentDrive[_tcslen(pCurrentDrive) + 1];
}
Then call GetDiskFreeSpaceEx for every element in the drives vector.
You could also use the GetLogicalDrives function instead, which returns the drives as a bit mask. However, I think GetLogicalDriveStrings is simpler in this case, because it returns the drives as strings which you can pass to GetDiskFreeSpaceEx directly.
How about:
for (char drive = 'a'; drive <= 'z'; drive++)
{
// Get for amount for `drive`
}
And for those who are wondering... Yes this is very naive and probably time-consuming.

GetLogicalDrives plus additional information C++

I need help with one of my programs that pulls out available drives on a system and prints various information about the drives. I am using VC++ and am fairly new to C++ and need some high level inputs or example code from experienced programmers.
Here is my current source code:
#include "stdafx.h"
#include Windows.h
#include stdio.h
#include iostream
using namespace std;
int main()
{
// Initial Dummy drive
WCHAR myDrives[] = L" A";
// Get the logical drive bitmask (1st drive at bit position 0, 2nd drive at bit position 1... so on)
DWORD myDrivesBitMask = GetLogicalDrives();
// Verifying the returned drive mask
if(myDrivesBitMask == 0)
wprintf(L"GetLogicalDrives() failed with error code: %d\n", GetLastError());
else {
wprintf(L"This machine has the following logical drives:\n");
while(myDrivesBitMask) {
// Use the bitwise AND with 1 to identify
// whether there is a drive present or not.
if(myDrivesBitMask & 1) {
// Printing out the available drives
wprintf(L"drive %s\n", myDrives);
}
// increment counter for the next available drive.
myDrives[1]++;
// shift the bitmask binary right
myDrivesBitMask >>= 1;
}
wprintf(L"\n");
}
system("pause");
}
`
-Here is the output-
This machine has the following logical drives:
drive C
drive D
drive E
drive F
drive G
drive H
drive I
I need to output additional information about each drive (perhaps an example will tell the story in a shorter amount of time):
Drive – C:\
Drive Type: Fixed
Drive Ready Status: True
Volume Label: Boot Drive
File System Type : NTFS
Free Space: 30021926912
Total Drive Size: 240055742464
Drive – D:\
Drive Type: Fixed
Drive Ready Status: True
Volume Label: Application Data
File System Type : NTFS
Free Space: 42462507008
Total Drive Size: 240054693888
Which methods, libs api, etc. can I use to pull out drive type, drive status, volume label, file system type, free space, and total drive size?
*Side note, I noticed a defect with my pre-processor directives, specifically within the standard I/O header files. I know that is not the recommended way using printf and cout is type safe and the proper route to go but I couldn't figure out how to format output in cout as you would do in wprintf(L"drive %s\n", myDrives);.... so how would you do this with cout??
Thanks in advance.
You want to look at functions such as GetVolumeInformation to retrieve file system information such as free space and volume name.
GetDriveType will give you some basic information about the drive type, but USB thumb sticks and flash readers can give surprising results.
I'm not sure what you mean by "ready status". If you mean whether there is a valid volume in the drive, then you can try CreateFile with a path of "\\.\C:" to try and open the volume. If it fails then there is no volume (disk) present. This will be of use for SD card readers. To do this without an error dialog appearing you will need to call SetErrorMode(SEM_NOOPENFILEERRORBOX) first.
To check whether a drive is ready you may also use GetDiskFreeSpaceEx. If this fails, the drive is not ready/usable.
Here is some example code: http://pinvoke.net/default.aspx/coredll/GetDiskFreeSpaceEx.html

appending to a memory-mapped file

I'm constantly appending to a file of stock quotes (ints, longs, doubles, etc.). I have this file mapped into memory with mmap.
What's the most efficient way to make newly appended data available as part of the memory mapping?
I understand that I can open the file again (new file descriptor) and then mmap it to get the new data but that seems to be inefficient. Another approach that has been suggested to me is to pre-allocate the file in 1mb chunks, write to a specific position until reaching the end then ftruncate the file to +1mb.
Are there other approaches?
Doest Boost help with this?
Boost.IOStreams has fixed-size only memory mapped files, so it won't help with your specific problem. Linux has an interface mremap which works as follows:
void *new_mapping = mremap(mapping, size, size + GROWTH, MREMAP_MAYMOVE);
if (new_mapping == MAP_FAILED)
// handle error
mapping = new_mapping;
This is non-portable, however (and poorly documented). Mac OS X seems not to have mremap.
In any case, you don't need to reopen the file, just munmap it and mmap it again:
void *append(int fd, char const *data, size_t nbytes, void *map, size_t &len)
{
// TODO: check for errors here!
ssize_t written = write(fd, data, nbytes);
munmap(map, len);
len += written;
return mmap(NULL, len, PROT_READ, 0, fd, 0);
}
A pre-allocation scheme may be very useful here. Be sure to keep track of the file's actual length and truncate it once more before closing.
I know the answer has already been accepted but maybe it will help someone else if I provide my answer. Allocate a large file ahead of time, say 10 GiB in size. Create three of these files ahead of time, I call them volumes. Keep track of your last known location somewhere like in the header, another file, etc. and then keep appending from that point. If you reach the maximum size of the file and run out of room switch to the next volume. If there are no more volumes, create another volume. Note that you would probably do this a few volumes ahead to make sure not to block your appends waiting for a new volume to be created. That's how we implement it where I work for storing continuous incoming video/audio in a DVR system for surveillance. We don't waste space to store file names for video clips which is why we don't use a real file system and instead we go flat file and we just track offsets, frame information (fps, frame type, width/height, etc), time recorded and camera channel. For you storage space is cheap for the kind of work you are doing, whereas your time is invaluable. So, grab as much as you want to ahead of time. You're basically implementing your own file system optimized for your needs. The needs that general-use file systems supply aren't the same needs that we need in other fields.
Looking at man page for mremap it should be possible.
My 5cents, but they are more C specific.
Make normal file, but mmap huge size - e.g file is say 100K, but mmap 1GB or more. Then you can safely access everything up to file size. Access over file size will result in error.
If you are on 32bit OS, just dont make mmap too big, because it will eat your address space.
If you're using boost/iostreams/device/mapped_file.hpp on windows:
boost::filesystem::resize_file throws an exception if a reading mapping object is open, due to lack of sharing privileges.
Instead, use windows-api to resize the file on the disc, and the reading mapped_files can still be open.
bool resize_file_wapi(string path, __int64 new_file_size) //boost::uintmax_t size
{
HANDLE handle = CreateFile(path.c_str(), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL, 0);
LARGE_INTEGER sz;
sz.QuadPart = new_file_size;
return handle != INVALID_HANDLE_VALUE
&& ::SetFilePointerEx(handle, sz, 0, FILE_BEGIN)
&& ::SetEndOfFile(handle)
&& ::CloseHandle(handle);
}

GetDiskFreeSpaceEx with compressed disk

I want to get the free space on a compressed disk to show it to a end user. I'm using C++, MFC on Windows 2000 and later. The Windows API offers the GetDiskFreeSpaceEx() function.
However, this function seems to return the "uncompressed" sized of the data. This cause me some problem.
For example :
- Disk size is 100 GB
- Data size is 90 GB
- Compressed data size is 80 GB
The user will see that the disk is 90% full, but in reality, it is only 80% full.
EDIT
As Gleb pointed out, the function is returning the good information.
So here is the new question : is there a way to get both the compressed size and the uncompressed one?
I think you would have to map over all files, query with GetFileSize() and GetCompressedFileSize() and sum them up. Use GetFileAttributes() to know if a file is compressed or not, in case only parts of the whole volume is compressed, which might certainly be the case.
Hum, so that's not a trivial
operation. I suppose I must implement
some mechanism to avoid querying all
files size all the time. I mean ... if
I have a 800GB hard drive, it could
take some very long time to get all
file size.
True.
Perhaps start off by a full scan (application startup) and populate your custom data structure, e.g. a hash/map from file name to file data struct/class, then poll the drive with FindFirstChangeNotification() and update your internal structure accordingly.
You might also want to read about "Change Journals". I have never used them myself so don't know how they work, but might be worth checking out.
The function returns the amount of free space correctly. It can be demonstrated by using this simple program.
#include <stdio.h>
#include <windows.h>
void main() {
ULARGE_INTEGER p1, p2, p3;
GetDiskFreeSpaceEx(".", &p1, &p2, &p3);
printf("%llu %llu %llu\n", p1, p2, p3);
}
After compressing a previously uncompressed directory the free space grows.
So what are you talking about?