diff --git a/src/constants.asm b/src/constants.asm index d5f70ee..e40e4d8 100644 --- a/src/constants.asm +++ b/src/constants.asm @@ -8,6 +8,7 @@ section .rodata NR_fstat equ 5 NR_lstat equ 6 NR_exit equ 60 + NR_creat equ 85 NR_umask equ 95 ; file descriptors diff --git a/src/file.asm b/src/file.asm index 53d0941..6242ff5 100644 --- a/src/file.asm +++ b/src/file.asm @@ -54,7 +54,7 @@ section .text ;----- fopen(*file[], char mode) -----; ; Opens a file -; Return value: Pointer to opened file pointer, 0 (EOS) otherwise. +; 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 @@ -68,6 +68,82 @@ section .text ; 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 + mov rax, 1 + jz %%createFile + jmp %1 + %%createFile: + push rsi + push rdi + call umask_get + pop rdi + push rdi + not rax + mov rsi, 00666q + 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(file) -----; @@ -96,4 +172,15 @@ fclose: ; rax* (ret) ; rdi (arg) Pointer to string holding (path+)file name fexist: + 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: ret diff --git a/src/tests.asm b/src/tests.asm index 98e3ca8..513cf02 100644 --- a/src/tests.asm +++ b/src/tests.asm @@ -123,6 +123,8 @@ section .rodata TEST_atoi equ 1 TEST_itoa equ 1 TEST_utoa equ 1 + ;file.asm + TEST_fopen equ 1 ;Includes fclose ;;; ;;; Global test messages @@ -315,13 +317,18 @@ section .rodata ;utoa() addTestHeader(_utoa, "utoa") addTest(utoa1, "// See printf outputs") - ;fopen() - ;fclose() - ;fexist() + ;fopen() / fclose() / fexist() + addTestHeader(_fopen, "fopen") + addTest(fexist1, "fexist(''testfile_1.txt'')") + addTest(fopen1, "fp1 = fopen(''testfile_1.txt'', 'w')") + addTest(fclose1, "fclose(fp1)") + addTest(fexist2, "fexist(''testfile_2.txt'')") + file1 db "testfile_1.txt",EOS section .bss strBuff1 resb 64 strBuff2 resb 64 + fp1 resq 1 section .text global _start @@ -1118,6 +1125,34 @@ _start: printTest(utoa1) %endif +;--- fopen() / fclose() / fexist() +%if TEST_fopen + printTestHeader(_fopen) + + ; TEST 1 + printTest(fexist1) + lea rdi, [rel file1] + call fexist + assert_eq(0) ;another bad test since it could exist + + printTest(fopen1) + lea rdi, [rel file1] + mov rsi, 'w' + call fopen + mov [fp1], rax + assert_more(0) + + printTest(fclose1) + mov rdi, [fp1] + call fclose + assert_eq(0) + + printTest(fexist2) + lea rdi, [rel file1] + call fexist + assert_eq(1) +%endif + ;;; ;;; TEST RESULTS ;;;