Skip to content

Commit 593d139

Browse files
committed
Updated the FileSystemWatcher in the Directory class to watch symlinked folders on Windows
1 parent 717400c commit 593d139

1 file changed

Lines changed: 96 additions & 33 deletions

File tree

src/javaxt/io/Directory.java

Lines changed: 96 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -2935,43 +2935,23 @@ public FileSystemWatcher(Directory directory) throws IOException {
29352935
public final void run(){
29362936

29372937
if (File.loadDLL()){
2938-
try {
2939-
long osWaitHandle = FileSystemWatcherNative.FindFirstChangeNotification(directory.getPath(), includeSubdirectories, -1);
2940-
this.osHandle = new Long(osWaitHandle);
2941-
2942-
FileSystemWatcherNative.FindNextChangeNotification(osWaitHandle);
29432938

2944-
//Process events. Note that the ReadDirectoryChangesW method will
2945-
//block until the next event comes in.
2946-
String event = null;
2947-
while(!terminationRequested && ( event = FileSystemWatcherNative.ReadDirectoryChangesW()) != null){
2948-
for (String e : event.split("\n")) addEvent(e.trim());
2949-
}
29502939

2951-
//I have no idea what this block of code does. Probably safe to delete.
2952-
if (FileSystemWatcherNative.WaitForSingleObject(osWaitHandle,
2953-
FileSystemWatcherNative.INFINITE) != FileSystemWatcherNative.WAIT_OBJECT_0) {
2954-
throw new Exception("Wait failed while waiting for OS to signal file system event.");
2955-
}
2940+
//Generate list of folders to watch. The FileSystemWatcherNative DLL
2941+
//skips events generated within junctions (symlinked folders). As a
2942+
//workaround, we have to create FileWatchers for individual junctions.
2943+
HashSet<Directory> watchFolders = new HashSet<>();
2944+
watchFolders.add(directory);
2945+
for (Directory link : getLinks(directory)){
2946+
watchFolders.add(link);
29562947
}
2957-
catch (Exception ex) {
2958-
//nothing can be done here except logging the error.
2959-
//Logger.getLogger("FileSystemWatcher").log(Level.WARNING, "Exception encountered.", ex);
2960-
}
2961-
finally {
2962-
if (this.osHandle != null) {
2963-
System.out.println("Shutting down...");
2964-
try {
2965-
FileSystemWatcherNative.FindCloseChangeNotification(this.osHandle.longValue());
2966-
}
2967-
catch (Exception ex2) {
2968-
//nothing can be done here except logging the error.
2969-
//Logger.getLogger("FileSystemWatcher").log(Level.WARNING,
2970-
//"Unable to close file system watch handle.", ex2);
2971-
}
2972-
this.osHandle = null;
2973-
}
2948+
2949+
2950+
//Start streaming events for each watch folder
2951+
for (Directory dir: watchFolders){
2952+
initFileSystemWatcherDLL(dir);
29742953
}
2954+
29752955
}
29762956
else{
29772957
if (javaxt.utils.Java.version>6 && !isWindows && !isMac){
@@ -3001,6 +2981,89 @@ public final void run(){
30012981
}
30022982

30032983

2984+
//**************************************************************************
2985+
//** getLinks
2986+
//**************************************************************************
2987+
/** Used to find symlinks in a given directory
2988+
*/
2989+
private HashSet<Directory> getLinks(Directory directory){
2990+
HashSet<Directory> links = new HashSet<>();
2991+
java.util.List files = directory.getChildren(true, null, false);
2992+
Object obj;
2993+
while (true){
2994+
synchronized (files) {
2995+
while (files.isEmpty()) {
2996+
try {
2997+
files.wait();
2998+
}
2999+
catch (InterruptedException e) {
3000+
break;
3001+
}
3002+
}
3003+
obj = files.remove(0);
3004+
files.notifyAll();
3005+
}
3006+
3007+
if (obj==null){
3008+
break;
3009+
}
3010+
else{
3011+
if (obj instanceof Directory){
3012+
Directory dir = (Directory) obj;
3013+
if (dir.isLink()) links.add(dir);
3014+
}
3015+
}
3016+
}
3017+
return links;
3018+
}
3019+
3020+
3021+
//**************************************************************************
3022+
//** initFileSystemWatcherDLL
3023+
//**************************************************************************
3024+
/** Used to instantiate FileSystemWatcherNative (Windows DLL)
3025+
*/
3026+
private void initFileSystemWatcherDLL(Directory dir){
3027+
try {
3028+
long osWaitHandle = FileSystemWatcherNative.FindFirstChangeNotification(dir.getPath(), includeSubdirectories, -1);
3029+
this.osHandle = new Long(osWaitHandle);
3030+
3031+
FileSystemWatcherNative.FindNextChangeNotification(osWaitHandle);
3032+
3033+
//Process events. Note that the ReadDirectoryChangesW method will
3034+
//block until the next event comes in.
3035+
String event = null;
3036+
while(!terminationRequested && ( event = FileSystemWatcherNative.ReadDirectoryChangesW()) != null){
3037+
for (String e : event.split("\n")) addEvent(e.trim());
3038+
}
3039+
3040+
//I have no idea what this block of code does. Probably safe to delete.
3041+
if (FileSystemWatcherNative.WaitForSingleObject(osWaitHandle,
3042+
FileSystemWatcherNative.INFINITE) != FileSystemWatcherNative.WAIT_OBJECT_0) {
3043+
throw new Exception("Wait failed while waiting for OS to signal file system event.");
3044+
}
3045+
}
3046+
catch (Exception ex) {
3047+
//nothing can be done here except logging the error.
3048+
//Logger.getLogger("FileSystemWatcher").log(Level.WARNING, "Exception encountered.", ex);
3049+
}
3050+
finally {
3051+
if (this.osHandle != null) {
3052+
System.out.println("Shutting down...");
3053+
try {
3054+
FileSystemWatcherNative.FindCloseChangeNotification(this.osHandle.longValue());
3055+
}
3056+
catch (Exception ex2) {
3057+
//nothing can be done here except logging the error.
3058+
//Logger.getLogger("FileSystemWatcher").log(Level.WARNING,
3059+
//"Unable to close file system watch handle.", ex2);
3060+
}
3061+
this.osHandle = null;
3062+
}
3063+
}
3064+
}
3065+
3066+
30043067
//**************************************************************************
30053068
//** startPolling
30063069
//**************************************************************************

0 commit comments

Comments
 (0)