1 /*****************************************************************************/ 2 // FolderWatcher 3 // 4 // Author 5 // Michael Pfeiffer 6 // 7 // This application and all source files used in its construction, except 8 // where noted, are licensed under the MIT License, and have been written 9 // and are: 10 // 11 // Copyright (c) 2002 Haiku Project 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a 14 // copy of this software and associated documentation files (the "Software"), 15 // to deal in the Software without restriction, including without limitation 16 // the rights to use, copy, modify, merge, publish, distribute, sublicense, 17 // and/or sell copies of the Software, and to permit persons to whom the 18 // Software is furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included 21 // in all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 24 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 26 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 28 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 29 // DEALINGS IN THE SOFTWARE. 30 /*****************************************************************************/ 31 32 33 #include "FolderWatcher.h" 34 35 #include <stdio.h> 36 37 // BeOS 38 #include <kernel/fs_attr.h> 39 #include <Node.h> 40 #include <NodeInfo.h> 41 #include <NodeMonitor.h> 42 43 44 // Implementation of FolderWatcher 45 46 FolderWatcher::FolderWatcher(BLooper* looper, const BDirectory& folder, bool watchAttrChanges) 47 : fFolder(folder) 48 , fListener(NULL) 49 , fWatchAttrChanges(watchAttrChanges) 50 { 51 // add this handler to the application for node monitoring 52 if (looper->Lock()) { 53 looper->AddHandler(this); 54 looper->Unlock(); 55 } 56 57 // start attribute change watching for existing files 58 if (watchAttrChanges) { 59 BEntry entry; 60 node_ref node; 61 while (fFolder.GetNextEntry(&entry) == B_OK && entry.GetNodeRef(&node) == B_OK) { 62 StartAttrWatching(&node); 63 } 64 } 65 66 // start watching the spooler directory 67 node_ref ref; 68 fFolder.GetNodeRef(&ref); 69 watch_node(&ref, B_WATCH_DIRECTORY, this); 70 } 71 72 FolderWatcher::~FolderWatcher() { 73 // stop node watching for spooler directory 74 node_ref ref; 75 fFolder.GetNodeRef(&ref); 76 watch_node(&ref, B_STOP_WATCHING, this); 77 // stop sending notifications to this handler 78 stop_watching(this); 79 80 if (LockLooper()) { 81 BLooper* looper = Looper(); 82 // and remove it 83 looper->RemoveHandler(this); 84 looper->Unlock(); 85 } 86 } 87 88 void FolderWatcher::SetListener(FolderListener* listener) { 89 fListener = listener; 90 } 91 92 bool FolderWatcher::BuildEntryRef(BMessage* msg, const char* dirName, entry_ref* entry) { 93 const char* name; 94 if (msg->FindInt32("device", &entry->device) == B_OK && 95 msg->FindInt64(dirName, &entry->directory) == B_OK && 96 msg->FindString("name", &name) == B_OK) { 97 entry->set_name(name); 98 return true; 99 } 100 return false; 101 } 102 103 bool FolderWatcher::BuildNodeRef(BMessage* msg, node_ref* node) { 104 return (msg->FindInt32("device", &node->device) == B_OK && 105 msg->FindInt64("node", &node->node) == B_OK); 106 } 107 108 void FolderWatcher::HandleCreatedEntry(BMessage* msg, const char* dirName) { 109 node_ref node; 110 entry_ref entry; 111 if (BuildEntryRef(msg, dirName, &entry) && 112 BuildNodeRef(msg, &node)) { 113 if (fWatchAttrChanges) StartAttrWatching(&node); 114 fListener->EntryCreated(&node, &entry); 115 } 116 } 117 118 void FolderWatcher::HandleRemovedEntry(BMessage* msg) { 119 node_ref node; 120 if (BuildNodeRef(msg, &node)) { 121 if (fWatchAttrChanges) StopAttrWatching(&node); 122 fListener->EntryRemoved(&node); 123 } 124 } 125 126 void FolderWatcher::HandleChangedAttr(BMessage* msg) { 127 node_ref node; 128 if (BuildNodeRef(msg, &node)) { 129 fListener->AttributeChanged(&node); 130 } 131 } 132 133 void FolderWatcher::MessageReceived(BMessage* msg) { 134 int32 opcode; 135 node_ref folder; 136 ino_t dir; 137 138 if (msg->what == B_NODE_MONITOR) { 139 if (fListener == NULL || msg->FindInt32("opcode", &opcode) != B_OK) return; 140 141 switch (opcode) { 142 case B_ENTRY_CREATED: 143 HandleCreatedEntry(msg, "directory"); 144 break; 145 case B_ENTRY_REMOVED: 146 HandleRemovedEntry(msg); 147 break; 148 case B_ENTRY_MOVED: 149 fFolder.GetNodeRef(&folder); 150 if (msg->FindInt64("to directory", &dir) == B_OK && folder.node == dir) { 151 // entry moved into this folder 152 HandleCreatedEntry(msg, "to directory"); 153 } else if (msg->FindInt64("from directory", &dir) == B_OK && folder.node == dir) { 154 // entry removed from this folder 155 HandleRemovedEntry(msg); 156 } 157 break; 158 case B_ATTR_CHANGED: 159 HandleChangedAttr(msg); 160 break; 161 default: // nothing to do 162 break; 163 } 164 } else { 165 inherited::MessageReceived(msg); 166 } 167 } 168 169 status_t FolderWatcher::StartAttrWatching(node_ref* node) { 170 return watch_node(node, B_WATCH_ATTR, this); 171 } 172 173 status_t FolderWatcher::StopAttrWatching(node_ref* node) { 174 return watch_node(node, B_STOP_WATCHING, this); 175 } 176