Panda3D
virtualFile.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 virtualFile.cxx
10  * @author drose
11  * @date 2002-08-03
12  */
13 
14 #include "virtualFile.h"
15 #include "virtualFileSystem.h"
16 #include "virtualFileList.h"
17 #include "config_express.h"
18 #include "pvector.h"
19 #include <iterator>
20 
21 using std::iostream;
22 using std::istream;
23 using std::ostream;
24 using std::string;
25 
26 TypeHandle VirtualFile::_type_handle;
27 
28 /**
29  * Returns true if this file exists, false otherwise.
30  */
31 bool VirtualFile::
32 has_file() const {
33  return false;
34 }
35 
36 /**
37  * Returns true if this file represents a directory (and scan_directory() may
38  * be called), false otherwise.
39  */
40 bool VirtualFile::
41 is_directory() const {
42  return false;
43 }
44 
45 /**
46  * Returns true if this file represents a regular file (and read_file() may be
47  * called), false otherwise.
48  */
49 bool VirtualFile::
50 is_regular_file() const {
51  return false;
52 }
53 
54 /**
55  * Returns true if this file may be written to, which implies write_file() may
56  * be called (unless it is a directory instead of a regular file).
57  */
58 bool VirtualFile::
59 is_writable() const {
60  return false;
61 }
62 
63 /**
64  * Attempts to delete this file or directory. This can remove a single file
65  * or an empty directory. It will not remove a nonempty directory. Returns
66  * true on success, false on failure.
67  */
68 bool VirtualFile::
70  return false;
71 }
72 
73 /**
74  * Attempts to move or rename this file or directory. If the original file is
75  * an ordinary file, it will quietly replace any already-existing file in the
76  * new filename (but not a directory). If the original file is a directory,
77  * the new filename must not already exist.
78  *
79  * If the file is a directory, the new filename must be within the same mount
80  * point. If the file is an ordinary file, the new filename may be anywhere;
81  * but if it is not within the same mount point then the rename operation is
82  * automatically performed as a two-step copy-and-delete operation.
83  */
84 bool VirtualFile::
86  return false;
87 }
88 
89 /**
90  * Attempts to copy the contents of this file to the indicated file. Returns
91  * true on success, false on failure.
92  */
93 bool VirtualFile::
94 copy_file(VirtualFile *new_file) {
95  return false;
96 }
97 
98 /**
99  * If the file represents a directory (that is, is_directory() returns true),
100  * this returns the list of files within the directory at the current time.
101  * Returns NULL if the file is not a directory or if the directory cannot be
102  * read.
103  */
105 scan_directory() const {
106  // First, we have to make sure there aren't any mount points attached under
107  // this directory. These will override any local filenames.
108  VirtualFileSystem *file_system = get_file_system();
109  Filename this_filename = get_filename();
110  vector_string mount_points_flat;
111  file_system->scan_mount_points(mount_points_flat, this_filename);
112 
113  // Copy the set of nested mount points to a sorted list so we can search it
114  // quickly.
115  ov_set<string> mount_points;
116  std::copy(mount_points_flat.begin(), mount_points_flat.end(),
117  std::back_inserter(mount_points));
118  mount_points.sort();
119 
120 
121  PT(VirtualFileList) file_list = new VirtualFileList;
122 
123  // Each of those mount points maps to a directory root or something from the
124  // file system.
125  ov_set<string>::const_iterator mi;
126  for (mi = mount_points.begin(); mi != mount_points.end(); ++mi) {
127  const string &basename = (*mi);
128  Filename filename(this_filename, basename);
129  PT(VirtualFile) file = file_system->get_file(filename);
130  file_list->add_file(file);
131  }
132 
133  // Now, get the actual local files in this directory.
134  vector_string names;
135  if (!scan_local_directory(file_list, mount_points)) {
136  // Not a directory, or unable to read directory.
137  if (file_list->get_num_files() == 0) {
138  return nullptr;
139  }
140 
141  // We couldn't read the physical directory, but we do have some mounted
142  // files to return.
143  return file_list;
144  }
145 
146  return file_list;
147 }
148 
149 /**
150  *
151  */
152 void VirtualFile::
153 output(ostream &out) const {
154  out << get_filename();
155 }
156 
157 /**
158  * If the file represents a directory, lists its contents.
159  */
160 void VirtualFile::
161 ls(ostream &out) const {
162  CPT(VirtualFileList) contents = scan_directory();
163  if (contents == nullptr) {
164  if (!is_directory()) {
165  out << get_filename() << "\n";
166  } else {
167  out << get_filename() << " cannot be read.\n";
168  }
169  return;
170  }
171 
172  int num_files = contents->get_num_files();
173  for (int i = 0; i < num_files; i++) {
174  VirtualFile *file = contents->get_file(i);
175  out << file->get_filename().get_basename() << "\n";
176  }
177 }
178 
179 /**
180  * If the file represents a directory, recursively lists its contents and
181  * those of all subdirectories.
182  */
183 void VirtualFile::
184 ls_all(ostream &out) const {
185  if (!is_directory()) {
186  out << get_filename() << " is not a directory.\n";
187  } else {
188  r_ls_all(out, get_filename());
189  }
190 }
191 
192 /**
193  * Opens the file for reading. Returns a newly allocated istream on success
194  * (which you should eventually delete when you are done reading). Returns
195  * NULL on failure.
196  */
197 istream *VirtualFile::
198 open_read_file(bool auto_unwrap) const {
199  return nullptr;
200 }
201 
202 /**
203  * Closes a file opened by a previous call to open_read_file(). This really
204  * just deletes the istream pointer, but it is recommended to use this
205  * interface instead of deleting it explicitly, to help work around compiler
206  * issues.
207  */
208 void VirtualFile::
209 close_read_file(istream *stream) const {
210  nassertv(false);
211 }
212 
213 /**
214  * Call this method after a reading the istream returned by open_read_file()
215  * to completion. If it returns true, the file was read completely and
216  * without error; if it returns false, there may have been some errors or a
217  * truncated file read. This is particularly likely if the stream is a
218  * VirtualFileHTTP.
219  */
220 bool VirtualFile::
222  return true;
223 }
224 
225 /**
226  * Opens the file for writing. Returns a newly allocated ostream on success
227  * (which you should eventually delete when you are done writing). Returns
228  * NULL on failure.
229  */
230 ostream *VirtualFile::
231 open_write_file(bool auto_wrap, bool truncate) {
232  return nullptr;
233 }
234 
235 /**
236  * Works like open_write_file(), but the file is opened in append mode. Like
237  * open_write_file, the returned pointer should eventually be passed to
238  * close_write_file().
239  */
240 ostream *VirtualFile::
242  return nullptr;
243 }
244 
245 /**
246  * Closes a file opened by a previous call to open_write_file(). This really
247  * just deletes the ostream pointer, but it is recommended to use this
248  * interface instead of deleting it explicitly, to help work around compiler
249  * issues.
250  */
251 void VirtualFile::
252 close_write_file(ostream *stream) {
253  nassertv(false);
254 }
255 
256 /**
257  * Opens the file for writing. Returns a newly allocated iostream on success
258  * (which you should eventually delete when you are done writing). Returns
259  * NULL on failure.
260  */
261 iostream *VirtualFile::
262 open_read_write_file(bool truncate) {
263  return nullptr;
264 }
265 
266 /**
267  * Works like open_read_write_file(), but the file is opened in append mode.
268  * Like open_read_write_file, the returned pointer should eventually be passed
269  * to close_read_write_file().
270  */
271 iostream *VirtualFile::
273  return nullptr;
274 }
275 
276 /**
277  * Closes a file opened by a previous call to open_read_write_file(). This
278  * really just deletes the iostream pointer, but it is recommended to use this
279  * interface instead of deleting it explicitly, to help work around compiler
280  * issues.
281  */
282 void VirtualFile::
283 close_read_write_file(iostream *stream) {
284  nassertv(false);
285 }
286 
287 /**
288  * Returns the current size on disk (or wherever it is) of the already-open
289  * file. Pass in the stream that was returned by open_read_file(); some
290  * implementations may require this stream to determine the size.
291  */
292 std::streamsize VirtualFile::
293 get_file_size(istream *stream) const {
294  return get_file_size();
295 }
296 
297 /**
298  * Returns the current size on disk (or wherever it is) of the file before it
299  * has been opened.
300  */
301 std::streamsize VirtualFile::
302 get_file_size() const {
303  return 0;
304 }
305 
306 /**
307  * Returns a time_t value that represents the time the file was last modified,
308  * to within whatever precision the operating system records this information
309  * (on a Windows95 system, for instance, this may only be accurate to within 2
310  * seconds).
311  *
312  * If the timestamp cannot be determined, either because it is not supported
313  * by the operating system or because there is some error (such as file not
314  * found), returns 0.
315  */
316 time_t VirtualFile::
317 get_timestamp() const {
318  return 0;
319 }
320 
321 /**
322  * Populates the SubfileInfo structure with the data representing where the
323  * file actually resides on disk, if this is knowable. Returns true if the
324  * file might reside on disk, and the info is populated, or false if it does
325  * not (or it is not known where the file resides), in which case the info is
326  * meaningless.
327  */
328 bool VirtualFile::
330  return false;
331 }
332 
333 /**
334  * See Filename::atomic_compare_and_exchange_contents().
335  */
336 bool VirtualFile::
338  const string &old_contents,
339  const string &new_contents) {
340  return false;
341 }
342 
343 /**
344  * See Filename::atomic_read_contents().
345  */
346 bool VirtualFile::
347 atomic_read_contents(string &contents) const {
348  return false;
349 }
350 
351 /**
352  * Fills up the indicated string with the contents of the file, if it is a
353  * regular file. Returns true on success, false otherwise.
354  */
355 bool VirtualFile::
356 read_file(string &result, bool auto_unwrap) const {
357  result = string();
358 
359  vector_uchar pv;
360  if (!read_file(pv, auto_unwrap)) {
361  return false;
362  }
363 
364  if (!pv.empty()) {
365  result.append((const char *)&pv[0], pv.size());
366  }
367 
368  return true;
369 }
370 
371 /**
372  * Fills up the indicated pvector with the contents of the file, if it is a
373  * regular file. Returns true on success, false otherwise.
374  */
375 bool VirtualFile::
376 read_file(vector_uchar &result, bool auto_unwrap) const {
377  return false;
378 }
379 
380 /**
381  * Writes the indicated data to the file, if it is writable. Returns true on
382  * success, false otherwise.
383  */
384 bool VirtualFile::
385 write_file(const unsigned char *data, size_t data_size, bool auto_wrap) {
386  return false;
387 }
388 
389 /**
390  * Fills up the indicated pvector with the contents of the just-opened file.
391  * Returns true on success, false otherwise. If the pvector was not empty on
392  * entry, the data read from the file will be appended onto it.
393  */
394 bool VirtualFile::
395 simple_read_file(istream *in, vector_uchar &result) {
396  static const size_t buffer_size = 4096;
397  char buffer[buffer_size];
398 
399  in->read(buffer, buffer_size);
400  size_t count = in->gcount();
401  while (count != 0) {
402  thread_consider_yield();
403  result.insert(result.end(), buffer, buffer + count);
404  in->read(buffer, buffer_size);
405  count = in->gcount();
406  }
407 
408  return (!in->fail() || in->eof());
409 }
410 
411 /**
412  * As in simple_read_file() with two parameters, above, but only reads up to
413  * max_bytes bytes from the file.
414  */
415 bool VirtualFile::
416 simple_read_file(istream *in, vector_uchar &result, size_t max_bytes) {
417  static const size_t buffer_size = 4096;
418  char buffer[buffer_size];
419 
420  in->read(buffer, std::min(buffer_size, max_bytes));
421  size_t count = in->gcount();
422  while (count != 0) {
423  thread_consider_yield();
424  nassertr(count <= max_bytes, false);
425  result.insert(result.end(), buffer, buffer + count);
426  max_bytes -= count;
427  in->read(buffer, std::min(buffer_size, max_bytes));
428  count = in->gcount();
429  }
430 
431  return (!in->fail() || in->eof());
432 }
433 
434 /**
435  * Fills file_list up with the list of files that are within this directory,
436  * excluding those whose basenames are listed in mount_points. Returns true
437  * if successful, false if the file is not a directory or the directory cannot
438  * be read.
439  */
440 bool VirtualFile::
441 scan_local_directory(VirtualFileList *, const ov_set<string> &) const {
442  return false;
443 }
444 
445 /**
446  * The recursive implementation of ls_all().
447  */
448 void VirtualFile::
449 r_ls_all(ostream &out, const Filename &root) const {
450  CPT(VirtualFileList) contents = scan_directory();
451  if (contents == nullptr) {
452  return;
453  }
454 
455  int num_files = contents->get_num_files();
456  for (int i = 0; i < num_files; i++) {
457  VirtualFile *file = contents->get_file(i);
458  Filename filename = file->get_filename();
459  filename.make_relative_to(root);
460  out << filename << "\n";
461  if (file->is_directory()) {
462  file->r_ls_all(out, root);
463  }
464  }
465 }
bool write_file(const std::string &data, bool auto_wrap)
Writes the entire contents of the file as a string, if it is writable.
Definition: virtualFile.I:45
virtual std::ostream * open_append_file()
Works like open_write_file(), but the file is opened in append mode.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A hierarchy of directories and files that appears to be one continuous file system,...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual std::ostream * open_write_file(bool auto_wrap, bool truncate)
Opens the file for writing.
iterator_0 begin()
Returns the iterator that marks the first element in the ordered vector.
virtual bool is_writable() const
Returns true if this file may be written to, which implies write_file() may be called (unless it is a...
Definition: virtualFile.cxx:59
virtual bool copy_file(VirtualFile *new_file)
Attempts to copy the contents of this file to the indicated file.
Definition: virtualFile.cxx:94
virtual time_t get_timestamp() const
Returns a time_t value that represents the time the file was last modified, to within whatever precis...
PointerTo< VirtualFileList > scan_directory() const
If the file represents a directory (that is, is_directory() returns true), this returns the list of f...
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
void ls_all(std::ostream &out=std::cout) const
If the file represents a directory, recursively lists its contents and those of all subdirectories.
A specialization of ordered_vector that emulates a standard STL set: one copy of each element is allo...
virtual bool get_system_info(SubfileInfo &info)
Populates the SubfileInfo structure with the data representing where the file actually resides on dis...
virtual std::iostream * open_read_write_file(bool truncate)
Opens the file for writing.
A list of VirtualFiles, as returned by VirtualFile::scan_directory().
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(std::string &contents) const
See Filename::atomic_read_contents().
virtual void close_read_write_file(std::iostream *stream)
Closes a file opened by a previous call to open_read_write_file().
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
virtual bool is_directory() const
Returns true if this file represents a directory (and scan_directory() may be called),...
Definition: virtualFile.cxx:41
void sort()
Maps to sort_unique().
virtual std::iostream * open_read_append_file()
Works like open_read_write_file(), but the file is opened in append mode.
void scan_mount_points(vector_string &names, const Filename &path) const
Adds to names a list of all the mount points in use that are one directory below path,...
virtual bool delete_file()
Attempts to delete this file or directory.
Definition: virtualFile.cxx:69
virtual bool was_read_successful() const
Call this method after a reading the istream returned by open_read_file() to completion.
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
std::string read_file(bool auto_unwrap) const
Returns the entire contents of the file as a string.
Definition: virtualFile.I:35
virtual bool has_file() const
Returns true if this file exists, false otherwise.
Definition: virtualFile.cxx:32
bool make_relative_to(Filename directory, bool allow_backups=true)
Adjusts this filename, which must be a fully-specified pathname beginning with a slash,...
Definition: filename.cxx:1640
std::string get_basename() const
Returns the basename part of the filename.
Definition: filename.I:367
virtual std::istream * open_read_file(bool auto_unwrap) const
Opens the file for reading.
void ls(std::ostream &out=std::cout) const
If the file represents a directory, lists its contents.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtual bool rename_file(VirtualFile *new_file)
Attempts to move or rename this file or directory.
Definition: virtualFile.cxx:85
This class records a particular byte sub-range within an existing file on disk.
Definition: subfileInfo.h:26
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.
static bool simple_read_file(std::istream *stream, vector_uchar &result)
Fills up the indicated pvector with the contents of the just-opened file.
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
virtual bool is_regular_file() const
Returns true if this file represents a regular file (and read_file() may be called),...
Definition: virtualFile.cxx:50
virtual void close_write_file(std::ostream *stream)
Closes a file opened by a previous call to open_write_file().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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().