|
Packit |
8f70b4 |
/*
|
|
Packit |
8f70b4 |
* lftp - file transfer program
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net)
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8f70b4 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8f70b4 |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit |
8f70b4 |
* (at your option) any later version.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
8f70b4 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8f70b4 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8f70b4 |
* GNU General Public License for more details.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
8f70b4 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
8f70b4 |
*/
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include <config.h>
|
|
Packit |
8f70b4 |
#include "keyvalue.h"
|
|
Packit |
8f70b4 |
#include <unistd.h>
|
|
Packit |
8f70b4 |
#include "trio.h"
|
|
Packit |
8f70b4 |
#include <fcntl.h>
|
|
Packit |
8f70b4 |
#include <errno.h>
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int KeyValueDB::Read(int fd)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
xstring key;
|
|
Packit |
8f70b4 |
xstring value;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int c;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
FILE *f=fdopen(fd,"r");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
c=getc(f);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// skip leading space
|
|
Packit |
8f70b4 |
while(c!=EOF && (c==' ' || c=='\t'))
|
|
Packit |
8f70b4 |
c=getc(f);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(c==EOF)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
if(c=='\n')
|
|
Packit |
8f70b4 |
continue; // next line
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
key.truncate(0);
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
key.append(c);
|
|
Packit |
8f70b4 |
c=getc(f);
|
|
Packit |
8f70b4 |
if(c==EOF)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
if(c==' ' || c=='\t' || c=='\n')
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(c==EOF || c=='\n' || key.length()==0)
|
|
Packit |
8f70b4 |
break; // invalid line
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// skip space in mid
|
|
Packit |
8f70b4 |
while(c!=EOF && (c==' ' || c=='\t'))
|
|
Packit |
8f70b4 |
c=getc(f);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(c==EOF || c=='\n')
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
value.truncate(0);
|
|
Packit |
8f70b4 |
for(;;)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
value.append(c);
|
|
Packit |
8f70b4 |
c=getc(f);
|
|
Packit |
8f70b4 |
if(c==EOF)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
if(c=='\n')
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Add(key,value);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(c==EOF)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
fclose(f);
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int KeyValueDB::VKeyCompare(const void *a,const void *b)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
KeyValueDB::Pair *pa=*(KeyValueDB::Pair*const*)a;
|
|
Packit |
8f70b4 |
KeyValueDB::Pair *pb=*(KeyValueDB::Pair*const*)b;
|
|
Packit |
8f70b4 |
return KeyValueDB::KeyCompare(pa,pb);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void KeyValueDB::Sort()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int count=0;
|
|
Packit |
8f70b4 |
Pair *scan;
|
|
Packit |
8f70b4 |
for(scan=chain; scan; scan=scan->next)
|
|
Packit |
8f70b4 |
count++;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(count==0)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Pair **arr=(Pair**)alloca(count*sizeof(*arr));
|
|
Packit |
8f70b4 |
count=0;
|
|
Packit |
8f70b4 |
for(scan=chain; scan; scan=scan->next)
|
|
Packit |
8f70b4 |
arr[count++]=scan;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
qsort(arr,count,sizeof(*arr),&KeyValueDB::VKeyCompare);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
chain=0;
|
|
Packit |
8f70b4 |
while(count--)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
arr[count]->next=chain;
|
|
Packit |
8f70b4 |
chain=arr[count];
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char *KeyValueDB::Format(StringMangler value_mangle)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Sort();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Pair *p;
|
|
Packit |
8f70b4 |
int max_key_len=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
for(p=chain; p; p=p->next)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int len=strlen(p->key);
|
|
Packit |
8f70b4 |
if(len>max_key_len)
|
|
Packit |
8f70b4 |
max_key_len=len;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
max_key_len&=~7; // save some bytes
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring buf("");
|
|
Packit |
8f70b4 |
for(p=chain; p; p=p->next)
|
|
Packit |
8f70b4 |
buf.appendf("%-*s\t%s\n",max_key_len,p->key.get(),value_mangle(p->value));
|
|
Packit |
8f70b4 |
return buf.borrow();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int KeyValueDB::Write(int fd)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
xstring_ca buf(Format());
|
|
Packit |
8f70b4 |
int res=write(fd,buf,strlen(buf));
|
|
Packit |
8f70b4 |
close(fd);
|
|
Packit |
8f70b4 |
return res;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void KeyValueDB::Add(const char *key,const char *value)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Pair **p=LookupPair(key);
|
|
Packit |
8f70b4 |
if(!p)
|
|
Packit |
8f70b4 |
AddPair(NewPair(key,value));
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
p[0]->SetValue(value);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void KeyValueDB::Remove(const char *key)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Pair **p=LookupPair(key);
|
|
Packit |
8f70b4 |
if(p)
|
|
Packit |
8f70b4 |
Purge(p);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
KeyValueDB::Pair **KeyValueDB::LookupPair(const char *key) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
for(const Pair * const*p=&chain; *p; p=&(*p)->next)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if((*p)->KeyCompare(key)==0)
|
|
Packit |
8f70b4 |
return const_cast<KeyValueDB::Pair **>(p);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *KeyValueDB::Lookup(const char *key) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const Pair * const*p=LookupPair(key);
|
|
Packit |
8f70b4 |
return p ? (*p)->value.get() : 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int KeyValueDB::Lock(int fd,int type)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
struct flock lk;
|
|
Packit |
8f70b4 |
lk.l_type=type;
|
|
Packit |
8f70b4 |
lk.l_whence=0;
|
|
Packit |
8f70b4 |
lk.l_start=0;
|
|
Packit |
8f70b4 |
lk.l_len=0;
|
|
Packit |
8f70b4 |
int res=fcntl(fd,F_SETLK,&lk;;
|
|
Packit |
8f70b4 |
if(res==-1 && E_RETRY(errno))
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int retries=5;
|
|
Packit |
8f70b4 |
bool echo=true;
|
|
Packit |
8f70b4 |
for(int i=0; i
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
sleep(1);
|
|
Packit |
8f70b4 |
if(echo && write(2,".",1)==-1)
|
|
Packit |
8f70b4 |
echo=false;
|
|
Packit |
8f70b4 |
res=fcntl(fd,F_SETLK,&lk;;
|
|
Packit |
8f70b4 |
if(res==0)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(echo && write(2,"\r",1)==-1)
|
|
Packit |
8f70b4 |
echo=false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
if(res==-1 && E_LOCK_IGNORE(errno))
|
|
Packit |
8f70b4 |
return 0;
|
|
Packit |
8f70b4 |
return res;
|
|
Packit |
8f70b4 |
}
|