^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * linux/fs/hfsplus/attributes.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Vyacheslav Dubeyko <slava@dubeyko.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * Handling of records in attributes tree
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include "hfsplus_fs.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "hfsplus_raw.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) static struct kmem_cache *hfsplus_attr_tree_cachep;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) int __init hfsplus_create_attr_tree_cache(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) if (hfsplus_attr_tree_cachep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) return -EEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) hfsplus_attr_tree_cachep =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) kmem_cache_create("hfsplus_attr_cache",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) sizeof(hfsplus_attr_entry), 0,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) SLAB_HWCACHE_ALIGN, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) if (!hfsplus_attr_tree_cachep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) void hfsplus_destroy_attr_tree_cache(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) kmem_cache_destroy(hfsplus_attr_tree_cachep);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) int hfsplus_attr_bin_cmp_key(const hfsplus_btree_key *k1,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) const hfsplus_btree_key *k2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) __be32 k1_cnid, k2_cnid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) k1_cnid = k1->attr.cnid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) k2_cnid = k2->attr.cnid;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) if (k1_cnid != k2_cnid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) return be32_to_cpu(k1_cnid) < be32_to_cpu(k2_cnid) ? -1 : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) return hfsplus_strcmp(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) (const struct hfsplus_unistr *)&k1->attr.key_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) (const struct hfsplus_unistr *)&k2->attr.key_name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) int hfsplus_attr_build_key(struct super_block *sb, hfsplus_btree_key *key,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) u32 cnid, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) memset(key, 0, sizeof(struct hfsplus_attr_key));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) key->attr.cnid = cpu_to_be32(cnid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) int res = hfsplus_asc2uni(sb,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) (struct hfsplus_unistr *)&key->attr.key_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) HFSPLUS_ATTR_MAX_STRLEN, name, strlen(name));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) if (res)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) return res;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) len = be16_to_cpu(key->attr.key_name.length);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) key->attr.key_name.length = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) len = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) /* The length of the key, as stored in key_len field, does not include
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * the size of the key_len field itself.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) * So, offsetof(hfsplus_attr_key, key_name) is a trick because
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * it takes into consideration key_len field (__be16) of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * hfsplus_attr_key structure instead of length field (__be16) of
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) * hfsplus_attr_unistr structure.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) key->key_len =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) cpu_to_be16(offsetof(struct hfsplus_attr_key, key_name) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) 2 * len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) hfsplus_attr_entry *hfsplus_alloc_attr_entry(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return kmem_cache_alloc(hfsplus_attr_tree_cachep, GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) void hfsplus_destroy_attr_entry(hfsplus_attr_entry *entry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) if (entry)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) kmem_cache_free(hfsplus_attr_tree_cachep, entry);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) #define HFSPLUS_INVALID_ATTR_RECORD -1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static int hfsplus_attr_build_record(hfsplus_attr_entry *entry, int record_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) u32 cnid, const void *value, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (record_type == HFSPLUS_ATTR_FORK_DATA) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) * Mac OS X supports only inline data attributes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) * Do nothing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) memset(entry, 0, sizeof(*entry));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) return sizeof(struct hfsplus_attr_fork_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) } else if (record_type == HFSPLUS_ATTR_EXTENTS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * Mac OS X supports only inline data attributes.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) * Do nothing.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) memset(entry, 0, sizeof(*entry));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) return sizeof(struct hfsplus_attr_extents);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) } else if (record_type == HFSPLUS_ATTR_INLINE_DATA) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) u16 len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) memset(entry, 0, sizeof(struct hfsplus_attr_inline_data));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) entry->inline_data.record_type = cpu_to_be32(record_type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) if (size <= HFSPLUS_MAX_INLINE_DATA_SIZE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) len = size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) return HFSPLUS_INVALID_ATTR_RECORD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) entry->inline_data.length = cpu_to_be16(len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) memcpy(entry->inline_data.raw_bytes, value, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) * Align len on two-byte boundary.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) * It needs to add pad byte if we have odd len.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) len = round_up(len, 2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) return offsetof(struct hfsplus_attr_inline_data, raw_bytes) +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) } else /* invalid input */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) memset(entry, 0, sizeof(*entry));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) return HFSPLUS_INVALID_ATTR_RECORD;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) int hfsplus_find_attr(struct super_block *sb, u32 cnid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) const char *name, struct hfs_find_data *fd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) hfs_dbg(ATTR_MOD, "find_attr: %s,%d\n", name ? name : NULL, cnid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) if (!HFSPLUS_SB(sb)->attr_tree) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) pr_err("attributes file doesn't exist\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) if (name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) err = hfsplus_attr_build_key(sb, fd->search_key, cnid, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) goto failed_find_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) err = hfs_brec_find(fd, hfs_find_rec_by_key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) goto failed_find_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) err = hfsplus_attr_build_key(sb, fd->search_key, cnid, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) goto failed_find_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) err = hfs_brec_find(fd, hfs_find_1st_rec_by_cnid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) goto failed_find_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) failed_find_attr:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) int hfsplus_attr_exists(struct inode *inode, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) struct super_block *sb = inode->i_sb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) struct hfs_find_data fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) if (!HFSPLUS_SB(sb)->attr_tree)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) err = hfs_find_init(HFSPLUS_SB(sb)->attr_tree, &fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) err = hfsplus_find_attr(sb, inode->i_ino, name, &fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) goto attr_not_found;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) hfs_find_exit(&fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) attr_not_found:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) hfs_find_exit(&fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) int hfsplus_create_attr(struct inode *inode,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) const char *name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) const void *value, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) struct super_block *sb = inode->i_sb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) struct hfs_find_data fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) hfsplus_attr_entry *entry_ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) int entry_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) int err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) hfs_dbg(ATTR_MOD, "create_attr: %s,%ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) name ? name : NULL, inode->i_ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) if (!HFSPLUS_SB(sb)->attr_tree) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) pr_err("attributes file doesn't exist\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) entry_ptr = hfsplus_alloc_attr_entry();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) if (!entry_ptr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) err = hfs_find_init(HFSPLUS_SB(sb)->attr_tree, &fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) goto failed_init_create_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) /* Fail early and avoid ENOSPC during the btree operation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) err = hfs_bmap_reserve(fd.tree, fd.tree->depth + 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) goto failed_create_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) if (name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) err = hfsplus_attr_build_key(sb, fd.search_key,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) inode->i_ino, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) goto failed_create_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) goto failed_create_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) /* Mac OS X supports only inline data attributes. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) entry_size = hfsplus_attr_build_record(entry_ptr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) HFSPLUS_ATTR_INLINE_DATA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) inode->i_ino,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) value, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) if (entry_size == HFSPLUS_INVALID_ATTR_RECORD) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) goto failed_create_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) err = hfs_brec_find(&fd, hfs_find_rec_by_key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) if (err != -ENOENT) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) if (!err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) err = -EEXIST;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) goto failed_create_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) err = hfs_brec_insert(&fd, entry_ptr, entry_size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) goto failed_create_attr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ATTR_DIRTY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) failed_create_attr:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) hfs_find_exit(&fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) failed_init_create_attr:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) hfsplus_destroy_attr_entry(entry_ptr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) static int __hfsplus_delete_attr(struct inode *inode, u32 cnid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) struct hfs_find_data *fd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) __be32 found_cnid, record_type;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) hfs_bnode_read(fd->bnode, &found_cnid,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) fd->keyoffset +
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) offsetof(struct hfsplus_attr_key, cnid),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) sizeof(__be32));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) if (cnid != be32_to_cpu(found_cnid))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) hfs_bnode_read(fd->bnode, &record_type,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) fd->entryoffset, sizeof(record_type));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) switch (be32_to_cpu(record_type)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) case HFSPLUS_ATTR_INLINE_DATA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) /* All is OK. Do nothing. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) case HFSPLUS_ATTR_FORK_DATA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) case HFSPLUS_ATTR_EXTENTS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) pr_err("only inline data xattr are supported\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) return -EOPNOTSUPP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) pr_err("invalid extended attribute record\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) return -ENOENT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) /* Avoid btree corruption */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) hfs_bnode_read(fd->bnode, fd->search_key,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) fd->keyoffset, fd->keylength);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) err = hfs_brec_remove(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ATTR_DIRTY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) int hfsplus_delete_attr(struct inode *inode, const char *name)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) struct super_block *sb = inode->i_sb;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) struct hfs_find_data fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) hfs_dbg(ATTR_MOD, "delete_attr: %s,%ld\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) name ? name : NULL, inode->i_ino);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) if (!HFSPLUS_SB(sb)->attr_tree) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) pr_err("attributes file doesn't exist\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) err = hfs_find_init(HFSPLUS_SB(sb)->attr_tree, &fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) /* Fail early and avoid ENOSPC during the btree operation */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) err = hfs_bmap_reserve(fd.tree, fd.tree->depth);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) if (name) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) err = hfsplus_attr_build_key(sb, fd.search_key,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) inode->i_ino, name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) pr_err("invalid extended attribute name\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) err = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) err = hfs_brec_find(&fd, hfs_find_rec_by_key);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) err = __hfsplus_delete_attr(inode, inode->i_ino, &fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) hfs_find_exit(&fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) int hfsplus_delete_all_attrs(struct inode *dir, u32 cnid)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) int err = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) struct hfs_find_data fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) hfs_dbg(ATTR_MOD, "delete_all_attrs: %d\n", cnid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) if (!HFSPLUS_SB(dir->i_sb)->attr_tree) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) pr_err("attributes file doesn't exist\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) err = hfs_find_init(HFSPLUS_SB(dir->i_sb)->attr_tree, &fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) for (;;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) err = hfsplus_find_attr(dir->i_sb, cnid, NULL, &fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) if (err) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) if (err != -ENOENT)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) pr_err("xattr search failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) goto end_delete_all;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) err = __hfsplus_delete_attr(dir, cnid, &fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) if (err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380) goto end_delete_all;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) end_delete_all:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) hfs_find_exit(&fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385) return err;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) }