1 /* @(#)cmpdir.c	1.28 19/11/28 Copyright 2002-2019 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static	UConst char sccsid[] =
5 	"@(#)cmpdir.c	1.28 19/11/28 Copyright 2002-2019 J. Schilling";
6 #endif
7 /*
8  *	Blocked directory sort/compare.
9  *
10  *	Copyright (c) 2002-2019 J. Schilling
11  */
12 /*
13  * The contents of this file are subject to the terms of the
14  * Common Development and Distribution License, Version 1.0 only
15  * (the "License").  You may not use this file except in compliance
16  * with the License.
17  *
18  * See the file CDDL.Schily.txt in this distribution for details.
19  * A copy of the CDDL is also available via the Internet at
20  * http://www.opensource.org/licenses/cddl1.txt
21  *
22  * When distributing Covered Code, include this CDDL HEADER in each
23  * file and include the License file CDDL.Schily.txt from this distribution.
24  */
25 
26 #include <schily/stdio.h>
27 #include <schily/stdlib.h>
28 #include <schily/unistd.h>
29 #include <schily/standard.h>
30 #include <schily/types.h>
31 #include <schily/utypes.h>
32 #include <schily/string.h>
33 #include <schily/schily.h>
34 #include <schily/fetchdir.h>
35 
36 EXPORT	int	fdircomp	__PR((const void *p1, const void *p2));
37 EXPORT	char	**sortdir	__PR((char *dir, size_t *entp));
38 EXPORT	int	cmpdir		__PR((size_t ents1, size_t ents2,
39 					char **ep1, char **ep2,
40 					char **oa, char **od,
41 					size_t *alenp, size_t *dlenp));
42 
43 /*
44  * Compare directory entries from fetchdir().
45  * Ignore first byte, it does not belong to the directory data.
46  */
47 EXPORT int
fdircomp(p1,p2)48 fdircomp(p1, p2)
49 	const void	*p1;
50 	const void	*p2;
51 {
52 	register Uchar	*s1;
53 	register Uchar	*s2;
54 
55 	s1 = *(Uchar **)p1;
56 	s2 = *(Uchar **)p2;
57 	s1++;
58 	s2++;
59 	while (*s1 == *s2) {
60 		if (*s1 == '\0')
61 			return (0);
62 		s1++;
63 		s2++;
64 	}
65 	return (*s1 - *s2);
66 }
67 
68 /*
69  * Sort a directory string as returned by fetchdir().
70  *
71  * If "ents" == (size_t)-1, start with counting exisiting entries.
72  *
73  * Return allocated arry with string pointers.
74  */
75 EXPORT char **
sortdir(dir,entp)76 sortdir(dir, entp)
77 	char	*dir;
78 	size_t	*entp;
79 {
80 	size_t	ents = (size_t)-1;
81 	char	**ea;
82 	char	*d;
83 	char	*p;
84 	size_t	i;
85 
86 	if (entp)
87 		ents = *entp;
88 	if (ents == (size_t)-1) {
89 		d = dir;
90 		ents = 0;
91 		while (*d) {
92 			ents++;
93 			p = strchr(d, '\0');
94 			d = &p[1];
95 		}
96 	}
97 	ea = ___malloc((ents+1)*sizeof (char *), "sortdir");
98 	for (i = 0; i < ents; i++) {
99 		ea[i] = NULL;
100 	}
101 	for (i = 0; i < ents; i++) {
102 		ea[i] = dir;
103 		p = strchr(dir, '\0');
104 		if (p == NULL)
105 			break;
106 		dir = ++p;
107 	}
108 	ea[ents] = NULL;
109 	qsort(ea, ents, sizeof (char *), fdircomp);
110 	if (entp)
111 		*entp = ents;
112 	return (ea);
113 }
114 
115 EXPORT int
cmpdir(ents1,ents2,ep1,ep2,oa,od,alenp,dlenp)116 cmpdir(ents1, ents2, ep1, ep2, oa, od, alenp, dlenp)
117 	register size_t	ents1;	/* # of directory entries in arch	*/
118 	register size_t	ents2;	/* # of directory entries on disk	*/
119 	register char	**ep1;	/* Directory entry pointer array (arch)	*/
120 	register char	**ep2;	/* Directory entry pointer array (disk)	*/
121 	register char	**oa;	/* Only in arch pointer array		*/
122 	register char	**od;	/* Only on disk pointer array		*/
123 		size_t	*alenp;	/* Len pointer for "only in arch" array	*/
124 		size_t	*dlenp;	/* Len pointer for "only on disk" array	*/
125 {
126 	register size_t	i1;	/* Index for 'only in archive'		*/
127 	register size_t	i2;	/* Index for 'only on disk'		*/
128 	register int	d;	/* 'diff' amount (== 0 means equal)	*/
129 	register size_t	alen = 0; /* Number of ents only in archive	*/
130 	register size_t	dlen = 0; /* Number of ents only on disk	*/
131 
132 	for (i1 = i2 = 0; i1 < ents1 && i2 < ents2; i1++, i2++) {
133 		d = fdircomp(&ep1[i1], &ep2[i2]);
134 		retry:
135 
136 		if (d > 0) {
137 			do {
138 				d = fdircomp(&ep1[i1], &ep2[i2]);
139 				if (d <= 0)
140 					goto retry;
141 				if (od)
142 					od[dlen] = ep2[i2];
143 				dlen++;
144 				i2++;
145 			} while (i1 < ents1 && i2 < ents2);
146 		}
147 		if (d < 0) {
148 			do {
149 				d = fdircomp(&ep1[i1], &ep2[i2]);
150 				if (d >= 0)
151 					goto retry;
152 				if (oa)
153 					oa[alen] = ep1[i1];
154 				alen++;
155 				i1++;
156 			} while (i1 < ents1 && i2 < ents2);
157 		}
158 		/*
159 		 * Do not increment i1 & i2 in case that the last elements are
160 		 * not equal and need to be treaten as longer list elements in
161 		 * the code below.
162 		 */
163 		if (i1 >= ents1 || i2 >= ents2)
164 			break;
165 	}
166 	/*
167 	 * One of both lists is longer after some amount.
168 	 */
169 	if (od == NULL) {
170 		if (i2 < ents2)
171 			dlen += ents2 - i2;
172 	} else {
173 		for (; i2 < ents2; i2++) {
174 			od[dlen] = ep2[i2];
175 			dlen++;
176 		}
177 	}
178 	if (oa == NULL) {
179 		if (i1 < ents1)
180 			alen += ents1 - i1;
181 	} else {
182 		for (; i1 < ents1; i1++) {
183 			oa[alen] = ep1[i1];
184 			alen++;
185 		}
186 	}
187 	if (alenp)
188 		*alenp = alen;
189 	if (dlenp)
190 		*dlenp = dlen;
191 
192 	return (alen + dlen);
193 }
194