3 * Ext2 Driver Version 1
\r
7 * \brief Second Extended Filesystem Driver
\r
8 * \todo Implement file full write support
\r
14 #include <modules.h>
\r
15 #include "fs_ext2.h"
\r
17 #define EXT2_UPDATE_WRITEBACK 1
\r
19 // === STRUCTURES ===
\r
25 tExt2_SuperBlock SuperBlock;
\r
29 tExt2_Group Groups[];
\r
32 // === PROTOTYPES ===
\r
33 int Ext2_Install(char **Arguments);
\r
34 // Interface Functions
\r
35 tVFS_Node *Ext2_InitDevice(char *Device, char **Options);
\r
36 void Ext2_Unmount(tVFS_Node *Node);
\r
37 Uint64 Ext2_Read(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
\r
38 Uint64 Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
\r
39 void Ext2_CloseFile(tVFS_Node *Node);
\r
40 char *Ext2_ReadDir(tVFS_Node *Node, int Pos);
\r
41 tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *FileName);
\r
42 int Ext2_MkNod(tVFS_Node *Node, char *Name, Uint Flags);
\r
44 int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode);
\r
45 tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeId, char *Name);
\r
46 int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode);
\r
47 Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum);
\r
48 Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent);
\r
49 Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock);
\r
50 void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk);
\r
52 // === SEMI-GLOBALS ===
\r
53 MODULE_DEFINE(0, 0x5B /*v0.90*/, EXT2, Ext2_Install, NULL);
\r
54 tExt2_Disk gExt2_disks[6];
\r
55 int giExt2_count = 0;
\r
56 tVFS_Driver gExt2_FSInfo = {
\r
57 "ext2", 0, Ext2_InitDevice, Ext2_Unmount, NULL
\r
63 * \fn int Ext2_Install(char **Arguments)
\r
64 * \brief Install the Ext2 Filesystem Driver
\r
66 int Ext2_Install(char **Arguments)
\r
68 VFS_AddDriver( &gExt2_FSInfo );
\r
73 \fn tVFS_Node *Ext2_InitDevice(char *Device, char **Options)
\r
74 \brief Initializes a device to be read by by the driver
\r
75 \param Device String - Device to read from
\r
76 \param Options NULL Terminated array of option strings
\r
79 tVFS_Node *Ext2_InitDevice(char *Device, char **Options)
\r
84 tExt2_SuperBlock sb;
\r
87 ENTER("sDevice pOptions", Device, Options);
\r
90 fd = VFS_Open(Device, VFS_OPENFLAG_READ|VFS_OPENFLAG_WRITE); //Open Device
\r
92 Warning("[EXT2 ] Unable to open '%s'", Device);
\r
97 // Read Superblock at offset 1024
\r
98 VFS_ReadAt(fd, 1024, 1024, &sb); // Read Superblock
\r
100 // Sanity Check Magic value
\r
101 if(sb.s_magic != 0xEF53) {
\r
102 Warning("[EXT2 ] Volume '%s' is not an EXT2 volume", Device);
\r
109 groupCount = DivUp(sb.s_blocks_count, sb.s_blocks_per_group);
\r
110 LOG("groupCount = %i", groupCount);
\r
112 // Allocate Disk Information
\r
113 disk = malloc(sizeof(tExt2_Disk) + sizeof(tExt2_Group)*groupCount);
\r
115 Warning("[EXT2 ] Unable to allocate disk structure");
\r
121 memcpy(&disk->SuperBlock, &sb, 1024);
\r
122 disk->GroupCount = groupCount;
\r
124 // Get an inode cache handle
\r
125 disk->CacheID = Inode_GetHandle();
\r
128 LOG("s_log_block_size = 0x%x", sb.s_log_block_size);
\r
129 disk->BlockSize = 1024 << sb.s_log_block_size;
\r
131 // Read Group Information
\r
134 sb.s_first_data_block * disk->BlockSize + 1024,
\r
135 sizeof(tExt2_Group)*groupCount,
\r
140 LOG("Block Group 0");
\r
141 LOG(".bg_block_bitmap = 0x%x", disk->Groups[0].bg_block_bitmap);
\r
142 LOG(".bg_inode_bitmap = 0x%x", disk->Groups[0].bg_inode_bitmap);
\r
143 LOG(".bg_inode_table = 0x%x", disk->Groups[0].bg_inode_table);
\r
144 LOG("Block Group 1");
\r
145 LOG(".bg_block_bitmap = 0x%x", disk->Groups[1].bg_block_bitmap);
\r
146 LOG(".bg_inode_bitmap = 0x%x", disk->Groups[1].bg_inode_bitmap);
\r
147 LOG(".bg_inode_table = 0x%x", disk->Groups[1].bg_inode_table);
\r
151 Ext2_int_ReadInode(disk, 2, &inode);
\r
153 // Create Root Node
\r
154 memset(&disk->RootNode, 0, sizeof(tVFS_Node));
\r
155 disk->RootNode.Inode = 2; // Root inode ID
\r
156 disk->RootNode.ImplPtr = disk; // Save disk pointer
\r
157 disk->RootNode.Size = -1; // Fill in later (on readdir)
\r
158 disk->RootNode.Flags = VFS_FFLAG_DIRECTORY;
\r
160 disk->RootNode.ReadDir = Ext2_ReadDir;
\r
161 disk->RootNode.FindDir = Ext2_FindDir;
\r
162 //disk->RootNode.Relink = Ext2_Relink;
\r
164 // Complete root node
\r
165 disk->RootNode.UID = inode.i_uid;
\r
166 disk->RootNode.GID = inode.i_gid;
\r
167 disk->RootNode.NumACLs = 1;
\r
168 disk->RootNode.ACLs = &gVFS_ACL_EveryoneRW;
\r
171 LOG("inode.i_size = 0x%x", inode.i_size);
\r
172 LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);
\r
175 LEAVE('p', &disk->RootNode);
\r
176 return &disk->RootNode;
\r
180 * \fn void Ext2_Unmount(tVFS_Node *Node)
\r
181 * \brief Close a mounted device
\r
183 void Ext2_Unmount(tVFS_Node *Node)
\r
185 tExt2_Disk *disk = Node->ImplPtr;
\r
187 VFS_Close( disk->FD );
\r
188 Inode_ClearCache( disk->CacheID );
\r
189 memset(disk, 0, sizeof(tExt2_Disk)+disk->GroupCount*sizeof(tExt2_Group));
\r
194 * \fn Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
\r
195 * \brief Read from a file
\r
197 Uint64 Ext2_Read(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
\r
199 tExt2_Disk *disk = Node->ImplPtr;
\r
205 ENTER("pNode XOffset XLength pBuffer", Node, Offset, Length, Buffer);
\r
208 Ext2_int_GetInode(Node, &inode);
\r
211 if(Offset >= inode.i_size) {
\r
215 if(Offset + Length > inode.i_size)
\r
216 Length = inode.i_size - Offset;
\r
218 block = Offset / disk->BlockSize;
\r
219 Offset = Offset / disk->BlockSize;
\r
220 base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
\r
222 Warning("[EXT2 ] NULL Block Detected in INode 0x%llx", Node->Inode);
\r
228 if(Length <= disk->BlockSize - Offset)
\r
230 VFS_ReadAt( disk->FD, base+Offset, Length, Buffer);
\r
231 LEAVE('X', Length);
\r
235 // Read first block
\r
237 VFS_ReadAt( disk->FD, base + Offset, disk->BlockSize - Offset, Buffer);
\r
238 remLen -= disk->BlockSize - Offset;
\r
239 Buffer += disk->BlockSize - Offset;
\r
242 // Read middle blocks
\r
243 while(remLen > disk->BlockSize)
\r
245 base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
\r
247 Warning("[EXT2 ] NULL Block Detected in INode 0x%llx", Node->Inode);
\r
251 VFS_ReadAt( disk->FD, base, disk->BlockSize, Buffer);
\r
252 Buffer += disk->BlockSize;
\r
253 remLen -= disk->BlockSize;
\r
258 base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
\r
259 VFS_ReadAt( disk->FD, base, remLen, Buffer);
\r
261 LEAVE('X', Length);
\r
266 * \fn Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
\r
267 * \brief Write to a file
\r
269 Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
\r
271 tExt2_Disk *disk = Node->ImplPtr;
\r
277 int bNewBlocks = 0;
\r
279 Debug_HexDump("Ext2_Write", Buffer, Length);
\r
281 Ext2_int_GetInode(Node, &inode);
\r
283 // Get the ammount of space already allocated
\r
284 // - Round size up to block size
\r
285 // - block size is a power of two, so this will work
\r
286 allocSize = (inode.i_size + disk->BlockSize) & ~(disk->BlockSize-1);
\r
288 // Are we writing to inside the allocated space?
\r
289 if( Offset < allocSize )
\r
291 // Will we go out of it?
\r
292 if(Offset + Length > allocSize) {
\r
294 retLen = allocSize - Offset;
\r
298 // Within the allocated space
\r
299 block = Offset / disk->BlockSize;
\r
300 Offset %= disk->BlockSize;
\r
301 base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
\r
303 // Write only block (if only one)
\r
304 if(Offset + retLen <= disk->BlockSize) {
\r
305 VFS_WriteAt(disk->FD, base+Offset, retLen, Buffer);
\r
306 if(!bNewBlocks) return Length;
\r
307 goto addBlocks; // Ugh! A goto, but it seems unavoidable
\r
310 // Write First Block
\r
311 VFS_WriteAt(disk->FD, base+Offset, disk->BlockSize-Offset, Buffer);
\r
312 Buffer += disk->BlockSize-Offset;
\r
313 retLen -= disk->BlockSize-Offset;
\r
316 // Write middle blocks
\r
317 while(retLen > disk->BlockSize)
\r
319 base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
\r
320 VFS_WriteAt(disk->FD, base, disk->BlockSize, Buffer);
\r
321 Buffer += disk->BlockSize;
\r
322 retLen -= disk->BlockSize;
\r
326 // Write last block
\r
327 base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
\r
328 VFS_WriteAt(disk->FD, base, retLen, Buffer);
\r
329 if(!bNewBlocks) return Length; // Writing in only allocated space
\r
333 ///\todo Implement block allocation
\r
334 Warning("[EXT2] File extending is not yet supported");
\r
340 * \fn void Ext2_CloseFile(tVFS_Node *Node)
\r
341 * \brief Close a file (Remove it from the cache)
\r
343 void Ext2_CloseFile(tVFS_Node *Node)
\r
345 tExt2_Disk *disk = Node->ImplPtr;
\r
346 Inode_UncacheNode(disk->CacheID, Node->Inode);
\r
351 \fn char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
\r
352 \brief Reads a directory entry
\r
354 char *Ext2_ReadDir(tVFS_Node *Node, int Pos)
\r
357 char namebuf[EXT2_NAME_LEN+1];
\r
358 tExt2_DirEnt dirent;
\r
359 Uint64 Base; // Block's Base Address
\r
360 int block = 0, ofs = 0;
\r
362 tExt2_Disk *disk = Node->ImplPtr;
\r
365 ENTER("pNode iPos", Node, Pos);
\r
367 // Read directory's inode
\r
368 Ext2_int_GetInode(Node, &inode);
\r
369 size = inode.i_size;
\r
371 LOG("inode.i_block[0] = 0x%x", inode.i_block[0]);
\r
375 // - Do this ourselves as it is a simple operation
\r
376 Base = inode.i_block[0] * disk->BlockSize;
\r
377 while(Pos -- && size > 0)
\r
379 VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
\r
380 ofs += dirent.rec_len;
\r
381 size -= dirent.rec_len;
\r
384 if(ofs >= disk->BlockSize) {
\r
386 if( ofs > disk->BlockSize ) {
\r
387 Warning("[EXT2] Directory Entry %i of inode %i extends over a block boundary, ignoring",
\r
388 entNum-1, Node->Inode);
\r
391 Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
\r
395 // Check for the end of the list
\r
402 VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent );
\r
403 //LOG("dirent.inode = %i", dirent.inode);
\r
404 //LOG("dirent.rec_len = %i", dirent.rec_len);
\r
405 //LOG("dirent.name_len = %i", dirent.name_len);
\r
406 VFS_ReadAt( disk->FD, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf );
\r
407 namebuf[ dirent.name_len ] = '\0'; // Cap off string
\r
410 // Ignore . and .. (these are done in the VFS)
\r
411 if( (namebuf[0] == '.' && namebuf[1] == '\0')
\r
412 || (namebuf[0] == '.' && namebuf[1] == '.' && namebuf[2]=='\0')) {
\r
413 LEAVE('p', VFS_SKIP);
\r
414 return VFS_SKIP; // Skip
\r
417 LEAVE('s', namebuf);
\r
419 return strdup(namebuf);
\r
423 \fn tVFS_Node *Ext2_FindDir(tVFS_Node *node, char *filename)
\r
424 \brief Gets information about a file
\r
425 \param node vfs node - Parent Node
\r
426 \param filename String - Name of file
\r
427 \return VFS Node of file
\r
429 tVFS_Node *Ext2_FindDir(tVFS_Node *Node, char *Filename)
\r
431 tExt2_Disk *disk = Node->ImplPtr;
\r
433 char namebuf[EXT2_NAME_LEN+1];
\r
434 tExt2_DirEnt dirent;
\r
435 Uint64 Base; // Block's Base Address
\r
436 int block = 0, ofs = 0;
\r
440 // Read directory's inode
\r
441 Ext2_int_GetInode(Node, &inode);
\r
442 size = inode.i_size;
\r
445 // - Do this ourselves as it is a simple operation
\r
446 Base = inode.i_block[0] * disk->BlockSize;
\r
450 VFS_ReadAt( disk->FD, Base+ofs, sizeof(tExt2_DirEnt), &dirent);
\r
451 VFS_ReadAt( disk->FD, Base+ofs+sizeof(tExt2_DirEnt), dirent.name_len, namebuf );
\r
452 namebuf[ dirent.name_len ] = '\0'; // Cap off string
\r
453 // If it matches, create a node and return it
\r
454 if(strcmp(namebuf, Filename) == 0)
\r
455 return Ext2_int_CreateNode( disk, dirent.inode, namebuf );
\r
456 // Increment pointers
\r
457 ofs += dirent.rec_len;
\r
458 size -= dirent.rec_len;
\r
461 // Check for end of block
\r
462 if(ofs >= disk->BlockSize) {
\r
464 if( ofs > disk->BlockSize ) {
\r
465 Warning("[EXT2 ] Directory Entry %i of inode %i extends over a block boundary, ignoring",
\r
466 entNum-1, Node->Inode);
\r
469 Base = Ext2_int_GetBlockAddr( disk, inode.i_block, block );
\r
477 * \fn int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags)
\r
478 * \brief Create a new node
\r
480 int Ext2_MkNod(tVFS_Node *Parent, char *Name, Uint Flags)
\r
485 //==================================
\r
486 //= INTERNAL FUNCTIONS =
\r
487 //==================================
\r
491 * \fn int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode)
\r
492 * \brief Gets the inode descriptor for a node
\r
493 * \param Node node to get the Inode of
\r
494 * \param Inode Destination
\r
496 int Ext2_int_GetInode(tVFS_Node *Node, tExt2_Inode *Inode)
\r
498 return Ext2_int_ReadInode(Node->ImplPtr, Node->Inode, Inode);
\r
502 * \fn vfs_node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name)
\r
503 * \brief Create a new VFS Node
\r
505 tVFS_Node *Ext2_int_CreateNode(tExt2_Disk *Disk, Uint InodeID, char *Name)
\r
509 tVFS_Node *tmpNode;
\r
511 if( !Ext2_int_ReadInode(Disk, InodeID, &inode) )
\r
514 if( (tmpNode = Inode_GetCache(Disk->CacheID, InodeID)) )
\r
519 retNode.Inode = InodeID;
\r
520 retNode.ImplPtr = Disk;
\r
523 retNode.Size = inode.i_size;
\r
525 // Set Access Permissions
\r
526 retNode.UID = inode.i_uid;
\r
527 retNode.GID = inode.i_gid;
\r
528 retNode.NumACLs = 3;
\r
529 retNode.ACLs = VFS_UnixToAcessACL(inode.i_mode & 0777, inode.i_uid, inode.i_gid);
\r
531 // Set Function Pointers
\r
532 retNode.Read = Ext2_Read;
\r
533 retNode.Write = Ext2_Write;
\r
534 retNode.Close = Ext2_CloseFile;
\r
536 switch(inode.i_mode & EXT2_S_IFMT)
\r
540 retNode.Flags = VFS_FFLAG_SYMLINK;
\r
545 retNode.Size |= (Uint64)inode.i_dir_acl << 32;
\r
549 retNode.ReadDir = Ext2_ReadDir;
\r
550 retNode.FindDir = Ext2_FindDir;
\r
551 retNode.MkNod = Ext2_MkNod;
\r
552 //retNode.Relink = Ext2_Relink;
\r
553 retNode.Flags = VFS_FFLAG_DIRECTORY;
\r
555 // Unknown, Write protect and hide it to be safe
\r
557 retNode.Flags = VFS_FFLAG_READONLY;//|VFS_FFLAG_HIDDEN;
\r
561 // Check if the file should be hidden
\r
562 //if(Name[0] == '.') retNode.Flags |= VFS_FFLAG_HIDDEN;
\r
565 retNode.ATime = now();
\r
566 retNode.MTime = inode.i_mtime * 1000;
\r
567 retNode.CTime = inode.i_ctime * 1000;
\r
569 // Save in node cache and return saved node
\r
570 return Inode_CacheNode(Disk->CacheID, &retNode);
\r
574 * \fn int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)
\r
575 * \brief Read an inode into memory
\r
577 int Ext2_int_ReadInode(tExt2_Disk *Disk, Uint InodeId, tExt2_Inode *Inode)
\r
581 //LogF("Ext2_int_ReadInode: (Disk=%p, InodeId=%i, Inode=%p)", Disk, InodeId, Inode);
\r
582 //ENTER("pDisk iInodeId pInode", Disk, InodeId, Inode);
\r
584 if(InodeId == 0) return 0;
\r
586 InodeId --; // Inodes are numbered starting at 1
\r
588 group = InodeId / Disk->SuperBlock.s_inodes_per_group;
\r
589 subId = InodeId % Disk->SuperBlock.s_inodes_per_group;
\r
591 //LOG("group=%i, subId = %i", group, subId);
\r
594 VFS_ReadAt(Disk->FD,
\r
595 Disk->Groups[group].bg_inode_table * Disk->BlockSize + sizeof(tExt2_Inode)*subId,
\r
596 sizeof(tExt2_Inode),
\r
602 * \fn Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)
\r
603 * \brief Get the address of a block from an inode's list
\r
604 * \param Disk Disk information structure
\r
605 * \param Blocks Pointer to an inode's block list
\r
606 * \param BlockNum Block index in list
\r
608 Uint64 Ext2_int_GetBlockAddr(tExt2_Disk *Disk, Uint32 *Blocks, int BlockNum)
\r
613 return (Uint64)Blocks[BlockNum] * Disk->BlockSize;
\r
615 // Single Indirect Blocks
\r
616 iBlocks = malloc( Disk->BlockSize );
\r
617 VFS_ReadAt(Disk->FD, (Uint64)Blocks[12]*Disk->BlockSize, Disk->BlockSize, iBlocks);
\r
620 if(BlockNum < 256) {
\r
621 BlockNum = iBlocks[BlockNum];
\r
623 return (Uint64)BlockNum * Disk->BlockSize;
\r
626 // Double Indirect Blocks
\r
627 if(BlockNum < 256*256)
\r
629 VFS_ReadAt(Disk->FD, (Uint64)Blocks[13]*Disk->BlockSize, Disk->BlockSize, iBlocks);
\r
630 VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/256]*Disk->BlockSize, Disk->BlockSize, iBlocks);
\r
631 BlockNum = iBlocks[BlockNum%256];
\r
633 return (Uint64)BlockNum * Disk->BlockSize;
\r
635 // Triple Indirect Blocks
\r
636 VFS_ReadAt(Disk->FD, (Uint64)Blocks[14]*Disk->BlockSize, Disk->BlockSize, iBlocks);
\r
637 VFS_ReadAt(Disk->FD, (Uint64)iBlocks[BlockNum/(256*256)]*Disk->BlockSize, Disk->BlockSize, iBlocks);
\r
638 VFS_ReadAt(Disk->FD, (Uint64)iBlocks[(BlockNum/256)%256]*Disk->BlockSize, Disk->BlockSize, iBlocks);
\r
639 BlockNum = iBlocks[BlockNum%256];
\r
641 return (Uint64)BlockNum * Disk->BlockSize;
\r
645 * \fn Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)
\r
646 * \brief Allocate an inode (from the current group preferably)
\r
647 * \param Disk EXT2 Disk Information Structure
\r
648 * \param Parent Inode ID of the parent (used to locate the child nearby)
\r
650 Uint32 Ext2_int_AllocateInode(tExt2_Disk *Disk, Uint32 Parent)
\r
652 // Uint block = (Parent - 1) / Disk->SuperBlock.s_inodes_per_group;
\r
657 * \fn Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock)
\r
658 * \brief Allocate a block from the best possible location
\r
659 * \param Disk EXT2 Disk Information Structure
\r
660 * \param PrevBlock Previous block ID in the file
\r
662 Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock)
\r
664 int bpg = Disk->SuperBlock.s_blocks_per_group;
\r
665 Uint blockgroup = PrevBlock / bpg;
\r
666 Uint bitmap[Disk->BlockSize/sizeof(Uint)];
\r
667 Uint bitsperblock = 8*Disk->BlockSize;
\r
671 // Are there any free blocks?
\r
672 if(Disk->SuperBlock.s_free_blocks_count == 0) return 0;
\r
674 if(Disk->Groups[blockgroup].bg_free_blocks_count > 0)
\r
676 // Search block group's bitmap
\r
677 for(i = 0; i < bpg; i++)
\r
679 // Get the block in the bitmap block
\r
680 j = i & (bitsperblock-1);
\r
682 // Read in if needed
\r
686 (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,
\r
693 if( bitmap[j/32] == -1 ) {
\r
694 j = (j + 31) & ~31;
\r
699 if( bitmap[j/32] & (1 << (j%32)) )
\r
702 // Ooh! We found one
\r
706 Warning("[EXT2 ] Inconsistency detected, Group Free Block count is non-zero when no free blocks exist");
\r
707 goto checkAll; // Search the entire filesystem for a free block
\r
708 // Goto needed for neatness
\r
712 bitmap[j/32] |= (1 << (j%32));
\r
715 (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,
\r
720 Disk->Groups[blockgroup].bg_free_blocks_count --;
\r
725 Warning("[EXT2 ] TODO - Implement using blocks outside the current block group");
\r
729 // Reduce global count
\r
730 Disk->SuperBlock.s_free_blocks_count --;
\r
731 #if EXT2_UPDATE_WRITEBACK
\r
732 Ext2_int_UpdateSuperblock(Disk);
\r
739 * \fn void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)
\r
741 void Ext2_int_UpdateSuperblock(tExt2_Disk *Disk)
\r
743 VFS_WriteAt(Disk->FD, 1024, 1024, &Disk->SuperBlock);
\r