Author: stippi Date: 2010-06-07 19:37:33 +0200 (Mon, 07 Jun 2010) New Revision: 37049 Changeset: http://dev.haiku-os.org/changeset/37049/haiku Modified: haiku/trunk/src/kits/storage/PathMonitor.cpp Log: Resolved TODO about recursively removing watched files and folders when a directory is moved outside the watched hierarchy or deleted entirely. It involves another TODO, because the generated notifications are B_ENTRY_REMOVED, while B_ENTRY_MOVED is probably more correct. Modified: haiku/trunk/src/kits/storage/PathMonitor.cpp =================================================================== --- haiku/trunk/src/kits/storage/PathMonitor.cpp 2010-06-07 17:12:56 UTC (rev 37048) +++ haiku/trunk/src/kits/storage/PathMonitor.cpp 2010-06-07 17:37:33 UTC (rev 37049) @@ -24,6 +24,7 @@ #include <map> #include <new> #include <set> +#include <stdio.h> #undef TRACE //#define TRACE_PATH_MONITOR @@ -125,6 +126,8 @@ status_t _RemoveFile(const node_ref& nodeRef); status_t _RemoveFile(BEntry& entry); + void _RemoveEntriesRecursively(BDirectory& directory); + BPath fPath; int32 fPathLength; BMessenger fTarget; @@ -771,8 +774,20 @@ fDirectories.erase(iterator); - // TODO: stop watching subdirectories and their files when in recursive - // mode! + // stop watching subdirectories and their files when in recursive mode + if (_WatchRecursively()) { + BDirectory entryDirectory(&nodeRef); + if (entryDirectory.InitCheck() == B_OK) { + // The directory still exists, but was moved outside our watched + // folder hierarchy. + _RemoveEntriesRecursively(entryDirectory); + } else { + // Actually, it shouldn't be possible to remove non-empty + // folders so for this case we don't need to do anything. We should + // have received remove notifications for all affected files and + // folders that used to live in this directory. + } + } return B_OK; } @@ -889,6 +904,57 @@ } +void +PathHandler::_RemoveEntriesRecursively(BDirectory& directory) +{ + node_ref directoryNode; + directory.GetNodeRef(&directoryNode); + + BMessage message(B_PATH_MONITOR); + message.AddInt32("opcode", B_ENTRY_REMOVED); + // TODO: B_ENTRY_MOVED could be regarded as more correct, + // but then we would definitely need more information in this + // function. + message.AddInt32("device", directoryNode.device); + message.AddInt64("directory", directoryNode.node); + message.AddInt64("node", 0LL); + // dummy node, will be replaced by real node + + // NOTE: The _NotifyTarget() gets the node id, but constructs + // the path to the previous location of the entry according to the file + // or folder in our sets. This makes it more expensive of course, but + // I have no inspiration for improvement at the moment. + + BEntry entry; + while (directory.GetNextEntry(&entry) == B_OK) { + node_ref nodeRef; + if (entry.GetNodeRef(&nodeRef) != B_OK) { + fprintf(stderr, "PathHandler::_RemoveEntriesRecursively() - " + "failed to get node_ref\n"); + continue; + } + + message.ReplaceInt64("node", nodeRef.node); + + if (entry.IsDirectory()) { + // notification + if (!_WatchFilesOnly()) + _NotifyTarget(&message, nodeRef); + + _RemoveDirectory(nodeRef, directoryNode.node); + BDirectory subDirectory(&entry); + _RemoveEntriesRecursively(subDirectory); + } else { + // notification + if (!_WatchFoldersOnly()) + _NotifyTarget(&message, nodeRef); + + _RemoveFile(nodeRef); + } + } +} + + // #pragma mark -