I am perplexed by the behavior of FSCTL_DISMOUNT_VOLUME. The first time I use it to dismount an NTFS volume on my Win2000 system (assuming the system has just recently been rebooted), I receive a user mode error code of 21, ERROR_NOT_READY, which is “The device is not ready.” This comes from the kernel mode error code of 0xC000026E, STATUS_VOLUME_DISMOUNTED, for status of the FSCTL_DISMOUNT_VOLUME IRP. After this fails once, all subsequent calls to FSCTL_DISMOUNT_VOLUME for that volume succeed. Why does this first call to FSCTL_DISMOUNT_VOLUME for each volume fail? The volume is mounted and accessible, but fails to dismount.
Here is what I have tried…
Upon booting my system, I run a simple utility I created, DismountVolume.exe (see code below), to dismount a volume. All this utility does is open a handle to a volume based on its volume GUID, locks the volume, dismounts the volume, unlocks the volume, then closes the handle to it. The first execution of this utility on a given volume fails, in spite of I/O to the file system on the volume prior to running it. Each subsequent execution completes successfully (provided there are no open file handles).
If anyone knows why the FSCTL_DISMOUNT_VOLUME fails the first time around, please let me know.
Kevin
//
// DismountTest.cpp
//
#include <windows.h>
#include <iostream.h>
#define SUCCESS 0
#define CANNOT_GET_VOLUME_HANDLE 1
#define VOLUME_LOCK_FAIL 2
#define DISMOUNT_VOLUME_FAIL 3
#define VOLUME_NAME_INVALID 4
#define VOLUME_NOT_FOUND 5
#define MaxNameStrSize 256
int DismountVolume( char* VolumeId );
int main(int argc, char* argv)
{
if( argc != 3 )
{
cerr << “\nError – invalid parameters\n\n”;
cerr << “Usage:\n”
" UnmountTest.exe \n"
“\n”
" Ex: UnmountTest.exe -l VolumeX\n"
“\n”
" Meaning: Unmount the volume with the lable "VolumeX"\n"
“\n”
" Flages: -i unmounts the volume with the unique volume id specified\n"
" volume id must be in the form \\.\Volume{12345678-1234-1234-1234-123456789ABC}\n"
" -d unmounts the volume with the drive letter specified\n"
" driver letter must be a single letter between A and Z inclusive\n"
" -l unmounts the volume with the lable specified\n"
" volume lable must be at least one character long\n";
return -1;
}
char tempString[MaxNameStrSize];
strncpy( tempString, argv[2], 11 );
tempString[11] = ‘\0’;
if( strcmp( argv[1], “-i” ) == 0 &&
strlen( argv[2] ) == 48 &&
strcmp( tempString, “\\.\Volume{” ) == 0
)
{
// Make sure that if “-i” is specified as the flag that
// the volume id parameter is long enough and
// the volume id starts with “\.\Volume{”
}
else if( strcmp( argv[1], “-d” ) == 0 &&
strlen( argv[2] ) == 1 &&
strcmp( argv[2], “A” ) >= 0 &&
strcmp( argv[2], “Z” ) <= 0
)
{
// Make sure that if “-d” is specified as the flag that
// the volume drive letter is only one characte long
// and that it is between “A” and “Z” inclusive
}
else if( strcmp( argv[1], “-l” ) == 0 &&
strlen( argv[2] ) >= 1
)
{
// Make sure that if “-l” is specified as the flag that
// the volume name is at least one characte long
}
else
{
cerr << “\nError – invalid parameters\n\n”;
cerr << “Usage:\n”
" UnmountTest.exe \n"
“\n”
" Ex: UnmountTest.exe -l VolumeX\n"
“\n”
" Meaning: Unmount the volume with the lable "VolumeX"\n"
“\n”
" Flages: -i unmounts the volume with the unique volume id specified\n"
" volume id must be in the form \\.\Volume{12345678-1234-1234-1234-123456789ABC}\n"
" -d unmounts the volume with the drive letter specified\n"
" driver letter must be a single letter between A and Z inclusive\n"
" -l unmounts the volume with the lable specified\n"
" volume lable must be at least one character long\n";
return -1;
}
if( strcmp( argv[1], “-i” ) == 0 )
{
int returnValue = DismountVolume( argv[2] );
switch( returnValue )
{
case SUCCESS:
{
cout << “SUCCESS”;
cout << “\n”;
return returnValue;
break;
}
case CANNOT_GET_VOLUME_HANDLE:
{
cout << “CANNOT_GET_VOLUME_HANDLE”;
cout << “\n”;
return returnValue;
break;
}
case VOLUME_LOCK_FAIL:
{
cout << “VOLUME_LOCK_FAIL”;
cout << “\n”;
return returnValue;
break;
}
case DISMOUNT_VOLUME_FAIL:
{
cout << “DISMOUNT_VOLUME_FAIL”;
cout << “\n”;
return returnValue;
break;
}
case VOLUME_NAME_INVALID:
{
cout << “VOLUME_NAME_INVALID”;
cout << “\n”;
return returnValue;
break;
}
case VOLUME_NOT_FOUND:
{
cout << “VOLUME_NOT_FOUND”;
cout << “\n”;
return returnValue;
break;
}
default:
cout << “Undefined Error”;
cout << “\n”;
return -1;
break;
}
}
else
{
cout << “Sorry, the -i flag is the only method implemented right now.\n”;
return -1;
}
}
int DismountVolume( char* VolumeId )
{
if( strlen( VolumeId ) == 0 )
{
return( VOLUME_NAME_INVALID );
}
HANDLE volumeHandle; // handle for the volume scan
BOOL lockFlag = FALSE; // lock volume results flag
BOOL dismountFlag = FALSE; // dismount volume results flag
BOOL unlockFlag = FALSE; // unlock volume results flag
DWORD returnedByteCount;
DWORD testValue;
char tempBuffer[MaxNameStrSize];
strcpy( tempBuffer, VolumeId );
volumeHandle = CreateFile( tempBuffer,
GENERIC_READ,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_ALWAYS,
0,
NULL
);
if( volumeHandle == INVALID_HANDLE_VALUE )
{
testValue = GetLastError( );
cout << "Error: " << testValue << “\n”;
cout << “\n”;
return( CANNOT_GET_VOLUME_HANDLE );
}
lockFlag = DeviceIoControl( volumeHandle,
FSCTL_LOCK_VOLUME,
NULL,
0,
NULL,
0,
&returnedByteCount,
NULL
);
if( lockFlag == FALSE )
{
testValue = GetLastError( );
cout << "Error: " << testValue << “\n”;
cout << “\n”;
CloseHandle( volumeHandle );
return( VOLUME_LOCK_FAIL );
}
dismountFlag = DeviceIoControl( volumeHandle,
FSCTL_DISMOUNT_VOLUME,
NULL,
0,
NULL,
0,
&returnedByteCount,
NULL
);
if( dismountFlag == FALSE )
{
testValue = GetLastError( );
cout << "Error: " << testValue << “\n”;
cout << “\n”;
unlockFlag = DeviceIoControl( volumeHandle, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &returnedByteCount, NULL );
CloseHandle( volumeHandle );
return( DISMOUNT_VOLUME_FAIL );
}
unlockFlag = DeviceIoControl( volumeHandle, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &returnedByteCount, NULL );
CloseHandle( volumeHandle );
return( SUCCESS );
}
—
You are currently subscribed to ntfsd as: $subst(‘Recip.EmailAddr’)
To unsubscribe send a blank email to leave-ntfsd-$subst(‘Recip.MemberIDChar’)@lists.osr.com</iostream.h></windows.h>