00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "virtualFileSystem.h"
00020 #include "virtualFileMount.h"
00021 #include "virtualFileMountMultifile.h"
00022 #include "virtualFileMountSystem.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 _cwd = "/";
00040 }
00041
00042
00043
00044
00045
00046
00047 VirtualFileSystem::
00048 ~VirtualFileSystem() {
00049 unmount_all();
00050 }
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 bool VirtualFileSystem::
00061 mount(Multifile *multifile, const string &mount_point, int flags) {
00062 VirtualFileMountMultifile *mount =
00063 new VirtualFileMountMultifile(this, multifile,
00064 normalize_mount_point(mount_point),
00065 flags);
00066 _mounts.push_back(mount);
00067 return true;
00068 }
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084 bool VirtualFileSystem::
00085 mount(const Filename &physical_filename, const string &mount_point,
00086 int flags) {
00087 if (!physical_filename.exists()) {
00088 express_cat.warning()
00089 << "Attempt to mount " << physical_filename << ", not found.\n";
00090 return false;
00091 }
00092
00093 if (physical_filename.is_directory()) {
00094 flags &= ~MF_owns_pointer;
00095 VirtualFileMountSystem *mount =
00096 new VirtualFileMountSystem(this, physical_filename,
00097 normalize_mount_point(mount_point),
00098 flags);
00099 _mounts.push_back(mount);
00100 return true;
00101
00102 } else {
00103
00104 Multifile *multifile = new Multifile;
00105
00106
00107
00108 flags |= MF_read_only;
00109 if (!multifile->open_read(physical_filename)) {
00110 delete multifile;
00111 return false;
00112 }
00113
00114
00115 flags |= MF_owns_pointer;
00116 return mount(multifile, mount_point, flags);
00117 }
00118 }
00119
00120
00121
00122
00123
00124
00125
00126
00127 int VirtualFileSystem::
00128 unmount(Multifile *multifile) {
00129 Mounts::iterator ri, wi;
00130 wi = ri = _mounts.begin();
00131 while (ri != _mounts.end()) {
00132 VirtualFileMount *mount = (*ri);
00133 (*wi) = mount;
00134
00135 if (mount->is_exact_type(VirtualFileMountMultifile::get_class_type())) {
00136 VirtualFileMountMultifile *mmount =
00137 DCAST(VirtualFileMountMultifile, mount);
00138 if (mmount->get_multifile() == multifile) {
00139
00140 delete mount;
00141 } else {
00142
00143 ++wi;
00144 }
00145 } else {
00146
00147 ++wi;
00148 }
00149 ++ri;
00150 }
00151
00152 int num_removed = _mounts.end() - wi;
00153 _mounts.erase(wi, _mounts.end());
00154 return num_removed;
00155 }
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165 int VirtualFileSystem::
00166 unmount(const Filename &physical_filename) {
00167 Mounts::iterator ri, wi;
00168 wi = ri = _mounts.begin();
00169 while (ri != _mounts.end()) {
00170 VirtualFileMount *mount = (*ri);
00171 (*wi) = mount;
00172
00173 if (mount->get_physical_filename() == physical_filename) {
00174
00175 delete mount;
00176 } else {
00177
00178 ++wi;
00179 }
00180 ++ri;
00181 }
00182
00183 int num_removed = _mounts.end() - wi;
00184 _mounts.erase(wi, _mounts.end());
00185 return num_removed;
00186 }
00187
00188
00189
00190
00191
00192
00193
00194
00195 int VirtualFileSystem::
00196 unmount_point(const string &mount_point) {
00197 Filename nmp = normalize_mount_point(mount_point);
00198 Mounts::iterator ri, wi;
00199 wi = ri = _mounts.begin();
00200 while (ri != _mounts.end()) {
00201 VirtualFileMount *mount = (*ri);
00202 (*wi) = mount;
00203
00204 if (mount->get_mount_point() == nmp) {
00205
00206 delete mount;
00207 } else {
00208
00209 ++wi;
00210 }
00211 ++ri;
00212 }
00213
00214 int num_removed = _mounts.end() - wi;
00215 _mounts.erase(wi, _mounts.end());
00216 return num_removed;
00217 }
00218
00219
00220
00221
00222
00223
00224
00225 int VirtualFileSystem::
00226 unmount_all() {
00227 Mounts::iterator mi;
00228 for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) {
00229 VirtualFileMount *mount = (*mi);
00230 delete mount;
00231 }
00232
00233 int num_removed = _mounts.size();
00234 _mounts.clear();
00235 return num_removed;
00236 }
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249 bool VirtualFileSystem::
00250 chdir(const string &new_directory) {
00251 if (new_directory == "/") {
00252
00253 _cwd = new_directory;
00254 return true;
00255 }
00256
00257 PT(VirtualFile) file = get_file(new_directory);
00258 if (file != (VirtualFile *)NULL && file->is_directory()) {
00259 _cwd = file->get_filename();
00260 return true;
00261 }
00262 return false;
00263 }
00264
00265
00266
00267
00268
00269
00270 const Filename &VirtualFileSystem::
00271 get_cwd() const {
00272 return _cwd;
00273 }
00274
00275
00276
00277
00278
00279
00280
00281
00282 PT(VirtualFile) VirtualFileSystem::
00283 get_file(const Filename &filename) const {
00284 nassertr(!filename.empty(), NULL);
00285 Filename pathname(filename);
00286 if (pathname.is_local()) {
00287 pathname = Filename(_cwd, filename);
00288 }
00289 pathname.standardize();
00290 string strpath = pathname.get_fullpath().substr(1);
00291
00292
00293
00294 PT(VirtualFile) found_file = NULL;
00295 VirtualFileComposite *composite_file = NULL;
00296
00297 Mounts::const_reverse_iterator rmi;
00298 for (rmi = _mounts.rbegin(); rmi != _mounts.rend(); ++rmi) {
00299 VirtualFileMount *mount = (*rmi);
00300 string mount_point = mount->get_mount_point();
00301 if (strpath == mount_point) {
00302
00303
00304 if (found_match(found_file, composite_file, mount, "")) {
00305 return found_file;
00306 }
00307
00308 } else if (mount_point.empty()) {
00309
00310 if (mount->has_file(strpath)) {
00311
00312 if (found_match(found_file, composite_file, mount, strpath)) {
00313 return found_file;
00314 }
00315 }
00316
00317 } else if (strpath.length() > mount_point.length() &&
00318 strpath.substr(0, mount_point.length()) == mount_point &&
00319 strpath[mount_point.length()] == '/') {
00320
00321 Filename local_filename = strpath.substr(mount_point.length() + 1);
00322 if (mount->has_file(local_filename)) {
00323
00324 if (found_match(found_file, composite_file, mount, local_filename)) {
00325 return found_file;
00326 }
00327 }
00328 }
00329 }
00330 return found_file;
00331 }
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341 PT(VirtualFile) VirtualFileSystem::
00342 find_file(const Filename &filename, const DSearchPath &searchpath) const {
00343 if (!filename.is_local()) {
00344 return get_file(filename);
00345 }
00346
00347 int num_directories = searchpath.get_num_directories();
00348 for (int i = 0; i < num_directories; i++) {
00349 Filename match(searchpath.get_directory(i), filename);
00350 if (searchpath.get_directory(i) == "." &&
00351 filename.is_fully_qualified()) {
00352
00353
00354
00355
00356
00357 match = filename;
00358 }
00359 PT(VirtualFile) found_file = get_file(match);
00360 if (found_file != (VirtualFile *)NULL) {
00361 return found_file;
00362 }
00363 }
00364
00365 return NULL;
00366 }
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377 bool VirtualFileSystem::
00378 resolve_filename(Filename &filename,
00379 const DSearchPath &searchpath,
00380 const string &default_extension) const {
00381 PT(VirtualFile) found;
00382
00383 if (filename.is_local()) {
00384 found = find_file(filename.get_fullpath(), searchpath);
00385
00386 if (found.is_null()) {
00387
00388
00389 if (filename.get_extension().empty() && !default_extension.empty()) {
00390 Filename try_ext = filename;
00391 try_ext.set_extension(default_extension);
00392 found = find_file(try_ext.get_fullpath(), searchpath);
00393 }
00394 }
00395
00396 } else {
00397 if (exists(filename)) {
00398
00399 return true;
00400
00401 } else {
00402
00403
00404 if (filename.get_extension().empty() && !default_extension.empty()) {
00405 Filename try_ext = filename;
00406 try_ext.set_extension(default_extension);
00407 found = get_file(try_ext);
00408 }
00409 }
00410 }
00411
00412 if (!found.is_null()) {
00413 filename = found->get_filename();
00414 return true;
00415 }
00416
00417 return false;
00418 }
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432 int VirtualFileSystem::
00433 find_all_files(const Filename &filename, const DSearchPath &searchpath,
00434 DSearchPath::Results &results) const {
00435 int num_added = 0;
00436
00437 if (filename.is_local()) {
00438 int num_directories = searchpath.get_num_directories();
00439 for (int i = 0; i < num_directories; i++) {
00440 Filename match(searchpath.get_directory(i), filename);
00441 if (exists(match)) {
00442 if (searchpath.get_directory(i) == "." &&
00443 filename.is_fully_qualified()) {
00444
00445
00446
00447
00448
00449 results.add_file(filename);
00450 } else {
00451 results.add_file(match);
00452 }
00453 num_added++;
00454 }
00455 }
00456 }
00457
00458 return num_added;
00459 }
00460
00461
00462
00463
00464
00465
00466 void VirtualFileSystem::
00467 write(ostream &out) const {
00468 Mounts::const_iterator mi;
00469 for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) {
00470 VirtualFileMount *mount = (*mi);
00471 mount->write(out);
00472 }
00473 }
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490 VirtualFileSystem *VirtualFileSystem::
00491 get_global_ptr() {
00492 if (_global_ptr == (VirtualFileSystem *)NULL) {
00493 _global_ptr = new VirtualFileSystem;
00494
00495
00496
00497 _global_ptr->mount("/", "/", 0);
00498
00499
00500 _global_ptr->chdir(ExecutionEnvironment::get_cwd());
00501
00502
00503 Config::ConfigTable::Symbol mounts;
00504 config_express.GetAll("vfs-mount", mounts);
00505
00506
00507
00508 pset<string> already_read;
00509
00510 Config::ConfigTable::Symbol::iterator si;
00511 for (si = mounts.begin(); si != mounts.end(); ++si) {
00512 string mount_desc = (*si).Val();
00513 if (already_read.insert(mount_desc).second) {
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526 size_t space = mount_desc.rfind(' ');
00527 if (space == string::npos) {
00528 express_cat.warning()
00529 << "No space in vfs-mount descriptor: " << mount_desc << "\n";
00530
00531 } else {
00532 string mount_point = mount_desc.substr(space + 1);
00533 while (space > 0 && isspace(mount_desc[space - 1])) {
00534 space--;
00535 }
00536 mount_desc = mount_desc.substr(0, space);
00537 string options;
00538
00539 space = mount_desc.rfind(' ');
00540 if (space != string::npos) {
00541
00542 options = mount_point;
00543 mount_point = mount_desc.substr(space + 1);
00544 while (space > 0 && isspace(mount_desc[space - 1])) {
00545 space--;
00546 }
00547 mount_desc = mount_desc.substr(0, space);
00548 }
00549
00550 mount_desc = ExecutionEnvironment::expand_string(mount_desc);
00551 Filename physical_filename = Filename::from_os_specific(mount_desc);
00552
00553 _global_ptr->mount(physical_filename, mount_point, 0);
00554 }
00555 }
00556 }
00557 }
00558
00559 return _global_ptr;
00560 }
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573 void VirtualFileSystem::
00574 scan_mount_points(vector_string &names, const Filename &path) const {
00575 nassertv(!path.empty() && !path.is_local());
00576 string prefix = path.get_fullpath().substr(1);
00577 Mounts::const_iterator mi;
00578 for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) {
00579 VirtualFileMount *mount = (*mi);
00580
00581 string mount_point = mount->get_mount_point();
00582 if (prefix.empty()) {
00583
00584
00585 if (mount_point.find('/') == string::npos) {
00586
00587
00588 names.push_back(mount_point);
00589 }
00590 } else {
00591 if (mount_point.substr(0, prefix.length()) == prefix &&
00592 mount_point.length() > prefix.length() &&
00593 mount_point[prefix.length()] == '/') {
00594
00595
00596 string basename = mount_point.substr(prefix.length());
00597 if (basename.find('/') == string::npos) {
00598
00599 names.push_back(basename);
00600 }
00601 }
00602 }
00603 }
00604 }
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614 Filename VirtualFileSystem::
00615 normalize_mount_point(const string &mount_point) const {
00616 Filename nmp = mount_point;
00617 if (nmp.is_local()) {
00618 nmp = Filename(_cwd, mount_point);
00619 }
00620 nmp.standardize();
00621 nassertr(!nmp.empty() && nmp[0] == '/', nmp);
00622 return nmp.get_fullpath().substr(1);
00623 }
00624
00625
00626
00627
00628
00629
00630
00631
00632
00633
00634
00635
00636
00637 bool VirtualFileSystem::
00638 found_match(PT(VirtualFile) &found_file, VirtualFileComposite *&composite_file,
00639 VirtualFileMount *mount, const string &local_filename) const {
00640 if (found_file == (VirtualFile *)NULL) {
00641
00642 found_file = new VirtualFileSimple(mount, local_filename);
00643 if (!mount->is_directory(local_filename)) {
00644
00645 return true;
00646 }
00647
00648 } else {
00649
00650
00651 if (!mount->is_directory(local_filename)) {
00652
00653 return true;
00654 }
00655
00656
00657
00658 if (composite_file == (VirtualFileComposite *)NULL) {
00659 composite_file =
00660 new VirtualFileComposite((VirtualFileSystem *)this, found_file->get_filename());
00661 composite_file->add_component(found_file);
00662 found_file = composite_file;
00663 }
00664 composite_file->add_component(new VirtualFileSimple(mount, local_filename));
00665 }
00666
00667
00668 return false;
00669 }
00670