OLD | NEW |
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "platform/globals.h" | 5 #include "platform/globals.h" |
6 #if defined(TARGET_OS_MACOS) | 6 #if defined(TARGET_OS_MACOS) |
7 | 7 |
8 #include "bin/file_system_watcher.h" | 8 #include "bin/file_system_watcher.h" |
9 | 9 |
10 #if !TARGET_OS_IOS | 10 #if !TARGET_OS_IOS |
11 | 11 |
12 #include <errno.h> // NOLINT | 12 #include <errno.h> // NOLINT |
13 #include <fcntl.h> // NOLINT | 13 #include <fcntl.h> // NOLINT |
14 #include <unistd.h> // NOLINT | 14 #include <unistd.h> // NOLINT |
15 #include <CoreServices/CoreServices.h> // NOLINT | 15 #include <CoreServices/CoreServices.h> // NOLINT |
16 | 16 |
17 #include "bin/eventhandler.h" | 17 #include "bin/eventhandler.h" |
18 #include "bin/fdutils.h" | 18 #include "bin/fdutils.h" |
19 #include "bin/file.h" | 19 #include "bin/file.h" |
20 #include "bin/socket.h" | 20 #include "bin/socket.h" |
21 #include "bin/thread.h" | 21 #include "bin/thread.h" |
22 | |
23 #include "platform/signal_blocker.h" | 22 #include "platform/signal_blocker.h" |
24 | 23 |
25 | |
26 #ifndef MAC_OS_X_VERSION_10_7 | 24 #ifndef MAC_OS_X_VERSION_10_7 |
27 enum { | 25 enum { |
28 kFSEventStreamCreateFlagFileEvents = 0x00000010 | 26 kFSEventStreamCreateFlagFileEvents = 0x00000010 |
29 }; | 27 }; |
30 enum { | 28 enum { |
31 kFSEventStreamEventFlagItemCreated = 0x00000100, | 29 kFSEventStreamEventFlagItemCreated = 0x00000100, |
32 kFSEventStreamEventFlagItemRemoved = 0x00000200, | 30 kFSEventStreamEventFlagItemRemoved = 0x00000200, |
33 kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400, | 31 kFSEventStreamEventFlagItemInodeMetaMod = 0x00000400, |
34 kFSEventStreamEventFlagItemRenamed = 0x00000800, | 32 kFSEventStreamEventFlagItemRenamed = 0x00000800, |
35 kFSEventStreamEventFlagItemModified = 0x00001000, | 33 kFSEventStreamEventFlagItemModified = 0x00001000, |
36 kFSEventStreamEventFlagItemFinderInfoMod = 0x00002000, | 34 kFSEventStreamEventFlagItemFinderInfoMod = 0x00002000, |
37 kFSEventStreamEventFlagItemChangeOwner = 0x00004000, | 35 kFSEventStreamEventFlagItemChangeOwner = 0x00004000, |
38 kFSEventStreamEventFlagItemXattrMod = 0x00008000, | 36 kFSEventStreamEventFlagItemXattrMod = 0x00008000, |
39 kFSEventStreamEventFlagItemIsFile = 0x00010000, | 37 kFSEventStreamEventFlagItemIsFile = 0x00010000, |
40 kFSEventStreamEventFlagItemIsDir = 0x00020000, | 38 kFSEventStreamEventFlagItemIsDir = 0x00020000, |
41 kFSEventStreamEventFlagItemIsSymlink = 0x00040000 | 39 kFSEventStreamEventFlagItemIsSymlink = 0x00040000 |
42 }; | 40 }; |
43 #endif | 41 #endif |
44 | 42 |
45 | |
46 namespace dart { | 43 namespace dart { |
47 namespace bin { | 44 namespace bin { |
48 | 45 |
49 union FSEvent { | 46 union FSEvent { |
50 struct { | 47 struct { |
51 uint32_t exists; | 48 uint32_t exists; |
52 uint32_t flags; | 49 uint32_t flags; |
53 char path[PATH_MAX]; | 50 char path[PATH_MAX]; |
54 } data; | 51 } data; |
55 uint8_t bytes[PATH_MAX + 8]; | 52 uint8_t bytes[PATH_MAX + 8]; |
56 }; | 53 }; |
57 | 54 |
| 55 |
58 class FSEventsWatcher { | 56 class FSEventsWatcher { |
59 public: | 57 public: |
60 class Node { | 58 class Node { |
61 public: | 59 public: |
62 Node(FSEventsWatcher* watcher, char* base_path, int read_fd, | 60 Node(FSEventsWatcher* watcher, char* base_path, int read_fd, |
63 int write_fd, bool recursive) | 61 int write_fd, bool recursive) |
64 : watcher_(watcher), | 62 : watcher_(watcher), |
65 ready_(false), | 63 ready_(false), |
66 base_path_length_(strlen(base_path)), | 64 base_path_length_(strlen(base_path)), |
67 path_ref_(CFStringCreateWithCString( | 65 path_ref_(CFStringCreateWithCString( |
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 | 171 |
174 private: | 172 private: |
175 FSEventsWatcher* watcher_; | 173 FSEventsWatcher* watcher_; |
176 bool ready_; | 174 bool ready_; |
177 intptr_t base_path_length_; | 175 intptr_t base_path_length_; |
178 CFStringRef path_ref_; | 176 CFStringRef path_ref_; |
179 int read_fd_; | 177 int read_fd_; |
180 int write_fd_; | 178 int write_fd_; |
181 bool recursive_; | 179 bool recursive_; |
182 FSEventStreamRef ref_; | 180 FSEventStreamRef ref_; |
| 181 |
| 182 DISALLOW_COPY_AND_ASSIGN(Node); |
183 }; | 183 }; |
184 | 184 |
185 | 185 |
186 FSEventsWatcher() : run_loop_(0) { | 186 FSEventsWatcher() : run_loop_(0) { |
187 Start(); | 187 Start(); |
188 } | 188 } |
189 | 189 |
190 void Start() { | 190 void Start() { |
191 Thread::Start(Run, reinterpret_cast<uword>(this)); | 191 Thread::Start(Run, reinterpret_cast<uword>(this)); |
192 monitor_.Enter(); | 192 monitor_.Enter(); |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 void* client, | 280 void* client, |
281 size_t num_events, | 281 size_t num_events, |
282 void* event_paths, | 282 void* event_paths, |
283 const FSEventStreamEventFlags event_flags[], | 283 const FSEventStreamEventFlags event_flags[], |
284 const FSEventStreamEventId event_ids[]) { | 284 const FSEventStreamEventId event_ids[]) { |
285 Node* node = reinterpret_cast<Node*>(client); | 285 Node* node = reinterpret_cast<Node*>(client); |
286 ASSERT(Thread::Compare(node->watcher()->threadId_, | 286 ASSERT(Thread::Compare(node->watcher()->threadId_, |
287 Thread::GetCurrentThreadId())); | 287 Thread::GetCurrentThreadId())); |
288 // `ready` is set on same thread as this callback is invoked, so we don't | 288 // `ready` is set on same thread as this callback is invoked, so we don't |
289 // need to lock here. | 289 // need to lock here. |
290 if (!node->ready()) return; | 290 if (!node->ready()) { |
| 291 return; |
| 292 } |
291 for (size_t i = 0; i < num_events; i++) { | 293 for (size_t i = 0; i < num_events; i++) { |
292 char *path = reinterpret_cast<char**>(event_paths)[i]; | 294 char *path = reinterpret_cast<char**>(event_paths)[i]; |
293 FSEvent event; | 295 FSEvent event; |
294 event.data.exists = File::GetType(path, false) != File::kDoesNotExist; | 296 event.data.exists = File::GetType(path, false) != File::kDoesNotExist; |
295 path += node->base_path_length(); | 297 path += node->base_path_length(); |
296 // If path is longer the base, skip next character ('/'). | 298 // If path is longer the base, skip next character ('/'). |
297 if (path[0] != '\0') path += 1; | 299 if (path[0] != '\0') { |
298 if (!node->recursive() && strstr(path, "/") != NULL) continue; | 300 path += 1; |
| 301 } |
| 302 if (!node->recursive() && (strstr(path, "/") != NULL)) { |
| 303 continue; |
| 304 } |
299 event.data.flags = event_flags[i]; | 305 event.data.flags = event_flags[i]; |
300 memmove(event.data.path, path, strlen(path) + 1); | 306 memmove(event.data.path, path, strlen(path) + 1); |
301 write(node->write_fd(), event.bytes, sizeof(event)); | 307 write(node->write_fd(), event.bytes, sizeof(event)); |
302 } | 308 } |
303 } | 309 } |
304 | 310 |
305 Monitor monitor_; | 311 Monitor monitor_; |
306 CFRunLoopRef run_loop_; | 312 CFRunLoopRef run_loop_; |
307 ThreadId threadId_; | 313 ThreadId threadId_; |
| 314 |
| 315 DISALLOW_COPY_AND_ASSIGN(FSEventsWatcher); |
308 }; | 316 }; |
309 | 317 |
310 | 318 |
311 #define kCFCoreFoundationVersionNumber10_7 635.00 | 319 #define kCFCoreFoundationVersionNumber10_7 635.00 |
312 bool FileSystemWatcher::IsSupported() { | 320 bool FileSystemWatcher::IsSupported() { |
313 return kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber10_7; | 321 return kCFCoreFoundationVersionNumber >= kCFCoreFoundationVersionNumber10_7; |
314 } | 322 } |
315 | 323 |
316 | 324 |
317 intptr_t FileSystemWatcher::Init() { | 325 intptr_t FileSystemWatcher::Init() { |
(...skipping 23 matching lines...) Expand all Loading... |
341 | 349 |
342 intptr_t FileSystemWatcher::GetSocketId(intptr_t id, intptr_t path_id) { | 350 intptr_t FileSystemWatcher::GetSocketId(intptr_t id, intptr_t path_id) { |
343 return reinterpret_cast<FSEventsWatcher::Node*>(path_id)->read_fd(); | 351 return reinterpret_cast<FSEventsWatcher::Node*>(path_id)->read_fd(); |
344 } | 352 } |
345 | 353 |
346 | 354 |
347 Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id, intptr_t path_id) { | 355 Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id, intptr_t path_id) { |
348 intptr_t fd = GetSocketId(id, path_id); | 356 intptr_t fd = GetSocketId(id, path_id); |
349 intptr_t avail = FDUtils::AvailableBytes(fd); | 357 intptr_t avail = FDUtils::AvailableBytes(fd); |
350 int count = avail / sizeof(FSEvent); | 358 int count = avail / sizeof(FSEvent); |
351 if (count <= 0) return Dart_NewList(0); | 359 if (count <= 0) { |
| 360 return Dart_NewList(0); |
| 361 } |
352 Dart_Handle events = Dart_NewList(count); | 362 Dart_Handle events = Dart_NewList(count); |
353 FSEvent e; | 363 FSEvent e; |
354 for (int i = 0; i < count; i++) { | 364 for (int i = 0; i < count; i++) { |
355 intptr_t bytes = TEMP_FAILURE_RETRY(read(fd, e.bytes, sizeof(e))); | 365 intptr_t bytes = TEMP_FAILURE_RETRY(read(fd, e.bytes, sizeof(e))); |
356 if (bytes < 0) { | 366 if (bytes < 0) { |
357 return DartUtils::NewDartOSError(); | 367 return DartUtils::NewDartOSError(); |
358 } | 368 } |
359 size_t path_len = strlen(e.data.path); | 369 size_t path_len = strlen(e.data.path); |
360 Dart_Handle event = Dart_NewList(5); | 370 Dart_Handle event = Dart_NewList(5); |
361 int flags = e.data.flags; | 371 int flags = e.data.flags; |
362 int mask = 0; | 372 int mask = 0; |
363 if (flags & kFSEventStreamEventFlagItemRenamed) { | 373 if (flags & kFSEventStreamEventFlagItemRenamed) { |
364 if (path_len == 0) { | 374 if (path_len == 0) { |
365 // The moved path is the path being watched. | 375 // The moved path is the path being watched. |
366 mask |= kDeleteSelf; | 376 mask |= kDeleteSelf; |
367 } else { | 377 } else { |
368 mask |= e.data.exists ? kCreate : kDelete; | 378 mask |= e.data.exists ? kCreate : kDelete; |
369 } | 379 } |
370 } | 380 } |
371 if (flags & kFSEventStreamEventFlagItemModified) mask |= kModifyContent; | 381 if (flags & kFSEventStreamEventFlagItemModified) { |
372 if (flags & kFSEventStreamEventFlagItemXattrMod) mask |= kModefyAttribute; | 382 mask |= kModifyContent; |
373 if (flags & kFSEventStreamEventFlagItemCreated) mask |= kCreate; | 383 } |
374 if (flags & kFSEventStreamEventFlagItemIsDir) mask |= kIsDir; | 384 if (flags & kFSEventStreamEventFlagItemXattrMod) { |
| 385 mask |= kModefyAttribute; |
| 386 } |
| 387 if (flags & kFSEventStreamEventFlagItemCreated) { |
| 388 mask |= kCreate; |
| 389 } |
| 390 if (flags & kFSEventStreamEventFlagItemIsDir) { |
| 391 mask |= kIsDir; |
| 392 } |
375 if (flags & kFSEventStreamEventFlagItemRemoved) { | 393 if (flags & kFSEventStreamEventFlagItemRemoved) { |
376 if (path_len == 0) { | 394 if (path_len == 0) { |
377 // The removed path is the path being watched. | 395 // The removed path is the path being watched. |
378 mask |= kDeleteSelf; | 396 mask |= kDeleteSelf; |
379 } else { | 397 } else { |
380 mask |= kDelete; | 398 mask |= kDelete; |
381 } | 399 } |
382 } | 400 } |
383 Dart_ListSetAt(event, 0, Dart_NewInteger(mask)); | 401 Dart_ListSetAt(event, 0, Dart_NewInteger(mask)); |
384 Dart_ListSetAt(event, 1, Dart_NewInteger(1)); | 402 Dart_ListSetAt(event, 1, Dart_NewInteger(1)); |
(...skipping 12 matching lines...) Expand all Loading... |
397 #else // !TARGET_OS_IOS | 415 #else // !TARGET_OS_IOS |
398 | 416 |
399 namespace dart { | 417 namespace dart { |
400 namespace bin { | 418 namespace bin { |
401 | 419 |
402 // FSEvents are unavailable on iOS. Stub out related methods | 420 // FSEvents are unavailable on iOS. Stub out related methods |
403 Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id, intptr_t path_id) { | 421 Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id, intptr_t path_id) { |
404 return DartUtils::NewDartOSError(); | 422 return DartUtils::NewDartOSError(); |
405 } | 423 } |
406 | 424 |
| 425 |
407 intptr_t FileSystemWatcher::GetSocketId(intptr_t id, intptr_t path_id) { | 426 intptr_t FileSystemWatcher::GetSocketId(intptr_t id, intptr_t path_id) { |
408 return -1; | 427 return -1; |
409 } | 428 } |
410 | 429 |
| 430 |
411 bool FileSystemWatcher::IsSupported() { | 431 bool FileSystemWatcher::IsSupported() { |
412 return false; | 432 return false; |
413 } | 433 } |
414 | 434 |
| 435 |
415 void FileSystemWatcher::UnwatchPath(intptr_t id, intptr_t path_id) { | 436 void FileSystemWatcher::UnwatchPath(intptr_t id, intptr_t path_id) { |
416 } | 437 } |
417 | 438 |
| 439 |
418 intptr_t FileSystemWatcher::Init() { | 440 intptr_t FileSystemWatcher::Init() { |
419 return -1; | 441 return -1; |
420 } | 442 } |
421 | 443 |
| 444 |
422 void FileSystemWatcher::Close(intptr_t id) { | 445 void FileSystemWatcher::Close(intptr_t id) { |
423 } | 446 } |
424 | 447 |
| 448 |
425 intptr_t FileSystemWatcher::WatchPath(intptr_t id, | 449 intptr_t FileSystemWatcher::WatchPath(intptr_t id, |
426 const char* path, | 450 const char* path, |
427 int events, | 451 int events, |
428 bool recursive) { | 452 bool recursive) { |
429 return -1; | 453 return -1; |
430 } | 454 } |
431 | 455 |
432 } // namespace bin | 456 } // namespace bin |
433 } // namespace dart | 457 } // namespace dart |
434 | 458 |
435 #endif // !TARGET_OS_IOS | 459 #endif // !TARGET_OS_IOS |
436 | |
437 #endif // defined(TARGET_OS_MACOS) | 460 #endif // defined(TARGET_OS_MACOS) |
OLD | NEW |