Browse Source

more robust vfs write operations

David Rose 14 years ago
parent
commit
84fdd2ea9e

+ 49 - 10
panda/src/express/virtualFile.cxx

@@ -219,7 +219,20 @@ was_read_successful() const {
 //               Returns NULL on failure.
 ////////////////////////////////////////////////////////////////////
 ostream *VirtualFile::
-open_write_file(bool auto_wrap) {
+open_write_file(bool auto_wrap, bool truncate) {
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFile::open_append_file
+//       Access: Published, Virtual
+//  Description: Works like open_write_file(), but the file is opened
+//               in append mode.  Like open_write_file, the returned
+//               pointer should eventually be passed to
+//               close_write_file().
+////////////////////////////////////////////////////////////////////
+ostream *VirtualFile::
+open_append_file() {
   return NULL;
 }
 
@@ -238,17 +251,43 @@ close_write_file(ostream *stream) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: VirtualFile::was_write_successful
+//     Function: VirtualFile::open_read_write_file
 //       Access: Published, Virtual
-//  Description: Call this method after a writing the ostream returned
-//               by open_write_file() to completion.  If it returns
-//               true, the file was written completely and without
-//               error; if it returns false, there may have been some
-//               errors or a truncated file write.
+//  Description: Opens the file for writing.  Returns a newly
+//               allocated iostream on success (which you should
+//               eventually delete when you are done writing).
+//               Returns NULL on failure.
 ////////////////////////////////////////////////////////////////////
-bool VirtualFile::
-was_write_successful() const {
-  return true;
+iostream *VirtualFile::
+open_read_write_file(bool truncate) {
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFile::open_read_append_file
+//       Access: Published, Virtual
+//  Description: Works like open_read_write_file(), but the file is opened
+//               in append mode.  Like open_read_write_file, the returned
+//               pointer should eventually be passed to
+//               close_read_write_file().
+////////////////////////////////////////////////////////////////////
+iostream *VirtualFile::
+open_read_append_file() {
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFile::close_read_write_file
+//       Access: Published
+//  Description: Closes a file opened by a previous call to
+//               open_read_write_file().  This really just deletes the
+//               iostream pointer, but it is recommended to use this
+//               interface instead of deleting it explicitly, to help
+//               work around compiler issues.
+////////////////////////////////////////////////////////////////////
+void VirtualFile::
+close_read_write_file(iostream *stream) {
+  nassertv(false);
 }
 
 ////////////////////////////////////////////////////////////////////

+ 6 - 2
panda/src/express/virtualFile.h

@@ -60,9 +60,13 @@ PUBLISHED:
   virtual bool was_read_successful() const;
 
   BLOCKING INLINE bool write_file(const string &data, bool auto_wrap);
-  BLOCKING virtual ostream *open_write_file(bool auto_wrap);
+  BLOCKING virtual ostream *open_write_file(bool auto_wrap, bool truncate);
+  BLOCKING virtual ostream *open_append_file();
   BLOCKING virtual void close_write_file(ostream *stream);
-  virtual bool was_write_successful() const;
+
+  BLOCKING virtual iostream *open_read_write_file(bool truncate);
+  BLOCKING virtual iostream *open_read_append_file();
+  BLOCKING virtual void close_read_write_file(iostream *stream);
 
   BLOCKING virtual off_t get_file_size(istream *stream) const;
   BLOCKING virtual off_t get_file_size() const;

+ 57 - 4
panda/src/express/virtualFileMount.cxx

@@ -143,7 +143,7 @@ read_file(const Filename &file, bool do_uncompress,
 bool VirtualFileMount::
 write_file(const Filename &file, bool do_compress,
            const unsigned char *data, size_t data_size) {
-  ostream *out = open_write_file(file, do_compress);
+  ostream *out = open_write_file(file, do_compress, true);
   if (out == (ostream *)NULL) {
     express_cat.info()
       << "Unable to write " << file << "\n";
@@ -210,7 +210,7 @@ close_read_file(istream *stream) const {
 //               Returns NULL on failure.
 ////////////////////////////////////////////////////////////////////
 ostream *VirtualFileMount::
-open_write_file(const Filename &file) {
+open_write_file(const Filename &file, bool truncate) {
   return NULL;
 }
 
@@ -226,8 +226,8 @@ open_write_file(const Filename &file) {
 //               compressed on-the-fly using zlib.
 ////////////////////////////////////////////////////////////////////
 ostream *VirtualFileMount::
-open_write_file(const Filename &file, bool do_compress) {
-  ostream *result = open_write_file(file);
+open_write_file(const Filename &file, bool do_compress, bool truncate) {
+  ostream *result = open_write_file(file, truncate);
 
 #ifdef HAVE_ZLIB
   if (result != (ostream *)NULL && do_compress) {
@@ -240,6 +240,19 @@ open_write_file(const Filename &file, bool do_compress) {
   return result;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileMount::open_append_file
+//       Access: Published, Virtual
+//  Description: Works like open_write_file(), but the file is opened
+//               in append mode.  Like open_write_file, the returned
+//               pointer should eventually be passed to
+//               close_write_file().
+////////////////////////////////////////////////////////////////////
+ostream *VirtualFileMount::
+open_append_file(const Filename &file) {
+  return NULL;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: VirtualFileMount::close_write_file
 //       Access: Public, Virtual
@@ -254,6 +267,46 @@ close_write_file(ostream *stream) {
   VirtualFileSystem::close_write_file(stream);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileMount::open_read_write_file
+//       Access: Published, Virtual
+//  Description: Opens the file for writing.  Returns a newly
+//               allocated iostream on success (which you should
+//               eventually delete when you are done writing).
+//               Returns NULL on failure.
+////////////////////////////////////////////////////////////////////
+iostream *VirtualFileMount::
+open_read_write_file(const Filename &file, bool truncate) {
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileMount::open_read_append_file
+//       Access: Published, Virtual
+//  Description: Works like open_read_write_file(), but the file is opened
+//               in append mode.  Like open_read_write_file, the returned
+//               pointer should eventually be passed to
+//               close_read_write_file().
+////////////////////////////////////////////////////////////////////
+iostream *VirtualFileMount::
+open_read_append_file(const Filename &file) {
+  return NULL;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileMount::close_read_write_file
+//       Access: Public, Virtual
+//  Description: Closes a file opened by a previous call to
+//               open_read_write_file().  This really just deletes the
+//               iostream pointer, but it is recommended to use this
+//               interface instead of deleting it explicitly, to help
+//               work around compiler issues.
+////////////////////////////////////////////////////////////////////
+void VirtualFileMount::
+close_read_write_file(iostream *stream) {
+  VirtualFileSystem::close_read_write_file(stream);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: VirtualFileMount::get_system_info
 //       Access: Public, Virtual

+ 7 - 2
panda/src/express/virtualFileMount.h

@@ -61,10 +61,15 @@ public:
   istream *open_read_file(const Filename &file, bool do_uncompress) const;
   virtual void close_read_file(istream *stream) const;
 
-  virtual ostream *open_write_file(const Filename &file);
-  ostream *open_write_file(const Filename &file, bool do_compress);
+  virtual ostream *open_write_file(const Filename &file, bool truncate);
+  ostream *open_write_file(const Filename &file, bool do_compress, bool truncate);
+  virtual ostream *open_append_file(const Filename &file);
   virtual void close_write_file(ostream *stream);
 
+  virtual iostream *open_read_write_file(const Filename &file, bool truncate);
+  virtual iostream *open_read_append_file(const Filename &file);
+  virtual void close_read_write_file(iostream *stream);
+
   virtual off_t get_file_size(const Filename &file, istream *stream) const=0;
   virtual off_t get_file_size(const Filename &file) const=0;
   virtual time_t get_timestamp(const Filename &file) const=0;

+ 104 - 2
panda/src/express/virtualFileMountSystem.cxx

@@ -177,7 +177,7 @@ open_read_file(const Filename &file) const {
 //               Returns NULL on failure.
 ////////////////////////////////////////////////////////////////////
 ostream *VirtualFileMountSystem::
-open_write_file(const Filename &file) {
+open_write_file(const Filename &file, bool truncate) {
 #ifdef WIN32
   // First ensure that the file exists to validate its case.
   if (VirtualFileSystem::get_global_ptr()->vfs_case_sensitive) {
@@ -193,7 +193,109 @@ open_write_file(const Filename &file) {
     pathname.set_binary();
   }
   pofstream *stream = new pofstream;
-  if (!pathname.open_write(*stream)) {
+  if (!pathname.open_write(*stream, truncate)) {
+    // Couldn't open the file for some reason.
+    close_write_file(stream);
+    return NULL;
+  }
+
+  return stream;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileMountSystem::open_append_file
+//       Access: Published
+//  Description: Works like open_write_file(), but the file is opened
+//               in append mode.  Like open_write_file, the returned
+//               pointer should eventually be passed to
+//               close_write_file().
+////////////////////////////////////////////////////////////////////
+ostream *VirtualFileMountSystem::
+open_append_file(const Filename &file) {
+#ifdef WIN32
+  // First ensure that the file exists to validate its case.
+  if (VirtualFileSystem::get_global_ptr()->vfs_case_sensitive) {
+    if (!has_file(file)) {
+      return NULL;
+    }
+  }
+#endif  // WIN32
+  Filename pathname(_physical_filename, file);
+  if (file.is_text()) {
+    pathname.set_text();
+  } else {
+    pathname.set_binary();
+  }
+  pofstream *stream = new pofstream;
+  if (!pathname.open_append(*stream)) {
+    // Couldn't open the file for some reason.
+    close_write_file(stream);
+    return NULL;
+  }
+
+  return stream;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileMountSystem::open_read_write_file
+//       Access: Published, Virtual
+//  Description: Opens the file for writing.  Returns a newly
+//               allocated iostream on success (which you should
+//               eventually delete when you are done writing).
+//               Returns NULL on failure.
+////////////////////////////////////////////////////////////////////
+iostream *VirtualFileMountSystem::
+open_read_write_file(const Filename &file, bool truncate) {
+#ifdef WIN32
+  // First ensure that the file exists to validate its case.
+  if (VirtualFileSystem::get_global_ptr()->vfs_case_sensitive) {
+    if (!has_file(file)) {
+      return NULL;
+    }
+  }
+#endif  // WIN32
+  Filename pathname(_physical_filename, file);
+  if (file.is_text()) {
+    pathname.set_text();
+  } else {
+    pathname.set_binary();
+  }
+  pfstream *stream = new pfstream;
+  if (!pathname.open_read_write(*stream, truncate)) {
+    // Couldn't open the file for some reason.
+    close_write_file(stream);
+    return NULL;
+  }
+
+  return stream;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileMountSystem::open_read_append_file
+//       Access: Published, Virtual
+//  Description: Works like open_read_write_file(), but the file is opened
+//               in append mode.  Like open_read_write_file, the returned
+//               pointer should eventually be passed to
+//               close_read_write_file().
+////////////////////////////////////////////////////////////////////
+iostream *VirtualFileMountSystem::
+open_read_append_file(const Filename &file) {
+#ifdef WIN32
+  // First ensure that the file exists to validate its case.
+  if (VirtualFileSystem::get_global_ptr()->vfs_case_sensitive) {
+    if (!has_file(file)) {
+      return NULL;
+    }
+  }
+#endif  // WIN32
+  Filename pathname(_physical_filename, file);
+  if (file.is_text()) {
+    pathname.set_text();
+  } else {
+    pathname.set_binary();
+  }
+  pfstream *stream = new pfstream;
+  if (!pathname.open_read_append(*stream)) {
     // Couldn't open the file for some reason.
     close_write_file(stream);
     return NULL;

+ 5 - 1
panda/src/express/virtualFileMountSystem.h

@@ -39,7 +39,11 @@ public:
   virtual bool is_writable(const Filename &file) const;
 
   virtual istream *open_read_file(const Filename &file) const;
-  virtual ostream *open_write_file(const Filename &file);
+  virtual ostream *open_write_file(const Filename &file, bool truncate);
+  virtual ostream *open_append_file(const Filename &file);
+  virtual iostream *open_read_write_file(const Filename &file, bool truncate);
+  virtual iostream *open_read_append_file(const Filename &file);
+
   virtual off_t get_file_size(const Filename &file, istream *stream) const;
   virtual off_t get_file_size(const Filename &file) const;
   virtual time_t get_timestamp(const Filename &file) const;

+ 59 - 4
panda/src/express/virtualFileSimple.cxx

@@ -150,11 +150,13 @@ close_read_file(istream *stream) const {
 //               eventually delete when you are done writing).
 //               Returns NULL on failure.
 //
-//               If auto_wrap is true, an explicitly-named .pz file
-//               is automatically compressed.
+//               If auto_wrap is true, an explicitly-named .pz file is
+//               automatically compressed while writing.  If truncate
+//               is true, the file is truncated to zero length before
+//               writing.
 ////////////////////////////////////////////////////////////////////
 ostream *VirtualFileSimple::
-open_write_file(bool auto_wrap) const {
+open_write_file(bool auto_wrap, bool truncate) {
   // Will we be automatically wrapping a .pz file?
   bool do_compress = (_implicit_pz_file || (auto_wrap && _local_filename.get_extension() == "pz"));
 
@@ -164,7 +166,20 @@ open_write_file(bool auto_wrap) const {
     local_filename.set_binary();
   }
 
-  return _mount->open_write_file(local_filename, do_compress);
+  return _mount->open_write_file(local_filename, do_compress, truncate);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileSimple::open_append_file
+//       Access: Published, Virtual
+//  Description: Works like open_write_file(), but the file is opened
+//               in append mode.  Like open_write_file, the returned
+//               pointer should eventually be passed to
+//               close_write_file().
+////////////////////////////////////////////////////////////////////
+ostream *VirtualFileSimple::
+open_append_file() {
+  return _mount->open_append_file(_local_filename);
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -181,6 +196,46 @@ close_write_file(ostream *stream) const {
   _mount->close_write_file(stream);
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileSimple::open_read_write_file
+//       Access: Published, Virtual
+//  Description: Opens the file for writing.  Returns a newly
+//               allocated iostream on success (which you should
+//               eventually delete when you are done writing).
+//               Returns NULL on failure.
+////////////////////////////////////////////////////////////////////
+iostream *VirtualFileSimple::
+open_read_write_file(bool truncate) {
+  return _mount->open_read_write_file(_local_filename, truncate);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileSimple::open_read_append_file
+//       Access: Published, Virtual
+//  Description: Works like open_read_write_file(), but the file is opened
+//               in append mode.  Like open_read_write_file, the returned
+//               pointer should eventually be passed to
+//               close_read_write_file().
+////////////////////////////////////////////////////////////////////
+iostream *VirtualFileSimple::
+open_read_append_file() {
+  return _mount->open_read_append_file(_local_filename);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileSimple::close_read_write_file
+//       Access: Published
+//  Description: Closes a file opened by a previous call to
+//               open_read_write_file().  This really just deletes the
+//               iostream pointer, but it is recommended to use this
+//               interface instead of deleting it explicitly, to help
+//               work around compiler issues.
+////////////////////////////////////////////////////////////////////
+void VirtualFileSimple::
+close_read_write_file(iostream *stream) {
+  _mount->close_read_write_file(stream);
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: VirtualFileSimple::get_file_size
 //       Access: Published, Virtual

+ 6 - 1
panda/src/express/virtualFileSimple.h

@@ -46,8 +46,13 @@ PUBLISHED:
 
   virtual istream *open_read_file(bool auto_unwrap) const;
   virtual void close_read_file(istream *stream) const;
-  virtual ostream *open_write_file(bool auto_wrap) const;
+  virtual ostream *open_write_file(bool auto_wrap, bool truncate);
+  virtual ostream *open_append_file();
   virtual void close_write_file(ostream *stream) const;
+  virtual iostream *open_read_write_file(bool truncate);
+  virtual iostream *open_read_append_file();
+  virtual void close_read_write_file(iostream *stream);
+
   virtual off_t get_file_size(istream *stream) const;
   virtual off_t get_file_size() const;
   virtual time_t get_timestamp() const;

+ 92 - 4
panda/src/express/virtualFileSystem.cxx

@@ -911,16 +911,40 @@ __py__write_file(const Filename &filename, PyObject *data, bool auto_wrap) {
 //               ostream if the file exists and can be written, or
 //               NULL otherwise.  Does not return an invalid ostream.
 //
-//               If auto_wrap is true, an explicitly-named .pz file
-//               is automatically compressed while writing.
+//               If auto_wrap is true, an explicitly-named .pz file is
+//               automatically compressed while writing.  If truncate
+//               is true, the file is truncated to zero length before
+//               writing.
 ////////////////////////////////////////////////////////////////////
 ostream *VirtualFileSystem::
-open_write_file(const Filename &filename, bool auto_wrap) {
+open_write_file(const Filename &filename, bool auto_wrap, bool truncate) {
   PT(VirtualFile) file = create_file(filename);
   if (file == (VirtualFile *)NULL) {
     return NULL;
   }
-  ostream *str = file->open_write_file(auto_wrap);
+  ostream *str = file->open_write_file(auto_wrap, truncate);
+  if (str != (ostream *)NULL && str->fail()) {
+    close_write_file(str);
+    str = (ostream *)NULL;
+  }
+  return str;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileSystem::open_append_file
+//       Access: Published
+//  Description: Works like open_write_file(), but the file is opened
+//               in append mode.  Like open_write_file, the returned
+//               pointer should eventually be passed to
+//               close_write_file().
+////////////////////////////////////////////////////////////////////
+ostream *VirtualFileSystem::
+open_append_file(const Filename &filename) {
+  PT(VirtualFile) file = create_file(filename);
+  if (file == (VirtualFile *)NULL) {
+    return NULL;
+  }
+  ostream *str = file->open_append_file();
   if (str != (ostream *)NULL && str->fail()) {
     close_write_file(str);
     str = (ostream *)NULL;
@@ -949,6 +973,70 @@ close_write_file(ostream *stream) {
   }
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileSystem::open_read_write_file
+//       Access: Published
+//  Description: Convenience function; returns a newly allocated
+//               iostream if the file exists and can be written, or
+//               NULL otherwise.  Does not return an invalid iostream.
+////////////////////////////////////////////////////////////////////
+iostream *VirtualFileSystem::
+open_read_write_file(const Filename &filename, bool truncate) {
+  PT(VirtualFile) file = create_file(filename);
+  if (file == (VirtualFile *)NULL) {
+    return NULL;
+  }
+  iostream *str = file->open_read_write_file(truncate);
+  if (str != (iostream *)NULL && str->fail()) {
+    close_read_write_file(str);
+    str = (iostream *)NULL;
+  }
+  return str;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileSystem::open_read_append_file
+//       Access: Published
+//  Description: Works like open_read_write_file(), but the file is opened
+//               in append mode.  Like open_read_write_file, the returned
+//               pointer should eventually be passed to
+//               close_read_write_file().
+////////////////////////////////////////////////////////////////////
+iostream *VirtualFileSystem::
+open_read_append_file(const Filename &filename) {
+  PT(VirtualFile) file = create_file(filename);
+  if (file == (VirtualFile *)NULL) {
+    return NULL;
+  }
+  iostream *str = file->open_read_append_file();
+  if (str != (iostream *)NULL && str->fail()) {
+    close_read_write_file(str);
+    str = (iostream *)NULL;
+  }
+  return str;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: VirtualFileSystem::close_read_write_file
+//       Access: Published, Static
+//  Description: Closes a file opened by a previous call to
+//               open_read_write_file().  This really just deletes the
+//               iostream pointer, but it is recommended to use this
+//               interface instead of deleting it explicitly, to help
+//               work around compiler issues.
+////////////////////////////////////////////////////////////////////
+void VirtualFileSystem::
+close_read_write_file(iostream *stream) {
+  if (stream != (iostream *)NULL) {
+#if (!defined(WIN32_VC) && !defined(WIN64_VC)) && !defined(USE_MEMORY_NOWRAPPERS) && defined(REDEFINE_GLOBAL_OPERATOR_NEW)
+    stream->~iostream();
+    (*global_operator_delete)(stream);
+#else
+    delete stream;
+#endif
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: VirtualFileSystem::scan_mount_points
 //       Access: Public

+ 6 - 1
panda/src/express/virtualFileSystem.h

@@ -106,9 +106,14 @@ PUBLISHED:
   BLOCKING PyObject *__py__write_file(const Filename &filename, PyObject *data, bool auto_wrap);
 #endif  // HAVE_PYTHON
   BLOCKING INLINE bool write_file(const Filename &filename, const string &data, bool auto_wrap);
-  BLOCKING ostream *open_write_file(const Filename &filename, bool auto_wrap);
+  BLOCKING ostream *open_write_file(const Filename &filename, bool auto_wrap, bool truncate);
+  BLOCKING ostream *open_append_file(const Filename &filename);
   BLOCKING static void close_write_file(ostream *stream);
 
+  BLOCKING iostream *open_read_write_file(const Filename &filename, bool truncate);
+  BLOCKING iostream *open_read_append_file(const Filename &filename);
+  BLOCKING static void close_read_write_file(iostream *stream);
+
 public:
   INLINE bool read_file(const Filename &filename, string &result, bool auto_unwrap) const;
   INLINE bool read_file(const Filename &filename, pvector<unsigned char> &result, bool auto_unwrap) const;