xref: /haiku/src/kits/storage/PathMonitor.cpp (revision 372a66634410cf0450e426716c14ad42d40c0da4)
1 /*
2  * Copyright 2007-2013, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  *		Stephan Aßmus, superstippi@gmx.de
8  *		Ingo Weinhold, ingo_weinhold@gmx.de
9  */
10 
11 
12 #include <PathMonitor.h>
13 
14 #include <pthread.h>
15 #include <stdio.h>
16 
17 #include <map>
18 #include <new>
19 #include <set>
20 
21 #include <Autolock.h>
22 #include <Directory.h>
23 #include <Entry.h>
24 #include <Handler.h>
25 #include <Locker.h>
26 #include <Looper.h>
27 #include <Path.h>
28 #include <String.h>
29 
30 #include <AutoDeleter.h>
31 #include <NotOwningEntryRef.h>
32 #include <ObjectList.h>
33 #include <util/OpenHashTable.h>
34 #include <util/SinglyLinkedList.h>
35 
36 
37 #undef TRACE
38 //#define TRACE_PATH_MONITOR
39 #ifdef TRACE_PATH_MONITOR
40 #	define TRACE(...) debug_printf("BPathMonitor: " __VA_ARGS__)
41 #else
42 #	define TRACE(...) ;
43 #endif
44 
45 
46 // TODO: Support symlink components in the path.
47 // TODO: Support mounting/unmounting of volumes in path components and within
48 // the watched path tree.
49 
50 
51 #define WATCH_NODE_FLAG_MASK	0x00ff
52 
53 
54 namespace {
55 
56 
57 struct Directory;
58 struct Node;
59 struct WatcherHashDefinition;
60 typedef BOpenHashTable<WatcherHashDefinition> WatcherMap;
61 
62 
63 static pthread_once_t sInitOnce = PTHREAD_ONCE_INIT;
64 static WatcherMap* sWatchers = NULL;
65 static BLocker* sLocker = NULL;
66 static BLooper* sLooper = NULL;
67 static BPathMonitor::BWatchingInterface* sDefaultWatchingInterface = NULL;
68 static BPathMonitor::BWatchingInterface* sWatchingInterface = NULL;
69 
70 
71 //	#pragma mark -
72 
73 
74 /*! Returns empty path, if either \a parent or \a subPath is empty or an
75 	allocation fails.
76  */
77 static BString
78 make_path(const BString& parent, const char* subPath)
79 {
80 	BString path = parent;
81 	int32 length = path.Length();
82 	if (length == 0 || subPath[0] == '\0')
83 		return BString();
84 
85 	if (parent.ByteAt(length - 1) != '/') {
86 		path << '/';
87 		if (path.Length() < ++length)
88 			return BString();
89 	}
90 
91 	path << subPath;
92 	if (path.Length() <= length)
93 		return BString();
94 	return path;
95 }
96 
97 
98 //	#pragma mark - Ancestor
99 
100 
101 class Ancestor {
102 public:
103 	Ancestor(Ancestor* parent, const BString& path, size_t pathComponentOffset)
104 		:
105 		fParent(parent),
106 		fChild(NULL),
107 		fPath(path),
108 		fEntryRef(-1, -1, fPath.String() + pathComponentOffset),
109 		fNodeRef(),
110 		fWatchingFlags(0),
111 		fIsDirectory(false)
112 	{
113 		if (pathComponentOffset == 0) {
114 			// must be "/"
115 			fEntryRef.SetTo(-1, -1, ".");
116 		}
117 
118 		if (fParent != NULL)
119 			fParent->fChild = this;
120 	}
121 
122 	Ancestor* Parent() const
123 	{
124 		return fParent;
125 	}
126 
127 	Ancestor* Child() const
128 	{
129 		return fChild;
130 	}
131 
132 	const BString& Path() const
133 	{
134 		return fPath;
135 	}
136 
137 	const char* Name() const
138 	{
139 		return fEntryRef.name;
140 	}
141 
142 	bool Exists() const
143 	{
144 		return fNodeRef.device >= 0;
145 	}
146 
147 	const NotOwningEntryRef& EntryRef() const
148 	{
149 		return fEntryRef;
150 	}
151 
152 	const node_ref& NodeRef() const
153 	{
154 		return fNodeRef;
155 	}
156 
157 	bool IsDirectory() const
158 	{
159 		return fIsDirectory;
160 	}
161 
162 	status_t StartWatching(uint32 pathFlags, BHandler* target)
163 	{
164 		// init entry ref
165 		BEntry entry;
166 		status_t error = entry.SetTo(fPath);
167 		if (error != B_OK)
168 			return error;
169 
170 		entry_ref entryRef;
171 		error = entry.GetRef(&entryRef);
172 		if (error != B_OK)
173 			return error;
174 
175 		fEntryRef.device = entryRef.device;
176 		fEntryRef.directory = entryRef.directory;
177 
178 		// init node ref
179 		struct stat st;
180 		error = entry.GetStat(&st);
181 		if (error != B_OK)
182 			return error == B_ENTRY_NOT_FOUND ? B_OK : error;
183 
184 		fNodeRef = node_ref(st.st_dev, st.st_ino);
185 		fIsDirectory = S_ISDIR(st.st_mode);
186 
187 		// start watching
188 		uint32 flags = fChild == NULL ?  pathFlags : B_WATCH_DIRECTORY;
189 			// In theory B_WATCH_NAME would suffice for all existing ancestors,
190 			// plus B_WATCH_DIRECTORY for the parent of the first not existing
191 			// ancestor. In practice this complicates the transitions when an
192 			// ancestor is created/removed/moved.
193 		if (flags != 0) {
194 			error = sWatchingInterface->WatchNode(&fNodeRef, flags, target);
195 			TRACE("  started to watch ancestor %p (\"%s\", %#" B_PRIx32
196 				") -> %s\n", this, Name(), flags, strerror(error));
197 			if (error != B_OK)
198 				return error;
199 		}
200 
201 		fWatchingFlags = flags;
202 		return B_OK;
203 	}
204 
205 	void StopWatching(BHandler* target)
206 	{
207 		// stop watching
208 		if (fWatchingFlags != 0) {
209 			sWatchingInterface->WatchNode(&fNodeRef, B_STOP_WATCHING, target);
210 			fWatchingFlags = 0;
211 		}
212 
213 		// uninitialize node and entry ref
214 		fIsDirectory = false;
215 		fNodeRef = node_ref();
216 		fEntryRef.SetDirectoryNodeRef(node_ref());
217 	}
218 
219 	Ancestor*& HashNext()
220 	{
221 		return fHashNext;
222 	}
223 
224 private:
225 	Ancestor*			fParent;
226 	Ancestor*			fChild;
227 	Ancestor*			fHashNext;
228 	BString				fPath;
229 	NotOwningEntryRef	fEntryRef;
230 	node_ref			fNodeRef;
231 	uint32				fWatchingFlags;
232 	bool				fIsDirectory;
233 };
234 
235 
236 //	#pragma mark - AncestorMap
237 
238 
239 struct AncestorHashDefinition {
240 	typedef	node_ref	KeyType;
241 	typedef	Ancestor	ValueType;
242 
243 	size_t HashKey(const node_ref& key) const
244 	{
245 		return size_t(key.device ^ key.node);
246 	}
247 
248 	size_t Hash(Ancestor* value) const
249 	{
250 		return HashKey(value->NodeRef());
251 	}
252 
253 	bool Compare(const node_ref& key, Ancestor* value) const
254 	{
255 		return key == value->NodeRef();
256 	}
257 
258 	Ancestor*& GetLink(Ancestor* value) const
259 	{
260 		return value->HashNext();
261 	}
262 };
263 
264 
265 typedef BOpenHashTable<AncestorHashDefinition> AncestorMap;
266 
267 
268 //	#pragma mark - Entry
269 
270 
271 class Entry : public SinglyLinkedListLinkImpl<Entry> {
272 public:
273 	Entry(Directory* parent, const BString& name, ::Node* node)
274 		:
275 		fParent(parent),
276 		fName(name),
277 		fNode(node)
278 	{
279 	}
280 
281 	Directory* Parent() const
282 	{
283 		return fParent;
284 	}
285 
286 	const BString& Name() const
287 	{
288 		return fName;
289 	}
290 
291 	::Node* Node() const
292 	{
293 		return fNode;
294 	}
295 
296 	void SetNode(::Node* node)
297 	{
298 		fNode = node;
299 	}
300 
301 	inline NotOwningEntryRef EntryRef() const;
302 
303 	Entry*& HashNext()
304 	{
305 		return fHashNext;
306 	}
307 
308 private:
309 	Directory*	fParent;
310 	BString		fName;
311 	::Node*		fNode;
312 	Entry*		fHashNext;
313 };
314 
315 typedef SinglyLinkedList<Entry> EntryList;
316 
317 
318 // EntryMap
319 
320 
321 struct EntryHashDefinition {
322 	typedef	const char*	KeyType;
323 	typedef	Entry		ValueType;
324 
325 	size_t HashKey(const char* key) const
326 	{
327 		return BString::HashValue(key);
328 	}
329 
330 	size_t Hash(Entry* value) const
331 	{
332 		return value->Name().HashValue();
333 	}
334 
335 	bool Compare(const char* key, Entry* value) const
336 	{
337 		return value->Name() == key;
338 	}
339 
340 	Entry*& GetLink(Entry* value) const
341 	{
342 		return value->HashNext();
343 	}
344 };
345 
346 
347 typedef BOpenHashTable<EntryHashDefinition> EntryMap;
348 
349 
350 //	#pragma mark - Node
351 
352 
353 class Node {
354 public:
355 	Node(const node_ref& nodeRef)
356 		:
357 		fNodeRef(nodeRef)
358 	{
359 	}
360 
361 	virtual ~Node()
362 	{
363 	}
364 
365 	virtual bool IsDirectory() const
366 	{
367 		return false;
368 	}
369 
370 	virtual Directory* ToDirectory()
371 	{
372 		return NULL;
373 	}
374 
375 	const node_ref& NodeRef() const
376 	{
377 		return fNodeRef;
378 	}
379 
380 	const EntryList& Entries() const
381 	{
382 		return fEntries;
383 	}
384 
385 	bool HasEntries() const
386 	{
387 		return !fEntries.IsEmpty();
388 	}
389 
390 	Entry* FirstNodeEntry() const
391 	{
392 		return fEntries.Head();
393 	}
394 
395 	bool IsOnlyNodeEntry(Entry* entry) const
396 	{
397 		return entry == fEntries.Head() && fEntries.GetNext(entry) == NULL;
398 	}
399 
400 	void AddNodeEntry(Entry* entry)
401 	{
402 		fEntries.Add(entry);
403 	}
404 
405 	void RemoveNodeEntry(Entry* entry)
406 	{
407 		fEntries.Remove(entry);
408 	}
409 
410 	Node*& HashNext()
411 	{
412 		return fHashNext;
413 	}
414 
415 private:
416 	node_ref			fNodeRef;
417 	EntryList			fEntries;
418 	Node*				fHashNext;
419 };
420 
421 
422 struct NodeHashDefinition {
423 	typedef	node_ref	KeyType;
424 	typedef	Node		ValueType;
425 
426 	size_t HashKey(const node_ref& key) const
427 	{
428 		return size_t(key.device ^ key.node);
429 	}
430 
431 	size_t Hash(Node* value) const
432 	{
433 		return HashKey(value->NodeRef());
434 	}
435 
436 	bool Compare(const node_ref& key, Node* value) const
437 	{
438 		return key == value->NodeRef();
439 	}
440 
441 	Node*& GetLink(Node* value) const
442 	{
443 		return value->HashNext();
444 	}
445 };
446 
447 
448 typedef BOpenHashTable<NodeHashDefinition> NodeMap;
449 
450 
451 //	#pragma mark - Directory
452 
453 
454 class Directory : public Node {
455 public:
456 	static Directory* Create(const node_ref& nodeRef)
457 	{
458 		Directory* directory = new(std::nothrow) Directory(nodeRef);
459 		if (directory == NULL || directory->fEntries.Init() != B_OK) {
460 			delete directory;
461 			return NULL;
462 		}
463 
464 		return directory;
465 	}
466 
467 	virtual bool IsDirectory() const
468 	{
469 		return true;
470 	}
471 
472 	virtual Directory* ToDirectory()
473 	{
474 		return this;
475 	}
476 
477 	Entry* FindEntry(const char* name) const
478 	{
479 		return fEntries.Lookup(name);
480 	}
481 
482 	Entry* CreateEntry(const BString& name, Node* node)
483 	{
484 		Entry* entry = new(std::nothrow) Entry(this, name, node);
485 		if (entry == NULL || entry->Name().IsEmpty()) {
486 			delete entry;
487 			return NULL;
488 		}
489 
490 		AddEntry(entry);
491 		return entry;
492 	}
493 
494 	void AddEntry(Entry* entry)
495 	{
496 		fEntries.Insert(entry);
497 	}
498 
499 	void RemoveEntry(Entry* entry)
500 	{
501 		fEntries.Remove(entry);
502 	}
503 
504 	EntryMap::Iterator GetEntryIterator() const
505 	{
506 		return fEntries.GetIterator();
507 	}
508 
509 	Entry* RemoveAllEntries()
510 	{
511 		return fEntries.Clear(true);
512 	}
513 
514 private:
515 	Directory(const node_ref& nodeRef)
516 		:
517 		Node(nodeRef)
518 	{
519 	}
520 
521 private:
522 	EntryMap	fEntries;
523 };
524 
525 
526 //	#pragma mark - Entry
527 
528 
529 inline NotOwningEntryRef
530 Entry::EntryRef() const
531 {
532 	return NotOwningEntryRef(fParent->NodeRef(), fName);
533 }
534 
535 
536 //	#pragma mark - PathHandler
537 
538 
539 class PathHandler : public BHandler {
540 public:
541 								PathHandler(const char* path, uint32 flags,
542 									const BMessenger& target, BLooper* looper);
543 	virtual						~PathHandler();
544 
545 			status_t			InitCheck() const;
546 			void				Quit();
547 
548 			const BString&		OriginalPath() const
549 									{ return fOriginalPath; }
550 			uint32				Flags() const	{ return fFlags; }
551 
552 	virtual	void				MessageReceived(BMessage* message);
553 
554 			PathHandler*&		HashNext()	{ return fHashNext; }
555 
556 private:
557 			status_t			_CreateAncestors();
558 			status_t			_StartWatchingAncestors(Ancestor* ancestor,
559 									bool notify);
560 			void				_StopWatchingAncestors(Ancestor* ancestor,
561 									bool notify);
562 
563 			void				_EntryCreated(BMessage* message);
564 			void				_EntryRemoved(BMessage* message);
565 			void				_EntryMoved(BMessage* message);
566 			void				_NodeChanged(BMessage* message);
567 
568 			bool				_EntryCreated(const NotOwningEntryRef& entryRef,
569 									const node_ref& nodeRef, bool isDirectory,
570 									bool dryRun, bool notify, Entry** _entry);
571 			bool				_EntryRemoved(const NotOwningEntryRef& entryRef,
572 									const node_ref& nodeRef, bool dryRun,
573 									bool notify, Entry** _keepEntry);
574 
575 			bool				_CheckDuplicateEntryNotification(int32 opcode,
576 									const entry_ref& toEntryRef,
577 									const node_ref& nodeRef,
578 									const entry_ref* fromEntryRef = NULL);
579 			void				_UnsetDuplicateEntryNotification();
580 
581 			Ancestor*			_GetAncestor(const node_ref& nodeRef) const;
582 
583 			status_t			_AddNode(const node_ref& nodeRef,
584 									bool isDirectory, bool notify,
585 					   				Entry* entry = NULL, Node** _node = NULL);
586 			void				_DeleteNode(Node* node, bool notify);
587 			Node*				_GetNode(const node_ref& nodeRef) const;
588 
589 			status_t			_AddEntryIfNeeded(Directory* directory,
590 									const char* name, const node_ref& nodeRef,
591 									bool isDirectory, bool notify,
592 									Entry** _entry = NULL);
593 			void				_DeleteEntry(Entry* entry, bool notify);
594 			void				_DeleteEntryAlreadyRemovedFromParent(
595 									Entry* entry, bool notify);
596 
597 			void				_NotifyFilesCreatedOrRemoved(Entry* entry,
598 									int32 opcode) const;
599 			void				_NotifyEntryCreatedOrRemoved(Entry* entry,
600 									int32 opcode) const;
601 			void				_NotifyEntryCreatedOrRemoved(
602 									const entry_ref& entryRef,
603 									const node_ref& nodeRef, const char* path,
604 									bool isDirectory, int32 opcode) const;
605 			void				_NotifyEntryMoved(const entry_ref& fromEntryRef,
606 									const entry_ref& toEntryRef,
607 									const node_ref& nodeRef,
608 							 		const char* fromPath, const char* path,
609 									bool isDirectory, bool wasAdded,
610 									bool wasRemoved) const;
611 			void				_NotifyTarget(BMessage& message,
612 									const char* path) const;
613 
614 			BString				_NodePath(const Node* node) const;
615 			BString				_EntryPath(const Entry* entry) const;
616 
617 
618 			bool				_WatchRecursively() const;
619 			bool				_WatchFilesOnly() const;
620 			bool				_WatchDirectoriesOnly() const;
621 
622 private:
623 			BMessenger			fTarget;
624 			uint32				fFlags;
625 			status_t			fStatus;
626 			BString				fOriginalPath;
627 			BString				fPath;
628 			Ancestor*			fRoot;
629 			Ancestor*			fBaseAncestor;
630 			Node*				fBaseNode;
631 			AncestorMap			fAncestors;
632 			NodeMap				fNodes;
633 			PathHandler*		fHashNext;
634 			int32				fDuplicateEntryNotificationOpcode;
635 			node_ref			fDuplicateEntryNotificationNodeRef;
636 			entry_ref			fDuplicateEntryNotificationToEntryRef;
637 			entry_ref			fDuplicateEntryNotificationFromEntryRef;
638 };
639 
640 
641 struct PathHandlerHashDefinition {
642 	typedef	const char*	KeyType;
643 	typedef	PathHandler	ValueType;
644 
645 	size_t HashKey(const char* key) const
646 	{
647 		return BString::HashValue(key);
648 	}
649 
650 	size_t Hash(PathHandler* value) const
651 	{
652 		return value->OriginalPath().HashValue();
653 	}
654 
655 	bool Compare(const char* key, PathHandler* value) const
656 	{
657 		return key == value->OriginalPath();
658 	}
659 
660 	PathHandler*& GetLink(PathHandler* value) const
661 	{
662 		return value->HashNext();
663 	}
664 };
665 
666 
667 typedef BOpenHashTable<PathHandlerHashDefinition> PathHandlerMap;
668 
669 
670 //	#pragma mark - Watcher
671 
672 
673 struct Watcher : public PathHandlerMap {
674 	static Watcher* Create(const BMessenger& target)
675 	{
676 		Watcher* watcher = new(std::nothrow) Watcher(target);
677 		if (watcher == NULL || watcher->Init() != B_OK) {
678 			delete watcher;
679 			return NULL;
680 		}
681 		return watcher;
682 	}
683 
684 	const BMessenger& Target() const
685 	{
686 		return fTarget;
687 	}
688 
689 	Watcher*& HashNext()
690 	{
691 		return fHashNext;
692 	}
693 
694 private:
695 	Watcher(const BMessenger& target)
696 		:
697 		fTarget(target)
698 	{
699 	}
700 
701 private:
702 	BMessenger		fTarget;
703 	Watcher*		fHashNext;
704 };
705 
706 
707 struct WatcherHashDefinition {
708 	typedef	BMessenger	KeyType;
709 	typedef	Watcher		ValueType;
710 
711 	size_t HashKey(const BMessenger& key) const
712 	{
713 		return key.HashValue();
714 	}
715 
716 	size_t Hash(Watcher* value) const
717 	{
718 		return HashKey(value->Target());
719 	}
720 
721 	bool Compare(const BMessenger& key, Watcher* value) const
722 	{
723 		return key == value->Target();
724 	}
725 
726 	Watcher*& GetLink(Watcher* value) const
727 	{
728 		return value->HashNext();
729 	}
730 };
731 
732 
733 //	#pragma mark - PathHandler
734 
735 
736 PathHandler::PathHandler(const char* path, uint32 flags,
737 	const BMessenger& target, BLooper* looper)
738 	:
739 	BHandler(path),
740 	fTarget(target),
741 	fFlags(flags),
742 	fStatus(B_OK),
743 	fOriginalPath(path),
744 	fPath(),
745 	fRoot(NULL),
746 	fBaseAncestor(NULL),
747 	fBaseNode(NULL),
748 	fAncestors(),
749 	fNodes()
750 {
751 	TRACE("%p->PathHandler::PathHandler(\"%s\", %#" B_PRIx32 ")\n", this, path,
752 		flags);
753 
754 	_UnsetDuplicateEntryNotification();
755 
756 	fStatus = fAncestors.Init();
757 	if (fStatus != B_OK)
758 		return;
759 
760 	fStatus = fNodes.Init();
761 	if (fStatus != B_OK)
762 		return;
763 
764 	// normalize the flags
765 	if ((fFlags & B_WATCH_RECURSIVELY) != 0) {
766 		// We add B_WATCH_NAME and B_WATCH_DIRECTORY as needed, so clear them
767 		// here.
768 		fFlags &= ~uint32(B_WATCH_NAME | B_WATCH_DIRECTORY);
769 	} else {
770 		// The B_WATCH_*_ONLY flags are only valid for the recursive mode.
771 		// B_WATCH_NAME is implied (we watch the parent directory).
772 		fFlags &= ~uint32(B_WATCH_FILES_ONLY | B_WATCH_DIRECTORIES_ONLY
773 			| B_WATCH_NAME);
774 	}
775 
776 	// Normalize the path a bit. We can't use BPath, as it may really normalize
777 	// the path, i.e. resolve symlinks and such, which may cause us to monitor
778 	// the wrong path. We want some normalization, though:
779 	// * relative -> absolute path
780 	// * fold duplicate '/'s
781 	// * omit "." components
782 	// * fail when encountering ".." components
783 
784 	// make absolute
785 	BString normalizedPath;
786 	if (path[0] == '/') {
787 		normalizedPath = "/";
788 		path++;
789 	} else
790 		normalizedPath = BPath(".").Path();
791 	if (normalizedPath.IsEmpty()) {
792 		fStatus = B_NO_MEMORY;
793 		return;
794 	}
795 
796 	// parse path components
797 	const char* pathEnd = path + strlen(path);
798 	for (;;) {
799 		// skip '/'s
800 		while (path[0] == '/')
801 			path++;
802 		if (path == pathEnd)
803 			break;
804 
805 		const char* componentEnd = strchr(path, '/');
806 		if (componentEnd == NULL)
807 			componentEnd = pathEnd;
808 		size_t componentLength = componentEnd - path;
809 
810 		// handle ".' and ".."
811 		if (path[0] == '.') {
812 			if (componentLength == 1) {
813 				path = componentEnd;
814 				continue;
815 			}
816 			if (componentLength == 2 && path[1] == '.') {
817 				fStatus = B_BAD_VALUE;
818 				return;
819 			}
820 		}
821 
822 		int32 normalizedPathLength = normalizedPath.Length();
823 		if (normalizedPath.ByteAt(normalizedPathLength - 1) != '/') {
824 			normalizedPath << '/';
825 			normalizedPathLength++;
826 		}
827 		normalizedPath.Append(path, componentEnd - path);
828 		normalizedPathLength += int32(componentEnd - path);
829 
830 		if (normalizedPath.Length() != normalizedPathLength) {
831 			fStatus = B_NO_MEMORY;
832 			return;
833 		}
834 
835 		path = componentEnd;
836 	}
837 
838 	fPath = normalizedPath;
839 
840 	// Create the Ancestor objects -- they correspond to the path components and
841 	// are used for watching changes that affect the entries on the path.
842 	fStatus = _CreateAncestors();
843 	if (fStatus != B_OK)
844 		return;
845 
846 	// add ourselves to the looper
847 	if (!looper->Lock())
848 		debugger("PathHandler: failed to lock the looper");
849 	looper->AddHandler(this);
850 	looper->Unlock();
851 
852 	// start watching
853 	fStatus = _StartWatchingAncestors(fRoot, false);
854 	if (fStatus != B_OK)
855 		return;
856 }
857 
858 
859 PathHandler::~PathHandler()
860 {
861 	TRACE("%p->PathHandler::~PathHandler(\"%s\", %#" B_PRIx32 ")\n", this,
862 		fPath.String(), fFlags);
863 
864 	if (fBaseNode != NULL)
865 		_DeleteNode(fBaseNode, false);
866 
867 	while (fRoot != NULL) {
868 		Ancestor* nextAncestor = fRoot->Child();
869 		delete fRoot;
870 		fRoot = nextAncestor;
871 	}
872 }
873 
874 
875 status_t
876 PathHandler::InitCheck() const
877 {
878 	return fStatus;
879 }
880 
881 
882 void
883 PathHandler::Quit()
884 {
885 	if (sLooper->Lock()) {
886 		TRACE("%p->PathHandler::Quit()\n", this);
887 		sWatchingInterface->StopWatching(this);
888 		sLooper->RemoveHandler(this);
889 		sLooper->Unlock();
890 	} else
891 		TRACE("%p->PathHandler::Quit(): failed to lock looper\n", this);
892 	delete this;
893 }
894 
895 
896 void
897 PathHandler::MessageReceived(BMessage* message)
898 {
899 	switch (message->what) {
900 		case B_NODE_MONITOR:
901 		{
902 			int32 opcode;
903 			if (message->FindInt32("opcode", &opcode) != B_OK)
904 				return;
905 
906 			switch (opcode) {
907 				case B_ENTRY_CREATED:
908 					_EntryCreated(message);
909 					break;
910 
911 				case B_ENTRY_REMOVED:
912 					_EntryRemoved(message);
913 					break;
914 
915 				case B_ENTRY_MOVED:
916 					_EntryMoved(message);
917 					break;
918 
919 				default:
920 					_UnsetDuplicateEntryNotification();
921 					_NodeChanged(message);
922 					break;
923 			}
924 
925 			break;
926 		}
927 
928 		default:
929 			BHandler::MessageReceived(message);
930 			break;
931 	}
932 }
933 
934 
935 status_t
936 PathHandler::_CreateAncestors()
937 {
938 	TRACE("%p->PathHandler::_CreateAncestors()\n", this);
939 
940 	// create the Ancestor objects
941 	const char* path = fPath.String();
942 	const char* pathEnd = path + fPath.Length();
943 	const char* component = path;
944 
945 	Ancestor* ancestor = NULL;
946 
947 	while (component < pathEnd) {
948 		const char* componentEnd = component == path
949 			? component + 1 : strchr(component, '/');
950 		if (componentEnd == NULL)
951 			componentEnd = pathEnd;
952 
953 		BString ancestorPath(path, componentEnd - path);
954 		if (ancestorPath.IsEmpty())
955 			return B_NO_MEMORY;
956 
957 		ancestor = new(std::nothrow) Ancestor(ancestor, ancestorPath,
958 			component - path);
959 		TRACE("  created ancestor %p (\"%s\" / \"%s\")\n", ancestor,
960 			ancestor->Path().String(), ancestor->Name());
961 		if (ancestor == NULL)
962 			return B_NO_MEMORY;
963 
964 		if (fRoot == NULL)
965 			fRoot = ancestor;
966 
967 		component = componentEnd[0] == '/' ? componentEnd + 1 : componentEnd;
968 	}
969 
970 	fBaseAncestor = ancestor;
971 
972 	return B_OK;
973 }
974 
975 
976 status_t
977 PathHandler::_StartWatchingAncestors(Ancestor* startAncestor, bool notify)
978 {
979 	TRACE("%p->PathHandler::_StartWatchingAncestors(%p, %d)\n", this,
980 		startAncestor, notify);
981 
982 	// The watch flags for the path (if it exists). Recursively implies
983 	// directory, since we need to watch the entries.
984 	uint32 watchFlags = (fFlags & WATCH_NODE_FLAG_MASK)
985 		| (_WatchRecursively() ? B_WATCH_DIRECTORY : 0);
986 
987 	for (Ancestor* ancestor = startAncestor; ancestor != NULL;
988 		ancestor = ancestor->Child()) {
989 		status_t error = ancestor->StartWatching(watchFlags, this);
990 		if (error != B_OK)
991 			return error;
992 
993 		if (!ancestor->Exists()) {
994 			TRACE("  -> ancestor doesn't exist\n");
995 			break;
996 		}
997 
998 		fAncestors.Insert(ancestor);
999 	}
1000 
1001 	if (!fBaseAncestor->Exists())
1002 		return B_OK;
1003 
1004 	if (notify) {
1005 		_NotifyEntryCreatedOrRemoved(fBaseAncestor->EntryRef(),
1006 			fBaseAncestor->NodeRef(), fPath, fBaseAncestor->IsDirectory(),
1007 			B_ENTRY_CREATED);
1008 	}
1009 
1010 	if (!_WatchRecursively())
1011 		return B_OK;
1012 
1013 	status_t error = _AddNode(fBaseAncestor->NodeRef(),
1014 		fBaseAncestor->IsDirectory(), notify && _WatchFilesOnly(), NULL,
1015 		&fBaseNode);
1016 	if (error != B_OK)
1017 		return error;
1018 
1019 	return B_OK;
1020 }
1021 
1022 
1023 void
1024 PathHandler::_StopWatchingAncestors(Ancestor* ancestor, bool notify)
1025 {
1026 	// stop watching the tree below path
1027 	if (fBaseNode != NULL) {
1028 		_DeleteNode(fBaseNode, notify && _WatchFilesOnly());
1029 		fBaseNode = NULL;
1030 	}
1031 
1032 	if (notify && fBaseAncestor->Exists()
1033 		&& (fBaseAncestor->IsDirectory()
1034 			? !_WatchFilesOnly() : !_WatchDirectoriesOnly())) {
1035 		_NotifyEntryCreatedOrRemoved(fBaseAncestor->EntryRef(),
1036 			fBaseAncestor->NodeRef(), fPath, fBaseAncestor->IsDirectory(),
1037 			B_ENTRY_REMOVED);
1038 	}
1039 
1040 	// stop watching the ancestors and uninitialize their entries
1041 	for (; ancestor != NULL; ancestor = ancestor->Child()) {
1042 		if (ancestor->Exists())
1043 			fAncestors.Remove(ancestor);
1044 		ancestor->StopWatching(this);
1045 	}
1046 }
1047 
1048 
1049 void
1050 PathHandler::_EntryCreated(BMessage* message)
1051 {
1052 	// TODO: Unless we're watching files only, we might want to forward (some
1053 	// of) the messages that don't agree with our model, since our client
1054 	// maintains its model at a different time and the notification might be
1055 	// necessary to keep it up-to-date. E.g. consider the following case:
1056 	// 1. a directory is created
1057 	// 2. a file is created in the directory
1058 	// 3. the file is removed from the directory
1059 	// If we get the notification after 1. and before 2., we pass it on to the
1060 	// client, which may get it after 2. and before 3., thus seeing the file.
1061 	// If we then get the entry-created notification after 3., we don't see the
1062 	// file anymore and ignore the notification as well as the following
1063 	// entry-removed notification. That is the client will never know that the
1064 	// file has been removed. This can only happen in recursive mode. Otherwise
1065 	// (and with B_WATCH_DIRECTORY) we just pass on all notifications.
1066 	// A possible solution could be to just create a zombie entry and pass on
1067 	// the entry-created notification. We wouldn't be able to adhere to the
1068 	// B_WATCH_FILES_ONLY/B_WATCH_DIRECTORIES_ONLY flags, but that should be
1069 	// acceptable. Either the client hasn't seen the entry either -- then it
1070 	// doesn't matter -- or it likely has ignored a not matching entry anyway.
1071 
1072 	NotOwningEntryRef entryRef;
1073 	node_ref nodeRef;
1074 
1075 	if (message->FindInt32("device", &nodeRef.device) != B_OK
1076 		|| message->FindInt64("node", &nodeRef.node) != B_OK
1077 		|| message->FindInt64("directory", &entryRef.directory) != B_OK
1078 		|| message->FindString("name", (const char**)&entryRef.name) != B_OK) {
1079 		return;
1080 	}
1081 	entryRef.device = nodeRef.device;
1082 
1083 	if (_CheckDuplicateEntryNotification(B_ENTRY_CREATED, entryRef, nodeRef))
1084 		return;
1085 
1086 	TRACE("%p->PathHandler::_EntryCreated(): entry: %" B_PRIdDEV ":%" B_PRIdINO
1087 		":\"%s\", node: %" B_PRIdDEV ":%" B_PRIdINO "\n", this, entryRef.device,
1088 		entryRef.directory, entryRef.name, nodeRef.device, nodeRef.node);
1089 
1090 	BEntry entry;
1091 	struct stat st;
1092 	if (entry.SetTo(&entryRef) != B_OK || entry.GetStat(&st) != B_OK
1093 		|| nodeRef != node_ref(st.st_dev, st.st_ino)) {
1094 		return;
1095 	}
1096 
1097 	_EntryCreated(entryRef, nodeRef, S_ISDIR(st.st_mode), false, true, NULL);
1098 }
1099 
1100 
1101 void
1102 PathHandler::_EntryRemoved(BMessage* message)
1103 {
1104 	NotOwningEntryRef entryRef;
1105 	node_ref nodeRef;
1106 
1107 	if (message->FindInt32("device", &nodeRef.device) != B_OK
1108 		|| message->FindInt64("node", &nodeRef.node) != B_OK
1109 		|| message->FindInt64("directory", &entryRef.directory) != B_OK
1110 		|| message->FindString("name", (const char**)&entryRef.name) != B_OK) {
1111 		return;
1112 	}
1113 	entryRef.device = nodeRef.device;
1114 
1115 	if (_CheckDuplicateEntryNotification(B_ENTRY_REMOVED, entryRef, nodeRef))
1116 		return;
1117 
1118 	TRACE("%p->PathHandler::_EntryRemoved(): entry: %" B_PRIdDEV ":%" B_PRIdINO
1119 		":\"%s\", node: %" B_PRIdDEV ":%" B_PRIdINO "\n", this, entryRef.device,
1120 		entryRef.directory, entryRef.name, nodeRef.device, nodeRef.node);
1121 
1122 	_EntryRemoved(entryRef, nodeRef, false, true, NULL);
1123 }
1124 
1125 
1126 void
1127 PathHandler::_EntryMoved(BMessage* message)
1128 {
1129 	NotOwningEntryRef fromEntryRef;
1130 	NotOwningEntryRef toEntryRef;
1131 	node_ref nodeRef;
1132 
1133 	if (message->FindInt32("node device", &nodeRef.device) != B_OK
1134 		|| message->FindInt64("node", &nodeRef.node) != B_OK
1135 		|| message->FindInt32("device", &fromEntryRef.device) != B_OK
1136 		|| message->FindInt64("from directory", &fromEntryRef.directory) != B_OK
1137 		|| message->FindInt64("to directory", &toEntryRef.directory) != B_OK
1138 		|| message->FindString("from name", (const char**)&fromEntryRef.name)
1139 			!= B_OK
1140 		|| message->FindString("name", (const char**)&toEntryRef.name)
1141 			!= B_OK) {
1142 		return;
1143 	}
1144 	toEntryRef.device = fromEntryRef.device;
1145 
1146 	if (_CheckDuplicateEntryNotification(B_ENTRY_MOVED, toEntryRef, nodeRef,
1147 			&fromEntryRef)) {
1148 		return;
1149 	}
1150 
1151 	TRACE("%p->PathHandler::_EntryMoved(): entry: %" B_PRIdDEV ":%" B_PRIdINO
1152 		":\"%s\" -> %" B_PRIdDEV ":%" B_PRIdINO ":\"%s\", node: %" B_PRIdDEV
1153 		":%" B_PRIdINO "\n", this, fromEntryRef.device, fromEntryRef.directory,
1154 		fromEntryRef.name, toEntryRef.device, toEntryRef.directory,
1155 		toEntryRef.name, nodeRef.device, nodeRef.node);
1156 
1157 	BEntry entry;
1158 	struct stat st;
1159 	if (entry.SetTo(&toEntryRef) != B_OK || entry.GetStat(&st) != B_OK
1160 		|| nodeRef != node_ref(st.st_dev, st.st_ino)) {
1161 		_EntryRemoved(fromEntryRef, nodeRef, false, true, NULL);
1162 		return;
1163 	}
1164 	bool isDirectory = S_ISDIR(st.st_mode);
1165 
1166 	Ancestor* fromAncestor = _GetAncestor(fromEntryRef.DirectoryNodeRef());
1167 	Ancestor* toAncestor = _GetAncestor(toEntryRef.DirectoryNodeRef());
1168 
1169 	if (_WatchRecursively()) {
1170 		Node* fromDirectoryNode = _GetNode(fromEntryRef.DirectoryNodeRef());
1171 		Node* toDirectoryNode = _GetNode(toEntryRef.DirectoryNodeRef());
1172 		if (fromDirectoryNode != NULL || toDirectoryNode != NULL) {
1173 			// Check whether _EntryRemoved()/_EntryCreated() can handle the
1174 			// respective entry regularly (i.e. don't encounter an out-of-sync
1175 			// issue) or don't need to be called at all (entry outside the
1176 			// monitored tree).
1177 			if ((fromDirectoryNode == NULL
1178 					|| _EntryRemoved(fromEntryRef, nodeRef, true, false, NULL))
1179 				&& (toDirectoryNode == NULL
1180 					|| _EntryCreated(toEntryRef, nodeRef, isDirectory, true,
1181 						false, NULL))) {
1182 				// The entries can be handled regularly. We delegate the work to
1183 				// _EntryRemoved() and _EntryCreated() and only handle the
1184 				// notification ourselves.
1185 
1186 				// handle removed
1187 				Entry* removedEntry = NULL;
1188 				if (fromDirectoryNode != NULL) {
1189 					_EntryRemoved(fromEntryRef, nodeRef, false, false,
1190 						&removedEntry);
1191 				}
1192 
1193 				// handle created
1194 				Entry* createdEntry = NULL;
1195 				if (toDirectoryNode != NULL) {
1196 					_EntryCreated(toEntryRef, nodeRef, isDirectory, false,
1197 						false, &createdEntry);
1198 				}
1199 
1200 				// notify
1201 				if (_WatchFilesOnly() && isDirectory) {
1202 					// recursively iterate through the removed and created
1203 					// hierarchy and send notifications for the files
1204 					if (removedEntry != NULL) {
1205 						_NotifyFilesCreatedOrRemoved(removedEntry,
1206 							B_ENTRY_REMOVED);
1207 					}
1208 
1209 					if (createdEntry != NULL) {
1210 						_NotifyFilesCreatedOrRemoved(createdEntry,
1211 							B_ENTRY_CREATED);
1212 					}
1213 				} else {
1214 					BString fromPath;
1215 					if (fromDirectoryNode != NULL) {
1216 						fromPath = make_path(_NodePath(fromDirectoryNode),
1217 							fromEntryRef.name);
1218 					}
1219 
1220 					BString path;
1221 					if (toDirectoryNode != NULL) {
1222 						path = make_path(_NodePath(toDirectoryNode),
1223 							toEntryRef.name);
1224 					}
1225 
1226 					_NotifyEntryMoved(fromEntryRef, toEntryRef, nodeRef,
1227 						fromPath, path, isDirectory, fromDirectoryNode == NULL,
1228 						toDirectoryNode == NULL);
1229 				}
1230 
1231 				if (removedEntry != NULL)
1232 					_DeleteEntry(removedEntry, false);
1233 			} else {
1234 				// The entries can't be handled regularly. We delegate all the
1235 				// work to _EntryRemoved() and _EntryCreated(). This will
1236 				// generate separate entry-removed and entry-created
1237 				// notifications.
1238 
1239 				// handle removed
1240 				if (fromDirectoryNode != NULL)
1241 					_EntryRemoved(fromEntryRef, nodeRef, false, true, NULL);
1242 
1243 				// handle created
1244 				if (toDirectoryNode != NULL) {
1245 					_EntryCreated(toEntryRef, nodeRef, isDirectory, false, true,
1246 						NULL);
1247 				}
1248 			}
1249 
1250 			return;
1251 		}
1252 
1253 		if (fromAncestor == fBaseAncestor || toAncestor == fBaseAncestor) {
1254 			// That should never happen, as we should have found a matching
1255 			// directory node in this case.
1256 #ifdef DEBUG
1257 			debugger("path ancestor exists, but doesn't have a directory");
1258 			// Could actually be an out-of-memory situation, if we simply failed
1259 			// to create the directory earlier.
1260 #endif
1261 			_StopWatchingAncestors(fRoot, false);
1262 			_StartWatchingAncestors(fRoot, false);
1263 			return;
1264 		}
1265 	} else {
1266 		// Non-recursive mode: This notification is only of interest to us, if
1267 		// it is either a move into/within/out of the path and B_WATCH_DIRECTORY
1268 		// is set, or an ancestor might be affected.
1269 		if (fromAncestor == NULL && toAncestor == NULL)
1270 			return;
1271 
1272 		if (fromAncestor == fBaseAncestor || toAncestor == fBaseAncestor) {
1273 			if ((fFlags & B_WATCH_DIRECTORY) != 0) {
1274 				BString fromPath;
1275 				if (fromAncestor == fBaseAncestor)
1276 					fromPath = make_path(fPath, fromEntryRef.name);
1277 
1278 				BString path;
1279 				if (toAncestor == fBaseAncestor)
1280 					path = make_path(fPath, toEntryRef.name);
1281 
1282 				_NotifyEntryMoved(fromEntryRef, toEntryRef, nodeRef,
1283 					fromPath, path, isDirectory, fromAncestor == NULL,
1284 					toAncestor == NULL);
1285 			}
1286 			return;
1287 		}
1288 	}
1289 
1290 	if (fromAncestor == NULL && toAncestor == NULL)
1291 		return;
1292 
1293 	if (fromAncestor == NULL) {
1294 		_EntryCreated(toEntryRef, nodeRef, isDirectory, false, true, NULL);
1295 		return;
1296 	}
1297 
1298 	if (toAncestor == NULL) {
1299 		_EntryRemoved(fromEntryRef, nodeRef, false, true, NULL);
1300 		return;
1301 	}
1302 
1303 	// An entry was moved in a true ancestor directory or between true ancestor
1304 	// directories. Unless the moved entry was or becomes our base ancestor, we
1305 	// let _EntryRemoved() and _EntryCreated() handle it.
1306 	bool fromIsBase = fromAncestor == fBaseAncestor->Parent()
1307 		&& strcmp(fromEntryRef.name, fBaseAncestor->Name()) == 0;
1308 	bool toIsBase = toAncestor == fBaseAncestor->Parent()
1309 		&& strcmp(toEntryRef.name, fBaseAncestor->Name()) == 0;
1310 	if (fromIsBase || toIsBase) {
1311 		// This might be a duplicate notification. Check whether our model
1312 		// already reflects the change. Otherwise stop/start watching the base
1313 		// ancestor as required.
1314 		bool notifyFilesRecursively = _WatchFilesOnly() && isDirectory;
1315 		if (fromIsBase) {
1316 			if (!fBaseAncestor->Exists())
1317 				return;
1318 			_StopWatchingAncestors(fBaseAncestor, notifyFilesRecursively);
1319 		} else {
1320 			if (fBaseAncestor->Exists()) {
1321 				if (fBaseAncestor->NodeRef() == nodeRef
1322 					&& isDirectory == fBaseAncestor->IsDirectory()) {
1323 					return;
1324 				}
1325 
1326 				// We're out of sync with reality.
1327 				_StopWatchingAncestors(fBaseAncestor, true);
1328 				_StartWatchingAncestors(fBaseAncestor, true);
1329 				return;
1330 			}
1331 
1332 			_StartWatchingAncestors(fBaseAncestor, notifyFilesRecursively);
1333 		}
1334 
1335 		if (!notifyFilesRecursively) {
1336 			_NotifyEntryMoved(fromEntryRef, toEntryRef, nodeRef,
1337 				fromIsBase ? fPath.String() : NULL,
1338 				toIsBase ? fPath.String() : NULL,
1339 				isDirectory, toIsBase, fromIsBase);
1340 		}
1341 		return;
1342 	}
1343 
1344 	_EntryRemoved(fromEntryRef, nodeRef, false, true, NULL);
1345 	_EntryCreated(toEntryRef, nodeRef, isDirectory, false, true, NULL);
1346 }
1347 
1348 
1349 void
1350 PathHandler::_NodeChanged(BMessage* message)
1351 {
1352 	node_ref nodeRef;
1353 
1354 	if (message->FindInt32("device", &nodeRef.device) != B_OK
1355 		|| message->FindInt64("node", &nodeRef.node) != B_OK) {
1356 		return;
1357 	}
1358 
1359 	TRACE("%p->PathHandler::_NodeChanged(): node: %" B_PRIdDEV ":%" B_PRIdINO
1360 		", %s%s\n", this, nodeRef.device, nodeRef.node,
1361 			message->GetInt32("opcode", B_STAT_CHANGED) == B_ATTR_CHANGED
1362 				? "attribute: " : "stat",
1363 			message->GetInt32("opcode", B_STAT_CHANGED) == B_ATTR_CHANGED
1364 				? message->GetString("attr", "") : "");
1365 
1366 	bool isDirectory = false;
1367 	BString path;
1368 	if (Ancestor* ancestor = _GetAncestor(nodeRef)) {
1369 		if (ancestor != fBaseAncestor)
1370 			return;
1371 		isDirectory = ancestor->IsDirectory();
1372 		path = fPath;
1373 	} else if (Node* node = _GetNode(nodeRef)) {
1374 		isDirectory = node->IsDirectory();
1375 		path = _NodePath(node);
1376 	} else
1377 		return;
1378 
1379 	if (isDirectory ? _WatchFilesOnly() : _WatchDirectoriesOnly())
1380 		return;
1381 
1382 	_NotifyTarget(*message, path);
1383 }
1384 
1385 
1386 bool
1387 PathHandler::_EntryCreated(const NotOwningEntryRef& entryRef,
1388 	const node_ref& nodeRef, bool isDirectory, bool dryRun, bool notify,
1389 	Entry** _entry)
1390 {
1391 	if (_entry != NULL)
1392 		*_entry = NULL;
1393 
1394 	Ancestor* ancestor = _GetAncestor(nodeRef);
1395 	if (ancestor != NULL) {
1396 		if (isDirectory == ancestor->IsDirectory()
1397 			&& entryRef == ancestor->EntryRef()) {
1398 			// just a duplicate notification
1399 			TRACE("  -> we already know the ancestor\n");
1400 			return true;
1401 		}
1402 
1403 		struct stat ancestorStat;
1404 		if (BEntry(&ancestor->EntryRef()).GetStat(&ancestorStat) == B_OK
1405 			&& node_ref(ancestorStat.st_dev, ancestorStat.st_ino)
1406 				== ancestor->NodeRef()
1407 			&& S_ISDIR(ancestorStat.st_mode) == ancestor->IsDirectory()) {
1408 			// Our information for the ancestor is up-to-date, so ignore the
1409 			// notification.
1410 			TRACE("  -> we know a different ancestor, but our info is "
1411 				"up-to-date\n");
1412 			return true;
1413 		}
1414 
1415 		// We're out of sync with reality.
1416 		TRACE("  -> ancestor mismatch -> resyncing\n");
1417 		if (!dryRun) {
1418 			_StopWatchingAncestors(ancestor, true);
1419 			_StartWatchingAncestors(ancestor, true);
1420 		}
1421 		return false;
1422 	}
1423 
1424 	ancestor = _GetAncestor(entryRef.DirectoryNodeRef());
1425 	if (ancestor != NULL) {
1426 		if (ancestor != fBaseAncestor) {
1427 			// The directory is a true ancestor -- the notification is only of
1428 			// interest, if the entry matches the child ancestor.
1429 			Ancestor* childAncestor = ancestor->Child();
1430 			if (strcmp(entryRef.name, childAncestor->Name()) != 0) {
1431 				TRACE("  -> not an ancestor entry we're interested in "
1432 					"(\"%s\")\n", childAncestor->Name());
1433 				return true;
1434 			}
1435 
1436 			if (!dryRun) {
1437 				if (childAncestor->Exists()) {
1438 					TRACE("  ancestor entry mismatch -> resyncing\n");
1439 					// We're out of sync with reality -- the new entry refers to
1440 					// a different node.
1441 					_StopWatchingAncestors(childAncestor, true);
1442 				}
1443 
1444 				TRACE("  -> starting to watch newly appeared ancestor\n");
1445 				_StartWatchingAncestors(childAncestor, true);
1446 			}
1447 			return false;
1448 		}
1449 
1450 		// The directory is our path. If watching recursively, just fall
1451 		// through. Otherwise, we want to pass on the notification, if directory
1452 		// watching is enabled.
1453 		if (!_WatchRecursively()) {
1454 			if ((fFlags & B_WATCH_DIRECTORY) != 0) {
1455 				_NotifyEntryCreatedOrRemoved(entryRef, nodeRef,
1456 					make_path(fPath, entryRef.name), isDirectory,
1457 					B_ENTRY_CREATED);
1458 			}
1459 			return true;
1460 		}
1461 	}
1462 
1463 	if (!_WatchRecursively()) {
1464 		// That shouldn't happen, since we only watch the ancestors in this
1465 		// case.
1466 		return true;
1467 	}
1468 
1469 	Node* directoryNode = _GetNode(entryRef.DirectoryNodeRef());
1470 	if (directoryNode == NULL)
1471 		return true;
1472 
1473 	Directory* directory = directoryNode->ToDirectory();
1474 	if (directory == NULL) {
1475 		// We're out of sync with reality.
1476 		if (!dryRun) {
1477 			if (Entry* nodeEntry = directory->FirstNodeEntry()) {
1478 				// remove the entry that is in the way and re-add the proper
1479 				// entry
1480 				NotOwningEntryRef directoryEntryRef = nodeEntry->EntryRef();
1481 				BString directoryName = nodeEntry->Name();
1482 				_DeleteEntry(nodeEntry, true);
1483 				_EntryCreated(directoryEntryRef, entryRef.DirectoryNodeRef(),
1484 					true, false, notify, NULL);
1485 			} else {
1486 				// It's either the base node or something's severely fishy.
1487 				// Resync the whole path.
1488 				_StopWatchingAncestors(fBaseAncestor, true);
1489 				_StartWatchingAncestors(fBaseAncestor, true);
1490 			}
1491 		}
1492 
1493 		return false;
1494 	}
1495 
1496 	// Check, if there's a colliding entry.
1497 	if (Entry* nodeEntry = directory->FindEntry(entryRef.name)) {
1498 		Node* entryNode = nodeEntry->Node();
1499 		if (entryNode->NodeRef() == nodeRef)
1500 			return true;
1501 
1502 		// We're out of sync with reality -- the new entry refers to a different
1503 		// node.
1504 		_DeleteEntry(nodeEntry, true);
1505 	}
1506 
1507 	if (dryRun)
1508 		return true;
1509 
1510 	_AddEntryIfNeeded(directory, entryRef.name, nodeRef, isDirectory, notify,
1511 		_entry);
1512 	return true;
1513 }
1514 
1515 
1516 bool
1517 PathHandler::_EntryRemoved(const NotOwningEntryRef& entryRef,
1518 	const node_ref& nodeRef, bool dryRun, bool notify, Entry** _keepEntry)
1519 {
1520 	if (_keepEntry != NULL)
1521 		*_keepEntry = NULL;
1522 
1523 	Ancestor* ancestor = _GetAncestor(nodeRef);
1524 	if (ancestor != NULL) {
1525 		// The node is an ancestor. If this is a true match, stop watching the
1526 		// ancestor.
1527 		if (!ancestor->Exists())
1528 			return true;
1529 
1530 		if (entryRef != ancestor->EntryRef()) {
1531 			// We might be out of sync with reality -- the new entry refers to a
1532 			// different node.
1533 			struct stat ancestorStat;
1534 			if (BEntry(&ancestor->EntryRef()).GetStat(&ancestorStat) != B_OK) {
1535 				if (!dryRun)
1536 					_StopWatchingAncestors(ancestor, true);
1537 				return false;
1538 			}
1539 
1540 			if (node_ref(ancestorStat.st_dev, ancestorStat.st_ino)
1541 					!= ancestor->NodeRef()
1542 				|| S_ISDIR(ancestorStat.st_mode) != ancestor->IsDirectory()) {
1543 				if (!dryRun) {
1544 					_StopWatchingAncestors(ancestor, true);
1545 					_StartWatchingAncestors(ancestor, true);
1546 				}
1547 				return false;
1548 			}
1549 			return true;
1550 		}
1551 
1552 		if (!dryRun)
1553 			_StopWatchingAncestors(ancestor, true);
1554 		return false;
1555 	}
1556 
1557 	ancestor = _GetAncestor(entryRef.DirectoryNodeRef());
1558 	if (ancestor != NULL) {
1559 		if (ancestor != fBaseAncestor) {
1560 			// The directory is a true ancestor -- the notification cannot be
1561 			// of interest, since the node didn't match a known ancestor.
1562 			return true;
1563 		}
1564 
1565 		// The directory is our path. If watching recursively, just fall
1566 		// through. Otherwise, we want to pass on the notification, if directory
1567 		// watching is enabled.
1568 		if (!_WatchRecursively()) {
1569 			if (notify && (fFlags & B_WATCH_DIRECTORY) != 0) {
1570 				_NotifyEntryCreatedOrRemoved(entryRef, nodeRef,
1571 					make_path(fPath, entryRef.name), false, B_ENTRY_REMOVED);
1572 					// We don't know whether this was a directory, but it
1573 					// doesn't matter in this case.
1574 			}
1575 			return true;
1576 		}
1577 	}
1578 
1579 	if (!_WatchRecursively()) {
1580 		// That shouldn't happen, since we only watch the ancestors in this
1581 		// case.
1582 		return true;
1583 	}
1584 
1585 	Node* directoryNode = _GetNode(entryRef.DirectoryNodeRef());
1586 	if (directoryNode == NULL) {
1587 		// We shouldn't get a notification, if we don't known the directory.
1588 		return true;
1589 	}
1590 
1591 	Directory* directory = directoryNode->ToDirectory();
1592 	if (directory == NULL) {
1593 		// We might be out of sync with reality or the notification is just
1594 		// late. The former case is extremely unlikely (we are watching the node
1595 		// and its parent directory after all) and rather hard to verify.
1596 		return true;
1597 	}
1598 
1599 	Entry* nodeEntry = directory->FindEntry(entryRef.name);
1600 	if (nodeEntry == NULL) {
1601 		// might be a non-directory node while we're in directories-only mode
1602 		return true;
1603 	}
1604 
1605 	if (!dryRun) {
1606 		if (_keepEntry != NULL)
1607 			*_keepEntry = nodeEntry;
1608 		else
1609 			_DeleteEntry(nodeEntry, notify);
1610 	}
1611 	return true;
1612 }
1613 
1614 
1615 bool
1616 PathHandler::_CheckDuplicateEntryNotification(int32 opcode,
1617 	const entry_ref& toEntryRef, const node_ref& nodeRef,
1618 	const entry_ref* fromEntryRef)
1619 {
1620 	if (opcode == fDuplicateEntryNotificationOpcode
1621 		&& nodeRef == fDuplicateEntryNotificationNodeRef
1622 		&& toEntryRef == fDuplicateEntryNotificationToEntryRef
1623 		&& (fromEntryRef == NULL
1624 			|| *fromEntryRef == fDuplicateEntryNotificationFromEntryRef)) {
1625 		return true;
1626 	}
1627 
1628 	fDuplicateEntryNotificationOpcode = opcode;
1629 	fDuplicateEntryNotificationNodeRef = nodeRef;
1630 	fDuplicateEntryNotificationToEntryRef = toEntryRef;
1631 	fDuplicateEntryNotificationFromEntryRef = fromEntryRef != NULL
1632 		? *fromEntryRef : entry_ref();
1633 	return false;
1634 }
1635 
1636 
1637 void
1638 PathHandler::_UnsetDuplicateEntryNotification()
1639 {
1640 	fDuplicateEntryNotificationOpcode = B_STAT_CHANGED;
1641 	fDuplicateEntryNotificationNodeRef = node_ref();
1642 	fDuplicateEntryNotificationFromEntryRef = entry_ref();
1643 	fDuplicateEntryNotificationToEntryRef = entry_ref();
1644 }
1645 
1646 
1647 Ancestor*
1648 PathHandler::_GetAncestor(const node_ref& nodeRef) const
1649 {
1650 	return fAncestors.Lookup(nodeRef);
1651 }
1652 
1653 
1654 status_t
1655 PathHandler::_AddNode(const node_ref& nodeRef, bool isDirectory, bool notify,
1656 	Entry* entry, Node** _node)
1657 {
1658 	TRACE("%p->PathHandler::_AddNode(%" B_PRIdDEV ":%" B_PRIdINO
1659 		", isDirectory: %d, notify: %d)\n", this, nodeRef.device, nodeRef.node,
1660 		isDirectory, notify);
1661 
1662 	// If hard links are supported, we may already know the node.
1663 	Node* node = _GetNode(nodeRef);
1664 	if (node != NULL) {
1665 		if (entry != NULL) {
1666 			entry->SetNode(node);
1667 			node->AddNodeEntry(entry);
1668 		}
1669 
1670 		if (_node != NULL)
1671 			*_node = node;
1672 		return B_OK;
1673 	}
1674 
1675 	// create the node
1676 	Directory* directoryNode = NULL;
1677 	if (isDirectory)
1678 		node = directoryNode = Directory::Create(nodeRef);
1679 	else
1680 		node = new(std::nothrow) Node(nodeRef);
1681 
1682 	if (node == NULL)
1683 		return B_NO_MEMORY;
1684 
1685 	ObjectDeleter<Node> nodeDeleter(node);
1686 
1687 	// start watching (don't do that for the base node, since we watch it
1688 	// already via fBaseAncestor)
1689 	if (nodeRef != fBaseAncestor->NodeRef()) {
1690 		uint32 flags = (fFlags & WATCH_NODE_FLAG_MASK) | B_WATCH_DIRECTORY;
1691 		status_t error = sWatchingInterface->WatchNode(&nodeRef, flags, this);
1692 		if (error != B_OK)
1693 			return error;
1694 	}
1695 
1696 	fNodes.Insert(nodeDeleter.Detach());
1697 
1698 	if (entry != NULL) {
1699 		entry->SetNode(node);
1700 		node->AddNodeEntry(entry);
1701 	}
1702 
1703 	if (_node != NULL)
1704 		*_node = node;
1705 
1706 	if (!isDirectory)
1707 		return B_OK;
1708 
1709 	// recursively add the directory's descendents
1710 	BDirectory directory;
1711 	if (directory.SetTo(&nodeRef) != B_OK) {
1712 		if (_node != NULL)
1713 			*_node = node;
1714 		return B_OK;
1715 	}
1716 
1717 	entry_ref entryRef;
1718 	while (directory.GetNextRef(&entryRef) == B_OK) {
1719 		struct stat st;
1720 		if (BEntry(&entryRef).GetStat(&st) != B_OK)
1721 			continue;
1722 
1723 		bool isDirectory = S_ISDIR(st.st_mode);
1724 		status_t error = _AddEntryIfNeeded(directoryNode, entryRef.name,
1725 			node_ref(st.st_dev, st.st_ino), isDirectory, notify);
1726 		if (error != B_OK) {
1727 			TRACE("%p->PathHandler::_AddNode(%" B_PRIdDEV ":%" B_PRIdINO
1728 				", isDirectory: %d, notify: %d): failed to add directory "
1729 				"entry: \"%s\"\n", this, nodeRef.device, nodeRef.node,
1730 				isDirectory, notify, entryRef.name);
1731 			continue;
1732 		}
1733 	}
1734 
1735 	return B_OK;
1736 }
1737 
1738 
1739 void
1740 PathHandler::_DeleteNode(Node* node, bool notify)
1741 {
1742 	if (Directory* directory = node->ToDirectory()) {
1743 		Entry* entry = directory->RemoveAllEntries();
1744 		while (entry != NULL) {
1745 			Entry* nextEntry = entry->HashNext();
1746 			_DeleteEntryAlreadyRemovedFromParent(entry, notify);
1747 			entry = nextEntry;
1748 		}
1749 	}
1750 
1751 	if (node->NodeRef() != fBaseAncestor->NodeRef())
1752 		sWatchingInterface->WatchNode(&node->NodeRef(), B_STOP_WATCHING, this);
1753 
1754 	fNodes.Remove(node);
1755 	delete node;
1756 }
1757 
1758 
1759 Node*
1760 PathHandler::_GetNode(const node_ref& nodeRef) const
1761 {
1762 	return fNodes.Lookup(nodeRef);
1763 }
1764 
1765 
1766 status_t
1767 PathHandler::_AddEntryIfNeeded(Directory* directory, const char* name,
1768 	const node_ref& nodeRef, bool isDirectory, bool notify,
1769 	Entry** _entry)
1770 {
1771 	TRACE("%p->PathHandler::_AddEntryIfNeeded(%" B_PRIdDEV ":%" B_PRIdINO
1772 		":\"%s\", %" B_PRIdDEV ":%" B_PRIdINO
1773 		", isDirectory: %d, notify: %d)\n", this, directory->NodeRef().device,
1774 		directory->NodeRef().node, name, nodeRef.device, nodeRef.node,
1775 		isDirectory, notify);
1776 
1777 	if (!isDirectory && _WatchDirectoriesOnly()) {
1778 		if (_entry != NULL)
1779 			*_entry = NULL;
1780 		return B_OK;
1781 	}
1782 
1783 	Entry* entry = directory->CreateEntry(name, NULL);
1784 	if (entry == NULL)
1785 		return B_NO_MEMORY;
1786 
1787 	status_t error = _AddNode(nodeRef, isDirectory, notify && _WatchFilesOnly(),
1788 		entry);
1789 	if (error != B_OK) {
1790 		directory->RemoveEntry(entry);
1791 		delete entry;
1792 		return error;
1793 	}
1794 
1795 	if (notify)
1796 		_NotifyEntryCreatedOrRemoved(entry, B_ENTRY_CREATED);
1797 
1798 	if (_entry != NULL)
1799 		*_entry = entry;
1800 	return B_OK;
1801 }
1802 
1803 
1804 void
1805 PathHandler::_DeleteEntry(Entry* entry, bool notify)
1806 {
1807 	entry->Parent()->RemoveEntry(entry);
1808 	_DeleteEntryAlreadyRemovedFromParent(entry, notify);
1809 }
1810 
1811 
1812 void
1813 PathHandler::_DeleteEntryAlreadyRemovedFromParent(Entry* entry, bool notify)
1814 {
1815 	if (notify)
1816 		_NotifyEntryCreatedOrRemoved(entry, B_ENTRY_REMOVED);
1817 
1818 	Node* node = entry->Node();
1819 	if (node->IsOnlyNodeEntry(entry))
1820 		_DeleteNode(node, notify && _WatchFilesOnly());
1821 
1822 	delete entry;
1823 }
1824 
1825 
1826 void
1827 PathHandler::_NotifyFilesCreatedOrRemoved(Entry* entry, int32 opcode) const
1828 {
1829 	Directory* directory = entry->Node()->ToDirectory();
1830 	if (directory == NULL) {
1831 		_NotifyEntryCreatedOrRemoved(entry, opcode);
1832 		return;
1833 	}
1834 
1835 	for (EntryMap::Iterator it = directory->GetEntryIterator(); it.HasNext();)
1836 		_NotifyFilesCreatedOrRemoved(it.Next(), opcode);
1837 }
1838 
1839 
1840 void
1841 PathHandler::_NotifyEntryCreatedOrRemoved(Entry* entry, int32 opcode) const
1842 {
1843 	Node* node = entry->Node();
1844 	_NotifyEntryCreatedOrRemoved(
1845 		NotOwningEntryRef(entry->Parent()->NodeRef(), entry->Name()),
1846 		node->NodeRef(), _EntryPath(entry), node->IsDirectory(), opcode);
1847 }
1848 
1849 
1850 void
1851 PathHandler::_NotifyEntryCreatedOrRemoved(const entry_ref& entryRef,
1852 	const node_ref& nodeRef, const char* path, bool isDirectory, int32 opcode)
1853 	const
1854 {
1855 	if (isDirectory ? _WatchFilesOnly() : _WatchDirectoriesOnly())
1856 		return;
1857 
1858 	TRACE("%p->PathHandler::_NotifyEntryCreatedOrRemoved(): entry %s: %"
1859 		B_PRIdDEV ":%" B_PRIdINO ":\"%s\", node: %" B_PRIdDEV ":%" B_PRIdINO
1860 		"\n", this, opcode == B_ENTRY_CREATED ? "created" : "removed",
1861 		entryRef.device, entryRef.directory, entryRef.name, nodeRef.device,
1862 		nodeRef.node);
1863 
1864 	BMessage message(B_PATH_MONITOR);
1865 	message.AddInt32("opcode", opcode);
1866 	message.AddInt32("device", entryRef.device);
1867 	message.AddInt64("directory", entryRef.directory);
1868 	message.AddInt32("node device", nodeRef.device);
1869 		// This field is not in a usual node monitoring message, since the node
1870 		// the created/removed entry refers to always belongs to the same FS as
1871 		// the directory, as another FS cannot yet/no longer be mounted there.
1872 		// In our case, however, this can very well be the case, e.g. when the
1873 		// the notification is triggered in response to a directory tree having
1874 		// been moved into/out of our path.
1875 	message.AddInt64("node", nodeRef.node);
1876 	message.AddString("name", entryRef.name);
1877 
1878 	_NotifyTarget(message, path);
1879 }
1880 
1881 
1882 void
1883 PathHandler::_NotifyEntryMoved(const entry_ref& fromEntryRef,
1884 	const entry_ref& toEntryRef, const node_ref& nodeRef, const char* fromPath,
1885 	const char* path, bool isDirectory, bool wasAdded, bool wasRemoved) const
1886 {
1887 	if ((isDirectory && _WatchFilesOnly())
1888 		|| (!isDirectory && _WatchDirectoriesOnly())) {
1889 		return;
1890 	}
1891 
1892 	TRACE("%p->PathHandler::_NotifyEntryMoved(): entry: %" B_PRIdDEV ":%"
1893 		B_PRIdINO ":\"%s\" -> %" B_PRIdDEV ":%" B_PRIdINO ":\"%s\", node: %"
1894 		B_PRIdDEV ":%" B_PRIdINO "\n", this, fromEntryRef.device,
1895 		fromEntryRef.directory, fromEntryRef.name, toEntryRef.device,
1896 		toEntryRef.directory, toEntryRef.name, nodeRef.device, nodeRef.node);
1897 
1898 	BMessage message(B_PATH_MONITOR);
1899 	message.AddInt32("opcode", B_ENTRY_MOVED);
1900 	message.AddInt32("device", fromEntryRef.device);
1901 	message.AddInt64("from directory", fromEntryRef.directory);
1902 	message.AddInt64("to directory", toEntryRef.directory);
1903 	message.AddInt32("node device", nodeRef.device);
1904 	message.AddInt64("node", nodeRef.node);
1905 	message.AddString("from name", fromEntryRef.name);
1906 	message.AddString("name", toEntryRef.name);
1907 
1908 	if (wasAdded)
1909 		message.AddBool("added", true);
1910 	if (wasRemoved)
1911 		message.AddBool("removed", true);
1912 
1913 	if (fromPath != NULL && fromPath[0] != '\0')
1914 		message.AddString("from path", fromPath);
1915 
1916 	_NotifyTarget(message, path);
1917 }
1918 
1919 
1920 void
1921 PathHandler::_NotifyTarget(BMessage& message, const char* path) const
1922 {
1923 	message.what = B_PATH_MONITOR;
1924 	if (path != NULL && path[0] != '\0')
1925 		message.AddString("path", path);
1926 	message.AddString("watched_path", fPath.String());
1927 	fTarget.SendMessage(&message);
1928 }
1929 
1930 
1931 
1932 BString
1933 PathHandler::_NodePath(const Node* node) const
1934 {
1935 	if (Entry* entry = node->FirstNodeEntry())
1936 		return _EntryPath(entry);
1937 	return node == fBaseNode ? fPath : BString();
1938 }
1939 
1940 
1941 BString
1942 PathHandler::_EntryPath(const Entry* entry) const
1943 {
1944 	return make_path(_NodePath(entry->Parent()), entry->Name());
1945 }
1946 
1947 
1948 bool
1949 PathHandler::_WatchRecursively() const
1950 {
1951 	return (fFlags & B_WATCH_RECURSIVELY) != 0;
1952 }
1953 
1954 
1955 bool
1956 PathHandler::_WatchFilesOnly() const
1957 {
1958 	return (fFlags & B_WATCH_FILES_ONLY) != 0;
1959 }
1960 
1961 
1962 bool
1963 PathHandler::_WatchDirectoriesOnly() const
1964 {
1965 	return (fFlags & B_WATCH_DIRECTORIES_ONLY) != 0;
1966 }
1967 
1968 
1969 } // namespace
1970 
1971 
1972 //	#pragma mark - BPathMonitor
1973 
1974 
1975 namespace BPrivate {
1976 
1977 
1978 BPathMonitor::BPathMonitor()
1979 {
1980 }
1981 
1982 
1983 BPathMonitor::~BPathMonitor()
1984 {
1985 }
1986 
1987 
1988 /*static*/ status_t
1989 BPathMonitor::StartWatching(const char* path, uint32 flags,
1990 	const BMessenger& target)
1991 {
1992 	TRACE("BPathMonitor::StartWatching(%s, %" B_PRIx32 ")\n", path, flags);
1993 
1994 	if (path == NULL || path[0] == '\0')
1995 		return B_BAD_VALUE;
1996 
1997 	// B_WATCH_FILES_ONLY and B_WATCH_DIRECTORIES_ONLY are mutual exclusive
1998 	if ((flags & B_WATCH_FILES_ONLY) != 0
1999 		&& (flags & B_WATCH_DIRECTORIES_ONLY) != 0) {
2000 		return B_BAD_VALUE;
2001 	}
2002 
2003 	status_t status = _InitIfNeeded();
2004 	if (status != B_OK)
2005 		return status;
2006 
2007 	BAutolock _(sLocker);
2008 
2009 	Watcher* watcher = sWatchers->Lookup(target);
2010 	bool newWatcher = false;
2011 	if (watcher != NULL) {
2012 		// If there's already a handler for the path, we'll replace it, but
2013 		// add its flags.
2014 		if (PathHandler* handler = watcher->Lookup(path)) {
2015 			// keep old flags save for conflicting mutually exclusive ones
2016 			uint32 oldFlags = handler->Flags();
2017 			const uint32 kMutuallyExclusiveFlags
2018 				= B_WATCH_FILES_ONLY | B_WATCH_DIRECTORIES_ONLY;
2019 			if ((flags & kMutuallyExclusiveFlags) != 0)
2020 				oldFlags &= ~(uint32)kMutuallyExclusiveFlags;
2021 			flags |= oldFlags;
2022 
2023 			watcher->Remove(handler);
2024 			handler->Quit();
2025 		}
2026 	} else {
2027 		watcher = Watcher::Create(target);
2028 		if (watcher == NULL)
2029 			return B_NO_MEMORY;
2030 		sWatchers->Insert(watcher);
2031 		newWatcher = true;
2032 	}
2033 
2034 	PathHandler* handler = new (std::nothrow) PathHandler(path, flags, target,
2035 		sLooper);
2036 	status = handler != NULL ? handler->InitCheck() : B_NO_MEMORY;
2037 
2038 	if (status != B_OK) {
2039 		if (handler != NULL)
2040 			handler->Quit();
2041 
2042 		if (newWatcher) {
2043 			sWatchers->Remove(watcher);
2044 			delete watcher;
2045 		}
2046 	}
2047 
2048 	watcher->Insert(handler);
2049 	return B_OK;
2050 }
2051 
2052 
2053 /*static*/ status_t
2054 BPathMonitor::StopWatching(const char* path, const BMessenger& target)
2055 {
2056 	if (sLocker == NULL)
2057 		return B_BAD_VALUE;
2058 
2059 	TRACE("BPathMonitor::StopWatching(%s)\n", path);
2060 
2061 	BAutolock _(sLocker);
2062 
2063 	Watcher* watcher = sWatchers->Lookup(target);
2064 	if (watcher == NULL)
2065 		return B_BAD_VALUE;
2066 
2067 	PathHandler* handler = watcher->Lookup(path);
2068 	if (handler == NULL)
2069 		return B_BAD_VALUE;
2070 
2071 	watcher->Remove(handler);
2072 	handler->Quit();
2073 
2074 	if (watcher->IsEmpty()) {
2075 		sWatchers->Remove(watcher);
2076 		delete watcher;
2077 	}
2078 
2079 	return B_OK;
2080 }
2081 
2082 
2083 /*static*/ status_t
2084 BPathMonitor::StopWatching(const BMessenger& target)
2085 {
2086 	if (sLocker == NULL)
2087 		return B_BAD_VALUE;
2088 
2089 	BAutolock _(sLocker);
2090 
2091 	Watcher* watcher = sWatchers->Lookup(target);
2092 	if (watcher == NULL)
2093 		return B_BAD_VALUE;
2094 
2095 	// delete handlers
2096 	PathHandler* handler = watcher->Clear(true);
2097 	while (handler != NULL) {
2098 		PathHandler* nextHandler = handler->HashNext();
2099 		handler->Quit();
2100 		handler = nextHandler;
2101 	}
2102 
2103 	sWatchers->Remove(watcher);
2104 	delete watcher;
2105 
2106 	return B_OK;
2107 }
2108 
2109 
2110 /*static*/ void
2111 BPathMonitor::SetWatchingInterface(BWatchingInterface* watchingInterface)
2112 {
2113 	sWatchingInterface = watchingInterface != NULL
2114 		? watchingInterface : sDefaultWatchingInterface;
2115 }
2116 
2117 
2118 /*static*/ status_t
2119 BPathMonitor::_InitIfNeeded()
2120 {
2121 	pthread_once(&sInitOnce, &BPathMonitor::_Init);
2122 	return sLooper != NULL ? B_OK : B_NO_MEMORY;
2123 }
2124 
2125 
2126 /*static*/ void
2127 BPathMonitor::_Init()
2128 {
2129 	sLocker = new (std::nothrow) BLocker("path monitor");
2130 	TRACE("Create PathMonitor locker\n");
2131 	if (sLocker == NULL)
2132 		return;
2133 
2134 	sDefaultWatchingInterface = new(std::nothrow) BWatchingInterface;
2135 	if (sDefaultWatchingInterface == NULL)
2136 		return;
2137 
2138 	sWatchers = new(std::nothrow) WatcherMap;
2139 	if (sWatchers == NULL || sWatchers->Init() != B_OK)
2140 		return;
2141 
2142 	if (sWatchingInterface == NULL)
2143 		SetWatchingInterface(sDefaultWatchingInterface);
2144 
2145 	BLooper* looper = new (std::nothrow) BLooper("PathMonitor looper");
2146 	TRACE("Start PathMonitor looper\n");
2147 	if (looper == NULL)
2148 		return;
2149 	thread_id thread = looper->Run();
2150 	if (thread < 0) {
2151 		delete looper;
2152 		return;
2153 	}
2154 
2155 	sLooper = looper;
2156 }
2157 
2158 
2159 // #pragma mark - BWatchingInterface
2160 
2161 
2162 BPathMonitor::BWatchingInterface::BWatchingInterface()
2163 {
2164 }
2165 
2166 
2167 BPathMonitor::BWatchingInterface::~BWatchingInterface()
2168 {
2169 }
2170 
2171 
2172 status_t
2173 BPathMonitor::BWatchingInterface::WatchNode(const node_ref* node, uint32 flags,
2174 	const BMessenger& target)
2175 {
2176 	return watch_node(node, flags, target);
2177 }
2178 
2179 
2180 status_t
2181 BPathMonitor::BWatchingInterface::WatchNode(const node_ref* node, uint32 flags,
2182 	const BHandler* handler, const BLooper* looper)
2183 {
2184 	return watch_node(node, flags, handler, looper);
2185 }
2186 
2187 
2188 status_t
2189 BPathMonitor::BWatchingInterface::StopWatching(const BMessenger& target)
2190 {
2191 	return stop_watching(target);
2192 }
2193 
2194 
2195 status_t
2196 BPathMonitor::BWatchingInterface::StopWatching(const BHandler* handler,
2197 	const BLooper* looper)
2198 {
2199 	return stop_watching(handler, looper);
2200 }
2201 
2202 
2203 }	// namespace BPrivate
2204