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")