1.0.3.16: experimental x86-64/darwin suport
[sbcl.git] / contrib / sb-posix / posix-tests.lisp
1 (defpackage "SB-POSIX-TESTS"
2   (:use "COMMON-LISP" "SB-RT"))
3
4 (in-package "SB-POSIX-TESTS")
5
6 (defvar *test-directory*
7   (ensure-directories-exist
8    (merge-pathnames (make-pathname :directory '(:relative "test-lab"))
9                     (make-pathname :directory
10                                    (pathname-directory *load-truename*)))))
11
12 (defvar *current-directory* *default-pathname-defaults*)
13
14 (defvar *this-file* *load-truename*)
15
16 (eval-when (:compile-toplevel :load-toplevel)
17   (defconstant +mode-rwx-all+
18     (logior sb-posix::s-irusr sb-posix::s-iwusr sb-posix::s-ixusr
19             #-win32
20             (logior
21              sb-posix::s-irgrp sb-posix::s-iwgrp sb-posix::s-ixgrp
22              sb-posix::s-iroth sb-posix::s-iwoth sb-posix::s-ixoth))))
23
24 (defmacro define-eacces-test (name form &rest values)
25   #-win32
26   `(deftest ,name
27     (block ,name
28       (when (= (sb-posix:geteuid) 0)
29         (return-from ,name (values ,@values)))
30       ,form)
31     ,@values))
32 \f
33 (deftest chdir.1
34   (sb-posix:chdir *test-directory*)
35   0)
36
37 (deftest chdir.2
38     (sb-posix:chdir (namestring *test-directory*))
39   0)
40
41 (deftest chdir.3
42     (sb-posix:chdir "/")
43   0)
44
45 (deftest chdir.4
46     (sb-posix:chdir #p"/")
47   0)
48
49 (deftest chdir.5
50     (sb-posix:chdir *current-directory*)
51   0)
52
53 (deftest chdir.6
54   (sb-posix:chdir "/../")
55   0)
56
57 (deftest chdir.7
58   (sb-posix:chdir #p"/../")
59   0)
60
61 (deftest chdir.8
62   (sb-posix:chdir (make-pathname :directory '(:absolute :up)))
63   0)
64
65 (deftest chdir.error.1
66   (let ((dne (make-pathname :directory '(:relative "chdir.does-not-exist"))))
67     (handler-case
68         (sb-posix:chdir (merge-pathnames dne *test-directory*))
69       (sb-posix:syscall-error (c)
70         (sb-posix:syscall-errno c))))
71   #.sb-posix::enoent)
72
73 (deftest chdir.error.2
74   (handler-case
75       (sb-posix:chdir *this-file*)
76     (sb-posix:syscall-error (c)
77       (sb-posix:syscall-errno c)))
78   #-win32
79   #.sb-posix:enotdir
80   #+win32
81   #.sb-posix:einval)
82 \f
83 (deftest mkdir.1
84   (let ((dne (make-pathname :directory '(:relative "mkdir.does-not-exist.1"))))
85     (unwind-protect
86          (sb-posix:mkdir (merge-pathnames dne *test-directory*) 0)
87       ;; FIXME: no delete-directory in CL, but using our own operators
88       ;; is probably not ideal
89       (ignore-errors (sb-posix:rmdir (merge-pathnames dne *test-directory*)))))
90   0)
91
92 (deftest mkdir.2
93   (let ((dne (make-pathname :directory '(:relative "mkdir.does-not-exist.2"))))
94     (unwind-protect
95          (sb-posix:mkdir (namestring (merge-pathnames dne *test-directory*)) 0)
96       (ignore-errors (sb-posix:rmdir (merge-pathnames dne *test-directory*)))))
97   0)
98
99 (deftest mkdir.error.1
100   (handler-case
101       (sb-posix:mkdir *test-directory* 0)
102     (sb-posix:syscall-error (c)
103       (sb-posix:syscall-errno c)))
104   #.sb-posix::eexist)
105
106 (deftest mkdir.error.2
107   (handler-case
108       (sb-posix:mkdir #-win32 "/" #+win32 "C:/" 0)
109     (sb-posix:syscall-error (c)
110       (sb-posix:syscall-errno c)))
111   #-win32
112   #.sb-posix::eexist
113   #+win32
114   #.sb-posix:eacces)
115
116 (define-eacces-test mkdir.error.3
117   (let* ((dir (merge-pathnames
118                (make-pathname :directory '(:relative "mkdir.error.3"))
119                *test-directory*))
120          (dir2 (merge-pathnames
121                 (make-pathname :directory '(:relative "does-not-exist"))
122                 dir)))
123     (sb-posix:mkdir dir 0)
124     (handler-case
125         (sb-posix:mkdir dir2 0)
126       (sb-posix:syscall-error (c)
127         (sb-posix:rmdir dir)
128         (sb-posix:syscall-errno c))
129       (:no-error (result)
130         (sb-posix:rmdir dir2)
131         (sb-posix:rmdir dir)
132         result)))
133   #.sb-posix::eacces)
134 \f
135 (deftest rmdir.1
136   (let ((dne (make-pathname :directory '(:relative "rmdir.does-not-exist.1"))))
137     (ensure-directories-exist (merge-pathnames dne *test-directory*))
138     (sb-posix:rmdir (merge-pathnames dne *test-directory*)))
139   0)
140
141 (deftest rmdir.2
142   (let ((dne (make-pathname :directory '(:relative "rmdir.does-not-exist.2"))))
143     (ensure-directories-exist (merge-pathnames dne *test-directory*))
144     (sb-posix:rmdir (namestring (merge-pathnames dne *test-directory*))))
145   0)
146
147 (deftest rmdir.error.1
148   (let ((dne (make-pathname :directory '(:relative "rmdir.dne.error.1"))))
149     (handler-case
150         (sb-posix:rmdir (merge-pathnames dne *test-directory*))
151       (sb-posix:syscall-error (c)
152         (sb-posix:syscall-errno c))))
153   #.sb-posix::enoent)
154
155 (deftest rmdir.error.2
156   (handler-case
157       (sb-posix:rmdir *this-file*)
158     (sb-posix:syscall-error (c)
159       (sb-posix:syscall-errno c)))
160   #-win32
161   #.sb-posix::enotdir
162   #+win32
163   #.sb-posix::einval)
164
165 (deftest rmdir.error.3
166   (handler-case
167       (sb-posix:rmdir #-win32 "/" #+win32 "C:/")
168     (sb-posix:syscall-error (c)
169       (sb-posix:syscall-errno c)))
170   #-win32
171   #.sb-posix::ebusy
172   #+win32
173   #.sb-posix::eacces)
174
175 (deftest rmdir.error.4
176   (let* ((dir (ensure-directories-exist
177                (merge-pathnames
178                 (make-pathname :directory '(:relative "rmdir.error.4"))
179                 *test-directory*)))
180          (file (make-pathname :name "foo" :defaults dir)))
181     (with-open-file (s file :direction :output :if-exists nil)
182       (write "" :stream s))
183     (handler-case
184         (sb-posix:rmdir dir)
185       (sb-posix:syscall-error (c)
186         (delete-file file)
187         (sb-posix:rmdir dir)
188         (let ((errno (sb-posix:syscall-errno c)))
189           ;; documented by POSIX
190           (or (= errno sb-posix::eexist) (= errno sb-posix::enotempty))))))
191   t)
192
193 (define-eacces-test rmdir.error.5
194   (let* ((dir (merge-pathnames
195                (make-pathname :directory '(:relative "rmdir.error.5"))
196                *test-directory*))
197          (dir2 (merge-pathnames
198                 (make-pathname :directory '(:relative "unremovable"))
199                 dir)))
200     (sb-posix:mkdir dir +mode-rwx-all+)
201     (sb-posix:mkdir dir2 +mode-rwx-all+)
202     (sb-posix:chmod dir 0)
203     (handler-case
204         (sb-posix:rmdir dir2)
205       (sb-posix:syscall-error (c)
206         (sb-posix:chmod dir (logior sb-posix::s-iread sb-posix::s-iwrite sb-posix::s-iexec))
207         (sb-posix:rmdir dir2)
208         (sb-posix:rmdir dir)
209         (sb-posix:syscall-errno c))
210       (:no-error (result)
211         (sb-posix:chmod dir (logior sb-posix::s-iread sb-posix::s-iwrite sb-posix::s-iexec))
212         (sb-posix:rmdir dir)
213         result)))
214   #.sb-posix::eacces)
215 \f
216 (deftest stat.1
217   (let* ((stat (sb-posix:stat *test-directory*))
218          (mode (sb-posix::stat-mode stat)))
219     ;; FIXME: Ugly ::s everywhere
220     (logand mode (logior sb-posix::s-iread sb-posix::s-iwrite sb-posix::s-iexec)))
221   #.(logior sb-posix::s-iread sb-posix::s-iwrite sb-posix::s-iexec))
222
223 #-win32
224 (deftest stat.2
225   (let* ((stat (sb-posix:stat "/"))
226          (mode (sb-posix::stat-mode stat)))
227     ;; it's logically possible for / to be writeable by others... but
228     ;; if it is, either someone is playing with strange security
229     ;; modules or they want to know about it anyway.
230     (logand mode sb-posix::s-iwoth))
231   0)
232
233 (deftest stat.3
234   (let* ((now (get-universal-time))
235          ;; FIXME: (encode-universal-time 00 00 00 01 01 1970)
236          (unix-now (- now 2208988800))
237          (stat (sb-posix:stat *test-directory*))
238          #+darwin (atime (sb-alien:slot (sb-posix:stat-atime stat) 'sb-posix::tv-sec))
239          #-darwin (atime (sb-posix::stat-atime stat)))
240     ;; FIXME: breaks if mounted noatime :-(
241     #+nil (< (- atime unix-now) 10)
242     (< (- atime unix-now) 10))
243   t)
244
245 #-win32
246 (deftest stat.4
247   (let* ((stat (sb-posix:stat (make-pathname :directory '(:absolute :up))))
248          (mode (sb-posix::stat-mode stat)))
249     ;; it's logically possible for / to be writeable by others... but
250     ;; if it is, either someone is playing with strange security
251     ;; modules or they want to know about it anyway.
252     (logand mode sb-posix::s-iwoth))
253   0)
254
255 ;;; FIXME: add tests for carrying a stat structure around in the
256 ;;; optional argument to SB-POSIX:STAT
257
258 (deftest stat.error.1
259   (handler-case (sb-posix:stat "")
260     (sb-posix:syscall-error (c)
261       (sb-posix:syscall-errno c)))
262   #.sb-posix::enoent)
263
264 (define-eacces-test stat.error.2
265   (let* ((dir (merge-pathnames
266                (make-pathname :directory '(:relative "stat.error.2"))
267                *test-directory*))
268          (file (merge-pathnames
269                 (make-pathname :name "unstatable")
270                 dir)))
271     (sb-posix:mkdir dir +mode-rwx-all+)
272     (with-open-file (s file :direction :output)
273       (write "" :stream s))
274     (sb-posix:chmod dir 0)
275     (handler-case
276         (sb-posix:stat file)
277       (sb-posix:syscall-error (c)
278         (sb-posix:chmod dir (logior sb-posix::s-iread sb-posix::s-iwrite sb-posix::s-iexec))
279         (sb-posix:unlink file)
280         (sb-posix:rmdir dir)
281         (sb-posix:syscall-errno c))
282       (:no-error (result)
283         (sb-posix:chmod dir (logior sb-posix::s-iread sb-posix::s-iwrite sb-posix::s-iexec))
284         (sb-posix:unlink file)
285         (sb-posix:rmdir dir)
286         result)))
287   #.sb-posix::eacces)
288 \f
289 ;;; stat-mode tests
290 (defmacro with-stat-mode ((mode pathname) &body body)
291   (let ((stat (gensym)))
292     `(let* ((,stat (sb-posix:stat ,pathname))
293             (,mode (sb-posix::stat-mode ,stat)))
294        ,@body)))
295
296 (defmacro with-lstat-mode ((mode pathname) &body body)
297   (let ((stat (gensym)))
298     `(let* ((,stat (sb-posix:lstat ,pathname))
299             (,mode (sb-posix::stat-mode ,stat)))
300        ,@body)))
301
302 (deftest stat-mode.1
303   (with-stat-mode (mode *test-directory*)
304     (sb-posix:s-isreg mode))
305   nil)
306
307 (deftest stat-mode.2
308   (with-stat-mode (mode *test-directory*)
309     (sb-posix:s-isdir mode))
310   t)
311
312 (deftest stat-mode.3
313   (with-stat-mode (mode *test-directory*)
314     (sb-posix:s-ischr mode))
315   nil)
316
317 (deftest stat-mode.4
318   (with-stat-mode (mode *test-directory*)
319     (sb-posix:s-isblk mode))
320   nil)
321
322 (deftest stat-mode.5
323   (with-stat-mode (mode *test-directory*)
324     (sb-posix:s-isfifo mode))
325   nil)
326
327 #-win32
328 (deftest stat-mode.6
329   (with-stat-mode (mode *test-directory*)
330     (sb-posix:s-issock mode))
331   nil)
332
333 #-win32
334 (deftest stat-mode.7
335   (let ((link-pathname (make-pathname :name "stat-mode.7"
336                                       :defaults *test-directory*)))
337     (unwind-protect
338          (progn
339            (sb-posix:symlink *test-directory* link-pathname)
340            (with-lstat-mode (mode link-pathname)
341              (sb-posix:s-islnk mode)))
342       (ignore-errors (sb-posix:unlink link-pathname))))
343   t)
344
345 (deftest stat-mode.8
346   (let ((pathname (make-pathname :name "stat-mode.8"
347                                  :defaults *test-directory*)))
348     (unwind-protect
349          (progn
350            (with-open-file (out pathname :direction :output)
351              (write-line "test" out))
352            (with-stat-mode (mode pathname)
353              (sb-posix:s-isreg mode)))
354       (ignore-errors (delete-file pathname))))
355   t)
356 \f
357 ;;; see comment in filename's designator definition, in macros.lisp
358 (deftest filename-designator.1
359   (let ((file (format nil "~A/[foo].txt" (namestring *test-directory*))))
360     ;; creat() with a string as argument
361     (let ((fd (sb-posix:creat file sb-posix:s-iwrite)))
362       #+win32
363       (sb-posix:close fd))
364     ;; if this test fails, it will probably be with
365     ;; "System call error 2 (No such file or directory)"
366     (let ((*default-pathname-defaults* *test-directory*))
367       (sb-posix:unlink (car (directory "*.txt")))))
368   0)
369 \f
370 (deftest open.1
371     (let ((name (merge-pathnames "open-test.txt" *test-directory*)))
372       (unwind-protect
373            (progn
374              (sb-posix:close
375               (sb-posix:creat name (logior sb-posix:s-iwrite sb-posix:s-iread)))
376              (let ((fd (sb-posix:open name sb-posix::o-rdonly)))
377                (ignore-errors (sb-posix:close fd))
378                (< fd 0)))
379         (ignore-errors (sb-posix:unlink name))))
380   nil)
381
382 (deftest open.error.1
383   (handler-case (sb-posix:open *test-directory* sb-posix::o-wronly)
384     (sb-posix:syscall-error (c)
385       (sb-posix:syscall-errno c)))
386   #-win32
387   #.sb-posix::eisdir
388   #+win32
389   #.sb-posix:eacces)
390
391 #-(or (and x86-64 linux) win32)
392 (deftest fcntl.1
393   (let ((fd (sb-posix:open "/dev/null" sb-posix::o-nonblock)))
394     (= (sb-posix:fcntl fd sb-posix::f-getfl) sb-posix::o-nonblock))
395   t)
396 ;; On AMD64/Linux O_LARGEFILE is always set, even though the whole
397 ;; flag makes no sense.
398 #+(and x86-64 linux)
399 (deftest fcntl.1
400   (let ((fd (sb-posix:open "/dev/null" sb-posix::o-nonblock)))
401     (/= 0 (logand (sb-posix:fcntl fd sb-posix::f-getfl)
402                   sb-posix::o-nonblock)))
403   t)
404
405 (deftest opendir.1
406   (let ((dir (sb-posix:opendir "/")))
407     (unwind-protect (sb-alien:null-alien dir)
408       (unless (sb-alien:null-alien dir)
409         (sb-posix:closedir dir))))
410   nil)
411
412 (deftest readdir.1
413   (let ((dir (sb-posix:opendir "/")))
414     (unwind-protect
415        (block dir-loop
416          (loop for dirent = (sb-posix:readdir dir)
417                until (sb-alien:null-alien dirent)
418                when (not (stringp (sb-posix:dirent-name dirent)))
419                  do (return-from dir-loop nil)
420                finally (return t)))
421       (sb-posix:closedir dir)))
422   t)
423
424 (deftest readdir/dirent-name
425     (let ((dir (sb-posix:opendir *current-directory*)))
426       (unwind-protect
427            (equal (sort (loop for entry = (sb-posix:readdir dir)
428                            until (sb-alien:null-alien entry)
429                            collect (sb-posix:dirent-name entry))
430                         #'string<)
431                   (sort (append '("." "..")
432                                 (mapcar (lambda (p)
433                                           (let ((string (enough-namestring p *current-directory*)))
434                                             (if (pathname-name p)
435                                                 string
436                                                 (subseq string 0 (1- (length string))))))
437                                         (directory (make-pathname
438                                                     :name :wild
439                                                     :type :wild
440                                                     :defaults *current-directory*))))
441                         #'string<))
442         (sb-posix:closedir dir)))
443   t)
444
445 #-win32
446 (deftest pwent.1
447   ;; make sure that we found something
448   (not (sb-posix:getpwuid 0))
449   nil)
450
451 #-win32
452 (deftest pwent.2
453   ;; make sure that we found something
454   (not (sb-posix:getpwnam "root"))
455   nil)
456
457 #+nil
458 ;; Requires root or special group + plus a sensible thing on the port
459 (deftest cfget/setispeed.1
460     (with-open-file (s "/dev/ttyS0")
461       (let* ((termios (sb-posix:tcgetattr s))
462              (old (sb-posix:cfgetispeed termios))
463              (new (if (= old sb-posix:b2400)
464                       sb-posix:b9600
465                       sb-posix:b2400)))
466         (sb-posix:cfsetispeed new termios)
467         (sb-posix:tcsetattr 0 sb-posix:tcsadrain termios)
468         (setf termios (sb-posix:tcgetattr s))
469         (= new (sb-posix:cfgetispeed termios))))
470   t)
471
472 #+nil
473 ;; Requires root or special group + a sensible thing on the port
474 (deftest cfget/setospeed.1
475     (with-open-file (s "/dev/ttyS0" :direction :output :if-exists :append)
476       (let* ((termios (sb-posix:tcgetattr s))
477              (old (sb-posix:cfgetospeed termios))
478              (new (if (= old sb-posix:b2400)
479                       sb-posix:b9600
480                       sb-posix:b2400)))
481         (sb-posix:cfsetospeed new termios)
482         (sb-posix:tcsetattr 0 sb-posix:tcsadrain termios)
483         (setf termios (sb-posix:tcgetattr 0))
484         (= new (sb-posix:cfgetospeed termios))))
485   t)
486
487
488 #-win32
489 (deftest time.1
490     (plusp (sb-posix:time))
491   t)
492
493 ;;; CLH: FIXME! For darwin atime and mtime return a timespec. This
494 ;;; _should_ work, but it doesn't. For some reason mtime is always
495 ;;; 0. Comment the mtime test out for the moment.
496 #+darwin
497 (deftest utime.1
498     (let ((file (merge-pathnames #p"utime.1" *test-directory*))
499           (atime (random (1- (expt 2 31))))
500           (mtime (random (1- (expt 2 31)))))
501       (with-open-file (stream file
502                        :direction :output
503                        :if-exists :supersede
504                        :if-does-not-exist :create)
505         (princ "Hello, utime" stream))
506       (sb-posix:utime file atime mtime)
507       (let* ((stat (sb-posix:stat file)))
508         (delete-file file)
509         (list (= (sb-alien:slot (sb-posix:stat-atime stat) 'sb-posix::tv-sec) atime)
510               #+nil (= (sb-alien:slot (sb-posix:stat-mtime stat) 'sb-posix::tv-sec) mtime))))
511   (t #+nil t))
512
513 #-(or win32 darwin)
514 (deftest utimes.1
515     (let ((file (merge-pathnames #p"utimes.1" *test-directory*))
516           (atime (random (1- (expt 2 31))))
517           (mtime (random (1- (expt 2 31)))))
518       (with-open-file (stream file
519                        :direction :output
520                        :if-exists :supersede
521                        :if-does-not-exist :create)
522         (princ "Hello, utimes" stream))
523       (sb-posix:utime file atime mtime)
524       (let* ((stat (sb-posix:stat file)))
525         (delete-file file)
526         (list (= (sb-posix:stat-atime stat) atime)
527               (= (sb-posix:stat-mtime stat) mtime))))
528   (t t))
529 \f
530 ;; readlink tests.
531 #-win32
532 (progn
533   (deftest readlink.1
534       (let ((link-pathname (make-pathname :name "readlink.1"
535                                           :defaults *test-directory*)))
536         (sb-posix:symlink "/" link-pathname)
537         (unwind-protect
538              (sb-posix:readlink link-pathname)
539           (ignore-errors (sb-posix:unlink link-pathname))))
540     "/")
541
542   ;; Same thing, but with a very long link target (which doesn't have
543   ;; to exist).  This tests the array adjustment in the wrapper,
544   ;; provided that the target's length is long enough.
545   (deftest readlink.2
546       (let ((target-pathname (make-pathname
547                               :name (make-string 255 :initial-element #\a)
548                               :directory '(:absolute)))
549             (link-pathname (make-pathname :name "readlink.2"
550                                           :defaults *test-directory*)))
551         (sb-posix:symlink target-pathname link-pathname)
552         (unwind-protect
553              (sb-posix:readlink link-pathname)
554           (ignore-errors (sb-posix:unlink link-pathname))))
555     #.(concatenate 'string "/" (make-string 255 :initial-element #\a)))
556
557   ;; The error tests are in the order of exposition from SUSv3.
558   (deftest readlink.error.1
559       (let* ((subdir-pathname (merge-pathnames
560                                (make-pathname
561                                 :directory '(:relative "readlink.error.1"))
562                                *test-directory*))
563              (link-pathname (make-pathname :name "readlink.error.1"
564                                            :defaults subdir-pathname)))
565         (sb-posix:mkdir subdir-pathname #o777)
566         (sb-posix:symlink "/" link-pathname)
567         (sb-posix:chmod subdir-pathname 0)
568         (unwind-protect
569              (handler-case (sb-posix:readlink link-pathname)
570                (sb-posix:syscall-error (c)
571                  (sb-posix:syscall-errno c)))
572           (ignore-errors
573             (sb-posix:chmod subdir-pathname #o777)
574             (sb-posix:unlink link-pathname)
575             (sb-posix:rmdir subdir-pathname))))
576     #.sb-posix:eacces)
577   (deftest readlink.error.2
578       (let* ((non-link-pathname (make-pathname :name "readlink.error.2"
579                                                :defaults *test-directory*))
580              (fd (sb-posix:open non-link-pathname sb-posix::o-creat)))
581         (unwind-protect
582              (handler-case (sb-posix:readlink non-link-pathname)
583                (sb-posix:syscall-error (c)
584                  (sb-posix:syscall-errno c)))
585           (ignore-errors
586             (sb-posix:close fd)
587             (sb-posix:unlink non-link-pathname))))
588     #.sb-posix:einval)
589   ;; Skipping EIO, ELOOP
590   (deftest readlink.error.3
591       (let* ((link-pathname (make-pathname :name "readlink.error.3"
592                                            :defaults *test-directory*))
593              (bogus-pathname (merge-pathnames
594                               (make-pathname
595                                :name "bogus"
596                                :directory '(:relative "readlink.error.3"))
597                                *test-directory*)))
598         (sb-posix:symlink link-pathname link-pathname)
599         (unwind-protect
600              (handler-case (sb-posix:readlink bogus-pathname)
601                (sb-posix:syscall-error (c)
602                  (sb-posix:syscall-errno c)))
603           (ignore-errors (sb-posix:unlink link-pathname))))
604     #.sb-posix:eloop)
605   ;; Note: PATH_MAX and NAME_MAX need not be defined, and may vary, so
606   ;; failure of this test is not too meaningful.
607   (deftest readlink.error.4
608       (let ((pathname
609              (make-pathname :name (make-string 257 ;NAME_MAX plus some, maybe
610                                                :initial-element #\a))))
611         (handler-case (sb-posix:readlink pathname)
612           (sb-posix:syscall-error (c)
613             (sb-posix:syscall-errno c))))
614     #.sb-posix:enametoolong)
615   (deftest readlink.error.5
616       (let ((string (format nil "~v{/A~}" 2049 ;PATH_MAX/2 plus some, maybe
617                                           '(x))))
618         (handler-case (sb-posix:readlink string)
619           (sb-posix:syscall-error (c)
620             (sb-posix:syscall-errno c))))
621     #.sb-posix:enametoolong)
622     (deftest readlink.error.6
623       (let ((no-such-pathname (make-pathname :name "readlink.error.6"
624                                              :defaults *test-directory*)))
625         (handler-case (sb-posix:readlink no-such-pathname)
626           (sb-posix:syscall-error (c)
627             (sb-posix:syscall-errno c))))
628     #.sb-posix:enoent)
629   (deftest readlink.error.7
630       (let* ((non-link-pathname (make-pathname :name "readlink.error.7"
631                                                :defaults *test-directory*))
632              (impossible-pathname (merge-pathnames
633                                    (make-pathname
634                                     :directory
635                                     '(:relative "readlink.error.7")
636                                     :name "readlink.error.7")
637                                    *test-directory*))
638              (fd (sb-posix:open non-link-pathname sb-posix::o-creat)))
639         (unwind-protect
640              (handler-case (sb-posix:readlink impossible-pathname)
641                (sb-posix:syscall-error (c)
642                  (sb-posix:syscall-errno c)))
643           (ignore-errors
644             (sb-posix:close fd)
645             (sb-posix:unlink non-link-pathname))))
646     #.sb-posix:enotdir)
647   )