// Copyright (c) 2004 David Muse // See the COPYING file for more information #include #include #include // for DIR #ifdef RUDIMENTS_HAVE_DIRENT_H #include #else #include #endif #include #ifdef RUDIMENTS_HAVE_UNISTD_H #include #endif #include #include #ifdef RUDIMENTS_NAMESPACE namespace rudiments { #endif class directoryprivate { friend class directory; private: DIR *_dir; uint64_t _currentindex; }; // LAME: not in the class #if !defined(RUDIMENTS_HAVE_READDIR_R) static mutex *_rdmutex; #endif // lame that this isn't part of the class, but I can't think of another way to // keep #ifndef RUDIMENTS_HAVE_DIRENT_H out of the header file #ifdef RUDIMENTS_HAVE_READDIR_R static int64_t bufferSize(directory *d, DIR *dirp) { int64_t name_max=d->maxFileNameLength(); if (name_max==-1) { return -1; } #ifdef RUDIMENTS_HAVE_DIRENT_H //return offsetof(struct dirent, d_name)+name_max+1; return sizeof(struct dirent)+name_max+1; #else return sizeof(struct direct)+name_max+1; #endif } #endif directory::directory() { pvt=new directoryprivate; pvt->_dir=NULL; pvt->_currentindex=0; } directory::~directory() { close(); delete pvt; } bool directory::open(const char *path) { do { pvt->_dir=opendir(path); } while (pvt->_dir==NULL && error::getErrorNumber()==EINTR); return (pvt->_dir!=NULL); } bool directory::close() { bool retval=true; if (pvt->_dir) { do { retval=!closedir(pvt->_dir); } while (!retval && error::getErrorNumber()==EINTR); pvt->_dir=NULL; pvt->_currentindex=0; } return retval; } uint64_t directory::getChildCount() { // handle unopened directory if (!pvt->_dir) { return 0; } // rewind rewinddir(pvt->_dir); pvt->_currentindex=0; #ifdef RUDIMENTS_HAVE_READDIR_R // get the size of the buffer int64_t size=bufferSize(this,pvt->_dir); if (size==-1) { return 0; } #ifdef RUDIMENTS_HAVE_DIRENT_H dirent *entry=reinterpret_cast( new unsigned char[size]); dirent *result; #else direct *entry=reinterpret_cast( new unsigned char[size]); dirent *result; #endif for (;;) { int rdresult; do { rdresult=readdir_r(pvt->_dir,entry,&result); } while (rdresult==-1 && error::getErrorNumber()==EINTR); if (!result) { delete[] entry; return pvt->_currentindex; } pvt->_currentindex++; } #else #ifdef RUDIMENTS_HAVE_DIRENT_H dirent *entry; #else direct *entry; #endif if (_rdmutex && !_rdmutex->lock()) { return 0; } for (;;) { do { entry=readdir(pvt->_dir); } while (!entry && error::getErrorNumber()==EINTR); if (!entry) { if (_rdmutex) { _rdmutex->unlock(); } return pvt->_currentindex; } pvt->_currentindex++; } #endif } char *directory::getChildName(uint64_t index) { // directory entries are 1-based uint64_t actualindex=index+1; if (actualindex_currentindex) { // handle unopened directory if (!pvt->_dir) { return NULL; } // rewind rewinddir(pvt->_dir); pvt->_currentindex=0; } #ifdef RUDIMENTS_HAVE_READDIR_R // get the size of the buffer int64_t size=bufferSize(this,pvt->_dir); if (size==-1) { return NULL; } #ifdef RUDIMENTS_HAVE_DIRENT_H dirent *entry=reinterpret_cast( new unsigned char[size]); dirent *result; #else direct *entry=reinterpret_cast( new unsigned char[size]); dirent *result; #endif for (uint64_t i=pvt->_currentindex; i_dir,entry,&result); } while (rdresult==-1 && error::getErrorNumber()==EINTR); if (rdresult || !result) { delete[] entry; return NULL; } pvt->_currentindex++; } char *retval=charstring::duplicate(result->d_name); delete[] entry; return retval; #else #ifdef RUDIMENTS_HAVE_DIRENT_H dirent *entry; #else direct *entry; #endif if (_rdmutex && !_rdmutex->lock()) { return NULL; } for (uint64_t i=pvt->_currentindex; i_dir); } while (!entry && error::getErrorNumber()==EINTR); if (!entry) { return NULL; } pvt->_currentindex++; } char *retval=charstring::duplicate(entry->d_name); if (_rdmutex) { _rdmutex->unlock(); } return retval; #endif } bool directory::create(const char *path, mode_t perms) { int result; do { result=mkdir(path,perms); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; } bool directory::remove(const char *path) { int result; do { result=rmdir(path); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; } char *directory::getCurrentWorkingDirectory() { size_t size=1024; for (;;) { char *buffer=new char[size]; char *result; do { result=getcwd(buffer,size); } while (!result && error::getErrorNumber()==EINTR); if (result) { return buffer; } else { delete[] buffer; size=size+1024; if (size>10240) { return NULL; } } } } bool directory::changeDirectory(const char *path) { int result; do { result=chdir(path); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; } bool directory::changeRoot(const char *path) { int result; do { result=chroot(path); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; } bool directory::needsMutex() { #if !defined(RUDIMENTS_HAVE_READDIR_R) return true; #else return false; #endif } void directory::setMutex(mutex *mtx) { #if !defined(RUDIMENTS_HAVE_READDIR_R) _rdmutex=mtx; #endif } int64_t directory::maxFileNameLength(const char *pathname) { int64_t retval=pathConf(pathname,_PC_NAME_MAX); #if defined(NAME_MAX) if (retval==-1) { retval = NAME_MAX; } #endif return retval; } int64_t directory::maxPathLength(const char *pathname) { return pathConf(pathname,_PC_PATH_MAX); } bool directory::canAccessLongFileNames(const char *pathname) { return !pathConf(pathname,_PC_NO_TRUNC); } int64_t directory::pathConf(const char *pathname, int name) { int64_t result; do { result=pathconf(pathname,name); } while (result==-1 && error::getErrorNumber()==EINTR); return result; } int64_t directory::maxFileNameLength() { int64_t retval=fpathConf(_PC_NAME_MAX); #if defined(NAME_MAX) if (retval==-1) { retval = NAME_MAX; } #endif return retval; } int64_t directory::maxPathLength() { return fpathConf(_PC_PATH_MAX); } bool directory::canAccessLongFileNames() { return !fpathConf(_PC_NO_TRUNC); } int64_t directory::fpathConf(int name) { int64_t result; do { result=fpathconf( #if defined(RUDIMENTS_HAVE_DIRFD) dirfd(pvt->_dir) #elif defined(RUDIMENTS_HAVE_DIR_DD_FD) pvt->_dir->dd_fd #elif defined(RUDIMENTS_HAVE_DIR_D_FD) pvt->_dir->d_fd #else #error need dirfd replacement #endif ,name); } while (result==-1 && error::getErrorNumber()==EINTR); return result; } #ifdef RUDIMENTS_NAMESPACE } #endif