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