xref: /freebsd/lib/libc/iconv/citrus_csmapper.c (revision 559a218c)
19ca40936STijl Coosemans /*	$NetBSD: citrus_csmapper.c,v 1.11 2011/11/20 07:43:52 tnozaki Exp $	*/
2ad30f8e7SGabor Kovesdan 
3ad30f8e7SGabor Kovesdan /*-
4d915a14eSPedro F. Giffuni  * SPDX-License-Identifier: BSD-2-Clause
5d915a14eSPedro F. Giffuni  *
6ad30f8e7SGabor Kovesdan  * Copyright (c)2003 Citrus Project,
7ad30f8e7SGabor Kovesdan  * All rights reserved.
8ad30f8e7SGabor Kovesdan  *
9ad30f8e7SGabor Kovesdan  * Redistribution and use in source and binary forms, with or without
10ad30f8e7SGabor Kovesdan  * modification, are permitted provided that the following conditions
11ad30f8e7SGabor Kovesdan  * are met:
12ad30f8e7SGabor Kovesdan  * 1. Redistributions of source code must retain the above copyright
13ad30f8e7SGabor Kovesdan  *    notice, this list of conditions and the following disclaimer.
14ad30f8e7SGabor Kovesdan  * 2. Redistributions in binary form must reproduce the above copyright
15ad30f8e7SGabor Kovesdan  *    notice, this list of conditions and the following disclaimer in the
16ad30f8e7SGabor Kovesdan  *    documentation and/or other materials provided with the distribution.
17ad30f8e7SGabor Kovesdan  *
18ad30f8e7SGabor Kovesdan  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19ad30f8e7SGabor Kovesdan  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20ad30f8e7SGabor Kovesdan  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21ad30f8e7SGabor Kovesdan  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22ad30f8e7SGabor Kovesdan  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23ad30f8e7SGabor Kovesdan  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24ad30f8e7SGabor Kovesdan  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25ad30f8e7SGabor Kovesdan  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26ad30f8e7SGabor Kovesdan  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27ad30f8e7SGabor Kovesdan  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28ad30f8e7SGabor Kovesdan  * SUCH DAMAGE.
29ad30f8e7SGabor Kovesdan  */
30ad30f8e7SGabor Kovesdan 
31ad30f8e7SGabor Kovesdan #include <sys/endian.h>
32ad30f8e7SGabor Kovesdan #include <sys/types.h>
33ad30f8e7SGabor Kovesdan #include <sys/queue.h>
34ad30f8e7SGabor Kovesdan 
35ad30f8e7SGabor Kovesdan #include <assert.h>
36ad30f8e7SGabor Kovesdan #include <errno.h>
37ad30f8e7SGabor Kovesdan #include <limits.h>
38ad30f8e7SGabor Kovesdan #include <paths.h>
39ad30f8e7SGabor Kovesdan #include <stdio.h>
40ad30f8e7SGabor Kovesdan #include <stdlib.h>
41ad30f8e7SGabor Kovesdan #include <string.h>
42ad30f8e7SGabor Kovesdan 
43ad30f8e7SGabor Kovesdan #include "citrus_namespace.h"
44ad30f8e7SGabor Kovesdan #include "citrus_types.h"
45ad30f8e7SGabor Kovesdan #include "citrus_bcs.h"
46ad30f8e7SGabor Kovesdan #include "citrus_region.h"
47ad30f8e7SGabor Kovesdan #include "citrus_lock.h"
48ad30f8e7SGabor Kovesdan #include "citrus_memstream.h"
49ad30f8e7SGabor Kovesdan #include "citrus_mmap.h"
50ad30f8e7SGabor Kovesdan #include "citrus_module.h"
51ad30f8e7SGabor Kovesdan #include "citrus_hash.h"
52ad30f8e7SGabor Kovesdan #include "citrus_mapper.h"
53ad30f8e7SGabor Kovesdan #include "citrus_csmapper.h"
54ad30f8e7SGabor Kovesdan #include "citrus_pivot_file.h"
55ad30f8e7SGabor Kovesdan #include "citrus_db.h"
56ad30f8e7SGabor Kovesdan #include "citrus_db_hash.h"
57ad30f8e7SGabor Kovesdan #include "citrus_lookup.h"
58ad30f8e7SGabor Kovesdan 
59ad30f8e7SGabor Kovesdan static struct _citrus_mapper_area	*maparea = NULL;
60ad30f8e7SGabor Kovesdan 
61ff0b75b8SPeter Wemm static pthread_rwlock_t			ma_lock = PTHREAD_RWLOCK_INITIALIZER;
62ff0b75b8SPeter Wemm 
63ad30f8e7SGabor Kovesdan #define CS_ALIAS	_PATH_CSMAPPER "/charset.alias"
64ad30f8e7SGabor Kovesdan #define CS_PIVOT	_PATH_CSMAPPER "/charset.pivot"
65ad30f8e7SGabor Kovesdan 
66ad30f8e7SGabor Kovesdan 
67ad30f8e7SGabor Kovesdan /* ---------------------------------------------------------------------- */
68ad30f8e7SGabor Kovesdan 
69ad30f8e7SGabor Kovesdan static int
get32(struct _region * r,uint32_t * rval)70ad30f8e7SGabor Kovesdan get32(struct _region *r, uint32_t *rval)
71ad30f8e7SGabor Kovesdan {
72ad30f8e7SGabor Kovesdan 
73ad30f8e7SGabor Kovesdan 	if (_region_size(r) != 4)
74ad30f8e7SGabor Kovesdan 		return (EFTYPE);
75ad30f8e7SGabor Kovesdan 
76ad30f8e7SGabor Kovesdan 	memcpy(rval, _region_head(r), (size_t)4);
77ad30f8e7SGabor Kovesdan 	*rval = be32toh(*rval);
78ad30f8e7SGabor Kovesdan 
79ad30f8e7SGabor Kovesdan 	return (0);
80ad30f8e7SGabor Kovesdan }
81ad30f8e7SGabor Kovesdan 
82ad30f8e7SGabor Kovesdan static int
open_subdb(struct _citrus_db ** subdb,struct _citrus_db * db,const char * src)83ad30f8e7SGabor Kovesdan open_subdb(struct _citrus_db **subdb, struct _citrus_db *db, const char *src)
84ad30f8e7SGabor Kovesdan {
85ad30f8e7SGabor Kovesdan 	struct _region r;
86ad30f8e7SGabor Kovesdan 	int ret;
87ad30f8e7SGabor Kovesdan 
88ad30f8e7SGabor Kovesdan 	ret = _db_lookup_by_s(db, src, &r, NULL);
89ad30f8e7SGabor Kovesdan 	if (ret)
90ad30f8e7SGabor Kovesdan 		return (ret);
91ad30f8e7SGabor Kovesdan 	ret = _db_open(subdb, &r, _CITRUS_PIVOT_SUB_MAGIC, _db_hash_std, NULL);
92ad30f8e7SGabor Kovesdan 	if (ret)
93ad30f8e7SGabor Kovesdan 		return (ret);
94ad30f8e7SGabor Kovesdan 
95ad30f8e7SGabor Kovesdan 	return (0);
96ad30f8e7SGabor Kovesdan }
97ad30f8e7SGabor Kovesdan 
98ad30f8e7SGabor Kovesdan 
99ad30f8e7SGabor Kovesdan #define NO_SUCH_FILE	EOPNOTSUPP
100ad30f8e7SGabor Kovesdan static int
find_best_pivot_pvdb(const char * src,const char * dst,char * pivot,size_t pvlen,unsigned long * rnorm)101ad30f8e7SGabor Kovesdan find_best_pivot_pvdb(const char *src, const char *dst, char *pivot,
102ad30f8e7SGabor Kovesdan     size_t pvlen, unsigned long *rnorm)
103ad30f8e7SGabor Kovesdan {
104ad30f8e7SGabor Kovesdan 	struct _citrus_db *db1, *db2, *db3;
105ad30f8e7SGabor Kovesdan 	struct _region fr, r1, r2;
106ad30f8e7SGabor Kovesdan 	char buf[LINE_MAX];
107ad30f8e7SGabor Kovesdan 	uint32_t val32;
108ad30f8e7SGabor Kovesdan 	unsigned long norm;
109ad30f8e7SGabor Kovesdan 	int i, num, ret;
110ad30f8e7SGabor Kovesdan 
111ad30f8e7SGabor Kovesdan 	ret = _map_file(&fr, CS_PIVOT ".pvdb");
112ad30f8e7SGabor Kovesdan 	if (ret) {
113ad30f8e7SGabor Kovesdan 		if (ret == ENOENT)
114ad30f8e7SGabor Kovesdan 			ret = NO_SUCH_FILE;
115ad30f8e7SGabor Kovesdan 		return (ret);
116ad30f8e7SGabor Kovesdan 	}
117ad30f8e7SGabor Kovesdan 	ret = _db_open(&db1, &fr, _CITRUS_PIVOT_MAGIC, _db_hash_std, NULL);
118ad30f8e7SGabor Kovesdan 	if (ret)
119ad30f8e7SGabor Kovesdan 		goto quit1;
120ad30f8e7SGabor Kovesdan 	ret = open_subdb(&db2, db1, src);
121ad30f8e7SGabor Kovesdan 	if (ret)
122ad30f8e7SGabor Kovesdan 		goto quit2;
123ad30f8e7SGabor Kovesdan 
124ad30f8e7SGabor Kovesdan 	num = _db_get_num_entries(db2);
125ad30f8e7SGabor Kovesdan 	*rnorm = ULONG_MAX;
126ad30f8e7SGabor Kovesdan 	for (i = 0; i < num; i++) {
127ad30f8e7SGabor Kovesdan 		/* iterate each pivot */
128ad30f8e7SGabor Kovesdan 		ret = _db_get_entry(db2, i, &r1, &r2);
129ad30f8e7SGabor Kovesdan 		if (ret)
130ad30f8e7SGabor Kovesdan 			goto quit3;
131ad30f8e7SGabor Kovesdan 		/* r1:pivot name, r2:norm among src and pivot */
132ad30f8e7SGabor Kovesdan 		ret = get32(&r2, &val32);
133ad30f8e7SGabor Kovesdan 		if (ret)
134ad30f8e7SGabor Kovesdan 			goto quit3;
135ad30f8e7SGabor Kovesdan 		norm = val32;
136ad30f8e7SGabor Kovesdan 		snprintf(buf, sizeof(buf), "%.*s",
137ad30f8e7SGabor Kovesdan 			 (int)_region_size(&r1), (char *)_region_head(&r1));
138ad30f8e7SGabor Kovesdan 		/* buf: pivot name */
139ad30f8e7SGabor Kovesdan 		ret = open_subdb(&db3, db1, buf);
140ad30f8e7SGabor Kovesdan 		if (ret)
141ad30f8e7SGabor Kovesdan 			goto quit3;
142ad30f8e7SGabor Kovesdan 		if (_db_lookup_by_s(db3, dst, &r2, NULL) != 0)
1439ca40936STijl Coosemans 			/* don't break the loop, test all src/dst pairs. */
144ad30f8e7SGabor Kovesdan 			goto quit4;
145ad30f8e7SGabor Kovesdan 		/* r2: norm among pivot and dst */
146ad30f8e7SGabor Kovesdan 		ret = get32(&r2, &val32);
147ad30f8e7SGabor Kovesdan 		if (ret)
148ad30f8e7SGabor Kovesdan 			goto quit4;
149ad30f8e7SGabor Kovesdan 		norm += val32;
150ad30f8e7SGabor Kovesdan 		/* judge minimum norm */
151ad30f8e7SGabor Kovesdan 		if (norm < *rnorm) {
152ad30f8e7SGabor Kovesdan 			*rnorm = norm;
153ad30f8e7SGabor Kovesdan 			strlcpy(pivot, buf, pvlen);
154ad30f8e7SGabor Kovesdan 		}
155ad30f8e7SGabor Kovesdan quit4:
156ad30f8e7SGabor Kovesdan 		_db_close(db3);
157ad30f8e7SGabor Kovesdan 		if (ret)
158ad30f8e7SGabor Kovesdan 			goto quit3;
159ad30f8e7SGabor Kovesdan 	}
160ad30f8e7SGabor Kovesdan quit3:
161ad30f8e7SGabor Kovesdan 	_db_close(db2);
162ad30f8e7SGabor Kovesdan quit2:
163ad30f8e7SGabor Kovesdan 	_db_close(db1);
164ad30f8e7SGabor Kovesdan quit1:
165ad30f8e7SGabor Kovesdan 	_unmap_file(&fr);
166ad30f8e7SGabor Kovesdan 	if (ret)
167ad30f8e7SGabor Kovesdan 		return (ret);
168ad30f8e7SGabor Kovesdan 
169ad30f8e7SGabor Kovesdan 	if (*rnorm == ULONG_MAX)
170ad30f8e7SGabor Kovesdan 		return (ENOENT);
171ad30f8e7SGabor Kovesdan 
172ad30f8e7SGabor Kovesdan 	return (0);
173ad30f8e7SGabor Kovesdan }
174ad30f8e7SGabor Kovesdan 
175ad30f8e7SGabor Kovesdan /* ---------------------------------------------------------------------- */
176ad30f8e7SGabor Kovesdan 
177ad30f8e7SGabor Kovesdan struct zone {
178ad30f8e7SGabor Kovesdan 	const char *begin, *end;
179ad30f8e7SGabor Kovesdan };
180ad30f8e7SGabor Kovesdan 
181ad30f8e7SGabor Kovesdan struct parse_arg {
182ad30f8e7SGabor Kovesdan 	char dst[PATH_MAX];
183ad30f8e7SGabor Kovesdan 	unsigned long norm;
184ad30f8e7SGabor Kovesdan };
185ad30f8e7SGabor Kovesdan 
186ad30f8e7SGabor Kovesdan static int
parse_line(struct parse_arg * pa,struct _region * r)187ad30f8e7SGabor Kovesdan parse_line(struct parse_arg *pa, struct _region *r)
188ad30f8e7SGabor Kovesdan {
189ad30f8e7SGabor Kovesdan 	struct zone z1, z2;
190ad30f8e7SGabor Kovesdan 	char buf[20];
191ad30f8e7SGabor Kovesdan 	size_t len;
192ad30f8e7SGabor Kovesdan 
193ad30f8e7SGabor Kovesdan 	len = _region_size(r);
194ad30f8e7SGabor Kovesdan 	z1.begin = _bcs_skip_ws_len(_region_head(r), &len);
195ad30f8e7SGabor Kovesdan 	if (len == 0)
196ad30f8e7SGabor Kovesdan 		return (EFTYPE);
197ad30f8e7SGabor Kovesdan 	z1.end = _bcs_skip_nonws_len(z1.begin, &len);
198ad30f8e7SGabor Kovesdan 	if (len == 0)
199ad30f8e7SGabor Kovesdan 		return (EFTYPE);
200ad30f8e7SGabor Kovesdan 	z2.begin = _bcs_skip_ws_len(z1.end, &len);
201ad30f8e7SGabor Kovesdan 	if (len == 0)
202ad30f8e7SGabor Kovesdan 		return (EFTYPE);
203ad30f8e7SGabor Kovesdan 	z2.end = _bcs_skip_nonws_len(z2.begin, &len);
204ad30f8e7SGabor Kovesdan 
205ad30f8e7SGabor Kovesdan 	/* z1 : dst name, z2 : norm */
206ad30f8e7SGabor Kovesdan 	snprintf(pa->dst, sizeof(pa->dst),
207ad30f8e7SGabor Kovesdan 	    "%.*s", (int)(z1.end-z1.begin), z1.begin);
208ad30f8e7SGabor Kovesdan 	snprintf(buf, sizeof(buf),
209ad30f8e7SGabor Kovesdan 	    "%.*s", (int)(z2.end-z2.begin), z2.begin);
210ad30f8e7SGabor Kovesdan 	pa->norm = _bcs_strtoul(buf, NULL, 0);
211ad30f8e7SGabor Kovesdan 
212ad30f8e7SGabor Kovesdan 	return (0);
213ad30f8e7SGabor Kovesdan }
214ad30f8e7SGabor Kovesdan 
215ad30f8e7SGabor Kovesdan static int
find_dst(struct parse_arg * pasrc,const char * dst)216ad30f8e7SGabor Kovesdan find_dst(struct parse_arg *pasrc, const char *dst)
217ad30f8e7SGabor Kovesdan {
218ad30f8e7SGabor Kovesdan 	struct _lookup *cl;
219ad30f8e7SGabor Kovesdan 	struct parse_arg padst;
220ad30f8e7SGabor Kovesdan 	struct _region data;
221ad30f8e7SGabor Kovesdan 	int ret;
222ad30f8e7SGabor Kovesdan 
223ad30f8e7SGabor Kovesdan 	ret = _lookup_seq_open(&cl, CS_PIVOT, _LOOKUP_CASE_IGNORE);
224ad30f8e7SGabor Kovesdan 	if (ret)
225ad30f8e7SGabor Kovesdan 		return (ret);
226ad30f8e7SGabor Kovesdan 
227ad30f8e7SGabor Kovesdan 	ret = _lookup_seq_lookup(cl, pasrc->dst, &data);
228ad30f8e7SGabor Kovesdan 	while (ret == 0) {
229ad30f8e7SGabor Kovesdan 		ret = parse_line(&padst, &data);
230ad30f8e7SGabor Kovesdan 		if (ret)
231ad30f8e7SGabor Kovesdan 			break;
232ad30f8e7SGabor Kovesdan 		if (strcmp(dst, padst.dst) == 0) {
233ad30f8e7SGabor Kovesdan 			pasrc->norm += padst.norm;
234ad30f8e7SGabor Kovesdan 			break;
235ad30f8e7SGabor Kovesdan 		}
236ad30f8e7SGabor Kovesdan 		ret = _lookup_seq_next(cl, NULL, &data);
237ad30f8e7SGabor Kovesdan 	}
238ad30f8e7SGabor Kovesdan 	_lookup_seq_close(cl);
239ad30f8e7SGabor Kovesdan 
240ad30f8e7SGabor Kovesdan 	return (ret);
241ad30f8e7SGabor Kovesdan }
242ad30f8e7SGabor Kovesdan 
243ad30f8e7SGabor Kovesdan static int
find_best_pivot_lookup(const char * src,const char * dst,char * pivot,size_t pvlen,unsigned long * rnorm)244ad30f8e7SGabor Kovesdan find_best_pivot_lookup(const char *src, const char *dst, char *pivot,
245ad30f8e7SGabor Kovesdan     size_t pvlen, unsigned long *rnorm)
246ad30f8e7SGabor Kovesdan {
247ad30f8e7SGabor Kovesdan 	struct _lookup *cl;
248ad30f8e7SGabor Kovesdan 	struct _region data;
249ad30f8e7SGabor Kovesdan 	struct parse_arg pa;
250ad30f8e7SGabor Kovesdan 	char pivot_min[PATH_MAX];
251ad30f8e7SGabor Kovesdan 	unsigned long norm_min;
252ad30f8e7SGabor Kovesdan 	int ret;
253ad30f8e7SGabor Kovesdan 
254ad30f8e7SGabor Kovesdan 	ret = _lookup_seq_open(&cl, CS_PIVOT, _LOOKUP_CASE_IGNORE);
255ad30f8e7SGabor Kovesdan 	if (ret)
256ad30f8e7SGabor Kovesdan 		return (ret);
257ad30f8e7SGabor Kovesdan 
258ad30f8e7SGabor Kovesdan 	norm_min = ULONG_MAX;
259ad30f8e7SGabor Kovesdan 
260ad30f8e7SGabor Kovesdan 	/* find pivot code */
261ad30f8e7SGabor Kovesdan 	ret = _lookup_seq_lookup(cl, src, &data);
262ad30f8e7SGabor Kovesdan 	while (ret == 0) {
263ad30f8e7SGabor Kovesdan 		ret = parse_line(&pa, &data);
264ad30f8e7SGabor Kovesdan 		if (ret)
265ad30f8e7SGabor Kovesdan 			break;
266ad30f8e7SGabor Kovesdan 		ret = find_dst(&pa, dst);
267ad30f8e7SGabor Kovesdan 		if (ret)
268ad30f8e7SGabor Kovesdan 			break;
269ad30f8e7SGabor Kovesdan 		if (pa.norm < norm_min) {
270ad30f8e7SGabor Kovesdan 			norm_min = pa.norm;
271ad30f8e7SGabor Kovesdan 			strlcpy(pivot_min, pa.dst, sizeof(pivot_min));
272ad30f8e7SGabor Kovesdan 		}
273ad30f8e7SGabor Kovesdan 		ret = _lookup_seq_next(cl, NULL, &data);
274ad30f8e7SGabor Kovesdan 	}
275ad30f8e7SGabor Kovesdan 	_lookup_seq_close(cl);
276ad30f8e7SGabor Kovesdan 
277ad30f8e7SGabor Kovesdan 	if (ret != ENOENT)
278ad30f8e7SGabor Kovesdan 		return (ret);
279ad30f8e7SGabor Kovesdan 	if (norm_min == ULONG_MAX)
280ad30f8e7SGabor Kovesdan 		return (ENOENT);
281ad30f8e7SGabor Kovesdan 	strlcpy(pivot, pivot_min, pvlen);
282ad30f8e7SGabor Kovesdan 	if (rnorm)
283ad30f8e7SGabor Kovesdan 		*rnorm = norm_min;
284ad30f8e7SGabor Kovesdan 
285ad30f8e7SGabor Kovesdan 	return (0);
286ad30f8e7SGabor Kovesdan }
287ad30f8e7SGabor Kovesdan 
288ad30f8e7SGabor Kovesdan static int
find_best_pivot(const char * src,const char * dst,char * pivot,size_t pvlen,unsigned long * rnorm)289ad30f8e7SGabor Kovesdan find_best_pivot(const char *src, const char *dst, char *pivot, size_t pvlen,
290ad30f8e7SGabor Kovesdan     unsigned long *rnorm)
291ad30f8e7SGabor Kovesdan {
292ad30f8e7SGabor Kovesdan 	int ret;
293ad30f8e7SGabor Kovesdan 
294ad30f8e7SGabor Kovesdan 	ret = find_best_pivot_pvdb(src, dst, pivot, pvlen, rnorm);
295ad30f8e7SGabor Kovesdan 	if (ret == NO_SUCH_FILE)
296ad30f8e7SGabor Kovesdan 		ret = find_best_pivot_lookup(src, dst, pivot, pvlen, rnorm);
297ad30f8e7SGabor Kovesdan 
298ad30f8e7SGabor Kovesdan 	return (ret);
299ad30f8e7SGabor Kovesdan }
300ad30f8e7SGabor Kovesdan 
301ad30f8e7SGabor Kovesdan static __inline int
open_serial_mapper(struct _citrus_mapper_area * __restrict ma,struct _citrus_mapper * __restrict * __restrict rcm,const char * src,const char * pivot,const char * dst)302ad30f8e7SGabor Kovesdan open_serial_mapper(struct _citrus_mapper_area *__restrict ma,
303ad30f8e7SGabor Kovesdan     struct _citrus_mapper * __restrict * __restrict rcm,
304ad30f8e7SGabor Kovesdan     const char *src, const char *pivot, const char *dst)
305ad30f8e7SGabor Kovesdan {
306ad30f8e7SGabor Kovesdan 	char buf[PATH_MAX];
307ad30f8e7SGabor Kovesdan 
308ad30f8e7SGabor Kovesdan 	snprintf(buf, sizeof(buf), "%s/%s,%s/%s", src, pivot, pivot, dst);
309ad30f8e7SGabor Kovesdan 
310ad30f8e7SGabor Kovesdan 	return (_mapper_open_direct(ma, rcm, "mapper_serial", buf));
311ad30f8e7SGabor Kovesdan }
312ad30f8e7SGabor Kovesdan 
313ad30f8e7SGabor Kovesdan static struct _citrus_csmapper *csm_none = NULL;
314ad30f8e7SGabor Kovesdan static int
get_none(struct _citrus_mapper_area * __restrict ma,struct _citrus_csmapper * __restrict * __restrict rcsm)315ad30f8e7SGabor Kovesdan get_none(struct _citrus_mapper_area *__restrict ma,
316ad30f8e7SGabor Kovesdan     struct _citrus_csmapper *__restrict *__restrict rcsm)
317ad30f8e7SGabor Kovesdan {
318ad30f8e7SGabor Kovesdan 	int ret;
319ad30f8e7SGabor Kovesdan 
320ff0b75b8SPeter Wemm 	WLOCK(&ma_lock);
321ad30f8e7SGabor Kovesdan 	if (csm_none) {
322ad30f8e7SGabor Kovesdan 		*rcsm = csm_none;
323ad30f8e7SGabor Kovesdan 		ret = 0;
324ad30f8e7SGabor Kovesdan 		goto quit;
325ad30f8e7SGabor Kovesdan 	}
326ad30f8e7SGabor Kovesdan 
327ad30f8e7SGabor Kovesdan 	ret = _mapper_open_direct(ma, &csm_none, "mapper_none", "");
328ad30f8e7SGabor Kovesdan 	if (ret)
329ad30f8e7SGabor Kovesdan 		goto quit;
330ad30f8e7SGabor Kovesdan 	_mapper_set_persistent(csm_none);
331ad30f8e7SGabor Kovesdan 
332ad30f8e7SGabor Kovesdan 	*rcsm = csm_none;
333ad30f8e7SGabor Kovesdan 	ret = 0;
334ad30f8e7SGabor Kovesdan quit:
335ff0b75b8SPeter Wemm 	UNLOCK(&ma_lock);
336ad30f8e7SGabor Kovesdan 	return (ret);
337ad30f8e7SGabor Kovesdan }
338ad30f8e7SGabor Kovesdan 
339ad30f8e7SGabor Kovesdan int
_citrus_csmapper_open(struct _citrus_csmapper * __restrict * __restrict rcsm,const char * __restrict src,const char * __restrict dst,uint32_t flags,unsigned long * rnorm)340ad30f8e7SGabor Kovesdan _citrus_csmapper_open(struct _citrus_csmapper * __restrict * __restrict rcsm,
341ad30f8e7SGabor Kovesdan     const char * __restrict src, const char * __restrict dst, uint32_t flags,
342ad30f8e7SGabor Kovesdan     unsigned long *rnorm)
343ad30f8e7SGabor Kovesdan {
344ad30f8e7SGabor Kovesdan 	const char *realsrc, *realdst;
345ad30f8e7SGabor Kovesdan 	char buf1[PATH_MAX], buf2[PATH_MAX], key[PATH_MAX], pivot[PATH_MAX];
346ad30f8e7SGabor Kovesdan 	unsigned long norm;
347ad30f8e7SGabor Kovesdan 	int ret;
348ad30f8e7SGabor Kovesdan 
349ad30f8e7SGabor Kovesdan 	norm = 0;
350ad30f8e7SGabor Kovesdan 
351ad30f8e7SGabor Kovesdan 	ret = _citrus_mapper_create_area(&maparea, _PATH_CSMAPPER);
352ad30f8e7SGabor Kovesdan 	if (ret)
353ad30f8e7SGabor Kovesdan 		return (ret);
354ad30f8e7SGabor Kovesdan 
355ad30f8e7SGabor Kovesdan 	realsrc = _lookup_alias(CS_ALIAS, src, buf1, sizeof(buf1),
356ad30f8e7SGabor Kovesdan 	    _LOOKUP_CASE_IGNORE);
357ad30f8e7SGabor Kovesdan 	realdst = _lookup_alias(CS_ALIAS, dst, buf2, sizeof(buf2),
358ad30f8e7SGabor Kovesdan 	    _LOOKUP_CASE_IGNORE);
359ad30f8e7SGabor Kovesdan 	if (!strcmp(realsrc, realdst)) {
360ad30f8e7SGabor Kovesdan 		ret = get_none(maparea, rcsm);
361ad30f8e7SGabor Kovesdan 		if (ret == 0 && rnorm != NULL)
362ad30f8e7SGabor Kovesdan 			*rnorm = 0;
363ad30f8e7SGabor Kovesdan 		return (ret);
364ad30f8e7SGabor Kovesdan 	}
365ad30f8e7SGabor Kovesdan 
366ad30f8e7SGabor Kovesdan 	snprintf(key, sizeof(key), "%s/%s", realsrc, realdst);
367ad30f8e7SGabor Kovesdan 
368ad30f8e7SGabor Kovesdan 	ret = _mapper_open(maparea, rcsm, key);
369ad30f8e7SGabor Kovesdan 	if (ret == 0) {
370ad30f8e7SGabor Kovesdan 		if (rnorm != NULL)
371ad30f8e7SGabor Kovesdan 			*rnorm = 0;
372ad30f8e7SGabor Kovesdan 		return (0);
373ad30f8e7SGabor Kovesdan 	}
374ad30f8e7SGabor Kovesdan 	if (ret != ENOENT || (flags & _CSMAPPER_F_PREVENT_PIVOT)!=0)
375ad30f8e7SGabor Kovesdan 		return (ret);
376ad30f8e7SGabor Kovesdan 
377ad30f8e7SGabor Kovesdan 	ret = find_best_pivot(realsrc, realdst, pivot, sizeof(pivot), &norm);
378ad30f8e7SGabor Kovesdan 	if (ret)
379ad30f8e7SGabor Kovesdan 		return (ret);
380ad30f8e7SGabor Kovesdan 
381ad30f8e7SGabor Kovesdan 	ret = open_serial_mapper(maparea, rcsm, realsrc, pivot, realdst);
382ad30f8e7SGabor Kovesdan 	if (ret == 0 && rnorm != NULL)
383ad30f8e7SGabor Kovesdan 		*rnorm = norm;
384ad30f8e7SGabor Kovesdan 
385ad30f8e7SGabor Kovesdan 	return (ret);
386ad30f8e7SGabor Kovesdan }
387