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
15#include "virtualFileSystem.h"
16
17using std::iostream;
18using std::istream;
19using std::ostream;
20using std::streampos;
21using std::streamsize;
22using std::string;
23
24TypeHandle VirtualFileMountSystem::_type_handle;
25
26
27/**
28 * Returns true if the indicated file exists within the mount system.
29 */
31has_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 */
56create_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 */
69delete_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 */
81rename_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 */
94copy_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 */
107make_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 */
117is_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 */
135is_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 */
153is_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 */
172open_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 */
198open_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 */
224open_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 */
250open_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 */
276open_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 */
302get_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 */
329get_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 */
345get_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 */
358get_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 */
370scan_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 */
388atomic_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 */
407atomic_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 */
423void VirtualFileMountSystem::
424output(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.