X-Git-Url: https://git.sur5r.net/?a=blobdiff_plain;ds=sidebyside;f=libraries%2Fliblutil%2Futils.c;h=6ed4c6bb04fa6daa917768608614aef987f12b6b;hb=4d0d12db27b3b44cc36acc089b0e640320480fe7;hp=e74f9093ced1da465c7d479bbb234232f01a8034;hpb=2cc356588e586809287fa6f3c92b437e3a32c11a;p=openldap diff --git a/libraries/liblutil/utils.c b/libraries/liblutil/utils.c index e74f9093ce..6ed4c6bb04 100644 --- a/libraries/liblutil/utils.c +++ b/libraries/liblutil/utils.c @@ -1,7 +1,7 @@ /* $OpenLDAP$ */ /* This work is part of OpenLDAP Software . * - * Copyright 1998-2006 The OpenLDAP Foundation. + * Copyright 1998-2012 The OpenLDAP Foundation. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -15,21 +15,29 @@ #include "portable.h" +#include #include #include +#include #include #include #include #include +#include #ifdef HAVE_IO_H #include #endif #ifdef HAVE_FCNTL_H #include #endif +#ifdef _WIN32 +#include +#endif -#include -#include +#include "lutil.h" +#include "ldap_defaults.h" +#include "ldap_pvt.h" +#include "lber_pvt.h" #ifdef HAVE_EBCDIC int _trans_argv = 1; @@ -70,6 +78,13 @@ char* lutil_progname( const char* name, int argc, char *argv[] ) LUTIL_SLASHPATH( argv[0] ); progname = strrchr ( argv[0], *LDAP_DIRSEP ); progname = progname ? &progname[1] : argv[0]; +#ifdef _WIN32 + { + size_t len = strlen( progname ); + if ( len > 4 && strcasecmp( &progname[len - 4], ".exe" ) == 0 ) + progname[len - 4] = '\0'; + } +#endif return progname; } @@ -133,7 +148,7 @@ size_t lutil_localtime( char *s, size_t smax, const struct tm *tm, long delta ) snprintf( p, smax - 15, "%02ld%02ld", delta / 3600, ( delta % 3600 ) / 60 ); - return ret + 5; + return ret + 4; } int lutil_tm2time( struct lutil_tm *tm, struct lutil_timet *tt ) @@ -303,6 +318,21 @@ lutil_strncopy( return a-1; } +/* memcopy is like memcpy except it returns a pointer to the byte past + * the end of the result buffer, set to NULL. This allows fast construction + * of catenated buffers. Provided for API consistency with lutil_str*copy(). + */ +char * +lutil_memcopy( + char *a, + const char *b, + size_t n +) +{ + AC_MEMCPY(a, b, n); + return a + n; +} + #ifndef HAVE_MKSTEMP int mkstemp( char * template ) { @@ -315,7 +345,40 @@ int mkstemp( char * template ) #endif #ifdef _MSC_VER -#include +/* Equivalent of MS CRT's _dosmaperr(). + * @param lastError[in] Result of GetLastError(). + */ +static errno_t win2errno(DWORD lastError) +{ + const struct { + DWORD windows_code; + errno_t errno_code; + } WIN2ERRNO_TABLE[] = { + { ERROR_SUCCESS, 0 }, + { ERROR_FILE_NOT_FOUND, ENOENT }, + { ERROR_PATH_NOT_FOUND, ENOENT }, + { ERROR_TOO_MANY_OPEN_FILES, EMFILE }, + { ERROR_ACCESS_DENIED, EACCES }, + { ERROR_INVALID_HANDLE, EBADF }, + { ERROR_NOT_ENOUGH_MEMORY, ENOMEM }, + { ERROR_LOCK_VIOLATION, EACCES }, + { ERROR_FILE_EXISTS, EEXIST }, + { ERROR_INVALID_PARAMETER, EINVAL }, + { ERROR_FILENAME_EXCED_RANGE, ENAMETOOLONG }, + }; + const unsigned int WIN2ERRNO_TABLE_SIZE = sizeof(WIN2ERRNO_TABLE) / +sizeof(WIN2ERRNO_TABLE[0]); + const errno_t DEFAULT_ERRNO_ERROR = -1; + unsigned int i; + + for (i = 0; i < WIN2ERRNO_TABLE_SIZE; ++i) { + if (WIN2ERRNO_TABLE[i].windows_code == lastError) { + return WIN2ERRNO_TABLE[i].errno_code; + } + } + return DEFAULT_ERRNO_ERROR; +} + struct dirent { char *d_name; }; @@ -333,8 +396,10 @@ DIR *opendir( char *path ) HANDLE h; WIN32_FIND_DATA data; - if (len+3 >= sizeof(tmp)) + if (len+3 >= sizeof(tmp)) { + errno = ENAMETOOLONG; return NULL; + } strcpy(tmp, path); tmp[len++] = '\\'; @@ -342,9 +407,11 @@ DIR *opendir( char *path ) tmp[len] = '\0'; h = FindFirstFile( tmp, &data ); - - if ( h == INVALID_HANDLE_VALUE ) + + if ( h == INVALID_HANDLE_VALUE ) { + errno = win2errno( GetLastError()); return NULL; + } d = ber_memalloc( sizeof(DIR) ); if ( !d ) @@ -368,7 +435,7 @@ struct dirent *readdir(DIR *dir) } return &dir->data; } -void closedir(DIR *dir) +int closedir(DIR *dir) { FindClose(dir->dir); ber_memfree(dir); @@ -379,7 +446,7 @@ void closedir(DIR *dir) * Memory Reverse Search */ void * -lutil_memrchr(const void *b, int c, size_t n) +(lutil_memrchr)(const void *b, int c, size_t n) { if (n != 0) { const unsigned char *s, *bb = b, cc = c; @@ -448,17 +515,28 @@ lutil_atoux( unsigned *v, const char *s, int x ) int lutil_atolx( long *v, const char *s, int x ) { - char *next; - long l; + char *next; + long l; + int save_errno; assert( s != NULL ); assert( v != NULL ); + if ( isspace( s[ 0 ] ) ) { + return -1; + } + + errno = 0; l = strtol( s, &next, x ); + save_errno = errno; if ( next == s || next[ 0 ] != '\0' ) { return -1; } + if ( ( l == LONG_MIN || l == LONG_MAX ) && save_errno != 0 ) { + return -1; + } + *v = l; return 0; @@ -467,29 +545,314 @@ lutil_atolx( long *v, const char *s, int x ) int lutil_atoulx( unsigned long *v, const char *s, int x ) { - char *next; - unsigned long ul; + char *next; + unsigned long ul; + int save_errno; assert( s != NULL ); assert( v != NULL ); /* strtoul() has an odd interface */ - if ( s[ 0 ] == '-' ) { + if ( s[ 0 ] == '-' || isspace( s[ 0 ] ) ) { return -1; } + errno = 0; ul = strtoul( s, &next, x ); + save_errno = errno; if ( next == s || next[ 0 ] != '\0' ) { return -1; } + if ( ( ul == 0 || ul == ULONG_MAX ) && save_errno != 0 ) { + return -1; + } + *v = ul; return 0; } +#ifdef HAVE_LONG_LONG +#if defined(HAVE_STRTOLL) || defined(HAVE_STRTOQ) +int +lutil_atollx( long long *v, const char *s, int x ) +{ + char *next; + long long ll; + int save_errno; + + assert( s != NULL ); + assert( v != NULL ); + + if ( isspace( s[ 0 ] ) ) { + return -1; + } + + errno = 0; +#ifdef HAVE_STRTOLL + ll = strtoll( s, &next, x ); +#else /* HAVE_STRTOQ */ + ll = (unsigned long long)strtoq( s, &next, x ); +#endif /* HAVE_STRTOQ */ + save_errno = errno; + if ( next == s || next[ 0 ] != '\0' ) { + return -1; + } + + /* LLONG_MIN, LLONG_MAX are C99 only */ +#if defined (LLONG_MIN) && defined(LLONG_MAX) + if ( ( ll == LLONG_MIN || ll == LLONG_MAX ) && save_errno != 0 ) { + return -1; + } +#endif /* LLONG_MIN && LLONG_MAX */ + + *v = ll; + + return 0; +} +#endif /* HAVE_STRTOLL || HAVE_STRTOQ */ + +#if defined(HAVE_STRTOULL) || defined(HAVE_STRTOUQ) +int +lutil_atoullx( unsigned long long *v, const char *s, int x ) +{ + char *next; + unsigned long long ull; + int save_errno; + + assert( s != NULL ); + assert( v != NULL ); + + /* strtoull() has an odd interface */ + if ( s[ 0 ] == '-' || isspace( s[ 0 ] ) ) { + return -1; + } + + errno = 0; +#ifdef HAVE_STRTOULL + ull = strtoull( s, &next, x ); +#else /* HAVE_STRTOUQ */ + ull = (unsigned long long)strtouq( s, &next, x ); +#endif /* HAVE_STRTOUQ */ + save_errno = errno; + if ( next == s || next[ 0 ] != '\0' ) { + return -1; + } + + /* ULLONG_MAX is C99 only */ +#if defined(ULLONG_MAX) + if ( ( ull == 0 || ull == ULLONG_MAX ) && save_errno != 0 ) { + return -1; + } +#endif /* ULLONG_MAX */ + + *v = ull; + + return 0; +} +#endif /* HAVE_STRTOULL || HAVE_STRTOUQ */ +#endif /* HAVE_LONG_LONG */ + +/* Multiply an integer by 100000000 and add new */ +typedef struct lutil_int_decnum { + unsigned char *buf; + int bufsiz; + int beg; + int len; +} lutil_int_decnum; + +#define FACTOR1 (100000000&0xffff) +#define FACTOR2 (100000000>>16) + +static void +scale( int new, lutil_int_decnum *prev, unsigned char *tmp ) +{ + int i, j; + unsigned char *in = prev->buf+prev->beg; + unsigned int part; + unsigned char *out = tmp + prev->bufsiz - prev->len; + + memset( tmp, 0, prev->bufsiz ); + if ( prev->len ) { + for ( i = prev->len-1; i>=0; i-- ) { + part = in[i] * FACTOR1; + for ( j = i; part; j-- ) { + part += out[j]; + out[j] = part & 0xff; + part >>= 8; + } + part = in[i] * FACTOR2; + for ( j = i-2; part; j-- ) { + part += out[j]; + out[j] = part & 0xff; + part >>= 8; + } + } + j++; + prev->beg += j; + prev->len -= j; + } + + out = tmp + prev->bufsiz; + i = 0; + do { + i--; + new += out[i]; + out[i] = new & 0xff; + new >>= 8; + } while ( new ); + i = -i; + if ( prev->len < i ) { + prev->beg = prev->bufsiz - i; + prev->len = i; + } + AC_MEMCPY( prev->buf+prev->beg, tmp+prev->beg, prev->len ); +} + +/* Convert unlimited length decimal or hex string to binary. + * Output buffer must be provided, bv_len must indicate buffer size + * Hex input can be "0x1234" or "'1234'H" + * + * Note: High bit of binary form is always the sign bit. If the number + * is supposed to be positive but has the high bit set, a zero byte + * is prepended. It is assumed that this has already been handled on + * any hex input. + */ +int +lutil_str2bin( struct berval *in, struct berval *out, void *ctx ) +{ + char *pin, *pout; + char *end; + int i, chunk, len, rc = 0, hex = 0; + if ( !out || !out->bv_val || out->bv_len < in->bv_len ) + return -1; + + pout = out->bv_val; + /* Leading "0x" for hex input */ + if ( in->bv_len > 2 && in->bv_val[0] == '0' && + ( in->bv_val[1] == 'x' || in->bv_val[1] == 'X' ) ) + { + len = in->bv_len - 2; + pin = in->bv_val + 2; + hex = 1; + } else if ( in->bv_len > 3 && in->bv_val[0] == '\'' && + in->bv_val[in->bv_len-2] == '\'' && + in->bv_val[in->bv_len-1] == 'H' ) + { + len = in->bv_len - 3; + pin = in->bv_val + 1; + hex = 1; + } + if ( hex ) { +#define HEXMAX (2 * sizeof(long)) + unsigned long l; + char tbuf[HEXMAX+1]; + + /* Convert a longword at a time, but handle leading + * odd bytes first + */ + chunk = len % HEXMAX; + if ( !chunk ) + chunk = HEXMAX; + + while ( len ) { + int ochunk; + memcpy( tbuf, pin, chunk ); + tbuf[chunk] = '\0'; + errno = 0; + l = strtoul( tbuf, &end, 16 ); + if ( errno ) + return -1; + ochunk = (chunk + 1)/2; + for ( i = ochunk - 1; i >= 0; i-- ) { + pout[i] = l & 0xff; + l >>= 8; + } + pin += chunk; + pout += ochunk; + len -= chunk; + chunk = HEXMAX; + } + out->bv_len = pout - out->bv_val; + } else { + /* Decimal */ +#define DECMAX 8 /* 8 digits at a time */ + char tmpbuf[64], *tmp; + lutil_int_decnum num; + int neg = 0; + long l; + char tbuf[DECMAX+1]; + + len = in->bv_len; + pin = in->bv_val; + num.buf = (unsigned char *)out->bv_val; + num.bufsiz = out->bv_len; + num.beg = num.bufsiz-1; + num.len = 0; + if ( pin[0] == '-' ) { + neg = 0xff; + len--; + pin++; + } + + /* tmp must be at least as large as outbuf */ + if ( out->bv_len > sizeof(tmpbuf)) { + tmp = ber_memalloc_x( out->bv_len, ctx ); + } else { + tmp = tmpbuf; + } + chunk = len & (DECMAX-1); + if ( !chunk ) + chunk = DECMAX; + + while ( len ) { + memcpy( tbuf, pin, chunk ); + tbuf[chunk] = '\0'; + errno = 0; + l = strtol( tbuf, &end, 10 ); + if ( errno ) { + rc = -1; + goto decfail; + } + scale( l, &num, (unsigned char *)tmp ); + pin += chunk; + len -= chunk; + chunk = DECMAX; + } + /* Negate the result */ + if ( neg ) { + unsigned char *ptr; + + ptr = num.buf+num.beg; + + /* flip all bits */ + for ( i=0; ibv_len = num.len; +decfail: + if ( tmp != tmpbuf ) { + ber_memfree_x( tmp, ctx ); + } + } + return rc; +} + static char time_unit[] = "dhms"; +/* Used to parse and unparse time intervals, not timestamps */ int lutil_parse_time( const char *in, @@ -571,3 +934,53 @@ lutil_unparse_time( return 0; } +/* + * formatted print to string + * + * - if return code < 0, the error code returned by vsnprintf(3) is returned + * + * - if return code > 0, the buffer was not long enough; + * - if next is not NULL, *next will be set to buf + bufsize - 1 + * - if len is not NULL, *len will contain the required buffer length + * + * - if return code == 0, the buffer was long enough; + * - if next is not NULL, *next will point to the end of the string printed so far + * - if len is not NULL, *len will contain the length of the string printed so far + */ +int +lutil_snprintf( char *buf, ber_len_t bufsize, char **next, ber_len_t *len, LDAP_CONST char *fmt, ... ) +{ + va_list ap; + int ret; + + assert( buf != NULL ); + assert( bufsize > 0 ); + assert( fmt != NULL ); + + va_start( ap, fmt ); + ret = vsnprintf( buf, bufsize, fmt, ap ); + va_end( ap ); + + if ( ret < 0 ) { + return ret; + } + + if ( len ) { + *len = ret; + } + + if ( (unsigned) ret >= bufsize ) { + if ( next ) { + *next = &buf[ bufsize - 1 ]; + } + + return 1; + } + + if ( next ) { + *next = &buf[ ret ]; + } + + return 0; +} +