2009-09-17 15:55:38 +04:00
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; ;;
|
2010-01-15 14:54:11 +03:00
|
|
|
;; Copyright (C) KolibriOS team 2004-2009. All rights reserved. ;;
|
2009-09-17 15:55:38 +04:00
|
|
|
;; Distributed under terms of the GNU General Public License ;;
|
|
|
|
;; ;;
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
|
2009-10-12 18:39:59 +04:00
|
|
|
$Revision$
|
2009-09-17 15:55:38 +04:00
|
|
|
|
|
|
|
|
|
|
|
image_of_eax EQU esp+36
|
|
|
|
image_of_ebx EQU esp+24
|
|
|
|
|
|
|
|
; 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 2,'fd'
|
|
|
|
dd fs_OnFloppy
|
|
|
|
dd fs_NextFloppy
|
|
|
|
db 10,'floppydisk'
|
|
|
|
dd fs_OnFloppy
|
|
|
|
dd fs_NextFloppy
|
|
|
|
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 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 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 fs_HasCd0
|
|
|
|
db 'cd0',0
|
|
|
|
dd fs_HasCd1
|
|
|
|
db 'cd1',0
|
|
|
|
dd fs_HasCd2
|
|
|
|
db 'cd2',0
|
|
|
|
dd fs_HasCd3
|
|
|
|
db 'cd3',0
|
|
|
|
;**********************************************
|
|
|
|
dd 0
|
|
|
|
|
|
|
|
fs_additional_handlers:
|
|
|
|
dd biosdisk_handler, biosdisk_enum_root
|
|
|
|
; add new handlers here
|
|
|
|
dd 0
|
|
|
|
|
|
|
|
endg
|
|
|
|
|
|
|
|
file_system_lfn:
|
|
|
|
; in: eax->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
|
|
|
|
xchg ebx, eax
|
|
|
|
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
|
2010-01-15 14:54:11 +03:00
|
|
|
jz .notfound
|
2009-09-17 15:55:38 +04:00
|
|
|
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_OnFloppy:
|
|
|
|
cmp ecx, 2
|
|
|
|
ja file_system_lfn.notfound
|
|
|
|
mov eax, [ebx]
|
|
|
|
cmp eax, fs_NumFloppyServices
|
|
|
|
jae fs_OnRamdisk.not_impl
|
|
|
|
call reserve_flp
|
|
|
|
mov [flp_number], cl
|
|
|
|
mov ecx, [ebx+12]
|
|
|
|
mov edx, [ebx+16]
|
|
|
|
; add edx, std_application_base_address
|
|
|
|
add ebx, 4
|
|
|
|
call dword [fs_FloppyServices + eax*4]
|
|
|
|
and [flp_status], 0
|
|
|
|
mov [image_of_eax], eax
|
|
|
|
mov [image_of_ebx], ebx
|
|
|
|
ret
|
|
|
|
|
|
|
|
fs_FloppyServices:
|
|
|
|
dd fs_FloppyRead
|
|
|
|
dd fs_FloppyReadFolder
|
|
|
|
dd fs_FloppyRewrite
|
|
|
|
dd fs_FloppyWrite
|
|
|
|
dd fs_FloppySetFileEnd
|
|
|
|
dd fs_FloppyGetFileInfo
|
|
|
|
dd fs_FloppySetFileInfo
|
|
|
|
dd 0
|
|
|
|
dd fs_FloppyDelete
|
|
|
|
dd fs_FloppyCreateFolder
|
|
|
|
fs_NumFloppyServices = ($ - fs_FloppyServices)/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 [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_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
|
|
|
|
fs_OnCd:
|
|
|
|
call reserve_cd_channel
|
|
|
|
pop eax
|
|
|
|
mov [cdpos], eax
|
|
|
|
pop eax
|
|
|
|
cmp ecx, 0x100
|
|
|
|
jae .nf
|
|
|
|
push ecx ebx
|
|
|
|
mov cl,al
|
|
|
|
mov bl,[DRIVE_DATA+1]
|
|
|
|
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_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<N>/... - 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<N>
|
|
|
|
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
|
|
|
|
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 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:
|
2010-01-15 14:54:11 +03:00
|
|
|
; 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
|
2009-09-17 15:55:38 +04:00
|
|
|
jz .set
|
2010-01-15 14:54:11 +03:00
|
|
|
dec ebx
|
2009-09-17 15:55:38 +04:00
|
|
|
jz .get
|
|
|
|
ret
|
|
|
|
.get:
|
|
|
|
; sysfunction 30.2: [for app] eax=30,ebx=2,ecx->buffer,edx=len
|
|
|
|
; for our code: ebx->buffer,ecx=len
|
2010-01-15 14:54:11 +03:00
|
|
|
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
|
2009-09-17 15:55:38 +04:00
|
|
|
@@:
|
2010-01-15 14:54:11 +03:00
|
|
|
;source string
|
|
|
|
pop esi
|
|
|
|
;destination string
|
|
|
|
pop edi
|
|
|
|
cmp edx, 1
|
2009-09-17 15:55:38 +04:00
|
|
|
jbe .ret
|
2010-01-15 14:54:11 +03:00
|
|
|
|
|
|
|
mov al,'/' ;start string with '/'
|
2009-09-17 15:55:38 +04:00
|
|
|
stosb
|
2010-01-15 14:54:11 +03:00
|
|
|
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]
|
2009-09-17 15:55:38 +04:00
|
|
|
ret
|
|
|
|
.set:
|
|
|
|
; sysfunction 30.1: [for app] eax=30,ebx=1,ecx->string
|
|
|
|
; for our code: ebx->string to set
|
2010-01-15 14:54:11 +03:00
|
|
|
; 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
|
2009-09-17 15:55:38 +04:00
|
|
|
@@:
|
|
|
|
inc esi
|
|
|
|
cmp byte [esi-1], 0
|
|
|
|
jnz @b
|
|
|
|
dec esi
|
|
|
|
cmp byte [ebx], '/'
|
|
|
|
jz .set_absolute
|
|
|
|
; string gives relative path
|
2010-01-15 14:54:11 +03:00
|
|
|
mov edi, [esp+8] ; destination
|
2009-09-17 15:55:38 +04:00
|
|
|
.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
|
2010-01-15 14:54:11 +03:00
|
|
|
.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
|
2009-09-17 15:55:38 +04:00
|
|
|
.doset_relative:
|
2010-01-15 14:54:11 +03:00
|
|
|
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
|
2009-09-17 15:55:38 +04:00
|
|
|
@@:
|
|
|
|
mov al, [ebx]
|
|
|
|
inc ebx
|
2010-01-15 14:54:11 +03:00
|
|
|
stosb
|
2009-09-17 15:55:38 +04:00
|
|
|
test al, al
|
2010-01-15 14:54:11 +03:00
|
|
|
jz .ret.ok
|
|
|
|
cmp edi, edx
|
2009-09-17 15:55:38 +04:00
|
|
|
jb @b
|
2010-01-15 14:54:11 +03:00
|
|
|
.overflow:
|
|
|
|
dec edi
|
|
|
|
jmp .fail
|
2009-09-17 15:55:38 +04:00
|
|
|
.set_absolute:
|
|
|
|
lea esi, [ebx+1]
|
|
|
|
call process_replace_file_name
|
2010-01-15 14:54:11 +03:00
|
|
|
mov edi, [esp+8]
|
|
|
|
mov edx, [esp+12]
|
|
|
|
add edx, edi
|
2009-09-17 15:55:38 +04:00
|
|
|
.set_copy:
|
|
|
|
lodsb
|
|
|
|
stosb
|
|
|
|
test al, al
|
|
|
|
jz .set_part2
|
|
|
|
.set_copy_cont:
|
|
|
|
cmp edi, edx
|
|
|
|
jb .set_copy
|
2010-01-15 14:54:11 +03:00
|
|
|
jmp .overflow
|
2009-09-17 15:55:38 +04:00
|
|
|
.set_part2:
|
|
|
|
mov esi, ebp
|
|
|
|
xor ebp, ebp
|
|
|
|
test esi, esi
|
2010-01-15 14:54:11 +03:00
|
|
|
jz .ret.ok
|
2009-09-17 15:55:38 +04:00
|
|
|
mov byte [edi-1], '/'
|
|
|
|
jmp .set_copy_cont
|