wmi-1.3.16 from opsview.com
This commit is contained in:
@@ -0,0 +1,24 @@
|
||||
PROJECT_NAME = SAMBA_UTIL
|
||||
OUTPUT_DIRECTORY = apidocs
|
||||
BRIEF_MEMBER_DESC = YES
|
||||
REPEAT_BRIEF = YES
|
||||
OPTIMIZE_OUTPUT_FOR_C = YES
|
||||
SORT_MEMBER_DOCS = YES
|
||||
SORT_BRIEF_DOCS = NO
|
||||
GENERATE_TODOLIST = YES
|
||||
GENERATE_BUGLIST = YES
|
||||
GENERATE_DEPRECATEDLIST= YES
|
||||
SHOW_USED_FILES = NO
|
||||
SHOW_DIRECTORIES = NO
|
||||
WARNINGS = YES
|
||||
WARN_IF_UNDOCUMENTED = YES
|
||||
WARN_IF_DOC_ERROR = YES
|
||||
WARN_NO_PARAMDOC = NO
|
||||
WARN_FORMAT = "$file:$line: $text"
|
||||
INPUT = .
|
||||
FILE_PATTERNS = *.c *.h *.dox
|
||||
GENERATE_HTML = YES
|
||||
HTML_OUTPUT = html
|
||||
GENERATE_MAN = YES
|
||||
ALWAYS_DETAILED_SEC = YES
|
||||
JAVADOC_AUTOBRIEF = YES
|
||||
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
SMB Byte handling
|
||||
Copyright (C) Andrew Tridgell 1992-1998
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _BYTEORDER_H
|
||||
#define _BYTEORDER_H
|
||||
|
||||
/*
|
||||
This file implements macros for machine independent short and
|
||||
int manipulation
|
||||
|
||||
Here is a description of this file that I emailed to the samba list once:
|
||||
|
||||
> I am confused about the way that byteorder.h works in Samba. I have
|
||||
> looked at it, and I would have thought that you might make a distinction
|
||||
> between LE and BE machines, but you only seem to distinguish between 386
|
||||
> and all other architectures.
|
||||
>
|
||||
> Can you give me a clue?
|
||||
|
||||
sure.
|
||||
|
||||
The distinction between 386 and other architectures is only there as
|
||||
an optimisation. You can take it out completely and it will make no
|
||||
difference. The routines (macros) in byteorder.h are totally byteorder
|
||||
independent. The 386 optimsation just takes advantage of the fact that
|
||||
the x86 processors don't care about alignment, so we don't have to
|
||||
align ints on int boundaries etc. If there are other processors out
|
||||
there that aren't alignment sensitive then you could also define
|
||||
CAREFUL_ALIGNMENT=0 on those processors as well.
|
||||
|
||||
Ok, now to the macros themselves. I'll take a simple example, say we
|
||||
want to extract a 2 byte integer from a SMB packet and put it into a
|
||||
type called uint16_t that is in the local machines byte order, and you
|
||||
want to do it with only the assumption that uint16_t is _at_least_ 16
|
||||
bits long (this last condition is very important for architectures
|
||||
that don't have any int types that are 2 bytes long)
|
||||
|
||||
You do this:
|
||||
|
||||
#define CVAL(buf,pos) (((uint8_t *)(buf))[pos])
|
||||
#define PVAL(buf,pos) ((uint_t)CVAL(buf,pos))
|
||||
#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
|
||||
|
||||
then to extract a uint16_t value at offset 25 in a buffer you do this:
|
||||
|
||||
char *buffer = foo_bar();
|
||||
uint16_t xx = SVAL(buffer,25);
|
||||
|
||||
We are using the byteoder independence of the ANSI C bitshifts to do
|
||||
the work. A good optimising compiler should turn this into efficient
|
||||
code, especially if it happens to have the right byteorder :-)
|
||||
|
||||
I know these macros can be made a bit tidier by removing some of the
|
||||
casts, but you need to look at byteorder.h as a whole to see the
|
||||
reasoning behind them. byteorder.h defines the following macros:
|
||||
|
||||
SVAL(buf,pos) - extract a 2 byte SMB value
|
||||
IVAL(buf,pos) - extract a 4 byte SMB value
|
||||
SVALS(buf,pos) signed version of SVAL()
|
||||
IVALS(buf,pos) signed version of IVAL()
|
||||
|
||||
SSVAL(buf,pos,val) - put a 2 byte SMB value into a buffer
|
||||
SIVAL(buf,pos,val) - put a 4 byte SMB value into a buffer
|
||||
SSVALS(buf,pos,val) - signed version of SSVAL()
|
||||
SIVALS(buf,pos,val) - signed version of SIVAL()
|
||||
|
||||
RSVAL(buf,pos) - like SVAL() but for NMB byte ordering
|
||||
RSVALS(buf,pos) - like SVALS() but for NMB byte ordering
|
||||
RIVAL(buf,pos) - like IVAL() but for NMB byte ordering
|
||||
RIVALS(buf,pos) - like IVALS() but for NMB byte ordering
|
||||
RSSVAL(buf,pos,val) - like SSVAL() but for NMB ordering
|
||||
RSIVAL(buf,pos,val) - like SIVAL() but for NMB ordering
|
||||
RSIVALS(buf,pos,val) - like SIVALS() but for NMB ordering
|
||||
|
||||
it also defines lots of intermediate macros, just ignore those :-)
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
on powerpc we can use the magic instructions to load/store
|
||||
in little endian
|
||||
*/
|
||||
#if (defined(__powerpc__) && defined(__GNUC__))
|
||||
static __inline__ uint16_t ld_le16(const uint16_t *addr)
|
||||
{
|
||||
uint16_t val;
|
||||
__asm__ ("lhbrx %0,0,%1" : "=r" (val) : "r" (addr), "m" (*addr));
|
||||
return val;
|
||||
}
|
||||
|
||||
static __inline__ void st_le16(uint16_t *addr, const uint16_t val)
|
||||
{
|
||||
__asm__ ("sthbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr));
|
||||
}
|
||||
|
||||
static __inline__ uint32_t ld_le32(const uint32_t *addr)
|
||||
{
|
||||
uint32_t val;
|
||||
__asm__ ("lwbrx %0,0,%1" : "=r" (val) : "r" (addr), "m" (*addr));
|
||||
return val;
|
||||
}
|
||||
|
||||
static __inline__ void st_le32(uint32_t *addr, const uint32_t val)
|
||||
{
|
||||
__asm__ ("stwbrx %1,0,%2" : "=m" (*addr) : "r" (val), "r" (addr));
|
||||
}
|
||||
#define HAVE_ASM_BYTEORDER 1
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#undef CAREFUL_ALIGNMENT
|
||||
|
||||
/* we know that the 386 can handle misalignment and has the "right"
|
||||
byteorder */
|
||||
#if defined(__i386__)
|
||||
#define CAREFUL_ALIGNMENT 0
|
||||
#endif
|
||||
|
||||
#ifndef CAREFUL_ALIGNMENT
|
||||
#define CAREFUL_ALIGNMENT 1
|
||||
#endif
|
||||
|
||||
#define CVAL(buf,pos) ((uint_t)(((const uint8_t *)(buf))[pos]))
|
||||
#define CVAL_NC(buf,pos) (((uint8_t *)(buf))[pos]) /* Non-const version of CVAL */
|
||||
#define PVAL(buf,pos) (CVAL(buf,pos))
|
||||
#define SCVAL(buf,pos,val) (CVAL_NC(buf,pos) = (val))
|
||||
|
||||
#if HAVE_ASM_BYTEORDER
|
||||
|
||||
#define _PTRPOS(buf,pos) (((const uint8_t *)buf)+(pos))
|
||||
#define SVAL(buf,pos) ld_le16((const uint16_t *)_PTRPOS(buf,pos))
|
||||
#define IVAL(buf,pos) ld_le32((const uint32_t *)_PTRPOS(buf,pos))
|
||||
#define SSVAL(buf,pos,val) st_le16((uint16_t *)_PTRPOS(buf,pos), val)
|
||||
#define SIVAL(buf,pos,val) st_le32((uint32_t *)_PTRPOS(buf,pos), val)
|
||||
#define SVALS(buf,pos) ((int16_t)SVAL(buf,pos))
|
||||
#define IVALS(buf,pos) ((int32_t)IVAL(buf,pos))
|
||||
#define SSVALS(buf,pos,val) SSVAL((buf),(pos),((int16_t)(val)))
|
||||
#define SIVALS(buf,pos,val) SIVAL((buf),(pos),((int32_t)(val)))
|
||||
|
||||
#elif CAREFUL_ALIGNMENT
|
||||
|
||||
#define SVAL(buf,pos) (PVAL(buf,pos)|PVAL(buf,(pos)+1)<<8)
|
||||
#define IVAL(buf,pos) (SVAL(buf,pos)|SVAL(buf,(pos)+2)<<16)
|
||||
#define SSVALX(buf,pos,val) (CVAL_NC(buf,pos)=(uint8_t)((val)&0xFF),CVAL_NC(buf,pos+1)=(uint8_t)((val)>>8))
|
||||
#define SIVALX(buf,pos,val) (SSVALX(buf,pos,val&0xFFFF),SSVALX(buf,pos+2,val>>16))
|
||||
#define SVALS(buf,pos) ((int16_t)SVAL(buf,pos))
|
||||
#define IVALS(buf,pos) ((int32_t)IVAL(buf,pos))
|
||||
#define SSVAL(buf,pos,val) SSVALX((buf),(pos),((uint16_t)(val)))
|
||||
#define SIVAL(buf,pos,val) SIVALX((buf),(pos),((uint32_t)(val)))
|
||||
#define SSVALS(buf,pos,val) SSVALX((buf),(pos),((int16_t)(val)))
|
||||
#define SIVALS(buf,pos,val) SIVALX((buf),(pos),((int32_t)(val)))
|
||||
|
||||
#else /* CAREFUL_ALIGNMENT */
|
||||
|
||||
/* this handles things for architectures like the 386 that can handle
|
||||
alignment errors */
|
||||
/*
|
||||
WARNING: This section is dependent on the length of int16_t and int32_t
|
||||
being correct
|
||||
*/
|
||||
|
||||
/* get single value from an SMB buffer */
|
||||
#define SVAL(buf,pos) (*(const uint16_t *)((const char *)(buf) + (pos)))
|
||||
#define SVAL_NC(buf,pos) (*(uint16_t *)((char *)(buf) + (pos))) /* Non const version of above. */
|
||||
#define IVAL(buf,pos) (*(const uint32_t *)((const char *)(buf) + (pos)))
|
||||
#define IVAL_NC(buf,pos) (*(uint32_t *)((char *)(buf) + (pos))) /* Non const version of above. */
|
||||
#define SVALS(buf,pos) (*(const int16_t *)((const char *)(buf) + (pos)))
|
||||
#define SVALS_NC(buf,pos) (*(int16_t *)((char *)(buf) + (pos))) /* Non const version of above. */
|
||||
#define IVALS(buf,pos) (*(const int32_t *)((const char *)(buf) + (pos)))
|
||||
#define IVALS_NC(buf,pos) (*(int32_t *)((char *)(buf) + (pos))) /* Non const version of above. */
|
||||
|
||||
/* store single value in an SMB buffer */
|
||||
#define SSVAL(buf,pos,val) SVAL_NC(buf,pos)=((uint16_t)(val))
|
||||
#define SIVAL(buf,pos,val) IVAL_NC(buf,pos)=((uint32_t)(val))
|
||||
#define SSVALS(buf,pos,val) SVALS_NC(buf,pos)=((int16_t)(val))
|
||||
#define SIVALS(buf,pos,val) IVALS_NC(buf,pos)=((int32_t)(val))
|
||||
|
||||
#endif /* CAREFUL_ALIGNMENT */
|
||||
|
||||
/* now the reverse routines - these are used in nmb packets (mostly) */
|
||||
#define SREV(x) ((((x)&0xFF)<<8) | (((x)>>8)&0xFF))
|
||||
#define IREV(x) ((SREV(x)<<16) | (SREV((x)>>16)))
|
||||
|
||||
#define RSVAL(buf,pos) SREV(SVAL(buf,pos))
|
||||
#define RSVALS(buf,pos) SREV(SVALS(buf,pos))
|
||||
#define RIVAL(buf,pos) IREV(IVAL(buf,pos))
|
||||
#define RIVALS(buf,pos) IREV(IVALS(buf,pos))
|
||||
#define RSSVAL(buf,pos,val) SSVAL(buf,pos,SREV(val))
|
||||
#define RSSVALS(buf,pos,val) SSVALS(buf,pos,SREV(val))
|
||||
#define RSIVAL(buf,pos,val) SIVAL(buf,pos,IREV(val))
|
||||
#define RSIVALS(buf,pos,val) SIVALS(buf,pos,IREV(val))
|
||||
|
||||
/* Alignment macros. */
|
||||
#define ALIGN4(p,base) ((p) + ((4 - (PTR_DIFF((p), (base)) & 3)) & 3))
|
||||
#define ALIGN2(p,base) ((p) + ((2 - (PTR_DIFF((p), (base)) & 1)) & 1))
|
||||
|
||||
|
||||
/* macros for accessing SMB protocol elements */
|
||||
#define VWV(vwv) ((vwv)*2)
|
||||
|
||||
/* 64 bit macros */
|
||||
#define SBVAL(p, ofs, v) (SIVAL(p,ofs,(v)&0xFFFFFFFF), SIVAL(p,(ofs)+4,((uint64_t)(v))>>32))
|
||||
#define BVAL(p, ofs) (IVAL(p,ofs) | (((uint64_t)IVAL(p,(ofs)+4)) << 32))
|
||||
|
||||
#endif /* _BYTEORDER_H */
|
||||
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Copyright (C) Andrew Tridgell 1992-1998
|
||||
Copyright (C) Jeremy Allison 1998-2002
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Capabilities functions
|
||||
**/
|
||||
|
||||
/*
|
||||
capabilities fns - will be needed when we enable kernel oplocks
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/network.h"
|
||||
#include "system/wait.h"
|
||||
#include "system/filesys.h"
|
||||
|
||||
|
||||
#if defined(HAVE_IRIX_SPECIFIC_CAPABILITIES)
|
||||
/**************************************************************************
|
||||
Try and abstract process capabilities (for systems that have them).
|
||||
****************************************************************************/
|
||||
static BOOL set_process_capability( uint32_t cap_flag, BOOL enable )
|
||||
{
|
||||
if(cap_flag == KERNEL_OPLOCK_CAPABILITY) {
|
||||
cap_t cap = cap_get_proc();
|
||||
|
||||
if (cap == NULL) {
|
||||
DEBUG(0,("set_process_capability: cap_get_proc failed. Error was %s\n",
|
||||
strerror(errno)));
|
||||
return False;
|
||||
}
|
||||
|
||||
if(enable)
|
||||
cap->cap_effective |= CAP_NETWORK_MGT;
|
||||
else
|
||||
cap->cap_effective &= ~CAP_NETWORK_MGT;
|
||||
|
||||
if (cap_set_proc(cap) == -1) {
|
||||
DEBUG(0,("set_process_capability: cap_set_proc failed. Error was %s\n",
|
||||
strerror(errno)));
|
||||
cap_free(cap);
|
||||
return False;
|
||||
}
|
||||
|
||||
cap_free(cap);
|
||||
|
||||
DEBUG(10,("set_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Try and abstract inherited process capabilities (for systems that have them).
|
||||
****************************************************************************/
|
||||
|
||||
static BOOL set_inherited_process_capability( uint32_t cap_flag, BOOL enable )
|
||||
{
|
||||
if(cap_flag == KERNEL_OPLOCK_CAPABILITY) {
|
||||
cap_t cap = cap_get_proc();
|
||||
|
||||
if (cap == NULL) {
|
||||
DEBUG(0,("set_inherited_process_capability: cap_get_proc failed. Error was %s\n",
|
||||
strerror(errno)));
|
||||
return False;
|
||||
}
|
||||
|
||||
if(enable)
|
||||
cap->cap_inheritable |= CAP_NETWORK_MGT;
|
||||
else
|
||||
cap->cap_inheritable &= ~CAP_NETWORK_MGT;
|
||||
|
||||
if (cap_set_proc(cap) == -1) {
|
||||
DEBUG(0,("set_inherited_process_capability: cap_set_proc failed. Error was %s\n",
|
||||
strerror(errno)));
|
||||
cap_free(cap);
|
||||
return False;
|
||||
}
|
||||
|
||||
cap_free(cap);
|
||||
|
||||
DEBUG(10,("set_inherited_process_capability: Set KERNEL_OPLOCK_CAPABILITY.\n"));
|
||||
}
|
||||
return True;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
AC_CACHE_CHECK([for irix specific capabilities],samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES,[
|
||||
AC_TRY_RUN([#include <sys/types.h>
|
||||
#include <sys/capability.h>
|
||||
main() {
|
||||
cap_t cap;
|
||||
if ((cap = cap_get_proc()) == NULL)
|
||||
exit(1);
|
||||
cap->cap_effective |= CAP_NETWORK_MGT;
|
||||
cap->cap_inheritable |= CAP_NETWORK_MGT;
|
||||
cap_set_proc(cap);
|
||||
exit(0);
|
||||
}
|
||||
],
|
||||
samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES=yes,samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES=no,samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES=cross)])
|
||||
if test x"$samba_cv_HAVE_IRIX_SPECIFIC_CAPABILITIES" = x"yes"; then
|
||||
AC_DEFINE(HAVE_IRIX_SPECIFIC_CAPABILITIES,1,[Whether IRIX specific capabilities are available])
|
||||
fi
|
||||
@@ -0,0 +1,58 @@
|
||||
[SUBSYSTEM::LIBSAMBA-UTIL]
|
||||
#VERSION = 0.0.1
|
||||
#SO_VERSION = 0
|
||||
#DESCRIPTION = Generic utility functions
|
||||
PUBLIC_PROTO_HEADER = util_proto.h
|
||||
PUBLIC_HEADERS = util.h \
|
||||
byteorder.h \
|
||||
debug.h \
|
||||
mutex.h \
|
||||
safe_string.h \
|
||||
xfile.h
|
||||
OBJ_FILES = xfile.o \
|
||||
debug.o \
|
||||
fault.o \
|
||||
signal.o \
|
||||
system.o \
|
||||
time.o \
|
||||
genrand.o \
|
||||
dprintf.o \
|
||||
util_str.o \
|
||||
util_strlist.o \
|
||||
util_file.o \
|
||||
data_blob.o \
|
||||
util.o \
|
||||
fsusage.o \
|
||||
ms_fnmatch.o \
|
||||
mutex.o \
|
||||
idtree.o \
|
||||
module.o
|
||||
PUBLIC_DEPENDENCIES = \
|
||||
LIBTALLOC LIBCRYPTO \
|
||||
SOCKET_WRAPPER EXT_NSL \
|
||||
CHARSET
|
||||
|
||||
[SUBSYSTEM::UNIX_PRIVS]
|
||||
PRIVATE_PROTO_HEADER = unix_privs.h
|
||||
OBJ_FILES = unix_privs.o
|
||||
|
||||
################################################
|
||||
# Start SUBSYSTEM WRAP_XATTR
|
||||
[SUBSYSTEM::WRAP_XATTR]
|
||||
PUBLIC_PROTO_HEADER = wrap_xattr.h
|
||||
OBJ_FILES = \
|
||||
wrap_xattr.o
|
||||
PUBLIC_DEPENDENCIES = XATTR
|
||||
#
|
||||
# End SUBSYSTEM WRAP_XATTR
|
||||
################################################
|
||||
|
||||
################################################
|
||||
# Start SUBSYSTEM UTIL_TDB
|
||||
[SUBSYSTEM::UTIL_TDB]
|
||||
PUBLIC_PROTO_HEADER = util_tdb.h
|
||||
OBJ_FILES = \
|
||||
util_tdb.o
|
||||
PUBLIC_DEPENDENCIES = LIBTDB
|
||||
# End SUBSYSTEM UTIL_TDB
|
||||
################################################
|
||||
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Easy management of byte-length data
|
||||
Copyright (C) Andrew Tridgell 2001
|
||||
Copyright (C) Andrew Bartlett 2001
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Manipulation of arbitrary data blobs
|
||||
**/
|
||||
|
||||
/**
|
||||
construct a data blob, must be freed with data_blob_free()
|
||||
you can pass NULL for p and get a blank data blob
|
||||
**/
|
||||
_PUBLIC_ DATA_BLOB data_blob_named(const void *p, size_t length, const char *name)
|
||||
{
|
||||
DATA_BLOB ret;
|
||||
|
||||
if (p == NULL && length == 0) {
|
||||
ZERO_STRUCT(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (p) {
|
||||
ret.data = talloc_memdup(NULL, p, length);
|
||||
} else {
|
||||
ret.data = talloc_size(NULL, length);
|
||||
}
|
||||
if (ret.data == NULL) {
|
||||
ret.length = 0;
|
||||
return ret;
|
||||
}
|
||||
talloc_set_name_const(ret.data, name);
|
||||
ret.length = length;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
construct a data blob, using supplied TALLOC_CTX
|
||||
**/
|
||||
_PUBLIC_ DATA_BLOB data_blob_talloc_named(TALLOC_CTX *mem_ctx, const void *p, size_t length, const char *name)
|
||||
{
|
||||
DATA_BLOB ret = data_blob_named(p, length, name);
|
||||
|
||||
if (ret.data) {
|
||||
talloc_steal(mem_ctx, ret.data);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
reference a data blob, to the supplied TALLOC_CTX.
|
||||
Returns a NULL DATA_BLOB on failure
|
||||
**/
|
||||
_PUBLIC_ DATA_BLOB data_blob_talloc_reference(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
|
||||
{
|
||||
DATA_BLOB ret = *blob;
|
||||
|
||||
ret.data = talloc_reference(mem_ctx, blob->data);
|
||||
|
||||
if (!ret.data) {
|
||||
return data_blob(NULL, 0);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
construct a zero data blob, using supplied TALLOC_CTX.
|
||||
use this sparingly as it initialises data - better to initialise
|
||||
yourself if you want specific data in the blob
|
||||
**/
|
||||
_PUBLIC_ DATA_BLOB data_blob_talloc_zero(TALLOC_CTX *mem_ctx, size_t length)
|
||||
{
|
||||
DATA_BLOB blob = data_blob_talloc(mem_ctx, NULL, length);
|
||||
data_blob_clear(&blob);
|
||||
return blob;
|
||||
}
|
||||
|
||||
/**
|
||||
free a data blob
|
||||
**/
|
||||
_PUBLIC_ void data_blob_free(DATA_BLOB *d)
|
||||
{
|
||||
if (d) {
|
||||
talloc_free(d->data);
|
||||
d->data = NULL;
|
||||
d->length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
clear a DATA_BLOB's contents
|
||||
**/
|
||||
_PUBLIC_ void data_blob_clear(DATA_BLOB *d)
|
||||
{
|
||||
if (d->data) {
|
||||
memset(d->data, 0, d->length);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
free a data blob and clear its contents
|
||||
**/
|
||||
_PUBLIC_ void data_blob_clear_free(DATA_BLOB *d)
|
||||
{
|
||||
data_blob_clear(d);
|
||||
data_blob_free(d);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
check if two data blobs are equal
|
||||
**/
|
||||
_PUBLIC_ BOOL data_blob_equal(const DATA_BLOB *d1, const DATA_BLOB *d2)
|
||||
{
|
||||
if (d1->length != d2->length) {
|
||||
return False;
|
||||
}
|
||||
if (d1->data == d2->data) {
|
||||
return True;
|
||||
}
|
||||
if (d1->data == NULL || d2->data == NULL) {
|
||||
return False;
|
||||
}
|
||||
if (memcmp(d1->data, d2->data, d1->length) == 0) {
|
||||
return True;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
/**
|
||||
print the data_blob as hex string
|
||||
**/
|
||||
_PUBLIC_ char *data_blob_hex_string(TALLOC_CTX *mem_ctx, DATA_BLOB *blob)
|
||||
{
|
||||
int i;
|
||||
char *hex_string;
|
||||
|
||||
hex_string = talloc_array(mem_ctx, char, (blob->length*2)+1);
|
||||
if (!hex_string) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < blob->length; i++)
|
||||
slprintf(&hex_string[i*2], 3, "%02X", blob->data[i]);
|
||||
|
||||
return hex_string;
|
||||
}
|
||||
|
||||
/**
|
||||
useful for constructing data blobs in test suites, while
|
||||
avoiding const warnings
|
||||
**/
|
||||
_PUBLIC_ DATA_BLOB data_blob_string_const(const char *str)
|
||||
{
|
||||
DATA_BLOB blob;
|
||||
blob.data = discard_const(str);
|
||||
blob.length = strlen(str);
|
||||
return blob;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new data blob from const data
|
||||
*/
|
||||
|
||||
_PUBLIC_ DATA_BLOB data_blob_const(const void *p, size_t length)
|
||||
{
|
||||
DATA_BLOB blob;
|
||||
blob.data = discard_const(p);
|
||||
blob.length = length;
|
||||
return blob;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
realloc a data_blob
|
||||
**/
|
||||
_PUBLIC_ NTSTATUS data_blob_realloc(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, size_t length)
|
||||
{
|
||||
blob->data = talloc_realloc_size(mem_ctx, blob->data, length);
|
||||
NT_STATUS_HAVE_NO_MEMORY(blob->data);
|
||||
blob->length = length;
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
append some data to a data blob
|
||||
**/
|
||||
_PUBLIC_ NTSTATUS data_blob_append(TALLOC_CTX *mem_ctx, DATA_BLOB *blob,
|
||||
const void *p, size_t length)
|
||||
{
|
||||
NTSTATUS status;
|
||||
size_t old_len = blob->length;
|
||||
size_t new_len = old_len + length;
|
||||
if (new_len < length || new_len < old_len) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
if ((const uint8_t *)p + length < (const uint8_t *)p) {
|
||||
return NT_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
status = data_blob_realloc(mem_ctx, blob, new_len);
|
||||
if (!NT_STATUS_IS_OK(status)) {
|
||||
return status;
|
||||
}
|
||||
|
||||
memcpy(blob->data + old_len, p, length);
|
||||
return NT_STATUS_OK;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Samba debug functions
|
||||
Copyright (C) Andrew Tridgell 2003
|
||||
Copyright (C) James J Myers 2003
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/filesys.h"
|
||||
#include "system/time.h"
|
||||
#include "dynconfig.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Debug logging
|
||||
**/
|
||||
|
||||
/**
|
||||
* this global variable determines what messages are printed
|
||||
*/
|
||||
_PUBLIC_ int DEBUGLEVEL;
|
||||
|
||||
/* the registered mutex handlers */
|
||||
static struct {
|
||||
const char *name;
|
||||
struct debug_ops ops;
|
||||
} debug_handlers;
|
||||
|
||||
/* state variables for the debug system */
|
||||
static struct {
|
||||
int fd;
|
||||
enum debug_logtype logtype;
|
||||
const char *prog_name;
|
||||
} state;
|
||||
|
||||
static BOOL reopen_logs_scheduled;
|
||||
static BOOL check_reopen_logs(void)
|
||||
{
|
||||
if (state.fd == 0 || reopen_logs_scheduled) {
|
||||
reopen_logs_scheduled = False;
|
||||
reopen_logs();
|
||||
}
|
||||
|
||||
if (state.fd <= 0) return False;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
_PUBLIC_ void debug_schedule_reopen_logs(void)
|
||||
{
|
||||
reopen_logs_scheduled = True;
|
||||
}
|
||||
|
||||
static void log_timestring(int level, const char *location, const char *func)
|
||||
{
|
||||
char *t = NULL;
|
||||
char *s = NULL;
|
||||
|
||||
if (!check_reopen_logs()) return;
|
||||
|
||||
if (state.logtype != DEBUG_FILE) return;
|
||||
|
||||
t = timestring(NULL, time(NULL));
|
||||
if (!t) return;
|
||||
|
||||
asprintf(&s, "[%s, %d %s:%s()]\n", t, level, location, func);
|
||||
talloc_free(t);
|
||||
if (!s) return;
|
||||
|
||||
write(state.fd, s, strlen(s));
|
||||
free(s);
|
||||
}
|
||||
|
||||
static void log_location(const char* location, const char* func)
|
||||
{
|
||||
char *s = NULL;
|
||||
|
||||
if (!check_reopen_logs()) return;
|
||||
|
||||
if (strncmp(location, "lib/talloc/talloc.c", strlen("lib/talloc/talloc.c")) == 0) return;
|
||||
|
||||
asprintf(&s, "[%s:%s()] ", location, func);
|
||||
if (!s) return;
|
||||
|
||||
write(state.fd, s, strlen(s));
|
||||
free(s);
|
||||
}
|
||||
|
||||
/**
|
||||
the backend for debug messages. Note that the DEBUG() macro has already
|
||||
ensured that the log level has been met before this is called
|
||||
*/
|
||||
_PUBLIC_ void do_debug_header(int level, const char *location, const char *func)
|
||||
{
|
||||
// log_timestring(level, location, func);
|
||||
log_location(location, func);
|
||||
log_task_id();
|
||||
}
|
||||
|
||||
/**
|
||||
the backend for debug messages. Note that the DEBUG() macro has already
|
||||
ensured that the log level has been met before this is called
|
||||
|
||||
@note You should never have to call this function directly. Call the DEBUG()
|
||||
macro instead.
|
||||
*/
|
||||
_PUBLIC_ void do_debug(const char *format, ...) _PRINTF_ATTRIBUTE(1,2)
|
||||
{
|
||||
va_list ap;
|
||||
char *s = NULL;
|
||||
|
||||
if (!check_reopen_logs()) return;
|
||||
|
||||
va_start(ap, format);
|
||||
vasprintf(&s, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
write(state.fd, s, strlen(s));
|
||||
free(s);
|
||||
}
|
||||
|
||||
_PUBLIC_ const char *logfile = NULL;
|
||||
|
||||
/**
|
||||
reopen the log file (usually called because the log file name might have changed)
|
||||
*/
|
||||
_PUBLIC_ void reopen_logs(void)
|
||||
{
|
||||
char *fname = NULL;
|
||||
int old_fd = state.fd;
|
||||
|
||||
switch (state.logtype) {
|
||||
case DEBUG_STDOUT:
|
||||
state.fd = 1;
|
||||
break;
|
||||
|
||||
case DEBUG_STDERR:
|
||||
state.fd = 2;
|
||||
break;
|
||||
|
||||
case DEBUG_FILE:
|
||||
if ((*logfile) == '/') {
|
||||
fname = strdup(logfile);
|
||||
} else {
|
||||
asprintf(&fname, "%s/%s.log", dyn_LOGFILEBASE, state.prog_name);
|
||||
}
|
||||
if (fname) {
|
||||
int newfd = open(fname, O_CREAT|O_APPEND|O_WRONLY, 0600);
|
||||
if (newfd == -1) {
|
||||
DEBUG(1, ("Failed to open new logfile: %s\n", fname));
|
||||
old_fd = -1;
|
||||
} else {
|
||||
state.fd = newfd;
|
||||
}
|
||||
free(fname);
|
||||
} else {
|
||||
DEBUG(1, ("Failed to find name for file-based logfile!\n"));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (old_fd > 2) {
|
||||
close(old_fd);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
control the name of the logfile and whether logging will be to stdout, stderr
|
||||
or a file
|
||||
*/
|
||||
_PUBLIC_ void setup_logging(const char *prog_name, enum debug_logtype new_logtype)
|
||||
{
|
||||
if (state.logtype < new_logtype) {
|
||||
state.logtype = new_logtype;
|
||||
}
|
||||
if (prog_name) {
|
||||
state.prog_name = prog_name;
|
||||
}
|
||||
reopen_logs();
|
||||
}
|
||||
|
||||
/**
|
||||
return a string constant containing n tabs
|
||||
no more than 10 tabs are returned
|
||||
*/
|
||||
_PUBLIC_ const char *do_debug_tab(int n)
|
||||
{
|
||||
const char *tabs[] = {"", "\t", "\t\t", "\t\t\t", "\t\t\t\t", "\t\t\t\t\t",
|
||||
"\t\t\t\t\t\t", "\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t\t",
|
||||
"\t\t\t\t\t\t\t\t\t", "\t\t\t\t\t\t\t\t\t\t"};
|
||||
return tabs[MIN(n, 10)];
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
log suspicious usage - print comments and backtrace
|
||||
*/
|
||||
_PUBLIC_ void log_suspicious_usage(const char *from, const char *info)
|
||||
{
|
||||
if (!debug_handlers.ops.log_suspicious_usage) return;
|
||||
|
||||
debug_handlers.ops.log_suspicious_usage(from, info);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
print suspicious usage - print comments and backtrace
|
||||
*/
|
||||
_PUBLIC_ void print_suspicious_usage(const char* from, const char* info)
|
||||
{
|
||||
if (!debug_handlers.ops.print_suspicious_usage) return;
|
||||
|
||||
debug_handlers.ops.print_suspicious_usage(from, info);
|
||||
}
|
||||
|
||||
_PUBLIC_ uint32_t get_task_id(void)
|
||||
{
|
||||
if (debug_handlers.ops.get_task_id) {
|
||||
return debug_handlers.ops.get_task_id();
|
||||
}
|
||||
return getpid();
|
||||
}
|
||||
|
||||
_PUBLIC_ void log_task_id(void)
|
||||
{
|
||||
if (!debug_handlers.ops.log_task_id) return;
|
||||
|
||||
if (!check_reopen_logs()) return;
|
||||
|
||||
debug_handlers.ops.log_task_id(state.fd);
|
||||
}
|
||||
|
||||
/**
|
||||
register a set of debug handlers.
|
||||
*/
|
||||
_PUBLIC_ void register_debug_handlers(const char *name, struct debug_ops *ops)
|
||||
{
|
||||
debug_handlers.name = name;
|
||||
debug_handlers.ops = *ops;
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Samba debug defines
|
||||
Copyright (C) Andrew Tridgell 2003
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Debugging macros
|
||||
*/
|
||||
|
||||
/* the debug operations structure - contains function pointers to
|
||||
various debug implementations of each operation */
|
||||
struct debug_ops {
|
||||
/* function to log (using DEBUG) suspicious usage of data structure */
|
||||
void (*log_suspicious_usage)(const char* from, const char* info);
|
||||
|
||||
/* function to log (using printf) suspicious usage of data structure.
|
||||
* To be used in circumstances when using DEBUG would cause loop. */
|
||||
void (*print_suspicious_usage)(const char* from, const char* info);
|
||||
|
||||
/* function to return process/thread id */
|
||||
uint32_t (*get_task_id)(void);
|
||||
|
||||
/* function to log process/thread id */
|
||||
void (*log_task_id)(int fd);
|
||||
};
|
||||
|
||||
extern int DEBUGLEVEL;
|
||||
#define DEBUGLVL(level) ((level) <= DEBUGLEVEL)
|
||||
#define _DEBUG(level, body, header) do { \
|
||||
if (DEBUGLVL(level)) { \
|
||||
if (header) { \
|
||||
do_debug_header(level, __location__, __FUNCTION__); \
|
||||
} \
|
||||
do_debug body; \
|
||||
} \
|
||||
} while (0)
|
||||
/**
|
||||
* Write to the debug log.
|
||||
*/
|
||||
#define DEBUG(level, body) _DEBUG(level, body, True)
|
||||
/**
|
||||
* Add data to an existing debug log entry.
|
||||
*/
|
||||
#define DEBUGADD(level, body) _DEBUG(level, body, False)
|
||||
|
||||
/**
|
||||
* Obtain indentation string for the debug log.
|
||||
*
|
||||
* Level specified by n.
|
||||
*/
|
||||
#define DEBUGTAB(n) do_debug_tab(n)
|
||||
|
||||
#define DEBUG_FN_ENTER DEBUG(9,("ENTER function %s\n", __FUNCTION__))
|
||||
#define DEBUG_FN_ENTER_MSG(_msg) DEBUG(9,("ENTER function %s (%s)\n", __FUNCTION__, _msg))
|
||||
#define DEBUG_FN_EXIT DEBUG(9,("EXIT function %s (PASS)\n", __FUNCTION__))
|
||||
#define DEBUG_FN_EXIT_MSG(_msg) DEBUG(9,("EXIT function %s (PASS) (%s)\n", __FUNCTION__, _msg))
|
||||
#define DEBUG_FN_FAIL(_msg) DEBUG(9,("exit function %s (FAIL) (%s)\n", __FUNCTION__, _msg))
|
||||
|
||||
/** Possible destinations for the debug log */
|
||||
enum debug_logtype {DEBUG_STDOUT = 0, DEBUG_FILE = 1, DEBUG_STDERR = 2};
|
||||
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
some simple double linked list macros
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/* To use these macros you must have a structure containing a next and
|
||||
prev pointer */
|
||||
|
||||
#ifndef _DLINKLIST_H
|
||||
#define _DLINKLIST_H
|
||||
|
||||
|
||||
/* hook into the front of the list */
|
||||
#define DLIST_ADD(list, p) \
|
||||
do { \
|
||||
if (!(list)) { \
|
||||
(list) = (p); \
|
||||
(p)->next = (p)->prev = NULL; \
|
||||
} else { \
|
||||
(list)->prev = (p); \
|
||||
(p)->next = (list); \
|
||||
(p)->prev = NULL; \
|
||||
(list) = (p); \
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
/* remove an element from a list - element doesn't have to be in list. */
|
||||
#define DLIST_REMOVE(list, p) \
|
||||
do { \
|
||||
if ((p) == (list)) { \
|
||||
(list) = (p)->next; \
|
||||
if (list) (list)->prev = NULL; \
|
||||
} else { \
|
||||
if ((p)->prev) (p)->prev->next = (p)->next; \
|
||||
if ((p)->next) (p)->next->prev = (p)->prev; \
|
||||
} \
|
||||
if ((p) != (list)) (p)->next = (p)->prev = NULL; \
|
||||
} while (0)
|
||||
|
||||
/* promote an element to the top of the list */
|
||||
#define DLIST_PROMOTE(list, p) \
|
||||
do { \
|
||||
DLIST_REMOVE(list, p); \
|
||||
DLIST_ADD(list, p); \
|
||||
} while (0)
|
||||
|
||||
/* hook into the end of the list - needs a tmp pointer */
|
||||
#define DLIST_ADD_END(list, p, type) \
|
||||
do { \
|
||||
if (!(list)) { \
|
||||
(list) = (p); \
|
||||
(p)->next = (p)->prev = NULL; \
|
||||
} else { \
|
||||
type tmp; \
|
||||
for (tmp = (list); tmp->next; tmp = tmp->next) ; \
|
||||
tmp->next = (p); \
|
||||
(p)->next = NULL; \
|
||||
(p)->prev = tmp; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/* insert 'p' after the given element 'el' in a list. If el is NULL then
|
||||
this is the same as a DLIST_ADD() */
|
||||
#define DLIST_ADD_AFTER(list, p, el) \
|
||||
do { \
|
||||
if (!(list) || !(el)) { \
|
||||
DLIST_ADD(list, p); \
|
||||
} else { \
|
||||
p->prev = el; \
|
||||
p->next = el->next; \
|
||||
el->next = p; \
|
||||
if (p->next) p->next->prev = p; \
|
||||
}\
|
||||
} while (0)
|
||||
|
||||
/* demote an element to the end of the list, needs a tmp pointer */
|
||||
#define DLIST_DEMOTE(list, p, tmp) \
|
||||
do { \
|
||||
DLIST_REMOVE(list, p); \
|
||||
DLIST_ADD_END(list, p, tmp); \
|
||||
} while (0)
|
||||
|
||||
/* concatenate two lists - putting all elements of the 2nd list at the
|
||||
end of the first list */
|
||||
#define DLIST_CONCATENATE(list1, list2, type) \
|
||||
do { \
|
||||
if (!(list1)) { \
|
||||
(list1) = (list2); \
|
||||
} else { \
|
||||
type tmp; \
|
||||
for (tmp = (list1); tmp->next; tmp = tmp->next) ; \
|
||||
tmp->next = (list2); \
|
||||
if (list2) { \
|
||||
(list2)->prev = tmp; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#endif /* _DLINKLIST_H */
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
display print functions
|
||||
Copyright (C) Andrew Tridgell 2001
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
this module provides functions for printing internal strings in the "display charset"
|
||||
This charset may be quite different from the chosen unix charset
|
||||
|
||||
Eventually these functions will need to take care of column count constraints
|
||||
|
||||
The d_ prefix on print functions in Samba refers to the display character set
|
||||
conversion
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
_PUBLIC_ int d_vfprintf(FILE *f, const char *format, va_list ap) _PRINTF_ATTRIBUTE(2,0)
|
||||
{
|
||||
char *p, *p2;
|
||||
int ret, maxlen, clen;
|
||||
va_list ap2;
|
||||
|
||||
/* do any message translations */
|
||||
va_copy(ap2, ap);
|
||||
|
||||
ret = vasprintf(&p, format, ap2);
|
||||
|
||||
if (ret <= 0) return ret;
|
||||
|
||||
/* now we have the string in unix format, convert it to the display
|
||||
charset, but beware of it growing */
|
||||
maxlen = ret*2;
|
||||
again:
|
||||
p2 = malloc(maxlen);
|
||||
if (!p2) {
|
||||
SAFE_FREE(p);
|
||||
return -1;
|
||||
}
|
||||
clen = convert_string(CH_UNIX, CH_DISPLAY, p, ret, p2, maxlen);
|
||||
|
||||
if (clen >= maxlen) {
|
||||
/* it didn't fit - try a larger buffer */
|
||||
maxlen *= 2;
|
||||
SAFE_FREE(p2);
|
||||
goto again;
|
||||
}
|
||||
|
||||
/* good, its converted OK */
|
||||
SAFE_FREE(p);
|
||||
ret = fwrite(p2, 1, clen, f);
|
||||
SAFE_FREE(p2);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
_PUBLIC_ int d_fprintf(FILE *f, const char *format, ...) _PRINTF_ATTRIBUTE(2,3)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, format);
|
||||
ret = d_vfprintf(f, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static FILE *outfile;
|
||||
|
||||
_PUBLIC_ int d_printf(const char *format, ...) _PRINTF_ATTRIBUTE(1,2)
|
||||
{
|
||||
int ret;
|
||||
va_list ap;
|
||||
|
||||
if (!outfile) outfile = stdout;
|
||||
|
||||
va_start(ap, format);
|
||||
ret = d_vfprintf(outfile, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* interactive programs need a way of tell d_*() to write to stderr instead
|
||||
of stdout */
|
||||
_PUBLIC_ void display_set_stderr(void)
|
||||
{
|
||||
outfile = stderr;
|
||||
}
|
||||
@@ -0,0 +1,226 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Critical Fault handling
|
||||
Copyright (C) Andrew Tridgell 1992-1998
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "version.h"
|
||||
#include "system/wait.h"
|
||||
#include "system/filesys.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Fault handling
|
||||
*/
|
||||
|
||||
/* the registered fault handler */
|
||||
static struct {
|
||||
const char *name;
|
||||
void (*fault_handler)(int sig);
|
||||
} fault_handlers;
|
||||
|
||||
static const char *progname;
|
||||
|
||||
#ifdef HAVE_BACKTRACE
|
||||
#include <execinfo.h>
|
||||
#elif HAVE_LIBEXC_H
|
||||
#include <libexc.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Write backtrace to debug log
|
||||
*/
|
||||
_PUBLIC_ void call_backtrace(void)
|
||||
{
|
||||
#ifdef HAVE_BACKTRACE
|
||||
#ifndef BACKTRACE_STACK_SIZE
|
||||
#define BACKTRACE_STACK_SIZE 64
|
||||
#endif
|
||||
void *backtrace_stack[BACKTRACE_STACK_SIZE];
|
||||
size_t backtrace_size;
|
||||
char **backtrace_strings;
|
||||
|
||||
/* get the backtrace (stack frames) */
|
||||
backtrace_size = backtrace(backtrace_stack,BACKTRACE_STACK_SIZE);
|
||||
backtrace_strings = backtrace_symbols(backtrace_stack, backtrace_size);
|
||||
|
||||
DEBUG(0, ("BACKTRACE: %lu stack frames:\n",
|
||||
(unsigned long)backtrace_size));
|
||||
|
||||
if (backtrace_strings) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < backtrace_size; i++)
|
||||
DEBUGADD(0, (" #%u %s\n", i, backtrace_strings[i]));
|
||||
|
||||
/* Leak the backtrace_strings, rather than risk what free() might do */
|
||||
}
|
||||
|
||||
#elif HAVE_LIBEXC
|
||||
|
||||
#define NAMESIZE 32 /* Arbitrary */
|
||||
#ifndef BACKTRACE_STACK_SIZE
|
||||
#define BACKTRACE_STACK_SIZE 64
|
||||
#endif
|
||||
|
||||
/* The IRIX libexc library provides an API for unwinding the stack. See
|
||||
* libexc(3) for details. Apparantly trace_back_stack leaks memory, but
|
||||
* since we are about to abort anyway, it hardly matters.
|
||||
*
|
||||
* Note that if we paniced due to a SIGSEGV or SIGBUS (or similar) this
|
||||
* will fail with a nasty message upon failing to open the /proc entry.
|
||||
*/
|
||||
{
|
||||
uint64_t addrs[BACKTRACE_STACK_SIZE];
|
||||
char * names[BACKTRACE_STACK_SIZE];
|
||||
char namebuf[BACKTRACE_STACK_SIZE * NAMESIZE];
|
||||
|
||||
int i;
|
||||
int levels;
|
||||
|
||||
ZERO_ARRAY(addrs);
|
||||
ZERO_ARRAY(names);
|
||||
ZERO_ARRAY(namebuf);
|
||||
|
||||
for (i = 0; i < BACKTRACE_STACK_SIZE; i++) {
|
||||
names[i] = namebuf + (i * NAMESIZE);
|
||||
}
|
||||
|
||||
levels = trace_back_stack(0, addrs, names,
|
||||
BACKTRACE_STACK_SIZE, NAMESIZE);
|
||||
|
||||
DEBUG(0, ("BACKTRACE: %d stack frames:\n", levels));
|
||||
for (i = 0; i < levels; i++) {
|
||||
DEBUGADD(0, (" #%d 0x%llx %s\n", i, addrs[i], names[i]));
|
||||
}
|
||||
}
|
||||
#undef NAMESIZE
|
||||
#endif
|
||||
}
|
||||
|
||||
_PUBLIC_ const char *panic_action = NULL;
|
||||
|
||||
/**
|
||||
Something really nasty happened - panic !
|
||||
**/
|
||||
_PUBLIC_ void smb_panic(const char *why)
|
||||
{
|
||||
int result;
|
||||
|
||||
if (panic_action && *panic_action) {
|
||||
char pidstr[20];
|
||||
char cmdstring[200];
|
||||
safe_strcpy(cmdstring, panic_action, sizeof(cmdstring));
|
||||
snprintf(pidstr, sizeof(pidstr), "%u", getpid());
|
||||
all_string_sub(cmdstring, "%PID%", pidstr, sizeof(cmdstring));
|
||||
if (progname) {
|
||||
all_string_sub(cmdstring, "%PROG%", progname, sizeof(cmdstring));
|
||||
}
|
||||
DEBUG(0, ("smb_panic(): calling panic action [%s]\n", cmdstring));
|
||||
result = system(cmdstring);
|
||||
|
||||
if (result == -1)
|
||||
DEBUG(0, ("smb_panic(): fork failed in panic action: %s\n",
|
||||
strerror(errno)));
|
||||
else
|
||||
DEBUG(0, ("smb_panic(): action returned status %d\n",
|
||||
WEXITSTATUS(result)));
|
||||
}
|
||||
DEBUG(0,("PANIC: %s\n", why));
|
||||
|
||||
call_backtrace();
|
||||
|
||||
#ifdef SIGABRT
|
||||
CatchSignal(SIGABRT,SIGNAL_CAST SIG_DFL);
|
||||
#endif
|
||||
abort();
|
||||
}
|
||||
|
||||
/**
|
||||
report a fault
|
||||
**/
|
||||
static void fault_report(int sig)
|
||||
{
|
||||
static int counter;
|
||||
|
||||
if (counter) _exit(1);
|
||||
|
||||
DEBUG(0,("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"));
|
||||
DEBUG(0,("INTERNAL ERROR: Signal %d in pid %d (%s)",sig,(int)getpid(),SAMBA_VERSION_STRING));
|
||||
DEBUG(0,("\nPlease read the file BUGS.txt in the distribution\n"));
|
||||
DEBUG(0,("=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=\n"));
|
||||
|
||||
smb_panic("internal error");
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/**
|
||||
catch serious errors
|
||||
**/
|
||||
static void sig_fault(int sig)
|
||||
{
|
||||
if (fault_handlers.fault_handler) {
|
||||
/* we have a fault handler, call it. It may not return. */
|
||||
fault_handlers.fault_handler(sig);
|
||||
}
|
||||
/* If it returns or doean't exist, use regular reporter */
|
||||
fault_report(sig);
|
||||
}
|
||||
|
||||
/**
|
||||
setup our fault handlers
|
||||
**/
|
||||
_PUBLIC_ void fault_setup(const char *pname)
|
||||
{
|
||||
if (progname == NULL) {
|
||||
progname = pname;
|
||||
}
|
||||
#ifdef SIGSEGV
|
||||
CatchSignal(SIGSEGV,SIGNAL_CAST sig_fault);
|
||||
#endif
|
||||
#ifdef SIGBUS
|
||||
CatchSignal(SIGBUS,SIGNAL_CAST sig_fault);
|
||||
#endif
|
||||
#ifdef SIGABRT
|
||||
CatchSignal(SIGABRT,SIGNAL_CAST sig_fault);
|
||||
#endif
|
||||
#ifdef SIGFPE
|
||||
CatchSignal(SIGFPE,SIGNAL_CAST sig_fault);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
register a fault handler.
|
||||
Should only be called once in the execution of smbd.
|
||||
*/
|
||||
_PUBLIC_ BOOL register_fault_handler(const char *name, void (*fault_handler)(int sig))
|
||||
{
|
||||
if (fault_handlers.name != NULL) {
|
||||
/* it's already registered! */
|
||||
DEBUG(2,("fault handler '%s' already registered - failed '%s'\n",
|
||||
fault_handlers.name, name));
|
||||
return False;
|
||||
}
|
||||
|
||||
fault_handlers.name = name;
|
||||
fault_handlers.fault_handler = fault_handler;
|
||||
|
||||
DEBUG(2,("fault handler '%s' registered\n", name));
|
||||
return True;
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
AC_CHECK_HEADER(execinfo.h)
|
||||
AC_CHECK_FUNCS(backtrace)
|
||||
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
functions to calculate the free disk space
|
||||
Copyright (C) Andrew Tridgell 1998-2000
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/filesys.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Utility functions for getting the amount of free disk space
|
||||
*/
|
||||
|
||||
/* Return the number of TOSIZE-byte blocks used by
|
||||
BLOCKS FROMSIZE-byte blocks, rounding away from zero.
|
||||
*/
|
||||
static uint64_t adjust_blocks(uint64_t blocks, uint64_t fromsize, uint64_t tosize)
|
||||
{
|
||||
if (fromsize == tosize) /* e.g., from 512 to 512 */
|
||||
return blocks;
|
||||
else if (fromsize > tosize) /* e.g., from 2048 to 512 */
|
||||
return blocks * (fromsize / tosize);
|
||||
else /* e.g., from 256 to 512 */
|
||||
return (blocks + 1) / (tosize / fromsize);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve amount of free disk space.
|
||||
* this does all of the system specific guff to get the free disk space.
|
||||
* It is derived from code in the GNU fileutils package, but has been
|
||||
* considerably mangled for use here
|
||||
*
|
||||
* results are returned in *dfree and *dsize, in 512 byte units
|
||||
*/
|
||||
_PUBLIC_ int sys_fsusage(const char *path, uint64_t *dfree, uint64_t *dsize)
|
||||
{
|
||||
#ifdef STAT_STATFS3_OSF1
|
||||
#define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)fsd.f_fsize, (uint64_t)512)
|
||||
struct statfs fsd;
|
||||
|
||||
if (statfs (path, &fsd, sizeof (struct statfs)) != 0)
|
||||
return -1;
|
||||
#endif /* STAT_STATFS3_OSF1 */
|
||||
|
||||
#ifdef STAT_STATFS2_FS_DATA /* Ultrix */
|
||||
#define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)1024, (uint64_t)512)
|
||||
struct fs_data fsd;
|
||||
|
||||
if (statfs (path, &fsd) != 1)
|
||||
return -1;
|
||||
|
||||
(*dsize) = CONVERT_BLOCKS (fsd.fd_req.btot);
|
||||
(*dfree) = CONVERT_BLOCKS (fsd.fd_req.bfreen);
|
||||
#endif /* STAT_STATFS2_FS_DATA */
|
||||
|
||||
#ifdef STAT_STATFS2_BSIZE /* 4.3BSD, SunOS 4, HP-UX, AIX */
|
||||
#define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)fsd.f_bsize, (uint64_t)512)
|
||||
struct statfs fsd;
|
||||
|
||||
if (statfs (path, &fsd) < 0)
|
||||
return -1;
|
||||
|
||||
#ifdef STATFS_TRUNCATES_BLOCK_COUNTS
|
||||
/* In SunOS 4.1.2, 4.1.3, and 4.1.3_U1, the block counts in the
|
||||
struct statfs are truncated to 2GB. These conditions detect that
|
||||
truncation, presumably without botching the 4.1.1 case, in which
|
||||
the values are not truncated. The correct counts are stored in
|
||||
undocumented spare fields. */
|
||||
if (fsd.f_blocks == 0x1fffff && fsd.f_spare[0] > 0) {
|
||||
fsd.f_blocks = fsd.f_spare[0];
|
||||
fsd.f_bfree = fsd.f_spare[1];
|
||||
fsd.f_bavail = fsd.f_spare[2];
|
||||
}
|
||||
#endif /* STATFS_TRUNCATES_BLOCK_COUNTS */
|
||||
#endif /* STAT_STATFS2_BSIZE */
|
||||
|
||||
|
||||
#ifdef STAT_STATFS2_FSIZE /* 4.4BSD */
|
||||
#define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)fsd.f_fsize, (uint64_t)512)
|
||||
|
||||
struct statfs fsd;
|
||||
|
||||
if (statfs (path, &fsd) < 0)
|
||||
return -1;
|
||||
#endif /* STAT_STATFS2_FSIZE */
|
||||
|
||||
#ifdef STAT_STATFS4 /* SVR3, Dynix, Irix, AIX */
|
||||
# if _AIX || defined(_CRAY)
|
||||
# define CONVERT_BLOCKS(B) adjust_blocks ((uint64_t)(B), (uint64_t)fsd.f_bsize, (uint64_t)512)
|
||||
# ifdef _CRAY
|
||||
# define f_bavail f_bfree
|
||||
# endif
|
||||
# else
|
||||
# define CONVERT_BLOCKS(B) ((uint64_t)B)
|
||||
# ifndef _SEQUENT_ /* _SEQUENT_ is DYNIX/ptx */
|
||||
# ifndef DOLPHIN /* DOLPHIN 3.8.alfa/7.18 has f_bavail */
|
||||
# define f_bavail f_bfree
|
||||
# endif
|
||||
# endif
|
||||
# endif
|
||||
|
||||
struct statfs fsd;
|
||||
|
||||
if (statfs (path, &fsd, sizeof fsd, 0) < 0)
|
||||
return -1;
|
||||
/* Empirically, the block counts on most SVR3 and SVR3-derived
|
||||
systems seem to always be in terms of 512-byte blocks,
|
||||
no matter what value f_bsize has. */
|
||||
|
||||
#endif /* STAT_STATFS4 */
|
||||
|
||||
#if defined(STAT_STATVFS) || defined(STAT_STATVFS64) /* SVR4 */
|
||||
# define CONVERT_BLOCKS(B) \
|
||||
adjust_blocks ((uint64_t)(B), fsd.f_frsize ? (uint64_t)fsd.f_frsize : (uint64_t)fsd.f_bsize, (uint64_t)512)
|
||||
|
||||
#ifdef STAT_STATVFS64
|
||||
struct statvfs64 fsd;
|
||||
if (statvfs64(path, &fsd) < 0) return -1;
|
||||
#else
|
||||
struct statvfs fsd;
|
||||
if (statvfs(path, &fsd) < 0) return -1;
|
||||
#endif
|
||||
|
||||
/* f_frsize isn't guaranteed to be supported. */
|
||||
|
||||
#endif /* STAT_STATVFS */
|
||||
|
||||
#ifndef CONVERT_BLOCKS
|
||||
/* we don't have any dfree code! */
|
||||
return -1;
|
||||
#else
|
||||
#if !defined(STAT_STATFS2_FS_DATA)
|
||||
/* !Ultrix */
|
||||
(*dsize) = CONVERT_BLOCKS (fsd.f_blocks);
|
||||
(*dfree) = CONVERT_BLOCKS (fsd.f_bavail);
|
||||
#endif /* not STAT_STATFS2_FS_DATA */
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,190 @@
|
||||
#################################################
|
||||
# these tests are taken from the GNU fileutils package
|
||||
AC_CHECKING(how to get filesystem space usage)
|
||||
AC_CHECK_HEADERS(sys/statfs.h sys/statvfs.h sys/vfs.h)
|
||||
|
||||
AC_CHECK_HEADERS(sys/mount.h, , , [AC_INCLUDES_DEFAULT
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif])
|
||||
|
||||
space=no
|
||||
|
||||
# Test for statvfs64.
|
||||
if test $space = no; then
|
||||
# SVR4
|
||||
AC_CACHE_CHECK([statvfs64 function (SVR4)], fu_cv_sys_stat_statvfs64,
|
||||
[AC_TRY_RUN([
|
||||
#if defined(HAVE_UNISTD_H)
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
#include <sys/types.h>
|
||||
#include <sys/statvfs.h>
|
||||
main ()
|
||||
{
|
||||
struct statvfs64 fsd;
|
||||
exit (statvfs64 (".", &fsd));
|
||||
}],
|
||||
fu_cv_sys_stat_statvfs64=yes,
|
||||
fu_cv_sys_stat_statvfs64=no,
|
||||
fu_cv_sys_stat_statvfs64=cross)])
|
||||
if test $fu_cv_sys_stat_statvfs64 = yes; then
|
||||
space=yes
|
||||
AC_DEFINE(STAT_STATVFS64,1,[Whether statvfs64() is available])
|
||||
fi
|
||||
fi
|
||||
|
||||
# Perform only the link test since it seems there are no variants of the
|
||||
# statvfs function. This check is more than just AC_CHECK_FUNCS(statvfs)
|
||||
# because that got a false positive on SCO OSR5. Adding the declaration
|
||||
# of a `struct statvfs' causes this test to fail (as it should) on such
|
||||
# systems. That system is reported to work fine with STAT_STATFS4 which
|
||||
# is what it gets when this test fails.
|
||||
if test $space = no; then
|
||||
# SVR4
|
||||
AC_CACHE_CHECK([statvfs function (SVR4)], fu_cv_sys_stat_statvfs,
|
||||
[AC_TRY_LINK([#include <sys/types.h>
|
||||
#include <sys/statvfs.h>],
|
||||
[struct statvfs fsd; statvfs (0, &fsd);],
|
||||
fu_cv_sys_stat_statvfs=yes,
|
||||
fu_cv_sys_stat_statvfs=no)])
|
||||
if test $fu_cv_sys_stat_statvfs = yes; then
|
||||
space=yes
|
||||
AC_DEFINE(STAT_STATVFS,1,[Whether statvfs() is available])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $space = no; then
|
||||
# DEC Alpha running OSF/1
|
||||
AC_MSG_CHECKING([for 3-argument statfs function (DEC OSF/1)])
|
||||
AC_CACHE_VAL(fu_cv_sys_stat_statfs3_osf1,
|
||||
[AC_TRY_RUN([
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/mount.h>
|
||||
main ()
|
||||
{
|
||||
struct statfs fsd;
|
||||
fsd.f_fsize = 0;
|
||||
exit (statfs (".", &fsd, sizeof (struct statfs)));
|
||||
}],
|
||||
fu_cv_sys_stat_statfs3_osf1=yes,
|
||||
fu_cv_sys_stat_statfs3_osf1=no,
|
||||
fu_cv_sys_stat_statfs3_osf1=no)])
|
||||
AC_MSG_RESULT($fu_cv_sys_stat_statfs3_osf1)
|
||||
if test $fu_cv_sys_stat_statfs3_osf1 = yes; then
|
||||
space=yes
|
||||
AC_DEFINE(STAT_STATFS3_OSF1,1,[Whether statfs requires 3 arguments])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $space = no; then
|
||||
# AIX
|
||||
AC_MSG_CHECKING([for two-argument statfs with statfs.bsize dnl
|
||||
member (AIX, 4.3BSD)])
|
||||
AC_CACHE_VAL(fu_cv_sys_stat_statfs2_bsize,
|
||||
[AC_TRY_RUN([
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_MOUNT_H
|
||||
#include <sys/mount.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_VFS_H
|
||||
#include <sys/vfs.h>
|
||||
#endif
|
||||
main ()
|
||||
{
|
||||
struct statfs fsd;
|
||||
fsd.f_bsize = 0;
|
||||
exit (statfs (".", &fsd));
|
||||
}],
|
||||
fu_cv_sys_stat_statfs2_bsize=yes,
|
||||
fu_cv_sys_stat_statfs2_bsize=no,
|
||||
fu_cv_sys_stat_statfs2_bsize=no)])
|
||||
AC_MSG_RESULT($fu_cv_sys_stat_statfs2_bsize)
|
||||
if test $fu_cv_sys_stat_statfs2_bsize = yes; then
|
||||
space=yes
|
||||
AC_DEFINE(STAT_STATFS2_BSIZE,1,[Whether statfs requires two arguments and struct statfs has bsize property])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $space = no; then
|
||||
# SVR3
|
||||
AC_MSG_CHECKING([for four-argument statfs (AIX-3.2.5, SVR3)])
|
||||
AC_CACHE_VAL(fu_cv_sys_stat_statfs4,
|
||||
[AC_TRY_RUN([#include <sys/types.h>
|
||||
#include <sys/statfs.h>
|
||||
main ()
|
||||
{
|
||||
struct statfs fsd;
|
||||
exit (statfs (".", &fsd, sizeof fsd, 0));
|
||||
}],
|
||||
fu_cv_sys_stat_statfs4=yes,
|
||||
fu_cv_sys_stat_statfs4=no,
|
||||
fu_cv_sys_stat_statfs4=no)])
|
||||
AC_MSG_RESULT($fu_cv_sys_stat_statfs4)
|
||||
if test $fu_cv_sys_stat_statfs4 = yes; then
|
||||
space=yes
|
||||
AC_DEFINE(STAT_STATFS4,1,[Whether statfs requires 4 arguments])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $space = no; then
|
||||
# 4.4BSD and NetBSD
|
||||
AC_MSG_CHECKING([for two-argument statfs with statfs.fsize dnl
|
||||
member (4.4BSD and NetBSD)])
|
||||
AC_CACHE_VAL(fu_cv_sys_stat_statfs2_fsize,
|
||||
[AC_TRY_RUN([#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_MOUNT_H
|
||||
#include <sys/mount.h>
|
||||
#endif
|
||||
main ()
|
||||
{
|
||||
struct statfs fsd;
|
||||
fsd.f_fsize = 0;
|
||||
exit (statfs (".", &fsd));
|
||||
}],
|
||||
fu_cv_sys_stat_statfs2_fsize=yes,
|
||||
fu_cv_sys_stat_statfs2_fsize=no,
|
||||
fu_cv_sys_stat_statfs2_fsize=no)])
|
||||
AC_MSG_RESULT($fu_cv_sys_stat_statfs2_fsize)
|
||||
if test $fu_cv_sys_stat_statfs2_fsize = yes; then
|
||||
space=yes
|
||||
AC_DEFINE(STAT_STATFS2_FSIZE,1,[Whether statfs requires 2 arguments and struct statfs has fsize])
|
||||
fi
|
||||
fi
|
||||
|
||||
if test $space = no; then
|
||||
# Ultrix
|
||||
AC_MSG_CHECKING([for two-argument statfs with struct fs_data (Ultrix)])
|
||||
AC_CACHE_VAL(fu_cv_sys_stat_fs_data,
|
||||
[AC_TRY_RUN([#include <sys/types.h>
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_MOUNT_H
|
||||
#include <sys/mount.h>
|
||||
#endif
|
||||
#ifdef HAVE_SYS_FS_TYPES_H
|
||||
#include <sys/fs_types.h>
|
||||
#endif
|
||||
main ()
|
||||
{
|
||||
struct fs_data fsd;
|
||||
/* Ultrix's statfs returns 1 for success,
|
||||
0 for not mounted, -1 for failure. */
|
||||
exit (statfs (".", &fsd) != 1);
|
||||
}],
|
||||
fu_cv_sys_stat_fs_data=yes,
|
||||
fu_cv_sys_stat_fs_data=no,
|
||||
fu_cv_sys_stat_fs_data=no)])
|
||||
AC_MSG_RESULT($fu_cv_sys_stat_fs_data)
|
||||
if test $fu_cv_sys_stat_fs_data = yes; then
|
||||
space=yes
|
||||
AC_DEFINE(STAT_STATFS2_FS_DATA,1,[Whether statfs requires 2 arguments and struct fs_data is available])
|
||||
fi
|
||||
fi
|
||||
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Functions to create reasonable random numbers for crypto use.
|
||||
|
||||
Copyright (C) Jeremy Allison 2001
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/filesys.h"
|
||||
#include "lib/crypto/crypto.h"
|
||||
#include "system/locale.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Random number generation
|
||||
*/
|
||||
|
||||
static unsigned char hash[258];
|
||||
static uint32_t counter;
|
||||
|
||||
static BOOL done_reseed = False;
|
||||
static void (*reseed_callback)(int *newseed);
|
||||
|
||||
/**
|
||||
Copy any user given reseed data.
|
||||
**/
|
||||
|
||||
_PUBLIC_ void set_rand_reseed_callback(void (*fn)(int *))
|
||||
{
|
||||
reseed_callback = fn;
|
||||
set_need_random_reseed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Tell the random number generator it needs to reseed.
|
||||
*/
|
||||
_PUBLIC_ void set_need_random_reseed(void)
|
||||
{
|
||||
done_reseed = False;
|
||||
}
|
||||
|
||||
static void get_rand_reseed_data(int *reseed_data)
|
||||
{
|
||||
if (reseed_callback) {
|
||||
reseed_callback(reseed_data);
|
||||
} else {
|
||||
*reseed_data = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
Setup the seed.
|
||||
*****************************************************************/
|
||||
|
||||
static void seed_random_stream(unsigned char *seedval, size_t seedlen)
|
||||
{
|
||||
unsigned char j = 0;
|
||||
size_t ind;
|
||||
|
||||
for (ind = 0; ind < 256; ind++)
|
||||
hash[ind] = (unsigned char)ind;
|
||||
|
||||
for( ind = 0; ind < 256; ind++) {
|
||||
unsigned char tc;
|
||||
|
||||
j += (hash[ind] + seedval[ind%seedlen]);
|
||||
|
||||
tc = hash[ind];
|
||||
hash[ind] = hash[j];
|
||||
hash[j] = tc;
|
||||
}
|
||||
|
||||
hash[256] = 0;
|
||||
hash[257] = 0;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
Get datasize bytes worth of random data.
|
||||
*****************************************************************/
|
||||
|
||||
static void get_random_stream(unsigned char *data, size_t datasize)
|
||||
{
|
||||
unsigned char index_i = hash[256];
|
||||
unsigned char index_j = hash[257];
|
||||
size_t ind;
|
||||
|
||||
for( ind = 0; ind < datasize; ind++) {
|
||||
unsigned char tc;
|
||||
unsigned char t;
|
||||
|
||||
index_i++;
|
||||
index_j += hash[index_i];
|
||||
|
||||
tc = hash[index_i];
|
||||
hash[index_i] = hash[index_j];
|
||||
hash[index_j] = tc;
|
||||
|
||||
t = hash[index_i] + hash[index_j];
|
||||
data[ind] = hash[t];
|
||||
}
|
||||
|
||||
hash[256] = index_i;
|
||||
hash[257] = index_j;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
Get a 16 byte hash from the contents of a file.
|
||||
|
||||
Note that the hash is initialised, because the extra entropy is not
|
||||
worth the valgrind pain.
|
||||
*****************************************************************/
|
||||
|
||||
static void do_filehash(const char *fname, unsigned char *the_hash)
|
||||
{
|
||||
unsigned char buf[1011]; /* deliberate weird size */
|
||||
unsigned char tmp_md4[16];
|
||||
int fd, n;
|
||||
|
||||
ZERO_STRUCT(tmp_md4);
|
||||
|
||||
fd = open(fname,O_RDONLY,0);
|
||||
if (fd == -1)
|
||||
return;
|
||||
|
||||
while ((n = read(fd, (char *)buf, sizeof(buf))) > 0) {
|
||||
mdfour(tmp_md4, buf, n);
|
||||
for (n=0;n<16;n++)
|
||||
the_hash[n] ^= tmp_md4[n];
|
||||
}
|
||||
close(fd);
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
Try and get a good random number seed. Try a number of
|
||||
different factors. Firstly, try /dev/urandom - use if exists.
|
||||
|
||||
We use /dev/urandom as a read of /dev/random can block if
|
||||
the entropy pool dries up. This leads clients to timeout
|
||||
or be very slow on connect.
|
||||
|
||||
If we can't use /dev/urandom then seed the stream random generator
|
||||
above...
|
||||
**************************************************************/
|
||||
|
||||
static int do_reseed(BOOL use_fd, int fd)
|
||||
{
|
||||
unsigned char seed_inbuf[40];
|
||||
uint32_t v1, v2; struct timeval tval; pid_t mypid;
|
||||
int reseed_data = 0;
|
||||
|
||||
if (use_fd) {
|
||||
if (fd != -1)
|
||||
return fd;
|
||||
|
||||
fd = open( "/dev/urandom", O_RDONLY,0);
|
||||
if(fd >= 0)
|
||||
return fd;
|
||||
}
|
||||
|
||||
/* Add in some secret file contents */
|
||||
|
||||
do_filehash("/etc/shadow", &seed_inbuf[0]);
|
||||
|
||||
/*
|
||||
* Add the counter, time of day, and pid.
|
||||
*/
|
||||
|
||||
GetTimeOfDay(&tval);
|
||||
mypid = getpid();
|
||||
v1 = (counter++) + mypid + tval.tv_sec;
|
||||
v2 = (counter++) * mypid + tval.tv_usec;
|
||||
|
||||
SIVAL(seed_inbuf, 32, v1 ^ IVAL(seed_inbuf, 32));
|
||||
SIVAL(seed_inbuf, 36, v2 ^ IVAL(seed_inbuf, 36));
|
||||
|
||||
/*
|
||||
* Add any user-given reseed data.
|
||||
*/
|
||||
|
||||
get_rand_reseed_data(&reseed_data);
|
||||
if (reseed_data) {
|
||||
size_t i;
|
||||
for (i = 0; i < sizeof(seed_inbuf); i++)
|
||||
seed_inbuf[i] ^= ((char *)(&reseed_data))[i % sizeof(reseed_data)];
|
||||
}
|
||||
|
||||
seed_random_stream(seed_inbuf, sizeof(seed_inbuf));
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
Interface to the (hopefully) good crypto random number generator.
|
||||
**/
|
||||
_PUBLIC_ void generate_random_buffer(uint8_t *out, int len)
|
||||
{
|
||||
static int urand_fd = -1;
|
||||
unsigned char md4_buf[64];
|
||||
unsigned char tmp_buf[16];
|
||||
unsigned char *p;
|
||||
|
||||
if(!done_reseed) {
|
||||
urand_fd = do_reseed(True, urand_fd);
|
||||
done_reseed = True;
|
||||
}
|
||||
|
||||
if (urand_fd != -1 && len > 0) {
|
||||
|
||||
if (read(urand_fd, out, len) == len)
|
||||
return; /* len bytes of random data read from urandom. */
|
||||
|
||||
/* Read of urand error, drop back to non urand method. */
|
||||
close(urand_fd);
|
||||
urand_fd = -1;
|
||||
do_reseed(False, -1);
|
||||
done_reseed = True;
|
||||
}
|
||||
|
||||
/*
|
||||
* Generate random numbers in chunks of 64 bytes,
|
||||
* then md4 them & copy to the output buffer.
|
||||
* This way the raw state of the stream is never externally
|
||||
* seen.
|
||||
*/
|
||||
|
||||
p = out;
|
||||
while(len > 0) {
|
||||
int copy_len = len > 16 ? 16 : len;
|
||||
|
||||
get_random_stream(md4_buf, sizeof(md4_buf));
|
||||
mdfour(tmp_buf, md4_buf, sizeof(md4_buf));
|
||||
memcpy(p, tmp_buf, copy_len);
|
||||
p += copy_len;
|
||||
len -= copy_len;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
generate a single random uint32_t
|
||||
**/
|
||||
_PUBLIC_ uint32_t generate_random(void)
|
||||
{
|
||||
uint8_t v[4];
|
||||
generate_random_buffer(v, 4);
|
||||
return IVAL(v, 0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
very basic password quality checker
|
||||
**/
|
||||
_PUBLIC_ BOOL check_password_quality(const char *s)
|
||||
{
|
||||
int has_digit=0, has_capital=0, has_lower=0;
|
||||
while (*s) {
|
||||
if (isdigit((unsigned char)*s)) {
|
||||
has_digit++;
|
||||
} else if (isupper((unsigned char)*s)) {
|
||||
has_capital++;
|
||||
} else if (islower((unsigned char)*s)) {
|
||||
has_lower++;
|
||||
}
|
||||
s++;
|
||||
}
|
||||
|
||||
return has_digit && has_lower && has_capital;
|
||||
}
|
||||
|
||||
/**
|
||||
Use the random number generator to generate a random string.
|
||||
**/
|
||||
|
||||
_PUBLIC_ char *generate_random_str_list(TALLOC_CTX *mem_ctx, size_t len, const char *list)
|
||||
{
|
||||
size_t i;
|
||||
size_t list_len = strlen(list);
|
||||
|
||||
char *retstr = talloc_array(mem_ctx, char, len + 1);
|
||||
if (!retstr) return NULL;
|
||||
|
||||
generate_random_buffer((uint8_t *)retstr, len);
|
||||
for (i = 0; i < len; i++) {
|
||||
retstr[i] = list[retstr[i] % list_len];
|
||||
}
|
||||
retstr[i] = '\0';
|
||||
|
||||
return retstr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a random text string consisting of the specified length.
|
||||
* The returned string will be allocated.
|
||||
*
|
||||
* Characters used are: ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,
|
||||
*/
|
||||
|
||||
_PUBLIC_ char *generate_random_str(TALLOC_CTX *mem_ctx, size_t len)
|
||||
{
|
||||
char *retstr;
|
||||
const char *c_list = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+_-#.,";
|
||||
|
||||
again:
|
||||
retstr = generate_random_str_list(mem_ctx, len, c_list);
|
||||
if (!retstr) return NULL;
|
||||
|
||||
/* we need to make sure the random string passes basic quality tests
|
||||
or it might be rejected by windows as a password */
|
||||
if (len >= 7 && !check_password_quality(retstr)) {
|
||||
talloc_free(retstr);
|
||||
goto again;
|
||||
}
|
||||
|
||||
return retstr;
|
||||
}
|
||||
@@ -0,0 +1,392 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
very efficient functions to manage mapping a id (such as a fnum) to
|
||||
a pointer. This is used for fnum and search id allocation.
|
||||
|
||||
Copyright (C) Andrew Tridgell 2004
|
||||
|
||||
This code is derived from lib/idr.c in the 2.6 Linux kernel, which was
|
||||
written by Jim Houston jim.houston@ccur.com, and is
|
||||
Copyright (C) 2002 by Concurrent Computer Corporation
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
see the section marked "public interface" below for documentation
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
#define IDR_BITS 5
|
||||
#define IDR_FULL 0xfffffffful
|
||||
#if 0 /* unused */
|
||||
#define TOP_LEVEL_FULL (IDR_FULL >> 30)
|
||||
#endif
|
||||
#define IDR_SIZE (1 << IDR_BITS)
|
||||
#define IDR_MASK ((1 << IDR_BITS)-1)
|
||||
#define MAX_ID_SHIFT (sizeof(int)*8 - 1)
|
||||
#define MAX_ID_BIT (1U << MAX_ID_SHIFT)
|
||||
#define MAX_ID_MASK (MAX_ID_BIT - 1)
|
||||
#define MAX_LEVEL (MAX_ID_SHIFT + IDR_BITS - 1) / IDR_BITS
|
||||
#define IDR_FREE_MAX MAX_LEVEL + MAX_LEVEL
|
||||
|
||||
#define set_bit(bit, v) (v) |= (1<<(bit))
|
||||
#define clear_bit(bit, v) (v) &= ~(1<<(bit))
|
||||
#define test_bit(bit, v) ((v) & (1<<(bit)))
|
||||
|
||||
struct idr_layer {
|
||||
uint32_t bitmap;
|
||||
struct idr_layer *ary[IDR_SIZE];
|
||||
int count;
|
||||
};
|
||||
|
||||
struct idr_context {
|
||||
struct idr_layer *top;
|
||||
struct idr_layer *id_free;
|
||||
int layers;
|
||||
int id_free_cnt;
|
||||
};
|
||||
|
||||
static struct idr_layer *alloc_layer(struct idr_context *idp)
|
||||
{
|
||||
struct idr_layer *p;
|
||||
|
||||
if (!(p = idp->id_free))
|
||||
return NULL;
|
||||
idp->id_free = p->ary[0];
|
||||
idp->id_free_cnt--;
|
||||
p->ary[0] = NULL;
|
||||
return p;
|
||||
}
|
||||
|
||||
static int find_next_bit(uint32_t bm, int maxid, int n)
|
||||
{
|
||||
while (n<maxid && !test_bit(n, bm)) n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
static void free_layer(struct idr_context *idp, struct idr_layer *p)
|
||||
{
|
||||
p->ary[0] = idp->id_free;
|
||||
idp->id_free = p;
|
||||
idp->id_free_cnt++;
|
||||
}
|
||||
|
||||
static int idr_pre_get(struct idr_context *idp)
|
||||
{
|
||||
while (idp->id_free_cnt < IDR_FREE_MAX) {
|
||||
struct idr_layer *new = talloc_zero(idp, struct idr_layer);
|
||||
if(new == NULL)
|
||||
return (0);
|
||||
free_layer(idp, new);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int sub_alloc(struct idr_context *idp, void *ptr, int *starting_id)
|
||||
{
|
||||
int n, m, sh;
|
||||
struct idr_layer *p, *new;
|
||||
struct idr_layer *pa[MAX_LEVEL];
|
||||
int l, id;
|
||||
uint32_t bm;
|
||||
|
||||
memset(pa, 0, sizeof(pa));
|
||||
|
||||
id = *starting_id;
|
||||
p = idp->top;
|
||||
l = idp->layers;
|
||||
pa[l--] = NULL;
|
||||
while (1) {
|
||||
/*
|
||||
* We run around this while until we reach the leaf node...
|
||||
*/
|
||||
n = (id >> (IDR_BITS*l)) & IDR_MASK;
|
||||
bm = ~p->bitmap;
|
||||
m = find_next_bit(bm, IDR_SIZE, n);
|
||||
if (m == IDR_SIZE) {
|
||||
/* no space available go back to previous layer. */
|
||||
l++;
|
||||
id = (id | ((1 << (IDR_BITS*l))-1)) + 1;
|
||||
if (!(p = pa[l])) {
|
||||
*starting_id = id;
|
||||
return -2;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (m != n) {
|
||||
sh = IDR_BITS*l;
|
||||
id = ((id >> sh) ^ n ^ m) << sh;
|
||||
}
|
||||
if ((id >= MAX_ID_BIT) || (id < 0))
|
||||
return -1;
|
||||
if (l == 0)
|
||||
break;
|
||||
/*
|
||||
* Create the layer below if it is missing.
|
||||
*/
|
||||
if (!p->ary[m]) {
|
||||
if (!(new = alloc_layer(idp)))
|
||||
return -1;
|
||||
p->ary[m] = new;
|
||||
p->count++;
|
||||
}
|
||||
pa[l--] = p;
|
||||
p = p->ary[m];
|
||||
}
|
||||
/*
|
||||
* We have reached the leaf node, plant the
|
||||
* users pointer and return the raw id.
|
||||
*/
|
||||
p->ary[m] = (struct idr_layer *)ptr;
|
||||
set_bit(m, p->bitmap);
|
||||
p->count++;
|
||||
/*
|
||||
* If this layer is full mark the bit in the layer above
|
||||
* to show that this part of the radix tree is full.
|
||||
* This may complete the layer above and require walking
|
||||
* up the radix tree.
|
||||
*/
|
||||
n = id;
|
||||
while (p->bitmap == IDR_FULL) {
|
||||
if (!(p = pa[++l]))
|
||||
break;
|
||||
n = n >> IDR_BITS;
|
||||
set_bit((n & IDR_MASK), p->bitmap);
|
||||
}
|
||||
return(id);
|
||||
}
|
||||
|
||||
static int idr_get_new_above_int(struct idr_context *idp, void *ptr, int starting_id)
|
||||
{
|
||||
struct idr_layer *p, *new;
|
||||
int layers, v, id;
|
||||
|
||||
idr_pre_get(idp);
|
||||
|
||||
id = starting_id;
|
||||
build_up:
|
||||
p = idp->top;
|
||||
layers = idp->layers;
|
||||
if (!p) {
|
||||
if (!(p = alloc_layer(idp)))
|
||||
return -1;
|
||||
layers = 1;
|
||||
}
|
||||
/*
|
||||
* Add a new layer to the top of the tree if the requested
|
||||
* id is larger than the currently allocated space.
|
||||
*/
|
||||
while ((layers < MAX_LEVEL) && (id >= (1 << (layers*IDR_BITS)))) {
|
||||
layers++;
|
||||
if (!p->count)
|
||||
continue;
|
||||
if (!(new = alloc_layer(idp))) {
|
||||
/*
|
||||
* The allocation failed. If we built part of
|
||||
* the structure tear it down.
|
||||
*/
|
||||
for (new = p; p && p != idp->top; new = p) {
|
||||
p = p->ary[0];
|
||||
new->ary[0] = NULL;
|
||||
new->bitmap = new->count = 0;
|
||||
free_layer(idp, new);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
new->ary[0] = p;
|
||||
new->count = 1;
|
||||
if (p->bitmap == IDR_FULL)
|
||||
set_bit(0, new->bitmap);
|
||||
p = new;
|
||||
}
|
||||
idp->top = p;
|
||||
idp->layers = layers;
|
||||
v = sub_alloc(idp, ptr, &id);
|
||||
if (v == -2)
|
||||
goto build_up;
|
||||
return(v);
|
||||
}
|
||||
|
||||
static int sub_remove(struct idr_context *idp, int shift, int id)
|
||||
{
|
||||
struct idr_layer *p = idp->top;
|
||||
struct idr_layer **pa[MAX_LEVEL];
|
||||
struct idr_layer ***paa = &pa[0];
|
||||
int n;
|
||||
|
||||
*paa = NULL;
|
||||
*++paa = &idp->top;
|
||||
|
||||
while ((shift > 0) && p) {
|
||||
n = (id >> shift) & IDR_MASK;
|
||||
clear_bit(n, p->bitmap);
|
||||
*++paa = &p->ary[n];
|
||||
p = p->ary[n];
|
||||
shift -= IDR_BITS;
|
||||
}
|
||||
n = id & IDR_MASK;
|
||||
if (p != NULL && test_bit(n, p->bitmap)) {
|
||||
clear_bit(n, p->bitmap);
|
||||
p->ary[n] = NULL;
|
||||
while(*paa && ! --((**paa)->count)){
|
||||
free_layer(idp, **paa);
|
||||
**paa-- = NULL;
|
||||
}
|
||||
if ( ! *paa )
|
||||
idp->layers = 0;
|
||||
return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void *_idr_find(struct idr_context *idp, int id)
|
||||
{
|
||||
int n;
|
||||
struct idr_layer *p;
|
||||
|
||||
n = idp->layers * IDR_BITS;
|
||||
p = idp->top;
|
||||
/*
|
||||
* This tests to see if bits outside the current tree are
|
||||
* present. If so, tain't one of ours!
|
||||
*/
|
||||
if ((id & ~(~0 << MAX_ID_SHIFT)) >> (n + IDR_BITS))
|
||||
return NULL;
|
||||
|
||||
/* Mask off upper bits we don't use for the search. */
|
||||
id &= MAX_ID_MASK;
|
||||
|
||||
while (n >= IDR_BITS && p) {
|
||||
n -= IDR_BITS;
|
||||
p = p->ary[(id >> n) & IDR_MASK];
|
||||
}
|
||||
return((void *)p);
|
||||
}
|
||||
|
||||
static int _idr_remove(struct idr_context *idp, int id)
|
||||
{
|
||||
struct idr_layer *p;
|
||||
|
||||
/* Mask off upper bits we don't use for the search. */
|
||||
id &= MAX_ID_MASK;
|
||||
|
||||
if (sub_remove(idp, (idp->layers - 1) * IDR_BITS, id) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ( idp->top && idp->top->count == 1 &&
|
||||
(idp->layers > 1) &&
|
||||
idp->top->ary[0]) {
|
||||
/* We can drop a layer */
|
||||
p = idp->top->ary[0];
|
||||
idp->top->bitmap = idp->top->count = 0;
|
||||
free_layer(idp, idp->top);
|
||||
idp->top = p;
|
||||
--idp->layers;
|
||||
}
|
||||
while (idp->id_free_cnt >= IDR_FREE_MAX) {
|
||||
p = alloc_layer(idp);
|
||||
talloc_free(p);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
this is the public interface
|
||||
**************************************************************************/
|
||||
|
||||
/**
|
||||
initialise a idr tree. The context return value must be passed to
|
||||
all subsequent idr calls. To destroy the idr tree use talloc_free()
|
||||
on this context
|
||||
*/
|
||||
_PUBLIC_ struct idr_context *idr_init(TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
return talloc_zero(mem_ctx, struct idr_context);
|
||||
}
|
||||
|
||||
/**
|
||||
allocate the next available id, and assign 'ptr' into its slot.
|
||||
you can retrieve later this pointer using idr_find()
|
||||
*/
|
||||
_PUBLIC_ int idr_get_new(struct idr_context *idp, void *ptr, int limit)
|
||||
{
|
||||
int ret = idr_get_new_above_int(idp, ptr, 0);
|
||||
if (ret > limit) {
|
||||
idr_remove(idp, ret);
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
allocate a new id, giving the first available value greater than or
|
||||
equal to the given starting id
|
||||
*/
|
||||
_PUBLIC_ int idr_get_new_above(struct idr_context *idp, void *ptr, int starting_id, int limit)
|
||||
{
|
||||
int ret = idr_get_new_above_int(idp, ptr, starting_id);
|
||||
if (ret > limit) {
|
||||
idr_remove(idp, ret);
|
||||
return -1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
allocate a new id randomly in the given range
|
||||
*/
|
||||
_PUBLIC_ int idr_get_new_random(struct idr_context *idp, void *ptr, int limit)
|
||||
{
|
||||
int id;
|
||||
|
||||
/* first try a random starting point in the whole range, and if that fails,
|
||||
then start randomly in the bottom half of the range. This can only
|
||||
fail if the range is over half full */
|
||||
id = idr_get_new_above(idp, ptr, 1+(generate_random() % limit), limit);
|
||||
if (id == -1) {
|
||||
id = idr_get_new_above(idp, ptr, 1+(generate_random()%(limit/2)), limit);
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
/**
|
||||
find a pointer value previously set with idr_get_new given an id
|
||||
*/
|
||||
_PUBLIC_ void *idr_find(struct idr_context *idp, int id)
|
||||
{
|
||||
return _idr_find(idp, id);
|
||||
}
|
||||
|
||||
/**
|
||||
remove an id from the idr tree
|
||||
*/
|
||||
_PUBLIC_ int idr_remove(struct idr_context *idp, int id)
|
||||
{
|
||||
int ret;
|
||||
ret = _idr_remove((struct idr_context *)idp, id);
|
||||
if (ret != 0) {
|
||||
DEBUG(0,("WARNING: attempt to remove unset id %d in idtree\n", id));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
|
||||
\mainpage util
|
||||
|
||||
\section Introduction
|
||||
|
||||
This library contains convenience functions that are used heavily
|
||||
throughout Samba. None of these functions are SMB or Samba-specific.
|
||||
It's a bit to Samba what GLib is to the GNOME folks.
|
||||
|
||||
*/
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Copyright (C) Jelmer Vernooij 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Module initialization function handling
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/dir.h"
|
||||
|
||||
/**
|
||||
* Obtain the init function from a shared library file
|
||||
*/
|
||||
_PUBLIC_ init_module_fn load_module(TALLOC_CTX *mem_ctx, const char *path)
|
||||
{
|
||||
void *handle;
|
||||
void *init_fn;
|
||||
|
||||
handle = dlopen(path, RTLD_NOW);
|
||||
if (handle == NULL) {
|
||||
DEBUG(0, ("Unable to open %s: %s\n", path, dlerror()));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
init_fn = dlsym(handle, "init_module");
|
||||
|
||||
if (init_fn == NULL) {
|
||||
DEBUG(0, ("Unable to find init_module() in %s: %s\n", path, dlerror()));
|
||||
DEBUG(1, ("Loading module '%s' failed\n", path));
|
||||
dlclose(handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (init_module_fn)init_fn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain list of init functions from the modules in the specified
|
||||
* directory
|
||||
*/
|
||||
_PUBLIC_ init_module_fn *load_modules(TALLOC_CTX *mem_ctx, const char *path)
|
||||
{
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
char *filename;
|
||||
int success = 0;
|
||||
init_module_fn *ret = talloc_array(mem_ctx, init_module_fn, 2);
|
||||
|
||||
ret[0] = NULL;
|
||||
|
||||
dir = opendir(path);
|
||||
if (dir == NULL) {
|
||||
talloc_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while((entry = readdir(dir))) {
|
||||
if (ISDOT(entry->d_name) || ISDOTDOT(entry->d_name))
|
||||
continue;
|
||||
|
||||
filename = talloc_asprintf(mem_ctx, "%s/%s", path, entry->d_name);
|
||||
|
||||
ret[success] = load_module(mem_ctx, filename);
|
||||
if (ret[success]) {
|
||||
ret = talloc_realloc(mem_ctx, ret, init_module_fn, success+2);
|
||||
success++;
|
||||
ret[success] = NULL;
|
||||
}
|
||||
|
||||
talloc_free(filename);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Run the specified init functions.
|
||||
*
|
||||
* @return True if all functions ran successfully, False otherwise
|
||||
*/
|
||||
_PUBLIC_ BOOL run_init_functions(NTSTATUS (**fns) (void))
|
||||
{
|
||||
int i;
|
||||
BOOL ret = True;
|
||||
|
||||
if (fns == NULL)
|
||||
return True;
|
||||
|
||||
for (i = 0; fns[i]; i++) { ret &= (BOOL)NT_STATUS_IS_OK(fns[i]()); }
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -0,0 +1,223 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
filename matching routine
|
||||
Copyright (C) Andrew Tridgell 1992-2004
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/*
|
||||
This module was originally based on fnmatch.c copyright by the Free
|
||||
Software Foundation. It bears little (if any) resemblence to that
|
||||
code now
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief MS-style Filename matching
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
static int null_match(const char *p)
|
||||
{
|
||||
for (;*p;p++) {
|
||||
if (*p != '*' &&
|
||||
*p != '<' &&
|
||||
*p != '"' &&
|
||||
*p != '>') return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
the max_n structure is purely for efficiency, it doesn't contribute
|
||||
to the matching algorithm except by ensuring that the algorithm does
|
||||
not grow exponentially
|
||||
*/
|
||||
struct max_n {
|
||||
const char *predot;
|
||||
const char *postdot;
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
p and n are the pattern and string being matched. The max_n array is
|
||||
an optimisation only. The ldot pointer is NULL if the string does
|
||||
not contain a '.', otherwise it points at the last dot in 'n'.
|
||||
*/
|
||||
static int ms_fnmatch_core(const char *p, const char *n,
|
||||
struct max_n *max_n, const char *ldot)
|
||||
{
|
||||
codepoint_t c, c2;
|
||||
int i;
|
||||
size_t size, size_n;
|
||||
|
||||
while ((c = next_codepoint(p, &size))) {
|
||||
p += size;
|
||||
|
||||
switch (c) {
|
||||
case '*':
|
||||
/* a '*' matches zero or more characters of any type */
|
||||
if (max_n->predot && max_n->predot <= n) {
|
||||
return null_match(p);
|
||||
}
|
||||
for (i=0; n[i]; i += size_n) {
|
||||
next_codepoint(n+i, &size_n);
|
||||
if (ms_fnmatch_core(p, n+i, max_n+1, ldot) == 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if (!max_n->predot || max_n->predot > n) max_n->predot = n;
|
||||
return null_match(p);
|
||||
|
||||
case '<':
|
||||
/* a '<' matches zero or more characters of
|
||||
any type, but stops matching at the last
|
||||
'.' in the string. */
|
||||
if (max_n->predot && max_n->predot <= n) {
|
||||
return null_match(p);
|
||||
}
|
||||
if (max_n->postdot && max_n->postdot <= n && n <= ldot) {
|
||||
return -1;
|
||||
}
|
||||
for (i=0; n[i]; i += size_n) {
|
||||
next_codepoint(n+i, &size_n);
|
||||
if (ms_fnmatch_core(p, n+i, max_n+1, ldot) == 0) return 0;
|
||||
if (n+i == ldot) {
|
||||
if (ms_fnmatch_core(p, n+i+size_n, max_n+1, ldot) == 0) return 0;
|
||||
if (!max_n->postdot || max_n->postdot > n) max_n->postdot = n;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if (!max_n->predot || max_n->predot > n) max_n->predot = n;
|
||||
return null_match(p);
|
||||
|
||||
case '?':
|
||||
/* a '?' matches any single character */
|
||||
if (! *n) {
|
||||
return -1;
|
||||
}
|
||||
next_codepoint(n, &size_n);
|
||||
n += size_n;
|
||||
break;
|
||||
|
||||
case '>':
|
||||
/* a '?' matches any single character, but
|
||||
treats '.' specially */
|
||||
if (n[0] == '.') {
|
||||
if (! n[1] && null_match(p) == 0) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (! *n) return null_match(p);
|
||||
next_codepoint(n, &size_n);
|
||||
n += size_n;
|
||||
break;
|
||||
|
||||
case '"':
|
||||
/* a bit like a soft '.' */
|
||||
if (*n == 0 && null_match(p) == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (*n != '.') return -1;
|
||||
next_codepoint(n, &size_n);
|
||||
n += size_n;
|
||||
break;
|
||||
|
||||
default:
|
||||
c2 = next_codepoint(n, &size_n);
|
||||
if (c != c2 && codepoint_cmpi(c, c2) != 0) {
|
||||
return -1;
|
||||
}
|
||||
n += size_n;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (! *n) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ms_fnmatch(const char *pattern, const char *string, enum protocol_types protocol)
|
||||
{
|
||||
int ret, count, i;
|
||||
struct max_n *max_n = NULL;
|
||||
|
||||
if (strcmp(string, "..") == 0) {
|
||||
string = ".";
|
||||
}
|
||||
|
||||
if (strpbrk(pattern, "<>*?\"") == NULL) {
|
||||
/* this is not just an optimisation - it is essential
|
||||
for LANMAN1 correctness */
|
||||
return strcasecmp_m(pattern, string);
|
||||
}
|
||||
|
||||
if (protocol <= PROTOCOL_LANMAN2) {
|
||||
char *p = talloc_strdup(NULL, pattern);
|
||||
if (p == NULL) {
|
||||
return -1;
|
||||
}
|
||||
/*
|
||||
for older negotiated protocols it is possible to
|
||||
translate the pattern to produce a "new style"
|
||||
pattern that exactly matches w2k behaviour
|
||||
*/
|
||||
for (i=0;p[i];i++) {
|
||||
if (p[i] == '?') {
|
||||
p[i] = '>';
|
||||
} else if (p[i] == '.' &&
|
||||
(p[i+1] == '?' ||
|
||||
p[i+1] == '*' ||
|
||||
p[i+1] == 0)) {
|
||||
p[i] = '"';
|
||||
} else if (p[i] == '*' &&
|
||||
p[i+1] == '.') {
|
||||
p[i] = '<';
|
||||
}
|
||||
}
|
||||
ret = ms_fnmatch(p, string, PROTOCOL_NT1);
|
||||
talloc_free(p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (count=i=0;pattern[i];i++) {
|
||||
if (pattern[i] == '*' || pattern[i] == '<') count++;
|
||||
}
|
||||
|
||||
max_n = talloc_array(NULL, struct max_n, count);
|
||||
if (!max_n) {
|
||||
return -1;
|
||||
}
|
||||
memset(max_n, 0, sizeof(struct max_n) * count);
|
||||
|
||||
ret = ms_fnmatch_core(pattern, string, max_n, strrchr(string, '.'));
|
||||
|
||||
talloc_free(max_n);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/** a generic fnmatch function - uses for non-CIFS pattern matching */
|
||||
int gen_fnmatch(const char *pattern, const char *string)
|
||||
{
|
||||
return ms_fnmatch(pattern, string, PROTOCOL_NT1);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Samba mutex/lock functions
|
||||
Copyright (C) Andrew Tridgell 2003
|
||||
Copyright (C) James J Myers 2003
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
#include "includes.h"
|
||||
#include "mutex.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Mutex utility functions
|
||||
*/
|
||||
|
||||
/* the registered mutex handlers */
|
||||
static struct {
|
||||
const char *name;
|
||||
struct mutex_ops ops;
|
||||
} mutex_handlers;
|
||||
|
||||
/* read/write lock routines */
|
||||
|
||||
|
||||
/**
|
||||
register a set of mutex/rwlock handlers.
|
||||
Should only be called once in the execution of smbd.
|
||||
*/
|
||||
_PUBLIC_ BOOL register_mutex_handlers(const char *name, struct mutex_ops *ops)
|
||||
{
|
||||
if (mutex_handlers.name != NULL) {
|
||||
/* it's already registered! */
|
||||
DEBUG(2,("mutex handler '%s' already registered - failed '%s'\n",
|
||||
mutex_handlers.name, name));
|
||||
return False;
|
||||
}
|
||||
|
||||
mutex_handlers.name = name;
|
||||
mutex_handlers.ops = *ops;
|
||||
|
||||
DEBUG(2,("mutex handler '%s' registered\n", name));
|
||||
return True;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
#ifndef _MUTEX_H_
|
||||
#define _MUTEX_H_
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Samba mutex functions
|
||||
Copyright (C) Andrew Tridgell 2003
|
||||
Copyright (C) James J Myers 2003
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Mutex operations
|
||||
*/
|
||||
|
||||
struct mutex_ops;
|
||||
|
||||
/* To add a new read/write lock, add it to enum rwlock_id
|
||||
*/
|
||||
enum rwlock_id { RWLOCK_SMBD, /* global smbd lock */
|
||||
|
||||
RWLOCK_MAX /* this MUST be kept last */
|
||||
};
|
||||
|
||||
#define MUTEX_LOCK_BY_ID(mutex_index) smb_mutex_lock_by_id(mutex_index, #mutex_index)
|
||||
#define MUTEX_UNLOCK_BY_ID(mutex_index) smb_mutex_unlock_by_id(mutex_index, #mutex_index)
|
||||
#define MUTEX_INIT(mutex, name) smb_mutex_init(mutex, #name)
|
||||
#define MUTEX_DESTROY(mutex, name) smb_mutex_destroy(mutex, #name)
|
||||
#define MUTEX_LOCK(mutex, name) smb_mutex_lock(mutex, #name)
|
||||
#define MUTEX_UNLOCK(mutex, name) smb_mutex_unlock(mutex, #name)
|
||||
|
||||
#define RWLOCK_INIT(rwlock, name) smb_rwlock_init(rwlock, #name)
|
||||
#define RWLOCK_DESTROY(rwlock, name) smb_rwlock_destroy(rwlock, #name)
|
||||
#define RWLOCK_LOCK_WRITE(rwlock, name) smb_rwlock_lock_write(rwlock, #name)
|
||||
#define RWLOCK_LOCK_READ(rwlock, name) smb_rwlock_lock_read(rwlock, #name)
|
||||
#define RWLOCK_UNLOCK(rwlock, name) smb_rwlock_unlock(rwlock, #name)
|
||||
|
||||
|
||||
|
||||
/* this null typedef ensures we get the types right and avoids the
|
||||
pitfalls of void* */
|
||||
typedef struct smb_mutex {
|
||||
void *mutex;
|
||||
} smb_mutex_t;
|
||||
typedef struct {
|
||||
void *rwlock;
|
||||
} smb_rwlock_t;
|
||||
|
||||
/* the mutex model operations structure - contains function pointers to
|
||||
the model-specific implementations of each operation */
|
||||
struct mutex_ops {
|
||||
int (*mutex_init)(smb_mutex_t *mutex, const char *name);
|
||||
int (*mutex_lock)(smb_mutex_t *mutex, const char *name);
|
||||
int (*mutex_unlock)(smb_mutex_t *mutex, const char *name);
|
||||
int (*mutex_destroy)(smb_mutex_t *mutex, const char *name);
|
||||
int (*rwlock_init)(smb_rwlock_t *rwlock, const char *name);
|
||||
int (*rwlock_lock_write)(smb_rwlock_t *rwlock, const char *name);
|
||||
int (*rwlock_lock_read)(smb_rwlock_t *rwlock, const char *name);
|
||||
int (*rwlock_unlock)(smb_rwlock_t *rwlock, const char *name);
|
||||
int (*rwlock_destroy)(smb_rwlock_t *rwlock, const char *name);
|
||||
};
|
||||
|
||||
#endif /* endif _MUTEX_H_ */
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Safe string handling routines.
|
||||
Copyright (C) Andrew Tridgell 1994-1998
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _SAFE_STRING_H
|
||||
#define _SAFE_STRING_H
|
||||
|
||||
#ifndef _SPLINT_ /* http://www.splint.org */
|
||||
/* Some macros to ensure people don't use buffer overflow vulnerable string
|
||||
functions. */
|
||||
|
||||
#ifdef strcpy
|
||||
#undef strcpy
|
||||
#endif /* strcpy */
|
||||
#define strcpy(dest,src) __ERROR__XX__NEVER_USE_STRCPY___;
|
||||
|
||||
#ifdef strcat
|
||||
#undef strcat
|
||||
#endif /* strcat */
|
||||
#define strcat(dest,src) __ERROR__XX__NEVER_USE_STRCAT___;
|
||||
|
||||
#ifdef sprintf
|
||||
#undef sprintf
|
||||
#endif /* sprintf */
|
||||
#define sprintf __ERROR__XX__NEVER_USE_SPRINTF__;
|
||||
|
||||
#endif /* !_SPLINT_ */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
signal handling functions
|
||||
|
||||
Copyright (C) Andrew Tridgell 1998
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/wait.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Signal handling
|
||||
*/
|
||||
|
||||
/****************************************************************************
|
||||
Catch child exits and reap the child zombie status.
|
||||
****************************************************************************/
|
||||
|
||||
static void sig_cld(int signum)
|
||||
{
|
||||
while (waitpid((pid_t)-1,(int *)NULL, WNOHANG) > 0)
|
||||
;
|
||||
|
||||
/*
|
||||
* Turns out it's *really* important not to
|
||||
* restore the signal handler here if we have real POSIX
|
||||
* signal handling. If we do, then we get the signal re-delivered
|
||||
* immediately - hey presto - instant loop ! JRA.
|
||||
*/
|
||||
|
||||
#if !defined(HAVE_SIGACTION)
|
||||
CatchSignal(SIGCLD, sig_cld);
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
catch child exits - leave status;
|
||||
****************************************************************************/
|
||||
|
||||
static void sig_cld_leave_status(int signum)
|
||||
{
|
||||
/*
|
||||
* Turns out it's *really* important not to
|
||||
* restore the signal handler here if we have real POSIX
|
||||
* signal handling. If we do, then we get the signal re-delivered
|
||||
* immediately - hey presto - instant loop ! JRA.
|
||||
*/
|
||||
|
||||
#if !defined(HAVE_SIGACTION)
|
||||
CatchSignal(SIGCLD, sig_cld_leave_status);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
Block sigs.
|
||||
**/
|
||||
|
||||
void BlockSignals(BOOL block,int signum)
|
||||
{
|
||||
#ifdef HAVE_SIGPROCMASK
|
||||
sigset_t set;
|
||||
sigemptyset(&set);
|
||||
sigaddset(&set,signum);
|
||||
sigprocmask(block?SIG_BLOCK:SIG_UNBLOCK,&set,NULL);
|
||||
#elif defined(HAVE_SIGBLOCK)
|
||||
if (block) {
|
||||
sigblock(sigmask(signum));
|
||||
} else {
|
||||
sigsetmask(siggetmask() & ~sigmask(signum));
|
||||
}
|
||||
#else
|
||||
/* yikes! This platform can't block signals? */
|
||||
static int done;
|
||||
if (!done) {
|
||||
DEBUG(0,("WARNING: No signal blocking available\n"));
|
||||
done=1;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
Catch a signal. This should implement the following semantics:
|
||||
|
||||
1) The handler remains installed after being called.
|
||||
2) The signal should be blocked during handler execution.
|
||||
**/
|
||||
|
||||
void (*CatchSignal(int signum,void (*handler)(int )))(int)
|
||||
{
|
||||
#ifdef HAVE_SIGACTION
|
||||
struct sigaction act;
|
||||
struct sigaction oldact;
|
||||
|
||||
ZERO_STRUCT(act);
|
||||
|
||||
act.sa_handler = handler;
|
||||
#ifdef SA_RESTART
|
||||
/*
|
||||
* We *want* SIGALRM to interrupt a system call.
|
||||
*/
|
||||
if(signum != SIGALRM)
|
||||
act.sa_flags = SA_RESTART;
|
||||
#endif
|
||||
sigemptyset(&act.sa_mask);
|
||||
sigaddset(&act.sa_mask,signum);
|
||||
sigaction(signum,&act,&oldact);
|
||||
return oldact.sa_handler;
|
||||
#else /* !HAVE_SIGACTION */
|
||||
/* FIXME: need to handle sigvec and systems with broken signal() */
|
||||
return signal(signum, handler);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
Ignore SIGCLD via whatever means is necessary for this OS.
|
||||
**/
|
||||
|
||||
void CatchChild(void)
|
||||
{
|
||||
CatchSignal(SIGCLD, sig_cld);
|
||||
}
|
||||
|
||||
/**
|
||||
Catch SIGCLD but leave the child around so it's status can be reaped.
|
||||
**/
|
||||
|
||||
void CatchChildLeaveStatus(void)
|
||||
{
|
||||
CatchSignal(SIGCLD, sig_cld_leave_status);
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
AC_CHECK_FUNCS(sigprocmask sigblock sigaction)
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Samba system utilities
|
||||
Copyright (C) Andrew Tridgell 1992-1998
|
||||
Copyright (C) Jeremy Allison 1998-2002
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/network.h"
|
||||
#include "system/filesys.h"
|
||||
|
||||
/*
|
||||
The idea is that this file will eventually have wrappers around all
|
||||
important system calls in samba. The aims are:
|
||||
|
||||
- to enable easier porting by putting OS dependent stuff in here
|
||||
|
||||
- to allow for hooks into other "pseudo-filesystems"
|
||||
|
||||
- to allow easier integration of things like the japanese extensions
|
||||
|
||||
- to support the philosophy of Samba to expose the features of
|
||||
the OS within the SMB model. In general whatever file/printer/variable
|
||||
expansions/etc make sense to the OS should be acceptable to Samba.
|
||||
*/
|
||||
|
||||
/**************************************************************************
|
||||
A wrapper for gethostbyname() that tries avoids looking up hostnames
|
||||
in the root domain, which can cause dial-on-demand links to come up for no
|
||||
apparent reason.
|
||||
****************************************************************************/
|
||||
|
||||
_PUBLIC_ struct hostent *sys_gethostbyname(const char *name)
|
||||
{
|
||||
#ifdef REDUCE_ROOT_DNS_LOOKUPS
|
||||
char query[256], hostname[256];
|
||||
char *domain;
|
||||
|
||||
/* Does this name have any dots in it? If so, make no change */
|
||||
|
||||
if (strchr(name, '.'))
|
||||
return(gethostbyname(name));
|
||||
|
||||
/* Get my hostname, which should have domain name
|
||||
attached. If not, just do the gethostname on the
|
||||
original string.
|
||||
*/
|
||||
|
||||
gethostname(hostname, sizeof(hostname) - 1);
|
||||
hostname[sizeof(hostname) - 1] = 0;
|
||||
if ((domain = strchr(hostname, '.')) == NULL)
|
||||
return(gethostbyname(name));
|
||||
|
||||
/* Attach domain name to query and do modified query.
|
||||
If names too large, just do gethostname on the
|
||||
original string.
|
||||
*/
|
||||
|
||||
if((strlen(name) + strlen(domain)) >= sizeof(query))
|
||||
return(gethostbyname(name));
|
||||
|
||||
slprintf(query, sizeof(query)-1, "%s%s", name, domain);
|
||||
return(gethostbyname(query));
|
||||
#else /* REDUCE_ROOT_DNS_LOOKUPS */
|
||||
return(gethostbyname(name));
|
||||
#endif /* REDUCE_ROOT_DNS_LOOKUPS */
|
||||
}
|
||||
|
||||
_PUBLIC_ const char *sys_inet_ntoa(struct ipv4_addr in)
|
||||
{
|
||||
struct in_addr in2;
|
||||
in2.s_addr = in.addr;
|
||||
return inet_ntoa(in2);
|
||||
}
|
||||
|
||||
_PUBLIC_ struct ipv4_addr sys_inet_makeaddr(int net, int host)
|
||||
{
|
||||
struct in_addr in;
|
||||
struct ipv4_addr in2;
|
||||
in = inet_makeaddr(net, host);
|
||||
in2.addr = in.s_addr;
|
||||
return in2;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,623 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
time handling functions
|
||||
|
||||
Copyright (C) Andrew Tridgell 1992-2004
|
||||
Copyright (C) Stefan (metze) Metzmacher 2002
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/time.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief time handling functions
|
||||
*/
|
||||
|
||||
#ifndef TIME_T_MIN
|
||||
/* we use 0 here, because (time_t)-1 means error */
|
||||
#define TIME_T_MIN 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* we use the INT32_MAX here as on 64 bit systems,
|
||||
* gmtime() fails with INT64_MAX
|
||||
*/
|
||||
|
||||
#ifndef TIME_T_MAX
|
||||
#define TIME_T_MAX MIN(INT32_MAX,_TYPE_MAXIMUM(time_t))
|
||||
#endif
|
||||
|
||||
/**
|
||||
External access to time_t_min and time_t_max.
|
||||
**/
|
||||
_PUBLIC_ time_t get_time_t_max(void)
|
||||
{
|
||||
return TIME_T_MAX;
|
||||
}
|
||||
|
||||
/**
|
||||
a gettimeofday wrapper
|
||||
**/
|
||||
_PUBLIC_ void GetTimeOfDay(struct timeval *tval)
|
||||
{
|
||||
#ifdef HAVE_GETTIMEOFDAY_TZ
|
||||
gettimeofday(tval,NULL);
|
||||
#else
|
||||
gettimeofday(tval);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#define TIME_FIXUP_CONSTANT 11644473600LL
|
||||
|
||||
/**
|
||||
interpret an 8 byte "filetime" structure to a time_t
|
||||
It's originally in "100ns units since jan 1st 1601"
|
||||
**/
|
||||
_PUBLIC_ time_t nt_time_to_unix(NTTIME nt)
|
||||
{
|
||||
if (nt == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (nt == -1LL) {
|
||||
return (time_t)-1;
|
||||
}
|
||||
nt += 1000*1000*10/2;
|
||||
nt /= 1000*1000*10;
|
||||
nt -= TIME_FIXUP_CONSTANT;
|
||||
|
||||
if (TIME_T_MIN > nt || nt > TIME_T_MAX) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (time_t)nt;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
put a 8 byte filetime from a time_t
|
||||
This takes GMT as input
|
||||
**/
|
||||
_PUBLIC_ void unix_to_nt_time(NTTIME *nt, time_t t)
|
||||
{
|
||||
uint64_t t2;
|
||||
|
||||
if (t == (time_t)-1) {
|
||||
*nt = (NTTIME)-1LL;
|
||||
return;
|
||||
}
|
||||
if (t == 0) {
|
||||
*nt = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
t2 = t;
|
||||
t2 += TIME_FIXUP_CONSTANT;
|
||||
t2 *= 1000*1000*10;
|
||||
|
||||
*nt = t2;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
check if it's a null unix time
|
||||
**/
|
||||
_PUBLIC_ BOOL null_time(time_t t)
|
||||
{
|
||||
return t == 0 ||
|
||||
t == (time_t)0xFFFFFFFF ||
|
||||
t == (time_t)-1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
check if it's a null NTTIME
|
||||
**/
|
||||
_PUBLIC_ BOOL null_nttime(NTTIME t)
|
||||
{
|
||||
return t == 0 || t == (NTTIME)-1;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
create a 16 bit dos packed date
|
||||
********************************************************************/
|
||||
static uint16_t make_dos_date1(struct tm *t)
|
||||
{
|
||||
uint16_t ret=0;
|
||||
ret = (((unsigned int)(t->tm_mon+1)) >> 3) | ((t->tm_year-80) << 1);
|
||||
ret = ((ret&0xFF)<<8) | (t->tm_mday | (((t->tm_mon+1) & 0x7) << 5));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
create a 16 bit dos packed time
|
||||
********************************************************************/
|
||||
static uint16_t make_dos_time1(struct tm *t)
|
||||
{
|
||||
uint16_t ret=0;
|
||||
ret = ((((unsigned int)t->tm_min >> 3)&0x7) | (((unsigned int)t->tm_hour) << 3));
|
||||
ret = ((ret&0xFF)<<8) | ((t->tm_sec/2) | ((t->tm_min & 0x7) << 5));
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
create a 32 bit dos packed date/time from some parameters
|
||||
This takes a GMT time and returns a packed localtime structure
|
||||
********************************************************************/
|
||||
static uint32_t make_dos_date(time_t unixdate, int zone_offset)
|
||||
{
|
||||
struct tm *t;
|
||||
uint32_t ret=0;
|
||||
|
||||
if (unixdate == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unixdate -= zone_offset;
|
||||
|
||||
t = gmtime(&unixdate);
|
||||
if (!t) {
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
ret = make_dos_date1(t);
|
||||
ret = ((ret&0xFFFF)<<16) | make_dos_time1(t);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
put a dos date into a buffer (time/date format)
|
||||
This takes GMT time and puts local time in the buffer
|
||||
**/
|
||||
_PUBLIC_ void push_dos_date(uint8_t *buf, int offset, time_t unixdate, int zone_offset)
|
||||
{
|
||||
uint32_t x = make_dos_date(unixdate, zone_offset);
|
||||
SIVAL(buf,offset,x);
|
||||
}
|
||||
|
||||
/**
|
||||
put a dos date into a buffer (date/time format)
|
||||
This takes GMT time and puts local time in the buffer
|
||||
**/
|
||||
_PUBLIC_ void push_dos_date2(uint8_t *buf,int offset,time_t unixdate, int zone_offset)
|
||||
{
|
||||
uint32_t x;
|
||||
x = make_dos_date(unixdate, zone_offset);
|
||||
x = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
|
||||
SIVAL(buf,offset,x);
|
||||
}
|
||||
|
||||
/**
|
||||
put a dos 32 bit "unix like" date into a buffer. This routine takes
|
||||
GMT and converts it to LOCAL time before putting it (most SMBs assume
|
||||
localtime for this sort of date)
|
||||
**/
|
||||
_PUBLIC_ void push_dos_date3(uint8_t *buf,int offset,time_t unixdate, int zone_offset)
|
||||
{
|
||||
if (!null_time(unixdate)) {
|
||||
unixdate -= zone_offset;
|
||||
}
|
||||
SIVAL(buf,offset,unixdate);
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
interpret a 32 bit dos packed date/time to some parameters
|
||||
********************************************************************/
|
||||
static void interpret_dos_date(uint32_t date,int *year,int *month,int *day,int *hour,int *minute,int *second)
|
||||
{
|
||||
uint32_t p0,p1,p2,p3;
|
||||
|
||||
p0=date&0xFF; p1=((date&0xFF00)>>8)&0xFF;
|
||||
p2=((date&0xFF0000)>>16)&0xFF; p3=((date&0xFF000000)>>24)&0xFF;
|
||||
|
||||
*second = 2*(p0 & 0x1F);
|
||||
*minute = ((p0>>5)&0xFF) + ((p1&0x7)<<3);
|
||||
*hour = (p1>>3)&0xFF;
|
||||
*day = (p2&0x1F);
|
||||
*month = ((p2>>5)&0xFF) + ((p3&0x1)<<3) - 1;
|
||||
*year = ((p3>>1)&0xFF) + 80;
|
||||
}
|
||||
|
||||
/**
|
||||
create a unix date (int GMT) from a dos date (which is actually in
|
||||
localtime)
|
||||
**/
|
||||
_PUBLIC_ time_t pull_dos_date(const uint8_t *date_ptr, int zone_offset)
|
||||
{
|
||||
uint32_t dos_date=0;
|
||||
struct tm t;
|
||||
time_t ret;
|
||||
|
||||
dos_date = IVAL(date_ptr,0);
|
||||
|
||||
if (dos_date == 0) return (time_t)0;
|
||||
|
||||
interpret_dos_date(dos_date,&t.tm_year,&t.tm_mon,
|
||||
&t.tm_mday,&t.tm_hour,&t.tm_min,&t.tm_sec);
|
||||
t.tm_isdst = -1;
|
||||
|
||||
ret = timegm(&t);
|
||||
|
||||
ret += zone_offset;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
like make_unix_date() but the words are reversed
|
||||
**/
|
||||
_PUBLIC_ time_t pull_dos_date2(const uint8_t *date_ptr, int zone_offset)
|
||||
{
|
||||
uint32_t x,x2;
|
||||
|
||||
x = IVAL(date_ptr,0);
|
||||
x2 = ((x&0xFFFF)<<16) | ((x&0xFFFF0000)>>16);
|
||||
SIVAL(&x,0,x2);
|
||||
|
||||
return pull_dos_date((void *)&x, zone_offset);
|
||||
}
|
||||
|
||||
/**
|
||||
create a unix GMT date from a dos date in 32 bit "unix like" format
|
||||
these generally arrive as localtimes, with corresponding DST
|
||||
**/
|
||||
_PUBLIC_ time_t pull_dos_date3(const uint8_t *date_ptr, int zone_offset)
|
||||
{
|
||||
time_t t = (time_t)IVAL(date_ptr,0);
|
||||
if (!null_time(t)) {
|
||||
t += zone_offset;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
return a HTTP/1.0 time string
|
||||
**/
|
||||
_PUBLIC_ char *http_timestring(TALLOC_CTX *mem_ctx, time_t t)
|
||||
{
|
||||
char *buf;
|
||||
char tempTime[60];
|
||||
struct tm *tm = localtime(&t);
|
||||
|
||||
if (!tm) {
|
||||
return talloc_asprintf(mem_ctx,"%ld seconds since the Epoch",(long)t);
|
||||
}
|
||||
|
||||
#ifndef HAVE_STRFTIME
|
||||
buf = talloc_strdup(mem_ctx, asctime(tm));
|
||||
if (buf[strlen(buf)-1] == '\n') {
|
||||
buf[strlen(buf)-1] = 0;
|
||||
}
|
||||
#else
|
||||
strftime(tempTime, sizeof(tempTime)-1, "%a, %d %b %Y %H:%M:%S %Z", tm);
|
||||
buf = talloc_strdup(mem_ctx, tempTime);
|
||||
#endif /* !HAVE_STRFTIME */
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
Return the date and time as a string
|
||||
**/
|
||||
_PUBLIC_ char *timestring(TALLOC_CTX *mem_ctx, time_t t)
|
||||
{
|
||||
char *TimeBuf;
|
||||
char tempTime[80];
|
||||
struct tm *tm;
|
||||
|
||||
tm = localtime(&t);
|
||||
if (!tm) {
|
||||
return talloc_asprintf(mem_ctx,
|
||||
"%ld seconds since the Epoch",
|
||||
(long)t);
|
||||
}
|
||||
|
||||
#ifdef HAVE_STRFTIME
|
||||
/* some versions of gcc complain about using %c. This is a bug
|
||||
in the gcc warning, not a bug in this code. See a recent
|
||||
strftime() manual page for details.
|
||||
*/
|
||||
strftime(tempTime,sizeof(tempTime)-1,"%c %Z",tm);
|
||||
TimeBuf = talloc_strdup(mem_ctx, tempTime);
|
||||
#else
|
||||
TimeBuf = talloc_strdup(mem_ctx, asctime(tm));
|
||||
#endif
|
||||
|
||||
return TimeBuf;
|
||||
}
|
||||
|
||||
/**
|
||||
return a talloced string representing a NTTIME for human consumption
|
||||
*/
|
||||
_PUBLIC_ const char *nt_time_string(TALLOC_CTX *mem_ctx, NTTIME nt)
|
||||
{
|
||||
time_t t;
|
||||
if (nt == 0) {
|
||||
return "NTTIME(0)";
|
||||
}
|
||||
t = nt_time_to_unix(nt);
|
||||
return timestring(mem_ctx, t);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
put a NTTIME into a packet
|
||||
*/
|
||||
_PUBLIC_ void push_nttime(uint8_t *base, uint16_t offset, NTTIME t)
|
||||
{
|
||||
SBVAL(base, offset, t);
|
||||
}
|
||||
|
||||
/**
|
||||
pull a NTTIME from a packet
|
||||
*/
|
||||
_PUBLIC_ NTTIME pull_nttime(uint8_t *base, uint16_t offset)
|
||||
{
|
||||
NTTIME ret = BVAL(base, offset);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
parse a nttime as a large integer in a string and return a NTTIME
|
||||
*/
|
||||
_PUBLIC_ NTTIME nttime_from_string(const char *s)
|
||||
{
|
||||
return strtoull(s, NULL, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
return (tv1 - tv2) in microseconds
|
||||
*/
|
||||
_PUBLIC_ int64_t usec_time_diff(struct timeval *tv1, struct timeval *tv2)
|
||||
{
|
||||
int64_t sec_diff = tv1->tv_sec - tv2->tv_sec;
|
||||
return (sec_diff * 1000000) + (int64_t)(tv1->tv_usec - tv2->tv_usec);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
return a zero timeval
|
||||
*/
|
||||
_PUBLIC_ struct timeval timeval_zero(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 0;
|
||||
return tv;
|
||||
}
|
||||
|
||||
/**
|
||||
return True if a timeval is zero
|
||||
*/
|
||||
_PUBLIC_ BOOL timeval_is_zero(const struct timeval *tv)
|
||||
{
|
||||
return tv->tv_sec == 0 && tv->tv_usec == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
return a timeval for the current time
|
||||
*/
|
||||
_PUBLIC_ struct timeval timeval_current(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
GetTimeOfDay(&tv);
|
||||
return tv;
|
||||
}
|
||||
|
||||
/**
|
||||
return a timeval struct with the given elements
|
||||
*/
|
||||
_PUBLIC_ struct timeval timeval_set(uint32_t secs, uint32_t usecs)
|
||||
{
|
||||
struct timeval tv;
|
||||
tv.tv_sec = secs;
|
||||
tv.tv_usec = usecs;
|
||||
return tv;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
return a timeval ofs microseconds after tv
|
||||
*/
|
||||
_PUBLIC_ struct timeval timeval_add(const struct timeval *tv,
|
||||
uint32_t secs, uint32_t usecs)
|
||||
{
|
||||
struct timeval tv2 = *tv;
|
||||
const unsigned int million = 1000000;
|
||||
tv2.tv_sec += secs;
|
||||
tv2.tv_usec += usecs;
|
||||
tv2.tv_sec += tv2.tv_usec / million;
|
||||
tv2.tv_usec = tv2.tv_usec % million;
|
||||
return tv2;
|
||||
}
|
||||
|
||||
/**
|
||||
return the sum of two timeval structures
|
||||
*/
|
||||
struct timeval timeval_sum(const struct timeval *tv1,
|
||||
const struct timeval *tv2)
|
||||
{
|
||||
return timeval_add(tv1, tv2->tv_sec, tv2->tv_usec);
|
||||
}
|
||||
|
||||
/**
|
||||
return a timeval secs/usecs into the future
|
||||
*/
|
||||
_PUBLIC_ struct timeval timeval_current_ofs(uint32_t secs, uint32_t usecs)
|
||||
{
|
||||
struct timeval tv = timeval_current();
|
||||
return timeval_add(&tv, secs, usecs);
|
||||
}
|
||||
|
||||
/**
|
||||
compare two timeval structures.
|
||||
Return -1 if tv1 < tv2
|
||||
Return 0 if tv1 == tv2
|
||||
Return 1 if tv1 > tv2
|
||||
*/
|
||||
_PUBLIC_ int timeval_compare(const struct timeval *tv1, const struct timeval *tv2)
|
||||
{
|
||||
if (tv1->tv_sec > tv2->tv_sec) return 1;
|
||||
if (tv1->tv_sec < tv2->tv_sec) return -1;
|
||||
if (tv1->tv_usec > tv2->tv_usec) return 1;
|
||||
if (tv1->tv_usec < tv2->tv_usec) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
return True if a timer is in the past
|
||||
*/
|
||||
_PUBLIC_ BOOL timeval_expired(const struct timeval *tv)
|
||||
{
|
||||
struct timeval tv2 = timeval_current();
|
||||
if (tv2.tv_sec > tv->tv_sec) return True;
|
||||
if (tv2.tv_sec < tv->tv_sec) return False;
|
||||
return (tv2.tv_usec >= tv->tv_usec);
|
||||
}
|
||||
|
||||
/**
|
||||
return the number of seconds elapsed between two times
|
||||
*/
|
||||
_PUBLIC_ double timeval_elapsed2(const struct timeval *tv1, const struct timeval *tv2)
|
||||
{
|
||||
return (tv2->tv_sec - tv1->tv_sec) +
|
||||
(tv2->tv_usec - tv1->tv_usec)*1.0e-6;
|
||||
}
|
||||
|
||||
/**
|
||||
return the number of seconds elapsed since a given time
|
||||
*/
|
||||
_PUBLIC_ double timeval_elapsed(const struct timeval *tv)
|
||||
{
|
||||
struct timeval tv2 = timeval_current();
|
||||
return timeval_elapsed2(tv, &tv2);
|
||||
}
|
||||
|
||||
/**
|
||||
return the lesser of two timevals
|
||||
*/
|
||||
_PUBLIC_ struct timeval timeval_min(const struct timeval *tv1,
|
||||
const struct timeval *tv2)
|
||||
{
|
||||
if (tv1->tv_sec < tv2->tv_sec) return *tv1;
|
||||
if (tv1->tv_sec > tv2->tv_sec) return *tv2;
|
||||
if (tv1->tv_usec < tv2->tv_usec) return *tv1;
|
||||
return *tv2;
|
||||
}
|
||||
|
||||
/**
|
||||
return the greater of two timevals
|
||||
*/
|
||||
_PUBLIC_ struct timeval timeval_max(const struct timeval *tv1,
|
||||
const struct timeval *tv2)
|
||||
{
|
||||
if (tv1->tv_sec > tv2->tv_sec) return *tv1;
|
||||
if (tv1->tv_sec < tv2->tv_sec) return *tv2;
|
||||
if (tv1->tv_usec > tv2->tv_usec) return *tv1;
|
||||
return *tv2;
|
||||
}
|
||||
|
||||
/**
|
||||
return the difference between two timevals as a timeval
|
||||
if tv1 comes after tv2, then return a zero timeval
|
||||
(this is *tv2 - *tv1)
|
||||
*/
|
||||
_PUBLIC_ struct timeval timeval_until(const struct timeval *tv1,
|
||||
const struct timeval *tv2)
|
||||
{
|
||||
struct timeval t;
|
||||
if (timeval_compare(tv1, tv2) >= 0) {
|
||||
return timeval_zero();
|
||||
}
|
||||
t.tv_sec = tv2->tv_sec - tv1->tv_sec;
|
||||
if (tv1->tv_usec > tv2->tv_usec) {
|
||||
t.tv_sec--;
|
||||
t.tv_usec = 1000000 - (tv1->tv_usec - tv2->tv_usec);
|
||||
} else {
|
||||
t.tv_usec = tv2->tv_usec - tv1->tv_usec;
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
convert a timeval to a NTTIME
|
||||
*/
|
||||
_PUBLIC_ NTTIME timeval_to_nttime(const struct timeval *tv)
|
||||
{
|
||||
return 10*(tv->tv_usec +
|
||||
((TIME_FIXUP_CONSTANT + (uint64_t)tv->tv_sec) * 1000000));
|
||||
}
|
||||
|
||||
/**
|
||||
convert a NTTIME to a timeval
|
||||
*/
|
||||
_PUBLIC_ void nttime_to_timeval(struct timeval *tv, NTTIME t)
|
||||
{
|
||||
if (tv == NULL) return;
|
||||
|
||||
t += 10/2;
|
||||
t /= 10;
|
||||
t -= TIME_FIXUP_CONSTANT*1000*1000;
|
||||
|
||||
tv->tv_sec = t / 1000000;
|
||||
|
||||
if (TIME_T_MIN > tv->tv_sec || tv->tv_sec > TIME_T_MAX) {
|
||||
tv->tv_sec = 0;
|
||||
tv->tv_usec = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
tv->tv_usec = t - tv->tv_sec*1000000;
|
||||
}
|
||||
|
||||
/*******************************************************************
|
||||
yield the difference between *A and *B, in seconds, ignoring leap seconds
|
||||
********************************************************************/
|
||||
static int tm_diff(struct tm *a, struct tm *b)
|
||||
{
|
||||
int ay = a->tm_year + (1900 - 1);
|
||||
int by = b->tm_year + (1900 - 1);
|
||||
int intervening_leap_days =
|
||||
(ay/4 - by/4) - (ay/100 - by/100) + (ay/400 - by/400);
|
||||
int years = ay - by;
|
||||
int days = 365*years + intervening_leap_days + (a->tm_yday - b->tm_yday);
|
||||
int hours = 24*days + (a->tm_hour - b->tm_hour);
|
||||
int minutes = 60*hours + (a->tm_min - b->tm_min);
|
||||
int seconds = 60*minutes + (a->tm_sec - b->tm_sec);
|
||||
|
||||
return seconds;
|
||||
}
|
||||
|
||||
/**
|
||||
return the UTC offset in seconds west of UTC, or 0 if it cannot be determined
|
||||
*/
|
||||
_PUBLIC_ int get_time_zone(time_t t)
|
||||
{
|
||||
struct tm *tm = gmtime(&t);
|
||||
struct tm tm_utc;
|
||||
if (!tm)
|
||||
return 0;
|
||||
tm_utc = *tm;
|
||||
tm = localtime(&t);
|
||||
if (!tm)
|
||||
return 0;
|
||||
return tm_diff(&tm_utc,tm);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
AC_CACHE_CHECK([if gettimeofday takes tz argument],samba_cv_HAVE_GETTIMEOFDAY_TZ,[
|
||||
AC_TRY_RUN([
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
main() { struct timeval tv; exit(gettimeofday(&tv, NULL));}],
|
||||
samba_cv_HAVE_GETTIMEOFDAY_TZ=yes,samba_cv_HAVE_GETTIMEOFDAY_TZ=no,samba_cv_HAVE_GETTIMEOFDAY_TZ=cross)])
|
||||
if test x"$samba_cv_HAVE_GETTIMEOFDAY_TZ" = x"yes"; then
|
||||
AC_DEFINE(HAVE_GETTIMEOFDAY_TZ,1,[Whether gettimeofday() is available])
|
||||
fi
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
gain/lose root privileges
|
||||
|
||||
Copyright (C) Andrew Tridgell 2004
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/filesys.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Gaining/losing root privileges
|
||||
*/
|
||||
|
||||
/*
|
||||
there are times when smbd needs to temporarily gain root privileges
|
||||
to do some operation. To do this you call root_privileges(), which
|
||||
returns a talloc handle. To restore your previous privileges
|
||||
talloc_free() this pointer.
|
||||
|
||||
Note that this call is considered successful even if it does not
|
||||
manage to gain root privileges, but it will call smb_abort() if it
|
||||
fails to restore the privileges afterwards. The logic is that
|
||||
failing to gain root access can be caught by whatever operation
|
||||
needs to be run as root failing, but failing to lose the root
|
||||
privileges is dangerous.
|
||||
|
||||
This also means that this code is safe to be called from completely
|
||||
unprivileged processes.
|
||||
*/
|
||||
|
||||
struct saved_state {
|
||||
uid_t uid;
|
||||
};
|
||||
|
||||
static int privileges_destructor(struct saved_state *s)
|
||||
{
|
||||
if (geteuid() != s->uid &&
|
||||
seteuid(s->uid) != 0) {
|
||||
smb_panic("Failed to restore privileges");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain root privileges for the current process.
|
||||
*
|
||||
* The privileges can be dropped by talloc_free()-ing the
|
||||
* token returned by this function
|
||||
*/
|
||||
void *root_privileges(void)
|
||||
{
|
||||
struct saved_state *s;
|
||||
s = talloc(NULL, struct saved_state);
|
||||
if (!s) return NULL;
|
||||
s->uid = geteuid();
|
||||
if (s->uid != 0) {
|
||||
seteuid(0);
|
||||
}
|
||||
talloc_set_destructor(s, privileges_destructor);
|
||||
return s;
|
||||
}
|
||||
@@ -0,0 +1,596 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Samba utility functions
|
||||
Copyright (C) Andrew Tridgell 1992-1998
|
||||
Copyright (C) Jeremy Allison 2001-2002
|
||||
Copyright (C) Simo Sorce 2001
|
||||
Copyright (C) Jim McDonough (jmcd@us.ibm.com) 2003.
|
||||
Copyright (C) James J Myers 2003
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/network.h"
|
||||
#include "system/filesys.h"
|
||||
#include "system/locale.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Misc utility functions
|
||||
*/
|
||||
|
||||
/**
|
||||
Find a suitable temporary directory. The result should be copied immediately
|
||||
as it may be overwritten by a subsequent call.
|
||||
**/
|
||||
_PUBLIC_ const char *tmpdir(void)
|
||||
{
|
||||
char *p;
|
||||
if ((p = getenv("TMPDIR")))
|
||||
return p;
|
||||
return "/tmp";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Check if a file exists - call vfs_file_exist for samba files.
|
||||
**/
|
||||
_PUBLIC_ BOOL file_exist(const char *fname)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(fname, &st) != 0) {
|
||||
return False;
|
||||
}
|
||||
|
||||
return ((S_ISREG(st.st_mode)) || (S_ISFIFO(st.st_mode)));
|
||||
}
|
||||
|
||||
/**
|
||||
Check a files mod time.
|
||||
**/
|
||||
|
||||
_PUBLIC_ time_t file_modtime(const char *fname)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
if (stat(fname,&st) != 0)
|
||||
return(0);
|
||||
|
||||
return(st.st_mtime);
|
||||
}
|
||||
|
||||
/**
|
||||
Check if a directory exists.
|
||||
**/
|
||||
|
||||
_PUBLIC_ BOOL directory_exist(const char *dname)
|
||||
{
|
||||
struct stat st;
|
||||
BOOL ret;
|
||||
|
||||
if (stat(dname,&st) != 0) {
|
||||
return False;
|
||||
}
|
||||
|
||||
ret = S_ISDIR(st.st_mode);
|
||||
if(!ret)
|
||||
errno = ENOTDIR;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Try to create the specified directory if it didn't exist.
|
||||
*
|
||||
* @retval True if the directory already existed and has the right permissions
|
||||
* or was successfully created.
|
||||
*/
|
||||
_PUBLIC_ BOOL directory_create_or_exist(const char *dname, uid_t uid,
|
||||
mode_t dir_perms)
|
||||
{
|
||||
mode_t old_umask;
|
||||
struct stat st;
|
||||
|
||||
old_umask = umask(0);
|
||||
if (lstat(dname, &st) == -1) {
|
||||
if (errno == ENOENT) {
|
||||
/* Create directory */
|
||||
if (mkdir(dname, dir_perms) == -1) {
|
||||
DEBUG(0, ("error creating directory "
|
||||
"%s: %s\n", dname,
|
||||
strerror(errno)));
|
||||
umask(old_umask);
|
||||
return False;
|
||||
}
|
||||
} else {
|
||||
DEBUG(0, ("lstat failed on directory %s: %s\n",
|
||||
dname, strerror(errno)));
|
||||
umask(old_umask);
|
||||
return False;
|
||||
}
|
||||
} else {
|
||||
/* Check ownership and permission on existing directory */
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
DEBUG(0, ("directory %s isn't a directory\n",
|
||||
dname));
|
||||
umask(old_umask);
|
||||
return False;
|
||||
}
|
||||
if ((st.st_uid != uid) ||
|
||||
((st.st_mode & 0777) != dir_perms)) {
|
||||
DEBUG(0, ("invalid permissions on directory "
|
||||
"%s\n", dname));
|
||||
umask(old_umask);
|
||||
return False;
|
||||
}
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
Close the low 3 fd's and open dev/null in their place.
|
||||
********************************************************************/
|
||||
static void close_low_fds(BOOL stderr_too)
|
||||
{
|
||||
#ifndef VALGRIND
|
||||
int fd;
|
||||
int i;
|
||||
|
||||
close(0);
|
||||
close(1);
|
||||
|
||||
if (stderr_too)
|
||||
close(2);
|
||||
|
||||
/* try and use up these file descriptors, so silly
|
||||
library routines writing to stdout etc won't cause havoc */
|
||||
for (i=0;i<3;i++) {
|
||||
if (i == 2 && !stderr_too)
|
||||
continue;
|
||||
|
||||
fd = open("/dev/null",O_RDWR,0);
|
||||
if (fd < 0)
|
||||
fd = open("/dev/null",O_WRONLY,0);
|
||||
if (fd < 0) {
|
||||
DEBUG(0,("Can't open /dev/null\n"));
|
||||
return;
|
||||
}
|
||||
if (fd != i) {
|
||||
DEBUG(0,("Didn't get file descriptor %d\n",i));
|
||||
return;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
Set a fd into blocking/nonblocking mode. Uses POSIX O_NONBLOCK if available,
|
||||
else
|
||||
if SYSV use O_NDELAY
|
||||
if BSD use FNDELAY
|
||||
**/
|
||||
|
||||
_PUBLIC_ int set_blocking(int fd, BOOL set)
|
||||
{
|
||||
int val;
|
||||
#ifdef O_NONBLOCK
|
||||
#define FLAG_TO_SET O_NONBLOCK
|
||||
#else
|
||||
#ifdef SYSV
|
||||
#define FLAG_TO_SET O_NDELAY
|
||||
#else /* BSD */
|
||||
#define FLAG_TO_SET FNDELAY
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if((val = fcntl(fd, F_GETFL, 0)) == -1)
|
||||
return -1;
|
||||
if(set) /* Turn blocking on - ie. clear nonblock flag */
|
||||
val &= ~FLAG_TO_SET;
|
||||
else
|
||||
val |= FLAG_TO_SET;
|
||||
return fcntl( fd, F_SETFL, val);
|
||||
#undef FLAG_TO_SET
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Sleep for a specified number of milliseconds.
|
||||
**/
|
||||
|
||||
_PUBLIC_ void msleep(unsigned int t)
|
||||
{
|
||||
struct timeval tval;
|
||||
|
||||
tval.tv_sec = t/1000;
|
||||
tval.tv_usec = 1000*(t%1000);
|
||||
/* this should be the real select - do NOT replace
|
||||
with sys_select() */
|
||||
select(0,NULL,NULL,NULL,&tval);
|
||||
}
|
||||
|
||||
/**
|
||||
Become a daemon, discarding the controlling terminal.
|
||||
**/
|
||||
|
||||
_PUBLIC_ void become_daemon(BOOL Fork)
|
||||
{
|
||||
if (Fork) {
|
||||
if (fork()) {
|
||||
_exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
/* detach from the terminal */
|
||||
#ifdef HAVE_SETSID
|
||||
setsid();
|
||||
#elif defined(TIOCNOTTY)
|
||||
{
|
||||
int i = open("/dev/tty", O_RDWR, 0);
|
||||
if (i != -1) {
|
||||
ioctl(i, (int) TIOCNOTTY, (char *)0);
|
||||
close(i);
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_SETSID */
|
||||
|
||||
/* Close fd's 0,1,2. Needed if started by rsh */
|
||||
close_low_fds(False); /* Don't close stderr, let the debug system
|
||||
attach it to the logfile */
|
||||
}
|
||||
|
||||
/**
|
||||
Get my own name, return in malloc'ed storage.
|
||||
**/
|
||||
|
||||
_PUBLIC_ char* get_myname(void)
|
||||
{
|
||||
char *hostname;
|
||||
const int host_name_max = 255;
|
||||
char *p;
|
||||
|
||||
hostname = malloc(host_name_max+1);
|
||||
*hostname = 0;
|
||||
|
||||
/* get my host name */
|
||||
if (gethostname(hostname, host_name_max+1) == -1) {
|
||||
DEBUG(0,("gethostname failed\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Ensure null termination. */
|
||||
hostname[host_name_max] = '\0';
|
||||
|
||||
/* split off any parts after an initial . */
|
||||
p = strchr(hostname,'.');
|
||||
|
||||
if (p)
|
||||
*p = 0;
|
||||
|
||||
return hostname;
|
||||
}
|
||||
|
||||
/**
|
||||
Return true if a string could be a pure IP address.
|
||||
**/
|
||||
|
||||
_PUBLIC_ BOOL is_ipaddress(const char *str)
|
||||
{
|
||||
BOOL pure_address = True;
|
||||
int i;
|
||||
|
||||
for (i=0; pure_address && str[i]; i++)
|
||||
if (!(isdigit((int)str[i]) || str[i] == '.'))
|
||||
pure_address = False;
|
||||
|
||||
/* Check that a pure number is not misinterpreted as an IP */
|
||||
pure_address = pure_address && (strchr(str, '.') != NULL);
|
||||
|
||||
return pure_address;
|
||||
}
|
||||
|
||||
/**
|
||||
Interpret an internet address or name into an IP address in 4 byte form.
|
||||
**/
|
||||
_PUBLIC_ uint32_t interpret_addr(const char *str)
|
||||
{
|
||||
struct hostent *hp;
|
||||
uint32_t res;
|
||||
|
||||
if (str == NULL || *str == 0 ||
|
||||
strcmp(str,"0.0.0.0") == 0) {
|
||||
return 0;
|
||||
}
|
||||
if (strcmp(str,"255.255.255.255") == 0) {
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
/* recognise 'localhost' as a special name. This fixes problems with
|
||||
some hosts that don't have localhost in /etc/hosts */
|
||||
if (strcasecmp(str,"localhost") == 0) {
|
||||
str = "127.0.0.1";
|
||||
}
|
||||
|
||||
/* if it's in the form of an IP address then get the lib to interpret it */
|
||||
if (is_ipaddress(str)) {
|
||||
res = inet_addr(str);
|
||||
} else {
|
||||
/* otherwise assume it's a network name of some sort and use
|
||||
sys_gethostbyname */
|
||||
if ((hp = sys_gethostbyname(str)) == 0) {
|
||||
DEBUG(3,("sys_gethostbyname: Unknown host. %s\n",str));
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(hp->h_addr == NULL) {
|
||||
DEBUG(3,("sys_gethostbyname: host address is invalid for host %s\n",str));
|
||||
return 0;
|
||||
}
|
||||
memcpy((char *)&res,(char *)hp->h_addr, 4);
|
||||
}
|
||||
|
||||
if (res == (uint32_t)-1)
|
||||
return(0);
|
||||
|
||||
return(res);
|
||||
}
|
||||
|
||||
/**
|
||||
A convenient addition to interpret_addr().
|
||||
**/
|
||||
_PUBLIC_ struct ipv4_addr interpret_addr2(const char *str)
|
||||
{
|
||||
struct ipv4_addr ret;
|
||||
uint32_t a = interpret_addr(str);
|
||||
ret.addr = a;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
Check if an IP is the 0.0.0.0.
|
||||
**/
|
||||
|
||||
_PUBLIC_ BOOL is_zero_ip(struct ipv4_addr ip)
|
||||
{
|
||||
return ip.addr == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
Are two IPs on the same subnet?
|
||||
**/
|
||||
|
||||
_PUBLIC_ BOOL same_net(struct ipv4_addr ip1,struct ipv4_addr ip2,struct ipv4_addr mask)
|
||||
{
|
||||
uint32_t net1,net2,nmask;
|
||||
|
||||
nmask = ntohl(mask.addr);
|
||||
net1 = ntohl(ip1.addr);
|
||||
net2 = ntohl(ip2.addr);
|
||||
|
||||
return((net1 & nmask) == (net2 & nmask));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Check if a process exists. Does this work on all unixes?
|
||||
**/
|
||||
|
||||
_PUBLIC_ BOOL process_exists(pid_t pid)
|
||||
{
|
||||
/* Doing kill with a non-positive pid causes messages to be
|
||||
* sent to places we don't want. */
|
||||
SMB_ASSERT(pid > 0);
|
||||
return(kill(pid,0) == 0 || errno != ESRCH);
|
||||
}
|
||||
|
||||
/**
|
||||
Simple routine to do POSIX file locking. Cruft in NFS and 64->32 bit mapping
|
||||
is dealt with in posix.c
|
||||
**/
|
||||
|
||||
_PUBLIC_ BOOL fcntl_lock(int fd, int op, off_t offset, off_t count, int type)
|
||||
{
|
||||
struct flock lock;
|
||||
int ret;
|
||||
|
||||
DEBUG(8,("fcntl_lock %d %d %.0f %.0f %d\n",fd,op,(double)offset,(double)count,type));
|
||||
|
||||
lock.l_type = type;
|
||||
lock.l_whence = SEEK_SET;
|
||||
lock.l_start = offset;
|
||||
lock.l_len = count;
|
||||
lock.l_pid = 0;
|
||||
|
||||
ret = fcntl(fd,op,&lock);
|
||||
|
||||
if (ret == -1 && errno != 0)
|
||||
DEBUG(3,("fcntl_lock: fcntl lock gave errno %d (%s)\n",errno,strerror(errno)));
|
||||
|
||||
/* a lock query */
|
||||
if (op == F_GETLK) {
|
||||
if ((ret != -1) &&
|
||||
(lock.l_type != F_UNLCK) &&
|
||||
(lock.l_pid != 0) &&
|
||||
(lock.l_pid != getpid())) {
|
||||
DEBUG(3,("fcntl_lock: fd %d is locked by pid %d\n",fd,(int)lock.l_pid));
|
||||
return(True);
|
||||
}
|
||||
|
||||
/* it must be not locked or locked by me */
|
||||
return(False);
|
||||
}
|
||||
|
||||
/* a lock set or unset */
|
||||
if (ret == -1) {
|
||||
DEBUG(3,("fcntl_lock: lock failed at offset %.0f count %.0f op %d type %d (%s)\n",
|
||||
(double)offset,(double)count,op,type,strerror(errno)));
|
||||
return(False);
|
||||
}
|
||||
|
||||
/* everything went OK */
|
||||
DEBUG(8,("fcntl_lock: Lock call successful\n"));
|
||||
|
||||
return(True);
|
||||
}
|
||||
|
||||
|
||||
static void print_asc(int level, const uint8_t *buf,int len)
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<len;i++)
|
||||
DEBUGADD(level,("%c", isprint(buf[i])?buf[i]:'.'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Write dump of binary data to the log file.
|
||||
*
|
||||
* The data is only written if the log level is at least level.
|
||||
*/
|
||||
_PUBLIC_ void dump_data(int level, const uint8_t *buf,int len)
|
||||
{
|
||||
int i=0;
|
||||
if (len<=0) return;
|
||||
|
||||
if (!DEBUGLVL(level)) return;
|
||||
|
||||
DEBUGADD(level,("[%03X] ",i));
|
||||
for (i=0;i<len;) {
|
||||
DEBUGADD(level,("%02X ",(int)buf[i]));
|
||||
i++;
|
||||
if (i%8 == 0) DEBUGADD(level,(" "));
|
||||
if (i%16 == 0) {
|
||||
print_asc(level,&buf[i-16],8); DEBUGADD(level,(" "));
|
||||
print_asc(level,&buf[i-8],8); DEBUGADD(level,("\n"));
|
||||
if (i<len) DEBUGADD(level,("[%03X] ",i));
|
||||
}
|
||||
}
|
||||
if (i%16) {
|
||||
int n;
|
||||
n = 16 - (i%16);
|
||||
DEBUGADD(level,(" "));
|
||||
if (n>8) DEBUGADD(level,(" "));
|
||||
while (n--) DEBUGADD(level,(" "));
|
||||
n = MIN(8,i%16);
|
||||
print_asc(level,&buf[i-(i%16)],n); DEBUGADD(level,( " " ));
|
||||
n = (i%16) - n;
|
||||
if (n>0) print_asc(level,&buf[i-n],n);
|
||||
DEBUGADD(level,("\n"));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
malloc that aborts with smb_panic on fail or zero size.
|
||||
**/
|
||||
|
||||
_PUBLIC_ void *smb_xmalloc(size_t size)
|
||||
{
|
||||
void *p;
|
||||
if (size == 0)
|
||||
smb_panic("smb_xmalloc: called with zero size.\n");
|
||||
if ((p = malloc(size)) == NULL)
|
||||
smb_panic("smb_xmalloc: malloc fail.\n");
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
Memdup with smb_panic on fail.
|
||||
**/
|
||||
|
||||
_PUBLIC_ void *smb_xmemdup(const void *p, size_t size)
|
||||
{
|
||||
void *p2;
|
||||
p2 = smb_xmalloc(size);
|
||||
memcpy(p2, p, size);
|
||||
return p2;
|
||||
}
|
||||
|
||||
/**
|
||||
strdup that aborts on malloc fail.
|
||||
**/
|
||||
|
||||
_PUBLIC_ char *smb_xstrdup(const char *s)
|
||||
{
|
||||
char *s1 = strdup(s);
|
||||
if (!s1)
|
||||
smb_panic("smb_xstrdup: malloc fail\n");
|
||||
return s1;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Like strdup but for memory.
|
||||
**/
|
||||
|
||||
_PUBLIC_ void *memdup(const void *p, size_t size)
|
||||
{
|
||||
void *p2;
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
p2 = malloc(size);
|
||||
if (!p2)
|
||||
return NULL;
|
||||
memcpy(p2, p, size);
|
||||
return p2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a password to the log file.
|
||||
*
|
||||
* @note Only actually does something if DEBUG_PASSWORD was defined during
|
||||
* compile-time.
|
||||
*/
|
||||
_PUBLIC_ void dump_data_pw(const char *msg, const uint8_t * data, size_t len)
|
||||
{
|
||||
#ifdef DEBUG_PASSWORD
|
||||
DEBUG(11, ("%s", msg));
|
||||
if (data != NULL && len > 0)
|
||||
{
|
||||
dump_data(11, data, len);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* see if a range of memory is all zero. A NULL pointer is considered
|
||||
* to be all zero
|
||||
*/
|
||||
_PUBLIC_ BOOL all_zero(const uint8_t *ptr, size_t size)
|
||||
{
|
||||
int i;
|
||||
if (!ptr) return True;
|
||||
for (i=0;i<size;i++) {
|
||||
if (ptr[i]) return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
realloc an array, checking for integer overflow in the array size
|
||||
*/
|
||||
_PUBLIC_ void *realloc_array(void *ptr, size_t el_size, unsigned count)
|
||||
{
|
||||
#define MAX_MALLOC_SIZE 0x7fffffff
|
||||
if (count == 0 ||
|
||||
count >= MAX_MALLOC_SIZE/el_size) {
|
||||
return NULL;
|
||||
}
|
||||
if (!ptr) {
|
||||
return malloc(el_size * count);
|
||||
}
|
||||
return realloc(ptr, el_size * count);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Utility functions for Samba
|
||||
Copyright (C) Andrew Tridgell 1992-1999
|
||||
Copyright (C) Jelmer Vernooij 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _SAMBA_UTIL_H_
|
||||
#define _SAMBA_UTIL_H_
|
||||
|
||||
#include "charset/charset.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief Helpful macros
|
||||
*/
|
||||
|
||||
struct substitute_context;
|
||||
struct smbsrv_tcon;
|
||||
|
||||
extern const char *logfile;
|
||||
extern const char *panic_action;
|
||||
|
||||
#include "util/xfile.h"
|
||||
#include "util/debug.h"
|
||||
#include "util/mutex.h"
|
||||
#include "util/byteorder.h"
|
||||
#include "lib/util/util_proto.h"
|
||||
|
||||
/**
|
||||
* zero a structure
|
||||
*/
|
||||
#define ZERO_STRUCT(x) memset((char *)&(x), 0, sizeof(x))
|
||||
|
||||
/**
|
||||
* zero a structure given a pointer to the structure
|
||||
*/
|
||||
#define ZERO_STRUCTP(x) do { if ((x) != NULL) memset((char *)(x), 0, sizeof(*(x))); } while(0)
|
||||
|
||||
/**
|
||||
* zero a structure given a pointer to the structure - no zero check
|
||||
*/
|
||||
#define ZERO_STRUCTPN(x) memset((char *)(x), 0, sizeof(*(x)))
|
||||
|
||||
/**
|
||||
* pointer difference macro
|
||||
*/
|
||||
#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((const char *)(p1)) - (const char *)(p2)))
|
||||
|
||||
/**
|
||||
* work out how many elements there are in a static array
|
||||
*/
|
||||
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
/**
|
||||
* assert macros
|
||||
*/
|
||||
#define SMB_ASSERT(b) do { if (!(b)) { \
|
||||
DEBUG(0,("PANIC: assert failed at %s(%d)\n", __FILE__, __LINE__)); \
|
||||
smb_panic("assert failed"); abort(); }} while (0)
|
||||
|
||||
#ifndef SAFE_FREE /* Oh no this is also defined in tdb.h */
|
||||
/**
|
||||
* Free memory if the pointer and zero the pointer.
|
||||
*
|
||||
* @note You are explicitly allowed to pass NULL pointers -- they will
|
||||
* always be ignored.
|
||||
**/
|
||||
#define SAFE_FREE(x) do { if ((x) != NULL) {free(discard_const_p(void *, (x))); (x)=NULL;} } while(0)
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Type-safe version of malloc. Allocated one copy of the
|
||||
* specified data type.
|
||||
*/
|
||||
#define malloc_p(type) (type *)malloc(sizeof(type))
|
||||
|
||||
/**
|
||||
* Allocate an array of elements of one data type. Does type-checking.
|
||||
*/
|
||||
#define malloc_array_p(type, count) (type *)realloc_array(NULL, sizeof(type), count)
|
||||
|
||||
/**
|
||||
* Resize an array of elements of one data type. Does type-checking.
|
||||
*/
|
||||
#define realloc_p(p, type, count) (type *)realloc_array(p, sizeof(type), count)
|
||||
|
||||
#define data_blob(ptr, size) data_blob_named(ptr, size, "DATA_BLOB: "__location__)
|
||||
#define data_blob_talloc(ctx, ptr, size) data_blob_talloc_named(ctx, ptr, size, "DATA_BLOB: "__location__)
|
||||
#define data_blob_dup_talloc(ctx, blob) data_blob_talloc_named(ctx, (blob)->data, (blob)->length, "DATA_BLOB: "__location__)
|
||||
|
||||
#if defined(VALGRIND)
|
||||
#define strlen(x) valgrind_strlen(x)
|
||||
#endif
|
||||
|
||||
/**
|
||||
this is a warning hack. The idea is to use this everywhere that we
|
||||
get the "discarding const" warning from gcc. That doesn't actually
|
||||
fix the problem of course, but it means that when we do get to
|
||||
cleaning them up we can do it by searching the code for
|
||||
discard_const.
|
||||
|
||||
It also means that other error types aren't as swamped by the noise
|
||||
of hundreds of const warnings, so we are more likely to notice when
|
||||
we get new errors.
|
||||
|
||||
Please only add more uses of this macro when you find it
|
||||
_really_ hard to fix const warnings. Our aim is to eventually use
|
||||
this function in only a very few places.
|
||||
|
||||
Also, please call this via the discard_const_p() macro interface, as that
|
||||
makes the return type safe.
|
||||
*/
|
||||
#define discard_const(ptr) ((void *)((intptr_t)(ptr)))
|
||||
|
||||
/** Type-safe version of discard_const */
|
||||
#define discard_const_p(type, ptr) ((type *)discard_const(ptr))
|
||||
|
||||
#endif /* _SAMBA_UTIL_H_ */
|
||||
@@ -0,0 +1 @@
|
||||
AC_CHECK_FUNCS(setsid)
|
||||
@@ -0,0 +1,405 @@
|
||||
/*
|
||||
* Unix SMB/CIFS implementation.
|
||||
* SMB parameters and setup
|
||||
* Copyright (C) Andrew Tridgell 1992-1998 Modified by Jeremy Allison 1995.
|
||||
*
|
||||
* Added afdgets() Jelmer Vernooij 2005
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it under
|
||||
* the terms of the GNU General Public License as published by the Free
|
||||
* Software Foundation; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along with
|
||||
* this program; if not, write to the Free Software Foundation, Inc., 675
|
||||
* Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/shmem.h"
|
||||
#include "system/filesys.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief File-related utility functions
|
||||
*/
|
||||
|
||||
/**
|
||||
read a line from a file with possible \ continuation chars.
|
||||
Blanks at the start or end of a line are stripped.
|
||||
The string will be allocated if s2 is NULL
|
||||
**/
|
||||
_PUBLIC_ char *fgets_slash(char *s2,int maxlen,XFILE *f)
|
||||
{
|
||||
char *s=s2;
|
||||
int len = 0;
|
||||
int c;
|
||||
BOOL start_of_line = True;
|
||||
|
||||
if (x_feof(f))
|
||||
return(NULL);
|
||||
|
||||
if (maxlen <2) return(NULL);
|
||||
|
||||
if (!s2)
|
||||
{
|
||||
maxlen = MIN(maxlen,8);
|
||||
s = (char *)malloc(maxlen);
|
||||
}
|
||||
|
||||
if (!s) return(NULL);
|
||||
|
||||
*s = 0;
|
||||
|
||||
while (len < maxlen-1)
|
||||
{
|
||||
c = x_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)
|
||||
SAFE_FREE(s);
|
||||
return(len>0?s:NULL);
|
||||
case ' ':
|
||||
if (start_of_line)
|
||||
break;
|
||||
/* fall through */
|
||||
default:
|
||||
start_of_line = False;
|
||||
s[len++] = c;
|
||||
s[len] = 0;
|
||||
}
|
||||
if (!s2 && len > maxlen-3)
|
||||
{
|
||||
char *t;
|
||||
|
||||
maxlen *= 2;
|
||||
t = realloc_p(s, char, maxlen);
|
||||
if (!t) {
|
||||
DEBUG(0,("fgets_slash: failed to expand buffer!\n"));
|
||||
SAFE_FREE(s);
|
||||
return(NULL);
|
||||
} else s = t;
|
||||
}
|
||||
}
|
||||
return(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read one line (data until next newline or eof) and allocate it
|
||||
*/
|
||||
_PUBLIC_ char *afdgets(int fd, TALLOC_CTX *mem_ctx, size_t hint)
|
||||
{
|
||||
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);
|
||||
|
||||
if (ret == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
} while (ret == hint);
|
||||
|
||||
data[offset] = '\0';
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
load a file into memory from a fd.
|
||||
**/
|
||||
_PUBLIC_ char *fd_load(int fd, size_t *size, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
struct stat sbuf;
|
||||
char *p;
|
||||
|
||||
if (fstat(fd, &sbuf) != 0) return NULL;
|
||||
|
||||
p = (char *)talloc_size(mem_ctx, sbuf.st_size+1);
|
||||
if (!p) return NULL;
|
||||
|
||||
if (read(fd, p, sbuf.st_size) != sbuf.st_size) {
|
||||
talloc_free(p);
|
||||
return NULL;
|
||||
}
|
||||
p[sbuf.st_size] = 0;
|
||||
|
||||
if (size) *size = sbuf.st_size;
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
load a file into memory
|
||||
**/
|
||||
_PUBLIC_ char *file_load(const char *fname, size_t *size, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
int fd;
|
||||
char *p;
|
||||
|
||||
if (!fname || !*fname) return NULL;
|
||||
|
||||
fd = open(fname,O_RDONLY);
|
||||
if (fd == -1) return NULL;
|
||||
|
||||
p = fd_load(fd, size, mem_ctx);
|
||||
|
||||
close(fd);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
mmap (if possible) or read a file
|
||||
**/
|
||||
_PUBLIC_ void *map_file(const char *fname, size_t size)
|
||||
{
|
||||
size_t s2 = 0;
|
||||
void *p = NULL;
|
||||
#ifdef HAVE_MMAP
|
||||
int fd;
|
||||
fd = open(fname, O_RDONLY, 0);
|
||||
if (fd == -1) {
|
||||
DEBUG(2,("Failed to load %s - %s\n", fname, strerror(errno)));
|
||||
return NULL;
|
||||
}
|
||||
p = mmap(NULL, size, PROT_READ, MAP_SHARED|MAP_FILE, fd, 0);
|
||||
close(fd);
|
||||
if (p == MAP_FAILED) {
|
||||
DEBUG(1,("Failed to mmap %s - %s\n", fname, strerror(errno)));
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
if (!p) {
|
||||
p = file_load(fname, &s2, talloc_autofree_context());
|
||||
if (!p) return NULL;
|
||||
if (s2 != size) {
|
||||
DEBUG(1,("incorrect size for %s - got %d expected %d\n",
|
||||
fname, (int)s2, (int)size));
|
||||
talloc_free(p);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
parse a buffer into lines
|
||||
'p' will be freed on error, and otherwise will be made a child of the returned array
|
||||
**/
|
||||
static char **file_lines_parse(char *p, size_t size, int *numlines, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
int i;
|
||||
char *s, **ret;
|
||||
|
||||
if (!p) return NULL;
|
||||
|
||||
for (s = p, i=0; s < p+size; s++) {
|
||||
if (s[0] == '\n') i++;
|
||||
}
|
||||
|
||||
ret = talloc_array(mem_ctx, char *, i+2);
|
||||
if (!ret) {
|
||||
talloc_free(p);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
talloc_steal(ret, p);
|
||||
|
||||
memset(ret, 0, sizeof(ret[0])*(i+2));
|
||||
|
||||
ret[0] = p;
|
||||
for (s = p, i=0; s < p+size; s++) {
|
||||
if (s[0] == '\n') {
|
||||
s[0] = 0;
|
||||
i++;
|
||||
ret[i] = s+1;
|
||||
}
|
||||
if (s[0] == '\r') s[0] = 0;
|
||||
}
|
||||
|
||||
/* remove any blank lines at the end */
|
||||
while (i > 0 && ret[i-1][0] == 0) {
|
||||
i--;
|
||||
}
|
||||
|
||||
if (numlines) *numlines = i;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
load a file into memory and return an array of pointers to lines in the file
|
||||
must be freed with talloc_free().
|
||||
**/
|
||||
_PUBLIC_ char **file_lines_load(const char *fname, int *numlines, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
char *p;
|
||||
size_t size;
|
||||
|
||||
p = file_load(fname, &size, mem_ctx);
|
||||
if (!p) return NULL;
|
||||
|
||||
return file_lines_parse(p, size, numlines, mem_ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
load a fd into memory and return an array of pointers to lines in the file
|
||||
must be freed with talloc_free(). If convert is true calls unix_to_dos on
|
||||
the list.
|
||||
**/
|
||||
_PUBLIC_ char **fd_lines_load(int fd, int *numlines, TALLOC_CTX *mem_ctx)
|
||||
{
|
||||
char *p;
|
||||
size_t size;
|
||||
|
||||
p = fd_load(fd, &size, mem_ctx);
|
||||
if (!p) return NULL;
|
||||
|
||||
return file_lines_parse(p, size, numlines, mem_ctx);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
take a list of lines and modify them to produce a list where \ continues
|
||||
a line
|
||||
**/
|
||||
_PUBLIC_ void file_lines_slashcont(char **lines)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i=0; lines[i];) {
|
||||
int len = strlen(lines[i]);
|
||||
if (lines[i][len-1] == '\\') {
|
||||
lines[i][len-1] = ' ';
|
||||
if (lines[i+1]) {
|
||||
char *p = &lines[i][len];
|
||||
while (p < lines[i+1]) *p++ = ' ';
|
||||
for (j = i+1; lines[j]; j++) lines[j] = lines[j+1];
|
||||
}
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
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)
|
||||
{
|
||||
int fd;
|
||||
fd = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0644);
|
||||
if (fd == -1) {
|
||||
return False;
|
||||
}
|
||||
if (write(fd, packet, length) != (size_t)length) {
|
||||
return False;
|
||||
}
|
||||
close(fd);
|
||||
return True;
|
||||
}
|
||||
|
||||
_PUBLIC_ int vfdprintf(int fd, const char *format, va_list ap) _PRINTF_ATTRIBUTE(2,0)
|
||||
{
|
||||
char *p;
|
||||
int len, ret;
|
||||
va_list ap2;
|
||||
|
||||
va_copy(ap2, ap);
|
||||
|
||||
len = vasprintf(&p, format, ap2);
|
||||
if (len <= 0) return len;
|
||||
ret = write(fd, p, len);
|
||||
SAFE_FREE(p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
_PUBLIC_ int fdprintf(int fd, const char *format, ...) _PRINTF_ATTRIBUTE(2,3)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start(ap, format);
|
||||
ret = vfdprintf(fd, format, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
try to determine if the filesystem supports large files
|
||||
*/
|
||||
_PUBLIC_ bool large_file_support(const char *path)
|
||||
{
|
||||
int fd;
|
||||
ssize_t ret;
|
||||
char c;
|
||||
|
||||
fd = open(path, O_RDWR|O_CREAT, 0600);
|
||||
unlink(path);
|
||||
if (fd == -1) {
|
||||
/* have to assume large files are OK */
|
||||
return true;
|
||||
}
|
||||
ret = pread(fd, &c, 1, ((uint64_t)1)<<32);
|
||||
close(fd);
|
||||
return ret == 0;
|
||||
}
|
||||
@@ -0,0 +1,284 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Samba utility functions
|
||||
Copyright (C) Simo Sorce 2001
|
||||
Copyright (C) Jeremy Allison 2001
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
|
||||
/****************************************************************
|
||||
Returns a single linked list of group entries.
|
||||
Use grent_free() to free it after use.
|
||||
****************************************************************/
|
||||
|
||||
struct sys_grent * getgrent_list(void)
|
||||
{
|
||||
struct sys_grent *glist;
|
||||
struct sys_grent *gent;
|
||||
struct group *grp;
|
||||
|
||||
gent = malloc_p(struct sys_grent);
|
||||
if (gent == NULL) {
|
||||
DEBUG (0, ("Out of memory in getgrent_list!\n"));
|
||||
return NULL;
|
||||
}
|
||||
memset(gent, '\0', sizeof(struct sys_grent));
|
||||
glist = gent;
|
||||
|
||||
setgrent();
|
||||
grp = getgrent();
|
||||
if (grp == NULL) {
|
||||
endgrent();
|
||||
SAFE_FREE(glist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (grp != NULL) {
|
||||
int i,num;
|
||||
|
||||
if (grp->gr_name) {
|
||||
if ((gent->gr_name = strdup(grp->gr_name)) == NULL)
|
||||
goto err;
|
||||
}
|
||||
if (grp->gr_passwd) {
|
||||
if ((gent->gr_passwd = strdup(grp->gr_passwd)) == NULL)
|
||||
goto err;
|
||||
}
|
||||
gent->gr_gid = grp->gr_gid;
|
||||
|
||||
/* number of strings in gr_mem */
|
||||
for (num = 0; grp->gr_mem[num]; num++)
|
||||
;
|
||||
|
||||
/* alloc space for gr_mem string pointers */
|
||||
if ((gent->gr_mem = malloc_array_p(char *, num+1)) == NULL)
|
||||
goto err;
|
||||
|
||||
memset(gent->gr_mem, '\0', (num+1) * sizeof(char *));
|
||||
|
||||
for (i=0; i < num; i++) {
|
||||
if ((gent->gr_mem[i] = strdup(grp->gr_mem[i])) == NULL)
|
||||
goto err;
|
||||
}
|
||||
gent->gr_mem[num] = NULL;
|
||||
|
||||
grp = getgrent();
|
||||
if (grp) {
|
||||
gent->next = malloc_p(struct sys_grent);
|
||||
if (gent->next == NULL)
|
||||
goto err;
|
||||
gent = gent->next;
|
||||
memset(gent, '\0', sizeof(struct sys_grent));
|
||||
}
|
||||
}
|
||||
|
||||
endgrent();
|
||||
return glist;
|
||||
|
||||
err:
|
||||
|
||||
endgrent();
|
||||
DEBUG(0, ("Out of memory in getgrent_list!\n"));
|
||||
grent_free(glist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
Free the single linked list of group entries made by
|
||||
getgrent_list()
|
||||
****************************************************************/
|
||||
|
||||
void grent_free (struct sys_grent *glist)
|
||||
{
|
||||
while (glist) {
|
||||
struct sys_grent *prev;
|
||||
|
||||
SAFE_FREE(glist->gr_name);
|
||||
SAFE_FREE(glist->gr_passwd);
|
||||
if (glist->gr_mem) {
|
||||
int i;
|
||||
for (i = 0; glist->gr_mem[i]; i++)
|
||||
SAFE_FREE(glist->gr_mem[i]);
|
||||
SAFE_FREE(glist->gr_mem);
|
||||
}
|
||||
prev = glist;
|
||||
glist = glist->next;
|
||||
SAFE_FREE(prev);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
Returns a single linked list of passwd entries.
|
||||
Use pwent_free() to free it after use.
|
||||
****************************************************************/
|
||||
|
||||
struct sys_pwent * getpwent_list(void)
|
||||
{
|
||||
struct sys_pwent *plist;
|
||||
struct sys_pwent *pent;
|
||||
struct passwd *pwd;
|
||||
|
||||
pent = malloc_p(struct sys_pwent);
|
||||
if (pent == NULL) {
|
||||
DEBUG (0, ("Out of memory in getpwent_list!\n"));
|
||||
return NULL;
|
||||
}
|
||||
plist = pent;
|
||||
|
||||
setpwent();
|
||||
pwd = getpwent();
|
||||
while (pwd != NULL) {
|
||||
memset(pent, '\0', sizeof(struct sys_pwent));
|
||||
if (pwd->pw_name) {
|
||||
if ((pent->pw_name = strdup(pwd->pw_name)) == NULL)
|
||||
goto err;
|
||||
}
|
||||
if (pwd->pw_passwd) {
|
||||
if ((pent->pw_passwd = strdup(pwd->pw_passwd)) == NULL)
|
||||
goto err;
|
||||
}
|
||||
pent->pw_uid = pwd->pw_uid;
|
||||
pent->pw_gid = pwd->pw_gid;
|
||||
if (pwd->pw_gecos) {
|
||||
if ((pent->pw_name = strdup(pwd->pw_gecos)) == NULL)
|
||||
goto err;
|
||||
}
|
||||
if (pwd->pw_dir) {
|
||||
if ((pent->pw_name = strdup(pwd->pw_dir)) == NULL)
|
||||
goto err;
|
||||
}
|
||||
if (pwd->pw_shell) {
|
||||
if ((pent->pw_name = strdup(pwd->pw_shell)) == NULL)
|
||||
goto err;
|
||||
}
|
||||
|
||||
pwd = getpwent();
|
||||
if (pwd) {
|
||||
pent->next = malloc_p(struct sys_pwent);
|
||||
if (pent->next == NULL)
|
||||
goto err;
|
||||
pent = pent->next;
|
||||
}
|
||||
}
|
||||
|
||||
endpwent();
|
||||
return plist;
|
||||
|
||||
err:
|
||||
|
||||
endpwent();
|
||||
DEBUG(0, ("Out of memory in getpwent_list!\n"));
|
||||
pwent_free(plist);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
Free the single linked list of passwd entries made by
|
||||
getpwent_list()
|
||||
****************************************************************/
|
||||
|
||||
void pwent_free (struct sys_pwent *plist)
|
||||
{
|
||||
while (plist) {
|
||||
struct sys_pwent *prev;
|
||||
|
||||
SAFE_FREE(plist->pw_name);
|
||||
SAFE_FREE(plist->pw_passwd);
|
||||
SAFE_FREE(plist->pw_gecos);
|
||||
SAFE_FREE(plist->pw_dir);
|
||||
SAFE_FREE(plist->pw_shell);
|
||||
|
||||
prev = plist;
|
||||
plist = plist->next;
|
||||
SAFE_FREE(prev);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
Add the individual group users onto the list.
|
||||
****************************************************************/
|
||||
|
||||
static struct sys_userlist *add_members_to_userlist(struct sys_userlist *list_head, const struct group *grp)
|
||||
{
|
||||
size_t num_users, i;
|
||||
|
||||
/* Count the number of users. */
|
||||
for (num_users = 0; grp->gr_mem[num_users]; num_users++)
|
||||
;
|
||||
|
||||
for (i = 0; i < num_users; i++) {
|
||||
struct sys_userlist *entry = malloc_p(struct sys_userlist);
|
||||
if (entry == NULL) {
|
||||
free_userlist(list_head);
|
||||
return NULL;
|
||||
}
|
||||
entry->unix_name = (char *)strdup(grp->gr_mem[i]);
|
||||
if (entry->unix_name == NULL) {
|
||||
SAFE_FREE(entry);
|
||||
free_userlist(list_head);
|
||||
return NULL;
|
||||
}
|
||||
DLIST_ADD(list_head, entry);
|
||||
}
|
||||
return list_head;
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
Get the list of UNIX users in a group.
|
||||
We have to enumerate the /etc/group file as some UNIX getgrnam()
|
||||
calls won't do that for us (notably Tru64 UNIX).
|
||||
****************************************************************/
|
||||
|
||||
struct sys_userlist *get_users_in_group(const char *gname)
|
||||
{
|
||||
struct sys_userlist *list_head = NULL;
|
||||
struct group *gptr;
|
||||
|
||||
#if !defined(BROKEN_GETGRNAM)
|
||||
if ((gptr = (struct group *)getgrnam(gname)) == NULL)
|
||||
return NULL;
|
||||
return add_members_to_userlist(list_head, gptr);
|
||||
#else
|
||||
/* BROKEN_GETGRNAM - True64 */
|
||||
setgrent();
|
||||
while((gptr = getgrent()) != NULL) {
|
||||
if (strequal(gname, gptr->gr_name)) {
|
||||
list_head = add_members_to_userlist(list_head, gptr);
|
||||
if (list_head == NULL)
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
endgrent();
|
||||
return list_head;
|
||||
#endif
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
Free list allocated above.
|
||||
****************************************************************/
|
||||
|
||||
void free_userlist(struct sys_userlist *list_head)
|
||||
{
|
||||
while (list_head) {
|
||||
struct sys_userlist *old_head = list_head;
|
||||
DLIST_REMOVE(list_head, list_head);
|
||||
SAFE_FREE(old_head->unix_name);
|
||||
SAFE_FREE(old_head);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Safe versions of getpw* calls
|
||||
|
||||
Copyright (C) Andrew Bartlett 2002
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
static struct passwd *alloc_copy_passwd(const struct passwd *from)
|
||||
{
|
||||
struct passwd *ret = smb_xmalloc_p(struct passwd);
|
||||
ZERO_STRUCTP(ret);
|
||||
ret->pw_name = smb_xstrdup(from->pw_name);
|
||||
ret->pw_passwd = smb_xstrdup(from->pw_passwd);
|
||||
ret->pw_uid = from->pw_uid;
|
||||
ret->pw_gid = from->pw_gid;
|
||||
ret->pw_gecos = smb_xstrdup(from->pw_gecos);
|
||||
ret->pw_dir = smb_xstrdup(from->pw_dir);
|
||||
ret->pw_shell = smb_xstrdup(from->pw_shell);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void passwd_free (struct passwd **buf)
|
||||
{
|
||||
if (!*buf) {
|
||||
DEBUG(0, ("attempted double-free of allocated passwd\n"));
|
||||
return;
|
||||
}
|
||||
|
||||
SAFE_FREE((*buf)->pw_name);
|
||||
SAFE_FREE((*buf)->pw_passwd);
|
||||
SAFE_FREE((*buf)->pw_gecos);
|
||||
SAFE_FREE((*buf)->pw_dir);
|
||||
SAFE_FREE((*buf)->pw_shell);
|
||||
|
||||
SAFE_FREE(*buf);
|
||||
}
|
||||
|
||||
struct passwd *getpwnam_alloc(const char *name)
|
||||
{
|
||||
struct passwd *temp;
|
||||
|
||||
temp = sys_getpwnam(name);
|
||||
|
||||
if (!temp) {
|
||||
#if 0
|
||||
if (errno == ENOMEM) {
|
||||
/* what now? */
|
||||
}
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return alloc_copy_passwd(temp);
|
||||
}
|
||||
|
||||
struct passwd *getpwuid_alloc(uid_t uid)
|
||||
{
|
||||
struct passwd *temp;
|
||||
|
||||
temp = sys_getpwuid(uid);
|
||||
|
||||
if (!temp) {
|
||||
#if 0
|
||||
if (errno == ENOMEM) {
|
||||
/* what now? */
|
||||
}
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return alloc_copy_passwd(temp);
|
||||
}
|
||||
@@ -0,0 +1,797 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
Samba utility functions
|
||||
|
||||
Copyright (C) Andrew Tridgell 1992-2001
|
||||
Copyright (C) Simo Sorce 2001-2002
|
||||
Copyright (C) Martin Pool 2003
|
||||
Copyright (C) James Peach 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "libcli/raw/smb.h"
|
||||
#include "pstring.h"
|
||||
#include "lib/ldb/include/ldb.h"
|
||||
#include "system/locale.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief String utilities.
|
||||
**/
|
||||
|
||||
|
||||
/**
|
||||
Trim the specified elements off the front and back of a string.
|
||||
**/
|
||||
_PUBLIC_ BOOL trim_string(char *s,const char *front,const char *back)
|
||||
{
|
||||
BOOL ret = False;
|
||||
size_t front_len;
|
||||
size_t back_len;
|
||||
size_t len;
|
||||
|
||||
/* Ignore null or empty strings. */
|
||||
if (!s || (s[0] == '\0'))
|
||||
return False;
|
||||
|
||||
front_len = front? strlen(front) : 0;
|
||||
back_len = back? strlen(back) : 0;
|
||||
|
||||
len = strlen(s);
|
||||
|
||||
if (front_len) {
|
||||
while (len && strncmp(s, front, front_len)==0) {
|
||||
/* Must use memmove here as src & dest can
|
||||
* easily overlap. Found by valgrind. JRA. */
|
||||
memmove(s, s+front_len, (len-front_len)+1);
|
||||
len -= front_len;
|
||||
ret=True;
|
||||
}
|
||||
}
|
||||
|
||||
if (back_len) {
|
||||
while ((len >= back_len) && strncmp(s+len-back_len,back,back_len)==0) {
|
||||
s[len-back_len]='\0';
|
||||
len -= back_len;
|
||||
ret=True;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
Find the number of 'c' chars in a string
|
||||
**/
|
||||
_PUBLIC_ size_t count_chars(const char *s, char c)
|
||||
{
|
||||
size_t count = 0;
|
||||
|
||||
while (*s) {
|
||||
if (*s == c) count++;
|
||||
s ++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Safe string copy into a known length string. maxlength does not
|
||||
include the terminating zero.
|
||||
**/
|
||||
_PUBLIC_ char *safe_strcpy(char *dest,const char *src, size_t maxlength)
|
||||
{
|
||||
size_t len;
|
||||
|
||||
if (!dest) {
|
||||
DEBUG(0,("ERROR: NULL dest in safe_strcpy\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef DEVELOPER
|
||||
/* We intentionally write out at the extremity of the destination
|
||||
* string. If the destination is too short (e.g. pstrcpy into mallocd
|
||||
* or fstring) then this should cause an error under a memory
|
||||
* checker. */
|
||||
dest[maxlength] = '\0';
|
||||
if (PTR_DIFF(&len, dest) > 0) { /* check if destination is on the stack, ok if so */
|
||||
log_suspicious_usage("safe_strcpy", src);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!src) {
|
||||
*dest = 0;
|
||||
return dest;
|
||||
}
|
||||
|
||||
len = strlen(src);
|
||||
|
||||
if (len > maxlength) {
|
||||
DEBUG(0,("ERROR: string overflow by %u (%u - %u) in safe_strcpy [%.50s]\n",
|
||||
(uint_t)(len-maxlength), (unsigned)len, (unsigned)maxlength, src));
|
||||
len = maxlength;
|
||||
}
|
||||
|
||||
memmove(dest, src, len);
|
||||
dest[len] = 0;
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
Safe string cat into a string. maxlength does not
|
||||
include the terminating zero.
|
||||
**/
|
||||
_PUBLIC_ char *safe_strcat(char *dest, const char *src, size_t maxlength)
|
||||
{
|
||||
size_t src_len, dest_len;
|
||||
|
||||
if (!dest) {
|
||||
DEBUG(0,("ERROR: NULL dest in safe_strcat\n"));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!src)
|
||||
return dest;
|
||||
|
||||
#ifdef DEVELOPER
|
||||
if (PTR_DIFF(&src_len, dest) > 0) { /* check if destination is on the stack, ok if so */
|
||||
log_suspicious_usage("safe_strcat", src);
|
||||
}
|
||||
#endif
|
||||
src_len = strlen(src);
|
||||
dest_len = strlen(dest);
|
||||
|
||||
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));
|
||||
if (maxlength > dest_len) {
|
||||
memcpy(&dest[dest_len], src, maxlength - dest_len);
|
||||
}
|
||||
dest[maxlength] = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
memcpy(&dest[dest_len], src, src_len);
|
||||
dest[dest_len + src_len] = 0;
|
||||
return dest;
|
||||
}
|
||||
|
||||
/**
|
||||
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\ta9\te3\n"
|
||||
|
||||
|
||||
**/
|
||||
_PUBLIC_ size_t strhex_to_str(char *p, size_t len, const char *strhex)
|
||||
{
|
||||
size_t i;
|
||||
size_t num_chars = 0;
|
||||
uint8_t lonybble, hinybble;
|
||||
const char *hexchars = "0123456789ABCDEF";
|
||||
char *p1 = NULL, *p2 = NULL;
|
||||
|
||||
for (i = 0; i < len && strhex[i] != 0; i++) {
|
||||
if (strncasecmp(hexchars, "0x", 2) == 0) {
|
||||
i++; /* skip two chars */
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!(p1 = strchr(hexchars, toupper((unsigned char)strhex[i]))))
|
||||
break;
|
||||
|
||||
i++; /* next hex digit */
|
||||
|
||||
if (!(p2 = strchr(hexchars, toupper((unsigned char)strhex[i]))))
|
||||
break;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a hex string and return a data blob.
|
||||
*/
|
||||
_PUBLIC_ DATA_BLOB strhex_to_data_blob(const char *strhex)
|
||||
{
|
||||
DATA_BLOB ret_blob = data_blob(NULL, strlen(strhex)/2+1);
|
||||
|
||||
ret_blob.length = strhex_to_str((char *)ret_blob.data,
|
||||
strlen(strhex),
|
||||
strhex);
|
||||
|
||||
return ret_blob;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Routine to print a buffer as HEX digits, into an allocated string.
|
||||
*/
|
||||
_PUBLIC_ void hex_encode(const unsigned char *buff_in, size_t len, char **out_hex_buffer)
|
||||
{
|
||||
int i;
|
||||
char *hex_buffer;
|
||||
|
||||
*out_hex_buffer = smb_xmalloc((len*2)+1);
|
||||
hex_buffer = *out_hex_buffer;
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
slprintf(&hex_buffer[i*2], 3, "%02X", buff_in[i]);
|
||||
}
|
||||
|
||||
/**
|
||||
Check if a string is part of a list.
|
||||
**/
|
||||
_PUBLIC_ BOOL in_list(const char *s, const char *list, BOOL casesensitive)
|
||||
{
|
||||
pstring tok;
|
||||
const char *p=list;
|
||||
|
||||
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_m(tok,s) == 0)
|
||||
return(True);
|
||||
}
|
||||
}
|
||||
return(False);
|
||||
}
|
||||
|
||||
/**
|
||||
Set a string value, allocing the space for the string
|
||||
**/
|
||||
static BOOL string_init(char **dest,const char *src)
|
||||
{
|
||||
if (!src) src = "";
|
||||
|
||||
(*dest) = strdup(src);
|
||||
if ((*dest) == NULL) {
|
||||
DEBUG(0,("Out of memory in string_init\n"));
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
Free a string value.
|
||||
**/
|
||||
_PUBLIC_ void string_free(char **s)
|
||||
{
|
||||
if (s) SAFE_FREE(*s);
|
||||
}
|
||||
|
||||
/**
|
||||
Set a string value, deallocating any existing space, and allocing the space
|
||||
for the string
|
||||
**/
|
||||
_PUBLIC_ BOOL string_set(char **dest, const char *src)
|
||||
{
|
||||
string_free(dest);
|
||||
return string_init(dest,src);
|
||||
}
|
||||
|
||||
/**
|
||||
Substitute a string for a pattern in another string. Make sure there is
|
||||
enough room!
|
||||
|
||||
This routine looks for pattern in s and replaces it with
|
||||
insert. It may do multiple replacements.
|
||||
|
||||
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.
|
||||
**/
|
||||
|
||||
_PUBLIC_ void string_sub(char *s,const char *pattern, const char *insert, size_t len)
|
||||
{
|
||||
char *p;
|
||||
ssize_t ls,lp,li, i;
|
||||
|
||||
if (!insert || !pattern || !*pattern || !s)
|
||||
return;
|
||||
|
||||
ls = (ssize_t)strlen(s);
|
||||
lp = (ssize_t)strlen(pattern);
|
||||
li = (ssize_t)strlen(insert);
|
||||
|
||||
if (len == 0)
|
||||
len = ls + 1; /* len is number of *bytes* */
|
||||
|
||||
while (lp <= ls && (p = strstr(s,pattern))) {
|
||||
if (ls + (li-lp) >= len) {
|
||||
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);
|
||||
}
|
||||
for (i=0;i<li;i++) {
|
||||
switch (insert[i]) {
|
||||
case '`':
|
||||
case '"':
|
||||
case '\'':
|
||||
case ';':
|
||||
case '$':
|
||||
case '%':
|
||||
case '\r':
|
||||
case '\n':
|
||||
p[i] = '_';
|
||||
break;
|
||||
default:
|
||||
p[i] = insert[i];
|
||||
}
|
||||
}
|
||||
s = p + li;
|
||||
ls += (li-lp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
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.
|
||||
**/
|
||||
|
||||
_PUBLIC_ void all_string_sub(char *s,const char *pattern,const char *insert, size_t len)
|
||||
{
|
||||
char *p;
|
||||
ssize_t ls,lp,li;
|
||||
|
||||
if (!insert || !pattern || !s)
|
||||
return;
|
||||
|
||||
ls = (ssize_t)strlen(s);
|
||||
lp = (ssize_t)strlen(pattern);
|
||||
li = (ssize_t)strlen(insert);
|
||||
|
||||
if (!*pattern)
|
||||
return;
|
||||
|
||||
if (len == 0)
|
||||
len = ls + 1; /* len is number of *bytes* */
|
||||
|
||||
while (lp <= ls && (p = strstr(s,pattern))) {
|
||||
if (ls + (li-lp) >= len) {
|
||||
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);
|
||||
}
|
||||
memcpy(p, insert, li);
|
||||
s = p + li;
|
||||
ls += (li-lp);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Unescape a URL encoded string, in place.
|
||||
**/
|
||||
|
||||
_PUBLIC_ void rfc1738_unescape(char *buf)
|
||||
{
|
||||
char *p=buf;
|
||||
|
||||
while ((p=strchr(p,'+')))
|
||||
*p = ' ';
|
||||
|
||||
p = buf;
|
||||
|
||||
while (p && *p && (p=strchr(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++;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VALGRIND
|
||||
size_t valgrind_strlen(const char *s)
|
||||
{
|
||||
size_t count;
|
||||
for(count = 0; *s++; count++)
|
||||
;
|
||||
return count;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
format a string into length-prefixed dotted domain format, as used in NBT
|
||||
and in some ADS structures
|
||||
**/
|
||||
_PUBLIC_ const char *str_format_nbt_domain(TALLOC_CTX *mem_ctx, const char *s)
|
||||
{
|
||||
char *ret;
|
||||
int i;
|
||||
if (!s || !*s) {
|
||||
return talloc_strdup(mem_ctx, "");
|
||||
}
|
||||
ret = talloc_size(mem_ctx, strlen(s)+2);
|
||||
if (!ret) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
memcpy(ret+1, s, strlen(s)+1);
|
||||
ret[0] = '.';
|
||||
|
||||
for (i=0;ret[i];i++) {
|
||||
if (ret[i] == '.') {
|
||||
char *p = strchr(ret+i+1, '.');
|
||||
if (p) {
|
||||
ret[i] = p-(ret+i+1);
|
||||
} else {
|
||||
ret[i] = strlen(ret+i+1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a string to an array of strings.
|
||||
*
|
||||
* num should be a pointer to an integer that holds the current
|
||||
* number of elements in strings. It will be updated by this function.
|
||||
*/
|
||||
_PUBLIC_ 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(mem_ctx,
|
||||
*strings,
|
||||
const char *, ((*num)+1));
|
||||
|
||||
if ((*strings == NULL) || (dup_str == NULL))
|
||||
return False;
|
||||
|
||||
(*strings)[*num] = dup_str;
|
||||
*num += 1;
|
||||
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
varient of strcmp() that handles NULL ptrs
|
||||
**/
|
||||
_PUBLIC_ int strcmp_safe(const char *s1, const char *s2)
|
||||
{
|
||||
if (s1 == s2) {
|
||||
return 0;
|
||||
}
|
||||
if (s1 == NULL || s2 == NULL) {
|
||||
return s1?-1:1;
|
||||
}
|
||||
return strcmp(s1, s2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
return the number of bytes occupied by a buffer in ASCII format
|
||||
the result includes the null termination
|
||||
limited by 'n' bytes
|
||||
**/
|
||||
_PUBLIC_ 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 a string representing a CIFS attribute for a file.
|
||||
**/
|
||||
_PUBLIC_ char *attrib_string(TALLOC_CTX *mem_ctx, uint32_t attrib)
|
||||
{
|
||||
int i, len;
|
||||
const struct {
|
||||
char c;
|
||||
uint16_t attr;
|
||||
} attr_strs[] = {
|
||||
{'V', FILE_ATTRIBUTE_VOLUME},
|
||||
{'D', FILE_ATTRIBUTE_DIRECTORY},
|
||||
{'A', FILE_ATTRIBUTE_ARCHIVE},
|
||||
{'H', FILE_ATTRIBUTE_HIDDEN},
|
||||
{'S', FILE_ATTRIBUTE_SYSTEM},
|
||||
{'N', FILE_ATTRIBUTE_NORMAL},
|
||||
{'R', FILE_ATTRIBUTE_READONLY},
|
||||
{'d', FILE_ATTRIBUTE_DEVICE},
|
||||
{'t', FILE_ATTRIBUTE_TEMPORARY},
|
||||
{'s', FILE_ATTRIBUTE_SPARSE},
|
||||
{'r', FILE_ATTRIBUTE_REPARSE_POINT},
|
||||
{'c', FILE_ATTRIBUTE_COMPRESSED},
|
||||
{'o', FILE_ATTRIBUTE_OFFLINE},
|
||||
{'n', FILE_ATTRIBUTE_NONINDEXED},
|
||||
{'e', FILE_ATTRIBUTE_ENCRYPTED}
|
||||
};
|
||||
char *ret;
|
||||
|
||||
ret = talloc_size(mem_ctx, ARRAY_SIZE(attr_strs)+1);
|
||||
if (!ret) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (len=i=0; i<ARRAY_SIZE(attr_strs); i++) {
|
||||
if (attrib & attr_strs[i].attr) {
|
||||
ret[len++] = attr_strs[i].c;
|
||||
}
|
||||
}
|
||||
|
||||
ret[len] = 0;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
Set a boolean variable from the text value stored in the passed string.
|
||||
Returns True in success, False if the passed string does not correctly
|
||||
represent a boolean.
|
||||
**/
|
||||
|
||||
_PUBLIC_ BOOL set_boolean(const char *boolean_string, BOOL *boolean)
|
||||
{
|
||||
if (strwicmp(boolean_string, "yes") == 0 ||
|
||||
strwicmp(boolean_string, "true") == 0 ||
|
||||
strwicmp(boolean_string, "on") == 0 ||
|
||||
strwicmp(boolean_string, "1") == 0) {
|
||||
*boolean = True;
|
||||
return True;
|
||||
} else if (strwicmp(boolean_string, "no") == 0 ||
|
||||
strwicmp(boolean_string, "false") == 0 ||
|
||||
strwicmp(boolean_string, "off") == 0 ||
|
||||
strwicmp(boolean_string, "0") == 0) {
|
||||
*boolean = False;
|
||||
return True;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a string containing a boolean value.
|
||||
*
|
||||
* val will be set to the read value.
|
||||
*
|
||||
* @retval True if a boolean value was parsed, False otherwise.
|
||||
*/
|
||||
_PUBLIC_ BOOL conv_str_bool(const char * str, BOOL * val)
|
||||
{
|
||||
char * end = NULL;
|
||||
long lval;
|
||||
|
||||
if (str == NULL || *str == '\0') {
|
||||
return False;
|
||||
}
|
||||
|
||||
lval = strtol(str, &end, 10 /* base */);
|
||||
if (end == NULL || *end != '\0' || end == str) {
|
||||
return set_boolean(str, val);
|
||||
}
|
||||
|
||||
*val = (lval) ? True : False;
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a size specification like 16K into an integral number of bytes.
|
||||
**/
|
||||
_PUBLIC_ BOOL conv_str_size(const char * str, uint64_t * val)
|
||||
{
|
||||
char * end = NULL;
|
||||
unsigned long long lval;
|
||||
|
||||
if (str == NULL || *str == '\0') {
|
||||
return False;
|
||||
}
|
||||
|
||||
lval = strtoull(str, &end, 10 /* base */);
|
||||
if (end == NULL || end == str) {
|
||||
return False;
|
||||
}
|
||||
|
||||
if (*end) {
|
||||
if (strwicmp(end, "K") == 0) {
|
||||
lval *= 1024ULL;
|
||||
} else if (strwicmp(end, "M") == 0) {
|
||||
lval *= (1024ULL * 1024ULL);
|
||||
} else if (strwicmp(end, "G") == 0) {
|
||||
lval *= (1024ULL * 1024ULL * 1024ULL);
|
||||
} else if (strwicmp(end, "T") == 0) {
|
||||
lval *= (1024ULL * 1024ULL * 1024ULL * 1024ULL);
|
||||
} else if (strwicmp(end, "P") == 0) {
|
||||
lval *= (1024ULL * 1024ULL * 1024ULL * 1024ULL * 1024ULL);
|
||||
} else {
|
||||
return False;
|
||||
}
|
||||
}
|
||||
|
||||
*val = (uint64_t)lval;
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a uint64_t value from a string
|
||||
*
|
||||
* val will be set to the value read.
|
||||
*
|
||||
* @retval True if parsing was successful, False otherwise
|
||||
*/
|
||||
_PUBLIC_ BOOL conv_str_u64(const char * str, uint64_t * val)
|
||||
{
|
||||
char * end = NULL;
|
||||
unsigned long long lval;
|
||||
|
||||
if (str == NULL || *str == '\0') {
|
||||
return False;
|
||||
}
|
||||
|
||||
lval = strtoull(str, &end, 10 /* base */);
|
||||
if (end == NULL || *end != '\0' || end == str) {
|
||||
return False;
|
||||
}
|
||||
|
||||
*val = (uint64_t)lval;
|
||||
return True;
|
||||
}
|
||||
|
||||
/**
|
||||
return the number of bytes occupied by a buffer in CH_UTF16 format
|
||||
the result includes the null termination
|
||||
**/
|
||||
_PUBLIC_ 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
|
||||
**/
|
||||
_PUBLIC_ 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;
|
||||
}
|
||||
|
||||
_PUBLIC_ size_t ucs2_align(const void *base_ptr, const void *p, int flags)
|
||||
{
|
||||
if (flags & (STR_NOALIGN|STR_ASCII))
|
||||
return 0;
|
||||
return PTR_DIFF(p, base_ptr) & 1;
|
||||
}
|
||||
|
||||
/**
|
||||
Do a case-insensitive, whitespace-ignoring string compare.
|
||||
**/
|
||||
_PUBLIC_ int strwicmp(const char *psz1, const char *psz2)
|
||||
{
|
||||
/* 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 */
|
||||
while (1) {
|
||||
while (isspace((int)*psz1))
|
||||
psz1++;
|
||||
while (isspace((int)*psz2))
|
||||
psz2++;
|
||||
if (toupper((unsigned char)*psz1) != toupper((unsigned char)*psz2)
|
||||
|| *psz1 == '\0'
|
||||
|| *psz2 == '\0')
|
||||
break;
|
||||
psz1++;
|
||||
psz2++;
|
||||
}
|
||||
return (*psz1 - *psz2);
|
||||
}
|
||||
|
||||
/**
|
||||
String replace.
|
||||
**/
|
||||
_PUBLIC_ void string_replace(char *s, char oldc, char newc)
|
||||
{
|
||||
while (*s) {
|
||||
if (*s == oldc) *s = newc;
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare 2 strings.
|
||||
*
|
||||
* @note The comparison is case-insensitive.
|
||||
**/
|
||||
_PUBLIC_ BOOL strequal(const char *s1, const char *s2)
|
||||
{
|
||||
if (s1 == s2)
|
||||
return(True);
|
||||
if (!s1 || !s2)
|
||||
return(False);
|
||||
|
||||
return strcasecmp(s1,s2) == 0;
|
||||
}
|
||||
@@ -0,0 +1,300 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
Copyright (C) Andrew Tridgell 2005
|
||||
Copyright (C) Jelmer Vernooij 2005
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief String list manipulation
|
||||
*/
|
||||
|
||||
/**
|
||||
build a null terminated list of strings from a input string and a
|
||||
separator list. The separator list must contain characters less than
|
||||
or equal to 0x2f for this to work correctly on multi-byte strings
|
||||
*/
|
||||
_PUBLIC_ const char **str_list_make(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
|
||||
{
|
||||
int num_elements = 0;
|
||||
const char **ret = NULL;
|
||||
|
||||
if (sep == NULL) {
|
||||
sep = LIST_SEP;
|
||||
}
|
||||
|
||||
ret = talloc_array(mem_ctx, const char *, 1);
|
||||
if (ret == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
while (string && *string) {
|
||||
size_t len = strcspn(string, sep);
|
||||
const char **ret2;
|
||||
|
||||
if (len == 0) {
|
||||
string += strspn(string, sep);
|
||||
continue;
|
||||
}
|
||||
|
||||
ret2 = talloc_realloc(mem_ctx, ret, const char *, num_elements+2);
|
||||
if (ret2 == NULL) {
|
||||
talloc_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
ret = ret2;
|
||||
|
||||
ret[num_elements] = talloc_strndup(ret, string, len);
|
||||
if (ret[num_elements] == NULL) {
|
||||
talloc_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
num_elements++;
|
||||
string += len;
|
||||
}
|
||||
|
||||
ret[num_elements] = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* build a null terminated list of strings from an argv-like input string
|
||||
* Entries are seperated by spaces and can be enclosed by quotes.
|
||||
* Does NOT support escaping
|
||||
*/
|
||||
_PUBLIC_ const char **str_list_make_shell(TALLOC_CTX *mem_ctx, const char *string, const char *sep)
|
||||
{
|
||||
int num_elements = 0;
|
||||
const char **ret = NULL;
|
||||
|
||||
ret = talloc_array(mem_ctx, const char *, 1);
|
||||
if (ret == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (sep == NULL)
|
||||
sep = " \t\n\r";
|
||||
|
||||
while (string && *string) {
|
||||
size_t len = strcspn(string, sep);
|
||||
char *element;
|
||||
const char **ret2;
|
||||
|
||||
if (len == 0) {
|
||||
string += strspn(string, sep);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (*string == '\"') {
|
||||
string++;
|
||||
len = strcspn(string, "\"");
|
||||
element = talloc_strndup(ret, string, len);
|
||||
string += len + 1;
|
||||
} else {
|
||||
element = talloc_strndup(ret, string, len);
|
||||
string += len;
|
||||
}
|
||||
|
||||
if (element == NULL) {
|
||||
talloc_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret2 = talloc_realloc(mem_ctx, ret, const char *, num_elements+2);
|
||||
if (ret2 == NULL) {
|
||||
talloc_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
ret = ret2;
|
||||
|
||||
ret[num_elements] = element;
|
||||
|
||||
num_elements++;
|
||||
}
|
||||
|
||||
ret[num_elements] = NULL;
|
||||
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* join a list back to one string
|
||||
*/
|
||||
_PUBLIC_ char *str_list_join(TALLOC_CTX *mem_ctx, const char **list, char seperator)
|
||||
{
|
||||
char *ret = NULL;
|
||||
int i;
|
||||
|
||||
if (list[0] == NULL)
|
||||
return talloc_strdup(mem_ctx, "");
|
||||
|
||||
ret = talloc_strdup(mem_ctx, list[0]);
|
||||
|
||||
for (i = 1; list[i]; i++) {
|
||||
ret = talloc_asprintf_append(ret, "%c%s", seperator, list[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** join a list back to one (shell-like) string; entries
|
||||
* seperated by spaces, using quotes where necessary */
|
||||
_PUBLIC_ char *str_list_join_shell(TALLOC_CTX *mem_ctx, const char **list, char sep)
|
||||
{
|
||||
char *ret = NULL;
|
||||
int i;
|
||||
|
||||
if (list[0] == NULL)
|
||||
return talloc_strdup(mem_ctx, "");
|
||||
|
||||
if (strchr(list[0], ' ') || strlen(list[0]) == 0)
|
||||
ret = talloc_asprintf(mem_ctx, "\"%s\"", list[0]);
|
||||
else
|
||||
ret = talloc_strdup(mem_ctx, list[0]);
|
||||
|
||||
for (i = 1; list[i]; i++) {
|
||||
if (strchr(list[i], ' ') || strlen(list[i]) == 0)
|
||||
ret = talloc_asprintf_append(ret, "%c\"%s\"", sep, list[i]);
|
||||
else
|
||||
ret = talloc_asprintf_append(ret, "%c%s", sep, list[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
return the number of elements in a string list
|
||||
*/
|
||||
_PUBLIC_ size_t str_list_length(const char **list)
|
||||
{
|
||||
size_t ret;
|
||||
for (ret=0;list && list[ret];ret++) /* noop */ ;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
copy a string list
|
||||
*/
|
||||
_PUBLIC_ const char **str_list_copy(TALLOC_CTX *mem_ctx, const char **list)
|
||||
{
|
||||
int i;
|
||||
const char **ret = talloc_array(mem_ctx, const char *, str_list_length(list)+1);
|
||||
if (ret == NULL) return NULL;
|
||||
|
||||
for (i=0;list && list[i];i++) {
|
||||
ret[i] = talloc_strdup(ret, list[i]);
|
||||
if (ret[i] == NULL) {
|
||||
talloc_free(ret);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
ret[i] = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
Return true if all the elements of the list match exactly.
|
||||
*/
|
||||
_PUBLIC_ BOOL str_list_equal(const char **list1, const char **list2)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (list1 == NULL || list2 == NULL) {
|
||||
return (list1 == list2);
|
||||
}
|
||||
|
||||
for (i=0;list1[i] && list2[i];i++) {
|
||||
if (strcmp(list1[i], list2[i]) != 0) {
|
||||
return False;
|
||||
}
|
||||
}
|
||||
if (list1[i] || list2[i]) {
|
||||
return False;
|
||||
}
|
||||
return True;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
add an entry to a string list
|
||||
*/
|
||||
_PUBLIC_ const char **str_list_add(const char **list, const char *s)
|
||||
{
|
||||
size_t len = str_list_length(list);
|
||||
const char **ret;
|
||||
|
||||
ret = talloc_realloc(NULL, list, const char *, len+2);
|
||||
if (ret == NULL) return NULL;
|
||||
|
||||
ret[len] = talloc_strdup(ret, s);
|
||||
if (ret[len] == NULL) return NULL;
|
||||
|
||||
ret[len+1] = NULL;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
remove an entry from a string list
|
||||
*/
|
||||
_PUBLIC_ void str_list_remove(const char **list, const char *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;list[i];i++) {
|
||||
if (strcmp(list[i], s) == 0) break;
|
||||
}
|
||||
if (!list[i]) return;
|
||||
|
||||
for (;list[i];i++) {
|
||||
list[i] = list[i+1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
return True if a string is in a list
|
||||
*/
|
||||
_PUBLIC_ BOOL str_list_check(const char **list, const char *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;list[i];i++) {
|
||||
if (strcmp(list[i], s) == 0) return True;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
|
||||
/**
|
||||
return True if a string is in a list, case insensitively
|
||||
*/
|
||||
_PUBLIC_ BOOL str_list_check_ci(const char **list, const char *s)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;list[i];i++) {
|
||||
if (strcasecmp(list[i], s) == 0) return True;
|
||||
}
|
||||
return False;
|
||||
}
|
||||
@@ -0,0 +1,541 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
tdb utility functions
|
||||
|
||||
Copyright (C) Andrew Tridgell 1992-2006
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "lib/tdb/include/tdb.h"
|
||||
#include "pstring.h"
|
||||
|
||||
/* these are little tdb utility functions that are meant to make
|
||||
dealing with a tdb database a little less cumbersome in Samba */
|
||||
|
||||
/***************************************************************
|
||||
Make a TDB_DATA and keep the const warning in one place
|
||||
****************************************************************/
|
||||
|
||||
static TDB_DATA make_tdb_data(const char *dptr, size_t dsize)
|
||||
{
|
||||
TDB_DATA ret;
|
||||
ret.dptr = discard_const_p(unsigned char, dptr);
|
||||
ret.dsize = dsize;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Lock a chain by string. Return -1 if lock failed.
|
||||
****************************************************************************/
|
||||
|
||||
int tdb_lock_bystring(struct tdb_context *tdb, const char *keyval)
|
||||
{
|
||||
TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
|
||||
|
||||
return tdb_chainlock(tdb, key);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Unlock a chain by string.
|
||||
****************************************************************************/
|
||||
|
||||
void tdb_unlock_bystring(struct tdb_context *tdb, const char *keyval)
|
||||
{
|
||||
TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
|
||||
|
||||
tdb_chainunlock(tdb, key);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Read lock a chain by string. Return -1 if lock failed.
|
||||
****************************************************************************/
|
||||
|
||||
int tdb_read_lock_bystring(struct tdb_context *tdb, const char *keyval)
|
||||
{
|
||||
TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
|
||||
|
||||
return tdb_chainlock_read(tdb, key);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Read unlock a chain by string.
|
||||
****************************************************************************/
|
||||
|
||||
void tdb_read_unlock_bystring(struct tdb_context *tdb, const char *keyval)
|
||||
{
|
||||
TDB_DATA key = make_tdb_data(keyval, strlen(keyval)+1);
|
||||
|
||||
tdb_chainunlock_read(tdb, key);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Fetch a int32_t value by a arbitrary blob key, return -1 if not found.
|
||||
Output is int32_t in native byte order.
|
||||
****************************************************************************/
|
||||
|
||||
int32_t tdb_fetch_int32_byblob(struct tdb_context *tdb, const char *keyval, size_t len)
|
||||
{
|
||||
TDB_DATA key = make_tdb_data(keyval, len);
|
||||
TDB_DATA data;
|
||||
int32_t ret;
|
||||
|
||||
data = tdb_fetch(tdb, key);
|
||||
if (!data.dptr || data.dsize != sizeof(int32_t)) {
|
||||
SAFE_FREE(data.dptr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = IVAL(data.dptr,0);
|
||||
SAFE_FREE(data.dptr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Fetch a int32_t value by string key, return -1 if not found.
|
||||
Output is int32_t in native byte order.
|
||||
****************************************************************************/
|
||||
|
||||
int32_t tdb_fetch_int32(struct tdb_context *tdb, const char *keystr)
|
||||
{
|
||||
return tdb_fetch_int32_byblob(tdb, keystr, strlen(keystr) + 1);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Store a int32_t value by an arbitary blob key, return 0 on success, -1 on failure.
|
||||
Input is int32_t in native byte order. Output in tdb is in little-endian.
|
||||
****************************************************************************/
|
||||
|
||||
int tdb_store_int32_byblob(struct tdb_context *tdb, const char *keystr, size_t len, int32_t v)
|
||||
{
|
||||
TDB_DATA key = make_tdb_data(keystr, len);
|
||||
TDB_DATA data;
|
||||
int32_t v_store;
|
||||
|
||||
SIVAL(&v_store,0,v);
|
||||
data.dptr = (void *)&v_store;
|
||||
data.dsize = sizeof(int32_t);
|
||||
|
||||
return tdb_store(tdb, key, data, TDB_REPLACE);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Store a int32_t value by string key, return 0 on success, -1 on failure.
|
||||
Input is int32_t in native byte order. Output in tdb is in little-endian.
|
||||
****************************************************************************/
|
||||
|
||||
int tdb_store_int32(struct tdb_context *tdb, const char *keystr, int32_t v)
|
||||
{
|
||||
return tdb_store_int32_byblob(tdb, keystr, strlen(keystr) + 1, v);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Fetch a uint32_t value by a arbitrary blob key, return -1 if not found.
|
||||
Output is uint32_t in native byte order.
|
||||
****************************************************************************/
|
||||
|
||||
BOOL tdb_fetch_uint32_byblob(struct tdb_context *tdb, const char *keyval, size_t len, uint32_t *value)
|
||||
{
|
||||
TDB_DATA key = make_tdb_data(keyval, len);
|
||||
TDB_DATA data;
|
||||
|
||||
data = tdb_fetch(tdb, key);
|
||||
if (!data.dptr || data.dsize != sizeof(uint32_t)) {
|
||||
SAFE_FREE(data.dptr);
|
||||
return False;
|
||||
}
|
||||
|
||||
*value = IVAL(data.dptr,0);
|
||||
SAFE_FREE(data.dptr);
|
||||
return True;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Fetch a uint32_t value by string key, return -1 if not found.
|
||||
Output is uint32_t in native byte order.
|
||||
****************************************************************************/
|
||||
|
||||
BOOL tdb_fetch_uint32(struct tdb_context *tdb, const char *keystr, uint32_t *value)
|
||||
{
|
||||
return tdb_fetch_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Store a uint32_t value by an arbitary blob key, return 0 on success, -1 on failure.
|
||||
Input is uint32_t in native byte order. Output in tdb is in little-endian.
|
||||
****************************************************************************/
|
||||
|
||||
BOOL tdb_store_uint32_byblob(struct tdb_context *tdb, const char *keystr, size_t len, uint32_t value)
|
||||
{
|
||||
TDB_DATA key = make_tdb_data(keystr, len);
|
||||
TDB_DATA data;
|
||||
uint32_t v_store;
|
||||
BOOL ret = True;
|
||||
|
||||
SIVAL(&v_store, 0, value);
|
||||
data.dptr = (void *)&v_store;
|
||||
data.dsize = sizeof(uint32_t);
|
||||
|
||||
if (tdb_store(tdb, key, data, TDB_REPLACE) == -1)
|
||||
ret = False;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Store a uint32_t value by string key, return 0 on success, -1 on failure.
|
||||
Input is uint32_t in native byte order. Output in tdb is in little-endian.
|
||||
****************************************************************************/
|
||||
|
||||
BOOL tdb_store_uint32(struct tdb_context *tdb, const char *keystr, uint32_t value)
|
||||
{
|
||||
return tdb_store_uint32_byblob(tdb, keystr, strlen(keystr) + 1, value);
|
||||
}
|
||||
/****************************************************************************
|
||||
Store a buffer by a null terminated string key. Return 0 on success, -1
|
||||
on failure.
|
||||
****************************************************************************/
|
||||
|
||||
int tdb_store_bystring(struct tdb_context *tdb, const char *keystr, TDB_DATA data, int flags)
|
||||
{
|
||||
TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
|
||||
|
||||
return tdb_store(tdb, key, data, flags);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Fetch a buffer using a null terminated string key. Don't forget to call
|
||||
free() on the result dptr.
|
||||
****************************************************************************/
|
||||
|
||||
TDB_DATA tdb_fetch_bystring(struct tdb_context *tdb, const char *keystr)
|
||||
{
|
||||
TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
|
||||
|
||||
return tdb_fetch(tdb, key);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Delete an entry using a null terminated string key.
|
||||
****************************************************************************/
|
||||
|
||||
int tdb_delete_bystring(struct tdb_context *tdb, const char *keystr)
|
||||
{
|
||||
TDB_DATA key = make_tdb_data(keystr, strlen(keystr)+1);
|
||||
|
||||
return tdb_delete(tdb, key);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Atomic integer change. Returns old value. To create, set initial value in *oldval.
|
||||
****************************************************************************/
|
||||
|
||||
int32_t tdb_change_int32_atomic(struct tdb_context *tdb, const char *keystr, int32_t *oldval, int32_t change_val)
|
||||
{
|
||||
int32_t val;
|
||||
int32_t ret = -1;
|
||||
|
||||
if (tdb_lock_bystring(tdb, keystr) == -1)
|
||||
return -1;
|
||||
|
||||
if ((val = tdb_fetch_int32(tdb, keystr)) == -1) {
|
||||
/* The lookup failed */
|
||||
if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
|
||||
/* but not because it didn't exist */
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* Start with 'old' value */
|
||||
val = *oldval;
|
||||
|
||||
} else {
|
||||
/* It worked, set return value (oldval) to tdb data */
|
||||
*oldval = val;
|
||||
}
|
||||
|
||||
/* Increment value for storage and return next time */
|
||||
val += change_val;
|
||||
|
||||
if (tdb_store_int32(tdb, keystr, val) == -1)
|
||||
goto err_out;
|
||||
|
||||
ret = 0;
|
||||
|
||||
err_out:
|
||||
|
||||
tdb_unlock_bystring(tdb, keystr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Atomic unsigned integer change. Returns old value. To create, set initial value in *oldval.
|
||||
****************************************************************************/
|
||||
|
||||
BOOL tdb_change_uint32_atomic(struct tdb_context *tdb, const char *keystr, uint32_t *oldval, uint32_t change_val)
|
||||
{
|
||||
uint32_t val;
|
||||
BOOL ret = False;
|
||||
|
||||
if (tdb_lock_bystring(tdb, keystr) == -1)
|
||||
return False;
|
||||
|
||||
if (!tdb_fetch_uint32(tdb, keystr, &val)) {
|
||||
/* It failed */
|
||||
if (tdb_error(tdb) != TDB_ERR_NOEXIST) {
|
||||
/* and not because it didn't exist */
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
/* Start with 'old' value */
|
||||
val = *oldval;
|
||||
|
||||
} else {
|
||||
/* it worked, set return value (oldval) to tdb data */
|
||||
*oldval = val;
|
||||
|
||||
}
|
||||
|
||||
/* get a new value to store */
|
||||
val += change_val;
|
||||
|
||||
if (!tdb_store_uint32(tdb, keystr, val))
|
||||
goto err_out;
|
||||
|
||||
ret = True;
|
||||
|
||||
err_out:
|
||||
|
||||
tdb_unlock_bystring(tdb, keystr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Allow tdb_delete to be used as a tdb_traversal_fn.
|
||||
****************************************************************************/
|
||||
|
||||
int tdb_traverse_delete_fn(struct tdb_context *the_tdb, TDB_DATA key, TDB_DATA dbuf,
|
||||
void *state)
|
||||
{
|
||||
return tdb_delete(the_tdb, key);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
Useful pair of routines for packing/unpacking data consisting of
|
||||
integers and strings.
|
||||
****************************************************************************/
|
||||
|
||||
size_t tdb_pack(TDB_CONTEXT *tdb, char *buf, int bufsize, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
uint8_t bt;
|
||||
uint16_t w;
|
||||
uint32_t d;
|
||||
int i;
|
||||
void *p;
|
||||
int len;
|
||||
char *s;
|
||||
char c;
|
||||
char *buf0 = buf;
|
||||
const char *fmt0 = fmt;
|
||||
int bufsize0 = bufsize;
|
||||
tdb_log_func log_fn = tdb_log_fn(tdb);
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
while (*fmt) {
|
||||
switch ((c = *fmt++)) {
|
||||
case 'b': /* unsigned 8-bit integer */
|
||||
len = 1;
|
||||
bt = (uint8_t)va_arg(ap, int);
|
||||
if (bufsize && bufsize >= len)
|
||||
SSVAL(buf, 0, bt);
|
||||
break;
|
||||
case 'w': /* unsigned 16-bit integer */
|
||||
len = 2;
|
||||
w = (uint16_t)va_arg(ap, int);
|
||||
if (bufsize && bufsize >= len)
|
||||
SSVAL(buf, 0, w);
|
||||
break;
|
||||
case 'd': /* signed 32-bit integer (standard int in most systems) */
|
||||
len = 4;
|
||||
d = va_arg(ap, uint32_t);
|
||||
if (bufsize && bufsize >= len)
|
||||
SIVAL(buf, 0, d);
|
||||
break;
|
||||
case 'p': /* pointer */
|
||||
len = 4;
|
||||
p = va_arg(ap, void *);
|
||||
d = p?1:0;
|
||||
if (bufsize && bufsize >= len)
|
||||
SIVAL(buf, 0, d);
|
||||
break;
|
||||
case 'P': /* null-terminated string */
|
||||
s = va_arg(ap,char *);
|
||||
w = strlen(s);
|
||||
len = w + 1;
|
||||
if (bufsize && bufsize >= len)
|
||||
memcpy(buf, s, len);
|
||||
break;
|
||||
case 'f': /* null-terminated string */
|
||||
s = va_arg(ap,char *);
|
||||
w = strlen(s);
|
||||
len = w + 1;
|
||||
if (bufsize && bufsize >= len)
|
||||
memcpy(buf, s, len);
|
||||
break;
|
||||
case 'B': /* fixed-length string */
|
||||
i = va_arg(ap, int);
|
||||
s = va_arg(ap, char *);
|
||||
len = 4+i;
|
||||
if (bufsize && bufsize >= len) {
|
||||
SIVAL(buf, 0, i);
|
||||
memcpy(buf+4, s, i);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log_fn(tdb, 0,"Unknown tdb_pack format %c in %s\n",
|
||||
c, fmt);
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
buf += len;
|
||||
if (bufsize)
|
||||
bufsize -= len;
|
||||
if (bufsize < 0)
|
||||
bufsize = 0;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
log_fn(tdb, 18,"tdb_pack(%s, %d) -> %d\n",
|
||||
fmt0, bufsize0, (int)PTR_DIFF(buf, buf0));
|
||||
|
||||
return PTR_DIFF(buf, buf0);
|
||||
}
|
||||
|
||||
/****************************************************************************
|
||||
Useful pair of routines for packing/unpacking data consisting of
|
||||
integers and strings.
|
||||
****************************************************************************/
|
||||
|
||||
int tdb_unpack(TDB_CONTEXT *tdb, char *buf, int bufsize, const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
uint8_t *bt;
|
||||
uint16_t *w;
|
||||
uint32_t *d;
|
||||
int len;
|
||||
int *i;
|
||||
void **p;
|
||||
char *s, **b;
|
||||
char c;
|
||||
char *buf0 = buf;
|
||||
const char *fmt0 = fmt;
|
||||
int bufsize0 = bufsize;
|
||||
tdb_log_func log_fn = tdb_log_fn(tdb);
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
while (*fmt) {
|
||||
switch ((c=*fmt++)) {
|
||||
case 'b':
|
||||
len = 1;
|
||||
bt = va_arg(ap, uint8_t *);
|
||||
if (bufsize < len)
|
||||
goto no_space;
|
||||
*bt = SVAL(buf, 0);
|
||||
break;
|
||||
case 'w':
|
||||
len = 2;
|
||||
w = va_arg(ap, uint16_t *);
|
||||
if (bufsize < len)
|
||||
goto no_space;
|
||||
*w = SVAL(buf, 0);
|
||||
break;
|
||||
case 'd':
|
||||
len = 4;
|
||||
d = va_arg(ap, uint32_t *);
|
||||
if (bufsize < len)
|
||||
goto no_space;
|
||||
*d = IVAL(buf, 0);
|
||||
break;
|
||||
case 'p':
|
||||
len = 4;
|
||||
p = va_arg(ap, void **);
|
||||
if (bufsize < len)
|
||||
goto no_space;
|
||||
*p = (void *)IVAL(buf, 0);
|
||||
break;
|
||||
case 'P':
|
||||
s = va_arg(ap,char *);
|
||||
len = strlen(buf) + 1;
|
||||
if (bufsize < len || len > sizeof(pstring))
|
||||
goto no_space;
|
||||
memcpy(s, buf, len);
|
||||
break;
|
||||
case 'f':
|
||||
s = va_arg(ap,char *);
|
||||
len = strlen(buf) + 1;
|
||||
if (bufsize < len || len > sizeof(fstring))
|
||||
goto no_space;
|
||||
memcpy(s, buf, len);
|
||||
break;
|
||||
case 'B':
|
||||
i = va_arg(ap, int *);
|
||||
b = va_arg(ap, char **);
|
||||
len = 4;
|
||||
if (bufsize < len)
|
||||
goto no_space;
|
||||
*i = IVAL(buf, 0);
|
||||
if (! *i) {
|
||||
*b = NULL;
|
||||
break;
|
||||
}
|
||||
len += *i;
|
||||
if (bufsize < len)
|
||||
goto no_space;
|
||||
*b = (char *)malloc(*i);
|
||||
if (! *b)
|
||||
goto no_space;
|
||||
memcpy(*b, buf+4, *i);
|
||||
break;
|
||||
default:
|
||||
log_fn(tdb, 0, "Unknown tdb_unpack format %c in %s\n",
|
||||
c, fmt);
|
||||
|
||||
len = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
buf += len;
|
||||
bufsize -= len;
|
||||
}
|
||||
|
||||
va_end(ap);
|
||||
|
||||
log_fn(tdb, 18, "tdb_unpack(%s, %d) -> %d\n",
|
||||
fmt0, bufsize0, (int)PTR_DIFF(buf, buf0));
|
||||
|
||||
return PTR_DIFF(buf, buf0);
|
||||
|
||||
no_space:
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
|
||||
POSIX NTVFS backend - xattr support using filesystem xattrs
|
||||
|
||||
Copyright (C) Andrew Tridgell 2004
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/filesys.h"
|
||||
#include "lib/util/wrap_xattr.h"
|
||||
|
||||
#if defined(HAVE_XATTR_SUPPORT) && defined(XATTR_ADDITIONAL_OPTIONS)
|
||||
static ssize_t _wrap_darwin_fgetxattr(int fd, const char *name, void *value, size_t size)
|
||||
{
|
||||
return fgetxattr(fd, name, value, size, 0, 0);
|
||||
}
|
||||
static ssize_t _wrap_darwin_getxattr(const char *path, const char *name, void *value, size_t size)
|
||||
{
|
||||
return getxattr(path, name, value, size, 0, 0);
|
||||
}
|
||||
static int _wrap_darwin_fsetxattr(int fd, const char *name, void *value, size_t size, int flags)
|
||||
{
|
||||
return fsetxattr(fd, name, value, size, 0, flags);
|
||||
}
|
||||
static int _wrap_darwin_setxattr(const char *path, const char *name, void *value, size_t size, int flags)
|
||||
{
|
||||
return setxattr(path, name, value, size, 0, flags);
|
||||
}
|
||||
static int _wrap_darwin_fremovexattr(int fd, const char *name)
|
||||
{
|
||||
return fremovexattr(fd, name, 0);
|
||||
}
|
||||
static int _wrap_darwin_removexattr(const char *path, const char *name)
|
||||
{
|
||||
return removexattr(path, name, 0);
|
||||
}
|
||||
#define fgetxattr _wrap_darwin_fgetxattr
|
||||
#define getxattr _wrap_darwin_getxattr
|
||||
#define fsetxattr _wrap_darwin_fsetxattr
|
||||
#define setxattr _wrap_darwin_setxattr
|
||||
#define fremovexattr _wrap_darwin_fremovexattr
|
||||
#define removexattr _wrap_darwin_removexattr
|
||||
#elif !defined(HAVE_XATTR_SUPPORT)
|
||||
static ssize_t _none_fgetxattr(int fd, const char *name, void *value, size_t size)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
static ssize_t _none_getxattr(const char *path, const char *name, void *value, size_t size)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
static int _none_fsetxattr(int fd, const char *name, void *value, size_t size, int flags)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
static int _none_setxattr(const char *path, const char *name, void *value, size_t size, int flags)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
static int _none_fremovexattr(int fd, const char *name)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
static int _none_removexattr(const char *path, const char *name)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
#define fgetxattr _none_fgetxattr
|
||||
#define getxattr _none_getxattr
|
||||
#define fsetxattr _none_fsetxattr
|
||||
#define setxattr _none_setxattr
|
||||
#define fremovexattr _none_fremovexattr
|
||||
#define removexattr _none_removexattr
|
||||
#endif
|
||||
|
||||
_PUBLIC_ ssize_t wrap_fgetxattr(int fd, const char *name, void *value, size_t size)
|
||||
{
|
||||
return fgetxattr(fd, name, value, size);
|
||||
}
|
||||
_PUBLIC_ ssize_t wrap_getxattr(const char *path, const char *name, void *value, size_t size)
|
||||
{
|
||||
return getxattr(path, name, value, size);
|
||||
}
|
||||
_PUBLIC_ int wrap_fsetxattr(int fd, const char *name, void *value, size_t size, int flags)
|
||||
{
|
||||
return fsetxattr(fd, name, value, size, flags);
|
||||
}
|
||||
_PUBLIC_ int wrap_setxattr(const char *path, const char *name, void *value, size_t size, int flags)
|
||||
{
|
||||
return setxattr(path, name, value, size, flags);
|
||||
}
|
||||
_PUBLIC_ int wrap_fremovexattr(int fd, const char *name)
|
||||
{
|
||||
return fremovexattr(fd, name);
|
||||
}
|
||||
_PUBLIC_ int wrap_removexattr(const char *path, const char *name)
|
||||
{
|
||||
return removexattr(path, name);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
dnl ############################################
|
||||
dnl use flistxattr as the key function for having
|
||||
dnl sufficient xattr support for posix xattr backend
|
||||
AC_CHECK_HEADERS(sys/attributes.h attr/xattr.h sys/xattr.h)
|
||||
AC_SEARCH_LIBS_EXT(flistxattr, [attr], XATTR_LIBS)
|
||||
AC_CHECK_FUNC_EXT(flistxattr, $XATTR_LIBS)
|
||||
SMB_EXT_LIB(XATTR,[${XATTR_LIBS}],[${XATTR_CFLAGS}],[${XATTR_CPPFLAGS}],[${XATTR_LDFLAGS}])
|
||||
if test x"$ac_cv_func_ext_flistxattr" = x"yes"; then
|
||||
AC_CACHE_CHECK([whether xattr interface takes additional options], smb_attr_cv_xattr_add_opt,
|
||||
[old_LIBS=$LIBS
|
||||
LIBS="$LIBS $XATTRLIBS"
|
||||
AC_TRY_COMPILE([
|
||||
#include <sys/types.h>
|
||||
#if HAVE_ATTR_XATTR_H
|
||||
#include <attr/xattr.h>
|
||||
#elif HAVE_SYS_XATTR_H
|
||||
#include <sys/xattr.h>
|
||||
#endif
|
||||
#ifndef NULL
|
||||
#define NULL ((void *)0)
|
||||
#endif
|
||||
],[
|
||||
getxattr(NULL, NULL, NULL, 0, 0, 0);
|
||||
],smb_attr_cv_xattr_add_opt=yes,smb_attr_cv_xattr_add_opt=no)
|
||||
LIBS=$old_LIBS])
|
||||
if test x"$smb_attr_cv_xattr_add_opt" = x"yes"; then
|
||||
AC_DEFINE(XATTR_ADDITIONAL_OPTIONS, 1, [xattr functions have additional options])
|
||||
fi
|
||||
AC_DEFINE(HAVE_XATTR_SUPPORT,1,[Whether we have xattr support])
|
||||
SMB_ENABLE(XATTR,YES)
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
stdio replacement
|
||||
Copyright (C) Andrew Tridgell 2001
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file
|
||||
* @brief scalable FILE replacement
|
||||
*/
|
||||
|
||||
/*
|
||||
stdio is very convenient, but on some systems the file descriptor
|
||||
in FILE* is 8 bits, so it fails when more than 255 files are open.
|
||||
|
||||
XFILE replaces stdio. It is less efficient, but at least it works
|
||||
when you have lots of files open
|
||||
|
||||
The main restriction on XFILE is that it doesn't support seeking,
|
||||
and doesn't support O_RDWR. That keeps the code simple.
|
||||
*/
|
||||
|
||||
#include "includes.h"
|
||||
#include "system/filesys.h"
|
||||
|
||||
#define XBUFSIZE BUFSIZ
|
||||
|
||||
static XFILE _x_stdin = { 0, NULL, NULL, XBUFSIZE, 0, O_RDONLY, X_IOFBF, 0 };
|
||||
static XFILE _x_stdout = { 1, NULL, NULL, XBUFSIZE, 0, O_WRONLY, X_IOLBF, 0 };
|
||||
static XFILE _x_stderr = { 2, NULL, NULL, 0, 0, O_WRONLY, X_IONBF, 0 };
|
||||
|
||||
XFILE *x_stdin = &_x_stdin;
|
||||
XFILE *x_stdout = &_x_stdout;
|
||||
XFILE *x_stderr = &_x_stderr;
|
||||
|
||||
#define X_FLAG_EOF 1
|
||||
#define X_FLAG_ERROR 2
|
||||
#define X_FLAG_EINVAL 3
|
||||
|
||||
/** simulate setvbuf() */
|
||||
int x_setvbuf(XFILE *f, char *buf, int mode, size_t size)
|
||||
{
|
||||
x_fflush(f);
|
||||
if (f->bufused) return -1;
|
||||
|
||||
/* on files being read full buffering is the only option */
|
||||
if ((f->open_flags & O_ACCMODE) == O_RDONLY) {
|
||||
mode = X_IOFBF;
|
||||
}
|
||||
|
||||
/* destroy any earlier buffer */
|
||||
SAFE_FREE(f->buf);
|
||||
f->buf = 0;
|
||||
f->bufsize = 0;
|
||||
f->next = NULL;
|
||||
f->bufused = 0;
|
||||
f->buftype = mode;
|
||||
|
||||
if (f->buftype == X_IONBF) return 0;
|
||||
|
||||
/* if buffering then we need some size */
|
||||
if (size == 0) size = XBUFSIZE;
|
||||
|
||||
f->bufsize = size;
|
||||
f->bufused = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* allocate the buffer */
|
||||
static int x_allocate_buffer(XFILE *f)
|
||||
{
|
||||
if (f->buf) return 1;
|
||||
if (f->bufsize == 0) return 0;
|
||||
f->buf = malloc(f->bufsize);
|
||||
if (!f->buf) return 0;
|
||||
f->next = f->buf;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
/** this looks more like open() than fopen(), but that is quite deliberate.
|
||||
I want programmers to *think* about O_EXCL, O_CREAT etc not just
|
||||
get them magically added
|
||||
*/
|
||||
XFILE *x_fopen(const char *fname, int flags, mode_t mode)
|
||||
{
|
||||
XFILE *ret;
|
||||
|
||||
ret = malloc_p(XFILE);
|
||||
if (!ret) return NULL;
|
||||
|
||||
memset(ret, 0, sizeof(XFILE));
|
||||
|
||||
if ((flags & O_ACCMODE) == O_RDWR) {
|
||||
/* we don't support RDWR in XFILE - use file
|
||||
descriptors instead */
|
||||
errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret->open_flags = flags;
|
||||
|
||||
ret->fd = open(fname, flags, mode);
|
||||
if (ret->fd == -1) {
|
||||
SAFE_FREE(ret);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
x_setvbuf(ret, NULL, X_IOFBF, XBUFSIZE);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** simulate fclose() */
|
||||
int x_fclose(XFILE *f)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* make sure we flush any buffered data */
|
||||
x_fflush(f);
|
||||
|
||||
ret = close(f->fd);
|
||||
f->fd = -1;
|
||||
if (f->buf) {
|
||||
/* make sure data can't leak into a later malloc */
|
||||
memset(f->buf, 0, f->bufsize);
|
||||
SAFE_FREE(f->buf);
|
||||
}
|
||||
/* check the file descriptor given to the function is NOT one of the static
|
||||
* descriptor of this libreary or we will free unallocated memory
|
||||
* --sss */
|
||||
if (f != x_stdin && f != x_stdout && f != x_stderr) {
|
||||
SAFE_FREE(f);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** simulate fwrite() */
|
||||
size_t x_fwrite(const void *p, size_t size, size_t nmemb, XFILE *f)
|
||||
{
|
||||
ssize_t ret;
|
||||
size_t total=0;
|
||||
|
||||
/* we might be writing unbuffered */
|
||||
if (f->buftype == X_IONBF ||
|
||||
(!f->buf && !x_allocate_buffer(f))) {
|
||||
ret = write(f->fd, p, size*nmemb);
|
||||
if (ret == -1) return -1;
|
||||
return ret/size;
|
||||
}
|
||||
|
||||
|
||||
while (total < size*nmemb) {
|
||||
size_t n = f->bufsize - f->bufused;
|
||||
n = MIN(n, (size*nmemb)-total);
|
||||
|
||||
if (n == 0) {
|
||||
/* it's full, flush it */
|
||||
x_fflush(f);
|
||||
continue;
|
||||
}
|
||||
|
||||
memcpy(f->buf + f->bufused, total+(const char *)p, n);
|
||||
f->bufused += n;
|
||||
total += n;
|
||||
}
|
||||
|
||||
/* when line buffered we need to flush at the last linefeed. This can
|
||||
flush a bit more than necessary, but that is harmless */
|
||||
if (f->buftype == X_IOLBF && f->bufused) {
|
||||
int i;
|
||||
for (i=(size*nmemb)-1; i>=0; i--) {
|
||||
if (*(i+(const char *)p) == '\n') {
|
||||
x_fflush(f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return total/size;
|
||||
}
|
||||
|
||||
/** thank goodness for asprintf() */
|
||||
int x_vfprintf(XFILE *f, const char *format, va_list ap)
|
||||
{
|
||||
char *p;
|
||||
int len, ret;
|
||||
va_list ap2;
|
||||
|
||||
va_copy(ap2, ap);
|
||||
|
||||
len = vasprintf(&p, format, ap2);
|
||||
if (len <= 0) return len;
|
||||
ret = x_fwrite(p, 1, len, f);
|
||||
SAFE_FREE(p);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int x_fprintf(XFILE *f, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int ret;
|
||||
|
||||
va_start(ap, format);
|
||||
ret = x_vfprintf(f, format, ap);
|
||||
va_end(ap);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* at least fileno() is simple! */
|
||||
int x_fileno(XFILE *f)
|
||||
{
|
||||
return f->fd;
|
||||
}
|
||||
|
||||
/** simulate fflush() */
|
||||
int x_fflush(XFILE *f)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (f->flags & X_FLAG_ERROR) return -1;
|
||||
|
||||
if ((f->open_flags & O_ACCMODE) != O_WRONLY) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (f->bufused == 0) return 0;
|
||||
|
||||
ret = write(f->fd, f->buf, f->bufused);
|
||||
if (ret == -1) return -1;
|
||||
|
||||
f->bufused -= ret;
|
||||
if (f->bufused > 0) {
|
||||
f->flags |= X_FLAG_ERROR;
|
||||
memmove(f->buf, ret + (char *)f->buf, f->bufused);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** simulate setbuffer() */
|
||||
void x_setbuffer(XFILE *f, char *buf, size_t size)
|
||||
{
|
||||
x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, size);
|
||||
}
|
||||
|
||||
/** simulate setbuf() */
|
||||
void x_setbuf(XFILE *f, char *buf)
|
||||
{
|
||||
x_setvbuf(f, buf, buf?X_IOFBF:X_IONBF, XBUFSIZE);
|
||||
}
|
||||
|
||||
/** simulate setlinebuf() */
|
||||
void x_setlinebuf(XFILE *f)
|
||||
{
|
||||
x_setvbuf(f, NULL, X_IOLBF, 0);
|
||||
}
|
||||
|
||||
|
||||
/** simulate feof() */
|
||||
int x_feof(XFILE *f)
|
||||
{
|
||||
if (f->flags & X_FLAG_EOF) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** simulate ferror() */
|
||||
int x_ferror(XFILE *f)
|
||||
{
|
||||
if (f->flags & X_FLAG_ERROR) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fill the read buffer */
|
||||
static void x_fillbuf(XFILE *f)
|
||||
{
|
||||
int n;
|
||||
|
||||
if (f->bufused) return;
|
||||
|
||||
if (!f->buf && !x_allocate_buffer(f)) return;
|
||||
|
||||
n = read(f->fd, f->buf, f->bufsize);
|
||||
if (n <= 0) return;
|
||||
f->bufused = n;
|
||||
f->next = f->buf;
|
||||
}
|
||||
|
||||
/** simulate fgetc() */
|
||||
int x_fgetc(XFILE *f)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (f->flags & (X_FLAG_EOF | X_FLAG_ERROR)) return EOF;
|
||||
|
||||
if (f->bufused == 0) x_fillbuf(f);
|
||||
|
||||
if (f->bufused == 0) {
|
||||
f->flags |= X_FLAG_EOF;
|
||||
return EOF;
|
||||
}
|
||||
|
||||
ret = *(uint8_t *)(f->next);
|
||||
f->next++;
|
||||
f->bufused--;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/** simulate fread */
|
||||
size_t x_fread(void *p, size_t size, size_t nmemb, XFILE *f)
|
||||
{
|
||||
size_t total = 0;
|
||||
while (total < size*nmemb) {
|
||||
int c = x_fgetc(f);
|
||||
if (c == EOF) break;
|
||||
(total+(char *)p)[0] = (char)c;
|
||||
total++;
|
||||
}
|
||||
return total/size;
|
||||
}
|
||||
|
||||
/** simulate fgets() */
|
||||
char *x_fgets(char *s, int size, XFILE *stream)
|
||||
{
|
||||
char *s0 = s;
|
||||
int l = size;
|
||||
while (l>1) {
|
||||
int c = x_fgetc(stream);
|
||||
if (c == EOF) break;
|
||||
*s++ = (char)c;
|
||||
l--;
|
||||
if (c == '\n') break;
|
||||
}
|
||||
if (l==size || x_ferror(stream)) {
|
||||
return 0;
|
||||
}
|
||||
*s = 0;
|
||||
return s0;
|
||||
}
|
||||
|
||||
/**
|
||||
* trivial seek, works only for SEEK_SET and SEEK_END if SEEK_CUR is
|
||||
* set then an error is returned */
|
||||
off_t x_tseek(XFILE *f, off_t offset, int whence)
|
||||
{
|
||||
if (f->flags & X_FLAG_ERROR)
|
||||
return -1;
|
||||
|
||||
/* only SEEK_SET and SEEK_END are supported */
|
||||
/* SEEK_CUR needs internal offset counter */
|
||||
if (whence != SEEK_SET && whence != SEEK_END) {
|
||||
f->flags |= X_FLAG_EINVAL;
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* empty the buffer */
|
||||
switch (f->open_flags & O_ACCMODE) {
|
||||
case O_RDONLY:
|
||||
f->bufused = 0;
|
||||
break;
|
||||
case O_WRONLY:
|
||||
if (x_fflush(f) != 0)
|
||||
return -1;
|
||||
break;
|
||||
default:
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
f->flags &= ~X_FLAG_EOF;
|
||||
return lseek(f->fd, offset, whence);
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
Unix SMB/CIFS implementation.
|
||||
stdio replacement
|
||||
Copyright (C) Andrew Tridgell 2001
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef _XFILE_H_
|
||||
#define _XFILE_H_
|
||||
/*
|
||||
see xfile.c for explanations
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
int fd;
|
||||
char *buf;
|
||||
char *next;
|
||||
int bufsize;
|
||||
int bufused;
|
||||
int open_flags;
|
||||
int buftype;
|
||||
int flags;
|
||||
} XFILE;
|
||||
|
||||
extern XFILE *x_stdin, *x_stdout, *x_stderr;
|
||||
|
||||
/* buffering type */
|
||||
#define X_IOFBF 0
|
||||
#define X_IOLBF 1
|
||||
#define X_IONBF 2
|
||||
|
||||
#define x_getc(f) x_fgetc(f)
|
||||
|
||||
int x_vfprintf(XFILE *f, const char *format, va_list ap) PRINTF_ATTRIBUTE(2, 0);
|
||||
int x_fprintf(XFILE *f, const char *format, ...) PRINTF_ATTRIBUTE(2, 3);
|
||||
#endif /* _XFILE_H_ */
|
||||
Reference in New Issue
Block a user