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