init
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
/target
|
25
Cargo.lock
generated
Normal file
25
Cargo.lock
generated
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "cfg-if"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "encoding_rs"
|
||||||
|
version = "0.8.35"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "restore-structure"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"encoding_rs",
|
||||||
|
]
|
7
Cargo.toml
Normal file
7
Cargo.toml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
[package]
|
||||||
|
name = "restore-structure"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
encoding_rs = "0.8.35"
|
68
src/main.rs
Normal file
68
src/main.rs
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
use std::fs;
|
||||||
|
use std::io;
|
||||||
|
use std::path::{Path, PathBuf};
|
||||||
|
|
||||||
|
use encoding_rs::WINDOWS_1250;
|
||||||
|
#[cfg(unix)]
|
||||||
|
use std::os::unix::ffi::OsStrExt;
|
||||||
|
|
||||||
|
fn main() -> io::Result<()> {
|
||||||
|
// Get input directory from command line arguments
|
||||||
|
let args: Vec<String> = std::env::args().collect();
|
||||||
|
if args.len() < 3 {
|
||||||
|
eprintln!("Usage: {} <input_directory> <output_directory>", args[0]);
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
|
let input_dir = PathBuf::from(&args[1]);
|
||||||
|
let output_dir = PathBuf::from(&args[2]);
|
||||||
|
let input_dir = Path::new(&input_dir);
|
||||||
|
let output_dir = Path::new(&output_dir);
|
||||||
|
|
||||||
|
fs::create_dir_all(output_dir)?;
|
||||||
|
|
||||||
|
for entry in fs::read_dir(input_dir)? {
|
||||||
|
let entry = entry?;
|
||||||
|
let file_type = entry.file_type()?;
|
||||||
|
if !file_type.is_file() {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Handle possibly non-UTF8 filenames ----
|
||||||
|
#[cfg(unix)]
|
||||||
|
let file_name = {
|
||||||
|
let raw = entry.file_name();
|
||||||
|
let bytes = raw.as_bytes();
|
||||||
|
let (decoded, _, _) = WINDOWS_1250.decode(bytes);
|
||||||
|
decoded.into_owned()
|
||||||
|
};
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
let file_name = entry.file_name().to_string_lossy().into_owned();
|
||||||
|
|
||||||
|
let path_segments: Vec<&str> = file_name.split('\\').filter(|s| !s.is_empty()).collect();
|
||||||
|
|
||||||
|
let mut restored_path = output_dir.to_path_buf();
|
||||||
|
for segment in path_segments {
|
||||||
|
restored_path.push(segment);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(parent) = restored_path.parent() {
|
||||||
|
fs::create_dir_all(parent)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to move, fall back to copy+delete if needed (cross-filesystem safe)
|
||||||
|
match fs::rename(entry.path(), &restored_path) {
|
||||||
|
Ok(_) => {}
|
||||||
|
Err(_) => {
|
||||||
|
fs::copy(entry.path(), &restored_path)?;
|
||||||
|
// fs::remove_file(entry.path())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
println!(
|
||||||
|
"Restored: {} -> {}",
|
||||||
|
entry.path().display(),
|
||||||
|
restored_path.display()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Reference in New Issue
Block a user