Ejemplo n.º 1
0
int squashfs_lookup_next(struct inode *dir, char *root_name,
				 char *cur_name)
{
	const unsigned char *name = root_name;
	int len = strlen(root_name);
	struct squashfs_sb_info *msblk = dir->i_sb->s_fs_info;
	struct squashfs_dir_header dirh;
	struct squashfs_dir_entry *dire;
	u64 block = squashfs_i(dir)->start + msblk->directory_table;
	int offset = squashfs_i(dir)->offset;
	int err, length;
	unsigned int dir_count, size;
	int name_found = 0, real_name_found = 0;

	TRACE("Entered squashfs_lookup_next [%llx:%x]\n", block, offset);

	dire = kmalloc(sizeof(*dire) + SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
	if (dire == NULL) {
		ERROR("Failed to allocate squashfs_dir_entry\n");
		return -ENOMEM;
	}

	if (len > SQUASHFS_NAME_LEN) {
		err = -ENAMETOOLONG;
		goto failed;
	}

	length = get_dir_index_using_name(dir->i_sb, &block, &offset,
				squashfs_i(dir)->dir_idx_start,
				squashfs_i(dir)->dir_idx_offset,
				squashfs_i(dir)->dir_idx_cnt, name, len);

	while (length < i_size_read(dir)) {
		/*
		 * Read directory header.
		 */
		err = squashfs_read_metadata(dir->i_sb, &dirh, &block,
				&offset, sizeof(dirh));
		if (err < 0)
			goto read_failure;

		length += sizeof(dirh);

		dir_count = le32_to_cpu(dirh.count) + 1;

		if (dir_count > SQUASHFS_DIR_COUNT)
			goto data_error;

		while (dir_count--) {
			/*
			 * Read directory entry.
			 */
			err = squashfs_read_metadata(dir->i_sb, dire, &block,
					&offset, sizeof(*dire));
			if (err < 0)
				goto read_failure;

			size = le16_to_cpu(dire->size) + 1;

			/* size should never be larger than SQUASHFS_NAME_LEN */
			if (size > SQUASHFS_NAME_LEN)
				goto data_error;

			err = squashfs_read_metadata(dir->i_sb, dire->name,
					&block, &offset, size);
			if (err < 0)
				goto read_failure;

			length += sizeof(*dire) + size;
			dire->name[size] = '\0';

			if (cur_name[0] == '/')
				name_found = 1;

			if (!strcmp(cur_name, name))
				name_found = 1;

			if (cur_name[0] != '/'
			    && strlen(cur_name) == size
			    && !strncmp(cur_name, dire->name, size)) {
				name_found = 1;
				continue;
			}

			if (name_found) {
				sprintf(cur_name, "%s", dire->name);
				real_name_found = 1;
				goto exit_lookup;
			}
		}
	}

exit_lookup:
	kfree(dire);
	return real_name_found ? 0 : 1;

data_error:
	err = -EIO;

read_failure:
	ERROR("Unable to read directory block [%llx:%x]\n",
		squashfs_i(dir)->start + msblk->directory_table,
		squashfs_i(dir)->offset);
failed:
	kfree(dire);
	return 1;
}
Ejemplo n.º 2
0
static struct dentry *squashfs_lookup(struct inode *dir, struct dentry *dentry,
				 unsigned int flags)
{
	const unsigned char *name = dentry->d_name.name;
	int len = dentry->d_name.len;
	struct inode *inode = NULL;
	struct squashfs_sb_info *msblk = dir->i_sb->s_fs_info;
	struct squashfs_dir_header dirh;
	struct squashfs_dir_entry *dire;
	u64 block = squashfs_i(dir)->start + msblk->directory_table;
	int offset = squashfs_i(dir)->offset;
	int err, length;
	unsigned int dir_count, size;

	TRACE("Entered squashfs_lookup [%llx:%x]\n", block, offset);

	dire = kmalloc(sizeof(*dire) + SQUASHFS_NAME_LEN + 1, GFP_KERNEL);
	if (dire == NULL) {
		ERROR("Failed to allocate squashfs_dir_entry\n");
		return ERR_PTR(-ENOMEM);
	}

	if (len > SQUASHFS_NAME_LEN) {
		err = -ENAMETOOLONG;
		goto failed;
	}

	length = get_dir_index_using_name(dir->i_sb, &block, &offset,
				squashfs_i(dir)->dir_idx_start,
				squashfs_i(dir)->dir_idx_offset,
				squashfs_i(dir)->dir_idx_cnt, name, len);

	while (length < i_size_read(dir)) {
		/*
		 * Read directory header.
		 */
		err = squashfs_read_metadata(dir->i_sb, &dirh, &block,
				&offset, sizeof(dirh));
		if (err < 0)
			goto read_failure;

		length += sizeof(dirh);

		dir_count = le32_to_cpu(dirh.count) + 1;

		if (dir_count > SQUASHFS_DIR_COUNT)
			goto data_error;

		while (dir_count--) {
			/*
			 * Read directory entry.
			 */
			err = squashfs_read_metadata(dir->i_sb, dire, &block,
					&offset, sizeof(*dire));
			if (err < 0)
				goto read_failure;

			size = le16_to_cpu(dire->size) + 1;

			/* size should never be larger than SQUASHFS_NAME_LEN */
			if (size > SQUASHFS_NAME_LEN)
				goto data_error;

			err = squashfs_read_metadata(dir->i_sb, dire->name,
					&block, &offset, size);
			if (err < 0)
				goto read_failure;

			length += sizeof(*dire) + size;

			if (name[0] < dire->name[0])
				goto exit_lookup;

			if (len == size && !strncmp(name, dire->name, len)) {
				unsigned int blk, off, ino_num;
				long long ino;
				blk = le32_to_cpu(dirh.start_block);
				off = le16_to_cpu(dire->offset);
				ino_num = le32_to_cpu(dirh.inode_number) +
					(short) le16_to_cpu(dire->inode_number);
				ino = SQUASHFS_MKINODE(blk, off);

				TRACE("calling squashfs_iget for directory "
					"entry %s, inode  %x:%x, %d\n", name,
					blk, off, ino_num);

				inode = squashfs_iget(dir->i_sb, ino, ino_num);
				goto exit_lookup;
			}
		}
	}

exit_lookup:
	kfree(dire);
	return d_splice_alias(inode, dentry);

data_error:
	err = -EIO;

read_failure:
	ERROR("Unable to read directory block [%llx:%x]\n",
		squashfs_i(dir)->start + msblk->directory_table,
		squashfs_i(dir)->offset);
failed:
	kfree(dire);
	return ERR_PTR(err);
}
Ejemplo 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;
}