1 //! Blocking `pxar` encoder.
6 use std
::task
::{Context, Poll}
;
8 use crate::decoder
::sync
::StandardReader
;
9 use crate::encoder
::{self, SeqWrite, LinkOffset}
;
11 use crate::util
::poll_result_once
;
14 /// Blocking `pxar` encoder.
16 /// This is the blocking I/O version of the `pxar` encoder. This will *not* work with an
17 /// asynchronous I/O object. I/O must always return `Poll::Ready`.
19 /// Attempting to use a `Waker` from this context *will* `panic!`
21 /// If you need to use asynchronous I/O, use `aio::Encoder`.
23 pub struct Encoder
<'a
, T
: SeqWrite
+ 'a
> {
24 inner
: encoder
::EncoderImpl
<'a
, T
>,
27 impl<'a
, T
: io
::Write
+ 'a
> Encoder
<'a
, StandardWriter
<T
>> {
28 /// Encode a `pxar` archive into a regular `std::io::Write` output.
30 pub fn from_std(output
: T
, metadata
: &Metadata
) -> io
::Result
<Encoder
<StandardWriter
<T
>>> {
31 Encoder
::new(StandardWriter
::new(output
), metadata
)
35 impl<'a
> Encoder
<'a
, StandardWriter
<std
::fs
::File
>> {
36 /// Convenience shortcut for `File::create` followed by `Encoder::from_file`.
37 pub fn create
<'b
, P
: AsRef
<Path
>>(
39 metadata
: &'b Metadata
,
40 ) -> io
::Result
<Encoder
<'a
, StandardWriter
<std
::fs
::File
>>> {
42 StandardWriter
::new(std
::fs
::File
::create(path
.as_ref())?
),
48 impl<'a
, T
: SeqWrite
+ 'a
> Encoder
<'a
, T
> {
49 /// Create a *blocking* encoder for an output implementing our internal write interface.
51 /// Note that the `output`'s `SeqWrite` implementation must always return `Poll::Ready` and is
52 /// not allowed to use the `Waker`, as this will cause a `panic!`.
53 pub fn new(output
: T
, metadata
: &Metadata
) -> io
::Result
<Self> {
55 inner
: poll_result_once(encoder
::EncoderImpl
::new(output
, metadata
))?
,
59 /// Create a new regular file in the archive. This returns a `File` object to which the
60 /// contents have to be written out *completely*. Failing to do so will put the encoder into an
62 pub fn create_file
<'b
, P
: AsRef
<Path
>>(
67 ) -> io
::Result
<File
<'b
>>
72 inner
: poll_result_once(self.inner
.create_file(
80 /// Convenience shortcut to add a *regular* file by path including its contents to the archive.
81 pub fn add_file
<P
: AsRef
<Path
>>(
86 content
: &mut dyn io
::Read
,
87 ) -> io
::Result
<LinkOffset
> {
88 poll_result_once(self.inner
.add_file(
92 &mut StandardReader
::new(content
),
96 /// Create a new subdirectory. Note that the subdirectory has to be finished by calling the
97 /// `finish()` method, otherwise the entire archive will be in an error state.
98 pub fn create_directory
<'b
, P
: AsRef
<Path
>>(
102 ) -> io
::Result
<Encoder
<'b
, &'b
mut dyn SeqWrite
>>
107 inner
: poll_result_once(self.inner
.create_directory(file_name
.as_ref(), metadata
))?
,
111 /// Finish this directory. This is mandatory, otherwise the `Drop` handler will `panic!`.
112 pub fn finish(self) -> io
::Result
<()> {
113 poll_result_once(self.inner
.finish())
116 /// Add a symbolic link to the archive.
117 pub fn add_symlink
<PF
: AsRef
<Path
>, PT
: AsRef
<Path
>>(
122 ) -> io
::Result
<LinkOffset
> {
125 .add_symlink(metadata
, file_name
.as_ref(), target
.as_ref()),
129 /// Add a hard link to the archive.
130 pub fn add_hardlink
<PF
: AsRef
<Path
>, PT
: AsRef
<Path
>>(
135 ) -> io
::Result
<()> {
136 poll_result_once(self.inner
.add_hardlink(file_name
.as_ref(), target
.as_ref(), offset
))
139 /// Add a device node to the archive.
140 pub fn add_device
<P
: AsRef
<Path
>>(
144 device
: format
::Device
,
145 ) -> io
::Result
<LinkOffset
> {
146 poll_result_once(self.inner
.add_device(metadata
, file_name
.as_ref(), device
))
149 /// Add a fifo node to the archive.
150 pub fn add_fifo
<P
: AsRef
<Path
>>(
154 ) -> io
::Result
<LinkOffset
> {
155 poll_result_once(self.inner
.add_fifo(metadata
, file_name
.as_ref()))
158 /// Add a socket node to the archive.
159 pub fn add_socket
<P
: AsRef
<Path
>>(
163 ) -> io
::Result
<LinkOffset
> {
164 poll_result_once(self.inner
.add_socket(metadata
, file_name
.as_ref()))
169 pub struct File
<'a
> {
170 inner
: encoder
::FileImpl
<'a
>,
174 /// Get the file offset to be able to reference it with `add_hardlink`.
175 pub fn file_offset(&self) -> LinkOffset
{
176 self.inner
.file_offset()
180 impl<'a
> io
::Write
for File
<'a
> {
181 fn write(&mut self, data
: &[u8]) -> io
::Result
<usize> {
182 poll_result_once(self.inner
.write(data
))
185 fn flush(&mut self) -> io
::Result
<()> {
190 /// Pxar encoder write adapter for `std::io::Write`.
191 pub struct StandardWriter
<T
> {
196 impl<T
: io
::Write
> StandardWriter
<T
> {
197 pub fn new(inner
: T
) -> Self {
204 fn inner(&mut self) -> io
::Result
<&mut T
> {
207 .ok_or_else(|| io_format_err
!("write after close"))
210 fn pin_to_inner(self: Pin
<&mut Self>) -> io
::Result
<&mut T
> {
211 unsafe { self.get_unchecked_mut() }
.inner()
215 impl<T
: io
::Write
> SeqWrite
for StandardWriter
<T
> {
217 self: Pin
<&mut Self>,
220 ) -> Poll
<io
::Result
<usize>> {
221 let this
= unsafe { self.get_unchecked_mut() }
;
222 Poll
::Ready(match this
.inner()?
.write(buf
) {
224 this
.position
+= got
as u64;
227 Err(err
) => Err(err
),
231 fn poll_position(self: Pin
<&mut Self>, _cx
: &mut Context
) -> Poll
<io
::Result
<u64>> {
232 Poll
::Ready(Ok(self.as_ref().position
))
235 fn poll_flush(self: Pin
<&mut Self>, _cx
: &mut Context
) -> Poll
<io
::Result
<()>> {
236 Poll
::Ready(self.pin_to_inner().and_then(|inner
| inner
.flush()))
239 fn poll_close(self: Pin
<&mut Self>, _cx
: &mut Context
) -> Poll
<io
::Result
<()>> {
240 let this
= unsafe { self.get_unchecked_mut() }
;
241 Poll
::Ready(match this
.inner
.as_mut() {