;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; Copyright (C) KolibriOS team 2013-2024. All rights reserved. ;; ;; Distributed under terms of the GNU General Public License. ;; ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; 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 - 8) / 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