Filename in directory listing..

I was hoping I could get some fresh eyes on this issue I am having. I am
using “ifstest.exe” to check if my implementation is “correct” and I get
this peculiar issue:

IRP_MJ_DIRECTORY_CONTROL, IRP_MN_QUERY_DIRECTORY
type 1 struct FILE_INFORMATION_CLASS size is 72

single: 1 restart: 0 index: 0
zfs_readdir: ‘hfhtest.dat’ -> ‘hfhtest.dat’ (namelen 22)
outsize adjusted to 92
-zfs_readdir: num 1
return information size 92

So it asked for a single dirlist, and I returned “hfhtest.dat” length
bytes 22 (wide characters 11). Dumping the binary returned:

39 25 FE 12 FileIndex 0-3
49 8D 24 51 E3 7E D3 01 CreationTime 4-11
49 8D 24 51 E3 7E D3 01 LastAccessTime 12-19
49 8D 24 51 E3 7E D3 01 LastWriteTime 20-27
49 8D 24 51 E3 7E D3 01 ChangeTime 28-35
00 00 00 00 00 00 00 00 EndOfFile 36-43
00 00 00 00 00 00 00 00 AllocationSize 44-51
80 00 00 00 FileAttributes 52-55
16 00 00 00 FileNameLength 56-59
68 00 66 00 68 00 74 00 65 00 “hfhte” 60-69
73 00 74 00 2E 00 64 00 61 00 “st.da” 70-79
74 00 74 00 fe 00 12 00 “tt” 80-87

returned string length: 0x16 = 22

struct is 72, with one wide char included. We return size 92. Bytes
added up inside struct, and struct size do not match, but most likely
about alignment, so we can most likely ignore that.

Then the next query from ifstest.exe is:

fsDispatcher: enter: major 0: minor 0: IRP_MJ_CREATE fsDeviceObject
IRP_MJ_CREATE: FileObject FFFFCE8963B4C460 name
‘\opcreatg\hfhtest.datt??’ flags 0x0

What? Why? I return exactly 22 bytes in Filename. Yes, there is garbage
after the string, due to alignment to next 8 bytes. What is the issue
here, do strings returned in singles have to be (wide) null terminated?
Nothing about that in the docs, surely the filenamelength is the full
string, and not minus the 2 chars inside the struct?

Lund

How are you printing the string in the IRP_MJ_CREATE path?

-scott
OSR
@OSRDrivers

Hi Lund,

(1) There should not be any alignment padding after the last entry being returned. In your example only 90 bytes should be returned. This is computed as FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, FileName[0] ) + FileNameLen * sizeof(WCHAR) == 68 + 22 == 90. Of course use the struct corresponding to the info class being queried; it’s not always FILE_FULL_DIR_INFORMATION.
(2) Between entries, there should be alignment padding inserted so that the next entry starts at a quadword (i.e. 8-byte) boundary.
(3) You do not have to null terminate the file name strings.

Hope this helps,
Craig (MSFT)

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of Jorgen Lundman
Sent: Saturday, December 30, 2017 8:09 PM
To: Windows File Systems Devs Interest List
Subject: [ntfsd] Filename in directory listing…

I was hoping I could get some fresh eyes on this issue I am having. I am using “ifstest.exe” to check if my implementation is “correct” and I get this peculiar issue:

IRP_MJ_DIRECTORY_CONTROL, IRP_MN_QUERY_DIRECTORY type 1 struct FILE_INFORMATION_CLASS size is 72

single: 1 restart: 0 index: 0
zfs_readdir: ‘hfhtest.dat’ -> ‘hfhtest.dat’ (namelen 22) outsize adjusted to 92
-zfs_readdir: num 1
return information size 92

So it asked for a single dirlist, and I returned “hfhtest.dat” length bytes 22 (wide characters 11). Dumping the binary returned:

