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