Browse Source

standard install dirs

David Rose 16 years ago
parent
commit
77b6df9fd7

+ 2 - 0
direct/src/plugin/Sources.pp

@@ -35,6 +35,8 @@
   #define INSTALL_HEADERS \
     p3d_plugin.h
 
+  #define WIN_SYS_LIBS shell32.lib
+
 #end lib_target
 
 #begin bin_target

+ 10 - 22
direct/src/plugin/make_package.py

@@ -38,25 +38,11 @@ import zlib
 import direct
 from pandac.PandaModules import *
 
+from FileSpec import FileSpec
+
 class ArgumentError(AttributeError):
     pass
 
-class FileSpec:
-    def __init__(self, filename, pathname):
-        self.filename = filename
-        self.pathname = pathname
-
-        self.size = pathname.getFileSize()
-        self.timestamp = pathname.getTimestamp()
-
-        hv = HashVal()
-        hv.hashFile(pathname)
-        self.hash = hv.asHex()
-
-    def getParams(self):
-        return 'filename="%s" size=%s timestamp=%s hash="%s"' % (
-            self.filename, self.size, self.timestamp, self.hash)
-
 class PackageMaker:
     def __init__(self):
         self.startDir = None
@@ -76,10 +62,12 @@ class PackageMaker:
         self.packageFullname = '%s_%s' % (
             self.packageName, self.packageVersion)
 
-        self.cleanDir(self.stageDir)
+        self.packageStageDir = Filename(self.stageDir, '%s/%s' % (self.packageName, self.packageVersion))
+
+        self.cleanDir(self.packageStageDir)
 
         uncompressedArchiveBasename = '%s.mf' % (self.packageFullname)
-        uncompressedArchivePathname = Filename(self.stageDir, uncompressedArchiveBasename)
+        uncompressedArchivePathname = Filename(self.packageStageDir, uncompressedArchiveBasename)
         self.archive = Multifile()
         if not self.archive.openWrite(uncompressedArchivePathname):
             raise IOError, "Couldn't open %s for writing" % (uncompressedArchivePathname)
@@ -92,7 +80,7 @@ class PackageMaker:
         uncompressedArchive = FileSpec(uncompressedArchiveBasename, uncompressedArchivePathname)
 
         compressedArchiveBasename = '%s.mf.pz' % (self.packageFullname)
-        compressedArchivePathname = Filename(self.stageDir, compressedArchiveBasename)
+        compressedArchivePathname = Filename(self.packageStageDir, compressedArchiveBasename)
 
         print "\ncompressing"
 
@@ -112,7 +100,7 @@ class PackageMaker:
         uncompressedArchivePathname.unlink()
 
         descFileBasename = '%s.xml' % (self.packageFullname)
-        descFilePathname = Filename(self.stageDir, descFileBasename)
+        descFilePathname = Filename(self.packageStageDir, descFileBasename)
 
         f = open(descFilePathname.toOsSpecific(), 'w')
         print >> f, '<?xml version="1.0" ?>'
@@ -148,11 +136,11 @@ class PackageMaker:
                 localpath = ''
             else:
                 assert dirpath.startswith(prefix)
-                localpath = dirpath[len(prefix):] + '/'
+                localpath = dirpath[len(prefix):].replace(os.sep, '/') + '/'
 
             for basename in filenames:
                 file = FileSpec(localpath + basename,
-                                Filename(self.startDir, basename))
+                                Filename(self.startDir, localpath + basename))
                 print file.filename
                 self.components.append(file)
                 self.archive.addSubfile(file.filename, file.pathname, 0)

+ 9 - 2
direct/src/plugin/p3dDownload.cxx

