3

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.

Xyz Abc
  • 77
  • 2
  • 6
  • I suppose you get the error after the 1st `if`. You cannot read from a drive lettre simply like that. – Jabberwocky Jul 29 '15 at 10:21
  • No, I don't, I'm talking about ReadFile function. And yes, I can read from a drive like that. – Xyz Abc Jul 29 '15 at 10:24
  • 4
    BUFFERSIZE-1 is wrong. You cannot count on the file system cache when you read raw data from a disk drive. Supported alignment depends on the file system, 4096 is a nice round number. You must also specify FILE_SHARE_WRITE in the CreateFile() call. And you'll need to make a lot more noise when CreateFile() fails, assert() does not cut it. – Hans Passant Jul 29 '15 at 10:25
  • Wow, that was it, thank you! – Xyz Abc Jul 29 '15 at 10:28
  • Could you explain though (or give a source) why I can't count on the file system cache when I read data from a disk drive? – Xyz Abc Jul 29 '15 at 10:49
  • 1
    Raw reads from a device must be a multiple of the block size. – Jonathan Potter Jul 29 '15 at 10:55

2 Answers2

4

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.

Community
  • 1
  • 1
Harry Johnston
  • 35,639
  • 6
  • 68
  • 158
0

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);
Andre
  • 172
  • 2
  • 8