diff options
Diffstat (limited to 'indra/llvfs/lldir.cpp')
-rw-r--r-- | indra/llvfs/lldir.cpp | 376 |
1 files changed, 273 insertions, 103 deletions
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; } |