Obtaining information about the physical device from a given file path - windows

Suppose you have a full path to an accessible file or folder on the system. How can I get some kind of unique identifier for the physical device that the file (or folder) actually resides on?
My first attempt was to use System.IO.DriveInfo which depends on having a drive letter. But UNC paths and multiple network drives mapped to the same physical device on a server add some complications. For example these 3 paths all point to the same folder on the same device.
\\myserver\users\brian\public\music\
s:\users\brian\public\music\ (here s:\ is mapped to \\myserver\)
u:\public\users\music\ (here u:\ is mapped to \\myserver\users\brian\)
Ultimately my goal is to take these multiple paths and report the amount of used and free disk space on each device. I want to combine these 3 paths into a single item in the report and not 3 separate items.
Is there any Windows API that can help find this information given any arbitrary full path?

This win API call should get you what you need regarding disk space
GetDiskFreeSpaceEx
http://msdn.microsoft.com/en-us/library/aa364937(VS.85).aspx
Also, to determine if the three mappings all are from the same physical disk, perform a call to
GetVolumeInformation
and compare the returned volume serial numbers
http://msdn.microsoft.com/en-us/library/aa364993(VS.85).aspx

Related

how does physical disk read work with volume shadow for ntfs?

my goal is to make a backup program reading a physical disk (with NTFS partitions) while using VSS for data consistency.
i use windows api's functions CreateFile with '\.\PhysicalDriveN'
as described here (basically, it allow me to access a disk as a big file)
https://support.microsoft.com/en-us/help/100027/info-direct-drive-access-under-win32
for tests i create volume shadows with this command
wmic shadowcopy call create Volume='C:\'
this is a temporary solution, i plan on using VSS via the program itself
My question is:
how are stored Volume shadows? does it stores data that have been modified since the volume shadow or does it store modification made since the last volume shadow?
in the first case:
when i read the disk, will i get consistent data (including ntfs metadata files)?
in the other case:
can i access a volume shadow the same way i would access a disk/partition? (in order to read hidden metadata files, etc)
-im am currenctly using windows 7 but planning on using it on differents version of windows server
-i've read a lot of microsoft doc about VSS but how it work seem really unclear for me (if you answer with one please explain a bit it meaning)
-i know that Volume shadows are stored in the folder "System Volume Information" as files with names like {3808876b-c176-4e48-b7ae-04046e6cc752}
"how are stored Volume shadows? does it stores data that have been modified since the volume shadow or does it store modification made since the last volume shadow?"
A hardware or software shadow copy provider uses one of the following methods for creating a shadow copy:(Answer by msdn doc)
Complete copy This method makes a complete copy (called a "full copy"
or "clone") of the original volume at a given point in time. This copy
is read-only.
Copy-on-write This method does not copy the original volume. Instead,
it makes a differential copy by copying all changes (completed write
I/O requests) that are made to the volume after a given point in time.
Redirect-on-write This method does not copy the original volume, and
it does not make any changes to the original volume after a given
point in time. Instead, it makes a differential copy by redirecting
all changes to a different volume.
"when i read the disk, will i get consistent data (including ntfs metadata files)?"
Even if an application does not have its files open in exclusive mode, it is possible—because of the finite time needed to open, back up, and close a file—that files copied to storage media may not all reflect the same application state.
"can i access a volume shadow the same way i would access a disk/partition? (in order to read hidden metadata files, etc)"
Requester Access to Shadow Copied Data
Paths on the shadow copied volume are obtained by replacing the root
of the original path with the device object. For example, given a path
on the original volume of "C:\DATABASE*.mdb" and a VSS_SNAPSHOT_PROP
instance of snapProp, you would obtain the path on the shadow copied
volume by concatenating snapProp.m_pwszSnapshotDeviceObject, "\",
and "\DATABASE*.mdb".
So i did more test and actually Shadow Volume are made at block level not file level. it mean that by using createfile with the path
\\?\GLOBALROOT\Device\HarddiskVolumeShadowCopy1 it would work in a similar way than using createfile with the path \\.\C:
So yeah you can access a shadow copy file system, it have it own boot sector, mft, etc.

Using local shares in place of drive letters possible?