@@ -25,6 +25,7 @@ P3DDownload() {
   _http_status_code = 0;
   _total_data = 0;
   _total_expected_data = 0;
+  _last_reported_time = 0;
   
   _canceled = false;
   _download_id = 0;
@@ -126,8 +127,12 @@ receive_data(const unsigned char *this_data, size_t this_data_size) {
 ////////////////////////////////////////////////////////////////////
 void P3DDownload::
 download_progress() {
-  cerr << "Downloading " << get_url() << ": " 
-       << int(get_download_progress() * 1000.0) / 10.0 << "\n";
+  time_t now = time(NULL);
+  if (now != _last_reported_time) {
+    cerr << "Downloading " << get_url() << ": " 
+         << int(get_download_progress() * 1000.0) / 10.0 << "\n";
+    _last_reported_time = now;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -140,4 +145,6 @@ download_progress() {
 ////////////////////////////////////////////////////////////////////
 void P3DDownload::
 download_finished(bool success) {
+  cerr << "Downloading " << get_url() << ": " 
+       << int(get_download_progress() * 1000.0) / 10.0 << "\n";
 }

+ 3 - 0
direct/src/plugin/p3dDownload.h

@@ -17,6 +17,8 @@
 
 #include "p3d_plugin_common.h"
 
+#include <time.h>
+
 ////////////////////////////////////////////////////////////////////
 //       Class : P3DDownload
 // Description : This represents a request to download a single file
@@ -62,6 +64,7 @@ protected:
 
   size_t _total_data;
   size_t _total_expected_data;
+  time_t _last_reported_time;
 
 private:
   bool _canceled;

+ 7 - 0
direct/src/plugin/p3dFileDownload.cxx

@@ -13,6 +13,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "p3dFileDownload.h"
+#include "p3dInstanceManager.h"
 
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DFileDownload::Constructor
@@ -44,6 +45,12 @@ set_filename(const string &filename) {
 ////////////////////////////////////////////////////////////////////
 bool P3DFileDownload::
 open_file() {
+  P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+  if (!inst_mgr->mkfile_public(_filename)) {
+    cerr << "Unable to create " << _filename << "\n";
+    return false;
+  }
+  
   _file.open(_filename.c_str(), ios::out | ios::ate | ios::binary);
   if (!_file) {
     return false;

+ 193 - 3
direct/src/plugin/p3dInstanceManager.cxx

@@ -17,6 +17,10 @@
 #include "p3dSession.h"
 #include "p3dPackage.h"
 
+#ifdef _WIN32
+#include <shlobj.h>
+#endif
+
 P3DInstanceManager *P3DInstanceManager::_global_ptr;
 
 ////////////////////////////////////////////////////////////////////
@@ -73,13 +77,21 @@ P3DInstanceManager::
 ////////////////////////////////////////////////////////////////////
 bool P3DInstanceManager::
 initialize() {
+  _root_dir = find_root_dir();
+  cerr << "_root_dir = " << _root_dir << "\n";
+
 #ifdef _WIN32
-  _root_dir = "c:/cygwin/home/drose/p3ddir";
-  _download_url = "http://10.196.143.118/~drose/";
+  _download_url = "http://10.196.143.118/~drose/p3d/";
+
 #else
-  _root_dir = "/Users/drose/p3ddir";
   _download_url = "http://orpheus.ddrose.com/~drose/";
 #endif
+
+  if (_root_dir.empty()) {
+    cerr << "Could not find root directory.\n";
+    return false;
+  }
+
   return true;
 }
 
@@ -264,6 +276,67 @@ signal_request_ready() {
 #endif
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstanceManager::mkdir_public
+//       Access: Public, Static
+//  Description: Creates a new directory with wide-open access
+//               priviledges.
+////////////////////////////////////////////////////////////////////
+void P3DInstanceManager::
+mkdir_public(const string &dirname) {
+#ifdef _WIN32
+  SECURITY_DESCRIPTOR sd;
+  InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
+  SetSecurityDescriptorDacl(&sd, true, NULL, false);
+  
+  SECURITY_ATTRIBUTES sa;
+  sa.nLength = sizeof(sa);
+  sa.lpSecurityDescriptor = &sd;
+  CreateDirectory(dirname.c_str(), &sa);
+
+#else  //_WIN32
+  mkdir(dirname.c_str(), 0777);
+
+#endif  // _WIN32
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstanceManager::mkfile_public
+//       Access: Public, Static
+//  Description: Creates a new file with wide-open access
+//               priviledges.
+////////////////////////////////////////////////////////////////////
+bool P3DInstanceManager::
+mkfile_public(const string &filename) {
+#ifdef _WIN32
+  SECURITY_DESCRIPTOR sd;
+  InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION);
+  SetSecurityDescriptorDacl(&sd, true, NULL, false);
+  
+  SECURITY_ATTRIBUTES sa;
+  sa.nLength = sizeof(sa);
+  sa.lpSecurityDescriptor = &sd;
+
+  HANDLE file = CreateFile(filename.c_str(), GENERIC_READ | GENERIC_WRITE,
+                           FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
+                           &sa, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
+  if (file == INVALID_HANDLE_VALUE) {
+    return false;
+  }
+  CloseHandle(file);
+  return true;
+
+#else  // _WIN32
+  int fd = creat(filename.c_str(), 0777);
+  if (fd == -1) {
+    return false;
+  }
+  close(fd);
+  return true;
+
+#endif  // _WIN32
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: P3DInstanceManager::get_global_ptr
 //       Access: Public, Static
@@ -292,3 +365,120 @@ create_command_instance() {
     new P3DInstance(NULL, "", P3D_WT_hidden, 0, 0, 0, 0, 
                     dummy_handle, NULL, 0);
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: P3DInstanceManager::find_root_dir
+//       Access: Private
+//  Description: Returns the path to the installable Panda3D directory
+//               on the user's machine.
+////////////////////////////////////////////////////////////////////
+string P3DInstanceManager::
+find_root_dir() const {
+#ifdef _WIN32
+  // Try to locate a writable directory to install Panda files into.
+  char buffer[MAX_PATH];
+
+  // First, check for a user-appdata Panda3D folder.  If it already
+  // exists, use it (but don't create it yet).
+  if (SHGetSpecialFolderPath(NULL, buffer, CSIDL_APPDATA, true)) {
+    bool isdir = false;
+    DWORD results = GetFileAttributes(buffer);
+    if (results != -1) {
+      isdir = (results & FILE_ATTRIBUTE_DIRECTORY) != 0;
+    }
+
+    if (isdir) {
+      // The user prefix exists; do we have a Panda3D child?
+      string root = buffer;
+      root += string("/Panda3D");
+
+      // Don't attempt to create the Panda3D folder yet.  Just see if
+      // it exists.
+      isdir = false;
+      results = GetFileAttributes(root.c_str());
+      if (results != -1) {
+        isdir = (results & FILE_ATTRIBUTE_DIRECTORY) != 0;
+      }
+
+      if (isdir) {
+        // The directory exists!
+        return root;
+      }
+    }
+  }
+
+  // If there's no user-appdata Panda3D folder, look for a common one.
+  // This time we'll create it if it doesn't exist, if we can.  (We'd
+  // prefer to create the folder in a common space if we can, since
+  // that way it can be shared by multiple users.)
+  if (SHGetSpecialFolderPath(NULL, buffer, CSIDL_COMMON_APPDATA, true)) {
+    bool isdir = false;
+    DWORD results = GetFileAttributes(buffer);
+    if (results != -1) {
+      isdir = (results & FILE_ATTRIBUTE_DIRECTORY) != 0;
+    }
+
+    if (isdir) {
+      // The common prefix exists; do we have a Panda3D child?
+      string root = buffer;
+      root += string("/Panda3D");
+
+      // Attempt to make it first, if possible.  Make sure the
+      // security attributes are wide open; this is a shared resource.
+      mkdir_public(root);
+
+      isdir = false;
+      results = GetFileAttributes(root.c_str());
+      if (results != -1) {
+        isdir = (results & FILE_ATTRIBUTE_DIRECTORY) != 0;
+      }
+
+      if (isdir) {
+        // The directory exists!
+        return root;
+      }
+    }
+  }
+
+  // Now try again to create a Panda3D folder in user-specific
+  // directory.  Presumably we'll have write permission to this one.
+  if (SHGetSpecialFolderPath(NULL, buffer, CSIDL_APPDATA, true)) {
+    bool isdir = false;
+    DWORD results = GetFileAttributes(buffer);
+    if (results != -1) {
+      isdir = (results & FILE_ATTRIBUTE_DIRECTORY) != 0;
+    }
+
+    if (isdir) {
+      // The user prefix exists; do we have a Panda3D child?
+      string root = buffer;
+      root += string("/Panda3D");
+
+      // Attempt to make it first, if possible.  This time we don't
+      // attempt to make it public, since this is a private space.
+      CreateDirectory(root.c_str(), NULL);
+
+      isdir = false;
+      results = GetFileAttributes(root.c_str());
+      if (results != -1) {
+        isdir = (results & FILE_ATTRIBUTE_DIRECTORY) != 0;
+      }
+
+      if (isdir) {
+        // The directory exists!
+        return root;
+      }
+    }
+  }
+
+  // Couldn't find a directory.  Bail.
+  cerr << "Couldn't find a root directory.\n";
+  return string();
+
+#else  // _WIN32
+  return "/Users/drose/p3ddir";
+
+#endif
+}
+
+

+ 4 - 0
direct/src/plugin/p3dInstanceManager.h

@@ -64,10 +64,14 @@ public:
   int get_unique_session_index();
   void signal_request_ready();
 
+  static void mkdir_public(const string &dirname);
+  static bool mkfile_public(const string &dirname);
+
   static P3DInstanceManager *get_global_ptr();
 
 private:
   void create_command_instance();
+  string find_root_dir() const;
 
 private:
   string _root_dir;

+ 10 - 2
direct/src/plugin/p3dMultifileReader.cxx

@@ -13,6 +13,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "p3dMultifileReader.h"
+#include "p3dInstanceManager.h"
 
 // This sequence of bytes begins each Multifile to identify it as a
 // Multifile.
@@ -77,6 +78,8 @@ extract(const string &pathname, const string &to_dir) {
     return false;
   }
 
+  P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+
   // Now walk through all of the files.
   Subfiles::iterator si;
   for (si = _subfiles.begin(); si != _subfiles.end(); ++si) {
@@ -84,12 +87,17 @@ extract(const string &pathname, const string &to_dir) {
     cerr << s._filename << "\n";
 
     string output_pathname = to_dir + "/" + s._filename;
-    ofstream out(output_pathname.c_str(), ios::out | ios::trunc | ios::binary);
-    if (!out) {
+    if (!inst_mgr->mkfile_public(output_pathname)) {
       cerr << "Unable to create " << output_pathname << "\n";
       return false;
     }
 
+    ofstream out(output_pathname.c_str(), ios::out | ios::binary);
+    if (!out) {
+      cerr << "Unable to write to " << output_pathname << "\n";
+      return false;
+    }
+
     _in.seekg(s._start);
 
     static const size_t buffer_size = 1024;

+ 15 - 10
direct/src/plugin/p3dPackage.cxx

@@ -58,18 +58,10 @@ P3DPackage(const string &package_name, const string &package_version) :
 
   // Ensure the package directory exists; create it if it does not.
   _package_dir = inst_mgr->get_root_dir() + string("/") + _package_name;
-#ifdef _WIN32
-  _mkdir(_package_dir.c_str());
-#else
-  mkdir(_package_dir.c_str(), 0777);
-#endif
+  inst_mgr->mkdir_public(_package_dir);
 
   _package_dir += string("/") + _package_version;
-#ifdef _WIN32
-  _mkdir(_package_dir.c_str());
-#else
-  mkdir(_package_dir.c_str(), 0777);
-#endif
+  inst_mgr->mkdir_public(_package_dir);
 
   _desc_file_basename = _package_fullname + ".xml";
   _desc_file_pathname = _package_dir + "/" + _desc_file_basename;
@@ -77,6 +69,9 @@ P3DPackage(const string &package_name, const string &package_version) :
   // TODO: we should check the desc file for updates with the server.
   // Perhaps this should be done in a parent class.
 
+  // TODO: if the desc file exists, and is consistent with the server
+  // contents file, don't re-download it.
+  /*
   // Load the desc file, if it exists.
   TiXmlDocument doc(_desc_file_pathname.c_str());
   if (!doc.LoadFile()) {
@@ -84,6 +79,9 @@ P3DPackage(const string &package_name, const string &package_version) :
   } else {
     got_desc_file(&doc, false);
   }
+  */
+
+  download_desc_file();
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -312,6 +310,13 @@ uncompress_archive() {
     return;
   }
 
+  P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr();
+  if (!inst_mgr->mkfile_public(target_pathname)) {
+    cerr << "Unable to create " << target_pathname << "\n";
+    report_done(false);
+    return;
+  }
+
   ofstream target(target_pathname.c_str(), ios::out | ios::binary);
   if (!target) {
     cerr << "Couldn't write to " << target_pathname << "\n";