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