1/* 2 * Squashfs - a compressed read only filesystem for Linux 3 * 4 * Copyright (c) 2002, 2003, 2004, 2005, 2006, 2007 5 * Phillip Lougher <phillip@lougher.org.uk> 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2, 10 * or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 20 * 21 * squashfs2_0.c 22 */ 23 24#include <linux/squashfs_fs.h> 25#include <linux/module.h> 26#include <linux/zlib.h> 27#include <linux/fs.h> 28#include <linux/squashfs_fs_sb.h> 29#include <linux/squashfs_fs_i.h> 30 31#include "squashfs.h" 32static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir); 33static struct dentry *squashfs_lookup_2(struct inode *, struct dentry *, 34 struct nameidata *); 35 36static struct file_operations squashfs_dir_ops_2 = { 37 .read = generic_read_dir, 38 .readdir = squashfs_readdir_2 39}; 40 41static struct inode_operations squashfs_dir_inode_ops_2 = { 42 .lookup = squashfs_lookup_2 43}; 44 45static unsigned char squashfs_filetype_table[] = { 46 DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK 47}; 48 49static int read_fragment_index_table_2(struct super_block *s) 50{ 51 struct squashfs_sb_info *msblk = s->s_fs_info; 52 struct squashfs_super_block *sblk = &msblk->sblk; 53 54 if (!(msblk->fragment_index_2 = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES_2 55 (sblk->fragments), GFP_KERNEL))) { 56 ERROR("Failed to allocate uid/gid table\n"); 57 return 0; 58 } 59 60 if (SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments) && 61 !squashfs_read_data(s, (char *) 62 msblk->fragment_index_2, 63 sblk->fragment_table_start, 64 SQUASHFS_FRAGMENT_INDEX_BYTES_2 65 (sblk->fragments) | 66 SQUASHFS_COMPRESSED_BIT_BLOCK, NULL, SQUASHFS_FRAGMENT_INDEX_BYTES_2(sblk->fragments))) { 67 ERROR("unable to read fragment index table\n"); 68 return 0; 69 } 70 71 if (msblk->swap) { 72 int i; 73 unsigned int fragment; 74 75 for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES_2(sblk->fragments); 76 i++) { 77 SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment), 78 &msblk->fragment_index_2[i], 1); 79 msblk->fragment_index_2[i] = fragment; 80 } 81 } 82 83 return 1; 84} 85 86 87static int get_fragment_location_2(struct super_block *s, unsigned int fragment, 88 long long *fragment_start_block, 89 unsigned int *fragment_size) 90{ 91 struct squashfs_sb_info *msblk = s->s_fs_info; 92 long long start_block = 93 msblk->fragment_index_2[SQUASHFS_FRAGMENT_INDEX_2(fragment)]; 94 int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET_2(fragment); 95 struct squashfs_fragment_entry_2 fragment_entry; 96 97 if (msblk->swap) { 98 struct squashfs_fragment_entry_2 sfragment_entry; 99 100 if (!squashfs_get_cached_block(s, (char *) &sfragment_entry, 101 start_block, offset, 102 sizeof(sfragment_entry), &start_block, 103 &offset)) 104 goto out; 105 SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry, &sfragment_entry); 106 } else 107 if (!squashfs_get_cached_block(s, (char *) &fragment_entry, 108 start_block, offset, 109 sizeof(fragment_entry), &start_block, 110 &offset)) 111 goto out; 112 113 *fragment_start_block = fragment_entry.start_block; 114 *fragment_size = fragment_entry.size; 115 116 return 1; 117 118out: 119 return 0; 120} 121 122 123static void squashfs_new_inode(struct squashfs_sb_info *msblk, struct inode *i, 124 struct squashfs_base_inode_header_2 *inodeb, unsigned int ino) 125{ 126 struct squashfs_super_block *sblk = &msblk->sblk; 127 128 i->i_ino = ino; 129 i->i_mtime.tv_sec = sblk->mkfs_time; 130 i->i_atime.tv_sec = sblk->mkfs_time; 131 i->i_ctime.tv_sec = sblk->mkfs_time; 132 i->i_uid = msblk->uid[inodeb->uid]; 133 i->i_mode = inodeb->mode; 134 i->i_nlink = 1; 135 i->i_size = 0; 136 if (inodeb->guid == SQUASHFS_GUIDS) 137 i->i_gid = i->i_uid; 138 else 139 i->i_gid = msblk->guid[inodeb->guid]; 140} 141 142 143static int squashfs_read_inode_2(struct inode *i, squashfs_inode_t inode) 144{ 145 struct super_block *s = i->i_sb; 146 struct squashfs_sb_info *msblk = s->s_fs_info; 147 struct squashfs_super_block *sblk = &msblk->sblk; 148 unsigned int block = SQUASHFS_INODE_BLK(inode) + 149 sblk->inode_table_start; 150 unsigned int offset = SQUASHFS_INODE_OFFSET(inode); 151 unsigned int ino = i->i_ino; 152 long long next_block; 153 unsigned int next_offset; 154 union squashfs_inode_header_2 id, sid; 155 struct squashfs_base_inode_header_2 *inodeb = &id.base, 156 *sinodeb = &sid.base; 157 158 TRACE("Entered squashfs_iget\n"); 159 160 if (msblk->swap) { 161 if (!squashfs_get_cached_block(s, (char *) sinodeb, block, 162 offset, sizeof(*sinodeb), &next_block, 163 &next_offset)) 164 goto failed_read; 165 SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb, 166 sizeof(*sinodeb)); 167 } else 168 if (!squashfs_get_cached_block(s, (char *) inodeb, block, 169 offset, sizeof(*inodeb), &next_block, 170 &next_offset)) 171 goto failed_read; 172 173 squashfs_new_inode(msblk, i, inodeb, ino); 174 175 switch(inodeb->inode_type) { 176 case SQUASHFS_FILE_TYPE: { 177 struct squashfs_reg_inode_header_2 *inodep = &id.reg; 178 struct squashfs_reg_inode_header_2 *sinodep = &sid.reg; 179 long long frag_blk; 180 unsigned int frag_size = 0; 181 182 if (msblk->swap) { 183 if (!squashfs_get_cached_block(s, (char *) 184 sinodep, block, offset, 185 sizeof(*sinodep), &next_block, 186 &next_offset)) 187 goto failed_read; 188 SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep); 189 } else 190 if (!squashfs_get_cached_block(s, (char *) 191 inodep, block, offset, 192 sizeof(*inodep), &next_block, 193 &next_offset)) 194 goto failed_read; 195 196 frag_blk = SQUASHFS_INVALID_BLK; 197 if (inodep->fragment != SQUASHFS_INVALID_FRAG && 198 !get_fragment_location_2(s, 199 inodep->fragment, &frag_blk, &frag_size)) 200 goto failed_read; 201 202 i->i_size = inodep->file_size; 203 i->i_fop = &generic_ro_fops; 204 i->i_mode |= S_IFREG; 205 i->i_mtime.tv_sec = inodep->mtime; 206 i->i_atime.tv_sec = inodep->mtime; 207 i->i_ctime.tv_sec = inodep->mtime; 208 i->i_blocks = ((i->i_size - 1) >> 9) + 1; 209 SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk; 210 SQUASHFS_I(i)->u.s1.fragment_size = frag_size; 211 SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset; 212 SQUASHFS_I(i)->start_block = inodep->start_block; 213 SQUASHFS_I(i)->u.s1.block_list_start = next_block; 214 SQUASHFS_I(i)->offset = next_offset; 215 if (sblk->block_size > 4096) 216 i->i_data.a_ops = &squashfs_aops; 217 else 218 i->i_data.a_ops = &squashfs_aops_4K; 219 220 TRACE("File inode %x:%x, start_block %x, " 221 "block_list_start %llx, offset %x\n", 222 SQUASHFS_INODE_BLK(inode), offset, 223 inodep->start_block, next_block, 224 next_offset); 225 break; 226 } 227 case SQUASHFS_DIR_TYPE: { 228 struct squashfs_dir_inode_header_2 *inodep = &id.dir; 229 struct squashfs_dir_inode_header_2 *sinodep = &sid.dir; 230 231 if (msblk->swap) { 232 if (!squashfs_get_cached_block(s, (char *) 233 sinodep, block, offset, 234 sizeof(*sinodep), &next_block, 235 &next_offset)) 236 goto failed_read; 237 SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep); 238 } else 239 if (!squashfs_get_cached_block(s, (char *) 240 inodep, block, offset, 241 sizeof(*inodep), &next_block, 242 &next_offset)) 243 goto failed_read; 244 245 i->i_size = inodep->file_size; 246 i->i_op = &squashfs_dir_inode_ops_2; 247 i->i_fop = &squashfs_dir_ops_2; 248 i->i_mode |= S_IFDIR; 249 i->i_mtime.tv_sec = inodep->mtime; 250 i->i_atime.tv_sec = inodep->mtime; 251 i->i_ctime.tv_sec = inodep->mtime; 252 SQUASHFS_I(i)->start_block = inodep->start_block; 253 SQUASHFS_I(i)->offset = inodep->offset; 254 SQUASHFS_I(i)->u.s2.directory_index_count = 0; 255 SQUASHFS_I(i)->u.s2.parent_inode = 0; 256 257 TRACE("Directory inode %x:%x, start_block %x, offset " 258 "%x\n", SQUASHFS_INODE_BLK(inode), 259 offset, inodep->start_block, 260 inodep->offset); 261 break; 262 } 263 case SQUASHFS_LDIR_TYPE: { 264 struct squashfs_ldir_inode_header_2 *inodep = &id.ldir; 265 struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir; 266 267 if (msblk->swap) { 268 if (!squashfs_get_cached_block(s, (char *) 269 sinodep, block, offset, 270 sizeof(*sinodep), &next_block, 271 &next_offset)) 272 goto failed_read; 273 SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep, 274 sinodep); 275 } else 276 if (!squashfs_get_cached_block(s, (char *) 277 inodep, block, offset, 278 sizeof(*inodep), &next_block, 279 &next_offset)) 280 goto failed_read; 281 282 i->i_size = inodep->file_size; 283 i->i_op = &squashfs_dir_inode_ops_2; 284 i->i_fop = &squashfs_dir_ops_2; 285 i->i_mode |= S_IFDIR; 286 i->i_mtime.tv_sec = inodep->mtime; 287 i->i_atime.tv_sec = inodep->mtime; 288 i->i_ctime.tv_sec = inodep->mtime; 289 SQUASHFS_I(i)->start_block = inodep->start_block; 290 SQUASHFS_I(i)->offset = inodep->offset; 291 SQUASHFS_I(i)->u.s2.directory_index_start = next_block; 292 SQUASHFS_I(i)->u.s2.directory_index_offset = 293 next_offset; 294 SQUASHFS_I(i)->u.s2.directory_index_count = 295 inodep->i_count; 296 SQUASHFS_I(i)->u.s2.parent_inode = 0; 297 298 TRACE("Long directory inode %x:%x, start_block %x, " 299 "offset %x\n", 300 SQUASHFS_INODE_BLK(inode), offset, 301 inodep->start_block, inodep->offset); 302 break; 303 } 304 case SQUASHFS_SYMLINK_TYPE: { 305 struct squashfs_symlink_inode_header_2 *inodep = 306 &id.symlink; 307 struct squashfs_symlink_inode_header_2 *sinodep = 308 &sid.symlink; 309 310 if (msblk->swap) { 311 if (!squashfs_get_cached_block(s, (char *) 312 sinodep, block, offset, 313 sizeof(*sinodep), &next_block, 314 &next_offset)) 315 goto failed_read; 316 SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep, 317 sinodep); 318 } else 319 if (!squashfs_get_cached_block(s, (char *) 320 inodep, block, offset, 321 sizeof(*inodep), &next_block, 322 &next_offset)) 323 goto failed_read; 324 325 i->i_size = inodep->symlink_size; 326 i->i_op = &page_symlink_inode_operations; 327 i->i_data.a_ops = &squashfs_symlink_aops; 328 i->i_mode |= S_IFLNK; 329 SQUASHFS_I(i)->start_block = next_block; 330 SQUASHFS_I(i)->offset = next_offset; 331 332 TRACE("Symbolic link inode %x:%x, start_block %llx, " 333 "offset %x\n", 334 SQUASHFS_INODE_BLK(inode), offset, 335 next_block, next_offset); 336 break; 337 } 338 case SQUASHFS_BLKDEV_TYPE: 339 case SQUASHFS_CHRDEV_TYPE: { 340 struct squashfs_dev_inode_header_2 *inodep = &id.dev; 341 struct squashfs_dev_inode_header_2 *sinodep = &sid.dev; 342 343 if (msblk->swap) { 344 if (!squashfs_get_cached_block(s, (char *) 345 sinodep, block, offset, 346 sizeof(*sinodep), &next_block, 347 &next_offset)) 348 goto failed_read; 349 SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep); 350 } else 351 if (!squashfs_get_cached_block(s, (char *) 352 inodep, block, offset, 353 sizeof(*inodep), &next_block, 354 &next_offset)) 355 goto failed_read; 356 357 i->i_mode |= (inodeb->inode_type == 358 SQUASHFS_CHRDEV_TYPE) ? S_IFCHR : 359 S_IFBLK; 360 init_special_inode(i, i->i_mode, 361 old_decode_dev(inodep->rdev)); 362 363 TRACE("Device inode %x:%x, rdev %x\n", 364 SQUASHFS_INODE_BLK(inode), offset, 365 inodep->rdev); 366 break; 367 } 368 case SQUASHFS_FIFO_TYPE: 369 case SQUASHFS_SOCKET_TYPE: { 370 371 i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE) 372 ? S_IFIFO : S_IFSOCK; 373 init_special_inode(i, i->i_mode, 0); 374 break; 375 } 376 default: 377 ERROR("Unknown inode type %d in squashfs_iget!\n", 378 inodeb->inode_type); 379 goto failed_read1; 380 } 381 382 return 1; 383 384failed_read: 385 ERROR("Unable to read inode [%x:%x]\n", block, offset); 386 387failed_read1: 388 return 0; 389} 390 391 392static int get_dir_index_using_offset(struct super_block *s, long long 393 *next_block, unsigned int *next_offset, 394 long long index_start, 395 unsigned int index_offset, int i_count, 396 long long f_pos) 397{ 398 struct squashfs_sb_info *msblk = s->s_fs_info; 399 struct squashfs_super_block *sblk = &msblk->sblk; 400 int i, length = 0; 401 struct squashfs_dir_index_2 index; 402 403 TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n", 404 i_count, (unsigned int) f_pos); 405 406 if (f_pos == 0) 407 goto finish; 408 409 for (i = 0; i < i_count; i++) { 410 if (msblk->swap) { 411 struct squashfs_dir_index_2 sindex; 412 squashfs_get_cached_block(s, (char *) &sindex, 413 index_start, index_offset, 414 sizeof(sindex), &index_start, 415 &index_offset); 416 SQUASHFS_SWAP_DIR_INDEX_2(&index, &sindex); 417 } else 418 squashfs_get_cached_block(s, (char *) &index, 419 index_start, index_offset, 420 sizeof(index), &index_start, 421 &index_offset); 422 423 if (index.index > f_pos) 424 break; 425 426 squashfs_get_cached_block(s, NULL, index_start, index_offset, 427 index.size + 1, &index_start, 428 &index_offset); 429 430 length = index.index; 431 *next_block = index.start_block + sblk->directory_table_start; 432 } 433 434 *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; 435 436finish: 437 return length; 438} 439 440 441static int get_dir_index_using_name(struct super_block *s, long long 442 *next_block, unsigned int *next_offset, 443 long long index_start, 444 unsigned int index_offset, int i_count, 445 const char *name, int size) 446{ 447 struct squashfs_sb_info *msblk = s->s_fs_info; 448 struct squashfs_super_block *sblk = &msblk->sblk; 449 int i, length = 0; 450 struct squashfs_dir_index_2 *index; 451 char *str; 452 453 TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count); 454 455 if (!(str = kmalloc(sizeof(struct squashfs_dir_index) + 456 (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) { 457 ERROR("Failed to allocate squashfs_dir_index\n"); 458 goto failure; 459 } 460 461 index = (struct squashfs_dir_index_2 *) (str + SQUASHFS_NAME_LEN + 1); 462 strncpy(str, name, size); 463 str[size] = '\0'; 464 465 for (i = 0; i < i_count; i++) { 466 if (msblk->swap) { 467 struct squashfs_dir_index_2 sindex; 468 squashfs_get_cached_block(s, (char *) &sindex, 469 index_start, index_offset, 470 sizeof(sindex), &index_start, 471 &index_offset); 472 SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex); 473 } else 474 squashfs_get_cached_block(s, (char *) index, 475 index_start, index_offset, 476 sizeof(struct squashfs_dir_index_2), 477 &index_start, &index_offset); 478 479 squashfs_get_cached_block(s, index->name, index_start, 480 index_offset, index->size + 1, 481 &index_start, &index_offset); 482 483 index->name[index->size + 1] = '\0'; 484 485 if (strcmp(index->name, str) > 0) 486 break; 487 488 length = index->index; 489 *next_block = index->start_block + sblk->directory_table_start; 490 } 491 492 *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE; 493 kfree(str); 494failure: 495 return length; 496} 497 498 499static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir) 500{ 501 struct inode *i = file->f_dentry->d_inode; 502 struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; 503 struct squashfs_super_block *sblk = &msblk->sblk; 504 long long next_block = SQUASHFS_I(i)->start_block + 505 sblk->directory_table_start; 506 int next_offset = SQUASHFS_I(i)->offset, length = 0, 507 dir_count; 508 struct squashfs_dir_header_2 dirh; 509 struct squashfs_dir_entry_2 *dire; 510 511 TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset); 512 513 if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + 514 SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { 515 ERROR("Failed to allocate squashfs_dir_entry\n"); 516 goto finish; 517 } 518 519 length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset, 520 SQUASHFS_I(i)->u.s2.directory_index_start, 521 SQUASHFS_I(i)->u.s2.directory_index_offset, 522 SQUASHFS_I(i)->u.s2.directory_index_count, 523 file->f_pos); 524 525 while (length < i_size_read(i)) { 526 /* read directory header */ 527 if (msblk->swap) { 528 struct squashfs_dir_header_2 sdirh; 529 530 if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, 531 next_block, next_offset, sizeof(sdirh), 532 &next_block, &next_offset)) 533 goto failed_read; 534 535 length += sizeof(sdirh); 536 SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); 537 } else { 538 if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, 539 next_block, next_offset, sizeof(dirh), 540 &next_block, &next_offset)) 541 goto failed_read; 542 543 length += sizeof(dirh); 544 } 545 546 dir_count = dirh.count + 1; 547 while (dir_count--) { 548 if (msblk->swap) { 549 struct squashfs_dir_entry_2 sdire; 550 if (!squashfs_get_cached_block(i->i_sb, (char *) 551 &sdire, next_block, next_offset, 552 sizeof(sdire), &next_block, 553 &next_offset)) 554 goto failed_read; 555 556 length += sizeof(sdire); 557 SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); 558 } else { 559 if (!squashfs_get_cached_block(i->i_sb, (char *) 560 dire, next_block, next_offset, 561 sizeof(*dire), &next_block, 562 &next_offset)) 563 goto failed_read; 564 565 length += sizeof(*dire); 566 } 567 568 if (!squashfs_get_cached_block(i->i_sb, dire->name, 569 next_block, next_offset, 570 dire->size + 1, &next_block, 571 &next_offset)) 572 goto failed_read; 573 574 length += dire->size + 1; 575 576 if (file->f_pos >= length) 577 continue; 578 579 dire->name[dire->size + 1] = '\0'; 580 581 TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n", 582 (unsigned int) dirent, dire->name, 583 dire->size + 1, (int) file->f_pos, 584 dirh.start_block, dire->offset, 585 squashfs_filetype_table[dire->type]); 586 587 if (filldir(dirent, dire->name, dire->size + 1, 588 file->f_pos, SQUASHFS_MK_VFS_INODE( 589 dirh.start_block, dire->offset), 590 squashfs_filetype_table[dire->type]) 591 < 0) { 592 TRACE("Filldir returned less than 0\n"); 593 goto finish; 594 } 595 file->f_pos = length; 596 } 597 } 598 599finish: 600 kfree(dire); 601 return 0; 602 603failed_read: 604 ERROR("Unable to read directory block [%llx:%x]\n", next_block, 605 next_offset); 606 kfree(dire); 607 return 0; 608} 609 610 611static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry, 612 struct nameidata *nd) 613{ 614 const unsigned char *name = dentry->d_name.name; 615 int len = dentry->d_name.len; 616 struct inode *inode = NULL; 617 struct squashfs_sb_info *msblk = i->i_sb->s_fs_info; 618 struct squashfs_super_block *sblk = &msblk->sblk; 619 long long next_block = SQUASHFS_I(i)->start_block + 620 sblk->directory_table_start; 621 int next_offset = SQUASHFS_I(i)->offset, length = 0, 622 dir_count; 623 struct squashfs_dir_header_2 dirh; 624 struct squashfs_dir_entry_2 *dire; 625 int sorted = sblk->s_major == 2 && sblk->s_minor >= 1; 626 627 TRACE("Entered squashfs_lookup_2 [%llx:%x]\n", next_block, next_offset); 628 629 if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) + 630 SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) { 631 ERROR("Failed to allocate squashfs_dir_entry\n"); 632 goto exit_loop; 633 } 634 635 if (len > SQUASHFS_NAME_LEN) 636 goto exit_loop; 637 638 length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset, 639 SQUASHFS_I(i)->u.s2.directory_index_start, 640 SQUASHFS_I(i)->u.s2.directory_index_offset, 641 SQUASHFS_I(i)->u.s2.directory_index_count, name, 642 len); 643 644 while (length < i_size_read(i)) { 645 /* read directory header */ 646 if (msblk->swap) { 647 struct squashfs_dir_header_2 sdirh; 648 if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh, 649 next_block, next_offset, sizeof(sdirh), 650 &next_block, &next_offset)) 651 goto failed_read; 652 653 length += sizeof(sdirh); 654 SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh); 655 } else { 656 if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh, 657 next_block, next_offset, sizeof(dirh), 658 &next_block, &next_offset)) 659 goto failed_read; 660 661 length += sizeof(dirh); 662 } 663 664 dir_count = dirh.count + 1; 665 while (dir_count--) { 666 if (msblk->swap) { 667 struct squashfs_dir_entry_2 sdire; 668 if (!squashfs_get_cached_block(i->i_sb, (char *) 669 &sdire, next_block,next_offset, 670 sizeof(sdire), &next_block, 671 &next_offset)) 672 goto failed_read; 673 674 length += sizeof(sdire); 675 SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire); 676 } else { 677 if (!squashfs_get_cached_block(i->i_sb, (char *) 678 dire, next_block,next_offset, 679 sizeof(*dire), &next_block, 680 &next_offset)) 681 goto failed_read; 682 683 length += sizeof(*dire); 684 } 685 686 if (!squashfs_get_cached_block(i->i_sb, dire->name, 687 next_block, next_offset, dire->size + 1, 688 &next_block, &next_offset)) 689 goto failed_read; 690 691 length += dire->size + 1; 692 693 if (sorted && name[0] < dire->name[0]) 694 goto exit_loop; 695 696 if ((len == dire->size + 1) && !strncmp(name, 697 dire->name, len)) { 698 squashfs_inode_t ino = 699 SQUASHFS_MKINODE(dirh.start_block, 700 dire->offset); 701 unsigned int inode_number = SQUASHFS_MK_VFS_INODE(dirh.start_block, 702 dire->offset); 703 704 TRACE("calling squashfs_iget for directory " 705 "entry %s, inode %x:%x, %lld\n", name, 706 dirh.start_block, dire->offset, ino); 707 708 inode = squashfs_iget(i->i_sb, ino, inode_number); 709 710 goto exit_loop; 711 } 712 } 713 } 714 715exit_loop: 716 kfree(dire); 717 d_add(dentry, inode); 718 return ERR_PTR(0); 719 720failed_read: 721 ERROR("Unable to read directory block [%llx:%x]\n", next_block, 722 next_offset); 723 goto exit_loop; 724} 725 726 727int squashfs_2_0_supported(struct squashfs_sb_info *msblk) 728{ 729 struct squashfs_super_block *sblk = &msblk->sblk; 730 731 msblk->read_inode = squashfs_read_inode_2; 732 msblk->read_fragment_index_table = read_fragment_index_table_2; 733 734 sblk->bytes_used = sblk->bytes_used_2; 735 sblk->uid_start = sblk->uid_start_2; 736 sblk->guid_start = sblk->guid_start_2; 737 sblk->inode_table_start = sblk->inode_table_start_2; 738 sblk->directory_table_start = sblk->directory_table_start_2; 739 sblk->fragment_table_start = sblk->fragment_table_start_2; 740 741 return 1; 742} 743