diff --git a/direct/src/plugin/Sources.pp b/direct/src/plugin/Sources.pp index f9efe6ce34..6a7e3ba6e1 100644 --- a/direct/src/plugin/Sources.pp +++ b/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 diff --git a/direct/src/plugin/make_package.py b/direct/src/plugin/make_package.py index c97033990c..d70b36a916 100755 --- a/direct/src/plugin/make_package.py +++ b/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, '' @@ -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) diff --git a/direct/src/plugin/p3dDownload.cxx b/direct/src/plugin/p3dDownload.cxx index b5053533d5..a579591082 100755 --- a/direct/src/plugin/p3dDownload.cxx +++ b/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"; } diff --git a/direct/src/plugin/p3dDownload.h b/direct/src/plugin/p3dDownload.h index aa44a8f2ce..b79e34743f 100755 --- a/direct/src/plugin/p3dDownload.h +++ b/direct/src/plugin/p3dDownload.h @@ -17,6 +17,8 @@ #include "p3d_plugin_common.h" +#include + //////////////////////////////////////////////////////////////////// // 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; diff --git a/direct/src/plugin/p3dFileDownload.cxx b/direct/src/plugin/p3dFileDownload.cxx index e370adfc2b..961d0e1af5 100755 --- a/direct/src/plugin/p3dFileDownload.cxx +++ b/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; diff --git a/direct/src/plugin/p3dInstanceManager.cxx b/direct/src/plugin/p3dInstanceManager.cxx index 90c3843aae..b3cedeeb73 100644 --- a/direct/src/plugin/p3dInstanceManager.cxx +++ b/direct/src/plugin/p3dInstanceManager.cxx @@ -17,6 +17,10 @@ #include "p3dSession.h" #include "p3dPackage.h" +#ifdef _WIN32 +#include +#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 +} + + diff --git a/direct/src/plugin/p3dInstanceManager.h b/direct/src/plugin/p3dInstanceManager.h index 7d1deb41cf..ac00494a70 100644 --- a/direct/src/plugin/p3dInstanceManager.h +++ b/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; diff --git a/direct/src/plugin/p3dMultifileReader.cxx b/direct/src/plugin/p3dMultifileReader.cxx index 3b09f5bc6e..05de8aad8b 100644 --- a/direct/src/plugin/p3dMultifileReader.cxx +++ b/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; diff --git a/direct/src/plugin/p3dPackage.cxx b/direct/src/plugin/p3dPackage.cxx index 73bc6be8bf..a8b0775e7b 100755 --- a/direct/src/plugin/p3dPackage.cxx +++ b/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";