;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; ;; ;; 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 ; 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 ? align 512 superblock SUPERBLOCK align 1024 rootInodeBuffer INODE align 1024 mainInodeBuffer INODE align 1024 tempInodeBuffer INODE 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 jne .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 stdcall kernel_alloc, 1000h 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: stdcall kernel_free, ebp 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] call kernel_free ret 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 ; out: ebx = block number ; TODO: fix to have correct preference. mov eax, ROOT_INODE 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: push edx ebx mov eax, [esi+INODE.addressBlock] test eax, eax jz .fail3 mov ebx, [ebp+EXTFS.tempBlockBuffer] call extfsReadBlock jc @f 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 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] push edx ebx mov eax, [esi+INODE.tripleAddress] 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 .fail3 call extfsReadBlock jc .fail2 mov eax, edx jmp @f .fail3: pop ebx edx movi eax, ERROR_FS_FAIL stc ret .get_double_indirect_block: push edx ebx mov eax, [esi+INODE.doubleAddress] test eax, eax jz .fail3 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 .fail3 call extfsReadBlock jc .fail2 mov ecx, [ebx+edx*4] .fail2: pop ebx edx ret extfsSetFileBlock: ; in: ; ecx = file block number ; edi = block 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 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 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 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 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 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.tempInodeBuffer] = inode push ebx ecx edx edi esi mov edi, eax mov ecx, eax lea esi, [ebp+EXTFS.tempInodeBuffer] 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.tempInodeBuffer] 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.tempInodeBuffer] = inode push ebx ecx edi esi mov edi, eax mov ecx, eax lea esi, [ebp+EXTFS.tempInodeBuffer] call extfsGetFileBlock jc @f test ecx, ecx jz @f mov eax, ecx xor ecx, ecx call extfsResourceFree mov ecx, edi xor edi, edi lea esi, [ebp+EXTFS.tempInodeBuffer] call extfsSetFileBlock mov eax, [ebp+EXTFS.sectorsPerBlock] sub [esi+INODE.sectorsUsed], eax xor eax, eax @@: pop esi edi ecx ebx ret extfsReadFileBlock: ; in: ; eax = file block number ; [ebp+EXTFS.tempInodeBuffer] = inode ; out: ; [ebp+EXTFS.mainBlockBuffer] -> block push ebx ecx edx esi mov ecx, eax lea esi, [ebp+EXTFS.tempInodeBuffer] 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.tempInodeBuffer] = inode ; [ebp+EXTFS.mainBlockBuffer] -> block to write push ebx ecx edx esi mov ecx, eax lea esi, [ebp+EXTFS.tempInodeBuffer] 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: ; eax = inode number ; ecx = new size push ebx ecx edx esi edi eax lea ebx, [ebp+EXTFS.tempInodeBuffer] call readInode jc .ret 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 .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] 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 .write_inode mov eax, [esp] xor edx, edx div [ebp+EXTFS.bytesPerBlock] mov edx, [esp+4] call extfsEraseFileBlock jc .error_inode_size add [esp], ecx .write_inode: xor eax, eax .error_inode_size: lea ebx, [ebp+EXTFS.tempInodeBuffer] pop [ebx+INODE.fileSize] push eax mov eax, [esp+4] call writeInode pop ebx jc .ret xchg eax, ebx cmp ebx, eax ; set CF .ret: pop edi edi esi edx ecx ebx ret extfsTruncateFile: ; in: ; eax = inode number ; ecx = new size push ebx ecx edx esi edi eax lea ebx, [ebp+EXTFS.tempInodeBuffer] call readInode jc .ret 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 .write_inode @@: call extfsFreeFileBlock sub [esp], esi sub ecx, esi jz .write_inode .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 .write_inode 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 .write_inode: xor eax, eax .error_inode_size: lea ebx, [ebp+EXTFS.tempInodeBuffer] pop [ebx+INODE.fileSize] push eax mov eax, [esp+4] call writeInode pop ebx jc .ret xchg eax, ebx cmp ebx, eax ; set CF .ret: pop edi edi esi edx ecx ebx ret linkInode: ; in: ; eax = inode on which to link ; ebx = inode to link ; esi -> name ; 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.tempInodeBuffer] 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 push eax ; maximum file block number push ecx ; current file block number .searchBlock: 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+8] 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 jmp .nextBlock .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 .nextBlock: add esp, 4 inc dword[esp] mov ecx, [esp] cmp ecx, [esp+4] jbe .searchBlock .alloc_block: mov eax, [esp+12] 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.tempInodeBuffer] 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 esi edi ebx lea ebx, [ebp+EXTFS.tempInodeBuffer] call readInode jc .fail push eax lea esi, [ebp+EXTFS.tempInodeBuffer] .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.tempInodeBuffer] call readInode jc .fail dec word [ebx+INODE.linksCount] mov eax, [esp] call writeInode jc .fail movzx eax, word [ebx+INODE.linksCount] @@: pop ebx edi esi edx ret findInode_parent: ; in: esi -> path ; out: ; edi -> file name ; esi = inode push esi xor edi, edi .loop: cmp byte [esi], '/' jne @f mov edi, esi inc esi jmp .loop @@: inc esi cmp byte [esi-1], 0 jne .loop cmp edi, 0 jne @f ; parent is root pop edi dec esi jmp .get_inode @@: ; parent is folder mov byte [edi], 0 inc edi pop esi .get_inode: push ebx edx call findInode pop edx ebx ret findInode: ; in: esi -> path string ; out: ; [ebp+EXTFS.mainInodeBuffer] = inode ; esi = inode number ; dl = first byte of file/folder name lea edx, [ebp+EXTFS.rootInodeBuffer] cmp [edx+INODE.sectorsUsed], 0 je .not_found cmp byte [esi], 0 jne .next_path_part ; root push edi ecx lea esi, [ebp+EXTFS.rootInodeBuffer] lea edi, [ebp+EXTFS.mainInodeBuffer] movzx ecx, [ebp+EXTFS.superblock.inodeSize] rep movsb pop ecx edi xor eax, eax xor dl, dl mov esi, ROOT_INODE ret .next_path_part: push [edx+INODE.sectorsUsed] xor ecx, ecx .folder_block_cycle: push ecx xchg esi, edx call extfsGetFileBlock jc .error_get_block xchg esi, edx mov eax, ecx mov ebx, [ebp+EXTFS.mainBlockBuffer] call extfsReadBlock jc .error_get_block push esi edx sub esp, 256 mov edx, ebx add edx, [ebp+EXTFS.bytesPerBlock] .start_rec: cmp [ebx+DIRENTRY.inodeNumber], 0 jz .next_rec mov edi, esp push esi movzx ecx, [ebx+DIRENTRY.nameLength] lea esi, [ebx+DIRENTRY.name] call utf8_to_cp866 mov ecx, edi lea edi, [esp+4] sub ecx, edi ; number of bytes in resulting string mov esi, [esp] @@: ; edi -> converted string in stack, ecx = size, esi -> original file path jecxz .test_find dec ecx lodsb call char_toupper mov ah, [edi] inc edi xchg al, ah call char_toupper cmp al, ah je @b @@: ; 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 @@: add esp, 256+4 pop edx edi ecx ; ebx -> matched directory entry, esi -> name without parent, or not changed cmp edi, esi je .next_folder_block cmp byte [esi], 0 je .get_inode_ret mov eax, [ebx+DIRENTRY.inodeNumber] lea ebx, [ebp+EXTFS.mainInodeBuffer] call readInode jc .error_get_inode movzx eax, [ebx+INODE.accessMode] and eax, TYPE_MASK cmp eax, DIRECTORY jne .not_found ; path folder is a file pop ecx mov edx, ebx jmp .next_path_part .next_folder_block: pop eax sub eax, [ebp+EXTFS.sectorsPerBlock] jle .not_found push eax inc ecx jmp .folder_block_cycle .get_inode_ret: pop eax mov dl, [ebx+DIRENTRY.name] mov eax, [ebx+DIRENTRY.inodeNumber] lea ebx, [ebp+EXTFS.mainInodeBuffer] mov esi, eax call readInode ret .not_found: movi eax, ERROR_FILE_NOT_FOUND stc ret .error_get_block: pop ebx .error_get_inode: pop ebx 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.mainInodeBuffer] test [esi+INODE.accessMode], DIRECTORY jz .error_not_found jmp @f .root_folder: lea esi, [ebp+EXTFS.rootInodeBuffer] lea edi, [ebp+EXTFS.mainInodeBuffer] 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 mov edi, edx xor eax, eax mov ecx, 40 / 4 rep stosd mov eax, [ebx+DIRENTRY.inodeNumber] lea ebx, [ebp+EXTFS.tempInodeBuffer] 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], DIRECTORY jnz @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 edi, [edx+40] lea esi, [esi+DIRENTRY.name] call utf8_to_cp866 and byte [edi], 0 pop esi ecx edi ebx cmp byte [edx+40], '.' jne @f or dword [edx], KOS_HIDDEN @@: add edx, 40+264 ; go to the next record 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 .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.mainInodeBuffer] 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 mov ebx, edx pop edx lea esi, [ebp+EXTFS.mainInodeBuffer] jnc @f push eax call ext_unlock pop eax ret .is_root: xor ebx, ebx lea esi, [ebp+EXTFS.rootInodeBuffer] @@: 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], DIRECTORY jnz @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.mainInodeBuffer] 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 push esi call findInode mov ebx, esi pop esi push eax jc .ret pop eax lea edx, [ebp+EXTFS.mainInodeBuffer] movzx edx, [edx+INODE.accessMode] and edx, TYPE_MASK cmp edx, DIRECTORY jne .file push esi ebx edx 0 lea esi, [ebp+EXTFS.mainInodeBuffer] .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 ebx esi .file: call findInode_parent jc .error mov eax, esi ; save file/folder's and parent's inode push ebx eax cmp edx, DIRECTORY jne @f ; Unlink '.' mov eax, [esp+4] call unlinkInode cmp eax, -1 je .error_stack8 ; Unlink '..' mov eax, [esp+4] mov ebx, [esp] call unlinkInode cmp eax, -1 je .error_stack8 @@: pop eax mov ebx, [esp] call unlinkInode cmp eax, -1 je .error_stack4 test eax, eax jz @f ; has hardlinks xor eax, eax mov [esp], eax jmp .disk_sync @@: mov eax, [esp] lea ebx, [ebp+EXTFS.mainInodeBuffer] call readInode jc .error_stack4_eax ; free file's data lea esi, [ebp+EXTFS.mainInodeBuffer] 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.mainInodeBuffer] 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.mainInodeBuffer] 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 .error_stack4: pop 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 push esi call findInode pop esi jnc .success ; exist call findInode_parent jc .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.tempInodeBuffer] movzx ecx, [ebp+EXTFS.superblock.inodeSize] rep stosb lea edi, [ebp+EXTFS.tempInodeBuffer] 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 ebx esi call findInode mov esi, [esp] jc @f call ext_unlock call ext_Delete push eax call ext_lock pop eax test eax, eax jnz .error mov esi, [esp] @@: call findInode_parent jc .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.tempInodeBuffer] movzx ecx, [ebp+EXTFS.superblock.inodeSize] rep stosb lea edi, [ebp+EXTFS.tempInodeBuffer] 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 .error ; link parent to child mov eax, esi mov ebx, edx mov esi, edi mov dl, DIR_FLAG_FILE call linkInode jc .error pop esi ebx call ext_unlock jmp ext_WriteFile .error: push eax call ext_unlock pop eax ebx ebx xor ebx, ebx ret ;---------------------------------------------------------------- ext_WriteFile: call extfsWritingInit push 0 ebx call findInode jc .error lea edx, [ebp+EXTFS.mainInodeBuffer] movi eax, ERROR_ACCESS_DENIED test [edx+INODE.accessMode], FLAG_FILE jz .error ; not a file mov ebx, [esp] push esi ; inode number mov eax, esi mov ecx, [ebx+4] call extfsExtendFile jc .error2 mov ecx, [ebx+12] mov esi, [ebx+16] mov eax, [edx+INODE.fileSize] 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.tempInodeBuffer] pop [ebx+INODE.fileSize] pop 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 .error2: pop ebx .error: pop ebx ebx push eax jmp @b ;---------------------------------------------------------------- ext_SetFileEnd: call extfsWritingInit pushd [ebx+4] call findInode pop ecx jc @f lea edx, [ebp+EXTFS.mainInodeBuffer] movi eax, ERROR_ACCESS_DENIED cmp [edx+INODE.accessMode], FLAG_FILE jnz @f ; not a file mov eax, esi call extfsExtendFile jc @f mov eax, esi call extfsTruncateFile jc @f mov eax, esi lea ebx, [ebp+EXTFS.tempInodeBuffer] call writeInode @@: push eax call writeSuperblock mov esi, [ebp+PARTITION.Disk] call disk_sync call ext_unlock pop eax ret