|
|
| version 1.1.2.5, 2010/07/13 12:38:23 | version 1.1.2.8, 2010/09/20 23:07:11 |
|---|---|
| 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 13 Usage() | Line 19 Usage() |
| "=== %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 ...\n" | "\t-l\t\tLong directory output ...\n" |
| "\t-s\t\tCompare dir from stdin list\n" | |
| "\t-o <filename>\tOutput diff to filename\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; | |
| } | |
| static struct tagDirName * | |
| find_tag(int const * __restrict tags, struct tagDirName const * __restrict l, u_short t, u_int hash) | |
| { | |
| struct tagDirName *find = NULL; | |
| register int i; | |
| // search in index tags | |
| 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 = (struct tagDirName*) &l[tags[t] + i]; | |
| find->ch = '*'; | |
| break; | |
| } | |
| } | |
| return find; | |
| } | |
| 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 szLine[MAX_STR], szStr[MAX_STR], szType[MAX_STR], *str, *pbrk; | |
| FILE *f = stdin; | |
| if (!csDir1 || !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 & 1) { | |
| 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; | |
| // if only 1 dir supplied and output filename is set, goto end | |
| if (lm & 2 && !csDir2) | |
| goto end; | |
| // | |
| if (lm & 4) { | |
| if (strcmp(csDir2, "-")) { | |
| f = fopen(csDir2, "r"); | |
| if (!f) { | |
| printf("Error:: %s(%d) #%d - %s\n", __func__, __LINE__, errno, strerror(errno)); | |
| free(l); | |
| return -1; | |
| } | |
| } | |
| while (fgets(szLine, MAX_STR, f)) { | |
| if (!*szLine || *szLine == '#') | |
| continue; | |
| str = strtok_r(szLine, " \t", &pbrk); | |
| if (!str) | |
| continue; | |
| str = strtok_r(NULL, " \t", &pbrk); | |
| if (!str) | |
| continue; | |
| else { | |
| i = strlen(str); | |
| t = crcFletcher16((u_short*) str, i / 2 + i % 2); | |
| hash = crcAdler((u_char*) str, i); | |
| } | |
| find = find_tag(tags, l, t, hash); | |
| // 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, str, MAXPATHLEN); | |
| if (lm & 1 && (str = strtok_r(NULL, "\r\n", &pbrk))) | |
| strlcpy(l[n].extra, str, MAX_STR); | |
| n++; | |
| } | |
| } | |
| if (strcmp(csDir2, "-")) | |
| fclose(f); | |
| goto delel; | |
| } | |
| //// | |
| // 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); | |
| } | |
| find = find_tag(tags, l, t, hash); | |
| // 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 & 1) { | |
| 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); | |
| delel: | |
| // 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; | |
| end: | |
| *list = l; | |
| return n; | |
| } | |
| // ---------------------------------------------------- | |
| int | |
| main(int argc, char **argv) | main(int argc, char **argv) |
| { | { |
| u_char *md[2] = { NULL, NULL }; | |
| char ch, szFName[MAXPATHLEN]; | char ch, szFName[MAXPATHLEN]; |
| int lm = 0; | |
| struct tagDirName *list; | struct tagDirName *list; |
| register int i; | register int i; |
| FILE *f = stdout; | FILE *f = stdout; |
| struct stat sb; | |
| while ((ch = getopt(argc, argv, "hlo:s")) != -1) | while ((ch = getopt(argc, argv, "hlo:")) != -1) |
| switch (ch) { | switch (ch) { |
| case 'o': | case 'o': |
| lm |= 2; | lm |= 2; |
| strlcpy(szFName, optarg, MAXPATHLEN); | strlcpy(szFName, optarg, MAXPATHLEN); |
| break; | break; |
| case 's': | |
| lm |= 4; | |
| break; | |
| case 'l': | case 'l': |
| lm |= 1; | lm |= 1; |
| break; | break; |
| Line 369 main(int argc, char **argv) | Line 55 main(int argc, char **argv) |
| 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 (argc > 1 && lm < 4) { | printf("Error:: %s(%d) #%d - %s\n", __func__, __LINE__, errno, strerror(errno)); |
| if (calcDir(argv[1], &md[1]) == -1) { | |
| free(md[0]); | |
| return 127; | return 127; |
| } | } |
| if (!memcmp(md[0], md[1], MD5_DIGEST_LENGTH)) { | |
| free(md[0]); | if (S_ISDIR(sb.st_mode)) |
| if (md[1]) | switch (sync_dircmp(argv[0], argv[1])) { |
| free(md[1]); | case -1: |
| printf("Directory %s == %s\n\n", argv[0], argv[1]); | printf("Error:: %s(%d) #%d - %s\n", __func__, __LINE__, errno, strerror(errno)); |
| return 0; | return 127; |
| } else { | case 0: |
| free(md[0]); | printf("Directory %s == %s\n\n", argv[0], argv[1]); |
| if (md[1]) | return 0; |
| free(md[1]); | case 1: |
| printf("Directory %s != %s ::\n\n", argv[0], argv[1]); | printf("Directory %s != %s ::\n\n", argv[0], argv[1]); |
| } | } |
| } | } |
| if (cmpDir(argv[0], argc > 1 ? argv[1] : NULL, &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, "-")) { | if (lm & 2 && strcmp(szFName, "-")) { |
| f = fopen(szFName, "w"); | f = fopen(szFName, "w"); |