Annotation of libaitsync/src/dir.c, revision 1.1.2.3
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.3 ! misho 6: * $Id: dir.c,v 1.1.2.2 2010/09/20 23:07:57 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;
1.1.2.3 ! misho 137: /* OpenBSD does not have this type */
! 138: #ifdef DT_WHT
1.1.2.1 misho 139: case DT_WHT:
140: strlcpy(szType, "wht", STRSIZ);
141: break;
1.1.2.3 ! misho 142: #endif
1.1.2.1 misho 143: case DT_UNKNOWN:
144: default:
145: strlcpy(szType, "unknown", STRSIZ);
146: break;
147: }
148: snprintf(l[n].extra, STRSIZ, "%s links=%d inode=%u %d:%d perm=0%o size=%llu %s",
149: szType, sb.st_nlink, sb.st_ino, sb.st_uid, sb.st_gid,
150: sb.st_mode & 0x1fff, sb.st_size, szStr);
151: }
152: }
153:
154: n++;
155: }
156: closedir(dir);
157:
158: qsort(l, n, sizeof(struct tagDirName), (int (*)(const void*, const void*)) func_comp);
159: for (i = n - 1; i > -1; i--)
160: tags[l[i].tag] = i;
161:
1.1.2.2 misho 162: chdir(old);
163: free(old);
164:
1.1.2.1 misho 165: *list = l;
166: return n;
167: }
168:
169: // ------------------------------------------------------
170:
171: /*
172: * sync_dirCSum() Calculate checksum of directory
173: * @csDir = Directory
174: * @md = Message digest allocated memory, must be free after use!
175: * return: -1 error or !=-1 ok
176: */
177: int
178: sync_dirCSum(const char *csDir, u_char **md)
179: {
180: DIR *dir;
181: struct dirent d, *pd;
182: MD5_CTX ctx;
183: register int ret = 0;
184:
185: *md = malloc(MD5_DIGEST_LENGTH);
186: if (!*md) {
187: SETERR;
188: return -1;
189: } else
190: memset(*md, 0, MD5_DIGEST_LENGTH);
191:
192: dir = opendir(csDir);
193: if (!dir) {
194: SETERR;
195: free(*md);
196: return -1;
197: }
198:
199: MD5_Init(&ctx);
200: while (!readdir_r(dir, &d, &pd) && pd) {
201: if (d.d_type == DT_DIR && (!strcmp(d.d_name, ".") || !strcmp(d.d_name, "..")))
202: continue;
203: MD5_Update(&ctx, d.d_name, d.d_namlen);
204: ret++;
205: }
206: MD5_Final(*md, &ctx);
207:
208: closedir(dir);
209: return ret;
210: }
211:
212: /*
213: * sync_dircmp() Compare directories
214: * @csDir1 = Directory 1
215: * @csDir2 = Directory 2
216: * return: -1 error, 0 is equal or 1 different
217: */
218: int
219: sync_dircmp(const char *csDir1, const char *csDir2)
220: {
221: u_char *md[2] = { NULL, NULL };
222: int ret = -1;
223:
224: if (!csDir1 || !csDir2)
225: return ret;
226:
227: if (sync_dirCSum(csDir1, &md[0]) == -1)
228: return ret;
229: if (sync_dirCSum(csDir2, &md[1]) == -1) {
230: free(md[0]);
231: return ret;
232: }
233:
234: if (!memcmp(md[0], md[1], MD5_DIGEST_LENGTH))
235: ret = 0;
236: else
237: ret = 1;
238:
239: free(md[1]);
240: free(md[0]);
241: return ret;
242: }
243:
244: /*
245: * sync_dircmpList() Compare directories or directory and file list
246: * @csDir1 = Directory 1
247: * @csDir2 = Directory 2 or File list, if "-" get input from console
248: * @lm = Long mode options, 1 long output
249: * @list = Output diff list, after use must be free!
250: * return: -1 error, 0 is equal or >0 count of returned list items
251: */
252: int
253: sync_dircmpList(const char *csDir1, const char *csDir2, int lm, struct tagDirName **list)
254: {
255: struct tagDirName *l, *find;
256: int n, cx;
257: DIR *dir;
258: FILE *f = stdin;
259: struct dirent d, *pd;
260: int *tags;
261: register int i;
262: u_short t;
263: u_int hash;
264: struct stat sb;
1.1.2.2 misho 265: char szLine[STRSIZ], szStr[STRSIZ], szType[STRSIZ], *str, *pbrk, *old;
1.1.2.1 misho 266:
267: if (!csDir1 || !list || !(tags = create_tags()))
268: return -1;
269:
270: n = create_diridx(csDir1, lm, tags, &l);
271: if (n == -1 || !csDir2) {
272: *list = l;
273: return n;
274: }
275:
1.1.2.2 misho 276: if (lstat(csDir2, &sb) == -1) {
277: SETERR;
278: free(l);
279: return -1;
280: }
281: if (S_ISDIR(sb.st_mode)) {
282: old = getcwd(NULL, 0);
1.1.2.1 misho 283: if (chdir(csDir2) == -1) {
284: SETERR;
1.1.2.2 misho 285: chdir(old);
286: free(old);
1.1.2.1 misho 287: free(l);
288: return -1;
289: }
290: dir = opendir(".");
291: if (!dir) {
292: SETERR;
1.1.2.2 misho 293: chdir(old);
294: free(old);
1.1.2.1 misho 295: free(l);
296: return -1;
297: }
298: while (!readdir_r(dir, &d, &pd) && pd) {
299: if (d.d_type == DT_DIR && (!strcmp(d.d_name, ".") || !strcmp(d.d_name, "..")))
300: continue;
301: else {
302: t = crcFletcher16((u_short*) d.d_name, d.d_namlen / 2 + d.d_namlen % 2);
303: hash = crcAdler((u_char*) d.d_name, d.d_namlen);
304: }
305:
306: find = find_tag(tags, l, t, hash);
307: // element not find in dir1, added
308: if (!find) {
309: l = realloc(l, sizeof(struct tagDirName) * (n + 2));
310: if (!l) {
311: SETERR;
1.1.2.2 misho 312: chdir(old);
313: free(old);
1.1.2.1 misho 314: closedir(dir);
315: return -1;
316: } else
317: memset(&l[n + 1], 0, sizeof(struct tagDirName));
318:
319: l[n].ch = '>';
320: l[n].tag = t;
321: l[n].hash = hash;
322: strlcpy(l[n].name, d.d_name, MAXPATHLEN);
323: if (lm & 1) {
324: if (lstat(d.d_name, &sb) != -1) {
325: memset(szStr, 0, STRSIZ);
326: strftime(szStr, STRSIZ, "%Y-%m-%d %H:%M:%S",
327: localtime((time_t*) &sb.st_mtim));
328: switch (d.d_type) {
329: case DT_FIFO:
330: strlcpy(szType, "fifo", STRSIZ);
331: break;
332: case DT_CHR:
333: strlcpy(szType, "char", STRSIZ);
334: break;
335: case DT_DIR:
336: strlcpy(szType, "dir", STRSIZ);
337: break;
338: case DT_BLK:
339: strlcpy(szType, "block", STRSIZ);
340: break;
341: case DT_REG:
342: strlcpy(szType, "file", STRSIZ);
343: break;
344: case DT_LNK:
345: strlcpy(szType, "link", STRSIZ);
346: break;
347: case DT_SOCK:
348: strlcpy(szType, "socket", STRSIZ);
349: break;
1.1.2.3 ! misho 350: /* OpenBSD does not have this type */
! 351: #ifdef DT_WHT
1.1.2.1 misho 352: case DT_WHT:
353: strlcpy(szType, "wht", STRSIZ);
354: break;
1.1.2.3 ! misho 355: #endif
1.1.2.1 misho 356: case DT_UNKNOWN:
357: default:
358: strlcpy(szType, "unknown", STRSIZ);
359: break;
360: }
361: snprintf(l[n].extra, STRSIZ,
362: "%s links=%d inode=%u %d:%d perm=0%o size=%llu %s",
363: szType, sb.st_nlink, sb.st_ino, sb.st_uid, sb.st_gid,
364: sb.st_mode & 0x1fff, sb.st_size, szStr);
365: }
366: }
367:
368: n++;
369: }
370: }
371: closedir(dir);
1.1.2.2 misho 372: chdir(old);
373: free(old);
1.1.2.1 misho 374: } else {
375: if (strcmp(csDir2, "-")) {
376: f = fopen(csDir2, "r");
377: if (!f) {
378: SETERR;
379: free(l);
380: return -1;
381: }
382: }
383: while (fgets(szLine, STRSIZ, f)) {
384: if (!*szLine || *szLine == '#')
385: continue;
386:
387: str = strtok_r(szLine, " \t", &pbrk);
388: if (!str)
389: continue;
390: str = strtok_r(NULL, " \t", &pbrk);
391: if (!str)
392: continue;
393: else {
394: i = strlen(str);
395: t = crcFletcher16((u_short*) str, i / 2 + i % 2);
396: hash = crcAdler((u_char*) str, i);
397: }
398:
399: find = find_tag(tags, l, t, hash);
400: // element not find in dir1, added
401: if (!find) {
402: l = realloc(l, sizeof(struct tagDirName) * (n + 2));
403: if (!l) {
404: SETERR;
405: if (strcmp(csDir2, "-"))
406: fclose(f);
407: return -1;
408: } else
409: memset(&l[n + 1], 0, sizeof(struct tagDirName));
410:
411: l[n].ch = '>';
412: l[n].tag = t;
413: l[n].hash = hash;
414: strlcpy(l[n].name, str, MAXPATHLEN);
415: if (lm & 1 && (str = strtok_r(NULL, "\r\n", &pbrk)))
416: strlcpy(l[n].extra, str, STRSIZ);
417:
418: n++;
419: }
420: }
421: if (strcmp(csDir2, "-"))
422: fclose(f);
423: }
424:
425: // delete equal elemets !!!
426: for (i = cx = 0; i < n; i++)
427: if (l[i].ch == '*') {
428: memmove(&l[i], &l[i + 1], (n - i + 1) * sizeof(struct tagDirName));
429: cx++;
430: i--;
431: }
432: n -= cx;
433:
434: *list = l;
435: return n;
436: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>