2 * Copyright (c) 2012 Paulo Alcantara <pcacjr@zytor.com>
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it would be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write the Free Software Foundation,
15 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #include <sys/dirent.h>
27 #include <klibc/compiler.h>
31 #include "xfs_types.h"
37 static inline struct inode
*xfs_new_inode(struct fs_info
*fs
)
41 inode
= alloc_inode(fs
, 0, sizeof(struct xfs_inode
));
43 malloc_error("xfs_inode structure");
48 static inline void fill_xfs_inode_pvt(struct inode
*inode
, struct fs_info
*fs
,
51 XFS_PVT(inode
)->i_agblock
=
52 agnumber_to_bytes(fs
, XFS_INO_TO_AGNO(fs
, ino
)) >> BLOCK_SHIFT(fs
);
53 XFS_PVT(inode
)->i_ino_blk
= ino_to_bytes(fs
, ino
) >> BLOCK_SHIFT(fs
);
54 XFS_PVT(inode
)->i_block_offset
=
55 XFS_INO_TO_OFFSET((struct xfs_fs_info
*)(fs
->fs_info
), ino
) <<
56 ((struct xfs_fs_info
*)(fs
->fs_info
))->inode_shift
;
59 static xfs_dinode_t
*xfs_get_ino_core(struct fs_info
*fs
, xfs_ino_t ino
)
65 xfs_debug("ino %lu", ino
);
67 blk
= ino_to_bytes(fs
, ino
) >> BLOCK_SHIFT(fs
);
68 offset
= XFS_INO_TO_OFFSET((struct xfs_fs_info
*)(fs
->fs_info
), ino
) <<
69 ((struct xfs_fs_info
*)(fs
->fs_info
))->inode_shift
;
70 if (offset
> BLOCK_SIZE(fs
)) {
71 xfs_error("Invalid inode offset in block!");
72 xfs_debug("offset: 0x%llx", offset
);
76 xfs_debug("blk %llu block offset 0x%llx", blk
, blk
<< BLOCK_SHIFT(fs
));
77 xfs_debug("inode offset in block (in bytes) is 0x%llx", offset
);
79 core
= (xfs_dinode_t
*)((uint8_t *)get_cache(fs
->fs_dev
, blk
) + offset
);
80 if (be16_to_cpu(core
->di_magic
) !=
81 be16_to_cpu(*(uint16_t *)XFS_DINODE_MAGIC
)) {
82 xfs_error("Inode core's magic number does not match!");
83 xfs_debug("magic number 0x%04x", (be16_to_cpu(core
->di_magic
)));
93 static char *get_entry_name(uint8_t *start
, uint8_t *end
)
98 s
= malloc(end
- start
+ 1);
100 malloc_error("string");
111 struct inode
*xfs_fmt_local_find_entry(const char *dname
, struct inode
*parent
,
114 xfs_dir2_sf_t
*sf
= (xfs_dir2_sf_t
*)&core
->di_literal_area
[0];
115 xfs_dir2_sf_entry_t
*sf_entry
;
116 uint8_t count
= sf
->hdr
.i8count
? sf
->hdr
.i8count
: sf
->hdr
.count
;
117 struct fs_info
*fs
= parent
->fs
;
120 xfs_dinode_t
*ncore
= NULL
;
122 xfs_debug("count %hhu i8count %hhu", sf
->hdr
.count
, sf
->hdr
.i8count
);
124 sf_entry
= (xfs_dir2_sf_entry_t
*)((uint8_t *)&sf
->list
[0] -
125 (!sf
->hdr
.i8count
? 4 : 0));
127 uint8_t *start_name
= &sf_entry
->name
[0];
128 uint8_t *end_name
= start_name
+ sf_entry
->namelen
;
131 name
= get_entry_name(start_name
, end_name
);
133 xfs_debug("entry name: %s", name
);
135 if (!strncmp(name
, dname
, strlen(dname
))) {
142 sf_entry
= (xfs_dir2_sf_entry_t
*)((uint8_t *)sf_entry
+
143 offsetof(struct xfs_dir2_sf_entry
,
146 (sf
->hdr
.i8count
? 8 : 4));
152 inode
= xfs_new_inode(fs
);
154 ino
= xfs_dir2_sf_get_inumber(sf
, (xfs_dir2_inou_t
*)(
155 (uint8_t *)sf_entry
+
156 offsetof(struct xfs_dir2_sf_entry
,
160 xfs_debug("entry inode's number %lu", ino
);
162 ncore
= xfs_get_ino_core(fs
, ino
);
163 fill_xfs_inode_pvt(inode
, fs
, ino
);
165 xfs_error("Failed to get dinode!");
170 XFS_PVT(inode
)->i_ino_blk
= ino_to_bytes(fs
, ino
) >> BLOCK_SHIFT(fs
);
171 inode
->size
= be64_to_cpu(ncore
->di_size
);
173 if (be16_to_cpu(ncore
->di_mode
) & S_IFDIR
) {
174 inode
->mode
= DT_DIR
;
175 xfs_debug("Found a directory inode!");
176 } else if (be16_to_cpu(ncore
->di_mode
) & S_IFREG
) {
177 inode
->mode
= DT_REG
;
178 xfs_debug("Found a file inode!");
179 xfs_debug("inode size %llu", inode
->size
);
190 static uint32_t xfs_getfssec(struct file
*file
, char *buf
, int sectors
,
195 return generic_getfssec(file
, buf
, sectors
, have_more
);
198 static int xfs_next_extent(struct inode
*inode
, uint32_t lstart
)
200 struct fs_info
*fs
= inode
->fs
;
201 xfs_dinode_t
*core
= NULL
;
212 core
= xfs_get_ino_core(fs
, inode
->ino
);
214 if (core
->di_format
== XFS_DINODE_FMT_EXTENTS
) {
215 /* The data fork contains the file's data extents */
216 if (XFS_PVT(inode
)->i_cur_extent
== be32_to_cpu(core
->di_nextents
))
219 rec
= (xfs_bmbt_rec_t
*)&core
->di_literal_area
[0] +
220 XFS_PVT(inode
)->i_cur_extent
++;
222 xfs_debug("l0 0x%llx l1 0x%llx", rec
->l0
, rec
->l1
);
224 /* l0:9-62 are startoff */
225 startoff
= (be64_to_cpu(rec
->l0
) & ((1ULL << 63) -1)) >> 9;
226 /* l0:0-8 and l1:21-63 are startblock */
227 startblock
= (be64_to_cpu(rec
->l0
) & ((1ULL << 9) - 1)) |
228 (be64_to_cpu(rec
->l1
) >> 21);
229 /* l1:0-20 are blockcount */
230 blockcount
= be64_to_cpu(rec
->l1
) & ((1ULL << 21) - 1);
232 xfs_debug("startoff 0x%llx startblock 0x%llx blockcount 0x%llx",
233 startoff
, startblock
, blockcount
);
235 blk
= fsblock_to_bytes(fs
, startblock
) >> BLOCK_SHIFT(fs
);
237 xfs_debug("blk %llu", blk
);
239 XFS_PVT(inode
)->i_offset
= startoff
;
241 inode
->next_extent
.pstart
= blk
<< BLOCK_SHIFT(fs
) >> SECTOR_SHIFT(fs
);
242 inode
->next_extent
.len
= ((blockcount
<< BLOCK_SHIFT(fs
)) +
243 SECTOR_SIZE(fs
) - 1) >> SECTOR_SHIFT(fs
);
252 static struct inode
*xfs_iget(const char *dname
, struct inode
*parent
)
254 struct fs_info
*fs
= parent
->fs
;
255 xfs_dinode_t
*core
= NULL
;
256 struct inode
*inode
= NULL
;
258 xfs_debug("dname %s parent %p parent ino %lu", dname
, parent
, parent
->ino
);
260 core
= xfs_get_ino_core(fs
, parent
->ino
);
262 xfs_debug("Cannot get dinode from disk. ino: 0x%llx", parent
->ino
);
266 /* TODO: Handle both shortform and block directories */
267 if (core
->di_format
== XFS_DINODE_FMT_LOCAL
) {
268 inode
= xfs_fmt_local_find_entry(dname
, parent
, core
);
270 xfs_error("Entry not found!");
274 xfs_debug("format %hhu", core
->di_format
);
275 xfs_debug("TODO: format \"local\" is the only supported ATM");
279 if (inode
->mode
== DT_REG
) {
280 XFS_PVT(inode
)->i_offset
= 0;
281 XFS_PVT(inode
)->i_cur_extent
= 0;
291 static struct inode
*xfs_iget_root(struct fs_info
*fs
)
293 xfs_dinode_t
*core
= NULL
;
294 struct inode
*inode
= xfs_new_inode(fs
);
296 xfs_debug("Looking for the root inode...");
298 core
= xfs_get_ino_core(fs
, XFS_INFO(fs
)->rootino
);
299 fill_xfs_inode_pvt(inode
, fs
, XFS_INFO(fs
)->rootino
);
301 xfs_error("Inode core's magic number does not match!");
302 xfs_debug("magic number 0x%04x", be16_to_cpu(core
->di_magic
));
306 xfs_debug("Root inode has been found!");
308 if (!(be16_to_cpu(core
->di_mode
) & S_IFDIR
)) {
309 xfs_error("root inode is not a directory ?! No makes sense...");
313 inode
->ino
= XFS_INFO(fs
)->rootino
;
314 inode
->mode
= DT_DIR
;
315 inode
->size
= be64_to_cpu(core
->di_size
);
325 static inline int xfs_read_superblock(struct fs_info
*fs
, xfs_sb_t
*sb
)
327 struct disk
*disk
= fs
->fs_dev
->disk
;
329 if (!disk
->rdwr_sectors(disk
, sb
, XFS_SB_DADDR
, 1, false))
335 static struct xfs_fs_info
*xfs_new_sb_info(xfs_sb_t
*sb
)
337 struct xfs_fs_info
*info
;
339 info
= malloc(sizeof *info
);
341 malloc_error("xfs_fs_info structure");
343 info
->blocksize
= be32_to_cpu(sb
->sb_blocksize
);
344 info
->block_shift
= sb
->sb_blocklog
;
345 info
->inopb_shift
= sb
->sb_inopblog
;
346 info
->agblk_shift
= sb
->sb_agblklog
;
347 info
->rootino
= be64_to_cpu(sb
->sb_rootino
);
348 info
->agblocks
= be32_to_cpu(sb
->sb_agblocks
);
349 info
->agblocks_shift
= sb
->sb_agblklog
;
350 info
->agcount
= be32_to_cpu(sb
->sb_agcount
);
351 info
->inodesize
= be16_to_cpu(sb
->sb_inodesize
);
352 info
->inode_shift
= sb
->sb_inodelog
;
357 static int xfs_fs_init(struct fs_info
*fs
)
359 struct disk
*disk
= fs
->fs_dev
->disk
;
361 struct xfs_fs_info
*info
;
363 xfs_debug("fs %p", fs
);
365 SECTOR_SHIFT(fs
) = disk
->sector_shift
;
366 SECTOR_SIZE(fs
) = 1 << SECTOR_SHIFT(fs
);
368 if (xfs_read_superblock(fs
, &sb
)) {
369 xfs_error("Superblock read failed");
373 if (!xfs_is_valid_magicnum(&sb
)) {
374 xfs_error("Invalid superblock");
378 xfs_debug("magicnum 0x%lX", be32_to_cpu(sb
.sb_magicnum
));
380 info
= xfs_new_sb_info(&sb
);
382 xfs_error("Failed to fill in filesystem-specific info structure");
388 xfs_debug("block_shift %u blocksize 0x%lX (%lu)", info
->block_shift
,
389 info
->blocksize
, info
->blocksize
);
391 xfs_debug("rootino 0x%llX (%llu)", info
->rootino
, info
->rootino
);
393 BLOCK_SHIFT(fs
) = info
->block_shift
;
394 BLOCK_SIZE(fs
) = info
->blocksize
;
396 cache_init(fs
->fs_dev
, BLOCK_SHIFT(fs
));
398 return BLOCK_SHIFT(fs
);
404 const struct fs_ops xfs_fs_ops
= {
406 .fs_flags
= FS_USEMEM
| FS_THISIND
,
407 .fs_init
= xfs_fs_init
,
408 .iget_root
= xfs_iget_root
,
410 .getfssec
= xfs_getfssec
,
411 .load_config
= generic_load_config
,
412 .close_file
= generic_close_file
,
413 .mangle_name
= generic_mangle_name
,
416 .next_extent
= xfs_next_extent
,