1998-11-05 19:48:35 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1998-11-05 19:48:35 +03:00
Samba utility functions
2003-03-19 00:21:21 +03:00
2001-07-04 11:15:53 +04:00
Copyright ( C ) Andrew Tridgell 1992 - 2001
2002-01-25 03:35:14 +03:00
Copyright ( C ) Simo Sorce 2001 - 2002
2003-03-19 00:21:21 +03:00
Copyright ( C ) Martin Pool 2003
2006-07-11 22:01:26 +04:00
Copyright ( C ) James Peach 2006
1998-11-05 19:48:35 +03:00
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
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
1998-11-05 19:48:35 +03:00
( 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 0213 9 , USA .
*/
# include "includes.h"
2003-03-19 00:21:21 +03:00
/**
* @ file
* @ brief String utilities .
* */
2003-03-18 04:48:11 +03:00
2003-02-24 06:09:08 +03:00
/**
2006-06-27 07:07:02 +04:00
* Internal function to get the next token from a string , return False if none
* found . Handles double - quotes . This is the work horse function called by
* next_token ( ) and next_token_no_ltrim ( ) .
*
2003-02-24 06:09:08 +03:00
* Based on a routine by GJC @ VILLAGE . COM .
* Extensively modified by Andrew . Tridgell @ anu . edu . au
2006-06-27 07:07:02 +04:00
*/
static BOOL next_token_internal ( const char * * ptr ,
char * buff ,
const char * sep ,
size_t bufsize ,
2006-06-27 07:59:34 +04:00
BOOL ltrim )
1998-11-05 19:48:35 +03:00
{
2003-08-15 06:25:41 +04:00
char * s ;
2003-06-25 21:41:05 +04:00
char * pbuf ;
2001-06-21 13:10:42 +04:00
BOOL quoted ;
size_t len = 1 ;
2002-10-02 23:12:14 +04:00
if ( ! ptr )
return ( False ) ;
2001-06-21 13:10:42 +04:00
2005-05-31 17:46:45 +04:00
s = ( char * ) * ptr ;
2001-06-21 13:10:42 +04:00
/* default to simple separators */
2002-10-02 23:12:14 +04:00
if ( ! sep )
sep = " \t \n \r " ;
2001-06-21 13:10:42 +04:00
2006-06-27 07:07:02 +04:00
/* find the first non sep char, if left-trimming is requested */
2006-06-27 07:59:34 +04:00
if ( ltrim ) {
while ( * s & & strchr_m ( sep , * s ) )
s + + ;
}
2001-06-21 13:10:42 +04:00
/* nothing left? */
2002-10-02 23:12:14 +04:00
if ( ! * s )
return ( False ) ;
2001-06-21 13:10:42 +04:00
/* copy over the token */
2003-06-25 21:41:05 +04:00
pbuf = buff ;
2001-07-04 11:36:09 +04:00
for ( quoted = False ; len < bufsize & & * s & & ( quoted | | ! strchr_m ( sep , * s ) ) ; s + + ) {
2004-06-09 00:10:26 +04:00
if ( * s = = ' \" ' ) {
2001-06-21 13:10:42 +04:00
quoted = ! quoted ;
} else {
len + + ;
2003-06-25 21:41:05 +04:00
* pbuf + + = * s ;
2001-06-21 13:10:42 +04:00
}
}
* ptr = ( * s ) ? s + 1 : s ;
2003-06-25 21:41:05 +04:00
* pbuf = 0 ;
2001-06-21 13:10:42 +04:00
return ( True ) ;
}
1998-11-05 19:48:35 +03:00
2006-06-27 07:07:02 +04:00
/*
* Get the next token from a string , return False if none found . Handles
* double - quotes . This version trims leading separator characters before
* looking for a token .
*/
BOOL next_token ( const char * * ptr , char * buff , const char * sep , size_t bufsize )
{
return next_token_internal ( ptr , buff , sep , bufsize , True ) ;
}
/*
* Get the next token from a string , return False if none found . Handles
* double - quotes . This version does not trim leading separator characters
* before looking for a token .
*/
BOOL next_token_no_ltrim ( const char * * ptr ,
char * buff ,
const char * sep ,
size_t bufsize )
{
return next_token_internal ( ptr , buff , sep , bufsize , False ) ;
}
2003-02-24 06:09:08 +03:00
/**
2001-06-21 13:10:42 +04:00
This is like next_token but is not re - entrant and " remembers " the first
parameter so you can pass NULL . This is useful for user interface code
but beware the fact that it is not re - entrant !
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
2003-08-15 08:42:05 +04:00
static const char * last_ptr = NULL ;
1998-11-05 19:48:35 +03:00
2003-08-15 08:42:05 +04:00
BOOL next_token_nr ( const char * * ptr , char * buff , const char * sep , size_t bufsize )
2001-06-21 13:10:42 +04:00
{
BOOL ret ;
2002-10-02 23:12:14 +04:00
if ( ! ptr )
2003-08-15 08:42:05 +04:00
ptr = & last_ptr ;
1998-11-05 19:48:35 +03:00
2001-06-21 13:10:42 +04:00
ret = next_token ( ptr , buff , sep , bufsize ) ;
last_ptr = * ptr ;
return ret ;
}
1998-11-05 19:48:35 +03:00
2001-06-21 13:10:42 +04:00
void set_first_token ( char * ptr )
{
last_ptr = ptr ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Convert list of tokens to array ; dependent on above routine .
Uses last_ptr from above - bit of a hack .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
char * * toktocliplist ( int * ctok , const char * sep )
1998-11-05 19:48:35 +03:00
{
2005-05-31 17:46:45 +04:00
char * s = ( char * ) last_ptr ;
2001-06-21 13:10:42 +04:00
int ictok = 0 ;
char * * ret , * * iret ;
2002-10-02 23:12:14 +04:00
if ( ! sep )
sep = " \t \n \r " ;
2001-06-21 13:10:42 +04:00
2002-10-02 23:12:14 +04:00
while ( * s & & strchr_m ( sep , * s ) )
s + + ;
2001-06-21 13:10:42 +04:00
/* nothing left? */
2002-10-02 23:12:14 +04:00
if ( ! * s )
return ( NULL ) ;
2001-06-21 13:10:42 +04:00
do {
ictok + + ;
2002-10-02 23:12:14 +04:00
while ( * s & & ( ! strchr_m ( sep , * s ) ) )
s + + ;
while ( * s & & strchr_m ( sep , * s ) )
* s + + = 0 ;
2001-06-21 13:10:42 +04:00
} while ( * s ) ;
* ctok = ictok ;
2005-05-31 17:46:45 +04:00
s = ( char * ) last_ptr ;
2001-06-21 13:10:42 +04:00
2004-12-07 21:25:53 +03:00
if ( ! ( ret = iret = SMB_MALLOC_ARRAY ( char * , ictok + 1 ) ) )
2002-10-02 23:12:14 +04:00
return NULL ;
2001-06-21 13:10:42 +04:00
while ( ictok - - ) {
* iret + + = s ;
2004-09-16 02:49:23 +04:00
if ( ictok > 0 ) {
while ( * s + + )
;
while ( ! * s )
s + + ;
}
2001-06-21 13:10:42 +04:00
}
2004-09-16 02:49:23 +04:00
ret [ * ctok ] = NULL ;
2001-06-21 13:10:42 +04:00
return ret ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2003-03-19 00:21:21 +03:00
* Case insensitive string compararison .
*
* iconv does not directly give us a way to compare strings in
* arbitrary unix character sets - - all we can is convert and then
* compare . This is expensive .
*
* As an optimization , we do a first pass that considers only the
* prefix of the strings that is entirely 7 - bit . Within this , we
* check whether they have the same value .
*
* Hopefully this will often give the answer without needing to copy .
* In particular it should speed comparisons to literal ascii strings
* or comparisons of strings that are " obviously " different .
*
* If we find a non - ascii character we fall back to converting via
* iconv .
*
* This should never be slower than convering the whole thing , and
* often faster .
*
* A different optimization would be to compare for bitwise equality
* in the binary encoding . ( It would be possible thought hairy to do
* both simultaneously . ) But in that case if they turn out to be
* different , we ' d need to restart the whole thing .
*
* Even better is to implement strcasecmp for each encoding and use a
* function pointer .
* */
1998-11-12 09:12:19 +03:00
int StrCaseCmp ( const char * s , const char * t )
1998-11-05 19:48:35 +03:00
{
2003-03-19 00:21:21 +03:00
2005-08-13 00:12:31 +04:00
const char * ps , * pt ;
2003-07-19 04:36:43 +04:00
size_t size ;
smb_ucs2_t * buffer_s , * buffer_t ;
int ret ;
2003-03-19 00:21:21 +03:00
for ( ps = s , pt = t ; ; ps + + , pt + + ) {
char us , ut ;
if ( ! * ps & & ! * pt )
return 0 ; /* both ended */
else if ( ! * ps )
return - 1 ; /* s is a prefix */
else if ( ! * pt )
return + 1 ; /* t is a prefix */
else if ( ( * ps & 0x80 ) | | ( * pt & 0x80 ) )
/* not ascii anymore, do it the hard way from here on in */
break ;
2005-12-27 23:52:36 +03:00
us = toupper_ascii ( * ps ) ;
ut = toupper_ascii ( * pt ) ;
2003-03-19 00:21:21 +03:00
if ( us = = ut )
continue ;
else if ( us < ut )
return - 1 ;
else if ( us > ut )
return + 1 ;
}
2005-08-13 00:12:31 +04:00
size = push_ucs2_allocate ( & buffer_s , ps ) ;
2003-07-27 06:40:06 +04:00
if ( size = = ( size_t ) - 1 ) {
2005-08-13 00:12:31 +04:00
return strcmp ( ps , pt ) ;
2003-07-19 04:36:43 +04:00
/* Not quite the right answer, but finding the right one
under this failure case is expensive , and it ' s pretty close */
}
2005-08-13 00:12:31 +04:00
size = push_ucs2_allocate ( & buffer_t , pt ) ;
2003-07-27 06:40:06 +04:00
if ( size = = ( size_t ) - 1 ) {
2003-07-19 04:36:43 +04:00
SAFE_FREE ( buffer_s ) ;
2005-08-13 00:12:31 +04:00
return strcmp ( ps , pt ) ;
2003-07-19 04:36:43 +04:00
/* Not quite the right answer, but finding the right one
under this failure case is expensive , and it ' s pretty close */
}
ret = strcasecmp_w ( buffer_s , buffer_t ) ;
SAFE_FREE ( buffer_s ) ;
SAFE_FREE ( buffer_t ) ;
return ret ;
1998-11-05 19:48:35 +03:00
}
2003-03-19 00:21:21 +03:00
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Case insensitive string compararison , length limited .
2003-02-24 06:09:08 +03:00
* */
1998-11-17 23:50:07 +03:00
int StrnCaseCmp ( const char * s , const char * t , size_t n )
1998-11-05 19:48:35 +03:00
{
2001-10-03 16:18:20 +04:00
pstring buf1 , buf2 ;
unix_strupper ( s , strlen ( s ) + 1 , buf1 , sizeof ( buf1 ) ) ;
unix_strupper ( t , strlen ( t ) + 1 , buf2 , sizeof ( buf2 ) ) ;
return strncmp ( buf1 , buf2 , n ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2003-03-18 01:42:01 +03:00
* Compare 2 strings .
*
* @ note The comparison is case - insensitive .
* */
1998-11-12 09:12:19 +03:00
BOOL strequal ( const char * s1 , const char * s2 )
1998-11-05 19:48:35 +03:00
{
2002-10-02 23:12:14 +04:00
if ( s1 = = s2 )
return ( True ) ;
if ( ! s1 | | ! s2 )
return ( False ) ;
1998-11-05 19:48:35 +03:00
2001-07-06 15:50:45 +04:00
return ( StrCaseCmp ( s1 , s2 ) = = 0 ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2003-03-18 01:42:01 +03:00
* Compare 2 strings up to and including the nth char .
*
* @ note The comparison is case - insensitive .
* */
1998-11-17 23:50:07 +03:00
BOOL strnequal ( const char * s1 , const char * s2 , size_t n )
1998-11-05 19:48:35 +03:00
{
2005-08-13 02:59:35 +04:00
if ( s1 = = s2 )
return ( True ) ;
if ( ! s1 | | ! s2 | | ! n )
return ( False ) ;
1998-11-05 19:48:35 +03:00
2005-08-13 02:59:35 +04:00
return ( StrnCaseCmp ( s1 , s2 , n ) = = 0 ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Compare 2 strings ( case sensitive ) .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-17 23:50:07 +03:00
BOOL strcsequal ( const char * s1 , const char * s2 )
1998-11-05 19:48:35 +03:00
{
2005-08-13 02:59:35 +04:00
if ( s1 = = s2 )
return ( True ) ;
if ( ! s1 | | ! s2 )
return ( False ) ;
1998-11-05 19:48:35 +03:00
2005-08-13 02:59:35 +04:00
return ( strcmp ( s1 , s2 ) = = 0 ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2000-08-29 18:33:39 +04:00
Do a case - insensitive , whitespace - ignoring string compare .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
2001-10-31 09:22:19 +03:00
int strwicmp ( const char * psz1 , const char * psz2 )
2000-08-29 18:33:39 +04:00
{
/* if BOTH strings are NULL, return TRUE, if ONE is NULL return */
/* appropriate value. */
if ( psz1 = = psz2 )
return ( 0 ) ;
else if ( psz1 = = NULL )
return ( - 1 ) ;
else if ( psz2 = = NULL )
return ( 1 ) ;
/* sync the strings on first non-whitespace */
2002-10-02 23:12:14 +04:00
while ( 1 ) {
2001-12-20 13:02:30 +03:00
while ( isspace ( ( int ) * psz1 ) )
2000-08-29 18:33:39 +04:00
psz1 + + ;
2001-12-20 13:02:30 +03:00
while ( isspace ( ( int ) * psz2 ) )
2000-08-29 18:33:39 +04:00
psz2 + + ;
2005-12-27 23:52:36 +03:00
if ( toupper_ascii ( * psz1 ) ! = toupper_ascii ( * psz2 ) | | * psz1 = = ' \0 '
2000-08-29 18:33:39 +04:00
| | * psz2 = = ' \0 ' )
break ;
psz1 + + ;
psz2 + + ;
}
return ( * psz1 - * psz2 ) ;
}
1998-11-05 19:48:35 +03:00
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Convert a string to upper case , but don ' t modify it .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
char * strupper_static ( const char * s )
{
static pstring str ;
pstrcpy ( str , s ) ;
2003-07-03 23:11:31 +04:00
strupper_m ( str ) ;
2002-08-17 21:00:51 +04:00
return str ;
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Convert a string to " normal " form .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
2004-05-07 22:37:47 +04:00
void strnorm ( char * s , int case_default )
1998-11-05 19:48:35 +03:00
{
2002-10-02 23:12:14 +04:00
if ( case_default = = CASE_UPPER )
2003-07-03 23:11:31 +04:00
strupper_m ( s ) ;
2002-10-02 23:12:14 +04:00
else
2003-07-03 23:11:31 +04:00
strlower_m ( s ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Check if a string is in " normal " case .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
2004-05-07 22:37:47 +04:00
BOOL strisnormal ( const char * s , int case_default )
1998-11-05 19:48:35 +03:00
{
2001-07-04 11:15:53 +04:00
if ( case_default = = CASE_UPPER )
return ( ! strhaslower ( s ) ) ;
return ( ! strhasupper ( s ) ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
String replace .
NOTE : oldc and newc must be 7 bit characters
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
2007-06-16 15:48:11 +04:00
void string_replace ( char * s , char oldc , char newc )
1998-11-05 19:48:35 +03:00
{
2005-03-22 19:39:09 +03:00
char * p ;
2007-06-16 15:48:11 +04:00
smb_ucs2_t * tmp ;
size_t src_len , len ;
2003-09-05 23:59:55 +04:00
/* this is quite a common operation, so we want it to be
fast . We optimise for the ascii case , knowing that all our
supported multi - byte character sets are ascii - compatible
( ie . they match for the first 128 chars ) */
2005-03-22 19:39:09 +03:00
for ( p = s ; * p ; p + + ) {
2003-09-05 23:59:55 +04:00
if ( * p & 0x80 ) /* mb string - slow path. */
break ;
if ( * p = = oldc )
* p = newc ;
}
if ( ! * p )
return ;
/* Slow (mb) path. */
2003-09-14 02:41:21 +04:00
# ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
/* With compose characters we must restart from the beginning. JRA. */
p = s ;
# endif
2007-06-16 15:48:11 +04:00
src_len = strlen ( p ) ;
len = push_ucs2_allocate ( & tmp , p ) ;
if ( len = = - 1 ) {
return ;
}
string_replace_w ( tmp , UCS2_CHAR ( oldc ) , UCS2_CHAR ( newc ) ) ;
pull_ucs2 ( NULL , p , tmp , src_len + 1 , - 1 , STR_TERMINATE ) ;
SAFE_FREE ( tmp ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2007-03-31 02:25:08 +04:00
* Skip past some strings in a buffer - old version - no checks .
* * */
2002-10-02 23:12:14 +04:00
2007-04-03 00:10:21 +04:00
char * push_skip_string ( char * buf )
1998-11-05 19:48:35 +03:00
{
2007-04-03 00:10:21 +04:00
buf + = strlen ( buf ) + 1 ;
2001-07-04 11:15:53 +04:00
return ( buf ) ;
1998-11-05 19:48:35 +03:00
}
2007-03-31 02:25:08 +04:00
/**
2007-04-03 00:10:21 +04:00
Skip past a string in a buffer . Buffer may not be
2007-03-31 02:25:08 +04:00
null terminated . end_ptr points to the first byte after
then end of the buffer .
* */
2007-04-03 00:10:21 +04:00
char * skip_string ( const char * base , size_t len , char * buf )
2007-03-31 02:25:08 +04:00
{
const char * end_ptr = base + len ;
if ( end_ptr < base | | ! base | | ! buf | | buf > = end_ptr ) {
return NULL ;
}
2007-04-03 00:10:21 +04:00
/* Skip the string */
while ( * buf ) {
2007-03-31 02:25:08 +04:00
buf + + ;
2007-04-03 00:10:21 +04:00
if ( buf > = end_ptr ) {
return NULL ;
}
2007-03-31 02:25:08 +04:00
}
2007-04-03 00:10:21 +04:00
/* Skip the '\0' */
buf + + ;
2007-03-31 02:25:08 +04:00
return buf ;
}
2003-02-24 06:09:08 +03:00
/**
1998-11-05 19:48:35 +03:00
Count the number of characters in a string . Normally this will
be the same as the number of bytes in a string for single byte strings ,
but will be different for multibyte .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-17 23:50:07 +03:00
size_t str_charnum ( const char * s )
1998-11-05 19:48:35 +03:00
{
2003-01-15 21:57:41 +03:00
uint16 tmpbuf2 [ sizeof ( pstring ) ] ;
push_ucs2 ( NULL , tmpbuf2 , s , sizeof ( tmpbuf2 ) , STR_TERMINATE ) ;
return strlen_w ( tmpbuf2 ) ;
}
2003-02-24 06:09:08 +03:00
/**
2003-01-15 21:57:41 +03:00
Count the number of characters in a string . Normally this will
be the same as the number of bytes in a string for single byte strings ,
but will be different for multibyte .
2003-02-24 06:09:08 +03:00
* */
2003-01-15 21:57:41 +03:00
size_t str_ascii_charnum ( const char * s )
{
pstring tmpbuf2 ;
push_ascii ( tmpbuf2 , s , sizeof ( tmpbuf2 ) , STR_TERMINATE ) ;
return strlen ( tmpbuf2 ) ;
1998-11-05 19:48:35 +03:00
}
2003-09-05 23:59:55 +04:00
BOOL trim_char ( char * s , char cfront , char cback )
{
BOOL ret = False ;
char * ep ;
char * fp = s ;
/* Ignore null or empty strings. */
if ( ! s | | ( s [ 0 ] = = ' \0 ' ) )
return False ;
if ( cfront ) {
while ( * fp & & * fp = = cfront )
fp + + ;
if ( ! * fp ) {
/* We ate the string. */
s [ 0 ] = ' \0 ' ;
return True ;
}
if ( fp ! = s )
ret = True ;
}
ep = fp + strlen ( fp ) - 1 ;
if ( cback ) {
/* Attempt ascii only. Bail for mb strings. */
while ( ( ep > = fp ) & & ( * ep = = cback ) ) {
ret = True ;
if ( ( ep > fp ) & & ( ( ( unsigned char ) ep [ - 1 ] ) & 0x80 ) ) {
/* Could be mb... bail back to tim_string. */
char fs [ 2 ] , bs [ 2 ] ;
if ( cfront ) {
fs [ 0 ] = cfront ;
fs [ 1 ] = ' \0 ' ;
}
bs [ 0 ] = cback ;
bs [ 1 ] = ' \0 ' ;
return trim_string ( s , cfront ? fs : NULL , bs ) ;
} else {
ep - - ;
}
}
if ( ep < fp ) {
/* We ate the string. */
s [ 0 ] = ' \0 ' ;
return True ;
}
}
ep [ 1 ] = ' \0 ' ;
memmove ( s , fp , ep - fp + 2 ) ;
return ret ;
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Trim the specified elements off the front and back of a string .
2003-02-24 06:09:08 +03:00
* */
1998-11-05 19:48:35 +03:00
1998-11-17 23:50:07 +03:00
BOOL trim_string ( char * s , const char * front , const char * back )
1998-11-05 19:48:35 +03:00
{
2001-07-04 11:15:53 +04:00
BOOL ret = False ;
size_t front_len ;
size_t back_len ;
size_t len ;
2001-04-16 02:21:04 +04:00
2001-05-11 03:17:46 +04:00
/* Ignore null or empty strings. */
2001-07-04 11:15:53 +04:00
if ( ! s | | ( s [ 0 ] = = ' \0 ' ) )
return False ;
2001-05-11 03:17:46 +04:00
2001-07-04 11:15:53 +04:00
front_len = front ? strlen ( front ) : 0 ;
back_len = back ? strlen ( back ) : 0 ;
1998-11-05 19:48:35 +03:00
2001-07-04 11:15:53 +04:00
len = strlen ( s ) ;
1998-11-05 19:48:35 +03:00
2001-07-04 11:15:53 +04:00
if ( front_len ) {
while ( len & & strncmp ( s , front , front_len ) = = 0 ) {
2003-09-03 04:56:43 +04:00
/* Must use memmove here as src & dest can
* easily overlap . Found by valgrind . JRA . */
memmove ( s , s + front_len , ( len - front_len ) + 1 ) ;
2001-07-04 11:15:53 +04:00
len - = front_len ;
ret = True ;
}
}
if ( back_len ) {
2002-08-17 21:00:51 +04:00
while ( ( len > = back_len ) & & strncmp ( s + len - back_len , back , back_len ) = = 0 ) {
2001-07-04 11:15:53 +04:00
s [ len - back_len ] = ' \0 ' ;
len - = back_len ;
ret = True ;
}
}
return ret ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Does a string have any uppercase chars in it ?
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-17 23:50:07 +03:00
BOOL strhasupper ( const char * s )
1998-11-05 19:48:35 +03:00
{
2007-06-16 15:48:11 +04:00
smb_ucs2_t * tmp , * p ;
BOOL ret ;
if ( push_ucs2_allocate ( & tmp , s ) = = - 1 ) {
return False ;
}
for ( p = tmp ; * p ! = 0 ; p + + ) {
if ( isupper_w ( * p ) ) {
break ;
}
}
ret = ( * p ! = 0 ) ;
SAFE_FREE ( tmp ) ;
return ret ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Does a string have any lowercase chars in it ?
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-17 23:50:07 +03:00
BOOL strhaslower ( const char * s )
1998-11-05 19:48:35 +03:00
{
2007-06-16 15:48:11 +04:00
smb_ucs2_t * tmp , * p ;
BOOL ret ;
if ( push_ucs2_allocate ( & tmp , s ) = = - 1 ) {
return False ;
}
for ( p = tmp ; * p ! = 0 ; p + + ) {
if ( islower_w ( * p ) ) {
break ;
}
}
ret = ( * p ! = 0 ) ;
SAFE_FREE ( tmp ) ;
return ret ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Find the number of ' c ' chars in a string
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-17 23:50:07 +03:00
size_t count_chars ( const char * s , char c )
1998-11-05 19:48:35 +03:00
{
2001-07-04 11:15:53 +04:00
smb_ucs2_t * ptr ;
int count ;
2004-02-14 01:34:29 +03:00
smb_ucs2_t * alloc_tmpbuf = NULL ;
2004-02-14 01:06:25 +03:00
if ( push_ucs2_allocate ( & alloc_tmpbuf , s ) = = ( size_t ) - 1 ) {
return 0 ;
}
for ( count = 0 , ptr = alloc_tmpbuf ; * ptr ; ptr + + )
2002-10-02 23:12:14 +04:00
if ( * ptr = = UCS2_CHAR ( c ) )
count + + ;
2004-02-14 01:06:25 +03:00
2004-02-14 01:34:29 +03:00
SAFE_FREE ( alloc_tmpbuf ) ;
2001-07-04 11:15:53 +04:00
return ( count ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Safe string copy into a known length string . maxlength does not
include the terminating zero .
2003-02-24 06:09:08 +03:00
* */
1999-12-13 16:27:58 +03:00
2003-03-18 04:48:11 +03:00
char * safe_strcpy_fn ( const char * fn , int line , char * dest , const char * src , size_t maxlength )
1998-11-05 19:48:35 +03:00
{
2001-07-04 11:15:53 +04:00
size_t len ;
1998-11-05 19:48:35 +03:00
2001-07-04 11:15:53 +04:00
if ( ! dest ) {
2003-11-20 01:56:02 +03:00
DEBUG ( 0 , ( " ERROR: NULL dest in safe_strcpy, called from [%s][%d] \n " , fn , line ) ) ;
2001-07-04 11:15:53 +04:00
return NULL ;
}
1998-11-05 19:48:35 +03:00
2003-09-04 05:12:39 +04:00
# ifdef DEVELOPER
2003-03-18 04:48:11 +03:00
clobber_region ( fn , line , dest , maxlength + 1 ) ;
2003-09-04 05:12:39 +04:00
# endif
2003-02-24 06:09:08 +03:00
2001-07-04 11:15:53 +04:00
if ( ! src ) {
* dest = 0 ;
return dest ;
}
1998-11-05 19:48:35 +03:00
2003-03-19 23:50:56 +03:00
len = strnlen ( src , maxlength + 1 ) ;
1998-11-05 19:48:35 +03:00
2001-07-04 11:15:53 +04:00
if ( len > maxlength ) {
2003-11-03 17:34:25 +03:00
DEBUG ( 0 , ( " ERROR: string overflow by %lu (%lu - %lu) in safe_strcpy [%.50s] \n " ,
( unsigned long ) ( len - maxlength ) , ( unsigned long ) len ,
( unsigned long ) maxlength , src ) ) ;
2001-07-04 11:15:53 +04:00
len = maxlength ;
}
1998-11-05 19:48:35 +03:00
2001-07-04 11:15:53 +04:00
memmove ( dest , src , len ) ;
dest [ len ] = 0 ;
return dest ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Safe string cat into a string . maxlength does not
include the terminating zero .
2003-02-24 06:09:08 +03:00
* */
2003-03-18 04:48:11 +03:00
char * safe_strcat_fn ( const char * fn , int line , char * dest , const char * src , size_t maxlength )
1998-11-05 19:48:35 +03:00
{
2001-07-04 11:15:53 +04:00
size_t src_len , dest_len ;
1998-11-05 19:48:35 +03:00
2001-07-04 11:15:53 +04:00
if ( ! dest ) {
2003-11-20 01:56:02 +03:00
DEBUG ( 0 , ( " ERROR: NULL dest in safe_strcat, called from [%s][%d] \n " , fn , line ) ) ;
2001-07-04 11:15:53 +04:00
return NULL ;
}
1998-11-05 19:48:35 +03:00
2002-10-02 23:12:14 +04:00
if ( ! src )
2001-07-04 11:15:53 +04:00
return dest ;
2003-03-19 23:50:56 +03:00
src_len = strnlen ( src , maxlength + 1 ) ;
dest_len = strnlen ( dest , maxlength + 1 ) ;
2003-02-07 07:11:36 +03:00
2003-09-04 05:12:39 +04:00
# ifdef DEVELOPER
2003-03-18 04:48:11 +03:00
clobber_region ( fn , line , dest + dest_len , maxlength + 1 - dest_len ) ;
2003-09-04 05:12:39 +04:00
# endif
2003-03-18 04:48:11 +03:00
2001-07-04 11:15:53 +04:00
if ( src_len + dest_len > maxlength ) {
DEBUG ( 0 , ( " ERROR: string overflow by %d in safe_strcat [%.50s] \n " ,
( int ) ( src_len + dest_len - maxlength ) , src ) ) ;
2003-02-07 07:11:36 +03:00
if ( maxlength > dest_len ) {
memcpy ( & dest [ dest_len ] , src , maxlength - dest_len ) ;
}
dest [ maxlength ] = 0 ;
return NULL ;
2001-07-04 11:15:53 +04:00
}
2003-03-18 04:48:11 +03:00
2001-07-04 11:15:53 +04:00
memcpy ( & dest [ dest_len ] , src , src_len ) ;
dest [ dest_len + src_len ] = 0 ;
return dest ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
1999-12-13 16:27:58 +03:00
Paranoid strcpy into a buffer of given length ( includes terminating
2001-06-23 11:22:16 +04:00
zero . Strips out all but ' a - Z0 - 9 ' and the character in other_safe_chars
and replaces with ' _ ' . Deliberately does * NOT * check for multibyte
characters . Don ' t change it !
2003-02-24 06:09:08 +03:00
* */
2003-03-18 04:48:11 +03:00
char * alpha_strcpy_fn ( const char * fn , int line , char * dest , const char * src , const char * other_safe_chars , size_t maxlength )
1998-11-05 19:48:35 +03:00
{
1999-12-13 16:27:58 +03:00
size_t len , i ;
1998-11-05 19:48:35 +03:00
2003-09-04 05:12:39 +04:00
# ifdef DEVELOPER
2003-03-18 04:48:11 +03:00
clobber_region ( fn , line , dest , maxlength ) ;
2003-09-04 05:12:39 +04:00
# endif
2003-03-18 04:48:11 +03:00
1999-12-13 16:27:58 +03:00
if ( ! dest ) {
2003-11-20 01:56:02 +03:00
DEBUG ( 0 , ( " ERROR: NULL dest in alpha_strcpy, called from [%s][%d] \n " , fn , line ) ) ;
1999-12-13 16:27:58 +03:00
return NULL ;
}
1998-11-05 19:48:35 +03:00
1999-12-13 16:27:58 +03:00
if ( ! src ) {
* dest = 0 ;
return dest ;
}
len = strlen ( src ) ;
if ( len > = maxlength )
len = maxlength - 1 ;
2001-06-23 11:22:16 +04:00
if ( ! other_safe_chars )
other_safe_chars = " " ;
1999-12-13 16:27:58 +03:00
for ( i = 0 ; i < len ; i + + ) {
int val = ( src [ i ] & 0xff ) ;
2005-12-27 23:52:36 +03:00
if ( isupper_ascii ( val ) | | islower_ascii ( val ) | | isdigit ( val ) | | strchr_m ( other_safe_chars , val ) )
1999-12-13 16:27:58 +03:00
dest [ i ] = src [ i ] ;
else
dest [ i ] = ' _ ' ;
}
dest [ i ] = ' \0 ' ;
return dest ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
1999-12-13 16:27:58 +03:00
Like strncpy but always null terminates . Make sure there is room !
The variable n should always be one less than the available size .
2003-02-24 06:09:08 +03:00
* */
2003-03-18 04:48:11 +03:00
char * StrnCpy_fn ( const char * fn , int line , char * dest , const char * src , size_t n )
1998-11-05 19:48:35 +03:00
{
2001-07-04 11:15:53 +04:00
char * d = dest ;
2003-03-18 04:48:11 +03:00
2003-09-04 05:12:39 +04:00
# ifdef DEVELOPER
2003-03-18 04:48:11 +03:00
clobber_region ( fn , line , dest , n + 1 ) ;
2003-09-04 05:12:39 +04:00
# endif
2003-03-18 04:48:11 +03:00
2003-11-18 22:15:29 +03:00
if ( ! dest ) {
2003-11-20 01:56:02 +03:00
DEBUG ( 0 , ( " ERROR: NULL dest in StrnCpy, called from [%s][%d] \n " , fn , line ) ) ;
2002-10-02 23:12:14 +04:00
return ( NULL ) ;
2003-11-18 22:15:29 +03:00
}
2001-07-04 11:15:53 +04:00
if ( ! src ) {
* dest = 0 ;
return ( dest ) ;
}
2003-03-24 12:54:13 +03:00
while ( n - - & & ( * d = * src ) ) {
d + + ;
src + + ;
}
2001-07-04 11:15:53 +04:00
* d = 0 ;
return ( dest ) ;
1998-11-05 19:48:35 +03:00
}
2003-03-18 04:48:11 +03:00
#if 0
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Like strncpy but copies up to the character marker . always null terminates .
returns a pointer to the character marker in the source string ( src ) .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
2003-03-18 04:48:11 +03:00
static char * strncpyn ( char * dest , const char * src , size_t n , char c )
1998-11-05 19:48:35 +03:00
{
char * p ;
1998-11-17 23:50:07 +03:00
size_t str_len ;
1998-11-05 19:48:35 +03:00
2003-09-04 05:12:39 +04:00
# ifdef DEVELOPER
2003-03-18 04:48:11 +03:00
clobber_region ( dest , n + 1 ) ;
2003-09-04 05:12:39 +04:00
# endif
2001-07-04 11:36:09 +04:00
p = strchr_m ( src , c ) ;
2002-10-02 23:12:14 +04:00
if ( p = = NULL ) {
1998-11-05 19:48:35 +03:00
DEBUG ( 5 , ( " strncpyn: separator character (%c) not found \n " , c ) ) ;
return NULL ;
}
str_len = PTR_DIFF ( p , src ) ;
strncpy ( dest , src , MIN ( n , str_len ) ) ;
dest [ str_len ] = ' \0 ' ;
return p ;
}
2003-03-18 04:48:11 +03:00
# endif
1998-11-05 19:48:35 +03:00
2003-02-24 06:09:08 +03:00
/**
1998-11-10 22:05:00 +03:00
Routine to get hex characters and turn them into a 16 byte array .
the array can be variable length , and any non - hex - numeric
characters are skipped . " 0xnn " or " 0Xnn " is specially catered
for .
valid examples : " 0A5D15 " ; " 0x15, 0x49, 0xa2 " ; " 59 \t a9 \t e3 \n "
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-17 23:50:07 +03:00
size_t strhex_to_str ( char * p , size_t len , const char * strhex )
1998-11-10 22:05:00 +03:00
{
1998-11-17 23:50:07 +03:00
size_t i ;
size_t num_chars = 0 ;
1998-11-10 22:05:00 +03:00
unsigned char lonybble , hinybble ;
2003-01-03 11:28:12 +03:00
const char * hexchars = " 0123456789ABCDEF " ;
1998-11-10 22:05:00 +03:00
char * p1 = NULL , * p2 = NULL ;
2002-10-02 23:12:14 +04:00
for ( i = 0 ; i < len & & strhex [ i ] ! = 0 ; i + + ) {
if ( strnequal ( hexchars , " 0x " , 2 ) ) {
1998-11-10 22:05:00 +03:00
i + + ; /* skip two chars */
continue ;
}
2005-12-27 23:52:36 +03:00
if ( ! ( p1 = strchr_m ( hexchars , toupper_ascii ( strhex [ i ] ) ) ) )
1999-03-23 17:56:25 +03:00
break ;
1998-11-10 22:05:00 +03:00
i + + ; /* next hex digit */
2005-12-27 23:52:36 +03:00
if ( ! ( p2 = strchr_m ( hexchars , toupper_ascii ( strhex [ i ] ) ) ) )
1999-03-23 17:56:25 +03:00
break ;
1998-11-10 22:05:00 +03:00
/* get the two nybbles */
hinybble = PTR_DIFF ( p1 , hexchars ) ;
lonybble = PTR_DIFF ( p2 , hexchars ) ;
p [ num_chars ] = ( hinybble < < 4 ) | lonybble ;
num_chars + + ;
p1 = NULL ;
p2 = NULL ;
}
return num_chars ;
}
2005-08-08 00:59:28 +04:00
DATA_BLOB strhex_to_data_blob ( TALLOC_CTX * mem_ctx , const char * strhex )
2004-04-07 13:27:50 +04:00
{
2005-08-08 00:59:28 +04:00
DATA_BLOB ret_blob ;
if ( mem_ctx ! = NULL )
ret_blob = data_blob_talloc ( mem_ctx , NULL , strlen ( strhex ) / 2 + 1 ) ;
else
2005-08-08 01:34:55 +04:00
ret_blob = data_blob ( NULL , strlen ( strhex ) / 2 + 1 ) ;
2004-04-07 13:27:50 +04:00
2005-03-22 21:07:58 +03:00
ret_blob . length = strhex_to_str ( ( char * ) ret_blob . data ,
2004-04-07 13:27:50 +04:00
strlen ( strhex ) ,
strhex ) ;
return ret_blob ;
}
2003-03-24 12:54:13 +03:00
/**
* Routine to print a buffer as HEX digits , into an allocated string .
*/
2005-08-08 00:59:28 +04:00
char * hex_encode ( TALLOC_CTX * mem_ctx , const unsigned char * buff_in , size_t len )
2003-03-24 12:54:13 +03:00
{
int i ;
char * hex_buffer ;
2005-08-08 00:59:28 +04:00
hex_buffer = TALLOC_ARRAY ( mem_ctx , char , ( len * 2 ) + 1 ) ;
2003-03-24 12:54:13 +03:00
for ( i = 0 ; i < len ; i + + )
slprintf ( & hex_buffer [ i * 2 ] , 3 , " %02X " , buff_in [ i ] ) ;
2005-08-08 00:59:28 +04:00
return hex_buffer ;
2003-03-24 12:54:13 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Check if a string is part of a list .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
2005-03-22 18:45:38 +03:00
BOOL in_list ( const char * s , const char * list , BOOL casesensitive )
1998-11-05 19:48:35 +03:00
{
2002-10-02 23:12:14 +04:00
pstring tok ;
2002-11-13 02:20:50 +03:00
const char * p = list ;
2002-10-02 23:12:14 +04:00
if ( ! list )
return ( False ) ;
while ( next_token ( & p , tok , LIST_SEP , sizeof ( tok ) ) ) {
if ( casesensitive ) {
if ( strcmp ( tok , s ) = = 0 )
return ( True ) ;
} else {
if ( StrCaseCmp ( tok , s ) = = 0 )
return ( True ) ;
}
}
return ( False ) ;
1998-11-05 19:48:35 +03:00
}
/* this is used to prevent lots of mallocs of size 1 */
2006-04-08 21:25:31 +04:00
static const char * null_string = " " ;
1998-11-05 19:48:35 +03:00
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Set a string value , allocing the space for the string
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
2000-01-16 14:07:11 +03:00
static BOOL string_init ( char * * dest , const char * src )
1998-11-05 19:48:35 +03:00
{
2002-10-02 23:12:14 +04:00
size_t l ;
2006-04-08 21:25:31 +04:00
2002-10-02 23:12:14 +04:00
if ( ! src )
src = " " ;
l = strlen ( src ) ;
if ( l = = 0 ) {
2006-04-08 21:25:31 +04:00
* dest = CONST_DISCARD ( char * , null_string ) ;
2002-10-02 23:12:14 +04:00
} else {
2004-12-07 21:25:53 +03:00
( * dest ) = SMB_STRDUP ( src ) ;
2002-10-02 23:12:14 +04:00
if ( ( * dest ) = = NULL ) {
DEBUG ( 0 , ( " Out of memory in string_init \n " ) ) ;
return False ;
}
}
return ( True ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Free a string value .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-05 19:48:35 +03:00
void string_free ( char * * s )
{
2002-10-02 23:12:14 +04:00
if ( ! s | | ! ( * s ) )
return ;
if ( * s = = null_string )
* s = NULL ;
SAFE_FREE ( * s ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Set a string value , deallocating any existing space , and allocing the space
for the string
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
1998-11-17 23:50:07 +03:00
BOOL string_set ( char * * dest , const char * src )
1998-11-05 19:48:35 +03:00
{
2002-10-02 23:12:14 +04:00
string_free ( dest ) ;
return ( string_init ( dest , src ) ) ;
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Substitute a string for a pattern in another string . Make sure there is
enough room !
1998-11-05 19:48:35 +03:00
2002-10-02 23:12:14 +04:00
This routine looks for pattern in s and replaces it with
2005-07-21 21:40:20 +04:00
insert . It may do multiple replacements or just one .
1998-11-05 19:48:35 +03:00
2002-10-02 23:12:14 +04:00
Any of " ; ' $ or ` in the insert string are replaced with _
if len = = 0 then the string cannot be extended . This is different from the old
use of len = = 0 which was for no length checks to be done .
2003-02-24 06:09:08 +03:00
* */
2002-07-15 14:35:28 +04:00
2005-07-21 21:40:20 +04:00
void string_sub2 ( char * s , const char * pattern , const char * insert , size_t len ,
2006-02-22 13:28:02 +03:00
BOOL remove_unsafe_characters , BOOL replace_once , BOOL allow_trailing_dollar )
1998-11-05 19:48:35 +03:00
{
1998-11-23 06:36:10 +03:00
char * p ;
1999-12-13 16:27:58 +03:00
ssize_t ls , lp , li , i ;
1998-11-23 06:36:10 +03:00
2002-07-15 14:35:28 +04:00
if ( ! insert | | ! pattern | | ! * pattern | | ! s )
return ;
1998-11-23 06:36:10 +03:00
1999-12-13 16:27:58 +03:00
ls = ( ssize_t ) strlen ( s ) ;
lp = ( ssize_t ) strlen ( pattern ) ;
li = ( ssize_t ) strlen ( insert ) ;
1998-11-23 06:36:10 +03:00
2002-07-15 14:35:28 +04:00
if ( len = = 0 )
2002-08-17 21:00:51 +04:00
len = ls + 1 ; /* len is number of *bytes* */
2002-07-15 14:35:28 +04:00
2004-03-09 03:17:14 +03:00
while ( lp < = ls & & ( p = strstr_m ( s , pattern ) ) ) {
2002-07-15 14:35:28 +04:00
if ( ls + ( li - lp ) > = len ) {
1999-12-13 16:27:58 +03:00
DEBUG ( 0 , ( " ERROR: string overflow by %d in string_sub(%.50s, %d) \n " ,
( int ) ( ls + ( li - lp ) - len ) ,
pattern , ( int ) len ) ) ;
break ;
}
if ( li ! = lp ) {
memmove ( p + li , p + lp , strlen ( p + lp ) + 1 ) ;
}
1998-11-23 06:36:10 +03:00
for ( i = 0 ; i < li ; i + + ) {
switch ( insert [ i ] ) {
case ' ` ' :
case ' " ' :
1998-11-23 06:46:51 +03:00
case ' \' ' :
1998-11-23 06:36:10 +03:00
case ' ; ' :
1999-12-13 16:27:58 +03:00
case ' $ ' :
2006-02-22 13:28:02 +03:00
/* allow a trailing $ (as in machine accounts) */
if ( allow_trailing_dollar & & ( i = = li - 1 ) ) {
p [ i ] = insert [ i ] ;
break ;
}
1999-12-13 16:27:58 +03:00
case ' % ' :
case ' \r ' :
case ' \n ' :
2005-07-15 21:38:55 +04:00
if ( remove_unsafe_characters ) {
p [ i ] = ' _ ' ;
/* yes this break should be here since we want to
fall throw if not replacing unsafe chars */
break ;
}
1998-11-23 06:36:10 +03:00
default :
p [ i ] = insert [ i ] ;
}
}
s = p + li ;
ls + = ( li - lp ) ;
2005-07-21 21:40:20 +04:00
if ( replace_once )
break ;
1998-11-23 06:36:10 +03:00
}
}
1998-11-05 19:48:35 +03:00
2005-07-21 21:40:20 +04:00
void string_sub_once ( char * s , const char * pattern , const char * insert , size_t len )
{
2006-02-22 13:28:02 +03:00
string_sub2 ( s , pattern , insert , len , True , True , False ) ;
2005-07-21 21:40:20 +04:00
}
2005-07-15 21:38:55 +04:00
void string_sub ( char * s , const char * pattern , const char * insert , size_t len )
{
2006-02-22 13:28:02 +03:00
string_sub2 ( s , pattern , insert , len , True , False , False ) ;
2005-07-15 21:38:55 +04:00
}
1999-12-13 16:27:58 +03:00
void fstring_sub ( char * s , const char * pattern , const char * insert )
{
string_sub ( s , pattern , insert , sizeof ( fstring ) ) ;
}
void pstring_sub ( char * s , const char * pattern , const char * insert )
{
string_sub ( s , pattern , insert , sizeof ( pstring ) ) ;
}
1998-11-05 19:48:35 +03:00
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Similar to string_sub , but it will accept only allocated strings
and may realloc them so pay attention at what you pass on no
pointers inside strings , no pstrings or const may be passed
as string .
2003-02-24 06:09:08 +03:00
* */
2002-07-15 14:35:28 +04:00
2005-12-18 21:06:15 +03:00
char * realloc_string_sub ( char * string , const char * pattern ,
const char * insert )
2002-07-15 14:35:28 +04:00
{
char * p , * in ;
char * s ;
ssize_t ls , lp , li , ld , i ;
if ( ! insert | | ! pattern | | ! * pattern | | ! string | | ! * string )
return NULL ;
s = string ;
2004-12-07 21:25:53 +03:00
in = SMB_STRDUP ( insert ) ;
2002-07-15 14:35:28 +04:00
if ( ! in ) {
DEBUG ( 0 , ( " realloc_string_sub: out of memory! \n " ) ) ;
return NULL ;
}
ls = ( ssize_t ) strlen ( s ) ;
lp = ( ssize_t ) strlen ( pattern ) ;
li = ( ssize_t ) strlen ( insert ) ;
ld = li - lp ;
for ( i = 0 ; i < li ; i + + ) {
switch ( in [ i ] ) {
case ' ` ' :
case ' " ' :
case ' \' ' :
case ' ; ' :
case ' $ ' :
case ' % ' :
case ' \r ' :
case ' \n ' :
in [ i ] = ' _ ' ;
default :
/* ok */
break ;
}
}
2004-03-09 03:17:14 +03:00
while ( ( p = strstr_m ( s , pattern ) ) ) {
2002-07-15 14:35:28 +04:00
if ( ld > 0 ) {
2003-08-26 00:42:24 +04:00
int offset = PTR_DIFF ( s , string ) ;
2006-07-30 20:36:56 +04:00
string = ( char * ) SMB_REALLOC ( string , ls + ld + 1 ) ;
r13915: Fixed a very interesting class of realloc() bugs found by Coverity.
realloc can return NULL in one of two cases - (1) the realloc failed,
(2) realloc succeeded but the new size requested was zero, in which
case this is identical to a free() call.
The error paths dealing with these two cases should be different,
but mostly weren't. Secondly the standard idiom for dealing with
realloc when you know the new size is non-zero is the following :
tmp = realloc(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
However, there were *many* *many* places in Samba where we were
using the old (broken) idiom of :
p = realloc(p, size)
if (!p) {
return error;
}
which will leak the memory pointed to by p on realloc fail.
This commit (hopefully) fixes all these cases by moving to
a standard idiom of :
p = SMB_REALLOC(p, size)
if (!p) {
return error;
}
Where if the realloc returns null due to the realloc failing
or size == 0 we *guarentee* that the storage pointed to by p
has been freed. This allows me to remove a lot of code that
was dealing with the standard (more verbose) method that required
a tmp pointer. This is almost always what you want. When a
realloc fails you never usually want the old memory, you
want to free it and get into your error processing asap.
For the 11 remaining cases where we really do need to keep the
old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR,
which can be used as follows :
tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the
pointer p, even on size == 0 or realloc fail. All this is
done by a hidden extra argument to Realloc(), BOOL free_old_on_error
which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR
macros (and their array counterparts).
It remains to be seen what this will do to our Coverity bug count :-).
Jeremy.
(This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
if ( ! string ) {
2002-07-15 14:35:28 +04:00
DEBUG ( 0 , ( " realloc_string_sub: out of memory! \n " ) ) ;
SAFE_FREE ( in ) ;
return NULL ;
}
r13915: Fixed a very interesting class of realloc() bugs found by Coverity.
realloc can return NULL in one of two cases - (1) the realloc failed,
(2) realloc succeeded but the new size requested was zero, in which
case this is identical to a free() call.
The error paths dealing with these two cases should be different,
but mostly weren't. Secondly the standard idiom for dealing with
realloc when you know the new size is non-zero is the following :
tmp = realloc(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
However, there were *many* *many* places in Samba where we were
using the old (broken) idiom of :
p = realloc(p, size)
if (!p) {
return error;
}
which will leak the memory pointed to by p on realloc fail.
This commit (hopefully) fixes all these cases by moving to
a standard idiom of :
p = SMB_REALLOC(p, size)
if (!p) {
return error;
}
Where if the realloc returns null due to the realloc failing
or size == 0 we *guarentee* that the storage pointed to by p
has been freed. This allows me to remove a lot of code that
was dealing with the standard (more verbose) method that required
a tmp pointer. This is almost always what you want. When a
realloc fails you never usually want the old memory, you
want to free it and get into your error processing asap.
For the 11 remaining cases where we really do need to keep the
old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR,
which can be used as follows :
tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the
pointer p, even on size == 0 or realloc fail. All this is
done by a hidden extra argument to Realloc(), BOOL free_old_on_error
which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR
macros (and their array counterparts).
It remains to be seen what this will do to our Coverity bug count :-).
Jeremy.
(This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
p = string + offset + ( p - s ) ;
2002-07-15 14:35:28 +04:00
}
if ( li ! = lp ) {
memmove ( p + li , p + lp , strlen ( p + lp ) + 1 ) ;
}
memcpy ( p , in , li ) ;
s = p + li ;
ls + = ld ;
}
SAFE_FREE ( in ) ;
return string ;
}
2005-12-18 21:06:15 +03:00
/* Same as string_sub, but returns a talloc'ed string */
char * talloc_string_sub ( TALLOC_CTX * mem_ctx , const char * src ,
const char * pattern , const char * insert )
{
char * p , * in ;
char * s ;
char * string ;
ssize_t ls , lp , li , ld , i ;
if ( ! insert | | ! pattern | | ! * pattern | | ! src | | ! * src )
return NULL ;
string = talloc_strdup ( mem_ctx , src ) ;
if ( string = = NULL ) {
DEBUG ( 0 , ( " talloc_strdup failed \n " ) ) ;
return NULL ;
}
s = string ;
in = SMB_STRDUP ( insert ) ;
if ( ! in ) {
DEBUG ( 0 , ( " talloc_string_sub: out of memory! \n " ) ) ;
return NULL ;
}
ls = ( ssize_t ) strlen ( s ) ;
lp = ( ssize_t ) strlen ( pattern ) ;
li = ( ssize_t ) strlen ( insert ) ;
ld = li - lp ;
for ( i = 0 ; i < li ; i + + ) {
switch ( in [ i ] ) {
case ' ` ' :
case ' " ' :
case ' \' ' :
case ' ; ' :
case ' $ ' :
case ' % ' :
case ' \r ' :
case ' \n ' :
in [ i ] = ' _ ' ;
default :
/* ok */
break ;
}
}
while ( ( p = strstr_m ( s , pattern ) ) ) {
if ( ld > 0 ) {
int offset = PTR_DIFF ( s , string ) ;
2006-07-30 20:36:56 +04:00
string = ( char * ) TALLOC_REALLOC ( mem_ctx , string ,
ls + ld + 1 ) ;
r13915: Fixed a very interesting class of realloc() bugs found by Coverity.
realloc can return NULL in one of two cases - (1) the realloc failed,
(2) realloc succeeded but the new size requested was zero, in which
case this is identical to a free() call.
The error paths dealing with these two cases should be different,
but mostly weren't. Secondly the standard idiom for dealing with
realloc when you know the new size is non-zero is the following :
tmp = realloc(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
However, there were *many* *many* places in Samba where we were
using the old (broken) idiom of :
p = realloc(p, size)
if (!p) {
return error;
}
which will leak the memory pointed to by p on realloc fail.
This commit (hopefully) fixes all these cases by moving to
a standard idiom of :
p = SMB_REALLOC(p, size)
if (!p) {
return error;
}
Where if the realloc returns null due to the realloc failing
or size == 0 we *guarentee* that the storage pointed to by p
has been freed. This allows me to remove a lot of code that
was dealing with the standard (more verbose) method that required
a tmp pointer. This is almost always what you want. When a
realloc fails you never usually want the old memory, you
want to free it and get into your error processing asap.
For the 11 remaining cases where we really do need to keep the
old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR,
which can be used as follows :
tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the
pointer p, even on size == 0 or realloc fail. All this is
done by a hidden extra argument to Realloc(), BOOL free_old_on_error
which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR
macros (and their array counterparts).
It remains to be seen what this will do to our Coverity bug count :-).
Jeremy.
(This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
if ( ! string ) {
2005-12-18 21:06:15 +03:00
DEBUG ( 0 , ( " talloc_string_sub: out of "
" memory! \n " ) ) ;
SAFE_FREE ( in ) ;
return NULL ;
}
r13915: Fixed a very interesting class of realloc() bugs found by Coverity.
realloc can return NULL in one of two cases - (1) the realloc failed,
(2) realloc succeeded but the new size requested was zero, in which
case this is identical to a free() call.
The error paths dealing with these two cases should be different,
but mostly weren't. Secondly the standard idiom for dealing with
realloc when you know the new size is non-zero is the following :
tmp = realloc(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
However, there were *many* *many* places in Samba where we were
using the old (broken) idiom of :
p = realloc(p, size)
if (!p) {
return error;
}
which will leak the memory pointed to by p on realloc fail.
This commit (hopefully) fixes all these cases by moving to
a standard idiom of :
p = SMB_REALLOC(p, size)
if (!p) {
return error;
}
Where if the realloc returns null due to the realloc failing
or size == 0 we *guarentee* that the storage pointed to by p
has been freed. This allows me to remove a lot of code that
was dealing with the standard (more verbose) method that required
a tmp pointer. This is almost always what you want. When a
realloc fails you never usually want the old memory, you
want to free it and get into your error processing asap.
For the 11 remaining cases where we really do need to keep the
old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR,
which can be used as follows :
tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the
pointer p, even on size == 0 or realloc fail. All this is
done by a hidden extra argument to Realloc(), BOOL free_old_on_error
which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR
macros (and their array counterparts).
It remains to be seen what this will do to our Coverity bug count :-).
Jeremy.
(This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
p = string + offset + ( p - s ) ;
2005-12-18 21:06:15 +03:00
}
if ( li ! = lp ) {
memmove ( p + li , p + lp , strlen ( p + lp ) + 1 ) ;
}
memcpy ( p , in , li ) ;
s = p + li ;
ls + = ld ;
}
SAFE_FREE ( in ) ;
return string ;
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Similar to string_sub ( ) but allows for any character to be substituted .
Use with caution !
if len = = 0 then the string cannot be extended . This is different from the old
use of len = = 0 which was for no length checks to be done .
2003-02-24 06:09:08 +03:00
* */
2002-07-15 14:35:28 +04:00
1999-12-13 16:27:58 +03:00
void all_string_sub ( char * s , const char * pattern , const char * insert , size_t len )
1998-11-23 06:36:10 +03:00
{
char * p ;
1999-12-13 16:27:58 +03:00
ssize_t ls , lp , li ;
1998-11-05 19:48:35 +03:00
2002-07-15 14:35:28 +04:00
if ( ! insert | | ! pattern | | ! s )
return ;
1998-11-05 19:48:35 +03:00
1999-12-13 16:27:58 +03:00
ls = ( ssize_t ) strlen ( s ) ;
lp = ( ssize_t ) strlen ( pattern ) ;
li = ( ssize_t ) strlen ( insert ) ;
1998-11-23 06:36:10 +03:00
2002-07-15 14:35:28 +04:00
if ( ! * pattern )
return ;
if ( len = = 0 )
2002-08-17 21:00:51 +04:00
len = ls + 1 ; /* len is number of *bytes* */
1998-11-23 06:36:10 +03:00
2004-03-09 03:17:14 +03:00
while ( lp < = ls & & ( p = strstr_m ( s , pattern ) ) ) {
2002-07-15 14:35:28 +04:00
if ( ls + ( li - lp ) > = len ) {
1999-12-13 16:27:58 +03:00
DEBUG ( 0 , ( " ERROR: string overflow by %d in all_string_sub(%.50s, %d) \n " ,
( int ) ( ls + ( li - lp ) - len ) ,
pattern , ( int ) len ) ) ;
break ;
}
if ( li ! = lp ) {
memmove ( p + li , p + lp , strlen ( p + lp ) + 1 ) ;
}
1998-11-23 06:36:10 +03:00
memcpy ( p , insert , li ) ;
s = p + li ;
ls + = ( li - lp ) ;
}
1998-11-05 19:48:35 +03:00
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Similar to all_string_sub but for unicode strings .
Return a new allocated unicode string .
similar to string_sub ( ) but allows for any character to be substituted .
Use with caution !
2003-02-24 06:09:08 +03:00
* */
2001-11-04 21:26:53 +03:00
2003-03-18 04:48:11 +03:00
static smb_ucs2_t * all_string_sub_w ( const smb_ucs2_t * s , const smb_ucs2_t * pattern ,
2002-01-25 03:35:14 +03:00
const smb_ucs2_t * insert )
2001-11-04 21:26:53 +03:00
{
2002-08-17 21:00:51 +04:00
smb_ucs2_t * r , * rp ;
const smb_ucs2_t * sp ;
2001-11-18 19:12:11 +03:00
size_t lr , lp , li , lt ;
2001-11-04 21:26:53 +03:00
2002-10-02 23:12:14 +04:00
if ( ! insert | | ! pattern | | ! * pattern | | ! s )
return NULL ;
2001-11-04 21:26:53 +03:00
2001-11-18 19:12:11 +03:00
lt = ( size_t ) strlen_w ( s ) ;
lp = ( size_t ) strlen_w ( pattern ) ;
li = ( size_t ) strlen_w ( insert ) ;
2001-11-04 21:26:53 +03:00
if ( li > lp ) {
2002-08-17 21:00:51 +04:00
const smb_ucs2_t * st = s ;
2001-11-04 21:26:53 +03:00
int ld = li - lp ;
2001-11-18 19:12:11 +03:00
while ( ( sp = strstr_w ( st , pattern ) ) ) {
2001-11-04 21:26:53 +03:00
st = sp + lp ;
lt + = ld ;
}
}
2004-12-07 21:25:53 +03:00
r = rp = SMB_MALLOC_ARRAY ( smb_ucs2_t , lt + 1 ) ;
2001-11-04 21:26:53 +03:00
if ( ! r ) {
DEBUG ( 0 , ( " all_string_sub_w: out of memory! \n " ) ) ;
return NULL ;
}
2001-11-18 19:12:11 +03:00
while ( ( sp = strstr_w ( s , pattern ) ) ) {
memcpy ( rp , s , ( sp - s ) ) ;
rp + = ( ( sp - s ) / sizeof ( smb_ucs2_t ) ) ;
memcpy ( rp , insert , ( li * sizeof ( smb_ucs2_t ) ) ) ;
2001-11-04 21:26:53 +03:00
s = sp + lp ;
rp + = li ;
}
2001-11-18 19:12:11 +03:00
lr = ( ( rp - r ) / sizeof ( smb_ucs2_t ) ) ;
if ( lr < lt ) {
memcpy ( rp , s , ( ( lt - lr ) * sizeof ( smb_ucs2_t ) ) ) ;
rp + = ( lt - lr ) ;
}
2001-11-04 21:26:53 +03:00
* rp = 0 ;
return r ;
}
smb_ucs2_t * all_string_sub_wa ( smb_ucs2_t * s , const char * pattern ,
const char * insert )
{
wpstring p , i ;
2002-10-02 23:12:14 +04:00
if ( ! insert | | ! pattern | | ! s )
return NULL ;
2001-11-04 21:26:53 +03:00
push_ucs2 ( NULL , p , pattern , sizeof ( wpstring ) - 1 , STR_TERMINATE ) ;
push_ucs2 ( NULL , i , insert , sizeof ( wpstring ) - 1 , STR_TERMINATE ) ;
return all_string_sub_w ( s , p , i ) ;
}
2003-03-18 04:48:11 +03:00
#if 0
2003-02-24 06:09:08 +03:00
/**
2002-08-17 21:00:51 +04:00
Splits out the front and back at a separator .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
2003-03-18 04:48:11 +03:00
static void split_at_last_component ( char * path , char * front , char sep , char * back )
1998-11-11 17:23:55 +03:00
{
2001-07-04 11:36:09 +04:00
char * p = strrchr_m ( path , sep ) ;
1998-11-11 17:23:55 +03:00
if ( p ! = NULL )
* p = 0 ;
2002-08-17 21:00:51 +04:00
1998-11-11 17:23:55 +03:00
if ( front ! = NULL )
pstrcpy ( front , path ) ;
2002-08-17 21:00:51 +04:00
if ( p ! = NULL ) {
1998-11-11 17:23:55 +03:00
if ( back ! = NULL )
pstrcpy ( back , p + 1 ) ;
1999-12-13 16:27:58 +03:00
* p = ' \\ ' ;
2002-08-17 21:00:51 +04:00
} else {
1998-11-11 17:23:55 +03:00
if ( back ! = NULL )
back [ 0 ] = 0 ;
}
}
2003-03-18 04:48:11 +03:00
# endif
1999-02-16 21:02:50 +03:00
2003-02-24 06:09:08 +03:00
/**
2002-08-17 21:00:51 +04:00
Write an octal as a string .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
2003-01-03 11:28:12 +03:00
const char * octal_string ( int i )
1999-02-16 21:02:50 +03:00
{
1999-12-13 16:27:58 +03:00
static char ret [ 64 ] ;
2002-08-17 21:00:51 +04:00
if ( i = = - 1 )
1999-12-13 16:27:58 +03:00
return " -1 " ;
2001-04-09 00:22:39 +04:00
slprintf ( ret , sizeof ( ret ) - 1 , " 0%o " , i ) ;
1999-12-13 16:27:58 +03:00
return ret ;
1999-02-16 21:02:50 +03:00
}
1999-12-13 16:27:58 +03:00
2003-02-24 06:09:08 +03:00
/**
2002-08-17 21:00:51 +04:00
Truncate a string at a specified length .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
2003-03-18 04:48:11 +03:00
char * string_truncate ( char * s , unsigned int length )
1999-02-16 21:02:50 +03:00
{
2002-08-17 21:00:51 +04:00
if ( s & & strlen ( s ) > length )
1999-12-13 16:27:58 +03:00
s [ length ] = 0 ;
return s ;
1999-02-16 21:02:50 +03:00
}
2001-07-04 11:15:53 +04:00
2003-02-24 06:09:08 +03:00
/**
2002-08-17 21:00:51 +04:00
Strchr and strrchr_m are very hard to do on general multi - byte strings .
We convert via ucs2 for now .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
2003-09-14 02:41:21 +04:00
char * strchr_m ( const char * src , char c )
2001-07-04 11:15:53 +04:00
{
wpstring ws ;
pstring s2 ;
smb_ucs2_t * p ;
2003-09-14 02:41:21 +04:00
const char * s ;
2001-07-04 11:15:53 +04:00
2004-09-24 05:32:19 +04:00
/* characters below 0x3F are guaranteed to not appear in
non - initial position in multi - byte charsets */
if ( ( c & 0xC0 ) = = 0 ) {
2004-09-25 00:06:13 +04:00
return strchr ( src , c ) ;
2004-09-24 05:32:19 +04:00
}
2003-09-05 03:26:13 +04:00
/* this is quite a common operation, so we want it to be
fast . We optimise for the ascii case , knowing that all our
supported multi - byte character sets are ascii - compatible
( ie . they match for the first 128 chars ) */
2003-09-14 02:41:21 +04:00
for ( s = src ; * s & & ! ( ( ( unsigned char ) s [ 0 ] ) & 0x80 ) ; s + + ) {
2003-09-05 03:26:13 +04:00
if ( * s = = c )
2005-05-31 17:46:45 +04:00
return ( char * ) s ;
2003-09-05 03:26:13 +04:00
}
if ( ! * s )
return NULL ;
2003-09-14 02:41:21 +04:00
# ifdef BROKEN_UNICODE_COMPOSE_CHARACTERS
/* With compose characters we must restart from the beginning. JRA. */
s = src ;
# endif
2001-07-04 11:15:53 +04:00
push_ucs2 ( NULL , ws , s , sizeof ( ws ) , STR_TERMINATE ) ;
2001-11-04 21:26:53 +03:00
p = strchr_w ( ws , UCS2_CHAR ( c ) ) ;
2002-08-17 21:00:51 +04:00
if ( ! p )
return NULL ;
2001-07-04 11:15:53 +04:00
* p = 0 ;
pull_ucs2_pstring ( s2 , ws ) ;
2005-05-31 17:46:45 +04:00
return ( char * ) ( s + strlen ( s2 ) ) ;
2001-07-04 11:15:53 +04:00
}
char * strrchr_m ( const char * s , char c )
{
2004-09-24 05:32:19 +04:00
/* characters below 0x3F are guaranteed to not appear in
non - initial position in multi - byte charsets */
if ( ( c & 0xC0 ) = = 0 ) {
return strrchr ( s , c ) ;
}
2003-09-05 05:33:22 +04:00
/* this is quite a common operation, so we want it to be
fast . We optimise for the ascii case , knowing that all our
supported multi - byte character sets are ascii - compatible
( ie . they match for the first 128 chars ) . Also , in Samba
we only search for ascii characters in ' c ' and that
in all mb character sets with a compound character
containing c , if ' c ' is not a match at position
p , then p [ - 1 ] > 0x7f . JRA . */
{
size_t len = strlen ( s ) ;
const char * cp = s ;
BOOL got_mb = False ;
if ( len = = 0 )
return NULL ;
cp + = ( len - 1 ) ;
do {
if ( c = = * cp ) {
/* Could be a match. Part of a multibyte ? */
if ( ( cp > s ) & & ( ( ( unsigned char ) cp [ - 1 ] ) & 0x80 ) ) {
/* Yep - go slow :-( */
got_mb = True ;
break ;
}
/* No - we have a match ! */
2005-05-31 17:46:45 +04:00
return ( char * ) cp ;
2003-09-05 05:33:22 +04:00
}
} while ( cp - - ! = s ) ;
if ( ! got_mb )
return NULL ;
}
2001-07-04 11:15:53 +04:00
2003-09-05 05:33:22 +04:00
/* String contained a non-ascii char. Slow path. */
{
wpstring ws ;
pstring s2 ;
smb_ucs2_t * p ;
push_ucs2 ( NULL , ws , s , sizeof ( ws ) , STR_TERMINATE ) ;
p = strrchr_w ( ws , UCS2_CHAR ( c ) ) ;
if ( ! p )
return NULL ;
* p = 0 ;
pull_ucs2_pstring ( s2 , ws ) ;
2005-05-31 17:46:45 +04:00
return ( char * ) ( s + strlen ( s2 ) ) ;
2003-09-05 05:33:22 +04:00
}
2001-07-04 11:15:53 +04:00
}
2003-07-03 00:01:51 +04:00
/***********************************************************************
Return the equivalent of doing strrchr ' n ' times - always going
backwards .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * strnrchr_m ( const char * s , char c , unsigned int n )
{
wpstring ws ;
pstring s2 ;
smb_ucs2_t * p ;
push_ucs2 ( NULL , ws , s , sizeof ( ws ) , STR_TERMINATE ) ;
p = strnrchr_w ( ws , UCS2_CHAR ( c ) , n ) ;
if ( ! p )
return NULL ;
* p = 0 ;
pull_ucs2_pstring ( s2 , ws ) ;
2005-05-31 17:46:45 +04:00
return ( char * ) ( s + strlen ( s2 ) ) ;
2003-07-03 00:01:51 +04:00
}
2004-03-09 03:17:14 +03:00
/***********************************************************************
strstr_m - We convert via ucs2 for now .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * strstr_m ( const char * src , const char * findstr )
{
smb_ucs2_t * p ;
smb_ucs2_t * src_w , * find_w ;
const char * s ;
char * s2 ;
char * retp ;
2004-03-09 12:56:33 +03:00
size_t findstr_len = 0 ;
2004-03-09 14:15:44 +03:00
/* for correctness */
if ( ! findstr [ 0 ] ) {
2005-05-31 17:46:45 +04:00
return ( char * ) src ;
2004-03-09 14:15:44 +03:00
}
2004-03-09 03:17:14 +03:00
/* Samba does single character findstr calls a *lot*. */
if ( findstr [ 1 ] = = ' \0 ' )
return strchr_m ( src , * findstr ) ;
/* We optimise for the ascii case, knowing that all our
supported multi - byte character sets are ascii - compatible
( ie . they match for the first 128 chars ) */
for ( s = src ; * s & & ! ( ( ( unsigned char ) s [ 0 ] ) & 0x80 ) ; s + + ) {
if ( * s = = * findstr ) {
2004-03-09 12:56:33 +03:00
if ( ! findstr_len )
findstr_len = strlen ( findstr ) ;
if ( strncmp ( s , findstr , findstr_len ) = = 0 ) {
2005-05-31 17:46:45 +04:00
return ( char * ) s ;
2004-03-09 03:17:14 +03:00
}
}
}
if ( ! * s )
return NULL ;
2004-03-09 14:15:44 +03:00
# if 1 /* def BROKEN_UNICODE_COMPOSE_CHARACTERS */
/* 'make check' fails unless we do this */
2004-03-09 03:17:14 +03:00
/* With compose characters we must restart from the beginning. JRA. */
s = src ;
# endif
if ( push_ucs2_allocate ( & src_w , src ) = = ( size_t ) - 1 ) {
DEBUG ( 0 , ( " strstr_m: src malloc fail \n " ) ) ;
return NULL ;
}
if ( push_ucs2_allocate ( & find_w , findstr ) = = ( size_t ) - 1 ) {
SAFE_FREE ( src_w ) ;
DEBUG ( 0 , ( " strstr_m: find malloc fail \n " ) ) ;
return NULL ;
}
2004-03-09 12:56:33 +03:00
2004-03-09 14:15:44 +03:00
p = strstr_w ( src_w , find_w ) ;
2004-03-09 03:17:14 +03:00
if ( ! p ) {
SAFE_FREE ( src_w ) ;
SAFE_FREE ( find_w ) ;
return NULL ;
}
2004-03-09 14:15:44 +03:00
2004-03-09 03:17:14 +03:00
* p = 0 ;
if ( pull_ucs2_allocate ( & s2 , src_w ) = = ( size_t ) - 1 ) {
SAFE_FREE ( src_w ) ;
SAFE_FREE ( find_w ) ;
DEBUG ( 0 , ( " strstr_m: dest malloc fail \n " ) ) ;
return NULL ;
}
2005-05-31 17:46:45 +04:00
retp = ( char * ) ( s + strlen ( s2 ) ) ;
2004-03-09 03:17:14 +03:00
SAFE_FREE ( src_w ) ;
SAFE_FREE ( find_w ) ;
SAFE_FREE ( s2 ) ;
return retp ;
}
2003-02-24 06:09:08 +03:00
/**
2002-08-17 21:00:51 +04:00
Convert a string to lower case .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
2001-07-04 11:15:53 +04:00
void strlower_m ( char * s )
{
2004-02-04 23:28:51 +03:00
size_t len ;
2004-09-01 21:39:27 +04:00
int errno_save ;
2004-02-04 23:28:51 +03:00
2002-04-11 13:56:38 +04:00
/* this is quite a common operation, so we want it to be
fast . We optimise for the ascii case , knowing that all our
supported multi - byte character sets are ascii - compatible
( ie . they match for the first 128 chars ) */
2002-08-17 21:00:51 +04:00
2004-01-08 02:21:36 +03:00
while ( * s & & ! ( ( ( unsigned char ) s [ 0 ] ) & 0x80 ) ) {
2005-12-27 23:52:36 +03:00
* s = tolower_ascii ( ( unsigned char ) * s ) ;
2003-01-17 09:40:12 +03:00
s + + ;
}
2002-04-11 13:56:38 +04:00
2002-08-17 21:00:51 +04:00
if ( ! * s )
return ;
2002-04-11 13:56:38 +04:00
2001-07-04 11:15:53 +04:00
/* I assume that lowercased string takes the same number of bytes
* as source string even in UTF - 8 encoding . ( VIV ) */
2004-02-04 23:28:51 +03:00
len = strlen ( s ) + 1 ;
2004-09-01 21:39:27 +04:00
errno_save = errno ;
2004-02-04 23:28:51 +03:00
errno = 0 ;
unix_strlower ( s , len , s , len ) ;
/* Catch mb conversion errors that may not terminate. */
if ( errno )
s [ len - 1 ] = ' \0 ' ;
2004-09-01 21:39:27 +04:00
errno = errno_save ;
2001-07-04 11:15:53 +04:00
}
2003-02-24 06:09:08 +03:00
/**
2002-08-17 21:00:51 +04:00
Convert a string to upper case .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
2001-07-04 11:15:53 +04:00
void strupper_m ( char * s )
{
2004-02-04 23:28:51 +03:00
size_t len ;
2004-09-01 21:39:27 +04:00
int errno_save ;
2004-02-04 23:28:51 +03:00
2002-04-11 13:56:38 +04:00
/* this is quite a common operation, so we want it to be
fast . We optimise for the ascii case , knowing that all our
supported multi - byte character sets are ascii - compatible
( ie . they match for the first 128 chars ) */
2002-08-17 21:00:51 +04:00
2004-01-08 02:21:36 +03:00
while ( * s & & ! ( ( ( unsigned char ) s [ 0 ] ) & 0x80 ) ) {
2005-12-27 23:52:36 +03:00
* s = toupper_ascii ( ( unsigned char ) * s ) ;
2003-01-17 09:40:12 +03:00
s + + ;
}
2002-04-11 13:56:38 +04:00
2002-08-17 21:00:51 +04:00
if ( ! * s )
return ;
2002-04-11 13:56:38 +04:00
2001-07-04 11:15:53 +04:00
/* I assume that lowercased string takes the same number of bytes
* as source string even in multibyte encoding . ( VIV ) */
2004-02-04 23:28:51 +03:00
len = strlen ( s ) + 1 ;
2004-09-01 21:39:27 +04:00
errno_save = errno ;
2004-02-04 23:28:51 +03:00
errno = 0 ;
unix_strupper ( s , len , s , len ) ;
/* Catch mb conversion errors that may not terminate. */
if ( errno )
s [ len - 1 ] = ' \0 ' ;
2004-09-01 21:39:27 +04:00
errno = errno_save ;
2001-07-04 11:15:53 +04:00
}
2001-12-10 03:39:01 +03:00
2006-09-21 21:00:07 +04:00
/**
Count the number of UCS2 characters in a string . Normally this will
be the same as the number of bytes in a string for single byte strings ,
but will be different for multibyte .
* */
size_t strlen_m ( const char * s )
{
size_t count = 0 ;
if ( ! s ) {
return 0 ;
}
while ( * s & & ! ( ( ( uint8_t ) * s ) & 0x80 ) ) {
s + + ;
count + + ;
}
if ( ! * s ) {
return count ;
}
while ( * s ) {
size_t c_size ;
codepoint_t c = next_codepoint ( s , & c_size ) ;
if ( c < 0x10000 ) {
/* Unicode char fits into 16 bits. */
count + = 1 ;
} else {
/* Double-width unicode char - 32 bits. */
count + = 2 ;
}
s + = c_size ;
}
return count ;
}
/**
Count the number of UCS2 characters in a string including the null
terminator .
* */
size_t strlen_m_term ( const char * s )
{
if ( ! s ) {
return 0 ;
}
return strlen_m ( s ) + 1 ;
}
2006-11-19 20:07:59 +03:00
/*
* Weird helper routine for the winreg pipe : If nothing is around , return 0 ,
* if a string is there , include the terminator .
*/
size_t strlen_m_term_null ( const char * s )
{
size_t len ;
if ( ! s ) {
return 0 ;
}
len = strlen_m ( s ) ;
if ( len = = 0 ) {
return 0 ;
}
return len + 1 ;
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Return a RFC2254 binary string representation of a buffer .
Used in LDAP filters .
Caller must free .
2003-02-24 06:09:08 +03:00
* */
2002-10-02 23:12:14 +04:00
2006-04-28 18:44:43 +04:00
char * binary_string_rfc2254 ( char * buf , int len )
2001-12-10 03:39:01 +03:00
{
char * s ;
int i , j ;
const char * hex = " 0123456789ABCDEF " ;
2006-07-30 20:36:56 +04:00
s = ( char * ) SMB_MALLOC ( len * 3 + 1 ) ;
2002-08-17 21:00:51 +04:00
if ( ! s )
return NULL ;
2001-12-10 03:39:01 +03:00
for ( j = i = 0 ; i < len ; i + + ) {
s [ j ] = ' \\ ' ;
s [ j + 1 ] = hex [ ( ( unsigned char ) buf [ i ] ) > > 4 ] ;
s [ j + 2 ] = hex [ ( ( unsigned char ) buf [ i ] ) & 0xF ] ;
j + = 3 ;
}
s [ j ] = 0 ;
return s ;
}
2006-04-28 18:44:43 +04:00
char * binary_string ( char * buf , int len )
{
char * s ;
int i , j ;
const char * hex = " 0123456789ABCDEF " ;
2006-07-30 20:36:56 +04:00
s = ( char * ) SMB_MALLOC ( len * 2 + 1 ) ;
2006-04-28 18:44:43 +04:00
if ( ! s )
return NULL ;
for ( j = i = 0 ; i < len ; i + + ) {
s [ j ] = hex [ ( ( unsigned char ) buf [ i ] ) > > 4 ] ;
s [ j + 1 ] = hex [ ( ( unsigned char ) buf [ i ] ) & 0xF ] ;
j + = 2 ;
}
s [ j ] = 0 ;
return s ;
}
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Just a typesafety wrapper for snprintf into a pstring .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
2003-01-03 06:24:23 +03:00
int pstr_sprintf ( pstring s , const char * fmt , . . . )
2002-01-15 04:37:12 +03:00
{
va_list ap ;
int ret ;
va_start ( ap , fmt ) ;
2002-01-16 05:42:07 +03:00
ret = vsnprintf ( s , PSTRING_LEN , fmt , ap ) ;
2002-01-15 04:37:12 +03:00
va_end ( ap ) ;
return ret ;
}
2003-04-15 23:51:17 +04:00
2003-02-24 06:09:08 +03:00
/**
2002-10-02 23:12:14 +04:00
Just a typesafety wrapper for snprintf into a fstring .
2003-02-24 06:09:08 +03:00
* */
2002-08-17 21:00:51 +04:00
2003-04-15 23:51:17 +04:00
int fstr_sprintf ( fstring s , const char * fmt , . . . )
2002-01-15 04:37:12 +03:00
{
va_list ap ;
int ret ;
va_start ( ap , fmt ) ;
2002-01-16 05:42:07 +03:00
ret = vsnprintf ( s , FSTRING_LEN , fmt , ap ) ;
2002-01-15 04:37:12 +03:00
va_end ( ap ) ;
return ret ;
}
2003-04-15 23:51:17 +04:00
2003-02-24 06:09:08 +03:00
/**
2002-07-15 14:35:28 +04:00
List of Strings manipulation functions
2003-02-24 06:09:08 +03:00
* */
2002-07-15 14:35:28 +04:00
# define S_LIST_ABS 16 /* List Allocation Block Size */
2006-02-04 01:19:41 +03:00
static char * * str_list_make_internal ( TALLOC_CTX * mem_ctx , const char * string , const char * sep )
2002-07-15 14:35:28 +04:00
{
char * * list , * * rlist ;
2002-11-13 02:20:50 +03:00
const char * str ;
char * s ;
2002-07-15 14:35:28 +04:00
int num , lsize ;
pstring tok ;
2002-08-17 21:00:51 +04:00
if ( ! string | | ! * string )
return NULL ;
2006-02-04 01:19:41 +03:00
if ( mem_ctx ) {
s = talloc_strdup ( mem_ctx , string ) ;
} else {
s = SMB_STRDUP ( string ) ;
}
2002-07-15 14:35:28 +04:00
if ( ! s ) {
DEBUG ( 0 , ( " str_list_make: Unable to allocate memory " ) ) ;
return NULL ;
}
2002-08-17 21:00:51 +04:00
if ( ! sep ) sep = LIST_SEP ;
2002-07-15 14:35:28 +04:00
num = lsize = 0 ;
list = NULL ;
str = s ;
2002-08-17 21:00:51 +04:00
while ( next_token ( & str , tok , sep , sizeof ( tok ) ) ) {
2002-07-15 14:35:28 +04:00
if ( num = = lsize ) {
lsize + = S_LIST_ABS ;
2006-02-04 01:19:41 +03:00
if ( mem_ctx ) {
rlist = TALLOC_REALLOC_ARRAY ( mem_ctx , list , char * , lsize + 1 ) ;
} else {
r13915: Fixed a very interesting class of realloc() bugs found by Coverity.
realloc can return NULL in one of two cases - (1) the realloc failed,
(2) realloc succeeded but the new size requested was zero, in which
case this is identical to a free() call.
The error paths dealing with these two cases should be different,
but mostly weren't. Secondly the standard idiom for dealing with
realloc when you know the new size is non-zero is the following :
tmp = realloc(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
However, there were *many* *many* places in Samba where we were
using the old (broken) idiom of :
p = realloc(p, size)
if (!p) {
return error;
}
which will leak the memory pointed to by p on realloc fail.
This commit (hopefully) fixes all these cases by moving to
a standard idiom of :
p = SMB_REALLOC(p, size)
if (!p) {
return error;
}
Where if the realloc returns null due to the realloc failing
or size == 0 we *guarentee* that the storage pointed to by p
has been freed. This allows me to remove a lot of code that
was dealing with the standard (more verbose) method that required
a tmp pointer. This is almost always what you want. When a
realloc fails you never usually want the old memory, you
want to free it and get into your error processing asap.
For the 11 remaining cases where we really do need to keep the
old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR,
which can be used as follows :
tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the
pointer p, even on size == 0 or realloc fail. All this is
done by a hidden extra argument to Realloc(), BOOL free_old_on_error
which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR
macros (and their array counterparts).
It remains to be seen what this will do to our Coverity bug count :-).
Jeremy.
(This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
/* We need to keep the old list on error so we can free the elements
if the realloc fails . */
rlist = SMB_REALLOC_ARRAY_KEEP_OLD_ON_ERROR ( list , char * , lsize + 1 ) ;
2006-02-04 01:19:41 +03:00
}
2002-07-15 14:35:28 +04:00
if ( ! rlist ) {
DEBUG ( 0 , ( " str_list_make: Unable to allocate memory " ) ) ;
str_list_free ( & list ) ;
2006-02-04 01:19:41 +03:00
if ( mem_ctx ) {
2006-02-20 20:59:58 +03:00
TALLOC_FREE ( s ) ;
2006-02-04 01:19:41 +03:00
} else {
SAFE_FREE ( s ) ;
}
2002-07-15 14:35:28 +04:00
return NULL ;
r13915: Fixed a very interesting class of realloc() bugs found by Coverity.
realloc can return NULL in one of two cases - (1) the realloc failed,
(2) realloc succeeded but the new size requested was zero, in which
case this is identical to a free() call.
The error paths dealing with these two cases should be different,
but mostly weren't. Secondly the standard idiom for dealing with
realloc when you know the new size is non-zero is the following :
tmp = realloc(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
However, there were *many* *many* places in Samba where we were
using the old (broken) idiom of :
p = realloc(p, size)
if (!p) {
return error;
}
which will leak the memory pointed to by p on realloc fail.
This commit (hopefully) fixes all these cases by moving to
a standard idiom of :
p = SMB_REALLOC(p, size)
if (!p) {
return error;
}
Where if the realloc returns null due to the realloc failing
or size == 0 we *guarentee* that the storage pointed to by p
has been freed. This allows me to remove a lot of code that
was dealing with the standard (more verbose) method that required
a tmp pointer. This is almost always what you want. When a
realloc fails you never usually want the old memory, you
want to free it and get into your error processing asap.
For the 11 remaining cases where we really do need to keep the
old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR,
which can be used as follows :
tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the
pointer p, even on size == 0 or realloc fail. All this is
done by a hidden extra argument to Realloc(), BOOL free_old_on_error
which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR
macros (and their array counterparts).
It remains to be seen what this will do to our Coverity bug count :-).
Jeremy.
(This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
} else {
2002-10-02 23:12:14 +04:00
list = rlist ;
r13915: Fixed a very interesting class of realloc() bugs found by Coverity.
realloc can return NULL in one of two cases - (1) the realloc failed,
(2) realloc succeeded but the new size requested was zero, in which
case this is identical to a free() call.
The error paths dealing with these two cases should be different,
but mostly weren't. Secondly the standard idiom for dealing with
realloc when you know the new size is non-zero is the following :
tmp = realloc(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
However, there were *many* *many* places in Samba where we were
using the old (broken) idiom of :
p = realloc(p, size)
if (!p) {
return error;
}
which will leak the memory pointed to by p on realloc fail.
This commit (hopefully) fixes all these cases by moving to
a standard idiom of :
p = SMB_REALLOC(p, size)
if (!p) {
return error;
}
Where if the realloc returns null due to the realloc failing
or size == 0 we *guarentee* that the storage pointed to by p
has been freed. This allows me to remove a lot of code that
was dealing with the standard (more verbose) method that required
a tmp pointer. This is almost always what you want. When a
realloc fails you never usually want the old memory, you
want to free it and get into your error processing asap.
For the 11 remaining cases where we really do need to keep the
old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR,
which can be used as follows :
tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the
pointer p, even on size == 0 or realloc fail. All this is
done by a hidden extra argument to Realloc(), BOOL free_old_on_error
which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR
macros (and their array counterparts).
It remains to be seen what this will do to our Coverity bug count :-).
Jeremy.
(This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
}
2002-07-15 14:35:28 +04:00
memset ( & list [ num ] , 0 , ( ( sizeof ( char * * ) ) * ( S_LIST_ABS + 1 ) ) ) ;
}
2006-02-04 01:19:41 +03:00
if ( mem_ctx ) {
list [ num ] = talloc_strdup ( mem_ctx , tok ) ;
} else {
list [ num ] = SMB_STRDUP ( tok ) ;
}
2002-07-15 14:35:28 +04:00
if ( ! list [ num ] ) {
DEBUG ( 0 , ( " str_list_make: Unable to allocate memory " ) ) ;
str_list_free ( & list ) ;
2006-02-04 01:19:41 +03:00
if ( mem_ctx ) {
2006-02-20 20:59:58 +03:00
TALLOC_FREE ( s ) ;
2006-02-04 01:19:41 +03:00
} else {
SAFE_FREE ( s ) ;
}
2002-07-15 14:35:28 +04:00
return NULL ;
}
num + + ;
}
2006-02-04 01:19:41 +03:00
if ( mem_ctx ) {
2006-02-20 20:59:58 +03:00
TALLOC_FREE ( s ) ;
2006-02-04 01:19:41 +03:00
} else {
SAFE_FREE ( s ) ;
}
2002-07-15 14:35:28 +04:00
return list ;
}
2006-02-04 01:19:41 +03:00
char * * str_list_make_talloc ( TALLOC_CTX * mem_ctx , const char * string , const char * sep )
{
return str_list_make_internal ( mem_ctx , string , sep ) ;
}
char * * str_list_make ( const char * string , const char * sep )
{
return str_list_make_internal ( NULL , string , sep ) ;
}
2002-11-13 02:20:50 +03:00
BOOL str_list_copy ( char * * * dest , const char * * src )
2002-07-15 14:35:28 +04:00
{
char * * list , * * rlist ;
int num , lsize ;
* dest = NULL ;
2002-08-17 21:00:51 +04:00
if ( ! src )
return False ;
2002-07-15 14:35:28 +04:00
num = lsize = 0 ;
list = NULL ;
2002-08-17 21:00:51 +04:00
while ( src [ num ] ) {
2002-07-15 14:35:28 +04:00
if ( num = = lsize ) {
lsize + = S_LIST_ABS ;
r13915: Fixed a very interesting class of realloc() bugs found by Coverity.
realloc can return NULL in one of two cases - (1) the realloc failed,
(2) realloc succeeded but the new size requested was zero, in which
case this is identical to a free() call.
The error paths dealing with these two cases should be different,
but mostly weren't. Secondly the standard idiom for dealing with
realloc when you know the new size is non-zero is the following :
tmp = realloc(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
However, there were *many* *many* places in Samba where we were
using the old (broken) idiom of :
p = realloc(p, size)
if (!p) {
return error;
}
which will leak the memory pointed to by p on realloc fail.
This commit (hopefully) fixes all these cases by moving to
a standard idiom of :
p = SMB_REALLOC(p, size)
if (!p) {
return error;
}
Where if the realloc returns null due to the realloc failing
or size == 0 we *guarentee* that the storage pointed to by p
has been freed. This allows me to remove a lot of code that
was dealing with the standard (more verbose) method that required
a tmp pointer. This is almost always what you want. When a
realloc fails you never usually want the old memory, you
want to free it and get into your error processing asap.
For the 11 remaining cases where we really do need to keep the
old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR,
which can be used as follows :
tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the
pointer p, even on size == 0 or realloc fail. All this is
done by a hidden extra argument to Realloc(), BOOL free_old_on_error
which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR
macros (and their array counterparts).
It remains to be seen what this will do to our Coverity bug count :-).
Jeremy.
(This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
rlist = SMB_REALLOC_ARRAY_KEEP_OLD_ON_ERROR ( list , char * , lsize + 1 ) ;
2002-07-15 14:35:28 +04:00
if ( ! rlist ) {
2002-10-01 17:10:57 +04:00
DEBUG ( 0 , ( " str_list_copy: Unable to re-allocate memory " ) ) ;
2002-07-15 14:35:28 +04:00
str_list_free ( & list ) ;
return False ;
2006-03-07 21:52:48 +03:00
} else {
2002-10-02 23:12:14 +04:00
list = rlist ;
2006-03-07 21:52:48 +03:00
}
2002-07-15 14:35:28 +04:00
memset ( & list [ num ] , 0 , ( ( sizeof ( char * * ) ) * ( S_LIST_ABS + 1 ) ) ) ;
}
2004-12-07 21:25:53 +03:00
list [ num ] = SMB_STRDUP ( src [ num ] ) ;
2002-07-15 14:35:28 +04:00
if ( ! list [ num ] ) {
DEBUG ( 0 , ( " str_list_copy: Unable to allocate memory " ) ) ;
str_list_free ( & list ) ;
return False ;
}
num + + ;
}
* dest = list ;
return True ;
}
2003-02-24 06:09:08 +03:00
/**
* Return true if all the elements of the list match exactly .
* */
2002-07-15 14:35:28 +04:00
BOOL str_list_compare ( char * * list1 , char * * list2 )
{
int num ;
2002-08-17 21:00:51 +04:00
if ( ! list1 | | ! list2 )
return ( list1 = = list2 ) ;
2002-07-15 14:35:28 +04:00
for ( num = 0 ; list1 [ num ] ; num + + ) {
2002-08-17 21:00:51 +04:00
if ( ! list2 [ num ] )
return False ;
if ( ! strcsequal ( list1 [ num ] , list2 [ num ] ) )
return False ;
2002-07-15 14:35:28 +04:00
}
2002-08-17 21:00:51 +04:00
if ( list2 [ num ] )
return False ; /* if list2 has more elements than list1 fail */
2002-07-15 14:35:28 +04:00
return True ;
}
2006-02-04 01:19:41 +03:00
static void str_list_free_internal ( TALLOC_CTX * mem_ctx , char * * * list )
2002-07-15 14:35:28 +04:00
{
char * * tlist ;
2002-08-17 21:00:51 +04:00
if ( ! list | | ! * list )
return ;
2002-07-15 14:35:28 +04:00
tlist = * list ;
2006-02-04 01:19:41 +03:00
for ( ; * tlist ; tlist + + ) {
if ( mem_ctx ) {
2006-02-20 20:59:58 +03:00
TALLOC_FREE ( * tlist ) ;
2006-02-04 01:19:41 +03:00
} else {
SAFE_FREE ( * tlist ) ;
}
}
if ( mem_ctx ) {
2006-02-20 20:59:58 +03:00
TALLOC_FREE ( * tlist ) ;
2006-02-04 01:19:41 +03:00
} else {
SAFE_FREE ( * list ) ;
}
}
void str_list_free_talloc ( TALLOC_CTX * mem_ctx , char * * * list )
{
str_list_free_internal ( mem_ctx , list ) ;
}
void str_list_free ( char * * * list )
{
str_list_free_internal ( NULL , list ) ;
2002-07-15 14:35:28 +04:00
}
2005-03-24 02:26:33 +03:00
/******************************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int str_list_count ( const char * * list )
{
int i = 0 ;
2006-02-08 18:09:09 +03:00
if ( ! list )
return 0 ;
2005-03-24 02:26:33 +03:00
/* count the number of list members */
for ( i = 0 ; * list ; i + + , list + + ) ;
return i ;
}
2003-09-05 09:32:32 +04:00
/******************************************************************************
version of standard_sub_basic ( ) for string lists ; uses alloc_sub_basic ( )
for the work
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-07-11 22:01:26 +04:00
BOOL str_list_sub_basic ( char * * list , const char * smb_name ,
const char * domain_name )
2003-09-05 09:32:32 +04:00
{
char * s , * tmpstr ;
while ( * list ) {
s = * list ;
2006-07-11 22:01:26 +04:00
tmpstr = alloc_sub_basic ( smb_name , domain_name , s ) ;
2003-09-05 09:32:32 +04:00
if ( ! tmpstr ) {
DEBUG ( 0 , ( " str_list_sub_basic: alloc_sub_basic() return NULL! \n " ) ) ;
return False ;
}
2004-08-30 22:27:07 +04:00
SAFE_FREE ( * list ) ;
2003-09-05 09:32:32 +04:00
* list = tmpstr ;
list + + ;
}
return True ;
}
/******************************************************************************
substritute a specific pattern in a string list
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-07-15 14:35:28 +04:00
BOOL str_list_substitute ( char * * list , const char * pattern , const char * insert )
{
char * p , * s , * t ;
ssize_t ls , lp , li , ld , i , d ;
2002-08-17 21:00:51 +04:00
if ( ! list )
return False ;
if ( ! pattern )
return False ;
if ( ! insert )
return False ;
2002-07-15 14:35:28 +04:00
lp = ( ssize_t ) strlen ( pattern ) ;
li = ( ssize_t ) strlen ( insert ) ;
ld = li - lp ;
2002-08-17 21:00:51 +04:00
while ( * list ) {
2002-07-15 14:35:28 +04:00
s = * list ;
ls = ( ssize_t ) strlen ( s ) ;
2004-03-09 03:17:14 +03:00
while ( ( p = strstr_m ( s , pattern ) ) ) {
2002-07-15 14:35:28 +04:00
t = * list ;
d = p - t ;
2002-08-17 21:00:51 +04:00
if ( ld ) {
2004-12-07 21:25:53 +03:00
t = ( char * ) SMB_MALLOC ( ls + ld + 1 ) ;
2002-07-15 14:35:28 +04:00
if ( ! t ) {
DEBUG ( 0 , ( " str_list_substitute: Unable to allocate memory " ) ) ;
return False ;
}
memcpy ( t , * list , d ) ;
memcpy ( t + d + li , p + lp , ls - d - lp + 1 ) ;
SAFE_FREE ( * list ) ;
* list = t ;
ls + = ld ;
s = t + d + li ;
}
for ( i = 0 ; i < li ; i + + ) {
switch ( insert [ i ] ) {
case ' ` ' :
case ' " ' :
case ' \' ' :
case ' ; ' :
case ' $ ' :
case ' % ' :
case ' \r ' :
case ' \n ' :
t [ d + i ] = ' _ ' ;
break ;
default :
t [ d + i ] = insert [ i ] ;
}
}
}
2003-09-05 09:32:32 +04:00
2002-07-15 14:35:28 +04:00
list + + ;
}
return True ;
}
2002-12-12 02:54:40 +03:00
2003-01-04 11:48:15 +03:00
# define IPSTR_LIST_SEP ","
2003-06-25 21:41:05 +04:00
# define IPSTR_LIST_CHAR ','
2003-01-04 11:48:15 +03:00
/**
* Add ip string representation to ipstr list . Used also
* as part of @ function ipstr_list_make
*
* @ param ipstr_list pointer to string containing ip list ;
* MUST BE already allocated and IS reallocated if necessary
* @ param ipstr_size pointer to current size of ipstr_list ( might be changed
* as a result of reallocation )
* @ param ip IP address which is to be added to list
* @ return pointer to string appended with new ip and possibly
* reallocated to new length
* */
2003-06-25 21:41:05 +04:00
char * ipstr_list_add ( char * * ipstr_list , const struct ip_service * service )
2003-01-04 11:48:15 +03:00
{
char * new_ipstr = NULL ;
/* arguments checking */
2003-06-25 21:41:05 +04:00
if ( ! ipstr_list | | ! service ) return NULL ;
2003-01-04 11:48:15 +03:00
/* attempt to convert ip to a string and append colon separator to it */
if ( * ipstr_list ) {
2003-06-25 21:41:05 +04:00
asprintf ( & new_ipstr , " %s%s%s:%d " , * ipstr_list , IPSTR_LIST_SEP ,
inet_ntoa ( service - > ip ) , service - > port ) ;
2003-01-04 11:48:15 +03:00
SAFE_FREE ( * ipstr_list ) ;
} else {
2003-06-25 21:41:05 +04:00
asprintf ( & new_ipstr , " %s:%d " , inet_ntoa ( service - > ip ) , service - > port ) ;
2003-01-04 11:48:15 +03:00
}
* ipstr_list = new_ipstr ;
return * ipstr_list ;
}
/**
* Allocate and initialise an ipstr list using ip adresses
* passed as arguments .
*
* @ param ipstr_list pointer to string meant to be allocated and set
* @ param ip_list array of ip addresses to place in the list
* @ param ip_count number of addresses stored in ip_list
* @ return pointer to allocated ip string
* */
2003-06-25 21:41:05 +04:00
char * ipstr_list_make ( char * * ipstr_list , const struct ip_service * ip_list , int ip_count )
2003-01-04 11:48:15 +03:00
{
int i ;
/* arguments checking */
2006-08-28 06:27:49 +04:00
if ( ! ip_list | | ! ipstr_list ) return 0 ;
2003-01-04 11:48:15 +03:00
* ipstr_list = NULL ;
/* process ip addresses given as arguments */
for ( i = 0 ; i < ip_count ; i + + )
* ipstr_list = ipstr_list_add ( ipstr_list , & ip_list [ i ] ) ;
return ( * ipstr_list ) ;
}
/**
* Parse given ip string list into array of ip addresses
2003-06-25 21:41:05 +04:00
* ( as ip_service structures )
* e . g . 192.168 .1 .100 : 389 , 192.168 .1 .78 , . . .
2003-01-04 11:48:15 +03:00
*
* @ param ipstr ip string list to be parsed
* @ param ip_list pointer to array of ip addresses which is
* allocated by this function and must be freed by caller
* @ return number of succesfully parsed addresses
* */
2003-06-25 21:41:05 +04:00
int ipstr_list_parse ( const char * ipstr_list , struct ip_service * * ip_list )
2003-01-04 11:48:15 +03:00
{
fstring token_str ;
2003-06-25 21:41:05 +04:00
size_t count ;
int i ;
2003-01-04 11:48:15 +03:00
2003-06-25 21:41:05 +04:00
if ( ! ipstr_list | | ! ip_list )
return 0 ;
count = count_chars ( ipstr_list , IPSTR_LIST_CHAR ) + 1 ;
2004-12-07 21:25:53 +03:00
if ( ( * ip_list = SMB_MALLOC_ARRAY ( struct ip_service , count ) ) = = NULL ) {
2003-07-25 08:24:40 +04:00
DEBUG ( 0 , ( " ipstr_list_parse: malloc failed for %lu entries \n " , ( unsigned long ) count ) ) ;
2003-06-25 21:41:05 +04:00
return 0 ;
}
2003-01-04 11:48:15 +03:00
2003-06-25 21:41:05 +04:00
for ( i = 0 ;
next_token ( & ipstr_list , token_str , IPSTR_LIST_SEP , FSTRING_LEN ) & & i < count ;
i + + )
{
2003-01-04 11:48:15 +03:00
struct in_addr addr ;
2003-06-25 21:41:05 +04:00
unsigned port = 0 ;
char * p = strchr ( token_str , ' : ' ) ;
if ( p ) {
* p = 0 ;
port = atoi ( p + 1 ) ;
}
2003-01-04 11:48:15 +03:00
/* convert single token to ip address */
if ( ( addr . s_addr = inet_addr ( token_str ) ) = = INADDR_NONE )
break ;
2003-06-25 21:41:05 +04:00
( * ip_list ) [ i ] . ip = addr ;
( * ip_list ) [ i ] . port = port ;
2003-01-04 11:48:15 +03:00
}
return count ;
}
/**
* Safely free ip string list
*
* @ param ipstr_list ip string list to be freed
* */
void ipstr_list_free ( char * ipstr_list )
{
SAFE_FREE ( ipstr_list ) ;
}
2003-02-24 06:09:08 +03:00
/**
2003-01-04 11:48:15 +03:00
Unescape a URL encoded string , in place .
2003-02-24 06:09:08 +03:00
* */
2003-01-04 11:48:15 +03:00
void rfc1738_unescape ( char * buf )
{
char * p = buf ;
while ( p & & * p & & ( p = strchr_m ( p , ' % ' ) ) ) {
int c1 = p [ 1 ] ;
int c2 = p [ 2 ] ;
if ( c1 > = ' 0 ' & & c1 < = ' 9 ' )
c1 = c1 - ' 0 ' ;
else if ( c1 > = ' A ' & & c1 < = ' F ' )
c1 = 10 + c1 - ' A ' ;
else if ( c1 > = ' a ' & & c1 < = ' f ' )
c1 = 10 + c1 - ' a ' ;
else { p + + ; continue ; }
if ( c2 > = ' 0 ' & & c2 < = ' 9 ' )
c2 = c2 - ' 0 ' ;
else if ( c2 > = ' A ' & & c2 < = ' F ' )
c2 = 10 + c2 - ' A ' ;
else if ( c2 > = ' a ' & & c2 < = ' f ' )
c2 = 10 + c2 - ' a ' ;
else { p + + ; continue ; }
* p = ( c1 < < 4 ) | c2 ;
memmove ( p + 1 , p + 3 , strlen ( p + 3 ) + 1 ) ;
p + + ;
}
}
2003-01-28 15:07:02 +03:00
static const char * b64 = " ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/ " ;
2003-02-24 06:09:08 +03:00
/**
* Decode a base64 string into a DATA_BLOB - simple and slow algorithm
* */
2003-01-28 15:07:02 +03:00
DATA_BLOB base64_decode_data_blob ( const char * s )
{
int bit_offset , byte_offset , idx , i , n ;
DATA_BLOB decoded = data_blob ( s , strlen ( s ) + 1 ) ;
unsigned char * d = decoded . data ;
char * p ;
n = i = 0 ;
while ( * s & & ( p = strchr_m ( b64 , * s ) ) ) {
idx = ( int ) ( p - b64 ) ;
byte_offset = ( i * 6 ) / 8 ;
bit_offset = ( i * 6 ) % 8 ;
d [ byte_offset ] & = ~ ( ( 1 < < ( 8 - bit_offset ) ) - 1 ) ;
if ( bit_offset < 3 ) {
d [ byte_offset ] | = ( idx < < ( 2 - bit_offset ) ) ;
n = byte_offset + 1 ;
} else {
d [ byte_offset ] | = ( idx > > ( bit_offset - 2 ) ) ;
d [ byte_offset + 1 ] = 0 ;
d [ byte_offset + 1 ] | = ( idx < < ( 8 - ( bit_offset - 2 ) ) ) & 0xFF ;
n = byte_offset + 2 ;
}
s + + ; i + + ;
}
2004-07-22 17:39:43 +04:00
if ( ( n > 0 ) & & ( * s = = ' = ' ) ) {
n - = 1 ;
}
2004-01-23 15:04:07 +03:00
2003-01-28 15:07:02 +03:00
/* fix up length */
decoded . length = n ;
return decoded ;
}
2003-02-24 06:09:08 +03:00
/**
* Decode a base64 string in - place - wrapper for the above
* */
2003-02-19 02:17:59 +03:00
void base64_decode_inplace ( char * s )
2003-01-28 15:07:02 +03:00
{
DATA_BLOB decoded = base64_decode_data_blob ( s ) ;
2004-07-22 17:39:43 +04:00
if ( decoded . length ! = 0 ) {
memcpy ( s , decoded . data , decoded . length ) ;
/* null terminate */
s [ decoded . length ] = ' \0 ' ;
} else {
* s = ' \0 ' ;
}
2003-04-02 04:17:03 +04:00
data_blob_free ( & decoded ) ;
2003-01-28 15:07:02 +03:00
}
2003-02-24 06:09:08 +03:00
/**
* Encode a base64 string into a malloc ( ) ed string caller to free .
*
* From SQUID : adopted from http : //ftp.sunet.se/pub2/gnu/vm/base64-encode.c with adjustments
* */
2003-01-28 15:07:02 +03:00
char * base64_encode_data_blob ( DATA_BLOB data )
{
int bits = 0 ;
int char_count = 0 ;
2005-02-01 21:24:39 +03:00
size_t out_cnt , len , output_len ;
char * result ;
if ( ! data . length | | ! data . data )
return NULL ;
out_cnt = 0 ;
len = data . length ;
output_len = data . length * 2 ;
2006-07-30 20:36:56 +04:00
result = ( char * ) SMB_MALLOC ( output_len ) ; /* get us plenty of space */
2003-01-28 15:07:02 +03:00
while ( len - - & & out_cnt < ( data . length * 2 ) - 5 ) {
int c = ( unsigned char ) * ( data . data + + ) ;
bits + = c ;
char_count + + ;
if ( char_count = = 3 ) {
result [ out_cnt + + ] = b64 [ bits > > 18 ] ;
result [ out_cnt + + ] = b64 [ ( bits > > 12 ) & 0x3f ] ;
result [ out_cnt + + ] = b64 [ ( bits > > 6 ) & 0x3f ] ;
result [ out_cnt + + ] = b64 [ bits & 0x3f ] ;
bits = 0 ;
char_count = 0 ;
} else {
bits < < = 8 ;
}
}
if ( char_count ! = 0 ) {
bits < < = 16 - ( 8 * char_count ) ;
result [ out_cnt + + ] = b64 [ bits > > 18 ] ;
result [ out_cnt + + ] = b64 [ ( bits > > 12 ) & 0x3f ] ;
if ( char_count = = 1 ) {
result [ out_cnt + + ] = ' = ' ;
result [ out_cnt + + ] = ' = ' ;
} else {
result [ out_cnt + + ] = b64 [ ( bits > > 6 ) & 0x3f ] ;
result [ out_cnt + + ] = ' = ' ;
}
}
result [ out_cnt ] = ' \0 ' ; /* terminate */
return result ;
}
2003-05-12 05:20:17 +04:00
/* read a SMB_BIG_UINT from a string */
SMB_BIG_UINT STR_TO_SMB_BIG_UINT ( const char * nptr , const char * * entptr )
{
SMB_BIG_UINT val = - 1 ;
const char * p = nptr ;
2006-06-20 03:19:24 +04:00
if ( ! p ) {
2006-08-28 05:48:04 +04:00
if ( entptr ) {
* entptr = p ;
}
2006-06-20 03:19:24 +04:00
return val ;
}
while ( * p & & isspace ( * p ) )
2003-05-12 05:20:17 +04:00
p + + ;
2006-06-20 03:19:24 +04:00
2003-05-12 05:20:17 +04:00
# ifdef LARGE_SMB_OFF_T
sscanf ( p , " %llu " , & val ) ;
# else /* LARGE_SMB_OFF_T */
sscanf ( p , " %lu " , & val ) ;
# endif /* LARGE_SMB_OFF_T */
if ( entptr ) {
2006-06-20 03:19:24 +04:00
while ( * p & & isdigit ( * p ) )
2003-05-12 05:20:17 +04:00
p + + ;
* entptr = p ;
}
return val ;
}
2004-04-07 16:43:44 +04:00
2006-07-11 22:01:26 +04:00
/* Convert a size specification to a count of bytes. We accept the following
* suffixes :
* bytes if there is no suffix
* kK kibibytes
* mM mebibytes
* gG gibibytes
* tT tibibytes
* pP whatever the ISO name for petabytes is
*
* Returns 0 if the string can ' t be converted .
*/
SMB_OFF_T conv_str_size ( const char * str )
{
SMB_OFF_T lval ;
char * end ;
if ( str = = NULL | | * str = = ' \0 ' ) {
return 0 ;
}
# ifdef HAVE_STRTOULL
if ( sizeof ( SMB_OFF_T ) = = 8 ) {
lval = strtoull ( str , & end , 10 /* base */ ) ;
} else {
lval = strtoul ( str , & end , 10 /* base */ ) ;
}
# else
lval = strtoul ( str , & end , 10 /* base */ ) ;
# endif
if ( end = = NULL | | end = = str ) {
return 0 ;
}
if ( * end ) {
SMB_OFF_T lval_orig = lval ;
if ( strwicmp ( end , " K " ) = = 0 ) {
lval * = ( SMB_OFF_T ) 1024 ;
} else if ( strwicmp ( end , " M " ) = = 0 ) {
lval * = ( ( SMB_OFF_T ) 1024 * ( SMB_OFF_T ) 1024 ) ;
} else if ( strwicmp ( end , " G " ) = = 0 ) {
lval * = ( ( SMB_OFF_T ) 1024 * ( SMB_OFF_T ) 1024 *
( SMB_OFF_T ) 1024 ) ;
} else if ( strwicmp ( end , " T " ) = = 0 ) {
lval * = ( ( SMB_OFF_T ) 1024 * ( SMB_OFF_T ) 1024 *
( SMB_OFF_T ) 1024 * ( SMB_OFF_T ) 1024 ) ;
} else if ( strwicmp ( end , " P " ) = = 0 ) {
lval * = ( ( SMB_OFF_T ) 1024 * ( SMB_OFF_T ) 1024 *
( SMB_OFF_T ) 1024 * ( SMB_OFF_T ) 1024 *
( SMB_OFF_T ) 1024 ) ;
} else {
return 0 ;
}
/* Primitive attempt to detect wrapping on platforms with
* 4 - byte SMB_OFF_T . It ' s better to let the caller handle
* a failure than some random number .
*/
if ( lval_orig < = lval ) {
return 0 ;
}
}
return lval ;
}
2004-04-07 16:43:44 +04:00
void string_append ( char * * left , const char * right )
{
int new_len = strlen ( right ) + 1 ;
if ( * left = = NULL ) {
2006-07-30 20:36:56 +04:00
* left = ( char * ) SMB_MALLOC ( new_len ) ;
2004-04-07 16:43:44 +04:00
* left [ 0 ] = ' \0 ' ;
} else {
new_len + = strlen ( * left ) ;
2006-07-30 20:36:56 +04:00
* left = ( char * ) SMB_REALLOC ( * left , new_len ) ;
2004-04-07 16:43:44 +04:00
}
r13915: Fixed a very interesting class of realloc() bugs found by Coverity.
realloc can return NULL in one of two cases - (1) the realloc failed,
(2) realloc succeeded but the new size requested was zero, in which
case this is identical to a free() call.
The error paths dealing with these two cases should be different,
but mostly weren't. Secondly the standard idiom for dealing with
realloc when you know the new size is non-zero is the following :
tmp = realloc(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
However, there were *many* *many* places in Samba where we were
using the old (broken) idiom of :
p = realloc(p, size)
if (!p) {
return error;
}
which will leak the memory pointed to by p on realloc fail.
This commit (hopefully) fixes all these cases by moving to
a standard idiom of :
p = SMB_REALLOC(p, size)
if (!p) {
return error;
}
Where if the realloc returns null due to the realloc failing
or size == 0 we *guarentee* that the storage pointed to by p
has been freed. This allows me to remove a lot of code that
was dealing with the standard (more verbose) method that required
a tmp pointer. This is almost always what you want. When a
realloc fails you never usually want the old memory, you
want to free it and get into your error processing asap.
For the 11 remaining cases where we really do need to keep the
old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR,
which can be used as follows :
tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the
pointer p, even on size == 0 or realloc fail. All this is
done by a hidden extra argument to Realloc(), BOOL free_old_on_error
which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR
macros (and their array counterparts).
It remains to be seen what this will do to our Coverity bug count :-).
Jeremy.
(This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
if ( * left = = NULL ) {
2004-04-07 16:43:44 +04:00
return ;
r13915: Fixed a very interesting class of realloc() bugs found by Coverity.
realloc can return NULL in one of two cases - (1) the realloc failed,
(2) realloc succeeded but the new size requested was zero, in which
case this is identical to a free() call.
The error paths dealing with these two cases should be different,
but mostly weren't. Secondly the standard idiom for dealing with
realloc when you know the new size is non-zero is the following :
tmp = realloc(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
However, there were *many* *many* places in Samba where we were
using the old (broken) idiom of :
p = realloc(p, size)
if (!p) {
return error;
}
which will leak the memory pointed to by p on realloc fail.
This commit (hopefully) fixes all these cases by moving to
a standard idiom of :
p = SMB_REALLOC(p, size)
if (!p) {
return error;
}
Where if the realloc returns null due to the realloc failing
or size == 0 we *guarentee* that the storage pointed to by p
has been freed. This allows me to remove a lot of code that
was dealing with the standard (more verbose) method that required
a tmp pointer. This is almost always what you want. When a
realloc fails you never usually want the old memory, you
want to free it and get into your error processing asap.
For the 11 remaining cases where we really do need to keep the
old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR,
which can be used as follows :
tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the
pointer p, even on size == 0 or realloc fail. All this is
done by a hidden extra argument to Realloc(), BOOL free_old_on_error
which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR
macros (and their array counterparts).
It remains to be seen what this will do to our Coverity bug count :-).
Jeremy.
(This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
}
2004-04-07 16:43:44 +04:00
safe_strcat ( * left , right , new_len - 1 ) ;
}
2005-01-15 06:54:03 +03:00
BOOL add_string_to_array ( TALLOC_CTX * mem_ctx ,
const char * str , const char * * * strings ,
int * num )
{
char * dup_str = talloc_strdup ( mem_ctx , str ) ;
* strings = TALLOC_REALLOC_ARRAY ( mem_ctx , * strings , const char * , ( * num ) + 1 ) ;
2006-12-09 05:58:18 +03:00
if ( ( * strings = = NULL ) | | ( dup_str = = NULL ) ) {
* num = 0 ;
2005-01-15 06:54:03 +03:00
return False ;
2006-12-09 05:58:18 +03:00
}
2005-01-15 06:54:03 +03:00
( * strings ) [ * num ] = dup_str ;
* num + = 1 ;
return True ;
}
2005-06-09 02:10:34 +04:00
/* Append an sprintf'ed string. Double buffer size on demand. Usable without
* error checking in between . The indiation that something weird happened is
* string = = NULL */
void sprintf_append ( TALLOC_CTX * mem_ctx , char * * string , ssize_t * len ,
size_t * bufsize , const char * fmt , . . . )
{
va_list ap ;
char * newstr ;
int ret ;
BOOL increased ;
/* len<0 is an internal marker that something failed */
if ( * len < 0 )
goto error ;
if ( * string = = NULL ) {
if ( * bufsize = = 0 )
* bufsize = 128 ;
2006-12-16 08:02:21 +03:00
* string = TALLOC_ARRAY ( mem_ctx , char , * bufsize ) ;
2005-06-09 02:10:34 +04:00
if ( * string = = NULL )
goto error ;
}
va_start ( ap , fmt ) ;
ret = vasprintf ( & newstr , fmt , ap ) ;
va_end ( ap ) ;
if ( ret < 0 )
goto error ;
increased = False ;
while ( ( * len ) + ret > = * bufsize ) {
increased = True ;
* bufsize * = 2 ;
if ( * bufsize > = ( 1024 * 1024 * 256 ) )
goto error ;
}
if ( increased ) {
2006-12-16 08:02:21 +03:00
* string = TALLOC_REALLOC_ARRAY ( mem_ctx , * string , char ,
* bufsize ) ;
r13915: Fixed a very interesting class of realloc() bugs found by Coverity.
realloc can return NULL in one of two cases - (1) the realloc failed,
(2) realloc succeeded but the new size requested was zero, in which
case this is identical to a free() call.
The error paths dealing with these two cases should be different,
but mostly weren't. Secondly the standard idiom for dealing with
realloc when you know the new size is non-zero is the following :
tmp = realloc(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
However, there were *many* *many* places in Samba where we were
using the old (broken) idiom of :
p = realloc(p, size)
if (!p) {
return error;
}
which will leak the memory pointed to by p on realloc fail.
This commit (hopefully) fixes all these cases by moving to
a standard idiom of :
p = SMB_REALLOC(p, size)
if (!p) {
return error;
}
Where if the realloc returns null due to the realloc failing
or size == 0 we *guarentee* that the storage pointed to by p
has been freed. This allows me to remove a lot of code that
was dealing with the standard (more verbose) method that required
a tmp pointer. This is almost always what you want. When a
realloc fails you never usually want the old memory, you
want to free it and get into your error processing asap.
For the 11 remaining cases where we really do need to keep the
old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR,
which can be used as follows :
tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the
pointer p, even on size == 0 or realloc fail. All this is
done by a hidden extra argument to Realloc(), BOOL free_old_on_error
which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR
macros (and their array counterparts).
It remains to be seen what this will do to our Coverity bug count :-).
Jeremy.
(This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
if ( * string = = NULL ) {
2005-06-09 02:10:34 +04:00
goto error ;
r13915: Fixed a very interesting class of realloc() bugs found by Coverity.
realloc can return NULL in one of two cases - (1) the realloc failed,
(2) realloc succeeded but the new size requested was zero, in which
case this is identical to a free() call.
The error paths dealing with these two cases should be different,
but mostly weren't. Secondly the standard idiom for dealing with
realloc when you know the new size is non-zero is the following :
tmp = realloc(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
However, there were *many* *many* places in Samba where we were
using the old (broken) idiom of :
p = realloc(p, size)
if (!p) {
return error;
}
which will leak the memory pointed to by p on realloc fail.
This commit (hopefully) fixes all these cases by moving to
a standard idiom of :
p = SMB_REALLOC(p, size)
if (!p) {
return error;
}
Where if the realloc returns null due to the realloc failing
or size == 0 we *guarentee* that the storage pointed to by p
has been freed. This allows me to remove a lot of code that
was dealing with the standard (more verbose) method that required
a tmp pointer. This is almost always what you want. When a
realloc fails you never usually want the old memory, you
want to free it and get into your error processing asap.
For the 11 remaining cases where we really do need to keep the
old pointer I have invented the new macro SMB_REALLOC_KEEP_OLD_ON_ERROR,
which can be used as follows :
tmp = SMB_REALLOC_KEEP_OLD_ON_ERROR(p, size);
if (!tmp) {
SAFE_FREE(p);
return error;
} else {
p = tmp;
}
SMB_REALLOC_KEEP_OLD_ON_ERROR guarentees never to free the
pointer p, even on size == 0 or realloc fail. All this is
done by a hidden extra argument to Realloc(), BOOL free_old_on_error
which is set appropriately by the SMB_REALLOC and SMB_REALLOC_KEEP_OLD_ON_ERROR
macros (and their array counterparts).
It remains to be seen what this will do to our Coverity bug count :-).
Jeremy.
(This used to be commit 1d710d06a214f3f1740e80e0bffd6aab44aac2b0)
2006-03-07 09:31:04 +03:00
}
2005-06-09 02:10:34 +04:00
}
StrnCpy ( ( * string ) + ( * len ) , newstr , ret ) ;
( * len ) + = ret ;
free ( newstr ) ;
return ;
error :
* len = - 1 ;
* string = NULL ;
}
2005-07-07 01:02:43 +04:00
/*
Returns the substring from src between the first occurrence of
the char " front " and the first occurence of the char " back " .
Mallocs the return string which must be freed . Not for use
with wide character strings .
*/
char * sstring_sub ( const char * src , char front , char back )
{
char * temp1 , * temp2 , * temp3 ;
ptrdiff_t len ;
temp1 = strchr ( src , front ) ;
if ( temp1 = = NULL ) return NULL ;
temp2 = strchr ( src , back ) ;
if ( temp2 = = NULL ) return NULL ;
len = temp2 - temp1 ;
if ( len < = 0 ) return NULL ;
temp3 = ( char * ) SMB_MALLOC ( len ) ;
if ( temp3 = = NULL ) {
DEBUG ( 1 , ( " Malloc failure in sstring_sub \n " ) ) ;
return NULL ;
}
memcpy ( temp3 , temp1 + 1 , len - 1 ) ;
temp3 [ len - 1 ] = ' \0 ' ;
return temp3 ;
}
2006-02-04 01:19:41 +03:00
/********************************************************************
Check a string for any occurrences of a specified list of invalid
characters .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL validate_net_name ( const char * name , const char * invalid_chars , int max_len )
{
int i ;
for ( i = 0 ; i < max_len & & name [ i ] ; i + + ) {
/* fail if strchr_m() finds one of the invalid characters */
if ( name [ i ] & & strchr_m ( invalid_chars , name [ i ] ) ) {
return False ;
}
}
return True ;
}
2006-07-11 22:01:26 +04:00
/**
return the number of bytes occupied by a buffer in ASCII format
the result includes the null termination
limited by ' n ' bytes
* */
size_t ascii_len_n ( const char * src , size_t n )
{
size_t len ;
len = strnlen ( src , n ) ;
if ( len + 1 < = n ) {
len + = 1 ;
}
return len ;
}
/**
return the number of bytes occupied by a buffer in CH_UTF16 format
the result includes the null termination
* */
size_t utf16_len ( const void * buf )
{
size_t len ;
for ( len = 0 ; SVAL ( buf , len ) ; len + = 2 ) ;
return len + 2 ;
}
/**
return the number of bytes occupied by a buffer in CH_UTF16 format
the result includes the null termination
limited by ' n ' bytes
* */
size_t utf16_len_n ( const void * src , size_t n )
{
size_t len ;
for ( len = 0 ; ( len + 2 < n ) & & SVAL ( src , len ) ; len + = 2 ) ;
if ( len + 2 < = n ) {
len + = 2 ;
}
return len ;
}
2007-05-14 18:23:51 +04:00
/*******************************************************************
Add a shell escape character ' \ ' to any character not in a known list
of characters . UNIX charset format .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-06-05 16:58:18 +04:00
# define INCLUDE_LIST "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_ / \t.,"
2007-05-14 18:23:51 +04:00
# define INSIDE_DQUOTE_LIST "$`\n\"\\"
char * escape_shell_string ( const char * src )
{
size_t srclen = strlen ( src ) ;
2007-06-16 15:48:11 +04:00
char * ret = SMB_MALLOC_ARRAY ( char , ( srclen * 2 ) + 1 ) ;
2007-05-14 18:23:51 +04:00
char * dest = ret ;
BOOL in_s_quote = False ;
BOOL in_d_quote = False ;
BOOL next_escaped = False ;
if ( ! ret ) {
return NULL ;
}
while ( * src ) {
size_t c_size ;
codepoint_t c = next_codepoint ( src , & c_size ) ;
if ( c = = INVALID_CODEPOINT ) {
SAFE_FREE ( ret ) ;
return NULL ;
}
if ( c_size > 1 ) {
memcpy ( dest , src , c_size ) ;
src + = c_size ;
dest + = c_size ;
next_escaped = False ;
continue ;
}
/*
* Deal with backslash escaped state .
* This only lasts for one character .
*/
if ( next_escaped ) {
* dest + + = * src + + ;
next_escaped = False ;
continue ;
}
/*
* Deal with single quote state . The
* only thing we care about is exiting
* this state .
*/
if ( in_s_quote ) {
if ( * src = = ' \' ' ) {
in_s_quote = False ;
}
* dest + + = * src + + ;
continue ;
}
/*
* Deal with double quote state . The most
* complex state . We must cope with \ , meaning
* possibly escape next char ( depending what it
* is ) , " , meaning exit this state, and possibly
* add an \ escape to any unprotected character
* ( listed in INSIDE_DQUOTE_LIST ) .
*/
if ( in_d_quote ) {
if ( * src = = ' \\ ' ) {
/*
* Next character might be escaped .
* We have to peek . Inside double
* quotes only INSIDE_DQUOTE_LIST
* characters are escaped by a \ .
*/
char nextchar ;
c = next_codepoint ( & src [ 1 ] , & c_size ) ;
if ( c = = INVALID_CODEPOINT ) {
SAFE_FREE ( ret ) ;
return NULL ;
}
if ( c_size > 1 ) {
/*
* Don ' t escape the next char .
* Just copy the \ .
*/
* dest + + = * src + + ;
continue ;
}
nextchar = src [ 1 ] ;
if ( nextchar & & strchr ( INSIDE_DQUOTE_LIST , ( int ) nextchar ) ) {
next_escaped = True ;
}
* dest + + = * src + + ;
continue ;
}
if ( * src = = ' \" ' ) {
/* Exit double quote state. */
in_d_quote = False ;
* dest + + = * src + + ;
continue ;
}
/*
* We know the character isn ' t \ or " ,
* so escape it if it ' s any of the other
* possible unprotected characters .
*/
if ( strchr ( INSIDE_DQUOTE_LIST , ( int ) * src ) ) {
* dest + + = ' \\ ' ;
}
* dest + + = * src + + ;
continue ;
}
/*
* From here to the end of the loop we ' re
* not in the single or double quote state .
*/
if ( * src = = ' \\ ' ) {
/* Next character must be escaped. */
next_escaped = True ;
* dest + + = * src + + ;
continue ;
}
if ( * src = = ' \' ' ) {
/* Go into single quote state. */
in_s_quote = True ;
* dest + + = * src + + ;
continue ;
}
if ( * src = = ' \" ' ) {
/* Go into double quote state. */
in_d_quote = True ;
* dest + + = * src + + ;
continue ;
}
/* Check if we need to escape the character. */
if ( ! strchr ( INCLUDE_LIST , ( int ) * src ) ) {
* dest + + = ' \\ ' ;
}
* dest + + = * src + + ;
}
* dest + + = ' \0 ' ;
return ret ;
}