0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/slab.h>
0009
0010 #include "types.h"
0011 #include "debug.h"
0012 #include "ntfs.h"
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026 static const u8 legal_ansi_char_array[0x40] = {
0027 0x00, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0028 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0029
0030 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0031 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0032
0033 0x17, 0x07, 0x18, 0x17, 0x17, 0x17, 0x17, 0x17,
0034 0x17, 0x17, 0x18, 0x16, 0x16, 0x17, 0x07, 0x00,
0035
0036 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17, 0x17,
0037 0x17, 0x17, 0x04, 0x16, 0x18, 0x16, 0x18, 0x18,
0038 };
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054 bool ntfs_are_names_equal(const ntfschar *s1, size_t s1_len,
0055 const ntfschar *s2, size_t s2_len, const IGNORE_CASE_BOOL ic,
0056 const ntfschar *upcase, const u32 upcase_size)
0057 {
0058 if (s1_len != s2_len)
0059 return false;
0060 if (ic == CASE_SENSITIVE)
0061 return !ntfs_ucsncmp(s1, s2, s1_len);
0062 return !ntfs_ucsncasecmp(s1, s2, s1_len, upcase, upcase_size);
0063 }
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082
0083 int ntfs_collate_names(const ntfschar *name1, const u32 name1_len,
0084 const ntfschar *name2, const u32 name2_len,
0085 const int err_val, const IGNORE_CASE_BOOL ic,
0086 const ntfschar *upcase, const u32 upcase_len)
0087 {
0088 u32 cnt, min_len;
0089 u16 c1, c2;
0090
0091 min_len = name1_len;
0092 if (name1_len > name2_len)
0093 min_len = name2_len;
0094 for (cnt = 0; cnt < min_len; ++cnt) {
0095 c1 = le16_to_cpu(*name1++);
0096 c2 = le16_to_cpu(*name2++);
0097 if (ic) {
0098 if (c1 < upcase_len)
0099 c1 = le16_to_cpu(upcase[c1]);
0100 if (c2 < upcase_len)
0101 c2 = le16_to_cpu(upcase[c2]);
0102 }
0103 if (c1 < 64 && legal_ansi_char_array[c1] & 8)
0104 return err_val;
0105 if (c1 < c2)
0106 return -1;
0107 if (c1 > c2)
0108 return 1;
0109 }
0110 if (name1_len < name2_len)
0111 return -1;
0112 if (name1_len == name2_len)
0113 return 0;
0114
0115 c1 = le16_to_cpu(*name1);
0116 if (c1 < 64 && legal_ansi_char_array[c1] & 8)
0117 return err_val;
0118 return 1;
0119 }
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135 int ntfs_ucsncmp(const ntfschar *s1, const ntfschar *s2, size_t n)
0136 {
0137 u16 c1, c2;
0138 size_t i;
0139
0140 for (i = 0; i < n; ++i) {
0141 c1 = le16_to_cpu(s1[i]);
0142 c2 = le16_to_cpu(s2[i]);
0143 if (c1 < c2)
0144 return -1;
0145 if (c1 > c2)
0146 return 1;
0147 if (!c1)
0148 break;
0149 }
0150 return 0;
0151 }
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171 int ntfs_ucsncasecmp(const ntfschar *s1, const ntfschar *s2, size_t n,
0172 const ntfschar *upcase, const u32 upcase_size)
0173 {
0174 size_t i;
0175 u16 c1, c2;
0176
0177 for (i = 0; i < n; ++i) {
0178 if ((c1 = le16_to_cpu(s1[i])) < upcase_size)
0179 c1 = le16_to_cpu(upcase[c1]);
0180 if ((c2 = le16_to_cpu(s2[i])) < upcase_size)
0181 c2 = le16_to_cpu(upcase[c2]);
0182 if (c1 < c2)
0183 return -1;
0184 if (c1 > c2)
0185 return 1;
0186 if (!c1)
0187 break;
0188 }
0189 return 0;
0190 }
0191
0192 void ntfs_upcase_name(ntfschar *name, u32 name_len, const ntfschar *upcase,
0193 const u32 upcase_len)
0194 {
0195 u32 i;
0196 u16 u;
0197
0198 for (i = 0; i < name_len; i++)
0199 if ((u = le16_to_cpu(name[i])) < upcase_len)
0200 name[i] = upcase[u];
0201 }
0202
0203 void ntfs_file_upcase_value(FILE_NAME_ATTR *file_name_attr,
0204 const ntfschar *upcase, const u32 upcase_len)
0205 {
0206 ntfs_upcase_name((ntfschar*)&file_name_attr->file_name,
0207 file_name_attr->file_name_length, upcase, upcase_len);
0208 }
0209
0210 int ntfs_file_compare_values(FILE_NAME_ATTR *file_name_attr1,
0211 FILE_NAME_ATTR *file_name_attr2,
0212 const int err_val, const IGNORE_CASE_BOOL ic,
0213 const ntfschar *upcase, const u32 upcase_len)
0214 {
0215 return ntfs_collate_names((ntfschar*)&file_name_attr1->file_name,
0216 file_name_attr1->file_name_length,
0217 (ntfschar*)&file_name_attr2->file_name,
0218 file_name_attr2->file_name_length,
0219 err_val, ic, upcase, upcase_len);
0220 }
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245 int ntfs_nlstoucs(const ntfs_volume *vol, const char *ins,
0246 const int ins_len, ntfschar **outs)
0247 {
0248 struct nls_table *nls = vol->nls_map;
0249 ntfschar *ucs;
0250 wchar_t wc;
0251 int i, o, wc_len;
0252
0253
0254 if (likely(ins)) {
0255 ucs = kmem_cache_alloc(ntfs_name_cache, GFP_NOFS);
0256 if (likely(ucs)) {
0257 for (i = o = 0; i < ins_len; i += wc_len) {
0258 wc_len = nls->char2uni(ins + i, ins_len - i,
0259 &wc);
0260 if (likely(wc_len >= 0 &&
0261 o < NTFS_MAX_NAME_LEN)) {
0262 if (likely(wc)) {
0263 ucs[o++] = cpu_to_le16(wc);
0264 continue;
0265 }
0266 break;
0267 }
0268
0269 goto name_err;
0270 }
0271 ucs[o] = 0;
0272 *outs = ucs;
0273 return o;
0274 }
0275 ntfs_error(vol->sb, "Failed to allocate buffer for converted "
0276 "name from ntfs_name_cache.");
0277 return -ENOMEM;
0278 }
0279 ntfs_error(vol->sb, "Received NULL pointer.");
0280 return -EINVAL;
0281 name_err:
0282 kmem_cache_free(ntfs_name_cache, ucs);
0283 if (wc_len < 0) {
0284 ntfs_error(vol->sb, "Name using character set %s contains "
0285 "characters that cannot be converted to "
0286 "Unicode.", nls->charset);
0287 i = -EILSEQ;
0288 } else {
0289 ntfs_error(vol->sb, "Name is too long (maximum length for a "
0290 "name on NTFS is %d Unicode characters.",
0291 NTFS_MAX_NAME_LEN);
0292 i = -ENAMETOOLONG;
0293 }
0294 return i;
0295 }
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309
0310
0311
0312
0313
0314
0315
0316
0317
0318
0319
0320
0321
0322 int ntfs_ucstonls(const ntfs_volume *vol, const ntfschar *ins,
0323 const int ins_len, unsigned char **outs, int outs_len)
0324 {
0325 struct nls_table *nls = vol->nls_map;
0326 unsigned char *ns;
0327 int i, o, ns_len, wc;
0328
0329
0330 if (ins) {
0331 ns = *outs;
0332 ns_len = outs_len;
0333 if (ns && !ns_len) {
0334 wc = -ENAMETOOLONG;
0335 goto conversion_err;
0336 }
0337 if (!ns) {
0338 ns_len = ins_len * NLS_MAX_CHARSET_SIZE;
0339 ns = kmalloc(ns_len + 1, GFP_NOFS);
0340 if (!ns)
0341 goto mem_err_out;
0342 }
0343 for (i = o = 0; i < ins_len; i++) {
0344 retry: wc = nls->uni2char(le16_to_cpu(ins[i]), ns + o,
0345 ns_len - o);
0346 if (wc > 0) {
0347 o += wc;
0348 continue;
0349 } else if (!wc)
0350 break;
0351 else if (wc == -ENAMETOOLONG && ns != *outs) {
0352 unsigned char *tc;
0353
0354 tc = kmalloc((ns_len + 64) &
0355 ~63, GFP_NOFS);
0356 if (tc) {
0357 memcpy(tc, ns, ns_len);
0358 ns_len = ((ns_len + 64) & ~63) - 1;
0359 kfree(ns);
0360 ns = tc;
0361 goto retry;
0362 }
0363 }
0364 goto conversion_err;
0365 }
0366 ns[o] = 0;
0367 *outs = ns;
0368 return o;
0369 }
0370 ntfs_error(vol->sb, "Received NULL pointer.");
0371 return -EINVAL;
0372 conversion_err:
0373 ntfs_error(vol->sb, "Unicode name contains characters that cannot be "
0374 "converted to character set %s. You might want to "
0375 "try to use the mount option nls=utf8.", nls->charset);
0376 if (ns != *outs)
0377 kfree(ns);
0378 if (wc != -ENAMETOOLONG)
0379 wc = -EILSEQ;
0380 return wc;
0381 mem_err_out:
0382 ntfs_error(vol->sb, "Failed to allocate name!");
0383 return -ENOMEM;
0384 }