I see cautions about treating network drives as looking like lettered drive. Can you turn it on its head?
So. What are the cautions about mapping a drive to a your-choice-of-name share in the usual way. For example share name "01-D-drive". In file explorer under network (for my local machine) I now have another "neater" more logical way to access my drives (shared with appropriate permissions) that gives me ordering and naming possibilities. Cautions might be raised that the performance is not the same--is it prohibitively expensive? Another step might be to map these "local" shares to a network path so I have top level access in file explorer to the "drives" e.g. define network resource to this local path //my-local-computer/01-D-drive. Where will this break down? Here's an example:
Open share on //my-local-computer to see (and use). --note: lettered drives are still there in file explorer
my-local-computer
01-zdrive
02-any-name-any-order
03-hey-system-drive-should-not-be-shared
04-why-not?
don't want to open share (surely even more overhead??) and reference in c
//my-local-computer/01-zdrive
etc, etc and so forth. this silly editor is trashing my paragraphs--try adding a blank line
There's very little overhead in using the redirector to access local UNC shares instead of local drives. I don't think you'll see a difference in either throughput or latency.
PS: After actually testing this, there is quite a difference. Throughput is very close but latency (open file, dir scan, or recursive traversal) is much slower:
dir /s on 2012R2 file server, 20,000 dirs, 61,000 files:
local drive letter: 3 s
UNC share: 43 s

How do I map the device details such as \Device\Harddisk1\DR1 in the event log to a drive letter such as C:?

