1 //! Blocking `pxar` random access handling.
5 use std
::os
::unix
::fs
::FileExt
;
9 use std
::task
::{Context, Poll}
;
11 use crate::accessor
::{self, cache::Cache, ReadAt}
;
12 use crate::decoder
::Decoder
;
13 use crate::format
::GoodbyeItem
;
14 use crate::util
::poll_result_once
;
17 /// Blocking `pxar` random-access decoder.
19 /// This is the blocking I/O version of the `pxar` accessor. This will *not* work with an
20 /// asynchronous I/O object. I/O must always return `Poll::Ready`.
22 /// Attempting to use a `Waker` from this context *will* `panic!`
24 /// If you need to use asynchronous I/O, use `aio::Accessor`.
26 pub struct Accessor
<T
> {
27 inner
: accessor
::AccessorImpl
<T
>,
30 impl<T
: FileExt
> Accessor
<FileReader
<T
>> {
31 /// Decode a `pxar` archive from a standard file implementing `FileExt`.
33 pub fn from_file_and_size(input
: T
, size
: u64) -> io
::Result
<Self> {
34 Accessor
::new(FileReader
::new(input
), size
)
38 impl Accessor
<FileReader
<std
::fs
::File
>> {
39 /// Decode a `pxar` archive from a regular `std::io::File` input.
41 pub fn from_file(input
: std
::fs
::File
) -> io
::Result
<Self> {
42 let size
= input
.metadata()?
.len();
43 Accessor
::from_file_and_size(input
, size
)
46 /// Convenience shortcut for `File::open` followed by `Accessor::from_file`.
47 pub fn open
<P
: AsRef
<Path
>>(path
: P
) -> io
::Result
<Self> {
48 Self::from_file(std
::fs
::File
::open(path
.as_ref())?
)
52 impl<T
: Clone
+ std
::ops
::Deref
<Target
= std
::fs
::File
>> Accessor
<FileRefReader
<T
>> {
53 /// Open an `Arc` or `Rc` of `File`.
54 pub fn from_file_ref(input
: T
) -> io
::Result
<Self> {
55 let size
= input
.deref().metadata()?
.len();
56 Accessor
::from_file_ref_and_size(input
, size
)
60 impl<T
> Accessor
<FileRefReader
<T
>>
62 T
: Clone
+ std
::ops
::Deref
,
65 /// Open an `Arc` or `Rc` of `File`.
66 pub fn from_file_ref_and_size(input
: T
, size
: u64) -> io
::Result
<Accessor
<FileRefReader
<T
>>> {
67 Accessor
::new(FileRefReader
::new(input
), size
)
71 impl<T
: ReadAt
> Accessor
<T
> {
72 /// Create a *blocking* random-access decoder from an input implementing our internal read
75 /// Note that the `input`'s `SeqRead` implementation must always return `Poll::Ready` and is
76 /// not allowed to use the `Waker`, as this will cause a `panic!`.
77 pub fn new(input
: T
, size
: u64) -> io
::Result
<Self> {
79 inner
: poll_result_once(accessor
::AccessorImpl
::new(input
, size
))?
,
83 /// Open a directory handle to the root of the pxar archive.
84 pub fn open_root_ref
<'a
>(&'a
self) -> io
::Result
<Directory
<&'a
dyn ReadAt
>> {
85 Ok(Directory
::new(poll_result_once(
86 self.inner
.open_root_ref(),
90 pub fn set_goodbye_table_cache
<C
>(&mut self, cache
: Option
<C
>)
92 C
: Cache
<u64, [GoodbyeItem
]> + Send
+ Sync
+ '
static,
95 .set_goodbye_table_cache(cache
.map(|cache
| Arc
::new(cache
) as _
))
98 /// Get the full archive size we're allowed to access.
100 pub fn size(&self) -> u64 {
105 impl<T
: Clone
+ ReadAt
> Accessor
<T
> {
106 pub fn open_root(&self) -> io
::Result
<Directory
<T
>> {
107 Ok(Directory
::new(poll_result_once(self.inner
.open_root())?
))
110 /// Allow opening a directory at a specified offset.
111 pub unsafe fn open_dir_at_end(&self, offset
: u64) -> io
::Result
<Directory
<T
>> {
112 Ok(Directory
::new(poll_result_once(
113 self.inner
.open_dir_at_end(offset
),
117 /// Allow opening a regular file from a specified range.
118 pub unsafe fn open_file_at_range(
120 entry_range_info
: &accessor
::EntryRangeInfo
,
121 ) -> io
::Result
<FileEntry
<T
>> {
123 inner
: poll_result_once(self.inner
.open_file_at_range(entry_range_info
))?
,
127 /// Allow opening arbitrary contents from a specific range.
128 pub unsafe fn open_contents_at_range(&self, range
: Range
<u64>) -> FileContents
<T
> {
130 inner
: self.inner
.open_contents_at_range(range
),
135 /// Following a hardlink.
136 pub fn follow_hardlink(&self, entry
: &FileEntry
<T
>) -> io
::Result
<FileEntry
<T
>> {
138 inner
: poll_result_once(self.inner
.follow_hardlink(&entry
.inner
))?
,
143 /// Adapter for FileExt readers.
145 pub struct FileReader
<T
> {
149 impl<T
: FileExt
> FileReader
<T
> {
150 pub fn new(inner
: T
) -> Self {
155 impl<T
: FileExt
> ReadAt
for FileReader
<T
> {
161 ) -> Poll
<io
::Result
<usize>> {
162 Poll
::Ready(self.get_ref().inner
.read_at(buf
, offset
))
166 /// Adapter for `Arc` or `Rc` to FileExt readers.
168 pub struct FileRefReader
<T
: Clone
> {
172 impl<T
: Clone
> FileRefReader
<T
> {
173 pub fn new(inner
: T
) -> Self {
178 impl<T
> ReadAt
for FileRefReader
<T
>
180 T
: Clone
+ std
::ops
::Deref
,
188 ) -> Poll
<io
::Result
<usize>> {
189 Poll
::Ready(self.get_ref().inner
.read_at(buf
, offset
))
193 /// A pxar directory entry. This provdies blocking access to the contents of a directory.
195 pub struct Directory
<T
> {
196 inner
: accessor
::DirectoryImpl
<T
>,
199 impl<T
: Clone
+ ReadAt
> Directory
<T
> {
200 fn new(inner
: accessor
::DirectoryImpl
<T
>) -> Self {
204 /// Get a decoder for the directory contents.
205 pub fn decode_full(&self) -> io
::Result
<Decoder
<accessor
::SeqReadAtAdapter
<T
>>> {
206 Ok(Decoder
::from_impl(poll_result_once(
207 self.inner
.decode_full(),
211 /// Get a `FileEntry` referencing the directory itself.
213 /// Helper function for our fuse implementation.
214 pub fn lookup_self(&self) -> io
::Result
<FileEntry
<T
>> {
216 inner
: poll_result_once(self.inner
.lookup_self())?
,
220 /// Lookup an entry starting from this current directory.
222 /// For convenience, this already resolves paths with multiple components.
223 pub fn lookup
<P
: AsRef
<Path
>>(&self, path
: P
) -> io
::Result
<Option
<FileEntry
<T
>>> {
224 if let Some(file_entry
) = poll_result_once(self.inner
.lookup(path
.as_ref()))?
{
225 Ok(Some(FileEntry { inner: file_entry }
))
231 /// Get an iterator over the directory's contents.
232 pub fn read_dir
<'a
>(&'a
self) -> ReadDir
<'a
, T
> {
234 inner
: self.inner
.read_dir(),
238 /// Get the number of entries in this directory.
240 pub fn entry_count(&self) -> usize {
241 self.inner
.entry_count()
245 /// A file entry in a direcotry, retrieved via the `lookup` method or from
246 /// `DirEntry::decode_entry``.
248 pub struct FileEntry
<T
: Clone
+ ReadAt
> {
249 inner
: accessor
::FileEntryImpl
<T
>,
252 impl<T
: Clone
+ ReadAt
> FileEntry
<T
> {
253 /// Get a handle to the subdirectory this file entry points to, if it is in fact a directory.
254 pub fn enter_directory(&self) -> io
::Result
<Directory
<T
>> {
255 Ok(Directory
::new(poll_result_once(
256 self.inner
.enter_directory(),
260 /// For use with unsafe accessor methods.
261 pub fn content_range(&self) -> io
::Result
<Option
<Range
<u64>>> {
262 self.inner
.content_range()
265 pub fn contents(&self) -> io
::Result
<FileContents
<T
>> {
267 inner
: poll_result_once(self.inner
.contents())?
,
273 pub fn into_entry(self) -> Entry
{
274 self.inner
.into_entry()
278 pub fn entry(&self) -> &Entry
{
282 /// Exposed for raw by-offset access methods (use with `open_dir_at_end`).
284 pub fn entry_range_info(&self) -> &accessor
::EntryRangeInfo
{
285 self.inner
.entry_range_info()
289 impl<T
: Clone
+ ReadAt
> std
::ops
::Deref
for FileEntry
<T
> {
292 fn deref(&self) -> &Self::Target
{
297 /// An iterator over the contents of a `Directory`.
299 pub struct ReadDir
<'a
, T
> {
300 inner
: accessor
::ReadDirImpl
<'a
, T
>,
303 impl<'a
, T
: Clone
+ ReadAt
> ReadDir
<'a
, T
> {
304 /// Efficient alternative to `Iterator::skip`.
306 pub fn skip(self, n
: usize) -> Self {
308 inner
: self.inner
.skip(n
),
312 /// Efficient alternative to `Iterator::count`.
314 pub fn count(self) -> usize {
319 impl<'a
, T
: Clone
+ ReadAt
> Iterator
for ReadDir
<'a
, T
> {
320 type Item
= io
::Result
<DirEntry
<'a
, T
>>;
322 fn next(&mut self) -> Option
<Self::Item
> {
323 match poll_result_once(self.inner
.next()) {
324 Ok(Some(inner
)) => Some(Ok(DirEntry { inner }
)),
326 Err(err
) => Some(Err(err
)),
331 impl<'a
, T
: Clone
+ ReadAt
> std
::iter
::FusedIterator
for ReadDir
<'a
, T
> {}
333 /// A directory entry. When iterating through the contents of a directory we first get access to
334 /// the file name. The remaining information can be decoded afterwards.
336 pub struct DirEntry
<'a
, T
: Clone
+ ReadAt
> {
337 inner
: accessor
::DirEntryImpl
<'a
, T
>,
340 impl<'a
, T
: Clone
+ ReadAt
> DirEntry
<'a
, T
> {
341 /// Get the current file name.
342 pub fn file_name(&self) -> &Path
{
343 self.inner
.file_name()
346 /// Decode the entry.
348 /// When iterating over a directory, the file name is read separately from the file attributes,
349 /// so only the file name is available here, while the attributes still need to be decoded.
350 pub fn decode_entry(&self) -> io
::Result
<FileEntry
<T
>> {
351 poll_result_once(self.inner
.decode_entry()).map(|inner
| FileEntry { inner }
)
354 /// Exposed for raw by-offset access methods.
356 pub fn entry_range_info(&self) -> &accessor
::EntryRangeInfo
{
357 self.inner
.entry_range_info()
361 /// A reader for file contents.
362 pub struct FileContents
<T
> {
363 inner
: accessor
::FileContentsImpl
<T
>,
367 impl<T
: Clone
+ ReadAt
> io
::Read
for FileContents
<T
> {
368 fn read(&mut self, buf
: &mut [u8]) -> io
::Result
<usize> {
369 let got
= poll_result_once(self.inner
.read_at(buf
, self.at
))?
;
370 self.at
+= got
as u64;
375 impl<T
: Clone
+ ReadAt
> FileExt
for FileContents
<T
> {
376 fn read_at(&self, buf
: &mut [u8], offset
: u64) -> io
::Result
<usize> {
377 poll_result_once(self.inner
.read_at(buf
, offset
))
380 fn write_at(&self, _buf
: &[u8], _offset
: u64) -> io
::Result
<usize> {
381 io_bail
!("write_at on read-only file");
385 impl<T
: Clone
+ ReadAt
> ReadAt
for FileContents
<T
> {
391 ) -> Poll
<io
::Result
<usize>> {
392 Poll
::Ready(poll_result_once(self.get_ref().inner
.read_at(buf
, offset
)))