summaryrefslogtreecommitdiff
path: root/indra/llfilesystem/lldir.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llfilesystem/lldir.cpp')
-rw-r--r--indra/llfilesystem/lldir.cpp1134
1 files changed, 0 insertions, 1134 deletions
diff --git a/indra/llfilesystem/lldir.cpp b/indra/llfilesystem/lldir.cpp
deleted file mode 100644
index 10fbc06c61..0000000000
--- a/indra/llfilesystem/lldir.cpp
+++ /dev/null
@@ -1,1134 +0,0 @@
-/**
- * @file lldir.cpp
- * @brief implementation of directory utilities base class
- *
- * $LicenseInfo:firstyear=2002&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"
-
-#if !LL_WINDOWS
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <errno.h>
-#else
-#include <direct.h>
-#endif
-
-#include "lldir.h"
-
-#include "llerror.h"
-#include "lltimer.h" // ms_sleep()
-#include "lluuid.h"
-
-#include "lldiriterator.h"
-#include "stringize.h"
-#include "llstring.h"
-#include <boost/filesystem.hpp>
-#include <boost/foreach.hpp>
-#include <boost/range/begin.hpp>
-#include <boost/range/end.hpp>
-#include <boost/assign/list_of.hpp>
-#include <boost/bind.hpp>
-#include <boost/ref.hpp>
-#include <algorithm>
-
-using boost::assign::list_of;
-using boost::assign::map_list_of;
-
-#if LL_WINDOWS
-#include "lldir_win32.h"
-LLDir_Win32 gDirUtil;
-#elif LL_DARWIN
-#include "lldir_mac.h"
-LLDir_Mac gDirUtil;
-#elif LL_SOLARIS
-#include "lldir_solaris.h"
-LLDir_Solaris gDirUtil;
-#else
-#include "lldir_linux.h"
-LLDir_Linux gDirUtil;
-#endif
-
-LLDir *gDirUtilp = (LLDir *)&gDirUtil;
-
-/// Values for findSkinnedFilenames(subdir) parameter
-const char
- *LLDir::XUI = "xui",
- *LLDir::TEXTURES = "textures",
- *LLDir::SKINBASE = "";
-
-static const char* const empty = "";
-std::string LLDir::sDumpDir = "";
-
-LLDir::LLDir()
-: mAppName(""),
- mExecutablePathAndName(""),
- mExecutableFilename(""),
- mExecutableDir(""),
- mAppRODataDir(""),
- mOSUserDir(""),
- mOSUserAppDir(""),
- mLindenUserDir(""),
- mOSCacheDir(""),
- mCAFile(""),
- mTempDir(""),
- mDirDelimiter("/"), // fallback to forward slash if not overridden
- mLanguage("en"),
- mUserName("undefined")
-{
-}
-
-LLDir::~LLDir()
-{
-}
-
-std::vector<std::string> LLDir::getFilesInDir(const std::string &dirname)
-{
- //Returns a vector of fullpath filenames.
-
-#ifdef LL_WINDOWS // or BOOST_WINDOWS_API
- boost::filesystem::path p(utf8str_to_utf16str(dirname));
-#else
- boost::filesystem::path p(dirname);
-#endif
-
- std::vector<std::string> v;
-
- if (exists(p))
- {
- if (is_directory(p))
- {
- boost::filesystem::directory_iterator end_iter;
- for (boost::filesystem::directory_iterator dir_itr(p);
- dir_itr != end_iter;
- ++dir_itr)
- {
- if (boost::filesystem::is_regular_file(dir_itr->status()))
- {
- v.push_back(dir_itr->path().filename().string());
- }
- }
- }
- }
- return v;
-}
-
-S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask)
-{
- S32 count = 0;
- std::string filename;
- std::string fullpath;
- S32 result;
-
- // File masks starting with "/" will match nothing, so we consider them invalid.
- if (LLStringUtil::startsWith(mask, getDirDelimiter()))
- {
- LL_WARNS() << "Invalid file mask: " << mask << LL_ENDL;
- llassert(!"Invalid file mask");
- }
-
- LLDirIterator iter(dirname, mask);
- while (iter.next(filename))
- {
- fullpath = add(dirname, filename);
-
- if(LLFile::isdir(fullpath))
- {
- // skipping directory traversal filenames
- count++;
- continue;
- }
-
- S32 retry_count = 0;
- while (retry_count < 5)
- {
- if (0 != LLFile::remove(fullpath))
- {
- retry_count++;
- result = errno;
- LL_WARNS() << "Problem removing " << fullpath << " - errorcode: "
- << result << " attempt " << retry_count << LL_ENDL;
-
- if(retry_count >= 5)
- {
- LL_WARNS() << "Failed to remove " << fullpath << LL_ENDL ;
- return count ;
- }
-
- ms_sleep(100);
- }
- else
- {
- if (retry_count)
- {
- LL_WARNS() << "Successfully removed " << fullpath << LL_ENDL;
- }
- break;
- }
- }
- count++;
- }
- return count;
-}
-
-U32 LLDir::deleteDirAndContents(const std::string& dir_name)
-{
- //Removes the directory and its contents. Returns number of files deleted.
-
- U32 num_deleted = 0;
-
- try
- {
-#ifdef LL_WINDOWS // or BOOST_WINDOWS_API
- boost::filesystem::path dir_path(utf8str_to_utf16str(dir_name));
-#else
- boost::filesystem::path dir_path(dir_name);
-#endif
-
- if (boost::filesystem::exists (dir_path))
- {
- if (!boost::filesystem::is_empty (dir_path))
- { // Directory has content
- num_deleted = boost::filesystem::remove_all (dir_path);
- }
- else
- { // Directory is empty
- boost::filesystem::remove (dir_path);
- }
- }
- }
- catch (boost::filesystem::filesystem_error &er)
- {
- LL_WARNS() << "Failed to delete " << dir_name << " with error " << er.code().message() << LL_ENDL;
- }
- return num_deleted;
-}
-
-const std::string LLDir::findFile(const std::string &filename,
- 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);
-}
-
-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)
- {
- if (!search_path_iter->empty())
- {
- std::string filename_and_path = (*search_path_iter);
- if (!filename.empty())
- {
- filename_and_path += getDirDelimiter() + filename;
- }
- if (fileExists(filename_and_path))
- {
- return filename_and_path;
- }
- }
- }
- return "";
-}
-
-
-const std::string &LLDir::getExecutablePathAndName() const
-{
- return mExecutablePathAndName;
-}
-
-const std::string &LLDir::getExecutableFilename() const
-{
- return mExecutableFilename;
-}
-
-const std::string &LLDir::getExecutableDir() const
-{
- return mExecutableDir;
-}
-
-const std::string &LLDir::getWorkingDir() const
-{
- return mWorkingDir;
-}
-
-const std::string &LLDir::getAppName() const
-{
- return mAppName;
-}
-
-const std::string &LLDir::getAppRODataDir() const
-{
- return mAppRODataDir;
-}
-
-const std::string &LLDir::getOSUserDir() const
-{
- return mOSUserDir;
-}
-
-const std::string &LLDir::getOSUserAppDir() const
-{
- return mOSUserAppDir;
-}
-
-const std::string &LLDir::getLindenUserDir() const
-{
- if (mLindenUserDir.empty())
- {
- LL_DEBUGS() << "getLindenUserDir() called early, we don't have the user name yet - returning empty string to caller" << LL_ENDL;
- }
-
- return mLindenUserDir;
-}
-
-const std::string& LLDir::getChatLogsDir() const
-{
- return mChatLogsDir;
-}
-
-void LLDir::setDumpDir( const std::string& path )
-{
- LLDir::sDumpDir = path;
- if (LLStringUtil::endsWith(sDumpDir, mDirDelimiter))
- {
- sDumpDir.erase(sDumpDir.size() - mDirDelimiter.size());
- }
-}
-
-const std::string &LLDir::getDumpDir() const
-{
- if (sDumpDir.empty() )
- {
- LLUUID uid;
- uid.generate();
-
- sDumpDir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "")
- + "dump-" + uid.asString();
-
- dir_exists_or_crash(sDumpDir);
- }
-
- return LLDir::sDumpDir;
-}
-
-const std::string &LLDir::getPerAccountChatLogsDir() const
-{
- return mPerAccountChatLogsDir;
-}
-
-const std::string &LLDir::getTempDir() const
-{
- return mTempDir;
-}
-
-const std::string LLDir::getCacheDir(bool get_default) const
-{
- if (mCacheDir.empty() || get_default)
- {
- 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";
- }
- else
- {
- res = add(getOSUserAppDir(), "cache");
- }
- }
- else
- {
- res = add(getOSCacheDir(), "SecondLife");
- }
- return res;
-}
-
-
-
-const std::string &LLDir::getOSCacheDir() const
-{
- return mOSCacheDir;
-}
-
-
-const std::string &LLDir::getCAFile() const
-{
- return mCAFile;
-}
-
-const std::string &LLDir::getDirDelimiter() const
-{
- return mDirDelimiter;
-}
-
-const std::string& LLDir::getDefaultSkinDir() const
-{
- return mDefaultSkinDir;
-}
-
-const std::string &LLDir::getSkinDir() const
-{
- return mSkinDir;
-}
-
-const std::string &LLDir::getUserDefaultSkinDir() const
-{
- return mUserDefaultSkinDir;
-}
-
-const std::string &LLDir::getUserSkinDir() const
-{
- return mUserSkinDir;
-}
-
-const std::string LLDir::getSkinBaseDir() const
-{
- return mSkinBaseDir;
-}
-
-const std::string &LLDir::getLLPluginDir() const
-{
- return mLLPluginDir;
-}
-
-const std::string &LLDir::getUserName() const
-{
- return mUserName;
-}
-
-static std::string ELLPathToString(ELLPath location)
-{
- typedef std::map<ELLPath, const char*> ELLPathMap;
-#define ENT(symbol) (symbol, #symbol)
- static const ELLPathMap sMap = map_list_of
- ENT(LL_PATH_NONE)
- ENT(LL_PATH_USER_SETTINGS)
- ENT(LL_PATH_APP_SETTINGS)
- ENT(LL_PATH_PER_SL_ACCOUNT) // returns/expands to blank string if we don't know the account name yet
- ENT(LL_PATH_CACHE)
- ENT(LL_PATH_CHARACTER)
- ENT(LL_PATH_HELP)
- ENT(LL_PATH_LOGS)
- ENT(LL_PATH_TEMP)
- ENT(LL_PATH_SKINS)
- ENT(LL_PATH_TOP_SKIN)
- ENT(LL_PATH_CHAT_LOGS)
- ENT(LL_PATH_PER_ACCOUNT_CHAT_LOGS)
- ENT(LL_PATH_USER_SKIN)
- ENT(LL_PATH_LOCAL_ASSETS)
- ENT(LL_PATH_EXECUTABLE)
- ENT(LL_PATH_DEFAULT_SKIN)
- ENT(LL_PATH_FONTS)
- ENT(LL_PATH_LAST)
- ;
-#undef ENT
-
- ELLPathMap::const_iterator found = sMap.find(location);
- if (found != sMap.end())
- return found->second;
- return STRINGIZE("Invalid ELLPath value " << location);
-}
-
-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& 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)
- {
- case LL_PATH_NONE:
- // Do nothing
- break;
-
- case LL_PATH_APP_SETTINGS:
- prefix = add(getAppRODataDir(), "app_settings");
- break;
-
- case LL_PATH_CHARACTER:
- prefix = add(getAppRODataDir(), "character");
- break;
-
- case LL_PATH_HELP:
- prefix = "help";
- break;
-
- case LL_PATH_CACHE:
- prefix = getCacheDir();
- break;
-
- case LL_PATH_DUMP:
- prefix=getDumpDir();
- break;
-
- case LL_PATH_USER_SETTINGS:
- prefix = add(getOSUserAppDir(), "user_settings");
- break;
-
- 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.
- LL_DEBUGS("LLDir") << "getLindenUserDir() not yet set: "
- << ELLPathToString(location)
- << ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename
- << "' => ''" << LL_ENDL;
- return std::string();
- }
- break;
-
- case LL_PATH_CHAT_LOGS:
- prefix = getChatLogsDir();
- break;
-
- case LL_PATH_PER_ACCOUNT_CHAT_LOGS:
- prefix = getPerAccountChatLogsDir();
- if (prefix.empty())
- {
- // potentially directory was not set yet
- // intentionally return a blank string to the caller
- LL_DEBUGS("LLDir") << "Conversation log directory is not yet set" << LL_ENDL;
- return std::string();
- }
- break;
-
- case LL_PATH_LOGS:
- prefix = add(getOSUserAppDir(), "logs");
- break;
-
- case LL_PATH_TEMP:
- prefix = getTempDir();
- break;
-
- case LL_PATH_TOP_SKIN:
- prefix = getSkinDir();
- break;
-
- case LL_PATH_DEFAULT_SKIN:
- prefix = getDefaultSkinDir();
- break;
-
- case LL_PATH_USER_SKIN:
- prefix = getUserSkinDir();
- break;
-
- case LL_PATH_SKINS:
- prefix = getSkinBaseDir();
- break;
-
- case LL_PATH_LOCAL_ASSETS:
- prefix = add(getAppRODataDir(), "local_assets");
- break;
-
- case LL_PATH_EXECUTABLE:
- prefix = getExecutableDir();
- break;
-
- case LL_PATH_FONTS:
- prefix = add(getAppRODataDir(), "fonts");
- break;
-
- default:
- llassert(0);
- }
-
- if (prefix.empty())
- {
- LL_WARNS() << ELLPathToString(location)
- << ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename
- << "': prefix is empty, possible bad filename" << LL_ENDL;
- }
-
- std::string expanded_filename = add(prefix, subdir1, subdir2);
- if (expanded_filename.empty() && in_filename.empty())
- {
- return "";
- }
- // Use explicit concatenation here instead of another add() call. Callers
- // passing in_filename as "" expect to obtain a pathname ending with
- // mDirSeparator so they can later directly concatenate with a specific
- // filename. A caller using add() doesn't care, but there's still code
- // loose in the system that uses std::string::operator+().
- expanded_filename += mDirDelimiter;
- expanded_filename += in_filename;
-
- LL_DEBUGS("LLDir") << ELLPathToString(location)
- << ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename
- << "' => '" << expanded_filename << "'" << LL_ENDL;
- 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::findSkinnedFilenameBaseLang(const std::string &subdir,
- const std::string &filename,
- ESkinConstraint constraint) const
-{
- // This implementation is basically just as described in the declaration comments.
- std::vector<std::string> found(findSkinnedFilenames(subdir, filename, constraint));
- if (found.empty())
- {
- return "";
- }
- return found.front();
-}
-
-std::string LLDir::findSkinnedFilename(const std::string &subdir,
- const std::string &filename,
- ESkinConstraint constraint) const
-{
- // This implementation is basically just as described in the declaration comments.
- std::vector<std::string> found(findSkinnedFilenames(subdir, filename, constraint));
- if (found.empty())
- {
- return "";
- }
- return found.back();
-}
-
-// This method exists because the two code paths for
-// findSkinnedFilenames(ALL_SKINS) and findSkinnedFilenames(CURRENT_SKIN) must
-// generate the list of candidate pathnames in identical ways. The only
-// difference is in the body of the inner loop.
-template <typename FUNCTION>
-void LLDir::walkSearchSkinDirs(const std::string& subdir,
- const std::vector<std::string>& subsubdirs,
- const std::string& filename,
- const FUNCTION& function) const
-{
- BOOST_FOREACH(std::string skindir, mSearchSkinDirs)
- {
- std::string subdir_path(add(skindir, subdir));
- BOOST_FOREACH(std::string subsubdir, subsubdirs)
- {
- std::string full_path(add(subdir_path, subsubdir, filename));
- if (fileExists(full_path))
- {
- function(subsubdir, full_path);
- }
- }
- }
-}
-
-// ridiculous little helper function that should go away when we can use lambda
-inline void push_back(std::vector<std::string>& vector, const std::string& value)
-{
- vector.push_back(value);
-}
-
-typedef std::map<std::string, std::string> StringMap;
-// ridiculous little helper function that should go away when we can use lambda
-inline void store_in_map(StringMap& map, const std::string& key, const std::string& value)
-{
- map[key] = value;
-}
-
-std::vector<std::string> LLDir::findSkinnedFilenames(const std::string& subdir,
- const std::string& filename,
- ESkinConstraint constraint) const
-{
- // Recognize subdirs that have no localization.
- static const std::set<std::string> sUnlocalized = list_of
- ("") // top-level directory not localized
- ("textures") // textures not localized
- ;
-
- LL_DEBUGS("LLDir") << "subdir '" << subdir << "', filename '" << filename
- << "', constraint "
- << ((constraint == CURRENT_SKIN)? "CURRENT_SKIN" : "ALL_SKINS")
- << LL_ENDL;
-
- // Build results vector.
- std::vector<std::string> results;
- // Disallow filenames that may escape subdir
- if (filename.find("..") != std::string::npos)
- {
- LL_WARNS("LLDir") << "Ignoring potentially relative filename '" << filename << "'" << LL_ENDL;
- return results;
- }
-
- // Cache the default language directory for each subdir we've encountered.
- // A cache entry whose value is the empty string means "not localized,
- // don't bother checking again."
- static StringMap sLocalized;
-
- // Check whether we've already discovered if this subdir is localized.
- StringMap::const_iterator found = sLocalized.find(subdir);
- if (found == sLocalized.end())
- {
- // We have not yet determined that. Is it one of the subdirs "known"
- // to be unlocalized?
- if (sUnlocalized.find(subdir) != sUnlocalized.end())
- {
- // This subdir is known to be unlocalized. Remember that.
- found = sLocalized.insert(StringMap::value_type(subdir, "")).first;
- }
- else
- {
- // We do not recognize this subdir. Investigate.
- std::string subdir_path(add(getDefaultSkinDir(), subdir));
- if (fileExists(add(subdir_path, "en")))
- {
- // defaultSkinDir/subdir contains subdir "en". That's our
- // default language; this subdir is localized.
- found = sLocalized.insert(StringMap::value_type(subdir, "en")).first;
- }
- else if (fileExists(add(subdir_path, "en-us")))
- {
- // defaultSkinDir/subdir contains subdir "en-us" but not "en".
- // Set as default language; this subdir is localized.
- found = sLocalized.insert(StringMap::value_type(subdir, "en-us")).first;
- }
- else
- {
- // defaultSkinDir/subdir contains neither "en" nor "en-us".
- // Assume it's not localized. Remember that assumption.
- found = sLocalized.insert(StringMap::value_type(subdir, "")).first;
- }
- }
- }
- // Every code path above should have resulted in 'found' becoming a valid
- // iterator to an entry in sLocalized.
- llassert(found != sLocalized.end());
-
- // Now -- is this subdir localized, or not? The answer determines what
- // subdirectories we check (under subdir) for the requested filename.
- std::vector<std::string> subsubdirs;
- if (found->second.empty())
- {
- // subdir is not localized. filename should be located directly within it.
- subsubdirs.push_back("");
- }
- else
- {
- // subdir is localized, and found->second is the default language
- // directory within it. Check both the default language and the
- // current language -- if it differs from the default, of course.
- subsubdirs.push_back(found->second);
- if (mLanguage != found->second)
- {
- subsubdirs.push_back(mLanguage);
- }
- }
-
- // The process we use depends on 'constraint'.
- if (constraint != CURRENT_SKIN) // meaning ALL_SKINS
- {
- // ALL_SKINS is simpler: just return every pathname generated by
- // walkSearchSkinDirs(). Tricky bit: walkSearchSkinDirs() passes its
- // FUNCTION the subsubdir as well as the full pathname. We just want
- // the full pathname.
- walkSearchSkinDirs(subdir, subsubdirs, filename,
- boost::bind(push_back, boost::ref(results), _2));
- }
- else // CURRENT_SKIN
- {
- // CURRENT_SKIN turns out to be a bit of a misnomer because we might
- // still return files from two different skins. In any case, this
- // value of 'constraint' means we will return at most two paths: one
- // for the default language, one for the current language (supposing
- // those differ).
- // It is important to allow a user to override only the localization
- // for a particular file, for all viewer installs, without also
- // overriding the default-language file.
- // It is important to allow a user to override only the default-
- // language file, for all viewer installs, without also overriding the
- // applicable localization of that file.
- // Therefore, treat the default language and the current language as
- // two separate cases. For each, capture the most-specialized file
- // that exists.
- // Use a map keyed by subsubdir (i.e. language code). This allows us
- // to handle the case of a single subsubdirs entry with the same logic
- // that handles two. For every real file path generated by
- // walkSearchSkinDirs(), update the map entry for its subsubdir.
- StringMap path_for;
- walkSearchSkinDirs(subdir, subsubdirs, filename,
- boost::bind(store_in_map, boost::ref(path_for), _1, _2));
- // Now that we have a path for each of the default language and the
- // current language, copy them -- in proper order -- into results.
- // Don't drive this by walking the map itself: it matters that we
- // generate results in the same order as subsubdirs.
- BOOST_FOREACH(std::string subsubdir, subsubdirs)
- {
- StringMap::const_iterator found(path_for.find(subsubdir));
- if (found != path_for.end())
- {
- results.push_back(found->second);
- }
- }
- }
-
- LL_DEBUGS("LLDir") << empty;
- const char* comma = "";
- BOOST_FOREACH(std::string path, results)
- {
- LL_CONT << comma << "'" << path << "'";
- comma = ", ";
- }
- LL_CONT << LL_ENDL;
-
- return results;
-}
-
-std::string LLDir::getTempFilename() const
-{
- LLUUID random_uuid;
- std::string uuid_str;
-
- random_uuid.generate();
- random_uuid.toString(uuid_str);
-
- return add(getTempDir(), uuid_str + ".tmp");
-}
-
-// static
-std::string LLDir::getScrubbedFileName(const std::string uncleanFileName)
-{
- 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.
- std::string userlower(username);
- LLStringUtil::toLower(userlower);
- LLStringUtil::replaceChar(userlower, ' ', '_');
- mLindenUserDir = add(getOSUserAppDir(), userlower);
- }
- else
- {
- LL_ERRS() << "NULL name for LLDir::setLindenUserDir" << LL_ENDL;
- }
-
- dumpCurrentDirectories();
-}
-
-void LLDir::setChatLogsDir(const std::string &path)
-{
- if (!path.empty() )
- {
- mChatLogsDir = path;
- }
- else
- {
- LL_WARNS() << "Invalid name for LLDir::setChatLogsDir" << LL_ENDL;
- }
-}
-
-void LLDir::updatePerAccountChatLogsDir()
-{
- mPerAccountChatLogsDir = add(getChatLogsDir(), mUserName);
-}
-
-void LLDir::setPerAccountChatLogsDir(const std::string &username)
-{
- // if both first and last aren't set, assume we're grabbing the cached dir
- if (!username.empty())
- {
- // some platforms have case-sensitive filesystems, so be
- // utterly consistent with our firstname/lastname case.
- std::string userlower(username);
- LLStringUtil::toLower(userlower);
- LLStringUtil::replaceChar(userlower, ' ', '_');
-
- mUserName = userlower;
- updatePerAccountChatLogsDir();
- }
- else
- {
- LL_ERRS() << "NULL name for LLDir::setPerAccountChatLogsDir" << LL_ENDL;
- }
-}
-
-void LLDir::setSkinFolder(const std::string &skin_folder, const std::string& language)
-{
- LL_DEBUGS("LLDir") << "Setting skin '" << skin_folder << "', language '" << language << "'"
- << LL_ENDL;
- mSkinName = skin_folder;
- mLanguage = language;
-
- // This method is called multiple times during viewer initialization. Each
- // time it's called, reset mSearchSkinDirs.
- mSearchSkinDirs.clear();
-
- // base skin which is used as fallback for all skinned files
- // e.g. c:\program files\secondlife\skins\default
- mDefaultSkinDir = getSkinBaseDir();
- append(mDefaultSkinDir, "default");
- // This is always the most general of the search skin directories.
- addSearchSkinDir(mDefaultSkinDir);
-
- mSkinDir = getSkinBaseDir();
- append(mSkinDir, skin_folder);
- // Next level of generality is a skin installed with the viewer.
- addSearchSkinDir(mSkinDir);
-
- // user modifications to skins, current and default
- // e.g. c:\documents and settings\users\username\application data\second life\skins\dazzle
- mUserSkinDir = getOSUserAppDir();
- append(mUserSkinDir, "skins");
- mUserDefaultSkinDir = mUserSkinDir;
- append(mUserDefaultSkinDir, "default");
- append(mUserSkinDir, skin_folder);
- // Next level of generality is user modifications to default skin...
- addSearchSkinDir(mUserDefaultSkinDir);
- // then user-defined skins.
- addSearchSkinDir(mUserSkinDir);
-}
-
-void LLDir::addSearchSkinDir(const std::string& skindir)
-{
- if (std::find(mSearchSkinDirs.begin(), mSearchSkinDirs.end(), skindir) == mSearchSkinDirs.end())
- {
- LL_DEBUGS("LLDir") << "search skin: '" << skindir << "'" << LL_ENDL;
- mSearchSkinDirs.push_back(skindir);
- }
-}
-
-std::string LLDir::getSkinFolder() const
-{
- return mSkinName;
-}
-
-std::string LLDir::getLanguage() const
-{
- return mLanguage;
-}
-
-bool LLDir::setCacheDir(const std::string &path)
-{
- if (path.empty() )
- {
- // reset to default
- mCacheDir = "";
- return true;
- }
- else
- {
- LLFile::mkdir(path);
- std::string tempname = add(path, "temp");
- LLFILE* file = LLFile::fopen(tempname,"wt");
- if (file)
- {
- fclose(file);
- LLFile::remove(tempname);
- mCacheDir = path;
- return true;
- }
- return false;
- }
-}
-
-void LLDir::dumpCurrentDirectories(LLError::ELevel level)
-{
- LL_VLOGS(level, "AppInit","Directories") << "Current Directories:" << LL_ENDL;
-
- LL_VLOGS(level, "AppInit", "Directories") << " CurPath: " << getCurPath() << LL_ENDL;
- LL_VLOGS(level, "AppInit", "Directories") << " AppName: " << getAppName() << LL_ENDL;
- LL_VLOGS(level, "AppInit", "Directories") << " ExecutableFilename: " << getExecutableFilename() << LL_ENDL;
- LL_VLOGS(level, "AppInit", "Directories") << " ExecutableDir: " << getExecutableDir() << LL_ENDL;
- LL_VLOGS(level, "AppInit", "Directories") << " ExecutablePathAndName: " << getExecutablePathAndName() << LL_ENDL;
- LL_VLOGS(level, "AppInit", "Directories") << " WorkingDir: " << getWorkingDir() << LL_ENDL;
- LL_VLOGS(level, "AppInit", "Directories") << " AppRODataDir: " << getAppRODataDir() << LL_ENDL;
- LL_VLOGS(level, "AppInit", "Directories") << " OSUserDir: " << getOSUserDir() << LL_ENDL;
- LL_VLOGS(level, "AppInit", "Directories") << " OSUserAppDir: " << getOSUserAppDir() << LL_ENDL;
- LL_VLOGS(level, "AppInit", "Directories") << " LindenUserDir: " << getLindenUserDir() << LL_ENDL;
- LL_VLOGS(level, "AppInit", "Directories") << " TempDir: " << getTempDir() << LL_ENDL;
- LL_VLOGS(level, "AppInit", "Directories") << " CAFile: " << getCAFile() << LL_ENDL;
- LL_VLOGS(level, "AppInit", "Directories") << " SkinBaseDir: " << getSkinBaseDir() << LL_ENDL;
- LL_VLOGS(level, "AppInit", "Directories") << " SkinDir: " << getSkinDir() << LL_ENDL;
-}
-
-void LLDir::append(std::string& destpath, const std::string& name) const
-{
- // Delegate question of whether we need a separator to helper method.
- SepOff sepoff(needSep(destpath, name));
- if (sepoff.first) // do we need a separator?
- {
- destpath += mDirDelimiter;
- }
- // If destpath ends with a separator, AND name starts with one, skip
- // name's leading separator.
- destpath += name.substr(sepoff.second);
-}
-
-LLDir::SepOff LLDir::needSep(const std::string& path, const std::string& name) const
-{
- if (path.empty() || name.empty())
- {
- // If either path or name are empty, we do not need a separator
- // between them.
- return SepOff(false, 0);
- }
- // Here we know path and name are both non-empty. But if path already ends
- // with a separator, or if name already starts with a separator, we need
- // not add one.
- std::string::size_type seplen(mDirDelimiter.length());
- bool path_ends_sep(path.substr(path.length() - seplen) == mDirDelimiter);
- bool name_starts_sep(name.substr(0, seplen) == mDirDelimiter);
- if ((! path_ends_sep) && (! name_starts_sep))
- {
- // If neither path nor name brings a separator to the junction, then
- // we need one.
- return SepOff(true, 0);
- }
- if (path_ends_sep && name_starts_sep)
- {
- // But if BOTH path and name bring a separator, we need not add one.
- // Moreover, we should actually skip the leading separator of 'name'.
- return SepOff(false, (unsigned short)seplen);
- }
- // Here we know that either path_ends_sep or name_starts_sep is true --
- // but not both. So don't add a separator, and don't skip any characters:
- // simple concatenation will do the trick.
- return SepOff(false, 0);
-}
-
-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, 0700);
-#else
- struct stat dir_stat;
- if(0 != LLFile::stat(dir_name, &dir_stat))
- {
- S32 stat_rv = errno;
- if(ENOENT == stat_rv)
- {
- if(0 != LLFile::mkdir(dir_name, 0700)) // octal
- {
- LL_ERRS() << "Unable to create directory: " << dir_name << LL_ENDL;
- }
- }
- else
- {
- LL_ERRS() << "Unable to stat: " << dir_name << " errno = " << stat_rv
- << LL_ENDL;
- }
- }
- else
- {
- // data_dir exists, make sure it's a directory.
- if(!S_ISDIR(dir_stat.st_mode))
- {
- LL_ERRS() << "Data directory collision: " << dir_name << LL_ENDL;
- }
- }
-#endif
-}