fix documented contracts for path functions

and make `cleanse-path' work for any platform's paths
  while fixing `resolve-path' checking to disallow paths
  for other platforms
 Closes PR 11891
This commit is contained in:
Matthew Flatt 2011-05-04 11:11:40 -06:00
parent 5e7d1f2d9c
commit 34b8dc249e
3 changed files with 55 additions and 43 deletions

View File

@ -103,7 +103,7 @@ the conversion of Windows paths.
See also @racket[some-system-path->string].}
@defproc[(path->bytes [path path?]) bytes?]{
@defproc[(path->bytes [path path-for-some-system?]) bytes?]{
Produces @racket[path]'s byte string representation. No information is
lost in this translation, so that @racket[(bytes->path (path->bytes
@ -138,7 +138,7 @@ As for @racket[path->string], information can be lost from
@defproc[(bytes->path-element [bstr bytes?]
[type (or/c 'unix 'windows) (system-path-convention-type)])
path?]{
path-for-some-system?]{
Like @racket[bytes->path], except that @racket[bstr] corresponds to a
single relative element in a path. In terms of conversions and
@ -186,7 +186,7 @@ reassembling the result with @racket[bytes->path-element] and
@racket[build-path]).}
@defproc[(path-convention-type [path path?])
@defproc[(path-convention-type [path path-for-some-system?])
(or/c 'unix 'windows)]{
Accepts a path value (not a string) and returns its convention
@ -201,11 +201,11 @@ Returns the path convention type of the current platform:
Windows.}
@defproc[(build-path [base (or/c path-string? 'up 'same)]
[sub (or/c (and/c path-string?
@defproc[(build-path [base (or/c path-string? path-for-some-system? 'up 'same)]
[sub (or/c (and/c (or/c path-string? path-for-some-system?)
(not/c complete-path?))
(or/c 'up 'same))] ...)
path?]{
path-for-some-system?]{
Creates a path given a base path and any number of sub-path
extensions. If @racket[base] is an absolute path, the result is an
@ -219,7 +219,7 @@ drive specification (with or without a trailing slash) the first
@racket[sub] can be an absolute (driveless) path. For all platforms,
the last @racket[sub] can be a filename.
The @racket[base] and @racket[sub-paths] arguments can be paths for
The @racket[base] and @racket[sub] arguments can be paths for
any platform. The platform for the resulting path is inferred from the
@racket[base] and @racket[sub] arguments, where string arguments imply
a path for the current platform. If different arguments are for
@ -261,15 +261,18 @@ Windows examples.
]}
@defproc[(build-path/convention-type [type (or/c 'unix 'windows)]
[base path-string?]
[sub (or/c path-string? 'up 'same)] ...)
path?]{
@defproc[(build-path/convention-type
[type (or/c 'unix 'windows)]
[base (or/c path-string? path-for-some-system? 'up 'same)]
[sub (or/c (and/c (or/c path-string? path-for-some-system?)
(not/c complete-path?))
(or/c 'up 'same))] ...)
path-for-some-system?]{
Like @racket[build-path], except a path convention type is specified
explicitly.}
@defproc[(absolute-path? [path path-string?]) boolean?]{
@defproc[(absolute-path? [path (or/c path-string? path-for-some-system?)]) boolean?]{
Returns @racket[#t] if @racket[path] is an absolute path, @racket[#f]
otherwise. The @racket[path] argument can be a path for any
@ -278,7 +281,7 @@ contains a nul character), @racket[#f] is returned. This procedure
does not access the filesystem.}
@defproc[(relative-path? [path path-string?]) boolean?]{
@defproc[(relative-path? [path (or/c path-string? path-for-some-system?)]) boolean?]{
Returns @racket[#t] if @racket[path] is a relative path, @racket[#f]
otherwise. The @racket[path] argument can be a path for any
@ -287,7 +290,7 @@ contains a nul character), @racket[#f] is returned. This procedure
does not access the filesystem.}
@defproc[(complete-path? [path path-string?]) boolean?]{
@defproc[(complete-path? [path (or/c path-string? path-for-some-system?)]) boolean?]{
Returns @racket[#t] if @racket[path] is a completely determined path
(@italic{not} relative to a directory or drive), @racket[#f]
@ -300,9 +303,9 @@ contains a nul character), @racket[#f] is returned.
This procedure does not access the filesystem.}
@defproc[(path->complete-path [path path-string?]
[base path-string? (current-directory)])
path?]{
@defproc[(path->complete-path [path (or/c path-string? path-for-some-system?)]
[base (or/c path-string? path-for-some-system?) (current-directory)])
path-for-some-system?]{
Returns @racket[path] as a complete path. If @racket[path] is already
a complete path, it is returned as the result. Otherwise,
@ -317,7 +320,8 @@ platforms, the @exnraise[exn:fail:contract].
This procedure does not access the filesystem.}
@defproc[(path->directory-path [path path-string?]) path?]{
@defproc[(path->directory-path [path (or/c path-string? path-for-some-system?)])
path-for-some-system?]{
Returns @racket[path] if @racket[path] syntactically refers to a
directory and ends in a separator, otherwise it returns an extended
@ -341,13 +345,14 @@ owning @racket[path]), otherwise @racket[path] is returned (after
expansion).}
@defproc[(cleanse-path [path path-string?]) path]{
@defproc[(cleanse-path [path (or/c path-string? path-for-some-system?)])
path-for-some-system?]{
@techlink{Cleanse}s @racket[path] (as described at the beginning of
this chapter) without consulting the filesystem.}
@defproc[(expand-user-path [path path-string?]) path]{
@defproc[(expand-user-path [path path-string?]) path?]{
@techlink{Cleanse}s @racket[path]. In addition, under @|AllUnix|, a
leading @litchar{~} is treated as user's home directory and expanded;
@ -356,7 +361,9 @@ of the path), where @litchar{~} by itself indicates the home directory
of the current user.}
@defproc[(simplify-path [path path-string?] [use-filesystem? boolean? #t]) path?]{
@defproc[(simplify-path [path (or/c path-string? path-for-some-system?)]
[use-filesystem? boolean? #t])
path-for-some-system?]{
Eliminates redundant path separators (except for a single trailing
separator), up-directory @litchar{..}, and same-directory @litchar{.}
@ -364,7 +371,7 @@ indicators in @racket[path], and changes @litchar{/} separators to
@litchar{\} separators in Windows paths, such that the result
accesses the same file or directory (if it exists) as @racket[path].
In general, the pathname is normalized as much as possible --- without
In general, the pathname is normalized as much as possible---without
consulting the filesystem if @racket[use-filesystem?] is @racket[#f],
and (under Windows) without changing the case of letters within the
path. If @racket[path] syntactically refers to a directory, the
@ -401,7 +408,8 @@ See @secref["unixpaths"] for more information on simplifying
information on simplifying Windows paths.}
@defproc[(normal-case-path [path path-string?]) path?]{
@defproc[(normal-case-path [path (or/c path-string? path-for-some-system?)])
path-for-some-system?]{
Returns @racket[path] with ``normalized'' case letters. For @|AllUnix|
paths, this procedure always returns the input path, because
@ -419,9 +427,9 @@ different on the current platform than for the path's platform.
This procedure does not access the filesystem.}
@defproc[(split-path [path path-string?])
(values (or/c path? 'relative #f)
(or/c path? 'up 'same)
@defproc[(split-path [path (or/c path-string? path-for-some-system?)])
(values (or/c path-for-some-system? 'relative #f)
(or/c path-for-some-system? 'up 'same)
boolean?)]{
Deconstructs @racket[path] into a smaller path and an immediate
@ -469,9 +477,9 @@ See @secref["unixpaths"] for more information on splitting
information on splitting Windows paths.}
@defproc[(path-replace-suffix [path path-string?]
@defproc[(path-replace-suffix [path (or/c path-string? path-for-some-system?)]
[suffix (or/c string? bytes?)])
path?]{
path-for-some-system?]{
Returns a path that is the same as @racket[path], except that the
suffix for the last element of the path is changed to
@ -483,9 +491,9 @@ at the end of the path element, as long as the path element is not
path for any platform, and the result is for the same platform. If
@racket[path] represents a root, the @exnraise[exn:fail:contract].}
@defproc[(path-add-suffix [path path-string?]
@defproc[(path-add-suffix [path (or/c path-string? path-for-some-system?)]
[suffix (or/c string? bytes?)])
path?]{
path-for-some-system?]{
Similar to @racket[path-replace-suffix], but any existing suffix on
@racket[path] is preserved by replacing every @litchar{.} in the last

View File

@ -674,9 +674,8 @@
(test (string->path "\\\\?\\RED\\..\\..") normal-case-path (coerce "\\\\?\\RED\\..\\.."))
;; cleanse-path removes redundant backslashes
(when (eq? 'windows (system-type))
(test (string->path "\\\\?\\\\UNC\\x\\y") cleanse-path (coerce "\\\\?\\\\UNC\\x\\y"))
(test (string->path "\\\\?\\c:\\") cleanse-path (coerce "\\\\?\\c:\\\\")))
(test (string->path "\\\\?\\\\UNC\\x\\y") cleanse-path (coerce "\\\\?\\\\UNC\\x\\y"))
(test (string->path "\\\\?\\c:\\") cleanse-path (coerce "\\\\?\\c:\\\\"))
;; cleanse-path removes redundant backslashes, and
;; simplify-path uses cleanse-path under Windows:
@ -690,9 +689,9 @@
(test (string->path "\\\\?\\UNC\\a\\b\\.") cleanse-path (coerce "\\\\?\\UNC\\\\a\\b\\\\."))
(test (string->path "\\\\?\\RED\\\\..") cleanse-path (coerce "\\\\?\\RED\\.."))
(test (string->path "\\\\?\\") cleanse-path (coerce "\\\\?\\\\")))])
(go cleanse-path)
(test (string->path "\\\\?\\c:") cleanse-path (coerce "\\\\?\\c:"))
(when (eq? 'windows (system-type))
(go cleanse-path)
(test (string->path "\\\\?\\c:") cleanse-path (coerce "\\\\?\\c:"))
(go simplify-path))
(go (lambda (p) (simplify-path p #f)))
(test (string->path "a\\b") simplify-path (coerce "a/b") #f)

View File

@ -4018,8 +4018,8 @@ static Scheme_Object *resolve_path(int argc, Scheme_Object *argv[])
char *filename;
int expanded;
if (!SCHEME_GENERAL_PATH_STRINGP(argv[0]))
scheme_wrong_type("resolve-path", SCHEME_GENERAL_PATH_STRING_STR, 0, argc, argv);
if (!SCHEME_PATH_STRINGP(argv[0]))
scheme_wrong_type("resolve-path", SCHEME_PATH_STRING_STR, 0, argc, argv);
filename = do_expand_filename(argv[0],
NULL,
@ -4669,10 +4669,15 @@ static Scheme_Object *current_drive(int argc, Scheme_Object *argv[])
static Scheme_Object *cleanse_path(int argc, Scheme_Object *argv[])
{
char *filename;
int expanded;
int expanded, kind;
if (!SCHEME_PATH_STRINGP(argv[0]))
scheme_wrong_type("cleanse-path", SCHEME_PATH_STRING_STR, 0, argc, argv);
if (!SCHEME_GENERAL_PATH_STRINGP(argv[0]))
scheme_wrong_type("cleanse-path", SCHEME_GENERAL_PATH_STRING_STR, 0, argc, argv);
if (SCHEME_GENERAL_PATHP(argv[0]))
kind = SCHEME_PATH_KIND(argv[0]);
else
kind = SCHEME_PLATFORM_PATH_KIND;
filename = do_expand_filename(argv[0],
NULL,
@ -4681,13 +4686,13 @@ static Scheme_Object *cleanse_path(int argc, Scheme_Object *argv[])
&expanded,
1, 0,
0, /* no security check, since the filesystem is not used */
SCHEME_PLATFORM_PATH_KIND,
kind,
0);
if (!expanded && SCHEME_PATHP(argv[0]))
if (!expanded && SCHEME_GENERAL_PATHP(argv[0]))
return argv[0];
else
return scheme_make_sized_path(filename, strlen(filename), 1);
return scheme_make_sized_offset_kind_path(filename, 0, strlen(filename), 1, kind);
}
static Scheme_Object *expand_user_path(int argc, Scheme_Object *argv[])