dir.scm 13 KB

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