diff --git a/libarchive/src/error.rs b/libarchive/src/error.rs index 2243865..48ca302 100644 --- a/libarchive/src/error.rs +++ b/libarchive/src/error.rs @@ -1,6 +1,7 @@ use crate::archive; use std::error; use std::fmt; +use std::io; pub type Result = std::result::Result; @@ -48,3 +49,9 @@ impl<'a> From<&'a dyn archive::Handle> for Result<()> { } } } + +impl From for io::Error { + fn from(err: ArchiveError) -> Self { + io::Error::new(io::ErrorKind::Other, format!("{}", err)) + } +} diff --git a/libarchive/src/lib.rs b/libarchive/src/lib.rs index 7ab9fbb..25ad235 100644 --- a/libarchive/src/lib.rs +++ b/libarchive/src/lib.rs @@ -3,18 +3,3 @@ pub mod error; pub mod read; pub use error::Result; - -pub fn add(left: usize, right: usize) -> usize { - left + right -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); - } -} diff --git a/libarchive/src/read/builder.rs b/libarchive/src/read/builder.rs index 50cbd59..73270e2 100644 --- a/libarchive/src/read/builder.rs +++ b/libarchive/src/read/builder.rs @@ -1,11 +1,11 @@ +use super::file::ArchiveFile; use crate::archive::{Handle, ReadCompression, ReadFilter, ReadFormat}; -use libarchive3_sys::ffi; use crate::error::{ArchiveError, Result}; +use crate::read::Archive; +use libarchive3_sys::ffi; use std::ffi::CString; use std::mem; use std::path::Path; -use super::file::ArchiveFile; -use crate::read::Archive; /// A struct that allows configuration of the reader before it is created. pub struct Builder { diff --git a/libarchive/src/read/entries.rs b/libarchive/src/read/entries.rs new file mode 100644 index 0000000..3e22155 --- /dev/null +++ b/libarchive/src/read/entries.rs @@ -0,0 +1,123 @@ +use crate::archive::Entry; +use crate::error::ArchiveError; +use crate::read::Archive; +use libarchive3_sys::ffi; +use libc::{c_void, ssize_t}; +use std::io; +use std::io::Read; +use std::marker; + +pub struct ReadEntry<'a, T: Archive> { + archive: *mut ffi::Struct_archive, + entry: *mut ffi::Struct_archive_entry, + offset: usize, + _ignored: marker::PhantomData<&'a T>, +} + +//impl<'b, T: Archive + 'b> ReadEntry<'b, T> { +// /// Create a new ReaderEntry from a raw pointer to an `archive_entry` struct +// /// +// /// # Safety +// /// The pointer must own the struct it points to, otherwise it may be freed twice +// pub unsafe fn new(archive: &'b mut T, handle: *mut ffi::Struct_archive_entry) -> Self { +// Self { archive, handle } +// } +//} + +impl<'a, T: Archive> Entry for ReadEntry<'a, T> { + unsafe fn entry(&self) -> *const ffi::Struct_archive_entry { + self.entry as *const _ + } + + unsafe fn entry_mut(&mut self) -> *mut ffi::Struct_archive_entry { + self.entry + } +} + +pub struct Entries<'a, T: 'a + Archive> { + archive: &'a mut T, // entry: &'b mut ReadEntry<'b, T> + // entry_handle: *mut ffi::Struct_archive_entry, // entry: ReadEntry<'a, T> +} + +// impl Default for ReadEntry { +// fn default() -> Self { +// Self { +// handle: std::ptr::null_mut(), +// } +// } +// } + +impl<'a, T: 'a + Archive> Entries<'a, T> { + pub fn new(archive: &'a mut T) -> Self { + Self { archive } + } +} + +// impl<'a, T: 'a + Archive> EntryFields<'a, T> { +// fn read_next_header(&'a mut self) -> crate::Result>> { +// let mut entry_ptr: *mut ffi::Struct_archive_entry = std::ptr::null_mut(); + +// let res = unsafe { +// ffi::archive_read_next_header(self.archive.handle() as *mut _, &mut entry_ptr) +// }; + +// match res { +// ffi::ARCHIVE_OK | ffi::ARCHIVE_WARN => Ok(Some(unsafe { +// EntryFields::new(self.archive, entry_ptr).into_entry() +// })), +// ffi::ARCHIVE_EOF => Ok(None), +// _ => Err(ArchiveError::Sys( +// self.archive.err_code(), +// self.archive.err_msg().to_owned(), +// )), +// } +// } +// } + +impl<'a, T: Archive + 'a> Iterator for Entries<'a, T> { + type Item = crate::Result>; + + fn next(&mut self) -> Option { + let mut entry_ptr: *mut ffi::Struct_archive_entry = std::ptr::null_mut(); + + let res = unsafe { + ffi::archive_read_next_header(self.archive.handle() as *mut _, &mut entry_ptr) + }; + + match res { + ffi::ARCHIVE_OK | ffi::ARCHIVE_WARN => { + let entry = ReadEntry { + archive: unsafe { self.archive.handle_mut() }, + entry: entry_ptr, + offset: 0, + _ignored: marker::PhantomData, + }; + + Some(Ok(entry)) + } + ffi::ARCHIVE_EOF => None, + _ => Some(Err(ArchiveError::Sys( + self.archive.err_code(), + self.archive.err_msg().to_owned(), + ))), + } + } +} + +impl<'a, T: Archive> Read for ReadEntry<'a, T> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let res = + unsafe { ffi::archive_read_data(self.archive, buf as *mut [u8] as *mut _, buf.len()) }; + + if res >= 0 { + let count: usize = res + .try_into() + .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?; + self.offset += count; + + Ok(count) + } else { + Err(io::Error::new(io::ErrorKind::Other, "error")) + } + } +} diff --git a/libarchive/src/read/file.rs b/libarchive/src/read/file.rs index ebf2619..a02f0e9 100644 --- a/libarchive/src/read/file.rs +++ b/libarchive/src/read/file.rs @@ -1,9 +1,9 @@ -use libarchive3_sys::ffi; use super::builder::Builder; -use crate::read::{Handle, Archive}; +use crate::error::ArchiveError; +use crate::read::{Archive, Handle}; +use libarchive3_sys::ffi; use std::ffi::CString; use std::path::Path; -use crate::error::ArchiveError; const BLOCK_SIZE: usize = 10240; @@ -32,9 +32,7 @@ impl Drop for ArchiveFile { impl Archive for ArchiveFile { fn new(handle: *mut ffi::Struct_archive) -> Self { - Self { - handle - } + Self { handle } } fn open>(mut builder: Builder, path: P) -> crate::Result { diff --git a/libarchive/src/read/mod.rs b/libarchive/src/read/mod.rs index ea2565a..d5108b8 100644 --- a/libarchive/src/read/mod.rs +++ b/libarchive/src/read/mod.rs @@ -1,15 +1,21 @@ mod builder; +mod entries; mod file; +pub use builder::Builder; + use crate::archive::Handle; -use builder::Builder; -use std::path::Path; +use entries::Entries; use libarchive3_sys::ffi; +use std::path::Path; // Represents a read view of an archive pub trait Archive: Handle + Sized { fn new(handle: *mut ffi::Struct_archive) -> Self; fn open>(builder: Builder, path: P) -> crate::Result; - // entries + + fn entries<'a>(&'a mut self) -> Entries<'a, Self> { + Entries::new(self) + } } diff --git a/server/src/repo/mod.rs b/server/src/repo/mod.rs index d02040c..ab8d34b 100644 --- a/server/src/repo/mod.rs +++ b/server/src/repo/mod.rs @@ -1,3 +1,5 @@ +mod manager; + use axum::extract::{BodyStream, Path, State}; use axum::http::StatusCode; use axum::response::IntoResponse; @@ -6,6 +8,10 @@ use axum::Router; use futures::StreamExt; use futures::TryFutureExt; use futures::TryStreamExt; +use libarchive::archive::Entry; +use libarchive::read::Archive; +use libarchive::read::Builder; +use std::io::Read; use tokio::{fs, io, io::AsyncWriteExt}; use tower_http::services::ServeDir; use uuid::Uuid; @@ -46,5 +52,27 @@ async fn post_package_archive( .await?; } + let mut builder = Builder::new(); + builder + .support_format(libarchive::archive::ReadFormat::Tar) + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + builder + .support_filter(libarchive::archive::ReadFilter::All) + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + let mut ar = builder + .open_file(&path) + .map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + + for entry in ar.entries() { + let mut entry = entry.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?; + + if entry.pathname() == ".PKGINFO" { + let mut buffer = String::new(); + entry.read_to_string(&mut buffer); + + println!("{}", buffer); + } + } + Ok(()) }