uninstall good
This commit is contained in:
parent
38d3eda196
commit
fd6e2fc82a
|
|
@ -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::
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -64,6 +64,8 @@ public:
|
|||
void choose_random_mirrors(vector<string> &result, int num_mirrors);
|
||||
void add_mirror(string mirror_url);
|
||||
|
||||
void uninstall();
|
||||
|
||||
private:
|
||||
void determine_host_dir(const string &host_dir_basename);
|
||||
|
||||
|
|
|
|||
|
|
@ -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<P3DHost *> hosts;
|
||||
|
||||
Packages::const_iterator pi;
|
||||
for (pi = _packages.begin(); pi != _packages.end(); ++pi) {
|
||||
P3DPackage *package = (*pi);
|
||||
hosts.insert(package->get_host());
|
||||
}
|
||||
|
||||
set<P3DHost *>::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);
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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<string> 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<string>::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
|
||||
|
|
|
|||
|
|
@ -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<string> &filename_contents,
|
||||
vector<string> &dirname_contents,
|
||||
const string &prefix = "");
|
||||
static void delete_directory_recursively(const string &root_dir);
|
||||
static bool remove_file_from_list(vector<string> &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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<string> contents, dirname_contents;
|
||||
inst_mgr->scan_directory_recursively(_package_dir, contents,
|
||||
dirname_contents);
|
||||
|
||||
vector<string>::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;
|
||||
|
|
|
|||
|
|
@ -96,6 +96,8 @@ P3DSession::
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void P3DSession::
|
||||
shutdown() {
|
||||
set_failed();
|
||||
|
||||
if (_p3dpython_started) {
|
||||
// Tell the process we're going away.
|
||||
TiXmlDocument doc;
|
||||
|
|
|
|||
Loading…
Reference in New Issue