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
);
170 if (!(inode
= alloc_inode(fs
, inr
, sizeof(struct ext2_pvt_inode
))))
172 fill_inode(inode
, e_inode
);
177 static struct inode
*ext2_iget_root(struct fs_info
*fs
)
179 return ext2_iget_by_inr(fs
, EXT2_ROOT_INO
);
182 static struct inode
*ext2_iget(const char *dname
, struct inode
*parent
)
184 const struct ext2_dir_entry
*de
;
185 struct fs_info
*fs
= parent
->fs
;
187 de
= ext2_find_entry(fs
, parent
, dname
);
191 return ext2_iget_by_inr(fs
, de
->d_inode
);
195 * Read the entire contents of an inode into a memory buffer
197 static int cache_get_file(struct inode
*inode
, void *buf
, size_t bytes
)
199 struct fs_info
*fs
= inode
->fs
;
200 size_t block_size
= BLOCK_SIZE(fs
);
201 uint32_t index
= 0; /* Logical block number */
206 if (inode
->size
> bytes
)
210 chunk
= min(bytes
, block_size
);
211 data
= ext2_get_cache(inode
, index
++);
212 memcpy(p
, data
, chunk
);
221 static int ext2_readlink(struct inode
*inode
, char *buf
)
223 struct fs_info
*fs
= inode
->fs
;
224 int sec_per_block
= 1 << (fs
->block_shift
- fs
->sector_shift
);
227 if (inode
->size
> BLOCK_SIZE(fs
))
228 return -1; /* Error! */
230 fast_symlink
= (inode
->file_acl
? sec_per_block
: 0) == inode
->blocks
;
232 memcpy(buf
, PVT(inode
)->i_block
, inode
->size
);
234 cache_get_file(inode
, buf
, inode
->size
);
240 * Read one directory entry at a time
242 static int ext2_readdir(struct file
*file
, struct dirent
*dirent
)
244 struct fs_info
*fs
= file
->fs
;
245 struct inode
*inode
= file
->inode
;
246 const struct ext2_dir_entry
*de
;
248 block_t index
= file
->offset
>> fs
->block_shift
;
250 if (file
->offset
>= inode
->size
)
251 return -1; /* End of file */
253 data
= ext2_get_cache(inode
, index
);
254 de
= (const struct ext2_dir_entry
*)
255 (data
+ (file
->offset
& (BLOCK_SIZE(fs
) - 1)));
257 dirent
->d_ino
= de
->d_inode
;
258 dirent
->d_off
= file
->offset
;
259 dirent
->d_reclen
= offsetof(struct dirent
, d_name
) + de
->d_name_len
+ 1;
260 dirent
->d_type
= ext2_cvt_type(de
->d_file_type
);
261 memcpy(dirent
->d_name
, de
->d_name
, de
->d_name_len
);
262 dirent
->d_name
[de
->d_name_len
] = '\0';
264 file
->offset
+= de
->d_rec_len
; /* Update for next reading */
270 * init. the fs meta data, return the block size bits.
272 static int ext2_fs_init(struct fs_info
*fs
)
274 struct disk
*disk
= fs
->fs_dev
->disk
;
275 struct ext2_sb_info
*sbi
;
276 struct ext2_super_block sb
;
279 /* read the super block */
280 disk
->rdwr_sectors(disk
, &sb
, 2, 2, 0);
282 /* check if it is ext2, since we also support btrfs now */
283 if (sb
.s_magic
!= EXT2_SUPER_MAGIC
)
286 sbi
= malloc(sizeof(*sbi
));
288 malloc_error("ext2_sb_info structure");
293 if (sb
.s_magic
!= EXT2_SUPER_MAGIC
) {
294 printf("ext2 mount error: it's not a EXT2/3/4 file system!\n");
298 fs
->sector_shift
= disk
->sector_shift
;
299 fs
->block_shift
= sb
.s_log_block_size
+ 10;
300 fs
->sector_size
= 1 << fs
->sector_shift
;
301 fs
->block_size
= 1 << fs
->block_shift
;
303 sbi
->s_inodes_per_group
= sb
.s_inodes_per_group
;
304 sbi
->s_blocks_per_group
= sb
.s_blocks_per_group
;
305 sbi
->s_inodes_per_block
= BLOCK_SIZE(fs
) / sb
.s_inode_size
;
306 if (sb
.s_desc_size
< sizeof(struct ext2_group_desc
))
307 sb
.s_desc_size
= sizeof(struct ext2_group_desc
);
308 sbi
->s_desc_per_block
= BLOCK_SIZE(fs
) / sb
.s_desc_size
;
309 sbi
->s_groups_count
= (sb
.s_blocks_count
- sb
.s_first_data_block
310 + EXT2_BLOCKS_PER_GROUP(fs
) - 1)
311 / EXT2_BLOCKS_PER_GROUP(fs
);
312 sbi
->s_first_data_block
= sb
.s_first_data_block
;
313 sbi
->s_inode_size
= sb
.s_inode_size
;
315 /* Initialize the cache, and force block zero to all zero */
316 cache_init(fs
->fs_dev
, fs
->block_shift
);
317 cs
= _get_cache_block(fs
->fs_dev
, 0);
318 memset(cs
->data
, 0, fs
->block_size
);
319 cache_lock_block(cs
);
321 return fs
->block_shift
;
324 const struct fs_ops ext2_fs_ops
= {
326 .fs_flags
= FS_THISIND
| FS_USEMEM
,
327 .fs_init
= ext2_fs_init
,
329 .getfssec
= generic_getfssec
,
330 .close_file
= generic_close_file
,
331 .mangle_name
= generic_mangle_name
,
332 .chdir_start
= generic_chdir_start
,
333 .open_config
= generic_open_config
,
334 .iget_root
= ext2_iget_root
,
336 .readlink
= ext2_readlink
,
337 .readdir
= ext2_readdir
,
338 .next_extent
= ext2_next_extent
,