Handle errors from DirectoryListingFunction

SkyFunctions that call DirectoryListingFunction directly, as in the
case of RecursiveDirectoryTraversalFunction, or transitively, as in
the case of IncludeParser's call to GlobFunction, had been failing
to handle the exceptions that DirectoryListingFunction can throw.

DirectoryListingFunction can throw InconsistentFilesystemException
directly, but it can also throw IOException and
FileOutsidePackageRootsException because of its call to
DirectoryListingStateFunction without any of its own error handling.

RecursiveFilesystemTraversalFunction also calls
DirectoryListingFunction, but is not yet in use. A follow-up CL will
take care of its error handling needs.

--
MOS_MIGRATED_REVID=97828177
diff --git a/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveDirectoryTraversalFunction.java b/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveDirectoryTraversalFunction.java
index f0a9ca7..eab8d2e 100644
--- a/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveDirectoryTraversalFunction.java
+++ b/src/main/java/com/google/devtools/build/lib/skyframe/RecursiveDirectoryTraversalFunction.java
@@ -117,7 +117,7 @@
     try {
       fileValue = (FileValue) env.getValueOrThrow(fileKey, InconsistentFilesystemException.class,
           FileSymlinkCycleException.class, IOException.class);
-    } catch (InconsistentFilesystemException | FileSymlinkCycleException  | IOException e) {
+    } catch (InconsistentFilesystemException | FileSymlinkCycleException | IOException e) {
       return reportErrorAndReturn(FileValue.class.getSimpleName(), e, rootRelativePath,
           env.getListener());
     }
@@ -192,8 +192,21 @@
       //  'foo/bar' under 'rootA/workspace'.
     }
 
-    DirectoryListingValue dirValue = (DirectoryListingValue)
-        env.getValue(DirectoryListingValue.key(rootedPath));
+    DirectoryListingValue dirValue;
+    try {
+      dirValue = (DirectoryListingValue) env.getValueOrThrow(DirectoryListingValue.key(rootedPath),
+          InconsistentFilesystemException.class, IOException.class,
+          FileSymlinkCycleException.class);
+    } catch (InconsistentFilesystemException | IOException e) {
+      return reportErrorAndReturn(DirectoryListingValue.class.getSimpleName(), e, rootRelativePath,
+          env.getListener());
+    } catch (FileSymlinkCycleException e) {
+      // DirectoryListingFunction only throws FileSymlinkCycleException when FileFunction throws it,
+      // but FileFunction was evaluated for rootedPath above, and didn't throw there. It shouldn't
+      // be able to avoid throwing there but throw here.
+      throw new IllegalStateException("Symlink cycle found after not being found for \""
+          + rootedPath + "\"");
+    }
     if (dirValue == null) {
       return null;
     }