diff options
Diffstat (limited to 'indra/llvfs')
-rw-r--r-- | indra/llvfs/CMakeLists.txt | 83 | ||||
-rw-r--r-- | indra/llvfs/lldir.cpp | 376 | ||||
-rw-r--r-- | indra/llvfs/lldir.h | 131 | ||||
-rw-r--r-- | indra/llvfs/lldir_linux.cpp | 105 | ||||
-rw-r--r-- | indra/llvfs/lldir_linux.h | 43 | ||||
-rw-r--r-- | indra/llvfs/lldir_mac.cpp | 102 | ||||
-rw-r--r-- | indra/llvfs/lldir_mac.h | 43 | ||||
-rw-r--r-- | indra/llvfs/lldir_solaris.cpp | 125 | ||||
-rw-r--r-- | indra/llvfs/lldir_solaris.h | 40 | ||||
-rw-r--r-- | indra/llvfs/lldir_win32.cpp | 126 | ||||
-rw-r--r-- | indra/llvfs/lldir_win32.h | 43 | ||||
-rw-r--r-- | indra/llvfs/lldirguard.h | 72 | ||||
-rw-r--r-- | indra/llvfs/lllfsthread.cpp | 69 | ||||
-rw-r--r-- | indra/llvfs/lllfsthread.h | 47 | ||||
-rw-r--r-- | indra/llvfs/llpidlock.cpp | 276 | ||||
-rw-r--r-- | indra/llvfs/llpidlock.h | 59 | ||||
-rw-r--r-- | indra/llvfs/llvfile.cpp | 42 | ||||
-rw-r--r-- | indra/llvfs/llvfile.h | 36 | ||||
-rw-r--r-- | indra/llvfs/llvfs.cpp | 389 | ||||
-rw-r--r-- | indra/llvfs/llvfs.h | 63 | ||||
-rw-r--r-- | indra/llvfs/llvfsthread.cpp | 36 | ||||
-rw-r--r-- | indra/llvfs/llvfsthread.h | 41 | ||||
-rw-r--r-- | indra/llvfs/tests/lldir_test.cpp | 260 |
23 files changed, 1833 insertions, 774 deletions
diff --git a/indra/llvfs/CMakeLists.txt b/indra/llvfs/CMakeLists.txt new file mode 100644 index 0000000000..722f4e2bfd --- /dev/null +++ b/indra/llvfs/CMakeLists.txt @@ -0,0 +1,83 @@ +# -*- cmake -*- + +project(llvfs) + +include(00-Common) +include(LLCommon) +include(UnixInstall) + +include_directories( + ${LLCOMMON_INCLUDE_DIRS} + ) + +set(llvfs_SOURCE_FILES + lldir.cpp + lllfsthread.cpp + llpidlock.cpp + llvfile.cpp + llvfs.cpp + llvfsthread.cpp + ) + +set(llvfs_HEADER_FILES + CMakeLists.txt + + lldir.h + lldirguard.h + lllfsthread.h + llpidlock.h + llvfile.h + llvfs.h + llvfsthread.h + ) + +if (DARWIN) + LIST(APPEND llvfs_SOURCE_FILES lldir_mac.cpp) + LIST(APPEND llvfs_HEADER_FILES lldir_mac.h) +endif (DARWIN) + +if (LINUX) + LIST(APPEND llvfs_SOURCE_FILES lldir_linux.cpp) + LIST(APPEND llvfs_HEADER_FILES lldir_linux.h) + + if (VIEWER AND INSTALL) + set_source_files_properties(lldir_linux.cpp + PROPERTIES COMPILE_FLAGS + "-DAPP_RO_DATA_DIR=\\\"${APP_SHARE_DIR}\\\"" + ) + endif (VIEWER AND INSTALL) +endif (LINUX) + +if (WINDOWS) + LIST(APPEND llvfs_SOURCE_FILES lldir_win32.cpp) + LIST(APPEND llvfs_HEADER_FILES lldir_win32.h) +endif (WINDOWS) + +set_source_files_properties(${llvfs_HEADER_FILES} + PROPERTIES HEADER_FILE_ONLY TRUE) + +list(APPEND llvfs_SOURCE_FILES ${llvfs_HEADER_FILES}) + +add_library (llvfs ${llvfs_SOURCE_FILES}) + +if (DARWIN) + include(CMakeFindFrameworks) + find_library(CARBON_LIBRARY Carbon) + target_link_libraries(llvfs ${CARBON_LIBRARY}) +endif (DARWIN) + + +if(LL_TESTS) + # Add tests + include(LLAddBuildTest) + # UNIT TESTS + SET(llvfs_TEST_SOURCE_FILES + # none so far + ) + LL_ADD_PROJECT_UNIT_TESTS(llvfs "${llvfs_TEST_SOURCE_FILES}") + + # INTEGRATION TESTS + set(test_libs llmath llcommon llvfs ${LLCOMMON_LIBRARIES} ${WINDOWS_LIBRARIES}) + # TODO: Some of these need refactoring to be proper Unit tests rather than Integration tests. + LL_ADD_INTEGRATION_TEST(lldir "" "${test_libs}") +endif(LL_TESTS) diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index ae35b656d6..938fb008c9 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -2,30 +2,25 @@ * @file lldir.cpp * @brief implementation of directory utilities base class * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,7 +35,9 @@ #endif #include "lldir.h" + #include "llerror.h" +#include "lltimer.h" // ms_sleep() #include "lluuid.h" #if LL_WINDOWS @@ -68,9 +65,10 @@ LLDir::LLDir() mOSUserDir(""), mOSUserAppDir(""), mLindenUserDir(""), + mOSCacheDir(""), mCAFile(""), mTempDir(""), - mDirDelimiter("") + mDirDelimiter("/") // fallback to forward slash if not overridden { } @@ -87,20 +85,21 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) S32 result; while (getNextFileInDir(dirname, mask, filename, FALSE)) { - if ((filename == ".") || (filename == "..")) + fullpath = dirname; + fullpath += getDirDelimiter(); + fullpath += filename; + + if(LLFile::isdir(fullpath)) { // skipping directory traversal filenames count++; continue; } - fullpath = dirname; - fullpath += getDirDelimiter(); - fullpath += filename; S32 retry_count = 0; while (retry_count < 5) { - if (0 != LLFile::remove(fullpath.c_str())) + if (0 != LLFile::remove(fullpath)) { result = errno; llwarns << "Problem removing " << fullpath << " - errorcode: " @@ -123,16 +122,20 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) } const std::string LLDir::findFile(const std::string &filename, - const std::string searchPath1, - const std::string searchPath2, - const std::string searchPath3) + const std::string& searchPath1, + const std::string& searchPath2, + const std::string& searchPath3) const { std::vector<std::string> search_paths; search_paths.push_back(searchPath1); search_paths.push_back(searchPath2); search_paths.push_back(searchPath3); + return findFile(filename, search_paths); +} - std::vector<std::string>::iterator search_path_iter; +const std::string LLDir::findFile(const std::string& filename, const std::vector<std::string> search_paths) const +{ + std::vector<std::string>::const_iterator search_path_iter; for (search_path_iter = search_paths.begin(); search_path_iter != search_paths.end(); ++search_path_iter) @@ -192,6 +195,11 @@ const std::string &LLDir::getOSUserAppDir() const const std::string &LLDir::getLindenUserDir() const { + if (mLindenUserDir.empty()) + { + lldebugs << "getLindenUserDir() called early, we don't have the user name yet - returning empty string to caller" << llendl; + } + return mLindenUserDir; } @@ -214,7 +222,26 @@ const std::string LLDir::getCacheDir(bool get_default) const { if (mCacheDir.empty() || get_default) { - std::string res; + if (!mDefaultCacheDir.empty()) + { // Set at startup - can't set here due to const API + return mDefaultCacheDir; + } + + std::string res = buildSLOSCacheDir(); + return res; + } + else + { + return mCacheDir; + } +} + +// Return the default cache directory +std::string LLDir::buildSLOSCacheDir() const +{ + std::string res; + if (getOSCacheDir().empty()) + { if (getOSUserAppDir().empty()) { res = "data"; @@ -223,14 +250,22 @@ const std::string LLDir::getCacheDir(bool get_default) const { res = getOSUserAppDir() + mDirDelimiter + "cache"; } - return res; } else { - return mCacheDir; + res = getOSCacheDir() + mDirDelimiter + "SecondLife"; } + return res; } + + +const std::string &LLDir::getOSCacheDir() const +{ + return mOSCacheDir; +} + + const std::string &LLDir::getCAFile() const { return mCAFile; @@ -246,12 +281,37 @@ const std::string &LLDir::getSkinDir() const return mSkinDir; } +const std::string &LLDir::getUserSkinDir() const +{ + return mUserSkinDir; +} + +const std::string& LLDir::getDefaultSkinDir() const +{ + return mDefaultSkinDir; +} + +const std::string LLDir::getSkinBaseDir() const +{ + return mSkinBaseDir; +} + +const std::string &LLDir::getLLPluginDir() const +{ + return mLLPluginDir; +} + std::string LLDir::getExpandedFilename(ELLPath location, const std::string& filename) const { return getExpandedFilename(location, "", filename); } -std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subdir, const std::string& in_filename) const +std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subdir, const std::string& filename) const +{ + return getExpandedFilename(location, "", subdir, filename); +} + +std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subdir1, const std::string& subdir2, const std::string& in_filename) const { std::string prefix; switch (location) @@ -265,25 +325,19 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd prefix += mDirDelimiter; prefix += "app_settings"; break; - + case LL_PATH_CHARACTER: prefix = getAppRODataDir(); prefix += mDirDelimiter; prefix += "character"; break; - case LL_PATH_MOTIONS: - prefix = getAppRODataDir(); - prefix += mDirDelimiter; - prefix += "motions"; - break; - case LL_PATH_HELP: prefix = "help"; break; case LL_PATH_CACHE: - prefix = getCacheDir(); + prefix = getCacheDir(); break; case LL_PATH_USER_SETTINGS: @@ -294,6 +348,11 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd case LL_PATH_PER_SL_ACCOUNT: prefix = getLindenUserDir(); + if (prefix.empty()) + { + // if we're asking for the per-SL-account directory but we haven't logged in yet (or otherwise don't know the account name from which to build this string), then intentionally return a blank string to the caller and skip the below warning about a blank prefix. + return std::string(); + } break; case LL_PATH_CHAT_LOGS: @@ -318,24 +377,36 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd prefix = getSkinDir(); break; - case LL_PATH_SKINS: - prefix = getAppRODataDir(); + case LL_PATH_DEFAULT_SKIN: + prefix = getDefaultSkinDir(); + break; + + case LL_PATH_USER_SKIN: + prefix = getOSUserAppDir(); + prefix += mDirDelimiter; + prefix += "user_settings"; prefix += mDirDelimiter; prefix += "skins"; break; - case LL_PATH_HTML: + case LL_PATH_SKINS: + prefix = getSkinBaseDir(); + break; + + case LL_PATH_LOCAL_ASSETS: prefix = getAppRODataDir(); prefix += mDirDelimiter; - prefix += "skins"; - prefix += mDirDelimiter; - prefix += "html"; + prefix += "local_assets"; break; - case LL_PATH_MOZILLA_PROFILE: - prefix = getOSUserAppDir(); + case LL_PATH_EXECUTABLE: + prefix = getExecutableDir(); + break; + + case LL_PATH_FONTS: + prefix = getAppRODataDir(); prefix += mDirDelimiter; - prefix += "browser_profile"; + prefix += "fonts"; break; default: @@ -343,13 +414,19 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd } std::string filename = in_filename; - if (!subdir.empty()) + if (!subdir2.empty()) { - filename = subdir + mDirDelimiter + in_filename; + filename = subdir2 + mDirDelimiter + filename; } - else + + if (!subdir1.empty()) { - filename = in_filename; + filename = subdir1 + mDirDelimiter + filename; + } + + if (prefix.empty()) + { + llwarns << "prefix is empty, possible bad filename" << llendl; } std::string expanded_filename; @@ -376,15 +453,77 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd expanded_filename.assign(""); } - //llinfos << "*** EXPANDED FILENAME: <" << mExpandedFilename << ">" << llendl; - + //llinfos << "*** EXPANDED FILENAME: <" << expanded_filename << ">" << llendl; return expanded_filename; } +std::string LLDir::getBaseFileName(const std::string& filepath, bool strip_exten) const +{ + std::size_t offset = filepath.find_last_of(getDirDelimiter()); + offset = (offset == std::string::npos) ? 0 : offset+1; + std::string res = filepath.substr(offset, std::string::npos); + if (strip_exten) + { + offset = res.find_last_of('.'); + if (offset != std::string::npos && + offset != 0) // if basename STARTS with '.', don't strip + { + res = res.substr(0, offset); + } + } + return res; +} + +std::string LLDir::getDirName(const std::string& filepath) const +{ + std::size_t offset = filepath.find_last_of(getDirDelimiter()); + S32 len = (offset == std::string::npos) ? 0 : offset; + std::string dirname = filepath.substr(0, len); + return dirname; +} + +std::string LLDir::getExtension(const std::string& filepath) const +{ + if (filepath.empty()) + return std::string(); + std::string basename = getBaseFileName(filepath, false); + std::size_t offset = basename.find_last_of('.'); + std::string exten = (offset == std::string::npos || offset == 0) ? "" : basename.substr(offset+1); + LLStringUtil::toLower(exten); + return exten; +} + +std::string LLDir::findSkinnedFilename(const std::string &filename) const +{ + return findSkinnedFilename("", "", filename); +} + +std::string LLDir::findSkinnedFilename(const std::string &subdir, const std::string &filename) const +{ + return findSkinnedFilename("", subdir, filename); +} + +std::string LLDir::findSkinnedFilename(const std::string &subdir1, const std::string &subdir2, const std::string &filename) const +{ + // generate subdirectory path fragment, e.g. "/foo/bar", "/foo", "" + std::string subdirs = ((subdir1.empty() ? "" : mDirDelimiter) + subdir1) + + ((subdir2.empty() ? "" : mDirDelimiter) + subdir2); + + std::vector<std::string> search_paths; + + search_paths.push_back(getUserSkinDir() + subdirs); // first look in user skin override + search_paths.push_back(getSkinDir() + subdirs); // then in current skin + search_paths.push_back(getDefaultSkinDir() + subdirs); // then default skin + search_paths.push_back(getCacheDir() + subdirs); // and last in preload directory + + std::string found_file = findFile(filename, search_paths); + return found_file; +} + std::string LLDir::getTempFilename() const { LLUUID random_uuid; - char uuid_str[64]; /* Flawfinder: ignore */ + std::string uuid_str; random_uuid.generate(); random_uuid.toString(uuid_str); @@ -397,26 +536,46 @@ std::string LLDir::getTempFilename() const return temp_filename; } -void LLDir::setLindenUserDir(const std::string &first, const std::string &last) +// static +std::string LLDir::getScrubbedFileName(const std::string uncleanFileName) { - // if both first and last aren't set, assume we're grabbing the cached dir - if (!first.empty() && !last.empty()) + std::string name(uncleanFileName); + const std::string illegalChars(getForbiddenFileChars()); + // replace any illegal file chars with and underscore '_' + for( unsigned int i = 0; i < illegalChars.length(); i++ ) + { + int j = -1; + while((j = name.find(illegalChars[i])) > -1) + { + name[j] = '_'; + } + } + return name; +} + +// static +std::string LLDir::getForbiddenFileChars() +{ + return "\\/:*?\"<>|"; +} + +void LLDir::setLindenUserDir(const std::string &username) +{ + // if the username isn't set, that's bad + if (!username.empty()) { // some platforms have case-sensitive filesystems, so be // utterly consistent with our firstname/lastname case. - LLString firstlower(first); - LLString::toLower(firstlower); - LLString lastlower(last); - LLString::toLower(lastlower); + std::string userlower(username); + LLStringUtil::toLower(userlower); + LLStringUtil::replaceChar(userlower, ' ', '_'); mLindenUserDir = getOSUserAppDir(); mLindenUserDir += mDirDelimiter; - mLindenUserDir += firstlower.c_str(); - mLindenUserDir += "_"; - mLindenUserDir += lastlower.c_str(); + mLindenUserDir += userlower; } else { - llerrs << "Invalid name for LLDir::setLindenUserDir" << llendl; + llerrs << "NULL name for LLDir::setLindenUserDir" << llendl; } dumpCurrentDirectories(); @@ -434,36 +593,46 @@ void LLDir::setChatLogsDir(const std::string &path) } } -void LLDir::setPerAccountChatLogsDir(const std::string &first, const std::string &last) +void LLDir::setPerAccountChatLogsDir(const std::string &username) { // if both first and last aren't set, assume we're grabbing the cached dir - if (!first.empty() && !last.empty()) + if (!username.empty()) { // some platforms have case-sensitive filesystems, so be // utterly consistent with our firstname/lastname case. - LLString firstlower(first); - LLString::toLower(firstlower); - LLString lastlower(last); - LLString::toLower(lastlower); + std::string userlower(username); + LLStringUtil::toLower(userlower); + LLStringUtil::replaceChar(userlower, ' ', '_'); mPerAccountChatLogsDir = getChatLogsDir(); mPerAccountChatLogsDir += mDirDelimiter; - mPerAccountChatLogsDir += firstlower.c_str(); - mPerAccountChatLogsDir += "_"; - mPerAccountChatLogsDir += lastlower.c_str(); + mPerAccountChatLogsDir += userlower; } else { - llwarns << "Invalid name for LLDir::setPerAccountChatLogsDir" << llendl; + llerrs << "NULL name for LLDir::setPerAccountChatLogsDir" << llendl; } + } void LLDir::setSkinFolder(const std::string &skin_folder) { - mSkinDir = getAppRODataDir(); - mSkinDir += mDirDelimiter; - mSkinDir += "skins"; + mSkinDir = getSkinBaseDir(); mSkinDir += mDirDelimiter; mSkinDir += skin_folder; + + // user modifications to current skin + // e.g. c:\documents and settings\users\username\application data\second life\skins\dazzle + mUserSkinDir = getOSUserAppDir(); + mUserSkinDir += mDirDelimiter; + mUserSkinDir += "skins"; + mUserSkinDir += mDirDelimiter; + mUserSkinDir += skin_folder; + + // base skin which is used as fallback for all skinned files + // e.g. c:\program files\secondlife\skins\default + mDefaultSkinDir = getSkinBaseDir(); + mDefaultSkinDir += mDirDelimiter; + mDefaultSkinDir += "default"; } bool LLDir::setCacheDir(const std::string &path) @@ -476,13 +645,13 @@ bool LLDir::setCacheDir(const std::string &path) } else { - LLFile::mkdir(path.c_str()); + LLFile::mkdir(path); std::string tempname = path + mDirDelimiter + "temp"; - LLFILE* file = LLFile::fopen(tempname.c_str(),"wt"); + LLFILE* file = LLFile::fopen(tempname,"wt"); if (file) { fclose(file); - LLFile::remove(tempname.c_str()); + LLFile::remove(tempname); mCacheDir = path; return true; } @@ -492,21 +661,22 @@ bool LLDir::setCacheDir(const std::string &path) void LLDir::dumpCurrentDirectories() { - llinfos << "Current Directories:" << llendl; - - llinfos << " CurPath: " << getCurPath() << llendl; - llinfos << " AppName: " << getAppName() << llendl; - llinfos << " ExecutableFilename: " << getExecutableFilename() << llendl; - llinfos << " ExecutableDir: " << getExecutableDir() << llendl; - llinfos << " ExecutablePathAndName: " << getExecutablePathAndName() << llendl; - llinfos << " WorkingDir: " << getWorkingDir() << llendl; - llinfos << " AppRODataDir: " << getAppRODataDir() << llendl; - llinfos << " OSUserDir: " << getOSUserDir() << llendl; - llinfos << " OSUserAppDir: " << getOSUserAppDir() << llendl; - llinfos << " LindenUserDir: " << getLindenUserDir() << llendl; - llinfos << " TempDir: " << getTempDir() << llendl; - llinfos << " CAFile: " << getCAFile() << llendl; - llinfos << " SkinDir: " << getSkinDir() << llendl; + LL_DEBUGS2("AppInit","Directories") << "Current Directories:" << LL_ENDL; + + LL_DEBUGS2("AppInit","Directories") << " CurPath: " << getCurPath() << LL_ENDL; + LL_DEBUGS2("AppInit","Directories") << " AppName: " << getAppName() << LL_ENDL; + LL_DEBUGS2("AppInit","Directories") << " ExecutableFilename: " << getExecutableFilename() << LL_ENDL; + LL_DEBUGS2("AppInit","Directories") << " ExecutableDir: " << getExecutableDir() << LL_ENDL; + LL_DEBUGS2("AppInit","Directories") << " ExecutablePathAndName: " << getExecutablePathAndName() << LL_ENDL; + LL_DEBUGS2("AppInit","Directories") << " WorkingDir: " << getWorkingDir() << LL_ENDL; + LL_DEBUGS2("AppInit","Directories") << " AppRODataDir: " << getAppRODataDir() << LL_ENDL; + LL_DEBUGS2("AppInit","Directories") << " OSUserDir: " << getOSUserDir() << LL_ENDL; + LL_DEBUGS2("AppInit","Directories") << " OSUserAppDir: " << getOSUserAppDir() << LL_ENDL; + LL_DEBUGS2("AppInit","Directories") << " LindenUserDir: " << getLindenUserDir() << LL_ENDL; + LL_DEBUGS2("AppInit","Directories") << " TempDir: " << getTempDir() << LL_ENDL; + LL_DEBUGS2("AppInit","Directories") << " CAFile: " << getCAFile() << LL_ENDL; + LL_DEBUGS2("AppInit","Directories") << " SkinBaseDir: " << getSkinBaseDir() << LL_ENDL; + LL_DEBUGS2("AppInit","Directories") << " SkinDir: " << getSkinDir() << LL_ENDL; } @@ -515,15 +685,15 @@ void dir_exists_or_crash(const std::string &dir_name) #if LL_WINDOWS // *FIX: lame - it doesn't do the same thing on windows. not so // important since we don't deploy simulator to windows boxes. - LLFile::mkdir(dir_name.c_str(), 0700); + LLFile::mkdir(dir_name, 0700); #else struct stat dir_stat; - if(0 != LLFile::stat(dir_name.c_str(), &dir_stat)) + if(0 != LLFile::stat(dir_name, &dir_stat)) { S32 stat_rv = errno; if(ENOENT == stat_rv) { - if(0 != LLFile::mkdir(dir_name.c_str(), 0700)) // octal + if(0 != LLFile::mkdir(dir_name, 0700)) // octal { llerrs << "Unable to create directory: " << dir_name << llendl; } diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h index 4426935e5c..4f63c04aab 100644 --- a/indra/llvfs/lldir.h +++ b/indra/llvfs/lldir.h @@ -2,55 +2,58 @@ * @file lldir.h * @brief Definition of directory utilities class * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #ifndef LL_LLDIR_H #define LL_LLDIR_H +#if LL_SOLARIS +#include <sys/param.h> +#define MAX_PATH MAXPATHLEN +#endif + +// these numbers *may* get serialized (really??), so we need to be explicit typedef enum ELLPath { LL_PATH_NONE = 0, LL_PATH_USER_SETTINGS = 1, LL_PATH_APP_SETTINGS = 2, - LL_PATH_PER_SL_ACCOUNT = 3, + LL_PATH_PER_SL_ACCOUNT = 3, // returns/expands to blank string if we don't know the account name yet LL_PATH_CACHE = 4, LL_PATH_CHARACTER = 5, - LL_PATH_MOTIONS = 6, - LL_PATH_HELP = 7, - LL_PATH_LOGS = 8, - LL_PATH_TEMP = 9, - LL_PATH_SKINS = 10, - LL_PATH_TOP_SKIN = 11, - LL_PATH_CHAT_LOGS = 12, - LL_PATH_PER_ACCOUNT_CHAT_LOGS = 13, - LL_PATH_MOZILLA_PROFILE = 14, - LL_PATH_HTML = 15, - LL_PATH_COUNT = 16 + LL_PATH_HELP = 6, + LL_PATH_LOGS = 7, + LL_PATH_TEMP = 8, + LL_PATH_SKINS = 9, + LL_PATH_TOP_SKIN = 10, + LL_PATH_CHAT_LOGS = 11, + LL_PATH_PER_ACCOUNT_CHAT_LOGS = 12, + LL_PATH_USER_SKIN = 14, + LL_PATH_LOCAL_ASSETS = 15, + LL_PATH_EXECUTABLE = 16, + LL_PATH_DEFAULT_SKIN = 17, + LL_PATH_FONTS = 18, + LL_PATH_LAST } ELLPath; @@ -60,18 +63,28 @@ class LLDir LLDir(); virtual ~LLDir(); - virtual void initAppDirs(const std::string &app_name) = 0; - public: - virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask); + // app_name - Usually SecondLife, used for creating settings directories + // in OS-specific location, such as C:\Documents and Settings + // app_read_only_data_dir - Usually the source code directory, used + // for test applications to read newview data files. + virtual void initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir = "") = 0; + + virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask); // pure virtual functions - virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask) = 0; - virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap) = 0; - virtual void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) = 0; + virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask) = 0; + virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap) = 0; + virtual void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) = 0; virtual std::string getCurPath() = 0; - virtual BOOL fileExists(const std::string &filename) = 0; + virtual BOOL fileExists(const std::string &filename) const = 0; + + const std::string findFile(const std::string& filename, const std::vector<std::string> filenames) const; + const std::string findFile(const std::string& filename, const std::string& searchPath1 = "", const std::string& searchPath2 = "", const std::string& searchPath3 = "") const; + + virtual std::string getLLPluginLauncher() = 0; // full path and name for the plugin shell + virtual std::string getLLPluginFilename(std::string base_name) = 0; // full path and name to the plugin DSO for this base_name (i.e. 'FOO' -> '/bar/baz/libFOO.so') - const std::string findFile(const std::string &filename, const std::string searchPath1 = "", const std::string searchPath2 = "", const std::string searchPath3 = ""); const std::string &getExecutablePathAndName() const; // Full pathname of the executable const std::string &getAppName() const; // install directory under progams/ ie "SecondLife" const std::string &getExecutableDir() const; // Directory where the executable is located @@ -85,25 +98,49 @@ class LLDir const std::string &getPerAccountChatLogsDir() const; // Location of the per account chat logs dir. const std::string &getTempDir() const; // Common temporary directory const std::string getCacheDir(bool get_default = false) const; // Location of the cache. + const std::string &getOSCacheDir() const; // location of OS-specific cache folder (may be empty string) const std::string &getCAFile() const; // File containing TLS certificate authorities const std::string &getDirDelimiter() const; // directory separator for platform (ie. '\' or '/' or ':') const std::string &getSkinDir() const; // User-specified skin folder. + const std::string &getUserSkinDir() const; // User-specified skin folder with user modifications. e.g. c:\documents and settings\username\application data\second life\skins\curskin + const std::string &getDefaultSkinDir() const; // folder for default skin. e.g. c:\program files\second life\skins\default + const std::string getSkinBaseDir() const; // folder that contains all installed skins (not user modifications). e.g. c:\program files\second life\skins + const std::string &getLLPluginDir() const; // Directory containing plugins and plugin shell // Expanded filename std::string getExpandedFilename(ELLPath location, const std::string &filename) const; std::string getExpandedFilename(ELLPath location, const std::string &subdir, const std::string &filename) const; + std::string getExpandedFilename(ELLPath location, const std::string &subdir1, const std::string &subdir2, const std::string &filename) const; + + // Base and Directory name extraction + std::string getBaseFileName(const std::string& filepath, bool strip_exten = false) const; + std::string getDirName(const std::string& filepath) const; + std::string getExtension(const std::string& filepath) const; // Excludes '.', e.g getExtension("foo.wav") == "wav" + + // these methods search the various skin paths for the specified file in the following order: + // getUserSkinDir(), getSkinDir(), getDefaultSkinDir() + std::string findSkinnedFilename(const std::string &filename) const; + std::string findSkinnedFilename(const std::string &subdir, const std::string &filename) const; + std::string findSkinnedFilename(const std::string &subdir1, const std::string &subdir2, const std::string &filename) const; // random filename in common temporary directory std::string getTempFilename() const; + // For producing safe download file names from potentially unsafe ones + static std::string getScrubbedFileName(const std::string uncleanFileName); + static std::string getForbiddenFileChars(); + virtual void setChatLogsDir(const std::string &path); // Set the chat logs dir to this user's dir - virtual void setPerAccountChatLogsDir(const std::string &first, const std::string &last); // Set the per user chat log directory. - virtual void setLindenUserDir(const std::string &first, const std::string &last); // Set the linden user dir to this user's dir + virtual void setPerAccountChatLogsDir(const std::string &username); // Set the per user chat log directory. + virtual void setLindenUserDir(const std::string &username); // Set the linden user dir to this user's dir virtual void setSkinFolder(const std::string &skin_folder); virtual bool setCacheDir(const std::string &path); virtual void dumpCurrentDirectories(); + // Utility routine + std::string buildSLOSCacheDir() const; + protected: std::string mAppName; // install directory under progams/ ie "SecondLife" std::string mExecutablePathAndName; // full path + Filename of .exe @@ -118,9 +155,15 @@ protected: std::string mChatLogsDir; // Location for chat logs. std::string mCAFile; // Location of the TLS certificate authority PEM file. std::string mTempDir; - std::string mCacheDir; + std::string mCacheDir; // cache directory as set by user preference + std::string mDefaultCacheDir; // default cache diretory + std::string mOSCacheDir; // operating system cache dir std::string mDirDelimiter; - std::string mSkinDir; // Location for u ser-specified skin info. + std::string mSkinBaseDir; // Base for skins paths. + std::string mSkinDir; // Location for current skin info. + std::string mDefaultSkinDir; // Location for default skin info. + std::string mUserSkinDir; // Location for user-modified skin info. + std::string mLLPluginDir; // Location for plugins and plugin shell }; void dir_exists_or_crash(const std::string &dir_name); diff --git a/indra/llvfs/lldir_linux.cpp b/indra/llvfs/lldir_linux.cpp index 8f9f577804..a1c6669b97 100644 --- a/indra/llvfs/lldir_linux.cpp +++ b/indra/llvfs/lldir_linux.cpp @@ -2,30 +2,25 @@ * @file lldir_linux.cpp * @brief Implementation of directory utilities for linux * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -93,10 +88,28 @@ LLDir_Linux::LLDir_Linux() mExecutablePathAndName = ""; mExecutableDir = tmp_str; mWorkingDir = tmp_str; +#ifdef APP_RO_DATA_DIR + mAppRODataDir = APP_RO_DATA_DIR; +#else mAppRODataDir = tmp_str; +#endif + std::string::size_type indra_pos = mExecutableDir.find("/indra"); + if (indra_pos != std::string::npos) + { + // ...we're in a dev checkout + mSkinBaseDir = mExecutableDir.substr(0, indra_pos) + "/indra/newview/skins"; + llinfos << "Running in dev checkout with mSkinBaseDir " + << mSkinBaseDir << llendl; + } + else + { + // ...normal installation running + mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; + } + mOSUserDir = getCurrentUserHome(tmp_str); mOSUserAppDir = ""; - mLindenUserDir = tmp_str; + mLindenUserDir = ""; char path [32]; /* Flawfinder: ignore */ @@ -123,6 +136,8 @@ LLDir_Linux::LLDir_Linux() } } + mLLPluginDir = mExecutableDir + mDirDelimiter + "llplugin"; + // *TODO: don't use /tmp, use $HOME/.secondlife/tmp or something. mTempDir = "/tmp"; } @@ -134,12 +149,19 @@ LLDir_Linux::~LLDir_Linux() // Implementation -void LLDir_Linux::initAppDirs(const std::string &app_name) +void LLDir_Linux::initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir) { + // Allow override so test apps can read newview directory + if (!app_read_only_data_dir.empty()) + { + mAppRODataDir = app_read_only_data_dir; + mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; + } mAppName = app_name; - LLString upper_app_name(app_name); - LLString::toUpper(upper_app_name); + std::string upper_app_name(app_name); + LLStringUtil::toUpper(upper_app_name); char* app_home_env = getenv((upper_app_name + "_USER_DIR").c_str()); /* Flawfinder: ignore */ if (app_home_env) @@ -153,14 +175,14 @@ void LLDir_Linux::initAppDirs(const std::string &app_name) mOSUserAppDir = mOSUserDir; mOSUserAppDir += "/"; mOSUserAppDir += "."; - LLString lower_app_name(app_name); - LLString::toLower(lower_app_name); + std::string lower_app_name(app_name); + LLStringUtil::toLower(lower_app_name); mOSUserAppDir += lower_app_name; } // create any directories we expect to write to. - int res = LLFile::mkdir(mOSUserAppDir.c_str()); + int res = LLFile::mkdir(mOSUserAppDir); if (res == -1) { if (errno != EEXIST) @@ -171,7 +193,7 @@ void LLDir_Linux::initAppDirs(const std::string &app_name) } } - res = LLFile::mkdir(getExpandedFilename(LL_PATH_LOGS,"").c_str()); + res = LLFile::mkdir(getExpandedFilename(LL_PATH_LOGS,"")); if (res == -1) { if (errno != EEXIST) @@ -180,7 +202,7 @@ void LLDir_Linux::initAppDirs(const std::string &app_name) } } - res = LLFile::mkdir(getExpandedFilename(LL_PATH_USER_SETTINGS,"").c_str()); + res = LLFile::mkdir(getExpandedFilename(LL_PATH_USER_SETTINGS,"")); if (res == -1) { if (errno != EEXIST) @@ -189,7 +211,7 @@ void LLDir_Linux::initAppDirs(const std::string &app_name) } } - res = LLFile::mkdir(getExpandedFilename(LL_PATH_CACHE,"").c_str()); + res = LLFile::mkdir(getExpandedFilename(LL_PATH_CACHE,"")); if (res == -1) { if (errno != EEXIST) @@ -198,15 +220,6 @@ void LLDir_Linux::initAppDirs(const std::string &app_name) } } - res = LLFile::mkdir(getExpandedFilename(LL_PATH_MOZILLA_PROFILE,"").c_str()); - if (res == -1) - { - if (errno != EEXIST) - { - llwarns << "Couldn't create LL_PATH_MOZILLA_PROFILE dir " << getExpandedFilename(LL_PATH_MOZILLA_PROFILE,"") << llendl; - } - } - mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem"); } @@ -349,7 +362,7 @@ std::string LLDir_Linux::getCurPath() } -BOOL LLDir_Linux::fileExists(const std::string &filename) +BOOL LLDir_Linux::fileExists(const std::string &filename) const { struct stat stat_data; // Check the age of the file @@ -365,3 +378,15 @@ BOOL LLDir_Linux::fileExists(const std::string &filename) } } + +/*virtual*/ std::string LLDir_Linux::getLLPluginLauncher() +{ + return gDirUtilp->getExecutableDir() + gDirUtilp->getDirDelimiter() + + "SLPlugin"; +} + +/*virtual*/ std::string LLDir_Linux::getLLPluginFilename(std::string base_name) +{ + return gDirUtilp->getLLPluginDir() + gDirUtilp->getDirDelimiter() + + "lib" + base_name + ".so"; +} diff --git a/indra/llvfs/lldir_linux.h b/indra/llvfs/lldir_linux.h index a81df89807..809959e873 100644 --- a/indra/llvfs/lldir_linux.h +++ b/indra/llvfs/lldir_linux.h @@ -2,30 +2,25 @@ * @file lldir_linux.h * @brief Definition of directory utilities class for linux * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -43,13 +38,17 @@ public: LLDir_Linux(); virtual ~LLDir_Linux(); - virtual void initAppDirs(const std::string &app_name); + /*virtual*/ void initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir); public: virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap); virtual void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); - /*virtual*/ BOOL fileExists(const std::string &filename); + /*virtual*/ BOOL fileExists(const std::string &filename) const; + + /*virtual*/ std::string getLLPluginLauncher(); + /*virtual*/ std::string getLLPluginFilename(std::string base_name); private: DIR *mDirp; diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llvfs/lldir_mac.cpp index 3cf70d76c2..b41b0ec5dd 100644 --- a/indra/llvfs/lldir_mac.cpp +++ b/indra/llvfs/lldir_mac.cpp @@ -2,30 +2,25 @@ * @file lldir_mac.cpp * @brief Implementation of directory utilities for Mac OS X * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -67,7 +62,8 @@ static void CFStringRefToLLString(CFStringRef stringRef, std::string &llString, { if (stringRef) { - long bufferSize = CFStringGetLength(stringRef) + 1; + long stringSize = CFStringGetLength(stringRef) + 1; + long bufferSize = CFStringGetMaximumSizeForEncoding(stringSize,kCFStringEncodingUTF8); char* buffer = new char[bufferSize]; memset(buffer, 0, bufferSize); if (CFStringGetCString(stringRef, buffer, bufferSize, kCFStringEncodingUTF8)) @@ -141,9 +137,34 @@ LLDir_Mac::LLDir_Mac() CFURLRefToLLString(executableParentURLRef, mExecutableDir, true); // mAppRODataDir - CFURLRef resourcesURLRef = CFBundleCopyResourcesDirectoryURL(mainBundleRef); + + + // *NOTE: When running in a dev tree, use the copy of + // skins in indra/newview/ rather than in the application bundle. This + // mirrors Windows dev environment behavior and allows direct checkin + // of edited skins/xui files. JC + + // MBW -- This keeps the mac application from finding other things. + // If this is really for skins, it should JUST apply to skins. + + CFURLRef resourcesURLRef = CFBundleCopyResourcesDirectoryURL(mainBundleRef); CFURLRefToLLString(resourcesURLRef, mAppRODataDir, true); + U32 indra_pos = mExecutableDir.find("/indra"); + if (indra_pos != std::string::npos) + { + // ...we're in a dev checkout + mSkinBaseDir = mExecutableDir.substr(0, indra_pos) + + "/indra/newview/skins"; + llinfos << "Running in dev checkout with mSkinBaseDir " + << mSkinBaseDir << llendl; + } + else + { + // ...normal installation running + mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; + } + // mOSUserDir error = FSFindFolder(kUserDomain, kApplicationSupportFolderType, true, &fileRef); if (error == noErr) @@ -159,13 +180,22 @@ LLDir_Mac::LLDir_Mac() // Create our sub-dirs (void) CFCreateDirectory(&newFileRef, CFSTR("data"), NULL); - (void) CFCreateDirectory(&newFileRef, CFSTR("cache"), NULL); + //(void) CFCreateDirectory(&newFileRef, CFSTR("cache"), NULL); (void) CFCreateDirectory(&newFileRef, CFSTR("logs"), NULL); (void) CFCreateDirectory(&newFileRef, CFSTR("user_settings"), NULL); (void) CFCreateDirectory(&newFileRef, CFSTR("browser_profile"), NULL); } } + //mOSCacheDir + FSRef cacheDirRef; + error = FSFindFolder(kUserDomain, kCachedDataFolderType, true, &cacheDirRef); + if (error == noErr) + { + FSRefToLLString(&cacheDirRef, mOSCacheDir); + (void)CFCreateDirectory(&cacheDirRef, CFSTR("SecondLife"),NULL); + } + // mOSUserAppDir mOSUserAppDir = mOSUserDir; @@ -180,6 +210,8 @@ LLDir_Mac::LLDir_Mac() } mWorkingDir = getCurPath(); + + mLLPluginDir = mAppRODataDir + mDirDelimiter + "llplugin"; CFRelease(executableURLRef); executableURLRef = NULL; @@ -193,8 +225,15 @@ LLDir_Mac::~LLDir_Mac() // Implementation -void LLDir_Mac::initAppDirs(const std::string &app_name) +void LLDir_Mac::initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir) { + // Allow override so test apps can read newview directory + if (!app_read_only_data_dir.empty()) + { + mAppRODataDir = app_read_only_data_dir; + mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; + } mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem"); //dumpCurrentDirectories(); @@ -361,7 +400,7 @@ std::string LLDir_Mac::getCurPath() -BOOL LLDir_Mac::fileExists(const std::string &filename) +BOOL LLDir_Mac::fileExists(const std::string &filename) const { struct stat stat_data; // Check the age of the file @@ -378,4 +417,17 @@ BOOL LLDir_Mac::fileExists(const std::string &filename) } +/*virtual*/ std::string LLDir_Mac::getLLPluginLauncher() +{ + return gDirUtilp->getAppRODataDir() + gDirUtilp->getDirDelimiter() + + "SLPlugin.app/Contents/MacOS/SLPlugin"; +} + +/*virtual*/ std::string LLDir_Mac::getLLPluginFilename(std::string base_name) +{ + return gDirUtilp->getLLPluginDir() + gDirUtilp->getDirDelimiter() + + base_name + ".dylib"; +} + + #endif // LL_DARWIN diff --git a/indra/llvfs/lldir_mac.h b/indra/llvfs/lldir_mac.h index c1244a2fa8..04c52dc940 100644 --- a/indra/llvfs/lldir_mac.h +++ b/indra/llvfs/lldir_mac.h @@ -2,30 +2,25 @@ * @file lldir_mac.h * @brief Definition of directory utilities class for Mac OS X * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -42,14 +37,18 @@ public: LLDir_Mac(); virtual ~LLDir_Mac(); - virtual void initAppDirs(const std::string &app_name); + /*virtual*/ void initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir); public: virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask); virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap); virtual void getRandomFileInDir(const std::string &dirname, const std::string &ask, std::string &fname); - virtual BOOL fileExists(const std::string &filename); + virtual BOOL fileExists(const std::string &filename) const; + + /*virtual*/ std::string getLLPluginLauncher(); + /*virtual*/ std::string getLLPluginFilename(std::string base_name); private: int mCurrentDirIndex; diff --git a/indra/llvfs/lldir_solaris.cpp b/indra/llvfs/lldir_solaris.cpp index b13d3d05ea..4323dfd44a 100644 --- a/indra/llvfs/lldir_solaris.cpp +++ b/indra/llvfs/lldir_solaris.cpp @@ -2,30 +2,25 @@ * @file fmodwrapper.cpp * @brief dummy source file for building a shared library to wrap libfmod.a * - * $LicenseInfo:firstyear=2005&license=viewergpl$ - * - * Copyright (c) 2005-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -36,14 +31,13 @@ #include "llrand.h" #include <sys/types.h> #include <sys/stat.h> -#include <fcntl.h> -#include <sys/param.h> #include <unistd.h> #include <glob.h> #include <pwd.h> #include <sys/utsname.h> #define _STRUCTURED_PROC 1 #include <sys/procfs.h> +#include <fcntl.h> static std::string getCurrentUserHome(char* fallback) { @@ -82,7 +76,16 @@ LLDir_Solaris::LLDir_Solaris() mDirp = NULL; char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */ - getcwd(tmp_str, LL_MAX_PATH); + if (getcwd(tmp_str, LL_MAX_PATH) == NULL) + { + strcpy(tmp_str, "/tmp"); + llwarns << "Could not get current directory; changing to " + << tmp_str << llendl; + if (chdir(tmp_str) == -1) + { + llerrs << "Could not change directory to " << tmp_str << llendl; + } + } mExecutableFilename = ""; mExecutablePathAndName = ""; @@ -91,7 +94,7 @@ LLDir_Solaris::LLDir_Solaris() mAppRODataDir = strdup(tmp_str); mOSUserDir = getCurrentUserHome(tmp_str); mOSUserAppDir = ""; - mLindenUserDir = tmp_str; + mLindenUserDir = ""; char path [LL_MAX_PATH]; /* Flawfinder: ignore */ @@ -121,22 +124,39 @@ LLDir_Solaris::LLDir_Solaris() return; } + char *p = execpath; // nuke trash in link, if any exists + int i = 0; + while(*p != NULL && ++i < LL_MAX_PATH && isprint((int)(*p++))); + *p = NULL; + mExecutablePathAndName = strdup(execpath); llinfos << "mExecutablePathAndName = [" << mExecutablePathAndName << "]" << llendl; + //NOTE: Why force people to cd into the package directory? + // Look for SECONDLIFE env variable and use it, if set. + + char *dcf = getenv("SECONDLIFE"); + if(dcf != NULL){ + (void)strcpy(path, dcf); + (void)strcat(path, "/bin"); //NOTE: make sure we point at the bin + mExecutableDir = strdup(path); + }else{ // plunk a null at last '/' to get exec dir - char *s = execpath + strlen(execpath) -1; - while(*s != '/' && s != execpath){ - --s; - } + char *s = execpath + strlen(execpath) -1; + while(*s != '/' && s != execpath){ + --s; + } - if(s != execpath){ - *s = (char)NULL; + if(s != execpath){ + *s = (char)NULL; - mExecutableDir = strdup(execpath); - llinfos << "mExecutableDir = [" << mExecutableDir << "]" << llendl; + mExecutableDir = strdup(execpath); + llinfos << "mExecutableDir = [" << mExecutableDir << "]" << llendl; + } } + mLLPluginDir = mExecutableDir + mDirDelimiter + "llplugin"; + // *TODO: don't use /tmp, use $HOME/.secondlife/tmp or something. mTempDir = "/tmp"; } @@ -148,12 +168,18 @@ LLDir_Solaris::~LLDir_Solaris() // Implementation -void LLDir_Solaris::initAppDirs(const std::string &app_name) +void LLDir_Solaris::initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir) { + // Allow override so test apps can read newview directory + if (!app_read_only_data_dir.empty()) + { + mAppRODataDir = app_read_only_data_dir; + } mAppName = app_name; - LLString upper_app_name(app_name); - LLString::toUpper(upper_app_name); + std::string upper_app_name(app_name); + LLStringUtil::toUpper(upper_app_name); char* app_home_env = getenv((upper_app_name + "_USER_DIR").c_str()); /* Flawfinder: ignore */ if (app_home_env) @@ -167,14 +193,14 @@ void LLDir_Solaris::initAppDirs(const std::string &app_name) mOSUserAppDir = mOSUserDir; mOSUserAppDir += "/"; mOSUserAppDir += "."; - LLString lower_app_name(app_name); - LLString::toLower(lower_app_name); + std::string lower_app_name(app_name); + LLStringUtil::toLower(lower_app_name); mOSUserAppDir += lower_app_name; } // create any directories we expect to write to. - int res = LLFile::mkdir(mOSUserAppDir.c_str()); + int res = LLFile::mkdir(mOSUserAppDir); if (res == -1) { if (errno != EEXIST) @@ -185,7 +211,7 @@ void LLDir_Solaris::initAppDirs(const std::string &app_name) } } - res = LLFile::mkdir(getExpandedFilename(LL_PATH_LOGS,"").c_str()); + res = LLFile::mkdir(getExpandedFilename(LL_PATH_LOGS,"")); if (res == -1) { if (errno != EEXIST) @@ -194,7 +220,7 @@ void LLDir_Solaris::initAppDirs(const std::string &app_name) } } - res = LLFile::mkdir(getExpandedFilename(LL_PATH_USER_SETTINGS,"").c_str()); + res = LLFile::mkdir(getExpandedFilename(LL_PATH_USER_SETTINGS,"")); if (res == -1) { if (errno != EEXIST) @@ -203,7 +229,7 @@ void LLDir_Solaris::initAppDirs(const std::string &app_name) } } - res = LLFile::mkdir(getExpandedFilename(LL_PATH_CACHE,"").c_str()); + res = LLFile::mkdir(getExpandedFilename(LL_PATH_CACHE,"")); if (res == -1) { if (errno != EEXIST) @@ -212,15 +238,6 @@ void LLDir_Solaris::initAppDirs(const std::string &app_name) } } - res = LLFile::mkdir(getExpandedFilename(LL_PATH_MOZILLA_PROFILE,"").c_str()); - if (res == -1) - { - if (errno != EEXIST) - { - llwarns << "Couldn't create LL_PATH_MOZILLA_PROFILE dir " << getExpandedFilename(LL_PATH_MOZILLA_PROFILE,"") << llendl; - } - } - mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem"); } @@ -354,12 +371,16 @@ void LLDir_Solaris::getRandomFileInDir(const std::string &dirname, const std::st std::string LLDir_Solaris::getCurPath() { char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */ - getcwd(tmp_str, LL_MAX_PATH); + if (getcwd(tmp_str, LL_MAX_PATH) == NULL) + { + llwarns << "Could not get current directory" << llendl; + tmp_str[0] = '\0'; + } return tmp_str; } -BOOL LLDir_Solaris::fileExists(const std::string &filename) +BOOL LLDir_Solaris::fileExists(const std::string &filename) const { struct stat stat_data; // Check the age of the file diff --git a/indra/llvfs/lldir_solaris.h b/indra/llvfs/lldir_solaris.h index 34e7f71dac..6e0c5cfc69 100644 --- a/indra/llvfs/lldir_solaris.h +++ b/indra/llvfs/lldir_solaris.h @@ -2,30 +2,25 @@ * @file fmodwrapper.cpp * @brief dummy source file for building a shared library to wrap libfmod.a * - * $LicenseInfo:firstyear=2005&license=viewergpl$ - * - * Copyright (c) 2005-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2005&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -43,13 +38,14 @@ public: LLDir_Solaris(); virtual ~LLDir_Solaris(); - virtual void initAppDirs(const std::string &app_name); + /*virtual*/ void initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir); public: virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap); virtual void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); - /*virtual*/ BOOL fileExists(const std::string &filename); + /*virtual*/ BOOL fileExists(const std::string &filename) const; private: DIR *mDirp; diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp index f415fe56ed..52d864e26f 100644 --- a/indra/llvfs/lldir_win32.cpp +++ b/indra/llvfs/lldir_win32.cpp @@ -2,30 +2,25 @@ * @file lldir_win32.cpp * @brief Implementation of directory utilities for windows * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -58,14 +53,18 @@ LLDir_Win32::LLDir_Win32() mOSUserDir = utf16str_to_utf8str(llutf16string(w_str)); - // Local Settings\Application Data is where cache files should - // go, they don't get copied to the server if the user moves his - // profile around on the network. JC + // We want cache files to go on the local disk, even if the + // user is on a network with a "roaming profile". + // + // On XP this is: + // C:\Docments and Settings\James\Local Settings\Application Data + // On Vista this is: + // C:\Users\James\AppData\Local // - // TODO: patch the installer to remove old cache files on update, then - // enable this code. - //SHGetSpecialFolderPath(NULL, w_str, CSIDL_LOCAL_APPDATA, TRUE); - //mOSUserCacheDir = utf16str_to_utf8str(llutf16string(w_str)); + // We used to store the cache in AppData\Roaming, and the installer + // cleans up that version on upgrade. JC + SHGetSpecialFolderPath(NULL, w_str, CSIDL_LOCAL_APPDATA, TRUE); + mOSCacheDir = utf16str_to_utf8str(llutf16string(w_str)); if (GetTempPath(MAX_PATH, w_str)) { @@ -116,10 +115,36 @@ LLDir_Win32::LLDir_Win32() GetCurrentDirectory(MAX_PATH, w_str); mExecutableDir = utf16str_to_utf8str(llutf16string(w_str)); #endif - if (strstr(mExecutableDir.c_str(), "indra\\newview")) - mAppRODataDir = getCurPath(); - else - mAppRODataDir = mExecutableDir; + + if (mExecutableDir.find("indra") == std::string::npos) + { + // Running from installed directory. Make sure current + // directory isn't something crazy (e.g. if invoking from + // command line). + SetCurrentDirectory(utf8str_to_utf16str(mExecutableDir).c_str()); + GetCurrentDirectory(MAX_PATH, w_str); + mWorkingDir = utf16str_to_utf8str(llutf16string(w_str)); + } + mAppRODataDir = mWorkingDir; + + llinfos << "mAppRODataDir = " << mAppRODataDir << llendl; + + mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; + + // Build the default cache directory + mDefaultCacheDir = buildSLOSCacheDir(); + + // Make sure it exists + int res = LLFile::mkdir(mDefaultCacheDir); + if (res == -1) + { + if (errno != EEXIST) + { + llwarns << "Couldn't create LL_PATH_CACHE dir " << mDefaultCacheDir << llendl; + } + } + + mLLPluginDir = mExecutableDir + mDirDelimiter + "llplugin"; } LLDir_Win32::~LLDir_Win32() @@ -128,14 +153,21 @@ LLDir_Win32::~LLDir_Win32() // Implementation -void LLDir_Win32::initAppDirs(const std::string &app_name) +void LLDir_Win32::initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir) { + // Allow override so test apps can read newview directory + if (!app_read_only_data_dir.empty()) + { + mAppRODataDir = app_read_only_data_dir; + mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; + } mAppName = app_name; mOSUserAppDir = mOSUserDir; mOSUserAppDir += "\\"; mOSUserAppDir += app_name; - int res = LLFile::mkdir(mOSUserAppDir.c_str()); + int res = LLFile::mkdir(mOSUserAppDir); if (res == -1) { if (errno != EEXIST) @@ -147,7 +179,7 @@ void LLDir_Win32::initAppDirs(const std::string &app_name) } //dumpCurrentDirectories(); - res = LLFile::mkdir(getExpandedFilename(LL_PATH_LOGS,"").c_str()); + res = LLFile::mkdir(getExpandedFilename(LL_PATH_LOGS,"")); if (res == -1) { if (errno != EEXIST) @@ -156,7 +188,7 @@ void LLDir_Win32::initAppDirs(const std::string &app_name) } } - res = LLFile::mkdir(getExpandedFilename(LL_PATH_USER_SETTINGS,"").c_str()); + res = LLFile::mkdir(getExpandedFilename(LL_PATH_USER_SETTINGS,"")); if (res == -1) { if (errno != EEXIST) @@ -165,7 +197,7 @@ void LLDir_Win32::initAppDirs(const std::string &app_name) } } - res = LLFile::mkdir(getExpandedFilename(LL_PATH_CACHE,"").c_str()); + res = LLFile::mkdir(getExpandedFilename(LL_PATH_CACHE,"")); if (res == -1) { if (errno != EEXIST) @@ -174,15 +206,14 @@ void LLDir_Win32::initAppDirs(const std::string &app_name) } } - res = LLFile::mkdir(getExpandedFilename(LL_PATH_MOZILLA_PROFILE,"").c_str()); + res = LLFile::mkdir(getExpandedFilename(LL_PATH_USER_SKIN,"")); if (res == -1) { if (errno != EEXIST) { - llwarns << "Couldn't create LL_PATH_MOZILLA_PROFILE dir " << getExpandedFilename(LL_PATH_MOZILLA_PROFILE,"") << llendl; + llwarns << "Couldn't create LL_PATH_SKINS dir " << getExpandedFilename(LL_PATH_USER_SKIN,"") << llendl; } } - mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem"); } @@ -338,12 +369,12 @@ std::string LLDir_Win32::getCurPath() } -BOOL LLDir_Win32::fileExists(const std::string &filename) +BOOL LLDir_Win32::fileExists(const std::string &filename) const { llstat stat_data; // Check the age of the file // Now, we see if the files we've gathered are recent... - int res = LLFile::stat(filename.c_str(), &stat_data); + int res = LLFile::stat(filename, &stat_data); if (!res) { return TRUE; @@ -355,6 +386,19 @@ BOOL LLDir_Win32::fileExists(const std::string &filename) } +/*virtual*/ std::string LLDir_Win32::getLLPluginLauncher() +{ + return gDirUtilp->getExecutableDir() + gDirUtilp->getDirDelimiter() + + "SLPlugin.exe"; +} + +/*virtual*/ std::string LLDir_Win32::getLLPluginFilename(std::string base_name) +{ + return gDirUtilp->getLLPluginDir() + gDirUtilp->getDirDelimiter() + + base_name + ".dll"; +} + + #if 0 // Utility function to get version number of a DLL diff --git a/indra/llvfs/lldir_win32.h b/indra/llvfs/lldir_win32.h index bddf17503b..d3e45dc1f3 100644 --- a/indra/llvfs/lldir_win32.h +++ b/indra/llvfs/lldir_win32.h @@ -2,30 +2,25 @@ * @file lldir_win32.h * @brief Definition of directory utilities class for windows * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -40,13 +35,17 @@ public: LLDir_Win32(); virtual ~LLDir_Win32(); - /*virtual*/ void initAppDirs(const std::string &app_name); + /*virtual*/ void initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir); /*virtual*/ std::string getCurPath(); /*virtual*/ U32 countFilesInDir(const std::string &dirname, const std::string &mask); /*virtual*/ BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap); /*virtual*/ void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); - /*virtual*/ BOOL fileExists(const std::string &filename); + /*virtual*/ BOOL fileExists(const std::string &filename) const; + + /*virtual*/ std::string getLLPluginLauncher(); + /*virtual*/ std::string getLLPluginFilename(std::string base_name); private: BOOL LLDir_Win32::getNextFileInDir(const llutf16string &dirname, const std::string &mask, std::string &fname, BOOL wrap); diff --git a/indra/llvfs/lldirguard.h b/indra/llvfs/lldirguard.h new file mode 100644 index 0000000000..4330095ad0 --- /dev/null +++ b/indra/llvfs/lldirguard.h @@ -0,0 +1,72 @@ +/** + * @file lldirguard.h + * @brief Protect working directory from being changed in scope. + * + * $LicenseInfo:firstyear=2009&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_DIRGUARD_H +#define LL_DIRGUARD_H + +#include "linden_common.h" +#include "llerror.h" + +#if LL_WINDOWS +class LLDirectoryGuard +{ +public: + LLDirectoryGuard() + { + mOrigDirLen = GetCurrentDirectory(MAX_PATH, mOrigDir); + } + + ~LLDirectoryGuard() + { + mFinalDirLen = GetCurrentDirectory(MAX_PATH, mFinalDir); + if ((mOrigDirLen!=mFinalDirLen) || + (wcsncmp(mOrigDir,mFinalDir,mOrigDirLen)!=0)) + { + // Dir has changed + std::string mOrigDirUtf8 = utf16str_to_utf8str(llutf16string(mOrigDir)); + std::string mFinalDirUtf8 = utf16str_to_utf8str(llutf16string(mFinalDir)); + llinfos << "Resetting working dir from " << mFinalDirUtf8 << " to " << mOrigDirUtf8 << llendl; + SetCurrentDirectory(mOrigDir); + } + } + +private: + TCHAR mOrigDir[MAX_PATH]; + DWORD mOrigDirLen; + TCHAR mFinalDir[MAX_PATH]; + DWORD mFinalDirLen; +}; +#else // No-op outside Windows. +class LLDirectoryGuard +{ +public: + LLDirectoryGuard() {} + ~LLDirectoryGuard() {} +}; +#endif + + +#endif diff --git a/indra/llvfs/lllfsthread.cpp b/indra/llvfs/lllfsthread.cpp index 8d2dc72ffc..3d3ed9f6d4 100644 --- a/indra/llvfs/lllfsthread.cpp +++ b/indra/llvfs/lllfsthread.cpp @@ -2,35 +2,29 @@ * @file lllfsthread.cpp * @brief LLLFSThread base class * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" -#include "llmath.h" #include "lllfsthread.h" #include "llstl.h" #include "llapr.h" @@ -73,6 +67,10 @@ LLLFSThread::LLLFSThread(bool threaded) : LLQueuedThread("LFS", threaded), mPriorityCounter(PRIORITY_LOWBITS) { + if(!mLocalAPRFilePoolp) + { + mLocalAPRFilePoolp = new LLVolatileAPRPool() ; + } } LLLFSThread::~LLLFSThread() @@ -82,7 +80,7 @@ LLLFSThread::~LLLFSThread() //---------------------------------------------------------------------------- -LLLFSThread::handle_t LLLFSThread::read(const LLString& filename, /* Flawfinder: ignore */ +LLLFSThread::handle_t LLLFSThread::read(const std::string& filename, /* Flawfinder: ignore */ U8* buffer, S32 offset, S32 numbytes, Responder* responder, U32 priority) { @@ -105,7 +103,7 @@ LLLFSThread::handle_t LLLFSThread::read(const LLString& filename, /* Flawfinder: return handle; } -LLLFSThread::handle_t LLLFSThread::write(const LLString& filename, +LLLFSThread::handle_t LLLFSThread::write(const std::string& filename, U8* buffer, S32 offset, S32 numbytes, Responder* responder, U32 priority) { @@ -131,7 +129,7 @@ LLLFSThread::handle_t LLLFSThread::write(const LLString& filename, LLLFSThread::Request::Request(LLLFSThread* thread, handle_t handle, U32 priority, - operation_t op, const LLString& filename, + operation_t op, const std::string& filename, U8* buffer, S32 offset, S32 numbytes, Responder* responder) : QueuedRequest(handle, priority, FLAG_AUTO_COMPLETE), @@ -184,8 +182,9 @@ bool LLLFSThread::Request::processRequest() if (mOperation == FILE_READ) { llassert(mOffset >= 0); - apr_file_t* filep = ll_apr_file_open(mFileName, LL_APR_RB, mThread->mAPRPoolp); - if (!filep) + LLAPRFile infile ; // auto-closes + infile.open(mFileName, LL_APR_RB, mThread->getLocalAPRFilePool()); + if (!infile.getFileHandle()) { llwarns << "LLLFS: Unable to read file: " << mFileName << llendl; mBytesRead = 0; // fail @@ -193,12 +192,11 @@ bool LLLFSThread::Request::processRequest() } S32 off; if (mOffset < 0) - off = ll_apr_file_seek(filep, APR_END, 0); + off = infile.seek(APR_END, 0); else - off = ll_apr_file_seek(filep, APR_SET, mOffset); + off = infile.seek(APR_SET, mOffset); llassert_always(off >= 0); - mBytesRead = ll_apr_file_read(filep, mBuffer, mBytes ); - apr_file_close(filep); + mBytesRead = infile.read(mBuffer, mBytes ); complete = true; // llinfos << "LLLFSThread::READ:" << mFileName << " Bytes: " << mBytesRead << llendl; } @@ -207,8 +205,9 @@ bool LLLFSThread::Request::processRequest() apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY; if (mOffset < 0) flags |= APR_APPEND; - apr_file_t* filep = ll_apr_file_open(mFileName, flags, mThread->mAPRPoolp); - if (!filep) + LLAPRFile outfile ; // auto-closes + outfile.open(mFileName, flags, mThread->getLocalAPRFilePool()); + if (!outfile.getFileHandle()) { llwarns << "LLLFS: Unable to write file: " << mFileName << llendl; mBytesRead = 0; // fail @@ -216,18 +215,16 @@ bool LLLFSThread::Request::processRequest() } if (mOffset >= 0) { - S32 seek = ll_apr_file_seek(filep, APR_SET, mOffset); + S32 seek = outfile.seek(APR_SET, mOffset); if (seek < 0) { - apr_file_close(filep); llwarns << "LLLFS: Unable to write file (seek failed): " << mFileName << llendl; mBytesRead = 0; // fail return true; } } - mBytesRead = ll_apr_file_write(filep, mBuffer, mBytes ); + mBytesRead = outfile.write(mBuffer, mBytes ); complete = true; - apr_file_close(filep); // llinfos << "LLLFSThread::WRITE:" << mFileName << " Bytes: " << mBytesRead << "/" << mBytes << " Offset:" << mOffset << llendl; } else diff --git a/indra/llvfs/lllfsthread.h b/indra/llvfs/lllfsthread.h index 2a23f550e7..cdb5c75946 100644 --- a/indra/llvfs/lllfsthread.h +++ b/indra/llvfs/lllfsthread.h @@ -2,30 +2,25 @@ * @file lllfsthread.h * @brief LLLFSThread base class * - * $LicenseInfo:firstyear=2000&license=viewergpl$ - * - * Copyright (c) 2000-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2000&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -38,7 +33,7 @@ #include <set> #include "llapr.h" - +#include "llpointer.h" #include "llqueuedthread.h" //============================================================================ @@ -75,7 +70,7 @@ public: public: Request(LLLFSThread* thread, handle_t handle, U32 priority, - operation_t op, const LLString& filename, + operation_t op, const std::string& filename, U8* buffer, S32 offset, S32 numbytes, Responder* responder); @@ -95,7 +90,7 @@ public: { return mBuffer; } - const LLString& getFilename() + const std::string& getFilename() { return mFileName; } @@ -108,7 +103,7 @@ public: LLLFSThread* mThread; operation_t mOperation; - LLString mFileName; + std::string mFileName; U8* mBuffer; // dest for reads, source for writes, new UUID for rename S32 mOffset; // offset into file, -1 = append (WRITE only) @@ -124,10 +119,10 @@ public: ~LLLFSThread(); // Return a Request handle - handle_t read(const LLString& filename, /* Flawfinder: ignore */ + handle_t read(const std::string& filename, /* Flawfinder: ignore */ U8* buffer, S32 offset, S32 numbytes, Responder* responder, U32 pri=0); - handle_t write(const LLString& filename, + handle_t write(const std::string& filename, U8* buffer, S32 offset, S32 numbytes, Responder* responder, U32 pri=0); diff --git a/indra/llvfs/llpidlock.cpp b/indra/llvfs/llpidlock.cpp new file mode 100644 index 0000000000..0424f2379e --- /dev/null +++ b/indra/llvfs/llpidlock.cpp @@ -0,0 +1,276 @@ +/** + * @file llformat.cpp + * @date January 2007 + * @brief string formatting utility + * + * $LicenseInfo:firstyear=2007&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "llpidlock.h" +#include "lldir.h" +#include "llsd.h" +#include "llsdserialize.h" +#include "llnametable.h" +#include "llframetimer.h" + +#if LL_WINDOWS //For windows platform. + +#include <windows.h> + +namespace { + inline DWORD getpid() { + return GetCurrentProcessId(); + } +} + +bool isProcessAlive(U32 pid) +{ + return (bool) GetProcessVersion((DWORD)pid); +} + +#else //Everyone Else +bool isProcessAlive(U32 pid) +{ + return (bool) kill( (pid_t)pid, 0); +} +#endif //Everyone else. + + + +class LLPidLockFile +{ + public: + LLPidLockFile( ) : + mAutosave(false), + mSaving(false), + mWaiting(false), + mPID(getpid()), + mNameTable(NULL), + mClean(true) + { + mLockName = gDirUtilp->getTempDir() + gDirUtilp->getDirDelimiter() + "savelock"; + } + bool requestLock(LLNameTable<void *> *name_table, bool autosave, + bool force_immediate=FALSE, F32 timeout=300.0); + bool checkLock(); + void releaseLock(); + + private: + void writeLockFile(LLSD pids); + public: + static LLPidLockFile& instance(); // return the singleton black list file + + bool mAutosave; + bool mSaving; + bool mWaiting; + LLFrameTimer mTimer; + U32 mPID; + std::string mLockName; + std::string mSaveName; + LLSD mPIDS_sd; + LLNameTable<void*> *mNameTable; + bool mClean; +}; + +LLPidLockFile& LLPidLockFile::instance() +{ + static LLPidLockFile the_file; + return the_file; +} + +void LLPidLockFile::writeLockFile(LLSD pids) +{ + llofstream ofile(mLockName); + + if (!LLSDSerialize::toXML(pids,ofile)) + { + llwarns << "Unable to write concurrent save lock file." << llendl; + } + ofile.close(); +} + +bool LLPidLockFile::requestLock(LLNameTable<void *> *name_table, bool autosave, + bool force_immediate, F32 timeout) +{ + bool readyToSave = FALSE; + + if (mSaving) return FALSE; //Bail out if we're currently saving. Will not queue another save. + + if (!mWaiting){ + mNameTable=name_table; + mAutosave = autosave; + } + + LLSD out_pids; + out_pids.append( (LLSD::Integer)mPID ); + + llifstream ifile(mLockName); + + if (ifile.is_open()) + { //If file exists, we need to decide whether or not to continue. + if ( force_immediate + || mTimer.hasExpired() ) //Only deserialize if we REALLY need to. + { + + LLSD in_pids; + + LLSDSerialize::fromXML(in_pids, ifile); + + //Clean up any dead PIDS that might be in there. + for (LLSD::array_iterator i=in_pids.beginArray(); + i !=in_pids.endArray(); + ++i) + { + U32 stored_pid=(*i).asInteger(); + + if (isProcessAlive(stored_pid)) + { + out_pids.append( (*i) ); + } + } + + readyToSave=TRUE; + } + ifile.close(); + } + else + { + readyToSave=TRUE; + } + + if (!mWaiting) //Not presently waiting to save. Queue up. + { + mTimer.resetWithExpiry(timeout); + mWaiting=TRUE; + } + + if (readyToSave) + { //Potential race condition won't kill us. Ignore it. + writeLockFile(out_pids); + mSaving=TRUE; + } + + return readyToSave; +} + +bool LLPidLockFile::checkLock() +{ + return mWaiting; +} + +void LLPidLockFile::releaseLock() +{ + llifstream ifile(mLockName); + LLSD in_pids; + LLSD out_pids; + bool write_file=FALSE; + + LLSDSerialize::fromXML(in_pids, ifile); + + //Clean up this PID and any dead ones. + for (LLSD::array_iterator i=in_pids.beginArray(); + i !=in_pids.endArray(); + ++i) + { + U32 stored_pid=(*i).asInteger(); + + if (stored_pid != mPID && isProcessAlive(stored_pid)) + { + out_pids.append( (*i) ); + write_file=TRUE; + } + } + ifile.close(); + + if (write_file) + { + writeLockFile(out_pids); + } + else + { + unlink(mLockName.c_str()); + } + + mSaving=FALSE; + mWaiting=FALSE; +} + +//LLPidLock + +void LLPidLock::initClass() { + (void) LLPidLockFile::instance(); +} + +bool LLPidLock::checkLock() +{ + return LLPidLockFile::instance().checkLock(); +} + +bool LLPidLock::requestLock(LLNameTable<void *> *name_table, bool autosave, + bool force_immediate, F32 timeout) +{ + return LLPidLockFile::instance().requestLock(name_table,autosave,force_immediate,timeout); +} + +void LLPidLock::releaseLock() +{ + return LLPidLockFile::instance().releaseLock(); +} + +bool LLPidLock::isClean() +{ + return LLPidLockFile::instance().mClean; +} + +//getters +LLNameTable<void *> * LLPidLock::getNameTable() +{ + return LLPidLockFile::instance().mNameTable; +} + +bool LLPidLock::getAutosave() +{ + return LLPidLockFile::instance().mAutosave; +} + +bool LLPidLock::getClean() +{ + return LLPidLockFile::instance().mClean; +} + +std::string LLPidLock::getSaveName() +{ + return LLPidLockFile::instance().mSaveName; +} + +//setters +void LLPidLock::setClean(bool clean) +{ + LLPidLockFile::instance().mClean=clean; +} + +void LLPidLock::setSaveName(std::string savename) +{ + LLPidLockFile::instance().mSaveName=savename; +} diff --git a/indra/llvfs/llpidlock.h b/indra/llvfs/llpidlock.h new file mode 100644 index 0000000000..d3295f4911 --- /dev/null +++ b/indra/llvfs/llpidlock.h @@ -0,0 +1,59 @@ +/** + * @file llpidlock.h + * @brief System information debugging classes. + * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#ifndef LL_PIDLOCK_H +#define LL_PIDLOCK_H +#include "llnametable.h" + +class LLSD; +class LLFrameTimer; + +#if !LL_WINDOWS //For non-windows platforms. +#include <signal.h> +#endif + +namespace LLPidLock +{ + void initClass(); // { (void) LLPidLockFile::instance(); } + + bool requestLock( LLNameTable<void *> *name_table=NULL, bool autosave=TRUE, + bool force_immediate=FALSE, F32 timeout=300.0); + bool checkLock(); + void releaseLock(); + bool isClean(); + + //getters + LLNameTable<void *> * getNameTable(); + bool getAutosave(); + bool getClean(); + std::string getSaveName(); + + //setters + void setClean(bool clean); + void setSaveName(std::string savename); +}; + +#endif // LL_PIDLOCK_H diff --git a/indra/llvfs/llvfile.cpp b/indra/llvfs/llvfile.cpp index bd4dfc2d78..a8db7b235e 100644 --- a/indra/llvfs/llvfile.cpp +++ b/indra/llvfs/llvfile.cpp @@ -2,30 +2,25 @@ * @file llvfile.cpp * @brief Implementation of virtual file * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -35,6 +30,7 @@ #include "llerror.h" #include "llthread.h" +#include "llstat.h" #include "llvfs.h" const S32 LLVFile::READ = 0x00000001; @@ -42,6 +38,8 @@ const S32 LLVFile::WRITE = 0x00000002; const S32 LLVFile::READ_WRITE = 0x00000003; // LLVFile::READ & LLVFile::WRITE const S32 LLVFile::APPEND = 0x00000006; // 0x00000004 & LLVFile::WRITE +static LLFastTimer::DeclareTimer FTM_VFILE_WAIT("VFile Wait"); + //---------------------------------------------------------------------------- LLVFSThread* LLVFile::sVFSThread = NULL; BOOL LLVFile::sAllocdVFSThread = FALSE; @@ -316,7 +314,7 @@ BOOL LLVFile::setMaxSize(S32 size) if (!mVFS->checkAvailable(size)) { - LLFastTimer t(LLFastTimer::FTM_VFILE_WAIT); + LLFastTimer t(FTM_VFILE_WAIT); S32 count = 0; while (sVFSThread->getPending() > 1000) { @@ -424,7 +422,7 @@ bool LLVFile::isLocked(EVFSLock lock) void LLVFile::waitForLock(EVFSLock lock) { - LLFastTimer t(LLFastTimer::FTM_VFILE_WAIT); + LLFastTimer t(FTM_VFILE_WAIT); // spin until the lock clears while (isLocked(lock)) { diff --git a/indra/llvfs/llvfile.h b/indra/llvfs/llvfile.h index cd4fc59174..7e9d9f73e5 100644 --- a/indra/llvfs/llvfile.h +++ b/indra/llvfs/llvfile.h @@ -2,30 +2,25 @@ * @file llvfile.h * @brief Definition of virtual file * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -87,7 +82,6 @@ protected: S32 mMode; LLVFS *mVFS; F32 mPriority; - BOOL mOnReadQueue; S32 mBytesRead; LLVFSThread::handle_t mHandle; diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp index 417e48c07c..c1fe21c57d 100644 --- a/indra/llvfs/llvfs.cpp +++ b/indra/llvfs/llvfs.cpp @@ -2,30 +2,25 @@ * @file llvfs.cpp * @brief Implementation of virtual file system * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -45,7 +40,9 @@ #endif #include "llvfs.h" + #include "llstl.h" +#include "lltimer.h" const S32 FILE_BLOCK_MASK = 0x000003FF; // 1024-byte blocks const S32 VFS_CLEANUP_SIZE = 5242880; // how much space we free up in a single stroke @@ -231,9 +228,11 @@ struct LLVFSFileBlock_less const S32 LLVFSFileBlock::SERIAL_SIZE = 34; - -LLVFS::LLVFS(const char *index_filename, const char *data_filename, const BOOL read_only, const U32 presize, const BOOL remove_after_crash) -: mRemoveAfterCrash(remove_after_crash) + +LLVFS::LLVFS(const std::string& index_filename, const std::string& data_filename, const BOOL read_only, const U32 presize, const BOOL remove_after_crash) +: mRemoveAfterCrash(remove_after_crash), + mDataFP(NULL), + mIndexFP(NULL) { mDataMutex = new LLMutex(0); @@ -244,29 +243,26 @@ LLVFS::LLVFS(const char *index_filename, const char *data_filename, const BOOL r } mValid = VFSVALID_OK; mReadOnly = read_only; - mIndexFilename = new char[strlen(index_filename) + 1]; /* Flawfinder: ignore */ - mDataFilename = new char[strlen(data_filename) + 1]; /* Flawfinder: ignore */ - if (mIndexFilename == NULL || mDataFilename == NULL) - { - llerrs << "Memory Allocation Failure" << llendl; - return; - } - strcpy(mIndexFilename, index_filename); /* Flawfinder: ignore */ - strcpy(mDataFilename, data_filename); /* Flawfinder: ignore */ + mIndexFilename = index_filename; + mDataFilename = data_filename; const char *file_mode = mReadOnly ? "rb" : "r+b"; - if (! (mDataFP = openAndLock(mDataFilename, file_mode, mReadOnly))) + LL_INFOS("VFS") << "Attempting to open VFS index file " << mIndexFilename << LL_ENDL; + LL_INFOS("VFS") << "Attempting to open VFS data file " << mDataFilename << LL_ENDL; + + mDataFP = openAndLock(mDataFilename, file_mode, mReadOnly); + if (!mDataFP) { - if (mReadOnly) { - llwarns << "Can't find " << mDataFilename << " to open read-only VFS" << llendl; + LL_WARNS("VFS") << "Can't find " << mDataFilename << " to open read-only VFS" << LL_ENDL; mValid = VFSVALID_BAD_CANNOT_OPEN_READONLY; return; } - - if((mDataFP = openAndLock(mDataFilename, "w+b", FALSE))) + + mDataFP = openAndLock(mDataFilename, "w+b", FALSE); + if (mDataFP) { // Since we're creating this data file, assume any index file is bogus // remove the index, since this vfs is now blank @@ -274,56 +270,12 @@ LLVFS::LLVFS(const char *index_filename, const char *data_filename, const BOOL r } else { - llwarns << "Can't open VFS data file " << mDataFilename << " attempting to use alternate" << llendl; - - char *temp_index = new char[strlen(mIndexFilename) + 10]; /* Flawfinder: ignore */ - if (!temp_index) - { - llerrs << "Out of the memory in LLVFS::LLVFS(const char *index_filename, const char *data_filename, const BOOL read_only, const U32 presize, const BOOL remove_after_crash)" << llendl; - return; - } - char *temp_data = new char[strlen(mDataFilename) + 10]; /* Flawfinder: ignore */ - if (!temp_data) - { - llerrs << "Out of the memory in LLVFS::LLVFS(const char *index_filename, const char *data_filename, const BOOL read_only, const U32 presize, const BOOL remove_after_crash)" << llendl; - return; - } - - for (U32 count = 0; count < 256; count++) - { - sprintf(temp_index, "%s.%u", mIndexFilename, count); /* Flawfinder: ignore */ - sprintf(temp_data, "%s.%u", mDataFilename, count); /* Flawfinder: ignore */ - - // try just opening, then creating, each alternate - if ((mDataFP = openAndLock(temp_data, "r+b", FALSE))) - { - break; - } - - if ((mDataFP = openAndLock(temp_data, "w+b", FALSE))) - { - // we're creating the datafile, so nuke the indexfile - LLFile::remove(temp_index); - break; - } - } - - if (! mDataFP) - { - llwarns << "Couldn't open vfs data file after trying many alternates" << llendl; - mValid = VFSVALID_BAD_CANNOT_CREATE; - delete[] temp_index; - delete[] temp_data; - return; - } - - delete[] mIndexFilename; - delete[] mDataFilename; - - mIndexFilename = temp_index; - mDataFilename = temp_data; + LL_WARNS("VFS") << "Couldn't open vfs data file " + << mDataFilename << LL_ENDL; + mValid = VFSVALID_BAD_CANNOT_CREATE; + return; } - + if (presize) { presizeDataFile(presize); @@ -335,20 +287,14 @@ LLVFS::LLVFS(const char *index_filename, const char *data_filename, const BOOL r if (!mReadOnly && mRemoveAfterCrash) { llstat marker_info; - char* marker = new char[strlen(mDataFilename) + strlen(".open") + 1]; /* Flawfinder: ignore */ - if (!marker ) - { - llerrs << "Out of memory in LLVFS::LLVFS(const char *index_filename, const char *data_filename, const BOOL read_only, const U32 presize, const BOOL remove_after_crash)" << llendl; - return; - } - sprintf(marker, "%s.open", mDataFilename); /* Flawfinder: ignore */ + std::string marker = mDataFilename + ".open"; if (!LLFile::stat(marker, &marker_info)) { // marker exists, kill the lock and the VFS files unlockAndClose(mDataFP); mDataFP = NULL; - llwarns << "VFS: File left open on last run, removing old VFS file " << mDataFilename << llendl; + LL_WARNS("VFS") << "VFS: File left open on last run, removing old VFS file " << mDataFilename << LL_ENDL; LLFile::remove(mIndexFilename); LLFile::remove(mDataFilename); LLFile::remove(marker); @@ -356,7 +302,7 @@ LLVFS::LLVFS(const char *index_filename, const char *data_filename, const BOOL r mDataFP = openAndLock(mDataFilename, "w+b", FALSE); if (!mDataFP) { - llwarns << "Can't open VFS data file in crash recovery" << llendl; + LL_WARNS("VFS") << "Can't open VFS data file in crash recovery" << LL_ENDL; mValid = VFSVALID_BAD_CANNOT_CREATE; return; } @@ -366,8 +312,6 @@ LLVFS::LLVFS(const char *index_filename, const char *data_filename, const BOOL r presizeDataFile(presize); } } - delete [] marker; - marker = NULL; } // determine the real file size @@ -380,21 +324,20 @@ LLVFS::LLVFS(const char *index_filename, const char *data_filename, const BOOL r llstat fbuf; if (! LLFile::stat(mIndexFilename, &fbuf) && fbuf.st_size >= LLVFSFileBlock::SERIAL_SIZE && - (mIndexFP = openAndLock(mIndexFilename, file_mode, mReadOnly)) + (mIndexFP = openAndLock(mIndexFilename, file_mode, mReadOnly)) // Yes, this is an assignment and not '==' ) { - U8 *buffer = new U8[fbuf.st_size]; - size_t nread = fread(buffer, 1, fbuf.st_size, mIndexFP); - - U8 *tmp_ptr = buffer; - + std::vector<U8> buffer(fbuf.st_size); + size_t buf_offset = 0; + size_t nread = fread(&buffer[0], 1, fbuf.st_size, mIndexFP); + std::vector<LLVFSFileBlock*> files_by_loc; - while (tmp_ptr < buffer + nread) + while (buf_offset < nread) { LLVFSFileBlock *block = new LLVFSFileBlock(); - block->deserialize(tmp_ptr, (S32)(tmp_ptr - buffer)); + block->deserialize(&buffer[buf_offset], (S32)buf_offset); // Do sanity check on this block. // Note that this skips zero size blocks, which helps VFS @@ -414,11 +357,10 @@ LLVFS::LLVFS(const char *index_filename, const char *data_filename, const BOOL r if (block->mLength && block->mSize > 0) { // this is corrupt, not empty - llwarns << "VFS corruption: " << block->mFileID << " (" << block->mFileType << ") at index " << block->mIndexLocation << " DS: " << data_size << llendl; - llwarns << "Length: " << block->mLength << "\tLocation: " << block->mLocation << "\tSize: " << block->mSize << llendl; - llwarns << "File has bad data - VFS removed" << llendl; + LL_WARNS("VFS") << "VFS corruption: " << block->mFileID << " (" << block->mFileType << ") at index " << block->mIndexLocation << " DS: " << data_size << LL_ENDL; + LL_WARNS("VFS") << "Length: " << block->mLength << "\tLocation: " << block->mLocation << "\tSize: " << block->mSize << LL_ENDL; + LL_WARNS("VFS") << "File has bad data - VFS removed" << LL_ENDL; - delete[] buffer; delete block; unlockAndClose( mIndexFP ); @@ -429,21 +371,25 @@ LLVFS::LLVFS(const char *index_filename, const char *data_filename, const BOOL r mDataFP = NULL; LLFile::remove( mDataFilename ); + LL_WARNS("VFS") << "Deleted corrupt VFS files " + << mDataFilename + << " and " + << mIndexFilename + << LL_ENDL; + mValid = VFSVALID_BAD_CORRUPT; return; } else { // this is a null or bad entry, skip it - S32 index_loc = (S32)(tmp_ptr - buffer); - mIndexHoles.push_back(index_loc); + mIndexHoles.push_back(buf_offset); delete block; } - tmp_ptr += LLVFSFileBlock::SERIAL_SIZE; + buf_offset += LLVFSFileBlock::SERIAL_SIZE; } - delete[] buffer; std::sort( files_by_loc.begin(), @@ -481,13 +427,13 @@ LLVFS::LLVFS(const char *index_filename, const char *data_filename, const BOOL r if (cur_file_block->mLocation == last_file_block->mLocation && cur_file_block->mLength == last_file_block->mLength) { - llwarns << "VFS: removing duplicate entry" + LL_WARNS("VFS") << "VFS: removing duplicate entry" << " at " << cur_file_block->mLocation << " length " << cur_file_block->mLength << " size " << cur_file_block->mSize << " ID " << cur_file_block->mFileID << " type " << cur_file_block->mFileType - << llendl; + << LL_ENDL; // Duplicate entries. Nuke them both for safety. mFileBlocks.erase(*cur_file_block); // remove ID/type entry @@ -528,12 +474,19 @@ LLVFS::LLVFS(const char *index_filename, const char *data_filename, const BOOL r mDataFP = NULL; LLFile::remove( mDataFilename ); - llwarns << "VFS: overlapping entries" + LL_WARNS("VFS") << "VFS: overlapping entries" << " at " << cur_file_block->mLocation << " length " << cur_file_block->mLength << " ID " << cur_file_block->mFileID << " type " << cur_file_block->mFileType - << llendl; + << LL_ENDL; + + LL_WARNS("VFS") << "Deleted corrupt VFS files " + << mDataFilename + << " and " + << mIndexFilename + << LL_ENDL; + mValid = VFSVALID_BAD_CORRUPT; return; } @@ -559,11 +512,11 @@ LLVFS::LLVFS(const char *index_filename, const char *data_filename, const BOOL r addFreeBlock(new LLVFSBlock(0, data_size)); } } - else + else // Pre-existing index file wasn't opened { if (mReadOnly) { - llwarns << "Can't find " << mIndexFilename << " to open read-only VFS" << llendl; + LL_WARNS("VFS") << "Can't find " << mIndexFilename << " to open read-only VFS" << LL_ENDL; mValid = VFSVALID_BAD_CANNOT_OPEN_READONLY; return; } @@ -572,7 +525,7 @@ LLVFS::LLVFS(const char *index_filename, const char *data_filename, const BOOL r mIndexFP = openAndLock(mIndexFilename, "w+b", FALSE); if (!mIndexFP) { - llwarns << "Couldn't open an index file for the VFS, probably a sharing violation!" << llendl; + LL_WARNS("VFS") << "Couldn't open an index file for the VFS, probably a sharing violation!" << LL_ENDL; unlockAndClose( mDataFP ); mDataFP = NULL; @@ -590,24 +543,17 @@ LLVFS::LLVFS(const char *index_filename, const char *data_filename, const BOOL r // Open marker file to look for bad shutdowns if (!mReadOnly && mRemoveAfterCrash) { - char* marker = new char[strlen(mDataFilename) + strlen(".open") + 1]; - if (!marker) - { - llerrs << "Out of memory in LLVFS::LLVFS(const char *index_filename, const char *data_filename, const BOOL read_only, const U32 presize, const BOOL remove_after_crash)" << llendl; - return; - } - sprintf(marker, "%s.open", mDataFilename); /* Flawfinder: ignore */ - FILE* marker_fp = LLFile::fopen(marker, "w"); /* Flawfinder: ignore */ + std::string marker = mDataFilename + ".open"; + LLFILE* marker_fp = LLFile::fopen(marker, "w"); /* Flawfinder: ignore */ if (marker_fp) { fclose(marker_fp); marker_fp = NULL; } - delete [] marker; - marker = NULL; } - llinfos << "VFS: Using index file " << mIndexFilename << " and data file " << mDataFilename << llendl; + LL_INFOS("VFS") << "Using VFS index file " << mIndexFilename << LL_ENDL; + LL_INFOS("VFS") << "Using VFS data file " << mDataFilename << LL_ENDL; mValid = VFSVALID_OK; } @@ -616,7 +562,7 @@ LLVFS::~LLVFS() { if (mDataMutex->isLocked()) { - llerrs << "LLVFS destroyed with mutex locked" << llendl; + LL_ERRS("VFS") << "LLVFS destroyed with mutex locked" << LL_ENDL; } unlockAndClose(mIndexFP); @@ -639,26 +585,54 @@ LLVFS::~LLVFS() // Remove marker file if (!mReadOnly && mRemoveAfterCrash) { - char* marker_file = new char[strlen(mDataFilename) + strlen(".open") + 1]; - if (marker_file == NULL) - { - llerrs << "Memory Allocation Failure" << llendl; - return; + std::string marker = mDataFilename + ".open"; + LLFile::remove(marker); + } + + delete mDataMutex; +} + + +// Use this function normally to create LLVFS files. +// Will append digits to the end of the filename with multiple re-trys +// static +LLVFS * LLVFS::createLLVFS(const std::string& index_filename, + const std::string& data_filename, + const BOOL read_only, + const U32 presize, + const BOOL remove_after_crash) +{ + LLVFS * new_vfs = new LLVFS(index_filename, data_filename, read_only, presize, remove_after_crash); + + if( !new_vfs->isValid() ) + { // First name failed, retry with new names + std::string retry_vfs_index_name; + std::string retry_vfs_data_name; + S32 count = 0; + while (!new_vfs->isValid() && + count < 256) + { // Append '.<number>' to end of filenames + retry_vfs_index_name = index_filename + llformat(".%u",count); + retry_vfs_data_name = data_filename + llformat(".%u", count); + + delete new_vfs; // Delete bad VFS and try again + new_vfs = new LLVFS(retry_vfs_index_name, retry_vfs_data_name, read_only, presize, remove_after_crash); + + count++; } - sprintf(marker_file, "%s.open", mDataFilename); /* Flawfinder: ignore */ - LLFile::remove(marker_file); - delete [] marker_file; - marker_file = NULL; } - delete[] mIndexFilename; - mIndexFilename = NULL; - delete[] mDataFilename; - mDataFilename = NULL; + if( !new_vfs->isValid() ) + { + delete new_vfs; // Delete bad VFS + new_vfs = NULL; // Total failure + } - delete mDataMutex; + return new_vfs; } + + void LLVFS::presizeDataFile(const U32 size) { if (!mDataFP) @@ -767,8 +741,14 @@ S32 LLVFS::getMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type BOOL LLVFS::checkAvailable(S32 max_size) { + lockData(); + blocks_length_map_t::iterator iter = mFreeBlocksByLength.lower_bound(max_size); // first entry >= size - return (iter == mFreeBlocksByLength.end()) ? FALSE : TRUE; + const BOOL res(iter == mFreeBlocksByLength.end() ? FALSE : TRUE); + + unlockData(); + + return res; } BOOL LLVFS::setMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type, S32 max_size) @@ -874,40 +854,42 @@ BOOL LLVFS::setMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type if (free_block) { + // Save location where data is going, useFreeSpace will move free_block->mLocation; + U32 new_data_location = free_block->mLocation; + + //mark the free block as used so it does not + //interfere with other operations such as addFreeBlock + useFreeSpace(free_block, max_size); // useFreeSpace takes ownership (and may delete) free_block + if (block->mLength > 0) { // create a new free block where this file used to be LLVFSBlock *new_free_block = new LLVFSBlock(block->mLocation, block->mLength); addFreeBlock(new_free_block); - + if (block->mSize > 0) { // move the file into the new block - U8 *buffer = new U8[block->mSize]; + std::vector<U8> buffer(block->mSize); fseek(mDataFP, block->mLocation, SEEK_SET); - if (fread(buffer, block->mSize, 1, mDataFP) == 1) + if (fread(&buffer[0], block->mSize, 1, mDataFP) == 1) { - fseek(mDataFP, free_block->mLocation, SEEK_SET); - if (fwrite(buffer, block->mSize, 1, mDataFP) != 1) + fseek(mDataFP, new_data_location, SEEK_SET); + if (fwrite(&buffer[0], block->mSize, 1, mDataFP) != 1) { llwarns << "Short write" << llendl; } } else { llwarns << "Short read" << llendl; } - - delete[] buffer; } } - block->mLocation = free_block->mLocation; + block->mLocation = new_data_location; block->mLength = max_size; - // Must call useFreeSpace before sync(), as sync() - // unlocks data structures. - useFreeSpace(free_block, max_size); sync(block); @@ -1122,14 +1104,14 @@ S32 LLVFS::getData(const LLUUID &file_id, const LLAssetType::EType file_type, U8 } } - unlockData(); - if (do_read) { fseek(mDataFP, location, SEEK_SET); bytesread = (S32)fread(buffer, 1, length, mDataFP); } + unlockData(); + return bytesread; } @@ -1194,8 +1176,6 @@ S32 LLVFS::storeData(const LLUUID &file_id, const LLAssetType::EType file_type, } U32 file_location = location + block->mLocation; - unlockData(); - fseek(mDataFP, file_location, SEEK_SET); S32 write_len = (S32)fwrite(buffer, 1, length, mDataFP); if (write_len != length) @@ -1204,7 +1184,6 @@ S32 LLVFS::storeData(const LLUUID &file_id, const LLAssetType::EType file_type, } // fflush(mDataFP); - lockData(); if (location + length > block->mSize) { block->mSize = location + write_len; @@ -1316,7 +1295,7 @@ void LLVFS::eraseBlockLength(LLVFSBlock *block) } if(!found_block) { - llwarns << "eraseBlock could not find block" << llendl; + llerrs << "eraseBlock could not find block" << llendl; } } @@ -1453,7 +1432,7 @@ void LLVFS::addFreeBlock(LLVFSBlock *block) // } //} - +// length bytes from free_block are going to be used (so they are no longer free) void LLVFS::useFreeSpace(LLVFSBlock *free_block, S32 length) { if (free_block->mLength == length) @@ -1536,8 +1515,6 @@ void LLVFS::sync(LLVFSFileBlock *block, BOOL remove) block->serialize(buffer); } - unlockData(); - // If set_index_to_end, file pointer is already at seek_pos // and we don't need to do anything. Only seek if not at end. if (!set_index_to_end) @@ -1549,11 +1526,10 @@ void LLVFS::sync(LLVFSFileBlock *block, BOOL remove) { llwarns << "Short write" << llendl; } - + + // *NOTE: Why was this commented out? // fflush(mIndexFP); - lockData(); - return; } @@ -1730,32 +1706,32 @@ void LLVFS::audit() fflush(mIndexFP); fseek(mIndexFP, 0, SEEK_END); - long index_size = ftell(mIndexFP); + size_t index_size = ftell(mIndexFP); fseek(mIndexFP, 0, SEEK_SET); BOOL vfs_corrupt = FALSE; - U8 *buffer = new U8[index_size]; + std::vector<U8> buffer(index_size); - if (fread(buffer, 1, index_size, mIndexFP) != index_size) + if (fread(&buffer[0], 1, index_size, mIndexFP) != index_size) { llwarns << "Index truncated" << llendl; vfs_corrupt = TRUE; } - U8 *tmp_ptr = buffer; + size_t buf_offset = 0; std::map<LLVFSFileSpecifier, LLVFSFileBlock*> found_files; U32 cur_time = (U32)time(NULL); std::vector<LLVFSFileBlock*> audit_blocks; - while (!vfs_corrupt && tmp_ptr < buffer + index_size) + while (!vfs_corrupt && buf_offset < index_size) { LLVFSFileBlock *block = new LLVFSFileBlock(); audit_blocks.push_back(block); - block->deserialize(tmp_ptr, (S32)(tmp_ptr - buffer)); - tmp_ptr += block->SERIAL_SIZE; + block->deserialize(&buffer[buf_offset], (S32)buf_offset); + buf_offset += block->SERIAL_SIZE; // do sanity check on this block if (block->mLength >= 0 && @@ -1814,8 +1790,6 @@ void LLVFS::audit() } } - delete[] buffer; - if (!vfs_corrupt) { for (fileblock_map::iterator it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it) @@ -2041,31 +2015,30 @@ void LLVFS::dumpStatistics() } // Debug Only! -LLString get_extension(LLAssetType::EType type) +std::string get_extension(LLAssetType::EType type) { - LLString extension; + std::string extension; switch(type) { - case LLAssetType::AT_TEXTURE: - extension = ".j2c"; + case LLAssetType::AT_TEXTURE: + extension = ".jp2"; // formerly ".j2c" break; - case LLAssetType::AT_SOUND: + case LLAssetType::AT_SOUND: extension = ".ogg"; break; - case LLAssetType::AT_SOUND_WAV: + case LLAssetType::AT_SOUND_WAV: extension = ".wav"; break; - case LLAssetType::AT_TEXTURE_TGA: + case LLAssetType::AT_TEXTURE_TGA: extension = ".tga"; break; - case LLAssetType::AT_IMAGE_JPEG: - extension = ".jpeg"; - break; - case LLAssetType::AT_ANIMATION: + case LLAssetType::AT_ANIMATION: extension = ".lla"; break; - default: - extension = ".data"; + default: + // Just use the asset server filename extension in most cases + extension += "."; + extension += LLAssetType::lookup(type); break; } return extension; @@ -2084,7 +2057,7 @@ void LLVFS::listFiles() if (length != BLOCK_LENGTH_INVALID && size > 0) { LLUUID id = file_spec.mFileID; - LLString extension = get_extension(file_spec.mFileType); + std::string extension = get_extension(file_spec.mFileType); llinfos << " File: " << id << " Type: " << LLAssetType::getDesc(file_spec.mFileType) << " Size: " << size @@ -2100,6 +2073,7 @@ void LLVFS::dumpFiles() { lockData(); + S32 files_extracted = 0; for (fileblock_map::iterator it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it) { LLVFSFileSpecifier file_spec = it->first; @@ -2110,23 +2084,28 @@ void LLVFS::dumpFiles() { LLUUID id = file_spec.mFileID; LLAssetType::EType type = file_spec.mFileType; - U8* buffer = new U8[size]; + std::vector<U8> buffer(size); unlockData(); - getData(id, type, buffer, 0, size); + getData(id, type, &buffer[0], 0, size); lockData(); - LLString extension = get_extension(type); - LLString filename = id.asString() + extension; + std::string extension = get_extension(type); + std::string filename = id.asString() + extension; llinfos << " Writing " << filename << llendl; - apr_file_t* file = ll_apr_file_open(filename, LL_APR_WB); - ll_apr_file_write(file, buffer, size); - apr_file_close(file); - delete[] buffer; + + LLAPRFile outfile; + outfile.open(filename, LL_APR_WB); + outfile.write(&buffer[0], size); + outfile.close(); + + files_extracted++; } } unlockData(); + + llinfos << "Extracted " << files_extracted << " files out of " << mFileBlocks.size() << llendl; } //============================================================================ @@ -2134,7 +2113,7 @@ void LLVFS::dumpFiles() //============================================================================ // static -FILE *LLVFS::openAndLock(const char *filename, const char *mode, BOOL read_lock) +LLFILE *LLVFS::openAndLock(const std::string& filename, const char* mode, BOOL read_lock) { #if LL_WINDOWS @@ -2142,7 +2121,7 @@ FILE *LLVFS::openAndLock(const char *filename, const char *mode, BOOL read_lock) #else - FILE *fp; + LLFILE *fp; int fd; // first test the lock in a non-destructive way @@ -2152,7 +2131,7 @@ FILE *LLVFS::openAndLock(const char *filename, const char *mode, BOOL read_lock) fl.l_start = 0; fl.l_len = 1; #else // !LL_SOLARIS - if (strstr(mode, "w")) + if (strchr(mode, 'w') != NULL) { fp = LLFile::fopen(filename, "rb"); /* Flawfinder: ignore */ if (fp) @@ -2192,7 +2171,7 @@ FILE *LLVFS::openAndLock(const char *filename, const char *mode, BOOL read_lock) } // static -void LLVFS::unlockAndClose(FILE *fp) +void LLVFS::unlockAndClose(LLFILE *fp) { if (fp) { diff --git a/indra/llvfs/llvfs.h b/indra/llvfs/llvfs.h index a068c0d644..63f0f28933 100644 --- a/indra/llvfs/llvfs.h +++ b/indra/llvfs/llvfs.h @@ -2,30 +2,25 @@ * @file llvfs.h * @brief Definition of virtual file system * - * $LicenseInfo:firstyear=2002&license=viewergpl$ - * - * Copyright (c) 2002-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2002&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -76,11 +71,25 @@ public: class LLVFS { -public: +private: + // Use createLLVFS() to open a VFS file // Pass 0 to not presize - LLVFS(const char *index_filename, const char *data_filename, const BOOL read_only, const U32 presize, const BOOL remove_after_crash); + LLVFS(const std::string& index_filename, + const std::string& data_filename, + const BOOL read_only, + const U32 presize, + const BOOL remove_after_crash); +public: ~LLVFS(); + // Use this function normally to create LLVFS files + // Pass 0 to not presize + static LLVFS * createLLVFS(const std::string& index_filename, + const std::string& data_filename, + const BOOL read_only, + const U32 presize, + const BOOL remove_after_crash); + BOOL isValid() const { return (VFSVALID_OK == mValid); } EVFSValid getValidState() const { return mValid; } @@ -131,7 +140,7 @@ protected: void sync(LLVFSFileBlock *block, BOOL remove = FALSE); void presizeDataFile(const U32 size); - static FILE *openAndLock(const char *filename, const char *mode, BOOL read_lock); + static LLFILE *openAndLock(const std::string& filename, const char* mode, BOOL read_lock); static void unlockAndClose(FILE *fp); // Can initiate LRU-based file removal to make space. @@ -153,13 +162,13 @@ protected: typedef std::multimap<U32, LLVFSBlock*> blocks_location_map_t; blocks_location_map_t mFreeBlocksByLocation; - FILE *mDataFP; - FILE *mIndexFP; + LLFILE *mDataFP; + LLFILE *mIndexFP; std::deque<S32> mIndexHoles; - char *mIndexFilename; - char *mDataFilename; + std::string mIndexFilename; + std::string mDataFilename; BOOL mReadOnly; EVFSValid mValid; diff --git a/indra/llvfs/llvfsthread.cpp b/indra/llvfs/llvfsthread.cpp index fbfbdffaf3..254f8b55ba 100644 --- a/indra/llvfs/llvfsthread.cpp +++ b/indra/llvfs/llvfsthread.cpp @@ -2,35 +2,29 @@ * @file llvfsthread.cpp * @brief LLVFSThread implementation * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ #include "linden_common.h" -#include "llmath.h" #include "llvfsthread.h" #include "llstl.h" diff --git a/indra/llvfs/llvfsthread.h b/indra/llvfs/llvfsthread.h index 6028199055..95f3c857c6 100644 --- a/indra/llvfs/llvfsthread.h +++ b/indra/llvfs/llvfsthread.h @@ -2,30 +2,25 @@ * @file llvfsthread.h * @brief LLVFSThread definition * - * $LicenseInfo:firstyear=2001&license=viewergpl$ - * - * Copyright (c) 2001-2007, Linden Research, Inc. - * + * $LicenseInfo:firstyear=2001&license=viewerlgpl$ * Second Life Viewer Source Code - * The source code in this file ("Source Code") is provided by Linden Lab - * to you under the terms of the GNU General Public License, version 2.0 - * ("GPL"), unless you have obtained a separate licensing agreement - * ("Other License"), formally executed by you and Linden Lab. Terms of - * the GPL can be found in doc/GPL-license.txt in this distribution, or - * online at http://secondlife.com/developers/opensource/gplv2 + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. * - * There are special exceptions to the terms and conditions of the GPL as - * it is applied to this Source Code. View the full text of the exception - * in the file doc/FLOSS-exception.txt in this software distribution, or - * online at http://secondlife.com/developers/opensource/flossexception + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. * - * By copying, modifying or distributing this software, you acknowledge - * that you have read and understood your obligations described above, - * and agree to abide by those obligations. + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO - * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY, - * COMPLETENESS OR PERFORMANCE. + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA * $/LicenseInfo$ */ @@ -87,9 +82,9 @@ public: } std::string getFilename() { - char tbuf[40]; /* Flawfinder: ignore */ - mFileID.toString(tbuf); - return std::string(tbuf); + std::string tstring; + mFileID.toString(tstring); + return tstring; } /*virtual*/ bool processRequest(); diff --git a/indra/llvfs/tests/lldir_test.cpp b/indra/llvfs/tests/lldir_test.cpp new file mode 100644 index 0000000000..bcffa449c8 --- /dev/null +++ b/indra/llvfs/tests/lldir_test.cpp @@ -0,0 +1,260 @@ +/** + * @file lldir_test.cpp + * @date 2008-05 + * @brief LLDir test cases. + * + * $LicenseInfo:firstyear=2008&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2010, Linden Research, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; + * version 2.1 of the License only. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + * + * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA + * $/LicenseInfo$ + */ + +#include "linden_common.h" + +#include "../lldir.h" + +#include "../test/lltut.h" + + +namespace tut +{ + struct LLDirTest + { + }; + typedef test_group<LLDirTest> LLDirTest_t; + typedef LLDirTest_t::object LLDirTest_object_t; + tut::LLDirTest_t tut_LLDirTest("LLDir"); + + template<> template<> + void LLDirTest_object_t::test<1>() + // getDirDelimiter + { + ensure("getDirDelimiter", !gDirUtilp->getDirDelimiter().empty()); + } + + template<> template<> + void LLDirTest_object_t::test<2>() + // getBaseFileName + { + std::string delim = gDirUtilp->getDirDelimiter(); + std::string rawFile = "foo"; + std::string rawFileExt = "foo.bAr"; + std::string rawFileNullExt = "foo."; + std::string rawExt = ".bAr"; + std::string rawDot = "."; + std::string pathNoExt = "aa" + delim + "bb" + delim + "cc" + delim + "dd" + delim + "ee"; + std::string pathExt = pathNoExt + ".eXt"; + std::string dottedPathNoExt = "aa" + delim + "bb" + delim + "cc.dd" + delim + "ee"; + std::string dottedPathExt = dottedPathNoExt + ".eXt"; + + // foo[.bAr] + + ensure_equals("getBaseFileName/r-no-ext/no-strip-exten", + gDirUtilp->getBaseFileName(rawFile, false), + "foo"); + + ensure_equals("getBaseFileName/r-no-ext/strip-exten", + gDirUtilp->getBaseFileName(rawFile, true), + "foo"); + + ensure_equals("getBaseFileName/r-ext/no-strip-exten", + gDirUtilp->getBaseFileName(rawFileExt, false), + "foo.bAr"); + + ensure_equals("getBaseFileName/r-ext/strip-exten", + gDirUtilp->getBaseFileName(rawFileExt, true), + "foo"); + + // foo. + + ensure_equals("getBaseFileName/rn-no-ext/no-strip-exten", + gDirUtilp->getBaseFileName(rawFileNullExt, false), + "foo."); + + ensure_equals("getBaseFileName/rn-no-ext/strip-exten", + gDirUtilp->getBaseFileName(rawFileNullExt, true), + "foo"); + + // .bAr + // interesting case - with no basename, this IS the basename, not the extension. + + ensure_equals("getBaseFileName/e-ext/no-strip-exten", + gDirUtilp->getBaseFileName(rawExt, false), + ".bAr"); + + ensure_equals("getBaseFileName/e-ext/strip-exten", + gDirUtilp->getBaseFileName(rawExt, true), + ".bAr"); + + // . + + ensure_equals("getBaseFileName/d/no-strip-exten", + gDirUtilp->getBaseFileName(rawDot, false), + "."); + + ensure_equals("getBaseFileName/d/strip-exten", + gDirUtilp->getBaseFileName(rawDot, true), + "."); + + // aa/bb/cc/dd/ee[.eXt] + + ensure_equals("getBaseFileName/no-ext/no-strip-exten", + gDirUtilp->getBaseFileName(pathNoExt, false), + "ee"); + + ensure_equals("getBaseFileName/no-ext/strip-exten", + gDirUtilp->getBaseFileName(pathNoExt, true), + "ee"); + + ensure_equals("getBaseFileName/ext/no-strip-exten", + gDirUtilp->getBaseFileName(pathExt, false), + "ee.eXt"); + + ensure_equals("getBaseFileName/ext/strip-exten", + gDirUtilp->getBaseFileName(pathExt, true), + "ee"); + + // aa/bb/cc.dd/ee[.eXt] + + ensure_equals("getBaseFileName/d-no-ext/no-strip-exten", + gDirUtilp->getBaseFileName(dottedPathNoExt, false), + "ee"); + + ensure_equals("getBaseFileName/d-no-ext/strip-exten", + gDirUtilp->getBaseFileName(dottedPathNoExt, true), + "ee"); + + ensure_equals("getBaseFileName/d-ext/no-strip-exten", + gDirUtilp->getBaseFileName(dottedPathExt, false), + "ee.eXt"); + + ensure_equals("getBaseFileName/d-ext/strip-exten", + gDirUtilp->getBaseFileName(dottedPathExt, true), + "ee"); + } + + template<> template<> + void LLDirTest_object_t::test<3>() + // getDirName + { + std::string delim = gDirUtilp->getDirDelimiter(); + std::string rawFile = "foo"; + std::string rawFileExt = "foo.bAr"; + std::string pathNoExt = "aa" + delim + "bb" + delim + "cc" + delim + "dd" + delim + "ee"; + std::string pathExt = pathNoExt + ".eXt"; + std::string dottedPathNoExt = "aa" + delim + "bb" + delim + "cc.dd" + delim + "ee"; + std::string dottedPathExt = dottedPathNoExt + ".eXt"; + + // foo[.bAr] + + ensure_equals("getDirName/r-no-ext", + gDirUtilp->getDirName(rawFile), + ""); + + ensure_equals("getDirName/r-ext", + gDirUtilp->getDirName(rawFileExt), + ""); + + // aa/bb/cc/dd/ee[.eXt] + + ensure_equals("getDirName/no-ext", + gDirUtilp->getDirName(pathNoExt), + "aa" + delim + "bb" + delim + "cc" + delim + "dd"); + + ensure_equals("getDirName/ext", + gDirUtilp->getDirName(pathExt), + "aa" + delim + "bb" + delim + "cc" + delim + "dd"); + + // aa/bb/cc.dd/ee[.eXt] + + ensure_equals("getDirName/d-no-ext", + gDirUtilp->getDirName(dottedPathNoExt), + "aa" + delim + "bb" + delim + "cc.dd"); + + ensure_equals("getDirName/d-ext", + gDirUtilp->getDirName(dottedPathExt), + "aa" + delim + "bb" + delim + "cc.dd"); + } + + template<> template<> + void LLDirTest_object_t::test<4>() + // getExtension + { + std::string delim = gDirUtilp->getDirDelimiter(); + std::string rawFile = "foo"; + std::string rawFileExt = "foo.bAr"; + std::string rawFileNullExt = "foo."; + std::string rawExt = ".bAr"; + std::string rawDot = "."; + std::string pathNoExt = "aa" + delim + "bb" + delim + "cc" + delim + "dd" + delim + "ee"; + std::string pathExt = pathNoExt + ".eXt"; + std::string dottedPathNoExt = "aa" + delim + "bb" + delim + "cc.dd" + delim + "ee"; + std::string dottedPathExt = dottedPathNoExt + ".eXt"; + + // foo[.bAr] + + ensure_equals("getExtension/r-no-ext", + gDirUtilp->getExtension(rawFile), + ""); + + ensure_equals("getExtension/r-ext", + gDirUtilp->getExtension(rawFileExt), + "bar"); + + // foo. + + ensure_equals("getExtension/rn-no-ext", + gDirUtilp->getExtension(rawFileNullExt), + ""); + + // .bAr + // interesting case - with no basename, this IS the basename, not the extension. + + ensure_equals("getExtension/e-ext", + gDirUtilp->getExtension(rawExt), + ""); + + // . + + ensure_equals("getExtension/d", + gDirUtilp->getExtension(rawDot), + ""); + + // aa/bb/cc/dd/ee[.eXt] + + ensure_equals("getExtension/no-ext", + gDirUtilp->getExtension(pathNoExt), + ""); + + ensure_equals("getExtension/ext", + gDirUtilp->getExtension(pathExt), + "ext"); + + // aa/bb/cc.dd/ee[.eXt] + + ensure_equals("getExtension/d-no-ext", + gDirUtilp->getExtension(dottedPathNoExt), + ""); + + ensure_equals("getExtension/d-ext", + gDirUtilp->getExtension(dottedPathExt), + "ext"); + } +} + |