mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
730 lines
26 KiB
C++
730 lines
26 KiB
C++
// Filename: virtualFileSystem.cxx
|
|
// Created by: drose (03Aug02)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
|
//
|
|
// All use of this software is subject to the terms of the Panda 3d
|
|
// Software license. You should have received a copy of this license
|
|
// along with this source code; you will also find a current copy of
|
|
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
|
//
|
|
// To contact the maintainers of this program write to
|
|
// panda3d-general@lists.sourceforge.net .
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "virtualFileSystem.h"
|
|
#include "virtualFileMount.h"
|
|
#include "virtualFileMountMultifile.h"
|
|
#include "virtualFileMountSystem.h"
|
|
#include "dSearchPath.h"
|
|
#include "dcast.h"
|
|
#include "config_express.h"
|
|
#include "executionEnvironment.h"
|
|
#include "pset.h"
|
|
|
|
VirtualFileSystem *VirtualFileSystem::_global_ptr = NULL;
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::Constructor
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
VirtualFileSystem::
|
|
VirtualFileSystem() {
|
|
_cwd = "/";
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::Destructor
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
VirtualFileSystem::
|
|
~VirtualFileSystem() {
|
|
unmount_all();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::mount
|
|
// Access: Published
|
|
// Description: Mounts the indicated Multifile at the given mount
|
|
// point.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool VirtualFileSystem::
|
|
mount(Multifile *multifile, const string &mount_point, int flags) {
|
|
VirtualFileMountMultifile *mount =
|
|
new VirtualFileMountMultifile(this, multifile,
|
|
normalize_mount_point(mount_point),
|
|
flags);
|
|
_mounts.push_back(mount);
|
|
return true;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::mount
|
|
// Access: Published
|
|
// Description: Mounts the indicated system file or directory at the
|
|
// given mount point. If the named file is a directory,
|
|
// mounts the directory. If the named file is a
|
|
// Multifile, mounts it as a Multifile. Returns true on
|
|
// success, false on failure.
|
|
//
|
|
// A given system directory may be mounted to multiple
|
|
// different mount point, and the same mount point may
|
|
// share multiple system directories. In the case of
|
|
// ambiguities (that is, two different files with
|
|
// exactly the same full pathname), the most-recently
|
|
// mounted system wins.
|
|
//
|
|
// Note that a mounted VirtualFileSystem directory is
|
|
// fully case-sensitive, unlike the native Windows file
|
|
// system, so you must refer to files within the virtual
|
|
// file system with exactly the right case.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool VirtualFileSystem::
|
|
mount(const Filename &physical_filename, const string &mount_point,
|
|
int flags, const string &password) {
|
|
if (!physical_filename.exists()) {
|
|
express_cat.warning()
|
|
<< "Attempt to mount " << physical_filename << ", not found.\n";
|
|
return false;
|
|
}
|
|
|
|
if (physical_filename.is_directory()) {
|
|
VirtualFileMountSystem *mount =
|
|
new VirtualFileMountSystem(this, physical_filename,
|
|
normalize_mount_point(mount_point),
|
|
flags);
|
|
_mounts.push_back(mount);
|
|
return true;
|
|
|
|
} else {
|
|
// It's not a directory; it must be a Multifile.
|
|
PT(Multifile) multifile = new Multifile;
|
|
|
|
multifile->set_encryption_password(password);
|
|
|
|
// For now these are always opened read only. Maybe later we'll
|
|
// support read-write on Multifiles.
|
|
flags |= MF_read_only;
|
|
if (!multifile->open_read(physical_filename)) {
|
|
delete multifile;
|
|
return false;
|
|
}
|
|
|
|
return mount(multifile, mount_point, flags);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::unmount
|
|
// Access: Published
|
|
// Description: Unmounts all appearances of the indicated Multifile
|
|
// from the file system. Returns the number of
|
|
// appearances unmounted.
|
|
////////////////////////////////////////////////////////////////////
|
|
int VirtualFileSystem::
|
|
unmount(Multifile *multifile) {
|
|
Mounts::iterator ri, wi;
|
|
wi = ri = _mounts.begin();
|
|
while (ri != _mounts.end()) {
|
|
VirtualFileMount *mount = (*ri);
|
|
(*wi) = mount;
|
|
|
|
if (mount->is_exact_type(VirtualFileMountMultifile::get_class_type())) {
|
|
VirtualFileMountMultifile *mmount =
|
|
DCAST(VirtualFileMountMultifile, mount);
|
|
if (mmount->get_multifile() == multifile) {
|
|
// Remove this one. Don't increment wi.
|
|
delete mount;
|
|
} else {
|
|
// Don't remove this one.
|
|
++wi;
|
|
}
|
|
} else {
|
|
// Don't remove this one.
|
|
++wi;
|
|
}
|
|
++ri;
|
|
}
|
|
|
|
int num_removed = _mounts.end() - wi;
|
|
_mounts.erase(wi, _mounts.end());
|
|
return num_removed;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::unmount
|
|
// Access: Published
|
|
// Description: Unmounts all appearances of the indicated physical
|
|
// filename (either a directory name or a Multifile
|
|
// name) from the file system. Returns the number of
|
|
// appearances unmounted.
|
|
////////////////////////////////////////////////////////////////////
|
|
int VirtualFileSystem::
|
|
unmount(const Filename &physical_filename) {
|
|
Mounts::iterator ri, wi;
|
|
wi = ri = _mounts.begin();
|
|
while (ri != _mounts.end()) {
|
|
VirtualFileMount *mount = (*ri);
|
|
(*wi) = mount;
|
|
|
|
if (mount->get_physical_filename() == physical_filename) {
|
|
// Remove this one. Don't increment wi.
|
|
delete mount;
|
|
} else {
|
|
// Don't remove this one.
|
|
++wi;
|
|
}
|
|
++ri;
|
|
}
|
|
|
|
int num_removed = _mounts.end() - wi;
|
|
_mounts.erase(wi, _mounts.end());
|
|
return num_removed;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::unmount_point
|
|
// Access: Published
|
|
// Description: Unmounts all systems attached to the given mount
|
|
// point from the file system. Returns the number of
|
|
// appearances unmounted.
|
|
////////////////////////////////////////////////////////////////////
|
|
int VirtualFileSystem::
|
|
unmount_point(const string &mount_point) {
|
|
Filename nmp = normalize_mount_point(mount_point);
|
|
Mounts::iterator ri, wi;
|
|
wi = ri = _mounts.begin();
|
|
while (ri != _mounts.end()) {
|
|
VirtualFileMount *mount = (*ri);
|
|
(*wi) = mount;
|
|
|
|
if (mount->get_mount_point() == nmp) {
|
|
// Remove this one. Don't increment wi.
|
|
delete mount;
|
|
} else {
|
|
// Don't remove this one.
|
|
++wi;
|
|
}
|
|
++ri;
|
|
}
|
|
|
|
int num_removed = _mounts.end() - wi;
|
|
_mounts.erase(wi, _mounts.end());
|
|
return num_removed;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::unmount_all
|
|
// Access: Published
|
|
// Description: Unmounts all files from the file system. Returns the
|
|
// number of systems unmounted.
|
|
////////////////////////////////////////////////////////////////////
|
|
int VirtualFileSystem::
|
|
unmount_all() {
|
|
Mounts::iterator mi;
|
|
for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) {
|
|
VirtualFileMount *mount = (*mi);
|
|
delete mount;
|
|
}
|
|
|
|
int num_removed = _mounts.size();
|
|
_mounts.clear();
|
|
return num_removed;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::chdir
|
|
// Access: Published
|
|
// Description: Changes the current directory. This is used to
|
|
// resolve relative pathnames in get_file() and/or
|
|
// find_file(). Returns true if successful, false
|
|
// otherwise.
|
|
//
|
|
// This accepts a string rather than a Filename simply
|
|
// for programmer convenience from the Python prompt.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool VirtualFileSystem::
|
|
chdir(const string &new_directory) {
|
|
if (new_directory == "/") {
|
|
// We can always return to the root.
|
|
_cwd = new_directory;
|
|
return true;
|
|
}
|
|
|
|
PT(VirtualFile) file = get_file(new_directory);
|
|
if (file != (VirtualFile *)NULL && file->is_directory()) {
|
|
_cwd = file->get_filename();
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::get_cwd
|
|
// Access: Published
|
|
// Description: Returns the current directory name. See chdir().
|
|
////////////////////////////////////////////////////////////////////
|
|
const Filename &VirtualFileSystem::
|
|
get_cwd() const {
|
|
return _cwd;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::get_file
|
|
// Access: Published
|
|
// Description: Looks up the file by the indicated name in the file
|
|
// system. Returns a VirtualFile pointer representing
|
|
// the file if it is found, or NULL if it is not.
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(VirtualFile) VirtualFileSystem::
|
|
get_file(const Filename &filename) const {
|
|
nassertr(!filename.empty(), NULL);
|
|
Filename pathname(filename);
|
|
if (pathname.is_local()) {
|
|
pathname = Filename(_cwd, filename);
|
|
}
|
|
pathname.standardize();
|
|
string strpath = pathname.get_fullpath().substr(1);
|
|
|
|
// Now scan all the mount points, from the back (since later mounts
|
|
// override more recent ones), until a match is found.
|
|
PT(VirtualFile) found_file = NULL;
|
|
VirtualFileComposite *composite_file = NULL;
|
|
|
|
Mounts::const_reverse_iterator rmi;
|
|
for (rmi = _mounts.rbegin(); rmi != _mounts.rend(); ++rmi) {
|
|
VirtualFileMount *mount = (*rmi);
|
|
string mount_point = mount->get_mount_point();
|
|
if (strpath == mount_point) {
|
|
// Here's an exact match on the mount point. This filename is
|
|
// the root directory of this mount object.
|
|
if (found_match(found_file, composite_file, mount, "")) {
|
|
return found_file;
|
|
}
|
|
|
|
} else if (mount_point.empty()) {
|
|
// This is the root mount point; all files are in here.
|
|
if (mount->has_file(strpath)) {
|
|
// Bingo!
|
|
if (found_match(found_file, composite_file, mount, strpath)) {
|
|
return found_file;
|
|
}
|
|
}
|
|
|
|
} else if (strpath.length() > mount_point.length() &&
|
|
strpath.substr(0, mount_point.length()) == mount_point &&
|
|
strpath[mount_point.length()] == '/') {
|
|
// This pathname falls within this mount system.
|
|
Filename local_filename = strpath.substr(mount_point.length() + 1);
|
|
if (mount->has_file(local_filename)) {
|
|
// Bingo!
|
|
if (found_match(found_file, composite_file, mount, local_filename)) {
|
|
return found_file;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return found_file;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::find_file
|
|
// Access: Published
|
|
// Description: Uses the indicated search path to find the file
|
|
// within the file system. Returns the first occurrence
|
|
// of the file found, or NULL if the file cannot be
|
|
// found.
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(VirtualFile) VirtualFileSystem::
|
|
find_file(const Filename &filename, const DSearchPath &searchpath) const {
|
|
if (!filename.is_local()) {
|
|
return get_file(filename);
|
|
}
|
|
|
|
int num_directories = searchpath.get_num_directories();
|
|
for (int i = 0; i < num_directories; i++) {
|
|
Filename match(searchpath.get_directory(i), filename);
|
|
if (searchpath.get_directory(i) == "." &&
|
|
filename.is_fully_qualified()) {
|
|
// A special case for the "." directory: to avoid prefixing an
|
|
// endless stream of ./ in front of files, if the filename
|
|
// already has a ./ prefixed (i.e. is_fully_qualified() is
|
|
// true), we don't prefix another one.
|
|
match = filename;
|
|
}
|
|
PT(VirtualFile) found_file = get_file(match);
|
|
if (found_file != (VirtualFile *)NULL) {
|
|
return found_file;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::resolve_filename
|
|
// Access: Public
|
|
// Description: Searches the given search path for the filename. If
|
|
// it is found, updates the filename to the full
|
|
// pathname found and returns true; otherwise, returns
|
|
// false.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool VirtualFileSystem::
|
|
resolve_filename(Filename &filename,
|
|
const DSearchPath &searchpath,
|
|
const string &default_extension) const {
|
|
PT(VirtualFile) found;
|
|
|
|
if (filename.is_local()) {
|
|
found = find_file(filename.get_fullpath(), searchpath);
|
|
|
|
if (found.is_null()) {
|
|
// We didn't find it with the given extension; can we try the
|
|
// default extension?
|
|
if (filename.get_extension().empty() && !default_extension.empty()) {
|
|
Filename try_ext = filename;
|
|
try_ext.set_extension(default_extension);
|
|
found = find_file(try_ext.get_fullpath(), searchpath);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
if (exists(filename)) {
|
|
// The full pathname exists. Return true.
|
|
return true;
|
|
|
|
} else {
|
|
// The full pathname doesn't exist with the given extension;
|
|
// does it exist with the default extension?
|
|
if (filename.get_extension().empty() && !default_extension.empty()) {
|
|
Filename try_ext = filename;
|
|
try_ext.set_extension(default_extension);
|
|
found = get_file(try_ext);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!found.is_null()) {
|
|
filename = found->get_filename();
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::find_all_files
|
|
// Access: Public
|
|
// Description: Searches all the directories in the search list for
|
|
// the indicated file, in order. Fills up the results
|
|
// list with *all* of the matching filenames found, if
|
|
// any. Returns the number of matches found.
|
|
//
|
|
// It is the responsibility of the the caller to clear
|
|
// the results list first; otherwise, the newly-found
|
|
// files will be appended to the list.
|
|
////////////////////////////////////////////////////////////////////
|
|
int VirtualFileSystem::
|
|
find_all_files(const Filename &filename, const DSearchPath &searchpath,
|
|
DSearchPath::Results &results) const {
|
|
int num_added = 0;
|
|
|
|
if (filename.is_local()) {
|
|
int num_directories = searchpath.get_num_directories();
|
|
for (int i = 0; i < num_directories; i++) {
|
|
Filename match(searchpath.get_directory(i), filename);
|
|
if (exists(match)) {
|
|
if (searchpath.get_directory(i) == "." &&
|
|
filename.is_fully_qualified()) {
|
|
// A special case for the "." directory: to avoid prefixing
|
|
// an endless stream of ./ in front of files, if the
|
|
// filename already has a ./ prefixed
|
|
// (i.e. is_fully_fully_qualified() is true), we don't
|
|
// prefix another one.
|
|
results.add_file(filename);
|
|
} else {
|
|
results.add_file(match);
|
|
}
|
|
num_added++;
|
|
}
|
|
}
|
|
}
|
|
|
|
return num_added;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::write
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void VirtualFileSystem::
|
|
write(ostream &out) const {
|
|
Mounts::const_iterator mi;
|
|
for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) {
|
|
VirtualFileMount *mount = (*mi);
|
|
mount->write(out);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::get_global_ptr
|
|
// Access: Published, Static
|
|
// Description: Returns the default global VirtualFileSystem. You
|
|
// may create your own personal VirtualFileSystem
|
|
// objects and use them for whatever you like, but Panda
|
|
// will attempt to load models and stuff from this
|
|
// default object.
|
|
//
|
|
// Initially, the global VirtualFileSystem is set up to
|
|
// mount the OS filesystem to root; i.e. it is
|
|
// equivalent to the OS filesystem. This may be
|
|
// subsequently adjusted by the user.
|
|
////////////////////////////////////////////////////////////////////
|
|
VirtualFileSystem *VirtualFileSystem::
|
|
get_global_ptr() {
|
|
if (_global_ptr == (VirtualFileSystem *)NULL) {
|
|
_global_ptr = new VirtualFileSystem;
|
|
|
|
// Set up the default mounts. First, there is always the root
|
|
// mount.
|
|
_global_ptr->mount("/", "/", 0);
|
|
|
|
// And our initial cwd comes from the environment.
|
|
_global_ptr->chdir(ExecutionEnvironment::get_cwd());
|
|
|
|
// Then, we add whatever mounts are listed in the Configrc file.
|
|
ConfigVariableList mounts
|
|
("vfs-mount",
|
|
"vfs-mount system-filename mount-point [options]");
|
|
|
|
int num_unique_values = mounts.get_num_unique_values();
|
|
for (int i = 0; i < num_unique_values; i++) {
|
|
string mount_desc = mounts.get_unique_value(i);
|
|
|
|
// The vfs-mount syntax is:
|
|
|
|
// vfs-mount system-filename mount-point [options]
|
|
|
|
// The last two spaces mark the beginning of the mount point,
|
|
// and of the options, respectively. There might be multiple
|
|
// spaces in the system filename, which are part of the
|
|
// filename.
|
|
|
|
// The last space marks the beginning of the mount point.
|
|
// Spaces before that are part of the system filename.
|
|
size_t space = mount_desc.rfind(' ');
|
|
if (space == string::npos) {
|
|
express_cat.warning()
|
|
<< "No space in vfs-mount descriptor: " << mount_desc << "\n";
|
|
|
|
} else {
|
|
string mount_point = mount_desc.substr(space + 1);
|
|
while (space > 0 && isspace(mount_desc[space - 1])) {
|
|
space--;
|
|
}
|
|
mount_desc = mount_desc.substr(0, space);
|
|
string options;
|
|
|
|
space = mount_desc.rfind(' ');
|
|
if (space != string::npos) {
|
|
// If there's another space, we have the optional options field.
|
|
options = mount_point;
|
|
mount_point = mount_desc.substr(space + 1);
|
|
while (space > 0 && isspace(mount_desc[space - 1])) {
|
|
space--;
|
|
}
|
|
mount_desc = mount_desc.substr(0, space);
|
|
}
|
|
|
|
mount_desc = ExecutionEnvironment::expand_string(mount_desc);
|
|
Filename physical_filename = Filename::from_os_specific(mount_desc);
|
|
|
|
int flags = 0;
|
|
string password;
|
|
|
|
// Split the options up by commas.
|
|
size_t p = 0;
|
|
size_t q = options.find(',', p);
|
|
while (q != string::npos) {
|
|
parse_option(options.substr(p, q - p),
|
|
flags, password);
|
|
p = q + 1;
|
|
q = options.find(',', p);
|
|
}
|
|
parse_option(options.substr(p), flags, password);
|
|
|
|
_global_ptr->mount(physical_filename, mount_point, flags, password);
|
|
}
|
|
}
|
|
}
|
|
|
|
return _global_ptr;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::close_read_file
|
|
// Access: Published
|
|
// Description: Closes a file opened by a previous call to
|
|
// open_read_file(). This really just deletes the
|
|
// istream pointer, but it is recommended to use this
|
|
// interface instead of deleting it explicitly, to help
|
|
// work around compiler issues.
|
|
////////////////////////////////////////////////////////////////////
|
|
void VirtualFileSystem::
|
|
close_read_file(istream *stream) const {
|
|
if (stream != (istream *)NULL) {
|
|
// For some reason--compiler bug in gcc 3.2?--explicitly deleting
|
|
// the stream pointer does not call the appropriate global delete
|
|
// function; instead apparently calling the system delete
|
|
// function. So we call the delete function by hand instead.
|
|
#ifndef NDEBUG
|
|
stream->~istream();
|
|
(*global_operator_delete)(stream);
|
|
#else
|
|
delete stream;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::scan_mount_points
|
|
// Access: Public
|
|
// Description: Adds to names a list of all the mount points in use
|
|
// that are one directory below path, if any. That is,
|
|
// these are the external files or directories mounted
|
|
// directly to the indicated path.
|
|
//
|
|
// The names vector is filled with a set of basenames,
|
|
// the basename part of the mount point.
|
|
////////////////////////////////////////////////////////////////////
|
|
void VirtualFileSystem::
|
|
scan_mount_points(vector_string &names, const Filename &path) const {
|
|
nassertv(!path.empty() && !path.is_local());
|
|
string prefix = path.get_fullpath().substr(1);
|
|
Mounts::const_iterator mi;
|
|
for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) {
|
|
VirtualFileMount *mount = (*mi);
|
|
|
|
string mount_point = mount->get_mount_point();
|
|
if (prefix.empty()) {
|
|
// The indicated path is the root. Is the mount point on the
|
|
// root?
|
|
if (mount_point.find('/') == string::npos) {
|
|
// No embedded slashes, so the mount point is only one
|
|
// directory below the root.
|
|
names.push_back(mount_point);
|
|
}
|
|
} else {
|
|
if (mount_point.substr(0, prefix.length()) == prefix &&
|
|
mount_point.length() > prefix.length() &&
|
|
mount_point[prefix.length()] == '/') {
|
|
// This mount point is below the indicated path. Is it only one
|
|
// directory below?
|
|
string basename = mount_point.substr(prefix.length());
|
|
if (basename.find('/') == string::npos) {
|
|
// No embedded slashes, so it's only one directory below.
|
|
names.push_back(basename);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::normalize_mount_point
|
|
// Access: Private
|
|
// Description: Converts the mount point string supplied by the user
|
|
// to standard form (relative to the current directory,
|
|
// with no double slashes, and not terminating with a
|
|
// slash). The initial slash is removed.
|
|
////////////////////////////////////////////////////////////////////
|
|
Filename VirtualFileSystem::
|
|
normalize_mount_point(const string &mount_point) const {
|
|
Filename nmp = mount_point;
|
|
if (nmp.is_local()) {
|
|
nmp = Filename(_cwd, mount_point);
|
|
}
|
|
nmp.standardize();
|
|
nassertr(!nmp.empty() && nmp[0] == '/', nmp);
|
|
return nmp.get_fullpath().substr(1);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::found_match
|
|
// Access: Private
|
|
// Description: Evaluates one match found during a get_file()
|
|
// operation. There may be multiple matches for a
|
|
// particular filename due to the ambiguities introduced
|
|
// by allowing multiple mount points, so we may have to
|
|
// keep searching even after the first match is found.
|
|
//
|
|
// Returns true if the search should terminate now, or
|
|
// false if it should keep iterating.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool VirtualFileSystem::
|
|
found_match(PT(VirtualFile) &found_file, VirtualFileComposite *&composite_file,
|
|
VirtualFileMount *mount, const string &local_filename) const {
|
|
if (found_file == (VirtualFile *)NULL) {
|
|
// This was our first match. Save it.
|
|
found_file = new VirtualFileSimple(mount, local_filename);
|
|
if (!mount->is_directory(local_filename)) {
|
|
// If it's not a directory, we're done.
|
|
return true;
|
|
}
|
|
|
|
} else {
|
|
// This was our second match. The previous match(es) must
|
|
// have been directories.
|
|
if (!mount->is_directory(local_filename)) {
|
|
// However, this one isn't a directory. We're done.
|
|
return true;
|
|
}
|
|
|
|
// At least two directories matched to the same path. We
|
|
// need a composite directory.
|
|
if (composite_file == (VirtualFileComposite *)NULL) {
|
|
composite_file =
|
|
new VirtualFileComposite((VirtualFileSystem *)this, found_file->get_filename());
|
|
composite_file->add_component(found_file);
|
|
found_file = composite_file;
|
|
}
|
|
composite_file->add_component(new VirtualFileSimple(mount, local_filename));
|
|
}
|
|
|
|
// Keep going, looking for more directories.
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: VirtualFileSystem::parse_option
|
|
// Access: Private, Static
|
|
// Description: Parses one of the option flags in the options list on
|
|
// the vfs-mount Config.prc line.
|
|
////////////////////////////////////////////////////////////////////
|
|
void VirtualFileSystem::
|
|
parse_option(const string &option, int &flags, string &password) {
|
|
if (option == "0" || option.empty()) {
|
|
// 0 is the null option.
|
|
|
|
} else if (option == "ro") {
|
|
flags |= MF_read_only;
|
|
|
|
} else if (option.substr(0, 3) == "pw:") {
|
|
password = option.substr(3);
|
|
|
|
} else {
|
|
express_cat.warning()
|
|
<< "Invalid option on vfs-mount: \"" << option << "\"\n";
|
|
}
|
|
}
|