Panda3D
 All Classes Functions Variables Enumerations
virtualFileMountSystem.cxx
1 // Filename: virtualFileMountSystem.cxx
2 // Created by: drose (03Aug02)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "virtualFileMountSystem.h"
16 
17 TypeHandle VirtualFileMountSystem::_type_handle;
18 
19 
20 ////////////////////////////////////////////////////////////////////
21 // Function: VirtualFileMountSystem::has_file
22 // Access: Public, Virtual
23 // Description: Returns true if the indicated file exists within the
24 // mount system.
25 ////////////////////////////////////////////////////////////////////
27 has_file(const Filename &file) const {
28  Filename pathname(_physical_filename, file);
29 #ifdef WIN32
30  if (VirtualFileSystem::get_global_ptr()->vfs_case_sensitive) {
31  Filename case_pathname = pathname;
32  if (!case_pathname.make_true_case()) {
33  return false;
34  }
35  if (case_pathname != pathname) {
36  express_cat.warning()
37  << "Filename is incorrect case: " << pathname
38  << " instead of " << case_pathname << "\n";
39  return false;
40  }
41  }
42 #endif // WIN32
43  return pathname.exists();
44 }
45 
46 ////////////////////////////////////////////////////////////////////
47 // Function: VirtualFileMountSystem::create_file
48 // Access: Public, Virtual
49 // Description: Attempts to create the indicated file within the
50 // mount, if it does not already exist. Returns true on
51 // success (or if the file already exists), or false if
52 // it cannot be created.
53 ////////////////////////////////////////////////////////////////////
55 create_file(const Filename &file) {
56  Filename pathname(_physical_filename, file);
57  pathname.set_binary();
58  ofstream stream;
59  return pathname.open_write(stream, false);
60 }
61 
62 ////////////////////////////////////////////////////////////////////
63 // Function: VirtualFileMountSystem::delete_file
64 // Access: Public, Virtual
65 // Description: Attempts to delete the indicated file or directory
66 // within the mount. This can remove a single file or
67 // an empty directory. It will not remove a nonempty
68 // directory. Returns true on success, false on
69 // failure.
70 ////////////////////////////////////////////////////////////////////
72 delete_file(const Filename &file) {
73  Filename pathname(_physical_filename, file);
74  return pathname.unlink() || pathname.rmdir();
75 }
76 
77 ////////////////////////////////////////////////////////////////////
78 // Function: VirtualFileMountSystem::rename_file
79 // Access: Public
80 // Description: Attempts to rename the contents of the indicated file
81 // to the indicated file. Both filenames will be within
82 // the mount. Returns true on success, false on
83 // failure. If this returns false, this will be
84 // attempted again with a copy-and-delete operation.
85 ////////////////////////////////////////////////////////////////////
87 rename_file(const Filename &orig_filename, const Filename &new_filename) {
88  Filename orig_pathname(_physical_filename, orig_filename);
89  Filename new_pathname(_physical_filename, new_filename);
90  return orig_pathname.rename_to(new_pathname);
91 }
92 
93 ////////////////////////////////////////////////////////////////////
94 // Function: VirtualFileMountSystem::copy_file
95 // Access: Public
96 // Description: Attempts to copy the contents of the indicated file
97 // to the indicated file. Both filenames will be within
98 // the mount. Returns true on success, false on
99 // failure. If this returns false, the copy will be
100 // performed by explicit read-and-write operations.
101 ////////////////////////////////////////////////////////////////////
103 copy_file(const Filename &orig_filename, const Filename &new_filename) {
104  Filename orig_pathname(_physical_filename, orig_filename);
105  Filename new_pathname(_physical_filename, new_filename);
106  return orig_pathname.copy_to(new_pathname);
107 }
108 
109 ////////////////////////////////////////////////////////////////////
110 // Function: VirtualFileMountSystem::make_directory
111 // Access: Public, Virtual
112 // Description: Attempts to create the indicated file within the
113 // mount, if it does not already exist. Returns true on
114 // success, or false if it cannot be created. If the
115 // directory already existed prior to this call, may
116 // return either true or false.
117 ////////////////////////////////////////////////////////////////////
119 make_directory(const Filename &file) {
120  Filename pathname(_physical_filename, file);
121  return pathname.mkdir();
122 }
123 
124 ////////////////////////////////////////////////////////////////////
125 // Function: VirtualFileMountSystem::is_directory
126 // Access: Public, Virtual
127 // Description: Returns true if the indicated file exists within the
128 // mount system and is a directory.
129 ////////////////////////////////////////////////////////////////////
131 is_directory(const Filename &file) const {
132 #ifdef WIN32
133  // First ensure that the file exists to validate its case.
134  if (VirtualFileSystem::get_global_ptr()->vfs_case_sensitive) {
135  if (!has_file(file)) {
136  return false;
137  }
138  }
139 #endif // WIN32
140  Filename pathname(_physical_filename, file);
141  return pathname.is_directory();
142 }
143 
144 ////////////////////////////////////////////////////////////////////
145 // Function: VirtualFileMountSystem::is_regular_file
146 // Access: Public, Virtual
147 // Description: Returns true if the indicated file exists within the
148 // mount system and is a regular file.
149 ////////////////////////////////////////////////////////////////////
151 is_regular_file(const Filename &file) const {
152 #ifdef WIN32
153  // First ensure that the file exists to validate its case.
154  if (VirtualFileSystem::get_global_ptr()->vfs_case_sensitive) {
155  if (!has_file(file)) {
156  return false;
157  }
158  }
159 #endif // WIN32
160  Filename pathname(_physical_filename, file);
161  return pathname.is_regular_file();
162 }
163 
164 ////////////////////////////////////////////////////////////////////
165 // Function: VirtualFileMountSystem::is_writable
166 // Access: Public, Virtual
167 // Description: Returns true if the named file or directory may be
168 // written to, false otherwise.
169 ////////////////////////////////////////////////////////////////////
171 is_writable(const Filename &file) const {
172 #ifdef WIN32
173  // First ensure that the file exists to validate its case.
174  if (VirtualFileSystem::get_global_ptr()->vfs_case_sensitive) {
175  if (!has_file(file)) {
176  return false;
177  }
178  }
179 #endif // WIN32
180  Filename pathname(_physical_filename, file);
181  return pathname.is_writable();
182 }
183 
184 ////////////////////////////////////////////////////////////////////
185 // Function: VirtualFileMountSystem::open_read_file
186 // Access: Public, Virtual
187 // Description: Opens the file for reading, if it exists. Returns a
188 // newly allocated istream on success (which you should
189 // eventually delete when you are done reading).
190 // Returns NULL on failure.
191 ////////////////////////////////////////////////////////////////////
193 open_read_file(const Filename &file) const {
194 #ifdef WIN32
195  // First ensure that the file exists to validate its case.
196  if (VirtualFileSystem::get_global_ptr()->vfs_case_sensitive) {
197  if (!has_file(file)) {
198  return NULL;
199  }
200  }
201 #endif // WIN32
202  Filename pathname(_physical_filename, file);
203  pifstream *stream = new pifstream;
204  if (!pathname.open_read(*stream)) {
205  // Couldn't open the file for some reason.
206  close_read_file(stream);
207  return NULL;
208  }
209 
210  return stream;
211 }
212 
213 ////////////////////////////////////////////////////////////////////
214 // Function: VirtualFileMountSystem::open_write_file
215 // Access: Published, Virtual
216 // Description: Opens the file for writing. Returns a newly
217 // allocated ostream on success (which you should
218 // eventually delete when you are done writing).
219 // Returns NULL on failure.
220 ////////////////////////////////////////////////////////////////////
222 open_write_file(const Filename &file, bool truncate) {
223 #ifdef WIN32
224  // First ensure that the file exists to validate its case.
225  if (VirtualFileSystem::get_global_ptr()->vfs_case_sensitive) {
226  if (!has_file(file)) {
227  return NULL;
228  }
229  }
230 #endif // WIN32
231  Filename pathname(_physical_filename, file);
232  pofstream *stream = new pofstream;
233  if (!pathname.open_write(*stream, truncate)) {
234  // Couldn't open the file for some reason.
235  close_write_file(stream);
236  return NULL;
237  }
238 
239  return stream;
240 }
241 
242 ////////////////////////////////////////////////////////////////////
243 // Function: VirtualFileMountSystem::open_append_file
244 // Access: Published
245 // Description: Works like open_write_file(), but the file is opened
246 // in append mode. Like open_write_file, the returned
247 // pointer should eventually be passed to
248 // close_write_file().
249 ////////////////////////////////////////////////////////////////////
252 #ifdef WIN32
253  // First ensure that the file exists to validate its case.
254  if (VirtualFileSystem::get_global_ptr()->vfs_case_sensitive) {
255  if (!has_file(file)) {
256  return NULL;
257  }
258  }
259 #endif // WIN32
260  Filename pathname(_physical_filename, file);
261  pofstream *stream = new pofstream;
262  if (!pathname.open_append(*stream)) {
263  // Couldn't open the file for some reason.
264  close_write_file(stream);
265  return NULL;
266  }
267 
268  return stream;
269 }
270 
271 ////////////////////////////////////////////////////////////////////
272 // Function: VirtualFileMountSystem::open_read_write_file
273 // Access: Published, Virtual
274 // Description: Opens the file for writing. Returns a newly
275 // allocated iostream on success (which you should
276 // eventually delete when you are done writing).
277 // Returns NULL on failure.
278 ////////////////////////////////////////////////////////////////////
279 iostream *VirtualFileMountSystem::
280 open_read_write_file(const Filename &file, bool truncate) {
281 #ifdef WIN32
282  // First ensure that the file exists to validate its case.
283  if (VirtualFileSystem::get_global_ptr()->vfs_case_sensitive) {
284  if (!has_file(file)) {
285  return NULL;
286  }
287  }
288 #endif // WIN32
289  Filename pathname(_physical_filename, file);
290  pfstream *stream = new pfstream;
291  if (!pathname.open_read_write(*stream, truncate)) {
292  // Couldn't open the file for some reason.
293  close_read_write_file(stream);
294  return NULL;
295  }
296 
297  return stream;
298 }
299 
300 ////////////////////////////////////////////////////////////////////
301 // Function: VirtualFileMountSystem::open_read_append_file
302 // Access: Published, Virtual
303 // Description: Works like open_read_write_file(), but the file is opened
304 // in append mode. Like open_read_write_file, the returned
305 // pointer should eventually be passed to
306 // close_read_write_file().
307 ////////////////////////////////////////////////////////////////////
308 iostream *VirtualFileMountSystem::
310 #ifdef WIN32
311  // First ensure that the file exists to validate its case.
312  if (VirtualFileSystem::get_global_ptr()->vfs_case_sensitive) {
313  if (!has_file(file)) {
314  return NULL;
315  }
316  }
317 #endif // WIN32
318  Filename pathname(_physical_filename, file);
319  pfstream *stream = new pfstream;
320  if (!pathname.open_read_append(*stream)) {
321  // Couldn't open the file for some reason.
322  close_read_write_file(stream);
323  return NULL;
324  }
325 
326  return stream;
327 }
328 
329 ////////////////////////////////////////////////////////////////////
330 // Function: VirtualFileMountSystem::get_file_size
331 // Access: Published, Virtual
332 // Description: Returns the current size on disk (or wherever it is)
333 // of the already-open file. Pass in the stream that
334 // was returned by open_read_file(); some
335 // implementations may require this stream to determine
336 // the size.
337 ////////////////////////////////////////////////////////////////////
338 streamsize VirtualFileMountSystem::
339 get_file_size(const Filename &file, istream *stream) const {
340  // First, save the original stream position.
341  streampos orig = stream->tellg();
342 
343  // Seek to the end and get the stream position there.
344  stream->seekg(0, ios::end);
345  if (stream->fail()) {
346  // Seeking not supported.
347  stream->clear();
348  return get_file_size(file);
349  }
350  streampos size = stream->tellg();
351 
352  // Then return to the original point.
353  stream->seekg(orig, ios::beg);
354 
355  // Make sure there are no error flags set as a result of the seek.
356  stream->clear();
357 
358  return size;
359 }
360 
361 ////////////////////////////////////////////////////////////////////
362 // Function: VirtualFileMountSystem::get_file_size
363 // Access: Published, Virtual
364 // Description: Returns the current size on disk (or wherever it is)
365 // of the file before it has been opened.
366 ////////////////////////////////////////////////////////////////////
367 streamsize VirtualFileMountSystem::
368 get_file_size(const Filename &file) const {
369  Filename pathname(_physical_filename, file);
370  return pathname.get_file_size();
371 }
372 
373 ////////////////////////////////////////////////////////////////////
374 // Function: VirtualFileMountSystem::get_timestamp
375 // Access: Published, Virtual
376 // Description: Returns a time_t value that represents the time the
377 // file was last modified, to within whatever precision
378 // the operating system records this information (on a
379 // Windows95 system, for instance, this may only be
380 // accurate to within 2 seconds).
381 //
382 // If the timestamp cannot be determined, either because
383 // it is not supported by the operating system or
384 // because there is some error (such as file not found),
385 // returns 0.
386 ////////////////////////////////////////////////////////////////////
388 get_timestamp(const Filename &file) const {
389  Filename pathname(_physical_filename, file);
390  return pathname.get_timestamp();
391 }
392 
393 ////////////////////////////////////////////////////////////////////
394 // Function: VirtualFileMountSystem::get_system_info
395 // Access: Public, Virtual
396 // Description: Populates the SubfileInfo structure with the data
397 // representing where the file actually resides on disk,
398 // if this is knowable. Returns true if the file might
399 // reside on disk, and the info is populated, or false
400 // if it does not (or it is not known where the file
401 // resides), in which case the info is meaningless.
402 ////////////////////////////////////////////////////////////////////
404 get_system_info(const Filename &file, SubfileInfo &info) {
405  Filename pathname(_physical_filename, file);
406  info = SubfileInfo(pathname, 0, pathname.get_file_size());
407  return true;
408 }
409 
410 ////////////////////////////////////////////////////////////////////
411 // Function: VirtualFileMountSystem::scan_directory
412 // Access: Public, Virtual
413 // Description: Fills the given vector up with the list of filenames
414 // that are local to this directory, if the filename is
415 // a directory. Returns true if successful, or false if
416 // the file is not a directory or cannot be read.
417 ////////////////////////////////////////////////////////////////////
419 scan_directory(vector_string &contents, const Filename &dir) const {
420 #ifdef WIN32
421  // First ensure that the file exists to validate its case.
422  if (VirtualFileSystem::get_global_ptr()->vfs_case_sensitive) {
423  if (!has_file(dir)) {
424  return false;
425  }
426  }
427 #endif // WIN32
428  Filename pathname(_physical_filename, dir);
429  return pathname.scan_directory(contents);
430 }
431 
432 
433 ////////////////////////////////////////////////////////////////////
434 // Function: VirtualFileMountSystem::atomic_compare_and_exchange_contents
435 // Access: Public, Virtual
436 // Description: See Filename::atomic_compare_and_exchange_contents().
437 ////////////////////////////////////////////////////////////////////
439 atomic_compare_and_exchange_contents(const Filename &file, string &orig_contents,
440  const string &old_contents,
441  const string &new_contents) {
442 #ifdef WIN32
443  // First ensure that the file exists to validate its case.
444  if (VirtualFileSystem::get_global_ptr()->vfs_case_sensitive) {
445  if (!has_file(file)) {
446  return NULL;
447  }
448  }
449 #endif // WIN32
450  Filename pathname(_physical_filename, file);
451  return pathname.atomic_compare_and_exchange_contents(orig_contents, old_contents, new_contents);
452 }
453 
454 ////////////////////////////////////////////////////////////////////
455 // Function: VirtualFileMountSystem::atomic_read_contents
456 // Access: Public, Virtual
457 // Description: See Filename::atomic_read_contents().
458 ////////////////////////////////////////////////////////////////////
460 atomic_read_contents(const Filename &file, string &contents) const {
461 #ifdef WIN32
462  // First ensure that the file exists to validate its case.
463  if (VirtualFileSystem::get_global_ptr()->vfs_case_sensitive) {
464  if (!has_file(file)) {
465  return NULL;
466  }
467  }
468 #endif // WIN32
469  Filename pathname(_physical_filename, file);
470  return pathname.atomic_read_contents(contents);
471 }
472 
473 ////////////////////////////////////////////////////////////////////
474 // Function: VirtualFileMountSystem::output
475 // Access: Public, Virtual
476 // Description:
477 ////////////////////////////////////////////////////////////////////
478 void VirtualFileMountSystem::
479 output(ostream &out) const {
480  out << get_physical_filename();
481 }
virtual bool make_directory(const Filename &file)
Attempts to create the indicated file within the mount, if it does not already exist.
bool mkdir() const
Creates the directory named by this filename.
Definition: filename.cxx:2789
bool open_append(ofstream &stream) const
Opens the indicated ofstream for writing the file, if possible.
Definition: filename.cxx:2101
bool atomic_read_contents(string &contents) const
Uses native file-locking mechanisms to atomically read the contents of a (small) file.
Definition: filename.cxx:3049
virtual bool is_directory(const Filename &file) const
Returns true if the indicated file exists within the mount system and is a directory.
virtual bool atomic_compare_and_exchange_contents(const Filename &file, string &orig_contents, const string &old_contents, const string &new_contents)
See Filename::atomic_compare_and_exchange_contents().
bool unlink() const
Permanently deletes the file associated with the filename, if possible.
Definition: filename.cxx:2554
bool is_directory() const
Returns true if the filename exists and is a directory name, false otherwise.
Definition: filename.cxx:1456
virtual istream * open_read_file(const Filename &file) const
Opens the file for reading, if it exists.
virtual iostream * open_read_write_file(const Filename &file, bool truncate)
Opens the file for writing.
virtual time_t get_timestamp(const Filename &file) const
Returns a time_t value that represents the time the file was last modified, to within whatever precis...
void set_binary()
Indicates that the filename represents a binary file.
Definition: filename.I:494
bool open_read(ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
Definition: filename.cxx:2003
bool make_true_case()
On a case-insensitive operating system (e.g.
Definition: filename.cxx:1120
bool open_read_write(fstream &stream, bool truncate=false) const
Opens the indicated fstream for read/write access to the file, if possible.
Definition: filename.cxx:2143
bool scan_directory(vector_string &contents) const
Attempts to open the named filename as if it were a directory and looks for the non-hidden files with...
Definition: filename.cxx:1854
virtual bool has_file(const Filename &file) const
Returns true if the indicated file exists within the mount system.
virtual ostream * open_write_file(const Filename &file, bool truncate)
Opens the file for writing.
virtual void close_read_file(istream *stream) const
Closes a file opened by a previous call to open_read_file().
bool copy_to(const Filename &other) const
Copies the file to the indicated new filename, by reading the contents and writing it to the new file...
Definition: filename.cxx:2680
virtual bool atomic_read_contents(const Filename &file, string &contents) const
See Filename::atomic_read_contents().
virtual ostream * open_append_file(const Filename &file)
Works like open_write_file(), but the file is opened in append mode.
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...
bool is_writable() const
Returns true if the filename exists and is either a directory or a regular file that can be written t...
Definition: filename.cxx:1422
virtual bool create_file(const Filename &file)
Attempts to create the indicated file within the mount, if it does not already exist.
virtual bool rename_file(const Filename &orig_filename, const Filename &new_filename)
Attempts to rename the contents of the indicated file to the indicated file.
virtual bool scan_directory(vector_string &contents, const Filename &dir) const
Fills the given vector up with the list of filenames that are local to this directory, if the filename is a directory.
bool rename_to(const Filename &other) const
Renames the file to the indicated new filename.
Definition: filename.cxx:2577
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
virtual bool is_regular_file(const Filename &file) const
Returns true if the indicated file exists within the mount system and is a regular file...
bool exists() const
Returns true if the filename exists on the disk, false otherwise.
Definition: filename.cxx:1356
bool open_read_append(fstream &stream) const
Opens the indicated ifstream for reading and writing the file, if possible; writes are appended to th...
Definition: filename.cxx:2196
streamsize get_file_size() const
Returns the size of the file in bytes, or 0 if there is an error.
Definition: filename.cxx:1665
This class records a particular byte sub-range within an existing file on disk.
Definition: subfileInfo.h:29
virtual void close_write_file(ostream *stream)
Closes a file opened by a previous call to open_write_file().
virtual bool delete_file(const Filename &file)
Attempts to delete the indicated file or directory within the mount.
bool is_regular_file() const
Returns true if the filename exists and is the name of a regular file (i.e.
Definition: filename.cxx:1389
bool open_write(ofstream &stream, bool truncate=true) const
Opens the indicated ifstream for writing the file, if possible.
Definition: filename.cxx:2045
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:85
virtual void close_read_write_file(iostream *stream)
Closes a file opened by a previous call to open_read_write_file().
virtual iostream * open_read_append_file(const Filename &file)
Works like open_read_write_file(), but the file is opened in append mode.
virtual bool copy_file(const Filename &orig_filename, const Filename &new_filename)
Attempts to copy the contents of the indicated file to the indicated file.
time_t get_timestamp() const
Returns a time_t value that represents the time the file was last modified, to within whatever precis...
Definition: filename.cxx:1605
bool rmdir() const
The inverse of mkdir(): this removes the directory named by this Filename, if it is in fact a directo...
Definition: filename.cxx:2808
bool atomic_compare_and_exchange_contents(string &orig_contents, const string &old_contents, const string &new_contents) const
Uses native file-locking mechanisms to atomically replace the contents of a (small) file with the spe...
Definition: filename.cxx:2906
virtual bool is_writable(const Filename &file) const
Returns true if the named file or directory may be written to, false otherwise.
virtual streamsize get_file_size(const Filename &file, istream *stream) const
Returns the current size on disk (or wherever it is) of the already-open file.
virtual bool get_system_info(const Filename &file, SubfileInfo &info)
Populates the SubfileInfo structure with the data representing where the file actually resides on dis...