/* * Dare library * Copyright (c)2004-2005 by Marek Zelem */ #include #include #include #include #include #include #include "libdare.h" int dare_is_supported( char *mountpoint ) { char path[PATH_MAX+80]; struct stat st; if( mountpoint[0]=='/' && mountpoint[1]==0 ) mountpoint++; snprintf(path,PATH_MAX,"%s/deleted",mountpoint); if( lstat(path,&st)!=0 ) return(0); if( !S_ISDIR(st.st_mode) ) return(0); return(1); } int dare_info_foreach( char *mountpoint, unsigned long dirnum, dare_info_do_t function, void *arg ) { struct dare_info *info; char path[PATH_MAX+80]; char *s; char *p[8]; int x,l; FILE *f; int count=0; if( mountpoint[0]=='/' && mountpoint[1]==0 ) mountpoint++; snprintf(path,PATH_MAX,"%s/deleted/%lu.inf",mountpoint,dirnum); if( (f=fopen(path,"r"))==NULL ) return(count); while( (s=fgets(path,PATH_MAX+80-1,f))!=NULL ) { l=strlen(s); if( l>0 && s[l-1]=='\n' ) s[l-1]=0; l=0; while( l<6 && s!=NULL && *s ) { p[l]=s; s=strchr(s,':'); if( s!=NULL ) *s++=0; l++; } if( l!=6 || s==NULL || *s==0 ) { /* error */ continue; } if( (info=malloc(sizeof(struct dare_info)+strlen(s)+1))==NULL ) { return(-1); } strcpy(info->path,s); info->mountpoint=mountpoint; info->dirnum=dirnum; info->ino=atol(p[0]); info->dtime=(time_t)(atol(p[1])); info->uid=atoi(p[2]); info->gid=atoi(p[3]); info->mode=strtoul(p[4],NULL,8); s=p[5]; l=0; while( l<6 && s!=NULL && *s ) { p[l]=s; x=strcspn(s,"(,);"); if( x>0 ) { s+=x; if( *s ) *s++=0; s+=strspn(s,"()"); } else s=NULL; l++; } if( l>0 ) info->p_fsuid=atol(p[0]); else info->p_fsuid=(unsigned int)(-1); if( l>1 ) info->p_uid=atol(p[1]); else info->p_uid=info->p_fsuid; if( l>2 ) info->p_luid=atol(p[2]); else info->p_luid=info->p_uid; if( function(arg,info)>=0 ) count++; } fclose(f); return(count); } static int cmpul( const void *a , const void *b ) { return( *((int*)a)-*((int*)b) ); } int dare_info_foreach_inf( char *mountpoint, int(*foreach_inf)(char *mountpoint,unsigned long dirnum,dare_info_do_t function,void *arg), dare_info_do_t function, void *arg ) { char path[PATH_MAX+80]; unsigned long *dirnum=NULL; int ndirnum=0; DIR *d; struct dirent *dirent; int i,x; int count; if( mountpoint[0]=='/' && mountpoint[1]==0 ) mountpoint++; snprintf(path,PATH_MAX,"%s/deleted",mountpoint); count=0; if( (d=opendir(path))==NULL ) return(-1); while( (dirent=readdir(d))!=NULL ) { x=strspn(dirent->d_name,"0123456789"); if( x<=0 || strcmp(dirent->d_name+x,".inf") ) continue; if( (dirnum=realloc(dirnum,(ndirnum+1)*sizeof(dirnum[0])))==NULL ) { fprintf(stderr,"Out of memory!\n"); exit(254); } dirnum[ndirnum++]=atol(dirent->d_name); } closedir(d); qsort(dirnum,ndirnum,sizeof(dirnum[0]),cmpul); for(i=0;id_name); unlink(path); } closedir(d); } snprintf(path,PATH_MAX,"%s/deleted/%lu",mountpoint,dirnum); rmdir(path); return(0); } char *dare_path( struct dare_info *info ) { static char buf[PATH_MAX+1]; snprintf(buf,PATH_MAX,"%s/deleted/%lu/%lu",info->mountpoint,info->dirnum,info->ino); return(buf); } struct stat *dare_lstat( struct dare_info *info ) { static struct stat st; if( lstat(dare_path(info),&st)!=0 ) return(NULL); return(&st); } int dare_exist( struct dare_info *info ) { struct stat st; if( S_ISDIR(info->mode) ) return(1); if( lstat(dare_path(info),&st)!=0 ) return(0); if( (st.st_mode & 0777) == 0 ) return(0); return(1); } char *dare_orig_path( struct dare_info *info ) { static char buf[PATH_MAX+1]; snprintf(buf,PATH_MAX,"%s%s",info->mountpoint,info->path); return(buf); } int dare_salvage( struct dare_info *info ) { char *d=dare_path(info); char *o=dare_orig_path(info); struct stat *st=dare_lstat(info); if( S_ISDIR(info->mode) && st==NULL ) { if( mkdir(o,0500)!=0 ) return(-1); } else if( st!=NULL && ((info->mode&~07777) == (st->st_mode&~07777)) ) { if( rename(d,o)!=0 ) return(-1); } else { errno=ENOENT; return(-1); } lchown(o,info->uid,info->gid); if( !S_ISLNK(info->mode) ) chmod(o,info->mode & 07777); return(0); } int dare_purge( struct dare_info *info ) { char *p=dare_path(info); if( truncate(p,0)!=0 ) return(-1); if( chmod(p,0000)!=0 ) return(-1); return(0); } static char *dare_uid2str( unsigned int uid ) { static char buf[16]; struct passwd *pw; if( (pw=getpwuid(uid))==NULL ) { if( uid==(unsigned int)-1 ) snprintf(buf,16,"%d",uid); else snprintf(buf,16,"%u",uid); return(buf); } return(pw->pw_name); } static char *dare_gid2str( unsigned int gid ) { static char buf[16]; struct group *gr; if( (gr=getgrgid(gid))==NULL ) { snprintf(buf,16,"%u",gid); return(buf); } return(gr->gr_name); } /* pwd must end with '/' */ char *dare_minimize_path( char *pwd, char *path ) { int x; x=strlen(pwd); if( !strncmp(pwd,path,x) ) { return( path+x ); } return( path ); } static char *dare_mode2str( unsigned int mode ) { static char buf[16]; int i,m; static char *rwx[8]={"---","--x","-w-","-wx","r--","r-x","rw-","rwx"}; if( S_ISREG(mode) ) buf[0]='-'; else if( S_ISDIR(mode) ) buf[0]='d'; else if( S_ISCHR(mode) ) buf[0]='c'; else if( S_ISBLK(mode) ) buf[0]='b'; else if( S_ISFIFO(mode) ) buf[0]='p'; else if( S_ISLNK(mode) ) buf[0]='l'; else if( S_ISSOCK(mode) ) buf[0]='s'; else buf[0]='?'; for(i=0;i<3;i++) { m= (mode>>((2-i)*3)) & 07; memcpy(buf+1+i*3,rwx[m],3); } if( mode & S_ISUID ) buf[3]= buf[3]=='-' ? 'S' : 's'; if( mode & S_ISGID ) buf[6]= buf[6]=='-' ? 'S' : 's'; if( mode & S_ISVTX ) buf[9]= buf[9]=='-' ? 'T' : 't'; buf[10]=0; return(buf); } static char *dare_time2str( time_t t, int format ) { struct tm *tm; unsigned long d; static char buf[1024]; static char *months[12]={"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"}; tm=localtime(&t); if( format==0 ) snprintf(buf,1024-1,"%04d-%02d-%02d %02d:%02d:%02d %s", 1900+tm->tm_year,1+tm->tm_mon,tm->tm_mday, tm->tm_hour,tm->tm_min,tm->tm_sec,tm->tm_zone); else if( format==1 ) { d=time(NULL)-t; if( d>0 && d < 60*60*24*365 ) snprintf(buf,1024-1,"%3s %2d %02d:%02d",months[tm->tm_mon],tm->tm_mday,tm->tm_hour,tm->tm_min); else snprintf(buf,1024-1,"%3s %2d %5d",months[tm->tm_mon],tm->tm_mday,1900+tm->tm_year); } else if( format==2 ) { snprintf(buf,1024-1,"%3s %2d %4d %02d:%02d:%02d",months[tm->tm_mon],tm->tm_mday,1900+tm->tm_year,tm->tm_hour,tm->tm_min,tm->tm_sec); } else snprintf(buf,1024-1,"?fmt?"); return(buf); } /* dir must end with '/' */ int dare_is_in_dir( struct dare_info *info, char *dir, int recursive ) { if( strncmp(info->path,dir,strlen(dir)) ) return(0); if( !recursive && strchr(info->path+strlen(dir),'/')!=NULL ) return(0); return(1); } char *dare_ls( struct dare_info *info, int format, char *pwd ) { static char buf[PATH_MAX+80]; static char tmp[80]; static char tmp2[16]; struct stat *st=dare_lstat(info); struct stat tmp_st; if( st==NULL ) { st=&tmp_st; st->st_nlink=0; st->st_size=0; st->st_ctime=0; } if( format==0 ) /* ls -1 */ snprintf(buf,PATH_MAX+80,"%s",dare_minimize_path(pwd,info->path)); else if( format==1 ) /* ls -l */ snprintf(buf,PATH_MAX+80,"%s %4u %-8s %-8s %8lu %12s %s",dare_mode2str(info->mode),st->st_nlink,dare_uid2str(info->uid),dare_gid2str(info->gid),st->st_size,dare_time2str(st->st_ctime,1),dare_minimize_path(pwd,info->path)); else if( format==2 ) /* ls -l s datumom zmazania */ { strncpy(tmp,dare_time2str(info->dtime,1),79); snprintf(buf,PATH_MAX+80,"%s %-8s %-6s %6lu %12s %12s %s",dare_mode2str(info->mode),dare_uid2str(info->uid),dare_gid2str(info->gid),st->st_size,dare_time2str(st->st_mtime,1),tmp,dare_minimize_path(pwd,info->path)); } else if( format==3 ) /* verbose */ { strncpy(tmp,dare_time2str(info->dtime,2),79); snprintf(tmp+strlen(tmp),79-strlen(tmp)," %-8s",dare_uid2str(info->p_uid)); snprintf(tmp+strlen(tmp),79-strlen(tmp)," %-8s",dare_uid2str(info->p_luid)); strncpy(tmp2,dare_uid2str(info->p_fsuid),15); snprintf(buf,PATH_MAX+80,"%7lu %s %2u %-8s %-8s %8lu %20s D:%-8s %s %s",info->ino,dare_mode2str(info->mode),st->st_nlink,dare_uid2str(info->uid),dare_gid2str(info->gid),st->st_size,dare_time2str(st->st_mtime,2),tmp2,tmp,dare_minimize_path(pwd,info->path)); } return(buf); }