Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MSVC compiler support with Win32 pread/pwrite #383

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -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)

Expand Down
54 changes: 52 additions & 2 deletions src/unix/pread.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,63 @@
#include <caml/signals.h>
#include <caml/unixsupport.h>

#ifdef _MSC_VER
#include <Windows.h>
#include <BaseTsd.h>
#include <Intsafe.h>
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);
Expand All @@ -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);
Expand Down
51 changes: 49 additions & 2 deletions src/unix/pwrite.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,60 @@
#include <caml/signals.h>
#include <caml/unixsupport.h>

#ifdef _MSC_VER
#include <Windows.h>
#include <BaseTsd.h>
#include <Intsafe.h>
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);
Expand All @@ -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);
Expand Down