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