cat-dev 0.0.14

A library for interacting with the CAT-DEV hardware units distributed by Nintendo (i.e. a type of Wii-U DevKits).
Documentation
//! All of the code related to filesystems.

pub mod host;
#[cfg_attr(docsrs, doc(cfg(feature = "nus")))]
#[cfg(feature = "nus")]
pub mod nus_fuse;

use std::path::PathBuf;
use valuable::{Fields, NamedField, NamedValues, StructDef, Structable, Valuable, Value, Visit};

#[cfg(feature = "nus")]
use sachet::{common::CafeContentFileInformation, title::TitleID};

/// A resolved location given an arbitrary path.
#[derive(Clone, Debug, PartialEq, Eq, Valuable)]
pub enum ResolvedLocation {
	/// A location on a particular filesystem.
	///
	/// This location _may not exist_. There is a boolean in this struct that
	/// tells you the final resolved location, the closest resolved location for
	/// permission checks, and if the path exists and is the same between
	/// resolution, and what actually exists.
	Filesystem(FilesystemLocation),
	/// A network location to fetch.
	///
	/// TODO(mythra): figure out type.
	Network(()),
	/// The location of this file is somewhere within NUS.
	#[cfg_attr(docsrs, doc(cfg(feature = "nus")))]
	#[cfg(feature = "nus")]
	NUSLocation(TitleID, PathBuf, PathBuf),
}

/// A pointer to a particular item within a folder.
#[derive(Clone, Debug, PartialEq, Eq, Valuable)]
pub enum ItemInFolder {
	/// An item that is 'local' within a folder.
	///
	/// The path that exists on disk, and the amount of components to strip.
	Local(PathBuf, usize),
	#[cfg(feature = "nus")]
	/// An item that is stored remotely in 'NUS', and doesn't actually exist on
	/// disk.
	///
	/// Items are:
	/// - Title ID
	/// - Relative path within NUS
	/// - Actual File on Disk.
	/// - File information (none on folder).
	Nus(
		Option<TitleID>,
		PathBuf,
		PathBuf,
		Option<CafeContentFileInformation>,
	),
}

/// A location that's been resolved, and is guaranteed to be in one of our
/// mounted paths.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FilesystemLocation {
	/// The final resolved path (may not exist).
	resolved_path: PathBuf,
	/// The resolved path that may not be the same as the final path, but is
	/// enough to confirm we're in the same directory.
	closest_resolved_path: PathBuf,
	/// If the canonicalized path is the same as the resolved path.
	canonicalized_is_exact: bool,
}
impl FilesystemLocation {
	#[must_use]
	pub const fn new(
		resolved_path: PathBuf,
		closest_resolved_path: PathBuf,
		canonicalized_is_exact: bool,
	) -> Self {
		Self {
			resolved_path,
			closest_resolved_path,
			canonicalized_is_exact,
		}
	}

	#[must_use]
	pub const fn resolved_path(&self) -> &PathBuf {
		&self.resolved_path
	}
	#[must_use]
	pub const fn closest_resolved_path(&self) -> &PathBuf {
		&self.closest_resolved_path
	}
	#[must_use]
	pub const fn canonicalized_is_exact(&self) -> bool {
		self.canonicalized_is_exact
	}
}

const FILESYSTEM_LOCATION_FIELDS: &[NamedField<'static>] = &[
	NamedField::new("resolved_path"),
	NamedField::new("closest_resolved_path"),
	NamedField::new("canonicalized_is_exact"),
];

impl Structable for FilesystemLocation {
	fn definition(&self) -> StructDef<'_> {
		StructDef::new_static(
			"FilesystemLocation",
			Fields::Named(FILESYSTEM_LOCATION_FIELDS),
		)
	}
}

impl Valuable for FilesystemLocation {
	fn as_value(&self) -> Value<'_> {
		Value::Structable(self)
	}

	fn visit(&self, visitor: &mut dyn Visit) {
		visitor.visit_named_fields(&NamedValues::new(
			FILESYSTEM_LOCATION_FIELDS,
			&[
				Valuable::as_value(&self.resolved_path),
				Valuable::as_value(&self.closest_resolved_path),
				Valuable::as_value(&self.canonicalized_is_exact),
			],
		));
	}
}