pub struct TaildropStore { /* private fields */ }Expand description
A Taildrop file store rooted at a fixed directory. All operations are confined to this root by
joining only validate_base_name-validated names.
Implementations§
Source§impl TaildropStore
impl TaildropStore
Sourcepub fn new(root: impl Into<PathBuf>) -> Result<Self, TaildropError>
pub fn new(root: impl Into<PathBuf>) -> Result<Self, TaildropError>
Create a store rooted at root, creating the directory (and parents) if needed.
Sourcepub async fn put_file<R>(
&self,
name: &str,
reader: R,
offset: u64,
expected_len: u64,
) -> Result<u64, TaildropError>
pub async fn put_file<R>( &self, name: &str, reader: R, offset: u64, expected_len: u64, ) -> Result<u64, TaildropError>
Receive a file named name from reader, writing to <name>.partial then atomically
renaming to a non-clobbering final name on success. Mirrors Go manager.PutFile.
offset lets a resumed transfer append past already-written bytes (the partial is opened, the
write starts at offset, and any bytes already on disk past offset are truncated away).
expected_len is the declared total length of the completed file (the request’s
Content-Length plus offset); the transfer is finalized only if exactly that many bytes are
present. Returns the total number of bytes in the completed file.
Fail-closed: an invalid name is rejected before any path is built; an in-progress partial for
the same name yields TaildropError::FileExists; an out-of-range resume offset (past the
current partial length) is rejected; an I/O error mid-transfer — or a body that ends before
expected_len (a short/interrupted stream) — leaves the .partial on disk and the final name
is never created. This matches Go feature/taildrop/send.go, which errors when the copied
length does not equal the declared length rather than publishing a truncated file.
The retained .partial is resumable only by a peer that issues a ranged retry (an offset > 0
PUT); a sender that always restarts at offset == 0 will instead hit the in-progress-conflict
path (TaildropError::FileExists) until the stale partial is cleared. There is no automatic
reaper for an abandoned partial yet (Go’s fileDeleter GCs one after ~1h); tracked separately.
Sourcepub fn waiting_files(&self) -> Result<Vec<WaitingFile>, TaildropError>
pub fn waiting_files(&self) -> Result<Vec<WaitingFile>, TaildropError>
List fully-received (non-partial) files, sorted by name (Go WaitingFiles).
Sourcepub fn delete_file(&self, name: &str) -> Result<(), TaildropError>
pub fn delete_file(&self, name: &str) -> Result<(), TaildropError>
Delete a fully-received file by base name (Go DeleteFile). The name is validated first, so a
traversal attempt can never escape the store root, and a symlink at the target is refused (Go
O_NOFOLLOW intent) rather than followed — a planted root/foo.txt -> /etc/passwd must not
let a delete foo.txt remove the link’s target.
Sourcepub fn open_file(&self, name: &str) -> Result<(File, u64), TaildropError>
pub fn open_file(&self, name: &str) -> Result<(File, u64), TaildropError>
Open a fully-received file by base name for reading, returning the handle and its size (Go
OpenFile). The name is validated first, and a symlink at the target is refused (Go
O_NOFOLLOW intent) so a planted symlink cannot redirect the read to an arbitrary file.
Trait Implementations§
Source§impl Clone for TaildropStore
impl Clone for TaildropStore
Source§fn clone(&self) -> TaildropStore
fn clone(&self) -> TaildropStore
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreAuto Trait Implementations§
impl Freeze for TaildropStore
impl RefUnwindSafe for TaildropStore
impl Send for TaildropStore
impl Sync for TaildropStore
impl Unpin for TaildropStore
impl UnsafeUnpin for TaildropStore
impl UnwindSafe for TaildropStore
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>, which can then be
downcast into Box<dyn ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>, which can then be further
downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSend for T
impl<T> DowncastSend for T
Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<A, T> DynMessage<A> for T
impl<A, T> DynMessage<A> for T
Source§fn handle_dyn<'a>(
self: Box<T>,
state: &'a mut A,
actor_ref: ActorRef<A>,
tx: Option<Sender<Result<Box<dyn Any + Send>, SendError<Box<dyn Any + Send>, Box<dyn Any + Send>>>>>,
stop: &'a mut bool,
) -> Pin<Box<dyn Future<Output = Result<(), Box<dyn ReplyError>>> + Send + 'a>>
fn handle_dyn<'a>( self: Box<T>, state: &'a mut A, actor_ref: ActorRef<A>, tx: Option<Sender<Result<Box<dyn Any + Send>, SendError<Box<dyn Any + Send>, Box<dyn Any + Send>>>>>, stop: &'a mut bool, ) -> Pin<Box<dyn Future<Output = Result<(), Box<dyn ReplyError>>> + Send + 'a>>
impl<T> ErasedDestructor for Twhere
T: 'static,
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more