2021-01-14 22:34:21 +01:00
|
|
|
(uiop:define-package #:ambrevar/file
|
|
|
|
(:documentation "File class.")
|
|
|
|
(:use #:common-lisp)
|
|
|
|
(:use #:trivia)
|
|
|
|
(:import-from #:hu.dwim.defclass-star #:defclass*)
|
|
|
|
(:import-from #:serapeum #:export-always))
|
|
|
|
(in-package #:ambrevar/file)
|
2021-01-15 10:50:39 +01:00
|
|
|
(eval-when (:compile-toplevel :load-toplevel :execute)
|
|
|
|
(trivial-package-local-nicknames:add-package-local-nickname :alex :alexandria)
|
|
|
|
(trivial-package-local-nicknames:add-package-local-nickname :sera :serapeum))
|
2021-01-14 22:34:21 +01:00
|
|
|
|
2021-01-15 10:50:39 +01:00
|
|
|
(sera:eval-always
|
|
|
|
(defun name-identity (name definition)
|
|
|
|
(declare (ignore definition))
|
|
|
|
name))
|
2021-01-14 22:34:21 +01:00
|
|
|
|
|
|
|
(defclass* file ()
|
|
|
|
((path (error "Path required")
|
|
|
|
:type string)
|
|
|
|
(inode 0)
|
|
|
|
(link-count 0)
|
|
|
|
(kind :regular-file ; "kind" because `type' is reserved by CL.
|
|
|
|
:type (member :directory
|
|
|
|
:character-device
|
|
|
|
:block-device
|
|
|
|
:regular-file
|
|
|
|
:symbolic-link
|
|
|
|
:socket
|
|
|
|
:pipe))
|
|
|
|
(size 0)
|
|
|
|
(user-id 0)
|
|
|
|
(group-id 0)
|
|
|
|
;; TODO: Include blocks?
|
|
|
|
(creation-date (local-time:unix-to-timestamp 0))
|
|
|
|
(modification-date (local-time:unix-to-timestamp 0))
|
|
|
|
(access-date (local-time:unix-to-timestamp 0))
|
|
|
|
(permissions '()
|
|
|
|
:type (or null
|
|
|
|
(cons #.(cons 'member (mapcar #'first osicat::+permissions+))))))
|
|
|
|
(:accessor-name-transformer #'name-identity))
|
|
|
|
|
|
|
|
;; TODO: Customize `print-object'.
|
|
|
|
|
2021-01-15 10:50:39 +01:00
|
|
|
(export-always 'file)
|
2021-01-14 22:34:21 +01:00
|
|
|
(defun file (path)
|
|
|
|
(let ((native-path (uiop:truename* (uiop:parse-native-namestring path))))
|
|
|
|
(assert (uiop:file-exists-p native-path))
|
|
|
|
(let ((stat (osicat-posix:stat native-path)))
|
|
|
|
;; From Osicat's `file-permissions':
|
|
|
|
(flet ((stat-permissions (stat)
|
|
|
|
(let ((mode (osicat-posix:stat-mode stat)))
|
|
|
|
(loop for (name . value) in osicat::+permissions+
|
|
|
|
when (plusp (logand mode value))
|
|
|
|
collect name))))
|
|
|
|
(make-instance 'file
|
|
|
|
:path (uiop:unix-namestring native-path)
|
|
|
|
:inode (osicat-posix:stat-ino stat)
|
|
|
|
:link-count (osicat-posix:stat-nlink stat)
|
|
|
|
:kind (osicat:file-kind native-path) ; TODO: Don't recall `stat'.
|
|
|
|
:size (osicat-posix:stat-size stat)
|
|
|
|
:user-id (osicat-posix:stat-uid stat)
|
|
|
|
:group-id (osicat-posix:stat-gid stat)
|
|
|
|
:creation-date (local-time:unix-to-timestamp (osicat-posix:stat-ctime stat))
|
|
|
|
:modification-date (local-time:unix-to-timestamp (osicat-posix:stat-mtime stat))
|
|
|
|
:access-date (local-time:unix-to-timestamp (osicat-posix:stat-atime stat))
|
|
|
|
:permissions (stat-permissions stat))))))
|