2006-09-18 22:49:20 +00:00
/*
Unix SMB / CIFS implementation .
replacement routines for broken systems
Copyright ( C ) Andrew Tridgell 1992 - 1998
2008-11-01 03:27:45 +01:00
Copyright ( C ) Jelmer Vernooij 2005 - 2008
2006-09-18 22:49:20 +00:00
* * NOTE ! The following LGPL license applies to the replace
* * library . This does NOT imply that all of Samba is released
* * under the LGPL
This library is free software ; you can redistribute it and / or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation ; either
2007-07-10 01:44:42 +00:00
version 3 of the License , or ( at your option ) any later version .
2006-09-18 22:49:20 +00:00
This library 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
Lesser General Public License for more details .
You should have received a copy of the GNU Lesser General Public
2007-07-10 03:42:26 +00:00
License along with this library ; if not , see < http : //www.gnu.org/licenses/>.
2006-09-18 22:49:20 +00:00
*/
# include "replace.h"
# include "system/filesys.h"
# include "system/time.h"
# include "system/passwd.h"
# include "system/syslog.h"
# include "system/locale.h"
# include "system/wait.h"
void replace_dummy ( void ) ;
void replace_dummy ( void ) { }
# ifndef HAVE_FTRUNCATE
/*******************************************************************
ftruncate for operating systems that don ' t have it
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int rep_ftruncate ( int f , off_t l )
{
# ifdef HAVE_CHSIZE
return chsize ( f , l ) ;
# elif defined(F_FREESP)
struct flock fl ;
fl . l_whence = 0 ;
fl . l_len = 0 ;
fl . l_start = l ;
fl . l_type = F_WRLCK ;
return fcntl ( f , F_FREESP , & fl ) ;
# else
# error "you must have a ftruncate function"
# endif
}
# endif /* HAVE_FTRUNCATE */
# ifndef HAVE_STRLCPY
/* like strncpy but does not 0 fill the buffer and always null
terminates . bufsize is the size of the destination buffer */
size_t rep_strlcpy ( char * d , const char * s , size_t bufsize )
{
size_t len = strlen ( s ) ;
size_t ret = len ;
if ( bufsize < = 0 ) return 0 ;
if ( len > = bufsize ) len = bufsize - 1 ;
memcpy ( d , s , len ) ;
d [ len ] = 0 ;
return ret ;
}
# endif
# ifndef HAVE_STRLCAT
/* like strncat but does not 0 fill the buffer and always null
terminates . bufsize is the length of the buffer , which should
be one more than the maximum resulting string length */
size_t rep_strlcat ( char * d , const char * s , size_t bufsize )
{
size_t len1 = strlen ( d ) ;
size_t len2 = strlen ( s ) ;
size_t ret = len1 + len2 ;
if ( len1 + len2 > = bufsize ) {
2008-07-02 11:57:13 -07:00
if ( bufsize < ( len1 + 1 ) ) {
return ret ;
}
2006-09-18 22:49:20 +00:00
len2 = bufsize - ( len1 + 1 ) ;
}
if ( len2 > 0 ) {
memcpy ( d + len1 , s , len2 ) ;
d [ len1 + len2 ] = 0 ;
}
return ret ;
}
# endif
# ifndef HAVE_MKTIME
/*******************************************************************
a mktime ( ) replacement for those who don ' t have it - contributed by
C . A . Lademann < cal @ zls . com >
Corrections by richard . kettlewell @ kewill . com
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define MINUTE 60
# define HOUR 60*MINUTE
# define DAY 24*HOUR
# define YEAR 365*DAY
time_t rep_mktime ( struct tm * t )
{
struct tm * u ;
time_t epoch = 0 ;
int n ;
int mon [ ] = { 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 } ,
y , m , i ;
if ( t - > tm_year < 70 )
return ( ( time_t ) - 1 ) ;
n = t - > tm_year + 1900 - 1 ;
epoch = ( t - > tm_year - 70 ) * YEAR +
( ( n / 4 - n / 100 + n / 400 ) - ( 1969 / 4 - 1969 / 100 + 1969 / 400 ) ) * DAY ;
y = t - > tm_year + 1900 ;
m = 0 ;
for ( i = 0 ; i < t - > tm_mon ; i + + ) {
epoch + = mon [ m ] * DAY ;
if ( m = = 1 & & y % 4 = = 0 & & ( y % 100 ! = 0 | | y % 400 = = 0 ) )
epoch + = DAY ;
if ( + + m > 11 ) {
m = 0 ;
y + + ;
}
}
epoch + = ( t - > tm_mday - 1 ) * DAY ;
epoch + = t - > tm_hour * HOUR + t - > tm_min * MINUTE + t - > tm_sec ;
if ( ( u = localtime ( & epoch ) ) ! = NULL ) {
t - > tm_sec = u - > tm_sec ;
t - > tm_min = u - > tm_min ;
t - > tm_hour = u - > tm_hour ;
t - > tm_mday = u - > tm_mday ;
t - > tm_mon = u - > tm_mon ;
t - > tm_year = u - > tm_year ;
t - > tm_wday = u - > tm_wday ;
t - > tm_yday = u - > tm_yday ;
t - > tm_isdst = u - > tm_isdst ;
}
return ( epoch ) ;
}
# endif /* !HAVE_MKTIME */
# ifndef HAVE_INITGROUPS
/****************************************************************************
some systems don ' t have an initgroups call
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int rep_initgroups ( char * name , gid_t id )
{
# ifndef HAVE_SETGROUPS
/* yikes! no SETGROUPS or INITGROUPS? how can this work? */
errno = ENOSYS ;
return - 1 ;
# else /* HAVE_SETGROUPS */
# include <grp.h>
gid_t * grouplst = NULL ;
2008-08-08 13:32:15 -04:00
int max_gr = NGROUPS_MAX ;
2006-09-18 22:49:20 +00:00
int ret ;
int i , j ;
struct group * g ;
char * gr ;
if ( ( grouplst = malloc ( sizeof ( gid_t ) * max_gr ) ) = = NULL ) {
errno = ENOMEM ;
return - 1 ;
}
grouplst [ 0 ] = id ;
i = 1 ;
while ( i < max_gr & & ( ( g = ( struct group * ) getgrent ( ) ) ! = ( struct group * ) NULL ) ) {
if ( g - > gr_gid = = id )
continue ;
j = 0 ;
gr = g - > gr_mem [ 0 ] ;
while ( gr & & ( * gr ! = ( char ) NULL ) ) {
if ( strcmp ( name , gr ) = = 0 ) {
grouplst [ i ] = g - > gr_gid ;
i + + ;
gr = ( char * ) NULL ;
break ;
}
gr = g - > gr_mem [ + + j ] ;
}
}
endgrent ( ) ;
ret = setgroups ( i , grouplst ) ;
free ( grouplst ) ;
return ret ;
# endif /* HAVE_SETGROUPS */
}
# endif /* HAVE_INITGROUPS */
# if (defined(SecureWare) && defined(SCO))
/* This is needed due to needing the nap() function but we don't want
to include the Xenix libraries since that will break other things . . .
BTW : system call # 0x0c28 is the same as calling nap ( ) */
long nap ( long milliseconds ) {
return syscall ( 0x0c28 , milliseconds ) ;
}
# endif
# ifndef HAVE_MEMMOVE
/*******************************************************************
safely copies memory , ensuring no overlap problems .
2007-11-26 15:28:13 +01:00
this is only used if the machine does not have its own memmove ( ) .
2006-09-18 22:49:20 +00:00
this is not the fastest algorithm in town , but it will do for our
needs .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void * rep_memmove ( void * dest , const void * src , int size )
{
unsigned long d , s ;
int i ;
if ( dest = = src | | ! size ) return ( dest ) ;
d = ( unsigned long ) dest ;
s = ( unsigned long ) src ;
if ( ( d > = ( s + size ) ) | | ( s > = ( d + size ) ) ) {
/* no overlap */
memcpy ( dest , src , size ) ;
return ( dest ) ;
}
if ( d < s ) {
/* we can forward copy */
if ( s - d > = sizeof ( int ) & &
! ( s % sizeof ( int ) ) & &
! ( d % sizeof ( int ) ) & &
! ( size % sizeof ( int ) ) ) {
/* do it all as words */
int * idest = ( int * ) dest ;
int * isrc = ( int * ) src ;
size / = sizeof ( int ) ;
for ( i = 0 ; i < size ; i + + ) idest [ i ] = isrc [ i ] ;
} else {
/* simplest */
char * cdest = ( char * ) dest ;
char * csrc = ( char * ) src ;
for ( i = 0 ; i < size ; i + + ) cdest [ i ] = csrc [ i ] ;
}
} else {
/* must backward copy */
if ( d - s > = sizeof ( int ) & &
! ( s % sizeof ( int ) ) & &
! ( d % sizeof ( int ) ) & &
! ( size % sizeof ( int ) ) ) {
/* do it all as words */
int * idest = ( int * ) dest ;
int * isrc = ( int * ) src ;
size / = sizeof ( int ) ;
for ( i = size - 1 ; i > = 0 ; i - - ) idest [ i ] = isrc [ i ] ;
} else {
/* simplest */
char * cdest = ( char * ) dest ;
char * csrc = ( char * ) src ;
for ( i = size - 1 ; i > = 0 ; i - - ) cdest [ i ] = csrc [ i ] ;
}
}
return ( dest ) ;
}
# endif /* HAVE_MEMMOVE */
# ifndef HAVE_STRDUP
/****************************************************************************
duplicate a string
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
char * rep_strdup ( const char * s )
{
size_t len ;
char * ret ;
if ( ! s ) return ( NULL ) ;
len = strlen ( s ) + 1 ;
ret = ( char * ) malloc ( len ) ;
if ( ! ret ) return ( NULL ) ;
memcpy ( ret , s , len ) ;
return ( ret ) ;
}
# endif /* HAVE_STRDUP */
# ifndef HAVE_SETLINEBUF
void rep_setlinebuf ( FILE * stream )
{
setvbuf ( stream , ( char * ) NULL , _IOLBF , 0 ) ;
}
# endif /* HAVE_SETLINEBUF */
# ifndef HAVE_VSYSLOG
# ifdef HAVE_SYSLOG
2006-09-29 12:30:14 +00:00
void rep_vsyslog ( int facility_priority , const char * format , va_list arglist )
2006-09-18 22:49:20 +00:00
{
char * msg = NULL ;
vasprintf ( & msg , format , arglist ) ;
if ( ! msg )
return ;
syslog ( facility_priority , " %s " , msg ) ;
free ( msg ) ;
}
# endif /* HAVE_SYSLOG */
# endif /* HAVE_VSYSLOG */
# ifndef HAVE_STRNLEN
/**
Some platforms don ' t have strnlen
* */
size_t rep_strnlen ( const char * s , size_t max )
{
size_t len ;
for ( len = 0 ; len < max ; len + + ) {
if ( s [ len ] = = ' \0 ' ) {
break ;
}
}
return len ;
}
# endif
# ifndef HAVE_STRNDUP
/**
Some platforms don ' t have strndup .
* */
char * rep_strndup ( const char * s , size_t n )
{
char * ret ;
n = strnlen ( s , n ) ;
ret = malloc ( n + 1 ) ;
if ( ! ret )
return NULL ;
memcpy ( ret , s , n ) ;
ret [ n ] = 0 ;
return ret ;
}
# endif
# ifndef HAVE_WAITPID
int rep_waitpid ( pid_t pid , int * status , int options )
{
return wait4 ( pid , status , options , NULL ) ;
}
# endif
# ifndef HAVE_SETEUID
int rep_seteuid ( uid_t euid )
{
# ifdef HAVE_SETRESUID
return setresuid ( - 1 , euid , - 1 ) ;
# else
# error "You need a seteuid function"
# endif
}
# endif
# ifndef HAVE_SETEGID
int rep_setegid ( gid_t egid )
{
# ifdef HAVE_SETRESGID
return setresgid ( - 1 , egid , - 1 ) ;
# else
# error "You need a setegid function"
# endif
}
# endif
/*******************************************************************
os / 2 also doesn ' t have chroot
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifndef HAVE_CHROOT
int rep_chroot ( const char * dname )
{
errno = ENOSYS ;
return - 1 ;
}
# endif
/*****************************************************************
Possibly replace mkstemp if it is broken .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# ifndef HAVE_SECURE_MKSTEMP
int rep_mkstemp ( char * template )
{
/* have a reasonable go at emulating it. Hope that
the system mktemp ( ) isn ' t completly hopeless */
char * p = mktemp ( template ) ;
if ( ! p )
return - 1 ;
return open ( p , O_CREAT | O_EXCL | O_RDWR , 0600 ) ;
}
# endif
# ifndef HAVE_MKDTEMP
char * rep_mkdtemp ( char * template )
{
char * dname ;
if ( ( dname = mktemp ( template ) ) ) {
if ( mkdir ( dname , 0700 ) > = 0 ) {
return dname ;
}
}
return NULL ;
}
# endif
2007-06-06 09:27:43 +00:00
/*****************************************************************
Watch out : this is not thread safe .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-09-18 22:49:20 +00:00
# ifndef HAVE_PREAD
ssize_t rep_pread ( int __fd , void * __buf , size_t __nbytes , off_t __offset )
{
if ( lseek ( __fd , __offset , SEEK_SET ) ! = __offset ) {
return - 1 ;
}
return read ( __fd , __buf , __nbytes ) ;
}
# endif
2007-06-06 09:27:43 +00:00
/*****************************************************************
Watch out : this is not thread safe .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2006-09-18 22:49:20 +00:00
# ifndef HAVE_PWRITE
ssize_t rep_pwrite ( int __fd , const void * __buf , size_t __nbytes , off_t __offset )
{
if ( lseek ( __fd , __offset , SEEK_SET ) ! = __offset ) {
return - 1 ;
}
return write ( __fd , __buf , __nbytes ) ;
}
# endif
# ifndef HAVE_STRCASESTR
char * rep_strcasestr ( const char * haystack , const char * needle )
{
const char * s ;
size_t nlen = strlen ( needle ) ;
for ( s = haystack ; * s ; s + + ) {
if ( toupper ( * needle ) = = toupper ( * s ) & &
strncasecmp ( s , needle , nlen ) = = 0 ) {
2008-04-18 00:30:50 -07:00
return ( char * ) ( ( uintptr_t ) s ) ;
2006-09-18 22:49:20 +00:00
}
}
return NULL ;
}
# endif
# ifndef HAVE_STRTOK_R
/* based on GLIBC version, copyright Free Software Foundation */
char * rep_strtok_r ( char * s , const char * delim , char * * save_ptr )
{
char * token ;
if ( s = = NULL ) s = * save_ptr ;
s + = strspn ( s , delim ) ;
if ( * s = = ' \0 ' ) {
* save_ptr = s ;
return NULL ;
}
token = s ;
s = strpbrk ( token , delim ) ;
if ( s = = NULL ) {
* save_ptr = token + strlen ( token ) ;
} else {
* s = ' \0 ' ;
* save_ptr = s + 1 ;
}
return token ;
}
# endif
# ifndef HAVE_STRTOLL
long long int rep_strtoll ( const char * str , char * * endptr , int base )
{
# ifdef HAVE_STRTOQ
return strtoq ( str , endptr , base ) ;
# elif defined(HAVE___STRTOLL)
return __strtoll ( str , endptr , base ) ;
# elif SIZEOF_LONG == SIZEOF_LONG_LONG
return ( long long int ) strtol ( str , endptr , base ) ;
# else
# error "You need a strtoll function"
# endif
}
# endif
# ifndef HAVE_STRTOULL
unsigned long long int rep_strtoull ( const char * str , char * * endptr , int base )
{
# ifdef HAVE_STRTOUQ
return strtouq ( str , endptr , base ) ;
# elif defined(HAVE___STRTOULL)
return __strtoull ( str , endptr , base ) ;
# elif SIZEOF_LONG == SIZEOF_LONG_LONG
return ( unsigned long long int ) strtoul ( str , endptr , base ) ;
# else
# error "You need a strtoull function"
# endif
}
# endif
# ifndef HAVE_SETENV
int rep_setenv ( const char * name , const char * value , int overwrite )
{
char * p ;
size_t l1 , l2 ;
int ret ;
if ( ! overwrite & & getenv ( name ) ) {
return 0 ;
}
l1 = strlen ( name ) ;
l2 = strlen ( value ) ;
p = malloc ( l1 + l2 + 2 ) ;
if ( p = = NULL ) {
return - 1 ;
}
memcpy ( p , name , l1 ) ;
p [ l1 ] = ' = ' ;
memcpy ( p + l1 + 1 , value , l2 ) ;
p [ l1 + l2 + 1 ] = 0 ;
ret = putenv ( p ) ;
if ( ret ! = 0 ) {
free ( p ) ;
}
return ret ;
}
# endif
2007-04-15 20:12:09 +00:00
# ifndef HAVE_UNSETENV
int rep_unsetenv ( const char * name )
{
extern char * * environ ;
size_t len = strlen ( name ) ;
2007-06-02 09:10:08 +00:00
size_t i , count ;
2007-04-15 20:12:09 +00:00
2007-06-02 09:10:08 +00:00
if ( environ = = NULL | | getenv ( name ) = = NULL ) {
return 0 ;
}
2007-04-15 20:12:09 +00:00
2007-06-02 09:10:08 +00:00
for ( i = 0 ; environ [ i ] ; i + + ) /* noop */ ;
count = i ;
for ( i = 0 ; i < count ; ) {
2007-04-15 20:12:09 +00:00
if ( strncmp ( environ [ i ] , name , len ) = = 0 & & environ [ i ] [ len ] = = ' = ' ) {
2007-06-02 09:10:08 +00:00
/* note: we do _not_ free the old variable here. It is unsafe to
do so , as the pointer may not have come from malloc */
memmove ( & environ [ i ] , & environ [ i + 1 ] , ( count - i ) * sizeof ( char * ) ) ;
count - - ;
} else {
i + + ;
2007-04-15 20:12:09 +00:00
}
}
return 0 ;
}
# endif
2008-05-07 13:10:31 +02:00
# ifndef HAVE_UTIME
int rep_utime ( const char * filename , const struct utimbuf * buf )
{
errno = ENOSYS ;
return - 1 ;
}
# endif
# ifndef HAVE_UTIMES
int rep_utimes ( const char * filename , const struct timeval tv [ 2 ] )
{
struct utimbuf u ;
u . actime = tv [ 0 ] . tv_sec ;
if ( tv [ 0 ] . tv_usec > 500000 ) {
u . actime + = 1 ;
}
u . modtime = tv [ 1 ] . tv_sec ;
if ( tv [ 1 ] . tv_usec > 500000 ) {
u . modtime + = 1 ;
}
return utime ( filename , & u ) ;
}
# endif
2008-11-01 03:58:14 +01:00
# ifndef HAVE_DUP2
int rep_dup2 ( int oldfd , int newfd )
{
errno = ENOSYS ;
return - 1 ;
}
# endif
2008-11-01 03:27:45 +01:00
# ifndef HAVE_CHOWN
/**
chown isn ' t used much but OS / 2 doesn ' t have it
* */
int rep_chown ( const char * fname , uid_t uid , gid_t gid )
{
errno = ENOSYS ;
return - 1 ;
}
# endif
2008-11-01 03:30:47 +01:00
# ifndef HAVE_LINK
int rep_link ( const char * oldpath , const char * newpath )
{
errno = ENOSYS ;
return - 1 ;
}
# endif
2008-11-01 03:33:39 +01:00
# ifndef HAVE_READLINK
int rep_readlink ( const char * path , char * buf , size_t bufsiz )
{
errno = ENOSYS ;
return - 1 ;
}
# endif
2008-11-01 03:35:58 +01:00
# ifndef HAVE_SYMLINK
int rep_symlink ( const char * oldpath , const char * newpath )
{
errno = ENOSYS ;
return - 1 ;
}
# endif
2008-11-01 03:39:20 +01:00
# ifndef HAVE_LCHOWN
int rep_lchown ( const char * fname , uid_t uid , gid_t gid )
{
errno = ENOSYS ;
return - 1 ;
}
# endif
2008-11-01 03:42:27 +01:00
# ifndef HAVE_REALPATH
char * rep_realpath ( const char * path , char * resolved_path )
{
/* As realpath is not a system call we can't return ENOSYS. */
errno = EINVAL ;
return NULL ;
}
# endif