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