2 * Squashfs - a compressed read only filesystem for Linux
4 * Copyright (c) 2002, 2003, 2004, 2005, 2006
5 * Phillip Lougher <phillip@lougher.demon.co.uk>
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.
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.
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.
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>
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>
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
);
46 static struct file_operations squashfs_dir_ops_2
= {
47 .read
= generic_read_dir
,
48 .readdir
= squashfs_readdir_2
51 static struct inode_operations squashfs_dir_inode_ops_2
= {
52 .lookup
= squashfs_lookup_2
55 static unsigned char squashfs_filetype_table
[] = {
56 DT_UNKNOWN
, DT_DIR
, DT_REG
, DT_LNK
, DT_BLK
, DT_CHR
, DT_FIFO
, DT_SOCK
59 static int read_fragment_index_table_2(struct super_block
*s
)
61 struct squashfs_sb_info
*msblk
= &s
->u
.squashfs_sb
;
62 struct squashfs_super_block
*sblk
= &msblk
->sblk
;
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");
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
76 SQUASHFS_COMPRESSED_BIT_BLOCK
, NULL
)) {
77 ERROR("unable to read fragment index table\n");
83 unsigned int fragment
;
85 for (i
= 0; i
< SQUASHFS_FRAGMENT_INDEXES_2(sblk
->fragments
);
87 SQUASHFS_SWAP_FRAGMENT_INDEXES_2((&fragment
),
88 &msblk
->fragment_index_2
[i
], 1);
89 msblk
->fragment_index_2
[i
] = fragment
;
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
)
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
;
108 struct squashfs_fragment_entry_2 sfragment_entry
;
110 if (!squashfs_get_cached_block(s
, (char *) &sfragment_entry
,
112 sizeof(sfragment_entry
), &start_block
,
115 SQUASHFS_SWAP_FRAGMENT_ENTRY_2(&fragment_entry
, &sfragment_entry
);
117 if (!squashfs_get_cached_block(s
, (char *) &fragment_entry
,
119 sizeof(fragment_entry
), &start_block
,
123 *fragment_start_block
= fragment_entry
.start_block
;
124 *fragment_size
= fragment_entry
.size
;
133 static struct inode
*squashfs_new_inode(struct super_block
*s
,
134 struct squashfs_base_inode_header_2
*inodeb
, unsigned int ino
)
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
);
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
;
149 if (inodeb
->guid
== SQUASHFS_GUIDS
)
152 i
->i_gid
= msblk
->guid
[inodeb
->guid
];
159 static struct inode
*squashfs_iget_2(struct super_block
*s
, squashfs_inode_t inode
)
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
;
175 TRACE("Entered squashfs_iget\n");
178 if (!squashfs_get_cached_block(s
, (char *) sinodeb
, block
,
179 offset
, sizeof(*sinodeb
), &next_block
,
182 SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb
, sinodeb
,
185 if (!squashfs_get_cached_block(s
, (char *) inodeb
, block
,
186 offset
, sizeof(*inodeb
), &next_block
,
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
;
195 unsigned int frag_size
;
198 if (!squashfs_get_cached_block(s
, (char *)
199 sinodep
, block
, offset
,
200 sizeof(*sinodep
), &next_block
,
203 SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep
, sinodep
);
205 if (!squashfs_get_cached_block(s
, (char *)
206 inodep
, block
, offset
,
207 sizeof(*inodep
), &next_block
,
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
))
217 if((i
= squashfs_new_inode(s
, inodeb
, ino
)) == NULL
)
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
;
237 i
->i_data
.a_ops
= &squashfs_aops_4K
;
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
,
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
;
251 if (!squashfs_get_cached_block(s
, (char *)
252 sinodep
, block
, offset
,
253 sizeof(*sinodep
), &next_block
,
256 SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep
, sinodep
);
258 if (!squashfs_get_cached_block(s
, (char *)
259 inodep
, block
, offset
,
260 sizeof(*inodep
), &next_block
,
264 if((i
= squashfs_new_inode(s
, inodeb
, ino
)) == NULL
)
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;
279 TRACE("Directory inode %x:%x, start_block %x, offset "
280 "%x\n", SQUASHFS_INODE_BLK(inode
),
281 offset
, inodep
->start_block
,
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
;
290 if (!squashfs_get_cached_block(s
, (char *)
291 sinodep
, block
, offset
,
292 sizeof(*sinodep
), &next_block
,
295 SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep
,
298 if (!squashfs_get_cached_block(s
, (char *)
299 inodep
, block
, offset
,
300 sizeof(*inodep
), &next_block
,
304 if((i
= squashfs_new_inode(s
, inodeb
, ino
)) == NULL
)
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
=
319 SQUASHFS_I(i
)->u
.s2
.directory_index_count
=
321 SQUASHFS_I(i
)->u
.s2
.parent_inode
= 0;
323 TRACE("Long directory inode %x:%x, start_block %x, "
325 SQUASHFS_INODE_BLK(inode
), offset
,
326 inodep
->start_block
, inodep
->offset
);
329 case SQUASHFS_SYMLINK_TYPE
: {
330 struct squashfs_symlink_inode_header_2
*inodep
=
332 struct squashfs_symlink_inode_header_2
*sinodep
=
336 if (!squashfs_get_cached_block(s
, (char *)
337 sinodep
, block
, offset
,
338 sizeof(*sinodep
), &next_block
,
341 SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep
,
344 if (!squashfs_get_cached_block(s
, (char *)
345 inodep
, block
, offset
,
346 sizeof(*inodep
), &next_block
,
350 if((i
= squashfs_new_inode(s
, inodeb
, ino
)) == NULL
)
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
;
360 TRACE("Symbolic link inode %x:%x, start_block %llx, "
362 SQUASHFS_INODE_BLK(inode
), offset
,
363 next_block
, next_offset
);
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
;
372 if (!squashfs_get_cached_block(s
, (char *)
373 sinodep
, block
, offset
,
374 sizeof(*sinodep
), &next_block
,
377 SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep
, sinodep
);
379 if (!squashfs_get_cached_block(s
, (char *)
380 inodep
, block
, offset
,
381 sizeof(*inodep
), &next_block
,
385 if ((i
= squashfs_new_inode(s
, inodeb
, ino
)) == NULL
)
388 i
->i_mode
|= (inodeb
->inode_type
==
389 SQUASHFS_CHRDEV_TYPE
) ? S_IFCHR
:
391 init_special_inode(i
, i
->i_mode
, inodep
->rdev
);
393 TRACE("Device inode %x:%x, rdev %x\n",
394 SQUASHFS_INODE_BLK(inode
), offset
,
398 case SQUASHFS_FIFO_TYPE
:
399 case SQUASHFS_SOCKET_TYPE
: {
400 if ((i
= squashfs_new_inode(s
, inodeb
, ino
)) == NULL
)
403 i
->i_mode
|= (inodeb
->inode_type
== SQUASHFS_FIFO_TYPE
)
404 ? S_IFIFO
: S_IFSOCK
;
405 init_special_inode(i
, i
->i_mode
, 0);
409 ERROR("Unknown inode type %d in squashfs_iget!\n",
414 insert_inode_hash(i
);
418 ERROR("Unable to read inode [%x:%x]\n", block
, offset
);
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
,
431 struct squashfs_sb_info
*msblk
= &s
->u
.squashfs_sb
;
432 struct squashfs_super_block
*sblk
= &msblk
->sblk
;
434 struct squashfs_dir_index_2 index
;
436 TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
437 i_count
, (unsigned int) f_pos
);
442 for (i
= 0; i
< i_count
; i
++) {
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
,
449 SQUASHFS_SWAP_DIR_INDEX_2(&index
, &sindex
);
451 squashfs_get_cached_block(s
, (char *) &index
,
452 index_start
, index_offset
,
453 sizeof(index
), &index_start
,
456 if (index
.index
> f_pos
)
459 squashfs_get_cached_block(s
, NULL
, index_start
, index_offset
,
460 index
.size
+ 1, &index_start
,
463 length
= index
.index
;
464 *next_block
= index
.start_block
+ sblk
->directory_table_start
;
467 *next_offset
= (length
+ *next_offset
) % SQUASHFS_METADATA_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
)
480 struct squashfs_sb_info
*msblk
= &s
->u
.squashfs_sb
;
481 struct squashfs_super_block
*sblk
= &msblk
->sblk
;
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];
487 TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count
);
489 strncpy(str
, name
, size
);
492 for (i
= 0; i
< i_count
; i
++) {
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
,
499 SQUASHFS_SWAP_DIR_INDEX_2(index
, &sindex
);
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
);
506 squashfs_get_cached_block(s
, index
->name
, index_start
,
507 index_offset
, index
->size
+ 1,
508 &index_start
, &index_offset
);
510 index
->name
[index
->size
+ 1] = '\0';
512 if (strcmp(index
->name
, str
) > 0)
515 length
= index
->index
;
516 *next_block
= index
->start_block
+ sblk
->directory_table_start
;
519 *next_offset
= (length
+ *next_offset
) % SQUASHFS_METADATA_SIZE
;
524 static int squashfs_readdir_2(struct file
*file
, void *dirent
, filldir_t filldir
)
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,
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
;
537 TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block
, next_offset
);
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
,
545 while (length
< i_size_read(i
)) {
546 /* read directory header */
548 struct squashfs_dir_header_2 sdirh
;
550 if (!squashfs_get_cached_block(i
->i_sb
, (char *) &sdirh
,
551 next_block
, next_offset
, sizeof(sdirh
),
552 &next_block
, &next_offset
))
555 length
+= sizeof(sdirh
);
556 SQUASHFS_SWAP_DIR_HEADER_2(&dirh
, &sdirh
);
558 if (!squashfs_get_cached_block(i
->i_sb
, (char *) &dirh
,
559 next_block
, next_offset
, sizeof(dirh
),
560 &next_block
, &next_offset
))
563 length
+= sizeof(dirh
);
566 dir_count
= dirh
.count
+ 1;
567 while (dir_count
--) {
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
,
576 length
+= sizeof(sdire
);
577 SQUASHFS_SWAP_DIR_ENTRY_2(dire
, &sdire
);
579 if (!squashfs_get_cached_block(i
->i_sb
, (char *)
580 dire
, next_block
, next_offset
,
581 sizeof(*dire
), &next_block
,
585 length
+= sizeof(*dire
);
588 if (!squashfs_get_cached_block(i
->i_sb
, dire
->name
,
589 next_block
, next_offset
,
590 dire
->size
+ 1, &next_block
,
594 length
+= dire
->size
+ 1;
596 if (file
->f_pos
>= length
)
599 dire
->name
[dire
->size
+ 1] = '\0';
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
]);
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
])
612 TRACE("Filldir returned less than 0\n");
615 file
->f_pos
= length
;
623 ERROR("Unable to read directory block [%llx:%x]\n", next_block
,
629 static struct dentry
*squashfs_lookup_2(struct inode
*i
, struct dentry
*dentry
)
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,
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;
645 TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block
, next_offset
);
647 if (len
> SQUASHFS_NAME_LEN
)
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
,
656 while (length
< i_size_read(i
)) {
657 /* read directory header */
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
))
665 length
+= sizeof(sdirh
);
666 SQUASHFS_SWAP_DIR_HEADER_2(&dirh
, &sdirh
);
668 if (!squashfs_get_cached_block(i
->i_sb
, (char *) &dirh
,
669 next_block
, next_offset
, sizeof(dirh
),
670 &next_block
, &next_offset
))
673 length
+= sizeof(dirh
);
676 dir_count
= dirh
.count
+ 1;
677 while (dir_count
--) {
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
,
686 length
+= sizeof(sdire
);
687 SQUASHFS_SWAP_DIR_ENTRY_2(dire
, &sdire
);
689 if (!squashfs_get_cached_block(i
->i_sb
, (char *)
690 dire
, next_block
,next_offset
,
691 sizeof(*dire
), &next_block
,
695 length
+= sizeof(*dire
);
698 if (!squashfs_get_cached_block(i
->i_sb
, dire
->name
,
699 next_block
, next_offset
, dire
->size
+ 1,
700 &next_block
, &next_offset
))
703 length
+= dire
->size
+ 1;
705 if (sorted
&& name
[0] < dire
->name
[0])
708 if ((len
== dire
->size
+ 1) && !strncmp(name
,
710 squashfs_inode_t ino
=
711 SQUASHFS_MKINODE(dirh
.start_block
,
714 TRACE("calling squashfs_iget for directory "
715 "entry %s, inode %x:%x, %d\n", name
,
716 dirh
.start_block
, dire
->offset
, ino
);
718 inode
= (msblk
->iget
)(i
->i_sb
, ino
);
726 d_add(dentry
, inode
);
730 ERROR("Unable to read directory block [%llx:%x]\n", next_block
,
736 int squashfs_2_0_supported(struct squashfs_sb_info
*msblk
)
738 struct squashfs_super_block
*sblk
= &msblk
->sblk
;
740 msblk
->iget
= squashfs_iget_2
;
741 msblk
->read_fragment_index_table
= read_fragment_index_table_2
;
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
;