// Reset(): /// <summary>Sets the enumerator back to an initial state, where MoveNext() will move to the very first item.</summary> public void Reset() { IsReset = true; Current = null; CurrentLevelSearchData = null; SearchStack.Clear(); } // end Reset()
} // end Reset() // MoveNext(): /// <summary>Moves the iterator to the next item.</summary> /// <returns> /// A <c>bool</c> indicating whether there was, in fact, a next item. /// Upon success, <c>Current</c> will contain the next item. /// If the return value is <c>false</c>, there was no next item and <c>Current</c> will be <c>null</c>. /// Calling this method repeatedly after passing the end of the iteration will have no effect (it will just keep returning <c>false</c>). /// </returns> public bool MoveNext() { bool returnValue = true; // Set up the return value to default to true. if (IsReset) { // IsReset was true, so we are about to move to the very first item. IsReset = false; // We aren't going to be reset anymore after this. // The very first item is the base item itself. // Set the current item to an object corresponding to that, but in the process // we also need to look up the path containing that item, and get enumerators for the files and subdirectories inside the base item, if any. IEnumerator <FileInfo> files; IEnumerator <DirectoryInfo> subDirectories; (Current, BaseContainerPath) = getBaseItem(out files, out subDirectories); if (Current.Type == BackupItemInfo.ItemType.Directory) { // The base item is a readable directory, so set the current search level to that directory and set the still-iterating state to true. CurrentLevelSearchData = new FileSystemWalkLevel(Current.RelativePath, files, subDirectories, true); IsStillIterating = true; } else { IsStillIterating = false; // Base item is a file. There is nothing further to enumerate. } } else if (IsStillIterating) { // IsReset was false, but IsStillIterating was true. So we are in the middle of an enumeration. // Iterate over the files and subdirectories, checking each against the inclusion / exclusion rules, // until we 1) find an included item to return, at which point we set the current item to that and break from the loop; // or 2) run out of things to iterate through and IsStillIterating becomes false. while (IsStillIterating) { // We will enumerate through the files in this directory first, then subdirectories. if (CurrentLevelSearchData.Files.MoveNext()) { // There is still at least one unexamined file in this directory. // Having moved to the next file, get its path and check it against the rules. FileInfo file = CurrentLevelSearchData.Files.Current; string relativePath = Path.Combine(CurrentLevelSearchData.RelativePath, file.Name); RuleSet.AllowanceType itemAllowance = Rules.checkPath(relativePath, CurrentLevelSearchData.ThisItemAllowedByRules); // CHANGE CODE HERE: handle exceptions if (itemAllowance == RuleSet.AllowanceType.Allowed) { // The file is included according to the rules, so set the current iterator item to point to it, and break from the loop to exit the function. Current = new BackupItemInfo(BackupItemInfo.ItemType.File, BaseContainerPath, relativePath); // CHANGE CODE HERE: Handle exceptions thrown by BackupItemInfo constructor break; } else { continue; // This file is not included according to the rules. Loop back and look at the next one. } } else if (CurrentLevelSearchData.SubDirectories.MoveNext()) { // There is still at least one unexamined subdirectory in this directory. // Having moved to the next subdirectory, get a DirectoryInfo object corresponding to it, // and determine its path relative to the base path. DirectoryInfo nextLevelDirectory = CurrentLevelSearchData.SubDirectories.Current; string nextLevelRelativePath = Path.Combine(CurrentLevelSearchData.RelativePath, nextLevelDirectory.Name); // Try reading the subdirectory, and get enumerators for iterating the files and subdirectories within it. IEnumerator <FileInfo> nextLevelFiles; IEnumerator <DirectoryInfo> nextLevelSubDirectories; bool ableToReadSubDirectory = tryOpeningDirectory(nextLevelDirectory, out nextLevelFiles, out nextLevelSubDirectories); // Check the path of the subdirectory against the inclusion / exclusion rules. RuleSet.AllowanceType subDirectoryAllowance = Rules.checkPath(nextLevelRelativePath, CurrentLevelSearchData.ThisItemAllowedByRules); // // CHANGE CODE HERE: handle exceptions bool subDirectoryAllowedByRules = (subDirectoryAllowance == RuleSet.AllowanceType.Allowed); // If we are able to read the subdirectory, we will traverse it, too, in our enumeration, // UNLESS the rules say it is an entire tree that is to be excluded (which is different from disallowing // just that subdirectory itself but potentially allowing things within it). // Push the current directory onto the stack of those currently being searched, so we come back to it, // and make the subdirectory the one to look at the next time through the loop. if (ableToReadSubDirectory && subDirectoryAllowance != RuleSet.AllowanceType.TreeDisallowed) { SearchStack.Push(CurrentLevelSearchData); CurrentLevelSearchData = new FileSystemWalkLevel(nextLevelRelativePath, nextLevelFiles, nextLevelSubDirectories, subDirectoryAllowedByRules); } // If the subdirectory is allowed by the rules, set it as the current item of this enumerator, and break from the loop to exit the function. if (subDirectoryAllowedByRules) { // CHANGE CODE HERE: Handle exceptions thrown by BackupItemInfo constructor Current = new BackupItemInfo( ableToReadSubDirectory ? BackupItemInfo.ItemType.Directory : BackupItemInfo.ItemType.UnreadableDirectory, BaseContainerPath, nextLevelRelativePath); break; } else { continue; // This subdirectory isn't included according to the rules. Loop back and look at the next one. } } else { // No more files or subdirectories at this level. Pop up to the next level. if (!SearchStack.TryPop(out CurrentLevelSearchData)) { // We're all the way to the top level. We've reached the end. Current = null; returnValue = false; IsStillIterating = false; } } } // end while (isStillIterating) } else { returnValue = false; // Not reset or still iterating, so we've already moved past the end. Return false. } return(returnValue); } // end MoveNext()