Example #1
0
File: dir.c Project: 020gzh/linux
static int squashfs_readdir(struct file *file, struct dir_context *ctx)
{
	struct inode *inode = file_inode(file);
	struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
	u64 block = squashfs_i(inode)->start + msblk->directory_table;
	int offset = squashfs_i(inode)->offset, length, err;
	unsigned int inode_number, dir_count, size, type;
	struct squashfs_dir_header dirh;
	struct squashfs_dir_entry *dire;

	TRACE("Entered squashfs_readdir [%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");
		goto finish;
	}

	/*
	 * Return "." and  ".." entries as the first two filenames in the
	 * directory.  To maximise compression these two entries are not
	 * stored in the directory, and so we invent them here.
	 *
	 * It also means that the external f_pos is offset by 3 from the
	 * on-disk directory f_pos.
	 */
	while (ctx->pos < 3) {
		char *name;
		int i_ino;

		if (ctx->pos == 0) {
			name = ".";
			size = 1;
			i_ino = inode->i_ino;
		} else {
			name = "..";
			size = 2;
			i_ino = squashfs_i(inode)->parent;
		}

		if (!dir_emit(ctx, name, size, i_ino,
				squashfs_filetype_table[1]))
			goto finish;

		ctx->pos += size;
	}

	length = get_dir_index_using_offset(inode->i_sb, &block, &offset,
				squashfs_i(inode)->dir_idx_start,
				squashfs_i(inode)->dir_idx_offset,
				squashfs_i(inode)->dir_idx_cnt,
				ctx->pos);

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

		length += sizeof(dirh);

		dir_count = le32_to_cpu(dirh.count) + 1;

		if (dir_count > SQUASHFS_DIR_COUNT)
			goto failed_read;

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

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

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

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

			length += sizeof(*dire) + size;

			if (ctx->pos >= length)
				continue;

			dire->name[size] = '\0';
			inode_number = le32_to_cpu(dirh.inode_number) +
				((short) le16_to_cpu(dire->inode_number));
			type = le16_to_cpu(dire->type);

			if (type > SQUASHFS_MAX_DIR_TYPE)
				goto failed_read;

			if (!dir_emit(ctx, dire->name, size,
					inode_number,
					squashfs_filetype_table[type]))
				goto finish;

			ctx->pos = length;
		}
	}

finish:
	kfree(dire);
	return 0;

failed_read:
	ERROR("Unable to read directory block [%llx:%x]\n", block, offset);
	kfree(dire);
	return 0;
}
static int squashfs_readdir(struct file *file, void *dirent, filldir_t filldir)
{
	struct inode *inode = file->f_dentry->d_inode;
	struct squashfs_sb_info *msblk = inode->i_sb->s_fs_info;
	u64 block = squashfs_i(inode)->start + msblk->directory_table;
	int offset = squashfs_i(inode)->offset, length, dir_count, size,
				type, err;
	unsigned int inode_number;
	struct squashfs_dir_header dirh;
	struct squashfs_dir_entry *dire;

	TRACE("Entered squashfs_readdir [%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");
		goto finish;
	}

	while (file->f_pos < 3) {
		char *name;
		int i_ino;

		if (file->f_pos == 0) {
			name = ".";
			size = 1;
			i_ino = inode->i_ino;
		} else {
			name = "..";
			size = 2;
			i_ino = squashfs_i(inode)->parent;
		}

		TRACE("Calling filldir(%p, %s, %d, %lld, %d, %d)\n",
				dirent, name, size, file->f_pos, i_ino,
				squashfs_filetype_table[1]);

		if (filldir(dirent, name, size, file->f_pos, i_ino,
				squashfs_filetype_table[1]) < 0) {
				TRACE("Filldir returned less than 0\n");
			goto finish;
		}

		file->f_pos += size;
	}

	length = get_dir_index_using_offset(inode->i_sb, &block, &offset,
				squashfs_i(inode)->dir_idx_start,
				squashfs_i(inode)->dir_idx_offset,
				squashfs_i(inode)->dir_idx_cnt,
				file->f_pos);

	while (length < i_size_read(inode)) {
		err = squashfs_read_metadata(inode->i_sb, &dirh, &block,
					&offset, sizeof(dirh));
		if (err < 0)
			goto failed_read;

		length += sizeof(dirh);

		dir_count = le32_to_cpu(dirh.count) + 1;

		if (dir_count > SQUASHFS_DIR_COUNT)
			goto failed_read;

		while (dir_count--) {
			err = squashfs_read_metadata(inode->i_sb, dire, &block,
					&offset, sizeof(*dire));
			if (err < 0)
				goto failed_read;

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

			
			if (size > SQUASHFS_NAME_LEN)
				goto failed_read;

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

			length += sizeof(*dire) + size;

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

			dire->name[size] = '\0';
			inode_number = le32_to_cpu(dirh.inode_number) +
				((short) le16_to_cpu(dire->inode_number));
			type = le16_to_cpu(dire->type);

			TRACE("Calling filldir(%p, %s, %d, %lld, %x:%x, %d, %d)"
					"\n", dirent, dire->name, size,
					file->f_pos,
					le32_to_cpu(dirh.start_block),
					le16_to_cpu(dire->offset),
					inode_number,
					squashfs_filetype_table[type]);

			if (filldir(dirent, dire->name, size, file->f_pos,
					inode_number,
					squashfs_filetype_table[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", block, offset);
	kfree(dire);
	return 0;
}
Example #3
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;
}