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
22 #include "xfs_types.h"
27 #include "xfs_dinode.h"
31 char *xfs_dir2_get_entry_name(uint8_t *start
, uint8_t *end
)
36 s
= malloc(end
- start
+ 1);
38 malloc_error("string");
49 uint32_t xfs_dir2_da_hashname(const uint8_t *name
, int namelen
)
54 * Do four characters at a time as long as we can.
56 for (hash
= 0; namelen
>= 4; namelen
-=4, name
+= 4)
57 hash
= (name
[0] << 21) ^ (name
[1] << 14) ^ (name
[2] << 7) ^
58 (name
[3] << 0) ^ rol32(hash
, 7 * 4);
61 * Now do the rest of the characters.
65 return (name
[0] << 14) ^ (name
[1] << 7) ^ (name
[2] << 0) ^
68 return (name
[0] << 7) ^ (name
[1] << 0) ^ rol32(hash
, 7 * 2);
70 return (name
[0] << 0) ^ rol32(hash
, 7 * 1);
71 default: /* case 0: */
76 void *xfs_dir2_get_dirblks(struct fs_info
*fs
, block_t startblock
,
79 int count
= c
<< XFS_INFO(fs
)->dirblklog
;
84 buf
= malloc(c
* XFS_INFO(fs
)->dirblksize
);
86 malloc_error("buffer memory");
88 memset(buf
, 0, XFS_INFO(fs
)->dirblksize
);
91 p
= (uint8_t *)get_cache(fs
->fs_dev
, startblock
++);
92 memcpy(buf
+ offset
, p
, BLOCK_SIZE(fs
));
93 offset
+= BLOCK_SIZE(fs
);
99 struct inode
*xfs_dir2_local_find_entry(const char *dname
, struct inode
*parent
,
102 xfs_dir2_sf_t
*sf
= (xfs_dir2_sf_t
*)&core
->di_literal_area
[0];
103 xfs_dir2_sf_entry_t
*sf_entry
;
104 uint8_t count
= sf
->hdr
.i8count
? sf
->hdr
.i8count
: sf
->hdr
.count
;
105 struct fs_info
*fs
= parent
->fs
;
108 xfs_dinode_t
*ncore
= NULL
;
110 xfs_debug("count %hhu i8count %hhu", sf
->hdr
.count
, sf
->hdr
.i8count
);
112 sf_entry
= (xfs_dir2_sf_entry_t
*)((uint8_t *)&sf
->list
[0] -
113 (!sf
->hdr
.i8count
? 4 : 0));
115 uint8_t *start_name
= &sf_entry
->name
[0];
116 uint8_t *end_name
= start_name
+ sf_entry
->namelen
;
119 name
= xfs_dir2_get_entry_name(start_name
, end_name
);
121 xfs_debug("entry name: %s", name
);
123 if (!strncmp(name
, dname
, strlen(dname
))) {
130 sf_entry
= (xfs_dir2_sf_entry_t
*)((uint8_t *)sf_entry
+
131 offsetof(struct xfs_dir2_sf_entry
,
134 (sf
->hdr
.i8count
? 8 : 4));
140 inode
= xfs_new_inode(fs
);
142 ino
= xfs_dir2_sf_get_inumber(sf
, (xfs_dir2_inou_t
*)(
143 (uint8_t *)sf_entry
+
144 offsetof(struct xfs_dir2_sf_entry
,
148 xfs_debug("entry inode's number %lu", ino
);
150 ncore
= xfs_dinode_get_core(fs
, ino
);
152 xfs_error("Failed to get dinode!");
156 fill_xfs_inode_pvt(fs
, inode
, ino
);
159 inode
->size
= be64_to_cpu(ncore
->di_size
);
161 if (be16_to_cpu(ncore
->di_mode
) & S_IFDIR
) {
162 inode
->mode
= DT_DIR
;
163 xfs_debug("Found a directory inode!");
164 } else if (be16_to_cpu(ncore
->di_mode
) & S_IFREG
) {
165 inode
->mode
= DT_REG
;
166 xfs_debug("Found a file inode!");
167 xfs_debug("inode size %llu", inode
->size
);
178 struct inode
*xfs_dir2_block_find_entry(const char *dname
, struct inode
*parent
,
183 struct fs_info
*fs
= parent
->fs
;
186 xfs_dir2_data_hdr_t
*hdr
;
187 struct inode
*inode
= NULL
;
188 xfs_dir2_block_tail_t
*btp
;
189 xfs_dir2_data_unused_t
*dup
;
190 xfs_dir2_data_entry_t
*dep
;
194 bmbt_irec_get(&r
, (xfs_bmbt_rec_t
*)&core
->di_literal_area
[0]);
195 dir_blk
= fsblock_to_bytes(fs
, r
.br_startblock
) >> BLOCK_SHIFT(fs
);
197 dirblk_buf
= xfs_dir2_get_dirblks(fs
, dir_blk
, r
.br_blockcount
);
198 hdr
= (xfs_dir2_data_hdr_t
*)dirblk_buf
;
199 if (be32_to_cpu(hdr
->magic
) != XFS_DIR2_BLOCK_MAGIC
) {
200 xfs_error("Block directory header's magic number does not match!");
201 xfs_debug("hdr->magic: 0x%lx", be32_to_cpu(hdr
->magic
));
205 p
= (uint8_t *)(hdr
+ 1);
207 btp
= xfs_dir2_block_tail_p(XFS_INFO(fs
), hdr
);
208 endp
= (uint8_t *)((xfs_dir2_leaf_entry_t
*)btp
- be32_to_cpu(btp
->count
));
215 dup
= (xfs_dir2_data_unused_t
*)p
;
216 if (be16_to_cpu(dup
->freetag
) == XFS_DIR2_DATA_FREE_TAG
) {
217 p
+= be16_to_cpu(dup
->length
);
221 dep
= (xfs_dir2_data_entry_t
*)p
;
223 start_name
= &dep
->name
[0];
224 end_name
= start_name
+ dep
->namelen
;
225 name
= xfs_dir2_get_entry_name(start_name
, end_name
);
227 if (!strncmp(name
, dname
, strlen(dname
))) {
233 p
+= xfs_dir2_data_entsize(dep
->namelen
);
242 inode
= xfs_new_inode(fs
);
244 ino
= be64_to_cpu(dep
->inumber
);
246 xfs_debug("entry inode's number %lu", ino
);
248 ncore
= xfs_dinode_get_core(fs
, ino
);
250 xfs_error("Failed to get dinode!");
254 fill_xfs_inode_pvt(fs
, inode
, ino
);
257 XFS_PVT(inode
)->i_ino_blk
= ino_to_bytes(fs
, ino
) >> BLOCK_SHIFT(fs
);
258 inode
->size
= be64_to_cpu(ncore
->di_size
);
260 if (be16_to_cpu(ncore
->di_mode
) & S_IFDIR
) {
261 inode
->mode
= DT_DIR
;
262 xfs_debug("Found a directory inode!");
263 } else if (be16_to_cpu(ncore
->di_mode
) & S_IFREG
) {
264 inode
->mode
= DT_REG
;
265 xfs_debug("Found a file inode!");
266 xfs_debug("inode size %llu", inode
->size
);
269 xfs_debug("entry inode's number %lu", ino
);
281 struct inode
*xfs_dir2_leaf_find_entry(const char *dname
, struct inode
*parent
,
284 xfs_dir2_leaf_t
*leaf
;
285 xfs_bmbt_irec_t irec
;
286 block_t leaf_blk
, dir_blk
;
287 xfs_dir2_leaf_entry_t
*lep
;
293 uint32_t newdb
, curdb
= -1;
294 xfs_dir2_data_entry_t
*dep
;
296 xfs_dir2_data_hdr_t
*data_hdr
;
304 bmbt_irec_get(&irec
, ((xfs_bmbt_rec_t
*)&core
->di_literal_area
[0]) +
305 be32_to_cpu(core
->di_nextents
) - 1);
306 leaf_blk
= fsblock_to_bytes(parent
->fs
, irec
.br_startblock
) >>
307 BLOCK_SHIFT(parent
->fs
);
309 leaf
= (xfs_dir2_leaf_t
*)xfs_dir2_get_dirblks(parent
->fs
, leaf_blk
,
311 if (be16_to_cpu(leaf
->hdr
.info
.magic
) != XFS_DIR2_LEAF1_MAGIC
) {
312 xfs_error("Single leaf block header's magic number does not match!");
316 if (!leaf
->hdr
.count
)
319 hashwant
= xfs_dir2_da_hashname((uint8_t *)dname
, strlen(dname
));
322 for (lep
= leaf
->ents
, low
= 0, high
= be16_to_cpu(leaf
->hdr
.count
) - 1;
324 mid
= (low
+ high
) >> 1;
325 if ((hash
= be32_to_cpu(lep
[mid
].hashval
)) == hashwant
)
333 /* If hash is not the one we want, then the directory does not contain the
334 * entry we're looking for and there is nothing to do anymore.
336 if (hash
!= hashwant
)
339 while (mid
> 0 && be32_to_cpu(lep
[mid
- 1].hashval
) == hashwant
)
342 for (lep
= &leaf
->ents
[mid
];
343 mid
< be16_to_cpu(leaf
->hdr
.count
) &&
344 be32_to_cpu(lep
->hashval
) == hashwant
;
346 /* Skip over stale leaf entries. */
347 if (be32_to_cpu(lep
->address
) == XFS_DIR2_NULL_DATAPTR
)
350 newdb
= xfs_dir2_dataptr_to_db(parent
->fs
, be32_to_cpu(lep
->address
));
351 if (newdb
!= curdb
) {
356 ((xfs_bmbt_rec_t
*)&core
->di_literal_area
[0]) + newdb
);
357 dir_blk
= fsblock_to_bytes(parent
->fs
, irec
.br_startblock
) >>
358 BLOCK_SHIFT(parent
->fs
);
359 buf
= xfs_dir2_get_dirblks(parent
->fs
, dir_blk
, irec
.br_blockcount
);
360 data_hdr
= (xfs_dir2_data_hdr_t
*)buf
;
361 if (be32_to_cpu(data_hdr
->magic
) != XFS_DIR2_DATA_MAGIC
) {
362 xfs_error("Leaf directory's data magic No. does not match!");
369 dep
= (xfs_dir2_data_entry_t
*)((char *)buf
+
370 xfs_dir2_dataptr_to_off(parent
->fs
, be32_to_cpu(lep
->address
)));
372 start_name
= &dep
->name
[0];
373 end_name
= start_name
+ dep
->namelen
;
374 name
= xfs_dir2_get_entry_name(start_name
, end_name
);
376 if (!strncmp(name
, dname
, strlen(dname
))) {
392 ip
= xfs_new_inode(parent
->fs
);
394 ino
= be64_to_cpu(dep
->inumber
);
396 xfs_debug("entry inode's number %lu", ino
);
398 ncore
= xfs_dinode_get_core(parent
->fs
, ino
);
400 xfs_error("Failed to get dinode!");
404 fill_xfs_inode_pvt(parent
->fs
, ip
, ino
);
407 XFS_PVT(ip
)->i_ino_blk
= ino_to_bytes(parent
->fs
, ino
) >>
408 BLOCK_SHIFT(parent
->fs
);
409 ip
->size
= be64_to_cpu(ncore
->di_size
);
411 if (be16_to_cpu(ncore
->di_mode
) & S_IFDIR
) {
413 xfs_debug("Found a directory inode!");
414 } else if (be16_to_cpu(ncore
->di_mode
) & S_IFREG
) {
416 xfs_debug("Found a file inode!");
417 xfs_debug("inode size %llu", ip
->size
);
420 xfs_debug("entry inode's number %lu", ino
);
435 block_t
xfs_dir2_get_right_blk(struct fs_info
*fs
, xfs_dinode_t
*core
,
436 uint32_t from
, uint32_t to
, block_t fsblkno
,
440 xfs_bmbt_irec_t irec
;
443 for (idx
= from
; idx
< to
; idx
++) {
445 ((xfs_bmbt_rec_t
*)&core
->di_literal_area
[0]) + idx
);
446 if (fsblkno
>= irec
.br_startoff
&&
447 fsblkno
< irec
.br_startoff
+ irec
.br_blockcount
)
451 if (fsblkno
< irec
.br_startoff
||
452 fsblkno
>= irec
.br_startoff
+ irec
.br_blockcount
)
455 return fsblock_to_bytes(fs
,
456 fsblkno
- irec
.br_startoff
+ irec
.br_startblock
) >>
460 struct inode
*xfs_dir2_node_find_entry(const char *dname
, struct inode
*parent
,
463 xfs_bmbt_irec_t irec
;
464 uint32_t node_off
= 0;
466 xfs_da_intnode_t
*node
= NULL
;
469 xfs_da_node_entry_t
*btree
;
474 xfs_dir2_data_hdr_t
*data_hdr
;
475 xfs_dir2_leaf_t
*leaf
;
476 xfs_dir2_leaf_entry_t
*lep
;
477 xfs_dir2_data_entry_t
*dep
;
485 uint32_t newdb
, curdb
= -1;
491 bmbt_irec_get(&irec
, ((xfs_bmbt_rec_t
*)&core
->di_literal_area
[0]) +
493 } while (irec
.br_startoff
<
494 xfs_dir2_byte_to_db(parent
->fs
, XFS_DIR2_LEAF_OFFSET
));
496 fsblkno
= fsblock_to_bytes(parent
->fs
, irec
.br_startblock
) >>
497 BLOCK_SHIFT(parent
->fs
);
499 node
= (xfs_da_intnode_t
*)xfs_dir2_get_dirblks(parent
->fs
, fsblkno
, 1);
500 if (be16_to_cpu(node
->hdr
.info
.magic
) != XFS_DA_NODE_MAGIC
) {
501 xfs_error("Node's magic number does not match!");
505 if (!node
->hdr
.count
)
508 hashwant
= xfs_dir2_da_hashname((uint8_t *)dname
, strlen(dname
));
510 /* Given a hash to lookup, you read the node's btree array and first
511 * "hashval" in the array that exceeds the given hash and it can then
512 * be found in the block pointed by the "before" value.
514 max
= be16_to_cpu(node
->hdr
.count
);
516 probe
= span
= max
/2;
517 for (btree
= &node
->btree
[probe
]; span
> 4; btree
= &node
->btree
[probe
]) {
519 hash
= be32_to_cpu(btree
->hashval
);
522 else if (hash
> hashwant
)
528 while ((probe
> 0) && (be32_to_cpu(btree
->hashval
) >= hashwant
)) {
532 while ((probe
< max
) && (be32_to_cpu(btree
->hashval
) < hashwant
)) {
538 fsblkno
= be32_to_cpu(node
->btree
[max
-1].before
);
540 fsblkno
= be32_to_cpu(node
->btree
[probe
].before
);
542 fsblkno
= xfs_dir2_get_right_blk(parent
->fs
, core
, node_off
+ 1,
543 be32_to_cpu(core
->di_nextents
) - 1,
546 xfs_error("Cannot find leaf rec!");
550 leaf
= (xfs_dir2_leaf_t
*)xfs_dir2_get_dirblks(parent
->fs
, fsblkno
, 1);
551 if (be16_to_cpu(leaf
->hdr
.info
.magic
) != XFS_DIR2_LEAFN_MAGIC
) {
552 xfs_error("Leaf's magic number does not match!");
556 if (!leaf
->hdr
.count
)
559 for (lep
= leaf
->ents
, low
= 0, high
= be16_to_cpu(leaf
->hdr
.count
) - 1;
561 mid
= (low
+ high
) >> 1;
562 if ((hash
= be32_to_cpu(lep
[mid
].hashval
)) == hashwant
)
570 /* If hash is not the one we want, then the directory does not contain the
571 * entry we're looking for and there is nothing to do anymore.
573 if (hash
!= hashwant
)
576 while (mid
> 0 && be32_to_cpu(lep
[mid
- 1].hashval
) == hashwant
)
579 for (lep
= &leaf
->ents
[mid
];
580 mid
< be16_to_cpu(leaf
->hdr
.count
) &&
581 be32_to_cpu(lep
->hashval
) == hashwant
;
583 /* Skip over stale leaf entries. */
584 if (be32_to_cpu(lep
->address
) == XFS_DIR2_NULL_DATAPTR
)
587 newdb
= xfs_dir2_dataptr_to_db(parent
->fs
, be32_to_cpu(lep
->address
));
588 if (newdb
!= curdb
) {
592 fsblkno
= xfs_dir2_get_right_blk(parent
->fs
, core
, 0, node_off
,
595 xfs_error("Cannot find data block!");
599 buf
= xfs_dir2_get_dirblks(parent
->fs
, fsblkno
, 1);
600 data_hdr
= (xfs_dir2_data_hdr_t
*)buf
;
601 if (be32_to_cpu(data_hdr
->magic
) != XFS_DIR2_DATA_MAGIC
) {
602 xfs_error("Leaf directory's data magic No. does not match!");
607 dep
= (xfs_dir2_data_entry_t
*)((char *)buf
+
608 xfs_dir2_dataptr_to_off(parent
->fs
, be32_to_cpu(lep
->address
)));
610 start_name
= &dep
->name
[0];
611 end_name
= start_name
+ dep
->namelen
;
612 name
= xfs_dir2_get_entry_name(start_name
, end_name
);
613 if (!strncmp(name
, dname
, strlen(dname
))) {
632 ip
= xfs_new_inode(parent
->fs
);
633 ino
= be64_to_cpu(dep
->inumber
);
634 ncore
= xfs_dinode_get_core(parent
->fs
, ino
);
636 xfs_error("Failed to get dinode!");
640 fill_xfs_inode_pvt(parent
->fs
, ip
, ino
);
642 XFS_PVT(ip
)->i_ino_blk
= ino_to_bytes(parent
->fs
, ino
) >>
643 BLOCK_SHIFT(parent
->fs
);
644 ip
->size
= be64_to_cpu(ncore
->di_size
);
646 if (be16_to_cpu(ncore
->di_mode
) & S_IFDIR
) {
648 xfs_debug("Found a directory inode!");
649 } else if (be16_to_cpu(ncore
->di_mode
) & S_IFREG
) {
651 xfs_debug("Found a file inode!");
652 xfs_debug("inode size %llu", ip
->size
);
655 xfs_debug("entry inode's number %lu", ino
);