44 (
"vfs-case-sensitive",
51 PRC_DESC(
"Set this true to make the VirtualFileSystem present the native " 52 "OS-provided filesystem as if it were a case-sensitive file " 53 "system, even if it is not (e.g. on Windows). This variable " 54 "has no effect if the native filesystem is already case-sensitive, " 55 "and it has no effect on mounted multifile systems, which are " 56 "always case-sensitive.")),
58 (
"vfs-implicit-pz", true,
59 PRC_DESC(
"When this is true, the VirtualFileSystem will pretend a named " 60 "file exists even if it doesn't, as long as a filename with the " 61 "same name and the additional extension .pz does exist. In this " 62 "case, the VirtualFileSystem will implicitly open the .pz file " 63 "and decompress it on-the-fly.")),
65 (
"vfs-implicit-mf", false,
66 PRC_DESC(
"When this is true, the VirtualFileSystem will automatically " 67 "mount multifiles on-the-fly when they are used as directories. " 68 "For instance, opening the file /c/files/foo.mf/dirname/mytex.jpg " 69 "will implicitly retrieve a file named 'dirname/mytex.jpg' " 70 "within the multifile /c/files/foo.mf, even if the multifile " 71 "has not already been mounted. This makes all of your multifiles " 72 "act like directories."))
82 ~VirtualFileSystem() {
93 return mount(new_mount, mount_point, flags);
118 int flags,
const string &password) {
119 if (!physical_filename.
exists()) {
120 express_cat->warning()
121 <<
"Attempt to mount " << physical_filename <<
", not found.\n";
128 return mount(new_mount, mount_point, flags);
136 flags |= MF_read_only;
137 if (!multifile->open_read(physical_filename)) {
141 return mount(multifile, mount_point, flags);
159 int flags,
const string &password) {
161 if (file ==
nullptr) {
162 express_cat->warning()
163 <<
"Attempt to mount " << virtual_filename <<
", not found.\n";
167 if (file->is_directory()) {
170 return mount(new_mount, mount_point, flags);
179 flags |= MF_read_only;
180 if (!multifile->open_read(virtual_filename)) {
184 return mount(multifile, mount_point, flags);
195 if (express_cat->is_debug()) {
197 <<
"mount " << *
mount <<
" under " << mount_point <<
"\n";
201 bool result = do_mount(
mount, mount_point, flags);
213 Mounts::iterator ri, wi;
214 wi = ri = _mounts.begin();
215 while (ri != _mounts.end()) {
219 if (
mount->is_exact_type(VirtualFileMountMultifile::get_class_type())) {
224 if (express_cat->is_debug()) {
226 <<
"unmount " << *
mount <<
" from " <<
mount->get_mount_point() <<
"\n";
228 mount->_file_system =
nullptr;
241 int num_removed = _mounts.end() - wi;
242 _mounts.erase(wi, _mounts.end());
255 Mounts::iterator ri, wi;
256 wi = ri = _mounts.begin();
257 while (ri != _mounts.end()) {
261 if (
mount->is_exact_type(VirtualFileMountSystem::get_class_type())) {
266 if (express_cat->is_debug()) {
268 <<
"unmount " << *
mount <<
" from " <<
mount->get_mount_point() <<
"\n";
270 mount->_file_system =
nullptr;
277 }
else if (
mount->is_exact_type(VirtualFileMountMultifile::get_class_type())) {
282 if (express_cat->is_debug()) {
284 <<
"unmount " << *
mount <<
" from " <<
mount->get_mount_point() <<
"\n";
286 mount->_file_system =
nullptr;
300 int num_removed = _mounts.end() - wi;
301 _mounts.erase(wi, _mounts.end());
314 Mounts::iterator ri, wi;
315 wi = ri = _mounts.begin();
316 while (ri != _mounts.end()) {
318 if ((*ri) ==
mount) {
320 if (express_cat->is_debug()) {
322 <<
"unmount " << *
mount <<
" from " <<
mount->get_mount_point() <<
"\n";
324 (*ri)->_file_system =
nullptr;
333 int num_removed = _mounts.end() - wi;
334 _mounts.erase(wi, _mounts.end());
347 Filename nmp = normalize_mount_point(mount_point);
348 Mounts::iterator ri, wi;
349 wi = ri = _mounts.begin();
350 while (ri != _mounts.end()) {
354 if (
mount->get_mount_point() == nmp) {
356 if (express_cat->is_debug()) {
358 <<
"unmount " << *
mount <<
" from " <<
mount->get_mount_point() <<
"\n";
360 mount->_file_system =
nullptr;
369 int num_removed = _mounts.end() - wi;
370 _mounts.erase(wi, _mounts.end());
384 for (ri = _mounts.begin(); ri != _mounts.end(); ++ri) {
386 if (express_cat->is_debug()) {
388 <<
"unmount " << *
mount <<
" from " <<
mount->get_mount_point() <<
"\n";
390 mount->_file_system =
nullptr;
393 int num_removed = _mounts.size();
403 int VirtualFileSystem::
404 get_num_mounts()
const {
406 int result = _mounts.size();
417 nassertd(n >= 0 && n < (
int)_mounts.size()) {
434 if (new_directory ==
"/") {
436 _cwd = new_directory;
441 PT(
VirtualFile) file = do_get_file(new_directory, OF_status_only);
442 if (file !=
nullptr && file->is_directory()) {
443 _cwd = file->get_filename();
471 PT(
VirtualFile) result = do_get_file(filename, OF_make_directory);
473 nassertr_always(result !=
nullptr,
false);
474 return result->is_directory();
489 string dirname = filename;
490 size_t slash = dirname.find(
'/', 1);
491 while (slash != string::npos) {
492 Filename component(dirname.substr(0, slash));
493 do_get_file(component, OF_make_directory);
494 slash = dirname.find(
'/', slash + 1);
498 PT(
VirtualFile) result = do_get_file(filename, OF_make_directory);
500 nassertr_always(result !=
nullptr,
false);
501 return result->is_directory();
517 int open_flags = status_only ? OF_status_only : 0;
519 PT(
VirtualFile) result = do_get_file(filename, open_flags);
533 PT(
VirtualFile) result = do_get_file(filename, OF_create_file);
545 bool status_only)
const {
547 return get_file(filename, status_only);
551 for (
int i = 0; i < num_directories; ++i) {
562 if (found_file !=
nullptr) {
578 if (file ==
nullptr) {
582 return file->delete_file();
599 PT(
VirtualFile) orig_file = do_get_file(orig_filename, OF_status_only);
600 if (orig_file ==
nullptr) {
605 PT(
VirtualFile) new_file = do_get_file(new_filename, OF_status_only | OF_allow_nonexist);
606 if (new_file ==
nullptr) {
613 return orig_file->rename_file(new_file);
623 if (orig_file ==
nullptr) {
628 if (new_file ==
nullptr) {
632 return orig_file->copy_file(new_file);
643 const string &default_extension)
const {
647 found =
find_file(filename, searchpath,
true);
649 if (found.is_null()) {
652 if (filename.
get_extension().empty() && !default_extension.empty()) {
655 found =
find_file(try_ext, searchpath,
true);
665 if (filename.
get_extension().empty() && !default_extension.empty()) {
673 if (!found.is_null()) {
674 filename = found->get_original_filename();
696 for (
int i = 0; i < num_directories; ++i) {
723 Mounts::const_iterator mi;
724 for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) {
743 if (_global_ptr ==
nullptr) {
750 _global_ptr->
mount(
"/",
"/", 0);
753 _global_ptr->
chdir(ExecutionEnvironment::get_cwd());
758 PRC_DESC(
"vfs-mount system-filename mount-point [options]"));
761 for (
int i = 0; i < num_unique_values; i++) {
774 size_t space = mount_desc.rfind(
' ');
775 if (space == string::npos) {
776 express_cat.warning()
777 <<
"No space in vfs-mount descriptor: " << mount_desc <<
"\n";
780 string mount_point = mount_desc.substr(space + 1);
781 while (space > 0 && isspace(mount_desc[space - 1])) {
784 mount_desc = mount_desc.substr(0, space);
787 space = mount_desc.rfind(
' ');
788 if (space != string::npos) {
790 options = mount_point;
791 mount_point = mount_desc.substr(space + 1);
792 while (space > 0 && isspace(mount_desc[space - 1])) {
795 mount_desc = mount_desc.substr(0, space);
804 _global_ptr->
mount(physical_filename, mount_point, flags, password);
809 (
"vfs-mount-ramdisk",
"",
810 PRC_DESC(
"vfs-mount-ramdisk mount-point [options]"));
811 if (!vfs_mount_ramdisk.empty()) {
812 string mount_point = vfs_mount_ramdisk;
815 size_t space = mount_point.rfind(
' ');
816 if (space != string::npos) {
818 options = mount_point.substr(space + 1);
819 while (space > 0 && isspace(mount_point[space - 1])) {
822 mount_point = mount_point.substr(0, space);
830 _global_ptr->
mount(ramdisk, mount_point, flags);
849 if (file ==
nullptr) {
852 istream *str = file->open_read_file(auto_unwrap);
853 if (str !=
nullptr && str->fail()) {
868 if (stream !=
nullptr) {
873 #if (!defined(WIN32_VC) && !defined(WIN64_VC)) && !defined(USE_MEMORY_NOWRAPPERS) && defined(REDEFINE_GLOBAL_OPERATOR_NEW) 875 (*global_operator_delete)(stream);
893 if (file ==
nullptr) {
896 ostream *str = file->open_write_file(auto_wrap, truncate);
897 if (str !=
nullptr && str->fail()) {
912 if (file ==
nullptr) {
915 ostream *str = file->open_append_file();
916 if (str !=
nullptr && str->fail()) {
931 if (stream !=
nullptr) {
932 #if (!defined(WIN32_VC) && !defined(WIN64_VC)) && !defined(USE_MEMORY_NOWRAPPERS) && defined(REDEFINE_GLOBAL_OPERATOR_NEW) 934 (*global_operator_delete)(stream);
949 if (file ==
nullptr) {
952 iostream *str = file->open_read_write_file(truncate);
953 if (str !=
nullptr && str->fail()) {
968 if (file ==
nullptr) {
971 iostream *str = file->open_read_append_file();
972 if (str !=
nullptr && str->fail()) {
987 if (stream !=
nullptr) {
988 #if (!defined(WIN32_VC) && !defined(WIN64_VC)) && !defined(USE_MEMORY_NOWRAPPERS) && defined(REDEFINE_GLOBAL_OPERATOR_NEW) 990 (*global_operator_delete)(stream);
1002 const string &old_contents,
1003 const string &new_contents) {
1005 if (file ==
nullptr) {
1009 return file->atomic_compare_and_exchange_contents(orig_contents, old_contents, new_contents);
1018 if (file ==
nullptr) {
1022 return file->atomic_read_contents(contents);
1035 nassertv(!path.empty() && !path.
is_local());
1037 Mounts::const_iterator mi;
1038 for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) {
1041 string mount_point =
mount->get_mount_point();
1042 if (prefix.empty()) {
1044 if (mount_point.find(
'/') == string::npos) {
1047 names.push_back(mount_point);
1050 if (mount_point.substr(0, prefix.length()) == prefix &&
1051 mount_point.length() > prefix.length() &&
1052 mount_point[prefix.length()] ==
'/') {
1055 string basename = mount_point.substr(prefix.length());
1056 if (basename.find(
'/') == string::npos) {
1058 names.push_back(basename);
1073 password = string();
1077 size_t q = options.find(
',', p);
1078 while (q != string::npos) {
1082 q = options.find(
',', p);
1093 if (option ==
"0" || option.empty()) {
1095 }
else if (option ==
"ro") {
1096 flags |= MF_read_only;
1097 }
else if (option.substr(0, 3) ==
"pw:") {
1098 password = option.substr(3);
1100 express_cat.warning()
1101 <<
"Invalid option on vfs-mount: \"" << option <<
"\"\n";
1113 normalize_mount_point(
const Filename &mount_point)
const {
1119 nassertr(!nmp.empty() && nmp[0] ==
'/', nmp);
1126 bool VirtualFileSystem::
1128 nassertr(
mount->_file_system ==
nullptr,
false);
1129 mount->_file_system =
this;
1130 mount->_mount_point = normalize_mount_point(mount_point);
1131 mount->_mount_flags = flags;
1132 _mounts.push_back(
mount);
1142 do_get_file(
const Filename &filename,
int open_flags)
const {
1143 if (filename.empty()) {
1147 if (pathname.is_local()) {
1148 pathname =
Filename(_cwd, filename);
1150 pathname.set_text();
1153 pathname.standardize();
1157 Filename strpath_pz = strpath +
".pz";
1166 unsigned int start_seq = _mount_seq;
1168 size_t i = _mounts.size();
1173 if (strpath == mount_point) {
1176 if (consider_match(found_file, composite_file,
mount,
"", pathname,
1177 false, open_flags)) {
1180 }
else if (mount_point.empty()) {
1182 if (consider_match(found_file, composite_file,
mount, strpath,
1183 pathname,
false, open_flags)) {
1187 if (vfs_implicit_pz) {
1188 if (consider_match(found_file, composite_file,
mount, strpath_pz,
1189 pathname,
true, open_flags)) {
1195 }
else if (strpath.length() > mount_point.length() &&
1196 mount_point == strpath.substr(0, mount_point.length()) &&
1197 strpath[mount_point.length()] ==
'/') {
1199 Filename local_filename = strpath.substr(mount_point.length() + 1);
1200 Filename local_filename_pz = strpath_pz.substr(mount_point.length() + 1);
1201 if (consider_match(found_file, composite_file,
mount, local_filename,
1202 pathname,
false, open_flags)) {
1206 if (vfs_implicit_pz) {
1208 if (consider_match(found_file, composite_file,
mount, local_filename_pz,
1209 pathname,
true, open_flags)) {
1218 if (start_seq != _mount_seq) {
1219 start_seq = _mount_seq;
1224 if (found_file ==
nullptr && vfs_implicit_mf) {
1229 if (start_seq != _mount_seq) {
1232 return do_get_file(filename, open_flags);
1236 #if defined(_WIN32) && !defined(NDEBUG) 1240 if (filename.length() > 2 && isalpha(filename[0]) && filename[1] ==
':' &&
1241 (filename[2] ==
'\\' || filename[2] ==
'/')) {
1244 if (corrected_fn.
exists()) {
1245 express_cat.warning()
1246 <<
"Filename uses Windows-style path: " << filename <<
"\n";
1247 express_cat.warning()
1248 <<
" expected Unix-style path: " << corrected_fn <<
"\n";
1266 bool VirtualFileSystem::
1269 const Filename &original_filename,
bool implicit_pz_file,
1270 int open_flags)
const {
1272 mount->make_virtual_file(local_filename, original_filename,
false, open_flags);
1273 if (!vfile->has_file() && ((open_flags & OF_allow_nonexist) == 0)) {
1278 if (found_file ==
nullptr) {
1281 if (!found_file->
is_directory() || ((open_flags & OF_make_directory) != 0)) {
1287 if (implicit_pz_file) {
1289 found_file =
nullptr;
1295 if (!vfile->is_directory()) {
1300 if (!implicit_pz_file) {
1303 if (composite_file ==
nullptr) {
1308 found_file = composite_file;
1327 bool VirtualFileSystem::
1328 consider_mount_mf(
const Filename &filename) {
1330 if (dirname.empty() || dirname == filename) {
1342 PT(
VirtualFile) file = do_get_file(dirname,
false);
1343 if (file ==
nullptr || !file->is_regular_file()) {
1350 istream *stream = file->open_read_file(
false);
1351 if (stream ==
nullptr) {
1360 if (!multifile->open_read(streamw,
true)) {
1367 <<
"Implicitly mounting " << dirname <<
"\n";
1371 return do_mount(new_mount, dirname, MF_read_only);
1375 return consider_mount_mf(dirname);
Filename get_filename_index(int index) const
If the pattern flag is set for this Filename and the filename string actually includes a sequence of ...
bool copy_file(const Filename &orig_filename, const Filename &new_filename)
Attempts to copy the contents of the indicated file to the indicated file.
std::iostream * open_read_append_file(const Filename &filename)
Works like open_read_write_file(), but the file is opened in append mode.
PointerTo< VirtualFile > find_file(const Filename &filename, const DSearchPath &searchpath, bool status_only=false) const
Uses the indicated search path to find the file within the file system.
std::string get_dirname() const
Returns the directory part of the filename.
void set_extension(const std::string &s)
Replaces the file extension.
bool rename_file(const Filename &orig_filename, const Filename &new_filename)
Attempts to move or rename the indicated file or directory.
Multifile * get_multifile() const
Returns the Multifile pointer that this mount object is based on.
int find_all_files(const Filename &filename, const DSearchPath &searchpath, DSearchPath::Results &results) const
Searches all the directories in the search list for the indicated file, in order. ...
static void close_read_write_file(std::iostream *stream)
Closes a file opened by a previous call to open_read_write_file().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
size_t get_num_unique_values() const
Returns the number of unique values in the variable.
Maps an actual OS directory into the VirtualFileSystem.
A hierarchy of directories and files that appears to be one continuous file system, even though the files may originate from several different sources that may not be related to the actual OS's file system.
std::istream * open_read_file(const Filename &filename, bool auto_unwrap) const
Convenience function; returns a newly allocated istream if the file exists and can be read...
void add_component(VirtualFile *file)
Adds one more component to the composite directory.
void set_type(Type type)
Sets the type of the file represented by the filename.
void set_binary()
Indicates that the filename represents a binary file.
void set_original_filename(const Filename &filename)
Stores the original filename that was used to locate this VirtualFile.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void init_libexpress()
Initializes the library.
bool atomic_read_contents(const Filename &filename, std::string &contents) const
See Filename::atomic_read_contents().
bool resolve_filename(Filename &filename, const DSearchPath &searchpath, const std::string &default_extension=std::string()) const
Searches the given search path for the filename.
bool make_directory_full(const Filename &filename)
Attempts to create a directory within the file system.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The abstract base class for a file or directory within the VirtualFileSystem.
bool is_fully_qualified() const
Returns true if the filename is fully qualified, e.g.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class is similar to ConfigVariable, but it reports its value as a list of strings.
PointerTo< VirtualFile > create_file(const Filename &filename)
Attempts to create a file by the indicated name in the filesystem, if possible, and returns it...
void standardize()
Converts the filename to standard form by replacing consecutive slashes with a single slash...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Simulates an actual directory on disk with in-memory storage.
Type get_type() const
Returns the type of the file represented by the filename, as previously set by set_type().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static void close_read_file(std::istream *stream)
Closes a file opened by a previous call to open_read_file().
static void parse_options(const std::string &options, int &flags, std::string &password)
Parses all of the option flags in the options list on the vfs-mount Config.prc line.
get_num_directories
Returns the number of directories on the search list.
bool exists(const Filename &filename) const
Convenience function; returns true if the named file exists.
bool mount(Multifile *multifile, const Filename &mount_point, int flags)
Mounts the indicated Multifile at the given mount point.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool is_directory(const Filename &filename) const
Convenience function; returns true if the named file exists and is a directory.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The name of a file, such as a texture file or an Egg file.
This is a convenience class to specialize ConfigVariable as a string type.
static std::string expand_string(const std::string &str)
Reads the string, looking for environment variable names marked by a $.
This class provides a locking wrapper around an arbitrary istream pointer.
bool make_directory(const Filename &filename)
Attempts to create a directory within the file system.
virtual bool is_directory() const
Returns true if this file represents a directory (and scan_directory() may be called), false otherwise.
std::string get_fullpath() const
Returns the entire filename: directory, basename, extension.
bool chdir(const Filename &new_directory)
Changes the current directory.
std::ostream * open_append_file(const Filename &filename)
Works like open_write_file(), but the file is opened in append mode.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
void scan_mount_points(vector_string &names, const Filename &path) const
Adds to names a list of all the mount points in use that are one directory below path, if any.
const Filename & get_physical_filename() const
Returns the name of the source file on the OS filesystem of the directory or file that is mounted...
int unmount_point(const Filename &mount_point)
Unmounts all systems attached to the given mount point from the file system.
void set_encryption_password(const std::string &encryption_password)
Specifies the password that will be used to encrypt subfiles subsequently added to the multifile...
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
const Filename & get_original_filename() const
Returns the original filename as it was used to locate this VirtualFile.
int unmount(Multifile *multifile)
Unmounts all appearances of the indicated Multifile from the file system.
std::string get_unique_value(size_t n) const
Returns the nth unique value of the variable.
bool is_local() const
Returns true if the filename is local, e.g.
bool is_text() const
Returns true if the Filename has been indicated to represent a text file via a previous call to set_t...
std::string get_extension() const
Returns the file extension.
std::string get_basename() const
Returns the basename part of the filename.
static void close_write_file(std::ostream *stream)
Closes a file opened by a previous call to open_write_file().
static void parse_option(const std::string &option, int &flags, std::string &password)
Parses one of the option flags in the options list on the vfs-mount Config.prc line.
bool mount_loop(const Filename &virtual_filename, const Filename &mount_point, int flags, const std::string &password="")
This is similar to mount(), but it receives the name of a Multifile that already appears within the v...
bool is_directory() const
Returns true if the filename exists and is a directory name, false otherwise.
std::ostream * open_write_file(const Filename &filename, bool auto_wrap, bool truncate)
Convenience function; returns a newly allocated ostream if the file exists and can be written...
The abstract base class for a mount definition used within a VirtualFileSystem.
std::iostream * open_read_write_file(const Filename &filename, bool truncate)
Convenience function; returns a newly allocated iostream if the file exists and can be written...
get_directory
Returns the nth directory on the search list.
A file that contains a set of files.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void write(std::ostream &out) const
Print debugging information.
This class stores a list of directories that can be searched, in order, to locate a particular file...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Filename get_cwd() const
Returns the current directory name.
get_mount
Returns the nth mount in the system.
int unmount_all()
Unmounts all files from the file system.
const Filename & get_multifile_name() const
Returns the filename of the Multifile, if it is available.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool delete_file(const Filename &filename)
Attempts to delete the indicated file or directory.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A composite directory within the VirtualFileSystem: this maps to more than one directory on different...
Maps a Multifile's contents into the VirtualFileSystem.
bool atomic_compare_and_exchange_contents(const Filename &filename, std::string &orig_contents, const std::string &old_contents, const std::string &new_contents)
See Filename::atomic_compare_and_exchange_contents().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool exists() const
Returns true if the filename exists on the disk, false otherwise.
void add_file(const Filename &file)
Adds a new file to the result list.
static Filename from_os_specific(const std::string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes, and no drive letter) based on the supplied filename string that describes a filename in the local system conventions (for instance, on Windows, it may use backslashes or begin with a drive letter and a colon).