Subversion Repositories Kolibri OS

Compare Revisions

No changes between revisions

Regard whitespace Rev 9046 → Rev 9047

/kernel/branches/kolibrios-pe-clevermouse/fs/fs_lfn.inc
0,0 → 1,794
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
ERROR_SUCCESS = 0
ERROR_DISK_BASE = 1
ERROR_UNSUPPORTED_FS = 2
ERROR_UNKNOWN_FS = 3
ERROR_PARTITION = 4
ERROR_FILE_NOT_FOUND = 5
ERROR_END_OF_FILE = 6
ERROR_MEMORY_POINTER = 7
ERROR_DISK_FULL = 8
ERROR_FS_FAIL = 9
ERROR_ACCESS_DENIED = 10
ERROR_DEVICE = 11
 
maxPathLength = 1000h
 
image_of_eax EQU esp+32
image_of_ebx EQU esp+20
 
; ; System function 70 security check
; align 4
; proc file_system_is_operation_safe stdcall, inf_struct_ptr: dword
; ; in:
; ; inf_struct_ptr = pointer to information structure was given to sysfn70
; ; out: ZF = 1 if operation is safe
; ; ZF = 0 if operation can cause kernel crash
; push ebx ecx edx
; xor ecx, ecx ; ecx - length of target buffer
 
; mov ebx, [inf_struct_ptr]
; mov edx, [ebx + 16] ; base of target buffer
 
; cmp dword [ebx], 0 ; if 70.0
; jnz .case1
; mov ecx, dword [ebx + 12]
; jmp .end_switch
 
; .case1:
; cmp dword [ebx], 1 ; if 70.1
; jnz .case2_3
; ;mov ecx, 32
; cmp dword [ebx + 8], 1 ; check encoding
; jbe .case1_304 ; if encdoing <= 1 i.e cpp866
; mov ecx, 560 ; if unicode then bdvk block len is 560 bytes
; jmp .case1_end
; .case1_304:
; mov ecx, 304 ; if cp866 then bdvk block len is 304 bytes
; .case1_end:
; imul ecx, dword [ebx + 12] ; multiply bdvk length by their count
; add ecx, 32 ; add result header len
; jmp .end_switch
 
; .case2_3:
; cmp dword [ebx], 3
; ja .case5 ; if subfn > 3
; mov ecx, dword [ebx + 12]
; jmp .end_switch
 
; .case5:
; cmp dword [ebx], 5
; jnz .case6
; mov ecx, 40
; jmp .end_switch
 
; .case6:
; cmp dword [ebx], 6
; jnz .switch_none
; mov ecx, 32
; jmp .end_switch
 
; .switch_none:
; mov ecx, 1
; test ecx, ecx
; jmp .ret
; .end_switch:
; ;;
; stdcall is_region_userspace, edx, ecx
; .ret:
; pop edx ecx ebx
; ret
; endp
 
; syscall_fileSystemUnicode: ; with user pointer correctness checking
; ; in: ebx -> f.80 parameter structure
; stdcall file_system_is_operation_safe, ebx
; jz @f
 
; DEBUGF 1, "sysfn80 addr error\n"
; mov dword [image_of_eax], ERROR_MEMORY_POINTER
; ret
; @@:
; jmp fileSystemUnicode
 
; temporarily commented out cause acpi driver (drivers/devman) uses sysfn70 via 0x40
; so because drivers it kernel space, pointer checking fails
; TODO solution: add filesystem functions without pointer checking to kernel exports
; and make the driver use them, not int 0x40
; syscall_fileSystemUnicode commented out for the same reason
; syscall_file_system_lfn: ; with user pointer correctness checking
; ; in: ebx -> f.70 parameter structure
; stdcall file_system_is_operation_safe, ebx
; jz @f
 
; DEBUGF 1, "sysfn70 addr error\n"
; mov dword [image_of_eax], ERROR_MEMORY_POINTER
; ret
; @@:
; jmp file_system_lfn
 
 
; System function 70
 
file_system_lfn_protected:
pushad
call protect_from_terminate
call file_system_lfn
call unprotect_from_terminate
popad
mov [image_of_eax], eax
mov [image_of_ebx], ebx
ret
 
fileSystemUnicode:
; in: ebx -> f.80 parameter structure
mov edi, [ebx+20]
mov esi, [ebx+24]
jmp @f
 
file_system_lfn:
; in: ebx -> f.70 parameter structure
xor edi, edi
lea esi, [ebx+20]
cmp byte [esi], 0
jnz @f
mov esi, [ebx+21]
@@:
cmp word [esi], '/'
jnz @f
cmp edi, 2
jnz .rootdir
cmp dword[esi], '/'
jz .rootdir
@@:
stdcall kernel_alloc, maxPathLength
push eax ebx
xchg eax, edi
call getFullPath
pop ebx ebp
test eax, eax
jz .notfound
cmp dword[ebx], 7 ; start application
jnz @f
mov edx, [ebx+4]
mov ecx, [ebx+8]
mov ebx, ebp
call fs_execute
mov [image_of_eax], eax
ret
 
@@:
lea esi, [ebp+2]
mov ax, [esi]
or ax, 2020h
cmp ax, 'cd'
jz .CD
call dyndisk_handler ; not returns if success
.notfound:
stdcall kernel_free, ebp
mov dword[image_of_eax], ERROR_FILE_NOT_FOUND
ret
 
.CD:
add esi, 2
xor eax, eax
lodsb ; disk number
sub eax, '0'
cmp eax, 10
jnc .notfound
mov edi, eax
lodsb
test eax, eax
jz .maindir
cmp al, '/'
jnz .notfound
lodsb ; partition number
test eax, eax
jz .maindir
cmp al, '1'
jnz .notfound
cmp byte [esi], '/'
jnz @f
inc esi
@@:
call reserve_cd
mov eax, edi
bt eax, 0
setc [DiskNumber]
bt eax, 1
setc [ChannelNumber]
inc [ChannelNumber]
inc eax
mov [cdpos], eax
call reserve_cd_channel
mov eax, edi
not eax
and eax, 3
shl eax, 1
inc eax
shr edi, 2
mov dword[image_of_eax], ERROR_FILE_NOT_FOUND
bt [edi*5+DRIVE_DATA+1], ax
jnc @f
mov ecx, [ebx+12]
mov edx, [ebx+16]
mov eax, [ebx]
mov dword[image_of_eax], ERROR_UNSUPPORTED_FS
cmp eax, fs_NumCdServices
jae @f
add ebx, 4
push ebp
call dword[fs_CdServices + eax*4]
pop ebp
mov [image_of_eax], eax
mov [image_of_ebx], ebx
@@:
call free_cd_channel
and [cd_status], 0
stdcall kernel_free, ebp
ret
 
.nextCD:
test eax, eax ; partition number
jnz @f
inc eax ; /cdX/1
ret
 
@@:
stc
ret
 
.maindir: ; list partitions
mov esi, .nextCD
xor ecx, ecx
.maindir_noesi: ; backjump from dyndisk_handler
push ebp
mov ebp, ecx
call kernel_free
mov edi, [ebx+16] ; buffer
cmp byte [ebx], 5
jz .deviceInfo
cmp byte [ebx], 1 ; read folder?
jnz .access_denied
push ebp
pushd [ebx+4] ; first block
mov ebp, [ebx+12] ; the number of blocks to read
mov ebx, [ebx+8] ; flags
mov ecx, 32/4
mov edx, edi
xor eax, eax
rep stosd
mov byte [edx], 1 ; version
.maindir_loop:
call esi
jc .maindir_done
inc dword[edx+8]
dec dword[esp]
jns .maindir_loop
dec ebp
js .maindir_loop
inc dword[edx+4]
mov dword[edi], 16 ; attributes: folder
mov dword[edi+4], ebx ; name encoding
push eax
mov ecx, 32/4
add edi, 8
xor eax, eax
rep stosd
pop eax
push eax edx edi
; convert number in eax to decimal string
push -'0'
mov ecx, 10
@@:
xor edx, edx
div ecx
push edx
test eax, eax
jnz @b
cmp ebx, 2
jz .uni
@@:
pop eax
add eax, '0'
stosb
test eax, eax
jnz @b
pop edi edx eax
cmp ebx, 3
jz @f
add edi, 264
jmp .maindir_loop
 
.uni:
pop eax
add eax, '0'
stosw
test eax, eax
jnz .uni
pop edi edx eax
@@:
add edi, 520
jmp .maindir_loop
 
.maindir_done:
pop eax eax
mov ebx, [edx+4]
xor eax, eax
dec ebp
js @f
mov al, ERROR_END_OF_FILE
@@:
mov [image_of_eax], eax
mov [image_of_ebx], ebx
ret
 
.access_denied:
mov dword[image_of_eax], ERROR_ACCESS_DENIED
ret
 
.deviceInfo:
test ebp, ebp
jz @f
mov eax, dword[ebp+DISK.MediaInfo.Capacity]
mov edx, dword[ebp+DISK.MediaInfo.Capacity+4]
shld edx, eax, 9
shl eax, 9
mov [edi+36], edx
mov [edi+32], eax
@@:
and dword[image_of_eax], 0
ret
 
.rootdir: ; / - virtual root folder
cmp byte [ebx], 5
jz @b
cmp byte [ebx], 1 ; read folder?
jnz .access_denied
mov ebp, [ebx+12] ; number of blocks
mov edx, [ebx+16] ; return area
push dword[ebx+4] ; first block
mov ebx, [ebx+8] ; flags
mov ecx, 32/4
mov edi, edx
xor eax, eax
rep stosd
mov byte [edx], 1 ; version
sub esp, 16
.rootdir_loop:
push edi
lea edi, [esp+4]
call dyndisk_enum_root
pop edi
test eax, eax
jz .rootdirCD
inc dword[edx+8]
dec dword[esp+16]
jns .rootdir_loop
dec ebp
js .rootdir_loop
inc dword[edx+4]
mov dword[edi], 16 ; attributes: folder
mov dword[edi+4], ebx ; name encoding
push eax
mov ecx, 32/4
add edi, 8
xor eax, eax
rep stosd
push edi
lea esi, [esp+8]
cmp ebx, 2
jz .uni2
@@:
lodsb
stosb
test eax, eax
jnz @b
pop edi eax
cmp ebx, 3
jz @f
add edi, 264
jmp .rootdir_loop
 
.uni2:
lodsb
stosw
test eax, eax
jnz .uni2
pop edi eax
@@:
add edi, 520
jmp .rootdir_loop
 
.rootdirCD:
add esp, 16
or esi, -1
.rootdirCD_loop:
inc esi
cmp esi, 10
jnc .rootdir_done
mov eax, esi
not eax
and eax, 3
shl eax, 1
inc eax
mov ecx, esi
shr ecx, 2
bt [ecx*5+DRIVE_DATA+1], ax
jnc .rootdirCD_loop
inc dword[edx+8]
dec dword[esp]
jns .rootdirCD_loop
dec ebp
js .rootdirCD_loop
inc dword[edx+4]
mov dword[edi], 16 ; attributes: folder
mov dword[edi+4], ebx ; name encoding
mov ecx, 32/4
add edi, 8
xor eax, eax
rep stosd
mov eax, esi
add eax, '0'
cmp ebx, 1
jz @f
mov word [edi], 'cd'
mov [edi+2], ax
add edi, 264
jmp .rootdirCD_loop
 
@@:
mov dword[edi], 640063h
mov [edi+4], eax
add edi, 520
jmp .rootdirCD_loop
 
.rootdir_done:
pop eax
mov ebx, [edx+4]
xor eax, eax
dec ebp
js @f
mov al, ERROR_END_OF_FILE
@@:
mov [image_of_eax], eax
mov [image_of_ebx], ebx
ret
 
;-----------------------------------------------------------------------------
process_replace_file_name:
; in: [esi] = virtual path
; out: [esi]+[ebp] = physical path
xor edi, edi
xor ebp, ebp
.loop:
cmp edi, [full_file_name_table.size]
jae .notfound
push esi edi
shl edi, 7
add edi, [full_file_name_table]
@@:
cmp byte [edi], 0
jz .dest_done
lodsb
test al, al
jz .cont
scasb
jz @b
or al, 20h
cmp [edi-1], al
jz @b
.cont:
pop edi esi
inc edi
jmp .loop
 
.dest_done:
cmp byte [esi], 0
jz .found
cmp byte [esi], '/'
jnz .cont
.found:
pop edi eax
shl edi, 7
add edi, [full_file_name_table]
mov ebp, esi
lea esi, [edi+64]
.notfound:
ret
 
;-----------------------------------------------------------------------------
uglobal
addDirSeal db ?
endg
 
sys_current_directory: ; sysfunction 30
mov eax, [current_slot]
mov edi, [eax+APPDATA.cur_dir]
xor eax, eax
dec ebx
jz .set
dec ebx
jz .get
dec ebx
jz .mount_additional_directory
mov eax, edx
dec ebx
jz .set
mov eax, esi
dec ebx
jz .get
@@:
ret
 
.mount_additional_directory:
; in: ecx -> dir name+dir path (128)
mov al, 1
xchg [addDirSeal], al
test al, al
jnz @b
mov esi, ecx
mov edi, sysdir_name1
mov ecx, 64
rep movsb ; copying fake directory name
mov byte [edi-1], 0
mov cl, 63
call cp866toUTF8_string
mov byte [edi], 0
mov [full_file_name_table.size], 2
ret
 
.get:
; in: ecx -> buffer, edx = length, eax = encoding
stdcall is_region_userspace, ecx, edx
jz @f
 
; if illegal buffer given
xor edx, edx
jmp .ret
@@:
 
mov esi, edi
inc esi
mov edi, ecx
cmp edx, maxPathLength
jc @f
mov edx, maxPathLength
@@:
mov ecx, edx
jecxz .ret
cmp eax, 2
jz .get16
cmp eax, 3
jz .get8
@@:
dec ecx
js @f
call utf8to16
call uni2ansi_char
stosb
test al, al
jnz @b
sub edx, ecx
@@:
mov byte [edi-1], 0
.ret:
mov [esp+32], edx
ret
 
.get8:
push edi
mov edi, esi
xor eax, eax
repnz scasb
sub edx, ecx
mov ecx, edx
pop edi
rep movsb
jmp @b
 
.get16:
shr ecx, 1
shr edx, 1
@@:
dec ecx
js @f
call utf8to16
stosw
test ax, ax
jnz @b
sub edx, ecx
@@:
shl edx, 1
mov word [edi-2], 0
jmp .ret
 
.set:
mov esi, ecx
getFullPath:
; in: esi -> file path, eax = string encoding, edi -> destination
; out: UTF-8 string (with marker), eax = length, 0 -> error
test eax, eax
jnz @f
cmp byte [esi], 4
jnc @f
cmp byte [esi], 0
jz @f
lodsb
@@:
cmp byte [esi], '/'
jnz .relative
cmp eax, 2
jnz @f
cmp word [esi], '/'
jnz .relative
inc esi
inc esi
jmp .start
 
@@:
inc esi
cmp byte [esi], 4
jnc .start
lodsb
cmp byte [esi], '/'
jnz .start
inc esi
.start:
push eax edi
call process_replace_file_name
mov edi, [esp]
mov ecx, maxPathLength
mov al, 3
mov ah, '/'
stosw
sub ecx, 2
test ebp, ebp
jz .absolute
@@:
lodsb
stosb
dec ecx
test al, al
jnz @b
mov esi, ebp
dec edi
.absolute:
cmp byte [esp+4], 2
jz .utf16
cmp byte [esp+4], 3
jz .utf8
call cp866toUTF8_string
jns .end
jmp .fail
 
.utf8:
dec ecx
js .fail
lodsb
stosb
test al, al
jz .end
jmp .utf8
 
.utf16:
call UTF16to8_string
jns .end
.fail:
mov byte [edi], 0
pop eax eax
xor eax, eax
ret
 
.relative:
push eax edi
mov ebx, esi
mov edi, [current_slot]
mov edi, [edi+APPDATA.cur_dir]
mov edx, edi
mov ecx, maxPathLength
xor eax, eax
repnz scasb
mov esi, edi
mov edi, [esp]
jecxz .fail
cmp byte [ebx], 0
jz .set_ok
dec esi
cmp edx, edi ; is destination equal to cur_dir?
mov edi, esi
jz @f
mov edi, [esp]
mov ecx, esi
sub ecx, edx
mov esi, edx
mov edx, edi
rep movsb
@@:
mov byte [edi], '/'
inc edi
mov esi, ebx
mov ecx, edx
add ecx, maxPathLength
sub ecx, edi
jmp .absolute
 
.set_ok:
cmp edx, edi ; is destination equal to cur_dir?
jz @f
mov ecx, esi
sub ecx, edx
mov esi, edx
rep movsb
@@:
pop eax
sub edi, eax
pop eax
mov eax, edi
ret
 
.end:
or ecx, -1
mov edi, [esp]
xor eax, eax
push edi
repnz scasb
not ecx
pop edi
.parse:
mov al, '/'
repnz scasb
jecxz @b
cmp byte [edi], '.'
jnz .parse
mov esi, edi
@@:
lodsw
sub ecx, 2
cmp ax, './'
jz @b
cmp ax, '..'
jnz @f
cmp byte [esi], '/'
jnz @f
mov edx, ecx
mov ecx, edi
sub ecx, [esp]
sub ecx, 2
jc .fail
sub edi, 2
lodsb
dec edx
std
repnz scasb
cld
add edi, 2
mov ecx, edx
jmp @b
 
@@:
sub esi, 2
add ecx, 2
cmp esi, edi
jz .parse
push edi ecx
rep movsb
pop ecx edi
jmp .parse
 
include "parse_fn.inc"
include "fs_common.inc"
include "iso9660.inc" ; read for CD filesystem
include "fat.inc"
include "ntfs.inc"
include "ext.inc"
include "xfs.asm"
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/fs/iso9660.inc
0,0 → 1,740
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; CD external functions
; in:
; esi -> path string in UTF-8
; ebx -> parameter structure +4
; ecx = bytes to read
; edx -> buffer
; out:
; eax, ebx = return values for sysfunc 70
iglobal
align 4
fs_CdServices:
dd fs_CdRead
dd fs_CdReadFolder
dd fs_NotImplemented
dd fs_NotImplemented
dd fs_NotImplemented
dd fs_CdGetFileInfo
dd fs_NotImplemented
dd 0
dd fs_NotImplemented
dd fs_NotImplemented
fs_NumCdServices = ($ - fs_CdServices)/4
endg
 
uglobal
align 4
cd_current_pointer_of_input dd 0
cd_current_pointer_of_input_2 dd 0
cd_mem_location dd 0
cd_counter_block dd 0
cd_status dd 0
endg
 
;-----------------------------------------------------------------------------
fs_NotImplemented:
movi eax, ERROR_UNSUPPORTED_FS
ret
;-----------------------------------------------------------------------------
reserve_cd:
cli
cmp [cd_status], 0
je reserve_ok2
 
sti
call change_task
jmp reserve_cd
;-----------------------------------------------------------------------------
reserve_ok2:
push eax
mov eax, [current_slot_idx]
shl eax, 5
mov eax, [eax+TASK_TABLE+TASKDATA.pid]
mov [cd_status], eax
pop eax
sti
ret
;-----------------------------------------------------------------------------
reserve_cd_channel:
pushad
mov eax, [cdpos]
dec eax
shr eax, 2
 
test eax, eax
jnz .1
 
cmp [ChannelNumber], 1
jne @f
 
mov ecx, ide_channel1_mutex
jmp .mutex_lock
;--------------------------------------
@@:
mov ecx, ide_channel2_mutex
jmp .mutex_lock
;--------------------------------------
.1:
dec eax
jnz .2
 
cmp [ChannelNumber], 1
jne @f
 
mov ecx, ide_channel3_mutex
jmp .mutex_lock
;--------------------------------------
@@:
mov ecx, ide_channel4_mutex
jmp .mutex_lock
;--------------------------------------
.2:
cmp [ChannelNumber], 1
jne @f
 
mov ecx, ide_channel5_mutex
jmp .mutex_lock
;--------------------------------------
@@:
mov ecx, ide_channel6_mutex
.mutex_lock:
call mutex_lock
popad
ret
;-----------------------------------------------------------------------------
free_cd_channel:
pushad
mov eax, [cdpos]
dec eax
shr eax, 2
 
test eax, eax
jnz .1
 
cmp [ChannelNumber], 1
jne @f
 
mov ecx, ide_channel1_mutex
jmp .mutex_unlock
;--------------------------------------
@@:
mov ecx, ide_channel2_mutex
jmp .mutex_unlock
;--------------------------------------
.1:
dec eax
jnz .2
 
cmp [ChannelNumber], 1
jne @f
 
mov ecx, ide_channel3_mutex
jmp .mutex_unlock
;--------------------------------------
@@:
mov ecx, ide_channel4_mutex
jmp .mutex_unlock
;--------------------------------------
.2:
cmp [ChannelNumber], 1
jne @f
 
mov ecx, ide_channel5_mutex
jmp .mutex_unlock
;--------------------------------------
@@:
mov ecx, ide_channel6_mutex
.mutex_unlock:
call mutex_unlock
popad
ret
 
;-----------------------------------------------------------------------------
fs_CdRead:
call cd_find_lfn
jc .notFound
mov edi, [cd_current_pointer_of_input]
test byte [edi+25], 10b ; do not allow read directories
jnz .noaccess
test ebx, ebx
jz .l1
cmp dword [ebx+4], 0
jz @f
xor ebx, ebx
movi eax, ERROR_END_OF_FILE
ret
 
.notFound:
cmp [DevErrorCode], 0
jne .noaccess
xor ebx, ebx
movi eax, ERROR_FILE_NOT_FOUND
ret
 
.noaccess_3:
pop eax edx ecx
.noaccess:
xor ebx, ebx
movi eax, ERROR_ACCESS_DENIED
ret
 
@@:
mov ebx, [ebx]
.l1:
push ecx edx 0
mov eax, [edi+10] ; real size of the file section
sub eax, ebx
jb .eof
cmp eax, ecx
jae @f
mov ecx, eax
pop eax
push ERROR_END_OF_FILE
@@:
mov eax, [edi+2]
mov [CDSectorAddress], eax
; now eax=cluster, ebx=position, ecx=count, edx=buffer for data
.new_sector:
test ecx, ecx
jz .done
sub ebx, 2048
jae .next
add ebx, 2048
jnz .incomplete_sector
cmp ecx, 2048
jb .incomplete_sector
; we may read and memmove complete sector
mov [CDDataBuf_pointer], edx
call ReadCDWRetr
cmp [DevErrorCode], 0
jne .noaccess_3
add edx, 2048
sub ecx, 2048
.next:
inc dword [CDSectorAddress]
jmp .new_sector
 
.eof:
pop eax
push ERROR_END_OF_FILE
.done:
mov ebx, edx
pop eax edx ecx
sub ebx, edx
ret
 
.incomplete_sector: ; we must read and memmove incomplete sector
mov [CDDataBuf_pointer], CDDataBuf
call ReadCDWRetr
cmp [DevErrorCode], 0
jne .noaccess_3
push ecx
add ecx, ebx
cmp ecx, 2048
jbe @f
mov ecx, 2048
@@:
sub ecx, ebx
push edi esi ecx
mov edi, edx
lea esi, [CDDataBuf + ebx]
cld
rep movsb
pop ecx esi edi
add edx, ecx
sub [esp], ecx
pop ecx
xor ebx, ebx
jmp .next
 
;-----------------------------------------------------------------------------
fs_CdReadFolder:
push edi
call cd_find_lfn
jnc .found
pop edi
cmp [DevErrorCode], 0
jne .noaccess_1
xor ebx, ebx
mov eax, ERROR_FILE_NOT_FOUND
ret
 
.found:
mov edi, [cd_current_pointer_of_input]
test byte [edi+25], 10b ; do not allow read directories
jnz .found_dir
pop edi
.noaccess_1:
xor ebx, ebx
mov eax, ERROR_ACCESS_DENIED
ret
 
.end_buffer:
pop edx eax
sub eax, 2048 ; directory is over?
ja .read_to_buffer
mov eax, [cd_counter_block]
mov [edx+8], eax
mov eax, [ebx]
sub [edx+4], eax
xor eax, eax
dec ecx
js @f
mov al, ERROR_END_OF_FILE
@@:
pop ecx edi
mov ebx, [edx+4]
ret
 
.found_dir:
mov eax, [edi+2] ; eax=cluster
mov [CDSectorAddress], eax
mov eax, [edi+10] ; directory size
push eax ecx
mov edi, edx
mov ecx, 32/4
xor eax, eax
rep stosd
pop ecx eax
mov byte [edx], 1 ; version
mov [cd_mem_location], edx
add [cd_mem_location], 32
mov [cd_counter_block], dword 0
dec dword [CDSectorAddress]
push ecx
.read_to_buffer:
inc dword [CDSectorAddress]
mov [CDDataBuf_pointer], CDDataBuf
call ReadCDWRetr ; read sector of directory
cmp [DevErrorCode], 0
jne .noaccess_1
mov [cd_current_pointer_of_input_2], CDDataBuf
push eax edx
.get_names_from_buffer:
call cd_get_name
jc .end_buffer
inc dword [cd_counter_block]
mov eax, [cd_counter_block]
cmp [ebx], eax
jae .get_names_from_buffer
test ecx, ecx
jz .get_names_from_buffer
mov edi, [cd_counter_block]
mov [edx+4], edi
dec ecx
mov esi, ebp
call cd_get_parameters_of_file
add edi, 40
mov ax, '.'
cmp dword[ebx+4], 2
jz .utf16
cmp dword[ebx+4], 3
jz .utf8
cmp [cd_counter_block], 2
jbe .parentDirectory
@@:
lodsw
xchg ah, al
call uni2ansi_char
stosb
call .checkForEnd
jc @b
@@:
mov [edi], byte 0
add [cd_mem_location], 304
jmp .get_names_from_buffer
 
.parentDirectory:
stosb
cmp [cd_counter_block], 2
jnz @b
stosb
jmp @b
 
.utf8:
add [cd_mem_location], 256
cmp [cd_counter_block], 2
jbe .parentDirectory
push ecx
mov ecx, 519
@@:
lodsw
xchg ah, al
call UTF16to8
js @f
call .checkForEnd
jc @b
@@:
pop ecx
mov [edi], byte 0
add [cd_mem_location], 304
jmp .get_names_from_buffer
 
.checkForEnd:
mov ax, [esi]
cmp ax, 3B00h ; ';'
jz @f
; check for files not ending with separator
movzx eax, byte [ebp-33]
add eax, ebp
sub eax, 34
cmp esi, eax
jz @f
; check the end of the directory
movzx eax, byte [ebp-1]
add eax, ebp
cmp esi, eax
@@:
ret
 
.utf16:
cmp [cd_counter_block], 2
jbe .utf16ParentDirectory
@@:
lodsw
xchg ah, al
stosw
call .checkForEnd
jc @b
@@:
mov [edi], word 0
add [cd_mem_location], 560
jmp .get_names_from_buffer
 
.utf16ParentDirectory:
stosw
cmp [cd_counter_block], 2
jnz @b
stosw
jmp @b
 
cd_get_parameters_of_file:
mov edi, [cd_mem_location]
cd_get_parameters_of_file_1:
; get file attributes
xor eax, eax
; file is not archived
inc eax
shl eax, 1
; is a directory?
test [ebp-8], byte 2
jz .file
inc eax
.file:
; not as a volume label in the FAT, in this form not available
; file is not a system
shl eax, 3
; file is hidden? (attribute of existence)
test [ebp-8], byte 1
jz .hidden
inc eax
.hidden:
shl eax, 1
; file is always read-only, as this CD
inc eax
mov [edi], eax
mov eax, [ebx+4]
mov [edi+4], eax
; get the time to file
; hour
movzx eax, byte [ebp-12]
shl eax, 8
; minute
mov al, [ebp-11]
shl eax, 8
; second
mov al, [ebp-10]
; file creation time
mov [edi+8], eax
; last access time
mov [edi+16], eax
; last write time
mov [edi+24], eax
; get date for file
; year
movzx eax, byte [ebp-15]
add eax, 1900
shl eax, 8
; month
mov al, [ebp-14]
shl eax, 8
; day
mov al, [ebp-13]
; file creation date
mov [edi+12], eax
; last access date
mov [edi+20], eax
; last write date
mov [edi+28], eax
; get the file size in bytes
xor eax, eax
mov [edi+32+4], eax
mov eax, [ebp-23]
mov [edi+32], eax
ret
 
;-----------------------------------------------------------------------------
fs_CdGetFileInfo:
call cd_find_lfn
movi eax, ERROR_FILE_NOT_FOUND
jc @f
mov edi, edx
mov eax, [ebx+4]
mov [edx+4], eax
cmp byte [esi], 0
jz .volume
mov ebp, [cd_current_pointer_of_input]
add ebp, 33
call cd_get_parameters_of_file_1
xor eax, eax
@@:
ret
 
.volume:
test eax, eax
jz .size
mov ecx, 16
mov esi, CDDataBuf+40
add edi, 40
cmp eax, 2
jz .utf16
cmp eax, 3
jz .utf8
@@:
lodsw
xchg al, ah
call uni2ansi_char
stosb
loop @b
jmp .size
 
.utf16:
lodsw
xchg al, ah
stosw
loop .utf16
jmp .size
 
.utf8:
mov ebx, ecx
shl ecx, 1
@@:
lodsw
xchg ah, al
call UTF16to8
dec ebx
jnz @b
.size:
mov eax, [CDDataBuf+80]
shl eax, 11
mov [edx+32], eax
xor eax, eax
mov [edx+36], eax
stosw
mov byte [edx], 8
ret
 
;-----------------------------------------------------------------------------
cd_find_lfn:
mov [cd_appl_data], 0
; in: esi -> path string in UTF-8
; out: [cd_current_pointer_of_input] -> direntry, CF=1 -> file not found
push eax esi
; Sector 16 - start set of volume descriptors
call WaitUnitReady
cmp [DevErrorCode], 0
jne .access_denied
 
call prevent_medium_removal
; testing of reading
mov [CDSectorAddress], dword 16
mov [CDDataBuf_pointer], CDDataBuf
call ReadCDWRetr;_1
cmp [DevErrorCode], 0
jne .access_denied
 
; calculation of the last session
call WaitUnitReady
cmp [DevErrorCode], 0
jne .access_denied
 
call Read_TOC
mov ah, [CDDataBuf+4+4]
mov al, [CDDataBuf+4+5]
shl eax, 16
mov ah, [CDDataBuf+4+6]
mov al, [CDDataBuf+4+7]
add eax, 15
mov [CDSectorAddress], eax
; mov [CDSectorAddress],dword 15
mov [CDDataBuf_pointer], CDDataBuf
;--------------------------------------
.start:
inc dword [CDSectorAddress]
call ReadCDWRetr;_1
cmp [DevErrorCode], 0
jne .access_denied
 
.start_check:
; checking for "lice"
cmp [CDDataBuf+1], dword 'CD00'
jne .access_denied
 
cmp [CDDataBuf+5], byte '1'
jne .access_denied
; sector is the terminator of set of descriptors volumes?
cmp [CDDataBuf], byte 0xff
je .access_denied
; sector is an additional and improved descriptor of volume?
cmp [CDDataBuf], byte 0x2
jne .start
; sector is an additional descriptor of volume?
cmp [CDDataBuf+6], byte 0x1
jne .start
 
; parameters of root directory
mov eax, [CDDataBuf+0x9c+2]; start of root directory
mov [CDSectorAddress], eax
mov eax, [CDDataBuf+0x9c+10]; size of root directory
cmp byte [esi], 0
jnz @f
 
mov [cd_current_pointer_of_input], CDDataBuf+0x9c
jmp .done
;--------------------------------------
@@:
; start the search
.mainloop:
dec dword [CDSectorAddress]
;--------------------------------------
.read_to_buffer:
inc dword [CDSectorAddress]
mov [CDDataBuf_pointer], CDDataBuf
call ReadCDWRetr ; read sector of directory
cmp [DevErrorCode], 0
jne .access_denied
call cd_find_name_in_buffer
jnc .found
sub eax, 2048
; directory is over?
cmp eax, 0
ja .read_to_buffer
; desired element of chain is not found
.access_denied:
pop esi eax
mov [cd_appl_data], 1
stc
ret
;--------------------------------------
; desired element of chain found
.found:
; the end of the file path
cmp byte [esi-1], 0
jz .done
mov eax, [cd_current_pointer_of_input]
push dword [eax+2]
pop dword [CDSectorAddress] ; beginning of the directory
mov eax, [eax+2+8] ; size of directory
jmp .mainloop
;--------------------------------------
; file pointer found
.done:
pop esi eax
mov [cd_appl_data], 1
clc
ret
;-----------------------------------------------------------------------------
cd_find_name_in_buffer:
mov [cd_current_pointer_of_input_2], CDDataBuf
;--------------------------------------
.start:
call cd_get_name
jc .not_found
 
call cd_compare_name
jc .start
;--------------------------------------
.found:
clc
ret
;--------------------------------------
.not_found:
stc
ret
;-----------------------------------------------------------------------------
cd_get_name:
push eax
mov ebp, [cd_current_pointer_of_input_2]
mov [cd_current_pointer_of_input], ebp
mov eax, [ebp]
test eax, eax ; entry's is over?
jz .next_sector
 
cmp ebp, CDDataBuf+2048 ; buffer is over?
jae .next_sector
 
movzx eax, byte [ebp]
add [cd_current_pointer_of_input_2], eax ; next entry of directory
add ebp, 33; pointer is set to the beginning of the name
pop eax
clc
ret
;--------------------------------------
.next_sector:
pop eax
stc
ret
;-----------------------------------------------------------------------------
cd_compare_name:
; in: esi -> UTF-8 name, ebp -> UTF-16BE name
; out: CF=0 -> names match, esi -> next component of name
; CF=1 -> esi is not changed
push edx edi eax esi
mov edi, ebp
.loop:
call utf8to16
call utf16toUpper
mov edx, eax
mov ax, [edi]
xchg al, ah
call utf16toUpper
cmp ax, dx
jne .name_not_coincide
add edi, 2
cmp [esi], byte '/' ; path separator is end of current element
je .done
cmp [esi], byte 0 ; path separator end of name
jne .loop
.done:
; check end of file
cmp [edi], word 3B00h; separator end of file ';'
je .done_1
; check for files not ending with separator
movzx eax, byte [ebp-33]
add eax, ebp
sub eax, 34
cmp edi, eax
je .done_1
; check the end of directory
movzx eax, byte [ebp-1]
add eax, ebp
cmp edi, eax
jne .name_not_coincide
.done_1:
pop eax eax edi edx
inc esi
ret
 
.name_not_coincide:
pop esi eax edi edx
stc
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/fs/parse_fn.inc
0,0 → 1,340
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
iglobal
full_file_name_table dd sysdir_name
.size dd 1
endg
 
uglobal
sysdir_name rb 64 ; 'sys',0
sysdir_path rb 64
sysdir_name1 rb 64
sysdir_path1 rb 64
endg
; Example:
; align 64
; sysdir_name1 db 'KolibriOS',0
; align 64
; sysdir_path1 db 'HD0/1',0
 
proc Parser_params
locals
buff rb 4 ; for test cd
endl
if defined extended_primary_loader
mov ecx, sysdir_path
mov [ecx-64], dword 'sys'
mov [ecx-2], byte 3
mov esi, BOOT.syspath
mov edi, sysdir_path-1
mov ecx, 20
rep movsb
ret
else
mov ax, [BOOT.sys_disk]
mov ecx, sysdir_path
mov [ecx-64], dword 'sys'
mov [ecx-2], byte 3
mov [ecx-1], byte '/'
cmp al, 'r' ; ram disk
jnz @f
mov [ecx], dword 'RD/?'
mov [ecx+3], byte ah
mov [ecx+4], byte 0
ret
 
@@:
cmp al, 'm'
jnz .hard_disk
mov [ecx], dword 'CD?/'
mov [ecx+4], byte '1'
mov [ecx+5], dword '/KOL'
mov [ecx+9], dword 'IBRI'
mov [ecx+13], byte 0
.next_cd:
mov [ecx+2], byte ah
inc ah
cmp ah, '5'
je @f
lea edx, [buff]
pushad
stdcall read_file, read_firstapp, edx, 0, 4
popad
cmp [edx], dword 'MENU'
jne .next_cd
@@:
ret
end if
 
.hard_disk:
sub al, '1'
mov [ecx], dword 'HD?/'
mov [ecx+2], byte al
mov [ecx+4], byte ah
mov [ecx+5], dword '/KOL'
mov [ecx+9], dword 'IBRI'
mov [ecx+13], byte 0
ret
endp
 
cp866toUpper:
; convert cp866 character in al to uppercase
cmp al, 'a'
jb .ret
cmp al, 'z'
jbe @f
cmp al, 0xA0
jb .ret
cmp al, 0xB0
jb @f
cmp al, 0xE0
jb .ret
cmp al, 0xF0
jb .rus
cmp al, 0xF7
ja .ret
and eax, -2
.ret:
ret
 
@@:
sub eax, 32
ret
 
.rus:
sub eax, 0xE0-0x90
ret
 
utf16toUpper:
; convert UTF-16 character in ax to uppercase
cmp ax, 'a'
jb .ret
cmp ax, 'z'
jbe @f
cmp ax, 430h
jb .ret
cmp ax, 450h
jb @f
cmp ax, 460h
jnc .ret
sub eax, 80
.ret:
ret
 
@@:
sub eax, 32
ret
 
uni2ansi_char:
; convert UNICODE character in ax to ANSI character in al using cp866 encoding
cmp ax, 0x80
jb .ret
cmp ax, 0xB6
jz .B6
cmp ax, 0x400
jb .unk
cmp ax, 0x410
jb @f
cmp ax, 0x440
jb .rus1
cmp ax, 0x450
jb .rus2
cmp ax, 0x460
jb @f
.unk:
mov al, '_'
.ret:
ret
 
.B6:
mov al, 20
ret
 
.rus1: ; 0x410-0x43F -> 0x80-0xAF
add al, 0x70
ret
 
.rus2: ; 0x440-0x44F -> 0xE0-0xEF
add al, 0xA0
ret
 
@@:
push ecx edi
mov ecx, 8
mov edi, .table
repnz scasb
mov ah, cl
pop edi ecx
jnz .unk
mov al, 0xF7
sub al, ah
ret
 
.table db 1, 51h, 4, 54h, 7, 57h, 0Eh, 5Eh
 
ansi2uni_char:
; convert ANSI character in al to UNICODE character in ax, using cp866 encoding
movzx eax, al
cmp al, 0x80
jb @f ; 0x00-0x7F - trivial map
cmp al, 0xB0
jb .rus ; 0x80-0xAF -> 0x410-0x43F
cmp al, 0xE0
jb .unk
cmp al, 0xF0
jb .rus2 ; 0xE0-0xEF -> 0x440-0x44F
cmp al, 0xF8
jnc .unk
mov al, [eax+uni2ansi_char.table-0xF0]
add ax, 400h
ret
 
@@:
cmp al, 20
jnz .ret
mov al, 0xB6
.ret:
ret
 
.rus:
add ax, 0x410-0x80
ret
 
.rus2:
add ax, 0x440-0xE0
ret
 
.unk:
mov al, '_'
ret
 
cp866toUTF8_string:
; in:
; esi -> cp866 string (could be zero terminated)
; edi -> buffer for UTF-8 string
; ecx = buffer size (signed)
lodsb
call ansi2uni_char
push eax
call UTF16to8
pop eax
js @f
test eax, eax
jnz cp866toUTF8_string
@@:
ret
 
; SF=1 -> counter
; ZF=1 -> zero char
 
UTF16to8_string:
; in:
; esi -> UTF-16 string (could be zero terminated)
; edi -> buffer for UTF-8 string
; ecx = buffer size (signed)
xor eax, eax
@@:
lodsw
push eax
call UTF16to8
pop eax
js @f
test eax, eax
jnz @b
@@:
ret
 
UTF16to8:
; in:
; eax = UTF-16 char
; edi -> buffer for UTF-8 char (increasing)
; ecx = byte counter (decreasing)
dec ecx
js .ret
cmp eax, 80h
jnc @f
stosb
test eax, eax ; SF=0
.ret:
ret
 
@@:
dec ecx
js .ret
cmp eax, 800h
jnc @f
shl eax, 2
shr al, 2
or eax, 1100000010000000b
xchg al, ah
stosw
ret
 
@@:
dec ecx
js .ret
shl eax, 4
shr ax, 2
shr al, 2
or eax, 111000001000000010000000b
bswap eax
shr eax, 8
stosb
shr eax, 8
stosw
ret
 
utf8to16:
; in: esi -> UTF-8 char (increasing)
; out: ax = UTF-16 char
lodsb
test al, al
jns .got
shl al, 2
jnc utf8to16
@@:
shl ax, 8
lodsb
test al, al
jns .got
shl al, 2
jc @b
shr ah, 2
shl ax, 3
jnc @f
shl eax, 3
lodsb
test al, al
jns .got
shl al, 2
jc @b
shr eax, 2
ret
 
@@:
shr ax, 5
ret
 
.got:
xor ah, ah
ret
 
strlen:
; in: esi -> source
; out: ecx = length
push edi eax
or ecx, -1
mov edi, esi
xor eax, eax
repnz scasb
inc ecx
not ecx
pop eax edi
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/fs/xfs.asm
0,0 → 1,2124
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2013-2020. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
 
include 'xfs.inc'
 
macro omit_frame_pointer_prologue procname,flag,parmbytes,localbytes,reglist {
local loc
loc = (localbytes+3) and (not 3)
if localbytes
sub esp, loc
end if
irps reg, reglist \{ push reg \}
counter = 0
irps reg, reglist \{counter = counter+1 \}
parmbase@proc equ esp+counter*4+loc+4
localbase@proc equ esp
}
 
macro omit_frame_pointer_epilogue procname,flag,parmbytes,localbytes,reglist {
local loc
loc = (localbytes+3) and (not 3)
irps reg, reglist \{ reverse pop reg \}
if localbytes
lea esp, [esp+loc]
end if
if flag and 10000b
retn
else
retn parmbytes
end if
}
 
prologue@proc equ omit_frame_pointer_prologue
epilogue@proc equ omit_frame_pointer_epilogue
 
macro movbe reg, arg {
if CPUID_MOVBE eq Y
movbe reg, arg
else
mov reg, arg
if reg in <eax,ebx,ecx,edx,esi,edi,ebp,esp>
bswap reg
else if ax eq reg
xchg al, ah
else if bx eq reg
xchg bl, bh
else if cx eq reg
xchg cl, ch
else if dx eq reg
xchg dl, dh
else
err
end if
end if
}
 
;
; This file contains XFS related code.
; For more information on XFS check links and source below.
;
; 1. https://xfs.wiki.kernel.org/
;
; 2. XFS Algorithms & Data Structures:
; git://git.kernel.org/pub/scm/fs/xfs/xfs-documentation.git
; https://mirrors.edge.kernel.org/pub/linux/utils/fs/xfs/docs/xfs_filesystem_structure.pdf
;
; 3. Linux source at https://www.kernel.org/
; git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
; /fs/xfs
;
 
iglobal
align 4
xfs._.user_functions:
dd xfs._.free
dd (xfs._.user_functions_end-xfs._.user_functions-4)/4
dd xfs_Read
dd xfs_ReadFolder
dd 0;xfs_Rewrite
dd 0;xfs_Write
dd 0;xfs_SetFileEnd
dd xfs_GetFileInfo
xfs._.user_functions_end:
endg
 
; test partition type (valid XFS one?)
; alloc and fill XFS (see xfs.inc) structure
; this function is called for each partition
; return 0 (not XFS or invalid) / pointer to partition structure
proc xfs_create_partition uses ebx esi edi
; check XFS signature
cmp [ebx+xfs_sb.sb_magicnum], XFS_SB_MAGIC
jnz .error_nofree
; test for supported feature flags and version in sb_versionnum
movzx eax, [ebx+xfs_sb.sb_versionnum]
xchg al, ah
; allow only known and supported features
; return error otherwise
test eax, NOT XFS_SB_VERSION_SUPPORTED
jnz .error_nofree
; version < 4 obsolete, not supported
; version = 4,5 supported
; version > 5 unknown
and al, XFS_SB_VERSION_NUMBITS
cmp al, 4
jb .error_nofree
cmp al, 5
ja .error_nofree
; if MOREBITS bit is set, additional feature flags are in sb_features2
test eax, XFS_SB_VERSION_MOREBITSBIT
jz @f
movbe eax, [ebx+xfs_sb.sb_features2]
test eax, NOT XFS_SB_VERSION2_SUPPORTED
jnz .error_nofree
@@:
movbe eax, [ebx+xfs_sb.sb_features_incompat]
test eax, NOT XFS_SB_FEAT_INCOMPAT_SUPPORTED
jnz .error_nofree
; all presented features are either supported or don't affect reading
movi eax, sizeof.XFS
call malloc
mov edi, eax
test eax, eax
jz .error
 
; standard partition initialization, common for all file systems
mov eax, dword[ebp+PARTITION.FirstSector+DQ.lo]
mov dword[edi+XFS.FirstSector+DQ.lo], eax
mov eax, dword[ebp+PARTITION.FirstSector+DQ.hi]
mov dword[edi+XFS.FirstSector+DQ.hi], eax
mov eax, dword[ebp+PARTITION.Length+DQ.lo]
mov dword[edi+XFS.Length+DQ.lo], eax
mov eax, dword[ebp+PARTITION.Length+DQ.hi]
mov dword[edi+XFS.Length+DQ.hi], eax
mov eax, [ebp+PARTITION.Disk]
mov [edi+XFS.Disk], eax
mov [edi+XFS.FSUserFunctions], xfs._.user_functions
; here we initialize only one mutex (for the entire partition)
; XFS potentially allows parallel r/w access to different AGs, keep it in mind
lea ecx, [edi+XFS.Lock]
call mutex_init
 
; movzx eax, [ebx+xfs_sb.sb_sectsize]
; xchg al, ah
mov eax, [eax+DISK.MediaInfo.SectorSize]
mov [edi+XFS.sectsize], eax
 
movbe eax, [ebx+xfs_sb.sb_blocksize]
mov [edi+XFS.blocksize], eax
 
movzx eax, [ebx+xfs_sb.sb_versionnum]
xchg al, ah
mov [edi+XFS.versionnum], eax
and eax, XFS_SB_VERSION_NUMBITS
mov [edi+XFS.version], eax
 
movbe eax, [ebx+xfs_sb.sb_features2]
mov [edi+XFS.features2], eax
cmp [edi+XFS.version], 5
jz .v5
.v4:
mov [edi+XFS.inode_core_size], sizeof.xfs_dinode_core
test eax, XFS_SB_VERSION2_FTYPE
setnz al
movzx eax, al
mov [edi+XFS.ftype_size], eax
mov [edi+XFS.dir_block_magic], XFS_DIR2_BLOCK_MAGIC
mov [edi+XFS.dir_data_magic], XFS_DIR2_DATA_MAGIC
mov [edi+XFS.dir_leaf1_magic], XFS_DIR2_LEAF1_MAGIC
mov [edi+XFS.dir_leafn_magic], XFS_DIR2_LEAFN_MAGIC
mov [edi+XFS.da_node_magic], XFS_DA_NODE_MAGIC
mov [edi+XFS.bmap_magic], XFS_BMAP_MAGIC
mov [edi+XFS.dir_block_size], sizeof.xfs_dir2_data_hdr
mov [edi+XFS.bmbt_block_size], sizeof.xfs_bmbt_block
mov [edi+XFS.da_blkinfo_size], sizeof.xfs_da_blkinfo
jmp .vcommon
.v5:
mov [edi+XFS.inode_core_size], sizeof.xfs_dinode3_core
movbe eax, [ebx+xfs_sb.sb_features_incompat]
mov [edi+XFS.features_incompat], eax
test eax, XFS_SB_FEAT_INCOMPAT_FTYPE
setnz al
movzx eax, al
mov [edi+XFS.ftype_size], eax
mov [edi+XFS.dir_block_magic], XFS_DIR3_BLOCK_MAGIC
mov [edi+XFS.dir_data_magic], XFS_DIR3_DATA_MAGIC
mov [edi+XFS.dir_leaf1_magic], XFS_DIR3_LEAF1_MAGIC
mov [edi+XFS.dir_leafn_magic], XFS_DIR3_LEAFN_MAGIC
mov [edi+XFS.da_node_magic], XFS_DA3_NODE_MAGIC
mov [edi+XFS.bmap_magic], XFS_BMAP3_MAGIC
mov [edi+XFS.dir_block_size], sizeof.xfs_dir3_data_hdr
mov [edi+XFS.bmbt_block_size], sizeof.xfs_bmbt3_block
mov [edi+XFS.da_blkinfo_size], sizeof.xfs_da3_blkinfo
.vcommon:
 
movzx eax, [ebx+xfs_sb.sb_inodesize]
xchg al, ah
mov [edi+XFS.inodesize], eax
 
movzx eax, [ebx+xfs_sb.sb_inopblock]
xchg al, ah
mov [edi+XFS.inopblock], eax
 
movzx eax, [ebx+xfs_sb.sb_blocklog]
mov [edi+XFS.blocklog], eax
 
; movzx eax, [ebx+xfs_sb.sb_sectlog]
mov eax, [edi+XFS.sectsize]
bsf eax, eax
mov [edi+XFS.sectlog], eax
 
movzx eax, [ebx+xfs_sb.sb_inodelog]
mov [edi+XFS.inodelog], eax
 
movzx eax, [ebx+xfs_sb.sb_inopblog]
mov [edi+XFS.inopblog], eax
 
movzx ecx, [ebx+xfs_sb.sb_dirblklog]
mov [edi+XFS.dirblklog], ecx
movi eax, 1
shl eax, cl
mov [edi+XFS.blkpdirblk], eax
 
movbe eax, [ebx+xfs_sb.sb_rootino.hi]
mov [edi+XFS.rootino.lo], eax
movbe eax, [ebx+xfs_sb.sb_rootino.lo]
mov [edi+XFS.rootino.hi], eax
 
mov eax, [edi+XFS.blocksize]
mov ecx, [edi+XFS.dirblklog]
shl eax, cl
mov [edi+XFS.dirblocksize], eax ; blocks are for files, dirblocks are for directories
 
; sector is always smaller than block
; so precalculate shift order to allow faster sector_num->block_num conversion
mov ecx, [edi+XFS.blocklog]
sub ecx, [edi+XFS.sectlog]
mov [edi+XFS.sectpblog], ecx
 
mov eax, 1
shl eax, cl
mov [edi+XFS.sectpblock], eax
 
movbe eax, [ebx+xfs_sb.sb_agblocks]
mov [edi+XFS.agblocks], eax
 
movzx ecx, [ebx+xfs_sb.sb_agblklog]
mov [edi+XFS.agblklog], ecx
 
; get the mask for block numbers
; block numbers are AG relative!
; bitfield length may vary between partitions
mov eax, 1
xor edx, edx
shld edx, eax, cl
shl eax, cl
sub eax, 1
sbb edx, 0
mov [edi+XFS.agblockmask.lo], eax
mov [edi+XFS.agblockmask.hi], edx
 
; calculate magic offsets for directories
mov ecx, [edi+XFS.blocklog]
mov eax, XFS_DIR2_LEAF_OFFSET AND 0xffffffff ; lo
mov edx, XFS_DIR2_LEAF_OFFSET SHR 32 ; hi
shrd eax, edx, cl
shr edx, cl
mov [edi+XFS.dir2_leaf_offset_blocks.lo], eax
mov [edi+XFS.dir2_leaf_offset_blocks.hi], edx
 
mov ecx, [edi+XFS.blocklog]
mov eax, XFS_DIR2_FREE_OFFSET AND 0xffffffff ; lo
mov edx, XFS_DIR2_FREE_OFFSET SHR 32 ; hi
shrd eax, edx, cl
shr edx, cl
mov [edi+XFS.dir2_free_offset_blocks.lo], eax
mov [edi+XFS.dir2_free_offset_blocks.hi], edx
 
 
; allocate memory for temp block, dirblock, inode, etc
mov eax, [edi+XFS.blocksize]
call malloc
mov [edi+XFS.cur_block], eax
test eax, eax
jz .error
 
mov eax, [edi+XFS.blocksize]
call malloc
mov [edi+XFS.cur_block_data], eax
test eax, eax
jz .error
 
; we do need XFS.blocksize bytes for single inode
; minimal file system structure is block, inodes are packed in blocks
; FIXME
mov eax, [edi+XFS.blocksize]
call malloc
mov [edi+XFS.cur_inode], eax
test eax, eax
jz .error
 
mov eax, [edi+XFS.blocksize]
call malloc
test eax, eax
jz .error
mov [edi+XFS.tmp_inode], eax
 
; current sector
; only for sector sized structures like AGF
; inodes usually fit this size, but not always!
; therefore never store inode here
mov eax, [edi+XFS.sectsize]
call malloc
mov [edi+XFS.cur_sect], eax
test eax, eax
jz .error
 
mov eax, [edi+XFS.dirblocksize]
call malloc
mov [edi+XFS.cur_dirblock], eax
test eax, eax
jz .error
 
.quit:
; return pointer to allocated XFS partition structure
mov eax, edi
ret
.error:
mov eax, edi
call xfs._.free
.error_nofree:
xor eax, eax
ret
endp
 
 
; lock partition access mutex
xfs._.lock:
lea ecx, [ebp+XFS.Lock]
jmp mutex_lock
 
 
; unlock partition access mutex
xfs._.unlock:
lea ecx, [ebp+XFS.Lock]
jmp mutex_unlock
 
 
; free all the allocated memory
; called on partition destroy
; or during failed initialization from xfs_create_partition
xfs._.free:
test eax, eax
jz .done
push ebx
mov ebx, eax
 
 
; freeing order must correspond the order of
; allocation in xfs_create_partition
mov eax, [ebx+XFS.cur_block]
test eax, eax
jz .done
call free
 
mov eax, [ebx+XFS.cur_block_data]
test eax, eax
jz .done
call free
 
mov eax, [ebx+XFS.cur_inode]
test eax, eax
jz .done
call free
 
mov eax, [ebx+XFS.tmp_inode]
test eax, eax
jz .done
call free
 
mov eax, [ebx+XFS.cur_sect]
test eax, eax
jz .done
call free
 
mov eax, [ebx+XFS.cur_dirblock]
test eax, eax
jz .done
call free
 
 
mov eax, ebx
call free
pop ebx
.done:
ret
 
 
;---------------------------------------------------------------
; block number
; eax -- inode_lo
; edx -- inode_hi
; ebx -- buffer
;---------------------------------------------------------------
proc xfs._.read_block
movi ecx, 1
call xfs._.read_blocks
ret
endp
 
 
proc xfs._.blkrel2sectabs uses esi
push edx eax
 
; XFS block numbers are AG relative
; they come in bitfield form of concatenated AG and block numbers
; to get absolute block number for fs_read64_sys we should
; 1. get AG number and multiply it by the AG size in blocks
; 2. extract and add AG relative block number
 
; 1.
mov ecx, [ebp+XFS.agblklog]
shrd eax, edx, cl
shr edx, cl
mul [ebp+XFS.agblocks]
; 2.
pop ecx esi
and ecx, [ebp+XFS.agblockmask.lo]
and esi, [ebp+XFS.agblockmask.hi]
add eax, ecx
adc edx, esi
 
mov ecx, [ebp+XFS.sectpblog]
shld edx, eax, cl
shl eax, cl
ret
endp
 
 
;---------------------------------------------------------------
; start block number
; edx:eax -- block
; ebx -- buffer
; ecx -- count
;---------------------------------------------------------------
proc xfs._.read_blocks
push ecx
call xfs._.blkrel2sectabs
pop ecx
imul ecx, [ebp+XFS.sectpblock]
call fs_read64_sys
test eax, eax
ret
endp
 
 
proc xfs._.read_dirblock uses ebx, _startblock:qword, _buffer
mov eax, dword[_startblock+DQ.lo]
mov edx, dword[_startblock+DQ.hi]
mov ebx, [_buffer]
mov ecx, [ebp+XFS.blkpdirblk]
call xfs._.read_blocks
ret
endp
 
 
;---------------------------------------------------------------
; test eax, eax
;---------------------------------------------------------------
proc xfs_read_inode uses ebx, _inode_lo, _inode_hi, _buffer
mov eax, [_inode_lo]
mov edx, [_inode_hi]
mov ebx, [_buffer]
; inodes are packed into blocks
; 1. calculate block number
; 2. read the block
; 3. add inode offset to block base address
; 1.
mov ecx, [ebp+XFS.inopblog]
shrd eax, edx, cl
shr edx, cl
; 2.
call xfs._.read_block
jnz .error
; inode numbers should be first extracted from bitfields by mask
 
mov eax, [_inode_lo]
mov edx, 1
mov ecx, [ebp+XFS.inopblog]
shl edx, cl
dec edx ; get inode number mask
and eax, edx ; apply mask
mov ecx, [ebp+XFS.inodelog]
shl eax, cl
add ebx, eax
xor eax, eax
 
cmp [ebx+xfs_inode.di_core.di_magic], XFS_DINODE_MAGIC
jz .quit
movi eax, ERROR_FS_FAIL
.quit:
mov edx, ebx
.error:
ret
endp
 
 
; skip ecx first entries
proc xfs._.dir_sf_skip _count
mov ecx, [_count]
.next:
dec ecx
js .quit
dec [ebp+XFS.entries_left_in_dir]
js .quit
.self:
bts [ebp+XFS.dir_sf_self_done], 0
jc .parent
jmp .next
.parent:
bts [ebp+XFS.dir_sf_parent_done], 0
jc .common
jmp .next
.common:
movzx eax, [esi+xfs_dir2_sf_entry.namelen]
add esi, xfs_dir2_sf_entry.name
add esi, eax
add esi, [ebp+XFS.ftype_size]
add esi, [ebp+XFS.shortform_inodelen]
jmp .next
.quit:
ret
endp
 
 
proc xfs._.dir_sf_read uses edi, _count
locals
_dst dd ?
endl
.next:
dec [_count]
js .quit
dec [ebp+XFS.entries_left_in_dir]
js .quit
mov [_dst], edx
.self:
bts [ebp+XFS.dir_sf_self_done], 0
jc .parent
lea edi, [edx+bdfe.name]
mov dword[edi], '.'
stdcall xfs_get_inode_info, [ebp+XFS.cur_inode], edx
jmp .common
.parent:
bts [ebp+XFS.dir_sf_parent_done], 0
jc .not_special
lea edi, [edx+bdfe.name] ; get file name offset
mov dword[edi], '..' ; terminator included
mov edi, edx
lea edx, [ebx+xfs_dir2_sf.hdr.parent]
call xfs._.get_inode_number_sf
stdcall xfs_read_inode, eax, edx, [ebp+XFS.tmp_inode]
test eax, eax
jnz .error
stdcall xfs_get_inode_info, edx, edi
jmp .common
.not_special:
movzx ecx, [esi+xfs_dir2_sf_entry.namelen]
add esi, xfs_dir2_sf_entry.name
lea edi, [edx+bdfe.name]
stdcall xfs._.copy_filename
add esi, [ebp+XFS.ftype_size]
mov edi, edx
mov edx, esi
call xfs._.get_inode_number_sf
stdcall xfs_read_inode, eax, edx, [ebp+XFS.tmp_inode]
test eax, eax
jnz .error
stdcall xfs_get_inode_info, edx, edi
add esi, [ebp+XFS.shortform_inodelen]
.common:
mov edx, [_dst]
mov eax, [ebp+XFS.bdfe_nameenc]
mov [edx+bdfe.nameenc], eax
add edx, [ebp+XFS.bdfe_len]
inc [ebp+XFS.entries_read]
jmp .next
.quit:
xor eax, eax
.error:
ret
endp
 
 
proc xfs._.readdir_sf uses esi, _src, _dst
mov ebx, [_src]
mov edx, [_dst]
mov [ebp+XFS.dir_sf_self_done], 0
mov [ebp+XFS.dir_sf_parent_done], 0
mov [ebp+XFS.entries_read], 0
movzx eax, [ebx+xfs_dir2_sf.hdr.count]
; '..' and '.' are implicit
add eax, 2
mov [ebp+XFS.entries_left_in_dir], eax
mov [edx+bdfe_hdr.total_cnt], eax
; inode numbers are often saved as 4 bytes (iff they fit)
; compute the length of inode numbers
; 8 iff i8count != 0, 4 otherwise
cmp [ebx+xfs_dir2_sf.hdr.i8count], 0
setnz al
lea eax, [eax*4+4]
mov [ebp+XFS.shortform_inodelen], eax
add edx, sizeof.bdfe_hdr
lea esi, [ebx+xfs_dir2_sf.hdr.parent+eax]
stdcall xfs._.dir_sf_skip, [ebp+XFS.entries_to_skip]
stdcall xfs._.dir_sf_read, [ebp+XFS.requested_cnt]
ret
endp
 
 
proc xfs._.readdir_block _literal_area, _out_buf
mov ebx, [_literal_area]
mov [ebp+XFS.entries_read], 0
mov eax, ebx
mov ebx, [ebp+XFS.cur_dirblock]
stdcall xfs._.extent_unpack, eax
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], ebx
mov edx, [_out_buf]
jnz .error
mov eax, [ebp+XFS.dir_block_magic]
cmp [ebx+xfs_dir2_block.hdr.magic], eax
movi eax, ERROR_FS_FAIL
jnz .error
mov eax, [ebp+XFS.dirblocksize]
movbe ecx, [ebx+eax-sizeof.xfs_dir2_block_tail+xfs_dir2_block_tail.stale]
movbe eax, [ebx+eax-sizeof.xfs_dir2_block_tail+xfs_dir2_block_tail.count]
sub eax, ecx ; actual number of entries = count - stale
mov [ebp+XFS.entries_left_in_dir], eax
mov [edx+bdfe_hdr.total_cnt], eax
 
add ebx, [ebp+XFS.dir_block_size]
add edx, sizeof.bdfe_hdr
mov [_out_buf], edx
lea edi, [_out_buf]
.next:
movi eax, ERROR_SUCCESS
cmp [ebp+XFS.requested_cnt], 0
jz .quit
cmp [ebp+XFS.entries_left_in_dir], 0
jz .quit
stdcall xfs._.dir_entry_skip_read, edi
jz .next
.error:
.quit:
ret
endp
 
 
proc xfs._.readdir_leaf_node uses esi, _inode_data, _out_buf
mov ebx, [_inode_data]
mov edx, [_out_buf]
mov [ebp+XFS.cur_inode_save], ebx
mov [ebp+XFS.entries_read], 0
mov eax, ebx
add eax, [ebp+XFS.inode_core_size]
movbe edx, [ebx+xfs_inode.di_core.di_nextents]
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.lo]
mov [ebp+XFS.offset_begin.lo], ecx
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
mov [ebp+XFS.offset_begin.hi], ecx
mov ecx, [ebp+XFS.dir2_free_offset_blocks.lo]
mov [ebp+XFS.offset_end.lo], ecx
mov ecx, [ebp+XFS.dir2_free_offset_blocks.hi]
mov [ebp+XFS.offset_end.hi], ecx
stdcall xfs._.walk_extent_list, edx, eax, xfs._.extent_iterate_dirblocks, xfs._.leafn_calc_entries, 0
jnz .error
mov eax, [ebp+XFS.entries_read]
mov edx, [_out_buf]
mov [edx+bdfe_hdr.total_cnt], eax
mov [ebp+XFS.entries_left_in_dir], eax
add [_out_buf], sizeof.bdfe_hdr
mov [ebp+XFS.entries_read], 0
movbe edx, [ebx+xfs_inode.di_core.di_nextents]
mov eax, ebx
add eax, [ebp+XFS.inode_core_size]
lea ecx, [_out_buf]
push ecx
mov [ebp+XFS.offset_begin.lo], 0
mov [ebp+XFS.offset_begin.hi], 0
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.lo]
mov [ebp+XFS.offset_end.lo], ecx
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
mov [ebp+XFS.offset_end.hi], ecx
pop ecx
stdcall xfs._.walk_extent_list, edx, eax, xfs._.extent_iterate_dirblocks, xfs._.dir_btree_skip_read, ecx
; jnz .error
.error:
.quit:
ret
endp
 
 
proc xfs._.dir_entry_skip_read uses esi edi, _arg
cmp [ebx+xfs_dir2_data_union.unused.freetag], XFS_NULL
jnz @f
movzx eax, [ebx+xfs_dir2_data_union.unused.length]
xchg al, ah
add ebx, eax
jmp .quit
@@:
cmp [ebp+XFS.entries_to_skip], 0
jz .read
.skip:
dec [ebp+XFS.entries_to_skip]
movzx ecx, [ebx+xfs_dir2_data_union.xentry.namelen]
lea ebx, [ebx+xfs_dir2_data_union.xentry.name+ecx+2]
add ebx, [ebp+XFS.ftype_size]
jmp .common
.read:
dec [ebp+XFS.requested_cnt]
inc [ebp+XFS.entries_read]
mov edi, [_arg]
mov edi, [edi]
movbe edx, [ebx+xfs_dir2_data_union.xentry.inumber.lo]
movbe eax, [ebx+xfs_dir2_data_union.xentry.inumber.hi]
stdcall xfs_read_inode, eax, edx, [ebp+XFS.tmp_inode]
stdcall xfs_get_inode_info, edx, edi
jnz .error
mov edx, [_arg]
mov edx, [edx]
mov ecx, [ebp+XFS.bdfe_nameenc]
mov [edx+bdfe.nameenc], ecx
lea edi, [edx+bdfe.name]
movzx ecx, [ebx+xfs_dir2_data_union.xentry.namelen]
lea esi, [ebx+xfs_dir2_data_union.xentry.name]
stdcall xfs._.copy_filename
lea ebx, [esi+2] ; skip 'tag'
add ebx, [ebp+XFS.ftype_size]
mov eax, [_arg]
mov edx, [eax]
add edx, [ebp+XFS.bdfe_len]
mov [eax], edx
.common:
sub ebx, [ebp+XFS.cur_dirblock]
add ebx, 7 ; xfs_dir2_data_entries are aligned to 8 bytes
and ebx, not 7
add ebx, [ebp+XFS.cur_dirblock]
dec [ebp+XFS.entries_left_in_dir]
.quit:
movi eax, ERROR_SUCCESS
cmp esp, esp
.error:
ret
endp
 
 
proc xfs._.dir_btree_skip_read uses ebx ecx edx esi edi, _cur_dirblock, _offset_lo, _offset_hi, _arg
mov ebx, [_cur_dirblock]
mov eax, [ebp+XFS.dir_data_magic]
cmp [ebx+xfs_dir2_block.hdr.magic], eax
movi eax, ERROR_FS_FAIL
jnz .error
mov eax, ebx
add eax, [ebp+XFS.dirblocksize]
mov [ebp+XFS.max_dirblockaddr], eax
; add ebx, xfs_dir2_block.u
add ebx, [ebp+XFS.dir_block_size]
.next:
movi eax, ERROR_SUCCESS
cmp [ebp+XFS.requested_cnt], 0
jz .quit
cmp [ebp+XFS.entries_left_in_dir], 0
jz .quit
cmp ebx, [ebp+XFS.max_dirblockaddr]
jz .quit
stdcall xfs._.dir_entry_skip_read, [_arg]
jz .next
.error:
.quit:
ret
endp
 
 
proc xfs._.readdir_btree uses esi, _inode_data, _out_buf
mov [ebp+XFS.cur_inode_save], ebx
mov [ebp+XFS.entries_read], 0
mov eax, [ebp+XFS.inodesize]
sub eax, xfs_inode.di_u
movzx ecx, [ebx+xfs_inode.di_core.di_forkoff]
jecxz @f
shl ecx, 3
mov eax, ecx
@@:
lea edx, [ebx+xfs_inode.di_u]
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.lo]
mov [ebp+XFS.offset_begin.lo], ecx
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
mov [ebp+XFS.offset_begin.hi], ecx
mov ecx, [ebp+XFS.dir2_free_offset_blocks.lo]
mov [ebp+XFS.offset_end.lo], ecx
mov ecx, [ebp+XFS.dir2_free_offset_blocks.hi]
mov [ebp+XFS.offset_end.hi], ecx
stdcall xfs._.walk_btree, edx, eax, xfs._.extent_iterate_dirblocks, xfs._.leafn_calc_entries, 0, 1
mov eax, [ebp+XFS.entries_read]
mov edx, [_out_buf]
mov [edx+bdfe_hdr.total_cnt], eax
mov [ebp+XFS.entries_left_in_dir], eax
mov [ebp+XFS.entries_read], 0
add [_out_buf], sizeof.bdfe_hdr
mov eax, [ebp+XFS.inodesize]
sub eax, xfs_inode.di_u
movzx ecx, [ebx+xfs_inode.di_core.di_forkoff]
jecxz @f
shl ecx, 3
mov eax, ecx
@@:
lea edx, [ebx+xfs_inode.di_u]
mov [ebp+XFS.offset_begin.lo], 0
mov [ebp+XFS.offset_begin.hi], 0
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.lo]
mov [ebp+XFS.offset_end.lo], ecx
mov ecx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
mov [ebp+XFS.offset_end.hi], ecx
mov ecx, [_out_buf]
push ecx
mov ecx, esp
stdcall xfs._.walk_btree, edx, eax, xfs._.extent_iterate_dirblocks, xfs._.dir_btree_skip_read, ecx, 1
pop ecx
.error:
.quit:
ret
endp
 
 
proc xfs._.copy_filename uses eax
mov eax, [ebp+XFS.bdfe_nameenc]
cmp eax, 3
jz .utf8
cmp eax, 2
jz .utf16
.cp866:
call unicode.utf8.decode
call unicode.cp866.encode
stosb
test ecx, ecx
jnz .cp866
mov byte[edi], 0
jmp .done
.utf16:
call unicode.utf8.decode
call unicode.utf16.encode
stosw
shr eax, 16
jz @f
stosw
@@:
test ecx, ecx
jnz .utf16
mov word[edi], 0
jmp .done
.utf8:
rep movsb
mov byte[edi], 0
.done:
ret
endp
 
;----------------------------------------------------------------
; src ; inode
; dst ; bdfe
; start_number ; from 0
;----------------------------------------------------------------
proc xfs._.readdir uses ebx esi edi, _start_number, _entries_to_read, _dst, _src, _encoding
mov ecx, [_start_number]
mov [ebp+XFS.entries_to_skip], ecx
mov eax, [_entries_to_read]
mov [ebp+XFS.requested_cnt], eax
mov eax, [_encoding]
mov [ebp+XFS.bdfe_nameenc], eax
mov ecx, 304
cmp eax, 1 ; CP866
jbe @f
mov ecx, 560
@@:
mov [ebp+XFS.bdfe_len], ecx
mov edx, [_dst]
mov [ebp+XFS.bdfe_buf], edx
mov ebx, [_src]
mov [ebp+XFS.cur_inode_save], ebx
 
mov [edx+bdfe_hdr.version], 1
mov [edx+bdfe_hdr.zeroed+0x00], 0
mov [edx+bdfe_hdr.zeroed+0x04], 0
mov [edx+bdfe_hdr.zeroed+0x08], 0
mov [edx+bdfe_hdr.zeroed+0x0c], 0
mov [edx+bdfe_hdr.zeroed+0x10], 0
 
movzx eax, [ebx+xfs_inode.di_core.di_format]
; switch directory ondisk format and jump to corresponding label
cmp eax, XFS_DINODE_FMT_LOCAL
jnz @f
add ebx, [ebp+XFS.inode_core_size]
stdcall xfs._.readdir_sf, ebx, [_dst]
test eax, eax
jnz .error
jmp .quit
@@:
cmp eax, XFS_DINODE_FMT_BTREE
jnz @f
stdcall xfs._.readdir_btree, ebx, [_dst]
jmp .quit
@@:
cmp eax, XFS_DINODE_FMT_EXTENTS
movi eax, ERROR_FS_FAIL
jnz .error
call xfs._.get_last_dirblock
test eax, eax
jnz @f
add ebx, [ebp+XFS.inode_core_size]
stdcall xfs._.readdir_block, ebx, [_dst]
jmp .quit
@@:
stdcall xfs._.readdir_leaf_node, ebx, [_dst]
jmp .quit
.quit:
mov edx, [_dst]
mov ebx, [ebp+XFS.entries_read]
mov [edx+bdfe_hdr.read_cnt], ebx
xor eax, eax
.error:
ret
endp
 
 
; returns edx:eax inode or 0
proc xfs._.lookup_sf _name, _len
add ebx, [ebp+XFS.inode_core_size]
mov esi, [_name]
mov ecx, [_len]
cmp ecx, 2
ja .common
jz .check_parent
.check_self:
cmp byte[esi], '.'
jnz .common
mov eax, [ebp+XFS.inode_self.lo]
mov edx, [ebp+XFS.inode_self.hi]
jmp .quit
.check_parent:
cmp word[esi], '..'
jnz .common
lea edx, [ebx+xfs_dir2_sf.hdr.parent]
call xfs._.get_inode_number_sf
jmp .quit
.common:
movzx edx, [ebx+xfs_dir2_sf.hdr.count]
movi eax, 0
cmp [ebx+xfs_dir2_sf.hdr.i8count], 0
setnz al
lea eax, [eax*4+4]
lea edi, [ebx+xfs_dir2_sf.hdr.parent+eax]
.next_name:
dec edx
jns @f
movi eax, ERROR_FILE_NOT_FOUND
jmp .error
@@:
movzx ecx, [edi+xfs_dir2_sf_entry.namelen]
add edi, xfs_dir2_sf_entry.name
mov esi, [_name]
cmp ecx, [_len]
jnz @f
repz cmpsb
jz .found
@@:
add edi, [ebp+XFS.ftype_size]
add edi, ecx
add edi, eax
jmp .next_name
.found:
add edi, [ebp+XFS.ftype_size]
mov edx, edi
call xfs._.get_inode_number_sf
.quit:
cmp esp, esp
.error:
ret
endp
 
 
proc xfs._.lookup_block uses esi, _name, _len
add ebx, [ebp+XFS.inode_core_size]
mov eax, ebx
mov ebx, [ebp+XFS.cur_dirblock]
stdcall xfs._.extent_unpack, eax
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], ebx
jnz .error
mov eax, [ebp+XFS.dir_block_magic]
cmp [ebx+xfs_dir2_block.hdr.magic], eax
movi eax, ERROR_FS_FAIL
jnz .error
stdcall xfs_hashname, [_name+4], [_len]
add ebx, [ebp+XFS.dirblocksize]
movbe ecx, [ebx-sizeof.xfs_dir2_block_tail+xfs_dir2_block_tail.count]
lea edx, [ecx*sizeof.xfs_dir2_leaf_entry+sizeof.xfs_dir2_block_tail]
sub ebx, edx
stdcall xfs._.get_addr_by_hash, ebx, ecx
jnz .error
mov ebx, [ebp+XFS.cur_dirblock]
movbe edx, [ebx+eax*XFS_DIR2_DATA_ALIGN+xfs_dir2_data_entry.inumber.lo]
movbe eax, [ebx+eax*XFS_DIR2_DATA_ALIGN+xfs_dir2_data_entry.inumber.hi]
.quit:
.error:
ret
endp
 
 
proc xfs._.get_inode_by_addr uses ebx esi edi, _inode_buf
xor edx, edx
shld edx, eax, XFS_DIR2_DATA_ALIGN_LOG
shl eax, XFS_DIR2_DATA_ALIGN_LOG
mov esi, [ebp+XFS.dirblocksize]
dec esi
and esi, eax
mov ecx, [ebp+XFS.blocklog]
add ecx, [ebp+XFS.dirblklog]
shrd eax, edx, cl
shr edx, cl
mov ecx, [ebp+XFS.dirblklog]
shld edx, eax, cl
shl eax, cl
mov ebx, [_inode_buf]
cmp [ebx+xfs_inode.di_core.di_format], XFS_DINODE_FMT_EXTENTS
jz .extents
cmp [ebx+xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE
jz .btree
jmp .error
.extents:
movbe ecx, [ebx+xfs_inode.di_core.di_nextents]
add ebx, [ebp+XFS.inode_core_size]
mov [ebp+XFS.offset_begin.lo], eax
mov [ebp+XFS.offset_begin.hi], edx
stdcall xfs._.extent_list.seek, ecx
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], [ebp+XFS.cur_dirblock]
jnz .error
jmp .common
.btree:
movzx ecx, [ebx+xfs_inode.di_core.di_forkoff]
shl ecx, 3
test ecx, ecx
jnz @f
mov ecx, [ebp+XFS.inodesize]
sub ecx, [ebp+XFS.inode_core_size]
@@:
add ebx, [ebp+XFS.inode_core_size]
stdcall xfs._.btree_read_block, ebx, ecx, eax, edx, [ebp+XFS.cur_dirblock]
.common:
mov ebx, [ebp+XFS.cur_dirblock]
mov eax, [ebp+XFS.dir_data_magic]
cmp [ebx+xfs_dir2_block.hdr.magic], eax
movi eax, ERROR_FS_FAIL
jnz .error
movbe edx, [ebx+esi+xfs_dir2_data_entry.inumber.lo]
movbe eax, [ebx+esi+xfs_dir2_data_entry.inumber.hi]
.error:
.quit:
ret
endp
 
 
proc xfs._.lookup_leaf uses ebx esi edi, _name, _len
movbe ecx, [ebx+xfs_inode.di_core.di_nextents]
add ebx, [ebp+XFS.inode_core_size]
mov eax, [ebp+XFS.dir2_leaf_offset_blocks.lo]
mov [ebp+XFS.offset_begin.lo], ecx
mov eax, [ebp+XFS.dir2_leaf_offset_blocks.hi]
mov [ebp+XFS.offset_begin.hi], ecx
stdcall xfs._.extent_list.seek, ecx
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], [ebp+XFS.cur_dirblock]
jnz .error
mov ebx, [ebp+XFS.cur_dirblock]
movzx eax, [ebp+XFS.dir_leaf1_magic]
cmp [ebx+xfs_dir2_leaf.hdr.info.magic], ax
movi eax, ERROR_FS_FAIL
jnz .error
stdcall xfs_hashname, [_name+4], [_len]
cmp [ebp+XFS.version], 5
jz .v5
.v4:
movzx ecx, [ebx+xfs_dir2_leaf.hdr.count]
xchg cl, ch
add ebx, xfs_dir2_leaf.ents
jmp .vcommon
.v5:
movzx ecx, [ebx+xfs_dir3_leaf.hdr.count]
xchg cl, ch
add ebx, xfs_dir3_leaf.ents
.vcommon:
stdcall xfs._.get_addr_by_hash, ebx, ecx
jnz .error
stdcall xfs._.get_inode_by_addr, [ebp+XFS.cur_inode_save]
.quit:
.error:
ret
endp
 
 
proc xfs._.lookup_node uses ebx esi edi, _name, _len
locals
.hash dd ?
endl
mov [ebp+XFS.cur_inode_save], ebx
stdcall xfs_hashname, [_name+4], [_len]
mov [.hash], eax
mov eax, ebx
add eax, [ebp+XFS.inode_core_size]
movbe edx, [ebx+xfs_inode.di_core.di_nextents]
mov esi, [ebp+XFS.dir2_leaf_offset_blocks.lo]
.begin:
mov ebx, [ebp+XFS.cur_inode_save]
mov eax, ebx
add eax, [ebp+XFS.inode_core_size]
movbe edx, [ebx+xfs_inode.di_core.di_nextents]
mov ebx, eax
mov [ebp+XFS.offset_begin.lo], esi
mov [ebp+XFS.offset_begin.hi], 0
stdcall xfs._.extent_list.seek, edx
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], [ebp+XFS.cur_dirblock]
jnz .error
mov ebx, [ebp+XFS.cur_dirblock]
movzx eax, [ebp+XFS.da_node_magic]
cmp [ebx+xfs_da_intnode.hdr.info.magic], ax
jz .node
movzx eax, [ebp+XFS.dir_leafn_magic]
cmp [ebx+xfs_dir2_leaf.hdr.info.magic], ax
jz .leaf
movi eax, ERROR_FS_FAIL
jmp .error
.node:
cmp [ebp+XFS.version], 5
jz .node.v5
.node.v4:
lea eax, [ebx+sizeof.xfs_da_intnode]
movzx edx, [ebx+xfs_da_intnode.hdr.count]
jmp .node.vcommon
.node.v5:
lea eax, [ebx+sizeof.xfs_da3_intnode]
movzx edx, [ebx+xfs_da3_intnode.hdr.count]
.node.vcommon:
xchg dl, dh
stdcall xfs._.get_before_by_hashval, eax, edx, [.hash]
jnz .error
mov esi, eax
jmp .begin
.leaf:
cmp [ebp+XFS.version], 5
jz .leaf.v5
.leaf.v4:
movzx ecx, [ebx+xfs_dir2_leaf.hdr.count]
xchg cl, ch
add ebx, xfs_dir2_leaf.ents
jmp .leaf.vcommon
.leaf.v5:
movzx ecx, [ebx+xfs_dir3_leaf.hdr.count]
xchg cl, ch
add ebx, xfs_dir3_leaf.ents
.leaf.vcommon:
mov eax, [.hash]
stdcall xfs._.get_addr_by_hash, ebx, ecx
jnz .error
stdcall xfs._.get_inode_by_addr, [ebp+XFS.cur_inode_save]
.quit:
cmp esp, esp
ret
.error:
test esp, esp
ret
endp
 
 
proc xfs._.lookup_btree uses ebx esi edi, _name, _len
locals
.hash dd ?
endl
mov [ebp+XFS.cur_inode_save], ebx
stdcall xfs_hashname, [_name+4], [_len]
mov [.hash], eax
mov edx, [ebp+XFS.dir2_leaf_offset_blocks.hi]
mov eax, [ebp+XFS.dir2_leaf_offset_blocks.lo]
jmp .next_level.first
.next_level:
lea eax, [ebx+sizeof.xfs_da_intnode]
movzx edx, [ebx+xfs_da_intnode.hdr.count]
xchg dl, dh
stdcall xfs._.get_before_by_hashval, eax, edx, [.hash]
jnz .error
xor edx, edx
.next_level.first:
mov ebx, [ebp+XFS.cur_inode_save]
movzx ecx, [ebx+xfs_inode.di_core.di_forkoff]
shl ecx, 3
test ecx, ecx
jnz @f
mov ecx, [ebp+XFS.inodesize]
sub ecx, xfs_inode.di_u
@@:
add ebx, xfs_inode.di_u
stdcall xfs._.btree_read_block, ebx, ecx, eax, edx, [ebp+XFS.cur_dirblock]
mov ebx, [ebp+XFS.cur_dirblock]
cmp [ebx+xfs_da_intnode.hdr.info.magic], XFS_DA_NODE_MAGIC
jz .next_level
cmp [ebx+xfs_dir2_leaf.hdr.info.magic], XFS_DIR2_LEAFN_MAGIC
jz .leafn
cmp [ebx+xfs_dir2_leaf.hdr.info.magic], XFS_DIR2_LEAF1_MAGIC
jnz .error
mov eax, [.hash]
movzx ecx, [ebx+xfs_dir2_leaf.hdr.count]
xchg cl, ch
add ebx, xfs_dir2_leaf.ents
stdcall xfs._.get_addr_by_hash, ebx, ecx
jnz .error
mov ebx, [ebp+XFS.cur_dirblock]
jmp .got_addr
.leafn:
movzx ecx, [ebx+xfs_dir2_leaf.hdr.count]
xchg cl, ch
add ebx, xfs_dir2_leaf.ents
mov eax, [.hash]
stdcall xfs._.get_addr_by_hash, ebx, ecx
jnz .error
mov ebx, [ebp+XFS.cur_block]
.got_addr:
stdcall xfs._.get_inode_by_addr, [ebp+XFS.cur_inode_save]
.quit:
cmp esp, esp
ret
.error:
test esp, esp
ret
endp
 
 
; search for the _name in _inode dir
; called for each /path/component/to/my/file
; out:
; ZF/zf = ok/fail
; edx:eax = inode/garbage:error
proc xfs._.get_inode_short uses esi, _inode:qword, _len, _name
mov esi, [_name]
mov eax, dword[_inode+DQ.lo]
mov edx, dword[_inode+DQ.hi]
stdcall xfs_read_inode, eax, edx, [ebp+XFS.cur_inode]
test eax, eax
movi eax, ERROR_FS_FAIL
jnz .error
; switch directory ondisk format
mov ebx, edx
mov [ebp+XFS.cur_inode_save], ebx
movzx eax, [ebx+xfs_inode.di_core.di_format]
cmp eax, XFS_DINODE_FMT_LOCAL
mov edi, xfs._.lookup_sf
jz .lookup
cmp eax, XFS_DINODE_FMT_BTREE
mov edi, xfs._.lookup_btree
jz .lookup
cmp eax, XFS_DINODE_FMT_EXTENTS
jnz .error
call xfs._.get_last_dirblock
test eax, eax
mov edi, xfs._.lookup_block
jz .lookup
cmp edx, [ebp+XFS.dir2_free_offset_blocks.hi]
mov edi, xfs._.lookup_node
ja .lookup
cmp eax, [ebp+XFS.dir2_free_offset_blocks.lo]
jae .lookup
mov edi, xfs._.lookup_leaf
.lookup:
stdcall edi, [_name+4], [_len]
.error:
ret
endp
 
 
; ZF/zf = ok/fail
; edx:eax = inode/garbage:error
proc xfs_get_inode uses ebx esi edi, _name
; call *._.get_inode_short until file is found / error returned
; start from the root inode
mov eax, [ebp+XFS.rootino.lo]
mov edx, [ebp+XFS.rootino.hi]
mov esi, [_name]
.next_dir:
@@:
cmp byte[esi], '/'
jnz @f
inc esi
jmp @b
@@:
cmp byte[esi], 0
jz .found
push esi
inc esi
@@:
cmp byte[esi], 0
jz @f
cmp byte[esi], '/'
jz @f
inc esi
jmp @b
@@:
mov ecx, esi
sub ecx, [esp]
mov [ebp+XFS.inode_self.lo], eax
mov [ebp+XFS.inode_self.hi], edx
stdcall xfs._.get_inode_short, eax, edx, ecx ; esi pushed above
jz .next_dir
.error:
.found:
ret
endp
 
 
; in: ebp = pointer to XFS structure
; in: esi
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
; out: [edx] -- f70.1 out structure
proc xfs_ReadFolder uses esi edi
call xfs._.lock
stdcall xfs_get_inode, esi
jnz .error
stdcall xfs_read_inode, eax, edx, [ebp+XFS.cur_inode]
test eax, eax
jnz .error
stdcall xfs._.readdir, [ebx+f70s1arg.start_idx], [ebx+f70s1arg.count], [ebx+f70s1arg.buf], edx, [ebx+f70s1arg.encoding]
test eax, eax
jnz .error
mov edx, [ebx+f70s1arg.buf]
mov ecx, [ebx+f70s1arg.count]
cmp [edx+bdfe_hdr.read_cnt], ecx
jz .quit
movi eax, ERROR_END_OF_FILE
.quit:
mov ebx, [edx+bdfe_hdr.read_cnt]
 
.error:
push eax
call xfs._.unlock
pop eax
ret
endp
 
 
; edx -- pointer to inode number in big endian
; ZF -- must be set at exit
proc xfs._.get_inode_number_sf
cmp [ebx+xfs_dir2_sf.hdr.i8count], 0
jz .i4bytes
.i8bytes:
movbe eax, [edx+DQ.hi]
movbe edx, [edx+DQ.lo]
ret
.i4bytes:
movbe eax, [edx+DQ.lo]
xor edx, edx
ret
endp
 
 
proc xfs_get_inode_info uses ebx, _src, _dst
; get access time and other file properties
; useful for browsing directories
; called for each dir entry
xor eax, eax
mov edx, [_src]
movzx ecx, [edx+xfs_inode.di_core.di_mode]
xchg cl, ch
test ecx, S_IFDIR
jz @f
movi eax, 0x10 ; set directory flag
@@:
mov edi, [_dst]
mov [edi+bdfe.attr], eax
movbe eax, [edx+xfs_inode.di_core.di_size.lo]
mov [edi+bdfe.size.hi], eax
movbe eax, [edx+xfs_inode.di_core.di_size.hi]
mov [edi+bdfe.size.lo], eax
 
add edi, 8
movbe eax, [edx+xfs_inode.di_core.di_ctime.t_sec]
push edx
sub eax, 978307200 ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
call fsTime2bdfe
pop edx
 
movbe eax, [edx+xfs_inode.di_core.di_atime.t_sec]
push edx
sub eax, 978307200 ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
call fsTime2bdfe
pop edx
 
movbe eax, [edx+xfs_inode.di_core.di_mtime.t_sec]
push edx
sub eax, 978307200 ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
call fsTime2bdfe
pop edx
 
movi eax, ERROR_SUCCESS
cmp esp, esp
ret
endp
 
 
proc xfs._.extent_unpack uses eax ebx ecx edx, _extent_data
; extents come as packet 128bit bitfields
; unpack them to access internal fields
; write result to the XFS.extent structure
mov ebx, [_extent_data]
 
xor eax, eax
movbe edx, [ebx+0]
test edx, 0x80000000 ; mask, see documentation
setnz al
mov [ebp+XFS.extent.br_state], eax
 
and edx, 0x7fffffff ; mask
movbe eax, [ebx+4]
shrd eax, edx, 9
shr edx, 9
mov [ebp+XFS.extent.br_startoff.lo], eax
mov [ebp+XFS.extent.br_startoff.hi], edx
 
movbe edx, [ebx+4]
movbe eax, [ebx+8]
movbe ecx, [ebx+12]
and edx, 0x000001ff ; mask
shrd ecx, eax, 21
shrd eax, edx, 21
mov [ebp+XFS.extent.br_startblock.lo], ecx
mov [ebp+XFS.extent.br_startblock.hi], eax
 
movbe eax, [ebx+12]
and eax, 0x001fffff ; mask
mov [ebp+XFS.extent.br_blockcount], eax
ret
endp
 
 
proc xfs_hashname uses ecx esi, _name, _len
xor eax, eax
mov esi, [_name]
mov ecx, [_len]
@@:
rol eax, 7
xor al, [esi]
add esi, 1
dec ecx
jnz @b
ret
endp
 
 
; eax -- hash value
proc xfs._.get_addr_by_hash uses ebx esi, _base, _len
; look for the directory entry offset by its file name hash
; allows fast file search for block, leaf and node directories
; binary (ternary) search
mov ebx, [_base]
mov edx, [_len]
.next:
mov ecx, edx
; jecxz .error
test ecx, ecx
jz .not_found
shr ecx, 1
movbe esi, [ebx+ecx*sizeof.xfs_dir2_leaf_entry+xfs_dir2_leaf_entry.hashval]
cmp eax, esi
jb .below
ja .above
movbe eax, [ebx+ecx*sizeof.xfs_dir2_leaf_entry+xfs_dir2_leaf_entry.address]
ret
.below:
mov edx, ecx
jmp .next
.above:
lea ebx, [ebx+(ecx+1)*sizeof.xfs_dir2_leaf_entry]
sub edx, ecx
dec edx
jmp .next
.not_found:
movi eax, ERROR_FILE_NOT_FOUND
test esp, esp
ret
endp
 
 
;----------------------------------------------------------------
; xfs_GetFileInfo: XFS implementation of getting file info
; in: ebp = pointer to XFS structure
; in: esi = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
proc xfs_GetFileInfo uses ecx edx esi edi
call xfs._.lock
stdcall xfs_get_inode, esi
jnz .error
stdcall xfs_read_inode, eax, edx, [ebp+XFS.cur_inode]
test eax, eax
movi eax, ERROR_FS_FAIL
jnz .error
stdcall xfs_get_inode_info, edx, [ebx+f70s5arg.buf]
.quit:
call xfs._.unlock
xor eax, eax
ret
.error:
push eax
call xfs._.unlock
pop eax
ret
endp
 
 
proc xfs._.file.read_extent uses ebx ecx edx, _callback, _callback_data
mov eax, [ebp+XFS.file_offset.lo]
mov edx, [ebp+XFS.file_offset.hi]
mov esi, [ebp+XFS.extent.br_startoff.lo]
mov edi, [ebp+XFS.extent.br_startoff.hi]
mov ecx, [ebp+XFS.blocklog]
shld edi, esi, cl
shl esi, cl
cmp edx, edi
jb .hole
ja .try_head
cmp eax, esi
ja .try_head
jz .try_match
.hole:
sub esi, eax
sbb edi, edx
movi ecx, -1
test edi, edi
jnz @f
mov ecx, esi
@@:
cmp ecx, [ebp+XFS.bytes_to_read]
jbe @f
mov ecx, [ebp+XFS.bytes_to_read]
@@:
mov edi, [ebp+XFS.file_buffer]
xor eax, eax
sub [ebp+XFS.bytes_to_read], ecx
sub [ebp+XFS.bytes_left_in_file.lo], ecx
sbb [ebp+XFS.bytes_left_in_file.hi], 0
add [ebp+XFS.bytes_read], ecx
add [ebp+XFS.file_buffer], ecx
add [ebp+XFS.file_offset.lo], ecx
adc [ebp+XFS.file_offset.hi], 0
rep stosb
cmp [ebp+XFS.bytes_to_read], 0
jz .quit
jmp .try_match
.try_head:
mov eax, [ebp+XFS.file_offset.lo]
mov ecx, [ebp+XFS.blocksize]
dec ecx
test eax, ecx
jz .try_match
.head:
mov eax, [ebp+XFS.extent.br_startblock.lo]
mov edx, [ebp+XFS.extent.br_startblock.hi]
mov ebx, [ebp+XFS.cur_block_data]
stdcall xfs._.read_block
mov esi, [ebp+XFS.cur_block_data]
mov edi, [ebp+XFS.file_buffer]
mov eax, [ebp+XFS.file_offset.lo]
mov ecx, [ebp+XFS.blocksize]
dec ecx
and eax, ecx
add esi, eax
inc ecx
sub ecx, eax
cmp ecx, [ebp+XFS.bytes_to_read]
jbe @f
mov ecx, [ebp+XFS.bytes_to_read]
@@:
sub [ebp+XFS.bytes_to_read], ecx
sub [ebp+XFS.bytes_left_in_file.lo], ecx
sbb [ebp+XFS.bytes_left_in_file.hi], 0
add [ebp+XFS.bytes_read], ecx
add [ebp+XFS.file_buffer], ecx
add [ebp+XFS.file_offset.lo], ecx
adc [ebp+XFS.file_offset.hi], 0
rep movsb
add [ebp+XFS.extent.br_startoff.lo], 1
adc [ebp+XFS.extent.br_startoff.hi], 0
add [ebp+XFS.extent.br_startblock.lo], 1
adc [ebp+XFS.extent.br_startblock.hi], 0
dec [ebp+XFS.extent.br_blockcount]
; cmp [ebp+XFS.bytes_to_read], 0
jz .quit
.try_match:
mov eax, [ebp+XFS.bytes_to_read]
test eax, eax
jz .quit
cmp eax, [ebp+XFS.blocksize]
jb .tail
mov ecx, [ebp+XFS.blocklog]
shr eax, cl
cmp eax, [ebp+XFS.extent.br_blockcount]
jbe @f
mov eax, [ebp+XFS.extent.br_blockcount]
@@:
mov ecx, eax
mov eax, [ebp+XFS.extent.br_startblock.lo]
mov edx, [ebp+XFS.extent.br_startblock.hi]
mov ebx, [ebp+XFS.file_buffer]
push ecx
stdcall xfs._.read_blocks
pop eax
add [ebp+XFS.extent.br_startoff.lo], eax
adc [ebp+XFS.extent.br_startoff.hi], 0
add [ebp+XFS.extent.br_startblock.lo], eax
adc [ebp+XFS.extent.br_startblock.hi], 0
sub [ebp+XFS.extent.br_blockcount], eax
imul eax, [ebp+XFS.blocksize]
sub [ebp+XFS.bytes_to_read], eax
sub [ebp+XFS.bytes_left_in_file.lo], eax
sbb [ebp+XFS.bytes_left_in_file.hi], 0
add [ebp+XFS.bytes_read], eax
add [ebp+XFS.file_buffer], eax
add [ebp+XFS.file_offset.lo], eax
adc [ebp+XFS.file_offset.hi], 0
; cmp [ebp+XFS.bytes_to_read], 0
cmp [ebp+XFS.extent.br_blockcount], 0
jz .quit
.tail:
mov eax, [ebp+XFS.extent.br_startblock.lo]
mov edx, [ebp+XFS.extent.br_startblock.hi]
mov ebx, [ebp+XFS.cur_block_data]
stdcall xfs._.read_block
mov ecx, [ebp+XFS.bytes_to_read]
cmp [ebp+XFS.bytes_left_in_file.hi], 0
jnz @f
cmp ecx, [ebp+XFS.bytes_left_in_file.lo]
jbe @f
mov ecx, [ebp+XFS.bytes_left_in_file.lo]
@@:
mov esi, [ebp+XFS.cur_block_data]
mov edi, [ebp+XFS.file_buffer]
mov eax, ecx
rep movsb
add [ebp+XFS.bytes_read], eax
sub [ebp+XFS.bytes_to_read], eax
sub [ebp+XFS.bytes_left_in_file.lo], eax
sbb [ebp+XFS.bytes_left_in_file.hi], 0
add [ebp+XFS.file_buffer], eax
add [ebp+XFS.file_offset.lo], eax
adc [ebp+XFS.file_offset.hi], 0
add [ebp+XFS.extent.br_startoff.lo], 1
adc [ebp+XFS.extent.br_startoff.hi], 0
add [ebp+XFS.extent.br_startblock.lo], 1
adc [ebp+XFS.extent.br_startblock.hi], 0
dec [ebp+XFS.extent.br_blockcount]
.quit:
mov esi, [ebp+XFS.extent.br_startoff.lo]
mov edi, [ebp+XFS.extent.br_startoff.hi]
movi eax, ERROR_SUCCESS
cmp esp, esp
ret
endp
 
 
;----------------------------------------------------------------
; in: ebp = pointer to XFS structure
; in: esi = name
; in: ebx = pointer to parameters from sysfunc 70
; out: eax, ebx = return values for sysfunc 70
;----------------------------------------------------------------
proc xfs_Read uses ecx edx esi edi
locals
.offset_begin DQ ?
.offset_end DQ ?
endl
call xfs._.lock
mov [ebp+XFS.bytes_read], 0
mov eax, [ebx+f70s0arg.count]
mov [ebp+XFS.bytes_to_read], eax
test eax, eax
jz .quit
mov eax, [ebx+f70s0arg.buf]
mov [ebp+XFS.file_buffer], eax
mov eax, [ebx+f70s0arg.offset.hi]
mov [ebp+XFS.file_offset.hi], eax
mov eax, [ebx+f70s0arg.offset.lo]
mov [ebp+XFS.file_offset.lo], eax
 
stdcall xfs_get_inode, esi
jnz .error
stdcall xfs_read_inode, eax, edx, [ebp+XFS.cur_inode]
test eax, eax
movi eax, ERROR_FS_FAIL
jnz .error
mov [ebp+XFS.cur_inode_save], edx
mov ebx, edx
; precompute .offset_begin
mov esi, [ebp+XFS.file_offset.lo]
mov edi, [ebp+XFS.file_offset.hi]
mov ecx, [ebp+XFS.blocklog]
shrd esi, edi, cl
shr edi, cl
mov [.offset_begin.lo], esi
mov [.offset_begin.hi], edi
; precompute .offset_end
mov esi, [ebp+XFS.file_offset.lo]
mov edi, [ebp+XFS.file_offset.hi]
add esi, [ebp+XFS.bytes_to_read]
adc edi, 0
mov ecx, [ebp+XFS.blocksize]
dec ecx
add esi, ecx
adc edi, 0
mov ecx, [ebp+XFS.blocklog]
shrd esi, edi, cl
shr edi, cl
mov [.offset_end.lo], esi
mov [.offset_end.hi], edi
 
movbe ecx, [ebx+xfs_inode.di_core.di_size.hi]
movbe edx, [ebx+xfs_inode.di_core.di_size.lo]
mov [ebp+XFS.bytes_left_in_file.lo], ecx
mov [ebp+XFS.bytes_left_in_file.hi], edx
 
sub ecx, [ebp+XFS.file_offset.lo]
sbb edx, [ebp+XFS.file_offset.hi]
movi eax, ERROR_END_OF_FILE
jb .error
mov [ebp+XFS.eof], 0
test edx, edx
jnz @f
cmp ecx, [ebp+XFS.bytes_to_read]
jae @f
mov [ebp+XFS.eof], ERROR_END_OF_FILE
mov [ebp+XFS.bytes_to_read], ecx
@@:
 
cmp [ebx+xfs_inode.di_core.di_format], XFS_DINODE_FMT_BTREE
jz .btree
.extent_list:
mov eax, ebx
add eax, [ebp+XFS.inode_core_size]
movbe edx, [ebx+xfs_inode.di_core.di_nextents]
mov ecx, [.offset_begin.lo]
mov [ebp+XFS.offset_begin.lo], ecx
mov ecx, [.offset_begin.hi]
mov [ebp+XFS.offset_begin.hi], ecx
mov ecx, [.offset_end.lo]
mov [ebp+XFS.offset_end.lo], ecx
mov ecx, [.offset_end.hi]
mov [ebp+XFS.offset_end.hi], ecx
stdcall xfs._.walk_extent_list, edx, eax, xfs._.file.read_extent, 0, 0
jnz .error
jmp .hole_check
.btree:
mov eax, [ebp+XFS.inodesize]
sub eax, [ebp+XFS.inode_core_size]
movzx ecx, [ebx+xfs_inode.di_core.di_forkoff]
jecxz @f
shl ecx, 3
mov eax, ecx
@@:
mov edx, ebx
add edx, [ebp+XFS.inode_core_size]
mov ecx, [.offset_begin.lo]
mov [ebp+XFS.offset_begin.lo], ecx
mov ecx, [.offset_begin.hi]
mov [ebp+XFS.offset_begin.hi], ecx
mov ecx, [.offset_end.lo]
mov [ebp+XFS.offset_end.lo], ecx
mov ecx, [.offset_end.hi]
mov [ebp+XFS.offset_end.hi], ecx
stdcall xfs._.walk_btree, edx, eax, xfs._.file.read_extent, 0, 0, 1
.hole_check:
cmp [ebp+XFS.bytes_left_in_file.hi], 0
jnz @f
cmp [ebp+XFS.bytes_left_in_file.lo], 0
jz .hole_done
@@:
cmp [ebp+XFS.bytes_to_read], 0
jz .hole_done
mov ebx, [ebp+XFS.cur_inode_save]
movbe edx, [ebx+xfs_inode.di_core.di_size.lo]
movbe eax, [ebx+xfs_inode.di_core.di_size.hi]
sub eax, [ebp+XFS.file_offset.lo]
sbb edx, [ebp+XFS.file_offset.hi]
jc .hole_done
mov ecx, [ebp+XFS.bytes_to_read]
test edx, edx
jnz .hole_read
cmp eax, [ebp+XFS.bytes_to_read]
jae .hole_read
mov ecx, eax
jmp .hole_read
.hole_read:
sub [ebp+XFS.bytes_to_read], ecx
add [ebp+XFS.bytes_read], ecx
mov edi, [ebp+XFS.file_buffer]
xor eax, eax
rep stosb
.hole_done:
.quit:
mov eax, [ebp+XFS.eof]
.error:
push eax
call xfs._.unlock
pop eax
mov ebx, [ebp+XFS.bytes_read]
ret
endp
 
 
proc xfs._.leafn_calc_entries uses ebx ecx edx esi edi, _cur_dirblock, _offset_lo, _offset_hi, _arg
mov edx, [_cur_dirblock]
movzx eax, [ebp+XFS.da_node_magic]
cmp [edx+xfs_dir2_leaf.hdr.info.magic], ax
jz .quit
cmp [ebp+XFS.version], 5
jnz @f
add edx, xfs_dir3_leaf.hdr.count-xfs_dir2_leaf.hdr.count
@@:
movzx eax, [edx+xfs_dir2_leaf.hdr.count]
movzx ecx, [edx+xfs_dir2_leaf.hdr.stale]
xchg al, ah
xchg cl, ch
sub eax, ecx
add [ebp+XFS.entries_read], eax
.quit:
movi eax, ERROR_SUCCESS
cmp esp, esp
ret
endp
 
 
proc xfs._.get_before_by_hashval uses ebx edx esi edi, _base, _count, _hash
mov edi, [_hash]
mov edx, [_count]
xor ecx, ecx
.node.next:
movbe eax, [ebx+xfs_da_intnode.btree+ecx*sizeof.xfs_da_node_entry+xfs_da_node_entry.hashval]
cmp [ebp+XFS.version], 5
jnz @f
movbe eax, [ebx+xfs_da3_intnode.btree+ecx*sizeof.xfs_da_node_entry+xfs_da_node_entry.hashval]
@@:
cmp eax, edi
ja .node.leaf_found
inc ecx
cmp ecx, edx
jnz .node.next
movi eax, ERROR_FILE_NOT_FOUND
test esp, esp
jmp .error
.node.leaf_found:
movbe eax, [ebx+xfs_da_intnode.btree+ecx*sizeof.xfs_da_node_entry+xfs_da_node_entry.before]
cmp [ebp+XFS.version], 5
jnz @f
movbe eax, [ebx+xfs_da3_intnode.btree+ecx*sizeof.xfs_da_node_entry+xfs_da_node_entry.before]
@@:
jmp .quit
.error:
test esp, esp
ret
.quit:
cmp esp, esp
ret
endp
 
 
proc xfs._.long_btree.seek uses ebx esi edi, _ptr, _size
mov ebx, [_ptr]
mov esi, [_size]
sub esi, sizeof.xfs_bmdr_block
shr esi, 4
shl esi, 3
movzx eax, [ebx+xfs_bmdr_block.bb_level]
movzx ecx, [ebx+xfs_bmdr_block.bb_numrecs]
xchg cl, ch
add ebx, sizeof.xfs_bmdr_block
jmp .common
.not_root:
mov esi, [ebp+XFS.blocksize]
sub esi, sizeof.xfs_bmbt_block
shr esi, 4
shl esi, 3
movzx eax, [ebx+xfs_bmbt_block.bb_level]
movzx ecx, [ebx+xfs_bmbt_block.bb_numrecs]
xchg cl, ch
add ebx, sizeof.xfs_bmbt_block
.common:
test eax, eax
jz .leaf
.node:
.next_rec:
dec ecx
js .error
movbe eax, [ebx+ecx*sizeof.xfs_bmbt_key+xfs_bmbt_key.br_startoff.lo]
cmp [ebp+XFS.offset_begin.hi], eax
ja .node_found
jb .next_rec
movbe eax, [ebx+ecx*sizeof.xfs_bmbt_key+xfs_bmbt_key.br_startoff.hi]
cmp [ebp+XFS.offset_begin.lo], eax
jae .node_found
jmp .next_rec
.node_found:
add ebx, esi
movbe edx, [ebx+ecx*sizeof.xfs_bmbt_ptr+xfs_bmbt_ptr.lo]
movbe eax, [ebx+ecx*sizeof.xfs_bmbt_ptr+xfs_bmbt_ptr.hi]
mov ebx, [ebp+XFS.cur_block]
stdcall xfs._.read_block
test eax, eax
jnz .error
mov ebx, [ebp+XFS.cur_block]
jmp .not_root
.leaf:
jmp .quit
.error:
.quit:
ret
endp
 
 
proc xfs._.walk_btree uses ebx esi edi, _ptr, _size, _callback_extent, _callback_block, _callback_data, _is_root
stdcall xfs._.long_btree.seek, [_ptr+4], [_size]
mov [_is_root], 0
.begin:
mov ebx, [ebp+XFS.cur_block]
mov eax, [ebp+XFS.bmap_magic]
cmp [ebx+xfs_bmbt_block.bb_magic], eax
movi eax, ERROR_FS_FAIL
jnz .error
movzx ecx, [ebx+xfs_bmbt_block.bb_numrecs]
xchg cl, ch
add ebx, [ebp+XFS.bmbt_block_size]
stdcall xfs._.walk_extent_list, ecx, ebx, [_callback_extent+8], [_callback_block+4], [_callback_data]
jnz .error
mov esi, [ebp+XFS.offset_begin.lo]
mov edi, [ebp+XFS.offset_begin.hi]
cmp edi, [ebp+XFS.offset_end.hi]
ja .quit
cmp esi, [ebp+XFS.offset_end.lo]
jae .quit
sub ebx, [ebp+XFS.bmbt_block_size]
movbe edx, [ebx+xfs_bmbt_block.bb_rightsib.lo]
movbe eax, [ebx+xfs_bmbt_block.bb_rightsib.hi]
mov ecx, eax
and ecx, edx
inc ecx
jz .quit
mov ebx, [ebp+XFS.cur_block]
stdcall xfs._.read_block
jnz .error
jmp .begin
.error:
.quit:
ret
endp
 
 
proc xfs._.btree_read_block uses ebx esi edi, _tree, _size, _block_lo, _block_hi, _buf
mov eax, [_block_lo]
mov [ebp+XFS.offset_begin.lo], eax
mov eax, [_block_hi]
mov [ebp+XFS.offset_begin.hi], eax
stdcall xfs._.long_btree.seek, [_tree+4], [_size]
jnz .error
mov ebx, [ebp+XFS.cur_block]
mov eax, [ebp+XFS.bmap_magic]
cmp [ebx+xfs_bmbt_block.bb_magic], eax
jnz .error
movzx ecx, [ebx+xfs_bmbt_block.bb_numrecs]
xchg cl, ch
add ebx, [ebp+XFS.bmbt_block_size]
mov eax, [_block_lo]
mov [ebp+XFS.offset_begin.lo], eax
mov eax, [_block_hi]
mov [ebp+XFS.offset_begin.hi], eax
stdcall xfs._.extent_list.seek, ecx
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], [_buf]
.error:
.quit:
ret
endp
 
 
proc xfs._.extent_list.seek uses esi, _count
sub ebx, sizeof.xfs_bmbt_rec
inc [_count]
.find_low:
add ebx, sizeof.xfs_bmbt_rec
dec [_count]
jz .quit
stdcall xfs._.extent_unpack, ebx
mov eax, [ebp+XFS.extent.br_startoff.lo]
mov edx, [ebp+XFS.extent.br_startoff.hi]
mov esi, [ebp+XFS.extent.br_blockcount]
add eax, esi
adc edx, 0
 
cmp edx, [ebp+XFS.offset_begin.hi]
ja .low_found
jb .find_low
cmp eax, [ebp+XFS.offset_begin.lo]
ja .low_found
jmp .find_low
.low_found:
add ebx, sizeof.xfs_bmbt_rec
 
mov eax, [ebp+XFS.offset_begin.lo]
mov edx, [ebp+XFS.offset_begin.hi]
mov esi, eax
sub esi, [ebp+XFS.extent.br_startoff.lo]
jbe .quit
; same br_blockcount for block and dirblock?
mov [ebp+XFS.extent.br_startoff.lo], eax
mov [ebp+XFS.extent.br_startoff.hi], edx
sub [ebp+XFS.extent.br_blockcount], esi
add [ebp+XFS.extent.br_startblock.lo], esi
adc [ebp+XFS.extent.br_startblock.hi], 0
jmp .quit
.quit:
mov eax, [_count]
ret
endp
 
 
proc xfs._.extent_iterate_dirblocks _callback, _callback_data
.check_high:
cmp edi, [ebp+XFS.offset_end.hi]
ja .quit
jb .read_dirblock
cmp esi, [ebp+XFS.offset_end.lo]
jae .quit
.read_dirblock:
stdcall xfs._.read_dirblock, [ebp+XFS.extent.br_startblock.lo], [ebp+XFS.extent.br_startblock.hi], [ebp+XFS.cur_dirblock]
mov edx, [ebp+XFS.cur_dirblock]
mov eax, [_callback]
stdcall eax, edx, esi, edi, [_callback_data]
test eax, eax
jnz .error
mov eax, [ebp+XFS.blkpdirblk]
add esi, eax
adc edi, 0
add [ebp+XFS.extent.br_startblock.lo], eax
adc [ebp+XFS.extent.br_startblock.hi], 0
sub [ebp+XFS.extent.br_blockcount], eax
jnz .check_high
.error:
.quit:
ret
endp
 
 
proc xfs._.walk_extent_list uses ebx esi edi, _count, _ptr, _callback_extent, _callback_block, _callback_data
mov ebx, [_ptr]
stdcall xfs._.extent_list.seek, [_count]
mov [_count], eax
dec [_count]
js .quit
jmp .next_extent.decoded
.next_extent:
stdcall xfs._.extent_unpack, ebx
add ebx, sizeof.xfs_bmbt_rec
.next_extent.decoded:
mov eax, [ebp+XFS.extent.br_blockcount]
add [ebp+XFS.offset_begin.lo], eax
adc [ebp+XFS.offset_begin.hi], 0
mov esi, [ebp+XFS.extent.br_startoff.lo]
mov edi, [ebp+XFS.extent.br_startoff.hi]
stdcall [_callback_extent+8], [_callback_block+4], [_callback_data]
jnz .error
cmp edi, [ebp+XFS.offset_end.hi]
ja .quit
jb @f
cmp esi, [ebp+XFS.offset_end.lo]
jae .quit
@@:
dec [_count]
js .quit
jmp .next_extent
.quit:
movi eax, ERROR_SUCCESS
.error:
test eax, eax
ret
endp
 
 
proc xfs._.get_last_dirblock uses ecx
movbe eax, [ebx+xfs_inode.di_core.di_nextents]
assert (sizeof.xfs_bmbt_rec AND (sizeof.xfs_bmbt_rec - 1)) = 0
shl eax, BSF sizeof.xfs_bmbt_rec
add eax, [ebp+XFS.inode_core_size]
lea eax, [ebx+eax-sizeof.xfs_bmbt_rec]
stdcall xfs._.extent_unpack, eax
xor edx, edx
mov eax, [ebp+XFS.extent.br_blockcount]
mov ecx, [ebp+XFS.dirblklog]
shr eax, cl
dec eax
add eax, [ebp+XFS.extent.br_startoff.lo]
adc edx, [ebp+XFS.extent.br_startoff.hi]
ret
endp
 
 
restore prologue@proc,epilogue@proc
restore movbe
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/fs/xfs.inc
0,0 → 1,622
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2013-2020. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; file types from stat.h
S_IFMT = 0170000o ; These bits determine file type
S_IFDIR = 0040000o ; Directory
S_IFCHR = 0020000o ; Character device
S_IFBLK = 0060000o ; Block device
S_IFREG = 0100000o ; Regular file
S_IFIFO = 0010000o ; FIFO
S_IFLNK = 0120000o ; Symbolic link
S_IFSOCK = 0140000o ; Socket
 
; XFS null constant: empty fields must be all ones, not zeros!
XFS_NULL = -1
 
XFS_SECT_SB = 0
 
; signatures of file system structures
XFS_AGF_MAGIC = 'XAGF'
XFS_DINODE_MAGIC = 'IN'
XFS_BMAP_MAGIC = 'BMAP'
XFS_DA_NODE_MAGIC = 0xbefe
XFS_DIR2_LEAF1_MAGIC = 0xf1d2
XFS_DIR2_LEAFN_MAGIC = 0xffd2
XFS_DIR2_BLOCK_MAGIC = 'XD2B'
XFS_DIR2_DATA_MAGIC = 'XD2D'
 
XFS_BMAP3_MAGIC = 'BMA3'
XFS_DA3_NODE_MAGIC = 0xbe3e ; non-leaf blocks
XFS_DIR3_LEAF1_MAGIC = 0xf13d ; v3 dir single blks
XFS_DIR3_LEAFN_MAGIC = 0xff3d ; v3 dir multi blks
XFS_DIR3_BLOCK_MAGIC = 'XDB3' ; single block dirs
XFS_DIR3_DATA_MAGIC = 'XDD3' ; multiblock dirs
 
XFS_SB_MAGIC = 'XFSB'
XFS_SB_VERSION_NUMBITS = 0x000f
XFS_SB_VERSION_ALLFBITS = 0xfff0
XFS_SB_VERSION_REALFBITS = 0x0ff0
XFS_SB_VERSION_ATTRBIT = 0x0010
XFS_SB_VERSION_NLINKBIT = 0x0020
XFS_SB_VERSION_QUOTABIT = 0x0040
XFS_SB_VERSION_ALIGNBIT = 0x0080
XFS_SB_VERSION_DALIGNBIT = 0x0100
XFS_SB_VERSION_SHAREDBIT = 0x0200
XFS_SB_VERSION_LOGV2BIT = 0x0400
XFS_SB_VERSION_SECTORBIT = 0x0800
XFS_SB_VERSION_EXTFLGBIT = 0x1000
XFS_SB_VERSION_DIRV2BIT = 0x2000
XFS_SB_VERSION_BORGBIT = 0x4000 ; ASCII only case-insensitive
XFS_SB_VERSION_MOREBITSBIT = 0x8000
 
XFS_SB_VERSION_SUPPORTED = XFS_SB_VERSION_NUMBITS OR \
XFS_SB_VERSION_ATTRBIT OR \
XFS_SB_VERSION_NLINKBIT OR \
XFS_SB_VERSION_QUOTABIT OR \
XFS_SB_VERSION_ALIGNBIT OR \
XFS_SB_VERSION_LOGV2BIT OR \
XFS_SB_VERSION_SECTORBIT OR \
XFS_SB_VERSION_EXTFLGBIT OR \
XFS_SB_VERSION_DIRV2BIT OR \
XFS_SB_VERSION_MOREBITSBIT
 
XFS_SB_VERSION2_RESERVED1BIT = 0x00000001
XFS_SB_VERSION2_LAZYSBCOUNTBIT = 0x00000002 ; Superblk counters
XFS_SB_VERSION2_RESERVED4BIT = 0x00000004
XFS_SB_VERSION2_ATTR2BIT = 0x00000008 ; Inline attr rework
XFS_SB_VERSION2_PARENTBIT = 0x00000010 ; parent pointers in xattr
XFS_SB_VERSION2_PROJID32BIT = 0x00000080 ; 32 bit project id
XFS_SB_VERSION2_CRCBIT = 0x00000100 ; metadata CRCs
XFS_SB_VERSION2_FTYPE = 0x00000200 ; inode type in dir
 
XFS_SB_VERSION2_SUPPORTED = XFS_SB_VERSION2_LAZYSBCOUNTBIT OR \
XFS_SB_VERSION2_ATTR2BIT OR \
XFS_SB_VERSION2_PARENTBIT OR \
XFS_SB_VERSION2_PROJID32BIT OR \
XFS_SB_VERSION2_CRCBIT OR \
XFS_SB_VERSION2_FTYPE
 
XFS_SB_FEAT_INCOMPAT_FTYPE = 1 ; filetype in dirent
XFS_SB_FEAT_INCOMPAT_SPINODES = 2 ; sparse inode chunks
XFS_SB_FEAT_INCOMPAT_META_UUID = 4 ; metadata UUID
XFS_SB_FEAT_INCOMPAT_SUPPORTED = XFS_SB_FEAT_INCOMPAT_FTYPE OR \
XFS_SB_FEAT_INCOMPAT_SPINODES OR \
XFS_SB_FEAT_INCOMPAT_META_UUID
 
; bitfield lengths for packed extent
; MSB to LSB / left to right
BMBT_EXNTFLAG_BITLEN = 1
BMBT_STARTOFF_BITLEN = 54
BMBT_STARTBLOCK_BITLEN = 52
BMBT_BLOCKCOUNT_BITLEN = 21
 
XFS_DIR2_DATA_ALIGN_LOG = 3
XFS_DIR2_DATA_ALIGN = 1 SHL XFS_DIR2_DATA_ALIGN_LOG
XFS_DIR2_SPACE_SIZE = (1 SHL (32 + XFS_DIR2_DATA_ALIGN_LOG))
XFS_DIR2_DATA_OFFSET = 0*XFS_DIR2_SPACE_SIZE
XFS_DIR2_LEAF_OFFSET = 1*XFS_DIR2_SPACE_SIZE
XFS_DIR2_FREE_OFFSET = 2*XFS_DIR2_SPACE_SIZE
 
; data section magic constants for directories (xfs_dir2_data.h)
XFS_DIR2_DATA_FD_COUNT = 3
 
; valid inode formats
; enum xfs_dinode_fmt (xfs_dinode.h)
XFS_DINODE_FMT_DEV = 0
XFS_DINODE_FMT_LOCAL = 1
XFS_DINODE_FMT_EXTENTS = 2
XFS_DINODE_FMT_BTREE = 3
XFS_DINODE_FMT_UUID = 4
 
; size of the unlinked inode hash table in the agi
XFS_AGI_UNLINKED_BUCKETS = 64
 
; possible extent states
; enum xfs_exntst_t (xfs_bmap_btree.h)
XFS_EXT_NORM = 0
XFS_EXT_UNWRITTEN = 1
XFS_EXT_DMAPI_OFFLINE = 2
XFS_EXT_INVALID = 3
 
; values for inode core flags / di_flags (xfs_dinode.h)
XFS_DIFLAG_REALTIME_BIT = 0 ; file's blocks come from rt area
XFS_DIFLAG_PREALLOC_BIT = 1 ; file space has been preallocated
XFS_DIFLAG_NEWRTBM_BIT = 2 ; for rtbitmap inode, new format
XFS_DIFLAG_NODUMP_BIT = 7 ; do not dump
XFS_DIFLAG_REALTIME = (1 SHL XFS_DIFLAG_REALTIME_BIT)
XFS_DIFLAG_PREALLOC = (1 SHL XFS_DIFLAG_PREALLOC_BIT)
XFS_DIFLAG_NEWRTBM = (1 SHL XFS_DIFLAG_NEWRTBM_BIT)
XFS_DIFLAG_NODUMP = (1 SHL XFS_DIFLAG_NODUMP_BIT)
 
; superblock _ondisk_ structure (xfs_sb.h)
; this is _not_ the partition structure
; for XFS partition structure see XFS below
struct xfs_sb
sb_magicnum dd ? ; signature, must be XFS_SB_MAGIC
sb_blocksize dd ? ; block is the minimal file system unit, in bytes
sb_dblocks DQ ? ; number of data blocks
sb_rblocks DQ ? ; number of realtime blocks
sb_rextents DQ ? ; number of realtime extents
sb_uuid rb 16 ; file system unique identifier
sb_logstart DQ ? ; starting block of log (for internal journal)
sb_rootino DQ ? ; root inode number
sb_rbmino DQ ? ; bitmap inode for realtime extents
sb_rsumino DQ ? ; summary inode for rt bitmap
sb_rextsize dd ? ; realtime extent size, blocks
sb_agblocks dd ? ; size of an allocation group (the last one may be smaller!)
sb_agcount dd ? ; number of allocation groups
sb_rbmblocks dd ? ; number of rt bitmap blocks
sb_logblocks dd ? ; number of log blocks
sb_versionnum dw ? ; header version
sb_sectsize dw ? ; volume sector size in bytes
sb_inodesize dw ? ; inode size, bytes
sb_inopblock dw ? ; inodes per block
sb_fname rb 12 ; inodes per block (aka label)
sb_blocklog db ? ; log2 of sb_blocksize
sb_sectlog db ? ; log2 of sb_blocksize
sb_inodelog db ? ; log2 of sb_inodesize
sb_inopblog db ? ; log2 of sb_inopblock
sb_agblklog db ? ; log2 of sb_agblocks (rounded up!)
sb_rextslog db ? ; log2 of sb_rextents
sb_inprogress db ? ; mkfs is in progress, don't mount
sb_imax_pct db ? ; max % of fs for inode space
; statistics
sb_icount DQ ? ; allocated inodes
sb_ifree DQ ? ; free inodes
sb_fdblocks DQ ? ; free data blocks
sb_frextents DQ ? ; free realtime extents
 
sb_uquotino DQ ? ; user quota inode
sb_gquotino DQ ? ; group quota inode
sb_qflags dw ? ; quota flags
sb_flags db ? ; misc. flags
sb_shared_vn db ? ; shared version number
sb_inoalignmt dd ? ; inode chunk alignment, fsblocks
sb_unit dd ? ; stripe or raid unit
sb_width dd ? ; stripe or raid width
sb_dirblklog db ? ; log2 of dir block size (fsbs)
sb_logsectlog db ? ; log2 of the log sector size
sb_logsectsize dw ? ; sector size for the log, bytes
sb_logsunit dd ? ; stripe unit size for the log
sb_features2 dd ? ; additional feature bits
sb_bad_features2 dd ?
sb_features_compat dd ?
sb_features_ro_compat dd ?
sb_features_incompat dd ?
sb_features_log_incompat dd ?
sb_crc dd ? ; superblock crc
sb_spino_align dd ? ; sparse inode chunk alignment
sb_pquotino DQ ? ; project quota inode
sb_lsn DQ ? ; last write sequence
sb_meta_uuid rb 16 ; metadata file system unique id
ends
 
; structure to store create, access and modification time in inode core
struct xfs_timestamp
t_sec dd ?
t_nsec dd ? ; nanoseconds
ends
 
; inode core structure: basic information about file
struct xfs_dinode_core
di_magic dw ? ; inode magic = XFS_DINODE_MAGIC
di_mode dw ? ; mode and type of file
di_version db ? ; inode version
di_format db ? ; format of di_c data
di_onlink dw ? ; old number of links to file
di_uid dd ? ; owner's user id
di_gid dd ? ; owner's group id
di_nlink dd ? ; number of links to file
di_projid dw ? ; owner's project id
di_pad rb 8 ; unused, zeroed space
di_flushiter dw ? ; incremented on flush
di_atime xfs_timestamp ; time last accessed
di_mtime xfs_timestamp ; time last modified
di_ctime xfs_timestamp ; time created/inode modified
di_size DQ ? ; number of bytes in file
di_nblocks DQ ? ; number of direct & btree blocks used
di_extsize dd ? ; basic/minimum extent size for file
di_nextents dd ? ; number of extents in data fork
di_anextents dw ? ; number of extents in attribute fork
di_forkoff db ? ; attr fork offs, <<3 for 64b align
di_aformat db ? ; format of attr fork's data
di_dmevmask dd ? ; DMIG event mask
di_dmstate dw ? ; DMIG state info
di_flags dw ? ; random flags, XFS_DIFLAG_...
di_gen dd ? ; generation number
di_next_unlinked dd ? ; unlinked but still used inode (if any, XFS_NULL otherwise)
ends
 
struct xfs_dinode3_core xfs_dinode_core
di_crc dd ? ; CRC of the inode
di_changecount DQ ? ; number of attribute changes
di_lsn DQ ? ; flush sequence
di_flags2 DQ ? ; more random flags
di_cowextsize dd ? ; basic cow extent size for file
di_pad2 rb 12 ; more padding for future expansion
 
; fields only written to during inode creation
di_crtime xfs_timestamp ; time created
di_ino DQ ? ; inode number
di_uuid rb 16 ; UUID of the filesystem
ends
 
 
struct xfs_dir2_sf_hdr
count db ?
i8count db ?
parent DQ ? ; parent inode number, 4 or 8 bytes
ends
 
struct xfs_dir2_sf_entry
namelen db ? ; actual name length (ASCII)
offset rb 2 ; saved offset
name db ? ; name, variable size
inumber DQ ? ; 4 or 8 bytes
ends
 
struct xfs_dir2_sf
hdr xfs_dir2_sf_hdr
entries xfs_dir2_sf_entry
ends
 
; active entry in a data block
; aligned to 8 bytes
; tag appears as the last 2 bytes
struct xfs_dir2_data_entry
inumber DQ ?
namelen db ?
name db ? ; name bytes array without terminator
; tag dw ? ; starting offset of the entry
ends
 
; unused entry in a data block
struct xfs_dir2_data_unused
freetag dw ? ; XFS_DIR2_DATA_FREE_TAG aka XFS_NULL
length dw ? ; total free length
; tag dw ? ; starting offset of the entry
ends
 
; generic data entry
struct xfs_dir2_data_union
union
xentry xfs_dir2_data_entry
unused xfs_dir2_data_unused
ends
ends
 
; describe a free area in the data block
; the freespace will be formatted as a xfs_dir2_data_unused_t
struct xfs_dir2_data_free
offset dw ? ; start of freespace
length dw ? ; length of freespace
ends
 
; header for the data blocks
; always at the beginning of a directory-sized block
; the code knows that XFS_DIR2_DATA_FD_COUNT is 3
struct xfs_dir2_data_hdr
magic dd ? ; XFS_DIR2_DATA_MAGIC or XFS_DIR2_BLOCK_MAGIC
bestfree xfs_dir2_data_free
bestfree2 xfs_dir2_data_free
bestfree3 xfs_dir2_data_free
ends
 
struct xfs_dir3_data_hdr xfs_dir2_data_hdr
magic3 dd ?
crc dd ?
blkno DQ ?
lsn DQ ?
uuid rb 16
owner DQ ?
ends
 
; leaf block entry
struct xfs_dir2_leaf_entry
hashval dd ? ; hash value of name
address dd ? ; address of data entry
ends
 
; the tail of directory block
struct xfs_dir2_block_tail
count dd ? ; count of leaf entries
stale dd ? ; count of stale leaf entries
ends
 
; generic single-block structure, for xfs_db
struct xfs_dir2_block
hdr xfs_dir2_data_hdr ; magic XFS_DIR2_DATA_MAGIC
u xfs_dir2_data_union
; leaf xfs_dir2_leaf_entry
; tail xfs_dir2_block_tail
ends
 
struct xfs_da_blkinfo
forw dd ? ; previous block in list
back dd ? ; following block in list
magic dw ? ; validity check on block
pad dw ? ; unused
ends
 
struct xfs_dir2_leaf_hdr
info xfs_da_blkinfo
count dw ?
stale dw ?
ends
 
struct xfs_da3_blkinfo xfs_da_blkinfo
crc dd ? ; CRC of block
blkno DQ ? ; first block of the buffer
lsn DQ ? ; sequence number of last write
uuid rb 16 ; filesystem we belong to
owner DQ ? ; inode that owns the block
ends
 
struct xfs_dir3_leaf_hdr
info xfs_da3_blkinfo
count dw ?
stale dw ?
pad dd ?
ends
 
; bests and tail are at the end of the block for single-leaf only
; (magic = XFS_DIR2_LEAF1_MAGIC not XFS_DIR2_LEAFN_MAGIC)
struct xfs_dir2_leaf
hdr xfs_dir2_leaf_hdr
ents xfs_dir2_leaf_entry
; bests dw ?
; tail xfs_dir2_leaf_tail
ends
 
struct xfs_dir3_leaf
hdr xfs_dir3_leaf_hdr
ents xfs_dir2_leaf_entry
; bests
; tail
ends
 
struct xfs_dir2_free_hdr
magic dd ? ; XFS_DIR2_FREE_MAGIC
firstdb dd ? ; db of first entry
nvalid dd ? ; count of valid entries
nused dd ? ; count of used entries
ends
 
struct xfs_da_node_hdr
info xfs_da_blkinfo
count dw ?
level dw ?
ends
 
struct xfs_da_node_entry
hashval dd ? ; hash value for this descendant
before dd ? ; Btree block before this key
ends
 
struct xfs_da_intnode
hdr xfs_da_node_hdr
btree xfs_da_node_entry
ends
 
struct xfs_da3_node_hdr
info xfs_da3_blkinfo
count dw ?
level dw ?
pad dd ?
ends
 
struct xfs_da3_intnode
hdr xfs_da3_node_hdr
btree xfs_da_node_entry
ends
 
; packet extent
struct xfs_bmbt_rec
l0 DQ ?
l1 DQ ?
ends
 
; unpacked extent
struct xfs_bmbt_irec
br_startoff DQ ?
br_startblock DQ ?
br_blockcount dd ?
br_state dd ?
ends
 
struct xfs_dir2_bmx
bmx xfs_bmbt_rec
ends
 
; bmap root header
struct xfs_bmdr_block
bb_level dw ? ; 0 is a leaf
bb_numrecs dw ? ; current number of data records
ends
 
; key structure for non-leaf levels of the tree
struct xfs_bmbt_key
br_startoff DQ ? ; starting file offset
ends
 
struct xfs_bmdr_ptr DQ
ends
 
struct xfs_bmbt_ptr DQ
ends
 
; long form header: bmap btrees
; xfs_btree_lblock is xfs_bmbt_block (xfs_btree.h)
struct xfs_bmbt_block
bb_magic dd ? ; magic number for block type
bb_level dw ? ; 0 is a leaf
bb_numrecs dw ? ; current number of data records
bb_leftsib DQ ? ; left sibling block or NULLDFSBNO
bb_rightsib DQ ? ; right sibling block or NULLDFSBNO
ends
 
struct xfs_bmbt3_block xfs_bmbt_block
bb_blkno DQ ?
bb_lsn DQ ?
bb_uuid rb 16
bb_owner DQ ?
bb_crc dd ?
bb_pad dd ?
ends
 
struct xfs_inode
di_core xfs_dinode_core ; main info, aka core
union
di_u db ? ; data fork inode part
dir2_sf xfs_dir2_sf
bmx xfs_dir2_bmx
ends
; di_a db ? ; data attribute
ends
 
struct xfs_agf
agf_magicnum dd ? ; magic number == XFS_AGF_MAGIC
agf_versionnum dd ? ; header version == XFS_AGF_VERSION
agf_seqno dd ? ; sequence # starting from 0
agf_length dd ? ; size in blocks of AG
agf_roots dd ?
agf_levels dd ?
agf_flfirst dd ?
agf_fllast dd ?
agf_flcount dd ?
agf_freeblks dd ? ; free blocks in AG
ends
 
; internal data for every XFS partition
; this _is_ XFS partition structure
; most fields are unpacked or bswap'ed values of the superblock, see xfs_sb structure above
struct XFS PARTITION
Lock MUTEX ? ; access mutex
sectsize dd ?
blocksize dd ?
dirblocksize dd ?
inodesize dd ?
rootino DQ ?
versionnum dd ?
version dd ?
features2 dd ?
inopblock dd ?
blkpdirblk dd ?
blocklog dd ?
sectlog dd ?
inodelog dd ?
inopblog dd ?
agblklog dd ?
sectpblog dd ?
dirblklog dd ? ; in fsblocks
sectpblock dd ?
agblocks dd ?
dir2_leaf_offset_blocks DQ ?
dir2_free_offset_blocks DQ ?
agblockmask DQ ?
inode_core_size dd ?
features_incompat dd ?
ftype_size dd ?
dir_block_magic dd ?
dir_data_magic dd ?
dir_leaf1_magic dw ?
dir_leafn_magic dw ?
da_node_magic dw ?
bmap_magic dd ?
bmbt_block_size dd ?
dir_block_size dd ?
dir_data_size dd ?
dir_leaf1_size dd ?
dir_leafn_size dd ?
da_node_size dd ?
da_blkinfo_size dd ?
; helpers, temporary vars, etc
; should go to file descriptor and local vars?
cur_block dd ?
cur_block_data dd ?
cur_inode dd ?
cur_sect dd ?
cur_dirblock dd ?
tmp_inode dd ?
extent xfs_bmbt_irec
bytes_to_read dd ?
bytes_read dd ?
bytes_left_in_file DQ ?
file_offset DQ ?
file_buffer dd ?
entries_read dd ?
requested_cnt dd ?
dir_sf_self_done dd ?
dir_sf_parent_done dd ?
entries_left_in_dir dd ?
entries_to_skip dd ?
max_dirblockaddr dd ?
cur_inode_save dd ?
shortform_inodelen dd ?
bdfe_nameenc dd ?
bdfe_len dd ?
bdfe_process dd ?
inode_self DQ ?
bdfe_buf dd ?
eof dd ?
offset_begin DQ ?
offset_end DQ ?
ends
 
struct f70s0arg
sf dd ?
offset DQ ?
count dd ?
buf dd ?
zero db ?
path dd ?
ends
 
struct f70s1arg
sf dd ?
start_idx dd ?
encoding dd ?
count dd ?
buf dd ?
zero db ?
path dd ?
ends
 
struct f70s5arg
sf dd ?
dd ?
xflags dd ? ; name flags is already used
dd ?
buf dd ?
zero db ?
path dd ?
ends
 
struct bdfe_hdr
version dd ?
read_cnt dd ?
total_cnt dd ?
zeroed rd 5
ends
 
struct bdfe
attr dd ?
nameenc dd ?
; nameenc db ?
; reserved db 3 dup(?)
ctime dd ?
cdate dd ?
atime dd ?
adate dd ?
mtime dd ?
mdate dd ?
size DQ ?
name db ?
ends
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Revision
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/fs/fat.inc
0,0 → 1,3152
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; FAT external functions
; in:
; ebx -> parameter structure of sysfunc 70
; ebp -> FAT structure
; esi -> path string in UTF-8
; out:
; eax, ebx = return values for sysfunc 70
iglobal
align 4
fat_user_functions:
dd fat_free
dd (fat_user_functions_end - fat_user_functions - 4) / 4
dd fat_Read
dd fat_ReadFolder
dd fat_CreateFile
dd fat_Write
dd fat_SetFileEnd
dd fat_GetFileInfo
dd fat_SetFileInfo
dd 0
dd fat_Delete
dd fat_CreateFolder
dd fat_Rename
fat_user_functions_end:
endg
 
cache_max = 1919 ; max. is 1919*512+0x610000=0x6ffe00
 
PUSHAD_EAX equ [esp+28]
PUSHAD_ECX equ [esp+24]
PUSHAD_EDX equ [esp+20]
PUSHAD_EBX equ [esp+16]
PUSHAD_EBP equ [esp+8]
PUSHAD_ESI equ [esp+4]
PUSHAD_EDI equ [esp+0]
 
; Internal data for every FAT partition.
struct FAT PARTITION
fs_type db ?
fat_change db ? ; 1=fat has changed
createOption db ?
rb 1
Lock MUTEX ; currently operations with one partition
; can not be executed in parallel since the legacy code is not ready
SECTORS_PER_FAT dd ?
NUMBER_OF_FATS dd ?
SECTORS_PER_CLUSTER dd ?
BYTES_PER_SECTOR dd ? ; Note: if BPS <> 512 need lots of changes
ROOT_CLUSTER dd ? ; first rootdir cluster
FAT_START dd ? ; start of fat table
ROOT_START dd ? ; start of rootdir (only fat16)
ROOT_SECTORS dd ? ; count of rootdir sectors (only fat16)
DATA_START dd ? ; start of data area (=first cluster 2)
LAST_CLUSTER dd ? ; last availabe cluster
ADR_FSINFO dd ? ; used only by fat32
fatRESERVED dd ?
fatBAD dd ?
fatEND dd ?
fatMASK dd ?
fatStartScan dd ?
cluster_tmp dd ? ; used by analyze_directory and analyze_directory_to_write
longname_sec1 dd ? ; used by analyze_directory to save 2 previous
longname_sec2 dd ? ; directory sectors for delete long filename
fat_in_cache dd ?
; For FAT16/FAT32, this points to 512-byte buffer for the current sector of FAT.
; For FAT12, the entire FAT structure is read
; and unpacked from 12bit per cluster to word per cluster.
; Note: work with unpacked copy of FAT12 means
; additional memory and additional code for packing/unpacking.
; I'm not sure that the economy justifies the cost, but anyway,
; there is how work was done before my edits, and I'm just keeping the principle.
fat_cache_ptr dd ?
fat12_unpacked_ptr dd ?
volumeLabel rb 12
buffer rb 512
fsinfo_buffer rb 512
ends
 
uglobal
align 4
partition_count dd ? ; partitions found by set_FAT32_variables
hd_error dd ?
hd_setup dd ?
hd_wait_timeout dd ?
cache_search_start dd ? ; used by find_empty_slot
Sector512: ; label for dev_hdcd.inc
buffer:
rb 512
endg
 
; these labels are located before the main function to make
; most of jumps to these be short
fat_create_partition.free_return0:
mov eax, ebp
call free
pop ebp
fat_create_partition.return0:
xor eax, eax
ret
 
fat_create_partition:
cmp dword [esi+DISK.MediaInfo.SectorSize], 512
jnz .return0
; bootsector must have been successfully read
cmp dword [esp+4], 0
jnz .return0
; bootsector signature must be correct
cmp word [ebx+0x1fe], 0xaa55
jnz .return0
; sectors per cluster must be nonzero
cmp byte [ebx+0xd], 0
jz .return0
; bytes per sector must be 0x200
cmp word [ebx+0xb], 0x200
jnz .return0
; number of fats must be nonzero
cmp byte [ebx+0x10], 0
jz .return0
; The only reason to be invalid partition now is FAT12. Since the test for
; FAT size requires knowledge of some calculated values, which are also used
; in the normal operation, let's hope for the best and allocate data now; if
; it will prove wrong, just deallocate it.
movi eax, sizeof.FAT
call malloc
test eax, eax
jz .return0
mov ecx, dword [ebp+PARTITION.FirstSector]
mov dword [eax+FAT.FirstSector], ecx
mov ecx, dword [ebp+PARTITION.FirstSector+4]
mov dword [eax+FAT.FirstSector+4], ecx
mov ecx, dword [ebp+PARTITION.Length]
mov dword [eax+FAT.Length], ecx
mov ecx, dword [ebp+PARTITION.Length+4]
mov dword [eax+FAT.Length+4], ecx
mov ecx, [ebp+PARTITION.Disk]
mov [eax+FAT.Disk], ecx
mov [eax+FAT.FSUserFunctions], fat_user_functions
or [eax+FAT.fat_in_cache], -1
mov [eax+FAT.fat_change], 0
push ebp
mov ebp, eax
lea ecx, [ebp+FAT.Lock]
call mutex_init
movzx eax, word [ebx+0xe] ; sectors reserved
mov [ebp+FAT.FAT_START], eax
movzx eax, byte [ebx+0xd] ; sectors per cluster
mov [ebp+FAT.SECTORS_PER_CLUSTER], eax
movzx ecx, word [ebx+0xb] ; bytes per sector
mov [ebp+FAT.BYTES_PER_SECTOR], ecx
movzx eax, word [ebx+0x11] ; count of rootdir entries (=0 fat32)
shl eax, 5 ; mul 32
dec ecx
add eax, ecx ; round up if not equal count
inc ecx ; bytes per sector
xor edx, edx
div ecx
mov [ebp+FAT.ROOT_SECTORS], eax ; count of rootdir sectors
movzx eax, word [ebx+0x16] ; sectors per fat <65536
test eax, eax
jnz @f
mov eax, [ebx+0x24] ; sectors per fat
@@:
mov [ebp+FAT.SECTORS_PER_FAT], eax
movzx eax, byte [ebx+0x10] ; number of fats
mov [ebp+FAT.NUMBER_OF_FATS], eax
mul [ebp+FAT.SECTORS_PER_FAT]
test edx, edx
jnz .free_return0
add eax, [ebp+FAT.FAT_START]
jc .free_return0
mov [ebp+FAT.ROOT_START], eax ; rootdir = fat_start + fat_size * fat_count
add eax, [ebp+FAT.ROOT_SECTORS] ; rootdir sectors should be 0 on fat32
jc .free_return0
mov [ebp+FAT.DATA_START], eax ; data area = rootdir + rootdir_size
movzx eax, word [ebx+0x13] ; total sector count <65536
test eax, eax
jnz @f
mov eax, [ebx+0x20] ; total sector count
@@:
cmp dword [ebp+FAT.Length+4], 0
jnz @f
cmp eax, dword [ebp+FAT.Length]
ja .free_return0
@@:
mov dword [ebp+FAT.Length], eax
and dword [ebp+FAT.Length+4], 0
sub eax, [ebp+FAT.DATA_START] ; eax = count of data sectors
jc .free_return0
xor edx, edx
div [ebp+FAT.SECTORS_PER_CLUSTER]
inc eax
mov [ebp+FAT.LAST_CLUSTER], eax
dec eax ; cluster count
jz .free_return0
mov [ebp+FAT.fatStartScan], 2
cmp eax, 0xfff5
jb .fat16
.fat32:
pusha
lea esi, [ebx+71]
lea edi, [ebp+FAT.volumeLabel]
movsd
movsd
movsd
popa
mov eax, [ebx+0x2c] ; rootdir cluster
mov [ebp+FAT.ROOT_CLUSTER], eax
movzx eax, word [ebx+0x30]
mov [ebp+FAT.ADR_FSINFO], eax
push ebx
add ebx, 512
call fs_read32_sys
test eax, eax
jnz @f
mov eax, [ebx+0x1ec]
cmp eax, -1
jz @f
mov [ebp+FAT.fatStartScan], eax
@@:
pop ebx
mov [ebp+FAT.fatRESERVED], 0x0FFFFFF6
mov [ebp+FAT.fatBAD], 0x0FFFFFF7
mov [ebp+FAT.fatEND], 0x0FFFFFF8
mov [ebp+FAT.fatMASK], 0x0FFFFFFF
mov al, 32
.fat_not_12_finalize:
mov [ebp+FAT.fs_type], al
; For FAT16 and FAT32, allocate 512 bytes for FAT cache.
mov eax, 512
call malloc
test eax, eax
jz .free_return0
mov [ebp+FAT.fat_cache_ptr], eax
mov eax, ebp
pop ebp
ret
 
.fat16:
pusha
lea esi, [ebx+43]
lea edi, [ebp+FAT.volumeLabel]
movsd
movsd
movsd
popa
cmp eax, 0xff5
jb .fat12
and [ebp+FAT.ROOT_CLUSTER], 0
mov [ebp+FAT.fatRESERVED], 0x0000FFF6
mov [ebp+FAT.fatBAD], 0x0000FFF7
mov [ebp+FAT.fatEND], 0x0000FFF8
mov [ebp+FAT.fatMASK], 0x0000FFFF
mov al, 16
jmp .fat_not_12_finalize
 
.fat12:
and [ebp+FAT.ROOT_CLUSTER], 0
mov [ebp+FAT.fatRESERVED], 0xFF6
mov [ebp+FAT.fatBAD], 0xFF7
mov [ebp+FAT.fatEND], 0xFFF
mov [ebp+FAT.fatMASK], 0xFFF
mov al, 12
mov [ebp+FAT.fs_type], al
; For FAT12, allocate&read data for entire table:
; calculate A = ALIGN_UP(NUM_CLUSTERS, 8),
; allocate ALIGN_UP(A*3/2, 512) bytes for FAT table plus A*2 bytes for unpacked data.
mov eax, [ebp+FAT.LAST_CLUSTER]
and eax, not 7
add eax, 8
mov edx, eax
lea eax, [eax*3]
add eax, 512*2-1
shr eax, 10
shl eax, 9
lea eax, [eax+edx*2]
call malloc
test eax, eax
jz .free_return0
; Read ALIGN_UP(NUM_CLUSTERS*3/2, 512) bytes.
push ebx
mov [ebp+FAT.fat_cache_ptr], eax
mov edx, [ebp+FAT.LAST_CLUSTER]
lea edx, [(edx+1)*3 + 512*2-1]
shr edx, 10
xchg eax, ebx
xor eax, eax
.read_fat:
push eax
add eax, [ebp+FAT.FAT_START]
call fs_read32_sys
test eax, eax
pop eax
jz @f
mov eax, [ebp+FAT.fat_cache_ptr]
call free
pop ebx
jmp .free_return0
 
@@:
add ebx, 512
inc eax
cmp eax, edx
jb .read_fat
mov [ebp+FAT.fat12_unpacked_ptr], ebx
pushad
mov esi, [ebp+FAT.fat_cache_ptr]
mov edi, [ebp+FAT.fat12_unpacked_ptr]
mov edx, [ebp+FAT.LAST_CLUSTER]
and edx, not 7
lea edx, [edi+(edx+8)*2]
push edx
@@:
mov eax, dword [esi]
mov ebx, dword [esi+4]
mov ecx, dword [esi+8]
mov edx, ecx
shr edx, 4
shr dx, 4
xor ch, ch
shld ecx, ebx, 20
shr cx, 4
shld ebx, eax, 12
and ebx, 0x0fffffff
shr bx, 4
shl eax, 4
and eax, 0x0fffffff
shr ax, 4
mov dword [edi], eax
mov dword [edi+4], ebx
mov dword [edi+8], ecx
mov dword [edi+12], edx
add edi, 16
add esi, 12
cmp edi, [esp]
jnz @b
pop eax
popad
mov eax, ebp
pop ebx ebp
ret
 
fat_free:
push eax
mov eax, [eax+FAT.fat_cache_ptr]
call free
pop eax
jmp free
 
iglobal
label fat_legal_chars byte
; 0 = not allowed
; 1 = allowed only in long names
; 3 = allowed
times 32 db 0
; ! " # $ % & ' ( ) * + , - . /
db 1,3,0,3,3,3,3,3,3,3,0,1,1,3,3,0
; 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
db 3,3,3,3,3,3,3,3,3,3,0,1,0,1,0,0
; @ A B C D E F G H I J K L M N O
db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
; P Q R S T U V W X Y Z [ \ ] ^ _
db 3,3,3,3,3,3,3,3,3,3,3,1,0,1,3,3
; ` a b c d e f g h i j k l m n o
db 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3
; p q r s t u v w x y z { | } ~
db 3,3,3,3,3,3,3,3,3,3,3,3,0,3,3,0
endg
 
fat_name_is_legal:
; in: esi -> UTF-8 name
; out: CF=1 -> legal
push esi
xor eax, eax
@@:
lodsb
test al, al
js @b
test [fat_legal_chars+eax], 1
jnz @b
test al, al
jnz @f
stc
@@:
pop esi
ret
 
fat_next_short_name:
; in: edi->8+3 name
; out: name corrected, CF=1 -> error
pushad
mov ecx, 8
mov al, '~'
std
push edi
add edi, 7
repnz scasb
pop edi
cld
jz .tilde
; tilde is not found, insert "~1" at end
add edi, 6
cmp word [edi], ' '
jnz .insert_tilde
@@:
dec edi
cmp byte [edi], ' '
jz @b
inc edi
.insert_tilde:
mov word [edi], '~1'
popad
clc
ret
 
.tilde:
push edi
add edi, 7
xor ecx, ecx
@@: ; after tilde may be only digits and trailing spaces
cmp byte [edi], '~'
jz .break
cmp byte [edi], ' '
jz .space
cmp byte [edi], '9'
jnz .found
dec edi
jmp @b
 
.space:
dec edi
inc ecx
jmp @b
 
.found:
inc byte [edi]
add dword [esp], 8
jmp .zerorest
 
.break:
jecxz .noplace
inc edi
mov al, '1'
@@:
xchg al, [edi]
inc edi
cmp al, ' '
mov al, '0'
jnz @b
.succ:
pop edi
popad
clc
ret
 
.noplace:
dec edi
cmp edi, [esp]
jz .err
add dword [esp], 8
mov word [edi], '~1'
inc edi
inc edi
@@:
mov byte [edi], '0'
.zerorest:
inc edi
cmp edi, [esp]
jb @b
pop edi
popad
ret
 
.err:
pop edi
popad
stc
ret
 
fat_gen_short_name:
; in:
; esi -> UTF-8 name
; edi -> buffer (8+3=11 chars)
pushad
mov eax, ' '
push edi
stosd
stosd
stosd
pop edi
xor eax, eax
movi ebx, 8
lea ecx, [edi+8]
.loop:
lodsb
test al, al
js .space
jz .done
test [fat_legal_chars+eax], 2
jz .space
cmp al, '.'
jz .dot
dec bl
jns .store
inc bl
.space:
or bh, 1
jmp .loop
 
.store:
call cp866toUpper
stosb
jmp .loop
 
.dot:
test bh, 2
jz .firstdot
pop ebx
add ebx, edi
sub ebx, ecx
push ebx
cmp ebx, ecx
jb @f
pop ebx
push ecx
@@:
cmp edi, ecx
jbe .skip
@@:
dec edi
mov al, [edi]
dec ebx
mov [ebx], al
mov byte [edi], ' '
cmp edi, ecx
ja @b
.skip:
mov bh, 3
jmp @f
 
.firstdot:
cmp bl, 8
jz .space
push edi
or bh, 2
@@:
mov edi, ecx
mov bl, 3
jmp .loop
 
.done:
test bh, 2
jz @f
pop edi
@@:
lea edi, [ecx-8]
test bh, 1
jz @f
call fat_next_short_name
@@:
popad
ret
 
set_FAT:
; in: eax = cluster, edx = value to save
; out: edx = old value, CF=1 -> error
push eax ebx esi
cmp eax, 2
jc .ret
cmp [ebp+FAT.LAST_CLUSTER], eax
jc .ret
cmp [ebp+FAT.fs_type], 12
je .FAT12
cmp [ebp+FAT.fs_type], 16
je @f
add eax, eax
@@:
add eax, eax
mov esi, 511
and esi, eax
shr eax, 9
add eax, [ebp+FAT.FAT_START]
mov ebx, [ebp+FAT.fat_cache_ptr]
cmp eax, [ebp+FAT.fat_in_cache]
je .inCache
cmp [ebp+FAT.fat_change], 0
je @f
call write_fat_sector
@@:
mov [ebp+FAT.fat_in_cache], eax
call fs_read32_sys
test eax, eax
jne .error
.inCache:
cmp [ebp+FAT.fs_type], 16
jne .test32
xchg [ebx+esi], dx ; save new value and get old value
jmp .write
 
.test32:
mov eax, [ebp+FAT.fatMASK]
and edx, eax
xor eax, -1 ; mask for high bits
and eax, [ebx+esi] ; get high 4 bits
or eax, edx
mov edx, [ebx+esi] ; get old value
mov [ebx+esi], eax ; save new value
.write:
mov [ebp+FAT.fat_change], 1
and edx, [ebp+FAT.fatMASK]
.ret:
pop esi ebx eax
ret
 
.error:
stc
jmp .ret
 
.FAT12:
test edx, 0xF000
jnz .error
mov ebx, [ebp+FAT.fat12_unpacked_ptr]
xchg [ebx+eax*2], dx
mov [ebp+FAT.fat_change], 1
jmp .ret
 
get_FAT:
; in: eax = cluster
; out: eax = next cluster, CF=1 -> error
push ebx esi
cmp [ebp+FAT.fs_type], 12
je .FAT12
cmp [ebp+FAT.fs_type], 16
je @f
add eax, eax
@@:
add eax, eax
mov esi, 511
and esi, eax
shr eax, 9
add eax, [ebp+FAT.FAT_START]
mov ebx, [ebp+FAT.fat_cache_ptr]
cmp eax, [ebp+FAT.fat_in_cache]
je .inCache
cmp [ebp+FAT.fat_change], 0
je @f
call write_fat_sector
@@:
mov [ebp+FAT.fat_in_cache], eax
call fs_read32_sys
test eax, eax
jnz .error
.inCache:
mov eax, [ebx+esi]
and eax, [ebp+FAT.fatMASK]
.ret:
pop esi ebx
ret
 
.error:
stc
jmp .ret
 
.FAT12:
mov ebx, [ebp+FAT.fat12_unpacked_ptr]
movzx eax, word [ebx+eax*2]
jmp .ret
 
get_free_FAT:
; out: eax = number of first free cluster, CF=1 -> disk full
push ecx
mov ecx, [ebp+FAT.LAST_CLUSTER]
mov eax, [ebp+FAT.fatStartScan]
cmp [ebp+FAT.fs_type], 12
jz get_free_FAT12
dec ecx
cmp eax, 2
jb .reset
.test:
cmp eax, [ebp+FAT.LAST_CLUSTER]
jbe .inRange
.reset:
mov eax, 2
.inRange:
push eax
call get_FAT
jc @f
test eax, eax
pop eax
je .found
inc eax
dec ecx
jnz .test
.notFound:
pop ecx
stc
ret
 
@@:
pop eax
jmp .notFound
 
.found:
lea ecx, [eax+1]
mov [ebp+FAT.fatStartScan], ecx
pop ecx
clc
ret
 
get_free_FAT12:
push edx edi
mov edi, [ebp+FAT.fat12_unpacked_ptr]
cmp eax, 2
jb .reset
cmp eax, ecx
jbe @f
.reset:
mov eax, 2
@@:
mov edx, eax
lea edi, [edi+eax*2]
sub ecx, eax
inc ecx
xor eax, eax
repnz scasw
jz .found
cmp edx, 2
jz .notfound
mov edi, [ebp+FAT.fat12_unpacked_ptr]
lea ecx, [edx-2]
repnz scasw
jnz .notfound
.found:
sub edi, [ebp+FAT.fat12_unpacked_ptr]
shr edi, 1
mov [ebp+FAT.fatStartScan], edi
lea eax, [edi-1]
@@:
pop edi edx ecx
ret
 
.notfound:
stc
jmp @b
 
write_fat_sector:
push eax ebx ecx
mov [ebp+FAT.fat_change], 0
mov eax, [ebp+FAT.fat_in_cache]
cmp eax, -1
jz @f
mov ebx, [ebp+FAT.fat_cache_ptr]
mov ecx, [ebp+FAT.NUMBER_OF_FATS]
.write_next_fat:
push eax
call fs_write32_sys
pop eax
add eax, [ebp+FAT.SECTORS_PER_FAT]
dec ecx
jnz .write_next_fat
@@:
pop ecx ebx eax
ret
 
get_date_for_file:
; out in ax:
; bits 0-4 = day
; bits 5-8 = month
; bits 9-15 = count of years from 1980
mov al, 7
call fsReadCMOS
ror eax, 5
mov al, 8
call fsReadCMOS
ror eax, 4
mov al, 9
call fsReadCMOS
add ax, 20
rol eax, 9
ret
 
get_time_for_file:
; out in ax:
; bits 0-4 = second (the low bit is lost)
; bits 5-10 = minute
; bits 11-15 = hour
mov al, 0
call fsReadCMOS
ror eax, 6
mov al, 2
call fsReadCMOS
ror eax, 6
mov al, 4
call fsReadCMOS
rol eax, 11
ret
 
add_disk_free_space:
; in: ecx = cluster count (signed)
test ecx, ecx
je .ret
cmp [ebp+FAT.fs_type], 32
jne .ret
push eax ebx
mov eax, [ebp+FAT.ADR_FSINFO]
lea ebx, [ebp+FAT.fsinfo_buffer]
call fs_read32_sys
test eax, eax
jnz @f
cmp dword [ebx+0x1fc], 0xaa550000 ; check sector id
jne @f
add [ebx+0x1e8], ecx
push [ebp+FAT.fatStartScan]
pop dword [ebx+0x1ec]
mov eax, [ebp+FAT.ADR_FSINFO]
call fs_write32_sys
@@:
pop ebx eax
.ret:
ret
 
clear_cluster_chain:
; in: eax = first cluster
push eax ecx edx
xor ecx, ecx ; cluster count
@@:
cmp eax, [ebp+FAT.LAST_CLUSTER]
ja @f
cmp eax, 2
jb @f
cmp eax, [ebp+FAT.ROOT_CLUSTER]
jz @f
xor edx, edx
call set_FAT
jc .ret
inc ecx
mov eax, edx
jmp @b
 
@@:
call add_disk_free_space
clc
.ret:
pop edx ecx eax
ret
 
update_disk:
cmp [ebp+FAT.fat_change], 0
jz .noChange
cmp [ebp+FAT.fs_type], 12
jz .fat12
call write_fat_sector
.noChange:
mov esi, [ebp+PARTITION.Disk]
call disk_sync
ret
 
.fat12:
mov esi, [ebp+FAT.fat12_unpacked_ptr]
mov edi, [ebp+FAT.fat_cache_ptr]
mov edx, [ebp+FAT.LAST_CLUSTER]
and edx, not 7
lea edx, [esi+(edx+8)*2]
@@:
mov eax, dword [esi]
mov ebx, dword [esi+4]
shl ax, 4
shl eax, 4
shl bx, 4
shr ebx, 4
shrd eax, ebx, 8
shr ebx, 8
mov dword [edi], eax
mov word [edi+4], bx
add edi, 6
add esi, 8
cmp esi, edx
jb @b
mov esi, [ebp+FAT.NUMBER_OF_FATS]
mov edx, [ebp+FAT.LAST_CLUSTER]
lea edx, [(edx+1)*3 + 512*2-1]
shr edx, 10
push [ebp+FAT.FAT_START]
.write_fats:
xor eax, eax
mov ebx, [ebp+FAT.fat_cache_ptr]
.loop1:
push eax
add eax, [esp+4]
call fs_write32_sys
test eax, eax
pop eax
jnz @f
add ebx, 512
inc eax
cmp eax, edx
jb .loop1
pop eax
add eax, [ebp+FAT.SECTORS_PER_FAT]
push eax
dec esi
jnz .write_fats
@@:
pop eax
mov [ebp+FAT.fat_change], 0
jmp .noChange
 
fat_lock:
lea ecx, [ebp+FAT.Lock]
jmp mutex_lock
 
fat_unlock:
lea ecx, [ebp+FAT.Lock]
jmp mutex_unlock
 
fat_get_name:
; in: edi -> FAT entry, esi -> buffer for UTF-16 name
; out: CF=1 -> no valid entry
cmp byte [edi], 0
jz .no
cmp byte [edi], 0xE5
jz .no
cmp byte [edi+11], 0xF
jz .longname
push edi
xchg esi, edi
test byte [esi+11], 8
jnz .label
pushd ecx 8
pop ecx
@@:
lodsb
call ansi2uni_char
stosw
loop @b
mov cl, 8
@@:
cmp word [edi-2], ' '
jnz @f
sub edi, 2
loop @b
@@:
mov word [edi], '.'
add edi, 2
mov cl, 3
@@:
lodsb
call ansi2uni_char
stosw
loop @b
mov cl, 3
@@:
cmp word [edi-2], ' '
jnz @f
sub edi, 2
loop @b
sub edi, 2
@@:
and word [edi], 0 ; CF=0
pop ecx edi
ret
 
.label:
lea edi, [ebp+FAT.volumeLabel]
movsd
movsd
movsd
pop edi
.no:
stc
ret
 
.longname:
mov al, byte [edi]
and eax, 0x3F
dec eax
cmp al, 20
jae .no ; ignore invalid entries
mov word [esi+260*2], 0 ; force null-terminating for orphans
imul eax, 13*2
test byte [edi], 0x40
jz @f
mov word [esi+eax+13*2], 0
@@: ; copy name (13 chars in UTF-16)
push edi
inc edi
add esi, eax
xchg esi, edi
movsd
movsd
movsw
add esi, 3
movsd
movsd
movsd
add esi, 2
movsd
pop edi
test eax, eax
jnz .no ; if this is not first entry, more processing required
ret
 
fat_find_lfn:
; in:
; esi -> path in UTF-8
; parameters in the stack
; out:
; esi -> next name in the path
; edi -> direntry
; CF=1 -> file not found, eax = error code
lea eax, [esp+12]
call dword [eax-4]
jc .reterr
sub esp, 262*2 ; reserve place for LFN
.l1:
push esi
lea esi, [esp+4]
call fat_get_name
pop esi
jc .no
push edi esi
lea edi, [esp+8]
@@:
call utf8to16
call utf16toUpper
mov edx, eax
mov ax, [edi]
call utf16toUpper
cmp ax, dx
jnz .done
add edi, 2
test ax, ax
jnz @b
dec esi
pop eax edi
.found:
add esp, 262*2
; if this is LFN entry, advance to true entry
cmp byte [edi+11], 0xF
jnz @f
lea eax, [esp+12]
call dword[eax-8]
jc .reterr
@@:
xor eax, eax
ret
 
.done:
cmp dx, '/'
jnz @f
test ax, ax
jnz @f
mov [esp], esi
@@:
pop esi edi
jz .found
.no:
lea eax, [esp+262*2+12]
call dword[eax-8]
jnc .l1
add esp, 262*2
.reterr:
stc
ret
 
fat_time_to_bdfe:
; in: eax=FAT time
; out: eax=BDFE time
push ecx edx
mov ecx, eax
mov edx, eax
shr eax, 11
shl eax, 16 ; hours
and edx, 0x1F
add edx, edx
mov al, dl ; seconds
shr ecx, 5
and ecx, 0x3F
mov ah, cl ; minutes
pop edx ecx
ret
 
fat_date_to_bdfe:
push ecx edx
mov ecx, eax
mov edx, eax
shr eax, 9
add ax, 1980
shl eax, 16 ; year
and edx, 0x1F
mov al, dl ; day
shr ecx, 5
and ecx, 0xF
mov ah, cl ; month
pop edx ecx
ret
 
bdfe_to_fat_time:
push edx
mov edx, eax
shr eax, 16
and dh, 0x3F
shl eax, 6
or al, dh
shr dl, 1
and dl, 0x1F
shl eax, 5
or al, dl
pop edx
ret
 
bdfe_to_fat_date:
push edx
mov edx, eax
shr eax, 16
sub ax, 1980
and dh, 0xF
shl eax, 4
or al, dh
and dl, 0x1F
shl eax, 5
or al, dl
pop edx
ret
 
fat_entry_to_bdfe:
; convert FAT entry at edi to BDFE (block of data of folder entry) at esi, advance esi
mov eax, [ebp-4]
mov [esi+4], eax ; cp866/UNICODE name
fat_entry_to_bdfe2:
movzx eax, byte [edi+11]
mov [esi], eax ; attributes
movzx eax, word [edi+14]
call fat_time_to_bdfe
mov [esi+8], eax ; creation time
movzx eax, word [edi+16]
call fat_date_to_bdfe
mov [esi+12], eax ; creation date
and dword [esi+16], 0 ; last access time is not supported on FAT
movzx eax, word [edi+18]
call fat_date_to_bdfe
mov [esi+20], eax ; last access date
movzx eax, word [edi+22]
call fat_time_to_bdfe
mov [esi+24], eax ; last write time
movzx eax, word [edi+24]
call fat_date_to_bdfe
mov [esi+28], eax ; last write date
mov eax, [edi+28]
mov [esi+32], eax ; file size (low dword)
xor eax, eax
mov [esi+36], eax ; file size (high dword)
test ebp, ebp
jz .ret
add esi, 40
push edi esi
mov edi, esi
mov esi, ebp
cmp byte [ebp-4], 2
jz .utf16
cmp byte [ebp-4], 3
jz .utf8
@@:
lodsw
call uni2ansi_char
stosb
test al, al
jnz @b
pop esi edi
add esi, 264
.ret:
ret
 
.utf8:
push ecx
mov ecx, 519
call UTF16to8_string
pop ecx
jmp @f
 
.utf16:
lodsw
stosw
test eax, eax
jnz .utf16
@@:
pop esi edi
add esi, 520
ret
 
bdfe_to_fat_entry:
; convert BDFE at edx to FAT entry at edi
; destroys eax
; attributes byte
test byte [edi+11], 8 ; volume label?
jnz @f
mov al, [edx]
and al, 0x27
and byte [edi+11], 0x10
or byte [edi+11], al
@@:
mov eax, [edx+8]
call bdfe_to_fat_time
mov [edi+14], ax ; creation time
mov eax, [edx+12]
call bdfe_to_fat_date
mov [edi+16], ax ; creation date
mov eax, [edx+20]
call bdfe_to_fat_date
mov [edi+18], ax ; last access date
mov eax, [edx+24]
call bdfe_to_fat_time
mov [edi+22], ax ; last write time
mov eax, [edx+28]
call bdfe_to_fat_date
mov [edi+24], ax ; last write date
ret
 
hd_find_lfn:
; in: esi -> path string in UTF-8
; out: CF=1 - file not found, eax=error code
; else CF=0 and edi->direntry, eax=sector
push esi edi
push 0
push 0
push fat1x_root_first
push fat1x_root_next
mov eax, [ebp+FAT.ROOT_CLUSTER]
cmp [ebp+FAT.fs_type], 32
jz .fat32
.loop:
and [ebp+FAT.longname_sec1], 0
and [ebp+FAT.longname_sec2], 0
call fat_find_lfn
jc .notfound
cmp byte [esi], 0
jz .found
test byte [edi+11], 10h
jz .notfound
and dword [esp+12], 0
mov eax, [edi+20-2]
mov ax, [edi+26] ; cluster
.fat32:
mov [esp+8], eax
mov dword [esp+4], fat_notroot_first
mov dword [esp], fat_notroot_next
jmp .loop
 
.notfound:
add esp, 16
pop edi esi
stc
ret
 
.found:
lea eax, [esp+8]
cmp dword [eax], 0
jz .root
call fat_get_sector
jmp .cmn
 
.root:
mov eax, [eax+4]
add eax, [ebp+FAT.ROOT_START]
.cmn:
add esp, 20 ; CF=0
pop esi
ret
 
;----------------------------------------------------------------
fat_Read:
call fat_lock
call hd_find_lfn
jc .notFound
test byte [edi+11], 0x10 ; do not allow read directories
jnz .noaccess
cmp dword [ebx+8], 0
jnz .endOfFile
mov edx, [ebx+4] ; file offset
mov ecx, [ebx+12] ; size
mov ebx, [ebx+16] ; buffer
push ebx
push 0
test ecx, ecx
jz .done
mov eax, [edi+28]
sub eax, edx
jb .fileEnd
cmp eax, ecx
jae @f
mov ecx, eax
mov byte [esp], 6
@@:
mov eax, [edi+20-2]
mov ax, [edi+26]
; now eax=cluster, ebx=buffer for data, ecx=count, edx=position
mov edi, [ebp+FAT.SECTORS_PER_CLUSTER]
shl edi, 9
@@:
cmp eax, 2
jb .fileEnd
cmp eax, [ebp+FAT.fatRESERVED]
jae .fileEnd
sub edx, edi
jc @f
call get_FAT
jc .noaccess2
jmp @b
 
.notFound:
push eax
jmp .ret
 
.noaccess:
push ERROR_ACCESS_DENIED
jmp .ret
 
.endOfFile:
push ERROR_END_OF_FILE
.ret:
call fat_unlock
pop eax
xor ebx, ebx
ret
 
@@:
mov esi, eax
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
add edx, edi
jz .alignedCluster
mov edi, edx
shr edi, 9
add eax, edi
and edx, 511
cmp ecx, 512
jc .sectorPiece
test edx, edx
jz .alignedSector
.sectorPiece:
push eax ebx
lea ebx, [ebp+FAT.buffer]
call fs_read32_app
test eax, eax
mov eax, ebx
pop ebx
jne .noaccess3
add eax, edx
push ecx
add ecx, edx
cmp ecx, 512
jbe @f
mov ecx, 512
@@:
sub ecx, edx
call memmove
sub [esp], ecx
add ebx, ecx
pop ecx eax
xor edx, edx
inc edi
inc eax
test ecx, ecx
jz .done
.alignedSector:
shl edi, 9
add ecx, edi
mov edi, [ebp+FAT.SECTORS_PER_CLUSTER]
shl edi, 9
.alignedCluster:
cmp ecx, 512
jc .sectorPiece
mov edx, eax
mov eax, esi
@@:
sub ecx, edi
jbe .readEnd
call get_FAT
jc .noaccess4
cmp eax, 2
jb .fileEnd2
cmp eax, [ebp+FAT.fatRESERVED]
jae .fileEnd2
inc esi
cmp eax, esi
jz @b
.fragmentEnd:
xchg eax, esi
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
push ecx
mov ecx, eax
mov eax, esi
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
push eax
.readFragment:
sub ecx, edx
mov eax, edx
xor edx, edx
call fs_read64_app
shl ecx, 9
add ebx, ecx
test eax, eax
pop eax
jnz .noaccess3
pop ecx
xor edx, edx
jecxz .done
jmp .alignedCluster
 
.readEnd:
add ecx, edi
mov edi, ecx
and ecx, 511
shr edi, 9
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
add eax, edi
push ecx
push eax
mov ecx, eax
jmp .readFragment
 
.noaccess3:
pop eax
.noaccess2:
mov byte [esp], ERROR_DEVICE
.done:
call fat_unlock
pop eax edx
sub ebx, edx
ret
 
.fileEnd:
mov byte [esp], ERROR_END_OF_FILE
jmp .done
 
.noaccess4:
mov byte [esp], ERROR_DEVICE
jmp @f
 
.fileEnd2:
mov byte [esp], ERROR_END_OF_FILE
@@:
inc esi
xor ecx, ecx
jmp .fragmentEnd
 
;----------------------------------------------------------------
fat_ReadFolder:
call fat_lock
mov eax, [ebp+FAT.ROOT_CLUSTER]
cmp byte [esi], 0
jz .doit
call hd_find_lfn
jc .error
test byte [edi+11], 0x10 ; do not allow read files
jz .accessDenied
mov eax, [edi+20-2]
mov ax, [edi+26] ; eax=cluster
.doit:
sub esp, 262*2 ; reserve space for LFN
push dword [ebx+8] ; cp866/UNICODE name
mov edx, [ebx+16] ; pointer to buffer
; init header
push eax
mov edi, edx
mov ecx, 32/4
xor eax, eax
rep stosd
pop eax
mov byte [edx], 1 ; version
mov esi, edi ; esi points to BDFE
mov ecx, [ebx+12] ; number of blocks to read
mov ebx, [ebx+4] ; index of the first block
.new_cluster:
mov [ebp+FAT.cluster_tmp], eax
test eax, eax
jnz @f
cmp [ebp+FAT.fs_type], 32
jz .notfound
mov eax, [ebp+FAT.ROOT_START]
push [ebp+FAT.ROOT_SECTORS]
push ebx
jmp .new_sector
 
@@:
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
push [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
push ebx
.new_sector:
lea ebx, [ebp+FAT.buffer]
mov edi, ebx
push eax
call fs_read32_sys
test eax, eax
pop eax
jnz .notfound2
add ebx, 512
push eax
.l1:
push esi
lea esi, [esp+20]
call fat_get_name
pop esi
jc .l2
cmp byte [edi+11], 0xF
jnz .do_bdfe
add edi, 0x20
cmp edi, ebx
jb .do_bdfe
pop eax
inc eax
dec dword [esp+4]
jnz @f
mov eax, [ebp+FAT.cluster_tmp]
test eax, eax
jz .done
call get_FAT
jc .notfound2
cmp eax, 2
jb .done
cmp eax, [ebp+FAT.fatRESERVED]
jae .done
push eax
mov eax, [ebp+FAT.SECTORS_PER_CLUSTER]
mov [esp+8], eax
pop eax
mov [ebp+FAT.cluster_tmp], eax
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
@@:
lea ebx, [ebp+FAT.buffer]
mov edi, ebx
push eax
call fs_read32_sys
test eax, eax
pop eax
jnz .notfound2
add ebx, 512
push eax
.do_bdfe:
inc dword [edx+8] ; new file found
dec dword [esp+4]
jns .l2
dec ecx
js .l2
inc dword [edx+4] ; new file block copied
push ebp
lea ebp, [esp+20]
call fat_entry_to_bdfe
pop ebp
.l2:
add edi, 0x20
cmp edi, ebx
jb .l1
pop eax
inc eax
dec dword [esp+4]
jnz .new_sector
mov eax, [ebp+FAT.cluster_tmp]
test eax, eax
jz .done
call get_FAT
jc .notfound2
cmp eax, 2
jb .done
cmp eax, [ebp+FAT.fatRESERVED]
jae .done
push eax
mov eax, [ebp+FAT.SECTORS_PER_CLUSTER]
mov [esp+8], eax
pop eax
pop ebx
add esp, 4
jmp .new_cluster
 
.notfound2:
add esp, 8
.notfound:
add esp, 262*2+4
push ERROR_DEVICE
jmp @f
 
.done:
add esp, 262*2+12
pushd 0
dec ecx
js @f
mov byte [esp], ERROR_END_OF_FILE
@@:
mov ebx, [edx+4]
.ret:
call fat_unlock
pop eax
ret
 
.error:
push eax
xor ebx, ebx
jmp .ret
 
.accessDenied:
push ERROR_ACCESS_DENIED
xor ebx, ebx
jmp .ret
 
fat1x_root_next:
push ecx
lea ecx, [ebp+FAT.buffer+0x200-0x20]
cmp edi, ecx
jae fat1x_root_next_sector
add edi, 0x20
@@:
pop ecx
ret
 
fat1x_root_next_write:
push ecx
lea ecx, [ebp+FAT.buffer+0x200]
cmp edi, ecx
jc @b
call fat1x_root_end_write
fat1x_root_next_sector:
push [ebp+FAT.longname_sec2]
pop [ebp+FAT.longname_sec1]
mov ecx, [eax+4]
push ecx
add ecx, [ebp+FAT.ROOT_START]
mov [ebp+FAT.longname_sec2], ecx
pop ecx
inc ecx
mov [eax+4], ecx
cmp ecx, [ebp+FAT.ROOT_SECTORS]
jnc fat_notroot_next_err
pop ecx
fat1x_root_first:
mov eax, [eax+4]
add eax, [ebp+FAT.ROOT_START]
push ebx
lea edi, [ebp+FAT.buffer]
mov ebx, edi
call fs_read32_sys
pop ebx
test eax, eax
jz @f
movi eax, ERROR_DEVICE
stc
@@:
ret
 
fat1x_root_begin_write:
push edi eax
call fat1x_root_first
pop eax edi
ret
 
fat1x_root_end_write:
pusha
mov eax, [eax+4]
add eax, [ebp+FAT.ROOT_START]
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
popa
ret
 
fat_notroot_next:
push ecx
lea ecx, [ebp+FAT.buffer+0x200-0x20]
cmp edi, ecx
jae fat_notroot_next_sector
add edi, 0x20
@@:
pop ecx
ret
 
fat_notroot_next_write:
push ecx
lea ecx, [ebp+FAT.buffer+0x200]
cmp edi, ecx
jc @b
push eax
call fat_notroot_end_write
pop eax
fat_notroot_next_sector:
push [ebp+FAT.longname_sec2]
pop [ebp+FAT.longname_sec1]
push eax
call fat_get_sector
mov [ebp+FAT.longname_sec2], eax
pop eax
mov ecx, [eax+4]
inc ecx
cmp ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
jae fat_notroot_next_cluster
mov [eax+4], ecx
jmp @f
 
fat_notroot_next_err:
pop ecx
movi eax, ERROR_FILE_NOT_FOUND
fat1x_root_extend_dir:
stc
ret
 
fat_notroot_next_cluster:
push eax
mov eax, [eax]
call get_FAT
mov ecx, eax
pop eax
jc fat_notroot_first.deverr
cmp ecx, 2
jb fat_notroot_next_err
cmp ecx, [ebp+FAT.fatRESERVED]
jae fat_notroot_next_err
mov [eax], ecx
and dword [eax+4], 0
@@:
pop ecx
fat_notroot_first:
call fat_get_sector
push ebx
lea edi, [ebp+FAT.buffer]
mov ebx, edi
call fs_read32_sys
pop ebx
test eax, eax
jz .ret ; CF=0
push ecx
.deverr:
pop ecx
mov eax, ERROR_DEVICE
stc
.ret:
ret
 
fat_notroot_begin_write:
push eax edi
call fat_notroot_first
pop edi eax
ret
 
fat_notroot_end_write:
call fat_get_sector
push ebx
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
pop ebx
ret
 
fat_notroot_extend_dir.writeerr:
pop edx
@@:
pop eax
ret
 
fat_notroot_extend_dir:
push eax
call get_free_FAT
jc @b
push edx
mov edx, [ebp+FAT.fatEND]
call set_FAT
jc .writeerr
mov edx, eax
mov eax, [esp+4]
mov eax, [eax]
push edx
call set_FAT
pop edx
jc .writeerr
push ecx
or ecx, -1
call add_disk_free_space
mov ecx, 512/4
lea edi, [ebp+FAT.buffer]
push edi
xor eax, eax
rep stosd
pop edi
pop ecx
mov eax, [esp+4]
mov [eax], edx
and dword [eax+4], 0
pop edx
mov eax, [eax]
dec eax
dec eax
push ebx ecx
mov ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
imul eax, ecx
add eax, [ebp+FAT.DATA_START]
mov ebx, edi
@@:
push eax
call fs_write32_sys
pop eax
inc eax
loop @b
pop ecx ebx eax
clc
ret
 
fat_get_sector:
push ecx
mov ecx, [eax]
dec ecx
dec ecx
imul ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
add ecx, [ebp+FAT.DATA_START]
add ecx, [eax+4]
mov eax, ecx
pop ecx
ret
 
;----------------------------------------------------------------
fat_CreateFolder:
mov [ebp+FAT.createOption], 0
jmp @f
 
fat_CreateFile:
mov [ebp+FAT.createOption], 1
@@:
call fat_lock
mov ecx, [ebx+12]
mov edx, [ebx+16]
.rename:
pushad
xor edi, edi
push esi
@@:
lodsb
test al, al
jz @f
cmp al, '/'
jnz @b
lea edi, [esi-1]
jmp @b
 
@@:
pop esi
test edi, edi
jnz .noroot
mov edx, [ebp+FAT.ROOT_CLUSTER]
cmp [ebp+FAT.fs_type], 32
jz .pushnotroot
xor edx, edx
push edx
push fat1x_root_extend_dir
push fat1x_root_end_write
push fat1x_root_next_write
push fat1x_root_begin_write
push edx
push edx
push fat1x_root_first
push fat1x_root_next
jmp .common1
 
.retNotFound:
movi eax, ERROR_FILE_NOT_FOUND
jmp .ret1
 
.noAccess:
movi eax, ERROR_ACCESS_DENIED
.ret1:
mov [esp+28], eax
call fat_unlock
popad
xor ebx, ebx
ret
 
.full:
movi eax, ERROR_DISK_FULL
jmp .ret1
 
.noroot:
cmp byte [edi+1], 0
jz .noAccess
; check existence
mov byte [edi], 0
push edi
call hd_find_lfn
pop esi
mov byte [esi], '/'
jc .retNotFound
inc esi
test byte [edi+11], 0x10
jz .noAccess ; file
mov edx, [edi+20-2]
mov dx, [edi+26]
movi eax, ERROR_FS_FAIL
cmp edx, 2
jb .ret1
.pushnotroot:
push edx
push fat_notroot_extend_dir
push fat_notroot_end_write
push fat_notroot_next_write
push fat_notroot_begin_write
push 0
push edx
push fat_notroot_first
push fat_notroot_next
.common1:
call fat_find_lfn
jc .notfound
test byte [edi+11], 10h
jz .exists_file
; found directory
add esp, 36
call fat_unlock
popad
xor eax, eax
cmp [ebp+FAT.createOption], 0
jz @f
mov al, ERROR_ACCESS_DENIED
@@:
xor ebx, ebx
ret
 
.exists_file:
cmp [ebp+FAT.createOption], 1
jz @f
add esp, 36
jmp .noAccess
 
@@: ; delete FAT chain
push edi
xor eax, eax
mov dword [edi+28], eax ; zero size
xor ecx, ecx
mov eax, [edi+20-2]
mov ax, [edi+26]
mov word [edi+20], cx
mov word [edi+26], cx
test eax, eax
jz .done1
@@:
cmp eax, [ebp+FAT.fatRESERVED]
jae .done1
xor edx, edx
call set_FAT
mov eax, edx
jc .done1
inc ecx
jmp @b
 
.short_name_found:
pop ecx edi esi
call fat_next_short_name
jnc .test_short_name_loop
.disk_full:
add esp, 12+36
jmp .full
 
.notfound: ; generate short name
call fat_name_is_legal
jc @f
add esp, 36
jmp .retNotFound
 
@@:
sub esp, 12
mov edi, esp
call fat_gen_short_name
.test_short_name_loop:
push esi edi ecx
mov esi, edi
lea eax, [esp+12+12+8]
mov edx, [eax+24]
mov [eax], edx
and dword [eax+4], 0
call dword [eax-4]
jc .found
.test_short_name_entry:
cmp byte [edi+11], 0xF
jz .test_short_name_cont
mov ecx, 11
push esi edi
repz cmpsb
pop edi esi
jz .short_name_found
.test_short_name_cont:
lea eax, [esp+12+12+8]
call dword [eax-8]
jnc .test_short_name_entry
.found:
pop ecx edi esi
; now find space in directory
; we need to save LFN <=> LFN is not equal to short name <=> generated name contains '~'
mov al, '~'
push ecx edi
mov ecx, 8
repnz scasb
movi eax, 1 ; 1 entry
jnz .notilde
; we need ceil(strlen(esi)/13) additional entries = floor((strlen(esi)+12+13)/13) total
xor ecx, ecx
push esi
@@:
call utf8to16
inc ecx
test ax, ax
jnz @b
pop esi
mov eax, ecx
add eax, 12+13-1
mov ecx, 13
cdq
div ecx
.notilde:
push -1
push -1
push -1
; find <eax> successive entries in directory
xor ecx, ecx
push eax
lea eax, [esp+16+8+12+8]
mov edx, [eax+24]
mov [eax], edx
and dword [eax+4], 0
call dword [eax-4]
pop eax
jnc .scan_dir
.fsfrfe3:
add esp, 12+8+12+36
movi eax, ERROR_DEVICE
jmp .ret1
 
.scan_dir:
cmp byte [edi], 0
jz .free
cmp byte [edi], 0xE5
jz .free
xor ecx, ecx
.scan_cont:
push eax
lea eax, [esp+16+8+12+8]
call dword [eax-8]
mov edx, eax
pop eax
jnc .scan_dir
cmp edx, ERROR_DEVICE
jz .fsfrfe3
push eax
lea eax, [esp+16+8+12+8]
call dword [eax+20] ; extend directory
pop eax
jnc .scan_dir
add esp, 12+8+12+36
jmp .full
 
.free:
test ecx, ecx
jnz @f
mov [esp], edi
mov ecx, [esp+12+8+12+8]
mov [esp+4], ecx
mov ecx, [esp+12+8+12+12]
mov [esp+8], ecx
xor ecx, ecx
@@:
inc ecx
cmp ecx, eax
jb .scan_cont
; found!
push esi ecx
; If creating a directory, allocate one data cluster or fail immediately if this is impossible.
; This prevents from creating an invalid directory entry on a full disk.
cmp [ebp+FAT.createOption], 0
jnz .notFolder
call get_free_FAT
jnc @f
add esp, 8+12+8
jmp .disk_full
 
@@:
mov [esp+8+12+8+12+36+20], eax ; store the cluster somewhere
.notFolder: ; calculate name checksum
mov esi, [esp+8+12]
mov ecx, 11
xor eax, eax
@@:
ror al, 1
add al, [esi]
inc esi
loop @b
pop ecx esi edi
pop dword [esp+8+12+12]
pop dword [esp+8+12+12]
; edi points to first entry in free chunk
dec ecx
jz .nolfn
push esi eax
lea eax, [esp+8+8+12+8]
call dword [eax+8] ; begin write
mov al, 40h
.writelfn:
or al, cl
stosb
mov esi, [esp+4]
push ecx
dec ecx
jz @f
imul ecx, 13
.scroll:
call utf8to16
loop .scroll
@@:
mov cl, 5
call fat_read_symbols
mov ax, 0xF
stosw
mov al, [esp+4]
stosb
mov cl, 6
call fat_read_symbols
xor eax, eax
stosw
mov cl, 2
call fat_read_symbols
pop ecx
lea eax, [esp+8+8+12+8]
call dword [eax+12] ; next write
xor eax, eax
loop .writelfn
pop eax esi
.nolfn:
pop esi
add esp, 16
mov ecx, 11
rep movsb
cmp [ebp+FAT.createOption], 2
jz .copy
mov word [edi], 20h ; attributes
sub edi, 11
mov byte [edi+13], 0 ; tenths of a second at file creation time
call get_time_for_file
mov [edi+14], ax ; creation time
mov [edi+22], ax ; last write time
call get_date_for_file
mov [edi+16], ax ; creation date
mov [edi+24], ax ; last write date
mov [edi+18], ax ; last access date
mov word [edi+20], cx ; high word of cluster
mov word [edi+26], cx ; low word of cluster - to be filled
mov dword [edi+28], ecx ; file size - to be filled
cmp [ebp+FAT.createOption], 0
jnz .doit
; create directory
mov byte [edi+11], 10h ; attributes: folder
mov esi, edi
mov eax, [esp+36+20] ; extract saved cluster
mov [esp+36+20], edi ; this is needed for calculating arg of add_disk_free_space!
push ecx
mov ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
shl ecx, 9
push ecx
push edi
jmp .doit2
 
.copy:
lea esi, [esp+72+11]
mov cl, 21
rep movsb
sub edi, 32
jmp .doit
 
.done1:
pop edi
call get_time_for_file
mov [edi+22], ax
call get_date_for_file
mov [edi+24], ax
mov [edi+18], ax
or byte [edi+11], 20h ; set 'archive' attribute
.doit:
mov esi, [esp+36+20]
lea eax, [esp+8]
call dword [eax+16] ; flush directory
push ecx
mov ecx, [esp+4+36+24]
xor eax, eax
test ecx, ecx
jz .done
push ecx edi
call get_free_FAT
jc .diskfull
.doit2:
push eax
mov [edi+26], ax
shr eax, 16
mov [edi+20], ax
lea eax, [esp+16+8]
call dword [eax+16] ; flush directory
pop eax
mov edx, [ebp+FAT.fatEND]
call set_FAT
.write_cluster:
push eax
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
push [ebp+FAT.SECTORS_PER_CLUSTER]
.write_sector:
cmp [ebp+FAT.createOption], 0
jz .writedir
mov ecx, 512
cmp dword [esp+12], ecx
jb .writeshort
; we can write directly from given buffer
mov ebx, esi
add esi, ecx
jmp .writecommon
 
.writedir:
push 512
lea edi, [ebp+FAT.buffer]
mov ebx, edi
mov ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
shl ecx, 9
cmp ecx, [esp+16]
jnz .writedircont
dec dword [esp+20]
push esi
mov ecx, 32/4
rep movsd
pop esi
mov dword [edi-32], '. '
mov dword [edi-32+4], ' '
mov dword [edi-32+8], ' '
mov byte [edi-32+11], 10h
push esi
mov ecx, 32/4
rep movsd
pop esi
mov dword [edi-32], '.. '
mov dword [edi-32+4], ' '
mov dword [edi-32+8], ' '
mov byte [edi-32+11], 10h
mov ecx, [esp+20+36]
cmp ecx, [ebp+FAT.ROOT_CLUSTER]
jnz @f
xor ecx, ecx
@@:
mov word [edi-32+26], cx
shr ecx, 16
mov [edi-32+20], cx
jmp .writedircont
 
.writeshort:
mov ecx, [esp+12]
push ecx
lea edi, [ebp+FAT.buffer]
mov ebx, edi
rep movsb
.writedircont:
lea ecx, [ebp+FAT.buffer+0x200]
sub ecx, edi
push eax
xor eax, eax
rep stosb
pop eax
pop ecx
.writecommon:
push eax
call fs_write32_app
test eax, eax
pop eax
jnz .writeerr
inc eax
sub dword [esp+12], ecx
jz .writedone
dec dword [esp]
jnz .write_sector
pop eax
; allocate new cluster
pop eax
mov ecx, eax
call get_free_FAT
jc .diskfull
mov edx, [ebp+FAT.fatEND]
call set_FAT
xchg eax, ecx
mov edx, ecx
call set_FAT
xchg eax, ecx
jmp .write_cluster
 
.diskfull:
mov eax, ERROR_DISK_FULL
jmp .ret
 
.writeerr:
pop eax eax
sub esi, ecx
mov eax, ERROR_DEVICE
jmp .ret
 
.writedone:
pop eax eax
xor eax, eax
.ret:
pop edi ecx
inc ecx
.done:
sub esi, [esp+4+36+20]
mov [esp+4+36+28], eax
mov [esp+4+36+16], esi
jecxz @f
lea eax, [esp+12]
call dword [eax+8]
mov [edi+28], esi
call dword [eax+16]
@@:
lea eax, [esi+511]
shr eax, 9
mov ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
lea eax, [eax+ecx-1]
xor edx, edx
div ecx
pop ecx
sub ecx, eax
call add_disk_free_space
add esp, 36
cmp [ebp+FAT.createOption], 2
jz @f
call update_disk
call fat_unlock
@@:
popad
ret
 
@@:
or eax, -1
rep stosw
ret
 
fat_read_symbols:
test esi, esi
jz @b
call utf8to16
stosw
test ax, ax
jnz @f
xor esi, esi
@@:
loop fat_read_symbols
ret
 
;----------------------------------------------------------------
fat_Write:
call fat_lock
call hd_find_lfn
jc .error
cmp dword [ebx+8], 0
jnz .eof ; FAT does not support files larger than 4GB
mov ecx, [ebx+12]
mov edx, [ebx+16]
mov ebx, [ebx+4]
; now edi points to direntry, ebx=start byte to write,
; ecx=number of bytes to write, edx=data pointer
; extend file if needed
add ecx, ebx
jc .eof ; FAT does not support files larger than 4GB
push edx
push eax ; save directory sector
push 0 ; return value=0
call get_time_for_file
mov [edi+22], ax ; last write time
call get_date_for_file
mov [edi+24], ax ; last write date
mov [edi+18], ax ; last access date
push dword [edi+28] ; save current file size
cmp ecx, [edi+28]
jbe .length_ok
cmp ecx, ebx
jz .length_ok
call hd_extend_file
jnc .length_ok
mov [esp+4], eax
; hd_extend_file can return three error codes: FAT table error, device error or disk full.
; First two cases are fatal errors, in third case we may write some data
cmp al, ERROR_DISK_FULL
jnz @f
; correct number of bytes to write
mov ecx, [edi+28]
cmp ecx, ebx
ja .length_ok
push 0
.ret:
pop eax eax eax ecx ecx
sub edx, ecx
push eax edx
call update_disk
pop ebx
@@:
call fat_unlock
pop eax
ret
 
.error:
push eax
jmp @b
 
.eof:
push ERROR_END_OF_FILE
xor ebx, ebx
jmp @b
 
.device_err2:
pop ecx
.device_err:
mov byte [esp+8], ERROR_DEVICE
jmp .ret
 
.fat_err:
mov byte [esp+8], ERROR_FS_FAIL
jmp .ret
 
.length_ok:
mov esi, [edi+28]
mov eax, [edi+20-2]
mov ax, [edi+26]
mov edi, eax ; edi=current cluster
push 0 ; current sector in cluster
; save directory
mov eax, [esp+12]
push ebx
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
pop ebx
test eax, eax
jnz .device_err
; now ebx=start pos, ecx=end pos, both lie inside file
sub ecx, ebx
jz .ret
.write_loop:
; skip unmodified sectors
cmp dword [esp+4], 0x200
jb .modify
sub ebx, 0x200
jae .skip
add ebx, 0x200
.modify:
; get length of data in current sector
push ecx
sub ebx, 0x200
jb .hasdata
neg ebx
xor ecx, ecx
jmp @f
.hasdata:
neg ebx
cmp ecx, ebx
jbe @f
mov ecx, ebx
@@:
; get current sector number
mov eax, edi
dec eax
dec eax
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
add eax, [esp+4]
; load sector if needed
cmp dword [esp+8], 0 ; we don't need to read uninitialized data
jz .noread
cmp ecx, 0x200 ; we don't need to read sector if it is fully rewritten
jz .noread
cmp ecx, esi ; (same for the last sector)
jz .noread
push eax ebx
lea ebx, [ebp+FAT.buffer]
call fs_read32_app
test eax, eax
pop ebx eax
jnz .device_err2
.noread:
; zero uninitialized data if file was extended (because hd_extend_file does not this)
push eax ecx edi
xor eax, eax
mov ecx, 0x200
sub ecx, [esp+8+12]
jbe @f
lea edi, [ebp+FAT.buffer]
add edi, [esp+8+12]
rep stosb
@@:
; zero uninitialized data in the last sector
mov ecx, 0x200
sub ecx, esi
jbe @f
lea edi, [ebp+FAT.buffer+esi]
rep stosb
@@:
pop edi ecx
; copy new data
mov eax, edx
neg ebx
jecxz @f
lea ebx, [ebp+FAT.buffer+0x200+ebx]
call memmove
xor ebx, ebx
@@:
pop eax
; save sector
push ebx
lea ebx, [ebp+FAT.buffer]
call fs_write32_app
pop ebx
test eax, eax
jnz .device_err2
add edx, ecx
sub [esp], ecx
pop ecx
jz .ret
.skip:
; next sector
pop eax
inc eax
push eax
cmp eax, [ebp+FAT.SECTORS_PER_CLUSTER]
jb @f
and dword [esp], 0
mov eax, edi
call get_FAT
mov edi, eax
jc .device_err
cmp edi, 2
jb .fat_err
cmp edi, [ebp+FAT.fatRESERVED]
jae .fat_err
@@:
sub esi, 0x200
jae @f
xor esi, esi
@@:
sub dword [esp+4], 0x200
jae @f
and dword [esp+4], 0
@@:
jmp .write_loop
 
hd_extend_file.zero_size:
xor eax, eax
jmp hd_extend_file.start_extend
 
; extends file on hd to given size (new data area is undefined)
; in: edi->direntry, ecx=new size
; out: CF=0 => OK, eax=0
; CF=1 => error, eax=code (ERROR_FS_FAIL or ERROR_DISK_FULL or ERROR_DEVICE)
hd_extend_file:
push esi
mov esi, [ebp+FAT.SECTORS_PER_CLUSTER]
imul esi, [ebp+FAT.BYTES_PER_SECTOR]
push ecx
; find the last cluster of file
mov eax, [edi+20-2]
mov ax, [edi+26]
mov ecx, [edi+28]
jecxz .zero_size
.last_loop:
sub ecx, esi
jbe .last_found
call get_FAT
jnc @f
.device_err:
pop ecx
.device_err2:
pop esi
push ERROR_DEVICE
.ret_err:
pop eax
stc
ret
@@:
cmp eax, 2
jb .fat_err
cmp eax, [ebp+FAT.fatRESERVED]
jb .last_loop
.fat_err:
pop ecx esi
push ERROR_FS_FAIL
jmp .ret_err
.last_found:
push eax
call get_FAT
jnc @f
pop eax
jmp .device_err
@@:
cmp eax, [ebp+FAT.fatRESERVED]
pop eax
jb .fat_err
; set length to full number of clusters
sub [edi+28], ecx
.start_extend:
pop ecx
; now do extend
push edx
mov edx, 2 ; start scan from cluster 2
.extend_loop:
cmp [edi+28], ecx
jae .extend_done
; add new cluster
push eax
call get_free_FAT
jc .disk_full
mov edx, [ebp+FAT.fatEND]
call set_FAT
mov edx, eax
pop eax
test eax, eax
jz .first_cluster
push edx
call set_FAT
pop edx
jmp @f
.first_cluster:
ror edx, 16
mov [edi+20], dx
ror edx, 16
mov [edi+26], dx
@@:
push ecx
mov ecx, -1
call add_disk_free_space
pop ecx
mov eax, edx
add [edi+28], esi
jmp .extend_loop
.extend_done:
mov [edi+28], ecx
pop edx esi
xor eax, eax ; CF=0
ret
.device_err3:
pop edx
jmp .device_err2
.disk_full:
pop eax edx esi
movi eax, ERROR_DISK_FULL
stc
ret
 
;----------------------------------------------------------------
fat_SetFileEnd:
call fat_lock
call hd_find_lfn
jc .reteax
; must not be directory
test byte [edi+11], 10h
jnz .access_denied
; file size must not exceed 4 Gb
cmp dword [ebx+8], 0
jnz .endOfFile
push eax ; save directory sector
; set file modification date/time to current
call get_time_for_file
mov [edi+22], ax ; last write
call get_date_for_file
mov [edi+24], ax ; last write
mov [edi+18], ax ; last access
mov eax, [ebx+4]
cmp eax, [edi+28]
jb .truncate
ja .expand
pop eax
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
test eax, eax
jnz .errorDevice
push 0
jmp .ret
 
.access_denied:
push ERROR_ACCESS_DENIED
jmp .ret
 
.endOfFile:
push ERROR_END_OF_FILE
jmp .ret
 
.errorDevice:
push ERROR_DEVICE
jmp .ret
 
.expand:
push ebx ebp ecx
push dword [edi+28] ; save old size
mov ecx, eax
call hd_extend_file
push eax ; return code
jnc .expand_ok
cmp al, ERROR_DISK_FULL
jnz .pop_ret
.expand_ok: ; save directory
mov eax, [edi+28]
xchg eax, [esp+20]
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
test eax, eax
jnz .pop_ret11
mov eax, [esp+20]
sub eax, [esp+4]
cmp eax, 1000001h
jnc .pop_ret
mov eax, [edi+20-2]
mov ax, [edi+26]
mov edi, eax
test edi, edi
jz .pop_ret
; now zero new data
push 0
; edi=current cluster, [esp]=sector in cluster
; [esp+24]=new size, [esp+8]=old size, [esp+4]=return code
.zero_loop:
cmp edi, 2
jb .error_fat
cmp edi, [ebp+FAT.fatRESERVED]
jae .error_fat
sub dword [esp+8], 0x200
jae .next_cluster
lea eax, [edi-2]
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
add eax, [esp]
cmp dword [esp+8], -0x200
jz .noread
push eax
lea ebx, [ebp+FAT.buffer]
call fs_read32_app
test eax, eax
pop eax
jnz .err_next
.noread:
mov ecx, [esp+8]
neg ecx
push edi
lea edi, [ebp+FAT.buffer+0x200]
add edi, [esp+12]
push eax
xor eax, eax
mov [esp+16], eax
rep stosb
pop eax
pop edi
call fs_write32_app
test eax, eax
jz .next_cluster
.err_next:
mov byte [esp+4], ERROR_DEVICE
.next_cluster:
pop eax
sub dword [esp+20], 0x200
jbe .pop_ret
inc eax
push eax
cmp eax, [ebp+FAT.SECTORS_PER_CLUSTER]
jb .zero_loop
and dword [esp], 0
mov eax, edi
call get_FAT
mov edi, eax
jnc .zero_loop
pop eax
.pop_ret11:
mov byte [esp], ERROR_DEVICE
.pop_ret:
call update_disk
pop eax ecx ecx ebp ebx ecx
.reteax:
push eax
.ret:
call fat_unlock
pop eax
ret
 
.error_fat:
pop eax
mov byte [esp], ERROR_FS_FAIL
jmp .pop_ret
 
.error_fat2:
pop eax ecx eax
call update_disk
push ERROR_FS_FAIL
jmp .ret
 
.truncate:
mov [edi+28], eax
push ecx
mov ecx, [edi+20-2]
mov cx, [edi+26]
push eax
test eax, eax
jz .zero_size
@@: ; find new last cluster
cmp ecx, 2
jb .error_fat2
cmp ecx, [ebp+FAT.fatRESERVED]
jae .error_fat2
mov eax, [ebp+FAT.SECTORS_PER_CLUSTER]
shl eax, 9
sub [esp], eax
jbe @f
mov eax, ecx
call get_FAT
mov ecx, eax
jnc @b
.device_err3:
pop eax ecx eax
call update_disk
push ERROR_DEVICE
jmp .ret
 
@@:
; we will zero data at the end of last sector - remember it
push ecx
; terminate FAT chain
push edx
mov eax, ecx
mov edx, [ebp+FAT.fatEND]
call set_FAT
mov eax, edx
pop edx
jnc @f
.device_err4:
pop ecx
jmp .device_err3
 
.zero_size:
and word [edi+20], 0
and word [edi+26], 0
push 0
mov eax, ecx
@@:
; delete FAT chain
call clear_cluster_chain
jc .device_err4
; save directory
mov eax, [esp+12]
push ebx
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
pop ebx
test eax, eax
jnz .device_err4
; zero last sector, ignore errors
pop ecx
pop eax
dec ecx
imul ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
add ecx, [ebp+FAT.DATA_START]
push eax
sar eax, 9
add ecx, eax
pop eax
and eax, 0x1FF
jz .truncate_done
push ebx eax
mov eax, ecx
lea ebx, [ebp+FAT.buffer]
call fs_read32_app
pop eax
lea edi, [ebp+FAT.buffer+eax]
push ecx
mov ecx, 0x200
sub ecx, eax
xor eax, eax
rep stosb
pop eax
call fs_write32_app
pop ebx
.truncate_done:
pop ecx eax
call update_disk
call fat_unlock
xor eax, eax
ret
 
;----------------------------------------------------------------
fat_GetFileInfo:
cmp byte [esi], 0
jz .volume
call fat_lock
call hd_find_lfn
jc @f
push ebp
xor ebp, ebp
mov esi, [ebx+16]
mov dword [esi+4], ebp
call fat_entry_to_bdfe2
pop ebp
xor eax, eax
@@:
push eax
call fat_unlock
pop eax
@@:
ret
 
.volume:
mov eax, dword[ebp+FAT.Length]
mov edx, dword[ebp+FAT.Length+4]
mov edi, [ebx+16]
shld edx, eax, 9
shl eax, 9
mov [edi+36], edx
mov [edi+32], eax
mov eax, [ebx+8]
mov byte [edi], 8
mov [edi+4], eax
test eax, eax
jz @b
lea esi, [ebp+FAT.volumeLabel]
mov ecx, 11
@@:
mov byte [esi+ecx], 0
dec ecx
jz @f
cmp byte [esi+ecx], ' '
jz @b
@@:
mov cl, 12
add edi, 40
cmp eax, 2
jz @f
rep movsb
xor eax, eax
ret
 
@@:
lodsb
stosw
loop @b
ret
 
;----------------------------------------------------------------
fat_SetFileInfo:
call fat_lock
call hd_find_lfn
jc @f
push eax
mov edx, [ebx+16]
call bdfe_to_fat_entry
pop eax
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
call update_disk
xor eax, eax
@@:
push eax
call fat_unlock
pop eax
ret
 
;----------------------------------------------------------------
fat_Delete:
call fat_lock
and [ebp+FAT.longname_sec1], 0
and [ebp+FAT.longname_sec2], 0
call hd_find_lfn
jc .notFound
cmp dword [edi], '. '
jz .access_denied2
cmp dword [edi], '.. '
jz .access_denied2
test byte [edi+11], 10h
jz .dodel
; we can delete only empty folders!
pushad
mov esi, [edi+20-2]
mov si, [edi+26]
xor ecx, ecx
lea eax, [esi-2]
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
lea ebx, [ebp+FAT.buffer]
call fs_read32_sys
test eax, eax
jnz .err1
lea eax, [ebx+0x200]
add ebx, 2*0x20
.checkempty:
cmp byte [ebx], 0
jz .empty
cmp byte [ebx], 0xE5
jnz .notempty
add ebx, 0x20
cmp ebx, eax
jb .checkempty
inc ecx
cmp ecx, [ebp+FAT.SECTORS_PER_CLUSTER]
jb @f
mov eax, esi
call get_FAT
jc .err1
cmp eax, 2
jb .error_fat
cmp eax, [ebp+FAT.fatRESERVED]
jae .empty
mov esi, eax
xor ecx, ecx
@@:
lea eax, [esi-2]
imul eax, [ebp+FAT.SECTORS_PER_CLUSTER]
add eax, [ebp+FAT.DATA_START]
add eax, ecx
lea ebx, [ebp+FAT.buffer]
call fs_read32_sys
test eax, eax
lea eax, [ebx+0x200]
jz .checkempty
.err1:
popad
.err2:
push ERROR_DEVICE
.ret:
call fat_unlock
pop eax
ret
 
.notFound:
push ERROR_FILE_NOT_FOUND
jmp .ret
 
.error_fat:
popad
push ERROR_FS_FAIL
jmp .ret
 
.notempty:
popad
.access_denied2:
push ERROR_ACCESS_DENIED
jmp .ret
 
.empty:
popad
push eax ebx
lea ebx, [ebp+FAT.buffer]
call fs_read32_sys
test eax, eax
pop ebx eax
jnz .err2
.dodel:
push eax
mov eax, [edi+20-2]
mov ax, [edi+26]
xchg eax, [esp]
; delete folder entry
mov byte [edi], 0xE5
; delete LFN (if present)
.lfndel:
lea edx, [ebp+FAT.buffer]
cmp edi, edx
ja @f
cmp [ebp+FAT.longname_sec2], 0
jz .lfndone
push [ebp+FAT.longname_sec2]
push [ebp+FAT.longname_sec1]
pop [ebp+FAT.longname_sec2]
and [ebp+FAT.longname_sec1], 0
push ebx
mov ebx, edx
call fs_write32_sys
mov eax, [esp+4]
call fs_read32_sys
pop ebx
pop eax
lea edi, [ebp+FAT.buffer+0x200]
@@:
sub edi, 0x20
cmp byte [edi], 0xE5
jz .lfndone
cmp byte [edi+11], 0xF
jnz .lfndone
mov byte [edi], 0xE5
jmp .lfndel
.lfndone:
push ebx
lea ebx, [ebp+FAT.buffer]
call fs_write32_sys
pop ebx
; delete FAT chain
pop eax
call clear_cluster_chain
call update_disk
call fat_unlock
xor eax, eax
ret
 
;----------------------------------------------------------------
fat_Rename:
; in: edi -> new path string in UTF-8
push esi edi
call fat_lock
call hd_find_lfn
pop ebx
jc .error
sub esp, 32
mov esi, edi
mov edi, esp
mov ecx, 8
rep movsd
mov [ebp+FAT.createOption], 2
mov esi, ebx
call fat_CreateFile.rename
add esp, 32
pop esi
test eax, eax
jnz .ret
push eax
mov [ebp+FAT.longname_sec1], eax
mov [ebp+FAT.longname_sec2], eax
call hd_find_lfn
jc .error
mov byte [edi], 0xE5
jmp fat_Delete.lfndel
 
.error:
push eax
call fat_unlock
pop eax ebx
.ret:
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/fs/ext.inc
0,0 → 1,2708
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2013-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; EXT external functions
; in:
; ebx -> parameter structure of sysfunc 70
; ebp -> EXTFS structure
; esi -> path string in UTF-8
; out:
; eax, ebx = return values for sysfunc 70
iglobal
align 4
ext_user_functions:
dd ext_free
dd (ext_user_functions_end - ext_user_functions - 4) / 4
dd ext_ReadFile
dd ext_ReadFolder
dd ext_CreateFile
dd ext_WriteFile
dd ext_SetFileEnd
dd ext_GetFileInfo
dd ext_SetFileInfo
dd 0
dd ext_Delete
dd ext_CreateFolder
dd ext_Rename
ext_user_functions_end:
endg
 
struct DIRENTRY
inodeNumber dd ?
entryLength dw ?
nameLength db ?
fileType db ?
name db ? ; rb [nameLength]
ends
 
struct INODE
accessMode dw ?
UID dw ?
fileSize dd ?
accessedTime dd ?
inodeModified dd ?
dataModified dd ?
deletedTime dd ?
GID dw ?
linksCount dw ?
sectorsUsed dd ?
featureFlags dd ?
reserved dd ?
blockNumbers rd 12
addressBlock dd ?
doubleAddress dd ?
tripleAddress dd ?
generation dd ?
ACL dd ?
fileSizeHigh dd ?
ends
 
struct BGDESCR ; block group descriptor
blockBitmap dd ?
inodeBitmap dd ?
inodeTable dd ?
blocksFree dw ?
inodesFree dw ?
directoriesCount dw ?
reserved rb 14
ends
 
struct SUPERBLOCK
inodesTotal dd ?
blocksTotal dd ?
blocksReserved dd ?
blocksFree dd ?
inodesFree dd ?
firstGroupBlock dd ?
sectorsPerBlockLog dd ? ; shift for 1024
fragmentSizeLog dd ?
blocksPerGroup dd ?
fragmentsPerGroup dd ?
inodesPerGroup dd ?
lastMountTime dd ?
lastWriteTime dd ?
mountCount dw ?
mountMax dw ?
magic dw ?
state dw ?
errorHandling dw ?
additionalVersion dw ?
lastCheck dd ?
checkInterval dd ?
creatorOS dd ?
dynamicVersionFlag dd ?
reservedUID dw ?
reservedGID dw ?
firstInode dd ?
inodeSize dw ?
thisBlockGroup dw ?
compatibleFlags dd ?
incompatibleFlags dd ?
RO_compatibleFlags dd ?
UUID rb 16
volumeLabel rb 16
ends
 
; ext4 extent tree
struct NODEHEADER ; tree node header
magic dw ? ; 0xF30A
entriesFolow dw ?
entriesMax dw ?
currentDepth dw ?
generation dd ?
ends
 
struct INDEX ; root/branch
fileBlock dd ?
nodeBlock dd ?
nodeBlockHigh dw ?
reserved dw ?
ends
 
struct EXTENT ; leaf
fileBlock dd ?
blocksCount dw ?
fsBlockHigh dw ?
fsBlock dd ?
ends
 
ROOT_INODE = 2
EXTENTS_USED = 80000h
TYPE_MASK = 0F000h
FLAG_FILE = 8000h
DIRECTORY = 4000h
DIR_FLAG_FILE = 1
DIR_DIRECTORY = 2
KOS_HIDDEN = 2
KOS_DIRECTORY = 10h
READ_ONLY = 1
 
; Implemented "incompatible" features:
; 2 = have file type in directory entry
; 40h = extents
; 200h = flexible block groups
INCOMPATIBLE_SUPPORT = 242h
; Read only support for "incompatible" features:
INCOMPATIBLE_READ_SUPPORT = 240h
 
; Implemented "read-only" features:
; 1 = sparse superblock
; 2 = 64-bit file size
READ_ONLY_SUPPORT = 3
 
struct EXTFS PARTITION
Lock MUTEX
mountType dd ?
bytesPerBlock dd ?
sectorsPerBlock dd ?
dwordsPerBlock dd ?
dwordsPerBranch dd ? ; dwordsPerBlock ^ 2
mainBlockBuffer dd ?
tempBlockBuffer dd ?
descriptorTable dd ?
descriptorTableEnd dd ?
align0 rb 200h-EXTFS.align0
superblock SUPERBLOCK
align1 rb 400h-EXTFS.align1
rootInodeBuffer INODE
align2 rb 600h-EXTFS.align2
inodeBuffer INODE
align3 rb 800h-EXTFS.align3
ends
 
; mount if it's a valid EXT partition
ext2_create_partition:
; in:
; ebp -> PARTITION structure
; ebx -> boot sector
; ebx+512 -> buffer
; out:
; eax -> EXTFS structure, 0 = not EXT
push ebx
cmp dword [esi+DISK.MediaInfo.SectorSize], 512
jnz .fail
mov eax, 2
add ebx, 512
call fs_read32_sys
test eax, eax
jnz .fail
cmp [ebx+SUPERBLOCK.magic], 0xEF53
jne .fail
cmp [ebx+SUPERBLOCK.state], 1
ja .fail
test [ebx+SUPERBLOCK.incompatibleFlags], not INCOMPATIBLE_SUPPORT
jnz .fail
cmp [ebx+SUPERBLOCK.sectorsPerBlockLog], 6 ; 64KB
ja .fail
cmp [ebx+SUPERBLOCK.inodeSize], 512
ja .fail
cmp [ebx+SUPERBLOCK.blocksPerGroup], 0
je .fail
cmp [ebx+SUPERBLOCK.inodesPerGroup], 0
je .fail
movi eax, sizeof.EXTFS
call malloc
test eax, eax
jz .fail
mov ecx, dword [ebp+PARTITION.FirstSector]
mov dword [eax+EXTFS.FirstSector], ecx
mov ecx, dword [ebp+PARTITION.FirstSector+4]
mov dword [eax+EXTFS.FirstSector+4], ecx
mov ecx, dword [ebp+PARTITION.Length]
mov dword [eax+EXTFS.Length], ecx
mov ecx, dword [ebp+PARTITION.Length+4]
mov dword [eax+EXTFS.Length+4], ecx
mov ecx, [ebp+PARTITION.Disk]
mov [eax+EXTFS.Disk], ecx
mov [eax+EXTFS.FSUserFunctions], ext_user_functions
 
push ebp esi edi
mov ebp, eax
lea ecx, [eax+EXTFS.Lock]
call mutex_init
mov esi, ebx
lea edi, [ebp+EXTFS.superblock]
mov ecx, 512/4
rep movsd ; copy superblock
mov ecx, [ebx+SUPERBLOCK.sectorsPerBlockLog]
inc ecx
mov eax, 1
shl eax, cl
mov [ebp+EXTFS.sectorsPerBlock], eax
shl eax, 9
mov [ebp+EXTFS.bytesPerBlock], eax
shl eax, 1
push eax
shr eax, 3
mov [ebp+EXTFS.dwordsPerBlock], eax
mul eax
mov [ebp+EXTFS.dwordsPerBranch], eax
call kernel_alloc
test eax, eax
jz .error
mov [ebp+EXTFS.mainBlockBuffer], eax
add eax, [ebp+EXTFS.bytesPerBlock]
mov [ebp+EXTFS.tempBlockBuffer], eax
mov [ebp+EXTFS.mountType], 0
test [ebx+SUPERBLOCK.RO_compatibleFlags], not READ_ONLY_SUPPORT
jnz .read_only
test [ebx+SUPERBLOCK.incompatibleFlags], INCOMPATIBLE_READ_SUPPORT
jz @f
.read_only:
or [ebp+EXTFS.mountType], READ_ONLY
@@:
mov eax, [ebx+SUPERBLOCK.inodesTotal]
dec eax
xor edx, edx
div [ebx+SUPERBLOCK.inodesPerGroup]
inc eax
shl eax, 5
push eax eax
call kernel_alloc
pop ecx
test eax, eax
jz .error2
mov [ebp+EXTFS.descriptorTable], eax
mov ebx, eax
add eax, ecx
mov [ebp+EXTFS.descriptorTableEnd], eax
mov eax, [ebp+EXTFS.superblock.firstGroupBlock]
inc eax
mul [ebp+EXTFS.sectorsPerBlock]
dec ecx
shr ecx, 9
inc ecx
call fs_read64_sys
test eax, eax
jnz @f
mov al, ROOT_INODE
lea ebx, [ebp+EXTFS.rootInodeBuffer]
call readInode
test eax, eax
jnz @f
mov eax, ebp
pop edi esi ebp ebx
ret
 
@@:
stdcall kernel_free, [ebp+EXTFS.descriptorTable]
.error2:
stdcall kernel_free, [ebp+EXTFS.mainBlockBuffer]
.error:
mov eax, ebp
call free
pop edi esi ebp
.fail:
pop ebx
xor eax, eax
ret
 
; unmount EXT partition
ext_free:
; in: eax -> EXTFS structure
push eax [eax+EXTFS.mainBlockBuffer]
stdcall kernel_free, [eax+EXTFS.descriptorTable]
call kernel_free
pop eax
jmp free
 
extfsWriteBlock:
push fs_write64_sys
jmp @f
; in: eax = block number, ebx -> buffer
extfsReadBlock:
push fs_read64_sys
@@:
push ecx edx
mov ecx, [ebp+EXTFS.sectorsPerBlock]
mul ecx
call dword[esp+8]
pop edx ecx
add esp, 4
test eax, eax
jz @f
movi eax, ERROR_DEVICE
stc
@@:
ret
 
extfsWriteDescriptor:
; in: ebx = block group descriptor
mov eax, [ebp+EXTFS.superblock.firstGroupBlock]
inc eax
mul [ebp+EXTFS.sectorsPerBlock]
sub ebx, [ebp+EXTFS.descriptorTable]
shr ebx, 9
add eax, ebx
shl ebx, 9
add ebx, [ebp+EXTFS.descriptorTable]
call fs_write32_sys
ret
 
extfsExtentFree:
; in: eax = first block number, ecx = extent size
push ebx edx edi
sub eax, [ebp+EXTFS.superblock.firstGroupBlock]
xor edx, edx
mov ebx, [ebp+EXTFS.superblock.blocksPerGroup]
div ebx
sub ebx, edx
sub ebx, ecx
jc .ret
push edx
mov ebx, [ebp+EXTFS.descriptorTable]
shl eax, 5
add ebx, eax
mov eax, ecx
mul [ebp+EXTFS.sectorsPerBlock]
add [ebx+BGDESCR.blocksFree], cx
add [ebp+EXTFS.superblock.blocksFree], ecx
sub [ebp+EXTFS.inodeBuffer.sectorsUsed], eax
push [ebx+BGDESCR.blockBitmap]
call extfsWriteDescriptor
pop eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov edx, eax
call extfsReadBlock
pop eax
jc .ret
push ebx edx
mov edi, eax
shr edi, 5
shl edi, 2
add edi, ebx
mov edx, ecx
and eax, 31
jz .aligned
mov ecx, 32
sub ecx, eax
sub edx, ecx
jnc @f
add ecx, edx
xor edx, edx
@@:
or ebx, -1
shl ebx, cl
not ebx
mov ecx, eax
shl ebx, cl
not ebx
and [edi], ebx
add edi, 4
xor eax, eax
.aligned:
mov ecx, edx
shr ecx, 5
rep stosd
and edx, 31
jz @f
mov ecx, edx
not eax
shl eax, cl
and [edi], eax
@@:
pop eax ebx
call extfsWriteBlock
.ret:
pop edi edx ebx
xor eax, eax
ret
 
extfsInodeAlloc:
; in: eax = parent inode number
; out: ebx = allocated inode number
push ecx edx edi
dec eax
xor edx, edx
div [ebp+EXTFS.superblock.inodesPerGroup]
mov ebx, [ebp+EXTFS.descriptorTable]
shl eax, 5
add ebx, eax
push ebx
.test_block_group:
push ebx
cmp [ebx+BGDESCR.blocksFree], 0
jz .next
cmp [ebx+BGDESCR.inodesFree], 0
jz .next
dec [ebx+BGDESCR.inodesFree]
dec [ebp+EXTFS.superblock.inodesFree]
push [ebx+BGDESCR.inodeBitmap]
call extfsWriteDescriptor
pop eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov edx, eax
mov edi, ebx
call extfsReadBlock
jc .fail
mov ecx, [ebp+EXTFS.superblock.inodesPerGroup]
or eax, -1
shr ecx, 5
repz scasd
jz .next
sub edi, 4
mov eax, [edi]
not eax
bsf eax, eax
bts [edi], eax
sub edi, [ebp+EXTFS.tempBlockBuffer]
shl edi, 3
add eax, edi
mov ecx, eax
mov eax, edx
call extfsWriteBlock
pop eax
sub eax, [ebp+EXTFS.descriptorTable]
shr eax, 5
mul [ebp+EXTFS.superblock.inodesPerGroup]
lea ebx, [eax+ecx+1]
xor eax, eax
.ret:
pop edi edi edx ecx
ret
 
.next: ; search forward, then backward
pop ebx
cmp ebx, [esp]
jc .backward
add ebx, 32
cmp ebx, [ebp+EXTFS.descriptorTableEnd]
jc .test_block_group
mov ebx, [esp]
.backward:
sub ebx, 32
cmp ebx, [ebp+EXTFS.descriptorTable]
jnc .test_block_group
movi eax, ERROR_DISK_FULL
push eax
.fail:
pop edi
jmp .ret
 
extfsExtentAlloc:
; in: eax = parent inode number, ecx = blocks max
; out: ebx = first block number, ecx = blocks allocated
push edx esi edi ecx
dec eax
xor edx, edx
div [ebp+EXTFS.superblock.inodesPerGroup]
mov ebx, [ebp+EXTFS.descriptorTable]
shl eax, 5
add ebx, eax
push ebx
.test_block_group:
push ebx
cmp [ebx+BGDESCR.blocksFree], 0
jz .next
mov eax, [ebx+BGDESCR.blockBitmap]
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov edx, eax
mov edi, ebx
call extfsReadBlock
jc .fail
mov ecx, [ebp+EXTFS.superblock.blocksPerGroup]
shr ecx, 5
or eax, -1
repz scasd
jz .next
mov esi, edi
sub esi, 4
push edx ecx
mov eax, [esi]
not eax
bsf ecx, eax
not eax
shr eax, cl
shl eax, cl
mov ebx, 32
bsf ebx, eax
sub ebx, ecx
mov eax, [esp+16]
cmp ebx, eax
jc @f
mov ebx, eax
@@:
or eax, -1
cmp ebx, 32
jz @f
xchg ebx, ecx
shl eax, cl
not eax
xchg ebx, ecx
shl eax, cl
@@:
or [esi], eax
sub esi, [ebp+EXTFS.tempBlockBuffer]
shl esi, 3
add esi, ecx
mov eax, [esp+16]
sub eax, ebx
mov [esp+16], ebx
add ebx, ecx
pop ecx
test eax, eax
jz .done
cmp ebx, 32
jnz .done
jecxz .done
mov ebx, eax
shr eax, 5
inc eax
and ebx, 31
cmp ecx, eax
jnc @f
mov eax, ecx
mov bl, 32
@@:
mov ecx, eax
shl eax, 5
add [esp+12], eax
xor eax, eax
push edi
repz scasd
jz @f
mov eax, [edi-4]
bsf eax, eax
xchg eax, ebx
test ecx, ecx
jnz @f
cmp ebx, eax
jc @f
mov ebx, eax
@@:
inc ecx
shl ecx, 5
sub ecx, ebx
sub [esp+16], ecx
mov ecx, edi
pop edi
sub ecx, edi
shr ecx, 2
dec ecx
or eax, -1
rep stosd
mov ecx, ebx
jecxz .done
neg ecx
add ecx, 32
shr eax, cl
or [edi], eax
.done:
pop eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
mov ebx, [esp]
mov ecx, [esp+8]
sub [ebx+BGDESCR.blocksFree], cx
jnc @f
mov [ebx+BGDESCR.blocksFree], 0
@@:
sub [ebp+EXTFS.superblock.blocksFree], ecx
call extfsWriteDescriptor
pop eax ebx
sub eax, [ebp+EXTFS.descriptorTable]
shr eax, 5
mul [ebp+EXTFS.superblock.blocksPerGroup]
mov ebx, eax
add ebx, esi
add ebx, [ebp+EXTFS.superblock.firstGroupBlock]
pop ecx
mov eax, ecx
mul [ebp+EXTFS.sectorsPerBlock]
add [ebp+EXTFS.inodeBuffer.sectorsUsed], eax
xor eax, eax
.ret:
pop edi esi edx
ret
 
.next: ; search forward, then backward
pop ebx
cmp ebx, [esp]
jc .backward
add ebx, 32
cmp ebx, [ebp+EXTFS.descriptorTableEnd]
jc .test_block_group
mov ebx, [esp]
.backward:
sub ebx, 32
cmp ebx, [ebp+EXTFS.descriptorTable]
jnc .test_block_group
movi eax, ERROR_DISK_FULL
push eax
.fail:
add esp, 12
xor ecx, ecx
stc
jmp .ret
 
extfsGetExtent:
; in: ecx = starting file block
; out: eax = first block number, ecx = extent size
push ebx edx esi
lea esi, [ebp+EXTFS.inodeBuffer]
test [esi+INODE.featureFlags], EXTENTS_USED
jz .listTreeSearch
add esi, INODE.blockNumbers
.extentTreeSearch:
cmp word [esi+NODEHEADER.magic], 0xF30A
jne .fail
movzx ebx, [esi+NODEHEADER.entriesFolow]
add esi, sizeof.NODEHEADER
test ebx, ebx
jz .noBlock
cmp word [esi-sizeof.NODEHEADER+NODEHEADER.currentDepth], 0
je .leaf_block
dec ebx
jz .end_search_index
@@:
cmp ecx, [esi+sizeof.INDEX+INDEX.fileBlock]
jb .end_search_index
add esi, sizeof.INDEX
dec ebx
jnz @b
.end_search_index:
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov eax, [esi+INDEX.nodeBlock]
call extfsReadBlock
jc .fail2
mov esi, ebx
jmp .extentTreeSearch
 
.fail:
movi eax, ERROR_FS_FAIL
jmp .fail2
 
.leaf_block:
movzx edx, [esi+EXTENT.blocksCount]
add edx, [esi+EXTENT.fileBlock]
sub edx, ecx
ja .end_search_extent
add esi, sizeof.EXTENT
dec ebx
jnz .leaf_block
.noBlock:
movi eax, ERROR_END_OF_FILE
.fail2:
pop esi edx ebx
stc
ret
 
.end_search_extent:
sub ecx, [esi+EXTENT.fileBlock]
jc .fail
add ecx, [esi+EXTENT.fsBlock]
mov eax, ecx
mov ecx, edx
pop esi edx ebx
ret
 
.listTreeSearch:
cmp ecx, 12
jb .get_direct_block
sub ecx, 12
cmp ecx, [ebp+EXTFS.dwordsPerBlock]
jb .get_indirect_block
sub ecx, [ebp+EXTFS.dwordsPerBlock]
cmp ecx, [ebp+EXTFS.dwordsPerBranch]
jb .get_double_indirect_block
; triply-indirect blocks
sub ecx, [ebp+EXTFS.dwordsPerBranch]
mov eax, [esi+INODE.tripleAddress]
test eax, eax
jz .noBlock
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail2
xor edx, edx
mov eax, ecx
div [ebp+EXTFS.dwordsPerBranch]
; eax = number in triply-indirect block, edx = number in branch
mov eax, [ebx+eax*4]
test eax, eax
jz .noBlock
call extfsReadBlock
jc .fail2
mov eax, edx
jmp @f
 
.get_direct_block:
mov edx, ecx
mov cl, 12
lea ebx, [esi+INODE.blockNumbers]
jmp .calculateExtent
 
.get_indirect_block:
mov eax, [esi+INODE.addressBlock]
test eax, eax
jz .noBlock
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail2
mov edx, ecx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
jmp .calculateExtent
 
.get_double_indirect_block:
mov eax, [esi+INODE.doubleAddress]
test eax, eax
jz .noBlock
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail2
mov eax, ecx
@@:
xor edx, edx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
div ecx
; eax = number in doubly-indirect block, edx = number in indirect block
mov eax, [ebx+eax*4]
test eax, eax
jz .noBlock
call extfsReadBlock
jc .fail2
.calculateExtent:
lea esi, [ebx+edx*4]
lodsd
test eax, eax
jz .noBlock
mov ebx, eax
sub ecx, edx
xor edx, edx
@@:
inc edx
dec ecx
jz @f
lodsd
sub eax, ebx
sub eax, edx
jz @b
@@:
mov eax, ebx
mov ecx, edx
pop esi edx ebx
clc
ret
 
getInodeLocation:
; in: eax = inode number
; out: eax = inode sector, edx = offset in sector
dec eax
xor edx, edx
div [ebp+EXTFS.superblock.inodesPerGroup]
shl eax, 5
add eax, [ebp+EXTFS.descriptorTable]
mov ebx, [eax+BGDESCR.inodeTable]
imul ebx, [ebp+EXTFS.sectorsPerBlock]
movzx eax, [ebp+EXTFS.superblock.inodeSize]
mul edx
mov edx, eax
shr eax, 9
and edx, 511
add eax, ebx
ret
 
writeInode:
; in: eax = inode number, ebx -> inode data
push edx edi esi ecx ebx eax
mov edi, ebx
call fsGetTime
add eax, 978307200
mov [edi+INODE.inodeModified], eax
pop eax
cmp eax, ROOT_INODE
jnz @f
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
mov esi, edi
lea edi, [ebp+EXTFS.rootInodeBuffer]
rep movsb
@@:
call getInodeLocation
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov ecx, eax
call fs_read32_sys
test eax, eax
jnz @f
mov eax, ecx
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
mov edi, edx
add edi, ebx
mov esi, [esp]
rep movsb
call fs_write32_sys
.ret:
pop ebx ecx esi edi edx
ret
 
@@:
movi eax, ERROR_DEVICE
stc
jmp .ret
 
readInode:
; in: eax = inode number, ebx -> inode buffer
push edx edi esi ecx ebx
mov edi, ebx
call getInodeLocation
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call fs_read32_sys
test eax, eax
jnz @b
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
mov esi, edx
add esi, ebx
rep movsb
xor eax, eax
pop ebx ecx esi edi edx
ret
 
indirectBlockAlloc:
; in:
; edi -> indirect block number
; ebx = starting extent block
; ecx = extent size
; edx = starting file block
mov eax, [edi]
test eax, eax
jz .newBlock
push edi ebx ecx
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .err2
lea edi, [ebx+edx*4]
test edx, edx
jz @f
cmp dword[edi-4], 0
jnz @f
pop ecx ebx edi
.err:
mov al, ERROR_FS_FAIL
stc
ret
 
.err2:
pop ecx ebx edi
ret
 
.newBlock:
test edx, edx
jnz .err
mov [edi], ebx
inc ebx
dec ecx
push edi ebx ecx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
mov edi, [ebp+EXTFS.tempBlockBuffer]
push edi
rep stosd
pop edi
@@:
mov ecx, [ebp+EXTFS.dwordsPerBlock]
sub ecx, edx
pop ebx eax
sub ebx, ecx
jnc @f
add ecx, ebx
xor ebx, ebx
@@:
jecxz .done
add edx, ecx
@@:
stosd
inc eax
loop @b
.done:
pop edi
push eax ebx
mov eax, [edi]
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
pop ecx ebx
ret
 
doublyIndirectBlockAlloc:
; in:
; edi -> indirect block number
; edx = starting file block
; ebx = starting extent block
; ecx = extent size
; [esp+4] = rest of size
; [esp+8] = parent inode number
mov eax, [edi]
test eax, eax
jz .newBlock
push edi ecx ebx
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsReadBlock
jc .err2
mov eax, edx
xor edx, edx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
div ecx
lea edi, [ebx+eax*4]
pop ebx
test eax, eax
jz @f
cmp dword[edi-4], 0
jnz @f
pop ecx edi
.err:
mov al, ERROR_FS_FAIL
stc
ret
 
.err2:
pop ebx ecx edi
ret
 
.newBlock:
test edx, edx
jnz .err
mov [edi], ebx
inc ebx
dec ecx
inc dword[esp+4]
push edi ecx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
mov edi, [ebp+EXTFS.mainBlockBuffer]
push ecx edi
rep stosd
pop edi ecx
@@:
sub ecx, eax
xchg [esp], ecx
.loop:
cmp dword[edi], 0
jnz @f
inc dword[esp+12]
@@:
jecxz .extentAlloc
call indirectBlockAlloc
jc .end
cmp edx, [ebp+EXTFS.dwordsPerBlock]
jnz @b
add edi, 4
xor edx, edx
dec dword[esp]
jnz .loop
.end:
pop edi edi
push ebx eax
mov eax, [edi]
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsWriteBlock
pop ebx
add eax, ebx
xor ebx, ebx
cmp ebx, eax
pop ebx
ret
 
.extentAlloc:
mov ecx, [esp+12]
xor eax, eax
jecxz .end
mov eax, [esp+16]
call extfsExtentAlloc
jc .end
sub [esp+12], ecx
jmp @b
 
extfsExtendFile:
; in:
; [ebp+EXTFS.inodeBuffer] = inode
; ecx = inode number
; edx:eax = new size
push ebx esi edi ecx
lea esi, [ebp+EXTFS.inodeBuffer]
mov ebx, [esi+INODE.fileSize]
mov ecx, [esi+INODE.fileSizeHigh]
cmp ebx, eax
sbb ecx, edx
jnc .ret
mov ecx, [esi+INODE.fileSizeHigh]
mov [esi+INODE.fileSize], eax
mov [esi+INODE.fileSizeHigh], edx
sub eax, 1
sbb edx, 0
div [ebp+EXTFS.bytesPerBlock]
inc eax
xchg eax, ebx
mov edx, ecx
sub eax, 1
sbb edx, 0
jc @f
div [ebp+EXTFS.bytesPerBlock]
@@:
inc eax
sub ebx, eax
jz .ret
push ebx
mov edx, eax
@@:
mov ecx, [esp]
mov eax, [esp+4]
test ecx, ecx
jz .done
call extfsExtentAlloc
jc .errDone
sub [esp], ecx
cmp edx, 12
jc .directBlocks
sub edx, 12
cmp edx, [ebp+EXTFS.dwordsPerBlock]
jc .indirectBlocks
sub edx, [ebp+EXTFS.dwordsPerBlock]
cmp edx, [ebp+EXTFS.dwordsPerBranch]
jc .doublyIndirectBlock
sub edx, [ebp+EXTFS.dwordsPerBranch]
jmp .triplyIndirectBlock
 
.newExtent:
jmp @b
 
.directBlocks:
lea edi, [esi+INODE.blockNumbers+edx*4]
test edx, edx
jz @f
cmp dword[edi-4], 0
jz .errDone
@@:
mov eax, ebx
mov ebx, ecx
mov ecx, 12
sub ecx, edx
sub ebx, ecx
jnc @f
add ecx, ebx
xor ebx, ebx
@@:
add edx, ecx
@@:
stosd
inc eax
loop @b
mov ecx, ebx
mov ebx, eax
jecxz .newExtent
xor edx, edx
.indirectBlocks:
lea edi, [esi+INODE.addressBlock]
cmp dword[edi], 0
jnz @f
inc dword[esp]
@@:
call indirectBlockAlloc
jc .errDone
add edx, 12
jecxz .newExtent
xor edx, edx
.doublyIndirectBlock:
lea edi, [esi+INODE.doubleAddress]
call doublyIndirectBlockAlloc
jc .errDone
mov edx, [ebp+EXTFS.dwordsPerBranch]
add edx, [ebp+EXTFS.dwordsPerBlock]
add edx, 12
jecxz .newExtent
xor edx, edx
.triplyIndirectBlock:
push ecx ebx edx
stdcall kernel_alloc, [ebp+EXTFS.bytesPerBlock]
pop edx
mov esi, eax
mov eax, [ebp+EXTFS.inodeBuffer.tripleAddress]
test eax, eax
jz .newBlock
mov ebx, esi
call extfsReadBlock
pop ebx ecx
jc .errFree
mov eax, edx
xor edx, edx
div [ebp+EXTFS.dwordsPerBranch]
lea edi, [esi+eax*4]
test eax, eax
jz @f
cmp dword[edi-4], 0
jnz @f
mov al, ERROR_FS_FAIL
.errFree:
push ecx eax
stdcall kernel_free, esi
pop eax ecx
.errDone:
imul ecx, [ebp+EXTFS.sectorsPerBlock]
sub [ebp+EXTFS.inodeBuffer.sectorsUsed], ecx
pop ebx
imul ebx, [ebp+EXTFS.sectorsPerBlock]
add ebx, ecx
shl ebx, 9
sub [ebp+EXTFS.inodeBuffer.fileSize], ebx
stc
jmp .ret
 
.newBlock:
pop ebx ecx
mov al, ERROR_FS_FAIL
test edx, edx
jnz .errFree
mov [ebp+EXTFS.inodeBuffer.tripleAddress], ebx
inc ebx
dec ecx
inc dword[esp]
push ecx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
mov edi, esi
xor eax, eax
rep stosd
mov edi, esi
pop ecx
@@:
jecxz .extentAlloc
call doublyIndirectBlockAlloc
jc .errSave
add edi, 4
jmp @b
 
.extentAlloc:
mov ecx, [esp]
mov eax, [esp+4]
jecxz @f
call extfsExtentAlloc
jc .errSave
sub [esp], ecx
jmp @b
 
@@:
mov eax, [ebp+EXTFS.inodeBuffer.tripleAddress]
mov ebx, esi
call extfsWriteBlock
stdcall kernel_free, esi
.done:
xor eax, eax
pop edi
.ret:
pop edi edi esi ebx
ret
 
.errSave:
push eax
mov eax, [ebp+EXTFS.inodeBuffer.tripleAddress]
mov ebx, esi
call extfsWriteBlock
pop eax
jmp .errFree
 
freeBlockList:
; in: edi -> list of blocks, edx = amount of blocks
; out: ebx=0 -> end of list
mov ebx, [edi]
test ebx, ebx
jz .ret
xor eax, eax
xor ecx, ecx
@@:
stosd
inc ecx
dec edx
jz @f
mov eax, [edi]
sub eax, ebx
sub eax, ecx
jz @b
@@:
mov eax, ebx
call extfsExtentFree
test edx, edx
jnz freeBlockList
.ret:
ret
 
freeIndirectBlock:
; in: edi -> indirect block number, edx = starting block
; out: edi = edi+4, eax=0 -> end
pushd ecx 0 edi edx
mov eax, [edi]
test eax, eax
jz .ret
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsReadBlock
jc .ret
lea edi, [ebx+edx*4]
neg edx
add edx, [ebp+EXTFS.dwordsPerBlock]
call freeBlockList
test ebx, ebx
jz @f
inc dword[esp+8]
@@:
pop edx edi
mov eax, [edi]
test edx, edx
jnz @f
xor ecx, ecx
inc ecx
call extfsExtentFree
stosd
jmp .done
 
@@:
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsWriteBlock
add edi, 4
.done:
pop eax ecx
xor edx, edx
ret
 
.ret:
pop edi edi edx ecx
ret
 
freeDoublyIndirectBlock:
; in: edi -> doubly-indirect block number, edx = starting block
; out: edi = edi+4, eax=-1 -> done, eax=0 -> end
mov eax, [edi]
test eax, eax
jz .ret
push ecx eax edx
stdcall kernel_alloc, [ebp+EXTFS.bytesPerBlock]
mov ebx, eax
pop edx eax
pushd 0 ebx edx
call extfsReadBlock
jc .err
mov eax, edx
xor edx, edx
mov ecx, [ebp+EXTFS.dwordsPerBlock]
div ecx
sub ecx, eax
push edi
lea edi, [ebx+eax*4]
@@:
call freeIndirectBlock
test eax, eax
jz .end
dec ecx
jnz @b
dec dword[esp+12]
.end:
pop edi edx
mov eax, [edi]
test edx, edx
jnz @f
xor ecx, ecx
inc ecx
call extfsExtentFree
stosd
jmp .done
 
@@:
mov ebx, [esp]
call extfsWriteBlock
add edi, 4
jmp .done
 
.err:
mov [esp+8], eax
pop eax
.done:
call kernel_free
pop eax ecx
.ret:
xor edx, edx
ret
 
extfsTruncateFile:
; in: edx:eax = new size, [ebp+EXTFS.inodeBuffer] = inode
lea esi, [ebp+EXTFS.inodeBuffer]
mov ecx, edx
cmp eax, [esi+INODE.fileSize]
sbb ecx, [esi+INODE.fileSizeHigh]
jnc .ret
mov [esi+INODE.fileSize], eax
mov [esi+INODE.fileSizeHigh], edx
sub eax, 1
sbb edx, 0
jc @f
div [ebp+EXTFS.bytesPerBlock]
@@:
inc eax
mov edx, eax
cmp edx, 12
jc .directBlocks
sub edx, 12
cmp edx, [ebp+EXTFS.dwordsPerBlock]
jc .indirectBlocks
sub edx, [ebp+EXTFS.dwordsPerBlock]
cmp edx, [ebp+EXTFS.dwordsPerBranch]
jc .doublyIndirectBlock
sub edx, [ebp+EXTFS.dwordsPerBranch]
jmp .triplyIndirectBlock
 
.directBlocks:
lea edi, [esi+INODE.blockNumbers+edx*4]
neg edx
add edx, 12
call freeBlockList
test ebx, ebx
jz .ret
.indirectBlocks:
lea edi, [esi+INODE.addressBlock]
call freeIndirectBlock
test eax, eax
jz .ret
.doublyIndirectBlock:
lea edi, [esi+INODE.doubleAddress]
call freeDoublyIndirectBlock
test eax, eax
jz .ret
.triplyIndirectBlock:
mov eax, [esi+INODE.tripleAddress]
test eax, eax
jz .ret
push eax edx
stdcall kernel_alloc, [ebp+EXTFS.bytesPerBlock]
mov ebx, eax
pop edx eax
push ebx eax edx
call extfsReadBlock
jc .err
mov eax, edx
xor edx, edx
div [ebp+EXTFS.dwordsPerBranch]
mov ecx, [ebp+EXTFS.dwordsPerBlock]
sub ecx, eax
lea edi, [ebx+eax*4]
@@:
call freeDoublyIndirectBlock
test eax, eax
jz .end
dec ecx
jnz @b
.end:
pop edx eax
test edx, edx
jnz @f
xor ecx, ecx
inc ecx
call extfsExtentFree
mov [esi+INODE.tripleAddress], eax
jmp .done
 
@@:
mov ebx, [esp]
call extfsWriteBlock
jmp .done
 
.err:
pop eax eax
.done:
call kernel_free
.ret:
ret
 
linkInode:
; in:
; eax = inode on which to link
; ebx = inode to link
; esi -> name in UTF-8
; dl = file type
push esi edi ebx ecx eax edx
call strlen
push esi ebx ecx
lea esi, [ebp+EXTFS.inodeBuffer]
mov ebx, esi
call readInode
jc .error_inode_read
mov eax, [esi+INODE.fileSize]
xor edx, edx
div [ebp+EXTFS.bytesPerBlock]
xor ecx, ecx
.searchBlock:
push eax ; blocks total
push ecx ; current file block number
cmp eax, ecx
jz .alloc_block
call extfsGetExtent
jc .error_get_inode_block
push eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .error_block_read
mov ecx, [esp+12]
add ecx, 8 ; directory entry size
mov edi, [ebp+EXTFS.tempBlockBuffer]
mov edx, edi
add edx, [ebp+EXTFS.bytesPerBlock]
.searchSpace:
movzx eax, [edi+DIRENTRY.entryLength]
test eax, eax
jz .zeroLength
cmp [edi+DIRENTRY.inodeNumber], 0
je .unusedEntry
movzx ebx, [edi+DIRENTRY.nameLength]
add ebx, 8+3
and ebx, -4
sub eax, ebx
add edi, ebx
cmp eax, ecx
jb .nextEntry
sub edi, ebx
mov [edi+DIRENTRY.entryLength], bx
add edi, ebx
mov [edi+DIRENTRY.entryLength], ax
jmp .found
 
.unusedEntry:
cmp eax, ecx
jge .found
.nextEntry:
add edi, eax
cmp edi, edx
jb .searchSpace
pop ecx
@@:
pop ecx eax
inc ecx
jmp .searchBlock
 
.zeroLength:
mov eax, edx
sub eax, edi
mov [edi+DIRENTRY.entryLength], ax
cmp eax, ecx
jge .found
mov [edi+DIRENTRY.inodeNumber], 0
pop eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
jmp @b
 
.alloc_block:
mov eax, [esi+INODE.fileSize]
add eax, [ebp+EXTFS.bytesPerBlock]
xor edx, edx
mov ecx, [esp+24]
call extfsExtendFile
jc .error_get_inode_block
mov eax, [esp+24]
mov ebx, esi
call writeInode
jc .error_get_inode_block
mov ecx, [esp]
call extfsGetExtent
jc .error_get_inode_block
push eax
mov edi, [ebp+EXTFS.tempBlockBuffer]
mov eax, [ebp+EXTFS.bytesPerBlock]
mov [edi+DIRENTRY.entryLength], ax
.found:
pop edx ecx ecx ecx ebx esi
mov [edi+DIRENTRY.inodeNumber], ebx
mov word [edi+DIRENTRY.nameLength], cx
sub eax, 8
cmp ecx, eax
adc ecx, 0
test [ebp+EXTFS.superblock.incompatibleFlags], 2
jz @f
mov eax, [esp]
mov [edi+DIRENTRY.fileType], al
@@:
add edi, 8
rep movsb
mov eax, edx
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
@@:
pop edx ecx ecx ebx edi esi
ret
 
.error_block_read:
pop ebx
.error_get_inode_block:
pop ebx ebx
.error_inode_read:
pop ebx ebx ebx
jmp @b
 
unlinkInode:
; in: eax = directory inode number, esi = inode to unlink
push edi
lea ebx, [ebp+EXTFS.inodeBuffer]
call readInode
jc .ret
xor ecx, ecx
.loop:
push ecx
call extfsGetExtent
jc .fail_loop
mov edi, eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .fail_loop
.first_dir_entry: ; edi -> block
cmp [ebx+DIRENTRY.inodeNumber], esi
jne @f
mov [ebx+DIRENTRY.inodeNumber], 0
mov word [ebx+DIRENTRY.nameLength], 0 ; fileType = 0
jmp .write_block
 
.fail:
pop edi
movi eax, ERROR_FS_FAIL
stc
.fail_loop:
pop edi
jmp .ret
 
.next:
pop ecx ecx
inc ecx
jmp .loop
 
@@:
mov edx, ebx
add edx, [ebp+EXTFS.bytesPerBlock]
push edx
@@:
movzx ecx, [ebx+DIRENTRY.entryLength]
jecxz .fail
mov edx, ebx
add ebx, ecx
cmp ebx, [esp]
jnc .next
cmp [ebx+DIRENTRY.inodeNumber], esi
jnz @b
mov cx, [ebx+DIRENTRY.entryLength]
add [edx+DIRENTRY.entryLength], cx
pop eax
.write_block:
pop eax
mov eax, edi
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsWriteBlock
.ret:
pop edi
ret
 
findInode:
; in: esi -> path string in UTF-8
; out:
; edi -> file name in UTF-8
; esi = last inode number
; [ebp+EXTFS.inodeBuffer] = last inode
; ecx = parent inode number
; CF=1 -> file not found, edi=0 -> error
push esi
lea esi, [ebp+EXTFS.rootInodeBuffer]
lea edi, [ebp+EXTFS.inodeBuffer]
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
mov edx, esi
rep movsb
pop esi
pushd ebx 0 ROOT_INODE
mov edi, esi
cmp [edx+INODE.fileSize], 0
jz .not_found
cmp byte [esi], 0
jnz .next_path_part
xor eax, eax
pop esi ecx ebx
ret
 
@@:
pop esi esi
.error:
pop esi ecx ebx
xor edi, edi
stc
ret
 
.next_path_part:
push [edx+INODE.fileSize]
xor ecx, ecx
.folder_block_cycle:
push ecx
call extfsGetExtent
jc @b
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsReadBlock
jc @b
push esi edx
mov edx, ebx
add edx, [ebp+EXTFS.bytesPerBlock]
.start_rec:
cmp [ebx+DIRENTRY.inodeNumber], 0
jz .next_rec
push esi
movzx ecx, [ebx+DIRENTRY.nameLength]
lea edi, [ebx+DIRENTRY.name]
repz cmpsb
jz .test_find
@@: ; doesn't match
pop esi
.next_rec:
movzx ecx, [ebx+DIRENTRY.entryLength]
jecxz .stop
add ebx, ecx
cmp ebx, edx
jb .start_rec
jmp .stop
 
.test_find:
cmp byte [esi], 0
je @f
cmp byte [esi], '/'
jne @b
inc esi
@@:
pop edx
.stop:
pop edx edi ecx eax
; ebx -> matched directory entry, esi -> name without parent, or not changed
cmp edi, esi
jnz @f
sub eax, [ebp+EXTFS.bytesPerBlock]
jle .not_found
push eax
inc ecx
jmp .folder_block_cycle
 
@@:
pop eax
mov [esp], eax
mov eax, [ebx+DIRENTRY.inodeNumber]
lea ebx, [ebp+EXTFS.inodeBuffer]
push eax
call readInode
jc .error
cmp byte [esi], 0
je .ret
mov edx, ebx
movzx eax, [ebx+INODE.accessMode]
and eax, TYPE_MASK
cmp eax, DIRECTORY
jz .next_path_part
xor edi, edi ; path folder is a file
jmp @f
 
.not_found:
mov esi, edi
call strlen
mov al, '/'
repnz scasb
mov edi, esi
jnz @f
xor edi, edi ; path folder not found
@@:
movi eax, ERROR_FILE_NOT_FOUND
stc
.ret:
pop esi ecx ebx
ret
 
writeSuperblock:
push ebx
mov eax, 2
lea ebx, [ebp+EXTFS.superblock]
call fs_write32_sys
pop ebx
ret
 
extfsWritingInit:
movi eax, ERROR_UNSUPPORTED_FS
test [ebp+EXTFS.mountType], READ_ONLY
jnz @f
ext_lock:
lea ecx, [ebp+EXTFS.Lock]
jmp mutex_lock
 
@@:
pop ebx
xor ebx, ebx
ret
 
ext_unlock:
lea ecx, [ebp+EXTFS.Lock]
jmp mutex_unlock
 
;----------------------------------------------------------------
ext_ReadFolder:
call ext_lock
cmp byte [esi], 0
jz .root_folder
call findInode
jc .error_ret
lea esi, [ebp+EXTFS.inodeBuffer]
test [esi+INODE.accessMode], FLAG_FILE
jnz .error_not_found
jmp @f
 
.root_folder:
lea esi, [ebp+EXTFS.rootInodeBuffer]
lea edi, [ebp+EXTFS.inodeBuffer]
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
shr ecx, 2
push edi
rep movsd
pop esi
@@:
cmp [esi+INODE.fileSize], 0
je .error_empty_dir
mov edx, [ebx+16]
push edx ; [edi+28] result buffer
push 0 ; [edi+24] end of the current block in folder
pushd [ebx+12] ; [edi+20] files to read
pushd [ebx+4] ; [edi+16] first wanted file
pushd [ebx+8] ; [edi+12] flags
push 0 ; [edi+8] read files
push 0 ; [edi+4] files in folder
push 0 ; [edi] current block index
mov edi, esp ; edi -> local variables
add edx, 32
xor ecx, ecx
call extfsGetExtent
jc .error_get_block
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsReadBlock
jc .error_get_block
mov eax, ebx
add eax, [ebp+EXTFS.bytesPerBlock]
mov [edi+24], eax
mov ecx, [edi+16]
.find_wanted_start:
jecxz .find_wanted_end
.find_wanted_cycle:
cmp [ebx+DIRENTRY.inodeNumber], 0
jz @f
inc dword [edi+4]
dec ecx
@@:
movzx eax, [ebx+DIRENTRY.entryLength]
cmp eax, 12 ; minimum entry length
jb .error_bad_len
test eax, 3 ; length must be aligned
jnz .error_bad_len
sub [esi+INODE.fileSize], eax
add ebx, eax
cmp ebx, [edi+24]
jb .find_wanted_start
push .find_wanted_start
.end_block: ; read next block
cmp [esi+INODE.fileSize], 0
jle .end_dir
inc dword [edi]
push ecx
mov ecx, [edi]
call extfsGetExtent
jc .error_get_block
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call extfsReadBlock
jc .error_get_block
pop ecx
mov eax, ebx
add eax, [ebp+EXTFS.bytesPerBlock]
mov [edi+24], eax
ret
 
.wanted_end:
loop .find_wanted_cycle
.find_wanted_end:
mov ecx, [edi+20]
.wanted_start:
jecxz .wanted_end
cmp [ebx+DIRENTRY.inodeNumber], 0
jz .empty_rec
inc dword [edi+8]
inc dword [edi+4]
push ebx edi ecx esi edx edi
pushd [edi+12]
mov edi, edx
xor eax, eax
mov ecx, 40 / 4
rep stosd
popd [edx+4] edi
mov eax, [ebx+DIRENTRY.inodeNumber]
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call readInode
jc .error_read_subinode
mov esi, ebx
lea edi, [edx+8]
mov eax, [ebx+INODE.inodeModified]
sub eax, 978307200 ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
call fsTime2bdfe
 
mov eax, [esi+INODE.accessedTime]
sub eax, 978307200
call fsTime2bdfe
 
mov eax, [esi+INODE.dataModified]
sub eax, 978307200
call fsTime2bdfe
pop edx
or dword [edx], KOS_DIRECTORY
test [esi+INODE.accessMode], FLAG_FILE
jz @f
xor dword [edx], KOS_DIRECTORY ; mark as file
mov eax, [esi+INODE.fileSize]
stosd
mov eax, [esi+INODE.fileSizeHigh]
stosd
@@:
mov esi, [esp+12]
movzx ecx, [esi+DIRENTRY.nameLength]
lea esi, [esi+DIRENTRY.name]
cmp byte [esi], '.'
jnz @f
or byte [edx], KOS_HIDDEN
@@:
lea edi, [edx+40]
cmp byte [edx+4], 3
jz .utf8
add ecx, esi
cmp byte [edx+4], 2
jz .utf16
@@:
call utf8to16
call uni2ansi_char
stosb
cmp esi, ecx
jc @b
and byte [edi], 0
add edx, 40+264
@@:
pop esi ecx edi ebx
dec ecx
.empty_rec:
movzx eax, [ebx+DIRENTRY.entryLength]
cmp eax, 12
jb .error_bad_len
test eax, 3
jnz .error_bad_len
sub [esi+INODE.fileSize], eax
add ebx, eax
cmp ebx, [edi+24]
jb .wanted_start
push .wanted_start
jmp .end_block
 
.utf8:
rep movsb
mov byte [edi], 0
add edx, 40+520
jmp @b
 
.utf16:
call utf8to16
stosw
cmp esi, ecx
jc .utf16
and word [edi], 0
add edx, 40+520
jmp @b
 
.end_dir:
call ext_unlock
mov edx, [edi+28]
mov ebx, [edi+8]
mov ecx, [edi+4]
mov dword [edx], 1 ; version
mov [edx+4], ebx
mov [edx+8], ecx
lea esp, [edi+32]
mov ecx, 20/4
lea edi, [edx+12]
xor eax, eax
rep stosd
ret
 
.error_bad_len:
movi eax, ERROR_FS_FAIL
.error_read_subinode:
.error_get_block:
lea esp, [edi+32]
.error_ret:
xor ebx, ebx
push eax
call ext_unlock
pop eax
ret
 
.error_empty_dir:
movi eax, ERROR_FS_FAIL
jmp .error_ret
 
.error_not_found:
movi eax, ERROR_FILE_NOT_FOUND
jmp .error_ret
 
;----------------------------------------------------------------
ext_ReadFile:
call ext_lock
call findInode
pushd 0 eax
jc .ret
lea esi, [ebp+EXTFS.inodeBuffer]
mov byte [esp], ERROR_ACCESS_DENIED
test [esi+INODE.accessMode], FLAG_FILE
jz .ret ; not a file
mov byte [esp], ERROR_END_OF_FILE
mov eax, [esi+INODE.fileSize]
mov edx, [esi+INODE.fileSizeHigh]
sub eax, [ebx+4]
sbb edx, [ebx+8]
jc .ret
mov ecx, [ebx+12]
sub eax, ecx
sbb edx, 0
jc @f
xor eax, eax
mov [esp], eax
@@:
add ecx, eax
mov eax, [ebx+4]
mov edx, [ebx+8]
mov edi, [ebx+16]
div [ebp+EXTFS.bytesPerBlock]
test edx, edx
jz .aligned
.piece:
push eax ecx
mov esi, edx
mov ecx, eax
call extfsGetExtent
jc .errorGet
mov ecx, [ebp+EXTFS.sectorsPerBlock]
mul ecx
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call fs_read64_sys
test eax, eax
jnz .errorRead
pop eax
mov ecx, [ebp+EXTFS.bytesPerBlock]
sub ecx, esi
sub eax, ecx
jnc @f
add ecx, eax
xor eax, eax
@@:
add esi, ebx
add [esp+8], ecx
rep movsb
mov ecx, eax
pop eax
inc eax
xor edx, edx
jecxz .ret
.aligned:
xchg eax, ecx
div [ebp+EXTFS.bytesPerBlock]
push edx
mov edx, eax
.writeExtent:
test edx, edx
jz .end
push ecx
call extfsGetExtent
jc .errorGet
sub edx, ecx
jnc @f
add ecx, edx
xor edx, edx
@@:
add [esp], ecx
imul ecx, [ebp+EXTFS.sectorsPerBlock]
mov ebx, edi
push edx ecx
mul [ebp+EXTFS.sectorsPerBlock]
call fs_read64_sys
pop ecx edx
test eax, eax
jnz .errorRead
shl ecx, 9
add edi, ecx
add [esp+12], ecx
pop ecx
jmp .writeExtent
 
.end:
mov eax, ecx
pop ecx
jecxz .ret
jmp .piece
 
.errorRead:
movi eax, ERROR_DEVICE
.errorGet:
pop ebx ebx
mov [esp], eax
.ret:
call ext_unlock
pop eax ebx
ret
 
;----------------------------------------------------------------
ext_GetFileInfo:
cmp byte [esi], 0
jz .volume
call ext_lock
call findInode
jc .ret
lea esi, [ebp+EXTFS.inodeBuffer]
mov edx, [ebx+16]
mov bl, [edi]
xor eax, eax
mov edi, edx
mov ecx, 40/4
rep stosd
cmp bl, '.'
jne @f
or dword [edx], KOS_HIDDEN
@@:
or dword [edx], KOS_DIRECTORY
test [esi+INODE.accessMode], FLAG_FILE
jz @f
xor dword [edx], KOS_DIRECTORY ; mark as file
mov eax, [esi+INODE.fileSize]
mov ebx, [esi+INODE.fileSizeHigh]
mov dword [edx+32], eax
mov dword [edx+36], ebx
@@:
lea edi, [edx+8]
mov eax, [esi+INODE.inodeModified]
sub eax, 978307200 ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
call fsTime2bdfe
 
mov eax, [esi+INODE.accessedTime]
sub eax, 978307200
call fsTime2bdfe
 
mov eax, [esi+INODE.dataModified]
sub eax, 978307200
call fsTime2bdfe
xor eax, eax
.ret:
push eax
call ext_unlock
pop eax
@@:
ret
 
.volume:
mov eax, dword[ebp+EXTFS.Length]
mov edx, dword[ebp+EXTFS.Length+4]
mov edi, [ebx+16]
shld edx, eax, 9
shl eax, 9
mov [edi+36], edx
mov [edi+32], eax
mov eax, [ebx+8]
mov byte [edi], 8
mov [edi+4], eax
test eax, eax
jz @b
lea esi, [ebp+EXTFS.superblock.volumeLabel]
mov ecx, 16
add edi, 40
cmp eax, 3
jz .utf8
add ecx, esi
cmp eax, 2
jz .utf16
@@:
call utf8to16
call uni2ansi_char
stosb
cmp esi, ecx
jc @b
jmp @f
 
.utf8:
rep movsb
jmp @f
 
.utf16:
call utf8to16
stosw
cmp esi, ecx
jc .utf16
@@:
xor eax, eax
mov [edi], ax
ret
 
;----------------------------------------------------------------
ext_SetFileInfo:
call extfsWritingInit
call findInode
jc @f
push esi
mov esi, [ebx+16]
add esi, 16
lea edi, [ebp+EXTFS.inodeBuffer]
call fsCalculateTime
add eax, 978307200 ; 01.01.1970-01.01.2001 = (365*31+8)*24*60*60
mov [edi+INODE.accessedTime], eax
 
add esi, 8
call fsCalculateTime
add eax, 978307200
mov [edi+INODE.dataModified], eax
mov ebx, edi
pop eax
call writeInode
@@:
push eax
jc @f
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
@@:
call ext_unlock
pop eax
ret
 
;----------------------------------------------------------------
ext_Delete:
call extfsWritingInit
call findInode
jc .error
push ecx
movzx edi, [ebp+EXTFS.inodeBuffer.accessMode]
and edi, TYPE_MASK
cmp edi, DIRECTORY
jne .file
xor ecx, ecx
.checkDirectory:
push ecx
call extfsGetExtent
jc .empty
mov ebx, [ebp+EXTFS.tempBlockBuffer]
call extfsReadBlock
jc .error8
mov edx, ebx
add edx, [ebp+EXTFS.bytesPerBlock]
.dir_entry:
movzx ecx, [ebx+DIRENTRY.nameLength]
mov ax, word [ebx+DIRENTRY.name]
jecxz @f
cmp al, '.'
jnz .not_empty
dec ecx
jz @f
cmp al, ah
jnz .not_empty
dec ecx
jnz .not_empty
@@:
mov cx, [ebx+DIRENTRY.entryLength]
jecxz @f
add ebx, ecx
cmp ebx, edx
jb .dir_entry
@@:
pop ecx
inc ecx
jmp .checkDirectory
 
.not_empty:
pop eax eax
push ERROR_ACCESS_DENIED
jmp .ret
 
.error8:
pop ebx
.error4:
pop ebx
.error:
push eax
jmp .ret
 
.empty:
pop ecx ecx
cmp eax, ERROR_END_OF_FILE
jnz .error
push ecx
.file:
mov eax, ecx
call unlinkInode
jc .error4
pop eax
lea ebx, [ebp+EXTFS.inodeBuffer]
cmp edi, DIRECTORY
jnz @f
dec [ebx+INODE.linksCount]
call writeInode
@@:
mov eax, esi
call readInode
jc .error
dec [ebx+INODE.linksCount]
jz @f
cmp edi, DIRECTORY
jnz .hardlinks
@@:
push esi edi
xor eax, eax
xor edx, edx
call extfsTruncateFile ; free file's data
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
lea edi, [ebp+EXTFS.inodeBuffer]
xor eax, eax
push edi
rep stosb
call fsGetTime
pop ebx edi esi
add eax, 978307200
mov [ebx+INODE.deletedTime], eax
mov eax, esi
dec eax
xor edx, edx
div [ebp+EXTFS.superblock.inodesPerGroup]
push edx
mov ebx, [ebp+EXTFS.descriptorTable]
shl eax, 5
add ebx, eax
cmp edi, DIRECTORY
jnz @f
dec [ebx+BGDESCR.directoriesCount]
@@:
inc [ebx+BGDESCR.inodesFree]
push [ebx+BGDESCR.inodeBitmap]
call extfsWriteDescriptor
pop eax
mov ebx, [ebp+EXTFS.tempBlockBuffer]
mov ecx, eax
call extfsReadBlock
pop edx
jc .error
mov eax, edx
and edx, 31
shr eax, 5
shl eax, 2
add eax, ebx
btr [eax], edx
mov eax, ecx
call extfsWriteBlock
inc [ebp+EXTFS.superblock.inodesFree]
.hardlinks:
mov eax, esi
lea ebx, [ebp+EXTFS.inodeBuffer]
call writeInode
push eax
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
.ret:
call ext_unlock
xor ebx, ebx
pop eax
ret
 
;----------------------------------------------------------------
ext_CreateFolder:
call extfsWritingInit
call findInode
jnc .success ; exist
test edi, edi
jz .error
mov eax, esi
call extfsInodeAlloc
jc .error
push ebx esi edi
lea edi, [ebp+EXTFS.inodeBuffer]
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
xor eax, eax
rep stosb
call fsGetTime
add eax, 978307200
lea ebx, [ebp+EXTFS.inodeBuffer]
mov [ebx+INODE.accessedTime], eax
mov [ebx+INODE.dataModified], eax
pop edi esi edx
; edx = allocated inode number, edi -> filename, esi = parent inode number
mov [ebx+INODE.accessMode], DIRECTORY or 511
mov byte [ebx+INODE.linksCount], 2
mov eax, edx
call writeInode
jc .error
; link to self
push edx esi
mov eax, edx
mov ebx, eax
mov dl, DIR_DIRECTORY
mov esi, self_link
call linkInode
pop esi edx
jc .error
; link to parent
push edx esi
mov eax, ebx
mov ebx, esi
mov dl, DIR_DIRECTORY
mov esi, parent_link
call linkInode
pop esi edx
jc .error
; link parent to child
push esi
mov eax, esi
mov ebx, edx
mov esi, edi
mov dl, DIR_DIRECTORY
call linkInode
pop edx
jc .error
push ebx
lea ebx, [ebp+EXTFS.inodeBuffer]
inc [ebx+INODE.linksCount]
mov eax, edx
call writeInode
pop ebx
jc .error
mov eax, ebx
dec eax
xor edx, edx
div [ebp+EXTFS.superblock.inodesPerGroup]
mov ebx, [ebp+EXTFS.descriptorTable]
shl eax, 5
add ebx, eax
inc [ebx+BGDESCR.directoriesCount]
call extfsWriteDescriptor
.success:
.error:
push eax
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
call ext_unlock
pop eax
ret
 
self_link db ".", 0
parent_link db "..", 0
 
;----------------------------------------------------------------
ext_CreateFile:
call extfsWritingInit
pushd 0 0 ebx
call findInode
jnc .exist
test edi, edi
jz .error
mov eax, esi
call extfsInodeAlloc
jc .error
push ebx ebx esi edi
lea edi, [ebp+EXTFS.inodeBuffer]
movzx ecx, [ebp+EXTFS.superblock.inodeSize]
xor eax, eax
rep stosb
call fsGetTime
add eax, 978307200
lea ebx, [ebp+EXTFS.inodeBuffer]
mov [ebx+INODE.accessedTime], eax
mov [ebx+INODE.dataModified], eax
pop edi esi edx
; edx = allocated inode number, edi -> filename, esi = parent inode number
mov [ebx+INODE.accessMode], FLAG_FILE or 110110110b
mov byte [ebx+INODE.linksCount], 1
mov eax, edx
call writeInode
jc .error2
; link parent to child
mov eax, esi
mov ebx, edx
mov esi, edi
mov dl, DIR_FLAG_FILE
call linkInode
jc .error2
mov eax, ebx
lea ebx, [ebp+EXTFS.inodeBuffer]
call readInode
jc .error2
pop esi ebx
mov eax, [ebx+12]
xor edx, edx
jmp ext_WriteFile.start
 
.exist:
movi eax, ERROR_ACCESS_DENIED
test [ebp+EXTFS.inodeBuffer.accessMode], FLAG_FILE
jz .error ; not a file
pop ebx
mov eax, [ebx+12]
xor edx, edx
push eax edx ebx esi
call extfsTruncateFile
pop esi ebx edx eax
jmp ext_WriteFile.start
 
.error2:
pop ebx
.error:
push eax
call ext_unlock
pop eax ebx ebx ebx
ret
 
;----------------------------------------------------------------
ext_WriteFile:
call extfsWritingInit
call findInode
pushd 0 eax
jc .ret
mov byte [esp], ERROR_ACCESS_DENIED
test [ebp+EXTFS.inodeBuffer.accessMode], FLAG_FILE
jz .ret ; not a file
mov byte [esp], 0
mov eax, [ebx+4]
mov edx, [ebx+8]
add eax, [ebx+12]
adc edx, 0
.start:
push esi
mov ecx, esi
call extfsExtendFile
jc .errorExtend
mov eax, [ebx+4]
mov edx, [ebx+8]
mov ecx, [ebx+12]
mov esi, [ebx+16]
.write:
jecxz .zero
div [ebp+EXTFS.bytesPerBlock]
test edx, edx
jz .aligned
.piece:
mov ebx, ecx
mov edi, edx
mov ecx, eax
push eax
call extfsGetExtent
jc .errorGet
mov ecx, [ebp+EXTFS.sectorsPerBlock]
mul ecx
push ecx eax ebx
mov ebx, [ebp+EXTFS.mainBlockBuffer]
call fs_read64_sys
test eax, eax
jnz .errorDevice
pop eax
mov ecx, [ebp+EXTFS.bytesPerBlock]
sub ecx, edi
sub eax, ecx
jnc @f
add ecx, eax
xor eax, eax
@@:
add edi, ebx
add [esp+20], ecx
rep movsb
mov edi, eax
pop eax ecx
xor edx, edx
call fs_write64_sys
mov ecx, edi
pop eax
inc eax
xor edx, edx
.zero:
jecxz .done
.aligned:
xchg eax, ecx
div [ebp+EXTFS.bytesPerBlock]
push edx
mov edx, eax
.writeExtent:
test edx, edx
jz .end
push ecx
call extfsGetExtent
jc .errorGet2
sub edx, ecx
jnc @f
add ecx, edx
xor edx, edx
@@:
add [esp], ecx
imul ecx, [ebp+EXTFS.sectorsPerBlock]
mov ebx, esi
push edx ecx
mul [ebp+EXTFS.sectorsPerBlock]
call fs_write64_sys
test eax, eax
jnz .errorDevice
pop ebx edx ecx
shl ebx, 9
add esi, ebx
add [esp+12], ebx
jmp .writeExtent
 
.end:
mov eax, ecx
pop ecx
jecxz .done
jmp .piece
 
.errorDevice:
pop eax eax
movi eax, ERROR_DEVICE
.errorGet2:
pop ebx
.errorGet:
pop ebx
.errorExtend:
mov [esp+4], eax
.done:
lea ebx, [ebp+EXTFS.inodeBuffer]
pop eax
call writeInode
add [esp], eax
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
.ret:
call ext_unlock
pop eax ebx
ret
 
.erase:
push eax eax edi
mov eax, ebx
jmp .write
 
;----------------------------------------------------------------
ext_SetFileEnd:
call extfsWritingInit
call findInode
jc .error2
lea edi, [ebp+EXTFS.inodeBuffer]
movi eax, ERROR_ACCESS_DENIED
test [edi+INODE.accessMode], FLAG_FILE
jz .error2 ; not a file
mov eax, [ebx+4]
mov edx, [ebx+8]
mov ebx, [edi+INODE.fileSize]
mov ecx, [edi+INODE.fileSizeHigh]
push esi ecx
cmp ebx, eax
sbb ecx, edx
mov ecx, esi
jnc @f
call extfsExtendFile
pop esi
jc .error
mov eax, [edi+INODE.fileSize]
mov edx, [edi+INODE.fileSizeHigh]
sub eax, ebx
sbb edx, esi
jnz .done
cmp eax, 1000001h
jnc .done
push eax
stdcall kernel_alloc, eax
pop ecx
test eax, eax
jz .error
push ecx
add ecx, 3
shr ecx, 2
mov edx, esi
mov esi, eax
mov edi, eax
xor eax, eax
rep stosd
pop ecx edi
push esi
call ext_WriteFile.erase
call kernel_free
xor eax, eax
ret
 
@@:
call extfsTruncateFile
pop eax
.done:
xor eax, eax
.error:
xchg eax, [esp]
lea ebx, [ebp+EXTFS.inodeBuffer]
call writeInode
add [esp], eax
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
pop eax
.error2:
push eax
call ext_unlock
pop eax
ret
 
;----------------------------------------------------------------
ext_Rename:
call extfsWritingInit
push esi
mov esi, edi
call findInode
jnc .error
test edi, edi
jz .error
xchg [esp], esi
push edi
call findInode
pop edi
jc .error
xor edx, edx
inc edx
test [ebp+EXTFS.inodeBuffer.accessMode], DIRECTORY
jz @f
inc edx
@@:
mov eax, ecx
push ecx edx
call unlinkInode
pop edx ecx
jc .error
cmp edx, 1
jz @f
lea ebx, [ebp+EXTFS.inodeBuffer]
dec [ebx+INODE.linksCount]
mov eax, ecx
call writeInode
jc .error
@@:
mov ebx, esi
mov esi, edi
pop eax
push eax edx
call linkInode
pop edx
jc .error
pop eax
cmp edx, 1
jz @f
lea ebx, [ebp+EXTFS.inodeBuffer]
inc [ebx+INODE.linksCount]
call writeInode
@@:
call writeSuperblock
mov esi, [ebp+PARTITION.Disk]
call disk_sync
call ext_unlock
xor eax, eax
ret
 
.error:
push eax
call ext_unlock
pop eax ebx
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/fs/ntfs.inc
0,0 → 1,4146
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
; NTFS external functions
; in:
; ebx -> parameter structure of sysfunc 70
; ebp -> NTFS structure
; esi -> path string in UTF-8
; out:
; eax, ebx = return values for sysfunc 70
iglobal
align 4
ntfs_user_functions:
dd ntfs_free
dd (ntfs_user_functions_end - ntfs_user_functions - 4) / 4
dd ntfs_ReadFile
dd ntfs_ReadFolder
dd ntfs_CreateFile
dd ntfs_WriteFile
dd ntfs_SetFileEnd
dd ntfs_GetFileInfo
dd ntfs_SetFileInfo
dd 0
dd ntfs_Delete
dd ntfs_CreateFolder
ntfs_user_functions_end:
endg
 
; Basic concepts:
; File is a FileRecord in the $MFT.
; $MFT is a file, that consists of FileRecords and starts with FileRecord of itself.
; FileRecord (FILE) consists of a header and attributes.
; Attribute consists of a header and a body.
; Attribute's body can be inside (resident) or outside of FileRecord.
; File's data is a body of $Data (80h) attribute.
; FileRecords is a data of the $MFT file.
; Directory is a file, that consists of index nodes.
; Resident index node is always located in a body of $IndexRoot (90h) attribute.
; Body of $IndexAllocation (A0h) attribute is always non resident
; and consists of IndexRecords.
; IndexRecord (INDX) consists of a header and an index node.
; Index node consists of a header and indexes.
; Index consists of a header and a copy of indexed attribute's body.
; Directories index $Filename (30h) attribute of all existing files.
; $IndexRoot and $IndexAllocation attributes of a directory has a name — $I30.
 
; Offsets:
; record header
magic = 0
updateSequenceOffset = 4
updateSequenceSize = 6
; FileRecord header
reuseCounter = 16
hardLinkCounter = 12h
attributeOffset = 14h
recordFlags = 16h
recordRealSize = 18h
recordAllocatedSize = 1ch
baseRecordReference = 20h ; for auxiliary records
baseRecordReuse = 26h
newAttributeID = 28h
; attribute header
attributeType = 0
sizeWithHeader = 4
nonResidentFlag = 8
nameLength = 9
nameOffset = 10
attributeFlags = 12
attributeID = 14
; resident attribute header
sizeWithoutHeader = 10h
attributeOffset = 14h
indexedFlag = 16h
; non resident attribute header
firstVCN = 10h
lastVCN = 18h
dataRunsOffset = 20h
attributeAllocatedSize = 28h
attributeRealSize = 30h
initialDataSize = 38h
; $IndexRoot
indexedAttributesType = 0
collationRule = 4
indexRecordSize = 8
indexRecordSizeClus = 12 ; in sectors if less than one cluster
rootNode = 16
; IndexRecord header
recordVCN = 16
recordNode = 18h
; node header
indexOffset = 0
nodeRealSize = 4
nodeAllocatedSize = 8
nonLeafFlag = 12
; $Filename index
fileRecordReference = 0
fileReferenceReuse = 6
indexAllocatedSize = 8
indexRawSize = 10
indexFlags = 12
directoryRecordReference = 16
directoryReferenceReuse = 16h
fileCreated = 18h
fileModified = 20h
recordModified = 28h
fileAccessed = 30h
fileAllocatedSize = 38h
fileRealSize = 40h
fileFlags = 48h
fileNameLength = 50h
namespace = 51h
fileName = 52h
 
struct NTFS PARTITION
Lock MUTEX ; Currently operations with one partition
; can not be executed in parallel since the legacy code is not ready.
sectors_per_cluster dd ?
mft_cluster dd ? ; location
mftmirr_cluster dd ? ; location
frs_size dd ? ; in bytes
frs_buffer dd ? ; MFT fileRecord buffer
mft_retrieval_end dd ?
mftSize dd ? ; in sectors
cur_index_size dd ? ; in sectors
cur_index_buf dd ? ; index node buffer
secondIndexBuffer dd ?
BitmapBuffer dd ?
BitmapTotalSize dd ? ; bytes reserved
BitmapSize dd ? ; bytes readen
BitmapLocation dd ? ; starting sector
BitmapStart dd ? ; first byte after area, reserved for MFT
mftBitmapBuffer dd ? ; one cluster
mftBitmapSize dd ? ; bytes readen
mftBitmapLocation dd ? ; starting sector
 
attr_size dq ?
attr_offs dd ?
attr_list dd ?
attr_iBaseRecord dd ?
cur_attr dd ? ; attribute type
cur_iRecord dd ? ; number of fileRecord in MFT
cur_offs dd ? ; attribute VCN in sectors
cur_size dd ? ; max sectors to read
cur_buf dd ?
cur_read dd ? ; bytes readen
cur_tail dd ?
cur_subnode_size dd ?
LastRead dd ? ; last readen block of sectors
mftLastRead dd ?
rootLastRead dd ?
nodeLastRead dd ?
indexRoot dd ?
indexPointer dd ?
newRecord dd ?
fileDataStart dd ? ; starting cluster
fileDataSize dd ? ; in clusters
fileDataBuffer dd ?
fileRealSize dd ? ; in bytes
fragmentCount db ?
bCanContinue db ?
bFolder db ?
bWriteAttr db ? ; Warning: Don't forget to turn off!!!
 
mft_retrieval rb 512
align0 rb 1024-NTFS.align0
attrlist_buf rb 1024
attrlist_mft_buf rb 1024
bitmap_buf rb 1024
ends
 
ntfs_test_bootsec:
; in: ebx -> buffer, edx = size of partition
; out: CF=1 -> invalid
; 1. Name=='NTFS '
cmp dword [ebx+3], 'NTFS'
jnz .no
cmp dword [ebx+7], ' '
jnz .no
; 2. Number of bytes per sector is the same as for physical device
; (that is, 0x200 for hard disk)
cmp word [ebx+11], 0x200
jnz .no
; 3. Number of sectors per cluster must be power of 2
movzx eax, byte [ebx+13]
dec eax
js .no
test al, [ebx+13]
jnz .no
; 4. FAT parameters must be zero
cmp word [ebx+14], 0
jnz .no
cmp dword [ebx+16], 0
jnz .no
cmp byte [ebx+20], 0
jnz .no
cmp word [ebx+22], 0
jnz .no
cmp dword [ebx+32], 0
jnz .no
; 5. Number of sectors <= partition size
cmp dword [ebx+0x2C], 0
ja .no
cmp [ebx+0x28], edx
ja .no
; 6. $MFT and $MFTMirr clusters must be within partition
cmp dword [ebx+0x34], 0
ja .no
push edx
movzx eax, byte [ebx+13]
mul dword [ebx+0x30]
test edx, edx
pop edx
jnz .no
cmp eax, edx
ja .no
cmp dword [ebx+0x3C], 0
ja .no
push edx
movzx eax, byte [ebx+13]
mul dword [ebx+0x38]
test edx, edx
pop edx
jnz .no
cmp eax, edx
ja .no
; 7. Clusters per FRS must be either power of 2 or between -31 and -9
movsx eax, byte [ebx+0x40]
cmp al, -31
jl .no
cmp al, -9
jle @f
dec eax
js .no
test [ebx+0x40], al
jnz .no
@@: ; 8. Same for clusters per IndexAllocationBuffer
movsx eax, byte [ebx+0x44]
cmp al, -31
jl .no
cmp al, -9
jle @f
dec eax
js .no
test [ebx+0x44], al
jnz .no
@@: ; OK, this is correct NTFS bootsector
clc
ret
.no: ; No, this bootsector isn't NTFS
stc
ret
 
; Mount if it's a valid NTFS partition.
ntfs_create_partition:
; in:
; ebp -> PARTITION structure
; ebx -> boot sector
; ebx+512 -> buffer
; out:
; eax -> NTFS structure, 0 = not NTFS
cmp dword [esi+DISK.MediaInfo.SectorSize], 512
jnz .nope
mov edx, dword [ebp+PARTITION.Length]
cmp dword [esp+4], 0
jz .boot_read_ok
add ebx, 512
lea eax, [edx-1]
call fs_read32_sys
test eax, eax
jnz @f
call ntfs_test_bootsec
jnc .ntfs_setup
@@:
mov eax, edx
shr eax, 1
call fs_read32_sys
test eax, eax
jnz .nope
.boot_read_ok:
call ntfs_test_bootsec
jnc .ntfs_setup
.nope:
xor eax, eax
jmp .exit
 
.ntfs_setup: ; By given bootsector, initialize some NTFS variables
stdcall kernel_alloc, 1000h
test eax, eax
jz .exit
mov ecx, dword [ebp+PARTITION.FirstSector]
mov dword [eax+NTFS.FirstSector], ecx
mov ecx, dword [ebp+PARTITION.FirstSector+4]
mov dword [eax+NTFS.FirstSector+4], ecx
mov ecx, [ebp+PARTITION.Disk]
mov [eax+NTFS.Disk], ecx
mov [eax+NTFS.FSUserFunctions], ntfs_user_functions
mov [eax+NTFS.bWriteAttr], 0
 
push ebx ebp esi
mov ebp, eax
lea ecx, [ebp+NTFS.Lock]
call mutex_init
movzx eax, byte [ebx+13]
mov [ebp+NTFS.sectors_per_cluster], eax
mov eax, [ebx+0x28]
mov dword [ebp+NTFS.Length], eax
and dword [ebp+NTFS.Length+4], 0
mov eax, [ebx+0x30]
mov [ebp+NTFS.mft_cluster], eax
mov eax, [ebx+0x38]
mov [ebp+NTFS.mftmirr_cluster], eax
movsx eax, byte [ebx+0x40]
test eax, eax
js @f
mul [ebp+NTFS.sectors_per_cluster]
shl eax, 9
jmp .1
 
@@:
neg eax
mov ecx, eax
mov eax, 1
shl eax, cl
.1:
mov [ebp+NTFS.frs_size], eax
stdcall kernel_alloc, eax
test eax, eax
jz .fail_free
mov [ebp+NTFS.frs_buffer], eax
; read $MFT disposition
mov eax, [ebp+NTFS.mft_cluster]
mul [ebp+NTFS.sectors_per_cluster]
mov ecx, [ebp+NTFS.frs_size]
shr ecx, 9
mov ebx, [ebp+NTFS.frs_buffer]
call fs_read64_sys
test eax, eax
jnz .usemirr
cmp dword [ebx], 'FILE'
jnz .usemirr
call ntfs_restore_usa_frs
jnc .mftok
.usemirr:
mov eax, [ebp+NTFS.mftmirr_cluster]
mul [ebp+NTFS.sectors_per_cluster]
mov ecx, [ebp+NTFS.frs_size]
shr ecx, 9
mov ebx, [ebp+NTFS.frs_buffer]
call fs_read64_sys
test eax, eax
jnz .fail_free_frs
cmp dword [ebx], 'FILE'
jnz .fail_free_frs
call ntfs_restore_usa_frs
jc .fail_free_frs
.mftok: ; prepare $MFT retrieval information
; search for unnamed non-resident $DATA attribute
movzx eax, word [ebx+attributeOffset]
add eax, ebx
.scandata:
cmp dword [eax], -1
jz .fail_free_frs
cmp dword [eax], 0x80
jnz @f
cmp byte [eax+nameLength], 0
jz .founddata
@@:
add eax, [eax+sizeWithHeader]
jmp .scandata
 
.founddata:
cmp byte [eax+nonResidentFlag], 0
jz .fail_free_frs
movzx esi, word [eax+dataRunsOffset]
add esi, eax
mov edx, [eax+attributeAllocatedSize+4]
mov eax, [eax+attributeAllocatedSize]
shrd eax, edx, 9
mov [ebp+NTFS.mftSize], eax
sub esp, 10h
lea ecx, [ebp+NTFS.mft_retrieval]
xor edx, edx
.scanmcb: ; load descriptions of fragments
call ntfs_decode_mcb_entry
jnc .scanmcbend
mov eax, [esp] ; block length
mov [ecx], eax
add edx, [esp+8] ; block addr
mov [ecx+4], edx
add ecx, 8
jmp .scanmcb
 
.scanmcbend:
add esp, 10h
lea eax, [ebp+NTFS.attrlist_buf]
cmp eax, ecx
jc @f
mov eax, ecx
@@:
mov [ebp+NTFS.mft_retrieval_end], eax
; allocate index buffers
stdcall kernel_alloc, 2000h
test eax, eax
jz .fail_free_frs
mov [ebp+NTFS.cur_index_buf], eax
add eax, 1000h
mov [ebp+NTFS.secondIndexBuffer], eax
mov [ebp+NTFS.cur_index_size], 8
; reserve adress space for bitmap buffer and load some part of bitmap
mov eax, dword [ebp+NTFS.Length]
xor edx, edx
div [ebp+NTFS.sectors_per_cluster]
shr eax, 3
mov [ebp+NTFS.BitmapTotalSize], eax
add eax, 7FFFh
and eax, not 7FFFh
push eax
call alloc_kernel_space
test eax, eax
jz .failFreeIndex
mov [ebp+NTFS.BitmapBuffer], eax
mov [ebp+NTFS.cur_buf], eax
mov eax, [ebp+NTFS.BitmapTotalSize]
add eax, [ebp+NTFS.mft_cluster]
shr eax, 3+2 ; reserve 1/8 of partition for $MFT
shl eax, 2
mov [ebp+NTFS.BitmapStart], eax
shr eax, 15
inc eax
shl eax, 3
push eax
push eax
shl eax, 3
mov [ebp+NTFS.cur_size], eax
call alloc_pages
test eax, eax
pop ecx
jz .failFreeBitmap
add eax, 3
mov ebx, [ebp+NTFS.BitmapBuffer]
call commit_pages
mov [ebp+NTFS.cur_iRecord], 6
mov [ebp+NTFS.cur_attr], 0x80
mov [ebp+NTFS.cur_offs], 0
call ntfs_read_attr
jc .failFreeBitmap
mov eax, [ebp+NTFS.cur_read]
mov [ebp+NTFS.BitmapSize], eax
mov eax, [ebp+NTFS.LastRead]
mov [ebp+NTFS.BitmapLocation], eax
; read MFT $BITMAP attribute
mov eax, [ebp+NTFS.sectors_per_cluster]
mov [ebp+NTFS.cur_size], eax
shl eax, 9
stdcall kernel_alloc, eax
test eax, eax
jz .failFreeBitmap
mov [ebp+NTFS.mftBitmapBuffer], eax
mov [ebp+NTFS.cur_buf], eax
mov [ebp+NTFS.cur_iRecord], 0
mov [ebp+NTFS.cur_attr], 0xB0
mov [ebp+NTFS.cur_offs], 0
call ntfs_read_attr
mov eax, [ebp+NTFS.cur_read]
cmp eax, 4
jc .failFreeBitmapMFT
mov ecx, [ebp+NTFS.attr_offs]
cmp byte [ecx+nonResidentFlag], 1
jnz .failFreeBitmapMFT
mov [ebp+NTFS.mftBitmapSize], eax
mov eax, [ebp+NTFS.LastRead]
mov [ebp+NTFS.mftBitmapLocation], eax
 
mov eax, ebp
.pop_exit:
pop esi ebp ebx
.exit:
cmp dword [esp+4], 0
jz @f
sub ebx, 512
@@:
ret
 
.failFreeBitmapMFT:
stdcall kernel_free, [ebp+NTFS.mftBitmapBuffer]
.failFreeBitmap:
stdcall kernel_free, [ebp+NTFS.BitmapBuffer]
.failFreeIndex:
mov eax, [ebp+NTFS.cur_index_buf]
cmp eax, [ebp+NTFS.secondIndexBuffer]
jc @f
mov eax, [ebp+NTFS.secondIndexBuffer]
@@:
stdcall kernel_free, eax
.fail_free_frs:
stdcall kernel_free, [ebp+NTFS.frs_buffer]
.fail_free:
stdcall kernel_free, ebp
xor eax, eax
jmp .pop_exit
 
ntfs_free:
push ebx
mov ebx, eax
stdcall kernel_free, [ebx+NTFS.frs_buffer]
stdcall kernel_free, [ebx+NTFS.mftBitmapBuffer]
stdcall kernel_free, [ebx+NTFS.BitmapBuffer]
mov eax, [ebx+NTFS.cur_index_buf]
cmp eax, [ebx+NTFS.secondIndexBuffer]
jc @f
mov eax, [ebx+NTFS.secondIndexBuffer]
@@:
stdcall kernel_free, eax
stdcall kernel_free, ebx
pop ebx
ret
 
ntfs_lock:
lea ecx, [ebp+NTFS.Lock]
jmp mutex_lock
 
ntfs_unlock:
lea ecx, [ebp+NTFS.Lock]
jmp mutex_unlock
 
ntfs_read_attr:
; [ebp+NTFS.bWriteAttr]=1 -> write attribute
; in:
; [ebp+NTFS.cur_iRecord] = number of fileRecord
; [ebp+NTFS.cur_attr] = attribute type
; [ebp+NTFS.cur_offs] = attribute VCN in sectors
; [ebp+NTFS.cur_buf] -> buffer for data
; [ebp+NTFS.cur_size] = max sectors to read
; out:
; [ebp+NTFS.cur_read] = bytes readen
; CF=1 -> failed, eax = disk error code, eax=0 -> something with FS
xor eax, eax
pushad
and [ebp+NTFS.cur_read], 0
cmp [ebp+NTFS.cur_iRecord], 0
jnz .nomft
cmp [ebp+NTFS.cur_attr], 0x80
jnz .nomft
; precalculated part of $Mft $DATA
mov eax, [ebp+NTFS.cur_offs]
xor edx, edx
div [ebp+NTFS.sectors_per_cluster]
mov ebx, edx
mov [ebp+NTFS.fragmentCount], 0
; eax = VCN, ebx = offset in sectors from beginning of cluster
lea esi, [ebp+NTFS.mft_retrieval]
sub esi, 8
.mftscan:
add esi, 8
cmp esi, [ebp+NTFS.mft_retrieval_end]
jz .nomft
mov ecx, [esi+4]
sub eax, [esi]
jnc .mftscan
add ecx, eax
add ecx, [esi]
neg eax
mul [ebp+NTFS.sectors_per_cluster]
xchg eax, ecx
mul [ebp+NTFS.sectors_per_cluster]
sub ecx, ebx
add eax, ebx
mov ebx, [ebp+NTFS.cur_buf]
cmp ecx, [ebp+NTFS.cur_size]
jb @f
mov ecx, [ebp+NTFS.cur_size]
@@:
mov [ebp+NTFS.LastRead], eax
mov edi, ecx
call fs_read64_sys
test eax, eax
jnz .errret
sub [ebp+NTFS.cur_size], edi
add [ebp+NTFS.cur_offs], edi
shl edi, 9
add [ebp+NTFS.cur_read], edi
add [ebp+NTFS.cur_buf], edi
inc [ebp+NTFS.fragmentCount]
xor eax, eax
xor ebx, ebx
cmp [ebp+NTFS.cur_size], eax
jz @f
jmp .mftscan
 
.errret2_pop:
xor eax, eax
.errret_pop:
pop ecx
pop ecx
.errret:
mov [esp+28], eax
stc
@@:
popad
ret
 
.nomft:
; 1. Read file record.
; N.B. This will do recursive call of read_attr for $MFT::$Data.
mov eax, [ebp+NTFS.cur_iRecord]
and [ebp+NTFS.attr_list], 0
or dword [ebp+NTFS.attr_size+4], -1
or [ebp+NTFS.attr_iBaseRecord], -1
call ntfs_read_file_record
jc .errret
; 2. Find required attribute.
mov eax, [ebp+NTFS.frs_buffer]
; a) For auxiliary records, read base record.
; If base record is present, base iRecord may be 0 (for $Mft),
; but SequenceNumber is nonzero.
cmp word [eax+baseRecordReuse], 0
jz @f
mov eax, [eax+baseRecordReference]
.beginfindattr:
call ntfs_read_file_record
jc .errret
jmp @f
 
.newAttribute:
pushad
and [ebp+NTFS.cur_read], 0
@@:
; b) Scan for required attribute and for $ATTR_LIST
mov eax, [ebp+NTFS.frs_buffer]
movzx ecx, word [eax+attributeOffset]
add eax, ecx
mov ecx, [ebp+NTFS.cur_attr]
and [ebp+NTFS.attr_offs], 0
.scanattr:
cmp dword [eax], -1
jz .scandone
cmp dword [eax], ecx
jz .okattr
cmp [ebp+NTFS.attr_iBaseRecord], -1
jnz .scancont
cmp dword [eax], 0x20 ; $ATTR_LIST
jnz .scancont
mov [ebp+NTFS.attr_list], eax
jmp .scancont
 
.okattr:
; ignore named $DATA attributes (aka NTFS streams)
cmp ecx, 0x80
jnz @f
cmp byte [eax+nameLength], 0
jnz .scancont
@@:
mov [ebp+NTFS.attr_offs], eax
.scancont:
add eax, [eax+sizeWithHeader]
jmp .scanattr
 
.continue:
pushad
and [ebp+NTFS.cur_read], 0
.scandone:
; c) Check for required offset and length
mov ecx, [ebp+NTFS.attr_offs]
jecxz .noattr
push [ebp+NTFS.cur_size]
push [ebp+NTFS.cur_read]
call .doreadattr
pop edx
pop ecx
jc .ret
cmp [ebp+NTFS.bCanContinue], 0
jz .ret
sub edx, [ebp+NTFS.cur_read]
neg edx
shr edx, 9
sub ecx, edx
mov [ebp+NTFS.cur_size], ecx
jz .ret
.noattr:
cmp [ebp+NTFS.cur_attr], 0x20
jz @f
mov ecx, [ebp+NTFS.attr_list]
test ecx, ecx
jnz .lookattr
and dword [esp+28], 0
cmp [ebp+NTFS.attr_offs], 1 ; define CF
.ret:
popad
ret
 
.lookattr:
; required attribute or required offset was not found in base record;
; it may be present in auxiliary records;
; scan $ATTR_LIST
mov eax, [ebp+NTFS.attr_iBaseRecord]
cmp eax, -1
jz @f
call ntfs_read_file_record
jc .errret
or [ebp+NTFS.attr_iBaseRecord], -1
@@:
push [ebp+NTFS.cur_offs]
push [ebp+NTFS.cur_size]
push [ebp+NTFS.cur_read]
push [ebp+NTFS.cur_buf]
push dword [ebp+NTFS.attr_size]
push dword [ebp+NTFS.attr_size+4]
or dword [ebp+NTFS.attr_size+4], -1
and [ebp+NTFS.cur_offs], 0
mov [ebp+NTFS.cur_size], 2
and [ebp+NTFS.cur_read], 0
lea eax, [ebp+NTFS.attrlist_buf]
cmp [ebp+NTFS.cur_iRecord], 0
jnz @f
lea eax, [ebp+NTFS.attrlist_mft_buf]
@@:
mov [ebp+NTFS.cur_buf], eax
push eax
call .doreadattr
pop esi
mov edx, 1
pop dword [ebp+NTFS.attr_size+4]
pop dword [ebp+NTFS.attr_size]
mov ecx, [ebp+NTFS.cur_read]
pop [ebp+NTFS.cur_buf]
pop [ebp+NTFS.cur_read]
pop [ebp+NTFS.cur_size]
pop [ebp+NTFS.cur_offs]
jc .errret
or edi, -1
lea ecx, [ecx+esi-1Ah]
.scanliststart:
push ecx
mov eax, [ebp+NTFS.cur_attr]
.scanlist:
cmp esi, [esp]
jae .scanlistdone
cmp eax, [esi]
jz @f
.scanlistcont:
movzx ecx, word [esi+4]
add esi, ecx
jmp .scanlist
 
@@:
; ignore named $DATA attributes (aka NTFS streams)
cmp eax, 0x80
jnz @f
cmp byte [esi+6], 0
jnz .scanlistcont
@@:
push eax
mov eax, [esi+8]
test eax, eax
jnz .testf
cmp dword [ebp+NTFS.attr_size+4], -1
jnz .testfz
; if attribute is in auxiliary records, its size is defined only in first
mov eax, [esi+10h]
call ntfs_read_file_record
jc .errret_pop
mov eax, [ebp+NTFS.frs_buffer]
movzx ecx, word [eax+14h]
add eax, ecx
mov ecx, [ebp+NTFS.cur_attr]
@@:
cmp dword [eax], -1
jz .errret2_pop
cmp dword [eax], ecx
jz @f
.l1:
add eax, [eax+4]
jmp @b
 
@@:
cmp eax, 0x80
jnz @f
cmp byte [eax+9], 0
jnz .l1
@@:
cmp byte [eax+8], 0
jnz .sdnores
mov eax, [eax+10h]
mov dword [ebp+NTFS.attr_size], eax
and dword [ebp+NTFS.attr_size+4], 0
jmp .testfz
 
.sdnores:
mov ecx, [eax+30h]
mov dword [ebp+NTFS.attr_size], ecx
mov ecx, [eax+34h]
mov dword [ebp+NTFS.attr_size+4], ecx
.testfz:
xor eax, eax
.testf:
imul eax, [ebp+NTFS.sectors_per_cluster]
cmp eax, [ebp+NTFS.cur_offs]
pop eax
ja @f
mov edi, [esi+10h] ; keep previous iRecord
jmp .scanlistcont
 
@@:
pop ecx
.scanlistfound:
cmp edi, -1
jz .ret
mov eax, [ebp+NTFS.cur_iRecord]
mov [ebp+NTFS.attr_iBaseRecord], eax
mov eax, edi
jmp .beginfindattr
 
.scanlistdone:
pop ecx
sub ecx, ebp
sub ecx, NTFS.attrlist_buf-1Ah
cmp [ebp+NTFS.cur_iRecord], 0
jnz @f
sub ecx, NTFS.attrlist_mft_buf-NTFS.attrlist_buf
@@:
cmp ecx, 0x400
jnz .scanlistfound
inc edx
push esi edi
lea esi, [ebp+NTFS.attrlist_buf+0x200]
lea edi, [ebp+NTFS.attrlist_buf]
cmp [ebp+NTFS.cur_iRecord], 0
jnz @f
lea esi, [ebp+NTFS.attrlist_mft_buf+0x200]
lea edi, [ebp+NTFS.attrlist_mft_buf]
@@:
mov ecx, 0x200/4
rep movsd
mov eax, edi
pop edi esi
sub esi, 0x200
push [ebp+NTFS.cur_offs]
push [ebp+NTFS.cur_size]
push [ebp+NTFS.cur_read]
push [ebp+NTFS.cur_buf]
push dword [ebp+NTFS.attr_size]
push dword [ebp+NTFS.attr_size+4]
or dword [ebp+NTFS.attr_size+4], -1
mov [ebp+NTFS.cur_offs], edx
mov [ebp+NTFS.cur_size], 1
and [ebp+NTFS.cur_read], 0
mov [ebp+NTFS.cur_buf], eax
mov ecx, [ebp+NTFS.attr_list]
push esi edx edi
call .doreadattr
pop edi edx esi
mov ecx, [ebp+NTFS.cur_read]
pop dword [ebp+NTFS.attr_size+4]
pop dword [ebp+NTFS.attr_size]
pop [ebp+NTFS.cur_buf]
pop [ebp+NTFS.cur_read]
pop [ebp+NTFS.cur_size]
pop [ebp+NTFS.cur_offs]
jc .errret
lea ecx, [ecx+ebp+NTFS.attrlist_buf+0x200-0x1A]
cmp [ebp+NTFS.cur_iRecord], 0
jnz .scanliststart
add ecx, NTFS.attrlist_mft_buf-NTFS.attrlist_buf
jmp .scanliststart
 
.doreadattr:
mov [ebp+NTFS.bCanContinue], 0
cmp byte [ecx+nonResidentFlag], 0
jnz .nonresident
mov eax, [ecx+sizeWithoutHeader]
mov esi, eax
mov edx, [ebp+NTFS.cur_offs]
shr eax, 9
cmp eax, edx
jb .okret
shl edx, 9
sub esi, edx
movzx eax, word [ecx+attributeOffset]
add edx, eax
add edx, ecx ; edx -> data
mov eax, [ebp+NTFS.cur_size]
cmp eax, (0xFFFFFFFF shr 9)+1
jbe @f
mov eax, (0xFFFFFFFF shr 9)+1
@@:
shl eax, 9
cmp eax, esi
jbe @f
mov eax, esi
@@:
; eax = length, edx -> data
mov [ebp+NTFS.cur_read], eax
mov ecx, eax
mov eax, edx
mov ebx, [ebp+NTFS.cur_buf]
call memmove
and [ebp+NTFS.cur_size], 0 ; CF=0
ret
 
.nonresident:
; Not all auxiliary records contain correct FileSize info
mov eax, dword [ebp+NTFS.attr_size]
mov edx, dword [ebp+NTFS.attr_size+4]
cmp edx, -1
jnz @f
mov eax, [ecx+attributeRealSize]
mov edx, [ecx+attributeRealSize+4]
mov dword [ebp+NTFS.attr_size], eax
mov dword [ebp+NTFS.attr_size+4], edx
@@:
add eax, 0x1FF
adc edx, 0
shrd eax, edx, 9
sub eax, [ebp+NTFS.cur_offs]
ja @f
; return with nothing read
and [ebp+NTFS.cur_size], 0
.okret:
clc
ret
 
@@:
; reduce read length
and [ebp+NTFS.cur_tail], 0
cmp [ebp+NTFS.cur_size], eax
jb @f
mov [ebp+NTFS.cur_size], eax
mov eax, dword [ebp+NTFS.attr_size]
and eax, 0x1FF
mov [ebp+NTFS.cur_tail], eax
@@:
mov eax, [ebp+NTFS.cur_offs]
xor edx, edx
div [ebp+NTFS.sectors_per_cluster]
sub eax, [ecx+firstVCN]
jb .okret
mov ebx, edx
; eax = starting cluster, ebx = sector in the cluster
cmp [ebp+NTFS.cur_attr], 0x80
jnz .sys
cmp [ebp+NTFS.cur_iRecord], 0
jz .sys
push fs_read64_app
cmp [ebp+NTFS.bWriteAttr], 1
jnz @f
mov dword[esp], fs_write64_app
jmp @f
 
.sys:
push fs_read64_sys
@@:
sub esp, 10h
movzx esi, word [ecx+dataRunsOffset]
add esi, ecx
xor edi, edi
mov [ebp+NTFS.fragmentCount], 0
.readloop:
call ntfs_decode_mcb_entry
jnc .break
add edi, [esp+8]
sub eax, [esp]
jae .readloop
mov ecx, edi
add ecx, eax
add ecx, [esp]
neg eax
mul [ebp+NTFS.sectors_per_cluster]
xchg eax, ecx
mul [ebp+NTFS.sectors_per_cluster]
sub ecx, ebx
add eax, ebx
mov ebx, [ebp+NTFS.cur_buf]
cmp ecx, [ebp+NTFS.cur_size]
jb @f
mov ecx, [ebp+NTFS.cur_size]
@@:
mov [ebp+NTFS.LastRead], eax
push ecx
call dword[esp+14h]
pop ecx
test eax, eax
jnz .errread2
sub [ebp+NTFS.cur_size], ecx
add [ebp+NTFS.cur_offs], ecx
shl ecx, 9
add [ebp+NTFS.cur_read], ecx
add [ebp+NTFS.cur_buf], ecx
inc [ebp+NTFS.fragmentCount]
xor eax, eax
xor ebx, ebx
cmp [ebp+NTFS.cur_size], 0
jnz .readloop
add esp, 14h
mov eax, [ebp+NTFS.cur_tail]
test eax, eax
jz @f
sub eax, 0x200
add [ebp+NTFS.cur_read], eax
@@:
clc
ret
 
.errread2:
add esp, 14h
stc
ret
 
.break:
add esp, 14h ; CF=0
mov [ebp+NTFS.bCanContinue], 1
ret
 
ntfs_read_file_record:
; in: eax = iRecord
; out: [ebp+NTFS.frs_buffer] -> file record
; CF=1 -> failed, eax = disk error code, eax=0 -> something with FS
; Read attr $DATA of $Mft, starting from eax*[ebp+NTFS.frs_size]
push ecx edx
mov ecx, [ebp+NTFS.frs_size]
mul ecx
shrd eax, edx, 9
shr edx, 9
jnz .errret
push [ebp+NTFS.attr_iBaseRecord]
push [ebp+NTFS.attr_offs]
push [ebp+NTFS.attr_list]
push dword [ebp+NTFS.attr_size+4]
push dword [ebp+NTFS.attr_size]
push [ebp+NTFS.cur_iRecord]
push [ebp+NTFS.cur_attr]
push [ebp+NTFS.cur_offs]
push [ebp+NTFS.cur_size]
push [ebp+NTFS.cur_buf]
push [ebp+NTFS.cur_read]
mov [ebp+NTFS.cur_attr], 0x80 ; $DATA
and [ebp+NTFS.cur_iRecord], 0 ; $Mft
mov [ebp+NTFS.cur_offs], eax
shr ecx, 9
mov [ebp+NTFS.cur_size], ecx
mov eax, [ebp+NTFS.frs_buffer]
mov [ebp+NTFS.cur_buf], eax
call ntfs_read_attr
mov edx, [ebp+NTFS.cur_read]
pop [ebp+NTFS.cur_read]
pop [ebp+NTFS.cur_buf]
pop [ebp+NTFS.cur_size]
pop [ebp+NTFS.cur_offs]
pop [ebp+NTFS.cur_attr]
pop [ebp+NTFS.cur_iRecord]
pop dword [ebp+NTFS.attr_size]
pop dword [ebp+NTFS.attr_size+4]
pop [ebp+NTFS.attr_list]
pop [ebp+NTFS.attr_offs]
pop [ebp+NTFS.attr_iBaseRecord]
jc .ret
cmp edx, [ebp+NTFS.frs_size]
jnz .errret
mov eax, [ebp+NTFS.LastRead]
mov [ebp+NTFS.mftLastRead], eax
mov eax, [ebp+NTFS.frs_buffer]
cmp dword [eax], 'FILE'
jnz .errret
push ebx
mov ebx, eax
call ntfs_restore_usa_frs
pop ebx
jc .errret
.ret:
pop edx ecx
ret
 
.errret:
pop edx ecx
xor eax, eax
stc
ret
 
ntfs_restore_usa_frs:
mov eax, [ebp+NTFS.frs_size]
ntfs_restore_usa:
; in:
; ebx -> record
; eax = size in bytes
pushad
shr eax, 9
mov ecx, eax
inc eax
cmp [ebx+updateSequenceSize], ax
jnz .err
movzx eax, word [ebx+updateSequenceOffset]
lea esi, [eax+ebx]
lodsw
mov edx, eax
lea edi, [ebx+0x1FE]
@@:
cmp [edi], dx
jnz .err
lodsw
stosw
add edi, 0x1FE
loop @b
popad
clc
ret
 
.err:
popad
stc
ret
 
ntfs_decode_mcb_entry:
; in:
; esi -> MCB entry
; esp -> buffer (16 bytes)
; out:
; esi -> next MCB entry
; esp -> data run size
; esp+8 -> cluster (delta)
; CF=0 -> MCB end
push eax ecx edi
lea edi, [esp+16]
xor eax, eax
lodsb
test al, al
jz .end
mov ecx, eax
and ecx, 0xF
cmp ecx, 8
ja .end
push ecx
rep movsb
pop ecx
sub ecx, 8
neg ecx
cmp byte [esi-1], 80h
jae .end
push eax
xor eax, eax
rep stosb
pop ecx
shr ecx, 4
cmp ecx, 8
ja .end
push ecx
rep movsb
pop ecx
sub ecx, 8
neg ecx
cmp byte [esi-1], 80h
cmc
sbb eax, eax
rep stosb
stc
.end:
pop edi ecx eax
ret
 
ntfs_find_lfn:
; in: esi -> path string in UTF-8
; out:
; [ebp+NTFS.cur_iRecord] = target fileRecord
; eax -> target index in the node
; [ebp+NTFS.LastRead] = target node location
; [ebp+NTFS.indexPointer] -> index, that points the target subnode
; [ebp+NTFS.nodeLastRead] = branch node location
; [ebp+NTFS.indexRoot] -> attribute
; [ebp+NTFS.rootLastRead] = directory fileRecord location
; [ebp+NTFS.cur_size] = index record size in sectors
; [ebp+NTFS.cur_subnode_size] = index record size in clusters or sectors
; CF=1 -> file not found, eax=0 -> error
mov [ebp+NTFS.cur_iRecord], 5 ; start from root directory
.doit2:
mov [ebp+NTFS.cur_attr], 0x90 ; $INDEX_ROOT
and [ebp+NTFS.cur_offs], 0
mov eax, [ebp+NTFS.cur_index_size]
mov [ebp+NTFS.cur_size], eax
mov eax, [ebp+NTFS.cur_index_buf]
mov [ebp+NTFS.cur_buf], eax
call ntfs_read_attr
mov eax, 0
jc .ret
cmp [ebp+NTFS.cur_read], 0x20
jc .ret
push esi
pushad
mov esi, [ebp+NTFS.cur_index_buf]
mov eax, [esi+indexRecordSize]
shr eax, 9
cmp [ebp+NTFS.cur_index_size], eax
jc .realloc
mov [ebp+NTFS.cur_size], eax
mov al, [esi+indexRecordSizeClus]
mov [ebp+NTFS.cur_subnode_size], eax
add esi, rootNode
mov eax, [esi+nodeRealSize]
add eax, rootNode
cmp [ebp+NTFS.cur_read], eax
jc .err
mov eax, [ebp+NTFS.mftLastRead]
mov [ebp+NTFS.rootLastRead], eax
mov eax, [ebp+NTFS.attr_offs]
mov [ebp+NTFS.indexRoot], eax
.scanloop: ; esi -> current index node
add esi, [esi+indexOffset]
.scanloopint:
push esi
test byte [esi+indexFlags], 2
jnz .subnode
movzx ecx, byte [esi+fileNameLength]
lea edi, [esi+fileName]
mov esi, [esp+8]
@@:
call utf8to16
cmp ax, '/'
jz .subnode
call utf16toUpper
push eax
mov ax, [edi]
call utf16toUpper
cmp [esp], ax
pop eax
jc .subnode
jnz .scanloopcont
add edi, 2
loop @b
call utf8to16
cmp ax, '/'
jz .found
test ax, ax
jz .found
.scanloopcont:
pop esi
movzx eax, word [esi+indexAllocatedSize]
add esi, eax
jmp .scanloopint
 
.realloc:
mov edi, eax
mov eax, [esi+indexRecordSize]
shl eax, 1
stdcall kernel_alloc, eax
test eax, eax
jz .err
mov edx, [ebp+NTFS.cur_index_buf]
cmp edx, [ebp+NTFS.secondIndexBuffer]
jc @f
mov edx, [ebp+NTFS.secondIndexBuffer]
@@:
mov [ebp+NTFS.cur_index_buf], eax
add eax, [esi+indexRecordSize]
mov [ebp+NTFS.secondIndexBuffer], eax
mov [ebp+NTFS.cur_index_size], edi
stdcall kernel_free, edx
popad
pop eax
jmp .doit2
 
.notfound:
mov [esp+28], esi
.err:
popad
stc
.ret2:
pop esi
.ret:
ret
 
.subnode:
pop esi
test byte [esi+indexFlags], 1
jz .notfound
mov eax, [ebp+NTFS.LastRead]
mov [ebp+NTFS.nodeLastRead], eax
mov [ebp+NTFS.indexPointer], esi
movzx eax, word [esi+indexAllocatedSize]
mov eax, [esi+eax-8]
mov edx, [ebp+NTFS.cur_size]
push edx
cmp edx, [ebp+NTFS.cur_subnode_size]
jz @f
mul [ebp+NTFS.sectors_per_cluster]
@@:
mov esi, [ebp+NTFS.cur_index_buf]
xchg [ebp+NTFS.secondIndexBuffer], esi
mov [ebp+NTFS.cur_index_buf], esi
mov [ebp+NTFS.cur_buf], esi
mov [ebp+NTFS.cur_attr], 0xA0 ; $INDEX_ALLOCATION
mov [ebp+NTFS.cur_offs], eax
call ntfs_read_attr.newAttribute
pop eax
mov [ebp+NTFS.cur_size], eax
shl eax, 9
cmp [ebp+NTFS.cur_read], eax
jnz .err
cmp dword [esi], 'INDX'
jnz .err
mov ebx, esi
call ntfs_restore_usa
jc .err
add esi, recordNode
jmp .scanloop
 
.found:
mov [esp+8], esi
pop eax
mov [esp+28], eax
mov eax, [eax+fileRecordReference]
mov [ebp+NTFS.cur_iRecord], eax
popad
cmp byte [esi-1], 0
jz .ret2
pop eax
jmp .doit2
 
;----------------------------------------------------------------
ntfs_ReadFile:
call ntfs_lock
call ntfs_find_lfn
jc ntfsNotFound
mov [ebp+NTFS.cur_attr], 0x80 ; $DATA
and [ebp+NTFS.cur_offs], 0
and [ebp+NTFS.cur_size], 0
call ntfs_read_attr
jc ntfsDenied
xor eax, eax
push eax
cmp dword [ebx+8], 0x200
jnc .eof
mov ecx, [ebx+12]
mov edx, [ebx+16]
mov eax, [ebx+4]
test eax, 0x1FF
jz .alignedstart
push edx
mov edx, [ebx+8]
shrd eax, edx, 9
pop edx
mov [ebp+NTFS.cur_offs], eax
mov [ebp+NTFS.cur_size], 1
lea eax, [ebp+NTFS.bitmap_buf]
mov [ebp+NTFS.cur_buf], eax
call ntfs_read_attr.continue
mov eax, [ebx+4]
and eax, 0x1FF
lea esi, [ebp+NTFS.bitmap_buf+eax]
sub eax, [ebp+NTFS.cur_read]
jae .eof
neg eax
push ecx
cmp ecx, eax
jb @f
mov ecx, eax
@@:
mov [esp+4], ecx
mov edi, edx
rep movsb
mov edx, edi
pop ecx
sub ecx, [esp]
jz .retok
cmp [ebp+NTFS.cur_read], 0x200
jnz .eof
.alignedstart:
mov eax, [ebx+4]
push edx
mov edx, [ebx+8]
add eax, 511
adc edx, 0
shrd eax, edx, 9
pop edx
mov [ebp+NTFS.cur_offs], eax
mov [ebp+NTFS.cur_buf], edx
mov eax, ecx
shr eax, 9
mov [ebp+NTFS.cur_size], eax
add eax, [ebp+NTFS.cur_offs]
push eax
call ntfs_read_attr.continue
pop [ebp+NTFS.cur_offs]
mov eax, [ebp+NTFS.cur_read]
add [esp], eax
mov eax, ecx
and eax, not 0x1FF
cmp [ebp+NTFS.cur_read], eax
jnz .eof
and ecx, 0x1FF
jz .retok
add edx, [ebp+NTFS.cur_read]
mov [ebp+NTFS.cur_size], 1
lea eax, [ebp+NTFS.bitmap_buf]
mov [ebp+NTFS.cur_buf], eax
call ntfs_read_attr.continue
cmp [ebp+NTFS.cur_read], ecx
jb @f
mov [ebp+NTFS.cur_read], ecx
@@:
xchg ecx, [ebp+NTFS.cur_read]
push ecx
mov edi, edx
lea esi, [ebp+NTFS.bitmap_buf]
add [esp+4], ecx
rep movsb
pop ecx
cmp ecx, [ebp+NTFS.cur_read]
jnz .eof
.retok:
pushd 0
.ret:
call ntfs_unlock
pop eax ebx
ret
 
.eof:
push ERROR_END_OF_FILE
jmp .ret
 
;----------------------------------------------------------------
ntfs_ReadFolder:
call ntfs_lock
mov [ebp+NTFS.cur_iRecord], 5 ; root directory
cmp byte [esi], 0
jz @f
call ntfs_find_lfn
jc ntfsNotFound
@@:
mov [ebp+NTFS.cur_attr], 0x10 ; $STANDARD_INFORMATION
and [ebp+NTFS.cur_offs], 0
mov [ebp+NTFS.cur_size], 1
lea eax, [ebp+NTFS.bitmap_buf]
mov [ebp+NTFS.cur_buf], eax
call ntfs_read_attr
jc ntfsFail
mov [ebp+NTFS.cur_attr], 0x90 ; $INDEX_ROOT
.doit:
mov eax, [ebp+NTFS.cur_index_size]
mov [ebp+NTFS.cur_size], eax
mov eax, [ebp+NTFS.cur_index_buf]
mov [ebp+NTFS.cur_buf], eax
call ntfs_read_attr.newAttribute
jc ntfsFail
cmp [ebp+NTFS.cur_read], 0x20
jc ntfsFail
mov esi, [ebp+NTFS.cur_index_buf]
mov eax, [esi+indexRecordSize]
shr eax, 9
cmp [ebp+NTFS.cur_index_size], eax
jc .realloc
mov [ebp+NTFS.cur_subnode_size], eax
add esi, rootNode
mov eax, [esi+nodeRealSize]
add eax, rootNode
cmp [ebp+NTFS.cur_read], eax
jc ntfsFail
mov edi, [ebx+16]
mov ecx, [ebx+12]
pushd [ebx]
pushd [ebx+8] ; read ANSI/UNICODE name
push edi
mov edx, esp
mov ebx, [ebx+4]
; init header
xor eax, eax
mov [edi+8], eax
mov [edi+4], eax
inc eax
mov [edi], eax ; version
add edi, 32
; edi -> BDFE, esi -> current index data, ebx = first wanted block,
; ecx = number of blocks to read
; edx -> parameters block: dd <output>, dd <flags>
cmp [ebp+NTFS.cur_iRecord], 5
jz .skip_specials
; dot and dotdot entries
push esi
xor esi, esi
call .add_special_entry
inc esi
call .add_special_entry
pop esi
.skip_specials:
; at first, dump index root
add esi, [esi+indexOffset]
.dump_root:
test byte [esi+indexFlags], 2
jnz .dump_root_done
call .add_entry
movzx eax, word [esi+indexAllocatedSize]
add esi, eax
jmp .dump_root
 
.realloc:
mov edi, eax
mov eax, [esi+indexRecordSize]
shl eax, 1
stdcall kernel_alloc, eax
test eax, eax
jz ntfsFail
mov edx, [ebp+NTFS.cur_index_buf]
cmp edx, [ebp+NTFS.secondIndexBuffer]
jc @f
mov edx, [ebp+NTFS.secondIndexBuffer]
@@:
mov [ebp+NTFS.cur_index_buf], eax
add eax, [esi+indexRecordSize]
mov [ebp+NTFS.secondIndexBuffer], eax
mov [ebp+NTFS.cur_index_size], edi
stdcall kernel_free, edx
jmp .doit
 
.dump_root_done:
; now dump all subnodes
push ecx edi
lea edi, [ebp+NTFS.bitmap_buf]
mov [ebp+NTFS.cur_buf], edi
mov ecx, 0x400/4
xor eax, eax
rep stosd
mov [ebp+NTFS.cur_attr], 0xB0 ; $BITMAP
and [ebp+NTFS.cur_offs], 0
mov [ebp+NTFS.cur_size], 2
call ntfs_read_attr.newAttribute
pop edi ecx
push 0 ; save offset in $BITMAP attribute
and [ebp+NTFS.cur_offs], 0
.dumploop:
mov [ebp+NTFS.cur_attr], 0xA0
mov eax, [ebp+NTFS.cur_subnode_size]
mov [ebp+NTFS.cur_size], eax
mov esi, [ebp+NTFS.cur_index_buf]
mov [ebp+NTFS.cur_buf], esi
mov eax, [ebp+NTFS.cur_offs]
push eax
imul eax, [ebp+NTFS.cur_subnode_size]
mov [ebp+NTFS.cur_offs], eax
call ntfs_read_attr.newAttribute
pop [ebp+NTFS.cur_offs]
mov eax, [ebp+NTFS.cur_subnode_size]
shl eax, 9
cmp [ebp+NTFS.cur_read], eax
jnz .done
push eax
mov eax, [ebp+NTFS.cur_offs]
and eax, 0x400*8-1
bt dword [ebp+NTFS.bitmap_buf], eax
pop eax
jnc .dump_subnode_done
cmp dword [esi], 'INDX'
jnz .dump_subnode_done
push ebx
mov ebx, esi
call ntfs_restore_usa
pop ebx
jc .dump_subnode_done
add esi, recordNode
add esi, [esi+indexOffset]
.dump_subnode:
test byte [esi+indexFlags], 2
jnz .dump_subnode_done
call .add_entry
movzx eax, word [esi+indexAllocatedSize]
add esi, eax
jmp .dump_subnode
 
.dump_subnode_done:
inc [ebp+NTFS.cur_offs]
test [ebp+NTFS.cur_offs], 0x400*8-1
jnz .dumploop
mov [ebp+NTFS.cur_attr], 0xB0
push ecx edi
lea edi, [ebp+NTFS.bitmap_buf]
mov [ebp+NTFS.cur_buf], edi
mov ecx, 0x400/4
xor eax, eax
rep stosd
pop edi ecx
pop eax
push [ebp+NTFS.cur_offs]
inc eax
mov [ebp+NTFS.cur_offs], eax
mov [ebp+NTFS.cur_size], 2
push eax
call ntfs_read_attr.newAttribute
pop eax
pop [ebp+NTFS.cur_offs]
push eax
jmp .dumploop
 
.done:
pop eax
pop eax
mov ebx, [eax+4]
pop eax
pop eax
test eax, eax
jz .ret
xor eax, eax
dec ecx
js @f
mov al, ERROR_END_OF_FILE
@@:
push eax
call ntfs_unlock
pop eax
ret
 
.add_special_entry:
mov eax, [edx]
inc dword [eax+8] ; new file found
dec ebx
jns .ret
dec ecx
js .ret
inc dword [eax+4] ; new file block copied
mov eax, [edx+4]
mov [edi+4], eax
mov eax, 0x10
stosd
scasd
push ebx ecx edx
mov eax, dword [ebp+NTFS.bitmap_buf]
mov edx, dword [ebp+NTFS.bitmap_buf+4]
call ntfs_datetime_to_bdfe
mov eax, dword [ebp+NTFS.bitmap_buf+0x18]
mov edx, dword [ebp+NTFS.bitmap_buf+0x1C]
call ntfs_datetime_to_bdfe
mov eax, dword [ebp+NTFS.bitmap_buf+8]
mov edx, dword [ebp+NTFS.bitmap_buf+0xC]
call ntfs_datetime_to_bdfe
pop edx ecx ebx
xor eax, eax
stosd
stosd
mov al, '.'
push edi ecx
lea ecx, [esi+1]
cmp dword[edi-36], 2
jz .utf16sp
rep stosb
mov byte [edi], 0
pop ecx edi
cmp dword[edi-36], 3
jz @f
add edi, 264
ret
 
.utf16sp:
rep stosw
mov word [edi], 0
pop ecx edi
@@:
add edi, 520
.ret:
ret
 
.add_entry:
; do not return DOS 8.3 names
cmp byte [esi+namespace], 2
jz .ret
; do not return system files
cmp dword[esi+fileRecordReference], 16
jb .ret
cmp byte [esi+fileNameLength], 0
jz .ret
mov eax, [edx]
inc dword [eax+8] ; new file found
dec ebx
jns .ret
dec ecx
js .ret
inc dword [eax+4] ; new file block copied
mov eax, [edx+4] ; flags
call ntfs_direntry_to_bdfe
push ecx esi edi
movzx ecx, byte [esi+fileNameLength]
add esi, fileName
cmp dword[edi-36], 2
jz .utf16
cmp dword[edi-36], 3
jz .utf8
@@:
lodsw
call uni2ansi_char
stosb
loop @b
mov byte [edi], 0
pop edi esi ecx
add edi, 264
ret
 
.utf8:
push ecx
mov cx, 519
@@:
lodsw
call UTF16to8
js @f
dec dword[esp]
jnz @b
@@:
mov byte [edi], 0
pop edi
@@:
pop edi esi ecx
add edi, 520
ret
 
.utf16:
rep movsw
mov word [edi], 0
jmp @b
 
ntfs_direntry_to_bdfe:
mov [edi+4], eax ; ANSI/UNICODE name
mov eax, [esi+fileFlags]
test eax, 0x10000000
jz @f
and eax, not 0x10000000
or al, 0x10
@@:
stosd
scasd
push ebx ecx edx
mov eax, [esi+fileCreated]
mov edx, [esi+fileCreated+4]
call ntfs_datetime_to_bdfe
mov eax, [esi+fileAccessed]
mov edx, [esi+fileAccessed+4]
call ntfs_datetime_to_bdfe
mov eax, [esi+fileModified]
mov edx, [esi+fileModified+4]
call ntfs_datetime_to_bdfe
pop edx ecx ebx
mov eax, [esi+fileRealSize]
stosd
mov eax, [esi+fileRealSize+4]
stosd
ret
 
ntfs_datetime_to_bdfe:
; in: edx:eax = seconds since 01.01.1601 x10000000
; edi -> data block
; out: edi = edi+8
sub eax, 3365781504
sbb edx, 29389701
mov ecx, 10000000
cmp edx, ecx
jc @f
xor edx, edx
@@:
div ecx
jmp fsTime2bdfe
 
;----------------------------------------------------------------
ntfs_GetFileInfo:
mov edi, [ebx+16]
cmp byte [esi], 0
jz .volume
call ntfs_lock
call ntfs_find_lfn
jnc .found
test eax, eax
jz ntfsFail
jmp ntfsNotFound
 
.found:
mov esi, eax
xor eax, eax
call ntfs_direntry_to_bdfe
.end:
call ntfs_unlock
xor eax, eax
@@:
ret
 
.volume:
mov eax, dword [ebp+NTFS.Length]
mov edx, dword [ebp+NTFS.Length+4]
shld edx, eax, 9
shl eax, 9
mov [edi+36], edx
mov [edi+32], eax
mov eax, [ebx+8]
mov byte [edi], 8
mov [edi+4], eax
test eax, eax
jz @b
call ntfs_lock
add edi, 40
mov [ebp+NTFS.cur_buf], edi
mov [ebp+NTFS.cur_iRecord], 3
mov [ebp+NTFS.cur_attr], 0x60
mov [ebp+NTFS.cur_offs], 0
mov [ebp+NTFS.cur_size], 1
call ntfs_read_attr
jc ntfsFail
mov ecx, [ebp+NTFS.cur_read]
mov [edi+ecx], ax
cmp byte [ebx+8], 2
jz .end
shr ecx, 1
jz .end
mov esi, edi
cmp byte [ebx+8], 3
jnz @f
shl ecx, 1
call UTF16to8_string
mov byte [edi], 0
jmp .end
 
@@:
lodsw
call uni2ansi_char
stosb
loop @b
mov byte [edi], 0
jmp .end
 
;----------------------------------------------------------------
ntfs_CreateFolder:
mov [ebp+NTFS.bFolder], 1
jmp @f
 
ntfs_CreateFile:
mov [ebp+NTFS.bFolder], 0
@@: ; 1. Search file
call ntfs_lock
call ntfs_find_lfn
jc .notFound
; found, rewrite
cmp [ebp+NTFS.cur_iRecord], 16
jc ntfsDenied
cmp [ebp+NTFS.bFolder], 1
jz .folder
test byte [eax+fileFlags], 1
jnz ntfsDenied
cmp [ebp+NTFS.fragmentCount], 1
jnz ntfsUnsupported ; record fragmented
; edit directory node
mov edi, [ebp+NTFS.cur_index_buf]
cmp dword [edi], 'INDX'
jz @f
mov esi, [ebp+NTFS.frs_buffer]
mov ecx, [esi+recordRealSize]
shr ecx, 2
rep movsd
mov esi, [ebp+NTFS.attr_offs]
mov cl, [esi+attributeOffset]
sub esi, [ebp+NTFS.frs_buffer]
add eax, ecx
add eax, esi
@@:
mov edi, eax
mov eax, [ebx+12]
mov [edi+fileRealSize], eax
mov dword [edi+fileRealSize+4], 0
push ebx eax
call ntfsGetTime
mov [edi+fileModified], eax
mov [edi+fileModified+4], edx
mov [edi+recordModified], eax
mov [edi+recordModified+4], edx
mov [edi+fileAccessed], eax
mov [edi+fileAccessed+4], edx
pop edx ebx
mov eax, [ebp+NTFS.LastRead]
mov [ebp+NTFS.nodeLastRead], eax
mov [ebp+NTFS.cur_attr], 0x80
mov [ebp+NTFS.cur_offs], 0
mov [ebp+NTFS.cur_size], 0
call ntfs_read_attr
jc ntfsFail
mov esi, edi
mov edi, [ebp+NTFS.frs_buffer]
cmp word [edi+baseRecordReuse], 0
jnz ntfsUnsupported ; auxiliary record
mov al, [edi+attributeOffset]
add edi, eax
mov al, [edi+attributeOffset]
add edi, eax
mov ecx, 6
add esi, fileModified
add edi, 8
rep movsd
mov eax, edx
xor edx, edx
mov ecx, [ebp+NTFS.attr_offs]
cmp word [ecx+attributeFlags], 0
jnz ntfsUnsupported
push ebx
cmp byte [ecx+nonResidentFlag], 0
jz @f
cmp [ecx+attributeRealSize+4], edx
jnz @f
cmp [ecx+attributeRealSize], eax
jz ntfs_WriteFile.writeNode
@@:
jmp ntfs_WriteFile.resizeAttribute
 
.folder:
bt dword [eax+fileFlags], 28
jnc ntfsDenied
push 0
jmp ntfsOut
 
.notFound: ; create
test eax, eax
jz ntfsFail
cmp [ebp+NTFS.fragmentCount], 1
jnz ntfsUnsupported ; record fragmented
; 2. Prepare directory record
mov edi, esi
mov edx, eax
xor ecx, ecx
@@: ; count characters
call utf8to16
cmp ax, '/'
jz ntfsNotFound ; path folder not found
inc ecx
test ax, ax
jnz @b
dec ecx
push ecx ; name length in chars
push edi
shl ecx, 1
add ecx, fileName+7
and ecx, not 7
mov edi, [ebp+NTFS.cur_index_buf]
mov eax, [ebx+12]
mov [ebp+NTFS.fileRealSize], eax
mov eax, [ebx+16]
mov [ebp+NTFS.fileDataBuffer], eax
push ecx ; index length
mov eax, edx
mov edx, ecx
cmp dword [edi], 'INDX'
jz .indexRecord
mov esi, [ebp+NTFS.frs_buffer] ; indexRoot
mov ecx, [esi+recordRealSize]
add edx, ecx
cmp [esi+recordAllocatedSize], edx
jc .growTree
mov [esi+recordRealSize], edx
shr ecx, 2
rep movsd
mov edi, [ebp+NTFS.indexRoot]
sub edi, [ebp+NTFS.frs_buffer]
add edi, [ebp+NTFS.cur_index_buf]
mov esi, [esp]
add [edi+sizeWithHeader], esi
add [edi+sizeWithoutHeader], esi
mov cl, [edi+attributeOffset]
add edi, ecx
add [edi+rootNode+nodeRealSize], esi
add [edi+rootNode+nodeAllocatedSize], esi
sub eax, [ebp+NTFS.cur_index_buf]
add eax, edi
mov edi, [ebp+NTFS.cur_index_buf]
jmp .common
 
.growTree: ; create indexRecord
mov edi, [ebp+NTFS.cur_index_buf]
mov ecx, 10
xor eax, eax
rep stosd
mov esi, [ebp+NTFS.indexRoot]
mov al, [esi+attributeOffset]
add esi, eax
rdtsc
stosw
mov eax, [esi+indexRecordSize]
cmp eax, [ebp+NTFS.frs_size]
jc .errorPop3
shr eax, 9
inc eax
mov edi, [ebp+NTFS.cur_index_buf]
mov dword[edi], 'INDX'
mov byte [edi+updateSequenceOffset], 28h
mov [edi+updateSequenceSize], al
add edi, recordNode
shl eax, 1
add eax, 28h-recordNode+7
and eax, not 7
mov [edi+indexOffset], eax
mov ecx, [esi+indexRecordSize]
sub ecx, recordNode
mov [edi+nodeAllocatedSize], ecx
add esi, rootNode
push esi
mov ecx, [esi+nodeRealSize]
sub ecx, [esi+indexOffset]
add eax, ecx
mov [edi+nodeRealSize], eax
mov eax, [esi+nonLeafFlag]
mov [edi+nonLeafFlag], eax
shr ecx, 2
add esi, [esi+indexOffset]
add edi, [edi+indexOffset]
rep movsd ; copy root indexes
; clear root node
mov cl, 10
mov edi, [esp]
xor eax, eax
rep stosd
pop edi
mov byte [edi+indexOffset], 16
mov byte [edi+nodeRealSize], 28h
mov byte [edi+nodeAllocatedSize], 28h
mov byte [edi+nonLeafFlag], 1
mov byte [edi+16+indexAllocatedSize], 18h
mov byte [edi+16+indexFlags], 3
mov esi, [ebp+NTFS.indexRoot]
add edi, 28h
mov eax, edi
sub eax, esi
mov word [esi+sizeWithoutHeader], 38h
xchg [esi+sizeWithHeader], eax
add esi, eax
mov [ebp+NTFS.attr_offs], edi
cmp byte [esi], 0xA0
jnz @f
cmp dword [esi+attributeAllocatedSize], 0
jz @f
mov eax, [ebp+NTFS.frs_buffer]
mov ecx, eax
add ecx, [eax+recordRealSize]
sub ecx, esi
shr ecx, 2
rep movsd
sub edi, eax
mov [eax+recordRealSize], edi
call .ntfsNodeAlloc
jc ntfsErrorPop3
mov eax, [ebp+NTFS.newRecord]
mov edi, [ebp+NTFS.cur_index_buf]
mov [edi+recordVCN], eax
mov edi, [ebp+NTFS.attr_offs]
mov [edi-8], eax
jmp .refresh
 
@@:
mov cl, 32
xor eax, eax
rep stosd
mov eax, [ebp+NTFS.cur_subnode_size]
cmp eax, [ebp+NTFS.cur_size]
jnz @f
cmp [ebp+NTFS.sectors_per_cluster], 1
jz @f
mov al, 1
@@:
mov [ebp+NTFS.fileDataSize], eax
mov edi, [ebp+NTFS.BitmapStart]
call ntfsSpaceAlloc
movi eax, ERROR_DISK_FULL
jc ntfsErrorPop3
; create $IndexAllocation
mov edi, [ebp+NTFS.attr_offs]
mov byte [edi+attributeType], 0xA0
mov byte [edi+nonResidentFlag], 1
mov byte [edi+nameLength], 4
mov byte [edi+nameOffset], 40h
mov byte [edi+dataRunsOffset], 48h
mov byte [edi+sizeWithHeader], 50h
mov eax, [ebp+NTFS.fileDataSize]
dec eax
mov [edi+lastVCN], eax
inc eax
mul [ebp+NTFS.sectors_per_cluster]
shl eax, 9
mov [edi+attributeAllocatedSize], eax
mov [edi+attributeRealSize], eax
mov [edi+initialDataSize], eax
mov dword[edi+40h], 490024h ; unicode $I30
mov dword[edi+40h+4], 300033h
push edi
mov esi, edi
add edi, 48h
call createMcbEntry
mov esi, [ebp+NTFS.frs_buffer]
pop edi
mov al, [esi+newAttributeID]
mov [edi+attributeID], al
add edi, 50h
inc eax
; create $Bitmap
mov [edi+attributeID], al
inc eax
mov [esi+newAttributeID], al
mov byte [edi+attributeType], 0xB0
mov byte [edi+nameLength], 4
mov byte [edi+nameOffset], 18h
mov byte [edi+attributeOffset], 20h
mov byte [edi+sizeWithoutHeader], 8
mov byte [edi+sizeWithHeader], 28h
mov dword[edi+18h], 490024h ; unicode $I30
mov dword[edi+18h+4], 300033h
mov byte [edi+20h], 1
mov dword[edi+28h], -1
add edi, 30h
sub edi, esi
mov [esi+recordRealSize], edi
mov eax, [ebp+NTFS.fileDataStart]
mul [ebp+NTFS.sectors_per_cluster]
mov edx, eax
jmp @f
 
.refresh:
mov [ebp+NTFS.cur_size], 0
call ntfs_read_attr.continue
movi eax, ERROR_FS_FAIL
jc ntfsErrorPop3
mov edx, [ebp+NTFS.LastRead]
@@:
mov ebx, [ebp+NTFS.cur_index_buf]
call writeRecord
mov ebx, [ebp+NTFS.frs_buffer]
mov edx, [ebp+NTFS.rootLastRead]
call writeRecord
mov esi, [esp+4]
call ntfs_find_lfn.doit2
test eax, eax
jz .errorPop3
mov edi, [ebp+NTFS.cur_index_buf]
mov edx, [esp]
.indexRecord:
add edi, recordNode
add edx, [edi+nodeRealSize]
cmp [edi+nodeAllocatedSize], edx
jc .arborizeTree
mov [edi+nodeRealSize], edx
jmp .common
 
.errorPop3:
add esp, 12
jmp ntfsUnsupported
 
.ntfsNodeAlloc:
; in: [ebp+NTFS.attr_offs] -> $IndexAllocation
; out:
; [ebp+NTFS.newRecord] = node VCN
; [ebp+NTFS.cur_offs]
; CF=1 -> eax = error code
mov esi, [ebp+NTFS.attr_offs]
add esi, [esi+sizeWithHeader]
cmp byte [esi], 0xB0
jnz .ret
movzx ecx, word [esi+sizeWithoutHeader]
shr ecx, 2
movzx edi, byte [esi+attributeOffset]
add edi, esi
mov edx, edi
or eax, -1
repz scasd
jnz @f
cmp [edi], eax
jnz .ret
; extend folder $Bitmap
add word [esi+sizeWithHeader], 8
add word [esi+sizeWithoutHeader], 8
mov esi, [ebp+NTFS.frs_buffer]
mov eax, [esi+recordRealSize]
add eax, 8
cmp [esi+recordAllocatedSize], eax
jc .ret
mov [esi+recordRealSize], eax
xor eax, eax
stosd
mov [edi], eax
mov [edi+8], eax
dec eax
mov [edi+4], eax
@@:
sub edi, 4
mov eax, [edi]
not eax
bsf eax, eax
bts [edi], eax
sub edi, edx
shl edi, 3
add eax, edi
mul [ebp+NTFS.cur_subnode_size]
mov [ebp+NTFS.newRecord], eax
mov ecx, [ebp+NTFS.cur_size]
cmp ecx, [ebp+NTFS.cur_subnode_size]
jz @f
mul [ebp+NTFS.sectors_per_cluster]
@@:
mov [ebp+NTFS.cur_offs], eax
add eax, ecx
shl eax, 9
mov esi, [ebp+NTFS.attr_offs]
cmp [esi+attributeAllocatedSize], eax
jnc @f
xor edx, edx
jmp resizeAttribute
 
.ret:
movi eax, ERROR_UNSUPPORTED_FS
stc
@@:
ret
 
.arborizeTree: ; find median index
mov ecx, [edi+nodeRealSize]
sub ecx, [edi+indexOffset]
shr ecx, 1
add edi, [edi+indexOffset]
xor eax, eax
@@:
add edi, eax
mov ax, [edi+indexAllocatedSize]
sub ecx, eax
jnc @b
add eax, 8
mov esi, [ebp+NTFS.secondIndexBuffer]
cmp dword [esi], 'INDX'
jz @f
; move index to the root node
mov esi, [ebp+NTFS.frs_buffer]
mov ecx, eax
add ecx, 8
add ecx, [esi+recordRealSize]
cmp [esi+recordAllocatedSize], ecx
jc .growTree
push edi eax
call .ntfsNodeAlloc
jc ntfsErrorPop5
pop eax
mov edi, [ebp+NTFS.indexRoot]
add [ebp+NTFS.attr_offs], eax
add [edi+sizeWithHeader], eax
add [edi+sizeWithoutHeader], eax
movzx ecx, byte [edi+attributeOffset]
add ecx, edi
add [ecx+rootNode+nodeRealSize], eax
add [ecx+rootNode+nodeAllocatedSize], eax
add ecx, [ebp+NTFS.indexPointer]
sub ecx, [ebp+NTFS.secondIndexBuffer]
mov esi, [ebp+NTFS.frs_buffer]
add [esi+recordRealSize], eax
add esi, [esi+recordRealSize]
mov edi, esi
sub esi, eax
neg ecx
add ecx, esi
shr ecx, 2
sub esi, 4
sub edi, 4
std
rep movsd ; make space
mov [edi], ecx
mov edi, esi
add edi, 4
mov esi, [esp]
add word [esi+indexAllocatedSize], 8
mov byte [esi+indexFlags], 1
mov ecx, eax
sub ecx, 8
shr ecx, 2
cld
rep movsd ; insert index
mov eax, [ebp+NTFS.newRecord]
stosd
jmp .splitNode
 
.growBranch: ; move node and replace it with empty one
mov esi, [ebp+NTFS.cur_index_buf]
mov edi, [ebp+NTFS.secondIndexBuffer]
mov eax, [esi+recordVCN]
mov [edi+recordVCN], eax
add edi, recordNode
mov eax, [edi+indexOffset]
add eax, 18h
mov [edi+nodeRealSize], eax
add edi, [edi+indexOffset]
mov ecx, 6
xor eax, eax
mov [ebp+NTFS.indexPointer], edi
push edi
rep stosd
pop edi
mov eax, [ebp+NTFS.newRecord]
mov byte [edi+indexAllocatedSize], 18h
mov byte [edi+indexFlags], 3
mov [edi+16], eax
mov [esi+recordVCN], eax
mov eax, [ebp+NTFS.LastRead]
mov [ebp+NTFS.nodeLastRead], eax
push [ebp+NTFS.cur_size]
mov [ebp+NTFS.cur_size], 0
call ntfs_read_attr.continue
pop [ebp+NTFS.cur_size]
movi eax, ERROR_FS_FAIL
jc ntfsErrorPop5
pop eax edi
@@: ; move index to the branch node
push edi eax
call .ntfsNodeAlloc
jc ntfsErrorPop5
mov eax, [esp]
mov esi, [ebp+NTFS.secondIndexBuffer]
add esi, recordNode
mov ecx, [esi+nodeRealSize]
add eax, ecx
cmp [esi+nodeAllocatedSize], eax
jc .growBranch
mov [esi+nodeRealSize], eax
lea edi, [esi+eax-4]
add esi, ecx
mov ecx, esi
sub ecx, [ebp+NTFS.indexPointer]
shr ecx, 2
sub esi, 4
std
rep movsd ; make space
mov [edi], ecx
pop ecx
sub ecx, 8
shr ecx, 2
mov edi, esi
add edi, 4
mov esi, [esp]
add word [esi+indexAllocatedSize], 8
mov byte [esi+indexFlags], 1
cld
rep movsd ; insert index
mov eax, [ebp+NTFS.newRecord]
stosd
mov ebx, [ebp+NTFS.secondIndexBuffer]
mov edx, [ebp+NTFS.nodeLastRead]
push esi
call writeRecord
pop esi
.splitNode:
mov edi, [ebp+NTFS.cur_index_buf]
mov eax, edi
add eax, recordNode
add eax, [edi+recordNode+nodeRealSize]
sub eax, esi
push eax
mov ecx, [edi+recordNode+indexOffset]
add eax, ecx
add ecx, recordNode
shr ecx, 2
push esi
mov esi, edi
mov edi, [ebp+NTFS.secondIndexBuffer]
rep movsd
pop esi
pop ecx
shr ecx, 2
rep movsd
mov edi, [ebp+NTFS.secondIndexBuffer]
mov [edi+recordNode+nodeRealSize], eax
pop edi
mov cl, 4
xor eax, eax
mov esi, edi
rep stosd
mov byte [esi+indexAllocatedSize], 16
mov byte [esi+indexFlags], 2
mov esi, [ebp+NTFS.cur_index_buf]
mov eax, [ebp+NTFS.newRecord]
mov [esi+recordVCN], eax
add esi, recordNode
sub edi, esi
mov [esi+nodeRealSize], edi
mov ebx, [ebp+NTFS.secondIndexBuffer]
mov edx, [ebp+NTFS.LastRead]
call writeRecord
jmp .refresh
 
.common:
add edi, edx
sub edi, 4
mov esi, edi
sub esi, [esp]
mov ecx, esi
sub ecx, eax ; eax = pointer in the record
shr ecx, 2
inc ecx
std
rep movsd ; move forward, make space
mov ecx, [esp]
shr ecx, 2
xor eax, eax
rep stosd
cld
add edi, 4
call ntfsGetTime
mov [edi+fileCreated], eax
mov [edi+fileCreated+4], edx
mov [edi+fileModified], eax
mov [edi+fileModified+4], edx
mov [edi+recordModified], eax
mov [edi+recordModified+4], edx
mov [edi+fileAccessed], eax
mov [edi+fileAccessed+4], edx
pop ecx
pop esi
mov [edi+indexAllocatedSize], cx ; fill index with data
mov eax, [esp]
shl eax, 1
add eax, 42h
mov [edi+indexRawSize], ax
mov eax, [ebp+NTFS.cur_iRecord]
mov [edi+directoryRecordReference], eax
mov eax, [ebp+NTFS.frs_buffer]
mov eax, [eax+reuseCounter]
mov [edi+directoryReferenceReuse], ax
mov eax, [ebp+NTFS.frs_size]
shr eax, 8
add ecx, 30h+48h+8+18h+8
add ecx, eax
mov eax, [ebp+NTFS.fileRealSize]
add ecx, eax
mov [edi+fileRealSize], eax
cmp [ebp+NTFS.frs_size], ecx
jc @f
xor eax, eax
@@:
mov ecx, [ebp+NTFS.sectors_per_cluster]
shl ecx, 9
add eax, ecx
dec eax
xor edx, edx
div ecx
mov [ebp+NTFS.fileDataSize], eax
mul ecx
mov [edi+fileAllocatedSize], eax
pop ecx
mov [ebp+NTFS.indexPointer], edi
mov [edi+fileNameLength], cl
add edi, fileName
@@: ; record filename
call utf8to16
stosw
loop @b
mov eax, [ebp+NTFS.LastRead]
mov [ebp+NTFS.nodeLastRead], eax
cmp [ebp+NTFS.bFolder], 0
jz @f
mov edi, [ebp+NTFS.indexPointer]
bts dword [edi+fileFlags], 28
jmp .mftBitmap
 
@@: ; 3. File data
cmp [ebp+NTFS.fileDataSize], 0
jz .mftBitmap
mov edi, [ebp+NTFS.BitmapStart]
call ntfsSpaceAlloc
jc ntfsDiskFull
mov eax, [ebp+NTFS.fileDataStart]
mul [ebp+NTFS.sectors_per_cluster]
mov ecx, [ebp+NTFS.fileRealSize]
add ecx, 511
shr ecx, 9
mov ebx, [ebp+NTFS.fileDataBuffer]
call fs_write64_app
test eax, eax
jnz ntfsDevice
; 4. MFT record
.mftBitmap: ; search for free record
mov edi, [ebp+NTFS.mftBitmapBuffer]
mov ecx, [ebp+NTFS.mftBitmapSize]
mov al, -1
add edi, 3
sub ecx, 3
repz scasb
dec edi
movzx eax, byte [edi]
not al
bsf ecx, eax
jz .extendBitmapMFT ; no free records
bts [edi], ecx
; get record location
sub edi, [ebp+NTFS.mftBitmapBuffer]
shl edi, 3
add edi, ecx
mov [ebp+NTFS.newRecord], edi
mov eax, [ebp+NTFS.frs_size]
shr eax, 9
mul edi
mov [ebp+NTFS.cur_iRecord], 0
mov [ebp+NTFS.cur_attr], 0x80
mov [ebp+NTFS.cur_offs], eax
push eax
mov [ebp+NTFS.cur_size], 0
mov eax, [ebp+NTFS.frs_buffer]
mov [ebp+NTFS.cur_buf], eax
call ntfs_read_attr
pop eax
jc ntfsFail
cmp eax, [ebp+NTFS.mftSize]
jnc .extendMFT
jmp .mftRecord
 
.extendBitmapMFT:
mov eax, [ebp+NTFS.sectors_per_cluster]
mov [ebp+NTFS.cur_offs], eax
shl eax, 9
cmp [ebp+NTFS.mftBitmapSize], eax
jnc ntfsUnsupported
mov [ebp+NTFS.cur_iRecord], 0
mov [ebp+NTFS.cur_attr], 0xB0
mov [ebp+NTFS.cur_size], 0
call ntfs_read_attr
jc ntfsFail
mov eax, [ebp+NTFS.mft_cluster]
mul [ebp+NTFS.sectors_per_cluster]
cmp eax, [ebp+NTFS.LastRead]
jnz ntfsUnsupported ; auxiliary record
mov edi, [ebp+NTFS.mftBitmapBuffer]
mov ecx, [ebp+NTFS.mftBitmapSize]
add edi, ecx
mov eax, ecx
mov edx, [ebp+NTFS.attr_offs]
add ecx, 8
mov [edx+attributeRealSize], ecx
mov [edx+initialDataSize], ecx
shl eax, 3
mov [ebp+NTFS.newRecord], eax
mov dword [edi], 1
mov dword [edi+4], 0
mov [ebp+NTFS.cur_attr], 0x80
mov [ebp+NTFS.cur_offs], 0
call ntfs_read_attr.newAttribute
jc ntfsFail
mov [ebp+NTFS.mftBitmapSize], ecx
.extendMFT:
mov eax, [ebp+NTFS.mft_cluster]
mul [ebp+NTFS.sectors_per_cluster]
cmp eax, [ebp+NTFS.LastRead]
jnz ntfsUnsupported ; auxiliary record
mov ecx, [ebp+NTFS.attr_offs]
mov eax, [ecx+attributeRealSize]
mov edx, [ecx+attributeRealSize+4]
xor ax, ax
add eax, 10000h
adc edx, 0
push [ebp+NTFS.fileDataStart]
push [ebp+NTFS.fileDataSize]
call resizeAttribute
jc ntfsErrorPop2
mov ebx, [ebp+NTFS.frs_buffer]
mov edx, [ebp+NTFS.LastRead]
call writeRecord ; $MFT
mov eax, [ebp+NTFS.mftmirr_cluster]
mul [ebp+NTFS.sectors_per_cluster]
mov ecx, [ebp+NTFS.frs_size]
shr ecx, 9
call fs_write64_sys ; $MFTMirr
; update $MFT retrieval information
mov edi, [ebp+NTFS.mft_retrieval_end]
mov eax, [edi-4]
add eax, [edi-8]
mov edx, [ebp+NTFS.fileDataSize]
cmp eax, [ebp+NTFS.fileDataStart]
jnz .newFragment
add [edi-8], edx
jmp @f
.newFragment:
lea eax, [ebp+NTFS.attrlist_buf]
cmp eax, edi
jz @f
mov [edi], edx
mov eax, [ebp+NTFS.fileDataStart]
mov [edi+4], eax
add [ebp+NTFS.mft_retrieval_end], 8
@@:
mov eax, [ebp+NTFS.fileDataSize]
mul [ebp+NTFS.sectors_per_cluster]
add [ebp+NTFS.mftSize], eax
call ntfsSpaceClean
pop [ebp+NTFS.fileDataSize]
pop [ebp+NTFS.fileDataStart]
.mftRecord:
mov ecx, [ebp+NTFS.frs_size]
shr ecx, 2
mov edi, [ebp+NTFS.frs_buffer]
xor eax, eax
rep stosd
mov esi, [ebp+NTFS.indexPointer]
mov eax, [ebp+NTFS.newRecord]
mov [esi+fileRecordReference], eax
rdtsc
mov [esi+fileReferenceReuse], ax
mov edi, [ebp+NTFS.frs_buffer]
; record header
mov [edi+reuseCounter], ax
mov [edi+2ah], ax
mov eax, [ebp+NTFS.frs_size]
mov [edi+recordAllocatedSize], eax
shr eax, 9
inc eax
mov [edi+updateSequenceSize], al
shl eax, 1
add eax, 2ah+7
and eax, not 7
mov dword[edi], 'FILE'
mov byte [edi+updateSequenceOffset], 2ah
mov byte [edi+hardLinkCounter], 1
mov byte [edi+newAttributeID], 3
mov [edi+attributeOffset], al
add edi, eax
; $StandardInformation
mov byte [edi+attributeType], 10h
mov byte [edi+sizeWithHeader], 48h
mov byte [edi+sizeWithoutHeader], 30h
mov byte [edi+attributeOffset], 18h
mov cl, 8
add esi, fileCreated
add edi, 18h
rep movsd
add edi, 16
mov esi, [ebp+NTFS.indexPointer]
; $FileName
mov byte [edi+attributeType], 30h
mov byte [edi+attributeID], 1
mov byte [edi+attributeOffset], 18h
mov byte [edi+indexedFlag], 1
mov cx, [esi+indexRawSize]
mov [edi+sizeWithoutHeader], ecx
mov cx, [esi+indexAllocatedSize]
add ecx, 8
mov [edi+sizeWithHeader], ecx
add edi, 18h
add esi, 16
sub ecx, 18h
shr ecx, 2
rep movsd
mov byte [edi+sizeWithHeader], 50h
mov byte [edi+attributeID], 2
cmp [ebp+NTFS.bFolder], 1
jz .indexRoot
; $Data
mov byte [edi+attributeType], 80h
mov eax, [ebp+NTFS.fileDataSize]
test eax, eax
jz .resident
mov esi, [ebp+NTFS.indexPointer]
dec eax
mov [edi+lastVCN], eax
mov byte [edi+nonResidentFlag], 1
mov byte [edi+dataRunsOffset], 40h
mov eax, [esi+fileAllocatedSize]
mov [edi+attributeAllocatedSize], eax
mov eax, [esi+fileRealSize]
mov [edi+attributeRealSize], eax
mov [edi+initialDataSize], eax
push edi
mov esi, edi
add edi, 40h
call createMcbEntry
inc edi
jmp @f
 
.resident:
mov ecx, [ebp+NTFS.fileRealSize]
mov [edi+sizeWithoutHeader], ecx
mov byte [edi+attributeOffset], 18h
push edi
mov esi, [ebp+NTFS.fileDataBuffer]
add edi, 18h
rep movsb
@@:
mov eax, edi
pop edi
sub eax, edi
add eax, 7
and eax, not 7
mov [edi+sizeWithHeader], eax
add edi, eax
mov al, 1
jmp .end
 
.indexRoot:
mov byte [edi+attributeType], 90h
mov byte [edi+nameLength], 4
mov byte [edi+nameOffset], 18h
mov byte [edi+sizeWithoutHeader], 30h
mov byte [edi+attributeOffset], 20h
mov dword[edi+18h], 490024h ; unicode $I30
mov dword[edi+18h+4], 300033h
mov byte [edi+20h+indexedAttributesType], 30h
mov byte [edi+20h+collationRule], 1
mov eax, [ebp+NTFS.sectors_per_cluster]
mov dl, 1
shl eax, 8
@@:
shl eax, 1
shl edx, 1
cmp eax, [ebp+NTFS.frs_size]
jc @b
shr edx, 1
mov [edi+20h+indexRecordSize], eax
mov [edi+20h+indexRecordSizeClus], dl
mov byte [edi+30h+indexOffset], 16
mov byte [edi+30h+nodeRealSize], 32
mov byte [edi+30h+nodeAllocatedSize], 32
mov byte [edi+40h+indexAllocatedSize], 16
mov byte [edi+40h+indexFlags], 2
add edi, 50h
mov al, 3
.end:
mov ebx, [ebp+NTFS.frs_buffer]
mov dword [edi], -1
mov dword [edi+4], 0
add edi, 8
sub edi, ebx
mov [ebx+recordFlags], al
mov [ebx+recordRealSize], edi
mov edx, [ebp+NTFS.LastRead]
call writeRecord
; write MFT bitmap
mov eax, [ebp+NTFS.newRecord]
shr eax, 3+9
mov ebx, eax
shl ebx, 9
add eax, [ebp+NTFS.mftBitmapLocation]
add ebx, [ebp+NTFS.mftBitmapBuffer]
mov ecx, 1
xor edx, edx
call fs_write64_sys
; 5. Write directory node
mov ebx, [ebp+NTFS.cur_index_buf]
mov edx, [ebp+NTFS.nodeLastRead]
call writeRecord
mov ebx, [ebp+NTFS.fileRealSize]
ntfsDone:
mov esi, [ebp+PARTITION.Disk]
call disk_sync
call ntfs_unlock
xor eax, eax
ret
 
writeRecord:
; make updateSequence and write to disk
; in:
; ebx -> record
; edx = partition sector
mov esi, ebx
mov edi, ebx
movzx ecx, word [esi+updateSequenceOffset]
add edi, ecx
mov ax, [edi]
inc ax
stosw
mov cx, [esi+updateSequenceSize]
dec ecx
push ecx
@@:
add esi, 510
movsw
mov [esi-2], ax
loop @b
mov eax, edx
xor edx, edx
pop ecx
jmp fs_write64_sys
 
createMcbEntry:
; in:
; [ebp+NTFS.fileDataStart] = position value
; [ebp+NTFS.fileDataSize] = size value
; edi -> destination
; esi -> attribute header
mov eax, [ebp+NTFS.fileDataStart]
xor edx, edx
shl eax, 1
jnc @f
not eax
@@:
inc edx
shr eax, 8
jnz @b
mov eax, [ebp+NTFS.fileDataSize]
shl eax, 1
xor ecx, ecx
@@:
inc ecx
shr eax, 8
jnz @b
lea eax, [edi+edx+1]
add eax, ecx
sub eax, esi
sub eax, [esi+sizeWithHeader]
jc @f
add word [esi+sizeWithHeader], 8 ; extend attribute
mov esi, [ebp+NTFS.frs_buffer]
mov eax, [esi+recordRealSize]
add eax, 8
cmp [esi+recordAllocatedSize], eax
jc .end ; no space in the record
mov [esi+recordRealSize], eax
push ecx edi
add esi, eax
mov ecx, esi
sub ecx, edi
sub ecx, 8
shr ecx, 2
mov edi, esi
sub edi, 4
sub esi, 12
std
rep movsd
cld
pop edi ecx
@@:
mov eax, edx
shl eax, 4
add eax, ecx
stosb
lea esi, [ebp+NTFS.fileDataSize]
rep movsb
lea esi, [ebp+NTFS.fileDataStart]
mov ecx, edx
rep movsb
mov [edi], cl
.end:
ret
 
resizeAttribute:
; in:
; [ebp+NTFS.frs_buffer] -> file record
; [ebp+NTFS.attr_offs] -> attribute
; edx:eax = new size
; out:
; [ebp+NTFS.fileDataSize] = clusters added (positive)
; [ebp+NTFS.fileDataStart] = added block
; CF=1 -> eax = error code
mov esi, [ebp+NTFS.attr_offs]
mov dword [ebp+NTFS.attr_size], eax
mov dword [ebp+NTFS.attr_size+4], edx
cmp byte [esi+nonResidentFlag], 0
jz .resident
mov ecx, [ebp+NTFS.sectors_per_cluster]
shl ecx, 9
mov [esi+attributeRealSize], eax
mov [esi+attributeRealSize+4], edx
mov [esi+initialDataSize], eax
mov [esi+initialDataSize+4], edx
sub eax, 1
sbb edx, 0
jc .makeResident
div ecx
mov edi, eax
inc eax
mul ecx
mov [esi+attributeAllocatedSize], eax
mov [esi+attributeAllocatedSize+4], edx
mov ecx, [esi+lastVCN]
mov [esi+lastVCN], edi
movzx eax, byte [esi+dataRunsOffset]
sub edi, ecx
mov [ebp+NTFS.fileDataSize], edi
jz .done
jc .shrinkAttribute
; extend attribute
xor edi, edi
add esi, eax
push edi edi edi edi
@@:
mov edx, eax
mov eax, esi
add edi, [esp+8]
call ntfs_decode_mcb_entry
jc @b
mov [esp+4], edx
mov [esp+12], edi
add edi, [esp]
push edi
shr edi, 5
shl edi, 2
push eax
cmp edi, [ebp+NTFS.BitmapStart]
jnc @f
cmp [ebp+NTFS.cur_iRecord], 0
jz @f
mov edi, [ebp+NTFS.BitmapStart]
@@:
call ntfsSpaceAlloc
jc .err1
mov eax, [ebp+NTFS.fileDataStart]
pop edi
pop edx
cmp edx, eax
jnz .newEntry
pop edx
pop edi
pop [ebp+NTFS.fileDataStart]
mov [esp], eax
push [ebp+NTFS.fileDataSize]
add [ebp+NTFS.fileDataSize], edx
jmp @f
 
.newEntry:
add esp, 12
pop edx
push eax
push [ebp+NTFS.fileDataSize]
sub eax, edx
mov [ebp+NTFS.fileDataStart], eax
@@:
mov esi, [ebp+NTFS.attr_offs]
call createMcbEntry
pop [ebp+NTFS.fileDataSize]
pop [ebp+NTFS.fileDataStart]
movi eax, ERROR_UNSUPPORTED_FS
.done:
ret
 
.err1:
add esp, 24
stc
.err2:
movi eax, ERROR_DISK_FULL
ret
 
.err3:
movi eax, ERROR_FS_FAIL
add esp, 20
stc
ret
 
.shrinkAttribute:
add ecx, edi
inc ecx
add esi, eax
xor edi, edi
sub esp, 20
@@:
mov [esp+16], esi
call ntfs_decode_mcb_entry
jnc .err3
add edi, [esp+8]
sub ecx, [esp]
jnc @b
mov ebx, ecx
add ecx, [esp]
mov eax, [esp+8]
mov [ebp+NTFS.fileDataSize], ecx
mov [ebp+NTFS.fileDataStart], eax
push edi
add edi, ecx
neg ebx
call ntfsSpaceFree
pop edi
jc .end
@@:
call ntfs_decode_mcb_entry
jnc .end
cmp dword[esp+8], 0
jz @b
add edi, [esp+8]
mov ebx, [esp]
call ntfsSpaceFree
jnc @b
.end:
add esp, 16
pop edi
cmp [ebp+NTFS.fileDataSize], 0
jz @f
mov esi, [ebp+NTFS.attr_offs]
call createMcbEntry
mov [ebp+NTFS.fileDataSize], 0
@@:
ret
 
.resident:
test edx, edx
jnz .nonResident
cmp eax, 8000h
jnc .nonResident
add ax, [esi+attributeOffset]
sub eax, [esi+sizeWithHeader]
jc @f
mov edi, [ebp+NTFS.frs_buffer]
mov ecx, eax
add ecx, [edi+recordRealSize]
cmp [edi+recordAllocatedSize], ecx
jc .nonResident
add eax, 7
and eax, not 7
add [edi+recordRealSize], eax
add edi, [edi+recordRealSize]
add [esi+sizeWithHeader], eax
add esi, [esi+sizeWithHeader]
mov ecx, edi
sub ecx, esi
shr ecx, 2
sub edi, 4
mov esi, edi
sub esi, eax
std
rep movsd
mov ecx, eax
shr ecx, 2
xor eax, eax
rep stosd
cld
mov esi, [ebp+NTFS.attr_offs]
@@:
mov eax, dword [ebp+NTFS.attr_size]
mov [esi+sizeWithoutHeader], eax
mov [ebp+NTFS.fileDataSize], 0
clc
ret
 
.nonResident: ; convert resident to non-resident
mov eax, dword [ebp+NTFS.attr_size]
sub eax, 1
sbb edx, 0
mov ecx, [ebp+NTFS.sectors_per_cluster]
shl ecx, 9
div ecx
inc eax
mov [ebp+NTFS.fileDataSize], eax
mov edi, [ebp+NTFS.BitmapStart]
push ecx
call ntfsSpaceAlloc
pop ecx
jc .err2
mov esi, [ebp+NTFS.attr_offs]
xor eax, eax
xor edx, edx
@@:
add eax, ecx
inc edx
cmp eax, [esi+sizeWithoutHeader]
jc @b
push edx
push eax
stdcall kernel_alloc, eax
mov ecx, [esp]
shr ecx, 2
mov edi, eax
mov ebx, eax
xor eax, eax
rep stosd
mov al, [esi+attributeOffset]
mov ecx, [esi+sizeWithoutHeader]
add esi, eax
mov edi, ebx
rep movsb
mov eax, [ebp+NTFS.fileDataStart]
mul [ebp+NTFS.sectors_per_cluster]
pop ecx
shr ecx, 9
call fs_write64_app
stdcall kernel_free, ebx
mov esi, [ebp+NTFS.attr_offs]
add esi, [esi+sizeWithHeader]
mov ecx, [ebp+NTFS.frs_buffer]
add ecx, [ecx+recordRealSize]
sub ecx, esi
shr ecx, 2
lea edi, [ebp+NTFS.bitmap_buf]
push ecx
rep movsd
mov edi, [ebp+NTFS.attr_offs]
add edi, 16
mov cl, 6
xor eax, eax
rep stosd
mov edi, [ebp+NTFS.attr_offs]
mov eax, [ebp+NTFS.fileDataSize]
dec eax
mov [edi+lastVCN], eax
inc eax
mov ecx, [ebp+NTFS.sectors_per_cluster]
shl ecx, 9
mul ecx
mov byte [edi+sizeWithHeader], 50h
mov byte [edi+nonResidentFlag], 1
mov byte [edi+dataRunsOffset], 40h
mov [edi+attributeAllocatedSize], eax
mov [edi+attributeAllocatedSize+4], edx
mov eax, dword [ebp+NTFS.attr_size]
mov edx, dword [ebp+NTFS.attr_size+4]
mov [edi+attributeRealSize], eax
mov [edi+attributeRealSize+4], edx
mov [edi+initialDataSize], eax
mov [edi+initialDataSize+4], edx
mov esi, edi
add edi, 40h
call createMcbEntry
mov eax, edi
mov edi, [ebp+NTFS.attr_offs]
sub eax, edi
add eax, 8
and eax, not 7
mov [edi+sizeWithHeader], eax
pop ecx
lea esi, [ebp+NTFS.bitmap_buf]
add edi, eax
rep movsd
mov esi, [ebp+NTFS.frs_buffer]
sub edi, esi
mov [esi+recordRealSize], edi
pop edx
sub [ebp+NTFS.fileDataSize], edx
add [ebp+NTFS.fileDataStart], edx
ret
 
.makeResident: ; convert non-resident to empty resident
movzx eax, byte [esi+dataRunsOffset]
mov byte [esi+nonResidentFlag], 0
mov dword [esi+sizeWithoutHeader], 0
mov dword [esi+attributeOffset], 18h
add esi, eax
xor edi, edi
sub esp, 16
@@:
call ntfs_decode_mcb_entry
jnc @f
cmp dword[esp+8], 0
jz @b
add edi, [esp+8]
mov ebx, [esp]
call ntfsSpaceFree
jnc @b
@@:
add esp, 16
mov [ebp+NTFS.fileDataSize], 0
ret
 
ntfsSpaceClean:
; clean up to 16 Mb of disk space
; in:
; [ebp+NTFS.fileDataStart] = block to clean
; [ebp+NTFS.fileDataSize] = block size
mov eax, [ebp+NTFS.fileDataSize]
test eax, eax
jz @f
mul [ebp+NTFS.sectors_per_cluster]
cmp eax, 8001h
jnc @f
push eax
shl eax, 9
stdcall kernel_alloc, eax
pop ecx
test eax, eax
jz @f
push ecx
shl ecx, 7
mov edi, eax
mov ebx, eax
xor eax, eax
rep stosd
mov eax, [ebp+NTFS.fileDataStart]
mul [ebp+NTFS.sectors_per_cluster]
mov [ebp+NTFS.LastRead], eax
pop ecx
call fs_write64_app
stdcall kernel_free, ebx
@@:
ret
 
ntfsSpaceAlloc:
; allocate disk space
; in:
; edi = offset in bitmap to start search from
; [ebp+NTFS.fileDataSize] = block size in clusters
; out:
; [ebp+NTFS.fileDataStart] = allocated block starting cluster
; CF=1 -> disk full
mov ecx, [ebp+NTFS.BitmapBuffer]
add edi, ecx
add ecx, [ebp+NTFS.BitmapSize]
sub ecx, edi
ja @f
push eax
call bitmapBuffering
pop eax
shl ecx, 2
@@:
shr ecx, 2
push ecx
mov eax, [ebp+NTFS.fileDataSize]
shr eax, 5
jz .small
mov ebx, eax ; bitmap dwords
.start:
mov ecx, [ebp+NTFS.BitmapBuffer]
add ecx, [ebp+NTFS.BitmapSize]
sub ecx, edi
shr ecx, 2
@@:
xor eax, eax
repnz scasd ; search for empty dword
jz @f
call bitmapBuffering
jmp @b
@@:
cmp ecx, ebx
jnc @f
call bitmapBuffering
jmp @b
@@:
sub edi, 4
mov ecx, ebx
mov esi, edi
xor eax, eax
repz scasd ; check following dwords
jnz .start
sub esi, 4
mov eax, [esi]
xor edx, edx
bsr edx, eax
inc edx
push edx ; starting bit
push esi ; starting dword
add esi, 4
neg edx
add edx, 32
mov eax, [ebp+NTFS.fileDataSize]
sub eax, edx
mov edx, eax
shr eax, 5
shl eax, 2
add esi, eax
mov eax, [esi]
bsf ecx, eax ; check last dword
jz .done
and edx, 31
cmp ecx, edx
jnc .done
add esp, 8
jmp .start
 
@@:
sub edi, 4
call bitmapBuffering
push ecx
.small: ; less than 32 clusters
pop ecx
or eax, -1
repz scasd
jecxz @b
push ecx
mov eax, [edi-4]
not eax
@@:
bsf ecx, eax ; first 0
jz .small
not eax
shr eax, cl
shl eax, cl
bsf edx, eax ; next 1
jz @f
sub edx, ecx
cmp edx, [ebp+NTFS.fileDataSize]
jnc .got ; fits inside
bsf ecx, eax
not eax
shr eax, cl
shl eax, cl
jmp @b
 
@@: ; next dword
mov eax, [edi]
bsf edx, eax
jz .got ; empty
add edx, 32
sub edx, ecx
cmp edx, [ebp+NTFS.fileDataSize]
jc .small
.got:
sub edi, 4
push ecx ; starting bit
push edi ; starting dword
.done: ; mark space
pop edi ecx
cmp ecx, 32
jc @f
xor ecx, ecx
add edi, 4
@@:
push ecx edi
or eax, -1
shr eax, cl
shl eax, cl
neg ecx
add ecx, 32
sub ecx, [ebp+NTFS.fileDataSize]
jc @f
shl eax, cl ; fits inside dword
shr eax, cl
or [edi], eax
jmp .end
 
@@:
or [edi], eax
neg ecx
push ecx
shr ecx, 5
add edi, 4
or eax, -1
rep stosd
pop ecx
and ecx, 31
shr eax, cl
shl eax, cl
not eax
or [edi], eax
.end:
pop eax
pop ecx
sub eax, [ebp+NTFS.BitmapBuffer]
shl eax, 3
add eax, ecx
pop ecx
mov ecx, [ebp+NTFS.fileDataSize]
mov [ebp+NTFS.fileDataStart], eax
add ecx, eax
add ecx, 4095
shr ecx, 3+9
shr eax, 3+9
sub ecx, eax
mov ebx, eax
shl ebx, 9
add eax, [ebp+NTFS.BitmapLocation]
add ebx, [ebp+NTFS.BitmapBuffer]
xor edx, edx
jmp fs_write64_app
 
ntfsSpaceFree:
; free disk space
; in:
; edi = starting cluster
; ebx = size in clusters
mov eax, edi
add eax, ebx
shr eax, 3
cmp eax, [ebp+NTFS.BitmapSize]
jc @f
add eax, [ebp+NTFS.BitmapBuffer]
push edi
mov edi, eax
call bitmapBuffering
pop edi
@@:
push edi
mov ecx, edi
shr edi, 5
shl edi, 2
add edi, [ebp+NTFS.BitmapBuffer]
and ecx, 31
xor eax, eax
dec eax
shr eax, cl
shl eax, cl
neg ecx
add ecx, 32
sub ecx, ebx
jc @f
shl eax, cl ; fits inside dword
shr eax, cl
not eax
and [edi], eax
jmp .writeBitmap
 
@@:
not eax
and [edi], eax
neg ecx
push ecx
shr ecx, 5
add edi, 4
xor eax, eax
rep stosd
pop ecx
and ecx, 31
dec eax
shr eax, cl
shl eax, cl
and [edi], eax
.writeBitmap:
pop eax
mov edi, eax
lea ecx, [eax+ebx+4095]
shr eax, 3+9
shr ecx, 3+9
sub ecx, eax
mov ebx, eax
shl ebx, 9
add eax, [ebp+NTFS.BitmapLocation]
add ebx, [ebp+NTFS.BitmapBuffer]
xor edx, edx
jmp fs_write64_app
 
bitmapBuffering:
; Extend BitmapBuffer and read next 32kb of bitmap
; Warning: $Bitmap fragmentation is not foreseen
; in: edi -> position in bitmap buffer
; out: ecx = number of buffered dwords left
push ebx
mov eax, [ebp+NTFS.BitmapTotalSize]
cmp eax, [ebp+NTFS.BitmapSize]
jz .end
stdcall alloc_pages, 8
test eax, eax
jz .end
add eax, 3
mov ebx, [ebp+NTFS.BitmapBuffer]
add ebx, [ebp+NTFS.BitmapSize]
push ebx
mov ecx, 8
call commit_pages
mov eax, [ebp+NTFS.BitmapSize]
shr eax, 9
add eax, [ebp+NTFS.BitmapLocation]
pop ebx
mov ecx, 64
xor edx, edx
call fs_read64_app
test eax, eax
jnz .err
mov eax, [ebp+NTFS.BitmapSize]
add eax, 8000h
cmp [ebp+NTFS.BitmapTotalSize], eax
jnc @f
mov eax, [ebp+NTFS.BitmapTotalSize]
@@:
mov [ebp+NTFS.BitmapSize], eax
pop ebx
mov ecx, [ebp+NTFS.BitmapBuffer]
add ecx, eax
sub ecx, edi
jbe bitmapBuffering
shr ecx, 2
ret
 
.err:
mov eax, [ebp+NTFS.BitmapBuffer]
add eax, [ebp+NTFS.BitmapSize]
mov ecx, 8
call release_pages
.end:
add esp, 12 ; ret
stc
ret
 
;----------------------------------------------------------------
ntfs_WriteFile:
call ntfs_lock
call ntfs_find_lfn
jc ntfsNotFound
cmp [ebp+NTFS.cur_iRecord], 16
jc ntfsDenied
test dword [eax+fileFlags], 10000001h
jnz ntfsDenied
cmp [ebp+NTFS.fragmentCount], 1
jnz ntfsUnsupported ; record fragmented
; edit directory node
mov edi, [ebp+NTFS.cur_index_buf]
cmp dword [edi], 'INDX'
jz @f
mov esi, [ebp+NTFS.frs_buffer]
mov ecx, [esi+recordRealSize]
shr ecx, 2
rep movsd
mov esi, [ebp+NTFS.attr_offs]
mov cl, [esi+attributeOffset]
sub esi, [ebp+NTFS.frs_buffer]
add eax, ecx
add eax, esi
@@:
mov edi, eax
mov eax, [ebx+4]
mov edx, [ebx+8]
add eax, [ebx+12]
adc edx, 0
mov [edi+fileRealSize], eax
mov [edi+fileRealSize+4], edx
push edx eax ebx
call ntfsGetTime
mov [edi+fileModified], eax
mov [edi+fileModified+4], edx
mov [edi+recordModified], eax
mov [edi+recordModified+4], edx
mov [edi+fileAccessed], eax
mov [edi+fileAccessed+4], edx
pop ebx ecx edx
mov eax, [ebp+NTFS.LastRead]
mov [ebp+NTFS.nodeLastRead], eax
mov [ebp+NTFS.cur_attr], 0x80
mov [ebp+NTFS.cur_offs], 0
mov [ebp+NTFS.cur_size], 0
call ntfs_read_attr
jc ntfsFail
mov esi, edi
mov edi, [ebp+NTFS.frs_buffer]
cmp word [edi+baseRecordReuse], 0
jnz ntfsUnsupported ; auxiliary record
mov al, [edi+attributeOffset]
add edi, eax
mov al, [edi+attributeOffset]
add edi, eax
mov eax, ecx
mov ecx, 6
add esi, fileModified
add edi, 8
rep movsd
mov ecx, [ebp+NTFS.attr_offs]
cmp word [ecx+attributeFlags], 0
jnz ntfsUnsupported
push ebx
cmp byte [ecx+nonResidentFlag], 0
jz .resizeAttribute
cmp edx, [ecx+attributeRealSize+4]
jc .writeNode
jnz .resizeAttribute
cmp [ecx+attributeRealSize], eax
jnc .writeNode
.resizeAttribute:
call resizeAttribute
jc ntfsErrorPop
mov ecx, [ebp+NTFS.attr_offs]
cmp byte [ecx+nonResidentFlag], 1
jz @f
mov ebx, [esp]
movzx edi, byte [ecx+attributeOffset]
add edi, ecx
add edi, [ebx+4]
mov ecx, [ebx+12]
mov esi, [ebx+16]
rep movsb
@@:
mov ebx, [ebp+NTFS.frs_buffer]
mov edx, [ebp+NTFS.mftLastRead]
call writeRecord ; file
call ntfs_restore_usa_frs
.writeNode:
mov ebx, [ebp+NTFS.cur_index_buf]
mov edx, [ebp+NTFS.nodeLastRead]
call writeRecord ; directory
pop ebx
mov ecx, [ebp+NTFS.attr_offs]
cmp byte [ecx+nonResidentFlag], 0
jz .done
mov ecx, [ebx+12]
test ecx, ecx
jz .done
mov eax, [ebx+4]
mov edx, [ebx+8]
mov esi, [ebx+16]
shrd eax, edx, 9
test dword[ebx+4], 1FFh
jz .aligned
mov [ebp+NTFS.cur_offs], eax
mov [ebp+NTFS.cur_size], 1
lea edi, [ebp+NTFS.bitmap_buf]
mov [ebp+NTFS.cur_buf], edi
call ntfs_read_attr.continue
jc ntfsDevice
mov eax, [ebx+4]
and eax, 1FFh
add edi, eax
sub eax, [ebp+NTFS.cur_read]
neg eax
push ecx
cmp ecx, eax
jb @f
mov ecx, eax
@@:
sub [esp], ecx
rep movsb
push ebx
mov eax, [ebp+NTFS.LastRead]
lea ebx, [ebp+NTFS.bitmap_buf]
mov ecx, 1
xor edx, edx
call fs_write64_app
pop ebx
pop ecx
test ecx, ecx
jz .done
mov eax, [ebx+4]
mov edx, [ebx+8]
shrd eax, edx, 9
inc eax
.aligned:
push ecx
shr ecx, 9
mov [ebp+NTFS.cur_offs], eax
mov [ebp+NTFS.cur_size], ecx
mov [ebp+NTFS.cur_buf], esi
add eax, ecx
push eax
mov [ebp+NTFS.bWriteAttr], 1
call ntfs_read_attr.continue
mov [ebp+NTFS.bWriteAttr], 0
pop [ebp+NTFS.cur_offs]
pop ecx
jc ntfsDevice
and ecx, 1FFh
jz .done
add esi, [ebp+NTFS.cur_read]
mov [ebp+NTFS.cur_size], 1
lea edi, [ebp+NTFS.bitmap_buf]
mov [ebp+NTFS.cur_buf], edi
call ntfs_read_attr.continue
jc ntfsDevice
rep movsb
push ebx
mov eax, [ebp+NTFS.LastRead]
lea ebx, [ebp+NTFS.bitmap_buf]
mov ecx, 1
xor edx, edx
call fs_write64_app
pop ebx
.done:
mov ebx, [ebx+12]
jmp ntfsDone
 
;----------------------------------------------------------------
ntfs_Delete:
call ntfs_lock
call ntfs_find_lfn
jc ntfsNotFound
cmp [ebp+NTFS.cur_iRecord], 16
jc ntfsDenied
test byte [eax+fileFlags], 1
jnz ntfsDenied
cmp [ebp+NTFS.fragmentCount], 1
jnz ntfsUnsupported ; record fragmented
mov ebx, [eax+directoryRecordReference]
mov [ebp+NTFS.newRecord], ebx
mov bx, [eax+fileReferenceReuse]
mov [ebp+NTFS.indexPointer], esi
mov eax, [ebp+NTFS.cur_iRecord]
shr eax, 3
cmp eax, [ebp+NTFS.mftBitmapSize]
jnc ntfsUnsupported
; examine file record
mov [ebp+NTFS.cur_attr], 0x80 ; file?
mov [ebp+NTFS.cur_offs], 0
mov [ebp+NTFS.cur_size], 0
call ntfs_read_attr
jnc @f
xor eax, eax
push ebx eax eax eax eax
mov [esp+12], esp
push eax
mov ebx, esp
mov [ebp+NTFS.cur_attr], 0x90 ; folder?
call ntfs_ReadFolder.doit
mov edx, [esp+12]
add esp, 20
pop ebx
test eax, eax
jnz .ret
cmp edx, 2
jnz ntfsDenied ; folder is not empty
mov [ebp+NTFS.cur_attr], 0xA0
mov [ebp+NTFS.cur_offs], 0
mov [ebp+NTFS.cur_size], 0
call ntfs_read_attr.newAttribute
jc .deleteFileRecord
@@:
mov esi, [ebp+NTFS.frs_buffer]
cmp word [esi+baseRecordReuse], 0
jnz ntfsUnsupported ; auxiliary record
cmp word [esi+reuseCounter], bx
jnz .backToIndex ; broken index
test byte [esi+recordFlags], 1
jz .writeBitmapMFT ; record deleted
cmp byte [esi+hardLinkCounter], 3
jnc ntfsUnsupported
mov esi, [ebp+NTFS.attr_offs]
cmp byte [esi+nonResidentFlag], 0
jz .deleteFileRecord
movzx eax, byte [esi+dataRunsOffset]
add esi, eax
xor edi, edi
sub esp, 16
@@:
call ntfs_decode_mcb_entry
jnc @f
cmp dword[esp+8], 0
jz @b
add edi, [esp+8]
mov ebx, [esp]
call ntfsSpaceFree
jnc @b
@@:
add esp, 16
.deleteFileRecord:
mov ebx, [ebp+NTFS.frs_buffer]
mov byte [ebx+recordFlags], 0
mov edx, [ebp+NTFS.mftLastRead]
call writeRecord
.writeBitmapMFT:
mov eax, [ebp+NTFS.cur_iRecord]
mov ecx, eax
shr eax, 3
and ecx, 7
mov edi, [ebp+NTFS.mftBitmapBuffer]
btr [edi+eax], ecx
shr eax, 9
mov ebx, eax
shl ebx, 9
add eax, [ebp+NTFS.mftBitmapLocation]
add ebx, edi
mov ecx, 1
xor edx, edx
call fs_write64_sys
.backToIndex:
mov eax, [ebp+NTFS.newRecord]
mov [ebp+NTFS.cur_iRecord], eax
mov esi, [ebp+NTFS.indexPointer]
call ntfs_find_lfn.doit2
jc ntfsFail
mov ebx, [ebp+NTFS.secondIndexBuffer]
mov byte [ebx], 0
mov ebx, [ebp+NTFS.LastRead]
mov [ebp+NTFS.nodeLastRead], ebx
xor ebx, ebx
test byte [eax+indexFlags], 1
jz .deleteIndex ; no subnode
mov edi, eax
call .findSubindex
jc ntfsFail
movzx edx, word [edi+indexAllocatedSize]
test esi, esi
jz @f
sub edx, eax
sub edx, 8
@@:
mov eax, edi
mov ebx, esi
jmp @f
 
.deleteIndex:
movzx edx, word [eax+indexAllocatedSize]
mov ecx, [eax+fileRecordReference]
cmp [eax+edx+fileRecordReference], ecx
jnz @f
add dx, [eax+edx+indexAllocatedSize]
@@:
mov edi, [ebp+NTFS.cur_index_buf]
cmp dword [edi], 'INDX'
jz .indexRecord
sub eax, edi
mov edi, [ebp+NTFS.indexRoot]
sub [edi+sizeWithHeader], edx
sub [edi+sizeWithoutHeader], edx
movzx ecx, byte [edi+attributeOffset]
add edi, ecx
add eax, edi
sub [edi+rootNode+nodeRealSize], edx
sub [edi+rootNode+nodeAllocatedSize], edx
mov edi, [ebp+NTFS.frs_buffer]
sub [edi+recordRealSize], edx
mov ecx, [edi+recordRealSize]
cmp [edi+recordAllocatedSize], ecx
jmp @f
 
.indexRecord:
add edi, recordNode
sub [edi+nodeRealSize], edx
mov ecx, [edi+nodeRealSize]
cmp [edi+nodeAllocatedSize], ecx
@@:
jc ntfsUnsupported
add ecx, edi
sub ecx, eax
mov esi, eax
add esi, edx
mov edi, eax
test edx, edx
jns @f
neg edx
add edx, ecx
sub edx, 4
add esi, edx
add edi, edx
std
@@:
jz @f
shr ecx, 2
rep movsd
cld
@@:
test ebx, ebx
jz .done
; copy index from the subnode to replace deleted pointing index
movzx ecx, word [ebx+indexAllocatedSize]
mov edx, ecx
test byte [ebx+indexFlags], 1
jz @f
sub ecx, 8
movzx edi, word [ebx+edx+indexAllocatedSize]
add edi, edx
mov esi, [ebx+ecx]
mov [ebx+edi-8], esi
mov [ebx+indexAllocatedSize], cx
@@:
shr ecx, 2
mov esi, ebx
mov edi, eax
rep movsd
add word [eax+indexAllocatedSize], 8
mov byte [eax+indexFlags], 1
mov edi, [ebp+NTFS.secondIndexBuffer]
mov eax, ebx
xor ebx, ebx
jmp .indexRecord
 
.done:
mov ebx, [ebp+NTFS.frs_buffer]
mov edx, [ebp+NTFS.rootLastRead]
call writeRecord
mov ebx, [ebp+NTFS.cur_index_buf]
cmp dword [ebx], 'INDX'
jnz @f
mov edx, [ebp+NTFS.nodeLastRead]
call writeRecord
@@:
mov ebx, [ebp+NTFS.secondIndexBuffer]
cmp byte [ebx], 0
jz ntfsDone
mov edx, [ebp+NTFS.LastRead]
call writeRecord
jmp ntfsDone
 
.findSubindex:
; in: eax -> index
; out:
; CF=1 -> error
; esi=0 -> subnode deleted
; esi -> replacement index
; eax = index effective size
movzx edx, word [eax+indexAllocatedSize]
mov eax, [eax+edx-8]
mov edx, [ebp+NTFS.cur_size]
push edx
cmp edx, [ebp+NTFS.cur_subnode_size]
jz @f
mul [ebp+NTFS.sectors_per_cluster]
@@:
mov [ebp+NTFS.cur_attr], 0xA0
mov [ebp+NTFS.cur_offs], eax
push eax
mov ebx, [ebp+NTFS.secondIndexBuffer]
mov esi, ebx
mov [ebp+NTFS.cur_buf], ebx
call ntfs_read_attr.newAttribute
pop [ebp+NTFS.cur_offs]
pop eax
jc .ret
cmp dword [esi], 'INDX'
stc
jnz .ret
mov [ebp+NTFS.cur_size], eax
shl eax, 9
call ntfs_restore_usa
jc .ret
add esi, recordNode
add esi, [esi+indexOffset]
test byte [esi+indexFlags], 2
jnz .emptyNode
cmp [ebp+NTFS.fragmentCount], 1
stc
jnz .ret ; record fragmented
xor eax, eax
@@:
add esi, eax
mov ax, [esi+indexAllocatedSize]
test byte [esi+eax+indexFlags], 2
jz @b
test byte [esi+indexFlags], 1
jz .ret
add eax, esi
push esi
push [ebp+NTFS.cur_offs]
call .findSubindex
pop [ebp+NTFS.cur_offs]
pop edx
jc .ret
test esi, esi
jnz .ret
mov esi, edx
mov ebx, [ebp+NTFS.secondIndexBuffer]
mov [ebp+NTFS.cur_buf], ebx
push [ebp+NTFS.cur_size]
call ntfs_read_attr.continue
pop eax
jc .ret
shl eax, 9
call ntfs_restore_usa
jc .ret
movzx eax, word [esi+indexAllocatedSize]
sub eax, 8
.ret:
ret
 
.emptyNode:
test byte [esi+indexFlags], 1
jz @f
mov eax, esi
push [ebp+NTFS.cur_offs]
call .findSubindex
pop [ebp+NTFS.cur_offs]
jc .ret
test esi, esi
jnz .ret
@@: ; delete node
mov esi, [ebp+NTFS.attr_offs]
add esi, [esi+sizeWithHeader]
cmp byte [esi], 0xB0
stc
jnz .ret
movzx eax, byte [esi+attributeOffset]
add esi, eax
mov eax, [ebp+NTFS.cur_offs]
xor edx, edx
div [ebp+NTFS.cur_size]
mov edx, eax
shr eax, 3
and edx, 7
btr [esi+eax], edx
mov esi, [ebp+NTFS.secondIndexBuffer]
mov byte [esi], 0
xor esi, esi
ret
 
;----------------------------------------------------------------
ntfs_SetFileEnd:
call ntfs_lock
call ntfs_find_lfn
jc ntfsNotFound
cmp [ebp+NTFS.cur_iRecord], 16
jc ntfsDenied
test dword [eax+fileFlags], 10000001h
jnz ntfsDenied
cmp [ebp+NTFS.fragmentCount], 1
jnz ntfsUnsupported ; record fragmented
; edit directory node
mov edi, [ebp+NTFS.cur_index_buf]
cmp dword [edi], 'INDX'
jz @f
mov esi, [ebp+NTFS.frs_buffer]
mov ecx, [esi+recordRealSize]
shr ecx, 2
rep movsd
mov esi, [ebp+NTFS.attr_offs]
mov cl, [esi+attributeOffset]
sub esi, [ebp+NTFS.frs_buffer]
add eax, ecx
add eax, esi
@@:
mov edi, eax
mov eax, [ebx+4]
mov edx, [ebx+8]
mov [edi+fileRealSize], eax
mov [edi+fileRealSize+4], edx
push edx eax ebx
call ntfsGetTime
mov [edi+fileModified], eax
mov [edi+fileModified+4], edx
mov [edi+recordModified], eax
mov [edi+recordModified+4], edx
mov [edi+fileAccessed], eax
mov [edi+fileAccessed+4], edx
pop ebx ecx edx
mov eax, [ebp+NTFS.LastRead]
mov [ebp+NTFS.nodeLastRead], eax
mov [ebp+NTFS.cur_attr], 0x80
mov [ebp+NTFS.cur_offs], 0
mov [ebp+NTFS.cur_size], 0
call ntfs_read_attr
jc ntfsFail
mov esi, edi
mov edi, [ebp+NTFS.frs_buffer]
cmp word [edi+baseRecordReuse], 0
jnz ntfsUnsupported ; auxiliary record
mov al, [edi+attributeOffset]
add edi, eax
mov al, [edi+attributeOffset]
add edi, eax
mov eax, ecx
mov ecx, 6
add esi, fileModified
add edi, 8
rep movsd
mov ecx, [ebp+NTFS.attr_offs]
cmp word [ecx+attributeFlags], 0
jnz ntfsUnsupported
cmp byte [ecx+nonResidentFlag], 0
jz .resizeAttribute
cmp [ecx+attributeRealSize+4], edx
jnz .resizeAttribute
cmp [ecx+attributeRealSize], eax
jnc .resizeAttribute
mov eax, [ecx+attributeRealSize]
mov ecx, [ebp+NTFS.sectors_per_cluster]
mov [ebp+NTFS.cur_size], ecx
shl ecx, 9
div ecx
test edx, edx
jz .aligned
push edx
push ecx
mul [ebp+NTFS.sectors_per_cluster]
mov [ebp+NTFS.cur_offs], eax
stdcall kernel_alloc, ecx
pop ecx
pop edi
mov esi, eax
sub ecx, edi
add edi, eax
mov [ebp+NTFS.cur_buf], eax
call ntfs_read_attr.continue
jc @f
xor eax, eax
rep stosb
push ebx
mov eax, [ebp+NTFS.LastRead]
mov ebx, esi
mov ecx, [ebp+NTFS.sectors_per_cluster]
xor edx, edx
call fs_write64_app
pop ebx
@@:
stdcall kernel_free, esi
.aligned:
mov eax, [ebx+4]
mov edx, [ebx+8]
.resizeAttribute:
call resizeAttribute
jc ntfsError
mov ebx, [ebp+NTFS.frs_buffer]
mov edx, [ebp+NTFS.mftLastRead]
call writeRecord ; file
mov ebx, [ebp+NTFS.cur_index_buf]
mov edx, [ebp+NTFS.nodeLastRead]
call writeRecord ; directory
call ntfsSpaceClean
jmp ntfsDone
 
ntfsGetTime:
call fsGetTime
jmp @f
 
ntfsCalculateTime:
; in: esi -> data block
; out: edx:eax = seconds since 01.01.1601 x10000000
call fsCalculateTime
@@:
mov edx, 10000000
mul edx
add eax, 3365781504
adc edx, 29389701
ret
 
;----------------------------------------------------------------
ntfs_SetFileInfo:
call ntfs_lock
call ntfs_find_lfn
jnc @f
test eax, eax
jz ntfsFail
jmp ntfsNotFound
 
@@:
cmp [ebp+NTFS.fragmentCount], 1
jnz ntfsUnsupported ; record fragmented
mov esi, [ebp+NTFS.cur_index_buf]
cmp dword [esi], 'INDX'
jz @f
sub eax, esi
mov esi, [ebp+NTFS.indexRoot]
movzx edx, byte [esi+attributeOffset]
add eax, esi
add eax, edx
@@:
mov esi, [ebx+16]
mov edi, eax
mov eax, [esi]
and eax, 27h
and byte [edi+fileFlags], -28h
or [edi+fileFlags], al
add esi, 8
call ntfsCalculateTime
mov [edi+fileCreated], eax
mov [edi+fileCreated+4], edx
add esi, 8
call ntfsCalculateTime
mov [edi+fileAccessed], eax
mov [edi+fileAccessed+4], edx
add esi, 8
call ntfsCalculateTime
mov [edi+fileModified], eax
mov [edi+fileModified+4], edx
mov ebx, [ebp+NTFS.cur_index_buf]
cmp dword [ebx], 'INDX'
jz @f
mov ebx, [ebp+NTFS.frs_buffer]
@@:
mov edx, [ebp+NTFS.LastRead]
call writeRecord
jmp ntfsDone
 
ntfsUnsupported:
push ERROR_UNSUPPORTED_FS
jmp ntfsOut
ntfsDevice:
push ERROR_DEVICE
jmp ntfsOut
ntfsNotFound:
push ERROR_FILE_NOT_FOUND
jmp ntfsOut
ntfsDenied:
push ERROR_ACCESS_DENIED
jmp ntfsOut
ntfsFail:
push ERROR_FS_FAIL
jmp ntfsOut
ntfsDiskFull:
push ERROR_DISK_FULL
jmp ntfsOut
ntfsErrorPop5:
pop ebx
pop ebx
ntfsErrorPop3:
pop ebx
ntfsErrorPop2:
pop ebx
ntfsErrorPop:
pop ebx
ntfsError:
push eax
ntfsOut:
call ntfs_unlock
xor ebx, ebx
pop eax
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/fs/fs_common.inc
0,0 → 1,142
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2016. All rights reserved. ;;
;; Distributed under terms of the GNU General Public License. ;;
;; ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
$Revision$
 
fsReadCMOS:
out 70h, al
in al, 71h
xor ah, ah
shl ax, 4
shr al, 4
aad
ret
 
fsGetTime:
mov al, 7
call fsReadCMOS
ror eax, 8
mov al, 8
call fsReadCMOS
ror eax, 8
mov al, 9
call fsReadCMOS
add eax, 2000
ror eax, 16
push eax
xor eax, eax
call fsReadCMOS
ror eax, 8
mov al, 2
call fsReadCMOS
ror eax, 8
mov al, 4
call fsReadCMOS
ror eax, 16
push eax
mov esi, esp
add esp, 8
fsCalculateTime:
; in: esi -> data block
; out: eax = seconds since 01.01.2001
movzx eax, word [esi+6]
sub eax, 2001
jnc @f
xor eax, eax
@@:
mov edx, months
mov ebx, eax
inc eax
test eax, 3
jnz @f
add edx, 12
@@:
movzx eax, byte [esi+5]
dec eax
xor ecx, ecx
@@:
dec eax
js @f
add cl, [edx+eax]
adc ch, 0
jmp @b
@@:
mov eax, ebx ; years
mov edx, 365
mul edx
shr ebx, 2
add eax, ebx
add eax, ecx
mov bl, [esi+4]
dec eax
add eax, ebx ; days
mov dl, 24
mul edx
mov bl, [esi+2]
add eax, ebx ; hours
mov ecx, 60
mul ecx
mov bl, [esi+1]
add eax, ebx ; minutes
mul ecx
mov bl, [esi]
add eax, ebx
ret
 
iglobal
months db 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
months2 db 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
endg
 
fsTime2bdfe:
; in: eax = seconds since 01.01.2001
; edi -> data block
; out: edi = edi+8
xor edx, edx
mov ecx, 60
div ecx
mov [edi], dl
xor edx, edx
div ecx
mov [edi+1], dl
xor edx, edx
mov cl, 24
div ecx
mov [edi+2], dx
xor edx, edx
mov cx, 365
div ecx
mov ebx, eax
add ebx, 2001
shr eax, 2
sub edx, eax
jns @f
dec ebx
add edx, 365
test ebx, 3
jnz @f
inc edx
@@:
xor eax, eax
mov ecx, months-1
test ebx, 3
jnz @f
add ecx, 12
@@:
inc ecx
inc eax
sub dl, [ecx]
jnc @b
dec dh
jns @b
add dl, [ecx]
inc edx
mov [edi+4], dl
mov [edi+5], al
mov [edi+6], bx
add edi, 8
ret
Property changes:
Added: svn:eol-style
+native
\ No newline at end of property
Added: svn:keywords
+Rev
\ No newline at end of property
/kernel/branches/kolibrios-pe-clevermouse/fs/.
Property changes:
Added: svn:ignore
+*.mnt
+lang.inc
+*.bat
+out.txt
+scin*
+*.obj