From d7f1f67136f8a1abab543c33b395b1429a4d26c1 Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 4 Nov 2008 22:57:34 +0000 Subject: [PATCH] vfs-implicit-mf --- panda/src/express/config_express.cxx | 10 + panda/src/express/config_express.h | 2 +- panda/src/express/multifile.I | 13 + panda/src/express/multifile.cxx | 46 ++-- panda/src/express/multifile.h | 8 +- panda/src/express/virtualFileSimple.I | 11 + panda/src/express/virtualFileSimple.h | 1 + panda/src/express/virtualFileSystem.I | 12 +- panda/src/express/virtualFileSystem.cxx | 316 +++++++++++++++++------- panda/src/express/virtualFileSystem.h | 13 +- 10 files changed, 318 insertions(+), 114 deletions(-) diff --git a/panda/src/express/config_express.cxx b/panda/src/express/config_express.cxx index 412b8f4527..f065964cff 100644 --- a/panda/src/express/config_express.cxx +++ b/panda/src/express/config_express.cxx @@ -83,6 +83,16 @@ ConfigVariableBool vfs_implicit_pz "case, the VirtualFileSystem will implicitly open the .pz file " "and decompress it on-the-fly.")); +ConfigVariableBool vfs_implicit_mf +("vfs-implicit-mf", true, + PRC_DESC("When this is true, the VirtualFileSystem will automatically " + "mount multifiles on-the-fly when they are used as directories. " + "For instance, opening the file /c/files/foo.mf/dirname/mytex.jpg " + "will implicitly retrieve a file named 'dirname/mytex.jpg' " + "within the multifile /c/files/foo.mf, even if the multifile " + "has not already been mounted. This makes all of your multifiles " + "act like directories.")); + ConfigVariableBool use_vfs ("use-vfs", true, PRC_DESC("Set this true to use the VirtualFileSystem mechanism for loading " diff --git a/panda/src/express/config_express.h b/panda/src/express/config_express.h index ca54a1ed65..0450256ec2 100644 --- a/panda/src/express/config_express.h +++ b/panda/src/express/config_express.h @@ -49,7 +49,7 @@ extern ConfigVariableInt multifile_encryption_iteration_count; extern ConfigVariableBool vfs_case_sensitive; extern ConfigVariableBool vfs_implicit_pz; -extern ConfigVariableBool vfs_auto_unwrap_pz; +extern ConfigVariableBool vfs_implicit_mf; extern EXPCL_PANDAEXPRESS ConfigVariableBool use_vfs; diff --git a/panda/src/express/multifile.I b/panda/src/express/multifile.I index d2839a5122..a3797862bd 100644 --- a/panda/src/express/multifile.I +++ b/panda/src/express/multifile.I @@ -24,6 +24,19 @@ get_multifile_name() const { return _multifile_name; } +//////////////////////////////////////////////////////////////////// +// Function: Multifile::set_multifile_name +// Access: Published +// Description: Replaces the filename of the Multifile. This is +// primarily used for documentation purposes only; +// changing this name does not open the indicated file. +// See open_read() or open_write() for that. +//////////////////////////////////////////////////////////////////// +INLINE void Multifile:: +set_multifile_name(const Filename &multifile_name) { + _multifile_name = multifile_name; +} + //////////////////////////////////////////////////////////////////// // Function: Multifile::is_read_valid // Access: Published diff --git a/panda/src/express/multifile.cxx b/panda/src/express/multifile.cxx index 49e2306d54..8dab8ae9ab 100644 --- a/panda/src/express/multifile.cxx +++ b/panda/src/express/multifile.cxx @@ -102,6 +102,7 @@ Multifile:: Multifile() { _read = (istream *)NULL; _write = (ostream *)NULL; + _owns_stream = false; _next_index = 0; _last_index = 0; _needs_repack = false; @@ -179,18 +180,18 @@ open_read(const Filename &multifile_name) { // istream. There must be seek functionality via // seekg() and tellg() on the istream. // -// The Multifile does *not* close or delete the istream -// when Multifile.close() is called. It is the caller's -// responsibility to ensure that the istream pointer -// does not destruct during the lifetime of the -// Multifile. +// If owns_pointer is true, then the Multifile assumes +// ownership of the stream pointer and will delete it +// when the multifile is closed, including if this +// function returns false. //////////////////////////////////////////////////////////////////// bool Multifile:: -open_read(istream *multifile_stream) { +open_read(istream *multifile_stream, bool owns_pointer) { close(); _timestamp = time(NULL); _timestamp_dirty = true; _read = multifile_stream; + _owns_stream = owns_pointer; _read->seekg(0, ios::beg); return read_index(); } @@ -230,18 +231,18 @@ open_write(const Filename &multifile_name) { // ostream. There must be seek functionality via // seekp() and tellp() on the pstream. // -// The Multifile does *not* close or delete the ostream -// when Multifile.close() is called. It is the caller's -// responsibility to ensure that the ostream pointer -// does not destruct during the lifetime of the -// Multifile. +// If owns_pointer is true, then the Multifile assumes +// ownership of the stream pointer and will delete it +// when the multifile is closed, including if this +// function returns false. //////////////////////////////////////////////////////////////////// bool Multifile:: -open_write(ostream *multifile_stream) { +open_write(ostream *multifile_stream, bool owns_pointer) { close(); _timestamp = time(NULL); _timestamp_dirty = true; _write = multifile_stream; + _owns_stream = owns_pointer; _write->seekp(0, ios::beg); return true; } @@ -293,19 +294,19 @@ open_read_write(const Filename &multifile_name) { // via seekg()/seekp() and tellg()/tellp() on the // iostream. // -// The Multifile does *not* close or delete the iostream -// when Multifile.close() is called. It is the caller's -// responsibility to ensure that the iostream pointer -// does not destruct during the lifetime of the -// Multifile. +// If owns_pointer is true, then the Multifile assumes +// ownership of the stream pointer and will delete it +// when the multifile is closed, including if this +// function returns false. //////////////////////////////////////////////////////////////////// bool Multifile:: -open_read_write(iostream *multifile_stream) { +open_read_write(iostream *multifile_stream, bool owns_pointer) { close(); _timestamp = time(NULL); _timestamp_dirty = true; _read = multifile_stream; _write = multifile_stream; + _owns_stream = owns_pointer; _write->seekp(0, ios::beg); // Check whether the read stream is empty. @@ -338,8 +339,17 @@ close() { flush(); } + if (_owns_stream) { + if (_read != (istream *)NULL) { + VirtualFileSystem::close_read_file(_read); + } else if (_write != (ostream *)NULL) { + delete _write; + } + } + _read = (istream *)NULL; _write = (ostream *)NULL; + _owns_stream = false; _next_index = 0; _last_index = 0; _needs_repack = false; diff --git a/panda/src/express/multifile.h b/panda/src/express/multifile.h index ef32332a83..16acae80b8 100644 --- a/panda/src/express/multifile.h +++ b/panda/src/express/multifile.h @@ -40,14 +40,15 @@ private: PUBLISHED: BLOCKING bool open_read(const Filename &multifile_name); - BLOCKING bool open_read(istream *multifile_stream); + BLOCKING bool open_read(istream *multifile_stream, bool owns_pointer = false); BLOCKING bool open_write(const Filename &multifile_name); - BLOCKING bool open_write(ostream *multifile_stream); + BLOCKING bool open_write(ostream *multifile_stream, bool owns_pointer = false); BLOCKING bool open_read_write(const Filename &multifile_name); - BLOCKING bool open_read_write(iostream *multifile_stream); + BLOCKING bool open_read_write(iostream *multifile_stream, bool owns_pointer = false); BLOCKING void close(); INLINE const Filename &get_multifile_name() const; + INLINE void set_multifile_name(const Filename &multifile_name); INLINE bool is_read_valid() const; INLINE bool is_write_valid() const; @@ -164,6 +165,7 @@ private: istream *_read; ostream *_write; + bool _owns_stream; streampos _next_index; streampos _last_index; diff --git a/panda/src/express/virtualFileSimple.I b/panda/src/express/virtualFileSimple.I index 95fb498260..8679de57f0 100644 --- a/panda/src/express/virtualFileSimple.I +++ b/panda/src/express/virtualFileSimple.I @@ -27,6 +27,17 @@ VirtualFileSimple(VirtualFileMount *mount, const Filename &local_filename, { } +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSimple::get_mount +// Access: Published, Virtual +// Description: Returns the VirtualFileMount this file is associated +// with. +//////////////////////////////////////////////////////////////////// +INLINE VirtualFileMount *VirtualFileSimple:: +get_mount() const { + return _mount; +} + //////////////////////////////////////////////////////////////////// // Function: VirtualFileSimple::is_implicit_pz_file // Access: Published diff --git a/panda/src/express/virtualFileSimple.h b/panda/src/express/virtualFileSimple.h index 3f721551d0..12e00204aa 100644 --- a/panda/src/express/virtualFileSimple.h +++ b/panda/src/express/virtualFileSimple.h @@ -33,6 +33,7 @@ public: bool implicit_pz_file); virtual VirtualFileSystem *get_file_system() const; + INLINE VirtualFileMount *get_mount() const; virtual Filename get_filename() const; virtual bool has_file() const; diff --git a/panda/src/express/virtualFileSystem.I b/panda/src/express/virtualFileSystem.I index 5f55ca9a3a..91751ee051 100644 --- a/panda/src/express/virtualFileSystem.I +++ b/panda/src/express/virtualFileSystem.I @@ -33,7 +33,7 @@ exists(const Filename &filename) const { //////////////////////////////////////////////////////////////////// INLINE bool VirtualFileSystem:: is_directory(const Filename &filename) const { - PT(VirtualFile) file = get_file(filename); + PT(VirtualFile) file = get_file(filename, true); return (file != (VirtualFile *)NULL && file->is_directory()); } @@ -45,7 +45,7 @@ is_directory(const Filename &filename) const { //////////////////////////////////////////////////////////////////// INLINE bool VirtualFileSystem:: is_regular_file(const Filename &filename) const { - PT(VirtualFile) file = get_file(filename); + PT(VirtualFile) file = get_file(filename, true); return (file != (VirtualFile *)NULL && file->is_regular_file()); } @@ -59,7 +59,7 @@ is_regular_file(const Filename &filename) const { //////////////////////////////////////////////////////////////////// INLINE void VirtualFileSystem:: ls(const string &filename) const { - PT(VirtualFile) file = get_file(filename); + PT(VirtualFile) file = get_file(filename, true); if (file == (VirtualFile *)NULL) { express_cat.info() << "Not found: " << filename << "\n"; @@ -79,7 +79,7 @@ ls(const string &filename) const { //////////////////////////////////////////////////////////////////// INLINE void VirtualFileSystem:: ls_all(const string &filename) const { - PT(VirtualFile) file = get_file(filename); + PT(VirtualFile) file = get_file(filename, true); if (file == (VirtualFile *)NULL) { express_cat.info() << "Not found: " << filename << "\n"; @@ -123,7 +123,7 @@ read_file(const Filename &filename, bool auto_unwrap) const { //////////////////////////////////////////////////////////////////// INLINE bool VirtualFileSystem:: read_file(const Filename &filename, string &result, bool auto_unwrap) const { - PT(VirtualFile) file = get_file(filename); + PT(VirtualFile) file = get_file(filename, false); return (file != (VirtualFile *)NULL && file->read_file(result, auto_unwrap)); } @@ -142,6 +142,6 @@ read_file(const Filename &filename, string &result, bool auto_unwrap) const { //////////////////////////////////////////////////////////////////// INLINE bool VirtualFileSystem:: read_file(const Filename &filename, pvector &result, bool auto_unwrap) const { - PT(VirtualFile) file = get_file(filename); + PT(VirtualFile) file = get_file(filename, false); return (file != (VirtualFile *)NULL && file->read_file(result, auto_unwrap)); } diff --git a/panda/src/express/virtualFileSystem.cxx b/panda/src/express/virtualFileSystem.cxx index cf9e1c8e12..53db182426 100644 --- a/panda/src/express/virtualFileSystem.cxx +++ b/panda/src/express/virtualFileSystem.cxx @@ -35,6 +35,7 @@ VirtualFileSystem *VirtualFileSystem::_global_ptr = NULL; VirtualFileSystem:: VirtualFileSystem() { _cwd = "/"; + _mount_seq = 0; } //////////////////////////////////////////////////////////////////// @@ -55,7 +56,7 @@ VirtualFileSystem:: //////////////////////////////////////////////////////////////////// bool VirtualFileSystem:: mount(Multifile *multifile, const string &mount_point, int flags) { - VirtualFileMountMultifile *new_mount = + PT(VirtualFileMountMultifile) new_mount = new VirtualFileMountMultifile(multifile); return mount(new_mount, mount_point, flags); } @@ -91,7 +92,7 @@ mount(const Filename &physical_filename, const string &mount_point, } if (physical_filename.is_directory()) { - VirtualFileMountSystem *new_mount = + PT(VirtualFileMountSystem) new_mount = new VirtualFileMountSystem(physical_filename); return mount(new_mount, mount_point, flags); } else { @@ -120,12 +121,10 @@ mount(const Filename &physical_filename, const string &mount_point, //////////////////////////////////////////////////////////////////// bool VirtualFileSystem:: mount(VirtualFileMount *mount, const string &mount_point, int flags) { - nassertr(mount->_file_system == NULL, false); - mount->_file_system = this; - mount->_mount_point = normalize_mount_point(mount_point); - mount->_mount_flags = flags; - _mounts.push_back(mount); - return true; + _lock.acquire(); + bool result = do_mount(mount, mount_point, flags); + _lock.release(); + return result; } //////////////////////////////////////////////////////////////////// @@ -137,6 +136,7 @@ mount(VirtualFileMount *mount, const string &mount_point, int flags) { //////////////////////////////////////////////////////////////////// int VirtualFileSystem:: unmount(Multifile *multifile) { + _lock.acquire(); Mounts::iterator ri, wi; wi = ri = _mounts.begin(); while (ri != _mounts.end()) { @@ -163,6 +163,8 @@ unmount(Multifile *multifile) { int num_removed = _mounts.end() - wi; _mounts.erase(wi, _mounts.end()); + ++_mount_seq; + _lock.release(); return num_removed; } @@ -175,6 +177,7 @@ unmount(Multifile *multifile) { //////////////////////////////////////////////////////////////////// int VirtualFileSystem:: unmount(const Filename &physical_filename) { + _lock.acquire(); Mounts::iterator ri, wi; wi = ri = _mounts.begin(); while (ri != _mounts.end()) { @@ -214,6 +217,8 @@ unmount(const Filename &physical_filename) { int num_removed = _mounts.end() - wi; _mounts.erase(wi, _mounts.end()); + ++_mount_seq; + _lock.release(); return num_removed; } @@ -226,6 +231,7 @@ unmount(const Filename &physical_filename) { //////////////////////////////////////////////////////////////////// int VirtualFileSystem:: unmount(VirtualFileMount *mount) { + _lock.acquire(); Mounts::iterator ri, wi; wi = ri = _mounts.begin(); while (ri != _mounts.end()) { @@ -243,6 +249,8 @@ unmount(VirtualFileMount *mount) { int num_removed = _mounts.end() - wi; _mounts.erase(wi, _mounts.end()); + ++_mount_seq; + _lock.release(); return num_removed; } @@ -255,6 +263,7 @@ unmount(VirtualFileMount *mount) { //////////////////////////////////////////////////////////////////// int VirtualFileSystem:: unmount_point(const string &mount_point) { + _lock.acquire(); Filename nmp = normalize_mount_point(mount_point); Mounts::iterator ri, wi; wi = ri = _mounts.begin(); @@ -275,6 +284,8 @@ unmount_point(const string &mount_point) { int num_removed = _mounts.end() - wi; _mounts.erase(wi, _mounts.end()); + ++_mount_seq; + _lock.release(); return num_removed; } @@ -286,6 +297,7 @@ unmount_point(const string &mount_point) { //////////////////////////////////////////////////////////////////// int VirtualFileSystem:: unmount_all() { + _lock.acquire(); Mounts::iterator ri; for (ri = _mounts.begin(); ri != _mounts.end(); ++ri) { (*ri)->_file_system = NULL; @@ -293,6 +305,8 @@ unmount_all() { int num_removed = _mounts.size(); _mounts.clear(); + ++_mount_seq; + _lock.release(); return num_removed; } @@ -304,7 +318,10 @@ unmount_all() { //////////////////////////////////////////////////////////////////// int VirtualFileSystem:: get_num_mounts() const { - return _mounts.size(); + ((VirtualFileSystem *)this)->_lock.acquire(); + int result = _mounts.size(); + ((VirtualFileSystem *)this)->_lock.release(); + return result; } //////////////////////////////////////////////////////////////////// @@ -312,10 +329,16 @@ get_num_mounts() const { // Access: Published // Description: Returns the nth mount in the system. //////////////////////////////////////////////////////////////////// -VirtualFileMount *VirtualFileSystem:: +PT(VirtualFileMount) VirtualFileSystem:: get_mount(int n) const { - nassertr(n >= 0 && n < (int)_mounts.size(), NULL); - return _mounts[n]; + ((VirtualFileSystem *)this)->_lock.acquire(); + nassertd(n >= 0 && n < (int)_mounts.size()) { + ((VirtualFileSystem *)this)->_lock.release(); + return NULL; + } + PT(VirtualFileMount) result = _mounts[n]; + ((VirtualFileSystem *)this)->_lock.release(); + return result; } //////////////////////////////////////////////////////////////////// @@ -331,17 +354,21 @@ get_mount(int n) const { //////////////////////////////////////////////////////////////////// bool VirtualFileSystem:: chdir(const string &new_directory) { + _lock.acquire(); if (new_directory == "/") { // We can always return to the root. _cwd = new_directory; + _lock.release(); return true; } - PT(VirtualFile) file = get_file(new_directory, true); + PT(VirtualFile) file = do_get_file(new_directory, true); if (file != (VirtualFile *)NULL && file->is_directory()) { _cwd = file->get_filename(); + _lock.release(); return true; } + _lock.release(); return false; } @@ -350,9 +377,12 @@ chdir(const string &new_directory) { // Access: Published // Description: Returns the current directory name. See chdir(). //////////////////////////////////////////////////////////////////// -const Filename &VirtualFileSystem:: +Filename VirtualFileSystem:: get_cwd() const { - return _cwd; + ((VirtualFileSystem *)this)->_lock.acquire(); + Filename result = _cwd; + ((VirtualFileSystem *)this)->_lock.release(); + return result; } //////////////////////////////////////////////////////////////////// @@ -373,72 +403,10 @@ get_cwd() const { //////////////////////////////////////////////////////////////////// PT(VirtualFile) VirtualFileSystem:: get_file(const Filename &filename, bool status_only) const { - nassertr(!filename.empty(), NULL); - Filename pathname(filename); - if (pathname.is_local()) { - pathname = Filename(_cwd, filename); - if (filename.is_text()) { - pathname.set_text(); - } - } - pathname.standardize(); - string strpath = pathname.get_filename_index(0).get_fullpath().substr(1); - // Also transparently look for a regular file suffixed .pz. - string strpath_pz = strpath + ".pz"; - - // 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 (consider_match(found_file, composite_file, mount, "", pathname, - false, status_only)) { - return found_file; - } - } else if (mount_point.empty()) { - // This is the root mount point; all files are in here. - if (consider_match(found_file, composite_file, mount, strpath, - pathname, false, status_only)) { - return found_file; - } -#ifdef HAVE_ZLIB - if (vfs_implicit_pz) { - if (consider_match(found_file, composite_file, mount, strpath_pz, - pathname, true, status_only)) { - return found_file; - } - } -#endif // HAVE_ZLIB - - } 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); - Filename local_filename_pz = strpath_pz.substr(mount_point.length() + 1); - if (consider_match(found_file, composite_file, mount, local_filename, - pathname, false, status_only)) { - return found_file; - } -#ifdef HAVE_ZLIB - if (vfs_implicit_pz) { - // Bingo! - if (consider_match(found_file, composite_file, mount, local_filename_pz, - pathname, true, status_only)) { - return found_file; - } - } -#endif // HAVE_ZLIB - } - } - return found_file; + ((VirtualFileSystem *)this)->_lock.acquire(); + PT(VirtualFile) result = do_get_file(filename, status_only); + ((VirtualFileSystem *)this)->_lock.release(); + return result; } //////////////////////////////////////////////////////////////////// @@ -575,12 +543,14 @@ find_all_files(const Filename &filename, const DSearchPath &searchpath, //////////////////////////////////////////////////////////////////// void VirtualFileSystem:: write(ostream &out) const { + ((VirtualFileSystem *)this)->_lock.acquire(); out << "_cwd" << _cwd << "\n_mounts:\n"; Mounts::const_iterator mi; for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) { VirtualFileMount *mount = (*mi); mount->write(out); } + ((VirtualFileSystem *)this)->_lock.release(); } @@ -708,7 +678,7 @@ open_read_file(const Filename &filename, bool auto_unwrap) const { //////////////////////////////////////////////////////////////////// // Function: VirtualFileSystem::close_read_file -// Access: Published +// Access: Published, Static // 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 @@ -716,7 +686,7 @@ open_read_file(const Filename &filename, bool auto_unwrap) const { // work around compiler issues. //////////////////////////////////////////////////////////////////// void VirtualFileSystem:: -close_read_file(istream *stream) const { +close_read_file(istream *stream) { 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 @@ -782,6 +752,8 @@ scan_mount_points(vector_string &names, const Filename &path) const { // to standard form (relative to the current directory, // with no double slashes, and not terminating with a // slash). The initial slash is removed. +// +// Assumes the lock is already held. //////////////////////////////////////////////////////////////////// Filename VirtualFileSystem:: normalize_mount_point(const string &mount_point) const { @@ -794,6 +766,125 @@ normalize_mount_point(const string &mount_point) const { return nmp.get_fullpath().substr(1); } +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::do_mount +// Access: Private +// Description: The private implementation of mount(). Assumes the +// lock is already held. +//////////////////////////////////////////////////////////////////// +bool VirtualFileSystem:: +do_mount(VirtualFileMount *mount, const string &mount_point, int flags) { + nassertr(mount->_file_system == NULL, false); + mount->_file_system = this; + mount->_mount_point = normalize_mount_point(mount_point); + mount->_mount_flags = flags; + _mounts.push_back(mount); + ++_mount_seq; + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::do_get_file +// Access: Private +// Description: The private implementation of get_file(). Assumes +// the lock is already held. +//////////////////////////////////////////////////////////////////// +PT(VirtualFile) VirtualFileSystem:: +do_get_file(const Filename &filename, bool status_only) const { + nassertr(!filename.empty(), NULL); + Filename pathname(filename); + if (pathname.is_local()) { + pathname = Filename(_cwd, filename); + if (filename.is_text()) { + pathname.set_text(); + } + } + pathname.standardize(); + string strpath = pathname.get_filename_index(0).get_fullpath().substr(1); + // Also transparently look for a regular file suffixed .pz. + string strpath_pz = strpath + ".pz"; + + // 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; + + // We use an index instead of an iterator, since the vector might + // change if implicit mounts are added during this loop. + unsigned int start_seq = _mount_seq; + + size_t i = _mounts.size(); + while (i > 0) { + --i; + VirtualFileMount *mount = _mounts[i]; + 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 (consider_match(found_file, composite_file, mount, "", pathname, + false, status_only)) { + return found_file; + } + } else if (mount_point.empty()) { + // This is the root mount point; all files are in here. + if (consider_match(found_file, composite_file, mount, strpath, + pathname, false, status_only)) { + return found_file; + } +#ifdef HAVE_ZLIB + if (vfs_implicit_pz) { + if (consider_match(found_file, composite_file, mount, strpath_pz, + pathname, true, status_only)) { + return found_file; + } + } +#endif // HAVE_ZLIB + + } 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); + Filename local_filename_pz = strpath_pz.substr(mount_point.length() + 1); + if (consider_match(found_file, composite_file, mount, local_filename, + pathname, false, status_only)) { + return found_file; + } +#ifdef HAVE_ZLIB + if (vfs_implicit_pz) { + // Bingo! + if (consider_match(found_file, composite_file, mount, local_filename_pz, + pathname, true, status_only)) { + return found_file; + } + } +#endif // HAVE_ZLIB + } + + // If we discover that a file has been implicitly mounted during + // one of the above operations, start over from the beginning of + // the loop. + if (start_seq != _mount_seq) { + start_seq = _mount_seq; + i = _mounts.size(); + } + } + + if (found_file == (VirtualFile *)NULL && vfs_implicit_mf) { + // The file wasn't found, as-is. Does it appear to be an implicit + // .mf file reference? + ((VirtualFileSystem *)this)->consider_mount_mf(filename); + + if (start_seq != _mount_seq) { + // Yes, it was, or some nested file was. Now that we've + // implicitly mounted the .mf file, go back and look again. + return do_get_file(filename, status_only); + } + } + + return found_file; +} + //////////////////////////////////////////////////////////////////// // Function: VirtualFileSystem::consider_match // Access: Private @@ -859,6 +950,65 @@ consider_match(PT(VirtualFile) &found_file, VirtualFileComposite *&composite_fil return false; } +//////////////////////////////////////////////////////////////////// +// Function: VirtualFileSystem::consider_mount_mf +// Access: Private +// Description: The indicated filename was not found. Check to see +// if it is using an implicit reference to a .mf file as +// a directory, that hasn't already been mounted. If it +// is, mount the .mf file in-place, and return true; if +// it is not, or if its .mf file is already mounted +// in-place, return false. +// +// Assumes the lock is already held. +//////////////////////////////////////////////////////////////////// +bool VirtualFileSystem:: +consider_mount_mf(const Filename &filename) { + Filename dirname = filename.get_dirname(); + if (dirname.empty()) { + // Reached the top directory; no .mf file references. + return false; + } + if (is_directory(dirname)) { + // Reached a real (or already-mounted) directory; no unmounted .mf + // file references. + return false; + } + if (dirname.get_extension() == "mf") { + // Hey, here's a multifile reference! + dirname.set_binary(); + PT(VirtualFile) file = do_get_file(dirname, false); + if (file == (VirtualFile *)NULL || !file->is_regular_file()) { + // Oh, never mind. Not a real file. + return false; + } + + PT(Multifile) multifile = new Multifile; + + istream *stream = file->open_read_file(false); + if (stream == (istream *)NULL) { + // Couldn't read file. + return false; + } + + if (!multifile->open_read(stream, true)) { + // Invalid multifile. + return false; + } + + multifile->set_multifile_name(dirname.get_basename()); + express_cat.info() + << "Implicitly mounting " << dirname << "\n"; + + PT(VirtualFileMountMultifile) new_mount = + new VirtualFileMountMultifile(multifile); + return do_mount(new_mount, dirname, MF_read_only); + } + + // Recurse. + return consider_mount_mf(dirname); +} + //////////////////////////////////////////////////////////////////// // Function: VirtualFileSystem::parse_option // Access: Private, Static diff --git a/panda/src/express/virtualFileSystem.h b/panda/src/express/virtualFileSystem.h index fd3a89ed58..cda07fd671 100644 --- a/panda/src/express/virtualFileSystem.h +++ b/panda/src/express/virtualFileSystem.h @@ -23,6 +23,7 @@ #include "dSearchPath.h" #include "pointerTo.h" #include "config_express.h" +#include "mutexImpl.h" #include "pvector.h" class Multifile; @@ -59,10 +60,10 @@ PUBLISHED: BLOCKING int unmount_all(); int get_num_mounts() const; - VirtualFileMount *get_mount(int n) const; + PT(VirtualFileMount) get_mount(int n) const; BLOCKING bool chdir(const string &new_directory); - BLOCKING const Filename &get_cwd() const; + BLOCKING Filename get_cwd() const; BLOCKING PT(VirtualFile) get_file(const Filename &filename, bool status_only = false) const; BLOCKING PT(VirtualFile) find_file(const Filename &filename, @@ -86,7 +87,7 @@ PUBLISHED: BLOCKING INLINE string read_file(const Filename &filename, bool auto_unwrap) const; BLOCKING istream *open_read_file(const Filename &filename, bool auto_unwrap) const; - BLOCKING void close_read_file(istream *stream) const; + BLOCKING static void close_read_file(istream *stream); public: INLINE bool read_file(const Filename &filename, string &result, bool auto_unwrap) const; @@ -96,15 +97,21 @@ public: private: Filename normalize_mount_point(const string &mount_point) const; + bool do_mount(VirtualFileMount *mount, const string &mount_point, int flags); + PT(VirtualFile) do_get_file(const Filename &filename, bool status_only) const; bool consider_match(PT(VirtualFile) &found_file, VirtualFileComposite *&composite_file, VirtualFileMount *mount, const string &local_filename, const Filename &original_filename, bool implicit_pz_file, bool status_only) const; + bool consider_mount_mf(const Filename &filename); static void parse_option(const string &option, int &flags, string &password); + MutexImpl _lock; typedef pvector Mounts; Mounts _mounts; + unsigned int _mount_seq; + Filename _cwd; static VirtualFileSystem *_global_ptr;