Home | History | Annotate | Download | only in xfs
      1 /*
      2  * Copyright (c) 2012-2013 Paulo Alcantara <pcacjr (at) zytor.com>
      3  *
      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.
      7  *
      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.
     12  *
     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
     16  */
     17 
     18 #include <cache.h>
     19 #include <core.h>
     20 #include <fs.h>
     21 
     22 #include "xfs_types.h"
     23 #include "xfs_sb.h"
     24 #include "xfs_ag.h"
     25 #include "misc.h"
     26 #include "xfs.h"
     27 #include "xfs_dinode.h"
     28 
     29 #include "xfs_dir2.h"
     30 
     31 #define XFS_DIR2_DIRBLKS_CACHE_SIZE 128
     32 
     33 struct xfs_dir2_dirblks_cache {
     34     block_t        dc_startblock;
     35     xfs_filblks_t  dc_blkscount;
     36     void          *dc_area;
     37 };
     38 
     39 static struct xfs_dir2_dirblks_cache dirblks_cache[XFS_DIR2_DIRBLKS_CACHE_SIZE];
     40 static unsigned char                 dirblks_cached_count = 0;
     41 
     42 uint32_t xfs_dir2_da_hashname(const uint8_t *name, int namelen)
     43 {
     44     uint32_t hash;
     45 
     46     /*
     47      * Do four characters at a time as long as we can.
     48      */
     49     for (hash = 0; namelen >= 4; namelen -=4, name += 4)
     50         hash = (name[0] << 21) ^ (name[1] << 14) ^ (name[2] << 7) ^
     51                (name[3] << 0) ^ rol32(hash, 7 * 4);
     52 
     53     /*
     54      * Now do the rest of the characters.
     55      */
     56     switch (namelen) {
     57     case 3:
     58         return (name[0] << 14) ^ (name[1] << 7) ^ (name[2] << 0) ^
     59                rol32(hash, 7 * 3);
     60     case 2:
     61         return (name[0] << 7) ^ (name[1] << 0) ^ rol32(hash, 7 * 2);
     62     case 1:
     63         return (name[0] << 0) ^ rol32(hash, 7 * 1);
     64     default: /* case 0: */
     65         return hash;
     66     }
     67 }
     68 
     69 static void *get_dirblks(struct fs_info *fs, block_t startblock,
     70 			 xfs_filblks_t c)
     71 {
     72     int count = c << XFS_INFO(fs)->dirblklog;
     73     uint8_t *p;
     74     uint8_t *buf;
     75     off_t offset = 0;
     76 
     77     buf = malloc(c * XFS_INFO(fs)->dirblksize);
     78     if (!buf)
     79         malloc_error("buffer memory");
     80 
     81     memset(buf, 0, XFS_INFO(fs)->dirblksize);
     82 
     83     while (count--) {
     84         p = (uint8_t *)get_cache(fs->fs_dev, startblock++);
     85         memcpy(buf + offset, p,  BLOCK_SIZE(fs));
     86         offset += BLOCK_SIZE(fs);
     87     }
     88 
     89     return buf;
     90 }
     91 
     92 const void *xfs_dir2_dirblks_get_cached(struct fs_info *fs, block_t startblock,
     93 					xfs_filblks_t c)
     94 {
     95     unsigned char i;
     96     void *buf;
     97 
     98     xfs_debug("fs %p startblock %llu (0x%llx) blkscount %lu", fs, startblock,
     99 	      startblock, c);
    100 
    101     if (!dirblks_cached_count) {
    102 	buf = get_dirblks(fs, startblock, c);
    103 
    104 	dirblks_cache[dirblks_cached_count].dc_startblock = startblock;
    105 	dirblks_cache[dirblks_cached_count].dc_blkscount = c;
    106 	dirblks_cache[dirblks_cached_count].dc_area = buf;
    107 
    108 	return dirblks_cache[dirblks_cached_count++].dc_area;
    109     } else if (dirblks_cached_count == XFS_DIR2_DIRBLKS_CACHE_SIZE) {
    110 	for (i = 0; i < XFS_DIR2_DIRBLKS_CACHE_SIZE / 2; i++) {
    111 	    unsigned char k = XFS_DIR2_DIRBLKS_CACHE_SIZE - (i + 1);
    112 
    113 	    free(dirblks_cache[i].dc_area);
    114 	    dirblks_cache[i] = dirblks_cache[k];
    115 	    memset(&dirblks_cache[k], 0, sizeof(dirblks_cache[k]));
    116 	}
    117 
    118 	buf = get_dirblks(fs, startblock, c);
    119 
    120 	dirblks_cache[XFS_DIR2_DIRBLKS_CACHE_SIZE / 2].dc_startblock =
    121 	    startblock;
    122 	dirblks_cache[XFS_DIR2_DIRBLKS_CACHE_SIZE / 2].dc_blkscount = c;
    123 	dirblks_cache[XFS_DIR2_DIRBLKS_CACHE_SIZE / 2].dc_area = buf;
    124 
    125 	dirblks_cached_count = XFS_DIR2_DIRBLKS_CACHE_SIZE / 2;
    126 
    127 	return dirblks_cache[dirblks_cached_count++].dc_area;
    128     } else {
    129 	block_t block;
    130 	xfs_filblks_t count;
    131 
    132 	block = dirblks_cache[dirblks_cached_count - 1].dc_startblock;
    133 	count = dirblks_cache[dirblks_cached_count - 1].dc_blkscount;
    134 
    135 	if (block == startblock && count == c) {
    136 	    return dirblks_cache[dirblks_cached_count - 1].dc_area;
    137 	} else {
    138 	    for (i = 0; i < dirblks_cached_count; i++) {
    139 		block = dirblks_cache[i].dc_startblock;
    140 		count = dirblks_cache[i].dc_blkscount;
    141 
    142 		if (block == startblock && count == c)
    143 		    return dirblks_cache[i].dc_area;
    144 	    }
    145 
    146 	    buf = get_dirblks(fs, startblock, c);
    147 
    148 	    dirblks_cache[dirblks_cached_count].dc_startblock = startblock;
    149 	    dirblks_cache[dirblks_cached_count].dc_blkscount = c;
    150 	    dirblks_cache[dirblks_cached_count].dc_area = buf;
    151 
    152 	    return dirblks_cache[dirblks_cached_count++].dc_area;
    153 	}
    154     }
    155 
    156     return NULL;
    157 }
    158 
    159 void xfs_dir2_dirblks_flush_cache(void)
    160 {
    161     unsigned char i;
    162 
    163     for (i = 0; i < dirblks_cached_count; i++) {
    164 	free(dirblks_cache[i].dc_area);
    165 	memset(&dirblks_cache[i], 0, sizeof(dirblks_cache[i]));
    166     }
    167 
    168     dirblks_cached_count = 0;
    169 }
    170 
    171 struct inode *xfs_dir2_local_find_entry(const char *dname, struct inode *parent,
    172 					xfs_dinode_t *core)
    173 {
    174     xfs_dir2_sf_t *sf = (xfs_dir2_sf_t *)&core->di_literal_area[0];
    175     xfs_dir2_sf_entry_t *sf_entry;
    176     uint8_t count = sf->hdr.i8count ? sf->hdr.i8count : sf->hdr.count;
    177     struct fs_info *fs = parent->fs;
    178     struct inode *inode;
    179     xfs_intino_t ino;
    180     xfs_dinode_t *ncore = NULL;
    181 
    182     xfs_debug("dname %s parent %p core %p", dname, parent, core);
    183     xfs_debug("count %hhu i8count %hhu", sf->hdr.count, sf->hdr.i8count);
    184 
    185     sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)&sf->list[0] -
    186 				       (!sf->hdr.i8count ? 4 : 0));
    187     while (count--) {
    188 	uint8_t *start_name = &sf_entry->name[0];
    189 	uint8_t *end_name = start_name + sf_entry->namelen;
    190 
    191 	if (!xfs_dir2_entry_name_cmp(start_name, end_name, dname)) {
    192 	    xfs_debug("Found entry %s", dname);
    193 	    goto found;
    194 	}
    195 
    196 	sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)sf_entry +
    197 					   offsetof(struct xfs_dir2_sf_entry,
    198 						    name[0]) +
    199 					   sf_entry->namelen +
    200 					   (sf->hdr.i8count ? 8 : 4));
    201     }
    202 
    203     return NULL;
    204 
    205 found:
    206     inode = xfs_new_inode(fs);
    207 
    208     ino = xfs_dir2_sf_get_inumber(sf, (xfs_dir2_inou_t *)(
    209 				      (uint8_t *)sf_entry +
    210 				      offsetof(struct xfs_dir2_sf_entry,
    211 					       name[0]) +
    212 				      sf_entry->namelen));
    213 
    214     xfs_debug("entry inode's number %lu", ino);
    215 
    216     ncore = xfs_dinode_get_core(fs, ino);
    217     if (!ncore) {
    218         xfs_error("Failed to get dinode!");
    219         goto out;
    220     }
    221 
    222     fill_xfs_inode_pvt(fs, inode, ino);
    223 
    224     inode->ino			= ino;
    225     inode->size 		= be64_to_cpu(ncore->di_size);
    226 
    227     if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
    228 	inode->mode = DT_DIR;
    229 	xfs_debug("Found a directory inode!");
    230     } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
    231 	inode->mode = DT_REG;
    232 	xfs_debug("Found a file inode!");
    233 	xfs_debug("inode size %llu", inode->size);
    234     } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
    235 	inode->mode = DT_LNK;
    236 	xfs_debug("Found a symbolic link inode!");
    237     }
    238 
    239     return inode;
    240 
    241 out:
    242     free(inode);
    243 
    244     return NULL;
    245 }
    246 
    247 struct inode *xfs_dir2_block_find_entry(const char *dname, struct inode *parent,
    248 					xfs_dinode_t *core)
    249 {
    250     xfs_bmbt_irec_t r;
    251     block_t dir_blk;
    252     struct fs_info *fs = parent->fs;
    253     const uint8_t *dirblk_buf;
    254     uint8_t *p, *endp;
    255     xfs_dir2_data_hdr_t *hdr;
    256     struct inode *inode = NULL;
    257     xfs_dir2_block_tail_t *btp;
    258     xfs_dir2_data_unused_t *dup;
    259     xfs_dir2_data_entry_t *dep;
    260     xfs_intino_t ino;
    261     xfs_dinode_t *ncore;
    262 
    263     xfs_debug("dname %s parent %p core %p", dname, parent, core);
    264 
    265     bmbt_irec_get(&r, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
    266     dir_blk = fsblock_to_bytes(fs, r.br_startblock) >> BLOCK_SHIFT(fs);
    267 
    268     dirblk_buf = xfs_dir2_dirblks_get_cached(fs, dir_blk, r.br_blockcount);
    269     hdr = (xfs_dir2_data_hdr_t *)dirblk_buf;
    270     if (be32_to_cpu(hdr->magic) != XFS_DIR2_BLOCK_MAGIC) {
    271         xfs_error("Block directory header's magic number does not match!");
    272         xfs_debug("hdr->magic: 0x%lx", be32_to_cpu(hdr->magic));
    273         goto out;
    274     }
    275 
    276     p = (uint8_t *)(hdr + 1);
    277 
    278     btp = xfs_dir2_block_tail_p(XFS_INFO(fs), hdr);
    279     endp = (uint8_t *)((xfs_dir2_leaf_entry_t *)btp - be32_to_cpu(btp->count));
    280 
    281     while (p < endp) {
    282         uint8_t *start_name;
    283         uint8_t *end_name;
    284 
    285         dup = (xfs_dir2_data_unused_t *)p;
    286         if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
    287             p += be16_to_cpu(dup->length);
    288             continue;
    289         }
    290 
    291         dep = (xfs_dir2_data_entry_t *)p;
    292 
    293         start_name = &dep->name[0];
    294         end_name = start_name + dep->namelen;
    295 
    296 	if (!xfs_dir2_entry_name_cmp(start_name, end_name, dname)) {
    297 	    xfs_debug("Found entry %s", dname);
    298             goto found;
    299         }
    300 
    301 	p += xfs_dir2_data_entsize(dep->namelen);
    302     }
    303 
    304 out:
    305     return NULL;
    306 
    307 found:
    308     inode = xfs_new_inode(fs);
    309 
    310     ino = be64_to_cpu(dep->inumber);
    311 
    312     xfs_debug("entry inode's number %lu", ino);
    313 
    314     ncore = xfs_dinode_get_core(fs, ino);
    315     if (!ncore) {
    316         xfs_error("Failed to get dinode!");
    317         goto failed;
    318     }
    319 
    320     fill_xfs_inode_pvt(fs, inode, ino);
    321 
    322     inode->ino = ino;
    323     XFS_PVT(inode)->i_ino_blk = ino_to_bytes(fs, ino) >> BLOCK_SHIFT(fs);
    324     inode->size = be64_to_cpu(ncore->di_size);
    325 
    326     if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
    327         inode->mode = DT_DIR;
    328         xfs_debug("Found a directory inode!");
    329     } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
    330         inode->mode = DT_REG;
    331         xfs_debug("Found a file inode!");
    332         xfs_debug("inode size %llu", inode->size);
    333     } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
    334         inode->mode = DT_LNK;
    335         xfs_debug("Found a symbolic link inode!");
    336     }
    337 
    338     xfs_debug("entry inode's number %lu", ino);
    339 
    340     return inode;
    341 
    342 failed:
    343     free(inode);
    344 
    345     return NULL;
    346 }
    347 
    348 struct inode *xfs_dir2_leaf_find_entry(const char *dname, struct inode *parent,
    349 				       xfs_dinode_t *core)
    350 {
    351     xfs_dir2_leaf_t *leaf;
    352     xfs_bmbt_irec_t irec;
    353     block_t leaf_blk, dir_blk;
    354     xfs_dir2_leaf_entry_t *lep;
    355     int low;
    356     int high;
    357     int mid = 0;
    358     uint32_t hash = 0;
    359     uint32_t hashwant;
    360     uint32_t newdb, curdb = -1;
    361     xfs_dir2_data_entry_t *dep;
    362     struct inode *ip;
    363     xfs_dir2_data_hdr_t *data_hdr;
    364     uint8_t *start_name;
    365     uint8_t *end_name;
    366     xfs_intino_t ino;
    367     xfs_dinode_t *ncore;
    368     const uint8_t *buf = NULL;
    369 
    370     xfs_debug("dname %s parent %p core %p", dname, parent, core);
    371 
    372     bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) +
    373 					be32_to_cpu(core->di_nextents) - 1);
    374     leaf_blk = fsblock_to_bytes(parent->fs, irec.br_startblock) >>
    375 	    BLOCK_SHIFT(parent->fs);
    376 
    377     leaf = (xfs_dir2_leaf_t *)xfs_dir2_dirblks_get_cached(parent->fs, leaf_blk,
    378 							  irec.br_blockcount);
    379     if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC) {
    380         xfs_error("Single leaf block header's magic number does not match!");
    381         goto out;
    382     }
    383 
    384     if (!leaf->hdr.count)
    385 	goto out;
    386 
    387     hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname));
    388 
    389     /* Binary search */
    390     for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) - 1;
    391 	 low <= high; ) {
    392         mid = (low + high) >> 1;
    393         if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant)
    394             break;
    395         if (hash < hashwant)
    396             low = mid + 1;
    397         else
    398             high = mid - 1;
    399     }
    400 
    401     /* If hash is not the one we want, then the directory does not contain the
    402      * entry we're looking for and there is nothing to do anymore.
    403      */
    404     if (hash != hashwant)
    405 	goto out;
    406 
    407     while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant)
    408 	mid--;
    409 
    410     for (lep = &leaf->ents[mid];
    411 	 mid < be16_to_cpu(leaf->hdr.count) &&
    412 	 be32_to_cpu(lep->hashval) == hashwant;
    413 	 lep++, mid++) {
    414         /* Skip over stale leaf entries. */
    415         if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
    416             continue;
    417 
    418         newdb = xfs_dir2_dataptr_to_db(parent->fs, be32_to_cpu(lep->address));
    419         if (newdb != curdb) {
    420             bmbt_irec_get(&irec,
    421 		  ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) + newdb);
    422             dir_blk = fsblock_to_bytes(parent->fs, irec.br_startblock) >>
    423 
    424 		      BLOCK_SHIFT(parent->fs);
    425             buf = xfs_dir2_dirblks_get_cached(parent->fs, dir_blk, irec.br_blockcount);
    426             data_hdr = (xfs_dir2_data_hdr_t *)buf;
    427             if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
    428                 xfs_error("Leaf directory's data magic No. does not match!");
    429                 goto out;
    430             }
    431 
    432             curdb = newdb;
    433         }
    434 
    435         dep = (xfs_dir2_data_entry_t *)((char *)buf +
    436                xfs_dir2_dataptr_to_off(parent->fs, be32_to_cpu(lep->address)));
    437 
    438         start_name = &dep->name[0];
    439         end_name = start_name + dep->namelen;
    440 
    441 	if (!xfs_dir2_entry_name_cmp(start_name, end_name, dname)) {
    442 	    xfs_debug("Found entry %s", dname);
    443             goto found;
    444         }
    445     }
    446 
    447 out:
    448     return NULL;
    449 
    450 found:
    451     ip = xfs_new_inode(parent->fs);
    452 
    453     ino = be64_to_cpu(dep->inumber);
    454 
    455     xfs_debug("entry inode's number %lu", ino);
    456 
    457     ncore = xfs_dinode_get_core(parent->fs, ino);
    458     if (!ncore) {
    459         xfs_error("Failed to get dinode!");
    460         goto failed;
    461     }
    462 
    463     fill_xfs_inode_pvt(parent->fs, ip, ino);
    464 
    465     ip->ino = ino;
    466     XFS_PVT(ip)->i_ino_blk = ino_to_bytes(parent->fs, ino) >>
    467 	                        BLOCK_SHIFT(parent->fs);
    468     ip->size = be64_to_cpu(ncore->di_size);
    469 
    470     if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
    471         ip->mode = DT_DIR;
    472         xfs_debug("Found a directory inode!");
    473     } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
    474         ip->mode = DT_REG;
    475         xfs_debug("Found a file inode!");
    476         xfs_debug("inode size %llu", ip->size);
    477     } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
    478         ip->mode = DT_LNK;
    479         xfs_debug("Found a symbolic link inode!");
    480     }
    481 
    482     xfs_debug("entry inode's number %lu", ino);
    483 
    484     return ip;
    485 
    486 failed:
    487     free(ip);
    488 
    489     return ip;
    490 }
    491 
    492 static xfs_fsblock_t
    493 select_child(xfs_dfiloff_t off,
    494              xfs_bmbt_key_t *kp,
    495              xfs_bmbt_ptr_t *pp,
    496              int nrecs)
    497 {
    498     int i;
    499 
    500     for (i = 0; i < nrecs; i++) {
    501         if (be64_to_cpu(kp[i].br_startoff) == off)
    502             return be64_to_cpu(pp[i]);
    503         if (be64_to_cpu(kp[i].br_startoff) > off) {
    504             if (i == 0)
    505                 return be64_to_cpu(pp[i]);
    506             else
    507                 return be64_to_cpu(pp[i-1]);
    508         }
    509     }
    510 
    511     return be64_to_cpu(pp[nrecs - 1]);
    512 }
    513 
    514 block_t xfs_dir2_get_right_blk(struct fs_info *fs, xfs_dinode_t *core,
    515 			       block_t fsblkno, int *error)
    516 {
    517     uint32_t idx;
    518     xfs_bmbt_irec_t irec;
    519     block_t bno;
    520     block_t nextbno;
    521     xfs_bmdr_block_t *rblock;
    522     int fsize;
    523     int nextents;
    524     xfs_bmbt_ptr_t *pp;
    525     xfs_bmbt_key_t *kp;
    526     xfs_btree_block_t *blk;
    527     xfs_bmbt_rec_t *xp;
    528 
    529     *error = 0;
    530     if (core->di_format == XFS_DINODE_FMT_EXTENTS) {
    531         xfs_debug("XFS_DINODE_FMT_EXTENTS");
    532         for (idx = 0; idx < be32_to_cpu(core->di_nextents); idx++) {
    533             bmbt_irec_get(&irec,
    534                           ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) + idx);
    535             if (fsblkno >= irec.br_startoff &&
    536                 fsblkno < irec.br_startoff + irec.br_blockcount)
    537                 break;
    538         }
    539     } else if (core->di_format == XFS_DINODE_FMT_BTREE) {
    540         xfs_debug("XFS_DINODE_FMT_BTREE");
    541         bno = NULLFSBLOCK;
    542         rblock = (xfs_bmdr_block_t *)&core->di_literal_area[0];
    543         fsize = XFS_DFORK_SIZE(core, fs, XFS_DATA_FORK);
    544         pp = XFS_BMDR_PTR_ADDR(rblock, 1, xfs_bmdr_maxrecs(fsize, 0));
    545         kp = XFS_BMDR_KEY_ADDR(rblock, 1);
    546         bno = fsblock_to_bytes(fs,
    547                   select_child(fsblkno, kp, pp,
    548                       be16_to_cpu(rblock->bb_numrecs))) >> BLOCK_SHIFT(fs);
    549 
    550         /* Find the leaf */
    551         for (;;) {
    552             blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
    553             if (be16_to_cpu(blk->bb_level) == 0)
    554                 break;
    555             pp = XFS_BMBT_PTR_ADDR(fs, blk, 1,
    556                      xfs_bmdr_maxrecs(XFS_INFO(fs)->blocksize, 0));
    557             kp = XFS_BMBT_KEY_ADDR(fs, blk, 1);
    558             bno = fsblock_to_bytes(fs,
    559                       select_child(fsblkno, kp, pp,
    560                           be16_to_cpu(blk->bb_numrecs))) >> BLOCK_SHIFT(fs);
    561         }
    562 
    563         /* Find the records among leaves */
    564         for (;;) {
    565             nextbno = be64_to_cpu(blk->bb_u.l.bb_rightsib);
    566             nextents = be16_to_cpu(blk->bb_numrecs);
    567             xp = (xfs_bmbt_rec_t *)XFS_BMBT_REC_ADDR(fs, blk, 1);
    568             for (idx = 0; idx < nextents; idx++) {
    569                 bmbt_irec_get(&irec, xp + idx);
    570                 if (fsblkno >= irec.br_startoff &&
    571                     fsblkno < irec.br_startoff + irec.br_blockcount) {
    572                     nextbno = NULLFSBLOCK;
    573                     break;
    574                 }
    575             }
    576             if (nextbno == NULLFSBLOCK)
    577                 break;
    578             bno = fsblock_to_bytes(fs, nextbno) >> BLOCK_SHIFT(fs);
    579             blk = (xfs_btree_block_t *)get_cache(fs->fs_dev, bno);
    580         }
    581     }
    582 
    583     if (fsblkno < irec.br_startoff ||
    584         fsblkno >= irec.br_startoff + irec.br_blockcount)
    585         *error = 1;
    586 
    587     return fsblock_to_bytes(fs,
    588                 fsblkno - irec.br_startoff + irec.br_startblock) >>
    589                 BLOCK_SHIFT(fs);
    590 }
    591 
    592 struct inode *xfs_dir2_node_find_entry(const char *dname, struct inode *parent,
    593 				       xfs_dinode_t *core)
    594 {
    595     block_t fsblkno;
    596     xfs_da_intnode_t *node = NULL;
    597     uint32_t hashwant;
    598     uint32_t hash = 0;
    599     xfs_da_node_entry_t *btree;
    600     uint16_t max;
    601     uint16_t span;
    602     uint16_t probe;
    603     int error;
    604     xfs_dir2_data_hdr_t *data_hdr;
    605     xfs_dir2_leaf_t *leaf;
    606     xfs_dir2_leaf_entry_t *lep;
    607     xfs_dir2_data_entry_t *dep;
    608     struct inode *ip;
    609     uint8_t *start_name;
    610     uint8_t *end_name;
    611     int low;
    612     int high;
    613     int mid = 0;
    614     uint32_t newdb, curdb = -1;
    615     xfs_intino_t ino;
    616     xfs_dinode_t *ncore;
    617     const uint8_t *buf = NULL;
    618 
    619     xfs_debug("dname %s parent %p core %p", dname, parent, core);
    620 
    621     hashwant = xfs_dir2_da_hashname((uint8_t *)dname, strlen(dname));
    622 
    623     fsblkno = xfs_dir2_get_right_blk(parent->fs, core,
    624                   xfs_dir2_byte_to_db(parent->fs, XFS_DIR2_LEAF_OFFSET),
    625                   &error);
    626     if (error) {
    627         xfs_error("Cannot find right rec!");
    628         return NULL;
    629     }
    630 
    631     node = (xfs_da_intnode_t *)xfs_dir2_dirblks_get_cached(parent->fs, fsblkno,
    632 							   1);
    633     if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) {
    634         xfs_error("Node's magic number does not match!");
    635         goto out;
    636     }
    637 
    638     do {
    639         if (!node->hdr.count)
    640             goto out;
    641 
    642         /* Given a hash to lookup, you read the node's btree array and first
    643          * "hashval" in the array that exceeds the given hash and it can then
    644          * be found in the block pointed by the "before" value.
    645          */
    646         max = be16_to_cpu(node->hdr.count);
    647 
    648         probe = span = max/2;
    649         for (btree = &node->btree[probe];
    650              span > 4; btree = &node->btree[probe]) {
    651             span /= 2;
    652             hash = be32_to_cpu(btree->hashval);
    653 
    654             if (hash < hashwant)
    655                 probe += span;
    656             else if (hash > hashwant)
    657                 probe -= span;
    658             else
    659                 break;
    660         }
    661 
    662         while ((probe > 0) && (be32_to_cpu(btree->hashval) >= hashwant)) {
    663             btree--;
    664             probe--;
    665         }
    666 
    667         while ((probe < max) && (be32_to_cpu(btree->hashval) < hashwant)) {
    668             btree++;
    669             probe++;
    670         }
    671 
    672         if (probe == max)
    673             fsblkno = be32_to_cpu(node->btree[max-1].before);
    674         else
    675             fsblkno = be32_to_cpu(node->btree[probe].before);
    676 
    677         fsblkno = xfs_dir2_get_right_blk(parent->fs, core, fsblkno, &error);
    678         if (error) {
    679             xfs_error("Cannot find right rec!");
    680             goto out;
    681         }
    682 
    683         node = (xfs_da_intnode_t *)xfs_dir2_dirblks_get_cached(parent->fs,
    684 							       fsblkno, 1);
    685     } while(be16_to_cpu(node->hdr.info.magic) == XFS_DA_NODE_MAGIC);
    686 
    687     leaf = (xfs_dir2_leaf_t*)node;
    688     if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) {
    689         xfs_error("Leaf's magic number does not match!");
    690         goto out;
    691     }
    692 
    693     if (!leaf->hdr.count)
    694         goto out;
    695 
    696     for (lep = leaf->ents, low = 0, high = be16_to_cpu(leaf->hdr.count) - 1;
    697          low <= high; ) {
    698         mid = (low + high) >> 1;
    699 
    700         if ((hash = be32_to_cpu(lep[mid].hashval)) == hashwant)
    701             break;
    702         if (hash < hashwant)
    703             low = mid + 1;
    704         else
    705             high = mid - 1;
    706     }
    707 
    708     /* If hash is not the one we want, then the directory does not contain the
    709      * entry we're looking for and there is nothing to do anymore.
    710      */
    711     if (hash != hashwant)
    712         goto out;
    713 
    714     while (mid > 0 && be32_to_cpu(lep[mid - 1].hashval) == hashwant)
    715         mid--;
    716 
    717     for (lep = &leaf->ents[mid];
    718          mid < be16_to_cpu(leaf->hdr.count) &&
    719          be32_to_cpu(lep->hashval) == hashwant;
    720          lep++, mid++) {
    721         /* Skip over stale leaf entries. */
    722         if (be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR)
    723             continue;
    724 
    725         newdb = xfs_dir2_dataptr_to_db(parent->fs, be32_to_cpu(lep->address));
    726         if (newdb != curdb) {
    727             fsblkno = xfs_dir2_get_right_blk(parent->fs, core, newdb, &error);
    728             if (error) {
    729                 xfs_error("Cannot find data block!");
    730                 goto out;
    731             }
    732 
    733             buf = xfs_dir2_dirblks_get_cached(parent->fs, fsblkno, 1);
    734             data_hdr = (xfs_dir2_data_hdr_t *)buf;
    735             if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
    736                 xfs_error("Leaf directory's data magic No. does not match!");
    737                 goto out;
    738             }
    739 
    740             curdb = newdb;
    741         }
    742 
    743         dep = (xfs_dir2_data_entry_t *)((char *)buf +
    744                xfs_dir2_dataptr_to_off(parent->fs, be32_to_cpu(lep->address)));
    745 
    746         start_name = &dep->name[0];
    747         end_name = start_name + dep->namelen;
    748 
    749 	if (!xfs_dir2_entry_name_cmp(start_name, end_name, dname)) {
    750 	    xfs_debug("Found entry %s", dname);
    751 	    goto found;
    752         }
    753     }
    754 
    755 out:
    756     return NULL;
    757 
    758 found:
    759     ip = xfs_new_inode(parent->fs);
    760     ino = be64_to_cpu(dep->inumber);
    761     ncore = xfs_dinode_get_core(parent->fs, ino);
    762     if (!ncore) {
    763         xfs_error("Failed to get dinode!");
    764         goto failed;
    765     }
    766 
    767     fill_xfs_inode_pvt(parent->fs, ip, ino);
    768     ip->ino = ino;
    769     XFS_PVT(ip)->i_ino_blk = ino_to_bytes(parent->fs, ino) >>
    770         BLOCK_SHIFT(parent->fs);
    771     ip->size = be64_to_cpu(ncore->di_size);
    772 
    773     if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFDIR) {
    774         ip->mode = DT_DIR;
    775         xfs_debug("Found a directory inode!");
    776     } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFREG) {
    777         ip->mode = DT_REG;
    778         xfs_debug("Found a file inode!");
    779         xfs_debug("inode size %llu", ip->size);
    780     } else if ((be16_to_cpu(ncore->di_mode) & S_IFMT) == S_IFLNK) {
    781         ip->mode = DT_LNK;
    782         xfs_debug("Found a symbolic link inode!");
    783     }
    784 
    785     xfs_debug("entry inode's number %lu", ino);
    786 
    787     return ip;
    788 
    789 failed:
    790     free(ip);
    791 
    792     return NULL;
    793 }
    794