diff --git a/indra/llvfs/lldir.h b/indra/llvfs/lldir.h
index 4f63c04aabefa6876ad8846417ff97fc873c603f..0730b0fa79ff0f0ce21a50a10481753a82f9c416 100644
--- a/indra/llvfs/lldir.h
+++ b/indra/llvfs/lldir.h
@@ -74,7 +74,23 @@ class LLDir
 
 // 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;
+
+    /// Walk the files in a directory, with file pattern matching
+	virtual BOOL getNextFileInDir(const std::string &dirname, ///< directory path - must end in trailing slash!
+                                  const std::string &mask,    ///< file pattern string (use "*" for all)
+                                  std::string &fname,         ///< found file name
+                                  BOOL wrap                   ///< DEPRECATED - set to FALSE
+                                  ) = 0;
+    /**<
+     * @returns true if a file was found, false if the entire directory has been scanned.
+     *
+     * @note that this function is NOT thread safe
+     *
+     * This function may not be used to scan part of a directory, then start a new search of a different
+     * directory, and then restart the first search where it left off.
+     *
+     * @todo this really should be rewritten as an iterator object.
+     */
 	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;
diff --git a/indra/llvfs/tests/lldir_test.cpp b/indra/llvfs/tests/lldir_test.cpp
index bcffa449c86ea1f2ea1ae878d0f13602cd77beb1..3247e0ab830413b9097450e448b179d39ffa1cc8 100644
--- a/indra/llvfs/tests/lldir_test.cpp
+++ b/indra/llvfs/tests/lldir_test.cpp
@@ -256,5 +256,176 @@ namespace tut
 			      gDirUtilp->getExtension(dottedPathExt),
 			      "ext");
 	}
