kolibrios-fun/kernel/branches/net/fs/fs_lfn.inc
hidnplayr fbf1d3eec3 Syncing net branch with trunk.
git-svn-id: svn://kolibrios.org@3187 a494cfbc-eb01-0410-851d-a64ba20cac60
2013-01-21 20:59:27 +00:00

1164 lines
30 KiB
PHP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; ;;
;; Copyright (C) KolibriOS team 2004-2011. 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
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 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
dd dyndisk_handler, dyndisk_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
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_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 [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_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 ecx
push biosdisk_cleanup
push fs_OnBd
mov edi, esp
jmp file_system_lfn.found2
fs_BdNext:
cmp eax, [BiosDiskPartitions+ecx*4]
inc eax
cmc
biosdisk_cleanup:
ret
fs_OnBd:
pop edx edx 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 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