Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java watch service appears to recreate deleted files. What is going on?

When a directory monitored by a WatchService gets deleted, its parent directory does not immediately reflect the deletion in its File's listFiles method and cannot be deleted. Until the entire service is explicitly stopped the consequences for the parent appear to be:

  1. The recommended recursive solution for deleting a non-empty directory failing.
  2. deleteOnExit not being carried out on normal termination
  3. Calls to delete returning false and having no effect on the filesystem.

To demonstrate, this test code:

import java.io.*;
import java.nio.file.*;

class DirectoryTester { 
  static WatchService watcher; 
  static {
    try{watcher = FileSystems.getDefault().newWatchService();} 
    catch (IOException e) {e.printStackTrace();}
  }

  public static void main(String[] args) throws IOException {
    String SEPARATE = System.getProperty("file.separator");
    String testDirName = System.getProperty("user.dir") + SEPARATE + "testDir";
    String subDirName = testDirName + SEPARATE + "subDir";
    String fileName = subDirName + SEPARATE +"aFile";
    create(fileName);
    Paths.get(subDirName).register(watcher, StandardWatchEventKinds.ENTRY_DELETE);
    delete(new File(testDirName));
  }

  static void create(String nameOfFile) throws IOException {
    new File(nameOfFile).getParentFile().mkdirs();
    Files.createFile(Paths.get(nameOfFile));
    System.out.println("Created " + nameOfFile);
  }     

  static void delete(File toDelete) throws IOException {
    if (toDelete.isDirectory())
      for (File c : toDelete.listFiles()) 
        delete(c);
    int numContainedFiles = toDelete.listFiles() != null ? toDelete.listFiles().length : 0;
    if (!toDelete.delete()) {
      System.out.println("Failed to delete " + toDelete + " containing " + numContainedFiles);
    }
    else {
      System.out.println("Deleted " + toDelete + " containing " + numContainedFiles);
    }
  }  
}

gives the following output on windows, which corresponds with testDir not being deleted on the filesystem.

Created C:\Dropbox\CodeSpace\JavaTestbed\src\testDir\subDir\aFile
Deleted C:\Dropbox\CodeSpace\JavaTestbed\src\testDir\subDir\aFile containing 0
Deleted C:\Dropbox\CodeSpace\JavaTestbed\src\testDir\subDir containing 0
Failed to delete C:\Dropbox\CodeSpace\JavaTestbed\src\testDir containing 1

If I put a breakpoint after the subDir deletion I can see that it has actually been deleted on the filesystem. Resuming from the breakpoint causes the last deletion to suceed, suggesting that this might be an issue with the visibility of changes made by the watch service thread. Does anyone know what is going on here, and if it is a bug? What I am actually trying to do is to delete directories that are monitored without stopping the monitoring on other directories, given that there does not appear to be an unregister path method provided by the API what are other standard Java ways of accomplishing this?

like image 248
MilesHampson Avatar asked Sep 07 '12 16:09

MilesHampson


People also ask

What is file watcher in Java?

public class FileSystemWatcher extends Object. Watches specific directories for file changes.

What is Java WatchService?

A watch service that watches registered objects for changes and events. For example a file manager may use a watch service to monitor a directory for changes so that it can update its display of the list of files when files are created or deleted.

What is $extend $deleted?

The “\$Extend\$Deleted” directory unlink() deletes a name from the filesystem. If that name was the last link to a file and no processes have the file open, the file is deleted and the space it was using is made available for reuse.


1 Answers

possibly related:

http://bugs.sun.com/view_bug.do?bug_id=6972833

The WatchService has an open handle to each watched directory. If a a watch directory is deleted then the WatchService closes the handle so that the directory entry can be removed from the parent directory. A problem arises for utilities and application that expect to be able to delete the parent directory immediately as it can take a few milliseconds for the watch service to get the notificationa and close the handle. If during that time that the tool attempts to delete the parent directory then it will fail. We don't have a solution to this issue at this time.

like image 165
irreputable Avatar answered Sep 20 '22 04:09

irreputable