180bca3d3SAxel Dörfler/**
280bca3d3SAxel Dörfler * collate.c - NTFS collation handling.  Originated from the Linux-NTFS project.
380bca3d3SAxel Dörfler *
480bca3d3SAxel Dörfler * Copyright (c) 2004 Anton Altaparmakov
580bca3d3SAxel Dörfler * Copyright (c) 2005 Yura Pakhuchiy
680bca3d3SAxel Dörfler *
780bca3d3SAxel Dörfler * This program/include file is free software; you can redistribute it and/or
880bca3d3SAxel Dörfler * modify it under the terms of the GNU General Public License as published
980bca3d3SAxel Dörfler * by the Free Software Foundation; either version 2 of the License, or
1080bca3d3SAxel Dörfler * (at your option) any later version.
1180bca3d3SAxel Dörfler *
1280bca3d3SAxel Dörfler * This program/include file is distributed in the hope that it will be
1380bca3d3SAxel Dörfler * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
1580bca3d3SAxel Dörfler * GNU General Public License for more details.
1680bca3d3SAxel Dörfler *
1780bca3d3SAxel Dörfler * You should have received a copy of the GNU General Public License
1880bca3d3SAxel Dörfler * along with this program (in the main directory of the NTFS-3G
1980bca3d3SAxel Dörfler * distribution in the file COPYING); if not, write to the Free Software
2080bca3d3SAxel Dörfler * Foundation,Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
2180bca3d3SAxel Dörfler */
2280bca3d3SAxel Dörfler
2380bca3d3SAxel Dörfler#ifdef HAVE_CONFIG_H
2480bca3d3SAxel Dörfler#include "config.h"
2580bca3d3SAxel Dörfler#endif
260d2c294fSGerasim Troeglazov#ifdef HAVE_STDLIB_H
270d2c294fSGerasim Troeglazov#include <stdlib.h>
280d2c294fSGerasim Troeglazov#endif
2980bca3d3SAxel Dörfler#ifdef HAVE_STRING_H
3080bca3d3SAxel Dörfler#include <string.h>
3180bca3d3SAxel Dörfler#endif
320d2c294fSGerasim Troeglazov#ifdef HAVE_ERRNO_H
330d2c294fSGerasim Troeglazov#include <errno.h>
340d2c294fSGerasim Troeglazov#endif
3580bca3d3SAxel Dörfler
360d2c294fSGerasim Troeglazov#include "attrib.h"
370d2c294fSGerasim Troeglazov#include "index.h"
3880bca3d3SAxel Dörfler#include "collate.h"
3980bca3d3SAxel Dörfler#include "debug.h"
4080bca3d3SAxel Dörfler#include "unistr.h"
4180bca3d3SAxel Dörfler#include "logging.h"
4280bca3d3SAxel Dörfler
4380bca3d3SAxel Dörfler/**
4480bca3d3SAxel Dörfler * ntfs_collate_binary - Which of two binary objects should be listed first
4580bca3d3SAxel Dörfler * @vol: unused
4680bca3d3SAxel Dörfler * @data1:
4780bca3d3SAxel Dörfler * @data1_len:
4880bca3d3SAxel Dörfler * @data2:
4980bca3d3SAxel Dörfler * @data2_len:
5080bca3d3SAxel Dörfler *
5180bca3d3SAxel Dörfler * Description...
5280bca3d3SAxel Dörfler *
5380bca3d3SAxel Dörfler * Returns:
5480bca3d3SAxel Dörfler */
5580bca3d3SAxel Dörflerstatic int ntfs_collate_binary(ntfs_volume *vol __attribute__((unused)),
5680bca3d3SAxel Dörfler		const void *data1, const int data1_len,
5780bca3d3SAxel Dörfler		const void *data2, const int data2_len)
5880bca3d3SAxel Dörfler{
5980bca3d3SAxel Dörfler	int rc;
6080bca3d3SAxel Dörfler
6180bca3d3SAxel Dörfler	ntfs_log_trace("Entering.\n");
6280bca3d3SAxel Dörfler	rc = memcmp(data1, data2, min(data1_len, data2_len));
6380bca3d3SAxel Dörfler	if (!rc && (data1_len != data2_len)) {
6480bca3d3SAxel Dörfler		if (data1_len < data2_len)
6580bca3d3SAxel Dörfler			rc = -1;
6680bca3d3SAxel Dörfler		else
6780bca3d3SAxel Dörfler			rc = 1;
6880bca3d3SAxel Dörfler	}
6980bca3d3SAxel Dörfler	ntfs_log_trace("Done, returning %i.\n", rc);
7080bca3d3SAxel Dörfler	return rc;
7180bca3d3SAxel Dörfler}
7280bca3d3SAxel Dörfler
7380bca3d3SAxel Dörfler/**
7480bca3d3SAxel Dörfler * ntfs_collate_ntofs_ulong - Which of two long ints should be listed first
7580bca3d3SAxel Dörfler * @vol: unused
7680bca3d3SAxel Dörfler * @data1:
7780bca3d3SAxel Dörfler * @data1_len:
7880bca3d3SAxel Dörfler * @data2:
7980bca3d3SAxel Dörfler * @data2_len:
8080bca3d3SAxel Dörfler *
8180bca3d3SAxel Dörfler * Description...
8280bca3d3SAxel Dörfler *
8380bca3d3SAxel Dörfler * Returns:
8480bca3d3SAxel Dörfler */
8580bca3d3SAxel Dörflerstatic int ntfs_collate_ntofs_ulong(ntfs_volume *vol __attribute__((unused)),
8680bca3d3SAxel Dörfler		const void *data1, const int data1_len,
8780bca3d3SAxel Dörfler		const void *data2, const int data2_len)
8880bca3d3SAxel Dörfler{
8980bca3d3SAxel Dörfler	int rc;
9080bca3d3SAxel Dörfler	u32 d1, d2;
9180bca3d3SAxel Dörfler
9280bca3d3SAxel Dörfler	ntfs_log_trace("Entering.\n");
9380bca3d3SAxel Dörfler	if (data1_len != data2_len || data1_len != 4) {
9480bca3d3SAxel Dörfler		ntfs_log_error("data1_len or/and data2_len not equal to 4.\n");
9580bca3d3SAxel Dörfler		return NTFS_COLLATION_ERROR;
9680bca3d3SAxel Dörfler	}
9780bca3d3SAxel Dörfler	d1 = le32_to_cpup(data1);
9880bca3d3SAxel Dörfler	d2 = le32_to_cpup(data2);
9980bca3d3SAxel Dörfler	if (d1 < d2)
10080bca3d3SAxel Dörfler		rc = -1;
10180bca3d3SAxel Dörfler	else {
10280bca3d3SAxel Dörfler		if (d1 == d2)
10380bca3d3SAxel Dörfler			rc = 0;
10480bca3d3SAxel Dörfler		else
10580bca3d3SAxel Dörfler			rc = 1;
10680bca3d3SAxel Dörfler	}
10780bca3d3SAxel Dörfler	ntfs_log_trace("Done, returning %i.\n", rc);
10880bca3d3SAxel Dörfler	return rc;
10980bca3d3SAxel Dörfler}
11080bca3d3SAxel Dörfler
1110d2c294fSGerasim Troeglazov/**
1120d2c294fSGerasim Troeglazov * ntfs_collate_ntofs_ulongs - Which of two le32 arrays should be listed first
1130d2c294fSGerasim Troeglazov *
1140d2c294fSGerasim Troeglazov * Returns: -1, 0 or 1 depending of how the arrays compare
1150d2c294fSGerasim Troeglazov */
1160d2c294fSGerasim Troeglazov
1170d2c294fSGerasim Troeglazovstatic int ntfs_collate_ntofs_ulongs(ntfs_volume *vol __attribute__((unused)),
1180d2c294fSGerasim Troeglazov		const void *data1, const int data1_len,
1190d2c294fSGerasim Troeglazov		const void *data2, const int data2_len)
1200d2c294fSGerasim Troeglazov{
1210d2c294fSGerasim Troeglazov	int rc;
1220d2c294fSGerasim Troeglazov	int len;
1230d2c294fSGerasim Troeglazov	const le32 *p1, *p2;
1240d2c294fSGerasim Troeglazov	u32 d1, d2;
1250d2c294fSGerasim Troeglazov
1260d2c294fSGerasim Troeglazov	ntfs_log_trace("Entering.\n");
1270d2c294fSGerasim Troeglazov	if ((data1_len != data2_len) || (data1_len <= 0) || (data1_len & 3)) {
1280d2c294fSGerasim Troeglazov		ntfs_log_error("data1_len or data2_len not valid\n");
1290d2c294fSGerasim Troeglazov		return NTFS_COLLATION_ERROR;
1300d2c294fSGerasim Troeglazov	}
1310d2c294fSGerasim Troeglazov	p1 = (const le32*)data1;
1320d2c294fSGerasim Troeglazov	p2 = (const le32*)data2;
1330d2c294fSGerasim Troeglazov	len = data1_len;
1340d2c294fSGerasim Troeglazov	do {
1350d2c294fSGerasim Troeglazov		d1 = le32_to_cpup(p1);
1360d2c294fSGerasim Troeglazov		p1++;
1370d2c294fSGerasim Troeglazov		d2 = le32_to_cpup(p2);
1380d2c294fSGerasim Troeglazov		p2++;
1390d2c294fSGerasim Troeglazov	} while ((d1 == d2) && ((len -= 4) > 0));
1400d2c294fSGerasim Troeglazov	if (d1 < d2)
1410d2c294fSGerasim Troeglazov		rc = -1;
1420d2c294fSGerasim Troeglazov	else {
1430d2c294fSGerasim Troeglazov		if (d1 == d2)
1440d2c294fSGerasim Troeglazov			rc = 0;
1450d2c294fSGerasim Troeglazov		else
1460d2c294fSGerasim Troeglazov			rc = 1;
1470d2c294fSGerasim Troeglazov	}
1480d2c294fSGerasim Troeglazov	ntfs_log_trace("Done, returning %i.\n", rc);
1490d2c294fSGerasim Troeglazov	return rc;
1500d2c294fSGerasim Troeglazov}
1510d2c294fSGerasim Troeglazov
1520d2c294fSGerasim Troeglazov/**
1530d2c294fSGerasim Troeglazov * ntfs_collate_ntofs_security_hash - Which of two security descriptors
1540d2c294fSGerasim Troeglazov *                    should be listed first
1550d2c294fSGerasim Troeglazov * @vol: unused
1560d2c294fSGerasim Troeglazov * @data1:
1570d2c294fSGerasim Troeglazov * @data1_len:
1580d2c294fSGerasim Troeglazov * @data2:
1590d2c294fSGerasim Troeglazov * @data2_len:
1600d2c294fSGerasim Troeglazov *
1610d2c294fSGerasim Troeglazov * JPA compare two security hash keys made of two unsigned le32
1620d2c294fSGerasim Troeglazov *
1630d2c294fSGerasim Troeglazov * Returns: -1, 0 or 1 depending of how the keys compare
1640d2c294fSGerasim Troeglazov */
1650d2c294fSGerasim Troeglazovstatic int ntfs_collate_ntofs_security_hash(ntfs_volume *vol __attribute__((unused)),
1660d2c294fSGerasim Troeglazov		const void *data1, const int data1_len,
1670d2c294fSGerasim Troeglazov		const void *data2, const int data2_len)
1680d2c294fSGerasim Troeglazov{
1690d2c294fSGerasim Troeglazov	int rc;
1700d2c294fSGerasim Troeglazov	u32 d1, d2;
1710d2c294fSGerasim Troeglazov	const le32 *p1, *p2;
1720d2c294fSGerasim Troeglazov
1730d2c294fSGerasim Troeglazov	ntfs_log_trace("Entering.\n");
1740d2c294fSGerasim Troeglazov	if (data1_len != data2_len || data1_len != 8) {
1750d2c294fSGerasim Troeglazov		ntfs_log_error("data1_len or/and data2_len not equal to 8.\n");
1760d2c294fSGerasim Troeglazov		return NTFS_COLLATION_ERROR;
1770d2c294fSGerasim Troeglazov	}
1780d2c294fSGerasim Troeglazov	p1 = (const le32*)data1;
1790d2c294fSGerasim Troeglazov	p2 = (const le32*)data2;
1800d2c294fSGerasim Troeglazov	d1 = le32_to_cpup(p1);
1810d2c294fSGerasim Troeglazov	d2 = le32_to_cpup(p2);
1820d2c294fSGerasim Troeglazov	if (d1 < d2)
1830d2c294fSGerasim Troeglazov		rc = -1;
1840d2c294fSGerasim Troeglazov	else {
1850d2c294fSGerasim Troeglazov		if (d1 > d2)
1860d2c294fSGerasim Troeglazov			rc = 1;
1870d2c294fSGerasim Troeglazov		else {
1880d2c294fSGerasim Troeglazov			p1++;
1890d2c294fSGerasim Troeglazov			p2++;
1900d2c294fSGerasim Troeglazov			d1 = le32_to_cpup(p1);
1910d2c294fSGerasim Troeglazov			d2 = le32_to_cpup(p2);
1920d2c294fSGerasim Troeglazov			if (d1 < d2)
1930d2c294fSGerasim Troeglazov				rc = -1;
1940d2c294fSGerasim Troeglazov			else {
1950d2c294fSGerasim Troeglazov				if (d1 > d2)
1960d2c294fSGerasim Troeglazov					rc = 1;
1970d2c294fSGerasim Troeglazov				else
1980d2c294fSGerasim Troeglazov					rc = 0;
1990d2c294fSGerasim Troeglazov			}
2000d2c294fSGerasim Troeglazov		}
2010d2c294fSGerasim Troeglazov	}
2020d2c294fSGerasim Troeglazov	ntfs_log_trace("Done, returning %i.\n", rc);
2030d2c294fSGerasim Troeglazov	return rc;
2040d2c294fSGerasim Troeglazov}
2050d2c294fSGerasim Troeglazov
20680bca3d3SAxel Dörfler/**
20780bca3d3SAxel Dörfler * ntfs_collate_file_name - Which of two filenames should be listed first
20880bca3d3SAxel Dörfler * @vol:
20980bca3d3SAxel Dörfler * @data1:
21080bca3d3SAxel Dörfler * @data1_len: unused
21180bca3d3SAxel Dörfler * @data2:
21280bca3d3SAxel Dörfler * @data2_len: unused
21380bca3d3SAxel Dörfler *
21480bca3d3SAxel Dörfler * Description...
21580bca3d3SAxel Dörfler *
21680bca3d3SAxel Dörfler * Returns:
21780bca3d3SAxel Dörfler */
21880bca3d3SAxel Dörflerstatic int ntfs_collate_file_name(ntfs_volume *vol,
21980bca3d3SAxel Dörfler		const void *data1, const int data1_len __attribute__((unused)),
22080bca3d3SAxel Dörfler		const void *data2, const int data2_len __attribute__((unused)))
22180bca3d3SAxel Dörfler{
2220d2c294fSGerasim Troeglazov	const FILE_NAME_ATTR *file_name_attr1;
2230d2c294fSGerasim Troeglazov	const FILE_NAME_ATTR *file_name_attr2;
22480bca3d3SAxel Dörfler	int rc;
22580bca3d3SAxel Dörfler
22680bca3d3SAxel Dörfler	ntfs_log_trace("Entering.\n");
2270d2c294fSGerasim Troeglazov	file_name_attr1 = (const FILE_NAME_ATTR*)data1;
2280d2c294fSGerasim Troeglazov	file_name_attr2 = (const FILE_NAME_ATTR*)data2;
2290d2c294fSGerasim Troeglazov	rc = ntfs_names_full_collate(
2300d2c294fSGerasim Troeglazov			(ntfschar*)&file_name_attr1->file_name,
2310d2c294fSGerasim Troeglazov			file_name_attr1->file_name_length,
2320d2c294fSGerasim Troeglazov			(ntfschar*)&file_name_attr2->file_name,
2330d2c294fSGerasim Troeglazov			file_name_attr2->file_name_length,
2340d2c294fSGerasim Troeglazov			CASE_SENSITIVE, vol->upcase, vol->upcase_len);
23580bca3d3SAxel Dörfler	ntfs_log_trace("Done, returning %i.\n", rc);
23680bca3d3SAxel Dörfler	return rc;
23780bca3d3SAxel Dörfler}
23880bca3d3SAxel Dörfler
2390d2c294fSGerasim Troeglazov/*
2400d2c294fSGerasim Troeglazov *		Get a pointer to appropriate collation function.
24180bca3d3SAxel Dörfler *
2420d2c294fSGerasim Troeglazov *	Returns NULL if the needed function is not implemented
24380bca3d3SAxel Dörfler */
2440d2c294fSGerasim Troeglazov
2450d2c294fSGerasim TroeglazovCOLLATE ntfs_get_collate_function(COLLATION_RULES cr)
24680bca3d3SAxel Dörfler{
2470d2c294fSGerasim Troeglazov	COLLATE collate;
24880bca3d3SAxel Dörfler
2490d2c294fSGerasim Troeglazov	switch (cr) {
2500d2c294fSGerasim Troeglazov	case COLLATION_BINARY :
2510d2c294fSGerasim Troeglazov		collate = ntfs_collate_binary;
2520d2c294fSGerasim Troeglazov		break;
2530d2c294fSGerasim Troeglazov	case COLLATION_FILE_NAME :
2540d2c294fSGerasim Troeglazov		collate = ntfs_collate_file_name;
2550d2c294fSGerasim Troeglazov		break;
2560d2c294fSGerasim Troeglazov	case COLLATION_NTOFS_SECURITY_HASH :
2570d2c294fSGerasim Troeglazov		collate = ntfs_collate_ntofs_security_hash;
2580d2c294fSGerasim Troeglazov		break;
2590d2c294fSGerasim Troeglazov	case COLLATION_NTOFS_ULONG :
2600d2c294fSGerasim Troeglazov		collate = ntfs_collate_ntofs_ulong;
2610d2c294fSGerasim Troeglazov		break;
2620d2c294fSGerasim Troeglazov	case COLLATION_NTOFS_ULONGS :
2630d2c294fSGerasim Troeglazov		collate = ntfs_collate_ntofs_ulongs;
2640d2c294fSGerasim Troeglazov		break;
2650d2c294fSGerasim Troeglazov	default :
2660d2c294fSGerasim Troeglazov		errno = EOPNOTSUPP;
2670d2c294fSGerasim Troeglazov		collate = (COLLATE)NULL;
2680d2c294fSGerasim Troeglazov		break;
26980bca3d3SAxel Dörfler	}
2700d2c294fSGerasim Troeglazov	return (collate);
27180bca3d3SAxel Dörfler}