SFUNC(uint32_t, ext2_allocate_indirect_block, ext2_device_t *device, ext2_inode_t *inode) { int status; size_t block_size = 1024 << device->superblock.block_size_enc; aoff_t size; uint32_t id; status = ext2_alloc_block(device, 0, &id);//TODO: Prevent fragmentation, swap 0 for previous block in inode if (status) THROW(status, 0); inode->blocks += 2 << device->superblock.block_size_enc; if (!ext2_zero_buffer) { ext2_zero_buffer = heapmm_alloc(block_size); memset(ext2_zero_buffer, 0, block_size); } status = ext2_write_block(device, id, 0, ext2_zero_buffer, block_size, &size); if (status) { THROW(status, 0); } RETURN(id); }
SFUNC(aoff_t, ext2_write_inode, inode_t *_inode, void *_buffer, aoff_t f_offset, aoff_t length) { ext2_device_t *device; ext2_vinode_t *inode; aoff_t count; aoff_t block_size; aoff_t in_blk_size; aoff_t rsize; aoff_t in_blk; aoff_t in_file; uint32_t block_addr, p_block_addr; uint8_t *buffer = _buffer; int status; assert( _inode != NULL ); assert( buffer != NULL ); device = (ext2_device_t *) _inode->device; inode = (ext2_vinode_t *) _inode; block_size = 1024 << device->superblock.block_size_enc; p_block_addr = 0; for (count = 0; count < length; count += in_blk_size) { in_file = count + f_offset; in_blk = in_file % block_size; in_blk_size = length - count; if (in_blk_size > (block_size - in_blk)) in_blk_size = block_size - in_blk; status = ext2_decode_block_id (device, &(inode->inode), in_file / block_size, &block_addr); if (status) THROW(status, 0); if (!block_addr) { //debugcon_printf("ext2: growing file!\n"); status = ext2_alloc_block(device, p_block_addr, &block_addr); if (status) THROW(status, 0); status = ext2_set_block_id(device, &(inode->inode), in_file / block_size, block_addr); if (status) THROW(status, 0); inode->inode.blocks += 2 << device->superblock.block_size_enc; } status = ext2_write_block(device, block_addr, in_blk, &(buffer[count]), in_blk_size, &rsize); if (status) THROW(status, 0); p_block_addr = block_addr; } RETURN(count); }
bool ext2_write_inode (PEXT2_FILESYS Ext2Sys, ULONG ino, ULONG offset, PVOID Buffer, ULONG size, PULONG dwReturn ) { PEXT2_BDL ext2_bdl = NULL; ULONG blocks, i; bool bRet = true; EXT2_INODE inode; ULONG dwTotal = 0; ULONG dwBlk = 0; ULONG TotalBlks; blocks = (size + offset + Ext2Sys->blocksize - 1) / Ext2Sys->blocksize; if (!ext2_load_inode(Ext2Sys, ino, &inode)) { return false; } TotalBlks = inode.i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE); TotalBlks = Ext2DataBlocks(Ext2Sys, TotalBlks); if (blocks > TotalBlks) { for (i=0; i < (blocks - TotalBlks); i++) { if (ext2_alloc_block(Ext2Sys, 0, &dwBlk) ) { ext2_expand_inode(Ext2Sys, &inode, dwBlk); inode.i_blocks += (Ext2Sys->blocksize/SECTOR_SIZE); } } } blocks = ext2_build_bdl(Ext2Sys, &inode, offset, size, &ext2_bdl); if (blocks <= 0) return false; for(i = 0; i < blocks; i++) { bRet = NT_SUCCESS(Ext2WriteDisk( Ext2Sys, ext2_bdl[i].Lba, ext2_bdl[i].Length, (PUCHAR)Buffer + ext2_bdl[i].Offset )); if (!bRet) { goto errorout; } dwTotal += ext2_bdl[i].Length; } *dwReturn = dwTotal; if (size + offset > inode.i_size) { inode.i_size = size + offset; } ext2_save_inode(Ext2Sys, ino, &inode); errorout: if (ext2_bdl) RtlFreeHeap(RtlGetProcessHeap(), 0, ext2_bdl); return bRet; }
bool ext2_expand_inode( PEXT2_FILESYS Ext2Sys, PEXT2_INODE Inode, ULONG newBlk ) { ULONG dwSizes[4] = {12, 1, 1, 1}; ULONG Index = 0; ULONG dwTotal = 0; ULONG dwBlk = 0, dwNewBlk = 0, Offset = 0; PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; int i = 0; bool bRet = true; bool bDirty = false; ULONG TotalBlocks; TotalBlocks = Inode->i_blocks / (Ext2Sys->blocksize / SECTOR_SIZE); Index = Ext2DataBlocks(Ext2Sys, TotalBlocks); for (i = 0; i < 4; i++) { dwSizes[i] = dwSizes[i] << ((10 + pExt2Sb->s_log_block_size - 2) * i); dwTotal += dwSizes[i]; } if (Index >= dwTotal) { DPRINT1("Mke2fs: ext2_expand_inode: beyond the maxinum size of an inode.\n"); return false; } for (i = 0; i < 4; i++) { if (Index < dwSizes[i]) { if (i == 0) { Inode->i_block[Index] = newBlk; bDirty = true; } else { dwBlk = Inode->i_block[(i + 12 - 1)]; if (dwBlk == 0) { if (ext2_alloc_block(Ext2Sys, 0, &dwBlk)) { Inode->i_block[(i + 12 - 1)] = dwBlk; bDirty = true; Inode->i_blocks += (Ext2Sys->blocksize / SECTOR_SIZE); } else { break; } } dwNewBlk = 0; bRet = ext2_expand_block( Ext2Sys, Inode, dwBlk, Index, i, newBlk, &dwNewBlk, &Offset ); } break; } Index -= dwSizes[i]; } return bRet; }
bool ext2_expand_block( PEXT2_FILESYS Ext2Sys, PEXT2_INODE Inode, ULONG dwContent, ULONG Index, int layer, ULONG newBlk, ULONG *dwRet, ULONG *off ) { ULONG *pData = NULL; ULONG i = 0, j = 0, temp = 1; ULONG dwBlk; ULONG dwNewBlk = newBlk; bool bDirty = false; bool bRet = true; ULONG Offset = 0; PEXT2_SUPER_BLOCK pExt2Sb = Ext2Sys->ext2_sb; pData = (ULONG *)RtlAllocateHeap(RtlGetProcessHeap(), 0, Ext2Sys->blocksize); if (!pData) { bRet = false; goto errorout; } if (!ext2_read_block(Ext2Sys, dwContent, (void *)pData)) { bRet = false; goto errorout; } if (layer == 1) { *dwRet = dwContent; *off = Index; pData[Index] = newBlk; bDirty = TRUE; } else if (layer <= 3) { temp = 1 << ((10 + pExt2Sb->s_log_block_size - 2) * (layer - 1)); i = Index / temp; j = Index % temp; dwBlk = pData[i]; if (dwBlk == 0) { if (ext2_alloc_block(Ext2Sys, 0, &dwBlk) ) { pData[i] = dwBlk; bDirty = true; Inode->i_blocks += (Ext2Sys->blocksize / SECTOR_SIZE); } if (!bDirty) goto errorout; } if (!ext2_expand_block(Ext2Sys, Inode, dwBlk, j, layer - 1, bDirty, &dwNewBlk, &Offset)) { bRet = false; DPRINT1("Mke2fs: ext2_expand_block: ... error recuise...\n"); goto errorout; } } if (bDirty) { bRet = ext2_write_block(Ext2Sys, dwContent, (void *)pData); } errorout: if (pData) RtlFreeHeap(RtlGetProcessHeap(), 0, pData); if (bRet && dwRet) *dwRet = dwNewBlk; return bRet; }