     [clojure.string :as string]
     [vault.blob.core :as blob :refer [BlobStore]])
   (:import
-    (java.io
-      File)))
+    java.io.File
+    java.util.Date))
 
 
 ;; HELPER FUNCTIONS
 
-(defn- hashid->file
+(defn- id->file
   ^File
   [root id]
   (let [id (blob/hash-id id)
         {:keys [algorithm digest]} id]
     (io/file root
-             (name algorithm)
-             (subs digest 0 3)
-             (subs digest 3 6)
-             (subs digest 6))))
+      (name algorithm)
+      (subs digest 0 3)
+      (subs digest 3 6)
+      (subs digest 6))))
 
 
-(defn- file->hashid
+(defn- file->id
   [root file]
   (let [root (str root)
         file (str file)]

(extend-protocol BlobStore
  FileBlobStore

  (-list [this opts]
    (->> (enumerate-files (:root this))
         (map (partial file->hashid (:root this)))
         (blob/select-ids opts)))


  (-stat [this id]
    (let [file (hashid->file (:root this) id)]
      (when (.exists file)
        {:size (.length file)
         :stored-at (java.util.Date. (.lastModified file))
         :location (.toURI file)})))


  (-open [this id]
    (let [file (hashid->file (:root this) id)]
      (when (.exists file)
        (byte-streams/to-input-stream file))))


  (-store! [this blob]
    (let [{:keys [id content]} blob
          file (hashid->file (:root this) id)]
      (when-not (.exists file)
        (io/make-parents file)
        ; For some reason, io/copy is much faster than byte-streams/transfer here.



(defn- enumerate-files
  "Generates a lazy sequence of blob files contained in a root directory."
  [^File root]
  ; TODO: intelligently skip entries based on 'after'
  (flatten
