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

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 $
1.5.4.1 ! misho       6: * $Id: dir.c,v 1.5 2014/02/04 16:58:17 misho Exp $
1.2       misho       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: 
1.5.4.1 ! misho      15: Copyright 2004 - 2016
1.2       misho      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: 
1.4       misho      61:        /* search in index tags */
1.2       misho      62:        if (tags[t] != -1 && l[tags[t]].tag == t) {
1.4       misho      63:                /* search in sorted hashes */
1.2       misho      64:                for (i = 0; l[tags[t] + i].tag == t; i++)
                     65:                        if (l[tags[t] + i].hash == hash) {
1.4       misho      66:                                /* finded & marked for delete! */
1.2       misho      67:                                find = (struct tagDirName*) &l[tags[t] + i];
1.4       misho      68:                                find->ch = DIFF_D0;
1.2       misho      69:                                break;
                     70:                        }
                     71:        }
                     72: 
                     73:        return find;
                     74: }
                     75: 
                     76: static int *
                     77: create_tags()
                     78: {
                     79:        int *tags;
                     80: 
1.5       misho      81:        tags = e_calloc(TABLESIZ, sizeof(int));
1.2       misho      82:        if (!tags) {
1.4       misho      83:                LOGERR;
1.2       misho      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: 
1.5       misho     101:        l = e_malloc(sizeof(struct tagDirName));
1.2       misho     102:        if (!l) {
1.4       misho     103:                LOGERR;
1.2       misho     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) {
1.4       misho     113:                LOGERR;
1.5       misho     114:                e_free(old);
                    115:                e_free(l);
1.2       misho     116:                *list = NULL;
                    117:                return -1;
                    118:        }
                    119:        dir = opendir(".");
                    120:        if (!dir) {
1.4       misho     121:                LOGERR;
1.2       misho     122:                chdir(old);
1.5       misho     123:                e_free(old);
                    124:                e_free(l);
1.2       misho     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: 
1.5       misho     132:                l = e_realloc(l, sizeof(struct tagDirName) * (n + 2));
1.2       misho     133:                if (!l) {
1.4       misho     134:                        LOGERR;
1.2       misho     135:                        chdir(old);
1.5       misho     136:                        e_free(old);
                    137:                        e_free(l);
1.2       misho     138:                        *list = NULL;
                    139:                        closedir(dir);
                    140:                        return -1;
                    141:                } else
                    142:                        memset(&l[n + 1], 0, sizeof(struct tagDirName));
                    143: 
1.4       misho     144:                l[n].ch = DIFF_D1;
1.5.4.1 ! misho     145: #ifndef __linux__
1.4       misho     146:                l[n].tag = crcFletcher16((u_short*) d.d_name, 
                    147:                                d.d_namlen / 2 + d.d_namlen % 2);
1.2       misho     148:                l[n].hash = crcAdler((u_char*) d.d_name, d.d_namlen);
1.5.4.1 ! misho     149: #else
        !           150:                l[n].tag = crcFletcher16((u_short*) d.d_name, 
        !           151:                                strlen(d.d_name) / 2 + strlen(d.d_name) % 2);
        !           152:                l[n].hash = crcAdler((u_char*) d.d_name, strlen(d.d_name));
        !           153: #endif
1.4       misho     154:                strlcpy(l[n].name, d.d_name, sizeof l[n].name);
1.2       misho     155:                if (lm & 1) {
                    156:                        if (lstat(d.d_name, &sb) != -1) {
1.4       misho     157:                                memset(szStr, 0, sizeof szStr);
1.2       misho     158: #if defined(__OpenBSD__)
1.4       misho     159:                                strftime(szStr, sizeof szStr, "%Y-%m-%d %H:%M:%S", 
                    160:                                                localtime((time_t*) &sb.st_mtim));
1.2       misho     161: #else
1.4       misho     162:                                strftime(szStr, sizeof szStr, "%Y-%m-%d %H:%M:%S", 
                    163:                                                localtime((time_t*) &sb.st_mtime));
1.2       misho     164: #endif
                    165:                                switch (d.d_type) {
                    166:                                        case DT_FIFO:
1.4       misho     167:                                                strlcpy(szType, "fifo", sizeof szType);
1.2       misho     168:                                                break;
                    169:                                        case DT_CHR:
1.4       misho     170:                                                strlcpy(szType, "char", sizeof szType);
1.2       misho     171:                                                break;
                    172:                                        case DT_DIR:
1.4       misho     173:                                                strlcpy(szType, "dir", sizeof szType);
1.2       misho     174:                                                break;
                    175:                                        case DT_BLK:
1.4       misho     176:                                                strlcpy(szType, "block", sizeof szType);
1.2       misho     177:                                                break;
                    178:                                        case DT_REG:
1.4       misho     179:                                                strlcpy(szType, "file", sizeof szType);
1.2       misho     180:                                                break;
                    181:                                        case DT_LNK:
1.4       misho     182:                                                strlcpy(szType, "link", sizeof szType);
1.2       misho     183:                                                break;
                    184:                                        case DT_SOCK:
1.4       misho     185:                                                strlcpy(szType, "socket", sizeof szType);
1.2       misho     186:                                                break;
                    187: /* OpenBSD does not have this type */
                    188: #ifdef DT_WHT
                    189:                                        case DT_WHT:
1.4       misho     190:                                                strlcpy(szType, "wht", sizeof szType);
1.2       misho     191:                                                break;
                    192: #endif
                    193:                                        case DT_UNKNOWN:
                    194:                                        default:
1.4       misho     195:                                                strlcpy(szType, "unknown", sizeof szType);
1.2       misho     196:                                                break;
                    197:                                }
1.4       misho     198:                                snprintf(l[n].extra, sizeof l[n].extra, 
1.5.4.1 ! misho     199:                                                "%s links=%ld inode=%ld %d:%d perm=0%o size=%ld %s", 
        !           200:                                                szType, (long) sb.st_nlink, (long) sb.st_ino, 
1.4       misho     201:                                                sb.st_uid, sb.st_gid, sb.st_mode & 0x1fff, 
                    202:                                                (long) sb.st_size, szStr);
1.2       misho     203:                        }
                    204:                }
                    205: 
                    206:                n++;
                    207:        }
                    208:        closedir(dir);
                    209: 
                    210:        qsort(l, n, sizeof(struct tagDirName), (int (*)(const void*, const void*)) func_comp);
                    211:        for (i = n - 1; i > -1; i--)
                    212:                tags[l[i].tag] = i;
                    213: 
                    214:        chdir(old);
1.5       misho     215:        e_free(old);
1.2       misho     216: 
                    217:        *list = l;
                    218:        return n;
                    219: }
                    220: 
1.4       misho     221: /* ------------------------------------------------------ */
1.2       misho     222: 
                    223: /*
1.4       misho     224:  * sync_dirChkSum() - Calculate checksum of directory
                    225:  *
1.2       misho     226:  * @csDir = Directory
1.5       misho     227:  * @md = Message digest allocated memory, must be e_free() after use!
1.2       misho     228:  * return: -1 error or !=-1 ok
                    229:  */
                    230: int
1.4       misho     231: sync_dirChkSum(const char *csDir, u_char **md)
1.2       misho     232: {
                    233:        DIR *dir;
                    234:        struct dirent d, *pd;
                    235:        MD5_CTX ctx;
                    236:        register int ret = 0;
                    237: 
1.5       misho     238:        *md = e_malloc(MD5_DIGEST_LENGTH);
1.2       misho     239:        if (!*md) {
1.4       misho     240:                LOGERR;
1.2       misho     241:                return -1;
                    242:        } else
                    243:                memset(*md, 0, MD5_DIGEST_LENGTH);
                    244: 
                    245:        dir = opendir(csDir);
                    246:        if (!dir) {
1.4       misho     247:                LOGERR;
1.5       misho     248:                e_free(*md);
1.2       misho     249:                return -1;
                    250:        }
                    251: 
                    252:        MD5_Init(&ctx);
                    253:        while (!readdir_r(dir, &d, &pd) && pd) {
                    254:                if (d.d_type == DT_DIR && (!strcmp(d.d_name, ".") || !strcmp(d.d_name, "..")))
                    255:                        continue;
1.5.4.1 ! misho     256: #ifndef __linux__
1.2       misho     257:                MD5_Update(&ctx, d.d_name, d.d_namlen);
1.5.4.1 ! misho     258: #else
        !           259:                MD5_Update(&ctx, d.d_name, strlen(d.d_name));
        !           260: #endif
1.2       misho     261:                ret++;
                    262:        }
                    263:        MD5_Final(*md, &ctx);
                    264: 
                    265:        closedir(dir);
                    266:        return ret;
                    267: }
                    268: 
                    269: /*
1.4       misho     270:  * sync_dircmp() - Compare directories
                    271:  *
1.2       misho     272:  * @csDir1 = Directory 1
                    273:  * @csDir2 = Directory 2
                    274:  * return: -1 error, 0 is equal or 1 different
                    275:  */
                    276: int
                    277: sync_dircmp(const char *csDir1, const char *csDir2)
                    278: {
                    279:        u_char *md[2] = { NULL, NULL };
                    280:        int ret = -1;
                    281: 
                    282:        if (!csDir1 || !csDir2)
                    283:                return ret;
                    284: 
1.4       misho     285:        if (sync_dirChkSum(csDir1, &md[0]) == -1)
1.2       misho     286:                return ret;
1.4       misho     287:        if (sync_dirChkSum(csDir2, &md[1]) == -1) {
1.5       misho     288:                e_free(md[0]);
1.2       misho     289:                return ret;
                    290:        }
                    291: 
                    292:        if (!memcmp(md[0], md[1], MD5_DIGEST_LENGTH))
                    293:                ret = 0;
                    294:        else
                    295:                ret = 1;
                    296: 
1.5       misho     297:        e_free(md[1]);
                    298:        e_free(md[0]);
1.2       misho     299:        return ret;
                    300: }
                    301: 
                    302: /*
1.4       misho     303:  * sync_dircmpList() - Compare directories or directory and file list
                    304:  *
1.2       misho     305:  * @csDir1 = Directory 1
                    306:  * @csDir2 = Directory 2 or File list, if "-" get input from console
1.4       misho     307:  * @lm = Long mode options, !=NULL long output
1.5       misho     308:  * @list = Output diff list, after use must be e_free()!
1.2       misho     309:  * return: -1 error, 0 is equal or >0 count of returned list items
                    310:  */
                    311: int
                    312: sync_dircmpList(const char *csDir1, const char *csDir2, int lm, struct tagDirName **list)
                    313: {
                    314:        struct tagDirName *l, *find;
                    315:        int n, cx;
                    316:        DIR *dir;
                    317:        FILE *f = stdin;
                    318:        struct dirent d, *pd;
                    319:        int *tags;
                    320:        register int i;
                    321:        u_short t;
                    322:        u_int hash;
                    323:        struct stat sb;
                    324:        char szLine[STRSIZ], szStr[STRSIZ], szType[STRSIZ], *str, *pbrk, *old;
                    325: 
                    326:        if (!csDir1 || !list || !(tags = create_tags()))
                    327:                return -1;
                    328: 
                    329:        n = create_diridx(csDir1, lm, tags, &l);
                    330:        if (n == -1 || !csDir2) {
                    331:                *list = l;
                    332:                return n;
                    333:        }
                    334: 
                    335:        if (lstat(csDir2, &sb) == -1) {
1.4       misho     336:                LOGERR;
1.5       misho     337:                e_free(tags);
                    338:                e_free(l);
1.2       misho     339:                return -1;
                    340:        }
                    341:        if (S_ISDIR(sb.st_mode)) {
                    342:                old = getcwd(NULL, 0);
                    343:                if (chdir(csDir2) == -1) {
1.4       misho     344:                        LOGERR;
1.2       misho     345:                        chdir(old);
1.5       misho     346:                        e_free(old);
                    347:                        e_free(tags);
                    348:                        e_free(l);
1.2       misho     349:                        return -1;
                    350:                }
                    351:                dir = opendir(".");
                    352:                if (!dir) {
1.4       misho     353:                        LOGERR;
1.2       misho     354:                        chdir(old);
1.5       misho     355:                        e_free(old);
                    356:                        e_free(tags);
                    357:                        e_free(l);
1.2       misho     358:                        return -1;
                    359:                }
                    360:                while (!readdir_r(dir, &d, &pd) && pd) {
                    361:                        if (d.d_type == DT_DIR && (!strcmp(d.d_name, ".") || !strcmp(d.d_name, "..")))
                    362:                                continue;
                    363:                        else {
1.5.4.1 ! misho     364: #ifndef __linux__
1.2       misho     365:                                t = crcFletcher16((u_short*) d.d_name, d.d_namlen / 2 + d.d_namlen % 2);
                    366:                                hash = crcAdler((u_char*) d.d_name, d.d_namlen);
1.5.4.1 ! misho     367: #else
        !           368:                                t = crcFletcher16((u_short*) d.d_name, strlen(d.d_name) / 2 + strlen(d.d_name) % 2);
        !           369:                                hash = crcAdler((u_char*) d.d_name, strlen(d.d_name));
        !           370: #endif
1.2       misho     371:                        }
                    372: 
                    373:                        find = find_tag(tags, l, t, hash);
1.4       misho     374:                        /* element not find in dir1, added */
1.2       misho     375:                        if (!find) {
1.5       misho     376:                                l = e_realloc(l, sizeof(struct tagDirName) * (n + 2));
1.2       misho     377:                                if (!l) {
1.4       misho     378:                                        LOGERR;
1.2       misho     379:                                        chdir(old);
1.5       misho     380:                                        e_free(old);
1.2       misho     381:                                        closedir(dir);
1.5       misho     382:                                        e_free(tags);
1.2       misho     383:                                        return -1;
                    384:                                } else
                    385:                                        memset(&l[n + 1], 0, sizeof(struct tagDirName));
                    386: 
1.4       misho     387:                                l[n].ch = DIFF_D2;
1.2       misho     388:                                l[n].tag = t;
                    389:                                l[n].hash = hash;
1.4       misho     390:                                strlcpy(l[n].name, d.d_name, sizeof l[n].name);
1.2       misho     391:                                if (lm & 1) {
                    392:                                        if (lstat(d.d_name, &sb) != -1) {
1.4       misho     393:                                                memset(szStr, 0, sizeof szStr);
1.2       misho     394: #if defined(__OpenBSD__)
1.4       misho     395:                                                strftime(szStr, sizeof szStr, "%Y-%m-%d %H:%M:%S", 
1.2       misho     396:                                                                localtime((time_t*) &sb.st_mtim));
                    397: #else
1.4       misho     398:                                                strftime(szStr, sizeof szStr, "%Y-%m-%d %H:%M:%S", 
1.2       misho     399:                                                                localtime((time_t*) &sb.st_mtime));
                    400: #endif
                    401:                                                switch (d.d_type) {
                    402:                                                        case DT_FIFO:
1.4       misho     403:                                                                strlcpy(szType, "fifo", sizeof szType);
1.2       misho     404:                                                                break;
                    405:                                                        case DT_CHR:
1.4       misho     406:                                                                strlcpy(szType, "char", sizeof szType);
1.2       misho     407:                                                                break;
                    408:                                                        case DT_DIR:
1.4       misho     409:                                                                strlcpy(szType, "dir", sizeof szType);
1.2       misho     410:                                                                break;
                    411:                                                        case DT_BLK:
1.4       misho     412:                                                                strlcpy(szType, "block", sizeof szType);
1.2       misho     413:                                                                break;
                    414:                                                        case DT_REG:
1.4       misho     415:                                                                strlcpy(szType, "file", sizeof szType);
1.2       misho     416:                                                                break;
                    417:                                                        case DT_LNK:
1.4       misho     418:                                                                strlcpy(szType, "link", sizeof szType);
1.2       misho     419:                                                                break;
                    420:                                                        case DT_SOCK:
1.4       misho     421:                                                                strlcpy(szType, "socket", sizeof szType);
1.2       misho     422:                                                                break;
                    423: /* OpenBSD does not have this type */
                    424: #ifdef DT_WHT
                    425:                                                        case DT_WHT:
1.4       misho     426:                                                                strlcpy(szType, "wht", sizeof szType);
1.2       misho     427:                                                                break;
                    428: #endif
                    429:                                                        case DT_UNKNOWN:
                    430:                                                        default:
1.4       misho     431:                                                                strlcpy(szType, "unknown", sizeof szType);
1.2       misho     432:                                                                break;
                    433:                                                }
1.4       misho     434:                                                snprintf(l[n].extra, sizeof l[n].extra, 
1.5.4.1 ! misho     435:                                                                "%s links=%ld inode=%ld %d:%d perm=0%o "
        !           436:                                                                "size=%ld %s", szType, (long) sb.st_nlink, 
1.4       misho     437:                                                                (long) sb.st_ino, sb.st_uid, sb.st_gid, 
                    438:                                                                sb.st_mode & 0x1fff, (long) sb.st_size, 
1.3       misho     439:                                                                szStr);
1.2       misho     440:                                        }
                    441:                                }
                    442: 
                    443:                                n++;
                    444:                        }
                    445:                }
                    446:                closedir(dir);
                    447:                chdir(old);
1.5       misho     448:                e_free(old);
1.2       misho     449:        } else {
                    450:                if (strcmp(csDir2, "-")) {
                    451:                        f = fopen(csDir2, "r");
                    452:                        if (!f) {
1.4       misho     453:                                LOGERR;
1.5       misho     454:                                e_free(tags);
                    455:                                e_free(l);
1.2       misho     456:                                return -1;
                    457:                        }
                    458:                }
1.4       misho     459:                while (fgets(szLine, sizeof szLine, f)) {
1.2       misho     460:                        if (!*szLine || *szLine == '#')
                    461:                                continue;
                    462: 
                    463:                        str = strtok_r(szLine, " \t", &pbrk);
                    464:                        if (!str)
                    465:                                continue;
                    466:                        str = strtok_r(NULL, " \t", &pbrk);
                    467:                        if (!str)
                    468:                                continue;
                    469:                        else {
                    470:                                i = strlen(str);
                    471:                                t = crcFletcher16((u_short*) str, i / 2 + i % 2);
                    472:                                hash = crcAdler((u_char*) str, i);
                    473:                        }
                    474: 
                    475:                        find = find_tag(tags, l, t, hash);
1.4       misho     476:                        /* element not find in dir1, added */
1.2       misho     477:                        if (!find) {
1.5       misho     478:                                l = e_realloc(l, sizeof(struct tagDirName) * (n + 2));
1.2       misho     479:                                if (!l) {
1.4       misho     480:                                        LOGERR;
1.2       misho     481:                                        if (strcmp(csDir2, "-"))
                    482:                                                fclose(f);
1.5       misho     483:                                        e_free(tags);
1.2       misho     484:                                        return -1;
                    485:                                } else
                    486:                                        memset(&l[n + 1], 0, sizeof(struct tagDirName));
                    487: 
1.4       misho     488:                                l[n].ch = DIFF_D2;
1.2       misho     489:                                l[n].tag = t;
                    490:                                l[n].hash = hash;
1.4       misho     491:                                strlcpy(l[n].name, str, sizeof l[n].name);
1.2       misho     492:                                if (lm & 1 && (str = strtok_r(NULL, "\r\n", &pbrk)))
1.4       misho     493:                                        strlcpy(l[n].extra, str, sizeof l[n].extra);
1.2       misho     494: 
                    495:                                n++;
                    496:                        }
                    497:                }
                    498:                if (strcmp(csDir2, "-"))
                    499:                        fclose(f);
                    500:        }
                    501: 
1.4       misho     502:        /* delete equal elemets !!! */
1.2       misho     503:        for (i = cx = 0; i < n; i++)
1.4       misho     504:                if (l[i].ch == DIFF_D0) {
1.2       misho     505:                        memmove(&l[i], &l[i + 1], (n - i + 1) * sizeof(struct tagDirName));
                    506:                        cx++;
                    507:                        i--;
                    508:                }
                    509:        n -= cx;
                    510: 
1.5       misho     511:        e_free(tags);
1.2       misho     512:        *list = l;
                    513:        return n;
                    514: }

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