diff --git a/CHANGES.md b/CHANGES.md index 00157499..53e19d92 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ ## Unreleased - Support all version of cmdliner (#386) +- 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 666d2670..b5f27d4f 100644 --- a/src/unix/pread.c +++ b/src/unix/pread.c @@ -4,13 +4,63 @@ #include #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 (value v_fd, value v_fd_off, value v_buf, value v_buf_off, value v_len) { 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); @@ -29,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 e91b71ca..78d267fe 100644 --- a/src/unix/pwrite.c +++ b/src/unix/pwrite.c @@ -4,13 +4,60 @@ #include #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 (value v_fd, value v_fd_off, value v_buf, value v_buf_off, value v_len) { 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); @@ -29,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);