open-source-search-engine/Dir.cpp
Matt Wells c669f8c138 fix file descriptor leak in Dir class.
try to fix core from Thread getting SIGALRM.
try to set NOFILES to 1024 at startup in case
more are allowed.
2013-11-19 13:41:56 -08:00

202 lines
4.5 KiB
C++

#include "gb-include.h"
#include "Dir.h"
Dir::Dir ( ) {
m_dirname = NULL;
m_dir = NULL;
m_needsClose = false;
}
Dir::~Dir ( ) {
reset();
}
void Dir::reset ( ) {
close();
if ( m_dirname ) free ( m_dirname );
m_dirname = NULL;
}
bool Dir::set ( char *d1 , char *d2 ) {
reset ();
char tmp[1024];
if ( gbstrlen(d1) + gbstrlen(d2) + 1 > 1024 ) {
log("disk: Could not set directory, directory name \"%s/%s\" "
"is too big.",d1,d2);
return false;
}
sprintf ( tmp , "%s/%s", d1 , d2 );
return set ( tmp );
}
bool Dir::set ( char *dirname ) {
reset ();
m_dirname = strdup ( dirname );
if ( m_dirname ) return true;
log("disk: Could not set directory, directory name to \"%s\": %s.",
dirname,mstrerror(g_errno));
return false;
}
bool Dir::close ( ) {
if ( m_dir && m_needsClose ) closedir ( m_dir );
m_needsClose = false;
return true;
}
bool Dir::open ( ) {
close ( );
if ( ! m_dirname ) return false;
retry8:
m_dir = opendir ( m_dirname );
// interrupted system call
if ( ! m_dir && errno == EINTR ) goto retry8;
g_errno = errno;
if ( ! m_dir )
return log("disk: opendir(%s) : %s",
m_dirname,strerror( g_errno ) );
m_needsClose = true;
return true;
}
// remove all files in m_dirname
bool Dir::cleanOut ( ) {
char buf[1024];
sprintf ( buf , "rm -r %s/*", m_dirname );
system ( buf );
return true;
}
// create m_dirname
bool Dir::create ( ) {
char buf[1024];
sprintf ( buf , "mkdir %s", m_dirname );
system ( buf );
return true;
}
int Dir::getNumFiles ( char *pattern ) {
int count = 0;
while ( getNextFilename ( pattern ) ) count++;
return count;
}
// rewind to get the first filename
void Dir::rewind ( ) {
rewinddir ( m_dir );
}
char *Dir::getNextFilename ( char *pattern ) {
struct dirent *ent;
long plen = gbstrlen ( pattern );
while ( (ent = readdir ( m_dir )) ) {
char *filename = ent->d_name;
if ( ! pattern ) return filename;
if ( plen>2 && pattern[0] == '*' && pattern[plen-1] == '*' ) {
pattern[plen-1]='\0';
char *s = strstr ( filename , pattern+1 ) ;
pattern[plen-1]='*';
if ( ! s ) continue;
else return filename;
}
if ( pattern[0] == '*' ) {
if ( gbstrlen(filename) < gbstrlen(pattern + 1) ) continue;
char *tail = filename +
gbstrlen ( filename ) -
gbstrlen ( pattern ) + 1;
if ( strcmp ( tail , pattern+1) == 0 ) return filename;
}
if ( pattern[plen-1]=='*' ) {
if ( strncmp ( filename , pattern , plen - 1 ) == 0 )
return filename;
}
}
return NULL;
}
// must call set first
// not recursive!
// return -1 on error
long long Dir::getUsedSpace ( ) {
rewinddir ( m_dir );
long long total = 0;
struct dirent *ent ;
while ( ( ent = readdir ( m_dir ) ) ) {
File tmpfile;
tmpfile.set ( ent->d_name );
long long space = tmpfile.getFileSize ( );
if ( space > 0 ) total += space;
}
return total;
}
// . replace the * in the pattern with a unique id from getNewId()
char *Dir::getFullName ( char *filename ) {
static char buf[1024];
sprintf ( buf , "%s/%s", m_dirname , filename );
return buf;
}
// . replace the * in the pattern with a unique id from getNewId()
char *Dir::getNewFilename ( char *pattern ) {
long long id = getNewId ( pattern );
static char buf[1024];
strcpy ( buf , m_dirname );
int j = gbstrlen ( buf );
for ( int i = 0 ; pattern[i] ; i++ ) {
if ( pattern[i] != '*' ) {buf[j++] = pattern[i]; continue;}
sprintf ( &buf[j] , "%lli" , id );
j = gbstrlen ( buf );
}
buf[j++] = '\0';
return buf;
}
// . a highly specialized function
// . gets a new id represented by files of pattern "pattern"
// . if pattern is "*.data" will return the LUB for *, a long long
long long Dir::getNewId ( char *pattern ) {
rewinddir ( m_dir );
char *filename ;
long long lub = 0;
while ( (filename = getNextFilename ( pattern )) ) {
long long id = getFileId ( filename );
if ( id >= lub ) lub = id + 1;
}
return lub;
}
// . another highly specialized function
// . expects filename to begin with a number
// . return -1 if none exists
long long Dir::getFileId ( char *filename ) {
int end = gbstrlen ( filename ) -1;
while ( end >= 0 && filename [ end ] != '.' ) end--;
if ( end < 0 ) return -1;
end--;
while ( end >= 0 && isdigit ( filename [ end ] ) ) end--;
// now 3 cases:
// 1. end = -1 and filename[0] is NOT a digit
// 2. end = -1 and filename[0] is a digit
// 3. end >= 0 and filename[end+1] is a digit
if ( end < 0 && ! isdigit ( filename[0] ) ) return -1;
if ( end < 0 ) end = 0;
else end++;
long long id = -1;
sscanf ( filename + end , "%lli." , & id );
return id;
}