1 ;;;; file system interface functions -- fairly Unix-centric, but with
2 ;;;; differences between Unix and Win32 papered over.
4 ;;;; This software is part of the SBCL system. See the README file for
7 ;;;; This software is derived from the CMU CL system, which was
8 ;;;; written at Carnegie Mellon University and released into the
9 ;;;; public domain. The software is in the public domain and is
10 ;;;; provided with absolutely no warranty. See the COPYING and CREDITS
11 ;;;; files for more information.
13 (in-package "SB!IMPL")
15 ;;;; Unix pathname host support
17 ;;; FIXME: the below shouldn't really be here, but in documentation
18 ;;; (chapter 19 makes a lot of requirements for documenting
19 ;;; implementation-dependent decisions), but anyway it's probably not
20 ;;; what we currently do.
22 ;;; Unix namestrings have the following format:
24 ;;; namestring := [ directory ] [ file [ type [ version ]]]
25 ;;; directory := [ "/" ] { file "/" }*
27 ;;; type := "." [^/.]*
28 ;;; version := "." ([0-9]+ | "*")
30 ;;; Note: this grammar is ambiguous. The string foo.bar.5 can be
31 ;;; parsed as either just the file specified or as specifying the
32 ;;; file, type, and version. Therefore, we use the following rules
33 ;;; when confronted with an ambiguous file.type.version string:
35 ;;; - If the first character is a dot, it's part of the file. It is not
36 ;;; considered a dot in the following rules.
38 ;;; - Otherwise, the last dot separates the file and the type.
40 ;;; Wildcard characters:
42 ;;; If the directory, file, type components contain any of the
43 ;;; following characters, it is considered part of a wildcard pattern
44 ;;; and has the following meaning.
46 ;;; ? - matches any one character
47 ;;; * - matches any zero or more characters.
48 ;;; [abc] - matches any of a, b, or c.
49 ;;; {str1,str2,...,strn} - matches any of str1, str2, ..., or strn.
50 ;;; (FIXME: no it doesn't)
52 ;;; Any of these special characters can be preceded by a backslash to
53 ;;; cause it to be treated as a regular character.
54 (defun remove-backslashes (namestr start end)
56 "Remove any occurrences of #\\ from the string because we've already
57 checked for whatever they may have protected."
58 (declare (type simple-string namestr)
59 (type index start end))
60 (let* ((result (make-string (- end start) :element-type 'character))
63 (do ((src start (1+ src)))
66 (setf (schar result dst) (schar namestr src))
70 (let ((char (schar namestr src)))
71 (cond ((char= char #\\)
74 (setf (schar result dst) char)
77 (error 'namestring-parse-error
78 :complaint "backslash in a bad place"
81 (%shrink-vector result dst)))
83 (defvar *ignore-wildcards* nil)
85 (/show0 "filesys.lisp 86")
87 (defun maybe-make-pattern (namestr start end)
88 (declare (type simple-string namestr)
89 (type index start end))
90 (if *ignore-wildcards*
91 (subseq namestr start end)
95 (last-regular-char nil)
97 (flet ((flush-pending-regulars ()
98 (when last-regular-char
99 (pattern (if any-quotes
100 (remove-backslashes namestr
103 (subseq namestr last-regular-char index)))
104 (setf any-quotes nil)
105 (setf last-regular-char nil))))
109 (let ((char (schar namestr index)))
116 (unless last-regular-char
117 (setf last-regular-char index))
120 (flush-pending-regulars)
121 (pattern :single-char-wild)
124 (flush-pending-regulars)
125 (pattern :multi-char-wild)
128 (flush-pending-regulars)
130 (position #\] namestr :start index :end end)))
131 (unless close-bracket
132 (error 'namestring-parse-error
133 :complaint "#\\[ with no corresponding #\\]"
136 (pattern (cons :character-set
140 (setf index (1+ close-bracket))))
142 (unless last-regular-char
143 (setf last-regular-char index))
145 (flush-pending-regulars)))
146 (cond ((null (pattern))
148 ((null (cdr (pattern)))
149 (let ((piece (first (pattern))))
151 ((member :multi-char-wild) :wild)
152 (simple-string piece)
154 (make-pattern (pattern))))))
156 (make-pattern (pattern)))))))
158 (/show0 "filesys.lisp 160")
160 (defun extract-name-type-and-version (namestr start end)
161 (declare (type simple-string namestr)
162 (type index start end))
163 (let* ((last-dot (position #\. namestr :start (1+ start) :end end
167 (values (maybe-make-pattern namestr start last-dot)
168 (maybe-make-pattern namestr (1+ last-dot) end)
171 (values (maybe-make-pattern namestr start end)
175 (/show0 "filesys.lisp 200")
178 ;;;; wildcard matching stuff
180 ;;; Return a list of all the Lispy filenames (not including e.g. the
181 ;;; Unix magic "." and "..") in the directory named by DIRECTORY-NAME.
182 (defun directory-lispy-filenames (directory-name)
183 (with-alien ((adlf (* c-string)
184 (alien-funcall (extern-alien
185 "alloc_directory_lispy_filenames"
186 (function (* c-string) c-string))
188 (if (null-alien adlf)
189 (error 'simple-file-error
190 :pathname directory-name
191 :format-control "~@<couldn't read directory ~S: ~2I~_~A~:>"
192 :format-arguments (list directory-name (strerror)))
194 (c-strings->string-list adlf)
195 (alien-funcall (extern-alien "free_directory_lispy_filenames"
196 (function void (* c-string)))
199 (/show0 "filesys.lisp 498")
201 ;; TODO: the implementation !enumerate-matches is some hairy stuff
202 ;; that we mostly don't need. Couldn't we use POSIX fts(3) to walk
203 ;; the file system and PATHNAME-MATCH-P to select matches, at least on
205 (defmacro !enumerate-matches ((var pathname &optional result
206 &key (verify-existence t)
210 (%enumerate-matches (pathname ,pathname)
213 (lambda (,var) ,@body))
216 (/show0 "filesys.lisp 500")
218 ;;; Call FUNCTION on matches.
220 ;;; KLUDGE: this assumes that an absolute pathname is indicated to the
221 ;;; operating system by having a directory separator as the first
222 ;;; character in the directory part. This is true for Win32 pathnames
223 ;;; and for Unix pathnames, but it isn't true for LispM pathnames (and
224 ;;; their bastard offspring, logical pathnames. Also it assumes that
225 ;;; Unix pathnames have an empty or :unspecific device, and that
226 ;;; windows drive letters are the only kinds of non-empty/:UNSPECIFIC
228 (defun %enumerate-matches (pathname verify-existence follow-links function)
229 (/noshow0 "entering %ENUMERATE-MATCHES")
230 (when (pathname-type pathname)
231 (unless (pathname-name pathname)
232 (error "cannot supply a type without a name:~% ~S" pathname)))
233 (when (and (integerp (pathname-version pathname))
234 (member (pathname-type pathname) '(nil :unspecific)))
235 (error "cannot supply a version without a type:~% ~S" pathname))
236 (let ((host (pathname-host pathname))
237 (device (pathname-device pathname))
238 (directory (pathname-directory pathname)))
239 (/noshow0 "computed HOST and DIRECTORY")
240 (let* ((dirstring (if directory
241 (ecase (first directory)
242 (:absolute (host-unparse-directory-separator host))
245 (devstring (if (and device (not (eq device :unspecific)))
246 (concatenate 'simple-string (string device) (string #\:))
248 (headstring (concatenate 'simple-string devstring dirstring)))
250 (%enumerate-directories headstring (rest directory) pathname
251 verify-existence follow-links nil function)
252 (%enumerate-files headstring pathname verify-existence function)))))
254 ;;; Call FUNCTION on directories.
255 (defun %enumerate-directories (head tail pathname verify-existence
256 follow-links nodes function
257 &aux (host (pathname-host pathname)))
258 (declare (simple-string head))
260 (setf follow-links nil)
261 (macrolet ((unix-xstat (name)
263 (sb!unix:unix-stat ,name)
264 (sb!unix:unix-lstat ,name)))
265 (with-directory-node-noted ((head) &body body)
266 `(multiple-value-bind (res dev ino mode)
268 (when (and res (eql (logand mode sb!unix:s-ifmt)
270 (let ((nodes (cons (cons dev ino) nodes)))
272 (with-directory-node-removed ((head) &body body)
273 `(multiple-value-bind (res dev ino mode)
275 (when (and res (eql (logand mode sb!unix:s-ifmt)
277 (let ((nodes (remove (cons dev ino) nodes :test #'equal)))
280 (let ((piece (car tail)))
283 (let ((head (concatenate 'string head piece)))
284 (with-directory-node-noted (head)
285 (%enumerate-directories
286 (concatenate 'string head
287 (host-unparse-directory-separator host))
289 verify-existence follow-links
291 ((member :wild-inferiors)
292 ;; now with extra error case handling from CLHS
293 ;; 19.2.2.4.3 -- CSR, 2004-01-24
294 (when (member (cadr tail) '(:up :back))
295 (error 'simple-file-error
297 :format-control "~@<invalid use of ~S after :WILD-INFERIORS~@:>."
298 :format-arguments (list (cadr tail))))
299 (%enumerate-directories head (rest tail) pathname
300 verify-existence follow-links
302 (dolist (name (directory-lispy-filenames head))
303 (let ((subdir (concatenate 'string head name)))
304 (multiple-value-bind (res dev ino mode)
306 (declare (type (or fixnum null) mode))
307 (when (and res (eql (logand mode sb!unix:s-ifmt)
309 (unless (dolist (dir nodes nil)
310 (when (and (eql (car dir) dev)
315 (let ((nodes (cons (cons dev ino) nodes))
316 (subdir (concatenate 'string subdir (host-unparse-directory-separator host))))
317 (%enumerate-directories subdir tail pathname
318 verify-existence follow-links
319 nodes function))))))))
320 ((or pattern (member :wild))
321 (dolist (name (directory-lispy-filenames head))
322 (when (or (eq piece :wild) (pattern-matches piece name))
323 (let ((subdir (concatenate 'string head name)))
324 (multiple-value-bind (res dev ino mode)
326 (declare (type (or fixnum null) mode))
328 (eql (logand mode sb!unix:s-ifmt)
330 (let ((nodes (cons (cons dev ino) nodes))
331 (subdir (concatenate 'string subdir (host-unparse-directory-separator host))))
332 (%enumerate-directories subdir (rest tail) pathname
333 verify-existence follow-links
334 nodes function))))))))
336 (when (string= head (host-unparse-directory-separator host))
337 (error 'simple-file-error
339 :format-control "~@<invalid use of :UP after :ABSOLUTE.~@:>"))
340 (with-directory-node-removed (head)
341 (let ((head (concatenate 'string head "..")))
342 (with-directory-node-noted (head)
343 (%enumerate-directories (concatenate 'string head (host-unparse-directory-separator host))
345 verify-existence follow-links
348 ;; :WILD-INFERIORS is handled above, so the only case here
349 ;; should be (:ABSOLUTE :BACK)
350 (aver (string= head (host-unparse-directory-separator host)))
351 (error 'simple-file-error
353 :format-control "~@<invalid use of :BACK after :ABSOLUTE.~@:>"))))
354 (%enumerate-files head pathname verify-existence function))))
356 ;;; Call FUNCTION on files.
357 (defun %enumerate-files (directory pathname verify-existence function)
358 (declare (simple-string directory))
359 (/noshow0 "entering %ENUMERATE-FILES")
360 (let ((name (%pathname-name pathname))
361 (type (%pathname-type pathname))
362 (version (%pathname-version pathname)))
363 (/noshow0 "computed NAME, TYPE, and VERSION")
364 (cond ((member name '(nil :unspecific))
365 (/noshow0 "UNSPECIFIC, more or less")
366 (let ((directory (coerce directory 'string)))
367 (when (or (not verify-existence)
368 (sb!unix:unix-file-kind directory))
369 (funcall function directory))))
370 ((or (pattern-p name)
374 (/noshow0 "WILD, more or less")
375 ;; I IGNORE-ERRORS here just because the original CMU CL
376 ;; code did. I think the intent is that it's not an error
377 ;; to request matches to a wild pattern when no matches
378 ;; exist, but I haven't tried to figure out whether
379 ;; everything is kosher. (E.g. what if we try to match a
380 ;; wildcard but we don't have permission to read one of the
381 ;; relevant directories?) -- WHN 2001-04-17
382 (dolist (complete-filename (ignore-errors
383 (directory-lispy-filenames directory)))
385 (file-name file-type file-version)
386 (let ((*ignore-wildcards* t))
387 (extract-name-type-and-version
388 complete-filename 0 (length complete-filename)))
389 (when (and (components-match file-name name)
390 (components-match file-type type)
391 (components-match file-version version))
395 complete-filename))))))
397 (/noshow0 "default case")
398 (let ((file (concatenate 'string directory name)))
399 (/noshow "computed basic FILE")
400 (unless (or (null type) (eq type :unspecific))
401 (/noshow0 "tweaking FILE for more-or-less-:UNSPECIFIC case")
402 (setf file (concatenate 'string file "." type)))
403 (unless (member version '(nil :newest :wild :unspecific))
404 (/noshow0 "tweaking FILE for more-or-less-:WILD case")
405 (setf file (concatenate 'string file "."
406 (quick-integer-to-string version))))
407 (/noshow0 "finished possibly tweaking FILE")
408 (when (or (not verify-existence)
409 (sb!unix:unix-file-kind file t))
410 (/noshow0 "calling FUNCTION on FILE")
411 (funcall function file)))))))
413 (/noshow0 "filesys.lisp 603")
415 ;;; FIXME: Why do we need this?
416 (defun quick-integer-to-string (n)
417 (declare (type integer n))
418 (cond ((not (fixnump n))
419 (write-to-string n :base 10 :radix nil))
423 (concatenate 'simple-base-string "-"
424 (the simple-base-string (quick-integer-to-string (- n)))))
426 (do* ((len (1+ (truncate (integer-length n) 3)))
427 (res (make-string len :element-type 'base-char))
433 (replace res res :start2 i :end2 len)
434 (%shrink-vector res (- len i)))
435 (declare (simple-string res)
437 (multiple-value-setq (q r) (truncate q 10))
438 (setf (schar res i) (schar "0123456789" r))))))
442 (defun empty-relative-pathname-spec-p (x)
445 (or (equal (pathname-directory x) '(:relative))
446 ;; KLUDGE: I'm not sure this second check should really
447 ;; have to be here. But on sbcl-0.6.12.7,
448 ;; (PATHNAME-DIRECTORY (PATHNAME "")) is NIL, and
449 ;; (PATHNAME "") seems to act like an empty relative
450 ;; pathname, so in order to work with that, I test
451 ;; for NIL here. -- WHN 2001-05-18
452 (null (pathname-directory x)))
453 (null (pathname-name x))
454 (null (pathname-type x)))
455 ;; (The ANSI definition of "pathname specifier" has
456 ;; other cases, but none of them seem to admit the possibility
457 ;; of being empty and relative.)
460 ;;; Convert PATHNAME into a string that can be used with UNIX system
461 ;;; calls, or return NIL if no match is found. Wild-cards are expanded.
463 ;;; FIXME: apart from the error checking (for wildness and for
464 ;;; existence) and conversion to physical pathanme, this is redundant
465 ;;; with UNPARSE-NATIVE-UNIX-NAMESTRING; one should probably be
466 ;;; written in terms of the other.
468 ;;; FIXME: actually this (I think) works not just for Unix.
469 (defun unix-namestring (pathname-spec &optional (for-input t))
470 (let* ((namestring (physicalize-pathname (merge-pathnames pathname-spec)))
471 (matches nil)) ; an accumulator for actual matches
472 (when (wild-pathname-p namestring)
473 (error 'simple-file-error
475 :format-control "bad place for a wild pathname"))
476 (!enumerate-matches (match namestring nil :verify-existence for-input)
477 (push match matches))
478 (case (length matches)
481 (t (bug "!ENUMERATE-MATCHES returned more than one match on a non-wild pathname")))))
483 ;;;; TRUENAME, PROBE-FILE, FILE-AUTHOR, FILE-WRITE-DATE.
485 ;;; Rewritten in 12/2007 by RMK, replacing 13+ year old CMU code that
486 ;;; made a mess of things in order to support search lists (which SBCL
487 ;;; has never had). These are now all relatively straightforward
488 ;;; wrappers around stat(2) and realpath(2), with the same basic logic
489 ;;; in all cases. The wrinkles to be aware of:
491 ;;; * SBCL defines the truename of an existing, dangling or
492 ;;; self-referring symlink to be the symlink itself.
493 ;;; * The old version of PROBE-FILE merged the pathspec against
494 ;;; *DEFAULT-PATHNAME-DEFAULTS* twice, and so lost when *D-P-D*
495 ;;; was a relative pathname. Even if the case where *D-P-D* is a
496 ;;; relative pathname is problematic, there's no particular reason
497 ;;; to get that wrong, so let's try not to.
498 ;;; * Note that while stat(2) is probably atomic, getting the truename
499 ;;; for a filename involves poking all over the place, and so is
500 ;;; subject to race conditions if other programs mutate the file
501 ;;; system while we're resolving symlinks. So it's not implausible for
502 ;;; realpath(3) to fail even if stat(2) succeeded. There's nothing
503 ;;; obvious we can do about this, however.
504 ;;; * Windows' apparent analogue of realpath(3) is called
505 ;;; GetFullPathName, and it's a bit less useful than realpath(3).
506 ;;; In particular, while realpath(3) errors in case the file doesn't
507 ;;; exist, GetFullPathName seems to return a filename in all cases.
508 ;;; As realpath(3) is not atomic anyway, we only ever call it when
509 ;;; we think a file exists, so just be careful when rewriting this
512 ;;; Given a pathname designator, some quality to query for, return one
513 ;;; of a pathname, a universal time, or a string (a file-author), or
514 ;;; NIL. QUERY-FOR may be one of :TRUENAME, :EXISTENCE, :WRITE-DATE,
515 ;;; :AUTHOR. If ERRORP is false, return NIL in case the file system
516 ;;; returns an error code; otherwise, signal an error. Accepts
517 ;;; logical pathnames, too (but never returns LPNs). For internal
519 (defun query-file-system (pathspec query-for &optional (errorp t))
520 (let ((pathname (translate-logical-pathname
523 (sane-default-pathname-defaults)))))
524 (when (wild-pathname-p pathname)
525 (error 'simple-file-error
527 :format-control "~@<can't find the ~A of wild pathname ~A~
528 (physicalized from ~A).~:>"
529 :format-arguments (list query-for pathname pathspec)))
530 (flet ((fail (note-format pathname errno)
532 (simple-file-perror note-format pathname errno)
533 (return-from query-file-system nil))))
534 (let ((filename (native-namestring pathname :as-file t)))
535 (multiple-value-bind (existsp errno ino mode nlink uid gid rdev size
537 (sb!unix:unix-stat filename)
538 (declare (ignore ino nlink gid rdev size atime))
541 (:existence (nth-value
543 (parse-native-namestring
545 (pathname-host pathname)
546 (sane-default-pathname-defaults)
547 :as-directory (eql (logand mode sb!unix:s-ifmt)
549 (:truename (nth-value
551 (parse-native-namestring
552 ;; Note: in case the file is stat'able, POSIX
553 ;; realpath(3) gets us a canonical absolute
554 ;; filename, even if the post-merge PATHNAME
555 ;; is not absolute...
556 (multiple-value-bind (realpath errno)
557 (sb!unix:unix-realpath filename)
560 (fail "couldn't resolve ~A" filename errno)))
561 (pathname-host pathname)
562 (sane-default-pathname-defaults)
563 ;; ... but without any trailing slash.
564 :as-directory (eql (logand mode sb!unix:s-ifmt)
566 (:author (sb!unix:uid-username uid))
567 (:write-date (+ unix-to-universal-time mtime)))
569 ;; SBCL has for many years had a policy that a pathname
570 ;; that names an existing, dangling or self-referential
571 ;; symlink denotes the symlink itself. stat(2) fails
572 ;; and sets errno to ENOENT or ELOOP respectively, but
573 ;; we must distinguish cases where the symlink exists
574 ;; from ones where there's a loop in the apparent
575 ;; containing directory.
577 (multiple-value-bind (linkp ignore ino mode nlink uid gid rdev
579 (sb!unix:unix-lstat filename)
580 (declare (ignore ignore ino mode nlink gid rdev size atime))
581 (when (and (or (= errno sb!unix:enoent)
582 (= errno sb!unix:eloop))
584 (return-from query-file-system
587 ;; We do this reparse so as to return a
588 ;; normalized pathname.
589 (parse-native-namestring
590 filename (pathname-host pathname)))
592 ;; So here's a trick: since lstat succeded,
593 ;; FILENAME exists, so its directory exists and
594 ;; only the non-directory part is loopy. So
595 ;; let's resolve FILENAME's directory part with
596 ;; realpath(3), in order to get a canonical
597 ;; absolute name for the directory, and then
598 ;; return a pathname having PATHNAME's name,
599 ;; type, and version, but the rest from the
600 ;; truename of the directory. Since we turned
601 ;; PATHNAME into FILENAME "as a file", FILENAME
602 ;; does not end in a slash, and so we get the
603 ;; directory part of FILENAME by reparsing
604 ;; FILENAME and masking off its name, type, and
605 ;; version bits. But note not to call ourselves
606 ;; recursively, because we don't want to
607 ;; re-merge against *DEFAULT-PATHNAME-DEFAULTS*,
608 ;; since PATHNAME may be a relative pathname.
612 (parse-native-namestring
613 (multiple-value-bind (realpath errno)
614 (sb!unix:unix-realpath
620 :defaults (parse-native-namestring
622 (pathname-host pathname)
623 (sane-default-pathname-defaults)))))
626 (fail "couldn't resolve ~A" filename errno)))
627 (pathname-host pathname)
628 (sane-default-pathname-defaults)
631 (:author (sb!unix:uid-username uid))
632 (:write-date (+ unix-to-universal-time mtime))))))
633 ;; If we're still here, the file doesn't exist; error.
635 (format nil "failed to find the ~A of ~~A" query-for)
636 pathspec errno))))))))
639 (defun probe-file (pathspec)
641 "Return the truename of PATHSPEC if the truename can be found,
642 or NIL otherwise. See TRUENAME for more information."
643 (query-file-system pathspec :truename nil))
645 (defun truename (pathspec)
647 "If PATHSPEC is a pathname that names an existing file, return
648 a pathname that denotes a canonicalized name for the file. If
649 pathspec is a stream associated with a file, return a pathname
650 that denotes a canonicalized name for the file associated with
653 An error of type FILE-ERROR is signalled if no such file exists
654 or if the file system is such that a canonicalized file name
655 cannot be determined or if the pathname is wild.
657 Under Unix, the TRUENAME of a symlink that links to itself or to
658 a file that doesn't exist is considered to be the name of the
659 broken symlink itself."
660 ;; Note that eventually this routine might be different for streams
661 ;; than for other pathname designators.
662 (if (streamp pathspec)
663 (query-file-system pathspec :truename)
664 (query-file-system pathspec :truename)))
666 (defun file-author (pathspec)
668 "Return the author of the file specified by PATHSPEC. Signal an
669 error of type FILE-ERROR if no such file exists, or if PATHSPEC
671 (query-file-system pathspec :author))
673 (defun file-write-date (pathspec)
675 "Return the write date of the file specified by PATHSPEC.
676 An error of type FILE-ERROR is signaled if no such file exists,
677 or if PATHSPEC is a wild pathname."
678 (query-file-system pathspec :write-date))
680 ;;;; miscellaneous other operations
682 (/show0 "filesys.lisp 700")
684 (defun rename-file (file new-name)
686 "Rename FILE to have the specified NEW-NAME. If FILE is a stream open to a
687 file, then the associated file is renamed."
688 (let* ((original (truename file))
689 (original-namestring (unix-namestring original t))
690 (new-name (merge-pathnames new-name original))
691 (new-namestring (unix-namestring new-name nil)))
692 (unless new-namestring
693 (error 'simple-file-error
695 :format-control "~S can't be created."
696 :format-arguments (list new-name)))
697 (multiple-value-bind (res error)
698 (sb!unix:unix-rename original-namestring new-namestring)
700 (error 'simple-file-error
702 :format-control "~@<couldn't rename ~2I~_~A ~I~_to ~2I~_~A: ~
704 :format-arguments (list original new-name (strerror error))))
706 (file-name file new-name))
707 (values new-name original (truename new-name)))))
709 (defun delete-file (file)
711 "Delete the specified FILE."
712 (let ((namestring (unix-namestring file t)))
714 (close file :abort t))
716 (error 'simple-file-error
718 :format-control "~S doesn't exist."
719 :format-arguments (list file)))
720 (multiple-value-bind (res err) (sb!unix:unix-unlink namestring)
722 (simple-file-perror "couldn't delete ~A" namestring err))))
725 (defun sbcl-homedir-pathname ()
726 (let ((sbcl-home (posix-getenv "SBCL_HOME")))
727 ;; SBCL_HOME isn't set for :EXECUTABLE T embedded cores
728 (when (and sbcl-home (not (string= sbcl-home "")))
729 (parse-native-namestring sbcl-home
730 #!-win32 sb!impl::*unix-host*
731 #!+win32 sb!impl::*win32-host*
732 *default-pathname-defaults*
735 ;;; (This is an ANSI Common Lisp function.)
736 (defun user-homedir-pathname (&optional host)
738 "Return the home directory of the user as a pathname. If the HOME
739 environment variable has been specified, the directory it designates
740 is returned; otherwise obtains the home directory from the operating
742 (declare (ignore host))
743 (let ((env-home (posix-getenv "HOME")))
745 (parse-native-namestring
746 (if (and env-home (not (string= env-home "")))
749 (sb!unix:uid-homedir (sb!unix:unix-getuid))
751 ;; Needs to bypass PARSE-NATIVE-NAMESTRING & ENSURE-TRAILING-SLASH
752 ;; What?! -- RMK, 2007-12-31
753 (return-from user-homedir-pathname
754 (sb!win32::get-folder-pathname sb!win32::csidl_profile)))
755 #!-win32 sb!impl::*unix-host*
756 #!+win32 sb!impl::*win32-host*
757 *default-pathname-defaults*
763 (/show0 "filesys.lisp 800")
765 ;;; NOTE: There is a fair amount of hair below that is probably not
766 ;;; strictly necessary.
768 ;;; The issue is the following: what does (DIRECTORY "SYS:*;") mean?
769 ;;; Until 2004-01, SBCL's behaviour was unquestionably wrong, as it
770 ;;; did not translate the logical pathname at all, but instead treated
771 ;;; it as a physical one. Other Lisps seem to to treat this call as
772 ;;; equivalent to (DIRECTORY (TRANSLATE-LOGICAL-PATHNAME "SYS:*;")),
773 ;;; which is fine as far as it goes, but not very interesting, and
774 ;;; arguably counterintuitive. (PATHNAME-MATCH-P "SYS:SRC;" "SYS:*;")
775 ;;; is true, so why should "SYS:SRC;" not show up in the call to
776 ;;; DIRECTORY? (assuming the physical pathname corresponding to it
777 ;;; exists, of course).
779 ;;; So, the interpretation that I am pushing is for all pathnames
780 ;;; matching the input pathname to be queried. This means that we
781 ;;; need to compute the intersection of the input pathname and the
782 ;;; logical host FROM translations, and then translate the resulting
783 ;;; pathname using the host to the TO translation; this treatment is
784 ;;; recursively invoked until we get a physical pathname, whereupon
785 ;;; our physical DIRECTORY implementation takes over.
787 ;;; FIXME: this is an incomplete implementation. It only works when
788 ;;; both are logical pathnames (which is OK, because that's the only
789 ;;; case when we call it), but there are other pitfalls as well: see
790 ;;; the DIRECTORY-HELPER below for some, but others include a lack of
791 ;;; pattern handling.
793 ;;; The above was written by CSR, I (RMK) believe. The argument that
794 ;;; motivates the interpretation is faulty, however: PATHNAME-MATCH-P
795 ;;; returns true for (PATHNAME-MATCH-P #P"/tmp/*/" #P"/tmp/../"), but
796 ;;; the latter pathname is not in the result of DIRECTORY on the
797 ;;; former. Indeed, if DIRECTORY were constrained to return the
798 ;;; truename for every pathname for which PATHNAME-MATCH-P returned
799 ;;; true and which denoted a filename that named an existing file,
800 ;;; (DIRECTORY #P"/tmp/**/") would be required to list every file on a
801 ;;; Unix system, since any file can be named as though it were "below"
802 ;;; /tmp, given the dotdot entries. So I think the strongest
803 ;;; "consistency" we can define between PATHNAME-MATCH-P and DIRECTORY
804 ;;; is that PATHNAME-MATCH-P returns true of everything DIRECTORY
805 ;;; returns, but not vice versa.
807 ;;; In any case, even if the motivation were sound, DIRECTORY on a
808 ;;; wild logical pathname has no portable semantics. I see nothing in
809 ;;; ANSI that requires implementations to support wild physical
810 ;;; pathnames, and so there need not be any translation of a wild
811 ;;; logical pathname to a phyiscal pathname. So a program that calls
812 ;;; DIRECTORY on a wild logical pathname is doing something
813 ;;; non-portable at best. And if the only sensible semantics for
814 ;;; DIRECTORY on a wild logical pathname is something like the
815 ;;; following, it would be just as well if it signaled an error, since
816 ;;; a program can't possibly rely on the result of an intersection of
817 ;;; user-defined translations with a file system probe. (Potentially
818 ;;; useful kinds of "pathname" that might not support wildcards could
819 ;;; include pathname hosts that model unqueryable namespaces like HTTP
820 ;;; URIs, or that model namespaces that it's not convenient to
821 ;;; investigate, such as the namespace of TCP ports that some network
822 ;;; host listens on. I happen to think it a bad idea to try to
823 ;;; shoehorn such namespaces into a pathnames system, but people
824 ;;; sometimes claim to want pathnames for these things.) -- RMK
827 (defun pathname-intersections (one two)
828 (aver (logical-pathname-p one))
829 (aver (logical-pathname-p two))
831 ((intersect-version (one two)
832 (aver (typep one '(or null (member :newest :wild :unspecific)
834 (aver (typep two '(or null (member :newest :wild :unspecific)
839 ((or (null one) (eq one :unspecific)) two)
840 ((or (null two) (eq two :unspecific)) one)
843 (intersect-name/type (one two)
844 (aver (typep one '(or null (member :wild :unspecific) string)))
845 (aver (typep two '(or null (member :wild :unspecific) string)))
849 ((or (null one) (eq one :unspecific)) two)
850 ((or (null two) (eq two :unspecific)) one)
851 ((string= one two) one)
853 (intersect-directory (one two)
854 (aver (typep one '(or null (member :wild :unspecific) list)))
855 (aver (typep two '(or null (member :wild :unspecific) list)))
859 ((or (null one) (eq one :unspecific)) two)
860 ((or (null two) (eq two :unspecific)) one)
861 (t (aver (eq (car one) (car two)))
863 (lambda (x) (cons (car one) x))
864 (intersect-directory-helper (cdr one) (cdr two)))))))
865 (let ((version (intersect-version
866 (pathname-version one) (pathname-version two)))
867 (name (intersect-name/type
868 (pathname-name one) (pathname-name two)))
869 (type (intersect-name/type
870 (pathname-type one) (pathname-type two)))
871 (host (pathname-host one)))
873 (make-pathname :host host :name name :type type
874 :version version :directory d))
876 (pathname-directory one) (pathname-directory two))))))
878 ;;; FIXME: written as its own function because I (CSR) don't
879 ;;; understand it, so helping both debuggability and modularity. In
880 ;;; case anyone is motivated to rewrite it, it returns a list of
881 ;;; sublists representing the intersection of the two input directory
882 ;;; paths (excluding the initial :ABSOLUTE or :RELATIVE).
884 ;;; FIXME: Does not work with :UP or :BACK
885 ;;; FIXME: Does not work with patterns
887 ;;; FIXME: PFD suggests replacing this implementation with a DFA
888 ;;; conversion of a NDFA. Find out (a) what this means and (b) if it
889 ;;; turns out to be worth it.
890 (defun intersect-directory-helper (one two)
891 (flet ((simple-intersection (cone ctwo)
893 ((eq cone :wild) ctwo)
894 ((eq ctwo :wild) cone)
895 (t (aver (typep cone 'string))
896 (aver (typep ctwo 'string))
897 (if (string= cone ctwo) cone nil)))))
899 ((loop-possible-wild-inferiors-matches
900 (lower-bound bounding-sequence order)
901 (let ((index (gensym)) (g2 (gensym)) (g3 (gensym)) (l (gensym)))
902 `(let ((,l (length ,bounding-sequence)))
903 (loop for ,index from ,lower-bound to ,l
904 append (mapcar (lambda (,g2)
906 (butlast ,bounding-sequence (- ,l ,index))
911 (if (eq (car (nthcdr ,index ,bounding-sequence))
915 (intersect-directory-helper
917 `((nthcdr ,index one) (cdr two))
918 `((cdr one) (nthcdr ,index two)))))))))))
920 ((and (eq (car one) :wild-inferiors)
921 (eq (car two) :wild-inferiors))
923 (append (mapcar (lambda (x) (cons :wild-inferiors x))
924 (intersect-directory-helper (cdr one) (cdr two)))
925 (loop-possible-wild-inferiors-matches 2 one t)
926 (loop-possible-wild-inferiors-matches 2 two nil))
928 ((eq (car one) :wild-inferiors)
929 (delete-duplicates (loop-possible-wild-inferiors-matches 0 two nil)
931 ((eq (car two) :wild-inferiors)
932 (delete-duplicates (loop-possible-wild-inferiors-matches 0 one t)
934 ((and (null one) (null two)) (list nil))
937 (t (and (simple-intersection (car one) (car two))
938 (mapcar (lambda (x) (cons (simple-intersection
939 (car one) (car two)) x))
940 (intersect-directory-helper (cdr one) (cdr two)))))))))
942 (defun directory (pathname &key (resolve-symlinks t))
944 "Return a list of PATHNAMEs, each the TRUENAME of a file that matched the
945 given pathname. Note that the interaction between this ANSI-specified
946 TRUENAMEing and the semantics of the Unix filesystem (symbolic links..)
947 means this function can sometimes return files which don't have the same
948 directory as PATHNAME. If :RESOLVE-SYMLINKS is NIL, don't resolve
949 symbolic links in matching filenames."
950 (let (;; We create one entry in this hash table for each truename,
951 ;; as an asymptotically efficient way of removing duplicates
952 ;; (which can arise when e.g. multiple symlinks map to the
954 (filenames (make-hash-table :test #'equal))
955 ;; FIXME: Possibly this MERGE-PATHNAMES call should only
956 ;; happen once we get a physical pathname.
957 (merged-pathname (merge-pathnames pathname)))
958 (labels ((do-physical-directory (pathname)
959 (aver (not (logical-pathname-p pathname)))
960 (!enumerate-matches (match pathname)
961 (let* ((*ignore-wildcards* t)
962 ;; FIXME: Why not TRUENAME? As reported by
963 ;; Milan Zamazal sbcl-devel 2003-10-05, using
964 ;; TRUENAME causes a race condition whereby
965 ;; removal of a file during the directory
966 ;; operation causes an error. It's not clear
967 ;; what the right thing to do is, though. --
969 (filename (if resolve-symlinks
970 (query-file-system match :truename nil)
971 (query-file-system match :existence nil))))
973 (setf (gethash (namestring filename) filenames)
975 (do-directory (pathname)
976 (if (logical-pathname-p pathname)
977 (let ((host (intern-logical-host (pathname-host pathname))))
978 (dolist (x (logical-host-canon-transls host))
979 (destructuring-bind (from to) x
981 (pathname-intersections pathname from)))
982 (dolist (p intersections)
983 (do-directory (translate-pathname p from to)))))))
984 (do-physical-directory pathname))))
985 (do-directory merged-pathname))
987 ;; Sorting isn't required by the ANSI spec, but sorting
988 ;; into some canonical order seems good just on the
989 ;; grounds that the implementation should have repeatable
990 ;; behavior when possible.
991 (sort (loop for name being each hash-key in filenames
992 using (hash-value filename)
993 collect (cons name filename))
997 (/show0 "filesys.lisp 899")
999 ;;; predicate to order pathnames by; goes by name
1000 ;; FIXME: Does anything use this? It's not exported, and I don't find
1001 ;; the name anywhere else.
1002 (defun pathname-order (x y)
1003 (let ((xn (%pathname-name x))
1004 (yn (%pathname-name y)))
1006 (let ((res (string-lessp xn yn)))
1007 (cond ((not res) nil)
1008 ((= res (length (the simple-string xn))) t)
1009 ((= res (length (the simple-string yn))) nil)
1013 (defun ensure-directories-exist (pathspec &key verbose (mode #o777))
1015 "Test whether the directories containing the specified file
1016 actually exist, and attempt to create them if they do not.
1017 The MODE argument is a CMUCL/SBCL-specific extension to control
1018 the Unix permission bits."
1019 (let ((pathname (physicalize-pathname (merge-pathnames (pathname pathspec))))
1021 (when (wild-pathname-p pathname)
1022 (error 'simple-file-error
1023 :format-control "bad place for a wild pathname"
1024 :pathname pathspec))
1025 (let ((dir (pathname-directory pathname)))
1026 (loop for i from 1 upto (length dir)
1027 do (let ((newpath (make-pathname
1028 :host (pathname-host pathname)
1029 :device (pathname-device pathname)
1030 :directory (subseq dir 0 i))))
1031 (unless (probe-file newpath)
1032 (let ((namestring (coerce (native-namestring newpath)
1035 (format *standard-output*
1036 "~&creating directory: ~A~%"
1038 (sb!unix:unix-mkdir namestring mode)
1039 (unless (probe-file newpath)
1040 (restart-case (error
1044 "can't create directory ~A"
1045 :format-arguments (list namestring))
1047 :report "Retry directory creation."
1048 (ensure-directories-exist
1050 :verbose verbose :mode mode))
1053 "Continue as if directory creation was successful."
1055 (setf created-p t)))))
1056 (values pathspec created-p))))
1058 (/show0 "filesys.lisp 1000")