/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 |