-1

I've got a Windows program that scans the contents of a hard disk. I'd like to display a meaningful progress bar while it does so. Is there a quick way to get the total number of files on the disk? The number doesn't have to be exact -- an approximation within 10% or so should do.

Mark
  • 2,792
  • 2
  • 18
  • 31
  • Do you have administrator privilege? [Reading the content of the MFT](http://stackoverflow.com/a/7459109/886887) provides a much faster way of scanning the contents of the disk, and if you did that, you could implement a progress bar by keeping track of [what percentage of the MFT](http://stackoverflow.com/a/11337898/886887) you have processed. – Harry Johnston Feb 23 '17 at 00:50
  • No luck on that -- this program needs to be able to run under as wide a range of circumstances as possible. – Mark Feb 23 '17 at 00:51

1 Answers1

1

this is possible for NTFS volume. one way as Harry Johnston write. also possible some another way, also fast enough by iterating file records:

struct NTFS_RECORD_HEADER 
{
    enum {
        FILE = 'ELIF',
        INDX = 'XDNI',
        BAAD = 'DAAB',
        HOLE = 'ELOH',
        CHKD = 'DKHC'
    } Type;
    USHORT UsaOffset;
    USHORT UsaCount;
    USN Usn;
};

struct NTFS_FILE_RECORD_HEADER : public NTFS_RECORD_HEADER
{
    USHORT SequenceNumber;
    USHORT LinkCount;
    USHORT AttributesOffset;
    USHORT Flags;
    ULONG BytesInUse;
    ULONG BytesAllocated;
    ULONGLONG BaseFileRecord;
    USHORT NextAttributeNumber;

    enum{
        flgInUse = 1, flgDirectory = 2
    };
};

ULONG GetFileCount(HANDLE hVolume, PULONG FileCount)
{
    NTFS_VOLUME_DATA_BUFFER nvdb;

    ULONG cb, BytesReturned;
    if (!DeviceIoControl(hVolume, FSCTL_GET_NTFS_VOLUME_DATA, NULL, 0, &nvdb, sizeof(nvdb), &BytesReturned, NULL))
    {
        return GetLastError();
    }

    NTFS_FILE_RECORD_INPUT_BUFFER nfrib;

    cb = FIELD_OFFSET(NTFS_FILE_RECORD_OUTPUT_BUFFER, FileRecordBuffer[nvdb.BytesPerFileRecordSegment]);

    PNTFS_FILE_RECORD_OUTPUT_BUFFER pnfrob = (PNTFS_FILE_RECORD_OUTPUT_BUFFER)alloca(cb);

    union {
        PVOID FileRecordBuffer;
        NTFS_RECORD_HEADER* pnrh;
        NTFS_FILE_RECORD_HEADER* pnfrh;
    };

    FileRecordBuffer = pnfrob->FileRecordBuffer;

    // get maximum valid FileReferenceNumber
    ULONG a = 0, b = MAXLONG, N;
    do 
    {
        nfrib.FileReferenceNumber.QuadPart = N = (a + b) >> 1;

        DeviceIoControl(hVolume, FSCTL_GET_NTFS_FILE_RECORD, 
            &nfrib, sizeof nfrib, pnfrob, cb, &BytesReturned, 0) ? a = N + 1 : b = N;

    } while(a < b);

    if (!b)
    {
        return ERROR_GEN_FAILURE;
    }

    N = 0;
    nfrib.FileReferenceNumber.QuadPart = b - 1;

    // itterate [0, nfrib.FileReferenceNumber.QuadPart)
    do 
    {
        if (DeviceIoControl(hVolume, FSCTL_GET_NTFS_FILE_RECORD, 
            &nfrib, sizeof nfrib, pnfrob, cb, &BytesReturned, 0))
        {
            // are really file
            if (
                pnrh->Type == NTFS_RECORD_HEADER::FILE &&
                pnfrh->Flags & NTFS_FILE_RECORD_HEADER::flgInUse &&
                !pnfrh->BaseFileRecord
                )
            {
                N++;
            }
        }
        else
        {
            pnfrob->FileReferenceNumber.QuadPart = nfrib.FileReferenceNumber.QuadPart;
        }

    } while (0 <= (nfrib.FileReferenceNumber.QuadPart = pnfrob->FileReferenceNumber.QuadPart - 1));

    *FileCount = N;

    return NOERROR;
}
Community
  • 1
  • 1
RbMm
  • 31,280
  • 3
  • 35
  • 56