Merge branch 'master' of https://code.google.com/p/plexi.fs
diff --git a/src/com/google/enterprise/adaptor/fs/FsAdaptor.java b/src/com/google/enterprise/adaptor/fs/FsAdaptor.java
index 977f924..faa36f5 100644
--- a/src/com/google/enterprise/adaptor/fs/FsAdaptor.java
+++ b/src/com/google/enterprise/adaptor/fs/FsAdaptor.java
@@ -34,12 +34,14 @@
 import com.google.enterprise.adaptor.Response;
 import com.google.enterprise.adaptor.StartupException;
 
+import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStreamWriter;
 import java.io.Writer;
 import java.nio.charset.Charset;
 import java.nio.file.AccessDeniedException;
+import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.attribute.AclFileAttributeView;
 import java.nio.file.attribute.BasicFileAttributes;
@@ -454,14 +456,6 @@
     DocId id = req.getDocId();
     Path doc = delegate.getPath(id.getUniqueId());
 
-    if (!isSupportedPath(doc)) {
-      log.log(Level.WARNING, "The path {0} is not a supported file type.", doc);
-      resp.respondNotFound();
-      return;
-    }
-
-    final boolean docIsDirectory = delegate.isDirectory(doc);
-
     if (!id.equals(delegate.newDocId(doc))) {
       log.log(Level.WARNING,
           "The {0} is not a valid id generated by the adaptor.", id);
@@ -475,18 +469,38 @@
     }
 
     // Populate the document metadata.
