File:  [ELWIX - Embedded LightWeight unIX -] / libaitsync / src / dir.c
Revision 1.5.4.1: download - view: text, annotated - select for diffs - revision graph
Thu Aug 18 09:53:02 2016 UTC (8 years ago) by misho
Branches: sync2_3
Diff to: branchpoint 1.5: preferred, unified
linux port

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

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