Hi,
we are working on software that is supposed to backup the in-use
clusters of a volume. Platform is W2K and XP. In order to do that, we
first try to obtain the bitmap of used clusters on the volume as
follows:
- Open the volume (CreateFile with FILE_SHARE_READ | FILE_SHARE_WRITE)
- Lock the volume (FSCTL_LOCK_VOLUME)
- Get volume bitmap (FSCTL_GET_VOLUME_BITMAP)
This works just fine for FAT but for NTFS volumes,
FSCTL_GET_VOLUME_BITMAP returns ERROR_NOT_READY. According to the docs
this “indicates that the volume is an NTFS volume, and it is not
mounted”. The native NT status for ERROR_NOT_READY is, indeed,
STATUS_VOLUME_DISMOUNTED.
How can the volume be dismounted although I never sent a
FSCTL_DISMOUNT_VOLUME? FYI, I inserted a simple ReadFile() on the volume
handle after locking it down and that succeeds, yet sending a
FSCTL_IS_VOLUME_MOUNTED in addition returns zero, indicating it’s indeed
not mounted. Does the read maybe get passed down to the RAW file system
here?
Anyway, I found that FSCTL_GET_VOLUME_BITMAP for NTFS volumes succeeds
only if either
- you don’t lock the volume at all
- or set dwShareMode in CreateFile to FILE_SHARE_READ or zero and lock it
However, this doesn’t look right. The docs say that for
FSCTL_LOCK_VOLUME, you must set dwShareMode in CreateFile to
FILE_SHARE_READ | FILE_SHARE_WRITE. The lock is mandatory for us because
we want to ensure that we are getting a consistent bitmap and nobody
else messes with the volume while we are working with it.
I’m pulling my hair out over this one. I’ve tested on W2K SP0/SP4 and XP
SP0/SP1 and it’s always the same. Anybody knows a way to make
FSCTL_GET_VOLUME_BITMAP succeed on a locked NTFS volume?
Below is the code I used for testing.
Thanks!
//======================================================================
#define UNICODE
#define _WIN32_WINNT 0x0500
#include <stdio.h>
#include <windows.h>
#include <winioctl.h>
int wmain(int argc, TCHAR *argv)
{
TCHAR szDrive[255];
BYTE Buf[2048];
HANDLE hVolume = INVALID_HANDLE_VALUE;
DWORD dwBytesReturned;
BOOL bIsLocked = FALSE;
STARTING_LCN_INPUT_BUFFER StartLcn;
__try
{
if (argc < 2)
{
printf(“Usage: Lock [driveletter]\n”);
__leave;
}
wsprintf(szDrive, L"\\.\%c:", argv[1][0]);
if (INVALID_HANDLE_VALUE == (hVolume = CreateFile(
szDrive,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL)))
{
printf(“Error %lu opening volume %ls\n”, GetLastError(), szDrive);
__leave;
}
// Lock the volume
if (!DeviceIoControl(
hVolume,
FSCTL_LOCK_VOLUME,
NULL, 0, NULL, 0,
&dwBytesReturned,
NULL))
{
printf(“Error %lu locking volume %ls\n”, GetLastError(), szDrive);
__leave;
}
bIsLocked = TRUE;
if (!DeviceIoControl(
hVolume,
FSCTL_IS_VOLUME_MOUNTED,
NULL, 0, NULL, 0,
&dwBytesReturned,
NULL
))
{
printf(“Volume %ls is no longer mounted\n”, szDrive);
}
else
{
printf(“Volume %ls is still mounted\n”, szDrive);
}
if (!ReadFile(
hVolume,
Buf, sizeof(Buf),
&dwBytesReturned, NULL))
{
printf(“Error %lu reading from volume %ls\n”, GetLastError(), szDrive);
}
StartLcn.StartingLcn.QuadPart = 0;
ZeroMemory(Buf, sizeof(Buf));
if(!DeviceIoControl(
hVolume,
FSCTL_GET_VOLUME_BITMAP,
&StartLcn, sizeof(StartLcn),
Buf, sizeof(Buf),
&dwBytesReturned,
NULL))
{
printf(“Error %lu getting cluster bitmap of volume %ls\n”, GetLastError(), szDrive);
}
}
__finally
{
if (INVALID_HANDLE_VALUE != hVolume)
{
if (bIsLocked)
DeviceIoControl(
hVolume,
FSCTL_UNLOCK_VOLUME,
NULL,
0,
NULL,
0,
&dwBytesReturned,
NULL
);
CloseHandle(hVolume);
}
}
return 0;
}
//======================================================================
Ralf.
–</winioctl.h></windows.h></stdio.h>