Implemented int 21h/AH=3A
authorRobert Pengelly <robertapengelly@hotmail.com>
Tue, 6 Aug 2024 16:02:27 +0000 (17:02 +0100)
committerRobert Pengelly <robertapengelly@hotmail.com>
Tue, 6 Aug 2024 16:02:27 +0000 (17:02 +0100)
12 files changed:
build/chimaera.img
build/chimaera.vhd
src/apps/pcomm/Makefile.unix
src/apps/pcomm/Makefile.w32
src/apps/pcomm/del.asm
src/apps/pcomm/pcomm.asm
src/apps/pcomm/rmdir.asm [new file with mode: 0644]
src/kernel/Makefile.unix
src/kernel/Makefile.w32
src/kernel/bootstrap.asm
src/kernel/get.asm [new file with mode: 0644]
src/kernel/int21.asm

index f77702e5bbb893147a8f231df71b79af0ebca794..23b8a081527111d936fcaba4d1c49da9627ee450 100644 (file)
Binary files a/build/chimaera.img and b/build/chimaera.img differ
index 768d5a4138b0ca71e18a031c535a20c76a742a7e..e6582f5ba99b244ea4d253666e25b7b2a31ed547 100644 (file)
Binary files a/build/chimaera.vhd and b/build/chimaera.vhd differ
index b256c626af262c3855f0c69636161d253ab773c8..bdad935d930ca2248e77076b158adb079f0e6251 100644 (file)
@@ -46,7 +46,7 @@ genver: genver.c
        gcc -o $@ $^
 endif
 
-pcomm.com: ../../lib/crt/crt0.o cbreak.o cd.o crlf.o date.o del.o dir.o erase.o exit.o history.o mkdir.o pcomm.o time.o touch.o type.o vector.o writedec.o writehex.o writestr.o xmalloc.o xstrcpy.o ../../lib/crt/libc.a
+pcomm.com: ../../lib/crt/crt0.o cbreak.o cd.o crlf.o date.o del.o dir.o erase.o exit.o history.o mkdir.o pcomm.o rmdir.o time.o touch.o type.o vector.o writedec.o writehex.o writestr.o xmalloc.o xstrcpy.o ../../lib/crt/libc.a
        ../../utils/binutils/slink --oformat msdos -o $@ $^
 
 %.o: %.asm
index ddfdcfc6777767e8a50c8504644fc4e23aca66a0..7f03f20916c60612520c50f26d4c0e6d3a8ee771 100644 (file)
@@ -30,7 +30,7 @@ genhash.exe: genhash.c
 genver.exe: genver.c
        gcc -o $@ $^
 
-pcomm.com: ../../lib/crt/crt0.o cbreak.o cd.o crlf.o date.o del.o dir.o erase.o exit.o history.o mkdir.o pcomm.o time.o touch.o type.o vector.o writedec.o writehex.o writestr.o xmalloc.o xstrcpy.o ../../lib/crt/libc.a
+pcomm.com: ../../lib/crt/crt0.o cbreak.o cd.o crlf.o date.o del.o dir.o erase.o exit.o history.o mkdir.o pcomm.o rmdir.o time.o touch.o type.o vector.o writedec.o writehex.o writestr.o xmalloc.o xstrcpy.o ../../lib/crt/libc.a
        ../../utils/binutils/slink --oformat msdos -o $@ $^
 
 %.o: %.asm
index 154872af396b45574c476e11798860c3e937c634..d9c086e7f9fddcf8a980d999d03090b3eb10b7b6 100644 (file)
@@ -132,7 +132,7 @@ _handler_del.delete:
     mov     ah,     HEX (41)
     mov     dx,     bx
     int     HEX (21)
-    jnc     _handler_del.deleted
+    jnc     _handler_del.close
     
     cmp     ax,     2
     jne     _handler_del.check3
@@ -168,11 +168,16 @@ _handler_del.error:
     call    _writestr
     call    _crlf
     
-    jmp     _handler_del.cleanup
+    jmp     _handler_del.next
 
-_handler_del.deleted:
+_handler_del.close:
 
     pop     bx
