Search code examples
cwindowsfileconcurrencyreadfile

Using ReadFile in C code


I am trying to concurrently read a file at different offsets. I am able to do so using pread in posix systems, but I can't figure out how to do it using ReadFile for windows systems. I'm having difficulty understanding a lot of the Windows documentation. Can anyone show me an example of how I should be using ReadFile instead?

EDIT See working code here!

    do {
#ifdef _WIN32
        OVERLAPPED overlapped;
        memset(&overlapped, 0, sizeof(OVERLAPPED));

        overlapped.Offset = shard_meta->index*state->shard_size + total_read;

        HANDLE file = (HANDLE)_get_osfhandle(fileno(state->original_file));
        SetLastError(0);
        bool RF = ReadFile(file, read_data, AES_BLOCK_SIZE * 256, NULL, &overlapped);
        if ((RF==0) && GetLastError() == ERROR_IO_PENDING) {
            printf ("Asynch readfile started. I can do other operations now\n");
            while( !GetOverlappedResult(file, &overlapped, &read_bytes, TRUE)) {
                if (GetLastError() == ERROR_IO_INCOMPLETE) {
                    printf("I/O pending: %d .\n",GetLastError());
                } else if  (GetLastError() == ERROR_HANDLE_EOF) {
                    printf("End of file reached.\n");
                    break;
                } else {
                    printf("GetOverlappedResult failed with error:%d\n",GetLastError());
                    break;
                }
            }
        } else if ((RF == 0) && GetLastError() != ERROR_IO_PENDING) {
            printf ("Error reading file :%d\n",GetLastError());
            goto clean_variables;
        }

#else
        read_bytes = pread(fileno(state->original_file),
                       read_data, AES_BLOCK_SIZE * 256,
                       shard_meta->index*state->shard_size + total_read);
#endif
        total_read += read_bytes;

        memset_zero(read_data, AES_BLOCK_SIZE * 256);
    } while(total_read < state->shard_size && read_bytes > 0);

Solution

  • See working code below

    #ifdef _WIN32
    ssize_t pread(int fd, void *buf, size_t count, uint64_t offset)
    {
        long unsigned int read_bytes = 0;
    
        OVERLAPPED overlapped;
        memset(&overlapped, 0, sizeof(OVERLAPPED));
    
        overlapped.OffsetHigh = (uint32_t)((offset & 0xFFFFFFFF00000000LL) >> 32);
        overlapped.Offset = (uint32_t)(offset & 0xFFFFFFFFLL);
    
        HANDLE file = (HANDLE)_get_osfhandle(fd);
        SetLastError(0);
        bool RF = ReadFile(file, buf, count, &read_bytes, &overlapped);
    
         // For some reason it errors when it hits end of file so we don't want to check that
        if ((RF == 0) && GetLastError() != ERROR_HANDLE_EOF) {
            errno = GetLastError();
            // printf ("Error reading file : %d\n", GetLastError());
            return -1;
        }
    
        return read_bytes;
    }
    
    ssize_t pwrite(int fd, const void *buf, size_t count, uint64_t offset)
    {
        long unsigned int written_bytes = 0;
    
        OVERLAPPED overlapped;
        memset(&overlapped, 0, sizeof(OVERLAPPED));
    
        overlapped.OffsetHigh = (uint32_t)((offset & 0xFFFFFFFF00000000LL) >> 32);
        overlapped.Offset = (uint32_t)(offset & 0xFFFFFFFFLL);
    
        HANDLE file = (HANDLE)_get_osfhandle(fd);
        SetLastError(0);
        bool RF = WriteFile(file, buf, count, &written_bytes, &overlapped);
        if ((RF == 0)) {
            errno = GetLastError();
            // printf ("Error reading file :%d\n", GetLastError());
            return -1;
        }
    
        return written_bytes;
    }
    #endif