| // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | |
| // for details. All rights reserved. Use of this source code is governed by a | |
| // BSD-style license that can be found in the LICENSE file. | |
| #include "platform/globals.h" | |
| #if defined(DART_HOST_OS_WINDOWS) | |
| #include "bin/file_system_watcher.h" | |
| #include <winioctl.h> // NOLINT | |
| #include "bin/builtin.h" | |
| #include "bin/eventhandler.h" | |
| #include "bin/utils.h" | |
| #include "bin/utils_win.h" | |
| #include "platform/syslog.h" | |
| namespace dart { | |
| namespace bin { | |
| void FileSystemWatcher::InitOnce() {} | |
| void FileSystemWatcher::Cleanup() {} | |
| bool FileSystemWatcher::IsSupported() { | |
| return true; | |
| } | |
| intptr_t FileSystemWatcher::Init() { | |
| return 0; | |
| } | |
| intptr_t FileSystemWatcher::WatchPath(intptr_t id, | |
| Namespace* namespc, | |
| const char* path, | |
| int events, | |
| bool recursive) { | |
| USE(id); | |
| const auto name = Utf8ToWideChar(path); | |
| HANDLE dir = | |
| CreateFileW(name.get(), FILE_LIST_DIRECTORY, | |
| FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, | |
| nullptr, OPEN_EXISTING, | |
| FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED, nullptr); | |
| if (dir == INVALID_HANDLE_VALUE) { | |
| return -1; | |
| } | |
| int list_events = 0; | |
| if ((events & (kCreate | kMove | kDelete)) != 0) { | |
| list_events |= FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME; | |
| } | |
| if ((events & kModifyContent) != 0) { | |
| list_events |= FILE_NOTIFY_CHANGE_LAST_WRITE; | |
| } | |
| DirectoryWatchHandle* handle = | |
| new DirectoryWatchHandle(dir, list_events, recursive); | |
| handle->Start(); | |
| handle->Retain(); | |
| return reinterpret_cast<intptr_t>(handle); | |
| } | |
| void FileSystemWatcher::DestroyWatch(void* ptr) { | |
| intptr_t path_id = reinterpret_cast<intptr_t>(ptr); | |
| FileSystemWatcher::UnwatchPath(0, path_id); | |
| } | |
| void FileSystemWatcher::UnwatchPath(intptr_t id, intptr_t path_id) { | |
| USE(id); | |
| DirectoryWatchHandle* handle = | |
| reinterpret_cast<DirectoryWatchHandle*>(path_id); | |
| handle->Stop(); | |
| handle->Release(); | |
| } | |
| intptr_t FileSystemWatcher::GetSocketId(intptr_t id, intptr_t path_id) { | |
| USE(id); | |
| return path_id; | |
| } | |
| Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id, intptr_t path_id) { | |
| USE(id); | |
| const intptr_t kEventSize = sizeof(FILE_NOTIFY_INFORMATION); | |
| DirectoryWatchHandle* dir = reinterpret_cast<DirectoryWatchHandle*>(path_id); | |
| intptr_t available = dir->Available(); | |
| if (available <= 0) { | |
| return Dart_NewList(0); | |
| } | |
| intptr_t max_count = available / kEventSize + 1; | |
| Dart_Handle events = Dart_NewList(max_count); | |
| uint8_t* buffer = Dart_ScopeAllocate(available); | |
| intptr_t bytes = dir->Read(buffer, available); | |
| intptr_t offset = 0; | |
| intptr_t i = 0; | |
| while (offset < bytes) { | |
| FILE_NOTIFY_INFORMATION* e = | |
| reinterpret_cast<FILE_NOTIFY_INFORMATION*>(buffer + offset); | |
| Dart_Handle event = Dart_NewList(kEventNumElements); | |
| int mask = 0; | |
| if (e->Action == FILE_ACTION_ADDED) { | |
| mask |= kCreate; | |
| } | |
| if (e->Action == FILE_ACTION_REMOVED) { | |
| mask |= kDelete; | |
| } | |
| if (e->Action == FILE_ACTION_MODIFIED) { | |
| mask |= kModifyContent; | |
| } | |
| if (e->Action == FILE_ACTION_RENAMED_OLD_NAME) { | |
| mask |= kMove; | |
| } | |
| if (e->Action == FILE_ACTION_RENAMED_NEW_NAME) { | |
| mask |= kMove | kMovedTo; | |
| } | |
| Dart_ListSetAt(event, kEventFlagsIndex, Dart_NewInteger(mask)); | |
| // Move events come in pairs. Just 'enable' by default. | |
| Dart_ListSetAt(event, kEventCookieIndex, Dart_NewInteger(1)); | |
| Dart_ListSetAt( | |
| event, kEventPathIndex, | |
| Dart_NewStringFromUTF16(reinterpret_cast<uint16_t*>(e->FileName), | |
| e->FileNameLength / 2)); | |
| Dart_ListSetAt(event, kEventPathIdIndex, Dart_NewInteger(path_id)); | |
| Dart_ListSetAt(events, i, event); | |
| i++; | |
| if (e->NextEntryOffset == 0) { | |
| break; | |
| } | |
| offset += e->NextEntryOffset; | |
| } | |
| return events; | |
| } | |
| } // namespace bin | |
| } // namespace dart | |
| #endif // defined(DART_HOST_OS_WINDOWS) |