Exemplo n.º 1
0
struct dir *squashfs_opendir_1(unsigned int block_start, unsigned int offset,
	struct inode **i)
{
	squashfs_dir_header_2 dirh;
	char buffer[sizeof(squashfs_dir_entry_2) + SQUASHFS_NAME_LEN + 1]
		__attribute__((aligned));
	squashfs_dir_entry_2 *dire = (squashfs_dir_entry_2 *) buffer;
	long long start;
	int bytes;
	int dir_count, size;
	struct dir_ent *new_dir;
	struct dir *dir;

	TRACE("squashfs_opendir: inode start block %d, offset %d\n",
		block_start, offset);

	*i = s_ops.read_inode(block_start, offset);
	start = sBlk.s.directory_table_start + (*i)->start;
	bytes = lookup_entry(directory_table_hash, start);
	if(bytes == -1)
		EXIT_UNSQUASH("squashfs_opendir: directory block %d not "
			"found!\n", block_start);

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

	if((dir = malloc(sizeof(struct dir))) == NULL)
		EXIT_UNSQUASH("squashfs_opendir: malloc failed!\n");

	dir->dir_count = 0;
	dir->cur_entry = 0;
	dir->mode = (*i)->mode;
	dir->uid = (*i)->uid;
	dir->guid = (*i)->gid;
	dir->mtime = (*i)->time;
	dir->xattr = (*i)->xattr;
	dir->dirs = NULL;

	while(bytes < size) {			
		if(swap) {
			squashfs_dir_header_2 sdirh;
			memcpy(&sdirh, directory_table + bytes, sizeof(sdirh));
			SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
		} else
			memcpy(&dirh, directory_table + bytes, sizeof(dirh));
	
		dir_count = dirh.count + 1;
		TRACE("squashfs_opendir: Read directory header @ byte position "
			"%d, %d directory entries\n", bytes, dir_count);
		bytes += sizeof(dirh);

		while(dir_count--) {
			if(swap) {
				squashfs_dir_entry_2 sdire;
				memcpy(&sdire, directory_table + bytes,
					sizeof(sdire));
				SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
			} else
				memcpy(dire, directory_table + bytes,
					sizeof(*dire));
			bytes += sizeof(*dire);

			memcpy(dire->name, directory_table + bytes,
				dire->size + 1);
			dire->name[dire->size + 1] = '\0';
			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)
					EXIT_UNSQUASH("squashfs_opendir: "
						"realloc failed!\n");
				dir->dirs = new_dir;
			}
			strcpy(dir->dirs[dir->dir_count].name, dire->name);
			dir->dirs[dir->dir_count].start_block =
				dirh.start_block;
			dir->dirs[dir->dir_count].offset = dire->offset;
			dir->dirs[dir->dir_count].type = dire->type;
			dir->dir_count ++;
			bytes += dire->size + 1;
		}
	}

	return dir;
}
Exemplo n.º 2
0
static int squashfs_readdir_2(struct file *file, void *dirent, filldir_t filldir)
{
    struct inode *i = file->f_dentry->d_inode;
    struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
    struct squashfs_super_block *sblk = &msblk->sblk;
    long long next_block = SQUASHFS_I(i)->start_block +
                           sblk->directory_table_start;
    int next_offset = SQUASHFS_I(i)->offset, length = 0,
        dir_count;
    struct squashfs_dir_header_2 dirh;
    struct squashfs_dir_entry_2 *dire;

    TRACE("Entered squashfs_readdir_2 [%llx:%x]\n", next_block, next_offset);

    if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
                         SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
        ERROR("Failed to allocate squashfs_dir_entry\n");
        goto finish;
    }

    length = get_dir_index_using_offset(i->i_sb, &next_block, &next_offset,
                                        SQUASHFS_I(i)->u.s2.directory_index_start,
                                        SQUASHFS_I(i)->u.s2.directory_index_offset,
                                        SQUASHFS_I(i)->u.s2.directory_index_count,
                                        file->f_pos);

    while (length < i_size_read(i)) {
        /* read directory header */
        if (msblk->swap) {
            struct squashfs_dir_header_2 sdirh;

            if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
                                           next_block, next_offset, sizeof(sdirh),
                                           &next_block, &next_offset))
                goto failed_read;

            length += sizeof(sdirh);
            SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
        } else {
            if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
                                           next_block, next_offset, sizeof(dirh),
                                           &next_block, &next_offset))
                goto failed_read;

            length += sizeof(dirh);
        }

        dir_count = dirh.count + 1;
        while (dir_count--) {
            if (msblk->swap) {
                struct squashfs_dir_entry_2 sdire;
                if (!squashfs_get_cached_block(i->i_sb, (char *)
                                               &sdire, next_block, next_offset,
                                               sizeof(sdire), &next_block,
                                               &next_offset))
                    goto failed_read;

                length += sizeof(sdire);
                SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
            } else {
                if (!squashfs_get_cached_block(i->i_sb, (char *)
                                               dire, next_block, next_offset,
                                               sizeof(*dire), &next_block,
                                               &next_offset))
                    goto failed_read;

                length += sizeof(*dire);
            }

            if (!squashfs_get_cached_block(i->i_sb, dire->name,
                                           next_block, next_offset,
                                           dire->size + 1, &next_block,
                                           &next_offset))
                goto failed_read;

            length += dire->size + 1;

            if (file->f_pos >= length)
                continue;

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

            TRACE("Calling filldir(%x, %s, %d, %d, %x:%x, %d)\n",
                  (unsigned int) dirent, dire->name,
                  dire->size + 1, (int) file->f_pos,
                  dirh.start_block, dire->offset,
                  squashfs_filetype_table[dire->type]);

            if (filldir(dirent, dire->name, dire->size + 1,
                        file->f_pos, SQUASHFS_MK_VFS_INODE(
                            dirh.start_block, dire->offset),
                        squashfs_filetype_table[dire->type])
                    < 0) {
                TRACE("Filldir returned less than 0\n");
                goto finish;
            }
            file->f_pos = length;
        }
    }

