%include "src/constants.asm" extern __INTERNAL_fmt extern strlen extern umask_get section .text global stat global lstat global fgettype global fgetmod global fopen global fclose global fexist global fwrite ;----- stat(*file[], *statBuffer[]) -----; ; Gets information from a file, stores it into statBuffer[] ; Return value: 0 if stats received, -errno otherwise ; Used registers: ; rax* (ret) ; rdi* (arg) Pointer to file ; rsi* arg for syscall NR_newfstatat ; rdx* arg for syscall NR_newfstatat ; r10* arg(flag) for syscall NR_newfstatat stat: sub rsp, SIZE_QWORD mov rax, NR_newfstatat mov rdx, rsi mov rsi, rdi mov rdi, AT_FDCWD xor r10, r10 syscall add rsp, SIZE_QWORD ret ;----- lstat(*file[], *statBuffer[]) -----; ; Same as stat, except do not follow links lstat: sub rsp, SIZE_QWORD mov rax, NR_newfstatat mov rdx, rsi mov rsi, rdi mov rdi, AT_FDCWD mov r10, AT_SYMLINK_NOFOLLOW syscall add rsp, SIZE_QWORD ret ;----- fgettype(*statBuffer[]) -----; ; Gets file type from stat buffer ; Return value: File type or -EINVAL if statBuffer is invalid (first bit is 0) ; See src/constants/file.asm for file types (S_IFxxx, eg S_IFREG for regular files) ; Used registers: ; rax* (ret) ; rdi (arg) Pointer to statBuffer[] fgettype: cmp byte [rdi], 0 jne .buffok mov rax, -EINVAL ret .buffok: mov eax, [rdi + ST_MODE] and eax, 0xF000 ret ;----- fgetmod(*statBuffer[]) -----; ; Gets file mode bits (file permissions) from stat buffer ; Return value: Permissions of given file or -EINVAL if statBuffer is invalid (first bit is 0) ; Used registers: ; rax* (ret) ; rdi (arg) Pointer to stat buffer fgetmod: cmp byte [rdi], 0 jne .buffok mov rax, -EINVAL ret .buffok: mov eax, [rdi + ST_MODE] and eax, 0x0FFF ret ;----- 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 0 push rdi push rsi call fexist pop rsi pop rdi test rax, 1 jz %%createFile jmp %%cnt %%createFile: push rsi push rdi call umask_get pop rdi push rdi not rax mov rsi, DEF_MODE_FILE and rsi, rax mov rax, NR_creat syscall pop rdi pop rsi %%cnt: %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 mov rsi, O_WRONLY | O_TRUNC jmp .open .setMode_a: createFile mov rsi, O_WRONLY | O_APPEND jmp .open .setMode_R: mov rsi, O_RDWR jmp .open .setMode_W: createFile mov rsi, O_RDWR | O_TRUNC jmp .open .setMode_A: createFile 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