aboutsummaryrefslogtreecommitdiff
path: root/signfs/signfs.c
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--signfs/signfs.c526
1 files changed, 526 insertions, 0 deletions
diff --git a/signfs/signfs.c b/signfs/signfs.c
new file mode 100644
index 0000000..efa7e97
--- /dev/null
+++ b/signfs/signfs.c
@@ -0,0 +1,526 @@
+/*
+ * SignFS : Tool to have an image of the filesystem
+ *
+ * Copyright (C) 1999-2001, Benoit Dolez <benoit@meta-x.org>
+ *
+ * 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, 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.
+ */
+
+/*
+ * File: signfs.c
+ * Object: Signing filesystem functions
+ * Version: 0.5
+ * Date: Sun Dec 23 14:21:50 CET 2001
+ */
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <malloc.h>
+#include <time.h>
+#include "structure.h"
+#include "signfs.h"
+#include "others.h"
+
+dev_t SingleDev;
+extern int SingleFileSystem,NoDate;
+extern int CheckMode;
+extern char *BaseFS,*BaseFile;
+extern int ShowDiff,Show;
+extern int HumanReadable;
+extern int CurrentDir;
+extern char *Output;
+
+#define DIFF(f,field) ((SHOWDIFF(f) && (datatemp.flag & (f))==(f) && \
+ data->field != datatemp.field)?(f):0)
+
+// print the data to the standart output
+void print_fileinfo(t_fileinfo *data,char *filename,int recurs,FILE *output) {
+ // recurs = 0 ne pas traiter la recursivité, écriture simple
+ // recurs = 1 traiter la recursivité, écriture des différences possible
+ // recurs = 2 ne pas traiter la récurisivité, écriture d'une différence
+ int s,l,show=1;
+ static char blk[8192];
+ t_list *c;
+ char directory[8192];
+
+ if (!filename || !data) return ;
+ s=0;
+ if (recurs == 2) {
+ s+=sprintf(blk+s,"< ");
+ }
+ else if (ShowDiff != 0 && recurs == 1) {
+ if (data->diff) {
+ print_fileinfo(data->diff,filename,2,output);
+ s+=sprintf(blk+s,"> ");
+ } else {
+ if ((data->filled & (FILLED_FS|FILLED_FILE)) != (FILLED_FS|FILLED_FILE))
+ if ((data->filled & FILLED_FS) && (Show & SHOW_NEW)!=0)
+ s+=sprintf(blk+s,"+ ");
+ else if ((data->filled & FILLED_FILE) && (Show & SHOW_OLD)!=0)
+ s+=sprintf(blk+s,"- ");
+ else show=0;
+ else if ((Show & SHOW_OTHERS) == 0) show=0;
+ else s+=sprintf(blk+s,"= ");
+ }
+ }
+ if ( ( show && data->filled) ) {
+ if (SHOW(FLAG_TYPE))
+ s+=sprintf(blk+s,"%c",FILE_TYPE(data->mode));
+
+ // s+=sprintf(blk+s,"%s ",right(data->mode));
+ if (SHOW(FLAG_MODE)) {
+ if (HumanReadable)
+ s+=sprintf(blk+s," %04o(%s) ",data->mode & 0007777,right(data->mode));
+ else
+ s+=sprintf(blk+s," %04o ",data->mode & 0007777);
+ }
+
+ if (SHOW(FLAG_MODE))
+ s+=sprintf(blk+s,"%5d %5d ",data->uid,data->gid);
+ if (SHOW(FLAG_SIZE)) {
+ if (S_ISBLK(data->mode) || S_ISCHR(data->mode)) {
+ char tmp[11];
+ sprintf(tmp,"%d,%d",major(data->rdev),minor(data->rdev));
+ s+=sprintf(blk+s,"%10s ",tmp);
+ } else {
+ s+=sprintf(blk+s,"%10ld ",data->size);
+ }
+ }
+ if (SHOW(FLAG_MD5SUM)) {
+ if (data->have_md5) {
+ s+=sprintf(blk+s,"%08x%08x",O4(data->md5sum),O4(data->md5sum+4));
+ s+=sprintf(blk+s,"%08x%08x ",O4(data->md5sum+8),O4(data->md5sum+12));
+ } else {
+ s+=sprintf(blk+s,"-------------------------------- ");
+ }
+ }
+ if (SHOW(FLAG_MTIME)) {
+ if (HumanReadable) {
+ char *c;
+ c=ctime(&(data->mtime));c[strlen(c)-1]=0;
+ s+=sprintf(blk+s,"%10ld(%s) ",data->mtime,c);
+ }
+ else
+ s+=sprintf(blk+s,"%10ld ",data->mtime);
+ }
+
+ s+=sprintf(blk+s,"%s",*filename?filename:".");
+ // s+=sprintf(blk+s,"%s",*filename?filename:"[current-directory]");
+
+ if (SHOW(FLAG_LINK))
+ if (S_ISLNK(data->mode) && data->link) {
+ s+=sprintf(blk+s," %s",data->link);
+ }
+ }
+ if (s > 0 && Output == NULL) {
+ // écriture sur la sortie standard
+ write(1,blk,strlen(blk));
+ write(1,"\n",1);
+ } else if (s > 0) {
+ // écriture dans l'output
+ fprintf(output,"%s\n",blk);
+ } else if (Output != NULL) {
+ // écriture dans l'output y compris le fichier vide qui est la base
+ }
+ if (recurs == 1 && (c=data->files)) {
+ strcpy(directory,filename);
+ l=strlen(directory);
+ if (l > 0 && directory[l-1] != '/')
+ strcpy(directory+l++,"/");
+ while(c) {
+ strcpy(directory+l,((t_fileinfo*)(c->data))->filename);
+ print_fileinfo((void*)(c->data),directory,recurs,output);
+ c=c->next;
+ }
+ }
+}
+
+// file data struct with filename and stat
+t_fileinfo *fill_fileinfo(char *filename, char *pfilename,
+ struct stat *stat, t_fileinfo *data) {
+ static MD5_CTX c;
+ static char blk[8192];
+ int fd,s,diff=0;
+ static t_fileinfo datatemp;
+
+ data->filename=strdup(pfilename);
+ if (!stat) return (data);
+ if (ShowDiff != 0) memcpy(&datatemp,data,sizeof(*data));
+ data->filled|=FILLED_FS;
+ data->fsflag=FLAG_ALL;
+ data->mode=stat->st_mode;
+ data->uid=stat->st_uid;
+ data->gid=stat->st_gid;
+ if (S_ISBLK(data->mode) || S_ISCHR(data->mode))
+ data->rdev=stat->st_rdev;
+ else if (!S_ISDIR(data->mode))
+ data->size=stat->st_size;
+ data->mtime=stat->st_mtime;
+ if (S_ISREG(data->mode)) {
+ if ((fd=open(SPD(filename),O_RDONLY)) < 0) {
+ pferror("open(%s) for checksum",SPD(filename));
+ } else {
+ MD5_Init(&c);
+ while ((s=read(fd,blk,8192))>0) MD5_Update(&c,blk,s);
+ MD5_Final(data->md5sum,&c);
+ close(fd);
+ data->have_md5=1;
+ }
+ } else if (S_ISLNK(data->mode)) {
+ int l;
+ if ((l=readlink(SPD(filename),blk,8192)) < 0) {
+ pferror("readlink(%s)",SPD(filename));
+ } else {
+ blk[l]=0;
+ MD5_Init(&c);
+ MD5_Update(&c,blk,l);
+ MD5_Final(data->md5sum,&c);
+ data->have_md5=1;
+ data->link=strdup(blk);
+ }
+ }
+ diff|=DIFF(FLAG_MODE,mode);
+ diff|=DIFF(FLAG_TYPE,mode);
+ diff|=DIFF(FLAG_UID,uid);
+ diff|=DIFF(FLAG_GID,gid);
+ diff|=DIFF(FLAG_SIZE,size);
+ diff|=DIFF(FLAG_RDEV,rdev);
+ diff|=DIFF(FLAG_MTIME,mtime);
+ if (SHOWDIFF(FLAG_MD5SUM) && (datatemp.flag&FLAG_MD5SUM) &&
+ ((data->have_md5 == datatemp.have_md5 &&
+ memcmp(data->md5sum,datatemp.md5sum,MD5_DIGEST_LENGTH)!=0) ||
+ data->have_md5 != datatemp.have_md5)) {
+ diff|=FLAG_MD5SUM;
+ }
+ if (SHOWDIFF(FLAG_LINK) && (datatemp.flag&FLAG_LINK) &&
+ strcmp(data->link,datatemp.link)) diff|=FLAG_LINK;
+ if (SHOWDIFF(diff) &&
+ (data->filled&(FILLED_FS|FILLED_FILE))==(FILLED_FS|FILLED_FILE)) {
+ data->diff=malloc(sizeof(t_fileinfo));
+ memcpy(data->diff,&datatemp,sizeof(t_fileinfo));
+ }
+ return (data);
+}
+
+// looking for directory in the current directory tree
+t_fileinfo *find_parent(char *directory,t_fileinfo *current) {
+ char *b,*r,bb[8192];
+ t_list *c;
+ int res;
+
+ strcpy(r=bb,directory);
+ while(current && *r) {
+ b=r;
+ if ((r=strchr(r,'/'))) { *r=0;r++; }
+ else return (current);
+ res=1;
+ for (c=current->files;c;c=c->next)
+ if ((res=strcmp(((t_fileinfo*)(c->data))->filename,b))>=0) break;
+ if (res == 0) { // ok
+ // in the futur, check if directory
+ current=(void*)(c->data);
+ }
+ else { // don't know,
+ current=build_fileinfo(NULL,b,NULL,current);
+ current->mode |= S_IFDIR;
+ }
+ }
+ return (current);
+}
+
+// find a file in the current directory
+t_fileinfo *find_fileinfo(char *filename, t_fileinfo *current) {
+ t_list *c;
+ int res=1;
+
+ if (!current) return (NULL);
+ // fprintf(stderr,"recherche\n");
+ for (c=current->files;c;c=c->next) {
+ // fprintf(stderr,"%s <-> %s\n",((t_fileinfo*)(c->data))->filename,filename);
+ if ((res=strcmp(((t_fileinfo*)(c->data))->filename,filename))>=0) break;
+ }
+ return (res==0?(t_fileinfo*)(c->data):NULL);
+}
+
+// build data from stat informations
+t_fileinfo *build_fileinfo(char *filename, char *pfilename,
+ struct stat *stat, t_fileinfo *parent) {
+ t_fileinfo *data;
+
+ if (!parent || !(data=find_fileinfo(pfilename,parent))) {
+ // inexistant : creation requise
+ data=malloc(sizeof(*data));
+ bzero(data,sizeof(*data));
+ data->parent=parent;
+ fill_fileinfo(filename,pfilename,stat,data);
+ if (parent)
+ list_put((void*)&(parent->files),(void*)data,off(t_fileinfo,filename),strcmp);
+ } else {
+ fill_fileinfo(filename,pfilename,stat,data);
+ }
+ return(data);
+}
+
+// had data from an other readed struct
+void complete_fileinfo(t_fileinfo *data,t_fileinfo *n) {
+ data->filename=n->filename;
+ data->mode=n->mode;
+ data->uid=n->uid;
+ data->gid=n->gid;
+ data->rdev=n->rdev;
+ data->size=n->size;
+ data->mtime=n->mtime;
+ data->have_md5=n->have_md5;
+ memcpy(data->md5sum,n->md5sum,MD5_DIGEST_LENGTH);
+ data->link=n->link;
+ data->flag=n->flag;
+}
+
+// get directory tree from file
+int read_file_fileinfo(t_fileinfo *data, FILE *file) {
+ char blk[8192],*b,*p,*f;
+ int status,i,l,parenthesis;
+ t_fileinfo *c;
+
+ // reading line by line
+ while(fgets(b=p=blk,8192,file)) {
+ t_fileinfo *n=malloc(sizeof(*n));
+ blk[strlen(blk)-1]=0;
+ bzero(n,sizeof(*n));
+ status=1;
+ while(*p) {
+ parenthesis=0;
+ for (b=p;*p && ( *p!=' ' || parenthesis==1 ) ;p++) {
+ if (*p == '(' && parenthesis==0) parenthesis=1;
+ if (*p == ')' && parenthesis==1) parenthesis=0;
+ }
+ if (*p)
+ for (*p=0,p++;*p==' ';p++);
+ switch (status) {
+ case 1:
+ switch(*b) {
+ case 'l':n->mode=S_IFLNK;break;
+ case 'd':n->mode=S_IFDIR;break;
+ case 'c':n->mode=S_IFCHR;break;
+ case 'b':n->mode=S_IFBLK;break;
+ case 'f':n->mode=S_IFIFO;break;
+ case 's':n->mode=S_IFSOCK;break;
+ case '-':n->mode=S_IFREG;break;
+ default:break;
+ }
+ n->flag|=FLAG_TYPE;
+ break;
+ case 2:
+ if ((f=strchr(b,'('))) { *f=0; }
+ n->mode+=strtol(b,NULL,8);
+ n->flag|=FLAG_MODE;
+ break;
+ case 3: n->uid=atoi(b); n->flag|=FLAG_UID; break;
+ case 4: n->gid=atoi(b); n->flag|=FLAG_GID; break;
+ case 5:
+ if ((f=strchr(b,','))) {
+ *f=0;f++;
+ n->rdev=atoi(b)*256+atoi(f);
+ } else {
+ n->size=atoi(b);
+ }
+ n->flag|=FLAG_SIZE;
+ break;
+ case 6:
+ n->have_md5=1;
+ if (!strstr(b,"----"))
+ for (i=0;i<MD5_DIGEST_LENGTH;i++)
+ n->md5sum[i]=(unsigned char)(HEXTODEC(b[i*2])*16+HEXTODEC(b[i*2+1]));
+ else
+ n->have_md5=0;
+ n->flag|=FLAG_MD5SUM;
+ break;
+ case 7:
+ if ((f=strchr(b,'('))) { *f=0; }
+ n->mtime=(time_t)atol(b);
+ n->flag|=FLAG_MTIME;
+ break;
+ case 8:
+ l=strlen(b);
+ while (l>0 && b[l-1]=='/') b[--l]=0;
+ n->parent=data;
+ if (BaseFile) {
+ if (!strncmp(b,BaseFile,strlen(BaseFile)) &&
+ (b[strlen(BaseFile)] == 0 || b[strlen(BaseFile)] == '/')) {
+ b += strlen(BaseFile);
+ if (*b == '/') b++;
+ l = strlen(b);
+ }
+ }
+ if (l>0) {
+ if ((f=strrchr(b,'/'))) {
+ n->parent=find_parent(b,data);
+ f++;
+ } else {
+ f=b;
+ }
+ n->filename=strdup(f);
+ c=list_put((void*)&(n->parent->files),(void*)n,
+ off(t_fileinfo,filename),strcmp);
+ n->filled|=FILLED_FILE;
+ if (c) { complete_fileinfo(c,n); free(n); n=c ; }
+ }
+ else {
+ n->filename="";
+ complete_fileinfo(data,n);
+ free(n);
+ n=data;
+ n->filled|=FILLED_FILE;
+ }
+ break;
+ case 9: n->link=strdup(b); n->flag|=FLAG_LINK; break;
+ default: break;
+ }
+ status++;
+ }
+ }
+ return(1);
+}
+
+// reading data from filesystem
+int read_directory_fileinfo(t_fileinfo *data, char *directory) {
+ DIR *dir;
+ t_fileinfo *tdata;
+ struct dirent *dirent;
+ struct stat stat;
+ char *temp;
+ int l;
+ off_t position;
+
+ l=strlen(directory);
+ if (!(dir=opendir(SPD(directory)))) {
+ pferror("opendir(%s)",SPD(directory));
+ return(0);
+ }
+ if (*directory) {
+ temp=malloc(strlen(directory)+1+NAME_MAX);
+ memcpy(temp,directory,l);
+ if (temp[l-1] != '/') strcpy(temp+l++,"/");
+ } else {
+ temp=malloc(NAME_MAX);
+ strcpy(temp,"");
+ }
+ while ((dirent = readdir(dir))) {
+ if (dirent->d_name[0] == '.' &&
+ (dirent->d_name[1] == 0 ||
+ (dirent->d_name[1] == '.' && dirent->d_name[2] == 0))) continue;
+ strcpy(temp+l,dirent->d_name);
+ if (lstat(temp,&stat)) {
+ pferror("stat(%s)",temp);
+ continue;
+ }
+ tdata=build_fileinfo(temp,temp+l,&stat,data);
+ if (S_ISDIR(stat.st_mode) &&
+ !(SingleFileSystem && SingleDev!= stat.st_dev)) {
+ position=telldir(dir);
+ closedir(dir);
+ read_directory_fileinfo(tdata,temp);
+ dir=opendir(SPD(directory));
+ seekdir(dir,position);
+ }
+ }
+ closedir(dir);
+ free(temp);
+ return(1);
+}
+
+
+// build directory tree from arg and filesystem
+int read_directories_fileinfo(t_fileinfo *data, char **argv) {
+ struct stat stat;
+ char *temp="";
+ char dfile[8192],*file;
+ int l,dir=0;
+ t_fileinfo *tdata,*pdata;
+
+ if (*argv == NULL) {
+ if (CurrentDir) {
+ if (lstat(".",&stat)) {
+ pferror("stat(%s)",".");
+ return(0);
+ }
+ SingleDev=stat.st_dev;
+ // logging for '.'
+ if (S_ISDIR(stat.st_mode)) {
+ read_directory_fileinfo(data,".");
+ }
+ }
+ } else {
+ while (*argv) {
+ strcpy(file=dfile,*argv);
+ l=strlen(file);
+ if (strcmp(file,"/")) {
+ if (l>0 && file[l-1]=='/') {
+ dir=1 ;
+ file[--l]=0;
+ } else dir=0;
+ if (BaseFS) {
+ // change root in the tree directory
+ l=strlen(BaseFS);
+ if (!strncmp(file,BaseFS,strlen(BaseFS)) &&
+ (file[strlen(BaseFS)]==0 || file[strlen(BaseFS)]=='/')) {
+ file += strlen(BaseFS);
+ if (*file=='/') file++;
+ }
+ }
+ }
+ if (lstat(dfile,&stat)) {
+ error("lstat(%s)",dfile);
+ return(0);
+ }
+ // keep the dev info for xdev option
+ SingleDev=stat.st_dev;
+ if (*file) {
+ if ((temp=dirname(file))) { // looking for parent if it exist
+ pdata=find_parent(file,data);
+ // making directory
+ tdata=build_fileinfo(file,basename(file),&stat,pdata);
+ } else {
+ pdata=data;
+ // making directory
+ tdata=build_fileinfo(file,file,&stat,pdata);
+ }
+ } else {
+ // if (!find_fileinfo(".",data))
+ fill_fileinfo("","",&stat,data);
+ tdata=data;
+ }
+ // had structure to data
+ if (S_ISDIR(stat.st_mode) || (dir && S_ISLNK(stat.st_mode))) {
+ read_directory_fileinfo(tdata,dfile);
+ }
+ argv++;
+ }
+ }
+ return(1);
+}
+
+
+// have to clean the fileinfo structure before existing
+int delete_fileinfo(t_fileinfo *data) {
+ return(1);
+}
+