+
+   std::string makeTestFile( const std::string& dir, const std::string& file )
+   {
+      std::string delim = gDirUtilp->getDirDelimiter();
+      std::string path = dir + delim + file;
+      LLFILE* handle = LLFile::fopen( path, "w" );
+      ensure("failed to open test file '"+path+"'", handle != NULL );
+      ensure("failed to write to test file '"+path+"'", !fputs("test file", handle) );
+      fclose(handle);
+      return path;
+   }
+
+   std::string makeTestDir( const std::string& dirbase )
+   {
+      int counter;
+      std::string uniqueDir;
+      bool foundUnused;
+      std::string delim = gDirUtilp->getDirDelimiter();
+      
+      for (counter=0, foundUnused=false; !foundUnused; counter++ )
+      {
+         char counterStr[3];
+         sprintf(counterStr, "%02d", counter);
+         uniqueDir = dirbase + counterStr;
+         foundUnused = ! ( LLFile::isdir(uniqueDir) || LLFile::isfile(uniqueDir) );
+      }
+      ensure("test directory '" + uniqueDir + "' creation failed", !LLFile::mkdir(uniqueDir));
+      
+      return uniqueDir + delim; // HACK - apparently, the trailing delimiter is needed...
+   }
+
+   template<> template<>
+   void LLDirTest_object_t::test<5>()
+      // getNextFileInDir
+   {
+      std::string delim = gDirUtilp->getDirDelimiter();
+      std::string dirTemp = LLFile::tmpdir();
+
+      // Create the same 5 file names of the two directories
+      const char* filenames[5] = { "file1.abc", "file2.abc", "file1.xyz", "file2.xyz", "file1.mno" };
+      std::string dir1 = makeTestDir(dirTemp + "getNextFileInDir");
+      std::string dir2 = makeTestDir(dirTemp + "getNextFileInDir");
+      std::string dir1files[5];
+      std::string dir2files[5];
+      for (int i=0; i<5; i++)
+      {
+         dir1files[i] = makeTestFile(dir1, filenames[i]);
+         dir2files[i] = makeTestFile(dir2, filenames[i]);
+      }
+
+      // Scan dir1 and see if each of the 5 files is found exactly once
+      std::string scan1result;
+      int   found1 = 0;
+      bool  filesFound1[5] = { false, false, false, false, false };
+      // std::cerr << "searching '"+dir1+"' for *\n";
+      while ( found1 <= 5 && gDirUtilp->getNextFileInDir(dir1, "*", scan1result, false) )
+      {
+         found1++;
+         // std::cerr << "  found '"+scan1result+"'\n";
+         int check;
+         for (check=0; check < 5 && ! ( scan1result == filenames[check] ); check++)
+         {
+         }
+         // check is now either 5 (not found) or the index of the matching name
+         if (check < 5)
+         {
+            ensure( "found file '"+(std::string)filenames[check]+"' twice", ! filesFound1[check] );
+            filesFound1[check] = true;
+         }
+         else
+         {
+            ensure( "found unknown file '"+(std::string)filenames[check]+"'", false);
+         }
+      }
+      ensure("wrong number of files found in '"+dir1+"'", found1 == 5);
+
+      // Scan dir2 and see if only the 2 *.xyz files are found
+      std::string scan2result;
+      int   found2 = 0;
+      bool  filesFound2[5] = { false, false, false, false, false };
+      // std::cerr << "searching '"+dir2+"' for *.xyz\n";
+
+      while ( found2 <= 5 && gDirUtilp->getNextFileInDir(dir2, "*.xyz", scan2result, false) )
+      {
+         found2++;
+         // std::cerr << "  found '"+scan2result+"'\n";
+         int check;
+         for (check=0; check < 5 && ! ( scan2result == filenames[check] ); check++)
+         {
+         }
+         // check is now either 5 (not found) or the index of the matching name
+         if (check < 5)
+         {
+            ensure( "found file '"+(std::string)filenames[check]+"' twice", ! filesFound2[check] );
+            filesFound2[check] = true;
+         }
+         else // check is 5 - should not happen
+         {
+            ensure( "found unknown file '"+(std::string)filenames[check]+"'", false);
+         }
+      }
+      ensure("wrong files found in '"+dir2+"'",
+             !filesFound2[0] && !filesFound2[1] && filesFound2[2] && filesFound2[3] && !filesFound2[4] );
+
+
+      // Scan dir2 and see if only the 1 *.mno file is found
+      std::string scan3result;
+      int   found3 = 0;
+      bool  filesFound3[5] = { false, false, false, false, false };
+      // std::cerr << "searching '"+dir2+"' for *.mno\n";
+
+      while ( found3 <= 5 && gDirUtilp->getNextFileInDir(dir2, "*.mno", scan3result, false) )
+      {
+         found3++;
+         // std::cerr << "  found '"+scan3result+"'\n";
+         int check;
+         for (check=0; check < 5 && ! ( scan3result == filenames[check] ); check++)
+         {
+         }
+         // check is now either 5 (not found) or the index of the matching name
+         if (check < 5)
+         {
+            ensure( "found file '"+(std::string)filenames[check]+"' twice", ! filesFound3[check] );
+            filesFound3[check] = true;
+         }
+         else // check is 5 - should not happen
+         {
+            ensure( "found unknown file '"+(std::string)filenames[check]+"'", false);
+         }
+      }
+      ensure("wrong files found in '"+dir2+"'",
+             !filesFound3[0] && !filesFound3[1] && !filesFound3[2] && !filesFound3[3] && filesFound3[4] );
+
+
+      // Scan dir1 and see if any *.foo files are found
+      std::string scan4result;
+      int   found4 = 0;
+      bool  filesFound4[5] = { false, false, false, false, false };
+      // std::cerr << "searching '"+dir1+"' for *.foo\n";
+
+      while ( found4 <= 5 && gDirUtilp->getNextFileInDir(dir1, "*.foo", scan4result, false) )
+      {
+         found4++;
+         // std::cerr << "  found '"+scan4result+"'\n";
+         int check;
+         for (check=0; check < 5 && ! ( scan4result == filenames[check] ); check++)
+         {
+         }
+         // check is now either 5 (not found) or the index of the matching name
+         if (check < 5)
+         {
+            ensure( "found file '"+(std::string)filenames[check]+"' twice", ! filesFound4[check] );
+            filesFound4[check] = true;
+         }
+         else // check is 5 - should not happen
+         {
+            ensure( "found unknown file '"+(std::string)filenames[check]+"'", false);
+         }
+      }
+      ensure("wrong files found in '"+dir1+"'",
+             !filesFound4[0] && !filesFound4[1] && !filesFound4[2] && !filesFound4[3] && !filesFound4[4] );
+
+      // clean up all test files and directories
+      for (int i=0; i<5; i++)
+      {
+         LLFile::remove(dir1files[i]);
+         LLFile::remove(dir2files[i]);
+      }
+      LLFile::rmdir(dir1);
+      LLFile::rmdir(dir2);
+   }
 }