#include #include #include #include #include #include #include #include "perr.h" #include "ft.h" #include "fi.h" #include "db.h" #include "cmpmark.h" #define OPT_DIFFDB 0x0010 #define OPT_SHOW 0x0020 #define OPT_SHOW_X 0x0001 #define OPT_SHOW_H 0x0002 #define OPT_SHOW_P 0x0004 #define OPT_MASK_SET 0x0100 #define OPT_MASK_AND 0x0200 #define DIFFFI(_fi1, _fi2) ( \ ((_fi1)->fi_ino != (_fi2)->fi_ino || \ (_fi1)->fi_mode != (_fi2)->fi_mode || \ (_fi1)->fi_nlink != (_fi2)->fi_nlink || \ (_fi1)->fi_uid != (_fi2)->fi_uid || \ (_fi1)->fi_gid != (_fi2)->fi_gid || \ (_fi1)->fi_size != (_fi2)->fi_size || \ (_fi1)->fi_flags != (_fi2)->fi_flags || \ memcmp((_fi1)->fi_sha, (_fi2)->fi_sha, FI_CSUMSIZE)!=0) \ ) typedef struct { int mask; int opt; } RSP; int buildfitree(dbhead, dbdata, sp) DBHEAD *dbhead; void *dbdata, *sp; { FT *ft=(FT *)sp; FTENT *ftent; FI fi; fi_chtos(dbdata, &fi); if (!(ftent=ft_add(ft, dbhead->db_path, &fi, sizeof(FI)))) return (-1); ftent->ft_opt=CM_DELETED; return (0); } int checkdiff(dbhead, dbdata, sp) DBHEAD *dbhead; void *dbdata, *sp; { FT *ft=(FT *)sp; FTENT *ftent; FI *np, fi, *fi1, *fi2; fi_chtos(dbdata, &fi); if (!(ftent=ft_find(ft, dbhead->db_path, 0))) { if (!(ftent=ft_add(ft, dbhead->db_path, &fi, sizeof(FI)))) return (-1); ftent->ft_opt=CM_NEW; } else if (ftent->ft_data) { if (DIFFFI((FI *)ftent->ft_data, &fi)) { if (!(np=(FI *)malloc(sizeof(FI)*2))) return (-1); (void)memcpy(&np[0], ftent->ft_data, sizeof(FI)); (void)memcpy(&np[1], &fi, sizeof(FI)); free(ftent->ft_data); ftent->ft_data=np; ftent->ft_opt=CM_CHANGED; } else { ftent->ft_opt=CM_OK; } } return (0); } int res_builddiffdb(ftent, sp) FTENT *ftent; void *sp; { DB *db=(DB *)sp; FI *fi=(FI *)ftent->ft_data; char chfi[2*FI_CHFISIZE]; if (!fi) return (0); switch(ftent->ft_opt) { case CM_OK: break; case CM_CHANGED: fi_stoch(&fi[0], chfi); fi_stoch(&fi[1], (char *)chfi+FI_CHFISIZE); if (db_argput(db, ftent->ft_path, 2*FI_CHFISIZE, ftent->ft_opt, chfi)!=0) { pwarn1x("db_argput()"); return (-1); } break; case CM_NEW: case CM_DELETED: fi_stoch(&fi[0], chfi); if (db_argput(db, ftent->ft_path, FI_CHFISIZE, ftent->ft_opt, chfi)!=0) { pwarn1x("db_argput()"); return (-1); } break; default: /* impossible */ break; } return (0); } int res_show(ftent, sp) const FTENT *ftent; void *sp; { RSP *rsp=(RSP *)sp; FI *fi=(FI *)ftent->ft_data; int mask; if (!fi) return (0); if (ftent->ft_opt==CM_OK) return (0); if (rsp->opt & OPT_MASK_SET) { mask=rsp->mask; } else if (rsp->opt & OPT_MASK_AND) { mask=fi[0].fi_mask & rsp->mask; } else { mask=fi[0].fi_mask; } if (rsp->opt & OPT_SHOW_P) { fi_pshow(ftent->ft_opt, fi, ftent->ft_path, mask); } else if (rsp->opt & OPT_SHOW_H) { if (rsp->opt & OPT_SHOW_X) { fi_hxshow(ftent->ft_opt, fi, ftent->ft_path, mask); } else { fi_hshow(ftent->ft_opt, fi, ftent->ft_path, mask); } } return (0); } void strmasktomask(s, m) const char *s; int *m; { *m=0x0; for ( ; *s; ++s) { switch (*s) { case 'F': *m=FI_MFULL; break; case 'C': *m=FI_MCHANGE; break; case 'i': *m|=FI_MINO; break; case 'l': *m|=FI_MNLINK; break; case 'u': *m|=FI_MUID; break; case 'g': *m|=FI_MGID; break; case 'm': *m|=FI_MMODE; break; case 's': *m|=FI_MSIZE; break; case 'f': *m|=FI_MFLAGS; break; case 't': *m|=FI_MCTIME; break; case 'c': *m|=FI_MSHA; break; } } } void usage(void) { (void)fprintf(stderr, "usage: fswcmp [-h [-x] | -p | -d file] [-m mask | -M mask] file1 file2\n"); exit (1); } int main(argc, argv) int argc; const char *const *argv; { char p_diffdb[PATH_MAX+1], dbbuff[FI_CHFISIZE]; RSP rsp; DB *diffdb; FT *ft; int ch, opt, dbflags, mask; mode_t dbmode; mask=0x0; opt=OPT_SHOW|OPT_SHOW_H; while ((ch=getopt(argc, (char *const *)argv, "hxpd:m:M:"))!=-1) { switch(ch) { case 'h': opt|=OPT_SHOW|OPT_SHOW_H; break; case 'x': opt|=OPT_SHOW|OPT_SHOW_X; break; case 'p': opt|=OPT_SHOW|OPT_SHOW_P; break; case 'd': opt|=OPT_DIFFDB; (void)strncpy(p_diffdb, optarg, PATH_MAX-1); p_diffdb[PATH_MAX-1]=(char)0x0; break; case 'm': opt|=OPT_MASK_AND; strmasktomask(optarg, &mask); break; case 'M': opt|=OPT_MASK_SET; strmasktomask(optarg, &mask); break; default: usage(); break; } } argc-=optind; argv+=optind; if (argc!=2) usage(); if (!(ft=ft_init(NULL, NULL))) perr1("ft_init()"); if (db_readall(argv[0], &buildfitree, ft, &dbbuff) < 0) perr2("db_readall()", argv[0]); if (db_readall(argv[1], &checkdiff, ft, &dbbuff) < 0) perr2("db_readall()", argv[1]); if (opt & OPT_DIFFDB) { dbflags=O_CREAT|O_EXCL|O_RDWR; dbmode=S_IRUSR|S_IWUSR; if (!(diffdb=db_open(p_diffdb, dbflags, dbmode))) perr2("db_open()", p_diffdb); if (ft_traverse(ft, &res_builddiffdb, diffdb)!=0) perr1("ft_traverse()"); if (db_close(diffdb)!=0) perr2("db_close()", p_diffdb); } else if (opt & OPT_SHOW) { rsp.mask=mask; rsp.opt=opt; (void)ft_traverse(ft, &res_show, &rsp); } else { /* impossible */ } ft_close(ft); exit (0); }