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

1.2     ! misho       1: /*************************************************************************
        !             2: * (C) 2010 AITNET ltd - Sofia/Bulgaria - <misho@aitbg.com>
        !             3: *  by Michael Pounov <misho@openbsd-bg.org>
        !             4: *
        !             5: * $Author: misho $
        !             6: * $Id: dir.c,v 1.1.2.6 2011/05/09 14:35:56 misho Exp $
        !             7: *
        !             8: **************************************************************************
        !             9: The ELWIX and AITNET software is distributed under the following
        !            10: terms:
        !            11: 
        !            12: All of the documentation and software included in the ELWIX and AITNET
        !            13: Releases is copyrighted by ELWIX - Sofia/Bulgaria <info@elwix.org>
        !            14: 
        !            15: Copyright 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011
        !            16:        by Michael Pounov <misho@elwix.org>.  All rights reserved.
        !            17: 
        !            18: Redistribution and use in source and binary forms, with or without
        !            19: modification, are permitted provided that the following conditions
        !            20: are met:
        !            21: 1. Redistributions of source code must retain the above copyright
        !            22:    notice, this list of conditions and the following disclaimer.
        !            23: 2. Redistributions in binary form must reproduce the above copyright
        !            24:    notice, this list of conditions and the following disclaimer in the
        !            25:    documentation and/or other materials provided with the distribution.
        !            26: 3. All advertising materials mentioning features or use of this software
        !            27:    must display the following acknowledgement:
        !            28: This product includes software developed by Michael Pounov <misho@elwix.org>
        !            29: ELWIX - Embedded LightWeight unIX and its contributors.
        !            30: 4. Neither the name of AITNET nor the names of its contributors
        !            31:    may be used to endorse or promote products derived from this software
        !            32:    without specific prior written permission.
        !            33: 
        !            34: THIS SOFTWARE IS PROVIDED BY AITNET AND CONTRIBUTORS ``AS IS'' AND
        !            35: ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            36: IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            37: ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            38: FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            39: DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            40: OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            41: HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            42: LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            43: OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            44: SUCH DAMAGE.
        !            45: */
        !            46: #include "global.h"
        !            47: 
        !            48: 
        !            49: static int
        !            50: func_comp(struct tagDirName const *d1, struct tagDirName const *d2)
        !            51: {
        !            52:        return d1->tag - d2->tag;
        !            53: }
        !            54: 
        !            55: static struct tagDirName *
        !            56: find_tag(int const * __restrict tags, struct tagDirName const * __restrict l, u_short t, u_int hash)
        !            57: {
        !            58:        struct tagDirName *find = NULL;
        !            59:        register int i;
        !            60: 
        !            61:        // search in index tags
        !            62:        if (tags[t] != -1 && l[tags[t]].tag == t) {
        !            63:                // search in sorted hashes
        !            64:                for (i = 0; l[tags[t] + i].tag == t; i++)
        !            65:                        if (l[tags[t] + i].hash == hash) {
        !            66:                                // finded & marked for delete!
        !            67:                                find = (struct tagDirName*) &l[tags[t] + i];
        !            68:                                find->ch = '*';
        !            69:                                break;
        !            70:                        }
        !            71:        }
        !            72: 
        !            73:        return find;
        !            74: }
        !            75: 
        !            76: static int *
        !            77: create_tags()
        !            78: {
        !            79:        int *tags;
        !            80: 
        !            81:        tags = calloc(TABLESIZ, sizeof(int));
        !            82:        if (!tags) {
        !            83:                SETERR;
        !            84:        } else
        !            85:                memset(tags, -1, TABLESIZ * sizeof(int));
        !            86: 
        !            87:        return tags;
        !            88: }
        !            89: 
        !            90: static int
        !            91: create_diridx(const char *csDir, int lm, int *tags, struct tagDirName **list)
        !            92: {
        !            93:        struct tagDirName *l = *list;
        !            94:        DIR *dir;
        !            95:        struct dirent d, *pd;
        !            96:        int n;
        !            97:        char szStr[STRSIZ], szType[STRSIZ], *old;
        !            98:        struct stat sb;
        !            99:        register int i;
        !           100: 
        !           101:        l = malloc(sizeof(struct tagDirName));
        !           102:        if (!l) {
        !           103:                SETERR;
        !           104:                *list = NULL;
        !           105:                return -1;
        !           106:        } else {
        !           107:                n = 0;
        !           108:                memset(l, 0, sizeof(struct tagDirName));
        !           109:        }
        !           110: 
        !           111:        old = getcwd(NULL, 0);
        !           112:        if (chdir(csDir) == -1) {
        !           113:                SETERR;
        !           114:                free(old);
        !           115:                free(l);
        !           116:                *list = NULL;
        !           117:                return -1;
        !           118:        }
        !           119:        dir = opendir(".");
        !           120:        if (!dir) {
        !           121:                SETERR;
        !           122:                chdir(old);
        !           123:                free(old);
        !           124:                free(l);
        !           125:                *list = NULL;
        !           126:                return -1;
        !           127:        }
        !           128:        while (!readdir_r(dir, &d, &pd) && pd) {
        !           129:                if (d.d_type == DT_DIR && (!strcmp(d.d_name, ".") || !strcmp(d.d_name, "..")))
        !           130:                        continue;
        !           131: 
        !           132:                l = realloc(l, sizeof(struct tagDirName) * (n + 2));
        !           133:                if (!l) {
        !           134:                        SETERR;
        !           135:                        chdir(old);
        !           136:                        free(old);
        !           137:                        free(l);
        !           138:                        *list = NULL;
        !           139:                        closedir(dir);
        !           140:                        return -1;
        !           141:                } else
        !           142:                        memset(&l[n + 1], 0, sizeof(struct tagDirName));
        !           143: 
        !           144:                l[n].ch = '<';
        !           145:                l[n].tag = crcFletcher16((u_short*) d.d_name, d.d_namlen / 2 + d.d_namlen % 2);
        !           146:                l[n].hash = crcAdler((u_char*) d.d_name, d.d_namlen);
        !           147:                strlcpy(l[n].name, d.d_name, MAXPATHLEN);
        !           148:                if (lm & 1) {
        !           149:                        if (lstat(d.d_name, &sb) != -1) {
        !           150:                                memset(szStr, 0, STRSIZ);
        !           151: #if defined(__OpenBSD__)
        !           152:                                strftime(szStr, STRSIZ, "%Y-%m-%d %H:%M:%S", localtime((time_t*) &sb.st_mtim));
        !           153: #else
        !           154:                                strftime(szStr, STRSIZ, "%Y-%m-%d %H:%M:%S", localtime((time_t*) &sb.st_mtime));
        !           155: #endif
        !           156:                                switch (d.d_type) {
        !           157:                                        case DT_FIFO:
        !           158:                                                strlcpy(szType, "fifo", STRSIZ);
        !           159:                                                break;
        !           160:                                        case DT_CHR:
        !           161:                                                strlcpy(szType, "char", STRSIZ);
        !           162:                                                break;
        !           163:                                        case DT_DIR:
        !           164:                                                strlcpy(szType, "dir", STRSIZ);
        !           165:                                                break;
        !           166:                                        case DT_BLK:
        !           167:                                                strlcpy(szType, "block", STRSIZ);
        !           168:                                                break;
        !           169:                                        case DT_REG:
        !           170:                                                strlcpy(szType, "file", STRSIZ);
        !           171:                                                break;
        !           172:                                        case DT_LNK:
        !           173:                                                strlcpy(szType, "link", STRSIZ);
        !           174:                                                break;
        !           175:                                        case DT_SOCK:
        !           176:                                                strlcpy(szType, "socket", STRSIZ);
        !           177:                                                break;
        !           178: /* OpenBSD does not have this type */
        !           179: #ifdef DT_WHT
        !           180:                                        case DT_WHT:
        !           181:                                                strlcpy(szType, "wht", STRSIZ);
        !           182:                                                break;
        !           183: #endif
        !           184:                                        case DT_UNKNOWN:
        !           185:                                        default:
        !           186:                                                strlcpy(szType, "unknown", STRSIZ);
        !           187:                                                break;
        !           188:                                }
        !           189:                                snprintf(l[n].extra, STRSIZ, "%s links=%d inode=%lu %d:%d perm=0%o size=%ld %s", 
        !           190:                                                szType, sb.st_nlink, sb.st_ino, sb.st_uid, sb.st_gid, 
        !           191:                                                sb.st_mode & 0x1fff, sb.st_size, szStr);
        !           192:                        }
        !           193:                }
        !           194: 
        !           195:                n++;
        !           196:        }
        !           197:        closedir(dir);
        !           198: 
        !           199:        qsort(l, n, sizeof(struct tagDirName), (int (*)(const void*, const void*)) func_comp);
        !           200:        for (i = n - 1; i > -1; i--)
        !           201:                tags[l[i].tag] = i;
        !           202: 
        !           203:        chdir(old);
        !           204:        free(old);
        !           205: 
        !           206:        *list = l;
        !           207:        return n;
        !           208: }
        !           209: 
        !           210: // ------------------------------------------------------
        !           211: 
        !           212: /*
        !           213:  * sync_dirCSum() Calculate checksum of directory
        !           214:  * @csDir = Directory
        !           215:  * @md = Message digest allocated memory, must be free after use!
        !           216:  * return: -1 error or !=-1 ok
        !           217:  */
        !           218: int
        !           219: sync_dirCSum(const char *csDir, u_char **md)
        !           220: {
        !           221:        DIR *dir;
        !           222:        struct dirent d, *pd;
        !           223:        MD5_CTX ctx;
        !           224:        register int ret = 0;
        !           225: 
        !           226:        *md = malloc(MD5_DIGEST_LENGTH);
        !           227:        if (!*md) {
        !           228:                SETERR;
        !           229:                return -1;
        !           230:        } else
        !           231:                memset(*md, 0, MD5_DIGEST_LENGTH);
        !           232: 
        !           233:        dir = opendir(csDir);
        !           234:        if (!dir) {
        !           235:                SETERR;
        !           236:                free(*md);
        !           237:                return -1;
        !           238:        }
        !           239: 
        !           240:        MD5_Init(&ctx);
        !           241:        while (!readdir_r(dir, &d, &pd) && pd) {
        !           242:                if (d.d_type == DT_DIR && (!strcmp(d.d_name, ".") || !strcmp(d.d_name, "..")))
        !           243:                        continue;
        !           244:                MD5_Update(&ctx, d.d_name, d.d_namlen);
        !           245:                ret++;
        !           246:        }
        !           247:        MD5_Final(*md, &ctx);
        !           248: 
        !           249:        closedir(dir);
        !           250:        return ret;
        !           251: }
        !           252: 
        !           253: /*
        !           254:  * sync_dircmp() Compare directories
        !           255:  * @csDir1 = Directory 1
        !           256:  * @csDir2 = Directory 2
        !           257:  * return: -1 error, 0 is equal or 1 different
        !           258:  */
        !           259: int
        !           260: sync_dircmp(const char *csDir1, const char *csDir2)
        !           261: {
        !           262:        u_char *md[2] = { NULL, NULL };
        !           263:        int ret = -1;
        !           264: 
        !           265:        if (!csDir1 || !csDir2)
        !           266:                return ret;
        !           267: 
        !           268:        if (sync_dirCSum(csDir1, &md[0]) == -1)
        !           269:                return ret;
        !           270:        if (sync_dirCSum(csDir2, &md[1]) == -1) {
        !           271:                free(md[0]);
        !           272:                return ret;
        !           273:        }
        !           274: 
        !           275:        if (!memcmp(md[0], md[1], MD5_DIGEST_LENGTH))
        !           276:                ret = 0;
        !           277:        else
        !           278:                ret = 1;
        !           279: 
        !           280:        free(md[1]);
        !           281:        free(md[0]);
        !           282:        return ret;
        !           283: }
        !           284: 
        !           285: /*
        !           286:  * sync_dircmpList() Compare directories or directory and file list
        !           287:  * @csDir1 = Directory 1
        !           288:  * @csDir2 = Directory 2 or File list, if "-" get input from console
        !           289:  * @lm = Long mode options, 1 long output
        !           290:  * @list = Output diff list, after use must be free!
        !           291:  * return: -1 error, 0 is equal or >0 count of returned list items
        !           292:  */
        !           293: int
        !           294: sync_dircmpList(const char *csDir1, const char *csDir2, int lm, struct tagDirName **list)
        !           295: {
        !           296:        struct tagDirName *l, *find;
        !           297:        int n, cx;
        !           298:        DIR *dir;
        !           299:        FILE *f = stdin;
        !           300:        struct dirent d, *pd;
        !           301:        int *tags;
        !           302:        register int i;
        !           303:        u_short t;
        !           304:        u_int hash;
        !           305:        struct stat sb;
        !           306:        char szLine[STRSIZ], szStr[STRSIZ], szType[STRSIZ], *str, *pbrk, *old;
        !           307: 
        !           308:        if (!csDir1 || !list || !(tags = create_tags()))
        !           309:                return -1;
        !           310: 
        !           311:        n = create_diridx(csDir1, lm, tags, &l);
        !           312:        if (n == -1 || !csDir2) {
        !           313:                *list = l;
        !           314:                return n;
        !           315:        }
        !           316: 
        !           317:        if (lstat(csDir2, &sb) == -1) {
        !           318:                SETERR;
        !           319:                free(l);
        !           320:                return -1;
        !           321:        }
        !           322:        if (S_ISDIR(sb.st_mode)) {
        !           323:                old = getcwd(NULL, 0);
        !           324:                if (chdir(csDir2) == -1) {
        !           325:                        SETERR;
        !           326:                        chdir(old);
        !           327:                        free(old);
        !           328:                        free(l);
        !           329:                        return -1;
        !           330:                }
        !           331:                dir = opendir(".");
        !           332:                if (!dir) {
        !           333:                        SETERR;
        !           334:                        chdir(old);
        !           335:                        free(old);
        !           336:                        free(l);
        !           337:                        return -1;
        !           338:                }
        !           339:                while (!readdir_r(dir, &d, &pd) && pd) {
        !           340:                        if (d.d_type == DT_DIR && (!strcmp(d.d_name, ".") || !strcmp(d.d_name, "..")))
        !           341:                                continue;
        !           342:                        else {
        !           343:                                t = crcFletcher16((u_short*) d.d_name, d.d_namlen / 2 + d.d_namlen % 2);
        !           344:                                hash = crcAdler((u_char*) d.d_name, d.d_namlen);
        !           345:                        }
        !           346: 
        !           347:                        find = find_tag(tags, l, t, hash);
        !           348:                        // element not find in dir1, added
        !           349:                        if (!find) {
        !           350:                                l = realloc(l, sizeof(struct tagDirName) * (n + 2));
        !           351:                                if (!l) {
        !           352:                                        SETERR;
        !           353:                                        chdir(old);
        !           354:                                        free(old);
        !           355:                                        closedir(dir);
        !           356:                                        return -1;
        !           357:                                } else
        !           358:                                        memset(&l[n + 1], 0, sizeof(struct tagDirName));
        !           359: 
        !           360:                                l[n].ch = '>';
        !           361:                                l[n].tag = t;
        !           362:                                l[n].hash = hash;
        !           363:                                strlcpy(l[n].name, d.d_name, MAXPATHLEN);
        !           364:                                if (lm & 1) {
        !           365:                                        if (lstat(d.d_name, &sb) != -1) {
        !           366:                                                memset(szStr, 0, STRSIZ);
        !           367: #if defined(__OpenBSD__)
        !           368:                                                strftime(szStr, STRSIZ, "%Y-%m-%d %H:%M:%S", 
        !           369:                                                                localtime((time_t*) &sb.st_mtim));
        !           370: #else
        !           371:                                                strftime(szStr, STRSIZ, "%Y-%m-%d %H:%M:%S", 
        !           372:                                                                localtime((time_t*) &sb.st_mtime));
        !           373: #endif
        !           374:                                                switch (d.d_type) {
        !           375:                                                        case DT_FIFO:
        !           376:                                                                strlcpy(szType, "fifo", STRSIZ);
        !           377:                                                                break;
        !           378:                                                        case DT_CHR:
        !           379:                                                                strlcpy(szType, "char", STRSIZ);
        !           380:                                                                break;
        !           381:                                                        case DT_DIR:
        !           382:                                                                strlcpy(szType, "dir", STRSIZ);
        !           383:                                                                break;
        !           384:                                                        case DT_BLK:
        !           385:                                                                strlcpy(szType, "block", STRSIZ);
        !           386:                                                                break;
        !           387:                                                        case DT_REG:
        !           388:                                                                strlcpy(szType, "file", STRSIZ);
        !           389:                                                                break;
        !           390:                                                        case DT_LNK:
        !           391:                                                                strlcpy(szType, "link", STRSIZ);
        !           392:                                                                break;
        !           393:                                                        case DT_SOCK:
        !           394:                                                                strlcpy(szType, "socket", STRSIZ);
        !           395:                                                                break;
        !           396: /* OpenBSD does not have this type */
        !           397: #ifdef DT_WHT
        !           398:                                                        case DT_WHT:
        !           399:                                                                strlcpy(szType, "wht", STRSIZ);
        !           400:                                                                break;
        !           401: #endif
        !           402:                                                        case DT_UNKNOWN:
        !           403:                                                        default:
        !           404:                                                                strlcpy(szType, "unknown", STRSIZ);
        !           405:                                                                break;
        !           406:                                                }
        !           407:                                                snprintf(l[n].extra, STRSIZ, 
        !           408:                                                                "%s links=%d inode=%lu %d:%d perm=0%o size=%ld %s", 
        !           409:                                                                szType, sb.st_nlink, sb.st_ino, sb.st_uid, sb.st_gid, 
        !           410:                                                                sb.st_mode & 0x1fff, sb.st_size, szStr);
        !           411:                                        }
        !           412:                                }
        !           413: 
        !           414:                                n++;
        !           415:                        }
        !           416:                }
        !           417:                closedir(dir);
        !           418:                chdir(old);
        !           419:                free(old);
        !           420:        } else {
        !           421:                if (strcmp(csDir2, "-")) {
        !           422:                        f = fopen(csDir2, "r");
        !           423:                        if (!f) {
        !           424:                                SETERR;
        !           425:                                free(l);
        !           426:                                return -1;
        !           427:                        }
        !           428:                }
        !           429:                while (fgets(szLine, STRSIZ, f)) {
        !           430:                        if (!*szLine || *szLine == '#')
        !           431:                                continue;
        !           432: 
        !           433:                        str = strtok_r(szLine, " \t", &pbrk);
        !           434:                        if (!str)
        !           435:                                continue;
        !           436:                        str = strtok_r(NULL, " \t", &pbrk);
        !           437:                        if (!str)
        !           438:                                continue;
        !           439:                        else {
        !           440:                                i = strlen(str);
        !           441:                                t = crcFletcher16((u_short*) str, i / 2 + i % 2);
        !           442:                                hash = crcAdler((u_char*) str, i);
        !           443:                        }
        !           444: 
        !           445:                        find = find_tag(tags, l, t, hash);
        !           446:                        // element not find in dir1, added
        !           447:                        if (!find) {
        !           448:                                l = realloc(l, sizeof(struct tagDirName) * (n + 2));
        !           449:                                if (!l) {
        !           450:                                        SETERR;
        !           451:                                        if (strcmp(csDir2, "-"))
        !           452:                                                fclose(f);
        !           453:                                        return -1;
        !           454:                                } else
        !           455:                                        memset(&l[n + 1], 0, sizeof(struct tagDirName));
        !           456: 
        !           457:                                l[n].ch = '>';
        !           458:                                l[n].tag = t;
        !           459:                                l[n].hash = hash;
        !           460:                                strlcpy(l[n].name, str, MAXPATHLEN);
        !           461:                                if (lm & 1 && (str = strtok_r(NULL, "\r\n", &pbrk)))
        !           462:                                        strlcpy(l[n].extra, str, STRSIZ);
        !           463: 
        !           464:                                n++;
        !           465:                        }
        !           466:                }
        !           467:                if (strcmp(csDir2, "-"))
        !           468:                        fclose(f);
        !           469:        }
        !           470: 
        !           471:        // delete equal elemets !!!
        !           472:        for (i = cx = 0; i < n; i++)
        !           473:                if (l[i].ch == '*') {
        !           474:                        memmove(&l[i], &l[i + 1], (n - i + 1) * sizeof(struct tagDirName));
        !           475:                        cx++;
        !           476:                        i--;
        !           477:                }
        !           478:        n -= cx;
        !           479: 
        !           480:        *list = l;
        !           481:        return n;
        !           482: }

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