Skip to content

Latest commit

 

History

History
160 lines (134 loc) · 8.71 KB

File metadata and controls

160 lines (134 loc) · 8.71 KB

Platform services

MiniLang exposes the same application-facing system interfaces on windows-x64 and linux-x64. The modules select native Win32 or POSIX/glibc operations at compile time. Existing Windows projects remain source-compatible: windows-x64 is still the default target and no new library is linked unless a source module imports it.

Platform, paths, processes and consoles

  • std.platform reports the target OS and architecture plus path separators, line endings and executable/shared-library extensions.
  • std.path provides target-aware absolute-path detection, joining, file and directory names, extensions and extension replacement. These functions are lexical and do not touch the filesystem.
  • std.process provides the process ID, environment lookup, current directory lookup and current-directory changes.
  • std.console detects interactive input, disables Windows QuickEdit when requested, and reads echo-free secrets or confirmed passwords. Linux secret input uses getpass; the native temporary buffer is explicitly wiped before returning. Call wipe on caller-owned secret byte arrays after use.

Durable random-access files

std.io.file complements the convenience-oriented std.fs module. Its FileHandle supports positional readAt, readExactAt and writeAt, append, size, truncate, explicit flush and close. Durable open/create variants request write-through semantics. Windows uses CreateFileW, FlushFileBuffers, LockFileEx and MoveFileExW; Linux uses open, pread, pwrite, fsync, flock and rename.

readAt and writeAt pass validated ranges of caller-owned byte buffers directly to the native file APIs, including nonzero buffer offsets and short-write retries. The requested count may be smaller than the buffer; readAt leaves bytes outside the bytes actually read unchanged. Reuse buffers for hot positional I/O loops. The native call is synchronous; callers must not mutate a buffer concurrently while a read or write is in progress.

lock(file, mode, wait) takes a whole-file advisory shared or exclusive lock. A non-blocking conflict returns error code 264. Every participant must obey the advisory-lock protocol. On Windows, cursor-based operations on one handle are serialized by the caller; servers should use separate handles per worker.

atomicMove atomically replaces a path within the guarantees of the host filesystem. For durable metadata updates, flush the file, perform the move and then call syncDirectory on the containing directory. readAllBytes and readAllText require an explicit maximum size to prevent accidental unbounded allocations.

The convenience std.fs.copyFile uses Win32 CopyFileW on Windows. On Linux it uses copy_file_range when the filesystem supports a fast kernel copy, with a 1-MiB reusable buffer fallback (selected directly for WSL DrvFS). It rejects a source and destination that resolve to the same inode before truncating, including hard links and symlinks.

Networking and TLS

std.net now exposes reusable-address, keepalive, TCP no-delay and send/receive timeout options. tcpListenAddress(host, port, backlog) binds an explicit IPv4 address; tcpListen keeps its established all-interface behavior. Public TCP and UDP helpers accept ports from 0 through 65535 and reject values outside that range. TCP listeners and ordinary bound UDP sockets request exclusive port ownership on Windows to avoid cross-process traffic routing; Linux TCP listeners retain SO_REUSEADDR restart semantics. An explicit setReuseAddress(socket, true) call opts a Windows UDP socket out of the exclusive default before it is bound, so intentional shared-port designs keep working. Process-wide socket initialization and cleanup are serialized; as before, applications must not call cleanup() while sockets are still in use. Native socket timeouts are portable for integer millisecond values in 0..2147483647; negative, oversized and non-integer values return a managed network error rather than being truncated by the platform ABI.

tcpSendAll sends directly from the source byte buffer even after a partial send. For allocation-free receives into an existing buffer, use tcpRecvInto(socket, destination, offset, count), which returns the received byte count (zero on orderly TCP shutdown), or udpRecvFromInto(socket, destination, offset, count), which returns [receivedCount, peerIp, peerPort]. Both validate the destination range and leave bytes outside the received range unchanged. The older tcpRecv and udpRecvFrom APIs remain available and return newly allocated payloads.

std.tls includes a native provider selected at compile time: Windows uses Schannel and the system certificate stores; Linux uses OpenSSL 3 (libssl.so.3 and libcrypto.so.3). nativeProviderName() reports the active backend. The callback-based provider(...), connectClient(...) and acceptServer(...) contract remains available for application-specific transports, while normal applications use connect(socket, options) and accept(socket, options).

Client options default to TLS 1.3, system trust and mandatory DNS-name verification. The minimum may be changed to TLS 1.2. A 32-byte SHA-256 leaf certificate pin is an additional fail-closed check; pinning cannot disable peer verification. Linux optionally accepts a PEM CA bundle through caFile. Schannel intentionally rejects caFile; install that CA in a Windows store or use a leaf pin. Neither backend silently falls back below the configured minimum.

Linux server options are PEM certificate-chain and private-key paths. Windows accepts store:<SHA1-thumbprint> (searched in CurrentUser and LocalMachine MY) or pfx:<path>. A PFX password is read from MINILANG_TLS_PFX_PASSWORD; alternatively set privateKeyReference to env:VARIABLE_NAME. Secret buffers and imported PFX payloads are wiped during release. requireClientCertificate requests native client-certificate validation.

TLS streams own their native security context, but never own the TCP socket. Call shutdown(stream) to send close_notify, then close(stream), and finally std.net.close(socket). sendAll handles partial provider writes, passes the original byte buffer to the provider on the first attempt, and copies only the unsent tail after a partial write. Providers must treat the input buffer as read-only. receive returns empty bytes after a clean peer shutdown. The native Schannel provider grows incomplete-record buffers geometrically and encrypts each outgoing record in one contiguous buffer; the Linux OpenSSL provider avoids copying exact-size receive results.

Identifiers and password derivation

std.uuid creates RFC 4122 version-4 UUIDs with std.crypto.secureRandom and provides byte/string format, parse and validation helpers. std.crypto adds PBKDF2-HMAC-SHA-256 and PBKDF2-HMAC-SHA-384 backed by Windows CNG or OpenSSL 3.

Portable compression

std.compress.fast(bytes) tries a standard LZ4 block, retaining raw bytes when that is smaller. std.compress.compact(bytes) additionally tries std.compress.rle, a simple byte-run format suited to long equal-byte runs. Both return the same MLC1 container on Windows and Linux: four magic bytes, one algorithm byte, three reserved zero bytes, a little-endian 32-bit decoded length, a little-endian CRC-32C, then the chosen payload. Algorithm 0 is raw, 1 is an LZ4 block, and 2 is MiniLang RLE. The container is not an LZ4 frame, ZIP archive, or gzip stream.

Call std.compress.decompress(container, maxOutputBytes) with an explicit application limit. The decoder checks the header, limit, payload bounds, exact decoded length, and checksum. CRC-32C detects accidental corruption but provides no authenticity; authenticate data separately when it may be modified by an attacker. The APIs are one-shot and hold input and output in memory; split very large files into application-level chunks. Raw std.compress.lz4.encode/decode blocks interoperate with liblz4 when the caller supplies the exact uncompressed size.

Target diagnostics and testing

An unguarded Windows .dll import is a compile error for --target linux-x64. Use conditional compilation around platform-specific providers. The shared tests/platform_services.ml acceptance fixture exercises both native targets, including PBKDF2 vectors, UUIDs, socket options, durable file operations, advisory lock conflicts and the TLS provider lifecycle. Run tests/run_tls_native.ps1 -Compiler <compiler> with WSL/OpenSSL installed for real positive and wrong-hostname Schannel/OpenSSL client/server handshakes.