fs.fnl (2790B)
1 (local ll (require :lualinux)) 2 (import-macros { : define-tests : expect : expect= } :anoia.assert) 3 4 (local S_IFMT 0xf000) 5 (local S_IFSOCK 0xc000) 6 (local S_IFLNK 0xa000) 7 (local S_IFREG 0x8000) 8 (local S_IFBLK 0x6000) 9 (local S_IFDIR 0x4000) 10 (local S_IFCHR 0x2000) 11 (local S_IFIFO 0x1000) 12 13 (macro errno-check [x] 14 `(match ,x 15 val# val# 16 (nil errno#) (assert nil (.. "system call failed, errno=" errno#)) 17 )) 18 19 (fn ifmt-bits [mode] (and mode (band mode 0xf000))) 20 21 ;; returns nil if the pathname doesn't exist 22 (fn file-type [pathname stat-flag] 23 "symbol describing the file type of pathname as detected by lstat(2). Pass non-nil second arg to use stat(2) instead" 24 (. { 25 S_IFDIR :directory 26 S_IFSOCK :socket 27 S_IFLNK :link 28 S_IFREG :file 29 S_IFBLK :block-device 30 S_IFCHR :character-device 31 S_IFIFO :fifo 32 } 33 (ifmt-bits (ll.lstat3 pathname (if stat-flag 1))))) 34 35 (fn directory? [pathname] 36 (= (file-type pathname) :directory)) 37 38 (fn mktree [pathname] 39 (if (or (= pathname "") (= pathname "/")) 40 (error (.. "can't mkdir " pathname))) 41 42 (case (file-type pathname :stat) 43 :directory true 44 ty (error (.. pathname " exists as " ty ", not a directory")) 45 nil 46 (let [parent (string.gsub pathname "/[^/]+/?$" "")] 47 (or (= (file-type parent :stat) :directory) (mktree parent)) 48 (errno-check (ll.mkdir pathname))))) 49 50 (fn dir [name] 51 (let [dp (errno-check (ll.opendir name) name)] 52 (fn [] 53 (case (ll.readdir dp) 54 (name filetype) (values name filetype) 55 (nil err) (do (if (> err 0) (print "ERR" err)) (ll.closedir dp) nil) 56 )))) 57 58 (fn rmtree [pathname] 59 (case (file-type pathname) 60 nil true 61 :directory 62 (do 63 (each [f (dir pathname)] 64 (when (not (or (= f ".") (= f ".."))) 65 (rmtree ( .. pathname "/" f))) 66 (ll.rmdir pathname))) 67 :file 68 (os.remove pathname) 69 :link 70 (os.remove pathname) 71 unknown 72 (error (.. "can't remove " pathname " of mode \"" unknown "\"")))) 73 74 ;; lualinux doesn't publish access(2), this is not exactly 75 ;; the same but will suffice until we can add it 76 (fn executable? [f] 77 (let [statbuf {} 78 stat (ll.lstat f statbuf 1)] 79 (and stat (> (band (. stat 3) 73) 0)))) ; \0111 80 81 (fn find-executable [exe search-path] 82 (accumulate [full-path nil 83 p (string.gmatch search-path "(.-):")] 84 (or full-path (let [f (.. p "/" exe)] (and (executable? f) f))))) 85 86 (define-tests 87 (let [p (find-executable "yes" (os.getenv "PATH"))] 88 (expect (string.match p "coreutils.+bin/yes$")))) 89 90 (define-tests 91 (let [setup (os.execute "mkdir foo; ln -s foo bar")] 92 (mktree "bar"))) 93 94 { 95 : mktree 96 : rmtree 97 : directory? 98 : dir 99 : file-type 100 : find-executable 101 :symlink (fn [from to] (ll.symlink from to)) 102 }