monitor: properly handle cleanup on directory moves

This commit is contained in:
Jean-Francois Dockes 2011-09-30 08:56:29 +02:00
parent 702fb88a1e
commit 0c5f41c41c
8 changed files with 309 additions and 56 deletions

View File

@ -21,6 +21,13 @@ rclmonrcv.o : rclmonrcv.cpp
rclmonprc.o : rclmonprc.cpp rclmonprc.o : rclmonprc.cpp
$(CXX) $(ALL_CXXFLAGS) -c -o rclmonprc.o $< $(CXX) $(ALL_CXXFLAGS) -c -o rclmonprc.o $<
SUBTREELIST_OBJS= subtreelist.o $(BIGLIB)
subtreelist : $(SUBTREELIST_OBJS)
$(CXX) $(ALL_CXXFLAGS) -o subtreelist $(SUBTREELIST_OBJS) \
$(LIBICONV) $(LIBXAPIAN) $(LIBSYS)
subtreelist.o : subtreelist.cpp
$(CXX) $(ALL_CXXFLAGS) -DTEST_SUBTREELIST -c subtreelist.cpp
CSGUESS_OBJS= trcsguess.o $(BIGLIB) CSGUESS_OBJS= trcsguess.o $(BIGLIB)
csguess : $(CSGUESS_OBJS) csguess : $(CSGUESS_OBJS)
$(CXX) $(ALL_CXXFLAGS) -o csguess $(CSGUESS_OBJS) \ $(CXX) $(ALL_CXXFLAGS) -o csguess $(CSGUESS_OBJS) \

View File

