@@ -32,14 +32,18 @@ pub struct Ext2Fs<T> {
32
32
bgdt : BlockGroupDescriptorTable ,
33
33
}
34
34
35
+ const SUPERBLOCK_OFFSET : usize = 1024 ;
36
+ const BLOCK_GROUP_DESCRIPTOR_TABLE_OFFSET : usize = 2048 ;
37
+ const BGD_SIZE : usize = 32 ; // 32 bytes per block group descriptor
38
+
35
39
impl < T > Ext2Fs < T >
36
40
where
37
41
T : BlockDevice ,
38
42
{
39
43
pub fn try_new ( block_device : T ) -> Result < Self , Error > {
40
44
let mut superblock_data = [ 0_u8 ; 1024 ] ;
41
45
block_device
42
- . read_at ( 1024 , & mut superblock_data)
46
+ . read_at ( SUPERBLOCK_OFFSET , & mut superblock_data)
43
47
. map_err ( |_| Error :: UnableToReadSuperblock ) ?;
44
48
45
49
let superblock = Superblock :: try_from ( SuperblockArray :: from ( superblock_data) ) . unwrap ( ) ;
@@ -48,11 +52,10 @@ where
48
52
49
53
let mut bgdt_data = vec ! [ 0_u8 ; superblock. block_size( ) as usize ] ;
50
54
block_device
51
- . read_at ( 2048 , & mut bgdt_data)
55
+ . read_at ( BLOCK_GROUP_DESCRIPTOR_TABLE_OFFSET , & mut bgdt_data)
52
56
. map_err ( |_| Error :: UnableToReadBlockGroupDescriptorTable ) ?;
53
57
let mut bgdt = BlockGroupDescriptorTable :: new ( ) ;
54
58
for i in 0 ..number_of_block_groups as usize {
55
- const BGD_SIZE : usize = 32 ; // 32 bytes per block group descriptor
56
59
let offset = i * BGD_SIZE ;
57
60
let end = offset + BGD_SIZE ;
58
61
let bgd_data = TryInto :: < [ u8 ; BGD_SIZE ] > :: try_into ( & bgdt_data[ offset..end] ) . unwrap ( ) ;
76
79
. and_then ( |inode| Directory :: try_from ( inode) . map_err ( |_| Error :: NotDirectory ) )
77
80
}
78
81
79
- fn read_inode ( & self , addr : InodeAddress ) -> Result < ( InodeAddress , Inode ) , Error > {
82
+ pub fn read_inode ( & self , addr : InodeAddress ) -> Result < ( InodeAddress , Inode ) , Error > {
80
83
let inodes_per_group = self . superblock . inodes_per_group ( ) ;
81
84
let block_group_index = ( addr. get ( ) - 1 ) / inodes_per_group;
82
85
let block_group = & self . bgdt [ block_group_index as usize ] ;
96
99
Ok ( ( addr, Inode :: try_from ( InodeRawArray :: from ( inode_buffer) ) . expect ( "inode conversion can't fail. if it does, the logic has changed and this should propagate the error" ) ) )
97
100
}
98
101
102
+ pub fn write_inode ( & mut self , addr : InodeAddress , inode : & Inode ) -> Result < ( ) , Error > {
103
+ let inodes_per_group = self . superblock . inodes_per_group ( ) ;
104
+ let block_group_index = ( addr. get ( ) - 1 ) / inodes_per_group;
105
+ let block_group = & self . bgdt [ block_group_index as usize ] ;
106
+ let itable_start_block =
107
+ BlockAddress :: new ( block_group. inode_table_starting_block ( ) ) . unwrap ( ) ;
108
+
109
+ let index = ( addr. get ( ) - 1 ) % inodes_per_group;
110
+ let inode_size = self . superblock . inode_size ( ) ;
111
+ let address =
112
+ self . resolve_block_offset ( itable_start_block) + ( index * inode_size as u32 ) as usize ;
113
+
114
+ let inode_raw = InodeRawArray :: from ( inode) ;
115
+ self . block_device
116
+ . write_at ( address, & inode_raw. as_slice ( ) )
117
+ . map_err ( |_| Error :: DeviceWrite )
118
+ . map ( |_| ( ) )
119
+ }
120
+
99
121
pub fn read_block ( & self , addr : BlockAddress , buf : & mut [ u8 ] ) -> Result < usize , Error > {
100
122
let offset = self . resolve_block_offset ( addr) ;
101
123
self . block_device
@@ -113,4 +135,69 @@ where
113
135
fn resolve_block_offset ( & self , addr : BlockAddress ) -> usize {
114
136
( 1024 + ( addr. get ( ) - 1 ) * self . superblock . block_size ( ) ) as usize
115
137
}
138
+
139
+ pub fn allocate_block ( & mut self ) -> Result < Option < BlockAddress > , Error > {
140
+ let block_size = self . superblock . block_size ( ) ;
141
+ let blocks_per_group = self . superblock . blocks_per_group ( ) ;
142
+ let num_groups = self . bgdt . len ( ) ;
143
+
144
+ for group_index in 0 ..num_groups {
145
+ let first_free_block_index = self . try_reserve_block_in_group ( group_index) ?;
146
+ if first_free_block_index. is_none ( ) {
147
+ continue ;
148
+ }
149
+ let first_free_block_index = first_free_block_index. unwrap ( ) ;
150
+
151
+ let descriptor = & mut self . bgdt [ group_index] ;
152
+ * descriptor. num_unallocated_blocks_mut ( ) -= 1 ;
153
+
154
+ // read the block group descriptor table
155
+ let mut bgdt_data = vec ! [ 0_u8 ; block_size as usize ] ;
156
+ self . block_device
157
+ . read_at ( BLOCK_GROUP_DESCRIPTOR_TABLE_OFFSET , & mut bgdt_data)
158
+ . map_err ( |_| Error :: UnableToReadBlockGroupDescriptorTable ) ?;
159
+ // merge the changed descriptor back into the table
160
+ let bgd_offset = group_index * BGD_SIZE ;
161
+ let bgd_end = bgd_offset + BGD_SIZE ;
162
+ let bgd_data = Into :: < [ u8 ; BGD_SIZE ] > :: into ( & * descriptor) ;
163
+ bgdt_data[ bgd_offset..bgd_end] . copy_from_slice ( & bgd_data) ;
164
+ // write the block group descriptor table back
165
+ self . block_device
166
+ . write_at ( BLOCK_GROUP_DESCRIPTOR_TABLE_OFFSET , & bgdt_data)
167
+ . map_err ( |_| Error :: UnableToWriteBlockGroupDescriptorTable ) ?;
168
+
169
+
170
+ * self . superblock . num_unallocated_blocks_mut ( ) -= 1 ;
171
+ let superblock_data = Into :: < SuperblockArray > :: into ( & self . superblock ) ;
172
+ self . block_device
173
+ . write_at ( SUPERBLOCK_OFFSET , superblock_data. as_slice ( ) )
174
+ . map_err ( |_| Error :: UnableToWriteSuperblock ) ?;
175
+
176
+ let global_block_num = group_index as u32 * blocks_per_group + first_free_block_index as u32 ;
177
+ return Ok ( Some ( BlockAddress :: new ( global_block_num) . unwrap ( ) ) ) ;
178
+ }
179
+
180
+ Ok ( None )
181
+ }
182
+
183
+ /// Tries to allocate a block in the given block group and returns the index in the group
184
+ /// if successful. This reads the block usage bitmap from the block group, maybe modifies
185
+ /// it and writes it back.
186
+ fn try_reserve_block_in_group ( & mut self , group_index : usize ) -> Result < Option < usize > , Error > {
187
+ let mut block_bitmap = vec ! [ 0_u8 ; self . superblock. block_size( ) as usize ] ;
188
+ let bitmap_block = self . bgdt [ group_index] . block_usage_bitmap_block ( ) ;
189
+ let bitmap_block_address = BlockAddress :: new ( bitmap_block) . expect ( "bgdt does not have valid block address for bitmap block" ) ;
190
+ self . read_block ( bitmap_block_address, & mut block_bitmap) ?;
191
+
192
+ for ( i, byte) in block_bitmap. iter_mut ( ) . enumerate ( ) {
193
+ for bit_index in 0 ..8 {
194
+ if * byte & ( 1_u8 << bit_index) == 0 {
195
+ * byte |= 1 << bit_index;
196
+ return Ok ( Some ( i * 8 + bit_index) ) ;
197
+ }
198
+ }
199
+ }
200
+ self . write_block ( bitmap_block_address, & block_bitmap) ?;
201
+ Ok ( None )
202
+ }
116
203
}
0 commit comments