;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; Copyright (C) KolibriOS team 2004-2015. 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_FAT_TABLE = 9 ;deprecated ERROR_FS_FAIL = 9 ERROR_ACCESS_DENIED = 10 ERROR_DEVICE = 11 ERROR_OUT_OF_MEMORY = 12 image_of_eax EQU esp+32 image_of_ebx EQU esp+20 ; System function 70 - files with long names (LFN) ; diamond, 2006 iglobal ; in this table names must be in lowercase rootdirs: ;********************************************** db 3,'cd0' dd fs_OnCd0 dd fs_NextCd db 3,'cd1' dd fs_OnCd1 dd fs_NextCd db 3,'cd2' dd fs_OnCd2 dd fs_NextCd db 3,'cd3' dd fs_OnCd3 dd fs_NextCd db 3,'cd4' dd fs_OnCd4 dd fs_NextCd db 3,'cd5' dd fs_OnCd5 dd fs_NextCd db 3,'cd6' dd fs_OnCd6 dd fs_NextCd db 3,'cd7' dd fs_OnCd7 dd fs_NextCd db 3,'cd8' dd fs_OnCd8 dd fs_NextCd db 3,'cd9' dd fs_OnCd9 dd fs_NextCd db 4,'cd10' dd fs_OnCd10 dd fs_NextCd db 4,'cd11' dd fs_OnCd11 dd fs_NextCd ;*********************************************** db 0 virtual_root_query: ;********************************************** dd fs_HasCd0 db 'cd0',0 dd fs_HasCd1 db 'cd1',0 dd fs_HasCd2 db 'cd2',0 dd fs_HasCd3 db 'cd3',0 dd fs_HasCd4 db 'cd4',0 dd fs_HasCd5 db 'cd5',0 dd fs_HasCd6 db 'cd6',0 dd fs_HasCd7 db 'cd7',0 dd fs_HasCd8 db 'cd8',0 dd fs_HasCd9 db 'cd9',0 dd fs_HasCd10 db 'cd10',0 dd fs_HasCd11 db 'cd11',0 ;********************************************** dd 0 endg 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 file_system_lfn: ; in: ebx->fileinfo block ; operation codes: ; 0 : read file ; 1 : read folder ; 2 : create/rewrite file ; 3 : write/append to file ; 4 : set end of file ; 5 : get file/directory attributes structure ; 6 : set file/directory attributes structure ; 7 : start application ; 8 : delete file ; 9 : create directory ; parse file name lea esi, [ebx+20] lodsb test al, al jnz @f mov esi, [esi] lodsb @@: lea ebp, [esi-1] cmp dword [ebx], 7 jne @F mov edx, [ebx+4] mov ebx, [ebx+8] call fs_execute; ebp, ebx, edx mov [image_of_eax], eax ret @@: cmp al, '/' jz .notcurdir dec esi mov ebp, esi test al, al jnz @f xor ebp, ebp @@: mov esi, [current_slot] mov esi, [esi+APPDATA.cur_dir] jmp .parse_normal .notcurdir: cmp byte [esi], 0 jz .rootdir call process_replace_file_name .parse_normal: mov edi, rootdirs-8 xor ecx, ecx push esi .scan1: pop esi add edi, ecx scasd scasd mov cl, byte [edi] test cl, cl jz .notfound_try inc edi push esi @@: lodsb or al, 20h scasb loopz @b jnz .scan1 lodsb cmp al, '/' jz .found1 test al, al jnz .scan1 pop eax ; directory /xxx .maindir: mov esi, [edi+4] .maindir_noesi: cmp dword [ebx], 1 jnz .access_denied xor eax, eax mov ebp, [ebx+12] ;the number of blocks to read mov edx, [ebx+16] ;where to write the result ; add edx, std_application_base_address push dword [ebx+4] ; first block mov ebx, [ebx+8] ; flags ; ebx=flags, [esp]=first block, ebp=number of blocks, edx=return area, esi='Next' handler mov edi, edx push ecx mov ecx, 32/4 rep stosd pop ecx 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], 0x10 ; attributes: folder mov dword [edi+4], 1 ; name type: UNICODE push eax xor eax, eax add edi, 8 push ecx mov ecx, 40/4-2 rep stosd pop ecx pop eax push eax edx ; convert number in eax to decimal UNICODE string push edi push ecx push -'0' mov ecx, 10 @@: xor edx, edx div ecx push edx test eax, eax jnz @b @@: pop eax add al, '0' stosb test bl, 1 ; UNICODE name? jz .ansi2 mov byte [edi], 0 inc edi .ansi2: test al, al jnz @b mov byte [edi-1], 0 pop ecx pop edi ; UNICODE name length is 520 bytes, ANSI - 264 add edi, 520 test bl, 1 jnz @f sub edi, 520-264 @@: pop edx eax jmp .maindir_loop .maindir_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 ; directory / .rootdir: cmp dword [ebx], 1 ; read folder? jz .readroot .access_denied: mov dword [image_of_eax], 10 ; access denied ret .readroot: ; virtual root folder - special handler mov ebp, [ebx+12] mov edx, [ebx+16] ; add edx, std_application_base_address push dword [ebx+4] ; first block mov ebx, [ebx+8] ; flags xor eax, eax ; eax=0, [esp]=first block, ebx=flags, ebp=number of blocks, edx=return area mov edi, edx mov ecx, 32/4 rep stosd mov byte [edx], 1 ; version sub esp, 16 .readroot_ah_loop2: push edi lea edi, [esp+4] call dyndisk_enum_root pop edi test eax, eax jz .readroot_done_dynamic inc dword [edx+8] dec dword [esp+16] jns .readroot_ah_loop2 dec ebp js .readroot_ah_loop2 push eax xor eax, eax inc dword [edx+4] mov dword [edi], 0x10 ; attributes: folder mov dword [edi+4], ebx add edi, 8 mov ecx, 40/4-2 rep stosd push esi edi lea esi, [esp+12] @@: lodsb stosb test bl, 1 jz .ansi3 mov byte [edi], 0 inc edi .ansi3: test al, al jnz @b pop edi esi eax add edi, 520 test bl, 1 jnz .readroot_ah_loop2 sub edi, 520-264 jmp .readroot_ah_loop2 .readroot_done_dynamic: add esp, 16 mov esi, virtual_root_query .readroot_loop: cmp dword [esi], eax jz .readroot_done call dword [esi] add esi, 4 test eax, eax jnz @f .readroot_next: or ecx, -1 xchg esi, edi repnz scasb xchg esi, edi jmp .readroot_loop @@: xor eax, eax inc dword [edx+8] dec dword [esp] jns .readroot_next dec ebp js .readroot_next inc dword [edx+4] mov dword [edi], 0x10 ; attributes: folder mov dword [edi+4], ebx ; name type: UNICODE add edi, 8 mov ecx, 40/4-2 rep stosd push edi @@: lodsb stosb test bl, 1 jz .ansi mov byte [edi], 0 inc edi .ansi: test eax, eax jnz @b pop edi add edi, 520 test bl, 1 jnz .readroot_loop sub edi, 520-264 jmp .readroot_loop .readroot_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 .notfound_try: call dyndisk_handler .notfound: mov dword [image_of_eax], ERROR_FILE_NOT_FOUND and dword [image_of_ebx], 0 ret .notfounda: cmp edi, esp jnz .notfound call dword [edi+4] add esp, 16 jmp .notfound .found1: pop eax cmp byte [esi], 0 jz .maindir .found2: ; read partition number xor ecx, ecx xor eax, eax @@: lodsb cmp al, '/' jz .done1 test al, al jz .done1 sub al, '0' cmp al, 9 ja .notfounda lea ecx, [ecx*5] lea ecx, [ecx*2+eax] jmp @b .done1: jecxz .notfounda test al, al jnz @f dec esi @@: cmp byte [esi], 0 jnz @f test ebp, ebp jz @f mov esi, ebp xor ebp, ebp @@: ; now [edi] contains handler address, ecx - partition number, ; esi points to ASCIIZ string - rest of name jmp dword [edi] ; handlers for devices ; in: ecx = 0 => query virtual directory /xxx ; in: ecx = partition number ; esi -> relative (for device) name ; ebx -> fileinfo ; ebp = 0 or pointer to rest of name from folder addressed by esi ; out: [image_of_eax]=image of eax, [image_of_ebx]=image of ebx fs_NotImplemented: mov eax, 2 ret ;----------------------------------------------------------------------------- fs_OnCd0: call reserve_cd mov [ChannelNumber], 1 mov [DiskNumber], 0 push 6 push 1 jmp fs_OnCd ;----------------------------------------------------------------------------- fs_OnCd1: call reserve_cd mov [ChannelNumber], 1 mov [DiskNumber], 1 push 4 push 2 jmp fs_OnCd ;----------------------------------------------------------------------------- fs_OnCd2: call reserve_cd mov [ChannelNumber], 2 mov [DiskNumber], 0 push 2 push 3 jmp fs_OnCd ;----------------------------------------------------------------------------- fs_OnCd3: call reserve_cd mov [ChannelNumber], 2 mov [DiskNumber], 1 push 0 push 4 jmp fs_OnCd ;----------------------------------------------------------------------------- fs_OnCd4: call reserve_cd mov [ChannelNumber], 1 mov [DiskNumber], 0 push 6 push 5 jmp fs_OnCd ;----------------------------------------------------------------------------- fs_OnCd5: call reserve_cd mov [ChannelNumber], 1 mov [DiskNumber], 1 push 4 push 6 jmp fs_OnCd ;----------------------------------------------------------------------------- fs_OnCd6: call reserve_cd mov [ChannelNumber], 2 mov [DiskNumber], 0 push 2 push 7 jmp fs_OnCd ;----------------------------------------------------------------------------- fs_OnCd7: call reserve_cd mov [ChannelNumber], 2 mov [DiskNumber], 1 push 0 push 8 jmp fs_OnCd ;----------------------------------------------------------------------------- fs_OnCd8: call reserve_cd mov [ChannelNumber], 1 mov [DiskNumber], 0 push 6 push 9 jmp fs_OnCd ;----------------------------------------------------------------------------- fs_OnCd9: call reserve_cd mov [ChannelNumber], 1 mov [DiskNumber], 1 push 4 push 10 jmp fs_OnCd ;----------------------------------------------------------------------------- fs_OnCd10: call reserve_cd mov [ChannelNumber], 2 mov [DiskNumber], 0 push 2 push 11 jmp fs_OnCd ;----------------------------------------------------------------------------- fs_OnCd11: call reserve_cd mov [ChannelNumber], 2 mov [DiskNumber], 1 push 0 push 12 ;----------------------------------------------------------------------------- fs_OnCd: pop eax mov [cdpos], eax call reserve_cd_channel pop eax cmp ecx, 0x100 jae .nf push ecx ebx mov cl, al push eax mov eax, [cdpos] dec eax shr eax, 2 lea eax, [eax*5] mov bl, [eax+DRIVE_DATA+1] pop eax shr bl, cl test bl, 2 pop ebx ecx jnz @f .nf: call free_cd_channel and [cd_status], 0 mov dword [image_of_eax], 5 ; not found ret @@: mov ecx, [ebx+12] mov edx, [ebx+16] ; add edx, std_application_base_address mov eax, [ebx] cmp eax, fs_NumCdServices jae .not_impl add ebx, 4 call dword [fs_CdServices + eax*4] call free_cd_channel and [cd_status], 0 mov [image_of_eax], eax mov [image_of_ebx], ebx ret .not_impl: call free_cd_channel and [cd_status], 0 mov dword [image_of_eax], 2 ; not implemented ret ;----------------------------------------------------------------------------- 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 ;----------------------------------------------------------------------------- fs_HasCd0: test byte [DRIVE_DATA+1], 10000000b setnz al ret ;-------------------------------------- fs_HasCd1: test byte [DRIVE_DATA+1], 00100000b setnz al ret ;-------------------------------------- fs_HasCd2: test byte [DRIVE_DATA+1], 00001000b setnz al ret ;-------------------------------------- fs_HasCd3: test byte [DRIVE_DATA+1], 00000010b setnz al ret ;-------------------------------------- fs_HasCd4: test byte [DRIVE_DATA+6], 10000000b setnz al ret ;-------------------------------------- fs_HasCd5: test byte [DRIVE_DATA+6], 00100000b setnz al ret ;-------------------------------------- fs_HasCd6: test byte [DRIVE_DATA+6], 00001000b setnz al ret ;-------------------------------------- fs_HasCd7: test byte [DRIVE_DATA+6], 00000010b setnz al ret ;-------------------------------------- fs_HasCd8: test byte [DRIVE_DATA+11], 10000000b setnz al ret ;-------------------------------------- fs_HasCd9: test byte [DRIVE_DATA+11], 00100000b setnz al ret ;-------------------------------------- fs_HasCd10: test byte [DRIVE_DATA+11], 00001000b setnz al ret ;-------------------------------------- fs_HasCd11: test byte [DRIVE_DATA+11], 00000010b setnz al ret ;----------------------------------------------------------------------------- ; ; fs_NextXXX functions: ; in: eax = partition number, from which start to scan ; out: CF=1 => no more partitions ; CF=0 => eax=next partition number ; ;----------------------------------------------------------------------------- fs_NextCd: ; we always have /cdX/1 test eax, eax stc jnz @f mov al, 1 clc @@: ret ;----------------------------------------------------------------------------- process_replace_file_name: ; in ; esi - path with filename(f.70) ; ; out ; ebp - full filename pushfd cli mov ebp, [full_file_name_table] xor edi, edi .loop: cmp edi, [full_file_name_table.size] jae .notfound push esi edi shl edi, 7 ; edi*128 add edi, ebp @@: cmp byte [edi], 0 ; end of dir_name jz .dest_done lodsb test al, al jz .cont or al, 20h ; 32 - space char scasb jz @b jmp .cont .dest_done: cmp byte [esi], 0 jz .found cmp byte [esi], '/' jnz .cont inc esi jmp .found .cont: pop edi esi inc edi jmp .loop .found: pop edi eax shl edi, 7 ; edi*128 add edi, ebp mov ebp, esi cmp byte [esi], 0 lea esi, [edi+64] jnz .ret .notfound: xor ebp, ebp .ret: popfd ret ;----------------------------------------------------------------------------- uglobal lock_flag_for_f30_3 rb 1 endg sys_current_directory: ; mov esi, [current_slot] ; mov esi, [esi+APPDATA.cur_dir] ; mov edx, esi ;get length string of appdata.cur_dir mov eax, [current_slot] mov edi, [eax+APPDATA.cur_dir] dec ebx jz .set dec ebx jz .get dec ebx jz .mount_additional_directory ret .mount_additional_directory: ; sysfunction 30.2: [for app] eax=30,ebx=3,ecx->dir name+dir path (128) ; for our code: nothing ; check lock of the function cmp [lock_flag_for_f30_3], 1 je @f mov esi, ecx mov edi, sysdir_name1 ; copying fake directory name mov ecx, 63 pushfd cli cld rep movsb ; terminator of name, in case if we get the inlet trash inc esi xor eax, eax stosb ; copying real directory path for mounting mov ecx, 63 rep movsb ; terminator of name, in case if we get the inlet trash xor eax, eax stosb ; increase the pointer of inputs for procedure "process_replace_file_name" mov [full_file_name_table.size], 2 ; block the ability to call f.30.3 because for one session is necessary ; for us only once mov [lock_flag_for_f30_3], 1 popfd @@: ret .get: ; sysfunction 30.2: [for app] eax=30,ebx=2,ecx->buffer,edx=len ; for our code: ebx->buffer,ecx=len max_cur_dir equ 0x1000 mov ebx, edi push ecx push edi xor eax, eax mov ecx, max_cur_dir repne scasb ;find zerro at and string jnz .error ; no zero in cur_dir: internal error, should not happen sub edi, ebx ;lenght for copy inc edi mov [esp+32+8], edi ;return in eax cmp edx, edi jbe @f mov edx, edi @@: ;source string pop esi ;destination string pop edi cmp edx, 1 jbe .ret mov al, '/' ;start string with '/' stosb mov ecx, edx rep movsb ;copy string .ret: ret .error: add esp, 8 or dword [esp+32], -1 ;error not found zerro at string ->[eax+APPDATA.cur_dir] ret .set: ; sysfunction 30.1: [for app] eax=30,ebx=1,ecx->string ; for our code: ebx->string to set ; use generic resolver with APPDATA.cur_dir as destination push max_cur_dir ;0x1000 push edi ;destination mov ebx, ecx call get_full_file_name ret ; in: ebx = file name, [esp+4] = destination, [esp+8] = sizeof destination ; destroys all registers except ebp,esp get_full_file_name: push ebp mov esi, [current_slot] mov esi, [esi+APPDATA.cur_dir] mov edx, esi @@: inc esi cmp byte [esi-1], 0 jnz @b dec esi cmp byte [ebx], '/' jz .set_absolute ; string gives relative path mov edi, [esp+8] ; destination .relative: cmp byte [ebx], 0 jz .set_ok cmp word [ebx], '.' jz .set_ok cmp word [ebx], './' jnz @f add ebx, 2 jmp .relative @@: cmp word [ebx], '..' jnz .doset_relative cmp byte [ebx+2], 0 jz @f cmp byte [ebx+2], '/' jnz .doset_relative @@: dec esi cmp byte [esi], '/' jnz @b add ebx, 3 jmp .relative .set_ok: cmp edx, edi ; is destination equal to APPDATA.cur_dir? jz .set_ok.cur_dir sub esi, edx cmp esi, [esp+12] jb .set_ok.copy .fail: mov byte [edi], 0 xor eax, eax ; fail pop ebp ret 8 .set_ok.copy: mov ecx, esi mov esi, edx rep movsb mov byte [edi], 0 .ret.ok: mov al, 1 ; ok pop ebp ret 8 .set_ok.cur_dir: mov byte [esi], 0 jmp .ret.ok .doset_relative: cmp edx, edi jz .doset_relative.cur_dir sub esi, edx cmp esi, [esp+12] jae .fail mov ecx, esi mov esi, edx mov edx, edi rep movsb jmp .doset_relative.copy .doset_relative.cur_dir: mov edi, esi .doset_relative.copy: add edx, [esp+12] mov byte [edi], '/' inc edi cmp edi, edx jae .overflow @@: mov al, [ebx] inc ebx stosb test al, al jz .ret.ok cmp edi, edx jb @b .overflow: dec edi jmp .fail .set_absolute: lea esi, [ebx+1] call process_replace_file_name mov edi, [esp+8] mov edx, [esp+12] add edx, edi .set_copy: lodsb stosb test al, al jz .set_part2 .set_copy_cont: cmp edi, edx jb .set_copy jmp .overflow .set_part2: mov esi, ebp xor ebp, ebp test esi, esi jz .ret.ok mov byte [edi-1], '/' jmp .set_copy_cont