work
Avril 4 years ago
parent 9e7586021c
commit dbd0e068f6
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -0,0 +1,94 @@
//! Database manipulation stuffs
use super::*;
use std::{
path::{
PathBuf,
},
error,
fmt,
io,
marker::Unpin,
};
/// An error in database operations
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
ExpectedLine(Option<String>),
IO(io::Error),
Unknown,
}
impl error::Error for Error
{
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match &self {
Self::IO(io) => Some(io),
_ => None,
}
}
}
impl fmt::Display for Error
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{
match self {
Self::IO(_)=> write!(f, "i/o"),
Self::ExpectedLine(None) => write!(f, "expected a line that was not present in the file"),
Self::ExpectedLine(Some(msg)) => write!(f, "{}", msg),
_ => write!(f, "unknown"),
}
}
}
/// Contains Videl information for a database directory
#[derive(Debug, Clone, PartialEq, Ord, Eq, PartialOrd, Hash)]
pub struct Database
{
pub path: PathBuf,
}
impl Database
{
/// Save this database to a stream
pub async fn save<T: AsyncWrite + Unpin + ?Sized>(&self, stream: &mut T) -> Result<usize, Error>
{
let bytes = resolve::path_bytes(&self.path);
stream.write_all(&bytes[..]).await?;
stream.write_u8(b'\n').await?;
Ok(bytes.len() + 1)
}
}
/// Load database info from this file
pub async fn load<T: AsyncBufRead + Unpin + ?Sized>(stream: &mut T) -> Result<Database, Error>
{
let mut buffer = String::new();
macro_rules! line {
($message:literal $($tt:tt)*) => {
{
buffer.clear();
let read = stream.read_line(&mut buffer).await?;
if read == 0 {
return Err(Error::ExpectedLine(Some(format!($message $($tt)*))));
}
&buffer[..]
}
}
}
let location_encoded = line!("expected the location line");
Ok(Database{
path: PathBuf::from(location_encoded),
})
}
impl From<io::Error> for Error
{
#[inline] fn from(from: io::Error) -> Self
{
Self::IO(from)
}
}

@ -4,7 +4,11 @@
use cfg_if::cfg_if; use cfg_if::cfg_if;
use lazy_static::lazy_static; use lazy_static::lazy_static;
use futures::prelude::*; //use futures::prelude::*;
use tokio::prelude::*;
use futures::{
Future,
};
#[allow(unused_imports)] #[allow(unused_imports)]
use color_eyre::{ use color_eyre::{
@ -21,12 +25,15 @@ use std::{
mod ext; mod ext;
use ext::*; use ext::*;
mod util; mod util;
mod dedup;
mod resolve;
mod database;
mod args; mod args;
mod config; mod config;
mod resolve;
mod dedup;
cfg_if!{ cfg_if!{
if #[cfg(nightly)] { if #[cfg(nightly)] {
@ -50,7 +57,11 @@ async fn process(config: Arc<config::Config>, file: String)
println!(" -> {:?}", file); println!(" -> {:?}", file);
let dbdir = resolve::mangle_path(&config, &file); let dbdir = resolve::mangle_path(&config, &file);
println!("Database path for this file {:?}", dbdir); println!("Database path for this file {:?}", dbdir);
println!("Demangle: {:?}", resolve::demangle_path(&dbdir).await); println!("Demangle: {:?}", resolve::demangle_path(&dbdir).await
.wrap_err(eyre!("Failed to demangle path"))
.with_section(|| dbdir.to_string_lossy().into_owned().header("Path was"))
.with_section(|| config.base_dir.clone().to_string_lossy().into_owned().header("The videl database root directory is"))
.with_suggestion(|| "Are you sure this database location is correct"));
} }
async fn begin() -> eyre::Result<i32> async fn begin() -> eyre::Result<i32>

@ -8,8 +8,14 @@ use std::{
collections::HashMap, collections::HashMap,
fmt, fmt,
error, error,
borrow::Cow,
}; };
use std::os::unix::ffi::{OsStrExt, OsStringExt}; use std::os::unix::ffi::{OsStrExt, OsStringExt};
use tokio::{
fs::{
OpenOptions,
},
};
#[cfg(not(feature="fast-pathnames"))] #[cfg(not(feature="fast-pathnames"))]
fn compute_hash_string(from: impl AsRef<[u8]>) -> String fn compute_hash_string(from: impl AsRef<[u8]>) -> String
@ -55,14 +61,44 @@ pub fn mangle_path(config: &config::Config, path: impl AsRef<Path>) -> PathBuf
} }
#[derive(Debug)] #[derive(Debug)]
pub struct ResolutionError; #[non_exhaustive]
pub enum ResolutionError
{
Name,
Utf8,
#[cfg(feature="fast-pathnames")]
Base64Decode(base64::Error),
IO(io::Error),
Open(io::Error),
Database(database::Error),
Unknown,
}
impl error::Error for ResolutionError{} impl error::Error for ResolutionError
{
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
Some(match &self {
#[cfg(feature="fast-pathnames")] Self::Base64Decode(er) => er,
Self::IO(er)=>er,
Self::Open(er)=>er,
Self::Database(er)=>er,
_ => return None,
})
}
}
impl fmt::Display for ResolutionError impl fmt::Display for ResolutionError
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
{ {
write!(f, "database path was in an invalid format") match self {
Self::Name => write!(f, "invalid pathname"),
Self::Utf8 => write!(f, "pathname contained invalid UTF-8"),
#[cfg(feature="fast-pathnames")] Self::Base64Decode(_) => write!(f, "failed to decode base64 pathname"),
Self::IO(_) => write!(f, "i/o error"),
Self::Open(_) => write!(f, "failed to open file"),
Self::Database(_) => write!(f, "failed to parse database"),
_ => write!(f, "unknown error")
}
} }
} }
@ -71,14 +107,26 @@ pub async fn demangle_path(path: impl AsRef<Path>) -> Result<PathBuf, Resolution
{ {
cfg_if! { cfg_if! {
if #[cfg(feature="fast-pathnames")] { if #[cfg(feature="fast-pathnames")] {
let part = path.as_ref().file_name().ok_or(ResolutionError)?; //get the base64 encoded part let part = path.as_ref().file_name().ok_or(ResolutionError::Name)?; //get the base64 encoded part
let part = replace_base64_from(part.to_str().ok_or(ResolutionError)?); //replace characters back let part = replace_base64_from(part.to_str().ok_or(ResolutionError::Utf8)?); //replace characters back
let bytes = base64::decode(part).map_err(|_| ResolutionError)?; let bytes = base64::decode(part).map_err(ResolutionError::Base64Decode)?;
Ok(std::ffi::OsString::from_vec(bytes).into()) Ok(std::ffi::OsString::from_vec(bytes).into())
} else { } else {
//TODO: Look up in `path/metadata` file let metafile = path.as_ref().join("metadata");
todo!() let file = OpenOptions::new()
.read(true)
.open(metafile).await.map_err(ResolutionError::Open)?;
let mut file = tokio::io::BufReader::new(file);
let db = database::load(&mut file).await.map_err(ResolutionError::Database)?;
Ok(db.path)
}
} }
} }
/// Get bytes from a path
pub fn path_bytes<'a, P: AsRef<Path> + ?Sized>(path: &'a P) -> Cow<'a, [u8]>
{
//for now, just use unix ext'ss things
Cow::Borrowed(path.as_ref().as_os_str().as_bytes())
} }

Loading…
Cancel
Save