Xyz Abc
Xyz Abc

Reputation: 97

ReadFile function returns ERROR_INVALID_PARAMETER

I'm trying to get to work ReadFile function. Here's my code:

#define BUFFERSIZE 5

int main(int argc, char* argv[])
{
    OVERLAPPED overlapIn = {};
    HANDLE tHandle;
    char buf[BUFFERSIZE] = {};
    DWORD  lpNumberOfBytesRead;

    tHandle = CreateFile(
        L"\\\\.\\D:",
        GENERIC_READ,
        FILE_SHARE_READ,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL);

    if (tHandle == INVALID_HANDLE_VALUE)
    {
        DWORD error = GetLastError();
        assert(0);
    }

    if (ReadFile(tHandle, &buf, BUFFERSIZE - 1, &lpNumberOfBytesRead, NULL) == 0)
    {
        int error = GetLastError();
        printf("Terminal failure: Unable to read from disk.\n GetLastError=%d\n", error);
        CloseHandle(tHandle);
        return 1;
    }

The GetLastError function returns code 87, which is ERROR_INVALID_PARAMETER.

It's clear that one of the parameters is wrong, but I have no idea which one, since I tried to do everything like it's written in the documentation.

Upvotes: 5

Views: 5102

Answers (2)

Andre
Andre

Reputation: 162

buffer size needs to be aligned with hdd sectorsize

WIN32_FIND_DATA atr = {0};
DWORD BYTES_PER_SECTOR;
char path[MAX_PATH];

/* get path length current dir */
const size_t len = GetCurrentDirectory(0, 0); 

/* set path to path char array */
GetCurrentDirectory(len, path);

/* windows function to get disk details */
GetDiskFreeSpace(NULL, NULL, &BYTES_PER_SECTOR, NULL, NULL); 

/* find first file in dir */
find = FindFirstFile(path, &atr);

for(;find != INVALID_HANDLE_VALUE;){

/* get the file size */
DWORD filesize = atr.nFileSizeLow;
  if(atr.nFileSizeHigh > 0){
                     filesize = atr.nFileSizeHigh;
                     filesize = (filesize << 31);
                     filesize = atr.nFileSizeLow;
                     }
 /* sector size aligned file size */
 size_t buffer_size = ((BYTES_PER_SECTOR + ((filesize + BYTES_PER_SECTOR)-1)) & ~(BYTES_PER_SECTOR -1));

 /* create buffer */
 DWORD buffer[buffer_size];                                                       

 /* create a new file or open an existing file */
 handle =   CreateFile(&path[0], GENERIC_READ | GENERIC_WRITE, 0 , NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING, NULL))!=INVALID_HANDLE_VALUE)

 /* read the file in to buffer */
 ReadFile(handle, (void*)&buffer, buffer_size, &bytesread, NULL)

if(FindNextFile(find, &atr)==0){ printf("last file processed, leaving\n");break;};
 } 
 CloseHandle(file);
 FindClose(find);

Upvotes: 0

Harry Johnston
Harry Johnston

Reputation: 36348

This is described in the documentation for CreateFile:

Volume handles can be opened as noncached at the discretion of the particular file system, even when the noncached option is not specified in CreateFile. You should assume that all Microsoft file systems open volume handles as noncached.

The MSDN article on File Buffering describes the requirements for noncached handles:

File access sizes, including the optional file offset in the OVERLAPPED structure, if specified, must be for a number of bytes that is an integer multiple of the volume sector size. For example, if the sector size is 512 bytes, an application can request reads and writes of 512, 1,024, 1,536, or 2,048 bytes, but not of 335, 981, or 7,171 bytes.

File access buffer addresses for read and write operations should be physical sector-aligned, which means aligned on addresses in memory that are integer multiples of the volume's physical sector size. Depending on the disk, this requirement may not be enforced.

Rigorous code should check the sector size for the file system in question, then use this approach to allocate the memory. However, in my experience, the sector size has always been less than or equal to the allocation granularity, so you can get away with just using VirtualAlloc() to allocate a memory block.

Upvotes: 4

Related Questions