diff options
-rw-r--r-- | fs/cramfs/inode.c | 110 |
1 files changed, 69 insertions, 41 deletions
diff --git a/fs/cramfs/inode.c b/fs/cramfs/inode.c index 32fd5fe9ca0e..e141939080f0 100644 --- a/fs/cramfs/inode.c +++ b/fs/cramfs/inode.c | |||
@@ -34,57 +34,81 @@ static const struct address_space_operations cramfs_aops; | |||
34 | static DEFINE_MUTEX(read_mutex); | 34 | static DEFINE_MUTEX(read_mutex); |
35 | 35 | ||
36 | 36 | ||
37 | /* These two macros may change in future, to provide better st_ino | 37 | /* These macros may change in future, to provide better st_ino semantics. */ |
38 | semantics. */ | ||
39 | #define CRAMINO(x) (((x)->offset && (x)->size)?(x)->offset<<2:1) | ||
40 | #define OFFSET(x) ((x)->i_ino) | 38 | #define OFFSET(x) ((x)->i_ino) |
41 | 39 | ||
42 | static void setup_inode(struct inode *inode, struct cramfs_inode * cramfs_inode) | 40 | static unsigned long cramino(struct cramfs_inode *cino, unsigned int offset) |
43 | { | 41 | { |
42 | if (!cino->offset) | ||
43 | return offset + 1; | ||
44 | if (!cino->size) | ||
45 | return offset + 1; | ||
46 | |||
47 | /* | ||
48 | * The file mode test fixes buggy mkcramfs implementations where | ||
49 | * cramfs_inode->offset is set to a non zero value for entries | ||
50 | * which did not contain data, like devices node and fifos. | ||
51 | */ | ||
52 | switch (cino->mode & S_IFMT) { | ||
53 | case S_IFREG: | ||
54 | case S_IFDIR: | ||
55 | case S_IFLNK: | ||
56 | return cino->offset << 2; | ||
57 | default: | ||
58 | break; | ||
59 | } | ||
60 | return offset + 1; | ||
61 | } | ||
62 | |||
63 | static struct inode *get_cramfs_inode(struct super_block *sb, | ||
64 | struct cramfs_inode *cramfs_inode, unsigned int offset) | ||
65 | { | ||
66 | struct inode *inode; | ||
44 | static struct timespec zerotime; | 67 | static struct timespec zerotime; |
68 | |||
69 | inode = iget_locked(sb, cramino(cramfs_inode, offset)); | ||
70 | if (!inode) | ||
71 | return ERR_PTR(-ENOMEM); | ||
72 | if (!(inode->i_state & I_NEW)) | ||
73 | return inode; | ||
74 | |||
75 | switch (cramfs_inode->mode & S_IFMT) { | ||
76 | case S_IFREG: | ||
77 | inode->i_fop = &generic_ro_fops; | ||
78 | inode->i_data.a_ops = &cramfs_aops; | ||
79 | break; | ||
80 | case S_IFDIR: | ||
81 | inode->i_op = &cramfs_dir_inode_operations; | ||
82 | inode->i_fop = &cramfs_directory_operations; | ||
83 | break; | ||
84 | case S_IFLNK: | ||
85 | inode->i_op = &page_symlink_inode_operations; | ||
86 | inode->i_data.a_ops = &cramfs_aops; | ||
87 | break; | ||
88 | default: | ||
89 | init_special_inode(inode, cramfs_inode->mode, | ||
90 | old_decode_dev(cramfs_inode->size)); | ||
91 | } | ||
92 | |||
45 | inode->i_mode = cramfs_inode->mode; | 93 | inode->i_mode = cramfs_inode->mode; |
46 | inode->i_uid = cramfs_inode->uid; | 94 | inode->i_uid = cramfs_inode->uid; |
47 | inode->i_size = cramfs_inode->size; | ||
48 | inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1; | ||
49 | inode->i_gid = cramfs_inode->gid; | 95 | inode->i_gid = cramfs_inode->gid; |
96 | |||
97 | /* if the lower 2 bits are zero, the inode contains data */ | ||
98 | if (!(inode->i_ino & 3)) { | ||
99 | inode->i_size = cramfs_inode->size; | ||
100 | inode->i_blocks = (cramfs_inode->size - 1) / 512 + 1; | ||
101 | } | ||
102 | |||
50 | /* Struct copy intentional */ | 103 | /* Struct copy intentional */ |
51 | inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime; | 104 | inode->i_mtime = inode->i_atime = inode->i_ctime = zerotime; |
52 | /* inode->i_nlink is left 1 - arguably wrong for directories, | 105 | /* inode->i_nlink is left 1 - arguably wrong for directories, |
53 | but it's the best we can do without reading the directory | 106 | but it's the best we can do without reading the directory |
54 | contents. 1 yields the right result in GNU find, even | 107 | contents. 1 yields the right result in GNU find, even |
55 | without -noleaf option. */ | 108 | without -noleaf option. */ |
56 | if (S_ISREG(inode->i_mode)) { | ||
57 | inode->i_fop = &generic_ro_fops; | ||
58 | inode->i_data.a_ops = &cramfs_aops; | ||
59 | } else if (S_ISDIR(inode->i_mode)) { | ||
60 | inode->i_op = &cramfs_dir_inode_operations; | ||
61 | inode->i_fop = &cramfs_directory_operations; | ||
62 | } else if (S_ISLNK(inode->i_mode)) { | ||
63 | inode->i_op = &page_symlink_inode_operations; | ||
64 | inode->i_data.a_ops = &cramfs_aops; | ||
65 | } else { | ||
66 | init_special_inode(inode, inode->i_mode, | ||
67 | old_decode_dev(cramfs_inode->size)); | ||
68 | } | ||
69 | } | ||
70 | 109 | ||
71 | static struct inode *get_cramfs_inode(struct super_block *sb, | 110 | unlock_new_inode(inode); |
72 | struct cramfs_inode * cramfs_inode) | 111 | |
73 | { | ||
74 | struct inode *inode; | ||
75 | if (CRAMINO(cramfs_inode) == 1) { | ||
76 | inode = new_inode(sb); | ||
77 | if (inode) { | ||
78 | inode->i_ino = 1; | ||
79 | setup_inode(inode, cramfs_inode); | ||
80 | } | ||
81 | } else { | ||
82 | inode = iget_locked(sb, CRAMINO(cramfs_inode)); | ||
83 | if (inode && (inode->i_state & I_NEW)) { | ||
84 | setup_inode(inode, cramfs_inode); | ||
85 | unlock_new_inode(inode); | ||
86 | } | ||
87 | } | ||
88 | return inode; | 112 | return inode; |
89 | } | 113 | } |
90 | 114 | ||
@@ -265,6 +289,9 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent) | |||
265 | printk(KERN_ERR "cramfs: root is not a directory\n"); | 289 | printk(KERN_ERR "cramfs: root is not a directory\n"); |
266 | goto out; | 290 | goto out; |
267 | } | 291 | } |
292 | /* correct strange, hard-coded permissions of mkcramfs */ | ||
293 | super.root.mode |= (S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); | ||
294 | |||
268 | root_offset = super.root.offset << 2; | 295 | root_offset = super.root.offset << 2; |
269 | if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) { | 296 | if (super.flags & CRAMFS_FLAG_FSID_VERSION_2) { |
270 | sbi->size=super.size; | 297 | sbi->size=super.size; |
@@ -289,7 +316,7 @@ static int cramfs_fill_super(struct super_block *sb, void *data, int silent) | |||
289 | 316 | ||
290 | /* Set it all up.. */ | 317 | /* Set it all up.. */ |
291 | sb->s_op = &cramfs_ops; | 318 | sb->s_op = &cramfs_ops; |
292 | root = get_cramfs_inode(sb, &super.root); | 319 | root = get_cramfs_inode(sb, &super.root, 0); |
293 | if (!root) | 320 | if (!root) |
294 | goto out; | 321 | goto out; |
295 | sb->s_root = d_alloc_root(root); | 322 | sb->s_root = d_alloc_root(root); |
@@ -365,7 +392,7 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir) | |||
365 | */ | 392 | */ |
366 | namelen = de->namelen << 2; | 393 | namelen = de->namelen << 2; |
367 | memcpy(buf, name, namelen); | 394 | memcpy(buf, name, namelen); |
368 | ino = CRAMINO(de); | 395 | ino = cramino(de, OFFSET(inode) + offset); |
369 | mode = de->mode; | 396 | mode = de->mode; |
370 | mutex_unlock(&read_mutex); | 397 | mutex_unlock(&read_mutex); |
371 | nextoffset = offset + sizeof(*de) + namelen; | 398 | nextoffset = offset + sizeof(*de) + namelen; |
@@ -404,8 +431,9 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s | |||
404 | struct cramfs_inode *de; | 431 | struct cramfs_inode *de; |
405 | char *name; | 432 | char *name; |
406 | int namelen, retval; | 433 | int namelen, retval; |
434 | int dir_off = OFFSET(dir) + offset; | ||
407 | 435 | ||
408 | de = cramfs_read(dir->i_sb, OFFSET(dir) + offset, sizeof(*de)+CRAMFS_MAXPATHLEN); | 436 | de = cramfs_read(dir->i_sb, dir_off, sizeof(*de)+CRAMFS_MAXPATHLEN); |
409 | name = (char *)(de+1); | 437 | name = (char *)(de+1); |
410 | 438 | ||
411 | /* Try to take advantage of sorted directories */ | 439 | /* Try to take advantage of sorted directories */ |
@@ -436,7 +464,7 @@ static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, s | |||
436 | if (!retval) { | 464 | if (!retval) { |
437 | struct cramfs_inode entry = *de; | 465 | struct cramfs_inode entry = *de; |
438 | mutex_unlock(&read_mutex); | 466 | mutex_unlock(&read_mutex); |
439 | d_add(dentry, get_cramfs_inode(dir->i_sb, &entry)); | 467 | d_add(dentry, get_cramfs_inode(dir->i_sb, &entry, dir_off)); |
440 | return NULL; | 468 | return NULL; |
441 | } | 469 | } |
442 | /* else (retval < 0) */ | 470 | /* else (retval < 0) */ |