source: clfs-embedded/patches/linux-2.6.20-squashfs-1.patch@ c273052

Last change on this file since c273052 was 5956516, checked in by Jim Gifford <clfs@…>, 18 years ago

Started Updating for 2.6.20

  • Property mode set to 100644
File size: 123.3 KB
  • linux-2.6.19.

    diff -Nru linux-2.6.19.ori2/fs/Kconfig linux-2.6.19.ori/fs/Kconfig
    old new  
    14071407
    14081408          If unsure, say N.
    14091409
     1410config SQUASHFS
     1411        tristate "SquashFS 3.1 - Squashed file system support"
     1412        select ZLIB_INFLATE
     1413        help
     1414          Saying Y here includes support for SquashFS 3.1 (a Compressed Read-Only File
     1415          System).  Squashfs is a highly compressed read-only filesystem for Linux.
     1416          It uses zlib compression to compress both files, inodes and directories.
     1417          Inodes in the system are very small and all blocks are packed to minimise
     1418          data overhead. Block sizes greater than 4K are supported up to a maximum of 64K.
     1419          SquashFS 3.1 supports 64 bit filesystems and files (larger than 4GB), full
     1420          uid/gid information, hard links and timestamps.
     1421
     1422          Squashfs is intended for general read-only filesystem use, for archival
     1423          use (i.e. in cases where a .tar.gz file may be used), and in embedded
     1424          systems where low overhead is needed.  Further information and filesystem tools
     1425          are available from http://squashfs.sourceforge.net.
     1426
     1427          If you want to compile this as a module ( = code which can be
     1428          inserted in and removed from the running kernel whenever you want),
     1429          say M here and read <file:Documentation/modules.txt>.  The module
     1430          will be called squashfs.  Note that the root file system (the one
     1431          containing the directory /) cannot be compiled as a module.
     1432
     1433          If unsure, say N.
     1434
     1435config SQUASHFS_EMBEDDED
     1436
     1437        bool "Additional options for memory-constrained systems"
     1438        depends on SQUASHFS
     1439        default n
     1440        help
     1441          Saying Y here allows you to specify cache sizes and how Squashfs
     1442          allocates memory.  This is only intended for memory constrained
     1443          systems.
     1444
     1445          If unsure, say N.
     1446
     1447config SQUASHFS_FRAGMENT_CACHE_SIZE
     1448        int "Number of fragments cached" if SQUASHFS_EMBEDDED
     1449        depends on SQUASHFS
     1450        default "3"
     1451        help
     1452          By default SquashFS caches the last 3 fragments read from
     1453          the filesystem.  Increasing this amount may mean SquashFS
     1454          has to re-read fragments less often from disk, at the expense
     1455          of extra system memory.  Decreasing this amount will mean
     1456          SquashFS uses less memory at the expense of extra reads from disk.
     1457
     1458          Note there must be at least one cached fragment.  Anything
     1459          much more than three will probably not make much difference.
     1460
     1461config SQUASHFS_VMALLOC
     1462        bool "Use Vmalloc rather than Kmalloc" if SQUASHFS_EMBEDDED
     1463        depends on SQUASHFS
     1464        default n
     1465        help
     1466          By default SquashFS uses kmalloc to obtain fragment cache memory.
     1467          Kmalloc memory is the standard kernel allocator, but it can fail
     1468          on memory constrained systems.  Because of the way Vmalloc works,
     1469          Vmalloc can succeed when kmalloc fails.  Specifying this option
     1470          will make SquashFS always use Vmalloc to allocate the
     1471          fragment cache memory.
     1472
     1473          If unsure, say N.
     1474
    14101475config VXFS_FS
    14111476        tristate "FreeVxFS file system support (VERITAS VxFS(TM) compatible)"
    14121477        depends on BLOCK
  • linux-2.6.19.

    diff -Nru linux-2.6.19.ori2/fs/Makefile linux-2.6.19.ori/fs/Makefile
    old new  
    6767obj-$(CONFIG_JBD2)              += jbd2/
    6868obj-$(CONFIG_EXT2_FS)           += ext2/
    6969obj-$(CONFIG_CRAMFS)            += cramfs/
     70obj-$(CONFIG_SQUASHFS)          += squashfs/
    7071obj-$(CONFIG_RAMFS)             += ramfs/
    7172obj-$(CONFIG_HUGETLBFS)         += hugetlbfs/
    7273obj-$(CONFIG_CODA_FS)           += coda/
  • fs/squashfs/Makefile

    diff -Nru linux-2.6.19.ori2/fs/squashfs/Makefile linux-2.6.19.ori/fs/squashfs/Makefile
    old new  
     1#
     2# Makefile for the linux squashfs routines.
     3#
     4
     5obj-$(CONFIG_SQUASHFS) += squashfs.o
     6squashfs-y += inode.o
     7squashfs-y += squashfs2_0.o
  • fs/squashfs/inode.c

    diff -Nru linux-2.6.19.ori2/fs/squashfs/inode.c linux-2.6.19.ori/fs/squashfs/inode.c
    old new  
     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 * inode.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/blkdev.h>
     41#include <linux/vmalloc.h>
     42#include <asm/uaccess.h>
     43#include <asm/semaphore.h>
     44
     45#include "squashfs.h"
     46
     47static void squashfs_put_super(struct super_block *);
     48static int squashfs_statfs(struct dentry *, struct kstatfs *);
     49static int squashfs_symlink_readpage(struct file *file, struct page *page);
     50static int squashfs_readpage(struct file *file, struct page *page);
     51static int squashfs_readpage4K(struct file *file, struct page *page);
     52static int squashfs_readdir(struct file *, void *, filldir_t);
     53static struct inode *squashfs_alloc_inode(struct super_block *sb);
     54static void squashfs_destroy_inode(struct inode *inode);
     55static int init_inodecache(void);
     56static void destroy_inodecache(void);
     57static struct dentry *squashfs_lookup(struct inode *, struct dentry *,
     58                                struct nameidata *);
     59static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode);
     60static long long read_blocklist(struct inode *inode, int index,
     61                                int readahead_blks, char *block_list,
     62                                unsigned short **block_p, unsigned int *bsize);
     63static int squashfs_get_sb(struct file_system_type *, int, const char *, void *,
     64                                struct vfsmount *);
     65
     66static struct file_system_type squashfs_fs_type = {
     67        .owner = THIS_MODULE,
     68        .name = "squashfs",
     69        .get_sb = squashfs_get_sb,
     70        .kill_sb = kill_block_super,
     71        .fs_flags = FS_REQUIRES_DEV
     72};
     73
     74static unsigned char squashfs_filetype_table[] = {
     75        DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
     76};
     77
     78static struct super_operations squashfs_ops = {
     79        .alloc_inode = squashfs_alloc_inode,
     80        .destroy_inode = squashfs_destroy_inode,
     81        .statfs = squashfs_statfs,
     82        .put_super = squashfs_put_super,
     83};
     84
     85SQSH_EXTERN struct address_space_operations squashfs_symlink_aops = {
     86        .readpage = squashfs_symlink_readpage
     87};
     88
     89SQSH_EXTERN struct address_space_operations squashfs_aops = {
     90        .readpage = squashfs_readpage
     91};
     92
     93SQSH_EXTERN struct address_space_operations squashfs_aops_4K = {
     94        .readpage = squashfs_readpage4K
     95};
     96
     97static struct file_operations squashfs_dir_ops = {
     98        .read = generic_read_dir,
     99        .readdir = squashfs_readdir
     100};
     101
     102SQSH_EXTERN struct inode_operations squashfs_dir_inode_ops = {
     103        .lookup = squashfs_lookup
     104};
     105
     106
     107static struct buffer_head *get_block_length(struct super_block *s,
     108                                int *cur_index, int *offset, int *c_byte)
     109{
     110        struct squashfs_sb_info *msblk = s->s_fs_info;
     111        unsigned short temp;
     112        struct buffer_head *bh;
     113
     114        if (!(bh = sb_bread(s, *cur_index)))
     115                goto out;
     116
     117        if (msblk->devblksize - *offset == 1) {
     118                if (msblk->swap)
     119                        ((unsigned char *) &temp)[1] = *((unsigned char *)
     120                                (bh->b_data + *offset));
     121                else
     122                        ((unsigned char *) &temp)[0] = *((unsigned char *)
     123                                (bh->b_data + *offset));
     124                brelse(bh);
     125                if (!(bh = sb_bread(s, ++(*cur_index))))
     126                        goto out;
     127                if (msblk->swap)
     128                        ((unsigned char *) &temp)[0] = *((unsigned char *)
     129                                bh->b_data);
     130                else
     131                        ((unsigned char *) &temp)[1] = *((unsigned char *)
     132                                bh->b_data);
     133                *c_byte = temp;
     134                *offset = 1;
     135        } else {
     136                if (msblk->swap) {
     137                        ((unsigned char *) &temp)[1] = *((unsigned char *)
     138                                (bh->b_data + *offset));
     139                        ((unsigned char *) &temp)[0] = *((unsigned char *)
     140                                (bh->b_data + *offset + 1));
     141                } else {
     142                        ((unsigned char *) &temp)[0] = *((unsigned char *)
     143                                (bh->b_data + *offset));
     144                        ((unsigned char *) &temp)[1] = *((unsigned char *)
     145                                (bh->b_data + *offset + 1));
     146                }
     147                *c_byte = temp;
     148                *offset += 2;
     149        }
     150
     151        if (SQUASHFS_CHECK_DATA(msblk->sblk.flags)) {
     152                if (*offset == msblk->devblksize) {
     153                        brelse(bh);
     154                        if (!(bh = sb_bread(s, ++(*cur_index))))
     155                                goto out;
     156                        *offset = 0;
     157                }
     158                if (*((unsigned char *) (bh->b_data + *offset)) !=
     159                                                SQUASHFS_MARKER_BYTE) {
     160                        ERROR("Metadata block marker corrupt @ %x\n",
     161                                                *cur_index);
     162                        brelse(bh);
     163                        goto out;
     164                }
     165                (*offset)++;
     166        }
     167        return bh;
     168
     169out:
     170        return NULL;
     171}
     172
     173
     174SQSH_EXTERN unsigned int squashfs_read_data(struct super_block *s, char *buffer,
     175                        long long index, unsigned int length,
     176                        long long *next_index)
     177{
     178        struct squashfs_sb_info *msblk = s->s_fs_info;
     179        struct buffer_head *bh[((SQUASHFS_FILE_MAX_SIZE - 1) >>
     180                        msblk->devblksize_log2) + 2];
     181        unsigned int offset = index & ((1 << msblk->devblksize_log2) - 1);
     182        unsigned int cur_index = index >> msblk->devblksize_log2;
     183        int bytes, avail_bytes, b = 0, k;
     184        char *c_buffer;
     185        unsigned int compressed;
     186        unsigned int c_byte = length;
     187
     188        if (c_byte) {
     189                bytes = msblk->devblksize - offset;
     190                compressed = SQUASHFS_COMPRESSED_BLOCK(c_byte);
     191                c_buffer = compressed ? msblk->read_data : buffer;
     192                c_byte = SQUASHFS_COMPRESSED_SIZE_BLOCK(c_byte);
     193
     194                TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
     195                                        ? "" : "un", (unsigned int) c_byte);
     196
     197                if (!(bh[0] = sb_getblk(s, cur_index)))
     198                        goto block_release;
     199
     200                for (b = 1; bytes < c_byte; b++) {
     201                        if (!(bh[b] = sb_getblk(s, ++cur_index)))
     202                                goto block_release;
     203                        bytes += msblk->devblksize;
     204                }
     205                ll_rw_block(READ, b, bh);
     206        } else {
     207                if (!(bh[0] = get_block_length(s, &cur_index, &offset,
     208                                                                &c_byte)))
     209                        goto read_failure;
     210
     211                bytes = msblk->devblksize - offset;
     212                compressed = SQUASHFS_COMPRESSED(c_byte);
     213                c_buffer = compressed ? msblk->read_data : buffer;
     214                c_byte = SQUASHFS_COMPRESSED_SIZE(c_byte);
     215
     216                TRACE("Block @ 0x%llx, %scompressed size %d\n", index, compressed
     217                                        ? "" : "un", (unsigned int) c_byte);
     218
     219                for (b = 1; bytes < c_byte; b++) {
     220                        if (!(bh[b] = sb_getblk(s, ++cur_index)))
     221                                goto block_release;
     222                        bytes += msblk->devblksize;
     223                }
     224                ll_rw_block(READ, b - 1, bh + 1);
     225        }
     226
     227        if (compressed)
     228                down(&msblk->read_data_mutex);
     229
     230        for (bytes = 0, k = 0; k < b; k++) {
     231                avail_bytes = (c_byte - bytes) > (msblk->devblksize - offset) ?
     232                                        msblk->devblksize - offset :
     233                                        c_byte - bytes;
     234                wait_on_buffer(bh[k]);
     235                if (!buffer_uptodate(bh[k]))
     236                        goto block_release;
     237                memcpy(c_buffer + bytes, bh[k]->b_data + offset, avail_bytes);
     238                bytes += avail_bytes;
     239                offset = 0;
     240                brelse(bh[k]);
     241        }
     242
     243        /*
     244         * uncompress block
     245         */
     246        if (compressed) {
     247                int zlib_err;
     248
     249                msblk->stream.next_in = c_buffer;
     250                msblk->stream.avail_in = c_byte;
     251                msblk->stream.next_out = buffer;
     252                msblk->stream.avail_out = msblk->read_size;
     253
     254                if (((zlib_err = zlib_inflateInit(&msblk->stream)) != Z_OK) ||
     255                                ((zlib_err = zlib_inflate(&msblk->stream, Z_FINISH))
     256                                 != Z_STREAM_END) || ((zlib_err =
     257                                zlib_inflateEnd(&msblk->stream)) != Z_OK)) {
     258                        ERROR("zlib_fs returned unexpected result 0x%x\n",
     259                                zlib_err);
     260                        bytes = 0;
     261                } else
     262                        bytes = msblk->stream.total_out;
     263               
     264                up(&msblk->read_data_mutex);
     265        }
     266
     267        if (next_index)
     268                *next_index = index + c_byte + (length ? 0 :
     269                                (SQUASHFS_CHECK_DATA(msblk->sblk.flags)
     270                                 ? 3 : 2));
     271        return bytes;
     272
     273block_release:
     274        while (--b >= 0)
     275                brelse(bh[b]);
     276
     277read_failure:
     278        ERROR("sb_bread failed reading block 0x%x\n", cur_index);
     279        return 0;
     280}
     281
     282
     283SQSH_EXTERN int squashfs_get_cached_block(struct super_block *s, char *buffer,
     284                                long long block, unsigned int offset,
     285                                int length, long long *next_block,
     286                                unsigned int *next_offset)
     287{
     288        struct squashfs_sb_info *msblk = s->s_fs_info;
     289        int n, i, bytes, return_length = length;
     290        long long next_index;
     291
     292        TRACE("Entered squashfs_get_cached_block [%llx:%x]\n", block, offset);
     293
     294        while ( 1 ) {
     295                for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
     296                        if (msblk->block_cache[i].block == block)
     297                                break;
     298               
     299                down(&msblk->block_cache_mutex);
     300
     301                if (i == SQUASHFS_CACHED_BLKS) {
     302                        /* read inode header block */
     303                        for (i = msblk->next_cache, n = SQUASHFS_CACHED_BLKS;
     304                                        n ; n --, i = (i + 1) %
     305                                        SQUASHFS_CACHED_BLKS)
     306                                if (msblk->block_cache[i].block !=
     307                                                        SQUASHFS_USED_BLK)
     308                                        break;
     309
     310                        if (n == 0) {
     311                                wait_queue_t wait;
     312
     313                                init_waitqueue_entry(&wait, current);
     314                                add_wait_queue(&msblk->waitq, &wait);
     315                                set_current_state(TASK_UNINTERRUPTIBLE);
     316                                up(&msblk->block_cache_mutex);
     317                                schedule();
     318                                set_current_state(TASK_RUNNING);
     319                                remove_wait_queue(&msblk->waitq, &wait);
     320                                continue;
     321                        }
     322                        msblk->next_cache = (i + 1) % SQUASHFS_CACHED_BLKS;
     323
     324                        if (msblk->block_cache[i].block ==
     325                                                        SQUASHFS_INVALID_BLK) {
     326                                if (!(msblk->block_cache[i].data =
     327                                                kmalloc(SQUASHFS_METADATA_SIZE,
     328                                                GFP_KERNEL))) {
     329                                        ERROR("Failed to allocate cache"
     330                                                        "block\n");
     331                                        up(&msblk->block_cache_mutex);
     332                                        goto out;
     333                                }
     334                        }
     335       
     336                        msblk->block_cache[i].block = SQUASHFS_USED_BLK;
     337                        up(&msblk->block_cache_mutex);
     338
     339                        if (!(msblk->block_cache[i].length =
     340                                                squashfs_read_data(s,
     341                                                msblk->block_cache[i].data,
     342                                                block, 0, &next_index))) {
     343                                ERROR("Unable to read cache block [%llx:%x]\n",
     344                                                block, offset);
     345                                goto out;
     346                        }
     347
     348                        down(&msblk->block_cache_mutex);
     349                        wake_up(&msblk->waitq);
     350                        msblk->block_cache[i].block = block;
     351                        msblk->block_cache[i].next_index = next_index;
     352                        TRACE("Read cache block [%llx:%x]\n", block, offset);
     353                }
     354
     355                if (msblk->block_cache[i].block != block) {
     356                        up(&msblk->block_cache_mutex);
     357                        continue;
     358                }
     359
     360                if ((bytes = msblk->block_cache[i].length - offset) >= length) {
     361                        if (buffer)
     362                                memcpy(buffer, msblk->block_cache[i].data +
     363                                                offset, length);
     364                        if (msblk->block_cache[i].length - offset == length) {
     365                                *next_block = msblk->block_cache[i].next_index;
     366                                *next_offset = 0;
     367                        } else {
     368                                *next_block = block;
     369                                *next_offset = offset + length;
     370                        }
     371                        up(&msblk->block_cache_mutex);
     372                        goto finish;
     373                } else {
     374                        if (buffer) {
     375                                memcpy(buffer, msblk->block_cache[i].data +
     376                                                offset, bytes);
     377                                buffer += bytes;
     378                        }
     379                        block = msblk->block_cache[i].next_index;
     380                        up(&msblk->block_cache_mutex);
     381                        length -= bytes;
     382                        offset = 0;
     383                }
     384        }
     385
     386finish:
     387        return return_length;
     388out:
     389        return 0;
     390}
     391
     392
     393static int get_fragment_location(struct super_block *s, unsigned int fragment,
     394                                long long *fragment_start_block,
     395                                unsigned int *fragment_size)
     396{
     397        struct squashfs_sb_info *msblk = s->s_fs_info;
     398        long long start_block =
     399                msblk->fragment_index[SQUASHFS_FRAGMENT_INDEX(fragment)];
     400        int offset = SQUASHFS_FRAGMENT_INDEX_OFFSET(fragment);
     401        struct squashfs_fragment_entry fragment_entry;
     402
     403        if (msblk->swap) {
     404                struct squashfs_fragment_entry sfragment_entry;
     405
     406                if (!squashfs_get_cached_block(s, (char *) &sfragment_entry,
     407                                        start_block, offset,
     408                                        sizeof(sfragment_entry), &start_block,
     409                                        &offset))
     410                        goto out;
     411                SQUASHFS_SWAP_FRAGMENT_ENTRY(&fragment_entry, &sfragment_entry);
     412        } else
     413                if (!squashfs_get_cached_block(s, (char *) &fragment_entry,
     414                                        start_block, offset,
     415                                        sizeof(fragment_entry), &start_block,
     416                                        &offset))
     417                        goto out;
     418
     419        *fragment_start_block = fragment_entry.start_block;
     420        *fragment_size = fragment_entry.size;
     421
     422        return 1;
     423
     424out:
     425        return 0;
     426}
     427
     428
     429SQSH_EXTERN void release_cached_fragment(struct squashfs_sb_info *msblk, struct
     430                                        squashfs_fragment_cache *fragment)
     431{
     432        down(&msblk->fragment_mutex);
     433        fragment->locked --;
     434        wake_up(&msblk->fragment_wait_queue);
     435        up(&msblk->fragment_mutex);
     436}
     437
     438
     439SQSH_EXTERN struct squashfs_fragment_cache *get_cached_fragment(struct super_block
     440                                        *s, long long start_block,
     441                                        int length)
     442{
     443        int i, n;
     444        struct squashfs_sb_info *msblk = s->s_fs_info;
     445
     446        while ( 1 ) {
     447                down(&msblk->fragment_mutex);
     448
     449                for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS &&
     450                                msblk->fragment[i].block != start_block; i++);
     451
     452                if (i == SQUASHFS_CACHED_FRAGMENTS) {
     453                        for (i = msblk->next_fragment, n =
     454                                SQUASHFS_CACHED_FRAGMENTS; n &&
     455                                msblk->fragment[i].locked; n--, i = (i + 1) %
     456                                SQUASHFS_CACHED_FRAGMENTS);
     457
     458                        if (n == 0) {
     459                                wait_queue_t wait;
     460
     461                                init_waitqueue_entry(&wait, current);
     462                                add_wait_queue(&msblk->fragment_wait_queue,
     463                                                                        &wait);
     464                                set_current_state(TASK_UNINTERRUPTIBLE);
     465                                up(&msblk->fragment_mutex);
     466                                schedule();
     467                                set_current_state(TASK_RUNNING);
     468                                remove_wait_queue(&msblk->fragment_wait_queue,
     469                                                                        &wait);
     470                                continue;
     471                        }
     472                        msblk->next_fragment = (msblk->next_fragment + 1) %
     473                                SQUASHFS_CACHED_FRAGMENTS;
     474                       
     475                        if (msblk->fragment[i].data == NULL)
     476                                if (!(msblk->fragment[i].data = SQUASHFS_ALLOC
     477                                                (SQUASHFS_FILE_MAX_SIZE))) {
     478                                        ERROR("Failed to allocate fragment "
     479                                                        "cache block\n");
     480                                        up(&msblk->fragment_mutex);
     481                                        goto out;
     482                                }
     483
     484                        msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
     485                        msblk->fragment[i].locked = 1;
     486                        up(&msblk->fragment_mutex);
     487
     488                        if (!(msblk->fragment[i].length = squashfs_read_data(s,
     489                                                msblk->fragment[i].data,
     490                                                start_block, length, NULL))) {
     491                                ERROR("Unable to read fragment cache block "
     492                                                        "[%llx]\n", start_block);
     493                                msblk->fragment[i].locked = 0;
     494                                goto out;
     495                        }
     496
     497                        msblk->fragment[i].block = start_block;
     498                        TRACE("New fragment %d, start block %lld, locked %d\n",
     499                                                i, msblk->fragment[i].block,
     500                                                msblk->fragment[i].locked);
     501                        break;
     502                }
     503
     504                msblk->fragment[i].locked++;
     505                up(&msblk->fragment_mutex);
     506                TRACE("Got fragment %d, start block %lld, locked %d\n", i,
     507                                                msblk->fragment[i].block,
     508                                                msblk->fragment[i].locked);
     509                break;
     510        }
     511
     512        return &msblk->fragment[i];
     513
     514out:
     515        return NULL;
     516}
     517
     518
     519static struct inode *squashfs_new_inode(struct super_block *s,
     520                struct squashfs_base_inode_header *inodeb)
     521{
     522        struct squashfs_sb_info *msblk = s->s_fs_info;
     523        struct inode *i = new_inode(s);
     524
     525        if (i) {
     526                i->i_ino = inodeb->inode_number;
     527                i->i_mtime.tv_sec = inodeb->mtime;
     528                i->i_atime.tv_sec = inodeb->mtime;
     529                i->i_ctime.tv_sec = inodeb->mtime;
     530                i->i_uid = msblk->uid[inodeb->uid];
     531                i->i_mode = inodeb->mode;
     532                i->i_size = 0;
     533                if (inodeb->guid == SQUASHFS_GUIDS)
     534                        i->i_gid = i->i_uid;
     535                else
     536                        i->i_gid = msblk->guid[inodeb->guid];
     537        }
     538
     539        return i;
     540}
     541
     542
     543static struct inode *squashfs_iget(struct super_block *s, squashfs_inode_t inode)
     544{
     545        struct inode *i;
     546        struct squashfs_sb_info *msblk = s->s_fs_info;
     547        struct squashfs_super_block *sblk = &msblk->sblk;
     548        long long block = SQUASHFS_INODE_BLK(inode) +
     549                sblk->inode_table_start;
     550        unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
     551        long long next_block;
     552        unsigned int next_offset;
     553        union squashfs_inode_header id, sid;
     554        struct squashfs_base_inode_header *inodeb = &id.base,
     555                                          *sinodeb = &sid.base;
     556
     557        TRACE("Entered squashfs_iget\n");
     558
     559        if (msblk->swap) {
     560                if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
     561                                        offset, sizeof(*sinodeb), &next_block,
     562                                        &next_offset))
     563                        goto failed_read;
     564                SQUASHFS_SWAP_BASE_INODE_HEADER(inodeb, sinodeb,
     565                                        sizeof(*sinodeb));
     566        } else
     567                if (!squashfs_get_cached_block(s, (char *) inodeb, block,
     568                                        offset, sizeof(*inodeb), &next_block,
     569                                        &next_offset))
     570                        goto failed_read;
     571
     572        switch(inodeb->inode_type) {
     573                case SQUASHFS_FILE_TYPE: {
     574                        unsigned int frag_size;
     575                        long long frag_blk;
     576                        struct squashfs_reg_inode_header *inodep = &id.reg;
     577                        struct squashfs_reg_inode_header *sinodep = &sid.reg;
     578                               
     579                        if (msblk->swap) {
     580                                if (!squashfs_get_cached_block(s, (char *)
     581                                                sinodep, block, offset,
     582                                                sizeof(*sinodep), &next_block,
     583                                                &next_offset))
     584                                        goto failed_read;
     585                                SQUASHFS_SWAP_REG_INODE_HEADER(inodep, sinodep);
     586                        } else
     587                                if (!squashfs_get_cached_block(s, (char *)
     588                                                inodep, block, offset,
     589                                                sizeof(*inodep), &next_block,
     590                                                &next_offset))
     591                                        goto failed_read;
     592
     593                        frag_blk = SQUASHFS_INVALID_BLK;
     594                        if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
     595                                        !get_fragment_location(s,
     596                                        inodep->fragment, &frag_blk, &frag_size))
     597                                goto failed_read;
     598                               
     599                        if((i = squashfs_new_inode(s, inodeb)) == NULL)
     600                                goto failed_read1;
     601
     602                        i->i_nlink = 1;
     603                        i->i_size = inodep->file_size;
     604                        i->i_fop = &generic_ro_fops;
     605                        i->i_mode |= S_IFREG;
     606                        i->i_blocks = ((i->i_size - 1) >> 9) + 1;
     607                        SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
     608                        SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
     609                        SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
     610                        SQUASHFS_I(i)->start_block = inodep->start_block;
     611                        SQUASHFS_I(i)->u.s1.block_list_start = next_block;
     612                        SQUASHFS_I(i)->offset = next_offset;
     613                        if (sblk->block_size > 4096)
     614                                i->i_data.a_ops = &squashfs_aops;
     615                        else
     616                                i->i_data.a_ops = &squashfs_aops_4K;
     617
     618                        TRACE("File inode %x:%x, start_block %llx, "
     619                                        "block_list_start %llx, offset %x\n",
     620                                        SQUASHFS_INODE_BLK(inode), offset,
     621                                        inodep->start_block, next_block,
     622                                        next_offset);
     623                        break;
     624                }
     625                case SQUASHFS_LREG_TYPE: {
     626                        unsigned int frag_size;
     627                        long long frag_blk;
     628                        struct squashfs_lreg_inode_header *inodep = &id.lreg;
     629                        struct squashfs_lreg_inode_header *sinodep = &sid.lreg;
     630                               
     631                        if (msblk->swap) {
     632                                if (!squashfs_get_cached_block(s, (char *)
     633                                                sinodep, block, offset,
     634                                                sizeof(*sinodep), &next_block,
     635                                                &next_offset))
     636                                        goto failed_read;
     637                                SQUASHFS_SWAP_LREG_INODE_HEADER(inodep, sinodep);
     638                        } else
     639                                if (!squashfs_get_cached_block(s, (char *)
     640                                                inodep, block, offset,
     641                                                sizeof(*inodep), &next_block,
     642                                                &next_offset))
     643                                        goto failed_read;
     644
     645                        frag_blk = SQUASHFS_INVALID_BLK;
     646                        if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
     647                                        !get_fragment_location(s,
     648                                        inodep->fragment, &frag_blk, &frag_size))
     649                                goto failed_read;
     650                               
     651                        if((i = squashfs_new_inode(s, inodeb)) == NULL)
     652                                goto failed_read1;
     653
     654                        i->i_nlink = inodep->nlink;
     655                        i->i_size = inodep->file_size;
     656                        i->i_fop = &generic_ro_fops;
     657                        i->i_mode |= S_IFREG;
     658                        i->i_blocks = ((i->i_size - 1) >> 9) + 1;
     659                        SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
     660                        SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
     661                        SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
     662                        SQUASHFS_I(i)->start_block = inodep->start_block;
     663                        SQUASHFS_I(i)->u.s1.block_list_start = next_block;
     664                        SQUASHFS_I(i)->offset = next_offset;
     665                        if (sblk->block_size > 4096)
     666                                i->i_data.a_ops = &squashfs_aops;
     667                        else
     668                                i->i_data.a_ops = &squashfs_aops_4K;
     669
     670                        TRACE("File inode %x:%x, start_block %llx, "
     671                                        "block_list_start %llx, offset %x\n",
     672                                        SQUASHFS_INODE_BLK(inode), offset,
     673                                        inodep->start_block, next_block,
     674                                        next_offset);
     675                        break;
     676                }
     677                case SQUASHFS_DIR_TYPE: {
     678                        struct squashfs_dir_inode_header *inodep = &id.dir;
     679                        struct squashfs_dir_inode_header *sinodep = &sid.dir;
     680
     681                        if (msblk->swap) {
     682                                if (!squashfs_get_cached_block(s, (char *)
     683                                                sinodep, block, offset,
     684                                                sizeof(*sinodep), &next_block,
     685                                                &next_offset))
     686                                        goto failed_read;
     687                                SQUASHFS_SWAP_DIR_INODE_HEADER(inodep, sinodep);
     688                        } else
     689                                if (!squashfs_get_cached_block(s, (char *)
     690                                                inodep, block, offset,
     691                                                sizeof(*inodep), &next_block,
     692                                                &next_offset))
     693                                        goto failed_read;
     694
     695                        if((i = squashfs_new_inode(s, inodeb)) == NULL)
     696                                goto failed_read1;
     697
     698                        i->i_nlink = inodep->nlink;
     699                        i->i_size = inodep->file_size;
     700                        i->i_op = &squashfs_dir_inode_ops;
     701                        i->i_fop = &squashfs_dir_ops;
     702                        i->i_mode |= S_IFDIR;
     703                        SQUASHFS_I(i)->start_block = inodep->start_block;
     704                        SQUASHFS_I(i)->offset = inodep->offset;
     705                        SQUASHFS_I(i)->u.s2.directory_index_count = 0;
     706                        SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
     707
     708                        TRACE("Directory inode %x:%x, start_block %x, offset "
     709                                        "%x\n", SQUASHFS_INODE_BLK(inode),
     710                                        offset, inodep->start_block,
     711                                        inodep->offset);
     712                        break;
     713                }
     714                case SQUASHFS_LDIR_TYPE: {
     715                        struct squashfs_ldir_inode_header *inodep = &id.ldir;
     716                        struct squashfs_ldir_inode_header *sinodep = &sid.ldir;
     717
     718                        if (msblk->swap) {
     719                                if (!squashfs_get_cached_block(s, (char *)
     720                                                sinodep, block, offset,
     721                                                sizeof(*sinodep), &next_block,
     722                                                &next_offset))
     723                                        goto failed_read;
     724                                SQUASHFS_SWAP_LDIR_INODE_HEADER(inodep,
     725                                                sinodep);
     726                        } else
     727                                if (!squashfs_get_cached_block(s, (char *)
     728                                                inodep, block, offset,
     729                                                sizeof(*inodep), &next_block,
     730                                                &next_offset))
     731                                        goto failed_read;
     732
     733                        if((i = squashfs_new_inode(s, inodeb)) == NULL)
     734                                goto failed_read1;
     735
     736                        i->i_nlink = inodep->nlink;
     737                        i->i_size = inodep->file_size;
     738                        i->i_op = &squashfs_dir_inode_ops;
     739                        i->i_fop = &squashfs_dir_ops;
     740                        i->i_mode |= S_IFDIR;
     741                        SQUASHFS_I(i)->start_block = inodep->start_block;
     742                        SQUASHFS_I(i)->offset = inodep->offset;
     743                        SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
     744                        SQUASHFS_I(i)->u.s2.directory_index_offset =
     745                                                                next_offset;
     746                        SQUASHFS_I(i)->u.s2.directory_index_count =
     747                                                                inodep->i_count;
     748                        SQUASHFS_I(i)->u.s2.parent_inode = inodep->parent_inode;
     749
     750                        TRACE("Long directory inode %x:%x, start_block %x, "
     751                                        "offset %x\n",
     752                                        SQUASHFS_INODE_BLK(inode), offset,
     753                                        inodep->start_block, inodep->offset);
     754                        break;
     755                }
     756                case SQUASHFS_SYMLINK_TYPE: {
     757                        struct squashfs_symlink_inode_header *inodep =
     758                                                                &id.symlink;
     759                        struct squashfs_symlink_inode_header *sinodep =
     760                                                                &sid.symlink;
     761       
     762                        if (msblk->swap) {
     763                                if (!squashfs_get_cached_block(s, (char *)
     764                                                sinodep, block, offset,
     765                                                sizeof(*sinodep), &next_block,
     766                                                &next_offset))
     767                                        goto failed_read;
     768                                SQUASHFS_SWAP_SYMLINK_INODE_HEADER(inodep,
     769                                                                sinodep);
     770                        } else
     771                                if (!squashfs_get_cached_block(s, (char *)
     772                                                inodep, block, offset,
     773                                                sizeof(*inodep), &next_block,
     774                                                &next_offset))
     775                                        goto failed_read;
     776
     777                        if((i = squashfs_new_inode(s, inodeb)) == NULL)
     778                                goto failed_read1;
     779
     780                        i->i_nlink = inodep->nlink;
     781                        i->i_size = inodep->symlink_size;
     782                        i->i_op = &page_symlink_inode_operations;
     783                        i->i_data.a_ops = &squashfs_symlink_aops;
     784                        i->i_mode |= S_IFLNK;
     785                        SQUASHFS_I(i)->start_block = next_block;
     786                        SQUASHFS_I(i)->offset = next_offset;
     787
     788                        TRACE("Symbolic link inode %x:%x, start_block %llx, "
     789                                        "offset %x\n",
     790                                        SQUASHFS_INODE_BLK(inode), offset,
     791                                        next_block, next_offset);
     792                        break;
     793                 }
     794                 case SQUASHFS_BLKDEV_TYPE:
     795                 case SQUASHFS_CHRDEV_TYPE: {
     796                        struct squashfs_dev_inode_header *inodep = &id.dev;
     797                        struct squashfs_dev_inode_header *sinodep = &sid.dev;
     798
     799                        if (msblk->swap) {
     800                                if (!squashfs_get_cached_block(s, (char *)
     801                                                sinodep, block, offset,
     802                                                sizeof(*sinodep), &next_block,
     803                                                &next_offset))
     804                                        goto failed_read;
     805                                SQUASHFS_SWAP_DEV_INODE_HEADER(inodep, sinodep);
     806                        } else 
     807                                if (!squashfs_get_cached_block(s, (char *)
     808                                                inodep, block, offset,
     809                                                sizeof(*inodep), &next_block,
     810                                                &next_offset))
     811                                        goto failed_read;
     812
     813                        if ((i = squashfs_new_inode(s, inodeb)) == NULL)
     814                                goto failed_read1;
     815
     816                        i->i_nlink = inodep->nlink;
     817                        i->i_mode |= (inodeb->inode_type ==
     818                                        SQUASHFS_CHRDEV_TYPE) ?  S_IFCHR :
     819                                        S_IFBLK;
     820                        init_special_inode(i, i->i_mode,
     821                                        old_decode_dev(inodep->rdev));
     822
     823                        TRACE("Device inode %x:%x, rdev %x\n",
     824                                        SQUASHFS_INODE_BLK(inode), offset,
     825                                        inodep->rdev);
     826                        break;
     827                 }
     828                 case SQUASHFS_FIFO_TYPE:
     829                 case SQUASHFS_SOCKET_TYPE: {
     830                        struct squashfs_ipc_inode_header *inodep = &id.ipc;
     831                        struct squashfs_ipc_inode_header *sinodep = &sid.ipc;
     832
     833                        if (msblk->swap) {
     834                                if (!squashfs_get_cached_block(s, (char *)
     835                                                sinodep, block, offset,
     836                                                sizeof(*sinodep), &next_block,
     837                                                &next_offset))
     838                                        goto failed_read;
     839                                SQUASHFS_SWAP_IPC_INODE_HEADER(inodep, sinodep);
     840                        } else 
     841                                if (!squashfs_get_cached_block(s, (char *)
     842                                                inodep, block, offset,
     843                                                sizeof(*inodep), &next_block,
     844                                                &next_offset))
     845                                        goto failed_read;
     846
     847                        if ((i = squashfs_new_inode(s, inodeb)) == NULL)
     848                                goto failed_read1;
     849
     850                        i->i_nlink = inodep->nlink;
     851                        i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
     852                                                        ? S_IFIFO : S_IFSOCK;
     853                        init_special_inode(i, i->i_mode, 0);
     854                        break;
     855                 }
     856                 default:
     857                        ERROR("Unknown inode type %d in squashfs_iget!\n",
     858                                        inodeb->inode_type);
     859                        goto failed_read1;
     860        }
     861       
     862        insert_inode_hash(i);
     863        return i;
     864
     865failed_read:
     866        ERROR("Unable to read inode [%llx:%x]\n", block, offset);
     867
     868failed_read1:
     869        return NULL;
     870}
     871
     872
     873static int read_fragment_index_table(struct super_block *s)
     874{
     875        struct squashfs_sb_info *msblk = s->s_fs_info;
     876        struct squashfs_super_block *sblk = &msblk->sblk;
     877
     878        /* Allocate fragment index table */
     879        if (!(msblk->fragment_index = kmalloc(SQUASHFS_FRAGMENT_INDEX_BYTES
     880                                        (sblk->fragments), GFP_KERNEL))) {
     881                ERROR("Failed to allocate uid/gid table\n");
     882                return 0;
     883        }
     884   
     885        if (SQUASHFS_FRAGMENT_INDEX_BYTES(sblk->fragments) &&
     886                                        !squashfs_read_data(s, (char *)
     887                                        msblk->fragment_index,
     888                                        sblk->fragment_table_start,
     889                                        SQUASHFS_FRAGMENT_INDEX_BYTES
     890                                        (sblk->fragments) |
     891                                        SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
     892                ERROR("unable to read fragment index table\n");
     893                return 0;
     894        }
     895
     896        if (msblk->swap) {
     897                int i;
     898                long long fragment;
     899
     900                for (i = 0; i < SQUASHFS_FRAGMENT_INDEXES(sblk->fragments);
     901                                                                        i++) {
     902                        SQUASHFS_SWAP_FRAGMENT_INDEXES((&fragment),
     903                                                &msblk->fragment_index[i], 1);
     904                        msblk->fragment_index[i] = fragment;
     905                }
     906        }
     907
     908        return 1;
     909}
     910
     911
     912static int supported_squashfs_filesystem(struct squashfs_sb_info *msblk, int silent)
     913{
     914        struct squashfs_super_block *sblk = &msblk->sblk;
     915
     916        msblk->iget = squashfs_iget;
     917        msblk->read_blocklist = read_blocklist;
     918        msblk->read_fragment_index_table = read_fragment_index_table;
     919
     920        if (sblk->s_major == 1) {
     921                if (!squashfs_1_0_supported(msblk)) {
     922                        SERROR("Major/Minor mismatch, Squashfs 1.0 filesystems "
     923                                "are unsupported\n");
     924                        SERROR("Please recompile with "
     925                                "Squashfs 1.0 support enabled\n");
     926                        return 0;
     927                }
     928        } else if (sblk->s_major == 2) {
     929                if (!squashfs_2_0_supported(msblk)) {
     930                        SERROR("Major/Minor mismatch, Squashfs 2.0 filesystems "
     931                                "are unsupported\n");
     932                        SERROR("Please recompile with "
     933                                "Squashfs 2.0 support enabled\n");
     934                        return 0;
     935                }
     936        } else if(sblk->s_major != SQUASHFS_MAJOR || sblk->s_minor >
     937                        SQUASHFS_MINOR) {
     938                SERROR("Major/Minor mismatch, trying to mount newer %d.%d "
     939                                "filesystem\n", sblk->s_major, sblk->s_minor);
     940                SERROR("Please update your kernel\n");
     941                return 0;
     942        }
     943
     944        return 1;
     945}
     946
     947
     948static int squashfs_fill_super(struct super_block *s, void *data, int silent)
     949{
     950        struct squashfs_sb_info *msblk;
     951        struct squashfs_super_block *sblk;
     952        int i;
     953        char b[BDEVNAME_SIZE];
     954        struct inode *root;
     955
     956        TRACE("Entered squashfs_read_superblock\n");
     957
     958        if (!(s->s_fs_info = kmalloc(sizeof(struct squashfs_sb_info),
     959                                                GFP_KERNEL))) {
     960                ERROR("Failed to allocate superblock\n");
     961                goto failure;
     962        }
     963        memset(s->s_fs_info, 0, sizeof(struct squashfs_sb_info));
     964        msblk = s->s_fs_info;
     965        if (!(msblk->stream.workspace = vmalloc(zlib_inflate_workspacesize()))) {
     966                ERROR("Failed to allocate zlib workspace\n");
     967                goto failure;
     968        }
     969        sblk = &msblk->sblk;
     970       
     971        msblk->devblksize = sb_min_blocksize(s, BLOCK_SIZE);
     972        msblk->devblksize_log2 = ffz(~msblk->devblksize);
     973
     974        init_MUTEX(&msblk->read_data_mutex);
     975        init_MUTEX(&msblk->read_page_mutex);
     976        init_MUTEX(&msblk->block_cache_mutex);
     977        init_MUTEX(&msblk->fragment_mutex);
     978        init_MUTEX(&msblk->meta_index_mutex);
     979       
     980        init_waitqueue_head(&msblk->waitq);
     981        init_waitqueue_head(&msblk->fragment_wait_queue);
     982
     983        if (!squashfs_read_data(s, (char *) sblk, SQUASHFS_START,
     984                                        sizeof(struct squashfs_super_block) |
     985                                        SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
     986                SERROR("unable to read superblock\n");
     987                goto failed_mount;
     988        }
     989
     990        /* Check it is a SQUASHFS superblock */
     991        msblk->swap = 0;
     992        if ((s->s_magic = sblk->s_magic) != SQUASHFS_MAGIC) {
     993                if (sblk->s_magic == SQUASHFS_MAGIC_SWAP) {
     994                        struct squashfs_super_block ssblk;
     995
     996                        WARNING("Mounting a different endian SQUASHFS "
     997                                "filesystem on %s\n", bdevname(s->s_bdev, b));
     998
     999                        SQUASHFS_SWAP_SUPER_BLOCK(&ssblk, sblk);
     1000                        memcpy(sblk, &ssblk, sizeof(struct squashfs_super_block));
     1001                        msblk->swap = 1;
     1002                } else  {
     1003                        SERROR("Can't find a SQUASHFS superblock on %s\n",
     1004                                                        bdevname(s->s_bdev, b));
     1005                        goto failed_mount;
     1006                }
     1007        }
     1008
     1009        /* Check the MAJOR & MINOR versions */
     1010        if(!supported_squashfs_filesystem(msblk, silent))
     1011                goto failed_mount;
     1012
     1013        TRACE("Found valid superblock on %s\n", bdevname(s->s_bdev, b));
     1014        TRACE("Inodes are %scompressed\n",
     1015                                        SQUASHFS_UNCOMPRESSED_INODES
     1016                                        (sblk->flags) ? "un" : "");
     1017        TRACE("Data is %scompressed\n",
     1018                                        SQUASHFS_UNCOMPRESSED_DATA(sblk->flags)
     1019                                        ? "un" : "");
     1020        TRACE("Check data is %s present in the filesystem\n",
     1021                                        SQUASHFS_CHECK_DATA(sblk->flags) ?
     1022                                        "" : "not");
     1023        TRACE("Filesystem size %lld bytes\n", sblk->bytes_used);
     1024        TRACE("Block size %d\n", sblk->block_size);
     1025        TRACE("Number of inodes %d\n", sblk->inodes);
     1026        if (sblk->s_major > 1)
     1027                TRACE("Number of fragments %d\n", sblk->fragments);
     1028        TRACE("Number of uids %d\n", sblk->no_uids);
     1029        TRACE("Number of gids %d\n", sblk->no_guids);
     1030        TRACE("sblk->inode_table_start %llx\n", sblk->inode_table_start);
     1031        TRACE("sblk->directory_table_start %llx\n", sblk->directory_table_start);
     1032        if (sblk->s_major > 1)
     1033                TRACE("sblk->fragment_table_start %llx\n",
     1034                                        sblk->fragment_table_start);
     1035        TRACE("sblk->uid_start %llx\n", sblk->uid_start);
     1036
     1037        s->s_flags |= MS_RDONLY;
     1038        s->s_op = &squashfs_ops;
     1039
     1040        /* Init inode_table block pointer array */
     1041        if (!(msblk->block_cache = kmalloc(sizeof(struct squashfs_cache) *
     1042                                        SQUASHFS_CACHED_BLKS, GFP_KERNEL))) {
     1043                ERROR("Failed to allocate block cache\n");
     1044                goto failed_mount;
     1045        }
     1046
     1047        for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
     1048                msblk->block_cache[i].block = SQUASHFS_INVALID_BLK;
     1049
     1050        msblk->next_cache = 0;
     1051
     1052        /* Allocate read_data block */
     1053        msblk->read_size = (sblk->block_size < SQUASHFS_METADATA_SIZE) ?
     1054                                        SQUASHFS_METADATA_SIZE :
     1055                                        sblk->block_size;
     1056
     1057        if (!(msblk->read_data = kmalloc(msblk->read_size, GFP_KERNEL))) {
     1058                ERROR("Failed to allocate read_data block\n");
     1059                goto failed_mount;
     1060        }
     1061
     1062        /* Allocate read_page block */
     1063        if (!(msblk->read_page = kmalloc(sblk->block_size, GFP_KERNEL))) {
     1064                ERROR("Failed to allocate read_page block\n");
     1065                goto failed_mount;
     1066        }
     1067
     1068        /* Allocate uid and gid tables */
     1069        if (!(msblk->uid = kmalloc((sblk->no_uids + sblk->no_guids) *
     1070                                        sizeof(unsigned int), GFP_KERNEL))) {
     1071                ERROR("Failed to allocate uid/gid table\n");
     1072                goto failed_mount;
     1073        }
     1074        msblk->guid = msblk->uid + sblk->no_uids;
     1075   
     1076        if (msblk->swap) {
     1077                unsigned int suid[sblk->no_uids + sblk->no_guids];
     1078
     1079                if (!squashfs_read_data(s, (char *) &suid, sblk->uid_start,
     1080                                        ((sblk->no_uids + sblk->no_guids) *
     1081                                         sizeof(unsigned int)) |
     1082                                        SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
     1083                        ERROR("unable to read uid/gid table\n");
     1084                        goto failed_mount;
     1085                }
     1086
     1087                SQUASHFS_SWAP_DATA(msblk->uid, suid, (sblk->no_uids +
     1088                        sblk->no_guids), (sizeof(unsigned int) * 8));
     1089        } else
     1090                if (!squashfs_read_data(s, (char *) msblk->uid, sblk->uid_start,
     1091                                        ((sblk->no_uids + sblk->no_guids) *
     1092                                         sizeof(unsigned int)) |
     1093                                        SQUASHFS_COMPRESSED_BIT_BLOCK, NULL)) {
     1094                        ERROR("unable to read uid/gid table\n");
     1095                        goto failed_mount;
     1096                }
     1097
     1098
     1099        if (sblk->s_major == 1 && squashfs_1_0_supported(msblk))
     1100                goto allocate_root;
     1101
     1102        if (!(msblk->fragment = kmalloc(sizeof(struct squashfs_fragment_cache) *
     1103                                SQUASHFS_CACHED_FRAGMENTS, GFP_KERNEL))) {
     1104                ERROR("Failed to allocate fragment block cache\n");
     1105                goto failed_mount;
     1106        }
     1107
     1108        for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++) {
     1109                msblk->fragment[i].locked = 0;
     1110                msblk->fragment[i].block = SQUASHFS_INVALID_BLK;
     1111                msblk->fragment[i].data = NULL;
     1112        }
     1113
     1114        msblk->next_fragment = 0;
     1115
     1116        /* Allocate fragment index table */
     1117        if (msblk->read_fragment_index_table(s) == 0)
     1118                goto failed_mount;
     1119
     1120allocate_root:
     1121        if ((root = (msblk->iget)(s, sblk->root_inode)) == NULL)
     1122                goto failed_mount;
     1123
     1124        if ((s->s_root = d_alloc_root(root)) == NULL) {
     1125                ERROR("Root inode create failed\n");
     1126                iput(root);
     1127                goto failed_mount;
     1128        }
     1129
     1130        TRACE("Leaving squashfs_read_super\n");
     1131        return 0;
     1132
     1133failed_mount:
     1134        kfree(msblk->fragment_index);
     1135        kfree(msblk->fragment);
     1136        kfree(msblk->uid);
     1137        kfree(msblk->read_page);
     1138        kfree(msblk->read_data);
     1139        kfree(msblk->block_cache);
     1140        kfree(msblk->fragment_index_2);
     1141        vfree(msblk->stream.workspace);
     1142        kfree(s->s_fs_info);
     1143        s->s_fs_info = NULL;
     1144        return -EINVAL;
     1145
     1146failure:
     1147        return -ENOMEM;
     1148}
     1149
     1150
     1151static int squashfs_statfs(struct dentry *dentry, struct kstatfs *buf)
     1152{
     1153        struct squashfs_sb_info *msblk = dentry->d_sb->s_fs_info;
     1154        struct squashfs_super_block *sblk = &msblk->sblk;
     1155
     1156        TRACE("Entered squashfs_statfs\n");
     1157
     1158        buf->f_type = SQUASHFS_MAGIC;
     1159        buf->f_bsize = sblk->block_size;
     1160        buf->f_blocks = ((sblk->bytes_used - 1) >> sblk->block_log) + 1;
     1161        buf->f_bfree = buf->f_bavail = 0;
     1162        buf->f_files = sblk->inodes;
     1163        buf->f_ffree = 0;
     1164        buf->f_namelen = SQUASHFS_NAME_LEN;
     1165
     1166        return 0;
     1167}
     1168
     1169
     1170static int squashfs_symlink_readpage(struct file *file, struct page *page)
     1171{
     1172        struct inode *inode = page->mapping->host;
     1173        int index = page->index << PAGE_CACHE_SHIFT, length, bytes;
     1174        long long block = SQUASHFS_I(inode)->start_block;
     1175        int offset = SQUASHFS_I(inode)->offset;
     1176        void *pageaddr = kmap(page);
     1177
     1178        TRACE("Entered squashfs_symlink_readpage, page index %ld, start block "
     1179                                "%llx, offset %x\n", page->index,
     1180                                SQUASHFS_I(inode)->start_block,
     1181                                SQUASHFS_I(inode)->offset);
     1182
     1183        for (length = 0; length < index; length += bytes) {
     1184                if (!(bytes = squashfs_get_cached_block(inode->i_sb, NULL,
     1185                                block, offset, PAGE_CACHE_SIZE, &block,
     1186                                &offset))) {
     1187                        ERROR("Unable to read symbolic link [%llx:%x]\n", block,
     1188                                        offset);
     1189                        goto skip_read;
     1190                }
     1191        }
     1192
     1193        if (length != index) {
     1194                ERROR("(squashfs_symlink_readpage) length != index\n");
     1195                bytes = 0;
     1196                goto skip_read;
     1197        }
     1198
     1199        bytes = (i_size_read(inode) - length) > PAGE_CACHE_SIZE ? PAGE_CACHE_SIZE :
     1200                                        i_size_read(inode) - length;
     1201
     1202        if (!(bytes = squashfs_get_cached_block(inode->i_sb, pageaddr, block,
     1203                                        offset, bytes, &block, &offset)))
     1204                ERROR("Unable to read symbolic link [%llx:%x]\n", block, offset);
     1205
     1206skip_read:
     1207        memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
     1208        kunmap(page);
     1209        SetPageUptodate(page);
     1210        unlock_page(page);
     1211
     1212        return 0;
     1213}
     1214
     1215
     1216struct meta_index *locate_meta_index(struct inode *inode, int index, int offset)
     1217{
     1218        struct meta_index *meta = NULL;
     1219        struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
     1220        int i;
     1221
     1222        down(&msblk->meta_index_mutex);
     1223
     1224        TRACE("locate_meta_index: index %d, offset %d\n", index, offset);
     1225
     1226        if(msblk->meta_index == NULL)
     1227                goto not_allocated;
     1228
     1229        for (i = 0; i < SQUASHFS_META_NUMBER; i ++)
     1230                if (msblk->meta_index[i].inode_number == inode->i_ino &&
     1231                                msblk->meta_index[i].offset >= offset &&
     1232                                msblk->meta_index[i].offset <= index &&
     1233                                msblk->meta_index[i].locked == 0) {
     1234                        TRACE("locate_meta_index: entry %d, offset %d\n", i,
     1235                                        msblk->meta_index[i].offset);
     1236                        meta = &msblk->meta_index[i];
     1237                        offset = meta->offset;
     1238                }
     1239
     1240        if (meta)
     1241                meta->locked = 1;
     1242
     1243not_allocated:
     1244        up(&msblk->meta_index_mutex);
     1245
     1246        return meta;
     1247}
     1248
     1249
     1250struct meta_index *empty_meta_index(struct inode *inode, int offset, int skip)
     1251{
     1252        struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
     1253        struct meta_index *meta = NULL;
     1254        int i;
     1255
     1256        down(&msblk->meta_index_mutex);
     1257
     1258        TRACE("empty_meta_index: offset %d, skip %d\n", offset, skip);
     1259
     1260        if(msblk->meta_index == NULL) {
     1261                if (!(msblk->meta_index = kmalloc(sizeof(struct meta_index) *
     1262                                        SQUASHFS_META_NUMBER, GFP_KERNEL))) {
     1263                        ERROR("Failed to allocate meta_index\n");
     1264                        goto failed;
     1265                }
     1266                for(i = 0; i < SQUASHFS_META_NUMBER; i++) {
     1267                        msblk->meta_index[i].inode_number = 0;
     1268                        msblk->meta_index[i].locked = 0;
     1269                }
     1270                msblk->next_meta_index = 0;
     1271        }
     1272
     1273        for(i = SQUASHFS_META_NUMBER; i &&
     1274                        msblk->meta_index[msblk->next_meta_index].locked; i --)
     1275                msblk->next_meta_index = (msblk->next_meta_index + 1) %
     1276                        SQUASHFS_META_NUMBER;
     1277
     1278        if(i == 0) {
     1279                TRACE("empty_meta_index: failed!\n");
     1280                goto failed;
     1281        }
     1282
     1283        TRACE("empty_meta_index: returned meta entry %d, %p\n",
     1284                        msblk->next_meta_index,
     1285                        &msblk->meta_index[msblk->next_meta_index]);
     1286
     1287        meta = &msblk->meta_index[msblk->next_meta_index];
     1288        msblk->next_meta_index = (msblk->next_meta_index + 1) %
     1289                        SQUASHFS_META_NUMBER;
     1290
     1291        meta->inode_number = inode->i_ino;
     1292        meta->offset = offset;
     1293        meta->skip = skip;
     1294        meta->entries = 0;
     1295        meta->locked = 1;
     1296
     1297failed:
     1298        up(&msblk->meta_index_mutex);
     1299        return meta;
     1300}
     1301
     1302
     1303void release_meta_index(struct inode *inode, struct meta_index *meta)
     1304{
     1305        meta->locked = 0;
     1306}
     1307
     1308
     1309static int read_block_index(struct super_block *s, int blocks, char *block_list,
     1310                long long *start_block, int *offset)
     1311{
     1312        struct squashfs_sb_info *msblk = s->s_fs_info;
     1313        unsigned int *block_listp;
     1314        int block = 0;
     1315       
     1316        if (msblk->swap) {
     1317                char sblock_list[blocks << 2];
     1318
     1319                if (!squashfs_get_cached_block(s, sblock_list, *start_block,
     1320                                *offset, blocks << 2, start_block, offset)) {
     1321                        ERROR("Unable to read block list [%llx:%x]\n",
     1322                                *start_block, *offset);
     1323                        goto failure;
     1324                }
     1325                SQUASHFS_SWAP_INTS(((unsigned int *)block_list),
     1326                                ((unsigned int *)sblock_list), blocks);
     1327        } else
     1328                if (!squashfs_get_cached_block(s, block_list, *start_block,
     1329                                *offset, blocks << 2, start_block, offset)) {
     1330                        ERROR("Unable to read block list [%llx:%x]\n",
     1331                                *start_block, *offset);
     1332                        goto failure;
     1333                }
     1334
     1335        for (block_listp = (unsigned int *) block_list; blocks;
     1336                                block_listp++, blocks --)
     1337                block += SQUASHFS_COMPRESSED_SIZE_BLOCK(*block_listp);
     1338
     1339        return block;
     1340
     1341failure:
     1342        return -1;
     1343}
     1344
     1345
     1346#define SIZE 256
     1347
     1348static inline int calculate_skip(int blocks) {
     1349        int skip = (blocks - 1) / ((SQUASHFS_SLOTS * SQUASHFS_META_ENTRIES + 1) * SQUASHFS_META_INDEXES);
     1350        return skip >= 7 ? 7 : skip + 1;
     1351}
     1352
     1353
     1354static int get_meta_index(struct inode *inode, int index,
     1355                long long *index_block, int *index_offset,
     1356                long long *data_block, char *block_list)
     1357{
     1358        struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
     1359        struct squashfs_super_block *sblk = &msblk->sblk;
     1360        int skip = calculate_skip(i_size_read(inode) >> sblk->block_log);
     1361        int offset = 0;
     1362        struct meta_index *meta;
     1363        struct meta_entry *meta_entry;
     1364        long long cur_index_block = SQUASHFS_I(inode)->u.s1.block_list_start;
     1365        int cur_offset = SQUASHFS_I(inode)->offset;
     1366        long long cur_data_block = SQUASHFS_I(inode)->start_block;
     1367        int i;
     1368 
     1369        index /= SQUASHFS_META_INDEXES * skip;
     1370
     1371        while ( offset < index ) {
     1372                meta = locate_meta_index(inode, index, offset + 1);
     1373
     1374                if (meta == NULL) {
     1375                        if ((meta = empty_meta_index(inode, offset + 1,
     1376                                                        skip)) == NULL)
     1377                                goto all_done;
     1378                } else {
     1379                        offset = index < meta->offset + meta->entries ? index :
     1380                                meta->offset + meta->entries - 1;
     1381                        meta_entry = &meta->meta_entry[offset - meta->offset];
     1382                        cur_index_block = meta_entry->index_block + sblk->inode_table_start;
     1383                        cur_offset = meta_entry->offset;
     1384                        cur_data_block = meta_entry->data_block;
     1385                        TRACE("get_meta_index: offset %d, meta->offset %d, "
     1386                                "meta->entries %d\n", offset, meta->offset,
     1387                                meta->entries);
     1388                        TRACE("get_meta_index: index_block 0x%llx, offset 0x%x"
     1389                                " data_block 0x%llx\n", cur_index_block,
     1390                                cur_offset, cur_data_block);
     1391                }
     1392
     1393                for (i = meta->offset + meta->entries; i <= index &&
     1394                                i < meta->offset + SQUASHFS_META_ENTRIES; i++) {
     1395                        int blocks = skip * SQUASHFS_META_INDEXES;
     1396
     1397                        while (blocks) {
     1398                                int block = blocks > (SIZE >> 2) ? (SIZE >> 2) :
     1399                                        blocks;
     1400                                int res = read_block_index(inode->i_sb, block,
     1401                                        block_list, &cur_index_block,
     1402                                        &cur_offset);
     1403
     1404                                if (res == -1)
     1405                                        goto failed;
     1406
     1407                                cur_data_block += res;
     1408                                blocks -= block;
     1409                        }
     1410
     1411                        meta_entry = &meta->meta_entry[i - meta->offset];
     1412                        meta_entry->index_block = cur_index_block - sblk->inode_table_start;
     1413                        meta_entry->offset = cur_offset;
     1414                        meta_entry->data_block = cur_data_block;
     1415                        meta->entries ++;
     1416                        offset ++;
     1417                }
     1418
     1419                TRACE("get_meta_index: meta->offset %d, meta->entries %d\n",
     1420                                meta->offset, meta->entries);
     1421
     1422                release_meta_index(inode, meta);
     1423        }
     1424
     1425all_done:
     1426        *index_block = cur_index_block;
     1427        *index_offset = cur_offset;
     1428        *data_block = cur_data_block;
     1429
     1430        return offset * SQUASHFS_META_INDEXES * skip;
     1431
     1432failed:
     1433        release_meta_index(inode, meta);
     1434        return -1;
     1435}
     1436
     1437
     1438static long long read_blocklist(struct inode *inode, int index,
     1439                                int readahead_blks, char *block_list,
     1440                                unsigned short **block_p, unsigned int *bsize)
     1441{
     1442        long long block_ptr;
     1443        int offset;
     1444        long long block;
     1445        int res = get_meta_index(inode, index, &block_ptr, &offset, &block,
     1446                block_list);
     1447
     1448        TRACE("read_blocklist: res %d, index %d, block_ptr 0x%llx, offset"
     1449                       " 0x%x, block 0x%llx\n", res, index, block_ptr, offset,
     1450                       block);
     1451
     1452        if(res == -1)
     1453                goto failure;
     1454
     1455        index -= res;
     1456
     1457        while ( index ) {
     1458                int blocks = index > (SIZE >> 2) ? (SIZE >> 2) : index;
     1459                int res = read_block_index(inode->i_sb, blocks, block_list,
     1460                        &block_ptr, &offset);
     1461                if (res == -1)
     1462                        goto failure;
     1463                block += res;
     1464                index -= blocks;
     1465        }
     1466
     1467        if (read_block_index(inode->i_sb, 1, block_list,
     1468                        &block_ptr, &offset) == -1)
     1469                goto failure;
     1470        *bsize = *((unsigned int *) block_list);
     1471
     1472        return block;
     1473
     1474failure:
     1475        return 0;
     1476}
     1477
     1478
     1479static int squashfs_readpage(struct file *file, struct page *page)
     1480{
     1481        struct inode *inode = page->mapping->host;
     1482        struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
     1483        struct squashfs_super_block *sblk = &msblk->sblk;
     1484        unsigned char *block_list;
     1485        long long block;
     1486        unsigned int bsize, i = 0, bytes = 0, byte_offset = 0;
     1487        int index = page->index >> (sblk->block_log - PAGE_CACHE_SHIFT);
     1488        void *pageaddr;
     1489        struct squashfs_fragment_cache *fragment = NULL;
     1490        char *data_ptr = msblk->read_page;
     1491       
     1492        int mask = (1 << (sblk->block_log - PAGE_CACHE_SHIFT)) - 1;
     1493        int start_index = page->index & ~mask;
     1494        int end_index = start_index | mask;
     1495
     1496        TRACE("Entered squashfs_readpage, page index %lx, start block %llx\n",
     1497                                        page->index,
     1498                                        SQUASHFS_I(inode)->start_block);
     1499
     1500        if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) {
     1501                ERROR("Failed to allocate block_list\n");
     1502                goto skip_read;
     1503        }
     1504
     1505        if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
     1506                                        PAGE_CACHE_SHIFT))
     1507                goto skip_read;
     1508
     1509        if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
     1510                                        || index < (i_size_read(inode) >>
     1511                                        sblk->block_log)) {
     1512                if ((block = (msblk->read_blocklist)(inode, index, 1,
     1513                                        block_list, NULL, &bsize)) == 0)
     1514                        goto skip_read;
     1515
     1516                down(&msblk->read_page_mutex);
     1517               
     1518                if (!(bytes = squashfs_read_data(inode->i_sb, msblk->read_page,
     1519                                        block, bsize, NULL))) {
     1520                        ERROR("Unable to read page, block %llx, size %x\n", block,
     1521                                        bsize);
     1522                        up(&msblk->read_page_mutex);
     1523                        goto skip_read;
     1524                }
     1525        } else {
     1526                if ((fragment = get_cached_fragment(inode->i_sb,
     1527                                        SQUASHFS_I(inode)->
     1528                                        u.s1.fragment_start_block,
     1529                                        SQUASHFS_I(inode)->u.s1.fragment_size))
     1530                                        == NULL) {
     1531                        ERROR("Unable to read page, block %llx, size %x\n",
     1532                                        SQUASHFS_I(inode)->
     1533                                        u.s1.fragment_start_block,
     1534                                        (int) SQUASHFS_I(inode)->
     1535                                        u.s1.fragment_size);
     1536                        goto skip_read;
     1537                }
     1538                bytes = SQUASHFS_I(inode)->u.s1.fragment_offset +
     1539                                        (i_size_read(inode) & (sblk->block_size
     1540                                        - 1));
     1541                byte_offset = SQUASHFS_I(inode)->u.s1.fragment_offset;
     1542                data_ptr = fragment->data;
     1543        }
     1544
     1545        for (i = start_index; i <= end_index && byte_offset < bytes;
     1546                                        i++, byte_offset += PAGE_CACHE_SIZE) {
     1547                struct page *push_page;
     1548                int available_bytes = (bytes - byte_offset) > PAGE_CACHE_SIZE ?
     1549                                        PAGE_CACHE_SIZE : bytes - byte_offset;
     1550
     1551                TRACE("bytes %d, i %d, byte_offset %d, available_bytes %d\n",
     1552                                        bytes, i, byte_offset, available_bytes);
     1553
     1554                if (i == page->index)  {
     1555                        pageaddr = kmap_atomic(page, KM_USER0);
     1556                        memcpy(pageaddr, data_ptr + byte_offset,
     1557                                        available_bytes);
     1558                        memset(pageaddr + available_bytes, 0,
     1559                                        PAGE_CACHE_SIZE - available_bytes);
     1560                        kunmap_atomic(pageaddr, KM_USER0);
     1561                        flush_dcache_page(page);
     1562                        SetPageUptodate(page);
     1563                        unlock_page(page);
     1564                } else if ((push_page =
     1565                                grab_cache_page_nowait(page->mapping, i))) {
     1566                        pageaddr = kmap_atomic(push_page, KM_USER0);
     1567
     1568                        memcpy(pageaddr, data_ptr + byte_offset,
     1569                                        available_bytes);
     1570                        memset(pageaddr + available_bytes, 0,
     1571                                        PAGE_CACHE_SIZE - available_bytes);
     1572                        kunmap_atomic(pageaddr, KM_USER0);
     1573                        flush_dcache_page(push_page);
     1574                        SetPageUptodate(push_page);
     1575                        unlock_page(push_page);
     1576                        page_cache_release(push_page);
     1577                }
     1578        }
     1579
     1580        if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
     1581                                        || index < (i_size_read(inode) >>
     1582                                        sblk->block_log))
     1583                up(&msblk->read_page_mutex);
     1584        else
     1585                release_cached_fragment(msblk, fragment);
     1586
     1587        kfree(block_list);
     1588        return 0;
     1589
     1590skip_read:
     1591        pageaddr = kmap_atomic(page, KM_USER0);
     1592        memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
     1593        kunmap_atomic(pageaddr, KM_USER0);
     1594        flush_dcache_page(page);
     1595        SetPageUptodate(page);
     1596        unlock_page(page);
     1597
     1598        kfree(block_list);
     1599        return 0;
     1600}
     1601
     1602
     1603static int squashfs_readpage4K(struct file *file, struct page *page)
     1604{
     1605        struct inode *inode = page->mapping->host;
     1606        struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
     1607        struct squashfs_super_block *sblk = &msblk->sblk;
     1608        unsigned char *block_list;
     1609        long long block;
     1610        unsigned int bsize, bytes = 0;
     1611        void *pageaddr;
     1612       
     1613        TRACE("Entered squashfs_readpage4K, page index %lx, start block %llx\n",
     1614                                        page->index,
     1615                                        SQUASHFS_I(inode)->start_block);
     1616
     1617        if (page->index >= ((i_size_read(inode) + PAGE_CACHE_SIZE - 1) >>
     1618                                        PAGE_CACHE_SHIFT)) {
     1619                pageaddr = kmap_atomic(page, KM_USER0);
     1620                block_list = NULL;
     1621                goto skip_read;
     1622        }
     1623
     1624        if (!(block_list = kmalloc(SIZE, GFP_KERNEL))) {
     1625                ERROR("Failed to allocate block_list\n");
     1626                pageaddr = kmap_atomic(page, KM_USER0);
     1627                block_list = NULL;
     1628                goto skip_read;
     1629        }
     1630
     1631        if (SQUASHFS_I(inode)->u.s1.fragment_start_block == SQUASHFS_INVALID_BLK
     1632                                        || page->index < (i_size_read(inode) >>
     1633                                        sblk->block_log)) {
     1634                block = (msblk->read_blocklist)(inode, page->index, 1,
     1635                                        block_list, NULL, &bsize);
     1636
     1637                down(&msblk->read_page_mutex);
     1638                bytes = squashfs_read_data(inode->i_sb, msblk->read_page, block,
     1639                                        bsize, NULL);
     1640                pageaddr = kmap_atomic(page, KM_USER0);
     1641                if (bytes)
     1642                        memcpy(pageaddr, msblk->read_page, bytes);
     1643                else
     1644                        ERROR("Unable to read page, block %llx, size %x\n",
     1645                                        block, bsize);
     1646                up(&msblk->read_page_mutex);
     1647        } else {
     1648                struct squashfs_fragment_cache *fragment =
     1649                        get_cached_fragment(inode->i_sb,
     1650                                        SQUASHFS_I(inode)->
     1651                                        u.s1.fragment_start_block,
     1652                                        SQUASHFS_I(inode)-> u.s1.fragment_size);
     1653                pageaddr = kmap_atomic(page, KM_USER0);
     1654                if (fragment) {
     1655                        bytes = i_size_read(inode) & (sblk->block_size - 1);
     1656                        memcpy(pageaddr, fragment->data + SQUASHFS_I(inode)->
     1657                                        u.s1.fragment_offset, bytes);
     1658                        release_cached_fragment(msblk, fragment);
     1659                } else
     1660                        ERROR("Unable to read page, block %llx, size %x\n",
     1661                                        SQUASHFS_I(inode)->
     1662                                        u.s1.fragment_start_block, (int)
     1663                                        SQUASHFS_I(inode)-> u.s1.fragment_size);
     1664        }
     1665
     1666skip_read:
     1667        memset(pageaddr + bytes, 0, PAGE_CACHE_SIZE - bytes);
     1668        kunmap_atomic(pageaddr, KM_USER0);
     1669        flush_dcache_page(page);
     1670        SetPageUptodate(page);
     1671        unlock_page(page);
     1672
     1673        kfree(block_list);
     1674        return 0;
     1675}
     1676
     1677
     1678static int get_dir_index_using_offset(struct super_block *s, long long
     1679                                *next_block, unsigned int *next_offset,
     1680                                long long index_start,
     1681                                unsigned int index_offset, int i_count,
     1682                                long long f_pos)
     1683{
     1684        struct squashfs_sb_info *msblk = s->s_fs_info;
     1685        struct squashfs_super_block *sblk = &msblk->sblk;
     1686        int i, length = 0;
     1687        struct squashfs_dir_index index;
     1688
     1689        TRACE("Entered get_dir_index_using_offset, i_count %d, f_pos %d\n",
     1690                                        i_count, (unsigned int) f_pos);
     1691
     1692        f_pos =- 3;
     1693        if (f_pos == 0)
     1694                goto finish;
     1695
     1696        for (i = 0; i < i_count; i++) {
     1697                if (msblk->swap) {
     1698                        struct squashfs_dir_index sindex;
     1699                        squashfs_get_cached_block(s, (char *) &sindex,
     1700                                        index_start, index_offset,
     1701                                        sizeof(sindex), &index_start,
     1702                                        &index_offset);
     1703                        SQUASHFS_SWAP_DIR_INDEX(&index, &sindex);
     1704                } else
     1705                        squashfs_get_cached_block(s, (char *) &index,
     1706                                        index_start, index_offset,
     1707                                        sizeof(index), &index_start,
     1708                                        &index_offset);
     1709
     1710                if (index.index > f_pos)
     1711                        break;
     1712
     1713                squashfs_get_cached_block(s, NULL, index_start, index_offset,
     1714                                        index.size + 1, &index_start,
     1715                                        &index_offset);
     1716
     1717                length = index.index;
     1718                *next_block = index.start_block + sblk->directory_table_start;
     1719        }
     1720
     1721        *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
     1722
     1723finish:
     1724        return length + 3;
     1725}
     1726
     1727
     1728static int get_dir_index_using_name(struct super_block *s, long long
     1729                                *next_block, unsigned int *next_offset,
     1730                                long long index_start,
     1731                                unsigned int index_offset, int i_count,
     1732                                const char *name, int size)
     1733{
     1734        struct squashfs_sb_info *msblk = s->s_fs_info;
     1735        struct squashfs_super_block *sblk = &msblk->sblk;
     1736        int i, length = 0;
     1737        struct squashfs_dir_index *index;
     1738        char *str;
     1739
     1740        TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
     1741
     1742        if (!(str = kmalloc(sizeof(struct squashfs_dir_index) +
     1743                (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) {
     1744                ERROR("Failed to allocate squashfs_dir_index\n");
     1745                goto failure;
     1746        }
     1747
     1748        index = (struct squashfs_dir_index *) (str + SQUASHFS_NAME_LEN + 1);
     1749        strncpy(str, name, size);
     1750        str[size] = '\0';
     1751
     1752        for (i = 0; i < i_count; i++) {
     1753                if (msblk->swap) {
     1754                        struct squashfs_dir_index sindex;
     1755                        squashfs_get_cached_block(s, (char *) &sindex,
     1756                                        index_start, index_offset,
     1757                                        sizeof(sindex), &index_start,
     1758                                        &index_offset);
     1759                        SQUASHFS_SWAP_DIR_INDEX(index, &sindex);
     1760                } else
     1761                        squashfs_get_cached_block(s, (char *) index,
     1762                                        index_start, index_offset,
     1763                                        sizeof(struct squashfs_dir_index),
     1764                                        &index_start, &index_offset);
     1765
     1766                squashfs_get_cached_block(s, index->name, index_start,
     1767                                        index_offset, index->size + 1,
     1768                                        &index_start, &index_offset);
     1769
     1770                index->name[index->size + 1] = '\0';
     1771
     1772                if (strcmp(index->name, str) > 0)
     1773                        break;
     1774
     1775                length = index->index;
     1776                *next_block = index->start_block + sblk->directory_table_start;
     1777        }
     1778
     1779        *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
     1780        kfree(str);
     1781failure:
     1782        return length + 3;
     1783}
     1784
     1785               
     1786static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
     1787{
     1788        struct inode *i = file->f_dentry->d_inode;
     1789        struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
     1790        struct squashfs_super_block *sblk = &msblk->sblk;
     1791        long long next_block = SQUASHFS_I(i)->start_block +
     1792                sblk->directory_table_start;
     1793        int next_offset = SQUASHFS_I(i)->offset, length = 0,
     1794                dir_count;
     1795        struct squashfs_dir_header dirh;
     1796        struct squashfs_dir_entry *dire;
     1797
     1798        TRACE("Entered squashfs_readdir [%llx:%x]\n", next_block, next_offset);
     1799
     1800        if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
     1801                SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
     1802                ERROR("Failed to allocate squashfs_dir_entry\n");
     1803                goto finish;
     1804        }
     1805
     1806        while(file->f_pos < 3) {
     1807                char *name;
     1808                int size, i_ino;
     1809
     1810                if(file->f_pos == 0) {
     1811                        name = ".";
     1812                        size = 1;
     1813                        i_ino = i->i_ino;
     1814                } else {
     1815                        name = "..";
     1816                        size = 2;
     1817                        i_ino = SQUASHFS_I(i)->u.s2.parent_inode;
     1818                }
     1819                TRACE("Calling filldir(%x, %s, %d, %d, %d, %d)\n",
     1820                                (unsigned int) dirent, name, size, (int)
     1821                                file->f_pos, i_ino,
     1822                                squashfs_filetype_table[1]);
     1823
     1824                if (filldir(dirent, name, size,
     1825                                file->f_pos, i_ino,
     1826                                squashfs_filetype_table[1]) < 0) {
     1827                                TRACE("Filldir returned less than 0\n");
     1828                                goto finish;
     1829                }
     1830                file->f_pos += size;
     1831        }
     1832
     1833        length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
     1834                                SQUASHFS_I(i)->u.s2.directory_index_start,
     1835                                SQUASHFS_I(i)->u.s2.directory_index_offset,
     1836                                SQUASHFS_I(i)->u.s2.directory_index_count,
     1837                                file->f_pos);
     1838
     1839        while (length < i_size_read(i)) {
     1840                /* read directory header */
     1841                if (msblk->swap) {
     1842                        struct squashfs_dir_header sdirh;
     1843                       
     1844                        if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
     1845                                        next_block, next_offset, sizeof(sdirh),
     1846                                        &next_block, &next_offset))
     1847                                goto failed_read;
     1848
     1849                        length += sizeof(sdirh);
     1850                        SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
     1851                } else {
     1852                        if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
     1853                                        next_block, next_offset, sizeof(dirh),
     1854                                        &next_block, &next_offset))
     1855                                goto failed_read;
     1856
     1857                        length += sizeof(dirh);
     1858                }
     1859
     1860                dir_count = dirh.count + 1;
     1861                while (dir_count--) {
     1862                        if (msblk->swap) {
     1863                                struct squashfs_dir_entry sdire;
     1864                                if (!squashfs_get_cached_block(i->i_sb, (char *)
     1865                                                &sdire, next_block, next_offset,
     1866                                                sizeof(sdire), &next_block,
     1867                                                &next_offset))
     1868                                        goto failed_read;
     1869                               
     1870                                length += sizeof(sdire);
     1871                                SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
     1872                        } else {
     1873                                if (!squashfs_get_cached_block(i->i_sb, (char *)
     1874                                                dire, next_block, next_offset,
     1875                                                sizeof(*dire), &next_block,
     1876                                                &next_offset))
     1877                                        goto failed_read;
     1878
     1879                                length += sizeof(*dire);
     1880                        }
     1881
     1882                        if (!squashfs_get_cached_block(i->i_sb, dire->name,
     1883                                                next_block, next_offset,
     1884                                                dire->size + 1, &next_block,
     1885                                                &next_offset))
     1886                                goto failed_read;
     1887
     1888                        length += dire->size + 1;
     1889
     1890                        if (file->f_pos >= length)
     1891                                continue;
     1892
     1893                        dire->name[dire->size + 1] = '\0';
     1894
     1895                        TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d, %d)\n",
     1896                                        (unsigned int) dirent, dire->name,
     1897                                        dire->size + 1, (int) file->f_pos,
     1898                                        dirh.start_block, dire->offset,
     1899                                        dirh.inode_number + dire->inode_number,
     1900                                        squashfs_filetype_table[dire->type]);
     1901
     1902                        if (filldir(dirent, dire->name, dire->size + 1,
     1903                                        file->f_pos,
     1904                                        dirh.inode_number + dire->inode_number,
     1905                                        squashfs_filetype_table[dire->type])
     1906                                        < 0) {
     1907                                TRACE("Filldir returned less than 0\n");
     1908                                goto finish;
     1909                        }
     1910                        file->f_pos = length;
     1911                }
     1912        }
     1913
     1914finish:
     1915        kfree(dire);
     1916        return 0;
     1917
     1918failed_read:
     1919        ERROR("Unable to read directory block [%llx:%x]\n", next_block,
     1920                next_offset);
     1921        return 0;
     1922}
     1923
     1924
     1925static struct dentry *squashfs_lookup(struct inode *i, struct dentry *dentry,
     1926                                struct nameidata *nd)
     1927{
     1928        const unsigned char *name = dentry->d_name.name;
     1929        int len = dentry->d_name.len;
     1930        struct inode *inode = NULL;
     1931        struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
     1932        struct squashfs_super_block *sblk = &msblk->sblk;
     1933        long long next_block = SQUASHFS_I(i)->start_block +
     1934                                sblk->directory_table_start;
     1935        int next_offset = SQUASHFS_I(i)->offset, length = 0,
     1936                                dir_count;
     1937        struct squashfs_dir_header dirh;
     1938        struct squashfs_dir_entry *dire;
     1939
     1940        TRACE("Entered squashfs_lookup [%llx:%x]\n", next_block, next_offset);
     1941
     1942        if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
     1943                SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
     1944                ERROR("Failed to allocate squashfs_dir_entry\n");
     1945                goto exit_loop;
     1946        }
     1947
     1948        if (len > SQUASHFS_NAME_LEN)
     1949                goto exit_loop;
     1950
     1951        length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
     1952                                SQUASHFS_I(i)->u.s2.directory_index_start,
     1953                                SQUASHFS_I(i)->u.s2.directory_index_offset,
     1954                                SQUASHFS_I(i)->u.s2.directory_index_count, name,
     1955                                len);
     1956
     1957        while (length < i_size_read(i)) {
     1958                /* read directory header */
     1959                if (msblk->swap) {
     1960                        struct squashfs_dir_header sdirh;
     1961                        if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
     1962                                        next_block, next_offset, sizeof(sdirh),
     1963                                        &next_block, &next_offset))
     1964                                goto failed_read;
     1965
     1966                        length += sizeof(sdirh);
     1967                        SQUASHFS_SWAP_DIR_HEADER(&dirh, &sdirh);
     1968                } else {
     1969                        if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
     1970                                        next_block, next_offset, sizeof(dirh),
     1971                                        &next_block, &next_offset))
     1972                                goto failed_read;
     1973
     1974                        length += sizeof(dirh);
     1975                }
     1976
     1977                dir_count = dirh.count + 1;
     1978                while (dir_count--) {
     1979                        if (msblk->swap) {
     1980                                struct squashfs_dir_entry sdire;
     1981                                if (!squashfs_get_cached_block(i->i_sb, (char *)
     1982                                                &sdire, next_block,next_offset,
     1983                                                sizeof(sdire), &next_block,
     1984                                                &next_offset))
     1985                                        goto failed_read;
     1986                               
     1987                                length += sizeof(sdire);
     1988                                SQUASHFS_SWAP_DIR_ENTRY(dire, &sdire);
     1989                        } else {
     1990                                if (!squashfs_get_cached_block(i->i_sb, (char *)
     1991                                                dire, next_block,next_offset,
     1992                                                sizeof(*dire), &next_block,
     1993                                                &next_offset))
     1994                                        goto failed_read;
     1995
     1996                                length += sizeof(*dire);
     1997                        }
     1998
     1999                        if (!squashfs_get_cached_block(i->i_sb, dire->name,
     2000                                        next_block, next_offset, dire->size + 1,
     2001                                        &next_block, &next_offset))
     2002                                goto failed_read;
     2003
     2004                        length += dire->size + 1;
     2005
     2006                        if (name[0] < dire->name[0])
     2007                                goto exit_loop;
     2008
     2009                        if ((len == dire->size + 1) && !strncmp(name,
     2010                                                dire->name, len)) {
     2011                                squashfs_inode_t ino =
     2012                                        SQUASHFS_MKINODE(dirh.start_block,
     2013                                        dire->offset);
     2014
     2015                                TRACE("calling squashfs_iget for directory "
     2016                                        "entry %s, inode %x:%x, %d\n", name,
     2017                                        dirh.start_block, dire->offset,
     2018                                        dirh.inode_number + dire->inode_number);
     2019
     2020                                inode = (msblk->iget)(i->i_sb, ino);
     2021
     2022                                goto exit_loop;
     2023                        }
     2024                }
     2025        }
     2026
     2027exit_loop:
     2028        kfree(dire);
     2029        d_add(dentry, inode);
     2030        return ERR_PTR(0);
     2031
     2032failed_read:
     2033        ERROR("Unable to read directory block [%llx:%x]\n", next_block,
     2034                next_offset);
     2035        goto exit_loop;
     2036}
     2037
     2038
     2039static void squashfs_put_super(struct super_block *s)
     2040{
     2041        int i;
     2042
     2043        if (s->s_fs_info) {
     2044                struct squashfs_sb_info *sbi = s->s_fs_info;
     2045                if (sbi->block_cache)
     2046                        for (i = 0; i < SQUASHFS_CACHED_BLKS; i++)
     2047                                if (sbi->block_cache[i].block !=
     2048                                                        SQUASHFS_INVALID_BLK)
     2049                                        kfree(sbi->block_cache[i].data);
     2050                if (sbi->fragment)
     2051                        for (i = 0; i < SQUASHFS_CACHED_FRAGMENTS; i++)
     2052                                SQUASHFS_FREE(sbi->fragment[i].data);
     2053                kfree(sbi->fragment);
     2054                kfree(sbi->block_cache);
     2055                kfree(sbi->read_data);
     2056                kfree(sbi->read_page);
     2057                kfree(sbi->uid);
     2058                kfree(sbi->fragment_index);
     2059                kfree(sbi->fragment_index_2);
     2060                kfree(sbi->meta_index);
     2061                vfree(sbi->stream.workspace);
     2062                kfree(s->s_fs_info);
     2063                s->s_fs_info = NULL;
     2064        }
     2065}
     2066
     2067
     2068static int squashfs_get_sb(struct file_system_type *fs_type, int flags,
     2069                                const char *dev_name, void *data,
     2070                                struct vfsmount *mnt)
     2071{
     2072        return get_sb_bdev(fs_type, flags, dev_name, data, squashfs_fill_super,
     2073                                mnt);
     2074}
     2075
     2076
     2077static int __init init_squashfs_fs(void)
     2078{
     2079        int err = init_inodecache();
     2080        if (err)
     2081                goto out;
     2082
     2083        printk(KERN_INFO "squashfs: version 3.1 (2006/08/19) "
     2084                "Phillip Lougher\n");
     2085
     2086        if ((err = register_filesystem(&squashfs_fs_type)))
     2087                destroy_inodecache();
     2088
     2089out:
     2090        return err;
     2091}
     2092
     2093
     2094static void __exit exit_squashfs_fs(void)
     2095{
     2096        unregister_filesystem(&squashfs_fs_type);
     2097        destroy_inodecache();
     2098}
     2099
     2100
     2101static kmem_cache_t * squashfs_inode_cachep;
     2102
     2103
     2104static struct inode *squashfs_alloc_inode(struct super_block *sb)
     2105{
     2106        struct squashfs_inode_info *ei;
     2107        ei = kmem_cache_alloc(squashfs_inode_cachep, SLAB_KERNEL);
     2108        if (!ei)
     2109                return NULL;
     2110        return &ei->vfs_inode;
     2111}
     2112
     2113
     2114static void squashfs_destroy_inode(struct inode *inode)
     2115{
     2116        kmem_cache_free(squashfs_inode_cachep, SQUASHFS_I(inode));
     2117}
     2118
     2119
     2120static void init_once(void * foo, kmem_cache_t * cachep, unsigned long flags)
     2121{
     2122        struct squashfs_inode_info *ei = foo;
     2123
     2124        if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
     2125                                                        SLAB_CTOR_CONSTRUCTOR)
     2126                inode_init_once(&ei->vfs_inode);
     2127}
     2128 
     2129
     2130static int __init init_inodecache(void)
     2131{
     2132        squashfs_inode_cachep = kmem_cache_create("squashfs_inode_cache",
     2133             sizeof(struct squashfs_inode_info),
     2134             0, SLAB_HWCACHE_ALIGN|SLAB_RECLAIM_ACCOUNT,
     2135             init_once, NULL);
     2136        if (squashfs_inode_cachep == NULL)
     2137                return -ENOMEM;
     2138        return 0;
     2139}
     2140
     2141
     2142static void destroy_inodecache(void)
     2143{
     2144        kmem_cache_destroy(squashfs_inode_cachep);
     2145}
     2146
     2147
     2148module_init(init_squashfs_fs);
     2149module_exit(exit_squashfs_fs);
     2150MODULE_DESCRIPTION("squashfs 3.1, a compressed read-only filesystem");
     2151MODULE_AUTHOR("Phillip Lougher <phillip@lougher.org.uk>");
     2152MODULE_LICENSE("GPL");
  • fs/squashfs/squashfs.h

    diff -Nru linux-2.6.19.ori2/fs/squashfs/squashfs.h linux-2.6.19.ori/fs/squashfs/squashfs.h
    old new  
     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 * squashfs.h
     22 */
     23
     24#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
     25#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY
     26#endif
     27
     28#ifdef SQUASHFS_TRACE
     29#define TRACE(s, args...)       printk(KERN_NOTICE "SQUASHFS: "s, ## args)
     30#else
     31#define TRACE(s, args...)       {}
     32#endif
     33
     34#define ERROR(s, args...)       printk(KERN_ERR "SQUASHFS error: "s, ## args)
     35
     36#define SERROR(s, args...)      do { \
     37                                if (!silent) \
     38                                printk(KERN_ERR "SQUASHFS error: "s, ## args);\
     39                                } while(0)
     40
     41#define WARNING(s, args...)     printk(KERN_WARNING "SQUASHFS: "s, ## args)
     42
     43static inline struct squashfs_inode_info *SQUASHFS_I(struct inode *inode)
     44{
     45        return list_entry(inode, struct squashfs_inode_info, vfs_inode);
     46}
     47
     48#if defined(CONFIG_SQUASHFS_1_0_COMPATIBILITY ) || defined(CONFIG_SQUASHFS_2_0_COMPATIBILITY)
     49#define SQSH_EXTERN
     50extern unsigned int squashfs_read_data(struct super_block *s, char *buffer,
     51                                long long index, unsigned int length,
     52                                long long *next_index);
     53extern int squashfs_get_cached_block(struct super_block *s, char *buffer,
     54                                long long block, unsigned int offset,
     55                                int length, long long *next_block,
     56                                unsigned int *next_offset);
     57extern void release_cached_fragment(struct squashfs_sb_info *msblk, struct
     58                                        squashfs_fragment_cache *fragment);
     59extern struct squashfs_fragment_cache *get_cached_fragment(struct super_block
     60                                        *s, long long start_block,
     61                                        int length);
     62extern struct address_space_operations squashfs_symlink_aops;
     63extern struct address_space_operations squashfs_aops;
     64extern struct address_space_operations squashfs_aops_4K;
     65extern struct inode_operations squashfs_dir_inode_ops;
     66#else
     67#define SQSH_EXTERN static
     68#endif
     69
     70#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
     71extern int squashfs_1_0_supported(struct squashfs_sb_info *msblk);
     72#else
     73static inline int squashfs_1_0_supported(struct squashfs_sb_info *msblk)
     74{
     75        return 0;
     76}
     77#endif
     78
     79#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
     80extern int squashfs_2_0_supported(struct squashfs_sb_info *msblk);
     81#else
     82static inline int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
     83{
     84        return 0;
     85}
     86#endif
  • fs/squashfs/squashfs2_0.c

    diff -Nru linux-2.6.19.ori2/fs/squashfs/squashfs2_0.c linux-2.6.19.ori/fs/squashfs/squashfs2_0.c
    old new  
     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"
     47static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir);
     48static struct dentry *squashfs_lookup_2(struct inode *, struct dentry *,
     49                                struct nameidata *);
     50
     51static struct file_operations squashfs_dir_ops_2 = {
     52        .read = generic_read_dir,
     53        .readdir = squashfs_readdir_2
     54};
     55
     56static struct inode_operations squashfs_dir_inode_ops_2 = {
     57        .lookup = squashfs_lookup_2
     58};
     59
     60static unsigned char squashfs_filetype_table[] = {
     61        DT_UNKNOWN, DT_DIR, DT_REG, DT_LNK, DT_BLK, DT_CHR, DT_FIFO, DT_SOCK
     62};
     63
     64static 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)) {
     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
     102static 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
     133out:
     134        return 0;
     135}
     136
     137
     138static struct inode *squashfs_new_inode(struct super_block *s,
     139                struct squashfs_base_inode_header_2 *inodeb, unsigned int ino)
     140{
     141        struct squashfs_sb_info *msblk = s->s_fs_info;
     142        struct squashfs_super_block *sblk = &msblk->sblk;
     143        struct inode *i = new_inode(s);
     144
     145        if (i) {
     146                i->i_ino = ino;
     147                i->i_mtime.tv_sec = sblk->mkfs_time;
     148                i->i_atime.tv_sec = sblk->mkfs_time;
     149                i->i_ctime.tv_sec = sblk->mkfs_time;
     150                i->i_uid = msblk->uid[inodeb->uid];
     151                i->i_mode = inodeb->mode;
     152                i->i_nlink = 1;
     153                i->i_size = 0;
     154                if (inodeb->guid == SQUASHFS_GUIDS)
     155                        i->i_gid = i->i_uid;
     156                else
     157                        i->i_gid = msblk->guid[inodeb->guid];
     158        }
     159
     160        return i;
     161}
     162
     163
     164static struct inode *squashfs_iget_2(struct super_block *s, squashfs_inode_t inode)
     165{
     166        struct inode *i;
     167        struct squashfs_sb_info *msblk = s->s_fs_info;
     168        struct squashfs_super_block *sblk = &msblk->sblk;
     169        unsigned int block = SQUASHFS_INODE_BLK(inode) +
     170                sblk->inode_table_start;
     171        unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
     172        unsigned int ino = SQUASHFS_MK_VFS_INODE(block
     173                - sblk->inode_table_start, offset);
     174        long long next_block;
     175        unsigned int next_offset;
     176        union squashfs_inode_header_2 id, sid;
     177        struct squashfs_base_inode_header_2 *inodeb = &id.base,
     178                                          *sinodeb = &sid.base;
     179
     180        TRACE("Entered squashfs_iget\n");
     181
     182        if (msblk->swap) {
     183                if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
     184                                        offset, sizeof(*sinodeb), &next_block,
     185                                        &next_offset))
     186                        goto failed_read;
     187                SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb,
     188                                        sizeof(*sinodeb));
     189        } else
     190                if (!squashfs_get_cached_block(s, (char *) inodeb, block,
     191                                        offset, sizeof(*inodeb), &next_block,
     192                                        &next_offset))
     193                        goto failed_read;
     194
     195        switch(inodeb->inode_type) {
     196                case SQUASHFS_FILE_TYPE: {
     197                        struct squashfs_reg_inode_header_2 *inodep = &id.reg;
     198                        struct squashfs_reg_inode_header_2 *sinodep = &sid.reg;
     199                        long long frag_blk;
     200                        unsigned int frag_size;
     201                               
     202                        if (msblk->swap) {
     203                                if (!squashfs_get_cached_block(s, (char *)
     204                                                sinodep, block, offset,
     205                                                sizeof(*sinodep), &next_block,
     206                                                &next_offset))
     207                                        goto failed_read;
     208                                SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep);
     209                        } else
     210                                if (!squashfs_get_cached_block(s, (char *)
     211                                                inodep, block, offset,
     212                                                sizeof(*inodep), &next_block,
     213                                                &next_offset))
     214                                        goto failed_read;
     215
     216                        frag_blk = SQUASHFS_INVALID_BLK;
     217                        if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
     218                                        !get_fragment_location_2(s,
     219                                        inodep->fragment, &frag_blk, &frag_size))
     220                                goto failed_read;
     221                               
     222                        if((i = squashfs_new_inode(s, inodeb, ino)) == NULL)
     223                                goto failed_read1;
     224
     225                        i->i_size = inodep->file_size;
     226                        i->i_fop = &generic_ro_fops;
     227                        i->i_mode |= S_IFREG;
     228                        i->i_mtime.tv_sec = inodep->mtime;
     229                        i->i_atime.tv_sec = inodep->mtime;
     230                        i->i_ctime.tv_sec = inodep->mtime;
     231                        i->i_blocks = ((i->i_size - 1) >> 9) + 1;
     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        struct squashfs_dir_index_2 *index;
     489        char *str;
     490
     491        TRACE("Entered get_dir_index_using_name, i_count %d\n", i_count);
     492
     493        if (!(str = kmalloc(sizeof(struct squashfs_dir_index) +
     494                (SQUASHFS_NAME_LEN + 1) * 2, GFP_KERNEL))) {
     495                ERROR("Failed to allocate squashfs_dir_index\n");
     496                goto failure;
     497        }
     498
     499        index = (struct squashfs_dir_index_2 *) (str + SQUASHFS_NAME_LEN + 1);
     500        strncpy(str, name, size);
     501        str[size] = '\0';
     502
     503        for (i = 0; i < i_count; i++) {
     504                if (msblk->swap) {
     505                        struct squashfs_dir_index_2 sindex;
     506                        squashfs_get_cached_block(s, (char *) &sindex,
     507                                        index_start, index_offset,
     508                                        sizeof(sindex), &index_start,
     509                                        &index_offset);
     510                        SQUASHFS_SWAP_DIR_INDEX_2(index, &sindex);
     511                } else
     512                        squashfs_get_cached_block(s, (char *) index,
     513                                        index_start, index_offset,
     514                                        sizeof(struct squashfs_dir_index_2),
     515                                        &index_start, &index_offset);
     516
     517                squashfs_get_cached_block(s, index->name, index_start,
     518                                        index_offset, index->size + 1,
     519                                        &index_start, &index_offset);
     520
     521                index->name[index->size + 1] = '\0';
     522
     523                if (strcmp(index->name, str) > 0)
     524                        break;
     525
     526                length = index->index;
     527                *next_block = index->start_block + sblk->directory_table_start;
     528        }
     529
     530        *next_offset = (length + *next_offset) % SQUASHFS_METADATA_SIZE;
     531        kfree(str);
     532failure:
     533        return length;
     534}
     535
     536               
     537static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir)
     538{
     539        struct inode *i = file->f_dentry->d_inode;
     540        struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
     541        struct squashfs_super_block *sblk = &msblk->sblk;
     542        long long next_block = SQUASHFS_I(i)->start_block +
     543                sblk->directory_table_start;
     544        int next_offset = SQUASHFS_I(i)->offset, length = 0,
     545                dir_count;
     546        struct squashfs_dir_header_2 dirh;
     547        struct squashfs_dir_entry_2 *dire;
     548
     549        TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset);
     550
     551        if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
     552                SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
     553                ERROR("Failed to allocate squashfs_dir_entry\n");
     554                goto finish;
     555        }
     556
     557        length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
     558                                SQUASHFS_I(i)->u.s2.directory_index_start,
     559                                SQUASHFS_I(i)->u.s2.directory_index_offset,
     560                                SQUASHFS_I(i)->u.s2.directory_index_count,
     561                                file->f_pos);
     562
     563        while (length < i_size_read(i)) {
     564                /* read directory header */
     565                if (msblk->swap) {
     566                        struct squashfs_dir_header_2 sdirh;
     567                       
     568                        if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
     569                                        next_block, next_offset, sizeof(sdirh),
     570                                        &next_block, &next_offset))
     571                                goto failed_read;
     572
     573                        length += sizeof(sdirh);
     574                        SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
     575                } else {
     576                        if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
     577                                        next_block, next_offset, sizeof(dirh),
     578                                        &next_block, &next_offset))
     579                                goto failed_read;
     580
     581                        length += sizeof(dirh);
     582                }
     583
     584                dir_count = dirh.count + 1;
     585                while (dir_count--) {
     586                        if (msblk->swap) {
     587                                struct squashfs_dir_entry_2 sdire;
     588                                if (!squashfs_get_cached_block(i->i_sb, (char *)
     589                                                &sdire, next_block, next_offset,
     590                                                sizeof(sdire), &next_block,
     591                                                &next_offset))
     592                                        goto failed_read;
     593                               
     594                                length += sizeof(sdire);
     595                                SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
     596                        } else {
     597                                if (!squashfs_get_cached_block(i->i_sb, (char *)
     598                                                dire, next_block, next_offset,
     599                                                sizeof(*dire), &next_block,
     600                                                &next_offset))
     601                                        goto failed_read;
     602
     603                                length += sizeof(*dire);
     604                        }
     605
     606                        if (!squashfs_get_cached_block(i->i_sb, dire->name,
     607                                                next_block, next_offset,
     608                                                dire->size + 1, &next_block,
     609                                                &next_offset))
     610                                goto failed_read;
     611
     612                        length += dire->size + 1;
     613
     614                        if (file->f_pos >= length)
     615                                continue;
     616
     617                        dire->name[dire->size + 1] = '\0';
     618
     619                        TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n",
     620                                        (unsigned int) dirent, dire->name,
     621                                        dire->size + 1, (int) file->f_pos,
     622                                        dirh.start_block, dire->offset,
     623                                        squashfs_filetype_table[dire->type]);
     624
     625                        if (filldir(dirent, dire->name, dire->size + 1,
     626                                        file->f_pos, SQUASHFS_MK_VFS_INODE(
     627                                        dirh.start_block, dire->offset),
     628                                        squashfs_filetype_table[dire->type])
     629                                        < 0) {
     630                                TRACE("Filldir returned less than 0\n");
     631                                goto finish;
     632                        }
     633                        file->f_pos = length;
     634                }
     635        }
     636
     637finish:
     638        kfree(dire);
     639        return 0;
     640
     641failed_read:
     642        ERROR("Unable to read directory block [%llx:%x]\n", next_block,
     643                next_offset);
     644        kfree(dire);
     645        return 0;
     646}
     647
     648
     649static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry,
     650                                struct nameidata *nd)
     651{
     652        const unsigned char *name = dentry->d_name.name;
     653        int len = dentry->d_name.len;
     654        struct inode *inode = NULL;
     655        struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
     656        struct squashfs_super_block *sblk = &msblk->sblk;
     657        long long next_block = SQUASHFS_I(i)->start_block +
     658                                sblk->directory_table_start;
     659        int next_offset = SQUASHFS_I(i)->offset, length = 0,
     660                                dir_count;
     661        struct squashfs_dir_header_2 dirh;
     662        struct squashfs_dir_entry_2 *dire;
     663        int sorted = sblk->s_major == 2 && sblk->s_minor >= 1;
     664
     665        TRACE("Entered squashfs_lookup_2 [%llx:%x]\n", next_block, next_offset);
     666
     667        if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
     668                SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
     669                ERROR("Failed to allocate squashfs_dir_entry\n");
     670                goto exit_loop;
     671        }
     672
     673        if (len > SQUASHFS_NAME_LEN)
     674                goto exit_loop;
     675
     676        length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
     677                                SQUASHFS_I(i)->u.s2.directory_index_start,
     678                                SQUASHFS_I(i)->u.s2.directory_index_offset,
     679                                SQUASHFS_I(i)->u.s2.directory_index_count, name,
     680                                len);
     681
     682        while (length < i_size_read(i)) {
     683                /* read directory header */
     684                if (msblk->swap) {
     685                        struct squashfs_dir_header_2 sdirh;
     686                        if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
     687                                        next_block, next_offset, sizeof(sdirh),
     688                                        &next_block, &next_offset))
     689                                goto failed_read;
     690
     691                        length += sizeof(sdirh);
     692                        SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
     693                } else {
     694                        if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
     695                                        next_block, next_offset, sizeof(dirh),
     696                                        &next_block, &next_offset))
     697                                goto failed_read;
     698
     699                        length += sizeof(dirh);
     700                }
     701
     702                dir_count = dirh.count + 1;
     703                while (dir_count--) {
     704                        if (msblk->swap) {
     705                                struct squashfs_dir_entry_2 sdire;
     706                                if (!squashfs_get_cached_block(i->i_sb, (char *)
     707                                                &sdire, next_block,next_offset,
     708                                                sizeof(sdire), &next_block,
     709                                                &next_offset))
     710                                        goto failed_read;
     711                               
     712                                length += sizeof(sdire);
     713                                SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
     714                        } else {
     715                                if (!squashfs_get_cached_block(i->i_sb, (char *)
     716                                                dire, next_block,next_offset,
     717                                                sizeof(*dire), &next_block,
     718                                                &next_offset))
     719                                        goto failed_read;
     720
     721                                length += sizeof(*dire);
     722                        }
     723
     724                        if (!squashfs_get_cached_block(i->i_sb, dire->name,
     725                                        next_block, next_offset, dire->size + 1,
     726                                        &next_block, &next_offset))
     727                                goto failed_read;
     728
     729                        length += dire->size + 1;
     730
     731                        if (sorted && name[0] < dire->name[0])
     732                                goto exit_loop;
     733
     734                        if ((len == dire->size + 1) && !strncmp(name,
     735                                                dire->name, len)) {
     736                                squashfs_inode_t ino =
     737                                        SQUASHFS_MKINODE(dirh.start_block,
     738                                        dire->offset);
     739
     740                                TRACE("calling squashfs_iget for directory "
     741                                        "entry %s, inode %x:%x, %lld\n", name,
     742                                        dirh.start_block, dire->offset, ino);
     743
     744                                inode = (msblk->iget)(i->i_sb, ino);
     745
     746                                goto exit_loop;
     747                        }
     748                }
     749        }
     750
     751exit_loop:
     752        kfree(dire);
     753        d_add(dentry, inode);
     754        return ERR_PTR(0);
     755
     756failed_read:
     757        ERROR("Unable to read directory block [%llx:%x]\n", next_block,
     758                next_offset);
     759        goto exit_loop;
     760}
     761
     762
     763int squashfs_2_0_supported(struct squashfs_sb_info *msblk)
     764{
     765        struct squashfs_super_block *sblk = &msblk->sblk;
     766
     767        msblk->iget = squashfs_iget_2;
     768        msblk->read_fragment_index_table = read_fragment_index_table_2;
     769
     770        sblk->bytes_used = sblk->bytes_used_2;
     771        sblk->uid_start = sblk->uid_start_2;
     772        sblk->guid_start = sblk->guid_start_2;
     773        sblk->inode_table_start = sblk->inode_table_start_2;
     774        sblk->directory_table_start = sblk->directory_table_start_2;
     775        sblk->fragment_table_start = sblk->fragment_table_start_2;
     776
     777        return 1;
     778}
  • include/linux/squashfs_fs.h

    diff -Nru linux-2.6.19.ori2/include/linux/squashfs_fs.h linux-2.6.19.ori/include/linux/squashfs_fs.h
    old new  
     1#ifndef SQUASHFS_FS
     2#define SQUASHFS_FS
     3
     4/*
     5 * Squashfs
     6 *
     7 * Copyright (c) 2002, 2003, 2004, 2005, 2006
     8 * Phillip Lougher <phillip@lougher.org.uk>
     9 *
     10 * This program is free software; you can redistribute it and/or
     11 * modify it under the terms of the GNU General Public License
     12 * as published by the Free Software Foundation; either version 2,
     13 * or (at your option) any later version.
     14 *
     15 * This program is distributed in the hope that it will be useful,
     16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     18 * GNU General Public License for more details.
     19 *
     20 * You should have received a copy of the GNU General Public License
     21 * along with this program; if not, write to the Free Software
     22 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     23 *
     24 * squashfs_fs.h
     25 */
     26
     27#ifndef CONFIG_SQUASHFS_2_0_COMPATIBILITY
     28#define CONFIG_SQUASHFS_2_0_COMPATIBILITY
     29#endif
     30
     31#ifdef  CONFIG_SQUASHFS_VMALLOC
     32#define SQUASHFS_ALLOC(a)               vmalloc(a)
     33#define SQUASHFS_FREE(a)                vfree(a)
     34#else
     35#define SQUASHFS_ALLOC(a)               kmalloc(a, GFP_KERNEL)
     36#define SQUASHFS_FREE(a)                kfree(a)
     37#endif
     38#define SQUASHFS_CACHED_FRAGMENTS       CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE     
     39#define SQUASHFS_MAJOR                  3
     40#define SQUASHFS_MINOR                  0
     41#define SQUASHFS_MAGIC                  0x73717368
     42#define SQUASHFS_MAGIC_SWAP             0x68737173
     43#define SQUASHFS_START                  0
     44
     45/* size of metadata (inode and directory) blocks */
     46#define SQUASHFS_METADATA_SIZE          8192
     47#define SQUASHFS_METADATA_LOG           13
     48
     49/* default size of data blocks */
     50#define SQUASHFS_FILE_SIZE              65536
     51#define SQUASHFS_FILE_LOG               16
     52
     53#define SQUASHFS_FILE_MAX_SIZE          65536
     54
     55/* Max number of uids and gids */
     56#define SQUASHFS_UIDS                   256
     57#define SQUASHFS_GUIDS                  255
     58
     59/* Max length of filename (not 255) */
     60#define SQUASHFS_NAME_LEN               256
     61
     62#define SQUASHFS_INVALID                ((long long) 0xffffffffffff)
     63#define SQUASHFS_INVALID_FRAG           ((unsigned int) 0xffffffff)
     64#define SQUASHFS_INVALID_BLK            ((long long) -1)
     65#define SQUASHFS_USED_BLK               ((long long) -2)
     66
     67/* Filesystem flags */
     68#define SQUASHFS_NOI                    0
     69#define SQUASHFS_NOD                    1
     70#define SQUASHFS_CHECK                  2
     71#define SQUASHFS_NOF                    3
     72#define SQUASHFS_NO_FRAG                4
     73#define SQUASHFS_ALWAYS_FRAG            5
     74#define SQUASHFS_DUPLICATE              6
     75
     76#define SQUASHFS_BIT(flag, bit)         ((flag >> bit) & 1)
     77
     78#define SQUASHFS_UNCOMPRESSED_INODES(flags)     SQUASHFS_BIT(flags, \
     79                                                SQUASHFS_NOI)
     80
     81#define SQUASHFS_UNCOMPRESSED_DATA(flags)       SQUASHFS_BIT(flags, \
     82                                                SQUASHFS_NOD)
     83
     84#define SQUASHFS_UNCOMPRESSED_FRAGMENTS(flags)  SQUASHFS_BIT(flags, \
     85                                                SQUASHFS_NOF)
     86
     87#define SQUASHFS_NO_FRAGMENTS(flags)            SQUASHFS_BIT(flags, \
     88                                                SQUASHFS_NO_FRAG)
     89
     90#define SQUASHFS_ALWAYS_FRAGMENTS(flags)        SQUASHFS_BIT(flags, \
     91                                                SQUASHFS_ALWAYS_FRAG)
     92
     93#define SQUASHFS_DUPLICATES(flags)              SQUASHFS_BIT(flags, \
     94                                                SQUASHFS_DUPLICATE)
     95
     96#define SQUASHFS_CHECK_DATA(flags)              SQUASHFS_BIT(flags, \
     97                                                SQUASHFS_CHECK)
     98
     99#define SQUASHFS_MKFLAGS(noi, nod, check_data, nof, no_frag, always_frag, \
     100                duplicate_checking)     (noi | (nod << 1) | (check_data << 2) \
     101                | (nof << 3) | (no_frag << 4) | (always_frag << 5) | \
     102                (duplicate_checking << 6))
     103
     104/* Max number of types and file types */
     105#define SQUASHFS_DIR_TYPE               1
     106#define SQUASHFS_FILE_TYPE              2
     107#define SQUASHFS_SYMLINK_TYPE           3
     108#define SQUASHFS_BLKDEV_TYPE            4
     109#define SQUASHFS_CHRDEV_TYPE            5
     110#define SQUASHFS_FIFO_TYPE              6
     111#define SQUASHFS_SOCKET_TYPE            7
     112#define SQUASHFS_LDIR_TYPE              8
     113#define SQUASHFS_LREG_TYPE              9
     114
     115/* 1.0 filesystem type definitions */
     116#define SQUASHFS_TYPES                  5
     117#define SQUASHFS_IPC_TYPE               0
     118
     119/* Flag whether block is compressed or uncompressed, bit is set if block is
     120 * uncompressed */
     121#define SQUASHFS_COMPRESSED_BIT         (1 << 15)
     122
     123#define SQUASHFS_COMPRESSED_SIZE(B)     (((B) & ~SQUASHFS_COMPRESSED_BIT) ? \
     124                (B) & ~SQUASHFS_COMPRESSED_BIT :  SQUASHFS_COMPRESSED_BIT)
     125
     126#define SQUASHFS_COMPRESSED(B)          (!((B) & SQUASHFS_COMPRESSED_BIT))
     127
     128#define SQUASHFS_COMPRESSED_BIT_BLOCK           (1 << 24)
     129
     130#define SQUASHFS_COMPRESSED_SIZE_BLOCK(B)       (((B) & \
     131        ~SQUASHFS_COMPRESSED_BIT_BLOCK) ? (B) & \
     132        ~SQUASHFS_COMPRESSED_BIT_BLOCK : SQUASHFS_COMPRESSED_BIT_BLOCK)
     133
     134#define SQUASHFS_COMPRESSED_BLOCK(B)    (!((B) & SQUASHFS_COMPRESSED_BIT_BLOCK))
     135
     136/*
     137 * Inode number ops.  Inodes consist of a compressed block number, and an
     138 * uncompressed  offset within that block
     139 */
     140#define SQUASHFS_INODE_BLK(a)           ((unsigned int) ((a) >> 16))
     141
     142#define SQUASHFS_INODE_OFFSET(a)        ((unsigned int) ((a) & 0xffff))
     143
     144#define SQUASHFS_MKINODE(A, B)          ((squashfs_inode_t)(((squashfs_inode_t) (A)\
     145                                        << 16) + (B)))
     146
     147/* Compute 32 bit VFS inode number from squashfs inode number */
     148#define SQUASHFS_MK_VFS_INODE(a, b)     ((unsigned int) (((a) << 8) + \
     149                                        ((b) >> 2) + 1))
     150/* XXX */
     151
     152/* Translate between VFS mode and squashfs mode */
     153#define SQUASHFS_MODE(a)                ((a) & 0xfff)
     154
     155/* fragment and fragment table defines */
     156#define SQUASHFS_FRAGMENT_BYTES(A)      (A * sizeof(struct squashfs_fragment_entry))
     157
     158#define SQUASHFS_FRAGMENT_INDEX(A)      (SQUASHFS_FRAGMENT_BYTES(A) / \
     159                                        SQUASHFS_METADATA_SIZE)
     160
     161#define SQUASHFS_FRAGMENT_INDEX_OFFSET(A)       (SQUASHFS_FRAGMENT_BYTES(A) % \
     162                                                SQUASHFS_METADATA_SIZE)
     163
     164#define SQUASHFS_FRAGMENT_INDEXES(A)    ((SQUASHFS_FRAGMENT_BYTES(A) + \
     165                                        SQUASHFS_METADATA_SIZE - 1) / \
     166                                        SQUASHFS_METADATA_SIZE)
     167
     168#define SQUASHFS_FRAGMENT_INDEX_BYTES(A)        (SQUASHFS_FRAGMENT_INDEXES(A) *\
     169                                                sizeof(long long))
     170
     171/* cached data constants for filesystem */
     172#define SQUASHFS_CACHED_BLKS            8
     173
     174#define SQUASHFS_MAX_FILE_SIZE_LOG      64
     175
     176#define SQUASHFS_MAX_FILE_SIZE          ((long long) 1 << \
     177                                        (SQUASHFS_MAX_FILE_SIZE_LOG - 2))
     178
     179#define SQUASHFS_MARKER_BYTE            0xff
     180
     181/* meta index cache */
     182#define SQUASHFS_META_INDEXES   (SQUASHFS_METADATA_SIZE / sizeof(unsigned int))
     183#define SQUASHFS_META_ENTRIES   31
     184#define SQUASHFS_META_NUMBER    8
     185#define SQUASHFS_SLOTS          4
     186
     187struct meta_entry {
     188        long long               data_block;
     189        unsigned int            index_block;
     190        unsigned short          offset;
     191        unsigned short          pad;
     192};
     193
     194struct meta_index {
     195        unsigned int            inode_number;
     196        unsigned int            offset;
     197        unsigned short          entries;
     198        unsigned short          skip;
     199        unsigned short          locked;
     200        unsigned short          pad;
     201        struct meta_entry       meta_entry[SQUASHFS_META_ENTRIES];
     202};
     203
     204
     205/*
     206 * definitions for structures on disk
     207 */
     208
     209typedef long long               squashfs_block_t;
     210typedef long long               squashfs_inode_t;
     211
     212struct squashfs_super_block {
     213        unsigned int            s_magic;
     214        unsigned int            inodes;
     215        unsigned int            bytes_used_2;
     216        unsigned int            uid_start_2;
     217        unsigned int            guid_start_2;
     218        unsigned int            inode_table_start_2;
     219        unsigned int            directory_table_start_2;
     220        unsigned int            s_major:16;
     221        unsigned int            s_minor:16;
     222        unsigned int            block_size_1:16;
     223        unsigned int            block_log:16;
     224        unsigned int            flags:8;
     225        unsigned int            no_uids:8;
     226        unsigned int            no_guids:8;
     227        unsigned int            mkfs_time /* time of filesystem creation */;
     228        squashfs_inode_t        root_inode;
     229        unsigned int            block_size;
     230        unsigned int            fragments;
     231        unsigned int            fragment_table_start_2;
     232        long long               bytes_used;
     233        long long               uid_start;
     234        long long               guid_start;
     235        long long               inode_table_start;
     236        long long               directory_table_start;
     237        long long               fragment_table_start;
     238        long long               unused;
     239} __attribute__ ((packed));
     240
     241struct squashfs_dir_index {
     242        unsigned int            index;
     243        unsigned int            start_block;
     244        unsigned char           size;
     245        unsigned char           name[0];
     246} __attribute__ ((packed));
     247
     248#define SQUASHFS_BASE_INODE_HEADER              \
     249        unsigned int            inode_type:4;   \
     250        unsigned int            mode:12;        \
     251        unsigned int            uid:8;          \
     252        unsigned int            guid:8;         \
     253        unsigned int            mtime;          \
     254        unsigned int            inode_number;
     255
     256struct squashfs_base_inode_header {
     257        SQUASHFS_BASE_INODE_HEADER;
     258} __attribute__ ((packed));
     259
     260struct squashfs_ipc_inode_header {
     261        SQUASHFS_BASE_INODE_HEADER;
     262        unsigned int            nlink;
     263} __attribute__ ((packed));
     264
     265struct squashfs_dev_inode_header {
     266        SQUASHFS_BASE_INODE_HEADER;
     267        unsigned int            nlink;
     268        unsigned short          rdev;
     269} __attribute__ ((packed));
     270       
     271struct squashfs_symlink_inode_header {
     272        SQUASHFS_BASE_INODE_HEADER;
     273        unsigned int            nlink;
     274        unsigned short          symlink_size;
     275        char                    symlink[0];
     276} __attribute__ ((packed));
     277
     278struct squashfs_reg_inode_header {
     279        SQUASHFS_BASE_INODE_HEADER;
     280        squashfs_block_t        start_block;
     281        unsigned int            fragment;
     282        unsigned int            offset;
     283        unsigned int            file_size;
     284        unsigned short          block_list[0];
     285} __attribute__ ((packed));
     286
     287struct squashfs_lreg_inode_header {
     288        SQUASHFS_BASE_INODE_HEADER;
     289        unsigned int            nlink;
     290        squashfs_block_t        start_block;
     291        unsigned int            fragment;
     292        unsigned int            offset;
     293        long long               file_size;
     294        unsigned short          block_list[0];
     295} __attribute__ ((packed));
     296
     297struct squashfs_dir_inode_header {
     298        SQUASHFS_BASE_INODE_HEADER;
     299        unsigned int            nlink;
     300        unsigned int            file_size:19;
     301        unsigned int            offset:13;
     302        unsigned int            start_block;
     303        unsigned int            parent_inode;
     304} __attribute__  ((packed));
     305
     306struct squashfs_ldir_inode_header {
     307        SQUASHFS_BASE_INODE_HEADER;
     308        unsigned int            nlink;
     309        unsigned int            file_size:27;
     310        unsigned int            offset:13;
     311        unsigned int            start_block;
     312        unsigned int            i_count:16;
     313        unsigned int            parent_inode;
     314        struct squashfs_dir_index       index[0];
     315} __attribute__  ((packed));
     316
     317union squashfs_inode_header {
     318        struct squashfs_base_inode_header       base;
     319        struct squashfs_dev_inode_header        dev;
     320        struct squashfs_symlink_inode_header    symlink;
     321        struct squashfs_reg_inode_header        reg;
     322        struct squashfs_lreg_inode_header       lreg;
     323        struct squashfs_dir_inode_header        dir;
     324        struct squashfs_ldir_inode_header       ldir;
     325        struct squashfs_ipc_inode_header        ipc;
     326};
     327       
     328struct squashfs_dir_entry {
     329        unsigned int            offset:13;
     330        unsigned int            type:3;
     331        unsigned int            size:8;
     332        int                     inode_number:16;
     333        char                    name[0];
     334} __attribute__ ((packed));
     335
     336struct squashfs_dir_header {
     337        unsigned int            count:8;
     338        unsigned int            start_block;
     339        unsigned int            inode_number;
     340} __attribute__ ((packed));
     341
     342struct squashfs_fragment_entry {
     343        long long               start_block;
     344        unsigned int            size;
     345        unsigned int            unused;
     346} __attribute__ ((packed));
     347
     348extern int squashfs_uncompress_block(void *d, int dstlen, void *s, int srclen);
     349extern int squashfs_uncompress_init(void);
     350extern int squashfs_uncompress_exit(void);
     351
     352/*
     353 * macros to convert each packed bitfield structure from little endian to big
     354 * endian and vice versa.  These are needed when creating or using a filesystem
     355 * on a machine with different byte ordering to the target architecture.
     356 *
     357 */
     358
     359#define SQUASHFS_SWAP_START \
     360        int bits;\
     361        int b_pos;\
     362        unsigned long long val;\
     363        unsigned char *s;\
     364        unsigned char *d;
     365
     366#define SQUASHFS_SWAP_SUPER_BLOCK(s, d) {\
     367        SQUASHFS_SWAP_START\
     368        SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_super_block));\
     369        SQUASHFS_SWAP((s)->s_magic, d, 0, 32);\
     370        SQUASHFS_SWAP((s)->inodes, d, 32, 32);\
     371        SQUASHFS_SWAP((s)->bytes_used_2, d, 64, 32);\
     372        SQUASHFS_SWAP((s)->uid_start_2, d, 96, 32);\
     373        SQUASHFS_SWAP((s)->guid_start_2, d, 128, 32);\
     374        SQUASHFS_SWAP((s)->inode_table_start_2, d, 160, 32);\
     375        SQUASHFS_SWAP((s)->directory_table_start_2, d, 192, 32);\
     376        SQUASHFS_SWAP((s)->s_major, d, 224, 16);\
     377        SQUASHFS_SWAP((s)->s_minor, d, 240, 16);\
     378        SQUASHFS_SWAP((s)->block_size_1, d, 256, 16);\
     379        SQUASHFS_SWAP((s)->block_log, d, 272, 16);\
     380        SQUASHFS_SWAP((s)->flags, d, 288, 8);\
     381        SQUASHFS_SWAP((s)->no_uids, d, 296, 8);\
     382        SQUASHFS_SWAP((s)->no_guids, d, 304, 8);\
     383        SQUASHFS_SWAP((s)->mkfs_time, d, 312, 32);\
     384        SQUASHFS_SWAP((s)->root_inode, d, 344, 64);\
     385        SQUASHFS_SWAP((s)->block_size, d, 408, 32);\
     386        SQUASHFS_SWAP((s)->fragments, d, 440, 32);\
     387        SQUASHFS_SWAP((s)->fragment_table_start_2, d, 472, 32);\
     388        SQUASHFS_SWAP((s)->bytes_used, d, 504, 64);\
     389        SQUASHFS_SWAP((s)->uid_start, d, 568, 64);\
     390        SQUASHFS_SWAP((s)->guid_start, d, 632, 64);\
     391        SQUASHFS_SWAP((s)->inode_table_start, d, 696, 64);\
     392        SQUASHFS_SWAP((s)->directory_table_start, d, 760, 64);\
     393        SQUASHFS_SWAP((s)->fragment_table_start, d, 824, 64);\
     394        SQUASHFS_SWAP((s)->unused, d, 888, 64);\
     395}
     396
     397#define SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
     398        SQUASHFS_MEMSET(s, d, n);\
     399        SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
     400        SQUASHFS_SWAP((s)->mode, d, 4, 12);\
     401        SQUASHFS_SWAP((s)->uid, d, 16, 8);\
     402        SQUASHFS_SWAP((s)->guid, d, 24, 8);\
     403        SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
     404        SQUASHFS_SWAP((s)->inode_number, d, 64, 32);
     405
     406#define SQUASHFS_SWAP_BASE_INODE_HEADER(s, d, n) {\
     407        SQUASHFS_SWAP_START\
     408        SQUASHFS_SWAP_BASE_INODE_CORE(s, d, n)\
     409}
     410
     411#define SQUASHFS_SWAP_IPC_INODE_HEADER(s, d) {\
     412        SQUASHFS_SWAP_START\
     413        SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
     414                        sizeof(struct squashfs_ipc_inode_header))\
     415        SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
     416}
     417
     418#define SQUASHFS_SWAP_DEV_INODE_HEADER(s, d) {\
     419        SQUASHFS_SWAP_START\
     420        SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
     421                        sizeof(struct squashfs_dev_inode_header)); \
     422        SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
     423        SQUASHFS_SWAP((s)->rdev, d, 128, 16);\
     424}
     425
     426#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER(s, d) {\
     427        SQUASHFS_SWAP_START\
     428        SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
     429                        sizeof(struct squashfs_symlink_inode_header));\
     430        SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
     431        SQUASHFS_SWAP((s)->symlink_size, d, 128, 16);\
     432}
     433
     434#define SQUASHFS_SWAP_REG_INODE_HEADER(s, d) {\
     435        SQUASHFS_SWAP_START\
     436        SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
     437                        sizeof(struct squashfs_reg_inode_header));\
     438        SQUASHFS_SWAP((s)->start_block, d, 96, 64);\
     439        SQUASHFS_SWAP((s)->fragment, d, 160, 32);\
     440        SQUASHFS_SWAP((s)->offset, d, 192, 32);\
     441        SQUASHFS_SWAP((s)->file_size, d, 224, 32);\
     442}
     443
     444#define SQUASHFS_SWAP_LREG_INODE_HEADER(s, d) {\
     445        SQUASHFS_SWAP_START\
     446        SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
     447                        sizeof(struct squashfs_lreg_inode_header));\
     448        SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
     449        SQUASHFS_SWAP((s)->start_block, d, 128, 64);\
     450        SQUASHFS_SWAP((s)->fragment, d, 192, 32);\
     451        SQUASHFS_SWAP((s)->offset, d, 224, 32);\
     452        SQUASHFS_SWAP((s)->file_size, d, 256, 64);\
     453}
     454
     455#define SQUASHFS_SWAP_DIR_INODE_HEADER(s, d) {\
     456        SQUASHFS_SWAP_START\
     457        SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
     458                        sizeof(struct squashfs_dir_inode_header));\
     459        SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
     460        SQUASHFS_SWAP((s)->file_size, d, 128, 19);\
     461        SQUASHFS_SWAP((s)->offset, d, 147, 13);\
     462        SQUASHFS_SWAP((s)->start_block, d, 160, 32);\
     463        SQUASHFS_SWAP((s)->parent_inode, d, 192, 32);\
     464}
     465
     466#define SQUASHFS_SWAP_LDIR_INODE_HEADER(s, d) {\
     467        SQUASHFS_SWAP_START\
     468        SQUASHFS_SWAP_BASE_INODE_CORE(s, d, \
     469                        sizeof(struct squashfs_ldir_inode_header));\
     470        SQUASHFS_SWAP((s)->nlink, d, 96, 32);\
     471        SQUASHFS_SWAP((s)->file_size, d, 128, 27);\
     472        SQUASHFS_SWAP((s)->offset, d, 155, 13);\
     473        SQUASHFS_SWAP((s)->start_block, d, 168, 32);\
     474        SQUASHFS_SWAP((s)->i_count, d, 200, 16);\
     475        SQUASHFS_SWAP((s)->parent_inode, d, 216, 32);\
     476}
     477
     478#define SQUASHFS_SWAP_DIR_INDEX(s, d) {\
     479        SQUASHFS_SWAP_START\
     480        SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index));\
     481        SQUASHFS_SWAP((s)->index, d, 0, 32);\
     482        SQUASHFS_SWAP((s)->start_block, d, 32, 32);\
     483        SQUASHFS_SWAP((s)->size, d, 64, 8);\
     484}
     485
     486#define SQUASHFS_SWAP_DIR_HEADER(s, d) {\
     487        SQUASHFS_SWAP_START\
     488        SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header));\
     489        SQUASHFS_SWAP((s)->count, d, 0, 8);\
     490        SQUASHFS_SWAP((s)->start_block, d, 8, 32);\
     491        SQUASHFS_SWAP((s)->inode_number, d, 40, 32);\
     492}
     493
     494#define SQUASHFS_SWAP_DIR_ENTRY(s, d) {\
     495        SQUASHFS_SWAP_START\
     496        SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry));\
     497        SQUASHFS_SWAP((s)->offset, d, 0, 13);\
     498        SQUASHFS_SWAP((s)->type, d, 13, 3);\
     499        SQUASHFS_SWAP((s)->size, d, 16, 8);\
     500        SQUASHFS_SWAP((s)->inode_number, d, 24, 16);\
     501}
     502
     503#define SQUASHFS_SWAP_FRAGMENT_ENTRY(s, d) {\
     504        SQUASHFS_SWAP_START\
     505        SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry));\
     506        SQUASHFS_SWAP((s)->start_block, d, 0, 64);\
     507        SQUASHFS_SWAP((s)->size, d, 64, 32);\
     508}
     509
     510#define SQUASHFS_SWAP_SHORTS(s, d, n) {\
     511        int entry;\
     512        int bit_position;\
     513        SQUASHFS_SWAP_START\
     514        SQUASHFS_MEMSET(s, d, n * 2);\
     515        for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
     516                        16)\
     517                SQUASHFS_SWAP(s[entry], d, bit_position, 16);\
     518}
     519
     520#define SQUASHFS_SWAP_INTS(s, d, n) {\
     521        int entry;\
     522        int bit_position;\
     523        SQUASHFS_SWAP_START\
     524        SQUASHFS_MEMSET(s, d, n * 4);\
     525        for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
     526                        32)\
     527                SQUASHFS_SWAP(s[entry], d, bit_position, 32);\
     528}
     529
     530#define SQUASHFS_SWAP_LONG_LONGS(s, d, n) {\
     531        int entry;\
     532        int bit_position;\
     533        SQUASHFS_SWAP_START\
     534        SQUASHFS_MEMSET(s, d, n * 8);\
     535        for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
     536                        64)\
     537                SQUASHFS_SWAP(s[entry], d, bit_position, 64);\
     538}
     539
     540#define SQUASHFS_SWAP_DATA(s, d, n, bits) {\
     541        int entry;\
     542        int bit_position;\
     543        SQUASHFS_SWAP_START\
     544        SQUASHFS_MEMSET(s, d, n * bits / 8);\
     545        for(entry = 0, bit_position = 0; entry < n; entry++, bit_position += \
     546                        bits)\
     547                SQUASHFS_SWAP(s[entry], d, bit_position, bits);\
     548}
     549
     550#define SQUASHFS_SWAP_FRAGMENT_INDEXES(s, d, n) SQUASHFS_SWAP_LONG_LONGS(s, d, n)
     551
     552#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
     553
     554struct squashfs_base_inode_header_1 {
     555        unsigned int            inode_type:4;
     556        unsigned int            mode:12; /* protection */
     557        unsigned int            uid:4; /* index into uid table */
     558        unsigned int            guid:4; /* index into guid table */
     559} __attribute__ ((packed));
     560
     561struct squashfs_ipc_inode_header_1 {
     562        unsigned int            inode_type:4;
     563        unsigned int            mode:12; /* protection */
     564        unsigned int            uid:4; /* index into uid table */
     565        unsigned int            guid:4; /* index into guid table */
     566        unsigned int            type:4;
     567        unsigned int            offset:4;
     568} __attribute__ ((packed));
     569
     570struct squashfs_dev_inode_header_1 {
     571        unsigned int            inode_type:4;
     572        unsigned int            mode:12; /* protection */
     573        unsigned int            uid:4; /* index into uid table */
     574        unsigned int            guid:4; /* index into guid table */
     575        unsigned short          rdev;
     576} __attribute__ ((packed));
     577       
     578struct squashfs_symlink_inode_header_1 {
     579        unsigned int            inode_type:4;
     580        unsigned int            mode:12; /* protection */
     581        unsigned int            uid:4; /* index into uid table */
     582        unsigned int            guid:4; /* index into guid table */
     583        unsigned short          symlink_size;
     584        char                    symlink[0];
     585} __attribute__ ((packed));
     586
     587struct squashfs_reg_inode_header_1 {
     588        unsigned int            inode_type:4;
     589        unsigned int            mode:12; /* protection */
     590        unsigned int            uid:4; /* index into uid table */
     591        unsigned int            guid:4; /* index into guid table */
     592        unsigned int            mtime;
     593        unsigned int            start_block;
     594        unsigned int            file_size:32;
     595        unsigned short          block_list[0];
     596} __attribute__ ((packed));
     597
     598struct squashfs_dir_inode_header_1 {
     599        unsigned int            inode_type:4;
     600        unsigned int            mode:12; /* protection */
     601        unsigned int            uid:4; /* index into uid table */
     602        unsigned int            guid:4; /* index into guid table */
     603        unsigned int            file_size:19;
     604        unsigned int            offset:13;
     605        unsigned int            mtime;
     606        unsigned int            start_block:24;
     607} __attribute__  ((packed));
     608
     609#define SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n) \
     610        SQUASHFS_MEMSET(s, d, n);\
     611        SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
     612        SQUASHFS_SWAP((s)->mode, d, 4, 12);\
     613        SQUASHFS_SWAP((s)->uid, d, 16, 4);\
     614        SQUASHFS_SWAP((s)->guid, d, 20, 4);
     615
     616#define SQUASHFS_SWAP_BASE_INODE_HEADER_1(s, d, n) {\
     617        SQUASHFS_SWAP_START\
     618        SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, n)\
     619}
     620
     621#define SQUASHFS_SWAP_IPC_INODE_HEADER_1(s, d) {\
     622        SQUASHFS_SWAP_START\
     623        SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
     624                        sizeof(struct squashfs_ipc_inode_header_1));\
     625        SQUASHFS_SWAP((s)->type, d, 24, 4);\
     626        SQUASHFS_SWAP((s)->offset, d, 28, 4);\
     627}
     628
     629#define SQUASHFS_SWAP_DEV_INODE_HEADER_1(s, d) {\
     630        SQUASHFS_SWAP_START\
     631        SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
     632                        sizeof(struct squashfs_dev_inode_header_1));\
     633        SQUASHFS_SWAP((s)->rdev, d, 24, 16);\
     634}
     635
     636#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_1(s, d) {\
     637        SQUASHFS_SWAP_START\
     638        SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
     639                        sizeof(struct squashfs_symlink_inode_header_1));\
     640        SQUASHFS_SWAP((s)->symlink_size, d, 24, 16);\
     641}
     642
     643#define SQUASHFS_SWAP_REG_INODE_HEADER_1(s, d) {\
     644        SQUASHFS_SWAP_START\
     645        SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
     646                        sizeof(struct squashfs_reg_inode_header_1));\
     647        SQUASHFS_SWAP((s)->mtime, d, 24, 32);\
     648        SQUASHFS_SWAP((s)->start_block, d, 56, 32);\
     649        SQUASHFS_SWAP((s)->file_size, d, 88, 32);\
     650}
     651
     652#define SQUASHFS_SWAP_DIR_INODE_HEADER_1(s, d) {\
     653        SQUASHFS_SWAP_START\
     654        SQUASHFS_SWAP_BASE_INODE_CORE_1(s, d, \
     655                        sizeof(struct squashfs_dir_inode_header_1));\
     656        SQUASHFS_SWAP((s)->file_size, d, 24, 19);\
     657        SQUASHFS_SWAP((s)->offset, d, 43, 13);\
     658        SQUASHFS_SWAP((s)->mtime, d, 56, 32);\
     659        SQUASHFS_SWAP((s)->start_block, d, 88, 24);\
     660}
     661
     662#endif
     663
     664#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
     665
     666struct squashfs_dir_index_2 {
     667        unsigned int            index:27;
     668        unsigned int            start_block:29;
     669        unsigned char           size;
     670        unsigned char           name[0];
     671} __attribute__ ((packed));
     672
     673struct squashfs_base_inode_header_2 {
     674        unsigned int            inode_type:4;
     675        unsigned int            mode:12; /* protection */
     676        unsigned int            uid:8; /* index into uid table */
     677        unsigned int            guid:8; /* index into guid table */
     678} __attribute__ ((packed));
     679
     680struct squashfs_ipc_inode_header_2 {
     681        unsigned int            inode_type:4;
     682        unsigned int            mode:12; /* protection */
     683        unsigned int            uid:8; /* index into uid table */
     684        unsigned int            guid:8; /* index into guid table */
     685} __attribute__ ((packed));
     686
     687struct squashfs_dev_inode_header_2 {
     688        unsigned int            inode_type:4;
     689        unsigned int            mode:12; /* protection */
     690        unsigned int            uid:8; /* index into uid table */
     691        unsigned int            guid:8; /* index into guid table */
     692        unsigned short          rdev;
     693} __attribute__ ((packed));
     694       
     695struct squashfs_symlink_inode_header_2 {
     696        unsigned int            inode_type:4;
     697        unsigned int            mode:12; /* protection */
     698        unsigned int            uid:8; /* index into uid table */
     699        unsigned int            guid:8; /* index into guid table */
     700        unsigned short          symlink_size;
     701        char                    symlink[0];
     702} __attribute__ ((packed));
     703
     704struct squashfs_reg_inode_header_2 {
     705        unsigned int            inode_type:4;
     706        unsigned int            mode:12; /* protection */
     707        unsigned int            uid:8; /* index into uid table */
     708        unsigned int            guid:8; /* index into guid table */
     709        unsigned int            mtime;
     710        unsigned int            start_block;
     711        unsigned int            fragment;
     712        unsigned int            offset;
     713        unsigned int            file_size:32;
     714        unsigned short          block_list[0];
     715} __attribute__ ((packed));
     716
     717struct squashfs_dir_inode_header_2 {
     718        unsigned int            inode_type:4;
     719        unsigned int            mode:12; /* protection */
     720        unsigned int            uid:8; /* index into uid table */
     721        unsigned int            guid:8; /* index into guid table */
     722        unsigned int            file_size:19;
     723        unsigned int            offset:13;
     724        unsigned int            mtime;
     725        unsigned int            start_block:24;
     726} __attribute__  ((packed));
     727
     728struct squashfs_ldir_inode_header_2 {
     729        unsigned int            inode_type:4;
     730        unsigned int            mode:12; /* protection */
     731        unsigned int            uid:8; /* index into uid table */
     732        unsigned int            guid:8; /* index into guid table */
     733        unsigned int            file_size:27;
     734        unsigned int            offset:13;
     735        unsigned int            mtime;
     736        unsigned int            start_block:24;
     737        unsigned int            i_count:16;
     738        struct squashfs_dir_index_2     index[0];
     739} __attribute__  ((packed));
     740
     741union squashfs_inode_header_2 {
     742        struct squashfs_base_inode_header_2     base;
     743        struct squashfs_dev_inode_header_2      dev;
     744        struct squashfs_symlink_inode_header_2  symlink;
     745        struct squashfs_reg_inode_header_2      reg;
     746        struct squashfs_dir_inode_header_2      dir;
     747        struct squashfs_ldir_inode_header_2     ldir;
     748        struct squashfs_ipc_inode_header_2      ipc;
     749};
     750       
     751struct squashfs_dir_header_2 {
     752        unsigned int            count:8;
     753        unsigned int            start_block:24;
     754} __attribute__ ((packed));
     755
     756struct squashfs_dir_entry_2 {
     757        unsigned int            offset:13;
     758        unsigned int            type:3;
     759        unsigned int            size:8;
     760        char                    name[0];
     761} __attribute__ ((packed));
     762
     763struct squashfs_fragment_entry_2 {
     764        unsigned int            start_block;
     765        unsigned int            size;
     766} __attribute__ ((packed));
     767
     768#define SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
     769        SQUASHFS_MEMSET(s, d, n);\
     770        SQUASHFS_SWAP((s)->inode_type, d, 0, 4);\
     771        SQUASHFS_SWAP((s)->mode, d, 4, 12);\
     772        SQUASHFS_SWAP((s)->uid, d, 16, 8);\
     773        SQUASHFS_SWAP((s)->guid, d, 24, 8);\
     774
     775#define SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, n) {\
     776        SQUASHFS_SWAP_START\
     777        SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, n)\
     778}
     779
     780#define SQUASHFS_SWAP_IPC_INODE_HEADER_2(s, d) \
     781        SQUASHFS_SWAP_BASE_INODE_HEADER_2(s, d, sizeof(struct squashfs_ipc_inode_header_2))
     782
     783#define SQUASHFS_SWAP_DEV_INODE_HEADER_2(s, d) {\
     784        SQUASHFS_SWAP_START\
     785        SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
     786                        sizeof(struct squashfs_dev_inode_header_2)); \
     787        SQUASHFS_SWAP((s)->rdev, d, 32, 16);\
     788}
     789
     790#define SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(s, d) {\
     791        SQUASHFS_SWAP_START\
     792        SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
     793                        sizeof(struct squashfs_symlink_inode_header_2));\
     794        SQUASHFS_SWAP((s)->symlink_size, d, 32, 16);\
     795}
     796
     797#define SQUASHFS_SWAP_REG_INODE_HEADER_2(s, d) {\
     798        SQUASHFS_SWAP_START\
     799        SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
     800                        sizeof(struct squashfs_reg_inode_header_2));\
     801        SQUASHFS_SWAP((s)->mtime, d, 32, 32);\
     802        SQUASHFS_SWAP((s)->start_block, d, 64, 32);\
     803        SQUASHFS_SWAP((s)->fragment, d, 96, 32);\
     804        SQUASHFS_SWAP((s)->offset, d, 128, 32);\
     805        SQUASHFS_SWAP((s)->file_size, d, 160, 32);\
     806}
     807
     808#define SQUASHFS_SWAP_DIR_INODE_HEADER_2(s, d) {\
     809        SQUASHFS_SWAP_START\
     810        SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
     811                        sizeof(struct squashfs_dir_inode_header_2));\
     812        SQUASHFS_SWAP((s)->file_size, d, 32, 19);\
     813        SQUASHFS_SWAP((s)->offset, d, 51, 13);\
     814        SQUASHFS_SWAP((s)->mtime, d, 64, 32);\
     815        SQUASHFS_SWAP((s)->start_block, d, 96, 24);\
     816}
     817
     818#define SQUASHFS_SWAP_LDIR_INODE_HEADER_2(s, d) {\
     819        SQUASHFS_SWAP_START\
     820        SQUASHFS_SWAP_BASE_INODE_CORE_2(s, d, \
     821                        sizeof(struct squashfs_ldir_inode_header_2));\
     822        SQUASHFS_SWAP((s)->file_size, d, 32, 27);\
     823        SQUASHFS_SWAP((s)->offset, d, 59, 13);\
     824        SQUASHFS_SWAP((s)->mtime, d, 72, 32);\
     825        SQUASHFS_SWAP((s)->start_block, d, 104, 24);\
     826        SQUASHFS_SWAP((s)->i_count, d, 128, 16);\
     827}
     828
     829#define SQUASHFS_SWAP_DIR_INDEX_2(s, d) {\
     830        SQUASHFS_SWAP_START\
     831        SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_index_2));\
     832        SQUASHFS_SWAP((s)->index, d, 0, 27);\
     833        SQUASHFS_SWAP((s)->start_block, d, 27, 29);\
     834        SQUASHFS_SWAP((s)->size, d, 56, 8);\
     835}
     836#define SQUASHFS_SWAP_DIR_HEADER_2(s, d) {\
     837        SQUASHFS_SWAP_START\
     838        SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_header_2));\
     839        SQUASHFS_SWAP((s)->count, d, 0, 8);\
     840        SQUASHFS_SWAP((s)->start_block, d, 8, 24);\
     841}
     842
     843#define SQUASHFS_SWAP_DIR_ENTRY_2(s, d) {\
     844        SQUASHFS_SWAP_START\
     845        SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_dir_entry_2));\
     846        SQUASHFS_SWAP((s)->offset, d, 0, 13);\
     847        SQUASHFS_SWAP((s)->type, d, 13, 3);\
     848        SQUASHFS_SWAP((s)->size, d, 16, 8);\
     849}
     850
     851#define SQUASHFS_SWAP_FRAGMENT_ENTRY_2(s, d) {\
     852        SQUASHFS_SWAP_START\
     853        SQUASHFS_MEMSET(s, d, sizeof(struct squashfs_fragment_entry_2));\
     854        SQUASHFS_SWAP((s)->start_block, d, 0, 32);\
     855        SQUASHFS_SWAP((s)->size, d, 32, 32);\
     856}
     857
     858#define SQUASHFS_SWAP_FRAGMENT_INDEXES_2(s, d, n) SQUASHFS_SWAP_INTS(s, d, n)
     859
     860/* fragment and fragment table defines */
     861#define SQUASHFS_FRAGMENT_BYTES_2(A)    (A * sizeof(struct squashfs_fragment_entry_2))
     862
     863#define SQUASHFS_FRAGMENT_INDEX_2(A)    (SQUASHFS_FRAGMENT_BYTES_2(A) / \
     864                                        SQUASHFS_METADATA_SIZE)
     865
     866#define SQUASHFS_FRAGMENT_INDEX_OFFSET_2(A)     (SQUASHFS_FRAGMENT_BYTES_2(A) % \
     867                                                SQUASHFS_METADATA_SIZE)
     868
     869#define SQUASHFS_FRAGMENT_INDEXES_2(A)  ((SQUASHFS_FRAGMENT_BYTES_2(A) + \
     870                                        SQUASHFS_METADATA_SIZE - 1) / \
     871                                        SQUASHFS_METADATA_SIZE)
     872
     873#define SQUASHFS_FRAGMENT_INDEX_BYTES_2(A)      (SQUASHFS_FRAGMENT_INDEXES_2(A) *\
     874                                                sizeof(int))
     875
     876#endif
     877
     878#ifdef __KERNEL__
     879
     880/*
     881 * macros used to swap each structure entry, taking into account
     882 * bitfields and different bitfield placing conventions on differing
     883 * architectures
     884 */
     885
     886#include <asm/byteorder.h>
     887
     888#ifdef __BIG_ENDIAN
     889        /* convert from little endian to big endian */
     890#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
     891                tbits, b_pos)
     892#else
     893        /* convert from big endian to little endian */
     894#define SQUASHFS_SWAP(value, p, pos, tbits) _SQUASHFS_SWAP(value, p, pos, \
     895                tbits, 64 - tbits - b_pos)
     896#endif
     897
     898#define _SQUASHFS_SWAP(value, p, pos, tbits, SHIFT) {\
     899        b_pos = pos % 8;\
     900        val = 0;\
     901        s = (unsigned char *)p + (pos / 8);\
     902        d = ((unsigned char *) &val) + 7;\
     903        for(bits = 0; bits < (tbits + b_pos); bits += 8) \
     904                *d-- = *s++;\
     905        value = (val >> (SHIFT))/* & ((1 << tbits) - 1)*/;\
     906}
     907
     908#define SQUASHFS_MEMSET(s, d, n)        memset(s, 0, n);
     909
     910#endif
     911#endif
  • include/linux/squashfs_fs_i.h

    diff -Nru linux-2.6.19.ori2/include/linux/squashfs_fs_i.h linux-2.6.19.ori/include/linux/squashfs_fs_i.h
    old new  
     1#ifndef SQUASHFS_FS_I
     2#define SQUASHFS_FS_I
     3/*
     4 * Squashfs
     5 *
     6 * Copyright (c) 2002, 2003, 2004, 2005, 2006
     7 * Phillip Lougher <phillip@lougher.org.uk>
     8 *
     9 * This program is free software; you can redistribute it and/or
     10 * modify it under the terms of the GNU General Public License
     11 * as published by the Free Software Foundation; either version 2,
     12 * or (at your option) any later version.
     13 *
     14 * This program is distributed in the hope that it will be useful,
     15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 * GNU General Public License for more details.
     18 *
     19 * You should have received a copy of the GNU General Public License
     20 * along with this program; if not, write to the Free Software
     21 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     22 *
     23 * squashfs_fs_i.h
     24 */
     25
     26struct squashfs_inode_info {
     27        long long       start_block;
     28        unsigned int    offset;
     29        union {
     30                struct {
     31                        long long       fragment_start_block;
     32                        unsigned int    fragment_size;
     33                        unsigned int    fragment_offset;
     34                        long long       block_list_start;
     35                } s1;
     36                struct {
     37                        long long       directory_index_start;
     38                        unsigned int    directory_index_offset;
     39                        unsigned int    directory_index_count;
     40                        unsigned int    parent_inode;
     41                } s2;
     42        } u;
     43        struct inode    vfs_inode;
     44};
     45#endif
  • include/linux/squashfs_fs_sb.h

    diff -Nru linux-2.6.19.ori2/include/linux/squashfs_fs_sb.h linux-2.6.19.ori/include/linux/squashfs_fs_sb.h
    old new  
     1#ifndef SQUASHFS_FS_SB
     2#define SQUASHFS_FS_SB
     3/*
     4 * Squashfs
     5 *
     6 * Copyright (c) 2002, 2003, 2004, 2005, 2006
     7 * Phillip Lougher <phillip@lougher.org.uk>
     8 *
     9 * This program is free software; you can redistribute it and/or
     10 * modify it under the terms of the GNU General Public License
     11 * as published by the Free Software Foundation; either version 2,
     12 * or (at your option) any later version.
     13 *
     14 * This program is distributed in the hope that it will be useful,
     15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
     16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     17 * GNU General Public License for more details.
     18 *
     19 * You should have received a copy of the GNU General Public License
     20 * along with this program; if not, write to the Free Software
     21 * Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
     22 *
     23 * squashfs_fs_sb.h
     24 */
     25
     26#include <linux/squashfs_fs.h>
     27
     28struct squashfs_cache {
     29        long long       block;
     30        int             length;
     31        long long       next_index;
     32        char            *data;
     33};
     34
     35struct squashfs_fragment_cache {
     36        long long       block;
     37        int             length;
     38        unsigned int    locked;
     39        char            *data;
     40};
     41
     42struct squashfs_sb_info {
     43        struct squashfs_super_block     sblk;
     44        int                     devblksize;
     45        int                     devblksize_log2;
     46        int                     swap;
     47        struct squashfs_cache   *block_cache;
     48        struct squashfs_fragment_cache  *fragment;
     49        int                     next_cache;
     50        int                     next_fragment;
     51        int                     next_meta_index;
     52        unsigned int            *uid;
     53        unsigned int            *guid;
     54        long long               *fragment_index;
     55        unsigned int            *fragment_index_2;
     56        unsigned int            read_size;
     57        char                    *read_data;
     58        char                    *read_page;
     59        struct semaphore        read_data_mutex;
     60        struct semaphore        read_page_mutex;
     61        struct semaphore        block_cache_mutex;
     62        struct semaphore        fragment_mutex;
     63        struct semaphore        meta_index_mutex;
     64        wait_queue_head_t       waitq;
     65        wait_queue_head_t       fragment_wait_queue;
     66        struct meta_index       *meta_index;
     67        z_stream                stream;
     68        struct inode            *(*iget)(struct super_block *s,  squashfs_inode_t
     69                                inode);
     70        long long               (*read_blocklist)(struct inode *inode, int
     71                                index, int readahead_blks, char *block_list,
     72                                unsigned short **block_p, unsigned int *bsize);
     73        int                     (*read_fragment_index_table)(struct super_block *s);
     74};
     75#endif
  • init/do_mounts_rd.c

    diff -Nru linux-2.6.19.ori2/init/do_mounts_rd.c linux-2.6.19.ori/init/do_mounts_rd.c
    old new  
    55#include <linux/ext2_fs.h>
    66#include <linux/romfs_fs.h>
    77#include <linux/cramfs_fs.h>
     8#include <linux/squashfs_fs.h>
    89#include <linux/initrd.h>
    910#include <linux/string.h>
    1011
     
    3940 * numbers could not be found.
    4041 *
    4142 * We currently check for the following magic numbers:
     43 *      squashfs
    4244 *      minix
    4345 *      ext2
    4446 *      romfs
     
    5355        struct ext2_super_block *ext2sb;
    5456        struct romfs_super_block *romfsb;
    5557        struct cramfs_super *cramfsb;
     58        struct squashfs_super_block *squashfsb;
    5659        int nblocks = -1;
    5760        unsigned char *buf;
    5861
     
    6467        ext2sb = (struct ext2_super_block *) buf;
    6568        romfsb = (struct romfs_super_block *) buf;
    6669        cramfsb = (struct cramfs_super *) buf;
     70        squashfsb = (struct squashfs_super_block *) buf;
    6771        memset(buf, 0xe5, size);
    6872
    6973        /*
     
    101105                goto done;
    102106        }
    103107
     108        /* squashfs is at block zero too */
     109        if (squashfsb->s_magic == SQUASHFS_MAGIC) {
     110                printk(KERN_NOTICE
     111                       "RAMDISK: squashfs filesystem found at block %d\n",
     112                       start_block);
     113                if (squashfsb->s_major < 3)
     114                        nblocks = (squashfsb->bytes_used_2+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
     115                else
     116                        nblocks = (squashfsb->bytes_used+BLOCK_SIZE-1)>>BLOCK_SIZE_BITS;
     117                goto done;
     118        }
     119
    104120        /*
    105121         * Read block 1 to test for minix and ext2 superblock
    106122         */
Note: See TracBrowser for help on using the repository browser.