@ -45,10 +45,11 @@ using std::multimap;
*/ */
class RclMonEvent { class RclMonEvent {
public: public:
enum EvType {RCLEVT_NONE, RCLEVT_MODIFY, RCLEVT_DELETE, enum EvType {RCLEVT_NONE= 0, RCLEVT_MODIFY=1, RCLEVT_DELETE=2,
RCLEVT_DIRCREATE}; RCLEVT_DIRCREATE=3, RCLEVT_ISDIR=0x10};
string m_path; string m_path;
EvType m_etyp; // Type and flags
int m_etyp;
///// For fast changing files: minimum time interval before reindex ///// For fast changing files: minimum time interval before reindex
// Minimum interval (from config) // Minimum interval (from config)
@ -58,8 +59,10 @@ class RclMonEvent {
// Changed since put in purgatory after reindex // Changed since put in purgatory after reindex
bool m_needidx; bool m_needidx;
RclMonEvent() : m_etyp(RCLEVT_NONE), RclMonEvent() : m_etyp(RCLEVT_NONE),
m_itvsecs(0), m_minclock(0), m_needidx(false) {} m_itvsecs(0), m_minclock(0), m_needidx(false) {}
EvType evtype() {return EvType(m_etyp & 0xf);}
int evflags() {return m_etyp & 0xf0;}
}; };
enum RclMonitorOption {RCLMON_NONE=0, RCLMON_NOFORK=1, RCLMON_NOX11=2}; enum RclMonitorOption {RCLMON_NONE=0, RCLMON_NOFORK=1, RCLMON_NOX11=2};

View File

@ -43,6 +43,7 @@
#include "pathut.h" #include "pathut.h"
#include "x11mon.h" #include "x11mon.h"
#include "rclionice.h" #include "rclionice.h"
#include "subtreelist.h"
typedef unsigned long mttcast; typedef unsigned long mttcast;
@ -482,14 +483,30 @@ bool startMonitor(RclConfig *conf, int opts)
RclMonEvent ev = rclEQ.pop(); RclMonEvent ev = rclEQ.pop();
if (ev.m_path.empty()) if (ev.m_path.empty())
break; break;
switch (ev.m_etyp) { switch (ev.evtype()) {
case RclMonEvent::RCLEVT_MODIFY: case RclMonEvent::RCLEVT_MODIFY:
case RclMonEvent::RCLEVT_DIRCREATE:
LOGDEB(("Monitor: Modify/Check on %s\n", ev.m_path.c_str())); LOGDEB(("Monitor: Modify/Check on %s\n", ev.m_path.c_str()));
modified.push_back(ev.m_path); modified.push_back(ev.m_path);
break; break;
case RclMonEvent::RCLEVT_DELETE: case RclMonEvent::RCLEVT_DELETE:
LOGDEB(("Monitor: Delete on %s\n", ev.m_path.c_str())); LOGDEB(("Monitor: Delete on %s\n", ev.m_path.c_str()));
// If this is for a directory (which the caller should
// tell us because he knows), we should purge the db
// of all the subtree, because on a directory rename,
// inotify will only generate one event for the
// renamed top, not the subentries. This is relatively
// complicated to do though, and we currently do not
// do it, and just wait for a restart to do a full run and
// purge.
deleted.push_back(ev.m_path); deleted.push_back(ev.m_path);
if (ev.evflags() & RclMonEvent::RCLEVT_ISDIR) {
list<string> paths;
if (subtreelist(conf, ev.m_path, paths)) {
deleted.insert(deleted.end(),
paths.begin(), paths.end());
}
}
break; break;
default: default:
LOGDEB(("Monitor: got Other on [%s]\n", ev.m_path.c_str())); LOGDEB(("Monitor: got Other on [%s]\n", ev.m_path.c_str()));

View File

@ -41,9 +41,9 @@ public:
virtual ~RclMonitor() {} virtual ~RclMonitor() {}
virtual bool addWatch(const string& path, bool isDir) = 0; virtual bool addWatch(const string& path, bool isDir) = 0;
virtual bool getEvent(RclMonEvent& ev, int secs = -1) = 0; virtual bool getEvent(RclMonEvent& ev, int secs = -1) = 0;
virtual bool ok() = 0; virtual bool ok() const = 0;
// Does this monitor generate 'exist' events at startup? // Does this monitor generate 'exist' events at startup?
virtual bool generatesExist() = 0; virtual bool generatesExist() const = 0;
}; };
// Monitor factory. We only have one compiled-in kind at a time, no // Monitor factory. We only have one compiled-in kind at a time, no
@ -96,6 +96,16 @@ public:
flg == FsTreeWalker::FtwRegular) { flg == FsTreeWalker::FtwRegular) {
// Have to synthetize events for regular files existence // Have to synthetize events for regular files existence
// at startup because the monitor does not do it // at startup because the monitor does not do it
// Note 2011-09-29: no sure this is actually needed. We just ran
// an incremental indexing pass (before starting the
// monitor). Why go over the files once more ? The only
// reason I can see would be to catch modifications that
// happen between the incremental and the start of
// monitoring ? There should be another way: maybe start
// monitoring without actually handling events (just
// queue), then run incremental then start handling
// events ? But we also have to do it on a directory
// move! So keep it
RclMonEvent ev; RclMonEvent ev;
ev.m_path = fn; ev.m_path = fn;
ev.m_etyp = RclMonEvent::RCLEVT_MODIFY; ev.m_etyp = RclMonEvent::RCLEVT_MODIFY;
@ -180,13 +190,21 @@ void *rclMonRcvRun(void *q)
// timeout so that an intr will be detected // timeout so that an intr will be detected
if (mon->getEvent(ev, 2)) { if (mon->getEvent(ev, 2)) {
if (ev.m_etyp == RclMonEvent::RCLEVT_DIRCREATE) { if (ev.m_etyp == RclMonEvent::RCLEVT_DIRCREATE) {
// Add watch after checking that this doesn't match // Recursive addwatch: there may already be stuff
// ignored files or paths // inside this directory. Ie: files were quickly
string name = path_getsimple(ev.m_path); // created, or this is actually the target of a
if (!walker.inSkippedNames(name) && // directory move. This is necessary for inotify, but
!walker.inSkippedPaths(ev.m_path)) // it seems that fam/gamin is doing the job for us so
mon->addWatch(ev.m_path, true); // that we are generating double events here (no big
// deal as prc will sort/merge).
if (!walker.inSkippedNames(path_getsimple(ev.m_path)) &&
!walker.inSkippedPaths(ev.m_path)) {
LOGDEB(("rclMonRcvRun: walking new dir %s\n",
ev.m_path.c_str()));
walker.walk(ev.m_path, walkcb);
}
} }
if (ev.m_etyp != RclMonEvent::RCLEVT_NONE) if (ev.m_etyp != RclMonEvent::RCLEVT_NONE)
queue->pushEvent(ev); queue->pushEvent(ev);
} }
@ -197,6 +215,24 @@ void *rclMonRcvRun(void *q)
return 0; return 0;
} }
// Utility routine used by both the fam/gamin and inotify versions to get
// rid of the id-path translation for a moved dir
bool eraseWatchSubTree(map<int, string>& idtopath, const string& top)
{
bool found = false;
LOGDEB0(("Clearing map for [%s]\n", top.c_str()));
map<int,string>::iterator it = idtopath.begin();
while (it != idtopath.end()) {
if (it->second.find(top) == 0) {
found = true;
idtopath.erase(it++);
} else {
it++;
}
}
return found;
}
// We dont compile both the inotify and the fam interface and inotify // We dont compile both the inotify and the fam interface and inotify
// has preference // has preference
#ifndef RCL_USE_INOTIFY #ifndef RCL_USE_INOTIFY
@ -215,8 +251,8 @@ public:
virtual ~RclFAM(); virtual ~RclFAM();
virtual bool addWatch(const string& path, bool isdir); virtual bool addWatch(const string& path, bool isdir);
virtual bool getEvent(RclMonEvent& ev, int secs = -1); virtual bool getEvent(RclMonEvent& ev, int secs = -1);
bool ok() {return m_ok;} bool ok() const {return m_ok;}
virtual bool generatesExist() {return true;} virtual bool generatesExist() const {return true;}
private: private:
bool m_ok; bool m_ok;
@ -225,7 +261,7 @@ private:
FAMClose(&m_conn); FAMClose(&m_conn);
m_ok = false; m_ok = false;
} }
map<int,string> m_reqtopath; map<int,string> m_idtopath;
const char *event_name(int code); const char *event_name(int code);
}; };
@ -286,7 +322,7 @@ bool RclFAM::addWatch(const string& path, bool isdir)
return false; return false;
} }
} }
m_reqtopath[req.reqnum] = path; m_idtopath[req.reqnum] = path;
return true; return true;
} }
@ -346,12 +382,13 @@ bool RclFAM::getEvent(RclMonEvent& ev, int secs)
map<int,string>::const_iterator it; map<int,string>::const_iterator it;
if ((fe.filename[0] != '/') && if ((fe.filename[0] != '/') &&
(it = m_reqtopath.find(fe.fr.reqnum)) != m_reqtopath.end()) { (it = m_idtopath.find(fe.fr.reqnum)) != m_idtopath.end()) {
ev.m_path = path_cat(it->second, fe.filename); ev.m_path = path_cat(it->second, fe.filename);
} else { } else {
ev.m_path = fe.filename; ev.m_path = fe.filename;
} }
MONDEB(("RclFAM::getEvent: %-12s %s\n",
LOGDEB(("RclFAM::getEvent: %-12s %s\n",
event_name(fe.code), ev.m_path.c_str())); event_name(fe.code), ev.m_path.c_str()));
switch (fe.code) { switch (fe.code) {
@ -367,13 +404,15 @@ bool RclFAM::getEvent(RclMonEvent& ev, int secs)
ev.m_etyp = RclMonEvent::RCLEVT_MODIFY; ev.m_etyp = RclMonEvent::RCLEVT_MODIFY;
break; break;
case FAMMoved:
case FAMDeleted: case FAMDeleted:
ev.m_etyp = RclMonEvent::RCLEVT_DELETE; ev.m_etyp = RclMonEvent::RCLEVT_DELETE;
break; // We would like to signal a directory here to enable cleaning
// the subtree (on a dir move), but can't test the actual file
case FAMMoved: /* Never generated it seems */ // which is gone. Let's rely on the fact that a directory
LOGINFO(("RclFAM::getEvent: got move event !\n")); // should be watched
ev.m_etyp = RclMonEvent::RCLEVT_MODIFY; if (eraseWatchSubTree(m_idtopath, ev.m_path))
ev.m_etyp |= RclMonEvent::RCLEVT_ISDIR;
break; break;
case FAMStartExecuting: case FAMStartExecuting:
@ -401,17 +440,29 @@ bool RclFAM::getEvent(RclMonEvent& ev, int secs)
class RclIntf : public RclMonitor { class RclIntf : public RclMonitor {
public: public:
RclIntf(); RclIntf()
virtual ~RclIntf(); : m_ok(false), m_fd(-1), m_evp(0), m_ep(0)
{
if ((m_fd = inotify_init()) < 0) {
LOGERR(("RclIntf:: inotify_init failed, errno %d\n", errno));
return;
}
m_ok = true;
}
virtual ~RclIntf()
{
close();
}
virtual bool addWatch(const string& path, bool isdir); virtual bool addWatch(const string& path, bool isdir);
virtual bool getEvent(RclMonEvent& ev, int secs = -1); virtual bool getEvent(RclMonEvent& ev, int secs = -1);
bool ok() {return m_ok;} bool ok() const {return m_ok;}
virtual bool generatesExist() {return false;} virtual bool generatesExist() const {return false;}
private: private:
bool m_ok; bool m_ok;
int m_fd; int m_fd;
map<int,string> m_wdtopath; // Watch descriptor to name map<int,string> m_idtopath; // Watch descriptor to name
#define EVBUFSIZE (32*1024) #define EVBUFSIZE (32*1024)
char m_evbuf[EVBUFSIZE]; // Event buffer char m_evbuf[EVBUFSIZE]; // Event buffer
char *m_evp; // Pointer to next event or 0 char *m_evp; // Pointer to next event or 0
@ -455,40 +506,27 @@ const char *RclIntf::event_name(int code)
}; };
} }
RclIntf::RclIntf()
: m_ok(false), m_fd(-1), m_evp(0), m_ep(0)
{
if ((m_fd = inotify_init()) < 0) {
LOGERR(("RclIntf::RclIntf: inotify_init failed, errno %d\n", errno));
return;
}
m_ok = true;
}
RclIntf::~RclIntf()
{
close();
}
bool RclIntf::addWatch(const string& path, bool) bool RclIntf::addWatch(const string& path, bool)
{ {
if (!ok()) if (!ok())
return false; return false;
MONDEB(("RclIntf::addWatch: adding %s\n", path.c_str())); MONDEB(("RclIntf::addWatch: adding %s\n", path.c_str()));
// CLOSE_WRITE is covered through MODIFY. CREATE is needed for mkdirs // CLOSE_WRITE is covered through MODIFY. CREATE is needed for mkdirs
uint32_t mask = IN_MODIFY | IN_CREATE uint32_t mask = IN_MODIFY | IN_CREATE
| IN_MOVED_FROM | IN_MOVED_TO | IN_MOVED_FROM | IN_MOVED_TO | IN_DELETE
| IN_DELETE
#ifdef IN_DONT_FOLLOW #ifdef IN_DONT_FOLLOW
| IN_DONT_FOLLOW | IN_DONT_FOLLOW
#endif #endif
; #ifdef IN_EXCL_UNLINK
| IN_EXCL_UNLINK
#endif
;
int wd; int wd;
if ((wd = inotify_add_watch(m_fd, path.c_str(), mask)) < 0) { if ((wd = inotify_add_watch(m_fd, path.c_str(), mask)) < 0) {
LOGERR(("RclIntf::addWatch: inotify_add_watch failed\n")); LOGERR(("RclIntf::addWatch: inotify_add_watch failed\n"));
return false; return false;
} }
m_wdtopath[wd] = path; m_idtopath[wd] = path;
return true; return true;
} }
@ -544,8 +582,8 @@ bool RclIntf::getEvent(RclMonEvent& ev, int secs)
m_evp = m_ep = 0; m_evp = m_ep = 0;
map<int,string>::const_iterator it; map<int,string>::const_iterator it;
if ((it = m_wdtopath.find(evp->wd)) == m_wdtopath.end()) { if ((it = m_idtopath.find(evp->wd)) == m_idtopath.end()) {
LOGERR(("RclIntf::getEvent: unknown wd\n")); LOGERR(("RclIntf::getEvent: unknown wd %d\n", evp->wd));
return true; return true;
} }
ev.m_path = it->second; ev.m_path = it->second;
@ -557,17 +595,36 @@ bool RclIntf::getEvent(RclMonEvent& ev, int secs)
MONDEB(("RclIntf::getEvent: %-12s %s\n", MONDEB(("RclIntf::getEvent: %-12s %s\n",
event_name(evp->mask), ev.m_path.c_str())); event_name(evp->mask), ev.m_path.c_str()));
if (evp->mask & (IN_MODIFY | IN_MOVED_TO)) { if ((evp->mask & IN_MOVED_FROM) && (evp->mask & IN_ISDIR)) {
// We get this when a directory is renamed. Erase the subtree
// entries in the map. The subsequent MOVED_TO will recreate
// them. This is probably not needed because the watches
// actually still exist in the kernel, so that the wds
// returned by future addwatches will be the old ones, and the
// map will be updated in place. But still, this feels safer
eraseWatchSubTree(m_idtopath, ev.m_path);
}
if (evp->mask & (IN_MODIFY)) {
ev.m_etyp = RclMonEvent::RCLEVT_MODIFY; ev.m_etyp = RclMonEvent::RCLEVT_MODIFY;
} else if (evp->mask & (IN_DELETE | IN_MOVED_FROM)) { } else if (evp->mask & (IN_DELETE | IN_MOVED_FROM)) {
ev.m_etyp = RclMonEvent::RCLEVT_DELETE; ev.m_etyp = RclMonEvent::RCLEVT_DELETE;
} else if (evp->mask & (IN_CREATE)) { if (evp->mask & IN_ISDIR)
if (path_isdir(ev.m_path)) { ev.m_etyp |= RclMonEvent::RCLEVT_ISDIR;
} else if (evp->mask & (IN_CREATE | IN_MOVED_TO)) {
if (evp->mask & IN_ISDIR) {
ev.m_etyp = RclMonEvent::RCLEVT_DIRCREATE; ev.m_etyp = RclMonEvent::RCLEVT_DIRCREATE;
} else { } else {
// Return null event. Will get modify event later // Return null event. Will get modify event later
return true; return true;
} }
} else if (evp->mask & (IN_IGNORED)) {
if (!m_idtopath.erase(evp->wd)) {
LOGDEB0(("Got IGNORE event for unknown watch\n"));
} else {
eraseWatchSubTree(m_idtopath, ev.m_path);
}
} else { } else {
LOGDEB(("RclIntf::getEvent: unhandled event %s 0x%x %s\n", LOGDEB(("RclIntf::getEvent: unhandled event %s 0x%x %s\n",
event_name(evp->mask), evp->mask, ev.m_path.c_str())); event_name(evp->mask), evp->mask, ev.m_path.c_str()));

129
src/index/subtreelist.cpp Normal file
View File

@ -0,0 +1,129 @@
/* Copyright (C) 2007 J.F.Dockes
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef TEST_SUBTREELIST
#include "refcntr.h"
#include "rcldb.h"
#include "searchdata.h"
#include "rclquery.h"
#include "subtreelist.h"
#include "debuglog.h"
bool subtreelist(RclConfig *config, const string& top,
list<string>& paths)
{
LOGDEB(("subtreelist: top: [%s]\n", top.c_str()));
Rcl::Db rcldb(config);
if (!rcldb.open(Rcl::Db::DbRO)) {
LOGERR(("subtreelist: can't open database in [%s]: %s\n",
config->getDbDir().c_str(), rcldb.getReason().c_str()));
return false;
}
Rcl::SearchData *sd = new Rcl::SearchData(Rcl::SCLT_OR);
RefCntr<Rcl::SearchData> rq(sd);
rq->setTopdir(top);
Rcl::Query query(&rcldb);
query.setQuery(rq);
int cnt = query.getResCnt();
for (int i = 0; i < cnt; i++) {
Rcl::Doc doc;
if (!query.getDoc(i, doc))
break;
string path = fileurltolocalpath(doc.url);
if (!path.empty())
paths.push_back(path);
}
return true;
}
#else // TEST
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <iostream>
#include <list>
#include <string>
using namespace std;
#include "subtreelist.h"
#include "rclconfig.h"
#include "rclinit.h"
static char *thisprog;
static char usage [] =
" <path> : list document paths in this tree\n"
;
static void
Usage(void)
{
cerr << thisprog << ": usage:" << endl << usage;
exit(1);
}
static int op_flags;
#define OPT_o 0x2
int main(int argc, char **argv)
{
string top;
thisprog = argv[0];
argc--; argv++;
while (argc > 0 && **argv == '-') {
(*argv)++;
if (!(**argv))
/* Cas du "adb - core" */
Usage();
while (**argv)
switch (*(*argv)++) {
default: Usage(); break;
}
argc--; argv++;
}
if (argc < 1)
Usage();
top = *argv++;argc--;
string reason;
RclConfig *config = recollinit(0, 0, reason, 0);
if (!config || !config->ok()) {
fprintf(stderr, "Recoll init failed: %s\n", reason.c_str());
exit(1);
}
list<string> paths;
if (!subtreelist(config, top, paths)) {
cerr << "subtreelist failed" << endl;
exit(1);
}
for (list<string>::const_iterator it = paths.begin();
it != paths.end(); it++) {
cout << *it << endl;
}
exit(0);
}
#endif

