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

+723 -24
+27 -5
Documentation/filesystems/squashfs.txt
··· 38 38 Real inode numbers: yes no 39 39 32-bit uids/gids: yes no 40 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 44 Squashfs compresses data, inodes and directories. In addition, inode and 44 45 directory data are highly compacted, and packed on byte boundaries. Each ··· 59 58 3. SQUASHFS FILESYSTEM DESIGN 60 59 ----------------------------- 61 60 62 - A squashfs filesystem consists of seven parts, packed together on a byte 61 + A squashfs filesystem consists of a maximum of eight parts, packed together on a byte 63 62 alignment: 64 63 65 64 --------------- ··· 81 80 |---------------| 82 81 | uid/gid | 83 82 | lookup table | 83 + |---------------| 84 + | xattr | 85 + | table | 84 86 --------------- 85 87 86 88 Compressed data blocks are written to the filesystem as files are read from ··· 196 192 used to locate these. This second index table for speed of access (and because 197 193 it is small) is read at mount time and cached in memory. 198 194 195 + 3.7 Xattr table 196 + --------------- 197 + 198 + The xattr table contains extended attributes for each inode. The xattrs 199 + for each inode are stored in a list, each list entry containing a type, 200 + name and value field. The type field encodes the xattr prefix 201 + ("user.", "trusted." etc) and it also encodes how the name/value fields 202 + should be interpreted. Currently the type indicates whether the value 203 + is stored inline (in which case the value field contains the xattr value), 204 + or if it is stored out of line (in which case the value field stores a 205 + reference to where the actual value is stored). This allows large values 206 + to be stored out of line improving scanning and lookup performance and it 207 + also allows values to be de-duplicated, the value being stored once, and 208 + all other occurences holding an out of line reference to that value. 209 + 210 + The xattr lists are packed into compressed 8K metadata blocks. 211 + To reduce overhead in inodes, rather than storing the on-disk 212 + location of the xattr list inside each inode, a 32-bit xattr id 213 + is stored. This xattr id is mapped into the location of the xattr 214 + list using a second xattr id lookup table. 199 215 200 216 4. TODOS AND OUTSTANDING ISSUES 201 217 ------------------------------- ··· 223 199 4.1 Todo list 224 200 ------------- 225 201 226 - Implement Xattr and ACL support. The Squashfs 4.0 filesystem layout has hooks 227 - for these but the code has not been written. Once the code has been written 228 - the existing layout should not require modification. 202 + Implement ACL support. 229 203 230 204 4.2 Squashfs internal cache 231 205 ---------------------------
+11
fs/squashfs/Kconfig
··· 26 26 27 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 40 config SQUASHFS_EMBEDDED 30 41 31 42 bool "Additional option for memory-constrained systems"
+2
fs/squashfs/Makefile
··· 5 5 obj-$(CONFIG_SQUASHFS) += squashfs.o 6 6 squashfs-y += block.o cache.o dir.o export.o file.o fragment.o id.o inode.o 7 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 +
+85 -7
fs/squashfs/inode.c
··· 40 40 41 41 #include <linux/fs.h> 42 42 #include <linux/vfs.h> 43 + #include <linux/xattr.h> 43 44 44 45 #include "squashfs_fs.h" 45 46 #include "squashfs_fs_sb.h" 46 47 #include "squashfs_fs_i.h" 47 48 #include "squashfs.h" 49 + #include "xattr.h" 48 50 49 51 /* 50 52 * Initialise VFS inode with the base inode information common to all ··· 113 111 int err, type, offset = SQUASHFS_INODE_OFFSET(ino); 114 112 union squashfs_inode squashfs_ino; 115 113 struct squashfs_base_inode *sqshb_ino = &squashfs_ino.base; 114 + int xattr_id = SQUASHFS_INVALID_XATTR; 116 115 117 116 TRACE("Entered squashfs_read_inode\n"); 118 117 ··· 202 199 frag_offset = 0; 203 200 } 204 201 202 + xattr_id = le32_to_cpu(sqsh_ino->xattr); 205 203 inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); 206 204 inode->i_size = le64_to_cpu(sqsh_ino->file_size); 205 + inode->i_op = &squashfs_inode_ops; 207 206 inode->i_fop = &generic_ro_fops; 208 207 inode->i_mode |= S_IFREG; 209 208 inode->i_blocks = ((inode->i_size - ··· 256 251 if (err < 0) 257 252 goto failed_read; 258 253 254 + xattr_id = le32_to_cpu(sqsh_ino->xattr); 259 255 inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); 260 256 inode->i_size = le32_to_cpu(sqsh_ino->file_size); 261 257 inode->i_op = &squashfs_dir_inode_ops; ··· 286 280 287 281 inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); 288 282 inode->i_size = le32_to_cpu(sqsh_ino->symlink_size); 289 - inode->i_op = &page_symlink_inode_operations; 283 + inode->i_op = &squashfs_symlink_inode_ops; 290 284 inode->i_data.a_ops = &squashfs_symlink_aops; 291 285 inode->i_mode |= S_IFLNK; 292 286 squashfs_i(inode)->start = block; 293 287 squashfs_i(inode)->offset = offset; 288 + 289 + if (type == SQUASHFS_LSYMLINK_TYPE) { 290 + __le32 xattr; 291 + 292 + err = squashfs_read_metadata(sb, NULL, &block, 293 + &offset, inode->i_size); 294 + if (err < 0) 295 + goto failed_read; 296 + err = squashfs_read_metadata(sb, &xattr, &block, 297 + &offset, sizeof(xattr)); 298 + if (err < 0) 299 + goto failed_read; 300 + xattr_id = le32_to_cpu(xattr); 301 + } 294 302 295 303 TRACE("Symbolic link inode %x:%x, start_block %llx, offset " 296 304 "%x\n", SQUASHFS_INODE_BLK(ino), offset, ··· 312 292 break; 313 293 } 314 294 case SQUASHFS_BLKDEV_TYPE: 315 - case SQUASHFS_CHRDEV_TYPE: 316 - case SQUASHFS_LBLKDEV_TYPE: 317 - case SQUASHFS_LCHRDEV_TYPE: { 295 + case SQUASHFS_CHRDEV_TYPE: { 318 296 struct squashfs_dev_inode *sqsh_ino = &squashfs_ino.dev; 319 297 unsigned int rdev; 320 298 ··· 333 315 SQUASHFS_INODE_BLK(ino), offset, rdev); 334 316 break; 335 317 } 318 + case SQUASHFS_LBLKDEV_TYPE: 319 + case SQUASHFS_LCHRDEV_TYPE: { 320 + struct squashfs_ldev_inode *sqsh_ino = &squashfs_ino.ldev; 321 + unsigned int rdev; 322 + 323 + err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, 324 + sizeof(*sqsh_ino)); 325 + if (err < 0) 326 + goto failed_read; 327 + 328 + if (type == SQUASHFS_LCHRDEV_TYPE) 329 + inode->i_mode |= S_IFCHR; 330 + else 331 + inode->i_mode |= S_IFBLK; 332 + xattr_id = le32_to_cpu(sqsh_ino->xattr); 333 + inode->i_op = &squashfs_inode_ops; 334 + inode->i_nlink = le32_to_cpu(sqsh_ino->nlink); 335 + rdev = le32_to_cpu(sqsh_ino->rdev); 336 + init_special_inode(inode, inode->i_mode, new_decode_dev(rdev)); 337 + 338 + TRACE("Device inode %x:%x, rdev %x\n", 339 + SQUASHFS_INODE_BLK(ino), offset, rdev); 340 + break; 341 + } 336 342 case SQUASHFS_FIFO_TYPE: 337 - case SQUASHFS_SOCKET_TYPE: 338 - case SQUASHFS_LFIFO_TYPE: 339 - case SQUASHFS_LSOCKET_TYPE: { 343 + case SQUASHFS_SOCKET_TYPE: { 340 344 struct squashfs_ipc_inode *sqsh_ino = &squashfs_ino.ipc; 341 345 342 346 err = squashfs_read_metadata(sb, sqsh_ino, &block, &offset, ··· 374 334 init_special_inode(inode, inode->i_mode, 0); 375 335 break; 376 336 } 337 + case SQUASHFS_LFIFO_TYPE: 338 + case SQUASHFS_LSOCKET_TYPE: { 339 + struct squashfs_lipc_inode *sqsh_ino = &squashfs_ino.lipc; 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_LFIFO_TYPE) 347 + inode->i_mode |= S_IFIFO; 348 + else 349 + inode->i_mode |= S_IFSOCK; 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 + init_special_inode(inode, inode->i_mode, 0); 354 + break; 355 + } 377 356 default: 378 357 ERROR("Unknown inode type %d in squashfs_iget!\n", type); 379 358 return -EINVAL; 380 359 } 360 + 361 + if (xattr_id != SQUASHFS_INVALID_XATTR && msblk->xattr_id_table) { 362 + err = squashfs_xattr_lookup(sb, xattr_id, 363 + &squashfs_i(inode)->xattr_count, 364 + &squashfs_i(inode)->xattr_size, 365 + &squashfs_i(inode)->xattr); 366 + if (err < 0) 367 + goto failed_read; 368 + inode->i_blocks += ((squashfs_i(inode)->xattr_size - 1) >> 9) 369 + + 1; 370 + } else 371 + squashfs_i(inode)->xattr_count = 0; 381 372 382 373 return 0; 383 374 ··· 416 345 ERROR("Unable to read inode 0x%llx\n", ino); 417 346 return err; 418 347 } 348 + 349 + 350 + const struct inode_operations squashfs_inode_ops = { 351 + .getxattr = generic_getxattr, 352 + .listxattr = squashfs_listxattr 353 + }; 354 +
+5 -1
fs/squashfs/namei.c
··· 57 57 #include <linux/slab.h> 58 58 #include <linux/string.h> 59 59 #include <linux/dcache.h> 60 + #include <linux/xattr.h> 60 61 61 62 #include "squashfs_fs.h" 62 63 #include "squashfs_fs_sb.h" 63 64 #include "squashfs_fs_i.h" 64 65 #include "squashfs.h" 66 + #include "xattr.h" 65 67 66 68 /* 67 69 * Lookup name in the directory index, returning the location of the metadata ··· 239 237 240 238 241 239 const struct inode_operations squashfs_dir_inode_ops = { 242 - .lookup = squashfs_lookup 240 + .lookup = squashfs_lookup, 241 + .getxattr = generic_getxattr, 242 + .listxattr = squashfs_listxattr 243 243 };
+11 -1
fs/squashfs/squashfs.h
··· 73 73 unsigned int); 74 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 83 /* dir.c */ ··· 89 86 /* file.c */ 90 87 extern const struct address_space_operations squashfs_aops; 91 88 89 + /* inode.c */ 90 + extern const struct inode_operations squashfs_inode_ops; 91 + 92 92 /* namei.c */ 93 93 extern const struct inode_operations squashfs_dir_inode_ops; 94 94 95 95 /* symlink.c */ 96 96 extern const struct address_space_operations squashfs_symlink_aops; 97 + extern const struct inode_operations squashfs_symlink_inode_ops; 98 + 99 + /* xattr.c */ 100 + extern const struct xattr_handler *squashfs_xattr_handlers[]; 97 101 98 102 /* zlib_wrapper.c */ 99 103 extern const struct squashfs_decompressor squashfs_zlib_comp_ops;
+75 -1
fs/squashfs/squashfs_fs.h
··· 46 46 #define SQUASHFS_NAME_LEN 256 47 47 48 48 #define SQUASHFS_INVALID_FRAG (0xffffffffU) 49 + #define SQUASHFS_INVALID_XATTR (0xffffffffU) 49 50 #define SQUASHFS_INVALID_BLK (-1LL) 50 51 51 52 /* Filesystem flags */ ··· 96 95 #define SQUASHFS_LCHRDEV_TYPE 12 97 96 #define SQUASHFS_LFIFO_TYPE 13 98 97 #define SQUASHFS_LSOCKET_TYPE 14 98 + 99 + /* Xattr types */ 100 + #define SQUASHFS_XATTR_USER 0 101 + #define SQUASHFS_XATTR_TRUSTED 1 102 + #define SQUASHFS_XATTR_SECURITY 2 103 + #define SQUASHFS_XATTR_VALUE_OOL 256 104 + #define SQUASHFS_XATTR_PREFIX_MASK 0xff 99 105 100 106 /* Flag whether block is compressed or uncompressed, bit is set if block is 101 107 * uncompressed */ ··· 182 174 183 175 #define SQUASHFS_ID_BLOCK_BYTES(A) (SQUASHFS_ID_BLOCKS(A) *\ 184 176 sizeof(u64)) 177 + /* xattr id lookup table defines */ 178 + #define SQUASHFS_XATTR_BYTES(A) ((A) * sizeof(struct squashfs_xattr_id)) 179 + 180 + #define SQUASHFS_XATTR_BLOCK(A) (SQUASHFS_XATTR_BYTES(A) / \ 181 + SQUASHFS_METADATA_SIZE) 182 + 183 + #define SQUASHFS_XATTR_BLOCK_OFFSET(A) (SQUASHFS_XATTR_BYTES(A) % \ 184 + SQUASHFS_METADATA_SIZE) 185 + 186 + #define SQUASHFS_XATTR_BLOCKS(A) ((SQUASHFS_XATTR_BYTES(A) + \ 187 + SQUASHFS_METADATA_SIZE - 1) / \ 188 + SQUASHFS_METADATA_SIZE) 189 + 190 + #define SQUASHFS_XATTR_BLOCK_BYTES(A) (SQUASHFS_XATTR_BLOCKS(A) *\ 191 + sizeof(u64)) 192 + #define SQUASHFS_XATTR_BLK(A) ((unsigned int) ((A) >> 16)) 193 + 194 + #define SQUASHFS_XATTR_OFFSET(A) ((unsigned int) ((A) & 0xffff)) 185 195 186 196 /* cached data constants for filesystem */ 187 197 #define SQUASHFS_CACHED_BLKS 8 ··· 254 228 __le64 root_inode; 255 229 __le64 bytes_used; 256 230 __le64 id_table_start; 257 - __le64 xattr_table_start; 231 + __le64 xattr_id_table_start; 258 232 __le64 inode_table_start; 259 233 __le64 directory_table_start; 260 234 __le64 fragment_table_start; ··· 287 261 __le32 nlink; 288 262 }; 289 263 264 + struct squashfs_lipc_inode { 265 + __le16 inode_type; 266 + __le16 mode; 267 + __le16 uid; 268 + __le16 guid; 269 + __le32 mtime; 270 + __le32 inode_number; 271 + __le32 nlink; 272 + __le32 xattr; 273 + }; 274 + 290 275 struct squashfs_dev_inode { 291 276 __le16 inode_type; 292 277 __le16 mode; ··· 307 270 __le32 inode_number; 308 271 __le32 nlink; 309 272 __le32 rdev; 273 + }; 274 + 275 + struct squashfs_ldev_inode { 276 + __le16 inode_type; 277 + __le16 mode; 278 + __le16 uid; 279 + __le16 guid; 280 + __le32 mtime; 281 + __le32 inode_number; 282 + __le32 nlink; 283 + __le32 rdev; 284 + __le32 xattr; 310 285 }; 311 286 312 287 struct squashfs_symlink_inode { ··· 398 349 union squashfs_inode { 399 350 struct squashfs_base_inode base; 400 351 struct squashfs_dev_inode dev; 352 + struct squashfs_ldev_inode ldev; 401 353 struct squashfs_symlink_inode symlink; 402 354 struct squashfs_reg_inode reg; 403 355 struct squashfs_lreg_inode lreg; 404 356 struct squashfs_dir_inode dir; 405 357 struct squashfs_ldir_inode ldir; 406 358 struct squashfs_ipc_inode ipc; 359 + struct squashfs_lipc_inode lipc; 407 360 }; 408 361 409 362 struct squashfs_dir_entry { ··· 426 375 __le64 start_block; 427 376 __le32 size; 428 377 unsigned int unused; 378 + }; 379 + 380 + struct squashfs_xattr_entry { 381 + __le16 type; 382 + __le16 size; 383 + char data[0]; 384 + }; 385 + 386 + struct squashfs_xattr_val { 387 + __le32 vsize; 388 + char value[0]; 389 + }; 390 + 391 + struct squashfs_xattr_id { 392 + __le64 xattr; 393 + __le32 count; 394 + __le32 size; 395 + }; 396 + 397 + struct squashfs_xattr_id_table { 398 + __le64 xattr_table_start; 399 + __le32 xattr_ids; 400 + __le32 unused; 429 401 }; 430 402 431 403 #endif
+3
fs/squashfs/squashfs_fs_i.h
··· 26 26 struct squashfs_inode_info { 27 27 u64 start; 28 28 int offset; 29 + u64 xattr; 30 + unsigned int xattr_size; 31 + int xattr_count; 29 32 union { 30 33 struct { 31 34 u64 fragment_block;
+3
fs/squashfs/squashfs_fs_sb.h
··· 61 61 int next_meta_index; 62 62 __le64 *id_table; 63 63 __le64 *fragment_index; 64 + __le64 *xattr_id_table; 64 65 struct mutex read_data_mutex; 65 66 struct mutex meta_index_mutex; 66 67 struct meta_index *meta_index; ··· 69 68 __le64 *inode_lookup_table; 70 69 u64 inode_table; 71 70 u64 directory_table; 71 + u64 xattr_table; 72 72 unsigned int block_size; 73 73 unsigned short block_log; 74 74 long long bytes_used; 75 75 unsigned int inodes; 76 + int xattr_ids; 76 77 }; 77 78 #endif
+21 -9
fs/squashfs/super.c
··· 36 36 #include <linux/init.h> 37 37 #include <linux/module.h> 38 38 #include <linux/magic.h> 39 + #include <linux/xattr.h> 39 40 40 41 #include "squashfs_fs.h" 41 42 #include "squashfs_fs_sb.h" 42 43 #include "squashfs_fs_i.h" 43 44 #include "squashfs.h" 44 45 #include "decompressor.h" 46 + #include "xattr.h" 45 47 46 48 static struct file_system_type squashfs_fs_type; 47 49 static const struct super_operations squashfs_super_ops; ··· 84 82 long long root_inode; 85 83 unsigned short flags; 86 84 unsigned int fragments; 87 - u64 lookup_table_start; 85 + u64 lookup_table_start, xattr_id_table_start; 88 86 int err; 89 87 90 88 TRACE("Entered squashfs_fill_superblock\n"); ··· 140 138 le16_to_cpu(sblk->compression)); 141 139 if (msblk->decompressor == NULL) 142 140 goto failed_mount; 143 - 144 - /* 145 - * Check if there's xattrs in the filesystem. These are not 146 - * supported in this version, so warn that they will be ignored. 147 - */ 148 - if (le64_to_cpu(sblk->xattr_table_start) != SQUASHFS_INVALID_BLK) 149 - ERROR("Xattrs in filesystem, these will be ignored\n"); 150 141 151 142 /* Check the filesystem does not extend beyond the end of the 152 143 block device */ ··· 248 253 allocate_lookup_table: 249 254 lookup_table_start = le64_to_cpu(sblk->lookup_table_start); 250 255 if (lookup_table_start == SQUASHFS_INVALID_BLK) 251 - goto allocate_root; 256 + goto allocate_xattr_table; 252 257 253 258 /* Allocate and read inode lookup table */ 254 259 msblk->inode_lookup_table = squashfs_read_inode_lookup_table(sb, ··· 261 266 262 267 sb->s_export_op = &squashfs_export_ops; 263 268 269 + allocate_xattr_table: 270 + sb->s_xattr = squashfs_xattr_handlers; 271 + xattr_id_table_start = le64_to_cpu(sblk->xattr_id_table_start); 272 + if (xattr_id_table_start == SQUASHFS_INVALID_BLK) 273 + goto allocate_root; 274 + 275 + /* Allocate and read xattr id lookup table */ 276 + msblk->xattr_id_table = squashfs_read_xattr_id_table(sb, 277 + xattr_id_table_start, &msblk->xattr_table, &msblk->xattr_ids); 278 + if (IS_ERR(msblk->xattr_id_table)) { 279 + err = PTR_ERR(msblk->xattr_id_table); 280 + msblk->xattr_id_table = NULL; 281 + if (err != -ENOTSUPP) 282 + goto failed_mount; 283 + } 264 284 allocate_root: 265 285 root = new_inode(sb); 266 286 if (!root) { ··· 311 301 kfree(msblk->inode_lookup_table); 312 302 kfree(msblk->fragment_index); 313 303 kfree(msblk->id_table); 304 + kfree(msblk->xattr_id_table); 314 305 kfree(sb->s_fs_info); 315 306 sb->s_fs_info = NULL; 316 307 kfree(sblk); ··· 366 355 kfree(sbi->fragment_index); 367 356 kfree(sbi->meta_index); 368 357 kfree(sbi->inode_lookup_table); 358 + kfree(sbi->xattr_id_table); 369 359 kfree(sb->s_fs_info); 370 360 sb->s_fs_info = NULL; 371 361 }
+11
fs/squashfs/symlink.c
··· 35 35 #include <linux/kernel.h> 36 36 #include <linux/string.h> 37 37 #include <linux/pagemap.h> 38 + #include <linux/xattr.h> 38 39 39 40 #include "squashfs_fs.h" 40 41 #include "squashfs_fs_sb.h" 41 42 #include "squashfs_fs_i.h" 42 43 #include "squashfs.h" 44 + #include "xattr.h" 43 45 44 46 static int squashfs_symlink_readpage(struct file *file, struct page *page) 45 47 { ··· 116 114 const struct address_space_operations squashfs_symlink_aops = { 117 115 .readpage = squashfs_symlink_readpage 118 116 }; 117 + 118 + const struct inode_operations squashfs_symlink_inode_ops = { 119 + .readlink = generic_readlink, 120 + .follow_link = page_follow_link_light, 121 + .put_link = page_put_link, 122 + .getxattr = generic_getxattr, 123 + .listxattr = squashfs_listxattr 124 + }; 125 +
+323
fs/squashfs/xattr.c
··· 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 +
+46
fs/squashfs/xattr.h
··· 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
+100
fs/squashfs/xattr_id.c
··· 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 + }