blob: f0b71f1c3225fea4a94c716eb116884cd46ff477 [file] [log] [blame]
// 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(TARGET_OS_WINDOWS)
#include "bin/file_system_watcher.h"
#include "bin/eventhandler.h"
#include <WinIoCtl.h> // NOLINT
#include "bin/builtin.h"
#include "bin/log.h"
#include "bin/utils.h"
namespace dart {
namespace bin {
bool FileSystemWatcher::IsSupported() {
return true;
}
intptr_t FileSystemWatcher::Init() {
return 0;
}
void FileSystemWatcher::Close(intptr_t id) {
USE(id);
}
intptr_t FileSystemWatcher::WatchPath(intptr_t id,
const char* path,
int events,
bool recursive) {
USE(id);
const wchar_t* name = StringUtils::Utf8ToWide(path);
HANDLE dir = CreateFileW(name,
FILE_LIST_DIRECTORY,
FILE_SHARE_READ |
FILE_SHARE_WRITE |
FILE_SHARE_DELETE,
NULL,
OPEN_EXISTING,
FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
NULL);
free(const_cast<wchar_t*>(name));
if (dir == INVALID_HANDLE_VALUE) {
return -1;
}
int list_events = 0;
if (events & (kCreate | kMove | kDelete)) {
list_events |= FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME;
}
if (events & kModifyContent) list_events |= FILE_NOTIFY_CHANGE_LAST_WRITE;
DirectoryWatchHandle* handle =
new DirectoryWatchHandle(dir, list_events, recursive);
// Issue a read directly, to be sure events are tracked from now on. This is
// okay, since in Dart, we create the socket and start reading immidiately.
handle->EnsureInitialized(EventHandler::delegate());
handle->IssueRead();
return reinterpret_cast<intptr_t>(handle);
}
void FileSystemWatcher::UnwatchPath(intptr_t id, intptr_t path_id) {
USE(id);
DirectoryWatchHandle* handle =
reinterpret_cast<DirectoryWatchHandle*>(path_id);
handle->Stop();
}
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();
intptr_t max_count = available / kEventSize + 1;
Dart_Handle events = Dart_NewList(max_count);
uint8_t* buffer = new uint8_t[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(5);
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;
Dart_ListSetAt(event, 0, Dart_NewInteger(mask));
// Move events come in pairs. Just 'enable' by default.
Dart_ListSetAt(event, 1, Dart_NewInteger(1));
Dart_ListSetAt(event, 2, Dart_NewStringFromUTF16(
reinterpret_cast<uint16_t*>(e->FileName), e->FileNameLength / 2));
Dart_ListSetAt(event, 3, Dart_NewBoolean(true));
Dart_ListSetAt(event, 4, Dart_NewInteger(path_id));
Dart_ListSetAt(events, i, event);
i++;
if (e->NextEntryOffset == 0) break;
offset += e->NextEntryOffset;
}
delete[] buffer;
return events;
}
} // namespace bin
} // namespace dart
#endif // defined(TARGET_OS_WINDOWS)