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