1/*
2 * Squashfs - a compressed read only filesystem for Linux
3 *
4 * Copyright (c) 2002, 2003, 2004, 2005, 2006
5 * Phillip Lougher <phillip@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
43static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir);
44static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry);
45
46static struct file_operations squashfs_dir_ops_2 = {
47	.read = generic_read_dir,
48	.readdir = squashfs_readdir_2
49};
50
51static struct inode_operations squashfs_dir_inode_ops_2 = {
52	.lookup = squashfs_lookup_2
53};
54
55static unsigned char squashfs_filetype_table[] = {
56	DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
57};
58
59static 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
97static 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
128out:
129	return 0;
130}
131
132
133static 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
159static 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
417failed_read:
418	ERROR("Unable to read inode [%x:%x]\n", block, offset);
419
420failed_read1:
421	return NULL;
422}
423
424
425static 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
469finish:
470	return length;
471}
472
473
474static 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
524static 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
619finish:
620	return 0;
621
622failed_read:
623	ERROR("Unable to read directory block [%llx:%x]\n", next_block,
624		next_offset);
625	return 0;
626}
627
628
629static 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
725exit_loop:
726	d_add(dentry, inode);
727	return ERR_PTR(0);
728
729failed_read:
730	ERROR("Unable to read directory block [%llx:%x]\n", next_block,
731		next_offset);
732	goto exit_loop;
733}
734
735
736int 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