LCOV - code coverage report
Current view: top level - source4/ntvfs/posix - pvfs_shortname.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 190 245 77.6 %
Date: 2024-04-21 15:09:00 Functions: 15 17 88.2 %

          Line data    Source code
       1             : /* 
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    POSIX NTVFS backend - 8.3 name routines
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2004
       7             : 
       8             :    This program is free software; you can redistribute it and/or modify
       9             :    it under the terms of the GNU General Public License as published by
      10             :    the Free Software Foundation; either version 3 of the License, or
      11             :    (at your option) any later version.
      12             :    
      13             :    This program is distributed in the hope that it will be useful,
      14             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :    GNU General Public License for more details.
      17             :    
      18             :    You should have received a copy of the GNU General Public License
      19             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "includes.h"
      23             : #include "system/locale.h"
      24             : #include "vfs_posix.h"
      25             : #include "param/param.h"
      26             : 
      27             : #undef strcasecmp
      28             : 
      29             : /*
      30             :   this mangling scheme uses the following format
      31             : 
      32             :   Annnn~n.AAA
      33             : 
      34             :   where nnnnn is a base 36 hash, and A represents characters from the original string
      35             : 
      36             :   The hash is taken of the leading part of the long filename, in uppercase
      37             : 
      38             :   for simplicity, we only allow ascii characters in 8.3 names
      39             : */
      40             : 
      41             : /*
      42             :   ===============================================================================
      43             :   NOTE NOTE NOTE!!!
      44             : 
      45             :   This file deliberately uses non-multibyte string functions in many places. This
      46             :   is *not* a mistake. This code is multi-byte safe, but it gets this property
      47             :   through some very subtle knowledge of the way multi-byte strings are encoded 
      48             :   and the fact that this mangling algorithm only supports ascii characters in
      49             :   8.3 names.
      50             : 
      51             :   please don't convert this file to use the *_m() functions!!
      52             :   ===============================================================================
      53             : */
      54             : 
      55             : 
      56             : #if 1
      57             : #define M_DEBUG(level, x) DEBUG(level, x)
      58             : #else
      59             : #define M_DEBUG(level, x)
      60             : #endif
      61             : 
      62             : /* these flags are used to mark characters in as having particular
      63             :    properties */
      64             : #define FLAG_BASECHAR 1
      65             : #define FLAG_ASCII 2
      66             : #define FLAG_ILLEGAL 4
      67             : #define FLAG_WILDCARD 8
      68             : 
      69             : /* the "possible" flags are used as a fast way to find possible DOS
      70             :    reserved filenames */
      71             : #define FLAG_POSSIBLE1 16
      72             : #define FLAG_POSSIBLE2 32
      73             : #define FLAG_POSSIBLE3 64
      74             : #define FLAG_POSSIBLE4 128
      75             : 
      76             : #define DEFAULT_MANGLE_PREFIX 4
      77             : 
      78             : #define MANGLE_BASECHARS "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
      79             : 
      80             : #define FLAG_CHECK(c, flag) (ctx->char_flags[(uint8_t)(c)] & (flag))
      81             : 
      82             : static const char *reserved_names[] = 
      83             : { "AUX", "CON",
      84             :   "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9",
      85             :   "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9",
      86             :   "NUL", "PRN", NULL };
      87             : 
      88             : 
      89             : struct pvfs_mangle_context {
      90             :         uint8_t char_flags[256];
      91             :         /*
      92             :           this determines how many characters are used from the original
      93             :           filename in the 8.3 mangled name. A larger value leads to a weaker
      94             :           hash and more collisions.  The largest possible value is 6.
      95             :         */
      96             :         int mangle_prefix;
      97             :         uint32_t mangle_modulus;
      98             : 
      99             :         /* we will use a very simple direct mapped prefix cache. The big
     100             :            advantage of this cache structure is speed and low memory usage 
     101             : 
     102             :            The cache is indexed by the low-order bits of the hash, and confirmed by
     103             :            hashing the resulting cache entry to match the known hash
     104             :         */
     105             :         uint32_t cache_size;
     106             :         char **prefix_cache;
     107             :         uint32_t *prefix_cache_hashes;
     108             : 
     109             :         /* this is used to reverse the base 36 mapping */
     110             :         unsigned char base_reverse[256];
     111             : };
     112             : 
     113             : 
     114             : /* 
     115             :    hash a string of the specified length. The string does not need to be
     116             :    null terminated 
     117             : 
     118             :    this hash needs to be fast with a low collision rate (what hash doesn't?)
     119             : */
     120      361831 : static uint32_t mangle_hash(struct pvfs_mangle_context *ctx,
     121             :                             const char *key, size_t length)
     122             : {
     123      361831 :         return pvfs_name_hash(key, length) % ctx->mangle_modulus;
     124             : }
     125             : 
     126             : /*
     127             :   insert an entry into the prefix cache. The string might not be null
     128             :   terminated */
     129      361831 : static void cache_insert(struct pvfs_mangle_context *ctx,
     130             :                          const char *prefix, int length, uint32_t hash)
     131             : {
     132      361831 :         int i = hash % ctx->cache_size;
     133             : 
     134      361831 :         if (ctx->prefix_cache[i]) {
     135      356048 :                 talloc_free(ctx->prefix_cache[i]);
     136             :         }
     137             : 
     138      361831 :         ctx->prefix_cache[i] = talloc_strndup(ctx->prefix_cache, prefix, length);
     139      361831 :         ctx->prefix_cache_hashes[i] = hash;
     140      361831 : }
     141             : 
     142             : /*
     143             :   lookup an entry in the prefix cache. Return NULL if not found.
     144             : */
     145          26 : static const char *cache_lookup(struct pvfs_mangle_context *ctx, uint32_t hash)
     146             : {
     147          26 :         int i = hash % ctx->cache_size;
     148             : 
     149             : 
     150          26 :         if (!ctx->prefix_cache[i] || hash != ctx->prefix_cache_hashes[i]) {
     151           0 :                 return NULL;
     152             :         }
     153             : 
     154             :         /* yep, it matched */
     155          26 :         return ctx->prefix_cache[i];
     156             : }
     157             : 
     158             : 
     159             : /* 
     160             :    determine if a string is possibly in a mangled format, ignoring
     161             :    case 
     162             : 
     163             :    In this algorithm, mangled names use only pure ascii characters (no
     164             :    multi-byte) so we can avoid doing a UCS2 conversion 
     165             :  */
     166      463024 : static bool is_mangled_component(struct pvfs_mangle_context *ctx,
     167             :                                  const char *name, size_t len)
     168             : {
     169           0 :         unsigned int i;
     170             : 
     171      463024 :         M_DEBUG(10,("is_mangled_component %s (len %u) ?\n", name, (unsigned int)len));
     172             : 
     173             :         /* check the length */
     174      463024 :         if (len > 12 || len < 8)
     175      294097 :                 return false;
     176             : 
     177             :         /* the best distinguishing characteristic is the ~ */
     178      168927 :         if (name[6] != '~')
     179      168901 :                 return false;
     180             : 
     181             :         /* check extension */
     182          26 :         if (len > 8) {
     183           3 :                 if (name[8] != '.')
     184           0 :                         return false;
     185          12 :                 for (i=9; name[i] && i < len; i++) {
     186           9 :                         if (! FLAG_CHECK(name[i], FLAG_ASCII)) {
     187           0 :                                 return false;
     188             :                         }
     189             :                 }
     190             :         }
     191             :         
     192             :         /* check lead characters */
     193         130 :         for (i=0;i<ctx->mangle_prefix;i++) {
     194         104 :                 if (! FLAG_CHECK(name[i], FLAG_ASCII)) {
     195           0 :                         return false;
     196             :                 }
     197             :         }
     198             :         
     199             :         /* check rest of hash */
     200          26 :         if (! FLAG_CHECK(name[7], FLAG_BASECHAR)) {
     201           0 :                 return false;
     202             :         }
     203          78 :         for (i=ctx->mangle_prefix;i<6;i++) {
     204          52 :                 if (! FLAG_CHECK(name[i], FLAG_BASECHAR)) {
     205           0 :                         return false;
     206             :                 }
     207             :         }
     208             : 
     209          26 :         M_DEBUG(10,("is_mangled_component %s (len %u) -> yes\n", name, (unsigned int)len));
     210             : 
     211          26 :         return true;
     212             : }
     213             : 
     214             : 
     215             : 
     216             : /* 
     217             :    determine if a string is possibly in a mangled format, ignoring
     218             :    case 
     219             : 
     220             :    In this algorithm, mangled names use only pure ascii characters (no
     221             :    multi-byte) so we can avoid doing a UCS2 conversion 
     222             : 
     223             :    NOTE! This interface must be able to handle a path with unix
     224             :    directory separators. It should return true if any component is
     225             :    mangled
     226             :  */
     227      463024 : static bool is_mangled(struct pvfs_mangle_context *ctx, const char *name)
     228             : {
     229           0 :         const char *p;
     230           0 :         const char *s;
     231             : 
     232      463024 :         M_DEBUG(10,("is_mangled %s ?\n", name));
     233             : 
     234      463024 :         for (s=name; (p=strchr(s, '/')); s=p+1) {
     235           0 :                 if (is_mangled_component(ctx, s, PTR_DIFF(p, s))) {
     236           0 :                         return true;
     237             :                 }
     238             :         }
     239             :         
     240             :         /* and the last part ... */
     241      463024 :         return is_mangled_component(ctx, s, strlen(s));
     242             : }
     243             : 
     244             : 
     245             : /* 
     246             :    see if a filename is an allowable 8.3 name.
     247             : 
     248             :    we are only going to allow ascii characters in 8.3 names, as this
     249             :    simplifies things greatly (it means that we know the string won't
     250             :    get larger when converted from UNIX to DOS formats)
     251             : */
     252    38133377 : static bool is_8_3(struct pvfs_mangle_context *ctx,
     253             :                    const char *name, bool check_case, bool allow_wildcards)
     254             : {
     255           0 :         int len, i;
     256           0 :         char *dot_p;
     257             : 
     258             :         /* as a special case, the names '.' and '..' are allowable 8.3 names */
     259    38133377 :         if (name[0] == '.') {
     260      349790 :                 if (!name[1] || (name[1] == '.' && !name[2])) {
     261      349765 :                         return true;
     262             :                 }
     263             :         }
     264             : 
     265             :         /* the simplest test is on the overall length of the
     266             :          filename. Note that we deliberately use the ascii string
     267             :          length (not the multi-byte one) as it is faster, and gives us
     268             :          the result we need in this case. Using strlen_m would not
     269             :          only be slower, it would be incorrect */
     270    37783612 :         len = strlen(name);
     271    37783612 :         if (len > 12)
     272      295528 :                 return false;
     273             : 
     274             :         /* find the '.'. Note that once again we use the non-multibyte
     275             :            function */
     276    37488084 :         dot_p = strchr(name, '.');
     277             : 
     278    37488084 :         if (!dot_p) {
     279             :                 /* if the name doesn't contain a '.' then its length
     280             :                    must be less than 8 */
     281    36849144 :                 if (len > 8) {
     282       66003 :                         return false;
     283             :                 }
     284             :         } else {
     285           0 :                 int prefix_len, suffix_len;
     286             : 
     287             :                 /* if it does contain a dot then the prefix must be <=
     288             :                    8 and the suffix <= 3 in length */
     289      638940 :                 prefix_len = PTR_DIFF(dot_p, name);
     290      638940 :                 suffix_len = len - (prefix_len+1);
     291             : 
     292      638940 :                 if (prefix_len > 8 || suffix_len > 3 || suffix_len == 0) {
     293         285 :                         return false;
     294             :                 }
     295             : 
     296             :                 /* a 8.3 name cannot contain more than 1 '.' */
     297      638655 :                 if (strchr(dot_p+1, '.')) {
     298           4 :                         return false;
     299             :                 }
     300             :         }
     301             : 
     302             :         /* the length are all OK. Now check to see if the characters themselves are OK */
     303   218296763 :         for (i=0; name[i]; i++) {
     304             :                 /* note that we may allow wildcard petterns! */
     305   180874982 :                 if (!FLAG_CHECK(name[i], FLAG_ASCII|(allow_wildcards ? FLAG_WILDCARD : 0)) && 
     306      638662 :                     name[i] != '.') {
     307          11 :                         return false;
     308             :                 }
     309             :         }
     310             : 
     311             :         /* it is a good 8.3 name */
     312    37421781 :         return true;
     313             : }
     314             : 
     315             : 
     316             : /*
     317             :   try to find a 8.3 name in the cache, and if found then
     318             :   return the original long name. 
     319             : */
     320      463024 : static char *check_cache(struct pvfs_mangle_context *ctx, 
     321             :                          TALLOC_CTX *mem_ctx, const char *name)
     322             : {
     323           0 :         uint32_t hash, multiplier;
     324           0 :         unsigned int i;
     325           0 :         const char *prefix;
     326           0 :         char extension[4];
     327             : 
     328             :         /* make sure that this is a mangled name from this cache */
     329      463024 :         if (!is_mangled(ctx, name)) {
     330      462998 :                 M_DEBUG(10,("check_cache: %s -> not mangled\n", name));
     331      462998 :                 return NULL;
     332             :         }
     333             : 
     334             :         /* we need to extract the hash from the 8.3 name */
     335          26 :         hash = ctx->base_reverse[(unsigned char)name[7]];
     336          78 :         for (multiplier=36, i=5;i>=ctx->mangle_prefix;i--) {
     337          52 :                 uint32_t v = ctx->base_reverse[(unsigned char)name[i]];
     338          52 :                 hash += multiplier * v;
     339          52 :                 multiplier *= 36;
     340             :         }
     341             : 
     342             :         /* now look in the prefix cache for that hash */
     343          26 :         prefix = cache_lookup(ctx, hash);
     344          26 :         if (!prefix) {
     345           0 :                 M_DEBUG(10,("check_cache: %s -> %08X -> not found\n", name, hash));
     346           0 :                 return NULL;
     347             :         }
     348             : 
     349             :         /* we found it - construct the full name */
     350          26 :         if (name[8] == '.') {
     351           3 :                 strncpy(extension, name+9, 3);
     352           3 :                 extension[3] = 0;
     353             :         } else {
     354          23 :                 extension[0] = 0;
     355             :         }
     356             : 
     357          26 :         if (extension[0]) {
     358           3 :                 return talloc_asprintf(mem_ctx, "%s.%s", prefix, extension);
     359             :         }
     360             : 
     361          23 :         return talloc_strdup(mem_ctx, prefix);
     362             : }
     363             : 
     364             : 
     365             : /*
     366             :   look for a DOS reserved name
     367             : */
     368    38596480 : static bool is_reserved_name(struct pvfs_mangle_context *ctx, const char *name)
     369             : {
     370    38596480 :         if (FLAG_CHECK(name[0], FLAG_POSSIBLE1) &&
     371      302572 :             FLAG_CHECK(name[1], FLAG_POSSIBLE2) &&
     372      142824 :             FLAG_CHECK(name[2], FLAG_POSSIBLE3) &&
     373        6103 :             FLAG_CHECK(name[3], FLAG_POSSIBLE4)) {
     374             :                 /* a likely match, scan the lot */
     375             :                 int i;
     376           0 :                 for (i=0; reserved_names[i]; i++) {
     377           0 :                         if (strcasecmp(name, reserved_names[i]) == 0) {
     378           0 :                                 return true;
     379             :                         }
     380             :                 }
     381             :         }
     382             : 
     383    38596480 :         return false;
     384             : }
     385             : 
     386             : 
     387             : /*
     388             :  See if a filename is a legal long filename.
     389             :  A filename ending in a '.' is not legal unless it's "." or "..". JRA.
     390             : */
     391           0 : static bool is_legal_name(struct pvfs_mangle_context *ctx, const char *name)
     392             : {
     393           0 :         while (*name) {
     394           0 :                 size_t c_size;
     395           0 :                 codepoint_t c = next_codepoint(name, &c_size);
     396           0 :                 if (c == INVALID_CODEPOINT) {
     397           0 :                         return false;
     398             :                 }
     399             :                 /* all high chars are OK */
     400           0 :                 if (c >= 128) {
     401           0 :                         name += c_size;
     402           0 :                         continue;
     403             :                 }
     404           0 :                 if (FLAG_CHECK(c, FLAG_ILLEGAL)) {
     405           0 :                         return false;
     406             :                 }
     407           0 :                 name += c_size;
     408             :         }
     409             : 
     410           0 :         return true;
     411             : }
     412             : 
     413             : /*
     414             :   the main forward mapping function, which converts a long filename to 
     415             :   a 8.3 name
     416             : 
     417             :   if need83 is not set then we only do the mangling if the name is illegal
     418             :   as a long name
     419             : 
     420             :   if cache83 is not set then we don't cache the result
     421             : 
     422             :   return NULL if we don't need to do any conversion
     423             : */
     424    38133377 : static char *name_map(struct pvfs_mangle_context *ctx,
     425             :                       const char *name, bool need83, bool cache83)
     426             : {
     427           0 :         char *dot_p;
     428           0 :         char lead_chars[7];
     429           0 :         char extension[4];
     430           0 :         unsigned int extension_length, i;
     431           0 :         unsigned int prefix_len;
     432           0 :         uint32_t hash, v;
     433           0 :         char *new_name;
     434    38133377 :         const char *basechars = MANGLE_BASECHARS;
     435             : 
     436             :         /* reserved names are handled specially */
     437    38133377 :         if (!is_reserved_name(ctx, name)) {
     438             :                 /* if the name is already a valid 8.3 name then we don't need to 
     439             :                    do anything */
     440    38133377 :                 if (is_8_3(ctx, name, false, false)) {
     441    37771546 :                         return NULL;
     442             :                 }
     443             : 
     444             :                 /* if the caller doesn't strictly need 8.3 then just check for illegal 
     445             :                    filenames */
     446      361831 :                 if (!need83 && is_legal_name(ctx, name)) {
     447           0 :                         return NULL;
     448             :                 }
     449             :         }
     450             : 
     451             :         /* find the '.' if any */
     452      361831 :         dot_p = strrchr(name, '.');
     453             : 
     454      361831 :         if (dot_p) {
     455             :                 /* if the extension contains any illegal characters or
     456             :                    is too long or zero length then we treat it as part
     457             :                    of the prefix */
     458     1181857 :                 for (i=0; i<4 && dot_p[i+1]; i++) {
     459      886368 :                         if (! FLAG_CHECK(dot_p[i+1], FLAG_ASCII)) {
     460           0 :                                 dot_p = NULL;
     461           0 :                                 break;
     462             :                         }
     463             :                 }
     464      295489 :                 if (i == 0 || i == 4) dot_p = NULL;
     465             :         }
     466             : 
     467             :         /* the leading characters in the mangled name is taken from
     468             :            the first characters of the name, if they are ascii otherwise
     469             :            '_' is used
     470             :         */
     471     1809139 :         for (i=0;i<ctx->mangle_prefix && name[i];i++) {
     472     1447308 :                 lead_chars[i] = name[i];
     473     1447308 :                 if (! FLAG_CHECK(lead_chars[i], FLAG_ASCII)) {
     474         298 :                         lead_chars[i] = '_';
     475             :                 }
     476     1447308 :                 lead_chars[i] = toupper((unsigned char)lead_chars[i]);
     477             :         }
     478      361847 :         for (;i<ctx->mangle_prefix;i++) {
     479          16 :                 lead_chars[i] = '_';
     480             :         }
     481             : 
     482             :         /* the prefix is anything up to the first dot */
     483      361831 :         if (dot_p) {
     484      294706 :                 prefix_len = PTR_DIFF(dot_p, name);
     485             :         } else {
     486       67125 :                 prefix_len = strlen(name);
     487             :         }
     488             : 
     489             :         /* the extension of the mangled name is taken from the first 3
     490             :            ascii chars after the dot */
     491      361831 :         extension_length = 0;
     492      361831 :         if (dot_p) {
     493     1178750 :                 for (i=1; extension_length < 3 && dot_p[i]; i++) {
     494      884044 :                         unsigned char c = dot_p[i];
     495      884044 :                         if (FLAG_CHECK(c, FLAG_ASCII)) {
     496      884044 :                                 extension[extension_length++] = toupper(c);
     497             :                         }
     498             :                 }
     499             :         }
     500             :            
     501             :         /* find the hash for this prefix */
     502      361831 :         v = hash = mangle_hash(ctx, name, prefix_len);
     503             : 
     504      361831 :         new_name = talloc_array(ctx, char, 13);
     505      361831 :         if (new_name == NULL) {
     506           0 :                 return NULL;
     507             :         }
     508             : 
     509             :         /* now form the mangled name. */
     510     1809155 :         for (i=0;i<ctx->mangle_prefix;i++) {
     511     1447324 :                 new_name[i] = lead_chars[i];
     512             :         }
     513      361831 :         new_name[7] = basechars[v % 36];
     514      361831 :         new_name[6] = '~';      
     515     1085493 :         for (i=5; i>=ctx->mangle_prefix; i--) {
     516      723662 :                 v = v / 36;
     517      723662 :                 new_name[i] = basechars[v % 36];
     518             :         }
     519             : 
     520             :         /* add the extension */
     521      361831 :         if (extension_length) {
     522      294706 :                 new_name[8] = '.';
     523      294706 :                 memcpy(&new_name[9], extension, extension_length);
     524      294706 :                 new_name[9+extension_length] = 0;
     525             :         } else {
     526       67125 :                 new_name[8] = 0;
     527             :         }
     528             : 
     529      361831 :         if (cache83) {
     530             :                 /* put it in the cache */
     531      361831 :                 cache_insert(ctx, name, prefix_len, hash);
     532             :         }
     533             : 
     534      361831 :         M_DEBUG(10,("name_map: %s -> %08X -> %s (cache=%d)\n", 
     535             :                    name, hash, new_name, cache83));
     536             : 
     537      361831 :         return new_name;
     538             : }
     539             : 
     540             : 
     541             : /* initialise the flags table 
     542             : 
     543             :   we allow only a very restricted set of characters as 'ascii' in this
     544             :   mangling backend. This isn't a significant problem as modern clients
     545             :   use the 'long' filenames anyway, and those don't have these
     546             :   restrictions. 
     547             : */
     548        1328 : static void init_tables(struct pvfs_mangle_context *ctx)
     549             : {
     550        1328 :         const char *basechars = MANGLE_BASECHARS;
     551           0 :         int i;
     552             :         /* the list of reserved dos names - all of these are illegal */
     553             : 
     554        1328 :         ZERO_STRUCT(ctx->char_flags);
     555             : 
     556      169984 :         for (i=1;i<128;i++) {
     557      168656 :                 if ((i >= '0' && i <= '9') || 
     558      155376 :                     (i >= 'a' && i <= 'z') || 
     559       49136 :                     (i >= 'A' && i <= 'Z')) {
     560       82336 :                         ctx->char_flags[i] |=  (FLAG_ASCII | FLAG_BASECHAR);
     561             :                 }
     562      168656 :                 if (strchr("_-$~", i)) {
     563        5312 :                         ctx->char_flags[i] |= FLAG_ASCII;
     564             :                 }
     565             : 
     566      168656 :                 if (strchr("*\\/?<>|\":", i)) {
     567       11952 :                         ctx->char_flags[i] |= FLAG_ILLEGAL;
     568             :                 }
     569             : 
     570      168656 :                 if (strchr("*?\"<>", i)) {
     571        6640 :                         ctx->char_flags[i] |= FLAG_WILDCARD;
     572             :                 }
     573             :         }
     574             : 
     575        1328 :         ZERO_STRUCT(ctx->base_reverse);
     576       49136 :         for (i=0;i<36;i++) {
     577       47808 :                 ctx->base_reverse[(uint8_t)basechars[i]] = i;
     578             :         }       
     579             : 
     580             :         /* fill in the reserved names flags. These are used as a very
     581             :            fast filter for finding possible DOS reserved filenames */
     582       30544 :         for (i=0; reserved_names[i]; i++) {
     583           0 :                 unsigned char c1, c2, c3, c4;
     584             : 
     585       29216 :                 c1 = (unsigned char)reserved_names[i][0];
     586       29216 :                 c2 = (unsigned char)reserved_names[i][1];
     587       29216 :                 c3 = (unsigned char)reserved_names[i][2];
     588       29216 :                 c4 = (unsigned char)reserved_names[i][3];
     589             : 
     590       29216 :                 ctx->char_flags[c1] |= FLAG_POSSIBLE1;
     591       29216 :                 ctx->char_flags[c2] |= FLAG_POSSIBLE2;
     592       29216 :                 ctx->char_flags[c3] |= FLAG_POSSIBLE3;
     593       29216 :                 ctx->char_flags[c4] |= FLAG_POSSIBLE4;
     594       29216 :                 ctx->char_flags[tolower(c1)] |= FLAG_POSSIBLE1;
     595       29216 :                 ctx->char_flags[tolower(c2)] |= FLAG_POSSIBLE2;
     596       29216 :                 ctx->char_flags[tolower(c3)] |= FLAG_POSSIBLE3;
     597       29216 :                 ctx->char_flags[tolower(c4)] |= FLAG_POSSIBLE4;
     598             : 
     599       29216 :                 ctx->char_flags[(unsigned char)'.'] |= FLAG_POSSIBLE4;
     600             :         }
     601             : 
     602        1328 :         ctx->mangle_modulus = 1;
     603        5312 :         for (i=0;i<(7-ctx->mangle_prefix);i++) {
     604        3984 :                 ctx->mangle_modulus *= 36;
     605             :         }
     606        1328 : }
     607             : 
     608             : /* 
     609             :    initialise the mangling code 
     610             :  */
     611        1328 : NTSTATUS pvfs_mangle_init(struct pvfs_state *pvfs)
     612             : {
     613           0 :         struct pvfs_mangle_context *ctx;
     614             : 
     615        1328 :         ctx = talloc(pvfs, struct pvfs_mangle_context);
     616        1328 :         if (ctx == NULL) {
     617           0 :                 return NT_STATUS_NO_MEMORY;
     618             :         }
     619             : 
     620             :         /* by default have a max of 512 entries in the cache. */
     621        1328 :         ctx->cache_size = lpcfg_parm_int(pvfs->ntvfs->ctx->lp_ctx, NULL, "mangle", "cachesize", 512);
     622             : 
     623        1328 :         ctx->prefix_cache = talloc_array(ctx, char *, ctx->cache_size);
     624        1328 :         if (ctx->prefix_cache == NULL) {
     625           0 :                 return NT_STATUS_NO_MEMORY;
     626             :         }
     627        1328 :         ctx->prefix_cache_hashes = talloc_array(ctx, uint32_t, ctx->cache_size);
     628        1328 :         if (ctx->prefix_cache_hashes == NULL) {
     629           0 :                 return NT_STATUS_NO_MEMORY;
     630             :         }
     631             : 
     632        1328 :         memset(ctx->prefix_cache, 0, sizeof(char *) * ctx->cache_size);
     633        1328 :         memset(ctx->prefix_cache_hashes, 0, sizeof(uint32_t) * ctx->cache_size);
     634             : 
     635        1328 :         ctx->mangle_prefix = lpcfg_parm_int(pvfs->ntvfs->ctx->lp_ctx, NULL, "mangle", "prefix", -1);
     636        1328 :         if (ctx->mangle_prefix < 0 || ctx->mangle_prefix > 6) {
     637        1328 :                 ctx->mangle_prefix = DEFAULT_MANGLE_PREFIX;
     638             :         }
     639             : 
     640        1328 :         init_tables(ctx);
     641             : 
     642        1328 :         pvfs->mangle_ctx = ctx;
     643             : 
     644        1328 :         return NT_STATUS_OK;
     645             : }
     646             : 
     647             : 
     648             : /*
     649             :   return the short name for a component of a full name
     650             : */
     651    38133377 : char *pvfs_short_name_component(struct pvfs_state *pvfs, const char *name)
     652             : {
     653    38133377 :         return name_map(pvfs->mangle_ctx, name, true, true);
     654             : }
     655             : 
     656             : 
     657             : /*
     658             :   return the short name for a given entry in a directory
     659             : */
     660       25900 : const char *pvfs_short_name(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, 
     661             :                             struct pvfs_filename *name)
     662             : {
     663       25900 :         char *p = strrchr(name->full_name, '/');
     664       25900 :         char *ret = pvfs_short_name_component(pvfs, p+1);
     665       25900 :         if (ret == NULL) {
     666       24143 :                 return p+1;
     667             :         }
     668        1757 :         talloc_steal(mem_ctx, ret);
     669        1757 :         return ret;
     670             : }
     671             : 
     672             : /*
     673             :   lookup a mangled name, returning the original long name if present
     674             :   in the cache
     675             : */
     676      463024 : char *pvfs_mangled_lookup(struct pvfs_state *pvfs, TALLOC_CTX *mem_ctx, 
     677             :                           const char *name)
     678             : {
     679      463024 :         return check_cache(pvfs->mangle_ctx, mem_ctx, name);
     680             : }
     681             : 
     682             : 
     683             : /*
     684             :   look for a DOS reserved name
     685             : */
     686      463103 : bool pvfs_is_reserved_name(struct pvfs_state *pvfs, const char *name)
     687             : {
     688      463103 :         return is_reserved_name(pvfs->mangle_ctx, name);
     689             : }
     690             : 
     691             : 
     692             : /*
     693             :   see if a component of a filename could be a mangled name from our
     694             :   mangling code
     695             : */
     696           0 : bool pvfs_is_mangled_component(struct pvfs_state *pvfs, const char *name)
     697             : {
     698           0 :         return is_mangled_component(pvfs->mangle_ctx, name, strlen(name));
     699             : }

Generated by: LCOV version 1.14