/* datei.cc * This file belongs to Worker, a filemanager for UNIX/X11. * Copyright (C) 2001-2004 Ralf Hoffmann. * You can contact me at: ralf@boomerangsworld.de * or http://www.boomerangsworld.de/worker * * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* $Id: datei.cc,v 1.102 2004/12/16 19:12:36 ralf Exp $ */ #include "datei.h" #include #include "wconfig.h" #include "grouphash.h" #include "worker_locale.h" #include "wdefines.h" #include "pdatei.h" #include "worker.h" #include "nmrowdata.h" #include "condparser.h" #include "stringbuf.h" #include #ifndef MAXPATHLEN #define MAXPATHLEN 2048 #endif int datelen=-1; Datei::Datei() { fp=NULL; error=0; } Datei::~Datei() { if(fp!=NULL) close(); } int Datei::open( const char *name, const char *mode ) { fp = worker_fopen( name, mode ); if(fp==NULL) return 1; return 0; } void Datei::close() { if(fp==NULL) return; worker_fclose( fp ); fp=NULL; } int Datei::putUChar(unsigned char value) { if(fp==NULL) return -1; int x; x=fputc(value,fp); if(x!=EOF) return 1; printf("fehler bei FPutChar\n"); return 0; } int Datei::putUShort(unsigned short int value) { if(fp==NULL) return -1; int x; x=fputc(value>>8,fp); if(x==EOF) return 0; x=fputc(value&0xff,fp); if(x==EOF) return 1; return 2; } int Datei::putInt(int value) { if(fp==NULL) return -1; int x,tv; if(value<0) { x=fputc(1,fp); if(x==EOF) return 0; } else { x=fputc(0,fp); if(x==EOF) return 0; } tv=abs(value); int i; for(i=0;i<4;i++) { x=fputc(tv&0xff,fp); if(x==EOF) return i+1; tv>>=8; } return i+1; } int Datei::getInt() { if(fp==NULL) return -1; int vz,x,value; vz=fgetc(fp); if(vz<0) { error++; return 0; } value=0; for(int i=0;i<4;i++) { x=fgetc(fp); if(x==EOF) { error++; return 0; } value+=(x<<(8*i)); } if(vz==1) value*=-1; return value; } int Datei::putULong(unsigned long value) { if(fp==NULL) return -1; int x; x=fputc((value&0xff000000)>>24,fp); if(x==EOF) return 0; x=fputc((value&0xff0000)>>16,fp); if(x==EOF) return 1; x=fputc((value&0xff00)>>8,fp); if(x==EOF) return 2; x=fputc(value&0xff,fp); if(x==EOF) return 3; return 4; } int Datei::putString( const char *str1 ) { if(fp==NULL) return -1; int x; x=fputs(str1,fp); if(x==EOF) return -2; return strlen(str1); } unsigned char Datei::getUChar() { if(fp==NULL) { error++; return 0; } int x; x=fgetc(fp); if(x==EOF) { error++; return 0; } return (unsigned char) x; } int Datei::getCharAsInt() { if(fp==NULL) { error++; return 0; } return fgetc(fp); } unsigned short Datei::getUShort() { if(fp==NULL) { error++; return 0; } int x; unsigned short int a; x=fgetc(fp); if(x==EOF) { error++; return 0; } a=((unsigned int)x)*0x100; x=fgetc(fp); if(x==EOF) { error++; return 1; } a+=(unsigned int)x; return a; } unsigned long Datei::getULong() { if(fp==NULL) { error++; return 0; } int x; unsigned long a; x=fgetc(fp); if(x==EOF) { error++; return 0; } a=((unsigned int)x)*0x1000000; x=fgetc(fp); if(x==EOF) { error++; return 1; } a+=((unsigned int)x)*0x10000; x=fgetc(fp); if(x==EOF) { error++; return 2; } a+=((unsigned int)x)*0x100; x=fgetc(fp); if(x==EOF) { error++; return 3; } a+=(unsigned int)x; return a; } char *Datei::getString(int count) { if(fp==NULL) return NULL; unsigned char *tstr,*tstr2; int ch; long x; long size; if(count==-1) { /* lesen bis NULL-Byte */ size=1024; tstr=(unsigned char*)_allocsafe(size); x=0; do { ch=fgetc(fp); if(ch!=EOF) { tstr[x++]=(unsigned char)ch; } else { tstr[x++]=0; break; } if(x==size) { size*=2; tstr2=(unsigned char*)_allocsafe(size); if(tstr2==NULL) break; strcpy((char*)tstr2,(char*)tstr); _freesafe(tstr); tstr=tstr2; } } while(ch!=0); } else { tstr=(unsigned char*)_allocsafe(count+1); if(tstr!=NULL) { for(x=0;xd_name,".")!=0) { fe1=new FileEntry(); if(strcmp(namelist->d_name,"..")==0) { // this is because of problems with NTFS havepointpoint=ldnr; fpp=fe1; } fe1->name=dupstring(namelist->d_name); x=strlen(fe1->name); tstr=(char*)_allocsafe(strlen(dirstr)+1+x+1); strcpy(tstr,dirstr); if(strlen(dirstr)>1) strcat(tstr,"/"); strcat(tstr,namelist->d_name); fe1->fullname=tstr; fe1->nr=ldnr++; if(fe1->readInfos()==0) { if(fe1->name[0]=='.') fe1->isHidden=true; else fe1->isHidden=false; files->addElement(fe1); } else { ldnr--; myerror = strerror( errno ); if ( ( Worker::getRequester() != NULL ) && ( dontWarnInvalid == false ) ) { tstr2 = (char*)_allocsafe( strlen( catalog.getLocale( 531 ) ) + strlen( fe1->fullname ) + strlen( myerror ) + 1 ); sprintf( tstr2, catalog.getLocale( 531 ), fe1->fullname, myerror ); str1 = catalog.getLocale( 11 ); str1 += "|"; str1 += catalog.getLocale( 8 ); erg = Worker::getRequester()->request( catalog.getLocale( 347 ), tstr2, str1.c_str() ); _freesafe( tstr2 ); if ( erg == 1 ) { user_abort = true; } } if ( strcmp( namelist->d_name, ".." ) == 0 ) { // we need a .. entry so reset flag havepointpoint = -1; fpp = NULL; delete fe1; } else { invalid_entries->addElement(fe1); } } } if ( user_abort == true ) break; } closedir(dir); if ( user_abort == false ) { if(havepointpoint==-1) { // there is no parent-dir-entry // create one // first raise the nr of all FEs id=files->initEnum(); fe1=(FileEntry*)files->getFirstElement(id); while(fe1!=NULL) { fe1->nr++; fe1=(FileEntry*)files->getNextElement(id); } files->closeEnum(id); fe1=new FileEntry(); fe1->name=dupstring(".."); x=strlen(fe1->name); tstr=(char*)_allocsafe(strlen(dirstr)+1+x+1); strcpy(tstr,dirstr); if(strlen(dirstr)>1) strcat(tstr,"/"); strcat(tstr,fe1->name); fe1->fullname=tstr; fe1->nr=0; // try to get some infos about .. // it's very likely that this works even when the dir have no .. if ( fe1->readInfos() != 0 ) { // failed, use some default values //TODO: Besonders toll gefällt mir das nicht // Füge ich in FileEntry ein Feld hinzu, muss ich dies u.U. auch hier // init. // Besser wäre, wenn ich statbuf direkt in Klasse aufnehme und // ich dann einfach ein memset machen kann memset( &( fe1->statbuf ), 0, sizeof ( fe1->statbuf ) ); memset( &( fe1->dstatbuf ), 0, sizeof ( fe1->dstatbuf ) ); fe1->statbuf.mode = S_IFDIR | S_IRUSR | S_IWUSR | S_IXUSR; fe1->statbuf.userid = (uid_t)-1; fe1->statbuf.groupid = (gid_t)-1; fe1->isCorrupt = false; fe1->isLink = false; } if(fe1->name[0]=='.') fe1->isHidden=true; else fe1->isHidden=false; files->addElementAt(0,fe1); } else if(havepointpoint>0) { if(fpp!=NULL) { id=files->initEnum(); fe1=(FileEntry*)files->getFirstElement(id); while((fe1!=NULL)&&(fe1!=fpp)) { fe1->nr++; fe1 = (FileEntry*)files->getNextElement( id ); } havepointpoint=files->getIndex(fpp); files->removeElementAt(havepointpoint); files->addElementAt(0,fpp); fpp->nr=0; files->closeEnum(id); } } actdir=dupstring(dirstr); } } else { // requester: can't read directory myerror = strerror( errno ); tstr2 = (char*)_allocsafe( strlen( catalog.getLocale( 532 ) ) + strlen( dirstr ) + strlen( myerror ) + 1 ); sprintf( tstr2, catalog.getLocale( 532 ), dirstr, myerror ); str1 = catalog.getLocale( 11 ); Worker::getRequester()->request( catalog.getLocale( 347 ), tstr2, str1.c_str() ); _freesafe( tstr2 ); returnvalue = -1; delete files; files=NULL; delete invalid_entries; invalid_entries=NULL; } if ( user_abort == true ) { id=files->initEnum(); fe1=(FileEntry*)files->getFirstElement(id); while(fe1!=NULL) { delete fe1; fe1=(FileEntry*)files->getNextElement(id); } files->closeEnum(id); id=invalid_entries->initEnum(); fe1=(FileEntry*)invalid_entries->getFirstElement(id); while(fe1!=NULL) { delete fe1; fe1=(FileEntry*)invalid_entries->getNextElement(id); } invalid_entries->closeEnum(id); returnvalue=1; delete files; files=NULL; delete invalid_entries; invalid_entries=NULL; } return returnvalue; } int Verzeichnis::sortfunction(void *p1,void *p2,int mode) { FileEntry *fe1,*fe2; int comp=0; fe1=(FileEntry*)p1; fe2=(FileEntry*)p2; loff_t s1,s2; int dirm=mode&0x600; WCFiletype *ft1, *ft2; /* if(strcmp(fe1->name,"..")==0) return true; // Sonderfall if(strcmp(fe2->name,"..")==0) return false;*/ if((strcmp(fe1->name,"..")==0)&&(strcmp(fe2->name,"..")==0)) return 0; else if(strcmp(fe1->name,"..")==0) return -1; else if(strcmp(fe2->name,"..")==0) return 1; switch(mode&0xff) { case SORT_NAME: comp=strcmp(fe1->name,fe2->name); break; case SORT_SIZE: s1=-1; s2=-1; if ( S_ISCHR( fe1->mode() ) || S_ISBLK( fe1->mode() ) ) { s1 = (loff_t)fe1->rdev(); } else { if ( fe1->isDir() == true) s1 = fe1->dirsize; if ( s1 < 0 ) s1 = fe1->size(); } if ( S_ISCHR( fe2->mode() ) || S_ISBLK( fe2->mode() ) ) { s2 = (loff_t)fe2->rdev(); } else { if ( fe2->isDir() == true ) s2 = fe2->dirsize; if ( s2 < 0 ) s2 = fe2->size(); } if(s1s2) comp=1; else comp=strcmp(fe1->name,fe2->name); break; case SORT_ACCTIME: if ( fe1->lastaccess() < fe2->lastaccess() ) comp = -1; else if ( fe1->lastaccess() > fe2->lastaccess() ) comp = 1; else comp=strcmp(fe1->name,fe2->name); break; case SORT_MODTIME: if ( fe1->lastmod() < fe2->lastmod() ) comp = -1; else if ( fe1->lastmod() > fe2->lastmod() ) comp = 1; else comp=strcmp(fe1->name,fe2->name); break; case SORT_CHGTIME: if ( fe1->lastchange() < fe2->lastchange() ) comp = -1; else if ( fe1->lastchange() > fe2->lastchange() ) comp = 1; else comp=strcmp(fe1->name,fe2->name); break; case SORT_TYPE: if ( fe1->filetype != NULL ) { ft1 = fe1->filetype; } else { if(fe1->isDir()==true) { ft1 = wconfig->getdirtype(); } else { ft1 = wconfig->getnotyettype(); } } if ( fe2->filetype != NULL ) { ft2 = fe2->filetype; } else { if(fe2->isDir()==true) { ft2 = wconfig->getdirtype(); } else { ft2 = wconfig->getnotyettype(); } } comp = strcmp( ft1->getName(), ft2->getName() ); if ( comp == 0 ) comp = strcmp( fe1->name, fe2->name ); break; case SORT_OWNER: // first cmp usernames // if equal cmp groupnames // if equal cmp names // getUserNameS only look for existing entry in hashtable and returns // static pointer // so it's fast //TODO: perhaps it makes more sense to first compare groups comp = strcmp( ugdb->getUserNameS( fe1->userid() ), ugdb->getUserNameS( fe2->userid() ) ); if ( comp == 0 ) { comp = strcmp( ugdb->getGroupNameS( fe1->groupid() ), ugdb->getGroupNameS( fe2->groupid() ) ); if ( comp == 0 ) comp = strcmp( fe1->name, fe2->name ); } break; case SORT_INODE: if ( (loff_t)fe1->inode() < (loff_t)fe2->inode() ) comp = -1; else if ( (loff_t)fe1->inode() > (loff_t)fe2->inode() ) comp = 1; else comp = strcmp( fe1->name, fe2->name ); break; case SORT_NLINK: if ( (loff_t)fe1->nlink() < (loff_t)fe2->nlink() ) comp = -1; else if ( (loff_t)fe1->nlink() > (loff_t)fe2->nlink() ) comp = 1; else comp = strcmp( fe1->name, fe2->name ); break; } if((mode&SORT_REVERSE)==SORT_REVERSE) comp*=-1; if(dirm!=SORT_DIRMIXED) { if(fe1->isDir()==true) { if(fe2->isDir()==false) comp=(dirm==SORT_DIRLAST)?1:-1; } else { if(fe2->isDir()==true) comp=(dirm==SORT_DIRLAST)?-1:1; } } return comp; } void Verzeichnis::closeDir() { if(files!=NULL) { FileEntry *fe=(FileEntry*)files->getFirstElement(); while(fe!=NULL) { delete fe; fe=(FileEntry*)files->getNextElement(); } delete files; files=NULL; _freesafe(actdir); actdir=NULL; actsortmode=-1; } if(invalid_entries!=NULL) { FileEntry *fe=(FileEntry*)invalid_entries->getFirstElement(); while(fe!=NULL) { delete fe; fe=(FileEntry*)invalid_entries->getNextElement(); } delete invalid_entries; invalid_entries=NULL; } } int Verzeichnis::getSize() { if(files!=NULL) return files->size(); else return -1; } char *Verzeichnis::getDir() { return actdir; } char *ParentDir(const char *pathstr,char *dirnamereturn) { char *newpath; int x,y; x=strlen(pathstr); if(x<2) { newpath=(char*)_allocsafe(2); strcpy(newpath,"/"); if(dirnamereturn!=NULL) strcpy(dirnamereturn,""); } else { if(pathstr[x-1]=='/') y=x-2; else y=x-1; while((pathstr[y]!='/')&&(y>0)) { y--; } if(y==0) { newpath=(char*)_allocsafe(2); strcpy(newpath,"/"); if(dirnamereturn!=NULL) strcpy(dirnamereturn,pathstr+1); } else { newpath=(char*)_allocsafe(y+1); strncpy(newpath,pathstr,y); if(dirnamereturn!=NULL) strcpy(dirnamereturn,pathstr+y+1); newpath[y]=0; } } return newpath; } char *HandlePath(const char *pathstr) { char *newpath, *newpath2, *buffer; int x,y,parentlevel; int start,end; int found,ende; buffer = (char*)_allocsafe( strlen( pathstr ) + 1 ); x=strlen(pathstr); y=0; found=0; parentlevel=0; ende=0; newpath=(char*)_allocsafe(1); newpath[0]=0; do { start=y; while((pathstr[y]!='/')&&((y+1)=x)&&(pathstr[y]!='/')) end=y+1; else end=y; if(end>start) { strncpy(buffer,pathstr+start,end-start); buffer[end-start]=0; if(strcmp(buffer,".")==0) { y++; } else if(strcmp(buffer,"..")==0) { y++; newpath2=ParentDir(newpath,NULL); _freesafe(newpath); newpath=newpath2; } else { newpath2=(char*)_allocsafe(strlen(newpath)+1+strlen(buffer)+1); strcpy(newpath2,newpath); if(strlen(newpath)>0) { if(newpath[strlen(newpath)-1]!='/') strcat(newpath2,"/"); } strcat(newpath2,buffer); _freesafe(newpath); newpath=newpath2; y++; } } else { if(start==0) { newpath2=(char*)_allocsafe(2); strcpy(newpath2,"/"); _freesafe(newpath); newpath=newpath2; } y++; } if(y>=x) ende=1; } while(ende==0); _freesafe( buffer ); return newpath; } int Verzeichnis::sort(int mode) { return sort(mode,false); } int Verzeichnis::sort(int mode,bool force) { if((mode!=actsortmode)||(force==true)) { files->sort(sortfunction,mode); // FEs erhalten Nummer anhand der Position, damit von LVC auf FE geschlossen werden kann int id=files->initEnum(),pos; FileEntry *fe=(FileEntry*)files->getFirstElement(id); pos=0; while(fe!=NULL) { fe->nr=pos++; fe=(FileEntry*)files->getNextElement(id); } files->closeEnum(id); actsortmode=mode; } return 0; } bool FileEntry::isDir() const { bool dir=false; if ( isLink == true ) { if ( isCorrupt == false ) { if ( S_ISDIR( dstatbuf.mode ) ) dir = true; } } else if ( S_ISDIR( statbuf.mode ) ) dir = true; return dir; } FileEntry *FileEntry::duplicate() { #if 0 FileEntry *tfe=new FileEntry(); tfe->fullname=dupstring(fullname); tfe->name=dupstring(name); tfe->dirsize=dirsize; tfe->select=select; tfe->isLink=isLink; tfe->isCorrupt=isCorrupt; tfe->nr=nr; tfe->inFilter=inFilter; tfe->filetype=filetype; memcpy( &( tfe->statbuf ), &statbuf, sizeof( statbuf ) ); memcpy( &( tfe->dstatbuf ), &dstatbuf, sizeof( dstatbuf ) ); tfe->setCustomColors( customcolors ); tfe->setColor( 0, fg ); tfe->setColor( 1, bg ); return tfe; #endif return new FileEntry( *this ); } bool Datei::fileExists(const char *name) { worker_struct_stat stbuf; if ( worker_lstat( name, &stbuf ) != 0 ) return false; else { /* kann auch verzeichnis sein */ // if(S_ISDIR(stbuf.st_mode)) return false; } return true; } Datei::d_fe_t Datei::fileExistsExt(const char*name) { worker_struct_stat stbuf; d_fe_t return_value; if ( worker_stat( name, &stbuf ) != 0 ) return_value = D_FE_NOFILE; else { if(S_ISDIR(stbuf.st_mode)) return_value=D_FE_DIR; else return_value=D_FE_FILE; if(S_ISLNK(stbuf.st_mode)) return_value=D_FE_LINK; } return return_value; } Datei::d_fe_t Datei::lfileExistsExt(const char*name) { worker_struct_stat stbuf; d_fe_t return_value; if ( worker_lstat( name, &stbuf ) != 0 ) return_value = D_FE_NOFILE; else { if(S_ISDIR(stbuf.st_mode)) return_value=D_FE_DIR; else return_value=D_FE_FILE; if(S_ISLNK(stbuf.st_mode)) return_value=D_FE_LINK; } return return_value; } void Datei::seek(long offset,int mode) { if ( fp != NULL ) worker_fseek( fp, offset, mode ); } int getOwnerStringLen(uid_t user,gid_t gr) { char *tstr; #ifdef DEBUG // printf("entering getOwnerStringLen\n"); #endif int len=0; int ost=wconfig->getOwnerstringtype(); #ifdef DEBUG // printf(" getUserNameS\n"); #endif tstr=ugdb->getUserNameS(user); if(tstr!=NULL) len+=strlen(tstr); len+=(ost==1)?1:3; #ifdef DEBUG // printf(" getGroupNameS\n"); #endif tstr=ugdb->getGroupNameS(gr); if(tstr!=NULL) len+=strlen(tstr); #ifdef DEBUG // printf("leaving getOwnerStringLen\n"); #endif return len; } char* getOwnerString(uid_t user,gid_t mygroup) { int len=0; char *tstr1,*tstr2; int ost=wconfig->getOwnerstringtype(); tstr1=ugdb->getUserNameS(user); tstr2=ugdb->getGroupNameS(mygroup); if(tstr1!=NULL) len+=strlen(tstr1); len+=(ost==1)?1:3; if(tstr2!=NULL) len+=strlen(tstr2); char *str=(char*)_allocsafe((len+2)*sizeof(char)); str[0]=0; if(tstr1!=NULL) strcat(str,tstr1); strcat(str,(ost==1)?".":" @ "); if(tstr2!=NULL) strcat(str,tstr2); return str; } int FileEntry::readInfos() { return readInfos(false); } int FileEntry::readInfos(bool update) { //TODO: auf update achten worker_struct_stat stbuf; select=false; dirsize=-1; filetype=NULL; inFilter=true; if(fullname==NULL) return 1; memset( &statbuf, 0, sizeof( statbuf ) ); memset( &dstatbuf, 0, sizeof( dstatbuf ) ); if ( worker_lstat( fullname, &stbuf ) == 0 ) { statbuf.size = stbuf.st_size; statbuf.lastaccess = stbuf.st_atime; statbuf.lastmod = stbuf.st_mtime; statbuf.lastchange = stbuf.st_ctime; statbuf.mode = stbuf.st_mode; statbuf.userid = stbuf.st_uid; statbuf.groupid = stbuf.st_gid; statbuf.inode = stbuf.st_ino; statbuf.nlink = stbuf.st_nlink; statbuf.blocks = stbuf.st_blocks; statbuf.rdev = stbuf.st_rdev; statbuf.dev = stbuf.st_dev; } else return 2; isCorrupt=false; if ( S_ISLNK( statbuf.mode ) ) { isLink=true; if ( worker_stat( fullname, &stbuf ) == 0 ) { dstatbuf.size = stbuf.st_size; dstatbuf.lastaccess = stbuf.st_atime; dstatbuf.lastmod = stbuf.st_mtime; dstatbuf.lastchange = stbuf.st_ctime; dstatbuf.mode = stbuf.st_mode; dstatbuf.userid = stbuf.st_uid; dstatbuf.groupid = stbuf.st_gid; dstatbuf.inode = stbuf.st_ino; dstatbuf.nlink = stbuf.st_nlink; dstatbuf.blocks = stbuf.st_blocks; dstatbuf.rdev = stbuf.st_rdev; dstatbuf.dev = stbuf.st_dev; } else { /* korrupt */ isCorrupt=true; dstatbuf.mode = 0; // to prevent corrupt links treated as dirs if(errno==ENOENT) { // Eventl. fuer spaetere Betrachtungen } } } else { isLink=false; } return 0; } char *FileEntry::getDestination() const { char *str=NULL,*tstr; if((isLink==true)&&(fullname!=NULL)) { tstr=(char*)_allocsafe((MAXPATHLEN+1)*sizeof(char)); int x=readlink(fullname,tstr,MAXPATHLEN); if(x>=0) { tstr[x]=0; str=dupstring(tstr); } _freesafe(tstr); } return str; } int FileEntry::writeDestination2Buf(char *buf,int size2,bool terminated) { int x=-1; if((isLink==true)&&(fullname!=NULL)) { x=readlink(fullname,buf,size2); if((terminated==true)&&(x>=0)) { buf[x]=0; } } return x; } extern double d1,d2,d3; void FileEntry::setLVC( FieldListView *lv, int row, const std::vector *dis ) { int mlen=0; char *str=NULL; struct tm *timeptr; loff_t dissize, li; bool sfds=false; std::string s1; int ost, x; char nbuf[ A_BYTESFORNUMBER( loff_t ) ]; if ( ( lv == NULL ) || ( dis == NULL ) ) return; for ( int i = 0; i < (int)dis->size(); i++ ) { switch( (*dis)[i]) { case WorkerTypes::LISTCOL_NAME: s1 = ""; if ( isLink == true ) { if ( isCorrupt == true ) s1 += '!'; else { if ( S_ISDIR( dstatbuf.mode ) ) s1 += '~'; else s1 += '@'; } } else { if ( S_ISDIR( statbuf.mode ) ) s1 += '/'; else if ( S_ISFIFO( statbuf.mode ) ) s1 += '|'; else if ( S_ISSOCK( statbuf.mode ) ) s1 += '='; else if ( S_ISCHR( statbuf.mode ) ) s1 += '-'; else if ( S_ISBLK( statbuf.mode ) ) s1 += '+'; else if ( isExe() == true ) s1 += '*'; else s1 += ' '; } s1 += name; lv->setText( row, 2 * i, s1 ); break; case WorkerTypes::LISTCOL_SIZE: if ( S_ISCHR( statbuf.mode ) || S_ISBLK( statbuf.mode ) ) { x = (int)statbuf.rdev; snprintf( nbuf, sizeof( nbuf ), "%d", x >> 8 ); s1 = nbuf; s1 += ", "; snprintf( nbuf, sizeof( nbuf ), "%3d", x & 0xff ); s1 += nbuf; lv->setText( row, 2 * i, s1 ); } else { if ( ( isDir() == true ) && ( isLink == false ) && ( dirsize >= 0 ) ) dissize = dirsize; else dissize = statbuf.size; if ( isDir() == true ) { if ( ! ( ( isLink == false ) && ( dirsize >= 0 ) ) ) { if(wconfig->getShowStringForDirSize()==true) sfds=true; } } if(sfds==true) { s1 = wconfig->getStringForDirSize(); lv->setText( row, 2 * i, s1 ); } else { mlen = NiceLongSize( dissize ); str = (char*)_allocsafe( mlen + 1 ); MakeLong2NiceStr( str, dissize ); str[ mlen ] = '\0'; s1 = str; _freesafe( str ); lv->setText( row, 2 * i, s1 ); } } break; case WorkerTypes::LISTCOL_TYPE: if ( filetype != NULL ) { s1 = filetype->getName(); } else { if ( isDir() == true ) { // Dir s1 = wconfig->getdirtype()->getName(); } else { s1 = wconfig->getnotyettype()->getName(); } } lv->setText( row, 2 * i, s1 ); break; case WorkerTypes::LISTCOL_PERM: s1 = getPermissionString(); lv->setText( row, 2 * i, s1 ); break; case WorkerTypes::LISTCOL_OWNER: // will be 1 for Owner.group, 0 else ost=wconfig->getOwnerstringtype(); s1 = ugdb->getUserNameS( statbuf.userid ); if(ost==1) { s1 += '.'; } else { s1 += " @ "; } s1 += ugdb->getGroupNameS( statbuf.groupid ); lv->setText( row, 2 * i, s1 ); break; case WorkerTypes::LISTCOL_DEST: str = getDestination(); if ( str != NULL ) { // only if there will be something to print lv->setText( row, 2 * i, str ); _freesafe( str ); } else { lv->setText( row, 2 * i, "" ); } break; case WorkerTypes::LISTCOL_MOD: timeptr = localtime( &( statbuf.lastmod ) ); mlen = wconfig->getDatelen( timeptr ); str = (char*)_allocsafe( mlen + 2 ); memset( str, ' ', mlen + 1 ); x = wconfig->writeDateToString( str , mlen + 1, timeptr ); str[ x ] = '\0'; s1 = str; _freesafe( str ); lv->setText( row, 2 * i, s1 ); break; case WorkerTypes::LISTCOL_ACC: timeptr = localtime( &( statbuf.lastaccess ) ); mlen = wconfig->getDatelen( timeptr ); str = (char*)_allocsafe( mlen + 2 ); memset( str, ' ', mlen + 1 ); x = wconfig->writeDateToString( str , mlen + 1, timeptr ); str[ x ] = '\0'; s1 = str; _freesafe( str ); lv->setText( row, 2 * i, s1 ); break; case WorkerTypes::LISTCOL_CHANGE: timeptr = localtime( &( statbuf.lastchange ) ); mlen = wconfig->getDatelen( timeptr ); str = (char*)_allocsafe( mlen + 2 ); memset( str, ' ', mlen + 1 ); x = wconfig->writeDateToString( str , mlen + 1, timeptr ); str[ x ] = '\0'; s1 = str; _freesafe( str ); lv->setText( row, 2 * i, s1 ); break; case WorkerTypes::LISTCOL_INODE: li = (loff_t)statbuf.inode; s1 = GetLong2Str( li ); lv->setText( row, 2 * i, s1 ); break; case WorkerTypes::LISTCOL_NLINK: li = (loff_t)statbuf.nlink; s1 = GetLong2Str( li ); lv->setText( row, 2 * i, s1 ); break; case WorkerTypes::LISTCOL_BLOCKS: li = (loff_t)statbuf.blocks; s1 = GetLong2Str( li ); lv->setText( row, 2 * i, s1 ); break; default: break; } } if ( customcolors == true ) { lv->setFG( row, FieldListView::CC_NORMAL, fg[0] ); lv->setBG( row, FieldListView::CC_NORMAL, bg[0] ); lv->setFG( row, FieldListView::CC_SELECT, fg[1] ); lv->setBG( row, FieldListView::CC_SELECT, bg[1] ); lv->setFG( row, FieldListView::CC_ACTIVE, fg[2] ); lv->setBG( row, FieldListView::CC_ACTIVE, bg[2] ); lv->setFG( row, FieldListView::CC_SELACT, fg[3] ); lv->setBG( row, FieldListView::CC_SELACT, bg[3] ); } else { if ( ( isDir() == true ) && ( isCorrupt == false ) ) { lv->setFG( row, FieldListView::CC_NORMAL, wconfig->getUnselDir( 0 ) ); lv->setBG( row, FieldListView::CC_NORMAL, wconfig->getUnselDir( 1 ) ); lv->setFG( row, FieldListView::CC_SELECT, wconfig->getSelDir( 0 ) ); lv->setBG( row, FieldListView::CC_SELECT, wconfig->getSelDir( 1 ) ); lv->setFG( row, FieldListView::CC_ACTIVE, wconfig->getUnselDirAct( 0 ) ); lv->setBG( row, FieldListView::CC_ACTIVE, wconfig->getUnselDirAct( 1 ) ); lv->setFG( row, FieldListView::CC_SELACT, wconfig->getSelDirAct( 0 ) ); lv->setBG( row, FieldListView::CC_SELACT, wconfig->getSelDirAct( 1 ) ); } else { lv->setFG( row, FieldListView::CC_NORMAL, wconfig->getUnselFile( 0 ) ); lv->setBG( row, FieldListView::CC_NORMAL, wconfig->getUnselFile( 1 ) ); lv->setFG( row, FieldListView::CC_SELECT, wconfig->getSelFile( 0 ) ); lv->setBG( row, FieldListView::CC_SELECT, wconfig->getSelFile( 1 ) ); lv->setFG( row, FieldListView::CC_ACTIVE, wconfig->getUnselFileAct( 0 ) ); lv->setBG( row, FieldListView::CC_ACTIVE, wconfig->getUnselFileAct( 1 ) ); lv->setFG( row, FieldListView::CC_SELACT, wconfig->getSelFileAct( 0 ) ); lv->setBG( row, FieldListView::CC_SELACT, wconfig->getSelFileAct( 1 ) ); } } if ( isCorrupt == true ) { lv->setFG( row, FieldListView::CC_NORMAL, 4 ); lv->setFG( row, FieldListView::CC_ACTIVE, 4 ); } } const char *FileEntry::getPermissionString() { static char str[WORKER_PERMCHARS + 1]; if ( isLink == true ) str[0] = 'l'; else { if ( S_ISDIR( statbuf.mode ) ) str[0] = 'd'; else if ( S_ISFIFO( statbuf.mode ) ) str[0] = 'p'; else if ( S_ISSOCK( statbuf.mode ) ) str[0] = 's'; else if ( S_ISCHR( statbuf.mode ) ) str[0] = 'c'; else if ( S_ISBLK( statbuf.mode ) ) str[0] = 'b'; else str[0] = '-'; } if ( ( statbuf.mode & S_IRUSR ) == S_IRUSR ) str[1] = 'r'; else str[1] = '-'; if ( ( statbuf.mode & S_IWUSR ) == S_IWUSR ) str[2] = 'w'; else str[2] = '-'; if ( ( statbuf.mode & S_ISUID ) == S_ISUID ) { if ( ( statbuf.mode & S_IXUSR ) == S_IXUSR ) str[3] = 's'; else str[3] = 'S'; } else { if ( ( statbuf.mode & S_IXUSR ) == S_IXUSR ) str[3] = 'x'; else str[3] = '-'; } if ( ( statbuf.mode & S_IRGRP ) == S_IRGRP ) str[4] = 'r'; else str[4] = '-'; if ( ( statbuf.mode & S_IWGRP ) == S_IWGRP ) str[5] = 'w'; else str[5] = '-'; if ( ( statbuf.mode & S_ISGID ) == S_ISGID ) { if ( ( statbuf.mode & S_IXGRP ) == S_IXGRP ) str[6] = 's'; else str[6] = 'S'; } else { if ( ( statbuf.mode & S_IXGRP ) == S_IXGRP ) str[6] = 'x'; else str[6] = '-'; } if ( ( statbuf.mode & S_IROTH ) == S_IROTH ) str[7] = 'r'; else str[7] = '-'; if ( ( statbuf.mode & S_IWOTH ) == S_IWOTH ) str[8] = 'w'; else str[8] = '-'; if ( ( statbuf.mode & S_ISVTX ) == S_ISVTX ) { if ( ( statbuf.mode & S_IXOTH ) == S_IXOTH ) str[9] = 't'; else str[9] = 'T'; } else { if ( ( statbuf.mode & S_IXOTH ) == S_IXOTH ) str[9] = 'x'; else str[9] = '-'; } str[10]=0; return str; } bool FileEntry::isExe( bool fastTest ) const { if ( fastTest == true ) { if ( ( statbuf.mode & S_IXUSR ) == S_IXUSR ) return true; if ( ( statbuf.mode & S_IXGRP ) == S_IXGRP ) return true; if ( ( statbuf.mode & S_IXOTH ) == S_IXOTH ) return true; } else { uid_t uid; gid_t gid; mode_t m; bool e = false; if ( isLink == false ) { uid = userid(); gid = groupid(); m = mode(); } else if ( isCorrupt == false ) { uid = duserid(); gid = dgroupid(); m = dmode(); } else { // corrupt symlink is not executable return false; } if ( uid == geteuid() ) { e = ( ( m & S_IXUSR ) != 0 ) ? true : false; } else if ( ugdb->isInGroup( gid ) == true ) { e = ( ( m & S_IXGRP ) != 0 ) ? true : false; } else { e = ( ( m & S_IXOTH ) != 0 ) ? true : false; } return e; } return false; } int getDatelen() { char str[128]; if(datelen<0) { /* Erst berechnen */ time_t t1; struct tm *mytm; int x; time(&t1); // Alle 7 Tage messen for(int i=0;i<7;i++) { mytm=localtime(&t1); x=strftime(str,127,"%H:%M:%S %d %b %Y",mytm); if(x>datelen) datelen=x; t1+=60*60*24; // Ein Tag drauf } } return datelen; } typecandidate_t FileEntry::runTests( WCFiletype *type, bool skipcontent, CondParser *condparser, unsigned char fbuffer[64], int reads ) { typecandidate_t erg; int minsize, x, y; char *tstr1; if ( type == NULL ) return erg; if ( condparser == NULL ) return erg; if ( skipcontent == false ) { short *filedesc; if ( type->getinternID() == NORMALTYPE ) { if ( type->getUseFiledesc() == true ) { erg.tests_done++; if ( reads > 0 ) { filedesc = type->getFiledesc(); minsize = 0; for ( x = 0; x < 64; x++ ) { if ( filedesc[x] > -1 ) minsize = x + 1; } if ( ( reads >= minsize ) && ( minsize > 0 ) ) { y = 0; for ( x = 0; x < reads; x++ ) { if ( filedesc[x] >= 0 ) { if ( filedesc[x] != (short)fbuffer[x] ) { y = 1; break; } } } if ( y == 0 ) { erg.prio = 3; erg.type = type; } } } } } } /* if no type found then check extended pattern */ if ( erg.type == NULL ) { if ( type->getinternID() == NORMALTYPE ) { if ( type->getUseExtCond() == true ) { erg.tests_done++; condparser->setIgnoreContent( skipcontent ); if ( condparser->parse( type->getExtCond(), this ) == 1 ) { erg.prio = 2; erg.type = type; } } } } /* if no type found then check the pattern */ if ( erg.type == NULL ) { if ( type->getinternID() == NORMALTYPE ) { if ( type->getUsePattern() == true ) { erg.tests_done++; if ( type->getPatternUseFullname() == true ) { tstr1 = fullname; } else { tstr1 = name; } if ( type->patternMatchString( tstr1 ) == true ) { erg.prio = 1; erg.type = type; } } } } return erg; } typecandidate_t FileEntry::checkFiletype( const std::list *ftlist, bool skipcontent, CondParser *condparser, unsigned char fbuffer[64], int reads ) { WCFiletype *ft; typecandidate_t cand1, erg, cand2; const std::list *subtypes; std::list::const_iterator it1; if ( ftlist == NULL ) return erg; if ( condparser == NULL ) return erg; if ( fbuffer == NULL ) return erg; if ( ftlist->size() < 1 ) { return erg; } if ( ( S_ISDIR( statbuf.mode ) ) && ( isCorrupt == false ) ) { // Wirklich ein Verzeichnis return erg; } for ( it1 = ftlist->begin(); it1 != ftlist->end(); it1++ ) { ft = *it1; cand1 = runTests( ft, skipcontent, condparser, fbuffer, reads ); if ( ( cand1.type != NULL ) || ( cand1.tests_done < 1 ) ) { // check subtypes if we had a hit or did no tests subtypes = ft->getSubTypeList(); if ( subtypes != NULL ) { if ( subtypes->size() > 0 ) { cand2 = checkFiletype( subtypes, skipcontent, condparser, fbuffer, reads ); if ( cand2.prio > 0 ) { // subtypes are always more important cand1.prio = cand2.prio; cand1.type = cand2.type; } } } } if ( cand1.type != NULL ) { if ( cand1.prio > erg.prio ) { erg.prio = cand1.prio; erg.type = cand1.type; } } } return erg; } WCFiletype* FileEntry::checkFiletype( List *ftlist, bool skipcontent, CondParser *condparser ) { unsigned char fbuffer[64]; int reads = 0; int id; WCFiletype *ft,*unknownft; CondParser *localparser = NULL; PDatei *pfp; typecandidate_t cand1, erg, cand2; const std::list *subtypes; if ( ftlist == NULL ) return NULL; // TODO: Momentan durchsuche ich jedesmal die Liste nach unknowntyp // Da ich nun dazuübergegangen bin, die Position nicht mehr zu // garantieren, muss ich suchen // Vielleicht wäre eine Variable möglich die bei Änderung der Liste // geändert wird und so Sofortzugriff erlaubt // wconfig->getunknowntype() geht AUF JEDEN FALL nicht, die ftlist // NICHT die gleiche wie im wconfig ist (wegen Thread-behandlung) // (zumindest im Moment nicht, bei einer thread-safe liste und FTs // könnte dies wieder zurückgenommen werden) id = ftlist->initEnum(); unknownft = (WCFiletype*)ftlist->getFirstElement( id ); while ( unknownft != NULL ) { if ( unknownft->getinternID() == UNKNOWNTYPE ) break; unknownft = (WCFiletype*)ftlist->getNextElement( id ); } ftlist->closeEnum( id ); // Vorbesetzen, damit immer unknown typ kommt, selbst wenn Datei nicht den Anforderungen // fuer Dateityperkennung genuegt filetype=unknownft; if(ftlist->size()<4) { return filetype; } if ( ( S_ISDIR( statbuf.mode ) ) && ( isCorrupt == false ) ) { // Wirklich ein Verzeichnis return filetype; } if ( isReg() == false ) skipcontent = true; if ( statbuf.size < 1 ) skipcontent = true; if(skipcontent==false) { reads = -1; pfp = new PDatei(); if ( pfp->open( fullname ) == 0 ) { reads = pfp->read( fbuffer, 64 ); } delete pfp; } if ( condparser == NULL ) { localparser = new CondParser(); condparser = localparser; } id = ftlist->initEnum(); ft = (WCFiletype*)ftlist->getFirstElement( id ); while ( ft != NULL ) { cand1 = runTests( ft, skipcontent, condparser, fbuffer, reads ); if ( ( cand1.type != NULL ) || ( cand1.tests_done < 1 ) ) { // check subtypes if we had a hit or did no tests subtypes = ft->getSubTypeList(); if ( subtypes != NULL ) { if ( subtypes->size() > 0 ) { cand2 = checkFiletype( subtypes, skipcontent, condparser, fbuffer, reads ); if ( cand2.prio > 0 ) { // subtypes are always more important cand1.prio = cand2.prio; cand1.type = cand2.type; } } } } if ( cand1.type != NULL ) { if ( cand1.prio > erg.prio ) { erg.prio = cand1.prio; erg.type = cand1.type; } } ft = (WCFiletype*)ftlist->getNextElement( id ); } if ( erg.type == NULL ) { filetype = unknownft; } else { filetype = erg.type; } ftlist->closeEnum( id ); if ( filetype != NULL ) { ft = filetype; while ( ft->getColorMode() == ft->PARENTCOL ) { ft = ft->getParentType(); if ( ft == NULL ) break; } if ( ft != NULL ) { if ( ft->getColorMode() == ft->CUSTOMCOL ) { setCustomColors( true ); setColor( 0, ft->getCustomColor( 0 ) ); setColor( 1, ft->getCustomColor( 1 ) ); } else if ( ft->getColorMode() == ft->EXTERNALCOL ) { char *o1 = condparser->getOutput( ft->getColorExt(), this ); int tfg[4], tbg[4], z; if ( o1 != NULL ) { z = sscanf( o1, "%d %d %d %d %d %d %d %d", &tfg[0], &tbg[0], &tfg[1], &tbg[1], &tfg[2], &tbg[2], &tfg[3], &tbg[3] ); if ( z == 8 ) { setCustomColors( true ); setColor( 0, tfg ); setColor( 1, tbg ); } _freesafe( o1 ); } } } } // free temporary buffers if ( localparser != NULL ) delete localparser; freeContentBuf(); freeOutputBuf(); return filetype; } bool FileEntry::match(char* pattern) { if(fnmatch(pattern,name,0)==0) return true; return false; } int Datei::overreadChunk() { int chunksize=getInt(); while(chunksize>0) { getUChar(); chunksize--; } return 0; } int Datei::getIntSize() { return 5; } int Datei::getUCharSize() { return 1; } int Datei::getUShortSize() { return 2; } int Datei::getULongSize() { return 4; } long Datei::errors() { long e=error; error=0; return e; } char *ParentDir(const char *pathstr,char *dirnamereturn,int returnsize) { char *newpath; int x,y; x=strlen(pathstr); if(x<2) { newpath=(char*)_allocsafe(2); strcpy(newpath,"/"); if(dirnamereturn!=NULL) strcpy(dirnamereturn,""); } else { if(pathstr[x-1]=='/') y=x-2; else y=x-1; while((pathstr[y]!='/')&&(y>0)) { y--; } if(y==0) { newpath=(char*)_allocsafe(2); strcpy(newpath,"/"); if(dirnamereturn!=NULL) { strncpy(dirnamereturn,pathstr+1,returnsize); dirnamereturn[returnsize-1]=0; } } else { newpath=(char*)_allocsafe(y+1); strncpy(newpath,pathstr,y); if(dirnamereturn!=NULL) { strncpy(dirnamereturn,pathstr+y+1,returnsize); dirnamereturn[returnsize-1]=0; } newpath[y]=0; } } return newpath; } int Verzeichnis::getUseSize() { int size=0; if(files!=NULL) { int id=files->initEnum(); FileEntry *fe=(FileEntry*)files->getFirstElement(id); while(fe!=NULL) { if(fe->use==true) size++; fe=(FileEntry*)files->getNextElement(id); } files->closeEnum(id); } return size; } char *Datei::getFilenameFromPath(const char*path) { char *tstr; int pos; if(path==NULL) return NULL; pos=strlen(path)-2; // -2 because a name contains min. 1 character // but it can be a slash so skiping it while(pos>=0) { if(path[pos]=='/') break; pos--; } if(pos>=0) tstr=dupstring(&path[pos+1]); else tstr=dupstring(path); return tstr; } char *Datei::getNameWithoutExt(const char *name) { char *tstr; int pos,len; bool found=false; if(name==NULL) return NULL; len=strlen(name); pos=len-1; while(pos>=0) { if((name[pos]=='/')&&(pos<(len-1))) break; if(name[pos]=='.') { found=true; break; } pos--; } if(found==false) tstr=dupstring(name); else { tstr=(char*)_allocsafe(pos+1); if(pos>0) strncpy(tstr,name,pos); tstr[pos]=0; } return tstr; } /* THREADSAFE */ char *Datei::createTMPName( const char *infix ) { char *returnstr,buffer[ 2 * A_BYTESFORNUMBER( int ) ]; int rannr; static int lfdnr = 0; FILE *tfp; static MutEx lock; if ( infix == NULL ) infix = ""; lock.lock(); for(;;) { rannr=rand(); sprintf( buffer, "%d%d", lfdnr++, rannr ); returnstr = (char*)_allocsafe( strlen( "/tmp/worker" ) + strlen( infix ) + strlen( buffer ) + 1 ); sprintf( returnstr, "/tmp/worker%s%s", infix, buffer ); if(Datei::lfileExistsExt(returnstr)==Datei::D_FE_NOFILE) break; _freesafe(returnstr); } tfp = fopen( returnstr, "w" ); if ( tfp != NULL ) { chmod( returnstr, S_IRUSR | S_IWUSR ); fclose( tfp ); } lock.unlock(); return returnstr; } char *Datei::createTMPName() { return createTMPName( "" ); } int Datei::putStringExt(const char *format,const char *str) { if(fp==NULL) return -1; fprintf(fp,format,str); return 0; } char *HandlePathExt(const char *src) { char *tstr,*tstr2; char *newpath; char *buf; int size=4096,i,j; newpath=dupstring(""); int pos=0,count; // resolve "." if(src[0]=='.') { if((src[1]==0)||(src[1]=='/')) { for(;;) { buf=(char*)_allocsafe(size); if(getcwd(buf,size)!=NULL) break; else if(errno!=ERANGE) { strcpy(buf,"/"); // use the root if getcwd doesn't report the actual break; } _freesafe(buf); size*=2; } _freesafe(newpath); if(src[1]=='/') newpath=catstring(buf,"/"); else newpath=dupstring(buf); _freesafe(buf); pos=2; } } for(i=pos;i<(int)strlen(src);i++) { if(src[i]=='$') { // there is an env-variable to resolve if(i>pos) { // copy the chars before buf=(char*)_allocsafe(i-pos+1); strncpy(buf,src+pos,i-pos); buf[i-pos]=0; tstr=catstring(newpath,buf); _freesafe(newpath); _freesafe(buf); newpath=tstr; } // now find the end of the env-variable if(src[i+1]=='{') { count=1; // search for closing bracket for(j=i+2;;j++) { if(src[j]=='{') count++; else if(src[j]==0) break; else if(src[j]=='}') count--; if(count==0) { j++; // to point at the first char after this break; } } // j-1 is the closing bracket if((j-2)>=(i+2)) { tstr=dupstring(src+i+2); tstr[(j-2)-(i+2)+1]=0; tstr2=resolveEnv(tstr); _freesafe(tstr); tstr=catstring(newpath,tstr2); _freesafe(newpath); _freesafe(tstr2); newpath=tstr; } } else { // find the "/" or the end for(j=i+1;;j++) { if(src[j]==0) break; else if(src[j]=='/') break; } // j-1 is last char for the env if((j-1)>=(i+1)) { tstr=dupstring(src+i+1); tstr[(j-1)-(i+1)+1]=0; tstr2=resolveEnv(tstr); _freesafe(tstr); tstr=catstring(newpath,tstr2); _freesafe(newpath); _freesafe(tstr2); newpath=tstr; } } pos=j; i=pos; } } if(i>pos) { // copy the chars before buf=(char*)_allocsafe(i-pos+1); strncpy(buf,src+pos,i-pos); buf[i-pos]=0; tstr=catstring(newpath,buf); _freesafe(newpath); _freesafe(buf); newpath=tstr; } // now resolve the normal things like ".." "." and so on tstr=HandlePath(newpath); _freesafe(newpath); return tstr; } char *resolveEnv(const char* str) { char *resstr,*tstr,*tstr2; char *buf; int i,j; resstr=dupstring(""); int pos=0,count; for(i=pos;i<(int)strlen(str);i++) { if(str[i]=='$') { // there is an env-variable to resolve if(i>pos) { // copy the chars before buf=(char*)_allocsafe(i-pos+1); strncpy(buf,str+pos,i-pos); buf[i-pos]=0; tstr=catstring(resstr,buf); _freesafe(resstr); _freesafe(buf); resstr=tstr; } // now find the end of the env-variable if(str[i+1]=='{') { count=1; // search for closing bracket for(j=i+2;;j++) { if(str[j]=='{') count++; else if(str[j]==0) break; else if(str[j]=='}') count--; if(count==0) { j++; // to point at the first char after this break; } } // j-1 is the closing bracket if((j-2)>=(i+2)) { tstr=dupstring(str+i+2); tstr[(j-2)-(i+2)+1]=0; tstr2=resolveEnv(tstr); _freesafe(tstr); tstr=catstring(resstr,tstr2); _freesafe(resstr); _freesafe(tstr2); resstr=tstr; } } else { // find the "/" or the end for(j=i+1;;j++) { if(str[j]==0) break; else if(str[j]=='/') break; } // j-1 is last char for the env if((j-1)>=(i+1)) { tstr=dupstring(str+i+1); tstr[(j-1)-(i+1)+1]=0; tstr2=resolveEnv(tstr); _freesafe(tstr); tstr=catstring(resstr,tstr2); _freesafe(resstr); _freesafe(tstr2); resstr=tstr; } } pos=j; } } if(i>pos) { // copy the chars before buf=(char*)_allocsafe(i-pos+1); strncpy(buf,str+pos,i-pos); buf[i-pos]=0; tstr=catstring(resstr,buf); _freesafe(resstr); _freesafe(buf); resstr=tstr; } tstr=getenv(resstr); _freesafe(resstr); if(tstr==NULL) resstr=dupstring(""); else resstr=dupstring(tstr); return resstr; } void FileEntry::setLVC_DND( FieldListViewDND *lv, int row, const std::vector *dis ) { if ( lv == NULL ) return; setLVC( lv, row, dis ); lv->replacedndtext( row, name ); lv->setDataExt( row, new NMRowData( row, this, fullname ) ); } loff_t FileEntry::size() const { return statbuf.size; } time_t FileEntry::lastaccess() const { return statbuf.lastaccess; } time_t FileEntry::lastmod() const { return statbuf.lastmod; } time_t FileEntry::lastchange() const { return statbuf.lastchange; } mode_t FileEntry::mode() const { return statbuf.mode; } uid_t FileEntry::userid() const { return statbuf.userid; } gid_t FileEntry::groupid() const { return statbuf.groupid; } ino_t FileEntry::inode() const { return statbuf.inode; } nlink_t FileEntry::nlink() const { return statbuf.nlink; } loff_t FileEntry::blocks() const { return statbuf.blocks; } loff_t FileEntry::dsize() const { return dstatbuf.size; } time_t FileEntry::dlastaccess() const { return dstatbuf.lastaccess; } time_t FileEntry::dlastmod() const { return dstatbuf.lastmod; } time_t FileEntry::dlastchange() const { return dstatbuf.lastchange; } mode_t FileEntry::dmode() const { return dstatbuf.mode; } uid_t FileEntry::duserid() const { return dstatbuf.userid; } gid_t FileEntry::dgroupid() const { return dstatbuf.groupid; } ino_t FileEntry::dinode() const { return dstatbuf.inode; } nlink_t FileEntry::dnlink() const { return dstatbuf.nlink; } loff_t FileEntry::dblocks() const { return dstatbuf.blocks; } dev_t FileEntry::rdev() const { return statbuf.rdev; } dev_t FileEntry::drdev() const { return dstatbuf.rdev; } dev_t FileEntry::dev() const { return statbuf.dev; } dev_t FileEntry::ddev() const { return dstatbuf.dev; } ArrayList *Verzeichnis::getInvalidEntries() { return invalid_entries; } char *Datei::shrinkFilename( const char *str, int maxlength ) { char *tstr = NULL; int len, len1, len2, leftuse; bool stopnow; const char *lastl, *lastr, *startl, *startr, *str1; const char *filename; // first test for null pointer if ( str == NULL ) return NULL; // now test if maxlength if big enough // let 5 chars be the minimum (1 at the beginning, 3 for "...", 1 at the end) if ( maxlength < 5 ) return NULL; // from now we will always return a shorten string // now test if the str will fit in maxlength len = strlen( str ); if( len <= maxlength ) return dupstring( str ); // now we really have to do something // first find the most important part, the filename // we will also take the beginning slash (if exists) to show the user // the filename is not shorten // first test: is there any slash // if not then shorten the str with lowlevelfunc shrinkstring // if: // filename starts at the last slash or the next to last // if the str ends with a slash // if this is longer then maxlength-5 (atleast 2 chars at the beginning and "...") // then just do a shringstring because the filename will be shorten in any case // otherwise: // find the first dirname from left // if it will fit into the string, add it // otherwise take the previous string and stop // do the same with the first dirname from right // specialcase: filename is shorter then maxlength-5 // but the first dir doesnt fit, then use as much chars from it // to fill maxlength str1 = str + len - // this is the 0 byte 2; // to skip a final / (if exists) // since a filename is atleast 1 char this would // point in the worst case at the beginning slash // remember that we require maxlength atleast 5 chars and so the str is // atleast 6 chars so this will always point into the string // now search for the slash backwards while ( *str1 != '/' ) { str1--; if ( str1 < str ) break; } if ( str1 < str ) { // no slash (or only a final one) return shrinkstring( str, maxlength ); } else { // found filename // we will also take the slash into it filename = str1; // longer then maxlength-5 ? // then short with shrinkstring if ( ( (int)strlen( filename ) ) > ( maxlength - 5 ) ) return shrinkstring( str, maxlength ); // enough room for some additional chars startl = str; startr = filename; lastl = str; // this are the last positions that will fit into maxlength lastr = filename; if ( startl[0] == '/' ) // starting slash => skip startl++; // startr is at the start filename and so points to a slash // but because we want to prefer the first dir from left, leave it so for ( stopnow = false; ; ) { // remember: there is a slash before the filename // so this will stop there (or before) while ( *startl != '/' ) { startl++; } // this could run over the left while ( *startr != '/' ) { startr--; if ( startr < str ) break; } if ( startl > startr ) { // since startr is before startl both found the same mid dir // this dir will not fit in maxlength because then everything would fit // but this cannot be because of previous checks // just take lastl und lastr to build new string stopnow = true; } else { // test if startl and/or startr will fit // otherwise stop len1 = startl - str + 1; len2 = len - ( lastr - str ); // ( lastr - str ) is the number of chars before lastr! // but because we sub it from len, don't add 1 like before if ( ( len1 + 3 + len2 ) <= maxlength ) { // new dir at the left will fit lastl = startl; } len1 = lastl - str + 1; len2 = len - ( startr - str ); if ( ( len1 + 3 + len2 ) <= maxlength ) { // new dir at the right will fit lastr = startr; } if ( ( lastl != startl ) && ( lastr != startr ) ) { // nothing has changed so stop stopnow = true; } } if ( stopnow == true ) { // time to stop tstr = (char*)_allocsafe( sizeof(char) * ( maxlength + 1 ) ); if ( lastl == str ) { // no fitting dirs found // so take as much as possibly // use maxlength - 3 - strlen( filename) chars from left leftuse = maxlength - 3 - strlen( filename ); strncpy( tstr, str, leftuse ); strncpy( tstr + leftuse, "...", 3 ); strncpy( tstr + leftuse + 3, filename, maxlength - 3 - leftuse ); tstr[ maxlength ] = '\0'; } else { len1 = ( lastl - str + 1); strncpy( tstr, str, len1 ); strncpy( tstr + len1, "...", 3 ); len1 += 3; len2 = maxlength - len1; // chars left in tstr strncpy( tstr + len1, lastr, len2 ); // if there were less then len2 chars in lastr // then tstr will be null-terminated // otherwise we have to set the end tstr[ maxlength ] = '\0'; } break; } startl++; startr--; } } return tstr; } int Datei::putLine( const char *str ) { if ( str == NULL ) return -1; if ( fp == NULL ) return -1; int x; x = fputs( str, fp ); if ( x == EOF ) return -2; x = fputs( "\n", fp ); if ( x == EOF ) return -2; return strlen( str ) + 1; } char *Datei::getLine() { if ( fp == NULL ) return NULL; unsigned char *tstr,*tstr2; int ch; long x; long size; size=1024; tstr = (unsigned char*)_allocsafe( size ); x = 0; do { ch = fgetc( fp ); if ( ch != EOF ) { tstr[ x++ ] = (unsigned char)ch; } else { tstr[ x++ ] = 0; break; } if ( x == size ) { size *= 2; tstr2 = (unsigned char*)_allocsafe( size ); if ( tstr2 == NULL ) break; memcpy( (char*)tstr2, (char*)tstr, x ); _freesafe( tstr ); tstr = tstr2; } } while ( ( ch != 0 ) && ( ch != '\n' ) ); if ( tstr[ x - 1 ] == '\n' ) tstr[ x - 1 ] = '\0'; return (char*)tstr; } bool Datei::isEOF() { if ( fp == NULL ) return true; if ( feof( fp ) != 0 ) return true; return false; } loff_t Datei::fileSize( const char *name ) { worker_struct_stat stbuf; loff_t return_value; if ( worker_stat( name, &stbuf ) != 0 ) return_value = -1; else { return_value = stbuf.st_size; } return return_value; } /* * getRelativePath * * will return relative path for source in destdir * in other words: destdir/returnvalue will be the same fileentry * as source */ char *Datei::getRelativePath( const char *source, const char *destdir ) { int startpos, curpos, mode, i; char *mysource, *mydestdir; std::string erg; if ( ( source == NULL ) || ( destdir == NULL ) ) return NULL; /* basicly it works this way: first remove same directories from the beginning then for each directory in destdir add ".." before the source because this code cannot handle .. and . in the paths I remove them with HandlePath It's not a big deal to handle these strings too (by ignoring "." and removing an added "../" for ".." but this way this function keeps small and clean :-) */ mysource = HandlePath( source ); for ( i = strlen( mysource ) - 1; i >= 0; i-- ) { if ( mysource[i] == '/' ) mysource[i] = '\0'; else break; } mydestdir = HandlePath( destdir ); for ( i = strlen( mydestdir ) - 1; i >= 0; i-- ) { if ( mydestdir[i] == '/' ) mydestdir[i] = '\0'; else break; } if ( ( strlen( mysource ) < 1 ) || ( strlen( mydestdir ) < 1 ) ) { _freesafe( mysource ); _freesafe( mydestdir ); return NULL; } startpos = curpos = 0; erg = ""; mode = 0; // I just parse mydestdir and add "../" for every / // but because I want to remove same basedir // I will also parse the source string for (;;) { // the end of mydestdir is the only way to break this loop if ( mydestdir[curpos] == '\0' ) { // add "../" because destdir is a dir (as the name says) // then add the rest of mysource #if 0 // this code is correct! // but it will create results the user // doesn't expect (because it's too complicated) // for example // linking /tmp/file1 into /tmp would // would result in ../tmp/file1 which is 100% // correct but the user expect just file1 as // relative path and that's what the #else part // checks erg += "../"; erg += &mysource[startpos]; #else if ( ( mode == 0 ) && ( mysource[ curpos ] == '/' ) ) { // mydestdir ended but we are still in "same character" mode // and the source also ends as an dir so there is no need // for any "../" // read the above comment ! erg += &mysource[ curpos + 1 ]; } else { erg += "../"; erg += &mysource[startpos]; } #endif break; } switch ( mode ) { case 1: if ( mydestdir[ curpos++ ] == '/' ) { erg += "../"; } break; default: if ( mysource[ curpos ] == '\0' ) mode = 1; // no curpos change! else if ( ( mysource[ curpos ] == '/' ) && ( mydestdir[ curpos ] == '/' ) ) { // new directory, old one was identically // so set new start startpos = ++curpos; } else if ( mysource[ curpos ] == mydestdir[ curpos ] ) { // same character => keep in this mode curpos++; } else mode = 1; // no cursorchange break; } } _freesafe( mysource ); _freesafe( mydestdir ); if ( erg.length() < 1 ) return NULL; return dupstring( erg.c_str() ); } bool FileEntry::checkAccess( int m ) { if ( fullname == NULL ) return false; return ( access( fullname, m ) == 0 ) ? true : false; } char *FileEntry::getContentStr( int pos, int len ) { char *resstr = NULL; int mylen, i; if ( pos < 0 ) return dupstring( "" ); if ( len < 1 ) return dupstring( "" ); if ( contentBuf.content == NULL ) readContentBuf(); if ( contentBuf.content != NULL ) { mylen = a_min( len, contentBuf.size - pos ); if ( mylen > 0 ) { resstr = (char*)_allocsafe( mylen + 1 ); for ( i = 0; i < mylen; i++ ) { resstr[i] = contentBuf.content[i+pos]; } resstr[i] = '\0'; } } return ( resstr != NULL ) ? resstr : dupstring( "" ); } int FileEntry::getContentNum( int pos, int len ) { int mylen, i; int res = -1; if ( pos < 0 ) return -1; if ( len < 1 ) return -1; if ( contentBuf.content == NULL ) readContentBuf(); if ( contentBuf.content != NULL ) { mylen = a_min( len, contentBuf.size - pos ); if ( mylen > 0 ) { res = 0; for ( i = 0; i < mylen; i++ ) { res <<= 8; res += (unsigned char)contentBuf.content[i+pos]; } } } return res; } void FileEntry::freeContentBuf() { if ( contentBuf.content != NULL ) { _freesafe( contentBuf.content ); contentBuf.content = NULL; contentBuf.size = 0; } } void FileEntry::readContentBuf( int len ) { int reads, i; unsigned char fbuffer[64]; PDatei *pfp; if ( isReg() == false ) return; if ( ( len < 1 ) || ( len > 64 ) ) return; if ( contentBuf.content == NULL ) { reads = -1; pfp = new PDatei(); if ( pfp->open( fullname ) == 0 ) { reads = pfp->read( fbuffer, len ); } delete pfp; if ( ( reads > 0 ) && ( reads <= len ) ) { contentBuf.content = (char*)_allocsafe( len + 1 ); contentBuf.size = reads; for ( i = 0; i < reads; i++ ) { contentBuf.content[i] = (char)fbuffer[i]; } for ( i = reads; i < ( len + 1 ); i++ ) { contentBuf.content[i] = '\0'; } } } } void FileEntry::freeOutputBuf() { if ( outputBuf != NULL ) { delete outputBuf; outputBuf = NULL; } } const char *FileEntry::findOutput( const char *tcommand ) { if ( outputBuf == NULL ) { outputBuf = new StringBuf(); } else { return outputBuf->find( tcommand ); } return NULL; } void FileEntry::addOutput( const char *tcommand, const char *toutput, int value ) { if ( outputBuf == NULL ) outputBuf = new StringBuf(); outputBuf->add( tcommand, toutput, value ); } int FileEntry::findReturnvalue( const char *tcommand, int *return_value ) { if ( outputBuf == NULL ) { outputBuf = new StringBuf(); } else { return outputBuf->findValue( tcommand, return_value ); } return -1; } int FileEntry::findOutputAndRV( const char *tcommand, const char **return_output, int *return_value ) { if ( outputBuf == NULL ) { outputBuf = new StringBuf(); } else { return outputBuf->find( tcommand, return_output, return_value ); } return -1; } bool FileEntry::isReg() const { if ( isLink == false ) { if ( S_ISREG( statbuf.mode ) ) return true; else return false; } if ( isCorrupt == true ) return false; if ( S_ISREG( dstatbuf.mode ) ) return true; return false; } void FileEntry::setCustomColors( bool nv ) { customcolors = nv; } bool FileEntry::getCustomColors() const { return customcolors; } void FileEntry::setColor( int m, const int *v ) { int i; if ( v == NULL ) return; if ( m == 0 ) { for ( i = 0; i < 4; i++ ) { fg[i] = v[i]; } } else if ( m == 1 ) { for ( i = 0; i < 4; i++ ) { bg[i] = v[i]; } } } void FileEntry::setColor( int m, int pos, int v ) { if ( ( pos >= 0 ) && ( pos < 4 ) ) { if ( m == 0 ) { fg[pos] = v; } else if ( m == 1 ) { bg[pos] = v; } } } int FileEntry::getColor( int m, int pos ) const { if ( ( pos >= 0 ) && ( pos < 4 ) ) { if ( m == 0 ) { return fg[pos]; } else if ( m == 1 ) { return bg[pos]; } } return -1; } const int *FileEntry::getColor( int m ) const { if ( m == 0 ) { return fg; } else if ( m == 1 ) { return bg; } return NULL; } /* * Method to check for same destination file * it currently only check the destination itself, not the possible * destination of a symlink */ bool FileEntry::isSameFile( const char *othername, bool follow_symlinks ) const { struct stat buf; if ( othername == NULL ) return false; if ( stat( othername, &buf ) != 0 ) return false; if ( ( isLink == true ) && ( follow_symlinks == true ) && ( isCorrupt == false ) ) { if ( ( dinode() == buf.st_ino ) && ( ddev() == buf.st_dev ) ) return true; } else { if ( ( inode() == buf.st_ino ) && ( dev() == buf.st_dev ) ) return true; } return false; } FileEntry::FileEntry( const FileEntry &other ) { fullname = ( other.fullname != NULL ) ? dupstring( other.fullname ) : NULL; name = (other.name != NULL ) ? dupstring( other.name ) : NULL; filetype = other.filetype; use = other.use; isHidden = other.isHidden; reclistQueued = other.reclistQueued; memcpy( &statbuf, &( other.statbuf ), sizeof( statbuf ) ); memcpy( &dstatbuf, &( other.dstatbuf ), sizeof( dstatbuf ) ); customcolors = other.customcolors; setColor( 0, other.fg ); setColor( 1, other.bg ); dirsize = other.dirsize; select = other.select; isLink = other.isLink; isCorrupt = other.isCorrupt; nr = other.nr; inFilter = other.inFilter; // not copied contentBuf.content = NULL; contentBuf.size = 0; outputBuf = NULL; } /* * Method to test for equal fileentry * * Does same extented test to ensure that the fileentry * is a duplicated version */ bool FileEntry::equals( const FileEntry *fe ) const { if ( fe == NULL ) return false; if ( fe == this ) return true; return equals( *fe ); } bool FileEntry::equals( const FileEntry &fe ) const { // require name if ( ( fullname == NULL ) || ( fe.fullname == NULL ) ) return false; // require same inode/device if ( statbuf.inode == 0 ) return false; if ( ( statbuf.inode != fe.statbuf.inode ) || ( statbuf.dev != fe.statbuf.dev ) ) return false; // require same size if ( statbuf.size != fe.statbuf.size ) return false; // require same name if ( strcmp( fullname, fe.fullname ) != 0 ) return false; // finally require same times if ( statbuf.lastaccess != fe.statbuf.lastaccess ) return false; if ( statbuf.lastmod != fe.statbuf.lastmod ) return false; if ( statbuf.lastchange != fe.statbuf.lastchange ) return false; return true; }