Ejemplo n.º 1
0
struct inode *read_inode_2(unsigned int start_block, unsigned int offset)
{
	static squashfs_inode_header_2 header;
	long long start = sBlk.inode_table_start + start_block;
	int bytes = lookup_entry(inode_table_hash, start);
	char *block_ptr = inode_table + bytes + offset;
	static struct inode i;

	TRACE("read_inode: reading inode [%d:%d]\n", start_block,  offset);

	if(bytes == -1) {
		ERROR("read_inode: inode table block %lld not found\n", start); 
		return NULL;
	}

	if(swap) {
		squashfs_base_inode_header_2 sinode;
		memcpy(&sinode, block_ptr, sizeof(header.base));
		SQUASHFS_SWAP_BASE_INODE_HEADER_2(&header.base, &sinode,
			sizeof(squashfs_base_inode_header_2));
	} else
		memcpy(&header.base, block_ptr, sizeof(header.base));

	i.uid = (uid_t) uid_table[header.base.uid];
	i.gid = header.base.guid == SQUASHFS_GUIDS ? i.uid :
		(uid_t) guid_table[header.base.guid];
	i.mode = lookup_type[header.base.inode_type] | header.base.mode;
	i.type = header.base.inode_type;
	i.time = sBlk.mkfs_time;
	i.inode_number = inode_number++;

	switch(header.base.inode_type) {
		case SQUASHFS_DIR_TYPE: {
			squashfs_dir_inode_header_2 *inode = &header.dir;

			if(swap) {
				squashfs_dir_inode_header_2 sinode;
				memcpy(&sinode, block_ptr, sizeof(header.dir));
				SQUASHFS_SWAP_DIR_INODE_HEADER_2(&header.dir,
					&sinode);
			} else
				memcpy(&header.dir, block_ptr,
					sizeof(header.dir));

			i.data = inode->file_size;
			i.offset = inode->offset;
			i.start = inode->start_block;
			i.time = inode->mtime;
			break;
		}
		case SQUASHFS_LDIR_TYPE: {
			squashfs_ldir_inode_header_2 *inode = &header.ldir;

			if(swap) {
				squashfs_ldir_inode_header_2 sinode;
				memcpy(&sinode, block_ptr, sizeof(header.ldir));
				SQUASHFS_SWAP_LDIR_INODE_HEADER_2(&header.ldir,
					&sinode);
			} else
				memcpy(&header.ldir, block_ptr,
					sizeof(header.ldir));

			i.data = inode->file_size;
			i.offset = inode->offset;
			i.start = inode->start_block;
			i.time = inode->mtime;
			break;
		}
		case SQUASHFS_FILE_TYPE: {
			squashfs_reg_inode_header_2 *inode = &header.reg;

			if(swap) {
				squashfs_reg_inode_header_2 sinode;
				memcpy(&sinode, block_ptr, sizeof(sinode));
				SQUASHFS_SWAP_REG_INODE_HEADER_2(inode,
					&sinode);
			} else
				memcpy(inode, block_ptr, sizeof(*inode));

			i.data = inode->file_size;
			i.time = inode->mtime;
			i.frag_bytes = inode->fragment == SQUASHFS_INVALID_FRAG
				?  0 : inode->file_size % sBlk.block_size;
			i.fragment = inode->fragment;
			i.offset = inode->offset;
			i.blocks = inode->fragment == SQUASHFS_INVALID_FRAG ?
				(inode->file_size + sBlk.block_size - 1) >>
				sBlk.block_log : inode->file_size >>
				sBlk.block_log;
			i.start = inode->start_block;
			i.sparse = 0;
			i.block_ptr = block_ptr + sizeof(*inode);
			break;
		}	
		case SQUASHFS_SYMLINK_TYPE: {
			squashfs_symlink_inode_header_2 *inodep =
				&header.symlink;

			if(swap) {
				squashfs_symlink_inode_header_2 sinodep;
				memcpy(&sinodep, block_ptr, sizeof(sinodep));
				SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep,
					&sinodep);
			} else
				memcpy(inodep, block_ptr, sizeof(*inodep));

			i.symlink = malloc(inodep->symlink_size + 1);
			if(i.symlink == NULL)
				EXIT_UNSQUASH("read_inode: failed to malloc "
					"symlink data\n");
			strncpy(i.symlink, block_ptr +
				sizeof(squashfs_symlink_inode_header_2),
				inodep->symlink_size);
			i.symlink[inodep->symlink_size] = '\0';
			i.data = inodep->symlink_size;
			break;
		}
 		case SQUASHFS_BLKDEV_TYPE:
	 	case SQUASHFS_CHRDEV_TYPE: {
			squashfs_dev_inode_header_2 *inodep = &header.dev;

			if(swap) {
				squashfs_dev_inode_header_2 sinodep;
				memcpy(&sinodep, block_ptr, sizeof(sinodep));
				SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep,
					&sinodep);
			} else
				memcpy(inodep, block_ptr, sizeof(*inodep));

