summaryrefslogtreecommitdiff
path: root/indra/llvfs/lldir.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llvfs/lldir.cpp')
-rw-r--r--indra/llvfs/lldir.cpp376
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;
}