Skip to content

Commit

Permalink
Unsquash-4: update to dynamically read directory table
Browse files Browse the repository at this point in the history
Originally when Unsquashfs was written it decompressed
the entire filesystem, and wrote it out to disk.
As such it made sense to read and decompress the
entire directory table at start-up.

Since then new options have been added to Unsquashfs which
can significantly limit the amount of the filesystem
written to disk, e.g. extract files, and more recently
exclude files and depth limiting (-max option).

So it no longer makes sense to read and decompress
the entire directory table at start-up, when much of it
may never be referenced.  It just adds unnecessary
overhead.

Signed-off-by: Phillip Lougher <[email protected]>
  • Loading branch information
plougher committed Mar 13, 2021
1 parent 227c10c commit 2bf96e1
Showing 1 changed file with 20 additions and 22 deletions.
42 changes: 20 additions & 22 deletions squashfs-tools/unsquash-4.c
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@

static struct squashfs_fragment_entry *fragment_table;
static unsigned int *id_table;
static char *directory_table;
static squashfs_operations ops;

static void read_block_list(unsigned int *block_list, long long start,
Expand Down Expand Up @@ -330,8 +329,7 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse
__attribute__((aligned));
struct squashfs_dir_entry *dire = (struct squashfs_dir_entry *) buffer;
long long start;
long long bytes;
int dir_count, size;
int bytes = 0, dir_count, size, res;
struct dir_ent *new_dir;
struct dir *dir;

Expand Down Expand Up @@ -363,17 +361,15 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse
return dir;

start = sBlk.s.directory_table_start + (*i)->start;
bytes = lookup_entry(directory_table_hash, start);

if(bytes == -1)
EXIT_UNSQUASH("squashfs_opendir: directory block %lld not "
"found!\n", start);

bytes += (*i)->offset;
offset = (*i)->offset;
size = (*i)->data + bytes - 3;

while(bytes < size) {
SQUASHFS_SWAP_DIR_HEADER(directory_table + bytes, &dirh);
res = read_directory_data(&dirh, &start, &offset, sizeof(dirh));
if(res == FALSE)
goto corrupted;

SQUASHFS_INSWAP_DIR_HEADER(&dirh);

dir_count = dirh.count + 1;
TRACE("squashfs_opendir: Read directory header @ byte position "
Expand All @@ -387,7 +383,11 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse
}

while(dir_count--) {
SQUASHFS_SWAP_DIR_ENTRY(directory_table + bytes, dire);
res = read_directory_data(dire, &start, &offset, sizeof(*dire));
if(res == FALSE)
goto corrupted;

SQUASHFS_INSWAP_DIR_ENTRY(dire);

bytes += sizeof(*dire);

Expand All @@ -397,8 +397,11 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse
goto corrupted;
}

memcpy(dire->name, directory_table + bytes,
dire->size + 1);
res = read_directory_data(dire->name, &start, &offset,
dire->size + 1);
if(res == FALSE)
goto corrupted;

dire->name[dire->size + 1] = '\0';

/* check name for invalid characters (i.e /, ., ..) */
Expand All @@ -410,13 +413,15 @@ static struct dir *squashfs_opendir(unsigned int block_start, unsigned int offse
TRACE("squashfs_opendir: directory entry %s, inode "
"%d:%d, type %d\n", dire->name,
dirh.start_block, dire->offset, dire->type);

if((dir->dir_count % DIR_ENT_SIZE) == 0) {
new_dir = realloc(dir->dirs, (dir->dir_count +
DIR_ENT_SIZE) * sizeof(struct dir_ent));
if(new_dir == NULL)
MEM_ERROR();
dir->dirs = new_dir;
}

strcpy(dir->dirs[dir->dir_count].name, dire->name);
dir->dirs[dir->dir_count].start_block =
dirh.start_block;
Expand Down Expand Up @@ -633,19 +638,12 @@ static int read_filesystem_tables()
}
}

/* Read directory table */

/* Sanity check super block contents */
/* Sanity check super block directory table values */
if(sBlk.s.directory_table_start > table_start) {
ERROR("read_filesystem_tables: directory table start too large in super block\n");
goto corrupted;
}

directory_table = read_directory_table(sBlk.s.directory_table_start,
table_start);
if(directory_table == NULL)
goto corrupted;

/* Sanity check super block inode table values */
if(sBlk.s.inode_table_start >= sBlk.s.directory_table_start) {
ERROR("read_filesystem_tables: inode table start too large in super block\n");
Expand Down

0 comments on commit 2bf96e1

Please sign in to comment.