I hacked up one of the file.d functions to create a function that returns the first Logical Cluster Number for a regular file. I've tested it on the 2GB layout that has been defragged with the myDefrag sortByName() operation, and it works as expected. Values of 0 mean the file was small enough to fit in the MFT. The LCN numbers would be a good thing to sort by before doing accesses on entries coming from any large directory operations ... for example zip, copy, delete of directories.


enum {
        FILE_DEVICE_FILE_SYSTEM = 9,
        METHOD_NEITHER = 3,
        FILE_ANY_ACCESS = 0
}
uint CTL_CODE(uint t, uint f, uint m, uint a) {
        return (t << 16) | (a << 14) | (f << 2) | m;
}

const FSCTL_GET_RETRIEVAL_POINTERS = CTL_CODE(FILE_DEVICE_FILE_SYSTEM,28,METHOD_NEITHER,FILE_ANY_ACCESS);

/*********************************************
extern (Windows) int DeviceIoControl(void *, uint, void *, uint, void *, uint, uint *, _OVERLAPPED *);
from WinIoCtl.h in SDK
#define FSCTL_GET_RETRIEVAL_POINTERS CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 28, METHOD_NEITHER, FILE_ANY_ACCESS) // STARTING_VCN_INPUT_BUFFER, RETRIEVAL_POINTERS_BUFFER

*/
struct  RETRIEVAL_POINTERS_BUFFER{
}
ulong getStartLCN (in char[] name)
{
        int[] buffer = [ 0 ];
    version(Windows)
    {
alias TypeTuple!(GENERIC_READ, FILE_SHARE_READ, null, OPEN_EXISTING,
                                                 FILE_ATTRIBUTE_NORMAL,
                                                 HANDLE.init)
            defaults;
        auto h = useWfuncs
            ? CreateFileW(std.utf.toUTF16z(name), defaults)
            : CreateFileA(toMBSz(name), defaults);

        cenforce(h != INVALID_HANDLE_VALUE, name);
        scope(exit) cenforce(CloseHandle(h), name);

                alias long LARGE_INTEGER ;
                struct STARTING_VCN_INPUT_BUFFER {
                        LARGE_INTEGER StartingVcn;
                }
                STARTING_VCN_INPUT_BUFFER inputVcn;
                inputVcn.StartingVcn = 0;

                struct RPExtents{
                        LARGE_INTEGER NextVcn;
                        LARGE_INTEGER Lcn;
                }
                struct RETRIEVAL_POINTERS_BUFFER {
                        DWORD         ExtentCount;
                        LARGE_INTEGER StartingVcn;
                        RPExtents rpExtents[1];
                }
                RETRIEVAL_POINTERS_BUFFER rpBuf;

                DWORD numBytes;

                //expect only a partial return of one rpExtent
                 DeviceIoControl(
                                                                 h, 
FSCTL_GET_RETRIEVAL_POINTERS,
                                                                 
cast(void*)&inputVcn, inputVcn.sizeof,
                                                                 
cast(void*)&rpBuf, rpBuf.sizeof,
                                                                 &numBytes, null
                                                                 );

                return cast(ulong)rpBuf.rpExtents[0].Lcn;
    }
    else version(Posix)
        return 0; // not implemented
}

Reply via email to