mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 01:04:41 +01:00
hfs/hfsplus updates for v7.0
- hfsplus: avoid double unload_nls() on mount failure
- hfsplus: fix warning issue in inode.c
- hfsplus: fix generic/062 xfstests failure
- hfsplus: fix generic/037 xfstests failure
- hfsplus: pretend special inodes as regular files
- hfsplus: return error when node already exists in hfs_bnode_create
- hfs: Replace BUG_ON with error handling for CNID count checks
- hfsplus: fix generic/020 xfstests failure
- hfsplus: fix volume corruption issue for generic/498
- hfsplus: fix volume corruption issue for generic/480
- hfsplus: ensure sb->s_fs_info is always cleaned up
- hfs: ensure sb->s_fs_info is always cleaned up
-----BEGIN PGP SIGNATURE-----
iHUEABYIAB0WIQT4wVoLCG92poNnMFAhI4xTh21NnQUCaYaAugAKCRAhI4xTh21N
nXLKAQCk3CLWz75YXHxkK1jJDqHC9iaVbjxd3I5Y0zI7KGVSoQEAmpw0oupfVpNp
fgASBHE6fBvMJq2shv41na7S6cjMUQk=
=wERj
-----END PGP SIGNATURE-----
Merge tag 'hfs-v7.0-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs
Pull hfs/hfsplus updates from Viacheslav Dubeyko:
"This pull request contains several fixes of syzbot reported issues and
HFS+ fixes of xfstests failures.
- fix an issue reported by syzbot triggering BUG_ON() in the case of
corrupted superblock, replacing the BUG_ON()s with proper error
handling (Jori Koolstra)
- fix memory leaks in the mount logic of HFS/HFS+ file systems. When
HFS/HFS+ were converted to the new mount api a bug was introduced
by changing the allocation pattern of sb->s_fs_info (Mehdi Ben Hadj
Khelifa)
- fix hfs_bnode_create() by returning ERR_PTR(-EEXIST) instead of
the node pointer when it's already hashed. This avoids a double
unload_nls() on mount failure (suggested by Shardul Bankar)
- set inode's mode as regular file for system inodes (Tetsuo Handa)
The rest fix failures in generic/020, generic/037, generic/062,
generic/480, and generic/498 xfstests for the case of HFS+ file
system. Currently, only 30 xfstests' test-cases experience failures
for HFS+ file system (initially, it was around 100 failed xfstests)"
* tag 'hfs-v7.0-tag1' of git://git.kernel.org/pub/scm/linux/kernel/git/vdubeyko/hfs:
hfsplus: avoid double unload_nls() on mount failure
hfsplus: fix warning issue in inode.c
hfsplus: fix generic/062 xfstests failure
hfsplus: fix generic/037 xfstests failure
hfsplus: pretend special inodes as regular files
hfsplus: return error when node already exists in hfs_bnode_create
hfs: Replace BUG_ON with error handling for CNID count checks
hfsplus: fix generic/020 xfstests failure
hfsplus: fix volume corruption issue for generic/498
hfsplus: fix volume corruption issue for generic/480
hfsplus: ensure sb->s_fs_info is always cleaned up
hfs: ensure sb->s_fs_info is always cleaned up
This commit is contained in:
commit
4fb7d86fbe
12 changed files with 407 additions and 122 deletions
15
fs/hfs/dir.c
15
fs/hfs/dir.c
|
|
@ -196,8 +196,8 @@ static int hfs_create(struct mnt_idmap *idmap, struct inode *dir,
|
|||
int res;
|
||||
|
||||
inode = hfs_new_inode(dir, &dentry->d_name, mode);
|
||||
if (!inode)
|
||||
return -ENOMEM;
|
||||
if (IS_ERR(inode))
|
||||
return PTR_ERR(inode);
|
||||
|
||||
res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode);
|
||||
if (res) {
|
||||
|
|
@ -226,8 +226,8 @@ static struct dentry *hfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
|
|||
int res;
|
||||
|
||||
inode = hfs_new_inode(dir, &dentry->d_name, S_IFDIR | mode);
|
||||
if (!inode)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (IS_ERR(inode))
|
||||
return ERR_CAST(inode);
|
||||
|
||||
res = hfs_cat_create(inode->i_ino, dir, &dentry->d_name, inode);
|
||||
if (res) {
|
||||
|
|
@ -254,11 +254,18 @@ static struct dentry *hfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
|
|||
*/
|
||||
static int hfs_remove(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct inode *inode = d_inode(dentry);
|
||||
int res;
|
||||
|
||||
if (S_ISDIR(inode->i_mode) && inode->i_size != 2)
|
||||
return -ENOTEMPTY;
|
||||
|
||||
if (unlikely(!is_hfs_cnid_counts_valid(sb))) {
|
||||
pr_err("cannot remove file/folder\n");
|
||||
return -ERANGE;
|
||||
}
|
||||
|
||||
res = hfs_cat_delete(inode->i_ino, dir, &dentry->d_name);
|
||||
if (res)
|
||||
return res;
|
||||
|
|
|
|||
|
|
@ -199,6 +199,7 @@ extern void hfs_delete_inode(struct inode *inode);
|
|||
extern const struct xattr_handler * const hfs_xattr_handlers[];
|
||||
|
||||
/* mdb.c */
|
||||
extern bool is_hfs_cnid_counts_valid(struct super_block *sb);
|
||||
extern int hfs_mdb_get(struct super_block *sb);
|
||||
extern void hfs_mdb_commit(struct super_block *sb);
|
||||
extern void hfs_mdb_close(struct super_block *sb);
|
||||
|
|
|
|||
|
|
@ -187,16 +187,23 @@ struct inode *hfs_new_inode(struct inode *dir, const struct qstr *name, umode_t
|
|||
s64 next_id;
|
||||
s64 file_count;
|
||||
s64 folder_count;
|
||||
int err = -ENOMEM;
|
||||
|
||||
if (!inode)
|
||||
return NULL;
|
||||
goto out_err;
|
||||
|
||||
err = -ERANGE;
|
||||
|
||||
mutex_init(&HFS_I(inode)->extents_lock);
|
||||
INIT_LIST_HEAD(&HFS_I(inode)->open_dir_list);
|
||||
spin_lock_init(&HFS_I(inode)->open_dir_lock);
|
||||
hfs_cat_build_key(sb, (btree_key *)&HFS_I(inode)->cat_key, dir->i_ino, name);
|
||||
next_id = atomic64_inc_return(&HFS_SB(sb)->next_id);
|
||||
BUG_ON(next_id > U32_MAX);
|
||||
if (next_id > U32_MAX) {
|
||||
atomic64_dec(&HFS_SB(sb)->next_id);
|
||||
pr_err("cannot create new inode: next CNID exceeds limit\n");
|
||||
goto out_discard;
|
||||
}
|
||||
inode->i_ino = (u32)next_id;
|
||||
inode->i_mode = mode;
|
||||
inode->i_uid = current_fsuid();
|
||||
|
|
@ -210,7 +217,11 @@ struct inode *hfs_new_inode(struct inode *dir, const struct qstr *name, umode_t
|
|||
if (S_ISDIR(mode)) {
|
||||
inode->i_size = 2;
|
||||
folder_count = atomic64_inc_return(&HFS_SB(sb)->folder_count);
|
||||
BUG_ON(folder_count > U32_MAX);
|
||||
if (folder_count> U32_MAX) {
|
||||
atomic64_dec(&HFS_SB(sb)->folder_count);
|
||||
pr_err("cannot create new inode: folder count exceeds limit\n");
|
||||
goto out_discard;
|
||||
}
|
||||
if (dir->i_ino == HFS_ROOT_CNID)
|
||||
HFS_SB(sb)->root_dirs++;
|
||||
inode->i_op = &hfs_dir_inode_operations;
|
||||
|
|
@ -220,7 +231,11 @@ struct inode *hfs_new_inode(struct inode *dir, const struct qstr *name, umode_t
|
|||
} else if (S_ISREG(mode)) {
|
||||
HFS_I(inode)->clump_blocks = HFS_SB(sb)->clumpablks;
|
||||
file_count = atomic64_inc_return(&HFS_SB(sb)->file_count);
|
||||
BUG_ON(file_count > U32_MAX);
|
||||
if (file_count > U32_MAX) {
|
||||
atomic64_dec(&HFS_SB(sb)->file_count);
|
||||
pr_err("cannot create new inode: file count exceeds limit\n");
|
||||
goto out_discard;
|
||||
}
|
||||
if (dir->i_ino == HFS_ROOT_CNID)
|
||||
HFS_SB(sb)->root_files++;
|
||||
inode->i_op = &hfs_file_inode_operations;
|
||||
|
|
@ -244,6 +259,11 @@ struct inode *hfs_new_inode(struct inode *dir, const struct qstr *name, umode_t
|
|||
hfs_mark_mdb_dirty(sb);
|
||||
|
||||
return inode;
|
||||
|
||||
out_discard:
|
||||
iput(inode);
|
||||
out_err:
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
|
||||
void hfs_delete_inode(struct inode *inode)
|
||||
|
|
@ -252,7 +272,6 @@ void hfs_delete_inode(struct inode *inode)
|
|||
|
||||
hfs_dbg("ino %lu\n", inode->i_ino);
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
BUG_ON(atomic64_read(&HFS_SB(sb)->folder_count) > U32_MAX);
|
||||
atomic64_dec(&HFS_SB(sb)->folder_count);
|
||||
if (HFS_I(inode)->cat_key.ParID == cpu_to_be32(HFS_ROOT_CNID))
|
||||
HFS_SB(sb)->root_dirs--;
|
||||
|
|
@ -261,7 +280,6 @@ void hfs_delete_inode(struct inode *inode)
|
|||
return;
|
||||
}
|
||||
|
||||
BUG_ON(atomic64_read(&HFS_SB(sb)->file_count) > U32_MAX);
|
||||
atomic64_dec(&HFS_SB(sb)->file_count);
|
||||
if (HFS_I(inode)->cat_key.ParID == cpu_to_be32(HFS_ROOT_CNID))
|
||||
HFS_SB(sb)->root_files--;
|
||||
|
|
|
|||
66
fs/hfs/mdb.c
66
fs/hfs/mdb.c
|
|
@ -64,6 +64,27 @@ static int hfs_get_last_session(struct super_block *sb,
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool is_hfs_cnid_counts_valid(struct super_block *sb)
|
||||
{
|
||||
struct hfs_sb_info *sbi = HFS_SB(sb);
|
||||
bool corrupted = false;
|
||||
|
||||
if (unlikely(atomic64_read(&sbi->next_id) > U32_MAX)) {
|
||||
pr_warn("next CNID exceeds limit\n");
|
||||
corrupted = true;
|
||||
}
|
||||
if (unlikely(atomic64_read(&sbi->file_count) > U32_MAX)) {
|
||||
pr_warn("file count exceeds limit\n");
|
||||
corrupted = true;
|
||||
}
|
||||
if (unlikely(atomic64_read(&sbi->folder_count) > U32_MAX)) {
|
||||
pr_warn("folder count exceeds limit\n");
|
||||
corrupted = true;
|
||||
}
|
||||
|
||||
return !corrupted;
|
||||
}
|
||||
|
||||
/*
|
||||
* hfs_mdb_get()
|
||||
*
|
||||
|
|
@ -92,7 +113,7 @@ int hfs_mdb_get(struct super_block *sb)
|
|||
/* See if this is an HFS filesystem */
|
||||
bh = sb_bread512(sb, part_start + HFS_MDB_BLK, mdb);
|
||||
if (!bh)
|
||||
goto out;
|
||||
return -EIO;
|
||||
|
||||
if (mdb->drSigWord == cpu_to_be16(HFS_SUPER_MAGIC))
|
||||
break;
|
||||
|
|
@ -102,13 +123,14 @@ int hfs_mdb_get(struct super_block *sb)
|
|||
* (should do this only for cdrom/loop though)
|
||||
*/
|
||||
if (hfs_part_find(sb, &part_start, &part_size))
|
||||
goto out;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
HFS_SB(sb)->alloc_blksz = size = be32_to_cpu(mdb->drAlBlkSiz);
|
||||
if (!size || (size & (HFS_SECTOR_SIZE - 1))) {
|
||||
pr_err("bad allocation block size %d\n", size);
|
||||
goto out_bh;
|
||||
brelse(bh);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
size = min(HFS_SB(sb)->alloc_blksz, (u32)PAGE_SIZE);
|
||||
|
|
@ -125,14 +147,16 @@ int hfs_mdb_get(struct super_block *sb)
|
|||
brelse(bh);
|
||||
if (!sb_set_blocksize(sb, size)) {
|
||||
pr_err("unable to set blocksize to %u\n", size);
|
||||
goto out;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
bh = sb_bread512(sb, part_start + HFS_MDB_BLK, mdb);
|
||||
if (!bh)
|
||||
goto out;
|
||||
if (mdb->drSigWord != cpu_to_be16(HFS_SUPER_MAGIC))
|
||||
goto out_bh;
|
||||
return -EIO;
|
||||
if (mdb->drSigWord != cpu_to_be16(HFS_SUPER_MAGIC)) {
|
||||
brelse(bh);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
HFS_SB(sb)->mdb_bh = bh;
|
||||
HFS_SB(sb)->mdb = mdb;
|
||||
|
|
@ -156,6 +180,11 @@ int hfs_mdb_get(struct super_block *sb)
|
|||
atomic64_set(&HFS_SB(sb)->file_count, be32_to_cpu(mdb->drFilCnt));
|
||||
atomic64_set(&HFS_SB(sb)->folder_count, be32_to_cpu(mdb->drDirCnt));
|
||||
|
||||
if (!is_hfs_cnid_counts_valid(sb)) {
|
||||
pr_warn("filesystem possibly corrupted, running fsck.hfs is recommended. Mounting read-only.\n");
|
||||
sb->s_flags |= SB_RDONLY;
|
||||
}
|
||||
|
||||
/* TRY to get the alternate (backup) MDB. */
|
||||
sect = part_start + part_size - 2;
|
||||
bh = sb_bread512(sb, sect, mdb2);
|
||||
|
|
@ -174,7 +203,7 @@ int hfs_mdb_get(struct super_block *sb)
|
|||
|
||||
HFS_SB(sb)->bitmap = kzalloc(8192, GFP_KERNEL);
|
||||
if (!HFS_SB(sb)->bitmap)
|
||||
goto out;
|
||||
return -EIO;
|
||||
|
||||
/* read in the bitmap */
|
||||
block = be16_to_cpu(mdb->drVBMSt) + part_start;
|
||||
|
|
@ -185,7 +214,7 @@ int hfs_mdb_get(struct super_block *sb)
|
|||
bh = sb_bread(sb, off >> sb->s_blocksize_bits);
|
||||
if (!bh) {
|
||||
pr_err("unable to read volume bitmap\n");
|
||||
goto out;
|
||||
return -EIO;
|
||||
}
|
||||
off2 = off & (sb->s_blocksize - 1);
|
||||
len = min((int)sb->s_blocksize - off2, size);
|
||||
|
|
@ -199,17 +228,17 @@ int hfs_mdb_get(struct super_block *sb)
|
|||
HFS_SB(sb)->ext_tree = hfs_btree_open(sb, HFS_EXT_CNID, hfs_ext_keycmp);
|
||||
if (!HFS_SB(sb)->ext_tree) {
|
||||
pr_err("unable to open extent tree\n");
|
||||
goto out;
|
||||
return -EIO;
|
||||
}
|
||||
HFS_SB(sb)->cat_tree = hfs_btree_open(sb, HFS_CAT_CNID, hfs_cat_keycmp);
|
||||
if (!HFS_SB(sb)->cat_tree) {
|
||||
pr_err("unable to open catalog tree\n");
|
||||
goto out;
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
attrib = mdb->drAtrb;
|
||||
if (!(attrib & cpu_to_be16(HFS_SB_ATTRIB_UNMNT))) {
|
||||
pr_warn("filesystem was not cleanly unmounted, running fsck.hfs is recommended. mounting read-only.\n");
|
||||
pr_warn("filesystem was not cleanly unmounted, running fsck.hfs is recommended. Mounting read-only.\n");
|
||||
sb->s_flags |= SB_RDONLY;
|
||||
}
|
||||
if ((attrib & cpu_to_be16(HFS_SB_ATTRIB_SLOCK))) {
|
||||
|
|
@ -229,12 +258,6 @@ int hfs_mdb_get(struct super_block *sb)
|
|||
}
|
||||
|
||||
return 0;
|
||||
|
||||
out_bh:
|
||||
brelse(bh);
|
||||
out:
|
||||
hfs_mdb_put(sb);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -273,15 +296,12 @@ void hfs_mdb_commit(struct super_block *sb)
|
|||
/* These parameters may have been modified, so write them back */
|
||||
mdb->drLsMod = hfs_mtime();
|
||||
mdb->drFreeBks = cpu_to_be16(HFS_SB(sb)->free_ablocks);
|
||||
BUG_ON(atomic64_read(&HFS_SB(sb)->next_id) > U32_MAX);
|
||||
mdb->drNxtCNID =
|
||||
cpu_to_be32((u32)atomic64_read(&HFS_SB(sb)->next_id));
|
||||
mdb->drNmFls = cpu_to_be16(HFS_SB(sb)->root_files);
|
||||
mdb->drNmRtDirs = cpu_to_be16(HFS_SB(sb)->root_dirs);
|
||||
BUG_ON(atomic64_read(&HFS_SB(sb)->file_count) > U32_MAX);
|
||||
mdb->drFilCnt =
|
||||
cpu_to_be32((u32)atomic64_read(&HFS_SB(sb)->file_count));
|
||||
BUG_ON(atomic64_read(&HFS_SB(sb)->folder_count) > U32_MAX);
|
||||
mdb->drDirCnt =
|
||||
cpu_to_be32((u32)atomic64_read(&HFS_SB(sb)->folder_count));
|
||||
|
||||
|
|
@ -359,8 +379,6 @@ void hfs_mdb_close(struct super_block *sb)
|
|||
* Release the resources associated with the in-core MDB. */
|
||||
void hfs_mdb_put(struct super_block *sb)
|
||||
{
|
||||
if (!HFS_SB(sb))
|
||||
return;
|
||||
/* free the B-trees */
|
||||
hfs_btree_close(HFS_SB(sb)->ext_tree);
|
||||
hfs_btree_close(HFS_SB(sb)->cat_tree);
|
||||
|
|
@ -373,6 +391,4 @@ void hfs_mdb_put(struct super_block *sb)
|
|||
unload_nls(HFS_SB(sb)->nls_disk);
|
||||
|
||||
kfree(HFS_SB(sb)->bitmap);
|
||||
kfree(HFS_SB(sb));
|
||||
sb->s_fs_info = NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ MODULE_LICENSE("GPL");
|
|||
|
||||
static int hfs_sync_fs(struct super_block *sb, int wait)
|
||||
{
|
||||
is_hfs_cnid_counts_valid(sb);
|
||||
hfs_mdb_commit(sb);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -65,6 +66,8 @@ static void flush_mdb(struct work_struct *work)
|
|||
sbi->work_queued = 0;
|
||||
spin_unlock(&sbi->work_lock);
|
||||
|
||||
is_hfs_cnid_counts_valid(sb);
|
||||
|
||||
hfs_mdb_commit(sb);
|
||||
}
|
||||
|
||||
|
|
@ -431,10 +434,18 @@ static int hfs_init_fs_context(struct fs_context *fc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void hfs_kill_super(struct super_block *sb)
|
||||
{
|
||||
struct hfs_sb_info *hsb = HFS_SB(sb);
|
||||
|
||||
kill_block_super(sb);
|
||||
kfree(hsb);
|
||||
}
|
||||
|
||||
static struct file_system_type hfs_fs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "hfs",
|
||||
.kill_sb = kill_block_super,
|
||||
.kill_sb = hfs_kill_super,
|
||||
.fs_flags = FS_REQUIRES_DEV,
|
||||
.init_fs_context = hfs_init_fs_context,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -117,8 +117,10 @@ static int hfsplus_attr_build_record(hfsplus_attr_entry *entry, int record_type,
|
|||
entry->inline_data.record_type = cpu_to_be32(record_type);
|
||||
if (size <= HFSPLUS_MAX_INLINE_DATA_SIZE)
|
||||
len = size;
|
||||
else
|
||||
else {
|
||||
hfs_dbg("value size %zu is too big\n", size);
|
||||
return HFSPLUS_INVALID_ATTR_RECORD;
|
||||
}
|
||||
entry->inline_data.length = cpu_to_be16(len);
|
||||
memcpy(entry->inline_data.raw_bytes, value, len);
|
||||
/*
|
||||
|
|
@ -191,14 +193,66 @@ attr_not_found:
|
|||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
int hfsplus_create_attr_nolock(struct inode *inode, const char *name,
|
||||
const void *value, size_t size,
|
||||
struct hfs_find_data *fd,
|
||||
hfsplus_attr_entry *entry_ptr)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
int entry_size;
|
||||
int err;
|
||||
|
||||
hfs_dbg("name %s, ino %ld\n",
|
||||
name ? name : NULL, inode->i_ino);
|
||||
|
||||
if (name) {
|
||||
err = hfsplus_attr_build_key(sb, fd->search_key,
|
||||
inode->i_ino, name);
|
||||
if (err)
|
||||
return err;
|
||||
} else
|
||||
return -EINVAL;
|
||||
|
||||
/* Mac OS X supports only inline data attributes. */
|
||||
entry_size = hfsplus_attr_build_record(entry_ptr,
|
||||
HFSPLUS_ATTR_INLINE_DATA,
|
||||
inode->i_ino,
|
||||
value, size);
|
||||
if (entry_size == HFSPLUS_INVALID_ATTR_RECORD) {
|
||||
if (size > HFSPLUS_MAX_INLINE_DATA_SIZE)
|
||||
err = -E2BIG;
|
||||
else
|
||||
err = -EINVAL;
|
||||
hfs_dbg("unable to store value: err %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = hfs_brec_find(fd, hfs_find_rec_by_key);
|
||||
if (err != -ENOENT) {
|
||||
if (!err)
|
||||
err = -EEXIST;
|
||||
return err;
|
||||
}
|
||||
|
||||
err = hfs_brec_insert(fd, entry_ptr, entry_size);
|
||||
if (err) {
|
||||
hfs_dbg("unable to store value: err %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ATTR_DIRTY);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hfsplus_create_attr(struct inode *inode,
|
||||
const char *name,
|
||||
const void *value, size_t size)
|
||||
const char *name,
|
||||
const void *value, size_t size)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct hfs_find_data fd;
|
||||
hfsplus_attr_entry *entry_ptr;
|
||||
int entry_size;
|
||||
int err;
|
||||
|
||||
hfs_dbg("name %s, ino %ld\n",
|
||||
|
|
@ -222,39 +276,11 @@ int hfsplus_create_attr(struct inode *inode,
|
|||
if (err)
|
||||
goto failed_create_attr;
|
||||
|
||||
if (name) {
|
||||
err = hfsplus_attr_build_key(sb, fd.search_key,
|
||||
inode->i_ino, name);
|
||||
if (err)
|
||||
goto failed_create_attr;
|
||||
} else {
|
||||
err = -EINVAL;
|
||||
goto failed_create_attr;
|
||||
}
|
||||
|
||||
/* Mac OS X supports only inline data attributes. */
|
||||
entry_size = hfsplus_attr_build_record(entry_ptr,
|
||||
HFSPLUS_ATTR_INLINE_DATA,
|
||||
inode->i_ino,
|
||||
value, size);
|
||||
if (entry_size == HFSPLUS_INVALID_ATTR_RECORD) {
|
||||
err = -EINVAL;
|
||||
goto failed_create_attr;
|
||||
}
|
||||
|
||||
err = hfs_brec_find(&fd, hfs_find_rec_by_key);
|
||||
if (err != -ENOENT) {
|
||||
if (!err)
|
||||
err = -EEXIST;
|
||||
goto failed_create_attr;
|
||||
}
|
||||
|
||||
err = hfs_brec_insert(&fd, entry_ptr, entry_size);
|
||||
err = hfsplus_create_attr_nolock(inode, name, value, size,
|
||||
&fd, entry_ptr);
|
||||
if (err)
|
||||
goto failed_create_attr;
|
||||
|
||||
hfsplus_mark_inode_dirty(inode, HFSPLUS_I_ATTR_DIRTY);
|
||||
|
||||
failed_create_attr:
|
||||
hfs_find_exit(&fd);
|
||||
|
||||
|
|
@ -304,6 +330,37 @@ static int __hfsplus_delete_attr(struct inode *inode, u32 cnid,
|
|||
return err;
|
||||
}
|
||||
|
||||
static
|
||||
int hfsplus_delete_attr_nolock(struct inode *inode, const char *name,
|
||||
struct hfs_find_data *fd)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
int err;
|
||||
|
||||
hfs_dbg("name %s, ino %ld\n",
|
||||
name ? name : NULL, inode->i_ino);
|
||||
|
||||
if (name) {
|
||||
err = hfsplus_attr_build_key(sb, fd->search_key,
|
||||
inode->i_ino, name);
|
||||
if (err)
|
||||
return err;
|
||||
} else {
|
||||
pr_err("invalid extended attribute name\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
err = hfs_brec_find(fd, hfs_find_rec_by_key);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
err = __hfsplus_delete_attr(inode, inode->i_ino, fd);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int hfsplus_delete_attr(struct inode *inode, const char *name)
|
||||
{
|
||||
int err = 0;
|
||||
|
|
@ -327,22 +384,7 @@ int hfsplus_delete_attr(struct inode *inode, const char *name)
|
|||
if (err)
|
||||
goto out;
|
||||
|
||||
if (name) {
|
||||
err = hfsplus_attr_build_key(sb, fd.search_key,
|
||||
inode->i_ino, name);
|
||||
if (err)
|
||||
goto out;
|
||||
} else {
|
||||
pr_err("invalid extended attribute name\n");
|
||||
err = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = hfs_brec_find(&fd, hfs_find_rec_by_key);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
err = __hfsplus_delete_attr(inode, inode->i_ino, &fd);
|
||||
err = hfsplus_delete_attr_nolock(inode, name, &fd);
|
||||
if (err)
|
||||
goto out;
|
||||
|
||||
|
|
@ -384,3 +426,50 @@ end_delete_all:
|
|||
hfs_find_exit(&fd);
|
||||
return err;
|
||||
}
|
||||
|
||||
int hfsplus_replace_attr(struct inode *inode,
|
||||
const char *name,
|
||||
const void *value, size_t size)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct hfs_find_data fd;
|
||||
hfsplus_attr_entry *entry_ptr;
|
||||
int err = 0;
|
||||
|
||||
hfs_dbg("name %s, ino %ld\n",
|
||||
name ? name : NULL, inode->i_ino);
|
||||
|
||||
if (!HFSPLUS_SB(sb)->attr_tree) {
|
||||
pr_err("attributes file doesn't exist\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
entry_ptr = hfsplus_alloc_attr_entry();
|
||||
if (!entry_ptr)
|
||||
return -ENOMEM;
|
||||
|
||||
err = hfs_find_init(HFSPLUS_SB(sb)->attr_tree, &fd);
|
||||
if (err)
|
||||
goto failed_init_replace_attr;
|
||||
|
||||
/* Fail early and avoid ENOSPC during the btree operation */
|
||||
err = hfs_bmap_reserve(fd.tree, fd.tree->depth + 1);
|
||||
if (err)
|
||||
goto failed_replace_attr;
|
||||
|
||||
err = hfsplus_delete_attr_nolock(inode, name, &fd);
|
||||
if (err)
|
||||
goto failed_replace_attr;
|
||||
|
||||
err = hfsplus_create_attr_nolock(inode, name, value, size,
|
||||
&fd, entry_ptr);
|
||||
if (err)
|
||||
goto failed_replace_attr;
|
||||
|
||||
failed_replace_attr:
|
||||
hfs_find_exit(&fd);
|
||||
|
||||
failed_init_replace_attr:
|
||||
hfsplus_destroy_attr_entry(entry_ptr);
|
||||
return err;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -629,7 +629,7 @@ struct hfs_bnode *hfs_bnode_create(struct hfs_btree *tree, u32 num)
|
|||
if (node) {
|
||||
pr_crit("new node %u already hashed?\n", num);
|
||||
WARN_ON(1);
|
||||
return node;
|
||||
return ERR_PTR(-EEXIST);
|
||||
}
|
||||
node = __hfs_bnode_create(tree, num);
|
||||
if (!node)
|
||||
|
|
|
|||
|
|
@ -313,6 +313,9 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
|
|||
if (!S_ISREG(inode->i_mode))
|
||||
return -EPERM;
|
||||
|
||||
hfs_dbg("src_dir->i_ino %lu, dst_dir->i_ino %lu, inode->i_ino %lu\n",
|
||||
src_dir->i_ino, dst_dir->i_ino, inode->i_ino);
|
||||
|
||||
mutex_lock(&sbi->vh_mutex);
|
||||
if (inode->i_ino == (u32)(unsigned long)src_dentry->d_fsdata) {
|
||||
for (;;) {
|
||||
|
|
@ -332,7 +335,7 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
|
|||
cnid = sbi->next_cnid++;
|
||||
src_dentry->d_fsdata = (void *)(unsigned long)cnid;
|
||||
res = hfsplus_create_cat(cnid, src_dir,
|
||||
&src_dentry->d_name, inode);
|
||||
&src_dentry->d_name, inode);
|
||||
if (res)
|
||||
/* panic? */
|
||||
goto out;
|
||||
|
|
@ -350,6 +353,21 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
|
|||
mark_inode_dirty(inode);
|
||||
sbi->file_count++;
|
||||
hfsplus_mark_mdb_dirty(dst_dir->i_sb);
|
||||
|
||||
res = hfsplus_cat_write_inode(src_dir);
|
||||
if (res)
|
||||
goto out;
|
||||
|
||||
res = hfsplus_cat_write_inode(dst_dir);
|
||||
if (res)
|
||||
goto out;
|
||||
|
||||
res = hfsplus_cat_write_inode(sbi->hidden_dir);
|
||||
if (res)
|
||||
goto out;
|
||||
|
||||
res = hfsplus_cat_write_inode(inode);
|
||||
|
||||
out:
|
||||
mutex_unlock(&sbi->vh_mutex);
|
||||
return res;
|
||||
|
|
@ -367,6 +385,9 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
|
|||
if (HFSPLUS_IS_RSRC(inode))
|
||||
return -EPERM;
|
||||
|
||||
hfs_dbg("dir->i_ino %lu, inode->i_ino %lu\n",
|
||||
dir->i_ino, inode->i_ino);
|
||||
|
||||
mutex_lock(&sbi->vh_mutex);
|
||||
cnid = (u32)(unsigned long)dentry->d_fsdata;
|
||||
if (inode->i_ino == cnid &&
|
||||
|
|
@ -408,6 +429,15 @@ static int hfsplus_unlink(struct inode *dir, struct dentry *dentry)
|
|||
inode_set_ctime_current(inode);
|
||||
mark_inode_dirty(inode);
|
||||
out:
|
||||
if (!res) {
|
||||
res = hfsplus_cat_write_inode(dir);
|
||||
if (!res) {
|
||||
res = hfsplus_cat_write_inode(sbi->hidden_dir);
|
||||
if (!res)
|
||||
res = hfsplus_cat_write_inode(inode);
|
||||
}
|
||||
}
|
||||
|
||||
mutex_unlock(&sbi->vh_mutex);
|
||||
return res;
|
||||
}
|
||||
|
|
@ -429,6 +459,8 @@ static int hfsplus_rmdir(struct inode *dir, struct dentry *dentry)
|
|||
inode_set_ctime_current(inode);
|
||||
hfsplus_delete_inode(inode);
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
res = hfsplus_cat_write_inode(dir);
|
||||
out:
|
||||
mutex_unlock(&sbi->vh_mutex);
|
||||
return res;
|
||||
|
|
@ -465,6 +497,12 @@ static int hfsplus_symlink(struct mnt_idmap *idmap, struct inode *dir,
|
|||
|
||||
hfsplus_instantiate(dentry, inode, inode->i_ino);
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
res = hfsplus_cat_write_inode(dir);
|
||||
if (res)
|
||||
goto out;
|
||||
|
||||
res = hfsplus_cat_write_inode(inode);
|
||||
goto out;
|
||||
|
||||
out_err:
|
||||
|
|
@ -506,6 +544,12 @@ static int hfsplus_mknod(struct mnt_idmap *idmap, struct inode *dir,
|
|||
|
||||
hfsplus_instantiate(dentry, inode, inode->i_ino);
|
||||
mark_inode_dirty(inode);
|
||||
|
||||
res = hfsplus_cat_write_inode(dir);
|
||||
if (res)
|
||||
goto out;
|
||||
|
||||
res = hfsplus_cat_write_inode(inode);
|
||||
goto out;
|
||||
|
||||
failed_mknod:
|
||||
|
|
|
|||
|
|
@ -344,6 +344,9 @@ int hfsplus_create_attr(struct inode *inode, const char *name,
|
|||
const void *value, size_t size);
|
||||
int hfsplus_delete_attr(struct inode *inode, const char *name);
|
||||
int hfsplus_delete_all_attrs(struct inode *dir, u32 cnid);
|
||||
int hfsplus_replace_attr(struct inode *inode,
|
||||
const char *name,
|
||||
const void *value, size_t size);
|
||||
|
||||
/* bitmap.c */
|
||||
int hfsplus_block_allocate(struct super_block *sb, u32 size, u32 offset,
|
||||
|
|
|
|||
|
|
@ -328,6 +328,9 @@ int hfsplus_file_fsync(struct file *file, loff_t start, loff_t end,
|
|||
struct hfsplus_vh *vhdr = sbi->s_vhdr;
|
||||
int error = 0, error2;
|
||||
|
||||
hfs_dbg("inode->i_ino %lu, start %llu, end %llu\n",
|
||||
inode->i_ino, start, end);
|
||||
|
||||
error = file_write_and_wait_range(file, start, end);
|
||||
if (error)
|
||||
return error;
|
||||
|
|
@ -393,6 +396,19 @@ static const struct inode_operations hfsplus_file_inode_operations = {
|
|||
.fileattr_set = hfsplus_fileattr_set,
|
||||
};
|
||||
|
||||
static const struct inode_operations hfsplus_symlink_inode_operations = {
|
||||
.get_link = page_get_link,
|
||||
.setattr = hfsplus_setattr,
|
||||
.getattr = hfsplus_getattr,
|
||||
.listxattr = hfsplus_listxattr,
|
||||
};
|
||||
|
||||
static const struct inode_operations hfsplus_special_inode_operations = {
|
||||
.setattr = hfsplus_setattr,
|
||||
.getattr = hfsplus_getattr,
|
||||
.listxattr = hfsplus_listxattr,
|
||||
};
|
||||
|
||||
static const struct file_operations hfsplus_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read_iter = generic_file_read_iter,
|
||||
|
|
@ -452,12 +468,17 @@ struct inode *hfsplus_new_inode(struct super_block *sb, struct inode *dir,
|
|||
hip->clump_blocks = sbi->data_clump_blocks;
|
||||
} else if (S_ISLNK(inode->i_mode)) {
|
||||
sbi->file_count++;
|
||||
inode->i_op = &page_symlink_inode_operations;
|
||||
inode->i_op = &hfsplus_symlink_inode_operations;
|
||||
inode_nohighmem(inode);
|
||||
inode->i_mapping->a_ops = &hfsplus_aops;
|
||||
hip->clump_blocks = 1;
|
||||
} else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) ||
|
||||
S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
|
||||
sbi->file_count++;
|
||||
inode->i_op = &hfsplus_special_inode_operations;
|
||||
} else
|
||||
sbi->file_count++;
|
||||
|
||||
insert_inode_hash(inode);
|
||||
mark_inode_dirty(inode);
|
||||
hfsplus_mark_mdb_dirty(sb);
|
||||
|
|
@ -588,10 +609,11 @@ int hfsplus_cat_read_inode(struct inode *inode, struct hfs_find_data *fd)
|
|||
inode->i_fop = &hfsplus_file_operations;
|
||||
inode->i_mapping->a_ops = &hfsplus_aops;
|
||||
} else if (S_ISLNK(inode->i_mode)) {
|
||||
inode->i_op = &page_symlink_inode_operations;
|
||||
inode->i_op = &hfsplus_symlink_inode_operations;
|
||||
inode_nohighmem(inode);
|
||||
inode->i_mapping->a_ops = &hfsplus_aops;
|
||||
} else {
|
||||
inode->i_op = &hfsplus_special_inode_operations;
|
||||
init_special_inode(inode, inode->i_mode,
|
||||
be32_to_cpu(file->permissions.dev));
|
||||
}
|
||||
|
|
@ -612,17 +634,20 @@ out:
|
|||
int hfsplus_cat_write_inode(struct inode *inode)
|
||||
{
|
||||
struct inode *main_inode = inode;
|
||||
struct hfs_btree *tree = HFSPLUS_SB(inode->i_sb)->cat_tree;
|
||||
struct hfs_find_data fd;
|
||||
hfsplus_cat_entry entry;
|
||||
int res = 0;
|
||||
|
||||
hfs_dbg("inode->i_ino %lu\n", inode->i_ino);
|
||||
|
||||
if (HFSPLUS_IS_RSRC(inode))
|
||||
main_inode = HFSPLUS_I(inode)->rsrc_inode;
|
||||
|
||||
if (!main_inode->i_nlink)
|
||||
return 0;
|
||||
|
||||
if (hfs_find_init(HFSPLUS_SB(main_inode->i_sb)->cat_tree, &fd))
|
||||
if (hfs_find_init(tree, &fd))
|
||||
/* panic? */
|
||||
return -EIO;
|
||||
|
||||
|
|
@ -687,6 +712,15 @@ int hfsplus_cat_write_inode(struct inode *inode)
|
|||
set_bit(HFSPLUS_I_CAT_DIRTY, &HFSPLUS_I(inode)->flags);
|
||||
out:
|
||||
hfs_find_exit(&fd);
|
||||
|
||||
if (!res) {
|
||||
res = hfs_btree_write(tree);
|
||||
if (res) {
|
||||
pr_err("b-tree write err: %d, ino %lu\n",
|
||||
res, inode->i_ino);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -53,6 +53,12 @@ static int hfsplus_system_read_inode(struct inode *inode)
|
|||
return -EIO;
|
||||
}
|
||||
|
||||
/*
|
||||
* Assign a dummy file type, for may_open() requires that
|
||||
* an inode has a valid file type.
|
||||
*/
|
||||
inode->i_mode = S_IFREG;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -344,8 +350,6 @@ static void hfsplus_put_super(struct super_block *sb)
|
|||
hfs_btree_close(sbi->ext_tree);
|
||||
kfree(sbi->s_vhdr_buf);
|
||||
kfree(sbi->s_backup_vhdr_buf);
|
||||
call_rcu(&sbi->rcu, delayed_free);
|
||||
|
||||
hfs_dbg("finished\n");
|
||||
}
|
||||
|
||||
|
|
@ -648,9 +652,7 @@ out_free_vhdr:
|
|||
kfree(sbi->s_vhdr_buf);
|
||||
kfree(sbi->s_backup_vhdr_buf);
|
||||
out_unload_nls:
|
||||
unload_nls(sbi->nls);
|
||||
unload_nls(nls);
|
||||
kfree(sbi);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
@ -709,10 +711,18 @@ static int hfsplus_init_fs_context(struct fs_context *fc)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void hfsplus_kill_super(struct super_block *sb)
|
||||
{
|
||||
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
|
||||
|
||||
kill_block_super(sb);
|
||||
call_rcu(&sbi->rcu, delayed_free);
|
||||
}
|
||||
|
||||
static struct file_system_type hfsplus_fs_type = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "hfsplus",
|
||||
.kill_sb = kill_block_super,
|
||||
.kill_sb = hfsplus_kill_super,
|
||||
.fs_flags = FS_REQUIRES_DEV,
|
||||
.init_fs_context = hfsplus_init_fs_context,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -258,6 +258,15 @@ end_attr_file_creation:
|
|||
return err;
|
||||
}
|
||||
|
||||
static inline
|
||||
bool is_xattr_operation_supported(struct inode *inode)
|
||||
{
|
||||
if (HFSPLUS_IS_RSRC(inode))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int __hfsplus_setxattr(struct inode *inode, const char *name,
|
||||
const void *value, size_t size, int flags)
|
||||
{
|
||||
|
|
@ -268,9 +277,11 @@ int __hfsplus_setxattr(struct inode *inode, const char *name,
|
|||
u16 folder_finderinfo_len = sizeof(DInfo) + sizeof(DXInfo);
|
||||
u16 file_finderinfo_len = sizeof(FInfo) + sizeof(FXInfo);
|
||||
|
||||
if ((!S_ISREG(inode->i_mode) &&
|
||||
!S_ISDIR(inode->i_mode)) ||
|
||||
HFSPLUS_IS_RSRC(inode))
|
||||
hfs_dbg("ino %lu, name %s, value %p, size %zu\n",
|
||||
inode->i_ino, name ? name : NULL,
|
||||
value, size);
|
||||
|
||||
if (!is_xattr_operation_supported(inode))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (value == NULL)
|
||||
|
|
@ -341,12 +352,11 @@ int __hfsplus_setxattr(struct inode *inode, const char *name,
|
|||
err = -EOPNOTSUPP;
|
||||
goto end_setxattr;
|
||||
}
|
||||
err = hfsplus_delete_attr(inode, name);
|
||||
if (err)
|
||||
goto end_setxattr;
|
||||
err = hfsplus_create_attr(inode, name, value, size);
|
||||
if (err)
|
||||
err = hfsplus_replace_attr(inode, name, value, size);
|
||||
if (err) {
|
||||
hfs_dbg("unable to replace xattr: err %d\n", err);
|
||||
goto end_setxattr;
|
||||
}
|
||||
} else {
|
||||
if (flags & XATTR_REPLACE) {
|
||||
pr_err("cannot replace xattr\n");
|
||||
|
|
@ -354,8 +364,10 @@ int __hfsplus_setxattr(struct inode *inode, const char *name,
|
|||
goto end_setxattr;
|
||||
}
|
||||
err = hfsplus_create_attr(inode, name, value, size);
|
||||
if (err)
|
||||
if (err) {
|
||||
hfs_dbg("unable to store value: err %d\n", err);
|
||||
goto end_setxattr;
|
||||
}
|
||||
}
|
||||
|
||||
cat_entry_type = hfs_bnode_read_u16(cat_fd.bnode, cat_fd.entryoffset);
|
||||
|
|
@ -389,12 +401,13 @@ int __hfsplus_setxattr(struct inode *inode, const char *name,
|
|||
|
||||
end_setxattr:
|
||||
hfs_find_exit(&cat_fd);
|
||||
hfs_dbg("finished: res %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int name_len(const char *xattr_name, int xattr_name_len)
|
||||
static size_t name_len(const char *xattr_name, size_t xattr_name_len)
|
||||
{
|
||||
int len = xattr_name_len + 1;
|
||||
size_t len = xattr_name_len + 1;
|
||||
|
||||
if (!is_known_namespace(xattr_name))
|
||||
len += XATTR_MAC_OSX_PREFIX_LEN;
|
||||
|
|
@ -402,15 +415,22 @@ static int name_len(const char *xattr_name, int xattr_name_len)
|
|||
return len;
|
||||
}
|
||||
|
||||
static ssize_t copy_name(char *buffer, const char *xattr_name, int name_len)
|
||||
static ssize_t copy_name(char *buffer, const char *xattr_name, size_t name_len)
|
||||
{
|
||||
ssize_t len;
|
||||
|
||||
if (!is_known_namespace(xattr_name))
|
||||
memset(buffer, 0, name_len);
|
||||
|
||||
if (!is_known_namespace(xattr_name)) {
|
||||
len = scnprintf(buffer, name_len + XATTR_MAC_OSX_PREFIX_LEN,
|
||||
"%s%s", XATTR_MAC_OSX_PREFIX, xattr_name);
|
||||
else
|
||||
} else {
|
||||
len = strscpy(buffer, xattr_name, name_len + 1);
|
||||
if (len < 0) {
|
||||
pr_err("fail to copy name: err %zd\n", len);
|
||||
len = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/* include NUL-byte in length for non-empty name */
|
||||
if (len >= 0)
|
||||
|
|
@ -423,16 +443,26 @@ int hfsplus_setxattr(struct inode *inode, const char *name,
|
|||
const char *prefix, size_t prefixlen)
|
||||
{
|
||||
char *xattr_name;
|
||||
size_t xattr_name_len =
|
||||
NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1;
|
||||
int res;
|
||||
|
||||
xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1,
|
||||
GFP_KERNEL);
|
||||
hfs_dbg("ino %lu, name %s, prefix %s, prefixlen %zu, "
|
||||
"value %p, size %zu\n",
|
||||
inode->i_ino, name ? name : NULL,
|
||||
prefix ? prefix : NULL, prefixlen,
|
||||
value, size);
|
||||
|
||||
xattr_name = kmalloc(xattr_name_len, GFP_KERNEL);
|
||||
if (!xattr_name)
|
||||
return -ENOMEM;
|
||||
strcpy(xattr_name, prefix);
|
||||
strcpy(xattr_name + prefixlen, name);
|
||||
res = __hfsplus_setxattr(inode, xattr_name, value, size, flags);
|
||||
kfree(xattr_name);
|
||||
|
||||
hfs_dbg("finished: res %d\n", res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -496,9 +526,7 @@ ssize_t __hfsplus_getxattr(struct inode *inode, const char *name,
|
|||
u16 record_length = 0;
|
||||
ssize_t res;
|
||||
|
||||
if ((!S_ISREG(inode->i_mode) &&
|
||||
!S_ISDIR(inode->i_mode)) ||
|
||||
HFSPLUS_IS_RSRC(inode))
|
||||
if (!is_xattr_operation_supported(inode))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (!strcmp_xattr_finder_info(name))
|
||||
|
|
@ -579,6 +607,10 @@ ssize_t hfsplus_getxattr(struct inode *inode, const char *name,
|
|||
int res;
|
||||
char *xattr_name;
|
||||
|
||||
hfs_dbg("ino %lu, name %s, prefix %s\n",
|
||||
inode->i_ino, name ? name : NULL,
|
||||
prefix ? prefix : NULL);
|
||||
|
||||
xattr_name = kmalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN + 1,
|
||||
GFP_KERNEL);
|
||||
if (!xattr_name)
|
||||
|
|
@ -589,6 +621,9 @@ ssize_t hfsplus_getxattr(struct inode *inode, const char *name,
|
|||
|
||||
res = __hfsplus_getxattr(inode, xattr_name, value, size);
|
||||
kfree(xattr_name);
|
||||
|
||||
hfs_dbg("finished: res %d\n", res);
|
||||
|
||||
return res;
|
||||
|
||||
}
|
||||
|
|
@ -679,11 +714,12 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
|||
struct hfs_find_data fd;
|
||||
struct hfsplus_attr_key attr_key;
|
||||
char *strbuf;
|
||||
size_t strbuf_size;
|
||||
int xattr_name_len;
|
||||
|
||||
if ((!S_ISREG(inode->i_mode) &&
|
||||
!S_ISDIR(inode->i_mode)) ||
|
||||
HFSPLUS_IS_RSRC(inode))
|
||||
hfs_dbg("ino %lu\n", inode->i_ino);
|
||||
|
||||
if (!is_xattr_operation_supported(inode))
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
res = hfsplus_listxattr_finder_info(dentry, buffer, size);
|
||||
|
|
@ -698,8 +734,9 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
|||
return err;
|
||||
}
|
||||
|
||||
strbuf = kzalloc(NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN +
|
||||
XATTR_MAC_OSX_PREFIX_LEN + 1, GFP_KERNEL);
|
||||
strbuf_size = NLS_MAX_CHARSET_SIZE * HFSPLUS_ATTR_MAX_STRLEN +
|
||||
XATTR_MAC_OSX_PREFIX_LEN + 1;
|
||||
strbuf = kzalloc(strbuf_size, GFP_KERNEL);
|
||||
if (!strbuf) {
|
||||
res = -ENOMEM;
|
||||
goto out;
|
||||
|
|
@ -708,8 +745,7 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
|||
err = hfsplus_find_attr(inode->i_sb, inode->i_ino, NULL, &fd);
|
||||
if (err) {
|
||||
if (err == -ENOENT) {
|
||||
if (res == 0)
|
||||
res = -ENODATA;
|
||||
res = 0;
|
||||
goto end_listxattr;
|
||||
} else {
|
||||
res = err;
|
||||
|
|
@ -746,6 +782,9 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
|||
res += name_len(strbuf, xattr_name_len);
|
||||
} else if (can_list(strbuf)) {
|
||||
if (size < (res + name_len(strbuf, xattr_name_len))) {
|
||||
pr_err("size %zu, res %zd, name_len %zu\n",
|
||||
size, res,
|
||||
name_len(strbuf, xattr_name_len));
|
||||
res = -ERANGE;
|
||||
goto end_listxattr;
|
||||
} else
|
||||
|
|
@ -753,6 +792,10 @@ ssize_t hfsplus_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
|||
strbuf, xattr_name_len);
|
||||
}
|
||||
|
||||
memset(fd.key->attr.key_name.unicode, 0,
|
||||
sizeof(fd.key->attr.key_name.unicode));
|
||||
memset(strbuf, 0, strbuf_size);
|
||||
|
||||
if (hfs_brec_goto(&fd, 1))
|
||||
goto end_listxattr;
|
||||
}
|
||||
|
|
@ -761,6 +804,9 @@ end_listxattr:
|
|||
kfree(strbuf);
|
||||
out:
|
||||
hfs_find_exit(&fd);
|
||||
|
||||
hfs_dbg("finished: res %zd\n", res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
@ -773,6 +819,9 @@ static int hfsplus_removexattr(struct inode *inode, const char *name)
|
|||
int is_xattr_acl_deleted;
|
||||
int is_all_xattrs_deleted;
|
||||
|
||||
hfs_dbg("ino %lu, name %s\n",
|
||||
inode->i_ino, name ? name : NULL);
|
||||
|
||||
if (!HFSPLUS_SB(inode->i_sb)->attr_tree)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
|
|
@ -833,6 +882,9 @@ static int hfsplus_removexattr(struct inode *inode, const char *name)
|
|||
|
||||
end_removexattr:
|
||||
hfs_find_exit(&cat_fd);
|
||||
|
||||
hfs_dbg("finished: err %d\n", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue