xref: /onnv-gate/usr/src/lib/libntfs/common/libntfs/collate.c (revision 9663:ace9a2ac3683)
1*9663SMark.Logan@Sun.COM /**
2*9663SMark.Logan@Sun.COM  * collate.c - NTFS collation handling.  Part of the Linux-NTFS project.
3*9663SMark.Logan@Sun.COM  *
4*9663SMark.Logan@Sun.COM  * Copyright (c) 2004 Anton Altaparmakov
5*9663SMark.Logan@Sun.COM  * Copyright (c) 2005 Yura Pakhuchiy
6*9663SMark.Logan@Sun.COM  *
7*9663SMark.Logan@Sun.COM  * This program/include file is free software; you can redistribute it and/or
8*9663SMark.Logan@Sun.COM  * modify it under the terms of the GNU General Public License as published
9*9663SMark.Logan@Sun.COM  * by the Free Software Foundation; either version 2 of the License, or
10*9663SMark.Logan@Sun.COM  * (at your option) any later version.
11*9663SMark.Logan@Sun.COM  *
12*9663SMark.Logan@Sun.COM  * This program/include file is distributed in the hope that it will be
13*9663SMark.Logan@Sun.COM  * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
14*9663SMark.Logan@Sun.COM  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15*9663SMark.Logan@Sun.COM  * GNU General Public License for more details.
16*9663SMark.Logan@Sun.COM  *
17*9663SMark.Logan@Sun.COM  * You should have received a copy of the GNU General Public License
18*9663SMark.Logan@Sun.COM  * along with this program (in the main directory of the Linux-NTFS
19*9663SMark.Logan@Sun.COM  * distribution in the file COPYING); if not, write to the Free Software
20*9663SMark.Logan@Sun.COM  * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21*9663SMark.Logan@Sun.COM  */
22*9663SMark.Logan@Sun.COM 
23*9663SMark.Logan@Sun.COM #ifdef HAVE_CONFIG_H
24*9663SMark.Logan@Sun.COM #include "config.h"
25*9663SMark.Logan@Sun.COM #endif
26*9663SMark.Logan@Sun.COM 
27*9663SMark.Logan@Sun.COM #ifdef HAVE_STRING_H
28*9663SMark.Logan@Sun.COM #include <string.h>
29*9663SMark.Logan@Sun.COM #endif
30*9663SMark.Logan@Sun.COM 
31*9663SMark.Logan@Sun.COM #include "collate.h"
32*9663SMark.Logan@Sun.COM #include "debug.h"
33*9663SMark.Logan@Sun.COM #include "unistr.h"
34*9663SMark.Logan@Sun.COM #include "logging.h"
35*9663SMark.Logan@Sun.COM 
36*9663SMark.Logan@Sun.COM /**
37*9663SMark.Logan@Sun.COM  * ntfs_collate_binary - Which of two binary objects should be listed first
38*9663SMark.Logan@Sun.COM  * @vol: unused
39*9663SMark.Logan@Sun.COM  * @data1:
40*9663SMark.Logan@Sun.COM  * @data1_len:
41*9663SMark.Logan@Sun.COM  * @data2:
42*9663SMark.Logan@Sun.COM  * @data2_len:
43*9663SMark.Logan@Sun.COM  *
44*9663SMark.Logan@Sun.COM  * Description...
45*9663SMark.Logan@Sun.COM  *
46*9663SMark.Logan@Sun.COM  * Returns:
47*9663SMark.Logan@Sun.COM  */
48*9663SMark.Logan@Sun.COM static int ntfs_collate_binary(ntfs_volume *vol __attribute__((unused)),
49*9663SMark.Logan@Sun.COM 		const void *data1, size_t data1_len,
50*9663SMark.Logan@Sun.COM 		const void *data2, size_t data2_len)
51*9663SMark.Logan@Sun.COM {
52*9663SMark.Logan@Sun.COM 	int rc;
53*9663SMark.Logan@Sun.COM 
54*9663SMark.Logan@Sun.COM 	ntfs_log_trace("Entering.\n");
55*9663SMark.Logan@Sun.COM 	rc = memcmp(data1, data2, min(data1_len, data2_len));
56*9663SMark.Logan@Sun.COM 	if (!rc && (data1_len != data2_len)) {
57*9663SMark.Logan@Sun.COM 		if (data1_len < data2_len)
58*9663SMark.Logan@Sun.COM 			rc = -1;
59*9663SMark.Logan@Sun.COM 		else
60*9663SMark.Logan@Sun.COM 			rc = 1;
61*9663SMark.Logan@Sun.COM 	}
62*9663SMark.Logan@Sun.COM 	ntfs_log_trace("Done, returning %i.\n", rc);
63*9663SMark.Logan@Sun.COM 	return rc;
64*9663SMark.Logan@Sun.COM }
65*9663SMark.Logan@Sun.COM 
66*9663SMark.Logan@Sun.COM /**
67*9663SMark.Logan@Sun.COM  * ntfs_collate_ntofs_ulong - Which of two long ints should be listed first
68*9663SMark.Logan@Sun.COM  * @vol: unused
69*9663SMark.Logan@Sun.COM  * @data1:
70*9663SMark.Logan@Sun.COM  * @data1_len:
71*9663SMark.Logan@Sun.COM  * @data2:
72*9663SMark.Logan@Sun.COM  * @data2_len:
73*9663SMark.Logan@Sun.COM  *
74*9663SMark.Logan@Sun.COM  * Description...
75*9663SMark.Logan@Sun.COM  *
76*9663SMark.Logan@Sun.COM  * Returns:
77*9663SMark.Logan@Sun.COM  */
78*9663SMark.Logan@Sun.COM static int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)),
79*9663SMark.Logan@Sun.COM 		const void *data1, size_t data1_len,
80*9663SMark.Logan@Sun.COM 		const void *data2, size_t data2_len)
81*9663SMark.Logan@Sun.COM {
82*9663SMark.Logan@Sun.COM 	int rc;
83*9663SMark.Logan@Sun.COM 	u32 d1, d2;
84*9663SMark.Logan@Sun.COM 
85*9663SMark.Logan@Sun.COM 	ntfs_log_trace("Entering.\n");
86*9663SMark.Logan@Sun.COM 	if (data1_len != data2_len || data1_len != 4) {
87*9663SMark.Logan@Sun.COM 		ntfs_log_error("data1_len or/and data2_len not equal to 4.\n");
88*9663SMark.Logan@Sun.COM 		return NTFS_COLLATION_ERROR;
89*9663SMark.Logan@Sun.COM 	}
90*9663SMark.Logan@Sun.COM 	d1 = le32_to_cpup(data1);
91*9663SMark.Logan@Sun.COM 	d2 = le32_to_cpup(data2);
92*9663SMark.Logan@Sun.COM 	if (d1 < d2)
93*9663SMark.Logan@Sun.COM 		rc = -1;
94*9663SMark.Logan@Sun.COM 	else {
95*9663SMark.Logan@Sun.COM 		if (d1 == d2)
96*9663SMark.Logan@Sun.COM 			rc = 0;
97*9663SMark.Logan@Sun.COM 		else
98*9663SMark.Logan@Sun.COM 			rc = 1;
99*9663SMark.Logan@Sun.COM 	}
100*9663SMark.Logan@Sun.COM 	ntfs_log_trace("Done, returning %i.\n", rc);
101*9663SMark.Logan@Sun.COM 	return rc;
102*9663SMark.Logan@Sun.COM }
103*9663SMark.Logan@Sun.COM 
104*9663SMark.Logan@Sun.COM /**
105*9663SMark.Logan@Sun.COM  * ntfs_collate_file_name - Which of two filenames should be listed first
106*9663SMark.Logan@Sun.COM  * @vol:
107*9663SMark.Logan@Sun.COM  * @data1:
108*9663SMark.Logan@Sun.COM  * @data1_len: unused
109*9663SMark.Logan@Sun.COM  * @data2:
110*9663SMark.Logan@Sun.COM  * @data2_len: unused
111*9663SMark.Logan@Sun.COM  *
112*9663SMark.Logan@Sun.COM  * Description...
113*9663SMark.Logan@Sun.COM  *
114*9663SMark.Logan@Sun.COM  * Returns:
115*9663SMark.Logan@Sun.COM  */
116*9663SMark.Logan@Sun.COM static int ntfs_collate_file_name(ntfs_volume *vol,
117*9663SMark.Logan@Sun.COM 		const void *data1, size_t data1_len __attribute__((unused)),
118*9663SMark.Logan@Sun.COM 		const void *data2, size_t data2_len __attribute__((unused)))
119*9663SMark.Logan@Sun.COM {
120*9663SMark.Logan@Sun.COM 	int rc;
121*9663SMark.Logan@Sun.COM 
122*9663SMark.Logan@Sun.COM 	ntfs_log_trace("Entering.\n");
123*9663SMark.Logan@Sun.COM 	rc = ntfs_file_values_compare(data1, data2, NTFS_COLLATION_ERROR,
124*9663SMark.Logan@Sun.COM 			IGNORE_CASE, vol->upcase, vol->upcase_len);
125*9663SMark.Logan@Sun.COM 	if (!rc)
126*9663SMark.Logan@Sun.COM 		rc = ntfs_file_values_compare(data1, data2,
127*9663SMark.Logan@Sun.COM 				NTFS_COLLATION_ERROR, CASE_SENSITIVE,
128*9663SMark.Logan@Sun.COM 				vol->upcase, vol->upcase_len);
129*9663SMark.Logan@Sun.COM 	ntfs_log_trace("Done, returning %i.\n", rc);
130*9663SMark.Logan@Sun.COM 	return rc;
131*9663SMark.Logan@Sun.COM }
132*9663SMark.Logan@Sun.COM 
133*9663SMark.Logan@Sun.COM typedef int (*ntfs_collate_func_t)(ntfs_volume *, const void *, size_t,
134*9663SMark.Logan@Sun.COM 		const void *, size_t);
135*9663SMark.Logan@Sun.COM 
136*9663SMark.Logan@Sun.COM static ntfs_collate_func_t ntfs_do_collate0x0[3] = {
137*9663SMark.Logan@Sun.COM 	ntfs_collate_binary,
138*9663SMark.Logan@Sun.COM 	ntfs_collate_file_name,
139*9663SMark.Logan@Sun.COM 	NULL/*ntfs_collate_unicode_string*/,
140*9663SMark.Logan@Sun.COM };
141*9663SMark.Logan@Sun.COM 
142*9663SMark.Logan@Sun.COM static ntfs_collate_func_t ntfs_do_collate0x1[4] = {
143*9663SMark.Logan@Sun.COM 	ntfs_collate_ntofs_ulong,
144*9663SMark.Logan@Sun.COM 	NULL/*ntfs_collate_ntofs_sid*/,
145*9663SMark.Logan@Sun.COM 	NULL/*ntfs_collate_ntofs_security_hash*/,
146*9663SMark.Logan@Sun.COM 	NULL/*ntfs_collate_ntofs_ulongs*/,
147*9663SMark.Logan@Sun.COM };
148*9663SMark.Logan@Sun.COM 
149*9663SMark.Logan@Sun.COM /**
150*9663SMark.Logan@Sun.COM  * ntfs_is_collation_rule_supported - Check if a collation rule is implemented.
151*9663SMark.Logan@Sun.COM  * @cr: The to-be-checked collation rule
152*9663SMark.Logan@Sun.COM  *
153*9663SMark.Logan@Sun.COM  * Use this function to know if @cr is supported by libntfs.
154*9663SMark.Logan@Sun.COM  *
155*9663SMark.Logan@Sun.COM  * 7 collation rules are known to be supported by NTFS as defined
156*9663SMark.Logan@Sun.COM  * in layout.h. However, libntfs only support 3 of them ATM.
157*9663SMark.Logan@Sun.COM  *
158*9663SMark.Logan@Sun.COM  * Return TRUE if @cr is supported. FALSE otherwise.
159*9663SMark.Logan@Sun.COM  */
160*9663SMark.Logan@Sun.COM BOOL ntfs_is_collation_rule_supported(COLLATION_RULES cr)
161*9663SMark.Logan@Sun.COM {
162*9663SMark.Logan@Sun.COM 	return (cr == COLLATION_BINARY || cr == COLLATION_NTOFS_ULONG ||
163*9663SMark.Logan@Sun.COM 			cr == COLLATION_FILE_NAME);
164*9663SMark.Logan@Sun.COM 	/*
165*9663SMark.Logan@Sun.COM 	 * FIXME:  At the moment we only support COLLATION_BINARY,
166*9663SMark.Logan@Sun.COM 	 * COLLATION_NTOFS_ULONG and COLLATION_FILE_NAME.
167*9663SMark.Logan@Sun.COM 	 * The correct future implementation of this function should be:
168*9663SMark.Logan@Sun.COM 	 *
169*9663SMark.Logan@Sun.COM 	 * u32 i = le32_to_cpu(cr);
170*9663SMark.Logan@Sun.COM 	 * return ((i <= 0x02) || ((i >= 0x10) && (i <= 0x13)));
171*9663SMark.Logan@Sun.COM 	 */
172*9663SMark.Logan@Sun.COM }
173*9663SMark.Logan@Sun.COM 
174*9663SMark.Logan@Sun.COM /**
175*9663SMark.Logan@Sun.COM  * ntfs_collate - collate two data items using a specified collation rule
176*9663SMark.Logan@Sun.COM  * @vol:	ntfs volume to which the data items belong
177*9663SMark.Logan@Sun.COM  * @cr:		collation rule to use when comparing the items
178*9663SMark.Logan@Sun.COM  * @data1:	first data item to collate
179*9663SMark.Logan@Sun.COM  * @data1_len:	length in bytes of @data1
180*9663SMark.Logan@Sun.COM  * @data2:	second data item to collate
181*9663SMark.Logan@Sun.COM  * @data2_len:	length in bytes of @data2
182*9663SMark.Logan@Sun.COM  *
183*9663SMark.Logan@Sun.COM  * Collate the two data items @data1 and @data2 using the collation rule @cr
184*9663SMark.Logan@Sun.COM  * and return -1, 0, or 1 if @data1 is found, respectively, to collate before,
185*9663SMark.Logan@Sun.COM  * to match, or to collate after @data2.
186*9663SMark.Logan@Sun.COM  *
187*9663SMark.Logan@Sun.COM  * For speed we use the collation rule @cr as an index into two tables of
188*9663SMark.Logan@Sun.COM  * function pointers to call the appropriate collation function.
189*9663SMark.Logan@Sun.COM  *
190*9663SMark.Logan@Sun.COM  * Return NTFS_COLLATION_ERROR if error occurred.
191*9663SMark.Logan@Sun.COM  */
192*9663SMark.Logan@Sun.COM int ntfs_collate(ntfs_volume *vol, COLLATION_RULES cr,
193*9663SMark.Logan@Sun.COM 		const void *data1, size_t data1_len,
194*9663SMark.Logan@Sun.COM 		const void *data2, size_t data2_len)
195*9663SMark.Logan@Sun.COM {
196*9663SMark.Logan@Sun.COM 	u32 i;
197*9663SMark.Logan@Sun.COM 
198*9663SMark.Logan@Sun.COM 	ntfs_log_trace("Entering.\n");
199*9663SMark.Logan@Sun.COM 	if (!vol || !data1 || !data2) {
200*9663SMark.Logan@Sun.COM 		ntfs_log_error("Invalid arguments passed.\n");
201*9663SMark.Logan@Sun.COM 		return NTFS_COLLATION_ERROR;
202*9663SMark.Logan@Sun.COM 	}
203*9663SMark.Logan@Sun.COM 
204*9663SMark.Logan@Sun.COM 	if (!ntfs_is_collation_rule_supported(cr))
205*9663SMark.Logan@Sun.COM 		goto err;
206*9663SMark.Logan@Sun.COM 	i = le32_to_cpu(cr);
207*9663SMark.Logan@Sun.COM 	if (i <= 0x02)
208*9663SMark.Logan@Sun.COM 		return ntfs_do_collate0x0[i](vol, data1, data1_len,
209*9663SMark.Logan@Sun.COM 				data2, data2_len);
210*9663SMark.Logan@Sun.COM 	if (i < 0x10)
211*9663SMark.Logan@Sun.COM 		goto err;
212*9663SMark.Logan@Sun.COM 	i -= 0x10;
213*9663SMark.Logan@Sun.COM 	if (i <= 3)
214*9663SMark.Logan@Sun.COM 		return ntfs_do_collate0x1[i](vol, data1, data1_len,
215*9663SMark.Logan@Sun.COM 				data2, data2_len);
216*9663SMark.Logan@Sun.COM err:
217*9663SMark.Logan@Sun.COM 	ntfs_log_debug("Unknown collation rule.\n");
218*9663SMark.Logan@Sun.COM 	return NTFS_COLLATION_ERROR;
219*9663SMark.Logan@Sun.COM }
220