dir.lisp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. (in-package :hurd-tree-translator)
  2. ;;
  3. ;; This file implements the special directory node and entry node.
  4. ;;
  5. (defvar *ino-value* 1)
  6. (defclass entry (node)
  7. ((parent :initform nil
  8. :initarg :parent
  9. :documentation "Parent node."))
  10. (:documentation "An entry, with a name and a parent."))
  11. (defmethod set-parent ((entry entry) new-val)
  12. (unless (null new-val)
  13. (setf (slot-value entry 'parent)
  14. (if (tg:weak-pointer-p new-val)
  15. new-val
  16. (tg:make-weak-pointer new-val)))))
  17. (defsetf parent set-parent)
  18. (defmethod parent ((entry entry))
  19. (with-slots ((parent parent)) entry
  20. (when (and parent
  21. (tg:weak-pointer-p parent))
  22. (tg:weak-pointer-value parent))))
  23. (defmethod print-object ((node entry) stream)
  24. "Print an entry to stream."
  25. (format stream "#<entry node: ")
  26. (call-next-method)
  27. (format stream ">"))
  28. (defclass inner-entry ()
  29. ((node :initarg :node
  30. :accessor node
  31. :documentation "Saved node.")
  32. (name :initarg :name
  33. :accessor name
  34. :documentation "Name of the entry.")))
  35. (defun make-inner-entry (node name)
  36. (make-instance 'inner-entry :node node :name name))
  37. (defclass dir-entry (entry)
  38. ((entries :initform (make-sorted-container #'string< #'name)
  39. :accessor entries
  40. :documentation "The directory entries."))
  41. (:documentation "A special entry: the directory entry."))
  42. (defun %new-ino-val (stat)
  43. "Sets and increments the ino value of a stat struct."
  44. (setf (stat-get stat 'st-ino) (incf *ino-value*)))
  45. (defmethod add-entry ((dir dir-entry) (entry entry) (name string))
  46. "Adds a new entry to the directory node 'dir'."
  47. (let ((found (get-entry dir name)))
  48. (cond
  49. (found found)
  50. (t
  51. (setf (stat-get (stat dir) 'st-mtime) +now-time-value+)
  52. (setf (stat-get (stat dir) 'st-ctime) +now-time-value+)
  53. (incf (stat-get (stat dir) 'st-nlink)) ; New entry.
  54. (assert (>= (stat-get (stat dir) 'st-nlink) 2))
  55. (incf (stat-get (stat entry) 'st-nlink)) ; New link to this file
  56. (insert-element (entries dir)
  57. (make-inner-entry entry name))
  58. entry))))
  59. (defmethod setup-entry ((entry entry))
  60. "Changes some node information to sane defaults."
  61. (%new-ino-val (stat entry))
  62. (setf (stat-get (stat entry) 'st-nlink) 0)
  63. entry)
  64. (defmethod setup-entry ((entry dir-entry))
  65. "Changes some node information to sane defaults on directories."
  66. (set-type (stat entry) :dir)
  67. (%new-ino-val (stat entry))
  68. ; st-nlink represents number of objects in a directory
  69. (setf (stat-get (stat entry) 'st-nlink) 1)
  70. entry)
  71. (defmethod initialize-instance :after ((entry entry) &key)
  72. (with-slots ((parent parent)) entry
  73. (when (and parent
  74. (not (tg:weak-pointer-p parent)))
  75. ; Install a weak pointer instead
  76. (setf (slot-value entry 'parent)
  77. (tg:make-weak-pointer parent))))
  78. (setup-entry entry))
  79. (defmethod dir-size ((dir dir-entry))
  80. "Returns number of entries in a directory."
  81. (+ 2 ; Entries "." and "..".
  82. (count-elements (entries dir))))
  83. (defmethod get-entry ((dir dir-entry) (entry string))
  84. "Gets an entry from a directory based on the filename 'entry'."
  85. (let ((found (get-element (entries dir) entry)))
  86. (if found
  87. (node found)
  88. nil)))
  89. (defmethod get-entry ((foo entry) (entry string))
  90. nil)
  91. (defmethod has-entry-p ((dir dir-entry) (entry string))
  92. "Determines if 'dir' has 'entry'."
  93. (let ((found (get-element (entries dir) entry)))
  94. (if found
  95. t
  96. nil)))
  97. (defmethod remove-dir-entry ((dir dir-entry) (entry string))
  98. "Removes a directory entry with name 'entry'."
  99. (let ((found (get-entry dir entry)))
  100. (when (and found
  101. (remove-element (entries dir) entry))
  102. (assert (> (stat-get (stat dir) 'st-nlink) 2))
  103. ; Decrease link count.
  104. (decf (stat-get (stat dir) 'st-nlink))
  105. (decf (stat-get (stat found) 'st-nlink))
  106. (setf (stat-get (stat dir) 'st-mtime) +now-time-value+)
  107. (setf (stat-get (stat dir) 'st-ctime) +now-time-value+)
  108. t)))
  109. (defmethod get-dir-entries ((dir dir-entry) start n)
  110. "Get directory entries from start to start + n."
  111. (setf (stat-get (stat dir) 'st-atime) +now-time-value+)
  112. (elements-from (entries dir) start n))
  113. (defmethod rename-dir-entry ((dir dir-entry) old-name (new-dir dir-entry) new-name &optional (force-p nil))
  114. "Rename file 'old-name' in dir to new-dir with name 'new-name'."
  115. (let ((entry (get-entry dir old-name)))
  116. (remove-dir-entry dir old-name)
  117. (setf (parent entry) new-dir)
  118. (when force-p
  119. (remove-dir-entry new-dir new-name))
  120. (add-entry new-dir entry new-name)))
  121. (defmethod iterate-entries ((dir dir-entry) fun)
  122. "Runs 'fun' for each entry in 'dir'. Arguments are entry name + entry node."
  123. (iterate-elements (entries dir)
  124. (lambda (key value)
  125. (funcall fun
  126. key
  127. (node value)))))
  128. (defmethod iterate-entries-deep ((dir dir-entry) fun)
  129. "Runs 'fun' for each entry in 'dir', recursively. If 'fun' returns T and the node is a directory, 'fun' will be run for the node's leafs, when it returns NIL the leafs will not be visited."
  130. (iterate-entries dir
  131. (lambda (name node)
  132. (when (and (funcall fun name node)
  133. (typep node 'dir-entry))
  134. (iterate-entries-deep node fun)))))
  135. (defmethod clear-dir ((dir dir-entry))
  136. "Clear all directory entries."
  137. (clear-elements (entries dir))
  138. (setf (stat-get (stat dir) 'st-nlink) 2)
  139. (setf (stat-get (stat dir) 'st-mtime) +now-time-value+)
  140. (setf (stat-get (stat dir) 'st-ctime) +now-time-value+)
  141. t)