• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 
read_fragment_index_table_2(struct super_block * s)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 
get_fragment_location_2(struct super_block * s,unsigned int fragment,long long * fragment_start_block,unsigned int * fragment_size)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 
squashfs_new_inode(struct super_block * s,struct squashfs_base_inode_header_2 * inodeb,unsigned int ino)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 
squashfs_iget_2(struct super_block * s,squashfs_inode_t inode)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 
get_dir_index_using_offset(struct super_block * s,long long * next_block,unsigned int * next_offset,long long index_start,unsigned int index_offset,int i_count,long long f_pos)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 
get_dir_index_using_name(struct super_block * s,long long * next_block,unsigned int * next_offset,long long index_start,unsigned int index_offset,int i_count,const char * name,int size)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 
squashfs_readdir_2(struct file * file,void * dirent,filldir_t filldir)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 
squashfs_lookup_2(struct inode * i,struct dentry * dentry)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 
squashfs_2_0_supported(struct squashfs_sb_info * msblk)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