aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaulo Alcantara <pcacjr@zytor.com>2015-12-14 22:39:30 -0200
committerPaulo Alcantara <pcacjr@zytor.com>2015-12-14 22:52:44 -0200
commit8535f5386a9a6fa6bd8046a9ce8adbff3c60adc8 (patch)
tree502d2d7ce4f6e332854631a8d0f221fa657ecb8d
parent721a0af2f0ba111c31685c5f6c5481eb25346971 (diff)
downloadsyslinux-8535f5386a9a6fa6bd8046a9ce8adbff3c60adc8.tar.gz
syslinux-8535f5386a9a6fa6bd8046a9ce8adbff3c60adc8.tar.xz
syslinux-8535f5386a9a6fa6bd8046a9ce8adbff3c60adc8.zip
xfs: Add support for v3 directories
Besides supporting newer version of xfs file system, this patch also does some code refactoring and fix completely broken listing and searching on v2-3 node directories. Cc: Gene Cumm <gene.cumm@gmail.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Raphael S. Carvalho <raphael.scarv@gmail.com> Cc: Ady <ady-sf@hotmail.com> Signed-off-by: Paulo Alcantara <pcacjr@zytor.com>
-rw-r--r--core/fs/xfs/xfs.c19
-rw-r--r--core/fs/xfs/xfs.h155
-rw-r--r--core/fs/xfs/xfs_dinode.c2
-rw-r--r--core/fs/xfs/xfs_dir2.c296
-rw-r--r--core/fs/xfs/xfs_dir2.h6
-rw-r--r--core/fs/xfs/xfs_readdir.c151
6 files changed, 399 insertions, 230 deletions
diff --git a/core/fs/xfs/xfs.c b/core/fs/xfs/xfs.c
index 8dbc8032..6f459737 100644
--- a/core/fs/xfs/xfs.c
+++ b/core/fs/xfs/xfs.c
@@ -74,10 +74,13 @@ static int xfs_readdir(struct file *file, struct dirent *dirent)
return -1;
}
- if (core->di_format == XFS_DINODE_FMT_LOCAL)
+ switch (core->di_format) {
+ case XFS_DINODE_FMT_LOCAL:
return xfs_fmt_local_readdir(file, dirent, core);
- else if (core->di_format == XFS_DINODE_FMT_EXTENTS)
+ case XFS_DINODE_FMT_EXTENTS:
+ case XFS_DINODE_FMT_BTREE:
return xfs_fmt_extents_readdir(file, dirent, core);
+ }
return -1;
}
@@ -117,8 +120,10 @@ static int xfs_next_extent(struct inode *inode, uint32_t lstart)
goto out;
if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
- bmbt_irec_get(&rec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] +
- XFS_PVT(inode)->i_cur_extent++);
+ bmbt_irec_get(&rec, (xfs_bmbt_rec_t *)XFS_DFORK_PTR(core,
+ XFS_DATA_FORK) +
+ XFS_PVT(inode)->i_cur_extent);
+ XFS_PVT(inode)->i_cur_extent++;
bno = fsblock_to_bytes(fs, rec.br_startblock) >> BLOCK_SHIFT(fs);
@@ -130,7 +135,7 @@ static int xfs_next_extent(struct inode *inode, uint32_t lstart)
} else if (core->di_format == XFS_DINODE_FMT_BTREE) {
xfs_debug("XFS_DINODE_FMT_BTREE");
index = XFS_PVT(inode)->i_cur_extent++;
- rblock = (xfs_bmdr_block_t *)&core->di_literal_area[0];
+ rblock = XFS_DFORK_PTR(core, XFS_DATA_FORK);
fsize = XFS_DFORK_SIZE(core, fs, XFS_DATA_FORK);
pp = XFS_BMDR_PTR_ADDR(rblock, 1, xfs_bmdr_maxrecs(fsize, 0));
bno = fsblock_to_bytes(fs, be64_to_cpu(pp[0])) >> BLOCK_SHIFT(fs);
@@ -278,9 +283,9 @@ static int xfs_readlink(struct inode *inode, char *buf)
}
if (core->di_format == XFS_DINODE_FMT_LOCAL) {
- memcpy(buf, (char *)&core->di_literal_area[0], pathlen);
+ memcpy(buf, XFS_DFORK_PTR(core, XFS_DATA_FORK), pathlen);
} else if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
- bmbt_irec_get(&rec, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
+ bmbt_irec_get(&rec, XFS_DFORK_PTR(core, XFS_DATA_FORK));
db = fsblock_to_bytes(fs, rec.br_startblock) >> BLOCK_SHIFT(fs);
dir_buf = xfs_dir2_dirblks_get_cached(fs, db, rec.br_blockcount);
diff --git a/core/fs/xfs/xfs.h b/core/fs/xfs/xfs.h
index a8bfa932..65acd17f 100644
--- a/core/fs/xfs/xfs.h
+++ b/core/fs/xfs/xfs.h
@@ -116,6 +116,9 @@ struct xfs_fs_info;
#define XFS_DIR2_NULL_DATAPTR ((uint32_t)0)
+#define XFS_DIR3_BLOCK_MAGIC 0x58444233 /* XDB3: single block dirs */
+#define XFS_DIR3_DATA_MAGIC 0x58444433 /* XDD3: multiblock dirs */
+
/* File types and modes */
#define S_IFMT 00170000
#define S_IFSOCK 0140000
@@ -346,8 +349,19 @@ typedef struct xfs_dinode {
/* di_next_unlinked is the only non-core field in the old dinode */
uint32_t di_next_unlinked;/* agi unlinked list ptr */
- uint8_t di_literal_area[1];
-} __attribute__((packed)) xfs_dinode_t;
+
+ /* start of the extended dinode, writable fields */
+ uint32_t di_crc; /* CRC of the inode */
+ uint64_t di_changecount; /* number of attribute changes */
+ uint64_t di_lsn; /* flush sequence */
+ uint64_t di_flags2; /* more random flags */
+ uint8_t di_pad2[16];
+
+ /* fields only written to during inode creation */
+ xfs_timestamp_t di_crtime; /* time created */
+ uint64_t di_ino; /* inode number */
+ uuid_t di_uuid; /* UUID of the filesystem */
+} __attribute__((__packed__)) xfs_dinode_t;
/*
* Inode size for given fs.
@@ -359,23 +373,41 @@ typedef struct xfs_dinode {
(XFS_BTREE_LBLOCK_LEN - sizeof(xfs_bmdr_block_t))
/*
+ * Size of the core inode on disk. Version 1 and 2 inodes have
+ * the same size, but version 3 has grown a few additional fields.
+ */
+static inline unsigned int xfs_dinode_size(int version)
+{
+ if (version == 3)
+ return sizeof(struct xfs_dinode);
+ return offsetof(struct xfs_dinode, di_crc);
+}
+
+/*
* Inode data & attribute fork sizes, per inode.
*/
#define XFS_DFORK_Q(dip) ((dip)->di_forkoff != 0)
#define XFS_DFORK_BOFF(dip) ((int)((dip)->di_forkoff << 3))
-#define XFS_DFORK_DSIZE(dip, fs) \
- (XFS_DFORK_Q(dip) ? \
- XFS_DFORK_BOFF(dip) : \
- XFS_LITINO(fs))
-#define XFS_DFORK_ASIZE(dip, fs) \
- (XFS_DFORK_Q(dip) ? \
- XFS_LITINO(fs) - XFS_DFORK_BOFF(dip) : \
- 0)
-#define XFS_DFORK_SIZE(dip, fs, w) \
- ((w) == XFS_DATA_FORK ? \
- XFS_DFORK_DSIZE(dip, fs) : \
- XFS_DFORK_ASIZE(dip, fs))
+#define XFS_DFORK_DSIZE(dip, fs) \
+ (XFS_DFORK_Q(dip) ? \
+ XFS_DFORK_BOFF(dip) : \
+ XFS_LITINO(fs))
+#define XFS_DFORK_ASIZE(dip, fs) \
+ (XFS_DFORK_Q(dip) ? \
+ XFS_LITINO(fs) - XFS_DFORK_BOFF(dip) : \
+ 0)
+#define XFS_DFORK_SIZE(dip, fs, w) \
+ ((w) == XFS_DATA_FORK ? \
+ XFS_DFORK_DSIZE(dip, fs) : \
+ XFS_DFORK_ASIZE(dip, fs))
+
+#define XFS_DFORK_DPTR(dip) \
+ ((void *)((uint8_t *)dip + xfs_dinode_size(dip->di_version)))
+#define XFS_DFORK_APTR(dip) \
+ ((void *)((uint8_t *)XFS_DFORK_DPTR(dip) + XFS_DFORK_BOFF(dip)))
+#define XFS_DFORK_PTR(dip,w) \
+ ((w) == XFS_DATA_FORK ? XFS_DFORK_DPTR(dip) : XFS_DFORK_APTR(dip))
struct xfs_inode {
xfs_agblock_t i_agblock;
@@ -406,13 +438,12 @@ typedef struct xfs_dir2_sf_hdr {
typedef struct xfs_dir2_sf_entry {
uint8_t namelen; /* actual name length */
xfs_dir2_sf_off_t offset; /* saved offset */
- uint8_t name[1]; /* name, variable size */
- xfs_dir2_inou_t inumber; /* inode number, var. offset */
+ uint8_t name[]; /* name, variable size */
} __attribute__((__packed__)) xfs_dir2_sf_entry_t;
typedef struct xfs_dir2_sf {
- xfs_dir2_sf_hdr_t hdr; /* shortform header */
- xfs_dir2_sf_entry_t list[1]; /* shortform entries */
+ xfs_dir2_sf_hdr_t hdr; /* shortform header */
+ xfs_dir2_sf_entry_t list[]; /* shortform entries */
} __attribute__((__packed__)) xfs_dir2_sf_t;
typedef xfs_ino_t xfs_intino_t;
@@ -483,6 +514,21 @@ typedef struct xfs_dir2_data_unused {
/* uint16_t tag; */ /* starting offset of us */
} __attribute__((__packed__)) xfs_dir2_data_unused_t;
+struct xfs_dir3_blk_hdr {
+ uint32_t magic; /* magic number */
+ uint32_t crc; /* CRC of block */
+ uint64_t blkno; /* first block of the buffer */
+ uint64_t lsn; /* sequence number of last write */
+ uuid_t uuid; /* filesystem we belong to */
+ uint64_t owner; /* inode that owns the block */
+} __attribute__((__packed__));
+
+struct xfs_dir3_data_hdr {
+ struct xfs_dir3_blk_hdr hdr;
+ xfs_dir2_data_free_t best_free[XFS_DIR2_DATA_FD_COUNT];
+ uint32_t pad; /* 64 bit alignment */
+} __attribute__((__packed__));
+
/**
* rol32 - rotate a 32-bit value left
* @word: value to rotate
@@ -502,10 +548,17 @@ static inline uint32_t rol32(uint32_t word, signed int shift)
static inline int xfs_dir2_data_entsize(int n)
{
- return (int)roundup(offsetof(struct xfs_dir2_data_entry, name[0]) + n +
+ return (int)roundup(offsetof(struct xfs_dir2_data_entry, name[0]) + n +
(unsigned int)sizeof(uint16_t), XFS_DIR2_DATA_ALIGN);
}
+static inline int xfs_dir3_data_entsize(int n)
+{
+ return (int)roundup(offsetof(struct xfs_dir2_data_entry, name[0]) + n +
+ (unsigned int)sizeof(uint16_t) + sizeof(uint8_t),
+ XFS_DIR2_DATA_ALIGN);
+}
+
static inline uint16_t *
xfs_dir2_data_entry_tag_p(struct xfs_dir2_data_entry *dep)
{
@@ -598,25 +651,67 @@ typedef struct xfs_dir2_leaf {
xfs_dir2_leaf_entry_t ents[]; /* entries */
} __attribute__((__packed__)) xfs_dir2_leaf_t;
+typedef struct xfs_da3_blkinfo {
+ /*
+ * the node link manipulation code relies on the fact that the first
+ * element of this structure is the struct xfs_da_blkinfo so it can
+ * ignore the differences in the rest of the structures.
+ */
+ xfs_da_blkinfo_t hdr;
+ uint32_t crc; /* CRC of block */
+ uint64_t blkno; /* first block of the buffer */
+ uint64_t lsn; /* sequence number of last write */
+ uuid_t uuid; /* filesystem we belong to */
+ uint64_t owner; /* inode that owns the block */
+} __attribute__((__packed__)) xfs_da3_blkinfo_t;
+
+typedef struct xfs_dir3_leaf_hdr {
+ xfs_da3_blkinfo_t info; /* header for da routines */
+ uint16_t count; /* count of entries */
+ uint16_t stale; /* count of stale entries */
+ uint32_t pad; /* 64 bit alignment */
+} __attribute__((__packed__)) xfs_dir3_leaf_hdr_t;
+
+typedef struct xfs_dir3_leaf {
+ xfs_dir3_leaf_hdr_t hdr; /* leaf header */
+ xfs_dir2_leaf_entry_t ents[]; /* entries */
+} __attribute__((__packed__)) xfs_dir3_leaf_t;
+
#define XFS_DA_NODE_MAGIC 0xfebeU /* magic number: non-leaf blocks */
#define XFS_ATTR_LEAF_MAGIC 0xfbeeU /* magic number: attribute leaf blks */
#define XFS_DIR2_LEAF1_MAGIC 0xd2f1U /* magic number: v2 dirlf single blks */
#define XFS_DIR2_LEAFN_MAGIC 0xd2ffU /* magic number: V2 dirlf multi blks */
+#define XFS_DA3_NODE_MAGIC 0x3ebe /* magic number: non-leaf blocks */
+#define XFS_ATTR3_LEAF_MAGIC 0x3bee /* magic number: attribute leaf blks */
+#define XFS_DIR3_LEAF1_MAGIC 0x3df1 /* magic number: v2 dirlf single blks */
+#define XFS_DIR3_LEAFN_MAGIC 0x3dff /* magic number: v2 dirlf multi blks */
+
+#define XFS_DIR3_LEAF1_MAGIC 0x3df1 /* magic number: v2 dirlf single blks */
+#define XFS_DIR3_LEAFN_MAGIC 0x3dff /* magic number: v2 dirlf multi blks */
+
+typedef struct xfs_da_node_hdr {
+ xfs_da_blkinfo_t info; /* block type, links, etc. */
+ uint16_t count; /* count of active entries */
+ uint16_t level; /* level above leaves (leaf == 0) */
+} __attribute__((__packed__)) xfs_da_node_hdr_t;
+
+typedef struct xfs_da_node_entry {
+ uint32_t hashval; /* hash value for this descendant */
+ uint32_t before; /* Btree block before this key */
+} __attribute__((__packed__)) xfs_da_node_entry_t;
+
typedef struct xfs_da_intnode {
- struct xfs_da_node_hdr { /* constant-structure header block */
- xfs_da_blkinfo_t info; /* block type, links, etc. */
- uint16_t count; /* count of active entries */
- uint16_t level; /* level above leaves (leaf == 0) */
- } hdr;
- struct xfs_da_node_entry {
- uint32_t hashval; /* hash value for this descendant */
- uint32_t before; /* Btree block before this key */
- } btree[1];
+ xfs_da_node_hdr_t hdr;
+ xfs_da_node_entry_t btree[];
} __attribute__((__packed__)) xfs_da_intnode_t;
-typedef struct xfs_da_node_hdr xfs_da_node_hdr_t;
-typedef struct xfs_da_node_entry xfs_da_node_entry_t;
+typedef struct xfs_da3_node_hdr {
+ xfs_da3_blkinfo_t info; /* block type, links, etc. */
+ uint16_t count; /* count of active entries */
+ uint16_t level; /* level above leaves (leaf == 0) */
+ uint32_t pad32;
+} __attribute__((__packed__)) xfs_da3_node_hdr_t;
static inline bool xfs_is_valid_sb(const xfs_sb_t *sb)
{
diff --git a/core/fs/xfs/xfs_dinode.c b/core/fs/xfs/xfs_dinode.c
index 55be6e2d..dff73826 100644
--- a/core/fs/xfs/xfs_dinode.c
+++ b/core/fs/xfs/xfs_dinode.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2013 Paulo Alcantara <pcacjr@zytor.com>
+ * Copyright (c) 2012-2015 Paulo Alcantara <pcacjr@zytor.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
diff --git a/core/fs/xfs/xfs_dir2.c b/core/fs/xfs/xfs_dir2.c
index de37ef7c..f738a582 100644
--- a/core/fs/xfs/xfs_dir2.c
+++ b/core/fs/xfs/xfs_dir2.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2013 Paulo Alcantara <pcacjr@zytor.com>
+ * Copyright (c) 2012-2015 Paulo Alcantara <pcacjr@zytor.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -67,30 +67,29 @@ uint32_t xfs_dir2_da_hashname(const uint8_t *name, int namelen)
}
static void *get_dirblks(struct fs_info *fs, block_t startblock,
- xfs_filblks_t c)
+ xfs_filblks_t c)
{
- int count = c << XFS_INFO(fs)->dirblklog;
- uint8_t *p;
- uint8_t *buf;
- off_t offset = 0;
+ const size_t len = c * XFS_INFO(fs)->dirblksize;
+ uint64_t offs = startblock << BLOCK_SHIFT(fs);
+ void *buf;
+ size_t ret;
- buf = malloc(c * XFS_INFO(fs)->dirblksize);
+ buf = malloc(len);
if (!buf)
malloc_error("buffer memory");
+ memset(buf, 0, len);
- memset(buf, 0, XFS_INFO(fs)->dirblksize);
-
- while (count--) {
- p = (uint8_t *)get_cache(fs->fs_dev, startblock++);
- memcpy(buf + offset, p, BLOCK_SIZE(fs));
- offset += BLOCK_SIZE(fs);
+ ret = cache_read(fs, buf, offs, len);
+ if (ret != len) {
+ xfs_error("failed to read contiguous directory blocks\n");
+ free(buf);
+ return NULL;
}
-
return buf;
}
-const void *xfs_dir2_dirblks_get_cached(struct fs_info *fs, block_t startblock,
- xfs_filblks_t c)
+void *xfs_dir2_dirblks_get_cached(struct fs_info *fs, block_t startblock,
+ xfs_filblks_t c)
{
unsigned char i;
void *buf;
@@ -100,6 +99,8 @@ const void *xfs_dir2_dirblks_get_cached(struct fs_info *fs, block_t startblock,
if (!dirblks_cached_count) {
buf = get_dirblks(fs, startblock, c);
+ if (!buf)
+ return NULL;
dirblks_cache[dirblks_cached_count].dc_startblock = startblock;
dirblks_cache[dirblks_cached_count].dc_blkscount = c;
@@ -116,6 +117,8 @@ const void *xfs_dir2_dirblks_get_cached(struct fs_info *fs, block_t startblock,
}
buf = get_dirblks(fs, startblock, c);
+ if (!buf)
+ return NULL;
dirblks_cache[XFS_DIR2_DIRBLKS_CACHE_SIZE / 2].dc_startblock =
startblock;
@@ -144,6 +147,8 @@ const void *xfs_dir2_dirblks_get_cached(struct fs_info *fs, block_t startblock,
}
buf = get_dirblks(fs, startblock, c);
+ if (!buf)
+ return NULL;
dirblks_cache[dirblks_cached_count].dc_startblock = startblock;
dirblks_cache[dirblks_cached_count].dc_blkscount = c;
@@ -152,7 +157,6 @@ const void *xfs_dir2_dirblks_get_cached(struct fs_info *fs, block_t startblock,
return dirblks_cache[dirblks_cached_count++].dc_area;
}
}
-
return NULL;
}
@@ -171,23 +175,27 @@ void xfs_dir2_dirblks_flush_cache(void)
struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode *parent,
xfs_dinode_t *core)
{
- xfs_dir2_sf_t *sf = (xfs_dir2_sf_t *)&core->di_literal_area[0];
+ xfs_dir2_sf_t *sf = XFS_DFORK_PTR(core, XFS_DATA_FORK);
xfs_dir2_sf_entry_t *sf_entry;
+ uint8_t ftypelen = core->di_version == 3 ? 1 : 0;
uint8_t count = sf->hdr.i8count ? sf->hdr.i8count : sf->hdr.count;
struct fs_info *fs = parent->fs;
struct inode *inode;
+ xfs_dir2_inou_t *inou;
xfs_intino_t ino;
xfs_dinode_t *ncore = NULL;
xfs_debug("dname %s parent %p core %p", dname, parent, core);
xfs_debug("count %hhu i8count %hhu", sf->hdr.count, sf->hdr.i8count);
- sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)&sf->list[0] -
+ sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)sf->list -
(!sf->hdr.i8count ? 4 : 0));
while (count--) {
- uint8_t *start_name = &sf_entry->name[0];
+ uint8_t *start_name = sf_entry->name;
uint8_t *end_name = start_name + sf_entry->namelen;
+ xfs_debug("namelen %u", sf_entry->namelen);
+
if (!xfs_dir2_entry_name_cmp(start_name, end_name, dname)) {
xfs_debug("Found entry %s", dname);
goto found;
@@ -195,8 +203,9 @@ struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode *parent,
sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)sf_entry +
offsetof(struct xfs_dir2_sf_entry,
- name[0]) +
+ name) +
sf_entry->namelen +
+ ftypelen +
(sf->hdr.i8count ? 8 : 4));
}
@@ -205,11 +214,12 @@ struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode *parent,
found:
inode = xfs_new_inode(fs);
- ino = xfs_dir2_sf_get_inumber(sf, (xfs_dir2_inou_t *)(
- (uint8_t *)sf_entry +
- offsetof(struct xfs_dir2_sf_entry,
- name[0]) +
- sf_entry->namelen));
+ inou = (xfs_dir2_inou_t *)((uint8_t *)sf_entry +
+ offsetof(struct xfs_dir2_sf_entry,
+ name) +
+ sf_entry->namelen +
+ ftypelen);
+ ino = xfs_dir2_sf_get_inumber(sf, inou);
xfs_debug("entry inode's number %lu", ino);
@@ -251,6 +261,7 @@ struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent,
block_t dir_blk;
struct fs_info *fs = parent->fs;
const uint8_t *dirblk_buf;
+ bool isdir3;
uint8_t *p, *endp;
xfs_dir2_data_hdr_t *hdr;
struct inode *inode = NULL;
@@ -262,18 +273,26 @@ struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent,
xfs_debug("dname %s parent %p core %p", dname, parent, core);
- bmbt_irec_get(&r, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
+ bmbt_irec_get(&r, XFS_DFORK_PTR(core, XFS_DATA_FORK));
dir_blk = fsblock_to_bytes(fs, r.br_startblock) >> BLOCK_SHIFT(fs);
dirblk_buf = xfs_dir2_dirblks_get_cached(fs, dir_blk, r.br_blockcount);
+ if (!dirblk_buf)
+ return NULL;
+
hdr = (xfs_dir2_data_hdr_t *)dirblk_buf;
- if (be32_to_cpu(hdr->magic) != XFS_DIR2_BLOCK_MAGIC) {
+ if (be32_to_cpu(hdr->magic) == XFS_DIR2_BLOCK_MAGIC) {
+ isdir3 = false;
+ } else if (be32_to_cpu(hdr->magic) == XFS_DIR3_BLOCK_MAGIC) {
+ isdir3 = true;
+ } else {
xfs_error("Block directory header's magic number does not match!");
xfs_debug("hdr->magic: 0x%lx", be32_to_cpu(hdr->magic));
goto out;
}
- p = (uint8_t *)(hdr + 1);
+ p = (uint8_t *)dirblk_buf + (isdir3 ? sizeof(struct xfs_dir3_data_hdr) :
+ sizeof(struct xfs_dir2_data_hdr));
btp = xfs_dir2_block_tail_p(XFS_INFO(fs), hdr);
endp = (uint8_t *)((xfs_dir2_leaf_entry_t *)btp - be32_to_cpu(btp->count));
@@ -290,7 +309,7 @@ struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent,
dep = (xfs_dir2_data_entry_t *)p;
- start_name = &dep->name[0];
+ start_name = dep->name;
end_name = start_name + dep->namelen;
if (!xfs_dir2_entry_name_cmp(start_name, end_name, dname)) {
@@ -298,7 +317,8 @@ struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent,
goto found;
}
- p += xfs_dir2_data_entsize(dep->namelen);
+ p += (isdir3 ? xfs_dir3_data_entsize(dep->namelen) :
+ xfs_dir2_data_entsize(dep->namelen));
}
out:
@@ -348,7 +368,9 @@ failed:
struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
xfs_dinode_t *core)
{
- xfs_dir2_leaf_t *leaf;
+ xfs_dir2_leaf_hdr_t *hdr;
+ xfs_dir2_leaf_entry_t *ents;
+ uint16_t count;
xfs_bmbt_irec_t irec;
block_t leaf_blk, dir_blk;
xfs_dir2_leaf_entry_t *lep;
@@ -358,37 +380,47 @@ struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
uint32_t hash = 0;
uint32_t hashwant;
uint32_t newdb, curdb = -1;
- xfs_dir2_data_entry_t *dep;
+ xfs_dir2_data_entry_t *dep = NULL;
struct inode *ip;
xfs_dir2_data_hdr_t *data_hdr;
uint8_t *start_name;
uint8_t *end_name;
xfs_intino_t ino;
xfs_dinode_t *ncore;
- const uint8_t *buf = NULL;
+ uint8_t *buf = NULL;
xfs_debug("dname %s parent %p core %p", dname, parent, core);
- bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) +
+ bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)XFS_DFORK_PTR(core, XFS_DATA_FORK) +
be32_to_cpu(core->di_nextents) - 1);
leaf_blk = fsblock_to_bytes(parent->fs, irec.br_startblock) >>
BLOCK_SHIFT(parent->fs);
- leaf = (xfs_dir2_leaf_t *)xfs_dir2_dirblks_get_cached(parent->fs, leaf_blk,
- irec.br_blockcount);
- if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC) {
+ hdr = xfs_dir2_dirblks_get_cached(parent->fs, leaf_blk,
+ irec.br_blockcount);
+ if (!hdr)
+ return NULL;
+
+ if (be16_to_cpu(hdr->info.magic) == XFS_DIR2_LEAF1_MAGIC) {
+ count = be16_to_cpu(hdr->count);
+ ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)hdr +
+ sizeof(struct xfs_dir2_leaf_hdr));
+ } else if (be16_to_cpu(hdr->info.magic) == XFS_DIR3_LEAF1_MAGIC) {
+ count = be16_to_cpu(((xfs_dir3_leaf_hdr_t *)hdr)->count);
+ ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)hdr +
+ sizeof(struct xfs_dir3_leaf_hdr));
+ } else {
xfs_error("Single leaf block header's magic number does not match!");
goto out;
}
- if (!leaf->hdr.count)
+ if (!count)
goto out;
hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname));
/* Binary search */
- for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) - 1;
- low <= high; ) {
+ for (lep = ents, low = 0, high = count - 1; low <= high; ) {
mid = (low + high) >> 1;
if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant)
break;
@@ -407,10 +439,8 @@ struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant)
mid--;
- for (lep = &leaf->ents[mid];
- mid < be16_to_cpu(leaf->hdr.count) &&
- be32_to_cpu(lep->hashval) == hashwant;
- lep++, mid++) {
+ for (lep = &ents[mid];
+ mid < count && be32_to_cpu(lep->hashval) == hashwant; lep++, mid++) {
/* Skip over stale leaf entries. */
if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
continue;
@@ -418,13 +448,17 @@ struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
newdb = xfs_dir2_dataptr_to_db(parent->fs, be32_to_cpu(lep->address));
if (newdb != curdb) {
bmbt_irec_get(&irec,
- ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) + newdb);
+ (xfs_bmbt_rec_t *)XFS_DFORK_PTR(core,
+ XFS_DATA_FORK) +
+ newdb);
dir_blk = fsblock_to_bytes(parent->fs, irec.br_startblock) >>
BLOCK_SHIFT(parent->fs);
- buf = xfs_dir2_dirblks_get_cached(parent->fs, dir_blk, irec.br_blockcount);
+ buf = xfs_dir2_dirblks_get_cached(parent->fs, dir_blk,
+ irec.br_blockcount);
data_hdr = (xfs_dir2_data_hdr_t *)buf;
- if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+ if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC &&
+ be32_to_cpu(data_hdr->magic) != XFS_DIR3_DATA_MAGIC) {
xfs_error("Leaf directory's data magic No. does not match!");
goto out;
}
@@ -432,10 +466,10 @@ struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
curdb = newdb;
}
- dep = (xfs_dir2_data_entry_t *)((char *)buf +
- xfs_dir2_dataptr_to_off(parent->fs, be32_to_cpu(lep->address)));
-
- start_name = &dep->name[0];
+ dep = (xfs_dir2_data_entry_t *)(
+ buf + xfs_dir2_dataptr_to_off(parent->fs,
+ be32_to_cpu(lep->address)));
+ start_name = dep->name;
end_name = start_name + dep->namelen;
if (!xfs_dir2_entry_name_cmp(start_name, end_name, dname)) {
@@ -523,7 +557,7 @@ block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core,
int nextents;
xfs_bmbt_ptr_t *pp;
xfs_bmbt_key_t *kp;
- xfs_btree_block_t *blk;
+ const xfs_btree_block_t *blk;
xfs_bmbt_rec_t *xp;
*error = 0;
@@ -531,7 +565,8 @@ block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core,
xfs_debug("XFS_DINODE_FMT_EXTENTS");
for (idx = 0; idx < be32_to_cpu(core->di_nextents); idx++) {
bmbt_irec_get(&irec,
- ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) + idx);
+ (xfs_bmbt_rec_t *)
+ XFS_DFORK_PTR(core, XFS_DATA_FORK) + idx);
if (fsblkno >= irec.br_startoff &&
fsblkno < irec.br_startoff + irec.br_blockcount)
break;
@@ -539,7 +574,7 @@ block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core,
} else if (core->di_format == XFS_DINODE_FMT_BTREE) {
xfs_debug("XFS_DINODE_FMT_BTREE");
bno = NULLFSBLOCK;
- rblock = (xfs_bmdr_block_t *)&core->di_literal_area[0];
+ rblock = XFS_DFORK_PTR(core, XFS_DATA_FORK);
fsize = XFS_DFORK_SIZE(core, fs, XFS_DATA_FORK);
pp = XFS_BMDR_PTR_ADDR(rblock, 1, xfs_bmdr_maxrecs(fsize, 0));
kp = XFS_BMDR_KEY_ADDR(rblock, 1);
@@ -549,7 +584,7 @@ block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core,
/* Find the leaf */
for (;;) {
- blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+ blk = get_cache(fs->fs_dev, bno);
if (be16_to_cpu(blk->bb_level) == 0)
break;
pp = XFS_BMBT_PTR_ADDR(fs, blk, 1,
@@ -576,7 +611,7 @@ block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core,
if (nextbno == NULLFSBLOCK)
break;
bno = fsblock_to_bytes(fs, nextbno) >> BLOCK_SHIFT(fs);
- blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
+ blk = get_cache(fs->fs_dev, bno);
}
}
@@ -593,110 +628,99 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
xfs_dinode_t *core)
{
block_t fsblkno;
- xfs_da_intnode_t *node = NULL;
+ xfs_da_node_hdr_t *nhdr;
uint32_t hashwant;
- uint32_t hash = 0;
+ uint32_t hash;
+ uint16_t i;
+ uint16_t count;
xfs_da_node_entry_t *btree;
- uint16_t max;
- uint16_t span;
- uint16_t probe;
int error;
+ xfs_dir2_leaf_hdr_t *lhdr;
xfs_dir2_data_hdr_t *data_hdr;
- xfs_dir2_leaf_t *leaf;
xfs_dir2_leaf_entry_t *lep;
xfs_dir2_data_entry_t *dep;
+ xfs_dir2_leaf_entry_t *ents;
struct inode *ip;
uint8_t *start_name;
uint8_t *end_name;
int low;
int high;
- int mid = 0;
- uint32_t newdb, curdb = -1;
+ int mid;
+ uint32_t newdb;
+ uint32_t curdb;
xfs_intino_t ino;
xfs_dinode_t *ncore;
- const uint8_t *buf = NULL;
+ uint8_t *buf = NULL;
xfs_debug("dname %s parent %p core %p", dname, parent, core);
- hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname));
-
- fsblkno = xfs_dir2_get_right_blk(parent->fs, core,
- xfs_dir2_byte_to_db(parent->fs, XFS_DIR2_LEAF_OFFSET),
- &error);
+ curdb = xfs_dir2_byte_to_db(parent->fs, XFS_DIR2_LEAF_OFFSET);
+ fsblkno = xfs_dir2_get_right_blk(parent->fs, core, curdb, &error);
if (error) {
xfs_error("Cannot find right rec!");
return NULL;
}
- node = (xfs_da_intnode_t *)xfs_dir2_dirblks_get_cached(parent->fs, fsblkno,
- 1);
- if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) {
- xfs_error("Node's magic number does not match!");
+ nhdr = xfs_dir2_dirblks_get_cached(parent->fs, fsblkno, 1);
+ if (be16_to_cpu(nhdr->info.magic) == XFS_DA_NODE_MAGIC) {
+ count = be16_to_cpu(nhdr->count);
+ btree = (xfs_da_node_entry_t *)((uint8_t *)nhdr +
+ sizeof(struct xfs_da_node_hdr));
+ } else if (be16_to_cpu(nhdr->info.magic) == XFS_DA3_NODE_MAGIC) {
+ count = be16_to_cpu(((xfs_da3_node_hdr_t *)nhdr)->count);
+ btree = (xfs_da_node_entry_t *)((uint8_t *)nhdr +
+ sizeof(struct xfs_da3_node_hdr));
+ } else {
+ xfs_error("Node's magic number (0x%04x) does not match!");
goto out;
}
- do {
- if (!node->hdr.count)
- goto out;
-
- /* Given a hash to lookup, you read the node's btree array and first
- * "hashval" in the array that exceeds the given hash and it can then
- * be found in the block pointed by the "before" value.
- */
- max = be16_to_cpu(node->hdr.count);
-
- probe = span = max/2;
- for (btree = &node->btree[probe];
- span > 4; btree = &node->btree[probe]) {
- span /= 2;
- hash = be32_to_cpu(btree->hashval);
-
- if (hash < hashwant)
- probe += span;
- else if (hash > hashwant)
- probe -= span;
- else
- break;
- }
-
- while ((probe > 0) && (be32_to_cpu(btree->hashval) >= hashwant)) {
- btree--;
- probe--;
- }
-
- while ((probe < max) && (be32_to_cpu(btree->hashval) < hashwant)) {
- btree++;
- probe++;
- }
+ hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname));
- if (probe == max)
- fsblkno = be32_to_cpu(node->btree[max-1].before);
- else
- fsblkno = be32_to_cpu(node->btree[probe].before);
+ /* Given a hash to lookup, you read the node's btree array and first
+ * "hashval" in the array that exceeds the given hash and it can then
+ * be found in the block pointed by the "before" value.
+ */
+ fsblkno = 0;
+ for (i = 0; i < count; i++) {
+ if (hashwant < be32_to_cpu(btree[i].hashval)) {
+ fsblkno = be32_to_cpu(btree[i].before);
+ break;
+ }
+ }
- fsblkno = xfs_dir2_get_right_blk(parent->fs, core, fsblkno, &error);
- if (error) {
- xfs_error("Cannot find right rec!");
- goto out;
- }
+ if (!fsblkno)
+ goto out;
- node = (xfs_da_intnode_t *)xfs_dir2_dirblks_get_cached(parent->fs,
- fsblkno, 1);
- } while(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
+ fsblkno = xfs_dir2_get_right_blk(parent->fs, core, fsblkno, &error);
+ if (error) {
+ xfs_error("Cannot find leaf record");
+ goto out;
+ }
- leaf = (xfs_dir2_leaf_t*)node;
- if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) {
- xfs_error("Leaf's magic number does not match!");
+ lhdr = xfs_dir2_dirblks_get_cached(parent->fs, fsblkno, 1);
+ if (be16_to_cpu(lhdr->info.magic) == XFS_DIR2_LEAFN_MAGIC) {
+ count = be16_to_cpu(lhdr->count);
+ ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)lhdr +
+ sizeof(struct xfs_dir2_leaf_hdr));
+ } else if (be16_to_cpu(lhdr->info.magic) == XFS_DIR3_LEAFN_MAGIC) {
+ count = be16_to_cpu(((xfs_dir3_leaf_hdr_t *)lhdr)->count);
+ ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)lhdr +
+ sizeof(struct xfs_dir3_leaf_hdr));
+ } else {
+ xfs_error("Leaf's magic number does not match (0x%04x)!",
+ be16_to_cpu(lhdr->info.magic));
goto out;
}
- if (!leaf->hdr.count)
- goto out;
+ if (!count)
+ goto out;
- for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) - 1;
- low <= high; ) {
+ lep = ents;
+ low = 0;
+ high = count - 1;
+ while (low <= high) {
mid = (low + high) >> 1;
-
if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant)
break;
if (hash < hashwant)
@@ -714,9 +738,8 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant)
mid--;
- for (lep = &leaf->ents[mid];
- mid < be16_to_cpu(leaf->hdr.count) &&
- be32_to_cpu(lep->hashval) == hashwant;
+ curdb = -1;
+ for (lep = &ents[mid]; mid < count && be32_to_cpu(lep->hashval) == hashwant;
lep++, mid++) {
/* Skip over stale leaf entries. */
if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
@@ -732,7 +755,8 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
buf = xfs_dir2_dirblks_get_cached(parent->fs, fsblkno, 1);
data_hdr = (xfs_dir2_data_hdr_t *)buf;
- if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+ if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC &&
+ be32_to_cpu(data_hdr->magic) != XFS_DIR3_DATA_MAGIC) {
xfs_error("Leaf directory's data magic No. does not match!");
goto out;
}
@@ -740,10 +764,10 @@ struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
curdb = newdb;
}
- dep = (xfs_dir2_data_entry_t *)((char *)buf +
- xfs_dir2_dataptr_to_off(parent->fs, be32_to_cpu(lep->address)));
-
- start_name = &dep->name[0];
+ dep = (xfs_dir2_data_entry_t *)(
+ buf + xfs_dir2_dataptr_to_off(parent->fs,
+ be32_to_cpu(lep->address)));
+ start_name = dep->name;
end_name = start_name + dep->namelen;
if (!xfs_dir2_entry_name_cmp(start_name, end_name, dname)) {
diff --git a/core/fs/xfs/xfs_dir2.h b/core/fs/xfs/xfs_dir2.h
index 158cf44f..1e1fb579 100644
--- a/core/fs/xfs/xfs_dir2.h
+++ b/core/fs/xfs/xfs_dir2.h
@@ -23,8 +23,8 @@
#include "xfs.h"
-const void *xfs_dir2_dirblks_get_cached(struct fs_info *fs, block_t startblock,
- xfs_filblks_t c);
+void *xfs_dir2_dirblks_get_cached(struct fs_info *fs, block_t startblock,
+ xfs_filblks_t c);
void xfs_dir2_dirblks_flush_cache(void);
uint32_t xfs_dir2_da_hashname(const uint8_t *name, int namelen);
@@ -46,7 +46,7 @@ static inline bool xfs_dir2_isleaf(struct fs_info *fs, xfs_dinode_t *dip)
uint64_t last = 0;
xfs_bmbt_irec_t irec;
- bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&dip->di_literal_area[0]) +
+ bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)XFS_DFORK_PTR(dip, XFS_DATA_FORK) +
be32_to_cpu(dip->di_nextents) - 1);
last = irec.br_startoff + irec.br_blockcount;
diff --git a/core/fs/xfs/xfs_readdir.c b/core/fs/xfs/xfs_readdir.c
index 86c8a77b..51518ef6 100644
--- a/core/fs/xfs/xfs_readdir.c
+++ b/core/fs/xfs/xfs_readdir.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2013 Paulo Alcantara <pcacjr@zytor.com>
+ * Copyright (c) 2012-2015 Paulo Alcantara <pcacjr@zytor.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -64,10 +64,12 @@ static int fill_dirent(struct fs_info *fs, struct dirent *dirent,
int xfs_readdir_dir2_local(struct file *file, struct dirent *dirent,
xfs_dinode_t *core)
{
- xfs_dir2_sf_t *sf = (xfs_dir2_sf_t *)&core->di_literal_area[0];
+ xfs_dir2_sf_t *sf = XFS_DFORK_PTR(core, XFS_DATA_FORK);
xfs_dir2_sf_entry_t *sf_entry;
+ uint8_t ftypelen = core->di_version == 3 ? 1 : 0;
uint8_t count = sf->hdr.i8count ? sf->hdr.i8count : sf->hdr.count;
uint32_t offset = file->offset;
+ xfs_dir2_inou_t *inou;
uint8_t *start_name;
uint8_t *end_name;
xfs_ino_t ino;
@@ -82,7 +84,7 @@ int xfs_readdir_dir2_local(struct file *file, struct dirent *dirent,
file->offset++;
- sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)&sf->list[0] -
+ sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)sf->list -
(!sf->hdr.i8count ? 4 : 0));
if (file->offset - 1) {
@@ -91,20 +93,22 @@ int xfs_readdir_dir2_local(struct file *file, struct dirent *dirent,
sf_entry = (xfs_dir2_sf_entry_t *)(
(uint8_t *)sf_entry +
offsetof(struct xfs_dir2_sf_entry,
- name[0]) +
+ name) +
sf_entry->namelen +
+ ftypelen +
(sf->hdr.i8count ? 8 : 4));
}
}
- start_name = &sf_entry->name[0];
+ start_name = sf_entry->name;
end_name = start_name + sf_entry->namelen;
- ino = xfs_dir2_sf_get_inumber(sf, (xfs_dir2_inou_t *)(
- (uint8_t *)sf_entry +
- offsetof(struct xfs_dir2_sf_entry,
- name[0]) +
- sf_entry->namelen));
+ inou = (xfs_dir2_inou_t *)((uint8_t *)sf_entry +
+ offsetof(struct xfs_dir2_sf_entry,
+ name) +
+ sf_entry->namelen +
+ ftypelen);
+ ino = xfs_dir2_sf_get_inumber(sf, inou);
retval = fill_dirent(fs, dirent, file->offset, ino, (char *)start_name,
end_name - start_name);
@@ -126,6 +130,7 @@ int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
block_t dir_blk;
struct fs_info *fs = file->fs;
const uint8_t *dirblk_buf;
+ bool isdir3;
uint8_t *p;
uint32_t offset;
xfs_dir2_data_hdr_t *hdr;
@@ -139,12 +144,16 @@ int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
xfs_debug("file %p dirent %p core %p", file, dirent, core);
- bmbt_irec_get(&r, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
+ bmbt_irec_get(&r, XFS_DFORK_PTR(core, XFS_DATA_FORK));
dir_blk = fsblock_to_bytes(fs, r.br_startblock) >> BLOCK_SHIFT(fs);
dirblk_buf = xfs_dir2_dirblks_get_cached(fs, dir_blk, r.br_blockcount);
hdr = (xfs_dir2_data_hdr_t *)dirblk_buf;
- if (be32_to_cpu(hdr->magic) != XFS_DIR2_BLOCK_MAGIC) {
+ if (be32_to_cpu(hdr->magic) == XFS_DIR2_BLOCK_MAGIC) {
+ isdir3 = false;
+ } else if (be32_to_cpu(hdr->magic) == XFS_DIR3_BLOCK_MAGIC) {
+ isdir3 = true;
+ } else {
xfs_error("Block directory header's magic number does not match!");
xfs_debug("hdr->magic: 0x%lx", be32_to_cpu(hdr->magic));
goto out;
@@ -157,7 +166,8 @@ int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
file->offset++;
- p = (uint8_t *)(hdr + 1);
+ p = (uint8_t *)dirblk_buf + (isdir3 ? sizeof(struct xfs_dir3_data_hdr) :
+ sizeof(struct xfs_dir2_data_hdr));
if (file->offset - 1) {
offset = file->offset;
@@ -170,7 +180,8 @@ int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
continue;
}
- p += xfs_dir2_data_entsize(dep->namelen);
+ p += (isdir3 ? xfs_dir3_data_entsize(dep->namelen) :
+ xfs_dir2_data_entsize(dep->namelen));
}
}
@@ -197,9 +208,11 @@ out:
int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent,
xfs_dinode_t *core)
{
+ xfs_dir2_leaf_hdr_t *hdr;
+ xfs_dir2_leaf_entry_t *ents;
+ uint16_t count;
xfs_bmbt_irec_t irec;
struct fs_info *fs = file->fs;
- xfs_dir2_leaf_t *leaf;
block_t leaf_blk, dir_blk;
xfs_dir2_leaf_entry_t *lep;
uint32_t db;
@@ -214,39 +227,49 @@ int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent,
xfs_debug("file %p dirent %p core %p", file, dirent, core);
- bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) +
+ bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)XFS_DFORK_PTR(core, XFS_DATA_FORK) +
be32_to_cpu(core->di_nextents) - 1);
leaf_blk = fsblock_to_bytes(fs, irec.br_startblock) >>
BLOCK_SHIFT(file->fs);
- leaf = (xfs_dir2_leaf_t *)xfs_dir2_dirblks_get_cached(fs, leaf_blk,
- irec.br_blockcount);
- if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC) {
+ hdr = xfs_dir2_dirblks_get_cached(fs, leaf_blk, irec.br_blockcount);
+ if (!hdr)
+ return -1;
+
+ if (be16_to_cpu(hdr->info.magic) == XFS_DIR2_LEAF1_MAGIC) {
+ count = be16_to_cpu(hdr->count);
+ ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)hdr +
+ sizeof(struct xfs_dir2_leaf_hdr));
+ } else if (be16_to_cpu(hdr->info.magic) == XFS_DIR3_LEAF1_MAGIC) {
+ count = be16_to_cpu(((xfs_dir3_leaf_hdr_t *)hdr)->count);
+ ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)hdr +
+ sizeof(struct xfs_dir3_leaf_hdr));
+ } else {
xfs_error("Single leaf block header's magic number does not match!");
goto out;
}
- if (!leaf->hdr.count)
- goto out;
-
- if (file->offset + 1 > be16_to_cpu(leaf->hdr.count))
+ if (!count || file->offset + 1 > count)
goto out;
- lep = &leaf->ents[file->offset++];
+ lep = &ents[file->offset++];
/* Skip over stale leaf entries */
for ( ; be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR;
- lep++, file->offset++);
+ lep++, file->offset++)
+ ;
db = xfs_dir2_dataptr_to_db(fs, be32_to_cpu(lep->address));
- bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] + db);
+ bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)XFS_DFORK_PTR(core,
+ XFS_DATA_FORK) + db);
dir_blk = fsblock_to_bytes(fs, irec.br_startblock) >> BLOCK_SHIFT(fs);
buf = xfs_dir2_dirblks_get_cached(fs, dir_blk, irec.br_blockcount);
data_hdr = (xfs_dir2_data_hdr_t *)buf;
- if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+ if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC &&
+ be32_to_cpu(data_hdr->magic) != XFS_DIR3_DATA_MAGIC) {
xfs_error("Leaf directory's data magic number does not match!");
goto out;
}
@@ -277,14 +300,16 @@ int xfs_readdir_dir2_node(struct file *file, struct dirent *dirent,
xfs_dinode_t *core)
{
struct fs_info *fs = file->fs;
- xfs_bmbt_irec_t irec;
- uint32_t node_off = 0;
block_t fsblkno;
- xfs_da_intnode_t *node = NULL;
+ xfs_da_node_hdr_t *nhdr;
+ xfs_da_node_entry_t *btree;
+ uint16_t btcount;
+ uint16_t lfcount;
+ xfs_dir2_leaf_hdr_t *lhdr;
+ xfs_dir2_leaf_entry_t *ents;
struct inode *inode = file->inode;
int error;
xfs_dir2_data_hdr_t *data_hdr;
- xfs_dir2_leaf_t *leaf;
xfs_dir2_leaf_entry_t *lep;
unsigned int offset;
xfs_dir2_data_entry_t *dep;
@@ -296,52 +321,71 @@ int xfs_readdir_dir2_node(struct file *file, struct dirent *dirent,
xfs_debug("file %p dirent %p core %p", file, dirent, core);
- do {
- bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] +
- ++node_off);
- } while (irec.br_startoff < xfs_dir2_byte_to_db(fs, XFS_DIR2_LEAF_OFFSET));
-
- fsblkno = fsblock_to_bytes(fs, irec.br_startblock) >> BLOCK_SHIFT(fs);
+ db = xfs_dir2_byte_to_db(fs, XFS_DIR2_LEAF_OFFSET);
+ fsblkno = xfs_dir2_get_right_blk(fs, core, db, &error);
+ if (error) {
+ xfs_error("Cannot find fs block");
+ return -1;
+ }
- node = (xfs_da_intnode_t *)xfs_dir2_dirblks_get_cached(fs, fsblkno, 1);
- if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) {
- xfs_error("Node's magic number does not match!");
+ nhdr = xfs_dir2_dirblks_get_cached(fs, fsblkno, 1);
+ if (be16_to_cpu(nhdr->info.magic) == XFS_DA_NODE_MAGIC) {
+ btcount = be16_to_cpu(nhdr->count);
+ btree = (xfs_da_node_entry_t *)((uint8_t *)nhdr +
+ sizeof(struct xfs_da_node_hdr));
+ } else if (be16_to_cpu(nhdr->info.magic) == XFS_DA3_NODE_MAGIC) {
+ btcount = be16_to_cpu(((xfs_da3_node_hdr_t *)nhdr)->count);
+ btree = (xfs_da_node_entry_t *)((uint8_t *)nhdr +
+ sizeof(struct xfs_da3_node_hdr));
+ } else {
+ xfs_error("Node's magic number (0x%04x) does not match!",
+ be16_to_cpu(nhdr->info.magic));
goto out;
}
try_next_btree:
- if (!node->hdr.count ||
- XFS_PVT(inode)->i_btree_offset >= be16_to_cpu(node->hdr.count))
+ if (!btcount ||
+ XFS_PVT(inode)->i_btree_offset >= btcount)
goto out;
- fsblkno = be32_to_cpu(node->btree[XFS_PVT(inode)->i_btree_offset].before);
+ fsblkno = be32_to_cpu(btree[XFS_PVT(inode)->i_btree_offset].before);
fsblkno = xfs_dir2_get_right_blk(fs, core, fsblkno, &error);
if (error) {
xfs_error("Cannot find leaf rec!");
goto out;
}
- leaf = (xfs_dir2_leaf_t*)xfs_dir2_dirblks_get_cached(fs, fsblkno, 1);
- if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) {
- xfs_error("Leaf's magic number does not match!");
+ lhdr = xfs_dir2_dirblks_get_cached(fs, fsblkno, 1);
+ if (be16_to_cpu(lhdr->info.magic) == XFS_DIR2_LEAFN_MAGIC) {
+ lfcount = be16_to_cpu(lhdr->count);
+ ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)lhdr +
+ sizeof(struct xfs_dir2_leaf_hdr));
+ } else if (be16_to_cpu(lhdr->info.magic) == XFS_DIR3_LEAFN_MAGIC) {
+ lfcount = be16_to_cpu(((xfs_dir3_leaf_hdr_t *)lhdr)->count);
+ ents = (xfs_dir2_leaf_entry_t *)((uint8_t *)lhdr +
+ sizeof(struct xfs_dir3_leaf_hdr));
+ } else {
+ xfs_error("Leaf's magic number does not match (0x%04x)!",
+ be16_to_cpu(lhdr->info.magic));
goto out;
}
- if (!leaf->hdr.count ||
- XFS_PVT(inode)->i_leaf_ent_offset >= be16_to_cpu(leaf->hdr.count)) {
+ if (!lfcount ||
+ XFS_PVT(inode)->i_leaf_ent_offset >= lfcount) {
XFS_PVT(inode)->i_btree_offset++;
XFS_PVT(inode)->i_leaf_ent_offset = 0;
goto try_next_btree;
}
- lep = &leaf->ents[XFS_PVT(inode)->i_leaf_ent_offset];
+ lep = &ents[XFS_PVT(inode)->i_leaf_ent_offset];
/* Skip over stale leaf entries */
- for ( ; XFS_PVT(inode)->i_leaf_ent_offset < be16_to_cpu(leaf->hdr.count) &&
+ for ( ; XFS_PVT(inode)->i_leaf_ent_offset < lfcount &&
be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR;
- lep++, XFS_PVT(inode)->i_leaf_ent_offset++);
+ lep++, XFS_PVT(inode)->i_leaf_ent_offset++)
+ ;
- if (XFS_PVT(inode)->i_leaf_ent_offset == be16_to_cpu(leaf->hdr.count)) {
+ if (XFS_PVT(inode)->i_leaf_ent_offset == lfcount) {
XFS_PVT(inode)->i_btree_offset++;
XFS_PVT(inode)->i_leaf_ent_offset = 0;
goto try_next_btree;
@@ -359,7 +403,8 @@ try_next_btree:
buf = xfs_dir2_dirblks_get_cached(fs, fsblkno, 1);
data_hdr = (xfs_dir2_data_hdr_t *)buf;
- if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
+ if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC &&
+ be32_to_cpu(data_hdr->magic) != XFS_DIR3_DATA_MAGIC) {
xfs_error("Leaf directory's data magic No. does not match!");
goto out;
}