// Copyright (c) 2002 David Muse // See the COPYING file for more information #include #include #include #include #include #include #include #include #include #ifdef RUDIMENTS_HAVE_UNISTD_H #include #endif #include #ifdef RUDIMENTS_HAVE_XATTRS #include #endif #ifdef RUDIMENTS_NAMESPACE namespace rudiments { #endif class fileprivate { friend class file; private: struct stat _st; bool _getcurrentpropertiesonopen; }; file::file() : filedescriptor() { pvt=new fileprivate; rawbuffer::zero(&pvt->_st,sizeof(pvt->_st)); pvt->_getcurrentpropertiesonopen=true; type("file"); } file::file(const file &f) : filedescriptor(f) { pvt=new fileprivate; fileClone(f); type("file"); } file &file::operator=(const file &f) { if (this!=&f) { filedescriptor::operator=(f); fileClone(f); } return *this; } void file::fileClone(const file &f) { pvt->_st=f.pvt->_st; pvt->_getcurrentpropertiesonopen=f.pvt->_getcurrentpropertiesonopen; } file::~file() { delete pvt; } bool file::create(const char *name, mode_t perms) { return open(name,O_CREAT|O_TRUNC|O_RDWR,perms); } ssize_t file::create(const char *name, mode_t perms, unsigned short number) { return create(name,perms,&number,sizeof(unsigned short)); } ssize_t file::create(const char *name, mode_t perms, unsigned long number) { return create(name,perms,&number,sizeof(unsigned long)); } ssize_t file::create(const char *name, mode_t perms, float number) { return create(name,perms,&number,sizeof(float)); } ssize_t file::create(const char *name, mode_t perms, double number) { return create(name,perms,&number,sizeof(double)); } ssize_t file::create(const char *name, mode_t perms, char number) { return create(name,perms,&number,sizeof(char)); } ssize_t file::create(const char *name, mode_t perms, const char *string, size_t size) { return create(name,perms,static_cast(string),size); } ssize_t file::create(const char *name, mode_t perms, const char *string) { return create(name,perms,static_cast(string), charstring::length(string)); } ssize_t file::create(const char *name, mode_t perms, const void *data, size_t size) { size_t retval; fd(openInternal(name,O_CREAT|O_TRUNC|O_RDWR,perms)); if (fd()!=-1 && ((retval=write(data,size))==size) && ((pvt->_getcurrentpropertiesonopen)? getCurrentProperties():true)) { return retval; } close(); return -1; } bool file::createFile(const char *name, mode_t perms) { file fl; return fl.create(name,perms); } ssize_t file::createFile(const char *name, mode_t perms, unsigned short number) { file fl; return fl.create(name,perms,number); } ssize_t file::createFile(const char *name, mode_t perms, unsigned long number) { file fl; return fl.create(name,perms,number); } ssize_t file::createFile(const char *name, mode_t perms, float number) { file fl; return fl.create(name,perms,number); } ssize_t file::createFile(const char *name, mode_t perms, double number) { file fl; return fl.create(name,perms,number); } ssize_t file::createFile(const char *name, mode_t perms, char number) { file fl; return fl.create(name,perms,number); } ssize_t file::createFile(const char *name, mode_t perms, const char *string, size_t size) { file fl; return fl.create(name,perms,string,size); } ssize_t file::createFile(const char *name, mode_t perms, const char *string) { file fl; return fl.create(name,perms,string); } ssize_t file::createFile(const char *name, mode_t perms, const void *data, size_t size) { file fl; return fl.create(name,perms,data,size); } int file::openInternal(const char *name, int flags) { int result; do { result=::open(name,flags); } while (result==-1 && error::getErrorNumber()==EINTR); return result; } int file::openInternal(const char *name, int flags, mode_t perms) { int result; do { result=::open(name,flags,perms); } while (result==-1 && error::getErrorNumber()==EINTR); return result; } bool file::open(const char *name, int flags) { fd(openInternal(name,flags)); return (fd()!=-1 && ((pvt->_getcurrentpropertiesonopen)? getCurrentProperties():true)); } bool file::open(const char *name, int flags, mode_t perms) { fd(openInternal(name,flags,perms)); return (fd()!=-1 && ((pvt->_getcurrentpropertiesonopen)? getCurrentProperties():true)); } char *file::getContents() { off64_t size=(fd()>-1)?pvt->_st.st_size:0; char *contents=new char[size+1]; contents[size]='\0'; return (size==0 || read(contents,size)==size)?contents:NULL; } char *file::getContents(const char *name) { file fl; fl.open(name,O_RDONLY); char *contents=fl.getContents(); fl.close(); return contents; } ssize_t file::getContents(const char *name, unsigned char *buffer, size_t buffersize) { file fl; fl.open(name,O_RDONLY); ssize_t bytes=fl.getContents(buffer,buffersize); fl.close(); return bytes; } ssize_t file::getContents(unsigned char *buffer, size_t buffersize) { return read(buffer,(buffersize<(size_t)getSize())?buffersize:getSize()); } bool file::tryLockFile(short type) const { return tryLockRegion(type,0,0); } bool file::lockFile(short type) const { return lockRegion(type,0,0); } bool file::checkLockFile(short type, struct flock *retlck) const { return checkLockRegion(type,0,0,retlck); } bool file::unlockFile() const { return unlockRegion(0,0); } bool file::tryLockRegion(short type, off64_t start, off64_t len) const { return lock(F_SETLK,type,SEEK_SET,start,len); } bool file::lockRegion(short type, off64_t start, off64_t len) const { return lock(F_SETLKW,type,SEEK_SET,start,len); } bool file::checkLockRegion(short type, off64_t start, off64_t len, struct flock *retlck) const { return checkLock(type,SEEK_SET,start,len,retlck); } bool file::unlockRegion(off64_t start, off64_t len) const { return unlock(SEEK_SET,start,len); } bool file::tryLockFromCurrent(short type, off64_t len) const { return tryLockFromCurrent(type,0,len); } bool file::tryLockFromCurrent(short type, off64_t start, off64_t len) const { return lock(F_SETLK,type,SEEK_CUR,start,len); } bool file::lockFromCurrent(short type, off64_t len) const { return lockFromCurrent(type,0,len); } bool file::lockFromCurrent(short type, off64_t start, off64_t len) const { return lock(F_SETLKW,type,SEEK_CUR,start,len); } bool file::checkLockFromCurrent(short type, off64_t len, struct flock *retlck) const { return checkLockFromCurrent(type,0,len,retlck); } bool file::checkLockFromCurrent(short type, off64_t start, off64_t len, struct flock *retlck) const { return checkLock(type,SEEK_CUR,start,len,retlck); } bool file::unlockFromCurrent(off64_t len) const { return unlockFromCurrent(0,len); } bool file::unlockFromCurrent(off64_t start, off64_t len) const { return unlock(SEEK_CUR,start,len); } bool file::tryLockFromEnd(short type, off64_t len) const { return tryLockFromEnd(type,0,len); } bool file::tryLockFromEnd(short type, off64_t start, off64_t len) const { return lock(F_SETLK,type,SEEK_END,start,len); } bool file::lockFromEnd(short type, off64_t len) const { return lockFromEnd(type,0,len); } bool file::lockFromEnd(short type, off64_t start, off64_t len) const { return lock(F_SETLKW,type,SEEK_END,start,len); } bool file::checkLockFromEnd(short type, off64_t len, struct flock *retlck) const { return checkLockFromEnd(type,0,len,retlck); } bool file::checkLockFromEnd(short type, off64_t start, off64_t len, struct flock *retlck) const { return checkLock(type,SEEK_END,start,len,retlck); } bool file::unlockFromEnd(off64_t len) const { return unlockFromEnd(0,len); } bool file::unlockFromEnd(off64_t start, off64_t len) const { return unlock(SEEK_END,start,len); } bool file::tryLockRemainder(short type, off64_t start) const { return lock(F_SETLK,type,SEEK_SET,start,0); } bool file::lockRemainder(short type, off64_t start) const { return lock(F_SETLKW,type,SEEK_SET,start,0); } bool file::checkLockRemainder(short type, off64_t start, struct flock *retlck) const { return checkLock(type,SEEK_SET,start,0,retlck); } bool file::unlockRemainder(off64_t start) const { return unlock(SEEK_SET,start,0); } bool file::tryLockRemainderFromCurrent(short type) const { return tryLockRemainderFromCurrent(type,0); } bool file::tryLockRemainderFromCurrent(short type, off64_t start) const { return lock(F_SETLK,type,SEEK_CUR,start,0); } bool file::lockRemainderFromCurrent(short type) const { return lockRemainderFromCurrent(type,0); } bool file::lockRemainderFromCurrent(short type, off64_t start) const { return lock(F_SETLKW,type,SEEK_CUR,start,0); } bool file::checkLockRemainderFromCurrent(short type, struct flock *retlck) const { return checkLockRemainderFromCurrent(type,0,retlck); } bool file::checkLockRemainderFromCurrent(short type, off64_t start, struct flock *retlck) const { return checkLock(type,SEEK_CUR,start,0,retlck); } bool file::unlockRemainderFromCurrent() const { return unlockRemainderFromCurrent(0); } bool file::unlockRemainderFromCurrent(off64_t start) const { return unlock(SEEK_CUR,start,0); } bool file::tryLockRemainderFromEnd(short type) const { return tryLockRemainderFromEnd(type,0); } bool file::tryLockRemainderFromEnd(short type, off64_t start) const { return lock(F_SETLK,type,SEEK_END,start,0); } bool file::lockRemainderFromEnd(short type) const { return lockRemainderFromEnd(type,0); } bool file::lockRemainderFromEnd(short type, off64_t start) const { return lock(F_SETLKW,type,SEEK_END,start,0); } bool file::checkLockRemainderFromEnd(short type, struct flock *retlck) const { return checkLockRemainderFromEnd(type,0,retlck); } bool file::checkLockRemainderFromEnd(short type, off64_t start, struct flock *retlck) const { return checkLock(type,SEEK_END,start,0,retlck); } bool file::sequentialAccess(off64_t start, size_t len) const { #if defined(RUDIMENTS_HAVE_POSIX_FADVISE) && \ defined(POSIX_FADV_SEQUENTIAL) return posixFadvise(start,len,POSIX_FADV_SEQUENTIAL); #else return true; #endif } bool file::randomAccess(off64_t start, size_t len) const { #if defined(RUDIMENTS_HAVE_POSIX_FADVISE) && \ defined(POSIX_FADV_RANDOM) return posixFadvise(start,len,POSIX_FADV_RANDOM); #else return true; #endif } bool file::onlyOnce(off64_t start, size_t len) const { #if defined(RUDIMENTS_HAVE_POSIX_FADVISE) && \ defined(POSIX_FADV_NOREUSE) return posixFadvise(start,len,POSIX_FADV_NOREUSE); #else return true; #endif } bool file::willNeed(off64_t start, size_t len) const { #if defined(RUDIMENTS_HAVE_POSIX_FADVISE) && \ defined(POSIX_FADV_WILLNEED) return posixFadvise(start,len,POSIX_FADV_WILLNEED); #else return true; #endif } bool file::wontNeed(off64_t start, size_t len) const { #if defined(RUDIMENTS_HAVE_POSIX_FADVISE) && \ defined(POSIX_FADV_DONTNEED) return posixFadvise(start,len,POSIX_FADV_DONTNEED); #else return true; #endif } bool file::normalAccess(off64_t start, size_t len) const { #if defined(RUDIMENTS_HAVE_POSIX_FADVISE) && \ defined(POSIX_FADV_NORMAL) return posixFadvise(start,len,POSIX_FADV_NORMAL); #else return true; #endif } bool file::reserve(off64_t start, size_t len) const { #ifdef RUDIMENTS_HAVE_POSIX_FALLOCATE int result; do { result=posix_fallocate(fd(),start,len); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; #else return false; #endif } bool file::truncate(const char *filename) { return truncate(filename,0); } bool file::truncate(const char *filename, off64_t length) { int result; do { result=::truncate(filename,length); } while (result==-1 && error::getErrorNumber()==-1); return !result; } bool file::truncate() const { return ftruncate(fd(),0); } bool file::truncate(off64_t length) const { int result; do { result=::ftruncate(fd(),length); } while (result==-1 && error::getErrorNumber()==-1); return !result; } bool file::unlockRemainderFromEnd() const { return unlockRemainderFromEnd(0); } bool file::unlockRemainderFromEnd(off64_t start) const { return unlock(SEEK_END,start,0); } off64_t file::setPositionRelativeToBeginning(off64_t offset) const { return lseek(offset,SEEK_SET); } off64_t file::setPositionRelativeToCurrent(off64_t offset) const { return lseek(offset,SEEK_CUR); } off64_t file::setPositionRelativeToEnd(off64_t offset) const { return lseek(offset,SEEK_END); } off64_t file::getCurrentPosition() const { return lseek(0,SEEK_CUR); } off64_t file::lseek(off64_t offset, int whence) const { int result; do { result=::lseek(fd(),offset,whence); } while (result==-1 && error::getErrorNumber()==EINTR); return result; } bool file::exists(const char *filename) { return accessible(filename,F_OK); } bool file::readable(const char *filename) { return accessible(filename,R_OK); } bool file::writeable(const char *filename) { return accessible(filename,W_OK); } bool file::executable(const char *filename) { return accessible(filename,X_OK); } bool file::accessible(const char *filename, int mode) { int result; do { result=access(filename,mode); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; } bool file::getCurrentProperties() { int result; do { result=fstat(fd(),&pvt->_st); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; } #define STAT(filename,out,member) \ struct stat st; \ int result; \ do { \ result=stat(filename,&st); \ } while (result==-1 && error::getErrorNumber()==EINTR); \ if (result==-1) { \ return false; \ } \ *out=st.member; \ return true; bool file::getPermissions(const char *filename, mode_t *mode) { STAT(filename,mode,st_mode) } bool file::getOwnerUserId(const char *filename, uid_t *uid) { STAT(filename,uid,st_uid) } bool file::getOwnerGroupId(const char *filename, gid_t *gid) { STAT(filename,gid,st_gid) } bool file::getSize(const char *filename, off64_t *size) { STAT(filename,size,st_size) } bool file::getBlockSize(const char *filename, blksize_t *size) { #ifdef RUDIMENTS_HAVE_BLKSIZE_T STAT(filename,size,st_blksize) #else *size=-1; return true; #endif } bool file::getBlockCount(const char *filename, blkcnt_t *blocks) { #ifdef RUDIMENTS_HAVE_BLKCNT_T STAT(filename,blocks,st_blocks) #else *blocks=-1; return true; #endif } #ifndef RUDIMENTS_HAVE_S_ISSOCK #define S_ISSOCK(m) ((m&040000==040000)?1:0) #endif int file::isSocket(const char *filename) { struct stat st; return (stat(filename,&st)>-1)?S_ISSOCK(st.st_mode):-1; } int file::isSymbolicLink(const char *filename) { struct stat st; return (stat(filename,&st)>-1)?S_ISLNK(st.st_mode):-1; } int file::isRegularFile(const char *filename) { struct stat st; return (stat(filename,&st)>-1)?S_ISREG(st.st_mode):-1; } int file::isBlockDevice(const char *filename) { struct stat st; return (stat(filename,&st)>-1)?S_ISBLK(st.st_mode):-1; } int file::isDirectory(const char *filename) { struct stat st; return (stat(filename,&st)>-1)?S_ISDIR(st.st_mode):-1; } int file::isCharacterDevice(const char *filename) { struct stat st; return (stat(filename,&st)>-1)?S_ISCHR(st.st_mode):-1; } int file::isFifo(const char *filename) { struct stat st; return (stat(filename,&st)>-1)?S_ISFIFO(st.st_mode):-1; } bool file::getLastAccessTime(const char *filename, time_t *atime) { STAT(filename,atime,st_atime) } bool file::getLastModificationTime(const char *filename, time_t *mtime) { STAT(filename,mtime,st_mtime) } bool file::getLastChangeTime(const char *filename, time_t *ctime) { STAT(filename,ctime,st_ctime) } bool file::getDevice(const char *filename, dev_t *dev) { STAT(filename,dev,st_dev) } bool file::getDeviceType(const char *filename, dev_t *devtype) { STAT(filename,devtype,st_rdev) } bool file::getInode(const char *filename, ino_t *inode) { STAT(filename,inode,st_ino) } bool file::getNumberOfHardLinks(const char *filename, nlink_t *nlink) { STAT(filename,nlink,st_nlink) } mode_t file::getPermissions() const { return pvt->_st.st_mode; } uid_t file::getOwnerUserId() const { return pvt->_st.st_uid; } gid_t file::getOwnerGroupId() const { return pvt->_st.st_gid; } off64_t file::getSize() const { return pvt->_st.st_size; } blksize_t file::getBlockSize() const { #ifdef RUDIMENTS_HAVE_BLKSIZE_T return pvt->_st.st_blksize; #else return -1; #endif } blkcnt_t file::getBlockCount() const { #ifdef RUDIMENTS_HAVE_BLKCNT_T return pvt->_st.st_blocks; #else return -1; #endif } int file::isSocket() const { return S_ISSOCK(pvt->_st.st_mode); } int file::isSymbolicLink() const { return S_ISLNK(pvt->_st.st_mode); } int file::isRegularFile() const { return S_ISREG(pvt->_st.st_mode); } int file::isBlockDevice() const { return S_ISBLK(pvt->_st.st_mode); } int file::isDirectory() const { return S_ISDIR(pvt->_st.st_mode); } int file::isCharacterDevice() const { return S_ISCHR(pvt->_st.st_mode); } int file::isFifo() const { return S_ISFIFO(pvt->_st.st_mode); } time_t file::getLastAccessTime() const { return pvt->_st.st_atime; } time_t file::getLastModificationTime() const { return pvt->_st.st_mtime; } time_t file::getLastChangeTime() const { return pvt->_st.st_ctime; } dev_t file::getDevice() const { return pvt->_st.st_dev; } dev_t file::getDeviceType() const { return pvt->_st.st_rdev; } ino_t file::getInode() const { return pvt->_st.st_ino; } nlink_t file::getNumberOfHardLinks() const { return pvt->_st.st_nlink; } void file::getCurrentPropertiesOnOpen() { pvt->_getcurrentpropertiesonopen=true; } void file::dontGetCurrentPropertiesOnOpen() { pvt->_getcurrentpropertiesonopen=false; } bool file::lock(int method, short type, short whence, off64_t start, off64_t len) const { struct flock lck; lck.l_type=type; lck.l_whence=whence; lck.l_start=start; lck.l_len=len; return !fcntl(method,reinterpret_cast(&lck)); } bool file::checkLock(short type, short whence, off64_t start, off64_t len, struct flock *retlck) const { struct flock lck; lck.l_type=type; lck.l_whence=whence; lck.l_start=start; lck.l_len=len; int result=fcntl(F_SETLKW,reinterpret_cast(&lck)); *retlck=lck; return !result; } bool file::unlock(short whence, off64_t start, off64_t len) const { struct flock lck; lck.l_type=F_UNLCK; lck.l_whence=whence; lck.l_start=start; lck.l_len=len; return !fcntl(F_SETLK,reinterpret_cast(&lck)); } bool file::changeOwner(const char *newuser, const char *newgroup) const { uid_t uid; gid_t gid; return (passwdentry::getUserId(newuser,&uid) && groupentry::getGroupId(newgroup,&gid) && changeOwner(uid,gid)); } bool file::changeOwner(uid_t uid, gid_t gid) const { int result; do { result=fchown(fd(),uid,gid); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; } bool file::changeOwner(const char *filename, const char *newuser, const char *newgroup) { uid_t uid; gid_t gid; return (passwdentry::getUserId(newuser,&uid) && groupentry::getGroupId(newgroup,&gid) && changeOwner(filename,uid,gid)); } bool file::changeOwner(const char *filename, uid_t uid, gid_t gid) { file fl; return (fl.open(filename,O_RDWR) && fl.changeOwner(uid,gid)); } bool file::changeOwnerUserId(const char *newuser) const { uid_t uid; return (passwdentry::getUserId(newuser,&uid) && changeOwnerUserId(uid)); } bool file::changeOwnerUserId(uid_t uid) const { return changeOwner(uid,(gid_t)-1); } bool file::changeOwnerUserId(const char *filename, const char *newuser) { uid_t uid; return (passwdentry::getUserId(newuser,&uid) && changeOwnerUserId(filename,uid)); } bool file::changeOwnerUserId(const char *filename, uid_t uid) { return changeOwner(filename,uid,(gid_t)-1); } bool file::changeOwnerGroupId(const char *newgroup) const { gid_t gid; return (groupentry::getGroupId(newgroup,&gid) && changeOwnerGroupId(gid)); } bool file::changeOwnerGroupId(gid_t gid) const { return changeOwner((uid_t)-1,gid); } bool file::changeOwnerGroupId(const char *filename, const char *newgroup) { gid_t gid; return (groupentry::getGroupId(newgroup,&gid) && changeOwnerGroupId(filename,gid)); } bool file::changeOwnerGroupId(const char *filename, gid_t gid) { return changeOwner(filename,(uid_t)-1,gid); } bool file::canChangeOwner(const char *filename) { return !pathConf(filename,_PC_CHOWN_RESTRICTED); } bool file::canChangeOwner() const { return !fpathConf(_PC_CHOWN_RESTRICTED); } bool file::rename(const char *oldpath, const char *newpath) { int result; do { result=::rename(oldpath,newpath); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; } bool file::remove(const char *filename) { int result; do { result=unlink(filename); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; } bool file::createHardLink(const char *oldpath, const char *newpath) { int result; do { result=link(oldpath,newpath); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; } bool file::createSymbolicLink(const char *oldpath, const char *newpath) { int result; do { result=symlink(oldpath,newpath); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; } char *file::resolveSymbolicLink(const char *filename) { size_t buffersize=1024; for (;;) { // create a buffer to store the path char *buffer=new char[buffersize]; // read the path into the buffer int len; do { len=::readlink(filename,buffer,buffersize); } while (len==-1 && error::getErrorNumber()==EINTR); if (len==-1) { // if the call to readlink failed, delete the buffer // and return NULL delete[] buffer; return NULL; } else if ((size_t)len==buffersize) { // if the length of the path was the same as the buffer // size the we didn't get the entire path, increase the // size of the buffer and try again delete[] buffer; buffersize=buffersize+1024; // if the buffer size exceeds 10k then return failure if (buffersize>10240) { return NULL; } } else { // NULL-terminate the buffer, readlink() // doesn't do this for us buffer[len]='\0'; return buffer; } } } bool file::sync() const { int result; do { result=fsync(fd()); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; } bool file::dataSync() const { #ifdef RUDIMENTS_HAVE_FDATASYNC int result; do { result=fdatasync(fd()); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; #else return sync(); #endif } bool file::setLastAccessTime(const char *filename, time_t lastaccesstime) { time_t lastmodtime; if (!getLastModificationTime(filename,&lastmodtime)) { return false; } return setLastAccessAndModificationTimes(filename, lastaccesstime, lastmodtime); } bool file::setLastModificationTime(const char *filename, time_t lastmodtime) { time_t lastaccesstime; if (!getLastAccessTime(filename,&lastaccesstime)) { return false; } return setLastAccessAndModificationTimes(filename, lastaccesstime, lastmodtime); } bool file::setLastAccessAndModificationTimes(const char *filename, time_t lastaccesstime, time_t lastmodtime) { timeval tv[2]; tv[0].tv_sec=static_cast(lastaccesstime); tv[0].tv_usec=0; tv[1].tv_sec=static_cast(lastmodtime); tv[1].tv_usec=0; int result; do { result=utimes(filename,tv); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; } bool file::setLastAccessAndModificationTimes(const char *filename) { int result; do { result=utimes(filename,NULL); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; } bool file::createFifo(const char *filename, mode_t perms) { int result; do { result=mkfifo(filename,perms); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; } int file::createTemporaryFile(char *templatefilename) { int result; do { result=mkstemp(templatefilename); } while (result==-1 && error::getErrorNumber()==EINTR); return result; } const char * const *file::listAttributes() const { #ifndef RUDIMENTS_HAVE_XATTRS return NULL; #else // The flistxattr interface is designed such that you have to guess the // size of the buffer that it will need, call flistxattr, then see if // your guess was correct. If not, you have to try again. // try with a 8 byte buffer to start size_t size=8; char *buffer; // try 100 times... for (int i=0; i<100; i++) { // allocate a buffer buffer=new char[size]; // attempt to read the attribute into the buffer ssize_t newsize; do { newsize=flistxattr(fd(),buffer,size); } while (newsize==-1 && error::getErrorNumber()==EINTR); // it's possible that someone changed the attribute between // the previous 2 calls to fgetxattr and increased the size // of the buffer necessary to retrieve it, if so, try again // with a bigger buffer. if (newsize==-1) { delete[] buffer; return NULL; } else if (newsize>(ssize_t)size) { delete[] buffer; size=newsize; } else { const char * const *retval= attributeArray(buffer,size); delete[] buffer; return retval; } } // if we couldn't get the attribute after 100 tries, give up return NULL; #endif } bool file::getAttribute(const char *name, unsigned short *number) const { size_t size; unsigned char *buffer; bool retval=getAttribute(name, reinterpret_cast(&buffer), &size); if (retval) { rawbuffer::copy(number,buffer,sizeof(unsigned short)); delete[] buffer; } return retval; } bool file::getAttribute(const char *name, unsigned long *number) const { size_t size; unsigned char *buffer; bool retval=getAttribute(name, reinterpret_cast(&buffer), &size); if (retval) { rawbuffer::copy(number,buffer,sizeof(unsigned long)); delete[] buffer; } return retval; } bool file::getAttribute(const char *name, short *number) const { size_t size; unsigned char *buffer; bool retval=getAttribute(name, reinterpret_cast(&buffer), &size); if (retval) { rawbuffer::copy(number,buffer,sizeof(short)); delete[] buffer; } return retval; } bool file::getAttribute(const char *name, long *number) const { size_t size; unsigned char *buffer; bool retval=getAttribute(name, reinterpret_cast(&buffer), &size); if (retval) { rawbuffer::copy(number,buffer,sizeof(long)); delete[] buffer; } return retval; } bool file::getAttribute(const char *name, float *number) const { size_t size; unsigned char *buffer; bool retval=getAttribute(name, reinterpret_cast(&buffer), &size); if (retval) { rawbuffer::copy(number,buffer,sizeof(float)); delete[] buffer; } return retval; } bool file::getAttribute(const char *name, double *number) const { size_t size; unsigned char *buffer; bool retval=getAttribute(name, reinterpret_cast(&buffer), &size); if (retval) { rawbuffer::copy(number,buffer,sizeof(double)); delete[] buffer; } return retval; } bool file::getAttribute(const char *name, unsigned char *character) const { size_t size; unsigned char *buffer; bool retval=getAttribute(name, reinterpret_cast(&buffer), &size); if (retval) { rawbuffer::copy(character,buffer,sizeof(unsigned char)); delete[] buffer; } return retval; } bool file::getAttribute(const char *name, char *character) const { size_t size; unsigned char *buffer; bool retval=getAttribute(name, reinterpret_cast(&buffer), &size); if (retval) { rawbuffer::copy(character,buffer,sizeof(char)); delete[] buffer; } return retval; } bool file::getAttribute(const char *name, bool *value) const { size_t size; unsigned char *buffer; bool retval=getAttribute(name, reinterpret_cast(&buffer), &size); if (retval) { rawbuffer::copy(value,buffer,sizeof(bool)); delete[] buffer; } return retval; } bool file::getAttribute(const char *name, unsigned char **string) const { size_t size; return getAttribute(name,reinterpret_cast(string),&size); } bool file::getAttribute(const char *name, char **string) const { size_t size; return getAttribute(name,reinterpret_cast(string),&size); } bool file::getAttribute(const char *name, unsigned char **string, size_t *size) const { return getAttribute(name,reinterpret_cast(string),size); } bool file::getAttribute(const char *name, char **string, size_t *size) const { return getAttribute(name,reinterpret_cast(string),size); } bool file::getAttribute(const char *name, void **buffer, size_t *size) const { #ifndef RUDIMENTS_HAVE_XATTRS *buffer=NULL; *size=0; return false; #else // The fgetxattr interface is designed such that you have to guess the // size of the buffer that it will need, call fgetxattr, then see if // your guess was correct. If not, you have to try again. // try with a 8 byte buffer to start (*size)=8; // try 100 times... for (int i=0; i<100; i++) { // allocate a buffer (*buffer)=static_cast(new unsigned char[(*size)]); // attempt to read the attribute into the buffer ssize_t newsize; do { newsize=fgetxattr(fd(),name,(*buffer),(*size)); } while (newsize==-1 && error::getErrorNumber()==EINTR); // it's possible that someone changed the attribute between // the previous 2 calls to fgetxattr and increased the size // of the buffer necessary to retrieve it, if so, try again // with a bigger buffer. if (newsize==-1) { delete[] static_cast(*buffer); return false; } else if (newsize>(ssize_t)(*size)) { delete[] static_cast(*buffer); (*size)=newsize; } else { return true; } } // if we couldn't get the attribute after 100 tries, give up return false; #endif } bool file::createAttribute(const char *name, unsigned short number) const { return createAttribute(name,&number,sizeof(number)); } bool file::createAttribute(const char *name, unsigned long number) const { return createAttribute(name,&number,sizeof(number)); } bool file::createAttribute(const char *name, short number) const { return createAttribute(name,&number,sizeof(number)); } bool file::createAttribute(const char *name, long number) const { return createAttribute(name,&number,sizeof(number)); } bool file::createAttribute(const char *name, float number) const { return createAttribute(name,&number,sizeof(number)); } bool file::createAttribute(const char *name, double number) const { return createAttribute(name,&number,sizeof(number)); } bool file::createAttribute(const char *name, unsigned char character) const { return createAttribute(name,&character,sizeof(character)); } bool file::createAttribute(const char *name, char character) const { return createAttribute(name,&character,sizeof(character)); } bool file::createAttribute(const char *name, bool value) const { return createAttribute(name,&value,sizeof(value)); } bool file::createAttribute(const char *name, const unsigned char *string) const { return createAttribute(name,string,charstring::length(string)); } bool file::createAttribute(const char *name, const char *string) const { return createAttribute(name,string,charstring::length(string)); } bool file::createAttribute(const char *name, const unsigned char *string, size_t size) const { return createAttribute(name,static_cast(string),size); } bool file::createAttribute(const char *name, const char *string, size_t size) const { return createAttribute(name,static_cast(string),size); } #ifndef XATTR_CREATE #define XATTR_CREATE 0 #endif bool file::createAttribute(const char *name, const void *value, size_t size) const { return setAttribute(name,value,size,XATTR_CREATE); } bool file::replaceAttribute(const char *name, unsigned short number) const { return replaceAttribute(name,&number,sizeof(number)); } bool file::replaceAttribute(const char *name, unsigned long number) const { return replaceAttribute(name,&number,sizeof(number)); } bool file::replaceAttribute(const char *name, short number) const { return replaceAttribute(name,&number,sizeof(number)); } bool file::replaceAttribute(const char *name, long number) const { return replaceAttribute(name,&number,sizeof(number)); } bool file::replaceAttribute(const char *name, float number) const { return replaceAttribute(name,&number,sizeof(number)); } bool file::replaceAttribute(const char *name, double number) const { return replaceAttribute(name,&number,sizeof(number)); } bool file::replaceAttribute(const char *name, unsigned char character) const { return replaceAttribute(name,&character,sizeof(character)); } bool file::replaceAttribute(const char *name, char character) const { return replaceAttribute(name,&character,sizeof(character)); } bool file::replaceAttribute(const char *name, bool value) const { return replaceAttribute(name,&value,sizeof(value)); } bool file::replaceAttribute(const char *name, const unsigned char *string) const { return replaceAttribute(name,string,charstring::length(string)); } bool file::replaceAttribute(const char *name, const char *string) const { return replaceAttribute(name,string,charstring::length(string)); } bool file::replaceAttribute(const char *name, const unsigned char *string, size_t size) const { return replaceAttribute(name,static_cast(string),size); } bool file::replaceAttribute(const char *name, const char *string, size_t size) const { return replaceAttribute(name,static_cast(string),size); } #ifndef XATTR_REPLACE #define XATTR_REPLACE 0 #endif bool file::replaceAttribute(const char *name, const void *value, size_t size) const { return setAttribute(name,value,size,XATTR_REPLACE); } bool file::setAttribute(const char *name, unsigned short number) const { return setAttribute(name,&number,sizeof(number)); } bool file::setAttribute(const char *name, unsigned long number) const { return setAttribute(name,&number,sizeof(number)); } bool file::setAttribute(const char *name, short number) const { return setAttribute(name,&number,sizeof(number)); } bool file::setAttribute(const char *name, long number) const { return setAttribute(name,&number,sizeof(number)); } bool file::setAttribute(const char *name, float number) const { return setAttribute(name,&number,sizeof(number)); } bool file::setAttribute(const char *name, double number) const { return setAttribute(name,&number,sizeof(number)); } bool file::setAttribute(const char *name, unsigned char character) const { return setAttribute(name,&character,sizeof(character)); } bool file::setAttribute(const char *name, char character) const { return setAttribute(name,&character,sizeof(character)); } bool file::setAttribute(const char *name, bool value) const { return setAttribute(name,&value,sizeof(value)); } bool file::setAttribute(const char *name, const unsigned char *string) const { return setAttribute(name,string,charstring::length(string)); } bool file::setAttribute(const char *name, const char *string) const { return setAttribute(name,string,charstring::length(string)); } bool file::setAttribute(const char *name, const unsigned char *string, size_t size) const { return setAttribute(name,static_cast(string),size); } bool file::setAttribute(const char *name, const char *string, size_t size) const { return setAttribute(name,static_cast(string),size); } bool file::setAttribute(const char *name, const void *value, size_t size) const { return setAttribute(name,value,size,0); } bool file::setAttribute(const char *name, const void *value, size_t size, int flags) const { #ifndef RUDIMENTS_HAVE_XATTRS return false; #else ssize_t result; do { result=fsetxattr(fd(),name,value,size,flags); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; #endif } bool file::removeAttribute(const char *name) const { #ifndef RUDIMENTS_HAVE_XATTRS return false; #else ssize_t result; do { result=fremovexattr(fd(),name); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; #endif } const char * const *file::attributeArray(const char *buffer, size_t size) const { #ifndef RUDIMENTS_HAVE_XATTRS return NULL; #else // count the number of attributes int counter=0; for (size_t index=0; index_st); } char *file::dirname(const char *filename) { if (!filename) { return NULL; } else if (!charstring::contains(filename,'/') || !charstring::compare(filename,".")) { return charstring::duplicate("."); } else if (!charstring::compare(filename,"..")) { return charstring::duplicate(".."); } else if (!charstring::compare(filename,"/")) { return charstring::duplicate("/"); } char *retval=charstring::duplicate(filename); charstring::rightTrim(retval,'/'); char *lastslash=charstring::findLast(retval,'/'); if (lastslash==retval) { (*(lastslash+1))='\0'; } else { (*lastslash)='\0'; } return retval; } char *file::basename(const char *filename) { if (!filename) { return NULL; } char *copy=charstring::duplicate(filename); charstring::rightTrim(copy,'/'); char *retval; char *ptr=charstring::findLast(copy,'/'); if (!ptr) { retval=charstring::duplicate(copy); } else { retval=charstring::duplicate(ptr+1); } delete[] copy; return retval; } char *file::basename(const char *filename, const char *suffix) { char *retval=basename(filename); char *ptr=charstring::findLast(retval,suffix); if (!(*(ptr+charstring::length(suffix)))) { (*ptr)='\0'; } return retval; } key_t file::generateKey(const char *filename, int id) { #ifdef RUDIMENTS_HAVE_FTOK #ifdef RUDIMENTS_HAVE_CONST_CHAR_FTOK return ::ftok(filename,id); #else return ::ftok(const_cast(filename),id); #endif #else file f; if (!f.open(filename,O_RDONLY)) { return -1; } return (key_t)((f.getInode() & 0xffff) | ((f.getDevice() & 0xff) << 16) | ((id & 0xff) << 24)); #endif } long file::maxLinks(const char *filename) { return pathConf(filename,_PC_LINK_MAX); } long file::maxLinks() const { return fpathConf(_PC_LINK_MAX); } bool file::posixFadvise(off64_t offset, off64_t len, int advice) const { #ifdef RUDIMENTS_HAVE_POSIX_FADVISE int result; do { result=posix_fadvise(fd(),offset,len,advice); } while (result==-1 && error::getErrorNumber()==EINTR); return !result; #else return true; #endif } long file::pathConf(const char *path, int name) { long result; do { result=pathconf(path,name); } while (result==-1 && error::getErrorNumber()==EINTR); return result; } long file::fpathConf(int name) const { long result; do { result=fpathconf(fd(),name); } while (result==-1 && error::getErrorNumber()==EINTR); return result; } #ifdef RUDIMENTS_NAMESPACE } #endif