summaryrefslogtreecommitdiff
path: root/indra/llvfs
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llvfs')
-rwxr-xr-x[-rw-r--r--]indra/llvfs/CMakeLists.txt53
-rwxr-xr-x[-rw-r--r--]indra/llvfs/lldir.cpp760
-rwxr-xr-x[-rw-r--r--]indra/llvfs/lldir.h160
-rwxr-xr-x[-rw-r--r--]indra/llvfs/lldir_linux.cpp178
-rwxr-xr-x[-rw-r--r--]indra/llvfs/lldir_linux.h50
-rwxr-xr-x[-rw-r--r--]indra/llvfs/lldir_mac.cpp420
-rwxr-xr-x[-rw-r--r--]indra/llvfs/lldir_mac.h55
-rwxr-xr-x[-rw-r--r--]indra/llvfs/lldir_solaris.cpp180
-rwxr-xr-x[-rw-r--r--]indra/llvfs/lldir_solaris.h48
-rwxr-xr-x[-rw-r--r--]indra/llvfs/lldir_win32.cpp220
-rwxr-xr-x[-rw-r--r--]indra/llvfs/lldir_win32.h46
-rwxr-xr-x[-rw-r--r--]indra/llvfs/lldirguard.h38
-rwxr-xr-xindra/llvfs/lldiriterator.cpp239
-rwxr-xr-xindra/llvfs/lldiriterator.h87
-rwxr-xr-x[-rw-r--r--]indra/llvfs/lllfsthread.cpp64
-rwxr-xr-x[-rw-r--r--]indra/llvfs/lllfsthread.h36
-rw-r--r--[-rwxr-xr-x]indra/llvfs/llpidlock.cpp55
-rw-r--r--[-rwxr-xr-x]indra/llvfs/llpidlock.h67
-rwxr-xr-x[-rw-r--r--]indra/llvfs/llvfile.cpp86
-rwxr-xr-x[-rw-r--r--]indra/llvfs/llvfile.h36
-rwxr-xr-x[-rw-r--r--]indra/llvfs/llvfs.cpp248
-rwxr-xr-x[-rw-r--r--]indra/llvfs/llvfs.h37
-rwxr-xr-xindra/llvfs/llvfs_objc.h43
-rwxr-xr-xindra/llvfs/llvfs_objc.mm108
-rwxr-xr-x[-rw-r--r--]indra/llvfs/llvfsthread.cpp64
-rwxr-xr-x[-rw-r--r--]indra/llvfs/llvfsthread.h36
-rwxr-xr-x[-rw-r--r--]indra/llvfs/tests/lldir_test.cpp545
-rwxr-xr-xindra/llvfs/tests/lldiriterator_test.cpp65
28 files changed, 2443 insertions, 1581 deletions
diff --git a/indra/llvfs/CMakeLists.txt b/indra/llvfs/CMakeLists.txt
index 05c7c7860c..67dce8c073 100644..100755
--- a/indra/llvfs/CMakeLists.txt
+++ b/indra/llvfs/CMakeLists.txt
@@ -8,10 +8,12 @@ include(UnixInstall)
include_directories(
${LLCOMMON_INCLUDE_DIRS}
+ ${LLCOMMON_SYSTEM_INCLUDE_DIRS}
)
set(llvfs_SOURCE_FILES
lldir.cpp
+ lldiriterator.cpp
lllfsthread.cpp
llpidlock.cpp
llvfile.cpp
@@ -24,6 +26,7 @@ set(llvfs_HEADER_FILES
lldir.h
lldirguard.h
+ lldiriterator.h
lllfsthread.h
llpidlock.h
llvfile.h
@@ -34,18 +37,20 @@ set(llvfs_HEADER_FILES
if (DARWIN)
LIST(APPEND llvfs_SOURCE_FILES lldir_mac.cpp)
LIST(APPEND llvfs_HEADER_FILES lldir_mac.h)
+ LIST(APPEND llvfs_SOURCE_FILES llvfs_objc.mm)
+ LIST(APPEND llvfs_HEADER_FILES llvfs_objc.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)
+ if (INSTALL)
set_source_files_properties(lldir_linux.cpp
PROPERTIES COMPILE_FLAGS
"-DAPP_RO_DATA_DIR=\\\"${APP_SHARE_DIR}\\\""
)
- endif (VIEWER AND INSTALL)
+ endif (INSTALL)
endif (LINUX)
if (WINDOWS)
@@ -60,22 +65,40 @@ list(APPEND llvfs_SOURCE_FILES ${llvfs_HEADER_FILES})
add_library (llvfs ${llvfs_SOURCE_FILES})
+set(vfs_BOOST_LIBRARIES
+ ${BOOST_FILESYSTEM_LIBRARY}
+ ${BOOST_SYSTEM_LIBRARY}
+ )
+
+target_link_libraries(llvfs
+ ${LLCOMMON_LIBRARIES}
+ ${vfs_BOOST_LIBRARIES}
+ )
+
if (DARWIN)
include(CMakeFindFrameworks)
- find_library(CARBON_LIBRARY Carbon)
- target_link_libraries(llvfs ${CARBON_LIBRARY})
+ find_library(COCOA_LIBRARY Cocoa)
+ target_link_libraries(llvfs ${COCOA_LIBRARY})
endif (DARWIN)
# 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}")
+if (LL_TESTS)
+ include(LLAddBuildTest)
+ # UNIT TESTS
+ SET(llvfs_TEST_SOURCE_FILES
+ lldiriterator.cpp
+ )
+
+ set_source_files_properties(lldiriterator.cpp
+ PROPERTIES
+ LL_TEST_ADDITIONAL_LIBRARIES "${vfs_BOOST_LIBRARIES}"
+ )
+ 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 da4abde451..5f4fb8f4a0 100644..100755
--- a/indra/llvfs/lldir.cpp
+++ b/indra/llvfs/lldir.cpp
@@ -2,31 +2,25 @@
* @file lldir.cpp
* @brief implementation of directory utilities base class
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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$
*/
@@ -46,6 +40,20 @@
#include "lltimer.h" // ms_sleep()
#include "lluuid.h"
+#include "lldiriterator.h"
+#include "stringize.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;
@@ -62,6 +70,15 @@ LLDir_Linux gDirUtil;
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(""),
@@ -74,7 +91,9 @@ LLDir::LLDir()
mOSCacheDir(""),
mCAFile(""),
mTempDir(""),
- mDirDelimiter("/") // fallback to forward slash if not overridden
+ mDirDelimiter("/"), // fallback to forward slash if not overridden
+ mLanguage("en"),
+ mUserName("undefined")
{
}
@@ -82,50 +101,118 @@ LLDir::~LLDir()
{
}
-
+std::vector<std::string> LLDir::getFilesInDir(const std::string &dirname)
+{
+ //Returns a vector of fullpath filenames.
+
+ boost::filesystem::path p (dirname);
+ 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;
- while (getNextFileInDir(dirname, mask, filename, FALSE))
+
+ // File masks starting with "/" will match nothing, so we consider them invalid.
+ if (LLStringUtil::startsWith(mask, getDirDelimiter()))
{
- if ((filename == ".") || (filename == ".."))
+ 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;
}
- fullpath = dirname;
- fullpath += getDirDelimiter();
- fullpath += filename;
S32 retry_count = 0;
while (retry_count < 5)
{
if (0 != LLFile::remove(fullpath))
{
+ retry_count++;
result = errno;
- llwarns << "Problem removing " << fullpath << " - errorcode: "
- << result << " attempt " << retry_count << llendl;
- ms_sleep(1000);
+ 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)
{
- llwarns << "Successfully removed " << fullpath << llendl;
+ LL_WARNS() << "Successfully removed " << fullpath << LL_ENDL;
}
break;
- }
- retry_count++;
+ }
}
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
+ {
+ boost::filesystem::path dir_path(dir_name);
+ 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,
@@ -147,7 +234,11 @@ const std::string LLDir::findFile(const std::string& filename, const std::vector
{
if (!search_path_iter->empty())
{
- std::string filename_and_path = (*search_path_iter) + getDirDelimiter() + filename;
+ 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;
@@ -202,17 +293,42 @@ 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;
+ 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
+const std::string& LLDir::getChatLogsDir() const
{
return mChatLogsDir;
}
+void LLDir::setDumpDir( const std::string& path )
+{
+ LLDir::sDumpDir = path;
+ if (! sDumpDir.empty() && sDumpDir.rbegin() == mDirDelimiter.rbegin() )
+ {
+ sDumpDir.erase(sDumpDir.size() -1);
+ }
+}
+
+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;
@@ -253,12 +369,12 @@ std::string LLDir::buildSLOSCacheDir() const
}
else
{
- res = getOSUserAppDir() + mDirDelimiter + "cache";
+ res = add(getOSUserAppDir(), "cache");
}
}
else
{
- res = getOSCacheDir() + mDirDelimiter + "SecondLife";
+ res = add(getOSCacheDir(), "SecondLife");
}
return res;
}
@@ -281,19 +397,24 @@ 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::getUserSkinDir() const
+const std::string &LLDir::getUserDefaultSkinDir() const
{
- return mUserSkinDir;
+ return mUserDefaultSkinDir;
}
-const std::string& LLDir::getDefaultSkinDir() const
+const std::string &LLDir::getUserSkinDir() const
{
- return mDefaultSkinDir;
+ return mUserSkinDir;
}
const std::string LLDir::getSkinBaseDir() const
@@ -306,6 +427,44 @@ 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);
@@ -326,15 +485,11 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd
break;
case LL_PATH_APP_SETTINGS:
- prefix = getAppRODataDir();
- prefix += mDirDelimiter;
- prefix += "app_settings";
+ prefix = add(getAppRODataDir(), "app_settings");
break;
case LL_PATH_CHARACTER:
- prefix = getAppRODataDir();
- prefix += mDirDelimiter;
- prefix += "character";
+ prefix = add(getAppRODataDir(), "character");
break;
case LL_PATH_HELP:
@@ -345,17 +500,27 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd
prefix = getCacheDir();
break;
+ case LL_PATH_DUMP:
+ prefix=getDumpDir();
+ break;
+
case LL_PATH_USER_SETTINGS:
- prefix = getOSUserAppDir();
- prefix += mDirDelimiter;
- prefix += "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.
+ // 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;
@@ -369,9 +534,7 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd
break;
case LL_PATH_LOGS:
- prefix = getOSUserAppDir();
- prefix += mDirDelimiter;
- prefix += "logs";
+ prefix = add(getOSUserAppDir(), "logs");
break;
case LL_PATH_TEMP:
@@ -387,11 +550,7 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd
break;
case LL_PATH_USER_SKIN:
- prefix = getOSUserAppDir();
- prefix += mDirDelimiter;
- prefix += "user_settings";
- prefix += mDirDelimiter;
- prefix += "skins";
+ prefix = getUserSkinDir();
break;
case LL_PATH_SKINS:
@@ -399,9 +558,7 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd
break;
case LL_PATH_LOCAL_ASSETS:
- prefix = getAppRODataDir();
- prefix += mDirDelimiter;
- prefix += "local_assets";
+ prefix = add(getAppRODataDir(), "local_assets");
break;
case LL_PATH_EXECUTABLE:
@@ -409,57 +566,36 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd
break;
case LL_PATH_FONTS:
- prefix = getAppRODataDir();
- prefix += mDirDelimiter;
- prefix += "fonts";
+ prefix = add(getAppRODataDir(), "fonts");
break;
default:
llassert(0);
}
- std::string filename = in_filename;
- if (!subdir2.empty())
- {
- filename = subdir2 + mDirDelimiter + filename;
- }
-
- if (!subdir1.empty())
- {
- filename = subdir1 + mDirDelimiter + filename;
- }
-
if (prefix.empty())
{
- llwarns << "prefix is empty, possible bad filename" << llendl;
+ LL_WARNS() << ELLPathToString(location)
+ << ", '" << subdir1 << "', '" << subdir2 << "', '" << in_filename
+ << "': prefix is empty, possible bad filename" << LL_ENDL;
}
-
- std::string expanded_filename;
- if (!filename.empty())
- {
- if (!prefix.empty())
- {
- expanded_filename += prefix;
- expanded_filename += mDirDelimiter;
- expanded_filename += filename;
- }
- else
- {
- expanded_filename = filename;
- }
- }
- else if (!prefix.empty())
- {
- // Directory only, no file name.
- expanded_filename = prefix;
- }
- else
+
+ std::string expanded_filename = add(add(prefix, subdir1), subdir2);
+ if (expanded_filename.empty() && in_filename.empty())
{
- expanded_filename.assign("");
+ return "";
}
-
- //llinfos << "*** EXPANDED FILENAME: <" << expanded_filename << ">" << llendl;
-
+ // 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;
}
@@ -499,31 +635,207 @@ std::string LLDir::getExtension(const std::string& filepath) const
return exten;
}
-std::string LLDir::findSkinnedFilename(const std::string &filename) const
+std::string LLDir::findSkinnedFilenameBaseLang(const std::string &subdir,
+ const std::string &filename,
+ ESkinConstraint constraint) const
{
- return findSkinnedFilename("", "", filename);
+ // 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) const
+std::string LLDir::findSkinnedFilename(const std::string &subdir,
+ const std::string &filename,
+ ESkinConstraint constraint) const
{
- return findSkinnedFilename("", subdir, filename);
+ // 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();
}
-std::string LLDir::findSkinnedFilename(const std::string &subdir1, const std::string &subdir2, const std::string &filename) const
+// 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
{
- // generate subdirectory path fragment, e.g. "/foo/bar", "/foo", ""
- std::string subdirs = ((subdir1.empty() ? "" : mDirDelimiter) + subdir1)
- + ((subdir2.empty() ? "" : mDirDelimiter) + subdir2);
+ BOOST_FOREACH(std::string skindir, mSearchSkinDirs)
+ {
+ std::string subdir_path(add(skindir, subdir));
+ BOOST_FOREACH(std::string subsubdir, subsubdirs)
+ {
+ std::string full_path(add(add(subdir_path, subsubdir), filename));
+ if (fileExists(full_path))
+ {
+ function(subsubdir, full_path);
+ }
+ }
+ }
+}
- 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
+// 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);
+}
- std::string found_file = findFile(filename, search_paths);
- return found_file;
+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;
+
+ // 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);
+ }
+ }
+
+ // Build results vector.
+ std::vector<std::string> results;
+ // 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
@@ -534,12 +846,7 @@ std::string LLDir::getTempFilename() const
random_uuid.generate();
random_uuid.toString(uuid_str);
- std::string temp_filename = getTempDir();
- temp_filename += mDirDelimiter;
- temp_filename += uuid_str;
- temp_filename += ".tmp";
-
- return temp_filename;
+ return add(getTempDir(), uuid_str + ".tmp");
}
// static
@@ -565,27 +872,21 @@ std::string LLDir::getForbiddenFileChars()
return "\\/:*?\"<>|";
}
-void LLDir::setLindenUserDir(const std::string &first, const std::string &last)
+void LLDir::setLindenUserDir(const std::string &username)
{
- // if both first and last aren't set, that's bad.
- if (!first.empty() && !last.empty())
+ // 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 firstlower(first);
- LLStringUtil::toLower(firstlower);
- std::string lastlower(last);
- LLStringUtil::toLower(lastlower);
- mLindenUserDir = getOSUserAppDir();
- mLindenUserDir += mDirDelimiter;
- mLindenUserDir += firstlower;
- mLindenUserDir += "_";
- mLindenUserDir += lastlower;
- llinfos << "Got name for LLDir::setLindenUserDir(first='" << first << "', last='" << last << "')" << llendl;
+ std::string userlower(username);
+ LLStringUtil::toLower(userlower);
+ LLStringUtil::replaceChar(userlower, ' ', '_');
+ mLindenUserDir = add(getOSUserAppDir(), userlower);
}
else
{
- llerrs << "Invalid name for LLDir::setLindenUserDir(first='" << first << "', last='" << last << "')" << llendl;
+ LL_ERRS() << "NULL name for LLDir::setLindenUserDir" << LL_ENDL;
}
dumpCurrentDirectories();
@@ -599,52 +900,88 @@ void LLDir::setChatLogsDir(const std::string &path)
}
else
{
- llwarns << "Invalid name for LLDir::setChatLogsDir" << llendl;
+ LL_WARNS() << "Invalid name for LLDir::setChatLogsDir" << LL_ENDL;
}
}
-void LLDir::setPerAccountChatLogsDir(const std::string &first, const std::string &last)
+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 (!first.empty() && !last.empty())
+ if (!username.empty())
{
// some platforms have case-sensitive filesystems, so be
// utterly consistent with our firstname/lastname case.
- std::string firstlower(first);
- LLStringUtil::toLower(firstlower);
- std::string lastlower(last);
- LLStringUtil::toLower(lastlower);
- mPerAccountChatLogsDir = getChatLogsDir();
- mPerAccountChatLogsDir += mDirDelimiter;
- mPerAccountChatLogsDir += firstlower;
- mPerAccountChatLogsDir += "_";
- mPerAccountChatLogsDir += lastlower;
+ std::string userlower(username);
+ LLStringUtil::toLower(userlower);
+ LLStringUtil::replaceChar(userlower, ' ', '_');
+
+ mUserName = userlower;
+ updatePerAccountChatLogsDir();
}
else
{
- llwarns << "Invalid name for LLDir::setPerAccountChatLogsDir" << llendl;
+ LL_ERRS() << "NULL name for LLDir::setPerAccountChatLogsDir" << LL_ENDL;
}
}
-void LLDir::setSkinFolder(const std::string &skin_folder)
+void LLDir::setSkinFolder(const std::string &skin_folder, const std::string& language)
{
- mSkinDir = getSkinBaseDir();
- mSkinDir += mDirDelimiter;
- mSkinDir += skin_folder;
+ LL_DEBUGS("LLDir") << "Setting skin '" << skin_folder << "', language '" << language << "'"
+ << LL_ENDL;
+ mSkinName = skin_folder;
+ mLanguage = language;
- // 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;
+ // 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();
- mDefaultSkinDir += mDirDelimiter;
- mDefaultSkinDir += "default";
+ 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)
@@ -658,7 +995,7 @@ bool LLDir::setCacheDir(const std::string &path)
else
{
LLFile::mkdir(path);
- std::string tempname = path + mDirDelimiter + "temp";
+ std::string tempname = add(path, "temp");
LLFILE* file = LLFile::fopen(tempname,"wt");
if (file)
{
@@ -673,24 +1010,75 @@ bool LLDir::setCacheDir(const std::string &path)
void LLDir::dumpCurrentDirectories()
{
- LL_DEBUGS2("AppInit","Directories") << "Current Directories:" << LL_ENDL;
+ LL_DEBUGS("AppInit","Directories") << "Current Directories:" << LL_ENDL;
+
+ LL_DEBUGS("AppInit","Directories") << " CurPath: " << getCurPath() << LL_ENDL;
+ LL_DEBUGS("AppInit","Directories") << " AppName: " << getAppName() << LL_ENDL;
+ LL_DEBUGS("AppInit","Directories") << " ExecutableFilename: " << getExecutableFilename() << LL_ENDL;
+ LL_DEBUGS("AppInit","Directories") << " ExecutableDir: " << getExecutableDir() << LL_ENDL;
+ LL_DEBUGS("AppInit","Directories") << " ExecutablePathAndName: " << getExecutablePathAndName() << LL_ENDL;
+ LL_DEBUGS("AppInit","Directories") << " WorkingDir: " << getWorkingDir() << LL_ENDL;
+ LL_DEBUGS("AppInit","Directories") << " AppRODataDir: " << getAppRODataDir() << LL_ENDL;
+ LL_DEBUGS("AppInit","Directories") << " OSUserDir: " << getOSUserDir() << LL_ENDL;
+ LL_DEBUGS("AppInit","Directories") << " OSUserAppDir: " << getOSUserAppDir() << LL_ENDL;
+ LL_DEBUGS("AppInit","Directories") << " LindenUserDir: " << getLindenUserDir() << LL_ENDL;
+ LL_DEBUGS("AppInit","Directories") << " TempDir: " << getTempDir() << LL_ENDL;
+ LL_DEBUGS("AppInit","Directories") << " CAFile: " << getCAFile() << LL_ENDL;
+ LL_DEBUGS("AppInit","Directories") << " SkinBaseDir: " << getSkinBaseDir() << LL_ENDL;
+ LL_DEBUGS("AppInit","Directories") << " SkinDir: " << getSkinDir() << 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;
+std::string LLDir::add(const std::string& path, const std::string& name) const
+{
+ std::string destpath(path);
+ append(destpath, name);
+ return destpath;
+}
+
+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, 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)
{
@@ -707,13 +1095,13 @@ void dir_exists_or_crash(const std::string &dir_name)
{
if(0 != LLFile::mkdir(dir_name, 0700)) // octal
{
- llerrs << "Unable to create directory: " << dir_name << llendl;
+ LL_ERRS() << "Unable to create directory: " << dir_name << LL_ENDL;
}
}
else
{
- llerrs << "Unable to stat: " << dir_name << " errno = " << stat_rv
- << llendl;
+ LL_ERRS() << "Unable to stat: " << dir_name << " errno = " << stat_rv
+ << LL_ENDL;
}
}
else
@@ -721,7 +1109,7 @@ void dir_exists_or_crash(const std::string &dir_name)
// data_dir exists, make sure it's a directory.
if(!S_ISDIR(dir_stat.st_mode))
{
- llerrs << "Data directory collision: " << dir_name << llendl;
+ LL_ERRS() << "Data directory collision: " << dir_name << LL_ENDL;
}
}
#endif
diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h
index 9067d75bac..b219c6e29f 100644..100755
--- a/indra/llvfs/lldir.h
+++ b/indra/llvfs/lldir.h
@@ -1,32 +1,26 @@
-/**
+/**
* @file lldir.h
* @brief Definition of directory utilities class
*
- * $LicenseInfo:firstyear=2000&license=viewergpl$
- *
- * Copyright (c) 2000-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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 +32,7 @@
#define MAX_PATH MAXPATHLEN
#endif
-// these numbers *may* get serialized (really??), so we need to be explicit
+// these numbers are read from settings_files.xml, so we need to be explicit
typedef enum ELLPath
{
LL_PATH_NONE = 0,
@@ -59,10 +53,11 @@ typedef enum ELLPath
LL_PATH_EXECUTABLE = 16,
LL_PATH_DEFAULT_SKIN = 17,
LL_PATH_FONTS = 18,
+ LL_PATH_DUMP = 19,
LL_PATH_LAST
} ELLPath;
-
+/// Directory operations
class LLDir
{
public:
@@ -77,13 +72,11 @@ class LLDir
const std::string& app_read_only_data_dir = "") = 0;
virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask);
-
+ U32 deleteDirAndContents(const std::string& dir_name);
+ std::vector<std::string> getFilesInDir(const std::string &dirname);
// 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 std::string getCurPath() = 0;
- virtual BOOL fileExists(const std::string &filename) const = 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;
@@ -101,17 +94,20 @@ class LLDir
const std::string &getOSUserAppDir() const; // Location of the os-specific user app dir
const std::string &getLindenUserDir() const; // Location of the Linden user dir.
const std::string &getChatLogsDir() const; // Location of the chat logs dir.
+ const std::string &getDumpDir() const; // Location of the per-run dump dir.
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 &getDefaultSkinDir() const; // folder for default skin. e.g. c:\program files\second life\skins\default
const std::string &getSkinDir() const; // User-specified skin folder.
+ const std::string &getUserDefaultSkinDir() const; // dir with user modifications to default skin
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
+ const std::string &getUserName() const;
// Expanded filename
std::string getExpandedFilename(ELLPath location, const std::string &filename) const;
@@ -124,10 +120,61 @@ class LLDir
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;
+ // getUserSkinDir(), getUserDefaultSkinDir(), getSkinDir(), getDefaultSkinDir()
+ /// param value for findSkinnedFilenames(), explained below
+ enum ESkinConstraint { CURRENT_SKIN, ALL_SKINS };
+ /**
+ * Given a filename within skin, return an ordered sequence of paths to
+ * search. Nonexistent files will be filtered out -- which means that the
+ * vector might be empty.
+ *
+ * @param subdir Identify top-level skin subdirectory by passing one of
+ * LLDir::XUI (file lives under "xui" subtree), LLDir::TEXTURES (file
+ * lives under "textures" subtree), LLDir::SKINBASE (file lives at top
+ * level of skin subdirectory).
+ * @param filename Desired filename within subdir within skin, e.g.
+ * "panel_login.xml". DO NOT prepend (e.g.) "xui" or the desired language.
+ * @param constraint Callers perform two different kinds of processing.
+ * When fetching a XUI file, for instance, the existence of @a filename in
+ * the specified skin completely supercedes any @a filename in the default
+ * skin. For that case, leave the default @a constraint=CURRENT_SKIN. The
+ * returned vector will contain only
+ * ".../<i>current_skin</i>/xui/en/<i>filename</i>",
+ * ".../<i>current_skin</i>/xui/<i>current_language</i>/<i>filename</i>".
+ * But for (e.g.) "strings.xml", we want a given skin to be able to
+ * override only specific entries from the default skin. Any string not
+ * defined in the specified skin will be sought in the default skin. For
+ * that case, pass @a constraint=ALL_SKINS. The returned vector will
+ * contain at least ".../default/xui/en/strings.xml",
+ * ".../default/xui/<i>current_language</i>/strings.xml",
+ * ".../<i>current_skin</i>/xui/en/strings.xml",
+ * ".../<i>current_skin</i>/xui/<i>current_language</i>/strings.xml".
+ */
+ std::vector<std::string> findSkinnedFilenames(const std::string& subdir,
+ const std::string& filename,
+ ESkinConstraint constraint=CURRENT_SKIN) const;
+ /// Values for findSkinnedFilenames(subdir) parameter
+ static const char *XUI, *TEXTURES, *SKINBASE;
+ /**
+ * Return the base-language pathname from findSkinnedFilenames(), or
+ * the empty string if no such file exists. Parameters are identical to
+ * findSkinnedFilenames(). This is shorthand for capturing the vector
+ * returned by findSkinnedFilenames(), checking for empty() and then
+ * returning front().
+ */
+ std::string findSkinnedFilenameBaseLang(const std::string &subdir,
+ const std::string &filename,
+ ESkinConstraint constraint=CURRENT_SKIN) const;
+ /**
+ * Return the "most localized" pathname from findSkinnedFilenames(), or
+ * the empty string if no such file exists. Parameters are identical to
+ * findSkinnedFilenames(). This is shorthand for capturing the vector
+ * returned by findSkinnedFilenames(), checking for empty() and then
+ * returning back().
+ */
+ std::string findSkinnedFilename(const std::string &subdir,
+ const std::string &filename,
+ ESkinConstraint constraint=CURRENT_SKIN) const;
// random filename in common temporary directory
std::string getTempFilename() const;
@@ -135,19 +182,44 @@ class LLDir
// For producing safe download file names from potentially unsafe ones
static std::string getScrubbedFileName(const std::string uncleanFileName);
static std::string getForbiddenFileChars();
+ void setDumpDir( const std::string& path );
+
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 setSkinFolder(const std::string &skin_folder);
+ 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, const std::string& language);
+ virtual std::string getSkinFolder() const;
+ virtual std::string getLanguage() const;
virtual bool setCacheDir(const std::string &path);
+ virtual void updatePerAccountChatLogsDir();
virtual void dumpCurrentDirectories();
-
+
// Utility routine
std::string buildSLOSCacheDir() const;
+ /// Append specified @a name to @a destpath, separated by getDirDelimiter()
+ /// if both are non-empty.
+ void append(std::string& destpath, const std::string& name) const;
+ /// Append specified @a name to @a path, separated by getDirDelimiter()
+ /// if both are non-empty. Return result, leaving @a path unmodified.
+ std::string add(const std::string& path, const std::string& name) const;
+
protected:
+ // Does an add() or append() call need a directory delimiter?
+ typedef std::pair<bool, unsigned short> SepOff;
+ SepOff needSep(const std::string& path, const std::string& name) const;
+ // build mSearchSkinDirs without adding duplicates
+ void addSearchSkinDir(const std::string& skindir);
+
+ // Internal to findSkinnedFilenames()
+ template <typename FUNCTION>
+ void walkSearchSkinDirs(const std::string& subdir,
+ const std::vector<std::string>& subsubdirs,
+ const std::string& filename,
+ const FUNCTION& function) const;
+
std::string mAppName; // install directory under progams/ ie "SecondLife"
std::string mExecutablePathAndName; // full path + Filename of .exe
std::string mExecutableFilename; // Filename of .exe
@@ -165,11 +237,21 @@ protected:
std::string mDefaultCacheDir; // default cache diretory
std::string mOSCacheDir; // operating system cache dir
std::string mDirDelimiter;
+ std::string mSkinName; // caller-specified skin name
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 mSkinDir; // Location for current skin info.
+ std::string mUserDefaultSkinDir; // Location for default skin info.
std::string mUserSkinDir; // Location for user-modified skin info.
+ // Skin directories to search, most general to most specific. This order
+ // works well for composing fine-grained files, in which an individual item
+ // in a specific file overrides the corresponding item in more general
+ // files. Of course, for a file-level search, iterate backwards.
+ std::vector<std::string> mSearchSkinDirs;
+ std::string mLanguage; // Current viewer language
std::string mLLPluginDir; // Location for plugins and plugin shell
+ static std::string sDumpDir; // Per-run crash report subdir of log directory.
+ std::string mUserName; // Current user name
};
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 a9736560ec..7a4034c228 100644..100755
--- a/indra/llvfs/lldir_linux.cpp
+++ b/indra/llvfs/lldir_linux.cpp
@@ -2,31 +2,25 @@
* @file lldir_linux.cpp
* @brief Implementation of directory utilities for linux
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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$
*/
@@ -55,7 +49,7 @@ static std::string getCurrentUserHome(char* fallback)
}
else
{
- llinfos << "Couldn't detect home directory from passwd - trying $HOME" << llendl;
+ LL_INFOS() << "Couldn't detect home directory from passwd - trying $HOME" << LL_ENDL;
const char *const home_env = getenv("HOME"); /* Flawfinder: ignore */
if (home_env)
{
@@ -63,7 +57,7 @@ static std::string getCurrentUserHome(char* fallback)
}
else
{
- llwarns << "Couldn't detect home directory! Falling back to " << fallback << llendl;
+ LL_WARNS() << "Couldn't detect home directory! Falling back to " << fallback << LL_ENDL;
}
}
@@ -82,11 +76,11 @@ LLDir_Linux::LLDir_Linux()
if (getcwd(tmp_str, LL_MAX_PATH) == NULL)
{
strcpy(tmp_str, "/tmp");
- llwarns << "Could not get current directory; changing to "
- << tmp_str << llendl;
+ LL_WARNS() << "Could not get current directory; changing to "
+ << tmp_str << LL_ENDL;
if (chdir(tmp_str) == -1)
{
- llerrs << "Could not change directory to " << tmp_str << llendl;
+ LL_ERRS() << "Could not change directory to " << tmp_str << LL_ENDL;
}
}
@@ -99,13 +93,13 @@ LLDir_Linux::LLDir_Linux()
#else
mAppRODataDir = tmp_str;
#endif
- U32 indra_pos = mExecutableDir.find("/indra");
- if (indra_pos != std::string::npos)
+ std::string::size_type build_dir_pos = mExecutableDir.rfind("/build-linux-");
+ if (build_dir_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;
+ mSkinBaseDir = mExecutableDir.substr(0, build_dir_pos) + "/indra/newview/skins";
+ LL_INFOS() << "Running in dev checkout with mSkinBaseDir "
+ << mSkinBaseDir << LL_ENDL;
}
else
{
@@ -193,8 +187,8 @@ void LLDir_Linux::initAppDirs(const std::string &app_name,
{
if (errno != EEXIST)
{
- llwarns << "Couldn't create app user dir " << mOSUserAppDir << llendl;
- llwarns << "Default to base dir" << mOSUserDir << llendl;
+ LL_WARNS() << "Couldn't create app user dir " << mOSUserAppDir << LL_ENDL;
+ LL_WARNS() << "Default to base dir" << mOSUserDir << LL_ENDL;
mOSUserAppDir = mOSUserDir;
}
}
@@ -204,7 +198,7 @@ void LLDir_Linux::initAppDirs(const std::string &app_name,
{
if (errno != EEXIST)
{
- llwarns << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << llendl;
+ LL_WARNS() << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << LL_ENDL;
}
}
@@ -213,7 +207,7 @@ void LLDir_Linux::initAppDirs(const std::string &app_name,
{
if (errno != EEXIST)
{
- llwarns << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << llendl;
+ LL_WARNS() << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << LL_ENDL;
}
}
@@ -222,7 +216,7 @@ void LLDir_Linux::initAppDirs(const std::string &app_name,
{
if (errno != EEXIST)
{
- llwarns << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << llendl;
+ LL_WARNS() << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << LL_ENDL;
}
}
@@ -248,127 +242,19 @@ U32 LLDir_Linux::countFilesInDir(const std::string &dirname, const std::string &
return (file_count);
}
-// get the next file in the directory
-// automatically wrap if we've hit the end
-BOOL LLDir_Linux::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap)
-{
- glob_t g;
- BOOL result = FALSE;
- fname = "";
-
- if(!(dirname == mCurrentDir))
- {
- // different dir specified, close old search
- mCurrentDirIndex = -1;
- mCurrentDirCount = -1;
- mCurrentDir = dirname;
- }
-
- std::string tmp_str;
- tmp_str = dirname;
- tmp_str += mask;
-
- if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0)
- {
- if(g.gl_pathc > 0)
- {
- if((int)g.gl_pathc != mCurrentDirCount)
- {
- // Number of matches has changed since the last search, meaning a file has been added or deleted.
- // Reset the index.
- mCurrentDirIndex = -1;
- mCurrentDirCount = g.gl_pathc;
- }
-
- mCurrentDirIndex++;
-
- if((mCurrentDirIndex >= (int)g.gl_pathc) && wrap)
- {
- mCurrentDirIndex = 0;
- }
-
- if(mCurrentDirIndex < (int)g.gl_pathc)
- {
-// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl;
-
- // The API wants just the filename, not the full path.
- //fname = g.gl_pathv[mCurrentDirIndex];
-
- char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/');
-
- if(s == NULL)
- s = g.gl_pathv[mCurrentDirIndex];
- else if(s[0] == '/')
- s++;
-
- fname = s;
-
- result = TRUE;
- }
- }
-
- globfree(&g);
- }
-
- return(result);
-}
-
-
-// get a random file in the directory
-// automatically wrap if we've hit the end
-void LLDir_Linux::getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
-{
- S32 num_files;
- S32 which_file;
- DIR *dirp;
- dirent *entryp = NULL;
-
- fname = "";
-
- num_files = countFilesInDir(dirname,mask);
- if (!num_files)
- {
- return;
- }
-
- which_file = ll_rand(num_files);
-
-// llinfos << "Random select file #" << which_file << llendl;
-
- // which_file now indicates the (zero-based) index to which file to play
-
- if (!((dirp = opendir(dirname.c_str()))))
- {
- while (which_file--)
- {
- if (!((entryp = readdir(dirp))))
- {
- return;
- }
- }
-
- if ((!which_file) && entryp)
- {
- fname = entryp->d_name;
- }
-
- closedir(dirp);
- }
-}
-
std::string LLDir_Linux::getCurPath()
{
char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */
if (getcwd(tmp_str, LL_MAX_PATH) == NULL)
{
- llwarns << "Could not get current directory" << llendl;
+ LL_WARNS() << "Could not get current directory" << LL_ENDL;
tmp_str[0] = '\0';
}
return tmp_str;
}
-BOOL LLDir_Linux::fileExists(const std::string &filename) const
+bool LLDir_Linux::fileExists(const std::string &filename) const
{
struct stat stat_data;
// Check the age of the file
diff --git a/indra/llvfs/lldir_linux.h b/indra/llvfs/lldir_linux.h
index 1fec15c5c6..e83a020ba4 100644..100755
--- a/indra/llvfs/lldir_linux.h
+++ b/indra/llvfs/lldir_linux.h
@@ -1,35 +1,33 @@
/**
* @file lldir_linux.h
- * @brief Definition of directory utilities class for linux
+ * @brief Definition of directory utilities class for linux
*
- * $LicenseInfo:firstyear=2000&license=viewergpl$
- *
- * Copyright (c) 2000-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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$
*/
+#if !LL_LINUX
+#error This header must not be included when compiling for any target other than Linux. Consider including lldir.h instead.
+#endif // !LL_LINUX
+
#ifndef LL_LLDIR_LINUX_H
#define LL_LLDIR_LINUX_H
@@ -46,12 +44,10 @@ public:
/*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) const;
+ /*virtual*/ bool fileExists(const std::string &filename) const;
/*virtual*/ std::string getLLPluginLauncher();
/*virtual*/ std::string getLLPluginFilename(std::string base_name);
@@ -60,7 +56,7 @@ private:
DIR *mDirp;
int mCurrentDirIndex;
int mCurrentDirCount;
- std::string mCurrentDir;
+ std::string mCurrentDir;
};
#endif // LL_LLDIR_LINUX_H
diff --git a/indra/llvfs/lldir_mac.cpp b/indra/llvfs/lldir_mac.cpp
index 7bc6f63e1f..4038c92465 100644..100755
--- a/indra/llvfs/lldir_mac.cpp
+++ b/indra/llvfs/lldir_mac.cpp
@@ -2,33 +2,27 @@
* @file lldir_mac.cpp
* @brief Implementation of directory utilities for Mac OS X
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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$
- */
+ */
#if LL_DARWIN
@@ -41,73 +35,27 @@
#include <sys/stat.h>
#include <unistd.h>
#include <glob.h>
-
-#include <Carbon/Carbon.h>
-
-// --------------------------------------------------------------------------------
-
-static OSStatus CFCreateDirectory(FSRef *parentRef, CFStringRef name, FSRef *newRef)
-{
- OSStatus result = noErr;
- HFSUniStr255 uniStr;
-
- uniStr.length = CFStringGetLength(name);
- CFStringGetCharacters(name, CFRangeMake(0, uniStr.length), uniStr.unicode);
- result = FSMakeFSRefUnicode(parentRef, uniStr.length, uniStr.unicode, kTextEncodingMacRoman, newRef);
- if (result != noErr)
- {
- result = FSCreateDirectoryUnicode(parentRef, uniStr.length, uniStr.unicode, 0, NULL, newRef, NULL, NULL);
- }
-
- return result;
-}
+#include <boost/filesystem.hpp>
+#include "llvfs_objc.h"
// --------------------------------------------------------------------------------
-static void CFStringRefToLLString(CFStringRef stringRef, std::string &llString, bool releaseWhenDone)
+static bool CreateDirectory(const std::string &parent,
+ const std::string &child,
+ std::string *fullname)
{
- if (stringRef)
- {
- 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))
- llString = buffer;
- delete[] buffer;
- if (releaseWhenDone)
- CFRelease(stringRef);
- }
-}
-
-// --------------------------------------------------------------------------------
-
-static void CFURLRefToLLString(CFURLRef urlRef, std::string &llString, bool releaseWhenDone)
-{
- if (urlRef)
- {
- CFURLRef absoluteURLRef = CFURLCopyAbsoluteURL(urlRef);
- if (absoluteURLRef)
- {
- CFStringRef stringRef = CFURLCopyFileSystemPath(absoluteURLRef, kCFURLPOSIXPathStyle);
- CFStringRefToLLString(stringRef, llString, true);
- CFRelease(absoluteURLRef);
- }
- if (releaseWhenDone)
- CFRelease(urlRef);
- }
-}
-
-// --------------------------------------------------------------------------------
-
-static void FSRefToLLString(FSRef *fsRef, std::string &llString)
-{
- OSStatus error = noErr;
- char path[MAX_PATH];
-
- error = FSRefMakePath(fsRef, (UInt8*) path, sizeof(path));
- if (error == noErr)
- llString = path;
+
+ boost::filesystem::path p(parent);
+ p /= child;
+
+ if (fullname)
+ *fullname = std::string(p.string());
+
+ if (! boost::filesystem::create_directory(p))
+ {
+ return (boost::filesystem::is_directory(p));
+ }
+ return true;
}
// --------------------------------------------------------------------------------
@@ -115,35 +63,28 @@ static void FSRefToLLString(FSRef *fsRef, std::string &llString)
LLDir_Mac::LLDir_Mac()
{
mDirDelimiter = "/";
- mCurrentDirIndex = -1;
- mCurrentDirCount = -1;
-
- CFBundleRef mainBundleRef = NULL;
- CFURLRef executableURLRef = NULL;
- CFStringRef stringRef = NULL;
- OSStatus error = noErr;
- FSRef fileRef;
- CFStringRef secondLifeString = CFSTR("SecondLife");
-
- mainBundleRef = CFBundleGetMainBundle();
-
- executableURLRef = CFBundleCopyExecutableURL(mainBundleRef);
-
- if (executableURLRef != NULL)
+
+ const std::string secondLifeString = "SecondLife";
+
+ std::string *executablepathstr = getSystemExecutableFolder();
+
+ //NOTE: LLINFOS/LLERRS will not output to log here. The streams are not initialized.
+
+ if (executablepathstr)
{
// mExecutablePathAndName
- CFURLRefToLLString(executableURLRef, mExecutablePathAndName, false);
-
- // mExecutableFilename
- stringRef = CFURLCopyLastPathComponent(executableURLRef);
- CFStringRefToLLString(stringRef, mExecutableFilename, true);
-
- // mExecutableDir
- CFURLRef executableParentURLRef = CFURLCreateCopyDeletingLastPathComponent(NULL, executableURLRef);
- CFURLRefToLLString(executableParentURLRef, mExecutableDir, true);
+ mExecutablePathAndName = *executablepathstr;
+
+ boost::filesystem::path executablepath(*executablepathstr);
+
+# ifndef BOOST_SYSTEM_NO_DEPRECATED
+#endif
+ mExecutableFilename = executablepath.filename().string();
+ mExecutableDir = executablepath.parent_path().string();
// mAppRODataDir
-
+ std::string *resourcepath = getSystemResourceFolder();
+ mAppRODataDir = *resourcepath;
// *NOTE: When running in a dev tree, use the copy of
// skins in indra/newview/ rather than in the application bundle. This
@@ -152,18 +93,15 @@ LLDir_Mac::LLDir_Mac()
// 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)
+
+ U32 build_dir_pos = mExecutableDir.rfind("/build-darwin-");
+ if (build_dir_pos != std::string::npos)
{
// ...we're in a dev checkout
- mSkinBaseDir = mExecutableDir.substr(0, indra_pos)
+ mSkinBaseDir = mExecutableDir.substr(0, build_dir_pos)
+ "/indra/newview/skins";
- llinfos << "Running in dev checkout with mSkinBaseDir "
- << mSkinBaseDir << llendl;
+ LL_INFOS() << "Running in dev checkout with mSkinBaseDir "
+ << mSkinBaseDir << LL_ENDL;
}
else
{
@@ -172,55 +110,50 @@ LLDir_Mac::LLDir_Mac()
}
// mOSUserDir
- error = FSFindFolder(kUserDomain, kApplicationSupportFolderType, true, &fileRef);
- if (error == noErr)
- {
- FSRef newFileRef;
-
- // Create the directory
- error = CFCreateDirectory(&fileRef, secondLifeString, &newFileRef);
- if (error == noErr)
- {
- // Save the full path to the folder
- FSRefToLLString(&newFileRef, mOSUserDir);
-
- // Create our sub-dirs
- (void) CFCreateDirectory(&newFileRef, CFSTR("data"), 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);
- }
- }
-
+ std::string *appdir = getSystemApplicationSupportFolder();
+ std::string rootdir;
+
+ //Create root directory
+ if (CreateDirectory(*appdir, secondLifeString, &rootdir))
+ {
+
+ // Save the full path to the folder
+ mOSUserDir = rootdir;
+
+ // Create our sub-dirs
+ CreateDirectory(rootdir, std::string("data"), NULL);
+ CreateDirectory(rootdir, std::string("logs"), NULL);
+ CreateDirectory(rootdir, std::string("user_settings"), NULL);
+ CreateDirectory(rootdir, std::string("browser_profile"), NULL);
+ }
+
//mOSCacheDir
- FSRef cacheDirRef;
- error = FSFindFolder(kUserDomain, kCachedDataFolderType, true, &cacheDirRef);
- if (error == noErr)
+ std::string *cachedir = getSystemCacheFolder();
+
+ if (cachedir)
+
{
- FSRefToLLString(&cacheDirRef, mOSCacheDir);
- (void)CFCreateDirectory(&cacheDirRef, CFSTR("SecondLife"),NULL);
+ mOSCacheDir = *cachedir;
+ //TODO: This changes from ~/Library/Cache/Secondlife to ~/Library/Cache/com.app.secondlife/Secondlife. Last dir level could go away.
+ CreateDirectory(mOSCacheDir, secondLifeString, NULL);
}
// mOSUserAppDir
mOSUserAppDir = mOSUserDir;
// mTempDir
- error = FSFindFolder(kOnAppropriateDisk, kTemporaryFolderType, true, &fileRef);
- if (error == noErr)
- {
- FSRef tempRef;
- error = CFCreateDirectory(&fileRef, secondLifeString, &tempRef);
- if (error == noErr)
- FSRefToLLString(&tempRef, mTempDir);
- }
+ //Aura 120920 boost::filesystem::temp_directory_path() not yet implemented on mac. :(
+ std::string *tmpdir = getSystemTempFolder();
+ if (tmpdir)
+ {
+
+ CreateDirectory(*tmpdir, secondLifeString, &mTempDir);
+ if (tmpdir) delete tmpdir;
+ }
mWorkingDir = getCurPath();
mLLPluginDir = mAppRODataDir + mDirDelimiter + "llplugin";
-
- CFRelease(executableURLRef);
- executableURLRef = NULL;
}
}
@@ -241,192 +174,25 @@ void LLDir_Mac::initAppDirs(const std::string &app_name,
mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins";
}
mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem");
-
- //dumpCurrentDirectories();
-}
-
-U32 LLDir_Mac::countFilesInDir(const std::string &dirname, const std::string &mask)
-{
- U32 file_count = 0;
- glob_t g;
-
- std::string tmp_str;
- tmp_str = dirname;
- tmp_str += mask;
-
- if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0)
- {
- file_count = g.gl_pathc;
-
- globfree(&g);
- }
-
- return (file_count);
-}
-
-// get the next file in the directory
-// automatically wrap if we've hit the end
-BOOL LLDir_Mac::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap)
-{
- glob_t g;
- BOOL result = FALSE;
- fname = "";
-
- if(!(dirname == mCurrentDir))
- {
- // different dir specified, close old search
- mCurrentDirIndex = -1;
- mCurrentDirCount = -1;
- mCurrentDir = dirname;
- }
-
- std::string tmp_str;
- tmp_str = dirname;
- tmp_str += mask;
-
- if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0)
- {
- if(g.gl_pathc > 0)
- {
- if(g.gl_pathc != mCurrentDirCount)
- {
- // Number of matches has changed since the last search, meaning a file has been added or deleted.
- // Reset the index.
- mCurrentDirIndex = -1;
- mCurrentDirCount = g.gl_pathc;
- }
-
- mCurrentDirIndex++;
-
- if((mCurrentDirIndex >= g.gl_pathc) && wrap)
- {
- mCurrentDirIndex = 0;
- }
-
- if(mCurrentDirIndex < g.gl_pathc)
- {
-// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl;
-
- // The API wants just the filename, not the full path.
- //fname = g.gl_pathv[mCurrentDirIndex];
-
- char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/');
-
- if(s == NULL)
- s = g.gl_pathv[mCurrentDirIndex];
- else if(s[0] == '/')
- s++;
-
- fname = s;
-
- result = TRUE;
- }
- }
-
- globfree(&g);
- }
-
- return(result);
-}
-
-// get a random file in the directory
-void LLDir_Mac::getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
-{
- S32 which_file;
- glob_t g;
- fname = "";
-
- std::string tmp_str;
- tmp_str = dirname;
- tmp_str += mask;
-
- if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0)
- {
- if(g.gl_pathc > 0)
- {
-
- which_file = ll_rand(g.gl_pathc);
-
-// llinfos << "getRandomFileInDir: returning number " << which_file << ", path is " << g.gl_pathv[which_file] << llendl;
- // The API wants just the filename, not the full path.
- //fname = g.gl_pathv[which_file];
-
- char *s = strrchr(g.gl_pathv[which_file], '/');
-
- if(s == NULL)
- s = g.gl_pathv[which_file];
- else if(s[0] == '/')
- s++;
-
- fname = s;
- }
-
- globfree(&g);
- }
-}
-
-S32 LLDir_Mac::deleteFilesInDir(const std::string &dirname, const std::string &mask)
-{
- glob_t g;
- S32 result = 0;
-
- std::string tmp_str;
- tmp_str = dirname;
- tmp_str += mask;
-
- if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0)
- {
- int i;
-
- for(i = 0; i < g.gl_pathc; i++)
- {
-// llinfos << "deleteFilesInDir: deleting number " << i << ", path is " << g.gl_pathv[i] << llendl;
-
- if(unlink(g.gl_pathv[i]) != 0)
- {
- result = errno;
-
- llwarns << "Problem removing " << g.gl_pathv[i] << " - errorcode: "
- << result << llendl;
- }
- }
-
- globfree(&g);
- }
-
- return(result);
}
std::string LLDir_Mac::getCurPath()
{
- char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */
- getcwd(tmp_str, LL_MAX_PATH);
- return tmp_str;
+ return boost::filesystem::path( boost::filesystem::current_path() ).string();
}
-BOOL LLDir_Mac::fileExists(const std::string &filename) const
+bool LLDir_Mac::fileExists(const std::string &filename) const
{
- struct stat stat_data;
- // Check the age of the file
- // Now, we see if the files we've gathered are recent...
- int res = stat(filename.c_str(), &stat_data);
- if (!res)
- {
- return TRUE;
- }
- else
- {
- return FALSE;
- }
+ return boost::filesystem::exists(filename);
}
/*virtual*/ std::string LLDir_Mac::getLLPluginLauncher()
{
return gDirUtilp->getAppRODataDir() + gDirUtilp->getDirDelimiter() +
- "SLPlugin";
+ "SLPlugin.app/Contents/MacOS/SLPlugin";
}
/*virtual*/ std::string LLDir_Mac::getLLPluginFilename(std::string base_name)
diff --git a/indra/llvfs/lldir_mac.h b/indra/llvfs/lldir_mac.h
index 834acc7262..558727ebbc 100644..100755
--- a/indra/llvfs/lldir_mac.h
+++ b/indra/llvfs/lldir_mac.h
@@ -2,33 +2,31 @@
* @file lldir_mac.h
* @brief Definition of directory utilities class for Mac OS X
*
- * $LicenseInfo:firstyear=2000&license=viewergpl$
- *
- * Copyright (c) 2000-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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$
- */
+ */
+
+#if !LL_DARWIN
+#error This header must not be included when compiling for any target other than Mac OS. Consider including lldir.h instead.
+#endif // !LL_DARWIN
#ifndef LL_LLDIR_MAC_H
#define LL_LLDIR_MAC_H
@@ -45,21 +43,12 @@ public:
/*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) const;
+ virtual bool fileExists(const std::string &filename) const;
/*virtual*/ std::string getLLPluginLauncher();
/*virtual*/ std::string getLLPluginFilename(std::string base_name);
-
-private:
- int mCurrentDirIndex;
- int mCurrentDirCount;
- std::string mCurrentDir;
};
#endif // LL_LLDIR_MAC_H
diff --git a/indra/llvfs/lldir_solaris.cpp b/indra/llvfs/lldir_solaris.cpp
index 8ac5a41e93..b43b2f27ce 100644..100755
--- a/indra/llvfs/lldir_solaris.cpp
+++ b/indra/llvfs/lldir_solaris.cpp
@@ -2,31 +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-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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$
*/
@@ -58,7 +52,7 @@ static std::string getCurrentUserHome(char* fallback)
}
else
{
- llinfos << "Couldn't detect home directory from passwd - trying $HOME" << llendl;
+ LL_INFOS() << "Couldn't detect home directory from passwd - trying $HOME" << LL_ENDL;
const char *const home_env = getenv("HOME"); /* Flawfinder: ignore */
if (home_env)
{
@@ -66,7 +60,7 @@ static std::string getCurrentUserHome(char* fallback)
}
else
{
- llwarns << "Couldn't detect home directory! Falling back to " << fallback << llendl;
+ LL_WARNS() << "Couldn't detect home directory! Falling back to " << fallback << LL_ENDL;
}
}
@@ -85,11 +79,11 @@ LLDir_Solaris::LLDir_Solaris()
if (getcwd(tmp_str, LL_MAX_PATH) == NULL)
{
strcpy(tmp_str, "/tmp");
- llwarns << "Could not get current directory; changing to "
- << tmp_str << llendl;
+ LL_WARNS() << "Could not get current directory; changing to "
+ << tmp_str << LL_ENDL;
if (chdir(tmp_str) == -1)
{
- llerrs << "Could not change directory to " << tmp_str << llendl;
+ LL_ERRS() << "Could not change directory to " << tmp_str << LL_ENDL;
}
}
@@ -107,12 +101,12 @@ LLDir_Solaris::LLDir_Solaris()
sprintf(path, "/proc/%d/psinfo", (int)getpid());
int proc_fd = -1;
if((proc_fd = open(path, O_RDONLY)) == -1){
- llwarns << "unable to open " << path << llendl;
+ LL_WARNS() << "unable to open " << path << LL_ENDL;
return;
}
psinfo_t proc_psinfo;
if(read(proc_fd, &proc_psinfo, sizeof(psinfo_t)) != sizeof(psinfo_t)){
- llwarns << "Unable to read " << path << llendl;
+ LL_WARNS() << "Unable to read " << path << LL_ENDL;
close(proc_fd);
return;
}
@@ -120,13 +114,13 @@ LLDir_Solaris::LLDir_Solaris()
close(proc_fd);
mExecutableFilename = strdup(proc_psinfo.pr_fname);
- llinfos << "mExecutableFilename = [" << mExecutableFilename << "]" << llendl;
+ LL_INFOS() << "mExecutableFilename = [" << mExecutableFilename << "]" << LL_ENDL;
sprintf(path, "/proc/%d/path/a.out", (int)getpid());
char execpath[LL_MAX_PATH];
if(readlink(path, execpath, LL_MAX_PATH) == -1){
- llwarns << "Unable to read link from " << path << llendl;
+ LL_WARNS() << "Unable to read link from " << path << LL_ENDL;
return;
}
@@ -136,7 +130,7 @@ LLDir_Solaris::LLDir_Solaris()
*p = NULL;
mExecutablePathAndName = strdup(execpath);
- llinfos << "mExecutablePathAndName = [" << mExecutablePathAndName << "]" << llendl;
+ LL_INFOS() << "mExecutablePathAndName = [" << mExecutablePathAndName << "]" << LL_ENDL;
//NOTE: Why force people to cd into the package directory?
// Look for SECONDLIFE env variable and use it, if set.
@@ -157,7 +151,7 @@ LLDir_Solaris::LLDir_Solaris()
*s = (char)NULL;
mExecutableDir = strdup(execpath);
- llinfos << "mExecutableDir = [" << mExecutableDir << "]" << llendl;
+ LL_INFOS() << "mExecutableDir = [" << mExecutableDir << "]" << LL_ENDL;
}
}
@@ -211,8 +205,8 @@ void LLDir_Solaris::initAppDirs(const std::string &app_name,
{
if (errno != EEXIST)
{
- llwarns << "Couldn't create app user dir " << mOSUserAppDir << llendl;
- llwarns << "Default to base dir" << mOSUserDir << llendl;
+ LL_WARNS() << "Couldn't create app user dir " << mOSUserAppDir << LL_ENDL;
+ LL_WARNS() << "Default to base dir" << mOSUserDir << LL_ENDL;
mOSUserAppDir = mOSUserDir;
}
}
@@ -222,7 +216,7 @@ void LLDir_Solaris::initAppDirs(const std::string &app_name,
{
if (errno != EEXIST)
{
- llwarns << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << llendl;
+ LL_WARNS() << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << LL_ENDL;
}
}
@@ -231,7 +225,7 @@ void LLDir_Solaris::initAppDirs(const std::string &app_name,
{
if (errno != EEXIST)
{
- llwarns << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << llendl;
+ LL_WARNS() << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << LL_ENDL;
}
}
@@ -240,7 +234,7 @@ void LLDir_Solaris::initAppDirs(const std::string &app_name,
{
if (errno != EEXIST)
{
- llwarns << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << llendl;
+ LL_WARNS() << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << LL_ENDL;
}
}
@@ -266,127 +260,19 @@ U32 LLDir_Solaris::countFilesInDir(const std::string &dirname, const std::string
return (file_count);
}
-// get the next file in the directory
-// automatically wrap if we've hit the end
-BOOL LLDir_Solaris::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap)
-{
- glob_t g;
- BOOL result = FALSE;
- fname = "";
-
- if(!(dirname == mCurrentDir))
- {
- // different dir specified, close old search
- mCurrentDirIndex = -1;
- mCurrentDirCount = -1;
- mCurrentDir = dirname;
- }
-
- std::string tmp_str;
- tmp_str = dirname;
- tmp_str += mask;
-
- if(glob(tmp_str.c_str(), GLOB_NOSORT, NULL, &g) == 0)
- {
- if(g.gl_pathc > 0)
- {
- if((int)g.gl_pathc != mCurrentDirCount)
- {
- // Number of matches has changed since the last search, meaning a file has been added or deleted.
- // Reset the index.
- mCurrentDirIndex = -1;
- mCurrentDirCount = g.gl_pathc;
- }
-
- mCurrentDirIndex++;
-
- if((mCurrentDirIndex >= (int)g.gl_pathc) && wrap)
- {
- mCurrentDirIndex = 0;
- }
-
- if(mCurrentDirIndex < (int)g.gl_pathc)
- {
-// llinfos << "getNextFileInDir: returning number " << mCurrentDirIndex << ", path is " << g.gl_pathv[mCurrentDirIndex] << llendl;
-
- // The API wants just the filename, not the full path.
- //fname = g.gl_pathv[mCurrentDirIndex];
-
- char *s = strrchr(g.gl_pathv[mCurrentDirIndex], '/');
-
- if(s == NULL)
- s = g.gl_pathv[mCurrentDirIndex];
- else if(s[0] == '/')
- s++;
-
- fname = s;
-
- result = TRUE;
- }
- }
-
- globfree(&g);
- }
-
- return(result);
-}
-
-
-// get a random file in the directory
-// automatically wrap if we've hit the end
-void LLDir_Solaris::getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
-{
- S32 num_files;
- S32 which_file;
- DIR *dirp;
- dirent *entryp = NULL;
-
- fname = "";
-
- num_files = countFilesInDir(dirname,mask);
- if (!num_files)
- {
- return;
- }
-
- which_file = ll_rand(num_files);
-
-// llinfos << "Random select file #" << which_file << llendl;
-
- // which_file now indicates the (zero-based) index to which file to play
-
- if (!((dirp = opendir(dirname.c_str()))))
- {
- while (which_file--)
- {
- if (!((entryp = readdir(dirp))))
- {
- return;
- }
- }
-
- if ((!which_file) && entryp)
- {
- fname = entryp->d_name;
- }
-
- closedir(dirp);
- }
-}
-
std::string LLDir_Solaris::getCurPath()
{
char tmp_str[LL_MAX_PATH]; /* Flawfinder: ignore */
if (getcwd(tmp_str, LL_MAX_PATH) == NULL)
{
- llwarns << "Could not get current directory" << llendl;
+ LL_WARNS() << "Could not get current directory" << LL_ENDL;
tmp_str[0] = '\0';
}
return tmp_str;
}
-BOOL LLDir_Solaris::fileExists(const std::string &filename) const
+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 1fa8348355..c6dac57e14 100644..100755
--- a/indra/llvfs/lldir_solaris.h
+++ b/indra/llvfs/lldir_solaris.h
@@ -2,34 +2,32 @@
* @file fmodwrapper.cpp
* @brief dummy source file for building a shared library to wrap libfmod.a
*
- * $LicenseInfo:firstyear=2005&license=viewergpl$
- *
- * Copyright (c) 2005-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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$
*/
+#if !LL_SOLARIS
+#error This header must not be included when compiling for any target other than Solaris. Consider including lldir.h instead.
+#endif // !LL_SOLARIS
+
#ifndef LL_LLDIR_SOLARIS_H
#define LL_LLDIR_SOLARIS_H
@@ -46,18 +44,16 @@ public:
/*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) const;
+ /*virtual*/ bool fileExists(const std::string &filename) const;
private:
DIR *mDirp;
int mCurrentDirIndex;
int mCurrentDirCount;
- std::string mCurrentDir;
+ std::string mCurrentDir;
};
#endif // LL_LLDIR_SOLARIS_H
diff --git a/indra/llvfs/lldir_win32.cpp b/indra/llvfs/lldir_win32.cpp
index 4eb10c842b..ebc8fdca33 100644..100755
--- a/indra/llvfs/lldir_win32.cpp
+++ b/indra/llvfs/lldir_win32.cpp
@@ -2,31 +2,25 @@
* @file lldir_win32.cpp
* @brief Implementation of directory utilities for windows
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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$
*/
@@ -87,10 +81,11 @@ LLDir_Win32::LLDir_Win32()
// fprintf(stderr, "mTempDir = <%s>",mTempDir);
-#if 1
- // Don't use the real app path for now, as we'll have to add parsing to detect if
- // we're in a developer tree, which has a different structure from the installed product.
+ // Set working directory, for LLDir::getWorkingDir()
+ GetCurrentDirectory(MAX_PATH, w_str);
+ mWorkingDir = utf16str_to_utf8str(llutf16string(w_str));
+ // Set the executable directory
S32 size = GetModuleFileName(NULL, w_str, MAX_PATH);
if (size)
{
@@ -106,36 +101,39 @@ LLDir_Win32::LLDir_Win32()
{
mExecutableFilename = mExecutablePathAndName;
}
- GetCurrentDirectory(MAX_PATH, w_str);
- mWorkingDir = utf16str_to_utf8str(llutf16string(w_str));
}
else
{
fprintf(stderr, "Couldn't get APP path, assuming current directory!");
- GetCurrentDirectory(MAX_PATH, w_str);
- mExecutableDir = utf16str_to_utf8str(llutf16string(w_str));
+ mExecutableDir = mWorkingDir;
// Assume it's the current directory
}
-#else
- GetCurrentDirectory(MAX_PATH, w_str);
- mExecutableDir = utf16str_to_utf8str(llutf16string(w_str));
-#endif
- mAppRODataDir = ".";
+ // mAppRODataDir = ".";
+
+ // Determine the location of the App-Read-Only-Data
+ // Try the working directory then the exe's dir.
+ mAppRODataDir = mWorkingDir;
- mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins";
- if (mExecutableDir.find("indra") == std::string::npos)
+// if (mExecutableDir.find("indra") == std::string::npos)
+
+ // *NOTE:Mani - It is a mistake to put viewer specific code in
+ // the LLDir implementation. The references to 'skins' and
+ // 'llplugin' need to go somewhere else.
+ // alas... this also gets called during static initialization
+ // time due to the construction of gDirUtil in lldir.cpp.
+ if(! LLFile::isdir(mAppRODataDir + mDirDelimiter + "skins"))
{
- // 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));
+ // What? No skins in the working dir?
+ // Try the executable's directory.
+ mAppRODataDir = mExecutableDir;
}
- llinfos << "mAppRODataDir = " << mAppRODataDir << llendl;
+
+// LL_INFOS() << "mAppRODataDir = " << mAppRODataDir << LL_ENDL;
+
+ mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins";
// Build the default cache directory
mDefaultCacheDir = buildSLOSCacheDir();
@@ -146,7 +144,7 @@ LLDir_Win32::LLDir_Win32()
{
if (errno != EEXIST)
{
- llwarns << "Couldn't create LL_PATH_CACHE dir " << mDefaultCacheDir << llendl;
+ LL_WARNS() << "Couldn't create LL_PATH_CACHE dir " << mDefaultCacheDir << LL_ENDL;
}
}
@@ -178,8 +176,8 @@ void LLDir_Win32::initAppDirs(const std::string &app_name,
{
if (errno != EEXIST)
{
- llwarns << "Couldn't create app user dir " << mOSUserAppDir << llendl;
- llwarns << "Default to base dir" << mOSUserDir << llendl;
+ LL_WARNS() << "Couldn't create app user dir " << mOSUserAppDir << LL_ENDL;
+ LL_WARNS() << "Default to base dir" << mOSUserDir << LL_ENDL;
mOSUserAppDir = mOSUserDir;
}
}
@@ -190,7 +188,7 @@ void LLDir_Win32::initAppDirs(const std::string &app_name,
{
if (errno != EEXIST)
{
- llwarns << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << llendl;
+ LL_WARNS() << "Couldn't create LL_PATH_LOGS dir " << getExpandedFilename(LL_PATH_LOGS,"") << LL_ENDL;
}
}
@@ -199,7 +197,7 @@ void LLDir_Win32::initAppDirs(const std::string &app_name,
{
if (errno != EEXIST)
{
- llwarns << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << llendl;
+ LL_WARNS() << "Couldn't create LL_PATH_USER_SETTINGS dir " << getExpandedFilename(LL_PATH_USER_SETTINGS,"") << LL_ENDL;
}
}
@@ -208,18 +206,10 @@ void LLDir_Win32::initAppDirs(const std::string &app_name,
{
if (errno != EEXIST)
{
- llwarns << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << llendl;
+ LL_WARNS() << "Couldn't create LL_PATH_CACHE dir " << getExpandedFilename(LL_PATH_CACHE,"") << LL_ENDL;
}
}
- res = LLFile::mkdir(getExpandedFilename(LL_PATH_USER_SKIN,""));
- if (res == -1)
- {
- if (errno != EEXIST)
- {
- llwarns << "Couldn't create LL_PATH_SKINS dir " << getExpandedFilename(LL_PATH_USER_SKIN,"") << llendl;
- }
- }
mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem");
}
@@ -250,122 +240,6 @@ U32 LLDir_Win32::countFilesInDir(const std::string &dirname, const std::string &
return (file_count);
}
-
-// get the next file in the directory
-// automatically wrap if we've hit the end
-BOOL LLDir_Win32::getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap)
-{
- llutf16string dirnamew = utf8str_to_utf16str(dirname);
- return getNextFileInDir(dirnamew, mask, fname, wrap);
-
-}
-
-BOOL LLDir_Win32::getNextFileInDir(const llutf16string &dirname, const std::string &mask, std::string &fname, BOOL wrap)
-{
- WIN32_FIND_DATAW FileData;
-
- fname = "";
- llutf16string pathname = dirname;
- pathname += utf8str_to_utf16str(mask);
-
- if (pathname != mCurrentDir)
- {
- // different dir specified, close old search
- if (mCurrentDir[0])
- {
- FindClose(mDirSearch_h);
- }
- mCurrentDir = pathname;
-
- // and open new one
- // Check error opening Directory structure
- if ((mDirSearch_h = FindFirstFile(pathname.c_str(), &FileData)) == INVALID_HANDLE_VALUE)
- {
-// llinfos << "Unable to locate first file" << llendl;
- return(FALSE);
- }
- }
- else // get next file in list
- {
- // Find next entry
- if (!FindNextFile(mDirSearch_h, &FileData))
- {
- if (GetLastError() == ERROR_NO_MORE_FILES)
- {
- // No more files, so reset to beginning of directory
- FindClose(mDirSearch_h);
- mCurrentDir[0] = NULL;
-
- if (wrap)
- {
- return(getNextFileInDir(pathname,"",fname,TRUE));
- }
- else
- {
- fname[0] = 0;
- return(FALSE);
- }
- }
- else
- {
- // Error
-// llinfos << "Unable to locate next file" << llendl;
- return(FALSE);
- }
- }
- }
-
- // convert from TCHAR to char
- fname = utf16str_to_utf8str(FileData.cFileName);
-
- // fname now first name in list
- return(TRUE);
-}
-
-
-// get a random file in the directory
-// automatically wrap if we've hit the end
-void LLDir_Win32::getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname)
-{
- S32 num_files;
- S32 which_file;
- HANDLE random_search_h;
-
- fname = "";
-
- llutf16string pathname = utf8str_to_utf16str(dirname);
- pathname += utf8str_to_utf16str(mask);
-
- WIN32_FIND_DATA FileData;
- fname[0] = NULL;
-
- num_files = countFilesInDir(dirname,mask);
- if (!num_files)
- {
- return;
- }
-
- which_file = ll_rand(num_files);
-
-// llinfos << "Random select mp3 #" << which_file << llendl;
-
- // which_file now indicates the (zero-based) index to which file to play
-
- if ((random_search_h = FindFirstFile(pathname.c_str(), &FileData)) != INVALID_HANDLE_VALUE)
- {
- while (which_file--)
- {
- if (!FindNextFile(random_search_h, &FileData))
- {
- return;
- }
- }
- FindClose(random_search_h);
-
- fname = utf16str_to_utf8str(llutf16string(FileData.cFileName));
- }
-}
-
std::string LLDir_Win32::getCurPath()
{
WCHAR w_str[MAX_PATH];
@@ -375,7 +249,7 @@ std::string LLDir_Win32::getCurPath()
}
-BOOL LLDir_Win32::fileExists(const std::string &filename) const
+bool LLDir_Win32::fileExists(const std::string &filename) const
{
llstat stat_data;
// Check the age of the file
diff --git a/indra/llvfs/lldir_win32.h b/indra/llvfs/lldir_win32.h
index c2acfa6bd4..450efaf9da 100644..100755
--- a/indra/llvfs/lldir_win32.h
+++ b/indra/llvfs/lldir_win32.h
@@ -2,34 +2,32 @@
* @file lldir_win32.h
* @brief Definition of directory utilities class for windows
*
- * $LicenseInfo:firstyear=2000&license=viewergpl$
- *
- * Copyright (c) 2000-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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$
*/
+#if !LL_WINDOWS
+#error This header must not be included when compiling for any target other than Windows. Consider including lldir.h instead.
+#endif // !LL_WINDOWS
+
#ifndef LL_LLDIR_WIN32_H
#define LL_LLDIR_WIN32_H
@@ -46,16 +44,12 @@ 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) const;
+ /*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);
-
void* mDirSearch_h;
llutf16string mCurrentDir;
};
diff --git a/indra/llvfs/lldirguard.h b/indra/llvfs/lldirguard.h
index 85366120d8..37b9e9b83e 100644..100755
--- a/indra/llvfs/lldirguard.h
+++ b/indra/llvfs/lldirguard.h
@@ -2,31 +2,25 @@
* @file lldirguard.h
* @brief Protect working directory from being changed in scope.
*
- * $LicenseInfo:firstyear=2009&license=viewergpl$
- *
- * Copyright (c) 2009, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2009&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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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$
*/
@@ -54,7 +48,7 @@ public:
// 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;
+ LL_INFOS() << "Resetting working dir from " << mFinalDirUtf8 << " to " << mOrigDirUtf8 << LL_ENDL;
SetCurrentDirectory(mOrigDir);
}
}
diff --git a/indra/llvfs/lldiriterator.cpp b/indra/llvfs/lldiriterator.cpp
new file mode 100755
index 0000000000..76296ff877
--- /dev/null
+++ b/indra/llvfs/lldiriterator.cpp
@@ -0,0 +1,239 @@
+/**
+ * @file lldiriterator.cpp
+ * @brief Iterator through directory entries matching the search pattern.
+ *
+ * $LicenseInfo:firstyear=2010&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 "lldiriterator.h"
+
+#include "fix_macros.h"
+#include <boost/filesystem.hpp>
+#include <boost/regex.hpp>
+
+namespace fs = boost::filesystem;
+
+static std::string glob_to_regex(const std::string& glob);
+
+class LLDirIterator::Impl
+{
+public:
+ Impl(const std::string &dirname, const std::string &mask);
+ ~Impl();
+
+ bool next(std::string &fname);
+
+private:
+ boost::regex mFilterExp;
+ fs::directory_iterator mIter;
+ bool mIsValid;
+};
+
+LLDirIterator::Impl::Impl(const std::string &dirname, const std::string &mask)
+ : mIsValid(false)
+{
+ fs::path dir_path(dirname);
+
+ bool is_dir = false;
+
+ // Check if path is a directory.
+ try
+ {
+ is_dir = fs::is_directory(dir_path);
+ }
+ catch (const fs::filesystem_error& e)
+ {
+ LL_WARNS() << e.what() << LL_ENDL;
+ return;
+ }
+
+ if (!is_dir)
+ {
+ LL_WARNS() << "Invalid path: \"" << dir_path.string() << "\"" << LL_ENDL;
+ return;
+ }
+
+ // Initialize the directory iterator for the given path.
+ try
+ {
+ mIter = fs::directory_iterator(dir_path);
+ }
+ catch (const fs::filesystem_error& e)
+ {
+ LL_WARNS() << e.what() << LL_ENDL;
+ return;
+ }
+
+ // Convert the glob mask to a regular expression
+ std::string exp = glob_to_regex(mask);
+
+ // Initialize boost::regex with the expression converted from
+ // the glob mask.
+ // An exception is thrown if the expression is not valid.
+ try
+ {
+ mFilterExp.assign(exp);
+ }
+ catch (boost::regex_error& e)
+ {
+ LL_WARNS() << "\"" << exp << "\" is not a valid regular expression: "
+ << e.what() << LL_ENDL;
+ return;
+ }
+
+ mIsValid = true;
+}
+
+LLDirIterator::Impl::~Impl()
+{
+}
+
+bool LLDirIterator::Impl::next(std::string &fname)
+{
+ fname = "";
+
+ if (!mIsValid)
+ {
+ LL_WARNS() << "The iterator is not correctly initialized." << LL_ENDL;
+ return false;
+ }
+
+ fs::directory_iterator end_itr; // default construction yields past-the-end
+ bool found = false;
+
+ // Check if path is a directory.
+ try
+ {
+ while (mIter != end_itr && !found)
+ {
+ boost::smatch match;
+ std::string name = mIter->path().filename().string();
+ found = boost::regex_match(name, match, mFilterExp);
+ if (found)
+ {
+ fname = name;
+ }
+
+ ++mIter;
+ }
+ }
+ catch (const fs::filesystem_error& e)
+ {
+ LL_WARNS() << e.what() << LL_ENDL;
+ }
+
+ return found;
+}
+
+/**
+Converts the incoming glob into a regex. This involves
+converting incoming glob expressions to regex equivilents and
+at the same time, escaping any regex meaningful characters which
+do not have glob meaning, i.e.
+ .()+|^$
+in the input.
+*/
+std::string glob_to_regex(const std::string& glob)
+{
+ std::string regex;
+ regex.reserve(glob.size()<<1);
+ S32 braces = 0;
+ bool escaped = false;
+ bool square_brace_open = false;
+
+ for (std::string::const_iterator i = glob.begin(); i != glob.end(); ++i)
+ {
+ char c = *i;
+
+ switch (c)
+ {
+ case '*':
+ if (glob.begin() == i)
+ {
+ regex+="[^.].*";
+ }
+ else
+ {
+ regex+= escaped ? "*" : ".*";
+ }
+ break;
+ case '?':
+ regex+= escaped ? '?' : '.';
+ break;
+ case '{':
+ braces++;
+ regex+='(';
+ break;
+ case '}':
+ if (!braces)
+ {
+ LL_ERRS() << "glob_to_regex: Closing brace without an equivalent opening brace: " << glob << LL_ENDL;
+ }
+
+ regex+=')';
+ braces--;
+ break;
+ case ',':
+ regex+= braces ? '|' : c;
+ break;
+ case '!':
+ regex+= square_brace_open ? '^' : c;
+ break;
+ case '.': // This collection have different regex meaning
+ case '^': // and so need escaping.
+ case '(':
+ case ')':
+ case '+':
+ case '|':
+ case '$':
+ regex += '\\';
+ default:
+ regex += c;
+ break;
+ }
+
+ escaped = ('\\' == c);
+ square_brace_open = ('[' == c);
+ }
+
+ if (braces)
+ {
+ LL_ERRS() << "glob_to_regex: Unterminated brace expression: " << glob << LL_ENDL;
+ }
+
+ return regex;
+}
+
+LLDirIterator::LLDirIterator(const std::string &dirname, const std::string &mask)
+{
+ mImpl = new Impl(dirname, mask);
+}
+
+LLDirIterator::~LLDirIterator()
+{
+ delete mImpl;
+}
+
+bool LLDirIterator::next(std::string &fname)
+{
+ return mImpl->next(fname);
+}
diff --git a/indra/llvfs/lldiriterator.h b/indra/llvfs/lldiriterator.h
new file mode 100755
index 0000000000..0b48be41b3
--- /dev/null
+++ b/indra/llvfs/lldiriterator.h
@@ -0,0 +1,87 @@
+/**
+ * @file lldiriterator.h
+ * @brief Iterator through directory entries matching the search pattern.
+ *
+ * $LicenseInfo:firstyear=2010&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_LLDIRITERATOR_H
+#define LL_LLDIRITERATOR_H
+
+#include "linden_common.h"
+
+/**
+ * Class LLDirIterator
+ *
+ * Iterates through directory entries matching the search pattern.
+ */
+class LLDirIterator
+{
+public:
+ /**
+ * Constructs LLDirIterator object to search for glob pattern
+ * matches in a directory.
+ *
+ * @param dirname - name of a directory to search in.
+ * @param mask - search pattern, a glob expression
+ *
+ * Wildcards supported in glob expressions:
+ * --------------------------------------------------------------
+ * | Wildcard | Matches |
+ * --------------------------------------------------------------
+ * | * |zero or more characters |
+ * | ? |exactly one character |
+ * | [abcde] |exactly one character listed |
+ * | [a-e] |exactly one character in the given range |
+ * | [!abcde] |any character that is not listed |
+ * | [!a-e] |any character that is not in the given range |
+ * | {abc,xyz} |exactly one entire word in the options given |
+ * --------------------------------------------------------------
+ */
+ LLDirIterator(const std::string &dirname, const std::string &mask);
+
+ ~LLDirIterator();
+
+ /**
+ * Searches for the next directory entry matching the glob mask
+ * specified upon iterator construction.
+ * Returns true if a match is found, sets fname
+ * parameter to the name of the matched directory entry and
+ * increments the iterator position.
+ *
+ * Typical usage:
+ * <code>
+ * LLDirIterator iter(directory, pattern);
+ * if ( iter.next(scanResult) )
+ * </code>
+ *
+ * @param fname - name of the matched directory entry.
+ * @return true if a match is found, false otherwise.
+ */
+ bool next(std::string &fname);
+
+protected:
+ class Impl;
+ Impl* mImpl;
+};
+
+#endif //LL_LLDIRITERATOR_H
diff --git a/indra/llvfs/lllfsthread.cpp b/indra/llvfs/lllfsthread.cpp
index e85cc437f4..2fd2614cce 100644..100755
--- a/indra/llvfs/lllfsthread.cpp
+++ b/indra/llvfs/lllfsthread.cpp
@@ -2,31 +2,25 @@
* @file lllfsthread.cpp
* @brief LLLFSThread base class
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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$
*/
@@ -51,7 +45,7 @@ void LLLFSThread::initClass(bool local_is_threaded)
//static
S32 LLLFSThread::updateClass(U32 ms_elapsed)
{
- sLocal->update(ms_elapsed);
+ sLocal->update((F32)ms_elapsed);
return sLocal->getPending();
}
@@ -103,7 +97,7 @@ LLLFSThread::handle_t LLLFSThread::read(const std::string& filename, /* Flawfind
bool res = addRequest(req);
if (!res)
{
- llerrs << "LLLFSThread::read called after LLLFSThread::cleanupClass()" << llendl;
+ LL_ERRS() << "LLLFSThread::read called after LLLFSThread::cleanupClass()" << LL_ENDL;
}
return handle;
@@ -125,7 +119,7 @@ LLLFSThread::handle_t LLLFSThread::write(const std::string& filename,
bool res = addRequest(req);
if (!res)
{
- llerrs << "LLLFSThread::read called after LLLFSThread::cleanupClass()" << llendl;
+ LL_ERRS() << "LLLFSThread::read called after LLLFSThread::cleanupClass()" << LL_ENDL;
}
return handle;
@@ -150,7 +144,7 @@ LLLFSThread::Request::Request(LLLFSThread* thread,
{
if (numbytes <= 0)
{
- llwarns << "LLLFSThread: Request with numbytes = " << numbytes << llendl;
+ LL_WARNS() << "LLLFSThread: Request with numbytes = " << numbytes << LL_ENDL;
}
}
@@ -172,7 +166,7 @@ void LLLFSThread::Request::deleteRequest()
{
if (getStatus() == STATUS_QUEUED)
{
- llerrs << "Attempt to delete a queued LLLFSThread::Request!" << llendl;
+ LL_ERRS() << "Attempt to delete a queued LLLFSThread::Request!" << LL_ENDL;
}
if (mResponder.notNull())
{
@@ -188,11 +182,11 @@ bool LLLFSThread::Request::processRequest()
if (mOperation == FILE_READ)
{
llassert(mOffset >= 0);
- LLAPRFile infile ;
+ LLAPRFile infile ; // auto-closes
infile.open(mFileName, LL_APR_RB, mThread->getLocalAPRFilePool());
if (!infile.getFileHandle())
{
- llwarns << "LLLFS: Unable to read file: " << mFileName << llendl;
+ LL_WARNS() << "LLLFS: Unable to read file: " << mFileName << LL_ENDL;
mBytesRead = 0; // fail
return true;
}
@@ -204,19 +198,18 @@ bool LLLFSThread::Request::processRequest()
llassert_always(off >= 0);
mBytesRead = infile.read(mBuffer, mBytes );
complete = true;
- infile.close() ;
-// llinfos << "LLLFSThread::READ:" << mFileName << " Bytes: " << mBytesRead << llendl;
+// LL_INFOS() << "LLLFSThread::READ:" << mFileName << " Bytes: " << mBytesRead << LL_ENDL;
}
else if (mOperation == FILE_WRITE)
{
apr_int32_t flags = APR_CREATE|APR_WRITE|APR_BINARY;
if (mOffset < 0)
flags |= APR_APPEND;
- LLAPRFile outfile ;
+ LLAPRFile outfile ; // auto-closes
outfile.open(mFileName, flags, mThread->getLocalAPRFilePool());
if (!outfile.getFileHandle())
{
- llwarns << "LLLFS: Unable to write file: " << mFileName << llendl;
+ LL_WARNS() << "LLLFS: Unable to write file: " << mFileName << LL_ENDL;
mBytesRead = 0; // fail
return true;
}
@@ -225,19 +218,18 @@ bool LLLFSThread::Request::processRequest()
S32 seek = outfile.seek(APR_SET, mOffset);
if (seek < 0)
{
- llwarns << "LLLFS: Unable to write file (seek failed): " << mFileName << llendl;
+ LL_WARNS() << "LLLFS: Unable to write file (seek failed): " << mFileName << LL_ENDL;
mBytesRead = 0; // fail
return true;
}
}
mBytesRead = outfile.write(mBuffer, mBytes );
complete = true;
-
-// llinfos << "LLLFSThread::WRITE:" << mFileName << " Bytes: " << mBytesRead << "/" << mBytes << " Offset:" << mOffset << llendl;
+// LL_INFOS() << "LLLFSThread::WRITE:" << mFileName << " Bytes: " << mBytesRead << "/" << mBytes << " Offset:" << mOffset << LL_ENDL;
}
else
{
- llerrs << "LLLFSThread::unknown operation: " << (S32)mOperation << llendl;
+ LL_ERRS() << "LLLFSThread::unknown operation: " << (S32)mOperation << LL_ENDL;
}
return complete;
}
diff --git a/indra/llvfs/lllfsthread.h b/indra/llvfs/lllfsthread.h
index 3139693302..cdb5c75946 100644..100755
--- a/indra/llvfs/lllfsthread.h
+++ b/indra/llvfs/lllfsthread.h
@@ -2,31 +2,25 @@
* @file lllfsthread.h
* @brief LLLFSThread base class
*
- * $LicenseInfo:firstyear=2000&license=viewergpl$
- *
- * Copyright (c) 2000-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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$
*/
diff --git a/indra/llvfs/llpidlock.cpp b/indra/llvfs/llpidlock.cpp
index 28cee29405..6572edead3 100755..100644
--- a/indra/llvfs/llpidlock.cpp
+++ b/indra/llvfs/llpidlock.cpp
@@ -3,31 +3,25 @@
* @date January 2007
* @brief string formatting utility
*
- * $LicenseInfo:firstyear=2007&license=viewergpl$
- *
- * Copyright (c) 2007-2009, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2007&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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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$
*/
@@ -44,12 +38,6 @@
#include <windows.h>
-namespace {
- inline DWORD getpid() {
- return GetCurrentProcessId();
- }
-}
-
bool isProcessAlive(U32 pid)
{
return (bool) GetProcessVersion((DWORD)pid);
@@ -107,11 +95,11 @@ LLPidLockFile& LLPidLockFile::instance()
void LLPidLockFile::writeLockFile(LLSD pids)
{
- llofstream ofile(mLockName);
+ llofstream ofile(mLockName.c_str());
if (!LLSDSerialize::toXML(pids,ofile))
{
- llwarns << "Unable to write concurrent save lock file." << llendl;
+ LL_WARNS() << "Unable to write concurrent save lock file." << LL_ENDL;
}
ofile.close();
}
@@ -131,7 +119,7 @@ bool LLPidLockFile::requestLock(LLNameTable<void *> *name_table, bool autosave,
LLSD out_pids;
out_pids.append( (LLSD::Integer)mPID );
- llifstream ifile(mLockName);
+ llifstream ifile(mLockName.c_str());
if (ifile.is_open())
{ //If file exists, we need to decide whether or not to continue.
@@ -187,7 +175,7 @@ bool LLPidLockFile::checkLock()
void LLPidLockFile::releaseLock()
{
- llifstream ifile(mLockName);
+ llifstream ifile(mLockName.c_str());
LLSD in_pids;
LLSD out_pids;
bool write_file=FALSE;
@@ -280,3 +268,8 @@ void LLPidLock::setSaveName(std::string savename)
{
LLPidLockFile::instance().mSaveName=savename;
}
+
+S32 LLPidLock::getPID()
+{
+ return (S32)getpid();
+}
diff --git a/indra/llvfs/llpidlock.h b/indra/llvfs/llpidlock.h
index 496e99cf5a..334f26bb29 100755..100644
--- a/indra/llvfs/llpidlock.h
+++ b/indra/llvfs/llpidlock.h
@@ -2,31 +2,25 @@
* @file llpidlock.h
* @brief System information debugging classes.
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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$
*/
@@ -45,21 +39,22 @@ 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);
+ 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();
+ S32 getPID();
+
+ //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 5fdf41188d..b8588e99f4 100644..100755
--- a/indra/llvfs/llvfile.cpp
+++ b/indra/llvfs/llvfile.cpp
@@ -2,31 +2,25 @@
* @file llvfile.cpp
* @brief Implementation of virtual file
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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,7 +30,9 @@
#include "llerror.h"
#include "llthread.h"
-#include "llstat.h"
+#include "lltimer.h"
+#include "llfasttimer.h"
+#include "llmemory.h"
#include "llvfs.h"
const S32 LLVFile::READ = 0x00000001;
@@ -44,7 +40,7 @@ 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");
+static LLTrace::BlockTimerStatHandle FTM_VFILE_WAIT("VFile Wait");
//----------------------------------------------------------------------------
LLVFSThread* LLVFile::sVFSThread = NULL;
@@ -77,7 +73,7 @@ LLVFile::~LLVFile()
{
if (!(mMode & LLVFile::WRITE))
{
- //llwarns << "Destroying LLVFile with pending async read/write, aborting..." << llendl;
+ //LL_WARNS() << "Destroying LLVFile with pending async read/write, aborting..." << LL_ENDL;
sVFSThread->setFlags(mHandle, LLVFSThread::FLAG_AUTO_COMPLETE | LLVFSThread::FLAG_ABORT);
}
else // WRITE
@@ -93,13 +89,13 @@ BOOL LLVFile::read(U8 *buffer, S32 bytes, BOOL async, F32 priority)
{
if (! (mMode & READ))
{
- llwarns << "Attempt to read from file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl;
+ LL_WARNS() << "Attempt to read from file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << LL_ENDL;
return FALSE;
}
if (mHandle != LLVFSThread::nullHandle())
{
- llwarns << "Attempt to read from vfile object " << mFileID << " with pending async operation" << llendl;
+ LL_WARNS() << "Attempt to read from vfile object " << mFileID << " with pending async operation" << LL_ENDL;
return FALSE;
}
mPriority = priority;
@@ -109,7 +105,7 @@ BOOL LLVFile::read(U8 *buffer, S32 bytes, BOOL async, F32 priority)
// We can't do a read while there are pending async writes
waitForLock(VFSLOCK_APPEND);
- // *FIX: (???)
+ // *FIX: (?)
if (async)
{
mHandle = sVFSThread->read(mVFS, mFileID, mFileType, buffer, mPosition, bytes, threadPri());
@@ -140,13 +136,13 @@ U8* LLVFile::readFile(LLVFS *vfs, const LLUUID &uuid, LLAssetType::EType type, S
data = NULL;
}
else
- {
- data = new U8[file_size];
+ {
+ data = (U8*) ll_aligned_malloc<16>(file_size);
file.read(data, file_size); /* Flawfinder: ignore */
if (file.getLastBytesRead() != (S32)file_size)
{
- delete[] data;
+ ll_aligned_free<16>(data);
data = NULL;
file_size = 0;
}
@@ -203,11 +199,11 @@ BOOL LLVFile::write(const U8 *buffer, S32 bytes)
{
if (! (mMode & WRITE))
{
- llwarns << "Attempt to write to file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl;
+ LL_WARNS() << "Attempt to write to file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << LL_ENDL;
}
if (mHandle != LLVFSThread::nullHandle())
{
- llerrs << "Attempt to write to vfile object " << mFileID << " with pending async operation" << llendl;
+ LL_ERRS() << "Attempt to write to vfile object " << mFileID << " with pending async operation" << LL_ENDL;
return FALSE;
}
BOOL success = TRUE;
@@ -237,7 +233,7 @@ BOOL LLVFile::write(const U8 *buffer, S32 bytes)
if (wrote < bytes)
{
- llwarns << "Tried to write " << bytes << " bytes, actually wrote " << wrote << llendl;
+ LL_WARNS() << "Tried to write " << bytes << " bytes, actually wrote " << wrote << LL_ENDL;
success = FALSE;
}
@@ -257,7 +253,7 @@ BOOL LLVFile::seek(S32 offset, S32 origin)
{
if (mMode == APPEND)
{
- llwarns << "Attempt to seek on append-only file" << llendl;
+ LL_WARNS() << "Attempt to seek on append-only file" << LL_ENDL;
return FALSE;
}
@@ -272,14 +268,14 @@ BOOL LLVFile::seek(S32 offset, S32 origin)
if (new_pos > size)
{
- llwarns << "Attempt to seek past end of file" << llendl;
+ LL_WARNS() << "Attempt to seek past end of file" << LL_ENDL;
mPosition = size;
return FALSE;
}
else if (new_pos < 0)
{
- llwarns << "Attempt to seek past beginning of file" << llendl;
+ LL_WARNS() << "Attempt to seek past beginning of file" << LL_ENDL;
mPosition = 0;
return FALSE;
@@ -313,20 +309,20 @@ BOOL LLVFile::setMaxSize(S32 size)
{
if (! (mMode & WRITE))
{
- llwarns << "Attempt to change size of file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl;
+ LL_WARNS() << "Attempt to change size of file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << LL_ENDL;
return FALSE;
}
if (!mVFS->checkAvailable(size))
{
- LLFastTimer t(FTM_VFILE_WAIT);
+ //LL_RECORD_BLOCK_TIME(FTM_VFILE_WAIT);
S32 count = 0;
while (sVFSThread->getPending() > 1000)
{
if (count % 100 == 0)
{
- llinfos << "VFS catching up... Pending: " << sVFSThread->getPending() << llendl;
+ LL_INFOS() << "VFS catching up... Pending: " << sVFSThread->getPending() << LL_ENDL;
}
if (sVFSThread->isPaused())
{
@@ -342,14 +338,14 @@ BOOL LLVFile::rename(const LLUUID &new_id, const LLAssetType::EType new_type)
{
if (! (mMode & WRITE))
{
- llwarns << "Attempt to rename file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl;
+ LL_WARNS() << "Attempt to rename file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << LL_ENDL;
return FALSE;
}
if (mHandle != LLVFSThread::nullHandle())
{
- llwarns << "Renaming file with pending async read" << llendl;
+ LL_WARNS() << "Renaming file with pending async read" << LL_ENDL;
}
waitForLock(VFSLOCK_READ);
@@ -369,18 +365,18 @@ BOOL LLVFile::rename(const LLUUID &new_id, const LLAssetType::EType new_type)
BOOL LLVFile::remove()
{
-// llinfos << "Removing file " << mFileID << llendl;
+// LL_INFOS() << "Removing file " << mFileID << LL_ENDL;
if (! (mMode & WRITE))
{
// Leaving paranoia warning just because this should be a very infrequent
// operation.
- llwarns << "Remove file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << llendl;
+ LL_WARNS() << "Remove file " << mFileID << " opened with mode " << std::hex << mMode << std::dec << LL_ENDL;
}
if (mHandle != LLVFSThread::nullHandle())
{
- llwarns << "Removing file with pending async read" << llendl;
+ LL_WARNS() << "Removing file with pending async read" << LL_ENDL;
}
// why not seek back to the beginning of the file too?
@@ -428,7 +424,7 @@ bool LLVFile::isLocked(EVFSLock lock)
void LLVFile::waitForLock(EVFSLock lock)
{
- LLFastTimer t(FTM_VFILE_WAIT);
+ //LL_RECORD_BLOCK_TIME(FTM_VFILE_WAIT);
// spin until the lock clears
while (isLocked(lock))
{
diff --git a/indra/llvfs/llvfile.h b/indra/llvfs/llvfile.h
index c3bca8c737..7e9d9f73e5 100644..100755
--- a/indra/llvfs/llvfile.h
+++ b/indra/llvfs/llvfile.h
@@ -2,31 +2,25 @@
* @file llvfile.h
* @brief Definition of virtual file
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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$
*/
diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp
index 9ce1e75d06..1cc0e819db 100644..100755
--- a/indra/llvfs/llvfs.cpp
+++ b/indra/llvfs/llvfs.cpp
@@ -2,36 +2,32 @@
* @file llvfs.cpp
* @brief Implementation of virtual file system
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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$
*/
#include "linden_common.h"
+#include "llvfs.h"
+
#include <sys/stat.h>
#include <set>
#include <map>
@@ -45,8 +41,6 @@
#include <sys/file.h>
#endif
-#include "llvfs.h"
-
#include "llstl.h"
#include "lltimer.h"
@@ -584,6 +578,7 @@ LLVFS::~LLVFS()
mFreeBlocksByLength.clear();
for_each(mFreeBlocksByLocation.begin(), mFreeBlocksByLocation.end(), DeletePairedPointer());
+ mFreeBlocksByLocation.clear();
unlockAndClose(mDataFP);
mDataFP = NULL;
@@ -643,7 +638,7 @@ void LLVFS::presizeDataFile(const U32 size)
{
if (!mDataFP)
{
- llerrs << "LLVFS::presizeDataFile() with no data file open" << llendl;
+ LL_ERRS() << "LLVFS::presizeDataFile() with no data file open" << LL_ENDL;
return;
}
@@ -658,11 +653,11 @@ void LLVFS::presizeDataFile(const U32 size)
if (tmp)
{
- llinfos << "Pre-sized VFS data file to " << ftell(mDataFP) << " bytes" << llendl;
+ LL_INFOS() << "Pre-sized VFS data file to " << ftell(mDataFP) << " bytes" << LL_ENDL;
}
else
{
- llwarns << "Failed to pre-size VFS data file" << llendl;
+ LL_WARNS() << "Failed to pre-size VFS data file" << LL_ENDL;
}
}
@@ -672,7 +667,7 @@ BOOL LLVFS::getExists(const LLUUID &file_id, const LLAssetType::EType file_type)
if (!isValid())
{
- llerrs << "Attempting to use invalid VFS!" << llendl;
+ LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL;
}
lockData();
@@ -698,7 +693,7 @@ S32 LLVFS::getSize(const LLUUID &file_id, const LLAssetType::EType file_type)
if (!isValid())
{
- llerrs << "Attempting to use invalid VFS!" << llendl;
+ LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL;
}
@@ -725,7 +720,7 @@ S32 LLVFS::getMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type
if (!isValid())
{
- llerrs << "Attempting to use invalid VFS!" << llendl;
+ LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL;
}
lockData();
@@ -761,15 +756,15 @@ BOOL LLVFS::setMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type
{
if (!isValid())
{
- llerrs << "Attempting to use invalid VFS!" << llendl;
+ LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL;
}
if (mReadOnly)
{
- llerrs << "Attempt to write to read-only VFS" << llendl;
+ LL_ERRS() << "Attempt to write to read-only VFS" << LL_ENDL;
}
if (max_size <= 0)
{
- llwarns << "VFS: Attempt to assign size " << max_size << " to vfile " << file_id << llendl;
+ LL_WARNS() << "VFS: Attempt to assign size " << max_size << " to vfile " << file_id << LL_ENDL;
return FALSE;
}
@@ -816,7 +811,7 @@ BOOL LLVFS::setMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type
if (block->mLength < block->mSize)
{
// JC: Was a warning, but Ian says it's bad.
- llerrs << "Truncating virtual file " << file_id << " to " << block->mLength << " bytes" << llendl;
+ LL_ERRS() << "Truncating virtual file " << file_id << " to " << block->mLength << " bytes" << LL_ENDL;
block->mSize = block->mLength;
}
@@ -884,10 +879,10 @@ BOOL LLVFS::setMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type
fseek(mDataFP, new_data_location, SEEK_SET);
if (fwrite(&buffer[0], block->mSize, 1, mDataFP) != 1)
{
- llwarns << "Short write" << llendl;
+ LL_WARNS() << "Short write" << LL_ENDL;
}
} else {
- llwarns << "Short read" << llendl;
+ LL_WARNS() << "Short read" << LL_ENDL;
}
}
}
@@ -904,7 +899,7 @@ BOOL LLVFS::setMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type
}
else
{
- llwarns << "VFS: No space (" << max_size << ") to resize existing vfile " << file_id << llendl;
+ LL_WARNS() << "VFS: No space (" << max_size << ") to resize existing vfile " << file_id << LL_ENDL;
//dumpMap();
unlockData();
dumpStatistics();
@@ -940,7 +935,7 @@ BOOL LLVFS::setMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type
}
else
{
- llwarns << "VFS: No space (" << max_size << ") for new virtual file " << file_id << llendl;
+ LL_WARNS() << "VFS: No space (" << max_size << ") for new virtual file " << file_id << LL_ENDL;
//dumpMap();
unlockData();
dumpStatistics();
@@ -959,11 +954,11 @@ void LLVFS::renameFile(const LLUUID &file_id, const LLAssetType::EType file_type
{
if (!isValid())
{
- llerrs << "Attempting to use invalid VFS!" << llendl;
+ LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL;
}
if (mReadOnly)
{
- llerrs << "Attempt to write to read-only VFS" << llendl;
+ LL_ERRS() << "Attempt to write to read-only VFS" << LL_ENDL;
}
lockData();
@@ -995,7 +990,7 @@ void LLVFS::renameFile(const LLUUID &file_id, const LLAssetType::EType file_type
{
if(dest_block->mLocks[i])
{
- llerrs << "Renaming VFS block to a locked file." << llendl;
+ LL_ERRS() << "Renaming VFS block to a locked file." << LL_ENDL;
}
dest_block->mLocks[i] = src_block->mLocks[i];
}
@@ -1015,7 +1010,7 @@ void LLVFS::renameFile(const LLUUID &file_id, const LLAssetType::EType file_type
}
else
{
- llwarns << "VFS: Attempt to rename nonexistent vfile " << file_id << ":" << file_type << llendl;
+ LL_WARNS() << "VFS: Attempt to rename nonexistent vfile " << file_id << ":" << file_type << LL_ENDL;
}
unlockData();
}
@@ -1047,11 +1042,11 @@ void LLVFS::removeFile(const LLUUID &file_id, const LLAssetType::EType file_type
{
if (!isValid())
{
- llerrs << "Attempting to use invalid VFS!" << llendl;
+ LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL;
}
if (mReadOnly)
{
- llerrs << "Attempt to write to read-only VFS" << llendl;
+ LL_ERRS() << "Attempt to write to read-only VFS" << LL_ENDL;
}
lockData();
@@ -1065,7 +1060,7 @@ void LLVFS::removeFile(const LLUUID &file_id, const LLAssetType::EType file_type
}
else
{
- llwarns << "VFS: attempting to remove nonexistent file " << file_id << " type " << file_type << llendl;
+ LL_WARNS() << "VFS: attempting to remove nonexistent file " << file_id << " type " << file_type << LL_ENDL;
}
unlockData();
@@ -1078,7 +1073,7 @@ S32 LLVFS::getData(const LLUUID &file_id, const LLAssetType::EType file_type, U8
if (!isValid())
{
- llerrs << "Attempting to use invalid VFS!" << llendl;
+ LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL;
}
llassert(location >= 0);
llassert(length >= 0);
@@ -1097,7 +1092,7 @@ S32 LLVFS::getData(const LLUUID &file_id, const LLAssetType::EType file_type, U8
if (location > block->mSize)
{
- llwarns << "VFS: Attempt to read location " << location << " in file " << file_id << " of length " << block->mSize << llendl;
+ LL_WARNS() << "VFS: Attempt to read location " << location << " in file " << file_id << " of length " << block->mSize << LL_ENDL;
}
else
{
@@ -1125,11 +1120,11 @@ S32 LLVFS::storeData(const LLUUID &file_id, const LLAssetType::EType file_type,
{
if (!isValid())
{
- llerrs << "Attempting to use invalid VFS!" << llendl;
+ LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL;
}
if (mReadOnly)
{
- llerrs << "Attempt to write to read-only VFS" << llendl;
+ LL_ERRS() << "Attempt to write to read-only VFS" << LL_ENDL;
}
llassert(length > 0);
@@ -1154,22 +1149,22 @@ S32 LLVFS::storeData(const LLUUID &file_id, const LLAssetType::EType file_type,
if (block->mLength == BLOCK_LENGTH_INVALID)
{
// Block was removed, ignore write
- llwarns << "VFS: Attempt to write to invalid block"
+ LL_WARNS() << "VFS: Attempt to write to invalid block"
<< " in file " << file_id
<< " location: " << in_loc
<< " bytes: " << length
- << llendl;
+ << LL_ENDL;
unlockData();
return length;
}
else if (location > block->mLength)
{
- llwarns << "VFS: Attempt to write to location " << location
+ LL_WARNS() << "VFS: Attempt to write to location " << location
<< " in file " << file_id
<< " type " << S32(file_type)
<< " of size " << block->mSize
<< " block length " << block->mLength
- << llendl;
+ << LL_ENDL;
unlockData();
return length;
}
@@ -1177,7 +1172,7 @@ S32 LLVFS::storeData(const LLUUID &file_id, const LLAssetType::EType file_type,
{
if (length > block->mLength - location )
{
- llwarns << "VFS: Truncating write to virtual file " << file_id << " type " << S32(file_type) << llendl;
+ LL_WARNS() << "VFS: Truncating write to virtual file " << file_id << " type " << S32(file_type) << LL_ENDL;
length = block->mLength - location;
}
U32 file_location = location + block->mLocation;
@@ -1186,7 +1181,7 @@ S32 LLVFS::storeData(const LLUUID &file_id, const LLAssetType::EType file_type,
S32 write_len = (S32)fwrite(buffer, 1, length, mDataFP);
if (write_len != length)
{
- llwarns << llformat("VFS Write Error: %d != %d",write_len,length) << llendl;
+ LL_WARNS() << llformat("VFS Write Error: %d != %d",write_len,length) << LL_ENDL;
}
// fflush(mDataFP);
@@ -1249,7 +1244,7 @@ void LLVFS::decLock(const LLUUID &file_id, const LLAssetType::EType file_type, E
}
else
{
- llwarns << "VFS: Decrementing zero-value lock " << lock << llendl;
+ LL_WARNS() << "VFS: Decrementing zero-value lock " << lock << LL_ENDL;
}
mLockCounts[lock]--;
}
@@ -1301,7 +1296,7 @@ void LLVFS::eraseBlockLength(LLVFSBlock *block)
}
if(!found_block)
{
- llerrs << "eraseBlock could not find block" << llendl;
+ LL_ERRS() << "eraseBlock could not find block" << LL_ENDL;
}
}
@@ -1324,7 +1319,7 @@ void LLVFS::addFreeBlock(LLVFSBlock *block)
size_t dbgcount = mFreeBlocksByLocation.count(block->mLocation);
if(dbgcount > 0)
{
- llerrs << "addFreeBlock called with block already in list" << llendl;
+ LL_ERRS() << "addFreeBlock called with block already in list" << LL_ENDL;
}
#endif
@@ -1353,7 +1348,7 @@ void LLVFS::addFreeBlock(LLVFSBlock *block)
if (merge_prev && merge_next)
{
- // llinfos << "VFS merge BOTH" << llendl;
+ // LL_INFOS() << "VFS merge BOTH" << LL_ENDL;
// Previous block is changing length (a lot), so only need to update length map.
// Next block is going away completely. JC
eraseBlockLength(prev_block);
@@ -1367,7 +1362,7 @@ void LLVFS::addFreeBlock(LLVFSBlock *block)
}
else if (merge_prev)
{
- // llinfos << "VFS merge previous" << llendl;
+ // LL_INFOS() << "VFS merge previous" << LL_ENDL;
// Previous block is maintaining location, only changing length,
// therefore only need to update the length map. JC
eraseBlockLength(prev_block);
@@ -1378,7 +1373,7 @@ void LLVFS::addFreeBlock(LLVFSBlock *block)
}
else if (merge_next)
{
- // llinfos << "VFS merge next" << llendl;
+ // LL_INFOS() << "VFS merge next" << LL_ENDL;
// Next block is changing both location and length,
// so both free lists must update. JC
eraseBlock(next_block);
@@ -1405,7 +1400,7 @@ void LLVFS::addFreeBlock(LLVFSBlock *block)
//{
// if (!isValid())
// {
-// llerrs << "Attempting to use invalid VFS!" << llendl;
+// LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL;
// }
// // TODO: could we optimize this with hints from the calling code?
// blocks_location_map_t::iterator iter = mFreeBlocksByLocation.begin();
@@ -1464,11 +1459,11 @@ void LLVFS::sync(LLVFSFileBlock *block, BOOL remove)
{
if (!isValid())
{
- llerrs << "Attempting to use invalid VFS!" << llendl;
+ LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL;
}
if (mReadOnly)
{
- llwarns << "Attempt to sync read-only VFS" << llendl;
+ LL_WARNS() << "Attempt to sync read-only VFS" << LL_ENDL;
return;
}
if (block->mLength == BLOCK_LENGTH_INVALID)
@@ -1478,7 +1473,7 @@ void LLVFS::sync(LLVFSFileBlock *block, BOOL remove)
}
if (block->mLength == 0)
{
- llerrs << "VFS syncing zero-length block" << llendl;
+ LL_ERRS() << "VFS syncing zero-length block" << LL_ENDL;
}
BOOL set_index_to_end = FALSE;
@@ -1530,7 +1525,7 @@ void LLVFS::sync(LLVFSFileBlock *block, BOOL remove)
if (fwrite(buffer, LLVFSFileBlock::SERIAL_SIZE, 1, mIndexFP) != 1)
{
- llwarns << "Short write" << llendl;
+ LL_WARNS() << "Short write" << LL_ENDL;
}
// *NOTE: Why was this commented out?
@@ -1546,7 +1541,7 @@ LLVFSBlock *LLVFS::findFreeBlock(S32 size, LLVFSFileBlock *immune)
{
if (!isValid())
{
- llerrs << "Attempting to use invalid VFS!" << llendl;
+ LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL;
}
LLVFSBlock *block = NULL;
@@ -1591,7 +1586,7 @@ LLVFSBlock *LLVFS::findFreeBlock(S32 size, LLVFSFileBlock *immune)
if (lru_list.size() == 0)
{
// No more files to delete, and still not enough room!
- llwarns << "VFS: Can't make " << size << " bytes of free space in VFS, giving up" << llendl;
+ LL_WARNS() << "VFS: Can't make " << size << " bytes of free space in VFS, giving up" << LL_ENDL;
break;
}
@@ -1602,7 +1597,7 @@ LLVFSBlock *LLVFS::findFreeBlock(S32 size, LLVFSFileBlock *immune)
{
// ditch this file and look again for a free block - should find it
// TODO: it'll be faster just to assign the free block and break
- llinfos << "LRU: Removing " << file_block->mFileID << ":" << file_block->mFileType << llendl;
+ LL_INFOS() << "LRU: Removing " << file_block->mFileID << ":" << file_block->mFileType << LL_ENDL;
lru_list.erase(it);
removeFileBlock(file_block);
file_block = NULL;
@@ -1610,7 +1605,7 @@ LLVFSBlock *LLVFS::findFreeBlock(S32 size, LLVFSFileBlock *immune)
}
- llinfos << "VFS: LRU: Aggressive: " << (S32)lru_list.size() << " files remain" << llendl;
+ LL_INFOS() << "VFS: LRU: Aggressive: " << (S32)lru_list.size() << " files remain" << LL_ENDL;
dumpLockCounts();
// Now it's time to aggressively make more space
@@ -1625,7 +1620,7 @@ LLVFSBlock *LLVFS::findFreeBlock(S32 size, LLVFSFileBlock *immune)
file_block = *it;
// TODO: it would be great to be able to batch all these sync() calls
- // llinfos << "LRU2: Removing " << file_block->mFileID << ":" << file_block->mFileType << " last accessed" << file_block->mAccessTime << llendl;
+ // LL_INFOS() << "LRU2: Removing " << file_block->mFileID << ":" << file_block->mFileType << " last accessed" << file_block->mAccessTime << LL_ENDL;
cleaned_up += file_block->mLength;
lru_list.erase(it++);
@@ -1639,7 +1634,7 @@ LLVFSBlock *LLVFS::findFreeBlock(S32 size, LLVFSFileBlock *immune)
F32 time = timer.getElapsedTimeF32();
if (time > 0.5f)
{
- llwarns << "VFS: Spent " << time << " seconds in findFreeBlock!" << llendl;
+ LL_WARNS() << "VFS: Spent " << time << " seconds in findFreeBlock!" << LL_ENDL;
}
return block;
@@ -1653,7 +1648,7 @@ void LLVFS::pokeFiles()
{
if (!isValid())
{
- llerrs << "Attempting to use invalid VFS!" << llendl;
+ LL_ERRS() << "Attempting to use invalid VFS!" << LL_ENDL;
}
U32 word;
@@ -1665,7 +1660,7 @@ void LLVFS::pokeFiles()
fseek(mDataFP, 0, SEEK_SET);
if (fwrite(&word, sizeof(word), 1, mDataFP) != 1)
{
- llwarns << "Could not write to data file" << llendl;
+ LL_WARNS() << "Could not write to data file" << LL_ENDL;
}
fflush(mDataFP);
}
@@ -1676,7 +1671,7 @@ void LLVFS::pokeFiles()
fseek(mIndexFP, 0, SEEK_SET);
if (fwrite(&word, sizeof(word), 1, mIndexFP) != 1)
{
- llwarns << "Could not write to index file" << llendl;
+ LL_WARNS() << "Could not write to index file" << LL_ENDL;
}
fflush(mIndexFP);
}
@@ -1685,20 +1680,20 @@ void LLVFS::pokeFiles()
void LLVFS::dumpMap()
{
- llinfos << "Files:" << llendl;
+ LL_INFOS() << "Files:" << LL_ENDL;
for (fileblock_map::iterator it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it)
{
LLVFSFileBlock *file_block = (*it).second;
- llinfos << "Location: " << file_block->mLocation << "\tLength: " << file_block->mLength << "\t" << file_block->mFileID << "\t" << file_block->mFileType << llendl;
+ LL_INFOS() << "Location: " << file_block->mLocation << "\tLength: " << file_block->mLength << "\t" << file_block->mFileID << "\t" << file_block->mFileType << LL_ENDL;
}
- llinfos << "Free Blocks:" << llendl;
+ LL_INFOS() << "Free Blocks:" << LL_ENDL;
for (blocks_location_map_t::iterator iter = mFreeBlocksByLocation.begin(),
end = mFreeBlocksByLocation.end();
iter != end; iter++)
{
LLVFSBlock *free_block = iter->second;
- llinfos << "Location: " << free_block->mLocation << "\tLength: " << free_block->mLength << llendl;
+ LL_INFOS() << "Location: " << free_block->mLocation << "\tLength: " << free_block->mLength << LL_ENDL;
}
}
@@ -1717,11 +1712,12 @@ void LLVFS::audit()
BOOL vfs_corrupt = FALSE;
- std::vector<U8> buffer(index_size);
+ // since we take the address of element 0, we need to have at least one element.
+ std::vector<U8> buffer(llmax<size_t>(index_size,1U));
if (fread(&buffer[0], 1, index_size, mIndexFP) != index_size)
{
- llwarns << "Index truncated" << llendl;
+ LL_WARNS() << "Index truncated" << LL_ENDL;
vfs_corrupt = TRUE;
}
@@ -1750,7 +1746,7 @@ void LLVFS::audit()
{
if (mFileBlocks.find(*block) == mFileBlocks.end())
{
- llwarns << "VFile " << block->mFileID << ":" << block->mFileType << " on disk, not in memory, loc " << block->mIndexLocation << llendl;
+ LL_WARNS() << "VFile " << block->mFileID << ":" << block->mFileType << " on disk, not in memory, loc " << block->mIndexLocation << LL_ENDL;
}
else if (found_files.find(*block) != found_files.end())
{
@@ -1762,22 +1758,22 @@ void LLVFS::audit()
mIndexFP = NULL;
unlockAndClose(mDataFP);
mDataFP = NULL;
- llwarns << "VFS: Original block index " << block->mIndexLocation
+ LL_WARNS() << "VFS: Original block index " << block->mIndexLocation
<< " location " << block->mLocation
<< " length " << block->mLength
<< " size " << block->mSize
<< " id " << block->mFileID
<< " type " << block->mFileType
- << llendl;
- llwarns << "VFS: Duplicate block index " << dupe->mIndexLocation
+ << LL_ENDL;
+ LL_WARNS() << "VFS: Duplicate block index " << dupe->mIndexLocation
<< " location " << dupe->mLocation
<< " length " << dupe->mLength
<< " size " << dupe->mSize
<< " id " << dupe->mFileID
<< " type " << dupe->mFileType
- << llendl;
- llwarns << "VFS: Index size " << index_size << llendl;
- llwarns << "VFS: INDEX CORRUPT" << llendl;
+ << LL_ENDL;
+ LL_WARNS() << "VFS: Index size " << index_size << LL_ENDL;
+ LL_WARNS() << "VFS: INDEX CORRUPT" << LL_ENDL;
vfs_corrupt = TRUE;
break;
}
@@ -1790,7 +1786,7 @@ void LLVFS::audit()
{
if (block->mLength)
{
- llwarns << "VFile " << block->mFileID << ":" << block->mFileType << " corrupt on disk" << llendl;
+ LL_WARNS() << "VFile " << block->mFileID << ":" << block->mFileType << " corrupt on disk" << LL_ENDL;
}
// else this is just a hole
}
@@ -1806,19 +1802,19 @@ void LLVFS::audit()
{
if (! found_files.count(*block))
{
- llwarns << "VFile " << block->mFileID << ":" << block->mFileType << " in memory, not on disk, loc " << block->mIndexLocation<< llendl;
+ LL_WARNS() << "VFile " << block->mFileID << ":" << block->mFileType << " in memory, not on disk, loc " << block->mIndexLocation<< LL_ENDL;
fseek(mIndexFP, block->mIndexLocation, SEEK_SET);
U8 buf[LLVFSFileBlock::SERIAL_SIZE];
if (fread(buf, LLVFSFileBlock::SERIAL_SIZE, 1, mIndexFP) != 1)
{
- llwarns << "VFile " << block->mFileID
- << " gave short read" << llendl;
+ LL_WARNS() << "VFile " << block->mFileID
+ << " gave short read" << LL_ENDL;
}
LLVFSFileBlock disk_block;
disk_block.deserialize(buf, block->mIndexLocation);
- llwarns << "Instead found " << disk_block.mFileID << ":" << block->mFileType << llendl;
+ LL_WARNS() << "Instead found " << disk_block.mFileID << ":" << block->mFileType << LL_ENDL;
}
else
{
@@ -1832,14 +1828,15 @@ void LLVFS::audit()
iter != found_files.end(); iter++)
{
LLVFSFileBlock* block = iter->second;
- llwarns << "VFile " << block->mFileID << ":" << block->mFileType << " szie:" << block->mSize << " leftover" << llendl;
+ LL_WARNS() << "VFile " << block->mFileID << ":" << block->mFileType << " szie:" << block->mSize << " leftover" << LL_ENDL;
}
- llinfos << "VFS: audit OK" << llendl;
+ LL_INFOS() << "VFS: audit OK" << LL_ENDL;
// mutex released by LLMutexLock() destructor.
}
for_each(audit_blocks.begin(), audit_blocks.end(), DeletePointer());
+ audit_blocks.clear();
}
@@ -1862,12 +1859,12 @@ void LLVFS::checkMem()
S32 index_loc = *iter;
if (index_loc == block->mIndexLocation)
{
- llwarns << "VFile block " << block->mFileID << ":" << block->mFileType << " is marked as a hole" << llendl;
+ LL_WARNS() << "VFile block " << block->mFileID << ":" << block->mFileType << " is marked as a hole" << LL_ENDL;
}
}
}
- llinfos << "VFS: mem check OK" << llendl;
+ LL_INFOS() << "VFS: mem check OK" << LL_ENDL;
unlockData();
}
@@ -1877,7 +1874,7 @@ void LLVFS::dumpLockCounts()
S32 i;
for (i = 0; i < VFSLOCK_COUNT; i++)
{
- llinfos << "LockType: " << i << ": " << mLockCounts[i] << llendl;
+ LL_INFOS() << "LockType: " << i << ": " << mLockCounts[i] << LL_ENDL;
}
}
@@ -1902,7 +1899,7 @@ void LLVFS::dumpStatistics()
}
else if (file_block->mLength <= 0)
{
- llinfos << "Bad file block at: " << file_block->mLocation << "\tLength: " << file_block->mLength << "\t" << file_block->mFileID << "\t" << file_block->mFileType << llendl;
+ LL_INFOS() << "Bad file block at: " << file_block->mLocation << "\tLength: " << file_block->mLength << "\t" << file_block->mFileID << "\t" << file_block->mFileType << LL_ENDL;
size_counts[file_block->mLength]++;
location_counts[file_block->mLocation]++;
}
@@ -1924,13 +1921,13 @@ void LLVFS::dumpStatistics()
{
S32 size = it->first;
S32 size_count = it->second;
- llinfos << "Bad files size " << size << " count " << size_count << llendl;
+ LL_INFOS() << "Bad files size " << size << " count " << size_count << LL_ENDL;
}
for (std::map<U32,S32>::iterator it = location_counts.begin(); it != location_counts.end(); ++it)
{
U32 location = it->first;
S32 location_count = it->second;
- llinfos << "Bad files location " << location << " count " << location_count << llendl;
+ LL_INFOS() << "Bad files location " << location << " count " << location_count << LL_ENDL;
}
// Investigate free list.
@@ -1944,14 +1941,14 @@ void LLVFS::dumpStatistics()
LLVFSBlock *free_block = iter->second;
if (free_block->mLength <= 0)
{
- llinfos << "Bad free block at: " << free_block->mLocation << "\tLength: " << free_block->mLength << llendl;
+ LL_INFOS() << "Bad free block at: " << free_block->mLocation << "\tLength: " << free_block->mLength << LL_ENDL;
}
else
{
- llinfos << "Block: " << free_block->mLocation
+ LL_INFOS() << "Block: " << free_block->mLocation
<< "\tLength: " << free_block->mLength
<< "\tEnd: " << free_block->mLocation + free_block->mLength
- << llendl;
+ << LL_ENDL;
total_free_size += free_block->mLength;
}
@@ -1966,38 +1963,38 @@ void LLVFS::dumpStatistics()
// Dump histogram of free block sizes
for (std::map<S32,S32>::iterator it = free_length_counts.begin(); it != free_length_counts.end(); ++it)
{
- llinfos << "Free length " << it->first << " count " << it->second << llendl;
+ LL_INFOS() << "Free length " << it->first << " count " << it->second << LL_ENDL;
}
- llinfos << "Invalid blocks: " << invalid_file_count << llendl;
- llinfos << "File blocks: " << mFileBlocks.size() << llendl;
+ LL_INFOS() << "Invalid blocks: " << invalid_file_count << LL_ENDL;
+ LL_INFOS() << "File blocks: " << mFileBlocks.size() << LL_ENDL;
S32 length_list_count = (S32)mFreeBlocksByLength.size();
S32 location_list_count = (S32)mFreeBlocksByLocation.size();
if (length_list_count == location_list_count)
{
- llinfos << "Free list lengths match, free blocks: " << location_list_count << llendl;
+ LL_INFOS() << "Free list lengths match, free blocks: " << location_list_count << LL_ENDL;
}
else
{
- llwarns << "Free list lengths do not match!" << llendl;
- llwarns << "By length: " << length_list_count << llendl;
- llwarns << "By location: " << location_list_count << llendl;
+ LL_WARNS() << "Free list lengths do not match!" << LL_ENDL;
+ LL_WARNS() << "By length: " << length_list_count << LL_ENDL;
+ LL_WARNS() << "By location: " << location_list_count << LL_ENDL;
}
- llinfos << "Max file: " << max_file_size/1024 << "K" << llendl;
- llinfos << "Max free: " << max_free_size/1024 << "K" << llendl;
- llinfos << "Total file size: " << total_file_size/1024 << "K" << llendl;
- llinfos << "Total free size: " << total_free_size/1024 << "K" << llendl;
- llinfos << "Sum: " << (total_file_size + total_free_size) << " bytes" << llendl;
- llinfos << llformat("%.0f%% full",((F32)(total_file_size)/(F32)(total_file_size+total_free_size))*100.f) << llendl;
+ LL_INFOS() << "Max file: " << max_file_size/1024 << "K" << LL_ENDL;
+ LL_INFOS() << "Max free: " << max_free_size/1024 << "K" << LL_ENDL;
+ LL_INFOS() << "Total file size: " << total_file_size/1024 << "K" << LL_ENDL;
+ LL_INFOS() << "Total free size: " << total_free_size/1024 << "K" << LL_ENDL;
+ LL_INFOS() << "Sum: " << (total_file_size + total_free_size) << " bytes" << LL_ENDL;
+ LL_INFOS() << llformat("%.0f%% full",((F32)(total_file_size)/(F32)(total_file_size+total_free_size))*100.f) << LL_ENDL;
- llinfos << " " << llendl;
+ LL_INFOS() << " " << LL_ENDL;
for (std::map<LLAssetType::EType, std::pair<S32,S32> >::iterator iter = filetype_counts.begin();
iter != filetype_counts.end(); ++iter)
{
- llinfos << "Type: " << LLAssetType::getDesc(iter->first)
+ LL_INFOS() << "Type: " << LLAssetType::getDesc(iter->first)
<< " Count: " << iter->second.first
- << " Bytes: " << (iter->second.second>>20) << " MB" << llendl;
+ << " Bytes: " << (iter->second.second>>20) << " MB" << LL_ENDL;
}
// Look for potential merges
@@ -2012,7 +2009,7 @@ void LLVFS::dumpStatistics()
LLVFSBlock *second_block = iter->second;
if (first_block->mLocation + first_block->mLength == second_block->mLocation)
{
- llinfos << "Potential merge at " << first_block->mLocation << llendl;
+ LL_INFOS() << "Potential merge at " << first_block->mLocation << LL_ENDL;
}
first_block = second_block;
}
@@ -2041,6 +2038,9 @@ std::string get_extension(LLAssetType::EType type)
case LLAssetType::AT_ANIMATION:
extension = ".lla";
break;
+ case LLAssetType::AT_MESH:
+ extension = ".slm";
+ break;
default:
// Just use the asset server filename extension in most cases
extension += ".";
@@ -2064,10 +2064,10 @@ void LLVFS::listFiles()
{
LLUUID id = file_spec.mFileID;
std::string extension = get_extension(file_spec.mFileType);
- llinfos << " File: " << id
+ LL_INFOS() << " File: " << id
<< " Type: " << LLAssetType::getDesc(file_spec.mFileType)
<< " Size: " << size
- << llendl;
+ << LL_ENDL;
}
}
@@ -2098,7 +2098,7 @@ void LLVFS::dumpFiles()
std::string extension = get_extension(type);
std::string filename = id.asString() + extension;
- llinfos << " Writing " << filename << llendl;
+ LL_INFOS() << " Writing " << filename << LL_ENDL;
LLAPRFile outfile;
outfile.open(filename, LL_APR_WB);
@@ -2111,7 +2111,7 @@ void LLVFS::dumpFiles()
unlockData();
- llinfos << "Extracted " << files_extracted << " files out of " << mFileBlocks.size() << llendl;
+ LL_INFOS() << "Extracted " << files_extracted << " files out of " << mFileBlocks.size() << LL_ENDL;
}
//============================================================================
diff --git a/indra/llvfs/llvfs.h b/indra/llvfs/llvfs.h
index 2acda7ae29..39f31a221b 100644..100755
--- a/indra/llvfs/llvfs.h
+++ b/indra/llvfs/llvfs.h
@@ -2,31 +2,25 @@
* @file llvfs.h
* @brief Definition of virtual file system
*
- * $LicenseInfo:firstyear=2002&license=viewergpl$
- *
- * Copyright (c) 2002-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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$
*/
@@ -35,7 +29,6 @@
#include <deque>
#include "lluuid.h"
-#include "linked_lists.h"
#include "llassettype.h"
#include "llthread.h"
diff --git a/indra/llvfs/llvfs_objc.h b/indra/llvfs/llvfs_objc.h
new file mode 100755
index 0000000000..56cdbebfc5
--- /dev/null
+++ b/indra/llvfs/llvfs_objc.h
@@ -0,0 +1,43 @@
+/**
+ * @file llvfs_objc.h
+ * @brief Definition of directory utilities class for Mac OS X
+ *
+ * $LicenseInfo:firstyear=2000&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$
+ */
+
+#if !LL_DARWIN
+#error This header must not be included when compiling for any target other than Mac OS. Consider including lldir.h instead.
+#endif // !LL_DARWIN
+
+#ifndef LL_LLVFS_OBJC_H
+#define LL_LLVFS_OBJC_H
+
+#include <iostream>
+
+std::string* getSystemTempFolder();
+std::string* getSystemCacheFolder();
+std::string* getSystemApplicationSupportFolder();
+std::string* getSystemResourceFolder();
+std::string* getSystemExecutableFolder();
+
+
+#endif // LL_LLVFS_OBJC_H
diff --git a/indra/llvfs/llvfs_objc.mm b/indra/llvfs/llvfs_objc.mm
new file mode 100755
index 0000000000..282ea41339
--- /dev/null
+++ b/indra/llvfs/llvfs_objc.mm
@@ -0,0 +1,108 @@
+/**
+ * @file llvfs_objc.cpp
+ * @brief Cocoa implementation of directory utilities for Mac OS X
+ *
+ * $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$
+ */
+#if LL_DARWIN
+
+//WARNING: This file CANNOT use standard linden includes due to conflicts between definitions of BOOL
+
+#include "llvfs_objc.h"
+#import <Cocoa/Cocoa.h>
+
+std::string* getSystemTempFolder()
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ NSString * tempDir = NSTemporaryDirectory();
+ if (tempDir == nil)
+ tempDir = @"/tmp";
+ std::string *result = ( new std::string([tempDir UTF8String]) );
+ [pool release];
+
+ return result;
+}
+
+//findSystemDirectory scoped exclusively to this file.
+std::string* findSystemDirectory(NSSearchPathDirectory searchPathDirectory,
+ NSSearchPathDomainMask domainMask)
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ std::string *result = nil;
+ NSString *path = nil;
+
+ // Search for the path
+ NSArray* paths = NSSearchPathForDirectoriesInDomains(searchPathDirectory,
+ domainMask,
+ YES);
+ if ([paths count])
+ {
+ path = [paths objectAtIndex:0];
+ //HACK: Always attempt to create directory, ignore errors.
+ NSError *error = nil;
+
+ [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&error];
+
+
+ result = new std::string([path UTF8String]);
+ }
+ [pool release];
+ return result;
+}
+
+std::string* getSystemExecutableFolder()
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSString *bundlePath = [[NSBundle mainBundle] executablePath];
+ std::string *result = (new std::string([bundlePath UTF8String]));
+ [pool release];
+
+ return result;
+}
+
+std::string* getSystemResourceFolder()
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSString *bundlePath = [[NSBundle mainBundle] resourcePath];
+ std::string *result = (new std::string([bundlePath UTF8String]));
+ [pool release];
+
+ return result;
+}
+
+std::string* getSystemCacheFolder()
+{
+ return findSystemDirectory (NSCachesDirectory,
+ NSUserDomainMask);
+}
+
+std::string* getSystemApplicationSupportFolder()
+{
+ return findSystemDirectory (NSApplicationSupportDirectory,
+ NSUserDomainMask);
+
+}
+
+#endif // LL_DARWIN
diff --git a/indra/llvfs/llvfsthread.cpp b/indra/llvfs/llvfsthread.cpp
index 69da4b75e5..8cd85929e2 100644..100755
--- a/indra/llvfs/llvfsthread.cpp
+++ b/indra/llvfs/llvfsthread.cpp
@@ -2,31 +2,25 @@
* @file llvfsthread.cpp
* @brief LLVFSThread implementation
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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$
*/
@@ -52,7 +46,7 @@ void LLVFSThread::initClass(bool local_is_threaded)
//static
S32 LLVFSThread::updateClass(U32 ms_elapsed)
{
- sLocal->update(ms_elapsed);
+ sLocal->update((F32)ms_elapsed);
return sLocal->getPending();
}
@@ -94,7 +88,7 @@ LLVFSThread::handle_t LLVFSThread::read(LLVFS* vfs, const LLUUID &file_id, const
bool res = addRequest(req);
if (!res)
{
- llerrs << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << llendl;
+ LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL;
req->deleteRequest();
handle = nullHandle();
}
@@ -113,7 +107,7 @@ S32 LLVFSThread::readImmediate(LLVFS* vfs, const LLUUID &file_id, const LLAssetT
S32 res = addRequest(req) ? 1 : 0;
if (res == 0)
{
- llerrs << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << llendl;
+ LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL;
req->deleteRequest();
}
else
@@ -136,7 +130,7 @@ LLVFSThread::handle_t LLVFSThread::write(LLVFS* vfs, const LLUUID &file_id, cons
bool res = addRequest(req);
if (!res)
{
- llerrs << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << llendl;
+ LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL;
req->deleteRequest();
handle = nullHandle();
}
@@ -155,7 +149,7 @@ S32 LLVFSThread::writeImmediate(LLVFS* vfs, const LLUUID &file_id, const LLAsset
S32 res = addRequest(req) ? 1 : 0;
if (res == 0)
{
- llerrs << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << llendl;
+ LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL;
req->deleteRequest();
}
else
@@ -181,7 +175,7 @@ S32 LLVFSThread::writeImmediate(LLVFS* vfs, const LLUUID &file_id, const LLAsset
// bool res = addRequest(req);
// if (!res)
// {
-// llerrs << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << llendl;
+// LL_ERRS() << "LLVFSThread::read called after LLVFSThread::cleanupClass()" << LL_ENDL;
// req->deleteRequest();
// handle = nullHandle();
// }
@@ -209,17 +203,17 @@ LLVFSThread::Request::Request(handle_t handle, U32 priority, U32 flags,
if (numbytes <= 0 && mOperation != FILE_RENAME)
{
- llwarns << "LLVFSThread: Request with numbytes = " << numbytes
+ LL_WARNS() << "LLVFSThread: Request with numbytes = " << numbytes
<< " operation = " << op
<< " offset " << offset
- << " file_type " << file_type << llendl;
+ << " file_type " << file_type << LL_ENDL;
}
if (mOperation == FILE_WRITE)
{
S32 blocksize = mVFS->getMaxSize(mFileID, mFileType);
if (blocksize < 0)
{
- llwarns << "VFS write to temporary block (shouldn't happen)" << llendl;
+ LL_WARNS() << "VFS write to temporary block (shouldn't happen)" << LL_ENDL;
}
mVFS->incLock(mFileID, mFileType, VFSLOCK_APPEND);
}
@@ -254,7 +248,7 @@ void LLVFSThread::Request::deleteRequest()
{
if (getStatus() == STATUS_QUEUED)
{
- llerrs << "Attempt to delete a queued LLVFSThread::Request!" << llendl;
+ LL_ERRS() << "Attempt to delete a queued LLVFSThread::Request!" << LL_ENDL;
}
if (mOperation == FILE_WRITE)
{
@@ -279,13 +273,13 @@ bool LLVFSThread::Request::processRequest()
llassert(mOffset >= 0);
mBytesRead = mVFS->getData(mFileID, mFileType, mBuffer, mOffset, mBytes);
complete = true;
- //llinfos << llformat("LLVFSThread::READ '%s': %d bytes arg:%d",getFilename(),mBytesRead) << llendl;
+ //LL_INFOS() << llformat("LLVFSThread::READ '%s': %d bytes arg:%d",getFilename(),mBytesRead) << LL_ENDL;
}
else if (mOperation == FILE_WRITE)
{
mBytesRead = mVFS->storeData(mFileID, mFileType, mBuffer, mOffset, mBytes);
complete = true;
- //llinfos << llformat("LLVFSThread::WRITE '%s': %d bytes arg:%d",getFilename(),mBytesRead) << llendl;
+ //LL_INFOS() << llformat("LLVFSThread::WRITE '%s': %d bytes arg:%d",getFilename(),mBytesRead) << LL_ENDL;
}
else if (mOperation == FILE_RENAME)
{
@@ -294,11 +288,11 @@ bool LLVFSThread::Request::processRequest()
mVFS->renameFile(mFileID, mFileType, *new_idp, new_type);
mFileID = *new_idp;
complete = true;
- //llinfos << llformat("LLVFSThread::RENAME '%s': %d bytes arg:%d",getFilename(),mBytesRead) << llendl;
+ //LL_INFOS() << llformat("LLVFSThread::RENAME '%s': %d bytes arg:%d",getFilename(),mBytesRead) << LL_ENDL;
}
else
{
- llerrs << llformat("LLVFSThread::unknown operation: %d", mOperation) << llendl;
+ LL_ERRS() << llformat("LLVFSThread::unknown operation: %d", mOperation) << LL_ENDL;
}
return complete;
}
diff --git a/indra/llvfs/llvfsthread.h b/indra/llvfs/llvfsthread.h
index 0a9786e9e1..95f3c857c6 100644..100755
--- a/indra/llvfs/llvfsthread.h
+++ b/indra/llvfs/llvfsthread.h
@@ -2,31 +2,25 @@
* @file llvfsthread.h
* @brief LLVFSThread definition
*
- * $LicenseInfo:firstyear=2001&license=viewergpl$
- *
- * Copyright (c) 2001-2009, 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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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$
*/
diff --git a/indra/llvfs/tests/lldir_test.cpp b/indra/llvfs/tests/lldir_test.cpp
index 9befa59477..3cff622a4b 100644..100755
--- a/indra/llvfs/tests/lldir_test.cpp
+++ b/indra/llvfs/tests/lldir_test.cpp
@@ -3,40 +3,191 @@
* @date 2008-05
* @brief LLDir test cases.
*
- * $LicenseInfo:firstyear=2008&license=viewergpl$
- *
- * Copyright (c) 2008-2009, Linden Research, Inc.
- *
+ * $LicenseInfo:firstyear=2008&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://secondlifegrid.net/programs/open_source/licensing/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://secondlifegrid.net/programs/open_source/licensing/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 "llstring.h"
+#include "tests/StringVec.h"
#include "../lldir.h"
+#include "../lldiriterator.h"
#include "../test/lltut.h"
+#include "stringize.h"
+#include <boost/foreach.hpp>
+#include <boost/assign/list_of.hpp>
+
+using boost::assign::list_of;
+
+// We use ensure_equals(..., vec(list_of(...))) not because it's functionally
+// required, but because ensure_equals() knows how to format a StringVec.
+// Turns out that when ensure_equals() displays a test failure with just
+// list_of("string")("another"), you see 'stringanother' vs. '("string",
+// "another")'.
+StringVec vec(const StringVec& v)
+{
+ return v;
+}
+// For some tests, use a dummy LLDir that uses memory data instead of touching
+// the filesystem
+struct LLDir_Dummy: public LLDir
+{
+ /*----------------------------- LLDir API ------------------------------*/
+ LLDir_Dummy()
+ {
+ // Initialize important LLDir data members based on the filesystem
+ // data below.
+ mDirDelimiter = "/";
+ mExecutableDir = "install";
+ mExecutableFilename = "test";
+ mExecutablePathAndName = add(mExecutableDir, mExecutableFilename);
+ mWorkingDir = mExecutableDir;
+ mAppRODataDir = "install";
+ mSkinBaseDir = add(mAppRODataDir, "skins");
+ mOSUserDir = "user";
+ mOSUserAppDir = mOSUserDir;
+ mLindenUserDir = "";
+
+ // Make the dummy filesystem look more or less like what we expect in
+ // the real one.
+ static const char* preload[] =
+ {
+ // We group these fixture-data pathnames by basename, rather than
+ // sorting by full path as you might expect, because the outcome
+ // of each test strongly depends on which skins/languages provide
+ // a given basename.
+ "install/skins/default/colors.xml",
+ "install/skins/steam/colors.xml",
+ "user/skins/default/colors.xml",
+ "user/skins/steam/colors.xml",
+
+ "install/skins/default/xui/en/strings.xml",
+ "install/skins/default/xui/fr/strings.xml",
+ "install/skins/steam/xui/en/strings.xml",
+ "install/skins/steam/xui/fr/strings.xml",
+ "user/skins/default/xui/en/strings.xml",
+ "user/skins/default/xui/fr/strings.xml",
+ "user/skins/steam/xui/en/strings.xml",
+ "user/skins/steam/xui/fr/strings.xml",
+
+ "install/skins/default/xui/en/floater.xml",
+ "install/skins/default/xui/fr/floater.xml",
+ "user/skins/default/xui/fr/floater.xml",
+
+ "install/skins/default/xui/en/newfile.xml",
+ "install/skins/default/xui/fr/newfile.xml",
+ "user/skins/default/xui/en/newfile.xml",
+
+ "install/skins/default/html/en-us/welcome.html",
+ "install/skins/default/html/fr/welcome.html",
+
+ "install/skins/default/textures/only_default.jpeg",
+ "install/skins/steam/textures/only_steam.jpeg",
+ "user/skins/default/textures/only_user_default.jpeg",
+ "user/skins/steam/textures/only_user_steam.jpeg",
+
+ "install/skins/default/future/somefile.txt"
+ };
+ BOOST_FOREACH(const char* path, preload)
+ {
+ buildFilesystem(path);
+ }
+ }
+
+ virtual ~LLDir_Dummy() {}
+
+ virtual void initAppDirs(const std::string& app_name, const std::string& app_read_only_data_dir)
+ {
+ // Implement this when we write a test that needs it
+ }
+
+ virtual std::string getCurPath()
+ {
+ // Implement this when we write a test that needs it
+ return "";
+ }
+
+ virtual U32 countFilesInDir(const std::string& dirname, const std::string& mask)
+ {
+ // Implement this when we write a test that needs it
+ return 0;
+ }
+
+ virtual bool fileExists(const std::string& pathname) const
+ {
+ // Record fileExists() calls so we can check whether caching is
+ // working right. Certain LLDir calls should be able to make decisions
+ // without calling fileExists() again, having already checked existence.
+ mChecked.insert(pathname);
+ // For our simple flat set of strings, see whether the identical
+ // pathname exists in our set.
+ return (mFilesystem.find(pathname) != mFilesystem.end());
+ }
+
+ virtual std::string getLLPluginLauncher()
+ {
+ // Implement this when we write a test that needs it
+ return "";
+ }
+
+ virtual std::string getLLPluginFilename(std::string base_name)
+ {
+ // Implement this when we write a test that needs it
+ return "";
+ }
+
+ /*----------------------------- Dummy data -----------------------------*/
+ void clearFilesystem() { mFilesystem.clear(); }
+ void buildFilesystem(const std::string& path)
+ {
+ // Split the pathname on slashes, ignoring leading, trailing, doubles
+ StringVec components;
+ LLStringUtil::getTokens(path, components, "/");
+ // Ensure we have an entry representing every level of this path
+ std::string partial;
+ BOOST_FOREACH(std::string component, components)
+ {
+ append(partial, component);
+ mFilesystem.insert(partial);
+ }
+ }
+
+ void clear_checked() { mChecked.clear(); }
+ void ensure_checked(const std::string& pathname) const
+ {
+ tut::ensure(STRINGIZE(pathname << " was not checked but should have been"),
+ mChecked.find(pathname) != mChecked.end());
+ }
+ void ensure_not_checked(const std::string& pathname) const
+ {
+ tut::ensure(STRINGIZE(pathname << " was checked but should not have been"),
+ mChecked.find(pathname) == mChecked.end());
+ }
+
+ std::set<std::string> mFilesystem;
+ mutable std::set<std::string> mChecked;
+};
namespace tut
{
@@ -262,5 +413,355 @@ namespace tut
gDirUtilp->getExtension(dottedPathExt),
"ext");
}
-}
+ std::string makeTestFile( const std::string& dir, const std::string& file )
+ {
+ std::string path = dir + file;
+ LLFILE* handle = LLFile::fopen( path, "w" );
+ ensure("failed to open test file '"+path+"'", handle != NULL );
+ // Harbison & Steele, 4th ed., p. 366: "If an error occurs, fputs
+ // returns EOF; otherwise, it returns some other, nonnegative value."
+ ensure("failed to write to test file '"+path+"'", EOF != fputs("test file", handle) );
+ fclose(handle);
+ return path;
+ }
+
+ std::string makeTestDir( const std::string& dirbase )
+ {
+ int counter;
+ std::string uniqueDir;
+ bool foundUnused;
+ std::string delim = gDirUtilp->getDirDelimiter();
+
+ for (counter=0, foundUnused=false; !foundUnused; counter++ )
+ {
+ char counterStr[3];
+ sprintf(counterStr, "%02d", counter);
+ uniqueDir = dirbase + counterStr;
+ foundUnused = ! ( LLFile::isdir(uniqueDir) || LLFile::isfile(uniqueDir) );
+ }
+ ensure("test directory '" + uniqueDir + "' creation failed", !LLFile::mkdir(uniqueDir));
+
+ return uniqueDir + delim; // HACK - apparently, the trailing delimiter is needed...
+ }
+
+ static const char* DirScanFilename[5] = { "file1.abc", "file2.abc", "file1.xyz", "file2.xyz", "file1.mno" };
+
+ void scanTest(const std::string& directory, const std::string& pattern, bool correctResult[5])
+ {
+
+ // Scan directory and see if any file1.* files are found
+ std::string scanResult;
+ int found = 0;
+ bool filesFound[5] = { false, false, false, false, false };
+ //std::cerr << "searching '"+directory+"' for '"+pattern+"'\n";
+
+ LLDirIterator iter(directory, pattern);
+ while ( found <= 5 && iter.next(scanResult) )
+ {
+ found++;
+ //std::cerr << " found '"+scanResult+"'\n";
+ int check;
+ for (check=0; check < 5 && ! ( scanResult == DirScanFilename[check] ); check++)
+ {
+ }
+ // check is now either 5 (not found) or the index of the matching name
+ if (check < 5)
+ {
+ ensure( "found file '"+(std::string)DirScanFilename[check]+"' twice", ! filesFound[check] );
+ filesFound[check] = true;
+ }
+ else // check is 5 - should not happen
+ {
+ fail( "found unknown file '"+scanResult+"'");
+ }
+ }
+ for (int i=0; i<5; i++)
+ {
+ if (correctResult[i])
+ {
+ ensure("scan of '"+directory+"' using '"+pattern+"' did not return '"+DirScanFilename[i]+"'", filesFound[i]);
+ }
+ else
+ {
+ ensure("scan of '"+directory+"' using '"+pattern+"' incorrectly returned '"+DirScanFilename[i]+"'", !filesFound[i]);
+ }
+ }
+ }
+
+ template<> template<>
+ void LLDirTest_object_t::test<5>()
+ // LLDirIterator::next
+ {
+ std::string delim = gDirUtilp->getDirDelimiter();
+ std::string dirTemp = LLFile::tmpdir();
+
+ // Create the same 5 file names of the two directories
+
+ std::string dir1 = makeTestDir(dirTemp + "LLDirIterator");
+ std::string dir2 = makeTestDir(dirTemp + "LLDirIterator");
+ std::string dir1files[5];
+ std::string dir2files[5];
+ for (int i=0; i<5; i++)
+ {
+ dir1files[i] = makeTestFile(dir1, DirScanFilename[i]);
+ dir2files[i] = makeTestFile(dir2, DirScanFilename[i]);
+ }
+
+ // Scan dir1 and see if each of the 5 files is found exactly once
+ bool expected1[5] = { true, true, true, true, true };
+ scanTest(dir1, "*", expected1);
+
+ // Scan dir2 and see if only the 2 *.xyz files are found
+ bool expected2[5] = { false, false, true, true, false };
+ scanTest(dir1, "*.xyz", expected2);
+
+ // Scan dir2 and see if only the 1 *.mno file is found
+ bool expected3[5] = { false, false, false, false, true };
+ scanTest(dir2, "*.mno", expected3);
+
+ // Scan dir1 and see if any *.foo files are found
+ bool expected4[5] = { false, false, false, false, false };
+ scanTest(dir1, "*.foo", expected4);
+
+ // Scan dir1 and see if any file1.* files are found
+ bool expected5[5] = { true, false, true, false, true };
+ scanTest(dir1, "file1.*", expected5);
+
+ // Scan dir1 and see if any file1.* files are found
+ bool expected6[5] = { true, true, false, false, false };
+ scanTest(dir1, "file?.abc", expected6);
+
+ // Scan dir2 and see if any file?.x?z files are found
+ bool expected7[5] = { false, false, true, true, false };
+ scanTest(dir2, "file?.x?z", expected7);
+
+ // Scan dir2 and see if any file?.??c files are found
+ bool expected8[5] = { true, true, false, false, false };
+ scanTest(dir2, "file?.??c", expected8);
+ scanTest(dir2, "*.??c", expected8);
+
+ // Scan dir1 and see if any *.?n? files are found
+ bool expected9[5] = { false, false, false, false, true };
+ scanTest(dir1, "*.?n?", expected9);
+
+ // Scan dir1 and see if any *.???? files are found
+ bool expected10[5] = { false, false, false, false, false };
+ scanTest(dir1, "*.????", expected10);
+
+ // Scan dir1 and see if any ?????.* files are found
+ bool expected11[5] = { true, true, true, true, true };
+ scanTest(dir1, "?????.*", expected11);
+
+ // Scan dir1 and see if any ??l??.xyz files are found
+ bool expected12[5] = { false, false, true, true, false };
+ scanTest(dir1, "??l??.xyz", expected12);
+
+ bool expected13[5] = { true, false, true, false, false };
+ scanTest(dir1, "file1.{abc,xyz}", expected13);
+
+ bool expected14[5] = { true, true, false, false, false };
+ scanTest(dir1, "file[0-9].abc", expected14);
+
+ bool expected15[5] = { true, true, false, false, false };
+ scanTest(dir1, "file[!a-z].abc", expected15);
+
+ // clean up all test files and directories
+ for (int i=0; i<5; i++)
+ {
+ LLFile::remove(dir1files[i]);
+ LLFile::remove(dir2files[i]);
+ }
+ LLFile::rmdir(dir1);
+ LLFile::rmdir(dir2);
+ }
+
+ template<> template<>
+ void LLDirTest_object_t::test<6>()
+ {
+ set_test_name("findSkinnedFilenames()");
+ LLDir_Dummy lldir;
+ /*------------------------ "default", "en" -------------------------*/
+ // Setting "default" means we shouldn't consider any "*/skins/steam"
+ // directories; setting "en" means we shouldn't consider any "xui/fr"
+ // directories.
+ lldir.setSkinFolder("default", "en");
+ ensure_equals(lldir.getSkinFolder(), "default");
+ ensure_equals(lldir.getLanguage(), "en");
+
+ // top-level directory of a skin isn't localized
+ ensure_equals(lldir.findSkinnedFilenames(LLDir::SKINBASE, "colors.xml", LLDir::ALL_SKINS),
+ vec(list_of("install/skins/default/colors.xml")
+ ("user/skins/default/colors.xml")));
+ // We should not have needed to check for skins/default/en. We should
+ // just "know" that SKINBASE is not localized.
+ lldir.ensure_not_checked("install/skins/default/en");
+
+ ensure_equals(lldir.findSkinnedFilenames(LLDir::TEXTURES, "only_default.jpeg"),
+ vec(list_of("install/skins/default/textures/only_default.jpeg")));
+ // Nor should we have needed to check skins/default/textures/en
+ // because textures is known not to be localized.
+ lldir.ensure_not_checked("install/skins/default/textures/en");
+
+ StringVec expected(vec(list_of("install/skins/default/xui/en/strings.xml")
+ ("user/skins/default/xui/en/strings.xml")));
+ ensure_equals(lldir.findSkinnedFilenames(LLDir::XUI, "strings.xml", LLDir::ALL_SKINS),
+ expected);
+ // The first time, we had to probe to find out whether xui was localized.
+ lldir.ensure_checked("install/skins/default/xui/en");
+ lldir.clear_checked();
+ // Now make the same call again -- should return same result --
+ ensure_equals(lldir.findSkinnedFilenames(LLDir::XUI, "strings.xml", LLDir::ALL_SKINS),
+ expected);
+ // but this time it should remember that xui is localized.
+ lldir.ensure_not_checked("install/skins/default/xui/en");
+
+ // localized subdir with "en-us" instead of "en"
+ ensure_equals(lldir.findSkinnedFilenames("html", "welcome.html"),
+ vec(list_of("install/skins/default/html/en-us/welcome.html")));
+ lldir.ensure_checked("install/skins/default/html/en");
+ lldir.ensure_checked("install/skins/default/html/en-us");
+ lldir.clear_checked();
+ ensure_equals(lldir.findSkinnedFilenames("html", "welcome.html"),
+ vec(list_of("install/skins/default/html/en-us/welcome.html")));
+ lldir.ensure_not_checked("install/skins/default/html/en");
+ lldir.ensure_not_checked("install/skins/default/html/en-us");
+
+ ensure_equals(lldir.findSkinnedFilenames("future", "somefile.txt"),
+ vec(list_of("install/skins/default/future/somefile.txt")));
+ // Test probing for an unrecognized unlocalized future subdir.
+ lldir.ensure_checked("install/skins/default/future/en");
+ lldir.clear_checked();
+ ensure_equals(lldir.findSkinnedFilenames("future", "somefile.txt"),
+ vec(list_of("install/skins/default/future/somefile.txt")));
+ // Second time it should remember that future is unlocalized.
+ lldir.ensure_not_checked("install/skins/default/future/en");
+
+ // When language is set to "en", requesting an html file pulls up the
+ // "en-us" version -- not because it magically matches those strings,
+ // but because there's no "en" localization and it falls back on the
+ // default "en-us"! Note that it would probably still be better to
+ // make the default localization be "en" and allow "en-gb" (or
+ // whatever) localizations, which would work much more the way you'd
+ // expect.
+ ensure_equals(lldir.findSkinnedFilenames("html", "welcome.html"),
+ vec(list_of("install/skins/default/html/en-us/welcome.html")));
+
+ /*------------------------ "default", "fr" -------------------------*/
+ // We start being able to distinguish localized subdirs from
+ // unlocalized when we ask for a non-English language.
+ lldir.setSkinFolder("default", "fr");
+ ensure_equals(lldir.getLanguage(), "fr");
+
+ // pass merge=true to request this filename in all relevant skins
+ ensure_equals(lldir.findSkinnedFilenames(LLDir::XUI, "strings.xml", LLDir::ALL_SKINS),
+ vec(list_of
+ ("install/skins/default/xui/en/strings.xml")
+ ("install/skins/default/xui/fr/strings.xml")
+ ("user/skins/default/xui/en/strings.xml")
+ ("user/skins/default/xui/fr/strings.xml")));
+
+ // pass (or default) merge=false to request only most specific skin
+ ensure_equals(lldir.findSkinnedFilenames(LLDir::XUI, "strings.xml"),
+ vec(list_of
+ ("user/skins/default/xui/en/strings.xml")
+ ("user/skins/default/xui/fr/strings.xml")));
+
+ // Our dummy floater.xml has a user localization (for "fr") but no
+ // English override. This is a case in which CURRENT_SKIN nonetheless
+ // returns paths from two different skins.
+ ensure_equals(lldir.findSkinnedFilenames(LLDir::XUI, "floater.xml"),
+ vec(list_of
+ ("install/skins/default/xui/en/floater.xml")
+ ("user/skins/default/xui/fr/floater.xml")));
+
+ // Our dummy newfile.xml has an English override but no user
+ // localization. This is another case in which CURRENT_SKIN
+ // nonetheless returns paths from two different skins.
+ ensure_equals(lldir.findSkinnedFilenames(LLDir::XUI, "newfile.xml"),
+ vec(list_of
+ ("user/skins/default/xui/en/newfile.xml")
+ ("install/skins/default/xui/fr/newfile.xml")));
+
+ ensure_equals(lldir.findSkinnedFilenames("html", "welcome.html"),
+ vec(list_of
+ ("install/skins/default/html/en-us/welcome.html")
+ ("install/skins/default/html/fr/welcome.html")));
+
+ /*------------------------ "default", "zh" -------------------------*/
+ lldir.setSkinFolder("default", "zh");
+ // Because strings.xml has only a "fr" override but no "zh" override
+ // in any skin, the most localized version we can find is "en".
+ ensure_equals(lldir.findSkinnedFilenames(LLDir::XUI, "strings.xml"),
+ vec(list_of("user/skins/default/xui/en/strings.xml")));
+
+ /*------------------------- "steam", "en" --------------------------*/
+ lldir.setSkinFolder("steam", "en");
+
+ ensure_equals(lldir.findSkinnedFilenames(LLDir::SKINBASE, "colors.xml", LLDir::ALL_SKINS),
+ vec(list_of
+ ("install/skins/default/colors.xml")
+ ("install/skins/steam/colors.xml")
+ ("user/skins/default/colors.xml")
+ ("user/skins/steam/colors.xml")));
+
+ ensure_equals(lldir.findSkinnedFilenames(LLDir::TEXTURES, "only_default.jpeg"),
+ vec(list_of("install/skins/default/textures/only_default.jpeg")));
+
+ ensure_equals(lldir.findSkinnedFilenames(LLDir::TEXTURES, "only_steam.jpeg"),
+ vec(list_of("install/skins/steam/textures/only_steam.jpeg")));
+
+ ensure_equals(lldir.findSkinnedFilenames(LLDir::TEXTURES, "only_user_default.jpeg"),
+ vec(list_of("user/skins/default/textures/only_user_default.jpeg")));
+
+ ensure_equals(lldir.findSkinnedFilenames(LLDir::TEXTURES, "only_user_steam.jpeg"),
+ vec(list_of("user/skins/steam/textures/only_user_steam.jpeg")));
+
+ // CURRENT_SKIN
+ ensure_equals(lldir.findSkinnedFilenames(LLDir::XUI, "strings.xml"),
+ vec(list_of("user/skins/steam/xui/en/strings.xml")));
+
+ // pass constraint=ALL_SKINS to request this filename in all relevant skins
+ ensure_equals(lldir.findSkinnedFilenames(LLDir::XUI, "strings.xml", LLDir::ALL_SKINS),
+ vec(list_of
+ ("install/skins/default/xui/en/strings.xml")
+ ("install/skins/steam/xui/en/strings.xml")
+ ("user/skins/default/xui/en/strings.xml")
+ ("user/skins/steam/xui/en/strings.xml")));
+
+ /*------------------------- "steam", "fr" --------------------------*/
+ lldir.setSkinFolder("steam", "fr");
+
+ // pass CURRENT_SKIN to request only the most specialized files
+ ensure_equals(lldir.findSkinnedFilenames(LLDir::XUI, "strings.xml"),
+ vec(list_of
+ ("user/skins/steam/xui/en/strings.xml")
+ ("user/skins/steam/xui/fr/strings.xml")));
+
+ // pass ALL_SKINS to request this filename in all relevant skins
+ ensure_equals(lldir.findSkinnedFilenames(LLDir::XUI, "strings.xml", LLDir::ALL_SKINS),
+ vec(list_of
+ ("install/skins/default/xui/en/strings.xml")
+ ("install/skins/default/xui/fr/strings.xml")
+ ("install/skins/steam/xui/en/strings.xml")
+ ("install/skins/steam/xui/fr/strings.xml")
+ ("user/skins/default/xui/en/strings.xml")
+ ("user/skins/default/xui/fr/strings.xml")
+ ("user/skins/steam/xui/en/strings.xml")
+ ("user/skins/steam/xui/fr/strings.xml")));
+ }
+
+ template<> template<>
+ void LLDirTest_object_t::test<7>()
+ {
+ set_test_name("add()");
+ LLDir_Dummy lldir;
+ ensure_equals("both empty", lldir.add("", ""), "");
+ ensure_equals("path empty", lldir.add("", "b"), "b");
+ ensure_equals("name empty", lldir.add("a", ""), "a");
+ ensure_equals("both simple", lldir.add("a", "b"), "a/b");
+ ensure_equals("name leading slash", lldir.add("a", "/b"), "a/b");
+ ensure_equals("path trailing slash", lldir.add("a/", "b"), "a/b");
+ ensure_equals("both bring slashes", lldir.add("a/", "/b"), "a/b");
+ }
+}
diff --git a/indra/llvfs/tests/lldiriterator_test.cpp b/indra/llvfs/tests/lldiriterator_test.cpp
new file mode 100755
index 0000000000..a65e3dada5
--- /dev/null
+++ b/indra/llvfs/tests/lldiriterator_test.cpp
@@ -0,0 +1,65 @@
+/**
+ * @file lldiriterator_test.cpp
+ * @date 2011-06
+ * @brief LLDirIterator test cases.
+ *
+ * $LicenseInfo:firstyear=2011&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2011, 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 "lltut.h"
+#include "../lldiriterator.h"
+
+
+namespace tut
+{
+
+ struct LLDirIteratorFixture
+ {
+ LLDirIteratorFixture()
+ {
+ }
+ };
+ typedef test_group<LLDirIteratorFixture> LLDirIteratorTest_factory;
+ typedef LLDirIteratorTest_factory::object LLDirIteratorTest_t;
+ LLDirIteratorTest_factory tf("LLDirIterator");
+
+ /*
+ CHOP-662 was originally introduced to deal with crashes deleting files from
+ a directory (VWR-25500). However, this introduced a crash looking for
+ old chat logs as the glob_to_regex function in lldiriterator wasn't escaping lots of regexp characters
+ */
+ void test_chop_662(void)
+ {
+ // Check a selection of bad group names from the crash reports
+ LLDirIterator iter(".","+bad-group-name]+?\?-??.*");
+ LLDirIterator iter1(".","))--@---bad-group-name2((?\?-??.*\\.txt");
+ LLDirIterator iter2(".","__^v--x)Cuide d sua vida(x--v^__?\?-??.*");
+ }
+
+ template<> template<>
+ void LLDirIteratorTest_t::test<1>()
+ {
+ test_chop_662();
+ }
+
+}