Files
klibc/src/file.asm

244 lines
4.7 KiB
NASM

%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