FILE_OPEN_BY_FILE_ID getting STATUS_NOT_SUPPORTED for file on mapped network drive

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;
}

What is the underlying file system, File_ID’s are not supported on FAT.

Regards,

Matt
----- Original Message -----
From:
To: “Windows File Systems Devs Interest List”
Sent: Monday, January 14, 2008 6:20 AM
Subject: [ntfsd] FILE_OPEN_BY_FILE_ID getting STATUS_NOT_SUPPORTED for file
on mapped network drive

> 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;
> }
>
>
> —
> NTFSD is sponsored by OSR
>
> For our schedule debugging and file system seminars
> (including our new fs mini-filter seminar) visit:
> http://www.osr.com/seminars
>
> You are currently subscribed to ntfsd as: matt-martin@tx.rr.com
> To unsubscribe send a blank email to xxxxx@lists.osr.com
>

LOL yes the file system of the volume containing the share on the remote machine is NTFS. (As - not that it matters, I hope - is the system volume on the machine running the tests).
:smiley:

Ms. Hamilton,

Laugh at my response all you like, people do forget little things like
this.

Good luck Ma’am,

Matt

----- Original Message -----
From:
To: “Windows File Systems Devs Interest List”
Sent: Monday, January 14, 2008 8:36 AM
Subject: RE:[ntfsd] FILE_OPEN_BY_FILE_ID getting STATUS_NOT_SUPPORTED for
file on mapped network drive

> LOL yes the file system of the volume containing the share on the remote
> machine is NTFS. (As - not that it matters, I hope - is the system volume
> on the machine running the tests).
> :smiley:
>
> —
> NTFSD is sponsored by OSR
>
> For our schedule debugging and file system seminars
> (including our new fs mini-filter seminar) visit:
> http://www.osr.com/seminars
>
> You are currently subscribed to ntfsd as: matt-martin@tx.rr.com
> To unsubscribe send a blank email to xxxxx@lists.osr.com
>

xxxxx@googlemail.com wrote:

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?

AFAIK, network redirectors do NOT support open by ID,

have a nice day,

Sandor LUKACS

Matt - they sure do forget things like that :slight_smile:
Mr Lukacs - oh dear, do they not? Shame they still *return* a file id in cases where they are not going to support using that same id to open the file later. Bah. Never mind, eh? Casting the first stone etc…

xxxxx@googlemail.com wrote:

Matt - they sure do forget things like that :slight_smile:
Mr Lukacs - oh dear, do they not? Shame they still *return* a file id in cases where they are not going to support using that same id to open the file later. Bah. Never mind, eh? Casting the first stone etc…
You can try for example to access a file that resides on a NTFS disk
from a network, and then query it’s file ID. You can then compare that
value with the value you would get on the very same file accessed
locally, on the system / volume where it resides. Are those two values
ALWAYS the same?

AFAIK, a NTFS file ID is made up from a MFT index (48 lower bits) and a
sequence number (16 upper bits) that protects against ID reuse. So, the
IDs are per-volume. That means, they can’t really have a global meaning,
across networks etc… In conclusion, the redirectors are the only one
who could provide unique IDs and so on. And, AFAIK they don’t do, or at
least, they don’t do it in a persistent way (if I’m wrong, please
correct me). I guess, that because they can’t provide it in a persistent
way, they don’t allow also open-by-ID (but, it might turn out, that the
reasons or facts are different ;-).

have a nice day,

Sandor LUKACS