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