Implement encoding and decoding for Windows-invalid characters in file names

- Added `encode_path_name` and `decode_path_name` functions to handle encoding and decoding of invalid characters.
- Updated `SyncbackRules` to include an option for encoding Windows-invalid characters during syncback.
- Modified `name_for_inst` to conditionally encode invalid characters based on the new option.
- Adjusted `ServeSession` and `InstanceContext` to support the new encoding feature.
- Updated tests and snapshots to reflect changes in encoding behavior.
This commit is contained in:
Joe 2025-12-19 22:50:53 -06:00
parent db87fa010f
commit 6d8c85682d
59 changed files with 350 additions and 53 deletions

View file

@ -6,12 +6,15 @@ use std::borrow::Cow;
use anyhow::Context;
use rbx_dom_weak::Instance;
use crate::{snapshot::InstanceWithMeta, snapshot_middleware::Middleware};
use crate::{
path_encoding::encode_path_name, snapshot::InstanceWithMeta, snapshot_middleware::Middleware,
};
pub fn name_for_inst<'old>(
middleware: Middleware,
new_inst: &Instance,
old_inst: Option<InstanceWithMeta<'old>>,
encode_invalid_chars: bool,
) -> anyhow::Result<Cow<'old, str>> {
if let Some(old_inst) = old_inst {
if let Some(source) = old_inst.metadata().relevant_paths.first() {
@ -35,13 +38,37 @@ pub fn name_for_inst<'old>(
| Middleware::CsvDir
| Middleware::ServerScriptDir
| Middleware::ClientScriptDir
| Middleware::ModuleScriptDir => Cow::Owned(new_inst.name.clone()),
| Middleware::ModuleScriptDir => {
let name = if encode_invalid_chars {
let encoded = encode_path_name(&new_inst.name);
// Validate for issues not fixed by encoding (trailing space/dot, control chars, reserved names)
validate_file_name(&encoded).with_context(|| {
format!("name '{}' (encoded from '{}') is not legal to write to the file system", encoded, new_inst.name)
})?;
encoded
} else {
validate_file_name(&new_inst.name).with_context(|| {
format!("name '{}' is not legal to write to the file system", new_inst.name)
})?;
new_inst.name.clone()
};
Cow::Owned(name)
}
_ => {
let extension = extension_for_middleware(middleware);
let name = &new_inst.name;
validate_file_name(name).with_context(|| {
format!("name '{name}' is not legal to write to the file system")
})?;
let name = if encode_invalid_chars {
let encoded = encode_path_name(&new_inst.name);
// Validate for issues not fixed by encoding (trailing space/dot, control chars, reserved names)
validate_file_name(&encoded).with_context(|| {
format!("name '{}' (encoded from '{}') is not legal to write to the file system", encoded, new_inst.name)
})?;
encoded
} else {
validate_file_name(&new_inst.name).with_context(|| {
format!("name '{}' is not legal to write to the file system", new_inst.name)
})?;
new_inst.name.clone()
};
Cow::Owned(format!("{name}.{extension}"))
}
})