virtualFileSystem.cxx 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724
  1. // Filename: virtualFileSystem.cxx
  2. // Created by: drose (03Aug02)
  3. //
  4. ////////////////////////////////////////////////////////////////////
  5. //
  6. // PANDA 3D SOFTWARE
  7. // Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
  8. //
  9. // All use of this software is subject to the terms of the Panda 3d
  10. // Software license. You should have received a copy of this license
  11. // along with this source code; you will also find a current copy of
  12. // the license at http://etc.cmu.edu/panda3d/docs/license/ .
  13. //
  14. // To contact the maintainers of this program write to
  15. // [email protected] .
  16. //
  17. ////////////////////////////////////////////////////////////////////
  18. #include "virtualFileSystem.h"
  19. #include "virtualFileMount.h"
  20. #include "virtualFileMountMultifile.h"
  21. #include "virtualFileMountSystem.h"
  22. #include "dSearchPath.h"
  23. #include "dcast.h"
  24. #include "config_express.h"
  25. #include "executionEnvironment.h"
  26. #include "pset.h"
  27. VirtualFileSystem *VirtualFileSystem::_global_ptr = NULL;
  28. ////////////////////////////////////////////////////////////////////
  29. // Function: VirtualFileSystem::Constructor
  30. // Access: Published
  31. // Description:
  32. ////////////////////////////////////////////////////////////////////
  33. VirtualFileSystem::
  34. VirtualFileSystem() {
  35. _cwd = "/";
  36. }
  37. ////////////////////////////////////////////////////////////////////
  38. // Function: VirtualFileSystem::Destructor
  39. // Access: Published
  40. // Description:
  41. ////////////////////////////////////////////////////////////////////
  42. VirtualFileSystem::
  43. ~VirtualFileSystem() {
  44. unmount_all();
  45. }
  46. ////////////////////////////////////////////////////////////////////
  47. // Function: VirtualFileSystem::mount
  48. // Access: Published
  49. // Description: Mounts the indicated Multifile at the given mount
  50. // point.
  51. ////////////////////////////////////////////////////////////////////
  52. bool VirtualFileSystem::
  53. mount(Multifile *multifile, const string &mount_point, int flags) {
  54. VirtualFileMountMultifile *mount =
  55. new VirtualFileMountMultifile(this, multifile,
  56. normalize_mount_point(mount_point),
  57. flags);
  58. _mounts.push_back(mount);
  59. return true;
  60. }
  61. ////////////////////////////////////////////////////////////////////
  62. // Function: VirtualFileSystem::mount
  63. // Access: Published
  64. // Description: Mounts the indicated system file or directory at the
  65. // given mount point. If the named file is a directory,
  66. // mounts the directory. If the named file is a
  67. // Multifile, mounts it as a Multifile. Returns true on
  68. // success, false on failure.
  69. //
  70. // A given system directory may be mounted to multiple
  71. // different mount point, and the same mount point may
  72. // share multiple system directories. In the case of
  73. // ambiguities (that is, two different files with
  74. // exactly the same full pathname), the most-recently
  75. // mounted system wins.
  76. //
  77. // Note that a mounted VirtualFileSystem directory is
  78. // fully case-sensitive, unlike the native Windows file
  79. // system, so you must refer to files within the virtual
  80. // file system with exactly the right case.
  81. ////////////////////////////////////////////////////////////////////
  82. bool VirtualFileSystem::
  83. mount(const Filename &physical_filename, const string &mount_point,
  84. int flags, const string &password) {
  85. if (!physical_filename.exists()) {
  86. express_cat.warning()
  87. << "Attempt to mount " << physical_filename << ", not found.\n";
  88. return false;
  89. }
  90. if (physical_filename.is_directory()) {
  91. VirtualFileMountSystem *mount =
  92. new VirtualFileMountSystem(this, physical_filename,
  93. normalize_mount_point(mount_point),
  94. flags);
  95. _mounts.push_back(mount);
  96. return true;
  97. } else {
  98. // It's not a directory; it must be a Multifile.
  99. PT(Multifile) multifile = new Multifile;
  100. multifile->set_encryption_password(password);
  101. // For now these are always opened read only. Maybe later we'll
  102. // support read-write on Multifiles.
  103. flags |= MF_read_only;
  104. if (!multifile->open_read(physical_filename)) {
  105. return false;
  106. }
  107. return mount(multifile, mount_point, flags);
  108. }
  109. }
  110. ////////////////////////////////////////////////////////////////////
  111. // Function: VirtualFileSystem::unmount
  112. // Access: Published
  113. // Description: Unmounts all appearances of the indicated Multifile
  114. // from the file system. Returns the number of
  115. // appearances unmounted.
  116. ////////////////////////////////////////////////////////////////////
  117. int VirtualFileSystem::
  118. unmount(Multifile *multifile) {
  119. Mounts::iterator ri, wi;
  120. wi = ri = _mounts.begin();
  121. while (ri != _mounts.end()) {
  122. VirtualFileMount *mount = (*ri);
  123. (*wi) = mount;
  124. if (mount->is_exact_type(VirtualFileMountMultifile::get_class_type())) {
  125. VirtualFileMountMultifile *mmount =
  126. DCAST(VirtualFileMountMultifile, mount);
  127. if (mmount->get_multifile() == multifile) {
  128. // Remove this one. Don't increment wi.
  129. delete mount;
  130. } else {
  131. // Don't remove this one.
  132. ++wi;
  133. }
  134. } else {
  135. // Don't remove this one.
  136. ++wi;
  137. }
  138. ++ri;
  139. }
  140. int num_removed = _mounts.end() - wi;
  141. _mounts.erase(wi, _mounts.end());
  142. return num_removed;
  143. }
  144. ////////////////////////////////////////////////////////////////////
  145. // Function: VirtualFileSystem::unmount
  146. // Access: Published
  147. // Description: Unmounts all appearances of the indicated physical
  148. // filename (either a directory name or a Multifile
  149. // name) from the file system. Returns the number of
  150. // appearances unmounted.
  151. ////////////////////////////////////////////////////////////////////
  152. int VirtualFileSystem::
  153. unmount(const Filename &physical_filename) {
  154. Mounts::iterator ri, wi;
  155. wi = ri = _mounts.begin();
  156. while (ri != _mounts.end()) {
  157. VirtualFileMount *mount = (*ri);
  158. (*wi) = mount;
  159. if (mount->get_physical_filename() == physical_filename) {
  160. // Remove this one. Don't increment wi.
  161. delete mount;
  162. } else {
  163. // Don't remove this one.
  164. ++wi;
  165. }
  166. ++ri;
  167. }
  168. int num_removed = _mounts.end() - wi;
  169. _mounts.erase(wi, _mounts.end());
  170. return num_removed;
  171. }
  172. ////////////////////////////////////////////////////////////////////
  173. // Function: VirtualFileSystem::unmount_point
  174. // Access: Published
  175. // Description: Unmounts all systems attached to the given mount
  176. // point from the file system. Returns the number of
  177. // appearances unmounted.
  178. ////////////////////////////////////////////////////////////////////
  179. int VirtualFileSystem::
  180. unmount_point(const string &mount_point) {
  181. Filename nmp = normalize_mount_point(mount_point);
  182. Mounts::iterator ri, wi;
  183. wi = ri = _mounts.begin();
  184. while (ri != _mounts.end()) {
  185. VirtualFileMount *mount = (*ri);
  186. (*wi) = mount;
  187. if (mount->get_mount_point() == nmp) {
  188. // Remove this one. Don't increment wi.
  189. delete mount;
  190. } else {
  191. // Don't remove this one.
  192. ++wi;
  193. }
  194. ++ri;
  195. }
  196. int num_removed = _mounts.end() - wi;
  197. _mounts.erase(wi, _mounts.end());
  198. return num_removed;
  199. }
  200. ////////////////////////////////////////////////////////////////////
  201. // Function: VirtualFileSystem::unmount_all
  202. // Access: Published
  203. // Description: Unmounts all files from the file system. Returns the
  204. // number of systems unmounted.
  205. ////////////////////////////////////////////////////////////////////
  206. int VirtualFileSystem::
  207. unmount_all() {
  208. Mounts::iterator mi;
  209. for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) {
  210. VirtualFileMount *mount = (*mi);
  211. delete mount;
  212. }
  213. int num_removed = _mounts.size();
  214. _mounts.clear();
  215. return num_removed;
  216. }
  217. ////////////////////////////////////////////////////////////////////
  218. // Function: VirtualFileSystem::chdir
  219. // Access: Published
  220. // Description: Changes the current directory. This is used to
  221. // resolve relative pathnames in get_file() and/or
  222. // find_file(). Returns true if successful, false
  223. // otherwise.
  224. //
  225. // This accepts a string rather than a Filename simply
  226. // for programmer convenience from the Python prompt.
  227. ////////////////////////////////////////////////////////////////////
  228. bool VirtualFileSystem::
  229. chdir(const string &new_directory) {
  230. if (new_directory == "/") {
  231. // We can always return to the root.
  232. _cwd = new_directory;
  233. return true;
  234. }
  235. PT(VirtualFile) file = get_file(new_directory);
  236. if (file != (VirtualFile *)NULL && file->is_directory()) {
  237. _cwd = file->get_filename();
  238. return true;
  239. }
  240. return false;
  241. }
  242. ////////////////////////////////////////////////////////////////////
  243. // Function: VirtualFileSystem::get_cwd
  244. // Access: Published
  245. // Description: Returns the current directory name. See chdir().
  246. ////////////////////////////////////////////////////////////////////
  247. const Filename &VirtualFileSystem::
  248. get_cwd() const {
  249. return _cwd;
  250. }
  251. ////////////////////////////////////////////////////////////////////
  252. // Function: VirtualFileSystem::get_file
  253. // Access: Published
  254. // Description: Looks up the file by the indicated name in the file
  255. // system. Returns a VirtualFile pointer representing
  256. // the file if it is found, or NULL if it is not.
  257. ////////////////////////////////////////////////////////////////////
  258. PT(VirtualFile) VirtualFileSystem::
  259. get_file(const Filename &filename) const {
  260. nassertr(!filename.empty(), NULL);
  261. Filename pathname(filename);
  262. if (pathname.is_local()) {
  263. pathname = Filename(_cwd, filename);
  264. }
  265. pathname.standardize();
  266. string strpath = pathname.get_filename_index(0).get_fullpath().substr(1);
  267. // Now scan all the mount points, from the back (since later mounts
  268. // override more recent ones), until a match is found.
  269. PT(VirtualFile) found_file = NULL;
  270. VirtualFileComposite *composite_file = NULL;
  271. Mounts::const_reverse_iterator rmi;
  272. for (rmi = _mounts.rbegin(); rmi != _mounts.rend(); ++rmi) {
  273. VirtualFileMount *mount = (*rmi);
  274. string mount_point = mount->get_mount_point();
  275. if (strpath == mount_point) {
  276. // Here's an exact match on the mount point. This filename is
  277. // the root directory of this mount object.
  278. if (found_match(found_file, composite_file, mount, "", pathname)) {
  279. return found_file;
  280. }
  281. } else if (mount_point.empty()) {
  282. // This is the root mount point; all files are in here.
  283. if (mount->has_file(strpath)) {
  284. // Bingo!
  285. if (found_match(found_file, composite_file, mount, strpath, pathname)) {
  286. return found_file;
  287. }
  288. }
  289. } else if (strpath.length() > mount_point.length() &&
  290. strpath.substr(0, mount_point.length()) == mount_point &&
  291. strpath[mount_point.length()] == '/') {
  292. // This pathname falls within this mount system.
  293. Filename local_filename = strpath.substr(mount_point.length() + 1);
  294. if (mount->has_file(local_filename)) {
  295. // Bingo!
  296. if (found_match(found_file, composite_file, mount, local_filename, pathname)) {
  297. return found_file;
  298. }
  299. }
  300. }
  301. }
  302. return found_file;
  303. }
  304. ////////////////////////////////////////////////////////////////////
  305. // Function: VirtualFileSystem::find_file
  306. // Access: Published
  307. // Description: Uses the indicated search path to find the file
  308. // within the file system. Returns the first occurrence
  309. // of the file found, or NULL if the file cannot be
  310. // found.
  311. ////////////////////////////////////////////////////////////////////
  312. PT(VirtualFile) VirtualFileSystem::
  313. find_file(const Filename &filename, const DSearchPath &searchpath) const {
  314. if (!filename.is_local()) {
  315. return get_file(filename);
  316. }
  317. int num_directories = searchpath.get_num_directories();
  318. for (int i = 0; i < num_directories; ++i) {
  319. Filename match(searchpath.get_directory(i), filename);
  320. if (searchpath.get_directory(i) == "." &&
  321. filename.is_fully_qualified()) {
  322. // A special case for the "." directory: to avoid prefixing an
  323. // endless stream of ./ in front of files, if the filename
  324. // already has a ./ prefixed (i.e. is_fully_qualified() is
  325. // true), we don't prefix another one.
  326. match = filename;
  327. }
  328. PT(VirtualFile) found_file = get_file(match);
  329. if (found_file != (VirtualFile *)NULL) {
  330. return found_file;
  331. }
  332. }
  333. return NULL;
  334. }
  335. ////////////////////////////////////////////////////////////////////
  336. // Function: VirtualFileSystem::resolve_filename
  337. // Access: Public
  338. // Description: Searches the given search path for the filename. If
  339. // it is found, updates the filename to the full
  340. // pathname found and returns true; otherwise, returns
  341. // false.
  342. ////////////////////////////////////////////////////////////////////
  343. bool VirtualFileSystem::
  344. resolve_filename(Filename &filename,
  345. const DSearchPath &searchpath,
  346. const string &default_extension) const {
  347. PT(VirtualFile) found;
  348. if (filename.is_local()) {
  349. found = find_file(filename, searchpath);
  350. if (found.is_null()) {
  351. // We didn't find it with the given extension; can we try the
  352. // default extension?
  353. if (filename.get_extension().empty() && !default_extension.empty()) {
  354. Filename try_ext = filename;
  355. try_ext.set_extension(default_extension);
  356. found = find_file(try_ext, searchpath);
  357. }
  358. }
  359. } else {
  360. if (exists(filename)) {
  361. // The full pathname exists. Return true.
  362. return true;
  363. } else {
  364. // The full pathname doesn't exist with the given extension;
  365. // does it exist with the default extension?
  366. if (filename.get_extension().empty() && !default_extension.empty()) {
  367. Filename try_ext = filename;
  368. try_ext.set_extension(default_extension);
  369. found = get_file(try_ext);
  370. }
  371. }
  372. }
  373. if (!found.is_null()) {
  374. filename = found->get_original_filename();
  375. return true;
  376. }
  377. return false;
  378. }
  379. ////////////////////////////////////////////////////////////////////
  380. // Function: VirtualFileSystem::find_all_files
  381. // Access: Public
  382. // Description: Searches all the directories in the search list for
  383. // the indicated file, in order. Fills up the results
  384. // list with *all* of the matching filenames found, if
  385. // any. Returns the number of matches found.
  386. //
  387. // It is the responsibility of the the caller to clear
  388. // the results list first; otherwise, the newly-found
  389. // files will be appended to the list.
  390. ////////////////////////////////////////////////////////////////////
  391. int VirtualFileSystem::
  392. find_all_files(const Filename &filename, const DSearchPath &searchpath,
  393. DSearchPath::Results &results) const {
  394. int num_added = 0;
  395. if (filename.is_local()) {
  396. int num_directories = searchpath.get_num_directories();
  397. for (int i = 0; i < num_directories; ++i) {
  398. Filename match(searchpath.get_directory(i), filename);
  399. if (exists(match)) {
  400. if (searchpath.get_directory(i) == "." &&
  401. filename.is_fully_qualified()) {
  402. // A special case for the "." directory: to avoid prefixing
  403. // an endless stream of ./ in front of files, if the
  404. // filename already has a ./ prefixed
  405. // (i.e. is_fully_fully_qualified() is true), we don't
  406. // prefix another one.
  407. results.add_file(filename);
  408. } else {
  409. results.add_file(match);
  410. }
  411. ++num_added;
  412. }
  413. }
  414. }
  415. return num_added;
  416. }
  417. ////////////////////////////////////////////////////////////////////
  418. // Function: VirtualFileSystem::write
  419. // Access: Published
  420. // Description: Print debugging information.
  421. // (e.g. from Python or gdb prompt).
  422. ////////////////////////////////////////////////////////////////////
  423. void VirtualFileSystem::
  424. write(ostream &out) const {
  425. out << "_cwd" << _cwd << "\n_mounts:\n";
  426. Mounts::const_iterator mi;
  427. for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) {
  428. VirtualFileMount *mount = (*mi);
  429. mount->write(out);
  430. }
  431. }
  432. ////////////////////////////////////////////////////////////////////
  433. // Function: VirtualFileSystem::get_global_ptr
  434. // Access: Published, Static
  435. // Description: Returns the default global VirtualFileSystem. You
  436. // may create your own personal VirtualFileSystem
  437. // objects and use them for whatever you like, but Panda
  438. // will attempt to load models and stuff from this
  439. // default object.
  440. //
  441. // Initially, the global VirtualFileSystem is set up to
  442. // mount the OS filesystem to root; i.e. it is
  443. // equivalent to the OS filesystem. This may be
  444. // subsequently adjusted by the user.
  445. ////////////////////////////////////////////////////////////////////
  446. VirtualFileSystem *VirtualFileSystem::
  447. get_global_ptr() {
  448. if (_global_ptr == (VirtualFileSystem *)NULL) {
  449. _global_ptr = new VirtualFileSystem;
  450. // Set up the default mounts. First, there is always the root
  451. // mount.
  452. _global_ptr->mount("/", "/", 0);
  453. // And our initial cwd comes from the environment.
  454. _global_ptr->chdir(ExecutionEnvironment::get_cwd());
  455. // Then, we add whatever mounts are listed in the Configrc file.
  456. ConfigVariableList mounts
  457. ("vfs-mount",
  458. PRC_DESC("vfs-mount system-filename mount-point [options]"));
  459. int num_unique_values = mounts.get_num_unique_values();
  460. for (int i = 0; i < num_unique_values; i++) {
  461. string mount_desc = mounts.get_unique_value(i);
  462. // The vfs-mount syntax is:
  463. // vfs-mount system-filename mount-point [options]
  464. // The last two spaces mark the beginning of the mount point,
  465. // and of the options, respectively. There might be multiple
  466. // spaces in the system filename, which are part of the
  467. // filename.
  468. // The last space marks the beginning of the mount point.
  469. // Spaces before that are part of the system filename.
  470. size_t space = mount_desc.rfind(' ');
  471. if (space == string::npos) {
  472. express_cat.warning()
  473. << "No space in vfs-mount descriptor: " << mount_desc << "\n";
  474. } else {
  475. string mount_point = mount_desc.substr(space + 1);
  476. while (space > 0 && isspace(mount_desc[space - 1])) {
  477. space--;
  478. }
  479. mount_desc = mount_desc.substr(0, space);
  480. string options;
  481. space = mount_desc.rfind(' ');
  482. if (space != string::npos) {
  483. // If there's another space, we have the optional options field.
  484. options = mount_point;
  485. mount_point = mount_desc.substr(space + 1);
  486. while (space > 0 && isspace(mount_desc[space - 1])) {
  487. --space;
  488. }
  489. mount_desc = mount_desc.substr(0, space);
  490. }
  491. mount_desc = ExecutionEnvironment::expand_string(mount_desc);
  492. Filename physical_filename = Filename::from_os_specific(mount_desc);
  493. int flags = 0;
  494. string password;
  495. // Split the options up by commas.
  496. size_t p = 0;
  497. size_t q = options.find(',', p);
  498. while (q != string::npos) {
  499. parse_option(options.substr(p, q - p),
  500. flags, password);
  501. p = q + 1;
  502. q = options.find(',', p);
  503. }
  504. parse_option(options.substr(p), flags, password);
  505. _global_ptr->mount(physical_filename, mount_point, flags, password);
  506. }
  507. }
  508. }
  509. return _global_ptr;
  510. }
  511. ////////////////////////////////////////////////////////////////////
  512. // Function: VirtualFileSystem::close_read_file
  513. // Access: Published
  514. // Description: Closes a file opened by a previous call to
  515. // open_read_file(). This really just deletes the
  516. // istream pointer, but it is recommended to use this
  517. // interface instead of deleting it explicitly, to help
  518. // work around compiler issues.
  519. ////////////////////////////////////////////////////////////////////
  520. void VirtualFileSystem::
  521. close_read_file(istream *stream) const {
  522. if (stream != (istream *)NULL) {
  523. // For some reason--compiler bug in gcc 3.2?--explicitly deleting
  524. // the stream pointer does not call the appropriate global delete
  525. // function; instead apparently calling the system delete
  526. // function. So we call the delete function by hand instead.
  527. #ifndef NDEBUG
  528. stream->~istream();
  529. (*global_operator_delete)(stream);
  530. #else
  531. delete stream;
  532. #endif
  533. }
  534. }
  535. ////////////////////////////////////////////////////////////////////
  536. // Function: VirtualFileSystem::scan_mount_points
  537. // Access: Public
  538. // Description: Adds to names a list of all the mount points in use
  539. // that are one directory below path, if any. That is,
  540. // these are the external files or directories mounted
  541. // directly to the indicated path.
  542. //
  543. // The names vector is filled with a set of basenames,
  544. // the basename part of the mount point.
  545. ////////////////////////////////////////////////////////////////////
  546. void VirtualFileSystem::
  547. scan_mount_points(vector_string &names, const Filename &path) const {
  548. nassertv(!path.empty() && !path.is_local());
  549. string prefix = path.get_fullpath().substr(1);
  550. Mounts::const_iterator mi;
  551. for (mi = _mounts.begin(); mi != _mounts.end(); ++mi) {
  552. VirtualFileMount *mount = (*mi);
  553. string mount_point = mount->get_mount_point();
  554. if (prefix.empty()) {
  555. // The indicated path is the root. Is the mount point on the
  556. // root?
  557. if (mount_point.find('/') == string::npos) {
  558. // No embedded slashes, so the mount point is only one
  559. // directory below the root.
  560. names.push_back(mount_point);
  561. }
  562. } else {
  563. if (mount_point.substr(0, prefix.length()) == prefix &&
  564. mount_point.length() > prefix.length() &&
  565. mount_point[prefix.length()] == '/') {
  566. // This mount point is below the indicated path. Is it only one
  567. // directory below?
  568. string basename = mount_point.substr(prefix.length());
  569. if (basename.find('/') == string::npos) {
  570. // No embedded slashes, so it's only one directory below.
  571. names.push_back(basename);
  572. }
  573. }
  574. }
  575. }
  576. }
  577. ////////////////////////////////////////////////////////////////////
  578. // Function: VirtualFileSystem::normalize_mount_point
  579. // Access: Private
  580. // Description: Converts the mount point string supplied by the user
  581. // to standard form (relative to the current directory,
  582. // with no double slashes, and not terminating with a
  583. // slash). The initial slash is removed.
  584. ////////////////////////////////////////////////////////////////////
  585. Filename VirtualFileSystem::
  586. normalize_mount_point(const string &mount_point) const {
  587. Filename nmp = mount_point;
  588. if (nmp.is_local()) {
  589. nmp = Filename(_cwd, mount_point);
  590. }
  591. nmp.standardize();
  592. nassertr(!nmp.empty() && nmp[0] == '/', nmp);
  593. return nmp.get_fullpath().substr(1);
  594. }
  595. ////////////////////////////////////////////////////////////////////
  596. // Function: VirtualFileSystem::found_match
  597. // Access: Private
  598. // Description: Evaluates one match found during a get_file()
  599. // operation. There may be multiple matches for a
  600. // particular filename due to the ambiguities introduced
  601. // by allowing multiple mount points, so we may have to
  602. // keep searching even after the first match is found.
  603. //
  604. // Returns true if the search should terminate now, or
  605. // false if it should keep iterating.
  606. ////////////////////////////////////////////////////////////////////
  607. bool VirtualFileSystem::
  608. found_match(PT(VirtualFile) &found_file, VirtualFileComposite *&composite_file,
  609. VirtualFileMount *mount, const string &local_filename,
  610. const Filename &original_filename) const {
  611. if (found_file == (VirtualFile *)NULL) {
  612. // This was our first match. Save it.
  613. found_file = new VirtualFileSimple(mount, local_filename);
  614. found_file->set_original_filename(original_filename);
  615. if (!mount->is_directory(local_filename)) {
  616. // If it's not a directory, we're done.
  617. return true;
  618. }
  619. } else {
  620. // This was our second match. The previous match(es) must
  621. // have been directories.
  622. if (!mount->is_directory(local_filename)) {
  623. // However, this one isn't a directory. We're done.
  624. return true;
  625. }
  626. // At least two directories matched to the same path. We
  627. // need a composite directory.
  628. if (composite_file == (VirtualFileComposite *)NULL) {
  629. composite_file =
  630. new VirtualFileComposite((VirtualFileSystem *)this, found_file->get_original_filename());
  631. composite_file->set_original_filename(original_filename);
  632. composite_file->add_component(found_file);
  633. found_file = composite_file;
  634. }
  635. composite_file->add_component(new VirtualFileSimple(mount, local_filename));
  636. }
  637. // Keep going, looking for more directories.
  638. return false;
  639. }
  640. ////////////////////////////////////////////////////////////////////
  641. // Function: VirtualFileSystem::parse_option
  642. // Access: Private, Static
  643. // Description: Parses one of the option flags in the options list on
  644. // the vfs-mount Config.prc line.
  645. ////////////////////////////////////////////////////////////////////
  646. void VirtualFileSystem::
  647. parse_option(const string &option, int &flags, string &password) {
  648. if (option == "0" || option.empty()) {
  649. // 0 is the null option.
  650. } else if (option == "ro") {
  651. flags |= MF_read_only;
  652. } else if (option.substr(0, 3) == "pw:") {
  653. password = option.substr(3);
  654. } else {
  655. express_cat.warning()
  656. << "Invalid option on vfs-mount: \"" << option << "\"\n";
  657. }
  658. }