00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00031
00032 #ifdef HAVE_CONFIG_H
00033 #include "autoconfig.h"
00034 #endif
00035
00036 #ifdef HAVE_INOTIFY
00037
00038 #include "autoscan_inotify.h"
00039 #include "content_manager.h"
00040
00041 #include <dirent.h>
00042 #include <sys/stat.h>
00043
00044 #define AUTOSCAN_INOTIFY_INITIAL_QUEUE_SIZE 20
00045
00046
00047 #define AUTOSCAN_INOTIFY_HASH_SIZE 30851
00048
00049 #define INOTIFY_MAX_USER_WATCHES_FILE "/proc/sys/fs/inotify/max_user_watches"
00050 using namespace zmm;
00051
00052 AutoscanInotify::AutoscanInotify()
00053 {
00054 mutex = Ref<Mutex>(new Mutex());
00055 cond = Ref<Cond>(new Cond(mutex));
00056
00057 int hash_size = AUTOSCAN_INOTIFY_HASH_SIZE;
00058
00059 if (check_path(_(INOTIFY_MAX_USER_WATCHES_FILE)))
00060 {
00061 int max_watches = -1;
00062 try
00063 {
00064 max_watches = trim_string(read_text_file(_(INOTIFY_MAX_USER_WATCHES_FILE))).toInt();
00065 log_debug("Max watches on the system: %d\n", max_watches);
00066 }
00067 catch (Exception ex)
00068 {
00069 log_error("Could not determine maximum number of inotify user watches: %s\n", ex.getMessage().c_str());
00070 }
00071
00072 if (max_watches > 0)
00073 hash_size = max_watches * 5;
00074 }
00075
00076 watches = Ref<DBOHash<int, Wd> >(new DBOHash<int, Wd>(hash_size, -1, -2));
00077 shutdownFlag = true;
00078 monitorQueue = Ref<ObjectQueue<AutoscanDirectory> >(new ObjectQueue<AutoscanDirectory>(AUTOSCAN_INOTIFY_INITIAL_QUEUE_SIZE));
00079 unmonitorQueue = Ref<ObjectQueue<AutoscanDirectory> >(new ObjectQueue<AutoscanDirectory>(AUTOSCAN_INOTIFY_INITIAL_QUEUE_SIZE));
00080 events = IN_CLOSE_WRITE | IN_CREATE | IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT;
00081 }
00082
00083 void AutoscanInotify::init()
00084 {
00085 AUTOLOCK(mutex);
00086 if (shutdownFlag)
00087 {
00088 shutdownFlag = false;
00089 inotify = Ref<Inotify>(new Inotify());
00090 log_debug("starting inotify thread...\n");
00091 int ret = pthread_create(
00092 &thread,
00093 NULL,
00094 AutoscanInotify::staticThreadProc,
00095 this
00096 );
00097
00098 if (ret)
00099 throw _Exception(_("failed to start inotify thread: ") + ret);
00100 }
00101 }
00102
00103 AutoscanInotify::~AutoscanInotify()
00104 {
00105 shutdown();
00106 }
00107
00108 void AutoscanInotify::shutdown()
00109 {
00110 AUTOLOCK(mutex);
00111 if (! shutdownFlag)
00112 {
00113 log_debug("start\n");
00114 shutdownFlag = true;
00115 inotify->stop();
00116 AUTOUNLOCK();
00117 if (thread)
00118 pthread_join(thread, NULL);
00119 thread = 0;
00120 log_debug("inotify thread died.\n");
00121 inotify = nil;
00122 watches->clear();
00123 }
00124 }
00125
00126 void *AutoscanInotify::staticThreadProc(void *arg)
00127 {
00128 log_debug("started inotify thread.\n");
00129 AutoscanInotify *inst = (AutoscanInotify *)arg;
00130 inst->threadProc();
00131 Storage::getInstance()->threadCleanup();
00132 log_debug("exiting inotify thread...\n");
00133 pthread_exit(NULL);
00134 return NULL;
00135 }
00136
00137 void AutoscanInotify::threadProc()
00138 {
00139 Ref<ContentManager> cm;
00140 Ref<Storage> st;
00141
00142 inotify_event *event;
00143
00144 Ref<StringBuffer> pathBuf (new StringBuffer());
00145
00146 try
00147 {
00148 cm = ContentManager::getInstance();
00149 st = Storage::getInstance();
00150 }
00151 catch (Exception e)
00152 {
00153 log_error("Inotify thread caught: %s\n", e.getMessage().c_str());
00154 e.printStackTrace();
00155 shutdownFlag = true;
00156 inotify = nil;
00157 }
00158 while(! shutdownFlag)
00159 {
00160 try
00161 {
00162 Ref<AutoscanDirectory> adir;
00163
00164 AUTOLOCK(mutex);
00165 while ((adir = unmonitorQueue->dequeue()) != nil)
00166 {
00167 AUTOUNLOCK();
00168
00169 String location = normalizePathNoEx(adir->getLocation());
00170 if (! string_ok(location))
00171 {
00172 AUTORELOCK();
00173 continue;
00174 }
00175
00176 if (adir->getRecursive())
00177 {
00178 log_debug("removing recursive watch: %s\n", location.c_str());
00179 monitorUnmonitorRecursive(location, true, adir, location, true);
00180 }
00181 else
00182 {
00183 log_debug("removing non-recursive watch: %s\n", location.c_str());
00184 unmonitorDirectory(location, adir);
00185 }
00186
00187 AUTORELOCK();
00188 }
00189
00190 while ((adir = monitorQueue->dequeue()) != nil)
00191 {
00192 AUTOUNLOCK();
00193
00194 String location = normalizePathNoEx(adir->getLocation());
00195 if (! string_ok(location))
00196 {
00197 AUTORELOCK();
00198 continue;
00199 }
00200
00201 if (adir->getRecursive())
00202 {
00203 log_debug("adding recursive watch: %s\n", location.c_str());
00204 monitorUnmonitorRecursive(location, false, adir, location, true);
00205 }
00206 else
00207 {
00208 log_debug("adding non-recursive watch: %s\n", location.c_str());
00209 monitorDirectory(location, adir, location, true);
00210 }
00211 cm->rescanDirectory(adir->getObjectID(), adir->getScanID(), adir->getScanMode(), nil, false);
00212
00213 AUTORELOCK();
00214 }
00215
00216 AUTOUNLOCK();
00217
00218
00219 event = inotify->nextEvent();
00220
00221
00222 if (event)
00223 {
00224 int wd = event->wd;
00225 int mask = event->mask;
00226 String name = event->name;
00227 log_debug("inotify event: %d %x %s\n", wd, mask, name.c_str());
00228
00229 Ref<Wd> wdObj = watches->get(wd);
00230 if (wdObj == nil)
00231 {
00232 inotify->removeWatch(wd);
00233 continue;
00234 }
00235
00236
00237 pathBuf->clear();
00238 *pathBuf << wdObj->getPath();
00239 if (! (mask & (IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT)))
00240 *pathBuf << name;
00241 String path = pathBuf->toString();
00242
00243 Ref<AutoscanDirectory> adir;
00244 Ref<WatchAutoscan> watchAs = getAppropriateAutoscan(wdObj, path);
00245 if (watchAs != nil)
00246 adir = watchAs->getAutoscanDirectory();
00247 else
00248 adir = nil;
00249
00250 if (mask & IN_MOVE_SELF)
00251 {
00252 checkMoveWatches(wd, wdObj);
00253 }
00254
00255 if (mask & (IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT))
00256 {
00257 recheckNonexistingMonitors(wd, wdObj);
00258 }
00259
00260 if (mask & IN_ISDIR)
00261 {
00262 if (mask & (IN_CREATE | IN_MOVED_TO))
00263 {
00264 recheckNonexistingMonitors(wd, wdObj);
00265 }
00266
00267 if (adir != nil && adir->getRecursive())
00268 {
00269 if (mask & IN_CREATE)
00270 {
00271 if (adir->getHidden() || name.charAt(0) != '.')
00272 {
00273 log_debug("new dir detected, adding to inotify: %s\n", path.c_str());
00274 monitorUnmonitorRecursive(path, false, adir, watchAs->getNormalizedAutoscanPath(), false);
00275 }
00276 else
00277 {
00278 log_debug("new dir detected, irgnoring because it's hidden: %s\n", path.c_str());
00279 }
00280 }
00281 }
00282 }
00283
00284 if (adir != nil && mask & (IN_DELETE | IN_DELETE_SELF | IN_MOVE_SELF | IN_CLOSE_WRITE | IN_MOVED_FROM | IN_MOVED_TO | IN_UNMOUNT))
00285 {
00286 String fullPath;
00287 if (mask & IN_ISDIR)
00288 fullPath = path + DIR_SEPARATOR;
00289 else
00290 fullPath = path;
00291
00292 if (! (mask & IN_MOVED_TO))
00293 {
00294 log_debug("deleting %s\n", fullPath.c_str());
00295
00296 if (mask & (IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT))
00297 {
00298 if (IN_MOVE_SELF)
00299 inotify->removeWatch(wd);
00300 Ref<WatchAutoscan> watch = getStartPoint(wdObj);
00301 if (watch != nil)
00302 {
00303 if (adir->persistent())
00304 {
00305 monitorNonexisting(path, watch->getAutoscanDirectory(), watch->getNormalizedAutoscanPath());
00306 cm->handlePeristentAutoscanRemove(adir->getScanID(), InotifyScanMode);
00307 }
00308 }
00309 }
00310
00311 int objectID = st->findObjectIDByPath(fullPath);
00312 if (objectID != INVALID_OBJECT_ID)
00313 cm->removeObject(objectID);
00314 }
00315 if (mask & (IN_CLOSE_WRITE | IN_MOVED_TO))
00316 {
00317 log_debug("adding %s\n", path.c_str());
00318
00319 cm->addFile(fullPath, adir->getRecursive(), true, adir->getHidden(), true, false);
00320
00321 if (mask & IN_ISDIR)
00322 monitorUnmonitorRecursive(path, false, adir, watchAs->getNormalizedAutoscanPath(), false);
00323 }
00324 }
00325 if (mask & IN_IGNORED)
00326 {
00327 removeWatchMoves(wd);
00328 removeDescendants(wd);
00329 watches->remove(wd);
00330 }
00331 }
00332 }
00333 catch (Exception e)
00334 {
00335 log_error("Inotify thread caught exception: %s\n", e.getMessage().c_str());
00336 e.printStackTrace();
00337 }
00338 }
00339 }
00340
00341 void AutoscanInotify::monitor(zmm::Ref<AutoscanDirectory> dir)
00342 {
00343 if (shutdownFlag)
00344 init();
00345 assert(dir->getScanMode() == InotifyScanMode);
00346 log_debug("---> INCOMING REQUEST TO MONITOR [%s]\n",
00347 dir->getLocation().c_str());
00348 AUTOLOCK(mutex);
00349 monitorQueue->enqueue(dir);
00350 inotify->stop();
00351 }
00352
00353 void AutoscanInotify::unmonitor(zmm::Ref<AutoscanDirectory> dir)
00354 {
00355
00356 assert(! dir->persistent());
00357
00358 log_debug("---> INCOMING REQUEST TO UNMONITOR [%s]\n",
00359 dir->getLocation().c_str());
00360 AUTOLOCK(mutex);
00361 unmonitorQueue->enqueue(dir);
00362 inotify->stop();
00363 }
00364
00365 int AutoscanInotify::watchPathForMoves(String path, int wd)
00366 {
00367 Ref<Array<StringBase> > pathAr = split_string(path, DIR_SEPARATOR);
00368 Ref<StringBuffer> buf(new StringBuffer());
00369 int parentWd = INOTIFY_ROOT;
00370 for (int i = -1; i < pathAr->size() - 1; i++)
00371 {
00372 if (i != 0)
00373 *buf << DIR_SEPARATOR;
00374 if (i >= 0)
00375 *buf << pathAr->get(i);
00376 log_debug("adding move watch: %s\n", buf->c_str());
00377 parentWd = addMoveWatch(buf->toString(), wd, parentWd);
00378 }
00379 return parentWd;
00380 }
00381
00382 int AutoscanInotify::addMoveWatch(String path, int removeWd, int parentWd)
00383 {
00384 int wd = inotify->addWatch(path, events);
00385 if (wd >= 0)
00386 {
00387 bool alreadyThere = false;
00388 Ref<Wd> wdObj = watches->get(wd);
00389 if (wdObj == nil)
00390 {
00391 wdObj = Ref<Wd>(new Wd(path, wd, parentWd));
00392 watches->put(wd, wdObj);
00393 }
00394 else
00395 {
00396 int parentWdSet = wdObj->getParentWd();
00397 if (parentWdSet >= 0)
00398 {
00399 if (parentWd != parentWdSet)
00400 {
00401 log_debug("error: parentWd doesn't match wd: %d, parent is: %d, should be: %d\n", wd, parentWdSet, parentWd);
00402 wdObj->setParentWd(parentWd);
00403 }
00404 }
00405 else
00406 wdObj->setParentWd(parentWd);
00407
00408
00409
00410 }
00411 if (! alreadyThere)
00412 {
00413 Ref<WatchMove> watch(new WatchMove(removeWd));
00414 wdObj->getWdWatches()->append(RefCast(watch, Watch));
00415 }
00416 }
00417 return wd;
00418 }
00419
00420 void AutoscanInotify::monitorNonexisting(String path, Ref<AutoscanDirectory> adir, String normalizedAutoscanPath)
00421 {
00422 String pathTmp = path;
00423 Ref<Array<StringBase> > pathAr = split_string(path, DIR_SEPARATOR);
00424 recheckNonexistingMonitor(-1, pathAr, adir, normalizedAutoscanPath);
00425 }
00426
00427 void AutoscanInotify::recheckNonexistingMonitor(int curWd, Ref<Array<StringBase> > pathAr, Ref<AutoscanDirectory> adir, String normalizedAutoscanPath)
00428 {
00429 Ref<StringBuffer> buf(new StringBuffer());
00430 bool first = true;
00431 for (int i = pathAr->size(); i >= 0; i--)
00432 {
00433 buf->clear();
00434 if (i == 0)
00435 *buf << DIR_SEPARATOR;
00436 else
00437 {
00438 for (int j = 0; j < i; j++)
00439 {
00440 *buf << DIR_SEPARATOR << pathAr->get(j);
00441
00442 }
00443 }
00444 bool pathExists = check_path(buf->toString(), true);
00445
00446 if (pathExists)
00447 {
00448 if (curWd != -1)
00449 removeNonexistingMonitor(curWd, watches->get(curWd), pathAr);
00450
00451 String path = buf->toString() + DIR_SEPARATOR;
00452 if (first)
00453 {
00454 monitorDirectory(path, adir, normalizedAutoscanPath, true);
00455 ContentManager::getInstance()->handlePersistentAutoscanRecreate(adir->getScanID(), adir->getScanMode());
00456 }
00457 else
00458 {
00459 monitorDirectory(path, adir, normalizedAutoscanPath, false, pathAr);
00460 }
00461 break;
00462 }
00463 if (first)
00464 first = false;
00465 }
00466 }
00467
00468 void AutoscanInotify::checkMoveWatches(int wd, Ref<Wd> wdObj)
00469 {
00470 Ref<Watch> watch;
00471 Ref<WatchMove> watchMv;
00472 Ref<Array<Watch> > wdWatches = wdObj->getWdWatches();
00473 for (int i = 0; i < wdWatches->size(); i++)
00474 {
00475 watch = wdWatches->get(i);
00476 if (watch->getType() == WatchMoveType)
00477 {
00478 if (wdWatches->size() == 1)
00479 {
00480 inotify->removeWatch(wd);
00481 }
00482 else
00483 {
00484 wdWatches->removeUnordered(i);
00485 }
00486
00487 watchMv = RefCast(watch, WatchMove);
00488 int removeWd = watchMv->getRemoveWd();
00489 Ref<Wd> wdToRemove = watches->get(removeWd);
00490 if (wdToRemove != nil)
00491 {
00492 recheckNonexistingMonitors(removeWd, wdToRemove);
00493
00494 String path = wdToRemove->getPath();
00495 log_debug("found wd to remove because of move event: %d %s\n", removeWd, path.c_str());
00496
00497 inotify->removeWatch(removeWd);
00498 Ref<ContentManager> cm = ContentManager::getInstance();
00499 Ref<WatchAutoscan> watch = getStartPoint(wdToRemove);
00500 if (watch != nil)
00501 {
00502 Ref<AutoscanDirectory> adir = watch->getAutoscanDirectory();
00503 if (adir->persistent())
00504 {
00505 monitorNonexisting(path, adir, watch->getNormalizedAutoscanPath());
00506 cm->handlePeristentAutoscanRemove(adir->getScanID(), InotifyScanMode);
00507 }
00508
00509 int objectID = Storage::getInstance()->findObjectIDByPath(path);
00510 if (objectID != INVALID_OBJECT_ID)
00511 cm->removeObject(objectID);
00512 }
00513 }
00514 }
00515 }
00516 }
00517
00518 void AutoscanInotify::recheckNonexistingMonitors(int wd, Ref<Wd> wdObj)
00519 {
00520 Ref<Watch> watch;
00521 Ref<WatchAutoscan> watchAs;
00522 Ref<Array<Watch> > wdWatches = wdObj->getWdWatches();
00523 for (int i = 0; i < wdWatches->size(); i++)
00524 {
00525 watch = wdWatches->get(i);
00526 if (watch->getType() == WatchAutoscanType)
00527 {
00528 watchAs = RefCast(watch, WatchAutoscan);
00529 Ref<Array<StringBase> > pathAr = watchAs->getNonexistingPathArray();
00530 if (pathAr != nil)
00531 {
00532 recheckNonexistingMonitor(wd, pathAr, watchAs->getAutoscanDirectory(), watchAs->getNormalizedAutoscanPath());
00533 }
00534 }
00535 }
00536 }
00537
00538 void AutoscanInotify::removeNonexistingMonitor(int wd, Ref<Wd> wdObj, Ref<Array<StringBase> > pathAr)
00539 {
00540 Ref<Watch> watch;
00541 Ref<WatchAutoscan> watchAs;
00542 Ref<Array<Watch> > wdWatches = wdObj->getWdWatches();
00543 for (int i = 0; i < wdWatches->size(); i++)
00544 {
00545 watch = wdWatches->get(i);
00546 if (watch->getType() == WatchAutoscanType)
00547 {
00548 watchAs = RefCast(watch, WatchAutoscan);
00549 if (watchAs->getNonexistingPathArray() == pathAr)
00550 {
00551 if (wdWatches->size() == 1)
00552 {
00553
00554
00555
00556 inotify->removeWatch(wd);
00557 }
00558 else
00559 {
00560 wdWatches->removeUnordered(i);
00561 }
00562 return;
00563 }
00564 }
00565 }
00566 }
00567
00568 void AutoscanInotify::monitorUnmonitorRecursive(String startPath, bool unmonitor, Ref<AutoscanDirectory> adir, String normalizedAutoscanPath, bool startPoint)
00569 {
00570 String location;
00571 if (unmonitor)
00572 unmonitorDirectory(startPath, adir);
00573 else
00574 {
00575 bool ok = (monitorDirectory(startPath, adir, normalizedAutoscanPath, startPoint) > 0);
00576 if (! ok)
00577 return;
00578 }
00579
00580 struct dirent *dent;
00581 struct stat statbuf;
00582
00583 DIR *dir = opendir(startPath.c_str());
00584 if (! dir)
00585 {
00586 log_warning("Could not open %s\n", startPath.c_str());
00587 return;
00588 }
00589
00590 while ((dent = readdir(dir)) != NULL && ! shutdownFlag)
00591 {
00592 char *name = dent->d_name;
00593 if (name[0] == '.')
00594 {
00595 if (name[1] == 0)
00596 continue;
00597 else if (name[1] == '.' && name[2] == 0)
00598 continue;
00599 }
00600
00601 String fullPath = startPath + DIR_SEPARATOR + name;
00602
00603 if (stat(fullPath.c_str(), &statbuf) != 0)
00604 continue;
00605
00606 if (S_ISDIR(statbuf.st_mode))
00607 {
00608 monitorUnmonitorRecursive(fullPath, unmonitor, adir, normalizedAutoscanPath, false);
00609 }
00610 }
00611
00612 closedir(dir);
00613 }
00614
00615 int AutoscanInotify::monitorDirectory(String pathOri, Ref<AutoscanDirectory> adir, String normalizedAutoscanPath, bool startPoint, Ref<Array<StringBase> > pathArray)
00616 {
00617 String path = pathOri + DIR_SEPARATOR;
00618
00619 int wd = inotify->addWatch(path, events);
00620 if (wd < 0)
00621 {
00622 if (startPoint && adir->persistent())
00623 {
00624 monitorNonexisting(path, adir, normalizedAutoscanPath);
00625 }
00626 }
00627 else
00628 {
00629 bool alreadyWatching = false;
00630 Ref<Wd> wdObj = watches->get(wd);
00631 int parentWd = INOTIFY_UNKNOWN_PARENT_WD;
00632 if (startPoint)
00633 parentWd = watchPathForMoves(pathOri, wd);
00634 if (wdObj == nil)
00635 {
00636 wdObj = Ref<Wd>(new Wd(path, wd, parentWd));
00637 watches->put(wd, wdObj);
00638 }
00639 else
00640 {
00641 if (parentWd >= 0 && wdObj->getParentWd() < 0)
00642 {
00643 wdObj->setParentWd(parentWd);
00644 }
00645
00646 if (pathArray == nil)
00647 alreadyWatching = (getAppropriateAutoscan(wdObj, adir) != nil);
00648
00649
00650
00651 }
00652 if (! alreadyWatching)
00653 {
00654 Ref<WatchAutoscan> watch(new WatchAutoscan(startPoint, adir, normalizedAutoscanPath));
00655 if (pathArray != nil)
00656 {
00657 watch->setNonexistingPathArray(pathArray);
00658 }
00659 wdObj->getWdWatches()->append(RefCast(watch, Watch));
00660
00661 if (! startPoint)
00662 {
00663 int startPointWd = inotify->addWatch(normalizedAutoscanPath, events);
00664 log_debug("getting start point for %s -> %s wd=%d\n", pathOri.c_str(), normalizedAutoscanPath.c_str(), startPointWd);
00665 if (wd >= 0)
00666 addDescendant(startPointWd, wd, adir);
00667 }
00668 }
00669 }
00670 return wd;
00671 }
00672
00673 void AutoscanInotify::unmonitorDirectory(String path, Ref<AutoscanDirectory> adir)
00674 {
00675 path = path + DIR_SEPARATOR;
00676
00677
00678
00679
00680 int wd = inotify->addWatch(path, events);
00681
00682 if (wd < 0)
00683 {
00684
00685 log_debug("unmonitorDirectory called, but it isn't monitored? (%s)\n", path.c_str());
00686 return;
00687 }
00688
00689 Ref<Wd> wdObj = watches->get(wd);
00690 if (wdObj == nil)
00691 {
00692 log_error("wd not found in watches!? (%d, %s)\n", wd, path.c_str());
00693 return;
00694 }
00695
00696 Ref<WatchAutoscan> watchAs = getAppropriateAutoscan(wdObj, adir);
00697 if (watchAs == nil)
00698 {
00699 log_debug("autoscan not found in watches? (%d, %s)\n", wd, path.c_str());
00700 }
00701 else
00702 {
00703 if (wdObj->getWdWatches()->size() == 1)
00704 {
00705
00706
00707
00708 inotify->removeWatch(wd);
00709 }
00710 else
00711 {
00712 removeFromWdObj(wdObj, watchAs);
00713 }
00714 }
00715 }
00716
00717 Ref<AutoscanInotify::WatchAutoscan> AutoscanInotify::getAppropriateAutoscan(Ref<Wd> wdObj, Ref<AutoscanDirectory> adir)
00718 {
00719 Ref<Watch> watch;
00720 Ref<WatchAutoscan> watchAs;
00721 Ref<Array<Watch> > wdWatches = wdObj->getWdWatches();
00722 for (int i = 0; i < wdWatches->size(); i++)
00723 {
00724 watch = wdWatches->get(i);
00725 if (watch->getType() == WatchAutoscanType)
00726 {
00727 watchAs = RefCast(watch, WatchAutoscan);
00728 if (watchAs->getNonexistingPathArray() == nil)
00729 {
00730 if (watchAs->getAutoscanDirectory()->getLocation() == adir->getLocation())
00731 {
00732 return watchAs;
00733 }
00734 }
00735 }
00736 }
00737 return nil;
00738 }
00739
00740 Ref<AutoscanInotify::WatchAutoscan> AutoscanInotify::getAppropriateAutoscan(Ref<Wd> wdObj, String path)
00741 {
00742 String pathBestMatch;
00743 Ref<WatchAutoscan> bestMatch = nil;
00744 Ref<Watch> watch;
00745 Ref<WatchAutoscan> watchAs;
00746 Ref<Array<Watch> > wdWatches = wdObj->getWdWatches();
00747 for (int i = 0; i < wdWatches->size(); i++)
00748 {
00749 watch = wdWatches->get(i);
00750 if (watch->getType() == WatchAutoscanType)
00751 {
00752 watchAs = RefCast(watch, WatchAutoscan);
00753 if (watchAs->getNonexistingPathArray() == nil)
00754 {
00755 String testLocation = watchAs->getNormalizedAutoscanPath();
00756 if (path.startsWith(testLocation))
00757 {
00758 if (string_ok(pathBestMatch))
00759 {
00760 if (pathBestMatch.length() < testLocation.length())
00761 {
00762 pathBestMatch = testLocation;
00763 bestMatch = watchAs;
00764 }
00765 }
00766 else
00767 {
00768 pathBestMatch = testLocation;
00769 bestMatch = watchAs;
00770 }
00771 }
00772 }
00773 }
00774 }
00775 return bestMatch;
00776 }
00777
00778 void AutoscanInotify::removeWatchMoves(int wd)
00779 {
00780 Ref<Wd> wdObj;
00781 Ref<Array<Watch> > wdWatches;
00782 Ref<Watch> watch;
00783 Ref<WatchMove> watchMv;
00784 bool first = true;
00785 int checkWd = wd;
00786 do
00787 {
00788 wdObj = watches->get(checkWd);
00789 if (wdObj == nil)
00790 break;
00791 wdWatches = wdObj->getWdWatches();
00792 if (wdWatches == nil)
00793 break;
00794
00795 if (first)
00796 first = false;
00797 else
00798 {
00799 for (int i = 0; i < wdWatches->size(); i++)
00800 {
00801 watch = wdWatches->get(i);
00802 if (watch->getType() == WatchMoveType)
00803 {
00804 watchMv = RefCast(watch, WatchMove);
00805 if (watchMv->getRemoveWd() == wd)
00806 {
00807 log_debug("removing watch move\n");
00808 if (wdWatches->size() == 1)
00809 inotify->removeWatch(checkWd);
00810 else
00811 wdWatches->removeUnordered(i);
00812 }
00813 }
00814 }
00815 }
00816 checkWd = wdObj->getParentWd();
00817 }
00818 while(checkWd >= 0);
00819 }
00820
00821 bool AutoscanInotify::removeFromWdObj(Ref<Wd> wdObj, Ref<Watch> toRemove)
00822 {
00823 Ref<Array<Watch> > wdWatches = wdObj->getWdWatches();
00824 Ref<Watch> watch;
00825 for (int i = 0; i < wdWatches->size(); i++)
00826 {
00827 watch = wdWatches->get(i);
00828 if (watch == toRemove)
00829 {
00830 if (wdWatches->size() == 1)
00831 inotify->removeWatch(wdObj->getWd());
00832 else
00833 wdWatches->removeUnordered(i);
00834 return true;
00835 }
00836 }
00837 return false;
00838 }
00839
00840 bool AutoscanInotify::removeFromWdObj(Ref<Wd> wdObj, Ref<WatchAutoscan> toRemove)
00841 {
00842 return removeFromWdObj(wdObj, RefCast(toRemove, Watch));
00843 }
00844
00845 bool AutoscanInotify::removeFromWdObj(Ref<Wd> wdObj, Ref<WatchMove> toRemove)
00846 {
00847 return removeFromWdObj(wdObj, RefCast(toRemove, Watch));
00848 }
00849
00850 Ref<AutoscanInotify::WatchAutoscan> AutoscanInotify::getStartPoint(Ref<Wd> wdObj)
00851 {
00852 Ref<Watch> watch;
00853 Ref<WatchAutoscan> watchAs;
00854 Ref<Array<Watch> > wdWatches = wdObj->getWdWatches();
00855 for (int i = 0; i < wdWatches->size(); i++)
00856 {
00857 watch = wdWatches->get(i);
00858 if (watch->getType() == WatchAutoscanType)
00859 {
00860 watchAs = RefCast(watch, WatchAutoscan);
00861 if (watchAs->isStartPoint())
00862 return watchAs;
00863 }
00864 }
00865 return nil;
00866 }
00867
00868 void AutoscanInotify::addDescendant(int startPointWd, int addWd, Ref<AutoscanDirectory> adir)
00869 {
00870
00871 Ref<Wd> wdObj = watches->get(startPointWd);
00872 if (wdObj == nil)
00873 return;
00874
00875 Ref<WatchAutoscan> watch = getAppropriateAutoscan(wdObj, adir);
00876 if (watch == nil)
00877 return;
00878
00879 watch->addDescendant(addWd);
00880
00881 }
00882
00883 void AutoscanInotify::removeDescendants(int wd)
00884 {
00885 Ref<Wd> wdObj = watches->get(wd);
00886 if (wdObj == nil)
00887 return;
00888 Ref<Array<Watch> > wdWatches = wdObj->getWdWatches();
00889 if (wdWatches == nil)
00890 return;
00891
00892 Ref<Watch> watch;
00893 Ref<WatchAutoscan> watchAs;
00894 for (int i = 0; i < wdWatches->size(); i++)
00895 {
00896 watch = wdWatches->get(i);
00897 if (watch->getType() == WatchAutoscanType)
00898 {
00899 watchAs = RefCast(watch, WatchAutoscan);
00900 Ref<IntArray> descendants = watchAs->getDescendants();
00901 if (descendants != nil)
00902 {
00903 for (int i = 0; i < descendants->size(); i++)
00904 {
00905 int descWd = descendants->get(i);
00906 inotify->removeWatch(descWd);
00907 }
00908 }
00909 }
00910 }
00911 }
00912
00913 String AutoscanInotify::normalizePathNoEx(String path)
00914 {
00915 try
00916 {
00917 return normalizePath(path);
00918 }
00919 catch (Exception e)
00920 {
00921 log_error("%s\n", e.getMessage().c_str());
00922 return nil;
00923 }
00924 }
00925
00926 #endif // HAVE_INOTIFY