mirror of
https://github.com/linux-apfs/linux-apfs-rw.git
synced 2026-08-18 02:19:59 -07:00
Compare commits
136
Commits
No files matched your search
@@ -13,6 +13,11 @@ apfs-y := btree.o compress.o dir.o extents.o file.o inode.o key.o libzbitmap.o \
|
||||
lzfse/lzvn_decode_base.o message.o namei.o node.o object.o snapshot.o \
|
||||
spaceman.o super.o symlink.o transaction.o unicode.o xattr.o xfield.o
|
||||
|
||||
# If you want mounts to be writable by default, run the build as:
|
||||
# make APFS_CONFIG=-DCONFIG_APFS_RW_ALWAYS
|
||||
# This is risky and not generally recommended.
|
||||
ccflags-y += $(APFS_CONFIG)
|
||||
|
||||
default:
|
||||
./genver.sh
|
||||
make -C $(KERNEL_DIR) M=$(PWD)
|
||||
|
||||
+33
-13
@@ -4,13 +4,8 @@ Apple File System for Linux
|
||||
|
||||
The Apple File System (APFS) is the copy-on-write filesystem currently used on
|
||||
all Apple devices. This module provides a degree of experimental support on
|
||||
Linux.
|
||||
|
||||
It's supposed to work with a range of kernel versions starting at 4.9 or before,
|
||||
but only a few of those have actually been tested. Also, kernel versions below
|
||||
4.12 will be slower for some operations. If you run into any problem, please
|
||||
send a report to <linux-apfs@googlegroups.com> or file a github issue at
|
||||
https://github.com/eafer/linux-apfs-rw/issues.
|
||||
Linux. It's intended to work with all kernel versions since 4.12, but testing
|
||||
is focused on 5.18 and above.
|
||||
|
||||
To help test write support, a set of userland tools is also under development.
|
||||
The git tree can be retrieved from https://github.com/eafer/apfsprogs.git.
|
||||
@@ -19,14 +14,32 @@ Known limitations
|
||||
=================
|
||||
|
||||
This module is the result of reverse engineering and testing has been limited.
|
||||
If you make use of the write support, expect data corruption. Please report any
|
||||
issues that you find, but I can't promise a quick resolution at this stage.
|
||||
If you make use of the write support, there is a real risk of data corruption,
|
||||
so mounts are read-only by default. Please report any issues that you find.
|
||||
|
||||
Encryption is not yet implemented even in read-only mode.
|
||||
Writes to fusion drives will likely never be supported, though I might
|
||||
reconsider this if people actually need it. Encryption is not yet implemented
|
||||
even in read-only mode.
|
||||
|
||||
Reporting bugs
|
||||
==============
|
||||
|
||||
If you encounter any problem, the first thing you should do is run (as root)::
|
||||
|
||||
dmesg | grep -i apfs
|
||||
|
||||
to see all the error messages. If that doesn't help you, please file a github
|
||||
issue at https://github.com/eafer/linux-apfs-rw/issues. Or send me an email if
|
||||
you prefer.
|
||||
|
||||
Build
|
||||
=====
|
||||
|
||||
Note that at this point the driver has been packaged for several distros, so
|
||||
it may be more convenient to install it from there instead of building it
|
||||
yourself. The distro packages are often outdated though, so be sure to check
|
||||
the version.
|
||||
|
||||
In order to build a module out-of-tree, you will first need the Linux kernel
|
||||
headers. Depending on your distro, you can get them by running (as root)::
|
||||
|
||||
@@ -44,10 +57,15 @@ Now you can just cd to the linux-apfs-rw directory and run::
|
||||
make
|
||||
|
||||
The resulting module is the apfs.ko file. Before you can use it you must insert
|
||||
it into the kernel, as well as its dependencies. Again as root::
|
||||
it into the kernel. Again as root::
|
||||
|
||||
insmod apfs.ko
|
||||
|
||||
If you get an "unknown symbol in module" error, run::
|
||||
|
||||
modprobe libcrc32c
|
||||
insmod apfs.ko
|
||||
|
||||
and then try the insmod command again.
|
||||
|
||||
Mount
|
||||
=====
|
||||
@@ -64,12 +82,14 @@ vol=n Volume number to mount. The default is volume 0.
|
||||
|
||||
snap=label Volume snapshot to mount (in read-only mode).
|
||||
|
||||
tier2=path Path to the tier 2 device. For fusion drives only.
|
||||
|
||||
uid=n, gid=n Override on-disk inode ownership data with given uid/gid.
|
||||
|
||||
cknodes Verify the checksum on all metadata nodes. Right now this has a
|
||||
severe performance cost, so it's not recommended.
|
||||
|
||||
readwrite Enable the experimental write support. This **will** corrupt your
|
||||
readwrite Enable the experimental write support. This may corrupt your
|
||||
container.
|
||||
============ =================================================================
|
||||
|
||||
|
||||
+56
-12
@@ -268,6 +268,10 @@ struct apfs_phys_ext_val {
|
||||
#define APFS_FILE_EXTENT_LEN_MASK 0x00ffffffffffffffULL
|
||||
#define APFS_FILE_EXTENT_FLAG_MASK 0xff00000000000000ULL
|
||||
#define APFS_FILE_EXTENT_FLAG_SHIFT 56
|
||||
#define APFS_FILE_EXTENT_CRYPTO_FLAG 0x01 /* Made-up name */
|
||||
#define APFS_FILE_EXTENT_PREALLOCATED 0x02 /* Made-up name */
|
||||
#define APFS_VALID_FILE_EXTENT_FLAGS (APFS_FILE_EXTENT_CRYPTO_FLAG \
|
||||
| APFS_FILE_EXTENT_PREALLOCATED)
|
||||
|
||||
/*
|
||||
* Put a bound on maximum file size so that a growing truncation will always
|
||||
@@ -1051,13 +1055,19 @@ struct apfs_checkpoint_map_phys {
|
||||
#define APFS_FS_SPILLEDOVER 0x00000010LL
|
||||
#define APFS_FS_RUN_SPILLOVER_CLEANER 0x00000020LL
|
||||
#define APFS_FS_ALWAYS_CHECK_EXTENTREF 0x00000040LL
|
||||
#define APFS_FS_PREVIOUSLY_SEALED 0x00000080LL /* Made-up name */
|
||||
#define APFS_FS_PFK 0x00000100LL /* Made-up name */
|
||||
#define APFS_FS_UNKNOWN_200 0x00000200LL
|
||||
#define APFS_FS_FLAGS_VALID_MASK (APFS_FS_UNENCRYPTED \
|
||||
| APFS_FS_EFFACEABLE \
|
||||
| APFS_FS_RESERVED_4 \
|
||||
| APFS_FS_ONEKEY \
|
||||
| APFS_FS_SPILLEDOVER \
|
||||
| APFS_FS_RUN_SPILLOVER_CLEANER \
|
||||
| APFS_FS_ALWAYS_CHECK_EXTENTREF)
|
||||
| APFS_FS_EFFACEABLE \
|
||||
| APFS_FS_RESERVED_4 \
|
||||
| APFS_FS_ONEKEY \
|
||||
| APFS_FS_SPILLEDOVER \
|
||||
| APFS_FS_RUN_SPILLOVER_CLEANER \
|
||||
| APFS_FS_ALWAYS_CHECK_EXTENTREF \
|
||||
| APFS_FS_PREVIOUSLY_SEALED \
|
||||
| APFS_FS_PFK \
|
||||
| APFS_FS_UNKNOWN_200)
|
||||
|
||||
#define APFS_FS_CRYPTOFLAGS (APFS_FS_UNENCRYPTED \
|
||||
| APFS_FS_EFFACEABLE \
|
||||
@@ -1124,7 +1134,9 @@ struct apfs_checkpoint_map_phys {
|
||||
#define APFS_INCOMPAT_NORMALIZATION_INSENSITIVE 0x00000008LL
|
||||
#define APFS_INCOMPAT_INCOMPLETE_RESTORE 0x00000010LL
|
||||
#define APFS_INCOMPAT_SEALED_VOLUME 0x00000020LL
|
||||
#define APFS_INCOMPAT_RESERVED_40 0x00000040LL
|
||||
#define APFS_INCOMPAT_PFK 0x00000040LL /* Made-up name */
|
||||
#define APFS_INCOMPAT_EXTENT_PREALLOC_FLAG 0x00000080LL /* Made-up name */
|
||||
#define APFS_INCOMPAT_SECONDARY_FSROOT 0x00000100LL /* Made-up name */
|
||||
|
||||
#define APFS_SUPPORTED_INCOMPAT_MASK (APFS_INCOMPAT_CASE_INSENSITIVE \
|
||||
| APFS_INCOMPAT_DATALESS_SNAPS \
|
||||
@@ -1132,7 +1144,9 @@ struct apfs_checkpoint_map_phys {
|
||||
| APFS_INCOMPAT_NORMALIZATION_INSENSITIVE \
|
||||
| APFS_INCOMPAT_INCOMPLETE_RESTORE \
|
||||
| APFS_INCOMPAT_SEALED_VOLUME \
|
||||
| APFS_INCOMPAT_RESERVED_40)
|
||||
| APFS_INCOMPAT_PFK \
|
||||
| APFS_INCOMPAT_EXTENT_PREALLOC_FLAG \
|
||||
| APFS_INCOMPAT_SECONDARY_FSROOT)
|
||||
|
||||
#define APFS_MODIFIED_NAMELEN 32
|
||||
|
||||
@@ -1162,6 +1176,18 @@ struct apfs_modified_by {
|
||||
#define APFS_CRYPTO_RESERVED_5 5
|
||||
#define APFS_UNASSIGNED_CRYPTO_ID (~0ULL)
|
||||
|
||||
/* Doc id index flags. I'm making up the names for now. */
|
||||
#define APFS_DOC_ID_HAS_PREV_TREE 0x00000001
|
||||
#define APFS_DOC_ID_UNKNOWN_02 0x00000002
|
||||
#define APFS_DOC_ID_UNKNOWN_04 0x00000004
|
||||
#define APFS_DOC_ID_UNKNOWN_08 0x00000008
|
||||
#define APFS_DOC_ID_UNKNOWN_10 0x00000010
|
||||
#define APFS_DOC_ID_VALID_FLAGS (APFS_DOC_ID_HAS_PREV_TREE \
|
||||
| APFS_DOC_ID_UNKNOWN_02 \
|
||||
| APFS_DOC_ID_UNKNOWN_04 \
|
||||
| APFS_DOC_ID_UNKNOWN_08 \
|
||||
| APFS_DOC_ID_UNKNOWN_10)
|
||||
|
||||
/*
|
||||
* Structure used to store the encryption state
|
||||
*/
|
||||
@@ -1241,15 +1267,24 @@ struct apfs_superblock {
|
||||
|
||||
__le64 apfs_snap_meta_ext_oid;
|
||||
|
||||
char apfs_volume_group_id[UUID_SIZE];
|
||||
/*3F0*/ char apfs_volume_group_id[UUID_SIZE];
|
||||
|
||||
__le64 apfs_integrity_meta_oid;
|
||||
/*400*/ __le64 apfs_integrity_meta_oid;
|
||||
|
||||
__le64 apfs_fext_tree_oid;
|
||||
__le32 apfs_fext_tree_type;
|
||||
/*410*/ __le32 apfs_fext_tree_type;
|
||||
|
||||
__le32 reserved_type;
|
||||
__le64 reserved_oid;
|
||||
|
||||
/*420*/ __le64 apfs_doc_id_index_xid;
|
||||
__le32 apfs_doc_id_index_flags;
|
||||
__le32 apfs_doc_id_tree_type;
|
||||
/*430*/ __le64 apfs_doc_id_tree_oid; /* Made-up name */
|
||||
__le64 apfs_prev_doc_id_tree_oid;
|
||||
__le64 apfs_doc_id_fixup_cursor;
|
||||
__le64 apfs_sec_root_tree_oid;
|
||||
/*450*/ __le32 apfs_sec_root_tree_type;
|
||||
} __packed;
|
||||
|
||||
/* Extended attributes constants */
|
||||
@@ -1268,9 +1303,10 @@ enum {
|
||||
APFS_XATTR_DATA_EMBEDDED = 0x00000002,
|
||||
APFS_XATTR_FILE_SYSTEM_OWNED = 0x00000004,
|
||||
APFS_XATTR_RESERVED_8 = 0x00000008,
|
||||
APFS_XATTR_UNKNOWN_10 = 0x00000010,
|
||||
};
|
||||
|
||||
#define APFS_XATTR_VALID_FLAGS 0x0000000f
|
||||
#define APFS_XATTR_VALID_FLAGS 0x0000001f
|
||||
|
||||
/*
|
||||
* Structure of the value of an extended attributes record
|
||||
@@ -1438,6 +1474,8 @@ struct apfs_compress_rsrc_data {
|
||||
} __packed block[];
|
||||
} __packed;
|
||||
|
||||
#define APFS_FUSION_TIER2_DEVICE_BYTE_ADDR 0x4000000000000000ULL
|
||||
|
||||
/*
|
||||
* TODO: this is a placeholder, create some snapshots with the official
|
||||
* implementation to find the actual limit.
|
||||
@@ -1459,6 +1497,12 @@ struct apfs_snap_metadata_val {
|
||||
u8 name[];
|
||||
} __packed;
|
||||
|
||||
/* Snapshot metadata record flags */
|
||||
enum {
|
||||
APFS_SNAP_META_PENDING_DATALESS = 0x00000001,
|
||||
APFS_SNAP_MERGE_IN_PROGRESS = 0x00000002,
|
||||
};
|
||||
|
||||
/*
|
||||
* Structure of the value of a snapshot name record
|
||||
*/
|
||||
|
||||
@@ -50,7 +50,7 @@ static int apfs_child_from_query(struct apfs_query *query, u64 *child)
|
||||
index_val = (struct apfs_btn_index_node_val *)(raw + query->off);
|
||||
*child = le64_to_cpu(index_val->binv_child_oid) + apfs_catalog_base_oid(query);
|
||||
} else {
|
||||
if (query->len != 8) { /* The data on a nonleaf node is the child id */
|
||||
if (query->len != 8) { /* The value on a nonleaf node is the child id */
|
||||
apfs_err(sb, "bad index value length (%d)", query->len);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
@@ -398,8 +398,6 @@ struct apfs_query *apfs_alloc_query(struct apfs_node *node,
|
||||
|
||||
/* To be released by free_query. */
|
||||
query->node = node;
|
||||
/* Start the search with the last record and go backwards */
|
||||
query->index = node->records;
|
||||
|
||||
if (parent) {
|
||||
query->key = parent->key;
|
||||
@@ -408,6 +406,15 @@ struct apfs_query *apfs_alloc_query(struct apfs_node *node,
|
||||
query->depth = parent->depth + 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* We start the search with the last record and go backwards, but
|
||||
* some queries later use the PREV flag later to list them in order.
|
||||
*/
|
||||
if (query->flags & APFS_QUERY_PREV)
|
||||
query->index = -1;
|
||||
else
|
||||
query->index = node->records;
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
@@ -514,7 +521,8 @@ next_node:
|
||||
* than enough to map every block.
|
||||
*/
|
||||
apfs_err(sb, "btree is too high");
|
||||
return -EFSCORRUPTED;
|
||||
err = -EFSCORRUPTED;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
err = apfs_node_query(sb, *query);
|
||||
@@ -526,12 +534,16 @@ next_node:
|
||||
err = apfs_query_set_before_first(sb, query);
|
||||
if (err) {
|
||||
apfs_err(sb, "failed to set before the first record");
|
||||
return err;
|
||||
goto fail;
|
||||
}
|
||||
return -ENODATA;
|
||||
err = -ENODATA;
|
||||
goto fail;
|
||||
} else if (err == -EAGAIN) {
|
||||
if (!(*query)->parent) /* We are at the root of the tree */
|
||||
return -ENODATA;
|
||||
if (!(*query)->parent) {
|
||||
/* We are at the root of the tree */
|
||||
err = -ENODATA;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Move back up one level and continue the query */
|
||||
parent = (*query)->parent;
|
||||
@@ -540,7 +552,7 @@ next_node:
|
||||
*query = parent;
|
||||
goto next_node;
|
||||
} else if (err) {
|
||||
return err;
|
||||
goto fail;
|
||||
}
|
||||
if (apfs_node_is_leaf((*query)->node)) /* All done */
|
||||
return 0;
|
||||
@@ -549,14 +561,15 @@ next_node:
|
||||
if (err) {
|
||||
apfs_alert(sb, "bad index block: 0x%llx",
|
||||
(*query)->node->object.block_nr);
|
||||
return err;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
/* Now go a level deeper and search the child */
|
||||
node = apfs_read_node(sb, child_id, storage, false /* write */);
|
||||
if (IS_ERR(node)) {
|
||||
apfs_err(sb, "failed to read node 0x%llx", child_id);
|
||||
return PTR_ERR(node);
|
||||
err = PTR_ERR(node);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if (node->object.oid != child_id)
|
||||
@@ -571,10 +584,16 @@ next_node:
|
||||
if (!*query) {
|
||||
apfs_node_free(node);
|
||||
*query = parent;
|
||||
return -ENOMEM;
|
||||
err = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
node = NULL;
|
||||
goto next_node;
|
||||
|
||||
fail:
|
||||
/* Don't leave stale record info here or some callers will use it */
|
||||
(*query)->key_len = (*query)->len = 0;
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __apfs_btree_replace(struct apfs_query *query, void *key, int key_len, void *val, int val_len);
|
||||
@@ -589,11 +608,22 @@ int apfs_query_join_transaction(struct apfs_query *query)
|
||||
struct super_block *sb = node->object.sb;
|
||||
u64 oid = node->object.oid;
|
||||
u32 storage = apfs_query_storage(query);
|
||||
struct apfs_obj_phys *raw = NULL;
|
||||
|
||||
/*
|
||||
* Ephemeral objects are checkpoint data, and all of their xids get
|
||||
* updated on commit. There is no real need to do it here as well, but
|
||||
* it's better for consistency with the other object types.
|
||||
*/
|
||||
if (storage == APFS_OBJ_EPHEMERAL) {
|
||||
ASSERT(node->object.ephemeral);
|
||||
raw = (void *)node->object.data;
|
||||
raw->o_xid = cpu_to_le64(APFS_NXI(sb)->nx_xid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (buffer_trans(node->object.o_bh)) /* Already in the transaction */
|
||||
return 0;
|
||||
/* Ephemeral objects are always checkpoint data */
|
||||
ASSERT(storage != APFS_OBJ_EPHEMERAL);
|
||||
/* Root nodes should join the transaction before the query is created */
|
||||
ASSERT(!apfs_node_is_root(node));
|
||||
|
||||
@@ -1121,3 +1151,24 @@ int apfs_btree_replace(struct apfs_query *query, void *key, int key_len, void *v
|
||||
apfs_btree_change_rec_count(query, 0 /* change */, key_len, val_len);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* apfs_query_direct_forward - Set a query to start listing records forwards
|
||||
* @query: a successfully executed query
|
||||
*
|
||||
* Multiple queries list records backwards, but queries marked with this
|
||||
* function after execution will go in the opposite direction.
|
||||
*/
|
||||
void apfs_query_direct_forward(struct apfs_query *query)
|
||||
{
|
||||
if (query->flags & APFS_QUERY_PREV)
|
||||
return;
|
||||
|
||||
apfs_assert_query_is_valid(query);
|
||||
ASSERT(apfs_node_is_leaf(query->node));
|
||||
|
||||
while (query) {
|
||||
query->flags |= APFS_QUERY_PREV;
|
||||
query = query->parent;
|
||||
}
|
||||
}
|
||||
+9
-5
@@ -409,7 +409,7 @@ static ssize_t apfs_compress_file_read_page(struct file *filp, char *buf, loff_t
|
||||
return step;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0)
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0) || RHEL_VERSION_GE(9, 3)
|
||||
static int apfs_compress_read_folio(struct file *filp, struct folio *folio)
|
||||
{
|
||||
struct page *page = &folio->page;
|
||||
@@ -417,16 +417,20 @@ static int apfs_compress_read_folio(struct file *filp, struct folio *folio)
|
||||
static int apfs_compress_readpage(struct file *filp, struct page *page)
|
||||
{
|
||||
#endif
|
||||
void *addr = NULL;
|
||||
char *addr = NULL;
|
||||
ssize_t ret;
|
||||
loff_t off;
|
||||
|
||||
/* Mostly copied from ext4_read_inline_page() */
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 16, 0)
|
||||
off = page_folio(page)->index << PAGE_SHIFT;
|
||||
#else
|
||||
off = page->index << PAGE_SHIFT;
|
||||
addr = kmap_atomic(page);
|
||||
#endif
|
||||
addr = kmap(page);
|
||||
ret = apfs_compress_file_read_page(filp, addr, off);
|
||||
flush_dcache_page(page);
|
||||
kunmap_atomic(addr);
|
||||
kunmap(page);
|
||||
if (ret >= 0) {
|
||||
zero_user_segment(page, ret, PAGE_SIZE);
|
||||
SetPageUptodate(page);
|
||||
@@ -438,7 +442,7 @@ static int apfs_compress_readpage(struct file *filp, struct page *page)
|
||||
}
|
||||
|
||||
const struct address_space_operations apfs_compress_aops = {
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0)
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0) || RHEL_VERSION_GE(9, 3)
|
||||
.read_folio = apfs_compress_read_folio,
|
||||
#else
|
||||
.readpage = apfs_compress_readpage,
|
||||
|
||||
@@ -261,7 +261,7 @@ const struct file_operations apfs_dir_operations = {
|
||||
*
|
||||
* Returns the length of the key, or a negative error code in case of failure.
|
||||
*/
|
||||
static int apfs_build_dentry_unhashed_key(struct qstr *qname, u64 parent_id,
|
||||
static int apfs_build_dentry_unhashed_key(const struct qstr *qname, u64 parent_id,
|
||||
struct apfs_drec_key **key_p)
|
||||
{
|
||||
struct apfs_drec_key *key;
|
||||
@@ -290,7 +290,7 @@ static int apfs_build_dentry_unhashed_key(struct qstr *qname, u64 parent_id,
|
||||
*
|
||||
* Returns the length of the key, or a negative error code in case of failure.
|
||||
*/
|
||||
static int apfs_build_dentry_hashed_key(struct qstr *qname, u64 hash, u64 parent_id,
|
||||
static int apfs_build_dentry_hashed_key(const struct qstr *qname, u64 hash, u64 parent_id,
|
||||
struct apfs_drec_hashed_key **key_p)
|
||||
{
|
||||
struct apfs_drec_hashed_key *key;
|
||||
@@ -363,7 +363,7 @@ static int apfs_build_dentry_val(struct inode *inode, u64 sibling_id,
|
||||
*
|
||||
* Returns 0 on success or a negative error code in case of failure.
|
||||
*/
|
||||
static int apfs_create_dentry_rec(struct inode *inode, struct qstr *qname,
|
||||
static int apfs_create_dentry_rec(struct inode *inode, const struct qstr *qname,
|
||||
u64 parent_id, u64 sibling_id)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
@@ -414,7 +414,6 @@ fail:
|
||||
apfs_free_query(query);
|
||||
return ret;
|
||||
}
|
||||
#define APFS_CREATE_DENTRY_REC_MAXOPS 1
|
||||
|
||||
/**
|
||||
* apfs_build_sibling_val - Allocate and initialize a sibling link's value
|
||||
@@ -427,7 +426,7 @@ static int apfs_build_sibling_val(struct dentry *dentry,
|
||||
struct apfs_sibling_val **val_p)
|
||||
{
|
||||
struct apfs_sibling_val *val;
|
||||
struct qstr *qname = &dentry->d_name;
|
||||
const struct qstr *qname = &dentry->d_name;
|
||||
u16 namelen = qname->len + 1; /* We count the null-termination */
|
||||
struct inode *parent = d_inode(dentry->d_parent);
|
||||
int val_len;
|
||||
@@ -491,7 +490,6 @@ fail:
|
||||
apfs_free_query(query);
|
||||
return ret;
|
||||
}
|
||||
#define APFS_CREATE_SIBLING_LINK_REC_MAXOPS 1
|
||||
|
||||
/**
|
||||
* apfs_create_sibling_map_rec - Create a sibling map record for a dentry
|
||||
@@ -534,7 +532,6 @@ fail:
|
||||
apfs_free_query(query);
|
||||
return ret;
|
||||
}
|
||||
#define APFS_CREATE_SIBLING_MAP_REC_MAXOPS 1
|
||||
|
||||
/**
|
||||
* apfs_create_sibling_recs - Create sibling link and map records for a dentry
|
||||
@@ -567,8 +564,6 @@ static int apfs_create_sibling_recs(struct dentry *dentry,
|
||||
*sibling_id = cnid;
|
||||
return 0;
|
||||
}
|
||||
#define APFS_CREATE_SIBLING_RECS_MAXOPS (APFS_CREATE_SIBLING_LINK_REC_MAXOPS + \
|
||||
APFS_CREATE_SIBLING_MAP_REC_MAXOPS)
|
||||
|
||||
/**
|
||||
* apfs_create_dentry - Create all records for a new dentry
|
||||
@@ -613,9 +608,6 @@ static int apfs_create_dentry(struct dentry *dentry, struct inode *inode)
|
||||
apfs_inode_join_transaction(parent->i_sb, parent);
|
||||
return 0;
|
||||
}
|
||||
#define APFS_CREATE_DENTRY_MAXOPS (APFS_CREATE_SIBLING_RECS_MAXOPS + \
|
||||
APFS_CREATE_DENTRY_REC_MAXOPS + \
|
||||
APFS_UPDATE_INODE_MAXOPS())
|
||||
|
||||
/**
|
||||
* apfs_undo_create_dentry - Clean up apfs_create_dentry()
|
||||
@@ -643,15 +635,9 @@ int apfs_mkany(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
{
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct inode *inode;
|
||||
struct apfs_max_ops maxops;
|
||||
int err;
|
||||
|
||||
maxops.cat = APFS_CREATE_INODE_REC_MAXOPS() + APFS_CREATE_DENTRY_MAXOPS;
|
||||
if (symname)
|
||||
maxops.cat += APFS_XATTR_SET_MAXOPS();
|
||||
maxops.blks = 0;
|
||||
|
||||
err = apfs_transaction_start(sb, maxops);
|
||||
err = apfs_transaction_start(sb, APFS_TRANS_REG);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -712,7 +698,7 @@ out_abort:
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 12, 0)
|
||||
int apfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
dev_t rdev)
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0) && !RHEL_VERSION_GE(9, 6)
|
||||
int apfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, dev_t rdev)
|
||||
#else
|
||||
@@ -730,7 +716,7 @@ int apfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
return apfs_mknod(dir, dentry, mode | S_IFDIR, 0 /* rdev */);
|
||||
}
|
||||
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0) && !RHEL_VERSION_GE(9, 6)
|
||||
|
||||
int apfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode)
|
||||
@@ -738,7 +724,7 @@ int apfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
return apfs_mknod(mnt_userns, dir, dentry, mode | S_IFDIR, 0 /* rdev */);
|
||||
}
|
||||
|
||||
#else
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(6, 15, 0)
|
||||
|
||||
int apfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode)
|
||||
@@ -746,6 +732,13 @@ int apfs_mkdir(struct mnt_idmap *idmap, struct inode *dir,
|
||||
return apfs_mknod(idmap, dir, dentry, mode | S_IFDIR, 0 /* rdev */);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
struct dentry *apfs_mkdir(struct mnt_idmap *idmap, struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
return ERR_PTR(apfs_mknod(idmap, dir, dentry, mode | S_IFDIR, 0 /* rdev */));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -757,7 +750,7 @@ int apfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
return apfs_mknod(dir, dentry, mode, 0 /* rdev */);
|
||||
}
|
||||
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0) && !RHEL_VERSION_GE(9, 6)
|
||||
|
||||
int apfs_create(struct user_namespace *mnt_userns, struct inode *dir,
|
||||
struct dentry *dentry, umode_t mode, bool excl)
|
||||
@@ -818,8 +811,6 @@ static int apfs_prepare_dentry_for_link(struct dentry *dentry)
|
||||
return apfs_create_dentry_rec(d_inode(dentry), &dentry->d_name,
|
||||
apfs_ino(parent), sibling_id);
|
||||
}
|
||||
#define APFS_PREPARE_DENTRY_FOR_LINK_MAXOPS (1 + APFS_CREATE_SIBLING_RECS_MAXOPS + \
|
||||
APFS_CREATE_DENTRY_REC_MAXOPS)
|
||||
|
||||
/**
|
||||
* __apfs_undo_link - Clean up __apfs_link()
|
||||
@@ -875,22 +866,15 @@ fail:
|
||||
drop_nlink(inode);
|
||||
return err;
|
||||
}
|
||||
#define __APFS_LINK_MAXOPS (APFS_UPDATE_INODE_MAXOPS() + \
|
||||
APFS_PREPARE_DENTRY_FOR_LINK_MAXOPS + \
|
||||
APFS_CREATE_DENTRY_MAXOPS)
|
||||
|
||||
int apfs_link(struct dentry *old_dentry, struct inode *dir,
|
||||
struct dentry *dentry)
|
||||
{
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct inode *inode = d_inode(old_dentry);
|
||||
struct apfs_max_ops maxops;
|
||||
int err;
|
||||
|
||||
maxops.cat = __APFS_LINK_MAXOPS;
|
||||
maxops.blks = 0;
|
||||
|
||||
err = apfs_transaction_start(sb, maxops);
|
||||
err = apfs_transaction_start(sb, APFS_TRANS_REG);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -954,7 +938,6 @@ fail:
|
||||
apfs_free_query(query);
|
||||
return ret;
|
||||
}
|
||||
#define APFS_DELETE_SIBLING_LINK_REC_MAXOPS 1
|
||||
|
||||
/**
|
||||
* apfs_delete_sibling_map_rec - Delete the sibling map record for a dentry
|
||||
@@ -995,7 +978,6 @@ fail:
|
||||
apfs_free_query(query);
|
||||
return ret;
|
||||
}
|
||||
#define APFS_DELETE_SIBLING_MAP_REC_MAXOPS 1
|
||||
|
||||
/**
|
||||
* apfs_delete_dentry - Delete all records for a dentry
|
||||
@@ -1048,9 +1030,6 @@ static int apfs_delete_dentry(struct dentry *dentry)
|
||||
apfs_inode_join_transaction(sb, parent);
|
||||
return err;
|
||||
}
|
||||
#define APFS_DELETE_DENTRY_MAXOPS (1 + APFS_DELETE_SIBLING_LINK_REC_MAXOPS + \
|
||||
APFS_DELETE_SIBLING_MAP_REC_MAXOPS + \
|
||||
APFS_UPDATE_INODE_MAXOPS())
|
||||
|
||||
/**
|
||||
* apfs_undo_delete_dentry - Clean up apfs_delete_dentry()
|
||||
@@ -1158,13 +1137,13 @@ fail:
|
||||
|
||||
/**
|
||||
* apfs_orphan_name - Get the name for an orphan inode's invisible link
|
||||
* @inode: the vfs inode
|
||||
* @qname: on return, the name assigned to the link
|
||||
* @ino: the inode number
|
||||
* @qname: on return, the name assigned to the link
|
||||
*
|
||||
* Returns 0 on success; the caller must remember to free @qname->name after
|
||||
* use. Returns a negative error code in case of failure.
|
||||
*/
|
||||
static int apfs_orphan_name(struct inode *inode, struct qstr *qname)
|
||||
static int apfs_orphan_name(u64 ino, struct qstr *qname)
|
||||
{
|
||||
int max_len;
|
||||
char *name;
|
||||
@@ -1174,7 +1153,7 @@ static int apfs_orphan_name(struct inode *inode, struct qstr *qname)
|
||||
name = kmalloc(max_len, GFP_KERNEL);
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
qname->len = snprintf(name, max_len, "0x%llx-dead", apfs_ino(inode));
|
||||
qname->len = snprintf(name, max_len, "0x%llx-dead", ino);
|
||||
qname->name = name;
|
||||
return 0;
|
||||
}
|
||||
@@ -1193,7 +1172,7 @@ static int apfs_create_orphan_link(struct inode *inode)
|
||||
struct qstr qname;
|
||||
int err = 0;
|
||||
|
||||
err = apfs_orphan_name(inode, &qname);
|
||||
err = apfs_orphan_name(apfs_ino(inode), &qname);
|
||||
if (err)
|
||||
return err;
|
||||
err = apfs_create_dentry_rec(inode, &qname, apfs_ino(priv_dir), 0 /* sibling_id */);
|
||||
@@ -1217,8 +1196,6 @@ fail:
|
||||
kfree(qname.name);
|
||||
return err;
|
||||
}
|
||||
#define APFS_CREATE_ORPHAN_LINK_MAXOPS (APFS_CREATE_DENTRY_REC_MAXOPS + \
|
||||
APFS_UPDATE_INODE_MAXOPS())
|
||||
|
||||
/**
|
||||
* apfs_delete_orphan_link - Delete the link for an orphan inode
|
||||
@@ -1236,7 +1213,7 @@ int apfs_delete_orphan_link(struct inode *inode)
|
||||
struct apfs_drec drec;
|
||||
int err;
|
||||
|
||||
err = apfs_orphan_name(inode, &qname);
|
||||
err = apfs_orphan_name(apfs_ino(inode), &qname);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -1269,10 +1246,6 @@ fail:
|
||||
kfree(qname.name);
|
||||
return err;
|
||||
}
|
||||
int APFS_DELETE_ORPHAN_LINK_MAXOPS(void)
|
||||
{
|
||||
return 1 + APFS_UPDATE_INODE_MAXOPS();
|
||||
}
|
||||
|
||||
/**
|
||||
* __apfs_undo_unlink - Clean up __apfs_unlink()
|
||||
@@ -1282,9 +1255,10 @@ static void __apfs_undo_unlink(struct dentry *dentry)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
|
||||
inode->i_state |= I_LINKABLE; /* Silence warning about nlink 0->1 */
|
||||
/* Silence warning about nlink 0->1 */
|
||||
apfs_inode_state_set_raw(inode, I_LINKABLE);
|
||||
inc_nlink(inode);
|
||||
inode->i_state &= ~I_LINKABLE;
|
||||
apfs_inode_state_clear_raw(inode, I_LINKABLE);
|
||||
|
||||
apfs_undo_delete_dentry(dentry);
|
||||
}
|
||||
@@ -1368,20 +1342,13 @@ fail:
|
||||
__apfs_undo_unlink(dentry);
|
||||
return err;
|
||||
}
|
||||
#define __APFS_UNLINK_MAXOPS (APFS_DELETE_DENTRY_MAXOPS + \
|
||||
APFS_CREATE_ORPHAN_LINK_MAXOPS + \
|
||||
APFS_UPDATE_INODE_MAXOPS())
|
||||
|
||||
int apfs_unlink(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct apfs_max_ops maxops;
|
||||
int err;
|
||||
|
||||
maxops.cat = __APFS_UNLINK_MAXOPS;
|
||||
maxops.blks = 0;
|
||||
|
||||
err = apfs_transaction_start(sb, maxops);
|
||||
err = apfs_transaction_start(sb, APFS_TRANS_DEL);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -1414,7 +1381,7 @@ int apfs_rmdir(struct inode *dir, struct dentry *dentry)
|
||||
int apfs_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags)
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0)
|
||||
#elif LINUX_VERSION_CODE < KERNEL_VERSION(6, 3, 0) && !RHEL_VERSION_GE(9, 6)
|
||||
int apfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
|
||||
struct dentry *old_dentry, struct inode *new_dir,
|
||||
struct dentry *new_dentry, unsigned int flags)
|
||||
@@ -1427,7 +1394,6 @@ int apfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
|
||||
struct super_block *sb = old_dir->i_sb;
|
||||
struct inode *old_inode = d_inode(old_dentry);
|
||||
struct inode *new_inode = d_inode(new_dentry);
|
||||
struct apfs_max_ops maxops;
|
||||
int err;
|
||||
|
||||
if (new_inode && APFS_I(new_inode)->i_nchildren)
|
||||
@@ -1436,12 +1402,7 @@ int apfs_rename(struct mnt_idmap *idmap, struct inode *old_dir,
|
||||
if (flags & ~RENAME_NOREPLACE) /* TODO: support RENAME_EXCHANGE */
|
||||
return -EINVAL;
|
||||
|
||||
maxops.cat = __APFS_UNLINK_MAXOPS + __APFS_LINK_MAXOPS;
|
||||
if (new_inode)
|
||||
maxops.cat += __APFS_UNLINK_MAXOPS;
|
||||
maxops.blks = 0;
|
||||
|
||||
err = apfs_transaction_start(sb, maxops);
|
||||
err = apfs_transaction_start(sb, APFS_TRANS_REG);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
@@ -1481,3 +1442,64 @@ out_abort:
|
||||
apfs_transaction_abort(sb);
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* apfs_any_orphan_ino - Find the inode number for any orphaned regular file
|
||||
* @sb: filesytem superblock
|
||||
* @ino_p: on return, the inode number found
|
||||
*
|
||||
* Returns 0 on success, or a negative error code in case of failure, which may
|
||||
* be -ENODATA if there are no orphan files.
|
||||
*/
|
||||
u64 apfs_any_orphan_ino(struct super_block *sb, u64 *ino_p)
|
||||
{
|
||||
struct apfs_sb_info *sbi = APFS_SB(sb);
|
||||
struct apfs_query *query = NULL;
|
||||
struct apfs_drec drec = {0};
|
||||
struct qstr qname = {0};
|
||||
bool hashed = apfs_is_normalization_insensitive(sb);
|
||||
bool found = false;
|
||||
int err;
|
||||
|
||||
query = apfs_alloc_query(sbi->s_cat_root, NULL /* parent */);
|
||||
if (!query)
|
||||
return -ENOMEM;
|
||||
apfs_init_drec_key(sb, APFS_PRIV_DIR_INO_NUM, NULL /* name */, 0 /* name_len */, &query->key);
|
||||
query->flags = APFS_QUERY_CAT | APFS_QUERY_MULTIPLE | APFS_QUERY_EXACT;
|
||||
|
||||
while (!found) {
|
||||
err = apfs_btree_query(sb, &query);
|
||||
if (err) {
|
||||
if (err == -ENODATA)
|
||||
goto out;
|
||||
apfs_err(sb, "drec query failed for private dir");
|
||||
goto out;
|
||||
}
|
||||
err = apfs_drec_from_query(query, &drec, hashed);
|
||||
if (err) {
|
||||
apfs_alert(sb, "bad dentry record in private dir");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* These files are deleted immediately by ->evict_inode() */
|
||||
if (drec.type != DT_REG)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Confirm that this is an orphan file, because the official
|
||||
* reference allows other uses for the private directory.
|
||||
*/
|
||||
err = apfs_orphan_name(drec.ino, &qname);
|
||||
if (err)
|
||||
goto out;
|
||||
found = strcmp(drec.name, qname.name) == 0;
|
||||
kfree(qname.name);
|
||||
qname.name = NULL;
|
||||
}
|
||||
*ino_p = drec.ino;
|
||||
|
||||
out:
|
||||
apfs_free_query(query);
|
||||
query = NULL;
|
||||
return err;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
PACKAGE_NAME="linux-apfs-rw"
|
||||
PACKAGE_VERSION="0.3.7"
|
||||
PACKAGE_VERSION="0.3.21"
|
||||
|
||||
BUILT_MODULE_NAME[0]="apfs"
|
||||
DEST_MODULE_LOCATION[0]="/extra"
|
||||
|
||||
@@ -8,8 +8,6 @@
|
||||
#include <linux/blk_types.h>
|
||||
#include "apfs.h"
|
||||
|
||||
#define MAX(X, Y) ((X) <= (Y) ? (Y) : (X))
|
||||
|
||||
/**
|
||||
* apfs_ext_is_hole - Does this extent represent a hole in a sparse file?
|
||||
* @extent: the extent to check
|
||||
@@ -387,7 +385,7 @@ static int apfs_shrink_extent_tail(struct apfs_query *query, struct apfs_dstream
|
||||
}
|
||||
|
||||
/**
|
||||
* apfs_query_found_extent - Is this query pointing to an extent record?
|
||||
* apfs_query_found_extent - Did this query find an extent with the right id?
|
||||
* @query: the (successful) query that found the record
|
||||
*/
|
||||
static inline bool apfs_query_found_extent(struct apfs_query *query)
|
||||
@@ -398,7 +396,12 @@ static inline bool apfs_query_found_extent(struct apfs_query *query)
|
||||
if (query->key_len < sizeof(*hdr))
|
||||
return false;
|
||||
hdr = raw + query->key_off;
|
||||
return apfs_cat_type(hdr) == APFS_TYPE_FILE_EXTENT;
|
||||
|
||||
if (apfs_cat_type(hdr) != APFS_TYPE_FILE_EXTENT)
|
||||
return false;
|
||||
if (apfs_cat_cnid(hdr) != query->key.id)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -755,7 +758,6 @@ static int apfs_update_extent(struct apfs_dstream_info *dstream, const struct ap
|
||||
}
|
||||
return apfs_update_mid_extent(dstream, extent);
|
||||
}
|
||||
#define APFS_UPDATE_EXTENTS_MAXOPS (1 + 2 * APFS_CRYPTO_ADJ_REFCNT_MAXOPS())
|
||||
|
||||
static int apfs_extend_phys_extent(struct apfs_query *query, u64 bno, u64 blkcnt, u64 dstream_id)
|
||||
{
|
||||
@@ -1133,7 +1135,6 @@ int apfs_flush_extent_cache(struct apfs_dstream_info *dstream)
|
||||
dstream->ds_ext_dirty = false;
|
||||
return 0;
|
||||
}
|
||||
#define APFS_FLUSH_EXTENT_CACHE APFS_UPDATE_EXTENTS_MAXOPS
|
||||
|
||||
/**
|
||||
* apfs_create_hole - Create and insert a hole extent for the dstream
|
||||
@@ -1448,10 +1449,6 @@ static int apfs_dstream_get_new_block(struct apfs_dstream_info *dstream, u64 dsb
|
||||
dstream->ds_ext_dirty = true;
|
||||
return 0;
|
||||
}
|
||||
int APFS_GET_NEW_BLOCK_MAXOPS(void)
|
||||
{
|
||||
return APFS_FLUSH_EXTENT_CACHE;
|
||||
}
|
||||
|
||||
/**
|
||||
* apfs_dstream_get_new_bno - Allocate a new block inside a dstream
|
||||
@@ -1625,6 +1622,125 @@ int apfs_truncate(struct apfs_dstream_info *dstream, loff_t new_size)
|
||||
return apfs_create_hole(dstream, old_blks, new_blks);
|
||||
}
|
||||
|
||||
/**
|
||||
* apfs_dstream_delete_front - Deletes as many leading extents as possible
|
||||
* @sb: filesystem superblock
|
||||
* @ds_id: id for the dstream to delete
|
||||
*
|
||||
* Returns 0 on success, or a negative error code in case of failure, which may
|
||||
* be -ENODATA if there are no more extents, or -EAGAIN if the free queue is
|
||||
* getting too full.
|
||||
*/
|
||||
static int apfs_dstream_delete_front(struct super_block *sb, u64 ds_id)
|
||||
{
|
||||
struct apfs_sb_info *sbi = APFS_SB(sb);
|
||||
struct apfs_spaceman *sm = APFS_SM(sb);
|
||||
struct apfs_spaceman_phys *sm_raw = sm->sm_raw;
|
||||
struct apfs_spaceman_free_queue *fq = NULL;
|
||||
struct apfs_query *query = NULL;
|
||||
struct apfs_file_extent head;
|
||||
bool first_match = true;
|
||||
int ret;
|
||||
|
||||
fq = &sm_raw->sm_fq[APFS_SFQ_MAIN];
|
||||
if (le64_to_cpu(fq->sfq_count) > APFS_TRANS_MAIN_QUEUE_MAX)
|
||||
return -EAGAIN;
|
||||
|
||||
query = apfs_alloc_query(sbi->s_cat_root, NULL /* parent */);
|
||||
if (!query)
|
||||
return -ENOMEM;
|
||||
apfs_init_file_extent_key(ds_id, 0, &query->key);
|
||||
query->flags = APFS_QUERY_CAT;
|
||||
|
||||
next_extent:
|
||||
ret = apfs_btree_query(sb, &query);
|
||||
if (ret && ret != -ENODATA) {
|
||||
apfs_err(sb, "query failed for first extent of id 0x%llx", ds_id);
|
||||
goto out;
|
||||
}
|
||||
apfs_query_direct_forward(query);
|
||||
if (!apfs_query_found_extent(query)) {
|
||||
/*
|
||||
* After the original lookup, the query may not be set to the
|
||||
* first extent, but instead to the record that comes right
|
||||
* before.
|
||||
*/
|
||||
if (first_match) {
|
||||
first_match = false;
|
||||
goto next_extent;
|
||||
}
|
||||
ret = -ENODATA;
|
||||
goto out;
|
||||
}
|
||||
first_match = false;
|
||||
|
||||
ret = apfs_extent_from_query(query, &head);
|
||||
if (ret) {
|
||||
apfs_err(sb, "bad head extent record on dstream 0x%llx", ds_id);
|
||||
goto out;
|
||||
}
|
||||
ret = apfs_btree_remove(query);
|
||||
if (ret) {
|
||||
apfs_err(sb, "removal failed for id 0x%llx, addr 0x%llx", ds_id, head.logical_addr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* The official fsck doesn't complain about wrong sparse byte counts
|
||||
* for orphans, so I guess we don't need to update them here
|
||||
*/
|
||||
if (!apfs_ext_is_hole(&head)) {
|
||||
ret = apfs_range_put_reference(sb, head.phys_block_num, head.len);
|
||||
if (ret) {
|
||||
apfs_err(sb, "failed to put range 0x%llx-0x%llx", head.phys_block_num, head.len);
|
||||
goto out;
|
||||
}
|
||||
ret = apfs_crypto_adj_refcnt(sb, head.crypto_id, -1);
|
||||
if (ret) {
|
||||
apfs_err(sb, "failed to take crypto id 0x%llx", head.crypto_id);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (le64_to_cpu(fq->sfq_count) <= APFS_TRANS_MAIN_QUEUE_MAX)
|
||||
goto next_extent;
|
||||
ret = -EAGAIN;
|
||||
out:
|
||||
apfs_free_query(query);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* apfs_inode_delete_front - Deletes as many leading extents as possible
|
||||
* @inode: inode to delete
|
||||
*
|
||||
* Tries to delete all extents for @inode, in which case it returns 0. If the
|
||||
* free queue is getting too full, deletes as much as is reasonable and returns
|
||||
* -EAGAIN. May return other negative error codes as well.
|
||||
*/
|
||||
int apfs_inode_delete_front(struct inode *inode)
|
||||
{
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct apfs_dstream_info *dstream = NULL;
|
||||
struct apfs_inode_info *ai = APFS_I(inode);
|
||||
int ret;
|
||||
|
||||
if (!ai->i_has_dstream)
|
||||
return 0;
|
||||
|
||||
dstream = &ai->i_dstream;
|
||||
ret = apfs_flush_extent_cache(dstream);
|
||||
if (ret) {
|
||||
apfs_err(sb, "extent cache flush failed for dstream 0x%llx", dstream->ds_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = apfs_dstream_delete_front(sb, dstream->ds_id);
|
||||
if (ret == -ENODATA)
|
||||
return 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 20, 0)
|
||||
loff_t apfs_remap_file_range(struct file *src_file, loff_t off, struct file *dst_file, loff_t destoff, loff_t len, unsigned int remap_flags)
|
||||
#else
|
||||
@@ -1639,8 +1755,6 @@ int apfs_clone_file_range(struct file *src_file, loff_t off, struct file *dst_fi
|
||||
struct apfs_dstream_info *dst_ds = &dst_ai->i_dstream;
|
||||
struct super_block *sb = src_inode->i_sb;
|
||||
struct apfs_sb_info *sbi = APFS_SB(sb);
|
||||
/* TODO: remember to update the maxops in the future */
|
||||
struct apfs_max_ops maxops = {0};
|
||||
const u64 xfield_flags = APFS_INODE_MAINTAIN_DIR_STATS | APFS_INODE_IS_SPARSE | APFS_INODE_HAS_PURGEABLE_FLAGS;
|
||||
int err;
|
||||
|
||||
@@ -1674,7 +1788,7 @@ int apfs_clone_file_range(struct file *src_file, loff_t off, struct file *dst_fi
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
err = apfs_transaction_start(sb, maxops);
|
||||
err = apfs_transaction_start(sb, APFS_TRANS_REG);
|
||||
if (err)
|
||||
return err;
|
||||
apfs_inode_join_transaction(sb, src_inode);
|
||||
@@ -1787,7 +1901,7 @@ out:
|
||||
* @paddr_end: first block after the extent to put
|
||||
* @paddr_min: don't put references before this block
|
||||
*
|
||||
* Puts a reference to the physical extent range that ends in paddr. Sets
|
||||
* Puts a reference to the physical extent range that ends in @paddr_end. Sets
|
||||
* @paddr_end to the beginning of the extent, so that the caller can continue
|
||||
* with the previous one. Returns 0 on success, or a negative error code in
|
||||
* case of failure.
|
||||
@@ -1849,7 +1963,7 @@ restart:
|
||||
prev_end = prev_ext.bno + prev_ext.blkcount;
|
||||
if (prev_end < *paddr_end) {
|
||||
/* The extent to put is part of a snapshot */
|
||||
tmp.phys_block_num = MAX(prev_end, paddr_min);
|
||||
tmp.phys_block_num = max(prev_end, paddr_min);
|
||||
tmp.len = (*paddr_end - tmp.phys_block_num) << sb->s_blocksize_bits;
|
||||
ret = apfs_create_update_pext(query, &tmp, -1);
|
||||
*paddr_end = tmp.phys_block_num;
|
||||
@@ -1929,7 +2043,7 @@ static int apfs_range_put_reference(struct super_block *sb, u64 paddr, u64 lengt
|
||||
* @paddr_end: first block after the extent to take
|
||||
* @paddr_min: don't take references before this block
|
||||
*
|
||||
* Takes a reference to the physical extent range that ends in paddr. Sets
|
||||
* Takes a reference to the physical extent range that ends in @paddr_end. Sets
|
||||
* @paddr_end to the beginning of the extent, so that the caller can continue
|
||||
* with the previous one. Returns 0 on success, or a negative error code in
|
||||
* case of failure.
|
||||
@@ -1989,7 +2103,7 @@ restart:
|
||||
prev_end = prev_ext.bno + prev_ext.blkcount;
|
||||
if (prev_end < *paddr_end) {
|
||||
/* The extent to take is part of a snapshot */
|
||||
tmp.phys_block_num = MAX(prev_end, paddr_min);
|
||||
tmp.phys_block_num = max(prev_end, paddr_min);
|
||||
tmp.len = (*paddr_end - tmp.phys_block_num) << sb->s_blocksize_bits;
|
||||
ret = apfs_create_update_pext(query, &tmp, +1);
|
||||
*paddr_end = tmp.phys_block_num;
|
||||
@@ -2173,11 +2287,7 @@ int apfs_nonsparse_dstream_read(struct apfs_dstream_info *dstream, void *buf, si
|
||||
goto out;
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0)
|
||||
bhs[idx] = __getblk_gfp(APFS_NXI(sb)->nx_bdev, bno, sb->s_blocksize, __GFP_MOVABLE);
|
||||
#else
|
||||
bhs[idx] = bdev_getblk(APFS_NXI(sb)->nx_bdev, bno, sb->s_blocksize, __GFP_MOVABLE);
|
||||
#endif
|
||||
bhs[idx] = __apfs_getblk(sb, bno);
|
||||
if (!bhs[idx]) {
|
||||
apfs_err(sb, "failed to map block 0x%llx", bno);
|
||||
ret = -EIO;
|
||||
@@ -2188,7 +2298,6 @@ int apfs_nonsparse_dstream_read(struct apfs_dstream_info *dstream, void *buf, si
|
||||
if (!buffer_uptodate(bh)) {
|
||||
get_bh(bh);
|
||||
lock_buffer(bh);
|
||||
bh->b_end_io = end_buffer_read_sync;
|
||||
apfs_submit_bh(REQ_OP_READ, 0, bh);
|
||||
}
|
||||
}
|
||||
@@ -2249,17 +2358,12 @@ void apfs_nonsparse_dstream_preread(struct apfs_dstream_info *dstream)
|
||||
if (ret || bno == 0)
|
||||
return;
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 7, 0)
|
||||
bh = __getblk_gfp(APFS_NXI(sb)->nx_bdev, bno, sb->s_blocksize, __GFP_MOVABLE);
|
||||
#else
|
||||
bh = bdev_getblk(APFS_NXI(sb)->nx_bdev, bno, sb->s_blocksize, __GFP_MOVABLE);
|
||||
#endif
|
||||
bh = __apfs_getblk(sb, bno);
|
||||
if (!bh)
|
||||
return;
|
||||
if (!buffer_uptodate(bh)) {
|
||||
get_bh(bh);
|
||||
lock_buffer(bh);
|
||||
bh->b_end_io = end_buffer_read_sync;
|
||||
apfs_submit_bh(REQ_OP_READ, 0, bh);
|
||||
}
|
||||
brelse(bh);
|
||||
|
||||
@@ -5,10 +5,20 @@
|
||||
|
||||
#include "apfs.h"
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 8, 0)
|
||||
#include <linux/splice.h>
|
||||
#endif
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 17, 0)
|
||||
typedef int vm_fault_t;
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 15, 0)
|
||||
static void wait_for_stable_page(struct page *page)
|
||||
{
|
||||
return folio_wait_stable(page_folio(page));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 11, 0)
|
||||
static vm_fault_t apfs_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
|
||||
{
|
||||
@@ -25,8 +35,6 @@ static vm_fault_t apfs_page_mkwrite(struct vm_fault *vmf)
|
||||
struct super_block *sb = inode->i_sb;
|
||||
struct buffer_head *bh, *head;
|
||||
vm_fault_t ret = VM_FAULT_LOCKED;
|
||||
struct apfs_max_ops maxops;
|
||||
int blkcount = PAGE_SIZE >> inode->i_blkbits;
|
||||
unsigned int blocksize, block_start, len;
|
||||
u64 size;
|
||||
int err = 0;
|
||||
@@ -34,12 +42,7 @@ static vm_fault_t apfs_page_mkwrite(struct vm_fault *vmf)
|
||||
sb_start_pagefault(inode->i_sb);
|
||||
file_update_time(vma->vm_file);
|
||||
|
||||
/* Placeholder values, I need to get back to this in the future */
|
||||
maxops.cat = APFS_UPDATE_INODE_MAXOPS() +
|
||||
blkcount * APFS_GET_NEW_BLOCK_MAXOPS();
|
||||
maxops.blks = blkcount;
|
||||
|
||||
err = apfs_transaction_start(sb, maxops);
|
||||
err = apfs_transaction_start(sb, APFS_TRANS_REG);
|
||||
if (err)
|
||||
goto out;
|
||||
apfs_inode_join_transaction(sb, inode);
|
||||
@@ -69,7 +72,11 @@ static vm_fault_t apfs_page_mkwrite(struct vm_fault *vmf)
|
||||
}
|
||||
|
||||
size = i_size_read(inode);
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 16, 0)
|
||||
if (page_folio(page)->index == size >> PAGE_SHIFT)
|
||||
#else
|
||||
if (page->index == size >> PAGE_SHIFT)
|
||||
#endif
|
||||
len = size & ~PAGE_MASK;
|
||||
else
|
||||
len = PAGE_SIZE;
|
||||
@@ -110,7 +117,7 @@ out_abort:
|
||||
apfs_transaction_abort(sb);
|
||||
out:
|
||||
if (err)
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0)
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 6, 0) && !RHEL_VERSION_GE(9, 5)
|
||||
ret = block_page_mkwrite_return(err);
|
||||
#else
|
||||
ret = vmf_fs_error(err);
|
||||
@@ -129,7 +136,7 @@ int apfs_file_mmap(struct file *file, struct vm_area_struct *vma)
|
||||
{
|
||||
struct address_space *mapping = file->f_mapping;
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0)
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 19, 0) || RHEL_VERSION_GE(9, 3)
|
||||
if (!mapping->a_ops->read_folio)
|
||||
#else
|
||||
if (!mapping->a_ops->readpage)
|
||||
@@ -152,6 +159,16 @@ int apfs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
||||
return apfs_sync_fs(sb, true /* wait */);
|
||||
}
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 8, 0)
|
||||
static ssize_t apfs_copy_file_range(struct file *src_file, loff_t src_off,
|
||||
struct file *dst_file, loff_t dst_off,
|
||||
size_t len, unsigned int flags)
|
||||
{
|
||||
return (splice_copy_file_range(src_file, src_off,
|
||||
dst_file, dst_off, len));
|
||||
}
|
||||
#endif
|
||||
|
||||
const struct file_operations apfs_file_operations = {
|
||||
.llseek = generic_file_llseek,
|
||||
.read_iter = generic_file_read_iter,
|
||||
@@ -161,7 +178,9 @@ const struct file_operations apfs_file_operations = {
|
||||
.fsync = apfs_fsync,
|
||||
.unlocked_ioctl = apfs_file_ioctl,
|
||||
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(6, 8, 0)
|
||||
.copy_file_range = apfs_copy_file_range,
|
||||
#elif LINUX_VERSION_CODE >= KERNEL_VERSION(5, 3, 0)
|
||||
.copy_file_range = generic_copy_file_range,
|
||||
#endif
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ int apfs_read_free_queue_key(void *raw, int size, struct apfs_key *key)
|
||||
{
|
||||
struct apfs_spaceman_free_queue_key *raw_key;
|
||||
|
||||
if (size < sizeof(struct apfs_spaceman_free_queue_key)) {
|
||||
if (size != sizeof(*raw_key)) {
|
||||
apfs_err(NULL, "bad key length (%d)", size);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
@@ -204,14 +204,17 @@ int apfs_read_free_queue_key(void *raw, int size, struct apfs_key *key)
|
||||
*/
|
||||
int apfs_read_omap_key(void *raw, int size, struct apfs_key *key)
|
||||
{
|
||||
if (size < sizeof(struct apfs_omap_key)) {
|
||||
struct apfs_omap_key *raw_key;
|
||||
|
||||
if (size != sizeof(*raw_key)) {
|
||||
apfs_err(NULL, "bad key length (%d)", size);
|
||||
return -EFSCORRUPTED;
|
||||
}
|
||||
raw_key = raw;
|
||||
|
||||
key->id = le64_to_cpu(((struct apfs_omap_key *)raw)->ok_oid);
|
||||
key->id = le64_to_cpu(raw_key->ok_oid);
|
||||
key->type = 0;
|
||||
key->number = le64_to_cpu(((struct apfs_omap_key *)raw)->ok_xid);
|
||||
key->number = le64_to_cpu(raw_key->ok_xid);
|
||||
key->name = NULL;
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
#include <linux/string.h>
|
||||
#include "libzbitmap.h"
|
||||
|
||||
#define MIN(x, y) ((x) > (y) ? (y) : (x))
|
||||
|
||||
#define ZBM_MAGIC "ZBM\x09"
|
||||
#define ZBM_MAGIC_SZ 4
|
||||
|
||||
|
||||
+25
-94
@@ -1,23 +1,24 @@
|
||||
/* SPDX-License-Identifier: BSD-3-Clause */
|
||||
/*
|
||||
Copyright (c) 2015-2016, Apple Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
* Copyright (c) 2015-2016, Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LZFSE_H
|
||||
#define LZFSE_H
|
||||
@@ -25,71 +26,6 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSI
|
||||
#include <linux/stddef.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
# define __attribute__(X)
|
||||
# pragma warning(disable : 4068)
|
||||
#endif
|
||||
|
||||
#if defined(LZFSE_DLL)
|
||||
# if defined(_WIN32) || defined(__CYGWIN__)
|
||||
# if defined(LZFSE_DLL_EXPORTS)
|
||||
# define LZFSE_API __declspec(dllexport)
|
||||
# else
|
||||
# define LZFSE_API __declspec(dllimport)
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(LZFSE_API)
|
||||
# if __GNUC__ >= 4
|
||||
# define LZFSE_API __attribute__((visibility("default")))
|
||||
# else
|
||||
# define LZFSE_API
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*! @abstract Get the required scratch buffer size to compress using LZFSE. */
|
||||
size_t lzfse_encode_scratch_size(void);
|
||||
|
||||
/*! @abstract Compress a buffer using LZFSE.
|
||||
*
|
||||
* @param dst_buffer
|
||||
* Pointer to the first byte of the destination buffer.
|
||||
*
|
||||
* @param dst_size
|
||||
* Size of the destination buffer in bytes.
|
||||
*
|
||||
* @param src_buffer
|
||||
* Pointer to the first byte of the source buffer.
|
||||
*
|
||||
* @param src_size
|
||||
* Size of the source buffer in bytes.
|
||||
*
|
||||
* @param scratch_buffer
|
||||
* If non-NULL, a pointer to scratch space for the routine to use as workspace;
|
||||
* the routine may use up to lzfse_encode_scratch_size( ) bytes of workspace
|
||||
* during its operation, and will not perform any internal allocations. If
|
||||
* NULL, the routine may allocate its own memory to use during operation via
|
||||
* a single call to malloc( ), and will release it by calling free( ) prior
|
||||
* to returning. For most use, passing NULL is perfectly satisfactory, but if
|
||||
* you require strict control over allocation, you will want to pass an
|
||||
* explicit scratch buffer.
|
||||
*
|
||||
* @return
|
||||
* The number of bytes written to the destination buffer if the input is
|
||||
* successfully compressed. If the input cannot be compressed to fit into
|
||||
* the provided buffer, or an error occurs, zero is returned, and the
|
||||
* contents of dst_buffer are unspecified. */
|
||||
size_t lzfse_encode_buffer(uint8_t *__restrict dst_buffer,
|
||||
size_t dst_size,
|
||||
const uint8_t *__restrict src_buffer,
|
||||
size_t src_size,
|
||||
void *__restrict scratch_buffer);
|
||||
|
||||
/*! @abstract Get the required scratch buffer size to decompress using LZFSE. */
|
||||
size_t lzfse_decode_scratch_size(void);
|
||||
|
||||
@@ -122,15 +58,10 @@ size_t lzfse_decode_scratch_size(void);
|
||||
* successfully decompressed. If there is not enough space in the destination
|
||||
* buffer to hold the entire expanded output, only the first dst_size bytes
|
||||
* will be written to the buffer and dst_size is returned. Note that this
|
||||
* behavior differs from that of lzfse_encode_buffer. */
|
||||
size_t lzfse_decode_buffer(uint8_t *__restrict dst_buffer,
|
||||
size_t dst_size,
|
||||
const uint8_t *__restrict src_buffer,
|
||||
size_t src_size,
|
||||
void *__restrict scratch_buffer);
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
* behavior differs from that of lzfse_encode_buffer.
|
||||
*/
|
||||
size_t lzfse_decode_buffer(uint8_t *__restrict dst_buffer, size_t dst_size,
|
||||
const uint8_t *__restrict src_buffer, size_t src_size,
|
||||
void *__restrict scratch_buffer);
|
||||
|
||||
#endif /* LZFSE_H */
|
||||
+65
-59
@@ -1,74 +1,80 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
/*
|
||||
Copyright (c) 2015-2016, Apple Inc. All rights reserved.
|
||||
* Copyright (c) 2015-2016, Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// LZFSE decode API
|
||||
/* LZFSE decode API */
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include "lzfse.h"
|
||||
#include "lzfse_internal.h"
|
||||
|
||||
size_t lzfse_decode_scratch_size(void) { return sizeof(lzfse_decoder_state); }
|
||||
size_t lzfse_decode_scratch_size(void)
|
||||
{
|
||||
return sizeof(lzfse_decoder_state);
|
||||
}
|
||||
|
||||
static size_t lzfse_decode_buffer_with_scratch(uint8_t *__restrict dst_buffer,
|
||||
size_t dst_size, const uint8_t *__restrict src_buffer,
|
||||
size_t src_size, void *__restrict scratch_buffer) {
|
||||
int status;
|
||||
lzfse_decoder_state *s = (lzfse_decoder_state *)scratch_buffer;
|
||||
memset(s, 0x00, sizeof(*s));
|
||||
static size_t lzfse_decode_buffer_with_scratch(uint8_t *__restrict dst_buffer, size_t dst_size,
|
||||
const uint8_t *__restrict src_buffer,
|
||||
size_t src_size, void *__restrict scratch_buffer)
|
||||
{
|
||||
int status;
|
||||
lzfse_decoder_state *s = (lzfse_decoder_state *)scratch_buffer;
|
||||
|
||||
// Initialize state
|
||||
s->src = src_buffer;
|
||||
s->src_begin = src_buffer;
|
||||
s->src_end = s->src + src_size;
|
||||
s->dst = dst_buffer;
|
||||
s->dst_begin = dst_buffer;
|
||||
s->dst_end = dst_buffer + dst_size;
|
||||
memset(s, 0x00, sizeof(*s));
|
||||
|
||||
// Decode
|
||||
status = lzfse_decode(s);
|
||||
if (status == LZFSE_STATUS_DST_FULL)
|
||||
return dst_size;
|
||||
if (status != LZFSE_STATUS_OK)
|
||||
return 0; // failed
|
||||
return (size_t)(s->dst - dst_buffer); // bytes written
|
||||
/* Initialize state */
|
||||
s->src = src_buffer;
|
||||
s->src_begin = src_buffer;
|
||||
s->src_end = s->src + src_size;
|
||||
s->dst = dst_buffer;
|
||||
s->dst_begin = dst_buffer;
|
||||
s->dst_end = dst_buffer + dst_size;
|
||||
|
||||
/* Decode */
|
||||
status = lzfse_decode(s);
|
||||
if (status == LZFSE_STATUS_DST_FULL)
|
||||
return dst_size;
|
||||
if (status != LZFSE_STATUS_OK)
|
||||
return 0; /* failed */
|
||||
return (size_t)(s->dst - dst_buffer); /* bytes written */
|
||||
}
|
||||
|
||||
size_t lzfse_decode_buffer(uint8_t *__restrict dst_buffer, size_t dst_size,
|
||||
const uint8_t *__restrict src_buffer,
|
||||
size_t src_size, void *__restrict scratch_buffer) {
|
||||
int has_malloc = 0;
|
||||
size_t ret = 0;
|
||||
const uint8_t *__restrict src_buffer, size_t src_size,
|
||||
void *__restrict scratch_buffer)
|
||||
{
|
||||
int has_malloc = 0;
|
||||
size_t ret = 0;
|
||||
|
||||
// Deal with the possible NULL pointer
|
||||
if (scratch_buffer == NULL) {
|
||||
// +1 in case scratch size could be zero
|
||||
scratch_buffer = kmalloc(lzfse_decode_scratch_size() + 1, GFP_KERNEL);
|
||||
has_malloc = 1;
|
||||
}
|
||||
if (scratch_buffer == NULL)
|
||||
return 0;
|
||||
ret = lzfse_decode_buffer_with_scratch(dst_buffer,
|
||||
dst_size, src_buffer,
|
||||
src_size, scratch_buffer);
|
||||
if (has_malloc)
|
||||
kfree(scratch_buffer);
|
||||
return ret;
|
||||
/* Deal with the possible NULL pointer */
|
||||
if (scratch_buffer == NULL) {
|
||||
/* +1 in case scratch size could be zero */
|
||||
scratch_buffer = kmalloc(lzfse_decode_scratch_size() + 1, GFP_KERNEL);
|
||||
has_malloc = 1;
|
||||
}
|
||||
if (scratch_buffer == NULL)
|
||||
return 0;
|
||||
ret = lzfse_decode_buffer_with_scratch(dst_buffer, dst_size, src_buffer, src_size,
|
||||
scratch_buffer);
|
||||
if (has_malloc)
|
||||
kfree(scratch_buffer);
|
||||
return ret;
|
||||
}
|
||||
+647
-556
File diff suppressed because it is too large.
Load diff
@@ -1,163 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016, Apple Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// LZFSE encode API
|
||||
|
||||
#include "lzfse.h"
|
||||
#include "lzfse_internal.h"
|
||||
|
||||
size_t lzfse_encode_scratch_size() {
|
||||
size_t s1 = sizeof(lzfse_encoder_state);
|
||||
size_t s2 = lzvn_encode_scratch_size();
|
||||
return (s1 > s2) ? s1 : s2; // max(lzfse,lzvn)
|
||||
}
|
||||
|
||||
size_t lzfse_encode_buffer_with_scratch(uint8_t *__restrict dst_buffer,
|
||||
size_t dst_size, const uint8_t *__restrict src_buffer,
|
||||
size_t src_size, void *__restrict scratch_buffer) {
|
||||
const size_t original_size = src_size;
|
||||
|
||||
// If input is really really small, go directly to uncompressed buffer
|
||||
// (because LZVN will refuse to encode it, and we will report a failure)
|
||||
if (src_size < LZVN_ENCODE_MIN_SRC_SIZE)
|
||||
goto try_uncompressed;
|
||||
|
||||
// If input is too small, try encoding with LZVN
|
||||
if (src_size < LZFSE_ENCODE_LZVN_THRESHOLD) {
|
||||
// need header + end-of-stream marker
|
||||
size_t extra_size = 4 + sizeof(lzvn_compressed_block_header);
|
||||
if (dst_size <= extra_size)
|
||||
goto try_uncompressed; // DST is really too small, give up
|
||||
|
||||
size_t sz = lzvn_encode_buffer(
|
||||
dst_buffer + sizeof(lzvn_compressed_block_header),
|
||||
dst_size - extra_size, src_buffer, src_size, scratch_buffer);
|
||||
if (sz == 0 || sz >= src_size)
|
||||
goto try_uncompressed; // failed, or no compression, fall back to
|
||||
// uncompressed block
|
||||
|
||||
// If we could encode, setup header and end-of-stream marker (we left room
|
||||
// for them, no need to test)
|
||||
lzvn_compressed_block_header header;
|
||||
header.magic = LZFSE_COMPRESSEDLZVN_BLOCK_MAGIC;
|
||||
header.n_raw_bytes = (uint32_t)src_size;
|
||||
header.n_payload_bytes = (uint32_t)sz;
|
||||
memcpy(dst_buffer, &header, sizeof(header));
|
||||
store4(dst_buffer + sizeof(lzvn_compressed_block_header) + sz,
|
||||
LZFSE_ENDOFSTREAM_BLOCK_MAGIC);
|
||||
|
||||
return sz + extra_size;
|
||||
}
|
||||
|
||||
// Try encoding with LZFSE
|
||||
{
|
||||
lzfse_encoder_state *state = scratch_buffer;
|
||||
memset(state, 0x00, sizeof *state);
|
||||
if (lzfse_encode_init(state) != LZFSE_STATUS_OK)
|
||||
goto try_uncompressed;
|
||||
state->dst = dst_buffer;
|
||||
state->dst_begin = dst_buffer;
|
||||
state->dst_end = &dst_buffer[dst_size];
|
||||
state->src = src_buffer;
|
||||
state->src_encode_i = 0;
|
||||
|
||||
if (src_size >= 0xffffffffU) {
|
||||
// lzfse only uses 32 bits for offsets internally, so if the input
|
||||
// buffer is really huge, we need to process it in smaller chunks.
|
||||
// Note that we switch over to this path for sizes much smaller
|
||||
// 2GB because it's actually faster to change algorithms well before
|
||||
// it's necessary for correctness.
|
||||
// The first chunk, we just process normally.
|
||||
const lzfse_offset encoder_block_size = 262144;
|
||||
state->src_end = encoder_block_size;
|
||||
if (lzfse_encode_base(state) != LZFSE_STATUS_OK)
|
||||
goto try_uncompressed;
|
||||
src_size -= encoder_block_size;
|
||||
while (src_size >= encoder_block_size) {
|
||||
// All subsequent chunks require a translation to keep the offsets
|
||||
// from getting too big. Note that we are always going from
|
||||
// encoder_block_size up to 2*encoder_block_size so that the
|
||||
// offsets remain positive (as opposed to resetting to zero and
|
||||
// having negative offsets).
|
||||
state->src_end = 2 * encoder_block_size;
|
||||
if (lzfse_encode_base(state) != LZFSE_STATUS_OK)
|
||||
goto try_uncompressed;
|
||||
lzfse_encode_translate(state, encoder_block_size);
|
||||
src_size -= encoder_block_size;
|
||||
}
|
||||
// Set the end for the final chunk.
|
||||
state->src_end = encoder_block_size + (lzfse_offset)src_size;
|
||||
}
|
||||
// If the source buffer is small enough to use 32-bit offsets, we simply
|
||||
// encode the whole thing in a single chunk.
|
||||
else
|
||||
state->src_end = (lzfse_offset)src_size;
|
||||
// This is either the trailing chunk (if the source file is huge), or
|
||||
// the whole source file.
|
||||
if (lzfse_encode_base(state) != LZFSE_STATUS_OK)
|
||||
goto try_uncompressed;
|
||||
if (lzfse_encode_finish(state) != LZFSE_STATUS_OK)
|
||||
goto try_uncompressed;
|
||||
// No error occured, return compressed size.
|
||||
return state->dst - dst_buffer;
|
||||
}
|
||||
|
||||
try_uncompressed:
|
||||
// Compression failed for some reason. If we can fit the data into the
|
||||
// output buffer uncompressed, go ahead and do that instead.
|
||||
if (original_size + 12 <= dst_size && original_size < INT32_MAX) {
|
||||
uncompressed_block_header header = {.magic = LZFSE_UNCOMPRESSED_BLOCK_MAGIC,
|
||||
.n_raw_bytes = (uint32_t)src_size};
|
||||
uint8_t *dst_end = dst_buffer;
|
||||
memcpy(dst_end, &header, sizeof header);
|
||||
dst_end += sizeof header;
|
||||
memcpy(dst_end, src_buffer, original_size);
|
||||
dst_end += original_size;
|
||||
store4(dst_end, LZFSE_ENDOFSTREAM_BLOCK_MAGIC);
|
||||
dst_end += 4;
|
||||
return dst_end - dst_buffer;
|
||||
}
|
||||
|
||||
// Otherwise, there's nothing we can do, so return zero.
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t lzfse_encode_buffer(uint8_t *__restrict dst_buffer, size_t dst_size,
|
||||
const uint8_t *__restrict src_buffer,
|
||||
size_t src_size, void *__restrict scratch_buffer) {
|
||||
int has_malloc = 0;
|
||||
size_t ret = 0;
|
||||
|
||||
// Deal with the possible NULL pointer
|
||||
if (scratch_buffer == NULL) {
|
||||
// +1 in case scratch size could be zero
|
||||
scratch_buffer = malloc(lzfse_encode_scratch_size() + 1);
|
||||
has_malloc = 1;
|
||||
}
|
||||
if (scratch_buffer == NULL)
|
||||
return 0;
|
||||
ret = lzfse_encode_buffer_with_scratch(dst_buffer,
|
||||
dst_size, src_buffer,
|
||||
src_size, scratch_buffer);
|
||||
if (has_malloc)
|
||||
free(scratch_buffer);
|
||||
return ret;
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -1,218 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2015-2016, Apple Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef LZFSE_ENCODE_TABLES_H
|
||||
#define LZFSE_ENCODE_TABLES_H
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
# define inline __inline
|
||||
#endif
|
||||
|
||||
static inline uint8_t l_base_from_value(int32_t value) {
|
||||
static const uint8_t sym[LZFSE_ENCODE_MAX_L_VALUE + 1] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16,
|
||||
16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19};
|
||||
return sym[value];
|
||||
}
|
||||
static inline uint8_t m_base_from_value(int32_t value) {
|
||||
static const uint8_t sym[LZFSE_ENCODE_MAX_M_VALUE + 1] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16,
|
||||
16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
|
||||
17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
|
||||
17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
|
||||
18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19,
|
||||
19, 19};
|
||||
return sym[value];
|
||||
}
|
||||
|
||||
static inline uint8_t d_base_from_value(int32_t value) {
|
||||
static const uint8_t sym[64 * 4] = {
|
||||
0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 8, 8, 9, 9,
|
||||
9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12,
|
||||
13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15,
|
||||
15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 17, 18, 19, 20, 20, 21, 21,
|
||||
22, 22, 23, 23, 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27,
|
||||
27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29,
|
||||
30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, 31, 31, 31, 32, 32,
|
||||
32, 32, 32, 33, 34, 35, 36, 36, 37, 37, 38, 38, 39, 39, 40, 40, 40, 40,
|
||||
41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, 44, 44, 44, 44, 44, 44,
|
||||
44, 44, 45, 45, 45, 45, 45, 45, 45, 45, 46, 46, 46, 46, 46, 46, 46, 46,
|
||||
47, 47, 47, 47, 47, 47, 47, 47, 48, 48, 48, 48, 48, 49, 50, 51, 52, 52,
|
||||
53, 53, 54, 54, 55, 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58,
|
||||
59, 59, 59, 59, 60, 60, 60, 60, 60, 60, 60, 60, 61, 61, 61, 61, 61, 61,
|
||||
61, 61, 62, 62, 62, 62, 62, 62, 62, 62, 63, 63, 63, 63, 63, 63, 63, 63,
|
||||
0, 0, 0, 0};
|
||||
int index = 0;
|
||||
int in_range_k;
|
||||
in_range_k = (value >= 0 && value < 60);
|
||||
index |= (((value - 0) >> 0) + 0) & -in_range_k;
|
||||
in_range_k = (value >= 60 && value < 1020);
|
||||
index |= (((value - 60) >> 4) + 64) & -in_range_k;
|
||||
in_range_k = (value >= 1020 && value < 16380);
|
||||
index |= (((value - 1020) >> 8) + 128) & -in_range_k;
|
||||
in_range_k = (value >= 16380 && value < 262140);
|
||||
index |= (((value - 16380) >> 12) + 192) & -in_range_k;
|
||||
return sym[index & 255];
|
||||
}
|
||||
|
||||
#endif // LZFSE_ENCODE_TABLES_H
|
||||
+112
-203
@@ -1,217 +1,126 @@
|
||||
// SPDX-License-Identifier: BSD-3-Clause
|
||||
/*
|
||||
Copyright (c) 2015-2016, Apple Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
||||
in the documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
* Copyright (c) 2015-2016, Apple Inc. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
|
||||
* in the documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
|
||||
* from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "lzfse_internal.h"
|
||||
|
||||
// Initialize encoder table T[NSYMBOLS].
|
||||
// NSTATES = sum FREQ[i] is the number of states (a power of 2)
|
||||
// NSYMBOLS is the number of symbols.
|
||||
// FREQ[NSYMBOLS] is a normalized histogram of symbol frequencies, with FREQ[i]
|
||||
// >= 0.
|
||||
// Some symbols may have a 0 frequency. In that case, they should not be
|
||||
// present in the data.
|
||||
void fse_init_encoder_table(int nstates, int nsymbols,
|
||||
const uint16_t *__restrict freq,
|
||||
fse_encoder_entry *__restrict t) {
|
||||
int offset = 0; // current offset
|
||||
int n_clz = __builtin_clz(nstates);
|
||||
int i;
|
||||
for (i = 0; i < nsymbols; i++) {
|
||||
int f = (int)freq[i];
|
||||
int k;
|
||||
if (f == 0)
|
||||
continue; // skip this symbol, no occurrences
|
||||
k = __builtin_clz(f) - n_clz; // shift needed to ensure N <= (F<<K) < 2*N
|
||||
t[i].s0 = (int16_t)((f << k) - nstates);
|
||||
t[i].k = (int16_t)k;
|
||||
t[i].delta0 = (int16_t)(offset - f + (nstates >> k));
|
||||
t[i].delta1 = (int16_t)(offset - f + (nstates >> (k - 1)));
|
||||
offset += f;
|
||||
}
|
||||
/*
|
||||
* Initialize decoder table T[NSTATES].
|
||||
* NSTATES = sum FREQ[i] is the number of states (a power of 2)
|
||||
* NSYMBOLS is the number of symbols.
|
||||
* FREQ[NSYMBOLS] is a normalized histogram of symbol frequencies, with FREQ[i]
|
||||
* >= 0.
|
||||
* Some symbols may have a 0 frequency. In that case, they should not be
|
||||
* present in the data.
|
||||
*/
|
||||
int fse_init_decoder_table(int nstates, int nsymbols, const uint16_t *__restrict freq,
|
||||
int32_t *__restrict t)
|
||||
{
|
||||
int n_clz = __builtin_clz(nstates);
|
||||
int sum_of_freq = 0;
|
||||
int i, j0, j;
|
||||
|
||||
for (i = 0; i < nsymbols; i++) {
|
||||
int f = (int)freq[i];
|
||||
int k;
|
||||
|
||||
if (f == 0)
|
||||
continue; /* skip this symbol, no occurrences */
|
||||
|
||||
sum_of_freq += f;
|
||||
|
||||
if (sum_of_freq > nstates)
|
||||
return -1;
|
||||
|
||||
k = __builtin_clz(f) - n_clz; /* shift needed to ensure N <= (F<<K) < 2*N */
|
||||
j0 = ((2 * nstates) >> k) - f;
|
||||
|
||||
/* Initialize all states S reached by this symbol: OFFSET <= S < OFFSET + F */
|
||||
for (j = 0; j < f; j++) {
|
||||
fse_decoder_entry e;
|
||||
|
||||
e.symbol = (uint8_t)i;
|
||||
if (j < j0) {
|
||||
e.k = (int8_t)k;
|
||||
e.delta = (int16_t)(((f + j) << k) - nstates);
|
||||
} else {
|
||||
e.k = (int8_t)(k - 1);
|
||||
e.delta = (int16_t)((j - j0) << (k - 1));
|
||||
}
|
||||
|
||||
memcpy(t, &e, sizeof(e));
|
||||
t++;
|
||||
}
|
||||
}
|
||||
|
||||
return 0; /* OK */
|
||||
}
|
||||
|
||||
// Initialize decoder table T[NSTATES].
|
||||
// NSTATES = sum FREQ[i] is the number of states (a power of 2)
|
||||
// NSYMBOLS is the number of symbols.
|
||||
// FREQ[NSYMBOLS] is a normalized histogram of symbol frequencies, with FREQ[i]
|
||||
// >= 0.
|
||||
// Some symbols may have a 0 frequency. In that case, they should not be
|
||||
// present in the data.
|
||||
int fse_init_decoder_table(int nstates, int nsymbols,
|
||||
const uint16_t *__restrict freq,
|
||||
int32_t *__restrict t) {
|
||||
int n_clz = __builtin_clz(nstates);
|
||||
int sum_of_freq = 0;
|
||||
int i, j0, j;
|
||||
for (i = 0; i < nsymbols; i++) {
|
||||
int f = (int)freq[i];
|
||||
int k;
|
||||
if (f == 0)
|
||||
continue; // skip this symbol, no occurrences
|
||||
/*
|
||||
* Initialize value decoder table T[NSTATES].
|
||||
* NSTATES = sum FREQ[i] is the number of states (a power of 2)
|
||||
* NSYMBOLS is the number of symbols.
|
||||
* FREQ[NSYMBOLS] is a normalized histogram of symbol frequencies, with FREQ[i]
|
||||
* >= 0.
|
||||
* SYMBOL_VBITS[NSYMBOLS] and SYMBOLS_VBASE[NSYMBOLS] are the number of value
|
||||
* bits to read and the base value for each symbol.
|
||||
* Some symbols may have a 0 frequency. In that case, they should not be
|
||||
* present in the data.
|
||||
*/
|
||||
void fse_init_value_decoder_table(int nstates, int nsymbols, const uint16_t *__restrict freq,
|
||||
const uint8_t *__restrict symbol_vbits,
|
||||
const int32_t *__restrict symbol_vbase,
|
||||
struct fse_value_decoder_entry *__restrict t)
|
||||
{
|
||||
int n_clz = __builtin_clz(nstates);
|
||||
int i;
|
||||
|
||||
sum_of_freq += f;
|
||||
for (i = 0; i < nsymbols; i++) {
|
||||
struct fse_value_decoder_entry ei = { 0 };
|
||||
int f = (int)freq[i];
|
||||
int k, j0, j;
|
||||
|
||||
if (sum_of_freq > nstates) {
|
||||
return -1;
|
||||
}
|
||||
if (f == 0)
|
||||
continue; /* skip this symbol, no occurrences */
|
||||
|
||||
k = __builtin_clz(f) - n_clz; // shift needed to ensure N <= (F<<K) < 2*N
|
||||
j0 = ((2 * nstates) >> k) - f;
|
||||
k = __builtin_clz(f) - n_clz; /* shift needed to ensure N <= (F<<K) < 2*N */
|
||||
j0 = ((2 * nstates) >> k) - f;
|
||||
|
||||
// Initialize all states S reached by this symbol: OFFSET <= S < OFFSET + F
|
||||
for (j = 0; j < f; j++) {
|
||||
fse_decoder_entry e;
|
||||
ei.value_bits = symbol_vbits[i];
|
||||
ei.vbase = symbol_vbase[i];
|
||||
|
||||
e.symbol = (uint8_t)i;
|
||||
if (j < j0) {
|
||||
e.k = (int8_t)k;
|
||||
e.delta = (int16_t)(((f + j) << k) - nstates);
|
||||
} else {
|
||||
e.k = (int8_t)(k - 1);
|
||||
e.delta = (int16_t)((j - j0) << (k - 1));
|
||||
}
|
||||
/* Initialize all states S reached by this symbol: OFFSET <= S < OFFSET + F */
|
||||
for (j = 0; j < f; j++) {
|
||||
struct fse_value_decoder_entry e = ei;
|
||||
|
||||
memcpy(t, &e, sizeof(e));
|
||||
t++;
|
||||
}
|
||||
}
|
||||
if (j < j0) {
|
||||
e.total_bits = (uint8_t)k + e.value_bits;
|
||||
e.delta = (int16_t)(((f + j) << k) - nstates);
|
||||
} else {
|
||||
e.total_bits = (uint8_t)(k - 1) + e.value_bits;
|
||||
e.delta = (int16_t)((j - j0) << (k - 1));
|
||||
}
|
||||
|
||||
return 0; // OK
|
||||
}
|
||||
|
||||
// Initialize value decoder table T[NSTATES].
|
||||
// NSTATES = sum FREQ[i] is the number of states (a power of 2)
|
||||
// NSYMBOLS is the number of symbols.
|
||||
// FREQ[NSYMBOLS] is a normalized histogram of symbol frequencies, with FREQ[i]
|
||||
// >= 0.
|
||||
// SYMBOL_VBITS[NSYMBOLS] and SYMBOLS_VBASE[NSYMBOLS] are the number of value
|
||||
// bits to read and the base value for each symbol.
|
||||
// Some symbols may have a 0 frequency. In that case, they should not be
|
||||
// present in the data.
|
||||
void fse_init_value_decoder_table(int nstates, int nsymbols,
|
||||
const uint16_t *__restrict freq,
|
||||
const uint8_t *__restrict symbol_vbits,
|
||||
const int32_t *__restrict symbol_vbase,
|
||||
fse_value_decoder_entry *__restrict t) {
|
||||
int n_clz = __builtin_clz(nstates);
|
||||
int i;
|
||||
for (i = 0; i < nsymbols; i++) {
|
||||
fse_value_decoder_entry ei = {0};
|
||||
int f = (int)freq[i];
|
||||
int k, j0, j;
|
||||
if (f == 0)
|
||||
continue; // skip this symbol, no occurrences
|
||||
|
||||
k = __builtin_clz(f) - n_clz; // shift needed to ensure N <= (F<<K) < 2*N
|
||||
j0 = ((2 * nstates) >> k) - f;
|
||||
|
||||
ei.value_bits = symbol_vbits[i];
|
||||
ei.vbase = symbol_vbase[i];
|
||||
|
||||
// Initialize all states S reached by this symbol: OFFSET <= S < OFFSET + F
|
||||
for (j = 0; j < f; j++) {
|
||||
fse_value_decoder_entry e = ei;
|
||||
|
||||
if (j < j0) {
|
||||
e.total_bits = (uint8_t)k + e.value_bits;
|
||||
e.delta = (int16_t)(((f + j) << k) - nstates);
|
||||
} else {
|
||||
e.total_bits = (uint8_t)(k - 1) + e.value_bits;
|
||||
e.delta = (int16_t)((j - j0) << (k - 1));
|
||||
}
|
||||
|
||||
memcpy(t, &e, 8);
|
||||
t++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove states from symbols until the correct number of states is used.
|
||||
static void fse_adjust_freqs(uint16_t *freq, int overrun, int nsymbols) {
|
||||
int shift;
|
||||
for (shift = 3; overrun != 0; shift--) {
|
||||
int sym;
|
||||
for (sym = 0; sym < nsymbols; sym++) {
|
||||
if (freq[sym] > 1) {
|
||||
int n = (freq[sym] - 1) >> shift;
|
||||
if (n > overrun)
|
||||
n = overrun;
|
||||
freq[sym] -= n;
|
||||
overrun -= n;
|
||||
if (overrun == 0)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize a table T[NSYMBOLS] of occurrences to FREQ[NSYMBOLS].
|
||||
void fse_normalize_freq(int nstates, int nsymbols, const uint32_t *__restrict t,
|
||||
uint16_t *__restrict freq) {
|
||||
uint32_t s_count = 0;
|
||||
int remaining = nstates; // must be signed; this may become < 0
|
||||
int max_freq = 0;
|
||||
int max_freq_sym = 0;
|
||||
int shift = __builtin_clz(nstates) - 1;
|
||||
uint32_t highprec_step;
|
||||
int i;
|
||||
|
||||
// Compute the total number of symbol occurrences
|
||||
for (i = 0; i < nsymbols; i++)
|
||||
s_count += t[i];
|
||||
|
||||
if (s_count == 0)
|
||||
highprec_step = 0; // no symbols used
|
||||
else
|
||||
highprec_step = ((uint32_t)1 << 31) / s_count;
|
||||
|
||||
for (i = 0; i < nsymbols; i++) {
|
||||
|
||||
// Rescale the occurrence count to get the normalized frequency.
|
||||
// Round up if the fractional part is >= 0.5; otherwise round down.
|
||||
// For efficiency, we do this calculation using integer arithmetic.
|
||||
int f = (((t[i] * highprec_step) >> shift) + 1) >> 1;
|
||||
|
||||
// If a symbol was used, it must be given a nonzero normalized frequency.
|
||||
if (f == 0 && t[i] != 0)
|
||||
f = 1;
|
||||
|
||||
freq[i] = f;
|
||||
remaining -= f;
|
||||
|
||||
// Remember the maximum frequency and which symbol had it.
|
||||
if (f > max_freq) {
|
||||
max_freq = f;
|
||||
max_freq_sym = i;
|
||||
}
|
||||
}
|
||||
|
||||
// If there remain states to be assigned, then just assign them to the most
|
||||
// frequent symbol. Alternatively, if we assigned more states than were
|
||||
// actually available, then either remove states from the most frequent symbol
|
||||
// (for minor overruns) or use the slower adjustment algorithm (for major
|
||||
// overruns).
|
||||
if (-remaining < (max_freq >> 2)) {
|
||||
freq[max_freq_sym] += remaining;
|
||||
} else {
|
||||
fse_adjust_freqs(freq, -remaining, nsymbols);
|
||||
}
|
||||
memcpy(t, &e, 8);
|
||||
t++;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loaded 20 of 37 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user