diff --git a/CHANGES.md b/CHANGES.md index 227b2e9c..53e19d92 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,8 +1,8 @@ ## Unreleased - Support all version of cmdliner (#386) -- Support MSVC compiler. Still missing implementations of pread and - pwrite. (#383) +- Support MSVC compiler. Supply Windows implementations of pread and pwrite. + (#383) # 1.6.0 (2022-02-12) diff --git a/src/unix/pread.c b/src/unix/pread.c index 012ef1ef..b5f27d4f 100644 --- a/src/unix/pread.c +++ b/src/unix/pread.c @@ -5,8 +5,53 @@ #include #ifdef _MSC_VER +#include #include +#include typedef SSIZE_T ssize_t; +typedef HANDLE file_descr_t; +#define File_descr_val Handle_val + +ssize_t pread(file_descr_t fd, void *buf, size_t count, size_t offset) +{ + OVERLAPPED oOverlap; + BOOL bResult; + DWORD dwError; + ssize_t ret; + HRESULT hr; + + /* https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile#synchronization-and-file-position */ + oOverlap.Internal = 0; + oOverlap.InternalHigh = 0; + oOverlap.Offset = LODWORD(offset); + oOverlap.OffsetHigh = HIDWORD(offset); + oOverlap.hEvent = 0; + bResult = ReadFile(fd, buf, count, NULL, &oOverlap); + + if (!bResult) { + /* ReadFile failed, or is completing asynchrously if opened with + FILE_FLAG_OVERLAPPED. OCaml does not use FILE_FLAG_OVERLAPPED. */ + dwError = GetLastError(); + if (dwError == ERROR_HANDLE_EOF) { + /* pread returns 0 on EOF */ + ret = 0; + } else { + /* pread returns -1 on any error */ + ret = -1; + } + } else { + /* pread returns number of bytes read */ + hr = ULongPtrToSSIZET(oOverlap.InternalHigh, &ret); + if(hr != S_OK) { + /* overflow. too many bytes read */ + ret = -1; + } + } + return ret; +} +#else +typedef size_t file_descr_t; +#define File_descr_val Int_val #endif CAMLprim value caml_index_pread_int @@ -15,7 +60,7 @@ CAMLprim value caml_index_pread_int CAMLparam5(v_fd, v_fd_off, v_buf, v_buf_off, v_len); ssize_t ret; - size_t fd = Int_val(v_fd); + file_descr_t fd = File_descr_val(v_fd); size_t fd_off = Long_val(v_fd_off); size_t buf_off = Long_val(v_buf_off); size_t len = Long_val(v_len); @@ -34,7 +79,7 @@ CAMLprim value caml_index_pread_int64 CAMLparam5(v_fd, v_fd_off, v_buf, v_buf_off, v_len); ssize_t ret; - size_t fd = Int_val(v_fd); + file_descr_t fd = File_descr_val(v_fd); size_t fd_off = Int64_val(v_fd_off); size_t buf_off = Long_val(v_buf_off); size_t len = Long_val(v_len); diff --git a/src/unix/pwrite.c b/src/unix/pwrite.c index 4bc8eac6..78d267fe 100644 --- a/src/unix/pwrite.c +++ b/src/unix/pwrite.c @@ -5,8 +5,50 @@ #include #ifdef _MSC_VER +#include #include +#include typedef SSIZE_T ssize_t; +typedef HANDLE file_descr_t; +#define File_descr_val Handle_val + +ssize_t pwrite(file_descr_t fd, const void *buf, size_t count, size_t offset) +{ + OVERLAPPED oOverlap; + DWORD dwBytesWritten; + BOOL bResult; + DWORD dwError; + ssize_t ret; + HRESULT hr; + + /* https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefile#synchronization-and-file-position */ + /* &dwBytesWritten - ignored but non-NULL for Windows 7 compatibility */ + oOverlap.Internal = 0; + oOverlap.InternalHigh = 0; + oOverlap.Offset = LODWORD(offset); + oOverlap.OffsetHigh = HIDWORD(offset); + oOverlap.hEvent = 0; + bResult = WriteFile(fd, buf, count, &dwBytesWritten, &oOverlap); + + if (!bResult) { + /* WriteFile failed, or is completing asynchrously if opened with + FILE_FLAG_OVERLAPPED. OCaml does not use FILE_FLAG_OVERLAPPED. */ + dwError = GetLastError(); + /* pwrite returns -1 on any error */ + ret = -1; + } else { + /* pwrite returns number of bytes written */ + hr = ULongPtrToSSIZET(oOverlap.InternalHigh, &ret); + if(hr != S_OK) { + /* overflow. too many bytes written */ + ret = -1; + } + } + return ret; +} +#else +typedef size_t file_descr_t; +#define File_descr_val Int_val #endif CAMLprim value caml_index_pwrite_int @@ -15,7 +57,7 @@ CAMLprim value caml_index_pwrite_int CAMLparam5(v_fd, v_fd_off, v_buf, v_buf_off, v_len); ssize_t ret; - size_t fd = Int_val(v_fd); + file_descr_t fd = File_descr_val(v_fd); size_t fd_off = Long_val(v_fd_off); size_t buf_off = Long_val(v_buf_off); size_t len = Long_val(v_len); @@ -34,7 +76,7 @@ CAMLprim value caml_index_pwrite_int64 CAMLparam5(v_fd, v_fd_off, v_buf, v_buf_off, v_len); ssize_t ret; - size_t fd = Int_val(v_fd); + file_descr_t fd = File_descr_val(v_fd); size_t fd_off = Int64_val(v_fd_off); size_t buf_off = Long_val(v_buf_off); size_t len = Long_val(v_len);