@c -*-texinfo-*-
@node VFS, Game Data, Libraries, Using Crystal Space
@section Virtual File System (@sc{vfs})
@cindex Virtual File System (@sc{vfs})
@cindex @sc{vfs}, Virtual File System

@noindent
@emph{Written by Andrew Zabolotny, @email{bit@@eltech.ru}.}

Since many even basic concepts in file systems on different operating systems
often differ, you often should take care to use the right path separators on
the right platform, search on different ``drives'', ``mounts'' and so on for
required files.  This library achieves the goal of making the file system
appear ``the same'' on various operating systems, and adds many bonus
features such as archive support and overlaid directories.

Each ``directory'' on the @sc{vfs} @dfn{virtual volume} is mapped to some
@dfn{real-world} directory or @sc{zip} archive. Additionally, you can make
one ``virtual directory'' map to several real-world directories (and/or
@sc{zip} files) at one time, thus covering such cases as having files either
on compact disc (@sc{cd}) or hard disk (depending upon the user's choice),
distributing data file updates (thus overriding some files on write-only
media) and so on.

The Virtual File System is driven by a configuration file.
@xref{VFS Configuration File}.

@menu
* VFS Details:: Details
* VFS Configuration File:: Configuration File (@file{vfs.cfg})
@end menu

@node VFS Details, VFS Configuration File, VFS, VFS
@subsection Details
@cindex @sc{vfs} Details
@cindex Details, @sc{vfs}

To make difference between @sc{zip} archives and physical disk directories
@sc{vfs} uses a simple convention: directories end with a path separator
character (@samp{$/}) while archives do not. @samp{$/} is a special
configuration file variable which represents the path separator on any
particular platform (@pxref{VFS Configuration File}). For example
@samp{$/data} refers to an archive, while @samp{$/data$/} refers to an actual
directory named @file{data}.  Failure to understand this distinction is often
the major cause of errors; so if you're getting unexpected results check in
the first place if directories have trailing path separators.

There are several differences between filesystems between operating systems
that you should always keep in mind because @sc{vfs} doesn't hide these
details from you. To avoid inconsistencies between different file systems you
should follow this list of guidelines:

@itemize @bullet
@item
Choose filenames that are well suited for all operating systems you are
targeting.  As of today @sc{dos} has the most restricted rules for naming
files (@sc{ascii7} characters except @samp{?}, @samp{*}, @samp{+}, and space,
and with only one dot per filename).
The part of @sc{vfs} that is located in archives support virtually any
filenames, so if you are sure that you will never have to place some file on a
``real'' filesystem, you can give it any name you desire.

@item
Different platforms use different filename comparison criteria.  On Unix and
MacOS/X @sc{ufs} filesystems, filenames are case-sensitive, while on Windows,
@sc{dos}, and Macintosh @sc{hfs} filesystems, they are case-insensitive.  To
avoid problems always refer to files by their exact names.  For example, if you
have a file on @sc{vfs} called @file{GaMe.DaT} you should open it exactly as
@file{GaMe.DaT} and not as @file{game.dat} or @file{GAME.DAT}.  On @sc{dos},
the file will appear to be entirely upper-case @file{GAME.DAT}, but you should
still use the correct name, @file{GaMe.DaT}, when opening it.

@item
Keep in mind that Unix @emph{can} delete files which are actively open, whereas
Windows, @sc{dos}, and possibly other platforms can not.  Therefore, you should
avoid deleting open files.  (@emph{Technical Note}: Actually, this should work
for files which are located in archives but is not advisable to do so, because
in general, program code will not know if a file resides within an archive or
within the physical filesystem.  Furthermore, deleting open files from an
archive not been tested.
@end itemize

@node VFS Configuration File, , VFS Details, VFS
@subsection Configuration File (@file{vfs.cfg})
@cindex @sc{vfs} Configuration File
@cindex @file{vfs.cfg}, @sc{vfs} Configuration File

When the @sc{vfs} plugin is loaded, it searches for a configuration file named
@file{vfs.cfg} in the following locations in the order shown:

@itemize @bullet
@item
Application resource directory; typically, the directory in which the
application executable resides but, on MacOS/X, it is the @file{Resources}
directory within the Cocoa application wrapper for @sc{gui} programs. (Returned
by @code{csGetResourceDir()}.)

@item
Directory where application executable resides, or the directory where Cocoa
application wrapper resides on MacOS/X. (Returned by @code{csGetAppDir()}.)

@item
Crystal Space installation directory. (Returned by @code{csGetConfigPath()}.)
@end itemize

@noindent
The full set of directories mounted by @sc{vfs} after it scans for
configuration files is the union of the entries in all of the discovered
@file{vfs.cfg} files. If there are conflicting entries, then mounts and
variable assignments specified in configuration files discovered earlier in the
scan take precedence over those discovered later.

Keys in the @file{vfs.cfg} configuration file with names starting with
@samp{VFS.Mount.} describe the layout of the @dfn{virtual} file system.
Imagine a clean disk drive onto which you start to create directories by making
links to existing @dfn{real} directories and archive (@file{.zip}) files.  An
archive is treated exactly like a subdirectory; you even can link one ``virtual
directory'' to several ``real'' paths and archives; however if you write files
they will be written to the first directory or archive in list.

These keys present a list of virtual-to-real path mappings.  The local name of
a key with the @samp{VFS.Mount.} prefix define the virtual directory, and the
values define the real paths, which can represent a list of @dfn{physical}
directories and @sc{zip} archives.  The physical directory path lists should be
separated by commas (,), therefore commas cannot be used in directory names.
This should not be much of a restriction, but if it is a problem for a
particular platform, you may want to take the drastic action of changing
@samp{VFS_PATH_DIVIDER} macro in @file{vfs.cpp}.

The @samp{VFS.Mount.} values typically makes heavy use of variables since
most operating systems have different pathname semantics and syntax.  The
``common denominator'' that @sc{vfs} emulates is a Unix-like filesystem.  To
include the value of a variable in a @sc{vfs} path use the
@samp{$(@var{variable-name})} construct.  In the case where
@samp{@var{variable-name}} consists of a single letter, you can omit the
parentheses, as in @code{$@var{variable-name}} (for example @samp{$A}).

Variables that are defined in the environment override those defined in this
file.  For example, the @samp{$HOME} environment variable is set in all
Unixes, but is undefined in many other operating systems.  They can define
their own values for these variables in system-dependent sections, but if the
user defines the @samp{$HOME} environment variable it will always override
the one from this file. You also can refer the variables in the following
way: @samp{$(@var{var}:@var{expr})} which means ``use the contents of
@samp{@var{var}} if @samp{@var{var}} is set (usually in environment), or use
@samp{@var{expr}} if not''.  This can be used for more complex expressions,
for example:

@example
$(HOME:$(HOMEDIR:$(HOMEPATH:/home)))
@end example

This expression means ``take the value of the @samp{$HOME} variable; if it is
not set, use the contents of @samp{$HOMEDIR}; if it is also not set, use
@samp{$HOMEPATH}; and if none are set, use the literal string @samp{/home} as
the resulting value.

@sc{vfs} defines a pseudo-variable named @samp{/} that contains the path
delimiter for the current operating system (i.e.  @file{/} for Unix and
MacOS/X, and @file{\} for Windows/@sc{dos}).  You reference this variable by
writing @samp{$/} rather than using the ``real-world'' delimiters @samp{/},
or @samp{\}.

Here is the complete list of pseudo-variables understood by @sc{vfs}:

@table @code
@item $/
Platform-specific path delimiter; @file{/} on Unix and MacOS/X; @file{\} on
Windows.

@item $@@
Crystal Space installation directory.

@item $*
Application resource directory; typically, the directory in which the
application executable resides but, on MacOS/X, it is the @file{Resources}
directory within the Cocoa application wrapper for @sc{gui} programs.

@item $^
Directory where application executable resides, or the directory where Cocoa
application wrapper resides on MacOS/X.
@end table

The following is an example @sc{vfs} configuration file.

Assume we wrote a game with three levels; the game is located on @sc{cd-rom}
and we want to be able to release patches in the future which will replace
several files from level archives (each level is presumed to be placed in a
separate @sc{zip} archive on either @sc{cd-rom} or cached on the hard drive).
Additionally, we will add a link to user's home directory (something somewhat
vaguely defined on non-Unix platforms) so that game can store the user's
settings into the file @file{~/game.profile}.

Note that in this example many of the options in the real @file{vfs.cfg} are
omitted. So you should not take this example for your game, because one of the
libraries or plug-in modules you use may require a mapping that is not listed
here. This example is only intended to understand the concept:

@example
;;; Virtual File System mount table
;;;
;;; $/ -- path delimiter (i.e. "/" on Unix; "\" on Windows)
;;; $@@ -- installation directory of Crystal Space
;;; $* -- application resource directory
;;; $^ -- directory in which application resides
;;; The expansions of $@@, $*, and $^ always have a trailing
;;; path delimiter.
;
; The following variables should be defined either in
; the environment or in system-dependent sections:
;
; $CD - The path to CD-ROM.
; $HOME - user's home directory
;
; A common error is to omit the last $/ from directories.
; This is an error since VFS will treat any path not ending
; in $/ as an archive file name and not as a physical
; directory.

; Mount points. (These are split over multiple lines in order to
; fit correctly on a printed page in the documentation.  In real
; life, the values would appear immediately after the `=' signs!)
VFS.Mount.~ = $(HOME)$/
VFS.Mount.map1 =
  $*$/patch$/map1$/, $*$/cache$/map1.zip, $(CD)$/data$/map1.zip
VFS.Mount.map2 =
  $*$/patch$/map2$/, $*$/cache$/map2.zip, $(CD)$/data$/map2.zip
VFS.Mount.map3 =
  $*$/patch$/map3$/, $*$/cache$/map3.zip, $(CD)$/data$/map3.zip

; Platform aliases.  Aliases are always read first; VFS
; entries specific to each platform override those defined
; in the platform alias section.  For example, if your
; current platform is MacOS/X, VFS will look for the value
; of a variable first in the environment, then in
; VFS.MacOS/X., and finally in VFS.Unix. (as specified in
; section below).

; Unix-style filesystems
VFS.Alias.Unix    = VFS.Unix
VFS.Alias.MacOS/X = VFS.Unix

; CP/M-style filesystems
VFS.Alias.Win32   = VFS.CP/M
VFS.Alias.DOS     = VFS.CP/M

; Strange key names follow:
; VFS.Unix.. means key '.' in section VFS.Unix.*
; VFS.Unix... means key '..' in section VFS.Unix.*
VFS.Unix.. = .
VFS.Unix... = ..
VFS.Unix.CDROM = /mnt/cdrom
VFS.Unix.TMP = /tmp

VFS.CP/M.. = .
VFS.CP/M... = ..
VFS.CP/M.HOME = $(HOMEDIR:$(HOMEPATH:.))
VFS.CP/M.CDROM = x:
VFS.CP/M.TMP = $(TEMP:$(TMP:$(SYSTEMROOT)$/temp))
@end example
