use std::pin::Pin;
use std::task::{Context, Poll};
-use crate::encoder::{self, SeqWrite};
+use crate::encoder::{self, SeqWrite, LinkOffset};
use crate::format;
use crate::Metadata;
metadata: &Metadata,
file_name: PF,
target: PT,
- ) -> io::Result<()> {
+ ) -> io::Result<LinkOffset> {
self.inner
.add_symlink(metadata, file_name.as_ref(), target.as_ref())
.await
&mut self,
file_name: PF,
target: PT,
- offset: u64,
+ offset: LinkOffset,
) -> io::Result<()> {
self.inner
.add_hardlink(file_name.as_ref(), target.as_ref(), offset)
metadata: &Metadata,
file_name: P,
device: format::Device,
- ) -> io::Result<()> {
+ ) -> io::Result<LinkOffset> {
self.inner
.add_device(metadata, file_name.as_ref(), device)
.await
&mut self,
metadata: &Metadata,
file_name: P,
- ) -> io::Result<()> {
+ ) -> io::Result<LinkOffset> {
self.inner.add_fifo(metadata, file_name.as_ref()).await
}
&mut self,
metadata: &Metadata,
file_name: P,
- ) -> io::Result<()> {
+ ) -> io::Result<LinkOffset> {
self.inner.add_socket(metadata, file_name.as_ref()).await
}
}
inner: encoder::FileImpl<'a>,
}
+impl<'a> File<'a> {
+ /// Get the file offset to be able to reference it with `add_hardlink`.
+ pub fn file_offset(&self) -> LinkOffset {
+ self.inner.file_offset()
+ }
+
+ /// Write file data for the current file entry in a pxar archive.
+ pub async fn write(&mut self, data: &[u8]) -> io::Result<usize> {
+ self.inner.write(data).await
+ }
+
+ /// Completely write file data for the current file entry in a pxar archive.
+ pub async fn write_all(&mut self, data: &[u8]) -> io::Result<()> {
+ self.inner.write_all(data).await
+ }
+}
+
#[cfg(feature = "futures-io")]
impl<'a> futures::io::AsyncWrite for File<'a> {
fn poll_write(self: Pin<&mut Self>, cx: &mut Context, data: &[u8]) -> Poll<io::Result<usize>> {
#[doc(inline)]
pub use sync::Encoder;
+/// File reference used to create hard links.
+#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
+pub struct LinkOffset(u64);
+
+impl LinkOffset {
+ #[inline]
+ pub fn raw(self) -> u64 {
+ self.0
+ }
+}
+
/// Sequential write interface used by the encoder's state machine.
///
/// This is our internal writer trait which is available for `std::io::Write` types in the
})
}
+ /// Return a file offset usable with `add_hardlink`.
pub async fn add_file(
&mut self,
metadata: &Metadata,
file_name: &Path,
file_size: u64,
content: &mut dyn SeqRead,
- ) -> io::Result<()> {
+ ) -> io::Result<LinkOffset> {
let mut file = self.create_file(metadata, file_name, file_size).await?;
let mut buf = crate::util::vec_new(4096);
loop {
file.write_all(&buf[..got]).await?;
}
}
- Ok(())
+ Ok(file.file_offset())
}
+ /// Return a file offset usable with `add_hardlink`.
pub async fn add_symlink(
&mut self,
metadata: &Metadata,
file_name: &Path,
target: &Path,
- ) -> io::Result<()> {
+ ) -> io::Result<LinkOffset> {
self.add_file_entry(
Some(metadata),
file_name,
.await
}
+ /// Return a file offset usable with `add_hardlink`.
pub async fn add_hardlink(
&mut self,
file_name: &Path,
target: &Path,
- offset: u64,
+ offset: LinkOffset,
) -> io::Result<()> {
let hardlink = format::Hardlink {
- offset,
+ offset: offset.0,
data: target.as_os_str().as_bytes().to_vec(),
};
let hardlink = unsafe {
size_of::<format::Hardlink>(),
)
};
- self.add_file_entry(
+ let _this_offset: LinkOffset = self.add_file_entry(
None,
file_name,
Some((format::PXAR_HARDLINK, hardlink)),
)
- .await
+ .await?;
+ Ok(())
}
+ /// Return a file offset usable with `add_hardlink`.
pub async fn add_device(
&mut self,
metadata: &Metadata,
file_name: &Path,
device: format::Device,
- ) -> io::Result<()> {
+ ) -> io::Result<LinkOffset> {
if !metadata.is_device() {
io_bail!("entry added via add_device must have a device mode in its metadata");
}
.await
}
- pub async fn add_fifo(&mut self, metadata: &Metadata, file_name: &Path) -> io::Result<()> {
+ /// Return a file offset usable with `add_hardlink`.
+ pub async fn add_fifo(&mut self, metadata: &Metadata, file_name: &Path) -> io::Result<LinkOffset> {
if !metadata.is_fifo() {
io_bail!("entry added via add_device must be of type fifo in its metadata");
}
self.add_file_entry(Some(metadata), file_name, None).await
}
- pub async fn add_socket(&mut self, metadata: &Metadata, file_name: &Path) -> io::Result<()> {
+ /// Return a file offset usable with `add_hardlink`.
+ pub async fn add_socket(&mut self, metadata: &Metadata, file_name: &Path) -> io::Result<LinkOffset> {
if !metadata.is_socket() {
io_bail!("entry added via add_device must be of type socket in its metadata");
}
self.add_file_entry(Some(metadata), file_name, None).await
}
+ /// Return a file offset usable with `add_hardlink`.
async fn add_file_entry(
&mut self,
metadata: Option<&Metadata>,
file_name: &Path,
entry_htype_data: Option<(u64, &[u8])>,
- ) -> io::Result<()> {
+ ) -> io::Result<LinkOffset> {
self.check()?;
let file_offset = seq_write_position(&mut self.output).await?;
size: end_offset - file_offset,
});
- Ok(())
+ Ok(LinkOffset(file_offset))
}
/// Helper
}
impl<'a> FileImpl<'a> {
+ /// Get the file offset to be able to reference it with `add_hardlink`.
+ pub fn file_offset(&self) -> LinkOffset {
+ LinkOffset(self.goodbye_item.offset)
+ }
+
fn check_remaining(&self, size: usize) -> io::Result<()> {
if size as u64 > self.remaining_size {
io_bail!("attempted to write more than previously allocated");
use std::task::{Context, Poll};
use crate::decoder::sync::StandardReader;
-use crate::encoder::{self, SeqWrite};
+use crate::encoder::{self, SeqWrite, LinkOffset};
use crate::format;
use crate::util::poll_result_once;
use crate::Metadata;
file_name: P,
file_size: u64,
content: &mut dyn io::Read,
- ) -> io::Result<()> {
+ ) -> io::Result<LinkOffset> {
poll_result_once(self.inner.add_file(
metadata,
file_name.as_ref(),
metadata: &Metadata,
file_name: PF,
target: PT,
- ) -> io::Result<()> {
+ ) -> io::Result<LinkOffset> {
poll_result_once(
self.inner
.add_symlink(metadata, file_name.as_ref(), target.as_ref()),
&mut self,
file_name: PF,
target: PT,
- offset: u64,
+ offset: LinkOffset,
) -> io::Result<()> {
poll_result_once(self.inner.add_hardlink(file_name.as_ref(), target.as_ref(), offset))
}
metadata: &Metadata,
file_name: P,
device: format::Device,
- ) -> io::Result<()> {
+ ) -> io::Result<LinkOffset> {
poll_result_once(self.inner.add_device(metadata, file_name.as_ref(), device))
}
&mut self,
metadata: &Metadata,
file_name: P,
- ) -> io::Result<()> {
+ ) -> io::Result<LinkOffset> {
poll_result_once(self.inner.add_fifo(metadata, file_name.as_ref()))
}
&mut self,
metadata: &Metadata,
file_name: P,
- ) -> io::Result<()> {
+ ) -> io::Result<LinkOffset> {
poll_result_once(self.inner.add_socket(metadata, file_name.as_ref()))
}
}
inner: encoder::FileImpl<'a>,
}
+impl<'a> File<'a> {
+ /// Get the file offset to be able to reference it with `add_hardlink`.
+ pub fn file_offset(&self) -> LinkOffset {
+ self.inner.file_offset()
+ }
+}
+
impl<'a> io::Write for File<'a> {
fn write(&mut self, data: &[u8]) -> io::Result<usize> {
poll_result_once(self.inner.write(data))