dir.scm 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482
  1. ; Part of Scheme 48 1.9. See file COPYING for notices and license.
  2. ; Authors: Richard Kelsey, Jonathan Rees, Marcus Crestani,
  3. ; Mike Sperber, Robert Ransom
  4. ; 5.1 Directories
  5. (import-dynamic-externals "=scheme48external/posix")
  6. ; A record for directory streams. It just has the name and a byte vector
  7. ; containing the C directory object. The name is used only for printing.
  8. (define-record-type directory :directory
  9. (make-directory-box name c-dir)
  10. directory-stream?
  11. (name directory-name)
  12. (c-dir directory-c-dir set-directory-c-dir!)) ;set when the directory is closed
  13. (define-record-discloser :directory
  14. (lambda (dir)
  15. (list 'dir (directory-name dir))))
  16. ; Directory streams are meaningless in a resumed image.
  17. (define-record-resumer :directory #f)
  18. ; Opening, reading, and closing directories.
  19. (define (open-directory-stream name)
  20. (let ((dir (make-directory-box name
  21. (call-imported-binding-2 posix-opendir
  22. (x->os-byte-vector name)))))
  23. (add-finalizer! dir close-directory-stream)
  24. dir))
  25. (define (read-directory-stream directory)
  26. (cond
  27. ((call-imported-binding-2 posix-readdir (directory-c-dir directory))
  28. => x->os-string)
  29. (else #f)))
  30. (define (close-directory-stream directory)
  31. (let ((c-dir (directory-c-dir directory)))
  32. (if c-dir
  33. (begin
  34. (call-imported-binding-2 posix-closedir c-dir)
  35. (set-directory-c-dir! directory #f)))))
  36. ; The C calls we use.
  37. (import-definition posix-opendir)
  38. (import-definition posix-closedir)
  39. (import-definition posix-readdir)
  40. ; The obvious utility. This returns a list of the names in a directory.
  41. (define (list-directory name)
  42. (let ((directory (open-directory-stream name)))
  43. (let loop ((names '()))
  44. (let ((next (read-directory-stream directory)))
  45. (if next
  46. (loop (cons next names))
  47. (begin
  48. (close-directory-stream directory)
  49. (reverse names)))))))
  50. ;----------------
  51. ; 5.2 Working Directory
  52. (define (working-directory)
  53. (x->os-string
  54. (call-imported-binding-2 posix-working-directory #f)))
  55. (define (set-working-directory! name)
  56. (call-imported-binding-2 posix-working-directory
  57. (x->os-byte-vector name)))
  58. (import-definition posix-working-directory)
  59. ;----------------
  60. ; 5.3 File Creation
  61. ;
  62. ; int open(char *path, int oflag)
  63. ; int open(char *path, int oflag, mode_t mode)
  64. ;
  65. ; The modes are required if the O_CREAT is in oflag, and are only used if
  66. ; the file doesn't already exist.
  67. (define (open-file path options . mode)
  68. (let* ((input? (file-options-on? options (file-options read-only)))
  69. (channel (call-imported-binding-2 posix-open
  70. (x->os-byte-vector path)
  71. path
  72. options
  73. (if (null? mode)
  74. #f
  75. (car mode))
  76. input?)))
  77. (if input?
  78. (input-channel->port channel)
  79. (output-channel->port channel))))
  80. (import-definition posix-open)
  81. ; int creat(char *path, int oflag, mode_t mode) ; redundant with open()
  82. ;
  83. ; mode_t umask(mode_t cmask)
  84. ; Sets the file-mode creation mask, returning the old value.
  85. (define (set-file-creation-mask! new-mask)
  86. (file-stuff 0 new-mask #f))
  87. ; int link(char *existing, char *new)
  88. ; Makes `new' be a link to `existing'.
  89. (define (link existing new)
  90. (file-stuff 1
  91. (x->os-byte-vector existing)
  92. (x->os-byte-vector new)))
  93. (import-lambda-definition-2 file-stuff (op arg1 arg2) "posix_file_stuff")
  94. ;----------------
  95. ; 5.4 Special File Creation
  96. ;
  97. ; int mkdir(char path, mode_t mode)
  98. ; int mkfifo(char path, mode_t mode)
  99. (define (make-directory path mode)
  100. (file-stuff 2 (x->os-byte-vector path) mode))
  101. (define (make-fifo path mode)
  102. (file-stuff 3 (x->os-byte-vector path) mode))
  103. ;----------------
  104. ; 5.5 File Removal
  105. ;
  106. ; int unlink(char *path)
  107. (define (unlink path)
  108. (file-stuff 4 (x->os-byte-vector path) #f))
  109. ; int rmdir(char *path)
  110. (define (remove-directory path)
  111. (file-stuff 5 (x->os-byte-vector path) #f))
  112. ; int rename(char *old, char *new)
  113. (define (rename old new)
  114. (file-stuff 6
  115. (x->os-byte-vector old)
  116. (x->os-byte-vector new)))
  117. ;----------------
  118. ; The C function posix_file_info() knows the offsets of these fields.
  119. (define-record-type file-info :file-info
  120. (really-do-not-make-file-info) ; these are made from C
  121. file-info?
  122. (name file-info-name) ; for printing
  123. (type file-info-type)
  124. (device file-info-device)
  125. (inode file-info-inode)
  126. (mode file-info-mode)
  127. (link-count file-info-link-count)
  128. (owner file-info-owner)
  129. (group file-info-group)
  130. (size file-info-size)
  131. (last-access file-info-last-access)
  132. (last-modification file-info-last-modification)
  133. (last-status-change file-info-last-status-change))
  134. ; These are made in C.
  135. (define-exported-binding "posix-file-info-type" :file-info)
  136. ; The order of these is known to the C code.
  137. (define-enumerated-type file-type :file-type
  138. file-type?
  139. file-types
  140. file-type-name
  141. file-type-index
  142. (regular
  143. directory
  144. character-device
  145. block-device
  146. fifo
  147. symbolic-link
  148. socket
  149. other))
  150. ;----------------
  151. ; 5.6 File Characteristics
  152. (import-definition posix-file-info)
  153. ; The following are stat(), lstat(), and fstat().
  154. (define (get-file-info name)
  155. (let ((os-str-name (x->os-string name)))
  156. (call-imported-binding-2 posix-file-info
  157. os-str-name
  158. (os-string->byte-vector os-str-name)
  159. #t file-types)))
  160. (define (get-file/link-info name)
  161. (let ((os-str-name (x->os-string name)))
  162. (call-imported-binding-2 posix-file-info
  163. os-str-name
  164. (os-string->byte-vector os-str-name)
  165. #f file-types)))
  166. (define (get-port-info port)
  167. (let ((channel (port->channel port)))
  168. (if channel
  169. (call-imported-binding-2 posix-file-info
  170. (x->os-string (channel-id channel))
  171. channel
  172. #f
  173. file-types)
  174. (assertion-violation 'get-port-info "port without channel" port))))
  175. ;----------------
  176. ; Modes
  177. (define-record-type file-mode :file-mode
  178. (really-make-file-mode value)
  179. file-mode?
  180. (value file-mode->integer))
  181. (define-record-discloser :file-mode
  182. (lambda (file-mode)
  183. (list 'file-mode
  184. (string-append "0"
  185. (number->string (file-mode->integer file-mode)
  186. 8)))))
  187. ; These are made in C.
  188. (define-exported-binding "posix-file-mode-type" :file-mode)
  189. ; STUFF can be a number (#o644), a string ("rwxr--r--"), or ???
  190. ; Or should there be another macro?
  191. ;
  192. ; For now it has to be a number
  193. (define (integer->file-mode stuff)
  194. (cond ((and (integer? stuff)
  195. (<= 0 stuff)
  196. (<= stuff #o7777))
  197. (really-make-file-mode stuff))
  198. (else
  199. (assertion-violation 'integer->file-mode "argument type error" stuff))))
  200. ; Arithmetic
  201. (define (file-mode+ . modes)
  202. (do ((i 0 (bitwise-ior i (file-mode->integer (car modes))))
  203. (modes modes (cdr modes)))
  204. ((null? modes)
  205. (integer->file-mode i))))
  206. (define (file-mode- mode1 mode2)
  207. (integer->file-mode (bitwise-and (file-mode->integer mode1)
  208. (bitwise-not (file-mode->integer mode2)))))
  209. ; Comparisons
  210. (define (file-mode=? mode1 mode2)
  211. (= (file-mode->integer mode1)
  212. (file-mode->integer mode2)))
  213. (define (file-mode<=? mode1 mode2)
  214. (= 0 (bitwise-and (file-mode->integer mode1)
  215. (bitwise-not (file-mode->integer mode2)))))
  216. (define (file-mode>=? mode1 mode2)
  217. (file-mode<=? mode2 mode1))
  218. ; Names for various permissions
  219. (define-syntax file-mode
  220. (lambda (e r c)
  221. (let* ((names '((set-uid . #o4000)
  222. (set-gid . #o2000)
  223. (owner-read . #o0400)
  224. (owner-write . #o0200)
  225. (owner-exec . #o0100)
  226. (owner . #o0700)
  227. (group-read . #o0040)
  228. (group-write . #o0020)
  229. (group-exec . #o0010)
  230. (group . #o0070)
  231. (other-read . #o0004)
  232. (other-write . #o0002)
  233. (other-exec . #o0001)
  234. (other . #o0007)
  235. (read . #o0444)
  236. (write . #o0222)
  237. (exec . #o0111)
  238. (all . #o0777)))
  239. (lookup (lambda (name)
  240. (let loop ((names names))
  241. (cond ((null? names)
  242. #f)
  243. ((c name (caar names))
  244. (cdar names))
  245. (else
  246. (loop (cdr names))))))))
  247. (if (or (null? (cdr e))
  248. (not (pair? (cdr e))))
  249. e
  250. (let loop ((todo (cdr e)) (mask 0))
  251. (cond ((null? todo)
  252. `(,(r 'integer->file-mode) ,mask))
  253. ((and (pair? todo)
  254. (lookup (car todo)))
  255. => (lambda (i)
  256. (loop (cdr todo) (bitwise-ior i mask))))
  257. (else
  258. e)))))))
  259. ;----------------
  260. ; Users
  261. (define-record-type user-id :user-id
  262. (integer->user-id uid)
  263. user-id?
  264. (uid user-id->integer))
  265. (define-record-discloser :user-id
  266. (lambda (user-id)
  267. (list 'user-id (user-id->integer user-id))))
  268. (define (user-id=? u1 u2)
  269. (= (user-id->integer u1)
  270. (user-id->integer u2)))
  271. ; We need to make these in the outside world.
  272. (define-exported-binding "posix-user-id-type" :user-id)
  273. (define-record-type user-info :user-info
  274. (really-make-user-info name uid group home-directory shell)
  275. user-info?
  276. (name user-info-name)
  277. (uid user-info-id)
  278. ;; this is misnamed: it should be called group-id
  279. (group user-info-group)
  280. (home-directory user-info-home-directory)
  281. (shell user-info-shell))
  282. (define (make-user-info name uid gid home-directory shell)
  283. (really-make-user-info (x->os-string name)
  284. uid gid
  285. (x->os-string home-directory)
  286. (x->os-string shell)))
  287. (define-record-discloser :user-info
  288. (lambda (user-info)
  289. (list 'user-info (user-info-name user-info))))
  290. (define (user-id->user-info user-id)
  291. (apply make-user-info
  292. (external-user-id->user-info user-id)))
  293. (define (name->user-info name)
  294. (apply make-user-info
  295. (external-name->user-info
  296. (x->os-byte-vector name))))
  297. (import-lambda-definition-2 external-user-id->user-info (user-id) "posix_getpwuid")
  298. (import-lambda-definition-2 external-name->user-info (name) "posix_getpwnam")
  299. ;----------------
  300. ; Groups
  301. (define-record-type group-id :group-id
  302. (integer->group-id gid)
  303. group-id?
  304. (gid group-id->integer))
  305. (define-record-discloser :group-id
  306. (lambda (group-id)
  307. (list 'group-id (group-id->integer group-id))))
  308. (define-exported-binding "posix-group-id-type" :group-id)
  309. (define (group-id=? g1 g2)
  310. (= (group-id->integer g1)
  311. (group-id->integer g2)))
  312. (define-record-type group-info :group-info
  313. (really-make-group-info name uid members)
  314. group-info?
  315. (name group-info-name)
  316. (uid group-info-id)
  317. (members group-info-members))
  318. (define (make-group-info name uid members)
  319. (really-make-group-info (x->os-string name)
  320. uid
  321. ;; #### this is in conflict with the docs,
  322. ;; which say we have uids here
  323. (map x->os-string (vector->list members))))
  324. (define-record-discloser :group-info
  325. (lambda (group-info)
  326. (list 'group-info (group-info-name group-info))))
  327. (define (group-id->group-info group-id)
  328. (apply make-group-info
  329. (external-group-id->group-info group-id)))
  330. (define (name->group-info name)
  331. (apply make-group-info
  332. (external-name->group-info
  333. (x->os-byte-vector name))))
  334. (import-lambda-definition-2 external-group-id->group-info (group-id) "posix_getgrgid")
  335. (import-lambda-definition-2 external-name->group-info (name) "posix_getgrnam")
  336. ;----------------
  337. ; Rest of 5.6
  338. ;
  339. ; int access(char *path, int amode)
  340. ;
  341. ; (accessible? "foo/bar/baz" (access-mode read))
  342. ; The masks are known to the C code.
  343. (define-finite-type access-mode :access-mode
  344. (mask)
  345. access-mode?
  346. access-modes
  347. access-mode-name
  348. access-mode-index
  349. (mask access-mode-mask)
  350. ((read #o0001)
  351. (write #o0002)
  352. (execute #o0004)
  353. (exists #o0010)))
  354. (define (accessible? path mode0 . more-modes)
  355. (file-stuff 7
  356. (x->os-byte-vector path)
  357. (if (null? more-modes)
  358. (access-mode-mask mode0)
  359. (apply + (map access-mode-mask
  360. (cons mode0 more-modes))))))
  361. ; int chmod(char *path, mode_t mode)
  362. ; int fchmod(int fd, mode_t mode)
  363. ; int chown(char *path, uid_t owner, gid_t group)
  364. ; int utime(char *path, struct utimbuf * times)
  365. ; int ftruncate(int fd, off_t length)
  366. ;----------------
  367. ; 5.7 Configurable Pathname Variables
  368. ;
  369. ; long pathconf(char *path, int name)
  370. ; long fpathconf(int fd, int name)
  371. ;----------------
  372. ; Symbolic links
  373. (import-lambda-definition-2 external-create-symbolic-link (name1 name2) "posix_create_symbolic_link")
  374. (import-lambda-definition-2 external-read-symbolic_link (name) "posix_read_symbolic_link")
  375. (define (create-symbolic-link name1 name2)
  376. (external-create-symbolic-link (x->os-byte-vector name1)
  377. (x->os-byte-vector name2)))
  378. (define (read-symbolic-link name)
  379. (byte-vector->os-string
  380. (external-read-symbolic_link (x->os-byte-vector name))))