xref: /linux/fs/ntfs/collate.c (revision cdd4dc3aebeab43a72ce0bc2b5bab6f0a80b97a5)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * NTFS kernel collation handling.
4  *
5  * Copyright (c) 2004 Anton Altaparmakov
6  *
7  * Part of this file is based on code from the NTFS-3G.
8  * and is copyrighted by the respective authors below:
9  * Copyright (c) 2004 Anton Altaparmakov
10  * Copyright (c) 2005 Yura Pakhuchiy
11  */
12 
13 #include "collate.h"
14 #include "debug.h"
15 #include "ntfs.h"
16 
17 #include <linux/sort.h>
18 
19 static int ntfs_collate_binary(struct ntfs_volume *vol,
20 		const void *data1, const u32 data1_len,
21 		const void *data2, const u32 data2_len)
22 {
23 	int rc;
24 
25 	rc = memcmp(data1, data2, min(data1_len, data2_len));
26 	if (!rc && (data1_len != data2_len)) {
27 		if (data1_len < data2_len)
28 			rc = -1;
29 		else
30 			rc = 1;
31 	}
32 	return rc;
33 }
34 
35 static int ntfs_collate_ntofs_ulong(struct ntfs_volume *vol,
36 		const void *data1, const u32 data1_len,
37 		const void *data2, const u32 data2_len)
38 {
39 	int rc;
40 	u32 d1 = le32_to_cpup(data1), d2 = le32_to_cpup(data2);
41 
42 	if (data1_len != data2_len || data1_len != 4)
43 		return -EINVAL;
44 
45 	if (d1 < d2)
46 		rc = -1;
47 	else {
48 		if (d1 == d2)
49 			rc = 0;
50 		else
51 			rc = 1;
52 	}
53 	return rc;
54 }
55 
56 /*
57  * ntfs_collate_ntofs_ulongs - Which of two le32 arrays should be listed first
58  * @vol: ntfs volume
59  * @data1: first ulong array to collate
60  * @data1_len: length in bytes of @data1
61  * @data2: second ulong array to collate
62  * @data2_len: length in bytes of @data2
63  *
64  * Returns: -1, 0 or 1 depending of how the arrays compare
65  */
66 static int ntfs_collate_ntofs_ulongs(struct ntfs_volume *vol,
67 		const void *data1, const u32 data1_len,
68 		const void *data2, const u32 data2_len)
69 {
70 	int len;
71 	const __le32 *p1 = data1, *p2 = data2;
72 	u32 d1, d2;
73 
74 	if (data1_len != data2_len || data1_len & 3) {
75 		ntfs_error(vol->sb, "data1_len or data2_len not valid\n");
76 		return -1;
77 	}
78 
79 	len = data1_len;
80 	do {
81 		d1 = le32_to_cpup(p1);
82 		p1++;
83 		d2 = le32_to_cpup(p2);
84 		p2++;
85 	} while (d1 == d2 && (len -= 4) > 0);
86 	return cmp_int(d1, d2);
87 }
88 
89 /*
90  * ntfs_collate_file_name - Which of two filenames should be listed first
91  * @vol: ntfs volume
92  * @data1: first filename to collate
93  * @data1_len: length in bytes of @data1(unused)
94  * @data2: second filename to collate
95  * @data2_len: length in bytes of @data2(unused)
96  */
97 static int ntfs_collate_file_name(struct ntfs_volume *vol,
98 		const void *data1, const u32 data1_len,
99 		const void *data2, const u32 data2_len)
100 {
101 	int rc;
102 
103 	rc = ntfs_file_compare_values(data1, data2, -EINVAL,
104 			IGNORE_CASE, vol->upcase, vol->upcase_len);
105 	if (!rc)
106 		rc = ntfs_file_compare_values(data1, data2,
107 			-EINVAL, CASE_SENSITIVE, vol->upcase, vol->upcase_len);
108 	return rc;
109 }
110 
111 /*
112  * ntfs_collate - collate two data items using a specified collation rule
113  * @vol:	ntfs volume to which the data items belong
114  * @cr:		collation rule to use when comparing the items
115  * @data1:	first data item to collate
116  * @data1_len:	length in bytes of @data1
117  * @data2:	second data item to collate
118  * @data2_len:	length in bytes of @data2
119  *
120  * Collate the two data items @data1 and @data2 using the collation rule @cr
121  * and return -1, 0, ir 1 if @data1 is found, respectively, to collate before,
122  * to match, or to collate after @data2. return -EINVAL if an error occurred.
123  */
124 int ntfs_collate(struct ntfs_volume *vol, __le32 cr,
125 		const void *data1, const u32 data1_len,
126 		const void *data2, const u32 data2_len)
127 {
128 	switch (le32_to_cpu(cr)) {
129 	case le32_to_cpu(COLLATION_BINARY):
130 		return ntfs_collate_binary(vol, data1, data1_len,
131 					   data2, data2_len);
132 	case le32_to_cpu(COLLATION_FILE_NAME):
133 		return ntfs_collate_file_name(vol, data1, data1_len,
134 					      data2, data2_len);
135 	case le32_to_cpu(COLLATION_NTOFS_ULONG):
136 		return ntfs_collate_ntofs_ulong(vol, data1, data1_len,
137 						data2, data2_len);
138 	case le32_to_cpu(COLLATION_NTOFS_ULONGS):
139 		return ntfs_collate_ntofs_ulongs(vol, data1, data1_len,
140 						 data2, data2_len);
141 	default:
142 		ntfs_error(vol->sb, "Unknown collation rule 0x%x",
143 			   le32_to_cpu(cr));
144 		return -EINVAL;
145 	}
146 }
147