|
From: Stephen H. <she...@vy...> - 2010-04-29 23:10:14
|
This is a revised version of Helge's patch to add xattr support to squashfs.
It fixes:
* updated to match -next tree.
* indentation and formatting cleaned up
* code is now checkpatch and sparse clean
* function and structure names shortened where it makes sense
* files without attributes are handled correctly by listxattr
(ie. getcap /mnt/sqfs/bin/ls)
Data format is same as original patch.
---
fs/squashfs/Makefile | 2
fs/squashfs/inode.c | 5
fs/squashfs/namei.c | 9 +
fs/squashfs/squashfs.h | 7 +
fs/squashfs/squashfs_fs.h | 10 +
fs/squashfs/squashfs_fs_i.h | 1
fs/squashfs/squashfs_fs_sb.h | 1
fs/squashfs/super.c | 8 -
fs/squashfs/xattr.c | 244 +++++++++++++++++++++++++++++++++++++++++++
9 files changed, 278 insertions(+), 9 deletions(-)
create mode 100644 fs/squashfs/xattr.c
--- a/fs/squashfs/Makefile 2010-03-17 16:08:04.743943243 -0700
+++ b/fs/squashfs/Makefile 2010-04-29 10:29:56.512141672 -0700
@@ -4,4 +4,4 @@
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-y += namei.o super.o symlink.o xattr.o zlib_wrapper.o decompressor.o
--- a/fs/squashfs/inode.c 2010-03-17 16:08:04.743943243 -0700
+++ b/fs/squashfs/inode.c 2010-04-29 15:56:12.596981893 -0700
@@ -126,6 +126,8 @@ int squashfs_read_inode(struct inode *in
if (err)
goto failed_read;
+ squashfs_i(inode)->xattr = -1;
+
block = SQUASHFS_INODE_BLK(ino) + msblk->inode_table;
offset = SQUASHFS_INODE_OFFSET(ino);
@@ -159,6 +161,7 @@ int squashfs_read_inode(struct inode *in
inode->i_nlink = 1;
inode->i_size = le32_to_cpu(sqsh_ino->file_size);
inode->i_fop = &generic_ro_fops;
+ inode->i_op = &squashfs_file_inode_ops;
inode->i_mode |= S_IFREG;
inode->i_blocks = ((inode->i_size - 1) >> 9) + 1;
squashfs_i(inode)->fragment_block = frag_blk;
@@ -202,10 +205,12 @@ int squashfs_read_inode(struct inode *in
inode->i_nlink = le32_to_cpu(sqsh_ino->nlink);
inode->i_size = le64_to_cpu(sqsh_ino->file_size);
inode->i_fop = &generic_ro_fops;
+ inode->i_op = &squashfs_file_inode_ops;
inode->i_mode |= S_IFREG;
inode->i_blocks = ((inode->i_size -
le64_to_cpu(sqsh_ino->sparse) - 1) >> 9) + 1;
+ squashfs_i(inode)->xattr = le32_to_cpu(sqsh_ino->xattr);
squashfs_i(inode)->fragment_block = frag_blk;
squashfs_i(inode)->fragment_size = frag_size;
squashfs_i(inode)->fragment_offset = frag_offset;
@@ -256,6 +261,7 @@ int squashfs_read_inode(struct inode *in
inode->i_op = &squashfs_dir_inode_ops;
inode->i_fop = &squashfs_dir_ops;
inode->i_mode |= S_IFDIR;
+ squashfs_i(inode)->xattr = le32_to_cpu(sqsh_ino->xattr);
squashfs_i(inode)->start = le32_to_cpu(sqsh_ino->start_block);
squashfs_i(inode)->offset = le16_to_cpu(sqsh_ino->offset);
squashfs_i(inode)->dir_idx_start = block;
--- a/fs/squashfs/namei.c 2010-03-17 16:08:04.743943243 -0700
+++ b/fs/squashfs/namei.c 2010-04-29 10:27:52.231936892 -0700
@@ -237,5 +237,12 @@ failed:
const struct inode_operations squashfs_dir_inode_ops = {
- .lookup = squashfs_lookup
+ .lookup = squashfs_lookup,
+ .listxattr = squashfs_listxattr,
+ .getxattr = squashfs_getxattr
+};
+
+const struct inode_operations squashfs_file_inode_ops = {
+ .listxattr = squashfs_listxattr,
+ .getxattr = squashfs_getxattr
};
--- a/fs/squashfs/squashfs.h 2010-03-17 16:08:04.743943243 -0700
+++ b/fs/squashfs/squashfs.h 2010-04-29 10:29:22.632766492 -0700
@@ -88,9 +88,16 @@ extern const struct address_space_operat
/* namei.c */
extern const struct inode_operations squashfs_dir_inode_ops;
+extern const struct inode_operations squashfs_file_inode_ops;
/* symlink.c */
extern const struct address_space_operations squashfs_symlink_aops;
+/* xattr.c */
+extern ssize_t squashfs_listxattr(struct dentry *dentry, char *buffer,
+ size_t size);
+extern ssize_t squashfs_getxattr(struct dentry *dentry, const char *name,
+ void *buffer, size_t size);
+
/* zlib_wrapper.c */
extern const struct squashfs_decompressor squashfs_zlib_comp_ops;
--- a/fs/squashfs/squashfs_fs.h 2010-03-17 16:08:04.743943243 -0700
+++ b/fs/squashfs/squashfs_fs.h 2010-04-29 10:38:59.649199700 -0700
@@ -377,4 +377,14 @@ struct squashfs_fragment_entry {
unsigned int unused;
};
+struct squashfs_xattr_entry {
+ __le32 name_len;
+ __le32 value_len;
+ char name_and_value_data[0];
+};
+
+struct squashfs_xattr_header {
+ __le32 size;
+};
+
#endif
--- a/fs/squashfs/squashfs_fs_i.h 2010-03-17 16:08:04.743943243 -0700
+++ b/fs/squashfs/squashfs_fs_i.h 2010-04-29 10:27:52.331829401 -0700
@@ -26,6 +26,7 @@
struct squashfs_inode_info {
u64 start;
int offset;
+ u32 xattr;
union {
struct {
u64 fragment_block;
--- a/fs/squashfs/squashfs_fs_sb.h 2010-03-17 16:08:04.743943243 -0700
+++ b/fs/squashfs/squashfs_fs_sb.h 2010-04-29 10:31:00.241205088 -0700
@@ -68,6 +68,7 @@ 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;
--- a/fs/squashfs/super.c 2010-04-29 09:27:15.871522099 -0700
+++ b/fs/squashfs/super.c 2010-04-29 10:27:52.351829435 -0700
@@ -139,13 +139,6 @@ static int squashfs_fill_super(struct su
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);
@@ -179,6 +172,7 @@ static int squashfs_fill_super(struct su
msblk->inode_table = le64_to_cpu(sblk->inode_table_start);
msblk->directory_table = le64_to_cpu(sblk->directory_table_start);
+ msblk->xattr_table = le64_to_cpu(sblk->xattr_table_start);
msblk->inodes = le32_to_cpu(sblk->inodes);
flags = le16_to_cpu(sblk->flags);
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ b/fs/squashfs/xattr.c 2010-04-29 15:50:38.593977693 -0700
@@ -0,0 +1,243 @@
+/*
+ * Squashfs - a compressed read only filesystem for Linux
+ *
+ * Copyright (c) 2010
+ * Helge Bahmann <hel...@se...>
+ *
+ * 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.c
+ */
+
+/*
+ * This file implements code to handle extended attributes.
+ *
+ * Extended attributes are stored in a fashion similar to directories: packed
+ * into compressed metadata blocks, stored in the xattr table. Extended
+ * attributes are located in this table using the start address of the
+ * metablock containing the first byte of the attribute, as well as
+ * the offset of the first byte. The tuple (<block, offset>) is encoded
+ * into a single 32-bit quantity, using the upper 19 bits for the block
+ * and the lower 13 bits for the offset.
+ *
+ * Each set of extended attributes associated with a file is stored as a
+ * 32-bit length marker, followed by all name/value pairs forming the
+ * attribute set. The attribute names must follow the common linux convention
+ * using "user.", "security." etc. as prefix respectively.
+ */
+
+#include <linux/fs.h>
+#include <linux/vfs.h>
+#include <linux/slab.h>
+#include <linux/zlib.h>
+#include <linux/xattr.h>
+
+#include "squashfs_fs.h"
+#include "squashfs_fs_sb.h"
+#include "squashfs_fs_i.h"
+#include "squashfs.h"
+
+struct squashfs_xattr_iterator {
+ unsigned int name_len, value_len;
+ char *name;
+ void *value;
+
+ struct super_block *sb;
+ u64 block;
+ int offset;
+
+ unsigned int remaining_bytes;
+};
+
+static void
+xattr_iterator_release_buffer(struct squashfs_xattr_iterator *iter)
+{
+ kfree(iter->name);
+ iter->name = NULL;
+ kfree(iter->value);
+ iter->value = NULL;
+}
+
+static int
+xattr_iterator_read_next(struct squashfs_xattr_iterator *iter)
+{
+ int err;
+ int total_len;
+ struct squashfs_xattr_entry entry;
+
+ if (iter->remaining_bytes == 0)
+ return 0;
+
+ if (iter->remaining_bytes < sizeof(struct squashfs_xattr_entry))
+ return -EIO;
+
+ err = squashfs_read_metadata(iter->sb, &entry, &iter->block,
+ &iter->offset, sizeof(entry));
+ if (err < 0)
+ return err;
+
+ if (err < sizeof(entry))
+ return 0;
+
+ iter->remaining_bytes -= sizeof(entry);
+ iter->name_len = le32_to_cpu(entry.name_len);
+ iter->value_len = le32_to_cpu(entry.value_len);
+ if (iter->name_len > 4096 || iter->value_len > 65536)
+ return -EIO;
+
+ total_len = iter->name_len + iter->value_len;
+ if (total_len > iter->remaining_bytes)
+ return -EIO;
+
+ iter->name = kmalloc(iter->name_len+1, GFP_KERNEL);
+ if (!iter->name)
+ return -ENOMEM;
+ iter->value = kmalloc(iter->value_len, GFP_KERNEL);
+ if (!iter->value)
+ return -ENOMEM;
+
+ err = squashfs_read_metadata(iter->sb, iter->name, &iter->block,
+ &iter->offset, iter->name_len);
+ if (err < 0)
+ return err;
+ if (err < iter->name_len)
+ return -EIO;
+ iter->name[iter->name_len] = 0;
+
+ err = squashfs_read_metadata(iter->sb, iter->value, &iter->block,
+ &iter->offset, iter->value_len);
+ if (err < 0)
+ return err;
+ if (err < iter->value_len)
+ return -EIO;
+
+ iter->remaining_bytes -= total_len;
+
+ return 1;
+}
+
+static int
+squashfs_xattr_iterator_start(struct squashfs_xattr_iterator *iter,
+ struct inode *inode)
+{
+ struct super_block *sb = inode->i_sb;
+ struct squashfs_sb_info *msblk = sb->s_fs_info;
+ int xattr = squashfs_i(inode)->xattr;
+ struct squashfs_xattr_header xattr_header;
+ int err;
+
+ iter->sb = sb;
+ iter->name = NULL;
+ iter->value = NULL;
+
+ if (xattr == -1 || msblk->xattr_table == -1)
+ return 0;
+
+ iter->block = msblk->xattr_table + (xattr >> 13);
+ iter->offset = xattr & 8191;
+
+ err = squashfs_read_metadata(iter->sb, &xattr_header, &iter->block,
+ &iter->offset, sizeof(xattr_header));
+ if (err < 0)
+ return err;
+ if (err < 4)
+ return -EIO;
+
+ iter->remaining_bytes = le32_to_cpu(xattr_header.size) - 4;
+
+ return xattr_iterator_read_next(iter);
+}
+
+static int
+squashfs_xattr_iterator_next(struct squashfs_xattr_iterator *iter)
+{
+ xattr_iterator_release_buffer(iter);
+ return xattr_iterator_read_next(iter);
+}
+
+static void
+squashfs_xattr_iterator_end(struct squashfs_xattr_iterator *iter)
+{
+ xattr_iterator_release_buffer(iter);
+}
+
+static inline int filtered(const char *name)
+{
+ if (capable(CAP_SYS_ADMIN))
+ return 0;
+
+ return strncmp(XATTR_TRUSTED_PREFIX, name,
+ XATTR_TRUSTED_PREFIX_LEN) == 0;
+}
+
+ssize_t
+squashfs_listxattr(struct dentry *dentry, char *buffer, size_t size)
+{
+ struct squashfs_xattr_iterator iter;
+ int next_xattr;
+ ssize_t xattr_names_size = 0;
+
+ next_xattr = squashfs_xattr_iterator_start(&iter, dentry->d_inode);
+ while (next_xattr == 1) {
+ if (!filtered(iter.name)) {
+ xattr_names_size += iter.name_len;
+ if (size) {
+ size_t to_copy = size > (iter.name_len + 1) ?
+ (iter.name_len + 1) : size;
+ memcpy(buffer, iter.name, to_copy);
+ buffer += to_copy;
+ size -= to_copy;
+ }
+ }
+ next_xattr = squashfs_xattr_iterator_next(&iter);
+ }
+
+ squashfs_xattr_iterator_end(&iter);
+
+ return (next_xattr < 0) ? next_xattr : xattr_names_size;
+}
+
+ssize_t
+squashfs_getxattr(struct dentry *dentry, const char *name,
+ void *buffer, size_t size)
+{
+ struct squashfs_xattr_iterator iter;
+ int next_xattr;
+
+ next_xattr = squashfs_xattr_iterator_start(&iter, dentry->d_inode);
+
+ while (next_xattr == 1) {
+ if (strcmp(name, iter.name) == 0) {
+ if (buffer) {
+ if (size >= iter.value_len) {
+ memcpy(buffer,
+ iter.value, iter.value_len);
+ next_xattr = iter.value_len;
+ } else
+ next_xattr = -ERANGE;
+ } else
+ next_xattr = iter.value_len;
+ break;
+ }
+ next_xattr = squashfs_xattr_iterator_next(&iter);
+ }
+
+ squashfs_xattr_iterator_end(&iter);
+
+ if (next_xattr == 0)
+ next_xattr = -ENODATA;
+
+ return next_xattr;
+}
|