123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811 |
- ;;;; filesys.test --- test file system functions -*- scheme -*-
- ;;;;
- ;;;; Copyright (C) 2004, 2006, 2013, 2019, 2021 Free Software Foundation, Inc.
- ;;;; Copyright (C) 2021 Maxime Devos <maximedevos@telenet.be>
- ;;;;
- ;;;; This library is free software; you can redistribute it and/or
- ;;;; modify it under the terms of the GNU Lesser General Public
- ;;;; License as published by the Free Software Foundation; either
- ;;;; version 3 of the License, or (at your option) any later version.
- ;;;;
- ;;;; This library is distributed in the hope that it will be useful,
- ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
- ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- ;;;; Lesser General Public License for more details.
- ;;;;
- ;;;; You should have received a copy of the GNU Lesser General Public
- ;;;; License along with this library; if not, write to the Free Software
- ;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- (define-module (test-suite test-filesys)
- #:use-module (test-suite lib)
- #:use-module (test-suite guile-test)
- #:use-module (ice-9 threads)
- #:use-module (ice-9 match)
- #:use-module (rnrs io ports)
- #:use-module (rnrs bytevectors))
- (define (test-file)
- (data-file-name "filesys-test.tmp"))
- (define (test-symlink)
- (data-file-name "filesys-test-link.tmp"))
- (define (test-directory)
- (data-file-name "filesys-test-dir.tmp"))
- (define (test-directory2)
- (data-file-name "filesys-test-dir2.tmp"))
- ;;;
- ;;; copy-file
- ;;;
- (with-test-prefix "copy-file"
- ;; return next prospective file descriptor number
- (define (next-fd)
- (let ((fd (dup 0)))
- (close fd)
- fd))
- ;; in guile 1.6.4 and earlier, copy-file didn't close the input fd when
- ;; the output could not be opened
- (pass-if "fd leak when dest unwritable"
- (let ((old-next (next-fd)))
- (false-if-exception (copy-file "/dev/null" "no/such/dir/foo"))
- (= old-next (next-fd)))))
- ;;;
- ;;; lstat
- ;;;
- (with-test-prefix "lstat"
- (pass-if "normal file"
- (call-with-output-file (test-file)
- (lambda (port)
- (display "hello" port)))
- (eqv? 5 (stat:size (lstat (test-file)))))
- (call-with-output-file (test-file)
- (lambda (port)
- (display "hello" port)))
- (false-if-exception (delete-file (test-symlink)))
- (if (not (false-if-exception
- (begin (symlink (test-file) (test-symlink)) #t)))
- (display "cannot create symlink, lstat test skipped\n")
- (pass-if "symlink"
- ;; not much to test, except that it works
- (->bool (lstat (test-symlink))))))
- ;;;
- ;;; opendir and friends
- ;;;
- (with-test-prefix "opendir"
- (with-test-prefix "root directory"
- (let ((d (opendir "/")))
- (pass-if "not empty"
- (string? (readdir d)))
- (pass-if "all entries are strings"
- (let more ()
- (let ((f (readdir d)))
- (cond ((string? f)
- (more))
- ((eof-object? f)
- #t)
- (else
- #f)))))
- (closedir d))))
- ;;;
- ;;; stat
- ;;;
- (with-test-prefix "stat"
- (with-test-prefix "filename"
- (pass-if "size"
- (call-with-output-file (test-file)
- (lambda (port)
- (display "hello" port)))
- (eqv? 5 (stat:size (stat (test-file))))))
- (with-test-prefix "file descriptor"
- (pass-if "size"
- (call-with-output-file (test-file)
- (lambda (port)
- (display "hello" port)))
- (let* ((fd (open-fdes (test-file) O_RDONLY))
- (st (stat fd)))
- (close-fdes fd)
- (eqv? 5 (stat:size st)))))
- (with-test-prefix "port"
- (pass-if "size"
- (call-with-output-file (test-file)
- (lambda (port)
- (display "hello" port)))
- (let* ((port (open-file (test-file) "r+"))
- (st (stat port)))
- (close-port port)
- (eqv? 5 (stat:size st))))))
- (with-test-prefix "statat"
- ;; file-exists? from (ice-9 boot) dereferences symbolic links
- ;; (a bug?).
- (define (file-exists? filename)
- (catch 'system-error
- (lambda () (lstat filename) #t)
- (lambda args
- (if (= (system-error-errno args) ENOENT)
- ;; For the purposes of the following tests,
- ;; it is safe to ignore errors like EPERM, but a correct
- ;; implementation would return #t for that error.
- #f
- (apply throw args)))))
- (define (maybe-delete-directory)
- (when (file-exists? (test-directory))
- (for-each
- (lambda (filename)
- (define full-name (in-vicinity (test-directory) filename))
- (when (file-exists? full-name)
- (delete-file full-name)))
- '("test-file" "test-symlink"))
- (rmdir (test-directory))))
- (define (skip-unless-defined . things)
- (for-each (lambda (thing)
- (unless (defined? thing)
- (throw 'unsupported)))
- things))
- (maybe-delete-directory)
- (mkdir (test-directory))
- (call-with-output-file (in-vicinity (test-directory) "test-file")
- (lambda (port)
- (display "hello" port)))
- ;; Return #true if the symlink was created, #false otherwise.
- (define (maybe-create-symlink)
- (if (file-exists? (in-vicinity (test-directory) "test-symlink"))
- #t
- (false-if-exception
- (symlink "test-file"
- (in-vicinity (test-directory) "test-symlink")))))
- (pass-if-equal "regular file" 5
- (skip-unless-defined 'statat)
- (call-with-port
- (open (test-directory) O_RDONLY)
- (lambda (port)
- (stat:size (statat port "test-file")))))
- (pass-if-equal "regular file, AT_SYMLINK_NOFOLLOW" 5
- (skip-unless-defined 'statat 'AT_SYMLINK_NOFOLLOW)
- (call-with-port
- (open (test-directory) O_RDONLY)
- (lambda (port)
- (stat:size (statat port "test-file" AT_SYMLINK_NOFOLLOW)))))
- (pass-if-equal "symbolic links are dereferenced" '(regular 5)
- ;; Not all systems support symlinks.
- (skip-unless-defined 'statat 'symlink)
- (unless (maybe-create-symlink)
- (throw 'unresolved))
- (call-with-port
- (open (test-directory) O_RDONLY)
- (lambda (port)
- (define result (statat port "test-symlink"))
- (list (stat:type result) (stat:size result)))))
- (pass-if-equal "symbolic links are not dereferenced"
- `(symlink ,(string-length "test-file"))
- ;; Not all systems support symlinks.
- (skip-unless-defined 'statat 'symlink)
- (unless (maybe-create-symlink)
- (throw 'unresolved))
- (call-with-port
- (open (test-directory) O_RDONLY)
- (lambda (port)
- (define result (statat port "test-symlink" AT_SYMLINK_NOFOLLOW))
- (list (stat:type result) (stat:size result)))))
- (maybe-delete-directory))
- (with-test-prefix "sendfile"
- (let* ((file (search-path %load-path "ice-9/boot-9.scm"))
- (len (stat:size (stat file)))
- (ref (call-with-input-file file get-bytevector-all)))
- (pass-if-equal "file" (cons len ref)
- (let* ((result (call-with-input-file file
- (lambda (input)
- (call-with-output-file (test-file)
- (lambda (output)
- (sendfile output input len 0))))))
- (out (call-with-input-file (test-file) get-bytevector-all)))
- (cons result out)))
- (pass-if-equal "file with offset"
- (cons (- len 777) (call-with-input-file file
- (lambda (input)
- (seek input 777 SEEK_SET)
- (get-bytevector-all input))))
- (let* ((result (call-with-input-file file
- (lambda (input)
- (call-with-output-file (test-file)
- (lambda (output)
- (sendfile output input (- len 777) 777))))))
- (out (call-with-input-file (test-file) get-bytevector-all)))
- (cons result out)))
- (pass-if-equal "file with offset past the end"
- (cons (- len 777) (call-with-input-file file
- (lambda (input)
- (seek input 777 SEEK_SET)
- (get-bytevector-all input))))
- (let* ((result (call-with-input-file file
- (lambda (input)
- (call-with-output-file (test-file)
- (lambda (output)
- (sendfile output input len 777))))))
- (out (call-with-input-file (test-file) get-bytevector-all)))
- (cons result out)))
- (pass-if-equal "file with offset near the end"
- (cons 77 (call-with-input-file file
- (lambda (input)
- (seek input (- len 77) SEEK_SET)
- (get-bytevector-all input))))
- (let* ((result (call-with-input-file file
- (lambda (input)
- (call-with-output-file (test-file)
- (lambda (output)
- (sendfile output input len (- len 77)))))))
- (out (call-with-input-file (test-file) get-bytevector-all)))
- (cons result out)))
- (pass-if-equal "pipe" (cons len ref)
- (if (provided? 'threads)
- (let* ((in+out (pipe))
- (child (call-with-new-thread
- (lambda ()
- (call-with-input-file file
- (lambda (input)
- (let ((result (sendfile (cdr in+out)
- (fileno input)
- len 0)))
- (close-port (cdr in+out))
- result)))))))
- (let ((out (get-bytevector-all (car in+out))))
- (close-port (car in+out))
- (cons (join-thread child) out)))
- (throw 'unresolved)))
- (pass-if-equal "pipe with offset"
- (cons (- len 777) (call-with-input-file file
- (lambda (input)
- (seek input 777 SEEK_SET)
- (get-bytevector-all input))))
- (if (provided? 'threads)
- (let* ((in+out (pipe))
- (child (call-with-new-thread
- (lambda ()
- (call-with-input-file file
- (lambda (input)
- (let ((result (sendfile (cdr in+out)
- (fileno input)
- (- len 777)
- 777)))
- (close-port (cdr in+out))
- result)))))))
- (let ((out (get-bytevector-all (car in+out))))
- (close-port (car in+out))
- (cons (join-thread child) out)))
- (throw 'unresolved)))))
- (with-test-prefix "basename"
- (pass-if-equal "/" "/" (basename "/"))
- (pass-if-equal "//" "/" (basename "//"))
- (pass-if-equal "a/b/c" "c" (basename "a/b/c")))
- (delete-file (test-file))
- (when (file-exists? (test-symlink))
- (delete-file (test-symlink)))
- (with-test-prefix "mkdtemp"
- (pass-if-exception "number arg" exception:wrong-type-arg
- (if (not (defined? 'mkdtemp))
- (throw 'unresolved)
- (mkdtemp 123)))
- (pass-if "template prefix is preserved"
- (if (not (defined? 'mkdtemp))
- (throw 'unresolved)
- (let* ((template "T-XXXXXX")
- (name (mkdtemp template)))
- (false-if-exception (rmdir name))
- (and
- (string? name)
- (string-contains name "T-")
- (= (string-length name) 8)))))
- (pass-if-exception "invalid template" exception:system-error
- (if (not (defined? 'mkdtemp))
- (throw 'unresolved)
- (mkdtemp "T-AAAAAA")))
- (pass-if "directory created"
- (if (not (defined? 'mkdtemp))
- (throw 'unresolved)
- (let* ((template "T-XXXXXX")
- (name (mkdtemp template)))
- (let* ((_stat (stat name))
- (result (eqv? 'directory (stat:type _stat))))
- (false-if-exception (rmdir name))
- result)))))
- ;;;
- ;;; chmodat
- ;;;
- (with-test-prefix "chmodat"
- (call-with-output-file (test-file) (const #f))
- (chmod (test-file) #o000)
- (pass-if-equal "regular file"
- #o300
- (unless (defined? 'chmodat)
- (throw 'unsupported))
- (call-with-port
- (open (dirname (test-file)) O_RDONLY)
- (lambda (port)
- (chmodat port (test-file) #o300)))
- (stat:perms (stat (test-file))))
- (chmod (test-file) #o000)
- (pass-if-equal "regular file, AT_SYMLINK_NOFOLLOW"
- #o300
- (unless (and (defined? 'chmodat)
- (defined? 'AT_SYMLINK_NOFOLLOW))
- (throw 'unsupported))
- (call-with-port
- (open (dirname (test-file)) O_RDONLY)
- (lambda (port)
- (catch 'system-error
- (lambda ()
- (chmodat port (basename (test-file)) #o300 AT_SYMLINK_NOFOLLOW))
- (lambda args
- (close-port port)
- ;; AT_SYMLINK_NOFOLLOW is not supported on Linux (at least Linux
- ;; 5.11.2 with the btrfs file system), even for regular files.
- (if (= ENOTSUP (system-error-errno args))
- (begin
- (display "fchmodat doesn't support AT_SYMLINK_NOFOLLOW\n")
- (throw 'unresolved))
- (apply throw args))))))
- (stat:perms (stat (test-file))))
- (pass-if-exception "not a port" exception:wrong-type-arg
- (unless (defined? 'chmodat)
- (throw 'unsupported))
- (chmodat "bogus" (test-file) #o300))
- (pass-if-exception "not a file port" exception:wrong-type-arg
- (unless (defined? 'chmodat)
- (throw 'unsupported))
- (chmodat (open-input-string "") (test-file) #o300))
- (pass-if-exception "closed port" exception:wrong-type-arg
- (unless (defined? 'chmodat)
- (throw 'unsupported))
- (chmodat (call-with-port (open "." O_RDONLY) identity) (test-file) #o300))
- (chmod (test-file) #o600)
- (delete-file (test-file)))
- (with-test-prefix "chdir"
- (pass-if-equal "current directory" (getcwd)
- (begin (chdir ".") (getcwd)))
- (define file (search-path %load-path "ice-9/boot-9.scm"))
- (pass-if-equal "test directory" (dirname file)
- (let ((olddir (getcwd))
- (dir #f))
- (chdir (dirname file))
- (set! dir (getcwd))
- (chdir olddir)
- dir))
- (pass-if-equal "test directory, via port" (dirname file)
- (unless (provided? 'chdir-port)
- (throw 'unresolved))
- (let ((olddir (getcwd))
- (port (open (dirname file) O_RDONLY))
- (dir #f))
- (chdir port)
- (set! dir (getcwd))
- (chdir olddir)
- dir))
- (pass-if-exception "closed port" exception:wrong-type-arg
- (unless (provided? 'chdir-port)
- (throw 'unresolved))
- (let ((port (open (dirname file) O_RDONLY))
- (olddir (getcwd)))
- (close-port port)
- (chdir port)
- (chdir olddir))) ; should not be reached
- (pass-if-exception "not a port or file name" exception:wrong-type-arg
- (chdir '(stuff)))
- (pass-if-exception "non-file port" exception:wrong-type-arg
- (chdir (open-input-string ""))))
- (with-test-prefix "readlink"
- (false-if-exception (delete-file (test-symlink)))
- (false-if-exception (delete-file (test-file)))
- (call-with-output-file (test-file)
- (lambda (port)
- (display "hello" port)))
- (if (not (false-if-exception
- (begin (symlink (test-file) (test-symlink)) #t)))
- (display "cannot create symlink, some readlink tests skipped\n")
- (let ()
- (pass-if-equal "file name of symlink" (test-file)
- (readlink (test-symlink)))
- (pass-if-equal "port representing a symlink" (test-file)
- (let ()
- (unless (and (provided? 'readlink-port)
- (defined? 'O_NOFOLLOW)
- (defined? 'O_PATH)
- (not (= 0 O_NOFOLLOW))
- (not (= 0 O_PATH)))
- (throw 'unsupported))
- (define port (open (test-symlink) (logior O_NOFOLLOW O_PATH)))
- (define points-to (false-if-exception (readlink port)))
- (close-port port)
- points-to))
- (pass-if-exception "not a port or file name" exception:wrong-type-arg
- (readlink '(stuff)))))
- (pass-if-equal "port representing a regular file" EINVAL
- (unless (provided? 'readlink-port)
- (throw 'unsupported))
- (call-with-input-file (test-file)
- (lambda (port)
- (catch 'system-error
- (lambda ()
- (readlink port)
- (close-port port) ; should be unreachable
- #f)
- (lambda args
- (close-port port)
- ;; At least Linux 5.10.46 returns ENOENT instead of EINVAL.
- ;; Possibly surprising, but it is documented in some man
- ;; pages and it doesn't appear to be an accident:
- ;; <https://elixir.bootlin.com/linux/v5.10.46/source/fs/stat.c#L419>.
- (define error (system-error-errno args))
- (if (= error ENOENT)
- EINVAL
- error))))))
- (pass-if-exception "non-file port" exception:wrong-type-arg
- (readlink (open-input-string "")))
- (pass-if-exception "closed port" exception:wrong-type-arg
- (let ((port (open-file (test-file) "r")))
- (close-port port)
- (readlink port)))
- (false-if-exception (delete-file (test-symlink)))
- (false-if-exception (delete-file (test-file))))
- (with-test-prefix "symlinkat"
- (pass-if-equal "create" (test-file)
- (unless (defined? 'symlinkat)
- (throw 'unsupported))
- (call-with-port
- (open "." O_RDONLY)
- (lambda (port)
- (symlinkat port (test-file) (test-symlink))
- (readlink (test-symlink)))))
- (false-if-exception (delete-file (test-symlink)))
- (pass-if-exception "not a port" exception:wrong-type-arg
- (unless (defined? 'symlinkat)
- (throw 'unsupported))
- (symlinkat "bogus" (test-file) (test-symlink)))
- (pass-if-exception "not a file port" exception:wrong-type-arg
- (unless (defined? 'symlinkat)
- (throw 'unsupported))
- (symlinkat (open-input-string "") (test-file) (test-symlink)))
- (pass-if-exception "closed port" exception:wrong-type-arg
- (unless (defined? 'symlinkat)
- (throw 'unsupported))
- (symlinkat (call-with-port (open "." O_RDONLY) identity)
- (test-file) (test-symlink))))
- (with-test-prefix "mkdirat"
- (define (skip-if-unsupported)
- (unless (defined? 'mkdirat)
- (throw 'unsupported)))
- (define (maybe-delete-directory)
- (when (file-exists? (test-directory))
- (rmdir (test-directory))))
- (maybe-delete-directory)
- (pass-if-equal "create" 'directory
- (skip-if-unsupported)
- (call-with-port
- (open "." O_RDONLY)
- (lambda (port)
- (mkdirat port (test-directory))
- (stat:type (stat (test-directory))))))
- (maybe-delete-directory)
- (pass-if-equal "explicit perms" (logand #o111 (lognot (umask)))
- (skip-if-unsupported)
- (call-with-port
- (open "." O_RDONLY)
- (lambda (port)
- (mkdirat port (test-directory) #o111)
- (stat:perms (stat (test-directory))))))
- (maybe-delete-directory)
- (pass-if-equal "create, implicit perms" (logand #o777 (lognot (umask)))
- (skip-if-unsupported)
- (call-with-port
- (open "." O_RDONLY)
- (lambda (port)
- (mkdirat port (test-directory))
- (stat:perms (stat (test-directory))))))
- (maybe-delete-directory))
- (with-test-prefix "rename-file-at"
- (define (skip-if-unsupported)
- (unless (defined? 'rename-file-at)
- (throw 'unsupported)))
- (pass-if-equal "current working directory" '(#f "hello")
- (skip-if-unsupported)
- ;; Create a file in the test directory
- (call-with-output-file "filesys-test-a.tmp"
- (lambda (port) (display "hello" port)))
- ;; Try to rename it
- (rename-file-at #f "filesys-test-a.tmp" #f "filesys-test-b.tmp")
- ;; Verify it exists under the new name, and not under the old name
- (list (file-exists? "filesys-test-a.tmp")
- (call-with-input-file "filesys-test-b.tmp" get-string-all)))
- (false-if-exception (delete-file "filesys-test-a.tmp"))
- (false-if-exception (delete-file "filesys-test-b.tmp"))
- (pass-if-equal "two ports" '(#f "hello")
- (skip-if-unsupported)
- (mkdir (test-directory))
- (mkdir (test-directory2))
- ;; Create a file in the first directory
- (call-with-output-file (in-vicinity (test-directory) "a")
- (lambda (port) (display "hello" port)))
- (let ((port1 (open (test-directory) O_RDONLY))
- (port2 (open (test-directory2) O_RDONLY)))
- ;; Try to rename it
- (rename-file-at port1 "a" port2 "b")
- (close-port port1)
- (close-port port2)
- ;; Verify it exists under the new name, and not under the old name
- (list (file-exists? (in-vicinity (test-directory) "a"))
- (call-with-input-file (in-vicinity (test-directory2) "b")
- get-string-all))))
- (false-if-exception (delete-file (in-vicinity (test-directory) "a")))
- (false-if-exception (delete-file (in-vicinity (test-directory2) "b")))
- (false-if-exception (rmdir (test-directory)))
- (false-if-exception (rmdir (test-directory2)))
- (pass-if-equal "port and current working directory" '(#f "hello")
- (skip-if-unsupported)
- (mkdir (test-directory))
- ;; Create a file in (test-directory)
- (call-with-output-file (in-vicinity (test-directory) "a")
- (lambda (port) (display "hello" port)))
- (let ((port (open (test-directory) O_RDONLY)))
- ;; Try to rename it
- (rename-file-at port "a" #f (basename (test-file)))
- (close-port port)
- ;; Verify it exists under the new name, and not under the old name.
- (list (file-exists? (in-vicinity (test-directory) "a"))
- (call-with-input-file (test-file) get-string-all))))
- (false-if-exception (delete-file (in-vicinity (test-directory) "a")))
- (false-if-exception (rmdir (test-directory)))
- (false-if-exception (delete-file (test-file)))
- (pass-if-equal "current working directory and port" '(#f "hello")
- (skip-if-unsupported)
- (mkdir (test-directory))
- ;; Create a file in the working directory
- (call-with-output-file (test-file)
- (lambda (port) (display "hello" port)))
- (let ((port (open (test-directory) O_RDONLY)))
- ;; Try to rename it
- (rename-file-at #f (basename (test-file)) port "b")
- (close-port port)
- ;; Verify it exists under the new name, and not under the old name.
- (list (file-exists? (test-file))
- (call-with-input-file (in-vicinity (test-directory) "b")
- get-string-all))))
- (false-if-exception (delete-file (in-vicinity (test-directory) "b")))
- (false-if-exception (delete-file (test-file)))
- (false-if-exception (rmdir (test-directory)))
- (pass-if-exception "not a file port (1)" exception:wrong-type-arg
- (skip-if-unsupported)
- (rename-file-at (open-input-string "") "some" #f "thing"))
- (pass-if-exception "not a file port (2)" exception:wrong-type-arg
- (skip-if-unsupported)
- (rename-file-at #f "some" (open-input-string "") "thing"))
- (pass-if-exception "closed port (1)" exception:wrong-type-arg
- (skip-if-unsupported)
- (rename-file-at (call-with-port (open "." O_RDONLY) identity)
- "some" #f "thing"))
- (pass-if-exception "closed port (2)" exception:wrong-type-arg
- (skip-if-unsupported)
- (rename-file-at #f "some" (call-with-port (open "." O_RDONLY) identity)
- "thing"))
- (pass-if-exception "not a string (1)" exception:wrong-type-arg
- (skip-if-unsupported)
- (rename-file-at #f 'what #f "thing"))
- (pass-if-exception "not a string (2)" exception:wrong-type-arg
- (skip-if-unsupported)
- (rename-file-at #f "some" #f 'what)))
- (with-test-prefix "delete-file-at"
- (define (skip-if-unsupported)
- (when (not (and (defined? 'delete-file-at)
- (defined? 'AT_REMOVEDIR)))
- (throw 'unsupported)))
- (define (create-test-file)
- (call-with-output-file (test-file) identity))
- (define (create-test-directory)
- (mkdir (test-directory)))
- (define (delete-test-file)
- (when (file-exists? (test-file))
- (delete-file (test-file))))
- (define (delete-test-directory)
- (when (file-exists? (test-directory))
- (rmdir (test-directory))))
- (pass-if-equal "regular file" #f
- (skip-if-unsupported)
- (create-test-file)
- (call-with-port
- (open (dirname (test-file)) O_RDONLY)
- (lambda (port)
- (delete-file-at port (basename (test-file)))))
- (file-exists? (test-file)))
- (delete-test-file)
- (pass-if-equal "regular file, explicit flags" #f
- (skip-if-unsupported)
- (create-test-file)
- (call-with-port
- (open (dirname (test-file)) O_RDONLY)
- (lambda (port)
- (delete-file-at port (basename (test-file)) 0)))
- (file-exists? (test-file)))
- (delete-test-file)
- (pass-if-equal "directory, explicit flags" #f
- (skip-if-unsupported)
- (create-test-directory)
- (call-with-port
- (open (dirname (test-directory)) O_RDONLY)
- (lambda (port)
- (delete-file-at port (basename (test-directory)) AT_REMOVEDIR)))
- (file-exists? (test-directory)))
- (delete-test-directory)
- (pass-if-exception "not a port" exception:wrong-type-arg
- (skip-if-unsupported)
- (delete-file-at 'bogus "irrelevant"))
- (pass-if-exception "not a file port" exception:wrong-type-arg
- (skip-if-unsupported)
- (delete-file-at (open-input-string "") "irrelevant"))
- (pass-if-exception "closed port" exception:wrong-type-arg
- (skip-if-unsupported)
- (delete-file-at (call-with-port (open "." O_RDONLY) identity)
- "irrelevant")))
- (with-test-prefix "openat"
- (define (skip-if-unsupported)
- (unless (defined? 'openat)
- (throw 'unsupported)))
- (define file (search-path %load-path "ice-9/boot-9.scm"))
- (define (call-with-relatively-opened-file directory-arguments file-arguments
- proc)
- (call-with-port
- (apply open directory-arguments)
- (lambda (directory)
- (call-with-port
- (apply openat directory file-arguments)
- (lambda (port)
- (proc port))))))
- (pass-if-equal "mode read-only" "r"
- (skip-if-unsupported)
- (call-with-relatively-opened-file
- (list (dirname file) O_RDONLY)
- (list (basename file) O_RDONLY)
- (lambda (port) (port-mode port))))
- (pass-if-equal "port-revealed count" 0
- (skip-if-unsupported)
- (call-with-relatively-opened-file
- (list (dirname file) O_RDONLY)
- (list (basename file) O_RDONLY)
- (lambda (port) (port-revealed port))))
- (when (file-exists? (test-file))
- (delete-file (test-file)))
- (pass-if-equal "O_CREAT/O_WRONLY" (list #t (logand (lognot (umask)) #o666) "w")
- (skip-if-unsupported)
- (call-with-relatively-opened-file
- (list (dirname (test-file)) O_RDONLY)
- (list (basename (test-file)) (logior O_WRONLY O_CREAT))
- (lambda (port)
- (list (file-exists? (test-file))
- (stat:perms (stat (test-file)))
- (port-mode port)))))
- (when (file-exists? (test-file))
- (delete-file (test-file)))
- (pass-if-equal "O_CREAT/O_WRONLY, non-default mode"
- (list #t (logand (lognot (umask)) #o700) "w")
- (skip-if-unsupported)
- (call-with-relatively-opened-file
- (list (dirname (test-file)) O_RDONLY)
- (list (basename (test-file)) (logior O_WRONLY O_CREAT) #o700)
- (lambda (port)
- (list (file-exists? (test-file))
- (stat:perms (stat (test-file)))
- (port-mode port)))))
- (pass-if-exception "closed port" exception:wrong-type-arg
- (skip-if-unsupported)
- (openat (call-with-port (open "." O_RDONLY) identity) "." O_RDONLY))
- (pass-if-exception "non-file port" exception:wrong-type-arg
- (skip-if-unsupported)
- (openat (open-input-string "") "." O_RDONLY))
- (pass-if-exception "not a port" exception:wrong-type-arg
- (skip-if-unsupported)
- (openat "not a port" "." O_RDONLY))
- (when (file-exists? (test-file))
- (delete-file (test-file))))
|