/* Unix SMB/Netbios implementation. Version 1.9. Name mangling Copyright (C) Andrew Tridgell 1992-1998 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ #include "includes.h" extern int DEBUGLEVEL; extern int case_default; extern BOOL case_mangle; /**************************************************************************** * Provide a checksum on a string * * Input: s - the nul-terminated character string for which the checksum * will be calculated. * Output: The checksum value calculated for s. * ****************************************************************************/ int str_checksum(char *s) { int res = 0; int c; int i=0; while( *s ) { c = *s; res ^= (c << (i % 15)) ^ (c >> (15-(i%15))); s++; i++; } return(res); } /* str_checksum */ /**************************************************************************** return True if a name is a special msdos reserved name ****************************************************************************/ static BOOL is_reserved_msdos(char *fname) { char upperFname[13]; char *p; StrnCpy (upperFname, fname, 12); /* lpt1.txt and con.txt etc are also illegal */ p=strchr(upperFname,'.'); if (p) *p='\0'; strupper (upperFname); if ((strcmp(upperFname,"CLOCK$") == 0) || (strcmp(upperFname,"CON") == 0) || (strcmp(upperFname,"AUX") == 0) || (strcmp(upperFname,"COM1") == 0) || (strcmp(upperFname,"COM2") == 0) || (strcmp(upperFname,"COM3") == 0) || (strcmp(upperFname,"COM4") == 0) || (strcmp(upperFname,"LPT1") == 0) || (strcmp(upperFname,"LPT2") == 0) || (strcmp(upperFname,"LPT3") == 0) || (strcmp(upperFname,"NUL") == 0) || (strcmp(upperFname,"PRN") == 0)) return (True) ; return (False); } /* is_reserved_msdos */ /**************************************************************************** return True if a name is in 8.3 dos format ****************************************************************************/ BOOL is_8_3(char *fname, BOOL check_case) { int len; char *dot_pos; char *slash_pos = strrchr(fname,'/'); int l; if( slash_pos ) fname = slash_pos+1; len = strlen(fname); DEBUG(5,("checking %s for 8.3\n",fname)); if( check_case && case_mangle ) { switch (case_default) { case CASE_LOWER: if (strhasupper(fname)) return(False); break; case CASE_UPPER: if (strhaslower(fname)) return(False); break; } } /* can't be longer than 12 chars */ if( len == 0 || len > 12 ) return(False); /* can't be an MS-DOS Special file such as lpt1 or even lpt1.txt */ if( is_reserved_msdos(fname) ) return(False); /* can't contain invalid dos chars */ /* Windows use the ANSI charset. But filenames are translated in the PC charset. This Translation may be more or less relaxed depending the Windows application. */ /* %%% A nice improvment to name mangling would be to translate filename to ANSI charset on the smb server host */ dot_pos = strchr(fname,'.'); { char *p = fname; if(lp_client_code_page() == KANJI_CODEPAGE) { dot_pos = 0; while (*p) { if (is_shift_jis (*p)) p += 2; else if (is_kana (*p)) p ++; else { if (*p == '.' && !dot_pos) dot_pos = (char *) p; if (!isdoschar(*p)) return(False); p++; } } } else { while (*p) { if (!isdoschar(*p)) return(False); p++; } } } /* no dot and less than 9 means OK */ if (!dot_pos) return(len <= 8); l = PTR_DIFF(dot_pos,fname); /* base must be at least 1 char except special cases . and .. */ if( l == 0 ) return(strcmp(fname,".") == 0 || strcmp(fname,"..") == 0); /* base can't be greater than 8 */ if( l > 8 ) return(False); if( lp_strip_dot() && len - l == 1 && !strchr(dot_pos+1,'.') ) { *dot_pos = 0; return(True); } /* extension must be between 1 and 3 */ if( (len - l < 2 ) || (len - l > 4) ) return(False); /* extension can't have a dot */ if( strchr(dot_pos+1,'.') ) return(False); /* must be in 8.3 format */ return(True); } /* is_8_3 */ /* -------------------------------------------------------------------------- ** * This section creates and maintains a stack of name mangling results. * The original comments read: "keep a stack of name mangling results - just * so file moves and copies have a chance of working" (whatever that means). * * There are three functions to manage the stack: * reset_mangled_stack() - * push_mangled_name() - * check_mangled_stack() - */ fstring *mangled_stack = NULL; int mangled_stack_size = 0; int mangled_stack_len = 0; /**************************************************************************** * create the mangled stack CRH ****************************************************************************/ void reset_mangled_stack( int size ) { if( mangled_stack ) { free(mangled_stack); mangled_stack_size = 0; mangled_stack_len = 0; } if( size > 0 ) { mangled_stack = (fstring *)malloc( sizeof(fstring) * size ); if( mangled_stack ) mangled_stack_size = size; } else mangled_stack = NULL; } /* create_mangled_stack */ /**************************************************************************** * push a mangled name onto the stack CRH ****************************************************************************/ static void push_mangled_name(char *s) { int i; char *p; /* If the stack doesn't exist... Fail. */ if( !mangled_stack ) return; /* If name is already on the stack, move it to the top. */ for( i=0; i wasn't already there, add it to the top of the stack. */ memmove( mangled_stack[1], mangled_stack[0], sizeof(fstring) * MIN(mangled_stack_len, mangled_stack_size-1) ); strcpy( mangled_stack[0], s ); mangled_stack_len = MIN( mangled_stack_size, mangled_stack_len+1 ); /* Hmmm... * Find the last dot '.' in the name, * if there are any upper case characters past the last dot * and there are no more than three characters past the last dot * then terminate the name *at* the last dot. */ p = strrchr( mangled_stack[0], '.' ); if( p && (!strhasupper(p+1)) && (strlen(p+1) < (size_t)4) ) *p = 0; } /* push_mangled_name */ /**************************************************************************** * check for a name on the mangled name stack CRH ****************************************************************************/ BOOL check_mangled_stack(char *s) { int i; pstring tmpname; char extension[5]; char *p = strrchr( s, '.' ); BOOL check_extension = False; extension[0] = 0; /* If the stack doesn't exist, fail. */ if( !mangled_stack ) return(False); /* If there is a file extension, then we need to play with it, too. */ if( p ) { check_extension = True; StrnCpy( extension, p, 4 ); strlower( extension ); /* XXXXXXX */ } for( i=0; i