00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "virtualFileSystem.h"
00016 #include "virtualFileSimple.h"
00017 #include "virtualFileComposite.h"
00018 #include "virtualFileMount.h"
00019 #include "virtualFileMountMultifile.h"
00020 #include "virtualFileMountRamdisk.h"
00021 #include "virtualFileMountSystem.h"
00022 #include "streamWrapper.h"
00023 #include "dSearchPath.h"
00024 #include "dcast.h"
00025 #include "config_express.h"
00026 #include "executionEnvironment.h"
00027 #include "pset.h"
00028
00029 VirtualFileSystem *VirtualFileSystem::_global_ptr = NULL;
00030
00031
00032
00033
00034
00035
00036
00037 VirtualFileSystem::
00038 VirtualFileSystem() :
00039 vfs_case_sensitive
00040 ("vfs-case-sensitive",
00041 #ifdef NDEBUG
00042 false,
00043
00044 #else
00045 true,
00046 #endif
00047 PRC_DESC("Set this true to make the VirtualFileSystem present the native "
00048 "OS-provided filesystem as if it were a case-sensitive file "
00049 "system, even if it is not (e.g. on Windows). This variable "
00050 "has no effect if the native filesystem is already case-sensitive, "
00051 "and it has no effect on mounted multifile systems, which are "
00052 "always case-sensitive.")),
00053 vfs_implicit_pz
00054 ("vfs-implicit-pz", true,
00055 PRC_DESC("When this is true, the VirtualFileSystem will pretend a named "
00056 "file exists even if it doesn't, as long as a filename with the "
00057 "same name and the additional extension .pz does exist. In this "
00058 "case, the VirtualFileSystem will implicitly open the .pz file "
00059 "and decompress it on-the-fly.")),
00060 vfs_implicit_mf
00061 ("vfs-implicit-mf", false,
00062 PRC_DESC("When this is true, the VirtualFileSystem will automatically "
00063 "mount multifiles on-the-fly when they are used as directories. "
00064 "For instance, opening the file /c/files/foo.mf/dirname/mytex.jpg "
00065 "will implicitly retrieve a file named 'dirname/mytex.jpg' "
00066 "within the multifile /c/files/foo.mf, even if the multifile "
00067 "has not already been mounted. This makes all of your multifiles "
00068 "act like directories."))
00069 {
00070 _cwd = "/";
00071 _mount_seq = 0;
00072 }
00073
00074
00075
00076
00077
00078
00079 VirtualFileSystem::
00080 ~VirtualFileSystem() {
00081 unmount_all();
00082 }
00083
00084
00085
00086
00087
00088
00089
00090 bool VirtualFileSystem::
00091 mount(Multifile *multifile, const Filename &mount_point, int flags) {
00092 PT(VirtualFileMountMultifile) new_mount =
00093 new VirtualFileMountMultifile(multifile);
00094 return mount(new_mount, mount_point, flags);
00095 }
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124 bool VirtualFileSystem::
00125 mount(const Filename &physical_filename, const Filename &mount_point,
00126 int flags, const string &password) {
00127 if (!physical_filename.exists()) {
00128 express_cat->warning()
00129 << "Attempt to mount " << physical_filename << ", not found.\n";
00130 return false;
00131 }
00132
00133 if (physical_filename.is_directory()) {
00134 PT(VirtualFileMountSystem) new_mount =
00135 new VirtualFileMountSystem(physical_filename);
00136 return mount(new_mount, mount_point, flags);
00137 } else {
00138
00139 PT(Multifile) multifile = new Multifile;
00140 multifile->set_encryption_password(password);
00141
00142
00143
00144 flags |= MF_read_only;
00145 if (!multifile->open_read(physical_filename)) {
00146 return false;
00147 }
00148
00149 return mount(multifile, mount_point, flags);
00150 }
00151 }
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171 bool VirtualFileSystem::
00172 mount_loop(const Filename &virtual_filename, const Filename &mount_point,
00173 int flags, const string &password) {
00174 PT(VirtualFile) file = get_file(virtual_filename, false);
00175 if (file == NULL) {
00176 express_cat->warning()
00177 << "Attempt to mount " << virtual_filename << ", not found.\n";
00178 return false;
00179 }
00180
00181 if (file->is_directory()) {
00182 PT(VirtualFileMountSystem) new_mount =
00183 new VirtualFileMountSystem(virtual_filename);
00184 return mount(new_mount, mount_point, flags);
00185
00186 } else {
00187
00188 PT(Multifile) multifile = new Multifile;
00189 multifile->set_encryption_password(password);
00190
00191
00192
00193 flags |= MF_read_only;
00194 if (!multifile->open_read(virtual_filename)) {
00195 return false;
00196 }
00197
00198 return mount(multifile, mount_point, flags);
00199 }
00200 }
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210 bool VirtualFileSystem::
00211 mount(VirtualFileMount *mount, const Filename &mount_point, int flags) {
00212 if (express_cat->is_debug()) {
00213 express_cat->debug()
00214 << "mount " << *mount << " under " << mount_point << "\n";
00215 }
00216
00217 _lock.acquire();
00218 bool result = do_mount(mount, mount_point, flags);
00219 _lock.release();
00220 return result;
00221 }
00222
00223
00224
00225
00226
00227
00228
00229
00230 int VirtualFileSystem::
00231 unmount(Multifile *multifile) {
00232 _lock.acquire();
00233 Mounts::iterator ri, wi;
00234 wi = ri = _mounts.begin();
00235 while (ri != _mounts.end()) {
00236 VirtualFileMount *mount = (*ri);
00237 (*wi) = mount;
00238
00239 if (mount->is_exact_type(VirtualFileMountMultifile::get_class_type())) {
00240 VirtualFileMountMultifile *mmount =
00241 DCAST(VirtualFileMountMultifile, mount);
00242 if (mmount->get_multifile() == multifile) {
00243
00244 if (express_cat->is_debug()) {
00245 express_cat->debug()
00246 << "unmount " << *mount << " from " << mount->get_mount_point() << "\n";
00247 }
00248 mount->_file_system = NULL;
00249
00250 } else {
00251
00252 ++wi;
00253 }
00254 } else {
00255
00256 ++wi;
00257 }
00258 ++ri;
00259 }
00260
00261 int num_removed = _mounts.end() - wi;
00262 _mounts.erase(wi, _mounts.end());
00263 ++_mount_seq;
00264 _lock.release();
00265 return num_removed;
00266 }
00267
00268
00269
00270
00271
00272
00273
00274
00275 int VirtualFileSystem::
00276 unmount(const Filename &physical_filename) {
00277 _lock.acquire();
00278 Mounts::iterator ri, wi;
00279 wi = ri = _mounts.begin();
00280 while (ri != _mounts.end()) {
00281 VirtualFileMount *mount = (*ri);
00282 (*wi) = mount;
00283
00284 if (mount->is_exact_type(VirtualFileMountSystem::get_class_type())) {
00285 VirtualFileMountSystem *smount =
00286 DCAST(VirtualFileMountSystem, mount);
00287 if (smount->get_physical_filename() == physical_filename) {
00288
00289 if (express_cat->is_debug()) {
00290 express_cat->debug()
00291 << "unmount " << *mount << " from " << mount->get_mount_point() << "\n";
00292 }
00293 mount->_file_system = NULL;
00294
00295 } else {
00296
00297 ++wi;
00298 }
00299
00300 } else if (mount->is_exact_type(VirtualFileMountMultifile::get_class_type())) {
00301 VirtualFileMountMultifile *mmount =
00302 DCAST(VirtualFileMountMultifile, mount);
00303 if (mmount->get_multifile()->get_multifile_name() == physical_filename) {
00304
00305 if (express_cat->is_debug()) {
00306 express_cat->debug()
00307 << "unmount " << *mount << " from " << mount->get_mount_point() << "\n";
00308 }
00309 mount->_file_system = NULL;
00310
00311 } else {
00312
00313 ++wi;
00314 }
00315
00316 } else {
00317
00318 ++wi;
00319 }
00320 ++ri;
00321 }
00322
00323 int num_removed = _mounts.end() - wi;
00324 _mounts.erase(wi, _mounts.end());
00325 ++_mount_seq;
00326 _lock.release();
00327 return num_removed;
00328 }
00329
00330
00331
00332
00333
00334
00335
00336
00337 int VirtualFileSystem::
00338 unmount(VirtualFileMount *mount) {
00339 _lock.acquire();
00340 Mounts::iterator ri, wi;
00341 wi = ri = _mounts.begin();
00342 while (ri != _mounts.end()) {
00343 (*wi) = (*ri);
00344 if ((*ri) == mount) {
00345
00346 if (express_cat->is_debug()) {
00347 express_cat->debug()
00348 << "unmount " << *mount << " from " << mount->get_mount_point() << "\n";
00349 }
00350 (*ri)->_file_system = NULL;
00351
00352 } else {
00353
00354 ++wi;
00355 }
00356 ++ri;
00357 }
00358
00359 int num_removed = _mounts.end() - wi;
00360 _mounts.erase(wi, _mounts.end());
00361 ++_mount_seq;
00362 _lock.release();
00363 return num_removed;
00364 }
00365
00366
00367
00368
00369
00370
00371
00372
00373 int VirtualFileSystem::
00374 unmount_point(const Filename &mount_point) {
00375 _lock.acquire();
00376 Filename nmp = normalize_mount_point(mount_point);
00377 Mounts::iterator ri, wi;
00378 wi = ri = _mounts.begin();
00379 while (ri != _mounts.end()) {
00380 VirtualFileMount *mount = (*ri);
00381 (*wi) = mount;
00382
00383 if (mount->get_mount_point() == nmp) {
00384
00385 if (express_cat->is_debug()) {
00386 express_cat->debug()
00387 << "unmount " << *mount << " from " << mount->get_mount_point() << "\n";
00388 }
00389 mount->_file_system = NULL;
00390
00391 } else {
00392
00393 ++wi;
00394 }
00395 ++ri;
00396 }
00397
00398 int num_removed = _mounts.end() - wi;
00399 _mounts.erase(wi, _mounts.end());
00400 ++_mount_seq;
00401 _lock.release();
00402 return num_removed;
00403 }
00404
00405
00406
00407
00408
00409
00410
00411 int VirtualFileSystem::
00412 unmount_all() {
00413 _lock.acquire();
00414 Mounts::iterator ri;
00415 for (ri = _mounts.begin(); ri != _mounts.end(); ++ri) {
00416 VirtualFileMount *mount = (*ri);
00417 if (express_cat->is_debug()) {
00418 express_cat->debug()
00419 << "unmount " << *mount << " from " << mount->get_mount_point() << "\n";
00420 }
00421 mount->_file_system = NULL;
00422 }
00423
00424 int num_removed = _mounts.size();
00425 _mounts.clear();
00426 ++_mount_seq;
00427 _lock.release();
00428 return num_removed;
00429 }
00430
00431
00432
00433
00434
00435
00436
00437 int VirtualFileSystem::
00438 get_num_mounts() const {
00439 ((VirtualFileSystem *)this)->_lock.acquire();
00440 int result = _mounts.size();
00441 ((VirtualFileSystem *)this)->_lock.release();
00442 return result;
00443 }
00444
00445
00446
00447
00448
00449
00450 PT(VirtualFileMount) VirtualFileSystem::
00451 get_mount(int n) const {
00452 ((VirtualFileSystem *)this)->_lock.acquire();
00453 nassertd(n >= 0 && n < (int)_mounts.size()) {
00454 ((VirtualFileSystem *)this)->_lock.release();
00455 return NULL;
00456 }
00457 PT(VirtualFileMount) result = _mounts[n];
00458 ((VirtualFileSystem *)this)->_lock.release();
00459 return result;
00460 }
00461
00462
00463
00464
00465
00466
00467
00468
00469
00470 bool VirtualFileSystem::
00471 chdir(const Filename &new_directory) {
00472 _lock.acquire();
00473 if (new_directory == "/") {
00474
00475 _cwd = new_directory;
00476 _lock.release();
00477 return true;
00478 }
00479
00480 PT(VirtualFile) file = do_get_file(new_directory, OF_status_only);
00481 if (file != (VirtualFile *)NULL && file->is_directory()) {
00482 _cwd = file->get_filename();
00483 _lock.release();
00484 return true;
00485 }
00486 _lock.release();
00487 return false;
00488 }
00489
00490
00491
00492
00493
00494
00495 Filename VirtualFileSystem::
00496 get_cwd() const {
00497 ((VirtualFileSystem *)this)->_lock.acquire();
00498 Filename result = _cwd;
00499 ((VirtualFileSystem *)this)->_lock.release();
00500 return result;
00501 }
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512 bool VirtualFileSystem::
00513 make_directory(const Filename &filename) {
00514 _lock.acquire();
00515 PT(VirtualFile) result = do_get_file(filename, OF_make_directory);
00516 _lock.release();
00517 return result->is_directory();
00518 }
00519
00520
00521
00522
00523
00524
00525
00526
00527 bool VirtualFileSystem::
00528 make_directory_full(const Filename &filename) {
00529 _lock.acquire();
00530
00531
00532
00533
00534 string dirname = filename;
00535 size_t slash = dirname.find('/', 1);
00536 while (slash != string::npos) {
00537 Filename component(dirname.substr(0, slash));
00538 do_get_file(component, OF_make_directory);
00539 slash = dirname.find('/', slash + 1);
00540 }
00541
00542
00543 PT(VirtualFile) result = do_get_file(filename, OF_make_directory);
00544 _lock.release();
00545 return result->is_directory();
00546 }
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564 PT(VirtualFile) VirtualFileSystem::
00565 get_file(const Filename &filename, bool status_only) const {
00566 int open_flags = status_only ? 0 : OF_status_only;
00567 ((VirtualFileSystem *)this)->_lock.acquire();
00568 PT(VirtualFile) result = do_get_file(filename, open_flags);
00569 ((VirtualFileSystem *)this)->_lock.release();
00570 return result;
00571 }
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583 PT(VirtualFile) VirtualFileSystem::
00584 create_file(const Filename &filename) {
00585 ((VirtualFileSystem *)this)->_lock.acquire();
00586 PT(VirtualFile) result = do_get_file(filename, OF_create_file);
00587 ((VirtualFileSystem *)this)->_lock.release();
00588 return result;
00589 }
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599 PT(VirtualFile) VirtualFileSystem::
00600 find_file(const Filename &filename, const DSearchPath &searchpath,
00601 bool status_only) const {
00602 if (!filename.is_local()) {
00603 return get_file(filename, status_only);
00604 }
00605
00606 int num_directories = searchpath.get_num_directories();
00607 for (int i = 0; i < num_directories; ++i) {
00608 Filename match(searchpath.get_directory(i), filename);
00609 if (searchpath.get_directory(i) == "." &&
00610 filename.is_fully_qualified()) {
00611
00612
00613
00614
00615 match = filename;
00616 }
00617 PT(VirtualFile) found_file = get_file(match, status_only);
00618 if (found_file != (VirtualFile *)NULL) {
00619 return found_file;
00620 }
00621 }
00622
00623 return NULL;
00624 }
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634 bool VirtualFileSystem::
00635 delete_file(const Filename &filename) {
00636 PT(VirtualFile) file = get_file(filename, true);
00637 if (file == (VirtualFile *)NULL) {
00638 return false;
00639 }
00640
00641 return file->delete_file();
00642 }
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661 bool VirtualFileSystem::
00662 rename_file(const Filename &orig_filename, const Filename &new_filename) {
00663 _lock.acquire();
00664 PT(VirtualFile) orig_file = do_get_file(orig_filename, OF_status_only);
00665 if (orig_file == (VirtualFile *)NULL) {
00666 _lock.release();
00667 return false;
00668 }
00669
00670 PT(VirtualFile) new_file = do_get_file(new_filename, OF_status_only | OF_allow_nonexist);
00671 if (new_file == (VirtualFile *)NULL) {
00672 _lock.release();
00673 return false;
00674 }
00675
00676 _lock.release();
00677
00678 return orig_file->rename_file(new_file);
00679 }
00680
00681
00682
00683
00684
00685
00686
00687
00688 bool VirtualFileSystem::
00689 copy_file(const Filename &orig_filename, const Filename &new_filename) {
00690 PT(VirtualFile) orig_file = get_file(orig_filename, true);
00691 if (orig_file == (VirtualFile *)NULL) {
00692 return false;
00693 }
00694
00695 PT(VirtualFile) new_file = create_file(new_filename);
00696 if (new_file == (VirtualFile *)NULL) {
00697 return false;
00698 }
00699
00700 return orig_file->copy_file(new_file);
00701 }
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711 bool VirtualFileSystem::
00712 resolve_filename(Filename &filename,
00713 const DSearchPath &searchpath,
00714 const string &default_extension) const {
00715 PT(VirtualFile) found;
00716
00717 if (filename.is_local()) {
00718 found = find_file(filename, searchpath, true);
00719
00720 if (found.is_null()) {
00721
00722
00723 if (filename.get_extension().empty() && !default_extension.empty()) {
00724 Filename try_ext = filename;
00725 try_ext.set_extension(default_extension);
00726 found = find_file(try_ext, searchpath, true);
00727 }
00728 }
00729 } else {
00730 if (exists(filename)) {
00731
00732 return true;
00733 } else {
00734
00735
00736 if (filename.get_extension().empty() && !default_extension.empty()) {
00737 Filename try_ext = filename;
00738 try_ext.set_extension(default_extension);
00739 found = get_file(try_ext, true);
00740 }
00741 }
00742 }
00743
00744 if (!found.is_null()) {
00745 filename = found->get_original_filename();
00746 return true;
00747 }
00748
00749 return false;
00750 }
00751
00752
00753
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764 int VirtualFileSystem::
00765 find_all_files(const Filename &filename, const DSearchPath &searchpath,
00766 DSearchPath::Results &results) const {
00767 int num_added = 0;
00768
00769 if (filename.is_local()) {
00770 int num_directories = searchpath.get_num_directories();
00771 for (int i = 0; i < num_directories; ++i) {
00772 Filename match(searchpath.get_directory(i), filename);
00773 if (exists(match)) {
00774 if (searchpath.get_directory(i) == "." &&
00775 filename.is_fully_qualified()) {
00776
00777
00778
00779
00780
00781 results.add_file(filename);
00782 } else {
00783 results.add_file(match);
00784 }
00785 ++num_added;
00786 }
00787 }
00788 }
00789
00790 return num_added;
00791 }
00792
00793
00794
00795
00796
00797
00798
00799 void VirtualFileSystem::
00800 write(ostream &out) const {
00801 ((VirtualFileSystem *)this)->_lock.acquire();
00802 Mounts::const_iterator mi;
00803 for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) {
00804 VirtualFileMount *mount = (*mi);
00805 mount->write(out);
00806 }
00807 ((VirtualFileSystem *)this)->_lock.release();
00808 }
00809
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825 VirtualFileSystem *VirtualFileSystem::
00826 get_global_ptr() {
00827 if (_global_ptr == (VirtualFileSystem *)NULL) {
00828
00829 init_libexpress();
00830
00831 _global_ptr = new VirtualFileSystem;
00832
00833
00834
00835 _global_ptr->mount("/", "/", 0);
00836
00837
00838 _global_ptr->chdir(ExecutionEnvironment::get_cwd());
00839
00840
00841 ConfigVariableList mounts
00842 ("vfs-mount",
00843 PRC_DESC("vfs-mount system-filename mount-point [options]"));
00844
00845 int num_unique_values = mounts.get_num_unique_values();
00846 for (int i = 0; i < num_unique_values; i++) {
00847 string mount_desc = mounts.get_unique_value(i);
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860 size_t space = mount_desc.rfind(' ');
00861 if (space == string::npos) {
00862 express_cat.warning()
00863 << "No space in vfs-mount descriptor: " << mount_desc << "\n";
00864
00865 } else {
00866 string mount_point = mount_desc.substr(space + 1);
00867 while (space > 0 && isspace(mount_desc[space - 1])) {
00868 space--;
00869 }
00870 mount_desc = mount_desc.substr(0, space);
00871 string options;
00872
00873 space = mount_desc.rfind(' ');
00874 if (space != string::npos) {
00875
00876 options = mount_point;
00877 mount_point = mount_desc.substr(space + 1);
00878 while (space > 0 && isspace(mount_desc[space - 1])) {
00879 --space;
00880 }
00881 mount_desc = mount_desc.substr(0, space);
00882 }
00883
00884 mount_desc = ExecutionEnvironment::expand_string(mount_desc);
00885 Filename physical_filename = Filename::from_os_specific(mount_desc);
00886
00887 int flags;
00888 string password;
00889 parse_options(options, flags, password);
00890 _global_ptr->mount(physical_filename, mount_point, flags, password);
00891 }
00892 }
00893
00894 ConfigVariableString vfs_mount_ramdisk
00895 ("vfs-mount-ramdisk", "",
00896 PRC_DESC("vfs-mount-ramdisk mount-point [options]"));
00897 if (!vfs_mount_ramdisk.empty()) {
00898 string mount_point = vfs_mount_ramdisk;
00899 string options;
00900
00901 size_t space = mount_point.rfind(' ');
00902 if (space != string::npos) {
00903
00904 options = mount_point.substr(space + 1);
00905 while (space > 0 && isspace(mount_point[space - 1])) {
00906 --space;
00907 }
00908 mount_point = mount_point.substr(0, space);
00909 }
00910
00911 int flags;
00912 string password;
00913 parse_options(options, flags, password);
00914
00915 PT(VirtualFileMount) ramdisk = new VirtualFileMountRamdisk;
00916 _global_ptr->mount(ramdisk, mount_point, flags);
00917 }
00918 }
00919
00920 return _global_ptr;
00921 }
00922
00923 #ifdef HAVE_PYTHON
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935 PyObject *VirtualFileSystem::
00936 __py__read_file(const Filename &filename, bool auto_unwrap) const {
00937 pvector<unsigned char> pv;
00938 bool okflag = read_file(filename, pv, auto_unwrap);
00939 nassertr(okflag, NULL);
00940
00941 if (pv.empty()) {
00942 return PyString_FromStringAndSize("", 0);
00943 } else {
00944 return PyString_FromStringAndSize((const char *)&pv[0], pv.size());
00945 }
00946 }
00947 #endif // HAVE_PYTHON
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957
00958
00959
00960
00961
00962 istream *VirtualFileSystem::
00963 open_read_file(const Filename &filename, bool auto_unwrap) const {
00964 PT(VirtualFile) file = get_file(filename, false);
00965 if (file == (VirtualFile *)NULL) {
00966 return NULL;
00967 }
00968 istream *str = file->open_read_file(auto_unwrap);
00969 if (str != (istream *)NULL && str->fail()) {
00970 close_read_file(str);
00971 str = (istream *)NULL;
00972 }
00973 return str;
00974 }
00975
00976
00977
00978
00979
00980
00981
00982
00983
00984
00985 void VirtualFileSystem::
00986 close_read_file(istream *stream) {
00987 if (stream != (istream *)NULL) {
00988
00989
00990
00991
00992 #if (!defined(WIN32_VC) && !defined(WIN64_VC)) && !defined(USE_MEMORY_NOWRAPPERS) && defined(REDEFINE_GLOBAL_OPERATOR_NEW)
00993 stream->~istream();
00994 (*global_operator_delete)(stream);
00995 #else
00996 delete stream;
00997 #endif
00998 }
00999 }
01000
01001 #ifdef HAVE_PYTHON
01002
01003
01004
01005
01006
01007
01008
01009
01010
01011
01012
01013 PyObject *VirtualFileSystem::
01014 __py__write_file(const Filename &filename, PyObject *data, bool auto_wrap) {
01015 char *buffer;
01016 Py_ssize_t length;
01017 if (PyString_AsStringAndSize(data, &buffer, &length) == -1) {
01018 return NULL;
01019 }
01020
01021 bool result = write_file(filename, (const unsigned char *)buffer, length, auto_wrap);
01022 return PyBool_FromLong(result);
01023 }
01024 #endif // HAVE_PYTHON
01025
01026
01027
01028
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038 ostream *VirtualFileSystem::
01039 open_write_file(const Filename &filename, bool auto_wrap, bool truncate) {
01040 PT(VirtualFile) file = create_file(filename);
01041 if (file == (VirtualFile *)NULL) {
01042 return NULL;
01043 }
01044 ostream *str = file->open_write_file(auto_wrap, truncate);
01045 if (str != (ostream *)NULL && str->fail()) {
01046 close_write_file(str);
01047 str = (ostream *)NULL;
01048 }
01049 return str;
01050 }
01051
01052
01053
01054
01055
01056
01057
01058
01059
01060 ostream *VirtualFileSystem::
01061 open_append_file(const Filename &filename) {
01062 PT(VirtualFile) file = create_file(filename);
01063 if (file == (VirtualFile *)NULL) {
01064 return NULL;
01065 }
01066 ostream *str = file->open_append_file();
01067 if (str != (ostream *)NULL && str->fail()) {
01068 close_write_file(str);
01069 str = (ostream *)NULL;
01070 }
01071 return str;
01072 }
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083 void VirtualFileSystem::
01084 close_write_file(ostream *stream) {
01085 if (stream != (ostream *)NULL) {
01086 #if (!defined(WIN32_VC) && !defined(WIN64_VC)) && !defined(USE_MEMORY_NOWRAPPERS) && defined(REDEFINE_GLOBAL_OPERATOR_NEW)
01087 stream->~ostream();
01088 (*global_operator_delete)(stream);
01089 #else
01090 delete stream;
01091 #endif
01092 }
01093 }
01094
01095
01096
01097
01098
01099
01100
01101
01102 iostream *VirtualFileSystem::
01103 open_read_write_file(const Filename &filename, bool truncate) {
01104 PT(VirtualFile) file = create_file(filename);
01105 if (file == (VirtualFile *)NULL) {
01106 return NULL;
01107 }
01108 iostream *str = file->open_read_write_file(truncate);
01109 if (str != (iostream *)NULL && str->fail()) {
01110 close_read_write_file(str);
01111 str = (iostream *)NULL;
01112 }
01113 return str;
01114 }
01115
01116
01117
01118
01119
01120
01121
01122
01123
01124 iostream *VirtualFileSystem::
01125 open_read_append_file(const Filename &filename) {
01126 PT(VirtualFile) file = create_file(filename);
01127 if (file == (VirtualFile *)NULL) {
01128 return NULL;
01129 }
01130 iostream *str = file->open_read_append_file();
01131 if (str != (iostream *)NULL && str->fail()) {
01132 close_read_write_file(str);
01133 str = (iostream *)NULL;
01134 }
01135 return str;
01136 }
01137
01138
01139
01140
01141
01142
01143
01144
01145
01146
01147 void VirtualFileSystem::
01148 close_read_write_file(iostream *stream) {
01149 if (stream != (iostream *)NULL) {
01150 #if (!defined(WIN32_VC) && !defined(WIN64_VC)) && !defined(USE_MEMORY_NOWRAPPERS) && defined(REDEFINE_GLOBAL_OPERATOR_NEW)
01151 stream->~iostream();
01152 (*global_operator_delete)(stream);
01153 #else
01154 delete stream;
01155 #endif
01156 }
01157 }
01158
01159
01160
01161
01162
01163
01164 bool VirtualFileSystem::
01165 atomic_compare_and_exchange_contents(const Filename &filename, string &orig_contents,
01166 const string &old_contents,
01167 const string &new_contents) {
01168 PT(VirtualFile) file = create_file(filename);
01169 if (file == NULL) {
01170 return false;
01171 }
01172
01173 return file->atomic_compare_and_exchange_contents(orig_contents, old_contents, new_contents);
01174 }
01175
01176
01177
01178
01179
01180
01181 bool VirtualFileSystem::
01182 atomic_read_contents(const Filename &filename, string &contents) const {
01183 PT(VirtualFile) file = get_file(filename, false);
01184 if (file == NULL) {
01185 return false;
01186 }
01187
01188 return file->atomic_read_contents(contents);
01189 }
01190
01191
01192
01193
01194
01195
01196
01197
01198
01199
01200
01201
01202 void VirtualFileSystem::
01203 scan_mount_points(vector_string &names, const Filename &path) const {
01204 nassertv(!path.empty() && !path.is_local());
01205 string prefix = path.get_fullpath().substr(1);
01206 Mounts::const_iterator mi;
01207 for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) {
01208 VirtualFileMount *mount = (*mi);
01209
01210 string mount_point = mount->get_mount_point();
01211 if (prefix.empty()) {
01212
01213
01214 if (mount_point.find('/') == string::npos) {
01215
01216
01217 names.push_back(mount_point);
01218 }
01219 } else {
01220 if (mount_point.substr(0, prefix.length()) == prefix &&
01221 mount_point.length() > prefix.length() &&
01222 mount_point[prefix.length()] == '/') {
01223
01224
01225 string basename = mount_point.substr(prefix.length());
01226 if (basename.find('/') == string::npos) {
01227
01228 names.push_back(basename);
01229 }
01230 }
01231 }
01232 }
01233 }
01234
01235
01236
01237
01238
01239
01240
01241
01242 void VirtualFileSystem::
01243 parse_options(const string &options, int &flags, string &password) {
01244 flags = 0;
01245 password = string();
01246
01247
01248 size_t p = 0;
01249 size_t q = options.find(',', p);
01250 while (q != string::npos) {
01251 parse_option(options.substr(p, q - p),
01252 flags, password);
01253 p = q + 1;
01254 q = options.find(',', p);
01255 }
01256 parse_option(options.substr(p), flags, password);
01257 }
01258
01259
01260
01261
01262
01263
01264
01265 void VirtualFileSystem::
01266 parse_option(const string &option, int &flags, string &password) {
01267 if (option == "0" || option.empty()) {
01268
01269 } else if (option == "ro") {
01270 flags |= MF_read_only;
01271 } else if (option.substr(0, 3) == "pw:") {
01272 password = option.substr(3);
01273 } else {
01274 express_cat.warning()
01275 << "Invalid option on vfs-mount: \"" << option << "\"\n";
01276 }
01277 }
01278
01279
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289 Filename VirtualFileSystem::
01290 normalize_mount_point(const Filename &mount_point) const {
01291 Filename nmp = mount_point;
01292 if (nmp.is_local()) {
01293 nmp = Filename(_cwd, mount_point);
01294 }
01295 nmp.standardize();
01296 nassertr(!nmp.empty() && nmp[0] == '/', nmp);
01297 return nmp.get_fullpath().substr(1);
01298 }
01299
01300
01301
01302
01303
01304
01305
01306 bool VirtualFileSystem::
01307 do_mount(VirtualFileMount *mount, const Filename &mount_point, int flags) {
01308 nassertr(mount->_file_system == NULL, false);
01309 mount->_file_system = this;
01310 mount->_mount_point = normalize_mount_point(mount_point);
01311 mount->_mount_flags = flags;
01312 _mounts.push_back(mount);
01313 ++_mount_seq;
01314 return true;
01315 }
01316
01317
01318
01319
01320
01321
01322
01323
01324 PT(VirtualFile) VirtualFileSystem::
01325 do_get_file(const Filename &filename, int open_flags) const {
01326 if (filename.empty()) {
01327 return NULL;
01328 }
01329 Filename pathname(filename);
01330 if (pathname.is_local()) {
01331 pathname = Filename(_cwd, filename);
01332 if (filename.is_text()) {
01333 pathname.set_text();
01334 }
01335 }
01336 pathname.standardize();
01337 Filename strpath = pathname.get_filename_index(0).get_fullpath().substr(1);
01338 strpath.set_type(filename.get_type());
01339
01340 Filename strpath_pz = strpath + ".pz";
01341
01342
01343
01344 PT(VirtualFile) found_file = NULL;
01345 VirtualFileComposite *composite_file = NULL;
01346
01347
01348
01349 unsigned int start_seq = _mount_seq;
01350
01351 size_t i = _mounts.size();
01352 while (i > 0) {
01353 --i;
01354 VirtualFileMount *mount = _mounts[i];
01355 Filename mount_point = mount->get_mount_point();
01356 if (strpath == mount_point) {
01357
01358
01359 if (consider_match(found_file, composite_file, mount, "", pathname,
01360 false, open_flags)) {
01361 return found_file;
01362 }
01363 } else if (mount_point.empty()) {
01364
01365 if (consider_match(found_file, composite_file, mount, strpath,
01366 pathname, false, open_flags)) {
01367 return found_file;
01368 }
01369 #ifdef HAVE_ZLIB
01370 if (vfs_implicit_pz) {
01371 if (consider_match(found_file, composite_file, mount, strpath_pz,
01372 pathname, true, open_flags)) {
01373 return found_file;
01374 }
01375 }
01376 #endif // HAVE_ZLIB
01377
01378 } else if (strpath.length() > mount_point.length() &&
01379 mount_point == strpath.substr(0, mount_point.length()) &&
01380 strpath[mount_point.length()] == '/') {
01381
01382 Filename local_filename = strpath.substr(mount_point.length() + 1);
01383 Filename local_filename_pz = strpath_pz.substr(mount_point.length() + 1);
01384 if (consider_match(found_file, composite_file, mount, local_filename,
01385 pathname, false, open_flags)) {
01386 return found_file;
01387 }
01388 #ifdef HAVE_ZLIB
01389 if (vfs_implicit_pz) {
01390
01391 if (consider_match(found_file, composite_file, mount, local_filename_pz,
01392 pathname, true, open_flags)) {
01393 return found_file;
01394 }
01395 }
01396 #endif // HAVE_ZLIB
01397 }
01398
01399
01400
01401
01402 if (start_seq != _mount_seq) {
01403 start_seq = _mount_seq;
01404 i = _mounts.size();
01405 }
01406 }
01407
01408 if (found_file == (VirtualFile *)NULL && vfs_implicit_mf) {
01409
01410
01411 ((VirtualFileSystem *)this)->consider_mount_mf(filename);
01412
01413 if (start_seq != _mount_seq) {
01414
01415
01416 return do_get_file(filename, open_flags);
01417 }
01418 }
01419
01420 return found_file;
01421 }
01422
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436 bool VirtualFileSystem::
01437 consider_match(PT(VirtualFile) &found_file, VirtualFileComposite *&composite_file,
01438 VirtualFileMount *mount, const Filename &local_filename,
01439 const Filename &original_filename, bool implicit_pz_file,
01440 int open_flags) const {
01441 PT(VirtualFile) vfile =
01442 mount->make_virtual_file(local_filename, original_filename, false, open_flags);
01443 if (!vfile->has_file() && ((open_flags & OF_allow_nonexist) == 0)) {
01444
01445 return false;
01446 }
01447
01448 if (found_file == (VirtualFile *)NULL) {
01449
01450 found_file = vfile;
01451 if (!found_file->is_directory() || ((open_flags & OF_make_directory) != 0)) {
01452
01453 return true;
01454 }
01455
01456 if (implicit_pz_file) {
01457
01458 found_file = NULL;
01459 }
01460
01461 } else {
01462
01463
01464 if (!vfile->is_directory()) {
01465
01466 return true;
01467 }
01468
01469 if (!implicit_pz_file) {
01470
01471
01472 if (composite_file == (VirtualFileComposite *)NULL) {
01473 composite_file =
01474 new VirtualFileComposite((VirtualFileSystem *)this, found_file->get_original_filename());
01475 composite_file->set_original_filename(original_filename);
01476 composite_file->add_component(found_file);
01477 found_file = composite_file;
01478 }
01479
01480 composite_file->add_component(vfile);
01481 }
01482 }
01483
01484
01485 return false;
01486 }
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497
01498
01499
01500 bool VirtualFileSystem::
01501 consider_mount_mf(const Filename &filename) {
01502 Filename dirname = filename.get_dirname();
01503 if (dirname.empty() || dirname == filename) {
01504
01505 return false;
01506 }
01507 if (is_directory(dirname)) {
01508
01509
01510 return false;
01511 }
01512 if (dirname.get_extension() == "mf") {
01513
01514 dirname.set_binary();
01515 PT(VirtualFile) file = do_get_file(dirname, false);
01516 if (file == (VirtualFile *)NULL || !file->is_regular_file()) {
01517
01518 return false;
01519 }
01520
01521 PT(Multifile) multifile = new Multifile;
01522
01523 istream *stream = file->open_read_file(false);
01524 if (stream == (istream *)NULL) {
01525
01526 return false;
01527 }
01528
01529
01530
01531 IStreamWrapper *streamw = new IStreamWrapper(stream, true);
01532
01533 if (!multifile->open_read(streamw, true)) {
01534
01535 return false;
01536 }
01537
01538 multifile->set_multifile_name(dirname.get_basename());
01539 express_cat->info()
01540 << "Implicitly mounting " << dirname << "\n";
01541
01542 PT(VirtualFileMountMultifile) new_mount =
01543 new VirtualFileMountMultifile(multifile);
01544 return do_mount(new_mount, dirname, MF_read_only);
01545 }
01546
01547
01548 return consider_mount_mf(dirname);
01549 }