#
Chapter 18
`file.ss`: Filesystem Utilities

To load: `(require (lib "file.ss"))`

See also section 11.3 in PLT MzScheme: Language Manual.

`(build-absolute-path``` `base path``` `···``)` PROCEDURE

Like `build-path` (see section 11.3 in PLT MzScheme: Language Manual), but `base` is required to be an absolute pathname. If `base` is not an absolute pathname, `error` is called.

`(build-relative-path``` `base path``` `···``)` PROCEDURE

Like `build-path` (see section 11.3 in PLT MzScheme: Language Manual), but `base` is required to be a relative pathname. If `base` is not a relative pathname, `error` is called.

`(call-with-input-file*``` `pathname proc flag-symbol``` `···``)` PROCEDURE

Like ``call-with-input-file``, except that the opened port is closed if control escapes from the body of `proc`.

`(call-with-output-file*``` `pathname proc flag-symbol``` `···``)` PROCEDURE

Like ``call-with-output-file``, except that the opened port is closed if control escapes from the body of `proc`.

`(copy-directory/files``` `src-path dest-path``)` PROCEDURE

Copies the file or directory `src-path` to `dest-path`, raising `exn:fail:filesystem` if the file or directory cannot be copied, possibly because `dest-path` exists already. If `src-path` is a directory, the copy applies recursively to the directory's content. If a source is a link, the target of the link is copied rather than the link itself.

`(delete-directory/files``` `path``)` PROCEDURE

Deletes the file or directory specified by `path`, raising `exn:fail:filesystem` if the file or directory cannot be deleted. If `path` is a directory, then `delete-directory/files` is first applied to each file and directory in `path` before the directory is deleted. The return value is void.

`(explode-path``` `path``)` PROCEDURE

Returns the list of directories that constitute `path`. The `path` argument must be normalized in the sense of `normalize-path` (see below).

`(file-name-from-path``` `path``)` PROCEDURE

If `path` is a file pathname, returns just the file name part without the directory path.

`(filename-extension``` `path``)` PROCEDURE

Returns a byte string that is the extension part of the filename in `path`. If `path` is (syntactically) a directory, `#f` is returned.

`(find-files``` `predicate``` [`start-pathname`]`)` PROCEDURE

Traverses the filesystem starting at `start-pathname` and creates a list of all files and directories for which `predicate` returns true. If `start-pathname` is `#f` (the default), then the traversal starts from the current directory (as determined by ``current-directory``; see section 7.9.1.1 in PLT MzScheme: Language Manual).

The `predicate` procedure is called with a single argument for each file or directory. If `start-pathname` is `#f`, the argument is a pathname string that is relative to the current directory. Otherwise, it is a pathname that starts with `start-pathname`. Consequently, supplying `(`current-directory`)` for `start-pathname` is different from supplying `#f`, because `predicate` receives complete paths in the former case and relative paths in the latter. Another difference is that `predicate` is not called for the current directory when `start-pathname` is `#f`.

The `find-files` traversal follows soft links. To avoid following links, use the more general `fold-files` procedure.

If `start-pathname` does not refer to an existing file or directory, then `predicate` will be called exactly once with `start-pathname` as the argument.

`(find-library``` `name collection``)` PROCEDURE

Returns the path of the specified library (see Chapter 16 in PLT MzScheme: Language Manual), returning `#f` if the specified library or collection cannot be found. The `collection` argument is optional, defaulting to `"mzlib"`.

`(find-relative-path``` `basepath path``)` PROCEDURE

Finds a relative pathname with respect to `basepath` that names the same file or directory as `path`. Both `basepath` and `path` must be normalized in the sense of `normalize-path` (see below). If `path` is not a proper subpath of `basepath` (i.e., a subpath that is strictly longer), `path` is returned.

`(fold-files``` `proc init-val``` [`start-pathname follow-links?`]`)` PROCEDURE

Traverses the filesystem starting at `start-pathname`, calling `proc` on each discovered file, directory, and link. If `start-pathname` is `#f` (the default), then the traversal starts from the current directory (as determined by ``current-directory``; see section 7.9.1.1 in PLT MzScheme: Language Manual).

The `proc` procedure is called with three arguments for each file, directory, or link:

- If `start-pathname` is `#f`, the first argument is a pathname string that is relative to the current directory. Otherwise, the first argument is a pathname that starts with `start-pathname`. Consequently, supplying `(`current-directory`)` for `start-pathname` is different from supplying `#f`, because `proc` receives complete paths in the former case and relative paths in the latter. Another difference is that `proc` is not called for the current directory when `start-pathname` is `#f`.

- The second argument is a symbol, either `'file`, `'dir`, or `'link`. The second argument can be `'link` only when `follow-links?` is `#f`, in which case the filesystem traversal does not follow links. The default for `follow-links?` is `#t`.

