Windows System Software -- Consulting, Training, Development -- Unique Expertise, Guaranteed Results

Before Posting... Please check out the Community Guidelines in the
Announcements and Administration Category.

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

Comments

  • How are you printing the string in the IRP_MJ_CREATE path?

    -scott
    OSR
    @OSRDrivers

    -scott
    OSR

  • 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 <xxxxx@lundman.net>
    Sent: Saturday, December 30, 2017 8:09 PM
    To: Windows File Systems Devs Interest List <xxxxx@lists.osr.com>
    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://na01.safelinks.protection.outlook.com/?url=http://www.osr.com/seminars&amp;data=02|01|[email protected]|cb16a9e3af134121c21b08d5500441cf|72f988bf86f141af91ab2d7cd011db47|1|0|636502901795797335&amp;sdata=nkiXsCZbtazbWrsMY78yC2Yr311oT6KSi4zBCxdWooQ=&amp;reserved=0&gt;

    To unsubscribe, visit the List Server section of OSR Online at <https://na01.safelinks.protection.outlook.com/?url=http://www.osronline.com/page.cfm?name=ListServer&amp;data=02|01|[email protected]|cb16a9e3af134121c21b08d5500441cf|72f988bf86f141af91ab2d7cd011db47|1|0|636502901795797335&amp;sdata=D2mgWvXBHcCUsEY10NYMFOjzJ0IDdB6Oc1t1hVcpNmc=&amp;reserved=0&gt;
  • Hi,

    Thanks for your replies Craig and Scott.

    Craig Barkhouse <xxxxx@microsoft.com> 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 | <xxxxx@lundman.net>
    Unix Administrator | +81 (0)90-5578-8500
    Shibuya-ku, Tokyo | Japan
Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!