blob: 9f1f6d06aa165d8289fc49861e936487021335ca [file] [log] [blame]
// Copyright (c) 2012, 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.
patch class _File {
/* patch */ static _exists(String path) native "File_Exists";
/* patch */ static _create(String path) native "File_Create";
/* patch */ static _createLink(String path, String target)
native "File_CreateLink";
/* patch */ static _linkTarget(String path) native "File_LinkTarget";
/* patch */ static _deleteNative(String path) native "File_Delete";
/* patch */ static _deleteLinkNative(String path) native "File_DeleteLink";
/* patch */ static _rename(String oldPath, String newPath)
native "File_Rename";
/* patch */ static _renameLink(String oldPath, String newPath)
native "File_RenameLink";
/* patch */ static _lengthFromPath(String path) native "File_LengthFromPath";
/* patch */ static _lastModified(String path) native "File_LastModified";
/* patch */ static _open(String path, int mode) native "File_Open";
/* patch */ static int _openStdio(int fd) native "File_OpenStdio";
}
patch class _RandomAccessFile {
/* patch */ static int _close(int id) native "File_Close";
/* patch */ static _readByte(int id) native "File_ReadByte";
/* patch */ static _read(int id, int bytes) native "File_Read";
/* patch */ static _readInto(int id, List<int> buffer, int start, int end)
native "File_ReadInto";
/* patch */ static _writeByte(int id, int value) native "File_WriteByte";
/* patch */ static _writeFrom(int id, List<int> buffer, int start, int end)
native "File_WriteFrom";
/* patch */ static _position(int id) native "File_Position";
/* patch */ static _setPosition(int id, int position)
native "File_SetPosition";
/* patch */ static _truncate(int id, int length) native "File_Truncate";
/* patch */ static _length(int id) native "File_Length";
/* patch */ static _flush(int id) native "File_Flush";
}
patch class _FileSystemWatcher {
/* patch */ factory _FileSystemWatcher(
String path, int events, bool recursive)
=> new _FileSystemWatcherImpl(path, events, recursive);
/* patch */ static bool get isSupported => _FileSystemWatcherImpl.isSupported;
}
class _FileSystemWatcherImpl
extends NativeFieldWrapperClass1
implements _FileSystemWatcher {
final String _path;
final int _events;
final bool _recursive;
StreamController _controller;
StreamSubscription _subscription;
_FileSystemWatcherImpl(this._path, this._events, this._recursive) {
if (!isSupported) {
throw new FileSystemException(
"File system watching is not supported on this system",
_path);
}
_controller = new StreamController.broadcast(onListen: _listen,
onCancel: _cancel);
}
void _listen() {
int socketId;
try {
socketId = _watchPath(_path, _events, identical(true, _recursive));
} catch (e) {
_controller.addError(new FileSystemException(
"Failed to watch path", _path, e));
_controller.close();
return;
}
var socket = new _RawSocket(new _NativeSocket.watch(socketId));
_subscription = socket.expand((event) {
bool stop = false;
var events = [];
var pair = {};
if (event == RawSocketEvent.READ) {
String getPath(event) {
var path = _path;
if (event[2] != null && event[2].isNotEmpty) {
path += Platform.pathSeparator;
path += event[2];
}
return path;
}
bool getIsDir(event) {
if (Platform.isWindows) {
// Windows does not get 'isDir' as part of the event.
return FileSystemEntity.isDirectorySync(getPath(event));
}
return (event[0] & FileSystemEvent._IS_DIR) != 0;
}
void add(event) {
if ((event.type & _events) == 0) return;
events.add(event);
}
void rewriteMove(event, isDir) {
if (event[3]) {
add(new FileSystemCreateEvent._(getPath(event), isDir));
} else {
add(new FileSystemDeleteEvent._(getPath(event), isDir));
}
}
while (socket.available() > 0) {
for (var event in _readEvents()) {
if (event == null) continue;
bool isDir = getIsDir(event);
var path = getPath(event);
if ((event[0] & FileSystemEvent.CREATE) != 0) {
add(new FileSystemCreateEvent._(path, isDir));
}
if ((event[0] & FileSystemEvent.MODIFY) != 0) {
add(new FileSystemModifyEvent._(path, isDir, true));
}
if ((event[0] & FileSystemEvent._MODIFY_ATTRIBUTES) != 0) {
add(new FileSystemModifyEvent._(path, isDir, false));
}
if ((event[0] & FileSystemEvent.MOVE) != 0) {
int link = event[1];
if (link > 0) {
if (pair.containsKey(link)) {
events.add(new FileSystemMoveEvent._(
getPath(pair[link]), isDir, path));
pair.remove(link);
} else {
pair[link] = event;
}
} else {
rewriteMove(event, isDir);
}
}
if ((event[0] & FileSystemEvent.DELETE) != 0) {
add(new FileSystemDeleteEvent._(path, isDir));
}
if ((event[0] & FileSystemEvent._DELETE_SELF) != 0) {
add(new FileSystemDeleteEvent._(path, isDir));
stop = true;
}
}
}
for (var event in pair.values) {
rewriteMove(event, getIsDir(event));
}
} else if (event == RawSocketEvent.CLOSED) {
} else if (event == RawSocketEvent.READ_CLOSED) {
} else {
assert(false);
}
if (stop) socket.close();
return events;
})
.listen(_controller.add, onDone: _cancel);
}
void _cancel() {
if (_subscription != null) {
_unwatchPath();
_subscription.cancel();
_subscription = null;
}
_controller.close();
}
Stream<FileSystemEvent> get stream => _controller.stream;
static bool get isSupported native "FileSystemWatcher_IsSupported";
int _watchPath(String path, int events, bool recursive)
native "FileSystemWatcher_WatchPath";
void _unwatchPath() native "FileSystemWatcher_UnwatchPath";
List _readEvents() native "FileSystemWatcher_ReadEvents";
}
Uint8List _makeUint8ListView(Uint8List source, int offsetInBytes, int length) {
return new Uint8List.view(source.buffer, offsetInBytes, length);
}