2003-08-13 05:53:07 +04:00
/*
* Unix SMB / CIFS implementation .
* SMB parameters and setup
* Copyright ( C ) Andrew Tridgell 1992 - 1998 Modified by Jeremy Allison 1995.
2005-09-29 01:54:29 +04:00
*
* Added afdgets ( ) Jelmer Vernooij 2005
2014-12-07 16:13:51 +03:00
*
2003-08-13 05:53:07 +04: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 the Free
2007-07-10 07:04:16 +04:00
* Software Foundation ; either version 3 of the License , or ( at your option )
2003-08-13 05:53:07 +04:00
* any later version .
2014-12-07 16:13:51 +03:00
*
2003-08-13 05:53:07 +04:00
* 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 .
2014-12-07 16:13:51 +03:00
*
2003-08-13 05:53:07 +04:00
* You should have received a copy of the GNU General Public License along with
2007-07-10 09:23:25 +04:00
* this program ; if not , see < http : //www.gnu.org/licenses/>.
2003-08-13 05:53:07 +04:00
*/
2011-10-21 15:42:34 +04:00
# include "replace.h"
2004-11-02 03:24:21 +03:00
# include "system/shmem.h"
2005-02-10 08:09:35 +03:00
# include "system/filesys.h"
2011-10-21 15:42:34 +04:00
# include <talloc.h>
# include "lib/util/samba_util.h"
2018-12-27 12:25:47 +03:00
# include "lib/util/sys_popen.h"
# include "lib/util/sys_rw.h"
2011-10-21 15:42:34 +04:00
# include "lib/util/debug.h"
2003-08-13 05:53:07 +04:00
2006-02-28 16:12:39 +03:00
/**
2014-12-07 16:13:51 +03:00
* Read one line ( data until next newline or eof ) and allocate it
2006-02-28 16:12:39 +03:00
*/
2006-03-05 20:15:19 +03:00
_PUBLIC_ char * afdgets ( int fd , TALLOC_CTX * mem_ctx , size_t hint )
2005-09-29 01:54:29 +04:00
{
char * data = NULL ;
ssize_t alloc_size = 0 , offset = 0 , ret ;
int p ;
if ( hint < = 0 ) hint = 0x100 ;
do {
alloc_size + = hint ;
data = talloc_realloc ( mem_ctx , data , char , alloc_size ) ;
if ( ! data )
return NULL ;
ret = read ( fd , data + offset , hint ) ;
2006-08-21 01:57:08 +04:00
if ( ret = = 0 ) {
return NULL ;
}
2005-09-29 01:54:29 +04:00
if ( ret = = - 1 ) {
talloc_free ( data ) ;
return NULL ;
}
/* Find newline */
for ( p = 0 ; p < ret ; p + + ) {
if ( data [ offset + p ] = = ' \n ' )
break ;
}
if ( p < ret ) {
data [ offset + p ] = ' \0 ' ;
/* Go back to position of newline */
lseek ( fd , p - ret + 1 , SEEK_CUR ) ;
return data ;
}
offset + = ret ;
2019-06-21 08:11:49 +03:00
} while ( ( size_t ) ret = = hint ) ;
2005-09-29 01:54:29 +04:00
data [ offset ] = ' \0 ' ;
return data ;
}
2003-08-13 05:53:07 +04:00
2018-03-21 14:49:38 +03:00
char * fgets_slash ( TALLOC_CTX * mem_ctx , char * s2 , size_t maxlen , FILE * f )
2016-11-21 21:20:10 +03:00
{
char * s = s2 ;
2018-03-21 14:49:38 +03:00
size_t len = 0 ;
2016-11-21 21:20:10 +03:00
int c ;
bool start_of_line = true ;
if ( feof ( f ) ) {
return NULL ;
}
if ( maxlen < 2 ) {
return NULL ;
}
if ( s2 = = NULL ) {
maxlen = MIN ( maxlen , 8 ) ;
s = talloc_array ( mem_ctx , char , maxlen ) ;
}
if ( s = = NULL ) {
return NULL ;
}
* s = 0 ;
while ( len < maxlen - 1 ) {
c = getc ( f ) ;
switch ( c )
{
case ' \r ' :
break ;
case ' \n ' :
while ( len > 0 & & s [ len - 1 ] = = ' ' ) {
s [ - - len ] = 0 ;
}
if ( len > 0 & & s [ len - 1 ] = = ' \\ ' ) {
s [ - - len ] = 0 ;
start_of_line = true ;
break ;
}
return s ;
case EOF :
if ( len < = 0 & & ( s2 = = NULL ) ) {
TALLOC_FREE ( s ) ;
}
return ( len > 0 ) ? s : NULL ;
case ' ' :
if ( start_of_line ) {
break ;
}
2017-07-26 19:41:25 +03:00
FALL_THROUGH ;
2016-11-21 21:20:10 +03:00
default :
start_of_line = false ;
s [ len + + ] = c ;
s [ len ] = 0 ;
}
if ( ( s2 = = NULL ) & & ( len > maxlen - 3 ) ) {
2019-06-21 08:10:19 +03:00
size_t m ;
2016-11-21 21:20:10 +03:00
char * t ;
m = maxlen * 2 ;
if ( m < maxlen ) {
2023-07-31 07:14:00 +03:00
DBG_ERR ( " length overflow \n " ) ;
2016-11-21 21:20:10 +03:00
TALLOC_FREE ( s ) ;
return NULL ;
}
maxlen = m ;
t = talloc_realloc ( mem_ctx , s , char , maxlen ) ;
if ( t = = NULL ) {
DBG_ERR ( " failed to expand buffer! \n " ) ;
TALLOC_FREE ( s ) ;
return NULL ;
}
s = t ;
}
}
return s ;
}
2003-08-13 05:53:07 +04:00
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
load a file into memory from a fd .
2006-02-28 16:12:39 +03:00
* */
2008-10-12 19:34:43 +04:00
_PUBLIC_ char * fd_load ( int fd , size_t * psize , size_t maxsize , TALLOC_CTX * mem_ctx )
2003-08-13 05:53:07 +04:00
{
2019-02-21 20:37:08 +03:00
FILE * file ;
char * p = NULL ;
size_t size = 0 ;
size_t chunk = 1024 ;
int err ;
2023-02-10 06:01:47 +03:00
int fd_dup ;
2019-02-21 20:37:08 +03:00
if ( maxsize = = 0 ) {
maxsize = SIZE_MAX ;
}
2003-08-13 05:53:07 +04:00
2023-02-10 06:01:47 +03:00
fd_dup = dup ( fd ) ;
if ( fd_dup = = - 1 ) {
return NULL ;
}
file = fdopen ( fd_dup , " r " ) ;
2019-02-21 20:37:08 +03:00
if ( file = = NULL ) {
2023-02-10 06:01:47 +03:00
close ( fd_dup ) ;
2019-02-21 20:37:08 +03:00
return NULL ;
}
2003-08-13 05:53:07 +04:00
2019-02-21 20:37:08 +03:00
while ( size < maxsize ) {
size_t newbufsize ;
size_t nread ;
2008-10-12 19:34:43 +04:00
2019-02-21 20:37:08 +03:00
chunk = MIN ( chunk , ( maxsize - size ) ) ;
2008-10-12 19:34:43 +04:00
2019-02-21 20:37:08 +03:00
newbufsize = size + ( chunk + 1 ) ; /* chunk+1 can't overflow */
if ( newbufsize < size ) {
goto fail ; /* overflow */
}
2003-08-13 05:53:07 +04:00
2019-02-21 20:37:08 +03:00
p = talloc_realloc ( mem_ctx , p , char , newbufsize ) ;
if ( p = = NULL ) {
goto fail ;
}
nread = fread ( p + size , 1 , chunk , file ) ;
size + = nread ;
if ( nread ! = chunk ) {
break ;
}
2003-08-13 05:53:07 +04:00
}
2019-02-21 20:37:08 +03:00
err = ferror ( file ) ;
if ( err ! = 0 ) {
goto fail ;
}
2003-08-13 05:53:07 +04:00
2019-02-21 20:37:08 +03:00
p [ size ] = ' \0 ' ;
if ( psize ! = NULL ) {
* psize = size ;
}
fclose ( file ) ;
2003-08-13 05:53:07 +04:00
return p ;
2019-02-21 20:37:08 +03:00
fail :
TALLOC_FREE ( p ) ;
fclose ( file ) ;
return NULL ;
2003-08-13 05:53:07 +04:00
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
load a file into memory
2006-02-28 16:12:39 +03:00
* */
2008-10-12 19:34:43 +04:00
_PUBLIC_ char * file_load ( const char * fname , size_t * size , size_t maxsize , TALLOC_CTX * mem_ctx )
2003-08-13 05:53:07 +04:00
{
int fd ;
char * p ;
if ( ! fname | | ! * fname ) return NULL ;
2014-12-07 16:13:51 +03:00
2003-08-13 05:53:07 +04:00
fd = open ( fname , O_RDONLY ) ;
if ( fd = = - 1 ) return NULL ;
2008-10-12 19:34:43 +04:00
p = fd_load ( fd , size , maxsize , mem_ctx ) ;
2003-08-13 05:53:07 +04:00
close ( fd ) ;
return p ;
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
parse a buffer into lines
2006-10-28 10:06:15 +04:00
' p ' will be freed on error , and otherwise will be made a child of the returned array
2006-02-28 16:12:39 +03:00
* */
2020-11-11 00:43:24 +03:00
static char * * file_lines_parse_internal ( char * p , size_t size , int * numlines , TALLOC_CTX * mem_ctx )
2003-08-13 05:53:07 +04:00
{
2018-12-14 06:43:57 +03:00
unsigned int i ;
2003-08-13 05:53:07 +04:00
char * s , * * ret ;
if ( ! p ) return NULL ;
for ( s = p , i = 0 ; s < p + size ; s + + ) {
if ( s [ 0 ] = = ' \n ' ) i + + ;
}
2014-12-26 22:41:23 +03:00
ret = talloc_zero_array ( mem_ctx , char * , i + 2 ) ;
2003-08-13 05:53:07 +04:00
if ( ! ret ) {
2005-08-30 21:21:41 +04:00
talloc_free ( p ) ;
2003-08-13 05:53:07 +04:00
return NULL ;
2014-12-07 16:13:51 +03:00
}
2006-10-28 10:06:15 +04:00
talloc_steal ( ret , p ) ;
2014-12-07 16:13:51 +03:00
2003-08-13 05:53:07 +04:00
ret [ 0 ] = p ;
2018-12-14 06:43:57 +03:00
for ( s = p , i = 1 ; s < p + size ; s + + ) {
2003-08-13 05:53:07 +04:00
if ( s [ 0 ] = = ' \n ' ) {
s [ 0 ] = 0 ;
ret [ i ] = s + 1 ;
2018-12-14 06:43:57 +03:00
i + + ;
2003-08-13 05:53:07 +04:00
}
if ( s [ 0 ] = = ' \r ' ) s [ 0 ] = 0 ;
}
2006-12-09 06:12:33 +03:00
/* remove any blank lines at the end */
while ( i > 0 & & ret [ i - 1 ] [ 0 ] = = 0 ) {
i - - ;
}
if ( numlines ) * numlines = i ;
2003-08-13 05:53:07 +04:00
return ret ;
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
load a file into memory and return an array of pointers to lines in the file
2014-12-07 16:13:51 +03:00
must be freed with talloc_free ( ) .
2006-02-28 16:12:39 +03:00
* */
2008-10-12 19:34:43 +04:00
_PUBLIC_ char * * file_lines_load ( const char * fname , int * numlines , size_t maxsize , TALLOC_CTX * mem_ctx )
2003-08-13 05:53:07 +04:00
{
char * p ;
size_t size ;
2008-10-12 19:34:43 +04:00
p = file_load ( fname , & size , maxsize , mem_ctx ) ;
2003-08-13 05:53:07 +04:00
if ( ! p ) return NULL ;
2020-11-11 00:43:24 +03:00
return file_lines_parse_internal ( p , size , numlines , mem_ctx ) ;
2003-08-13 05:53:07 +04:00
}
2006-02-28 16:12:39 +03:00
/**
2003-08-13 05:53:07 +04:00
load a fd into memory and return an array of pointers to lines in the file
2005-08-30 21:21:41 +04:00
must be freed with talloc_free ( ) . If convert is true calls unix_to_dos on
2003-08-13 05:53:07 +04:00
the list .
2006-02-28 16:12:39 +03:00
* */
2008-10-12 19:34:43 +04:00
_PUBLIC_ char * * fd_lines_load ( int fd , int * numlines , size_t maxsize , TALLOC_CTX * mem_ctx )
2003-08-13 05:53:07 +04:00
{
char * p ;
size_t size ;
2008-10-12 19:34:43 +04:00
p = fd_load ( fd , & size , maxsize , mem_ctx ) ;
2003-08-13 05:53:07 +04:00
if ( ! p ) return NULL ;
2020-11-11 00:43:24 +03:00
return file_lines_parse_internal ( p , size , numlines , mem_ctx ) ;
}
2020-11-11 00:52:01 +03:00
_PUBLIC_ char * * file_lines_parse ( const char * p_in ,
2020-11-11 00:43:24 +03:00
size_t size ,
int * numlines ,
TALLOC_CTX * mem_ctx )
{
2020-11-11 00:52:01 +03:00
/*
* Copy the incoming string so it can end up
* being owned by the returned pointer and
* freed when that is .
*/
char * p = talloc_strdup ( mem_ctx , p_in ) ;
if ( p = = NULL ) {
return NULL ;
}
2020-11-11 00:43:24 +03:00
return file_lines_parse_internal ( p , size , numlines , mem_ctx ) ;
2003-08-13 05:53:07 +04:00
}
2013-10-29 20:48:11 +04:00
_PUBLIC_ bool file_save_mode ( const char * fname , const void * packet ,
size_t length , mode_t mode )
2003-08-13 05:53:07 +04:00
{
2019-06-21 08:11:49 +03:00
ssize_t num_written ;
2003-08-13 05:53:07 +04:00
int fd ;
2019-11-11 03:52:22 +03:00
fd = open ( fname , O_WRONLY | O_CREAT | O_EXCL , mode ) ;
2003-08-13 05:53:07 +04:00
if ( fd = = - 1 ) {
2007-08-27 21:21:16 +04:00
return false ;
2003-08-13 05:53:07 +04:00
}
2019-06-21 08:11:49 +03:00
num_written = write ( fd , packet , length ) ;
if ( num_written = = - 1 | | ( size_t ) num_written ! = length ) {
2009-07-18 13:28:53 +04:00
close ( fd ) ;
2007-08-27 21:21:16 +04:00
return false ;
2003-08-13 05:53:07 +04:00
}
close ( fd ) ;
2007-08-27 21:21:16 +04:00
return true ;
2003-08-13 05:53:07 +04:00
}
2005-04-14 12:24:36 +04:00
2013-10-29 20:48:11 +04:00
/**
save a lump of data into a file . Mostly used for debugging
*/
_PUBLIC_ bool file_save ( const char * fname , const void * packet , size_t length )
{
return file_save_mode ( fname , packet , length , 0644 ) ;
}
2008-04-02 06:53:27 +04:00
_PUBLIC_ int vfdprintf ( int fd , const char * format , va_list ap )
2005-09-15 23:52:13 +04:00
{
char * p ;
int len , ret ;
va_list ap2 ;
2006-04-08 20:05:21 +04:00
va_copy ( ap2 , ap ) ;
2005-09-15 23:52:13 +04:00
len = vasprintf ( & p , format , ap2 ) ;
2007-02-06 08:26:25 +03:00
va_end ( ap2 ) ;
2005-09-15 23:52:13 +04:00
if ( len < = 0 ) return len ;
ret = write ( fd , p , len ) ;
SAFE_FREE ( p ) ;
return ret ;
}
2008-04-02 06:53:27 +04:00
_PUBLIC_ int fdprintf ( int fd , const char * format , . . . )
2005-09-15 23:52:13 +04:00
{
va_list ap ;
int ret ;
va_start ( ap , format ) ;
ret = vfdprintf ( fd , format , ap ) ;
va_end ( ap ) ;
return ret ;
}
2006-10-28 10:06:15 +04:00
2010-02-11 12:19:40 +03:00
/*
compare two files , return true if the two files have the same content
*/
bool file_compare ( const char * path1 , const char * path2 )
{
2019-05-01 16:34:22 +03:00
FILE * f1 = NULL , * f2 = NULL ;
uint8_t buf1 [ 1024 ] , buf2 [ 1024 ] ;
bool ret = false ;
f1 = fopen ( path1 , " r " ) ;
if ( f1 = = NULL ) {
goto done ;
2010-02-11 12:19:40 +03:00
}
2019-05-01 16:34:22 +03:00
f2 = fopen ( path2 , " r " ) ;
if ( f2 = = NULL ) {
goto done ;
2010-02-11 12:19:40 +03:00
}
2019-05-01 16:34:22 +03:00
while ( ! feof ( f1 ) ) {
size_t n1 = fread ( buf1 , 1 , sizeof ( buf1 ) , f1 ) ;
size_t n2 = fread ( buf2 , 1 , sizeof ( buf2 ) , f2 ) ;
if ( n1 ! = n2 ) {
goto done ;
}
if ( n1 = = 0 ) {
ret = ( feof ( f1 ) & & feof ( f2 ) ) ;
goto done ;
}
if ( memcmp ( buf1 , buf2 , n1 ) ! = 0 ) {
goto done ;
}
if ( n1 < sizeof ( buf1 ) ) {
bool has_error = ( ferror ( f1 ) | | ferror ( f2 ) ) ;
if ( has_error ) {
goto done ;
}
}
}
ret = true ;
done :
if ( f2 ! = NULL ) {
fclose ( f2 ) ;
}
if ( f1 ! = NULL ) {
fclose ( f1 ) ;
}
return ret ;
2010-02-11 12:19:40 +03:00
}
2018-12-27 12:25:47 +03:00
2019-05-17 07:56:13 +03:00
/**
Load from a pipe into memory .
* */
char * file_ploadv ( char * const argl [ ] , size_t * size )
{
int fd , n ;
char * p = NULL ;
char buf [ 1024 ] ;
size_t total ;
fd = sys_popenv ( argl ) ;
if ( fd = = - 1 ) {
return NULL ;
}
total = 0 ;
while ( ( n = sys_read ( fd , buf , sizeof ( buf ) ) ) > 0 ) {
p = talloc_realloc ( NULL , p , char , total + n + 1 ) ;
if ( p = = NULL ) {
DBG_ERR ( " failed to expand buffer! \n " ) ;
close ( fd ) ;
return NULL ;
}
memcpy ( p + total , buf , n ) ;
total + = n ;
}
if ( p ! = NULL ) {
p [ total ] = 0 ;
}
/*
* FIXME : Perhaps ought to check that the command completed
* successfully ( returned 0 ) ; if not the data may be
* truncated .
*/
sys_pclose ( fd ) ;
if ( size ) {
* size = total ;
}
return p ;
}