33
src/index/subtreelist.h Normal file
View File

@ -0,0 +1,33 @@
/* Copyright (C) 2007 J.F.Dockes
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the
* Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef _SUBTREELIST_H_INCLUDED_
#define _SUBTREELIST_H_INCLUDED_
#include <list>
using std::list;
class RclConfig;
// This queries the database with a pure directory-filter query, to
// retrieve all the entries beside the specified path. This is used by
// the real time indexer to purge entries when a top directory is
// renamed. This is really convoluted, I'd like a better way.
extern bool subtreelist(RclConfig *config, const string& top,
list<string>& paths);
#endif /* _SUBTREELIST_H_INCLUDED_ */

View File

@ -6,8 +6,8 @@ LIBS = librcl.a
all: $(LIBS) all: $(LIBS)
OBJS = rclaspell.o beaglequeuecache.o rclconfig.o rclinit.o textsplit.o unacpp.o beaglequeue.o csguess.o fsindexer.o indexer.o mimetype.o htmlparse.o myhtmlparse.o mimehandler.o internfile.o mh_exec.o mh_execm.o mh_html.o mh_mail.o mh_mbox.o mh_text.o docseq.o docseqdb.o docseqhist.o filtseq.o dynconf.o plaintorich.o recollq.o reslistpager.o sortseq.o wasastringtoquery.o wasatorcl.o rcldb.o rcldoc.o rclquery.o searchdata.o stemdb.o stoplist.o base64.o circache.o closefrom.o conftree.o copyfile.o debuglog.o execmd.o fstreewalk.o idfile.o fileudi.o md5.o mimeparse.o netcon.o pathut.o pxattr.o rclionice.o readfile.o smallut.o transcode.o wipedir.o x11mon.o mime-getpart.o mime-parsefull.o mime-parseonlyheader.o mime-printbody.o mime-printdoc.o mime-printheader.o mime.o convert.o iodevice.o iofactory.o OBJS = rclaspell.o beaglequeuecache.o rclconfig.o rclinit.o textsplit.o unacpp.o beaglequeue.o csguess.o fsindexer.o indexer.o mimetype.o subtreelist.o htmlparse.o myhtmlparse.o mimehandler.o internfile.o mh_exec.o mh_execm.o mh_html.o mh_mail.o mh_mbox.o mh_text.o docseq.o docseqdb.o docseqhist.o filtseq.o dynconf.o plaintorich.o recollq.o reslistpager.o sortseq.o wasastringtoquery.o wasatorcl.o rcldb.o rcldoc.o rclquery.o searchdata.o stemdb.o stoplist.o base64.o circache.o closefrom.o conftree.o copyfile.o debuglog.o execmd.o fstreewalk.o idfile.o fileudi.o md5.o mimeparse.o netcon.o pathut.o pxattr.o rclionice.o readfile.o smallut.o transcode.o wipedir.o x11mon.o mime-getpart.o mime-parsefull.o mime-parseonlyheader.o mime-printbody.o mime-printdoc.o mime-printheader.o mime.o convert.o iodevice.o iofactory.o
DEPS = rclaspell.dep.stamp beaglequeuecache.dep.stamp rclconfig.dep.stamp rclinit.dep.stamp textsplit.dep.stamp unacpp.dep.stamp beaglequeue.dep.stamp csguess.dep.stamp fsindexer.dep.stamp indexer.dep.stamp mimetype.dep.stamp htmlparse.dep.stamp myhtmlparse.dep.stamp mimehandler.dep.stamp internfile.dep.stamp mh_exec.dep.stamp mh_execm.dep.stamp mh_html.dep.stamp mh_mail.dep.stamp mh_mbox.dep.stamp mh_text.dep.stamp docseq.dep.stamp docseqdb.dep.stamp docseqhist.dep.stamp filtseq.dep.stamp dynconf.dep.stamp plaintorich.dep.stamp recollq.dep.stamp reslistpager.dep.stamp sortseq.dep.stamp wasastringtoquery.dep.stamp wasatorcl.dep.stamp rcldb.dep.stamp rcldoc.dep.stamp rclquery.dep.stamp searchdata.dep.stamp stemdb.dep.stamp stoplist.dep.stamp base64.dep.stamp circache.dep.stamp closefrom.dep.stamp conftree.dep.stamp copyfile.dep.stamp debuglog.dep.stamp execmd.dep.stamp fstreewalk.dep.stamp idfile.dep.stamp fileudi.dep.stamp md5.dep.stamp mimeparse.dep.stamp netcon.dep.stamp pathut.dep.stamp pxattr.dep.stamp rclionice.dep.stamp readfile.dep.stamp smallut.dep.stamp transcode.dep.stamp wipedir.dep.stamp x11mon.dep.stamp mime-getpart.dep.stamp mime-parsefull.dep.stamp mime-parseonlyheader.dep.stamp mime-printbody.dep.stamp mime-printdoc.dep.stamp mime-printheader.dep.stamp mime.dep.stamp convert.dep.stamp iodevice.dep.stamp iofactory.dep.stamp DEPS = rclaspell.dep.stamp beaglequeuecache.dep.stamp rclconfig.dep.stamp rclinit.dep.stamp textsplit.dep.stamp unacpp.dep.stamp beaglequeue.dep.stamp csguess.dep.stamp fsindexer.dep.stamp indexer.dep.stamp mimetype.dep.stamp subtreelist.dep.stamp htmlparse.dep.stamp myhtmlparse.dep.stamp mimehandler.dep.stamp internfile.dep.stamp mh_exec.dep.stamp mh_execm.dep.stamp mh_html.dep.stamp mh_mail.dep.stamp mh_mbox.dep.stamp mh_text.dep.stamp docseq.dep.stamp docseqdb.dep.stamp docseqhist.dep.stamp filtseq.dep.stamp dynconf.dep.stamp plaintorich.dep.stamp recollq.dep.stamp reslistpager.dep.stamp sortseq.dep.stamp wasastringtoquery.dep.stamp wasatorcl.dep.stamp rcldb.dep.stamp rcldoc.dep.stamp rclquery.dep.stamp searchdata.dep.stamp stemdb.dep.stamp stoplist.dep.stamp base64.dep.stamp circache.dep.stamp closefrom.dep.stamp conftree.dep.stamp copyfile.dep.stamp debuglog.dep.stamp execmd.dep.stamp fstreewalk.dep.stamp idfile.dep.stamp fileudi.dep.stamp md5.dep.stamp mimeparse.dep.stamp netcon.dep.stamp pathut.dep.stamp pxattr.dep.stamp rclionice.dep.stamp readfile.dep.stamp smallut.dep.stamp transcode.dep.stamp wipedir.dep.stamp x11mon.dep.stamp mime-getpart.dep.stamp mime-parsefull.dep.stamp mime-parseonlyheader.dep.stamp mime-printbody.dep.stamp mime-printdoc.dep.stamp mime-printheader.dep.stamp mime.dep.stamp convert.dep.stamp iodevice.dep.stamp iofactory.dep.stamp
librcl.a : $(DEPS) $(OBJS) unac.o librcl.a : $(DEPS) $(OBJS) unac.o
ar ru librcl.a $(OBJS) unac.o ar ru librcl.a $(OBJS) unac.o
@ -37,6 +37,8 @@ indexer.o : ../index/indexer.cpp $(depth)/mk/localdefs
$(CXX) $(ALL_CXXFLAGS) -c ../index/indexer.cpp $(CXX) $(ALL_CXXFLAGS) -c ../index/indexer.cpp
mimetype.o : ../index/mimetype.cpp $(depth)/mk/localdefs mimetype.o : ../index/mimetype.cpp $(depth)/mk/localdefs
$(CXX) $(ALL_CXXFLAGS) -c ../index/mimetype.cpp $(CXX) $(ALL_CXXFLAGS) -c ../index/mimetype.cpp
subtreelist.o : ../index/subtreelist.cpp $(depth)/mk/localdefs
$(CXX) $(ALL_CXXFLAGS) -c ../index/subtreelist.cpp
htmlparse.o : ../internfile/htmlparse.cpp $(depth)/mk/localdefs htmlparse.o : ../internfile/htmlparse.cpp $(depth)/mk/localdefs
$(CXX) $(ALL_CXXFLAGS) -c ../internfile/htmlparse.cpp $(CXX) $(ALL_CXXFLAGS) -c ../internfile/htmlparse.cpp
myhtmlparse.o : ../internfile/myhtmlparse.cpp $(depth)/mk/localdefs myhtmlparse.o : ../internfile/myhtmlparse.cpp $(depth)/mk/localdefs
@ -192,6 +194,9 @@ indexer.dep.stamp : ../index/indexer.cpp $(depth)/mk/localdefs
mimetype.dep.stamp : ../index/mimetype.cpp $(depth)/mk/localdefs mimetype.dep.stamp : ../index/mimetype.cpp $(depth)/mk/localdefs
$(CXX) -M $(ALL_CXXFLAGS) ../index/mimetype.cpp > mimetype.dep $(CXX) -M $(ALL_CXXFLAGS) ../index/mimetype.cpp > mimetype.dep
touch mimetype.dep.stamp touch mimetype.dep.stamp
subtreelist.dep.stamp : ../index/subtreelist.cpp $(depth)/mk/localdefs
$(CXX) -M $(ALL_CXXFLAGS) ../index/subtreelist.cpp > subtreelist.dep
touch subtreelist.dep.stamp
htmlparse.dep.stamp : ../internfile/htmlparse.cpp $(depth)/mk/localdefs htmlparse.dep.stamp : ../internfile/htmlparse.cpp $(depth)/mk/localdefs
$(CXX) -M $(ALL_CXXFLAGS) ../internfile/htmlparse.cpp > htmlparse.dep $(CXX) -M $(ALL_CXXFLAGS) ../internfile/htmlparse.cpp > htmlparse.dep
touch htmlparse.dep.stamp touch htmlparse.dep.stamp
@ -347,6 +352,7 @@ include csguess.dep
include fsindexer.dep include fsindexer.dep
include indexer.dep include indexer.dep
include mimetype.dep include mimetype.dep
include subtreelist.dep
include htmlparse.dep include htmlparse.dep
include myhtmlparse.dep include myhtmlparse.dep
include mimehandler.dep include mimehandler.dep

View File

@ -15,6 +15,7 @@ ${depth}/index/csguess.cpp \
${depth}/index/fsindexer.cpp \ ${depth}/index/fsindexer.cpp \
${depth}/index/indexer.cpp \ ${depth}/index/indexer.cpp \
${depth}/index/mimetype.cpp \ ${depth}/index/mimetype.cpp \
${depth}/index/subtreelist.cpp \
${depth}/internfile/htmlparse.cpp \ ${depth}/internfile/htmlparse.cpp \
${depth}/internfile/myhtmlparse.cpp \ ${depth}/internfile/myhtmlparse.cpp \
${depth}/internfile/mimehandler.cpp \ ${depth}/internfile/mimehandler.cpp \