Commit 4b7cfb8
Changed files (18)
fs
platform
common
linux
testing
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