diff --git a/Cargo.lock b/Cargo.lock
index 7fcff0c..c678a51 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -563,28 +563,6 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
-[[package]]
-name = "errno"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba"
-dependencies = [
- "libc",
- "windows-sys 0.52.0",
-]
-
-[[package]]
-name = "filetime"
-version = "0.2.23"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd"
-dependencies = [
- "cfg-if",
- "libc",
- "redox_syscall 0.4.1",
- "windows-sys 0.52.0",
-]
-
[[package]]
name = "flate2"
version = "1.0.30"
@@ -795,7 +773,6 @@ dependencies = [
"futures",
"log",
"percent-encoding",
- "tar",
"v_htmlescape",
]
@@ -876,15 +853,9 @@ checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388"
[[package]]
name = "libc"
-version = "0.2.153"
+version = "0.2.161"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
-
-[[package]]
-name = "linux-raw-sys"
-version = "0.4.14"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89"
+checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1"
[[package]]
name = "local-channel"
@@ -1007,7 +978,7 @@ checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
dependencies = [
"cfg-if",
"libc",
- "redox_syscall 0.5.1",
+ "redox_syscall",
"smallvec",
"windows-targets 0.52.5",
]
@@ -1102,15 +1073,6 @@ dependencies = [
"getrandom",
]
-[[package]]
-name = "redox_syscall"
-version = "0.4.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
-dependencies = [
- "bitflags 1.3.2",
-]
-
[[package]]
name = "redox_syscall"
version = "0.5.1"
@@ -1164,19 +1126,6 @@ dependencies = [
"semver",
]
-[[package]]
-name = "rustix"
-version = "0.38.34"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f"
-dependencies = [
- "bitflags 2.5.0",
- "errno",
- "libc",
- "linux-raw-sys",
- "windows-sys 0.52.0",
-]
-
[[package]]
name = "ryu"
version = "1.0.18"
@@ -1311,17 +1260,6 @@ dependencies = [
"unicode-ident",
]
-[[package]]
-name = "tar"
-version = "0.4.40"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb"
-dependencies = [
- "filetime",
- "libc",
- "xattr",
-]
-
[[package]]
name = "termcolor"
version = "1.4.1"
@@ -1674,17 +1612,6 @@ version = "0.52.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
-[[package]]
-name = "xattr"
-version = "1.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f"
-dependencies = [
- "libc",
- "linux-raw-sys",
- "rustix",
-]
-
[[package]]
name = "zerocopy"
version = "0.7.34"
diff --git a/Cargo.toml b/Cargo.toml
index 7262061..23e0de9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -15,7 +15,6 @@ clap = { version = "3.2.20", features = ["cargo"] }
env_logger = "*"
log = "*"
futures = "0.3.24"
-tar = "0.4.38"
percent-encoding = "2.2"
v_htmlescape = "0.15"
diff --git a/src/directory_listing.rs b/src/directory_listing.rs
index 4b8c916..7f849b8 100644
--- a/src/directory_listing.rs
+++ b/src/directory_listing.rs
@@ -27,46 +27,56 @@ pub fn directory_listing(
let mut body = String::new();
let base = Path::new(req.path());
- for entry in dir.path.read_dir()? {
- if dir.is_visible(&entry) {
- let entry = entry.unwrap();
- let p = match entry.path().strip_prefix(&dir.path) {
- Ok(p) if cfg!(windows) => base.join(p).to_string_lossy().replace('\\', "/"),
- Ok(p) => base.join(p).to_string_lossy().into_owned(),
- Err(_) => continue,
- };
+ let mut paths: Vec<_> = dir.path.read_dir()?.map(|r| r.unwrap()).collect();
+ paths.sort_by(|a, b| {
+ let (oan, obn) = (a.file_name(), b.file_name());
+ let (an, bn) = (oan.to_str().unwrap(), obn.to_str().unwrap());
- // if file is a directory, add '/' to the end of the name
- if let Ok(metadata) = entry.metadata() {
- if metadata.is_dir() {
- let _ = write!(
- body,
- "
📂 {}/ | [.tar] |
",
- encode_file_url!(p),
- encode_file_name!(entry),
- encode_file_url!(p),
- );
- } else {
- let _ = write!(
- body,
- "🗎 {} | {} |
",
- encode_file_url!(p),
- encode_file_name!(entry),
- metadata.len(),
- );
- }
+ if let (Ok(am), Ok(bm)) = (a.metadata(), b.metadata()) {
+ return bm.is_dir().cmp(&am.is_dir()).then(an.cmp(bn));
+ } else {
+ return an.cmp(bn);
+ }
+ });
+
+ for entry in paths {
+ let p = match entry.path().strip_prefix(&dir.path) {
+ Ok(p) if cfg!(windows) => base.join(p).to_string_lossy().replace('\\', "/"),
+ Ok(p) => base.join(p).to_string_lossy().into_owned(),
+ Err(_) => continue,
+ };
+
+ if !base.has_root() {
+ let _ = write!(
+ body,
+ "../ | Size |
\n"
+ );
+ }
+
+ // if file is a directory, add '/' to the end of the name
+ if let Ok(metadata) = entry.metadata() {
+ if metadata.is_dir() {
+ let _ = write!(
+ body,
+ "{}/ | dir |
",
+ encode_file_url!(p),
+ encode_file_name!(entry),
+ );
} else {
- continue;
+ let _ = write!(
+ body,
+ "{} | {} |
",
+ encode_file_url!(p),
+ encode_file_name!(entry),
+ metadata.len(),
+ );
}
+ } else {
+ continue;
}
}
- let header = format!(
- "Index of {}/
\n\
- [.tar of whole directory]",
- index_of,
- if index_of.is_empty() { "_" } else { index_of }
- );
+ let header = format!("Index of {}/
\n", index_of);
let footer = format!(
r#""#,
@@ -81,11 +91,10 @@ pub fn directory_listing(
"\n\
\n\
\n\
- Index of {}\n\
+ Index of {}/\n\
\n\
\n{}\n\
\n\
{}\
diff --git a/src/favicon.png b/src/favicon.png
index edb8b85..3ef7f6b 100644
Binary files a/src/favicon.png and b/src/favicon.png differ
diff --git a/src/main.rs b/src/main.rs
index ab10c49..5ac9876 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,4 @@
mod directory_listing;
-mod threaded_archiver;
mod web;
#[actix_web::main]
diff --git a/src/style.css b/src/style.css
index cc50398..ed5b852 100644
--- a/src/style.css
+++ b/src/style.css
@@ -1,14 +1,35 @@
-body {background-color: #282f34; color: #aeb9a6; font-family:monospace; font-size:10.5pt;}
-a { color: #adad9d; }
-footer a {color: darkgray; text-decoration:none; font-size:smaller}
-h1 {margin-bottom: 0}
-table td:nth-child(2) {text-align:right}
+body {
+ background-color: #282f34;
+ color: #aeb9a6;
+ font-family: monospace;
+ font-size: 10.5pt;
+}
+
+a {
+ color: #adad9d;
+}
+
+footer a {
+ color: darkgray;
+ text-decoration: none;
+ font-size: smaller
+}
+
+h1 {
+ margin-bottom: 0
+}
+
+table td:nth-child(2) {
+ text-align: right
+}
+
table {
- width:100%;
- margin: 1em auto;
+ width: 100%;
+ max-width: 35em;
+ margin: 1em 0;
padding: 0.5em 0;
border-top: 1px;
border-bottom: 1px;
border-color: #444;
border-style: solid none;
-}
+}
\ No newline at end of file
diff --git a/src/threaded_archiver.rs b/src/threaded_archiver.rs
deleted file mode 100644
index 89bdf05..0000000
--- a/src/threaded_archiver.rs
+++ /dev/null
@@ -1,57 +0,0 @@
-use futures::prelude::*;
-
-use std::io;
-use std::path::Path;
-use std::thread;
-
-/*
- * TODO:
- * don't tar hidden files
- */
-
-type Stream = futures::channel::mpsc::Receiver;
-type Sender = futures::channel::mpsc::Sender;
-
-pub fn stream_tar_in_thread(path: P) -> Stream
-where
- P: AsRef + Send + 'static,
-{
- let (writer, stream) = StreamWriter::new(64);
-
- thread::spawn(move || {
- let mut a = tar::Builder::new(writer);
- let last_path_component = path.as_ref().file_name().unwrap();
- a.mode(tar::HeaderMode::Deterministic);
- a.append_dir_all(last_path_component, &path)
- .unwrap_or_else(|e| println!("{}", e));
- a.finish().unwrap_or_else(|e| println!("{}", e));
- });
- stream
-}
-
-struct StreamWriter {
- tx: Sender,
-}
-
-impl StreamWriter {
- fn new(size: usize) -> (Self, Stream) {
- let (tx, rx) = futures::channel::mpsc::channel(size);
- (StreamWriter { tx }, rx)
- }
-}
-
-impl io::Write for StreamWriter {
- fn write(&mut self, data: &[u8]) -> io::Result {
- let len = data.len();
- futures::executor::block_on(async move {
- let buf = bytes::Bytes::copy_from_slice(data);
- self.tx.send(buf).await.ok(); // maybe propagate any errors back
- });
- Ok(len)
- }
-
- fn flush(&mut self) -> io::Result<()> {
- futures::executor::block_on(async move { self.tx.flush().await.ok() });
- Ok(())
- }
-}
diff --git a/src/web.rs b/src/web.rs
index 593cbab..92c5fd6 100644
--- a/src/web.rs
+++ b/src/web.rs
@@ -1,8 +1,8 @@
-use actix_files::{Files, NamedFile};
+use actix_files::Files;
use actix_web::{
- get, middleware, web, App, Error, HttpRequest, HttpResponse, HttpServer, Responder,
+ dev::{fn_service, ServiceRequest, ServiceResponse},
+ get, middleware, App, HttpResponse, HttpServer, Responder,
};
-use futures::StreamExt;
use std::path::PathBuf;
@@ -10,15 +10,41 @@ pub async fn run(bind_addr: &str, root: &PathBuf) -> std::io::Result<()> {
let root_ = root.clone();
let s = HttpServer::new(move || {
let static_files = Files::new("/", &root_)
+ .prefer_utf8(true)
+ .index_file("index.html")
+ .use_hidden_files()
.show_files_listing()
.redirect_to_slash_directory()
- .files_listing_renderer(crate::directory_listing::directory_listing);
+ .files_listing_renderer(crate::directory_listing::directory_listing)
+ .default_handler(fn_service(|req: ServiceRequest| async {
+ let (req, _) = req.into_parts();
+ let style = include_str!("style.css");
+
+ let html = format!(
+ "\n\
+ \n\
+ \n\
+ Error\n\
+ \n\
+ \n\
+ Error
\
+ File not found
\
+ \n",
+ style
+ );
+
+ Ok(ServiceResponse::new(
+ req,
+ HttpResponse::NotFound()
+ .content_type("text/html; charset=utf-8")
+ .body(html),
+ ))
+ }));
App::new()
.app_data(root_.clone())
.wrap(middleware::Logger::default())
.service(favicon_ico)
- .service(handle_tar)
.service(static_files)
})
.bind(bind_addr)?
@@ -28,37 +54,6 @@ pub async fn run(bind_addr: &str, root: &PathBuf) -> std::io::Result<()> {
s.await
}
-#[get("/{tail:.*}.tar")]
-async fn handle_tar(
- req: HttpRequest,
- root: web::Data,
- tail: web::Path,
-) -> impl Responder {
- let relpath = PathBuf::from(tail.trim_end_matches('/'));
- let fullpath = root.join(&relpath).canonicalize().unwrap();
-
- // if a .tar already exists, just return it as-is
- let mut fullpath_tar = fullpath.clone();
- fullpath_tar.set_extension("tar");
- if fullpath_tar.is_file() {
- return NamedFile::open_async(fullpath_tar)
- .await
- .unwrap()
- .into_response(&req);
- }
-
- if !(fullpath.is_dir()) {
- return HttpResponse::NotFound().body("Directory not found\n");
- }
-
- let stream = crate::threaded_archiver::stream_tar_in_thread(fullpath).map(Ok::<_, Error>);
- let response = HttpResponse::Ok()
- .content_type("application/x-tar")
- .streaming(stream);
-
- response
-}
-
const FAVICON_ICO: &[u8] = include_bytes!("favicon.png");
#[get("/favicon.ico")]