mode.lisp 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. (in-package :hurd-common)
  2. ;;
  3. ;; In this file we implement an abstraction to the mode_t type.
  4. ;; mode_t is a byte field with information about permissions, types, etc of a node
  5. ;;
  6. ;;
  7. ;; Bits for file types.
  8. ;;
  9. (defconstant +ifmt+ #o170000 "Bits for types")
  10. (defconstant +ifdir+ #o040000 "Is a directory")
  11. (defconstant +ifchr+ #o020000 "Is a character device")
  12. (defconstant +ifblk+ #o060000 "Is a block device")
  13. (defconstant +ifreg+ #o0100000 "Regular file")
  14. (defconstant +iflnk+ #o120000 "Link")
  15. (defconstant +ifsock+ #o140000 "Socket")
  16. (defconstant +ififo+ #o10000 "Fifo")
  17. ;;
  18. ;; Bits for permissions.
  19. ;; 4 groups:
  20. ;; owner, group, others and unknown.
  21. ;; Each one has bits for reading, writing, and exec'ing.
  22. ;;
  23. ;; owner
  24. (defconstant +irusr+ #o0400 "Read for owner")
  25. (defconstant +iwusr+ #o0200 "Write for owner")
  26. (defconstant +ixusr+ #o0100 "Execute for owner")
  27. (defconstant +iusr+ #o0700 "Bits for owner")
  28. ;; group
  29. (defconstant +irgrp+ (ash +irusr+ -3) "Read for group")
  30. (defconstant +iwgrp+ (ash +iwusr+ -3) "Write for group")
  31. (defconstant +ixgrp+ (ash +ixusr+ -3) "Execute for group")
  32. (defconstant +igrp+ (ash +iusr+ -3) "Bits for group")
  33. ;; others
  34. (defconstant +iroth+ (ash +irusr+ -6) "Read for others")
  35. (defconstant +iwoth+ (ash +iwusr+ -6) "Write for others")
  36. (defconstant +ixoth+ (ash +ixusr+ -6) "Execute for others")
  37. (defconstant +ioth+ (ash +iusr+ -6) "Bits for others")
  38. ;; unknown
  39. (defconstant +irunk+ (ash +irusr+ 12) "Read for unknown")
  40. (defconstant +iwunk+ (ash +iwusr+ 12) "Write for unknown")
  41. (defconstant +ixunk+ (ash +ixusr+ 12) "Execute for unknown")
  42. (defconstant +iunknown+ #o000007000000 "Mask for unknown permissions")
  43. ;;
  44. ;; These are read-only bits.
  45. ;;
  46. ;; Translator related bits.
  47. (defconstant +iptrans+ #o000010000000 "Has a passive translator")
  48. (defconstant +iatrans+ #o000020000000 "Has an active translator")
  49. (defconstant +iroot+ #o000040000000 "Is a translator root")
  50. (defconstant +itrans+ #o000070000000 "All the above bits")
  51. (defconstant +immap0+ #o000100000000 "No mmaps to this")
  52. (defconstant +isuid+ #o04000 "Set user ID on execution")
  53. (defconstant +isgid+ #o02000 "Set group ID on execution")
  54. (defconstant +isvtx+ #o01000 "Save swapped text after use (sticky).")
  55. (defconstant +inocache+ #o000000200000 "Don't cache contents for this file")
  56. (defconstant +iuseunk+ #o000000400000 "Use unknown bits")
  57. ;; All permission bits.
  58. (defconstant +permission+
  59. (chained-bit-op boole-ior
  60. +iusr+
  61. +igrp+
  62. +ioth+
  63. +iunknown+
  64. +iuseunk+))
  65. ;; Unused bits.
  66. (defconstant +ispare+ (boole boole-xor
  67. #xffffffff
  68. (chained-bit-op boole-ior
  69. +ifmt+
  70. +itrans+
  71. +inocache+
  72. +immap0+
  73. +iuseunk+
  74. +iunknown+
  75. +permission+
  76. #o7777)))
  77. ;; Define generic functions for accessing and setfing the mode-bits
  78. ;; We use them here and in the stat file.
  79. ;; (defgeneric mode-bits (mode))
  80. ;; (defgeneric (setf mode-bits) (val obj))
  81. (define-accessor mode-bits)
  82. ;; Base classe for mode and stat.
  83. (defclass base-mode () ())
  84. (defclass mode (base-mode)
  85. ((mode-bits :initform 0
  86. :accessor mode-bits
  87. :initarg :mode-bits))
  88. (:documentation "Mode class for saving a mode_t bitfield"))
  89. (define-foreign-type <mode-type> ()
  90. ()
  91. (:documentation "CFFI mode type.")
  92. (:actual-type :unsigned-int)
  93. (:simple-parser mode-t))
  94. (defmethod translate-to-foreign (mode (type <mode-type>))
  95. "Translate a mode object to a foreign bit field."
  96. (if (null mode)
  97. 0
  98. (mode-bits mode)))
  99. (defmethod translate-from-foreign (value (type <mode-type>))
  100. "Translate a foreign bitfield to a mode object."
  101. (make-instance 'mode :mode-bits value))
  102. ;; These functions do some common operations on bitfields.
  103. (defun %disable-bits (val bits) (boole boole-andc2 val bits))
  104. (defun %only-bits (val bits) (boole boole-and val bits))
  105. (defun %enable-bits (val bits) (boole boole-ior val bits))
  106. (defmacro define-mode-meth (name extra-args doc &body body)
  107. "Define a new base-mode method with arguments the base-mode object and extra-args.
  108. 'val' is accessible, representing the mode bitfield."
  109. #`(defmethod #,name ((mode <base-mode>)
  110. #,@(if (null extra-args)
  111. #nil
  112. extra-args))
  113. #,doc
  114. (with-accessors ((val mode-bits)) mode
  115. #,@body)))
  116. (defmacro define-is-type-meth (name bits doc)
  117. "Defines a new is type method."
  118. #`(define-mode-meth #,name #nil
  119. #,doc
  120. (eq (%only-bits val +ifmt+) #,bits)))
  121. ;; These functions check for a specific mode type.
  122. ;; Return T in success, NIL otherwise.
  123. (define-is-type-meth is-dir? +ifdir+ "Is a directory?")
  124. (define-is-type-meth is-chr? +ifchr+ "Is a character device?")
  125. (define-is-type-meth is-reg? +ifreg+ "Is a regular device?")
  126. (define-is-type-meth is-blk? +ifblk+ "Is a block device?")
  127. (define-is-type-meth is-lnk? +iflnk+ "Is a link?")
  128. (define-is-type-meth is-sock? +ifsock+ "Is a socket?")
  129. (define-is-type-meth is-fifo? +ififo+ "Is a fifo?")
  130. (define-mode-meth get-type #nil
  131. "Returns type of mode."
  132. (cond
  133. ((is-dir? mode) :dir)
  134. ((is-chr? mode) :chr)
  135. ((is-reg? mode) :reg)
  136. ((is-blk? mode) :blk)
  137. ((is-lnk? mode) :lnk)
  138. ((is-sock? mode) :sock)
  139. (#t
  140. (warn "Could not get type for mode~%")
  141. :unknown)))
  142. (defun %get-type-bits (type)
  143. "Returns the bits that must be activated from a certain type."
  144. (case type
  145. (:dir +ifdir+)
  146. (:reg +ifreg+)
  147. (:chr +ifchr+)
  148. (:blk +ifblk+)
  149. (:lnk +iflnk+)
  150. (:sock +ifsock+)
  151. (:fifo +ififo+)
  152. (otherwise
  153. (warn "invalid type at get-type-bits")
  154. #o000000)))
  155. (define-mode-meth set-type (new-type)
  156. "Changes type of mode. Possible values for new-type are:
  157. dir, reg, chr, blk, lnk, sock."
  158. (setf (mode-bits mode)
  159. (%enable-bits
  160. (%disable-bits val +ifmt+)
  161. (%get-type-bits new-type)))
  162. new-type)
  163. (defun %get-perm-bits (perm-type &optional user-type useunk-p)
  164. "Returns the permission bytes associated with perm-type and user-type.
  165. These are the possible combinations:
  166. perm-type: read / write / exec
  167. user-type: owner / group / others / unknown
  168. You can also ignore user-type and the bits will be for all the user types.
  169. "
  170. (if (null user-type)
  171. (case perm-type
  172. (:read
  173. (chained-bit-op boole-ior
  174. +irusr+
  175. +irgrp+
  176. +iroth+
  177. (if useunk-p +irunk+ 0)))
  178. (:write
  179. (chained-bit-op boole-ior
  180. +iwusr+
  181. +iwgrp+
  182. +iwoth+
  183. (if useunk-p +iwunk+ 0)))
  184. (:exec
  185. (chained-bit-op boole-ior
  186. +ixusr+
  187. +ixgrp+
  188. +ixoth+
  189. (if useunk-p +ixunk+ 0)))
  190. (otherwise
  191. 0))
  192. (case user-type
  193. (:owner
  194. (case perm-type
  195. (:read +irusr+)
  196. (:write +iwusr+)
  197. (:exec +ixusr+)
  198. (otherwise 0)))
  199. (:group
  200. (case perm-type
  201. (:read +irgrp+)
  202. (:write +iwgrp+)
  203. (:exec +ixgrp+)
  204. (otherwise 0)))
  205. (:others
  206. (case perm-type
  207. (:read +iroth+)
  208. (:write +iwoth+)
  209. (:exec +ixoth+)
  210. (otherwise 0)))
  211. (:unknown
  212. (if useunk-p
  213. (case perm-type
  214. (:read +irunk+)
  215. (:write +iwunk+)
  216. (:exec +ixunk+)
  217. (otherwise 0))
  218. 0))
  219. (otherwise 0))))
  220. (define-mode-meth has-perms? (perm-type &optional user-type)
  221. "Predicate telling if the mode bitfield has certain permissions. Same combinations as get-perm-bits."
  222. (let* ((useunk-p (is-useunk? mode))
  223. (bits (%get-perm-bits perm-type user-type useunk-p)))
  224. (and (plusp bits)
  225. (= bits
  226. (%only-bits val bits)))))
  227. (define-mode-meth set-perms! (perm-type &optional user-type)
  228. "Activates permission bits for perm-type/user-type."
  229. (setf (mode-bits mode)
  230. (%enable-bits
  231. val
  232. (%get-perm-bits perm-type user-type t)))
  233. t)
  234. (define-mode-meth clear-perms! (perm-type &optional user-type)
  235. "Clears permission bits for perm-type/user-type."
  236. (setf (mode-bits mode)
  237. (%disable-bits
  238. val
  239. (%get-perm-bits perm-type user-type t)))
  240. t)
  241. (define-mode-meth set-perms-if! (condit perm-type &optional user-type)
  242. "Activates or clears permission bits based on the 'condit' value."
  243. (if condit
  244. (set-perms! mode perm-type user-type)
  245. (clear-perms! mode perm-type user-type)))
  246. (defmethod copy-perms! ((mode1 <base-mode>) (mode2 <base-mode>))
  247. "Copy all the permission bits from mode1 to mode2."
  248. (setf (mode-bits mode2)
  249. (%enable-bits
  250. (%disable-bits (mode-bits mode2) +permission+)
  251. (%only-bits (mode-bits mode1) +permission+)))
  252. mode2)
  253. (defmacro define-mode-query-meth (name bits doc)
  254. "Defines a new predicate based on 'bits'."
  255. #`(define-mode-meth #,name #nil
  256. #,doc
  257. (= #,bits (%only-bits val #,bits))))
  258. ;; Predicates for some mode bits.
  259. (define-mode-query-meth has-passive-trans? +iptrans+ "Has a passive translator?")
  260. (define-mode-query-meth has-active-trans? +iatrans+ "Has an active translator?")
  261. (define-mode-query-meth is-fs-root? +iroot+ "Is filesystem root?")
  262. (define-mode-query-meth is-uid? +isuid+ "Has uid bit?")
  263. (define-mode-query-meth is-gid? +isgid+ "Has gid bit?")
  264. (define-mode-query-meth is-vtx? +isvtx+ "Has sticky bit?")
  265. (define-mode-query-meth is-mmap? +immap0+ "No mmaps on this?")
  266. (define-mode-query-meth is-nocache? +inocache+ "Don't use caching?")
  267. (define-mode-query-meth is-useunk? +iuseunk+ "Use unknown permission system?")
  268. (defmacro define-mode-switcher-meth (name bits doc)
  269. "Creates a new switcher function for 'bits'."
  270. #`(define-mode-meth #,name (&optional (yes t))
  271. #,doc
  272. (setf (mode-bits mode)
  273. (if yes
  274. (%enable-bits val #,bits)
  275. (%disable-bits val #,bits)))
  276. t))
  277. ;; These functions accept two arguments:
  278. ;; A mode object and a boolean, activating certain mode bits.
  279. (define-mode-switcher-meth set-uid! +isuid+ "Sets uid bit")
  280. (define-mode-switcher-meth set-gid! +isgid+ "Sets gid bit")
  281. (define-mode-switcher-meth set-vtx! +isvtx+ "Sets sticky bit")
  282. (define-mode-switcher-meth set-mmap! +immap0+ "Sets decision on using mmaps")
  283. (define-mode-switcher-meth set-nocache! +inocache+ "Sets decision on caching the node")
  284. (define-mode-switcher-meth set-useunk! +iuseunk+ "Uses unknown bits")
  285. (define-mode-switcher-meth set-active-trans! +iatrans+ "Sets active translator bit")
  286. (define-mode-switcher-meth set-passive-trans! +iptrans+ "Sets passive translator bit")
  287. (define-mode-switcher-meth set-trans! +itrans+ "Sets all the translator bits")
  288. (define-mode-switcher-meth set-root! +iroot+ "Sets root bit")
  289. (define-mode-switcher-meth set-types! +ifmt+ "Sets all the type bits")
  290. (define-mode-switcher-meth set-spare! +ispare+ "Sets all the spare bits")
  291. (define-mode-switcher-meth set-owner! +iusr+ "Set all the owner perm bits")
  292. (define-mode-switcher-meth set-group! +igrp+ "Set all the group perm bits")
  293. (define-mode-switcher-meth set-others! +ioth+ "Set all the others perm bits")
  294. (define-mode-switcher-meth set-unknown! +iunknown+ "Set all the unknown perm bits")
  295. (defun make-mode-clone (bits)
  296. "Makes a mode object based on 'bits' bitfield."
  297. (make-instance 'mode :mode-bits bits))
  298. (defun make-mode (&key (type :reg)
  299. (perms '((:owner :read :write)
  300. (:group :read))) ; default permissions
  301. (uid nil) ; activate uid bit
  302. (gid nil) ; activate gid bit
  303. (vtx nil) ; activate sticky bit
  304. (mmap nil) ; activate mmap bit
  305. (nocache nil) ; activate nocache bit
  306. (useunk nil)) ; use unknown bits
  307. "Creates a new mode object.
  308. 'perms' is a list with the form ((user-type1 perm1 perm2 ...) (user-type2 perm1..))."
  309. (let ((obj (make-instance 'mode)))
  310. (set-type obj type)
  311. (mapcar (lambda (owner-list)
  312. (let ((owner-type (first owner-list))
  313. (perm-list (cdr owner-list)))
  314. (mapcar (lambda (perm-type)
  315. (set-perms! obj perm-type owner-type))
  316. perm-list)))
  317. perms)
  318. (set-uid! obj uid)
  319. (set-gid! obj gid)
  320. (set-vtx! obj vtx)
  321. (set-mmap! obj mmap)
  322. (set-nocache! obj nocache)
  323. (set-useunk! obj useunk)
  324. obj))
  325. (defun %perm-char (type)
  326. "Returns the associated character with 'type' permission type."
  327. (case type
  328. (:read #\r)
  329. (:write #\w)
  330. (:exec #\x)
  331. (otherwise #\-)))
  332. (defun %type-char (type)
  333. "Returns the associated character with 'type' file type."
  334. (case type
  335. (:dir #\d)
  336. (:chr #\c)
  337. (:blk #\b)
  338. (:reg #\-)
  339. (:lnk #\l)
  340. (:sock #\s)
  341. (otherwise #\-)))
  342. (define-mode-meth print-object (stream)
  343. "Prints a mode object."
  344. (format stream "#<Mode ~c" (%type-char (get-type mode)))
  345. (flet ((show-perm-bits (user-type)
  346. (mapcar (lambda (perm-type)
  347. (format stream "~c"
  348. (cond
  349. ((and (eq perm-type :exec)
  350. (eq user-type :owner)
  351. (is-uid? mode))
  352. #\s)
  353. ((and (eq perm-type :exec)
  354. (eq user-type :group)
  355. (is-gid? mode))
  356. #\s)
  357. ((has-perms? mode perm-type user-type)
  358. (%perm-char perm-type))
  359. (t
  360. #\-))
  361. #\-))
  362. '(:read :write :exec))))
  363. (mapcar show-perm-bits '(:owner :group :others)))
  364. (if (is-vtx? mode)
  365. (format stream " vtx"))
  366. (if (is-mmap? mode)
  367. (format stream " mmap"))
  368. (if (is-nocache? mode)
  369. (format stream " nocache"))
  370. (if (is-useunk? mode)
  371. (format stream " useunk"))
  372. (format stream ">"))