stat.lisp 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227
  1. (in-package :hurd-common)
  2. ;;
  3. ;; This file implements the needed
  4. ;; abstractions to deal with the stat struct.
  5. ;;
  6. ;; POSIX.1b structure for a time value
  7. ;; Has seconds and nanoseconds.
  8. ;;
  9. (defcstruct <timespec-struct>
  10. (sec :unsigned-int)
  11. (nsec :unsigned-int))
  12. ;; Just to be sure..
  13. (assert (= (foreign-type-size <timespec-struct>) 8))
  14. (defconstant +stat-size+ 128 "Size of a stat struct")
  15. (defcstruct (<stat-struct> :size 128)
  16. "The stat struct."
  17. (st-fstype :unsigned-int) ; File system type
  18. (st-fsid :long-long) ; File system ID
  19. (st-ino ino-t) ; File number
  20. (st-gen :unsigned-int) ; To detect reuse of file numbers
  21. (st-rdev :unsigned-int) ; Device if special file
  22. (st-mode :unsigned-int) ; File mode
  23. (st-nlink :unsigned-int) ; Number of links
  24. (st-uid uid-t) ; Owner
  25. (st-gid gid-t) ; Owning group
  26. (st-size :long-long) ; Size in bytes
  27. (st-atim timespec-struct) ; Time of last access
  28. (st-mtim timespec-struct) ; Time of last modification
  29. (st-ctim timespec-struct) ; Time of last status change
  30. (st-blksize :unsigned-int) ; Optimal size of IO
  31. (st-blocks :long-long) ; Number of 512-byte blocks allocated
  32. (st-author uid-t) ; File author
  33. (st-flags :unsigned-int)) ; User defined flags
  34. (defclass <stat> (base-mode)
  35. ((ptr :initform nil
  36. :initarg :ptr
  37. :accessor ptr
  38. :documentation "Pointer to a struct stat."))
  39. (:documentation "Class for objects containing a pointer to a stat struct."))
  40. (defmethod mode-bits ((stat <stat>))
  41. "Returns the mode bits from a stat."
  42. (foreign-slot-value (ptr stat) <stat-struct> 'st-mode))
  43. (defmethod (setf mode-bits) (new-value (stat <stat>))
  44. "Sets the mode bits from a stat."
  45. (setf (foreign-slot-value (ptr stat) <stat-struct> 'st-mode) new-value))
  46. (defun stat-copy (stat-dest stat-src)
  47. "Copies to 'stat-dest' all the stat information from 'stat-src'."
  48. (memcpy (ptr stat-dest) (ptr stat-src) +stat-size+))
  49. (defun %stat-time-get (ptr what)
  50. "Access from a 'ptr' stat struct the 'sec' field from the timespec field 'what'."
  51. (let ((ptr (foreign-slot-value ptr <stat-struct> what)))
  52. (make-time-value :seconds (foreign-slot-value ptr <timespec-struct> 'sec)
  53. :microseconds (nanosecs->microsecs (foreign-slot-value ptr <timespec-struct> 'nsec)))))
  54. (defmethod stat-get ((stat <stat>) what)
  55. "Gets specific information from a stat object.
  56. 'what' can be:
  57. st-atime, st-mtime, st-ctime, st-ev, st-mode, st-fstype,
  58. st-fsid, st-ino, st-gen, st-rdev, st-nlink,
  59. st-uid, st-gid, st-size, st-atim, st-mtim, st-ctim,
  60. st-blksize, st-blocks, st-author, st-flags."
  61. (with-slots ((ptr ptr)) stat
  62. (case what
  63. (st-atime (%stat-time-get ptr 'st-atim))
  64. (st-mtime (%stat-time-get ptr 'st-mtim))
  65. (st-ctime (%stat-time-get ptr 'st-ctim))
  66. ; Get type from the mode bits.
  67. (st-type (get-type stat))
  68. ; 'st-dev' is an alias to 'st-fsid'.
  69. (st-dev (foreign-slot-value ptr <stat-struct> 'st-fsid))
  70. ; We return a mode object here
  71. (st-mode (make-mode-clone
  72. (foreign-slot-value ptr <stat-struct> 'st-mode)))
  73. ; With st-rdev, we return a device-id object.
  74. (st-rdev
  75. (let ((field (foreign-slot-value ptr <stat-struct> 'st-rdev)))
  76. (make-instance <device-id>
  77. :major (get-major-dev field)
  78. :minor (get-minor-dev field))))
  79. (otherwise
  80. (foreign-slot-value ptr <stat-struct> what)))))
  81. (defun %stat-time-set (ptr field new-value)
  82. "From a stat pointer 'ptr' set the timespec field 'field' to 'new-value'."
  83. (let ((timespec (foreign-slot-value ptr <stat-struct> field))) ; Get the field
  84. (cond
  85. ((typep new-value 'time-value) ; Test if this is a kernel time-value
  86. ; Copy the time-value seconds
  87. ; and convert the microseconds to nanoseconds.
  88. (setf (foreign-slot-value timespec <timespec-struct> 'sec)
  89. (time-value-seconds new-value)
  90. (foreign-slot-value timespec <timespec-struct> 'nsec)
  91. (microsecs->nanosecs (time-value-microseconds new-value)))
  92. t)
  93. (t
  94. ; For everything else just copy the value to seconds.
  95. (setf (foreign-slot-value timespec <timespec-struct> 'sec)
  96. new-value)
  97. (setf (foreign-slot-value timespec <timespec-struct> 'nsec) 0)
  98. t))))
  99. (defmethod stat-set! ((stat <stat>) what new-value)
  100. "Sets a stat field 'what' to 'new-value'.
  101. 'what' can have the same values as 'stat-get'."
  102. (with-slots ((ptr ptr)) stat
  103. (case what
  104. (st-atime (%stat-time-set ptr 'st-atim new-value))
  105. (st-mtime (%stat-time-set ptr 'st-mtim new-value))
  106. (st-ctime (%stat-time-set ptr 'st-ctim new-value))
  107. ; Just an alias to st-fsid
  108. (st-dev
  109. (setf (foreign-slot-value ptr <stat-struct> 'st-fsid)
  110. new-value))
  111. ; We can use device-id objects here.
  112. (st-rdev
  113. (setf (foreign-slot-value ptr <stat-struct> 'st-rdev)
  114. (if (typep new-value 'device-id)
  115. (get-device-integer new-value)
  116. new-value))) ; We treat 'new-value' as a simple integer value
  117. (st-mode
  118. ; If 'new-value' is a mode object, copy its bits
  119. ; else it must be the mode bitfield itself.
  120. (setf (foreign-slot-value ptr <stat-struct> 'st-mode)
  121. (if (typep new-value 'mode)
  122. (mode-bits new-value)
  123. new-value)))
  124. (otherwise
  125. (setf (foreign-slot-value ptr <stat-struct> what) new-value)))))
  126. ; Use the new method...
  127. (defsetf stat-get stat-set!)
  128. (defmethod stat-eq ((stat1 stat) (stat2 stat))
  129. "Return T if stat1 is equal to stat2, otherwise NIL."
  130. (memcmp (ptr stat1) (ptr stat2) +stat-size+))
  131. (defun make-stat (&optional (extra nil)
  132. &key
  133. (size 0)
  134. (mode nil)
  135. (uid nil)
  136. (gid nil)
  137. (type nil)
  138. (nlink nil)
  139. (ctime +now-time-value+)
  140. (atime +now-time-value+)
  141. (mtime +now-time-value+))
  142. "Create a new stat object. 'extra' can be:
  143. a mode object: we copy it to the mode field.
  144. a stat object: we make a copy of it for the new stat object.
  145. Other arguments:
  146. size: initial size for the size field.
  147. mode: mode object for st-mode field.
  148. uid: owner id.
  149. gid: group id.
  150. type: file type.
  151. ctime, atime, mtime: different time values, should be a time-value object.
  152. "
  153. (let* ((mem (foreign-alloc <stat-struct>)) ; Allocate memory for a stat
  154. (obj (make-instance <stat> :ptr mem))) ; Instantiate new object
  155. ; Don't leak memory.
  156. (finalize obj (lambda ()
  157. (foreign-free mem)))
  158. (unless (null extra)
  159. (case (type-of extra)
  160. (mode
  161. ; Copy it to the mode field.
  162. (setf (stat-get obj 'st-mode)
  163. (mode-bits extra)))
  164. (stat
  165. ; Copy the whole thing.
  166. (memcpy mem (ptr extra) +stat-size+))))
  167. ; Optional/Key parameters go here:
  168. (when (numberp size)
  169. (setf (stat-get obj 'st-size) size))
  170. (when mode
  171. (setf (stat-get obj 'st-mode) mode))
  172. (when type
  173. (set-type obj type))
  174. (when (valid-id? uid)
  175. (setf (stat-get obj 'st-uid) uid))
  176. (when (valid-id? gid)
  177. (setf (stat-get obj 'st-gid) gid))
  178. (when atime
  179. (setf (stat-get obj 'st-atime) atime))
  180. (when ctime
  181. (setf (stat-get obj 'st-ctime) ctime))
  182. (when mtime
  183. (setf (stat-get obj 'st-mtime) mtime))
  184. (when nlink
  185. (setf (stat-get obj 'st-nlink) nlink))
  186. ; Return the new object
  187. obj))
  188. (defmethod print-object ((stat <stat>) stream)
  189. "Print a stat object."
  190. (format stream "#<stat: ")
  191. ; Print the mode object too
  192. (print-object (stat-get stat 'st-mode) stream)
  193. (format stream ">"))
  194. (define-foreign-type <stat-type> ()
  195. ()
  196. (:documentation "CFFI type for stat objects.")
  197. (:actual-type :pointer)
  198. (:simple-parser stat-t))
  199. (defmethod translate-to-foreign (stat (type <stat-type>))
  200. "Translate a stat object to a foreign pointer."
  201. (ptr stat))
  202. (defmethod translate-from-foreign (value (type <stat-type>))
  203. "Translate a stat pointer to a stat object."
  204. (make-instance <stat> :ptr value))