+    mov     bx,     ax
+    
+    mov     ah,     HEX (3E)
+    int     HEX (21)
+    
     jmp     _handler_del.next
 
 _handler_del.cleanup:
index 755fc5fa1150f75f6067f88a1b84192f9d79318b..22a54efd188dbc87b775e2eb2003059723e8e854 100644 (file)
@@ -1076,6 +1076,7 @@ _handler_help.msg:
     db      "EXIT       Exit the current shell if it's not the last instance.",             HEX (0D),   HEX (0A)
     db      "MKDIR      Create a new directory.",                                           HEX (0D),   HEX (0A)
     db      "REBOOT     Reboots the machine.",                                              HEX (0D),   HEX (0A)
+    db      "RMDIR      Delete an empty directory.",                                        HEX (0D),   HEX (0A)
     db      "TIME       Displays the system time.",                                         HEX (0D),   HEX (0A)
     db      "TOUCH      Create a new file if it doesn't already exist.",                    HEX (0D),   HEX (0A)
     db      "TYPE       Displays the contents of a text file.",                             HEX (0D),   HEX (0A)
@@ -1307,6 +1308,10 @@ _cmd_table:
     dw      0
     dw      _handler_reboot
     
+    dw      hash_rmdir
+    dw      0
+    dw      _handler_rmdir
+    
     dw      hash_time
     dw      0
     dw      _handler_time
diff --git a/src/apps/pcomm/rmdir.asm b/src/apps/pcomm/rmdir.asm
new file mode 100644 (file)
index 0000000..bc06adc
--- /dev/null
@@ -0,0 +1,223 @@
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; @file            type.asm
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;******************************************************************************
+; @function         _handler_rmdir
+;******************************************************************************
+global      _handler_rmdir
+_handler_rmdir:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     4
+    
+    push    ax
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    mov     word ptr [bp - 4],      0
+    mov     word ptr [bp - 2],      0
+    
+    cmp     byte ptr [bx],      0
+    jne     _handler_rmdir.ok
+    
+    mov     bx,     offset _err_invalid
+    call    _writestr
+    
+    jmp     _handler_rmdir.done
+
+_handler_rmdir.ok:
+
+    push    bx
+    
+    call    _strlen
+    add     sp,     2
+    
+    mov     di,     offset _cmdline
+    mov     si,     bx
+    
+    mov     cx,     ax
+    rep     movsb
+    
+    xor     al,     al
+    stosb
+    
+    mov     bx,     offset _cmdline
+
+_handler_rmdir.store_arg:
+
+    cmp     byte ptr [bx],      0
+    je      _handler_rmdir.next
+    
+    mov     si,     bx
+    push    si
+    
+    mov     ax,     offset _vec_files
+    push    ax
+    
+    call    _vec_push
+    add     sp,     4
+
+_handler_rmdir.check:
+
+    mov     ax,     ' '
+    push    ax
+    
+    mov     si,     bx
+    push    si
+    
+    call    _strchr
+    add     sp,     4
+    
+    and     ax,     ax
+    jz      _handler_rmdir.next
+    
+    mov     bx,     ax
+    mov     byte ptr [bx],      0
+    
+    inc     bx
+
+_handler_rmdir.skip:
+
+    cmp     byte ptr [bx],      0
+    je      _handler_rmdir.next
+    
+    cmp     byte ptr [bx],      ' '
+    ja      _handler_rmdir.store_arg
+    
+    inc     bx
+    jmp     _handler_rmdir.skip
+
+_handler_rmdir.next:
+
+    mov     ax,     word ptr [bp - 4]
+    inc     ax
+    
+    cmp     ax,     cs:[_vec_files + 4]
+    ja      _handler_rmdir.cleanup
+    
+    mov     word ptr [bp - 4],      ax
+    dec     ax
+    
+    xor     dx,     dx
+    
+    mov     cx,     2
+    mul     cx
+    
+    mov     bx,     ax
+    push    es
+    
+    mov     ax,     cs:[_vec_files + 0]
+    mov     es,     ax
+    
+    mov     ax,     es:[bx]
+    mov     bx,     ax
+    
+    pop     es
+
+_handler_rmdir.delete:
+
+    mov     ah,     HEX (3A)
+    mov     dx,     bx
+    int     HEX (21)
+    jnc     _handler_rmdir.next
+    
+    mov     cx,     bx
+    
+    cmp     ax,     3
+    jne     _handler_rmdir.check3
+    
+    mov     bx,     offset _err_failed
+    jmp     _handler_rmdir.error
+
+_handler_rmdir.check3:
+
+    cmp     ax,     16
+    jne     _handler_rmdir.unhandled
+    
+    mov     bx,     offset _err_current
+    jmp     _handler_rmdir.error
+
+_handler_rmdir.unhandled:
+
+    mov     bx,     offset _err_unhandled
+
+_handler_rmdir.error:
+
+    cmp     ax,     3
+    jne     _handler_rmdir.error2
+    
+    xchg    bx,     cx
+    call    _writestr
+    
+    xchg    bx,     cx
+
+_handler_rmdir.error2:
+
+    call    _writestr
+    
+    cmp     ax,     16
+    jne     _handler_rmdir.next
+    
+    mov     bx,     cx
+    
+    call    _writestr
+    call    _crlf
+    
+    jmp     _handler_rmdir.next
+
+_handler_rmdir.cleanup:
+
+    mov     ax,     cs:[_vec_files + 0]
+    push    ax
+    
+    call    _free
+    add     sp,     2
+    
+    mov     ax,     cs
+    mov     es,     ax
+    
+    mov     di,     offset _vec_files
+    xor     al,     al
+    
+    mov     cx,     6
+    rep     stosb
+
+_handler_rmdir.done:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    pop     ax
+    
+    add     sp,     4
+    pop     bp
+    
+    ret
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Data area.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+_vec_files:                     db      6       dup (0)
+_cmdline:                       db      256     dup (0)
+
+_err_invalid:                   db      "Invalid number of parameters",     HEX (0D),   HEX (0A),   HEX (00)
+
+_err_failed:                    db      " is either an invalid directory, not a directory or is not empty",     HEX (0D),   HEX (0A),   HEX (00)
+_err_current:                   db      "Attempt to remove current directory: ",                                HEX (00)
+
+_err_unhandled:                 db      "Unhandled error code",     HEX (0D),   HEX (0A),   HEX (00)
index ec98783bd772917d925b42b96c7cc295f6fe9c2f..b8922e9a3f4f784d157673d2fd25b4d410a46c0a 100644 (file)
@@ -13,7 +13,7 @@ clean:
        for f in *.lst; do if [ -f $$f ]; then rm -rf $$f; fi; done
        if [ -f kernel.sys ]; then rm -rf kernel.sys; fi
 
