source: src/linux/universal/linux-4.9/fs/squashfs-dd/squashfs2_0.c @ 31630

Last change on this file since 31630 was 31630, checked in by brainslayer, 5 months ago

new fs is compatible with standard squashfs, just smaller

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