Using the event viewer, I can see that the event log has entries such as "The driver detected a controller error on \Device\Harddisk1\DR1." and "The driver detected a controller error on \Device\Harddisk1\DR7.".
Using VC++ code, I want to translate this device path (e.g. \Device\Harddisk1\DR1) to a drive letter such as C: wherever applicable (I understand that not all the devices will map to a drive letter).
Using FindFirstVolume and FindNextVolume I am able to loop through all the volumes and for each, I am using QueryDosDevice to get the device name and GetVolumePathNamesForVolumeName to get the drive letter.
The problem I am having is that when I use the above method to get the device names, I end up with device names such as "\Device\HarddiskVolume3", "\Device\HarddiskVolume2", etc.
I do get these mapped to the drive letters. However, I am not sure how these map to the device name format I see in the event log entry.
So, in summary, my question is:
How do I map the device name format "\Device\HarddiskVolume%d" to the format "\Device\Harddisk%d\DR%d" where each %d is a number.
This isn't C++ code, but two applications written in C++ show this information, at least to check your results. I don't believe the source of either application is readily available.
NirSoft's DriveLetterView matches drive letter to \Device\HarddiskVolume%d in the Drive Letter and Device Path columns.
SysInternals' WinObj matches drive letter to \Device\HarddiskVolume%d and \Device\Harddisk%d\DR%d to PhysicalDrive%d.
Updating #Dan-H's answer:
DriveLetterView
NirSoft DriveLetterView doesn't show the DRnumber, as in \Device\Harddisk1\DR1
But it does show the \Device\HarddiskVolumeN and the \PhysicalDriveN and the X:\ drive letter
The \Device\HarddiskN number and the \PhysicalDriveN number are the same.
So knowing that, you can take the \Device\HarddiskN number from \Device\HarddiskN\DRx and look at the corresponding \PhysicalDriveN in DriveLetterView and then look at the corresponding X:\ drive letter.
WinOjb
WinObj has had some improvements since 2014. It's now up to v3.10 as of 07/20/2021.
Note, have to run as administrator, otherwise it doesn't show as much info.
Also note, sorting the columns is incredibly helpful in finding information. As is the new search.
GLOBAL?? is the most useful in the left nav pane.
Sorting GLOBAL?? by column Symbolic Link Target you can map
\Device\HarddiskN\DRx
to \PhysicalDriveN
to Harddisk1Partition1
to \Device\HarddiskVolumeN
to X:\ drive letter
You can also use WinObj search to find these mappings.
The volume numbers do not match command line tool diskpart; that has its own volume numbering scheme. But the \PhysicalDriveN and HarddiskN appear to match diskpart numbering (but I'd confirm before relying on it).

How can I find information about a file from logical cluster number in NTFS/FAT32?

I am trying to defragment a single file through Windows defragmentation API ( http://msdn.microsoft.com/en-us/library/aa363911(VS.85).aspx ) but if there is no free space block large enough for my file I would like to move other parts of files to make room for it.
The linked article mentions moving parts of other files but I can't find any information about how to find out which files to move. From the free space bitmap I can find an almost large enough space and I know the logical cluster numbers surrounding it, but from this I can't find out which files are surrounding it and a handle to the files is required to do FSCTL_MOVE_FILE which moves parts of files.
Is there any way, through the API or by parsing the MFT, to find out what file a logical cluster number is part of, and what virtual cluster number in the file corresponds to the logical cluster number found through the bitmap?
The slow but compatible method is to recursively scan all directories for files, and use the FSCTL_GET_RETRIEVAL_POINTERS. Then scan the resulting VCN-LCN mapping for the cluster in question.
Another option would be to query the USN Journal of the drive to get the File Reference IDs, then use FSCT_GET_NTFS_FILE_RECORD to get the $MFT file record.
I'm currently working on a simple Defrag program (written in Java) with the aim to pack files of a directory (e.g. all files of a large game) close together to reduce loading times and loading lags.
I use a faster method to retrieve the file mappings on the NTFS or FAT32 drive.
I parse the $MFT file directly (the format has some pitfalls), or the FAT32 file allocation table along with the directories.
The trick is to open the drive (e.g. "c:") with FileCreate for fully shared GENERIC read. The resulting handle can then be read with FileRead and FileSeek on a byte granularity. This works only in administrator mode (or elevated).
On NTFS, the $MFT might be fragmented and is a bit tricky to locate it from the boot sector info. I use the FSCTL_GET_RETRIEVAL_POINTERS on the C:\$MFT file to get its clusters.
On FAT32, one must parse the boot sector to locate the FAT table and the cluster containing root directory file. You need to parse the directory entries and recursively locate the clusters of the sub-directories.
There is no O(1) way of mapping from block # to file. You need to walk the entire MFT looking for files that contain that block.
Of course, in a live system, once you've read that data it's out-of-date and you must be prepared for failures in the move data FSCTL.

Find which drive corresponds to which USB mass storage device in WinXP

I have several USB drives connected to a WinXP SP3 computer, and I need to tell them apart programatically - I need to find which drive letter corresponds to which device (in this case, one device ~ one volume). I can get their Volume IDs and drive letters using mountvol, looking something like this:
C:\WINDOWS\> mountvol
\\?\Volume{bdb681b2-1ddf-11dd-bf71-806d6172696f}\
C:\
\\?\Volume{6a8784f8-7406-11dd-a8c3-001e8c829b67}\
A:\
Also, using devcon or the Device Manager, I can see the device IDs:
C:\WINDOWS\> devcon resources *STOR*
STORAGE\REMOVABLEMEDIA\7&190C24E5&0&RM
Name: Generic volume
STORAGE\VOLUME\1&30A96598&0&SIGNATURED84ED84EOFFSET7E00LENGTH2543150400
Name: Generic volume
USBSTOR\DISK&VEN_KINGSTON&PROD_DATATRAVELER2.0&REV_1.00\0803240752536&0
Name: Kingston DataTraveler2.0 USB Device
However, I haven't found a way to link the device ID and the volume ID/letter, like the "Safely remove hardware" dialog does (therefore I assume it's possible):
(source: piskvor.org)
As you may see, these are the same devices that I see in devcon and the same volume that mountvol sees; but so far I haven't found the link between them.
I've found some related questions, but those seem to use the approach "whatever you find first is your USB device", which is not very useful in my case, since there will be several similar devices (same vendor, often same product type) connected.
Edit:
#MSalters' answer looks promising: On XP, HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices has REG_BINARY values \DosDevices\x: (where x is [A-Z]); the comment is (UTF-16) name of the correct device (e.g.
\DosDevices\A: = "\??\STORAGE#RemovableMedia#7&190c24e5&0&RM#{53f5630d-b6bf-11d0-94f2-00a0c91efb8b}\", which corresponds to
STORAGE\REMOVABLEMEDIA\7&190C24E5&0&RM seen above in the device list).
Will see if that's the way to go.
It's a non-trivial question. There is no official API for it, as far as I can tell. So, you need an undocumented API: the registry. HKEY_LOCAL_MACHINE\SYSTEM\MountedDevices contains entries for both drive letters and volume IDs. If you look at the actual data, you'll find that it identifies the drive. Look at the binary data as a Unicode string. It will point you to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\ENUM\. However, XP and Vista differ in exactly what subkeys are referenced there, and how. (Vista is easier, so try that first).
There is an official API to do this. See this sample:
http://www.codeproject.com/KB/system/RemoveDriveByLetter.aspx
The principle is that each storage volume on Windows is assigned a global number. First, you ask your drive for its number (by opening "\X:" and sending a IOCTL_STORAGE_GET_DEVICE_NUMBER request). Second, you go over all disk devices and ask each one for its number (by opening it, through a different path, so you can't just string-compare).
Once you find a disk device carrying the same number as you queried your drive, you know you have a winner.

Resources