diff options
| -rw-r--r-- | Documentation/filesystems/squashfs.txt | 32 | ||||
| -rw-r--r-- | fs/squashfs/Kconfig | 11 | ||||
| -rw-r--r-- | fs/squashfs/Makefile | 2 | ||||
| -rw-r--r-- | fs/squashfs/inode.c | 92 | ||||
| -rw-r--r-- | fs/squashfs/namei.c | 6 | ||||
| -rw-r--r-- | fs/squashfs/squashfs.h | 12 | ||||
| -rw-r--r-- | fs/squashfs/squashfs_fs.h | 76 | ||||
| -rw-r--r-- | fs/squashfs/squashfs_fs_i.h | 3 | ||||
| -rw-r--r-- | fs/squashfs/squashfs_fs_sb.h | 3 | ||||
| -rw-r--r-- | fs/squashfs/super.c | 30 | ||||
| -rw-r--r-- | fs/squashfs/symlink.c | 11 | ||||
| -rw-r--r-- | fs/squashfs/xattr.c | 323 | ||||
| -rw-r--r-- | fs/squashfs/xattr.h | 46 | ||||
| -rw-r--r-- | fs/squashfs/xattr_id.c | 100 |
14 files changed, 723 insertions, 24 deletions
diff --git a/Documentation/filesystems/squashfs.txt b/Documentation/filesystems/squashfs.txt index b324c033035a..203f7202cc9e 100644 --- a/Documentation/filesystems/squashfs.txt +++ b/Documentation/filesystems/squashfs.txt | |||
| @@ -38,7 +38,8 @@ Hard link support: yes no | |||
| 38 | Real inode numbers: yes no | 38 | Real inode numbers: yes no |
| 39 | 32-bit uids/gids: yes no | 39 | 32-bit uids/gids: yes no |
| 40 | File creation time: yes no | 40 | File creation time: yes no |
| 41 | Xattr and ACL support: no no | 41 | Xattr support: yes no |
| 42 | ACL support: no no | ||
| 42 | 43 | ||
| 43 | Squashfs compresses data, inodes and directories. In addition, inode and | 44 | Squashfs compresses data, inodes and directories. In addition, inode and |
| 44 | directory data are highly compacted, and packed on byte boundaries. Each | 45 | directory data are highly compacted, and packed on byte boundaries. Each |
| @@ -58,7 +59,7 @@ obtained from this site also. | |||
| 58 | 3. SQUASHFS FILESYSTEM DESIGN | 59 | 3. SQUASHFS FILESYSTEM DESIGN |
| 59 | ----------------------------- | 60 | ----------------------------- |
| 60 | 61 | ||
| 61 | A squashfs filesystem consists of seven parts, packed together on a byte | 62 | A squashfs filesystem consists of a maximum of eight parts, packed together on a byte |
| 62 | alignment: | 63 | alignment: |
| 63 | 64 | ||
| 64 | --------------- | 65 | --------------- |
| @@ -80,6 +81,9 @@ alignment: | |||
| 80 | |---------------| | 81 | |---------------| |
| 81 | | uid/gid | | 82 | | uid/gid | |
| 82 | | lookup table | | 83 | | lookup table | |
| 84 | |---------------| | ||
| 85 | | xattr | | ||
| 86 | | table | | ||
| 83 | --------------- | 87 | --------------- |
| 84 | 88 | ||
| 85 | Compressed data blocks are written to the filesystem as files are read from | 89 | 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 | |||
| 192 | used to locate these. This second index table for speed of access (and because | 196 | used to locate these. This second index table for speed of access (and because |
| 193 | it is small) is read at mount time and cached in memory. | 197 | it is small) is read at mount time and cached in memory. |
| 194 | 198 | ||
| 199 | 3.7 Xattr table | ||
| 200 | --------------- | ||
| 201 | |||
| 202 | The xattr table contains extended attributes for each inode. The xattrs | ||
| 203 | for each inode are stored in a list, each list entry containing a type, | ||
| 204 | name and value field. The type field encodes the xattr prefix | ||
| 205 | ("user.", "trusted." etc) and it also encodes how the name/value fields | ||
| 206 | should be interpreted. Currently the type indicates whether the value | ||
| 207 | is stored inline (in which case the value field contains the xattr value), | ||
| 208 | or if it is stored out of line (in which case the value field stores a | ||
| 209 | reference to where the actual value is stored). This allows large values | ||
| 210 | to be stored out of line improving scanning and lookup performance and it | ||
| 211 | also allows values to be de-duplicated, the value being stored once, and | ||
| 212 | all other occurences holding an out of line reference to that value. | ||
| 213 | |||
| 214 | The xattr lists are packed into compressed 8K metadata blocks. | ||
| 215 | To reduce overhead in inodes, rather than storing the on-disk | ||
| 216 | location of the xattr list inside each inode, a 32-bit xattr id | ||
| 217 | is stored. This xattr id is mapped into the location of the xattr | ||
| 218 | list using a second xattr id lookup table. | ||
| 195 | 219 | ||
| 196 | 4. TODOS AND OUTSTANDING ISSUES | 220 | 4. TODOS AND OUTSTANDING ISSUES |
| 197 | ------------------------------- | 221 | ------------------------------- |
| @@ -199,9 +223,7 @@ it is small) is read at mount time and cached in memory. | |||
| 199 | 4.1 Todo list | 223 | 4.1 Todo list |
| 200 | ------------- | 224 | ------------- |
| 201 | 225 | ||
| 202 | Implement Xattr and ACL support. The Squashfs 4.0 filesystem layout has hooks | 226 | Implement ACL support. |
| 203 | for these but the code has not been written. Once the code has been written | ||
| 204 | the existing layout should not require modification. | ||
| 205 | 227 | ||
| 206 | 4.2 Squashfs internal cache | 228 | 4.2 Squashfs internal cache |
| 207 | --------------------------- | 229 | --------------------------- |
diff --git a/fs/squashfs/Kconfig b/fs/squashfs/Kconfig index 25a00d19d686..cc6ce8a84c21 100644 --- a/fs/squashfs/Kconfig +++ b/fs/squashfs/Kconfig | |||
| @@ -26,6 +26,17 @@ config SQUASHFS | |||
| 26 | 26 | ||
| 27 | If unsure, say N. | 27 | If unsure, say N. |
| 28 | 28 | ||
| 29 | config SQUASHFS_XATTRS | ||
| 30 | bool "Squashfs XATTR support" | ||
| 31 | depends on SQUASHFS | ||
| 32 | default n | ||
| 33 | help | ||
| 34 | Saying Y here includes support for extended attributes (xattrs). | ||
| 35 | Xattrs are name:value pairs associated with inodes by | ||
| 36 | the kernel or by users (see the attr(5) manual page). | ||
| 37 | |||
| 38 | If unsure, say N. | ||
| 39 | |||
| 29 | config SQUASHFS_EMBEDDED | 40 | config SQUASHFS_EMBEDDED |
| 30 | 41 | ||
| 31 | bool "Additional option for memory-constrained systems" | 42 | bool "Additional option for memory-constrained systems" |
diff --git a/fs/squashfs/Makefile b/fs/squashfs/Makefile index df8a19ef870d..2cee3e9fa452 100644 --- a/fs/squashfs/Makefile +++ b/fs/squashfs/Makefile | |||
| @@ -5,3 +5,5 @@ | |||
| 5 | obj-$(CONFIG_SQUASHFS) += squashfs.o | 5 | obj-$(CONFIG_SQUASHFS) += squashfs.o |
| 6 | squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o | 6 | squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o |
| 7 | squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o | 7 | squashfs-y += namei.o super.o symlink.o zlib_wrapper.o decompressor.o |
| 8 | squashfs-$(CONFIG_SQUASHFS_XATTRS) += xattr.o xattr_id.o | ||
| 9 | |||
diff --git a/fs/squashfs/inode.c b/fs/squashfs/inode.c index 49daaf669e41..62e63ad25075 100644 --- a/fs/squashfs/inode.c +++ b/fs/squashfs/inode.c | |||
| @@ -40,11 +40,13 @@ | |||
| 40 | 40 | ||
| 41 | #include <linux/fs.h> | 41 | #include <linux/fs.h> |
| 42 | #include <linux/vfs.h> | 42 | #include <linux/vfs.h> |
| 43 | #include <linux/xattr.h> | ||
| 43 | 44 | ||
| 44 | #include "squashfs_fs.h" | 45 | #include "squashfs_fs.h" |
| 45 | #include "squashfs_fs_sb.h" | 46 | #include "squashfs_fs_sb.h" |
| 46 | #include "squashfs_fs_i.h" | 47 | #include "squashfs_fs_i.h" |
| 47 | #include "squashfs.h" | 48 | #include "squashfs.h" |
| 49 | #include "xattr.h" | ||
| 48 | 50 | ||
| 49 | /* | 51 | /* |
| 50 | * Initialise VFS inode with the base inode information common to all | 52 | * 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) | |||
| 111 | int err, type, offset = SQUASHFS_INODE_OFFSET(ino); | 113 | int err, type, offset = SQUASHFS_INODE_OFFSET(ino); |
| 112 | union squashfs_inode squashfs_ino; | 114 | union squashfs_inode squashfs_ino; |
| 113 | struct squashfs_base_inode *sqshb_ino = &squashfs_ino.base; | 115 | struct squashfs_base_inode *sqshb_ino = &squashfs_ino.base; |
| 116 | int xattr_id = SQUASHFS_INVALID_XATTR; | ||
| 114 | 117 | ||
| 115 | TRACE("Entered squashfs_read_inode\n"); | 118 | TRACE("Entered squashfs_read_inode\n"); |
| 116 | 119 | ||
| @@ -199,8 +202,10 @@ int squashfs_read_inode(struct inode *inode, long long ino) | |||
| 199 | frag_offset = 0; | 202 | frag_offset = 0; |
| 200 | } | 203 | } |
| 201 | 204 | ||
| 205 | xattr_id = le32_to_cpu(sqsh_ino->xattr); | ||
| 202 | inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); | 206 | inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); |
| 203 | inode->i_size = le64_to_cpu(sqsh_ino->file_size); | 207 | inode->i_size = le64_to_cpu(sqsh_ino->file_size); |
| 208 | inode->i_op = &squashfs_inode_ops; | ||
| 204 | inode->i_fop = &generic_ro_fops; | 209 | inode->i_fop = &generic_ro_fops; |
| 205 | inode->i_mode |= S_IFREG; | 210 | inode->i_mode |= S_IFREG; |
| 206 | inode->i_blocks = ((inode->i_size - | 211 | inode->i_blocks = ((inode->i_size - |
| @@ -251,6 +256,7 @@ int squashfs_read_inode(struct inode *inode, long long ino) | |||
| 251 | if (err < 0) | 256 | if (err < 0) |
| 252 | goto failed_read; | 257 | goto failed_read; |
| 253 | 258 | ||
| 259 | xattr_id = le32_to_cpu(sqsh_ino->xattr); | ||
| 254 | inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); | 260 | inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); |
| 255 | inode->i_size = le32_to_cpu(sqsh_ino->file_size); | 261 | inode->i_size = le32_to_cpu(sqsh_ino->file_size); |
| 256 | inode->i_op = &squashfs_dir_inode_ops; | 262 | inode->i_op = &squashfs_dir_inode_ops; |
| @@ -280,21 +286,33 @@ int squashfs_read_inode(struct inode *inode, long long ino) | |||
| 280 | 286 | ||
| 281 | inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); | 287 | inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); |
| 282 | inode->i_size = le32_to_cpu(sqsh_ino->symlink_size); | 288 | inode->i_size = le32_to_cpu(sqsh_ino->symlink_size); |
| 283 | inode->i_op = &page_symlink_inode_operations; | 289 | inode->i_op = &squashfs_symlink_inode_ops; |
| 284 | inode->i_data.a_ops = &squashfs_symlink_aops; | 290 | inode->i_data.a_ops = &squashfs_symlink_aops; |
| 285 | inode->i_mode |= S_IFLNK; | 291 | inode->i_mode |= S_IFLNK; |
| 286 | squashfs_i(inode)->start = block; | 292 | squashfs_i(inode)->start = block; |
| 287 | squashfs_i(inode)->offset = offset; | 293 | squashfs_i(inode)->offset = offset; |
| 288 | 294 | ||
| 295 | if (type == SQUASHFS_LSYMLINK_TYPE) { | ||
| 296 | __le32 xattr; | ||
| 297 | |||
| 298 | err = squashfs_read_metadata(sb, NULL, &block, | ||
| 299 | &offset, inode->i_size); | ||
| 300 | if (err < 0) | ||
| 301 | goto failed_read; | ||
| 302 | err = squashfs_read_metadata(sb, &xattr, &block, | ||
| 303 | &offset, sizeof(xattr)); | ||
| 304 | if (err < 0) | ||
| 305 | goto failed_read; | ||
| 306 | xattr_id = le32_to_cpu(xattr); | ||
| 307 | } | ||
| 308 | |||
| 289 | TRACE("Symbolic link inode %x:%x, start_block %llx, offset " | 309 | TRACE("Symbolic link inode %x:%x, start_block %llx, offset " |
| 290 | "%x\n", SQUASHFS_INODE_BLK(ino), offset, | 310 | "%x\n", SQUASHFS_INODE_BLK(ino), offset, |
| 291 | block, offset); | 311 | block, offset); |
| 292 | break; | 312 | break; |
| 293 | } | 313 | } |
| 294 | case SQUASHFS_BLKDEV_TYPE: | 314 | case SQUASHFS_BLKDEV_TYPE: |
| 295 | case SQUASHFS_CHRDEV_TYPE: | 315 | case SQUASHFS_CHRDEV_TYPE: { |
| 296 | case SQUASHFS_LBLKDEV_TYPE: | ||
| 297 | case SQUASHFS_LCHRDEV_TYPE: { | ||
| 298 | struct squashfs_dev_inode *sqsh_ino = &squashfs_ino.dev; | 316 | struct squashfs_dev_inode *sqsh_ino = &squashfs_ino.dev; |
| 299 | unsigned int rdev; | 317 | unsigned int rdev; |
| 300 | 318 | ||
| @@ -315,10 +333,32 @@ int squashfs_read_inode(struct inode *inode, long long ino) | |||
| 315 | SQUASHFS_INODE_BLK(ino), offset, rdev); | 333 | SQUASHFS_INODE_BLK(ino), offset, rdev); |
| 316 | break; | 334 | break; |
| 317 | } | 335 | } |
| 336 | case SQUASHFS_LBLKDEV_TYPE: | ||
| 337 | case SQUASHFS_LCHRDEV_TYPE: { | ||
| 338 | struct squashfs_ldev_inode *sqsh_ino = &squashfs_ino.ldev; | ||
| 339 | unsigned int rdev; | ||
| 340 | |||
| 341 | err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, | ||
| 342 | sizeof(*sqsh_ino)); | ||
| 343 | if (err < 0) | ||
| 344 | goto failed_read; | ||
| 345 | |||
| 346 | if (type == SQUASHFS_LCHRDEV_TYPE) | ||
| 347 | inode->i_mode |= S_IFCHR; | ||
| 348 | else | ||
| 349 | inode->i_mode |= S_IFBLK; | ||
| 350 | xattr_id = le32_to_cpu(sqsh_ino->xattr); | ||
| 351 | inode->i_op = &squashfs_inode_ops; | ||
| 352 | inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); | ||
| 353 | rdev = le32_to_cpu(sqsh_ino->rdev); | ||
| 354 | init_special_inode(inode, inode->i_mode, new_decode_dev(rdev)); | ||
| 355 | |||
| 356 | TRACE("Device inode %x:%x, rdev %x\n", | ||
| 357 | SQUASHFS_INODE_BLK(ino), offset, rdev); | ||
| 358 | break; | ||
| 359 | } | ||
| 318 | case SQUASHFS_FIFO_TYPE: | 360 | case SQUASHFS_FIFO_TYPE: |
| 319 | case SQUASHFS_SOCKET_TYPE: | 361 | case SQUASHFS_SOCKET_TYPE: { |
| 320 | case SQUASHFS_LFIFO_TYPE: | ||
| 321 | case SQUASHFS_LSOCKET_TYPE: { | ||
| 322 | struct squashfs_ipc_inode *sqsh_ino = &squashfs_ino.ipc; | 362 | struct squashfs_ipc_inode *sqsh_ino = &squashfs_ino.ipc; |
| 323 | 363 | ||
| 324 | err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, | 364 | err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, |
| @@ -334,14 +374,52 @@ int squashfs_read_inode(struct inode *inode, long long ino) | |||
| 334 | init_special_inode(inode, inode->i_mode, 0); | 374 | init_special_inode(inode, inode->i_mode, 0); |
| 335 | break; | 375 | break; |
| 336 | } | 376 | } |
| 377 | case SQUASHFS_LFIFO_TYPE: | ||
| 378 | case SQUASHFS_LSOCKET_TYPE: { | ||
| 379 | struct squashfs_lipc_inode *sqsh_ino = &squashfs_ino.lipc; | ||
| 380 | |||
| 381 | err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, | ||
| 382 | sizeof(*sqsh_ino)); | ||
| 383 | if (err < 0) | ||
| 384 | goto failed_read; | ||
| 385 | |||
| 386 | if (type == SQUASHFS_LFIFO_TYPE) | ||
| 387 | inode->i_mode |= S_IFIFO; | ||
| 388 | else | ||
| 389 | inode->i_mode |= S_IFSOCK; | ||
| 390 | xattr_id = le32_to_cpu(sqsh_ino->xattr); | ||
| 391 | inode->i_op = &squashfs_inode_ops; | ||
| 392 | inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); | ||
| 393 | init_special_inode(inode, inode->i_mode, 0); | ||
| 394 | break; | ||
| 395 | } | ||
| 337 | default: | 396 | default: |
| 338 | ERROR("Unknown inode type %d in squashfs_iget!\n", type); | 397 | ERROR("Unknown inode type %d in squashfs_iget!\n", type); |
| 339 | return -EINVAL; | 398 | return -EINVAL; |
| 340 | } | 399 | } |
| 341 | 400 | ||
| 401 | if (xattr_id != SQUASHFS_INVALID_XATTR && msblk->xattr_id_table) { | ||
| 402 | err = squashfs_xattr_lookup(sb, xattr_id, | ||
| 403 | &squashfs_i(inode)->xattr_count, | ||
| 404 | &squashfs_i(inode)->xattr_size, | ||
| 405 | &squashfs_i(inode)->xattr); | ||
| 406 | if (err < 0) | ||
| 407 | goto failed_read; | ||
| 408 | inode->i_blocks += ((squashfs_i(inode)->xattr_size - 1) >> 9) | ||
| 409 | + 1; | ||
| 410 | } else | ||
| 411 | squashfs_i(inode)->xattr_count = 0; | ||
| 412 | |||
| 342 | return 0; | 413 | return 0; |
| 343 | 414 | ||
| 344 | failed_read: | 415 | failed_read: |
| 345 | ERROR("Unable to read inode 0x%llx\n", ino); | 416 | ERROR("Unable to read inode 0x%llx\n", ino); |
| 346 | return err; | 417 | return err; |
| 347 | } | 418 | } |
| 419 | |||
| 420 | |||
| 421 | const struct inode_operations squashfs_inode_ops = { | ||
| 422 | .getxattr = generic_getxattr, | ||
| 423 | .listxattr = squashfs_listxattr | ||
| 424 | }; | ||
| 425 | |||
diff --git a/fs/squashfs/namei.c b/fs/squashfs/namei.c index 5266bd8ad932..7a9464d08cf6 100644 --- a/fs/squashfs/namei.c +++ b/fs/squashfs/namei.c | |||
| @@ -57,11 +57,13 @@ | |||
| 57 | #include <linux/slab.h> | 57 | #include <linux/slab.h> |
| 58 | #include <linux/string.h> | 58 | #include <linux/string.h> |
| 59 | #include <linux/dcache.h> | 59 | #include <linux/dcache.h> |
| 60 | #include <linux/xattr.h> | ||
| 60 | 61 | ||
| 61 | #include "squashfs_fs.h" | 62 | #include "squashfs_fs.h" |
| 62 | #include "squashfs_fs_sb.h" | 63 | #include "squashfs_fs_sb.h" |
| 63 | #include "squashfs_fs_i.h" | 64 | #include "squashfs_fs_i.h" |
| 64 | #include "squashfs.h" | 65 | #include "squashfs.h" |
| 66 | #include "xattr.h" | ||
| 65 | 67 | ||
| 66 | /* | 68 | /* |
| 67 | * Lookup name in the directory index, returning the location of the metadata | 69 | * Lookup name in the directory index, returning the location of the metadata |
| @@ -237,5 +239,7 @@ failed: | |||
| 237 | 239 | ||
| 238 | 240 | ||
| 239 | const struct inode_operations squashfs_dir_inode_ops = { | 241 | const struct inode_operations squashfs_dir_inode_ops = { |
| 240 | .lookup = squashfs_lookup | 242 | .lookup = squashfs_lookup, |
| 243 | .getxattr = generic_getxattr, | ||
| 244 | .listxattr = squashfs_listxattr | ||
| 241 | }; | 245 | }; |
diff --git a/fs/squashfs/squashfs.h b/fs/squashfs/squashfs.h index fe2587af5512..733a17c42945 100644 --- a/fs/squashfs/squashfs.h +++ b/fs/squashfs/squashfs.h | |||
| @@ -73,8 +73,11 @@ extern struct inode *squashfs_iget(struct super_block *, long long, | |||
| 73 | unsigned int); | 73 | unsigned int); |
| 74 | extern int squashfs_read_inode(struct inode *, long long); | 74 | extern int squashfs_read_inode(struct inode *, long long); |
| 75 | 75 | ||
| 76 | /* xattr.c */ | ||
| 77 | extern ssize_t squashfs_listxattr(struct dentry *, char *, size_t); | ||
| 78 | |||
| 76 | /* | 79 | /* |
| 77 | * Inodes, files and decompressor operations | 80 | * Inodes, files, decompressor and xattr operations |
| 78 | */ | 81 | */ |
| 79 | 82 | ||
| 80 | /* dir.c */ | 83 | /* dir.c */ |
| @@ -86,11 +89,18 @@ extern const struct export_operations squashfs_export_ops; | |||
| 86 | /* file.c */ | 89 | /* file.c */ |
| 87 | extern const struct address_space_operations squashfs_aops; | 90 | extern const struct address_space_operations squashfs_aops; |
| 88 | 91 | ||
| 92 | /* inode.c */ | ||
| 93 | extern const struct inode_operations squashfs_inode_ops; | ||
| 94 | |||
| 89 | /* namei.c */ | 95 | /* namei.c */ |
| 90 | extern const struct inode_operations squashfs_dir_inode_ops; | 96 | extern const struct inode_operations squashfs_dir_inode_ops; |
| 91 | 97 | ||
| 92 | /* symlink.c */ | 98 | /* symlink.c */ |
| 93 | extern const struct address_space_operations squashfs_symlink_aops; | 99 | extern const struct address_space_operations squashfs_symlink_aops; |
| 100 | extern const struct inode_operations squashfs_symlink_inode_ops; | ||
| 101 | |||
| 102 | /* xattr.c */ | ||
| 103 | extern const struct xattr_handler *squashfs_xattr_handlers[]; | ||
| 94 | 104 | ||
| 95 | /* zlib_wrapper.c */ | 105 | /* zlib_wrapper.c */ |
| 96 | extern const struct squashfs_decompressor squashfs_zlib_comp_ops; | 106 | extern const struct squashfs_decompressor squashfs_zlib_comp_ops; |
diff --git a/fs/squashfs/squashfs_fs.h b/fs/squashfs/squashfs_fs.h index 79024245ea00..8eabb808b78d 100644 --- a/fs/squashfs/squashfs_fs.h +++ b/fs/squashfs/squashfs_fs.h | |||
| @@ -46,6 +46,7 @@ | |||
| 46 | #define SQUASHFS_NAME_LEN 256 | 46 | #define SQUASHFS_NAME_LEN 256 |
| 47 | 47 | ||
| 48 | #define SQUASHFS_INVALID_FRAG (0xffffffffU) | 48 | #define SQUASHFS_INVALID_FRAG (0xffffffffU) |
| 49 | #define SQUASHFS_INVALID_XATTR (0xffffffffU) | ||
| 49 | #define SQUASHFS_INVALID_BLK (-1LL) | 50 | #define SQUASHFS_INVALID_BLK (-1LL) |
| 50 | 51 | ||
| 51 | /* Filesystem flags */ | 52 | /* Filesystem flags */ |
| @@ -96,6 +97,13 @@ | |||
| 96 | #define SQUASHFS_LFIFO_TYPE 13 | 97 | #define SQUASHFS_LFIFO_TYPE 13 |
| 97 | #define SQUASHFS_LSOCKET_TYPE 14 | 98 | #define SQUASHFS_LSOCKET_TYPE 14 |
| 98 | 99 | ||
| 100 | /* Xattr types */ | ||
| 101 | #define SQUASHFS_XATTR_USER 0 | ||
| 102 | #define SQUASHFS_XATTR_TRUSTED 1 | ||
| 103 | #define SQUASHFS_XATTR_SECURITY 2 | ||
| 104 | #define SQUASHFS_XATTR_VALUE_OOL 256 | ||
| 105 | #define SQUASHFS_XATTR_PREFIX_MASK 0xff | ||
| 106 | |||
| 99 | /* Flag whether block is compressed or uncompressed, bit is set if block is | 107 | /* Flag whether block is compressed or uncompressed, bit is set if block is |
| 100 | * uncompressed */ | 108 | * uncompressed */ |
| 101 | #define SQUASHFS_COMPRESSED_BIT (1 << 15) | 109 | #define SQUASHFS_COMPRESSED_BIT (1 << 15) |
| @@ -174,6 +182,24 @@ | |||
| 174 | 182 | ||
| 175 | #define SQUASHFS_ID_BLOCK_BYTES(A) (SQUASHFS_ID_BLOCKS(A) *\ | 183 | #define SQUASHFS_ID_BLOCK_BYTES(A) (SQUASHFS_ID_BLOCKS(A) *\ |
| 176 | sizeof(u64)) | 184 | sizeof(u64)) |
| 185 | /* xattr id lookup table defines */ | ||
| 186 | #define SQUASHFS_XATTR_BYTES(A) ((A) * sizeof(struct squashfs_xattr_id)) | ||
| 187 | |||
| 188 | #define SQUASHFS_XATTR_BLOCK(A) (SQUASHFS_XATTR_BYTES(A) / \ | ||
| 189 | SQUASHFS_METADATA_SIZE) | ||
| 190 | |||
| 191 | #define SQUASHFS_XATTR_BLOCK_OFFSET(A) (SQUASHFS_XATTR_BYTES(A) % \ | ||
| 192 | SQUASHFS_METADATA_SIZE) | ||
| 193 | |||
| 194 | #define SQUASHFS_XATTR_BLOCKS(A) ((SQUASHFS_XATTR_BYTES(A) + \ | ||
| 195 | SQUASHFS_METADATA_SIZE - 1) / \ | ||
| 196 | SQUASHFS_METADATA_SIZE) | ||
| 197 | |||
| 198 | #define SQUASHFS_XATTR_BLOCK_BYTES(A) (SQUASHFS_XATTR_BLOCKS(A) *\ | ||
| 199 | sizeof(u64)) | ||
| 200 | #define SQUASHFS_XATTR_BLK(A) ((unsigned int) ((A) >> 16)) | ||
| 201 | |||
| 202 | #define SQUASHFS_XATTR_OFFSET(A) ((unsigned int) ((A) & 0xffff)) | ||
| 177 | 203 | ||
| 178 | /* cached data constants for filesystem */ | 204 | /* cached data constants for filesystem */ |
| 179 | #define SQUASHFS_CACHED_BLKS 8 | 205 | #define SQUASHFS_CACHED_BLKS 8 |
| @@ -228,7 +254,7 @@ struct squashfs_super_block { | |||
| 228 | __le64 root_inode; | 254 | __le64 root_inode; |
| 229 | __le64 bytes_used; | 255 | __le64 bytes_used; |
| 230 | __le64 id_table_start; | 256 | __le64 id_table_start; |
| 231 | __le64 xattr_table_start; | 257 | __le64 xattr_id_table_start; |
| 232 | __le64 inode_table_start; | 258 | __le64 inode_table_start; |
| 233 | __le64 directory_table_start; | 259 | __le64 directory_table_start; |
| 234 | __le64 fragment_table_start; | 260 | __le64 fragment_table_start; |
| @@ -261,6 +287,17 @@ struct squashfs_ipc_inode { | |||
| 261 | __le32 nlink; | 287 | __le32 nlink; |
| 262 | }; | 288 | }; |
| 263 | 289 | ||
| 290 | struct squashfs_lipc_inode { | ||
| 291 | __le16 inode_type; | ||
| 292 | __le16 mode; | ||
| 293 | __le16 uid; | ||
| 294 | __le16 guid; | ||
| 295 | __le32 mtime; | ||
| 296 | __le32 inode_number; | ||
| 297 | __le32 nlink; | ||
| 298 | __le32 xattr; | ||
| 299 | }; | ||
| 300 | |||
| 264 | struct squashfs_dev_inode { | 301 | struct squashfs_dev_inode { |
| 265 | __le16 inode_type; | 302 | __le16 inode_type; |
| 266 | __le16 mode; | 303 | __le16 mode; |
| @@ -272,6 +309,18 @@ struct squashfs_dev_inode { | |||
| 272 | __le32 rdev; | 309 | __le32 rdev; |
| 273 | }; | 310 | }; |
| 274 | 311 | ||
| 312 | struct squashfs_ldev_inode { | ||
| 313 | __le16 inode_type; | ||
| 314 | __le16 mode; | ||
| 315 | __le16 uid; | ||
| 316 | __le16 guid; | ||
| 317 | __le32 mtime; | ||
| 318 | __le32 inode_number; | ||
| 319 | __le32 nlink; | ||
| 320 | __le32 rdev; | ||
| 321 | __le32 xattr; | ||
| 322 | }; | ||
| 323 | |||
| 275 | struct squashfs_symlink_inode { | 324 | struct squashfs_symlink_inode { |
| 276 | __le16 inode_type; | 325 | __le16 inode_type; |
| 277 | __le16 mode; | 326 | __le16 mode; |
| @@ -349,12 +398,14 @@ struct squashfs_ldir_inode { | |||
| 349 | union squashfs_inode { | 398 | union squashfs_inode { |
| 350 | struct squashfs_base_inode base; | 399 | struct squashfs_base_inode base; |
| 351 | struct squashfs_dev_inode dev; | 400 | struct squashfs_dev_inode dev; |
| 401 | struct squashfs_ldev_inode ldev; | ||
| 352 | struct squashfs_symlink_inode symlink; | 402 | struct squashfs_symlink_inode symlink; |
| 353 | struct squashfs_reg_inode reg; | 403 | struct squashfs_reg_inode reg; |
| 354 | struct squashfs_lreg_inode lreg; | 404 | struct squashfs_lreg_inode lreg; |
| 355 | struct squashfs_dir_inode dir; | 405 | struct squashfs_dir_inode dir; |
| 356 | struct squashfs_ldir_inode ldir; | 406 | struct squashfs_ldir_inode ldir; |
| 357 | struct squashfs_ipc_inode ipc; | 407 | struct squashfs_ipc_inode ipc; |
| 408 | struct squashfs_lipc_inode lipc; | ||
| 358 | }; | 409 | }; |
| 359 | 410 | ||
| 360 | struct squashfs_dir_entry { | 411 | struct squashfs_dir_entry { |
| @@ -377,4 +428,27 @@ struct squashfs_fragment_entry { | |||
| 377 | unsigned int unused; | 428 | unsigned int unused; |
| 378 | }; | 429 | }; |
| 379 | 430 | ||
| 431 | struct squashfs_xattr_entry { | ||
| 432 | __le16 type; | ||
| 433 | __le16 size; | ||
| 434 | char data[0]; | ||
| 435 | }; | ||
| 436 | |||
| 437 | struct squashfs_xattr_val { | ||
| 438 | __le32 vsize; | ||
| 439 | char value[0]; | ||
| 440 | }; | ||
| 441 | |||
| 442 | struct squashfs_xattr_id { | ||
| 443 | __le64 xattr; | ||
| 444 | __le32 count; | ||
| 445 | __le32 size; | ||
| 446 | }; | ||
| 447 | |||
| 448 | struct squashfs_xattr_id_table { | ||
| 449 | __le64 xattr_table_start; | ||
| 450 | __le32 xattr_ids; | ||
| 451 | __le32 unused; | ||
| 452 | }; | ||
| 453 | |||
| 380 | #endif | 454 | #endif |
diff --git a/fs/squashfs/squashfs_fs_i.h b/fs/squashfs/squashfs_fs_i.h index fbfca30c0c68..d3e3a37f28a1 100644 --- a/fs/squashfs/squashfs_fs_i.h +++ b/fs/squashfs/squashfs_fs_i.h | |||
| @@ -26,6 +26,9 @@ | |||
| 26 | struct squashfs_inode_info { | 26 | struct squashfs_inode_info { |
| 27 | u64 start; | 27 | u64 start; |
| 28 | int offset; | 28 | int offset; |
| 29 | u64 xattr; | ||
| 30 | unsigned int xattr_size; | ||
| 31 | int xattr_count; | ||
| 29 | union { | 32 | union { |
| 30 | struct { | 33 | struct { |
| 31 | u64 fragment_block; | 34 | u64 fragment_block; |
diff --git a/fs/squashfs/squashfs_fs_sb.h b/fs/squashfs/squashfs_fs_sb.h index 2e77dc547e25..d9037a5215f0 100644 --- a/fs/squashfs/squashfs_fs_sb.h +++ b/fs/squashfs/squashfs_fs_sb.h | |||
| @@ -61,6 +61,7 @@ struct squashfs_sb_info { | |||
| 61 | int next_meta_index; | 61 | int next_meta_index; |
| 62 | __le64 *id_table; | 62 | __le64 *id_table; |
| 63 | __le64 *fragment_index; | 63 | __le64 *fragment_index; |
| 64 | __le64 *xattr_id_table; | ||
| 64 | struct mutex read_data_mutex; | 65 | struct mutex read_data_mutex; |
| 65 | struct mutex meta_index_mutex; | 66 | struct mutex meta_index_mutex; |
| 66 | struct meta_index *meta_index; | 67 | struct meta_index *meta_index; |
| @@ -68,9 +69,11 @@ struct squashfs_sb_info { | |||
| 68 | __le64 *inode_lookup_table; | 69 | __le64 *inode_lookup_table; |
| 69 | u64 inode_table; | 70 | u64 inode_table; |
| 70 | u64 directory_table; | 71 | u64 directory_table; |
| 72 | u64 xattr_table; | ||
| 71 | unsigned int block_size; | 73 | unsigned int block_size; |
| 72 | unsigned short block_log; | 74 | unsigned short block_log; |
| 73 | long long bytes_used; | 75 | long long bytes_used; |
| 74 | unsigned int inodes; | 76 | unsigned int inodes; |
| 77 | int xattr_ids; | ||
| 75 | }; | 78 | }; |
| 76 | #endif | 79 | #endif |
diff --git a/fs/squashfs/super.c b/fs/squashfs/super.c index 48b6f4a385a6..88b4f8606652 100644 --- a/fs/squashfs/super.c +++ b/fs/squashfs/super.c | |||
| @@ -36,12 +36,14 @@ | |||
| 36 | #include <linux/init.h> | 36 | #include <linux/init.h> |
| 37 | #include <linux/module.h> | 37 | #include <linux/module.h> |
| 38 | #include <linux/magic.h> | 38 | #include <linux/magic.h> |
| 39 | #include <linux/xattr.h> | ||
| 39 | 40 | ||
| 40 | #include "squashfs_fs.h" | 41 | #include "squashfs_fs.h" |
| 41 | #include "squashfs_fs_sb.h" | 42 | #include "squashfs_fs_sb.h" |
| 42 | #include "squashfs_fs_i.h" | 43 | #include "squashfs_fs_i.h" |
| 43 | #include "squashfs.h" | 44 | #include "squashfs.h" |
| 44 | #include "decompressor.h" | 45 | #include "decompressor.h" |
| 46 | #include "xattr.h" | ||
| 45 | 47 | ||
| 46 | static struct file_system_type squashfs_fs_type; | 48 | static struct file_system_type squashfs_fs_type; |
| 47 | static const struct super_operations squashfs_super_ops; | 49 | 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) | |||
| 82 | long long root_inode; | 84 | long long root_inode; |
| 83 | unsigned short flags; | 85 | unsigned short flags; |
| 84 | unsigned int fragments; | 86 | unsigned int fragments; |
| 85 | u64 lookup_table_start; | 87 | u64 lookup_table_start, xattr_id_table_start; |
| 86 | int err; | 88 | int err; |
| 87 | 89 | ||
| 88 | TRACE("Entered squashfs_fill_superblock\n"); | 90 | TRACE("Entered squashfs_fill_superblock\n"); |
| @@ -139,13 +141,6 @@ static int squashfs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 139 | if (msblk->decompressor == NULL) | 141 | if (msblk->decompressor == NULL) |
| 140 | goto failed_mount; | 142 | goto failed_mount; |
| 141 | 143 | ||
| 142 | /* | ||
| 143 | * Check if there's xattrs in the filesystem. These are not | ||
| 144 | * supported in this version, so warn that they will be ignored. | ||
| 145 | */ | ||
| 146 | if (le64_to_cpu(sblk->xattr_table_start) != SQUASHFS_INVALID_BLK) | ||
| 147 | ERROR("Xattrs in filesystem, these will be ignored\n"); | ||
| 148 | |||
| 149 | /* Check the filesystem does not extend beyond the end of the | 144 | /* Check the filesystem does not extend beyond the end of the |
| 150 | block device */ | 145 | block device */ |
| 151 | msblk->bytes_used = le64_to_cpu(sblk->bytes_used); | 146 | 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) | |||
| 253 | allocate_lookup_table: | 248 | allocate_lookup_table: |
| 254 | lookup_table_start = le64_to_cpu(sblk->lookup_table_start); | 249 | lookup_table_start = le64_to_cpu(sblk->lookup_table_start); |
| 255 | if (lookup_table_start == SQUASHFS_INVALID_BLK) | 250 | if (lookup_table_start == SQUASHFS_INVALID_BLK) |
| 256 | goto allocate_root; | 251 | goto allocate_xattr_table; |
| 257 | 252 | ||
| 258 | /* Allocate and read inode lookup table */ | 253 | /* Allocate and read inode lookup table */ |
| 259 | msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb, | 254 | msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb, |
| @@ -266,6 +261,21 @@ allocate_lookup_table: | |||
| 266 | 261 | ||
| 267 | sb->s_export_op = &squashfs_export_ops; | 262 | sb->s_export_op = &squashfs_export_ops; |
| 268 | 263 | ||
| 264 | allocate_xattr_table: | ||
| 265 | sb->s_xattr = squashfs_xattr_handlers; | ||
| 266 | xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start); | ||
| 267 | if (xattr_id_table_start == SQUASHFS_INVALID_BLK) | ||
| 268 | goto allocate_root; | ||
| 269 | |||
| 270 | /* Allocate and read xattr id lookup table */ | ||
| 271 | msblk->xattr_id_table = squashfs_read_xattr_id_table(sb, | ||
| 272 | xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids); | ||
| 273 | if (IS_ERR(msblk->xattr_id_table)) { | ||
| 274 | err = PTR_ERR(msblk->xattr_id_table); | ||
| 275 | msblk->xattr_id_table = NULL; | ||
| 276 | if (err != -ENOTSUPP) | ||
| 277 | goto failed_mount; | ||
| 278 | } | ||
| 269 | allocate_root: | 279 | allocate_root: |
| 270 | root = new_inode(sb); | 280 | root = new_inode(sb); |
| 271 | if (!root) { | 281 | if (!root) { |
| @@ -301,6 +311,7 @@ failed_mount: | |||
| 301 | kfree(msblk->inode_lookup_table); | 311 | kfree(msblk->inode_lookup_table); |
| 302 | kfree(msblk->fragment_index); | 312 | kfree(msblk->fragment_index); |
| 303 | kfree(msblk->id_table); | 313 | kfree(msblk->id_table); |
| 314 | kfree(msblk->xattr_id_table); | ||
| 304 | kfree(sb->s_fs_info); | 315 | kfree(sb->s_fs_info); |
| 305 | sb->s_fs_info = NULL; | 316 | sb->s_fs_info = NULL; |
| 306 | kfree(sblk); | 317 | kfree(sblk); |
| @@ -355,6 +366,7 @@ static void squashfs_put_super(struct super_block *sb) | |||
| 355 | kfree(sbi->fragment_index); | 366 | kfree(sbi->fragment_index); |
| 356 | kfree(sbi->meta_index); | 367 | kfree(sbi->meta_index); |
| 357 | kfree(sbi->inode_lookup_table); | 368 | kfree(sbi->inode_lookup_table); |
| 369 | kfree(sbi->xattr_id_table); | ||
| 358 | kfree(sb->s_fs_info); | 370 | kfree(sb->s_fs_info); |
| 359 | sb->s_fs_info = NULL; | 371 | sb->s_fs_info = NULL; |
| 360 | } | 372 | } |
diff --git a/fs/squashfs/symlink.c b/fs/squashfs/symlink.c index 32b911f4ee39..ec86434921e1 100644 --- a/fs/squashfs/symlink.c +++ b/fs/squashfs/symlink.c | |||
| @@ -35,11 +35,13 @@ | |||
| 35 | #include <linux/kernel.h> | 35 | #include <linux/kernel.h> |
| 36 | #include <linux/string.h> | 36 | #include <linux/string.h> |
| 37 | #include <linux/pagemap.h> | 37 | #include <linux/pagemap.h> |
| 38 | #include <linux/xattr.h> | ||
| 38 | 39 | ||
| 39 | #include "squashfs_fs.h" | 40 | #include "squashfs_fs.h" |
| 40 | #include "squashfs_fs_sb.h" | 41 | #include "squashfs_fs_sb.h" |
| 41 | #include "squashfs_fs_i.h" | 42 | #include "squashfs_fs_i.h" |
| 42 | #include "squashfs.h" | 43 | #include "squashfs.h" |
| 44 | #include "xattr.h" | ||
| 43 | 45 | ||
| 44 | static int squashfs_symlink_readpage(struct file *file, struct page *page) | 46 | static int squashfs_symlink_readpage(struct file *file, struct page *page) |
| 45 | { | 47 | { |
| @@ -114,3 +116,12 @@ error_out: | |||
| 114 | const struct address_space_operations squashfs_symlink_aops = { | 116 | const struct address_space_operations squashfs_symlink_aops = { |
| 115 | .readpage = squashfs_symlink_readpage | 117 | .readpage = squashfs_symlink_readpage |
| 116 | }; | 118 | }; |
| 119 | |||
| 120 | const struct inode_operations squashfs_symlink_inode_ops = { | ||
| 121 | .readlink = generic_readlink, | ||
| 122 | .follow_link = page_follow_link_light, | ||
| 123 | .put_link = page_put_link, | ||
| 124 | .getxattr = generic_getxattr, | ||
| 125 | .listxattr = squashfs_listxattr | ||
| 126 | }; | ||
| 127 | |||
diff --git a/fs/squashfs/xattr.c b/fs/squashfs/xattr.c new file mode 100644 index 000000000000..c7655e8b31cd --- /dev/null +++ b/fs/squashfs/xattr.c | |||
| @@ -0,0 +1,323 @@ | |||
| 1 | /* | ||
| 2 | * Squashfs - a compressed read only filesystem for Linux | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 | ||
| 5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * as published by the Free Software Foundation; either version 2, | ||
| 10 | * or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
| 20 | * | ||
| 21 | * xattr_id.c | ||
| 22 | */ | ||
| 23 | |||
| 24 | #include <linux/init.h> | ||
| 25 | #include <linux/module.h> | ||
| 26 | #include <linux/string.h> | ||
| 27 | #include <linux/fs.h> | ||
| 28 | #include <linux/vfs.h> | ||
| 29 | #include <linux/xattr.h> | ||
| 30 | #include <linux/slab.h> | ||
| 31 | |||
| 32 | #include "squashfs_fs.h" | ||
| 33 | #include "squashfs_fs_sb.h" | ||
| 34 | #include "squashfs_fs_i.h" | ||
| 35 | #include "squashfs.h" | ||
| 36 | |||
| 37 | static const struct xattr_handler *squashfs_xattr_handler(int); | ||
| 38 | |||
| 39 | ssize_t squashfs_listxattr(struct dentry *d, char *buffer, | ||
| 40 | size_t buffer_size) | ||
| 41 | { | ||
| 42 | struct inode *inode = d->d_inode; | ||
| 43 | struct super_block *sb = inode->i_sb; | ||
| 44 | struct squashfs_sb_info *msblk = sb->s_fs_info; | ||
| 45 | u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr) | ||
| 46 | + msblk->xattr_table; | ||
| 47 | int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr); | ||
| 48 | int count = squashfs_i(inode)->xattr_count; | ||
| 49 | size_t rest = buffer_size; | ||
| 50 | int err; | ||
| 51 | |||
| 52 | /* check that the file system has xattrs */ | ||
| 53 | if (msblk->xattr_id_table == NULL) | ||
| 54 | return -EOPNOTSUPP; | ||
| 55 | |||
| 56 | /* loop reading each xattr name */ | ||
| 57 | while (count--) { | ||
| 58 | struct squashfs_xattr_entry entry; | ||
| 59 | struct squashfs_xattr_val val; | ||
| 60 | const struct xattr_handler *handler; | ||
| 61 | int name_size, prefix_size = 0; | ||
| 62 | |||
| 63 | err = squashfs_read_metadata(sb, &entry, &start, &offset, | ||
| 64 | sizeof(entry)); | ||
| 65 | if (err < 0) | ||
| 66 | goto failed; | ||
| 67 | |||
| 68 | name_size = le16_to_cpu(entry.size); | ||
| 69 | handler = squashfs_xattr_handler(le16_to_cpu(entry.type)); | ||
| 70 | if (handler) | ||
| 71 | prefix_size = handler->list(d, buffer, rest, NULL, | ||
| 72 | name_size, handler->flags); | ||
| 73 | if (prefix_size) { | ||
| 74 | if (buffer) { | ||
| 75 | if (prefix_size + name_size + 1 > rest) { | ||
| 76 | err = -ERANGE; | ||
| 77 | goto failed; | ||
| 78 | } | ||
| 79 | buffer += prefix_size; | ||
| 80 | } | ||
| 81 | err = squashfs_read_metadata(sb, buffer, &start, | ||
| 82 | &offset, name_size); | ||
| 83 | if (err < 0) | ||
| 84 | goto failed; | ||
| 85 | if (buffer) { | ||
| 86 | buffer[name_size] = '\0'; | ||
| 87 | buffer += name_size + 1; | ||
| 88 | } | ||
| 89 | rest -= prefix_size + name_size + 1; | ||
| 90 | } else { | ||
| 91 | /* no handler or insuffficient privileges, so skip */ | ||
| 92 | err = squashfs_read_metadata(sb, NULL, &start, | ||
| 93 | &offset, name_size); | ||
| 94 | if (err < 0) | ||
| 95 | goto failed; | ||
| 96 | } | ||
| 97 | |||
| 98 | |||
| 99 | /* skip remaining xattr entry */ | ||
| 100 | err = squashfs_read_metadata(sb, &val, &start, &offset, | ||
| 101 | sizeof(val)); | ||
| 102 | if (err < 0) | ||
| 103 | goto failed; | ||
| 104 | |||
| 105 | err = squashfs_read_metadata(sb, NULL, &start, &offset, | ||
| 106 | le32_to_cpu(val.vsize)); | ||
| 107 | if (err < 0) | ||
| 108 | goto failed; | ||
| 109 | } | ||
| 110 | err = buffer_size - rest; | ||
| 111 | |||
| 112 | failed: | ||
| 113 | return err; | ||
| 114 | } | ||
| 115 | |||
| 116 | |||
| 117 | static int squashfs_xattr_get(struct inode *inode, int name_index, | ||
| 118 | const char *name, void *buffer, size_t buffer_size) | ||
| 119 | { | ||
| 120 | struct super_block *sb = inode->i_sb; | ||
| 121 | struct squashfs_sb_info *msblk = sb->s_fs_info; | ||
| 122 | u64 start = SQUASHFS_XATTR_BLK(squashfs_i(inode)->xattr) | ||
| 123 | + msblk->xattr_table; | ||
| 124 | int offset = SQUASHFS_XATTR_OFFSET(squashfs_i(inode)->xattr); | ||
| 125 | int count = squashfs_i(inode)->xattr_count; | ||
| 126 | int name_len = strlen(name); | ||
| 127 | int err, vsize; | ||
| 128 | char *target = kmalloc(name_len, GFP_KERNEL); | ||
| 129 | |||
| 130 | if (target == NULL) | ||
| 131 | return -ENOMEM; | ||
| 132 | |||
| 133 | /* loop reading each xattr name */ | ||
| 134 | for (; count; count--) { | ||
| 135 | struct squashfs_xattr_entry entry; | ||
| 136 | struct squashfs_xattr_val val; | ||
| 137 | int type, prefix, name_size; | ||
| 138 | |||
| 139 | err = squashfs_read_metadata(sb, &entry, &start, &offset, | ||
| 140 | sizeof(entry)); | ||
| 141 | if (err < 0) | ||
| 142 | goto failed; | ||
| 143 | |||
| 144 | name_size = le16_to_cpu(entry.size); | ||
| 145 | type = le16_to_cpu(entry.type); | ||
| 146 | prefix = type & SQUASHFS_XATTR_PREFIX_MASK; | ||
| 147 | |||
| 148 | if (prefix == name_index && name_size == name_len) | ||
| 149 | err = squashfs_read_metadata(sb, target, &start, | ||
| 150 | &offset, name_size); | ||
| 151 | else | ||
| 152 | err = squashfs_read_metadata(sb, NULL, &start, | ||
| 153 | &offset, name_size); | ||
| 154 | if (err < 0) | ||
| 155 | goto failed; | ||
| 156 | |||
| 157 | if (prefix == name_index && name_size == name_len && | ||
| 158 | strncmp(target, name, name_size) == 0) { | ||
| 159 | /* found xattr */ | ||
| 160 | if (type & SQUASHFS_XATTR_VALUE_OOL) { | ||
| 161 | __le64 xattr; | ||
| 162 | /* val is a reference to the real location */ | ||
| 163 | err = squashfs_read_metadata(sb, &val, &start, | ||
| 164 | &offset, sizeof(val)); | ||
| 165 | if (err < 0) | ||
| 166 | goto failed; | ||
| 167 | err = squashfs_read_metadata(sb, &xattr, &start, | ||
| 168 | &offset, sizeof(xattr)); | ||
| 169 | if (err < 0) | ||
| 170 | goto failed; | ||
| 171 | xattr = le64_to_cpu(xattr); | ||
| 172 | start = SQUASHFS_XATTR_BLK(xattr) + | ||
| 173 | msblk->xattr_table; | ||
| 174 | offset = SQUASHFS_XATTR_OFFSET(xattr); | ||
| 175 | } | ||
| 176 | /* read xattr value */ | ||
| 177 | err = squashfs_read_metadata(sb, &val, &start, &offset, | ||
| 178 | sizeof(val)); | ||
| 179 | if (err < 0) | ||
| 180 | goto failed; | ||
| 181 | |||
| 182 | vsize = le32_to_cpu(val.vsize); | ||
| 183 | if (buffer) { | ||
| 184 | if (vsize > buffer_size) { | ||
| 185 | err = -ERANGE; | ||
| 186 | goto failed; | ||
| 187 | } | ||
| 188 | err = squashfs_read_metadata(sb, buffer, &start, | ||
| 189 | &offset, vsize); | ||
| 190 | if (err < 0) | ||
| 191 | goto failed; | ||
| 192 | } | ||
| 193 | break; | ||
| 194 | } | ||
| 195 | |||
| 196 | /* no match, skip remaining xattr entry */ | ||
| 197 | err = squashfs_read_metadata(sb, &val, &start, &offset, | ||
| 198 | sizeof(val)); | ||
| 199 | if (err < 0) | ||
| 200 | goto failed; | ||
| 201 | err = squashfs_read_metadata(sb, NULL, &start, &offset, | ||
| 202 | le32_to_cpu(val.vsize)); | ||
| 203 | if (err < 0) | ||
| 204 | goto failed; | ||
| 205 | } | ||
| 206 | err = count ? vsize : -ENODATA; | ||
| 207 | |||
| 208 | failed: | ||
| 209 | kfree(target); | ||
| 210 | return err; | ||
| 211 | } | ||
| 212 | |||
| 213 | |||
| 214 | /* | ||
| 215 | * User namespace support | ||
| 216 | */ | ||
| 217 | static size_t squashfs_user_list(struct dentry *d, char *list, size_t list_size, | ||
| 218 | const char *name, size_t name_len, int type) | ||
| 219 | { | ||
| 220 | if (list && XATTR_USER_PREFIX_LEN <= list_size) | ||
| 221 | memcpy(list, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN); | ||
| 222 | return XATTR_USER_PREFIX_LEN; | ||
| 223 | } | ||
| 224 | |||
| 225 | static int squashfs_user_get(struct dentry *d, const char *name, void *buffer, | ||
| 226 | size_t size, int type) | ||
| 227 | { | ||
| 228 | if (name[0] == '\0') | ||
| 229 | return -EINVAL; | ||
| 230 | |||
| 231 | return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_USER, name, | ||
| 232 | buffer, size); | ||
| 233 | } | ||
| 234 | |||
| 235 | static const struct xattr_handler squashfs_xattr_user_handler = { | ||
| 236 | .prefix = XATTR_USER_PREFIX, | ||
| 237 | .list = squashfs_user_list, | ||
| 238 | .get = squashfs_user_get | ||
| 239 | }; | ||
| 240 | |||
| 241 | /* | ||
| 242 | * Trusted namespace support | ||
| 243 | */ | ||
| 244 | static size_t squashfs_trusted_list(struct dentry *d, char *list, | ||
| 245 | size_t list_size, const char *name, size_t name_len, int type) | ||
| 246 | { | ||
| 247 | if (!capable(CAP_SYS_ADMIN)) | ||
| 248 | return 0; | ||
| 249 | |||
| 250 | if (list && XATTR_TRUSTED_PREFIX_LEN <= list_size) | ||
| 251 | memcpy(list, XATTR_TRUSTED_PREFIX, XATTR_TRUSTED_PREFIX_LEN); | ||
| 252 | return XATTR_TRUSTED_PREFIX_LEN; | ||
| 253 | } | ||
| 254 | |||
| 255 | static int squashfs_trusted_get(struct dentry *d, const char *name, | ||
| 256 | void *buffer, size_t size, int type) | ||
| 257 | { | ||
| 258 | if (name[0] == '\0') | ||
| 259 | return -EINVAL; | ||
| 260 | |||
| 261 | return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_TRUSTED, name, | ||
| 262 | buffer, size); | ||
| 263 | } | ||
| 264 | |||
| 265 | static const struct xattr_handler squashfs_xattr_trusted_handler = { | ||
| 266 | .prefix = XATTR_TRUSTED_PREFIX, | ||
| 267 | .list = squashfs_trusted_list, | ||
| 268 | .get = squashfs_trusted_get | ||
| 269 | }; | ||
| 270 | |||
| 271 | /* | ||
| 272 | * Security namespace support | ||
| 273 | */ | ||
| 274 | static size_t squashfs_security_list(struct dentry *d, char *list, | ||
| 275 | size_t list_size, const char *name, size_t name_len, int type) | ||
| 276 | { | ||
| 277 | if (list && XATTR_SECURITY_PREFIX_LEN <= list_size) | ||
| 278 | memcpy(list, XATTR_SECURITY_PREFIX, XATTR_SECURITY_PREFIX_LEN); | ||
| 279 | return XATTR_SECURITY_PREFIX_LEN; | ||
| 280 | } | ||
| 281 | |||
| 282 | static int squashfs_security_get(struct dentry *d, const char *name, | ||
| 283 | void *buffer, size_t size, int type) | ||
| 284 | { | ||
| 285 | if (name[0] == '\0') | ||
| 286 | return -EINVAL; | ||
| 287 | |||
| 288 | return squashfs_xattr_get(d->d_inode, SQUASHFS_XATTR_SECURITY, name, | ||
| 289 | buffer, size); | ||
| 290 | } | ||
| 291 | |||
| 292 | static const struct xattr_handler squashfs_xattr_security_handler = { | ||
| 293 | .prefix = XATTR_SECURITY_PREFIX, | ||
| 294 | .list = squashfs_security_list, | ||
| 295 | .get = squashfs_security_get | ||
| 296 | }; | ||
| 297 | |||
| 298 | static inline const struct xattr_handler *squashfs_xattr_handler(int type) | ||
| 299 | { | ||
| 300 | if (type & ~(SQUASHFS_XATTR_PREFIX_MASK | SQUASHFS_XATTR_VALUE_OOL)) | ||
| 301 | /* ignore unrecognised type */ | ||
| 302 | return NULL; | ||
| 303 | |||
| 304 | switch (type & SQUASHFS_XATTR_PREFIX_MASK) { | ||
| 305 | case SQUASHFS_XATTR_USER: | ||
| 306 | return &squashfs_xattr_user_handler; | ||
| 307 | case SQUASHFS_XATTR_TRUSTED: | ||
| 308 | return &squashfs_xattr_trusted_handler; | ||
| 309 | case SQUASHFS_XATTR_SECURITY: | ||
| 310 | return &squashfs_xattr_security_handler; | ||
| 311 | default: | ||
| 312 | /* ignore unrecognised type */ | ||
| 313 | return NULL; | ||
| 314 | } | ||
| 315 | } | ||
| 316 | |||
| 317 | const struct xattr_handler *squashfs_xattr_handlers[] = { | ||
| 318 | &squashfs_xattr_user_handler, | ||
| 319 | &squashfs_xattr_trusted_handler, | ||
| 320 | &squashfs_xattr_security_handler, | ||
| 321 | NULL | ||
| 322 | }; | ||
| 323 | |||
diff --git a/fs/squashfs/xattr.h b/fs/squashfs/xattr.h new file mode 100644 index 000000000000..9da071ae181c --- /dev/null +++ b/fs/squashfs/xattr.h | |||
| @@ -0,0 +1,46 @@ | |||
| 1 | /* | ||
| 2 | * Squashfs - a compressed read only filesystem for Linux | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 | ||
| 5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * as published by the Free Software Foundation; either version 2, | ||
| 10 | * or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
| 20 | * | ||
| 21 | * xattr.h | ||
| 22 | */ | ||
| 23 | |||
| 24 | #ifdef CONFIG_SQUASHFS_XATTRS | ||
| 25 | extern __le64 *squashfs_read_xattr_id_table(struct super_block *, u64, | ||
| 26 | u64 *, int *); | ||
| 27 | extern int squashfs_xattr_lookup(struct super_block *, unsigned int, int *, | ||
| 28 | int *, unsigned long long *); | ||
| 29 | #else | ||
| 30 | static inline __le64 *squashfs_read_xattr_id_table(struct super_block *sb, | ||
| 31 | u64 start, u64 *xattr_table_start, int *xattr_ids) | ||
| 32 | { | ||
| 33 | ERROR("Xattrs in filesystem, these will be ignored\n"); | ||
| 34 | return ERR_PTR(-ENOTSUPP); | ||
| 35 | } | ||
| 36 | |||
| 37 | static inline int squashfs_xattr_lookup(struct super_block *sb, | ||
| 38 | unsigned int index, int *count, int *size, | ||
| 39 | unsigned long long *xattr) | ||
| 40 | { | ||
| 41 | return 0; | ||
| 42 | } | ||
| 43 | #define squashfs_listxattr NULL | ||
| 44 | #define generic_getxattr NULL | ||
| 45 | #define squashfs_xattr_handlers NULL | ||
| 46 | #endif | ||
diff --git a/fs/squashfs/xattr_id.c b/fs/squashfs/xattr_id.c new file mode 100644 index 000000000000..cfb41106098f --- /dev/null +++ b/fs/squashfs/xattr_id.c | |||
| @@ -0,0 +1,100 @@ | |||
| 1 | /* | ||
| 2 | * Squashfs - a compressed read only filesystem for Linux | ||
| 3 | * | ||
| 4 | * Copyright (c) 2010 | ||
| 5 | * Phillip Lougher <phillip@lougher.demon.co.uk> | ||
| 6 | * | ||
| 7 | * This program is free software; you can redistribute it and/or | ||
| 8 | * modify it under the terms of the GNU General Public License | ||
| 9 | * as published by the Free Software Foundation; either version 2, | ||
| 10 | * or (at your option) any later version. | ||
| 11 | * | ||
| 12 | * This program is distributed in the hope that it will be useful, | ||
| 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 15 | * GNU General Public License for more details. | ||
| 16 | * | ||
| 17 | * You should have received a copy of the GNU General Public License | ||
| 18 | * along with this program; if not, write to the Free Software | ||
| 19 | * Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||
| 20 | * | ||
| 21 | * xattr_id.c | ||
| 22 | */ | ||
| 23 | |||
| 24 | /* | ||
| 25 | * This file implements code to map the 32-bit xattr id stored in the inode | ||
| 26 | * into the on disk location of the xattr data. | ||
| 27 | */ | ||
| 28 | |||
| 29 | #include <linux/fs.h> | ||
| 30 | #include <linux/vfs.h> | ||
| 31 | #include <linux/slab.h> | ||
| 32 | |||
| 33 | #include "squashfs_fs.h" | ||
| 34 | #include "squashfs_fs_sb.h" | ||
| 35 | #include "squashfs_fs_i.h" | ||
| 36 | #include "squashfs.h" | ||
| 37 | |||
| 38 | /* | ||
| 39 | * Map xattr id using the xattr id look up table | ||
| 40 | */ | ||
| 41 | int squashfs_xattr_lookup(struct super_block *sb, unsigned int index, | ||
| 42 | int *count, unsigned int *size, unsigned long long *xattr) | ||
| 43 | { | ||
| 44 | struct squashfs_sb_info *msblk = sb->s_fs_info; | ||
| 45 | int block = SQUASHFS_XATTR_BLOCK(index); | ||
| 46 | int offset = SQUASHFS_XATTR_BLOCK_OFFSET(index); | ||
| 47 | u64 start_block = le64_to_cpu(msblk->xattr_id_table[block]); | ||
| 48 | struct squashfs_xattr_id id; | ||
| 49 | int err; | ||
| 50 | |||
| 51 | err = squashfs_read_metadata(sb, &id, &start_block, &offset, | ||
| 52 | sizeof(id)); | ||
| 53 | if (err < 0) | ||
| 54 | return err; | ||
| 55 | |||
| 56 | *xattr = le64_to_cpu(id.xattr); | ||
| 57 | *size = le32_to_cpu(id.size); | ||
| 58 | *count = le32_to_cpu(id.count); | ||
| 59 | return 0; | ||
| 60 | } | ||
| 61 | |||
| 62 | |||
| 63 | /* | ||
| 64 | * Read uncompressed xattr id lookup table indexes from disk into memory | ||
| 65 | */ | ||
| 66 | __le64 *squashfs_read_xattr_id_table(struct super_block *sb, u64 start, | ||
| 67 | u64 *xattr_table_start, int *xattr_ids) | ||
| 68 | { | ||
| 69 | unsigned int len; | ||
| 70 | __le64 *xid_table; | ||
| 71 | struct squashfs_xattr_id_table id_table; | ||
| 72 | int err; | ||
| 73 | |||
| 74 | err = squashfs_read_table(sb, &id_table, start, sizeof(id_table)); | ||
| 75 | if (err < 0) { | ||
| 76 | ERROR("unable to read xattr id table\n"); | ||
| 77 | return ERR_PTR(err); | ||
| 78 | } | ||
| 79 | *xattr_table_start = le64_to_cpu(id_table.xattr_table_start); | ||
| 80 | *xattr_ids = le32_to_cpu(id_table.xattr_ids); | ||
| 81 | len = SQUASHFS_XATTR_BLOCK_BYTES(*xattr_ids); | ||
| 82 | |||
| 83 | TRACE("In read_xattr_index_table, length %d\n", len); | ||
| 84 | |||
| 85 | /* Allocate xattr id lookup table indexes */ | ||
| 86 | xid_table = kmalloc(len, GFP_KERNEL); | ||
| 87 | if (xid_table == NULL) { | ||
| 88 | ERROR("Failed to allocate xattr id index table\n"); | ||
| 89 | return ERR_PTR(-ENOMEM); | ||
| 90 | } | ||
| 91 | |||
| 92 | err = squashfs_read_table(sb, xid_table, start + sizeof(id_table), len); | ||
| 93 | if (err < 0) { | ||
| 94 | ERROR("unable to read xattr id index table\n"); | ||
| 95 | kfree(xid_table); | ||
| 96 | return ERR_PTR(err); | ||
| 97 | } | ||
| 98 | |||
| 99 | return xid_table; | ||
| 100 | } | ||
