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