You've already forked linux-apfs-oot
mirror of
https://github.com/linux-apfs/linux-apfs-oot.git
synced 2026-05-01 15:01:20 -07:00
72e6425af6
Copy the code of the APFS module into its own repository, without the rest of the kernel tree. Development will continue upstream, but the intention is to make life easier for potential users. To get the module to build independently, rewrite the Makefile and add a definition for the APFS_SUPER_MAGIC macro. Since the intention is to support a range of kernel versions, use preprocessor checks to handle kernels without statx, without iversion, and without SB_RDONLY. Provide a README file based on the upstream documentation, but with additional build and mount instructions. Add a LICENSE file as well. Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
89 lines
2.0 KiB
C
89 lines
2.0 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* linux/fs/apfs/namei.c
|
|
*
|
|
* Copyright (C) 2018 Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
|
|
*/
|
|
|
|
#include "apfs.h"
|
|
#include "dir.h"
|
|
#include "inode.h"
|
|
#include "key.h"
|
|
#include "super.h"
|
|
#include "unicode.h"
|
|
#include "xattr.h"
|
|
|
|
static struct dentry *apfs_lookup(struct inode *dir, struct dentry *dentry,
|
|
unsigned int flags)
|
|
{
|
|
struct inode *inode = NULL;
|
|
u64 ino = 0;
|
|
int err;
|
|
|
|
if (dentry->d_name.len > APFS_NAME_LEN)
|
|
return ERR_PTR(-ENAMETOOLONG);
|
|
|
|
err = apfs_inode_by_name(dir, &dentry->d_name, &ino);
|
|
if (err && err != -ENODATA)
|
|
return ERR_PTR(err);
|
|
|
|
if (!err) {
|
|
inode = apfs_iget(dir->i_sb, ino);
|
|
if (IS_ERR(inode))
|
|
return ERR_CAST(inode);
|
|
}
|
|
|
|
return d_splice_alias(inode, dentry);
|
|
}
|
|
|
|
const struct inode_operations apfs_dir_inode_operations = {
|
|
.lookup = apfs_lookup,
|
|
.getattr = apfs_getattr,
|
|
.listxattr = apfs_listxattr,
|
|
};
|
|
|
|
const struct inode_operations apfs_special_inode_operations = {
|
|
.getattr = apfs_getattr,
|
|
.listxattr = apfs_listxattr,
|
|
};
|
|
|
|
static int apfs_dentry_hash(const struct dentry *dir, struct qstr *child)
|
|
{
|
|
struct apfs_unicursor cursor;
|
|
unsigned long hash;
|
|
bool case_fold = apfs_is_case_insensitive(dir->d_sb);
|
|
|
|
apfs_init_unicursor(&cursor, child->name);
|
|
hash = init_name_hash(dir);
|
|
|
|
while (1) {
|
|
int i;
|
|
unicode_t utf32;
|
|
|
|
utf32 = apfs_normalize_next(&cursor, case_fold);
|
|
if (!utf32)
|
|
break;
|
|
|
|
/* Hash the unicode character one byte at a time */
|
|
for (i = 0; i < 4; ++i) {
|
|
hash = partial_name_hash((u8)utf32, hash);
|
|
utf32 = utf32 >> 8;
|
|
}
|
|
}
|
|
child->hash = end_name_hash(hash);
|
|
|
|
/* TODO: return error instead of truncating invalid UTF-8? */
|
|
return 0;
|
|
}
|
|
|
|
static int apfs_dentry_compare(const struct dentry *dentry, unsigned int len,
|
|
const char *str, const struct qstr *name)
|
|
{
|
|
return apfs_filename_cmp(dentry->d_sb, name->name, str);
|
|
}
|
|
|
|
const struct dentry_operations apfs_dentry_operations = {
|
|
.d_hash = apfs_dentry_hash,
|
|
.d_compare = apfs_dentry_compare,
|
|
};
|