finish:
    kfree(dire);
    return 0;

failed_read:
    ERROR("Unable to read directory block [%llx:%x]\n", next_block,
          next_offset);
    kfree(dire);
    return 0;
}
Exemplo n.º 3
0
static struct dentry *squashfs_lookup_2(struct inode *i, struct dentry *dentry,
                                        struct nameidata *nd)
{
    const unsigned char *name = dentry->d_name.name;
    int len = dentry->d_name.len;
    struct inode *inode = NULL;
    struct squashfs_sb_info *msblk = i->i_sb->s_fs_info;
    struct squashfs_super_block *sblk = &msblk->sblk;
    long long next_block = SQUASHFS_I(i)->start_block +
                           sblk->directory_table_start;
    int next_offset = SQUASHFS_I(i)->offset, length = 0,
        dir_count;
    struct squashfs_dir_header_2 dirh;
    struct squashfs_dir_entry_2 *dire;
    int sorted = sblk->s_major == 2 && sblk->s_minor >= 1;

    TRACE("Entered squashfs_lookup_2 [%llx:%x]\n", next_block, next_offset);

    if (!(dire = kmalloc(sizeof(struct squashfs_dir_entry) +
                         SQUASHFS_NAME_LEN + 1, GFP_KERNEL))) {
        ERROR("Failed to allocate squashfs_dir_entry\n");
        goto exit_loop;
    }

    if (len > SQUASHFS_NAME_LEN)
        goto exit_loop;

    length = get_dir_index_using_name(i->i_sb, &next_block, &next_offset,
                                      SQUASHFS_I(i)->u.s2.directory_index_start,
                                      SQUASHFS_I(i)->u.s2.directory_index_offset,
                                      SQUASHFS_I(i)->u.s2.directory_index_count, name,
                                      len);

    while (length < i_size_read(i)) {
        /* read directory header */
        if (msblk->swap) {
            struct squashfs_dir_header_2 sdirh;
            if (!squashfs_get_cached_block(i->i_sb, (char *) &sdirh,
                                           next_block, next_offset, sizeof(sdirh),
                                           &next_block, &next_offset))
                goto failed_read;

            length += sizeof(sdirh);
            SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
        } else {
            if (!squashfs_get_cached_block(i->i_sb, (char *) &dirh,
                                           next_block, next_offset, sizeof(dirh),
                                           &next_block, &next_offset))
                goto failed_read;

            length += sizeof(dirh);
        }

        dir_count = dirh.count + 1;
        while (dir_count--) {
            if (msblk->swap) {
                struct squashfs_dir_entry_2 sdire;
                if (!squashfs_get_cached_block(i->i_sb, (char *)
                                               &sdire, next_block,next_offset,
                                               sizeof(sdire), &next_block,
                                               &next_offset))
                    goto failed_read;

                length += sizeof(sdire);
                SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
            } else {
                if (!squashfs_get_cached_block(i->i_sb, (char *)
                                               dire, next_block,next_offset,
                                               sizeof(*dire), &next_block,
                                               &next_offset))
                    goto failed_read;

                length += sizeof(*dire);
            }

            if (!squashfs_get_cached_block(i->i_sb, dire->name,
                                           next_block, next_offset, dire->size + 1,
                                           &next_block, &next_offset))
                goto failed_read;

            length += dire->size + 1;

            if (sorted && name[0] < dire->name[0])
                goto exit_loop;

            if ((len == dire->size + 1) && !strncmp(name,
                                                    dire->name, len)) {
                squashfs_inode_t ino =
                    SQUASHFS_MKINODE(dirh.start_block,
                                     dire->offset);
                unsigned int inode_number = SQUASHFS_MK_VFS_INODE(dirh.start_block,
                                            dire->offset);

                TRACE("calling squashfs_iget for directory "
                      "entry %s, inode %x:%x, %lld\n", name,
                      dirh.start_block, dire->offset, ino);

                inode = squashfs_iget(i->i_sb, ino, inode_number);

                goto exit_loop;
            }
        }
    }

exit_loop:
    kfree(dire);
    d_add(dentry, inode);
    return ERR_PTR(0);

failed_read:
    ERROR("Unable to read directory block [%llx:%x]\n", next_block,
          next_offset);
    goto exit_loop;
}
Exemplo n.º 4
0
struct dir *squashfs_opendir_1(unsigned int block_start, unsigned int offset,
	struct inode **i)
{
	squashfs_dir_header_2 dirh;
	char buffer[sizeof(squashfs_dir_entry_2) + SQUASHFS_NAME_LEN + 1]
		__attribute__((aligned));
	squashfs_dir_entry_2 *dire = (squashfs_dir_entry_2 *) buffer;
	long long start;
	int bytes;
	int dir_count, size;
	struct dir_ent *new_dir;
	struct dir *dir;

	TRACE("squashfs_opendir: inode start block %d, offset %d\n",
		block_start, offset);

	*i = s_ops.read_inode(block_start, offset);

	dir = malloc(sizeof(struct dir));
	if(dir == NULL)
		EXIT_UNSQUASH("squashfs_opendir: malloc failed!\n");

	dir->dir_count = 0;
	dir->cur_entry = 0;
	dir->mode = (*i)->mode;
	dir->uid = (*i)->uid;
	dir->guid = (*i)->gid;
	dir->mtime = (*i)->time;
	dir->xattr = (*i)->xattr;
	dir->dirs = NULL;

	if ((*i)->data == 0)
		/*
		 * if the directory is empty, skip the unnecessary
		 * lookup_entry, this fixes the corner case with
		 * completely empty filesystems where lookup_entry correctly
		 * returning -1 is incorrectly treated as an error
		 */
		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 %d not "
			"found!\n", block_start);

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

	while(bytes < size) {			
		if(swap) {
			squashfs_dir_header_2 sdirh;
			memcpy(&sdirh, directory_table + bytes, sizeof(sdirh));
			SQUASHFS_SWAP_DIR_HEADER_2(&dirh, &sdirh);
		} else
			memcpy(&dirh, directory_table + bytes, sizeof(dirh));
	
		dir_count = dirh.count + 1;
		TRACE("squashfs_opendir: Read directory header @ byte position "
			"%d, %d directory entries\n", bytes, dir_count);
		bytes += sizeof(dirh);

		/* dir_count should never be larger than 256 */
		if(dir_count > 256)
			goto corrupted;

		while(dir_count--) {
			if(swap) {
				squashfs_dir_entry_2 sdire;
				memcpy(&sdire, directory_table + bytes,
					sizeof(sdire));
				SQUASHFS_SWAP_DIR_ENTRY_2(dire, &sdire);
			} else
				memcpy(dire, directory_table + bytes,
					sizeof(*dire));
			bytes += sizeof(*dire);

			/* size should never be larger than SQUASHFS_NAME_LEN */
			if(dire->size > SQUASHFS_NAME_LEN)
				goto corrupted;

			memcpy(dire->name, directory_table + bytes,
				dire->size + 1);
			dire->name[dire->size + 1] = '\0';
			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)
					EXIT_UNSQUASH("squashfs_opendir: "
						"realloc failed!\n");
				dir->dirs = new_dir;
			}
			strcpy(dir->dirs[dir->dir_count].name, dire->name);
			dir->dirs[dir->dir_count].start_block =
				dirh.start_block;
			dir->dirs[dir->dir_count].offset = dire->offset;
			dir->dirs[dir->dir_count].type = dire->type;
			dir->dir_count ++;
			bytes += dire->size + 1;
		}
	}

	return dir;

corrupted:
	free(dir->dirs);
	free(dir);
	return NULL;
}