Annotation of libaitsync/src/dir.c, revision 1.1.2.4

1.1.2.1   misho       1: /*************************************************************************
                      2: * (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
                      3: *  by Michael Pounov <misho@openbsd-bg.org>
                      4: *
                      5: * $Author: misho $
1.1.2.4 ! misho       6: * $Id: dir.c,v 1.1.2.3 2011/03/16 17:17:44 misho Exp $
1.1.2.1   misho       7: *
                      8: *************************************************************************/
                      9: #include "global.h"
                     10: 
                     11: 
                     12: static int
                     13: func_comp(struct tagDirName const *d1, struct tagDirName const *d2)
                     14: {
                     15:        return d1->tag - d2->tag;
                     16: }
                     17: 
                     18: static struct tagDirName *
                     19: find_tag(int const * __restrict tags, struct tagDirName const * __restrict l, u_short t, u_int hash)
                     20: {
                     21:        struct tagDirName *find = NULL;
                     22:        register int i;
                     23: 
                     24:        // search in index tags
                     25:        if (tags[t] != -1 && l[tags[t]].tag == t) {
                     26:                // search in sorted hashes
                     27:                for (i = 0; l[tags[t] + i].tag == t; i++)
                     28:                        if (l[tags[t] + i].hash == hash) {
                     29:                                // finded & marked for delete!
                     30:                                find = (struct tagDirName*) &l[tags[t] + i];
                     31:                                find->ch = '*';
                     32:                                break;
                     33:                        }
                     34:        }
                     35: 
                     36:        return find;
                     37: }
                     38: 
                     39: static int *
                     40: create_tags()
                     41: {
                     42:        int *tags;
                     43: 
                     44:        tags = calloc(TABLESIZ, sizeof(int));
                     45:        if (!tags) {
                     46:                SETERR;
                     47:        } else
                     48:                memset(tags, -1, TABLESIZ * sizeof(int));
                     49: 
                     50:        return tags;
                     51: }
                     52: 
                     53: static int
                     54: create_diridx(const char *csDir, int lm, int *tags, struct tagDirName **list)
                     55: {
                     56:        struct tagDirName *l = *list;
                     57:        DIR *dir;
                     58:        struct dirent d, *pd;
                     59:        int n;
1.1.2.2   misho      60:        char szStr[STRSIZ], szType[STRSIZ], *old;
1.1.2.1   misho      61:        struct stat sb;
                     62:        register int i;
                     63: 
                     64:        l = malloc(sizeof(struct tagDirName));
                     65:        if (!l) {
                     66:                SETERR;
                     67:                *list = NULL;
                     68:                return -1;
                     69:        } else {
                     70:                n = 0;
                     71:                memset(l, 0, sizeof(struct tagDirName));
                     72:        }
                     73: 
1.1.2.2   misho      74:        old = getcwd(NULL, 0);
1.1.2.1   misho      75:        if (chdir(csDir) == -1) {
                     76:                SETERR;
1.1.2.2   misho      77:                free(old);
1.1.2.1   misho      78:                free(l);
                     79:                *list = NULL;
                     80:                return -1;
                     81:        }
                     82:        dir = opendir(".");
                     83:        if (!dir) {
                     84:                SETERR;
1.1.2.2   misho      85:                chdir(old);
                     86:                free(old);
1.1.2.1   misho      87:                free(l);
                     88:                *list = NULL;
                     89:                return -1;
                     90:        }
                     91:        while (!readdir_r(dir, &d, &pd) && pd) {
                     92:                if (d.d_type == DT_DIR && (!strcmp(d.d_name, ".") || !strcmp(d.d_name, "..")))
                     93:                        continue;
                     94: 
                     95:                l = realloc(l, sizeof(struct tagDirName) * (n + 2));
                     96:                if (!l) {
                     97:                        SETERR;
1.1.2.2   misho      98:                        chdir(old);
                     99:                        free(old);
1.1.2.1   misho     100:                        free(l);
                    101:                        *list = NULL;
                    102:                        closedir(dir);
                    103:                        return -1;
                    104:                } else
                    105:                        memset(&l[n + 1], 0, sizeof(struct tagDirName));
                    106: 
                    107:                l[n].ch = '<';
                    108:                l[n].tag = crcFletcher16((u_short*) d.d_name, d.d_namlen / 2 + d.d_namlen % 2);
                    109:                l[n].hash = crcAdler((u_char*) d.d_name, d.d_namlen);
                    110:                strlcpy(l[n].name, d.d_name, MAXPATHLEN);
                    111:                if (lm & 1) {
                    112:                        if (lstat(d.d_name, &sb) != -1) {
                    113:                                memset(szStr, 0, STRSIZ);
1.1.2.4 ! misho     114: #if defined(__OpenBSD__)
1.1.2.1   misho     115:                                strftime(szStr, STRSIZ, "%Y-%m-%d %H:%M:%S", localtime((time_t*) &sb.st_mtim));
1.1.2.4 ! misho     116: #else
        !           117:                                strftime(szStr, STRSIZ, "%Y-%m-%d %H:%M:%S", localtime((time_t*) &sb.st_mtime));
        !           118: #endif
1.1.2.1   misho     119:                                switch (d.d_type) {
                    120:                                        case DT_FIFO:
                    121:                                                strlcpy(szType, "fifo", STRSIZ);
                    122:                                                break;
                    123:                                        case DT_CHR:
                    124:                                                strlcpy(szType, "char", STRSIZ);
                    125:                                                break;
                    126:                                        case DT_DIR:
                    127:                                                strlcpy(szType, "dir", STRSIZ);
                    128:                                                break;
                    129:                                        case DT_BLK:
                    130:                                                strlcpy(szType, "block", STRSIZ);
                    131:                                                break;
                    132:                                        case DT_REG:
                    133:                                                strlcpy(szType, "file", STRSIZ);
                    134:                                                break;
                    135:                                        case DT_LNK:
                    136:                                                strlcpy(szType, "link", STRSIZ);
                    137:                                                break;
                    138:                                        case DT_SOCK:
                    139:                                                strlcpy(szType, "socket", STRSIZ);
                    140:                                                break;
1.1.2.3   misho     141: /* OpenBSD does not have this type */
                    142: #ifdef DT_WHT
1.1.2.1   misho     143:                                        case DT_WHT:
                    144:                                                strlcpy(szType, "wht", STRSIZ);
                    145:                                                break;
1.1.2.3   misho     146: #endif
1.1.2.1   misho     147:                                        case DT_UNKNOWN:
                    148:                                        default:
                    149:                                                strlcpy(szType, "unknown", STRSIZ);
                    150:                                                break;
                    151:                                }
                    152:                                snprintf(l[n].extra, STRSIZ, "%s links=%d inode=%u %d:%d perm=0%o size=%llu %s", 
                    153:                                                szType, sb.st_nlink, sb.st_ino, sb.st_uid, sb.st_gid, 
                    154:                                                sb.st_mode & 0x1fff, sb.st_size, szStr);
                    155:                        }
                    156:                }
                    157: 
                    158:                n++;
                    159:        }
                    160:        closedir(dir);
                    161: 
                    162:        qsort(l, n, sizeof(struct tagDirName), (int (*)(const void*, const void*)) func_comp);
                    163:        for (i = n - 1; i > -1; i--)
                    164:                tags[l[i].tag] = i;
                    165: 
1.1.2.2   misho     166:        chdir(old);
                    167:        free(old);
                    168: 
1.1.2.1   misho     169:        *list = l;
                    170:        return n;
                    171: }
                    172: 
                    173: // ------------------------------------------------------
                    174: 
                    175: /*
                    176:  * sync_dirCSum() Calculate checksum of directory
                    177:  * @csDir = Directory
                    178:  * @md = Message digest allocated memory, must be free after use!
                    179:  * return: -1 error or !=-1 ok
                    180:  */
                    181: int
                    182: sync_dirCSum(const char *csDir, u_char **md)
                    183: {
                    184:        DIR *dir;
                    185:        struct dirent d, *pd;
                    186:        MD5_CTX ctx;
                    187:        register int ret = 0;
                    188: 
                    189:        *md = malloc(MD5_DIGEST_LENGTH);
                    190:        if (!*md) {
                    191:                SETERR;
                    192:                return -1;
                    193:        } else
                    194:                memset(*md, 0, MD5_DIGEST_LENGTH);
                    195: 
                    196:        dir = opendir(csDir);
                    197:        if (!dir) {
                    198:                SETERR;
                    199:                free(*md);
                    200:                return -1;
                    201:        }
                    202: 
                    203:        MD5_Init(&ctx);
                    204:        while (!readdir_r(dir, &d, &pd) && pd) {
                    205:                if (d.d_type == DT_DIR && (!strcmp(d.d_name, ".") || !strcmp(d.d_name, "..")))
                    206:                        continue;
                    207:                MD5_Update(&ctx, d.d_name, d.d_namlen);
                    208:                ret++;
                    209:        }
                    210:        MD5_Final(*md, &ctx);
                    211: 
                    212:        closedir(dir);
                    213:        return ret;
                    214: }
                    215: 
                    216: /*
                    217:  * sync_dircmp() Compare directories
                    218:  * @csDir1 = Directory 1
                    219:  * @csDir2 = Directory 2
                    220:  * return: -1 error, 0 is equal or 1 different
                    221:  */
                    222: int
                    223: sync_dircmp(const char *csDir1, const char *csDir2)
                    224: {
                    225:        u_char *md[2] = { NULL, NULL };
                    226:        int ret = -1;
                    227: 
                    228:        if (!csDir1 || !csDir2)
                    229:                return ret;
                    230: 
                    231:        if (sync_dirCSum(csDir1, &md[0]) == -1)
                    232:                return ret;
                    233:        if (sync_dirCSum(csDir2, &md[1]) == -1) {
                    234:                free(md[0]);
                    235:                return ret;
                    236:        }
                    237: 
                    238:        if (!memcmp(md[0], md[1], MD5_DIGEST_LENGTH))
                    239:                ret = 0;
                    240:        else
                    241:                ret = 1;
                    242: 
                    243:        free(md[1]);
                    244:        free(md[0]);
                    245:        return ret;
                    246: }
                    247: 
                    248: /*
                    249:  * sync_dircmpList() Compare directories or directory and file list
                    250:  * @csDir1 = Directory 1
                    251:  * @csDir2 = Directory 2 or File list, if "-" get input from console
                    252:  * @lm = Long mode options, 1 long output
                    253:  * @list = Output diff list, after use must be free!
                    254:  * return: -1 error, 0 is equal or >0 count of returned list items
                    255:  */
                    256: int
                    257: sync_dircmpList(const char *csDir1, const char *csDir2, int lm, struct tagDirName **list)
                    258: {
                    259:        struct tagDirName *l, *find;
                    260:        int n, cx;
                    261:        DIR *dir;
                    262:        FILE *f = stdin;
                    263:        struct dirent d, *pd;
                    264:        int *tags;
                    265:        register int i;
                    266:        u_short t;
                    267:        u_int hash;
                    268:        struct stat sb;
1.1.2.2   misho     269:        char szLine[STRSIZ], szStr[STRSIZ], szType[STRSIZ], *str, *pbrk, *old;
1.1.2.1   misho     270: 
                    271:        if (!csDir1 || !list || !(tags = create_tags()))
                    272:                return -1;
                    273: 
                    274:        n = create_diridx(csDir1, lm, tags, &l);
                    275:        if (n == -1 || !csDir2) {
                    276:                *list = l;
                    277:                return n;
                    278:        }
                    279: 
1.1.2.2   misho     280:        if (lstat(csDir2, &sb) == -1) {
                    281:                SETERR;
                    282:                free(l);
                    283:                return -1;
                    284:        }
                    285:        if (S_ISDIR(sb.st_mode)) {
                    286:                old = getcwd(NULL, 0);
1.1.2.1   misho     287:                if (chdir(csDir2) == -1) {
                    288:                        SETERR;
1.1.2.2   misho     289:                        chdir(old);
                    290:                        free(old);
1.1.2.1   misho     291:                        free(l);
                    292:                        return -1;
                    293:                }
                    294:                dir = opendir(".");
                    295:                if (!dir) {
                    296:                        SETERR;
1.1.2.2   misho     297:                        chdir(old);
                    298:                        free(old);
1.1.2.1   misho     299:                        free(l);
                    300:                        return -1;
                    301:                }
                    302:                while (!readdir_r(dir, &d, &pd) && pd) {
                    303:                        if (d.d_type == DT_DIR && (!strcmp(d.d_name, ".") || !strcmp(d.d_name, "..")))
                    304:                                continue;
                    305:                        else {
                    306:                                t = crcFletcher16((u_short*) d.d_name, d.d_namlen / 2 + d.d_namlen % 2);
                    307:                                hash = crcAdler((u_char*) d.d_name, d.d_namlen);
                    308:                        }
                    309: 
                    310:                        find = find_tag(tags, l, t, hash);
                    311:                        // element not find in dir1, added
                    312:                        if (!find) {
                    313:                                l = realloc(l, sizeof(struct tagDirName) * (n + 2));
                    314:                                if (!l) {
                    315:                                        SETERR;
1.1.2.2   misho     316:                                        chdir(old);
                    317:                                        free(old);
1.1.2.1   misho     318:                                        closedir(dir);
                    319:                                        return -1;
                    320:                                } else
                    321:                                        memset(&l[n + 1], 0, sizeof(struct tagDirName));
                    322: 
                    323:                                l[n].ch = '>';
                    324:                                l[n].tag = t;
                    325:                                l[n].hash = hash;
                    326:                                strlcpy(l[n].name, d.d_name, MAXPATHLEN);
                    327:                                if (lm & 1) {
                    328:                                        if (lstat(d.d_name, &sb) != -1) {
                    329:                                                memset(szStr, 0, STRSIZ);
1.1.2.4 ! misho     330: #if defined(__OpenBSD__)
1.1.2.1   misho     331:                                                strftime(szStr, STRSIZ, "%Y-%m-%d %H:%M:%S", 
                    332:                                                                localtime((time_t*) &sb.st_mtim));
1.1.2.4 ! misho     333: #else
        !           334:                                                strftime(szStr, STRSIZ, "%Y-%m-%d %H:%M:%S", 
        !           335:                                                                localtime((time_t*) &sb.st_mtime));
        !           336: #endif
1.1.2.1   misho     337:                                                switch (d.d_type) {
                    338:                                                        case DT_FIFO:
                    339:                                                                strlcpy(szType, "fifo", STRSIZ);
                    340:                                                                break;
                    341:                                                        case DT_CHR:
                    342:                                                                strlcpy(szType, "char", STRSIZ);
                    343:                                                                break;
                    344:                                                        case DT_DIR:
                    345:                                                                strlcpy(szType, "dir", STRSIZ);
                    346:                                                                break;
                    347:                                                        case DT_BLK:
                    348:                                                                strlcpy(szType, "block", STRSIZ);
                    349:                                                                break;
                    350:                                                        case DT_REG:
                    351:                                                                strlcpy(szType, "file", STRSIZ);
                    352:                                                                break;
                    353:                                                        case DT_LNK:
                    354:                                                                strlcpy(szType, "link", STRSIZ);
                    355:                                                                break;
                    356:                                                        case DT_SOCK:
                    357:                                                                strlcpy(szType, "socket", STRSIZ);
                    358:                                                                break;
1.1.2.3   misho     359: /* OpenBSD does not have this type */
                    360: #ifdef DT_WHT
1.1.2.1   misho     361:                                                        case DT_WHT:
                    362:                                                                strlcpy(szType, "wht", STRSIZ);
                    363:                                                                break;
1.1.2.3   misho     364: #endif
1.1.2.1   misho     365:                                                        case DT_UNKNOWN:
                    366:                                                        default:
                    367:                                                                strlcpy(szType, "unknown", STRSIZ);
                    368:                                                                break;
                    369:                                                }
                    370:                                                snprintf(l[n].extra, STRSIZ, 
                    371:                                                                "%s links=%d inode=%u %d:%d perm=0%o size=%llu %s", 
                    372:                                                                szType, sb.st_nlink, sb.st_ino, sb.st_uid, sb.st_gid, 
                    373:                                                                sb.st_mode & 0x1fff, sb.st_size, szStr);
                    374:                                        }
                    375:                                }
                    376: 
                    377:                                n++;
                    378:                        }
                    379:                }
                    380:                closedir(dir);
1.1.2.2   misho     381:                chdir(old);
                    382:                free(old);
1.1.2.1   misho     383:        } else {
                    384:                if (strcmp(csDir2, "-")) {
                    385:                        f = fopen(csDir2, "r");
                    386:                        if (!f) {
                    387:                                SETERR;
                    388:                                free(l);
                    389:                                return -1;
                    390:                        }
                    391:                }
                    392:                while (fgets(szLine, STRSIZ, f)) {
                    393:                        if (!*szLine || *szLine == '#')
                    394:                                continue;
                    395: 
                    396:                        str = strtok_r(szLine, " \t", &pbrk);
                    397:                        if (!str)
                    398:                                continue;
                    399:                        str = strtok_r(NULL, " \t", &pbrk);
                    400:                        if (!str)
                    401:                                continue;
                    402:                        else {
                    403:                                i = strlen(str);
                    404:                                t = crcFletcher16((u_short*) str, i / 2 + i % 2);
                    405:                                hash = crcAdler((u_char*) str, i);
                    406:                        }
                    407: 
                    408:                        find = find_tag(tags, l, t, hash);
                    409:                        // element not find in dir1, added
                    410:                        if (!find) {
                    411:                                l = realloc(l, sizeof(struct tagDirName) * (n + 2));
                    412:                                if (!l) {
                    413:                                        SETERR;
                    414:                                        if (strcmp(csDir2, "-"))
                    415:                                                fclose(f);
                    416:                                        return -1;
                    417:                                } else
                    418:                                        memset(&l[n + 1], 0, sizeof(struct tagDirName));
                    419: 
                    420:                                l[n].ch = '>';
                    421:                                l[n].tag = t;
                    422:                                l[n].hash = hash;
                    423:                                strlcpy(l[n].name, str, MAXPATHLEN);
                    424:                                if (lm & 1 && (str = strtok_r(NULL, "\r\n", &pbrk)))
                    425:                                        strlcpy(l[n].extra, str, STRSIZ);
                    426: 
                    427:                                n++;
                    428:                        }
                    429:                }
                    430:                if (strcmp(csDir2, "-"))
                    431:                        fclose(f);
                    432:        }
                    433: 
                    434:        // delete equal elemets !!!
                    435:        for (i = cx = 0; i < n; i++)
                    436:                if (l[i].ch == '*') {
                    437:                        memmove(&l[i], &l[i + 1], (n - i + 1) * sizeof(struct tagDirName));
                    438:                        cx++;
                    439:                        i--;
                    440:                }
                    441:        n -= cx;
                    442: 
                    443:        *list = l;
                    444:        return n;
                    445: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>