Close file watcher when target is deleted.

BUG=http://code.google.com/p/dart/issues/detail?id=14374
R=sgjesse@google.com

Review URL: https://codereview.chromium.org//39613002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart@29159 260f80e4-7a28-3924-810f-c04153c831b5
This commit is contained in:
ajohnsen@google.com 2013-10-24 08:12:16 +00:00
parent faba61a261
commit fdea26c768
5 changed files with 48 additions and 11 deletions

View file

@ -76,6 +76,7 @@ class _FileSystemWatcherImpl
}
var socket = new _RawSocket(new _NativeSocket.watch(socketId));
_subscription = socket.expand((event) {
bool stop = false;
var events = [];
var pair = {};
if (event == RawSocketEvent.READ) {
@ -87,18 +88,22 @@ class _FileSystemWatcherImpl
}
return path;
}
void add(event) {
if ((event.type & _events) == 0) return;
events.add(event);
}
while (socket.available() > 0) {
for (var event in _readEvents()) {
if (event == null) continue;
var path = getPath(event);
if ((event[0] & FileSystemEvent.CREATE) != 0) {
events.add(new FileSystemCreateEvent._(path));
add(new FileSystemCreateEvent._(path));
}
if ((event[0] & FileSystemEvent.MODIFY) != 0) {
events.add(new FileSystemModifyEvent._(path, true));
add(new FileSystemModifyEvent._(path, true));
}
if ((event[0] & FileSystemEvent._MODIFY_ATTRIBUTES) != 0) {
events.add(new FileSystemModifyEvent._(path, false));
add(new FileSystemModifyEvent._(path, false));
}
if ((event[0] & FileSystemEvent.MOVE) != 0) {
int link = event[1];
@ -111,11 +116,15 @@ class _FileSystemWatcherImpl
pair[link] = event;
}
} else {
events.add(new FileSystemMoveEvent._(path, null));
add(new FileSystemMoveEvent._(path, null));
}
}
if ((event[0] & FileSystemEvent.DELETE) != 0) {
events.add(new FileSystemDeleteEvent._(path));
add(new FileSystemDeleteEvent._(path));
}
if ((event[0] & FileSystemEvent._DELETE_SELF) != 0) {
add(new FileSystemDeleteEvent._(path));
stop = true;
}
}
}
@ -127,9 +136,9 @@ class _FileSystemWatcherImpl
} else {
assert(false);
}
if (stop) socket.close();
return events;
})
.where((event) => (event.type & _events) != 0)
.listen(_controller.add, onDone: _cancel);
}
@ -138,6 +147,7 @@ class _FileSystemWatcherImpl
if (_subscription != null) {
_subscription.cancel();
}
_controller.close();
}
Stream<FileSystemEvent> get stream => _controller.stream;

View file

@ -24,7 +24,8 @@ class FileSystemWatcher {
kModifyContent = 1 << 1,
kDelete = 1 << 2,
kMove = 1 << 3,
kModefyAttribute = 1 << 4
kModefyAttribute = 1 << 4,
kDeleteSelf = 1 << 5
};
struct Event {

View file

@ -24,7 +24,7 @@ intptr_t FileSystemWatcher::WatchPath(const char* path,
bool recursive) {
int fd = TEMP_FAILURE_RETRY(inotify_init1(IN_NONBLOCK | IN_CLOEXEC));
if (fd < 0) return -1;
int list_events = 0;
int list_events = IN_DELETE_SELF;
if (events & kCreate) list_events |= IN_CREATE;
if (events & kModifyContent) list_events |= IN_MODIFY | IN_ATTRIB;
if (events & kDelete) list_events |= IN_DELETE;
@ -56,7 +56,7 @@ Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id) {
if (bytes < 0) {
return DartUtils::NewDartOSError();
}
const intptr_t kMaxCount = kBufferSize / kEventSize + 1;
const intptr_t kMaxCount = bytes / kEventSize;
Dart_Handle events = Dart_NewList(kMaxCount);
intptr_t offset = 0;
intptr_t i = 0;
@ -70,6 +70,7 @@ Dart_Handle FileSystemWatcher::ReadEvents(intptr_t id) {
if (e->mask & IN_CREATE) mask |= kCreate;
if (e->mask & IN_MOVE) mask |= kMove;
if (e->mask & IN_DELETE) mask |= kDelete;
if (e->mask & IN_DELETE_SELF) mask |= kDeleteSelf;
Dart_ListSetAt(event, 0, Dart_NewInteger(mask));
Dart_ListSetAt(event, 1, Dart_NewInteger(e->cookie));
if (e->len > 0) {

View file

@ -353,8 +353,13 @@ abstract class FileSystemEntity {
* files and directories. Recursive watching is supported.
*
* The system will start listening for events once the returned [Stream] is
* being listened to, not when the call to [watch] is issued. Note that the
* returned [Stream] is endless. To stop the [Stream], cancel the subscription.
* being listened to, not when the call to [watch] is issued.
*
* Note that the returned [Stream] is endless, unless:
*
* * The [Stream] is canceled, e.g. by calling `cancel` on the
* [StreamSubscription].
* * The [FileSystemEntity] being watches, is deleted.
*/
Stream<FileSystemEvent> watch({int events: FileSystemEvent.ALL,
bool recursive: false})
@ -623,6 +628,7 @@ class FileSystemEvent {
static const int ALL = CREATE | MODIFY | DELETE | MOVE;
static const int _MODIFY_ATTRIBUTES = 1 << 4;
static const int _DELETE_SELF = 1 << 5;
/**
* The type of event. See [FileSystemEvent] for a list of events.

View file

@ -111,6 +111,24 @@ void testWatchDeleteFile() {
}
void testWatchDeleteDir() {
var dir = Directory.systemTemp.createTempSync('dart_file_system_watcher');
var watcher = dir.watch(events: 0);
asyncStart();
var sub;
sub = watcher.listen((event) {
if (event is FileSystemDeleteEvent) {
Expect.isTrue(event.path == dir.path);
}
}, onDone: () {
asyncEnd();
});
dir.deleteSync();
}
void testWatchOnlyModifyFile() {
var dir = Directory.systemTemp.createTempSync('dart_file_system_watcher');
var file = new File(dir.path + '/file');
@ -244,6 +262,7 @@ void main() {
testWatchModifyFile();
testWatchMoveFile();
testWatchDeleteFile();
testWatchDeleteDir();
testWatchOnlyModifyFile();
testMultipleEvents();
testWatchNonRecursive();