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>