-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathext4.rs
More file actions
196 lines (163 loc) · 6.4 KB
/
Copy pathext4.rs
File metadata and controls
196 lines (163 loc) · 6.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
use crate::prelude::*;
use crate::return_errno_with_message;
use crate::utils::*;
use crate::ext4_defs::*;
impl Ext4 {
/// 获取system zone缓存
pub fn get_system_zone(&self) -> Vec<SystemZone> {
let mut zones = Vec::new();
let group_count = self.super_block.block_group_count();
let inodes_per_group = self.super_block.inodes_per_group();
let inode_size = self.super_block.inode_size() as u64;
let block_size = self.super_block.block_size() as u64;
log::debug!("get_system_zone: group_count={}", group_count);
for bgid in 0..group_count {
if bgid % 1024 == 0 && bgid > 0 {
log::debug!("get_system_zone: processed {}/{} groups", bgid, group_count);
}
// meta blocks
let meta_blks = self.num_base_meta_blocks(bgid);
if meta_blks != 0 {
let start = self.get_block_of_bgid(bgid);
zones.push(SystemZone {
group: bgid,
start_blk: start,
end_blk: start + meta_blks as u64 - 1,
});
}
// block group描述符
let block_group = Ext4BlockGroup::load_new(&self.block_device, &self.super_block, bgid as usize);
// block bitmap
let blk_bmp = block_group.get_block_bitmap_block(&self.super_block);
zones.push(SystemZone {
group: bgid,
start_blk: blk_bmp,
end_blk: blk_bmp,
});
// inode bitmap
let ino_bmp = block_group.get_inode_bitmap_block(&self.super_block);
zones.push(SystemZone {
group: bgid,
start_blk: ino_bmp,
end_blk: ino_bmp,
});
// inode table
let ino_tbl = block_group.get_inode_table_blk_num() as u64;
let itb_per_group = ((inodes_per_group as u64 * inode_size + block_size - 1) / block_size) as u64;
zones.push(SystemZone {
group: bgid,
start_blk: ino_tbl,
end_blk: ino_tbl + itb_per_group - 1,
});
}
log::debug!("get_system_zone: finished, total zones={}", zones.len());
zones
}
/// Opens and loads an Ext4 from the `block_device`.
pub fn open(block_device: Arc<dyn BlockDevice>) -> Self {
// Load the superblock (aligned to block 0)
let block = Block::load(&block_device, 0);
let super_block: Ext4Superblock = block.read_offset_as(SUPERBLOCK_OFFSET);
let group_count = super_block.block_group_count() as usize;
log::debug!("Ext4::open: group_count={}", group_count);
let mut inode_table_cache = Vec::with_capacity(group_count);
for bgid in 0..group_count {
if bgid % 1024 == 0 && bgid > 0 {
log::debug!("Ext4::open: caching inode tables {}/{}", bgid, group_count);
}
let block_group = Ext4BlockGroup::load_new(&block_device, &super_block, bgid);
inode_table_cache.push(block_group.get_inode_table_blk_num());
}
let ext4_tmp = Ext4 {
block_device,
super_block,
system_zone_cache: None,
inode_table_cache,
inode_cache: spin::Mutex::new([None; 16]),
};
log::debug!("Ext4::open: initializing system zone cache");
let zones = ext4_tmp.get_system_zone();
log::debug!("Ext4::open: complete");
Ext4 {
system_zone_cache: Some(zones),
..ext4_tmp
}
}
// with dir result search path offset
pub fn generic_open(
&self,
path: &str,
parent_inode_num: &mut u32,
create: bool,
ftype: u16,
name_off: &mut u32,
) -> Result<u32> {
let mut is_goal = false;
let mut parent = parent_inode_num;
let mut search_path = path;
let mut dir_search_result = Ext4DirSearchResult::new(Ext4DirEntry::default());
loop {
while search_path.starts_with('/') {
*name_off += 1; // Skip the slash
search_path = &search_path[1..];
}
let len = path_check(search_path, &mut is_goal);
let current_path = &search_path[..len];
if len == 0 || search_path.is_empty() {
break;
}
search_path = &search_path[len..];
let r = self.dir_find_entry(*parent, current_path, &mut dir_search_result);
// log::trace!("find in parent {:x?} r {:?} name {:?}", parent, r, current_path);
if let Err(e) = r {
if e.error() != Errno::ENOENT || !create {
return_errno_with_message!(Errno::ENOENT, "No such file or directory");
}
let mut inode_mode = 0;
if is_goal {
inode_mode = ftype;
} else {
inode_mode = InodeFileType::S_IFDIR.bits();
}
let new_inode_ref = self.create(*parent, current_path, inode_mode)?;
// Update parent to the new inode
*parent = new_inode_ref.inode_num;
// Now, update dir_search_result to reflect the new inode
dir_search_result.dentry.inode = new_inode_ref.inode_num;
continue;
}
if is_goal {
break;
} else {
// update parent
*parent = dir_search_result.dentry.inode;
}
*name_off += len as u32;
}
if is_goal {
return Ok(dir_search_result.dentry.inode);
}
Ok(dir_search_result.dentry.inode)
}
#[allow(unused)]
pub fn dir_mk(&self, path: &str) -> Result<usize> {
let mut nameoff = 0;
let filetype = InodeFileType::S_IFDIR;
// todo get this path's parent
// start from root
let mut parent = ROOT_INODE;
let r = self.generic_open(path, &mut parent, true, filetype.bits(), &mut nameoff);
Ok(EOK)
}
pub fn unlink(
&self,
parent: &mut Ext4InodeRef,
child: &mut Ext4InodeRef,
name: &str,
) -> Result<usize> {
self.dir_remove_entry(parent, name)?;
let is_dir = child.inode.is_dir();
self.ialloc_free_inode(child.inode_num, is_dir);
Ok(EOK)
}
}