xref: /linux/fs/hfsplus/inode.c (revision 056a5087d87ead77dedbe9cf5bde53b7cd4b4651)
1 // SPDX-License-Identifier: GPL-2.0
2 /*
3  *  linux/fs/hfsplus/inode.c
4  *
5  * Copyright (C) 2001
6  * Brad Boyer (flar@allandria.com)
7  * (C) 2003 Ardis Technologies <roman@ardistech.com>
8  *
9  * Inode handling routines
10  */
11 
12 #include <linux/blkdev.h>
13 #include <linux/mm.h>
14 #include <linux/fs.h>
15 #include <linux/pagemap.h>
16 #include <linux/mpage.h>
17 #include <linux/sched.h>
18 #include <linux/cred.h>
19 #include <linux/uio.h>
20 #include <linux/fileattr.h>
21 
22 #include "hfsplus_fs.h"
23 #include "hfsplus_raw.h"
24 #include "xattr.h"
25 
26 static int hfsplus_read_folio(struct file *file, struct folio *folio)
27 {
28 	return block_read_full_folio(folio, hfsplus_get_block);
29 }
30 
31 static void hfsplus_write_failed(struct address_space *mapping, loff_t to)
32 {
33 	struct inode *inode = mapping->host;
34 
35 	if (to > inode->i_size) {
36 		truncate_pagecache(inode, inode->i_size);
37 		hfsplus_file_truncate(inode);
38 	}
39 }
40 
41 int hfsplus_write_begin(const struct kiocb *iocb,
42 			struct address_space *mapping, loff_t pos,
43 			unsigned len, struct folio **foliop,
44 			void **fsdata)
45 {
46 	int ret;
47 
48 	ret = cont_write_begin(iocb, mapping, pos, len, foliop, fsdata,
49 				hfsplus_get_block,
50 				&HFSPLUS_I(mapping->host)->phys_size);
51 	if (unlikely(ret))
52 		hfsplus_write_failed(mapping, pos + len);
53 
54 	return ret;
55 }
56 
57 static sector_t hfsplus_bmap(struct address_space *mapping, sector_t block)
58 {
59 	return generic_block_bmap(mapping, block, hfsplus_get_block);
60 }
61 
62 static bool hfsplus_release_folio(struct folio *folio, gfp_t mask)
63 {
64 	struct inode *inode = folio->mapping->host;
65 	struct super_block *sb = inode->i_sb;
66 	struct hfs_btree *tree;
67 	struct hfs_bnode *node;
68 	u32 nidx;
69 	int i;
70 	bool res = true;
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 false;
85 	}
86 	if (!tree)
87 		return false;
88 	if (tree->node_size >= PAGE_SIZE) {
89 		nidx = folio->index >>
90 			(tree->node_size_shift - PAGE_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 = false;
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 = folio->index <<
104 			(PAGE_SHIFT - tree->node_size_shift);
105 		i = 1 << (PAGE_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 = false;
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(folio) : false;
121 }
122 
123 static ssize_t hfsplus_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
124 {
125 	struct file *file = iocb->ki_filp;
126 	struct address_space *mapping = file->f_mapping;
127 	struct inode *inode = mapping->host;
128 	loff_t isize;
129 	size_t count = iov_iter_count(iter);
130 	loff_t end = iocb->ki_pos + count;
131 	ssize_t ret;
132 
133 	/*
134 	 * The hfsplus_get_block() only allows creating the next sequential block.
135 	 * For direct writes beyond EOF, expand the file first.
136 	 */
137 	if (iov_iter_rw(iter) == WRITE && iocb->ki_pos > i_size_read(inode)) {
138 		loff_t start_off, end_off;
139 		loff_t start_page, end_page;
140 
141 		isize = i_size_read(inode);
142 
143 		/*
144 		 * Wait for any in-flight DIO on this inode to finish before
145 		 * calling generic_cont_expand_simple().
146 		 */
147 		inode_dio_wait(inode);
148 
149 		ret = generic_cont_expand_simple(inode, iocb->ki_pos);
150 		if (ret)
151 			return ret;
152 
153 		start_off = isize;
154 		end_off = (end > 0) ? end - 1 : end;
155 
156 		ret = filemap_write_and_wait_range(mapping, start_off, end_off);
157 		if (ret)
158 			return ret;
159 
160 		start_page = start_off >> PAGE_SHIFT;
161 		end_page = end_off >> PAGE_SHIFT;
162 
163 		invalidate_inode_pages2_range(mapping, start_page, end_page);
164 	}
165 
166 	ret = blockdev_direct_IO(iocb, inode, iter, hfsplus_get_block);
167 
168 	/*
169 	 * In case of error extending write may have instantiated a few
170 	 * blocks outside i_size. Trim these off again.
171 	 */
172 	if (unlikely(iov_iter_rw(iter) == WRITE && ret < 0)) {
173 		isize = i_size_read(inode);
174 
175 		if (end > isize)
176 			hfsplus_write_failed(mapping, end);
177 	}
178 
179 	return ret;
180 }
181 
182 static int hfsplus_writepages(struct address_space *mapping,
183 			      struct writeback_control *wbc)
184 {
185 	return mpage_writepages(mapping, wbc, hfsplus_get_block);
186 }
187 
188 const struct address_space_operations hfsplus_btree_aops = {
189 	.dirty_folio	= block_dirty_folio,
190 	.invalidate_folio = block_invalidate_folio,
191 	.read_folio	= hfsplus_read_folio,
192 	.writepages	= hfsplus_writepages,
193 	.write_begin	= hfsplus_write_begin,
194 	.write_end	= generic_write_end,
195 	.migrate_folio	= buffer_migrate_folio,
196 	.bmap		= hfsplus_bmap,
197 	.release_folio	= hfsplus_release_folio,
198 };
199 
200 const struct address_space_operations hfsplus_aops = {
201 	.dirty_folio	= block_dirty_folio,
202 	.invalidate_folio = block_invalidate_folio,
203 	.read_folio	= hfsplus_read_folio,
204 	.write_begin	= hfsplus_write_begin,
205 	.write_end	= generic_write_end,
206 	.bmap		= hfsplus_bmap,
207 	.direct_IO	= hfsplus_direct_IO,
208 	.writepages	= hfsplus_writepages,
209 	.migrate_folio	= buffer_migrate_folio,
210 };
211 
212 const struct dentry_operations hfsplus_dentry_operations = {
213 	.d_hash       = hfsplus_hash_dentry,
214 	.d_compare    = hfsplus_compare_dentry,
215 };
216 
217 static int hfsplus_get_perms(struct inode *inode,
218 			     struct hfsplus_perm *perms, int dir)
219 {
220 	struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
221 	u16 mode;
222 
223 	mode = be16_to_cpu(perms->mode);
224 	if (dir) {
225 		if (mode && !S_ISDIR(mode))
226 			goto bad_type;
227 	} else if (mode) {
228 		switch (mode & S_IFMT) {
229 		case S_IFREG:
230 		case S_IFLNK:
231 		case S_IFCHR:
232 		case S_IFBLK:
233 		case S_IFIFO:
234 		case S_IFSOCK:
235 			break;
236 		default:
237 			goto bad_type;
238 		}
239 	}
240 
241 	i_uid_write(inode, be32_to_cpu(perms->owner));
242 	if ((test_bit(HFSPLUS_SB_UID, &sbi->flags)) || (!i_uid_read(inode) && !mode))
243 		inode->i_uid = sbi->uid;
244 
245 	i_gid_write(inode, be32_to_cpu(perms->group));
246 	if ((test_bit(HFSPLUS_SB_GID, &sbi->flags)) || (!i_gid_read(inode) && !mode))
247 		inode->i_gid = sbi->gid;
248 
249 	if (dir) {
250 		mode = mode ? (mode & S_IALLUGO) : (S_IRWXUGO & ~(sbi->umask));
251 		mode |= S_IFDIR;
252 	} else if (!mode)
253 		mode = S_IFREG | ((S_IRUGO|S_IWUGO) & ~(sbi->umask));
254 	inode->i_mode = mode;
255 
256 	HFSPLUS_I(inode)->userflags = perms->userflags;
257 	if (perms->rootflags & HFSPLUS_FLG_IMMUTABLE)
258 		inode->i_flags |= S_IMMUTABLE;
259 	else
260 		inode->i_flags &= ~S_IMMUTABLE;
261 	if (perms->rootflags & HFSPLUS_FLG_APPEND)
262 		inode->i_flags |= S_APPEND;
263 	else
264 		inode->i_flags &= ~S_APPEND;
265 	return 0;
266 bad_type:
267 	pr_err("invalid file type 0%04o for inode %llu\n", mode, inode->i_ino);
268 	return -EIO;
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 		inode_lock(inode);
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 		inode_unlock(inode);
296 	}
297 	return 0;
298 }
299 
300 static int hfsplus_setattr(struct mnt_idmap *idmap,
301 			   struct dentry *dentry, struct iattr *attr)
302 {
303 	struct inode *inode = d_inode(dentry);
304 	int error;
305 
306 	error = setattr_prepare(&nop_mnt_idmap, dentry, attr);
307 	if (error)
308 		return error;
309 
310 	if ((attr->ia_valid & ATTR_SIZE) &&
311 	    attr->ia_size != i_size_read(inode)) {
312 		inode_dio_wait(inode);
313 		if (attr->ia_size > inode->i_size) {
314 			error = generic_cont_expand_simple(inode,
315 							   attr->ia_size);
316 			if (error)
317 				return error;
318 		}
319 		truncate_setsize(inode, attr->ia_size);
320 		hfsplus_file_truncate(inode);
321 		inode_set_mtime_to_ts(inode, inode_set_ctime_current(inode));
322 	}
323 
324 	setattr_copy(&nop_mnt_idmap, inode, attr);
325 	mark_inode_dirty(inode);
326 
327 	return 0;
328 }
329 
330 int hfsplus_getattr(struct mnt_idmap *idmap, const struct path *path,
331 		    struct kstat *stat, u32 request_mask,
332 		    unsigned int query_flags)
333 {
334 	struct inode *inode = d_inode(path->dentry);
335 	struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
336 
337 	if (request_mask & STATX_BTIME) {
338 		stat->result_mask |= STATX_BTIME;
339 		stat->btime = hfsp_mt2ut(hip->create_date);
340 	}
341 
342 	if (inode->i_flags & S_APPEND)
343 		stat->attributes |= STATX_ATTR_APPEND;
344 	if (inode->i_flags & S_IMMUTABLE)
345 		stat->attributes |= STATX_ATTR_IMMUTABLE;
346 	if (hip->userflags & HFSPLUS_FLG_NODUMP)
347 		stat->attributes |= STATX_ATTR_NODUMP;
348 
349 	stat->attributes_mask |= STATX_ATTR_APPEND | STATX_ATTR_IMMUTABLE |
350 				 STATX_ATTR_NODUMP;
351 
352 	generic_fillattr(&nop_mnt_idmap, request_mask, inode, stat);
353 	return 0;
354 }
355 
356 int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end,
357 		       int datasync)
358 {
359 	struct inode *inode = file->f_mapping->host;
360 	struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
361 	struct super_block *sb = inode->i_sb;
362 	struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
363 	struct hfsplus_vh *vhdr = sbi->s_vhdr;
364 	int error = 0, error2;
365 
366 	hfs_dbg("inode->i_ino %llu, start %llu, end %llu\n",
367 		inode->i_ino, start, end);
368 
369 	error = file_write_and_wait_range(file, start, end);
370 	if (error)
371 		return error;
372 	inode_lock(inode);
373 
374 	/*
375 	 * Sync inode metadata into the catalog and extent trees.
376 	 */
377 	sync_inode_metadata(inode, 1);
378 
379 	/*
380 	 * And explicitly write out the btrees.
381 	 */
382 	if (test_and_clear_bit(HFSPLUS_I_CAT_DIRTY,
383 				&HFSPLUS_I(HFSPLUS_CAT_TREE_I(sb))->flags)) {
384 		clear_bit(HFSPLUS_I_CAT_DIRTY, &hip->flags);
385 		error = filemap_write_and_wait(sbi->cat_tree->inode->i_mapping);
386 	}
387 
388 	if (test_and_clear_bit(HFSPLUS_I_EXT_DIRTY,
389 				&HFSPLUS_I(HFSPLUS_EXT_TREE_I(sb))->flags)) {
390 		clear_bit(HFSPLUS_I_EXT_DIRTY, &hip->flags);
391 		error2 =
392 			filemap_write_and_wait(sbi->ext_tree->inode->i_mapping);
393 		if (!error)
394 			error = error2;
395 	}
396 
397 	if (sbi->attr_tree) {
398 		if (test_and_clear_bit(HFSPLUS_I_ATTR_DIRTY,
399 				&HFSPLUS_I(HFSPLUS_ATTR_TREE_I(sb))->flags)) {
400 			clear_bit(HFSPLUS_I_ATTR_DIRTY, &hip->flags);
401 			error2 =
402 				filemap_write_and_wait(
403 					    sbi->attr_tree->inode->i_mapping);
404 			if (!error)
405 				error = error2;
406 		}
407 	} else {
408 		if (test_and_clear_bit(HFSPLUS_I_ATTR_DIRTY, &hip->flags))
409 			pr_err("sync non-existent attributes tree\n");
410 	}
411 
412 	if (test_and_clear_bit(HFSPLUS_I_ALLOC_DIRTY,
413 				&HFSPLUS_I(sbi->alloc_file)->flags)) {
414 		clear_bit(HFSPLUS_I_ALLOC_DIRTY, &hip->flags);
415 		error2 = filemap_write_and_wait(sbi->alloc_file->i_mapping);
416 		if (!error)
417 			error = error2;
418 	}
419 
420 	mutex_lock(&sbi->vh_mutex);
421 	hfsplus_prepare_volume_header_for_commit(vhdr);
422 	mutex_unlock(&sbi->vh_mutex);
423 
424 	error2 = hfsplus_commit_superblock(inode->i_sb);
425 	if (!error)
426 		error = error2;
427 
428 	if (!test_bit(HFSPLUS_SB_NOBARRIER, &sbi->flags))
429 		blkdev_issue_flush(inode->i_sb->s_bdev);
430 
431 	inode_unlock(inode);
432 
433 	return error;
434 }
435 
436 static const struct inode_operations hfsplus_file_inode_operations = {
437 	.setattr	= hfsplus_setattr,
438 	.getattr	= hfsplus_getattr,
439 	.listxattr	= hfsplus_listxattr,
440 	.fileattr_get	= hfsplus_fileattr_get,
441 	.fileattr_set	= hfsplus_fileattr_set,
442 };
443 
444 static const struct inode_operations hfsplus_symlink_inode_operations = {
445 	.get_link	= page_get_link,
446 	.setattr	= hfsplus_setattr,
447 	.getattr	= hfsplus_getattr,
448 	.listxattr	= hfsplus_listxattr,
449 };
450 
451 static const struct inode_operations hfsplus_special_inode_operations = {
452 	.setattr	= hfsplus_setattr,
453 	.getattr	= hfsplus_getattr,
454 	.listxattr	= hfsplus_listxattr,
455 };
456 
457 static const struct file_operations hfsplus_file_operations = {
458 	.llseek		= generic_file_llseek,
459 	.read_iter	= generic_file_read_iter,
460 	.write_iter	= generic_file_write_iter,
461 	.mmap_prepare	= generic_file_mmap_prepare,
462 	.splice_read	= filemap_splice_read,
463 	.splice_write	= iter_file_splice_write,
464 	.fsync		= hfsplus_file_fsync,
465 	.open		= hfsplus_file_open,
466 	.release	= hfsplus_file_release,
467 	.unlocked_ioctl = hfsplus_ioctl,
468 };
469 
470 struct inode *hfsplus_new_inode(struct super_block *sb, struct inode *dir,
471 				umode_t mode)
472 {
473 	struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
474 	struct inode *inode = new_inode(sb);
475 	struct hfsplus_inode_info *hip;
476 
477 	if (!inode)
478 		return NULL;
479 
480 	inode->i_ino = sbi->next_cnid++;
481 	inode_init_owner(&nop_mnt_idmap, inode, dir, mode);
482 	set_nlink(inode, 1);
483 	simple_inode_init_ts(inode);
484 
485 	hip = HFSPLUS_I(inode);
486 	mutex_init(&hip->extents_lock);
487 	atomic_set(&hip->opencnt, 0);
488 	hip->extent_state = 0;
489 	hip->flags = 0;
490 	hip->userflags = 0;
491 	hip->subfolders = 0;
492 	memset(hip->first_extents, 0, sizeof(hfsplus_extent_rec));
493 	memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
494 	hip->alloc_blocks = 0;
495 	hip->first_blocks = 0;
496 	hip->cached_start = 0;
497 	hip->cached_blocks = 0;
498 	hip->phys_size = 0;
499 	hip->fs_blocks = 0;
500 	hip->rsrc_inode = NULL;
501 	if (S_ISDIR(inode->i_mode)) {
502 		inode->i_size = 2;
503 		sbi->folder_count++;
504 		inode->i_op = &hfsplus_dir_inode_operations;
505 		inode->i_fop = &hfsplus_dir_operations;
506 	} else if (S_ISREG(inode->i_mode)) {
507 		sbi->file_count++;
508 		inode->i_op = &hfsplus_file_inode_operations;
509 		inode->i_fop = &hfsplus_file_operations;
510 		inode->i_mapping->a_ops = &hfsplus_aops;
511 		hip->clump_blocks = sbi->data_clump_blocks;
512 	} else if (S_ISLNK(inode->i_mode)) {
513 		sbi->file_count++;
514 		inode->i_op = &hfsplus_symlink_inode_operations;
515 		inode_nohighmem(inode);
516 		inode->i_mapping->a_ops = &hfsplus_aops;
517 		hip->clump_blocks = 1;
518 	} else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
519 		   S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
520 		sbi->file_count++;
521 		inode->i_op = &hfsplus_special_inode_operations;
522 	} else
523 		sbi->file_count++;
524 
525 	insert_inode_hash(inode);
526 	mark_inode_dirty(inode);
527 	hfsplus_mark_mdb_dirty(sb);
528 
529 	return inode;
530 }
531 
532 void hfsplus_delete_inode(struct inode *inode)
533 {
534 	struct super_block *sb = inode->i_sb;
535 
536 	if (S_ISDIR(inode->i_mode)) {
537 		HFSPLUS_SB(sb)->folder_count--;
538 		hfsplus_mark_mdb_dirty(sb);
539 		return;
540 	}
541 	HFSPLUS_SB(sb)->file_count--;
542 	if (S_ISREG(inode->i_mode)) {
543 		if (!inode->i_nlink) {
544 			inode->i_size = 0;
545 			hfsplus_file_truncate(inode);
546 		}
547 	} else if (S_ISLNK(inode->i_mode)) {
548 		inode->i_size = 0;
549 		hfsplus_file_truncate(inode);
550 	}
551 	hfsplus_mark_mdb_dirty(sb);
552 }
553 
554 void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
555 {
556 	struct super_block *sb = inode->i_sb;
557 	struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
558 	struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
559 	u32 count;
560 	int i;
561 
562 	memcpy(&hip->first_extents, &fork->extents, sizeof(hfsplus_extent_rec));
563 	for (count = 0, i = 0; i < 8; i++)
564 		count += be32_to_cpu(fork->extents[i].block_count);
565 	hip->first_blocks = count;
566 	memset(hip->cached_extents, 0, sizeof(hfsplus_extent_rec));
567 	hip->cached_start = 0;
568 	hip->cached_blocks = 0;
569 
570 	hip->alloc_blocks = be32_to_cpu(fork->total_blocks);
571 	hip->phys_size = inode->i_size = be64_to_cpu(fork->total_size);
572 	hip->fs_blocks =
573 		(inode->i_size + sb->s_blocksize - 1) >> sb->s_blocksize_bits;
574 	inode_set_bytes(inode, hip->fs_blocks << sb->s_blocksize_bits);
575 	hip->clump_blocks =
576 		be32_to_cpu(fork->clump_size) >> sbi->alloc_blksz_shift;
577 	if (!hip->clump_blocks) {
578 		hip->clump_blocks = HFSPLUS_IS_RSRC(inode) ?
579 			sbi->rsrc_clump_blocks :
580 			sbi->data_clump_blocks;
581 	}
582 }
583 
584 void hfsplus_inode_write_fork(struct inode *inode,
585 		struct hfsplus_fork_raw *fork)
586 {
587 	memcpy(&fork->extents, &HFSPLUS_I(inode)->first_extents,
588 	       sizeof(hfsplus_extent_rec));
589 	fork->total_size = cpu_to_be64(inode->i_size);
590 	fork->total_blocks = cpu_to_be32(HFSPLUS_I(inode)->alloc_blocks);
591 }
592 
593 int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
594 {
595 	hfsplus_cat_entry entry;
596 	int res = 0;
597 	u16 type;
598 
599 	type = hfs_bnode_read_u16(fd->bnode, fd->entryoffset);
600 
601 	HFSPLUS_I(inode)->linkid = 0;
602 	if (type == HFSPLUS_FOLDER) {
603 		struct hfsplus_cat_folder *folder = &entry.folder;
604 
605 		if (fd->entrylength < sizeof(struct hfsplus_cat_folder)) {
606 			pr_err("bad catalog folder entry\n");
607 			res = -EIO;
608 			goto out;
609 		}
610 		hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
611 					sizeof(struct hfsplus_cat_folder));
612 		res = hfsplus_get_perms(inode, &folder->permissions, 1);
613 		if (res)
614 			goto out;
615 		set_nlink(inode, 1);
616 		inode->i_size = 2 + be32_to_cpu(folder->valence);
617 		inode_set_atime_to_ts(inode, hfsp_mt2ut(folder->access_date));
618 		inode_set_mtime_to_ts(inode,
619 				      hfsp_mt2ut(folder->content_mod_date));
620 		inode_set_ctime_to_ts(inode,
621 				      hfsp_mt2ut(folder->attribute_mod_date));
622 		HFSPLUS_I(inode)->create_date = folder->create_date;
623 		HFSPLUS_I(inode)->fs_blocks = 0;
624 		if (folder->flags & cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT)) {
625 			HFSPLUS_I(inode)->subfolders =
626 				be32_to_cpu(folder->subfolders);
627 		}
628 		inode->i_op = &hfsplus_dir_inode_operations;
629 		inode->i_fop = &hfsplus_dir_operations;
630 	} else if (type == HFSPLUS_FILE) {
631 		struct hfsplus_cat_file *file = &entry.file;
632 
633 		if (fd->entrylength < sizeof(struct hfsplus_cat_file)) {
634 			pr_err("bad catalog file entry\n");
635 			res = -EIO;
636 			goto out;
637 		}
638 		hfs_bnode_read(fd->bnode, &entry, fd->entryoffset,
639 					sizeof(struct hfsplus_cat_file));
640 
641 		hfsplus_inode_read_fork(inode, HFSPLUS_IS_RSRC(inode) ?
642 					&file->rsrc_fork : &file->data_fork);
643 		res = hfsplus_get_perms(inode, &file->permissions, 0);
644 		if (res)
645 			goto out;
646 		set_nlink(inode, 1);
647 		if (S_ISREG(inode->i_mode)) {
648 			if (file->permissions.dev)
649 				set_nlink(inode,
650 					  be32_to_cpu(file->permissions.dev));
651 			inode->i_op = &hfsplus_file_inode_operations;
652 			inode->i_fop = &hfsplus_file_operations;
653 			inode->i_mapping->a_ops = &hfsplus_aops;
654 		} else if (S_ISLNK(inode->i_mode)) {
655 			inode->i_op = &hfsplus_symlink_inode_operations;
656 			inode_nohighmem(inode);
657 			inode->i_mapping->a_ops = &hfsplus_aops;
658 		} else {
659 			inode->i_op = &hfsplus_special_inode_operations;
660 			init_special_inode(inode, inode->i_mode,
661 					   be32_to_cpu(file->permissions.dev));
662 		}
663 		inode_set_atime_to_ts(inode, hfsp_mt2ut(file->access_date));
664 		inode_set_mtime_to_ts(inode,
665 				      hfsp_mt2ut(file->content_mod_date));
666 		inode_set_ctime_to_ts(inode,
667 				      hfsp_mt2ut(file->attribute_mod_date));
668 		HFSPLUS_I(inode)->create_date = file->create_date;
669 	} else {
670 		pr_err("bad catalog entry used to create inode\n");
671 		res = -EIO;
672 	}
673 out:
674 	return res;
675 }
676 
677 int hfsplus_cat_write_inode(struct inode *inode)
678 {
679 	struct inode *main_inode = inode;
680 	struct hfs_btree *tree = HFSPLUS_SB(inode->i_sb)->cat_tree;
681 	struct hfs_find_data fd;
682 	hfsplus_cat_entry entry;
683 	int res = 0;
684 
685 	hfs_dbg("inode->i_ino %llu\n", inode->i_ino);
686 
687 	if (HFSPLUS_IS_RSRC(inode))
688 		main_inode = HFSPLUS_I(inode)->rsrc_inode;
689 
690 	if (!main_inode->i_nlink)
691 		return 0;
692 
693 	if (hfs_find_init(tree, &fd))
694 		/* panic? */
695 		return -EIO;
696 
697 	if (hfsplus_find_cat(main_inode->i_sb, main_inode->i_ino, &fd))
698 		/* panic? */
699 		goto out;
700 
701 	if (S_ISDIR(main_inode->i_mode)) {
702 		struct hfsplus_cat_folder *folder = &entry.folder;
703 
704 		if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) {
705 			pr_err("bad catalog folder entry\n");
706 			res = -EIO;
707 			goto out;
708 		}
709 		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
710 					sizeof(struct hfsplus_cat_folder));
711 		/* simple node checks? */
712 		hfsplus_cat_set_perms(inode, &folder->permissions);
713 		folder->access_date = hfsp_ut2mt(inode_get_atime(inode));
714 		folder->content_mod_date = hfsp_ut2mt(inode_get_mtime(inode));
715 		folder->attribute_mod_date = hfsp_ut2mt(inode_get_ctime(inode));
716 		folder->valence = cpu_to_be32(inode->i_size - 2);
717 		if (folder->flags & cpu_to_be16(HFSPLUS_HAS_FOLDER_COUNT)) {
718 			folder->subfolders =
719 				cpu_to_be32(HFSPLUS_I(inode)->subfolders);
720 		}
721 		hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
722 					 sizeof(struct hfsplus_cat_folder));
723 	} else if (HFSPLUS_IS_RSRC(inode)) {
724 		struct hfsplus_cat_file *file = &entry.file;
725 		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
726 			       sizeof(struct hfsplus_cat_file));
727 		hfsplus_inode_write_fork(inode, &file->rsrc_fork);
728 		hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
729 				sizeof(struct hfsplus_cat_file));
730 	} else {
731 		struct hfsplus_cat_file *file = &entry.file;
732 
733 		if (fd.entrylength < sizeof(struct hfsplus_cat_file)) {
734 			pr_err("bad catalog file entry\n");
735 			res = -EIO;
736 			goto out;
737 		}
738 		hfs_bnode_read(fd.bnode, &entry, fd.entryoffset,
739 					sizeof(struct hfsplus_cat_file));
740 		hfsplus_inode_write_fork(inode, &file->data_fork);
741 		hfsplus_cat_set_perms(inode, &file->permissions);
742 		if (HFSPLUS_FLG_IMMUTABLE &
743 				(file->permissions.rootflags |
744 					file->permissions.userflags))
745 			file->flags |= cpu_to_be16(HFSPLUS_FILE_LOCKED);
746 		else
747 			file->flags &= cpu_to_be16(~HFSPLUS_FILE_LOCKED);
748 		file->access_date = hfsp_ut2mt(inode_get_atime(inode));
749 		file->content_mod_date = hfsp_ut2mt(inode_get_mtime(inode));
750 		file->attribute_mod_date = hfsp_ut2mt(inode_get_ctime(inode));
751 		hfs_bnode_write(fd.bnode, &entry, fd.entryoffset,
752 					 sizeof(struct hfsplus_cat_file));
753 	}
754 
755 	res = hfs_btree_write(tree);
756 	if (res) {
757 		pr_err("b-tree write err: %d, ino %llu\n",
758 		       res, inode->i_ino);
759 		goto out;
760 	}
761 
762 	set_bit(HFSPLUS_I_CAT_DIRTY,
763 		&HFSPLUS_I(HFSPLUS_CAT_TREE_I(inode->i_sb))->flags);
764 	set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags);
765 out:
766 	hfs_find_exit(&fd);
767 
768 	return res;
769 }
770 
771 int hfsplus_fileattr_get(struct dentry *dentry, struct file_kattr *fa)
772 {
773 	struct inode *inode = d_inode(dentry);
774 	struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
775 	struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
776 	unsigned int flags = 0;
777 
778 	if (inode->i_flags & S_IMMUTABLE)
779 		flags |= FS_IMMUTABLE_FL;
780 	if (inode->i_flags & S_APPEND)
781 		flags |= FS_APPEND_FL;
782 	if (hip->userflags & HFSPLUS_FLG_NODUMP)
783 		flags |= FS_NODUMP_FL;
784 	if (test_bit(HFSPLUS_SB_CASEFOLD, &sbi->flags))
785 		flags |= FS_CASEFOLD_FL;
786 
787 	fileattr_fill_flags(fa, flags);
788 
789 	return 0;
790 }
791 
792 int hfsplus_fileattr_set(struct mnt_idmap *idmap,
793 			 struct dentry *dentry, struct file_kattr *fa)
794 {
795 	struct inode *inode = d_inode(dentry);
796 	struct hfsplus_inode_info *hip = HFSPLUS_I(inode);
797 	struct hfsplus_sb_info *sbi = HFSPLUS_SB(inode->i_sb);
798 	unsigned int allowed = FS_IMMUTABLE_FL | FS_APPEND_FL | FS_NODUMP_FL;
799 	unsigned int new_fl = 0;
800 
801 	if (fileattr_has_fsx(fa))
802 		return -EOPNOTSUPP;
803 
804 	/*
805 	 * FS_CASEFOLD_FL reflects HFSPLUS_SB_CASEFOLD, a mount-time
806 	 * property. Accept it as a no-op so chattr's RMW round-trip
807 	 * succeeds; reject any attempt to enable it on a volume that
808 	 * was not formatted case-insensitive.
809 	 */
810 	if (test_bit(HFSPLUS_SB_CASEFOLD, &sbi->flags))
811 		allowed |= FS_CASEFOLD_FL;
812 
813 	/* don't silently ignore unsupported ext2 flags */
814 	if (fa->flags & ~allowed)
815 		return -EOPNOTSUPP;
816 
817 	if (fa->flags & FS_IMMUTABLE_FL)
818 		new_fl |= S_IMMUTABLE;
819 
820 	if (fa->flags & FS_APPEND_FL)
821 		new_fl |= S_APPEND;
822 
823 	inode_set_flags(inode, new_fl, S_IMMUTABLE | S_APPEND);
824 
825 	if (fa->flags & FS_NODUMP_FL)
826 		hip->userflags |= HFSPLUS_FLG_NODUMP;
827 	else
828 		hip->userflags &= ~HFSPLUS_FLG_NODUMP;
829 
830 	inode_set_ctime_current(inode);
831 	mark_inode_dirty(inode);
832 
833 	return 0;
834 }
835