[new] [#57] File handling: make file stream more robust

1. Check `.canWrite` rather than just `.exists`
2. Recreate file and/or dir/s if needed any time
   file stream is recreated.
This commit is contained in:
Peter Taoussanis 2025-03-10 12:11:45 +01:00
parent af45ffc396
commit 82f4c31651

View file

@ -232,12 +232,18 @@
(truss/ex-info! "Unable to prepare writable `java.io.File`" (truss/ex-info! "Unable to prepare writable `java.io.File`"
{:path (.getAbsolutePath file)}))))) {:path (.getAbsolutePath file)})))))
(comment
(let [f (writeable-file! "__test-file.txt")]
(enc/qb 1e4 ; [10.27 37.69]
(.exists f)
(.canWrite f))))
#?(:clj #?(:clj
(defn ^:no-doc file-stream (defn ^:no-doc writeable-file-stream!
"Private, don't use. "Private, don't use.
Returns new `java.io.FileOutputStream` for given `java.io.File`." Returns new writeable `java.io.FileOutputStream` or throws."
^java.io.FileOutputStream [file append?] ^java.io.FileOutputStream [file append?]
(java.io.FileOutputStream. (as-file file) (boolean append?)))) (java.io.FileOutputStream. (writeable-file! file) (boolean append?))))
#?(:clj #?(:clj
(defn file-writer (defn file-writer
@ -259,8 +265,8 @@
(when-not file (truss/ex-info! "Expected `:file` value" (truss/typed-val file))) (when-not file (truss/ex-info! "Expected `:file` value" (truss/typed-val file)))
(let [file (writeable-file! file) (let [file (as-file file)
stream_ (volatile! (file-stream file append?)) stream_ (volatile! (writeable-file-stream! file append?))
open?_ (enc/latom true) open?_ (enc/latom true)
close! close!
@ -274,7 +280,7 @@
reset! reset!
(fn [] (fn []
(close!) (close!)
(vreset! stream_ (file-stream file append?)) (vreset! stream_ (writeable-file-stream! file append?))
(reset! open?_ true) (reset! open?_ true)
true) true)
@ -285,11 +291,11 @@
(.flush stream) (.flush stream)
true)) true))
file-exists! check-file!
(let [rl (enc/rate-limiter-once-per 100)] (let [rl (enc/rate-limiter-once-per 100)]
(fn [] (fn []
(or (rl) (.exists file) (or (rl) #_(.exists file) (.canWrite file)
(throw (java.io.IOException. "File doesn't exist"))))) (throw (java.io.IOException. "File doesn't exist or isn't writeable")))))
lock (Object.)] lock (Object.)]
@ -305,7 +311,7 @@
ba (enc/str->utf8-ba (str content))] ba (enc/str->utf8-ba (str content))]
(locking lock (locking lock
(try (try
(file-exists!) (check-file!)
(write-ba! ba) (write-ba! ba)
(catch java.io.IOException _ ; Retry once (catch java.io.IOException _ ; Retry once
(reset!) (reset!)