Import upstream v0.16.22, stripped

Upstream commit: 474dd0229cb20cf513036619781ed97bd8073c3f
Enterprise-only files removed or emptied: 63
Enterprise-only snippets removed: 117 in 50 files
Dangling module declarations removed: 5
Cargo edits turning enterprise off: 14
Verification: clean
Enterprise feature gates left for rebuilt features: 19 in 18 files

Produced by tools/fork/strip.py. The full report is in docs/fork/strip-reports/ on main.
This commit is contained in:
2026-09-18 10:21:56 -07:00
commit 7dae9b29fd
1650 changed files with 485521 additions and 0 deletions
+97
View File
@@ -0,0 +1,97 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use super::{ArchivedFileNode, FileNode};
use common::storage::index::{IndexValue, IndexableAndSerializableObject, IndexableObject};
use types::{acl::AclGrant, collection::SyncCollection};
impl IndexableObject for FileNode {
fn index_values(&self) -> impl Iterator<Item = IndexValue<'_>> {
let mut values = Vec::with_capacity(6);
values.extend([
IndexValue::Acl {
value: (&self.acls).into(),
},
IndexValue::LogItem {
prefix: None,
sync_collection: SyncCollection::FileNode,
},
IndexValue::Quota {
used: self.size() as u32,
},
]);
if let Some(file) = &self.file {
values.extend([IndexValue::Blob {
value: file.blob_hash.clone(),
}]);
}
values.into_iter()
}
}
impl IndexableObject for &ArchivedFileNode {
fn index_values(&self) -> impl Iterator<Item = IndexValue<'_>> {
let mut values = Vec::with_capacity(6);
values.extend([
IndexValue::Acl {
value: self
.acls
.iter()
.map(AclGrant::from)
.collect::<Vec<_>>()
.into(),
},
IndexValue::LogItem {
prefix: None,
sync_collection: SyncCollection::FileNode,
},
IndexValue::Quota {
used: self.size() as u32,
},
]);
if let Some(file) = self.file.as_ref() {
values.extend([IndexValue::Blob {
value: (&file.blob_hash).into(),
}]);
}
values.into_iter()
}
}
impl IndexableAndSerializableObject for FileNode {
fn is_versioned() -> bool {
true
}
}
impl FileNode {
pub fn size(&self) -> usize {
self.dead_properties.size()
+ self.display_name.as_ref().map_or(0, |n| n.len())
+ self.name.len()
+ self.file.as_ref().map_or(0, |f| f.size as usize)
+ std::mem::size_of::<FileNode>()
}
}
impl ArchivedFileNode {
pub fn size(&self) -> usize {
self.dead_properties.size()
+ self.display_name.as_ref().map_or(0, |n| n.len())
+ self.name.len()
+ self
.file
.as_ref()
.map_or(0, |f| f.size.to_native() as usize)
+ std::mem::size_of::<FileNode>()
}
}
+36
View File
@@ -0,0 +1,36 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
pub mod index;
pub mod storage;
use types::{acl::AclGrant, blob_hash::BlobHash, dead_property::DeadProperty};
#[derive(
rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, Debug, Default, Clone, PartialEq, Eq,
)]
#[rkyv(derive(Debug))]
pub struct FileNode {
pub parent_id: u32,
pub name: String,
pub display_name: Option<String>,
pub file: Option<FileProperties>,
pub created: i64,
pub modified: i64,
pub dead_properties: DeadProperty,
pub acls: Vec<AclGrant>,
}
#[derive(
rkyv::Archive, rkyv::Deserialize, rkyv::Serialize, Debug, Default, Clone, PartialEq, Eq,
)]
#[rkyv(derive(Debug))]
pub struct FileProperties {
pub blob_hash: BlobHash,
pub size: u32,
pub media_type: Option<String>,
pub executable: bool,
}
+170
View File
@@ -0,0 +1,170 @@
/*
* SPDX-FileCopyrightText: 2020 Stalwart Labs LLC <[email protected]>
*
* SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-SEL
*/
use super::{ArchivedFileNode, FileNode};
use crate::DestroyArchive;
use common::{Server, auth::AccountTenantIds, storage::index::ObjectIndexBuilder};
use store::{
ValueKey,
write::{AlignedBytes, Archive, BatchBuilder, now},
};
use trc::AddContext;
use types::collection::{Collection, VanishedCollection};
impl FileNode {
pub fn insert(
self,
changed_by: AccountTenantIds,
account_id: u32,
document_id: u32,
set_created: bool,
set_modified: bool,
batch: &mut BatchBuilder,
) -> trc::Result<&mut BatchBuilder> {
let mut node = self;
let now = now() as i64;
if set_created {
node.created = now;
}
if set_modified {
node.modified = now;
}
// Prepare write batch
batch
.with_account_id(account_id)
.with_collection(Collection::FileNode)
.with_document(document_id)
.custom(
ObjectIndexBuilder::<(), _>::new()
.with_changes(node)
.with_changed_by(changed_by),
)
.map(|b| b.commit_point())
}
pub fn update<'x>(
self,
changed_by: AccountTenantIds,
node: Archive<&ArchivedFileNode>,
account_id: u32,
document_id: u32,
set_modified: bool,
batch: &'x mut BatchBuilder,
) -> trc::Result<&'x mut BatchBuilder> {
let mut new_node = self;
if set_modified {
new_node.modified = now() as i64;
}
batch
.with_account_id(account_id)
.with_collection(Collection::FileNode)
.with_document(document_id)
.custom(
ObjectIndexBuilder::new()
.with_current(node)
.with_changes(new_node)
.with_changed_by(changed_by),
)
.map(|b| b.commit_point())
}
}
impl DestroyArchive<Archive<&ArchivedFileNode>> {
pub fn delete(
self,
changed_by: AccountTenantIds,
account_id: u32,
document_id: u32,
batch: &mut BatchBuilder,
path: String,
) -> trc::Result<()> {
// Prepare write batch
batch
.with_account_id(account_id)
.with_collection(Collection::FileNode)
.with_document(document_id)
.custom(
ObjectIndexBuilder::<_, ()>::new()
.with_current(self.0)
.with_changed_by(changed_by),
)?
.log_vanished_item(VanishedCollection::FileNode, path)
.commit_point();
Ok(())
}
}
impl DestroyArchive<Vec<u32>> {
pub async fn delete(
self,
server: &Server,
changed_by: AccountTenantIds,
account_id: u32,
delete_path: Option<String>,
) -> trc::Result<()> {
// Process deletions
let mut batch = BatchBuilder::new();
self.delete_batch(server, changed_by, account_id, delete_path, &mut batch)
.await?;
// Write changes
if !batch.is_empty() {
server
.commit_batch(batch)
.await
.caused_by(trc::location!())?;
}
Ok(())
}
pub async fn delete_batch(
self,
server: &Server,
changed_by: AccountTenantIds,
account_id: u32,
delete_path: Option<String>,
batch: &mut BatchBuilder,
) -> trc::Result<()> {
// Process deletions
batch
.with_account_id(account_id)
.with_collection(Collection::FileNode);
for document_id in self.0 {
if let Some(node) = server
.store()
.get_value::<Archive<AlignedBytes>>(ValueKey::archive(
account_id,
Collection::FileNode,
document_id,
))
.await?
{
// Delete record
batch
.with_document(document_id)
.custom(
ObjectIndexBuilder::<_, ()>::new()
.with_changed_by(changed_by)
.with_current(
node.to_unarchived::<FileNode>()
.caused_by(trc::location!())?,
),
)
.caused_by(trc::location!())?
.commit_point();
}
}
if !batch.is_empty()
&& let Some(delete_path) = delete_path
{
batch.log_vanished_item(VanishedCollection::FileNode, delete_path);
}
Ok(())
}
}