Reorganised the modules directory, started serious work on GUI support
[tpg/acess2.git] / Modules / Filesystems / FS_Ext2 / write.c
1 /*
2  * Acess OS
3  * Ext2 Driver Version 1
4  */
5 /**
6  * \file write.c
7  * \brief Second Extended Filesystem Driver
8  * \todo Implement file full write support
9  */
10 #define DEBUG   1
11 #define VERBOSE 0
12 #include "ext2_common.h"
13
14 // === PROTOYPES ===
15 Uint64          Ext2_Write(tVFS_Node *node, Uint64 offset, Uint64 length, void *buffer);
16 Uint32          Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock);
17
18 // === CODE ===
19 /**
20  * \fn Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
21  * \brief Write to a file
22  */
23 Uint64 Ext2_Write(tVFS_Node *Node, Uint64 Offset, Uint64 Length, void *Buffer)
24 {
25         tExt2_Disk      *disk = Node->ImplPtr;
26         tExt2_Inode     inode;
27         Uint64  base;
28         Uint64  retLen;
29         Uint    block;
30         Uint64  allocSize;
31          int    bNewBlocks = 0;
32         
33         Debug_HexDump("Ext2_Write", Buffer, Length);
34         
35         Ext2_int_GetInode(Node, &inode);
36         
37         // Get the ammount of space already allocated
38         // - Round size up to block size
39         // - block size is a power of two, so this will work
40         allocSize = (inode.i_size + disk->BlockSize) & ~(disk->BlockSize-1);
41         
42         // Are we writing to inside the allocated space?
43         if( Offset < allocSize )
44         {
45                 // Will we go out of it?
46                 if(Offset + Length > allocSize) {
47                         bNewBlocks = 1;
48                         retLen = allocSize - Offset;
49                 } else
50                         retLen = Length;
51                 
52                 // Within the allocated space
53                 block = Offset / disk->BlockSize;
54                 Offset %= disk->BlockSize;
55                 base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
56                 
57                 // Write only block (if only one)
58                 if(Offset + retLen <= disk->BlockSize) {
59                         VFS_WriteAt(disk->FD, base+Offset, retLen, Buffer);
60                         if(!bNewBlocks) return Length;
61                         goto addBlocks; // Ugh! A goto, but it seems unavoidable
62                 }
63                 
64                 // Write First Block
65                 VFS_WriteAt(disk->FD, base+Offset, disk->BlockSize-Offset, Buffer);
66                 Buffer += disk->BlockSize-Offset;
67                 retLen -= disk->BlockSize-Offset;
68                 block ++;
69                 
70                 // Write middle blocks
71                 while(retLen > disk->BlockSize)
72                 {
73                         base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
74                         VFS_WriteAt(disk->FD, base, disk->BlockSize, Buffer);
75                         Buffer += disk->BlockSize;
76                         retLen -= disk->BlockSize;
77                         block ++;
78                 }
79                 
80                 // Write last block
81                 base = Ext2_int_GetBlockAddr(disk, inode.i_block, block);
82                 VFS_WriteAt(disk->FD, base, retLen, Buffer);
83                 if(!bNewBlocks) return Length;  // Writing in only allocated space
84         }
85         
86 addBlocks:
87         ///\todo Implement block allocation
88         Warning("[EXT2] File extending is not yet supported");
89         
90         return 0;
91 }
92
93 /**
94  * \fn Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock)
95  * \brief Allocate a block from the best possible location
96  * \param Disk  EXT2 Disk Information Structure
97  * \param PrevBlock     Previous block ID in the file
98  */
99 Uint32 Ext2_int_AllocateBlock(tExt2_Disk *Disk, Uint32 PrevBlock)
100 {
101          int    bpg = Disk->SuperBlock.s_blocks_per_group;
102         Uint    blockgroup = PrevBlock / bpg;
103         Uint    bitmap[Disk->BlockSize/sizeof(Uint)];
104         Uint    bitsperblock = 8*Disk->BlockSize;
105          int    i, j = 0;
106         Uint    block;
107         
108         // Are there any free blocks?
109         if(Disk->SuperBlock.s_free_blocks_count == 0)   return 0;
110         
111         if(Disk->Groups[blockgroup].bg_free_blocks_count > 0)
112         {
113                 // Search block group's bitmap
114                 for(i = 0; i < bpg; i++)
115                 {
116                         // Get the block in the bitmap block
117                         j = i & (bitsperblock-1);
118                         
119                         // Read in if needed
120                         if(j == 0) {
121                                 VFS_ReadAt(
122                                         Disk->FD,
123                                         (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,
124                                         Disk->BlockSize,
125                                         bitmap
126                                         );
127                         }
128                         
129                         // Fast Check
130                         if( bitmap[j/32] == -1 ) {
131                                 j = (j + 31) & ~31;
132                                 continue;
133                         }
134                         
135                         // Is the bit set?
136                         if( bitmap[j/32] & (1 << (j%32)) )
137                                 continue;
138                         
139                         // Ooh! We found one
140                         break;
141                 }
142                 if( i < bpg ) {
143                         Warning("[EXT2 ] Inconsistency detected, Group Free Block count is non-zero when no free blocks exist");
144                         goto    checkAll;       // Search the entire filesystem for a free block
145                         // Goto needed for neatness
146                 }
147                 
148                 // Mark as used
149                 bitmap[j/32] |= (1 << (j%32));
150                 VFS_WriteAt(
151                         Disk->FD,
152                         (Uint64)Disk->Groups[blockgroup].bg_block_bitmap + i / bitsperblock,
153                         Disk->BlockSize,
154                         bitmap
155                         );
156                 block = i;
157                 Disk->Groups[blockgroup].bg_free_blocks_count --;
158                 #if EXT2_UPDATE_WRITEBACK
159                 //Ext2_int_UpdateBlockGroup(blockgroup);
160                 #endif
161         }
162         else
163         {
164         checkAll:
165                 Warning("[EXT2 ] TODO - Implement using blocks outside the current block group");
166                 return 0;
167         }
168         
169         // Reduce global count
170         Disk->SuperBlock.s_free_blocks_count --;
171         #if EXT2_UPDATE_WRITEBACK
172         Ext2_int_UpdateSuperblock(Disk);
173         #endif
174         
175         return block;
176 }

UCC git Repository :: git.ucc.asn.au