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 #include "xfs_dir2.h"
     29 
     30 #include "xfs_readdir.h"
     31 
     32 static int fill_dirent(struct fs_info *fs, struct dirent *dirent,
     33 		       uint32_t offset, xfs_ino_t ino, char *name,
     34 		       size_t namelen)
     35 {
     36     xfs_dinode_t *core;
     37 
     38     xfs_debug("fs %p, dirent %p offset %lu ino %llu name %s namelen %llu", fs,
     39 	      dirent, offset, ino, name, namelen);
     40 
     41     dirent->d_ino = ino;
     42     dirent->d_off = offset;
     43     dirent->d_reclen = offsetof(struct dirent, d_name) + namelen + 1;
     44 
     45     core = xfs_dinode_get_core(fs, ino);
     46     if (!core) {
     47         xfs_error("Failed to get dinode from disk (ino 0x%llx)", ino);
     48         return -1;
     49     }
     50 
     51     if (be16_to_cpu(core->di_mode) & S_IFDIR)
     52 	dirent->d_type = DT_DIR;
     53     else if (be16_to_cpu(core->di_mode) & S_IFREG)
     54 	dirent->d_type = DT_REG;
     55     else if (be16_to_cpu(core->di_mode) & S_IFLNK)
     56         dirent->d_type = DT_LNK;
     57 
     58     memcpy(dirent->d_name, name, namelen);
     59     dirent->d_name[namelen] = '\0';
     60 
     61     return 0;
     62 }
     63 
     64 int xfs_readdir_dir2_local(struct file *file, struct dirent *dirent,
     65 			   xfs_dinode_t *core)
     66 {
     67     xfs_dir2_sf_t *sf = (xfs_dir2_sf_t *)&core->di_literal_area[0];
     68     xfs_dir2_sf_entry_t *sf_entry;
     69     uint8_t count = sf->hdr.i8count ? sf->hdr.i8count : sf->hdr.count;
     70     uint32_t offset = file->offset;
     71     uint8_t *start_name;
     72     uint8_t *end_name;
     73     xfs_ino_t ino;
     74     struct fs_info *fs = file->fs;
     75     int retval = 0;
     76 
     77     xfs_debug("file %p dirent %p core %p", file, dirent, core);
     78     xfs_debug("count %hhu i8count %hhu", sf->hdr.count, sf->hdr.i8count);
     79 
     80     if (file->offset + 1 > count)
     81 	goto out;
     82 
     83     file->offset++;
     84 
     85     sf_entry = (xfs_dir2_sf_entry_t *)((uint8_t *)&sf->list[0] -
     86 				       (!sf->hdr.i8count ? 4 : 0));
     87 
     88     if (file->offset - 1) {
     89 	offset = file->offset;
     90 	while (--offset) {
     91 	    sf_entry = (xfs_dir2_sf_entry_t *)(
     92 				(uint8_t *)sf_entry +
     93 				offsetof(struct xfs_dir2_sf_entry,
     94 					 name[0]) +
     95 				sf_entry->namelen +
     96 				(sf->hdr.i8count ? 8 : 4));
     97 	}
     98     }
     99 
    100     start_name = &sf_entry->name[0];
    101     end_name = start_name + sf_entry->namelen;
    102 
    103     ino = xfs_dir2_sf_get_inumber(sf, (xfs_dir2_inou_t *)(
    104 				      (uint8_t *)sf_entry +
    105 				      offsetof(struct xfs_dir2_sf_entry,
    106 					       name[0]) +
    107 				      sf_entry->namelen));
    108 
    109     retval = fill_dirent(fs, dirent, file->offset, ino, (char *)start_name,
    110 			 end_name - start_name);
    111     if (retval)
    112 	xfs_error("Failed to fill in dirent structure");
    113 
    114     return retval;
    115 
    116 out:
    117     xfs_dir2_dirblks_flush_cache();
    118 
    119     return -1;
    120 }
    121 
    122 int xfs_readdir_dir2_block(struct file *file, struct dirent *dirent,
    123 			   xfs_dinode_t *core)
    124 {
    125     xfs_bmbt_irec_t r;
    126     block_t dir_blk;
    127     struct fs_info *fs = file->fs;
    128     const uint8_t *dirblk_buf;
    129     uint8_t *p;
    130     uint32_t offset;
    131     xfs_dir2_data_hdr_t *hdr;
    132     xfs_dir2_block_tail_t *btp;
    133     xfs_dir2_data_unused_t *dup;
    134     xfs_dir2_data_entry_t *dep;
    135     uint8_t *start_name;
    136     uint8_t *end_name;
    137     xfs_ino_t ino;
    138     int retval = 0;
    139 
    140     xfs_debug("file %p dirent %p core %p", file, dirent, core);
    141 
    142     bmbt_irec_get(&r, (xfs_bmbt_rec_t *)&core->di_literal_area[0]);
    143     dir_blk = fsblock_to_bytes(fs, r.br_startblock) >> BLOCK_SHIFT(fs);
    144 
    145     dirblk_buf = xfs_dir2_dirblks_get_cached(fs, dir_blk, r.br_blockcount);
    146     hdr = (xfs_dir2_data_hdr_t *)dirblk_buf;
    147     if (be32_to_cpu(hdr->magic) != XFS_DIR2_BLOCK_MAGIC) {
    148         xfs_error("Block directory header's magic number does not match!");
    149         xfs_debug("hdr->magic: 0x%lx", be32_to_cpu(hdr->magic));
    150 	goto out;
    151     }
    152 
    153     btp = xfs_dir2_block_tail_p(XFS_INFO(fs), hdr);
    154 
    155     if (file->offset + 1 > be32_to_cpu(btp->count))
    156 	goto out;
    157 
    158     file->offset++;
    159 
    160     p = (uint8_t *)(hdr + 1);
    161 
    162     if (file->offset - 1) {
    163 	offset = file->offset;
    164 	while (--offset) {
    165 	    dep = (xfs_dir2_data_entry_t *)p;
    166 
    167 	    dup = (xfs_dir2_data_unused_t *)p;
    168 	    if (be16_to_cpu(dup->freetag) == XFS_DIR2_DATA_FREE_TAG) {
    169 		p += be16_to_cpu(dup->length);
    170 		continue;
    171 	    }
    172 
    173 	    p += xfs_dir2_data_entsize(dep->namelen);
    174 	}
    175     }
    176 
    177     dep = (xfs_dir2_data_entry_t *)p;
    178 
    179     start_name = &dep->name[0];
    180     end_name = start_name + dep->namelen;
    181 
    182     ino = be64_to_cpu(dep->inumber);
    183 
    184     retval = fill_dirent(fs, dirent, file->offset, ino, (char *)start_name,
    185 			 end_name - start_name);
    186     if (retval)
    187 	xfs_error("Failed to fill in dirent structure");
    188 
    189     return retval;
    190 
    191 out:
    192     xfs_dir2_dirblks_flush_cache();
    193 
    194     return -1;
    195 }
    196 
    197 int xfs_readdir_dir2_leaf(struct file *file, struct dirent *dirent,
    198 			  xfs_dinode_t *core)
    199 {
    200     xfs_bmbt_irec_t irec;
    201     struct fs_info *fs = file->fs;
    202     xfs_dir2_leaf_t *leaf;
    203     block_t leaf_blk, dir_blk;
    204     xfs_dir2_leaf_entry_t *lep;
    205     uint32_t db;
    206     unsigned int offset;
    207     xfs_dir2_data_entry_t *dep;
    208     xfs_dir2_data_hdr_t *data_hdr;
    209     uint8_t *start_name;
    210     uint8_t *end_name;
    211     xfs_intino_t ino;
    212     const uint8_t *buf = NULL;
    213     int retval = 0;
    214 
    215     xfs_debug("file %p dirent %p core %p", file, dirent, core);
    216 
    217     bmbt_irec_get(&irec, ((xfs_bmbt_rec_t *)&core->di_literal_area[0]) +
    218 					be32_to_cpu(core->di_nextents) - 1);
    219     leaf_blk = fsblock_to_bytes(fs, irec.br_startblock) >>
    220 					BLOCK_SHIFT(file->fs);
    221 
    222     leaf = (xfs_dir2_leaf_t *)xfs_dir2_dirblks_get_cached(fs, leaf_blk,
    223 							  irec.br_blockcount);
    224     if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAF1_MAGIC) {
    225         xfs_error("Single leaf block header's magic number does not match!");
    226         goto out;
    227     }
    228 
    229     if (!leaf->hdr.count)
    230         goto out;
    231 
    232     if (file->offset + 1 > be16_to_cpu(leaf->hdr.count))
    233 	goto out;
    234 
    235     lep = &leaf->ents[file->offset++];
    236 
    237     /* Skip over stale leaf entries */
    238     for ( ; be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR;
    239 	  lep++, file->offset++);
    240 
    241     db = xfs_dir2_dataptr_to_db(fs, be32_to_cpu(lep->address));
    242 
    243     bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] + db);
    244 
    245     dir_blk = fsblock_to_bytes(fs, irec.br_startblock) >> BLOCK_SHIFT(fs);
    246 
    247     buf = xfs_dir2_dirblks_get_cached(fs, dir_blk, irec.br_blockcount);
    248     data_hdr = (xfs_dir2_data_hdr_t *)buf;
    249     if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
    250 	xfs_error("Leaf directory's data magic number does not match!");
    251 	goto out;
    252     }
    253 
    254     offset = xfs_dir2_dataptr_to_off(fs, be32_to_cpu(lep->address));
    255 
    256     dep = (xfs_dir2_data_entry_t *)((uint8_t *)buf + offset);
    257 
    258     start_name = &dep->name[0];
    259     end_name = start_name + dep->namelen;
    260 
    261     ino = be64_to_cpu(dep->inumber);
    262 
    263     retval = fill_dirent(fs, dirent, file->offset, ino, (char *)start_name,
    264 			 end_name - start_name);
    265     if (retval)
    266 	xfs_error("Failed to fill in dirent structure");
    267 
    268     return retval;
    269 
    270 out:
    271     xfs_dir2_dirblks_flush_cache();
    272 
    273     return -1;
    274 }
    275 
    276 int xfs_readdir_dir2_node(struct file *file, struct dirent *dirent,
    277 			  xfs_dinode_t *core)
    278 {
    279     struct fs_info *fs = file->fs;
    280     xfs_bmbt_irec_t irec;
    281     uint32_t node_off = 0;
    282     block_t fsblkno;
    283     xfs_da_intnode_t *node = NULL;
    284     struct inode *inode = file->inode;
    285     int error;
    286     xfs_dir2_data_hdr_t *data_hdr;
    287     xfs_dir2_leaf_t *leaf;
    288     xfs_dir2_leaf_entry_t *lep;
    289     unsigned int offset;
    290     xfs_dir2_data_entry_t *dep;
    291     uint8_t *start_name;
    292     uint8_t *end_name;
    293     uint32_t db;
    294     const uint8_t *buf = NULL;
    295     int retval = 0;
    296 
    297     xfs_debug("file %p dirent %p core %p", file, dirent, core);
    298 
    299     do {
    300         bmbt_irec_get(&irec, (xfs_bmbt_rec_t *)&core->di_literal_area[0] +
    301 								++node_off);
    302     } while (irec.br_startoff < xfs_dir2_byte_to_db(fs, XFS_DIR2_LEAF_OFFSET));
    303 
    304     fsblkno = fsblock_to_bytes(fs, irec.br_startblock) >> BLOCK_SHIFT(fs);
    305 
    306     node = (xfs_da_intnode_t *)xfs_dir2_dirblks_get_cached(fs, fsblkno, 1);
    307     if (be16_to_cpu(node->hdr.info.magic) != XFS_DA_NODE_MAGIC) {
    308         xfs_error("Node's magic number does not match!");
    309         goto out;
    310     }
    311 
    312 try_next_btree:
    313     if (!node->hdr.count ||
    314 	XFS_PVT(inode)->i_btree_offset >= be16_to_cpu(node->hdr.count))
    315 	goto out;
    316 
    317     fsblkno = be32_to_cpu(node->btree[XFS_PVT(inode)->i_btree_offset].before);
    318     fsblkno = xfs_dir2_get_right_blk(fs, core, fsblkno, &error);
    319     if (error) {
    320         xfs_error("Cannot find leaf rec!");
    321         goto out;
    322     }
    323 
    324     leaf = (xfs_dir2_leaf_t*)xfs_dir2_dirblks_get_cached(fs, fsblkno, 1);
    325     if (be16_to_cpu(leaf->hdr.info.magic) != XFS_DIR2_LEAFN_MAGIC) {
    326         xfs_error("Leaf's magic number does not match!");
    327         goto out;
    328     }
    329 
    330     if (!leaf->hdr.count ||
    331 	XFS_PVT(inode)->i_leaf_ent_offset >= be16_to_cpu(leaf->hdr.count)) {
    332 	XFS_PVT(inode)->i_btree_offset++;
    333 	XFS_PVT(inode)->i_leaf_ent_offset = 0;
    334 	goto try_next_btree;
    335     }
    336 
    337     lep = &leaf->ents[XFS_PVT(inode)->i_leaf_ent_offset];
    338 
    339     /* Skip over stale leaf entries */
    340     for ( ; XFS_PVT(inode)->i_leaf_ent_offset < be16_to_cpu(leaf->hdr.count) &&
    341 			be32_to_cpu(lep->address) == XFS_DIR2_NULL_DATAPTR;
    342 	  lep++, XFS_PVT(inode)->i_leaf_ent_offset++);
    343 
    344     if (XFS_PVT(inode)->i_leaf_ent_offset == be16_to_cpu(leaf->hdr.count)) {
    345 	XFS_PVT(inode)->i_btree_offset++;
    346 	XFS_PVT(inode)->i_leaf_ent_offset = 0;
    347 	goto try_next_btree;
    348     } else {
    349 	XFS_PVT(inode)->i_leaf_ent_offset++;
    350     }
    351 
    352     db = xfs_dir2_dataptr_to_db(fs, be32_to_cpu(lep->address));
    353 
    354     fsblkno = xfs_dir2_get_right_blk(fs, core, db, &error);
    355     if (error) {
    356 	xfs_error("Cannot find data block!");
    357 	goto out;
    358     }
    359 
    360     buf = xfs_dir2_dirblks_get_cached(fs, fsblkno, 1);
    361     data_hdr = (xfs_dir2_data_hdr_t *)buf;
    362     if (be32_to_cpu(data_hdr->magic) != XFS_DIR2_DATA_MAGIC) {
    363 	xfs_error("Leaf directory's data magic No. does not match!");
    364 	goto out;
    365     }
    366 
    367     offset = xfs_dir2_dataptr_to_off(fs, be32_to_cpu(lep->address));
    368 
    369     dep = (xfs_dir2_data_entry_t *)((uint8_t *)buf + offset);
    370 
    371     start_name = &dep->name[0];
    372     end_name = start_name + dep->namelen;
    373 
    374     retval = fill_dirent(fs, dirent, 0, be64_to_cpu(dep->inumber),
    375 			 (char *)start_name, end_name - start_name);
    376     if (retval)
    377 	xfs_error("Failed to fill in dirent structure");
    378 
    379     return retval;
    380 
    381 out:
    382     xfs_dir2_dirblks_flush_cache();
    383 
    384     XFS_PVT(inode)->i_btree_offset = 0;
    385     XFS_PVT(inode)->i_leaf_ent_offset = 0;
    386 
    387     return -1;
    388 }
    389