|
|
| version 1.1.2.3, 2010/07/13 11:22:36 | version 1.2, 2011/06/08 12:45:41 |
|---|---|
| Line 1 | Line 1 |
| /************************************************************************* | |
| * (C) 2010 AITNET - Sofia/Bulgaria - <office@aitbg.com> | |
| * by Michael Pounov <misho@aitbg.com> | |
| * | |
| * $Author$ | |
| * $Id$ | |
| * | |
| *************************************************************************/ | |
| #include "global.h" | #include "global.h" |
| #include "dircmp.h" | |
| extern char compiled[], compiledby[], compilehost[]; | extern char compiled[], compiledby[], compilehost[]; |
| char lm; | |
| static void | static void |
| Line 11 Usage() | Line 17 Usage() |
| { | { |
| printf( "-= DirCmp =- Tool for compare directories and show differences\n" | printf( "-= DirCmp =- Tool for compare directories and show differences\n" |
| "=== %s === %s@%s ===\n\n" | "=== %s === %s@%s ===\n\n" |
| " Syntax: dircmp [options] <dir> <cmp_dir>\n\n" | " Syntax: dircmp [options] <dir> [<cmp_dir>]\n\n" |
| "\t-l\t\tLong directory output ..." | "\t-l\t\tLong directory output ...\n" |
| "\t-o <filename>\tOutput diff to filename\n" | |
| "\n", compiled, compiledby, compilehost); | "\n", compiled, compiledby, compilehost); |
| } | } |
| int | 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)); | |
| } | |
| if (chdir(csDir1) == -1) { | |
| printf("Error:: %s(%d) #%d - %s\n", __func__, __LINE__, errno, strerror(errno)); | |
| free(l); | |
| return -1; | |
| } | |
| dir = opendir("."); | |
| 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 (lm) { | |
| if (lstat(d.d_name, &sb) != -1) { | |
| memset(szStr, 0, MAX_STR); | |
| strftime(szStr, MAX_STR, "%Y-%m-%d %H:%M:%S", localtime((time_t*) &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 inode=%u %d:%d perm=0%o size=%llu %s", | |
| szType, sb.st_nlink, sb.st_ino, sb.st_uid, sb.st_gid, | |
| sb.st_mode & 0x1fff, 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 ... | |
| if (chdir(csDir2) == -1) { | |
| printf("Error:: %s(%d) #%d - %s\n", __func__, __LINE__, errno, strerror(errno)); | |
| free(l); | |
| return -1; | |
| } | |
| dir = opendir("."); | |
| 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); | |
| if (lm) { | |
| if (lstat(d.d_name, &sb) != -1) { | |
| memset(szStr, 0, MAX_STR); | |
| strftime(szStr, MAX_STR, "%Y-%m-%d %H:%M:%S", localtime((time_t*) &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 inode=%u %d:%d perm=0%o size=%llu %s", | |
| szType, sb.st_nlink, sb.st_ino, sb.st_uid, sb.st_gid, | |
| sb.st_mode & 0x1fff, sb.st_size, szStr); | |
| } | |
| } | |
| 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) | main(int argc, char **argv) |
| { | { |
| u_char *md[2]; | char ch, szFName[MAXPATHLEN]; |
| char ch; | int lm = 0; |
| struct tagDirName *list; | struct tagDirName *list; |
| register int i; | register int i; |
| FILE *f = stdout; | |
| struct stat sb; | |
| while ((ch = getopt(argc, argv, "hl")) != -1) | while ((ch = getopt(argc, argv, "hlo:")) != -1) |
| switch (ch) { | switch (ch) { |
| case 'o': | |
| lm |= 2; | |
| strlcpy(szFName, optarg, MAXPATHLEN); | |
| break; | |
| case 'l': | case 'l': |
| lm = 1; | lm |= 1; |
| break; | break; |
| case 'h': | case 'h': |
| default: | default: |
| Line 286 main(int argc, char **argv) | Line 50 main(int argc, char **argv) |
| argc -= optind; | argc -= optind; |
| argv += optind; | argv += optind; |
| if (argc < 2) { | if (!argc || (!(lm & 2) && argc < 2)) { |
| Usage(); | Usage(); |
| return 127; | return 127; |
| } | } |
| // check for general differences | // check for general differences |
| if (calcDir(argv[0], &md[0]) == -1) | if (argc > 1) { |
| return 127; | if (lstat(argv[1], &sb) == -1) { |
| if (calcDir(argv[1], &md[1]) == -1) { | printf("Error:: %s(%d) #%d - %s\n", __func__, __LINE__, errno, strerror(errno)); |
| free(md[0]); | return 127; |
| return 127; | } |
| if (S_ISDIR(sb.st_mode)) | |
| switch (sync_dircmp(argv[0], argv[1])) { | |
| case -1: | |
| printf("Error:: %s(%d) #%d - %s\n", __func__, __LINE__, errno, strerror(errno)); | |
| return 127; | |
| case 0: | |
| printf("Directory %s == %s\n\n", argv[0], argv[1]); | |
| return 0; | |
| case 1: | |
| printf("Directory %s != %s ::\n\n", argv[0], argv[1]); | |
| } | |
| } | } |
| 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) | if (sync_dircmpList(argv[0], argc > 1 ? argv[1] : NULL, lm, &list) == -1) { |
| printf("Error:: %s(%d) #%d - %s\n", __func__, __LINE__, sync_GetErrno(), sync_GetError()); | |
| return 127; | return 127; |
| } | |
| if (lm & 2 && strcmp(szFName, "-")) { | |
| f = fopen(szFName, "w"); | |
| if (!f) { | |
| printf("Error:: %s(%d) #%d - %s\n", __func__, __LINE__, errno, strerror(errno)); | |
| if (list) | |
| free(list); | |
| return 0; | |
| } | |
| } | |
| for (i = 0; list[i].ch; i++) | for (i = 0; list[i].ch; i++) |
| printf("%c %s %s\n", list[i].ch, list[i].name, list[i].extra); | fprintf(f, "%c %s %s\n", list[i].ch, list[i].name, list[i].extra); |
| printf("\nTotal count of elements = %d\n", i); | if (lm & 2) |
| fclose(f); | |
| printf("\nTotal count of elements = %d\n", i); | |
| free(list); | free(list); |
| return 1; | return 1; |
| } | } |