xref: /openbmc/linux/fs/hfsplus/inode.c (revision 97da55fc)
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/blkdev.h>
12 #include <linux/mm.h>
13 #include <linux/fs.h>
14 #include <linux/pagemap.h>
15 #include <linux/mpage.h>
16 #include <linux/sched.h>
17 
18 #include "hfsplus_fs.h"
19 #include "hfsplus_raw.h"
20 #include "xattr.h"
21 
22 static int hfsplus_readpage(struct file *file, struct page *page)
23 {
24 	return block_read_full_page(page, hfsplus_get_block);
25 }
26 
27 static int hfsplus_writepage(struct page *page, struct writeback_control *wbc)
28 {
29 	return block_write_full_page(page, hfsplus_get_block, wbc);
30 }
31 
32 static void hfsplus_write_failed(struct address_space *mapping, loff_t to)
33 {
34 	struct inode *inode = mapping->host;
35 
36 	if (to > inode->i_size) {
37 		truncate_pagecache(inode, to, inode->i_size);
38 		hfsplus_file_truncate(inode);
39 	}
40 }
41 
42 static int hfsplus_write_begin(struct file *file, struct address_space *mapping,
43 			loff_t pos, unsigned len, unsigned flags,
44 			struct page **pagep, void **fsdata)
45 {
46 	int ret;
47 
48 	*pagep = NULL;
49 	ret = cont_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
50 				hfsplus_get_block,
51 				&HFSPLUS_I(mapping->host)->phys_size);
52 	if (unlikely(ret))
53 		hfsplus_write_failed(mapping, pos + len);
54 
55 	return ret;
56 }
57 
58 static sector_t hfsplus_bmap(struct address_space *mapping, sector_t block)
59 {
60 	return generic_block_bmap(mapping, block, hfsplus_get_block);
61 }
62 
63 static int hfsplus_releasepage(struct page *page, gfp_t mask)
64 {
65 	struct inode *inode = page->mapping->host;
66 	struct super_block *sb = inode->i_sb;
67 	struct hfs_btree *tree;
68 	struct hfs_bnode *node;
69 	u32 nidx;
70 	int i, res = 1;
71 
72 	switch (inode->i_ino) {
73 	case HFSPLUS_EXT_CNID:
74 		tree = HFSPLUS_SB(sb)->ext_tree;
75 		break;
76 	case HFSPLUS_CAT_CNID:
77 		tree = HFSPLUS_SB(sb)->cat_tree;
78 		break;
79 	case HFSPLUS_ATTR_CNID:
80 		tree = HFSPLUS_SB(sb)->attr_tree;
81 		break;
82 	default:
83 		BUG();
84 		return 0;
85 	}
86 	if (!tree)
87 		return 0;
88 	if (tree->node_size >= PAGE_CACHE_SIZE) {
89 		nidx = page->index >>
90 			(tree->node_size_shift - PAGE_CACHE_SHIFT);
91 		spin_lock(&tree->hash_lock);
92 		node = hfs_bnode_findhash(tree, nidx);
93 		if (!node)
94 			;
95 		else if (atomic_read(&node->refcnt))
96 			res = 0;
97 		if (res && node) {
98 			hfs_bnode_unhash(node);
99 			hfs_bnode_free(node);
100 		}
101 		spin_unlock(&tree->hash_lock);
102 	} else {
103 		nidx = page->index <<
104 			(PAGE_CACHE_SHIFT - tree->node_size_shift);
105 		i = 1 << (PAGE_CACHE_SHIFT - tree->node_size_shift);
106 		spin_lock(&tree->hash_lock);
107 		do {
108 			node = hfs_bnode_findhash(tree, nidx++);
109 			if (!node)
110 				continue;
111 			if (atomic_read(&node->refcnt)) {
112 				res = 0;
113 				break;
114 			}
115 			hfs_bnode_unhash(node);
116 			hfs_bnode_free(node);
117 		} while (--i && nidx < tree->node_count);
118 		spin_unlock(&tree->hash_lock);
119 	}
120 	return res ? try_to_free_buffers(page) : 0;
121 }
122 
123 static ssize_t hfsplus_direct_IO(int rw, struct kiocb *iocb,
124 		const struct iovec *iov, loff_t offset, unsigned long nr_segs)
125 {
126 	struct file *file = iocb->ki_filp;
127 	struct address_space *mapping = file->f_mapping;
128 	struct inode *inode = file_inode(file)->i_mapping->host;
129 	ssize_t ret;
130 
131 	ret = blockdev_direct_IO(rw, iocb, inode, iov, offset, nr_segs,
132 				 hfsplus_get_block);
133 
134 	/*
135 	 * In case of error extending write may have instantiated a few
136 	 * blocks outside i_size. Trim these off again.
137 	 */
138 	if (unlikely((rw & WRITE) && ret < 0)) {
139 		loff_t isize = i_size_read(inode);
140 		loff_t end = offset + iov_length(iov, nr_segs);
141 
142 		if (end > isize)
143 			hfsplus_write_failed(mapping, end);
144 	}
145 
146 	return ret;
147 }
148 
149 static int hfsplus_writepages(struct address_space *mapping,
150 			      struct writeback_control *wbc)
151 {
152 	return mpage_writepages(mapping, wbc, hfsplus_get_block);
153 }
154 
155 const struct address_space_operations hfsplus_btree_aops = {
156 	.readpage	= hfsplus_readpage,
157 	.writepage	= hfsplus_writepage,
158 	.write_begin	= hfsplus_write_begin,
159 	.write_end	= generic_write_end,
160 	.bmap		= hfsplus_bmap,
161 	.releasepage	= hfsplus_releasepage,
162 };
163 
164 const struct address_space_operations hfsplus_aops = {
165 	.readpage	= hfsplus_readpage,
166 	.writepage	= hfsplus_writepage,
167 	.write_begin	= hfsplus_write_begin,
168 	.write_end	= generic_write_end,
169 	.bmap		= hfsplus_bmap,
170 	.direct_IO	= hfsplus_direct_IO,
171 	.writepages	= hfsplus_writepages,
172 };
173 
174 const struct dentry_operations hfsplus_dentry_operations = {
175 	.d_hash       = hfsplus_hash_dentry,
176 	.d_compare    = hfsplus_compare_dentry,
177 };
178 
179 static struct dentry *hfsplus_file_lookup(struct inode *dir,
180 		struct dentry *dentry, unsigned int flags)
181 {
182 	struct hfs_find_data fd;
183 	struct super_block *sb = dir->i_sb;
184 	struct inode *inode = NULL;
185 	struct hfsplus_inode_info *hip;
186 	int err;
187 
188 	if (HFSPLUS_IS_RSRC(dir) || strcmp(dentry->d_name.name, "rsrc"))
189 		goto out;
190 
191 	inode = HFSPLUS_I(dir)->rsrc_inode;
192 	if (inode)
193 		goto out;
194 
195 	inode = new_inode(sb);
196 	if (!inode)
197 		return ERR_PTR(-ENOMEM);
198 
199 	hip = HFSPLUS_I(inode);
200 	inode->i_ino = dir->i_ino;
201 	INIT_LIST_HEAD(&hip->open_dir_list);
202 	mutex_init(&hip->extents_lock);
203 	hip->extent_state = 0;
204 	hip->flags = 0;
205 	hip->userflags = 0;
206 	set_bit(HFSPLUS_I_RSRC, &hip->flags);
207 
208 	err = hfs_find_init(HFSPLUS_SB(sb)->cat_tree, &fd);
209 	if (!err) {
210 		err = hfsplus_find_cat(sb, dir->i_ino, &fd);
211 		if (!err)
212 			err = hfsplus_cat_read_inode(inode, &fd);
213 		hfs_find_exit(&fd);
214 	}
215 	if (err) {
216 		iput(inode);
217 		return ERR_PTR(err);
218 	}
219 	hip->rsrc_inode = dir;
220 	HFSPLUS_I(dir)->rsrc_inode = inode;
221 	igrab(dir);
222 
223 	/*
224 	 * __mark_inode_dirty expects inodes to be hashed.  Since we don't
225 	 * want resource fork inodes in the regular inode space, we make them
226 	 * appear hashed, but do not put on any lists.  hlist_del()
227 	 * will work fine and require no locking.
228 	 */
229 	hlist_add_fake(&inode->i_hash);
230 
231 	mark_inode_dirty(inode);
232 out:
233 	d_add(dentry, inode);
234 	return NULL;
235 }
236 
237 static void hfsplus_get_perms(struct inode *inode,
238 		struct hfsplus_perm *perms, int dir)
239 {
240 	struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
241 	u16 mode;
242 
243 	mode = be16_to_cpu(perms->mode);
244 
245 	i_uid_write(inode, be32_to_cpu(perms->owner));
246 	if (!i_uid_read(inode) && !mode)
247 		inode->i_uid = sbi->uid;
248 
249 	i_gid_write(inode, be32_to_cpu(perms->group));
250 	if (!i_gid_read(inode) && !mode)
251 		inode->i_gid = sbi->gid;
252 
253 	if (dir) {
254 		mode = mode ? (mode & S_IALLUGO) : (S_IRWXUGO & ~(sbi->umask));
255 		mode |= S_IFDIR;
256 	} else if (!mode)
257 		mode = S_IFREG | ((S_IRUGO|S_IWUGO) & ~(sbi->umask));
258 	inode->i_mode = mode;
259 
260 	HFSPLUS_I(inode)->userflags = perms->userflags;
261 	if (perms->rootflags & HFSPLUS_FLG_IMMUTABLE)
262 		inode->i_flags |= S_IMMUTABLE;
263 	else
264 		inode->i_flags &= ~S_IMMUTABLE;
265 	if (perms->rootflags & HFSPLUS_FLG_APPEND)
266 		inode->i_flags |= S_APPEND;
267 	else
268 		inode->i_flags &= ~S_APPEND;
269 }
270 
271 static int hfsplus_file_open(struct inode *inode, struct file *file)
272 {
273 	if (HFSPLUS_IS_RSRC(inode))
274 		inode = HFSPLUS_I(inode)->rsrc_inode;
275 	if (!(file->f_flags & O_LARGEFILE) && i_size_read(inode) > MAX_NON_LFS)
276 		return -EOVERFLOW;
277 	atomic_inc(&HFSPLUS_I(inode)->opencnt);
278 	return 0;
279 }
280 
281 static int hfsplus_file_release(struct inode *inode, struct file *file)
282 {
283 	struct super_block *sb = inode->i_sb;
284 
285 	if (HFSPLUS_IS_RSRC(inode))
286 		inode = HFSPLUS_I(inode)->rsrc_inode;
287 	if (atomic_dec_and_test(&HFSPLUS_I(inode)->opencnt)) {
288 		mutex_lock(&inode->i_mutex);
289 		hfsplus_file_truncate(inode);
290 		if (inode->i_flags & S_DEAD) {
291 			hfsplus_delete_cat(inode->i_ino,
292 					   HFSPLUS_SB(sb)->hidden_dir, NULL);
293 			hfsplus_delete_inode(inode);
294 		}
295 		mutex_unlock(&inode->i_mutex);
296 	}
297 	return 0;
298 }
299 
300 static int hfsplus_setattr(struct dentry *dentry, struct iattr *attr)
301 {
302 	struct inode *inode = dentry->d_inode;
303 	int error;
304 
305 	error = inode_change_ok(inode, attr);
306 	if (error)
307 		return error;
308 
309 	if ((attr->ia_valid & ATTR_SIZE) &&
310 	    attr->ia_size != i_size_read(inode)) {
311 		inode_dio_wait(inode);
312 		truncate_setsize(inode, attr->ia_size);
313 		hfsplus_file_truncate(inode);
314 	}
315 
316 	setattr_copy(inode, attr);
317 	mark_inode_dirty(inode);
318 	return 0;
319 }
320 
321 int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end,
322 		       int datasync)
323 {
324 	struct inode *inode = file->f_mapping->host;
325 	struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
326 	struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
327 	int error = 0, error2;
328 
329 	error = filemap_write_and_wait_range(inode->i_mapping, start, end);
330 	if (error)
331 		return error;
332 	mutex_lock(&inode->i_mutex);
333 
334 	/*
335 	 * Sync inode metadata into the catalog and extent trees.
336 	 */
337 	sync_inode_metadata(inode, 1);
338 
339 	/*
340 	 * And explicitly write out the btrees.
341 	 */
342 	if (test_and_clear_bit(HFSPLUS_I_CAT_DIRTY, &hip->flags))
343 		error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping);
344 
345 	if (test_and_clear_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags)) {
346 		error2 =
347 			filemap_write_and_wait(sbi->ext_tree->inode->i_mapping);
348 		if (!error)
349 			error = error2;
350 	}
351 
352 	if (test_and_clear_bit(HFSPLUS_I_ATTR_DIRTY, &hip->flags)) {
353 		if (sbi->attr_tree) {
354 			error2 =
355 				filemap_write_and_wait(
356 					    sbi->attr_tree->inode->i_mapping);
357 			if (!error)
358 				error = error2;
359 		} else {
360 			printk(KERN_ERR "hfs: sync non-existent attributes tree\n");
361 		}
362 	}
363 
364 	if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags)) {
365 		error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
366 		if (!error)
367 			error = error2;
368 	}
369 
370 	if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
371 		blkdev_issue_flush(inode->i_sb->s_bdev, GFP_KERNEL, NULL);
372 
373 	mutex_unlock(&inode->i_mutex);
374 
375 	return error;
376 }
377 
378 static const struct inode_operations hfsplus_file_inode_operations = {
379 	.lookup		= hfsplus_file_lookup,
380 	.setattr	= hfsplus_setattr,
381 	.setxattr	= generic_setxattr,
382 	.getxattr	= generic_getxattr,
383 	.listxattr	= hfsplus_listxattr,
384 	.removexattr	= hfsplus_removexattr,
385 };
386 
387 static const struct file_operations hfsplus_file_operations = {
388 	.llseek		= generic_file_llseek,
389 	.read		= do_sync_read,
390 	.aio_read	= generic_file_aio_read,
391 	.write		= do_sync_write,
392 	.aio_write	= generic_file_aio_write,
393 	.mmap		= generic_file_mmap,
394 	.splice_read	= generic_file_splice_read,
395 	.fsync		= hfsplus_file_fsync,
396 	.open		= hfsplus_file_open,
397 	.release	= hfsplus_file_release,
398 	.unlocked_ioctl = hfsplus_ioctl,
399 };
400 
401 struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode)
402 {
403 	struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
404 	struct inode *inode = new_inode(sb);
405 	struct hfsplus_inode_info *hip;
406 
407 	if (!inode)
408 		return NULL;
409 
410 	inode->i_ino = sbi->next_cnid++;
411 	inode->i_mode = mode;
412 	inode->i_uid = current_fsuid();
413 	inode->i_gid = current_fsgid();
414 	set_nlink(inode, 1);
415 	inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
416 
417 	hip = HFSPLUS_I(inode);
418 	INIT_LIST_HEAD(&hip->open_dir_list);
419 	mutex_init(&hip->extents_lock);
420 	atomic_set(&hip->opencnt, 0);
421 	hip->extent_state = 0;
422 	hip->flags = 0;
423 	hip->userflags = 0;
424 	memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec));
425 	memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
426 	hip->alloc_blocks = 0;
427 	hip->first_blocks = 0;
428 	hip->cached_start = 0;
429 	hip->cached_blocks = 0;
430 	hip->phys_size = 0;
431 	hip->fs_blocks = 0;
432 	hip->rsrc_inode = NULL;
433 	if (S_ISDIR(inode->i_mode)) {
434 		inode->i_size = 2;
435 		sbi->folder_count++;
436 		inode->i_op = &hfsplus_dir_inode_operations;
437 		inode->i_fop = &hfsplus_dir_operations;
438 	} else if (S_ISREG(inode->i_mode)) {
439 		sbi->file_count++;
440 		inode->i_op = &hfsplus_file_inode_operations;
441 		inode->i_fop = &hfsplus_file_operations;
442 		inode->i_mapping->a_ops = &hfsplus_aops;
443 		hip->clump_blocks = sbi->data_clump_blocks;
444 	} else if (S_ISLNK(inode->i_mode)) {
445 		sbi->file_count++;
446 		inode->i_op = &page_symlink_inode_operations;
447 		inode->i_mapping->a_ops = &hfsplus_aops;
448 		hip->clump_blocks = 1;
449 	} else
450 		sbi->file_count++;
451 	insert_inode_hash(inode);
452 	mark_inode_dirty(inode);
453 	hfsplus_mark_mdb_dirty(sb);
454 
455 	return inode;
456 }
457 
458 void hfsplus_delete_inode(struct inode *inode)
459 {
460 	struct super_block *sb = inode->i_sb;
461 
462 	if (S_ISDIR(inode->i_mode)) {
463 		HFSPLUS_SB(sb)->folder_count--;
464 		hfsplus_mark_mdb_dirty(sb);
465 		return;
466 	}
467 	HFSPLUS_SB(sb)->file_count--;
468 	if (S_ISREG(inode->i_mode)) {
469 		if (!inode->i_nlink) {
470 			inode->i_size = 0;
471 			hfsplus_file_truncate(inode);
472 		}
473 	} else if (S_ISLNK(inode->i_mode)) {
474 		inode->i_size = 0;
475 		hfsplus_file_truncate(inode);
476 	}
477 	hfsplus_mark_mdb_dirty(sb);
478 }
479 
480 void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
481 {
482 	struct super_block *sb = inode->i_sb;
483 	struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
484 	struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
485 	u32 count;
486 	int i;
487 
488 	memcpy(&hip->first_extents, &fork->extents, sizeof(hfsplus_extent_rec));
489 	for (count = 0, i = 0; i < 8; i++)
490 		count += be32_to_cpu(fork->extents[i].block_count);
491 	hip->first_blocks = count;
492 	memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
493 	hip->cached_start = 0;
494 	hip->cached_blocks = 0;
495 
496 	hip->alloc_blocks = be32_to_cpu(fork->total_blocks);
497 	hip->phys_size = inode->i_size = be64_to_cpu(fork->total_size);
498 	hip->fs_blocks =
499 		(inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
500 	inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits);
501 	hip->clump_blocks =
502 		be32_to_cpu(fork->clump_size) >> sbi->alloc_blksz_shift;
503 	if (!hip->clump_blocks) {
504 		hip->clump_blocks = HFSPLUS_IS_RSRC(inode) ?
505 			sbi->rsrc_clump_blocks :
506 			sbi->data_clump_blocks;
507 	}
508 }
509 
510 void hfsplus_inode_write_fork(struct inode *inode,
511 		struct hfsplus_fork_raw *fork)
512 {
513 	memcpy(&fork->extents, &HFSPLUS_I(inode)->first_extents,
514 	       sizeof(hfsplus_extent_rec));
515 	fork->total_size = cpu_to_be64(inode->i_size);
516 	fork->total_blocks = cpu_to_be32(HFSPLUS_I(inode)->alloc_blocks);
517 }
518 
519 int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
520 {
521 	hfsplus_cat_entry entry;
522 	int res = 0;
523 	u16 type;
524 
525 	type = hfs_bnode_read_u16(fd->bnode, fd->entryoffset);
526 
527 	HFSPLUS_I(inode)->linkid = 0;
528 	if (type == HFSPLUS_FOLDER) {
529 		struct hfsplus_cat_folder *folder = &entry.folder;
530 
531 		if (fd->entrylength < sizeof(struct hfsplus_cat_folder))
532 			/* panic? */;
533 		hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
534 					sizeof(struct hfsplus_cat_folder));
535 		hfsplus_get_perms(inode, &folder->permissions, 1);
536 		set_nlink(inode, 1);
537 		inode->i_size = 2 + be32_to_cpu(folder->valence);
538 		inode->i_atime = hfsp_mt2ut(folder->access_date);
539 		inode->i_mtime = hfsp_mt2ut(folder->content_mod_date);
540 		inode->i_ctime = hfsp_mt2ut(folder->attribute_mod_date);
541 		HFSPLUS_I(inode)->create_date = folder->create_date;
542 		HFSPLUS_I(inode)->fs_blocks = 0;
543 		inode->i_op = &hfsplus_dir_inode_operations;
544 		inode->i_fop = &hfsplus_dir_operations;
545 	} else if (type == HFSPLUS_FILE) {
546 		struct hfsplus_cat_file *file = &entry.file;
547 
548 		if (fd->entrylength < sizeof(struct hfsplus_cat_file))
549 			/* panic? */;
550 		hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
551 					sizeof(struct hfsplus_cat_file));
552 
553 		hfsplus_inode_read_fork(inode, HFSPLUS_IS_RSRC(inode) ?
554 					&file->rsrc_fork : &file->data_fork);
555 		hfsplus_get_perms(inode, &file->permissions, 0);
556 		set_nlink(inode, 1);
557 		if (S_ISREG(inode->i_mode)) {
558 			if (file->permissions.dev)
559 				set_nlink(inode,
560 					  be32_to_cpu(file->permissions.dev));
561 			inode->i_op = &hfsplus_file_inode_operations;
562 			inode->i_fop = &hfsplus_file_operations;
563 			inode->i_mapping->a_ops = &hfsplus_aops;
564 		} else if (S_ISLNK(inode->i_mode)) {
565 			inode->i_op = &page_symlink_inode_operations;
566 			inode->i_mapping->a_ops = &hfsplus_aops;
567 		} else {
568 			init_special_inode(inode, inode->i_mode,
569 					   be32_to_cpu(file->permissions.dev));
570 		}
571 		inode->i_atime = hfsp_mt2ut(file->access_date);
572 		inode->i_mtime = hfsp_mt2ut(file->content_mod_date);
573 		inode->i_ctime = hfsp_mt2ut(file->attribute_mod_date);
574 		HFSPLUS_I(inode)->create_date = file->create_date;
575 	} else {
576 		printk(KERN_ERR "hfs: bad catalog entry used to create inode\n");
577 		res = -EIO;
578 	}
579 	return res;
580 }
581 
582 int hfsplus_cat_write_inode(struct inode *inode)
583 {
584 	struct inode *main_inode = inode;
585 	struct hfs_find_data fd;
586 	hfsplus_cat_entry entry;
587 
588 	if (HFSPLUS_IS_RSRC(inode))
589 		main_inode = HFSPLUS_I(inode)->rsrc_inode;
590 
591 	if (!main_inode->i_nlink)
592 		return 0;
593 
594 	if (hfs_find_init(HFSPLUS_SB(main_inode->i_sb)->cat_tree, &fd))
595 		/* panic? */
596 		return -EIO;
597 
598 	if (hfsplus_find_cat(main_inode->i_sb, main_inode->i_ino, &fd))
599 		/* panic? */
600 		goto out;
601 
602 	if (S_ISDIR(main_inode->i_mode)) {
603 		struct hfsplus_cat_folder *folder = &entry.folder;
604 
605 		if (fd.entrylength < sizeof(struct hfsplus_cat_folder))
606 			/* panic? */;
607 		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
608 					sizeof(struct hfsplus_cat_folder));
609 		/* simple node checks? */
610 		hfsplus_cat_set_perms(inode, &folder->permissions);
611 		folder->access_date = hfsp_ut2mt(inode->i_atime);
612 		folder->content_mod_date = hfsp_ut2mt(inode->i_mtime);
613 		folder->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
614 		folder->valence = cpu_to_be32(inode->i_size - 2);
615 		hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
616 					 sizeof(struct hfsplus_cat_folder));
617 	} else if (HFSPLUS_IS_RSRC(inode)) {
618 		struct hfsplus_cat_file *file = &entry.file;
619 		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
620 			       sizeof(struct hfsplus_cat_file));
621 		hfsplus_inode_write_fork(inode, &file->rsrc_fork);
622 		hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
623 				sizeof(struct hfsplus_cat_file));
624 	} else {
625 		struct hfsplus_cat_file *file = &entry.file;
626 
627 		if (fd.entrylength < sizeof(struct hfsplus_cat_file))
628 			/* panic? */;
629 		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
630 					sizeof(struct hfsplus_cat_file));
631 		hfsplus_inode_write_fork(inode, &file->data_fork);
632 		hfsplus_cat_set_perms(inode, &file->permissions);
633 		if (HFSPLUS_FLG_IMMUTABLE &
634 				(file->permissions.rootflags |
635 					file->permissions.userflags))
636 			file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
637 		else
638 			file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED);
639 		file->access_date = hfsp_ut2mt(inode->i_atime);
640 		file->content_mod_date = hfsp_ut2mt(inode->i_mtime);
641 		file->attribute_mod_date = hfsp_ut2mt(inode->i_ctime);
642 		hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
643 					 sizeof(struct hfsplus_cat_file));
644 	}
645 
646 	set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags);
647 out:
648 	hfs_find_exit(&fd);
649 	return 0;
650 }
651