%include "src/constants.asm" extern __INTERNAL_fmt extern strlen extern umask_get section .rodata ; Open flags O_ACCMODE equ 00000003q O_RDONLY equ 00000000q O_WRONLY equ 00000001q O_RDWR equ 00000002q O_CREAT equ 00000100q ;create if not exist O_EXCL equ 00000200q ;fail if file exists and O_EXCL+O_CREAT set O_NOCTTY equ 00000400q O_TRUNC equ 00001000q O_APPEND equ 00002000q O_NONBLOCK equ 00004000q O_DSYNC equ 00010000q FASYNC equ 00020000q O_DIRECT equ 00040000q O_LARGEFILE equ 00100000q O_DIRECTORY equ 00200000q O_NOFOLLOW equ 00400000q O_NOATIME equ 01000000q O_CLOEXEC equ 02000000q __O_SYNC equ 04000000q O_SYNC equ (__O_SYNC | O_DSYNC) O_PATH equ 01000000q __O_TMPFILE equ 02000000q O_TMPFILE equ (__O_TMPFILE | O_DIRECTORY) O_NDELAY equ O_NONBLOCK ; Permission flags S_IXOTH equ 00001q ;o=x S_IWOTH equ 00002q ;o=w S_IROTH equ 00004q ;o=r S_IRWXO equ 00007q ;o=rwx S_IXGRP equ 00010q ;g=x S_IWGRP equ 00020q ;g=w S_IRGRP equ 00040q ;g=r S_IRWXG equ 00070q ;g=rwx S_IXUSR equ 00100q ;u=x S_IWUSR equ 00200q ;u=w S_IRUSR equ 00400q ;u=r S_IRWXU equ 00700q ;u=rwx S_ISVIX equ 0001000q ;sticky bit S_ISGID equ 0002000q ;set-group-ID bit S_ISUID equ 0004000q ;set-user-ID bit section .bss section .text global fopen global fclose global fexist global fwrite ;----- fopen(*file[], char mode) -----; ; Opens a file ; Return value: Pointer to opened file pointer, -errno otherwise ; Possible modes: ; 'r' Read-only, file must exist ; 'w' Write-only. Creates empty file or truncates an existing file ; 'a' Append. Creates file if it does not exist ; 'R' Read+write, file must exist ; 'W' Read+write. Creates empty file or truncates an existing file ; 'A' Read+append. Creates file if it does not exist ; Invalid mode will also return 0 (EOS) ; Used registers: ; rax* (ret) ; rdi (arg) Pointer to string holding (path+)file name ; rsi Mode to open the file with (see description above) fopen: %macro createFile 1 push rdi push rsi call fexist pop rsi pop rdi test rax, 1 jz %%createFile jmp %1 %%createFile: push rsi push rdi call umask_get pop rdi push rdi not rax mov rsi, 0666q and rsi, rax mov rax, NR_creat syscall pop rdi pop rsi %endmacro ;;; ;;; ENTRY ;;; sub rsp, SIZE_QWORD cmp sil, 'r' je .setMode_r cmp sil, 'w' je .setMode_w cmp sil, 'a' je .setMode_a cmp sil, 'R' je .setMode_R cmp sil, 'W' je .setMode_W cmp sil, 'A' je .setMode_A mov rax, -EINVAL jmp .quit .setMode_r: mov rsi, O_RDONLY jmp .open .setMode_w: createFile .open_w .open_w: mov rsi, O_WRONLY | O_TRUNC jmp .open .setMode_a: createFile .open_a .open_a: mov rsi, O_WRONLY | O_APPEND jmp .open .setMode_R: mov rsi, O_RDWR jmp .open .setMode_W: createFile .open_W .open_W: mov rsi, O_RDWR | O_TRUNC jmp .open .setMode_A: createFile .open_A .open_A: mov rsi, O_RDWR | O_APPEND jmp .open .open: mov rax, NR_open syscall .quit: add rsp, SIZE_QWORD ret ;----- fclose(*filePointer) -----; ; Closes an opened file ; Return value: 0 if file closed. Negative error number if an error occured ; Used registers: ; rax* (ret) ; rdi (arg) Pointer to opened file fclose: sub rsp, SIZE_QWORD cmp rdi, 3 jl .invalid_fd ;disallow closing stdin,stdout,stderr mov rax, NR_close syscall jmp .quit .invalid_fd: mov rax, -EINVAL .quit: add rsp, SIZE_QWORD ret ;----- fexist(*file[]) -----; ; Checks if given file exists (attempts to open the file) ; Return value: 1- File exists. 0- File does not exist or is a directory ; Used registers: ; rax* (ret) ; rdi (arg) Pointer to string holding (path+)file name fexist: sub rsp, SIZE_QWORD mov rsi, 'r' call fopen test rax, rax js .not_exist mov rdi, rax call fclose mov rax, 1 jmp .quit .not_exist: xor rax, rax .quit: add rsp, SIZE_QWORD ret ;--- fwrite(*filePointer, *data[], ...) -----; ; Writes data to given file. Allows format specifiers and variable arguments (see `__INTERNAL_fmt` for supported specifiers) ; Return value: Length of given string(data[]), 0 if nothing was written (eg invalid file or file not writable, or data[] is empty) ; Used registers: ; rax* (ret) ; rdi (arg) Pointer to file ; rsi (arg) Data to write fwrite: push rbp mov rbp, rsp cmp rdi, 2 jg .cnt xor rax, rax leave ret .cnt: mov rax, rdi mov rdi, rsi mov rsi, rdx mov rdx, rcx mov rcx, r8 mov r8, r9 mov r9, [rbp + RBP_OFFSET_CALLER] call __INTERNAL_fmt leave ret