diff --git a/indra/cmake/Boost.cmake b/indra/cmake/Boost.cmake
index 7ce57a5572336c4927a7f2b6e4e97d4e3aecb745..012d3c2ab204853214cdd09db8f79762c3d6806c 100644
--- a/indra/cmake/Boost.cmake
+++ b/indra/cmake/Boost.cmake
@@ -10,6 +10,8 @@ if (STANDALONE)
   set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-mt)
   set(BOOST_REGEX_LIBRARY boost_regex-mt)
   set(BOOST_SIGNALS_LIBRARY boost_signals-mt)
+  set(BOOST_SYSTEM_LIBRARY boost_system-mt)
+  set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-mt)
 else (STANDALONE)
   use_prebuilt_binary(boost)
   set(Boost_INCLUDE_DIRS ${LIBS_PREBUILT_DIR}/include)
@@ -26,6 +28,12 @@ else (STANDALONE)
       set(BOOST_SIGNALS_LIBRARY 
           optimized libboost_signals-vc71-mt-s-${BOOST_VERSION}
           debug libboost_signals-vc71-mt-sgd-${BOOST_VERSION})
+      set(BOOST_SYSTEM_LIBRARY 
+          optimized libboost_system-vc71-mt-s-${BOOST_VERSION}
+          debug libboost_system-vc71-mt-sgd-${BOOST_VERSION})
+      set(BOOST_FILESYSTEM_LIBRARY 
+          optimized libboost_filesystem-vc71-mt-s-${BOOST_VERSION}
+          debug libboost_filesystem-vc71-mt-sgd-${BOOST_VERSION})
     else (MSVC71)
       set(BOOST_PROGRAM_OPTIONS_LIBRARY 
           optimized libboost_program_options-vc80-mt-${BOOST_VERSION}
@@ -36,14 +44,24 @@ else (STANDALONE)
       set(BOOST_SIGNALS_LIBRARY 
           optimized libboost_signals-vc80-mt-${BOOST_VERSION}
           debug libboost_signals-vc80-mt-gd-${BOOST_VERSION})
+      set(BOOST_SYSTEM_LIBRARY 
+          optimized libboost_system-vc80-mt-${BOOST_VERSION}
+          debug libboost_system-vc80-mt-gd-${BOOST_VERSION})
+      set(BOOST_FILESYSTEM_LIBRARY 
+          optimized libboost_filesystem-vc80-mt-${BOOST_VERSION}
+          debug libboost_filesystem-vc80-mt-gd-${BOOST_VERSION})
     endif (MSVC71)
   elseif (DARWIN)
     set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-xgcc40-mt)
     set(BOOST_REGEX_LIBRARY boost_regex-xgcc40-mt)
     set(BOOST_SIGNALS_LIBRARY boost_signals-xgcc40-mt)
+    set(BOOST_SYSTEM_LIBRARY boost_system-xgcc40-mt)
+    set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-xgcc40-mt)
   elseif (LINUX)
     set(BOOST_PROGRAM_OPTIONS_LIBRARY boost_program_options-gcc41-mt)
     set(BOOST_REGEX_LIBRARY boost_regex-gcc41-mt)
     set(BOOST_SIGNALS_LIBRARY boost_signals-gcc41-mt)
+    set(BOOST_SYSTEM_LIBRARY boost_system-gcc41-mt)
+    set(BOOST_FILESYSTEM_LIBRARY boost_filesystem-gcc41-mt)
   endif (WINDOWS)
 endif (STANDALONE)
