mirror of
https://github.com/torvalds/linux.git
synced 2024-11-24 05:02:12 +00:00
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pkl/squashfs-linus
* git://git.kernel.org/pub/scm/linux/kernel/git/pkl/squashfs-linus: squashfs: update documentation to include description of xattr layout squashfs: fix name reading in squashfs_xattr_get squashfs: constify xattr handlers squashfs: xattr fix sparse warnings squashfs: xattr_lookup sparse fix squashfs: add xattr support configure option squashfs: add new extended inode types squashfs: add support for xattr reading squashfs: add xattr id support
This commit is contained in:
commit
63a6440326
@ -38,7 +38,8 @@ Hard link support: yes no
|
||||
Real inode numbers: yes no
|
||||
32-bit uids/gids: yes no
|
||||
File creation time: yes no
|
||||
Xattr and ACL support: no no
|
||||
Xattr support: yes no
|
||||
ACL support: no no
|
||||
|
||||
Squashfs compresses data, inodes and directories. In addition, inode and
|
||||
directory data are highly compacted, and packed on byte boundaries. Each
|
||||
@ -58,7 +59,7 @@ obtained from this site also.
|
||||
3. SQUASHFS FILESYSTEM DESIGN
|
||||
-----------------------------
|
||||
|
||||
A squashfs filesystem consists of seven parts, packed together on a byte
|
||||
A squashfs filesystem consists of a maximum of eight parts, packed together on a byte
|
||||
alignment:
|
||||
|
||||
---------------
|
||||
@ -80,6 +81,9 @@ alignment:
|
||||
|---------------|
|
||||
| uid/gid |
|
||||
| lookup table |
|
||||
|---------------|
|
||||
| xattr |
|
||||
| table |
|
||||
---------------
|
||||
|
||||
Compressed data blocks are written to the filesystem as files are read from
|
||||
@ -192,6 +196,26 @@ This table is stored compressed into metadata blocks. A second index table is
|
||||
used to locate these. This second index table for speed of access (and because
|
||||
it is small) is read at mount time and cached in memory.
|
||||
|
||||
3.7 Xattr table
|
||||
---------------
|
||||
|
||||
The xattr table contains extended attributes for each inode. The xattrs
|
||||
for each inode are stored in a list, each list entry containing a type,
|
||||
name and value field. The type field encodes the xattr prefix
|
||||
("user.", "trusted." etc) and it also encodes how the name/value fields
|
||||
should be interpreted. Currently the type indicates whether the value
|
||||
is stored inline (in which case the value field contains the xattr value),
|
||||
or if it is stored out of line (in which case the value field stores a
|
||||
reference to where the actual value is stored). This allows large values
|
||||
to be stored out of line improving scanning and lookup performance and it
|
||||
also allows values to be de-duplicated, the value being stored once, and
|
||||
all other occurences holding an out of line reference to that value.
|
||||
|
||||
The xattr lists are packed into compressed 8K metadata blocks.
|
||||
To reduce overhead in inodes, rather than storing the on-disk
|
||||
location of the xattr list inside each inode, a 32-bit xattr id
|
||||
is stored. This xattr id is mapped into the location of the xattr
|
||||
list using a second xattr id lookup table.
|
||||
|
||||
4. TODOS AND OUTSTANDING ISSUES
|
||||
-------------------------------
|
||||
@ -199,9 +223,7 @@ it is small) is read at mount time and cached in memory.
|
||||
4.1 Todo list
|
||||
-------------
|
||||
|
||||
Implement Xattr and ACL support. The Squashfs 4.0 filesystem layout has hooks
|
||||
for these but the code has not been written. Once the code has been written
|
||||
the existing layout should not require modification.
|
||||
Implement ACL support.
|
||||
|
||||
4.2 Squashfs internal cache
|
||||
---------------------------
|
||||
|
@ -26,6 +26,17 @@ config SQUASHFS
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SQUASHFS_XATTRS
|
||||
bool "Squashfs XATTR support"
|
||||
depends on SQUASHFS
|
||||
default n
|
||||
help
|
||||
Saying Y here includes support for extended attributes (xattrs).
|
||||
Xattrs are name:value pairs associated with inodes by
|
||||
the kernel or by users (see the attr(5) manual page).
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config SQUASHFS_EMBEDDED
|
||||
|
||||
bool "Additional option for memory-constrained systems"
|
||||
|
@ -5,3 +5,5 @@
|
||||
obj-$(CONFIG_SQUASHFS) += squashfs.o
|
||||
squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o
|
||||
squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o
|
||||
squashfs-$(CONFIG_SQUASHFS_XATTRS) += xattr.o xattr_id.o
|
||||
|
||||
|
@ -40,11 +40,13 @@
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/xattr.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_fs_sb.h"
|
||||
#include "squashfs_fs_i.h"
|
||||
#include "squashfs.h"
|
||||
#include "xattr.h"
|
||||
|
||||
/*
|
||||
* Initialise VFS inode with the base inode information common to all
|
||||
@ -111,6 +113,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
|
||||
int err, type, offset = SQUASHFS_INODE_OFFSET(ino);
|
||||
union squashfs_inode squashfs_ino;
|
||||
struct squashfs_base_inode *sqshb_ino = &squashfs_ino.base;
|
||||
int xattr_id = SQUASHFS_INVALID_XATTR;
|
||||
|
||||
TRACE("Entered squashfs_read_inode\n");
|
||||
|
||||
@ -199,8 +202,10 @@ int squashfs_read_inode(struct inode *inode, long long ino)
|
||||
frag_offset = 0;
|
||||
}
|
||||
|
||||
xattr_id = le32_to_cpu(sqsh_ino->xattr);
|
||||
inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
|
||||
inode->i_size = le64_to_cpu(sqsh_ino->file_size);
|
||||
inode->i_op = &squashfs_inode_ops;
|
||||
inode->i_fop = &generic_ro_fops;
|
||||
inode->i_mode |= S_IFREG;
|
||||
inode->i_blocks = ((inode->i_size -
|
||||
@ -251,6 +256,7 @@ int squashfs_read_inode(struct inode *inode, long long ino)
|
||||
if (err < 0)
|
||||
goto failed_read;
|
||||
|
||||
xattr_id = le32_to_cpu(sqsh_ino->xattr);
|
||||
inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
|
||||
inode->i_size = le32_to_cpu(sqsh_ino->file_size);
|
||||
inode->i_op = &squashfs_dir_inode_ops;
|
||||
@ -280,21 +286,33 @@ int squashfs_read_inode(struct inode *inode, long long ino)
|
||||
|
||||
inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
|
||||
inode->i_size = le32_to_cpu(sqsh_ino->symlink_size);
|
||||
inode->i_op = &page_symlink_inode_operations;
|
||||
inode->i_op = &squashfs_symlink_inode_ops;
|
||||
inode->i_data.a_ops = &squashfs_symlink_aops;
|
||||
inode->i_mode |= S_IFLNK;
|
||||
squashfs_i(inode)->start = block;
|
||||
squashfs_i(inode)->offset = offset;
|
||||
|
||||
if (type == SQUASHFS_LSYMLINK_TYPE) {
|
||||
__le32 xattr;
|
||||
|
||||
err = squashfs_read_metadata(sb, NULL, &block,
|
||||
&offset, inode->i_size);
|
||||
if (err < 0)
|
||||
goto failed_read;
|
||||
err = squashfs_read_metadata(sb, &xattr, &block,
|
||||
&offset, sizeof(xattr));
|
||||
if (err < 0)
|
||||
goto failed_read;
|
||||
xattr_id = le32_to_cpu(xattr);
|
||||
}
|
||||
|
||||
TRACE("Symbolic link inode %x:%x, start_block %llx, offset "
|
||||
"%x\n", SQUASHFS_INODE_BLK(ino), offset,
|
||||
block, offset);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_BLKDEV_TYPE:
|
||||
case SQUASHFS_CHRDEV_TYPE:
|
||||
case SQUASHFS_LBLKDEV_TYPE:
|
||||
case SQUASHFS_LCHRDEV_TYPE: {
|
||||
case SQUASHFS_CHRDEV_TYPE: {
|
||||
struct squashfs_dev_inode *sqsh_ino = &squashfs_ino.dev;
|
||||
unsigned int rdev;
|
||||
|
||||
@ -315,10 +333,32 @@ int squashfs_read_inode(struct inode *inode, long long ino)
|
||||
SQUASHFS_INODE_BLK(ino), offset, rdev);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_LBLKDEV_TYPE:
|
||||
case SQUASHFS_LCHRDEV_TYPE: {
|
||||
struct squashfs_ldev_inode *sqsh_ino = &squashfs_ino.ldev;
|
||||
unsigned int rdev;
|
||||
|
||||
err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
|
||||
sizeof(*sqsh_ino));
|
||||
if (err < 0)
|
||||
goto failed_read;
|
||||
|
||||
if (type == SQUASHFS_LCHRDEV_TYPE)
|
||||
inode->i_mode |= S_IFCHR;
|
||||
else
|
||||
inode->i_mode |= S_IFBLK;
|
||||
xattr_id = le32_to_cpu(sqsh_ino->xattr);
|
||||
inode->i_op = &squashfs_inode_ops;
|
||||
inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
|
||||
rdev = le32_to_cpu(sqsh_ino->rdev);
|
||||
init_special_inode(inode, inode->i_mode, new_decode_dev(rdev));
|
||||
|
||||
TRACE("Device inode %x:%x, rdev %x\n",
|
||||
SQUASHFS_INODE_BLK(ino), offset, rdev);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_FIFO_TYPE:
|
||||
case SQUASHFS_SOCKET_TYPE:
|
||||
case SQUASHFS_LFIFO_TYPE:
|
||||
case SQUASHFS_LSOCKET_TYPE: {
|
||||
case SQUASHFS_SOCKET_TYPE: {
|
||||
struct squashfs_ipc_inode *sqsh_ino = &squashfs_ino.ipc;
|
||||
|
||||
err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
|
||||
@ -334,14 +374,52 @@ int squashfs_read_inode(struct inode *inode, long long ino)
|
||||
init_special_inode(inode, inode->i_mode, 0);
|
||||
break;
|
||||
}
|
||||
case SQUASHFS_LFIFO_TYPE:
|
||||
case SQUASHFS_LSOCKET_TYPE: {
|
||||
struct squashfs_lipc_inode *sqsh_ino = &squashfs_ino.lipc;
|
||||
|
||||
err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset,
|
||||
sizeof(*sqsh_ino));
|
||||
if (err < 0)
|
||||
goto failed_read;
|
||||
|
||||
if (type == SQUASHFS_LFIFO_TYPE)
|
||||
inode->i_mode |= S_IFIFO;
|
||||
else
|
||||
inode->i_mode |= S_IFSOCK;
|
||||
xattr_id = le32_to_cpu(sqsh_ino->xattr);
|
||||
inode->i_op = &squashfs_inode_ops;
|
||||
inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
|
||||
init_special_inode(inode, inode->i_mode, 0);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ERROR("Unknown inode type %d in squashfs_iget!\n", type);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (xattr_id != SQUASHFS_INVALID_XATTR && msblk->xattr_id_table) {
|
||||
err = squashfs_xattr_lookup(sb, xattr_id,
|
||||
&squashfs_i(inode)->xattr_count,
|
||||
&squashfs_i(inode)->xattr_size,
|
||||
&squashfs_i(inode)->xattr);
|
||||
if (err < 0)
|
||||
goto failed_read;
|
||||
inode->i_blocks += ((squashfs_i(inode)->xattr_size - 1) >> 9)
|
||||
+ 1;
|
||||
} else
|
||||
squashfs_i(inode)->xattr_count = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
failed_read:
|
||||
ERROR("Unable to read inode 0x%llx\n", ino);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
const struct inode_operations squashfs_inode_ops = {
|
||||
.getxattr = generic_getxattr,
|
||||
.listxattr = squashfs_listxattr
|
||||
};
|
||||
|
||||
|
@ -57,11 +57,13 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/xattr.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_fs_sb.h"
|
||||
#include "squashfs_fs_i.h"
|
||||
#include "squashfs.h"
|
||||
#include "xattr.h"
|
||||
|
||||
/*
|
||||
* Lookup name in the directory index, returning the location of the metadata
|
||||
@ -237,5 +239,7 @@ failed:
|
||||
|
||||
|
||||
const struct inode_operations squashfs_dir_inode_ops = {
|
||||
.lookup = squashfs_lookup
|
||||
.lookup = squashfs_lookup,
|
||||
.getxattr = generic_getxattr,
|
||||
.listxattr = squashfs_listxattr
|
||||
};
|
||||
|
@ -73,8 +73,11 @@ extern struct inode *squashfs_iget(struct super_block *, long long,
|
||||
unsigned int);
|
||||
extern int squashfs_read_inode(struct inode *, long long);
|
||||
|
||||
/* xattr.c */
|
||||
extern ssize_t squashfs_listxattr(struct dentry *, char *, size_t);
|
||||
|
||||
/*
|
||||
* Inodes, files and decompressor operations
|
||||
* Inodes, files, decompressor and xattr operations
|
||||
*/
|
||||
|
||||
/* dir.c */
|
||||
@ -86,11 +89,18 @@ extern const struct export_operations squashfs_export_ops;
|
||||
/* file.c */
|
||||
extern const struct address_space_operations squashfs_aops;
|
||||
|
||||
/* inode.c */
|
||||
extern const struct inode_operations squashfs_inode_ops;
|
||||
|
||||
/* namei.c */
|
||||
extern const struct inode_operations squashfs_dir_inode_ops;
|
||||
|
||||
/* symlink.c */
|
||||
extern const struct address_space_operations squashfs_symlink_aops;
|
||||
extern const struct inode_operations squashfs_symlink_inode_ops;
|
||||
|
||||
/* xattr.c */
|
||||
extern const struct xattr_handler *squashfs_xattr_handlers[];
|
||||
|
||||
/* zlib_wrapper.c */
|
||||
extern const struct squashfs_decompressor squashfs_zlib_comp_ops;
|
||||
|
@ -46,6 +46,7 @@
|
||||
#define SQUASHFS_NAME_LEN 256
|
||||
|
||||
#define SQUASHFS_INVALID_FRAG (0xffffffffU)
|
||||
#define SQUASHFS_INVALID_XATTR (0xffffffffU)
|
||||
#define SQUASHFS_INVALID_BLK (-1LL)
|
||||
|
||||
/* Filesystem flags */
|
||||
@ -96,6 +97,13 @@
|
||||
#define SQUASHFS_LFIFO_TYPE 13
|
||||
#define SQUASHFS_LSOCKET_TYPE 14
|
||||
|
||||
/* Xattr types */
|
||||
#define SQUASHFS_XATTR_USER 0
|
||||
#define SQUASHFS_XATTR_TRUSTED 1
|
||||
#define SQUASHFS_XATTR_SECURITY 2
|
||||
#define SQUASHFS_XATTR_VALUE_OOL 256
|
||||
#define SQUASHFS_XATTR_PREFIX_MASK 0xff
|
||||
|
||||
/* Flag whether block is compressed or uncompressed, bit is set if block is
|
||||
* uncompressed */
|
||||
#define SQUASHFS_COMPRESSED_BIT (1 << 15)
|
||||
@ -174,6 +182,24 @@
|
||||
|
||||
#define SQUASHFS_ID_BLOCK_BYTES(A) (SQUASHFS_ID_BLOCKS(A) *\
|
||||
sizeof(u64))
|
||||
/* xattr id lookup table defines */
|
||||
#define SQUASHFS_XATTR_BYTES(A) ((A) * sizeof(struct squashfs_xattr_id))
|
||||
|
||||
#define SQUASHFS_XATTR_BLOCK(A) (SQUASHFS_XATTR_BYTES(A) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_XATTR_BLOCK_OFFSET(A) (SQUASHFS_XATTR_BYTES(A) % \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_XATTR_BLOCKS(A) ((SQUASHFS_XATTR_BYTES(A) + \
|
||||
SQUASHFS_METADATA_SIZE - 1) / \
|
||||
SQUASHFS_METADATA_SIZE)
|
||||
|
||||
#define SQUASHFS_XATTR_BLOCK_BYTES(A) (SQUASHFS_XATTR_BLOCKS(A) *\
|
||||
sizeof(u64))
|
||||
#define SQUASHFS_XATTR_BLK(A) ((unsigned int) ((A) >> 16))
|
||||
|
||||
#define SQUASHFS_XATTR_OFFSET(A) ((unsigned int) ((A) & 0xffff))
|
||||
|
||||
/* cached data constants for filesystem */
|
||||
#define SQUASHFS_CACHED_BLKS 8
|
||||
@ -228,7 +254,7 @@ struct squashfs_super_block {
|
||||
__le64 root_inode;
|
||||
__le64 bytes_used;
|
||||
__le64 id_table_start;
|
||||
__le64 xattr_table_start;
|
||||
__le64 xattr_id_table_start;
|
||||
__le64 inode_table_start;
|
||||
__le64 directory_table_start;
|
||||
__le64 fragment_table_start;
|
||||
@ -261,6 +287,17 @@ struct squashfs_ipc_inode {
|
||||
__le32 nlink;
|
||||
};
|
||||
|
||||
struct squashfs_lipc_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
__le16 uid;
|
||||
__le16 guid;
|
||||
__le32 mtime;
|
||||
__le32 inode_number;
|
||||
__le32 nlink;
|
||||
__le32 xattr;
|
||||
};
|
||||
|
||||
struct squashfs_dev_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
@ -272,6 +309,18 @@ struct squashfs_dev_inode {
|
||||
__le32 rdev;
|
||||
};
|
||||
|
||||
struct squashfs_ldev_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
__le16 uid;
|
||||
__le16 guid;
|
||||
__le32 mtime;
|
||||
__le32 inode_number;
|
||||
__le32 nlink;
|
||||
__le32 rdev;
|
||||
__le32 xattr;
|
||||
};
|
||||
|
||||
struct squashfs_symlink_inode {
|
||||
__le16 inode_type;
|
||||
__le16 mode;
|
||||
@ -349,12 +398,14 @@ struct squashfs_ldir_inode {
|
||||
union squashfs_inode {
|
||||
struct squashfs_base_inode base;
|
||||
struct squashfs_dev_inode dev;
|
||||
struct squashfs_ldev_inode ldev;
|
||||
struct squashfs_symlink_inode symlink;
|
||||
struct squashfs_reg_inode reg;
|
||||
struct squashfs_lreg_inode lreg;
|
||||
struct squashfs_dir_inode dir;
|
||||
struct squashfs_ldir_inode ldir;
|
||||
struct squashfs_ipc_inode ipc;
|
||||
struct squashfs_lipc_inode lipc;
|
||||
};
|
||||
|
||||
struct squashfs_dir_entry {
|
||||
@ -377,4 +428,27 @@ struct squashfs_fragment_entry {
|
||||
unsigned int unused;
|
||||
};
|
||||
|
||||
struct squashfs_xattr_entry {
|
||||
__le16 type;
|
||||
__le16 size;
|
||||
char data[0];
|
||||
};
|
||||
|
||||
struct squashfs_xattr_val {
|
||||
__le32 vsize;
|
||||
char value[0];
|
||||
};
|
||||
|
||||
struct squashfs_xattr_id {
|
||||
__le64 xattr;
|
||||
__le32 count;
|
||||
__le32 size;
|
||||
};
|
||||
|
||||
struct squashfs_xattr_id_table {
|
||||
__le64 xattr_table_start;
|
||||
__le32 xattr_ids;
|
||||
__le32 unused;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -26,6 +26,9 @@
|
||||
struct squashfs_inode_info {
|
||||
u64 start;
|
||||
int offset;
|
||||
u64 xattr;
|
||||
unsigned int xattr_size;
|
||||
int xattr_count;
|
||||
union {
|
||||
struct {
|
||||
u64 fragment_block;
|
||||
|
@ -61,6 +61,7 @@ struct squashfs_sb_info {
|
||||
int next_meta_index;
|
||||
__le64 *id_table;
|
||||
__le64 *fragment_index;
|
||||
__le64 *xattr_id_table;
|
||||
struct mutex read_data_mutex;
|
||||
struct mutex meta_index_mutex;
|
||||
struct meta_index *meta_index;
|
||||
@ -68,9 +69,11 @@ struct squashfs_sb_info {
|
||||
__le64 *inode_lookup_table;
|
||||
u64 inode_table;
|
||||
u64 directory_table;
|
||||
u64 xattr_table;
|
||||
unsigned int block_size;
|
||||
unsigned short block_log;
|
||||
long long bytes_used;
|
||||
unsigned int inodes;
|
||||
int xattr_ids;
|
||||
};
|
||||
#endif
|
||||
|
@ -36,12 +36,14 @@
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/magic.h>
|
||||
#include <linux/xattr.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_fs_sb.h"
|
||||
#include "squashfs_fs_i.h"
|
||||
#include "squashfs.h"
|
||||
#include "decompressor.h"
|
||||
#include "xattr.h"
|
||||
|
||||
static struct file_system_type squashfs_fs_type;
|
||||
static const struct super_operations squashfs_super_ops;
|
||||
@ -82,7 +84,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
long long root_inode;
|
||||
unsigned short flags;
|
||||
unsigned int fragments;
|
||||
u64 lookup_table_start;
|
||||
u64 lookup_table_start, xattr_id_table_start;
|
||||
int err;
|
||||
|
||||
TRACE("Entered squashfs_fill_superblock\n");
|
||||
@ -139,13 +141,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
if (msblk->decompressor == NULL)
|
||||
goto failed_mount;
|
||||
|
||||
/*
|
||||
* Check if there's xattrs in the filesystem. These are not
|
||||
* supported in this version, so warn that they will be ignored.
|
||||
*/
|
||||
if (le64_to_cpu(sblk->xattr_table_start) != SQUASHFS_INVALID_BLK)
|
||||
ERROR("Xattrs in filesystem, these will be ignored\n");
|
||||
|
||||
/* Check the filesystem does not extend beyond the end of the
|
||||
block device */
|
||||
msblk->bytes_used = le64_to_cpu(sblk->bytes_used);
|
||||
@ -253,7 +248,7 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent)
|
||||
allocate_lookup_table:
|
||||
lookup_table_start = le64_to_cpu(sblk->lookup_table_start);
|
||||
if (lookup_table_start == SQUASHFS_INVALID_BLK)
|
||||
goto allocate_root;
|
||||
goto allocate_xattr_table;
|
||||
|
||||
/* Allocate and read inode lookup table */
|
||||
msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb,
|
||||
@ -266,6 +261,21 @@ allocate_lookup_table:
|
||||
|
||||
sb->s_export_op = &squashfs_export_ops;
|
||||
|
||||
allocate_xattr_table:
|
||||
sb->s_xattr = squashfs_xattr_handlers;
|
||||
xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start);
|
||||
if (xattr_id_table_start == SQUASHFS_INVALID_BLK)
|
||||
goto allocate_root;
|
||||
|
||||
/* Allocate and read xattr id lookup table */
|
||||
msblk->xattr_id_table = squashfs_read_xattr_id_table(sb,
|
||||
xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids);
|
||||
if (IS_ERR(msblk->xattr_id_table)) {
|
||||
err = PTR_ERR(msblk->xattr_id_table);
|
||||
msblk->xattr_id_table = NULL;
|
||||
if (err != -ENOTSUPP)
|
||||
goto failed_mount;
|
||||
}
|
||||
allocate_root:
|
||||
root = new_inode(sb);
|
||||
if (!root) {
|
||||
@ -301,6 +311,7 @@ failed_mount:
|
||||
kfree(msblk->inode_lookup_table);
|
||||
kfree(msblk->fragment_index);
|
||||
kfree(msblk->id_table);
|
||||
kfree(msblk->xattr_id_table);
|
||||
kfree(sb->s_fs_info);
|
||||
sb->s_fs_info = NULL;
|
||||
kfree(sblk);
|
||||
@ -355,6 +366,7 @@ static void squashfs_put_super(struct super_block *sb)
|
||||
kfree(sbi->fragment_index);
|
||||
kfree(sbi->meta_index);
|
||||
kfree(sbi->inode_lookup_table);
|
||||
kfree(sbi->xattr_id_table);
|
||||
kfree(sb->s_fs_info);
|
||||
sb->s_fs_info = NULL;
|
||||
}
|
||||
|
@ -35,11 +35,13 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/xattr.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_fs_sb.h"
|
||||
#include "squashfs_fs_i.h"
|
||||
#include "squashfs.h"
|
||||
#include "xattr.h"
|
||||
|
||||
static int squashfs_symlink_readpage(struct file *file, struct page *page)
|
||||
{
|
||||
@ -114,3 +116,12 @@ error_out:
|
||||
const struct address_space_operations squashfs_symlink_aops = {
|
||||
.readpage = squashfs_symlink_readpage
|
||||
};
|
||||
|
||||
const struct inode_operations squashfs_symlink_inode_ops = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = page_follow_link_light,
|
||||
.put_link = page_put_link,
|
||||
.getxattr = generic_getxattr,
|
||||
.listxattr = squashfs_listxattr
|
||||
};
|
||||
|
||||
|
323
fs/squashfs/xattr.c
Normal file
323
fs/squashfs/xattr.c
Normal file
@ -0,0 +1,323 @@
|
||||
/*
|
||||
* Squashfs - a compressed read only filesystem for Linux
|
||||
*
|
||||
* Copyright (c) 2010
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* xattr_id.c
|
||||
*/
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_fs_sb.h"
|
||||
#include "squashfs_fs_i.h"
|
||||
#include "squashfs.h"
|
||||
|
||||
static const struct xattr_handler *squashfs_xattr_handler(int);
|
||||
|
||||
ssize_t squashfs_listxattr(struct dentry *d, char *buffer,
|
||||
size_t buffer_size)
|
||||
{
|
||||
struct inode *inode = d->d_inode;
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct squashfs_sb_info *msblk = sb->s_fs_info;
|
||||
u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr)
|
||||
+ msblk->xattr_table;
|
||||
int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr);
|
||||
int count = squashfs_i(inode)->xattr_count;
|
||||
size_t rest = buffer_size;
|
||||
int err;
|
||||
|
||||
/* check that the file system has xattrs */
|
||||
if (msblk->xattr_id_table == NULL)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
/* loop reading each xattr name */
|
||||
while (count--) {
|
||||
struct squashfs_xattr_entry entry;
|
||||
struct squashfs_xattr_val val;
|
||||
const struct xattr_handler *handler;
|
||||
int name_size, prefix_size = 0;
|
||||
|
||||
err = squashfs_read_metadata(sb, &entry, &start, &offset,
|
||||
sizeof(entry));
|
||||
if (err < 0)
|
||||
goto failed;
|
||||
|
||||
name_size = le16_to_cpu(entry.size);
|
||||
handler = squashfs_xattr_handler(le16_to_cpu(entry.type));
|
||||
if (handler)
|
||||
prefix_size = handler->list(d, buffer, rest, NULL,
|
||||
name_size, handler->flags);
|
||||
if (prefix_size) {
|
||||
if (buffer) {
|
||||
if (prefix_size + name_size + 1 > rest) {
|
||||
err = -ERANGE;
|
||||
goto failed;
|
||||
}
|
||||
buffer += prefix_size;
|
||||
}
|
||||
err = squashfs_read_metadata(sb, buffer, &start,
|
||||
&offset, name_size);
|
||||
if (err < 0)
|
||||
goto failed;
|
||||
if (buffer) {
|
||||
buffer[name_size] = '\0';
|
||||
buffer += name_size + 1;
|
||||
}
|
||||
rest -= prefix_size + name_size + 1;
|
||||
} else {
|
||||
/* no handler or insuffficient privileges, so skip */
|
||||
err = squashfs_read_metadata(sb, NULL, &start,
|
||||
&offset, name_size);
|
||||
if (err < 0)
|
||||
goto failed;
|
||||
}
|
||||
|
||||
|
||||
/* skip remaining xattr entry */
|
||||
err = squashfs_read_metadata(sb, &val, &start, &offset,
|
||||
sizeof(val));
|
||||
if (err < 0)
|
||||
goto failed;
|
||||
|
||||
err = squashfs_read_metadata(sb, NULL, &start, &offset,
|
||||
le32_to_cpu(val.vsize));
|
||||
if (err < 0)
|
||||
goto failed;
|
||||
}
|
||||
err = buffer_size - rest;
|
||||
|
||||
failed:
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
static int squashfs_xattr_get(struct inode *inode, int name_index,
|
||||
const char *name, void *buffer, size_t buffer_size)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct squashfs_sb_info *msblk = sb->s_fs_info;
|
||||
u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr)
|
||||
+ msblk->xattr_table;
|
||||
int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr);
|
||||
int count = squashfs_i(inode)->xattr_count;
|
||||
int name_len = strlen(name);
|
||||
int err, vsize;
|
||||
char *target = kmalloc(name_len, GFP_KERNEL);
|
||||
|
||||
if (target == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
/* loop reading each xattr name */
|
||||
for (; count; count--) {
|
||||
struct squashfs_xattr_entry entry;
|
||||
struct squashfs_xattr_val val;
|
||||
int type, prefix, name_size;
|
||||
|
||||
err = squashfs_read_metadata(sb, &entry, &start, &offset,
|
||||
sizeof(entry));
|
||||
if (err < 0)
|
||||
goto failed;
|
||||
|
||||
name_size = le16_to_cpu(entry.size);
|
||||
type = le16_to_cpu(entry.type);
|
||||
prefix = type & SQUASHFS_XATTR_PREFIX_MASK;
|
||||
|
||||
if (prefix == name_index && name_size == name_len)
|
||||
err = squashfs_read_metadata(sb, target, &start,
|
||||
&offset, name_size);
|
||||
else
|
||||
err = squashfs_read_metadata(sb, NULL, &start,
|
||||
&offset, name_size);
|
||||
if (err < 0)
|
||||
goto failed;
|
||||
|
||||
if (prefix == name_index && name_size == name_len &&
|
||||
strncmp(target, name, name_size) == 0) {
|
||||
/* found xattr */
|
||||
if (type & SQUASHFS_XATTR_VALUE_OOL) {
|
||||
__le64 xattr;
|
||||
/* val is a reference to the real location */
|
||||
err = squashfs_read_metadata(sb, &val, &start,
|
||||
&offset, sizeof(val));
|
||||
if (err < 0)
|
||||
goto failed;
|
||||
err = squashfs_read_metadata(sb, &xattr, &start,
|
||||
&offset, sizeof(xattr));
|
||||
if (err < 0)
|
||||
goto failed;
|
||||
xattr = le64_to_cpu(xattr);
|
||||
start = SQUASHFS_XATTR_BLK(xattr) +
|
||||
msblk->xattr_table;
|
||||
offset = SQUASHFS_XATTR_OFFSET(xattr);
|
||||
}
|
||||
/* read xattr value */
|
||||
err = squashfs_read_metadata(sb, &val, &start, &offset,
|
||||
sizeof(val));
|
||||
if (err < 0)
|
||||
goto failed;
|
||||
|
||||
vsize = le32_to_cpu(val.vsize);
|
||||
if (buffer) {
|
||||
if (vsize > buffer_size) {
|
||||
err = -ERANGE;
|
||||
goto failed;
|
||||
}
|
||||
err = squashfs_read_metadata(sb, buffer, &start,
|
||||
&offset, vsize);
|
||||
if (err < 0)
|
||||
goto failed;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* no match, skip remaining xattr entry */
|
||||
err = squashfs_read_metadata(sb, &val, &start, &offset,
|
||||
sizeof(val));
|
||||
if (err < 0)
|
||||
goto failed;
|
||||
err = squashfs_read_metadata(sb, NULL, &start, &offset,
|
||||
le32_to_cpu(val.vsize));
|
||||
if (err < 0)
|
||||
goto failed;
|
||||
}
|
||||
err = count ? vsize : -ENODATA;
|
||||
|
||||
failed:
|
||||
kfree(target);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* User namespace support
|
||||
*/
|
||||
static size_t squashfs_user_list(struct dentry *d, char *list, size_t list_size,
|
||||
const char *name, size_t name_len, int type)
|
||||
{
|
||||
if (list && XATTR_USER_PREFIX_LEN <= list_size)
|
||||
memcpy(list, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN);
|
||||
return XATTR_USER_PREFIX_LEN;
|
||||
}
|
||||
|
||||
static int squashfs_user_get(struct dentry *d, const char *name, void *buffer,
|
||||
size_t size, int type)
|
||||
{
|
||||
if (name[0] == '\0')
|
||||
return -EINVAL;
|
||||
|
||||
return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_USER, name,
|
||||
buffer, size);
|
||||
}
|
||||
|
||||
static const struct xattr_handler squashfs_xattr_user_handler = {
|
||||
.prefix = XATTR_USER_PREFIX,
|
||||
.list = squashfs_user_list,
|
||||
.get = squashfs_user_get
|
||||
};
|
||||
|
||||
/*
|
||||
* Trusted namespace support
|
||||
*/
|
||||
static size_t squashfs_trusted_list(struct dentry *d, char *list,
|
||||
size_t list_size, const char *name, size_t name_len, int type)
|
||||
{
|
||||
if (!capable(CAP_SYS_ADMIN))
|
||||
return 0;
|
||||
|
||||
if (list && XATTR_TRUSTED_PREFIX_LEN <= list_size)
|
||||
memcpy(list, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN);
|
||||
return XATTR_TRUSTED_PREFIX_LEN;
|
||||
}
|
||||
|
||||
static int squashfs_trusted_get(struct dentry *d, const char *name,
|
||||
void *buffer, size_t size, int type)
|
||||
{
|
||||
if (name[0] == '\0')
|
||||
return -EINVAL;
|
||||
|
||||
return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_TRUSTED, name,
|
||||
buffer, size);
|
||||
}
|
||||
|
||||
static const struct xattr_handler squashfs_xattr_trusted_handler = {
|
||||
.prefix = XATTR_TRUSTED_PREFIX,
|
||||
.list = squashfs_trusted_list,
|
||||
.get = squashfs_trusted_get
|
||||
};
|
||||
|
||||
/*
|
||||
* Security namespace support
|
||||
*/
|
||||
static size_t squashfs_security_list(struct dentry *d, char *list,
|
||||
size_t list_size, const char *name, size_t name_len, int type)
|
||||
{
|
||||
if (list && XATTR_SECURITY_PREFIX_LEN <= list_size)
|
||||
memcpy(list, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN);
|
||||
return XATTR_SECURITY_PREFIX_LEN;
|
||||
}
|
||||
|
||||
static int squashfs_security_get(struct dentry *d, const char *name,
|
||||
void *buffer, size_t size, int type)
|
||||
{
|
||||
if (name[0] == '\0')
|
||||
return -EINVAL;
|
||||
|
||||
return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_SECURITY, name,
|
||||
buffer, size);
|
||||
}
|
||||
|
||||
static const struct xattr_handler squashfs_xattr_security_handler = {
|
||||
.prefix = XATTR_SECURITY_PREFIX,
|
||||
.list = squashfs_security_list,
|
||||
.get = squashfs_security_get
|
||||
};
|
||||
|
||||
static inline const struct xattr_handler *squashfs_xattr_handler(int type)
|
||||
{
|
||||
if (type & ~(SQUASHFS_XATTR_PREFIX_MASK | SQUASHFS_XATTR_VALUE_OOL))
|
||||
/* ignore unrecognised type */
|
||||
return NULL;
|
||||
|
||||
switch (type & SQUASHFS_XATTR_PREFIX_MASK) {
|
||||
case SQUASHFS_XATTR_USER:
|
||||
return &squashfs_xattr_user_handler;
|
||||
case SQUASHFS_XATTR_TRUSTED:
|
||||
return &squashfs_xattr_trusted_handler;
|
||||
case SQUASHFS_XATTR_SECURITY:
|
||||
return &squashfs_xattr_security_handler;
|
||||
default:
|
||||
/* ignore unrecognised type */
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
const struct xattr_handler *squashfs_xattr_handlers[] = {
|
||||
&squashfs_xattr_user_handler,
|
||||
&squashfs_xattr_trusted_handler,
|
||||
&squashfs_xattr_security_handler,
|
||||
NULL
|
||||
};
|
||||
|
46
fs/squashfs/xattr.h
Normal file
46
fs/squashfs/xattr.h
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Squashfs - a compressed read only filesystem for Linux
|
||||
*
|
||||
* Copyright (c) 2010
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* xattr.h
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SQUASHFS_XATTRS
|
||||
extern __le64 *squashfs_read_xattr_id_table(struct super_block *, u64,
|
||||
u64 *, int *);
|
||||
extern int squashfs_xattr_lookup(struct super_block *, unsigned int, int *,
|
||||
int *, unsigned long long *);
|
||||
#else
|
||||
static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb,
|
||||
u64 start, u64 *xattr_table_start, int *xattr_ids)
|
||||
{
|
||||
ERROR("Xattrs in filesystem, these will be ignored\n");
|
||||
return ERR_PTR(-ENOTSUPP);
|
||||
}
|
||||
|
||||
static inline int squashfs_xattr_lookup(struct super_block *sb,
|
||||
unsigned int index, int *count, int *size,
|
||||
unsigned long long *xattr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#define squashfs_listxattr NULL
|
||||
#define generic_getxattr NULL
|
||||
#define squashfs_xattr_handlers NULL
|
||||
#endif
|
100
fs/squashfs/xattr_id.c
Normal file
100
fs/squashfs/xattr_id.c
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Squashfs - a compressed read only filesystem for Linux
|
||||
*
|
||||
* Copyright (c) 2010
|
||||
* Phillip Lougher <phillip@lougher.demon.co.uk>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2,
|
||||
* or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* xattr_id.c
|
||||
*/
|
||||
|
||||
/*
|
||||
* This file implements code to map the 32-bit xattr id stored in the inode
|
||||
* into the on disk location of the xattr data.
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/vfs.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "squashfs_fs.h"
|
||||
#include "squashfs_fs_sb.h"
|
||||
#include "squashfs_fs_i.h"
|
||||
#include "squashfs.h"
|
||||
|
||||
/*
|
||||
* Map xattr id using the xattr id look up table
|
||||
*/
|
||||
int squashfs_xattr_lookup(struct super_block *sb, unsigned int index,
|
||||
int *count, unsigned int *size, unsigned long long *xattr)
|
||||
{
|
||||
struct squashfs_sb_info *msblk = sb->s_fs_info;
|
||||
int block = SQUASHFS_XATTR_BLOCK(index);
|
||||
int offset = SQUASHFS_XATTR_BLOCK_OFFSET(index);
|
||||
u64 start_block = le64_to_cpu(msblk->xattr_id_table[block]);
|
||||
struct squashfs_xattr_id id;
|
||||
int err;
|
||||
|
||||
err = squashfs_read_metadata(sb, &id, &start_block, &offset,
|
||||
sizeof(id));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
*xattr = le64_to_cpu(id.xattr);
|
||||
*size = le32_to_cpu(id.size);
|
||||
*count = le32_to_cpu(id.count);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read uncompressed xattr id lookup table indexes from disk into memory
|
||||
*/
|
||||
__le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start,
|
||||
u64 *xattr_table_start, int *xattr_ids)
|
||||
{
|
||||
unsigned int len;
|
||||
__le64 *xid_table;
|
||||
struct squashfs_xattr_id_table id_table;
|
||||
int err;
|
||||
|
||||
err = squashfs_read_table(sb, &id_table, start, sizeof(id_table));
|
||||
if (err < 0) {
|
||||
ERROR("unable to read xattr id table\n");
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
*xattr_table_start = le64_to_cpu(id_table.xattr_table_start);
|
||||
*xattr_ids = le32_to_cpu(id_table.xattr_ids);
|
||||
len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids);
|
||||
|
||||
TRACE("In read_xattr_index_table, length %d\n", len);
|
||||
|
||||
/* Allocate xattr id lookup table indexes */
|
||||
xid_table = kmalloc(len, GFP_KERNEL);
|
||||
if (xid_table == NULL) {
|
||||
ERROR("Failed to allocate xattr id index table\n");
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
err = squashfs_read_table(sb, xid_table, start + sizeof(id_table), len);
|
||||
if (err < 0) {
|
||||
ERROR("unable to read xattr id index table\n");
|
||||
kfree(xid_table);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
return xid_table;
|
||||
}
|
Loading…
Reference in New Issue
Block a user