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