-    BasicFileAttributes attrs = delegate.readBasicAttributes(doc);
+    BasicFileAttributes attrs;
+    try {
+      attrs = delegate.readBasicAttributes(doc);
+    } catch (FileNotFoundException e) {
+      log.log(Level.INFO, "Not found: {0}", doc);
+      resp.respondNotFound();
+      return;
+    } catch (NoSuchFileException e) {
+      log.log(Level.INFO, "Not found: {0}", doc);
+      resp.respondNotFound();
+      return;
+    }      
+
+    if (!isFileOrFolder(doc)) {
+      log.log(Level.INFO, "The path {0} is not a regular file or directory.",
+              doc);
+      resp.respondNotFound();
+      return;
+    }
+
+    final boolean docIsDirectory = attrs.isDirectory();
     final FileTime lastAccessTime = attrs.lastAccessTime();
 
     if (!docIsDirectory) {
       if (lastAccessTimeFilter.excluded(lastAccessTime)) {
-        log.log(Level.WARNING, "Skipping {0} because it was last accessed {1}.",
+        log.log(Level.FINE, "Skipping {0} because it was last accessed {1}.",
             new Object[] {doc, lastAccessTime.toString().substring(0, 10)});
         resp.respondNotFound();
         return;
       }
       if (lastModifiedTimeFilter.excluded(attrs.lastModifiedTime())) {
-        log.log(Level.WARNING, "Skipping {0} because it was last modified {1}.",
+        log.log(Level.FINE, "Skipping {0} because it was last modified {1}.",
             new Object[] {doc, 
                 attrs.lastModifiedTime().toString().substring(0, 10)});
         resp.respondNotFound();
@@ -587,7 +601,7 @@
       HtmlResponseWriter writer = createHtmlResponseWriter(resp);
       writer.start(id, getFileName(doc));
       for (Path file : delegate.newDirectoryStream(doc)) {
-        if (isSupportedPath(file)) {
+        if (isFileOrFolder(file)) {
           writer.addLink(delegate.newDocId(file), getFileName(file));
         }
       }
@@ -631,8 +645,12 @@
     return name.isEmpty() ? file.getRoot().toString() : name;
   }
 
+  /**
+   * Returns true if the path is a regular file or a folder;
+   * false if the path is a link, a special file, or doesn't exist.
+   */
   @VisibleForTesting
-  boolean isSupportedPath(Path p) throws IOException {
+  boolean isFileOrFolder(Path p) throws IOException {
     return delegate.isRegularFile(p) || delegate.isDirectory(p);
   }
 
diff --git a/test/com/google/enterprise/adaptor/fs/FsAdaptorTest.java b/test/com/google/enterprise/adaptor/fs/FsAdaptorTest.java
index c756af8..6a5b25f 100644
--- a/test/com/google/enterprise/adaptor/fs/FsAdaptorTest.java
+++ b/test/com/google/enterprise/adaptor/fs/FsAdaptorTest.java
@@ -202,13 +202,13 @@
   }
 
   @Test
-  public void testIsSupportedPath() throws Exception {
+  public void testIsFileOrFolder() throws Exception {
     root.addChildren(new MockFile("foo"), new MockFile("bar", true),
                      new MockFile("link").setIsRegularFile(false));
-    assertTrue(adaptor.isSupportedPath(rootPath));
-    assertTrue(adaptor.isSupportedPath(getPath("foo")));
-    assertTrue(adaptor.isSupportedPath(getPath("bar")));
-    assertFalse(adaptor.isSupportedPath(getPath("link")));
+    assertTrue(adaptor.isFileOrFolder(rootPath));
+    assertTrue(adaptor.isFileOrFolder(getPath("foo")));
+    assertTrue(adaptor.isFileOrFolder(getPath("bar")));
+    assertFalse(adaptor.isFileOrFolder(getPath("link")));
   }
 
   @Test
@@ -321,13 +321,6 @@
     assertTrue(response.notFound);
   }
 
-  /*
-   * This test was invalidated when the check for isSupportedPath()
-   * was moved above the check for bad DocIds in the beginning of
-   * FsAdaptor.getDocumentContent().  This test still passes, but
-   * the notFound response is coming from the earlier check for
-   * isSupportedPath(), not from the bad DocId.
-   */
   @Test
   public void testGetDocContentBadDocId() throws Exception {
     root.addChildren(new MockFile("badfile"));
@@ -339,6 +332,15 @@
   }
 
   @Test
+  public void testGetDocContentFileNotFound() throws Exception {
+    adaptor.init(context);
+    MockResponse response = new MockResponse();
+    // The requested DocId is missing the root component of the path.
+    adaptor.getDocContent(new MockRequest(getDocId("non-existent")), response);
+    assertTrue(response.notFound);
+  }
+
+  @Test
   public void testGetDocContentHiddenFile() throws Exception {
     root.addChildren(new MockFile("hidden.txt").setIsHidden(true));
     adaptor.init(context);
diff --git a/test/com/google/enterprise/adaptor/fs/NioFileDelegateTest.java b/test/com/google/enterprise/adaptor/fs/NioFileDelegateTest.java
index 761fdd9..ee79e96 100644
--- a/test/com/google/enterprise/adaptor/fs/NioFileDelegateTest.java
+++ b/test/com/google/enterprise/adaptor/fs/NioFileDelegateTest.java
@@ -30,6 +30,7 @@
 import java.io.InputStreamReader;
 import java.nio.file.DirectoryStream;
 import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
 import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.attribute.AclFileAttributeView;
@@ -43,6 +44,9 @@
   private FileDelegate delegate = new TestNioFileDelegate();
 
   @Rule
+  public ExpectedException thrown = ExpectedException.none();
+
+  @Rule
   public TemporaryFolder temp = new TemporaryFolder();
 
   private Path newTempDir(String name) throws IOException {
@@ -131,6 +135,13 @@
   }
 
   @Test
+  public void testReadBasicAttributesFileNotFound() throws Exception {
+    Path file = Paths.get(temp.getRoot().toString(), "notFound");
+    thrown.expect(NoSuchFileException.class);
+    BasicFileAttributes attrs = delegate.readBasicAttributes(file);
+  }
+
+  @Test
   public void testProbeContentType() throws Exception {
     TestHelper.assumeOsIsNotMac();
     String content = "<html><title>Foo</title><body>Bar</body></html>";