diff --git a/Cargo.toml b/Cargo.toml
index 0001eb31119c68e1e9dcde8837c4ac23341389d1..5f3ec27497cc915accd0e058e6ba3f006b5fd722 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "hashtoc"
-version = "0.1.3"
+version = "0.1.4"
 authors = ["Anders Blomdell <anders.blomdell@control.lth.se>"]
 build = "build.rs"
 links = "libhash.a,libssl"
diff --git a/src/main.rs b/src/main.rs
index 98bfda3f195a53d1fe74384bb153c0a1431d2dc3..abb4be56e1007e1045a1d0a3b6c948aa6579170e 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -39,7 +39,7 @@ use std::cell::RefCell;
 use libc::{c_int, time_t};
 use std::result::Result;
 use std::io::Error as IOError;
-use std::io::{self, Write};
+use std::io::{self, Write, BufRead};
 use bytes::BytesMut;
 use std::ops::Deref;
 
@@ -554,7 +554,7 @@ fn dispatcher(options: clap::ArgMatches,
     zprintln!();
 }
 
-fn main() {
+fn main() -> std::io::Result<()> {
     let matches = App::new("hashtoc")
         .version("1.0")
         .author("Anders Blomdell <anders.blomdell@control.lth.se>")
@@ -608,7 +608,11 @@ fn main() {
         .arg(Arg::with_name("zero-terminated")
              .short("z")
              .long("zero-terminated")
-             .help("End lines with NULL character"))
+             .help("Line endings are the NULL character"))
+        .arg(Arg::with_name("stdin")
+             .long("stdin")
+             .required(true)
+             .help("Read paths from stdin"))
         .arg(Arg::with_name("max_age")
              .short("m")
              .long("max-age")
@@ -616,7 +620,8 @@ fn main() {
              .help("max age of HASH extended attribute(s)"))
         .arg(Arg::with_name("PATH")
              .help("path(s) to traverse")
-             .required(true)
+             .required(false)
+             .conflicts_with("stdin")
              .multiple(true)
              .index(1))
         .get_matches();
@@ -628,18 +633,47 @@ fn main() {
         let worker = thread::spawn(move|| { dispatcher(args, rx); });
         (worker, tx)
     };
-    let callback = | p:&Path, m:&Metadata | {
-        tx.send( WalkerMessage::Inode(
-            Inode{path:p.to_owned(), metadata:Some(m.clone())})).unwrap();
-    };
-    let paths : Vec<_> = matches.values_of_os("PATH").unwrap().collect();
-//    let mut paths : Vec<_> = matches.values_of_os("PATH").unwrap().collect();
-//    paths.sort();
-    for p in paths {
-        let path = std::path::Path::new(p);
-        let _ = tx.send(WalkerMessage::Start(path.to_owned()));
-        walk::visit(std::path::Path::new(p), &callback).unwrap();
+    match matches.values_of_os("PATH") {
+        Some(_) => {
+            let callback = | p:&Path, m:&Metadata | {
+                tx.send( WalkerMessage::Inode(
+                    Inode{path:p.to_owned(),
+                          metadata:Some(m.clone())})).unwrap();
+            };
+            let paths : Vec<_> =
+                matches.values_of_os("PATH").unwrap().collect();
+            for p in paths {
+                let path = std::path::Path::new(p);
+                let _ = tx.send(WalkerMessage::Start(path.to_owned()));
+                walk::visit(std::path::Path::new(p), &callback).unwrap();
+            }
+        },
+        None => {
+            let terminator =
+                if matches.is_present("zero-terminated") { 0 } else { 10 };
+            let stdin = std::io::stdin();
+            let mut handle = stdin.lock();
+            let get_metadata= walk::metadata_getter();
+            loop {
+                let mut buf = vec![];
+                let len = handle.read_until(terminator, &mut buf).unwrap();
+                if len == 0 {
+                    break;
+                }
+                let path = Path::new(OsStr::from_bytes(&buf[..len-1]));
+                let metadata = get_metadata(&path);
+                match metadata {
+                    Ok(metadata) =>
+                        tx.send(WalkerMessage::Inode(Inode {
+                            path: path.to_owned(),
+                            metadata: Some(metadata)
+                        })).unwrap(),
+                    Err(e) => { println!("{} {:?}", e, path) }
+                };
+            }
+        }
     }
     tx.send(WalkerMessage::Done).unwrap();
     worker.join().unwrap();
+    Ok(())
 }
diff --git a/src/walk.rs b/src/walk.rs
index 5215f0a3c6c11bec12e2814b93faf8cfec942e5f..c75364b6f506af8834630488a7a891e86128ff00 100644
--- a/src/walk.rs
+++ b/src/walk.rs
@@ -26,6 +26,7 @@ use std::fs::{read_dir, symlink_metadata, Metadata};
 use std::os::unix::fs::MetadataExt;
 use libc::{AT_FDCWD, R_OK, X_OK, AT_SYMLINK_NOFOLLOW};
 use libc;
+use std::io::{Error, ErrorKind};
 
 macro_rules! reportln {
     () => (writeln!(io::stderr()).unwrap_or(()));
@@ -165,5 +166,30 @@ pub fn visit(path: &Path, cb: &Fn(&Path, &Metadata)) -> io::Result<()>
     Ok(())
 }
 
-
-
+pub fn metadata_getter() -> impl Fn(&Path) -> io::Result<Metadata>
+{
+    let do_access_check = need_access_check();
+    move |path: &Path| {
+        let metadata = symlink_metadata(path);
+        let access = match metadata {
+            Ok(ref m) => {
+                if ! do_access_check {
+                    true
+                } else {
+                    if m.file_type().is_dir() {
+                        check_full_path(&path, R_OK|X_OK)
+                    } else {
+                        check_full_path(&path, R_OK)
+                    }
+                }
+            },
+            _ => false
+        };
+        if ! access {
+            Err(Error::new(ErrorKind::PermissionDenied,
+                           "Access denied"))
+        } else {
+            metadata
+        }
+    }
+}