Panda3D
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.
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().
virtual bool is_directory(const Filename &file) const
Returns true if the indicated file exists within the mount system and is a directory.
bool open_write(ofstream &stream, bool truncate=true) const
Opens the indicated ifstream for writing the file, if possible.
Definition: filename.cxx:2045
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.
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
virtual void close_read_file(istream *stream) const
Closes a file opened by a previous call to open_read_file().
virtual bool has_file(const Filename &file) const
Returns true if the indicated file exists within the mount system.
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 bool is_regular_file(const Filename &file) const
Returns true if the indicated file exists within the mount system and is a regular file...
streamsize get_file_size() const
Returns the size of the file in bytes, or 0 if there is an error.
Definition: filename.cxx:1665
void set_binary()
Indicates that the filename represents a binary file.
Definition: filename.I:494
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
bool make_true_case()
On a case-insensitive operating system (e.g.
Definition: filename.cxx:1120
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
bool open_append(ofstream &stream) const
Opens the indicated ofstream for writing the file, if possible.
Definition: filename.cxx:2101
virtual ostream * open_write_file(const Filename &file, bool truncate)
Opens the file for writing.
bool open_read(ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
Definition: filename.cxx:2003
virtual ostream * open_append_file(const Filename &file)
Works like open_write_file(), but the file is opened in append mode.
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.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
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
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
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
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 unlink() const
Permanently deletes the file associated with the filename, if possible.
Definition: filename.cxx:2554
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
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...
bool is_directory() const
Returns true if the filename exists and is a directory name, false otherwise.
Definition: filename.cxx:1456
virtual bool atomic_read_contents(const Filename &file, string &contents) const
See Filename::atomic_read_contents().
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
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().
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
virtual bool delete_file(const Filename &file)
Attempts to delete the indicated file or directory within the mount.
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 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.
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.
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
bool rename_to(const Filename &other) const
Renames the file to the indicated new filename.
Definition: filename.cxx:2577
bool exists() const
Returns true if the filename exists on the disk, false otherwise.
Definition: filename.cxx:1356
virtual bool is_writable(const Filename &file) const
Returns true if the named file or directory may be written to, false otherwise.
bool mkdir() const
Creates the directory named by this filename.
Definition: filename.cxx:2789
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...