4 #include <sys/dirent.h>
13 * Convert an ext2 file type to the global values
15 static enum dirent_type
ext2_cvt_type(unsigned int d_file_type
)
17 static const enum dirent_type inode_type
[] = {
18 DT_UNKNOWN
, DT_REG
, DT_DIR
, DT_CHR
,
19 DT_BLK
, DT_FIFO
, DT_SOCK
, DT_LNK
,
22 if (d_file_type
> sizeof inode_type
/ sizeof *inode_type
)
25 return inode_type
[d_file_type
];
29 * get the group's descriptor of group_num
31 static const struct ext2_group_desc
*
32 ext2_get_group_desc(struct fs_info
*fs
, uint32_t group_num
)
34 struct ext2_sb_info
*sbi
= EXT2_SB(fs
);
35 uint32_t desc_block
, desc_index
;
36 const struct ext2_group_desc
*desc_data_block
;
38 if (group_num
>= sbi
->s_groups_count
) {
39 printf ("ext2_get_group_desc"
40 "block_group >= groups_count - "
41 "block_group = %d, groups_count = %d",
42 group_num
, sbi
->s_groups_count
);
47 desc_block
= group_num
/ sbi
->s_desc_per_block
;
48 desc_index
= group_num
% sbi
->s_desc_per_block
;
50 desc_block
+= sbi
->s_first_data_block
+ 1;
52 desc_data_block
= get_cache(fs
->fs_dev
, desc_block
);
53 return &desc_data_block
[desc_index
];
57 * Unlike strncmp, ext2_match_entry returns 1 for success, 0 for failure.
59 static inline bool ext2_match_entry(const char *name
, size_t len
,
60 const struct ext2_dir_entry
* de
)
64 if (len
!= de
->d_name_len
)
66 return !memcmp(name
, de
->d_name
, len
);
71 * p is at least 6 bytes before the end of page
73 static inline struct ext2_dir_entry
*ext2_next_entry(struct ext2_dir_entry
*p
)
75 return (struct ext2_dir_entry
*)((char*)p
+ p
->d_rec_len
);
79 * Map a logical sector and load it into the cache
82 ext2_get_cache(struct inode
*inode
, block_t lblock
)
84 block_t pblock
= ext2_bmap(inode
, lblock
, NULL
);
85 return get_cache(inode
->fs
->fs_dev
, pblock
);
89 * find a dir entry, return it if found, or return NULL.
91 static const struct ext2_dir_entry
*
92 ext2_find_entry(struct fs_info
*fs
, struct inode
*inode
, const char *dname
)
95 uint32_t i
= 0, offset
, maxoffset
;
96 const struct ext2_dir_entry
*de
;
98 size_t dname_len
= strlen(dname
);
100 while (i
< inode
->size
) {
101 data
= ext2_get_cache(inode
, index
++);
103 maxoffset
= min(BLOCK_SIZE(fs
), i
-inode
->size
);
105 /* The smallest possible size is 9 bytes */
106 while (offset
< maxoffset
-8) {
107 de
= (const struct ext2_dir_entry
*)(data
+ offset
);
108 if (de
->d_rec_len
> maxoffset
- offset
)
111 if (ext2_match_entry(dname
, dname_len
, de
))
114 offset
+= de
->d_rec_len
;
122 static const struct ext2_inode
*
123 ext2_get_inode(struct fs_info
*fs
, int inr
)
125 const struct ext2_group_desc
*desc
;
127 uint32_t inode_group
, inode_offset
;
128 uint32_t block_num
, block_off
;
131 inode_group
= inr
/ EXT2_INODES_PER_GROUP(fs
);
132 inode_offset
= inr
% EXT2_INODES_PER_GROUP(fs
);
133 desc
= ext2_get_group_desc(fs
, inode_group
);
137 block_num
= desc
->bg_inode_table
+
138 inode_offset
/ EXT2_INODES_PER_BLOCK(fs
);
139 block_off
= inode_offset
% EXT2_INODES_PER_BLOCK(fs
);
141 data
= get_cache(fs
->fs_dev
, block_num
);
143 return (const struct ext2_inode
*)
144 (data
+ block_off
* EXT2_SB(fs
)->s_inode_size
);
147 static void fill_inode(struct inode
*inode
, const struct ext2_inode
*e_inode
)
149 inode
->mode
= IFTODT(e_inode
->i_mode
);
150 inode
->size
= e_inode
->i_size
;
151 inode
->atime
= e_inode
->i_atime
;
152 inode
->ctime
= e_inode
->i_ctime
;
153 inode
->mtime
= e_inode
->i_mtime
;
154 inode
->dtime
= e_inode
->i_dtime
;
155 inode
->blocks
= e_inode
->i_blocks
;
156 inode
->flags
= e_inode
->i_flags
;
157 inode
->file_acl
= e_inode
->i_file_acl
;
158 memcpy(PVT(inode
)->i_block
, e_inode
->i_block
, sizeof PVT(inode
)->i_block
);
161 static struct inode
*ext2_iget_by_inr(struct fs_info
*fs
, uint32_t inr
)
163 const struct ext2_inode
*e_inode
;
166 e_inode
= ext2_get_inode(fs
, inr
);
167 if (!(inode
= alloc_inode(fs
, inr
, sizeof(struct ext2_pvt_inode
))))
169 fill_inode(inode
, e_inode
);
174 static struct inode
*ext2_iget_root(struct fs_info
*fs
)
176 return ext2_iget_by_inr(fs
, EXT2_ROOT_INO
);
179 static struct inode
*ext2_iget(const char *dname
, struct inode
*parent
)
181 const struct ext2_dir_entry
*de
;
182 struct fs_info
*fs
= parent
->fs
;
184 de
= ext2_find_entry(fs
, parent
, dname
);
188 return ext2_iget_by_inr(fs
, de
->d_inode
);
192 * Read the entire contents of an inode into a memory buffer
194 static int cache_get_file(struct inode
*inode
, void *buf
, size_t bytes
)
196 struct fs_info
*fs
= inode
->fs
;
197 size_t block_size
= BLOCK_SIZE(fs
);
198 uint32_t index
= 0; /* Logical block number */
203 if (inode
->size
> bytes
)
207 chunk
= min(bytes
, block_size
);
208 data
= ext2_get_cache(inode
, index
++);
209 memcpy(p
, data
, chunk
);
218 static int ext2_readlink(struct inode
*inode
, char *buf
)
220 struct fs_info
*fs
= inode
->fs
;
221 int sec_per_block
= 1 << (fs
->block_shift
- fs
->sector_shift
);
224 if (inode
->size
> BLOCK_SIZE(fs
))
225 return -1; /* Error! */
227 fast_symlink
= (inode
->file_acl
? sec_per_block
: 0) == inode
->blocks
;
229 memcpy(buf
, PVT(inode
)->i_block
, inode
->size
);
231 cache_get_file(inode
, buf
, inode
->size
);
237 * Read one directory entry at a time
239 static int ext2_readdir(struct file
*file
, struct dirent
*dirent
)
241 struct fs_info
*fs
= file
->fs
;
242 struct inode
*inode
= file
->inode
;
243 const struct ext2_dir_entry
*de
;
245 block_t index
= file
->offset
>> fs
->block_shift
;
247 if (file
->offset
>= inode
->size
)
248 return -1; /* End of file */
250 data
= ext2_get_cache(inode
, index
);
251 de
= (const struct ext2_dir_entry
*)
252 (data
+ (file
->offset
& (BLOCK_SIZE(fs
) - 1)));
254 dirent
->d_ino
= de
->d_inode
;
255 dirent
->d_off
= file
->offset
;
256 dirent
->d_reclen
= offsetof(struct dirent
, d_name
) + de
->d_name_len
+ 1;
257 dirent
->d_type
= ext2_cvt_type(de
->d_file_type
);
258 memcpy(dirent
->d_name
, de
->d_name
, de
->d_name_len
);
259 dirent
->d_name
[de
->d_name_len
] = '\0';
261 file
->offset
+= de
->d_rec_len
; /* Update for next reading */
267 * init. the fs meta data, return the block size bits.
269 static int ext2_fs_init(struct fs_info
*fs
)
271 struct disk
*disk
= fs
->fs_dev
->disk
;
272 struct ext2_sb_info
*sbi
;
273 struct ext2_super_block sb
;
276 /* read the super block */
277 disk
->rdwr_sectors(disk
, &sb
, 2, 2, 0);
279 /* check if it is ext2, since we also support btrfs now */
280 if (sb
.s_magic
!= EXT2_SUPER_MAGIC
)
283 sbi
= malloc(sizeof(*sbi
));
285 malloc_error("ext2_sb_info structure");
290 if (sb
.s_magic
!= EXT2_SUPER_MAGIC
) {
291 printf("ext2 mount error: it's not a EXT2/3/4 file system!\n");
295 fs
->sector_shift
= disk
->sector_shift
;
296 fs
->block_shift
= sb
.s_log_block_size
+ 10;
297 fs
->sector_size
= 1 << fs
->sector_shift
;
298 fs
->block_size
= 1 << fs
->block_shift
;
300 sbi
->s_inodes_per_group
= sb
.s_inodes_per_group
;
301 sbi
->s_blocks_per_group
= sb
.s_blocks_per_group
;
302 sbi
->s_inodes_per_block
= BLOCK_SIZE(fs
) / sb
.s_inode_size
;
303 if (sb
.s_desc_size
< sizeof(struct ext2_group_desc
))
304 sb
.s_desc_size
= sizeof(struct ext2_group_desc
);
305 sbi
->s_desc_per_block
= BLOCK_SIZE(fs
) / sb
.s_desc_size
;
306 sbi
->s_groups_count
= (sb
.s_blocks_count
- sb
.s_first_data_block
307 + EXT2_BLOCKS_PER_GROUP(fs
) - 1)
308 / EXT2_BLOCKS_PER_GROUP(fs
);
309 sbi
->s_first_data_block
= sb
.s_first_data_block
;
310 sbi
->s_inode_size
= sb
.s_inode_size
;
312 /* Initialize the cache, and force block zero to all zero */
313 cache_init(fs
->fs_dev
, fs
->block_shift
);
314 cs
= _get_cache_block(fs
->fs_dev
, 0);
315 memset(cs
->data
, 0, fs
->block_size
);
316 cache_lock_block(cs
);
318 return fs
->block_shift
;
321 const struct fs_ops ext2_fs_ops
= {
323 .fs_flags
= FS_THISIND
| FS_USEMEM
,
324 .fs_init
= ext2_fs_init
,
326 .getfssec
= generic_getfssec
,
327 .close_file
= generic_close_file
,
328 .mangle_name
= generic_mangle_name
,
329 .load_config
= generic_load_config
,
330 .iget_root
= ext2_iget_root
,
332 .readlink
= ext2_readlink
,
333 .readdir
= ext2_readdir
,
334 .next_extent
= ext2_next_extent
,