Algorithm 版 (精华区)
发信人: Lerry (想不开·撞树), 信区: Algorithm
标 题: parkerd.c
发信站: 哈工大紫丁香 (2002年06月09日21:27:58 星期天), 站内信件
/*
* NoseyParker, the search engine for FTP archives
* Copyright (C) 1993-96 by Jiri A. Randus
*
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* The author can be reached as follows:
* Internet: <Jiri.Randus@vslib.cz>
* Phone: ++42 48 5227374
* SnailMail: Jiri Randus
* KIN HF TU v Liberci
* Halkova 6
* 46117 Liberec
* Czech Republic
*/
#define PARKERD_VERSION "3.23"
#include "parker.h"
char ThisHost[MAX];
struct FileDBList {char *file; struct FileDBList *next;};
struct FileDBList *FDBhead=NULL;
struct CMDS {char *command; void (*cmd)(char *); char *help;} Cmds[];
FILE *idx;
char *exline[MAX]={ GREP, "-i", NULL, NULL};
int Counter=-1;
char RestartK[MAX]="";
int SearchFiles=0;
char FilesPath[MAX];
char FilesFile[MAX];
char FilesSize[MAX];
void Quit(char *);
void Chop(char *s)
{
char *ptr;
if((ptr=strchr(s,CR))!=NULL) *ptr='\0';
if((ptr=strchr(s,LF))!=NULL) *ptr='\0';
}
void main(void)
{
int i;
char Command[MAX];
dup2(0,1);
dup2(0,2);
gethostname(ThisHost,MAX);
#ifndef DEBUG
if(chdir(PARKER_HOME)) {
printf("550 Can't chdir to PARKER_HOME %s\n", PARKER_HOME);
exit(101);
}
#endif
setlinebuf(stdin);
setlinebuf(stdout);
printf("220 This is %s, NoseyParker %s, Server V%s\n",ThisHost,VERSION, PA
RKERD_VERSION);
while(1)
{
#ifndef DEBUG
if(chdir(PARKER_HOME)) {
printf("550 Can't chdir to PARKER_HOME %s\n", PARKER_HOME);
exit(101);
}
#endif
fflush(stdout);
fgets(Command,MAX,stdin);
if(feof(stdin)) Quit(" ");
Chop(Command);
for(i=0;Cmds[i].command;i++)
if(!strncasecmp(Cmds[i].command,Command,strlen(Cmds[i].command))) {
Cmds[i].cmd(Command);
break;
}
if(!Cmds[i].command) puts("500 Command not understood");
}
}
void Quit(char *CLine)
{
*CLine='\0';
printf("221 %s closing connection\n",ThisHost);
exit(0);
}
void Reset(char *CLine)
{
*CLine='\0';
Counter=-1;
*RestartK='\0';
SearchFiles=0;
puts("205 Reset OK");
}
void Files(char *CLine)
{
*CLine='\0';
SearchFiles=1;
printf("206 FileSeach OK\n");
}
void Hosts(char *CLine)
{
*CLine='\0';
SearchFiles=0;
printf("207 HostsSearch OK\n");
}
void Hits(char *CLine)
{
char *ptr;
if((ptr=strchr(CLine,' '))!=NULL) sscanf(ptr,"%d",&Counter);
else Counter=-1;
if(Counter==0) Counter=-1;
printf("208 Ok, the hitcounter set to %d %s\n",Counter,
(Counter==-1)?"(Unlimited)":"");
}
void Restart(char *CLine)
{
char *ptr;
if((ptr=strchr(CLine,' '))!=NULL)
{
strcpy(RestartK,ptr+1);
printf("209 Ok, the restart point set to %s\n",RestartK);
}
else
{
*RestartK='\0';
printf("209 Ok, the restart point unset\n");
}
}
void TopDir(char *CLine)
{
char *ptr;
FILE *f;
char genbuf[MAX];
if(!(ptr=strchr(CLine,' '))) {
printf("501 Ho host specified\n");
return;
}
sprintf(genbuf,"%s/%sDB.%s.topdir",PARKER_HOME,SEEDDB,ptr+1);
if(!(f=fopen(genbuf,"r"))) {
printf("554 Cannot open %s\n",genbuf);
return;
}
fgets(genbuf,MAX,f);
fclose(f);
Chop(genbuf);
printf("216 %s\n",genbuf);
return;
}
void Status(char *CLine)
{
FILE *status;
char buf[MAX];
*CLine='\0';
if(!(status=fopen(STATUSTXT,"r"))) {
puts("550 No status available");
return;
}
while(!feof(status))
{
fgets(buf,MAX,status);
if(feof(status)) break;
printf("211-%s",buf);
}
fclose(status);
puts("211 *** end of status ***");
}
void Help(char *CLine)
{
int i;
*CLine='\0';
for(i=0;Cmds[i].command;i++)
printf("214- %s\n",Cmds[i].help);
puts("214-");
puts("214 end of help");
}
void Egrep(char *seekfor, int count)
{
char genbuf[MAX];
char path[MAX];
int j;
char *ptr;
int fd[2];
FILE *pathdb, *dbfile, *egrep;
DIR *serverdir;
struct dirent *dirp;
long offset,oldoffset;
pid_t child;
if(!(serverdir=opendir("."))) {puts("550 Can't open dir");exit(106);}
j=3;
pipe(fd);
if((child=fork())==-1) {puts("545 Fork failed"); return;}
if(!child) {
dup2(fd[0],0);
close(fd[0]);
close(fd[1]);
exline[2]=seekfor;
exline[3]=NULL;
execve(GREPPATH, exline, NULL);
perror("500 Grep exec failed");
exit(1);
}
close(fd[0]);
if(!(pathdb=fopen(SEEDPATHDB,"r"))) {
perror("550 Cannot open SEEDPATHDB");
return;
}
if(!(egrep=fdopen(fd[1],"w"))) {
perror("555 Cannot fdopen pipe to egrep");
return;
}
else while((dirp=readdir(serverdir))!=NULL)
{
oldoffset=-1;
if((strncmp(dirp->d_name,EXCLUDEFILES,strlen(EXCLUDEFILES))) &&
(strcmp(dirp->d_name,CORE)) &&
(*dirp->d_name!='.') &&
((dbfile=fopen(dirp->d_name,"r"))!=NULL))
while(1) {
fgets(genbuf,MAX,dbfile);
if(feof(dbfile)) break;
ptr=NULL;
ptr=strrchr(genbuf,' ');
*ptr++='\0';
sscanf(ptr,"%ld",&offset);
if(offset==-1) fprintf(egrep,"200-%s:%s\n",dirp->d_name,genbuf);
else if(offset==oldoffset)
fprintf(egrep,"200-%s:%s/%s\n",dirp->d_name,path,genbuf);
else {
oldoffset=offset;
fseek(pathdb,offset,SEEK_SET);
fgets(path,MAX,pathdb);
Chop(path);
if(!path[1]) *path='\0';
if(!(fprintf(egrep,"200-%s:%s/%s\n",dirp->d_name,path,genbuf)))
{ /* Did the client close the connection prematurely? */
break;
}
}
}
}
fclose(egrep);
close(fd[1]);
fclose(pathdb);
closedir(serverdir);
kill(child, SIGTERM);
wait(NULL);
puts("\n257 End of E search");
}
void LoadFDB(void)
{
FILE *filedb;
char buffer[MAX];
struct FileDBList *FDBptr;
struct FileDBList *FDBptr2;
if(!(filedb=fopen(SEEDFILEDB,"r"))) {
perror("550 Cannot open SEEDFILEDB");
exit(101);
}
while(1)
{
fgets(buffer,MAX,filedb);
if(feof(filedb)) break;
Chop(buffer);
FDBptr=malloc(sizeof(struct FileDBList));
FDBptr->file=strdup(buffer);
FDBptr->next=NULL;
if(!FDBhead) FDBhead=FDBptr;
else {
for(FDBptr2=FDBhead;FDBptr2->next;FDBptr2=FDBptr2->next);
FDBptr2->next=FDBptr;
}
}
fclose(filedb);
}
int FindBItem(FILE *idx, char *key, struct DiskBTreeHead *head)
{
int i;
while(1)
{
fread(head, sizeof(struct DiskBTreeHead), 1, idx);
if(!strncasecmp(key, head->key, KEYSIZE)) return(S_OK);
for(i=0;i<B;i++)
{
if((*head->treerefs[i].top) &&
(strncasecmp(key,head->treerefs[i].top,KEYSIZE)<=0))
{
fseek(idx, head->treerefs[i].offset, SEEK_SET);
break;
}
}
if(i==B) return(S_ERROR);
}
}
void DumpRefs(FILE *idx, long numrefs, long restart)
{
union DiskTripleRef ref;
struct FileDBList *FDBptr;
FILE *db;
char buffer[MAX];
long itemcnt;
db=NULL;
FDBptr=NULL;
itemcnt=0L;
while(numrefs--)
{
fread(&ref, sizeof(union DiskTripleRef), 1, idx);
if(ref.file.mark==BTREEENDMARK) {
if(db) fclose(db);
FDBptr=FDBhead;
while((FDBptr)&&(ref.file.fileno--)) FDBptr=FDBptr->next;
if(!FDBptr) {fprintf(stderr,"Error: out of FDB\n");exit(105);}
db=fopen(FDBptr->file,"r");
continue;
}
if(!restart || (restart<itemcnt)) {
fseek(db, ref.offset, SEEK_SET);
fgets(buffer,MAX,db);
/* It ends with CR/LF; cut off when interrupted */
if(!printf("%ld|%s:%s",itemcnt,FDBptr->file,buffer)) break;
}
itemcnt++;
}
fclose(db);
}
void OpenIdx(void)
{
switch(SearchFiles)
{
case 0:
if(!(idx=fopen(SEEDBTREE,"r"))) {
perror("550 Cannot open SEEDBTREE");
exit(102);
}
break;
case 1:
if(!(idx=fopen(SEEDBTREEFILES,"r"))) {
perror("550 Cannot open SEEDBTREEFILES");
exit(102);
}
break;
default:
break;
}
}
void DumpBTree(long restart)
{
struct DiskBTreeHead head;
if(!FDBhead) LoadFDB();
if(!idx) {fprintf(stderr,"ERROR ! Idx not open !\n");return;}
fread(&head, sizeof(struct DiskBTreeHead), 1, idx);
DumpRefs(idx, head.numrefs, restart);
fclose(idx);
idx=NULL;
}
int DumpFilesSearch(char *path, char *file, int *count)
{
char *size;
char *ptr, *ptr1;
int rc;
if(!path) {
/* a call to flush down the buffers */
if(*FilesFile) {
printf("200-*:%s%s%s",FilesPath,(strcmp(FilesPath,"/"))?"/":"",
FilesFile);
if(FilesFile[strlen(FilesFile)-1]!='/') printf(" %s", FilesSize);
printf("\n");
}
return(1);
}
/* Cut off the size/date from the filename */
if((size=strchr(file,' '))!=NULL) *size++='\0';
/* Cut off the date from the size */
if(size &&((ptr=strchr(size,' '))!=NULL)) *ptr='\0';
if(!strcasecmp(file,FilesFile) && ((file[strlen(file)-1]=='/') ||
!size || !strcasecmp(size,FilesSize)))
{
/* if counted, increase the counter */
if(*count!=-1) (*count)++;
/* Compare the paths */
ptr1=path+strlen(path)-1;
ptr=FilesPath+strlen(FilesPath)-1;
while(ptr>FilesPath)
if(tolower(*ptr)!=tolower(*ptr1)) break; else {ptr--;ptr1--;}
if(ptr!=FilesPath) strcpy(FilesPath,ptr+1);
rc=1;
}
else {
/* a new file */
if(*FilesFile) {
rc=printf("200-*:%s%s%s",FilesPath,(strcmp(FilesPath,"/"))?"/":"",
FilesFile);
if(FilesFile[strlen(FilesFile)-1]!='/') printf(" %s", FilesSize);
printf("\n");
} else rc=1;
strcpy(FilesPath,path);
strcpy(FilesFile,file);
if(size) strcpy(FilesSize,size); else *FilesSize='\0';
}
return(rc);
}
void egrepDB(char *key,char *seekfor,int count, long restart)
{
char genbuf[MAX];
char path[MAX];
char lastoff[MAX];
char *ptr,*ptr1,*ptr3;
int intoegrep[2], outofegrep[2];
FILE *egrep,*pathdb;
long offset;
pid_t child1, child2;
*FilesPath=*FilesFile=*FilesSize='\0';
pipe(intoegrep);
pipe(outofegrep);
fflush(stdout);
if((child1=fork())==-1) {puts("545 Btree fork failed"); return;}
if(!child1) {
dup2(intoegrep[1],1);
close(intoegrep[0]);
close(intoegrep[1]);
close(outofegrep[0]);
close(outofegrep[1]);
DumpBTree(restart);
exit(0);
}
if((child2=fork())==-1) {puts("545 Egrep fork failed"); return;}
if(!child2) {
dup2(intoegrep[0],0);
close(intoegrep[0]);
close(intoegrep[1]);
dup2(outofegrep[1],1);
close(outofegrep[0]);
close(outofegrep[1]);
exline[2]=seekfor;
execve(GREPPATH, exline, NULL);
perror("Grep exec failed");
exit(1);
}
close(outofegrep[1]);
close(intoegrep[0]);
close(intoegrep[1]);
if(!(egrep=fdopen(outofegrep[0],"r")))
{
puts("555 Cannot open pipe thru fdopen");
return;
}
if(!(pathdb=fopen(SEEDPATHDB,"r")))
perror("550 Cannot open SEEDPATHDB");
else {
while((count==-1) || count)
{
count--;
fgets(genbuf,MAX,egrep);
if(feof(egrep)) break;
ptr=NULL;
/* Cut off the restart code & the host name */
ptr3=strchr(genbuf,':');
if(!ptr3) return;
*ptr3++='\0';
/* Cut off the restart code */
ptr1=strchr(genbuf,'|');
if(!ptr1) continue;
*ptr1++='\0';
/* Cut off the pathDB offset */
ptr=strrchr(ptr3,' ');
if(ptr) {
*ptr++='\0';
sscanf(ptr,"%ld",&offset);
}
else offset=-1;
strcpy(lastoff,genbuf);
/* offset missing ? */
if(offset==-1) printf("200-%s:%s\n",ptr1,ptr3);
else {
fseek(pathdb,offset,SEEK_SET);
fgets(path,MAX,pathdb);
Chop(path);
if(!SearchFiles) { /* Sort by hosts */
/* Did the client close the connection prematurely? */
if(!printf("200-%s:%s/%s\n",ptr1,path[1]?path:"",ptr3)) break;
}
else if(!DumpFilesSearch(path,ptr3,&count)) break;
}
}
if(SearchFiles) DumpFilesSearch(NULL,NULL,NULL);
fclose(pathdb);
fclose(egrep);
if(!count)
printf("258 End of S/W search (\"%s%s\" to continue)\n",key,lastoff);
else printf("257 End of S/W search\n");
}
/* Paranoia precaution */
kill(child1, SIGTERM);
kill(child2, SIGTERM);
wait(NULL);
wait(NULL);
close(intoegrep[0]);
close(intoegrep[1]);
close(outofegrep[0]);
close(outofegrep[1]);
}
void Substring(char *CLine)
{
char *p;
char pattern[MAX];
char *c;
char z[2];
char key[KEYSIZE+1];
struct DiskBTreeHead head;
long minrefs;
long bestoffset;
long Res;
int len;
int i=0;
#ifndef DEBUG
if(chdir(SEEDDB)) {printf("550 Can't chdir to SEEDDB %s\n",SEEDDB);exit(10
6);}
#endif
if(!(c=strchr(CLine,' '))) {
puts("501 No lookup key");
return;
}
while(*c && (*c==' ')) c++;
if(!*c) {
puts("501 No lookup key");
return;
}
Chop(c);
if(strlen(c)<MINLENGTHOFSEARCH)
{
puts("504 The query is too short");
return;
}
if(!idx) OpenIdx();
minrefs=-1;
bestoffset=0L;
if(!*RestartK) {
len=strlen(c)-KEYSIZE;
for(i=0;i<=len;i++)
{
rewind(idx);
if(FindBItem(idx, &c[i], &head)!=S_OK) {
bestoffset=-1;
break;
}
if((minrefs==-1) || (minrefs>head.numrefs)) {
strncpy(key,&c[i],KEYSIZE);
minrefs=head.numrefs;
bestoffset=ftell(idx)-sizeof(struct DiskBTreeHead);
}
}
if(bestoffset==-1) {
Log("Unsuccessful substring search for %s",c,NULL);
puts("125 Dummy searching");
puts("257 End of dummy search");
return;
}
key[KEYSIZE]='\0';
Res=0L;
}
else /* Restarting the search */
{
strncpy(key,RestartK,KEYSIZE);
key[KEYSIZE]='\0';
sscanf(&RestartK[KEYSIZE],"%ld",&Res);
rewind(idx);
if(FindBItem(idx, key, &head)!=S_OK) {
Log("Unsuccessful restarted substring search for %s",c,NULL);
puts("125 Dummy restarted searching");
puts("257 End of dummy search");
return;
}
bestoffset=ftell(idx)-sizeof(struct DiskBTreeHead);
}
fseek(idx, bestoffset, SEEK_SET);
printf("125 Searching (key=`%s', restart at %ld)\n",key,Res);
fflush(stdout);
Log("Substring search for %s",c,NULL);
p=c;
strcpy(pattern,"^[^:]*:.*");
z[1]='\0';
while(*p)
{
*z=*p++;
if(strchr(SPECIALREGCHAR,*z)) strcat(pattern,"\\");
strcat(pattern,z);
}
strcat(pattern,"[^/]*/? ");
egrepDB(key,pattern,Counter,Res);
*RestartK='\0';
}
void Wildcards(char *CLine)
{
char *p;
char pattern[MAX];
char *c;
char z[2];
char key[KEYSIZE+1];
struct DiskBTreeHead head;
long minrefs;
long bestoffset;
int len;
int i=0;
long Res;
#ifndef DEBUG
if(chdir(SEEDDB)) {printf("550 Can't chdir to SEEDDB %s\n",SEEDDB);exit(10
6);}
#endif
if(!(c=strchr(CLine,' '))) {
puts("501 No lookup key");
return;
}
while(*c && (*c==' ')) c++;
if(!*c) {
puts("501 No lookup key");
return;
}
Chop(c);
if(!idx) OpenIdx();
minrefs=-1;
bestoffset=0L;
len=strlen(c)-KEYSIZE;
if(!*RestartK) {
for(i=0;i<=len;i++)
{
if(!strchr(SPECIALWILDCHAR,c[i]) &&
!strchr(SPECIALWILDCHAR,c[i+1]) &&
!strchr(SPECIALWILDCHAR,c[i+2]))
{
rewind(idx);
if(FindBItem(idx, &c[i], &head)!=S_OK) {
bestoffset=-1;
break;
}
if((minrefs==-1) || (minrefs>head.numrefs)) {
strncpy(key,&c[i],KEYSIZE);
minrefs=head.numrefs;
bestoffset=ftell(idx)-sizeof(struct DiskBTreeHead);
}
}
}
if(bestoffset==-1) {
Log("Unsuccessful wildcards search for %s",c,NULL);
puts("125 Dummy searching");
puts("257 End of dummy search");
return;
}
if(minrefs==-1) {
puts("501 Wildcards must contain at least 3 subsequent ASCII character
s");
return;
}
Res=0L;
}
else /* Restarting the search */
{
strncpy(key,RestartK,KEYSIZE);
key[KEYSIZE]='\0';
sscanf(&RestartK[KEYSIZE],"%ld",&Res);
rewind(idx);
if(FindBItem(idx, key, &head)!=S_OK) {
Log("Unsuccessful restarted substring search for %s",c,NULL);
puts("125 Dummy restarted searching");
puts("257 End of dummy search");
return;
}
bestoffset=ftell(idx)-sizeof(struct DiskBTreeHead);
}
fseek(idx, bestoffset, SEEK_SET);
key[KEYSIZE]='\0';
printf("125 Searching (key=`%s', restart at %ld)\n",key,Res);
fflush(stdout);
Log("Wildcards search for %s",c,NULL);
p=c;
strcpy(pattern,"^[^:]*:");
z[1]='\0';
while(*p)
{
if(*p=='?') strcat(pattern,"[^/]");
else if(*p=='*') strcat(pattern,"[^/]*");
else {
*z=*p;
if(strchr(SPECIALREGCHAR,*z)) strcat(pattern,"\\");
strcat(pattern,z);
}
p++;
}
strcat(pattern,"/? ");
egrepDB(key,pattern,Counter,Res);
*RestartK='\0';
}
void AskEgrep(char *CLine)
{
char *p,*ptr;
char *c;
int okegrep;
char buf[MAX];
#ifndef DEBUG
if(chdir(SEEDDB)) {printf("550 Can't chdir to SEEDDB %s\n",SEEDDB);exit(10
6);}
#endif
if(!(c=strchr(CLine,' '))) {
puts("501 No lookup key");
return;
}
while(*c && (*c==' ')) c++;
if(!*c) {
puts("501 No lookup key");
return;
}
Chop(c);
if(strlen(c)<MINLENGTHOFSEARCH) {
puts("504 The query is too short");
return;
}
p=SPECIALREGCHAR;
okegrep=0;
while(*p)
{
ptr=c-1;
while((ptr=strchr(ptr+1,*p))!=NULL) okegrep++;
p++;
}
if(okegrep<2) {
puts("504 Not a regular expression. This doesn't look like an Egrep quer
y.");
return;
}
if(*c=='^') { /* the regexp starts with carrot -> gotta insert 200- */
sprintf(buf,"^200-%s",c+1);
strcpy(c,buf);
}
puts("125 Searchin fflush(stdout);
Log("Egrep search for %s",c,NULL);
Egrep(c, Counter);
}
struct CMDS Cmds[]=
{
"help", Help, "help Display this message",
"reset", Reset, "reset Restore default settings",
"files", Files, "files Sort the result by files",
"hosts", Hosts, "hosts Sort the result by hosts",
"hits", Hits, "hits <number> Set the hit count",
"restart", Restart, "restart <rstkey> Enter the restart key",
"substring", Substring, "substring <key> Perform a substring search",
"wildcards", Wildcards, "wildcards <key> Perform a wildcards search",
"egrep", AskEgrep, "egrep <key> Perform an egrep search",
"status", Status, "status Display the database status",
"topdir", TopDir, "topdir <host> Display the top dir of the hierarch
y",
"quit", Quit, "quit Disconnect from the server",
NULL, NULL, NULL
};
--
当一个女孩儿觉得她不太容易了解那个男人的时候,她会爱他。
※ 来源:·哈工大紫丁香 bbs.hit.edu.cn·[FROM: 天外飞仙]
Powered by KBS BBS 2.0 (http://dev.kcn.cn)
页面执行时间:211.342毫秒