xfs: Cleanup
[syslinux.git] / core / fs / xfs / xfs.c
blobb1fa5cdf228d4899a0e7d76ed5fbe2bf97a468df
1 /*
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
18 #include <dprintf.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <sys/dirent.h>
22 #include <cache.h>
23 #include <core.h>
24 #include <disk.h>
25 #include <fs.h>
26 #include <ilog2.h>
27 #include <klibc/compiler.h>
28 #include <ctype.h>
30 #include "codepage.h"
31 #include "xfs_types.h"
32 #include "xfs_sb.h"
33 #include "xfs.h"
34 #include "xfs_ag.h"
35 #include "misc.h"
37 static inline struct inode *xfs_new_inode(struct fs_info *fs)
39 struct inode *inode;
41 inode = alloc_inode(fs, 0, sizeof(struct xfs_inode));
42 if (!inode)
43 malloc_error("xfs_inode structure");
45 return inode;
48 static inline void fill_xfs_inode_pvt(struct inode *inode, struct fs_info *fs,
49 xfs_ino_t ino)
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)
61 block_t blk;
62 xfs_dinode_t *core;
63 uint64_t offset;
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);
73 goto out;
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)));
84 goto out;
87 return core;
89 out:
90 return NULL;
93 static char *get_entry_name(uint8_t *start, uint8_t *end)
95 char *s;
96 char *p;
98 s = malloc(end - start + 1);
99 if (!s)
100 malloc_error("string");
102 p = s;
103 while (start < end)
104 *p++ = *start++;
106 *p = '\0';
108 return s;
111 struct inode *xfs_fmt_local_find_entry(const char *dname, struct inode *parent,
112 xfs_dinode_t *core)
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;
118 struct inode *inode;
119 xfs_intino_t ino;
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));
126 while (count--) {
127 uint8_t *start_name = &sf_entry->name[0];
128 uint8_t *end_name = start_name + sf_entry->namelen;
129 char *name;
131 name = get_entry_name(start_name, end_name);
133 xfs_debug("entry name: %s", name);
135 if (!strncmp(name, dname, strlen(dname))) {
136 free(name);
137 goto found;
140 free(name);
142 sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)sf_entry +
143 offsetof(struct xfs_dir2_sf_entry,
144 name[0]) +
145 sf_entry->namelen +
146 (sf->hdr.i8count ? 8 : 4));
149 return NULL;
151 found:
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,
157 name[0]) +
158 sf_entry->namelen));
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);
164 if (!ncore) {
165 xfs_error("Failed to get dinode!");
166 goto out;
169 inode->ino = ino;
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);
182 return inode;
184 out:
185 free(inode);
187 return NULL;
190 static uint32_t xfs_getfssec(struct file *file, char *buf, int sectors,
191 bool *have_more)
193 xfs_debug("in");
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;
202 xfs_bmbt_rec_t *rec;
203 uint64_t startoff;
204 uint64_t startblock;
205 uint64_t blockcount;
206 block_t blk;
208 (void)lstart;
210 xfs_debug("in");
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))
217 goto out;
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);
246 return 0;
248 out:
249 return -1;
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);
261 if (!core) {
262 xfs_debug("Cannot get dinode from disk. ino: 0x%llx", parent->ino);
263 goto out;
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);
269 if (!inode) {
270 xfs_error("Entry not found!");
271 goto out;
273 } else {
274 xfs_debug("format %hhu", core->di_format);
275 xfs_debug("TODO: format \"local\" is the only supported ATM");
276 goto out;
279 if (inode->mode == DT_REG) {
280 XFS_PVT(inode)->i_offset = 0;
281 XFS_PVT(inode)->i_cur_extent = 0;
284 return inode;
286 out:
288 return NULL;
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);
300 if (!core) {
301 xfs_error("Inode core's magic number does not match!");
302 xfs_debug("magic number 0x%04x", be16_to_cpu(core->di_magic));
303 goto out;
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...");
310 goto out;
313 inode->ino = XFS_INFO(fs)->rootino;
314 inode->mode = DT_DIR;
315 inode->size = be64_to_cpu(core->di_size);
317 return inode;
319 out:
320 free(inode);
322 return NULL;
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))
330 return -1;
332 return 0;
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);
340 if (!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;
354 return info;
357 static int xfs_fs_init(struct fs_info *fs)
359 struct disk *disk = fs->fs_dev->disk;
360 xfs_sb_t sb;
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");
370 goto out;
373 if (!xfs_is_valid_magicnum(&sb)) {
374 xfs_error("Invalid superblock");
375 goto out;
378 xfs_debug("magicnum 0x%lX", be32_to_cpu(sb.sb_magicnum));
380 info = xfs_new_sb_info(&sb);
381 if (!info) {
382 xfs_error("Failed to fill in filesystem-specific info structure");
383 goto out;
386 fs->fs_info = info;
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);
400 out:
401 return -1;
404 const struct fs_ops xfs_fs_ops = {
405 .fs_name = "xfs",
406 .fs_flags = FS_USEMEM | FS_THISIND,
407 .fs_init = xfs_fs_init,
408 .iget_root = xfs_iget_root,
409 .searchdir = NULL,
410 .getfssec = xfs_getfssec,
411 .load_config = generic_load_config,
412 .close_file = generic_close_file,
413 .mangle_name = generic_mangle_name,
414 .readdir = NULL,
415 .iget = xfs_iget,
416 .next_extent = xfs_next_extent,