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();
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 return (result !=
nullptr) ? result->is_directory() :
false;
516 int open_flags = status_only ? OF_status_only : 0;
518 PT(
VirtualFile) result = do_get_file(filename, open_flags);
532 PT(
VirtualFile) result = do_get_file(filename, OF_create_file);
544 bool status_only)
const {
546 return get_file(filename, status_only);
550 for (
int i = 0; i < num_directories; ++i) {
561 if (found_file !=
nullptr) {
577 if (file ==
nullptr) {
581 return file->delete_file();
598 PT(
VirtualFile) orig_file = do_get_file(orig_filename, OF_status_only);
599 if (orig_file ==
nullptr) {
604 PT(
VirtualFile) new_file = do_get_file(new_filename, OF_status_only | OF_allow_nonexist);
605 if (new_file ==
nullptr) {
612 return orig_file->rename_file(new_file);
622 if (orig_file ==
nullptr) {
627 if (new_file ==
nullptr) {
631 return orig_file->copy_file(new_file);
642 const string &default_extension)
const {
646 found =
find_file(filename, searchpath,
true);
648 if (found.is_null()) {
651 if (filename.
get_extension().empty() && !default_extension.empty()) {
654 found =
find_file(try_ext, searchpath,
true);
664 if (filename.
get_extension().empty() && !default_extension.empty()) {
672 if (!found.is_null()) {
673 filename = found->get_original_filename();
695 for (
int i = 0; i < num_directories; ++i) {
720 write(ostream &out)
const {
722 Mounts::const_iterator mi;
723 for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) {
742 if (_global_ptr ==
nullptr) {
749 _global_ptr->
mount(
"/",
"/", 0);
757 PRC_DESC(
"vfs-mount system-filename mount-point [options]"));
760 for (
int i = 0; i < num_unique_values; i++) {
773 size_t space = mount_desc.rfind(
' ');
774 if (space == string::npos) {
775 express_cat.warning()
776 <<
"No space in vfs-mount descriptor: " << mount_desc <<
"\n";
779 string mount_point = mount_desc.substr(space + 1);
780 while (space > 0 && isspace(mount_desc[space - 1])) {
783 mount_desc = mount_desc.substr(0, space);
786 space = mount_desc.rfind(
' ');
787 if (space != string::npos) {
789 options = mount_point;
790 mount_point = mount_desc.substr(space + 1);
791 while (space > 0 && isspace(mount_desc[space - 1])) {
794 mount_desc = mount_desc.substr(0, space);
803 _global_ptr->
mount(physical_filename, mount_point, flags, password);
808 (
"vfs-mount-ramdisk",
"",
809 PRC_DESC(
"vfs-mount-ramdisk mount-point [options]"));
810 if (!vfs_mount_ramdisk.empty()) {
811 string mount_point = vfs_mount_ramdisk;
814 size_t space = mount_point.rfind(
' ');
815 if (space != string::npos) {
817 options = mount_point.substr(space + 1);
818 while (space > 0 && isspace(mount_point[space - 1])) {
821 mount_point = mount_point.substr(0, space);
829 _global_ptr->
mount(ramdisk, mount_point, flags);
848 if (file ==
nullptr) {
851 istream *str = file->open_read_file(auto_unwrap);
852 if (str !=
nullptr && str->fail()) {
867 if (stream !=
nullptr) {
872 #if (!defined(WIN32_VC) && !defined(WIN64_VC)) && !defined(USE_MEMORY_NOWRAPPERS) && defined(REDEFINE_GLOBAL_OPERATOR_NEW)
874 (*global_operator_delete)(stream);
892 if (file ==
nullptr) {
895 ostream *str = file->open_write_file(auto_wrap, truncate);
896 if (str !=
nullptr && str->fail()) {
911 if (file ==
nullptr) {
914 ostream *str = file->open_append_file();
915 if (str !=
nullptr && str->fail()) {
930 if (stream !=
nullptr) {
931 #if (!defined(WIN32_VC) && !defined(WIN64_VC)) && !defined(USE_MEMORY_NOWRAPPERS) && defined(REDEFINE_GLOBAL_OPERATOR_NEW)
933 (*global_operator_delete)(stream);
948 if (file ==
nullptr) {
951 iostream *str = file->open_read_write_file(truncate);
952 if (str !=
nullptr && str->fail()) {
967 if (file ==
nullptr) {
970 iostream *str = file->open_read_append_file();
971 if (str !=
nullptr && str->fail()) {
986 if (stream !=
nullptr) {
987 #if (!defined(WIN32_VC) && !defined(WIN64_VC)) && !defined(USE_MEMORY_NOWRAPPERS) && defined(REDEFINE_GLOBAL_OPERATOR_NEW)
989 (*global_operator_delete)(stream);
1001 const string &old_contents,
1002 const string &new_contents) {
1004 if (file ==
nullptr) {
1008 return file->atomic_compare_and_exchange_contents(orig_contents, old_contents, new_contents);
1017 if (file ==
nullptr) {
1021 return file->atomic_read_contents(contents);
1034 nassertv(!path.empty() && !path.
is_local());
1036 Mounts::const_iterator mi;
1037 for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) {
1040 string mount_point =
mount->get_mount_point();
1041 if (prefix.empty()) {
1043 if (mount_point.find(
'/') == string::npos) {
1046 names.push_back(mount_point);
1049 if (mount_point.substr(0, prefix.length()) == prefix &&
1050 mount_point.length() > prefix.length() &&
1051 mount_point[prefix.length()] ==
'/') {
1054 string basename = mount_point.substr(prefix.length());
1055 if (basename.find(
'/') == string::npos) {
1057 names.push_back(basename);
1070 parse_options(
const string &options,
int &flags,
string &password) {
1072 password = string();
1076 size_t q = options.find(
',', p);
1077 while (q != string::npos) {
1081 q = options.find(
',', p);
1091 parse_option(
const string &option,
int &flags,
string &password) {
1092 if (option ==
"0" || option.empty()) {
1094 }
else if (option ==
"ro") {
1095 flags |= MF_read_only;
1096 }
else if (option.substr(0, 3) ==
"pw:") {
1097 password = option.substr(3);
1099 express_cat.warning()
1100 <<
"Invalid option on vfs-mount: \"" << option <<
"\"\n";
1112 normalize_mount_point(
const Filename &mount_point)
const {
1118 nassertr(!nmp.empty() && nmp[0] ==
'/', nmp);
1125 bool VirtualFileSystem::
1127 nassertr(
mount->_file_system ==
nullptr,
false);
1128 mount->_file_system =
this;
1129 mount->_mount_point = normalize_mount_point(mount_point);
1130 mount->_mount_flags = flags;
1131 _mounts.push_back(
mount);
1141 do_get_file(
const Filename &filename,
int open_flags)
const {
1142 if (filename.empty()) {
1146 if (pathname.is_local()) {
1147 pathname =
Filename(_cwd, filename);
1149 pathname.set_text();
1152 pathname.standardize();
1156 Filename strpath_pz = strpath +
".pz";
1165 unsigned int start_seq = _mount_seq;
1167 size_t i = _mounts.size();
1172 if (strpath == mount_point) {
1175 if (consider_match(found_file, composite_file,
mount,
"", pathname,
1176 false, open_flags)) {
1179 }
else if (mount_point.empty()) {
1181 if (consider_match(found_file, composite_file,
mount, strpath,
1182 pathname,
false, open_flags)) {
1186 if (vfs_implicit_pz) {
1187 if (consider_match(found_file, composite_file,
mount, strpath_pz,
1188 pathname,
true, open_flags)) {
1194 }
else if (strpath.length() > mount_point.length() &&
1195 mount_point == strpath.substr(0, mount_point.length()) &&
1196 strpath[mount_point.length()] ==
'/') {
1198 Filename local_filename = strpath.substr(mount_point.length() + 1);
1199 Filename local_filename_pz = strpath_pz.substr(mount_point.length() + 1);
1200 if (consider_match(found_file, composite_file,
mount, local_filename,
1201 pathname,
false, open_flags)) {
1205 if (vfs_implicit_pz) {
1207 if (consider_match(found_file, composite_file,
mount, local_filename_pz,
1208 pathname,
true, open_flags)) {
1217 if (start_seq != _mount_seq) {
1218 start_seq = _mount_seq;
1223 if (found_file ==
nullptr && vfs_implicit_mf) {
1228 if (start_seq != _mount_seq) {
1231 return do_get_file(filename, open_flags);
1235 #if defined(_WIN32) && !defined(NDEBUG)
1239 if (filename.length() > 2 && isalpha(filename[0]) && filename[1] ==
':' &&
1240 (filename[2] ==
'\\' || filename[2] ==
'/')) {
1243 if (corrected_fn.
exists()) {
1244 express_cat.warning()
1245 <<
"Filename uses Windows-style path: " << filename <<
"\n";
1246 express_cat.warning()
1247 <<
" expected Unix-style path: " << corrected_fn <<
"\n";
1265 bool VirtualFileSystem::
1268 const Filename &original_filename,
bool implicit_pz_file,
1269 int open_flags)
const {
1271 mount->make_virtual_file(local_filename, original_filename,
false, open_flags);
1272 if (!vfile->has_file() && ((open_flags & OF_allow_nonexist) == 0)) {
1277 if (found_file ==
nullptr) {
1280 if (!found_file->
is_directory() || ((open_flags & OF_make_directory) != 0)) {
1286 if (implicit_pz_file) {
1288 found_file =
nullptr;
1294 if (!vfile->is_directory()) {
1299 if (!implicit_pz_file) {
1302 if (composite_file ==
nullptr) {
1307 found_file = composite_file;
1326 bool VirtualFileSystem::
1327 consider_mount_mf(
const Filename &filename) {
1329 if (dirname.empty() || dirname == filename) {
1341 PT(
VirtualFile) file = do_get_file(dirname,
false);
1342 if (file ==
nullptr || !file->is_regular_file()) {
1349 istream *stream = file->open_read_file(
false);
1350 if (stream ==
nullptr) {
1359 if (!multifile->open_read(streamw,
true)) {
1366 <<
"Implicitly mounting " << dirname <<
"\n";
1370 return do_mount(new_mount, dirname, MF_read_only);
1374 return consider_mount_mf(dirname);
This class is similar to ConfigVariable, but it reports its value as a list of strings.
std::string get_unique_value(size_t n) const
Returns the nth unique value of the variable.
size_t get_num_unique_values() const
Returns the number of unique values in the variable.
This is a convenience class to specialize ConfigVariable as a string type.
void add_file(const Filename &file)
Adds a new file to the result list.
This class stores a list of directories that can be searched, in order, to locate a particular file.
get_num_directories
Returns the number of directories on the search list.
get_directory
Returns the nth directory on the search list.
static std::string expand_string(const std::string &str)
Reads the string, looking for environment variable names marked by a $.
get_cwd
Returns the name of the current working directory.
The name of a file, such as a texture file or an Egg file.
void set_type(Type type)
Sets the type of the file represented by the filename.
bool is_fully_qualified() const
Returns true if the filename is fully qualified, e.g.
std::string get_basename() const
Returns the basename part of the filename.
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 is_text() const
Returns true if the Filename has been indicated to represent a text file via a previous call to set_t...
void standardize()
Converts the filename to standard form by replacing consecutive slashes with a single slash,...
void set_binary()
Indicates that the filename represents a binary file.
std::string get_fullpath() const
Returns the entire filename: directory, basename, extension.
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,...
void set_extension(const std::string &s)
Replaces the file extension.
bool is_directory() const
Returns true if the filename exists and is a directory name, false otherwise.
std::string get_extension() const
Returns the file extension.
bool is_local() const
Returns true if the filename is local, e.g.
std::string get_dirname() const
Returns the directory part of the filename.
Type get_type() const
Returns the type of the file represented by the filename, as previously set by set_type().
bool exists() const
Returns true if the filename exists on the disk, false otherwise.
This class provides a locking wrapper around an arbitrary istream pointer.
A file that contains a set of files.
const Filename & get_multifile_name() const
Returns the filename of the Multifile, if it is available.
void set_encryption_password(const std::string &encryption_password)
Specifies the password that will be used to encrypt subfiles subsequently added to the multifile,...
A composite directory within the VirtualFileSystem: this maps to more than one directory on different...
void add_component(VirtualFile *file)
Adds one more component to the composite directory.
Maps a Multifile's contents into the VirtualFileSystem.
Multifile * get_multifile() const
Returns the Multifile pointer that this mount object is based on.
Simulates an actual directory on disk with in-memory storage.
Maps an actual OS directory into the VirtualFileSystem.
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.
The abstract base class for a mount definition used within a VirtualFileSystem.
A hierarchy of directories and files that appears to be one continuous file system,...
bool rename_file(const Filename &orig_filename, const Filename &new_filename)
Attempts to move or rename the indicated file or directory.
static void close_write_file(std::ostream *stream)
Closes a file opened by a previous call to open_write_file().
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,...
int unmount_point(const Filename &mount_point)
Unmounts all systems attached to the given mount point from the file system.
Filename get_cwd() const
Returns the current directory name.
void write(std::ostream &out) const
Print debugging information.
bool exists(const Filename &filename) const
Convenience function; returns true if the named file exists.
int unmount(Multifile *multifile)
Unmounts all appearances of the indicated Multifile from the file system.
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.
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.
bool resolve_filename(Filename &filename, const DSearchPath &searchpath, const std::string &default_extension=std::string()) const
Searches the given search path for the filename.
std::ostream * open_append_file(const Filename &filename)
Works like open_write_file(), but the file is opened in append mode.
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,...
static void close_read_file(std::istream *stream)
Closes a file opened by a previous call to open_read_file().
static void close_read_write_file(std::iostream *stream)
Closes a file opened by a previous call to open_read_write_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.
PointerTo< VirtualFile > create_file(const Filename &filename)
Attempts to create a file by the indicated name in the filesystem, if possible, and returns it.
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.
std::iostream * open_read_append_file(const Filename &filename)
Works like open_read_write_file(), but the file is opened in append mode.
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...
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,...
get_mount
Returns the nth mount in the system.
bool is_directory(const Filename &filename) const
Convenience function; returns true if the named file exists and is a directory.
bool chdir(const Filename &new_directory)
Changes the current directory.
get_num_mounts
Returns the number of individual mounts in the system.
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().
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the 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,...
bool delete_file(const Filename &filename)
Attempts to delete the indicated file or directory.
bool make_directory_full(const Filename &filename)
Attempts to create a directory within the file system.
bool make_directory(const Filename &filename)
Attempts to create a directory within the file system.
bool mount(Multifile *multifile, const Filename &mount_point, int flags)
Mounts the indicated Multifile at the given mount point.
bool copy_file(const Filename &orig_filename, const Filename &new_filename)
Attempts to copy the contents of the indicated file to the indicated file.
int unmount_all()
Unmounts all files from the file system.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
bool atomic_read_contents(const Filename &filename, std::string &contents) const
See Filename::atomic_read_contents().
The abstract base class for a file or directory within the VirtualFileSystem.
const Filename & get_original_filename() const
Returns the original filename as it was used to locate this VirtualFile.
virtual bool is_directory() const
Returns true if this file represents a directory (and scan_directory() may be called),...
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void init_libexpress()
Initializes the library.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.