File:  [ELWIX - Embedded LightWeight unIX -] / libaitsync / src / dir.c
Revision 1.1.2.4: download - view: text, annotated - select for diffs - revision graph
Thu Apr 28 07:16:05 2011 UTC (13 years, 2 months ago) by misho
Branches: sync1_0
added multios supported stat struct

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>