| 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) != 0) { |
| 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) != 0) { |
| 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) != 0) { |
| 375 if (flags & kFSEventStreamEventFlagItemRemoved) { | 385 mask |= kModefyAttribute; |
| 386 } |
| 387 if ((flags & kFSEventStreamEventFlagItemCreated) != 0) { |
| 388 mask |= kCreate; |
| 389 } |
| 390 if ((flags & kFSEventStreamEventFlagItemIsDir) != 0) { |
| 391 mask |= kIsDir; |
| 392 } |
| 393 if ((flags & kFSEventStreamEventFlagItemRemoved) != 0) { |
| 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)); |
| 385 Dart_ListSetAt(event, 2, Dart_NewStringFromUTF8( | 403 Dart_ListSetAt(event, 2, Dart_NewStringFromUTF8( |
| (...skipping 11 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 |