How can I tell whether a file is on a removable drive, a fixed drive, or a remote drive?


With the introduction of junctions, symbolic links, and volume mount points, it is no longer the case that a drive letter corresponds to a drive. You can mount multiple drives into a single drive letter, you can have drives with no drive letter, you can have symbolic links and junctions that graft directory trees into each other in pecular ways, possibly resulting in infinitely recursive directory trees.

You can ask the kernel to dig through the whole mess and provide the volume root for a path. You can then use this volume root for other volume queries.

Remember, Little Programs take shortcuts so as to focus on the algorithm. They do little to no boundary checking.

#include <windows.h>
#include <stdio.h>

int _wmain(int argc, wchar_t** argv)
{
    wchar_t buffer[1024];
    if (GetVolumePathNameW(argv[1], buffer, 1024)) {
        printf("path = %ls, type = %d\n", buffer, GetDriveType(buffer));
    } else {
        printf("failed %d\n", GetLastError());
    }
    return 0;
}

The program takes the path from the command line and first asks the kernel to identify the volume path name for the thing the path refers to. This will navigate through all the mount points, junctions, soft links, you name it, and tell you which volume is responsible for that path.

That volume root can then be passed to the Get­Drive­Type function in order to identify what kind of volume it is.

More generally, you can pass the volume path to Get­Volume­Information in order to obtain information about the volume.

Note that this tells you the information as far as the volume manager is concerned, but there are other layers of weirdness that come into play. For example, you may have a local virtual drive that was mounted from a VHD stored on a network server, or a local virtual drive that is mounted from an iSCSI drive. These report themselves as local even though the physical storage is remote. Conversely, you can use the loopback adapter to connect to the local machine (\\127.0.0.1\sharename), and it will report as remote even though it is physically local.

Comments (7)
  1. Ivo says:

    How does GetVolumePathName deal with relative paths? The docs say "If either a relative directory or a file is passed without a volume qualifier, the function returns the drive letter of the boot volume.". My understanding of this statement is that I would get "C:\" for all relative paths. Yet in practice the function returned the correct drive letter - D:, E: - for relative paths.
    Is the documentation wrong?

    I wanted to use GetVolumePathName to predict if MoveFileEx would move a file instead of copying it, but the uncertainty of the documentation turned me to look for other solutions.

    1. I would play it safe and use GetFullPathName to convert the relative path to absolute.

      1. Ivo says:

        Understood, thanks!

      2. skSdnW says:

        GetFullPathName eats trailing whitespace (and who knows what else) so you might have to restore the filename if you are using lstrcmpi against a string that has not been tampered with...

  2. cheong00 says:

    It's reported on MSDN forum that USB drives, especially those has Win8 compatibility logo, will not be displayed as removable (displayed with same icon as harddisk and no "Eject" option in context menu) in Explorer.

    Would this function be able to distinguish those drives?

    1. cheong00 says:

      I'll add that those askers did not specify which system they're on. So it's possible that those people were having this problem in WinXP/Vista/7 instead of Win8 or later.

    2. I have a USB drive like that -- I got it at the Build conference a few years ago -- and GetDriveType returns DRIVE_FIXED for it. That makes sense, since it appears as a hard drive in the disk manager tool, and I presume that Explorer calls GetDriveType as part of deciding how to display the drive.

Comments are closed.

Skip to main content