diff --git a/direct/src/plugin/p3dHost.I b/direct/src/plugin/p3dHost.I index a31a922a2b..14a1c10f2a 100644 --- a/direct/src/plugin/p3dHost.I +++ b/direct/src/plugin/p3dHost.I @@ -70,7 +70,8 @@ get_download_url_prefix() const { // Function: P3DHost::get_descriptive_name // Access: Public // Description: Returns the descriptive name provided for this host, -// if any. This will be available after +// if any. Returns the url if no descriptive name is +// provided. This will be available after // read_contents_file() has been called. //////////////////////////////////////////////////////////////////// inline const string &P3DHost:: diff --git a/direct/src/plugin/p3dHost.cxx b/direct/src/plugin/p3dHost.cxx index 485953142e..a2813287a1 100644 --- a/direct/src/plugin/p3dHost.cxx +++ b/direct/src/plugin/p3dHost.cxx @@ -37,6 +37,8 @@ P3DHost(const string &host_url) : } _download_url_prefix = _host_url_prefix; + _descriptive_name = _host_url; + _xcontents = NULL; _contents_seq = 0; } @@ -449,6 +451,37 @@ add_mirror(string mirror_url) { } } +//////////////////////////////////////////////////////////////////// +// Function: P3DHost::uninstall +// Access: Public +// Description: Removes the host directory and all its contents +// from the user's hard disk. +//////////////////////////////////////////////////////////////////// +void P3DHost:: +uninstall() { + if (_host_dir.empty()) { + nout << "Cannot uninstall " << _descriptive_name << ": host directory not yet known.\n"; + return; + } + + // First, explicitly uninstall each of our packages. + Packages::iterator mi; + for (mi = _packages.begin(); mi != _packages.end(); ++mi) { + PackageMap &package_map = (*mi).second; + PackageMap::iterator pi; + for (pi = package_map.begin(); pi != package_map.end(); ++pi) { + P3DPackage *package = (*pi).second; + package->uninstall(); + } + } + + // Then, uninstall the host itself. + nout << "Uninstalling " << _descriptive_name << " from " << _host_dir << "\n"; + + P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); + inst_mgr->delete_directory_recursively(_host_dir); +} + //////////////////////////////////////////////////////////////////// // Function: P3DHost::determine_host_dir // Access: Private diff --git a/direct/src/plugin/p3dHost.h b/direct/src/plugin/p3dHost.h index 0227fea891..4caffb48e5 100644 --- a/direct/src/plugin/p3dHost.h +++ b/direct/src/plugin/p3dHost.h @@ -64,6 +64,8 @@ public: void choose_random_mirrors(vector &result, int num_mirrors); void add_mirror(string mirror_url); + void uninstall(); + private: void determine_host_dir(const string &host_dir_basename); diff --git a/direct/src/plugin/p3dInstance.cxx b/direct/src/plugin/p3dInstance.cxx index c03a8be387..3e340b28e3 100644 --- a/direct/src/plugin/p3dInstance.cxx +++ b/direct/src/plugin/p3dInstance.cxx @@ -421,6 +421,10 @@ set_p3d_filename(const string &p3d_filename, const int &p3d_offset) { //////////////////////////////////////////////////////////////////// void P3DInstance:: set_wparams(const P3DWindowParams &wparams) { + if (is_failed()) { + return; + } + _got_wparams = true; _wparams = wparams; @@ -1080,6 +1084,12 @@ start_download(P3DDownload *download, bool add_request) { assert(download->get_download_id() == 0); assert(!download->get_url().empty()); + if (is_failed()) { + // Can't download anything more after failure. + download->cancel(); + return 0; + } + P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); int download_id = inst_mgr->get_unique_id(); @@ -1239,6 +1249,11 @@ splash_button_clicked_sub_thread() { //////////////////////////////////////////////////////////////////// void P3DInstance:: splash_button_clicked_main_thread() { + if (is_failed()) { + // Can't click the button after we've failed. + return; + } + if (!_p3d_trusted) { auth_button_clicked(); } else if (_session == NULL) { @@ -1329,7 +1344,7 @@ auth_finished_main_thread() { } //////////////////////////////////////////////////////////////////// -// Function: P3DInstance::uninstall +// Function: P3DInstance::uninstall_packages // Access: Public // Description: Stops the instance (if it is running) and deletes any // packages referenced by the instance. This is @@ -1337,23 +1352,39 @@ auth_finished_main_thread() { // P3DMainObject::call_uninstall(). //////////////////////////////////////////////////////////////////// void P3DInstance:: -uninstall() { - if (_session != NULL) { - _session->set_failed(); - _session->shutdown(); - } - +uninstall_packages() { Packages::const_iterator pi; for (pi = _packages.begin(); pi != _packages.end(); ++pi) { P3DPackage *package = (*pi); package->uninstall(); - package->remove_instance(this); } - _packages.clear(); +} - _auto_install = false; - _instance_window_opened = false; - set_failed(); +//////////////////////////////////////////////////////////////////// +// Function: P3DInstance::uninstall_host +// Access: Public +// Description: Stops the instance (if it is running) and deletes all +// packages downloaded from any of the host(s) +// referenced by the instance. This is a more +// aggressive uninstall than uninstall_packages(). This +// is normally called by JavaScript, via +// P3DMainObject::call_uninstall(). +//////////////////////////////////////////////////////////////////// +void P3DInstance:: +uninstall_host() { + set hosts; + + Packages::const_iterator pi; + for (pi = _packages.begin(); pi != _packages.end(); ++pi) { + P3DPackage *package = (*pi); + hosts.insert(package->get_host()); + } + + set::iterator hi; + for (hi = hosts.begin(); hi != hosts.end(); ++hi) { + P3DHost *host = (*hi); + host->uninstall(); + } } //////////////////////////////////////////////////////////////////// @@ -2283,9 +2314,9 @@ handle_script_request(const string &operation, P3D_object *object, //////////////////////////////////////////////////////////////////// void P3DInstance:: set_failed() { - _failed = true; set_button_image(IT_none); set_background_image(IT_failed); + _failed = true; make_splash_window(); } @@ -2312,7 +2343,7 @@ make_splash_window() { make_visible = false; } - if (_failed) { + if (is_failed()) { // But, if we've failed to launch somehow, we need to let the user // know. make_visible = true; @@ -2423,6 +2454,11 @@ make_splash_window() { //////////////////////////////////////////////////////////////////// void P3DInstance:: set_background_image(ImageType image_type) { + if (is_failed()) { + // Can't change the background again after we've failed. + return; + } + if (image_type != _current_background_image) { nout << "setting background to " << _image_type_names[image_type] << ", splash_window = " << _splash_window << "\n"; @@ -2455,6 +2491,11 @@ set_background_image(ImageType image_type) { //////////////////////////////////////////////////////////////////// void P3DInstance:: set_button_image(ImageType image_type) { + if (is_failed()) { + // Can't set the button again after we've failed. + return; + } + if (image_type != _current_button_image) { nout << "setting button to " << _image_type_names[image_type] << "\n"; // Remove the previous image. @@ -2659,6 +2700,10 @@ start_next_download() { //////////////////////////////////////////////////////////////////// void P3DInstance:: mark_download_complete() { + if (_failed) { + return; + } + if (!_download_complete) { _download_complete = true; _panda_script_object->set_bool_property("downloadComplete", true); diff --git a/direct/src/plugin/p3dInstance.h b/direct/src/plugin/p3dInstance.h index 4f8c20fe10..293a12797e 100644 --- a/direct/src/plugin/p3dInstance.h +++ b/direct/src/plugin/p3dInstance.h @@ -116,7 +116,8 @@ public: void auth_finished_sub_thread(); void auth_finished_main_thread(); - void uninstall(); + void uninstall_packages(); + void uninstall_host(); private: class ImageDownload : public P3DFileDownload { diff --git a/direct/src/plugin/p3dInstanceManager.I b/direct/src/plugin/p3dInstanceManager.I index 7013fde368..c8444f4bc7 100644 --- a/direct/src/plugin/p3dInstanceManager.I +++ b/direct/src/plugin/p3dInstanceManager.I @@ -24,6 +24,21 @@ is_initialized() const { return _is_initialized; } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstanceManager::reconsider_runtime_environment +// Access: Public +// Description: Recreates the runtime environment if a previous call +// to uninstall_all() removed it. Does nothing if the +// runtime environment is already correctly set up. +//////////////////////////////////////////////////////////////////// +inline void P3DInstanceManager:: +reconsider_runtime_environment() { + assert(_is_initialized); + if (!_created_runtime_environment) { + create_runtime_environment(); + } +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstanceManager::verify_contents // Access: Public diff --git a/direct/src/plugin/p3dInstanceManager.cxx b/direct/src/plugin/p3dInstanceManager.cxx index 288b4e2aa6..90b01f2b44 100644 --- a/direct/src/plugin/p3dInstanceManager.cxx +++ b/direct/src/plugin/p3dInstanceManager.cxx @@ -58,6 +58,7 @@ P3DInstanceManager() { init_xml(); _is_initialized = false; + _created_runtime_environment = false; _api_version = 0; _next_temp_filename_counter = 1; _unique_id = 0; @@ -187,36 +188,51 @@ initialize(int api_version, const string &contents_filename, const string &log_basename, bool trusted_environment, bool console_environment) { _api_version = api_version; - _trusted_environment = trusted_environment; - _console_environment = console_environment; + _host_url = host_url; _verify_contents = verify_contents; _platform = platform; - if (_platform.empty()) { - _platform = DTOOL_PLATFORM; - } + _log_directory = log_directory; + _log_basename = log_basename; + _trusted_environment = trusted_environment; + _console_environment = console_environment; - _host_url = host_url; if (_host_url.empty()) { _host_url = PANDA_PACKAGE_HOST_URL; } - _root_dir = find_root_dir(); + if (_platform.empty()) { + _platform = DTOOL_PLATFORM; + } - // Allow the caller (e.g. panda3d.exe) to specify a log directory. - _log_directory = log_directory; - - // Or, allow the developer to compile one in. #ifdef P3D_PLUGIN_LOG_DIRECTORY if (_log_directory.empty()) { _log_directory = P3D_PLUGIN_LOG_DIRECTORY; } #endif + +#ifdef P3D_PLUGIN_LOG_BASENAME2 + if (_log_basename.empty()) { + _log_basename = P3D_PLUGIN_LOG_BASENAME2; + } +#endif + if (_log_basename.empty()) { + _log_basename = "p3dcore"; + } + + _root_dir = find_root_dir(); + + if (_root_dir.empty()) { + cerr << "Could not find root directory.\n"; + return false; + } + + // Allow the caller (e.g. panda3d.exe) to specify a log directory. + // Or, allow the developer to compile one in. // Failing that, we write logfiles to Panda3D/log. if (_log_directory.empty()) { _log_directory = _root_dir + "/log"; } - mkdir_complete(_log_directory, cerr); // Ensure that the log directory ends with a slash. if (!_log_directory.empty() && _log_directory[_log_directory.size() - 1] != '/') { @@ -227,126 +243,11 @@ initialize(int api_version, const string &contents_filename, } // Construct the logfile pathname. - _log_basename = log_basename; -#ifdef P3D_PLUGIN_LOG_BASENAME2 - if (_log_basename.empty()) { - _log_basename = P3D_PLUGIN_LOG_BASENAME2; - } -#endif - if (_log_basename.empty()) { - _log_basename = "p3dcore"; - } _log_pathname = _log_directory; _log_pathname += _log_basename; _log_pathname += ".log"; - logfile.close(); - logfile.clear(); - logfile.open(_log_pathname.c_str(), ios::out | ios::trunc); - if (logfile) { - logfile.setf(ios::unitbuf); - nout_stream = &logfile; - } - - // Determine the temporary directory. -#ifdef _WIN32 - char buffer_1[MAX_PATH]; - - // Figuring out the correct path for temporary files is a real mess - // on Windows. We should be able to use GetTempPath(), but that - // relies on $TMP or $TEMP being defined, and it appears that - // Mozilla clears these environment variables for the plugin, which - // forces GetTempPath() into $USERPROFILE instead. This is really - // an inappropriate place for temporary files, so, GetTempPath() - // isn't a great choice. - - // We could use SHGetSpecialFolderPath() instead to get us the path - // to "Temporary Internet Files", which is acceptable. The trouble - // is, if we happen to be running in "Protected Mode" on Vista, this - // folder isn't actually writable by us! On Vista, we're supposed - // to use IEGetWriteableFolderPath() instead, but *this* function - // doesn't exist on XP and below. Good Lord. - - // We could go through a bunch of LoadLibrary() calls to try to find - // the right path, like we do in find_root_dir(), but I'm just tired - // of doing all that nonsense. We'll use a two-stage trick instead. - // We'll check for $TEMP or $TMP being defined specifically, and if - // they are, we'll use GetTempPath(); otherwise, we'll fall back to - // SHGetSpecialFolderPath(). - - if (getenv("TEMP") != NULL || getenv("TMP") != NULL) { - if (GetTempPath(MAX_PATH, buffer_1) != 0) { - _temp_directory = buffer_1; - } - } - if (_temp_directory.empty()) { - if (SHGetSpecialFolderPath(NULL, buffer_1, CSIDL_INTERNET_CACHE, true)) { - _temp_directory = buffer_1; - - // That just *might* return a non-writable folder, if we're in - // Protected Mode. We'll test this with GetTempFileName(). - char temp_buffer[MAX_PATH]; - if (!GetTempFileName(_temp_directory.c_str(), "p3d", 0, temp_buffer)) { - nout << "GetTempFileName failed on " << _temp_directory - << ", switching to GetTempPath\n"; - _temp_directory.clear(); - } else { - DeleteFile(temp_buffer); - } - } - } - - // If both of the above failed, we'll fall back to GetTempPath() - // once again as a last resort, which is supposed to return - // *something* that works, even if $TEMP and $TMP are undefined. - if (_temp_directory.empty()) { - if (GetTempPath(MAX_PATH, buffer_1) != 0) { - _temp_directory = buffer_1; - } - } - - // Also insist that the temp directory is fully specified. - size_t needs_size_2 = GetFullPathName(_temp_directory.c_str(), 0, NULL, NULL); - char *buffer_2 = new char[needs_size_2]; - if (GetFullPathName(_temp_directory.c_str(), needs_size_2, buffer_2, NULL) != 0) { - _temp_directory = buffer_2; - } - delete[] buffer_2; - - // And make sure the directory actually exists. - mkdir_complete(_temp_directory, nout); - -#else - _temp_directory = "/tmp/"; -#endif // _WIN32 - - // Ensure that the temp directory ends with a slash. - if (!_temp_directory.empty() && _temp_directory[_temp_directory.size() - 1] != '/') { -#ifdef _WIN32 - if (_temp_directory[_temp_directory.size() - 1] != '\\') -#endif - _temp_directory += "/"; - } - - nout << "_root_dir = " << _root_dir - << ", _temp_directory = " << _temp_directory - << ", platform = " << _platform - << ", contents_filename = " << contents_filename - << ", host_url = " << host_url - << ", verify_contents = " << verify_contents - << "\n"; - - if (_root_dir.empty()) { - nout << "Could not find root directory.\n"; - return false; - } - - // Make the certificate directory. - _certs_dir = _root_dir + "/certs"; - if (!mkdir_complete(_certs_dir, nout)) { - nout << "Couldn't mkdir " << _certs_dir << "\n"; - } - + create_runtime_environment(); _is_initialized = true; if (!_verify_contents && @@ -373,6 +274,7 @@ set_plugin_version(int major, int minor, int sequence, bool official, const string &distributor, const string &coreapi_host_url, time_t coreapi_timestamp) { + reconsider_runtime_environment(); _plugin_major_version = major; _plugin_minor_version = minor; _plugin_sequence_version = sequence; @@ -389,6 +291,7 @@ set_plugin_version(int major, int minor, int sequence, //////////////////////////////////////////////////////////////////// void P3DInstanceManager:: set_super_mirror(const string &super_mirror_url) { + reconsider_runtime_environment(); if (!super_mirror_url.empty()) { nout << "super_mirror = " << super_mirror_url << "\n"; } @@ -410,6 +313,7 @@ P3DInstance *P3DInstanceManager:: create_instance(P3D_request_ready_func *func, const P3D_token tokens[], size_t num_tokens, int argc, const char *argv[], void *user_data) { + reconsider_runtime_environment(); P3DInstance *inst = new P3DInstance(func, tokens, num_tokens, argc, argv, user_data); inst->ref(); @@ -961,6 +865,43 @@ cert_to_der(X509 *cert) { return result; } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstanceManager::uninstall_all +// Access: Public +// Description: Stops all active instances and removes *all* +// downloaded files from all hosts, and empties the +// current user's Panda3D directory as much as possible. +// +// This cannot remove the coreapi dll or directory on +// Windows. +//////////////////////////////////////////////////////////////////// +void P3DInstanceManager:: +uninstall_all() { + Instances::iterator ii; + for (ii = _instances.begin(); ii != _instances.end(); ++ii) { + P3DInstance *inst = (*ii); + inst->uninstall_host(); + } + + Hosts::iterator hi; + for (hi = _hosts.begin(); hi != _hosts.end(); ++hi) { + P3DHost *host = (*hi).second; + host->uninstall(); + } + + // Close the logfile so we can remove that too. + logfile.close(); + + if (!_root_dir.empty()) { + // This won't be able to delete the coreapi directory on Windows, + // because we're running that DLL right now. But it will delete + // everything else. + delete_directory_recursively(_root_dir); + } + + _created_runtime_environment = false; +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstanceManager::get_global_ptr // Access: Public, Static @@ -1112,6 +1053,82 @@ scan_directory_recursively(const string &dirname, return true; } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstanceManager::delete_directory_recursively +// Access: Public, Static +// Description: Deletes all of the files and directories in the named +// directory and below, like rm -rf. Use with extreme +// caution. +//////////////////////////////////////////////////////////////////// +void P3DInstanceManager:: +delete_directory_recursively(const string &root_dir) { + vector contents, dirname_contents; + if (!scan_directory_recursively(root_dir, contents, dirname_contents)) { + // Maybe it's just a single file, not a directory. Delete it. +#ifdef _WIN32 + // Windows can't delete a file if it's read-only. + chmod(root_dir.c_str(), 0644); +#endif + int result = unlink(root_dir.c_str()); + if (result == 0) { + nout << "Deleted " << root_dir << "\n"; + } else { + if (access(root_dir.c_str(), F_OK) == 0) { + nout << "Could not delete " << root_dir << "\n"; + } + } + return; + } + + vector::iterator ci; + for (ci = contents.begin(); ci != contents.end(); ++ci) { + string filename = (*ci); + string pathname = root_dir + "/" + filename; + +#ifdef _WIN32 + // Windows can't delete a file if it's read-only. + chmod(pathname.c_str(), 0644); +#endif + int result = unlink(pathname.c_str()); + if (result == 0) { + nout << " Deleted " << filename << "\n"; + } else { + nout << " Could not delete " << filename << "\n"; + } + } + + // Now delete all of the directories too. They're already in + // reverse order, so we remove deeper directories first. + for (ci = dirname_contents.begin(); ci != dirname_contents.end(); ++ci) { + string filename = (*ci); + string pathname = root_dir + "/" + filename; + +#ifdef _WIN32 + chmod(pathname.c_str(), 0755); +#endif + int result = rmdir(pathname.c_str()); + if (result == 0) { + nout << " Removed directory " << filename << "\n"; + } else { + nout << " Could not remove directory " << filename << "\n"; + } + } + + // Finally, delete the root directory itself. + string pathname = root_dir; +#ifdef _WIN32 + chmod(pathname.c_str(), 0755); +#endif + int result = rmdir(pathname.c_str()); + if (result == 0) { + nout << "Removed directory " << root_dir << "\n"; + } else { + if (access(pathname.c_str(), F_OK) == 0) { + nout << "Could not remove directory " << root_dir << "\n"; + } + } +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstanceManager::remove_file_from_list // Access: Public, Static @@ -1185,6 +1202,121 @@ append_safe_dir(string &root, const string &basename) { } } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstanceManager::create_runtime_environment +// Access: Private +// Description: Called during initialize, or after a previous call to +// uninstall_all(), to make sure all needed +// directories exist and the logfile is open. +//////////////////////////////////////////////////////////////////// +void P3DInstanceManager:: +create_runtime_environment() { + mkdir_complete(_log_directory, cerr); + + logfile.close(); + logfile.clear(); + logfile.open(_log_pathname.c_str(), ios::out | ios::trunc); + if (logfile) { + logfile.setf(ios::unitbuf); + nout_stream = &logfile; + } + + // Determine the temporary directory. +#ifdef _WIN32 + char buffer_1[MAX_PATH]; + + // Figuring out the correct path for temporary files is a real mess + // on Windows. We should be able to use GetTempPath(), but that + // relies on $TMP or $TEMP being defined, and it appears that + // Mozilla clears these environment variables for the plugin, which + // forces GetTempPath() into $USERPROFILE instead. This is really + // an inappropriate place for temporary files, so, GetTempPath() + // isn't a great choice. + + // We could use SHGetSpecialFolderPath() instead to get us the path + // to "Temporary Internet Files", which is acceptable. The trouble + // is, if we happen to be running in "Protected Mode" on Vista, this + // folder isn't actually writable by us! On Vista, we're supposed + // to use IEGetWriteableFolderPath() instead, but *this* function + // doesn't exist on XP and below. Good Lord. + + // We could go through a bunch of LoadLibrary() calls to try to find + // the right path, like we do in find_root_dir(), but I'm just tired + // of doing all that nonsense. We'll use a two-stage trick instead. + // We'll check for $TEMP or $TMP being defined specifically, and if + // they are, we'll use GetTempPath(); otherwise, we'll fall back to + // SHGetSpecialFolderPath(). + + if (getenv("TEMP") != NULL || getenv("TMP") != NULL) { + if (GetTempPath(MAX_PATH, buffer_1) != 0) { + _temp_directory = buffer_1; + } + } + if (_temp_directory.empty()) { + if (SHGetSpecialFolderPath(NULL, buffer_1, CSIDL_INTERNET_CACHE, true)) { + _temp_directory = buffer_1; + + // That just *might* return a non-writable folder, if we're in + // Protected Mode. We'll test this with GetTempFileName(). + char temp_buffer[MAX_PATH]; + if (!GetTempFileName(_temp_directory.c_str(), "p3d", 0, temp_buffer)) { + nout << "GetTempFileName failed on " << _temp_directory + << ", switching to GetTempPath\n"; + _temp_directory.clear(); + } else { + DeleteFile(temp_buffer); + } + } + } + + // If both of the above failed, we'll fall back to GetTempPath() + // once again as a last resort, which is supposed to return + // *something* that works, even if $TEMP and $TMP are undefined. + if (_temp_directory.empty()) { + if (GetTempPath(MAX_PATH, buffer_1) != 0) { + _temp_directory = buffer_1; + } + } + + // Also insist that the temp directory is fully specified. + size_t needs_size_2 = GetFullPathName(_temp_directory.c_str(), 0, NULL, NULL); + char *buffer_2 = new char[needs_size_2]; + if (GetFullPathName(_temp_directory.c_str(), needs_size_2, buffer_2, NULL) != 0) { + _temp_directory = buffer_2; + } + delete[] buffer_2; + + // And make sure the directory actually exists. + mkdir_complete(_temp_directory, nout); + +#else + _temp_directory = "/tmp/"; +#endif // _WIN32 + + // Ensure that the temp directory ends with a slash. + if (!_temp_directory.empty() && _temp_directory[_temp_directory.size() - 1] != '/') { +#ifdef _WIN32 + if (_temp_directory[_temp_directory.size() - 1] != '\\') +#endif + _temp_directory += "/"; + } + + nout << "_root_dir = " << _root_dir + << ", _temp_directory = " << _temp_directory + << ", platform = " << _platform + << ", host_url = " << _host_url + << ", verify_contents = " << _verify_contents + << "\n"; + + // Make the certificate directory. + _certs_dir = _root_dir + "/certs"; + if (!mkdir_complete(_certs_dir, nout)) { + nout << "Couldn't mkdir " << _certs_dir << "\n"; + } + + _created_runtime_environment = true; +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstanceManager::append_safe_dir_component // Access: Private, Static diff --git a/direct/src/plugin/p3dInstanceManager.h b/direct/src/plugin/p3dInstanceManager.h index 811de78fcf..dc23b94043 100644 --- a/direct/src/plugin/p3dInstanceManager.h +++ b/direct/src/plugin/p3dInstanceManager.h @@ -60,6 +60,7 @@ public: bool console_environment); inline bool is_initialized() const; + inline void reconsider_runtime_environment(); inline bool get_verify_contents() const; inline void reset_verify_contents(); @@ -126,6 +127,8 @@ public: string get_cert_dir(X509 *cert); static string cert_to_der(X509 *cert); + void uninstall_all(); + static P3DInstanceManager *get_global_ptr(); static void delete_global_ptr(); @@ -135,11 +138,13 @@ public: vector &filename_contents, vector &dirname_contents, const string &prefix = ""); + static void delete_directory_recursively(const string &root_dir); static bool remove_file_from_list(vector &contents, const string &filename); static void append_safe_dir(string &root, const string &basename); private: + void create_runtime_environment(); static void append_safe_dir_component(string &root, const string &component); private: @@ -151,6 +156,7 @@ private: private: bool _is_initialized; + bool _created_runtime_environment; int _api_version; string _host_url; string _root_dir; diff --git a/direct/src/plugin/p3dMainObject.cxx b/direct/src/plugin/p3dMainObject.cxx index 4417ced798..37e493cc72 100644 --- a/direct/src/plugin/p3dMainObject.cxx +++ b/direct/src/plugin/p3dMainObject.cxx @@ -451,9 +451,29 @@ P3D_object *P3DMainObject:: call_uninstall(P3D_object *params[], int num_params) { P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); + // Get the first parameter, the uninstall mode. + string mode; + if (num_params > 0) { + int size = P3D_OBJECT_GET_STRING(params[0], NULL, 0); + char *buffer = new char[size]; + P3D_OBJECT_GET_STRING(params[0], buffer, size); + mode = string(buffer, size); + delete[] buffer; + } + + if (mode == "all") { + nout << "uninstall all\n"; + inst_mgr->uninstall_all(); + return inst_mgr->new_bool_object(true); + } + if (_inst != NULL) { - nout << "uninstall for " << _inst << "\n"; - _inst->uninstall(); + nout << "uninstall " << mode << " for " << _inst << "\n"; + if (mode == "host") { + _inst->uninstall_host(); + } else { + _inst->uninstall_packages(); + } return inst_mgr->new_bool_object(true); } diff --git a/direct/src/plugin/p3dPackage.cxx b/direct/src/plugin/p3dPackage.cxx index 91c235c570..9dc1e2cfb3 100755 --- a/direct/src/plugin/p3dPackage.cxx +++ b/direct/src/plugin/p3dPackage.cxx @@ -217,56 +217,23 @@ uninstall() { nout << "Uninstalling package " << _package_name << " from " << _package_dir << "\n"; + // First, make sure that all instances that are sharing this package + // are stopped, so there will be no access conflicts preventing us + // from removing the files. This is particularly important on + // Windows. + Instances::iterator ii; + for (ii = _instances.begin(); ii != _instances.end(); ++ii) { + P3DInstance *inst = (*ii); + P3DSession *session = inst->get_session(); + if (session != NULL) { + nout << "Stopping session " << session << "\n"; + session->shutdown(); + } + inst->set_failed(); + } + P3DInstanceManager *inst_mgr = P3DInstanceManager::get_global_ptr(); - vector contents, dirname_contents; - inst_mgr->scan_directory_recursively(_package_dir, contents, - dirname_contents); - - vector::iterator ci; - for (ci = contents.begin(); ci != contents.end(); ++ci) { - string filename = (*ci); - string pathname = _package_dir + "/" + filename; - -#ifdef _WIN32 - // Windows can't delete a file if it's read-only. - chmod(pathname.c_str(), 0644); -#endif - int result = unlink(pathname.c_str()); - if (result == 0) { - nout << " Deleted " << filename << "\n"; - } else { - nout << " Could not delete " << filename << "\n"; - } - } - - // Now delete all of the directories too. They're already in - // reverse order, so we remove deeper directories first. - for (ci = dirname_contents.begin(); ci != dirname_contents.end(); ++ci) { - string filename = (*ci); - string pathname = _package_dir + "/" + filename; - -#ifdef _WIN32 - chmod(pathname.c_str(), 0755); -#endif - int result = rmdir(pathname.c_str()); - if (result == 0) { - nout << " Removed directory " << filename << "\n"; - } else { - nout << " Could not remove directory " << filename << "\n"; - } - } - - // Finally, delete the package directory itself. - string pathname = _package_dir; -#ifdef _WIN32 - chmod(pathname.c_str(), 0755); -#endif - int result = rmdir(pathname.c_str()); - if (result == 0) { - nout << "Removed directory " << _package_dir << "\n"; - } else { - nout << "Could not remove directory " << _package_dir << "\n"; - } + inst_mgr->delete_directory_recursively(_package_dir); _info_ready = false; _ready = false; diff --git a/direct/src/plugin/p3dSession.cxx b/direct/src/plugin/p3dSession.cxx index 64d0c627e5..aaac6ec47a 100644 --- a/direct/src/plugin/p3dSession.cxx +++ b/direct/src/plugin/p3dSession.cxx @@ -96,6 +96,8 @@ P3DSession:: //////////////////////////////////////////////////////////////////// void P3DSession:: shutdown() { + set_failed(); + if (_p3dpython_started) { // Tell the process we're going away. TiXmlDocument doc;