Skip to content
Merged
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
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,7 @@ jobs:
# seventh is absent from the list for the same reason it is absent
# from the objects.
bash .spec/tools/run-conformance.sh openkal-windows . \
full,exec,random,terminal,net,datagram,timeout $extra
full,exec,random,terminal,net,datagram,timeout,map $extra

# run-conformance.sh above has already pointed the manifest at the
# specification's working tree and restored it through a trap; this
Expand Down Expand Up @@ -447,7 +447,7 @@ jobs:
WINEDEBUG: '-all'
run: |
bash .spec/tools/run-conformance.sh openkal-windows . \
full,exec,random,terminal,net,datagram,timeout \
full,exec,random,terminal,net,datagram,timeout,map \
--target x86_64-windows-gnu

- name: The exported surface is complete and contains nothing else
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ An implementation of [openkal](https://github.com/mcpplibs/openkal) for Windows.
openkal = "0.17.1"

[target.'cfg(windows)'.dependencies]
openkal-windows = "0.13.3"
openkal-windows = "0.14.0"
```

Its purpose is as much to test the specification as to be used. openkal was
Expand Down
5 changes: 3 additions & 2 deletions mcpp.toml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
[package]
namespace = "mcpplibs"
name = "openkal-windows"
version = "0.13.3"
version = "0.14.0"
description = "An implementation of openkal for Windows, written on the Win32 interfaces and the object manager beneath them, using no C runtime symbol."
license = "Apache-2.0"

Expand Down Expand Up @@ -59,10 +59,11 @@ provides-interfaces = [
"openkal.net",
"openkal.datagram",
"openkal.timeout",
"openkal.map",
]

[dependencies]
openkal = "0.17.1"
openkal = "0.18.0"

# The package contributes definitions and no modules. The interface it
# implements is declared by the specification package, which this package
Expand Down
4 changes: 4 additions & 0 deletions port/kernel32.def
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ AssignProcessToJobObject
CancelIoEx
CloseHandle
CreateEventW
CreateFileMappingW
CreateFileW
CreateJobObjectW
CreatePipe
Expand All @@ -20,6 +21,7 @@ DeviceIoControl
ExitProcess
FlushFileBuffers
FlushInstructionCache
FlushViewOfFile
FreeEnvironmentStringsW
GetCommandLineW
GetConsoleMode
Expand Down Expand Up @@ -51,6 +53,7 @@ HeapFree
InitializeProcThreadAttributeList
LoadLibraryW
LocalFree
MapViewOfFile
MultiByteToWideChar
OpenProcess
PeekNamedPipe
Expand All @@ -68,6 +71,7 @@ Sleep
SwitchToThread
TerminateJobObject
TerminateProcess
UnmapViewOfFile
UpdateProcThreadAttribute
VirtualAlloc
VirtualFree
Expand Down
72 changes: 72 additions & 0 deletions src/map.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#include "win.h"
#include "handle.h"
#include <openkal/map.h>

// openkal.map on this system (openkal 0.18).
//
// A section of the file (CreateFileMappingW, of the file's own length) and a
// view of it (MapViewOfFile). The section is closed as soon as the view exists:
// the view keeps it alive, and a view is released by its address alone, so
// nothing is recorded --- the reason the specification gives a region no
// handle (map.h). The offset's alignment is this system's allocation
// granularity, which is the specification's constant.
//
// THE FILE'S LENGTH IS ASKED FIRST. A view cannot extend past the section, and
// a section of a writable file larger than the file would lengthen it; the
// specification refuses such a region at the call. A file that is not on a
// disk (a device, a pipe) has no contents to map.
//
// A FILE SHORTENED BENEATH A VIEW is refused by this system with
// ERROR_USER_MAPPED_FILE, which win.cpp reports as kal_err_permission --- the
// first of the two outcomes map.h permits.

namespace { void* file_of(kal_file f) { return okw::unpack(f.h); } }

extern "C" {

int kal_map_file(kal_file f, kal_u64 offset, kal_uintptr length, kal_uintptr how, void** out) {
if (out == nullptr) return kal_err_invalid;
*out = nullptr;
void* h = file_of(f);
if (h == nullptr || length == 0 || offset % KAL_MAP_ALIGNMENT != 0
|| (how & ~(KAL_MAP_WRITE | KAL_MAP_SHARED)) != 0)
return kal_err_invalid;
if (GetFileType(h) != FILE_TYPE_DISK) return kal_err_not_supported;
okw::io_status_block s{};
okw::file_standard_information standard{};
const long q = okw::NtQueryInformationFile(h, &s, &standard, sizeof standard,
okw::file_standard_information_class);
if (!okw::ok(q)) return okw::translate_nt(q);
const kal_u64 size = standard.end_of_file > 0 ? static_cast<kal_u64>(standard.end_of_file) : 0;
if (offset > size || static_cast<kal_u64>(length) > size - offset) return kal_err_invalid;

const bool write = (how & KAL_MAP_WRITE) != 0, shared = (how & KAL_MAP_SHARED) != 0;
// Shared and written: the file's pages. Written and private: copy on write,
// which needs only reading of the file. Otherwise read.
const DWORD protect = write ? (shared ? PAGE_READWRITE : PAGE_WRITECOPY) : PAGE_READONLY;
const DWORD access = write ? (shared ? FILE_MAP_WRITE : FILE_MAP_COPY) : FILE_MAP_READ;
HANDLE section = CreateFileMappingW(h, nullptr, protect, 0, 0, nullptr);
if (section == nullptr) return okw::translate_win32(GetLastError());
void* view = MapViewOfFile(section, access, static_cast<DWORD>(offset >> 32),
static_cast<DWORD>(offset & 0xffffffffu), length);
const DWORD e = view ? 0 : GetLastError();
CloseHandle(section);
if (view == nullptr) return okw::translate_win32(e);
*out = view;
return kal_ok;
}

int kal_map_sync(void* region, kal_uintptr length) {
if (region == nullptr || length == 0) return kal_err_invalid;
// FlushViewOfFile writes the view's changed pages to the file, after which
// a read of the file reads them --- the visibility the specification asks
// for. A view of a copy has nothing to write and succeeds.
return FlushViewOfFile(region, length) ? kal_ok : okw::translate_win32(GetLastError());
}

void kal_map_release(void* region, kal_uintptr length) {
if (region == nullptr || length == 0) return;
(void)UnmapViewOfFile(region);
}

}
2 changes: 1 addition & 1 deletion src/version.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ kal_u64 kal_interfaces(void) {
| KAL_IFACE_ENV | KAL_IFACE_TIME | KAL_IFACE_RANDOM
| KAL_IFACE_FS | KAL_IFACE_PROCESS | KAL_IFACE_TASK
| KAL_IFACE_EXEC | KAL_IFACE_TERMINAL | KAL_IFACE_NET
| KAL_IFACE_DATAGRAM | KAL_IFACE_TIMEOUT;
| KAL_IFACE_DATAGRAM | KAL_IFACE_TIMEOUT | KAL_IFACE_MAP;
}

}
3 changes: 2 additions & 1 deletion src/win.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ int translate_win32(unsigned long e) {
case ERROR_HANDLE_DISK_FULL: return kal_err_no_space;
case ERROR_ACCESS_DENIED:
case ERROR_WRITE_PROTECT:
case ERROR_SHARING_VIOLATION: return kal_err_permission;
case ERROR_SHARING_VIOLATION:
case ERROR_USER_MAPPED_FILE: return kal_err_permission;
case ERROR_CALL_NOT_IMPLEMENTED:
case ERROR_NOT_SUPPORTED:
case ERROR_INVALID_FUNCTION: return kal_err_not_supported;
Expand Down
18 changes: 18 additions & 0 deletions src/win32.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,13 +276,23 @@ enum : DWORD {
ERROR_DIRECTORY = 267,
ERROR_DIR_NOT_EMPTY = 145,
ERROR_IO_PENDING = 997,
// A file that holds a mapped view refuses to be shortened (openkal 0.18,
// openkal.map): kal_err_permission, which map.h names for this refusal.
ERROR_USER_MAPPED_FILE = 1224,

// For openkal.exec.
MEM_COMMIT = 0x00001000u,
MEM_RESERVE = 0x00002000u,
MEM_RELEASE = 0x00008000u,
PAGE_READWRITE = 0x04u,
PAGE_EXECUTE_READ = 0x20u,

// For openkal.map.
PAGE_READONLY = 0x02u,
PAGE_WRITECOPY = 0x08u,
FILE_MAP_COPY = 0x0001u,
FILE_MAP_WRITE = 0x0002u,
FILE_MAP_READ = 0x0004u,
};

// ── the functions ───────────────────────────────────────────────────────────
Expand Down Expand Up @@ -433,6 +443,14 @@ OKW_IMPORT int OKW_API WideCharToMultiByte(UINT, DWORD, LPCWSTR, int, LPSTR,
// whose instruction path does not see the data path's writes.
OKW_IMPORT LPVOID OKW_API VirtualAlloc(LPVOID, unsigned long long, DWORD, DWORD);

// A part of a file in the address space, for openkal.map. The section object
// is closed as soon as its view exists, which keeps it alive; a view is
// released by its address alone.
OKW_IMPORT HANDLE OKW_API CreateFileMappingW(HANDLE, SECURITY_ATTRIBUTES*, DWORD, DWORD, DWORD, LPCWSTR);
OKW_IMPORT LPVOID OKW_API MapViewOfFile(HANDLE, DWORD, DWORD, DWORD, unsigned long long);
OKW_IMPORT BOOL OKW_API UnmapViewOfFile(LPCVOID);
OKW_IMPORT BOOL OKW_API FlushViewOfFile(LPCVOID, unsigned long long);

// What this system reports about itself. Only two fields are read and the rest
// are named so that the record has the layout the system writes.
struct SYSTEM_INFO {
Expand Down
Loading