mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
DirectoryIterator: Avoid recursing into previously-visited directories
This commit is contained in:
parent
4cf036bb8b
commit
00e7fbf1c2
7 changed files with 95 additions and 24 deletions
|
|
@ -75,13 +75,26 @@ bool DirectoryIterator::next (bool* isDirResult, bool* isHiddenResult, int64* fi
|
|||
|
||||
if (! filename.containsOnly ("."))
|
||||
{
|
||||
const auto fullPath = File::createFileWithoutCheckingPath (path + filename);
|
||||
bool matches = false;
|
||||
|
||||
if (isDirectory)
|
||||
{
|
||||
if (isRecursive && ((whatToLookFor & File::ignoreHiddenFiles) == 0 || ! isHidden))
|
||||
subIterator.reset (new DirectoryIterator (File::createFileWithoutCheckingPath (path + filename),
|
||||
true, wildCard, whatToLookFor));
|
||||
const auto mayRecurseIntoPossibleHiddenDir = [this, &isHidden]
|
||||
{
|
||||
return (whatToLookFor & File::ignoreHiddenFiles) == 0 || ! isHidden;
|
||||
};
|
||||
|
||||
const auto mayRecurseIntoPossibleSymlink = [this, &fullPath]
|
||||
{
|
||||
return followSymlinks == File::FollowSymlinks::yes
|
||||
|| ! fullPath.isSymbolicLink()
|
||||
|| (followSymlinks == File::FollowSymlinks::noCycles
|
||||
&& knownPaths->find (fullPath.getLinkedTarget()) == knownPaths->end());
|
||||
};
|
||||
|
||||
if (isRecursive && mayRecurseIntoPossibleHiddenDir() && mayRecurseIntoPossibleSymlink())
|
||||
subIterator.reset (new DirectoryIterator (fullPath, true, wildCard, whatToLookFor, followSymlinks, knownPaths));
|
||||
|
||||
matches = (whatToLookFor & File::findDirectories) != 0;
|
||||
}
|
||||
|
|
@ -99,7 +112,7 @@ bool DirectoryIterator::next (bool* isDirResult, bool* isHiddenResult, int64* fi
|
|||
|
||||
if (matches)
|
||||
{
|
||||
currentFile = File::createFileWithoutCheckingPath (path + filename);
|
||||
currentFile = fullPath;
|
||||
if (isHiddenResult != nullptr) *isHiddenResult = isHidden;
|
||||
if (isDirResult != nullptr) *isDirResult = isDirectory;
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,10 @@ namespace juce
|
|||
A DirectoryIterator will search through a directory and its subdirectories using
|
||||
a wildcard filepattern match.
|
||||
|
||||
The iterator keeps track of directories that it has previously traversed, and will
|
||||
skip any previously-seen directories in the case of cycles caused by symbolic links.
|
||||
It is also possible to avoid following symbolic links altogether.
|
||||
|
||||
If you may be scanning a large number of files, it's usually smarter to use this
|
||||
class than File::findChildFiles() because it allows you to stop at any time, rather
|
||||
than having to wait for the entire scan to finish before getting the results.
|
||||
|
|
@ -73,17 +77,10 @@ public:
|
|||
DirectoryIterator (const File& directory,
|
||||
bool recursive,
|
||||
const String& pattern = "*",
|
||||
int type = File::findFiles)
|
||||
: wildCards (parseWildcards (pattern)),
|
||||
fileFinder (directory, (recursive || wildCards.size() > 1) ? "*" : pattern),
|
||||
wildCard (pattern),
|
||||
path (File::addTrailingSeparator (directory.getFullPathName())),
|
||||
whatToLookFor (type),
|
||||
isRecursive (recursive)
|
||||
int type = File::findFiles,
|
||||
File::FollowSymlinks follow = File::FollowSymlinks::yes)
|
||||
: DirectoryIterator (directory, recursive, pattern, type, follow, nullptr)
|
||||
{
|
||||
// you have to specify the type of files you're looking for!
|
||||
jassert ((whatToLookFor & (File::findFiles | File::findDirectories)) != 0);
|
||||
jassert (whatToLookFor > 0 && whatToLookFor <= 7);
|
||||
}
|
||||
|
||||
/** Moves the iterator along to the next file.
|
||||
|
|
@ -126,6 +123,39 @@ public:
|
|||
float getEstimatedProgress() const;
|
||||
|
||||
private:
|
||||
using KnownPaths = std::set<File>;
|
||||
|
||||
DirectoryIterator (const File& directory,
|
||||
bool recursive,
|
||||
const String& pattern,
|
||||
int type,
|
||||
File::FollowSymlinks follow,
|
||||
KnownPaths* seenPaths)
|
||||
: wildCards (parseWildcards (pattern)),
|
||||
fileFinder (directory, (recursive || wildCards.size() > 1) ? "*" : pattern),
|
||||
wildCard (pattern),
|
||||
path (File::addTrailingSeparator (directory.getFullPathName())),
|
||||
whatToLookFor (type),
|
||||
isRecursive (recursive),
|
||||
followSymlinks (follow),
|
||||
knownPaths (seenPaths)
|
||||
{
|
||||
// you have to specify the type of files you're looking for!
|
||||
jassert ((whatToLookFor & (File::findFiles | File::findDirectories)) != 0);
|
||||
jassert (whatToLookFor > 0 && whatToLookFor <= 7);
|
||||
|
||||
if (followSymlinks == File::FollowSymlinks::noCycles)
|
||||
{
|
||||
if (knownPaths == nullptr)
|
||||
{
|
||||
heapKnownPaths = std::make_unique<KnownPaths>();
|
||||
knownPaths = heapKnownPaths.get();
|
||||
}
|
||||
|
||||
knownPaths->insert (directory);
|
||||
}
|
||||
}
|
||||
|
||||
//==============================================================================
|
||||
struct NativeIterator
|
||||
{
|
||||
|
|
@ -152,6 +182,9 @@ private:
|
|||
bool hasBeenAdvanced = false;
|
||||
std::unique_ptr<DirectoryIterator> subIterator;
|
||||
File currentFile;
|
||||
File::FollowSymlinks followSymlinks = File::FollowSymlinks::yes;
|
||||
KnownPaths* knownPaths = nullptr;
|
||||
std::unique_ptr<KnownPaths> heapKnownPaths;
|
||||
|
||||
static StringArray parseWildcards (const String& pattern);
|
||||
static bool fileMatches (const StringArray& wildCards, const String& filename);
|
||||
|
|
|
|||
|
|
@ -561,18 +561,18 @@ void File::readLines (StringArray& destLines) const
|
|||
}
|
||||
|
||||
//==============================================================================
|
||||
Array<File> File::findChildFiles (int whatToLookFor, bool searchRecursively, const String& wildcard) const
|
||||
Array<File> File::findChildFiles (int whatToLookFor, bool searchRecursively, const String& wildcard, FollowSymlinks followSymlinks) const
|
||||
{
|
||||
Array<File> results;
|
||||
findChildFiles (results, whatToLookFor, searchRecursively, wildcard);
|
||||
findChildFiles (results, whatToLookFor, searchRecursively, wildcard, followSymlinks);
|
||||
return results;
|
||||
}
|
||||
|
||||
int File::findChildFiles (Array<File>& results, int whatToLookFor, bool searchRecursively, const String& wildcard) const
|
||||
int File::findChildFiles (Array<File>& results, int whatToLookFor, bool searchRecursively, const String& wildcard, FollowSymlinks followSymlinks) const
|
||||
{
|
||||
int total = 0;
|
||||
|
||||
for (const auto& di : RangedDirectoryIterator (*this, searchRecursively, wildcard, whatToLookFor))
|
||||
for (const auto& di : RangedDirectoryIterator (*this, searchRecursively, wildcard, whatToLookFor, followSymlinks))
|
||||
{
|
||||
results.add (di.getFile());
|
||||
++total;
|
||||
|
|
|
|||
|
|
@ -560,6 +560,23 @@ public:
|
|||
ignoreHiddenFiles = 4 /**< Add this flag to avoid returning any hidden files in the results. */
|
||||
};
|
||||
|
||||
enum class FollowSymlinks
|
||||
{
|
||||
/** Requests that a file system traversal should not follow any symbolic links. */
|
||||
no,
|
||||
|
||||
/** Requests that a file system traversal may follow symbolic links, but should attempt to
|
||||
skip any symbolic links to directories that may cause a cycle.
|
||||
*/
|
||||
noCycles,
|
||||
|
||||
/** Requests that a file system traversal follow all symbolic links. Use with care, as this
|
||||
may produce inconsistent results, or fail to terminate, if the filesystem contains cycles
|
||||
due to symbolic links.
|
||||
*/
|
||||
yes
|
||||
};
|
||||
|
||||
/** Searches this directory for files matching a wildcard pattern.
|
||||
|
||||
Assuming that this file is a directory, this method will search it
|
||||
|
|
@ -572,13 +589,15 @@ public:
|
|||
@param searchRecursively if true, all subdirectories will be recursed into to do
|
||||
an exhaustive search
|
||||
@param wildCardPattern the filename pattern to search for, e.g. "*.txt"
|
||||
@param followSymlinks the method that should be used to handle symbolic links
|
||||
@returns the set of files that were found
|
||||
|
||||
@see getNumberOfChildFiles, RangedDirectoryIterator
|
||||
*/
|
||||
Array<File> findChildFiles (int whatToLookFor,
|
||||
bool searchRecursively,
|
||||
const String& wildCardPattern = "*") const;
|
||||
const String& wildCardPattern = "*",
|
||||
FollowSymlinks followSymlinks = FollowSymlinks::yes) const;
|
||||
|
||||
/** Searches inside a directory for files matching a wildcard pattern.
|
||||
Note that there's a newer, better version of this method which returns the results
|
||||
|
|
@ -586,7 +605,8 @@ public:
|
|||
mainly for legacy code to use.
|
||||
*/
|
||||
int findChildFiles (Array<File>& results, int whatToLookFor,
|
||||
bool searchRecursively, const String& wildCardPattern = "*") const;
|
||||
bool searchRecursively, const String& wildCardPattern = "*",
|
||||
FollowSymlinks followSymlinks = FollowSymlinks::yes) const;
|
||||
|
||||
/** Searches inside a directory and counts how many files match a wildcard pattern.
|
||||
|
||||
|
|
|
|||
|
|
@ -39,11 +39,13 @@ float DirectoryEntry::getEstimatedProgress() const
|
|||
RangedDirectoryIterator::RangedDirectoryIterator (const File& directory,
|
||||
bool isRecursive,
|
||||
const String& wildCard,
|
||||
int whatToLookFor)
|
||||
int whatToLookFor,
|
||||
File::FollowSymlinks followSymlinks)
|
||||
: iterator (new DirectoryIterator (directory,
|
||||
isRecursive,
|
||||
wildCard,
|
||||
whatToLookFor))
|
||||
whatToLookFor,
|
||||
followSymlinks))
|
||||
{
|
||||
entry.iterator = iterator;
|
||||
increment();
|
||||
|
|
|
|||
|
|
@ -118,11 +118,13 @@ public:
|
|||
separated by a semi-colon or comma, e.g. "*.jpg;*.png"
|
||||
@param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying
|
||||
whether to look for files, directories, or both.
|
||||
@param followSymlinks the policy to use when symlinks are encountered
|
||||
*/
|
||||
RangedDirectoryIterator (const File& directory,
|
||||
bool isRecursive,
|
||||
const String& wildCard = "*",
|
||||
int whatToLookFor = File::findFiles);
|
||||
int whatToLookFor = File::findFiles,
|
||||
File::FollowSymlinks followSymlinks = File::FollowSymlinks::yes);
|
||||
|
||||
/** Returns true if both iterators are in their end/sentinel state,
|
||||
otherwise returns false.
|
||||
|
|
|
|||
|
|
@ -55,13 +55,14 @@
|
|||
#include <limits>
|
||||
#include <list>
|
||||
#include <map>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <numeric>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <sstream>
|
||||
#include <typeindex>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue