7acff6c5464ffdca66599d0dbebe524571139c40
[pandora-kernel.git] / fs / hfsplus / inode.c
1 /*
2  *  linux/fs/hfsplus/inode.c
3  *
4  * Copyright (C) 2001
5  * Brad Boyer (flar@allandria.com)
6  * (C) 2003 Ardis Technologies <roman@ardistech.com>
7  *
8  * Inode handling routines
9  */
10
11 #include <linux/mm.h>
12 #include <linux/fs.h>
13 #include <linux/pagemap.h>
14 #include <linux/mpage.h>
15
16 #include "hfsplus_fs.h"
17 #include "hfsplus_raw.h"
18
19 static int hfsplus_readpage(struct file *file, struct page *page)
20 {
21         //printk("readpage: %lu\n", page->index);
22         return block_read_full_page(page, hfsplus_get_block);
23 }
24
25 static int hfsplus_writepage(struct page *page, struct writeback_control *wbc)
26 {
27         //printk("writepage: %lu\n", page->index);
28         return block_write_full_page(page, hfsplus_get_block, wbc);
29 }
30
31 static int hfsplus_prepare_write(struct file *file, struct page *page, unsigned from, unsigned to)
32 {
33         return cont_prepare_write(page, from, to, hfsplus_get_block,
34                 &HFSPLUS_I(page->mapping->host).phys_size);
35 }
36
37 static sector_t hfsplus_bmap(struct address_space *mapping, sector_t block)
38 {
39         return generic_block_bmap(mapping, block, hfsplus_get_block);
40 }
41
42 static int hfsplus_releasepage(struct page *page, gfp_t mask)
43 {
44         struct inode *inode = page->mapping->host;
45         struct super_block *sb = inode->i_sb;
46         struct hfs_btree *tree;
47         struct hfs_bnode *node;
48         u32 nidx;
49         int i, res = 1;
50
51         switch (inode->i_ino) {
52         case HFSPLUS_EXT_CNID:
53                 tree = HFSPLUS_SB(sb).ext_tree;
54                 break;
55         case HFSPLUS_CAT_CNID:
56                 tree = HFSPLUS_SB(sb).cat_tree;
57                 break;
58         case HFSPLUS_ATTR_CNID:
59                 tree = HFSPLUS_SB(sb).attr_tree;
60                 break;
61         default:
62                 BUG();
63                 return 0;
64         }
65         if (tree->node_size >= PAGE_CACHE_SIZE) {
66                 nidx = page->index >> (tree->node_size_shift - PAGE_CACHE_SHIFT);
67                 spin_lock(&tree->hash_lock);
68                 node = hfs_bnode_findhash(tree, nidx);
69                 if (!node)
70                         ;
71                 else if (atomic_read(&node->refcnt))
72                         res = 0;
73                 if (res && node) {
74                         hfs_bnode_unhash(node);
75                         hfs_bnode_free(node);
76                 }
77                 spin_unlock(&tree->hash_lock);
78         } else {
79                 nidx = page->index << (PAGE_CACHE_SHIFT - tree->node_size_shift);
80                 i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift);
81                 spin_lock(&tree->hash_lock);
82                 do {
83                         node = hfs_bnode_findhash(tree, nidx++);
84                         if (!node)
85                                 continue;
86                         if (atomic_read(&node->refcnt)) {
87                                 res = 0;
88                                 break;
89                         }
90                         hfs_bnode_unhash(node);
91                         hfs_bnode_free(node);
92                 } while (--i && nidx < tree->node_count);
93                 spin_unlock(&tree->hash_lock);
94         }
95         //printk("releasepage: %lu,%x = %d\n", page->index, mask, res);
96         return res ? try_to_free_buffers(page) : 0;
97 }
98
99 static int hfsplus_get_blocks(struct inode *inode, sector_t iblock, unsigned long max_blocks,
100                               struct buffer_head *bh_result, int create)
101 {
102         int ret;
103
104         ret = hfsplus_get_block(inode, iblock, bh_result, create);
105         if (!ret)
106                 bh_result->b_size = (1 << inode->i_blkbits);
107         return ret;
108 }
109
110 static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb,
111                 const struct iovec *iov, loff_t offset, unsigned long nr_segs)
112 {
113         struct file *file = iocb->ki_filp;
114         struct inode *inode = file->f_dentry->d_inode->i_mapping->host;
115
116         return blockdev_direct_IO(rw, iocb, inode, inode->i_sb->s_bdev, iov,
117                                   offset, nr_segs, hfsplus_get_blocks, NULL);
118 }
119
120 static int hfsplus_writepages(struct address_space *mapping,
121                               struct writeback_control *wbc)
122 {
123         return mpage_writepages(mapping, wbc, hfsplus_get_block);
124 }
125
126 struct address_space_operations hfsplus_btree_aops = {
127         .readpage       = hfsplus_readpage,
128         .writepage      = hfsplus_writepage,
129         .sync_page      = block_sync_page,
130         .prepare_write  = hfsplus_prepare_write,
131         .commit_write   = generic_commit_write,
132         .bmap           = hfsplus_bmap,
133         .releasepage    = hfsplus_releasepage,
134 };
135
136 struct address_space_operations hfsplus_aops = {
137         .readpage       = hfsplus_readpage,
138         .writepage      = hfsplus_writepage,
139         .sync_page      = block_sync_page,
140         .prepare_write  = hfsplus_prepare_write,
141         .commit_write   = generic_commit_write,
142         .bmap           = hfsplus_bmap,
143         .direct_IO      = hfsplus_direct_IO,
144         .writepages     = hfsplus_writepages,
145 };
146
147 static struct dentry *hfsplus_file_lookup(struct inode *dir, struct dentry *dentry,
148                                           struct nameidata *nd)
149 {
150         struct hfs_find_data fd;
151         struct super_block *sb = dir->i_sb;
152         struct inode *inode = NULL;
153         int err;
154
155         if (HFSPLUS_IS_RSRC(dir) || strcmp(dentry->d_name.name, "rsrc"))
156                 goto out;
157
158         inode = HFSPLUS_I(dir).rsrc_inode;
159         if (inode)
160                 goto out;
161
162         inode = new_inode(sb);
163         if (!inode)
164                 return ERR_PTR(-ENOMEM);
165
166         inode->i_ino = dir->i_ino;
167         INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
168         init_MUTEX(&HFSPLUS_I(inode).extents_lock);
169         HFSPLUS_I(inode).flags = HFSPLUS_FLG_RSRC;
170
171         hfs_find_init(HFSPLUS_SB(sb).cat_tree, &fd);
172         err = hfsplus_find_cat(sb, dir->i_ino, &fd);
173         if (!err)
174                 err = hfsplus_cat_read_inode(inode, &fd);
175         hfs_find_exit(&fd);
176         if (err) {
177                 iput(inode);
178                 return ERR_PTR(err);
179         }
180         HFSPLUS_I(inode).rsrc_inode = dir;
181         HFSPLUS_I(dir).rsrc_inode = inode;
182         igrab(dir);
183         hlist_add_head(&inode->i_hash, &HFSPLUS_SB(sb).rsrc_inodes);
184         mark_inode_dirty(inode);
185 out:
186         d_add(dentry, inode);
187         return NULL;
188 }
189
190 static void hfsplus_get_perms(struct inode *inode, struct hfsplus_perm *perms, int dir)
191 {
192         struct super_block *sb = inode->i_sb;
193         u16 mode;
194
195         mode = be16_to_cpu(perms->mode);
196
197         inode->i_uid = be32_to_cpu(perms->owner);
198         if (!inode->i_uid && !mode)
199                 inode->i_uid = HFSPLUS_SB(sb).uid;
200
201         inode->i_gid = be32_to_cpu(perms->group);
202         if (!inode->i_gid && !mode)
203                 inode->i_gid = HFSPLUS_SB(sb).gid;
204
205         if (dir) {
206                 mode = mode ? (mode & S_IALLUGO) :
207                         (S_IRWXUGO & ~(HFSPLUS_SB(sb).umask));
208                 mode |= S_IFDIR;
209         } else if (!mode)
210                 mode = S_IFREG | ((S_IRUGO|S_IWUGO) &
211                         ~(HFSPLUS_SB(sb).umask));
212         inode->i_mode = mode;
213
214         HFSPLUS_I(inode).rootflags = perms->rootflags;
215         HFSPLUS_I(inode).userflags = perms->userflags;
216         if (perms->rootflags & HFSPLUS_FLG_IMMUTABLE)
217                 inode->i_flags |= S_IMMUTABLE;
218         else
219                 inode->i_flags &= ~S_IMMUTABLE;
220         if (perms->rootflags & HFSPLUS_FLG_APPEND)
221                 inode->i_flags |= S_APPEND;
222         else
223                 inode->i_flags &= ~S_APPEND;
224 }
225
226 static void hfsplus_set_perms(struct inode *inode, struct hfsplus_perm *perms)
227 {
228         if (inode->i_flags & S_IMMUTABLE)
229                 perms->rootflags |= HFSPLUS_FLG_IMMUTABLE;
230         else
231                 perms->rootflags &= ~HFSPLUS_FLG_IMMUTABLE;
232         if (inode->i_flags & S_APPEND)
233                 perms->rootflags |= HFSPLUS_FLG_APPEND;
234         else
235                 perms->rootflags &= ~HFSPLUS_FLG_APPEND;
236         perms->userflags = HFSPLUS_I(inode).userflags;
237         perms->mode = cpu_to_be16(inode->i_mode);
238         perms->owner = cpu_to_be32(inode->i_uid);
239         perms->group = cpu_to_be32(inode->i_gid);
240         perms->dev = cpu_to_be32(HFSPLUS_I(inode).dev);
241 }
242
243 static int hfsplus_permission(struct inode *inode, int mask, struct nameidata *nd)
244 {
245         /* MAY_EXEC is also used for lookup, if no x bit is set allow lookup,
246          * open_exec has the same test, so it's still not executable, if a x bit
247          * is set fall back to standard permission check.
248          */
249         if (S_ISREG(inode->i_mode) && mask & MAY_EXEC && !(inode->i_mode & 0111))
250                 return 0;
251         return generic_permission(inode, mask, NULL);
252 }
253
254
255 static int hfsplus_file_open(struct inode *inode, struct file *file)
256 {
257         if (HFSPLUS_IS_RSRC(inode))
258                 inode = HFSPLUS_I(inode).rsrc_inode;
259         if (atomic_read(&file->f_count) != 1)
260                 return 0;
261         atomic_inc(&HFSPLUS_I(inode).opencnt);
262         return 0;
263 }
264
265 static int hfsplus_file_release(struct inode *inode, struct file *file)
266 {
267         struct super_block *sb = inode->i_sb;
268
269         if (HFSPLUS_IS_RSRC(inode))
270                 inode = HFSPLUS_I(inode).rsrc_inode;
271         if (atomic_read(&file->f_count) != 0)
272                 return 0;
273         if (atomic_dec_and_test(&HFSPLUS_I(inode).opencnt)) {
274                 mutex_lock(&inode->i_mutex);
275                 hfsplus_file_truncate(inode);
276                 if (inode->i_flags & S_DEAD) {
277                         hfsplus_delete_cat(inode->i_ino, HFSPLUS_SB(sb).hidden_dir, NULL);
278                         hfsplus_delete_inode(inode);
279                 }
280                 mutex_unlock(&inode->i_mutex);
281         }
282         return 0;
283 }
284
285 extern struct inode_operations hfsplus_dir_inode_operations;
286 extern struct file_operations hfsplus_dir_operations;
287
288 static struct inode_operations hfsplus_file_inode_operations = {
289         .lookup         = hfsplus_file_lookup,
290         .truncate       = hfsplus_file_truncate,
291         .permission     = hfsplus_permission,
292         .setxattr       = hfsplus_setxattr,
293         .getxattr       = hfsplus_getxattr,
294         .listxattr      = hfsplus_listxattr,
295 };
296
297 static struct file_operations hfsplus_file_operations = {
298         .llseek         = generic_file_llseek,
299         .read           = generic_file_read,
300         .write          = generic_file_write,
301         .mmap           = generic_file_mmap,
302         .sendfile       = generic_file_sendfile,
303         .fsync          = file_fsync,
304         .open           = hfsplus_file_open,
305         .release        = hfsplus_file_release,
306         .ioctl          = hfsplus_ioctl,
307 };
308
309 struct inode *hfsplus_new_inode(struct super_block *sb, int mode)
310 {
311         struct inode *inode = new_inode(sb);
312         if (!inode)
313                 return NULL;
314
315         inode->i_ino = HFSPLUS_SB(sb).next_cnid++;
316         inode->i_mode = mode;
317         inode->i_uid = current->fsuid;
318         inode->i_gid = current->fsgid;
319         inode->i_nlink = 1;
320         inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
321         inode->i_blksize = HFSPLUS_SB(sb).alloc_blksz;
322         INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
323         init_MUTEX(&HFSPLUS_I(inode).extents_lock);
324         atomic_set(&HFSPLUS_I(inode).opencnt, 0);
325         HFSPLUS_I(inode).flags = 0;
326         memset(HFSPLUS_I(inode).first_extents, 0, sizeof(hfsplus_extent_rec));
327         memset(HFSPLUS_I(inode).cached_extents, 0, sizeof(hfsplus_extent_rec));
328         HFSPLUS_I(inode).alloc_blocks = 0;
329         HFSPLUS_I(inode).first_blocks = 0;
330         HFSPLUS_I(inode).cached_start = 0;
331         HFSPLUS_I(inode).cached_blocks = 0;
332         HFSPLUS_I(inode).phys_size = 0;
333         HFSPLUS_I(inode).fs_blocks = 0;
334         HFSPLUS_I(inode).rsrc_inode = NULL;
335         if (S_ISDIR(inode->i_mode)) {
336                 inode->i_size = 2;
337                 HFSPLUS_SB(sb).folder_count++;
338                 inode->i_op = &hfsplus_dir_inode_operations;
339                 inode->i_fop = &hfsplus_dir_operations;
340         } else if (S_ISREG(inode->i_mode)) {
341                 HFSPLUS_SB(sb).file_count++;
342                 inode->i_op = &hfsplus_file_inode_operations;
343                 inode->i_fop = &hfsplus_file_operations;
344                 inode->i_mapping->a_ops = &hfsplus_aops;
345                 HFSPLUS_I(inode).clump_blocks = HFSPLUS_SB(sb).data_clump_blocks;
346         } else if (S_ISLNK(inode->i_mode)) {
347                 HFSPLUS_SB(sb).file_count++;
348                 inode->i_op = &page_symlink_inode_operations;
349                 inode->i_mapping->a_ops = &hfsplus_aops;
350                 HFSPLUS_I(inode).clump_blocks = 1;
351         } else
352                 HFSPLUS_SB(sb).file_count++;
353         insert_inode_hash(inode);
354         mark_inode_dirty(inode);
355         sb->s_dirt = 1;
356
357         return inode;
358 }
359
360 void hfsplus_delete_inode(struct inode *inode)
361 {
362         struct super_block *sb = inode->i_sb;
363
364         if (S_ISDIR(inode->i_mode)) {
365                 HFSPLUS_SB(sb).folder_count--;
366                 sb->s_dirt = 1;
367                 return;
368         }
369         HFSPLUS_SB(sb).file_count--;
370         if (S_ISREG(inode->i_mode)) {
371                 if (!inode->i_nlink) {
372                         inode->i_size = 0;
373                         hfsplus_file_truncate(inode);
374                 }
375         } else if (S_ISLNK(inode->i_mode)) {
376                 inode->i_size = 0;
377                 hfsplus_file_truncate(inode);
378         }
379         sb->s_dirt = 1;
380 }
381
382 void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
383 {
384         struct super_block *sb = inode->i_sb;
385         u32 count;
386         int i;
387
388         memcpy(&HFSPLUS_I(inode).first_extents, &fork->extents,
389                sizeof(hfsplus_extent_rec));
390         for (count = 0, i = 0; i < 8; i++)
391                 count += be32_to_cpu(fork->extents[i].block_count);
392         HFSPLUS_I(inode).first_blocks = count;
393         memset(HFSPLUS_I(inode).cached_extents, 0, sizeof(hfsplus_extent_rec));
394         HFSPLUS_I(inode).cached_start = 0;
395         HFSPLUS_I(inode).cached_blocks = 0;
396
397         HFSPLUS_I(inode).alloc_blocks = be32_to_cpu(fork->total_blocks);
398         inode->i_size = HFSPLUS_I(inode).phys_size = be64_to_cpu(fork->total_size);
399         HFSPLUS_I(inode).fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
400         inode_set_bytes(inode, HFSPLUS_I(inode).fs_blocks << sb->s_blocksize_bits);
401         HFSPLUS_I(inode).clump_blocks = be32_to_cpu(fork->clump_size) >> HFSPLUS_SB(sb).alloc_blksz_shift;
402         if (!HFSPLUS_I(inode).clump_blocks)
403                 HFSPLUS_I(inode).clump_blocks = HFSPLUS_IS_RSRC(inode) ? HFSPLUS_SB(sb).rsrc_clump_blocks :
404                                 HFSPLUS_SB(sb).data_clump_blocks;
405 }
406
407 void hfsplus_inode_write_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
408 {
409         memcpy(&fork->extents, &HFSPLUS_I(inode).first_extents,
410                sizeof(hfsplus_extent_rec));
411         fork->total_size = cpu_to_be64(inode->i_size);
412         fork->total_blocks = cpu_to_be32(HFSPLUS_I(inode).alloc_blocks);
413 }
414
415 int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
416 {
417         hfsplus_cat_entry entry;
418         int res = 0;
419         u16 type;
420
421         type = hfs_bnode_read_u16(fd->bnode, fd->entryoffset);
422
423         HFSPLUS_I(inode).dev = 0;
424         inode->i_blksize = HFSPLUS_SB(inode->i_sb).alloc_blksz;
425         if (type == HFSPLUS_FOLDER) {
426                 struct hfsplus_cat_folder *folder = &entry.folder;
427
428                 if (fd->entrylength < sizeof(struct hfsplus_cat_folder))
429                         /* panic? */;
430                 hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
431                                         sizeof(struct hfsplus_cat_folder));
432                 hfsplus_get_perms(inode, &folder->permissions, 1);
433                 inode->i_nlink = 1;
434                 inode->i_size = 2 + be32_to_cpu(folder->valence);
435                 inode->i_atime = hfsp_mt2ut(folder->access_date);
436                 inode->i_mtime = hfsp_mt2ut(folder->content_mod_date);
437                 inode->i_ctime = inode->i_mtime;
438                 HFSPLUS_I(inode).fs_blocks = 0;
439                 inode->i_op = &hfsplus_dir_inode_operations;
440                 inode->i_fop = &hfsplus_dir_operations;
441         } else if (type == HFSPLUS_FILE) {
442                 struct hfsplus_cat_file *file = &entry.file;
443
444                 if (fd->entrylength < sizeof(struct hfsplus_cat_file))
445                         /* panic? */;
446                 hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
447                                         sizeof(struct hfsplus_cat_file));
448
449                 hfsplus_inode_read_fork(inode, HFSPLUS_IS_DATA(inode) ?
450                                         &file->data_fork : &file->rsrc_fork);
451                 hfsplus_get_perms(inode, &file->permissions, 0);
452                 inode->i_nlink = 1;
453                 if (S_ISREG(inode->i_mode)) {
454                         if (file->permissions.dev)
455                                 inode->i_nlink = be32_to_cpu(file->permissions.dev);
456                         inode->i_op = &hfsplus_file_inode_operations;
457                         inode->i_fop = &hfsplus_file_operations;
458                         inode->i_mapping->a_ops = &hfsplus_aops;
459                 } else if (S_ISLNK(inode->i_mode)) {
460                         inode->i_op = &page_symlink_inode_operations;
461                         inode->i_mapping->a_ops = &hfsplus_aops;
462                 } else {
463                         init_special_inode(inode, inode->i_mode,
464                                            be32_to_cpu(file->permissions.dev));
465                 }
466                 inode->i_atime = hfsp_mt2ut(file->access_date);
467                 inode->i_mtime = hfsp_mt2ut(file->content_mod_date);
468                 inode->i_ctime = inode->i_mtime;
469         } else {
470                 printk("HFS+-fs: bad catalog entry used to create inode\n");
471                 res = -EIO;
472         }
473         return res;
474 }
475
476 int hfsplus_cat_write_inode(struct inode *inode)
477 {
478         struct inode *main_inode = inode;
479         struct hfs_find_data fd;
480         hfsplus_cat_entry entry;
481
482         if (HFSPLUS_IS_RSRC(inode))
483                 main_inode = HFSPLUS_I(inode).rsrc_inode;
484
485         if (!main_inode->i_nlink)
486                 return 0;
487
488         if (hfs_find_init(HFSPLUS_SB(main_inode->i_sb).cat_tree, &fd))
489                 /* panic? */
490                 return -EIO;
491
492         if (hfsplus_find_cat(main_inode->i_sb, main_inode->i_ino, &fd))
493                 /* panic? */
494                 goto out;
495
496         if (S_ISDIR(main_inode->i_mode)) {
497                 struct hfsplus_cat_folder *folder = &entry.folder;
498
499                 if (fd.entrylength < sizeof(struct hfsplus_cat_folder))
500                         /* panic? */;
501                 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
502                                         sizeof(struct hfsplus_cat_folder));
503                 /* simple node checks? */
504                 hfsplus_set_perms(inode, &folder->permissions);
505                 folder->access_date = hfsp_ut2mt(inode->i_atime);
506                 folder->content_mod_date = hfsp_ut2mt(inode->i_mtime);
507                 folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
508                 folder->valence = cpu_to_be32(inode->i_size - 2);
509                 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
510                                          sizeof(struct hfsplus_cat_folder));
511         } else if (HFSPLUS_IS_RSRC(inode)) {
512                 struct hfsplus_cat_file *file = &entry.file;
513                 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
514                                sizeof(struct hfsplus_cat_file));
515                 hfsplus_inode_write_fork(inode, &file->rsrc_fork);
516                 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
517                                 sizeof(struct hfsplus_cat_file));
518         } else {
519                 struct hfsplus_cat_file *file = &entry.file;
520
521                 if (fd.entrylength < sizeof(struct hfsplus_cat_file))
522                         /* panic? */;
523                 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
524                                         sizeof(struct hfsplus_cat_file));
525                 hfsplus_inode_write_fork(inode, &file->data_fork);
526                 if (S_ISREG(inode->i_mode))
527                         HFSPLUS_I(inode).dev = inode->i_nlink;
528                 if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
529                         HFSPLUS_I(inode).dev = kdev_t_to_nr(inode->i_rdev);
530                 hfsplus_set_perms(inode, &file->permissions);
531                 if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE)
532                         file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
533                 else
534                         file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED);
535                 file->access_date = hfsp_ut2mt(inode->i_atime);
536                 file->content_mod_date = hfsp_ut2mt(inode->i_mtime);
537                 file->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
538                 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
539                                          sizeof(struct hfsplus_cat_file));
540         }
541 out:
542         hfs_find_exit(&fd);
543         return 0;
544 }