- The third argument is the accumulated result. For the first call to `proc`, the third argument is `init-val`. For the second call to `proc` (if any), the third argument is the result from the first call, and so on. The result of the last call to `proc` is the result of `fold-files`.

If `start-pathname` does not refer to an existing file or directory, then `proc` will be called exactly once with `start-pathname` as the first argument, `'file` as the second argument, and `init-val` as the third argument.

`(get-preference``` `name``` [`failure-thunk flush-cache? filename`]`)` PROCEDURE

Extracts a preference value from the file designated by `(`find-system-path` 'pref-file)` (see section 11.3 in PLT MzScheme: Language Manual), or by `filename` if it is provided and is not `#f`. In the former case, if the preference file doesn't exist, `get-preferences` attempts to read a `plt-prefs.ss` file in the `defaults` collection, instead. If neither file exists, the preference set is empty.

The preference file should contain a symbol-keyed association list (written to the file with the default parameter settings). Keys starting with `mzscheme:`, `mred:`, and `plt:` in any letter case are reserved for use by PLT.

The result of `get-preference` is the value associated with `name` if it exists in the association list, or the result of calling `failure-thunk` otherwise. The default `failure-thunk` returns `#f`.

Preference settings from the standard preference file are cached (weakly) across calls to `get-preference`; if `flush-cache?` is provided as `#f`, the cache is used instead of the re-consulting the preferences file.

See also `put-preferences`. The `framework` collection supports a more elaborate preference system; see PLT Framework: GUI Application Framework for details.

`(make-directory*``` `path``)` PROCEDURE

Creates directory specified by `path`, creating intermediate directories as necessary.

`(make-temporary-file``` [`format-string copy-from-filename directory`]`)` PROCEDURE

Creates a new temporary file and returns a pathname string for the file. Instead of merely generating a fresh file name, the file is actually created; this prevents other threads or processes from picking the same temporary name. If `copy-from-filename` is provided as path, the temporary file is created as a copy of the named file (using `copy-file`). If `copy-from-filename` is `#f` or not provided, the temporary file is created as empty. If `directory` is provided and is not `#f`, then the file name generated from `format-string` is combined with `directory` to obtain a full path.

The temporary file is not opened for reading or writing when the pathname is returned. The client program calling `make-temporary-file` is expected to open the file with the desired access and flags (probably using the `'truncate` flag; see section 11.1.3 in PLT MzScheme: Language Manual) and to delete it when it is no longer needed.

If `format-string` is specified, it must be a format string suitable for use with `format` and one additional string argument (where the string contains only digits). If the resulting string is a relative path, it is combined with the result of `(`find-system-path` 'temp-dir)`, unless `directory` is provided and non-`#f`. The default `format-string` is `"mztmp~a"`.

`(normalize-path``` `path wrt``)` PROCEDURE

Returns a normalized, complete version of `path`, expanding the path and resolving all soft links. If `path` is relative, then the pathname `wrt` is used as the base path. The `wrt` argument is optional; if is omitted, then the current directory is used as the base path.

Letter case is not normalized by `normalize-path`. For this and other reasons, the result of `normalize-path` is not suitable for comparisons that determine whether two paths refer to the same file (i.e., the comparison may produce false negatives).

An error is signaled by `normalize-path` if the input path contains an embedded path for a non-existent directory, or if an infinite cycle of soft-links is detected.

`(path-only``` `path``)` PROCEDURE

If `path` is a filename, the file's path is returned. If `path` is syntactically a directory, `#f` is returned.

`(put-preferences``` `name-list val-list``` [`locked-proc filename`]`)` PROCEDURE

See also `get-preference`.

Installs a set of preference values and writes all current values to the preference file designated by `(`find-system-path` 'pref-file)` (see section 11.3 in PLT MzScheme: Language Manual), or `filename` if it is supplied and not `#f`. The `name-list` argument must be a list of symbols for the preference names, and `val-list` must have the same length as `name-list`. Each element of `val-list` must be an instance of a built-in data type whose `write` output is `read`able (i.e., the `print-unreadable` parameter is set to `#f` while writing preferences; see section 7.9.1.4 in PLT MzScheme: Language Manual).

Current preference values are read from the preference file before updating, and an update ``lock'' is held starting before the file read, and lasting until after the preferences file is updated. The lock is implemented by the existence of a file in the same directory as the preference file. If the directory of the preferences file does not already exist, it is created.

If the update lock is already held (i.e., the lock file exists), then `locked-proc` is called with a single argument: the path of the lock file. The default `locked-proc` reports an error; an alternative thunk might wait a while and try again, or give the user the choice to delete the lock file (in case a previous update attempt encountered disaster).

If `filename` is `#f` or not supplied, and the preference file does not already exist, then values read from the `defaults` collection (if any) are written for preferences that are not mentioned in `name-list`.