28
28
29
29
import static engineering .swat .watch .impl .mac .apis .FileSystemEvents .FSEventStreamCreateFlag .FILE_EVENTS ;
30
30
import static engineering .swat .watch .impl .mac .apis .FileSystemEvents .FSEventStreamCreateFlag .NO_DEFER ;
31
+ import static engineering .swat .watch .impl .mac .apis .FileSystemEvents .FSEventStreamCreateFlag .USE_CF_TYPES ;
32
+ import static engineering .swat .watch .impl .mac .apis .FileSystemEvents .FSEventStreamCreateFlag .USE_EXTENDED_DATA ;
31
33
import static engineering .swat .watch .impl .mac .apis .FileSystemEvents .FSEventStreamCreateFlag .WATCH_ROOT ;
32
34
import static org .awaitility .Awaitility .await ;
33
35
52
54
import com .sun .jna .Pointer ;
53
55
import com .sun .jna .platform .mac .CoreFoundation ;
54
56
import com .sun .jna .platform .mac .CoreFoundation .CFArrayRef ;
57
+ import com .sun .jna .platform .mac .CoreFoundation .CFDictionaryRef ;
55
58
import com .sun .jna .platform .mac .CoreFoundation .CFIndex ;
59
+ import com .sun .jna .platform .mac .CoreFoundation .CFNumberRef ;
56
60
import com .sun .jna .platform .mac .CoreFoundation .CFStringRef ;
57
61
58
62
import engineering .swat .watch .TestDirectory ;
@@ -78,13 +82,13 @@ void smokeTest() throws IOException {
78
82
var paths = ConcurrentHashMap .<String > newKeySet ();
79
83
80
84
var s = test .getTestDirectory ().toString ();
81
- var handler = (MinimalWorkingExample .EventHandler ) (path , flags , id ) -> {
85
+ var handler = (MinimalWorkingExample .EventHandler ) (path , inode , flags , id ) -> {
82
86
synchronized (ready ) {
83
87
while (!ready .get ()) {
84
88
try {
85
89
ready .wait ();
86
90
} catch (InterruptedException e ) {
87
- LOGGER .error ("Unexpected interrupt. Test likely to fail. Event ignored ({})." , prettyPrint (path , flags , id ));
91
+ LOGGER .error ("Unexpected interrupt. Test likely to fail. Event ignored ({})." , prettyPrint (path , inode , flags , id ));
88
92
Thread .currentThread ().interrupt ();
89
93
return ;
90
94
}
@@ -93,7 +97,7 @@ void smokeTest() throws IOException {
93
97
paths .remove (path );
94
98
};
95
99
96
- try (var mwe = new MinimalWorkingExample (s , handler )) {
100
+ try (var mwe = new MinimalWorkingExample (s , handler , true )) {
97
101
var dir = test .getTestDirectory ().toRealPath ();
98
102
paths .add (Files .writeString (dir .resolve ("a.txt" ), "foo" ).toString ());
99
103
paths .add (Files .writeString (dir .resolve ("b.txt" ), "bar" ).toString ());
@@ -111,33 +115,34 @@ void smokeTest() throws IOException {
111
115
112
116
public static void main (String [] args ) throws IOException {
113
117
var s = args [0 ];
114
- var handler = (MinimalWorkingExample .EventHandler ) (path , flags , id ) -> {
115
- LOGGER .info (prettyPrint (path , flags , id ));
118
+ var handler = (MinimalWorkingExample .EventHandler ) (path , inode , flags , id ) -> {
119
+ LOGGER .info (prettyPrint (path , inode , flags , id ));
116
120
};
121
+ var useExtendedData = args .length >= 2 && Boolean .parseBoolean (args [1 ]);
117
122
118
- try (var mwe = new MinimalWorkingExample (s , handler )) {
123
+ try (var mwe = new MinimalWorkingExample (s , handler , useExtendedData )) {
119
124
// Block the program from terminating until `ENTER` is pressed
120
125
new BufferedReader (new InputStreamReader (System .in )).readLine ();
121
126
}
122
127
}
123
128
124
- private static String prettyPrint (String path , int flags , long id ) {
129
+ private static String prettyPrint (String path , long inode , int flags , long id ) {
125
130
var flagsPrettyPrinted = Stream
126
131
.of (FSEventStreamEventFlag .values ())
127
132
.filter (f -> (f .mask & flags ) == f .mask )
128
133
.map (Object ::toString )
129
134
.collect (Collectors .joining (", " ));
130
135
131
- var format = "path: \" %s\" , flags: [%s], id: %s" ;
132
- return String .format (format , path , flagsPrettyPrinted , id );
136
+ var format = "path: \" %s\" , inode: %s, flags: [%s], id: %s" ;
137
+ return String .format (format , path , inode , flagsPrettyPrinted , id );
133
138
}
134
139
135
140
private static class MinimalWorkingExample implements Closeable {
136
141
private FileSystemEvents .FSEventStreamCallback callback ;
137
142
private Pointer stream ;
138
143
private Pointer queue ;
139
144
140
- public MinimalWorkingExample (String s , EventHandler handler ) {
145
+ public MinimalWorkingExample (String s , EventHandler handler , boolean useExtendedData ) {
141
146
142
147
// Allocate singleton array of paths
143
148
CFStringRef pathToWatch = CFStringRef .createCFString (s );
@@ -154,11 +159,24 @@ public MinimalWorkingExample(String s, EventHandler handler) {
154
159
155
160
// Allocate callback
156
161
this .callback = (x1 , x2 , x3 , x4 , x5 , x6 ) -> {
157
- var paths = x4 .getStringArray (0 , (int ) x3 );
158
- var flags = x5 .getIntArray (0 , (int ) x3 );
159
- var ids = x6 .getLongArray (0 , (int ) x3 );
162
+ var paths = x4 .getStringArray (0 , (int ) x3 );
163
+ var inodes = new long [(int ) x3 ];
164
+ var flags = x5 .getIntArray (0 , (int ) x3 );
165
+ var ids = x6 .getLongArray (0 , (int ) x3 );
166
+
167
+ if (useExtendedData ) {
168
+ var extendedData = new CFArrayRef (x4 );
169
+ for (int i = 0 ; i < x3 ; i ++) {
170
+ var dictionary = new CFDictionaryRef (extendedData .getValueAtIndex (i ));
171
+ var dictionaryPath = dictionary .getValue (FileSystemEvents .kFSEventStreamEventExtendedDataPathKey );
172
+ var dictionaryInode = dictionary .getValue (FileSystemEvents .kFSEventStreamEventExtendedFileIDKey );
173
+ paths [i ] = dictionaryPath == null ? null : new CFStringRef (dictionaryPath ).stringValue ();
174
+ inodes [i ] = dictionaryInode == null ? 0 : new CFNumberRef (dictionaryInode ).longValue ();
175
+ }
176
+ }
177
+
160
178
for (int i = 0 ; i < x3 ; i ++) {
161
- handler .handle (paths [i ], flags [i ], ids [i ]);
179
+ handler .handle (paths [i ], inodes [ i ], flags [i ], ids [i ]);
162
180
}
163
181
};
164
182
@@ -170,7 +188,8 @@ public MinimalWorkingExample(String s, EventHandler handler) {
170
188
pathsToWatch ,
171
189
FSE .FSEventsGetCurrentEventId (),
172
190
0.15 ,
173
- NO_DEFER .mask | WATCH_ROOT .mask | FILE_EVENTS .mask );
191
+ NO_DEFER .mask | WATCH_ROOT .mask | FILE_EVENTS .mask |
192
+ (useExtendedData ? USE_EXTENDED_DATA .mask | USE_CF_TYPES .mask : 0 ));
174
193
175
194
// Deallocate array of paths
176
195
pathsToWatch .release ();
@@ -203,7 +222,7 @@ public void close() throws IOException {
203
222
204
223
@ FunctionalInterface
205
224
private static interface EventHandler {
206
- void handle (String path , int flags , long id );
225
+ void handle (String path , long inode , int flags , long id );
207
226
}
208
227
}
209
228
}
0 commit comments