-kernel.sys: bootstrap.o crlf.o disk.o divide.o error.o fat.o file.o find.o int21.o int23.o invalid.o kernel.o kmalloc.o krealloc.o make.o mangle.o mem.o prog.o query.o search.o vector.o walk.o writechr.o writedec.o writehex.o writestr.o ../lib/crt/libc.a
+kernel.sys: bootstrap.o crlf.o disk.o divide.o error.o fat.o file.o find.o get.o int21.o int23.o invalid.o kernel.o kmalloc.o krealloc.o make.o mangle.o mem.o prog.o query.o search.o vector.o walk.o writechr.o writedec.o writehex.o writestr.o ../lib/crt/libc.a
        ../utils/binutils/slink --oformat binary -o $@ $^
 
 %.o: %.asm
index 202bd392b16cc8e7b228db605b4f5cdfc7d0e93d..d867896ee2325811fed3e4fdd1aaf8335cf0e316 100644 (file)
@@ -13,7 +13,7 @@ clean:
        for %%f in (*.lst) do ( if exist %%f ( del /q %%f ) )
        if exist kernel.sys ( del /q kernel.sys )
 
-kernel.sys: bootstrap.o crlf.o disk.o divide.o error.o fat.o file.o find.o int21.o int23.o invalid.o kernel.o kmalloc.o krealloc.o make.o mangle.o mem.o prog.o query.o search.o vector.o walk.o writechr.o writedec.o writehex.o writestr.o ../lib/crt/libc.a
+kernel.sys: bootstrap.o crlf.o disk.o divide.o error.o fat.o file.o find.o get.o int21.o int23.o invalid.o kernel.o kmalloc.o krealloc.o make.o mangle.o mem.o prog.o query.o search.o vector.o walk.o writechr.o writedec.o writehex.o writestr.o ../lib/crt/libc.a
        ../utils/binutils/slink --oformat binary -o $@ $^
 
 %.o: %.asm
