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
50namespace {
51
52
53class Directory;
54class Node;
55struct WatcherHashDefinition;
56typedef BOpenHashTable<WatcherHashDefinition> WatcherMap;
57
58
59static pthread_once_t sInitOnce = PTHREAD_ONCE_INIT;
60static WatcherMap* sWatchers = NULL;
61static BLooper* sLooper = NULL;
62static BPathMonitor::BWatchingInterface* sDefaultWatchingInterface = NULL;
63static 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 */
72static BString
73make_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
96class Ancestor {
97public:
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
117	Ancestor* Parent() const
118	{
119		return fParent;
120	}
121
122	Ancestor* Child() const
123	{
124		return fChild;
125	}
126
127	const BString& Path() const
128	{
129		return fPath;
130	}
131
132	const char* Name() const
133	{
134		return fEntryRef.name;
135	}
136
137	bool Exists() const
138	{
139		return fNodeRef.device >= 0;
140	}
141
142	const NotOwningEntryRef& EntryRef() const
143	{
144		return fEntryRef;
145	}
146
147	const node_ref& NodeRef() const
148	{
149		return fNodeRef;
150	}
151
152	bool IsDirectory() const
153	{
154		return fIsDirectory;
155	}
156
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
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
214	Ancestor*& HashNext()
215	{
216		return fHashNext;
217	}
218
219private:
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
234struct AncestorHashDefinition {
235	typedef	node_ref	KeyType;
236	typedef	Ancestor	ValueType;
237
238	size_t HashKey(const node_ref& key) const
239	{
240		return size_t(key.device ^ key.node);
241	}
242
243	size_t Hash(Ancestor* value) const
244	{
245		return HashKey(value->NodeRef());
246	}
247
248	bool Compare(const node_ref& key, Ancestor* value) const
249	{
250		return key == value->NodeRef();
251	}
252
253	Ancestor*& GetLink(Ancestor* value) const
254	{
255		return value->HashNext();
256	}
257};
258
259
260typedef BOpenHashTable<AncestorHashDefinition> AncestorMap;
261
262
263//	#pragma mark - Entry
264
265
266class Entry : public SinglyLinkedListLinkImpl<Entry> {
267public:
268	Entry(Directory* parent, const BString& name, ::Node* node)
269		:
270		fParent(parent),
271		fName(name),
272		fNode(node)
273	{
274	}
275
276	Directory* Parent() const
277	{
278		return fParent;
279	}
280
281	const BString& Name() const
282	{
283		return fName;
284	}
285
286	::Node* Node() const
287	{
288		return fNode;
289	}
290
291	void SetNode(::Node* node)
292	{
293		fNode = node;
294	}
295
296	inline NotOwningEntryRef EntryRef() const;
297
298	Entry*& HashNext()
299	{
300		return fHashNext;
301	}
302
303private:
304	Directory*	fParent;
305	BString		fName;
306	::Node*		fNode;
307	Entry*		fHashNext;
308};
309
310typedef SinglyLinkedList<Entry> EntryList;
311
312
313// EntryMap
314
315
316struct EntryHashDefinition {
317	typedef	const char*	KeyType;
318	typedef	Entry		ValueType;
319
320	size_t HashKey(const char* key) const
321	{
322		return BString::HashValue(key);
323	}
324
325	size_t Hash(Entry* value) const
326	{
327		return value->Name().HashValue();
328	}
329
330	bool Compare(const char* key, Entry* value) const
331	{
332		return value->Name() == key;
333	}
334
335	Entry*& GetLink(Entry* value) const
336	{
337		return value->HashNext();
338	}
339};
340
341
342typedef BOpenHashTable<EntryHashDefinition> EntryMap;
343
344
345//	#pragma mark - Node
346
347
348class Node {
349public:
350	Node(const node_ref& nodeRef)
351		:
352		fNodeRef(nodeRef)
353	{
354	}
355
356	virtual ~Node()
357	{
358	}
359
360	virtual bool IsDirectory() const
361	{
362		return false;
363	}
364
365	virtual Directory* ToDirectory()
366	{
367		return NULL;
368	}
369
370	const node_ref& NodeRef() const
371	{
372		return fNodeRef;
373	}
374
375	const EntryList& Entries() const
376	{
377		return fEntries;
378	}
379
380	bool HasEntries() const
381	{
382		return !fEntries.IsEmpty();
383	}
384
385	Entry* FirstNodeEntry() const
386	{
387		return fEntries.Head();
388	}
389
390	bool IsOnlyNodeEntry(Entry* entry) const
391	{
392		return entry == fEntries.Head() && fEntries.GetNext(entry) == NULL;
393	}
394
395	void AddNodeEntry(Entry* entry)
396	{
397		fEntries.Add(entry);
398	}
399
400	void RemoveNodeEntry(Entry* entry)
401	{
402		fEntries.Remove(entry);
403	}
404
405	Node*& HashNext()
406	{
407		return fHashNext;
408	}
409
410private:
411	node_ref			fNodeRef;
412	EntryList			fEntries;
413	Node*				fHashNext;
414};
415
416
417struct NodeHashDefinition {
418	typedef	node_ref	KeyType;
419	typedef	Node		ValueType;
420
421	size_t HashKey(const node_ref& key) const
422	{
423		return size_t(key.device ^ key.node);
424	}
425
426	size_t Hash(Node* value) const
427	{
428		return HashKey(value->NodeRef());
429	}
430
431	bool Compare(const node_ref& key, Node* value) const
432	{
433		return key == value->NodeRef();
434	}
435
436	Node*& GetLink(Node* value) const
437	{
438		return value->HashNext();
439	}
440};
441
442
443typedef BOpenHashTable<NodeHashDefinition> NodeMap;
444
445
446//	#pragma mark - Directory
447
448
449class Directory : public Node {
450public:
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
462	virtual bool IsDirectory() const
463	{
464		return true;
465	}
466
467	virtual Directory* ToDirectory()
468	{
469		return this;
470	}
471
472	Entry* FindEntry(const char* name) const
473	{
474		return fEntries.Lookup(name);
475	}
476
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
489	void AddEntry(Entry* entry)
490	{
491		fEntries.Insert(entry);
492	}
493
494	void RemoveEntry(Entry* entry)
495	{
496		fEntries.Remove(entry);
497	}
498
499	EntryMap::Iterator GetEntryIterator() const
500	{
501		return fEntries.GetIterator();
502	}
503
504	Entry* RemoveAllEntries()
505	{
506		return fEntries.Clear(true);
507	}
508
509private:
510	Directory(const node_ref& nodeRef)
511		:
512		Node(nodeRef)
513	{
514	}
515
516private:
517	EntryMap	fEntries;
518};
519
520
521//	#pragma mark - Entry
522
523
524inline NotOwningEntryRef
525Entry::EntryRef() const
526{
527	return NotOwningEntryRef(fParent->NodeRef(), fName);
528}
529
530
531//	#pragma mark - PathHandler
532
533
534class PathHandler : public BHandler {
535public:
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
543			const BString&		OriginalPath() const
544									{ return fOriginalPath; }
545			uint32				Flags() const	{ return fFlags; }
546
547	virtual	void				MessageReceived(BMessage* message);
548
549			PathHandler*&		HashNext()	{ return fHashNext; }
550
551private:
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
617private:
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
636struct PathHandlerHashDefinition {
637	typedef	const char*	KeyType;
638	typedef	PathHandler	ValueType;
639
640	size_t HashKey(const char* key) const
641	{
642		return BString::HashValue(key);
643	}
644
645	size_t Hash(PathHandler* value) const
646	{
647		return value->OriginalPath().HashValue();
648	}
649
650	bool Compare(const char* key, PathHandler* value) const
651	{
652		return key == value->OriginalPath();
653	}
654
655	PathHandler*& GetLink(PathHandler* value) const
656	{
657		return value->HashNext();
658	}
659};
660
661
662typedef BOpenHashTable<PathHandlerHashDefinition> PathHandlerMap;
663
664
665//	#pragma mark - Watcher
666
667
668struct Watcher : public PathHandlerMap {
669	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
679	const BMessenger& Target() const
680	{
681		return fTarget;
682	}
683
684	Watcher*& HashNext()
685	{
686		return fHashNext;
687	}
688
689private:
690	Watcher(const BMessenger& target)
691		:
692		fTarget(target)
693	{
694	}
695
696private:
697	BMessenger		fTarget;
698	Watcher*		fHashNext;
699};
700
701
702struct WatcherHashDefinition {
703	typedef	BMessenger	KeyType;
704	typedef	Watcher		ValueType;
705
706	size_t HashKey(const BMessenger& key) const
707	{
708		return key.HashValue();
709	}
710
711	size_t Hash(Watcher* value) const
712	{
713		return HashKey(value->Target());
714	}
715
716	bool Compare(const BMessenger& key, Watcher* value) const
717	{
718		return key == value->Target();
719	}
720
721	Watcher*& GetLink(Watcher* value) const
722	{
723		return value->HashNext();
724	}
725};
726
727
728//	#pragma mark - PathHandler
729
730
731PathHandler::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
851PathHandler::~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
867status_t
868PathHandler::InitCheck() const
869{
870	return fStatus;
871}
872
873
874void
875PathHandler::Quit()
876{
877	TRACE("%p->PathHandler::Quit()\n", this);
878	sWatchingInterface->StopWatching(this);
879	sLooper->RemoveHandler(this);
880	delete this;
881}
882
883
884void
885PathHandler::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
923status_t
924PathHandler::_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
964status_t
965PathHandler::_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
1011void
1012PathHandler::_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
1037void
1038PathHandler::_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
1089void
1090PathHandler::_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
1114void
1115PathHandler::_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
1337void
1338PathHandler::_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
1374bool
1375PathHandler::_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 = directory->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
1504bool
1505PathHandler::_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
1603bool
1604PathHandler::_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
1625void
1626PathHandler::_UnsetDuplicateEntryNotification()
1627{
1628	fDuplicateEntryNotificationOpcode = B_STAT_CHANGED;
1629	fDuplicateEntryNotificationNodeRef = node_ref();
1630	fDuplicateEntryNotificationFromEntryRef = entry_ref();
1631	fDuplicateEntryNotificationToEntryRef = entry_ref();
1632}
1633
1634
1635Ancestor*
1636PathHandler::_GetAncestor(const node_ref& nodeRef) const
1637{
1638	return fAncestors.Lookup(nodeRef);
1639}
1640
1641
1642status_t
1643PathHandler::_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
1727void
1728PathHandler::_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
1747Node*
1748PathHandler::_GetNode(const node_ref& nodeRef) const
1749{
1750	return fNodes.Lookup(nodeRef);
1751}
1752
1753
1754status_t
1755PathHandler::_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
1792void
1793PathHandler::_DeleteEntry(Entry* entry, bool notify)
1794{
1795	entry->Parent()->RemoveEntry(entry);
1796	_DeleteEntryAlreadyRemovedFromParent(entry, notify);
1797}
1798
1799
1800void
1801PathHandler::_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
1814void
1815PathHandler::_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
1828void
1829PathHandler::_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
1838void
1839PathHandler::_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
1870void
1871PathHandler::_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
1908void
1909PathHandler::_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
1920BString
1921PathHandler::_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
1929BString
1930PathHandler::_EntryPath(const Entry* entry) const
1931{
1932	return make_path(_NodePath(entry->Parent()), entry->Name());
1933}
1934
1935
1936bool
1937PathHandler::_WatchRecursively() const
1938{
1939	return (fFlags & B_WATCH_RECURSIVELY) != 0;
1940}
1941
1942
1943bool
1944PathHandler::_WatchFilesOnly() const
1945{
1946	return (fFlags & B_WATCH_FILES_ONLY) != 0;
1947}
1948
1949
1950bool
1951PathHandler::_WatchDirectoriesOnly() const
1952{
1953	return (fFlags & B_WATCH_DIRECTORIES_ONLY) != 0;
1954}
1955
1956
1957} // namespace
1958
1959
1960//	#pragma mark - BPathMonitor
1961
1962
1963namespace BPrivate {
1964
1965
1966BPathMonitor::BPathMonitor()
1967{
1968}
1969
1970
1971BPathMonitor::~BPathMonitor()
1972{
1973}
1974
1975
1976/*static*/ status_t
1977BPathMonitor::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
2043BPathMonitor::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
2073BPathMonitor::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
2100BPathMonitor::SetWatchingInterface(BWatchingInterface* watchingInterface)
2101{
2102	sWatchingInterface = watchingInterface != NULL
2103		? watchingInterface : sDefaultWatchingInterface;
2104}
2105
2106
2107/*static*/ status_t
2108BPathMonitor::_InitIfNeeded()
2109{
2110	pthread_once(&sInitOnce, &BPathMonitor::_Init);
2111	return sLooper != NULL ? B_OK : B_NO_MEMORY;
2112}
2113
2114
2115/*static*/ void
2116BPathMonitor::_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
2146BPathMonitor::BWatchingInterface::BWatchingInterface()
2147{
2148}
2149
2150
2151BPathMonitor::BWatchingInterface::~BWatchingInterface()
2152{
2153}
2154
2155
2156status_t
2157BPathMonitor::BWatchingInterface::WatchNode(const node_ref* node, uint32 flags,
2158	const BMessenger& target)
2159{
2160	return watch_node(node, flags, target);
2161}
2162
2163
2164status_t
2165BPathMonitor::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
2172status_t
2173BPathMonitor::BWatchingInterface::StopWatching(const BMessenger& target)
2174{
2175	return stop_watching(target);
2176}
2177
2178
2179status_t
2180BPathMonitor::BWatchingInterface::StopWatching(const BHandler* handler,
2181	const BLooper* looper)
2182{
2183	return stop_watching(handler, looper);
2184}
2185
2186
2187}	// namespace BPrivate
2188