Last active
July 5, 2021 15:53
-
-
Save danielcompton/ace643cbb487b1bb4eb3149e41f7a064 to your computer and use it in GitHub Desktop.
Extended attributes in Clojure
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defn supports-extended-attributes? | |
"Not all filesystems suport Java's UserDefinedFileAttributes (a.k.a. extended attributes), | |
notably HFS+ and APFS on macOS. | |
Waiting for https://bugs.openjdk.java.net/browse/JDK-8030048 to add macOS support." | |
[^Path path] | |
(.supportsFileAttributeView | |
(Files/getFileStore path) | |
^Class UserDefinedFileAttributeView)) | |
(defn ^UserDefinedFileAttributeView get-user-defined-attribute-view [path] | |
(Files/getFileAttributeView | |
path | |
UserDefinedFileAttributeView | |
(into-array LinkOption []))) | |
(def checksum-attribute-name "user.checksum") | |
(defn get-attribute [path attribute] | |
(try | |
(let [view (get-user-defined-attribute-view path) | |
name attribute | |
size (.size view name) | |
attr-buf (ByteBuffer/allocate size)] | |
(.read view name attr-buf) | |
(.flip attr-buf) | |
(str (.decode (Charset/defaultCharset) attr-buf))) | |
(catch FileSystemException e | |
nil))) | |
(defn set-attribute [path attribute ^String value] | |
(let [view (get-user-defined-attribute-view path)] | |
(.write view attribute (.encode (Charset/defaultCharset) value)))) | |
(defn add-file-etag | |
"Adds an etag for a Ring response which contains a File as the body. | |
If extended-attributes? is true, then the File is checked for a checksum | |
and if it doesn't exist then it is added to the file as an extended attribute." | |
[response extended-attributes?] | |
(let [file (:body response)] | |
(if (instance? File file) | |
(let [path (.toPath file)] | |
(if extended-attributes? | |
(if-let [checksum (get-attribute path checksum-attribute-name)] | |
(response/header response "ETag" checksum) | |
(let [checksum (checksum-file file)] | |
(set-attribute path checksum-attribute-name (str checksum)) | |
(response/header response "ETag" checksum))) | |
(response/header response "ETag" (checksum-file file)))) | |
response))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment