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,...
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),...
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,...
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,...