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