			i.data = inodep->rdev;
			break;
			}
		case SQUASHFS_FIFO_TYPE:
		case SQUASHFS_SOCKET_TYPE:
			i.data = 0;
			break;
		default:
			ERROR("Unknown inode type %d in read_inode_header_2!\n",
				header.base.inode_type);
			return NULL;
	}
	return &i;
}
Ejemplo n.º 2
0
static int squashfs_read_inode_2(struct inode *i, squashfs_inode_t inode)
{
    struct super_block *s = i->i_sb;
    struct squashfs_sb_info *msblk = s->s_fs_info;
    struct squashfs_super_block *sblk = &msblk->sblk;
    unsigned int block = SQUASHFS_INODE_BLK(inode) +
                         sblk->inode_table_start;
    unsigned int offset = SQUASHFS_INODE_OFFSET(inode);
    unsigned int ino = i->i_ino;
    long long next_block;
    unsigned int next_offset;
    union squashfs_inode_header_2 id, sid;
    struct squashfs_base_inode_header_2 *inodeb = &id.base,
                                             *sinodeb = &sid.base;

    TRACE("Entered squashfs_iget\n");

    if (msblk->swap) {
        if (!squashfs_get_cached_block(s, (char *) sinodeb, block,
                                       offset, sizeof(*sinodeb), &next_block,
                                       &next_offset))
            goto failed_read;
        SQUASHFS_SWAP_BASE_INODE_HEADER_2(inodeb, sinodeb,
                                          sizeof(*sinodeb));
    } else if (!squashfs_get_cached_block(s, (char *) inodeb, block,
                                          offset, sizeof(*inodeb), &next_block,
                                          &next_offset))
        goto failed_read;

    squashfs_new_inode(msblk, i, inodeb, ino);

    switch(inodeb->inode_type) {
    case SQUASHFS_FILE_TYPE: {
        struct squashfs_reg_inode_header_2 *inodep = &id.reg;
        struct squashfs_reg_inode_header_2 *sinodep = &sid.reg;
        long long frag_blk;
        unsigned int frag_size = 0;

        if (msblk->swap) {
            if (!squashfs_get_cached_block(s, (char *)
                                           sinodep, block, offset,
                                           sizeof(*sinodep), &next_block,
                                           &next_offset))
                goto failed_read;
            SQUASHFS_SWAP_REG_INODE_HEADER_2(inodep, sinodep);
        } else if (!squashfs_get_cached_block(s, (char *)
                                              inodep, block, offset,
                                              sizeof(*inodep), &next_block,
                                              &next_offset))
            goto failed_read;

        frag_blk = SQUASHFS_INVALID_BLK;
        if (inodep->fragment != SQUASHFS_INVALID_FRAG &&
                !get_fragment_location_2(s,
                                         inodep->fragment, &frag_blk, &frag_size))
            goto failed_read;

        i->i_size = inodep->file_size;
        i->i_fop = &generic_ro_fops;
        i->i_mode |= S_IFREG;
        i->i_mtime.tv_sec = inodep->mtime;
        i->i_atime.tv_sec = inodep->mtime;
        i->i_ctime.tv_sec = inodep->mtime;
        i->i_blocks = ((i->i_size - 1) >> 9) + 1;
        SQUASHFS_I(i)->u.s1.fragment_start_block = frag_blk;
        SQUASHFS_I(i)->u.s1.fragment_size = frag_size;
        SQUASHFS_I(i)->u.s1.fragment_offset = inodep->offset;
        SQUASHFS_I(i)->start_block = inodep->start_block;
        SQUASHFS_I(i)->u.s1.block_list_start = next_block;
        SQUASHFS_I(i)->offset = next_offset;
        if (sblk->block_size > 4096)
            i->i_data.a_ops = &squashfs_aops;
        else
            i->i_data.a_ops = &squashfs_aops_4K;

        TRACE("File inode %x:%x, start_block %x, "
              "block_list_start %llx, offset %x\n",
              SQUASHFS_INODE_BLK(inode), offset,
              inodep->start_block, next_block,
              next_offset);
        break;
    }
    case SQUASHFS_DIR_TYPE: {
        struct squashfs_dir_inode_header_2 *inodep = &id.dir;
        struct squashfs_dir_inode_header_2 *sinodep = &sid.dir;

        if (msblk->swap) {
            if (!squashfs_get_cached_block(s, (char *)
                                           sinodep, block, offset,
                                           sizeof(*sinodep), &next_block,
                                           &next_offset))
                goto failed_read;
            SQUASHFS_SWAP_DIR_INODE_HEADER_2(inodep, sinodep);
        } else if (!squashfs_get_cached_block(s, (char *)
                                              inodep, block, offset,
                                              sizeof(*inodep), &next_block,
                                              &next_offset))
            goto failed_read;

        i->i_size = inodep->file_size;
        i->i_op = &squashfs_dir_inode_ops_2;
        i->i_fop = &squashfs_dir_ops_2;
        i->i_mode |= S_IFDIR;
        i->i_mtime.tv_sec = inodep->mtime;
        i->i_atime.tv_sec = inodep->mtime;
        i->i_ctime.tv_sec = inodep->mtime;
        SQUASHFS_I(i)->start_block = inodep->start_block;
        SQUASHFS_I(i)->offset = inodep->offset;
        SQUASHFS_I(i)->u.s2.directory_index_count = 0;
        SQUASHFS_I(i)->u.s2.parent_inode = 0;

        TRACE("Directory inode %x:%x, start_block %x, offset "
              "%x\n", SQUASHFS_INODE_BLK(inode),
              offset, inodep->start_block,
              inodep->offset);
        break;
    }
    case SQUASHFS_LDIR_TYPE: {
        struct squashfs_ldir_inode_header_2 *inodep = &id.ldir;
        struct squashfs_ldir_inode_header_2 *sinodep = &sid.ldir;

        if (msblk->swap) {
            if (!squashfs_get_cached_block(s, (char *)
                                           sinodep, block, offset,
                                           sizeof(*sinodep), &next_block,
                                           &next_offset))
                goto failed_read;
            SQUASHFS_SWAP_LDIR_INODE_HEADER_2(inodep,
                                              sinodep);
        } else if (!squashfs_get_cached_block(s, (char *)
                                              inodep, block, offset,
                                              sizeof(*inodep), &next_block,
                                              &next_offset))
            goto failed_read;

        i->i_size = inodep->file_size;
        i->i_op = &squashfs_dir_inode_ops_2;
        i->i_fop = &squashfs_dir_ops_2;
        i->i_mode |= S_IFDIR;
        i->i_mtime.tv_sec = inodep->mtime;
        i->i_atime.tv_sec = inodep->mtime;
        i->i_ctime.tv_sec = inodep->mtime;
        SQUASHFS_I(i)->start_block = inodep->start_block;
        SQUASHFS_I(i)->offset = inodep->offset;
        SQUASHFS_I(i)->u.s2.directory_index_start = next_block;
        SQUASHFS_I(i)->u.s2.directory_index_offset =
            next_offset;
        SQUASHFS_I(i)->u.s2.directory_index_count =
            inodep->i_count;
        SQUASHFS_I(i)->u.s2.parent_inode = 0;

        TRACE("Long directory inode %x:%x, start_block %x, "
              "offset %x\n",
              SQUASHFS_INODE_BLK(inode), offset,
              inodep->start_block, inodep->offset);
        break;
    }
    case SQUASHFS_SYMLINK_TYPE: {
        struct squashfs_symlink_inode_header_2 *inodep =
                &id.symlink;
        struct squashfs_symlink_inode_header_2 *sinodep =
                &sid.symlink;

        if (msblk->swap) {
            if (!squashfs_get_cached_block(s, (char *)
                                           sinodep, block, offset,
                                           sizeof(*sinodep), &next_block,
                                           &next_offset))
                goto failed_read;
            SQUASHFS_SWAP_SYMLINK_INODE_HEADER_2(inodep,
                                                 sinodep);
        } else if (!squashfs_get_cached_block(s, (char *)
                                              inodep, block, offset,
                                              sizeof(*inodep), &next_block,
                                              &next_offset))
            goto failed_read;

        i->i_size = inodep->symlink_size;
        i->i_op = &page_symlink_inode_operations;
        i->i_data.a_ops = &squashfs_symlink_aops;
        i->i_mode |= S_IFLNK;
        SQUASHFS_I(i)->start_block = next_block;
        SQUASHFS_I(i)->offset = next_offset;

        TRACE("Symbolic link inode %x:%x, start_block %llx, "
              "offset %x\n",
              SQUASHFS_INODE_BLK(inode), offset,
              next_block, next_offset);
        break;
    }
    case SQUASHFS_BLKDEV_TYPE:
    case SQUASHFS_CHRDEV_TYPE: {
        struct squashfs_dev_inode_header_2 *inodep = &id.dev;
        struct squashfs_dev_inode_header_2 *sinodep = &sid.dev;

        if (msblk->swap) {
            if (!squashfs_get_cached_block(s, (char *)
                                           sinodep, block, offset,
                                           sizeof(*sinodep), &next_block,
                                           &next_offset))
                goto failed_read;
            SQUASHFS_SWAP_DEV_INODE_HEADER_2(inodep, sinodep);
        } else if (!squashfs_get_cached_block(s, (char *)
                                              inodep, block, offset,
                                              sizeof(*inodep), &next_block,
                                              &next_offset))
            goto failed_read;

        i->i_mode |= (inodeb->inode_type ==
                      SQUASHFS_CHRDEV_TYPE) ?  S_IFCHR :
                     S_IFBLK;
        init_special_inode(i, i->i_mode,
                           old_decode_dev(inodep->rdev));

        TRACE("Device inode %x:%x, rdev %x\n",
              SQUASHFS_INODE_BLK(inode), offset,
              inodep->rdev);
        break;
    }
    case SQUASHFS_FIFO_TYPE:
    case SQUASHFS_SOCKET_TYPE: {

        i->i_mode |= (inodeb->inode_type == SQUASHFS_FIFO_TYPE)
                     ? S_IFIFO : S_IFSOCK;
        init_special_inode(i, i->i_mode, 0);
        break;
    }
    default:
        ERROR("Unknown inode type %d in squashfs_iget!\n",
              inodeb->inode_type);
        goto failed_read1;
    }

    return 1;

failed_read:
    ERROR("Unable to read inode [%x:%x]\n", block, offset);

failed_read1:
    return 0;
}