All file system accesses go through the global library Filesystem object that can be retrieved with the GetFilesystem function. A Filesystem object provides a very flexible abstraction of the machine file system.
FileDriver abstracts access to files and directories behind a unified API. Different drivers are available to access files on the local machine or on a remote one. The most basic driver, and the one you will almost always need, is StdFileDriver which provides access to the local machine file system.
While a driver can be used directly, all of the library load and save operations are working with files using the global Filesystem object. You can mount a specific driver on the library file system object to control where these operations will get and store their files to.
For example, when saving a file to
c:/tree.geo the file system is queried for the adequate driver to write the file with. In this case, mounting StdFileDriver with no prefix will direct the access to the OS standard library.
# create a new StdFileDriver and mount it on the file system hg.GetFilesystem().Mount(hg.StdFileDriver())
Note: The library file system object is initially empty so you need to mount at least one driver in order to be able to read or write files.
The previous mount operation did not specify any prefix so the driver will be forwarded all accesses to the file system. It is possible to specialize file access to a particular path of the file system by using a mount prefix.
When mounting a driver with a prefix, all accesses to a path starting with the specified prefix will be forwarded to this driver.
# create a new StdFileDriver and mount it on the engine file system under the "@std" prefix hg.GetFilesystem().Mount(hg.StdFileDriver(), "@FS/") handle = hg.GetFilesystem().Open("@FS/c:/tree.geo") # the driver will operate on "c:/tree.geo"
Once a prefix is matched against a mount point it is stripped from the path before being forwarded to the driver.
Driver chaining can happen in two different ways. Explicitly, such as with BufferFileDriver which wraps another driver to implement read/write buffering. And implicitly, through mount points.
A typical scenario in which implicit chaining happens is with the ZipFileDriver which needs to access a file before it can serve its content. Here is an example of serving files through a Zip archive stored on the local file system.
std_driver = hg.StdFileDriver("/app_path/", True) # sandboxed access to the local file system hg.GetFilesystem().Mount(std_driver, "@app/") # mount under the "@app/" prefix zip_driver = hg.ZipFileDriver("@app/data.zip") # connect to archive on the local file system hg.GetFilesystem().Mount(zip_driver) # mount as a root driver (no prefix) handle = hg.GetFilesystem().Open("test_file") # open "test_file" on the root zip driver
Note: In the previous example any driver could be sitting in front of the zip archive driver under the
Some file driver such as StdFileDriver supports sandboxing. You can specify a root path to serve through the driver and prevent any access outside of this path.
Let's say that we wish to serve our application files from a known directory on the local file system and prevent any access outside of this directory, this can be done like this:
driver = hg.StdFileDriver("/local_path_to_app_data/", True) # True to enable sandboxing hg.GetFilesystem().Mount(driver) # mount as root driver okay = hg.GetFilesystem().Open("test_file") # opens "/local_path_to_app_data/test_file" fail = hg.GetFilesystem().Open("../test_file") # fails to open "/local_path_to_app_data/../test_file"