From 5d87098bd037cd42913d6cc3d940bb9f7d16a643 Mon Sep 17 00:00:00 2001 From: Aleric Inglewood Date: Mon, 6 Jun 2011 21:38:58 +0200 Subject: [PATCH] Port Viewer 2 indra/llvfs This introduces some API changes, like the new LLDirIterator, that causes changes elsewhere. It also include Log Linden's cache changes that aren't in viewer-development yet that increase the maximum cache size to ~10 GB. --- indra/cmake/LLVFS.cmake | 7 +- indra/llvfs/CMakeLists.txt | 8 + indra/llvfs/lldir.cpp | 126 ++++++----- indra/llvfs/lldir.h | 41 ++-- indra/llvfs/lldir_linux.cpp | 178 +++------------ indra/llvfs/lldir_linux.h | 13 +- indra/llvfs/lldir_mac.cpp | 172 +++----------- indra/llvfs/lldir_mac.h | 12 +- indra/llvfs/lldir_solaris.cpp | 134 +---------- indra/llvfs/lldir_solaris.h | 13 +- indra/llvfs/lldir_win32.cpp | 193 ++++------------ indra/llvfs/lldir_win32.h | 11 +- indra/llvfs/lldiriterator.cpp | 210 ++++++++++++++++++ indra/llvfs/lldiriterator.h | 87 ++++++++ indra/llvfs/lllfsthread.cpp | 1 - indra/llvfs/lllfsthread.h | 2 +- indra/llvfs/llpidlock.cpp | 14 +- indra/llvfs/llpidlock.h | 10 +- indra/llvfs/llvfile.cpp | 5 +- indra/llvfs/llvfs.cpp | 170 +++++++------- indra/llvfs/llvfs.h | 19 +- indra/newview/app_settings/settings.xml | 11 + indra/newview/ascentdaycyclemanager.cpp | 7 +- indra/newview/lgghunspell_wrapper.cpp | 48 ++-- indra/newview/llappviewer.cpp | 151 +++++++++---- indra/newview/llappviewerlinux.cpp | 5 +- indra/newview/llappviewermacosx.cpp | 4 +- indra/newview/llpanelnetwork.cpp | 10 +- indra/newview/llpanelskins.cpp | 7 +- indra/newview/lltexturecache.cpp | 6 +- indra/newview/llwaterparammanager.cpp | 7 +- indra/newview/llwlparammanager.cpp | 7 +- .../xui/en-us/panel_preferences_network.xml | 4 +- 33 files changed, 837 insertions(+), 856 deletions(-) create mode 100644 indra/llvfs/lldiriterator.cpp create mode 100644 indra/llvfs/lldiriterator.h diff --git a/indra/cmake/LLVFS.cmake b/indra/cmake/LLVFS.cmake index 0fe87cdea..0ff227c12 100644 --- a/indra/cmake/LLVFS.cmake +++ b/indra/cmake/LLVFS.cmake @@ -1,7 +1,12 @@ # -*- cmake -*- +include(Boost) + set(LLVFS_INCLUDE_DIRS ${LIBS_OPEN_DIR}/llvfs ) -set(LLVFS_LIBRARIES llvfs) +set(LLVFS_LIBRARIES + llvfs + ${BOOST_REGEX_LIBRARY} + ) diff --git a/indra/llvfs/CMakeLists.txt b/indra/llvfs/CMakeLists.txt index d6a0bbc08..e5889805b 100644 --- a/indra/llvfs/CMakeLists.txt +++ b/indra/llvfs/CMakeLists.txt @@ -4,6 +4,7 @@ project(llvfs) include(00-Common) include(LLCommon) +include(UnixInstall) include_directories( ${LLCOMMON_INCLUDE_DIRS} @@ -11,6 +12,7 @@ include_directories( set(llvfs_SOURCE_FILES lldir.cpp + lldiriterator.cpp lllfsthread.cpp llpidlock.cpp llvfile.cpp @@ -22,6 +24,7 @@ set(llvfs_HEADER_FILES CMakeLists.txt lldir.h + lldiriterator.h lllfsthread.h llpidlock.h llvfile.h @@ -59,6 +62,11 @@ list(APPEND llvfs_SOURCE_FILES ${llvfs_HEADER_FILES}) add_library (llvfs ${llvfs_SOURCE_FILES}) add_dependencies(llvfs prepare) +target_link_libraries(llvfs + ${BOOST_FILESYSTEM_LIBRARY} + ${BOOST_SYSTEM_LIBRARY} + ) + if (DARWIN) include(CMakeFindFrameworks) find_library(CARBON_LIBRARY Carbon) diff --git a/indra/llvfs/lldir.cpp b/indra/llvfs/lldir.cpp index 28fcd7751..63023a28e 100644 --- a/indra/llvfs/lldir.cpp +++ b/indra/llvfs/lldir.cpp @@ -41,9 +41,12 @@ #endif #include "lldir.h" + #include "llerror.h" +#include "lltimer.h" // ms_sleep() #include "lluuid.h" -#include "lltimer.h" + +#include "lldiriterator.h" #if LL_WINDOWS #include "lldir_win32.h" @@ -88,27 +91,38 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) std::string filename; std::string fullpath; S32 result; - while (getNextFileInDir(dirname, mask, filename, FALSE)) + + LLDirIterator iter(dirname, mask); + while (iter.next(filename)) { - if ((filename == ".") || (filename == "..")) + fullpath = dirname; + fullpath += getDirDelimiter(); + fullpath += filename; + + if(LLFile::isdir(fullpath)) { // skipping directory traversal filenames count++; continue; } - fullpath = dirname; - fullpath += getDirDelimiter(); - fullpath += filename; S32 retry_count = 0; while (retry_count < 5) { if (0 != LLFile::remove(fullpath)) { + retry_count++; result = errno; llwarns << "Problem removing " << fullpath << " - errorcode: " << result << " attempt " << retry_count << llendl; - ms_sleep(1000); + + if(retry_count >= 5) + { + llwarns << "Failed to remove " << fullpath << llendl ; + return count ; + } + + ms_sleep(100); } else { @@ -117,8 +131,7 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) llwarns << "Successfully removed " << fullpath << llendl; } break; - } - retry_count++; + } } count++; } @@ -126,23 +139,31 @@ S32 LLDir::deleteFilesInDir(const std::string &dirname, const std::string &mask) } const std::string LLDir::findFile(const std::string &filename, - const std::string searchPath1, - const std::string searchPath2, - const std::string searchPath3) const + const std::string& searchPath1, + const std::string& searchPath2, + const std::string& searchPath3) const { std::vector search_paths; search_paths.push_back(searchPath1); search_paths.push_back(searchPath2); search_paths.push_back(searchPath3); + return findFile(filename, search_paths); +} - std::vector::iterator search_path_iter; +const std::string LLDir::findFile(const std::string& filename, const std::vector search_paths) const +{ + std::vector::const_iterator search_path_iter; for (search_path_iter = search_paths.begin(); search_path_iter != search_paths.end(); ++search_path_iter) { if (!search_path_iter->empty()) { - std::string filename_and_path = (*search_path_iter) + 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; @@ -289,11 +310,7 @@ const std::string& LLDir::getDefaultSkinDir() const const std::string LLDir::getSkinBaseDir() const { - std::string dir = getAppRODataDir(); - dir += mDirDelimiter; - dir += "skins"; - - return dir; + return mSkinBaseDir; } const std::string &LLDir::getLLPluginDir() const @@ -325,25 +342,19 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd prefix += mDirDelimiter; prefix += "app_settings"; break; - + case LL_PATH_CHARACTER: prefix = getAppRODataDir(); prefix += mDirDelimiter; prefix += "character"; break; - case LL_PATH_MOTIONS: - prefix = getAppRODataDir(); - prefix += mDirDelimiter; - prefix += "motions"; - break; - case LL_PATH_HELP: prefix = "help"; break; case LL_PATH_CACHE: - prefix = getCacheDir(); + prefix = getCacheDir(); break; case LL_PATH_USER_SETTINGS: @@ -378,28 +389,34 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd prefix = getSkinDir(); break; - case LL_PATH_SKINS: - prefix = getAppRODataDir(); - prefix += mDirDelimiter; - prefix += "skins"; + case LL_PATH_DEFAULT_SKIN: + prefix = getDefaultSkinDir(); break; - //case LL_PATH_HTML: - // prefix = getSkinDir(); - // prefix += mDirDelimiter; - // prefix += "html"; - // break; + case LL_PATH_USER_SKIN: + prefix = getUserSkinDir(); + break; - case LL_PATH_MOZILLA_PROFILE: - prefix = getOSUserAppDir(); + case LL_PATH_SKINS: + prefix = getSkinBaseDir(); + break; + + case LL_PATH_LOCAL_ASSETS: + prefix = getAppRODataDir(); prefix += mDirDelimiter; - prefix += "browser_profile"; + prefix += "local_assets"; break; case LL_PATH_EXECUTABLE: prefix = getExecutableDir(); break; + case LL_PATH_FONTS: + prefix = getAppRODataDir(); + prefix += mDirDelimiter; + prefix += "fonts"; + break; + default: llassert(0); } @@ -415,6 +432,11 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd filename = subdir1 + mDirDelimiter + filename; } + if (prefix.empty()) + { + llwarns << "prefix is empty, possible bad filename" << llendl; + } + std::string expanded_filename; if (!filename.empty()) { @@ -440,7 +462,6 @@ std::string LLDir::getExpandedFilename(ELLPath location, const std::string& subd } //llinfos << "*** EXPANDED FILENAME: <" << expanded_filename << ">" << llendl; - return expanded_filename; } @@ -496,11 +517,14 @@ std::string LLDir::findSkinnedFilename(const std::string &subdir1, const std::st std::string subdirs = ((subdir1.empty() ? "" : mDirDelimiter) + subdir1) + ((subdir2.empty() ? "" : mDirDelimiter) + subdir2); - std::string found_file = findFile(filename, - getUserSkinDir() + subdirs, // first look in user skin override - getSkinDir() + subdirs, // then in current skin - getDefaultSkinDir() + subdirs); // and last in default skin + std::vector search_paths; + + search_paths.push_back(getUserSkinDir() + subdirs); // first look in user skin override + search_paths.push_back(getSkinDir() + subdirs); // then in current skin + search_paths.push_back(getDefaultSkinDir() + subdirs); // then default skin + search_paths.push_back(getCacheDir() + subdirs); // and last in preload directory + std::string found_file = findFile(filename, search_paths); return found_file; } @@ -625,9 +649,7 @@ void LLDir::setPerAccountChatLogsDir(const std::string &grid, const std::string void LLDir::setSkinFolder(const std::string &skin_folder) { - mSkinDir = getAppRODataDir(); - mSkinDir += mDirDelimiter; - mSkinDir += "skins"; + mSkinDir = getSkinBaseDir(); mSkinDir += mDirDelimiter; mSkinDir += skin_folder; @@ -641,9 +663,7 @@ void LLDir::setSkinFolder(const std::string &skin_folder) // base skin which is used as fallback for all skinned files // e.g. c:\program files\secondlife\skins\default - mDefaultSkinDir = getAppRODataDir(); - mDefaultSkinDir += mDirDelimiter; - mDefaultSkinDir += "skins"; + mDefaultSkinDir = getSkinBaseDir(); mDefaultSkinDir += mDirDelimiter; mDefaultSkinDir += "default"; } @@ -688,12 +708,8 @@ void LLDir::dumpCurrentDirectories() 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; - -#if LL_LIBXUL_ENABLED - LL_DEBUGS2("AppInit","Directories") << " HTML Path: " << getExpandedFilename( LL_PATH_HTML, "" ) << llendl; - LL_DEBUGS2("AppInit","Directories") << " Mozilla Profile Path: " << getExpandedFilename( LL_PATH_MOZILLA_PROFILE, "" ) << llendl; -#endif } diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h index a90b8ab24..250369b78 100644 --- a/indra/llvfs/lldir.h +++ b/indra/llvfs/lldir.h @@ -38,26 +38,27 @@ #define MAX_PATH MAXPATHLEN #endif -// these numbers *may* get serialized, so we need to be explicit +// these numbers *may* get serialized (really??), so we need to be explicit typedef enum ELLPath { LL_PATH_NONE = 0, LL_PATH_USER_SETTINGS = 1, LL_PATH_APP_SETTINGS = 2, - LL_PATH_PER_SL_ACCOUNT = 3, + LL_PATH_PER_SL_ACCOUNT = 3, // returns/expands to blank string if we don't know the account name yet LL_PATH_CACHE = 4, LL_PATH_CHARACTER = 5, - LL_PATH_MOTIONS = 6, - LL_PATH_HELP = 7, - LL_PATH_LOGS = 8, - LL_PATH_TEMP = 9, - LL_PATH_SKINS = 10, - LL_PATH_TOP_SKIN = 11, - LL_PATH_CHAT_LOGS = 12, - LL_PATH_PER_ACCOUNT_CHAT_LOGS = 13, - LL_PATH_MOZILLA_PROFILE = 14, -// LL_PATH_HTML = 15, + LL_PATH_HELP = 6, + LL_PATH_LOGS = 7, + LL_PATH_TEMP = 8, + LL_PATH_SKINS = 9, + LL_PATH_TOP_SKIN = 10, + LL_PATH_CHAT_LOGS = 11, + LL_PATH_PER_ACCOUNT_CHAT_LOGS = 12, + LL_PATH_USER_SKIN = 14, + LL_PATH_LOCAL_ASSETS = 15, LL_PATH_EXECUTABLE = 16, + LL_PATH_DEFAULT_SKIN = 17, + LL_PATH_FONTS = 18, LL_PATH_LAST } ELLPath; @@ -68,18 +69,23 @@ class LLDir LLDir(); virtual ~LLDir(); - virtual void initAppDirs(const std::string &app_name) = 0; - public: + // app_name - Usually SecondLife, used for creating settings directories + // in OS-specific location, such as C:\Documents and Settings + // app_read_only_data_dir - Usually the source code directory, used + // for test applications to read newview data files. + virtual void initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir = "") = 0; + virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask); // pure virtual functions virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask) = 0; - virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap) = 0; - virtual void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname) = 0; + virtual std::string getCurPath() = 0; virtual BOOL fileExists(const std::string &filename) const = 0; - const std::string findFile(const std::string &filename, const std::string searchPath1 = "", const std::string searchPath2 = "", const std::string searchPath3 = "") const; + const std::string findFile(const std::string& filename, const std::vector filenames) const; + const std::string findFile(const std::string& filename, const std::string& searchPath1 = "", const std::string& searchPath2 = "", const std::string& searchPath3 = "") const; virtual std::string getLLPluginLauncher() = 0; // full path and name for the plugin shell virtual std::string getLLPluginFilename(std::string base_name) = 0; // full path and name to the plugin DSO for this base_name (i.e. 'FOO' -> '/bar/baz/libFOO.so') @@ -158,6 +164,7 @@ protected: std::string mDefaultCacheDir; // default cache diretory std::string mOSCacheDir; // operating system cache dir std::string mDirDelimiter; + std::string mSkinBaseDir; // Base for skins paths. std::string mSkinDir; // Location for current skin info. std::string mDefaultSkinDir; // Location for default skin info. std::string mUserSkinDir; // Location for user-modified skin info. diff --git a/indra/llvfs/lldir_linux.cpp b/indra/llvfs/lldir_linux.cpp index ce6b1885f..a4df354c5 100644 --- a/indra/llvfs/lldir_linux.cpp +++ b/indra/llvfs/lldir_linux.cpp @@ -94,7 +94,25 @@ LLDir_Linux::LLDir_Linux() mExecutablePathAndName = ""; mExecutableDir = tmp_str; mWorkingDir = tmp_str; +#ifdef APP_RO_DATA_DIR + mAppRODataDir = APP_RO_DATA_DIR; +#else mAppRODataDir = tmp_str; +#endif + std::string::size_type build_dir_pos = mExecutableDir.rfind("/indra/viewer-linux-"); + if (build_dir_pos != std::string::npos) + { + // ...we're in a dev checkout + mSkinBaseDir = mExecutableDir.substr(0, build_dir_pos) + "/indra/newview/skins"; + llinfos << "Running in dev checkout with mSkinBaseDir " + << mSkinBaseDir << llendl; + } + else + { + // ...normal installation running + mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; + } + mOSUserDir = getCurrentUserHome(tmp_str); mOSUserAppDir = ""; mLindenUserDir = ""; @@ -126,31 +144,6 @@ LLDir_Linux::LLDir_Linux() mLLPluginDir = mExecutableDir + mDirDelimiter + "llplugin"; -#ifdef APP_RO_DATA_DIR - const char* appRODataDir = APP_RO_DATA_DIR; - if(appRODataDir[0] == '/') - { - // We have a full path to the data directory. - mAppRODataDir = appRODataDir; - } - else if(appRODataDir[0] != '\0') - { - // We have a relative path to the data directory. Search - // for it in each potential install prefix containing the - // executable. - for(std::string prefix = getDirName(mExecutableDir); - !prefix.empty(); prefix = getDirName(prefix)) - { - std::string dir = prefix + "/" + appRODataDir; - if(fileExists(dir + "/app_settings")) - { - mAppRODataDir = dir; - break; - } - } - } -#endif - // *TODO: don't use /tmp, use $HOME/.secondlife/tmp or something. mTempDir = "/tmp"; } @@ -162,8 +155,15 @@ LLDir_Linux::~LLDir_Linux() // Implementation -void LLDir_Linux::initAppDirs(const std::string &app_name) +void LLDir_Linux::initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir) { + // Allow override so test apps can read newview directory + if (!app_read_only_data_dir.empty()) + { + mAppRODataDir = app_read_only_data_dir; + mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; + } mAppName = app_name; std::string upper_app_name(app_name); @@ -226,24 +226,6 @@ void LLDir_Linux::initAppDirs(const std::string &app_name) } } - res = LLFile::mkdir(getExpandedFilename(LL_PATH_MOZILLA_PROFILE,"")); - if (res == -1) - { - if (errno != EEXIST) - { - llwarns << "Couldn't create LL_PATH_MOZILLA_PROFILE dir " << getExpandedFilename(LL_PATH_MOZILLA_PROFILE,"") << llendl; - } - } - - res = LLFile::mkdir(getExpandedFilename(LL_PATH_USER_SETTINGS, "dictionaries")); - if (res == -1) - { - if (errno != EEXIST) - { - llwarns << "Couldn't create LL_PATH_USER_SETTINGS/dictionaries dir " << getExpandedFilename(LL_PATH_MOZILLA_PROFILE,"") << llendl; - } - } - mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem"); } @@ -266,114 +248,6 @@ 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 */ diff --git a/indra/llvfs/lldir_linux.h b/indra/llvfs/lldir_linux.h index 8e94fb1c9..46bf91c69 100644 --- a/indra/llvfs/lldir_linux.h +++ b/indra/llvfs/lldir_linux.h @@ -30,6 +30,10 @@ * $/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 @@ -44,12 +48,11 @@ public: LLDir_Linux(); virtual ~LLDir_Linux(); - virtual void initAppDirs(const std::string &app_name); -public: + /*virtual*/ void initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir); + virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); - virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap); - virtual void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); @@ -59,7 +62,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 98eb8fd5e..c15bc7ee0 100644 --- a/indra/llvfs/lldir_mac.cpp +++ b/indra/llvfs/lldir_mac.cpp @@ -68,7 +68,8 @@ static void CFStringRefToLLString(CFStringRef stringRef, std::string &llString, { if (stringRef) { - long bufferSize = CFStringGetLength(stringRef) + 1; + long stringSize = CFStringGetLength(stringRef) + 1; + long bufferSize = CFStringGetMaximumSizeForEncoding(stringSize,kCFStringEncodingUTF8); char* buffer = new char[bufferSize]; memset(buffer, 0, bufferSize); if (CFStringGetCString(stringRef, buffer, bufferSize, kCFStringEncodingUTF8)) @@ -142,9 +143,34 @@ LLDir_Mac::LLDir_Mac() CFURLRefToLLString(executableParentURLRef, mExecutableDir, true); // mAppRODataDir - CFURLRef resourcesURLRef = CFBundleCopyResourcesDirectoryURL(mainBundleRef); + + + // *NOTE: When running in a dev tree, use the copy of + // skins in indra/newview/ rather than in the application bundle. This + // mirrors Windows dev environment behavior and allows direct checkin + // of edited skins/xui files. JC + + // MBW -- This keeps the mac application from finding other things. + // If this is really for skins, it should JUST apply to skins. + + CFURLRef resourcesURLRef = CFBundleCopyResourcesDirectoryURL(mainBundleRef); CFURLRefToLLString(resourcesURLRef, mAppRODataDir, true); + U32 build_dir_pos = mExecutableDir.rfind("/indra/build-darwin-"); + if (build_dir_pos != std::string::npos) + { + // ...we're in a dev checkout + mSkinBaseDir = mExecutableDir.substr(0, build_dir_pos) + + "/indra/newview/skins"; + llinfos << "Running in dev checkout with mSkinBaseDir " + << mSkinBaseDir << llendl; + } + else + { + // ...normal installation running + mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; + } + // mOSUserDir error = FSFindFolder(kUserDomain, kApplicationSupportFolderType, true, &fileRef); if (error == noErr) @@ -205,8 +231,15 @@ LLDir_Mac::~LLDir_Mac() // Implementation -void LLDir_Mac::initAppDirs(const std::string &app_name) +void LLDir_Mac::initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir) { + // Allow override so test apps can read newview directory + if (!app_read_only_data_dir.empty()) + { + mAppRODataDir = app_read_only_data_dir; + mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; + } mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem"); //dumpCurrentDirectories(); @@ -231,139 +264,6 @@ U32 LLDir_Mac::countFilesInDir(const std::string &dirname, const std::string &ma 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 */ diff --git a/indra/llvfs/lldir_mac.h b/indra/llvfs/lldir_mac.h index 8be5d03b2..d99f9e39e 100644 --- a/indra/llvfs/lldir_mac.h +++ b/indra/llvfs/lldir_mac.h @@ -30,6 +30,10 @@ * $/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 @@ -43,13 +47,11 @@ public: LLDir_Mac(); virtual ~LLDir_Mac(); - virtual void initAppDirs(const std::string &app_name); -public: - virtual S32 deleteFilesInDir(const std::string &dirname, const std::string &mask); + /*virtual*/ void initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir); + virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); - virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap); - virtual void getRandomFileInDir(const std::string &dirname, const std::string &ask, std::string &fname); virtual BOOL fileExists(const std::string &filename) const; /*virtual*/ std::string getLLPluginLauncher(); diff --git a/indra/llvfs/lldir_solaris.cpp b/indra/llvfs/lldir_solaris.cpp index 2ebd6e471..22df6a9a3 100644 --- a/indra/llvfs/lldir_solaris.cpp +++ b/indra/llvfs/lldir_solaris.cpp @@ -174,8 +174,14 @@ LLDir_Solaris::~LLDir_Solaris() // Implementation -void LLDir_Solaris::initAppDirs(const std::string &app_name) +void LLDir_Solaris::initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir) { + // Allow override so test apps can read newview directory + if (!app_read_only_data_dir.empty()) + { + mAppRODataDir = app_read_only_data_dir; + } mAppName = app_name; std::string upper_app_name(app_name); @@ -238,24 +244,6 @@ void LLDir_Solaris::initAppDirs(const std::string &app_name) } } - res = LLFile::mkdir(getExpandedFilename(LL_PATH_MOZILLA_PROFILE,"")); - if (res == -1) - { - if (errno != EEXIST) - { - llwarns << "Couldn't create LL_PATH_MOZILLA_PROFILE dir " << getExpandedFilename(LL_PATH_MOZILLA_PROFILE,"") << llendl; - } - } - - res = LLFile::mkdir(getExpandedFilename(LL_PATH_USER_SETTINGS, "dictionaries")); - if (res == -1) - { - if (errno != EEXIST) - { - llwarns << "Couldn't create LL_PATH_USER_SETTINGS/dictionaries dir " << getExpandedFilename(LL_PATH_MOZILLA_PROFILE,"") << llendl; - } - } - mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem"); } @@ -278,114 +266,6 @@ 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 */ diff --git a/indra/llvfs/lldir_solaris.h b/indra/llvfs/lldir_solaris.h index 139754ba2..88da8500d 100644 --- a/indra/llvfs/lldir_solaris.h +++ b/indra/llvfs/lldir_solaris.h @@ -30,6 +30,10 @@ * $/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 @@ -44,19 +48,18 @@ public: LLDir_Solaris(); virtual ~LLDir_Solaris(); - virtual void initAppDirs(const std::string &app_name); -public: + /*virtual*/ void initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir); + virtual std::string getCurPath(); virtual U32 countFilesInDir(const std::string &dirname, const std::string &mask); - virtual BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap); - virtual void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) 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 c41c591c5..009add14b 100644 --- a/indra/llvfs/lldir_win32.cpp +++ b/indra/llvfs/lldir_win32.cpp @@ -87,10 +87,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,30 +107,39 @@ LLDir_Win32::LLDir_Win32() { mExecutableFilename = mExecutablePathAndName; } - GetCurrentDirectory(MAX_PATH, w_str); - mWorkingDir = utf16str_to_utf8str(llutf16string(w_str)); } else { - LL_WARNS("AppInit") << "Couldn't get APP path, assuming current directory!\n" << LL_ENDL; - GetCurrentDirectory(MAX_PATH, w_str); - mExecutableDir = utf16str_to_utf8str(llutf16string(w_str)); + fprintf(stderr, "Couldn't get APP path, assuming current directory!\n"); + mExecutableDir = mWorkingDir; // Assume it's the current directory } -#else - GetCurrentDirectory(MAX_PATH, w_str); - mExecutableDir = utf16str_to_utf8str(llutf16string(w_str)); -#endif - - // When running in a dev tree, app_settings is under indra/newview/ - // but in production it is under Program Files/SecondLife/ - // Attempt to detect which one we're using. JC - if (mExecutableDir.find("indra") != std::string::npos) - mAppRODataDir = getCurPath(); - else - mAppRODataDir = mExecutableDir; + // mAppRODataDir = "."; + + // Determine the location of the App-Read-Only-Data + // Try the working directory then the exe's dir. + mAppRODataDir = mWorkingDir; + + +// 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")) + { + // What? No skins in the working dir? + // Try the executable's directory. + mAppRODataDir = mExecutableDir; + } + + llinfos << "mAppRODataDir = " << mAppRODataDir << llendl; + + mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; // Build the default cache directory mDefaultCacheDir = buildSLOSCacheDir(); @@ -153,8 +163,15 @@ LLDir_Win32::~LLDir_Win32() // Implementation -void LLDir_Win32::initAppDirs(const std::string &app_name) +void LLDir_Win32::initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir) { + // Allow override so test apps can read newview directory + if (!app_read_only_data_dir.empty()) + { + mAppRODataDir = app_read_only_data_dir; + mSkinBaseDir = mAppRODataDir + mDirDelimiter + "skins"; + } mAppName = app_name; mOSUserAppDir = mOSUserDir; mOSUserAppDir += "\\"; @@ -199,24 +216,6 @@ void LLDir_Win32::initAppDirs(const std::string &app_name) } } - res = LLFile::mkdir(getExpandedFilename(LL_PATH_MOZILLA_PROFILE,"")); - if (res == -1) - { - if (errno != EEXIST) - { - llwarns << "Couldn't create LL_PATH_MOZILLA_PROFILE dir " << getExpandedFilename(LL_PATH_MOZILLA_PROFILE,"") << llendl; - } - } - - res = LLFile::mkdir(getExpandedFilename(LL_PATH_USER_SETTINGS, "dictionaries")); - if (res == -1) - { - if (errno != EEXIST) - { - llwarns << "Couldn't create LL_PATH_USER_SETTINGS/dictionaries dir " << getExpandedFilename(LL_PATH_MOZILLA_PROFILE,"") << llendl; - } - } - mCAFile = getExpandedFilename(LL_PATH_APP_SETTINGS, "CA.pem"); } @@ -247,122 +246,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]; diff --git a/indra/llvfs/lldir_win32.h b/indra/llvfs/lldir_win32.h index 9ef4d300b..4421b87f0 100644 --- a/indra/llvfs/lldir_win32.h +++ b/indra/llvfs/lldir_win32.h @@ -30,6 +30,10 @@ * $/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 @@ -41,20 +45,17 @@ public: LLDir_Win32(); virtual ~LLDir_Win32(); - /*virtual*/ void initAppDirs(const std::string &app_name); + /*virtual*/ void initAppDirs(const std::string &app_name, + const std::string& app_read_only_data_dir); /*virtual*/ std::string getCurPath(); /*virtual*/ U32 countFilesInDir(const std::string &dirname, const std::string &mask); - /*virtual*/ BOOL getNextFileInDir(const std::string &dirname, const std::string &mask, std::string &fname, BOOL wrap); - /*virtual*/ void getRandomFileInDir(const std::string &dirname, const std::string &mask, std::string &fname); /*virtual*/ BOOL fileExists(const std::string &filename) 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/lldiriterator.cpp b/indra/llvfs/lldiriterator.cpp new file mode 100644 index 000000000..9434efd40 --- /dev/null +++ b/indra/llvfs/lldiriterator.cpp @@ -0,0 +1,210 @@ +/** + * @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 +#include + +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); + + // Check if path exists. + if (!fs::exists(dir_path)) + { + llwarns << "Invalid path: \"" << dir_path.string() << "\"" << llendl; + return; + } + + // Initialize the directory iterator for the given path. + try + { + mIter = fs::directory_iterator(dir_path); + } +#if BOOST_FILESYSTEM_VERSION == 2 + catch (fs::basic_filesystem_error& e) +#else + catch (fs::filesystem_error& e) +#endif + { + llerrs << e.what() << llendl; + 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) + { + llerrs << "\"" << exp << "\" is not a valid regular expression: " + << e.what() << llendl; + return; + } + + mIsValid = true; +} + +LLDirIterator::Impl::~Impl() +{ +} + +bool LLDirIterator::Impl::next(std::string &fname) +{ + fname = ""; + + if (!mIsValid) + { + llwarns << "The iterator is not correctly initialized." << llendl; + return false; + } + + fs::directory_iterator end_itr; // default construction yields past-the-end + bool found = false; + while (mIter != end_itr && !found) + { + boost::smatch match; +#if BOOST_FILESYSTEM_VERSION == 2 + std::string name = mIter->path().filename(); +#else + std::string name = mIter->path().filename().string(); +#endif + if (found = boost::regex_match(name, match, mFilterExp)) + { + fname = name; + } + + ++mIter; + } + + return found; +} + +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 '.': + regex+="\\."; + break; + case '*': + if (glob.begin() == i) + { + regex+="[^.].*"; + } + else + { + regex+= escaped ? "*" : ".*"; + } + break; + case '?': + regex+= escaped ? '?' : '.'; + break; + case '{': + braces++; + regex+='('; + break; + case '}': + if (!braces) + { + llerrs << "glob_to_regex: Closing brace without an equivalent opening brace: " << glob << llendl; + } + + regex+=')'; + braces--; + break; + case ',': + regex+= braces ? '|' : c; + break; + case '!': + regex+= square_brace_open ? '^' : c; + break; + default: + regex+=c; + break; + } + + escaped = ('\\' == c); + square_brace_open = ('[' == c); + } + + if (braces) + { + llerrs << "glob_to_regex: Unterminated brace expression: " << glob << llendl; + } + + 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 100644 index 000000000..0b48be41b --- /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: + * + * LLDirIterator iter(directory, pattern); + * if ( iter.next(scanResult) ) + * + * + * @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 69c7eb6d6..ba4ccba0e 100644 --- a/indra/llvfs/lllfsthread.cpp +++ b/indra/llvfs/lllfsthread.cpp @@ -227,7 +227,6 @@ bool LLLFSThread::Request::processRequest() } mBytesRead = outfile.write(mBuffer, mBytes ); complete = true; - // llinfos << "LLLFSThread::WRITE:" << mFileName << " Bytes: " << mBytesRead << "/" << mBytes << " Offset:" << mOffset << llendl; } else diff --git a/indra/llvfs/lllfsthread.h b/indra/llvfs/lllfsthread.h index 5a11cb33d..9b2b542d2 100644 --- a/indra/llvfs/lllfsthread.h +++ b/indra/llvfs/lllfsthread.h @@ -39,7 +39,7 @@ #include #include "llapr.h" - +#include "llmemory.h" // LLPointer #include "llqueuedthread.h" //============================================================================ diff --git a/indra/llvfs/llpidlock.cpp b/indra/llvfs/llpidlock.cpp index 93f1af52b..28cee2940 100644 --- a/indra/llvfs/llpidlock.cpp +++ b/indra/llvfs/llpidlock.cpp @@ -39,9 +39,17 @@ #include "llsdserialize.h" #include "llnametable.h" #include "llframetimer.h" -#include "llapp.h" #if LL_WINDOWS //For windows platform. + +#include + +namespace { + inline DWORD getpid() { + return GetCurrentProcessId(); + } +} + bool isProcessAlive(U32 pid) { return (bool) GetProcessVersion((DWORD)pid); @@ -63,11 +71,11 @@ class LLPidLockFile mAutosave(false), mSaving(false), mWaiting(false), - mPID(LLApp::getPid()), + mPID(getpid()), mNameTable(NULL), mClean(true) { - mLockName = gDirUtilp->getTempDir() + "/savelock"; + mLockName = gDirUtilp->getTempDir() + gDirUtilp->getDirDelimiter() + "savelock"; } bool requestLock(LLNameTable *name_table, bool autosave, bool force_immediate=FALSE, F32 timeout=300.0); diff --git a/indra/llvfs/llpidlock.h b/indra/llvfs/llpidlock.h index efcfd9150..496e99cf5 100644 --- a/indra/llvfs/llpidlock.h +++ b/indra/llvfs/llpidlock.h @@ -37,15 +37,9 @@ class LLSD; class LLFrameTimer; -#if LL_WINDOWS //For windows platform. - -#include - -#else //Everyone Else - +#if !LL_WINDOWS //For non-windows platforms. #include - -#endif //Everyone else. +#endif namespace LLPidLock { diff --git a/indra/llvfs/llvfile.cpp b/indra/llvfs/llvfile.cpp index 630975a05..4336cf542 100644 --- a/indra/llvfs/llvfile.cpp +++ b/indra/llvfs/llvfile.cpp @@ -38,7 +38,6 @@ #include "llthread.h" #include "llstat.h" #include "llvfs.h" -#include "llfasttimer.h" const S32 LLVFile::READ = 0x00000001; const S32 LLVFile::WRITE = 0x00000002; @@ -319,7 +318,7 @@ BOOL LLVFile::setMaxSize(S32 size) if (!mVFS->checkAvailable(size)) { - LLFastTimer t(LLFastTimer::FTM_VFILE_WAIT); + //LLFastTimer t(FTM_VFILE_WAIT); S32 count = 0; while (sVFSThread->getPending() > 1000) { @@ -427,7 +426,7 @@ bool LLVFile::isLocked(EVFSLock lock) void LLVFile::waitForLock(EVFSLock lock) { - LLFastTimer t(LLFastTimer::FTM_VFILE_WAIT); + //LLFastTimer t(FTM_VFILE_WAIT); // spin until the lock clears while (isLocked(lock)) { diff --git a/indra/llvfs/llvfs.cpp b/indra/llvfs/llvfs.cpp index 1f4c991b2..4767ffcfb 100644 --- a/indra/llvfs/llvfs.cpp +++ b/indra/llvfs/llvfs.cpp @@ -32,6 +32,8 @@ #include "linden_common.h" +#include "llvfs.h" + #include #include #include @@ -45,7 +47,6 @@ #include #endif -#include "llvfs.h" #include "llstl.h" #include "lltimer.h" @@ -217,7 +218,9 @@ const S32 LLVFSFileBlock::SERIAL_SIZE = 34; LLVFS::LLVFS(const std::string& index_filename, const std::string& data_filename, const BOOL read_only, const U32 presize, const BOOL remove_after_crash) -: mRemoveAfterCrash(remove_after_crash) +: mRemoveAfterCrash(remove_after_crash), + mDataFP(NULL), + mIndexFP(NULL) { mDataMutex = new LLMutex; @@ -233,17 +236,21 @@ LLVFS::LLVFS(const std::string& index_filename, const std::string& data_filename const char *file_mode = mReadOnly ? "rb" : "r+b"; - if (! (mDataFP = openAndLock(mDataFilename, file_mode, mReadOnly))) + LL_INFOS("VFS") << "Attempting to open VFS index file " << mIndexFilename << LL_ENDL; + LL_INFOS("VFS") << "Attempting to open VFS data file " << mDataFilename << LL_ENDL; + + mDataFP = openAndLock(mDataFilename, file_mode, mReadOnly); + if (!mDataFP) { - if (mReadOnly) { LL_WARNS("VFS") << "Can't find " << mDataFilename << " to open read-only VFS" << LL_ENDL; mValid = VFSVALID_BAD_CANNOT_OPEN_READONLY; return; } - - if((mDataFP = openAndLock(mDataFilename, "w+b", FALSE))) + + mDataFP = openAndLock(mDataFilename, "w+b", FALSE); + if (mDataFP) { // Since we're creating this data file, assume any index file is bogus // remove the index, since this vfs is now blank @@ -251,41 +258,12 @@ LLVFS::LLVFS(const std::string& index_filename, const std::string& data_filename } else { - LL_WARNS("VFS") << "Can't open VFS data file " << mDataFilename << " attempting to use alternate" << LL_ENDL; - - std::string temp_index; - std::string temp_data; - - for (U32 count = 0; count < 256; count++) - { - temp_index = mIndexFilename + llformat(".%u",count); - temp_data = mDataFilename + llformat(".%u", count); - - // try just opening, then creating, each alternate - if ((mDataFP = openAndLock(temp_data, "r+b", FALSE))) - { - break; - } - - if ((mDataFP = openAndLock(temp_data, "w+b", FALSE))) - { - // we're creating the datafile, so nuke the indexfile - LLFile::remove(temp_index); - break; - } - } - - if (! mDataFP) - { - LL_WARNS("VFS") << "Couldn't open vfs data file after trying many alternates" << LL_ENDL; - mValid = VFSVALID_BAD_CANNOT_CREATE; - return; - } - - mIndexFilename = temp_index; - mDataFilename = temp_data; + LL_WARNS("VFS") << "Couldn't open vfs data file " + << mDataFilename << LL_ENDL; + mValid = VFSVALID_BAD_CANNOT_CREATE; + return; } - + if (presize) { presizeDataFile(presize); @@ -334,21 +312,20 @@ LLVFS::LLVFS(const std::string& index_filename, const std::string& data_filename llstat fbuf; if (! LLFile::stat(mIndexFilename, &fbuf) && fbuf.st_size >= LLVFSFileBlock::SERIAL_SIZE && - (mIndexFP = openAndLock(mIndexFilename, file_mode, mReadOnly)) + (mIndexFP = openAndLock(mIndexFilename, file_mode, mReadOnly)) // Yes, this is an assignment and not '==' ) { - U8 *buffer = new U8[fbuf.st_size]; - size_t nread = fread(buffer, 1, fbuf.st_size, mIndexFP); - - U8 *tmp_ptr = buffer; - + std::vector buffer(fbuf.st_size); + size_t buf_offset = 0; + size_t nread = fread(&buffer[0], 1, fbuf.st_size, mIndexFP); + std::vector files_by_loc; - while (tmp_ptr < buffer + nread) + while (buf_offset < nread) { LLVFSFileBlock *block = new LLVFSFileBlock(); - block->deserialize(tmp_ptr, (S32)(tmp_ptr - buffer)); + block->deserialize(&buffer[buf_offset], (S32)buf_offset); // Do sanity check on this block. // Note that this skips zero size blocks, which helps VFS @@ -372,7 +349,6 @@ LLVFS::LLVFS(const std::string& index_filename, const std::string& data_filename LL_WARNS("VFS") << "Length: " << block->mLength << "\tLocation: " << block->mLocation << "\tSize: " << block->mSize << LL_ENDL; LL_WARNS("VFS") << "File has bad data - VFS removed" << LL_ENDL; - delete[] buffer; delete block; unlockAndClose( mIndexFP ); @@ -395,15 +371,13 @@ LLVFS::LLVFS(const std::string& index_filename, const std::string& data_filename else { // this is a null or bad entry, skip it - S32 index_loc = (S32)(tmp_ptr - buffer); - mIndexHoles.push_back(index_loc); + mIndexHoles.push_back(buf_offset); delete block; } - tmp_ptr += LLVFSFileBlock::SERIAL_SIZE; + buf_offset += LLVFSFileBlock::SERIAL_SIZE; } - delete[] buffer; std::sort( files_by_loc.begin(), @@ -526,7 +500,7 @@ LLVFS::LLVFS(const std::string& index_filename, const std::string& data_filename addFreeBlock(new LLVFSBlock(0, data_size)); } } - else + else // Pre-existing index file wasn't opened { if (mReadOnly) { @@ -566,9 +540,8 @@ LLVFS::LLVFS(const std::string& index_filename, const std::string& data_filename } } - // Success! - LL_INFOS("VFS") << "Using index file " << mIndexFilename << LL_ENDL; - LL_INFOS("VFS") << "Using data file " << mDataFilename << LL_ENDL; + LL_INFOS("VFS") << "Using VFS index file " << mIndexFilename << LL_ENDL; + LL_INFOS("VFS") << "Using VFS data file " << mDataFilename << LL_ENDL; mValid = VFSVALID_OK; } @@ -607,6 +580,47 @@ LLVFS::~LLVFS() delete mDataMutex; } + +// Use this function normally to create LLVFS files. +// Will append digits to the end of the filename with multiple re-trys +// static +LLVFS * LLVFS::createLLVFS(const std::string& index_filename, + const std::string& data_filename, + const BOOL read_only, + const U32 presize, + const BOOL remove_after_crash) +{ + LLVFS * new_vfs = new LLVFS(index_filename, data_filename, read_only, presize, remove_after_crash); + + if( !new_vfs->isValid() ) + { // First name failed, retry with new names + std::string retry_vfs_index_name; + std::string retry_vfs_data_name; + S32 count = 0; + while (!new_vfs->isValid() && + count < 256) + { // Append '.' to end of filenames + retry_vfs_index_name = index_filename + llformat(".%u",count); + retry_vfs_data_name = data_filename + llformat(".%u", count); + + delete new_vfs; // Delete bad VFS and try again + new_vfs = new LLVFS(retry_vfs_index_name, retry_vfs_data_name, read_only, presize, remove_after_crash); + + count++; + } + } + + if( !new_vfs->isValid() ) + { + delete new_vfs; // Delete bad VFS + new_vfs = NULL; // Total failure + } + + return new_vfs; +} + + + void LLVFS::presizeDataFile(const U32 size) { if (!mDataFP) @@ -845,20 +859,18 @@ BOOL LLVFS::setMaxSize(const LLUUID &file_id, const LLAssetType::EType file_type if (block->mSize > 0) { // move the file into the new block - U8 *buffer = new U8[block->mSize]; + std::vector buffer(block->mSize); fseek(mDataFP, block->mLocation, SEEK_SET); - if (fread(buffer, block->mSize, 1, mDataFP) == 1) + if (fread(&buffer[0], block->mSize, 1, mDataFP) == 1) { fseek(mDataFP, new_data_location, SEEK_SET); - if (fwrite(buffer, block->mSize, 1, mDataFP) != 1) + if (fwrite(&buffer[0], block->mSize, 1, mDataFP) != 1) { llwarns << "Short write" << llendl; } } else { llwarns << "Short read" << llendl; } - - delete[] buffer; } } @@ -1682,32 +1694,33 @@ void LLVFS::audit() fflush(mIndexFP); fseek(mIndexFP, 0, SEEK_END); - long index_size = ftell(mIndexFP); + size_t index_size = ftell(mIndexFP); fseek(mIndexFP, 0, SEEK_SET); BOOL vfs_corrupt = FALSE; - U8 *buffer = new U8[index_size]; + // since we take the address of element 0, we need to have at least one element. + std::vector buffer(llmax(index_size,1U)); - if (fread(buffer, 1, index_size, mIndexFP) != index_size) + if (fread(&buffer[0], 1, index_size, mIndexFP) != index_size) { llwarns << "Index truncated" << llendl; vfs_corrupt = TRUE; } - U8 *tmp_ptr = buffer; + size_t buf_offset = 0; std::map found_files; U32 cur_time = (U32)time(NULL); std::vector audit_blocks; - while (!vfs_corrupt && tmp_ptr < buffer + index_size) + while (!vfs_corrupt && buf_offset < index_size) { LLVFSFileBlock *block = new LLVFSFileBlock(); audit_blocks.push_back(block); - block->deserialize(tmp_ptr, (S32)(tmp_ptr - buffer)); - tmp_ptr += block->SERIAL_SIZE; + block->deserialize(&buffer[buf_offset], (S32)buf_offset); + buf_offset += block->SERIAL_SIZE; // do sanity check on this block if (block->mLength >= 0 && @@ -1766,8 +1779,6 @@ void LLVFS::audit() } } - delete[] buffer; - if (!vfs_corrupt) { for (fileblock_map::iterator it = mFileBlocks.begin(); it != mFileBlocks.end(); ++it) @@ -2013,6 +2024,11 @@ std::string get_extension(LLAssetType::EType type) case LLAssetType::AT_ANIMATION: extension = ".lla"; break; +#if 0 // Don't have this defined yet. + case LLAssetType::AT_MESH: + extension = ".slm"; + break; +#endif default: // Just use the asset server filename extension in most cases extension += "."; @@ -2072,21 +2088,21 @@ void LLVFS::dumpFiles() { LLUUID id = file_spec.mFileID; LLAssetType::EType type = file_spec.mFileType; - U8* buffer = new U8[size]; + std::vector buffer(size); unlockData(); - getData(id, type, buffer, 0, size); + getData(id, type, &buffer[0], 0, size); lockData(); std::string extension = get_extension(type); std::string filename = id.asString() + extension; llinfos << " Writing " << filename << llendl; - LLAPRFile outfile ; - outfile.open(filename, LL_APR_WB, LLAPRFile::global); - outfile.write(buffer, size); + LLAPRFile outfile; + outfile.open(filename, LL_APR_WB, LLAPRFile::local); + outfile.write(&buffer[0], size); outfile.close(); - delete[] buffer; + files_extracted++; } } diff --git a/indra/llvfs/llvfs.h b/indra/llvfs/llvfs.h index db3713f7d..da57d0468 100644 --- a/indra/llvfs/llvfs.h +++ b/indra/llvfs/llvfs.h @@ -118,11 +118,25 @@ public: class LLVFS { -public: +private: + // Use createLLVFS() to open a VFS file // Pass 0 to not presize - LLVFS(const std::string& index_filename, const std::string& data_filename, const BOOL read_only, const U32 presize, const BOOL remove_after_crash); + LLVFS(const std::string& index_filename, + const std::string& data_filename, + const BOOL read_only, + const U32 presize, + const BOOL remove_after_crash); +public: ~LLVFS(); + // Use this function normally to create LLVFS files + // Pass 0 to not presize + static LLVFS * createLLVFS(const std::string& index_filename, + const std::string& data_filename, + const BOOL read_only, + const U32 presize, + const BOOL remove_after_crash); + BOOL isValid() const { return (VFSVALID_OK == mValid); } EVFSValid getValidState() const { return mValid; } @@ -184,6 +198,7 @@ protected: void lockData() { mDataMutex->lock(); } void unlockData() { mDataMutex->unlock(); } +protected: LLMutex* mDataMutex; // diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index d0f5ac23e..9c01fb349 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -4623,6 +4623,17 @@ Value 4 + DumpVFSCaches + + Comment + Dump VFS caches on startup. + Persist + 1 + Type + Boolean + Value + 0 + DynamicCameraStrength Comment diff --git a/indra/newview/ascentdaycyclemanager.cpp b/indra/newview/ascentdaycyclemanager.cpp index 43f243f08..4462435cf 100644 --- a/indra/newview/ascentdaycyclemanager.cpp +++ b/indra/newview/ascentdaycyclemanager.cpp @@ -18,6 +18,7 @@ #include "pipeline.h" #include "llsky.h" +#include "lldiriterator.h" #include "llsliderctrl.h" #include "llspinctrl.h" #include "llcheckboxctrl.h" @@ -58,10 +59,11 @@ void AscentDayCycleManager::loadPresets(const std::string& file_name) LL_INFOS2("AppInit", "Shaders") << "Loading Default Day Cycle preset from " << path_name << LL_ENDL; bool found = true; + LLDirIterator app_settings_iter(path_name, "*.xml"); while(found) { std::string name; - found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name, false); + found = app_settings_iter.next(name); if(found) { @@ -84,10 +86,11 @@ void AscentDayCycleManager::loadPresets(const std::string& file_name) LL_INFOS2("AppInit", "Shaders") << "Loading User Daycycle preset from " << path_name2 << LL_ENDL; found = true; + LLDirIterator user_settings_iter(path_name2, "*.xml"); while(found) { std::string name; - found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name, false); + found = user_settings_iter.next(name); if(found) { name=name.erase(name.length()-4); diff --git a/indra/newview/lgghunspell_wrapper.cpp b/indra/newview/lgghunspell_wrapper.cpp index b8748ff2c..6eb1297f9 100644 --- a/indra/newview/lgghunspell_wrapper.cpp +++ b/indra/newview/lgghunspell_wrapper.cpp @@ -21,6 +21,7 @@ #include "llweb.h" #include "llviewercontrol.h" #include "llviewerwindow.h" +#include "lldiriterator.h" #include "llfile.h" #include "llhttpclient.h" #include "lggdicdownload.h" @@ -768,28 +769,18 @@ std::vector lggHunSpell_Wrapper::getDicts() { std::vector names; std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "dictionaries", "")); - bool found = true; - while (found) + std::string name; + LLDirIterator app_iter(path_name, "*.aff"); + while (app_iter.next(name)) { - std::string name; - found = gDirUtilp->getNextFileInDir(path_name, "*.aff", name, false); - if (found) - { - names.push_back(dictName2FullName(name)); - } + names.push_back(dictName2FullName(name)); } path_name = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "dictionaries", ""); - found = true; - while (found) + LLDirIterator user_iter(path_name, "*.aff"); + while (user_iter.next(name)) { - std::string name; - found = gDirUtilp->getNextFileInDir(path_name, "*.aff", name, false); - if (found) - { - names.push_back(dictName2FullName(name)); - } + names.push_back(dictName2FullName(name)); } - return names; } @@ -797,26 +788,17 @@ std::vector lggHunSpell_Wrapper::getExtraDicts() { std::vector names; std::string path_name(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "dictionaries", "")); - bool found = true; - while (found) + std::string name; + LLDirIterator app_iter(path_name, "*.dic"); + while (app_iter.next(name)) { - std::string name; - found = gDirUtilp->getNextFileInDir(path_name, "*.dic", name, false); - if (found) - { - names.push_back(dictName2FullName(name)); - } + names.push_back(dictName2FullName(name)); } path_name = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "dictionaries", ""); - found = true; - while (found) + LLDirIterator user_iter(path_name, "*.dic"); + while (user_iter.next(name)) { - std::string name; - found = gDirUtilp->getNextFileInDir(path_name, "*.dic", name, false); - if (found) - { - names.push_back(dictName2FullName(name)); - } + names.push_back(dictName2FullName(name)); } return names; } diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index e3f95f5ca..74b18209b 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -178,6 +178,7 @@ #include "llviewerthrottle.h" #include "llparcel.h" +#include "lldiriterator.h" #include "llavatarnamecache.h" #include "llinventoryview.h" @@ -2952,8 +2953,10 @@ void LLAppViewer::migrateCacheDirectory() // Migrate inventory cache to avoid pain to inventory database after mass update S32 file_count = 0; std::string file_name; - std::string mask = delimiter + "*.*"; - while (gDirUtilp->getNextFileInDir(old_cache_dir, mask, file_name, false)) + std::string mask = "*.*"; + + LLDirIterator iter(old_cache_dir, mask); + while (iter.next(file_name)) { if (file_name == "." || file_name == "..") continue; std::string source_path = old_cache_dir + delimiter + file_name; @@ -2987,6 +2990,44 @@ void LLAppViewer::migrateCacheDirectory() #endif // LL_WINDOWS || LL_DARWIN } +void dumpVFSCaches() +{ + llinfos << "======= Static VFS ========" << llendl; + gStaticVFS->listFiles(); +#if LL_WINDOWS + llinfos << "======= Dumping static VFS to StaticVFSDump ========" << llendl; + WCHAR w_str[MAX_PATH]; + GetCurrentDirectory(MAX_PATH, w_str); + S32 res = LLFile::mkdir("StaticVFSDump"); + if (res == -1) + { + if (errno != EEXIST) + { + llwarns << "Couldn't create dir StaticVFSDump" << llendl; + } + } + SetCurrentDirectory(utf8str_to_utf16str("StaticVFSDump").c_str()); + gStaticVFS->dumpFiles(); + SetCurrentDirectory(w_str); +#endif + llinfos << "========= Dynamic VFS ====" << llendl; + gVFS->listFiles(); +#if LL_WINDOWS + llinfos << "========= Dumping dynamic VFS to VFSDump ====" << llendl; + res = LLFile::mkdir("VFSDump"); + if (res == -1) + { + if (errno != EEXIST) + { + llwarns << "Couldn't create dir VFSDump" << llendl; + } + } + SetCurrentDirectory(utf8str_to_utf16str("VFSDump").c_str()); + gVFS->dumpFiles(); + SetCurrentDirectory(w_str); +#endif +} + //static U32 LLAppViewer::getTextureCacheVersion() { @@ -3017,11 +3058,12 @@ bool LLAppViewer::initCache() if (gSavedSettings.getBOOL("PurgeCacheOnStartup") || gSavedSettings.getBOOL("PurgeCacheOnNextStartup")) { - gSavedSettings.setBOOL("PurgeCacheOnNextStartup", false); - mPurgeCache = true; + gSavedSettings.setBOOL("PurgeCacheOnNextStartup", false); + mPurgeCache = true; // STORM-1141 force purgeAllTextures to get called to prevent a crash here. -brad - texture_cache_mismatch = true; - } + // Bullshit, mPurgeCache already causes the same and doing it twice just leads to loads of warnings. --Aleric + //texture_cache_mismatch = true; + } // We have moved the location of the cache directory over time. migrateCacheDirectory(); @@ -3047,38 +3089,53 @@ bool LLAppViewer::initCache() { LLSplashScreen::update("Clearing cache..."); purgeCache(); + // + texture_cache_mismatch = false; + // } LLSplashScreen::update("Initializing Texture Cache..."); // Init the texture cache // Allocate 80% of the cache size for textures - const S32 MB = 1024*1024; + const S32 MB = 1024 * 1024; + const S64 MIN_CACHE_SIZE = 64 * MB; + const S64 MAX_CACHE_SIZE = 9984ll * MB; + const S64 MAX_VFS_SIZE = 1024 * MB; // 1 GB + S64 cache_size = (S64)(gSavedSettings.getU32("CacheSize")) * MB; - const S64 MAX_CACHE_SIZE = 1024*MB; - cache_size = llmin(cache_size, MAX_CACHE_SIZE); - S64 texture_cache_size = ((cache_size * 8)/10); + cache_size = llclamp(cache_size, MIN_CACHE_SIZE, MAX_CACHE_SIZE); + + S64 texture_cache_size = ((cache_size * 8) / 10); + S64 vfs_size = cache_size - texture_cache_size; + + if (vfs_size > MAX_VFS_SIZE) + { + // Give the texture cache more space, since the VFS can't be bigger than 1GB. + // This happens when the user's CacheSize setting is greater than 5GB. + vfs_size = MAX_VFS_SIZE; + texture_cache_size = cache_size - MAX_VFS_SIZE; + } + S64 extra = LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, texture_cache_mismatch); texture_cache_size -= extra; LLSplashScreen::update("Initializing VFS..."); // Init the VFS - S64 vfs_size = cache_size - texture_cache_size; - const S64 MAX_VFS_SIZE = 1024 * MB; // 1 GB - vfs_size = llmin(vfs_size, MAX_VFS_SIZE); + vfs_size = llmin(vfs_size + extra, MAX_VFS_SIZE); vfs_size = (vfs_size / MB) * MB; // make sure it is MB aligned U32 vfs_size_u32 = (U32)vfs_size; U32 old_vfs_size = gSavedSettings.getU32("VFSOldSize") * MB; bool resize_vfs = (vfs_size_u32 != old_vfs_size); if (resize_vfs) { - gSavedSettings.setU32("VFSOldSize", vfs_size_u32/MB); + gSavedSettings.setU32("VFSOldSize", vfs_size_u32 / MB); } - LL_INFOS("AppCache") << "VFS CACHE SIZE: " << vfs_size/(1024*1024) << " MB" << LL_ENDL; + LL_INFOS("AppCache") << "VFS CACHE SIZE: " << vfs_size / (1024*1024) << " MB" << LL_ENDL; // This has to happen BEFORE starting the vfs - //time_t ltime; + // time_t ltime; srand(time(NULL)); // Flawfinder: ignore U32 old_salt = gSavedSettings.getU32("VFSSalt"); U32 new_salt; @@ -3099,10 +3156,10 @@ bool LLAppViewer::initCache() do { new_salt = rand(); - } while( new_salt == old_salt ); + } while(new_salt == old_salt); } - old_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_DATA_FILE_BASE) + llformat("%u",old_salt); + old_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, VFS_DATA_FILE_BASE) + llformat("%u",old_salt); // make sure this file exists llstat s; @@ -3111,15 +3168,15 @@ bool LLAppViewer::initCache() { // doesn't exist, look for a data file std::string mask; - mask = gDirUtilp->getDirDelimiter(); - mask += VFS_DATA_FILE_BASE; + mask = VFS_DATA_FILE_BASE; mask += "*"; std::string dir; - dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""); + dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); std::string found_file; - if (gDirUtilp->getNextFileInDir(dir, mask, found_file, false)) + LLDirIterator iter(dir, mask); + if (iter.next(found_file)) { old_vfs_data_file = dir + gDirUtilp->getDirDelimiter() + found_file; @@ -3132,7 +3189,7 @@ bool LLAppViewer::initCache() } } - old_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_INDEX_FILE_BASE) + llformat("%u",old_salt); + old_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, VFS_INDEX_FILE_BASE) + llformat("%u",old_salt); stat_result = LLFile::stat(old_vfs_index_file, &s); if (stat_result) @@ -3145,27 +3202,25 @@ bool LLAppViewer::initCache() // Just in case, nuke any other old cache files in the directory. std::string dir; - dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""); + dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""); std::string mask; - mask = gDirUtilp->getDirDelimiter(); - mask += VFS_DATA_FILE_BASE; + mask = VFS_DATA_FILE_BASE; mask += "*"; gDirUtilp->deleteFilesInDir(dir, mask); - mask = gDirUtilp->getDirDelimiter(); - mask += VFS_INDEX_FILE_BASE; + mask = VFS_INDEX_FILE_BASE; mask += "*"; gDirUtilp->deleteFilesInDir(dir, mask); } - new_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_DATA_FILE_BASE) + llformat("%u",new_salt); - new_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, VFS_INDEX_FILE_BASE) + llformat("%u",new_salt); + new_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, VFS_DATA_FILE_BASE) + llformat("%u", new_salt); + new_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, VFS_INDEX_FILE_BASE) + llformat("%u", new_salt); - static_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"static_data.db2"); - static_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"static_index.db2"); + static_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "static_data.db2"); + static_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "static_index.db2"); if (resize_vfs) { @@ -3187,36 +3242,44 @@ bool LLAppViewer::initCache() gSavedSettings.setU32("VFSSalt", new_salt); // Don't remove VFS after viewer crashes. If user has corrupt data, they can reinstall. JC - gVFS = new LLVFS(new_vfs_index_file, new_vfs_data_file, false, vfs_size_u32, false); - if( VFSVALID_BAD_CORRUPT == gVFS->getValidState() ) + gVFS = LLVFS::createLLVFS(new_vfs_index_file, new_vfs_data_file, false, vfs_size_u32, false); + if (!gVFS) { - // Try again with fresh files - // (The constructor deletes corrupt files when it finds them.) - LL_WARNS("AppCache") << "VFS corrupt, deleted. Making new VFS." << LL_ENDL; - delete gVFS; - gVFS = new LLVFS(new_vfs_index_file, new_vfs_data_file, false, vfs_size_u32, false); + return false; } - gStaticVFS = new LLVFS(static_vfs_index_file, static_vfs_data_file, true, 0, false); + gStaticVFS = LLVFS::createLLVFS(static_vfs_index_file, static_vfs_data_file, true, 0, false); + if (!gStaticVFS) + { + return false; + } BOOL success = gVFS->isValid() && gStaticVFS->isValid(); - if( !success ) + if (!success) { return false; } else { LLVFile::initClass(); + +#ifndef LL_RELEASE_FOR_DOWNLOAD + if (gSavedSettings.getBOOL("DumpVFSCaches")) + { + dumpVFSCaches(); + } +#endif + return true; } } void LLAppViewer::purgeCache() { - LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << llendl; + LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << LL_ENDL; LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE); - std::string mask = gDirUtilp->getDirDelimiter() + "*.*"; - gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),mask); + std::string mask = "*.*"; + gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), mask); } const std::string& LLAppViewer::getSecondLifeTitle() const diff --git a/indra/newview/llappviewerlinux.cpp b/indra/newview/llappviewerlinux.cpp index 4e4bbcb43..154e38de3 100644 --- a/indra/newview/llappviewerlinux.cpp +++ b/indra/newview/llappviewerlinux.cpp @@ -36,6 +36,7 @@ #include "llcommandlineparser.h" +#include "lldiriterator.h" #include "llmemtype.h" #include "llurldispatcher.h" // SLURL from other app instance #include "llviewernetwork.h" @@ -741,8 +742,8 @@ std::string LLAppViewerLinux::generateSerialNumber() // trawl /dev/disk/by-uuid looking for a good-looking UUID to grab std::string this_name; - BOOL wrap = FALSE; - while (gDirUtilp->getNextFileInDir(uuiddir, "*", this_name, wrap)) + LLDirIterator iter(uuiddir, "*"); + while (iter.next(this_name)) { if (this_name.length() > best.length() || (this_name.length() == best.length() && diff --git a/indra/newview/llappviewermacosx.cpp b/indra/newview/llappviewermacosx.cpp index b7bb39a74..67e5b8d78 100644 --- a/indra/newview/llappviewermacosx.cpp +++ b/indra/newview/llappviewermacosx.cpp @@ -41,6 +41,7 @@ #include "llmemtype.h" +#include "lldiriterator.h" #include "llviewernetwork.h" #include "llviewercontrol.h" #include "llmd5.h" @@ -406,7 +407,8 @@ void LLAppViewerMacOSX::handleCrashReporting(bool reportFreeze) std::string pathname = std::string(path) + std::string("/CrashReporter/"); std::string mask = "Second Life*"; std::string file_name; - while(gDirUtilp->getNextFileInDir(pathname, mask, file_name, false)) + LLDirIterator iter(pathname, mask); + while(iter.next(file_name)) { LLFile::remove(pathname + file_name); } diff --git a/indra/newview/llpanelnetwork.cpp b/indra/newview/llpanelnetwork.cpp index 6bc34989a..003af8116 100644 --- a/indra/newview/llpanelnetwork.cpp +++ b/indra/newview/llpanelnetwork.cpp @@ -186,12 +186,14 @@ void LLPanelNetwork::onClickSetCache_continued(void* user_data, AIDirPicker* dir void LLPanelNetwork::onClickResetCache(void* user_data) { LLPanelNetwork* self = (LLPanelNetwork*)user_data; - if (!gSavedSettings.getString("CacheLocation").empty()) + if (gDirUtilp->getCacheDir(false) == gDirUtilp->getCacheDir(true)) { - gSavedSettings.setString("NewCacheLocation", ""); - LLNotifications::instance().add("CacheWillBeMoved"); + // The cache location was already the default. + return; } - std::string cache_location = gDirUtilp->getCacheDir(true); + gSavedSettings.setString("NewCacheLocation", ""); + LLNotifications::instance().add("CacheWillBeMoved"); + std::string cache_location = gDirUtilp->getCacheDir(false); self->childSetText("cache_location", cache_location); } diff --git a/indra/newview/llpanelskins.cpp b/indra/newview/llpanelskins.cpp index 324efa20d..7be656031 100644 --- a/indra/newview/llpanelskins.cpp +++ b/indra/newview/llpanelskins.cpp @@ -38,6 +38,7 @@ #include "llradiogroup.h" #include "llbutton.h" #include "lluictrlfactory.h" +#include "lldiriterator.h" // project includes #include "llviewercontrol.h" @@ -79,8 +80,6 @@ void LLPanelSkins::refresh() if(comboBox != NULL) { - std::string name; - gDirUtilp->getNextFileInDir(gDirUtilp->getChatLogsDir(),"*",name,false);//stupid hack to clear last file search comboBox->removeall(); datas.clear(); //comboBox->add("===OFF==="); @@ -88,9 +87,11 @@ void LLPanelSkins::refresh() llinfos << "Reading skin listing from " << path_name << llendl; bool found = true; std::string currentSkinName(""); + LLDirIterator iter(path_name, "*.xml"); while(found) { - found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name, false); + std::string name; + found = iter.next(name); //llinfos << "path name " << path_name << " and name " << name << " and found " << found << llendl; if(found) { diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index c37add97a..e10880ecc 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -951,7 +951,7 @@ S64 LLTextureCache::initCache(ELLPath location, S64 max_size, BOOL texture_cache max_size -= sCacheMaxTexturesSize; LL_INFOS("TextureCache") << "Headers: " << sCacheMaxEntries - << " Textures size: " << sCacheMaxTexturesSize/(1024*1024) << " MB" << LL_ENDL; + << " Textures size: " << sCacheMaxTexturesSize / (1024 * 1024) << " MB" << LL_ENDL; setDirNames(location); @@ -1513,12 +1513,12 @@ void LLTextureCache::purgeAllTextures(bool purge_directories) { const char* subdirs = "0123456789abcdef"; std::string delem = gDirUtilp->getDirDelimiter(); - std::string mask = delem + "*"; + std::string mask = "*"; for (S32 i=0; i<16; i++) { std::string dirname = mTexturesDirName + delem + subdirs[i]; llinfos << "Deleting files in directory: " << dirname << llendl; - gDirUtilp->deleteFilesInDir(dirname,mask); + gDirUtilp->deleteFilesInDir(dirname, mask); if (purge_directories) { LLFile::rmdir(dirname); diff --git a/indra/newview/llwaterparammanager.cpp b/indra/newview/llwaterparammanager.cpp index 682079249..77ca7e54b 100644 --- a/indra/newview/llwaterparammanager.cpp +++ b/indra/newview/llwaterparammanager.cpp @@ -39,6 +39,7 @@ #include "pipeline.h" #include "llsky.h" +#include "lldiriterator.h" #include "llsliderctrl.h" #include "llspinctrl.h" #include "llcheckboxctrl.h" @@ -93,10 +94,11 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name) LL_INFOS2("AppInit", "Shaders") << "Loading Default water settings from " << path_name << LL_ENDL; bool found = true; + LLDirIterator app_settings_iter(path_name, "*.xml"); while(found) { std::string name; - found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name, false); + found = app_settings_iter.next(name); if(found) { @@ -119,10 +121,11 @@ void LLWaterParamManager::loadAllPresets(const std::string& file_name) LL_INFOS2("AppInit", "Shaders") << "Loading User water settings from " << path_name2 << LL_ENDL; found = true; + LLDirIterator user_settings_iter(path_name2, "*.xml"); while(found) { std::string name; - found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name, false); + found = user_settings_iter.next(name); if(found) { name=name.erase(name.length()-4); diff --git a/indra/newview/llwlparammanager.cpp b/indra/newview/llwlparammanager.cpp index bb41f9aac..d3fc32835 100644 --- a/indra/newview/llwlparammanager.cpp +++ b/indra/newview/llwlparammanager.cpp @@ -37,6 +37,7 @@ #include "pipeline.h" #include "llsky.h" +#include "lldiriterator.h" #include "llsliderctrl.h" #include "llspinctrl.h" #include "llcheckboxctrl.h" @@ -111,10 +112,11 @@ void LLWLParamManager::loadPresets(const std::string& file_name) LL_INFOS2("AppInit", "Shaders") << "Loading Default WindLight settings from " << path_name << LL_ENDL; bool found = true; + LLDirIterator app_settings_iter(path_name, "*.xml"); while(found) { std::string name; - found = gDirUtilp->getNextFileInDir(path_name, "*.xml", name, false); + found = app_settings_iter.next(name); if(found) { @@ -137,10 +139,11 @@ void LLWLParamManager::loadPresets(const std::string& file_name) LL_INFOS2("AppInit", "Shaders") << "Loading User WindLight settings from " << path_name2 << LL_ENDL; found = true; + LLDirIterator user_settings_iter(path_name2, "*.xml"); while(found) { std::string name; - found = gDirUtilp->getNextFileInDir(path_name2, "*.xml", name, false); + found = user_settings_iter.next(name); if(found) { name=name.erase(name.length()-4); diff --git a/indra/newview/skins/default/xui/en-us/panel_preferences_network.xml b/indra/newview/skins/default/xui/en-us/panel_preferences_network.xml index 51f24730d..c1040da37 100644 --- a/indra/newview/skins/default/xui/en-us/panel_preferences_network.xml +++ b/indra/newview/skins/default/xui/en-us/panel_preferences_network.xml @@ -25,11 +25,11 @@ follows="left|top" font="SansSerifSmall" h_pad="0" halign="left" height="10" left="12" mouse_opaque="false" name="cache_size_label_l" v_pad="0" width="200"> - Disk Cache Size: + Disk Cache Size (MB):