244 lines
4.7 KiB
NASM
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
|