;; ;; ;; Copyright (C) KolibriOS team 2004-2009. All rights reserved. ;; ;; Distributed under terms of the GNU General Public License ;; ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; $Revision$ 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 2,'rd' dd fs_OnRamdisk dd fs_NextRamdisk db 7,'ramdisk' dd fs_OnRamdisk dd fs_NextRamdisk db 3,'hd0' dd fs_OnHd0 dd fs_NextHd0 db 3,'hd1' dd fs_OnHd1 dd fs_NextHd1 db 3,'hd2' dd fs_OnHd2 dd fs_NextHd2 db 3,'hd3' dd fs_OnHd3 dd fs_NextHd3 db 0 virtual_root_query: dd fs_HasRamdisk db 'rd',0 dd fs_HasFloppy db 'fd',0 dd fs_HasHd0 db 'hd0',0 dd fs_HasHd1 db 'hd1',0 dd fs_HasHd2 db 'hd2',0 dd fs_HasHd3 db 'hd3',0 dd 0 fs_additional_handlers: dd biosdisk_handler, biosdisk_enum_root ; add new handlers here dd 0 endg 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 @@: 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: cmp dword [ebx], 7 jne @F mov edx, [ebx+4] mov ebx, [ebx+8] call fs_execute ; esi+ebp, ebx, edx mov [image_of_eax], eax ret @@: 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] ; mov edx, [ebx+16] ; ; 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 esi, virtual_root_query 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 .readroot_loop: cmp dword [esi], eax jz .readroot_done_static 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_static: mov esi, fs_additional_handlers-8 sub esp, 16 .readroot_ah_loop: add esi, 8 cmp dword [esi], 0 jz .readroot_done xor eax, eax .readroot_ah_loop2: push edi lea edi, [esp+4] call dword [esi+4] pop edi test eax, eax jz .readroot_ah_loop 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: add esp, 16 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: mov edi, fs_additional_handlers @@: cmp dword [edi], 0 jz .notfound call dword [edi] scasd scasd jmp @b .notfound: mov dword [image_of_eax], ERROR_FILE_NOT_FOUND and dword [image_of_ebx], 0 ret .notfounda: cmp edi, esp jnz .notfound add esp, 8 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_OnRamdisk: cmp ecx, 1 jnz file_system_lfn.notfound mov eax, [ebx] cmp eax, fs_NumRamdiskServices jae .not_impl mov ecx, [ebx+12] mov edx, [ebx+16] ; add edx, std_application_base_address add ebx, 4 call dword [fs_RamdiskServices + eax*4] mov [image_of_eax], eax mov [image_of_ebx], ebx ret .not_impl: mov dword [image_of_eax], 2 ; not implemented ret fs_NotImplemented: mov eax, 2 ret fs_RamdiskServices: dd fs_RamdiskRead dd fs_RamdiskReadFolder dd fs_RamdiskRewrite dd fs_RamdiskWrite dd fs_RamdiskSetFileEnd dd fs_RamdiskGetFileInfo dd fs_RamdiskSetFileInfo dd 0 dd fs_RamdiskDelete dd fs_RamdiskCreateFolder fs_NumRamdiskServices = ($ - fs_RamdiskServices)/4 fs_OnHd0: call reserve_hd1 mov [hdbase], 0x1F0 mov [hdid], 0 push 1 jmp fs_OnHd fs_OnHd1: call reserve_hd1 mov [hdbase], 0x1F0 mov [hdid], 0x10 push 2 jmp fs_OnHd fs_OnHd2: call reserve_hd1 mov [hdbase], 0x170 mov [hdid], 0 push 3 jmp fs_OnHd fs_OnHd3: call reserve_hd1 mov [hdbase], 0x170 mov [hdid], 0x10 push 4 fs_OnHd: call reserve_hd_channel pop eax mov [hdpos], eax cmp ecx, 0x100 jae fs_OnHdAndBd.nf cmp cl, [DRIVE_DATA+1+eax] fs_OnHdAndBd: jbe @f .nf: call free_hd_channel and [hd1_status], 0 mov dword [image_of_eax], 5 ; not found ret @@: mov [known_part], ecx ; mov [fat32part], ecx push ebx esi call choice_necessity_partition_1 pop esi ebx mov ecx, [ebx+12] mov edx, [ebx+16] ; add edx, std_application_base_address mov eax, [ebx] cmp eax, fs_NumHdServices jae .not_impl add ebx, 4 call dword [fs_HdServices + eax*4] call free_hd_channel and [hd1_status], 0 mov [image_of_eax], eax mov [image_of_ebx], ebx ret .not_impl: call free_hd_channel and [hd1_status], 0 mov dword [image_of_eax], 2 ; not implemented ret fs_HdServices: dd fs_HdRead dd fs_HdReadFolder dd fs_HdRewrite dd fs_HdWrite dd fs_HdSetFileEnd dd fs_HdGetFileInfo dd fs_HdSetFileInfo dd 0 dd fs_HdDelete dd fs_HdCreateFolder fs_NumHdServices = ($ - fs_HdServices)/4 fs_HasRamdisk: mov al, 1 ; we always have ramdisk ret fs_HasFloppy: cmp byte [DRIVE_DATA], 0 setnz al ret fs_HasHd0: mov al, [DRIVE_DATA+1] and al, 11000000b cmp al, 01000000b setz al ret fs_HasHd1: mov al, [DRIVE_DATA+1] and al, 00110000b cmp al, 00010000b setz al ret fs_HasHd2: mov al, [DRIVE_DATA+1] and al, 00001100b cmp al, 00000100b setz al ret fs_HasHd3: mov al, [DRIVE_DATA+1] and al, 00000011b cmp al, 00000001b setz al ret ;******************************************************* fs_HasCd0: mov al, [DRIVE_DATA+1] and al, 11000000b cmp al, 10000000b setz al ret fs_HasCd1: mov al, [DRIVE_DATA+1] and al, 00110000b cmp al, 00100000b setz al ret fs_HasCd2: mov al, [DRIVE_DATA+1] and al, 00001100b cmp al, 00001000b setz al ret fs_HasCd3: mov al, [DRIVE_DATA+1] and al, 00000011b cmp al, 00000010b setz 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_NextRamdisk: ; we always have /rd/1 test eax, eax stc jnz @f mov al, 1 clc @@: ret fs_NextFloppy: ; we have /fd/1 iff (([DRIVE_DATA] and 0xF0) != 0) and /fd/2 iff (([DRIVE_DATA] and 0x0F) != 0) test byte [DRIVE_DATA], 0xF0 jz .no1 test eax, eax jnz .no1 inc eax ret ; CF cleared .no1: test byte [DRIVE_DATA], 0x0F jz .no2 cmp al, 2 jae .no2 mov al, 2 clc ret .no2: stc ret ; on hdx, we have partitions from 1 to [0x40002+x] fs_NextHd0: push 0 jmp fs_NextHd fs_NextHd1: push 1 jmp fs_NextHd fs_NextHd2: push 2 jmp fs_NextHd fs_NextHd3: push 3 fs_NextHd: pop ecx movzx ecx, byte [DRIVE_DATA+2+ecx] cmp eax, ecx jae fs_NextFloppy.no2 inc eax clc ret ;******************************************************* fs_NextCd: ; we always have /cdX/1 test eax, eax stc jnz @f mov al, 1 clc @@: ret ;******************************************************* ; Additional FS handlers. ; This handler gets the control each time when fn 70 is called ; with unknown item of root subdirectory. ; in: esi -> name ; ebp = 0 or rest of name relative to esi ; out: if the handler processes path, he must not return in file_system_lfn, ; but instead pop return address and return directly to the caller ; otherwise simply return ; here we test for /bd/... - BIOS disks biosdisk_handler: cmp [NumBiosDisks], 0 jz .ret mov al, [esi] or al, 20h cmp al, 'b' jnz .ret mov al, [esi+1] or al, 20h cmp al, 'd' jnz .ret push esi inc esi inc esi cmp byte [esi], '0' jb .ret2 cmp byte [esi], '9' ja .ret2 xor edx, edx @@: lodsb test al, al jz .ok cmp al, '/' jz .ok sub al, '0' cmp al, 9 ja .ret2 lea edx, [edx*5] lea edx, [edx*2+eax] jmp @b .ret2: pop esi .ret: ret .ok: cmp al, '/' jz @f dec esi @@: add dl, 80h xor ecx, ecx @@: cmp dl, [BiosDisksData+ecx*4] jz .ok2 inc ecx cmp ecx, [NumBiosDisks] jb @b jmp .ret2 .ok2: add esp, 8 test al, al jnz @f mov esi, fs_BdNext jmp file_system_lfn.maindir_noesi @@: push ecx push fs_OnBd mov edi, esp jmp file_system_lfn.found2 fs_BdNext: cmp eax, [BiosDiskPartitions+ecx*4] inc eax cmc ret fs_OnBd: pop edx edx ; edx = disk number, ecx = partition number ; esi+ebp = name call reserve_hd1 add edx, 0x80 mov [hdpos], edx cmp ecx, [BiosDiskPartitions+(edx-0x80)*4] jmp fs_OnHdAndBd ; This handler is called when virtual root is enumerated ; and must return all items which can be handled by this. ; It is called several times, first time with eax=0 ; in: eax = 0 for first call, previously returned value for subsequent calls ; out: eax = 0 => no more items ; eax != 0 => buffer pointed to by edi contains name of item ; here we enumerate existing BIOS disks /bd biosdisk_enum_root: cmp eax, [NumBiosDisks] jae .end push eax movzx eax, byte [BiosDisksData+eax*4] sub al, 80h push eax mov al, 'b' stosb mov al, 'd' stosb pop eax cmp al, 10 jae .big add al, '0' stosb mov byte [edi], 0 pop eax inc eax ret .end: xor eax, eax ret .big: push ecx edx push -'0' mov ecx, 10 @@: xor edx, edx div ecx push edx test eax, eax jnz @b xchg eax, edx @@: pop eax add al, '0' stosb jnz @b pop edx ecx pop eax inc eax ret process_replace_file_name: mov ebp, [full_file_name_table] mov edi, [full_file_name_table.size] dec edi shl edi, 7 add edi, ebp .loop: cmp edi, ebp jb .notfound push esi edi @@: cmp byte [edi], 0 jz .dest_done lodsb test al, al jz .cont or al, 20h 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 sub edi, 128 jmp .loop .found: pop edi eax mov ebp, esi cmp byte [esi], 0 lea esi, [edi+64] jnz .ret .notfound: xor ebp, ebp .ret: ret 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 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 ; =============== moved from fs/iso9660.inc char_todown: ; convert character to uppercase, using cp866 encoding ; in: al=symbol ; out: al=converted symbol cmp al, 'A' jb .ret cmp al, 'Z' jbe .az cmp al, '' jb .ret cmp al, '' jb .rus1 cmp al, '' ja .ret ; 0x90-0x9F -> 0xE0-0xEF add al, ''-'' .ret: ret .rus1: ; 0x80-0x8F -> 0xA0-0xAF .az: add al, 0x20 ret uni2ansi_char: ; convert UNICODE character in al to ANSI character in ax, using cp866 encoding ; in: ax=UNICODE character ; out: al=converted ANSI character cmp ax, 0x80 jb .ascii cmp ax, 0x401 jz .yo1 cmp ax, 0x451 jz .yo2 cmp ax, 0x410 jb .unk cmp ax, 0x440 jb .rus1 cmp ax, 0x450 jb .rus2 .unk: mov al, '_' jmp .doit .yo1: mov al, '' jmp .doit .yo2: mov al, '' jmp .doit .rus1: ; 0x410-0x43F -> 0x80-0xAF add al, 0x70 jmp .doit .rus2: ; 0x440-0x44F -> 0xE0-0xEF add al, 0xA0 .ascii: .doit: ret