Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions packages/app-lib/src/api/instance/synced_packs/storage.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use super::{PackLibrary, SyncedPack};
use crate::state::content_store::{
StoredFileHandle, content_file_path, hash_file, input, validate_digest,
validate_relative,
validate_instance_path, validate_relative,
};
use crate::state::instances::adapters::sqlite::{content_rows, instance_rows};
use crate::state::{CachedEntry, State};
Expand Down Expand Up @@ -360,7 +360,7 @@ async fn recover_legacy_pack(
return Ok(stored_file);
}
for instance in instance_rows::list_instances(&state.pool).await? {
validate_relative(&instance.path)?;
validate_instance_path(&instance.path)?;
let base = state.directories.instances_dir().join(&instance.path);
if let Some(placement) = library
.instances
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use crate::state::content_store::{
ContentStore, FileContent, InstanceFileStorage, ReadableContent,
StoredFileHandle, StoredFileMetadata, StoredFileRecord, StoredFileStatus,
content_file_path, hash_file_with_progress, input, validate_digest,
validate_relative,
validate_instance_path, validate_relative,
};
use crate::state::{InstanceFile, file_modified_at_ns};
use itertools::Itertools;
Expand Down Expand Up @@ -197,7 +197,7 @@ impl ContentStore {
}
FileContent::Unmanaged => {}
}
validate_relative(instance_path)?;
validate_instance_path(instance_path)?;
let relative_path = content_file_path(file);
validate_relative(&relative_path)?;
let path = self.instance_path(instance_path, &relative_path).await?;
Expand All @@ -212,7 +212,7 @@ impl ContentStore {
instance_path: &str,
relative_path: &str,
) -> crate::Result<PathBuf> {
validate_relative(instance_path)?;
validate_instance_path(instance_path)?;
if !relative_path.is_empty() {
validate_relative(relative_path)?;
}
Expand Down
12 changes: 11 additions & 1 deletion packages/app-lib/src/state/content_store/domain/paths.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,21 @@ pub(crate) fn validate_relative(path: &str) -> crate::Result<()> {
.components()
.any(|part| !matches!(part, Component::Normal(_)))
{
return Err(input("Invalid instance-relative path"));
return Err(input(format!("Invalid instance-relative path: {path:?}")));
}
Ok(())
}

pub(crate) fn validate_instance_path(path: &str) -> crate::Result<()> {
// Legacy instance names can end in dots or spaces; preserve their on-disk path.
let normalized = path
.split('/')
.map(|part| part.trim_end_matches(['.', ' ']))
.join("/");
validate_relative(&normalized)
.map_err(|_| input(format!("Invalid instance folder path: {path:?}")))
}

pub(crate) fn is_managed_content_path(path: &str) -> bool {
if validate_relative(path).is_err() {
return false;
Expand Down
3 changes: 2 additions & 1 deletion packages/app-lib/src/state/content_store/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ pub(crate) use commands::{
};
pub(crate) use domain::{
content_file_path, file_path_on_disk, is_managed_content_path, normalize,
object_relative_path, relative_link, validate_digest, validate_relative,
object_relative_path, relative_link, validate_digest,
validate_instance_path, validate_relative,
};
use model::StoreIssue;
pub(crate) use model::{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::state::content_store;
use crate::state::content_store::{
FileStorageKind, content_file_path, hash_file, input, sync_directory,
validate_relative,
validate_instance_path, validate_relative,
};
use crate::state::content_store::{
remove_instance_file, try_shared_file, validate_parent_directories,
Expand Down Expand Up @@ -36,7 +36,7 @@ pub(super) async fn prepare(
) -> crate::Result<Vec<ManagedContentMove>> {
let mut moves = Vec::new();
for instance in instance_rows::list_instances(pool).await? {
validate_relative(&instance.path)?;
validate_instance_path(&instance.path)?;
let files =
content_rows::get_instance_files(&instance.id, pool).await?;
for binding in
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ pub(crate) fn scan_content_files(
instances_dir: &Path,
instance_path: &str,
) -> crate::Result<Vec<ScannedContentFile>> {
crate::state::content_store::validate_relative(instance_path)?;
crate::state::content_store::validate_instance_path(instance_path)?;
let instance_full_path = instances_dir.join(instance_path);
let instance_dir = io::canonicalize(instance_full_path)?;
let linked_instance =
Expand Down
11 changes: 7 additions & 4 deletions packages/app-lib/src/state/instances/commands/create_instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,8 +258,11 @@ fn content_source_kind(link: &InstanceLink) -> ContentSourceKind {
}

fn sanitize_instance_name(input: &str) -> String {
input.replace(
['/', '\\', '?', '*', ':', '\'', '\"', '|', '<', '>', '!'],
"_",
)
input
.replace(
['/', '\\', '?', '*', ':', '\'', '\"', '|', '<', '>', '!'],
"_",
)
.trim_end_matches(['.', ' '])
.to_string()
}
Loading