/*
file utilites
*/
#include <unistd.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <utime.h>
#include <errno.h>
#include <string.h>
#include <ctype.h>
#include "config.h"
int access_via_stat(char *name,int mode)
/* check F_OK (exist) ok
* check R_OK (readable) same as F_OK (buggy but ...)
* assert violation if mode == W_OK (writeable)
* */
{
struct stat stat_buf;
ass(mode==F_OK || mode==R_OK);
return(stat(name,&stat_buf));
}
/* ln, cp, mv, find_file_by_size_and_crc */
/* all functions returns 0 when success */
void rm_by_mask(char *dirname,char *mask)
/* delete files by mask (dirname/mask) */
{
char *p; struct stat stat_buf;
DIR *dir; struct dirent *dirp;
dir=opendir(dirname);
if(dir==NULL) return;
while(1)
{
dirp=readdir(dir);
if(!dirp) break;
if(wildmat_icase(dirp->d_name,mask))
{
p=xstrcpy(dirname);
p=xstrcat(p,"/");
p=xstrcat(p,dirp->d_name);
if(stat(p,&stat_buf)) continue;
if(!(stat_buf.st_mode & S_IFREG)) continue;
l_printf("%s deleted by %s",p,mask);
remove(p);
xfree(p);
}
}
closedir(dir);
}
static int cp_(char *oldname,char *newname,int add);
int cp(char *oldname,char *newname)
{
return cp_(oldname,newname,FALSE);
}
int cp_add(char *oldname,char *newname)
{
return cp_(oldname,newname,TRUE);
}
#define CP_BUFSIZE (1024*1024) /* 1mb blocks */
static int cp_(char *oldname,char *newname,int add)
/*
copy oldname to newname
use mmap with maximal buffer size = CP_BUFSIZE
mmap fails on big size files
*/
{
struct stat stbuf; int r,fd_in,fd_out; ssize_t write_return;
char *data; struct utimbuf utbuf; unsigned long a,b,i;
if((r=stat(oldname,&stbuf)))
return r;
fd_in=open(oldname,O_RDONLY|O_BINARY);
if(fd_in==-1) return -1;
if(add==FALSE)
fd_out=open(newname,O_BINARY|O_WRONLY|O_TRUNC|O_CREAT,stbuf.st_mode);
else
fd_out=open(newname,O_BINARY|O_WRONLY|O_CREAT|O_APPEND,stbuf.st_mode);
if(fd_out==-1) { close(fd_in); return -1; }
a=stbuf.st_size / CP_BUFSIZE; /* how many blocks */
b=stbuf.st_size % CP_BUFSIZE; /* last block size */
for(i=0;i<a;i++)
{
data=mmap(NULL,CP_BUFSIZE,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd_in,CP_BUFSIZE*i);
if(data==(char *)-1 || data==NULL)
{
close(fd_in);
close(fd_out);
remove(newname);
return -1;
}
write_return=write(fd_out,data,CP_BUFSIZE);
munmap(data,CP_BUFSIZE);
if(write_return!=CP_BUFSIZE)
{
close(fd_in);
close(fd_out);
remove(newname);
return -1;
}
}
if(b)
{
data=mmap(NULL,b,PROT_READ|PROT_WRITE,MAP_PRIVATE,fd_in,CP_BUFSIZE*a);
if(data==(char *)-1 || data==NULL)
{
close(fd_in);
close(fd_out);
remove(newname);
return -1;
}
write_return=write(fd_out,data,b);
munmap(data,stbuf.st_size);
}
close(fd_in);
close(fd_out);
if(b)
if(write_return!=b)
{
remove(newname);
return -1;
}
utbuf.actime=stbuf.st_atime;
utbuf.modtime=stbuf.st_mtime;
utime(newname,&utbuf);
chmod(newname,stbuf.st_mode);
chown(newname,stbuf.st_uid,stbuf.st_gid);
return 0;
}
int ln(char *oldname,char *newname)
/* try to make hardlink, and call cp() if link() failed */
{
int r;
if(link(oldname,newname))
{
if((r=cp(oldname,newname)))
return r;
return 0;
}
return 0;
}
int mv(char *oldname,char *newname)
/* try to move, and call cp()+unlink() if link() failed */
{
int r;
if(rename(oldname,newname))
{
if((r=cp(oldname,newname)))
return r;
if((r=remove(oldname)))
{
remove(newname);
return r;
}
return 0;
}
return 0;
}
int find_file(char *dirname,char *outbuff,char *origname,
unsigned long crc32,unsigned long size)
{
char buff[PATH_MAX],pattern[PATH_MAX*5];
int i,j; struct stat stat_buf;
DIR *dir; struct dirent *dirp;
strcpy(outbuff,origname);
/* simple check by access() */
snprintf(buff,sizeof(buff)-1,"%s/%s",dirname,origname);
if(!access_via_stat(buff,F_OK))
{
strcpy(outbuff,origname);
return 0;
}
/* opendir and try to find filename ignoring case */
dir=opendir(dirname);
if(dir==NULL) return -1;
while(1)
{
dirp=readdir(dir);
if(!dirp) break;
if(strcasecmp(dirp->d_name,origname)) continue;
snprintf(buff,sizeof(buff)-1,"%s/%s",dirname,dirp->d_name);
if(stat(buff,&stat_buf)) continue;
if(!(stat_buf.st_mode & S_IFREG)) continue;
strcpy(outbuff,dirp->d_name);
closedir(dir);
return 0;
}
closedir(dir);
/* opendir and try to find filename by size and crc32 */
j=strlen(origname); pattern[0]=0;
for(i=0;i<j;i++)
{
if(origname[i]=='.') break;
if(isalpha(origname[i]))
snprintf(buff,sizeof(buff)-1,"[%c%c]",toupper(origname[i]),tolower(origname[i]));
else
snprintf(buff,sizeof(buff)-1,"%c",origname[i]);
strcat(pattern,buff);
}
strcat(pattern,".*");
/*printf("DEBUG: pattern=%s\n",pattern);*/
dir=opendir(dirname);
if(dir==NULL) return -1;
while(1)
{
dirp=readdir(dir);
if(!dirp) break;
if(!wildmat(dirp->d_name,pattern)) continue;
snprintf(buff,sizeof(buff)-1,"%s/%s",dirname,dirp->d_name);
if(stat(buff,&stat_buf)) continue;
if(!(stat_buf.st_mode & S_IFREG)) continue;
if(size!=(unsigned long)(-1) && size!=stat_buf.st_size) continue;
if(crc32!=filecrc32(buff)) continue;
strcpy(outbuff,dirp->d_name);
closedir(dir);
return 0;
}
closedir(dir);
return 1;
}
int dirmode(int filemode)
{
int result;
result=filemode;
if(filemode & 0400) result|=0100;
if(filemode & 0040) result|=0010;
if(filemode & 0004) result|=0001;
return result;
}
void write_flag_tab_to_FILE(FILE *fp,int flags,struct flag_tab *tab)
/* write flag_tab structure to fp (comma list)*/
{
int no_comma=TRUE;
while(1)
{
if(tab->text==NULL) break;
if(tab->bitmask & flags)
{
if(no_comma==FALSE) fprintf(fp,",");
no_comma=FALSE;
fprintf(fp,"%s",tab->text);
}
tab++;
}
}
#ifdef TEST
int main(int argc,char *argv[])
{
if(argc<4) return -1;
if(!strcmp(argv[1],"ln"))
printf("ln(%s,%s)=%d\n",argv[2],argv[3],ln(argv[2],argv[3]));
if(!strcmp(argv[1],"mv"))
printf("mv(%s,%s)=%d\n",argv[2],argv[3],mv(argv[2],argv[3]));
if(!strcmp(argv[1],"cp"))
printf("cp(%s,%s)=%d\n",argv[2],argv[3],cp(argv[2],argv[3]));
if(!strcmp(argv[1],"zz"))
{
char b1[999],b2[999],b3[999]; unsigned long crc32,size;
strcpy(b1,argv[2]); strcpy(b3,argv[3]); crc32=strtoul(argv[4],NULL,16);
size=atol(argv[5]);
printf("crc32 of %s = %lX\n",b3,filecrc32(b3));
printf("find_file(%s,(b2),%s,%X,%lu)=%d\n",b1,b2,crc32,size,
find_file(b1,b2,b3,crc32,size));
printf("b2=%s\n",b2);
}
return 0;
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1