39 25 FE 12 FileIndex 0-3
49 8D 24 51 E3 7E D3 01 CreationTime 4-11
49 8D 24 51 E3 7E D3 01 LastAccessTime 12-19
49 8D 24 51 E3 7E D3 01 LastWriteTime 20-27
49 8D 24 51 E3 7E D3 01 ChangeTime 28-35
00 00 00 00 00 00 00 00 EndOfFile 36-43
00 00 00 00 00 00 00 00 AllocationSize 44-51
80 00 00 00 FileAttributes 52-55
16 00 00 00 FileNameLength 56-59
68 00 66 00 68 00 74 00 65 00 “hfhte” 60-69
73 00 74 00 2E 00 64 00 61 00 “st.da” 70-79
74 00 74 00 fe 00 12 00 “tt” 80-87

returned string length: 0x16 = 22

struct is 72, with one wide char included. We return size 92. Bytes added up inside struct, and struct size do not match, but most likely about alignment, so we can most likely ignore that.

Then the next query from ifstest.exe is:

fsDispatcher: enter: major 0: minor 0: IRP_MJ_CREATE fsDeviceObject
IRP_MJ_CREATE: FileObject FFFFCE8963B4C460 name ‘\opcreatg\hfhtest.datt??’ flags 0x0

What? Why? I return exactly 22 bytes in Filename. Yes, there is garbage after the string, due to alignment to next 8 bytes. What is the issue here, do strings returned in singles have to be (wide) null terminated?
Nothing about that in the docs, surely the filenamelength is the full string, and not minus the 2 chars inside the struct?

Lund


NTFSD is sponsored by OSR

MONTHLY seminars on crash dump analysis, WDF, Windows internals and software drivers!
Details at https:

To unsubscribe, visit the List Server section of OSR Online at https:</https:></https:>

Hi,

Thanks for your replies Craig and Scott.

Craig Barkhouse wrote:
> (1) There should not be any alignment padding after the last entry being returned. In your example only 90 bytes should be returned. This is computed as FIELD_OFFSET( FILE_FULL_DIR_INFORMATION, FileName[0] ) + FileNameLen * sizeof(WCHAR) == 68 + 22 == 90. Of course use the struct corresponding to the info class being queried; it’s not always FILE_FULL_DIR_INFORMATION.

I had clearly picked up poor coding practices already, as I used
sizeof(FILE_DIRECTORY_INFORMATION) - sizeof(eodp->FileName)
to work out the size “to advance by”, but replacing it with FIELD_OFFSET()
made everything happier.

These lines are interesting:

FILE_DIRECTORY_INFORMATION *eodp;

dprintf(“type 1 struct size is %d and field_offset size %d size of Name[0]
%d\n”,
sizeof(FILE_DIRECTORY_INFORMATION),
FIELD_OFFSET(FILE_DIRECTORY_INFORMATION, FileName[0]);
sizeof(eodp->FileName));

type 1 struct size is 72 and field_offset size 64 size of Name[0] 2

So 72 - 2 is 70, some 6 bytes off. Probably the final 2-bytes in FileName
is aligned up to 8, but I will only use FIELD_OFFSET() from now on. But it
is a little alarming that “they” would use the returned-size in
“IoStatus.Information” instead of the FileNameLength. But since it is
“ifstest.exe” we’ll let it slide, as it proved a point/bug here.

zfs_readdir: ‘hfhtest.dat’ -> ‘hfhtest.dat’ (namelen 22 bytes: structsize 64)
outsize adjusted to 86
-zfs_readdir: num 1
dirlist information size 86
00 00 00 00 D8 15 36 12 52 41 BD 53 E3 7E D3 01
52 41 BD 53 E3 7E D3 01 52 41 BD 53 E3 7E D3 01
52 41 BD 53 E3 7E D3 01 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 80 00 00 00 16 00 00 00
68 00 66 00 68 00 74 00 65 00 73 00 74 00 2E 00
64 00 61 00 74 00

IRP_MJ_CREATE: FileObject FFFFCE8963000510 name ‘\opcreatg\hfhtest.dat’
flags 0x0

The best surprise so far was IRP_MJ_CREATE on an existing/new directory,
with DeleteOnClose set. I did expect that one. I look forward to finding
other surprises as I dig deeper.

Lund


Jorgen Lundman |
Unix Administrator | +81 (0)90-5578-8500
Shibuya-ku, Tokyo | Japan