--- embedtools/src/dircmp.c 2010/07/13 09:35:01 1.1 +++ embedtools/src/dircmp.c 2010/07/13 09:35:01 1.1.2.1 @@ -0,0 +1,270 @@ +#include "global.h" +#include "dircmp.h" + + +extern char compiled[], compiledby[], compilehost[]; +char l; + + +static void +Usage() +{ + printf( "-= DirCmp =- Tool for compare directories and show differences\n" + "=== %s === %s@%s ===\n\n" + " Syntax: dircmp [options] \n\n" + "\t-l\t\tLong directory output ..." + "\n", compiled, compiledby, compilehost); +} + +int +calcDir(const char *csDir, u_char **md) +{ + DIR *dir; + struct dirent d, *pd; + MD5_CTX ctx; + + *md = malloc(MD5_DIGEST_LENGTH); + if (!*md) { + printf("Error:: %s(%d) #%d - %s\n", __func__, __LINE__, errno, strerror(errno)); + return -1; + } else + memset(*md, 0, MD5_DIGEST_LENGTH); + + dir = opendir(csDir); + if (!dir) { + printf("Error:: %s(%d) #%d - %s\n", __func__, __LINE__, errno, strerror(errno)); + free(*md); + return -1; + } + + MD5_Init(&ctx); + while (!readdir_r(dir, &d, &pd) && pd) { + if (d.d_type == DT_DIR && (!strcmp(d.d_name, ".") || !strcmp(d.d_name, ".."))) + continue; + MD5_Update(&ctx, d.d_name, d.d_namlen); + } + MD5_Final(*md, &ctx); + + closedir(dir); + return 0; +} + +// ------------------------------------------------------------------- + +static int +func_comp(struct tagDirName const *d1, struct tagDirName const *d2) +{ + return d1->tag - d2->tag; +} + +int +cmpDir(const char *csDir1, const char *csDir2, struct tagDirName **list) +{ + struct tagDirName *l, *find; + int n, cx; + DIR *dir; + struct dirent d, *pd; + int tags[USHRT_MAX]; + register int i; + u_short t; + u_int hash; + struct stat sb; + char szStr[MAX_STR], szType[MAX_STR]; + + if (!csDir1 || !csDir2 || !list) + return -1; + else + memset(tags, -1, sizeof tags); + + l = malloc(sizeof(struct tagDirName)); + if (!l) { + printf("Error:: %s(%d) #%d - %s\n", __func__, __LINE__, errno, strerror(errno)); + return -1; + } else { + n = 0; + memset(l, 0, sizeof(struct tagDirName)); + } + + dir = opendir(csDir1); + if (!dir) { + printf("Error:: %s(%d) #%d - %s\n", __func__, __LINE__, errno, strerror(errno)); + free(l); + return -1; + } + while (!readdir_r(dir, &d, &pd) && pd) { + if (d.d_type == DT_DIR && (!strcmp(d.d_name, ".") || !strcmp(d.d_name, ".."))) + continue; + + l = realloc(l, sizeof(struct tagDirName) * (n + 2)); + if (!l) { + printf("Error:: %s(%d) #%d - %s\n", __func__, __LINE__, errno, strerror(errno)); + closedir(dir); + return -1; + } else + memset(&l[n + 1], 0, sizeof(struct tagDirName)); + + l[n].ch = '<'; + l[n].tag = crcFletcher16((u_short*) d.d_name, d.d_namlen / 2 + d.d_namlen % 2); + l[n].hash = crcAdler((u_char*) d.d_name, d.d_namlen); + strlcpy(l[n].name, d.d_name, MAXPATHLEN); + if (l) { + if (lstat(d.d_name, &sb) != -1) { + memset(szStr, 0, MAX_STR); + strftime(szStr, MAX_STR, "%y-%m-%d %H:%M:%S", localtime(&sb.st_mtim)); + switch (d.d_type) { + case DT_FIFO: + strlcpy(szType, "fifo", MAX_STR); + break; + case DT_CHR: + strlcpy(szType, "char", MAX_STR); + break; + case DT_DIR: + strlcpy(szType, "dir", MAX_STR); + break; + case DT_BLK: + strlcpy(szType, "block", MAX_STR); + break; + case DT_REG: + strlcpy(szType, "file", MAX_STR); + break; + case DT_LNK: + strlcpy(szType, "link", MAX_STR); + break; + case DT_SOCK: + strlcpy(szType, "socket", MAX_STR); + break; + case DT_WHT: + strlcpy(szType, "wht", MAX_STR); + break; + case DT_UNKNOWN: + default: + strlcpy(szType, "unknown", MAX_STR); + break; + } + snprintf(l[n].extra, MAX_STR, "%s links=%d %d:%d perm=0%o size=%llu %s\n", szType, + sb.st_nlink, sb.st_uid, sb.st_gid, sb.st_mode, sb.st_size, szStr); + } + } + + n++; + } + closedir(dir); + qsort(l, n, sizeof(struct tagDirName), (int (*)(const void*, const void*)) func_comp); + for (i = n - 1; i > -1; i--) + tags[l[i].tag] = i; + + // open dir 2 for diff ... + dir = opendir(csDir2); + if (!dir) { + printf("Error:: %s(%d) #%d - %s\n", __func__, __LINE__, errno, strerror(errno)); + free(l); + return -1; + } + while (!readdir_r(dir, &d, &pd) && pd) { + if (d.d_type == DT_DIR && (!strcmp(d.d_name, ".") || !strcmp(d.d_name, ".."))) + continue; + else { + t = crcFletcher16((u_short*) d.d_name, d.d_namlen / 2 + d.d_namlen % 2); + hash = crcAdler((u_char*) d.d_name, d.d_namlen); + } + + // search in index tags + find = NULL; + if (tags[t] != -1 && l[tags[t]].tag == t) { + // search in sorted hashes + for (i = 0; l[tags[t] + i].tag == t; i++) + if (l[tags[t] + i].hash == hash) { + // finded & marked for delete! + find = &l[tags[t] + i]; + find->ch = '*'; + break; + } + } + // element not find in dir1, added + if (!find) { + l = realloc(l, sizeof(struct tagDirName) * (n + 2)); + if (!l) { + printf("Error:: %s(%d) #%d - %s\n", __func__, __LINE__, errno, strerror(errno)); + closedir(dir); + return -1; + } else + memset(&l[n + 1], 0, sizeof(struct tagDirName)); + + l[n].ch = '>'; + l[n].tag = t; + l[n].hash = hash; + strlcpy(l[n].name, d.d_name, MAXPATHLEN); + + n++; + } + } + closedir(dir); + + // delete equal elemets !!! + for (i = cx = 0; i < n; i++) + if (l[i].ch == '*') { + memmove(&l[i], &l[i + 1], (n - i + 1) * sizeof(struct tagDirName)); + cx++; + i--; + } + n -= cx; + + *list = l; + return n; +} + +// ---------------------------------------------------- + +int +main(int argc, char **argv) +{ + u_char *md[2]; + char ch; + struct tagDirName *list; + register int i; + + while ((ch = getopt(argc, argv, "hl")) != -1) + switch (ch) { + case 'l': + l = 1; + break; + case 'h': + default: + Usage(); + return 127; + } + argc -= optind; + argv += optind; + + if (argc < 2) { + Usage(); + return 127; + } + // check for general differences + if (calcDir(argv[0], &md[0]) == -1) + return 127; + if (calcDir(argv[1], &md[1]) == -1) { + free(md[0]); + return 127; + } + if (!memcmp(md[0], md[1], MD5_DIGEST_LENGTH)) { + free(md[0]); + free(md[1]); + printf("Directory %s == %s\n\n", argv[0], argv[1]); + return 0; + } else { + free(md[0]); + free(md[1]); + printf("Directory %s != %s ::\n\n", argv[0], argv[1]); + } + + if (cmpDir(argv[0], argv[1], &list) == -1) + return 127; + + for (i = 0; list[i].ch; i++) + printf("%c %s %s\n", list[i].ch, list[i].name, list[i].extra); + printf("\nTotal count of elements = %d\n", i); + + free(list); + return 1; +}