Auto-update from upstream
[linux-2.6] / 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         {
186         void hfsplus_inode_check(struct super_block *sb);
187         atomic_inc(&HFSPLUS_SB(sb).inode_cnt);
188         hfsplus_inode_check(sb);
189         }
190 out:
191         d_add(dentry, inode);
192         return NULL;
193 }
194
195 static void hfsplus_get_perms(struct inode *inode, struct hfsplus_perm *perms, int dir)
196 {
197         struct super_block *sb = inode->i_sb;
198         u16 mode;
199
200         mode = be16_to_cpu(perms->mode);
201
202         inode->i_uid = be32_to_cpu(perms->owner);
203         if (!inode->i_uid && !mode)
204                 inode->i_uid = HFSPLUS_SB(sb).uid;
205
206         inode->i_gid = be32_to_cpu(perms->group);
207         if (!inode->i_gid && !mode)
208                 inode->i_gid = HFSPLUS_SB(sb).gid;
209
210         if (dir) {
211                 mode = mode ? (mode & S_IALLUGO) :
212                         (S_IRWXUGO & ~(HFSPLUS_SB(sb).umask));
213                 mode |= S_IFDIR;
214         } else if (!mode)
215                 mode = S_IFREG | ((S_IRUGO|S_IWUGO) &
216                         ~(HFSPLUS_SB(sb).umask));
217         inode->i_mode = mode;
218
219         HFSPLUS_I(inode).rootflags = perms->rootflags;
220         HFSPLUS_I(inode).userflags = perms->userflags;
221         if (perms->rootflags & HFSPLUS_FLG_IMMUTABLE)
222                 inode->i_flags |= S_IMMUTABLE;
223         else
224                 inode->i_flags &= ~S_IMMUTABLE;
225         if (perms->rootflags & HFSPLUS_FLG_APPEND)
226                 inode->i_flags |= S_APPEND;
227         else
228                 inode->i_flags &= ~S_APPEND;
229 }
230
231 static void hfsplus_set_perms(struct inode *inode, struct hfsplus_perm *perms)
232 {
233         if (inode->i_flags & S_IMMUTABLE)
234                 perms->rootflags |= HFSPLUS_FLG_IMMUTABLE;
235         else
236                 perms->rootflags &= ~HFSPLUS_FLG_IMMUTABLE;
237         if (inode->i_flags & S_APPEND)
238                 perms->rootflags |= HFSPLUS_FLG_APPEND;
239         else
240                 perms->rootflags &= ~HFSPLUS_FLG_APPEND;
241         perms->userflags = HFSPLUS_I(inode).userflags;
242         perms->mode = cpu_to_be16(inode->i_mode);
243         perms->owner = cpu_to_be32(inode->i_uid);
244         perms->group = cpu_to_be32(inode->i_gid);
245         perms->dev = cpu_to_be32(HFSPLUS_I(inode).dev);
246 }
247
248 static int hfsplus_permission(struct inode *inode, int mask, struct nameidata *nd)
249 {
250         /* MAY_EXEC is also used for lookup, if no x bit is set allow lookup,
251          * open_exec has the same test, so it's still not executable, if a x bit
252          * is set fall back to standard permission check.
253          */
254         if (S_ISREG(inode->i_mode) && mask & MAY_EXEC && !(inode->i_mode & 0111))
255                 return 0;
256         return generic_permission(inode, mask, NULL);
257 }
258
259
260 static int hfsplus_file_open(struct inode *inode, struct file *file)
261 {
262         if (HFSPLUS_IS_RSRC(inode))
263                 inode = HFSPLUS_I(inode).rsrc_inode;
264         if (atomic_read(&file->f_count) != 1)
265                 return 0;
266         atomic_inc(&HFSPLUS_I(inode).opencnt);
267         return 0;
268 }
269
270 static int hfsplus_file_release(struct inode *inode, struct file *file)
271 {
272         struct super_block *sb = inode->i_sb;
273
274         if (HFSPLUS_IS_RSRC(inode))
275                 inode = HFSPLUS_I(inode).rsrc_inode;
276         if (atomic_read(&file->f_count) != 0)
277                 return 0;
278         if (atomic_dec_and_test(&HFSPLUS_I(inode).opencnt)) {
279                 down(&inode->i_sem);
280                 hfsplus_file_truncate(inode);
281                 if (inode->i_flags & S_DEAD) {
282                         hfsplus_delete_cat(inode->i_ino, HFSPLUS_SB(sb).hidden_dir, NULL);
283                         hfsplus_delete_inode(inode);
284                 }
285                 up(&inode->i_sem);
286         }
287         return 0;
288 }
289
290 extern struct inode_operations hfsplus_dir_inode_operations;
291 extern struct file_operations hfsplus_dir_operations;
292
293 static struct inode_operations hfsplus_file_inode_operations = {
294         .lookup         = hfsplus_file_lookup,
295         .truncate       = hfsplus_file_truncate,
296         .permission     = hfsplus_permission,
297         .setxattr       = hfsplus_setxattr,
298         .getxattr       = hfsplus_getxattr,
299         .listxattr      = hfsplus_listxattr,
300 };
301
302 static struct file_operations hfsplus_file_operations = {
303         .llseek         = generic_file_llseek,
304         .read           = generic_file_read,
305         .write          = generic_file_write,
306         .mmap           = generic_file_mmap,
307         .sendfile       = generic_file_sendfile,
308         .fsync          = file_fsync,
309         .open           = hfsplus_file_open,
310         .release        = hfsplus_file_release,
311         .ioctl          = hfsplus_ioctl,
312 };
313
314 struct inode *hfsplus_new_inode(struct super_block *sb, int mode)
315 {
316         struct inode *inode = new_inode(sb);
317         if (!inode)
318                 return NULL;
319
320         {
321         void hfsplus_inode_check(struct super_block *sb);
322         atomic_inc(&HFSPLUS_SB(sb).inode_cnt);
323         hfsplus_inode_check(sb);
324         }
325         inode->i_ino = HFSPLUS_SB(sb).next_cnid++;
326         inode->i_mode = mode;
327         inode->i_uid = current->fsuid;
328         inode->i_gid = current->fsgid;
329         inode->i_nlink = 1;
330         inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
331         inode->i_blksize = HFSPLUS_SB(sb).alloc_blksz;
332         INIT_LIST_HEAD(&HFSPLUS_I(inode).open_dir_list);
333         init_MUTEX(&HFSPLUS_I(inode).extents_lock);
334         atomic_set(&HFSPLUS_I(inode).opencnt, 0);
335         HFSPLUS_I(inode).flags = 0;
336         memset(HFSPLUS_I(inode).first_extents, 0, sizeof(hfsplus_extent_rec));
337         memset(HFSPLUS_I(inode).cached_extents, 0, sizeof(hfsplus_extent_rec));
338         HFSPLUS_I(inode).alloc_blocks = 0;
339         HFSPLUS_I(inode).first_blocks = 0;
340         HFSPLUS_I(inode).cached_start = 0;
341         HFSPLUS_I(inode).cached_blocks = 0;
342         HFSPLUS_I(inode).phys_size = 0;
343         HFSPLUS_I(inode).fs_blocks = 0;
344         HFSPLUS_I(inode).rsrc_inode = NULL;
345         if (S_ISDIR(inode->i_mode)) {
346                 inode->i_size = 2;
347                 HFSPLUS_SB(sb).folder_count++;
348                 inode->i_op = &hfsplus_dir_inode_operations;
349                 inode->i_fop = &hfsplus_dir_operations;
350         } else if (S_ISREG(inode->i_mode)) {
351                 HFSPLUS_SB(sb).file_count++;
352                 inode->i_op = &hfsplus_file_inode_operations;
353                 inode->i_fop = &hfsplus_file_operations;
354                 inode->i_mapping->a_ops = &hfsplus_aops;
355                 HFSPLUS_I(inode).clump_blocks = HFSPLUS_SB(sb).data_clump_blocks;
356         } else if (S_ISLNK(inode->i_mode)) {
357                 HFSPLUS_SB(sb).file_count++;
358                 inode->i_op = &page_symlink_inode_operations;
359                 inode->i_mapping->a_ops = &hfsplus_aops;
360                 HFSPLUS_I(inode).clump_blocks = 1;
361         } else
362                 HFSPLUS_SB(sb).file_count++;
363         insert_inode_hash(inode);
364         mark_inode_dirty(inode);
365         sb->s_dirt = 1;
366
367         return inode;
368 }
369
370 void hfsplus_delete_inode(struct inode *inode)
371 {
372         struct super_block *sb = inode->i_sb;
373
374         if (S_ISDIR(inode->i_mode)) {
375                 HFSPLUS_SB(sb).folder_count--;
376                 sb->s_dirt = 1;
377                 return;
378         }
379         HFSPLUS_SB(sb).file_count--;
380         if (S_ISREG(inode->i_mode)) {
381                 if (!inode->i_nlink) {
382                         inode->i_size = 0;
383                         hfsplus_file_truncate(inode);
384                 }
385         } else if (S_ISLNK(inode->i_mode)) {
386                 inode->i_size = 0;
387                 hfsplus_file_truncate(inode);
388         }
389         sb->s_dirt = 1;
390 }
391
392 void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
393 {
394         struct super_block *sb = inode->i_sb;
395         u32 count;
396         int i;
397
398         memcpy(&HFSPLUS_I(inode).first_extents, &fork->extents,
399                sizeof(hfsplus_extent_rec));
400         for (count = 0, i = 0; i < 8; i++)
401                 count += be32_to_cpu(fork->extents[i].block_count);
402         HFSPLUS_I(inode).first_blocks = count;
403         memset(HFSPLUS_I(inode).cached_extents, 0, sizeof(hfsplus_extent_rec));
404         HFSPLUS_I(inode).cached_start = 0;
405         HFSPLUS_I(inode).cached_blocks = 0;
406
407         HFSPLUS_I(inode).alloc_blocks = be32_to_cpu(fork->total_blocks);
408         inode->i_size = HFSPLUS_I(inode).phys_size = be64_to_cpu(fork->total_size);
409         HFSPLUS_I(inode).fs_blocks = (inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
410         inode_set_bytes(inode, HFSPLUS_I(inode).fs_blocks << sb->s_blocksize_bits);
411         HFSPLUS_I(inode).clump_blocks = be32_to_cpu(fork->clump_size) >> HFSPLUS_SB(sb).alloc_blksz_shift;
412         if (!HFSPLUS_I(inode).clump_blocks)
413                 HFSPLUS_I(inode).clump_blocks = HFSPLUS_IS_RSRC(inode) ? HFSPLUS_SB(sb).rsrc_clump_blocks :
414                                 HFSPLUS_SB(sb).data_clump_blocks;
415 }
416
417 void hfsplus_inode_write_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
418 {
419         memcpy(&fork->extents, &HFSPLUS_I(inode).first_extents,
420                sizeof(hfsplus_extent_rec));
421         fork->total_size = cpu_to_be64(inode->i_size);
422         fork->total_blocks = cpu_to_be32(HFSPLUS_I(inode).alloc_blocks);
423 }
424
425 int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
426 {
427         hfsplus_cat_entry entry;
428         int res = 0;
429         u16 type;
430
431         type = hfs_bnode_read_u16(fd->bnode, fd->entryoffset);
432
433         HFSPLUS_I(inode).dev = 0;
434         inode->i_blksize = HFSPLUS_SB(inode->i_sb).alloc_blksz;
435         if (type == HFSPLUS_FOLDER) {
436                 struct hfsplus_cat_folder *folder = &entry.folder;
437
438                 if (fd->entrylength < sizeof(struct hfsplus_cat_folder))
439                         /* panic? */;
440                 hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
441                                         sizeof(struct hfsplus_cat_folder));
442                 hfsplus_get_perms(inode, &folder->permissions, 1);
443                 inode->i_nlink = 1;
444                 inode->i_size = 2 + be32_to_cpu(folder->valence);
445                 inode->i_atime = hfsp_mt2ut(folder->access_date);
446                 inode->i_mtime = hfsp_mt2ut(folder->content_mod_date);
447                 inode->i_ctime = inode->i_mtime;
448                 HFSPLUS_I(inode).fs_blocks = 0;
449                 inode->i_op = &hfsplus_dir_inode_operations;
450                 inode->i_fop = &hfsplus_dir_operations;
451         } else if (type == HFSPLUS_FILE) {
452                 struct hfsplus_cat_file *file = &entry.file;
453
454                 if (fd->entrylength < sizeof(struct hfsplus_cat_file))
455                         /* panic? */;
456                 hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
457                                         sizeof(struct hfsplus_cat_file));
458
459                 hfsplus_inode_read_fork(inode, HFSPLUS_IS_DATA(inode) ?
460                                         &file->data_fork : &file->rsrc_fork);
461                 hfsplus_get_perms(inode, &file->permissions, 0);
462                 inode->i_nlink = 1;
463                 if (S_ISREG(inode->i_mode)) {
464                         if (file->permissions.dev)
465                                 inode->i_nlink = be32_to_cpu(file->permissions.dev);
466                         inode->i_op = &hfsplus_file_inode_operations;
467                         inode->i_fop = &hfsplus_file_operations;
468                         inode->i_mapping->a_ops = &hfsplus_aops;
469                 } else if (S_ISLNK(inode->i_mode)) {
470                         inode->i_op = &page_symlink_inode_operations;
471                         inode->i_mapping->a_ops = &hfsplus_aops;
472                 } else {
473                         init_special_inode(inode, inode->i_mode,
474                                            be32_to_cpu(file->permissions.dev));
475                 }
476                 inode->i_atime = hfsp_mt2ut(file->access_date);
477                 inode->i_mtime = hfsp_mt2ut(file->content_mod_date);
478                 inode->i_ctime = inode->i_mtime;
479         } else {
480                 printk("HFS+-fs: bad catalog entry used to create inode\n");
481                 res = -EIO;
482         }
483         return res;
484 }
485
486 int hfsplus_cat_write_inode(struct inode *inode)
487 {
488         struct inode *main_inode = inode;
489         struct hfs_find_data fd;
490         hfsplus_cat_entry entry;
491
492         if (HFSPLUS_IS_RSRC(inode))
493                 main_inode = HFSPLUS_I(inode).rsrc_inode;
494
495         if (!main_inode->i_nlink)
496                 return 0;
497
498         if (hfs_find_init(HFSPLUS_SB(main_inode->i_sb).cat_tree, &fd))
499                 /* panic? */
500                 return -EIO;
501
502         if (hfsplus_find_cat(main_inode->i_sb, main_inode->i_ino, &fd))
503                 /* panic? */
504                 goto out;
505
506         if (S_ISDIR(main_inode->i_mode)) {
507                 struct hfsplus_cat_folder *folder = &entry.folder;
508
509                 if (fd.entrylength < sizeof(struct hfsplus_cat_folder))
510                         /* panic? */;
511                 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
512                                         sizeof(struct hfsplus_cat_folder));
513                 /* simple node checks? */
514                 hfsplus_set_perms(inode, &folder->permissions);
515                 folder->access_date = hfsp_ut2mt(inode->i_atime);
516                 folder->content_mod_date = hfsp_ut2mt(inode->i_mtime);
517                 folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
518                 folder->valence = cpu_to_be32(inode->i_size - 2);
519                 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
520                                          sizeof(struct hfsplus_cat_folder));
521         } else if (HFSPLUS_IS_RSRC(inode)) {
522                 struct hfsplus_cat_file *file = &entry.file;
523                 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
524                                sizeof(struct hfsplus_cat_file));
525                 hfsplus_inode_write_fork(inode, &file->rsrc_fork);
526                 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
527                                 sizeof(struct hfsplus_cat_file));
528         } else {
529                 struct hfsplus_cat_file *file = &entry.file;
530
531                 if (fd.entrylength < sizeof(struct hfsplus_cat_file))
532                         /* panic? */;
533                 hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
534                                         sizeof(struct hfsplus_cat_file));
535                 hfsplus_inode_write_fork(inode, &file->data_fork);
536                 if (S_ISREG(inode->i_mode))
537                         HFSPLUS_I(inode).dev = inode->i_nlink;
538                 if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode))
539                         HFSPLUS_I(inode).dev = kdev_t_to_nr(inode->i_rdev);
540                 hfsplus_set_perms(inode, &file->permissions);
541                 if ((file->permissions.rootflags | file->permissions.userflags) & HFSPLUS_FLG_IMMUTABLE)
542                         file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
543                 else
544                         file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED);
545                 file->access_date = hfsp_ut2mt(inode->i_atime);
546                 file->content_mod_date = hfsp_ut2mt(inode->i_mtime);
547                 file->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
548                 hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
549                                          sizeof(struct hfsplus_cat_file));
550         }
551 out:
552         hfs_find_exit(&fd);
553         return 0;
554 }