Commit 4b7cfb8

kravantokh <kravantokh@noreply.codeberg.org>
2026-07-31 18:29:04
Add minimal memory-mapped file I/O.
1 parent 0e25e49
datatypes/error.h
@@ -32,19 +32,28 @@ enum _ErrorSources {
 
 #define S_REASON_MASK (0xfffff)
 enum _ErrorReasons {
-	ERR_GENERIC = 0, /* Even numbers are for the implementations, odd are for user-defined errors */
+	ERR_GENERIC = 0x0, /* Even numbers are for the implementations, odd are for user-defined errors */
 
-	ERR_INVALID_ARGUMENT = 2,
+	ERR_INVALID_ARGUMENT = 0x2,
 
-	ERR_OVERFLOW = 4,
+	ERR_OVERFLOW = 0x4,
+
+	ERR_OUT_OF_BOUND = 0x6, /* a value is out of bounds or the operation would violate certain bounds with the current arguments */
+
+	ERR_PERMISSION_DENIED = 0x8,
 
-	ERR_OUT_OF_BOUND = 6, /* a value is out of bounds or the operation would violate certain bounds with the current arguments */
 
 	ERR_MEM_MAP_FAILURE = 0x100,
 	ERR_MEM_UNMAP_FAILURE = 0x102,
 	ERR_MEM_SETPERM_FAILURE = 0x104,
 	ERR_MEM_SETHINT_FAILURE = 0x106,
 
+	ERR_FILE_ALREADY_EXISTS = 0x110,
+	ERR_FILE_DOESNT_EXIST = 0x112,
+
+	ERR_NO_DISK_SPACE = 0x114,
+
+
 };
 
 
datatypes/string.h
@@ -1,7 +1,7 @@
 #ifndef NOTLIBC_HEADER_DATATYPES_STRING_INCLUDED
 #define NOTLIBC_HEADER_DATATYPES_STRING_INCLUDED
 
-#include "platform/platform.h"
+#include "platform/common/types.h"
 
 STRUCT( String,
 	usize len;
@@ -19,9 +19,8 @@ STRUCT( String,
 #define STRING( varname, string )                        \
 	struct {                                            \
 		u64 len;                                       \
-		u8  data[sizeof( string )];                    \
-	} varname = { .len = sizeof(str)-1, .data = str }
-
+		u8  data[sizeof(string)];                      \
+	} varname = { .len = sizeof(string)-1, .data = string }
 #else
 	#error String not implemented for current platform. 
 
fs/file.h
@@ -1,14 +1,85 @@
 #ifndef NOTLIBC_HEADER_FS_FILE_INCLUDED
 #define NOTLIBC_HEADER_FS_FILE_INCLUDED
 
-#include "datatypes/common.h"
+#include "datatypes/string.h"
+#include "datatypes/error.h"
+#include "platform/info/build.h"
+#include "platform/common/corefunc.h"
+#include "util/mathops.h"
 
 typedef struct _File File;
+typedef struct _FileView FileView;
 
-Status File_open( String *name );
+
+enum FileOpenFlags {
+
+	FILE_ACCESS_READ   = (1 << 1),
+	FILE_ACCESS_WRITE  = (1 << 2),
+	FILE_ACCESS_APPEND = (1 << 3),
+
+	FILE_ACCESS_MASK = (FILE_ACCESS_READ | FILE_ACCESS_WRITE | FILE_ACCESS_APPEND),
+
+	FILE_EXISTING_OPEN     = (1 << 4),
+	FILE_EXISTING_TRUNCATE = (1 << 5),
+	FILE_EXISTING_FAIL     = (1 << 6),
+
+	FILE_EXISTING_MASK = (FILE_EXISTING_OPEN | FILE_EXISTING_TRUNCATE | FILE_EXISTING_FAIL),
+
+	FILE_MISSING_CREATE = (1 << 7),
+	FILE_MISSING_FAIL   = (1 << 8),
+
+	FILE_MISSING_MASK = (FILE_MISSING_CREATE | FILE_MISSING_FAIL),
+
+	FILE_LINK_FOLLOW = (1 << 9),
+	FILE_LINK_FAIL = (1 << 10), /* os-dependent option - whatever the os guarantees. O_NOFOLLOW on linux. */
+
+	FILE_LINK_MASK = (FILE_LINK_FOLLOW | FILE_LINK_FAIL),
+
+};
+
+static inline Status File_open_validate_flags( usize flags, Status err_source ) {
+
+	usize existing_flags = flags & FILE_EXISTING_MASK;
+	u8 existing_flags_multiple_set = !usize_is_power_of_two( existing_flags );
+
+	if( existing_flags_multiple_set ) {
+		DEBUG(breakpoint());
+		return S_FAILURE | ERR_INVALID_ARGUMENT | err_source;
+	}
+
+	if( !( !!(flags & FILE_MISSING_CREATE) ^ !!(flags & FILE_MISSING_FAIL) ) ) {
+		DEBUG(breakpoint());
+		return ERR_INVALID_ARGUMENT | err_source;
+	}
+
+	if( !( !!(flags & FILE_LINK_FOLLOW ) ^ !!(flags & FILE_LINK_FAIL) ) ) {
+		DEBUG(breakpoint());
+		return S_FAILURE | ERR_INVALID_ARGUMENT | err_source;
+	}
+
+	if( !( !!(flags & FILE_ACCESS_WRITE ) ^ !!(flags & FILE_ACCESS_APPEND) ) ) {
+		DEBUG(breakpoint());
+		return S_FAILURE | ERR_INVALID_ARGUMENT | err_source;
+	}
+
+	return S_SUCCESS;
+}
+
+Status File_open( const String *name, usize flags, File *out );
 Status File_close( File *f );
 
-Status File_memorymap( File *f, u8 **out_ptr, usize *out_size );
-Status File_memoryunmap( File *f, u8 **out_ptr, usize *out_size );
+
+enum FileViewFlags {
+	FILEVIEW_OWN_FILE = (1 << 1),
+	FILEVIEW_PAGE_ALIGNED_EXTEND = (1 << 2),
+};
+
+Status FileView_from_file( File *file, usize claim_amount, usize flags, FileView *out ); /* if claim_amount == 0 => claims exact filesize */
+Status FileView_from_path( const String *path, usize claim_amount, usize flags, FileView *out ); /* This is for quick and easy mmaping of files. If you actually want control over the opening flags use FileView_from_file - if you don't  */
+
+Status FileView_extend_file( FileView *fv, usize amount ); /* Extend the file's end by amount */
+
+Status FileView_destroy( FileView *fv );
+
 
 #endif
platform/common/corefunc.h
@@ -2,6 +2,11 @@
 #define NOTLIBC_HEADER_PLATFORM_COREFUNC_INCLUDED
 
 #include "./types.h"
+#include "./headers.h"
+
+#ifdef NOTLIBC_IMPLEMENT
+	#include PLATFORM_FUNC_HEADER
+#endif
 
 static inline void terminate(u32 code); /* aka exit */
 static inline void terminate_forced(void); /* force exit, fault, anything that terminates forcefully */
platform/common/headers.h
@@ -7,7 +7,7 @@
 	#define PLATFORM_TYPES_HEADER "platform/linux/core/types.h"
 	#define PLATFORM_FUNC_HEADER "platform/linux/core/func.h"
 	#define PLATFORM_ENTRYPOINT_HEADER "platform/linux/core/entry.h"
-	#define PLATFORM_FILE_HEADER "platform/linux/fs.h"
+	#define PLATFORM_FILE_HEADER "platform/linux/file.h"
 #elif PLATFORM == PLATFORM_WINDOWS
 #endif
 
platform/linux/core/entry.h
@@ -18,6 +18,7 @@ void entry(void); /* aka main */
 			"movq %rsp, (%rax)\n" /* save original stack pointer */
 			"xor %rax, %rax\n"
 			"call entry\n"
+			"ud2\n"
 	);
 #elif ARCH == ARCH_I386
 	#error "i386 entrypoint not implemented"
platform/linux/core/func.h
@@ -1,8 +1,6 @@
 #ifndef HEADER_PLATFORM_LINUX_CORE_FUNC_INCLUDED
 #define HEADER_PLATFORM_LINUX_CORE_FUNC_INCLUDED
 
-#include "platform/common/corefunc.h"
-
 static inline void breakpoint(void) {
 	__asm__ volatile (
 		"int $3\n"
platform/linux/file.h
@@ -1,11 +1,253 @@
 #ifndef NOTLIBC_HEADER_PLATFORM_LINUX_FILE_INCLUDED
 #define NOTLIBC_HEADER_PLATFORM_LINUX_FILE_INCLUDED
 
-#include "datatypes/common.h"
+#include "datatypes/error.h"
+#include "platform/common/types.h"
+#include "platform/common/corefunc.h"
+#include "platform/info/build.h"
+#include "platform/info/os.h"
+#include "platform/linux/syscalls.h"
+#include "platform/linux/memory.h"
 #include "fs/file.h"
 
 STRUCT( File,
 	s32 fd;
 )
 
+STRUCT( FileView,
+	File file;
+	Page *start;
+	usize claimed;
+	usize filesize;
+	usize flags;
+)
+
+Status File_open( const String *name, usize flags, File *out ) {
+	DEBUG( assert( name->data[name->len] == 0 ) );
+
+	if(
+		!(flags & FILE_ACCESS_WRITE) &&
+		!(flags & FILE_ACCESS_APPEND) &&
+		(flags & FILE_EXISTING_TRUNCATE)
+	) {
+		DEBUG( breakpoint() ); /* Can not truncate a file without write access. */
+		return S_FAILURE | ERR_INVALID_ARGUMENT | ERR_ARG_3;
+	}
+
+	if( (flags & FILE_EXISTING_FAIL) && (flags & FILE_MISSING_FAIL) ) {
+		DEBUG( breakpoint() ); /* Useless flag combination: error if there is a file, error if there isn't one aka always error */
+		return S_FAILURE | ERR_INVALID_ARGUMENT | ERR_ARG_3;
+	}
+
+	TRY( File_open_validate_flags( flags, ERR_ARG_3 ) );
+
+	usize syscall_flags = O_CLOEXEC; /* Close all files on exec */
+
+	switch( flags & FILE_ACCESS_MASK ) {
+		case FILE_ACCESS_READ:
+			syscall_flags |= O_RDONLY;
+			break;
+
+		case FILE_ACCESS_WRITE:
+			syscall_flags |= O_WRONLY;
+			break;
+
+		case FILE_ACCESS_APPEND:
+			syscall_flags |= O_WRONLY | O_APPEND;
+			break;
+
+		case FILE_ACCESS_READ | FILE_ACCESS_WRITE:
+			syscall_flags |= O_RDWR;
+			break;
+
+		case FILE_ACCESS_READ | FILE_ACCESS_APPEND:
+			syscall_flags |= O_RDWR | O_APPEND;
+			break;
+
+		default:
+			UNREACHABLE;
+			return S_FAILURE | ERR_INVALID_ARGUMENT | ERR_ARG_3;
+	}
+
+	switch( flags & FILE_EXISTING_MASK ) {
+		case FILE_EXISTING_OPEN:
+			/* done by default on linux */
+			break;
+		case FILE_EXISTING_FAIL:
+			syscall_flags |= O_CREAT | O_EXCL;
+			break;
+		case FILE_EXISTING_TRUNCATE:
+			syscall_flags |= O_TRUNC;
+			break;
+		default:
+			UNREACHABLE;
+			return S_FAILURE | ERR_INVALID_ARGUMENT | ERR_ARG_3;
+	}
+
+	switch( flags & FILE_MISSING_MASK ) {
+		case FILE_MISSING_CREATE:
+			syscall_flags |= O_CREAT;
+			break;
+		case FILE_MISSING_FAIL:
+			/* done by default on linux */
+			break;
+		default:
+			UNREACHABLE;
+			return S_FAILURE | ERR_INVALID_ARGUMENT | ERR_ARG_3;
+	}
+
+	switch( flags & FILE_LINK_MASK ) {
+		case FILE_LINK_FOLLOW:
+			/* Default on linux */
+			break;
+		case FILE_LINK_FAIL:
+			syscall_flags |= O_NOFOLLOW;
+			break;
+	}
+
+	out->fd = linux_open( &name->data[0], syscall_flags, 0666 );
+
+	if( !LINUX_SYSCALL_ERROR( out->fd ) ) {
+		return S_SUCCESS;
+	} else {
+		switch( out->fd ) {
+			case -EACCES:
+			case -EPERM:
+				return S_FAILURE | ERR_PLATFORM | ERR_PERMISSION_DENIED;
+			case -EEXIST:
+				return S_FAILURE | ERR_PLATFORM | ERR_FILE_ALREADY_EXISTS;
+			case -EINVAL:
+				return S_FAILURE | ERR_PLATFORM | ERR_INVALID_ARGUMENT;
+			case -ENOENT:
+				return S_FAILURE | ERR_PLATFORM | ERR_FILE_DOESNT_EXIST;
+			case -ENAMETOOLONG:
+				return S_FAILURE | ERR_ARG_1 | ERR_INVALID_ARGUMENT;
+			case -ENOSPC:
+				return S_FAILURE | ERR_PLATFORM | ERR_NO_DISK_SPACE;
+			default:
+				return S_FAILURE | ERR_PLATFORM | ERR_GENERIC;
+		}
+	}
+}
+
+Status File_close( File *f ) {
+	usize res = linux_close( f->fd );
+
+	if( !LINUX_SYSCALL_ERROR( res ) ) {
+		f->fd = -1;
+		return S_SUCCESS;
+	} else {
+		switch( res ) {
+			case -EBADF:
+				return ERR_ARG_1 | ERR_INVALID_ARGUMENT;
+			default:
+				return S_FAILURE | ERR_PLATFORM | ERR_GENERIC;
+		}
+	}
+}
+
+Status FileView_from_file( File *file, usize claim_amount, usize flags, FileView *out ) {
+	DEBUG( assert( claim_amount%sizeof(Page) == 0 ) );
+
+	if( claim_amount%sizeof(Page) != 0 ) {
+		return ERR_ARG_2 | ERR_INVALID_ARGUMENT;
+	}
+
+	TRY( mem_claim( claim_amount/sizeof(Page), &out->start ) );
+	out->claimed = claim_amount;
+
+	/* Get filesize */
+	struct stat s = {0};
+	isize res = linux_fstat( file->fd, &s );
+
+	if( LINUX_SYSCALL_ERROR(res) ) {
+		DEBUG(breakpoint());
+		return S_FAILURE | ERR_PLATFORM | ERR_GENERIC;
+	}
+
+	out->filesize = s.st_size;
+
+	if( out->filesize != 0 ) { /* Nothing to map in an empty file */
+		res = linux_mmap( (usize)out->start, out->filesize, LINUX_PROT_READ | LINUX_PROT_WRITE, MMAP_MAP_FIXED | MMAP_MAP_SHARED, file->fd, 0 );
+		if( LINUX_SYSCALL_ERROR(res) ) {
+			DEBUG(breakpoint());
+			return S_FAILURE | ERR_PLATFORM | ERR_GENERIC;
+		}
+	}
+	/* Finalize output */
+	out->file = *file;
+	out->flags = flags;
+
+	if( flags & FILEVIEW_OWN_FILE ) {
+		file->fd = -1;
+	}
+
+	return S_SUCCESS;
+}
+
+Status FileView_from_path( const String *path, usize claim_amount, usize flags, FileView *out ) {
+	File file = {0};
+	TRY( File_open( path,
+		FILE_EXISTING_OPEN |
+		FILE_MISSING_CREATE |
+		FILE_LINK_FOLLOW |
+		FILE_ACCESS_READ | FILE_ACCESS_WRITE,
+		&file
+	));
+
+	return FileView_from_file(&file, claim_amount, flags, out);
+}
+
+Status FileView_extend_file( FileView *fv, usize amount ) {
+	if( amount > fv->claimed - fv->filesize ) {
+		return S_FAILURE | ERR_OUT_OF_BOUND;
+	}
+
+	usize map_start_offset = 0;
+	TRY( usize_round_down( fv->filesize, sizeof(Page), &map_start_offset ) );
+
+	usize map_start_addr = (u64)((u8*)fv->start + map_start_offset);
+
+
+	usize res = linux_fallocate( fv->file.fd, 0, fv->filesize, amount );
+	if( LINUX_SYSCALL_ERROR(res) ) {
+		return S_FAILURE | ERR_PLATFORM | ERR_GENERIC;
+	}
+	fv->filesize += amount;
+
+	res = linux_mmap(
+		map_start_addr,
+		fv->filesize - map_start_offset + amount,
+		LINUX_PROT_READ | LINUX_PROT_WRITE,
+		MMAP_MAP_FIXED | MMAP_MAP_SHARED,
+		fv->file.fd,
+		map_start_offset
+	);
+
+
+	if( LINUX_SYSCALL_ERROR(res) ) {
+		return S_FAILURE | ERR_PLATFORM | ERR_MEM_MAP_FAILURE;
+	}
+
+	return S_SUCCESS;
+}
+
+Status FileView_destroy( FileView *fv ) {
+	if( fv->flags & FILEVIEW_OWN_FILE ) { 
+		TRY(File_close( &fv->file ));
+		fv->file.fd = -1;
+	}
+
+	usize res = linux_munmap( (usize)fv->start, fv->claimed );
+	if( LINUX_SYSCALL_ERROR(res) ) {
+		return S_FAILURE | ERR_PLATFORM | ERR_MEM_UNMAP_FAILURE;
+	}
+
+	fv->flags = 0;
+	fv->filesize = 0;
+	fv->claimed = 0;
+	fv->start = 0;
+	return S_SUCCESS;
+}
+
 #endif
platform/linux/syscall_wrappers_gcclike.h
@@ -1,7 +1,8 @@
 #ifndef HEADER_PLATFORM_LINUX_SYSCALL_WRAPPERS_GCCLIKE_INCLUDED
 #define HEADER_PLATFORM_LINUX_SYSCALL_WRAPPERS_GCCLIKE_INCLUDED
 
-#include "../common/types.h"
+#include "platform/common/types.h"
+#include "datatypes/error.h"
 
 #if ARCH == ARCH_X86_64
 	/* All this mess, just so *maybe* the compiler can optimize register usage when inlining. Check the generic wrappers for a more typical way of going about this. This here is unusual, from what I have seen. */
platform/linux/syscalls.h
@@ -16,8 +16,145 @@ static inline isize linux_syscall6(usize num, usize arg1, usize arg2, usize arg3
 	#include "./syscall_wrappers_generic.h"
 #endif
 
-#define LINUX_SYSCALL_ERROR_START ((usize)-4095)
-#define LINUX_SYSCALL_ERROR(value) ((usize)value >= LINUX_SYSCALL_ERROR_START)
+#define LINUX_SYSCALL_ERROR_RANGE_START ((usize)-4095)
+#define LINUX_SYSCALL_ERROR(value) ((usize)value >= LINUX_SYSCALL_ERROR_RANGE_START)
+
+#define EPERM           1 /* Operation not permitted */
+#define ENOENT          2 /* No such file or directory */
+#define ESRCH           3 /* No such process */
+#define EINTR           4 /* Interrupted system call */
+#define EIO             5 /* I/O error */
+#define ENXIO           6 /* No such device or address */
+#define E2BIG           7 /* Argument list too long */
+#define ENOEXEC         8 /* Exec format error */
+#define EBADF           9 /* Bad file number */
+#define ECHILD          10 /* No child processes */
+#define EAGAIN          11 /* Try again */
+#define ENOMEM          12 /* Out of memory */
+#define EACCES          13 /* Permission denied */
+#define EFAULT          14 /* Bad address */
+#define ENOTBLK         15 /* Block device required */
+#define EBUSY           16 /* Device or resource busy */
+#define EEXIST          17 /* File exists */
+#define EXDEV           18 /* Cross-device link */
+#define ENODEV          19 /* No such device */
+#define ENOTDIR         20 /* Not a directory */
+#define EISDIR          21 /* Is a directory */
+#define EINVAL          22 /* Invalid argument */
+#define ENFILE          23 /* File table overflow */
+#define EMFILE          24 /* Too many open files */
+#define ENOTTY          25 /* Not a typewriter */
+#define ETXTBSY         26 /* Text file busy */
+#define EFBIG           27 /* File too large */
+#define ENOSPC          28 /* No space left on device */
+#define ESPIPE          29 /* Illegal seek */
+#define EROFS           30 /* Read-only file system */
+#define EMLINK          31 /* Too many links */
+#define EPIPE           32 /* Broken pipe */
+#define EDOM            33 /* Math argument out of domain of func */
+#define ERANGE          34 /* Math result not representable */
+#define EDEADLK         35 /* Resource deadlock would occur */
+#define ENAMETOOLONG    36 /* File name too long */
+#define ENOLCK          37 /* No record locks available */
+#define ENOSYS          38 /* Invalid system call number */
+#define ENOTEMPTY       39 /* Directory not empty */
+#define ELOOP           40 /* Too many symbolic links encountered */
+#define EWOULDBLOCK     EAGAIN /* Operation would block */
+#define ENOMSG          42 /* No message of desired type */
+#define EIDRM           43 /* Identifier removed */
+#define ECHRNG          44 /* Channel number out of range */
+#define EL2NSYNC        45 /* Level 2 not synchronized */
+#define EL3HLT          46 /* Level 3 halted */
+#define EL3RST          47 /* Level 3 reset */
+#define ELNRNG          48 /* Link number out of range */
+#define EUNATCH         49 /* Protocol driver not attached */
+#define ENOCSI          50 /* No CSI structure available */
+#define EL2HLT          51 /* Level 2 halted */
+#define EBADE           52 /* Invalid exchange */
+#define EBADR           53 /* Invalid request descriptor */
+#define EXFULL          54 /* Exchange full */
+#define ENOANO          55 /* No anode */
+#define EBADRQC         56 /* Invalid request code */
+#define EBADSLT         57 /* Invalid slot */
+#define EDEADLOCK       EDEADLK
+#define EBFONT          59 /* Bad font file format */
+#define ENOSTR          60 /* Device not a stream */
+#define ENODATA         61 /* No data available */
+#define ETIME           62 /* Timer expired */
+#define ENOSR           63 /* Out of streams resources */
+#define ENONET          64 /* Machine is not on the network */
+#define ENOPKG          65 /* Package not installed */
+#define EREMOTE         66 /* Object is remote */
+#define ENOLINK         67 /* Link has been severed */
+#define EADV            68 /* Advertise error */
+#define ESRMNT          69 /* Srmount error */
+#define ECOMM           70 /* Communication error on send */
+#define EPROTO          71 /* Protocol error */
+#define EMULTIHOP       72 /* Multihop attempted */
+#define EDOTDOT         73 /* RFS specific error */
+#define EBADMSG         74 /* Not a data message */
+#define EFSBADCRC       EBADMSG /* Bad CRC detected */
+#define EOVERFLOW       75 /* Value too large for defined data type */
+#define ENOTUNIQ        76 /* Name not unique on network */
+#define EBADFD          77 /* File descriptor in bad state */
+#define EREMCHG         78 /* Remote address changed */
+#define ELIBACC         79 /* Can not access a needed shared library */
+#define ELIBBAD         80 /* Accessing a corrupted shared library */
+#define ELIBSCN         81 /* .lib section in a.out corrupted */
+#define ELIBMAX         82 /* Attempting to link in too many shared libraries */
+#define ELIBEXEC        83 /* Cannot exec a shared library directly */
+#define EILSEQ          84 /* Illegal byte sequence */
+#define ERESTART        85 /* Interrupted system call should be restarted */
+#define ESTRPIPE        86 /* Streams pipe error */
+#define EUSERS          87 /* Too many users */
+#define ENOTSOCK        88 /* Socket operation on non-socket */
+#define EDESTADDRREQ    89 /* Destination address required */
+#define EMSGSIZE        90 /* Message too long */
+#define EPROTOTYPE      91 /* Protocol wrong type for socket */
+#define ENOPROTOOPT     92 /* Protocol not available */
+#define EPROTONOSUPPORT 93 /* Protocol not supported */
+#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
+#define EOPNOTSUPP      95 /* Operation not supported on transport endpoint */
+#define EPFNOSUPPORT    96 /* Protocol family not supported */
+#define EAFNOSUPPORT    97 /* Address family not supported by protocol */
+#define EADDRINUSE      98 /* Address already in use */
+#define EADDRNOTAVAIL   99 /* Cannot assign requested address */
+#define ENETDOWN        100 /* Network is down */
+#define ENETUNREACH     101 /* Network is unreachable */
+#define ENETRESET       102 /* Network dropped connection because of reset */
+#define ECONNABORTED    103 /* Software caused connection abort */
+#define ECONNRESET      104 /* Connection reset by peer */
+#define ENOBUFS         105 /* No buffer space available */
+#define EISCONN         106 /* Transport endpoint is already connected */
+#define ENOTCONN        107 /* Transport endpoint is not connected */
+#define ESHUTDOWN       108 /* Cannot send after transport endpoint shutdown */
+#define ETOOMANYREFS    109 /* Too many references: cannot splice */
+#define ETIMEDOUT       110 /* Connection timed out */
+#define ECONNREFUSED    111 /* Connection refused */
+#define EHOSTDOWN       112 /* Host is down */
+#define EHOSTUNREACH    113 /* No route to host */
+#define EALREADY        114 /* Operation already in progress */
+#define EINPROGRESS     115 /* Operation now in progress */
+#define ESTALE          116 /* Stale file handle */
+#define EUCLEAN         117 /* Structure needs cleaning */
+#define EFSCORRUPTED    EUCLEAN /* Filesystem is corrupted */
+#define ENOTNAM         118 /* Not a XENIX named type file */
+#define ENAVAIL         119 /* No XENIX semaphores available */
+#define EISNAM          120 /* Is a named type file */
+#define EREMOTEIO       121 /* Remote I/O error */
+#define EDQUOT          122 /* Quota exceeded */
+#define ENOMEDIUM       123 /* No medium found */
+#define EMEDIUMTYPE     124 /* Wrong medium type */
+#define ECANCELED       125 /* Operation Canceled */
+#define ENOKEY          126 /* Required key not available */
+#define EKEYEXPIRED     127 /* Key has expired */
+#define EKEYREVOKED     128 /* Key has been revoked */
+#define EKEYREJECTED    129 /* Key was rejected by service */
+#define EOWNERDEAD      130 /* Owner died */
+#define ENOTRECOVERABLE 131 /* State not recoverable */
+#define ERFKILL         132 /* Operation not possible due to RF-kill */
+#define EHWPOISON       133 /* Memory page has hardware error */
+
 
 static inline isize linux_read( u32 fd, u8* buf, usize count ) {
 	return linux_syscall3( 0, fd, (usize)buf, count );
@@ -27,14 +164,80 @@ static inline isize linux_write( u32 fd, const u8* buf, usize count ) {
 	return linux_syscall3( 1, fd, (usize)buf, count );
 }
 
+/* Copied from some header included by linux/fcntl */
+#define O_RDONLY     00
+#define O_WRONLY     01
+#define O_RDWR       02
+#define O_ACCMODE    03
+#define O_CREAT      0100
+#define O_EXCL       0200
+#define O_NOCTTY     0400
+#define O_TRUNC      01000
+#define O_APPEND     02000
+#define O_NONBLOCK   04000
+#define O_DSYNC      010000
+#define FASYNC       020000
+#define O_DIRECT     040000
+#define O_LARGEFILE  0100000
+#define O_DIRECTORY  0200000
+#define O_NOFOLLOW   0400000
+#define O_NOATIME    01000000
+#define O_CLOEXEC    02000000
+#define __O_SYNC     04000000
+#define O_SYNC       (__O_SYNC|O_DSYNC)
+#define O_PATH       010000000
+#define __O_TMPFILE  020000000
+#define O_TMPFILE    (__O_TMPFILE | O_DIRECTORY)
+
+
 static inline isize linux_open( const u8* path, s32 flags, s32 mode ) {
-	return linux_syscall3( 2, (usize)path, (usize)flags, (usize)&mode);
+	return linux_syscall3( 2, (usize)path, (usize)flags, (usize)mode);
 }
 
 static inline isize linux_close( u32 fd ) {
 	return linux_syscall1( 3, fd );
 }
 
+#if ARCH == ARCH_X86_64
+struct stat {
+    u64 st_dev;
+    u64 st_ino;
+    u64 st_nlink;
+
+    u32 st_mode;
+    u32 st_uid;
+    u32 st_gid;
+    u32 __pad0;
+
+    u64 st_rdev;
+
+    s64 st_size;
+    s64 st_blksize;
+    s64 st_blocks;
+
+    u64 st_atime;
+    u64 st_atime_nsec;
+    u64 st_mtime;
+    u64 st_mtime_nsec;
+    u64 st_ctime;
+    u64 st_ctime_nsec;
+
+    s64 __unused[3];
+};
+
+#else 
+#error struct stat is not defined
+#endif
+
+
+static inline isize linux_stat( const char* path, struct stat *statbuf ) {
+	return linux_syscall2( 4, (usize)path, (usize)statbuf );
+}
+
+static inline isize linux_fstat( s32 fd, struct stat *statbuf ) {
+	return linux_syscall2( 5, (usize)fd, (usize)statbuf );
+}
+
 static inline void linux_exit( s32 exitcode ) {
 	(void)linux_syscall1( 60, exitcode );
 	UNREACHABLE;
@@ -45,11 +248,12 @@ static inline void linux_exit( s32 exitcode ) {
 #define LINUX_PROT_WRITE (0x2)
 #define LINUX_PROT_EXEC (0x4)
 
-#define MMAP_MAP_SHARED 0x1 
-#define MMAP_MAP_PRIVATE 0x2
-#define MMAP_MAP_SHARED_VALIDATE 0x3
-#define MMAP_MAP_SHARED_DROPPABLE 0x08
-#define MMAP_MAP_ANONYMOUS 0x20
+#define MMAP_MAP_SHARED (0x1)
+#define MMAP_MAP_PRIVATE (0x2)
+#define MMAP_MAP_SHARED_VALIDATE (0x3)
+#define MMAP_MAP_SHARED_DROPPABLE (0x08)
+#define MMAP_MAP_FIXED (0x10)
+#define MMAP_MAP_ANONYMOUS (0x20)
 
 #define MMAP_MAP_FAILED ((void *)-1)
 
@@ -97,4 +301,8 @@ static inline isize linux_madvise( usize start, usize len, s32 behaviour ) {
 	return linux_syscall3( 11, start, len, (usize)(u32)behaviour );
 }
 
+static inline isize linux_fallocate( s32 fd, s32 mode, usize offset, usize len ) {
+	return linux_syscall4(285, fd, mode, offset, len);
+}
+
 #endif
platform/platform.h
@@ -11,8 +11,8 @@
 #include "platform/common/types.h"
 
 #ifdef NOTLIBC_IMPLEMENT
-	#include PLATFORM_FUNC_HEADER
 	#include PLATFORM_ENTRYPOINT_HEADER
+	#include PLATFORM_FILE_HEADER
 #endif
 
 
testing/tests/013_arena_basic.c
@@ -1,4 +1,4 @@
-#include "memory/arena.h"
+#include "notlibc/core.h"
 
 Arena a = {0};
 
testing/tests/020_fileview.c
@@ -0,0 +1,40 @@
+#include "notlibc/core.h"
+
+void entry(void) {
+
+	FileView fv = {0};
+	STRING( filename, "test.txt" );
+
+	Status s;
+
+	s = FileView_from_path( (String*)&filename, MiB(1), FILEVIEW_OWN_FILE, &fv );
+	assert( S_SUCCESSFUL(s) );
+
+	s = FileView_extend_file( &fv, 5 );
+	assert( S_SUCCESSFUL(s) );
+
+	fv.start->data[0] = 'h';
+	fv.start->data[1] = 'e';
+	fv.start->data[2] = 'l';
+	fv.start->data[3] = 'l';
+	fv.start->data[4] = 'o';
+
+	s = FileView_destroy( &fv );
+	assert( S_SUCCESSFUL(s) );
+
+	mem_set( &fv, sizeof(fv), 0 );
+
+	s = FileView_from_path( (String*)&filename, MiB(1), FILEVIEW_OWN_FILE, &fv );
+	assert( S_SUCCESSFUL(s) );
+
+	assert( fv.start->data[0] == 'h');
+	assert( fv.start->data[1] == 'e');
+	assert( fv.start->data[2] == 'l');
+	assert( fv.start->data[3] == 'l');
+	assert( fv.start->data[4] == 'o');
+
+	s = FileView_destroy( &fv );
+	assert( S_SUCCESSFUL(s) );
+
+	terminate(0);
+}
util/limits.h
@@ -1,7 +1,7 @@
 #ifndef NOTLIBC_HEADER_UTIL_LIMITS_INCLUDED
 #define NOTLIBC_HEADER_UTIL_LIMITS_INCLUDED
 
-#include "../platform/platform.h"
+#include "../platform/common/types.h"
 
 #define  u8_MIN 0
 #define u16_MIN 0
util/mathops.h
@@ -3,6 +3,26 @@
 
 #include "./safemath.h"
 
+static inline u8 u64_is_power_of_two( u64 num ) {
+	return num && !(num & (num - 1));
+}
+
+static inline u8 u32_is_power_of_two( u32 num ) {
+	return num && !(num & (num - 1));
+}
+
+static inline u8 u16_is_power_of_two( u16 num ) {
+	return num && !(num & (num - 1));
+}
+
+static inline u8 u8_is_power_of_two( u8 num ) {
+	return num && !(num & (num - 1));
+}
+
+static inline u8 usize_is_power_of_two( usize num ) {
+	return num && !(num & (num - 1));
+}
+
 static inline Status u64_round_up( u64 number, u64 multiple, u64 *out ) {
 	if( multiple == 0 ) return S_FAILURE | ERR_ARG_2 | ERR_INVALID_ARGUMENT;
 	u64 rem = number%multiple;
@@ -47,6 +67,15 @@ static inline Status u8_round_up( u8 number, u8 multiple, u8 *out ) {
 	return S_SUCCESS;
 }
 
+#if ARCH == ARCH_X86_64
+static inline Status usize_round_up( usize number, usize multiple, usize *out ) {
+	return u64_round_up(number, multiple, out);
+}
+#elif ARCH == ARCH_I386
+static inline Status usize_round_up( usize number, usize multiple, usize *out ) {
+	return u32_round_up(number, multiple, out);
+}
+#endif
 
 static inline Status u64_round_down(u64 number, u64 multiple, u64 *out) {
 	if( multiple == 0 ) return S_FAILURE | ERR_ARG_2 | ERR_INVALID_ARGUMENT;
@@ -72,6 +101,14 @@ static inline Status u8_round_down(u8 number, u8 multiple, u8 *out) {
 	return S_SUCCESS;
 }
 
-
+#if ARCH == ARCH_X86_64
+static inline Status usize_round_down( usize number, usize multiple, usize *out ) {
+	return u64_round_down(number, multiple, out);
+}
+#elif ARCH == ARCH_I386
+static inline Status usize_round_down( usize number, usize multiple, usize *out ) {
+	return u32_round_down(number, multiple, out);
+}
+#endif
 
 #endif
util/safemath.h
@@ -1,7 +1,8 @@
 #ifndef NOTLIBC_HEADER_UTIL_SAFEMATH_INCLUDED
 #define NOTLIBC_HEADER_UTIL_SAFEMATH_INCLUDED
 
-#include "datatypes/common.h"
+#include "platform/common/types.h"
+#include "datatypes/error.h"
 #include "./limits.h"
 
 
util/safemath_generic.h
@@ -1,7 +1,8 @@
 #ifndef NOTLIBC_HEADER_UTIL_SAFEMATH_GENERIC_INCLUDED
 #define NOTLIBC_HEADER_UTIL_SAFEMATH_GENERIC_INCLUDED
 
-#include "datatypes/common.h"
+#include "platform/common/types.h"
+#include "datatypes/error.h"
 #include "./limits.h"
 
 /* Unsigned addition */
test.txt
@@ -0,0 +1,1 @@
+hello
\ No newline at end of file