Hello all,
Am in the process of writing additional automated user-mode tests for a fs filter driver and am now exercising opens made with the FILE_OPEN_BY_FILE_ID flag.
Using the following code (see below) I can get an id and use it to open the appropriate file (which does exist) when the drive is local (e.g. good old C:) but…
when the drive is a mapped network drive (mapped to a very generously permissioned share) the call to NtCreateFile returns STATUS_NOT_SUPPORTED, whether or not the driver being tested is running.
So: do network redirectors (some or all) really not support FILE_OPEN_BY_FILE_ID, or… how might I change my code so that the call does succeed?
Any advice appreciated (feel free to point and laugh, we all have to learn somehow :D). I have searched the archives but if there is answer I haven’t found, of course please just post a link.
FYI both the machine running the test progs and the one with the share are XP SP2 boxes - although eventually I have to get the stuff working for sp0 and indeed w2k.
regards MH
BOOL QueryFileId(std::wstring& fullName, LARGE_INTEGER * id)
{
if( fullName.length() > MAX_PATH )
{
SetLastError(RtlNtStatusToDosError(STATUS_NAME_TOO_LONG));
return FALSE;
}
WCHAR drive[MAX_PATH];
WCHAR dir[MAX_PATH];
WCHAR name[MAX_PATH];
WCHAR ext[MAX_PATH];
_wsplitpath( fullName.c_str(), drive, dir, name, ext );
drive[2] = L’\‘;
drive[3] = L’\0’;
CHandle hDir(CreateFileW( drive,
GENERIC_READ,FILE_SHARE_READ|FILE_SHARE_WRITE,0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL |
FILE_FLAG_BACKUP_SEMANTICS , 0 ));
if(hDir == INVALID_HANDLE_VALUE)
{
DWORD dwErr = GetLastError();
return FALSE;
}
std::wstring fileName(name);
fileName += ext;
char buffer[1024];
IO_STATUS_BLOCK iosb;
UNICODE_STRING ucName = { (USHORT) 2 * fileName.length(), (USHORT) 2 * fileName.length(), (PWSTR)
fileName.c_str() };
NTSTATUS status = NtQueryDirectoryFile(hDir, NULL, NULL, NULL, &iosb, buffer, sizeof(buffer),
(FILE_INFORMATION_CLASS) FileIdBothDirectoryInformation, TRUE, &ucName, TRUE);
if( status != 0 )
{
SetLastError(RtlNtStatusToDosError(status));
return FALSE;
}
PFILE_ID_BOTH_DIR_INFORMATION info = (PFILE_ID_BOTH_DIR_INFORMATION) &buffer[0];
id->QuadPart = info->FileId.QuadPart;
return TRUE;
}
// Note about calling code: normally QueryFileId used to get id and lenID is 8
HANDLE OpenFileById(std::wstring& drive, void * id, DWORD access, DWORD share, unsigned lenID)
{
// open the drive as a volume
std::wstring driveString=L"\\.\";
driveString+=drive;
// note does not appear to make any difference whether drivestring is z:\ (drive + backslash for its root
dir)
// or \.\z: - either way we get a handle but it makes no difference to the resulting NtCreateFile call
CHandle hDrive( CreateFileW( driveString.c_str(), GENERIC_READ /*| GENERIC_WRITE*/,
FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0 ) );
if(hDrive == INVALID_HANDLE_VALUE)
{
DWORD dwErr = GetLastError();
return hDrive;
}
UNICODE_STRING ucName = { lenID, lenID, (PWSTR) id };
OBJECT_ATTRIBUTES oa;
InitializeObjectAttributes (&oa, &ucName, OBJ_CASE_INSENSITIVE, hDrive, NULL);
HANDLE hFile;
IO_STATUS_BLOCK iosb;
NTSTATUS status = NtCreateFile(&hFile, access,
&oa, &iosb, NULL, FILE_ATTRIBUTE_NORMAL, share,
FILE_OPEN,
FILE_OPEN_BY_FILE_ID|FILE_NON_DIRECTORY_FILE, NULL, 0);
if(status) // oh dear
{
if (STATUS_NOT_SUPPORTED == status)
{
std::string err ("not supported - if fs is not FAT why might this be? - ");
err += (char)drive[0];
std::cout << std::endl << err << std::endl;
}
SetLastError(RtlNtStatusToDosError(status));
return INVALID_HANDLE_VALUE;
}
// check we can read the name back from it (which should be possible save those test cases where we have
// been changing traverse permissions etc or we asked for access that does not allow this)
if (access & GENERIC_READ)
{
char buffer[1000]; // don’t do this in production code of course
NTSTATUS statusQuery = NtQueryInformationFile (hFile, &iosb, buffer, sizeof(buffer),
FileNameInformation);
PFILE_NAME_INFORMATION info = (PFILE_NAME_INFORMATION) buffer;
// inspect filename in debugger… todo: add code to check value, but for now our eyes will do
}
return hFile;
}