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