Panda3D
virtualFileSimple.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 virtualFileSimple.cxx
10  * @author drose
11  * @date 2002-08-03
12  */
13 
14 #include "virtualFileSimple.h"
15 #include "virtualFileMount.h"
16 #include "virtualFileList.h"
17 #include "dcast.h"
18 
19 using std::iostream;
20 using std::istream;
21 using std::ostream;
22 using std::string;
23 
24 TypeHandle VirtualFileSimple::_type_handle;
25 
26 
27 /**
28  * Returns the VirtualFileSystem this file is associated with.
29  */
31 get_file_system() const {
32  return _mount->get_file_system();
33 }
34 
35 /**
36  * Returns the full pathname to this file within the virtual file system.
37  */
39 get_filename() const {
40  string mount_point = _mount->get_mount_point();
41  if (_local_filename.empty()) {
42  if (mount_point.empty()) {
43  return "/";
44  } else {
45  return string("/") + mount_point;
46  }
47 
48  } else {
49  if (mount_point.empty()) {
50  return string("/") + _local_filename.get_fullpath();
51  } else {
52  return string("/") + mount_point + string("/") + _local_filename.get_fullpath();
53  }
54  }
55 }
56 
57 /**
58  * Returns true if this file exists, false otherwise.
59  */
61 has_file() const {
62  return _mount->has_file(_local_filename);
63 }
64 
65 /**
66  * Returns true if this file represents a directory (and scan_directory() may
67  * be called), false otherwise.
68  */
70 is_directory() const {
71  return _mount->is_directory(_local_filename);
72 }
73 
74 /**
75  * Returns true if this file represents a regular file (and read_file() may be
76  * called), false otherwise.
77  */
79 is_regular_file() const {
80  return _mount->is_regular_file(_local_filename);
81 }
82 
83 /**
84  * Returns true if this file represents a writable regular file (and
85  * write_file() may be called), false otherwise.
86  */
88 is_writable() const {
89  return _mount->is_writable(_local_filename);
90 }
91 
92 /**
93  * Attempts to delete this file or directory. This can remove a single file
94  * or an empty directory. It will not remove a nonempty directory. Returns
95  * true on success, false on failure.
96  */
99  return _mount->delete_file(_local_filename);
100 }
101 
102 /**
103  * Attempts to move or rename this file or directory. If the original file is
104  * an ordinary file, it will quietly replace any already-existing file in the
105  * new filename (but not a directory). If the original file is a directory,
106  * the new filename must not already exist.
107  *
108  * If the file is a directory, the new filename must be within the same mount
109  * point. If the file is an ordinary file, the new filename may be anywhere;
110  * but if it is not within the same mount point then the rename operation is
111  * automatically performed as a two-step copy-and-delete operation.
112  */
115  if (new_file->is_of_type(VirtualFileSimple::get_class_type())) {
116  VirtualFileSimple *new_file_simple = DCAST(VirtualFileSimple, new_file);
117  if (new_file_simple->_mount == _mount) {
118  // Same mount pount.
119  if (_mount->rename_file(_local_filename, new_file_simple->_local_filename)) {
120  return true;
121  }
122  }
123  }
124 
125  // Different mount point, or the mount doesn't support renaming. Do it by
126  // hand.
127  if (is_regular_file() && !new_file->is_directory()) {
128  // copy-and-delete.
129  new_file->delete_file();
130  if (copy_file(new_file)) {
131  delete_file();
132  return true;
133  }
134  }
135 
136  return false;
137 }
138 
139 /**
140  * Attempts to copy the contents of this file to the indicated file. Returns
141  * true on success, false on failure.
142  */
144 copy_file(VirtualFile *new_file) {
145  if (new_file->is_of_type(VirtualFileSimple::get_class_type())) {
146  VirtualFileSimple *new_file_simple = DCAST(VirtualFileSimple, new_file);
147  if (new_file_simple->_mount == _mount) {
148  // Same mount pount.
149  if (_mount->copy_file(_local_filename, new_file_simple->_local_filename)) {
150  return true;
151  }
152  }
153  }
154 
155  // Different mount point, or the mount doesn't support copying. Do it by
156  // hand.
157  ostream *out = new_file->open_write_file(false, true);
158  if (out == nullptr) {
159  return false;
160  }
161 
162  istream *in = open_read_file(false);
163  if (in == nullptr) {
164  new_file->close_write_file(out);
165  new_file->delete_file();
166  return false;
167  }
168 
169  static const size_t buffer_size = 4096;
170  char buffer[buffer_size];
171 
172  in->read(buffer, buffer_size);
173  size_t count = in->gcount();
174  while (count != 0) {
175  out->write(buffer, count);
176  if (out->fail()) {
177  new_file->close_write_file(out);
178  close_read_file(in);
179  new_file->delete_file();
180  return false;
181  }
182  in->read(buffer, buffer_size);
183  count = in->gcount();
184  }
185 
186  if (!in->eof()) {
187  new_file->close_write_file(out);
188  close_read_file(in);
189  new_file->delete_file();
190  return false;
191  }
192 
193  new_file->close_write_file(out);
194  close_read_file(in);
195  return true;
196 }
197 
198 /**
199  * Opens the file for reading. Returns a newly allocated istream on success
200  * (which you should eventually delete when you are done reading). Returns
201  * NULL on failure.
202  *
203  * If auto_unwrap is true, an explicitly-named .pz/.gz file is automatically
204  * decompressed and the decompressed contents are returned. This is different
205  * than vfs-implicit-pz, which will automatically decompress a file if the
206  * extension .pz is *not* given.
207  */
208 istream *VirtualFileSimple::
209 open_read_file(bool auto_unwrap) const {
210 
211  // Will we be automatically unwrapping a .pz file?
212  bool do_uncompress = (_implicit_pz_file ||
213  (auto_unwrap && (_local_filename.get_extension() == "pz" ||
214  _local_filename.get_extension() == "gz")));
215 
216  Filename local_filename(_local_filename);
217  if (do_uncompress) {
218  // .pz files are always binary, of course.
219  local_filename.set_binary();
220  }
221 
222  return _mount->open_read_file(local_filename, do_uncompress);
223 }
224 
225 /**
226  * Closes a file opened by a previous call to open_read_file(). This really
227  * just deletes the istream pointer, but it is recommended to use this
228  * interface instead of deleting it explicitly, to help work around compiler
229  * issues.
230  */
232 close_read_file(istream *stream) const {
233  _mount->close_read_file(stream);
234 }
235 
236 /**
237  * Opens the file for writing. Returns a newly allocated ostream on success
238  * (which you should eventually delete when you are done writing). Returns
239  * NULL on failure.
240  *
241  * If auto_wrap is true, an explicitly-named .pz file is automatically
242  * compressed while writing. If truncate is true, the file is truncated to
243  * zero length before writing.
244  */
245 ostream *VirtualFileSimple::
246 open_write_file(bool auto_wrap, bool truncate) {
247  // Will we be automatically wrapping a .pz file?
248  bool do_compress = (_implicit_pz_file || (auto_wrap && _local_filename.get_extension() == "pz"));
249 
250  Filename local_filename(_local_filename);
251  if (do_compress) {
252  // .pz files are always binary, of course.
253  local_filename.set_binary();
254  }
255 
256  return _mount->open_write_file(local_filename, do_compress, truncate);
257 }
258 
259 /**
260  * Works like open_write_file(), but the file is opened in append mode. Like
261  * open_write_file, the returned pointer should eventually be passed to
262  * close_write_file().
263  */
264 ostream *VirtualFileSimple::
266  return _mount->open_append_file(_local_filename);
267 }
268 
269 /**
270  * Closes a file opened by a previous call to open_write_file(). This really
271  * just deletes the ostream pointer, but it is recommended to use this
272  * interface instead of deleting it explicitly, to help work around compiler
273  * issues.
274  */
276 close_write_file(ostream *stream) {
277  _mount->close_write_file(stream);
278 }
279 
280 /**
281  * Opens the file for writing. Returns a newly allocated iostream on success
282  * (which you should eventually delete when you are done writing). Returns
283  * NULL on failure.
284  */
285 iostream *VirtualFileSimple::
286 open_read_write_file(bool truncate) {
287  return _mount->open_read_write_file(_local_filename, truncate);
288 }
289 
290 /**
291  * Works like open_read_write_file(), but the file is opened in append mode.
292  * Like open_read_write_file, the returned pointer should eventually be passed
293  * to close_read_write_file().
294  */
295 iostream *VirtualFileSimple::
297  return _mount->open_read_append_file(_local_filename);
298 }
299 
300 /**
301  * Closes a file opened by a previous call to open_read_write_file(). This
302  * really just deletes the iostream pointer, but it is recommended to use this
303  * interface instead of deleting it explicitly, to help work around compiler
304  * issues.
305  */
307 close_read_write_file(iostream *stream) {
308  _mount->close_read_write_file(stream);
309 }
310 
311 /**
312  * Returns the current size on disk (or wherever it is) of the already-open
313  * file. Pass in the stream that was returned by open_read_file(); some
314  * implementations may require this stream to determine the size.
315  */
316 std::streamsize VirtualFileSimple::
317 get_file_size(istream *stream) const {
318  return _mount->get_file_size(_local_filename, stream);
319 }
320 
321 /**
322  * Returns the current size on disk (or wherever it is) of the file before it
323  * has been opened.
324  */
325 std::streamsize VirtualFileSimple::
326 get_file_size() const {
327  return _mount->get_file_size(_local_filename);
328 }
329 
330 /**
331  * Returns a time_t value that represents the time the file was last modified,
332  * to within whatever precision the operating system records this information
333  * (on a Windows95 system, for instance, this may only be accurate to within 2
334  * seconds).
335  *
336  * If the timestamp cannot be determined, either because it is not supported
337  * by the operating system or because there is some error (such as file not
338  * found), returns 0.
339  */
340 time_t VirtualFileSimple::
341 get_timestamp() const {
342  return _mount->get_timestamp(_local_filename);
343 }
344 
345 /**
346  * Populates the SubfileInfo structure with the data representing where the
347  * file actually resides on disk, if this is knowable. Returns true if the
348  * file might reside on disk, and the info is populated, or false if it does
349  * not (or it is not known where the file resides), in which case the info is
350  * meaningless.
351  */
354  return _mount->get_system_info(_local_filename, info);
355 }
356 
357 /**
358  * See Filename::atomic_compare_and_exchange_contents().
359  */
362  const string &old_contents,
363  const string &new_contents) {
364  return _mount->atomic_compare_and_exchange_contents(_local_filename, orig_contents, old_contents, new_contents);
365 }
366 
367 /**
368  * See Filename::atomic_read_contents().
369  */
371 atomic_read_contents(string &contents) const {
372  return _mount->atomic_read_contents(_local_filename, contents);
373 }
374 
375 /**
376  * Fills up the indicated pvector with the contents of the file, if it is a
377  * regular file. Returns true on success, false otherwise.
378  */
380 read_file(vector_uchar &result, bool auto_unwrap) const {
381 
382  // Will we be automatically unwrapping a .pz file?
383  bool do_uncompress = (_implicit_pz_file ||
384  (auto_unwrap && (_local_filename.get_extension() == "pz" ||
385  _local_filename.get_extension() == "gz")));
386 
387  Filename local_filename(_local_filename);
388  if (do_uncompress) {
389  // .pz files are always binary, of course.
390  local_filename.set_binary();
391  }
392 
393  return _mount->read_file(local_filename, do_uncompress, result);
394 }
395 
396 /**
397  * Writes the indicated data to the file, if it is writable. Returns true on
398  * success, false otherwise.
399  */
401 write_file(const unsigned char *data, size_t data_size, bool auto_wrap) {
402  // Will we be automatically wrapping a .pz file?
403  bool do_compress = (_implicit_pz_file || (auto_wrap && _local_filename.get_extension() == "pz"));
404 
405  Filename local_filename(_local_filename);
406  if (do_compress) {
407  // .pz files are always binary, of course.
408  local_filename.set_binary();
409  }
410 
411  return _mount->write_file(local_filename, do_compress, data, data_size);
412 }
413 
414 /**
415  * Fills file_list up with the list of files that are within this directory,
416  * excluding those whose basenames are listed in mount_points. Returns true
417  * if successful, false if the file is not a directory or the directory cannot
418  * be read.
419  */
420 bool VirtualFileSimple::
421 scan_local_directory(VirtualFileList *file_list,
422  const ov_set<string> &mount_points) const {
423  vector_string names;
424  if (!_mount->scan_directory(names, _local_filename)) {
425  return false;
426  }
427 
428  // Now the scan above gave us a list of basenames. Turn these back into
429  // VirtualFile pointers.
430 
431  // Each of the files returned by the mount will be just a simple file within
432  // the same mount tree, unless it is shadowed by a mount point listed in
433  // mount_points.
434 
435  vector_string::const_iterator ni;
436  for (ni = names.begin(); ni != names.end(); ++ni) {
437  const string &basename = (*ni);
438  if (mount_points.find(basename) == mount_points.end()) {
439  Filename filename(_local_filename, basename);
440  VirtualFileSimple *file = new VirtualFileSimple(_mount, filename, false, 0);
441  file_list->add_file(file);
442  }
443  }
444 
445  return true;
446 }
virtual void close_write_file(std::ostream *stream)
Closes a file opened by a previous call to open_write_file().
virtual time_t get_timestamp() const
Returns a time_t value that represents the time the file was last modified, to within whatever precis...
VirtualFileSystem * get_file_system() const
Returns the file system this mount object is attached to.
virtual void close_read_file(std::istream *stream) const
Closes a file opened by a previous call to open_read_file().
virtual bool atomic_read_contents(const Filename &file, std::string &contents) const
See Filename::atomic_read_contents().
virtual bool is_regular_file() const
Returns true if this file represents a regular file (and read_file() may be called),...
virtual void close_read_file(std::istream *stream) const
Closes a file opened by a previous call to open_read_file().
virtual void close_read_write_file(std::iostream *stream)
Closes a file opened by a previous call to open_read_write_file().
A hierarchy of directories and files that appears to be one continuous file system,...
const Filename & get_mount_point() const
Returns the name of the directory within the virtual file system that this mount object is attached t...
virtual Filename get_filename() const
Returns the full pathname to this file within the virtual file system.
virtual bool is_directory() const
Returns true if this file represents a directory (and scan_directory() may be called),...
virtual bool atomic_read_contents(std::string &contents) const
See Filename::atomic_read_contents().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual std::ostream * open_write_file(bool auto_wrap, bool truncate)
Opens the file for writing.
void set_binary()
Indicates that the filename represents a binary file.
Definition: filename.I:414
virtual bool is_writable() const
Returns true if this file represents a writable regular file (and write_file() may be called),...
virtual bool atomic_compare_and_exchange_contents(std::string &orig_contents, const std::string &old_contents, const std::string &new_contents)
See Filename::atomic_compare_and_exchange_contents().
virtual bool delete_file(const Filename &file)
Attempts to delete the indicated file or directory within the mount.
virtual bool read_file(vector_uchar &result, bool auto_unwrap) const
Fills up the indicated pvector with the contents of the file, if it is a regular 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().
iterator_0 end()
Returns the iterator that marks the end of the ordered vector.
The abstract base class for a file or directory within the VirtualFileSystem.
Definition: virtualFile.h:35
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool write_file(const unsigned char *data, size_t data_size, bool auto_wrap)
Writes the indicated data to the file, if it is writable.
virtual std::ostream * open_append_file()
Works like open_write_file(), but the file is opened in append mode.
A specialization of ordered_vector that emulates a standard STL set: one copy of each element is allo...
virtual bool rename_file(VirtualFile *new_file)
Attempts to move or rename this file or directory.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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 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 is_writable(const Filename &file) const
Returns true if the named file or directory may be written to, false otherwise.
A list of VirtualFiles, as returned by VirtualFile::scan_directory().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
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 VirtualFileSystem * get_file_system() const
Returns the VirtualFileSystem this file is associated with.
virtual bool is_directory() const
Returns true if this file represents a directory (and scan_directory() may be called),...
Definition: virtualFile.cxx:41
std::string get_fullpath() const
Returns the entire filename: directory, basename, extension.
Definition: filename.I:338
virtual std::istream * open_read_file(bool auto_unwrap) const
Opens the file for reading.
virtual std::ostream * open_write_file(bool auto_wrap, bool truncate)
Opens the file for writing.
virtual bool write_file(const Filename &file, bool do_compress, const unsigned char *data, size_t data_size)
Writes the indicated data to the file, if it is a writable file.
virtual bool delete_file()
Attempts to delete this file or directory.
virtual std::ostream * open_append_file(const Filename &file)
Works like open_write_file(), but the file is opened in append mode.
virtual bool delete_file()
Attempts to delete this file or directory.
Definition: virtualFile.cxx:69
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 std::streamsize get_file_size() const
Returns the current size on disk (or wherever it is) of the file before it has been opened.
std::string get_extension() const
Returns the file extension.
Definition: filename.I:400
virtual bool copy_file(VirtualFile *new_file)
Attempts to copy the contents of this file to the indicated 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...
This class records a particular byte sub-range within an existing file on disk.
Definition: subfileInfo.h:26
virtual std::iostream * open_read_write_file(bool truncate)
Opens the file for writing.
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition: typedObject.I:28
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
A simple file or directory within the VirtualFileSystem: this maps to exactly one file on one mount p...
virtual bool read_file(const Filename &file, bool do_uncompress, vector_uchar &result) const
Fills up the indicated pvector with the contents of the file, if it is a regular file.
virtual std::ostream * open_write_file(const Filename &file, bool truncate)
Opens the file for writing.
virtual bool get_system_info(SubfileInfo &info)
Populates the SubfileInfo structure with the data representing where the file actually resides on dis...
virtual void close_write_file(std::ostream *stream)
Closes a file opened by a previous call to open_write_file().
void add_file(VirtualFile *file)
Adds a new file to the list.
virtual std::iostream * open_read_write_file(const Filename &file, bool truncate)
Opens the file for writing.
virtual std::iostream * open_read_append_file()
Works like open_read_write_file(), but the file is opened in append mode.
virtual bool has_file() const
Returns true if this file exists, false otherwise.