diff --git a/indra/llvfs/CMakeLists.txt b/indra/llvfs/CMakeLists.txt
index 722f4e2bfdef9c6212c9edf06f2abee5f55ff996..a3782d824b4cbbcf0abe31ecb5d754238cf3c8a5 100644
--- a/indra/llvfs/CMakeLists.txt
+++ b/indra/llvfs/CMakeLists.txt
@@ -12,6 +12,7 @@ include_directories(
 
 set(llvfs_SOURCE_FILES
     lldir.cpp
+    lldiriterator.cpp
     lllfsthread.cpp
     llpidlock.cpp
     llvfile.cpp
@@ -24,6 +25,7 @@ set(llvfs_HEADER_FILES
 
     lldir.h
     lldirguard.h
+    lldiriterator.h
     lllfsthread.h
     llpidlock.h
     llvfile.h
@@ -60,6 +62,11 @@ list(APPEND llvfs_SOURCE_FILES ${llvfs_HEADER_FILES})
 
 add_library (llvfs ${llvfs_SOURCE_FILES})
 
+target_link_libraries(llvfs
+    ${BOOST_FILESYSTEM_LIBRARY}
+    ${BOOST_SYSTEM_LIBRARY}
+    )
+
 if (DARWIN)
   include(CMakeFindFrameworks)
   find_library(CARBON_LIBRARY Carbon)
diff --git a/indra/llvfs/lldiriterator.cpp b/indra/llvfs/lldiriterator.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5536ed8f69a97c49721cf0242d8a97bf5d89ad1f
--- /dev/null
+++ b/indra/llvfs/lldiriterator.cpp
@@ -0,0 +1,203 @@
+/**
+ * @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 <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);
+
+	// Check if path exists.
+	if (!fs::exists(dir_path))
+	{
+		llerrs << "Invalid path: \"" << dir_path.string() << "\"" << llendl;
+		return;
+	}
+
+	// Initialize the directory iterator for the given path.
+	try
+	{
+		mIter = fs::directory_iterator(dir_path);
+	}
+	catch (fs::basic_filesystem_error<fs::path>& e)
+	{
+		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)
+	{
+		llerrs << "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;
+		std::string name = mIter->path().filename();
+		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 0000000000000000000000000000000000000000..0b48be41b321c71935957773ea5a43494c9d5959
--- /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/tests/lldir_test.cpp b/indra/llvfs/tests/lldir_test.cpp
index 8788bd63e87d2b8030324ffcd0e0434057844151..ea321c5ae958829d739137eae3548f5cbf07c540 100644
--- a/indra/llvfs/tests/lldir_test.cpp
+++ b/indra/llvfs/tests/lldir_test.cpp
@@ -28,6 +28,7 @@
 #include "linden_common.h"
 
 #include "../lldir.h"
+#include "../lldiriterator.h"
 
 #include "../test/lltut.h"
 
@@ -259,13 +260,12 @@ namespace tut
 
    std::string makeTestFile( const std::string& dir, const std::string& file )
    {
-      std::string delim = gDirUtilp->getDirDelimiter();
-      std::string path = dir + delim + 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+"'", fputs("test file", handle) >= 0);
+      ensure("failed to write to test file '"+path+"'", EOF != fputs("test file", handle) );
       fclose(handle);
       return path;
    }
@@ -290,7 +290,7 @@ namespace tut
    }
 
    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])
    {
 
@@ -300,7 +300,8 @@ namespace tut
       bool  filesFound[5] = { false, false, false, false, false };
       //std::cerr << "searching '"+directory+"' for '"+pattern+"'\n";
 
-      while ( found <= 5 && gDirUtilp->getNextFileInDir(directory, pattern, scanResult) )
+      LLDirIterator iter(directory, pattern);
+      while ( found <= 5 && iter.next(scanResult) )
       {
          found++;
          //std::cerr << "  found '"+scanResult+"'\n";
@@ -334,15 +335,15 @@ namespace tut
    
    template<> template<>
    void LLDirTest_object_t::test<5>()
-      // getNextFileInDir
+      // 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 + "getNextFileInDir");
-      std::string dir2 = makeTestDir(dirTemp + "getNextFileInDir");
+      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++)
@@ -380,19 +381,17 @@ namespace tut
       scanTest(dir2, "file?.x?z", expected7);
 
       // Scan dir2 and see if any file?.??c files are found
-      // THESE FAIL ON Mac and Windows, SO ARE COMMENTED OUT FOR NOW
-      //      bool  expected8[5] = { true, true, false, false, false };
-      //      scanTest(dir2, "file?.??c", expected8);
-      //      scanTest(dir2, "*.??c", expected8);
+      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
-      // THIS ONE FAILS ON WINDOWS (returns three charater suffixes) SO IS COMMENTED OUT FOR NOW
-      // bool  expected10[5] = { false, false, false, false, false };
-      // scanTest(dir1, "*.????", expected10);
+      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 };
@@ -402,6 +401,15 @@ namespace tut
       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++)
       {