Skip to content

Instantly share code, notes, and snippets.

@danielcompton
Last active July 5, 2021 15:53
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save danielcompton/ace643cbb487b1bb4eb3149e41f7a064 to your computer and use it in GitHub Desktop.
Save danielcompton/ace643cbb487b1bb4eb3149e41f7a064 to your computer and use it in GitHub Desktop.
Extended attributes in Clojure
(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