diff --git a/direct/src/p3d/FileSpec.py b/direct/src/p3d/FileSpec.py index fe926912ae..09885d751a 100644 --- a/direct/src/p3d/FileSpec.py +++ b/direct/src/p3d/FileSpec.py @@ -164,9 +164,12 @@ class FileSpec: def __updateTimestamp(self, pathname, st): # On Windows, we have to change the file to read-write before # we can successfully update its timestamp. - os.chmod(pathname.toOsSpecific(), 0755) - os.utime(pathname.toOsSpecific(), (st.st_atime, self.timestamp)) - os.chmod(pathname.toOsSpecific(), 0555) + try: + os.chmod(pathname.toOsSpecific(), 0755) + os.utime(pathname.toOsSpecific(), (st.st_atime, self.timestamp)) + os.chmod(pathname.toOsSpecific(), 0555) + except OSError: + pass def checkHash(self, packageDir, pathname, st): """ Returns true if the file has the expected md5 hash, false diff --git a/direct/src/plugin/find_root_dir.cxx b/direct/src/plugin/find_root_dir.cxx index b7c955a222..a542841726 100755 --- a/direct/src/plugin/find_root_dir.cxx +++ b/direct/src/plugin/find_root_dir.cxx @@ -114,7 +114,7 @@ wstr_to_string(string &result, const LPWSTR wstr) { // on the user's machine. //////////////////////////////////////////////////////////////////// string -find_root_dir(ostream &logfile) { +find_root_dir() { #ifdef _WIN32 // First, use IEIsProtectedModeProcess() to determine if we are // running in IE's "protected mode" under Vista. @@ -130,7 +130,6 @@ find_root_dir(ostream &logfile) { HRESULT hr = (*func)(&result); if (hr == S_OK) { is_protected = (result != 0); - logfile << "IEIsProtectedModeProcess indicates: " << is_protected << "\n"; } // Any other return value means some error, especially // E_NOTIMPL, which means we're not running under Vista. In diff --git a/direct/src/plugin/find_root_dir.h b/direct/src/plugin/find_root_dir.h index f05602672e..7e39e13bb6 100755 --- a/direct/src/plugin/find_root_dir.h +++ b/direct/src/plugin/find_root_dir.h @@ -19,6 +19,6 @@ #include using namespace std; -string find_root_dir(ostream &logfile); +string find_root_dir(); #endif diff --git a/direct/src/plugin/p3dInstanceManager.I b/direct/src/plugin/p3dInstanceManager.I index 883f36c7ef..4aae0aadb7 100644 --- a/direct/src/plugin/p3dInstanceManager.I +++ b/direct/src/plugin/p3dInstanceManager.I @@ -75,14 +75,26 @@ get_platform() const { return _platform; } +//////////////////////////////////////////////////////////////////// +// Function: P3DInstanceManager::get_temp_directory +// Access: Public +// Description: Returns the pathname of the directory into which +// temporary files should be written. This filename +// will end with a slash, so that full pathnames may be +// made by concatenting directly with this string. +//////////////////////////////////////////////////////////////////// +inline const string &P3DInstanceManager:: +get_temp_directory() const { + return _temp_directory; +} + //////////////////////////////////////////////////////////////////// // Function: P3DInstanceManager::get_log_directory // Access: Public // Description: Returns the pathname of the directory into which all // log files should be written. This filename will end -// with a slash or backslash, as appropriate, so that -// logfile pathnames may be made by concatenting -// directly with this string. +// with a slash, so that full pathnames may be made by +// concatenting directly with this string. //////////////////////////////////////////////////////////////////// inline const string &P3DInstanceManager:: get_log_directory() const { diff --git a/direct/src/plugin/p3dInstanceManager.cxx b/direct/src/plugin/p3dInstanceManager.cxx index ad208ff66d..9db9b4a909 100644 --- a/direct/src/plugin/p3dInstanceManager.cxx +++ b/direct/src/plugin/p3dInstanceManager.cxx @@ -180,28 +180,109 @@ initialize(const string &contents_filename, const string &download_url, _platform = DTOOL_PLATFORM; } + _root_dir = find_root_dir(); + + // 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 + + // 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] != '/') { +#ifdef _WIN32 + if (_log_directory[_log_directory.size() - 1] != '\\') +#endif + _log_directory += "/"; + } + + // 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_pathname = _log_directory; + _log_pathname += _log_basename; + _log_pathname += ".log"; + + 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 - size_t needs_size_1 = GetTempPath(0, NULL); - char *buffer_1 = new char[needs_size_1]; - if (GetTempPath(needs_size_1, buffer_1) != 0) { - _temp_directory = buffer_1; - } - delete[] buffer_1; + char buffer_1[MAX_PATH]; - static const size_t buffer_size = 4096; - char buffer[buffer_size]; - if (GetTempPath(buffer_size, buffer) != 0) { - _temp_directory = buffer; + // 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]; @@ -217,18 +298,6 @@ initialize(const string &contents_filename, const string &download_url, _temp_directory = "/tmp/"; #endif // _WIN32 - // If the log directory is still empty, use the temp directory. - if (_log_directory.empty()) { - _log_directory = _temp_directory; - } - - _log_basename = log_basename; -#ifdef P3D_PLUGIN_LOG_BASENAME2 - if (_log_basename.empty()) { - _log_basename = P3D_PLUGIN_LOG_BASENAME2; - } -#endif - // Ensure that the temp directory ends with a slash. if (!_temp_directory.empty() && _temp_directory[_temp_directory.size() - 1] != '/') { #ifdef _WIN32 @@ -237,31 +306,8 @@ initialize(const string &contents_filename, const string &download_url, _temp_directory += "/"; } - // Ensure that the log directory ends with a slash. - if (!_log_directory.empty() && _log_directory[_log_directory.size() - 1] != '/') { -#ifdef _WIN32 - if (_log_directory[_log_directory.size() - 1] != '\\') -#endif - _log_directory += "/"; - } - - // Construct the logfile pathname. - if (!_log_basename.empty()) { - _log_pathname = _log_directory; - _log_pathname += _log_basename; - _log_pathname += ".log"; - - logfile.clear(); - logfile.open(_log_pathname.c_str(), ios::out | ios::trunc); - if (logfile) { - logfile.setf(ios::unitbuf); - nout_stream = &logfile; - } - } - - _root_dir = find_root_dir(nout); - nout << "_root_dir = " << _root_dir + << ", _temp_directory = " << _temp_directory << ", platform = " << _platform << ", contents_filename = " << contents_filename << ", download_url = " << download_url diff --git a/direct/src/plugin/p3dInstanceManager.h b/direct/src/plugin/p3dInstanceManager.h index 4d8bdbd09b..ff87059b4f 100644 --- a/direct/src/plugin/p3dInstanceManager.h +++ b/direct/src/plugin/p3dInstanceManager.h @@ -63,6 +63,7 @@ public: inline const string &get_root_dir() const; inline const string &get_platform() const; + inline const string &get_temp_directory() const; inline const string &get_log_directory() const; inline const string &get_log_pathname() const; inline bool get_trusted_environment() const; diff --git a/direct/src/plugin/p3dSession.cxx b/direct/src/plugin/p3dSession.cxx index b996abd59a..7cf32cc290 100644 --- a/direct/src/plugin/p3dSession.cxx +++ b/direct/src/plugin/p3dSession.cxx @@ -769,7 +769,7 @@ start_p3dpython(P3DInstance *inst) { // These are the enviroment variables we forward from the current // environment, if they are set. const char *keep[] = { - "TMP", "TEMP", "HOME", "USER", + "HOME", "USER", #ifdef _WIN32 "SYSTEMROOT", "USERPROFILE", "COMSPEC", #endif @@ -795,6 +795,7 @@ start_p3dpython(P3DInstance *inst) { const char *dont_keep[] = { "PATH", "LD_LIBRARY_PATH", "DYLD_LIBRARY_PATH", "PYTHONPATH", "PYTHONHOME", "PRC_PATH", "PANDA_PRC_PATH", + "TEMP", NULL }; @@ -862,6 +863,10 @@ start_p3dpython(P3DInstance *inst) { _env += "PANDA_PRC_PATH="; _env += prc_path; _env += '\0'; + + _env += "TEMP="; + _env += inst_mgr->get_temp_directory(); + _env += '\0'; // Define each package's root directory in an environment variable // named after the package, for the convenience of the packages in diff --git a/direct/src/plugin_activex/PPInstance.cpp b/direct/src/plugin_activex/PPInstance.cpp index 9b1a4b3945..75f694318a 100644 --- a/direct/src/plugin_activex/PPInstance.cpp +++ b/direct/src/plugin_activex/PPInstance.cpp @@ -71,10 +71,12 @@ void P3D_NofificationSync(P3D_instance *instance) PPInstance::PPInstance( CP3DActiveXCtrl& parentCtrl ) : m_parentCtrl( parentCtrl ), m_p3dInstance( NULL ), m_p3dObject( NULL ), m_handleRequestOnUIThread( true ), m_isInit( false ) { - // Open the logfile first. - m_logger.Open( ); + // We need the root dir first. + m_rootDir = find_root_dir( ); + + // Then open the logfile. + m_logger.Open( m_rootDir ); - m_rootDir = find_root_dir( nout ); m_pluginLoaded = false; } @@ -177,10 +179,12 @@ int PPInstance::DownloadP3DComponents( std::string& p3dDllFilename ) // file. We get a unique temporary filename each time; this is a // small file and it's very important that we get the most current // version, not an old cached version. - TCHAR tempFolderName[ MAX_PATH ]; - ::GetTempPath( MAX_PATH, tempFolderName ); TCHAR tempFileName[ MAX_PATH ]; - ::GetTempFileName( tempFolderName, "p3d", 0, tempFileName ); + if (!::GetTempFileName( m_rootDir.c_str(), "p3d", 0, tempFileName )) { + nout << "GetTempFileName failed (folder is " << m_rootDir << ")\n"; + return 1; + } + std::string localContentsFileName( tempFileName ); // We'll also get the final installation path of the contents.xml diff --git a/direct/src/plugin_activex/PPLogger.cpp b/direct/src/plugin_activex/PPLogger.cpp index 354d91e48d..a45d27248e 100644 --- a/direct/src/plugin_activex/PPLogger.cpp +++ b/direct/src/plugin_activex/PPLogger.cpp @@ -89,45 +89,51 @@ int PPLogger::CreateNewFile(const std::string& dirname, const std::string& filen return error; } -void PPLogger::Open( ) +void PPLogger::Open( const std::string &rootDir ) { if (!m_isOpen) { // Note that this logfile name may not be specified at runtime. It // must be compiled in if it is specified at all. + std::string log_directory; + // Allow the developer to compile in the log directory. +#ifdef P3D_PLUGIN_LOG_DIRECTORY + if (log_directory.empty()) { + log_directory = P3D_PLUGIN_LOG_DIRECTORY; + } +#endif + + // Failing that, we write logfiles to Panda3D/log. + if (log_directory.empty()) { + log_directory = rootDir + "/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] != '/') { +#ifdef _WIN32 + if (log_directory[log_directory.size() - 1] != '\\') +#endif + log_directory += "/"; + } + + // Construct the logfile pathname. + std::string log_basename; #ifdef P3D_PLUGIN_LOG_BASENAME1 - log_basename = P3D_PLUGIN_LOG_BASENAME1; + if (log_basename.empty()) { + log_basename = P3D_PLUGIN_LOG_BASENAME1; + } #endif if (!log_basename.empty()) { - // Get the log directory. - std::string log_directory; -#ifdef P3D_PLUGIN_LOG_DIRECTORY - log_directory = P3D_PLUGIN_LOG_DIRECTORY; -#endif - if (log_directory.empty()) { - static const size_t buffer_size = MAX_PATH; - char buffer[buffer_size]; - if (GetTempPath(buffer_size, buffer) != 0) { - log_directory = buffer; - } - } - - // Ensure that the log directory ends with a slash. - if (!log_directory.empty() && log_directory[log_directory.size() - 1] != '/') { - if (log_directory[log_directory.size() - 1] != '\\') - log_directory += "/"; - } - - // Construct the full logfile pathname. std::string log_pathname = log_directory; log_pathname += log_basename; log_pathname += ".log"; - + m_logfile.clear(); - m_logfile.open(log_pathname.c_str()); - m_logfile.setf(std::ios::unitbuf); + m_logfile.open(log_pathname.c_str(), ios::out | ios::trunc); + m_logfile.setf(ios::unitbuf); } // If we didn't have a logfile name compiled in, we throw away log diff --git a/direct/src/plugin_activex/PPLogger.h b/direct/src/plugin_activex/PPLogger.h index f66a3b3f81..34cb810096 100644 --- a/direct/src/plugin_activex/PPLogger.h +++ b/direct/src/plugin_activex/PPLogger.h @@ -26,7 +26,7 @@ public: PPLogger( ); virtual ~PPLogger( ); - void Open( ); + void Open( const std::string &rootDir ); static std::ofstream& Log( ) { return m_logfile; } protected: diff --git a/direct/src/plugin_installer/p3d_installer.nsi b/direct/src/plugin_installer/p3d_installer.nsi index e24f107054..956bac06bd 100755 --- a/direct/src/plugin_installer/p3d_installer.nsi +++ b/direct/src/plugin_installer/p3d_installer.nsi @@ -219,7 +219,7 @@ Mozilla-Uninstall-End: # contents are installed. Too bad we can't do this for every system # user, not just the current user. - RmDir /r "$LOCALAPPDATA\Low\${APP_INTERNAL_NAME}" + RmDir /r "$LOCALAPPDATALow\${APP_INTERNAL_NAME}" RmDir /r "$LOCALAPPDATA\${APP_INTERNAL_NAME}" Delete "$INSTDIR\uninst.exe" diff --git a/direct/src/plugin_npapi/startup.cxx b/direct/src/plugin_npapi/startup.cxx index 941ac22efd..06b48f26ea 100644 --- a/direct/src/plugin_npapi/startup.cxx +++ b/direct/src/plugin_npapi/startup.cxx @@ -18,6 +18,7 @@ #include "ppBrowserObject.h" #ifdef _WIN32 +#include #include #endif @@ -28,51 +29,54 @@ string global_root_dir; NPNetscapeFuncs *browser; +// open_logfile() also assigns global_root_dir. static bool logfile_is_open = false; static void open_logfile() { if (!logfile_is_open) { + global_root_dir = find_root_dir(); + // Note that this logfile name may not be specified at runtime. It // must be compiled in if it is specified at all. + string log_directory; + // Allow the developer to compile in the log directory. +#ifdef P3D_PLUGIN_LOG_DIRECTORY + if (log_directory.empty()) { + log_directory = P3D_PLUGIN_LOG_DIRECTORY; + } +#endif + + // Failing that, we write logfiles to Panda3D/log. + if (log_directory.empty()) { + log_directory = global_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] != '/') { +#ifdef _WIN32 + if (log_directory[log_directory.size() - 1] != '\\') +#endif + log_directory += "/"; + } + + // Construct the logfile pathname. + string log_basename; #ifdef P3D_PLUGIN_LOG_BASENAME1 - log_basename = P3D_PLUGIN_LOG_BASENAME1; + if (log_basename.empty()) { + log_basename = P3D_PLUGIN_LOG_BASENAME1; + } #endif if (!log_basename.empty()) { - // Get the log directory. - string log_directory; -#ifdef P3D_PLUGIN_LOG_DIRECTORY - log_directory = P3D_PLUGIN_LOG_DIRECTORY; -#endif - if (log_directory.empty()) { -#ifdef _WIN32 - static const size_t buffer_size = MAX_PATH; - char buffer[buffer_size]; - if (GetTempPath(buffer_size, buffer) != 0) { - log_directory = buffer; - } -#else - log_directory = "/tmp/"; -#endif // _WIN32 - } - - // Ensure that the log directory ends with a slash. - if (!log_directory.empty() && log_directory[log_directory.size() - 1] != '/') { -#ifdef _WIN32 - if (log_directory[log_directory.size() - 1] != '\\') -#endif - log_directory += "/"; - } - - // Construct the full logfile pathname. string log_pathname = log_directory; log_pathname += log_basename; log_pathname += ".log"; - + logfile.clear(); - logfile.open(log_pathname.c_str()); + logfile.open(log_pathname.c_str(), ios::out | ios::trunc); logfile.setf(ios::unitbuf); } @@ -146,9 +150,9 @@ NP_Initialize(NPNetscapeFuncs *browserFuncs, // save away browser functions browser = browserFuncs; + // open_logfile() also assigns global_root_dir. open_logfile(); nout << "initializing\n"; - global_root_dir = find_root_dir(nout); nout << "browserFuncs = " << browserFuncs << "\n"; @@ -173,6 +177,7 @@ NP_Initialize(NPNetscapeFuncs *browserFuncs, //////////////////////////////////////////////////////////////////// NPError OSCALL NP_GetEntryPoints(NPPluginFuncs *pluginFuncs) { + // open_logfile() also assigns global_root_dir. open_logfile(); nout << "NP_GetEntryPoints, pluginFuncs = " << pluginFuncs << "\n"; pluginFuncs->version = 11; diff --git a/direct/src/plugin_standalone/panda3d.cxx b/direct/src/plugin_standalone/panda3d.cxx index f7286b5c58..2f83ddeb00 100644 --- a/direct/src/plugin_standalone/panda3d.cxx +++ b/direct/src/plugin_standalone/panda3d.cxx @@ -49,8 +49,9 @@ static const double wait_cycle = 0.2; //////////////////////////////////////////////////////////////////// Panda3D:: Panda3D() { - _root_dir = find_root_dir(nout); + _root_dir = find_root_dir(); _reporting_download = false; + _enable_security = false; } //////////////////////////////////////////////////////////////////// @@ -67,7 +68,7 @@ run(int argc, char *argv[]) { // We prefix a "+" sign to tell gnu getopt not to parse options // following the first not-option parameter. (These will be passed // into the sub-process.) - const char *optstr = "+mu:M:p:fw:t:s:o:l:ih"; + const char *optstr = "+mu:M:Sp:fw:t:s:o:l:ih"; bool allow_multiple = false; string download_url = PANDA_PACKAGE_HOST_URL; @@ -95,6 +96,10 @@ run(int argc, char *argv[]) { super_mirror_url = optarg; break; + case 'S': + _enable_security = true; + break; + case 'p': this_platform = optarg; break; @@ -542,9 +547,11 @@ get_core_api(const Filename &contents_filename, const string &download_url, } #endif // P3D_PLUGIN_P3D_PLUGIN + bool trusted_environment = !_enable_security; + if (!load_plugin(pathname, contents_filename.to_os_specific(), download_url, verify_contents, this_platform, _log_dirname, - _log_basename, true, cerr)) { + _log_basename, trusted_environment, cerr)) { cerr << "Unable to launch core API in " << pathname << "\n" << flush; return false; } @@ -855,6 +862,10 @@ usage() { << " Python files within the p3d file, for rapid iteration on the Python\n" << " code.\n\n" + << " -S\n" + << " Runs the application with security enabled, as if it were embedded in\n" + << " a web page.\n\n" + << " -u url\n" << " Specify the URL of the Panda3D download server. This is the host\n" diff --git a/direct/src/plugin_standalone/panda3d.h b/direct/src/plugin_standalone/panda3d.h index 4a3242453f..302daa7f18 100755 --- a/direct/src/plugin_standalone/panda3d.h +++ b/direct/src/plugin_standalone/panda3d.h @@ -81,6 +81,7 @@ private: string _log_basename; FileSpec _core_api_dll; bool _reporting_download; + bool _enable_security; typedef pset Instances; Instances _instances;