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  */
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  */
249 iostream *VirtualFileMountSystem::
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  */
275 iostream *VirtualFileMountSystem::
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  */
301 streamsize VirtualFileMountSystem::
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  */
328 streamsize VirtualFileMountSystem::
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 }
virtual bool make_directory(const Filename &file)
Attempts to create the indicated file within the mount, if it does not already exist.
virtual void close_write_file(std::ostream *stream)
Closes a file opened by a previous call to open_write_file().
bool open_write(std::ofstream &stream, bool truncate=true) const
Opens the indicated ifstream for writing the file, if possible.
Definition: filename.cxx:1899
virtual bool is_directory(const Filename &file) const
Returns true if the indicated file exists within the mount system and is a directory.
virtual void close_read_file(std::istream *stream) const
Closes a file opened by a previous call to open_read_file().
bool open_append(std::ofstream &stream) const
Opens the indicated ofstream for writing the file, if possible.
Definition: filename.cxx:1945
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
virtual bool has_file(const Filename &file) const
Returns true if the indicated file exists within the mount system.
virtual std::istream * open_read_file(const Filename &file) const
Opens the file for reading, if it exists.
virtual std::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.
void set_binary()
Indicates that the filename represents a binary file.
Definition: filename.I:414
bool open_read(std::ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
Definition: filename.cxx:1863
virtual void close_read_write_file(std::iostream *stream)
Closes a file opened by a previous call to open_read_write_file().
bool make_true_case()
On a case-insensitive operating system (e.g.
Definition: filename.cxx:1053
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
virtual std::ostream * open_write_file(const Filename &file, bool truncate)
Opens the file for writing.
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
virtual std::ostream * open_append_file(const Filename &file)
Works like open_write_file(), but the file is opened in append mode.
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 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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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().
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
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
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
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:2319
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 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
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:1359
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
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class records a particular byte sub-range within an existing file on disk.
Definition: subfileInfo.h:26
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
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
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:1718
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
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,...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
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 copy_file(const Filename &orig_filename, const Filename &new_filename)
Attempts to copy the contents of the indicated file to the indicated file.
bool rename_to(const Filename &other) const
Renames the file to the indicated new filename.
Definition: filename.cxx:2339
virtual bool atomic_read_contents(const Filename &file, std::string &contents) const
See Filename::atomic_read_contents().
bool exists() const
Returns true if the filename exists on the disk, false otherwise.
Definition: filename.cxx:1267
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:2540
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...