mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-08-18 02:22:47 -07:00
apfs: begin work on common xfield code
Define apfs_find_xfield() in the new xfield.c file; use it to replace the ad hoc code that finds extended fields in inodes and dentries. Creation of xfields will soon be moved to common code as well. Signed-off-by: Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
This commit is contained in:
1 parent
4e12c07a30
commit
b4a2effba1
6 files changed
+149
-98
No files matched your search
+1
-1
@@ -7,4 +7,4 @@ obj-$(CONFIG_APFS_FS) += apfs.o
|
||||
|
||||
apfs-y := btree.o dir.o extents.o file.o inode.o key.o message.o namei.o \
|
||||
node.o object.o spaceman.o super.o symlink.o transaction.o \
|
||||
unicode.o xattr.o
|
||||
unicode.o xattr.o xfield.o
|
||||
+8
-11
@@ -16,6 +16,7 @@
|
||||
#include "node.h"
|
||||
#include "super.h"
|
||||
#include "transaction.h"
|
||||
#include "xfield.h"
|
||||
|
||||
/**
|
||||
* apfs_drec_from_query - Read the directory record found by a successful query
|
||||
@@ -36,6 +37,8 @@ static int apfs_drec_from_query(struct apfs_query *query,
|
||||
struct apfs_drec_hashed_key *de_key;
|
||||
struct apfs_drec_val *de;
|
||||
int namelen = query->key_len - sizeof(*de_key);
|
||||
char *xval = NULL;
|
||||
int xlen;
|
||||
|
||||
if (namelen < 1)
|
||||
return -EFSCORRUPTED;
|
||||
@@ -54,18 +57,12 @@ static int apfs_drec_from_query(struct apfs_query *query,
|
||||
return -EFSCORRUPTED;
|
||||
|
||||
/* The dentry may have at most one xfield: the sibling id */
|
||||
if (query->len == sizeof(*de)) {
|
||||
drec->sibling_id = 0;
|
||||
} else {
|
||||
int x_meta_len;
|
||||
__le64 *sib_id;
|
||||
drec->sibling_id = 0;
|
||||
xlen = apfs_find_xfield(de->xfields, query->len - sizeof(*de),
|
||||
APFS_DREC_EXT_TYPE_SIBLING_ID, &xval);
|
||||
if (xlen >= sizeof(__le64)) {
|
||||
__le64 *sib_id = (__le64 *)xval;
|
||||
|
||||
x_meta_len = sizeof(struct apfs_xf_blob) +
|
||||
sizeof(struct apfs_x_field);
|
||||
if (query->len != sizeof(*de) + x_meta_len + sizeof(*sib_id))
|
||||
return -EFSCORRUPTED;
|
||||
|
||||
sib_id = (void *)de->xfields + x_meta_len;
|
||||
drec->sibling_id = le64_to_cpup(sib_id);
|
||||
}
|
||||
|
||||
|
||||
+20
-40
@@ -18,6 +18,7 @@
|
||||
#include "node.h"
|
||||
#include "super.h"
|
||||
#include "xattr.h"
|
||||
#include "xfield.h"
|
||||
|
||||
static int apfs_readpage(struct file *file, struct page *page)
|
||||
{
|
||||
@@ -84,11 +85,9 @@ static int apfs_inode_from_query(struct apfs_query *query, struct inode *inode)
|
||||
{
|
||||
struct apfs_inode_info *ai = APFS_I(inode);
|
||||
struct apfs_inode_val *inode_val;
|
||||
struct apfs_dstream *dstream = NULL;
|
||||
struct apfs_xf_blob *xblob;
|
||||
struct apfs_x_field *xfield;
|
||||
char *raw = query->node->object.bh->b_data;
|
||||
int rest, i;
|
||||
char *xval = NULL;
|
||||
int xlen;
|
||||
u32 rdev = 0;
|
||||
|
||||
if (query->len < sizeof(*inode_val))
|
||||
@@ -121,45 +120,26 @@ static int apfs_inode_from_query(struct apfs_query *query, struct inode *inode)
|
||||
inode->i_mtime = apfs_timespec(inode_val->mod_time);
|
||||
ai->i_crtime = apfs_timespec(inode_val->create_time);
|
||||
|
||||
xblob = (struct apfs_xf_blob *) inode_val->xfields;
|
||||
xfield = (struct apfs_x_field *) xblob->xf_data;
|
||||
rest = query->len - (sizeof(*inode_val) + sizeof(*xblob));
|
||||
rest -= le16_to_cpu(xblob->xf_num_exts) * sizeof(xfield[0]);
|
||||
if (rest < 0)
|
||||
goto corrupted;
|
||||
for (i = 0; i < le16_to_cpu(xblob->xf_num_exts); ++i) {
|
||||
int attrlen;
|
||||
inode->i_size = inode->i_blocks = 0; /* TODO: compressed inodes */
|
||||
xlen = apfs_find_xfield(inode_val->xfields,
|
||||
query->len - sizeof(*inode_val),
|
||||
APFS_INO_EXT_TYPE_DSTREAM, &xval);
|
||||
if (xlen >= sizeof(struct apfs_dstream)) {
|
||||
struct apfs_dstream *dstream = (struct apfs_dstream *)xval;
|
||||
|
||||
/* Attribute length is padded to a multiple of 8 */
|
||||
attrlen = round_up(le16_to_cpu(xfield[i].x_size), 8);
|
||||
if (attrlen > rest)
|
||||
break;
|
||||
|
||||
/* These are the only xfields we care about, for now */
|
||||
if (xfield[i].x_type == APFS_INO_EXT_TYPE_DSTREAM) {
|
||||
dstream = (struct apfs_dstream *)
|
||||
((char *)inode_val + query->len - rest);
|
||||
break;
|
||||
}
|
||||
if (xfield[i].x_type == APFS_INO_EXT_TYPE_RDEV) {
|
||||
__le32 *rdev_p = (void *)inode_val + query->len - rest;
|
||||
|
||||
rdev = le32_to_cpu(*rdev_p);
|
||||
}
|
||||
|
||||
rest -= attrlen;
|
||||
}
|
||||
|
||||
if (dstream) {
|
||||
inode->i_size = le64_to_cpu(dstream->size);
|
||||
inode->i_blocks = le64_to_cpu(dstream->alloced_size) >> 9;
|
||||
} else {
|
||||
/*
|
||||
* This inode is "empty", but it may actually hold compressed
|
||||
* data in the named attribute com.apple.decmpfs, and sometimes
|
||||
* in com.apple.ResourceFork
|
||||
*/
|
||||
inode->i_size = inode->i_blocks = 0;
|
||||
}
|
||||
xval = NULL;
|
||||
|
||||
rdev = 0;
|
||||
xlen = apfs_find_xfield(inode_val->xfields,
|
||||
query->len - sizeof(*inode_val),
|
||||
APFS_INO_EXT_TYPE_RDEV, &xval);
|
||||
if (xlen >= sizeof(__le32)) {
|
||||
__le32 *rdev_p = (__le32 *)xval;
|
||||
|
||||
rdev = le32_to_cpup(rdev_p);
|
||||
}
|
||||
|
||||
apfs_inode_set_ops(inode, rdev);
|
||||
|
||||
@@ -49,52 +49,6 @@ struct apfs_inode_val {
|
||||
/*5C*/ u8 xfields[];
|
||||
} __packed;
|
||||
|
||||
/* Extended field types */
|
||||
#define APFS_DREC_EXT_TYPE_SIBLING_ID 1
|
||||
|
||||
#define APFS_INO_EXT_TYPE_SNAP_XID 1
|
||||
#define APFS_INO_EXT_TYPE_DELTA_TREE_OID 2
|
||||
#define APFS_INO_EXT_TYPE_DOCUMENT_ID 3
|
||||
#define APFS_INO_EXT_TYPE_NAME 4
|
||||
#define APFS_INO_EXT_TYPE_PREV_FSIZE 5
|
||||
#define APFS_INO_EXT_TYPE_RESERVED_6 6
|
||||
#define APFS_INO_EXT_TYPE_FINDER_INFO 7
|
||||
#define APFS_INO_EXT_TYPE_DSTREAM 8
|
||||
#define APFS_INO_EXT_TYPE_RESERVED_9 9
|
||||
#define APFS_INO_EXT_TYPE_DIR_STATS_KEY 10
|
||||
#define APFS_INO_EXT_TYPE_FS_UUID 11
|
||||
#define APFS_INO_EXT_TYPE_RESERVED_12 12
|
||||
#define APFS_INO_EXT_TYPE_SPARSE_BYTES 13
|
||||
#define APFS_INO_EXT_TYPE_RDEV 14
|
||||
|
||||
/* Extended field flags */
|
||||
#define APFS_XF_DATA_DEPENDENT 0x01
|
||||
#define APFS_XF_DO_NOT_COPY 0x02
|
||||
#define APFS_XF_RESERVED_4 0x04
|
||||
#define APFS_XF_CHILDREN_INHERIT 0x08
|
||||
#define APFS_XF_USER_FIELD 0x10
|
||||
#define APFS_XF_SYSTEM_FIELD 0x20
|
||||
#define APFS_XF_RESERVED_40 0x40
|
||||
#define APFS_XF_RESERVED_80 0x80
|
||||
|
||||
/*
|
||||
* Structure used to store the number and size of extended fields of an inode
|
||||
*/
|
||||
struct apfs_xf_blob {
|
||||
__le16 xf_num_exts;
|
||||
__le16 xf_used_data;
|
||||
u8 xf_data[];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Structure used to store an inode's extended field
|
||||
*/
|
||||
struct apfs_x_field {
|
||||
u8 x_type;
|
||||
u8 x_flags;
|
||||
__le16 x_size;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Structure of a data stream record
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* linux/fs/apfs/xfield.c
|
||||
*
|
||||
* Copyright (C) 2019 Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
|
||||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include "xfield.h"
|
||||
|
||||
/**
|
||||
* apfs_find_xfield - Find an extended field value in an inode or dentry record
|
||||
* @xfields: pointer to the on-disk xfield collection for the record
|
||||
* @len: length of the collection
|
||||
* @xtype: type of the xfield to retrieve
|
||||
* @xval: on return, a pointer to the wanted on-disk xfield value
|
||||
*
|
||||
* Returns the length of @xval on success, or 0 if no matching xfield was found;
|
||||
* the caller must check that the expected structures fit before casting @xval.
|
||||
*/
|
||||
int apfs_find_xfield(u8 *xfields, int len, u8 xtype, char **xval)
|
||||
{
|
||||
struct apfs_xf_blob *blob;
|
||||
struct apfs_x_field *xfield;
|
||||
int count;
|
||||
int rest = len;
|
||||
int i;
|
||||
|
||||
if (!len)
|
||||
return 0; /* No xfield data */
|
||||
|
||||
rest -= sizeof(*blob);
|
||||
if (rest < 0)
|
||||
return 0; /* Corruption */
|
||||
blob = (struct apfs_xf_blob *)xfields;
|
||||
|
||||
count = le16_to_cpu(blob->xf_num_exts);
|
||||
rest -= count * sizeof(*xfield);
|
||||
if (rest < 0)
|
||||
return 0; /* Corruption */
|
||||
xfield = (struct apfs_x_field *)blob->xf_data;
|
||||
|
||||
for (i = 0; i < count; ++i) {
|
||||
int xlen;
|
||||
|
||||
/* Attribute length is padded to a multiple of 8 */
|
||||
xlen = round_up(le16_to_cpu(xfield[i].x_size), 8);
|
||||
if (xlen > rest)
|
||||
return 0; /* Corruption */
|
||||
|
||||
if (xfield[i].x_type == xtype) {
|
||||
*xval = (char *)xfields + len - rest;
|
||||
return xlen;
|
||||
}
|
||||
rest -= xlen;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* linux/fs/apfs/xfield.h
|
||||
*
|
||||
* Copyright (C) 2019 Ernesto A. Fernández <ernesto.mnd.fernandez@gmail.com>
|
||||
*/
|
||||
|
||||
#ifndef _APFS_XFIELD_H
|
||||
#define _APFS_XFIELD_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
/* Extended field types for dentries */
|
||||
#define APFS_DREC_EXT_TYPE_SIBLING_ID 1
|
||||
|
||||
/* Extended field types for inodes */
|
||||
#define APFS_INO_EXT_TYPE_SNAP_XID 1
|
||||
#define APFS_INO_EXT_TYPE_DELTA_TREE_OID 2
|
||||
#define APFS_INO_EXT_TYPE_DOCUMENT_ID 3
|
||||
#define APFS_INO_EXT_TYPE_NAME 4
|
||||
#define APFS_INO_EXT_TYPE_PREV_FSIZE 5
|
||||
#define APFS_INO_EXT_TYPE_RESERVED_6 6
|
||||
#define APFS_INO_EXT_TYPE_FINDER_INFO 7
|
||||
#define APFS_INO_EXT_TYPE_DSTREAM 8
|
||||
#define APFS_INO_EXT_TYPE_RESERVED_9 9
|
||||
#define APFS_INO_EXT_TYPE_DIR_STATS_KEY 10
|
||||
#define APFS_INO_EXT_TYPE_FS_UUID 11
|
||||
#define APFS_INO_EXT_TYPE_RESERVED_12 12
|
||||
#define APFS_INO_EXT_TYPE_SPARSE_BYTES 13
|
||||
#define APFS_INO_EXT_TYPE_RDEV 14
|
||||
|
||||
/* Extended field flags */
|
||||
#define APFS_XF_DATA_DEPENDENT 0x01
|
||||
#define APFS_XF_DO_NOT_COPY 0x02
|
||||
#define APFS_XF_RESERVED_4 0x04
|
||||
#define APFS_XF_CHILDREN_INHERIT 0x08
|
||||
#define APFS_XF_USER_FIELD 0x10
|
||||
#define APFS_XF_SYSTEM_FIELD 0x20
|
||||
#define APFS_XF_RESERVED_40 0x40
|
||||
#define APFS_XF_RESERVED_80 0x80
|
||||
|
||||
/*
|
||||
* Structure used to store the number and size of an xfield collection
|
||||
*/
|
||||
struct apfs_xf_blob {
|
||||
__le16 xf_num_exts;
|
||||
__le16 xf_used_data;
|
||||
u8 xf_data[];
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Structure used to describe an extended field
|
||||
*/
|
||||
struct apfs_x_field {
|
||||
u8 x_type;
|
||||
u8 x_flags;
|
||||
__le16 x_size;
|
||||
} __packed;
|
||||
|
||||
extern int apfs_find_xfield(u8 *xfields, int len, u8 xtype, char **xval);
|
||||
|
||||
#endif /* _APFS_XFIELD_H */
|
||||
Reference in new issue
Block a user