index 28231f01f4b5babba8063d8635674855b0fa4c0f..3dad07f0c04f3037e6d6c35375e0cb65d6d69a80 100644 (file)
@@ -303,7 +303,9 @@ _calc_offsets:
     ;; Calculate the sector shift.
     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     xor     cx,     cx
+    
     xchg    ax,     cx
+    inc     cx
 
 _secshift:
 
diff --git a/src/kernel/get.asm b/src/kernel/get.asm
new file mode 100644 (file)
index 0000000..9b84031
--- /dev/null
@@ -0,0 +1,208 @@
+;******************************************************************************
+; @file             search.asm
+;******************************************************************************
+%ifndef     HEX
+% define        HEX(y)                  0x##y
+%endif
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;; Include our fat.inc file for our BPB offsets.
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+%include    "fat.inc"
+
+;******************************************************************************
+; @function         _get_files
+;******************************************************************************
+global      _get_files
+_get_files:
+
+    push    bp
+    
+    mov     bp,     sp
+    sub     sp,     34
+    
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    mov     word ptr [bp - 32],     0
+    
+    mov     word ptr [bp - 20],     0
+    mov     word ptr [bp - 16],     0
+    
+    mov     bx,     ax
+    or      bx,     dx
+    
+    and     bx,     bx
+    jnz     _get_files.not_root
+    
+    mov     ax,     cs:[_root_start]
+    mov     dx,     cs:[_root_start + 2]
+
+_get_files.got_root:
+
+    mov     word ptr [bp - 30],     1
+    mov     word ptr [bp - 24],     1
+    
+    mov     word ptr [bp - 28],     ax
+    mov     word ptr [bp - 26],     dx
+    
+    mov     ax,     32
+    xor     dx,     dx
+    
+    mov     cx,     cs:[_root_entries]
+    mul     cx
+    
+    mov     cx,     cs:[_bytes_per_sector]
+    div     cx
+    
+    xchg    cx,     ax
+    dec     cx
+    
+    xor     dx,     dx
+    mov     word ptr [bp - 22],     cx
+    
+    mov     ax,     word ptr [bp - 28]
+    mov     dx,     word ptr [bp - 26]
+    
+    mov     word ptr [bp - 6],      ax
+    mov     word ptr [bp - 4],      dx
+    
+    jmp     _get_files.read
+
+_get_files.not_root:
+
+    mov     word ptr [bp - 30],     0
+    mov     word ptr [bp - 24],     1
+    
+    mov     word ptr [bp - 28],     ax
+    mov     word ptr [bp - 26],     dx
+    
+    call    cs:[_convert_cluster]
+    jc      _get_files.done
+    
+    mov     word ptr [bp - 6],      ax
+    mov     word ptr [bp - 4],      dx
+    
+    xor     ch,     ch
+    mov     cl,     cs:[_sectors_per_cluster]
+    
+    mov     word ptr [bp - 34],     cx
+    dec     word ptr [bp - 34]
+
+_get_files.read:
+
+    mov     bx,     cs:[_disk_scratch]
+    mov     es,     bx
+    xor     bx,     bx
+    
+    mov     ax,     word ptr [bp - 6]
+    mov     dx,     word ptr [bp - 4]
+    
+    mov     cx,     word ptr [bp - 24]
+    call    _read_sectors
+    
+    mov     ax,     cs:[_bytes_per_sector]
+    xor     dx,     dx
+    
+    mov     cx,     32
+    div     cx
+    xchg    cx,     ax
+    
+    xor     di,     di
+
+_get_files.search:
+
+    cmp     byte ptr es:[di],       0
+    je      _get_files.advance
+    
+    cmp     byte ptr es:[di],       HEX (E5)
+    je      _get_files.advance
+    
+    inc     word ptr [bp - 32]
+
+_get_files.advance:
+
+    add     di,     32
+    loop    _get_files.search
+    
+    cmp     word ptr [bp - 30],     1
+    jne     _get_files.check
+    
+    mov     ax,     word ptr [bp - 22]
+    
+    and     ax,     ax
+    jz      _get_files.done
+    
+    dec     ax
+    mov     word ptr [bp - 22],     ax
+    
+    mov     ax,     word ptr [bp - 6]
+    mov     dx,     word ptr [bp - 4]
+    
+    add     ax,     word ptr [bp - 24]
+    adc     dx,     0
+    
+    mov     word ptr [bp - 6],      ax
+    mov     word ptr [bp - 4],      dx
+    
+    jmp     _get_files.read
+
+_get_files.check:
+
+    mov     ax,     word ptr [bp - 34]
+    
+    and     ax,     ax
+    jz      _get_files.next_clust
+    
+    dec     ax
+    mov     word ptr [bp - 34],     ax
+    
+    mov     ax,     word ptr [bp - 6]
+    mov     dx,     word ptr [bp - 4]
+    
+    add     ax,     word ptr [bp - 24]
+    adc     dx,     0
+    
+    mov     word ptr [bp - 6],      ax
+    mov     word ptr [bp - 4],      dx
+    
+    jmp     _get_files.read
+
+_get_files.next_clust:
+
+    mov     ax,     word ptr [bp - 28]
+    mov     dx,     word ptr [bp - 26]
+    
+    call    cs:[_next_cluster]
+    jmp     _get_files.not_root
+
+_get_files.done:
+
+    mov     ax,     word ptr [bp - 32]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore registers.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Clean up the stack and restore the base pointer.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    add     sp,     34
+    pop     bp
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Return to caller.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ret
index 6f189c3e05304180efa909f077739888d9522d91..8a0b2ae1be57987b5c490da064f09544d1ed568f 100644 (file)
@@ -830,6 +830,12 @@ _int21_dispatch.list:
     db      HEX (39)
     dw      _int21_39
     
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Delete Directory (rmdir).
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    db      HEX (3A)
+    dw      _int21_3A
+    
     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
     ;; Set Current Directory.
     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@@ -1764,6 +1770,296 @@ _int21_39.done:
     
     jmp     iretc
 
