1.0.31.2: snow leopard (macos 10.6) build fixes
[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 #-darwin
217 (deftest stat.1
218   (let* ((stat (sb-posix:stat *test-directory*))
219          (mode (sb-posix::stat-mode stat)))
220     ;; FIXME: Ugly ::s everywhere
221     (logand mode (logior sb-posix::s-iread sb-posix::s-iwrite sb-posix::s-iexec)))
222   #.(logior sb-posix::s-iread sb-posix::s-iwrite sb-posix::s-iexec))
223
224 #-(or darwin win32)
225 (deftest stat.2
226   (let* ((stat (sb-posix:stat "/"))
227          (mode (sb-posix::stat-mode stat)))
228     ;; it's logically possible for / to be writeable by others... but
229     ;; if it is, either someone is playing with strange security
230     ;; modules or they want to know about it anyway.
231     (logand mode sb-posix::s-iwoth))
232   0)
233
234 (deftest stat.3
235   (let* ((now (get-universal-time))
236          ;; FIXME: (encode-universal-time 00 00 00 01 01 1970)
237          (unix-now (- now 2208988800))
238          (stat (sb-posix:stat *test-directory*))
239          (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 #-(or darwin 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 ;; Test that stat can take a second argument.
256 #-win32
257 (deftest stat.5
258     (let* ((stat-1 (sb-posix:stat "/"))
259            (inode-1 (sb-posix:stat-ino stat-1))
260            (stat-2 (sb-posix:stat "/bin/sh"
261                                    stat-1))
262            (inode-2 (sb-posix:stat-ino stat-2)))
263       (values
264        (eq stat-1 stat-2)
265        (/= inode-1 inode-2)))
266   t
267   t)
268
269 #+win32
270 (deftest stat.5
271     (let* ((stat-1 (sb-posix:stat "/"))
272            (mode-1 (sb-posix:stat-mode stat-1))
273            (stat-2 (sb-posix:stat "C:\\CONFIG.SYS"
274                                    stat-1))
275            (mode-2 (sb-posix:stat-mode stat-2)))
276       (values
277        (eq stat-1 stat-2)
278        (/= mode-1 mode-2)))
279   t
280   t)
281
282 ;;; FIXME: add tests for carrying a stat structure around in the
283 ;;; optional argument to SB-POSIX:STAT
284
285 (deftest stat.error.1
286   (handler-case (sb-posix:stat "")
287     (sb-posix:syscall-error (c)
288       (sb-posix:syscall-errno c)))
289   #.sb-posix::enoent)
290
291 (define-eacces-test stat.error.2
292   (let* ((dir (merge-pathnames
293                (make-pathname :directory '(:relative "stat.error.2"))
294                *test-directory*))
295          (file (merge-pathnames
296                 (make-pathname :name "unstatable")
297                 dir)))
298     (sb-posix:mkdir dir +mode-rwx-all+)
299     (with-open-file (s file :direction :output)
300       (write "" :stream s))
301     (sb-posix:chmod dir 0)
302     (handler-case
303         (sb-posix:stat file)
304       (sb-posix:syscall-error (c)
305         (sb-posix:chmod dir (logior sb-posix::s-iread sb-posix::s-iwrite sb-posix::s-iexec))
306         (sb-posix:unlink file)
307         (sb-posix:rmdir dir)
308         (sb-posix:syscall-errno c))
309       (:no-error (result)
310         (sb-posix:chmod dir (logior sb-posix::s-iread sb-posix::s-iwrite sb-posix::s-iexec))
311         (sb-posix:unlink file)
312         (sb-posix:rmdir dir)
313         result)))
314   #.sb-posix::eacces)
315 \f
316 ;;; stat-mode tests
317 (defmacro with-stat-mode ((mode pathname) &body body)
318   (let ((stat (gensym)))
319     `(let* ((,stat (sb-posix:stat ,pathname))
320             (,mode (sb-posix::stat-mode ,stat)))
321        ,@body)))
322
323 (defmacro with-lstat-mode ((mode pathname) &body body)
324   (let ((stat (gensym)))
325     `(let* ((,stat (sb-posix:lstat ,pathname))
326             (,mode (sb-posix::stat-mode ,stat)))
327        ,@body)))
328
329 (deftest stat-mode.1
330   (with-stat-mode (mode *test-directory*)
331     (sb-posix:s-isreg mode))
332   nil)
333
334 #-darwin
335 (deftest stat-mode.2
336   (with-stat-mode (mode *test-directory*)
337     (sb-posix:s-isdir mode))
338   t)
339
340 (deftest stat-mode.3
341   (with-stat-mode (mode *test-directory*)
342     (sb-posix:s-ischr mode))
343   nil)
344
345 (deftest stat-mode.4
346   (with-stat-mode (mode *test-directory*)
347     (sb-posix:s-isblk mode))
348   nil)
349
350 (deftest stat-mode.5
351   (with-stat-mode (mode *test-directory*)
352     (sb-posix:s-isfifo mode))
353   nil)
354
355 #-win32
356 (deftest stat-mode.6
357   (with-stat-mode (mode *test-directory*)
358     (sb-posix:s-issock mode))
359   nil)
360
361 #-(or win32 darwin)
362 (deftest stat-mode.7
363   (let ((link-pathname (make-pathname :name "stat-mode.7"
364                                       :defaults *test-directory*)))
365     (unwind-protect
366          (progn
367            (sb-posix:symlink *test-directory* link-pathname)
368            (with-lstat-mode (mode link-pathname)
369              (sb-posix:s-islnk mode)))
370       (ignore-errors (sb-posix:unlink link-pathname))))
371   t)
372
373 #-darwin
374 (deftest stat-mode.8
375   (let ((pathname (make-pathname :name "stat-mode.8"
376                                  :defaults *test-directory*)))
377     (unwind-protect
378          (progn
379            (with-open-file (out pathname :direction :output)
380              (write-line "test" out))
381            (with-stat-mode (mode pathname)
382              (sb-posix:s-isreg mode)))
383       (ignore-errors (delete-file pathname))))
384   t)
385 \f
386 ;;; see comment in filename's designator definition, in macros.lisp
387 (deftest filename-designator.1
388   (let ((file (format nil "~A/[foo].txt" (namestring *test-directory*))))
389     ;; creat() with a string as argument
390     (let ((fd (sb-posix:creat file sb-posix:s-iwrite)))
391       #+win32
392       (sb-posix:close fd))
393     ;; if this test fails, it will probably be with
394     ;; "System call error 2 (No such file or directory)"
395     (let ((*default-pathname-defaults* *test-directory*))
396       (sb-posix:unlink (car (directory "*.txt")))))
397   0)
398 \f
399 (deftest open.1
400     (let ((name (merge-pathnames "open-test.txt" *test-directory*)))
401       (unwind-protect
402            (progn
403              (sb-posix:close
404               (sb-posix:creat name (logior sb-posix:s-iwrite sb-posix:s-iread)))
405              (let ((fd (sb-posix:open name sb-posix::o-rdonly)))
406                (ignore-errors (sb-posix:close fd))
407                (< fd 0)))
408         (ignore-errors (sb-posix:unlink name))))
409   nil)
410
411 #-hpux ; fix: cant handle c-vargs
412 (deftest open.error.1
413   (handler-case (sb-posix:open *test-directory* sb-posix::o-wronly)
414     (sb-posix:syscall-error (c)
415       (sb-posix:syscall-errno c)))
416   #-win32
417   #.sb-posix::eisdir
418   #+win32
419   #.sb-posix:eacces)
420
421 #-(or (and x86-64 (or linux sunos)) win32)
422 (deftest fcntl.1
423   (let ((fd (sb-posix:open "/dev/null" sb-posix::o-nonblock)))
424     (= (sb-posix:fcntl fd sb-posix::f-getfl) sb-posix::o-nonblock))
425   t)
426 ;; On AMD64/Linux O_LARGEFILE is always set, even though the whole
427 ;; flag makes no sense.
428 #+(and x86-64 (or linux sunos))
429 (deftest fcntl.1
430   (let ((fd (sb-posix:open "/dev/null" sb-posix::o-nonblock)))
431     (/= 0 (logand (sb-posix:fcntl fd sb-posix::f-getfl)
432                   sb-posix::o-nonblock)))
433   t)
434
435 #-(or hpux win32) ; fix: cant handle c-vargs
436 (deftest fcntl.flock.1
437     (locally (declare (sb-ext:muffle-conditions sb-ext:compiler-note))
438       (let ((flock (make-instance 'sb-posix:flock
439                       :type sb-posix:f-wrlck
440                       :whence sb-posix:seek-set
441                       :start 0 :len 10))
442             (pathname "fcntl.flock.1")
443             kid-status)
444         (catch 'test
445           (with-open-file (f pathname :direction :output)
446             (write-line "1234567890" f)
447             (assert (zerop (sb-posix:fcntl f sb-posix:f-setlk flock)))
448             (let ((pid (sb-posix:fork)))
449               (if (zerop pid)
450                   (progn
451                     (multiple-value-bind (nope error)
452                         (ignore-errors (sb-posix:fcntl f sb-posix:f-setlk flock))
453                       (sb-ext:quit
454                        :unix-status
455                        (cond ((not (null nope)) 1)
456                              ((= (sb-posix:syscall-errno error) sb-posix:eagain)
457                               42)
458                              (t 86))
459                        :recklessly-p t #| don't delete the file |#)))
460                   (progn
461                     (setf kid-status
462                           (sb-posix:wexitstatus
463                            (nth-value
464                             1 (sb-posix:waitpid pid 0))))
465                     (throw 'test nil))))))
466         kid-status))
467   42)
468
469
470 #-win32
471 (deftest fcntl.flock.2
472     (locally (declare (sb-ext:muffle-conditions sb-ext:compiler-note))
473       (let ((flock (make-instance 'sb-posix:flock
474                       :type sb-posix:f-wrlck
475                       :whence sb-posix:seek-set
476                       :start 0 :len 10))
477             (pathname "fcntl.flock.2")
478             kid-status)
479         (catch 'test
480           (with-open-file (f pathname :direction :output)
481             (write-line "1234567890" f)
482             (assert (zerop (sb-posix:fcntl f sb-posix:f-setlk flock)))
483             (let ((ppid (sb-posix:getpid))
484                   (pid (sb-posix:fork)))
485               (if (zerop pid)
486                   (let ((r (sb-posix:fcntl f sb-posix:f-getlk flock)))
487                     (sb-ext:quit
488                      :unix-status
489                      (cond ((not (zerop r)) 1)
490                            ((= (sb-posix:flock-pid flock) ppid) 42)
491                            (t 86))
492                      :recklessly-p t #| don't delete the file |#))
493                   (progn
494                     (setf kid-status
495                           (sb-posix:wexitstatus
496                            (nth-value
497                             1 (sb-posix:waitpid pid 0))))
498                     (throw 'test nil))))))
499         kid-status))
500   42)
501
502 (deftest opendir.1
503   (let ((dir (sb-posix:opendir "/")))
504     (unwind-protect (sb-alien:null-alien dir)
505       (unless (sb-alien:null-alien dir)
506         (sb-posix:closedir dir))))
507   nil)
508
509 (deftest readdir.1
510   (let ((dir (sb-posix:opendir "/")))
511     (unwind-protect
512        (block dir-loop
513          (loop for dirent = (sb-posix:readdir dir)
514                until (sb-alien:null-alien dirent)
515                when (not (stringp (sb-posix:dirent-name dirent)))
516                  do (return-from dir-loop nil)
517                finally (return t)))
518       (sb-posix:closedir dir)))
519   t)
520
521 #-darwin
522 (deftest readdir/dirent-name
523     (let ((dir (sb-posix:opendir *current-directory*)))
524       (unwind-protect
525            (equal (sort (loop for entry = (sb-posix:readdir dir)
526                            until (sb-alien:null-alien entry)
527                            collect (sb-posix:dirent-name entry))
528                         #'string<)
529                   (sort (append '("." "..")
530                                 (mapcar (lambda (p)
531                                           (let ((string (enough-namestring p *current-directory*)))
532                                             (if (pathname-name p)
533                                                 string
534                                                 (subseq string 0 (1- (length string))))))
535                                         (directory (make-pathname
536                                                     :name :wild
537                                                     :type :wild
538                                                     :defaults *current-directory*))))
539                         #'string<))
540         (sb-posix:closedir dir)))
541   t)
542
543 #-win32
544 (deftest pwent.1
545   ;; make sure that we found something
546   (not (sb-posix:getpwuid 0))
547   nil)
548
549 #-win32
550 (deftest pwent.2
551   ;; make sure that we found something
552   (not (sb-posix:getpwnam "root"))
553   nil)
554
555 #-win32
556 (deftest pwent.non-existing
557     ;; make sure that we get something sensible, not an error
558     (handler-case (progn (sb-posix:getpwnam "almost-certainly-does-not-exist")
559                          nil)
560       (t (cond) t))
561   nil)
562
563 #-win32
564 (deftest grent.1
565   ;; make sure that we found something
566   (not (sb-posix:getgrgid 0))
567   nil)
568
569 #-win32
570 (deftest grent.2
571   ;; make sure that we found something
572   (not (sb-posix:getgrnam "sys"))
573   nil)
574
575 #-win32
576 (deftest grent.non-existing
577     ;; make sure that we get something sensible, not an error
578     (handler-case (progn (sb-posix:getgrnam "almost-certainly-does-not-exist")
579                          nil)
580       (t (cond) t))
581   nil)
582
583 #+nil
584 ;; Requires root or special group + plus a sensible thing on the port
585 (deftest cfget/setispeed.1
586     (with-open-file (s "/dev/ttyS0")
587       (let* ((termios (sb-posix:tcgetattr s))
588              (old (sb-posix:cfgetispeed termios))
589              (new (if (= old sb-posix:b2400)
590                       sb-posix:b9600
591                       sb-posix:b2400)))
592         (sb-posix:cfsetispeed new termios)
593         (sb-posix:tcsetattr 0 sb-posix:tcsadrain termios)
594         (setf termios (sb-posix:tcgetattr s))
595         (= new (sb-posix:cfgetispeed termios))))
596   t)
597
598 #+nil
599 ;; Requires root or special group + a sensible thing on the port
600 (deftest cfget/setospeed.1
601     (with-open-file (s "/dev/ttyS0" :direction :output :if-exists :append)
602       (let* ((termios (sb-posix:tcgetattr s))
603              (old (sb-posix:cfgetospeed termios))
604              (new (if (= old sb-posix:b2400)
605                       sb-posix:b9600
606                       sb-posix:b2400)))
607         (sb-posix:cfsetospeed new termios)
608         (sb-posix:tcsetattr 0 sb-posix:tcsadrain termios)
609         (setf termios (sb-posix:tcgetattr 0))
610         (= new (sb-posix:cfgetospeed termios))))
611   t)
612
613
614 #-(or darwin win32)
615 (deftest time.1
616     (plusp (sb-posix:time))
617   t)
618
619 #-(or darwin win32)
620 (deftest utimes.1
621     (let ((file (merge-pathnames #p"utimes.1" *test-directory*))
622           (atime (random (1- (expt 2 31))))
623           (mtime (random (1- (expt 2 31)))))
624       (with-open-file (stream file
625                        :direction :output
626                        :if-exists :supersede
627                        :if-does-not-exist :create)
628         (princ "Hello, utimes" stream))
629       (sb-posix:utime file atime mtime)
630       (let* ((stat (sb-posix:stat file)))
631         (delete-file file)
632         (list (= (sb-posix:stat-atime stat) atime)
633               (= (sb-posix:stat-mtime stat) mtime))))
634   (t t))
635 \f
636 ;; readlink tests.
637 #-win32
638 (progn
639   (deftest readlink.1
640       (let ((link-pathname (make-pathname :name "readlink.1"
641                                           :defaults *test-directory*)))
642         (sb-posix:symlink "/" link-pathname)
643         (unwind-protect
644              (sb-posix:readlink link-pathname)
645           (ignore-errors (sb-posix:unlink link-pathname))))
646     "/")
647
648   ;; Same thing, but with a very long link target (which doesn't have
649   ;; to exist).  This tests the array adjustment in the wrapper,
650   ;; provided that the target's length is long enough.
651   #-hpux ; arg2 to readlink is 80, and arg0 is larger than that
652   (deftest readlink.2
653       (let ((target-pathname (make-pathname
654                               :name (make-string 255 :initial-element #\a)
655                               :directory '(:absolute)))
656             (link-pathname (make-pathname :name "readlink.2"
657                                           :defaults *test-directory*)))
658         (sb-posix:symlink target-pathname link-pathname)
659         (unwind-protect
660              (sb-posix:readlink link-pathname)
661           (ignore-errors (sb-posix:unlink link-pathname))))
662     #.(concatenate 'string "/" (make-string 255 :initial-element #\a)))
663
664   ;; The error tests are in the order of exposition from SUSv3.
665   (deftest readlink.error.1
666       (let* ((subdir-pathname (merge-pathnames
667                                (make-pathname
668                                 :directory '(:relative "readlink.error.1"))
669                                *test-directory*))
670              (link-pathname (make-pathname :name "readlink.error.1"
671                                            :defaults subdir-pathname)))
672         (sb-posix:mkdir subdir-pathname #o777)
673         (sb-posix:symlink "/" link-pathname)
674         (sb-posix:chmod subdir-pathname 0)
675         (unwind-protect
676              (handler-case (sb-posix:readlink link-pathname)
677                (sb-posix:syscall-error (c)
678                  (sb-posix:syscall-errno c)))
679           (ignore-errors
680             (sb-posix:chmod subdir-pathname #o777)
681             (sb-posix:unlink link-pathname)
682             (sb-posix:rmdir subdir-pathname))))
683     #.sb-posix:eacces)
684   (deftest readlink.error.2
685       (let* ((non-link-pathname (make-pathname :name "readlink.error.2"
686                                                :defaults *test-directory*))
687              (fd (sb-posix:open non-link-pathname sb-posix::o-creat)))
688         (unwind-protect
689              (handler-case (sb-posix:readlink non-link-pathname)
690                (sb-posix:syscall-error (c)
691                  (sb-posix:syscall-errno c)))
692           (ignore-errors
693             (sb-posix:close fd)
694             (sb-posix:unlink non-link-pathname))))
695     #.sb-posix:einval)
696   ;; Skipping EIO, ELOOP
697   (deftest readlink.error.3
698       (let* ((link-pathname (make-pathname :name "readlink.error.3"
699                                            :defaults *test-directory*))
700              (bogus-pathname (merge-pathnames
701                               (make-pathname
702                                :name "bogus"
703                                :directory '(:relative "readlink.error.3"))
704                                *test-directory*)))
705         (sb-posix:symlink link-pathname link-pathname)
706         (unwind-protect
707              (handler-case (sb-posix:readlink bogus-pathname)
708                (sb-posix:syscall-error (c)
709                  (sb-posix:syscall-errno c)))
710           (ignore-errors (sb-posix:unlink link-pathname))))
711     #.sb-posix:eloop)
712   ;; Note: PATH_MAX and NAME_MAX need not be defined, and may vary, so
713   ;; failure of this test is not too meaningful.
714   (deftest readlink.error.4
715       (let ((pathname
716              (make-pathname :name (make-string 257 ;NAME_MAX plus some, maybe
717                                                :initial-element #\a))))
718         (handler-case (sb-posix:readlink pathname)
719           (sb-posix:syscall-error (c)
720             (sb-posix:syscall-errno c))))
721     #.sb-posix:enametoolong)
722   (deftest readlink.error.5
723       (let ((string (format nil "~v{/A~}" 2049 ;PATH_MAX/2 plus some, maybe
724                                           '(x))))
725         (handler-case (sb-posix:readlink string)
726           (sb-posix:syscall-error (c)
727             (sb-posix:syscall-errno c))))
728     #.sb-posix:enametoolong)
729     (deftest readlink.error.6
730       (let ((no-such-pathname (make-pathname :name "readlink.error.6"
731                                              :defaults *test-directory*)))
732         (handler-case (sb-posix:readlink no-such-pathname)
733           (sb-posix:syscall-error (c)
734             (sb-posix:syscall-errno c))))
735     #.sb-posix:enoent)
736   (deftest readlink.error.7
737       (let* ((non-link-pathname (make-pathname :name "readlink.error.7"
738                                                :defaults *test-directory*))
739              (impossible-pathname (merge-pathnames
740                                    (make-pathname
741                                     :directory
742                                     '(:relative "readlink.error.7")
743                                     :name "readlink.error.7")
744                                    *test-directory*))
745              (fd (sb-posix:open non-link-pathname sb-posix::o-creat)))
746         (unwind-protect
747              (handler-case (sb-posix:readlink impossible-pathname)
748                (sb-posix:syscall-error (c)
749                  (sb-posix:syscall-errno c)))
750           (ignore-errors
751             (sb-posix:close fd)
752             (sb-posix:unlink non-link-pathname))))
753     #.sb-posix:enotdir)
754   )
755
756 (deftest getcwd.1
757     ;; FIXME: something saner, please
758     (equal (sb-unix::posix-getcwd) (sb-posix:getcwd))
759   t)
760
761 #-win32
762 (deftest mkstemp.1
763     (multiple-value-bind (fd temp)
764         (sb-posix:mkstemp (make-pathname
765                            :name "mkstemp-1"
766                            :type "XXXXXX"
767                            :defaults *test-directory*))
768       (let ((pathname (sb-ext:parse-native-namestring temp)))
769         (unwind-protect
770              (values (integerp fd) (pathname-name pathname))
771           (delete-file temp))))
772   t "mkstemp-1")
773
774 ;#-(or win32 sunos hpux)
775 ;;;; mkdtemp is unimplemented on at least Solaris 10
776 #-(or win32 hpux)
777 ;;; But it is implemented on OpenSolaris 2008.11
778 (deftest mkdtemp.1
779     (let ((pathname
780            (sb-ext:parse-native-namestring
781             (sb-posix:mkdtemp (make-pathname
782                                :name "mkdtemp-1"
783                                :type "XXXXXX"
784                                :defaults *test-directory*))
785             nil
786             *default-pathname-defaults*
787             :as-directory t)))
788       (unwind-protect
789            (values (let* ((xxx (car (last (pathname-directory pathname))))
790                           (p (position #\. xxx)))
791                      (and p (subseq xxx 0 p)))
792                    (pathname-name pathname)
793                    (pathname-type pathname))
794         (sb-posix:rmdir pathname)))
795   "mkdtemp-1" nil nil)
796
797 #-win32
798 (deftest mktemp.1
799     (let ((pathname (sb-ext:parse-native-namestring
800                      (sb-posix:mktemp #p"mktemp.XXXXXX"))))
801       (values (equal "mktemp" (pathname-name pathname))
802               (not (equal "XXXXXX" (pathname-type pathname)))))
803   t t)
804
805 #-win32
806 (deftest mkstemp.null-terminate
807     (let* ((default (make-pathname :directory '(:absolute "tmp")))
808            (filename (namestring (make-pathname :name "mkstemp-1"
809                                                 :type "XXXXXX"
810                                                 :defaults default)))
811            ;; The magic 64 is the filename length that happens to
812            ;; trigger the no null termination bug at least on my
813            ;; machine on a certain build.
814            (n (- 64 (length (sb-ext:string-to-octets filename)))))
815       (multiple-value-bind (fd temp)
816           (sb-posix:mkstemp (make-pathname
817                              :name "mkstemp-1"
818                              :type (format nil "~AXXXXXX"
819                                            (make-string n :initial-element #\x))
820                              :defaults default))
821         (let ((pathname (sb-ext:parse-native-namestring temp)))
822           (unwind-protect
823                (values (integerp fd) (pathname-name pathname))
824             (delete-file temp)))))
825   t "mkstemp-1")