// 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()