+;******************************************************************************
+; @function         _int21_3A
+; @brief            Delete Directory (rmdir)
+;
+; @in               DS:DX -> Pointer to ASCIIZ path name.
+;******************************************************************************
+_int21_3A:
+
+    push    bx
+    push    cx
+    push    dx
+    push    si
+    push    di
+    push    es
+    push    ds
+    
+    mov     si,     dx
+    
+    call    _get_disk_info
+    jc      _int21_3A.error_path
+    
+    mov     di,     si
+    
+    call    _walk_path
+    jc      _int21_3A.error_path
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Mangle the file name and search for it in the file system.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    call    _mangle_dos_name
+    jc      _int21_3A.error_path
+    
+    call    _search_dos_dir
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; If the carry flag was set then the entry doesn't exists.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jc      _int21_3A.error_path
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Transfer the offset in ax to the si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     si,     ax
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Check if the entry is a directory.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     cl,     cs:[si + 8]
+    
+    test    cl,     HEX (10)
+    jz      _int21_3A.error_path
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Check the starting cluster is the root cluster.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[si + 0]
+    mov     dx,     cs:[si + 2]
+    
+    cmp     dx,     cs:[_root_cluster + 2]
+    ja      _int21_3A.get_files
+    
+    cmp     dx,     cs:[_root_cluster + 2]
+    jne     _int21_3A.error_path
+    
+    cmp     ax,     cs:[_root_cluster]
+    jbe     _int21_3A.error_path
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Check if the starting cluster is the current cluster.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    cmp     dx,     cs:[_curr_cluster + 2]
+    ja      _int21_3A.get_files
+    
+    cmp     dx,     cs:[_curr_cluster + 2]
+    jne     _int21_3A.curr_dir
+    
+    cmp     ax,     cs:[_curr_cluster]
+    je      _int21_3A.curr_dir
+
+_int21_3A.get_files:
+
+    call    _get_files
+    
+    cmp     ax,     2
+    jb      _int21_3A.error_path
+    
+    sub     ax,     2
+    
+    and     ax,     ax
+    jnz     _int21_3A.error_path
+
+_int21_3A.remove:
+
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Get the starting cluster again.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[si + 0]
+    mov     dx,     cs:[si + 2]
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; We'll use the cx register as a counter.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     cx,     cx
+
+_int21_3A.clear:
+
+    push    ax
+    push    dx
+    
+    call    cs:[_next_cluster]
+    jc      _int21_3A.clear_final
+    
+    mov     si,     ax
+    mov     di,     dx
+    
+    pop     dx
+    pop     ax
+    
+    push    bx
+    push    cx
+    
+    xor     bx,     bx
+    xor     cx,     cx
+    
+    call    cs:[_update_cluster]
+    
+    pop     cx
+    pop     bx
+    
+    inc     cx
+    
+    mov     ax,     si
+    mov     dx,     si
+    
+    jmp     _int21_3A.clear
+
+_int21_3A.clear_final:
+
+    inc     cx
+    
+    pop     dx
+    pop     ax
+    
+    push    bx
+    push    cx
+    
+    xor     bx,     bx
+    xor     cx,     cx
+    
+    call    cs:[_update_cluster]
+    pop     cx
+    pop     bx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the si register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Preserve the count.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    push    cx
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Update the entry on disk.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[si + 10]
+    mov     dx,     cs:[si + 12]
+    
+    mov     cx,     cs:[si + 14]
+    mov     di,     cs:[si + 16]
+    
+    push    es
+    push    bx
+    push    ax
+    push    dx
+    push    cx
+    
+    mov     bx,     cs:[_disk_scratch]
+    mov     es,     bx
+    
+    xor     bx,     bx
+    call    _read_sectors
+    
+    mov     byte ptr es:[di + 0],       HEX (E5)
+    pop     cx
+    pop     dx
+    pop     ax
+    
+    xor     bx,     bx
+    call    _write_sectors
+    
+    pop     bx
+    pop     es
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Restore the value in the cx register.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    pop     si
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Check if we have an info sector.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    mov     ax,     cs:[_info_sector]
+    
+    and     ax,     ax
+    jz      _int21_41.done
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Update the free clusters.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    xor     dx,     dx
+    
+    add     ax,     cs:[_hidden_sectors]
+    adc     dx,     cs:[_hidden_sectors + 2]
+    
+    mov     bx,     cs:[_disk_scratch]
+    mov     es,     bx
+    xor     bx,     bx
+    
+    mov     cx,     1
+    call    _read_sectors
+    
+    mov     di,     HEX (01E0)
+    
+    mov     ax,     es:[di + 8]
+    mov     dx,     es:[di + 10]
+    
+    add     ax,     si
+    adc     dx,     0
+    
+    mov     es:[di + 8],    ax
+    mov     es:[di + 10],   dx
+    
+    mov     ax,     cs:[_info_sector]
+    xor     dx,     dx
+    
+    add     ax,     cs:[_hidden_sectors]
+    adc     dx,     cs:[_hidden_sectors + 2]
+    
+    mov     cx,     1
+    call    _write_sectors
+    
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    ;; Jump to done.
+    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+    jmp     _int21_3A.done
+
+_int21_3A.error_path:
+
+    mov     ax,     3
+    jmp     _int21_3A.error
+
+_int21_3A.curr_dir:
+
+    mov     ax,     16
+
+_int21_3A.error:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    stc
+    jmp     iretc
+
+_int21_3A.done:
+
+    pop     ds
+    pop     es
+    pop     di
+    pop     si
+    pop     dx
+    pop     cx
+    pop     bx
+    
+    xor     ax,     ax
+    clc
+    
+    jmp     iretc
+
 ;******************************************************************************
 ; @function         _int21_3B
 ; @brief            Set Current Directory