;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; Copyright (C) KolibriOS team 2013-2016. All rights reserved. ;; ;; Distributed under terms of the GNU General Public License. ;; ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; $Revision$ ; 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 - 4) / 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 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 ? 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 PERMISSIONS = 110110110b 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 ? sectorsPerBlockLog dd ? ; shift for 512 bytesPerBlock dd ? sectorsPerBlock dd ? dwordsPerBlock dd ? dwordsPerBranch dd ? ; dwordsPerBlock ^ 2 mainBlockBuffer dd ? tempBlockBuffer 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], 1024 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 [ebp+EXTFS.sectorsPerBlockLog], 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 @@: ; read root inode lea ebx, [ebp+EXTFS.rootInodeBuffer] mov eax, ROOT_INODE call readInode test eax, eax jnz @f mov eax, ebp pop edi esi ebp ebx ret @@: 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 stdcall kernel_free, [eax+EXTFS.mainBlockBuffer] 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 extfsReadDescriptor: ; in: eax = block group number ; out: ; [ebp+EXTFS.tempBlockBuffer] -> relevant block ; eax -> block group descriptor, 0 = error push edx ebx shl eax, 5 xor edx, edx div [ebp+EXTFS.bytesPerBlock] add eax, [ebp+EXTFS.superblock.firstGroupBlock] inc eax mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsReadBlock jc .fail mov eax, ebx add eax, edx @@: pop ebx edx ret .fail: xor eax, eax stc jmp @b extfsWriteDescriptor: ; in: ; eax = block group number ; [ebp+EXTFS.tempBlockBuffer] -> relevant block push edx ebx shl eax, 5 xor edx, edx div [ebp+EXTFS.bytesPerBlock] add eax, [ebp+EXTFS.superblock.firstGroupBlock] inc eax mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsWriteBlock pop ebx edx ret extfsResourceFree: ; in: ; ecx=0 -> block, ecx=1 -> inode ; eax = block/inode number push ebx edx sub eax, [ebp+EXTFS.superblock.firstGroupBlock] xor edx, edx div [ebp+EXTFS.superblock.blocksPerGroup] push eax edx call extfsReadDescriptor jc .fail inc [eax+BGDESCR.blocksFree+ecx*2] mov eax, [eax+BGDESCR.blockBitmap+ecx*4] mov ebx, [ebp+EXTFS.mainBlockBuffer] mov edx, eax call extfsReadBlock jc .fail pop eax push edx mov edx, eax and edx, 31 shr eax, 5 shl eax, 2 add eax, [ebp+EXTFS.mainBlockBuffer] btr [eax], edx pop eax mov ebx, [ebp+EXTFS.mainBlockBuffer] call extfsWriteBlock jc @f inc [ebp+EXTFS.superblock.blocksFree+ecx*4] pop eax call extfsWriteDescriptor .ret: pop edx ebx ret .fail: pop eax @@: pop eax movi eax, ERROR_DEVICE jmp .ret freeDoublyIndirectBlock: ; in: eax = doubly-indirect block number ; out: eax=1 -> finished test eax, eax jz .complete push eax mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsReadBlock pop eax jc .ret xor ecx, ecx call extfsResourceFree mov edx, ebx add edx, [ebp+EXTFS.bytesPerBlock] @@: mov eax, [ebx] test eax, eax jz .complete call extfsResourceFree add ebx, 4 cmp ebx, edx jb @b .ret: xor eax, eax ret .complete: inc eax ret inodeBlockAlloc: ; in: esi -> inode, eax = inode number ; out: ebx = block number call extfsBlockAlloc jc @f mov eax, [ebp+EXTFS.sectorsPerBlock] add [esi+INODE.sectorsUsed], eax xor eax, eax @@: ret extfsBlockAlloc: ; also erases ; in: eax = inode number ; out: ebx = block number xor ebx, ebx call extfsResourceAlloc jc @f push ebx ecx edi mov ecx, [ebp+EXTFS.dwordsPerBlock] mov edi, [ebp+EXTFS.tempBlockBuffer] mov ebx, edi xor eax, eax rep stosd pop edi ecx mov eax, [esp] call extfsWriteBlock pop ebx @@: ret extfsResourceAlloc: ; in: ; eax = inode number ; ebx=0 -> block, ebx=1 -> inode ; out: ; ebx = block/inode number push ecx edx esi edi dec eax xor edx, edx div [ebp+EXTFS.superblock.inodesPerGroup] push eax eax mov esi, .forward ; search forward, then backward .test_block_group: call extfsReadDescriptor jc .fail dec [eax+BGDESCR.blocksFree+ebx*2] mov eax, [eax+BGDESCR.blockBitmap+ebx*4] push ebx mov ebx, [ebp+EXTFS.mainBlockBuffer] mov edx, eax mov edi, ebx call extfsReadBlock pop ebx jc .fail mov ecx, [ebp+EXTFS.superblock.blocksPerGroup+ebx*8] or eax, -1 shr ecx, 5 jz .next repz scasd jz .next sub edi, 4 mov eax, [edi] not eax bsf eax, eax bts [edi], eax sub edi, [ebp+EXTFS.mainBlockBuffer] shl edi, 3 add eax, edi mov ecx, eax mov eax, edx push ebx mov ebx, [ebp+EXTFS.mainBlockBuffer] call extfsWriteBlock pop ebx jc .fail mov eax, [esp] mul [ebp+EXTFS.superblock.blocksPerGroup+ebx*8] add eax, ecx dec [ebp+EXTFS.superblock.blocksFree+ebx*4] mov ebx, eax pop eax add esp, 4 call extfsWriteDescriptor @@: pop edi esi edx ecx ret .fail: pop eax eax movi eax, ERROR_DEVICE jmp @b .next: jmp esi .forward: inc dword[esp] mov eax, [esp] mul [ebp+EXTFS.superblock.blocksPerGroup+ebx*8] neg ebx cmp eax, [ebp+EXTFS.superblock.blocksTotal+ebx*4] ja @f neg ebx mov eax, [esp] jmp .test_block_group @@: neg ebx mov eax, [esp+4] mov [esp], eax mov esi, .backward .backward: sub dword[esp], 1 jc .fail mov eax, [esp] jmp .test_block_group extfsGetFileBlock: ; in: ; ecx = file block number ; esi -> inode ; out: ; ecx = block number test [esi+INODE.featureFlags], EXTENTS_USED jz .listTreeSearch pushad add esi, INODE.blockNumbers .extentTreeSearch: cmp word [esi+NODEHEADER.magic], 0xF30A jne .fail movzx ebx, [esi+NODEHEADER.entriesFolow] add esi, sizeof.NODEHEADER cmp word [esi-sizeof.NODEHEADER+NODEHEADER.currentDepth], 0 je .leaf_block test ebx, ebx jz .fail ; empty @@: cmp ebx, 1 je .end_search_index cmp ecx, [esi+INDEX.fileBlock] jb .fail cmp ecx, [esi+sizeof.INDEX+INDEX.fileBlock] jb .end_search_index add esi, sizeof.INDEX dec ebx jmp @b .end_search_index: mov ebx, [ebp+EXTFS.tempBlockBuffer] mov eax, [esi+INDEX.nodeBlock] call extfsReadBlock jc .fail mov esi, ebx jmp .extentTreeSearch .leaf_block: test ebx, ebx jz .fail mov edx, [esi+EXTENT.fileBlock] cmp ecx, edx jb .fail movzx edi, [esi+EXTENT.blocksCount] add edx, edi cmp ecx, edx jb .end_search_extent add esi, sizeof.EXTENT dec ebx jmp .leaf_block .end_search_extent: sub ecx, [esi+EXTENT.fileBlock] add ecx, [esi+EXTENT.fsBlock] mov PUSHAD_ECX, ecx popad xor eax, eax ret .fail: popad movi eax, ERROR_FS_FAIL stc ret .get_indirect_block: mov eax, [esi+INODE.addressBlock] test eax, eax jz .noBlock mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsReadBlock jc .fail2 mov ecx, [ebx+ecx*4] pop ebx edx ret .get_direct_block: mov ecx, [esi+INODE.blockNumbers+ecx*4] xor eax, eax ret .listTreeSearch: cmp ecx, 12 jb .get_direct_block push edx ebx 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 .noBlock: xor ecx, ecx .fail2: pop ebx edx ret .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 div [ebp+EXTFS.dwordsPerBlock] ; 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 mov ecx, [ebx+edx*4] pop ebx edx ret extfsSetFileBlock: ; in: ; ecx = file block number ; edi = block number ; edx = inode number ; esi -> inode push ebx ecx edx cmp ecx, 12 jb .direct_block sub ecx, 12 cmp ecx, [ebp+EXTFS.dwordsPerBlock] jb .indirect_block sub ecx, [ebp+EXTFS.dwordsPerBlock] cmp ecx, [ebp+EXTFS.dwordsPerBranch] jb .double_indirect_block ; triple indirect blocks sub ecx, [ebp+EXTFS.dwordsPerBranch] mov eax, [esi+INODE.tripleAddress] test eax, eax jnz @f mov eax, edx call inodeBlockAlloc jc .ret mov [esi+INODE.tripleAddress], ebx mov eax, ebx @@: push eax mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsReadBlock jc .fail_alloc_4 xor edx, edx mov eax, ecx div [ebp+EXTFS.dwordsPerBranch] ; eax = number in triply-indirect block, edx = number in branch lea ecx, [ebx+eax*4] mov eax, [ebx+eax*4] test eax, eax jnz @f mov eax, [esp+4] call inodeBlockAlloc jc .fail_alloc_4 mov [ecx], ebx mov eax, [esp] mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsWriteBlock jc .fail_alloc_4 mov eax, [ecx] @@: mov [esp], eax call extfsReadBlock jc .fail_alloc_4 mov eax, edx jmp @f .double_indirect_block: mov eax, [esi+INODE.doubleAddress] test eax, eax jnz .double_indirect_present mov eax, edx call inodeBlockAlloc jc .ret mov [esi+INODE.doubleAddress], ebx mov eax, ebx .double_indirect_present: push eax mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsReadBlock jc .fail_alloc_4 mov eax, ecx @@: xor edx, edx div [ebp+EXTFS.dwordsPerBlock] ; eax = number in doubly-indirect block, edx = number in indirect block lea ecx, [ebx+edx*4] push ecx lea ecx, [ebx+eax*4] cmp dword[ecx], 0 jne @f mov eax, [esp+8] call inodeBlockAlloc jc .fail_alloc_8 mov [ecx], ebx mov eax, [esp+4] mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsWriteBlock jc .fail_alloc_8 @@: mov eax, [ecx] push eax call extfsReadBlock jc .fail_alloc_12 pop eax ecx edx mov [ecx], edi call extfsWriteBlock jmp .ret .indirect_block: mov eax, [esi+INODE.addressBlock] test eax, eax jnz @f mov eax, edx call inodeBlockAlloc jc .ret mov [esi+INODE.addressBlock], ebx mov eax, ebx @@: push eax mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsReadBlock jc .fail_alloc_4 mov [ebx+ecx*4], edi pop eax call extfsWriteBlock jmp .ret .direct_block: mov [esi+INODE.blockNumbers+ecx*4], edi xor eax, eax .ret: pop edx ecx ebx ret .fail_alloc_12: pop ebx .fail_alloc_8: pop ebx .fail_alloc_4: pop ebx jmp .ret extfsEraseFileBlock: ; also allocates ; in: ; edx = inode number ; eax = file block number ; [ebp+EXTFS.inodeBuffer] = inode push ebx ecx edx edi esi mov edi, eax mov ecx, eax lea esi, [ebp+EXTFS.inodeBuffer] call extfsGetFileBlock jc @f test ecx, ecx jz .allocate mov edx, ecx mov ecx, [ebp+EXTFS.bytesPerBlock] mov edi, [ebp+EXTFS.tempBlockBuffer] xor eax, eax rep stosb mov eax, edx mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsWriteBlock jmp @f .allocate: mov eax, edx call extfsBlockAlloc jc @f mov ecx, edi mov edi, ebx lea esi, [ebp+EXTFS.inodeBuffer] call extfsSetFileBlock jc @f mov eax, [ebp+EXTFS.sectorsPerBlock] add [esi+INODE.sectorsUsed], eax xor eax, eax @@: pop esi edi edx ecx ebx ret extfsFreeFileBlock: ; in: ; eax = file block number ; [ebp+EXTFS.inodeBuffer] = inode push ebx ecx edx edi esi mov edi, eax mov ecx, eax lea esi, [ebp+EXTFS.inodeBuffer] call extfsGetFileBlock jc @f test ecx, ecx jz @f mov eax, ecx xor ecx, ecx call extfsResourceFree mov ecx, edi xor edi, edi movi edx, ROOT_INODE lea esi, [ebp+EXTFS.inodeBuffer] call extfsSetFileBlock mov eax, [ebp+EXTFS.sectorsPerBlock] sub [esi+INODE.sectorsUsed], eax xor eax, eax @@: pop esi edi edx ecx ebx ret extfsReadFileBlock: ; in: ; eax = file block number ; [ebp+EXTFS.inodeBuffer] = inode ; out: ; [ebp+EXTFS.mainBlockBuffer] -> block push ebx ecx edx esi mov ecx, eax lea esi, [ebp+EXTFS.inodeBuffer] call extfsGetFileBlock jc .ret test ecx, ecx jz @f mov eax, ecx mov ebx, [ebp+EXTFS.mainBlockBuffer] call extfsReadBlock .ret: pop esi edx ecx ebx ret @@: movi eax, ERROR_FS_FAIL stc jmp .ret extfsWriteFileBlock: ; in: ; eax = file block number ; [ebp+EXTFS.inodeBuffer] = inode ; [ebp+EXTFS.mainBlockBuffer] -> block to write push ebx ecx edx esi mov ecx, eax lea esi, [ebp+EXTFS.inodeBuffer] call extfsGetFileBlock jc @f test ecx, ecx jz @b mov eax, ecx mov ebx, [ebp+EXTFS.mainBlockBuffer] call extfsWriteBlock @@: pop esi edx ecx ebx ret getInodeLocation: ; in: eax = inode number ; out: ; ebx = inode sector ; edx = offset in sector dec eax xor edx, edx div [ebp+EXTFS.superblock.inodesPerGroup] mov ecx, edx shl eax, 5 xor edx, edx div [ebp+EXTFS.bytesPerBlock] add eax, [ebp+EXTFS.superblock.firstGroupBlock] inc eax mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsReadBlock jc @f add ebx, edx mov ebx, [ebx+BGDESCR.inodeTable] mov eax, ecx mov ecx, [ebp+EXTFS.sectorsPerBlockLog] shl ebx, cl mul [ebp+EXTFS.superblock.inodeSize] mov edx, eax shr eax, 9 and edx, 511 add ebx, eax xor eax, eax @@: 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 call getInodeLocation jc .ret mov eax, ebx mov ebx, [ebp+EXTFS.tempBlockBuffer] mov ecx, eax call fs_read32_sys test eax, eax jnz @f mov eax, ecx mov esi, edi movzx ecx, [ebp+EXTFS.superblock.inodeSize] mov edi, edx add edi, ebx 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 jc @f mov eax, ebx 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 extfsExtendFile: ; in: ; [ebp+EXTFS.inodeBuffer] = inode ; eax = inode number ; ecx = new size push ebx ecx edx esi edi eax lea ebx, [ebp+EXTFS.inodeBuffer] cmp [ebx+INODE.fileSize], ecx jnc .ret mov eax, [ebx+INODE.fileSize] push eax sub ecx, eax xor edx, edx div [ebp+EXTFS.bytesPerBlock] test edx, edx jz .start_aligned mov esi, [ebp+EXTFS.bytesPerBlock] sub esi, edx cmp esi, ecx jbe @f mov esi, ecx @@: ; clear esi trailing bytes in block number eax push eax call extfsReadFileBlock pop edi jc .error_inode_size push edi ecx xor eax, eax mov ecx, esi mov edi, ebx add edi, edx rep stosb pop ecx eax call extfsWriteFileBlock jc .error_inode_size add [esp], esi sub ecx, esi jz .done .start_aligned: cmp ecx, [ebp+EXTFS.bytesPerBlock] jb @f mov eax, [esp] xor edx, edx div [ebp+EXTFS.bytesPerBlock] mov edx, [esp+4] call extfsEraseFileBlock jc .error_inode_size mov eax, [ebp+EXTFS.bytesPerBlock] sub ecx, eax add [esp], eax jmp .start_aligned @@: ; handle the remaining bytes test ecx, ecx jz .done mov eax, [esp] xor edx, edx div [ebp+EXTFS.bytesPerBlock] mov edx, [esp+4] call extfsEraseFileBlock jc .error_inode_size add [esp], ecx .done: xor eax, eax .error_inode_size: lea ebx, [ebp+EXTFS.inodeBuffer] pop [ebx+INODE.fileSize] .ret: pop edi edi esi edx ecx ebx ret extfsTruncateFile: ; in: ; [ebp+EXTFS.inodeBuffer] = inode ; ecx = new size push ebx ecx edx esi edi lea ebx, [ebp+EXTFS.inodeBuffer] cmp ecx, [ebx+INODE.fileSize] jnc .ret mov eax, [ebx+INODE.fileSize] push eax sub ecx, eax not ecx inc ecx xor edx, edx div [ebp+EXTFS.bytesPerBlock] test edx, edx jz .start_aligned mov esi, edx cmp esi, ecx jbe @f ; if the size to truncate is smaller than the unaligned bytes ; we're going to clear neccessary bytes from the EOF push eax call extfsReadFileBlock pop edi jc .error_inode_size push edi ecx mov edi, [ebp+EXTFS.mainBlockBuffer] sub edx, ecx add edi, edx xor eax, eax rep stosb pop ecx eax call extfsWriteFileBlock jc .error_inode_size sub [esp], ecx jmp .done @@: call extfsFreeFileBlock sub [esp], esi sub ecx, esi jz .done .start_aligned: cmp ecx, [ebp+EXTFS.bytesPerBlock] jb @f mov eax, [esp] xor edx, edx div [ebp+EXTFS.bytesPerBlock] dec eax call extfsFreeFileBlock mov eax, [ebp+EXTFS.bytesPerBlock] sub ecx, eax sub [esp], eax jmp .start_aligned @@: ; handle the remaining bytes test ecx, ecx jz .done mov eax, [esp] xor edx, edx div [ebp+EXTFS.bytesPerBlock] dec eax push eax call extfsReadFileBlock pop edi jc .error_inode_size push edi ecx mov edi, [ebp+EXTFS.mainBlockBuffer] mov edx, [ebp+EXTFS.bytesPerBlock] sub edx, ecx add edi, edx xor eax, eax rep stosb pop ecx eax call extfsWriteFileBlock jc .error_inode_size sub [esp], ecx .done: xor eax, eax .error_inode_size: lea ebx, [ebp+EXTFS.inodeBuffer] pop [ebx+INODE.fileSize] .ret: pop edi esi edx ecx ebx 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 add ecx, 8 ; directory entry size push esi ebx ecx xor ecx, ecx lea esi, [ebp+EXTFS.inodeBuffer] mov ebx, esi call readInode jc .error_inode_read mov ecx, [ebp+EXTFS.sectorsPerBlockLog] mov eax, [esi+INODE.sectorsUsed] shr eax, cl xor ecx, ecx .searchBlock: push eax ; blocks total push ecx ; current file block number cmp eax, ecx jz .alloc_block call extfsGetFileBlock jc .error_get_inode_block test ecx, ecx jz .alloc_block push ecx mov eax, ecx mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsReadBlock jc .error_block_read mov ecx, [esp+12] 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 ecx eax inc ecx jmp .searchBlock .zeroLength: mov [edi+DIRENTRY.entryLength], cx mov eax, edx sub eax, edi cmp eax, ecx jge .found mov [edi+DIRENTRY.inodeNumber], 0 mov [edi+DIRENTRY.entryLength], ax ; this block wasn't linking to the next one, so write it, and use the next block pop eax mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsWriteBlock jc .error_get_inode_block inc dword[esp] mov ecx, [esp] call extfsGetFileBlock jc .error_get_inode_block test ecx, ecx jz .alloc_block push ecx jmp .prepare_block .alloc_block: mov eax, [esp+24] mov edx, eax call extfsBlockAlloc jc .error_get_inode_block mov ecx, [esp] mov edi, ebx call extfsSetFileBlock jc .error_get_inode_block mov eax, [ebp+EXTFS.bytesPerBlock] add [esi+INODE.fileSize], eax mov eax, [ebp+EXTFS.sectorsPerBlock] add [esi+INODE.sectorsUsed], eax mov eax, [esp+24] mov ebx, esi call writeInode jc .error_get_inode_block push edi ; save the block we just allocated .prepare_block: mov eax, [esp] mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsReadBlock jc .error_block_read mov edi, ebx mov eax, [ebp+EXTFS.bytesPerBlock] mov [edi+DIRENTRY.entryLength], ax .found: pop edx ecx ecx ecx ebx esi push ebx mov [edi], ebx ; save inode mov eax, [esp+4] cmp [ebp+EXTFS.superblock.dynamicVersionFlag], 0 je .name mov [edi+DIRENTRY.fileType], al .name: sub ecx, 8 mov [edi+DIRENTRY.nameLength], cl add edi, 8 rep movsb mov eax, edx mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsWriteBlock jc .error_block_write mov eax, [esp] lea ebx, [ebp+EXTFS.inodeBuffer] call readInode jc .error_block_write pop eax inc [ebx+INODE.linksCount] call writeInode jc @f xor eax, eax @@: 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 .error_block_write: pop ebx jmp @b unlinkInode: ; in: ; eax = inode from which to unlink ; ebx = inode to unlink ; out: ; eax = current number of links to inode, -1 = error push edx ebx lea ebx, [ebp+EXTFS.inodeBuffer] call readInode jc .fail push eax lea esi, [ebp+EXTFS.inodeBuffer] .loop: mov ecx, [esp] call extfsGetFileBlock jc .fail_loop test ecx, ecx jz .fail_loop mov eax, ecx mov edi, ecx mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsReadBlock jc .fail_loop .first_dir_entry: ; edi -> block mov eax, [esp+4] cmp [ebx+DIRENTRY.inodeNumber], eax jne @f mov [ebx+DIRENTRY.inodeNumber], 0 mov word [ebx+DIRENTRY.nameLength], 0 ; fileType = 0 jmp .write_block @@: mov edx, ebx add edx, [ebp+EXTFS.bytesPerBlock] push edx mov edx, ebx movzx ecx, [ebx+DIRENTRY.entryLength] add ebx, ecx .dir_entry: cmp [ebx+DIRENTRY.inodeNumber], eax jne @f mov cx, [ebx+DIRENTRY.entryLength] add [edx+DIRENTRY.entryLength], cx pop eax jmp .write_block @@: mov edx, ebx movzx ecx, [ebx+DIRENTRY.entryLength] test ecx, ecx jz .fail_inode add ebx, ecx cmp ebx, [esp] jb .dir_entry pop ecx inc dword[esp] jmp .loop .fail_inode: pop eax .fail_loop: pop eax .fail: or eax, -1 jmp @f .write_block: pop eax mov eax, edi mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsWriteBlock jc .fail mov eax, [esp] lea ebx, [ebp+EXTFS.inodeBuffer] call readInode jc .fail dec word [ebx+INODE.linksCount] mov eax, [esp] call writeInode jc .fail movzx eax, word [ebx+INODE.linksCount] @@: pop ebx edx 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 0 ROOT_INODE mov edi, esi cmp [edx+INODE.sectorsUsed], 0 jz .not_found cmp byte [esi], 0 jnz .next_path_part xor eax, eax pop esi ecx ret @@: pop esi esi .error: pop esi ecx xor edi, edi stc ret .next_path_part: push [edx+INODE.sectorsUsed] xor ecx, ecx .folder_block_cycle: push ecx xchg esi, edx call extfsGetFileBlock jc @b xchg esi, edx mov eax, ecx 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 eax, [ebx+DIRENTRY.entryLength] add ebx, eax cmp ebx, edx jb .start_rec push eax jmp @f .test_find: cmp byte [esi], 0 je @f cmp byte [esi], '/' jne @b inc esi @@: pop edx edx edi ecx eax ; ebx -> matched directory entry, esi -> name without parent, or not changed cmp edi, esi jnz @f sub eax, [ebp+EXTFS.sectorsPerBlock] 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 ret writeSuperblock: push ebx mov eax, 2 lea ebx, [ebp+EXTFS.superblock] call fs_write32_sys pop ebx ret extfsWritingInit: movi eax, ERROR_ACCESS_DENIED cmp byte [esi], 0 jz @f 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 push ebx call findInode pop ebx 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 extfsGetFileBlock jc .error_get_block mov eax, ecx 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 extfsGetFileBlock jc .error_get_block mov eax, ecx 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] add ecx, esi cmp byte [esi], '.' jnz @f or byte [edx], KOS_HIDDEN @@: lea edi, [edx+40] cmp byte [edx+4], 1 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 .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: or ebx, -1 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 push ERROR_ACCESS_DENIED cmp byte [esi], 0 jz .error ; root mov [esp], ebx call findInode pop ebx jc .error_eax push ERROR_ACCESS_DENIED lea esi, [ebp+EXTFS.inodeBuffer] mov ax, [esi+INODE.accessMode] and ax, TYPE_MASK cmp ax, FLAG_FILE jnz .error ; not a file pop eax mov edi, [ebx+16] mov ecx, [ebx+12] mov eax, [ebx+4] mov edx, [ebx+8] push ERROR_END_OF_FILE cmp [esi+INODE.fileSizeHigh], edx ja @f jb .error cmp [esi+INODE.fileSize], eax jna .error @@: add esp, 4 add eax, ecx adc edx, 0 cmp [esi+INODE.fileSizeHigh], edx ja .read_till_requested jb .read_whole_file cmp [esi+INODE.fileSize], eax jae .read_till_requested .read_whole_file: push 1 ; read till the end of file mov ecx, [esi+INODE.fileSize] sub ecx, [ebx+4] jmp @f .read_till_requested: push 0 ; read as much as requested @@: ; ecx = bytes to read, edi -> buffer push ecx ; read part of the first block mov edx, [ebx+8] mov eax, [ebx+4] div [ebp+EXTFS.bytesPerBlock] push eax push ecx mov ecx, eax call extfsGetFileBlock jc .error_at_first_block mov ebx, [ebp+EXTFS.mainBlockBuffer] mov eax, ecx call extfsReadBlock jc .error_at_first_block pop ecx add ebx, edx neg edx add edx, [ebp+EXTFS.bytesPerBlock] cmp ecx, edx jbe .only_one_block mov eax, ecx sub eax, edx ; bytes to read mov ecx, edx push esi mov esi, ebx rep movsb pop esi mov ebx, edi xor edx, edx div [ebp+EXTFS.bytesPerBlock] mov edi, eax @@: test edi, edi jz .finish_block inc dword [esp] mov ecx, [esp] call extfsGetFileBlock jc .error_at_read_cycle mov eax, ecx call extfsReadBlock jc .error_at_read_cycle add ebx, [ebp+EXTFS.bytesPerBlock] dec edi jmp @b .finish_block: ; edx = number of bytes in the last block test edx, edx jz .end_read pop ecx ; block counter inc ecx call extfsGetFileBlock jc .error_at_finish_block mov edi, ebx mov eax, ecx mov ebx, [ebp+EXTFS.mainBlockBuffer] call extfsReadBlock jc .error_at_finish_block push eax mov ecx, edx .only_one_block: mov esi, ebx rep movsb .end_read: call ext_unlock pop eax ebx eax test eax, eax jz @f movi eax, ERROR_END_OF_FILE @@: ret .error_at_first_block: pop ebx .error_at_read_cycle: pop ebx .error_at_finish_block: pop ebx ebx .error_eax: push eax .error: call ext_unlock xor ebx, ebx pop eax ret ;---------------------------------------------------------------- ext_GetFileInfo: call ext_lock mov edx, [ebx+16] cmp byte [esi], 0 jz .is_root push edx call findInode pop edx lea esi, [ebp+EXTFS.inodeBuffer] jnc @f push eax call ext_unlock pop eax ret .is_root: mov edi, esi lea esi, [ebp+EXTFS.rootInodeBuffer] @@: 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 call ext_unlock xor eax, eax ret ;---------------------------------------------------------------- ext_SetFileInfo: call extfsWritingInit pushd [ebx+16] call findInode pop edx jc @f push esi ; inode number lea esi, [edx+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 mov ebx, esi push eax jc .ret pop eax lea edx, [ebp+EXTFS.inodeBuffer] movzx edx, [edx+INODE.accessMode] and edx, TYPE_MASK cmp edx, DIRECTORY jne .file push ebx ecx edx 0 lea esi, [ebp+EXTFS.inodeBuffer] .checkDirectory: mov ecx, [esp] call extfsGetFileBlock jc .not_empty_eax test ecx, ecx jz .empty mov eax, ecx mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsReadBlock jc .not_empty_eax mov edx, ebx add edx, [ebp+EXTFS.bytesPerBlock] movzx ecx, [ebx+DIRENTRY.entryLength] add ebx, ecx .dir_entry: cmp byte [ebx+DIRENTRY.nameLength], 1 jne @f cmp byte [ebx+DIRENTRY.name], '.' jne .not_empty @@: cmp byte [ebx+DIRENTRY.nameLength], 2 jne .not_empty cmp word [ebx+DIRENTRY.name], '..' jne .not_empty movzx ecx, [ebx+DIRENTRY.entryLength] add ebx, ecx cmp ebx, edx jb .dir_entry inc dword[esp] jmp .checkDirectory .empty: pop edx edx ecx ebx .file: mov eax, ecx push ebx ecx call unlinkInode cmp eax, -1 je .error_stack8 pop ebx test eax, eax jz @f xor eax, eax cmp edx, DIRECTORY jnz .error_stack4_eax ; hardlinks mov eax, [esp] call unlinkInode @@: mov eax, [esp] lea ebx, [ebp+EXTFS.inodeBuffer] call readInode jc .error_stack4_eax ; free file's data lea esi, [ebp+EXTFS.inodeBuffer] xor ecx, ecx @@: push ecx call extfsGetFileBlock jc .error_stack8_eax mov eax, ecx test eax, eax jz @f xor ecx, ecx call extfsResourceFree pop ecx inc ecx jmp @b @@: ; free indirect blocks pop ecx push edx lea edi, [ebp+EXTFS.inodeBuffer] mov eax, [edi+INODE.addressBlock] test eax, eax jz .success xor ecx, ecx call extfsResourceFree mov eax, [edi+INODE.doubleAddress] call freeDoublyIndirectBlock cmp eax, 1 je .success mov eax, [edi+INODE.tripleAddress] test eax, eax jz .success push eax mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsReadBlock pop ecx jc .error_stack8_eax mov eax, ecx xor ecx, ecx call extfsResourceFree mov edx, ebx add edx, [ebp+EXTFS.bytesPerBlock] @@: mov eax, [ebx] test eax, eax jz .success push ebx edx call freeDoublyIndirectBlock pop edx ebx cmp eax, 1 je .success add ebx, 4 cmp ebx, edx jb @b .success: ; clear the inode, and add deletion time xor eax, eax movzx ecx, [ebp+EXTFS.superblock.inodeSize] rep stosb lea edi, [ebp+EXTFS.inodeBuffer] call fsGetTime pop edx add eax, 978307200 mov [edi+INODE.deletedTime], eax mov eax, [esp] mov ebx, edi call writeInode jc .error_stack4_eax cmp edx, DIRECTORY jne @f mov eax, [esp] dec eax xor edx, edx div [ebp+EXTFS.superblock.inodesPerGroup] push eax call extfsReadDescriptor jc .error_stack8 dec [eax+BGDESCR.directoriesCount] pop eax call extfsWriteDescriptor @@: ; free inode pop eax dec eax xor ecx, ecx inc ecx call extfsResourceFree push eax .disk_sync: call writeSuperblock mov esi, [ebp+PARTITION.Disk] call disk_sync .ret: call ext_unlock xor ebx, ebx pop eax ret .not_empty: pop eax .error_stack8: pop eax eax push ERROR_ACCESS_DENIED jmp .disk_sync .not_empty_eax: pop ebx .error_stack8_eax: pop ebx .error_stack4_eax: pop ebx .error: push eax jmp .disk_sync ;---------------------------------------------------------------- ext_CreateFolder: call extfsWritingInit call findInode jnc .success ; exist test edi, edi jz .error mov eax, esi xor ebx, ebx inc ebx call extfsResourceAlloc jc .error inc ebx push ebx esi edi xor al, al lea edi, [ebp+EXTFS.inodeBuffer] movzx ecx, [ebp+EXTFS.superblock.inodeSize] rep stosb lea edi, [ebp+EXTFS.inodeBuffer] call fsGetTime add eax, 978307200 mov [edi+INODE.accessedTime], eax mov [edi+INODE.dataModified], eax mov ebx, edi pop edi esi edx ; edx = allocated inode number, edi -> filename, esi = parent inode number mov [ebx+INODE.accessMode], DIRECTORY or PERMISSIONS 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 mov eax, esi mov ebx, edx mov esi, edi mov dl, DIR_DIRECTORY call linkInode jc .error mov eax, ebx dec eax xor edx, edx div [ebp+EXTFS.superblock.inodesPerGroup] mov edx, eax call extfsReadDescriptor jc @f inc [eax+BGDESCR.directoriesCount] mov eax, edx call extfsWriteDescriptor .success: .error: push eax call writeSuperblock mov esi, [ebp+PARTITION.Disk] call disk_sync call ext_unlock pop eax ret @@: movi eax, ERROR_DEVICE jmp .error self_link db ".", 0 parent_link db "..", 0 ;---------------------------------------------------------------- ext_CreateFile: call extfsWritingInit push 0 ebx call findInode jnc .exist test edi, edi jz .error mov eax, esi xor ebx, ebx inc ebx call extfsResourceAlloc jc .error inc ebx push ebx ebx esi edi xor al, al lea edi, [ebp+EXTFS.inodeBuffer] movzx ecx, [ebp+EXTFS.superblock.inodeSize] rep stosb lea edi, [ebp+EXTFS.inodeBuffer] call fsGetTime add eax, 978307200 mov [edi+INODE.accessedTime], eax mov [edi+INODE.dataModified], eax mov ebx, edi pop edi esi edx ; edx = allocated inode number, edi -> filename, esi = parent inode number mov [ebx+INODE.accessMode], FLAG_FILE or PERMISSIONS 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 pop esi ebx push ebx esi mov ecx, [ebx+12] jmp ext_WriteFile.start .exist: lea edx, [ebp+EXTFS.inodeBuffer] movi eax, ERROR_ACCESS_DENIED test [edx+INODE.accessMode], FLAG_FILE jz .error ; not a file pop ebx push ebx esi mov ecx, [ebx+12] call extfsTruncateFile jnc ext_WriteFile.start .error2: pop ebx .error: push eax call ext_unlock pop eax ebx ebx xor ebx, ebx ret ;---------------------------------------------------------------- ext_WriteFile: call extfsWritingInit push 0 ebx call findInode pop ebx push ebx esi jc .error lea edx, [ebp+EXTFS.inodeBuffer] movi eax, ERROR_ACCESS_DENIED test [edx+INODE.accessMode], FLAG_FILE jz .error ; not a file mov ecx, [ebx+4] add ecx, [ebx+12] .start: mov eax, esi call extfsExtendFile jc .error mov eax, [ebx+4] mov ecx, [ebx+12] mov esi, [ebx+16] push eax xor edx, edx div [ebp+EXTFS.bytesPerBlock] test edx, edx jz .start_aligned mov ebx, [ebp+EXTFS.bytesPerBlock] sub ebx, edx cmp ebx, ecx jbe @f mov ebx, ecx @@: push eax call extfsReadFileBlock pop edi jc .error_inode_size mov eax, edi push ecx mov ecx, ebx mov edi, ebx add edi, edx rep movsb pop ecx call extfsWriteFileBlock jc .error_inode_size add [esp], ebx sub ecx, ebx jz .write_inode .start_aligned: cmp ecx, [ebp+EXTFS.bytesPerBlock] jb @f mov eax, [esp] xor edx, edx div [ebp+EXTFS.bytesPerBlock] mov edx, [esp+4] push eax call extfsEraseFileBlock pop edi jc .error_inode_size mov eax, edi push ecx mov ecx, [ebp+EXTFS.bytesPerBlock] mov edi, [ebp+EXTFS.mainBlockBuffer] rep movsb pop ecx call extfsWriteFileBlock jc .error_inode_size mov eax, [ebp+EXTFS.bytesPerBlock] sub ecx, eax add [esp], eax jmp .start_aligned @@: ; Handle the remaining bytes. test ecx, ecx jz .write_inode mov eax, [esp] xor edx, edx div [ebp+EXTFS.bytesPerBlock] push eax call extfsReadFileBlock pop eax jnc @f mov edx, [esp+4] push eax call extfsEraseFileBlock pop edi jc .error_inode_size mov eax, edi @@: push ecx mov edi, [ebp+EXTFS.mainBlockBuffer] rep movsb pop ecx call extfsWriteFileBlock jc .error_inode_size add [esp], ecx xor ecx, ecx .error_inode_size: mov [esp+12], eax .write_inode: lea ebx, [ebp+EXTFS.inodeBuffer] pop eax eax call writeInode pop ebx mov ebx, [ebx+12] sub ebx, ecx test eax, eax jz @f mov [esp], eax @@: call writeSuperblock mov esi, [ebp+PARTITION.Disk] call disk_sync @@: call ext_unlock pop eax ret .error: pop ebx ebx ebx push eax jmp @b ;---------------------------------------------------------------- ext_SetFileEnd: call extfsWritingInit pushd [ebx+4] call findInode pop ecx jc @f lea edx, [ebp+EXTFS.inodeBuffer] movi eax, ERROR_ACCESS_DENIED cmp [edx+INODE.accessMode], FLAG_FILE jnz @f ; not a file mov eax, esi call extfsExtendFile jc @f call extfsTruncateFile jc @f mov eax, esi lea ebx, [ebp+EXTFS.inodeBuffer] call writeInode @@: push eax call writeSuperblock mov esi, [ebp+PARTITION.Disk] call disk_sync call ext_unlock pop eax ret