diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:44:55 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-05 17:44:55 +0000 |
commit | bfe2e03d5ecddce1b9666a58a57e66078a737ea1 (patch) | |
tree | 4a4130aca118d9aaaf1494e0e6a5015a0aa409b5 /lib | |
parent | Initial commit. (diff) | |
download | tevent-upstream.tar.xz tevent-upstream.zip |
Adding upstream version 0.14.1.upstream/0.14.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
155 files changed, 28879 insertions, 0 deletions
diff --git a/lib/replace/.checker_innocent b/lib/replace/.checker_innocent new file mode 100644 index 0000000..e619176 --- /dev/null +++ b/lib/replace/.checker_innocent @@ -0,0 +1,4 @@ +>>>MISTAKE21_create_files_6a9e68ada99a97cb +>>>MISTAKE21_os2_delete_9b2bfa7f38711d09 +>>>MISTAKE21_os2_delete_2fcc29aaa99a97cb +>>>SECURITY2_os2_delete_9b2bfa7f1c9396ca diff --git a/lib/replace/Makefile b/lib/replace/Makefile new file mode 100644 index 0000000..a123a37 --- /dev/null +++ b/lib/replace/Makefile @@ -0,0 +1,64 @@ +# simple makefile wrapper to run waf + +WAF_BINARY=$(PYTHON) ../../buildtools/bin/waf +WAF=PYTHONHASHSEED=1 WAF_MAKE=1 $(WAF_BINARY) + +all: + $(WAF) build + +install: + $(WAF) install + +uninstall: + $(WAF) uninstall + +test: + $(WAF) test $(TEST_OPTIONS) + +testenv: + $(WAF) test --testenv $(TEST_OPTIONS) + +quicktest: + $(WAF) test --quick $(TEST_OPTIONS) + +dist: + touch .tmplock + WAFLOCK=.tmplock $(WAF) dist + +distcheck: + touch .tmplock + WAFLOCK=.tmplock $(WAF) distcheck + +clean: + $(WAF) clean + +distclean: + $(WAF) distclean + +reconfigure: configure + $(WAF) reconfigure + +show_waf_options: + $(WAF) --help + +# some compatibility make targets +everything: all + +testsuite: all + +check: test + +torture: all + +# this should do an install as well, once install is finished +installcheck: test + +etags: + $(WAF) etags + +ctags: + $(WAF) ctags + +bin/%:: FORCE + $(WAF) --targets=`basename $@` +FORCE: diff --git a/lib/replace/README b/lib/replace/README new file mode 100644 index 0000000..6612eab --- /dev/null +++ b/lib/replace/README @@ -0,0 +1,128 @@ +This subsystem ensures that we can always use a certain core set of +functions and types, that are either provided by the OS or by replacement +functions / definitions in this subsystem. The aim is to try to stick +to POSIX functions in here as much as possible. Convenience functions +that are available on no platform at all belong in other subsystems +(such as LIBUTIL). + +The following functions are guaranteed: + +ftruncate +strlcpy +strlcat +mktime +rename +initgroups +memmove +strdup +setlinebuf +vsyslog +timegm +setenv +unsetenv +strndup +strnlen +waitpid +seteuid +setegid +asprintf +snprintf +vasprintf +vsnprintf +opendir +readdir +telldir +seekdir +clock_gettime +closedir +dlopen +dlclose +dlsym +dlerror +chroot +bzero +strerror +errno +mkdtemp +mkstemp (a secure one!) +pread +pwrite +chown +lchown +readline (the library) +inet_ntoa +inet_ntop +inet_pton +inet_aton +strtoll +strtoull +socketpair +strptime +getaddrinfo +freeaddrinfo +getnameinfo +gai_strerror +getifaddrs +freeifaddrs +utime +utimes +dup2 +link +readlink +symlink +realpath +poll +setproctitle +memset_s + +Types: +bool +socklen_t +uint{8,16,32,64}_t +int{8,16,32,64}_t +intptr_t +sig_atomic_t +blksize_t +blkcnt_t + +Constants: +PATH_NAME_MAX +UINT{16,32,64}_MAX +INT32_MAX +RTLD_LAZY +HOST_NAME_MAX +UINT16_MAX +UINT32_MAX +UINT64_MAX +CHAR_BIT + +Macros: +va_copy +__FUNCTION__ +__FILE__ +__LINE__ +__LINESTR__ +__location__ +__STRING +__STRINGSTRING +MIN +MAX +QSORT_CAST +ZERO_STRUCT +ZERO_STRUCTP +ZERO_STRUCTPN +ZERO_ARRAY +ARRAY_SIZE +PTR_DIFF + +Headers: +stdint.h +stdbool.h + +Optional C keywords: +volatile + +Prerequisites: +memset (for bzero) +syslog (for vsyslog) +mktemp (for mkstemp and mkdtemp) diff --git a/lib/replace/closefrom.c b/lib/replace/closefrom.c new file mode 100644 index 0000000..bef53e4 --- /dev/null +++ b/lib/replace/closefrom.c @@ -0,0 +1,138 @@ +/* + * Unix SMB/CIFS implementation. + * Samba utility functions + * Copyright (C) Volker Lendecke 2016 + * + * ** NOTE! The following LGPL license applies to the replace + * ** library. This does NOT imply that all of Samba is released + * ** under the LGPL + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "replace.h" +#include <dirent.h> +#include <unistd.h> +#include <limits.h> + +static int closefrom_sysconf(int lower) +{ + long max_files, fd; + + max_files = sysconf(_SC_OPEN_MAX); + if (max_files == -1) { + max_files = 65536; + } + + for (fd=lower; fd<max_files; fd++) { + close(fd); + } + + return 0; +} + +static int closefrom_procfs(int lower) +{ + DIR *dirp; + int dir_fd; + struct dirent *dp; + int *fds = NULL; + size_t num_fds = 0; + size_t fd_array_size = 0; + size_t i; + int ret = ENOMEM; + + dirp = opendir("/proc/self/fd"); + if (dirp == NULL) { + return errno; + } + + dir_fd = dirfd(dirp); + if (dir_fd == -1) { + ret = errno; + goto fail; + } + + while ((dp = readdir(dirp)) != NULL) { + char *endptr; + unsigned long long fd; + + errno = 0; + + fd = strtoull(dp->d_name, &endptr, 10); + if ((fd == 0) && (errno == EINVAL)) { + continue; + } + if ((fd == ULLONG_MAX) && (errno == ERANGE)) { + continue; + } + if (*endptr != '\0') { + continue; + } + if (fd == dir_fd) { + continue; + } + if (fd > INT_MAX) { + continue; + } + if (fd < lower) { + continue; + } + + if (num_fds >= (fd_array_size / sizeof(int))) { + void *tmp; + + if (fd_array_size == 0) { + fd_array_size = 16 * sizeof(int); + } else { + if (fd_array_size + fd_array_size < + fd_array_size) { + /* overflow */ + goto fail; + } + fd_array_size = fd_array_size + fd_array_size; + } + + tmp = realloc(fds, fd_array_size); + if (tmp == NULL) { + goto fail; + } + fds = tmp; + } + + fds[num_fds++] = fd; + } + + for (i=0; i<num_fds; i++) { + close(fds[i]); + } + + ret = 0; +fail: + closedir(dirp); + free(fds); + return ret; +} + +int rep_closefrom(int lower) +{ + int ret; + + ret = closefrom_procfs(lower); + if (ret == 0) { + return 0; + } + + return closefrom_sysconf(lower); +} diff --git a/lib/replace/configure b/lib/replace/configure new file mode 100755 index 0000000..af76185 --- /dev/null +++ b/lib/replace/configure @@ -0,0 +1,28 @@ +#!/bin/sh + +PREVPATH=$(dirname $0) + +if [ -f $PREVPATH/../../buildtools/bin/waf ]; then + WAF=../../buildtools/bin/waf +elif [ -f $PREVPATH/buildtools/bin/waf ]; then + WAF=./buildtools/bin/waf +else + echo "replace: Unable to find waf" + exit 1 +fi + +# using JOBS=1 gives maximum compatibility with +# systems like AIX which have broken threading in python +JOBS=1 +export JOBS + +# Make sure we don't have any library preloaded. +unset LD_PRELOAD + +# Make sure we get stable hashes +PYTHONHASHSEED=1 +export PYTHONHASHSEED + +cd . || exit 1 +$PYTHON $WAF configure "$@" || exit 1 +cd $PREVPATH diff --git a/lib/replace/dlfcn.c b/lib/replace/dlfcn.c new file mode 100644 index 0000000..88431ed --- /dev/null +++ b/lib/replace/dlfcn.c @@ -0,0 +1,76 @@ +/* + Unix SMB/CIFS implementation. + Samba system utilities + Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Jeremy Allison 1998-2002 + Copyright (C) Jelmer Vernooij 2006 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" +#ifdef HAVE_DL_H +#include <dl.h> +#endif + +#ifndef HAVE_DLOPEN +#ifdef DLOPEN_TAKES_UNSIGNED_FLAGS +void *rep_dlopen(const char *name, unsigned int flags) +#else +void *rep_dlopen(const char *name, int flags) +#endif +{ +#ifdef HAVE_SHL_LOAD + if (name == NULL) + return PROG_HANDLE; + return (void *)shl_load(name, flags, 0); +#else + return NULL; +#endif +} +#endif + +#ifndef HAVE_DLSYM +void *rep_dlsym(void *handle, const char *symbol) +{ +#ifdef HAVE_SHL_FINDSYM + void *sym_addr; + if (!shl_findsym((shl_t *)&handle, symbol, TYPE_UNDEFINED, &sym_addr)) + return sym_addr; +#endif + return NULL; +} +#endif + +#ifndef HAVE_DLERROR +char *rep_dlerror(void) +{ + return "dynamic loading of objects not supported on this platform"; +} +#endif + +#ifndef HAVE_DLCLOSE +int rep_dlclose(void *handle) +{ +#ifdef HAVE_SHL_CLOSE + return shl_unload((shl_t)handle); +#else + return 0; +#endif +} +#endif diff --git a/lib/replace/getaddrinfo.c b/lib/replace/getaddrinfo.c new file mode 100644 index 0000000..8440d8e --- /dev/null +++ b/lib/replace/getaddrinfo.c @@ -0,0 +1,493 @@ +/* +PostgreSQL Database Management System +(formerly known as Postgres, then as Postgres95) + +Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group + +Portions Copyright (c) 1994, The Regents of the University of California + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose, without fee, and without a written agreement +is hereby granted, provided that the above copyright notice and this paragraph +and the following two paragraphs appear in all copies. + +IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR +DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING +LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, +EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS +ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS +TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +*/ + +/*------------------------------------------------------------------------- + * + * getaddrinfo.c + * Support getaddrinfo() on platforms that don't have it. + * + * We also supply getnameinfo() here, assuming that the platform will have + * it if and only if it has getaddrinfo(). If this proves false on some + * platform, we'll need to split this file and provide a separate configure + * test for getnameinfo(). + * + * Copyright (c) 2003-2007, PostgreSQL Global Development Group + * + * Copyright (C) 2007 Jeremy Allison. + * Modified to return multiple IPv4 addresses for Samba. + * + *------------------------------------------------------------------------- + */ + +#include "replace.h" +#include "system/network.h" + +#ifndef SMB_MALLOC +#define SMB_MALLOC(s) malloc(s) +#endif + +#ifndef SMB_STRDUP +#define SMB_STRDUP(s) strdup(s) +#endif + +static int check_hostent_err(struct hostent *hp) +{ + if (!hp) { + switch (h_errno) { + case HOST_NOT_FOUND: + case NO_DATA: + return EAI_NONAME; + case TRY_AGAIN: + return EAI_AGAIN; + case NO_RECOVERY: + default: + return EAI_FAIL; + } + } + if (!hp->h_name || hp->h_addrtype != AF_INET) { + return EAI_FAIL; + } + return 0; +} + +static char *canon_name_from_hostent(struct hostent *hp, + int *perr) +{ + char *ret = NULL; + + *perr = check_hostent_err(hp); + if (*perr) { + return NULL; + } + ret = SMB_STRDUP(hp->h_name); + if (!ret) { + *perr = EAI_MEMORY; + } + return ret; +} + +static char *get_my_canon_name(int *perr) +{ + char name[HOST_NAME_MAX+1]; + + if (gethostname(name, HOST_NAME_MAX) == -1) { + *perr = EAI_FAIL; + return NULL; + } + /* Ensure null termination. */ + name[HOST_NAME_MAX] = '\0'; + return canon_name_from_hostent(gethostbyname(name), perr); +} + +static char *get_canon_name_from_addr(struct in_addr ip, + int *perr) +{ + return canon_name_from_hostent( + gethostbyaddr(&ip, sizeof(ip), AF_INET), + perr); +} + +static struct addrinfo *alloc_entry(const struct addrinfo *hints, + struct in_addr ip, + unsigned short port) +{ + struct sockaddr_in *psin = NULL; + struct addrinfo *ai = SMB_MALLOC(sizeof(*ai)); + + if (!ai) { + return NULL; + } + memset(ai, '\0', sizeof(*ai)); + + psin = SMB_MALLOC(sizeof(*psin)); + if (!psin) { + free(ai); + return NULL; + } + + memset(psin, '\0', sizeof(*psin)); + + psin->sin_family = AF_INET; + psin->sin_port = htons(port); + psin->sin_addr = ip; + + ai->ai_flags = 0; + ai->ai_family = AF_INET; + ai->ai_socktype = hints->ai_socktype; + ai->ai_protocol = hints->ai_protocol; + ai->ai_addrlen = sizeof(*psin); + ai->ai_addr = (struct sockaddr *) psin; + ai->ai_canonname = NULL; + ai->ai_next = NULL; + + return ai; +} + +/* + * get address info for a single ipv4 address. + * + * Bugs: - servname can only be a number, not text. + */ + +static int getaddr_info_single_addr(const char *service, + uint32_t addr, + const struct addrinfo *hints, + struct addrinfo **res) +{ + + struct addrinfo *ai = NULL; + struct in_addr ip; + unsigned short port = 0; + + if (service) { + port = (unsigned short)atoi(service); + } + ip.s_addr = htonl(addr); + + ai = alloc_entry(hints, ip, port); + if (!ai) { + return EAI_MEMORY; + } + + /* If we're asked for the canonical name, + * make sure it returns correctly. */ + if (!(hints->ai_flags & AI_NUMERICSERV) && + hints->ai_flags & AI_CANONNAME) { + int err; + if (addr == INADDR_LOOPBACK || addr == INADDR_ANY) { + ai->ai_canonname = get_my_canon_name(&err); + } else { + ai->ai_canonname = + get_canon_name_from_addr(ip,&err); + } + if (ai->ai_canonname == NULL) { + freeaddrinfo(ai); + return err; + } + } + + *res = ai; + return 0; +} + +/* + * get address info for multiple ipv4 addresses. + * + * Bugs: - servname can only be a number, not text. + */ + +static int getaddr_info_name(const char *node, + const char *service, + const struct addrinfo *hints, + struct addrinfo **res) +{ + struct addrinfo *listp = NULL, *prevp = NULL; + char **pptr = NULL; + int err; + struct hostent *hp = NULL; + unsigned short port = 0; + + if (service) { + port = (unsigned short)atoi(service); + } + + hp = gethostbyname(node); + err = check_hostent_err(hp); + if (err) { + return err; + } + + for(pptr = hp->h_addr_list; *pptr; pptr++) { + struct in_addr ip = *(struct in_addr *)*pptr; + struct addrinfo *ai = alloc_entry(hints, ip, port); + + if (!ai) { + freeaddrinfo(listp); + return EAI_MEMORY; + } + + if (!listp) { + listp = ai; + prevp = ai; + ai->ai_canonname = SMB_STRDUP(hp->h_name); + if (!ai->ai_canonname) { + freeaddrinfo(listp); + return EAI_MEMORY; + } + } else { + prevp->ai_next = ai; + prevp = ai; + } + } + *res = listp; + return 0; +} + +/* + * get address info for ipv4 sockets. + * + * Bugs: - servname can only be a number, not text. + */ + +int rep_getaddrinfo(const char *node, + const char *service, + const struct addrinfo * hintp, + struct addrinfo ** res) +{ + struct addrinfo hints; + + /* Setup the hints struct. */ + if (hintp == NULL) { + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_STREAM; + } else { + memcpy(&hints, hintp, sizeof(hints)); + } + + if (hints.ai_family != AF_INET && hints.ai_family != AF_UNSPEC) { + return EAI_FAMILY; + } + + if (hints.ai_socktype == 0) { + hints.ai_socktype = SOCK_STREAM; + } + + if (!node && !service) { + return EAI_NONAME; + } + + if (node) { + if (node[0] == '\0') { + return getaddr_info_single_addr(service, + INADDR_ANY, + &hints, + res); + } else if (hints.ai_flags & AI_NUMERICHOST) { + struct in_addr ip; + if (!inet_aton(node, &ip)) { + return EAI_FAIL; + } + return getaddr_info_single_addr(service, + ntohl(ip.s_addr), + &hints, + res); + } else { + return getaddr_info_name(node, + service, + &hints, + res); + } + } else if (hints.ai_flags & AI_PASSIVE) { + return getaddr_info_single_addr(service, + INADDR_ANY, + &hints, + res); + } + return getaddr_info_single_addr(service, + INADDR_LOOPBACK, + &hints, + res); +} + + +void rep_freeaddrinfo(struct addrinfo *res) +{ + struct addrinfo *next = NULL; + + for (;res; res = next) { + next = res->ai_next; + free(res->ai_canonname); + free(res->ai_addr); + free(res); + } +} + + +const char *rep_gai_strerror(int errcode) +{ +#ifdef HAVE_HSTRERROR + int hcode; + + switch (errcode) + { + case EAI_NONAME: + hcode = HOST_NOT_FOUND; + break; + case EAI_AGAIN: + hcode = TRY_AGAIN; + break; + case EAI_FAIL: + default: + hcode = NO_RECOVERY; + break; + } + + return hstrerror(hcode); +#else /* !HAVE_HSTRERROR */ + + switch (errcode) + { + case EAI_NONAME: + return "Unknown host"; + case EAI_AGAIN: + return "Host name lookup failure"; +#ifdef EAI_BADFLAGS + case EAI_BADFLAGS: + return "Invalid argument"; +#endif +#ifdef EAI_FAMILY + case EAI_FAMILY: + return "Address family not supported"; +#endif +#ifdef EAI_MEMORY + case EAI_MEMORY: + return "Not enough memory"; +#endif +#ifdef EAI_NODATA + case EAI_NODATA: + return "No host data of that type was found"; +#endif +#ifdef EAI_SERVICE + case EAI_SERVICE: + return "Class type not found"; +#endif +#ifdef EAI_SOCKTYPE + case EAI_SOCKTYPE: + return "Socket type not supported"; +#endif + default: + return "Unknown server error"; + } +#endif /* HAVE_HSTRERROR */ +} + +static int gethostnameinfo(const struct sockaddr *sa, + char *node, + size_t nodelen, + int flags) +{ + int ret = -1; + char *p = NULL; + + if (!(flags & NI_NUMERICHOST)) { + struct hostent *hp = gethostbyaddr( + &((struct sockaddr_in *)sa)->sin_addr, + sizeof(struct in_addr), + sa->sa_family); + ret = check_hostent_err(hp); + if (ret == 0) { + /* Name looked up successfully. */ + ret = snprintf(node, nodelen, "%s", hp->h_name); + if (ret < 0 || (size_t)ret >= nodelen) { + return EAI_MEMORY; + } + if (flags & NI_NOFQDN) { + p = strchr(node,'.'); + if (p) { + *p = '\0'; + } + } + return 0; + } + + if (flags & NI_NAMEREQD) { + /* If we require a name and didn't get one, + * automatically fail. */ + return ret; + } + /* Otherwise just fall into the numeric host code... */ + } + p = inet_ntoa(((struct sockaddr_in *)sa)->sin_addr); + ret = snprintf(node, nodelen, "%s", p); + if (ret < 0 || (size_t)ret >= nodelen) { + return EAI_MEMORY; + } + return 0; +} + +static int getservicenameinfo(const struct sockaddr *sa, + char *service, + size_t servicelen, + int flags) +{ + int ret = -1; + int port = ntohs(((struct sockaddr_in *)sa)->sin_port); + + if (!(flags & NI_NUMERICSERV)) { + struct servent *se = getservbyport( + port, + (flags & NI_DGRAM) ? "udp" : "tcp"); + if (se && se->s_name) { + /* Service name looked up successfully. */ + ret = snprintf(service, servicelen, "%s", se->s_name); + if (ret < 0 || (size_t)ret >= servicelen) { + return EAI_MEMORY; + } + return 0; + } + /* Otherwise just fall into the numeric service code... */ + } + ret = snprintf(service, servicelen, "%d", port); + if (ret < 0 || (size_t)ret >= servicelen) { + return EAI_MEMORY; + } + return 0; +} + +/* + * Convert an ipv4 address to a hostname. + * + * Bugs: - No IPv6 support. + */ +int rep_getnameinfo(const struct sockaddr *sa, socklen_t salen, + char *node, size_t nodelen, + char *service, size_t servicelen, int flags) +{ + + /* Invalid arguments. */ + if (sa == NULL || (node == NULL && service == NULL)) { + return EAI_FAIL; + } + + if (sa->sa_family != AF_INET) { + return EAI_FAIL; + } + + if (salen < sizeof(struct sockaddr_in)) { + return EAI_FAIL; + } + + if (node) { + return gethostnameinfo(sa, node, nodelen, flags); + } + + if (service) { + return getservicenameinfo(sa, service, servicelen, flags); + } + return 0; +} diff --git a/lib/replace/getaddrinfo.h b/lib/replace/getaddrinfo.h new file mode 100644 index 0000000..cf040da --- /dev/null +++ b/lib/replace/getaddrinfo.h @@ -0,0 +1,91 @@ +/* +PostgreSQL Database Management System +(formerly known as Postgres, then as Postgres95) + +Portions Copyright (c) 1996-2005, The PostgreSQL Global Development Group + +Portions Copyright (c) 1994, The Regents of the University of California + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose, without fee, and without a written agreement +is hereby granted, provided that the above copyright notice and this paragraph +and the following two paragraphs appear in all copies. + +IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR +DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING +LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, +EVEN IF THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGE. + +THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES, +INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS +ON AN "AS IS" BASIS, AND THE UNIVERSITY OF CALIFORNIA HAS NO OBLIGATIONS +TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. + +*/ + +/*------------------------------------------------------------------------- + * + * getaddrinfo.h + * Support getaddrinfo() on platforms that don't have it. + * + * Note: we use our own routines on platforms that don't HAVE_STRUCT_ADDRINFO, + * whether or not the library routine getaddrinfo() can be found. This + * policy is needed because on some platforms a manually installed libbind.a + * may provide getaddrinfo(), yet the system headers may not provide the + * struct definitions needed to call it. To avoid conflict with the libbind + * definition in such cases, we rename our routines to pg_xxx() via macros. + * + +in lib/replace we use rep_xxx() + + * This code will also work on platforms where struct addrinfo is defined + * in the system headers but no getaddrinfo() can be located. + * + * Copyright (c) 2003-2007, PostgreSQL Global Development Group + * + *------------------------------------------------------------------------- + */ +#ifndef GETADDRINFO_H +#define GETADDRINFO_H + +#ifndef HAVE_GETADDRINFO + +/* Rename private copies per comments above */ +#ifdef getaddrinfo +#undef getaddrinfo +#endif +#define getaddrinfo rep_getaddrinfo +#define HAVE_GETADDRINFO + +#ifdef freeaddrinfo +#undef freeaddrinfo +#endif +#define freeaddrinfo rep_freeaddrinfo +#define HAVE_FREEADDRINFO + +#ifdef gai_strerror +#undef gai_strerror +#endif +#define gai_strerror rep_gai_strerror +#define HAVE_GAI_STRERROR + +#ifdef getnameinfo +#undef getnameinfo +#endif +#define getnameinfo rep_getnameinfo +#ifndef HAVE_GETNAMEINFO +#define HAVE_GETNAMEINFO +#endif + +extern int rep_getaddrinfo(const char *node, const char *service, + const struct addrinfo * hints, struct addrinfo ** res); +extern void rep_freeaddrinfo(struct addrinfo * res); +extern const char *rep_gai_strerror(int errcode); +extern int rep_getnameinfo(const struct sockaddr * sa, socklen_t salen, + char *node, size_t nodelen, + char *service, size_t servicelen, int flags); +#endif /* HAVE_GETADDRINFO */ + +#endif /* GETADDRINFO_H */ diff --git a/lib/replace/getifaddrs.c b/lib/replace/getifaddrs.c new file mode 100644 index 0000000..a55ef7e --- /dev/null +++ b/lib/replace/getifaddrs.c @@ -0,0 +1,383 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + Copyright (C) Andrew Tridgell 1998 + Copyright (C) Jeremy Allison 2007 + Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" +#include "system/network.h" + +#include <unistd.h> +#include <stdio.h> +#include <sys/types.h> + +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif + +#ifndef SIOCGIFCONF +#ifdef HAVE_SYS_SOCKIO_H +#include <sys/sockio.h> +#endif +#endif + +#ifdef HAVE_IFACE_GETIFADDRS +#define _FOUND_IFACE_ANY +#else + +void rep_freeifaddrs(struct ifaddrs *ifp) +{ + if (ifp != NULL) { + free(ifp->ifa_name); + free(ifp->ifa_addr); + free(ifp->ifa_netmask); + free(ifp->ifa_dstaddr); + freeifaddrs(ifp->ifa_next); + free(ifp); + } +} + +static struct sockaddr *sockaddr_dup(struct sockaddr *sa) +{ + struct sockaddr *ret; + socklen_t socklen; +#ifdef HAVE_SOCKADDR_SA_LEN + socklen = sa->sa_len; +#else + socklen = sizeof(struct sockaddr_storage); +#endif + ret = calloc(1, socklen); + if (ret == NULL) + return NULL; + memcpy(ret, sa, socklen); + return ret; +} +#endif + +#ifdef HAVE_IFACE_IFCONF + +/* this works for Linux 2.2, Solaris 2.5, SunOS4, HPUX 10.20, OSF1 + V4.0, Ultrix 4.4, SCO Unix 3.2, IRIX 6.4 and FreeBSD 3.2. + + It probably also works on any BSD style system. */ + +int rep_getifaddrs(struct ifaddrs **ifap) +{ + struct ifconf ifc; + char buff[8192]; + int fd, i, n; + struct ifreq *ifr=NULL; + struct ifaddrs *curif; + struct ifaddrs *lastif = NULL; + + *ifap = NULL; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + return -1; + } + + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + + if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) { + close(fd); + return -1; + } + + ifr = ifc.ifc_req; + + n = ifc.ifc_len / sizeof(struct ifreq); + + /* Loop through interfaces, looking for given IP address */ + for (i=n-1; i>=0; i--) { + if (ioctl(fd, SIOCGIFFLAGS, &ifr[i]) == -1) { + freeifaddrs(*ifap); + close(fd); + return -1; + } + + curif = calloc(1, sizeof(struct ifaddrs)); + if (curif == NULL) { + freeifaddrs(*ifap); + close(fd); + return -1; + } + curif->ifa_name = strdup(ifr[i].ifr_name); + if (curif->ifa_name == NULL) { + free(curif); + freeifaddrs(*ifap); + close(fd); + return -1; + } + curif->ifa_flags = ifr[i].ifr_flags; + curif->ifa_dstaddr = NULL; + curif->ifa_data = NULL; + curif->ifa_next = NULL; + + curif->ifa_addr = NULL; + if (ioctl(fd, SIOCGIFADDR, &ifr[i]) != -1) { + curif->ifa_addr = sockaddr_dup(&ifr[i].ifr_addr); + if (curif->ifa_addr == NULL) { + free(curif->ifa_name); + free(curif); + freeifaddrs(*ifap); + close(fd); + return -1; + } + } + + curif->ifa_netmask = NULL; + if (ioctl(fd, SIOCGIFNETMASK, &ifr[i]) != -1) { + curif->ifa_netmask = sockaddr_dup(&ifr[i].ifr_addr); + if (curif->ifa_netmask == NULL) { + if (curif->ifa_addr != NULL) { + free(curif->ifa_addr); + } + free(curif->ifa_name); + free(curif); + freeifaddrs(*ifap); + close(fd); + return -1; + } + } + + if (lastif == NULL) { + *ifap = curif; + } else { + lastif->ifa_next = curif; + } + lastif = curif; + } + + close(fd); + + return 0; +} + +#define _FOUND_IFACE_ANY +#endif /* HAVE_IFACE_IFCONF */ +#ifdef HAVE_IFACE_IFREQ + +#ifndef I_STR +#include <sys/stropts.h> +#endif + +/**************************************************************************** +this should cover most of the streams based systems +Thanks to Andrej.Borsenkow@mow.siemens.ru for several ideas in this code +****************************************************************************/ +int rep_getifaddrs(struct ifaddrs **ifap) +{ + struct ifreq ifreq; + struct strioctl strioctl; + char buff[8192]; + int fd, i, n; + struct ifreq *ifr=NULL; + struct ifaddrs *curif; + struct ifaddrs *lastif = NULL; + + *ifap = NULL; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + return -1; + } + + strioctl.ic_cmd = SIOCGIFCONF; + strioctl.ic_dp = buff; + strioctl.ic_len = sizeof(buff); + if (ioctl(fd, I_STR, &strioctl) < 0) { + close(fd); + return -1; + } + + /* we can ignore the possible sizeof(int) here as the resulting + number of interface structures won't change */ + n = strioctl.ic_len / sizeof(struct ifreq); + + /* we will assume that the kernel returns the length as an int + at the start of the buffer if the offered size is a + multiple of the structure size plus an int */ + if (n*sizeof(struct ifreq) + sizeof(int) == strioctl.ic_len) { + ifr = (struct ifreq *)(buff + sizeof(int)); + } else { + ifr = (struct ifreq *)buff; + } + + /* Loop through interfaces */ + + for (i = 0; i<n; i++) { + ifreq = ifr[i]; + + curif = calloc(1, sizeof(struct ifaddrs)); + if (lastif == NULL) { + *ifap = curif; + } else { + lastif->ifa_next = curif; + } + + strioctl.ic_cmd = SIOCGIFFLAGS; + strioctl.ic_dp = (char *)&ifreq; + strioctl.ic_len = sizeof(struct ifreq); + if (ioctl(fd, I_STR, &strioctl) != 0) { + freeifaddrs(*ifap); + return -1; + } + + curif->ifa_flags = ifreq.ifr_flags; + + strioctl.ic_cmd = SIOCGIFADDR; + strioctl.ic_dp = (char *)&ifreq; + strioctl.ic_len = sizeof(struct ifreq); + if (ioctl(fd, I_STR, &strioctl) != 0) { + freeifaddrs(*ifap); + return -1; + } + + curif->ifa_name = strdup(ifreq.ifr_name); + curif->ifa_addr = sockaddr_dup(&ifreq.ifr_addr); + curif->ifa_dstaddr = NULL; + curif->ifa_data = NULL; + curif->ifa_next = NULL; + curif->ifa_netmask = NULL; + + strioctl.ic_cmd = SIOCGIFNETMASK; + strioctl.ic_dp = (char *)&ifreq; + strioctl.ic_len = sizeof(struct ifreq); + if (ioctl(fd, I_STR, &strioctl) != 0) { + freeifaddrs(*ifap); + return -1; + } + + curif->ifa_netmask = sockaddr_dup(&ifreq.ifr_addr); + + lastif = curif; + } + + close(fd); + + return 0; +} + +#define _FOUND_IFACE_ANY +#endif /* HAVE_IFACE_IFREQ */ +#ifdef HAVE_IFACE_AIX + +/**************************************************************************** +this one is for AIX (tested on 4.2) +****************************************************************************/ +int rep_getifaddrs(struct ifaddrs **ifap) +{ + char buff[8192]; + int fd, i; + struct ifconf ifc; + struct ifreq *ifr=NULL; + struct ifaddrs *curif; + struct ifaddrs *lastif = NULL; + + *ifap = NULL; + + if ((fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { + return -1; + } + + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + + if (ioctl(fd, SIOCGIFCONF, &ifc) != 0) { + close(fd); + return -1; + } + + ifr = ifc.ifc_req; + + /* Loop through interfaces */ + i = ifc.ifc_len; + + while (i > 0) { + unsigned int inc; + + inc = ifr->ifr_addr.sa_len; + + if (ioctl(fd, SIOCGIFADDR, ifr) != 0) { + freeaddrinfo(*ifap); + return -1; + } + + curif = calloc(1, sizeof(struct ifaddrs)); + if (lastif == NULL) { + *ifap = curif; + } else { + lastif->ifa_next = curif; + } + + curif->ifa_name = strdup(ifr->ifr_name); + curif->ifa_addr = sockaddr_dup(&ifr->ifr_addr); + curif->ifa_dstaddr = NULL; + curif->ifa_data = NULL; + curif->ifa_netmask = NULL; + curif->ifa_next = NULL; + + if (ioctl(fd, SIOCGIFFLAGS, ifr) != 0) { + freeaddrinfo(*ifap); + return -1; + } + + curif->ifa_flags = ifr->ifr_flags; + + if (ioctl(fd, SIOCGIFNETMASK, ifr) != 0) { + freeaddrinfo(*ifap); + return -1; + } + + curif->ifa_netmask = sockaddr_dup(&ifr->ifr_addr); + + lastif = curif; + + next: + /* + * Patch from Archie Cobbs (archie@whistle.com). The + * addresses in the SIOCGIFCONF interface list have a + * minimum size. Usually this doesn't matter, but if + * your machine has tunnel interfaces, etc. that have + * a zero length "link address", this does matter. */ + + if (inc < sizeof(ifr->ifr_addr)) + inc = sizeof(ifr->ifr_addr); + inc += IFNAMSIZ; + + ifr = (struct ifreq*) (((char*) ifr) + inc); + i -= inc; + } + + close(fd); + return 0; +} + +#define _FOUND_IFACE_ANY +#endif /* HAVE_IFACE_AIX */ +#ifndef _FOUND_IFACE_ANY +int rep_getifaddrs(struct ifaddrs **ifap) +{ + errno = ENOSYS; + return -1; +} +#endif diff --git a/lib/replace/hdr_replace.h b/lib/replace/hdr_replace.h new file mode 100644 index 0000000..6cfa50f --- /dev/null +++ b/lib/replace/hdr_replace.h @@ -0,0 +1,2 @@ +/* this is a replacement header for a missing system header */ +#include "replace.h" diff --git a/lib/replace/inet_aton.c b/lib/replace/inet_aton.c new file mode 100644 index 0000000..c6b3bb1 --- /dev/null +++ b/lib/replace/inet_aton.c @@ -0,0 +1,33 @@ +/* + * Unix SMB/CIFS implementation. + * replacement functions + * Copyright (C) Michael Adam <obnox@samba.org> 2008 + * + * ** NOTE! The following LGPL license applies to the replace + * ** library. This does NOT imply that all of Samba is released + * ** under the LGPL + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "replace.h" +#include "system/network.h" + +/** + * We know that we have inet_pton from earlier libreplace checks. + */ +int rep_inet_aton(const char *src, struct in_addr *dst) +{ + return (inet_pton(AF_INET, src, dst) > 0) ? 1 : 0; +} diff --git a/lib/replace/inet_ntoa.c b/lib/replace/inet_ntoa.c new file mode 100644 index 0000000..e3b80eb --- /dev/null +++ b/lib/replace/inet_ntoa.c @@ -0,0 +1,39 @@ +/* + * Unix SMB/CIFS implementation. + * replacement routines for broken systems + * Copyright (C) Andrew Tridgell 2003 + * Copyright (C) Michael Adam 2008 + * + * ** NOTE! The following LGPL license applies to the replace + * ** library. This does NOT imply that all of Samba is released + * ** under the LGPL + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "replace.h" +#include "system/network.h" + +/** + * NOTE: this is not thread safe, but it can't be, either + * since it returns a pointer to static memory. + */ +char *rep_inet_ntoa(struct in_addr ip) +{ + uint8_t *p = (uint8_t *)&ip.s_addr; + static char buf[18]; + slprintf(buf, 17, "%d.%d.%d.%d", + (int)p[0], (int)p[1], (int)p[2], (int)p[3]); + return buf; +} diff --git a/lib/replace/inet_ntop.c b/lib/replace/inet_ntop.c new file mode 100644 index 0000000..fb3d8e9 --- /dev/null +++ b/lib/replace/inet_ntop.c @@ -0,0 +1,191 @@ +/* + * Copyright (C) 1996-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +#include "replace.h" +#include "system/network.h" + +#define NS_INT16SZ 2 +#define NS_IN6ADDRSZ 16 + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static const char *inet_ntop4(const unsigned char *src, char *dst, + socklen_t size); + +#ifdef AF_INET6 +static const char *inet_ntop6(const unsigned char *src, char *dst, + socklen_t size); +#endif + +/* char * + * isc_net_ntop(af, src, dst, size) + * convert a network format address to presentation format. + * return: + * pointer to presentation format address (`dst'), or NULL (see errno). + * author: + * Paul Vixie, 1996. + */ +const char * +rep_inet_ntop(int af, const void *src, char *dst, socklen_t size) +{ + switch (af) { + case AF_INET: + return (inet_ntop4(src, dst, size)); +#ifdef AF_INET6 + case AF_INET6: + return (inet_ntop6(src, dst, size)); +#endif + default: + errno = EAFNOSUPPORT; + return (NULL); + } + /* NOTREACHED */ +} + +/* const char * + * inet_ntop4(src, dst, size) + * format an IPv4 address + * return: + * `dst' (as a const) + * notes: + * (1) uses no statics + * (2) takes a unsigned char* not an in_addr as input + * author: + * Paul Vixie, 1996. + */ +static const char * +inet_ntop4(const unsigned char *src, char *dst, socklen_t size) +{ + static const char *fmt = "%u.%u.%u.%u"; + char tmp[sizeof "255.255.255.255"]; + size_t len; + + len = snprintf(tmp, sizeof tmp, fmt, src[0], src[1], src[2], src[3]); + if (len >= size) { + errno = ENOSPC; + return (NULL); + } + memcpy(dst, tmp, len + 1); + + return (dst); +} + +/* const char * + * isc_inet_ntop6(src, dst, size) + * convert IPv6 binary address into presentation (printable) format + * author: + * Paul Vixie, 1996. + */ +#ifdef AF_INET6 +static const char * +inet_ntop6(const unsigned char *src, char *dst, socklen_t size) +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; + struct { int base, len; } best, cur; + unsigned int words[NS_IN6ADDRSZ / NS_INT16SZ]; + int i, inc; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof words); + for (i = 0; i < NS_IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + best.len = 0; + cur.base = -1; + cur.len = 0; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && + (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) { + if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) + return (NULL); + tp += strlen(tp); + break; + } + inc = snprintf(tp, 5, "%x", words[i]); + if (inc >= 5) { + abort(); + } + tp += inc; + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == + (NS_IN6ADDRSZ / NS_INT16SZ)) + *tp++ = ':'; + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t)(tp - tmp) > size) { + errno = ENOSPC; + return (NULL); + } + memcpy(dst, tmp, tp - tmp); + return (dst); +} +#endif /* AF_INET6 */ diff --git a/lib/replace/inet_pton.c b/lib/replace/inet_pton.c new file mode 100644 index 0000000..80e4865 --- /dev/null +++ b/lib/replace/inet_pton.c @@ -0,0 +1,213 @@ +/* + * Copyright (C) 1996-2001 Internet Software Consortium. + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM + * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL + * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, + * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING + * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, + * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "replace.h" +#include "system/network.h" + +#define NS_INT16SZ 2 +#define NS_INADDRSZ 4 +#define NS_IN6ADDRSZ 16 + +/* + * WARNING: Don't even consider trying to compile this on a system where + * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX. + */ + +static int inet_pton4(const char *src, unsigned char *dst); +#ifdef AF_INET6 +static int inet_pton6(const char *src, unsigned char *dst); +#endif + +/* int + * inet_pton(af, src, dst) + * convert from presentation format (which usually means ASCII printable) + * to network format (which is usually some kind of binary format). + * return: + * 1 if the address was valid for the specified address family + * 0 if the address wasn't valid (`dst' is untouched in this case) + * -1 if some other error occurred (`dst' is untouched in this case, too) + * author: + * Paul Vixie, 1996. + */ +int +rep_inet_pton(int af, + const char *src, + void *dst) +{ + switch (af) { + case AF_INET: + return (inet_pton4(src, dst)); +#ifdef AF_INET6 + case AF_INET6: + return (inet_pton6(src, dst)); +#endif + default: + errno = EAFNOSUPPORT; + return (-1); + } + /* NOTREACHED */ +} + +/* int + * inet_pton4(src, dst) + * like inet_aton() but without all the hexadecimal and shorthand. + * return: + * 1 if `src' is a valid dotted quad, else 0. + * notice: + * does not touch `dst' unless it's returning 1. + * author: + * Paul Vixie, 1996. + */ +static int +inet_pton4(src, dst) + const char *src; + unsigned char *dst; +{ + static const char digits[] = "0123456789"; + int saw_digit, octets, ch; + unsigned char tmp[NS_INADDRSZ], *tp; + + saw_digit = 0; + octets = 0; + *(tp = tmp) = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr(digits, ch)) != NULL) { + unsigned int new = *tp * 10 + (pch - digits); + + if (new > 255) + return (0); + *tp = new; + if (! saw_digit) { + if (++octets > 4) + return (0); + saw_digit = 1; + } + } else if (ch == '.' && saw_digit) { + if (octets == 4) + return (0); + *++tp = 0; + saw_digit = 0; + } else + return (0); + } + if (octets < 4) + return (0); + memcpy(dst, tmp, NS_INADDRSZ); + return (1); +} + +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +#ifdef AF_INET6 +static int +inet_pton6(src, dst) + const char *src; + unsigned char *dst; +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + unsigned char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + unsigned int val; + + memset((tp = tmp), '\0', NS_IN6ADDRSZ); + endp = tp + NS_IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return (0); + curtok = src; + saw_xdigit = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) + return (0); + saw_xdigit = 1; + continue; + } + if (ch == ':') { + curtok = src; + if (!saw_xdigit) { + if (colonp) + return (0); + colonp = tp; + continue; + } + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0) { + tp += NS_INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if (saw_xdigit) { + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (unsigned char) (val >> 8) & 0xff; + *tp++ = (unsigned char) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return (0); + memcpy(dst, tmp, NS_IN6ADDRSZ); + return (1); +} +#endif diff --git a/lib/replace/poll.c b/lib/replace/poll.c new file mode 100644 index 0000000..1105617 --- /dev/null +++ b/lib/replace/poll.c @@ -0,0 +1,139 @@ +/* + Unix SMB/CIFS implementation. + poll.c - poll wrapper + + This file is based on code from libssh (LGPLv2.1+ at the time it + was downloaded), thus the following copyrights: + + Copyright (c) 2009-2010 by Andreas Schneider <mail@cynapses.org> + Copyright (c) 2003-2009 by Aris Adamantiadis + Copyright (c) 2009 Aleksandar Kanchev + Copyright (C) Volker Lendecke 2011 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "replace.h" +#include "system/select.h" +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#endif +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + + +int rep_poll(struct pollfd *fds, nfds_t nfds, int timeout) +{ + fd_set rfds, wfds, efds; + struct timeval tv, *ptv; + int max_fd; + int rc; + nfds_t i; + + if ((fds == NULL) && (nfds != 0)) { + errno = EFAULT; + return -1; + } + + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&efds); + + rc = 0; + max_fd = 0; + + /* compute fd_sets and find largest descriptor */ + for (i = 0; i < nfds; i++) { + if ((fds[i].fd < 0) || (fds[i].fd >= FD_SETSIZE)) { + fds[i].revents = POLLNVAL; + continue; + } + + if (fds[i].events & (POLLIN | POLLRDNORM)) { + FD_SET(fds[i].fd, &rfds); + } + if (fds[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND)) { + FD_SET(fds[i].fd, &wfds); + } + if (fds[i].events & (POLLPRI | POLLRDBAND)) { + FD_SET(fds[i].fd, &efds); + } + if (fds[i].fd > max_fd && + (fds[i].events & (POLLIN | POLLOUT | POLLPRI | + POLLRDNORM | POLLRDBAND | + POLLWRNORM | POLLWRBAND))) { + max_fd = fds[i].fd; + } + } + + if (timeout < 0) { + ptv = NULL; + } else { + ptv = &tv; + if (timeout == 0) { + tv.tv_sec = 0; + tv.tv_usec = 0; + } else { + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + } + } + + rc = select(max_fd + 1, &rfds, &wfds, &efds, ptv); + if (rc < 0) { + return -1; + } + + for (rc = 0, i = 0; i < nfds; i++) { + if ((fds[i].fd < 0) || (fds[i].fd >= FD_SETSIZE)) { + continue; + } + + fds[i].revents = 0; + + if (FD_ISSET(fds[i].fd, &rfds)) { + int err = errno; + int available = 0; + int ret; + + /* support for POLLHUP */ + ret = ioctl(fds[i].fd, FIONREAD, &available); + if ((ret == -1) || (available == 0)) { + fds[i].revents |= POLLHUP; + } else { + fds[i].revents |= fds[i].events + & (POLLIN | POLLRDNORM); + } + + errno = err; + } + if (FD_ISSET(fds[i].fd, &wfds)) { + fds[i].revents |= fds[i].events + & (POLLOUT | POLLWRNORM | POLLWRBAND); + } + if (FD_ISSET(fds[i].fd, &efds)) { + fds[i].revents |= fds[i].events + & (POLLPRI | POLLRDBAND); + } + if (fds[i].revents & ~POLLHUP) { + rc++; + } + } + return rc; +} diff --git a/lib/replace/replace-test.h b/lib/replace/replace-test.h new file mode 100644 index 0000000..ed8e75e --- /dev/null +++ b/lib/replace/replace-test.h @@ -0,0 +1,9 @@ +#ifndef __LIB_REPLACE_REPLACE_TEST_H__ +#define __LIB_REPLACE_REPLACE_TEST_H__ + +int libreplace_test_strptime(void); +int test_readdir_os2_delete(void); +int getifaddrs_test(void); + +#endif /* __LIB_REPLACE_REPLACE_TEST_H__ */ + diff --git a/lib/replace/replace-testsuite.h b/lib/replace/replace-testsuite.h new file mode 100644 index 0000000..b28dbec --- /dev/null +++ b/lib/replace/replace-testsuite.h @@ -0,0 +1,10 @@ +#ifndef __LIB_REPLACE_REPLACE_TESTSUITE_H__ +#define __LIB_REPLACE_REPLACE_TESTSUITE_H__ + +#include <stdbool.h> +struct torture_context; + +bool torture_local_replace(struct torture_context *ctx); + +#endif /* __LIB_REPLACE_REPLACE_TESTSUITE_H__ */ + diff --git a/lib/replace/replace.c b/lib/replace/replace.c new file mode 100644 index 0000000..68829f2 --- /dev/null +++ b/lib/replace/replace.c @@ -0,0 +1,1145 @@ +/* + Unix SMB/CIFS implementation. + replacement routines for broken systems + Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Jelmer Vernooij 2005-2008 + Copyright (C) Matthieu Patou 2010 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" + +#include "system/filesys.h" +#include "system/time.h" +#include "system/network.h" +#include "system/passwd.h" +#include "system/syslog.h" +#include "system/locale.h" +#include "system/wait.h" + +#ifdef HAVE_SYS_SYSCALL_H +#include <sys/syscall.h> +#endif + +#ifdef _WIN32 +#define mkdir(d,m) _mkdir(d) +#endif + +void replace_dummy(void); +void replace_dummy(void) {} + +#ifndef HAVE_FTRUNCATE + /******************************************************************* +ftruncate for operating systems that don't have it +********************************************************************/ +int rep_ftruncate(int f, off_t l) +{ +#ifdef HAVE_CHSIZE + return chsize(f,l); +#elif defined(F_FREESP) + struct flock fl; + + fl.l_whence = 0; + fl.l_len = 0; + fl.l_start = l; + fl.l_type = F_WRLCK; + return fcntl(f, F_FREESP, &fl); +#else +#error "you must have a ftruncate function" +#endif +} +#endif /* HAVE_FTRUNCATE */ + + +#ifndef HAVE_STRLCPY +/* + * Like strncpy but does not 0 fill the buffer and always null + * terminates. bufsize is the size of the destination buffer. + * Returns the length of s. + */ +size_t rep_strlcpy(char *d, const char *s, size_t bufsize) +{ + size_t len = strlen(s); + size_t ret = len; + + if (bufsize <= 0) { + return 0; + } + if (len >= bufsize) { + len = bufsize - 1; + } + memcpy(d, s, len); + d[len] = 0; + return ret; +} +#endif + +#ifndef HAVE_STRLCAT +/* like strncat but does not 0 fill the buffer and always null + terminates. bufsize is the length of the buffer, which should + be one more than the maximum resulting string length */ +size_t rep_strlcat(char *d, const char *s, size_t bufsize) +{ + size_t len1 = strnlen(d, bufsize); + size_t len2 = strlen(s); + size_t ret = len1 + len2; + + if (len1+len2 >= bufsize) { + if (bufsize < (len1+1)) { + return ret; + } + len2 = bufsize - (len1+1); + } + if (len2 > 0) { + memcpy(d+len1, s, len2); + d[len1+len2] = 0; + } + return ret; +} +#endif + +#ifndef HAVE_MKTIME +/******************************************************************* +a mktime() replacement for those who don't have it - contributed by +C.A. Lademann <cal@zls.com> +Corrections by richard.kettlewell@kewill.com +********************************************************************/ + +#define MINUTE 60 +#define HOUR 60*MINUTE +#define DAY 24*HOUR +#define YEAR 365*DAY +time_t rep_mktime(struct tm *t) +{ + struct tm *u; + time_t epoch = 0; + int n; + int mon [] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, + y, m, i; + + if(t->tm_year < 70) + return((time_t)-1); + + n = t->tm_year + 1900 - 1; + epoch = (t->tm_year - 70) * YEAR + + ((n / 4 - n / 100 + n / 400) - (1969 / 4 - 1969 / 100 + 1969 / 400)) * DAY; + + y = t->tm_year + 1900; + m = 0; + + for(i = 0; i < t->tm_mon; i++) { + epoch += mon [m] * DAY; + if(m == 1 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) + epoch += DAY; + + if(++m > 11) { + m = 0; + y++; + } + } + + epoch += (t->tm_mday - 1) * DAY; + epoch += t->tm_hour * HOUR + t->tm_min * MINUTE + t->tm_sec; + + if((u = localtime(&epoch)) != NULL) { + t->tm_sec = u->tm_sec; + t->tm_min = u->tm_min; + t->tm_hour = u->tm_hour; + t->tm_mday = u->tm_mday; + t->tm_mon = u->tm_mon; + t->tm_year = u->tm_year; + t->tm_wday = u->tm_wday; + t->tm_yday = u->tm_yday; + t->tm_isdst = u->tm_isdst; + } + + return(epoch); +} +#endif /* !HAVE_MKTIME */ + + +#ifndef HAVE_INITGROUPS +/**************************************************************************** + some systems don't have an initgroups call +****************************************************************************/ +int rep_initgroups(char *name, gid_t id) +{ +#ifndef HAVE_SETGROUPS + /* yikes! no SETGROUPS or INITGROUPS? how can this work? */ + errno = ENOSYS; + return -1; +#else /* HAVE_SETGROUPS */ + +#include <grp.h> + + gid_t *grouplst = NULL; + int max_gr = NGROUPS_MAX; + int ret; + int i,j; + struct group *g; + char *gr; + + if((grouplst = malloc(sizeof(gid_t) * max_gr)) == NULL) { + errno = ENOMEM; + return -1; + } + + grouplst[0] = id; + i = 1; + while (i < max_gr && ((g = (struct group *)getgrent()) != (struct group *)NULL)) { + if (g->gr_gid == id) + continue; + j = 0; + gr = g->gr_mem[0]; + while (gr && (*gr != (char)NULL)) { + if (strcmp(name,gr) == 0) { + grouplst[i] = g->gr_gid; + i++; + gr = (char *)NULL; + break; + } + gr = g->gr_mem[++j]; + } + } + endgrent(); + ret = setgroups(i, grouplst); + free(grouplst); + return ret; +#endif /* HAVE_SETGROUPS */ +} +#endif /* HAVE_INITGROUPS */ + + +#ifndef HAVE_MEMMOVE +/******************************************************************* +safely copies memory, ensuring no overlap problems. +this is only used if the machine does not have its own memmove(). +this is not the fastest algorithm in town, but it will do for our +needs. +********************************************************************/ +void *rep_memmove(void *dest,const void *src,int size) +{ + unsigned long d,s; + int i; + if (dest==src || !size) return(dest); + + d = (unsigned long)dest; + s = (unsigned long)src; + + if ((d >= (s+size)) || (s >= (d+size))) { + /* no overlap */ + memcpy(dest,src,size); + return(dest); + } + + if (d < s) { + /* we can forward copy */ + if (s-d >= sizeof(int) && + !(s%sizeof(int)) && + !(d%sizeof(int)) && + !(size%sizeof(int))) { + /* do it all as words */ + int *idest = (int *)dest; + int *isrc = (int *)src; + size /= sizeof(int); + for (i=0;i<size;i++) idest[i] = isrc[i]; + } else { + /* simplest */ + char *cdest = (char *)dest; + char *csrc = (char *)src; + for (i=0;i<size;i++) cdest[i] = csrc[i]; + } + } else { + /* must backward copy */ + if (d-s >= sizeof(int) && + !(s%sizeof(int)) && + !(d%sizeof(int)) && + !(size%sizeof(int))) { + /* do it all as words */ + int *idest = (int *)dest; + int *isrc = (int *)src; + size /= sizeof(int); + for (i=size-1;i>=0;i--) idest[i] = isrc[i]; + } else { + /* simplest */ + char *cdest = (char *)dest; + char *csrc = (char *)src; + for (i=size-1;i>=0;i--) cdest[i] = csrc[i]; + } + } + return(dest); +} +#endif /* HAVE_MEMMOVE */ + +#ifndef HAVE_STRDUP +/**************************************************************************** +duplicate a string +****************************************************************************/ +char *rep_strdup(const char *s) +{ + size_t len; + char *ret; + + if (!s) return(NULL); + + len = strlen(s)+1; + ret = (char *)malloc(len); + if (!ret) return(NULL); + memcpy(ret,s,len); + return(ret); +} +#endif /* HAVE_STRDUP */ + +#ifndef HAVE_SETLINEBUF +void rep_setlinebuf(FILE *stream) +{ + setvbuf(stream, (char *)NULL, _IOLBF, 0); +} +#endif /* HAVE_SETLINEBUF */ + +#ifndef HAVE_VSYSLOG +#ifdef HAVE_SYSLOG +void rep_vsyslog (int facility_priority, const char *format, va_list arglist) +{ + char *msg = NULL; + vasprintf(&msg, format, arglist); + if (!msg) + return; + syslog(facility_priority, "%s", msg); + free(msg); +} +#endif /* HAVE_SYSLOG */ +#endif /* HAVE_VSYSLOG */ + +#ifndef HAVE_STRNLEN +/** + Some platforms don't have strnlen +**/ + size_t rep_strnlen(const char *s, size_t max) +{ + size_t len; + + for (len = 0; len < max; len++) { + if (s[len] == '\0') { + break; + } + } + return len; +} +#endif + +#ifndef HAVE_STRNDUP +/** + Some platforms don't have strndup. +**/ +char *rep_strndup(const char *s, size_t n) +{ + char *ret; + + n = strnlen(s, n); + ret = malloc(n+1); + if (!ret) + return NULL; + memcpy(ret, s, n); + ret[n] = 0; + + return ret; +} +#endif + +#if !defined(HAVE_WAITPID) && defined(HAVE_WAIT4) +int rep_waitpid(pid_t pid,int *status,int options) +{ + return wait4(pid, status, options, NULL); +} +#endif + +#ifndef HAVE_SETEUID +int rep_seteuid(uid_t euid) +{ +#ifdef HAVE_SETRESUID + return setresuid(-1, euid, -1); +#else + errno = ENOSYS; + return -1; +#endif +} +#endif + +#ifndef HAVE_SETEGID +int rep_setegid(gid_t egid) +{ +#ifdef HAVE_SETRESGID + return setresgid(-1, egid, -1); +#else + errno = ENOSYS; + return -1; +#endif +} +#endif + +/******************************************************************* +os/2 also doesn't have chroot +********************************************************************/ +#ifndef HAVE_CHROOT +int rep_chroot(const char *dname) +{ + errno = ENOSYS; + return -1; +} +#endif + +/***************************************************************** + Possibly replace mkstemp if it is broken. +*****************************************************************/ + +#ifndef HAVE_SECURE_MKSTEMP +int rep_mkstemp(char *template) +{ + /* have a reasonable go at emulating it. Hope that + the system mktemp() isn't completely hopeless */ + mktemp(template); + if (template[0] == 0) + return -1; + return open(template, O_CREAT|O_EXCL|O_RDWR, 0600); +} +#endif + +#ifndef HAVE_MKDTEMP +char *rep_mkdtemp(char *template) +{ + char *dname; + + if ((dname = mktemp(template))) { + if (mkdir(dname, 0700) >= 0) { + return dname; + } + } + + return NULL; +} +#endif + +/***************************************************************** + Watch out: this is not thread safe. +*****************************************************************/ + +#ifndef HAVE_PREAD +ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset) +{ + if (lseek(__fd, __offset, SEEK_SET) != __offset) { + return -1; + } + return read(__fd, __buf, __nbytes); +} +#endif + +/***************************************************************** + Watch out: this is not thread safe. +*****************************************************************/ + +#ifndef HAVE_PWRITE +ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset) +{ + if (lseek(__fd, __offset, SEEK_SET) != __offset) { + return -1; + } + return write(__fd, __buf, __nbytes); +} +#endif + +#ifndef HAVE_STRCASESTR +char *rep_strcasestr(const char *haystack, const char *needle) +{ + const char *s; + size_t nlen = strlen(needle); + for (s=haystack;*s;s++) { + if (toupper(*needle) == toupper(*s) && + strncasecmp(s, needle, nlen) == 0) { + return (char *)((uintptr_t)s); + } + } + return NULL; +} +#endif + +#ifndef HAVE_STRSEP +char *rep_strsep(char **pps, const char *delim) +{ + char *ret = *pps; + char *p = *pps; + + if (p == NULL) { + return NULL; + } + p += strcspn(p, delim); + if (*p == '\0') { + *pps = NULL; + } else { + *p = '\0'; + *pps = p + 1; + } + return ret; +} +#endif + +#ifndef HAVE_STRTOK_R +/* based on GLIBC version, copyright Free Software Foundation */ +char *rep_strtok_r(char *s, const char *delim, char **save_ptr) +{ + char *token; + + if (s == NULL) s = *save_ptr; + + s += strspn(s, delim); + if (*s == '\0') { + *save_ptr = s; + return NULL; + } + + token = s; + s = strpbrk(token, delim); + if (s == NULL) { + *save_ptr = token + strlen(token); + } else { + *s = '\0'; + *save_ptr = s + 1; + } + + return token; +} +#endif + + +#ifndef HAVE_STRTOLL +long long int rep_strtoll(const char *str, char **endptr, int base) +{ +#ifdef HAVE_STRTOQ + return strtoq(str, endptr, base); +#elif defined(HAVE___STRTOLL) + return __strtoll(str, endptr, base); +#elif SIZEOF_LONG == SIZEOF_LONG_LONG + return (long long int) strtol(str, endptr, base); +#else +# error "You need a strtoll function" +#endif +} +#else +#ifdef HAVE_BSD_STRTOLL +#undef strtoll +long long int rep_strtoll(const char *str, char **endptr, int base) +{ + int saved_errno = errno; + long long int nb = strtoll(str, endptr, base); + /* With glibc EINVAL is only returned if base is not ok */ + if (errno == EINVAL) { + if (base == 0 || (base >1 && base <37)) { + /* Base was ok so it's because we were not + * able to make the conversion. + * Let's reset errno. + */ + errno = saved_errno; + } + } + return nb; +} +#endif /* HAVE_BSD_STRTOLL */ +#endif /* HAVE_STRTOLL */ + + +#ifndef HAVE_STRTOULL +unsigned long long int rep_strtoull(const char *str, char **endptr, int base) +{ +#ifdef HAVE_STRTOUQ + return strtouq(str, endptr, base); +#elif defined(HAVE___STRTOULL) + return __strtoull(str, endptr, base); +#elif SIZEOF_LONG == SIZEOF_LONG_LONG + return (unsigned long long int) strtoul(str, endptr, base); +#else +# error "You need a strtoull function" +#endif +} +#else +#ifdef HAVE_BSD_STRTOLL +#undef strtoull +unsigned long long int rep_strtoull(const char *str, char **endptr, int base) +{ + int saved_errno = errno; + unsigned long long int nb = strtoull(str, endptr, base); + /* With glibc EINVAL is only returned if base is not ok */ + if (errno == EINVAL) { + if (base == 0 || (base >1 && base <37)) { + /* Base was ok so it's because we were not + * able to make the conversion. + * Let's reset errno. + */ + errno = saved_errno; + } + } + return nb; +} +#endif /* HAVE_BSD_STRTOLL */ +#endif /* HAVE_STRTOULL */ + +#ifndef HAVE_SETENV +int rep_setenv(const char *name, const char *value, int overwrite) +{ + char *p; + size_t l1, l2; + int ret; + + if (!overwrite && getenv(name)) { + return 0; + } + + l1 = strlen(name); + l2 = strlen(value); + + p = malloc(l1+l2+2); + if (p == NULL) { + return -1; + } + memcpy(p, name, l1); + p[l1] = '='; + memcpy(p+l1+1, value, l2); + p[l1+l2+1] = 0; + + ret = putenv(p); + if (ret != 0) { + free(p); + } + + return ret; +} +#endif + +#ifndef HAVE_UNSETENV +int rep_unsetenv(const char *name) +{ + extern char **environ; + size_t len = strlen(name); + size_t i, count; + + if (environ == NULL || getenv(name) == NULL) { + return 0; + } + + for (i=0;environ[i];i++) /* noop */ ; + + count=i; + + for (i=0;i<count;) { + if (strncmp(environ[i], name, len) == 0 && environ[i][len] == '=') { + /* note: we do _not_ free the old variable here. It is unsafe to + do so, as the pointer may not have come from malloc */ + memmove(&environ[i], &environ[i+1], (count-i)*sizeof(char *)); + count--; + } else { + i++; + } + } + + return 0; +} +#endif + +#ifndef HAVE_UTIME +int rep_utime(const char *filename, const struct utimbuf *buf) +{ + errno = ENOSYS; + return -1; +} +#endif + +#ifndef HAVE_UTIMES +int rep_utimes(const char *filename, const struct timeval tv[2]) +{ + struct utimbuf u; + + u.actime = tv[0].tv_sec; + if (tv[0].tv_usec > 500000) { + u.actime += 1; + } + + u.modtime = tv[1].tv_sec; + if (tv[1].tv_usec > 500000) { + u.modtime += 1; + } + + return utime(filename, &u); +} +#endif + +#ifndef HAVE_DUP2 +int rep_dup2(int oldfd, int newfd) +{ + errno = ENOSYS; + return -1; +} +#endif + +#ifndef HAVE_CHOWN +/** +chown isn't used much but OS/2 doesn't have it +**/ +int rep_chown(const char *fname, uid_t uid, gid_t gid) +{ + errno = ENOSYS; + return -1; +} +#endif + +#ifndef HAVE_LINK +int rep_link(const char *oldpath, const char *newpath) +{ + errno = ENOSYS; + return -1; +} +#endif + +#ifndef HAVE_READLINK +int rep_readlink(const char *path, char *buf, size_t bufsiz) +{ + errno = ENOSYS; + return -1; +} +#endif + +#ifndef HAVE_SYMLINK +int rep_symlink(const char *oldpath, const char *newpath) +{ + errno = ENOSYS; + return -1; +} +#endif + +#ifndef HAVE_LCHOWN +int rep_lchown(const char *fname,uid_t uid,gid_t gid) +{ + errno = ENOSYS; + return -1; +} +#endif + +#ifndef HAVE_REALPATH +char *rep_realpath(const char *path, char *resolved_path) +{ + /* As realpath is not a system call we can't return ENOSYS. */ + errno = EINVAL; + return NULL; +} +#endif + + +#ifndef HAVE_MEMMEM +void *rep_memmem(const void *haystack, size_t haystacklen, + const void *needle, size_t needlelen) +{ + if (needlelen == 0) { + return discard_const(haystack); + } + while (haystacklen >= needlelen) { + char *p = (char *)memchr(haystack, *(const char *)needle, + haystacklen-(needlelen-1)); + if (!p) return NULL; + if (memcmp(p, needle, needlelen) == 0) { + return p; + } + haystack = p+1; + haystacklen -= (p - (const char *)haystack) + 1; + } + return NULL; +} +#endif + +#if !defined(HAVE_VDPRINTF) || !defined(HAVE_C99_VSNPRINTF) +int rep_vdprintf(int fd, const char *format, va_list ap) +{ + char *s = NULL; + int ret; + + vasprintf(&s, format, ap); + if (s == NULL) { + errno = ENOMEM; + return -1; + } + ret = write(fd, s, strlen(s)); + free(s); + return ret; +} +#endif + +#if !defined(HAVE_DPRINTF) || !defined(HAVE_C99_VSNPRINTF) +int rep_dprintf(int fd, const char *format, ...) +{ + int ret; + va_list ap; + + va_start(ap, format); + ret = vdprintf(fd, format, ap); + va_end(ap); + + return ret; +} +#endif + +#ifndef HAVE_GET_CURRENT_DIR_NAME +char *rep_get_current_dir_name(void) +{ + char buf[PATH_MAX+1]; + char *p; + p = getcwd(buf, sizeof(buf)); + if (p == NULL) { + return NULL; + } + return strdup(p); +} +#endif + +#ifndef HAVE_STRERROR_R +int rep_strerror_r(int errnum, char *buf, size_t buflen) +{ + char *s = strerror(errnum); + if (strlen(s)+1 > buflen) { + errno = ERANGE; + return -1; + } + strncpy(buf, s, buflen); + return 0; +} +#elif (!defined(STRERROR_R_XSI_NOT_GNU)) +#undef strerror_r +int rep_strerror_r(int errnum, char *buf, size_t buflen) +{ + char *s = strerror_r(errnum, buf, buflen); + if (s == NULL) { + /* Shouldn't happen, should always get a string */ + return EINVAL; + } + if (s != buf) { + strlcpy(buf, s, buflen); + if (strlen(s) > buflen - 1) { + return ERANGE; + } + } + return 0; + +} +#endif + +#ifndef HAVE_CLOCK_GETTIME +int rep_clock_gettime(clockid_t clk_id, struct timespec *tp) +{ + struct timeval tval; + switch (clk_id) { + case 0: /* CLOCK_REALTIME :*/ +#if defined(HAVE_GETTIMEOFDAY_TZ) || defined(HAVE_GETTIMEOFDAY_TZ_VOID) + gettimeofday(&tval,NULL); +#else + gettimeofday(&tval); +#endif + tp->tv_sec = tval.tv_sec; + tp->tv_nsec = tval.tv_usec * 1000; + break; + default: + errno = EINVAL; + return -1; + } + return 0; +} +#endif + +#ifndef HAVE_MEMALIGN +void *rep_memalign( size_t align, size_t size ) +{ +#if defined(HAVE_POSIX_MEMALIGN) + void *p = NULL; + int ret = posix_memalign( &p, align, size ); + if ( ret == 0 ) + return p; + + return NULL; +#else + /* On *BSD systems memaligns doesn't exist, but memory will + * be aligned on allocations of > pagesize. */ +#if defined(SYSCONF_SC_PAGESIZE) + size_t pagesize = (size_t)sysconf(_SC_PAGESIZE); +#elif defined(HAVE_GETPAGESIZE) + size_t pagesize = (size_t)getpagesize(); +#else + size_t pagesize = (size_t)-1; +#endif + if (pagesize == (size_t)-1) { + errno = ENOSYS; + return NULL; + } + if (size < pagesize) { + size = pagesize; + } + return malloc(size); +#endif +} +#endif + +#ifndef HAVE_GETPEEREID +int rep_getpeereid(int s, uid_t *uid, gid_t *gid) +{ +#if defined(HAVE_PEERCRED) + struct ucred cred; + socklen_t cred_len = sizeof(struct ucred); + int ret; + +#undef getsockopt + ret = getsockopt(s, SOL_SOCKET, SO_PEERCRED, (void *)&cred, &cred_len); + if (ret != 0) { + return -1; + } + + if (cred_len != sizeof(struct ucred)) { + errno = EINVAL; + return -1; + } + + *uid = cred.uid; + *gid = cred.gid; + return 0; +#else + errno = ENOSYS; + return -1; +#endif +} +#endif + +#ifndef HAVE_USLEEP +int rep_usleep(useconds_t sec) +{ + struct timeval tval; + /* + * Fake it with select... + */ + tval.tv_sec = 0; + tval.tv_usec = usecs/1000; + select(0,NULL,NULL,NULL,&tval); + return 0; +} +#endif /* HAVE_USLEEP */ + +#ifndef HAVE_SETPROCTITLE +void rep_setproctitle(const char *fmt, ...) +{ +} +#endif +#ifndef HAVE_SETPROCTITLE_INIT +void rep_setproctitle_init(int argc, char *argv[], char *envp[]) +{ +} +#endif + +#ifndef HAVE_MEMSET_S +# ifndef RSIZE_MAX +# define RSIZE_MAX (SIZE_MAX >> 1) +# endif + +int rep_memset_s(void *dest, size_t destsz, int ch, size_t count) +{ + if (dest == NULL) { + return EINVAL; + } + + if (destsz > RSIZE_MAX || + count > RSIZE_MAX || + count > destsz) { + return ERANGE; + } + +#if defined(HAVE_MEMSET_EXPLICIT) + memset_explicit(dest, destsz, ch, count); +#else /* HAVE_MEMSET_EXPLICIT */ + memset(dest, ch, count); +# if defined(HAVE_GCC_VOLATILE_MEMORY_PROTECTION) + /* See http://llvm.org/bugs/show_bug.cgi?id=15495 */ + __asm__ volatile("" : : "g"(dest) : "memory"); +# endif /* HAVE_GCC_VOLATILE_MEMORY_PROTECTION */ +#endif /* HAVE_MEMSET_EXPLICIT */ + + return 0; +} +#endif /* HAVE_MEMSET_S */ + +#ifndef HAVE_GETPROGNAME +# ifndef HAVE_PROGRAM_INVOCATION_SHORT_NAME +# define PROGNAME_SIZE 32 +static char rep_progname[PROGNAME_SIZE]; +# endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */ + +const char *rep_getprogname(void) +{ +#ifdef HAVE_PROGRAM_INVOCATION_SHORT_NAME + return program_invocation_short_name; +#else /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */ + FILE *fp = NULL; + char cmdline[4096] = {0}; + char *p = NULL; + pid_t pid; + size_t nread; + int len; + int rc; + + if (rep_progname[0] != '\0') { + return rep_progname; + } + + len = snprintf(rep_progname, sizeof(rep_progname), "%s", "<unknown>"); + if (len <= 0) { + return NULL; + } + + pid = getpid(); + if (pid <= 1 || pid == (pid_t)-1) { + return NULL; + } + + len = snprintf(cmdline, + sizeof(cmdline), + "/proc/%u/cmdline", + (unsigned int)pid); + if (len <= 0 || len == sizeof(cmdline)) { + return NULL; + } + + fp = fopen(cmdline, "r"); + if (fp == NULL) { + return NULL; + } + + nread = fread(cmdline, 1, sizeof(cmdline) - 1, fp); + + rc = fclose(fp); + if (rc != 0) { + return NULL; + } + + if (nread == 0) { + return NULL; + } + + cmdline[nread] = '\0'; + + p = strrchr(cmdline, '/'); + if (p != NULL) { + p++; + } else { + p = cmdline; + } + + len = strlen(p); + if (len > PROGNAME_SIZE) { + p[PROGNAME_SIZE - 1] = '\0'; + } + + (void)snprintf(rep_progname, sizeof(rep_progname), "%s", p); + + return rep_progname; +#endif /* HAVE_PROGRAM_INVOCATION_SHORT_NAME */ +} +#endif /* HAVE_GETPROGNAME */ + +#ifndef HAVE_COPY_FILE_RANGE +ssize_t rep_copy_file_range(int fd_in, + loff_t *off_in, + int fd_out, + loff_t *off_out, + size_t len, + unsigned int flags) +{ +# ifdef HAVE_SYSCALL_COPY_FILE_RANGE + return syscall(__NR_copy_file_range, + fd_in, + off_in, + fd_out, + off_out, + len, + flags); +# endif /* HAVE_SYSCALL_COPY_FILE_RANGE */ + errno = ENOSYS; + return -1; +} +#endif /* HAVE_COPY_FILE_RANGE */ + +#ifndef HAVE_OPENAT2 + +/* fallback known wellknown __NR_openat2 values */ +#ifndef __NR_openat2 +# if defined(LINUX) && defined(HAVE_SYS_SYSCALL_H) +# if defined(__i386__) +# define __NR_openat2 437 +# elif defined(__x86_64__) && defined(__LP64__) +# define __NR_openat2 437 /* 437 0x1B5 */ +# elif defined(__x86_64__) && defined(__ILP32__) +# define __NR_openat2 1073742261 /* 1073742261 0x400001B5 */ +# elif defined(__aarch64__) +# define __NR_openat2 437 +# elif defined(__arm__) +# define __NR_openat2 437 +# elif defined(__sparc__) +# define __NR_openat2 437 +# endif +# endif /* defined(LINUX) && defined(HAVE_SYS_SYSCALL_H) */ +#endif /* !__NR_openat2 */ + +#ifdef DISABLE_OPATH +/* + * systems without O_PATH also don't have openat2, + * so make sure we at a realistic combination. + */ +#undef __NR_openat2 +#endif /* DISABLE_OPATH */ + +long rep_openat2(int dirfd, const char *pathname, + struct open_how *how, size_t size) +{ +#ifdef __NR_openat2 +#if _FILE_OFFSET_BITS == 64 && SIZE_MAX == 0xffffffffUL && defined(O_LARGEFILE) + struct open_how __how; + +#if defined(O_PATH) && ! defined(DISABLE_OPATH) + if ((how->flags & O_PATH) == 0) +#endif + { + if (sizeof(__how) == size) { + __how = *how; + + __how.flags |= O_LARGEFILE; + how = &__how; + } + } +#endif + + return syscall(__NR_openat2, + dirfd, + pathname, + how, + size); +#else + errno = ENOSYS; + return -1; +#endif +} +#endif /* !HAVE_OPENAT2 */ diff --git a/lib/replace/replace.h b/lib/replace/replace.h new file mode 100644 index 0000000..b15f3d1 --- /dev/null +++ b/lib/replace/replace.h @@ -0,0 +1,1097 @@ +/* + Unix SMB/CIFS implementation. + + macros to go along with the lib/replace/ portability layer code + + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Jelmer Vernooij 2006-2008 + Copyright (C) Jeremy Allison 2007. + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _LIBREPLACE_REPLACE_H +#define _LIBREPLACE_REPLACE_H + +#ifndef NO_CONFIG_H +#include "config.h" +#endif + +#ifdef HAVE_STANDARDS_H +#include <standards.h> +#endif + +/* + * Needs to be defined before std*.h and string*.h are included + * As it's also needed when Python.h is the first header we + * require a global -D__STDC_WANT_LIB_EXT1__=1 + */ +#ifndef __STDC_WANT_LIB_EXT1__ +#error -D__STDC_WANT_LIB_EXT1__=1 required +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <errno.h> + +#ifndef HAVE_DECL_EWOULDBLOCK +#define EWOULDBLOCK EAGAIN +#endif + +#if defined(_MSC_VER) || defined(__MINGW32__) +#include "win32_replace.h" +#endif + + +#ifdef HAVE_INTTYPES_H +#define __STDC_FORMAT_MACROS +#include <inttypes.h> +#elif defined(HAVE_STDINT_H) +#include <stdint.h> +/* force off HAVE_INTTYPES_H so that roken doesn't try to include both, + which causes a warning storm on irix */ +#undef HAVE_INTTYPES_H +#endif + +#ifdef HAVE_MALLOC_H +#include <malloc.h> +#endif + +#ifndef __PRI64_PREFIX +# if __WORDSIZE == 64 && ! defined __APPLE__ +# define __PRI64_PREFIX "l" +# else +# define __PRI64_PREFIX "ll" +# endif +#endif + +/* Decimal notation. */ +#ifndef PRId8 +# define PRId8 "d" +#endif +#ifndef PRId16 +# define PRId16 "d" +#endif +#ifndef PRId32 +# define PRId32 "d" +#endif +#ifndef PRId64 +# define PRId64 __PRI64_PREFIX "d" +#endif + +#ifndef PRIi8 +# define PRIi8 "i" +#endif +#ifndef PRIi16 +# define PRIi16 "i" +#endif +#ifndef PRIi32 +# define PRIi32 "i" +#endif +#ifndef PRIi64 +# define PRIi64 __PRI64_PREFIX "i" +#endif + +#ifndef PRIu8 +# define PRIu8 "u" +#endif +#ifndef PRIu16 +# define PRIu16 "u" +#endif +#ifndef PRIu32 +# define PRIu32 "u" +#endif +#ifndef PRIu64 +# define PRIu64 __PRI64_PREFIX "u" +#endif + +#ifndef SCNd8 +# define SCNd8 "hhd" +#endif +#ifndef SCNd16 +# define SCNd16 "hd" +#endif +#ifndef SCNd32 +# define SCNd32 "d" +#endif +#ifndef SCNd64 +# define SCNd64 __PRI64_PREFIX "d" +#endif + +#ifndef SCNi8 +# define SCNi8 "hhi" +#endif +#ifndef SCNi16 +# define SCNi16 "hi" +#endif +#ifndef SCNi32 +# define SCNi32 "i" +#endif +#ifndef SCNi64 +# define SCNi64 __PRI64_PREFIX "i" +#endif + +#ifndef SCNu8 +# define SCNu8 "hhu" +#endif +#ifndef SCNu16 +# define SCNu16 "hu" +#endif +#ifndef SCNu32 +# define SCNu32 "u" +#endif +#ifndef SCNu64 +# define SCNu64 __PRI64_PREFIX "u" +#endif + +#ifdef HAVE_BSD_STRING_H +#include <bsd/string.h> +#endif + +#ifdef HAVE_BSD_UNISTD_H +#include <bsd/unistd.h> +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +#ifdef HAVE_STRINGS_H +#include <strings.h> +#endif + +#ifdef HAVE_SYS_TYPES_H +#include <sys/types.h> +#endif + +#ifdef HAVE_SYS_SYSMACROS_H +#include <sys/sysmacros.h> +#endif + +#ifdef HAVE_SETPROCTITLE_H +#include <setproctitle.h> +#endif + +#if STDC_HEADERS +#include <stdlib.h> +#include <stddef.h> +#endif + +#ifdef HAVE_LINUX_TYPES_H +/* + * This is needed as some broken header files require this to be included early + */ +#include <linux/types.h> +#endif + +#ifndef HAVE_STRERROR +extern char *sys_errlist[]; +#define strerror(i) sys_errlist[i] +#endif + +#ifndef HAVE_ERRNO_DECL +extern int errno; +#endif + +#ifndef HAVE_STRDUP +#define strdup rep_strdup +char *rep_strdup(const char *s); +#endif + +#ifndef HAVE_MEMMOVE +#define memmove rep_memmove +void *rep_memmove(void *dest,const void *src,int size); +#endif + +#ifndef HAVE_MEMMEM +#define memmem rep_memmem +void *rep_memmem(const void *haystack, size_t haystacklen, + const void *needle, size_t needlelen); +#endif + +#ifndef HAVE_MEMALIGN +#define memalign rep_memalign +void *rep_memalign(size_t boundary, size_t size); +#endif + +#ifndef HAVE_MKTIME +#define mktime rep_mktime +/* prototype is in "system/time.h" */ +#endif + +#ifndef HAVE_TIMEGM +#define timegm rep_timegm +/* prototype is in "system/time.h" */ +#endif + +#ifndef HAVE_UTIME +#define utime rep_utime +/* prototype is in "system/time.h" */ +#endif + +#ifndef HAVE_UTIMES +#define utimes rep_utimes +/* prototype is in "system/time.h" */ +#endif + +#ifndef HAVE_STRLCPY +#define strlcpy rep_strlcpy +size_t rep_strlcpy(char *d, const char *s, size_t bufsize); +#endif + +#ifndef HAVE_STRLCAT +#define strlcat rep_strlcat +size_t rep_strlcat(char *d, const char *s, size_t bufsize); +#endif + +#ifndef HAVE_CLOSEFROM +#define closefrom rep_closefrom +int rep_closefrom(int lower); +#endif + + +#if (defined(BROKEN_STRNDUP) || !defined(HAVE_STRNDUP)) +#undef HAVE_STRNDUP +#define strndup rep_strndup +char *rep_strndup(const char *s, size_t n); +#endif + +#if (defined(BROKEN_STRNLEN) || !defined(HAVE_STRNLEN)) +#undef HAVE_STRNLEN +#define strnlen rep_strnlen +size_t rep_strnlen(const char *s, size_t n); +#endif + +#if !defined(HAVE_DECL_ENVIRON) +# ifdef __APPLE__ +# include <crt_externs.h> +# define environ (*_NSGetEnviron()) +# else /* __APPLE__ */ +extern char **environ; +# endif /* __APPLE */ +#endif /* !defined(HAVE_DECL_ENVIRON) */ + +#ifndef HAVE_SETENV +#define setenv rep_setenv +int rep_setenv(const char *name, const char *value, int overwrite); +#else +#ifndef HAVE_SETENV_DECL +int setenv(const char *name, const char *value, int overwrite); +#endif +#endif + +#ifndef HAVE_UNSETENV +#define unsetenv rep_unsetenv +int rep_unsetenv(const char *name); +#endif + +#ifndef HAVE_SETEUID +#define seteuid rep_seteuid +int rep_seteuid(uid_t); +#endif + +#ifndef HAVE_SETEGID +#define setegid rep_setegid +int rep_setegid(gid_t); +#endif + +#if (defined(USE_SETRESUID) && !defined(HAVE_SETRESUID_DECL)) +/* stupid glibc */ +int setresuid(uid_t ruid, uid_t euid, uid_t suid); +#endif +#if (defined(USE_SETRESUID) && !defined(HAVE_SETRESGID_DECL)) +int setresgid(gid_t rgid, gid_t egid, gid_t sgid); +#endif + +#ifndef HAVE_CHOWN +#define chown rep_chown +int rep_chown(const char *path, uid_t uid, gid_t gid); +#endif + +#ifndef HAVE_CHROOT +#define chroot rep_chroot +int rep_chroot(const char *dirname); +#endif + +#ifndef HAVE_LINK +#define link rep_link +int rep_link(const char *oldpath, const char *newpath); +#endif + +#ifndef HAVE_READLINK +#define readlink rep_readlink +ssize_t rep_readlink(const char *path, char *buf, size_t bufsize); +#endif + +#ifndef HAVE_SYMLINK +#define symlink rep_symlink +int rep_symlink(const char *oldpath, const char *newpath); +#endif + +#ifndef HAVE_REALPATH +#define realpath rep_realpath +char *rep_realpath(const char *path, char *resolved_path); +#endif + +#ifndef HAVE_LCHOWN +#define lchown rep_lchown +int rep_lchown(const char *fname,uid_t uid,gid_t gid); +#endif + +#ifdef HAVE_UNIX_H +#include <unix.h> +#endif + +#ifndef HAVE_SETLINEBUF +#define setlinebuf rep_setlinebuf +void rep_setlinebuf(FILE *); +#endif + +#ifndef HAVE_STRCASESTR +#define strcasestr rep_strcasestr +char *rep_strcasestr(const char *haystack, const char *needle); +#endif + +#ifndef HAVE_STRSEP +#define strsep rep_strsep +char *rep_strsep(char **pps, const char *delim); +#endif + +#ifndef HAVE_STRTOK_R +#define strtok_r rep_strtok_r +char *rep_strtok_r(char *s, const char *delim, char **save_ptr); +#endif + + + +#ifndef HAVE_STRTOLL +#define strtoll rep_strtoll +long long int rep_strtoll(const char *str, char **endptr, int base); +#else +#ifdef HAVE_BSD_STRTOLL +#define strtoll rep_strtoll +long long int rep_strtoll(const char *str, char **endptr, int base); +#endif +#endif + +#ifndef HAVE_STRTOULL +#define strtoull rep_strtoull +unsigned long long int rep_strtoull(const char *str, char **endptr, int base); +#else +#ifdef HAVE_BSD_STRTOLL /* yes, it's not HAVE_BSD_STRTOULL */ +#define strtoull rep_strtoull +unsigned long long int rep_strtoull(const char *str, char **endptr, int base); +#endif +#endif + +#ifndef HAVE_FTRUNCATE +#define ftruncate rep_ftruncate +int rep_ftruncate(int,off_t); +#endif + +#ifndef HAVE_INITGROUPS +#define initgroups rep_initgroups +int rep_initgroups(char *name, gid_t id); +#endif + +#if !defined(HAVE_BZERO) && defined(HAVE_MEMSET) +#define bzero(a,b) memset((a),'\0',(b)) +#endif + +#ifndef HAVE_DLERROR +#define dlerror rep_dlerror +char *rep_dlerror(void); +#endif + +#ifndef HAVE_DLOPEN +#define dlopen rep_dlopen +#ifdef DLOPEN_TAKES_UNSIGNED_FLAGS +void *rep_dlopen(const char *name, unsigned int flags); +#else +void *rep_dlopen(const char *name, int flags); +#endif +#endif + +#ifndef HAVE_DLSYM +#define dlsym rep_dlsym +void *rep_dlsym(void *handle, const char *symbol); +#endif + +#ifndef HAVE_DLCLOSE +#define dlclose rep_dlclose +int rep_dlclose(void *handle); +#endif + +#ifndef HAVE_SOCKETPAIR +#define socketpair rep_socketpair +/* prototype is in system/network.h */ +#endif + +/* for old gcc releases that don't have the feature test macro __has_attribute */ +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif + +#ifndef PRINTF_ATTRIBUTE +#if __has_attribute(format) || (__GNUC__ >= 3) +/** Use gcc attribute to check printf fns. a1 is the 1-based index of + * the parameter containing the format, and a2 the index of the first + * argument. Note that some gcc 2.x versions don't handle this + * properly **/ +#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2))) +#else +#define PRINTF_ATTRIBUTE(a1, a2) +#endif +#endif + +#ifndef _DEPRECATED_ +#if __has_attribute(deprecated) || (__GNUC__ >= 3) +#define _DEPRECATED_ __attribute__ ((deprecated)) +#else +#define _DEPRECATED_ +#endif +#endif + +#if !defined(HAVE_VDPRINTF) || !defined(HAVE_C99_VSNPRINTF) +#define vdprintf rep_vdprintf +int rep_vdprintf(int fd, const char *format, va_list ap) PRINTF_ATTRIBUTE(2,0); +#endif + +#if !defined(HAVE_DPRINTF) || !defined(HAVE_C99_VSNPRINTF) +#define dprintf rep_dprintf +int rep_dprintf(int fd, const char *format, ...) PRINTF_ATTRIBUTE(2,3); +#endif + +#if !defined(HAVE_VASPRINTF) || !defined(HAVE_C99_VSNPRINTF) +#define vasprintf rep_vasprintf +int rep_vasprintf(char **ptr, const char *format, va_list ap) PRINTF_ATTRIBUTE(2,0); +#endif + +#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF) +#define snprintf rep_snprintf +int rep_snprintf(char *,size_t ,const char *, ...) PRINTF_ATTRIBUTE(3,4); +#endif + +#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF) +#define vsnprintf rep_vsnprintf +int rep_vsnprintf(char *,size_t ,const char *, va_list ap) PRINTF_ATTRIBUTE(3,0); +#endif + +#if !defined(HAVE_ASPRINTF) || !defined(HAVE_C99_VSNPRINTF) +#define asprintf rep_asprintf +int rep_asprintf(char **,const char *, ...) PRINTF_ATTRIBUTE(2,3); +#endif + +#if !defined(HAVE_C99_VSNPRINTF) +#ifdef REPLACE_BROKEN_PRINTF +/* + * We do not redefine printf by default + * as it breaks the build if system headers + * use __attribute__((format(printf, 3, 0))) + * instead of __attribute__((format(__printf__, 3, 0))) + */ +#define printf rep_printf +#endif +int rep_printf(const char *, ...) PRINTF_ATTRIBUTE(1,2); +#endif + +#if !defined(HAVE_C99_VSNPRINTF) +#define fprintf rep_fprintf +int rep_fprintf(FILE *stream, const char *, ...) PRINTF_ATTRIBUTE(2,3); +#endif + +#ifndef HAVE_VSYSLOG +#ifdef HAVE_SYSLOG +#define vsyslog rep_vsyslog +void rep_vsyslog (int facility_priority, const char *format, va_list arglist) PRINTF_ATTRIBUTE(2,0); +#endif +#endif + +/* we used to use these fns, but now we have good replacements + for snprintf and vsnprintf */ +#define slprintf snprintf + + +#ifndef HAVE_VA_COPY +#undef va_copy +#ifdef HAVE___VA_COPY +#define va_copy(dest, src) __va_copy(dest, src) +#else +#define va_copy(dest, src) (dest) = (src) +#endif +#endif + +#ifndef HAVE_VOLATILE +#define volatile +#endif + +#ifndef HAVE_COMPARISON_FN_T +typedef int (*comparison_fn_t)(const void *, const void *); +#endif + +#ifndef HAVE_WORKING_STRPTIME +#define strptime rep_strptime +struct tm; +char *rep_strptime(const char *buf, const char *format, struct tm *tm); +#endif + +#ifndef HAVE_DUP2 +#define dup2 rep_dup2 +int rep_dup2(int oldfd, int newfd); +#endif + +/* Load header file for dynamic linking stuff */ +#ifdef HAVE_DLFCN_H +#include <dlfcn.h> +#endif + +#ifndef RTLD_LAZY +#define RTLD_LAZY 0 +#endif +#ifndef RTLD_NOW +#define RTLD_NOW 0 +#endif +#ifndef RTLD_GLOBAL +#define RTLD_GLOBAL 0 +#endif + +#ifndef HAVE_SECURE_MKSTEMP +#define mkstemp(path) rep_mkstemp(path) +int rep_mkstemp(char *temp); +#endif + +#ifndef HAVE_MKDTEMP +#define mkdtemp rep_mkdtemp +char *rep_mkdtemp(char *template); +#endif + +#ifndef HAVE_PREAD +#define pread rep_pread +ssize_t rep_pread(int __fd, void *__buf, size_t __nbytes, off_t __offset); +#define LIBREPLACE_PREAD_REPLACED 1 +#else +#define LIBREPLACE_PREAD_NOT_REPLACED 1 +#endif + +#ifndef HAVE_PWRITE +#define pwrite rep_pwrite +ssize_t rep_pwrite(int __fd, const void *__buf, size_t __nbytes, off_t __offset); +#define LIBREPLACE_PWRITE_REPLACED 1 +#else +#define LIBREPLACE_PWRITE_NOT_REPLACED 1 +#endif + +#if !defined(HAVE_INET_NTOA) || defined(REPLACE_INET_NTOA) +#define inet_ntoa rep_inet_ntoa +/* prototype is in "system/network.h" */ +#endif + +#ifndef HAVE_INET_PTON +#define inet_pton rep_inet_pton +/* prototype is in "system/network.h" */ +#endif + +#ifndef HAVE_INET_NTOP +#define inet_ntop rep_inet_ntop +/* prototype is in "system/network.h" */ +#endif + +#ifndef HAVE_INET_ATON +#define inet_aton rep_inet_aton +/* prototype is in "system/network.h" */ +#endif + +#ifndef HAVE_CONNECT +#define connect rep_connect +/* prototype is in "system/network.h" */ +#endif + +#ifndef HAVE_GETHOSTBYNAME +#define gethostbyname rep_gethostbyname +/* prototype is in "system/network.h" */ +#endif + +#ifndef HAVE_GETIFADDRS +#define getifaddrs rep_getifaddrs +/* prototype is in "system/network.h" */ +#endif + +#ifndef HAVE_FREEIFADDRS +#define freeifaddrs rep_freeifaddrs +/* prototype is in "system/network.h" */ +#endif + +#ifndef HAVE_GET_CURRENT_DIR_NAME +#define get_current_dir_name rep_get_current_dir_name +char *rep_get_current_dir_name(void); +#endif + +#if (!defined(HAVE_STRERROR_R) || !defined(STRERROR_R_XSI_NOT_GNU)) +#define strerror_r rep_strerror_r +int rep_strerror_r(int errnum, char *buf, size_t buflen); +#endif + +#if !defined(HAVE_CLOCK_GETTIME) +#define clock_gettime rep_clock_gettime +#endif + +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif + +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + +/* The extra casts work around common compiler bugs. */ +#define _TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) +/* The outer cast is needed to work around a bug in Cray C 5.0.3.0. + It is necessary at least when t == time_t. */ +#define _TYPE_MINIMUM(t) ((t) (_TYPE_SIGNED (t) \ + ? ~ (t) 0 << (sizeof (t) * CHAR_BIT - 1) : (t) 0)) +#define _TYPE_MAXIMUM(t) ((t) (~ (t) 0 - _TYPE_MINIMUM (t))) + +#ifndef UINT16_MAX +#define UINT16_MAX 65535 +#endif + +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#ifndef UINT64_MAX +#define UINT64_MAX ((uint64_t)-1) +#endif + +#ifndef INT64_MAX +#define INT64_MAX 9223372036854775807LL +#endif + +#ifndef CHAR_BIT +#define CHAR_BIT 8 +#endif + +#ifndef INT32_MAX +#define INT32_MAX _TYPE_MAXIMUM(int32_t) +#endif + +#ifdef HAVE_STDBOOL_H +#include <stdbool.h> +#endif + +#ifndef HAVE_BOOL +#error Need a real boolean type +#endif + +#if !defined(HAVE_INTPTR_T) +typedef long long intptr_t ; +#define __intptr_t_defined +#endif + +#if !defined(HAVE_UINTPTR_T) +typedef unsigned long long uintptr_t ; +#define __uintptr_t_defined +#endif + +#if !defined(HAVE_PTRDIFF_T) +typedef unsigned long long ptrdiff_t ; +#endif + +/* + * to prevent <rpcsvc/yp_prot.h> from doing a redefine of 'bool' + * + * IRIX, HPUX, MacOS 10 and Solaris need BOOL_DEFINED + * Tru64 needs _BOOL_EXISTS + * AIX needs _BOOL,_TRUE,_FALSE + */ +#ifndef BOOL_DEFINED +#define BOOL_DEFINED +#endif +#ifndef _BOOL_EXISTS +#define _BOOL_EXISTS +#endif +#ifndef _BOOL +#define _BOOL +#endif + +#ifndef __bool_true_false_are_defined +#define __bool_true_false_are_defined +#endif + +#ifndef true +#define true (1) +#endif +#ifndef false +#define false (0) +#endif + +#ifndef _TRUE +#define _TRUE true +#endif +#ifndef _FALSE +#define _FALSE false +#endif + +#ifndef HAVE_FUNCTION_MACRO +#ifdef HAVE_func_MACRO +#define __FUNCTION__ __func__ +#else +#define __FUNCTION__ ("") +#endif +#endif + + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + +#ifndef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif + +#if !defined(HAVE_VOLATILE) +#define volatile +#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 *)((uintptr_t)(ptr))) + +/** Type-safe version of discard_const */ +#define discard_const_p(type, ptr) ((type *)discard_const(ptr)) + +#ifndef __STRING +#define __STRING(x) #x +#endif + +#ifndef __STRINGSTRING +#define __STRINGSTRING(x) __STRING(x) +#endif + +#ifndef __LINESTR__ +#define __LINESTR__ __STRINGSTRING(__LINE__) +#endif + +#ifndef __location__ +#define __location__ __FILE__ ":" __LINESTR__ +#endif + +/** + * Zero a structure. + */ +#define ZERO_STRUCT(x) memset_s((char *)&(x), sizeof(x), 0, sizeof(x)) + +/** + * Zero a structure given a pointer to the structure. + */ +#define ZERO_STRUCTP(x) do { \ + if ((x) != NULL) { \ + memset_s((char *)(x), sizeof(*(x)), 0, sizeof(*(x))); \ + } \ +} while(0) + +/** + * Zero a structure given a pointer to the structure - no zero check + */ +#define ZERO_STRUCTPN(x) memset_s((char *)(x), sizeof(*(x)), 0, sizeof(*(x))) + +/** + * Zero an array - note that sizeof(array) must work - ie. it must not be a + * pointer + */ +#define ZERO_ARRAY(x) memset_s((char *)(x), sizeof(x), 0, sizeof(x)) + +/** + * Zero a given len of an array + */ +#define ZERO_ARRAY_LEN(x, l) memset_s((char *)(x), (l), 0, (l)) + +/** + * Explicitly zero data from memory. This is guaranteed to be not optimized + * away. + */ +#define BURN_DATA(x) memset_s((char *)&(x), sizeof(x), 0, sizeof(x)) + +/** + * Explicitly zero data from memory. This is guaranteed to be not optimized + * away. + */ +#define BURN_DATA_SIZE(x, s) memset_s((char *)&(x), (s), 0, (s)) + +/** + * Explicitly zero data from memory. This is guaranteed to be not optimized + * away. + */ +#define BURN_PTR_SIZE(x, s) memset_s((x), (s), 0, (s)) + +/** + * Explicitly zero data in string. This is guaranteed to be not optimized + * away. + */ +#define BURN_STR(x) do { \ + if ((x) != NULL) { \ + size_t s = strlen(x); \ + memset_s((x), s, 0, s); \ + } \ + } while(0) + +/** + * Work out how many elements there are in a static array. + */ +#ifdef ARRAY_SIZE +#undef ARRAY_SIZE +#endif +#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0])) + +/** + * Remove an array element by moving the rest one down + */ +#define ARRAY_DEL_ELEMENT(a,i,n) \ +if((i)<((n)-1)){memmove(&((a)[(i)]),&((a)[(i)+1]),(sizeof(*(a))*((n)-(i)-1)));} + +/** + * Pointer difference macro + */ +#define PTR_DIFF(p1,p2) ((ptrdiff_t)(((const char *)(p1)) - (const char *)(p2))) + +#ifdef __COMPAR_FN_T +#define QSORT_CAST (__compar_fn_t) +#endif + +#ifndef QSORT_CAST +#define QSORT_CAST (int (*)(const void *, const void *)) +#endif + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +#ifndef MAX_DNS_NAME_LENGTH +#define MAX_DNS_NAME_LENGTH 256 /* Actually 255 but +1 for terminating null. */ +#endif + +#ifdef HAVE_CRYPT_H +#include <crypt.h> +#endif + +/* these macros gain us a few percent of speed on gcc */ +#if (__GNUC__ >= 3) +/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1 + as its first argument */ +#ifndef likely +#define likely(x) __builtin_expect(!!(x), 1) +#endif +#ifndef unlikely +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif +#else +#ifndef likely +#define likely(x) (x) +#endif +#ifndef unlikely +#define unlikely(x) (x) +#endif +#endif + +#ifndef HAVE_FDATASYNC +#define fdatasync(fd) fsync(fd) +#elif !defined(HAVE_DECL_FDATASYNC) +int fdatasync(int ); +#endif + +/* these are used to mark symbols as local to a shared lib, or + * publicly available via the shared lib API */ +#ifndef _PUBLIC_ +#ifdef HAVE_VISIBILITY_ATTR +#define _PUBLIC_ __attribute__((visibility("default"))) +#else +#define _PUBLIC_ +#endif +#endif + +#ifndef _PRIVATE_ +#ifdef HAVE_VISIBILITY_ATTR +# define _PRIVATE_ __attribute__((visibility("hidden"))) +#else +# define _PRIVATE_ +#endif +#endif + +#ifndef HAVE_POLL +#define poll rep_poll +/* prototype is in "system/network.h" */ +#endif + +#ifndef HAVE_GETPEEREID +#define getpeereid rep_getpeereid +int rep_getpeereid(int s, uid_t *uid, gid_t *gid); +#endif + +#ifndef HAVE_USLEEP +#define usleep rep_usleep +typedef long useconds_t; +int usleep(useconds_t); +#endif + +#ifndef HAVE_SETPROCTITLE +#define setproctitle rep_setproctitle +void rep_setproctitle(const char *fmt, ...) PRINTF_ATTRIBUTE(1, 2); +#endif + +#ifndef HAVE_SETPROCTITLE_INIT +#define setproctitle_init rep_setproctitle_init +void rep_setproctitle_init(int argc, char *argv[], char *envp[]); +#endif + +#ifndef HAVE_MEMSET_S +#define memset_s rep_memset_s +int rep_memset_s(void *dest, size_t destsz, int ch, size_t count); +#endif + +#ifndef HAVE_GETPROGNAME +#define getprogname rep_getprogname +const char *rep_getprogname(void); +#endif + +#ifndef HAVE_COPY_FILE_RANGE +#define copy_file_range rep_copy_file_range +ssize_t rep_copy_file_range(int fd_in, + loff_t *off_in, + int fd_out, + loff_t *off_out, + size_t len, + unsigned int flags); +#endif /* HAVE_COPY_FILE_RANGE */ + +#ifndef FALL_THROUGH +# ifdef HAVE_FALLTHROUGH_ATTRIBUTE +# define FALL_THROUGH __attribute__ ((fallthrough)) +# else /* HAVE_FALLTHROUGH_ATTRIBUTE */ +# define FALL_THROUGH ((void)0) +# endif /* HAVE_FALLTHROUGH_ATTRIBUTE */ +#endif /* FALL_THROUGH */ + +struct __rep_cwrap_enabled_state { + const char *fnname; + bool cached; + bool retval; +}; + +static inline bool __rep_cwrap_enabled_fn(struct __rep_cwrap_enabled_state *state) +{ + bool (*__wrapper_enabled_fn)(void) = NULL; + + if (state->cached) { + return state->retval; + } + state->retval = false; + state->cached = true; + + __wrapper_enabled_fn = (bool (*)(void))dlsym(RTLD_DEFAULT, state->fnname); + if (__wrapper_enabled_fn == NULL) { + return state->retval; + } + + state->retval = __wrapper_enabled_fn(); + return state->retval; +} + +static inline bool nss_wrapper_enabled(void) +{ + struct __rep_cwrap_enabled_state state = { + .fnname = "nss_wrapper_enabled", + }; + return __rep_cwrap_enabled_fn(&state); +} +static inline bool nss_wrapper_hosts_enabled(void) +{ + struct __rep_cwrap_enabled_state state = { + .fnname = "nss_wrapper_hosts_enabled", + }; + return __rep_cwrap_enabled_fn(&state); +} +static inline bool socket_wrapper_enabled(void) +{ + struct __rep_cwrap_enabled_state state = { + .fnname = "socket_wrapper_enabled", + }; + return __rep_cwrap_enabled_fn(&state); +} +static inline bool uid_wrapper_enabled(void) +{ + struct __rep_cwrap_enabled_state state = { + .fnname = "uid_wrapper_enabled", + }; + return __rep_cwrap_enabled_fn(&state); +} + +static inline bool _hexcharval(char c, uint8_t *val) +{ + if ((c >= '0') && (c <= '9')) { *val = c - '0'; return true; } + if ((c >= 'a') && (c <= 'f')) { *val = c - 'a' + 10; return true; } + if ((c >= 'A') && (c <= 'F')) { *val = c - 'A' + 10; return true; } + return false; +} + +static inline bool hex_byte(const char *in, uint8_t *out) +{ + uint8_t hi=0, lo=0; + bool ok = _hexcharval(in[0], &hi) && _hexcharval(in[1], &lo); + *out = (hi<<4)+lo; + return ok; +} + +/* Needed for Solaris atomic_add_XX functions. */ +#if defined(HAVE_SYS_ATOMIC_H) +#include <sys/atomic.h> +#endif + +/* + * This handles the case of missing pthread support and ensures code can use + * __thread unconditionally, such that when built on a platform without pthread + * support, the __thread qualifier is an empty define. + */ +#ifndef HAVE___THREAD +# ifdef HAVE_PTHREAD +# error Configure failed to detect pthread library with missing TLS support +# endif +#define HAVE___THREAD +#endif + +#endif /* _LIBREPLACE_REPLACE_H */ diff --git a/lib/replace/snprintf.c b/lib/replace/snprintf.c new file mode 100644 index 0000000..de814af --- /dev/null +++ b/lib/replace/snprintf.c @@ -0,0 +1,1536 @@ +/* + * NOTE: If you change this file, please merge it into rsync, samba, etc. + */ + +/* + * Copyright Patrick Powell 1995 + * This code is based on code written by Patrick Powell (papowell@astart.com) + * It may be used for any purpose as long as this notice remains intact + * on all source code distributions + */ + +/************************************************************** + * Original: + * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 + * A bombproof version of doprnt (dopr) included. + * Sigh. This sort of thing is always nasty do deal with. Note that + * the version here does not include floating point... + * + * snprintf() is used instead of sprintf() as it does limit checks + * for string length. This covers a nasty loophole. + * + * The other functions are there to prevent NULL pointers from + * causing nast effects. + * + * More Recently: + * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43 + * This was ugly. It is still ugly. I opted out of floating point + * numbers, but the formatter understands just about everything + * from the normal C string format, at least as far as I can tell from + * the Solaris 2.5 printf(3S) man page. + * + * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1 + * Ok, added some minimal floating point support, which means this + * probably requires libm on most operating systems. Don't yet + * support the exponent (e,E) and sigfig (g,G). Also, fmtint() + * was pretty badly broken, it just wasn't being exercised in ways + * which showed it, so that's been fixed. Also, formatted the code + * to mutt conventions, and removed dead code left over from the + * original. Also, there is now a builtin-test, just compile with: + * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm + * and run snprintf for results. + * + * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i + * The PGP code was using unsigned hexadecimal formats. + * Unfortunately, unsigned formats simply didn't work. + * + * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8 + * The original code assumed that both snprintf() and vsnprintf() were + * missing. Some systems only have snprintf() but not vsnprintf(), so + * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. + * + * Andrew Tridgell (tridge@samba.org) Oct 1998 + * fixed handling of %.0f + * added test for HAVE_LONG_DOUBLE + * + * tridge@samba.org, idra@samba.org, April 2001 + * got rid of fcvt code (twas buggy and made testing harder) + * added C99 semantics + * + * date: 2002/12/19 19:56:31; author: herb; state: Exp; lines: +2 -0 + * actually print args for %g and %e + * + * date: 2002/06/03 13:37:52; author: jmcd; state: Exp; lines: +8 -0 + * Since includes.h isn't included here, VA_COPY has to be defined here. I don't + * see any include file that is guaranteed to be here, so I'm defining it + * locally. Fixes AIX and Solaris builds. + * + * date: 2002/06/03 03:07:24; author: tridge; state: Exp; lines: +5 -13 + * put the ifdef for HAVE_VA_COPY in one place rather than in lots of + * functions + * + * date: 2002/05/17 14:51:22; author: jmcd; state: Exp; lines: +21 -4 + * Fix usage of va_list passed as an arg. Use __va_copy before using it + * when it exists. + * + * date: 2002/04/16 22:38:04; author: idra; state: Exp; lines: +20 -14 + * Fix incorrect zpadlen handling in fmtfp. + * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it. + * few mods to make it easier to compile the tests. + * addedd the "Ollie" test to the floating point ones. + * + * Martin Pool (mbp@samba.org) April 2003 + * Remove NO_CONFIG_H so that the test case can be built within a source + * tree with less trouble. + * Remove unnecessary SAFE_FREE() definition. + * + * Martin Pool (mbp@samba.org) May 2003 + * Put in a prototype for dummy_snprintf() to quiet compiler warnings. + * + * Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even + * if the C library has some snprintf functions already. + * + * Darren Tucker (dtucker@zip.com.au) 2005 + * Fix bug allowing read overruns of the source string with "%.*s" + * Usually harmless unless the read runs outside the process' allocation + * (eg if your malloc does guard pages) in which case it will segfault. + * From OpenSSH. Also added test for same. + * + * Simo Sorce (idra@samba.org) Jan 2006 + * + * Add support for position independent parameters + * fix fmtstr now it conforms to sprintf wrt min.max + * + **************************************************************/ + +#include "replace.h" +#include "system/locale.h" + +#ifdef TEST_SNPRINTF /* need math library headers for testing */ + +/* In test mode, we pretend that this system doesn't have any snprintf + * functions, regardless of what config.h says. */ +# undef HAVE_SNPRINTF +# undef HAVE_VSNPRINTF +# undef HAVE_C99_VSNPRINTF +# undef HAVE_ASPRINTF +# undef HAVE_VASPRINTF +# include <math.h> +#endif /* TEST_SNPRINTF */ + +#if defined(HAVE_SNPRINTF) && defined(HAVE_VSNPRINTF) && defined(HAVE_C99_VSNPRINTF) +/* only include stdio.h if we are not re-defining snprintf or vsnprintf */ +#include <stdio.h> + /* make the compiler happy with an empty file */ + void dummy_snprintf(void); + void dummy_snprintf(void) {} +#endif /* HAVE_SNPRINTF, etc */ + +/* yes this really must be a ||. Don't muck with this (tridge) */ +#if !defined(HAVE_VSNPRINTF) || !defined(HAVE_C99_VSNPRINTF) + +#ifdef HAVE_LONG_DOUBLE +#define LDOUBLE long double +#else +#define LDOUBLE double +#endif + +#ifdef HAVE_LONG_LONG +#define LLONG long long +#else +#define LLONG long +#endif + +#ifndef VA_COPY +#ifdef HAVE_VA_COPY +#define VA_COPY(dest, src) va_copy(dest, src) +#else +#ifdef HAVE___VA_COPY +#define VA_COPY(dest, src) __va_copy(dest, src) +#else +#define VA_COPY(dest, src) (dest) = (src) +#endif +#endif + +/* + * dopr(): poor man's version of doprintf + */ + +/* format read states */ +#define DP_S_DEFAULT 0 +#define DP_S_FLAGS 1 +#define DP_S_MIN 2 +#define DP_S_DOT 3 +#define DP_S_MAX 4 +#define DP_S_MOD 5 +#define DP_S_CONV 6 +#define DP_S_DONE 7 + +/* format flags - Bits */ +#define DP_F_MINUS (1 << 0) +#define DP_F_PLUS (1 << 1) +#define DP_F_SPACE (1 << 2) +#define DP_F_NUM (1 << 3) +#define DP_F_ZERO (1 << 4) +#define DP_F_UP (1 << 5) +#define DP_F_UNSIGNED (1 << 6) + +/* Conversion Flags */ +#define DP_C_CHAR 1 +#define DP_C_SHORT 2 +#define DP_C_LONG 3 +#define DP_C_LDOUBLE 4 +#define DP_C_LLONG 5 +#define DP_C_SIZET 6 + +/* Chunk types */ +#define CNK_FMT_STR 0 +#define CNK_INT 1 +#define CNK_OCTAL 2 +#define CNK_UINT 3 +#define CNK_HEX 4 +#define CNK_FLOAT 5 +#define CNK_CHAR 6 +#define CNK_STRING 7 +#define CNK_PTR 8 +#define CNK_NUM 9 +#define CNK_PRCNT 10 + +#define char_to_int(p) ((p)- '0') +#ifndef MAX +#define MAX(p,q) (((p) >= (q)) ? (p) : (q)) +#endif + +struct pr_chunk { + int type; /* chunk type */ + int num; /* parameter number */ + int min; + int max; + int flags; + int cflags; + int start; + int len; + LLONG value; + LDOUBLE fvalue; + char *strvalue; + void *pnum; + struct pr_chunk *min_star; + struct pr_chunk *max_star; + struct pr_chunk *next; +}; + +struct pr_chunk_x { + struct pr_chunk **chunks; + int num; +}; + +static int dopr(char *buffer, size_t maxlen, const char *format, + va_list args_in); +static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, + char *value, int flags, int min, int max); +static void fmtint(char *buffer, size_t *currlen, size_t maxlen, + LLONG value, int base, int min, int max, int flags); +static void fmtfp(char *buffer, size_t *currlen, size_t maxlen, + LDOUBLE fvalue, int min, int max, int flags); +static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c); +static struct pr_chunk *new_chunk(void); +static int add_cnk_list_entry(struct pr_chunk_x **list, + int max_num, struct pr_chunk *chunk); + +static int dopr(char *buffer, size_t maxlen, const char *format, va_list args_in) +{ + char ch; + int state; + int pflag; + int pnum; + int pfirst; + size_t currlen; + va_list args; + const char *base; + struct pr_chunk *chunks = NULL; + struct pr_chunk *cnk = NULL; + struct pr_chunk_x *clist = NULL; + int max_pos; + int ret = -1; + + VA_COPY(args, args_in); + + state = DP_S_DEFAULT; + pfirst = 1; + pflag = 0; + pnum = 0; + + max_pos = 0; + base = format; + ch = *format++; + + /* retrieve the string structure as chunks */ + while (state != DP_S_DONE) { + if (ch == '\0') + state = DP_S_DONE; + + switch(state) { + case DP_S_DEFAULT: + + if (cnk) { + cnk->next = new_chunk(); + cnk = cnk->next; + } else { + cnk = new_chunk(); + } + if (!cnk) goto done; + if (!chunks) chunks = cnk; + + if (ch == '%') { + state = DP_S_FLAGS; + ch = *format++; + } else { + cnk->type = CNK_FMT_STR; + cnk->start = format - base -1; + while ((ch != '\0') && (ch != '%')) ch = *format++; + cnk->len = format - base - cnk->start -1; + } + break; + case DP_S_FLAGS: + switch (ch) { + case '-': + cnk->flags |= DP_F_MINUS; + ch = *format++; + break; + case '+': + cnk->flags |= DP_F_PLUS; + ch = *format++; + break; + case ' ': + cnk->flags |= DP_F_SPACE; + ch = *format++; + break; + case '#': + cnk->flags |= DP_F_NUM; + ch = *format++; + break; + case '0': + cnk->flags |= DP_F_ZERO; + ch = *format++; + break; + case 'I': + /* internationalization not supported yet */ + ch = *format++; + break; + default: + state = DP_S_MIN; + break; + } + break; + case DP_S_MIN: + if (isdigit((unsigned char)ch)) { + cnk->min = 10 * cnk->min + char_to_int (ch); + ch = *format++; + } else if (ch == '$') { + if (!pfirst && !pflag) { + /* parameters must be all positioned or none */ + goto done; + } + if (pfirst) { + pfirst = 0; + pflag = 1; + } + if (cnk->min == 0) /* what ?? */ + goto done; + cnk->num = cnk->min; + cnk->min = 0; + ch = *format++; + } else if (ch == '*') { + if (pfirst) pfirst = 0; + cnk->min_star = new_chunk(); + if (!cnk->min_star) /* out of memory :-( */ + goto done; + cnk->min_star->type = CNK_INT; + if (pflag) { + int num; + ch = *format++; + if (!isdigit((unsigned char)ch)) { + /* parameters must be all positioned or none */ + goto done; + } + for (num = 0; isdigit((unsigned char)ch); ch = *format++) { + num = 10 * num + char_to_int(ch); + } + cnk->min_star->num = num; + if (ch != '$') /* what ?? */ + goto done; + } else { + cnk->min_star->num = ++pnum; + } + max_pos = add_cnk_list_entry(&clist, max_pos, cnk->min_star); + if (max_pos == 0) /* out of memory :-( */ + goto done; + ch = *format++; + state = DP_S_DOT; + } else { + if (pfirst) pfirst = 0; + state = DP_S_DOT; + } + break; + case DP_S_DOT: + if (ch == '.') { + state = DP_S_MAX; + ch = *format++; + } else { + state = DP_S_MOD; + } + break; + case DP_S_MAX: + if (isdigit((unsigned char)ch)) { + if (cnk->max < 0) + cnk->max = 0; + cnk->max = 10 * cnk->max + char_to_int (ch); + ch = *format++; + } else if (ch == '$') { + if (!pfirst && !pflag) { + /* parameters must be all positioned or none */ + goto done; + } + if (cnk->max <= 0) /* what ?? */ + goto done; + cnk->num = cnk->max; + cnk->max = -1; + ch = *format++; + } else if (ch == '*') { + cnk->max_star = new_chunk(); + if (!cnk->max_star) /* out of memory :-( */ + goto done; + cnk->max_star->type = CNK_INT; + if (pflag) { + int num; + ch = *format++; + if (!isdigit((unsigned char)ch)) { + /* parameters must be all positioned or none */ + goto done; + } + for (num = 0; isdigit((unsigned char)ch); ch = *format++) { + num = 10 * num + char_to_int(ch); + } + cnk->max_star->num = num; + if (ch != '$') /* what ?? */ + goto done; + } else { + cnk->max_star->num = ++pnum; + } + max_pos = add_cnk_list_entry(&clist, max_pos, cnk->max_star); + if (max_pos == 0) /* out of memory :-( */ + goto done; + + ch = *format++; + state = DP_S_MOD; + } else { + state = DP_S_MOD; + } + break; + case DP_S_MOD: + switch (ch) { + case 'h': + cnk->cflags = DP_C_SHORT; + ch = *format++; + if (ch == 'h') { + cnk->cflags = DP_C_CHAR; + ch = *format++; + } + break; + case 'l': + cnk->cflags = DP_C_LONG; + ch = *format++; + if (ch == 'l') { /* It's a long long */ + cnk->cflags = DP_C_LLONG; + ch = *format++; + } + break; + case 'j': + cnk->cflags = DP_C_LLONG; + ch = *format++; + break; + case 'L': + cnk->cflags = DP_C_LDOUBLE; + ch = *format++; + break; + case 'z': + cnk->cflags = DP_C_SIZET; + ch = *format++; + break; + default: + break; + } + state = DP_S_CONV; + break; + case DP_S_CONV: + if (cnk->num == 0) cnk->num = ++pnum; + max_pos = add_cnk_list_entry(&clist, max_pos, cnk); + if (max_pos == 0) /* out of memory :-( */ + goto done; + + switch (ch) { + case 'd': + case 'i': + cnk->type = CNK_INT; + break; + case 'o': + cnk->type = CNK_OCTAL; + cnk->flags |= DP_F_UNSIGNED; + break; + case 'u': + cnk->type = CNK_UINT; + cnk->flags |= DP_F_UNSIGNED; + break; + case 'X': + cnk->flags |= DP_F_UP; + case 'x': + cnk->type = CNK_HEX; + cnk->flags |= DP_F_UNSIGNED; + break; + case 'A': + /* hex float not supported yet */ + case 'E': + case 'G': + case 'F': + cnk->flags |= DP_F_UP; + case 'a': + /* hex float not supported yet */ + case 'e': + case 'f': + case 'g': + cnk->type = CNK_FLOAT; + break; + case 'c': + cnk->type = CNK_CHAR; + break; + case 's': + cnk->type = CNK_STRING; + break; + case 'p': + cnk->type = CNK_PTR; + cnk->flags |= DP_F_UNSIGNED; + break; + case 'n': + cnk->type = CNK_NUM; + break; + case '%': + cnk->type = CNK_PRCNT; + break; + default: + /* Unknown, bail out*/ + goto done; + } + ch = *format++; + state = DP_S_DEFAULT; + break; + case DP_S_DONE: + break; + default: + /* hmm? */ + break; /* some picky compilers need this */ + } + } + + /* retrieve the format arguments */ + for (pnum = 0; pnum < max_pos; pnum++) { + int i; + + if (clist[pnum].num == 0) { + /* ignoring a parameter should not be permitted + * all parameters must be matched at least once + * BUT seem some system ignore this rule ... + * at least my glibc based system does --SSS + */ +#ifdef DEBUG_SNPRINTF + printf("parameter at position %d not used\n", pnum+1); +#endif + /* eat the parameter */ + va_arg (args, int); + continue; + } + for (i = 1; i < clist[pnum].num; i++) { + if (clist[pnum].chunks[0]->type != clist[pnum].chunks[i]->type) { + /* nooo noo no! + * all the references to a parameter + * must be of the same type + */ + goto done; + } + } + cnk = clist[pnum].chunks[0]; + switch (cnk->type) { + case CNK_INT: + if (cnk->cflags == DP_C_SHORT) + cnk->value = va_arg (args, int); + else if (cnk->cflags == DP_C_LONG) + cnk->value = va_arg (args, long int); + else if (cnk->cflags == DP_C_LLONG) + cnk->value = va_arg (args, LLONG); + else if (cnk->cflags == DP_C_SIZET) + cnk->value = va_arg (args, ssize_t); + else + cnk->value = va_arg (args, int); + + for (i = 1; i < clist[pnum].num; i++) { + clist[pnum].chunks[i]->value = cnk->value; + } + break; + + case CNK_OCTAL: + case CNK_UINT: + case CNK_HEX: + if (cnk->cflags == DP_C_SHORT) + cnk->value = va_arg (args, unsigned int); + else if (cnk->cflags == DP_C_LONG) + cnk->value = (unsigned long int)va_arg (args, unsigned long int); + else if (cnk->cflags == DP_C_LLONG) + cnk->value = (LLONG)va_arg (args, unsigned LLONG); + else if (cnk->cflags == DP_C_SIZET) + cnk->value = (size_t)va_arg (args, size_t); + else + cnk->value = (unsigned int)va_arg (args, unsigned int); + + for (i = 1; i < clist[pnum].num; i++) { + clist[pnum].chunks[i]->value = cnk->value; + } + break; + + case CNK_FLOAT: + if (cnk->cflags == DP_C_LDOUBLE) + cnk->fvalue = va_arg (args, LDOUBLE); + else + cnk->fvalue = va_arg (args, double); + + for (i = 1; i < clist[pnum].num; i++) { + clist[pnum].chunks[i]->fvalue = cnk->fvalue; + } + break; + + case CNK_CHAR: + cnk->value = va_arg (args, int); + + for (i = 1; i < clist[pnum].num; i++) { + clist[pnum].chunks[i]->value = cnk->value; + } + break; + + case CNK_STRING: + cnk->strvalue = va_arg (args, char *); + if (!cnk->strvalue) cnk->strvalue = "(NULL)"; + + for (i = 1; i < clist[pnum].num; i++) { + clist[pnum].chunks[i]->strvalue = cnk->strvalue; + } + break; + + case CNK_PTR: + cnk->strvalue = va_arg (args, void *); + for (i = 1; i < clist[pnum].num; i++) { + clist[pnum].chunks[i]->strvalue = cnk->strvalue; + } + break; + + case CNK_NUM: + if (cnk->cflags == DP_C_CHAR) + cnk->pnum = va_arg (args, char *); + else if (cnk->cflags == DP_C_SHORT) + cnk->pnum = va_arg (args, short int *); + else if (cnk->cflags == DP_C_LONG) + cnk->pnum = va_arg (args, long int *); + else if (cnk->cflags == DP_C_LLONG) + cnk->pnum = va_arg (args, LLONG *); + else if (cnk->cflags == DP_C_SIZET) + cnk->pnum = va_arg (args, ssize_t *); + else + cnk->pnum = va_arg (args, int *); + + for (i = 1; i < clist[pnum].num; i++) { + clist[pnum].chunks[i]->pnum = cnk->pnum; + } + break; + + case CNK_PRCNT: + break; + + default: + /* what ?? */ + goto done; + } + } + /* print out the actual string from chunks */ + currlen = 0; + cnk = chunks; + while (cnk) { + int len, min, max; + + if (cnk->min_star) min = cnk->min_star->value; + else min = cnk->min; + if (cnk->max_star) max = cnk->max_star->value; + else max = cnk->max; + + switch (cnk->type) { + + case CNK_FMT_STR: + if (maxlen != 0 && maxlen > currlen) { + if (maxlen > (currlen + cnk->len)) len = cnk->len; + else len = maxlen - currlen; + + memcpy(&(buffer[currlen]), &(base[cnk->start]), len); + } + currlen += cnk->len; + + break; + + case CNK_INT: + case CNK_UINT: + fmtint (buffer, &currlen, maxlen, cnk->value, 10, min, max, cnk->flags); + break; + + case CNK_OCTAL: + fmtint (buffer, &currlen, maxlen, cnk->value, 8, min, max, cnk->flags); + break; + + case CNK_HEX: + fmtint (buffer, &currlen, maxlen, cnk->value, 16, min, max, cnk->flags); + break; + + case CNK_FLOAT: + fmtfp (buffer, &currlen, maxlen, cnk->fvalue, min, max, cnk->flags); + break; + + case CNK_CHAR: + dopr_outch (buffer, &currlen, maxlen, cnk->value); + break; + + case CNK_STRING: + if (max == -1) { + max = strlen(cnk->strvalue); + } + fmtstr (buffer, &currlen, maxlen, cnk->strvalue, cnk->flags, min, max); + break; + + case CNK_PTR: + fmtint (buffer, &currlen, maxlen, (long)(cnk->strvalue), 16, min, max, cnk->flags); + break; + + case CNK_NUM: + if (cnk->cflags == DP_C_CHAR) + *((char *)(cnk->pnum)) = (char)currlen; + else if (cnk->cflags == DP_C_SHORT) + *((short int *)(cnk->pnum)) = (short int)currlen; + else if (cnk->cflags == DP_C_LONG) + *((long int *)(cnk->pnum)) = (long int)currlen; + else if (cnk->cflags == DP_C_LLONG) + *((LLONG *)(cnk->pnum)) = (LLONG)currlen; + else if (cnk->cflags == DP_C_SIZET) + *((ssize_t *)(cnk->pnum)) = (ssize_t)currlen; + else + *((int *)(cnk->pnum)) = (int)currlen; + break; + + case CNK_PRCNT: + dopr_outch (buffer, &currlen, maxlen, '%'); + break; + + default: + /* what ?? */ + goto done; + } + cnk = cnk->next; + } + if (maxlen != 0) { + if (currlen < maxlen - 1) + buffer[currlen] = '\0'; + else if (maxlen > 0) + buffer[maxlen - 1] = '\0'; + } + ret = currlen; + +done: + va_end(args); + + while (chunks) { + cnk = chunks->next; + if (chunks->min_star) free(chunks->min_star); + if (chunks->max_star) free(chunks->max_star); + free(chunks); + chunks = cnk; + } + if (clist) { + for (pnum = 0; pnum < max_pos; pnum++) { + if (clist[pnum].chunks) free(clist[pnum].chunks); + } + free(clist); + } + return ret; +} + +static void fmtstr(char *buffer, size_t *currlen, size_t maxlen, + char *value, int flags, int min, int max) +{ + int padlen, strln; /* amount to pad */ + int cnt = 0; + +#ifdef DEBUG_SNPRINTF + printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value); +#endif + if (value == 0) { + value = "<NULL>"; + } + + for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */ + padlen = min - strln; + if (padlen < 0) + padlen = 0; + if (flags & DP_F_MINUS) + padlen = -padlen; /* Left Justify */ + + while (padlen > 0) { + dopr_outch (buffer, currlen, maxlen, ' '); + --padlen; + } + while (*value && (cnt < max)) { + dopr_outch (buffer, currlen, maxlen, *value++); + ++cnt; + } + while (padlen < 0) { + dopr_outch (buffer, currlen, maxlen, ' '); + ++padlen; + } +} + +/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ + +static void fmtint(char *buffer, size_t *currlen, size_t maxlen, + LLONG value, int base, int min, int max, int flags) +{ + int signvalue = 0; + unsigned LLONG uvalue; + char convert[22+1]; /* 64-bit value in octal: 22 digits + \0 */ + int place = 0; + int spadlen = 0; /* amount to space pad */ + int zpadlen = 0; /* amount to zero pad */ + int caps = 0; + + if (max < 0) + max = 0; + + uvalue = value; + + if(!(flags & DP_F_UNSIGNED)) { + if( value < 0 ) { + signvalue = '-'; + uvalue = -value; + } else { + if (flags & DP_F_PLUS) /* Do a sign (+/i) */ + signvalue = '+'; + else if (flags & DP_F_SPACE) + signvalue = ' '; + } + } + + if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ + + do { + convert[place++] = + (caps? "0123456789ABCDEF":"0123456789abcdef") + [uvalue % (unsigned)base ]; + uvalue = (uvalue / (unsigned)base ); + } while(uvalue && (place < sizeof(convert))); + if (place == sizeof(convert)) place--; + convert[place] = 0; + + zpadlen = max - place; + spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); + if (zpadlen < 0) zpadlen = 0; + if (spadlen < 0) spadlen = 0; + if (flags & DP_F_ZERO) { + zpadlen = MAX(zpadlen, spadlen); + spadlen = 0; + } + if (flags & DP_F_MINUS) + spadlen = -spadlen; /* Left Justifty */ + +#ifdef DEBUG_SNPRINTF + printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", + zpadlen, spadlen, min, max, place); +#endif + + /* Spaces */ + while (spadlen > 0) { + dopr_outch (buffer, currlen, maxlen, ' '); + --spadlen; + } + + /* Sign */ + if (signvalue) + dopr_outch (buffer, currlen, maxlen, signvalue); + + /* Zeros */ + if (zpadlen > 0) { + while (zpadlen > 0) { + dopr_outch (buffer, currlen, maxlen, '0'); + --zpadlen; + } + } + + /* Digits */ + while (place > 0) + dopr_outch (buffer, currlen, maxlen, convert[--place]); + + /* Left Justified spaces */ + while (spadlen < 0) { + dopr_outch (buffer, currlen, maxlen, ' '); + ++spadlen; + } +} + +static LDOUBLE abs_val(LDOUBLE value) +{ + LDOUBLE result = value; + + if (value < 0) + result = -value; + + return result; +} + +static LDOUBLE POW10(int exp) +{ + LDOUBLE result = 1; + + while (exp) { + result *= 10; + exp--; + } + + return result; +} + +static LLONG ROUND(LDOUBLE value) +{ + LLONG intpart; + + intpart = (LLONG)value; + value = value - intpart; + if (value >= 0.5) intpart++; + + return intpart; +} + +/* a replacement for modf that doesn't need the math library. Should + be portable, but slow */ +static double my_modf(double x0, double *iptr) +{ + int i; + LLONG l=0; + double x = x0; + double f = 1.0; + + for (i=0;i<100;i++) { + l = (long)x; + if (l <= (x+1) && l >= (x-1)) break; + x *= 0.1; + f *= 10.0; + } + + if (i == 100) { + /* yikes! the number is beyond what we can handle. What do we do? */ + (*iptr) = 0; + return 0; + } + + if (i != 0) { + double i2; + double ret; + + ret = my_modf(x0-l*f, &i2); + (*iptr) = l*f + i2; + return ret; + } + + (*iptr) = l; + return x - (*iptr); +} + + +static void fmtfp (char *buffer, size_t *currlen, size_t maxlen, + LDOUBLE fvalue, int min, int max, int flags) +{ + int signvalue = 0; + double ufvalue; + char iconvert[311]; + char fconvert[311]; + int iplace = 0; + int fplace = 0; + int padlen = 0; /* amount to pad */ + int zpadlen = 0; + int caps = 0; + int idx; + double intpart; + double fracpart; + double temp; + + /* + * AIX manpage says the default is 0, but Solaris says the default + * is 6, and sprintf on AIX defaults to 6 + */ + if (max < 0) + max = 6; + + ufvalue = abs_val (fvalue); + + if (fvalue < 0) { + signvalue = '-'; + } else { + if (flags & DP_F_PLUS) { /* Do a sign (+/i) */ + signvalue = '+'; + } else { + if (flags & DP_F_SPACE) + signvalue = ' '; + } + } + +#if 0 + if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ +#endif + +#if 0 + if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */ +#endif + + /* + * Sorry, we only support 9 digits past the decimal because of our + * conversion method + */ + if (max > 9) + max = 9; + + /* We "cheat" by converting the fractional part to integer by + * multiplying by a factor of 10 + */ + + temp = ufvalue; + my_modf(temp, &intpart); + + fracpart = ROUND((POW10(max)) * (ufvalue - intpart)); + + if (fracpart >= POW10(max)) { + intpart++; + fracpart -= POW10(max); + } + + + /* Convert integer part */ + do { + temp = intpart*0.1; + my_modf(temp, &intpart); + idx = (int) ((temp -intpart +0.05)* 10.0); + /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */ + /* printf ("%llf, %f, %x\n", temp, intpart, idx); */ + iconvert[iplace++] = + (caps? "0123456789ABCDEF":"0123456789abcdef")[idx]; + } while (intpart && (iplace < 311)); + if (iplace == 311) iplace--; + iconvert[iplace] = 0; + + /* Convert fractional part */ + if (fracpart) + { + do { + temp = fracpart*0.1; + my_modf(temp, &fracpart); + idx = (int) ((temp -fracpart +0.05)* 10.0); + /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */ + /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */ + fconvert[fplace++] = + (caps? "0123456789ABCDEF":"0123456789abcdef")[idx]; + } while(fracpart && (fplace < 311)); + if (fplace == 311) fplace--; + } + fconvert[fplace] = 0; + + /* -1 for decimal point, another -1 if we are printing a sign */ + padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); + zpadlen = max - fplace; + if (zpadlen < 0) zpadlen = 0; + if (padlen < 0) + padlen = 0; + if (flags & DP_F_MINUS) + padlen = -padlen; /* Left Justifty */ + + if ((flags & DP_F_ZERO) && (padlen > 0)) { + if (signvalue) { + dopr_outch (buffer, currlen, maxlen, signvalue); + --padlen; + signvalue = 0; + } + while (padlen > 0) { + dopr_outch (buffer, currlen, maxlen, '0'); + --padlen; + } + } + while (padlen > 0) { + dopr_outch (buffer, currlen, maxlen, ' '); + --padlen; + } + if (signvalue) + dopr_outch (buffer, currlen, maxlen, signvalue); + + while (iplace > 0) + dopr_outch (buffer, currlen, maxlen, iconvert[--iplace]); + +#ifdef DEBUG_SNPRINTF + printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen); +#endif + + /* + * Decimal point. This should probably use locale to find the correct + * char to print out. + */ + if (max > 0) { + dopr_outch (buffer, currlen, maxlen, '.'); + + while (zpadlen > 0) { + dopr_outch (buffer, currlen, maxlen, '0'); + --zpadlen; + } + + while (fplace > 0) + dopr_outch (buffer, currlen, maxlen, fconvert[--fplace]); + } + + while (padlen < 0) { + dopr_outch (buffer, currlen, maxlen, ' '); + ++padlen; + } +} + +static void dopr_outch(char *buffer, size_t *currlen, size_t maxlen, char c) +{ + if (*currlen < maxlen) { + buffer[(*currlen)] = c; + } + (*currlen)++; +} + +static struct pr_chunk *new_chunk(void) { + struct pr_chunk *new_c = (struct pr_chunk *)malloc(sizeof(struct pr_chunk)); + + if (!new_c) + return NULL; + + new_c->type = 0; + new_c->num = 0; + new_c->min = 0; + new_c->min_star = NULL; + new_c->max = -1; + new_c->max_star = NULL; + new_c->flags = 0; + new_c->cflags = 0; + new_c->start = 0; + new_c->len = 0; + new_c->value = 0; + new_c->fvalue = 0; + new_c->strvalue = NULL; + new_c->pnum = NULL; + new_c->next = NULL; + + return new_c; +} + +static int add_cnk_list_entry(struct pr_chunk_x **list, + int max_num, struct pr_chunk *chunk) { + struct pr_chunk_x *l; + struct pr_chunk **c; + int max; + int cnum; + int i, pos; + + if (chunk->num > max_num) { + max = chunk->num; + + if (*list == NULL) { + l = (struct pr_chunk_x *)malloc(sizeof(struct pr_chunk_x) * max); + pos = 0; + } else { + l = (struct pr_chunk_x *)realloc(*list, sizeof(struct pr_chunk_x) * max); + pos = max_num; + } + if (l == NULL) { + for (i = 0; i < max; i++) { + if ((*list)[i].chunks) free((*list)[i].chunks); + } + return 0; + } + for (i = pos; i < max; i++) { + l[i].chunks = NULL; + l[i].num = 0; + } + } else { + l = *list; + max = max_num; + } + + i = chunk->num - 1; + cnum = l[i].num + 1; + if (l[i].chunks == NULL) { + c = (struct pr_chunk **)malloc(sizeof(struct pr_chunk *) * cnum); + } else { + c = (struct pr_chunk **)realloc(l[i].chunks, sizeof(struct pr_chunk *) * cnum); + } + if (c == NULL) { + for (i = 0; i < max; i++) { + if (l[i].chunks) free(l[i].chunks); + } + return 0; + } + c[l[i].num] = chunk; + l[i].chunks = c; + l[i].num = cnum; + + *list = l; + return max; +} + + int rep_vsnprintf (char *str, size_t count, const char *fmt, va_list args) +{ + return dopr(str, count, fmt, args); +} +#endif + +/* yes this really must be a ||. Don't muck with this (tridge) + * + * The logic for these two is that we need our own definition if the + * OS *either* has no definition of *sprintf, or if it does have one + * that doesn't work properly according to the autoconf test. + */ +#if !defined(HAVE_SNPRINTF) || !defined(HAVE_C99_VSNPRINTF) + int rep_snprintf(char *str,size_t count,const char *fmt,...) +{ + size_t ret; + va_list ap; + + va_start(ap, fmt); + ret = vsnprintf(str, count, fmt, ap); + va_end(ap); + return ret; +} +#endif + +#ifndef HAVE_C99_VSNPRINTF + int rep_printf(const char *fmt, ...) +{ + va_list ap; + int ret; + char *s; + + s = NULL; + va_start(ap, fmt); + ret = vasprintf(&s, fmt, ap); + va_end(ap); + + if (s) { + fwrite(s, 1, strlen(s), stdout); + } + free(s); + + return ret; +} +#endif + +#ifndef HAVE_C99_VSNPRINTF + int rep_fprintf(FILE *stream, const char *fmt, ...) +{ + va_list ap; + int ret; + char *s; + + s = NULL; + va_start(ap, fmt); + ret = vasprintf(&s, fmt, ap); + va_end(ap); + + if (s) { + fwrite(s, 1, strlen(s), stream); + } + free(s); + + return ret; +} +#endif + +#endif + +#if !defined(HAVE_VASPRINTF) || !defined(HAVE_C99_VSNPRINTF) + int rep_vasprintf(char **ptr, const char *format, va_list ap) +{ + int ret; + va_list ap2; + + VA_COPY(ap2, ap); + ret = vsnprintf(NULL, 0, format, ap2); + va_end(ap2); + if (ret < 0) return ret; + + (*ptr) = (char *)malloc(ret+1); + if (!*ptr) return -1; + + VA_COPY(ap2, ap); + ret = vsnprintf(*ptr, ret+1, format, ap2); + va_end(ap2); + + return ret; +} +#endif + +#if !defined(HAVE_ASPRINTF) || !defined(HAVE_C99_VSNPRINTF) + int rep_asprintf(char **ptr, const char *format, ...) +{ + va_list ap; + int ret; + + *ptr = NULL; + va_start(ap, format); + ret = vasprintf(ptr, format, ap); + va_end(ap); + + return ret; +} +#endif + +#ifdef TEST_SNPRINTF + + int sprintf(char *str,const char *fmt,...); + int printf(const char *fmt,...); + + int main (void) +{ + char buf1[1024]; + char buf2[1024]; + char *buf3; + char *fp_fmt[] = { + "%1.1f", + "%-1.5f", + "%1.5f", + "%123.9f", + "%10.5f", + "% 10.5f", + "%+22.9f", + "%+4.9f", + "%01.3f", + "%4f", + "%3.1f", + "%3.2f", + "%.0f", + "%f", + "%-8.8f", + "%-9.9f", + NULL + }; + double fp_nums[] = { 6442452944.1234, -1.5, 134.21, 91340.2, 341.1234, 203.9, 0.96, 0.996, + 0.9996, 1.996, 4.136, 5.030201, 0.00205, + /* END LIST */ 0}; + char *int_fmt[] = { + "%-1.5d", + "%1.5d", + "%123.9d", + "%5.5d", + "%10.5d", + "% 10.5d", + "%+22.33d", + "%01.3d", + "%4d", + "%d", + NULL + }; + long int_nums[] = { -1, 134, 91340, 341, 0203, 1234567890, 0}; + char *str_fmt[] = { + "%10.5s", + "%-10.5s", + "%5.10s", + "%-5.10s", + "%10.1s", + "%0.10s", + "%10.0s", + "%1.10s", + "%s", + "%.1s", + "%.10s", + "%10s", + NULL + }; + char *str_vals[] = {"hello", "a", "", "a longer string", NULL}; +#ifdef HAVE_LONG_LONG + char *ll_fmt[] = { + "%llu", + NULL + }; + LLONG ll_nums[] = { 134, 91340, 341, 0203, 1234567890, 128006186140000000LL, 0}; +#endif + int x, y; + int fail = 0; + int num = 0; + int l1, l2; + char *ss_fmt[] = { + "%zd", + "%zu", + NULL + }; + size_t ss_nums[] = {134, 91340, 123456789, 0203, 1234567890, 0}; + + printf ("Testing snprintf format codes against system sprintf...\n"); + + for (x = 0; fp_fmt[x] ; x++) { + for (y = 0; fp_nums[y] != 0 ; y++) { + buf1[0] = buf2[0] = '\0'; + l1 = snprintf(buf1, sizeof(buf1), fp_fmt[x], fp_nums[y]); + l2 = sprintf (buf2, fp_fmt[x], fp_nums[y]); + buf1[1023] = buf2[1023] = '\0'; + if (strcmp (buf1, buf2) || (l1 != l2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", + fp_fmt[x], l1, buf1, l2, buf2); + fail++; + } + num++; + } + } + + for (x = 0; int_fmt[x] ; x++) { + for (y = 0; int_nums[y] != 0 ; y++) { + buf1[0] = buf2[0] = '\0'; + l1 = snprintf(buf1, sizeof(buf1), int_fmt[x], int_nums[y]); + l2 = sprintf (buf2, int_fmt[x], int_nums[y]); + buf1[1023] = buf2[1023] = '\0'; + if (strcmp (buf1, buf2) || (l1 != l2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", + int_fmt[x], l1, buf1, l2, buf2); + fail++; + } + num++; + } + } + + for (x = 0; str_fmt[x] ; x++) { + for (y = 0; str_vals[y] != 0 ; y++) { + buf1[0] = buf2[0] = '\0'; + l1 = snprintf(buf1, sizeof(buf1), str_fmt[x], str_vals[y]); + l2 = sprintf (buf2, str_fmt[x], str_vals[y]); + buf1[1023] = buf2[1023] = '\0'; + if (strcmp (buf1, buf2) || (l1 != l2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", + str_fmt[x], l1, buf1, l2, buf2); + fail++; + } + num++; + } + } + +#ifdef HAVE_LONG_LONG + for (x = 0; ll_fmt[x] ; x++) { + for (y = 0; ll_nums[y] != 0 ; y++) { + buf1[0] = buf2[0] = '\0'; + l1 = snprintf(buf1, sizeof(buf1), ll_fmt[x], ll_nums[y]); + l2 = sprintf (buf2, ll_fmt[x], ll_nums[y]); + buf1[1023] = buf2[1023] = '\0'; + if (strcmp (buf1, buf2) || (l1 != l2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", + ll_fmt[x], l1, buf1, l2, buf2); + fail++; + } + num++; + } + } +#endif + +#define BUFSZ 2048 + + buf1[0] = buf2[0] = '\0'; + if ((buf3 = malloc(BUFSZ)) == NULL) { + fail++; + } else { + num++; + memset(buf3, 'a', BUFSZ); + snprintf(buf1, sizeof(buf1), "%.*s", 1, buf3); + buf1[1023] = '\0'; + if (strcmp(buf1, "a") != 0) { + printf("length limit buf1 '%s' expected 'a'\n", buf1); + fail++; + } + } + + buf1[0] = buf2[0] = '\0'; + l1 = snprintf(buf1, sizeof(buf1), "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9); + l2 = sprintf(buf2, "%4$*1$d %2$s %3$*1$.*1$f", 3, "pos test", 12.3456, 9); + buf1[1023] = buf2[1023] = '\0'; + if (strcmp(buf1, buf2) || (l1 != l2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", + "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2); + fail++; + } + + buf1[0] = buf2[0] = '\0'; + l1 = snprintf(buf1, sizeof(buf1), "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9); + l2 = sprintf(buf2, "%4$*4$d %2$s %3$*4$.*4$f", 3, "pos test", 12.3456, 9); + buf1[1023] = buf2[1023] = '\0'; + if (strcmp(buf1, buf2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", + "%4$*1$d %2$s %3$*1$.*1$f", l1, buf1, l2, buf2); + fail++; + } + + for (x = 0; ss_fmt[x] ; x++) { + for (y = 0; ss_nums[y] != 0 ; y++) { + buf1[0] = buf2[0] = '\0'; + l1 = snprintf(buf1, sizeof(buf1), ss_fmt[x], ss_nums[y]); + l2 = sprintf (buf2, ss_fmt[x], ss_nums[y]); + buf1[1023] = buf2[1023] = '\0'; + if (strcmp (buf1, buf2) || (l1 != l2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", + ss_fmt[x], l1, buf1, l2, buf2); + fail++; + } + num++; + } + } +#if 0 + buf1[0] = buf2[0] = '\0'; + l1 = snprintf(buf1, sizeof(buf1), "%lld", (LLONG)1234567890); + l2 = sprintf(buf2, "%lld", (LLONG)1234567890); + buf1[1023] = buf2[1023] = '\0'; + if (strcmp(buf1, buf2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", + "%lld", l1, buf1, l2, buf2); + fail++; + } + + buf1[0] = buf2[0] = '\0'; + l1 = snprintf(buf1, sizeof(buf1), "%Lf", (LDOUBLE)890.1234567890123); + l2 = sprintf(buf2, "%Lf", (LDOUBLE)890.1234567890123); + buf1[1023] = buf2[1023] = '\0'; + if (strcmp(buf1, buf2)) { + printf("snprintf doesn't match Format: %s\n\tsnprintf(%d) = [%s]\n\t sprintf(%d) = [%s]\n", + "%Lf", l1, buf1, l2, buf2); + fail++; + } +#endif + printf ("%d tests failed out of %d.\n", fail, num); + + printf("seeing how many digits we support\n"); + { + double v0 = 0.12345678901234567890123456789012345678901; + for (x=0; x<100; x++) { + double p = pow(10, x); + double r = v0*p; + snprintf(buf1, sizeof(buf1), "%1.1f", r); + sprintf(buf2, "%1.1f", r); + if (strcmp(buf1, buf2)) { + printf("we seem to support %d digits\n", x-1); + break; + } + } + } + + return 0; +} +#endif /* TEST_SNPRINTF */ diff --git a/lib/replace/socket.c b/lib/replace/socket.c new file mode 100644 index 0000000..4cd9d2e --- /dev/null +++ b/lib/replace/socket.c @@ -0,0 +1,39 @@ +/* + * Unix SMB/CIFS implementation. + * + * Dummy replacements for socket functions. + * + * Copyright (C) Michael Adam <obnox@samba.org> 2008 + * + * ** NOTE! The following LGPL license applies to the replace + * ** library. This does NOT imply that all of Samba is released + * ** under the LGPL + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "replace.h" +#include "system/network.h" + +int rep_connect(int sockfd, const struct sockaddr *serv_addr, socklen_t addrlen) +{ + errno = ENOSYS; + return -1; +} + +struct hostent *rep_gethostbyname(const char *name) +{ + errno = ENOSYS; + return NULL; +} diff --git a/lib/replace/socketpair.c b/lib/replace/socketpair.c new file mode 100644 index 0000000..c775730 --- /dev/null +++ b/lib/replace/socketpair.c @@ -0,0 +1,46 @@ +/* + * Unix SMB/CIFS implementation. + * replacement routines for broken systems + * Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2006 + * Copyright (C) Michael Adam <obnox@samba.org> 2008 + * + * ** NOTE! The following LGPL license applies to the replace + * ** library. This does NOT imply that all of Samba is released + * ** under the LGPL + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include "replace.h" +#include "system/network.h" + +int rep_socketpair(int d, int type, int protocol, int sv[2]) +{ + if (d != AF_UNIX) { + errno = EAFNOSUPPORT; + return -1; + } + + if (protocol != 0) { + errno = EPROTONOSUPPORT; + return -1; + } + + if (type != SOCK_STREAM) { + errno = EOPNOTSUPP; + return -1; + } + + return pipe(sv); +} diff --git a/lib/replace/strptime.c b/lib/replace/strptime.c new file mode 100644 index 0000000..bbc7422 --- /dev/null +++ b/lib/replace/strptime.c @@ -0,0 +1,995 @@ +/* Convert a string representation of time to a time value. + Copyright (C) 1996, 1997, 1998, 1999, 2000 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Ulrich Drepper <drepper@cygnus.com>, 1996. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + see <http://www.gnu.org/licenses/>. */ + +/* XXX This version of the implementation is not really complete. + Some of the fields cannot add information alone. But if seeing + some of them in the same format (such as year, week and weekday) + this is enough information for determining the date. */ + +#include "replace.h" +#include "system/locale.h" +#include "system/time.h" + +#ifndef __P +# if defined (__GNUC__) || (defined (__STDC__) && __STDC__) +# define __P(args) args +# else +# define __P(args) () +# endif /* GCC. */ +#endif /* Not __P. */ + +#if ! HAVE_LOCALTIME_R && ! defined localtime_r +# ifdef _LIBC +# define localtime_r __localtime_r +# else +/* Approximate localtime_r as best we can in its absence. */ +# define localtime_r my_localtime_r +static struct tm *localtime_r __P ((const time_t *, struct tm *)); +static struct tm * +localtime_r (t, tp) + const time_t *t; + struct tm *tp; +{ + struct tm *l = localtime (t); + if (! l) + return 0; + *tp = *l; + return tp; +} +# endif /* ! _LIBC */ +#endif /* ! HAVE_LOCALTIME_R && ! defined (localtime_r) */ + + +#define match_char(ch1, ch2) if (ch1 != ch2) return NULL +#if defined __GNUC__ && __GNUC__ >= 2 +# define match_string(cs1, s2) \ + ({ size_t len = strlen (cs1); \ + int result = strncasecmp ((cs1), (s2), len) == 0; \ + if (result) (s2) += len; \ + result; }) +#else +/* Oh come on. Get a reasonable compiler. */ +# define match_string(cs1, s2) \ + (strncasecmp ((cs1), (s2), strlen (cs1)) ? 0 : ((s2) += strlen (cs1), 1)) +#endif +/* We intentionally do not use isdigit() for testing because this will + lead to problems with the wide character version. */ +#define get_number(from, to, n) \ + do { \ + int __n = n; \ + val = 0; \ + while (*rp == ' ') \ + ++rp; \ + if (*rp < '0' || *rp > '9') \ + return NULL; \ + do { \ + val *= 10; \ + val += *rp++ - '0'; \ + } while (--__n > 0 && val * 10 <= to && *rp >= '0' && *rp <= '9'); \ + if (val < from || val > to) \ + return NULL; \ + } while (0) +#ifdef _NL_CURRENT +# define get_alt_number(from, to, n) \ + ({ \ + __label__ do_normal; \ + if (*decided != raw) \ + { \ + const char *alts = _NL_CURRENT (LC_TIME, ALT_DIGITS); \ + int __n = n; \ + int any = 0; \ + while (*rp == ' ') \ + ++rp; \ + val = 0; \ + do { \ + val *= 10; \ + while (*alts != '\0') \ + { \ + size_t len = strlen (alts); \ + if (strncasecmp (alts, rp, len) == 0) \ + break; \ + alts += len + 1; \ + ++val; \ + } \ + if (*alts == '\0') \ + { \ + if (*decided == not && ! any) \ + goto do_normal; \ + /* If we haven't read anything it's an error. */ \ + if (! any) \ + return NULL; \ + /* Correct the premature multiplication. */ \ + val /= 10; \ + break; \ + } \ + else \ + *decided = loc; \ + } while (--__n > 0 && val * 10 <= to); \ + if (val < from || val > to) \ + return NULL; \ + } \ + else \ + { \ + do_normal: \ + get_number (from, to, n); \ + } \ + 0; \ + }) +#else +# define get_alt_number(from, to, n) \ + /* We don't have the alternate representation. */ \ + get_number(from, to, n) +#endif +#define recursive(new_fmt) \ + (*(new_fmt) != '\0' \ + && (rp = strptime_internal (rp, (new_fmt), tm, decided, era_cnt)) != NULL) + + +#ifdef _LIBC +/* This is defined in locale/C-time.c in the GNU libc. */ +extern const struct locale_data _nl_C_LC_TIME; +extern const unsigned short int __mon_yday[2][13]; + +# define weekday_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (DAY_1)].string) +# define ab_weekday_name \ + (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABDAY_1)].string) +# define month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (MON_1)].string) +# define ab_month_name (&_nl_C_LC_TIME.values[_NL_ITEM_INDEX (ABMON_1)].string) +# define HERE_D_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_T_FMT)].string) +# define HERE_D_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (D_FMT)].string) +# define HERE_AM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (AM_STR)].string) +# define HERE_PM_STR (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (PM_STR)].string) +# define HERE_T_FMT_AMPM \ + (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT_AMPM)].string) +# define HERE_T_FMT (_nl_C_LC_TIME.values[_NL_ITEM_INDEX (T_FMT)].string) + +# define strncasecmp(s1, s2, n) __strncasecmp (s1, s2, n) +#else +static char const weekday_name[][10] = + { + "Sunday", "Monday", "Tuesday", "Wednesday", + "Thursday", "Friday", "Saturday" + }; +static char const ab_weekday_name[][4] = + { + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" + }; +static char const month_name[][10] = + { + "January", "February", "March", "April", "May", "June", + "July", "August", "September", "October", "November", "December" + }; +static char const ab_month_name[][4] = + { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" + }; +# define HERE_D_T_FMT "%a %b %e %H:%M:%S %Y" +# define HERE_D_FMT "%m/%d/%y" +# define HERE_AM_STR "AM" +# define HERE_PM_STR "PM" +# define HERE_T_FMT_AMPM "%I:%M:%S %p" +# define HERE_T_FMT "%H:%M:%S" + +static const unsigned short int __mon_yday[2][13] = + { + /* Normal years. */ + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + /* Leap years. */ + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } + }; +#endif + +/* Status of lookup: do we use the locale data or the raw data? */ +enum locale_status { not, loc, raw }; + + +#ifndef __isleap +/* Nonzero if YEAR is a leap year (every 4 years, + except every 100th isn't, and every 400th is). */ +# define __isleap(year) \ + ((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0)) +#endif + +/* Compute the day of the week. */ +static void +day_of_the_week (struct tm *tm) +{ + /* We know that January 1st 1970 was a Thursday (= 4). Compute the + the difference between this data in the one on TM and so determine + the weekday. */ + int corr_year = 1900 + tm->tm_year - (tm->tm_mon < 2); + int wday = (-473 + + (365 * (tm->tm_year - 70)) + + (corr_year / 4) + - ((corr_year / 4) / 25) + ((corr_year / 4) % 25 < 0) + + (((corr_year / 4) / 25) / 4) + + __mon_yday[0][tm->tm_mon] + + tm->tm_mday - 1); + tm->tm_wday = ((wday % 7) + 7) % 7; +} + +/* Compute the day of the year. */ +static void +day_of_the_year (struct tm *tm) +{ + tm->tm_yday = (__mon_yday[__isleap (1900 + tm->tm_year)][tm->tm_mon] + + (tm->tm_mday - 1)); +} + +static char * +#ifdef _LIBC +internal_function +#endif +strptime_internal __P ((const char *rp, const char *fmt, struct tm *tm, + enum locale_status *decided, int era_cnt)); + +static char * +#ifdef _LIBC +internal_function +#endif +strptime_internal (rp, fmt, tm, decided, era_cnt) + const char *rp; + const char *fmt; + struct tm *tm; + enum locale_status *decided; + int era_cnt; +{ + int cnt; + size_t val; + int have_I, is_pm; + int century, want_century; + int want_era; + int have_wday, want_xday; + int have_yday; + int have_mon, have_mday; +#ifdef _NL_CURRENT + const char *rp_backup; + size_t num_eras; + struct era_entry *era; + + era = NULL; +#endif + + have_I = is_pm = 0; + century = -1; + want_century = 0; + want_era = 0; + + have_wday = want_xday = have_yday = have_mon = have_mday = 0; + + while (*fmt != '\0') + { + /* A white space in the format string matches 0 more or white + space in the input string. */ + if (isspace (*fmt)) + { + while (isspace (*rp)) + ++rp; + ++fmt; + continue; + } + + /* Any character but `%' must be matched by the same character + in the iput string. */ + if (*fmt != '%') + { + match_char (*fmt++, *rp++); + continue; + } + + ++fmt; +#ifndef _NL_CURRENT + /* We need this for handling the `E' modifier. */ + start_over: +#endif + +#ifdef _NL_CURRENT + /* Make back up of current processing pointer. */ + rp_backup = rp; +#endif + + switch (*fmt++) + { + case '%': + /* Match the `%' character itself. */ + match_char ('%', *rp++); + break; + case 'a': + case 'A': + /* Match day of week. */ + for (cnt = 0; cnt < 7; ++cnt) + { +#ifdef _NL_CURRENT + if (*decided !=raw) + { + if (match_string (_NL_CURRENT (LC_TIME, DAY_1 + cnt), rp)) + { + if (*decided == not + && strcmp (_NL_CURRENT (LC_TIME, DAY_1 + cnt), + weekday_name[cnt])) + *decided = loc; + break; + } + if (match_string (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), rp)) + { + if (*decided == not + && strcmp (_NL_CURRENT (LC_TIME, ABDAY_1 + cnt), + ab_weekday_name[cnt])) + *decided = loc; + break; + } + } +#endif + if (*decided != loc + && (match_string (weekday_name[cnt], rp) + || match_string (ab_weekday_name[cnt], rp))) + { + *decided = raw; + break; + } + } + if (cnt == 7) + /* Does not match a weekday name. */ + return NULL; + tm->tm_wday = cnt; + have_wday = 1; + break; + case 'b': + case 'B': + case 'h': + /* Match month name. */ + for (cnt = 0; cnt < 12; ++cnt) + { +#ifdef _NL_CURRENT + if (*decided !=raw) + { + if (match_string (_NL_CURRENT (LC_TIME, MON_1 + cnt), rp)) + { + if (*decided == not + && strcmp (_NL_CURRENT (LC_TIME, MON_1 + cnt), + month_name[cnt])) + *decided = loc; + break; + } + if (match_string (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), rp)) + { + if (*decided == not + && strcmp (_NL_CURRENT (LC_TIME, ABMON_1 + cnt), + ab_month_name[cnt])) + *decided = loc; + break; + } + } +#endif + if (match_string (month_name[cnt], rp) + || match_string (ab_month_name[cnt], rp)) + { + *decided = raw; + break; + } + } + if (cnt == 12) + /* Does not match a month name. */ + return NULL; + tm->tm_mon = cnt; + want_xday = 1; + break; + case 'c': + /* Match locale's date and time format. */ +#ifdef _NL_CURRENT + if (*decided != raw) + { + if (!recursive (_NL_CURRENT (LC_TIME, D_T_FMT))) + { + if (*decided == loc) + return NULL; + else + rp = rp_backup; + } + else + { + if (*decided == not && + strcmp (_NL_CURRENT (LC_TIME, D_T_FMT), HERE_D_T_FMT)) + *decided = loc; + want_xday = 1; + break; + } + *decided = raw; + } +#endif + if (!recursive (HERE_D_T_FMT)) + return NULL; + want_xday = 1; + break; + case 'C': + /* Match century number. */ +#ifdef _NL_CURRENT + match_century: +#endif + get_number (0, 99, 2); + century = val; + want_xday = 1; + break; + case 'd': + case 'e': + /* Match day of month. */ + get_number (1, 31, 2); + tm->tm_mday = val; + have_mday = 1; + want_xday = 1; + break; + case 'F': + if (!recursive ("%Y-%m-%d")) + return NULL; + want_xday = 1; + break; + case 'x': +#ifdef _NL_CURRENT + if (*decided != raw) + { + if (!recursive (_NL_CURRENT (LC_TIME, D_FMT))) + { + if (*decided == loc) + return NULL; + else + rp = rp_backup; + } + else + { + if (*decided == not + && strcmp (_NL_CURRENT (LC_TIME, D_FMT), HERE_D_FMT)) + *decided = loc; + want_xday = 1; + break; + } + *decided = raw; + } +#endif + + FALL_THROUGH; + case 'D': + /* Match standard day format. */ + if (!recursive (HERE_D_FMT)) + return NULL; + want_xday = 1; + break; + case 'k': + case 'H': + /* Match hour in 24-hour clock. */ + get_number (0, 23, 2); + tm->tm_hour = val; + have_I = 0; + break; + case 'I': + /* Match hour in 12-hour clock. */ + get_number (1, 12, 2); + tm->tm_hour = val % 12; + have_I = 1; + break; + case 'j': + /* Match day number of year. */ + get_number (1, 366, 3); + tm->tm_yday = val - 1; + have_yday = 1; + break; + case 'm': + /* Match number of month. */ + get_number (1, 12, 2); + tm->tm_mon = val - 1; + have_mon = 1; + want_xday = 1; + break; + case 'M': + /* Match minute. */ + get_number (0, 59, 2); + tm->tm_min = val; + break; + case 'n': + case 't': + /* Match any white space. */ + while (isspace (*rp)) + ++rp; + break; + case 'p': + /* Match locale's equivalent of AM/PM. */ +#ifdef _NL_CURRENT + if (*decided != raw) + { + if (match_string (_NL_CURRENT (LC_TIME, AM_STR), rp)) + { + if (strcmp (_NL_CURRENT (LC_TIME, AM_STR), HERE_AM_STR)) + *decided = loc; + break; + } + if (match_string (_NL_CURRENT (LC_TIME, PM_STR), rp)) + { + if (strcmp (_NL_CURRENT (LC_TIME, PM_STR), HERE_PM_STR)) + *decided = loc; + is_pm = 1; + break; + } + *decided = raw; + } +#endif + if (!match_string (HERE_AM_STR, rp)) { + if (match_string (HERE_PM_STR, rp)) { + is_pm = 1; + } else { + return NULL; + } + } + break; + case 'r': +#ifdef _NL_CURRENT + if (*decided != raw) + { + if (!recursive (_NL_CURRENT (LC_TIME, T_FMT_AMPM))) + { + if (*decided == loc) + return NULL; + else + rp = rp_backup; + } + else + { + if (*decided == not && + strcmp (_NL_CURRENT (LC_TIME, T_FMT_AMPM), + HERE_T_FMT_AMPM)) + *decided = loc; + break; + } + *decided = raw; + } +#endif + if (!recursive (HERE_T_FMT_AMPM)) + return NULL; + break; + case 'R': + if (!recursive ("%H:%M")) + return NULL; + break; + case 's': + { + /* The number of seconds may be very high so we cannot use + the `get_number' macro. Instead read the number + character for character and construct the result while + doing this. */ + time_t secs = 0; + if (*rp < '0' || *rp > '9') + /* We need at least one digit. */ + return NULL; + + do + { + secs *= 10; + secs += *rp++ - '0'; + } + while (*rp >= '0' && *rp <= '9'); + + if (localtime_r (&secs, tm) == NULL) + /* Error in function. */ + return NULL; + } + break; + case 'S': + get_number (0, 61, 2); + tm->tm_sec = val; + break; + case 'X': +#ifdef _NL_CURRENT + if (*decided != raw) + { + if (!recursive (_NL_CURRENT (LC_TIME, T_FMT))) + { + if (*decided == loc) + return NULL; + else + rp = rp_backup; + } + else + { + if (strcmp (_NL_CURRENT (LC_TIME, T_FMT), HERE_T_FMT)) + *decided = loc; + break; + } + *decided = raw; + } +#endif + + FALL_THROUGH; + case 'T': + if (!recursive (HERE_T_FMT)) + return NULL; + break; + case 'u': + get_number (1, 7, 1); + tm->tm_wday = val % 7; + have_wday = 1; + break; + case 'g': + get_number (0, 99, 2); + /* XXX This cannot determine any field in TM. */ + break; + case 'G': + if (*rp < '0' || *rp > '9') + return NULL; + /* XXX Ignore the number since we would need some more + information to compute a real date. */ + do + ++rp; + while (*rp >= '0' && *rp <= '9'); + break; + case 'U': + case 'V': + case 'W': + get_number (0, 53, 2); + /* XXX This cannot determine any field in TM without some + information. */ + break; + case 'w': + /* Match number of weekday. */ + get_number (0, 6, 1); + tm->tm_wday = val; + have_wday = 1; + break; + case 'y': +#ifdef _NL_CURRENT + match_year_in_century: +#endif + /* Match year within century. */ + get_number (0, 99, 2); + /* The "Year 2000: The Millennium Rollover" paper suggests that + values in the range 69-99 refer to the twentieth century. */ + tm->tm_year = val >= 69 ? val : val + 100; + /* Indicate that we want to use the century, if specified. */ + want_century = 1; + want_xday = 1; + break; + case 'Y': + /* Match year including century number. */ + get_number (0, 9999, 4); + tm->tm_year = val - 1900; + want_century = 0; + want_xday = 1; + break; + case 'Z': + /* XXX How to handle this? */ + break; + case 'E': +#ifdef _NL_CURRENT + switch (*fmt++) + { + case 'c': + /* Match locale's alternate date and time format. */ + if (*decided != raw) + { + const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_T_FMT); + + if (*fmt == '\0') + fmt = _NL_CURRENT (LC_TIME, D_T_FMT); + + if (!recursive (fmt)) + { + if (*decided == loc) + return NULL; + else + rp = rp_backup; + } + else + { + if (strcmp (fmt, HERE_D_T_FMT)) + *decided = loc; + want_xday = 1; + break; + } + *decided = raw; + } + /* The C locale has no era information, so use the + normal representation. */ + if (!recursive (HERE_D_T_FMT)) + return NULL; + want_xday = 1; + break; + case 'C': + if (*decided != raw) + { + if (era_cnt >= 0) + { + era = _nl_select_era_entry (era_cnt); + if (match_string (era->era_name, rp)) + { + *decided = loc; + break; + } + else + return NULL; + } + else + { + num_eras = _NL_CURRENT_WORD (LC_TIME, + _NL_TIME_ERA_NUM_ENTRIES); + for (era_cnt = 0; era_cnt < (int) num_eras; + ++era_cnt, rp = rp_backup) + { + era = _nl_select_era_entry (era_cnt); + if (match_string (era->era_name, rp)) + { + *decided = loc; + break; + } + } + if (era_cnt == (int) num_eras) + { + era_cnt = -1; + if (*decided == loc) + return NULL; + } + else + break; + } + + *decided = raw; + } + /* The C locale has no era information, so use the + normal representation. */ + goto match_century; + case 'y': + if (*decided == raw) + goto match_year_in_century; + + get_number(0, 9999, 4); + tm->tm_year = val; + want_era = 1; + want_xday = 1; + break; + case 'Y': + if (*decided != raw) + { + num_eras = _NL_CURRENT_WORD (LC_TIME, + _NL_TIME_ERA_NUM_ENTRIES); + for (era_cnt = 0; era_cnt < (int) num_eras; + ++era_cnt, rp = rp_backup) + { + era = _nl_select_era_entry (era_cnt); + if (recursive (era->era_format)) + break; + } + if (era_cnt == (int) num_eras) + { + era_cnt = -1; + if (*decided == loc) + return NULL; + else + rp = rp_backup; + } + else + { + *decided = loc; + era_cnt = -1; + break; + } + + *decided = raw; + } + get_number (0, 9999, 4); + tm->tm_year = val - 1900; + want_century = 0; + want_xday = 1; + break; + case 'x': + if (*decided != raw) + { + const char *fmt = _NL_CURRENT (LC_TIME, ERA_D_FMT); + + if (*fmt == '\0') + fmt = _NL_CURRENT (LC_TIME, D_FMT); + + if (!recursive (fmt)) + { + if (*decided == loc) + return NULL; + else + rp = rp_backup; + } + else + { + if (strcmp (fmt, HERE_D_FMT)) + *decided = loc; + break; + } + *decided = raw; + } + if (!recursive (HERE_D_FMT)) + return NULL; + break; + case 'X': + if (*decided != raw) + { + const char *fmt = _NL_CURRENT (LC_TIME, ERA_T_FMT); + + if (*fmt == '\0') + fmt = _NL_CURRENT (LC_TIME, T_FMT); + + if (!recursive (fmt)) + { + if (*decided == loc) + return NULL; + else + rp = rp_backup; + } + else + { + if (strcmp (fmt, HERE_T_FMT)) + *decided = loc; + break; + } + *decided = raw; + } + if (!recursive (HERE_T_FMT)) + return NULL; + break; + default: + return NULL; + } + break; +#else + /* We have no information about the era format. Just use + the normal format. */ + if (*fmt != 'c' && *fmt != 'C' && *fmt != 'y' && *fmt != 'Y' + && *fmt != 'x' && *fmt != 'X') + /* This is an illegal format. */ + return NULL; + + goto start_over; +#endif + case 'O': + switch (*fmt++) + { + case 'd': + case 'e': + /* Match day of month using alternate numeric symbols. */ + get_alt_number (1, 31, 2); + tm->tm_mday = val; + have_mday = 1; + want_xday = 1; + break; + case 'H': + /* Match hour in 24-hour clock using alternate numeric + symbols. */ + get_alt_number (0, 23, 2); + tm->tm_hour = val; + have_I = 0; + break; + case 'I': + /* Match hour in 12-hour clock using alternate numeric + symbols. */ + get_alt_number (1, 12, 2); + tm->tm_hour = val - 1; + have_I = 1; + break; + case 'm': + /* Match month using alternate numeric symbols. */ + get_alt_number (1, 12, 2); + tm->tm_mon = val - 1; + have_mon = 1; + want_xday = 1; + break; + case 'M': + /* Match minutes using alternate numeric symbols. */ + get_alt_number (0, 59, 2); + tm->tm_min = val; + break; + case 'S': + /* Match seconds using alternate numeric symbols. */ + get_alt_number (0, 61, 2); + tm->tm_sec = val; + break; + case 'U': + case 'V': + case 'W': + get_alt_number (0, 53, 2); + /* XXX This cannot determine any field in TM without + further information. */ + break; + case 'w': + /* Match number of weekday using alternate numeric symbols. */ + get_alt_number (0, 6, 1); + tm->tm_wday = val; + have_wday = 1; + break; + case 'y': + /* Match year within century using alternate numeric symbols. */ + get_alt_number (0, 99, 2); + tm->tm_year = val >= 69 ? val : val + 100; + want_xday = 1; + break; + default: + return NULL; + } + break; + default: + return NULL; + } + } + + if (have_I && is_pm) + tm->tm_hour += 12; + + if (century != -1) + { + if (want_century) + tm->tm_year = tm->tm_year % 100 + (century - 19) * 100; + else + /* Only the century, but not the year. Strange, but so be it. */ + tm->tm_year = (century - 19) * 100; + } + +#ifdef _NL_CURRENT + if (era_cnt != -1) + { + era = _nl_select_era_entry(era_cnt); + if (want_era) + tm->tm_year = (era->start_date[0] + + ((tm->tm_year - era->offset) + * era->absolute_direction)); + else + /* Era start year assumed. */ + tm->tm_year = era->start_date[0]; + } + else +#endif + if (want_era) + return NULL; + + if (want_xday && !have_wday) + { + if ( !(have_mon && have_mday) && have_yday) + { + /* We don't have tm_mon and/or tm_mday, compute them. */ + int t_mon = 0; + while (__mon_yday[__isleap(1900 + tm->tm_year)][t_mon] <= tm->tm_yday) + t_mon++; + if (!have_mon) + tm->tm_mon = t_mon - 1; + if (!have_mday) + tm->tm_mday = + (tm->tm_yday + - __mon_yday[__isleap(1900 + tm->tm_year)][t_mon - 1] + 1); + } + day_of_the_week (tm); + } + if (want_xday && !have_yday) + day_of_the_year (tm); + + return discard_const_p(char, rp); +} + + +char *rep_strptime(const char *buf, const char *format, struct tm *tm) +{ + enum locale_status decided; + +#ifdef _NL_CURRENT + decided = not; +#else + decided = raw; +#endif + return strptime_internal (buf, format, tm, &decided, -1); +} diff --git a/lib/replace/system/README b/lib/replace/system/README new file mode 100644 index 0000000..69a2b80 --- /dev/null +++ b/lib/replace/system/README @@ -0,0 +1,4 @@ +This directory contains wrappers around logical groups of system +include files. The idea is to avoid #ifdef blocks in the main code, +and instead put all the necessary conditional includes in subsystem +specific header files in this directory. diff --git a/lib/replace/system/capability.h b/lib/replace/system/capability.h new file mode 100644 index 0000000..44b8d51 --- /dev/null +++ b/lib/replace/system/capability.h @@ -0,0 +1,57 @@ +#ifndef _system_capability_h +#define _system_capability_h +/* + Unix SMB/CIFS implementation. + + capability system include wrappers + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#ifdef HAVE_SYS_CAPABILITY_H + +#if defined(BROKEN_REDHAT_7_SYSTEM_HEADERS) && !defined(_I386_STATFS_H) && !defined(_PPC_STATFS_H) +#define _I386_STATFS_H +#define _PPC_STATFS_H +#define BROKEN_REDHAT_7_STATFS_WORKAROUND +#endif + +#if defined(BROKEN_RHEL5_SYS_CAP_HEADER) && !defined(_LINUX_TYPES_H) +#define BROKEN_RHEL5_SYS_CAP_HEADER_WORKAROUND +#endif + +#ifdef HAVE_POSIX_CAPABILITIES +#include <sys/capability.h> +#endif + +#ifdef BROKEN_RHEL5_SYS_CAP_HEADER_WORKAROUND +#undef _LINUX_TYPES_H +#undef BROKEN_RHEL5_SYS_CAP_HEADER_WORKAROUND +#endif + +#ifdef BROKEN_REDHAT_7_STATFS_WORKAROUND +#undef _PPC_STATFS_H +#undef _I386_STATFS_H +#undef BROKEN_REDHAT_7_STATFS_WORKAROUND +#endif + +#endif + +#endif diff --git a/lib/replace/system/dir.h b/lib/replace/system/dir.h new file mode 100644 index 0000000..497b5a7 --- /dev/null +++ b/lib/replace/system/dir.h @@ -0,0 +1,71 @@ +#ifndef _system_dir_h +#define _system_dir_h +/* + Unix SMB/CIFS implementation. + + directory system include wrappers + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#ifdef HAVE_DIRENT_H +# include <dirent.h> +# define NAMLEN(dirent) strlen((dirent)->d_name) +#else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if HAVE_SYS_NDIR_H +# include <sys/ndir.h> +# endif +# if HAVE_SYS_DIR_H +# include <sys/dir.h> +# endif +# if HAVE_NDIR_H +# include <ndir.h> +# endif +#endif + +#ifndef HAVE_MKDIR_MODE +#define mkdir(dir, mode) mkdir(dir) +#endif + +#ifdef HAVE_LIBGEN_H +# include <libgen.h> +#endif + +/* Test whether a file name is the "." or ".." directory entries. + * These really should be inline functions. + */ +#ifndef ISDOT +#define ISDOT(path) ( \ + *((const char *)(path)) == '.' && \ + *(((const char *)(path)) + 1) == '\0' \ + ) +#endif + +#ifndef ISDOTDOT +#define ISDOTDOT(path) ( \ + *((const char *)(path)) == '.' && \ + *(((const char *)(path)) + 1) == '.' && \ + *(((const char *)(path)) + 2) == '\0' \ + ) +#endif + +#endif diff --git a/lib/replace/system/filesys.h b/lib/replace/system/filesys.h new file mode 100644 index 0000000..8005b18 --- /dev/null +++ b/lib/replace/system/filesys.h @@ -0,0 +1,281 @@ +#ifndef _system_filesys_h +#define _system_filesys_h +/* + Unix SMB/CIFS implementation. + + filesystem system include wrappers + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#include <sys/stat.h> + +#ifdef HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + +/* This include is required on UNIX (*BSD, AIX, ...) for statfs() */ +#if !defined(LINUX) && defined(HAVE_SYS_MOUNT_H) +#include <sys/mount.h> +#endif + +#ifdef HAVE_MNTENT_H +#include <mntent.h> +#endif + +/* This include is required on Linux for statfs() */ +#ifdef HAVE_SYS_VFS_H +#include <sys/vfs.h> +#endif + +#ifdef HAVE_SYS_ACL_H +#include <sys/acl.h> +#endif + +#ifdef HAVE_ACL_LIBACL_H +#include <acl/libacl.h> +#endif + +#ifdef HAVE_SYS_FS_S5PARAM_H +#include <sys/fs/s5param.h> +#endif + +#if defined (HAVE_SYS_FILSYS_H) && !defined (_CRAY) +#include <sys/filsys.h> +#endif + +#ifdef HAVE_SYS_STATFS_H +# include <sys/statfs.h> +#endif + +#ifdef HAVE_DUSTAT_H +#include <sys/dustat.h> +#endif + +#ifdef HAVE_SYS_STATVFS_H +#include <sys/statvfs.h> +#endif + +#ifdef HAVE_SYS_FILIO_H +#include <sys/filio.h> +#endif + +#ifdef HAVE_SYS_FILE_H +#include <sys/file.h> +#endif + +#ifdef HAVE_FCNTL_H +#include <fcntl.h> +#else +#ifdef HAVE_SYS_FCNTL_H +#include <sys/fcntl.h> +#endif +#endif + +#ifdef HAVE_SYS_MODE_H +/* apparently AIX needs this for S_ISLNK */ +#ifndef S_ISLNK +#include <sys/mode.h> +#endif +#endif + +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#ifdef HAVE_SYS_UIO_H +#include <sys/uio.h> +#endif + +/* mutually exclusive (SuSE 8.2) */ +#if defined(HAVE_SYS_XATTR_H) +#include <sys/xattr.h> +#elif defined(HAVE_ATTR_XATTR_H) +#include <attr/xattr.h> +#elif defined(HAVE_SYS_ATTRIBUTES_H) +#include <sys/attributes.h> +#elif defined(HAVE_ATTR_ATTRIBUTES_H) +#include <attr/attributes.h> +#endif + +#ifdef HAVE_SYS_EA_H +#include <sys/ea.h> +#endif + +#ifdef HAVE_SYS_EXTATTR_H +#include <sys/extattr.h> +#endif + +#ifdef HAVE_SYS_RESOURCE_H +#include <sys/resource.h> +#endif + +#ifndef XATTR_CREATE +#define XATTR_CREATE 0x1 /* set value, fail if attr already exists */ +#endif + +#ifndef XATTR_REPLACE +#define XATTR_REPLACE 0x2 /* set value, fail if attr does not exist */ +#endif + +/* Some POSIX definitions for those without */ + +#ifndef S_IFDIR +#define S_IFDIR 0x4000 +#endif +#ifndef S_ISDIR +#define S_ISDIR(mode) ((mode & 0xF000) == S_IFDIR) +#endif +#ifndef S_IRWXU +#define S_IRWXU 00700 /* read, write, execute: owner */ +#endif +#ifndef S_IRUSR +#define S_IRUSR 00400 /* read permission: owner */ +#endif +#ifndef S_IWUSR +#define S_IWUSR 00200 /* write permission: owner */ +#endif +#ifndef S_IXUSR +#define S_IXUSR 00100 /* execute permission: owner */ +#endif +#ifndef S_IRWXG +#define S_IRWXG 00070 /* read, write, execute: group */ +#endif +#ifndef S_IRGRP +#define S_IRGRP 00040 /* read permission: group */ +#endif +#ifndef S_IWGRP +#define S_IWGRP 00020 /* write permission: group */ +#endif +#ifndef S_IXGRP +#define S_IXGRP 00010 /* execute permission: group */ +#endif +#ifndef S_IRWXO +#define S_IRWXO 00007 /* read, write, execute: other */ +#endif +#ifndef S_IROTH +#define S_IROTH 00004 /* read permission: other */ +#endif +#ifndef S_IWOTH +#define S_IWOTH 00002 /* write permission: other */ +#endif +#ifndef S_IXOTH +#define S_IXOTH 00001 /* execute permission: other */ +#endif + +#ifndef O_ACCMODE +#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR) +#endif + +#ifndef MAXPATHLEN +#define MAXPATHLEN 256 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#ifdef _WIN32 +#define mkdir(d,m) _mkdir(d) +#endif + +#ifdef DISABLE_OPATH +#undef O_PATH +#endif + +/* + this allows us to use a uniform error handling for our xattr + wrappers +*/ +#ifndef ENOATTR +#define ENOATTR ENODATA +#endif + + +#if !defined(HAVE_XATTR_XATTR) || defined(XATTR_ADDITIONAL_OPTIONS) + +ssize_t rep_getxattr (const char *path, const char *name, void *value, size_t size); +#define getxattr(path, name, value, size) rep_getxattr(path, name, value, size) +/* define is in "replace.h" */ +ssize_t rep_fgetxattr (int filedes, const char *name, void *value, size_t size); +#define fgetxattr(filedes, name, value, size) rep_fgetxattr(filedes, name, value, size) +/* define is in "replace.h" */ +ssize_t rep_listxattr (const char *path, char *list, size_t size); +#define listxattr(path, list, size) rep_listxattr(path, list, size) +/* define is in "replace.h" */ +ssize_t rep_flistxattr (int filedes, char *list, size_t size); +#define flistxattr(filedes, value, size) rep_flistxattr(filedes, value, size) +/* define is in "replace.h" */ +int rep_removexattr (const char *path, const char *name); +#define removexattr(path, name) rep_removexattr(path, name) +/* define is in "replace.h" */ +int rep_fremovexattr (int filedes, const char *name); +#define fremovexattr(filedes, name) rep_fremovexattr(filedes, name) +/* define is in "replace.h" */ +int rep_setxattr (const char *path, const char *name, const void *value, size_t size, int flags); +#define setxattr(path, name, value, size, flags) rep_setxattr(path, name, value, size, flags) +/* define is in "replace.h" */ +int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags); +#define fsetxattr(filedes, name, value, size, flags) rep_fsetxattr(filedes, name, value, size, flags) +/* define is in "replace.h" */ + +#endif /* !defined(HAVE_XATTR_XATTR) || defined(XATTR_ADDITIONAL_OPTIONS) */ + +#ifdef HAVE_LINUX_OPENAT2_H +#include <linux/openat2.h> +#else /* ! HAVE_LINUX_OPENAT2_H */ +/* how->resolve flags for openat2(2). */ +#define RESOLVE_NO_XDEV 0x01 /* Block mount-point crossings + (includes bind-mounts). */ +#define RESOLVE_NO_MAGICLINKS 0x02 /* Block traversal through procfs-style + "magic-links". */ +#define RESOLVE_NO_SYMLINKS 0x04 /* Block traversal through all symlinks + (implies OEXT_NO_MAGICLINKS) */ +#define RESOLVE_BENEATH 0x08 /* Block "lexical" trickery like + "..", symlinks, and absolute + paths which escape the dirfd. */ +#define RESOLVE_IN_ROOT 0x10 /* Make all jumps to "/" and ".." + be scoped inside the dirfd + (similar to chroot(2)). */ +#define RESOLVE_CACHED 0x20 /* Only complete if resolution can be + completed through cached lookup. May + return -EAGAIN if that's not + possible. */ +struct __rep_open_how { + uint64_t flags; + uint64_t mode; + uint64_t resolve; +}; +#define open_how __rep_open_how +#endif /* ! HAVE_LINUX_OPENAT2_H */ + +#ifndef HAVE_OPENAT2 +long rep_openat2(int dirfd, const char *pathname, + struct open_how *how, size_t size); +#define openat2(dirfd, pathname, how, size) \ + rep_openat2(dirfd, pathname, how, size) +#endif /* !HAVE_OPENAT2 */ + +#endif diff --git a/lib/replace/system/glob.h b/lib/replace/system/glob.h new file mode 100644 index 0000000..3e23db6 --- /dev/null +++ b/lib/replace/system/glob.h @@ -0,0 +1,37 @@ +#ifndef _system_glob_h +#define _system_glob_h +/* + Unix SMB/CIFS implementation. + + glob system include wrappers + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifdef HAVE_GLOB_H +#include <glob.h> +#endif + +#ifdef HAVE_FNMATCH_H +#include <fnmatch.h> +#endif + +#endif diff --git a/lib/replace/system/gssapi.h b/lib/replace/system/gssapi.h new file mode 100644 index 0000000..d8632d7 --- /dev/null +++ b/lib/replace/system/gssapi.h @@ -0,0 +1,53 @@ +#ifndef _system_gssapi_h +#define _system_gssapi_h + +/* + Unix SMB/CIFS implementation. + + GSSAPI system include wrappers + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifdef HAVE_GSSAPI + +#ifdef HAVE_GSSAPI_GSSAPI_EXT_H +#include <gssapi/gssapi_ext.h> +#elif defined(HAVE_GSSAPI_GSSAPI_H) +#include <gssapi/gssapi.h> +#elif defined(HAVE_GSSAPI_GSSAPI_GENERIC_H) +#include <gssapi/gssapi_generic.h> +#elif defined(HAVE_GSSAPI_H) +#include <gssapi.h> +#endif + +#ifdef HAVE_GSSAPI_GSSAPI_KRB5_H +#include <gssapi/gssapi_krb5.h> +#endif + +#ifdef HAVE_GSSAPI_GSSAPI_SPNEGO_H +#include <gssapi/gssapi_spnego.h> +#elif defined(HAVE_GSSAPI_SPNEGO_H) +#include <gssapi_spnego.h> +#endif + +#endif +#endif diff --git a/lib/replace/system/iconv.h b/lib/replace/system/iconv.h new file mode 100644 index 0000000..3c8a71f --- /dev/null +++ b/lib/replace/system/iconv.h @@ -0,0 +1,57 @@ +#ifndef _system_iconv_h +#define _system_iconv_h +/* + Unix SMB/CIFS implementation. + + iconv memory system include wrappers + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. + +*/ + +#if !defined(HAVE_ICONV) && defined(HAVE_ICONV_H) +#define HAVE_ICONV +#endif + +#if !defined(HAVE_GICONV) && defined(HAVE_GICONV_H) +#define HAVE_GICONV +#endif + +#if !defined(HAVE_BICONV) && defined(HAVE_BICONV_H) +#define HAVE_BICONV +#endif + +#ifdef HAVE_NATIVE_ICONV +#if defined(HAVE_ICONV) +#include <iconv.h> +#elif defined(HAVE_GICONV) +#include <giconv.h> +#elif defined(HAVE_BICONV) +#include <biconv.h> +#endif +#endif /* HAVE_NATIVE_ICONV */ + +/* needed for some systems without iconv. Doesn't really matter + what error code we use */ +#ifndef EILSEQ +#define EILSEQ EIO +#endif + +#endif diff --git a/lib/replace/system/kerberos.h b/lib/replace/system/kerberos.h new file mode 100644 index 0000000..ebd8657 --- /dev/null +++ b/lib/replace/system/kerberos.h @@ -0,0 +1,41 @@ +#ifndef _system_kerberos_h +#define _system_kerberos_h + +/* + Unix SMB/CIFS implementation. + + kerberos system include wrappers + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifdef HAVE_KRB5 + +#ifdef HAVE_KRB5_H +#include <krb5.h> +#endif + +#ifdef HAVE_COM_ERR_H +#include <com_err.h> +#endif + +#endif +#endif diff --git a/lib/replace/system/locale.h b/lib/replace/system/locale.h new file mode 100644 index 0000000..504a3bb --- /dev/null +++ b/lib/replace/system/locale.h @@ -0,0 +1,42 @@ +#ifndef _system_locale_h +#define _system_locale_h + +/* + Unix SMB/CIFS implementation. + + locale include wrappers + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifdef HAVE_CTYPE_H +#include <ctype.h> +#endif + +#ifdef HAVE_LOCALE_H +#include <locale.h> +#endif + +#ifdef HAVE_LANGINFO_H +#include <langinfo.h> +#endif + +#endif diff --git a/lib/replace/system/network.h b/lib/replace/system/network.h new file mode 100644 index 0000000..1721d65 --- /dev/null +++ b/lib/replace/system/network.h @@ -0,0 +1,391 @@ +#ifndef _system_network_h +#define _system_network_h +/* + Unix SMB/CIFS implementation. + + networking system include wrappers + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Jelmer Vernooij 2007 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifndef LIBREPLACE_NETWORK_CHECKS +#error "AC_LIBREPLACE_NETWORK_CHECKS missing in configure" +#endif + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif + +#ifdef HAVE_UNIXSOCKET +#include <sys/un.h> +#endif + +#ifdef HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif + +#ifdef HAVE_NETDB_H +#include <netdb.h> +#endif + +#ifdef HAVE_NETINET_TCP_H +#include <netinet/tcp.h> +#endif + +/* + * The next three defines are needed to access the IPTOS_* options + * on some systems. + */ + +#ifdef HAVE_NETINET_IN_SYSTM_H +#include <netinet/in_systm.h> +#endif + +#ifdef HAVE_NETINET_IN_IP_H +#include <netinet/in_ip.h> +#endif + +#ifdef HAVE_NETINET_IP_H +#include <netinet/ip.h> +#endif + +#ifdef HAVE_NET_IF_H +#include <net/if.h> +#endif + +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#ifdef HAVE_SYS_UIO_H +#include <sys/uio.h> +#endif + +#ifdef HAVE_STROPTS_H +#include <stropts.h> +#endif + +#include <limits.h> + +#ifndef HAVE_SOCKLEN_T +#define HAVE_SOCKLEN_T +typedef int socklen_t; +#endif + +#if !defined (HAVE_INET_NTOA) || defined(REPLACE_INET_NTOA) +/* define is in "replace.h" */ +char *rep_inet_ntoa(struct in_addr ip); +#endif + +#ifndef HAVE_INET_PTON +/* define is in "replace.h" */ +int rep_inet_pton(int af, const char *src, void *dst); +#endif + +#ifndef HAVE_INET_NTOP +/* define is in "replace.h" */ +const char *rep_inet_ntop(int af, const void *src, char *dst, socklen_t size); +#endif + +#ifndef HAVE_INET_ATON +/* define is in "replace.h" */ +int rep_inet_aton(const char *src, struct in_addr *dst); +#endif + +#ifndef HAVE_CONNECT +/* define is in "replace.h" */ +int rep_connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen); +#endif + +#ifndef HAVE_GETHOSTBYNAME +/* define is in "replace.h" */ +struct hostent *rep_gethostbyname(const char *name); +#endif + +#ifdef HAVE_IFADDRS_H +#include <ifaddrs.h> +#endif + +#ifndef HAVE_STRUCT_IFADDRS +struct ifaddrs { + struct ifaddrs *ifa_next; /* Pointer to next struct */ + char *ifa_name; /* Interface name */ + unsigned int ifa_flags; /* Interface flags */ + struct sockaddr *ifa_addr; /* Interface address */ + struct sockaddr *ifa_netmask; /* Interface netmask */ +#undef ifa_dstaddr + struct sockaddr *ifa_dstaddr; /* P2P interface destination */ + void *ifa_data; /* Address specific data */ +}; +#endif + +#ifndef HAVE_GETIFADDRS +int rep_getifaddrs(struct ifaddrs **); +#endif + +#ifndef HAVE_FREEIFADDRS +void rep_freeifaddrs(struct ifaddrs *); +#endif + +#ifndef HAVE_SOCKETPAIR +/* define is in "replace.h" */ +int rep_socketpair(int d, int type, int protocol, int sv[2]); +#endif + +/* + * Some systems have getaddrinfo but not the + * defines needed to use it. + */ + +/* Various macros that ought to be in <netdb.h>, but might not be */ + +#ifndef EAI_FAIL +#define EAI_BADFLAGS (-1) +#define EAI_NONAME (-2) +#define EAI_AGAIN (-3) +#define EAI_FAIL (-4) +#define EAI_FAMILY (-6) +#define EAI_SOCKTYPE (-7) +#define EAI_SERVICE (-8) +#define EAI_MEMORY (-10) +#define EAI_SYSTEM (-11) +#endif /* !EAI_FAIL */ + +#ifndef AI_PASSIVE +#define AI_PASSIVE 0x0001 +#endif + +#ifndef AI_CANONNAME +#define AI_CANONNAME 0x0002 +#endif + +#ifndef AI_NUMERICHOST +/* + * some platforms don't support AI_NUMERICHOST; define as zero if using + * the system version of getaddrinfo... + */ +#if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO) +#define AI_NUMERICHOST 0 +#else +#define AI_NUMERICHOST 0x0004 +#endif +#endif + +/* + * Some of the functions in source3/lib/util_sock.c use AI_ADDRCONFIG. On QNX + * 6.3.0, this macro is defined but, if it's used, getaddrinfo will fail. This + * prevents smbd from opening any sockets. + * + * If I undefine AI_ADDRCONFIG on such systems and define it to be 0, + * this works around the issue. + */ +#ifdef __QNX__ +#include <sys/neutrino.h> +#if _NTO_VERSION == 630 +#undef AI_ADDRCONFIG +#endif +#endif +#ifndef AI_ADDRCONFIG +/* + * logic copied from AI_NUMERICHOST + */ +#if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO) +#define AI_ADDRCONFIG 0 +#else +#define AI_ADDRCONFIG 0x0020 +#endif +#endif + +#ifndef AI_NUMERICSERV +/* + * logic copied from AI_NUMERICHOST + */ +#if defined(HAVE_STRUCT_ADDRINFO) && defined(HAVE_GETADDRINFO) +#define AI_NUMERICSERV 0 +#else +#define AI_NUMERICSERV 0x0400 +#endif +#endif + +#ifndef NI_NUMERICHOST +#define NI_NUMERICHOST 1 +#endif + +#ifndef NI_NUMERICSERV +#define NI_NUMERICSERV 2 +#endif + +#ifndef NI_NOFQDN +#define NI_NOFQDN 4 +#endif + +#ifndef NI_NAMEREQD +#define NI_NAMEREQD 8 +#endif + +#ifndef NI_DGRAM +#define NI_DGRAM 16 +#endif + + +#ifndef NI_MAXHOST +#define NI_MAXHOST 1025 +#endif + +#ifndef NI_MAXSERV +#define NI_MAXSERV 32 +#endif + +/* + * glibc on linux doesn't seem to have MSG_WAITALL + * defined. I think the kernel has it though.. + */ +#ifndef MSG_WAITALL +#define MSG_WAITALL 0 +#endif + +#ifndef INADDR_LOOPBACK +#define INADDR_LOOPBACK 0x7f000001 +#endif + +#ifndef INADDR_NONE +#define INADDR_NONE 0xffffffff +#endif + +#ifndef EAFNOSUPPORT +#define EAFNOSUPPORT EINVAL +#endif + +#ifndef INET_ADDRSTRLEN +#define INET_ADDRSTRLEN 16 +#endif + +#ifndef INET6_ADDRSTRLEN +#define INET6_ADDRSTRLEN 46 +#endif + +#ifndef HOST_NAME_MAX +#define HOST_NAME_MAX 255 +#endif + +#ifndef MAXHOSTNAMELEN +#define MAXHOSTNAMELEN HOST_NAME_MAX +#endif + +#ifndef HAVE_SA_FAMILY_T +#define HAVE_SA_FAMILY_T +typedef unsigned short int sa_family_t; +#endif + +#ifndef HAVE_STRUCT_SOCKADDR_STORAGE +#define HAVE_STRUCT_SOCKADDR_STORAGE +#ifdef HAVE_STRUCT_SOCKADDR_IN6 +#define sockaddr_storage sockaddr_in6 +#define ss_family sin6_family +#define HAVE_SS_FAMILY 1 +#else /*HAVE_STRUCT_SOCKADDR_IN6*/ +#define sockaddr_storage sockaddr_in +#define ss_family sin_family +#define HAVE_SS_FAMILY 1 +#endif /*HAVE_STRUCT_SOCKADDR_IN6*/ +#endif /*HAVE_STRUCT_SOCKADDR_STORAGE*/ + +#ifndef HAVE_SS_FAMILY +#ifdef HAVE___SS_FAMILY +#define ss_family __ss_family +#define HAVE_SS_FAMILY 1 +#endif +#endif + +#ifndef IOV_MAX +# ifdef UIO_MAXIOV +# define IOV_MAX UIO_MAXIOV +# else +# ifdef __sgi + /* + * IRIX 6.5 has sysconf(_SC_IOV_MAX) + * which might return 512 or bigger + */ +# define IOV_MAX 512 +# endif +# ifdef __GNU__ + /* + * GNU/Hurd does not have such hardcoded limitations. Use a reasonable + * amount. + */ +# define IOV_MAX 512 +# endif +# endif +#endif + +#ifndef PIPE_BUF +# ifdef __GNU__ + /* + * GNU/Hurd does not have such hardcoded limitations. But it has to support + * the minimum POSIX value anyway. + */ +# define PIPE_BUF 512 +# endif +#endif + +#ifndef HAVE_STRUCT_ADDRINFO +#define HAVE_STRUCT_ADDRINFO +struct addrinfo { + int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + socklen_t ai_addrlen; + struct sockaddr *ai_addr; + char *ai_canonname; + struct addrinfo *ai_next; +}; +#endif /* HAVE_STRUCT_ADDRINFO */ + +#if !defined(HAVE_GETADDRINFO) +#include "getaddrinfo.h" +#endif + +/* Needed for some systems that don't define it (Solaris). */ +#ifndef ifr_netmask +#define ifr_netmask ifr_addr +#endif + +/* Some old Linux systems have broken header files */ +#ifdef HAVE_IPV6 +#ifdef HAVE_LINUX_IPV6_V6ONLY_26 +#define IPV6_V6ONLY 26 +#endif /* HAVE_LINUX_IPV6_V6ONLY_26 */ +#endif /* HAVE_IPV6 */ + +#ifndef SCOPE_DELIMITER +#define SCOPE_DELIMITER '%' +#endif + +#endif diff --git a/lib/replace/system/passwd.h b/lib/replace/system/passwd.h new file mode 100644 index 0000000..ecc9f60 --- /dev/null +++ b/lib/replace/system/passwd.h @@ -0,0 +1,92 @@ +#ifndef _system_passwd_h +#define _system_passwd_h + +/* + Unix SMB/CIFS implementation. + + passwd system include wrappers + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#ifdef HAVE_PWD_H +#include <pwd.h> +#endif +#ifdef HAVE_GRP_H +#include <grp.h> +#endif +#ifdef HAVE_SYS_PRIV_H +#include <sys/priv.h> +#endif +#ifdef HAVE_SYS_ID_H +#include <sys/id.h> +#endif + +#ifdef HAVE_CRYPT_H +#include <crypt.h> +#endif + +#ifdef HAVE_SHADOW_H +#include <shadow.h> +#endif + +#ifdef HAVE_SYS_SECURITY_H +#include <sys/security.h> +#include <prot.h> +#define PASSWORD_LENGTH 16 +#endif /* HAVE_SYS_SECURITY_H */ + +#ifdef HAVE_GETPWANAM +#include <sys/label.h> +#include <sys/audit.h> +#include <pwdadj.h> +#endif + +#ifdef HAVE_COMPAT_H +#include <compat.h> +#endif + +#ifndef NGROUPS_MAX +#define NGROUPS_MAX 32 /* Guess... */ +#endif + +/* what is the longest significant password available on your system? + Knowing this speeds up password searches a lot */ +#ifndef PASSWORD_LENGTH +#define PASSWORD_LENGTH 8 +#endif + + +#ifndef ALLOW_CHANGE_PASSWORD +#if (defined(HAVE_TERMIOS_H) && defined(HAVE_DUP2) && defined(HAVE_SETSID)) +#define ALLOW_CHANGE_PASSWORD 1 +#endif +#endif + +#if defined(HAVE_CRYPT16) && defined(HAVE_GETAUTHUID) +#define ULTRIX_AUTH 1 +#endif + +#endif diff --git a/lib/replace/system/readline.h b/lib/replace/system/readline.h new file mode 100644 index 0000000..2937962 --- /dev/null +++ b/lib/replace/system/readline.h @@ -0,0 +1,61 @@ +#ifndef _system_readline_h +#define _system_readline_h +/* + Unix SMB/CIFS implementation. + + Readline wrappers + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifdef HAVE_LIBREADLINE +# ifdef HAVE_READLINE_READLINE_H +# ifdef HAVE_READLINE_READLINE_WORKAROUND +# define _FUNCTION_DEF +# endif +# include <readline/readline.h> +# ifdef HAVE_READLINE_HISTORY_H +# include <readline/history.h> +# endif +# else +# ifdef HAVE_READLINE_H +# include <readline.h> +# ifdef HAVE_HISTORY_H +# include <history.h> +# endif +# else +# undef HAVE_LIBREADLINE +# endif +# endif +#endif + +#ifdef HAVE_NEW_LIBREADLINE +#ifdef HAVE_CPPFUNCTION +# define RL_COMPLETION_CAST (CPPFunction *) +#elif defined(HAVE_RL_COMPLETION_T) +# define RL_COMPLETION_CAST (rl_completion_t *) +#else +# define RL_COMPLETION_CAST +#endif +#else +/* This type is missing from libreadline<4.0 (approximately) */ +# define RL_COMPLETION_CAST +#endif /* HAVE_NEW_LIBREADLINE */ + +#endif diff --git a/lib/replace/system/select.h b/lib/replace/system/select.h new file mode 100644 index 0000000..11c5390 --- /dev/null +++ b/lib/replace/system/select.h @@ -0,0 +1,77 @@ +#ifndef _system_select_h +#define _system_select_h +/* + Unix SMB/CIFS implementation. + + select system include wrappers + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> +#endif + +#ifdef HAVE_SYS_EPOLL_H +#include <sys/epoll.h> +#endif + +#ifndef SELECT_CAST +#define SELECT_CAST +#endif + +#ifdef HAVE_POLL + +#include <poll.h> + +#else + +/* Type used for the number of file descriptors. */ +typedef unsigned long int nfds_t; + +/* Data structure describing a polling request. */ +struct pollfd +{ + int fd; /* File descriptor to poll. */ + short int events; /* Types of events poller cares about. */ + short int revents; /* Types of events that actually occurred. */ +}; + +/* Event types that can be polled for. These bits may be set in `events' + to indicate the interesting event types; they will appear in `revents' + to indicate the status of the file descriptor. */ +#define POLLIN 0x001 /* There is data to read. */ +#define POLLPRI 0x002 /* There is urgent data to read. */ +#define POLLOUT 0x004 /* Writing now will not block. */ +#define POLLRDNORM 0x040 /* Normal data may be read. */ +#define POLLRDBAND 0x080 /* Priority data may be read. */ +#define POLLWRNORM 0x100 /* Writing now will not block. */ +#define POLLWRBAND 0x200 /* Priority data may be written. */ +#define POLLERR 0x008 /* Error condition. */ +#define POLLHUP 0x010 /* Hung up. */ +#define POLLNVAL 0x020 /* Invalid polling request. */ + +/* define is in "replace.h" */ +int rep_poll(struct pollfd *fds, nfds_t nfds, int timeout); + +#endif + +#endif diff --git a/lib/replace/system/shmem.h b/lib/replace/system/shmem.h new file mode 100644 index 0000000..64fe39b --- /dev/null +++ b/lib/replace/system/shmem.h @@ -0,0 +1,59 @@ +#ifndef _system_shmem_h +#define _system_shmem_h +/* + Unix SMB/CIFS implementation. + + shared memory system include wrappers + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. + +*/ + +#if defined(HAVE_SYS_IPC_H) +#include <sys/ipc.h> +#endif /* HAVE_SYS_IPC_H */ + +#if defined(HAVE_SYS_SHM_H) +#include <sys/shm.h> +#endif /* HAVE_SYS_SHM_H */ + +#ifdef HAVE_SYS_MMAN_H +#include <sys/mman.h> +#endif + +/* NetBSD doesn't have these */ +#ifndef SHM_R +#define SHM_R 0400 +#endif + +#ifndef SHM_W +#define SHM_W 0200 +#endif + + +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif + +#ifndef MAP_FAILED +#define MAP_FAILED ((void *)-1) +#endif + +#endif diff --git a/lib/replace/system/syslog.h b/lib/replace/system/syslog.h new file mode 100644 index 0000000..104be1d --- /dev/null +++ b/lib/replace/system/syslog.h @@ -0,0 +1,70 @@ +#ifndef _system_syslog_h +#define _system_syslog_h +/* + Unix SMB/CIFS implementation. + + syslog system include wrappers + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifdef HAVE_SYSLOG_H +#include <syslog.h> +#else +#ifdef HAVE_SYS_SYSLOG_H +#include <sys/syslog.h> +#endif +#endif + +/* For sys_adminlog(). */ +#ifndef LOG_EMERG +#define LOG_EMERG 0 /* system is unusable */ +#endif + +#ifndef LOG_ALERT +#define LOG_ALERT 1 /* action must be taken immediately */ +#endif + +#ifndef LOG_CRIT +#define LOG_CRIT 2 /* critical conditions */ +#endif + +#ifndef LOG_ERR +#define LOG_ERR 3 /* error conditions */ +#endif + +#ifndef LOG_WARNING +#define LOG_WARNING 4 /* warning conditions */ +#endif + +#ifndef LOG_NOTICE +#define LOG_NOTICE 5 /* normal but significant condition */ +#endif + +#ifndef LOG_INFO +#define LOG_INFO 6 /* informational */ +#endif + +#ifndef LOG_DEBUG +#define LOG_DEBUG 7 /* debug-level messages */ +#endif + +#endif diff --git a/lib/replace/system/terminal.h b/lib/replace/system/terminal.h new file mode 100644 index 0000000..9ad601a --- /dev/null +++ b/lib/replace/system/terminal.h @@ -0,0 +1,46 @@ +#ifndef _system_terminal_h +#define _system_terminal_h +/* + Unix SMB/CIFS implementation. + + terminal system include wrappers + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifdef SUNOS4 +/* on SUNOS4 termios.h conflicts with sys/ioctl.h */ +#undef HAVE_TERMIOS_H +#endif + + +#if defined(HAVE_TERMIOS_H) +/* POSIX terminal handling. */ +#include <termios.h> +#elif defined(HAVE_TERMIO_H) +/* Older SYSV terminal handling - don't use if we can avoid it. */ +#include <termio.h> +#elif defined(HAVE_SYS_TERMIO_H) +/* Older SYSV terminal handling - don't use if we can avoid it. */ +#include <sys/termio.h> +#endif + +#endif diff --git a/lib/replace/system/threads.h b/lib/replace/system/threads.h new file mode 100644 index 0000000..d189ed6 --- /dev/null +++ b/lib/replace/system/threads.h @@ -0,0 +1,72 @@ +#ifndef _system_threads_h +#define _system_threads_h +/* + Unix SMB/CIFS implementation. + + macros to go along with the lib/replace/ portability layer code + + Copyright (C) Volker Lendecke 2012 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include <pthread.h> + +#if defined(HAVE_PTHREAD_MUTEXATTR_SETROBUST_NP) && \ + !defined(HAVE_PTHREAD_MUTEXATTR_SETROBUST) +#define pthread_mutexattr_setrobust pthread_mutexattr_setrobust_np +#endif + +#if defined(HAVE_DECL_PTHREAD_MUTEX_ROBUST_NP) && \ + !defined(HAVE_DECL_PTHREAD_MUTEX_ROBUST) +#define PTHREAD_MUTEX_ROBUST PTHREAD_MUTEX_ROBUST_NP +#endif + +#if defined(HAVE_PTHREAD_MUTEX_CONSISTENT_NP) && \ + !defined(HAVE_PTHREAD_MUTEX_CONSISTENT) +#define pthread_mutex_consistent pthread_mutex_consistent_np +#endif + +#ifdef HAVE_STDATOMIC_H +#include <stdatomic.h> +#endif + +#ifndef HAVE_ATOMIC_THREAD_FENCE +#ifdef HAVE___ATOMIC_THREAD_FENCE +#define atomic_thread_fence(__ignore_order) __atomic_thread_fence(__ATOMIC_SEQ_CST) +#define HAVE_ATOMIC_THREAD_FENCE 1 +#endif /* HAVE___ATOMIC_THREAD_FENCE */ +#endif /* not HAVE_ATOMIC_THREAD_FENCE */ + +#ifndef HAVE_ATOMIC_THREAD_FENCE +#ifdef HAVE___SYNC_SYNCHRONIZE +#define atomic_thread_fence(__ignore_order) __sync_synchronize() +#define HAVE_ATOMIC_THREAD_FENCE 1 +#endif /* HAVE___SYNC_SYNCHRONIZE */ +#endif /* not HAVE_ATOMIC_THREAD_FENCE */ + +#ifndef HAVE_ATOMIC_THREAD_FENCE +#ifdef HAVE_ATOMIC_THREAD_FENCE_SUPPORT +#error mismatch_error_between_configure_test_and_header +#endif +/* make sure the build fails if someone uses it without checking the define */ +#define atomic_thread_fence(__order) \ + __function__atomic_thread_fence_not_available_on_this_platform__() +#endif /* not HAVE_ATOMIC_THREAD_FENCE */ + +#endif diff --git a/lib/replace/system/time.h b/lib/replace/system/time.h new file mode 100644 index 0000000..272fe84 --- /dev/null +++ b/lib/replace/system/time.h @@ -0,0 +1,106 @@ +#ifndef _system_time_h +#define _system_time_h +/* + Unix SMB/CIFS implementation. + + time system include wrappers + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifdef TIME_WITH_SYS_TIME +#include <sys/time.h> +#include <time.h> +#else +#ifdef HAVE_SYS_TIME_H +#include <sys/time.h> +#else +#include <time.h> +#endif +#endif + +#ifdef HAVE_UTIME_H +#include <utime.h> +#else +struct utimbuf { + time_t actime; /* access time */ + time_t modtime; /* modification time */ +}; +#endif + +#ifndef HAVE_STRUCT_TIMESPEC +struct timespec { + time_t tv_sec; /* Seconds. */ + long tv_nsec; /* Nanoseconds. */ +}; +#endif + +#ifndef HAVE_MKTIME +/* define is in "replace.h" */ +time_t rep_mktime(struct tm *t); +#endif + +#ifndef HAVE_TIMEGM +/* define is in "replace.h" */ +time_t rep_timegm(struct tm *tm); +#endif + +#ifndef HAVE_UTIME +/* define is in "replace.h" */ +int rep_utime(const char *filename, const struct utimbuf *buf); +#endif + +#ifndef HAVE_UTIMES +/* define is in "replace.h" */ +int rep_utimes(const char *filename, const struct timeval tv[2]); +#endif + +#ifndef HAVE_CLOCK_GETTIME +/* CLOCK_REALTIME is required by POSIX */ +#define CLOCK_REALTIME 0 +typedef int clockid_t; +int rep_clock_gettime(clockid_t clk_id, struct timespec *tp); +#endif +/* make sure we have a best effort CUSTOM_CLOCK_MONOTONIC we can rely on. + * + * on AIX the values of CLOCK_* are cast expressions, not integer constants, + * this prevents them from being compared against in a preprocessor directive. + * The following ...IS_* macros can be used to check which clock is in use. + */ +#if defined(CLOCK_MONOTONIC) +#define CUSTOM_CLOCK_MONOTONIC CLOCK_MONOTONIC +#define CUSTOM_CLOCK_MONOTONIC_IS_MONOTONIC +#elif defined(CLOCK_HIGHRES) +#define CUSTOM_CLOCK_MONOTONIC CLOCK_HIGHRES +#define CUSTOM_CLOCK_MONOTONIC_IS_HIGHRES +#else +#define CUSTOM_CLOCK_MONOTONIC CLOCK_REALTIME +#define CUSTOM_CLOCK_MONOTONIC_IS_REALTIME +#endif + +#ifndef UTIME_NOW +#define UTIME_NOW ((1l << 30) - 1l) +#endif +#ifndef UTIME_OMIT +#define UTIME_OMIT ((1l << 30) - 2l) +#endif + +#endif diff --git a/lib/replace/system/wait.h b/lib/replace/system/wait.h new file mode 100644 index 0000000..1f5fcd9 --- /dev/null +++ b/lib/replace/system/wait.h @@ -0,0 +1,55 @@ +#ifndef _system_wait_h +#define _system_wait_h +/* + Unix SMB/CIFS implementation. + + waitpid system include wrappers + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. + +*/ + +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif + +#include <signal.h> + +#ifndef SIGCLD +#define SIGCLD SIGCHLD +#endif + +#ifdef HAVE_SETJMP_H +#include <setjmp.h> +#endif + +#ifdef HAVE_SYS_UCONTEXT_H +#include <sys/ucontext.h> +#endif + +#if !defined(HAVE_SIG_ATOMIC_T_TYPE) +typedef int sig_atomic_t; +#endif + +#if !defined(HAVE_WAITPID) && defined(HAVE_WAIT4) +int rep_waitpid(pid_t pid,int *status,int options); +#endif + +#endif diff --git a/lib/replace/system/wscript_configure b/lib/replace/system/wscript_configure new file mode 100644 index 0000000..ecd9964 --- /dev/null +++ b/lib/replace/system/wscript_configure @@ -0,0 +1,18 @@ +#!/usr/bin/env python + +# solaris varients of getXXent_r +conf.CHECK_C_PROTOTYPE('getpwent_r', + 'struct passwd *getpwent_r(struct passwd *src, char *buf, int buflen)', + define='SOLARIS_GETPWENT_R', headers='pwd.h') +conf.CHECK_C_PROTOTYPE('getgrent_r', + 'struct group *getgrent_r(struct group *src, char *buf, int buflen)', + define='SOLARIS_GETGRENT_R', headers='grp.h') + +# the irix varients +conf.CHECK_C_PROTOTYPE('getpwent_r', + 'struct passwd *getpwent_r(struct passwd *src, char *buf, size_t buflen)', + define='SOLARIS_GETPWENT_R', headers='pwd.h') +conf.CHECK_C_PROTOTYPE('getgrent_r', + 'struct group *getgrent_r(struct group *src, char *buf, size_t buflen)', + define='SOLARIS_GETGRENT_R', headers='grp.h') + diff --git a/lib/replace/tests/getifaddrs.c b/lib/replace/tests/getifaddrs.c new file mode 100644 index 0000000..8d575af --- /dev/null +++ b/lib/replace/tests/getifaddrs.c @@ -0,0 +1,105 @@ +/* + * Unix SMB/CIFS implementation. + * + * libreplace getifaddrs test + * + * Copyright (C) Michael Adam <obnox@samba.org> 2008 + * + * ** NOTE! The following LGPL license applies to the replace + * ** library. This does NOT imply that all of Samba is released + * ** under the LGPL + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef AUTOCONF_TEST +#include "replace.h" +#include "system/network.h" +#include "replace-test.h" +#endif + +#ifdef HAVE_INET_NTOP +#define rep_inet_ntop inet_ntop +#endif + +static const char *format_sockaddr(struct sockaddr *addr, + char *addrstring, + socklen_t addrlen) +{ + const char *result = NULL; + + if (addr->sa_family == AF_INET) { + result = rep_inet_ntop(AF_INET, + &((struct sockaddr_in *)addr)->sin_addr, + addrstring, + addrlen); +#ifdef HAVE_STRUCT_SOCKADDR_IN6 + } else if (addr->sa_family == AF_INET6) { + result = rep_inet_ntop(AF_INET6, + &((struct sockaddr_in6 *)addr)->sin6_addr, + addrstring, + addrlen); +#endif + } + return result; +} + +int getifaddrs_test(void) +{ + struct ifaddrs *ifs = NULL; + struct ifaddrs *ifs_head = NULL; + int ret; + + ret = getifaddrs(&ifs); + ifs_head = ifs; + if (ret != 0) { + fprintf(stderr, "getifaddrs() failed: %s\n", strerror(errno)); + return 1; + } + + while (ifs) { + printf("%-10s ", ifs->ifa_name); + if (ifs->ifa_addr != NULL) { + char addrstring[INET6_ADDRSTRLEN]; + const char *result; + + result = format_sockaddr(ifs->ifa_addr, + addrstring, + sizeof(addrstring)); + if (result != NULL) { + printf("IP=%s ", addrstring); + } + + if (ifs->ifa_netmask != NULL) { + result = format_sockaddr(ifs->ifa_netmask, + addrstring, + sizeof(addrstring)); + if (result != NULL) { + printf("NETMASK=%s", addrstring); + } + } else { + printf("AF=%d ", ifs->ifa_addr->sa_family); + } + } else { + printf("<no address>"); + } + + printf("\n"); + ifs = ifs->ifa_next; + } + + freeifaddrs(ifs_head); + + return 0; +} diff --git a/lib/replace/tests/incoherent_mmap.c b/lib/replace/tests/incoherent_mmap.c new file mode 100644 index 0000000..ee288fd --- /dev/null +++ b/lib/replace/tests/incoherent_mmap.c @@ -0,0 +1,83 @@ +/* In OpenBSD, if you write to a file, another process doesn't see it + * in its mmap. Returns with exit status 0 if that is the case, 1 if + * it's coherent, and other if there's a problem. */ +#include <err.h> +#include <sys/mman.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> + +#define DATA "coherent.mmap" + +int main(int argc, char *argv[]) +{ + int tochild[2], toparent[2]; + int fd; + volatile unsigned char *map; + unsigned char *page; + const char *fname = argv[1]; + char c = 0; + + if (pipe(tochild) != 0 || pipe(toparent) != 0) + err(2, "Creating pipe"); + + if (!fname) + fname = DATA; + + fd = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0600); + if (fd < 0) + err(2, "opening %s", fname); + unlink(fname); + + switch (fork()) { + case -1: + err(2, "Fork"); + case 0: + close(tochild[1]); + close(toparent[0]); + + /* Wait for parent to create file. */ + if (read(tochild[0], &c, 1) != 1) + err(2, "reading from parent"); + + /* Alter first byte. */ + pwrite(fd, &c, 1, 0); + + if (write(toparent[1], &c, 1) != 1) + err(2, "writing to parent"); + exit(0); + + default: + close(tochild[0]); + close(toparent[1]); + + /* Create a file and mmap it. */ + page = malloc(getpagesize()); + memset(page, 0x42, getpagesize()); + if (write(fd, page, getpagesize()) != getpagesize()) + err(2, "writing first page"); + map = mmap(NULL, getpagesize(), PROT_READ|PROT_WRITE, + MAP_SHARED, fd, 0); + if (map == MAP_FAILED) + err(2, "mapping file"); + + if (*map != 0x42) + errx(2, "first byte isn't 0x42!"); + + /* Tell child to alter file. */ + if (write(tochild[1], &c, 1) != 1) + err(2, "writing to child"); + + if (read(toparent[0], &c, 1) != 1) + err(2, "reading from child"); + + if (*map) + errx(0, "mmap incoherent: first byte isn't 0."); + + exit(1); + } +} diff --git a/lib/replace/tests/main.c b/lib/replace/tests/main.c new file mode 100644 index 0000000..94264d7 --- /dev/null +++ b/lib/replace/tests/main.c @@ -0,0 +1,35 @@ +/* + Unix SMB/CIFS implementation. + + libreplace tests + + Copyright (C) Jelmer Vernooij 2006 + + ** NOTE! The following LGPL license applies to the talloc + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" +#include "replace-testsuite.h" + +int main(void) +{ + bool ret = torture_local_replace(NULL); + if (ret) + return 0; + return -1; +} diff --git a/lib/replace/tests/os2_delete.c b/lib/replace/tests/os2_delete.c new file mode 100644 index 0000000..a3e45f7 --- /dev/null +++ b/lib/replace/tests/os2_delete.c @@ -0,0 +1,135 @@ +/* + test readdir/unlink pattern that OS/2 uses + tridge@samba.org July 2005 +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/types.h> +#include <dirent.h> +#include <errno.h> +#include <string.h> +#include <fcntl.h> +#include "replace-test.h" + +#define NUM_FILES 700 +#define READDIR_SIZE 100 +#define DELETE_SIZE 4 + +#define TESTDIR "test.dir" + +static int test_readdir_os2_delete_ret; + +#define FAILED(d) (printf("failure: readdir [\nFailed for %s - %d = %s\n]\n", d, errno, strerror(errno)), test_readdir_os2_delete_ret = 1) + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + +#ifdef _WIN32 +#define mkdir(d,m) _mkdir(d) +#endif + +static void cleanup(void) +{ + /* I'm a lazy bastard */ + if (system("rm -rf " TESTDIR)) { + FAILED("system"); + } + mkdir(TESTDIR, 0700) == 0 || FAILED("mkdir"); +} + +static void create_files(void) +{ + int i; + for (i=0;i<NUM_FILES;i++) { + char fname[40]; + int fd; + snprintf(fname, sizeof(fname), TESTDIR "/test%u.txt", i); + fd = open(fname, O_CREAT|O_RDWR, 0600); + if (fd < 0) { + FAILED("open"); + } + if (close(fd) != 0) { + FAILED("close"); + } + } +} + +static int os2_delete(DIR *d) +{ + off_t offsets[READDIR_SIZE]; + int i, j; + struct dirent *de; + char names[READDIR_SIZE][256]; + + /* scan, remembering offsets */ + for (i=0, de=readdir(d); + de && i < READDIR_SIZE; + de=readdir(d), i++) { + offsets[i] = telldir(d); + /* strlcpy not available here */ + snprintf(names[i], sizeof(names[i]), "%s", de->d_name); + } + + if (i == 0) { + return 0; + } + + /* delete the first few */ + for (j=0; j<MIN(i, DELETE_SIZE); j++) { + char fname[40]; + snprintf(fname, sizeof(fname), TESTDIR "/%s", names[j]); + unlink(fname) == 0 || FAILED("unlink"); + } + + /* seek to just after the deletion */ + seekdir(d, offsets[j-1]); + + /* return number deleted */ + return j; +} + +int test_readdir_os2_delete(void) +{ + int total_deleted = 0; + DIR *d; + struct dirent *de; + + test_readdir_os2_delete_ret = 0; + + cleanup(); + create_files(); + + d = opendir(TESTDIR "/test0.txt"); + if (d != NULL) FAILED("opendir() on file succeed"); + if (errno != ENOTDIR) FAILED("opendir() on file didn't give ENOTDIR"); + if (d != NULL) closedir(d); + + d = opendir(TESTDIR); + + /* skip past . and .. */ + de = readdir(d); + strcmp(de->d_name, ".") == 0 || FAILED("match ."); + de = readdir(d); + strcmp(de->d_name, "..") == 0 || FAILED("match .."); + + while (1) { + int n = os2_delete(d); + if (n == 0) break; + total_deleted += n; + } + closedir(d); + + fprintf(stderr, "Deleted %d files of %d\n", total_deleted, NUM_FILES); + + rmdir(TESTDIR) == 0 || FAILED("rmdir"); + + if (system("rm -rf " TESTDIR) == -1) { + FAILED("system"); + } + + return test_readdir_os2_delete_ret; +} diff --git a/lib/replace/tests/shared_mmap.c b/lib/replace/tests/shared_mmap.c new file mode 100644 index 0000000..9d6e3fc --- /dev/null +++ b/lib/replace/tests/shared_mmap.c @@ -0,0 +1,71 @@ +/* this tests whether we can use a shared writeable mmap on a file - + as needed for the mmap variant of FAST_SHARE_MODES */ + +#if defined(HAVE_UNISTD_H) +#include <unistd.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#define DATA "conftest.mmap" + +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif + +int main(void) +{ + int *buf; + int i; + int fd = open(DATA,O_RDWR|O_CREAT|O_TRUNC,0666); + int count=7; + + if (fd == -1) exit(1); + + for (i=0;i<10000;i++) { + write(fd,&i,sizeof(i)); + } + + close(fd); + + if (fork() == 0) { + fd = open(DATA,O_RDWR); + if (fd == -1) exit(1); + + buf = (int *)mmap(NULL, 10000*sizeof(int), + (PROT_READ | PROT_WRITE), + MAP_FILE | MAP_SHARED, + fd, 0); + + while (count-- && buf[9124] != 55732) sleep(1); + + if (count <= 0) exit(1); + + buf[1763] = 7268; + exit(0); + } + + fd = open(DATA,O_RDWR); + if (fd == -1) exit(1); + + buf = (int *)mmap(NULL, 10000*sizeof(int), + (PROT_READ | PROT_WRITE), + MAP_FILE | MAP_SHARED, + fd, 0); + + if (buf == (int *)-1) exit(1); + + buf[9124] = 55732; + + while (count-- && buf[1763] != 7268) sleep(1); + + unlink(DATA); + + if (count > 0) exit(0); + exit(1); +} diff --git a/lib/replace/tests/shared_mremap.c b/lib/replace/tests/shared_mremap.c new file mode 100644 index 0000000..08040e2 --- /dev/null +++ b/lib/replace/tests/shared_mremap.c @@ -0,0 +1,51 @@ +/* this tests whether we can use mremap */ + +#if defined(HAVE_UNISTD_H) +#include <unistd.h> +#endif +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#define DATA "conftest.mmap" + +#ifndef MAP_FILE +#define MAP_FILE 0 +#endif + +#ifndef MAP_FAILED +#define MAP_FAILED (int *)-1 +#endif + +int main(void) +{ + int *buf; + int fd; + int err = 1; + + fd = open(DATA, O_RDWR|O_CREAT|O_TRUNC, 0666); + if (fd == -1) { + exit(1); + } + + buf = (int *)mmap(NULL, 0x1000, PROT_READ | PROT_WRITE, + MAP_FILE | MAP_SHARED, fd, 0); + if (buf == MAP_FAILED) { + goto done; + } + + buf = mremap(buf, 0x1000, 0x2000, MREMAP_MAYMOVE); + if (buf == MAP_FAILED) { + goto done; + } + + err = 0; +done: + close(fd); + unlink(DATA); + exit(err); +} diff --git a/lib/replace/tests/snprintf.c b/lib/replace/tests/snprintf.c new file mode 100644 index 0000000..77473f0 --- /dev/null +++ b/lib/replace/tests/snprintf.c @@ -0,0 +1,29 @@ +void foo(const char *format, ...) +{ + va_list ap; + int len; + char buf[20]; + long long l = 1234567890; + l *= 100; + + va_start(ap, format); + len = vsnprintf(buf, 0, format, ap); + va_end(ap); + if (len != 5) exit(1); + + va_start(ap, format); + len = vsnprintf(0, 0, format, ap); + va_end(ap); + if (len != 5) exit(2); + + if (snprintf(buf, 3, "hello") != 5 || strcmp(buf, "he") != 0) exit(3); + + if (snprintf(buf, 20, "%lld", l) != 12 || strcmp(buf, "123456789000") != 0) exit(4); + if (snprintf(buf, 20, "%zu", 123456789) != 9 || strcmp(buf, "123456789") != 0) exit(5); + if (snprintf(buf, 20, "%2\$d %1\$d", 3, 4) != 3 || strcmp(buf, "4 3") != 0) exit(6); + if (snprintf(buf, 20, "%s", 0) < 3) exit(7); + + printf("1"); + exit(0); +} +int main(void) { foo("hello"); } diff --git a/lib/replace/tests/strptime.c b/lib/replace/tests/strptime.c new file mode 100644 index 0000000..5bf03f5 --- /dev/null +++ b/lib/replace/tests/strptime.c @@ -0,0 +1,173 @@ + +#ifdef LIBREPLACE_CONFIGURE_TEST_STRPTIME + +#include <stdio.h> +#include <stdlib.h> +#include <time.h> + +#define true 1 +#define false 0 + +#ifndef __STRING +#define __STRING(x) #x +#endif + +/* make printf a no-op */ +#define printf if(0) printf + +#else /* LIBREPLACE_CONFIGURE_TEST_STRPTIME */ + +#include "replace.h" +#include "system/time.h" +#include "replace-test.h" + +#endif /* LIBREPLACE_CONFIGURE_TEST_STRPTIME */ + +int libreplace_test_strptime(void) +{ + const char *s = "20070414101546Z"; + char *ret; + struct tm t, t2; + + memset(&t, 0, sizeof(t)); + memset(&t2, 0, sizeof(t2)); + + printf("test: strptime\n"); + + ret = strptime(s, "%Y%m%d%H%M%S", &t); + if ( ret == NULL ) { + printf("failure: strptime [\n" + "returned NULL\n" + "]\n"); + return false; + } + + if ( *ret != 'Z' ) { + printf("failure: strptime [\n" + "ret doesn't point to 'Z'\n" + "]\n"); + return false; + } + + ret = strptime(s, "%Y%m%d%H%M%SZ", &t2); + if ( ret == NULL ) { + printf("failure: strptime [\n" + "returned NULL with Z\n" + "]\n"); + return false; + } + + if ( *ret != '\0' ) { + printf("failure: strptime [\n" + "ret doesn't point to '\\0'\n" + "]\n"); + return false; + } + +#define CMP_TM_ELEMENT(t1,t2,elem) \ + if (t1.elem != t2.elem) { \ + printf("failure: strptime [\n" \ + "result differs if the format string has a 'Z' at the end\n" \ + "element: %s %d != %d\n" \ + "]\n", \ + __STRING(elen), t1.elem, t2.elem); \ + return false; \ + } + + CMP_TM_ELEMENT(t,t2,tm_sec); + CMP_TM_ELEMENT(t,t2,tm_min); + CMP_TM_ELEMENT(t,t2,tm_hour); + CMP_TM_ELEMENT(t,t2,tm_mday); + CMP_TM_ELEMENT(t,t2,tm_mon); + CMP_TM_ELEMENT(t,t2,tm_year); + CMP_TM_ELEMENT(t,t2,tm_wday); + CMP_TM_ELEMENT(t,t2,tm_yday); + CMP_TM_ELEMENT(t,t2,tm_isdst); + + if (t.tm_sec != 46) { + printf("failure: strptime [\n" + "tm_sec: expected: 46, got: %d\n" + "]\n", + t.tm_sec); + return false; + } + + if (t.tm_min != 15) { + printf("failure: strptime [\n" + "tm_min: expected: 15, got: %d\n" + "]\n", + t.tm_min); + return false; + } + + if (t.tm_hour != 10) { + printf("failure: strptime [\n" + "tm_hour: expected: 10, got: %d\n" + "]\n", + t.tm_hour); + return false; + } + + if (t.tm_mday != 14) { + printf("failure: strptime [\n" + "tm_mday: expected: 14, got: %d\n" + "]\n", + t.tm_mday); + return false; + } + + if (t.tm_mon != 3) { + printf("failure: strptime [\n" + "tm_mon: expected: 3, got: %d\n" + "]\n", + t.tm_mon); + return false; + } + + if (t.tm_year != 107) { + printf("failure: strptime [\n" + "tm_year: expected: 107, got: %d\n" + "]\n", + t.tm_year); + return false; + } + + if (t.tm_wday != 6) { /* saturday */ + printf("failure: strptime [\n" + "tm_wday: expected: 6, got: %d\n" + "]\n", + t.tm_wday); + return false; + } + + if (t.tm_yday != 103) { + printf("failure: strptime [\n" + "tm_yday: expected: 103, got: %d\n" + "]\n", + t.tm_yday); + return false; + } + + /* we don't test this as it depends on the host configuration + if (t.tm_isdst != 0) { + printf("failure: strptime [\n" + "tm_isdst: expected: 0, got: %d\n" + "]\n", + t.tm_isdst); + return false; + }*/ + + printf("success: strptime\n"); + + return true; +} + +#ifdef LIBREPLACE_CONFIGURE_TEST_STRPTIME +int main (void) +{ + int ret; + ret = libreplace_test_strptime(); + if (ret == false) return 1; + return 0; +} +#endif diff --git a/lib/replace/tests/testsuite.c b/lib/replace/tests/testsuite.c new file mode 100644 index 0000000..c0dcda5 --- /dev/null +++ b/lib/replace/tests/testsuite.c @@ -0,0 +1,1227 @@ +/* + Unix SMB/CIFS implementation. + + libreplace tests + + Copyright (C) Jelmer Vernooij 2006 + + ** NOTE! The following LGPL license applies to the talloc + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" +#include "replace-test.h" +#include "replace-testsuite.h" + +/* + we include all the system/ include files here so that libreplace tests + them in the build farm +*/ +#include "system/capability.h" +#include "system/dir.h" +#include "system/filesys.h" +#include "system/glob.h" +#include "system/iconv.h" +#include "system/locale.h" +#include "system/network.h" +#include "system/passwd.h" +#include "system/readline.h" +#include "system/select.h" +#include "system/shmem.h" +#include "system/syslog.h" +#include "system/terminal.h" +#include "system/time.h" +#include "system/wait.h" + +#define TESTFILE "testfile.dat" + + +/* + test ftruncate() function + */ +static int test_ftruncate(void) +{ + struct stat st; + int fd; + const int size = 1234; + printf("test: ftruncate\n"); + unlink(TESTFILE); + fd = open(TESTFILE, O_RDWR|O_CREAT, 0600); + if (fd == -1) { + printf("failure: ftruncate [\n" + "creating '%s' failed - %s\n]\n", TESTFILE, strerror(errno)); + return false; + } + if (ftruncate(fd, size) != 0) { + printf("failure: ftruncate [\n%s\n]\n", strerror(errno)); + close(fd); + return false; + } + if (fstat(fd, &st) != 0) { + printf("failure: ftruncate [\nfstat failed - %s\n]\n", strerror(errno)); + close(fd); + return false; + } + if (st.st_size != size) { + printf("failure: ftruncate [\ngave wrong size %d - expected %d\n]\n", + (int)st.st_size, size); + close(fd); + return false; + } + unlink(TESTFILE); + printf("success: ftruncate\n"); + close(fd); + return true; +} + +/* + test strlcpy() function. + see http://www.gratisoft.us/todd/papers/strlcpy.html + */ +static int test_strlcpy(void) +{ + char buf[4]; + const struct { + const char *src; + size_t result; + } tests[] = { + { "abc", 3 }, + { "abcdef", 6 }, + { "abcd", 4 }, + { "", 0 }, + { NULL, 0 } + }; + int i; + printf("test: strlcpy\n"); + for (i=0;tests[i].src;i++) { + if (strlcpy(buf, tests[i].src, sizeof(buf)) != tests[i].result) { + printf("failure: strlcpy [\ntest %d failed\n]\n", i); + return false; + } + } + printf("success: strlcpy\n"); + return true; +} + +static int test_strlcat(void) +{ + char tmp[10]; + printf("test: strlcat\n"); + strlcpy(tmp, "", sizeof(tmp)); + if (strlcat(tmp, "bla", 3) != 3) { + printf("failure: strlcat [\ninvalid return code\n]\n"); + return false; + } + if (strcmp(tmp, "bl") != 0) { + printf("failure: strlcat [\nexpected \"bl\", got \"%s\"\n]\n", + tmp); + return false; + } + + strlcpy(tmp, "da", sizeof(tmp)); + if (strlcat(tmp, "me", 4) != 4) { + printf("failure: strlcat [\nexpected \"dam\", got \"%s\"\n]\n", + tmp); + return false; + } + + printf("success: strlcat\n"); + return true; +} + +static int test_mktime(void) +{ + /* FIXME */ + return true; +} + +static int test_initgroups(void) +{ + /* FIXME */ + return true; +} + +static int test_memmove(void) +{ + /* FIXME */ + return true; +} + +static int test_strdup(void) +{ + char *x; + int cmp; + + printf("test: strdup\n"); + x = strdup("bla"); + + cmp = strcmp("bla", x); + if (cmp != 0) { + printf("failure: strdup [\nfailed: expected \"bla\", got \"%s\"\n]\n", + x); + free(x); + return false; + } + free(x); + printf("success: strdup\n"); + return true; +} + +static int test_setlinebuf(void) +{ + printf("test: setlinebuf\n"); + setlinebuf(stdout); + printf("success: setlinebuf\n"); + return true; +} + +static int test_vsyslog(void) +{ + /* FIXME */ + return true; +} + +static int test_timegm(void) +{ + /* FIXME */ + return true; +} + +static int test_setenv(void) +{ +#define TEST_SETENV(key, value, overwrite, result) do { \ + int _ret; \ + char *_v; \ + _ret = setenv(key, value, overwrite); \ + if (_ret != 0) { \ + printf("failure: setenv [\n" \ + "setenv(%s, %s, %d) failed\n" \ + "]\n", \ + key, value, overwrite); \ + return false; \ + } \ + _v=getenv(key); \ + if (!_v) { \ + printf("failure: setenv [\n" \ + "getenv(%s) returned NULL\n" \ + "]\n", \ + key); \ + return false; \ + } \ + if (strcmp(result, _v) != 0) { \ + printf("failure: setenv [\n" \ + "getenv(%s): '%s' != '%s'\n" \ + "]\n", \ + key, result, _v); \ + return false; \ + } \ +} while(0) + +#define TEST_UNSETENV(key) do { \ + char *_v; \ + unsetenv(key); \ + _v=getenv(key); \ + if (_v) { \ + printf("failure: setenv [\n" \ + "getenv(%s): NULL != '%s'\n" \ + "]\n", \ + SETENVTEST_KEY, _v); \ + return false; \ + } \ +} while (0) + +#define SETENVTEST_KEY "SETENVTESTKEY" +#define SETENVTEST_VAL "SETENVTESTVAL" + + printf("test: setenv\n"); + TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"1", 0, SETENVTEST_VAL"1"); + TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"2", 0, SETENVTEST_VAL"1"); + TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"3", 1, SETENVTEST_VAL"3"); + TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"4", 1, SETENVTEST_VAL"4"); + TEST_UNSETENV(SETENVTEST_KEY); + TEST_UNSETENV(SETENVTEST_KEY); + TEST_SETENV(SETENVTEST_KEY, SETENVTEST_VAL"5", 0, SETENVTEST_VAL"5"); + TEST_UNSETENV(SETENVTEST_KEY); + TEST_UNSETENV(SETENVTEST_KEY); + printf("success: setenv\n"); + return true; +} + +static int test_strndup(void) +{ + char *x; + int cmp; + + printf("test: strndup\n"); + x = strndup("bla", 0); + cmp = strcmp(x, ""); + free(x); + if (cmp != 0) { + printf("failure: strndup [\ninvalid\n]\n"); + return false; + } + + x = strndup("bla", 2); + cmp = strcmp(x, "bl"); + free(x); + if (cmp != 0) { + printf("failure: strndup [\ninvalid\n]\n"); + return false; + } + +#ifdef __GNUC__ +# if __GNUC__ < 11 + /* + * This code will not compile with gcc11 -O3 anymore. + * + * error: ‘strndup’ specified bound 10 exceeds source size 4 [-Werror=stringop-overread] + * x = strndup("bla", 10); + * ^~~~~~~~~~~~~~~~~~ + */ + x = strndup("bla", 10); + cmp = strcmp(x, "bla"); + free(x); + if (cmp != 0) { + printf("failure: strndup [\ninvalid\n]\n"); + return false; + } +# endif +#endif /* __GNUC__ */ + + printf("success: strndup\n"); + return true; +} + +static int test_strnlen(void) +{ + char longlen[20] = { 0 }; + + printf("test: strnlen\n"); + if (strnlen("bla", 2) != 2) { + printf("failure: strnlen [\nunexpected length\n]\n"); + return false; + } + + if (strnlen("some text\n", 0) != 0) { + printf("failure: strnlen [\nunexpected length\n]\n"); + return false; + } + + memcpy(longlen, "some text", 10); + + if (strnlen(longlen, 20) != 9) { + printf("failure: strnlen [\nunexpected length\n]\n"); + return false; + } + + printf("success: strnlen\n"); + return true; +} + +static int test_waitpid(void) +{ + /* FIXME */ + return true; +} + +static int test_seteuid(void) +{ + /* FIXME */ + return true; +} + +static int test_setegid(void) +{ + /* FIXME */ + return true; +} + +static int test_asprintf(void) +{ + char *x = NULL; + + printf("test: asprintf\n"); + if (asprintf(&x, "%d", 9) != 1) { + printf("failure: asprintf [\ngenerate asprintf\n]\n"); + free(x); + return false; + } + if (strcmp(x, "9") != 0) { + printf("failure: asprintf [\ngenerate asprintf\n]\n"); + free(x); + return false; + } + if (asprintf(&x, "dat%s", "a") != 4) { + printf("failure: asprintf [\ngenerate asprintf\n]\n"); + free(x); + return false; + } + if (strcmp(x, "data") != 0) { + printf("failure: asprintf [\ngenerate asprintf\n]\n"); + free(x); + return false; + } + free(x); + printf("success: asprintf\n"); + return true; +} + +static int test_snprintf(void) +{ + char tmp[10]; + printf("test: snprintf\n"); + if (snprintf(tmp, 3, "foo%d", 9) != 4) { + printf("failure: snprintf [\nsnprintf return code failed\n]\n"); + return false; + } + + if (strcmp(tmp, "fo") != 0) { + printf("failure: snprintf [\nsnprintf failed\n]\n"); + return false; + } + + printf("success: snprintf\n"); + return true; +} + +static int test_vasprintf(void) +{ + /* FIXME */ + return true; +} + +static int test_vsnprintf(void) +{ + /* FIXME */ + return true; +} + +static int test_opendir(void) +{ + /* FIXME */ + return true; +} + +static int test_readdir(void) +{ + printf("test: readdir\n"); + if (test_readdir_os2_delete() != 0) { + return false; + } + printf("success: readdir\n"); + return true; +} + +static int test_telldir(void) +{ + /* FIXME */ + return true; +} + +static int test_seekdir(void) +{ + /* FIXME */ + return true; +} + +static int test_dlopen(void) +{ + /* FIXME: test dlopen, dlsym, dlclose, dlerror */ + return true; +} + + +static int test_chroot(void) +{ + /* FIXME: chroot() */ + return true; +} + +static int test_bzero(void) +{ + /* FIXME: bzero */ + return true; +} + +static int test_strerror(void) +{ + /* FIXME */ + return true; +} + +static int test_errno(void) +{ + printf("test: errno\n"); + errno = 3; + if (errno != 3) { + printf("failure: errno [\nerrno failed\n]\n"); + return false; + } + + printf("success: errno\n"); + return true; +} + +static int test_mkdtemp(void) +{ + /* FIXME */ + return true; +} + +static int test_mkstemp(void) +{ + /* FIXME */ + return true; +} + +static int test_pread(void) +{ + /* FIXME */ + return true; +} + +static int test_pwrite(void) +{ + /* FIXME */ + return true; +} + +static int test_inet_ntoa(void) +{ + /* FIXME */ + return true; +} + +#define TEST_STRTO_X(type,fmt,func,str,base,res,diff,rrnoo) do {\ + type _v; \ + char _s[64]; \ + char *_p = NULL;\ + char *_ep = NULL; \ + strlcpy(_s, str, sizeof(_s));\ + if (diff >= 0) { \ + _ep = &_s[diff]; \ + } \ + errno = 0; \ + _v = func(_s, &_p, base); \ + if (errno != rrnoo) { \ + printf("failure: %s [\n" \ + "\t%s\n" \ + "\t%s(\"%s\",%d,%d): " fmt " (=/!)= " fmt "\n" \ + "\terrno: %d != %d\n" \ + "]\n", \ + __STRING(func), __location__, __STRING(func), \ + str, diff, base, res, _v, rrnoo, errno); \ + return false; \ + } else if (_v != res) { \ + printf("failure: %s [\n" \ + "\t%s\n" \ + "\t%s(\"%s\",%d,%d): " fmt " != " fmt "\n" \ + "]\n", \ + __STRING(func), __location__, __STRING(func), \ + str, diff, base, res, _v); \ + return false; \ + } else if (_p != _ep) { \ + printf("failure: %s [\n" \ + "\t%s\n" \ + "\t%s(\"%s\",%d,%d): " fmt " (=/!)= " fmt "\n" \ + "\tptr: %p - %p = %d != %d\n" \ + "]\n", \ + __STRING(func), __location__, __STRING(func), \ + str, diff, base, res, _v, _ep, _p, (int)(diff - (_ep - _p)), diff); \ + return false; \ + } \ +} while (0) + +static int test_strtoll(void) +{ + printf("test: strtoll\n"); + +#define TEST_STRTOLL(str,base,res,diff,errnoo) TEST_STRTO_X(long long int, "%lld", strtoll,str,base,res,diff,errnoo) + + TEST_STRTOLL("15", 10, 15LL, 2, 0); + TEST_STRTOLL(" 15", 10, 15LL, 4, 0); + TEST_STRTOLL("15", 0, 15LL, 2, 0); + TEST_STRTOLL(" 15 ", 0, 15LL, 3, 0); + TEST_STRTOLL("+15", 10, 15LL, 3, 0); + TEST_STRTOLL(" +15", 10, 15LL, 5, 0); + TEST_STRTOLL("+15", 0, 15LL, 3, 0); + TEST_STRTOLL(" +15 ", 0, 15LL, 4, 0); + TEST_STRTOLL("-15", 10, -15LL, 3, 0); + TEST_STRTOLL(" -15", 10, -15LL, 5, 0); + TEST_STRTOLL("-15", 0, -15LL, 3, 0); + TEST_STRTOLL(" -15 ", 0, -15LL, 4, 0); + TEST_STRTOLL("015", 10, 15LL, 3, 0); + TEST_STRTOLL(" 015", 10, 15LL, 5, 0); + TEST_STRTOLL("015", 0, 13LL, 3, 0); + TEST_STRTOLL(" 015", 0, 13LL, 5, 0); + TEST_STRTOLL("0x15", 10, 0LL, 1, 0); + TEST_STRTOLL(" 0x15", 10, 0LL, 3, 0); + TEST_STRTOLL("0x15", 0, 21LL, 4, 0); + TEST_STRTOLL(" 0x15", 0, 21LL, 6, 0); + + TEST_STRTOLL("10", 16, 16LL, 2, 0); + TEST_STRTOLL(" 10 ", 16, 16LL, 4, 0); + TEST_STRTOLL("0x10", 16, 16LL, 4, 0); + TEST_STRTOLL("0x10", 0, 16LL, 4, 0); + TEST_STRTOLL(" 0x10 ", 0, 16LL, 5, 0); + TEST_STRTOLL("+10", 16, 16LL, 3, 0); + TEST_STRTOLL(" +10 ", 16, 16LL, 5, 0); + TEST_STRTOLL("+0x10", 16, 16LL, 5, 0); + TEST_STRTOLL("+0x10", 0, 16LL, 5, 0); + TEST_STRTOLL(" +0x10 ", 0, 16LL, 6, 0); + TEST_STRTOLL("-10", 16, -16LL, 3, 0); + TEST_STRTOLL(" -10 ", 16, -16LL, 5, 0); + TEST_STRTOLL("-0x10", 16, -16LL, 5, 0); + TEST_STRTOLL("-0x10", 0, -16LL, 5, 0); + TEST_STRTOLL(" -0x10 ", 0, -16LL, 6, 0); + TEST_STRTOLL("010", 16, 16LL, 3, 0); + TEST_STRTOLL(" 010 ", 16, 16LL, 5, 0); + TEST_STRTOLL("-010", 16, -16LL, 4, 0); + + TEST_STRTOLL("11", 8, 9LL, 2, 0); + TEST_STRTOLL("011", 8, 9LL, 3, 0); + TEST_STRTOLL("011", 0, 9LL, 3, 0); + TEST_STRTOLL("-11", 8, -9LL, 3, 0); + TEST_STRTOLL("-011", 8, -9LL, 4, 0); + TEST_STRTOLL("-011", 0, -9LL, 4, 0); + + TEST_STRTOLL("011", 8, 9LL, 3, 0); + TEST_STRTOLL("011", 0, 9LL, 3, 0); + TEST_STRTOLL("-11", 8, -9LL, 3, 0); + TEST_STRTOLL("-011", 8, -9LL, 4, 0); + TEST_STRTOLL("-011", 0, -9LL, 4, 0); + + TEST_STRTOLL("Text", 0, 0LL, 0, 0); + + TEST_STRTOLL("9223372036854775807", 10, 9223372036854775807LL, 19, 0); + TEST_STRTOLL("9223372036854775807", 0, 9223372036854775807LL, 19, 0); + TEST_STRTOLL("9223372036854775808", 0, 9223372036854775807LL, 19, ERANGE); + TEST_STRTOLL("9223372036854775808", 10, 9223372036854775807LL, 19, ERANGE); + TEST_STRTOLL("0x7FFFFFFFFFFFFFFF", 0, 9223372036854775807LL, 18, 0); + TEST_STRTOLL("0x7FFFFFFFFFFFFFFF", 16, 9223372036854775807LL, 18, 0); + TEST_STRTOLL("7FFFFFFFFFFFFFFF", 16, 9223372036854775807LL, 16, 0); + TEST_STRTOLL("0x8000000000000000", 0, 9223372036854775807LL, 18, ERANGE); + TEST_STRTOLL("0x8000000000000000", 16, 9223372036854775807LL, 18, ERANGE); + TEST_STRTOLL("80000000000000000", 16, 9223372036854775807LL, 17, ERANGE); + TEST_STRTOLL("0777777777777777777777", 0, 9223372036854775807LL, 22, 0); + TEST_STRTOLL("0777777777777777777777", 8, 9223372036854775807LL, 22, 0); + TEST_STRTOLL("777777777777777777777", 8, 9223372036854775807LL, 21, 0); + TEST_STRTOLL("01000000000000000000000", 0, 9223372036854775807LL, 23, ERANGE); + TEST_STRTOLL("01000000000000000000000", 8, 9223372036854775807LL, 23, ERANGE); + TEST_STRTOLL("1000000000000000000000", 8, 9223372036854775807LL, 22, ERANGE); + + TEST_STRTOLL("-9223372036854775808", 10, -9223372036854775807LL -1, 20, 0); + TEST_STRTOLL("-9223372036854775808", 0, -9223372036854775807LL -1, 20, 0); + TEST_STRTOLL("-9223372036854775809", 0, -9223372036854775807LL -1, 20, ERANGE); + TEST_STRTOLL("-9223372036854775809", 10, -9223372036854775807LL -1, 20, ERANGE); + TEST_STRTOLL("-0x8000000000000000", 0, -9223372036854775807LL -1, 19, 0); + TEST_STRTOLL("-0x8000000000000000", 16, -9223372036854775807LL -1, 19, 0); + TEST_STRTOLL("-8000000000000000", 16, -9223372036854775807LL -1, 17, 0); + TEST_STRTOLL("-0x8000000000000001", 0, -9223372036854775807LL -1, 19, ERANGE); + TEST_STRTOLL("-0x8000000000000001", 16, -9223372036854775807LL -1, 19, ERANGE); + TEST_STRTOLL("-80000000000000001", 16, -9223372036854775807LL -1, 18, ERANGE); + TEST_STRTOLL("-01000000000000000000000",0, -9223372036854775807LL -1, 24, 0); + TEST_STRTOLL("-01000000000000000000000",8, -9223372036854775807LL -1, 24, 0); + TEST_STRTOLL("-1000000000000000000000", 8, -9223372036854775807LL -1, 23, 0); + TEST_STRTOLL("-01000000000000000000001",0, -9223372036854775807LL -1, 24, ERANGE); + TEST_STRTOLL("-01000000000000000000001",8, -9223372036854775807LL -1, 24, ERANGE); + TEST_STRTOLL("-1000000000000000000001", 8, -9223372036854775807LL -1, 23, ERANGE); + + printf("success: strtoll\n"); + return true; +} + +static int test_strtoull(void) +{ + printf("test: strtoull\n"); + +#define TEST_STRTOULL(str,base,res,diff,errnoo) TEST_STRTO_X(long long unsigned int,"%llu",strtoull,str,base,res,diff,errnoo) + + TEST_STRTOULL("15", 10, 15LLU, 2, 0); + TEST_STRTOULL(" 15", 10, 15LLU, 4, 0); + TEST_STRTOULL("15", 0, 15LLU, 2, 0); + TEST_STRTOULL(" 15 ", 0, 15LLU, 3, 0); + TEST_STRTOULL("+15", 10, 15LLU, 3, 0); + TEST_STRTOULL(" +15", 10, 15LLU, 5, 0); + TEST_STRTOULL("+15", 0, 15LLU, 3, 0); + TEST_STRTOULL(" +15 ", 0, 15LLU, 4, 0); + TEST_STRTOULL("-15", 10, 18446744073709551601LLU, 3, 0); + TEST_STRTOULL(" -15", 10, 18446744073709551601LLU, 5, 0); + TEST_STRTOULL("-15", 0, 18446744073709551601LLU, 3, 0); + TEST_STRTOULL(" -15 ", 0, 18446744073709551601LLU, 4, 0); + TEST_STRTOULL("015", 10, 15LLU, 3, 0); + TEST_STRTOULL(" 015", 10, 15LLU, 5, 0); + TEST_STRTOULL("015", 0, 13LLU, 3, 0); + TEST_STRTOULL(" 015", 0, 13LLU, 5, 0); + TEST_STRTOULL("0x15", 10, 0LLU, 1, 0); + TEST_STRTOULL(" 0x15", 10, 0LLU, 3, 0); + TEST_STRTOULL("0x15", 0, 21LLU, 4, 0); + TEST_STRTOULL(" 0x15", 0, 21LLU, 6, 0); + + TEST_STRTOULL("10", 16, 16LLU, 2, 0); + TEST_STRTOULL(" 10 ", 16, 16LLU, 4, 0); + TEST_STRTOULL("0x10", 16, 16LLU, 4, 0); + TEST_STRTOULL("0x10", 0, 16LLU, 4, 0); + TEST_STRTOULL(" 0x10 ", 0, 16LLU, 5, 0); + TEST_STRTOULL("+10", 16, 16LLU, 3, 0); + TEST_STRTOULL(" +10 ", 16, 16LLU, 5, 0); + TEST_STRTOULL("+0x10", 16, 16LLU, 5, 0); + TEST_STRTOULL("+0x10", 0, 16LLU, 5, 0); + TEST_STRTOULL(" +0x10 ", 0, 16LLU, 6, 0); + TEST_STRTOULL("-10", 16, -16LLU, 3, 0); + TEST_STRTOULL(" -10 ", 16, -16LLU, 5, 0); + TEST_STRTOULL("-0x10", 16, -16LLU, 5, 0); + TEST_STRTOULL("-0x10", 0, -16LLU, 5, 0); + TEST_STRTOULL(" -0x10 ", 0, -16LLU, 6, 0); + TEST_STRTOULL("010", 16, 16LLU, 3, 0); + TEST_STRTOULL(" 010 ", 16, 16LLU, 5, 0); + TEST_STRTOULL("-010", 16, -16LLU, 4, 0); + + TEST_STRTOULL("11", 8, 9LLU, 2, 0); + TEST_STRTOULL("011", 8, 9LLU, 3, 0); + TEST_STRTOULL("011", 0, 9LLU, 3, 0); + TEST_STRTOULL("-11", 8, -9LLU, 3, 0); + TEST_STRTOULL("-011", 8, -9LLU, 4, 0); + TEST_STRTOULL("-011", 0, -9LLU, 4, 0); + + TEST_STRTOULL("011", 8, 9LLU, 3, 0); + TEST_STRTOULL("011", 0, 9LLU, 3, 0); + TEST_STRTOULL("-11", 8, -9LLU, 3, 0); + TEST_STRTOULL("-011", 8, -9LLU, 4, 0); + TEST_STRTOULL("-011", 0, -9LLU, 4, 0); + + TEST_STRTOULL("Text", 0, 0LLU, 0, 0); + + TEST_STRTOULL("9223372036854775807", 10, 9223372036854775807LLU, 19, 0); + TEST_STRTOULL("9223372036854775807", 0, 9223372036854775807LLU, 19, 0); + TEST_STRTOULL("9223372036854775808", 0, 9223372036854775808LLU, 19, 0); + TEST_STRTOULL("9223372036854775808", 10, 9223372036854775808LLU, 19, 0); + TEST_STRTOULL("0x7FFFFFFFFFFFFFFF", 0, 9223372036854775807LLU, 18, 0); + TEST_STRTOULL("0x7FFFFFFFFFFFFFFF", 16, 9223372036854775807LLU, 18, 0); + TEST_STRTOULL("7FFFFFFFFFFFFFFF", 16, 9223372036854775807LLU, 16, 0); + TEST_STRTOULL("0x8000000000000000", 0, 9223372036854775808LLU, 18, 0); + TEST_STRTOULL("0x8000000000000000", 16, 9223372036854775808LLU, 18, 0); + TEST_STRTOULL("8000000000000000", 16, 9223372036854775808LLU, 16, 0); + TEST_STRTOULL("0777777777777777777777", 0, 9223372036854775807LLU, 22, 0); + TEST_STRTOULL("0777777777777777777777", 8, 9223372036854775807LLU, 22, 0); + TEST_STRTOULL("777777777777777777777", 8, 9223372036854775807LLU, 21, 0); + TEST_STRTOULL("01000000000000000000000",0, 9223372036854775808LLU, 23, 0); + TEST_STRTOULL("01000000000000000000000",8, 9223372036854775808LLU, 23, 0); + TEST_STRTOULL("1000000000000000000000", 8, 9223372036854775808LLU, 22, 0); + + TEST_STRTOULL("-9223372036854775808", 10, 9223372036854775808LLU, 20, 0); + TEST_STRTOULL("-9223372036854775808", 0, 9223372036854775808LLU, 20, 0); + TEST_STRTOULL("-9223372036854775809", 0, 9223372036854775807LLU, 20, 0); + TEST_STRTOULL("-9223372036854775809", 10, 9223372036854775807LLU, 20, 0); + TEST_STRTOULL("-0x8000000000000000", 0, 9223372036854775808LLU, 19, 0); + TEST_STRTOULL("-0x8000000000000000", 16, 9223372036854775808LLU, 19, 0); + TEST_STRTOULL("-8000000000000000", 16, 9223372036854775808LLU, 17, 0); + TEST_STRTOULL("-0x8000000000000001", 0, 9223372036854775807LLU, 19, 0); + TEST_STRTOULL("-0x8000000000000001", 16, 9223372036854775807LLU, 19, 0); + TEST_STRTOULL("-8000000000000001", 16, 9223372036854775807LLU, 17, 0); + TEST_STRTOULL("-01000000000000000000000",0, 9223372036854775808LLU, 24, 0); + TEST_STRTOULL("-01000000000000000000000",8, 9223372036854775808LLU, 24, 0); + TEST_STRTOULL("-1000000000000000000000",8, 9223372036854775808LLU, 23, 0); + TEST_STRTOULL("-01000000000000000000001",0, 9223372036854775807LLU, 24, 0); + TEST_STRTOULL("-01000000000000000000001",8, 9223372036854775807LLU, 24, 0); + TEST_STRTOULL("-1000000000000000000001",8, 9223372036854775807LLU, 23, 0); + + TEST_STRTOULL("18446744073709551615", 0, 18446744073709551615LLU, 20, 0); + TEST_STRTOULL("18446744073709551615", 10, 18446744073709551615LLU, 20, 0); + TEST_STRTOULL("18446744073709551616", 0, 18446744073709551615LLU, 20, ERANGE); + TEST_STRTOULL("18446744073709551616", 10, 18446744073709551615LLU, 20, ERANGE); + TEST_STRTOULL("0xFFFFFFFFFFFFFFFF", 0, 18446744073709551615LLU, 18, 0); + TEST_STRTOULL("0xFFFFFFFFFFFFFFFF", 16, 18446744073709551615LLU, 18, 0); + TEST_STRTOULL("FFFFFFFFFFFFFFFF", 16, 18446744073709551615LLU, 16, 0); + TEST_STRTOULL("0x10000000000000000", 0, 18446744073709551615LLU, 19, ERANGE); + TEST_STRTOULL("0x10000000000000000", 16, 18446744073709551615LLU, 19, ERANGE); + TEST_STRTOULL("10000000000000000", 16, 18446744073709551615LLU, 17, ERANGE); + TEST_STRTOULL("01777777777777777777777",0, 18446744073709551615LLU, 23, 0); + TEST_STRTOULL("01777777777777777777777",8, 18446744073709551615LLU, 23, 0); + TEST_STRTOULL("1777777777777777777777", 8, 18446744073709551615LLU, 22, 0); + TEST_STRTOULL("02000000000000000000000",0, 18446744073709551615LLU, 23, ERANGE); + TEST_STRTOULL("02000000000000000000000",8, 18446744073709551615LLU, 23, ERANGE); + TEST_STRTOULL("2000000000000000000000", 8, 18446744073709551615LLU, 22, ERANGE); + + TEST_STRTOULL("-18446744073709551615", 0, 1LLU, 21, 0); + TEST_STRTOULL("-18446744073709551615", 10, 1LLU, 21, 0); + TEST_STRTOULL("-18446744073709551616", 0, 18446744073709551615LLU, 21, ERANGE); + TEST_STRTOULL("-18446744073709551616", 10, 18446744073709551615LLU, 21, ERANGE); + TEST_STRTOULL("-0xFFFFFFFFFFFFFFFF", 0, 1LLU, 19, 0); + TEST_STRTOULL("-0xFFFFFFFFFFFFFFFF", 16, 1LLU, 19, 0); + TEST_STRTOULL("-FFFFFFFFFFFFFFFF", 16, 1LLU, 17, 0); + TEST_STRTOULL("-0x10000000000000000", 0, 18446744073709551615LLU, 20, ERANGE); + TEST_STRTOULL("-0x10000000000000000", 16, 18446744073709551615LLU, 20, ERANGE); + TEST_STRTOULL("-10000000000000000", 16, 18446744073709551615LLU, 18, ERANGE); + TEST_STRTOULL("-01777777777777777777777",0, 1LLU, 24, 0); + TEST_STRTOULL("-01777777777777777777777",8, 1LLU, 24, 0); + TEST_STRTOULL("-1777777777777777777777",8, 1LLU, 23, 0); + TEST_STRTOULL("-02000000000000000000000",0, 18446744073709551615LLU, 24, ERANGE); + TEST_STRTOULL("-02000000000000000000000",8, 18446744073709551615LLU, 24, ERANGE); + TEST_STRTOULL("-2000000000000000000000",8, 18446744073709551615LLU, 23, ERANGE); + + printf("success: strtoull\n"); + return true; +} + +/* +FIXME: +Types: +bool +socklen_t +uint{8,16,32,64}_t +int{8,16,32,64}_t +intptr_t + +Constants: +PATH_NAME_MAX +UINT{16,32,64}_MAX +INT32_MAX +*/ + +static int test_va_copy(void) +{ + /* FIXME */ + return true; +} + +static int test_FUNCTION(void) +{ + printf("test: FUNCTION\n"); + if (strcmp(__FUNCTION__, "test_FUNCTION") != 0) { + printf("failure: FUNCTION [\nFUNCTION invalid\n]\n"); + return false; + } + printf("success: FUNCTION\n"); + return true; +} + +static int test_MIN(void) +{ + printf("test: MIN\n"); + if (MIN(20, 1) != 1) { + printf("failure: MIN [\nMIN invalid\n]\n"); + return false; + } + if (MIN(1, 20) != 1) { + printf("failure: MIN [\nMIN invalid\n]\n"); + return false; + } + printf("success: MIN\n"); + return true; +} + +static int test_MAX(void) +{ + printf("test: MAX\n"); + if (MAX(20, 1) != 20) { + printf("failure: MAX [\nMAX invalid\n]\n"); + return false; + } + if (MAX(1, 20) != 20) { + printf("failure: MAX [\nMAX invalid\n]\n"); + return false; + } + printf("success: MAX\n"); + return true; +} + +static int test_socketpair(void) +{ + int sock[2]; + char buf[20]; + + printf("test: socketpair\n"); + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sock) == -1) { + printf("failure: socketpair [\n" + "socketpair() failed\n" + "]\n"); + return false; + } + + if (write(sock[1], "automatisch", 12) == -1) { + printf("failure: socketpair [\n" + "write() failed: %s\n" + "]\n", strerror(errno)); + return false; + } + + if (read(sock[0], buf, 12) == -1) { + printf("failure: socketpair [\n" + "read() failed: %s\n" + "]\n", strerror(errno)); + return false; + } + + if (strcmp(buf, "automatisch") != 0) { + printf("failure: socketpair [\n" + "expected: automatisch, got: %s\n" + "]\n", buf); + return false; + } + + printf("success: socketpair\n"); + + return true; +} + +extern int libreplace_test_strptime(void); + +static int test_strptime(void) +{ + return libreplace_test_strptime(); +} + +extern int getifaddrs_test(void); + +static int test_getifaddrs(void) +{ + + printf("test: getifaddrs\n"); + + if (getifaddrs_test() != 0) { + printf("failure: getifaddrs\n"); + return false; + } + + printf("success: getifaddrs\n"); + return true; +} + +static int test_utime(void) +{ + struct utimbuf u; + struct stat st1, st2, st3; + int fd; + + printf("test: utime\n"); + unlink(TESTFILE); + + fd = open(TESTFILE, O_RDWR|O_CREAT, 0600); + if (fd == -1) { + printf("failure: utime [\n" + "creating '%s' failed - %s\n]\n", + TESTFILE, strerror(errno)); + return false; + } + + if (fstat(fd, &st1) != 0) { + printf("failure: utime [\n" + "fstat (1) failed - %s\n]\n", + strerror(errno)); + close(fd); + return false; + } + + u.actime = st1.st_atime + 300; + u.modtime = st1.st_mtime - 300; + if (utime(TESTFILE, &u) != 0) { + printf("failure: utime [\n" + "utime(&u) failed - %s\n]\n", + strerror(errno)); + close(fd); + return false; + } + + if (fstat(fd, &st2) != 0) { + printf("failure: utime [\n" + "fstat (2) failed - %s\n]\n", + strerror(errno)); + close(fd); + return false; + } + + if (utime(TESTFILE, NULL) != 0) { + printf("failure: utime [\n" + "utime(NULL) failed - %s\n]\n", + strerror(errno)); + close(fd); + return false; + } + + if (fstat(fd, &st3) != 0) { + printf("failure: utime [\n" + "fstat (3) failed - %s\n]\n", + strerror(errno)); + close(fd); + return false; + } + +#define CMP_VAL(a,c,b) do { \ + if (a c b) { \ + printf("failure: utime [\n" \ + "%s: %s(%d) %s %s(%d)\n]\n", \ + __location__, \ + #a, (int)a, #c, #b, (int)b); \ + close(fd); \ + return false; \ + } \ +} while(0) +#define EQUAL_VAL(a,b) CMP_VAL(a,!=,b) +#define GREATER_VAL(a,b) CMP_VAL(a,<=,b) +#define LESSER_VAL(a,b) CMP_VAL(a,>=,b) + + EQUAL_VAL(st2.st_atime, st1.st_atime + 300); + EQUAL_VAL(st2.st_mtime, st1.st_mtime - 300); + LESSER_VAL(st3.st_atime, st2.st_atime); + GREATER_VAL(st3.st_mtime, st2.st_mtime); + +#undef CMP_VAL +#undef EQUAL_VAL +#undef GREATER_VAL +#undef LESSER_VAL + + unlink(TESTFILE); + printf("success: utime\n"); + close(fd); + return true; +} + +static int test_utimes(void) +{ + struct timeval tv[2]; + struct stat st1, st2; + int fd; + + printf("test: utimes\n"); + unlink(TESTFILE); + + fd = open(TESTFILE, O_RDWR|O_CREAT, 0600); + if (fd == -1) { + printf("failure: utimes [\n" + "creating '%s' failed - %s\n]\n", + TESTFILE, strerror(errno)); + return false; + } + + if (fstat(fd, &st1) != 0) { + printf("failure: utimes [\n" + "fstat (1) failed - %s\n]\n", + strerror(errno)); + close(fd); + return false; + } + + ZERO_STRUCT(tv); + tv[0].tv_sec = st1.st_atime + 300; + tv[1].tv_sec = st1.st_mtime - 300; + if (utimes(TESTFILE, tv) != 0) { + printf("failure: utimes [\n" + "utimes(tv) failed - %s\n]\n", + strerror(errno)); + close(fd); + return false; + } + + if (fstat(fd, &st2) != 0) { + printf("failure: utimes [\n" + "fstat (2) failed - %s\n]\n", + strerror(errno)); + close(fd); + return false; + } + +#define EQUAL_VAL(a,b) do { \ + if (a != b) { \ + printf("failure: utimes [\n" \ + "%s: %s(%d) != %s(%d)\n]\n", \ + __location__, \ + #a, (int)a, #b, (int)b); \ + close(fd); \ + return false; \ + } \ +} while(0) + + EQUAL_VAL(st2.st_atime, st1.st_atime + 300); + EQUAL_VAL(st2.st_mtime, st1.st_mtime - 300); + +#undef EQUAL_VAL + + unlink(TESTFILE); + printf("success: utimes\n"); + close(fd); + return true; +} + +static int test_memmem(void) +{ + char *s; + + printf("test: memmem\n"); + + s = (char *)memmem("foo", 3, "fo", 2); + if (strcmp(s, "foo") != 0) { + printf(__location__ ": Failed memmem\n"); + return false; + } + + s = (char *)memmem("foo", 3, "", 0); + /* it is allowable for this to return NULL (as happens on + FreeBSD) */ + if (s && strcmp(s, "foo") != 0) { + printf(__location__ ": Failed memmem\n"); + return false; + } + + s = (char *)memmem("foo", 4, "o", 1); + if (strcmp(s, "oo") != 0) { + printf(__location__ ": Failed memmem\n"); + return false; + } + + s = (char *)memmem("foobarfodx", 11, "fod", 3); + if (strcmp(s, "fodx") != 0) { + printf(__location__ ": Failed memmem\n"); + return false; + } + + printf("success: memmem\n"); + + return true; +} + +static bool test_closefrom(void) +{ + int i, fd; + + for (i=0; i<100; i++) { + fd = dup(0); + if (fd == -1) { + perror("dup failed"); + closefrom(3); + return false; + } + + /* 1000 is just an arbitrarily chosen upper bound */ + + if (fd >= 1000) { + printf("fd=%d\n", fd); + closefrom(3); + return false; + } + } + + closefrom(3); + + for (i=3; i<=fd; i++) { + off_t off; + off = lseek(i, 0, SEEK_CUR); + if ((off != (off_t)-1) || (errno != EBADF)) { + printf("fd %d not closed\n", i); + return false; + } + } + + return true; +} + +static bool test_array_del_element(void) +{ + int a[] = { 1,2,3,4,5 }; + + printf("test: array_del_element\n"); + + ARRAY_DEL_ELEMENT(a, 4, ARRAY_SIZE(a)); + + if ((a[0] != 1) || + (a[1] != 2) || + (a[2] != 3) || + (a[3] != 4) || + (a[4] != 5)) { + return false; + } + + ARRAY_DEL_ELEMENT(a, 0, ARRAY_SIZE(a)); + + if ((a[0] != 2) || + (a[1] != 3) || + (a[2] != 4) || + (a[3] != 5) || + (a[4] != 5)) { + return false; + } + + ARRAY_DEL_ELEMENT(a, 2, ARRAY_SIZE(a)); + + if ((a[0] != 2) || + (a[1] != 3) || + (a[2] != 5) || + (a[3] != 5) || + (a[4] != 5)) { + return false; + } + + printf("success: array_del_element\n"); + + return true; +} + +bool torture_local_replace(struct torture_context *ctx) +{ + bool ret = true; + ret &= test_ftruncate(); + ret &= test_strlcpy(); + ret &= test_strlcat(); + ret &= test_mktime(); + ret &= test_initgroups(); + ret &= test_memmove(); + ret &= test_strdup(); + ret &= test_setlinebuf(); + ret &= test_vsyslog(); + ret &= test_timegm(); + ret &= test_setenv(); + ret &= test_strndup(); + ret &= test_strnlen(); + ret &= test_waitpid(); + ret &= test_seteuid(); + ret &= test_setegid(); + ret &= test_asprintf(); + ret &= test_snprintf(); + ret &= test_vasprintf(); + ret &= test_vsnprintf(); + ret &= test_opendir(); + ret &= test_readdir(); + ret &= test_telldir(); + ret &= test_seekdir(); + ret &= test_dlopen(); + ret &= test_chroot(); + ret &= test_bzero(); + ret &= test_strerror(); + ret &= test_errno(); + ret &= test_mkdtemp(); + ret &= test_mkstemp(); + ret &= test_pread(); + ret &= test_pwrite(); + ret &= test_inet_ntoa(); + ret &= test_strtoll(); + ret &= test_strtoull(); + ret &= test_va_copy(); + ret &= test_FUNCTION(); + ret &= test_MIN(); + ret &= test_MAX(); + ret &= test_socketpair(); + ret &= test_strptime(); + ret &= test_getifaddrs(); + ret &= test_utime(); + ret &= test_utimes(); + ret &= test_memmem(); + ret &= test_closefrom(); + ret &= test_array_del_element(); + + return ret; +} diff --git a/lib/replace/timegm.c b/lib/replace/timegm.c new file mode 100644 index 0000000..93263a2 --- /dev/null +++ b/lib/replace/timegm.c @@ -0,0 +1,78 @@ +/* + * Copyright (c) 1997 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* + adapted for Samba4 by Andrew Tridgell +*/ + +#include "replace.h" +#include "system/time.h" + +static int is_leap(unsigned y) +{ + y += 1900; + return (y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0); +} + +time_t rep_timegm(struct tm *tm) +{ + static const unsigned ndays[2][12] ={ + {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, + {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; + time_t res = 0; + unsigned i; + + if (tm->tm_mon > 12 || + tm->tm_mon < 0 || + tm->tm_mday > 31 || + tm->tm_min > 60 || + tm->tm_sec > 60 || + tm->tm_hour > 24) { + /* invalid tm structure */ + return 0; + } + + for (i = 70; i < tm->tm_year; ++i) + res += is_leap(i) ? 366 : 365; + + for (i = 0; i < tm->tm_mon; ++i) + res += ndays[is_leap(tm->tm_year)][i]; + res += tm->tm_mday - 1; + res *= 24; + res += tm->tm_hour; + res *= 60; + res += tm->tm_min; + res *= 60; + res += tm->tm_sec; + return res; +} diff --git a/lib/replace/win32_replace.h b/lib/replace/win32_replace.h new file mode 100644 index 0000000..9901e72 --- /dev/null +++ b/lib/replace/win32_replace.h @@ -0,0 +1,159 @@ +#ifndef _WIN32_REPLACE_H +#define _WIN32_REPLACE_H + +#ifdef HAVE_WINSOCK2_H +#include <winsock2.h> +#endif + +#ifdef HAVE_WS2TCPIP_H +#include <ws2tcpip.h> +#endif + +#ifdef HAVE_WINDOWS_H +#include <windows.h> +#endif + +/* Map BSD Socket errorcodes to the WSA errorcodes (if possible) */ + +#define EAFNOSUPPORT WSAEAFNOSUPPORT +#define ECONNREFUSED WSAECONNREFUSED +#define EINPROGRESS WSAEINPROGRESS +#define EMSGSIZE WSAEMSGSIZE +#define ENOBUFS WSAENOBUFS +#define ENOTSOCK WSAENOTSOCK +#define ENETUNREACH WSAENETUNREACH +#define ENOPROTOOPT WSAENOPROTOOPT +#define ENOTCONN WSAENOTCONN +#define ENOTSUP 134 + +/* We undefine the following constants due to conflicts with the w32api headers + * and the Windows Platform SDK/DDK. + */ + +#undef interface + +#undef ERROR_INVALID_PARAMETER +#undef ERROR_INSUFFICIENT_BUFFER +#undef ERROR_INVALID_DATATYPE + +#undef FILE_GENERIC_READ +#undef FILE_GENERIC_WRITE +#undef FILE_GENERIC_EXECUTE +#undef FILE_ATTRIBUTE_READONLY +#undef FILE_ATTRIBUTE_HIDDEN +#undef FILE_ATTRIBUTE_SYSTEM +#undef FILE_ATTRIBUTE_DIRECTORY +#undef FILE_ATTRIBUTE_ARCHIVE +#undef FILE_ATTRIBUTE_DEVICE +#undef FILE_ATTRIBUTE_NORMAL +#undef FILE_ATTRIBUTE_TEMPORARY +#undef FILE_ATTRIBUTE_REPARSE_POINT +#undef FILE_ATTRIBUTE_COMPRESSED +#undef FILE_ATTRIBUTE_OFFLINE +#undef FILE_ATTRIBUTE_ENCRYPTED +#undef FILE_FLAG_WRITE_THROUGH +#undef FILE_FLAG_NO_BUFFERING +#undef FILE_FLAG_RANDOM_ACCESS +#undef FILE_FLAG_SEQUENTIAL_SCAN +#undef FILE_FLAG_DELETE_ON_CLOSE +#undef FILE_FLAG_BACKUP_SEMANTICS +#undef FILE_FLAG_POSIX_SEMANTICS +#undef FILE_TYPE_DISK +#undef FILE_TYPE_UNKNOWN +#undef FILE_CASE_SENSITIVE_SEARCH +#undef FILE_CASE_PRESERVED_NAMES +#undef FILE_UNICODE_ON_DISK +#undef FILE_PERSISTENT_ACLS +#undef FILE_FILE_COMPRESSION +#undef FILE_VOLUME_QUOTAS +#undef FILE_VOLUME_IS_COMPRESSED +#undef FILE_NOTIFY_CHANGE_FILE_NAME +#undef FILE_NOTIFY_CHANGE_DIR_NAME +#undef FILE_NOTIFY_CHANGE_ATTRIBUTES +#undef FILE_NOTIFY_CHANGE_SIZE +#undef FILE_NOTIFY_CHANGE_LAST_WRITE +#undef FILE_NOTIFY_CHANGE_LAST_ACCESS +#undef FILE_NOTIFY_CHANGE_CREATION +#undef FILE_NOTIFY_CHANGE_EA +#undef FILE_NOTIFY_CHANGE_SECURITY +#undef FILE_NOTIFY_CHANGE_STREAM_NAME +#undef FILE_NOTIFY_CHANGE_STREAM_SIZE +#undef FILE_NOTIFY_CHANGE_STREAM_WRITE +#undef FILE_NOTIFY_CHANGE_NAME + +#undef PRINTER_ATTRIBUTE_QUEUED +#undef PRINTER_ATTRIBUTE_DIRECT +#undef PRINTER_ATTRIBUTE_DEFAULT +#undef PRINTER_ATTRIBUTE_SHARED +#undef PRINTER_ATTRIBUTE_NETWORK +#undef PRINTER_ATTRIBUTE_HIDDEN +#undef PRINTER_ATTRIBUTE_LOCAL +#undef PRINTER_ATTRIBUTE_ENABLE_DEVQ +#undef PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS +#undef PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST +#undef PRINTER_ATTRIBUTE_WORK_OFFLINE +#undef PRINTER_ATTRIBUTE_ENABLE_BIDI +#undef PRINTER_ATTRIBUTE_RAW_ONLY +#undef PRINTER_ATTRIBUTE_PUBLISHED +#undef PRINTER_ENUM_DEFAULT +#undef PRINTER_ENUM_LOCAL +#undef PRINTER_ENUM_CONNECTIONS +#undef PRINTER_ENUM_FAVORITE +#undef PRINTER_ENUM_NAME +#undef PRINTER_ENUM_REMOTE +#undef PRINTER_ENUM_SHARED +#undef PRINTER_ENUM_NETWORK +#undef PRINTER_ENUM_EXPAND +#undef PRINTER_ENUM_CONTAINER +#undef PRINTER_ENUM_ICON1 +#undef PRINTER_ENUM_ICON2 +#undef PRINTER_ENUM_ICON3 +#undef PRINTER_ENUM_ICON4 +#undef PRINTER_ENUM_ICON5 +#undef PRINTER_ENUM_ICON6 +#undef PRINTER_ENUM_ICON7 +#undef PRINTER_ENUM_ICON8 +#undef PRINTER_STATUS_PAUSED +#undef PRINTER_STATUS_ERROR +#undef PRINTER_STATUS_PENDING_DELETION +#undef PRINTER_STATUS_PAPER_JAM +#undef PRINTER_STATUS_PAPER_OUT +#undef PRINTER_STATUS_MANUAL_FEED +#undef PRINTER_STATUS_PAPER_PROBLEM +#undef PRINTER_STATUS_OFFLINE +#undef PRINTER_STATUS_IO_ACTIVE +#undef PRINTER_STATUS_BUSY +#undef PRINTER_STATUS_PRINTING +#undef PRINTER_STATUS_OUTPUT_BIN_FULL +#undef PRINTER_STATUS_NOT_AVAILABLE +#undef PRINTER_STATUS_WAITING +#undef PRINTER_STATUS_PROCESSING +#undef PRINTER_STATUS_INITIALIZING +#undef PRINTER_STATUS_WARMING_UP +#undef PRINTER_STATUS_TONER_LOW +#undef PRINTER_STATUS_NO_TONER +#undef PRINTER_STATUS_PAGE_PUNT +#undef PRINTER_STATUS_USER_INTERVENTION +#undef PRINTER_STATUS_OUT_OF_MEMORY +#undef PRINTER_STATUS_DOOR_OPEN +#undef PRINTER_STATUS_SERVER_UNKNOWN +#undef PRINTER_STATUS_POWER_SAVE + +#undef DWORD +#undef HKEY_CLASSES_ROOT +#undef HKEY_CURRENT_USER +#undef HKEY_LOCAL_MACHINE +#undef HKEY_USERS +#undef HKEY_PERFORMANCE_DATA +#undef HKEY_CURRENT_CONFIG +#undef HKEY_DYN_DATA +#undef REG_DWORD +#undef REG_QWORD + +#undef SERVICE_STATE_ALL + +#undef SE_GROUP_MANDATORY +#undef SE_GROUP_ENABLED_BY_DEFAULT +#undef SE_GROUP_ENABLED + +#endif /* _WIN32_REPLACE_H */ diff --git a/lib/replace/wscript b/lib/replace/wscript new file mode 100644 index 0000000..5c2b750 --- /dev/null +++ b/lib/replace/wscript @@ -0,0 +1,992 @@ +#!/usr/bin/env python + +APPNAME = 'libreplace' +VERSION = '1.2.1' + +import sys +import os + +# find the buildtools directory +top = '.' +while not os.path.exists(top+'/buildtools') and len(top.split('/')) < 5: + top = top + '/..' +sys.path.insert(0, top + '/buildtools/wafsamba') + +out = 'bin' + +import wafsamba +from wafsamba import samba_dist +from waflib import Options, Utils, Logs, Context + +samba_dist.DIST_DIRS('lib/replace buildtools:buildtools third_party/waf:third_party/waf') + +def options(opt): + opt.BUILTIN_DEFAULT('NONE') + opt.PRIVATE_EXTENSION_DEFAULT('') + opt.RECURSE('buildtools/wafsamba') + +@Utils.run_once +def configure(conf): + conf.RECURSE('buildtools/wafsamba') + + conf.env.standalone_replace = conf.IN_LAUNCH_DIR() + + if sys.platform.rfind('linux') > -1: + conf.DEFINE('LINUX', '1') + + conf.DEFINE('BOOL_DEFINED', 1) + conf.DEFINE('HAVE_LIBREPLACE', 1) + conf.DEFINE('LIBREPLACE_NETWORK_CHECKS', 1) + + conf.CHECK_HEADERS('linux/types.h crypt.h locale.h acl/libacl.h compat.h') + conf.CHECK_HEADERS('acl/libacl.h attr/xattr.h compat.h ctype.h dustat.h') + conf.CHECK_HEADERS('fcntl.h fnmatch.h glob.h history.h krb5.h langinfo.h') + conf.CHECK_HEADERS('locale.h ndir.h pwd.h') + conf.CHECK_HEADERS('shadow.h sys/acl.h') + conf.CHECK_HEADERS('sys/attributes.h attr/attributes.h sys/capability.h sys/dir.h sys/epoll.h') + conf.CHECK_HEADERS('sys/fcntl.h sys/filio.h sys/filsys.h sys/fs/s5param.h') + conf.CHECK_HEADERS('sys/id.h sys/ioctl.h sys/ipc.h sys/mman.h sys/mode.h sys/ndir.h sys/priv.h') + conf.CHECK_HEADERS('sys/resource.h sys/security.h sys/shm.h sys/statfs.h sys/statvfs.h sys/termio.h') + conf.CHECK_HEADERS('sys/vfs.h sys/xattr.h termio.h termios.h sys/file.h') + conf.CHECK_HEADERS('sys/ucontext.h sys/wait.h sys/stat.h') + + if not conf.CHECK_DECLS('malloc', headers='stdlib.h'): + conf.CHECK_HEADERS('malloc.h') + + conf.CHECK_HEADERS('grp.h') + conf.CHECK_HEADERS('sys/select.h setjmp.h utime.h sys/syslog.h syslog.h') + conf.CHECK_HEADERS('stdarg.h vararg.h sys/mount.h mntent.h') + conf.CHECK_HEADERS('stropts.h unix.h string.h strings.h sys/param.h limits.h') + conf.CHECK_HEADERS('''sys/socket.h netinet/in.h netdb.h arpa/inet.h netinet/in_systm.h + netinet/ip.h netinet/tcp.h netinet/in_ip.h + sys/sockio.h sys/un.h''', together=True) + conf.CHECK_HEADERS('sys/uio.h ifaddrs.h direct.h dirent.h') + conf.CHECK_HEADERS('windows.h winsock2.h ws2tcpip.h') + conf.CHECK_HEADERS('errno.h') + conf.CHECK_HEADERS('getopt.h iconv.h') + conf.CHECK_HEADERS('memory.h nss.h sasl/sasl.h') + conf.CHECK_HEADERS('linux/openat2.h') + + conf.CHECK_FUNCS_IN('inotify_init', 'inotify', checklibc=True, + headers='sys/inotify.h') + + conf.CHECK_HEADERS('security/pam_appl.h zlib.h asm/unistd.h') + conf.CHECK_HEADERS('sys/unistd.h alloca.h float.h') + + conf.SET_TARGET_TYPE('tirpc', 'EMPTY') + + if conf.CHECK_CODE( + '\n#ifndef _TIRPC_RPC_H\n#error "no tirpc headers in system path"\n#endif\n', + 'HAVE_RPC_RPC_HEADERS', + headers=['rpc/rpc.h', 'rpc/nettype.h'], + msg='Checking for tirpc rpc headers in default system path'): + if conf.CONFIG_SET('HAVE_RPC_RPC_H'): + conf.undefine('HAVE_RPC_RPC_H') + + if not conf.CONFIG_SET('HAVE_RPC_RPC_H'): + if conf.CHECK_CFG(package='libtirpc', args='--cflags --libs', + msg='Checking for libtirpc headers', + uselib_store='TIRPC'): + conf.CHECK_HEADERS('rpc/rpc.h rpc/nettype.h', lib='tirpc', together=True) + conf.SET_TARGET_TYPE('tirpc', 'SYSLIB') + if not conf.CONFIG_SET('HAVE_RPC_RPC_H'): + if conf.CHECK_CFG(package='libntirpc', args='--cflags', + msg='Checking for libntirpc headers', + uselib_store='TIRPC'): + conf.CHECK_HEADERS('rpc/rpc.h rpc/nettype.h', lib='tirpc', together=True) + conf.SET_TARGET_TYPE('tirpc', 'SYSLIB') + if not conf.CONFIG_SET('HAVE_RPC_RPC_H'): + Logs.warn('No rpc/rpc.h header found, tirpc or libntirpc missing?') + + # This file is decprecated with glibc >= 2.30 so we need to check if it + # includes a deprecation warning: + # #warning "The <sys/sysctl.h> header is deprecated and will be removed." + conf.CHECK_CODE(''' + #include <sys/sysctl.h> + int main(void) { return 0; } + ''', + define='HAVE_SYS_SYSCTL_H', + cflags=['-Werror=cpp'], + addmain=False, + msg='Checking for header sys/sysctl.h') + + conf.CHECK_HEADERS('sys/fileio.h sys/filesys.h sys/dustat.h sys/sysmacros.h') + conf.CHECK_HEADERS('xfs/libxfs.h netgroup.h') + + conf.CHECK_HEADERS('valgrind.h valgrind/valgrind.h') + conf.CHECK_HEADERS('valgrind/memcheck.h valgrind/helgrind.h') + conf.CHECK_HEADERS('nss_common.h nsswitch.h ns_api.h') + conf.CHECK_HEADERS('sys/extattr.h sys/ea.h sys/proplist.h sys/cdefs.h') + conf.CHECK_HEADERS('utmp.h utmpx.h lastlog.h') + conf.CHECK_HEADERS('syscall.h sys/syscall.h inttypes.h') + conf.CHECK_HEADERS('sys/atomic.h stdatomic.h') + conf.CHECK_HEADERS('libgen.h') + + if conf.CHECK_CFLAGS('-Wno-format-truncation'): + conf.define('HAVE_WNO_FORMAT_TRUNCATION', '1') + + if conf.CHECK_CFLAGS('-Wno-unused-function'): + conf.define('HAVE_WNO_UNUSED_FUNCTION', '1') + + if conf.CHECK_CFLAGS('-Wno-strict-overflow'): + conf.define('HAVE_WNO_STRICT_OVERFLOW', '1') + + if conf.CHECK_CFLAGS('-Wuse-after-free=1'): + conf.define('HAVE_WUSE_AFTER_FREE_1', '1') + + # Check for process set name support + conf.CHECK_CODE(''' + #include <sys/prctl.h> + int main(void) { + prctl(0); + return 0; + } + ''', + 'HAVE_PRCTL', + addmain=False, + headers='sys/prctl.h', + msg='Checking for prctl syscall') + + conf.CHECK_CODE(''' + #include <unistd.h> + #ifdef HAVE_FCNTL_H + #include <fcntl.h> + #endif + int main(void) { int fd = open("/dev/null", O_DIRECT); } + ''', + define='HAVE_OPEN_O_DIRECT', + addmain=False, + msg='Checking for O_DIRECT flag to open(2)') + + conf.CHECK_TYPES('"long long" intptr_t uintptr_t ptrdiff_t comparison_fn_t') + if not conf.CHECK_TYPE('bool', define='HAVE_BOOL', headers='stdbool.h'): + raise Errors.WafError('Samba requires a genuine boolean type') + + conf.CHECK_TYPE('int8_t', 'char') + conf.CHECK_TYPE('uint8_t', 'unsigned char') + conf.CHECK_TYPE('int16_t', 'short') + conf.CHECK_TYPE('uint16_t', 'unsigned short') + conf.CHECK_TYPE('int32_t', 'int') + conf.CHECK_TYPE('uint32_t', 'unsigned') + conf.CHECK_TYPE('int64_t', 'long long') + conf.CHECK_TYPE('uint64_t', 'unsigned long long') + conf.CHECK_TYPE('size_t', 'unsigned int') + conf.CHECK_TYPE('ssize_t', 'int') + conf.CHECK_TYPE('ino_t', 'unsigned') + conf.CHECK_TYPE('loff_t', 'off_t') + conf.CHECK_TYPE('offset_t', 'loff_t') + conf.CHECK_TYPE('volatile int', define='HAVE_VOLATILE') + conf.CHECK_TYPE('uint_t', 'unsigned int') + conf.CHECK_TYPE('blksize_t', 'long', headers='sys/types.h sys/stat.h unistd.h') + conf.CHECK_TYPE('blkcnt_t', 'long', headers='sys/types.h sys/stat.h unistd.h') + + conf.CHECK_SIZEOF('bool char int "long long" long short size_t ssize_t') + conf.CHECK_SIZEOF('int8_t uint8_t int16_t uint16_t int32_t uint32_t int64_t uint64_t') + conf.CHECK_SIZEOF('void*', define='SIZEOF_VOID_P') + conf.CHECK_SIZEOF('off_t dev_t ino_t time_t') + + conf.CHECK_TYPES('socklen_t', headers='sys/socket.h') + conf.CHECK_TYPE_IN('struct ifaddrs', 'ifaddrs.h') + conf.CHECK_TYPE_IN('struct addrinfo', 'netdb.h') + conf.CHECK_TYPE_IN('struct sockaddr', 'sys/socket.h') + conf.CHECK_CODE('struct sockaddr_in6 x', define='HAVE_STRUCT_SOCKADDR_IN6', + headers='sys/socket.h netdb.h netinet/in.h') + conf.CHECK_TYPE_IN('struct sockaddr_storage', 'sys/socket.h') + conf.CHECK_TYPE_IN('sa_family_t', 'sys/socket.h') + + conf.CHECK_TYPE_IN('sig_atomic_t', 'signal.h', define='HAVE_SIG_ATOMIC_T_TYPE') + conf.CHECK_FUNCS('sigsetmask siggetmask sigprocmask sigblock sigaction sigset') + + # Those functions are normally available in libc + if not conf.CHECK_FUNCS(''' + inet_ntoa + inet_aton + inet_ntop + inet_pton + connect + gethostbyname + getaddrinfo + getnameinfo + freeaddrinfo + gai_strerror + socketpair''', + headers='sys/socket.h netinet/in.h arpa/inet.h netdb.h'): + conf.CHECK_FUNCS_IN(''' + inet_ntoa + inet_aton + inet_ntop + inet_pton + connect + gethostbyname + getaddrinfo + getnameinfo + freeaddrinfo + gai_strerror + socketpair''', + 'socket nsl', + headers='sys/socket.h netinet/in.h arpa/inet.h netdb.h') + conf.DEFINE('REPLACE_REQUIRES_LIBSOCKET_LIBNSL', 1) + + conf.CHECK_FUNCS('memset_s memset_explicit') + + conf.CHECK_CODE(''' + #include <string.h> + + int main(void) + { + char buf[] = "This is some content"; + memset(buf, '\0', sizeof(buf)); __asm__ volatile("" : : "g"(&buf) : "memory"); + return 0; + } + ''', + define='HAVE_GCC_VOLATILE_MEMORY_PROTECTION', + addmain=False, + msg='Checking for volatile memory protection', + local_include=False) + + # Some old Linux systems have broken header files and + # miss the IPV6_V6ONLY define in netinet/in.h, + # but have it in linux/in6.h. + # We can't include both files so we just check if the value + # if defined and do the replacement in system/network.h + if not conf.CHECK_VARIABLE('IPV6_V6ONLY', + headers='sys/socket.h netdb.h netinet/in.h'): + conf.CHECK_CODE(''' + #include <linux/in6.h> + #if (IPV6_V6ONLY != 26) + #error no IPV6_V6ONLY support on linux + #endif + int main(void) { return IPV6_V6ONLY; } + ''', + define='HAVE_LINUX_IPV6_V6ONLY_26', + addmain=False, + msg='Checking for IPV6_V6ONLY in linux/in6.h', + local_include=False) + + conf.CHECK_CODE(''' + struct sockaddr_storage sa_store; + struct addrinfo *ai = NULL; + struct in6_addr in6addr; + int idx = if_nametoindex("iface1"); + int s = socket(AF_INET6, SOCK_STREAM, 0); + int ret = getaddrinfo(NULL, NULL, NULL, &ai); + if (ret != 0) { + const char *es = gai_strerror(ret); + } + freeaddrinfo(ai); + { + int val = 1; + #ifdef HAVE_LINUX_IPV6_V6ONLY_26 + #define IPV6_V6ONLY 26 + #endif + ret = setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, + (const void *)&val, sizeof(val)); + } + ''', + define='HAVE_IPV6', + lib='nsl socket', + headers='sys/socket.h netdb.h netinet/in.h net/if.h') + + if conf.CONFIG_SET('HAVE_SYS_UCONTEXT_H') and conf.CONFIG_SET('HAVE_SIGNAL_H'): + conf.CHECK_CODE(''' + ucontext_t uc; + sigaddset(&uc.uc_sigmask, SIGUSR1); + ''', + 'HAVE_UCONTEXT_T', + msg="Checking whether we have ucontext_t", + headers='signal.h sys/ucontext.h') + + # Check for atomic builtins. */ + conf.CHECK_CODE(''' + int i; + (void)__sync_fetch_and_add(&i, 1); + ''', + 'HAVE___SYNC_FETCH_AND_ADD', + msg='Checking for __sync_fetch_and_add compiler builtin') + + conf.CHECK_CODE(''' + int i; + (void)__sync_add_and_fetch(&i, 1); + ''', + 'HAVE___SYNC_ADD_AND_FETCH', + msg='Checking for __sync_add_and_fetch compiler builtin') + + conf.CHECK_CODE(''' + int32_t i; + atomic_add_32(&i, 1); + ''', + 'HAVE_ATOMIC_ADD_32', + headers='stdint.h sys/atomic.h', + msg='Checking for atomic_add_32 compiler builtin') + + conf.CHECK_CODE(''' + uint32_t i,j; + j = __atomic_add_fetch(&i,1,__ATOMIC_SEQ_CST) + ''', + 'HAVE___ATOMIC_ADD_FETCH', + headers='stdint.h', + msg='Checking for __atomic_add_fetch compiler builtin') + + conf.CHECK_CODE(''' + uint32_t i,j; + __atomic_load(&i,&j,__ATOMIC_SEQ_CST) + ''', + 'HAVE___ATOMIC_ADD_LOAD', + headers='stdint.h', + msg='Checking for __atomic_load compiler builtin') + + # Check for thread fence. */ + tf = conf.CHECK_CODE('atomic_thread_fence(memory_order_seq_cst);', + 'HAVE_ATOMIC_THREAD_FENCE', + headers='stdatomic.h', + msg='Checking for atomic_thread_fence(memory_order_seq_cst) in stdatomic.h') + if not tf: + tf = conf.CHECK_CODE('__atomic_thread_fence(__ATOMIC_SEQ_CST);', + 'HAVE___ATOMIC_THREAD_FENCE', + msg='Checking for __atomic_thread_fence(__ATOMIC_SEQ_CST)') + if not tf: + # __sync_synchronize() is available since 2005 in gcc. + tf = conf.CHECK_CODE('__sync_synchronize();', + 'HAVE___SYNC_SYNCHRONIZE', + msg='Checking for __sync_synchronize') + if tf: + conf.DEFINE('HAVE_ATOMIC_THREAD_FENCE_SUPPORT', 1) + + conf.CHECK_CODE(''' + #define FALL_THROUGH __attribute__((fallthrough)) + + enum direction_e { + UP = 0, + DOWN, + }; + + int main(void) { + enum direction_e key = UP; + int i = 10; + int j = 0; + + switch (key) { + case UP: + i = 5; + FALL_THROUGH; + case DOWN: + j = i * 2; + break; + default: + break; + } + + if (j < i) { + return 1; + } + + return 0; + } + ''', + 'HAVE_FALLTHROUGH_ATTRIBUTE', + addmain=False, + strict=True, + cflags=['-Werror=missing-declarations'], + msg='Checking for fallthrough attribute') + + # these may be builtins, so we need the link=False strategy + conf.CHECK_FUNCS('strdup memmem printf memset memcpy memmove strcpy strncpy bzero', link=False) + + # See https://bugzilla.samba.org/show_bug.cgi?id=1097 + # + # Ported in from autoconf where it was added with this commit: + # commit 804cfb20a067b4b687089dc72a8271b3abf20f31 + # Author: Simo Sorce <idra@samba.org> + # Date: Wed Aug 25 14:24:16 2004 +0000 + # r2070: Let's try to overload srnlen and strndup for AIX where they are natly broken. + + host_os = sys.platform + if host_os.rfind('aix') > -1: + conf.DEFINE('BROKEN_STRNLEN', 1) + conf.DEFINE('BROKEN_STRNDUP', 1) + + conf.CHECK_FUNCS('shl_load shl_unload shl_findsym') + conf.CHECK_FUNCS('pipe strftime srandom random srand rand usleep setbuffer') + conf.CHECK_FUNCS('lstat getpgrp utime utimes setuid seteuid setreuid setresuid setgid setegid') + conf.CHECK_FUNCS('setregid setresgid chroot strerror vsyslog setlinebuf mktime') + conf.CHECK_FUNCS('ftruncate chsize rename waitpid wait4') + conf.CHECK_FUNCS('initgroups pread pwrite strndup strcasestr strsep') + conf.CHECK_FUNCS('strtok_r mkdtemp dup2 dprintf vdprintf isatty chown lchown') + conf.CHECK_FUNCS('link readlink symlink realpath snprintf vsnprintf') + conf.CHECK_FUNCS('asprintf vasprintf setenv unsetenv strnlen strtoull __strtoull') + conf.CHECK_FUNCS('strtouq strtoll __strtoll strtoq memalign posix_memalign') + conf.CHECK_FUNCS('fmemopen') + + if conf.CONFIG_SET('HAVE_MEMALIGN'): + conf.CHECK_DECLS('memalign', headers='malloc.h') + + # glibc up to 2.3.6 had dangerously broken posix_fallocate(). DON'T USE IT. + if conf.CHECK_CODE(''' +#define _XOPEN_SOURCE 600 +#include <stdlib.h> +#if defined(__GLIBC__) && ((__GLIBC__ < 2) || (__GLIBC__ == 2 && __GLIBC_MINOR__ < 4)) +#error probably broken posix_fallocate +#endif +''', + '_POSIX_FALLOCATE_CAPABLE_LIBC', + msg='Checking for posix_fallocate-capable libc'): + conf.CHECK_FUNCS('posix_fallocate') + + conf.CHECK_FUNCS('prctl dirname basename') + + strlcpy_in_bsd = False + + # libbsd on some platforms provides strlcpy and strlcat + if not conf.CHECK_FUNCS('strlcpy strlcat'): + if conf.CHECK_FUNCS_IN('strlcpy strlcat', 'bsd', headers='bsd/string.h', + checklibc=True): + strlcpy_in_bsd = True + if not conf.CHECK_FUNCS('getpeereid'): + conf.CHECK_FUNCS_IN('getpeereid', 'bsd', headers='sys/types.h bsd/unistd.h') + if not conf.CHECK_FUNCS_IN('setproctitle', 'setproctitle', headers='setproctitle.h'): + conf.CHECK_FUNCS_IN('setproctitle', 'bsd', headers='sys/types.h bsd/unistd.h') + if not conf.CHECK_FUNCS('setproctitle_init'): + conf.CHECK_FUNCS_IN('setproctitle_init', 'bsd', headers='sys/types.h bsd/unistd.h') + + if not conf.CHECK_FUNCS('closefrom'): + conf.CHECK_FUNCS_IN('closefrom', 'bsd', headers='bsd/unistd.h') + + conf.CHECK_CODE(''' + struct ucred cred; + socklen_t cred_len; + int ret = getsockopt(0, SOL_SOCKET, SO_PEERCRED, &cred, &cred_len);''', + 'HAVE_PEERCRED', + msg="Checking whether we can use SO_PEERCRED to get socket credentials", + headers='sys/types.h sys/socket.h') + + #Some OS (ie. freebsd) return EINVAL if the conversion could not be done, it's not what we expect + #Let's detect those cases + if conf.CONFIG_SET('HAVE_STRTOLL'): + conf.CHECK_CODE(''' + long long nb = strtoll("Text", NULL, 0); + if (errno == EINVAL) { + return 0; + } else { + return 1; + } + ''', + msg="Checking correct behavior of strtoll", + headers = 'errno.h', + execute = True, + define = 'HAVE_BSD_STRTOLL', + ) + conf.CHECK_FUNCS('if_nameindex if_nametoindex strerror_r') + conf.CHECK_FUNCS('syslog') + conf.CHECK_FUNCS('gai_strerror get_current_dir_name') + conf.CHECK_FUNCS('timegm getifaddrs freeifaddrs mmap setgroups syscall setsid') + conf.CHECK_FUNCS('getgrent_r getgrgid_r getgrnam_r getgrouplist getpagesize') + conf.CHECK_FUNCS('getpwent_r getpwnam_r getpwuid_r epoll_create') + conf.CHECK_FUNCS('getprogname') + if not conf.CHECK_FUNCS('copy_file_range'): + conf.CHECK_CODE(''' +syscall(SYS_copy_file_range,0,NULL,0,NULL,0,0); + ''', + 'HAVE_SYSCALL_COPY_FILE_RANGE', + headers='sys/syscall.h unistd.h', + msg='Checking whether we have copy_file_range system call') + + conf.SET_TARGET_TYPE('attr', 'EMPTY') + + xattr_headers='sys/attributes.h attr/xattr.h sys/xattr.h' + + # default to 1, we set it to 0 if we don't find any EA implementation below: + conf.DEFINE('HAVE_XATTR_SUPPORT', 1) + if conf.CHECK_FUNCS_IN('getxattr', 'attr', checklibc=True, headers=xattr_headers): + conf.DEFINE('HAVE_XATTR_XATTR', 1) + # Darwin has extra options to xattr-family functions + conf.CHECK_CODE('getxattr(NULL, NULL, NULL, 0, 0, 0)', + headers=xattr_headers, local_include=False, + define='XATTR_ADDITIONAL_OPTIONS', + msg="Checking whether xattr interface takes additional options") + elif conf.CHECK_FUNCS_IN('attr_listf', 'attr', checklibc=True, headers=xattr_headers): + conf.DEFINE('HAVE_XATTR_ATTR', 1) + elif conf.CHECK_FUNCS('extattr_list_fd'): + conf.DEFINE('HAVE_XATTR_EXTATTR', 1) + elif conf.CHECK_FUNCS('flistea'): + conf.DEFINE('HAVE_XATTR_EA', 1) + elif not conf.CHECK_FUNCS('attropen'): + conf.DEFINE('HAVE_XATTR_SUPPORT', 0) + + + conf.CHECK_FUNCS_IN('dlopen dlsym dlerror dlclose', 'dl', + checklibc=True, headers='dlfcn.h dl.h') + + conf.CHECK_C_PROTOTYPE('dlopen', 'void *dlopen(const char* filename, unsigned int flags)', + define='DLOPEN_TAKES_UNSIGNED_FLAGS', headers='dlfcn.h dl.h') + + # + # Check for clock_gettime and fdatasync + # + # First check libc to avoid linking libreplace against librt. + # + if conf.CHECK_FUNCS('fdatasync'): + # some systems are missing the declaration + conf.CHECK_DECLS('fdatasync') + else: + if conf.CHECK_FUNCS_IN('fdatasync', 'rt'): + # some systems are missing the declaration + conf.CHECK_DECLS('fdatasync') + + has_clock_gettime = False + if conf.CHECK_FUNCS('clock_gettime'): + has_clock_gettime = True + + if not has_clock_gettime: + if conf.CHECK_FUNCS_IN('clock_gettime', 'rt', checklibc=True): + has_clock_gettime = True + + if has_clock_gettime: + for c in ['CLOCK_MONOTONIC', 'CLOCK_PROCESS_CPUTIME_ID', 'CLOCK_REALTIME']: + conf.CHECK_CODE(''' + #if TIME_WITH_SYS_TIME + # include <sys/time.h> + # include <time.h> + #else + # if HAVE_SYS_TIME_H + # include <sys/time.h> + # else + # include <time.h> + # endif + #endif + clockid_t clk = %s''' % c, + 'HAVE_%s' % c, + msg='Checking whether the clock_gettime clock ID %s is available' % c) + + conf.CHECK_TYPE('struct timespec', headers='sys/time.h time.h') + + # these headers need to be tested as a group on freebsd + conf.CHECK_HEADERS(headers='sys/socket.h net/if.h', together=True) + conf.CHECK_HEADERS(headers='netinet/in.h arpa/nameser.h resolv.h', together=True) + conf.CHECK_FUNCS_IN('res_search', 'resolv', checklibc=True, + headers='netinet/in.h arpa/nameser.h resolv.h') + + + # try to find libintl (if --without-gettext is not given) + conf.env.intl_libs='' + if not Options.options.disable_gettext: + conf.CHECK_HEADERS('libintl.h') + conf.CHECK_LIB('intl') + conf.CHECK_DECLS('dgettext gettext bindtextdomain textdomain bind_textdomain_codeset', headers="libintl.h") + # *textdomain functions are not strictly necessary + conf.CHECK_FUNCS_IN('bindtextdomain textdomain bind_textdomain_codeset', + '', checklibc=True, headers='libintl.h') + # gettext and dgettext must exist + # on some systems (the ones with glibc, those are in libc) + if conf.CHECK_FUNCS_IN('dgettext gettext', '', checklibc=True, headers='libintl.h'): + # save for dependency definitions + conf.env.intl_libs='' + # others (e.g. FreeBSD) have separate libintl + elif conf.CHECK_FUNCS_IN('dgettext gettext', 'intl', checklibc=False, headers='libintl.h'): + # save for dependency definitions + conf.env.intl_libs='intl' + # recheck with libintl + conf.CHECK_FUNCS_IN('bindtextdomain textdomain bind_textdomain_codeset', + 'intl', checklibc=False, headers='libintl.h') + else: + # Some hosts need lib iconv for linking with lib intl + # So we try with flags just in case it helps. + oldflags = list(conf.env['EXTRA_LDFLAGS']); + conf.env['EXTRA_LDFLAGS'].extend(["-liconv"]) + conf.CHECK_FUNCS_IN('dgettext gettext bindtextdomain textdomain bind_textdomain_codeset', + 'intl', checklibc=False, headers='libintl.h') + conf.env['EXTRA_LDFLAGS'] = oldflags + if conf.env['HAVE_GETTEXT'] and conf.env['HAVE_DGETTEXT']: + # save for dependency definitions + conf.env.intl_libs='iconv intl' + + # did we find both prototypes and a library to link against? + # if not, unset the detected values (see Bug #9911) + if not (conf.env['HAVE_GETTEXT'] and conf.env['HAVE_DECL_GETTEXT']): + conf.undefine('HAVE_GETTEXT') + conf.undefine('HAVE_DECL_GETTEXT') + if not (conf.env['HAVE_DGETTEXT'] and conf.env['HAVE_DECL_DGETTEXT']): + conf.undefine('HAVE_DGETTEXT') + conf.undefine('HAVE_DECL_DGETTEXT') + + conf.CHECK_FUNCS_IN('pthread_create', 'pthread', checklibc=True, headers='pthread.h') + + PTHREAD_CFLAGS='error' + PTHREAD_LDFLAGS='error' + + if PTHREAD_LDFLAGS == 'error': + # Check if pthread_attr_init() is provided by libc first! + if conf.CHECK_FUNCS('pthread_attr_init'): + PTHREAD_CFLAGS='-D_REENTRANT' + PTHREAD_LDFLAGS='' + if PTHREAD_LDFLAGS == 'error': + if conf.CHECK_FUNCS_IN('pthread_attr_init', 'pthread'): + PTHREAD_CFLAGS='-D_REENTRANT -D_POSIX_PTHREAD_SEMANTICS' + PTHREAD_LDFLAGS='-lpthread' + if PTHREAD_LDFLAGS == 'error': + if conf.CHECK_FUNCS_IN('pthread_attr_init', 'pthreads'): + PTHREAD_CFLAGS='-D_THREAD_SAFE' + PTHREAD_LDFLAGS='-lpthreads' + if PTHREAD_LDFLAGS == 'error': + if conf.CHECK_FUNCS_IN('pthread_attr_init', 'c_r'): + PTHREAD_CFLAGS='-D_THREAD_SAFE -pthread' + PTHREAD_LDFLAGS='-pthread' + + # especially for HP-UX, where the CHECK_FUNC macro fails to test for + # pthread_attr_init. On pthread_mutex_lock it works there... + if PTHREAD_LDFLAGS == 'error': + if conf.CHECK_FUNCS_IN('pthread_mutex_lock', 'pthread'): + PTHREAD_CFLAGS='-D_REENTRANT' + PTHREAD_LDFLAGS='-lpthread' + + if PTHREAD_CFLAGS != 'error' and PTHREAD_LDFLAGS != 'error': + if conf.CONFIG_SET('replace_add_global_pthread'): + conf.ADD_CFLAGS(PTHREAD_CFLAGS) + conf.ADD_LDFLAGS(PTHREAD_LDFLAGS) + conf.CHECK_HEADERS('pthread.h') + conf.DEFINE('HAVE_PTHREAD', '1') + + if conf.CONFIG_SET('HAVE_PTHREAD'): + + conf.CHECK_FUNCS_IN('pthread_mutexattr_setrobust', 'pthread', + checklibc=True, headers='pthread.h') + if not conf.CONFIG_SET('HAVE_PTHREAD_MUTEXATTR_SETROBUST'): + conf.CHECK_FUNCS_IN('pthread_mutexattr_setrobust_np', 'pthread', + checklibc=True, headers='pthread.h') + + conf.CHECK_DECLS('PTHREAD_MUTEX_ROBUST', headers='pthread.h') + if not conf.CONFIG_SET('HAVE_DECL_PTHREAD_MUTEX_ROBUST'): + conf.CHECK_DECLS('PTHREAD_MUTEX_ROBUST_NP', headers='pthread.h') + + conf.CHECK_FUNCS_IN('pthread_mutex_consistent', 'pthread', + checklibc=True, headers='pthread.h') + if not conf.CONFIG_SET('HAVE_PTHREAD_MUTEX_CONSISTENT'): + conf.CHECK_FUNCS_IN('pthread_mutex_consistent_np', 'pthread', + checklibc=True, headers='pthread.h') + + if ((conf.CONFIG_SET('HAVE_PTHREAD_MUTEXATTR_SETROBUST') or + conf.CONFIG_SET('HAVE_PTHREAD_MUTEXATTR_SETROBUST_NP')) and + (conf.CONFIG_SET('HAVE_DECL_PTHREAD_MUTEX_ROBUST') or + conf.CONFIG_SET('HAVE_DECL_PTHREAD_MUTEX_ROBUST_NP')) and + (conf.CONFIG_SET('HAVE_PTHREAD_MUTEX_CONSISTENT') or + conf.CONFIG_SET('HAVE_PTHREAD_MUTEX_CONSISTENT_NP'))): + conf.DEFINE('HAVE_ROBUST_MUTEXES', 1) + + # __thread is available in Solaris Studio, IBM XL, + # gcc, Clang and Intel C Compiler + conf.CHECK_CODE(''' + __thread int tls; + + int main(void) { + return 0; + } + ''', + 'HAVE___THREAD', + addmain=False, + msg='Checking for __thread local storage') + + if conf.CONFIG_SET('HAVE_PTHREAD') and not conf.CONFIG_SET('HAVE___THREAD'): + conf.fatal('Missing required TLS support in pthread library') + + conf.CHECK_FUNCS_IN('crypt', 'crypt', checklibc=True) + conf.CHECK_FUNCS_IN('crypt_r', 'crypt', checklibc=True) + conf.CHECK_FUNCS_IN('crypt_rn', 'crypt', checklibc=True) + + conf.CHECK_VARIABLE('rl_event_hook', define='HAVE_DECL_RL_EVENT_HOOK', always=True, + headers='readline.h readline/readline.h readline/history.h') + conf.CHECK_VARIABLE('program_invocation_short_name', headers='errno.h') + + conf.CHECK_DECLS('snprintf vsnprintf asprintf vasprintf') + + conf.CHECK_DECLS('errno', headers='errno.h', reverse=True) + conf.CHECK_DECLS('EWOULDBLOCK', headers='errno.h') + conf.CHECK_DECLS('environ', reverse=True, headers='unistd.h') + conf.CHECK_DECLS('getgrent_r getpwent_r', reverse=True, headers='pwd.h grp.h') + conf.CHECK_DECLS('pread pwrite setenv setresgid setresuid', reverse=True) + + if conf.CONFIG_SET('HAVE_EPOLL_CREATE') and conf.CONFIG_SET('HAVE_SYS_EPOLL_H'): + conf.DEFINE('HAVE_EPOLL', 1) + + if conf.CHECK_FUNCS('eventfd', headers='sys/eventfd.h'): + conf.DEFINE('HAVE_EVENTFD', 1) + + conf.CHECK_HEADERS('poll.h') + conf.CHECK_FUNCS('poll') + + conf.CHECK_FUNCS('strptime') + conf.CHECK_DECLS('strptime', headers='time.h') + conf.CHECK_CODE('''#define LIBREPLACE_CONFIGURE_TEST_STRPTIME + #include "tests/strptime.c"''', + define='HAVE_WORKING_STRPTIME', + execute=True, + addmain=False, + msg='Checking for working strptime') + + conf.CHECK_C_PROTOTYPE('gettimeofday', + 'int gettimeofday(struct timeval *tv, struct timezone *tz)', + define='HAVE_GETTIMEOFDAY_TZ', headers='sys/time.h') + + conf.CHECK_C_PROTOTYPE('gettimeofday', + 'int gettimeofday(struct timeval *tv, void *tz)', + define='HAVE_GETTIMEOFDAY_TZ_VOID', + headers='sys/time.h') + + conf.CHECK_CODE('#include "tests/snprintf.c"', + define="HAVE_C99_VSNPRINTF", + execute=True, + addmain=False, + msg="Checking for C99 vsnprintf") + + conf.CHECK_CODE('#include "tests/shared_mmap.c"', + addmain=False, add_headers=False, execute=True, + define='HAVE_SHARED_MMAP', + msg="Checking for HAVE_SHARED_MMAP") + + conf.CHECK_CODE('#include "tests/shared_mremap.c"', + addmain=False, add_headers=False, execute=True, + define='HAVE_MREMAP', + msg="Checking for HAVE_MREMAP") + + # OpenBSD (and I've heard HPUX) doesn't sync between mmap and write. + # FIXME: Anything other than a 0 or 1 exit code should abort configure! + conf.CHECK_CODE('#include "tests/incoherent_mmap.c"', + addmain=False, add_headers=False, execute=True, + define='HAVE_INCOHERENT_MMAP', + msg="Checking for HAVE_INCOHERENT_MMAP") + + conf.SAMBA_BUILD_ENV() + + conf.CHECK_CODE(''' + typedef struct {unsigned x;} FOOBAR; + #define X_FOOBAR(x) ((FOOBAR) { x }) + #define FOO_ONE X_FOOBAR(1) + FOOBAR f = FOO_ONE; + static const struct { + FOOBAR y; + } f2[] = { + {FOO_ONE} + }; + static const FOOBAR f3[] = {FOO_ONE}; + ''', + define='HAVE_IMMEDIATE_STRUCTURES') + + conf.CHECK_CODE('mkdir("foo",0777)', define='HAVE_MKDIR_MODE', headers='sys/stat.h') + + # we need the st_rdev test under two names + conf.CHECK_STRUCTURE_MEMBER('struct stat', 'st_rdev', + define='HAVE_STRUCT_STAT_ST_RDEV', + headers='sys/stat.h') + conf.CHECK_STRUCTURE_MEMBER('struct stat', 'st_rdev', define='HAVE_ST_RDEV', + headers='sys/stat.h') + conf.CHECK_STRUCTURE_MEMBER('struct sockaddr_storage', 'ss_family', + headers='sys/socket.h netinet/in.h') + conf.CHECK_STRUCTURE_MEMBER('struct sockaddr_storage', '__ss_family', + headers='sys/socket.h netinet/in.h') + + + if conf.CHECK_STRUCTURE_MEMBER('struct sockaddr', 'sa_len', + headers='sys/socket.h netinet/in.h', + define='HAVE_SOCKADDR_SA_LEN'): + # the old build system produced both defines + conf.DEFINE('HAVE_STRUCT_SOCKADDR_SA_LEN', 1) + + conf.CHECK_STRUCTURE_MEMBER('struct sockaddr_in', 'sin_len', + headers='sys/socket.h netinet/in.h', + define='HAVE_SOCK_SIN_LEN') + + conf.CHECK_STRUCTURE_MEMBER('struct sockaddr_in6', 'sin6_len', + headers='sys/socket.h netinet/in.h', + define='HAVE_SOCK_SIN6_LEN') + + conf.CHECK_CODE('struct sockaddr_un sunaddr; sunaddr.sun_family = AF_UNIX;', + define='HAVE_UNIXSOCKET', headers='sys/socket.h sys/un.h') + + + conf.CHECK_CODE(''' + struct stat st; + char tpl[20]="/tmp/test.XXXXXX"; + char tpl2[20]="/tmp/test.XXXXXX"; + int fd = mkstemp(tpl); + int fd2 = mkstemp(tpl2); + if (fd == -1) { + if (fd2 != -1) { + unlink(tpl2); + } + exit(1); + } + if (fd2 == -1) exit(1); + unlink(tpl); + unlink(tpl2); + if (fstat(fd, &st) != 0) exit(1); + if ((st.st_mode & 0777) != 0600) exit(1); + if (strcmp(tpl, "/tmp/test.XXXXXX") == 0) { + exit(1); + } + if (strcmp(tpl, tpl2) == 0) { + exit(1); + } + exit(0); + ''', + define='HAVE_SECURE_MKSTEMP', + execute=True, + mandatory=True) # lets see if we get a mandatory failure for this one + + # look for a method of finding the list of network interfaces + for method in ['HAVE_IFACE_GETIFADDRS', 'HAVE_IFACE_AIX', 'HAVE_IFACE_IFCONF', 'HAVE_IFACE_IFREQ']: + bsd_for_strlcpy = '' + if strlcpy_in_bsd: + bsd_for_strlcpy = ' bsd' + if conf.CHECK_CODE(''' + #define %s 1 + #define NO_CONFIG_H 1 + #define AUTOCONF_TEST 1 + #include "replace.c" + #include "inet_ntop.c" + #include "snprintf.c" + #include "getifaddrs.c" + #define getifaddrs_test main + #include "tests/getifaddrs.c" + ''' % method, + method, + lib='nsl socket' + bsd_for_strlcpy, + addmain=False, + execute=True): + break + + conf.RECURSE('system') + conf.SAMBA_CONFIG_H() + if conf.CHECK_FUNCS('strerror_r'): + # Check if strerror_r is XSI-Compatable, the default GNU implementation + # is not + conf.CHECK_CODE('int strerror_r(int errnum, char *buf, size_t buflen);', + 'STRERROR_R_XSI_NOT_GNU', + headers='string.h', addmain=False, link=False, + msg="Checking for XSI (rather than GNU) prototype for strerror_r") + + +REPLACEMENT_FUNCTIONS = { + 'replace.c': ['ftruncate', 'strlcpy', 'strlcat', 'mktime', 'initgroups', + 'memmove', 'strdup', 'setlinebuf', 'vsyslog', 'strnlen', + 'strndup', 'waitpid', 'seteuid', 'setegid', 'chroot', + 'mkstemp', 'mkdtemp', 'pread', 'pwrite', 'strcasestr', + 'strsep', 'strtok_r', 'strtoll', 'strtoull', 'setenv', 'unsetenv', + 'utime', 'utimes', 'dup2', 'chown', 'link', 'readlink', + 'symlink', 'lchown', 'realpath', 'memmem', 'vdprintf', + 'dprintf', 'get_current_dir_name', 'copy_file_range', + 'strerror_r', 'clock_gettime', 'memset_s'], + 'timegm.c': ['timegm'], + # Note: C99_VSNPRINTF is not a function, but a special condition + # for replacement + 'snprintf.c': ['C99_VSNPRINTF', 'snprintf', 'vsnprintf', 'asprintf', 'vasprintf'], + # Note: WORKING_STRPTIME is not a function, but a special condition + # for replacement + 'strptime.c': ['WORKING_STRPTIME', 'strptime'], + } + + +def build(bld): + bld.RECURSE('buildtools/wafsamba') + + REPLACE_HOSTCC_SOURCE = '' + + for filename in REPLACEMENT_FUNCTIONS.keys(): + for function in REPLACEMENT_FUNCTIONS[filename]: + if not bld.CONFIG_SET('HAVE_%s' % function.upper()): + REPLACE_HOSTCC_SOURCE += ' %s' % filename + break + + extra_libs = '' + if bld.CONFIG_SET('HAVE_LIBBSD'): extra_libs += ' bsd' + if bld.CONFIG_SET('HAVE_LIBRT'): extra_libs += ' rt' + if bld.CONFIG_SET('REPLACE_REQUIRES_LIBSOCKET_LIBNSL'): extra_libs += ' socket nsl' + + if not bld.CONFIG_SET('HAVE_CLOSEFROM'): + REPLACE_HOSTCC_SOURCE += ' closefrom.c' + + bld.SAMBA_SUBSYSTEM('LIBREPLACE_HOSTCC', + REPLACE_HOSTCC_SOURCE, + use_hostcc=True, + use_global_deps=False, + group='hostcc_base_build_main', + deps = extra_libs + ) + + REPLACE_SOURCE = REPLACE_HOSTCC_SOURCE + + if not bld.CONFIG_SET('HAVE_DLOPEN'): REPLACE_SOURCE += ' dlfcn.c' + if not bld.CONFIG_SET('HAVE_POLL'): REPLACE_SOURCE += ' poll.c' + + if not bld.CONFIG_SET('HAVE_SOCKETPAIR'): REPLACE_SOURCE += ' socketpair.c' + if not bld.CONFIG_SET('HAVE_CONNECT'): REPLACE_SOURCE += ' socket.c' + if not bld.CONFIG_SET('HAVE_GETIFADDRS'): REPLACE_SOURCE += ' getifaddrs.c' + if not bld.CONFIG_SET('HAVE_GETADDRINFO'): REPLACE_SOURCE += ' getaddrinfo.c' + if not bld.CONFIG_SET('HAVE_INET_NTOA'): REPLACE_SOURCE += ' inet_ntoa.c' + if not bld.CONFIG_SET('HAVE_INET_ATON'): REPLACE_SOURCE += ' inet_aton.c' + if not bld.CONFIG_SET('HAVE_INET_NTOP'): REPLACE_SOURCE += ' inet_ntop.c' + if not bld.CONFIG_SET('HAVE_INET_PTON'): REPLACE_SOURCE += ' inet_pton.c' + if not bld.CONFIG_SET('HAVE_GETXATTR') or bld.CONFIG_SET('XATTR_ADDITIONAL_OPTIONS'): + REPLACE_SOURCE += ' xattr.c' + + if not bld.CONFIG_SET('HAVE_CLOSEFROM'): + REPLACE_SOURCE += ' closefrom.c' + + bld.SAMBA_LIBRARY('replace', + source=REPLACE_SOURCE, + group='base_libraries', + # FIXME: Ideally symbols should be hidden here so they + # don't appear in the global namespace when Samba + # libraries are loaded, but this doesn't appear to work + # at the moment: + # hide_symbols=bld.BUILTIN_LIBRARY('replace'), + private_library=True, + provide_builtin_linking=True, + deps='dl attr' + extra_libs) + + replace_test_cflags = '' + if bld.CONFIG_SET('HAVE_WNO_FORMAT_TRUNCATION'): + replace_test_cflags += " -Wno-format-truncation" + bld.SAMBA_SUBSYSTEM('replace-test', + source='''tests/testsuite.c tests/strptime.c + tests/os2_delete.c tests/getifaddrs.c''', + deps='replace', + cflags=replace_test_cflags) + + bld.SAMBA_BINARY('replace_testsuite', + source='tests/main.c', + deps='replace replace-test', + install=False) + + # build replacements for stdint.h and stdbool.h if needed + bld.SAMBA_GENERATOR('replace_stdint_h', + rule='cp ${SRC} ${TGT}', + source='hdr_replace.h', + target='stdint.h', + enabled = not bld.CONFIG_SET('HAVE_STDINT_H')) + bld.SAMBA_GENERATOR('replace_stdbool_h', + rule='cp ${SRC} ${TGT}', + source='hdr_replace.h', + target='stdbool.h', + enabled = not bld.CONFIG_SET('HAVE_STDBOOL_H')) + + bld.SAMBA_SUBSYSTEM('samba_intl', source='', use_global_deps=False,deps=bld.env.intl_libs) + +def testonly(ctx): + '''run talloc testsuite''' + import samba_utils + + samba_utils.ADD_LD_LIBRARY_PATH('bin/shared') + samba_utils.ADD_LD_LIBRARY_PATH('bin/shared/private') + + cmd = os.path.join(Context.g_module.out, 'replace_testsuite') + ret = samba_utils.RUN_COMMAND(cmd) + print("testsuite returned %d" % ret) + sys.exit(ret) + +# WAF doesn't build the unit tests for this, maybe because they don't link with talloc? +# This forces it +def test(ctx): + Options.commands.append('build') + Options.commands.append('testonly') + +def dist(): + '''makes a tarball for distribution''' + samba_dist.dist() diff --git a/lib/replace/xattr.c b/lib/replace/xattr.c new file mode 100644 index 0000000..1044942 --- /dev/null +++ b/lib/replace/xattr.c @@ -0,0 +1,852 @@ +/* + Unix SMB/CIFS implementation. + replacement routines for xattr implementations + Copyright (C) Jeremy Allison 1998-2005 + Copyright (C) Timur Bakeyev 2005 + Copyright (C) Bjoern Jacke 2006-2007 + Copyright (C) Herb Lewis 2003 + Copyright (C) Andrew Bartlett 2012 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#define UID_WRAPPER_NOT_REPLACE +#include "replace.h" +#include "system/filesys.h" +#include "system/dir.h" + +/******** Solaris EA helper function prototypes ********/ +#ifdef HAVE_ATTROPEN +#define SOLARIS_ATTRMODE S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP +static int solaris_write_xattr(int attrfd, const char *value, size_t size); +static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size); +static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size); +static int solaris_unlinkat(int attrdirfd, const char *name); +static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode); +static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode); +#endif + +/************************************************************************** + Wrappers for extented attribute calls. Based on the Linux package with + support for IRIX and (Net|Free)BSD also. Expand as other systems have them. +****************************************************************************/ + +ssize_t rep_getxattr (const char *path, const char *name, void *value, size_t size) +{ +#if defined(HAVE_XATTR_XATTR) +#ifndef XATTR_ADDITIONAL_OPTIONS + return getxattr(path, name, value, size); +#else + +/* So that we do not recursively call this function */ +#undef getxattr + int options = 0; + return getxattr(path, name, value, size, 0, options); +#endif +#elif defined(HAVE_XATTR_EA) + return getea(path, name, value, size); +#elif defined(HAVE_XATTR_EXTATTR) + ssize_t retval; + int attrnamespace; + const char *attrname; + + if (strncmp(name, "system.", 7) == 0) { + attrnamespace = EXTATTR_NAMESPACE_SYSTEM; + attrname = name + 7; + } else if (strncmp(name, "user.", 5) == 0) { + attrnamespace = EXTATTR_NAMESPACE_USER; + attrname = name + 5; + } else { + errno = EINVAL; + return -1; + } + + /* + * The BSD implementation has a nasty habit of silently truncating + * the returned value to the size of the buffer, so we have to check + * that the buffer is large enough to fit the returned value. + */ + if((retval=extattr_get_file(path, attrnamespace, attrname, NULL, 0)) >= 0) { + if (size == 0) { + return retval; + } else if (retval > size) { + errno = ERANGE; + return -1; + } + if((retval=extattr_get_file(path, attrnamespace, attrname, value, size)) >= 0) + return retval; + } + + return -1; +#elif defined(HAVE_XATTR_ATTR) + int retval, flags = 0; + int valuelength = (int)size; + char *attrname = strchr(name,'.') + 1; + + if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT; + + retval = attr_get(path, attrname, (char *)value, &valuelength, flags); + if (size == 0 && retval == -1 && errno == E2BIG) { + return valuelength; + } + + return retval ? retval : valuelength; +#elif defined(HAVE_ATTROPEN) + ssize_t ret = -1; + int attrfd = solaris_attropen(path, name, O_RDONLY, 0); + if (attrfd >= 0) { + ret = solaris_read_xattr(attrfd, value, size); + close(attrfd); + } + return ret; +#else + errno = ENOSYS; + return -1; +#endif +} + +ssize_t rep_fgetxattr (int filedes, const char *name, void *value, size_t size) +{ +#if defined(HAVE_XATTR_XATTR) +#ifndef XATTR_ADDITIONAL_OPTIONS + return fgetxattr(filedes, name, value, size); +#else + +/* So that we do not recursively call this function */ +#undef fgetxattr + int options = 0; + return fgetxattr(filedes, name, value, size, 0, options); +#endif +#elif defined(HAVE_XATTR_EA) + return fgetea(filedes, name, value, size); +#elif defined(HAVE_XATTR_EXTATTR) + ssize_t retval; + int attrnamespace; + const char *attrname; + + if (strncmp(name, "system.", 7) == 0) { + attrnamespace = EXTATTR_NAMESPACE_SYSTEM; + attrname = name + 7; + } else if (strncmp(name, "user.", 5) == 0) { + attrnamespace = EXTATTR_NAMESPACE_USER; + attrname = name + 5; + } else { + errno = EINVAL; + return -1; + } + + if((retval=extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0)) >= 0) { + if (size == 0) { + return retval; + } else if (retval > size) { + errno = ERANGE; + return -1; + } + if((retval=extattr_get_fd(filedes, attrnamespace, attrname, value, size)) >= 0) + return retval; + } + + return -1; +#elif defined(HAVE_XATTR_ATTR) + int retval, flags = 0; + int valuelength = (int)size; + char *attrname = strchr(name,'.') + 1; + + if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT; + + retval = attr_getf(filedes, attrname, (char *)value, &valuelength, flags); + if (size == 0 && retval == -1 && errno == E2BIG) { + return valuelength; + } + return retval ? retval : valuelength; +#elif defined(HAVE_ATTROPEN) + ssize_t ret = -1; + int attrfd = solaris_openat(filedes, name, O_RDONLY|O_XATTR, 0); + if (attrfd >= 0) { + ret = solaris_read_xattr(attrfd, value, size); + close(attrfd); + } + return ret; +#else + errno = ENOSYS; + return -1; +#endif +} + +#if defined(HAVE_XATTR_EXTATTR) + +#define EXTATTR_PREFIX(s) (s), (sizeof((s))-1) + +static struct { + int space; + const char *name; + size_t len; +} +extattr[] = { + { EXTATTR_NAMESPACE_SYSTEM, EXTATTR_PREFIX("system.") }, + { EXTATTR_NAMESPACE_USER, EXTATTR_PREFIX("user.") }, +}; + +typedef union { + const char *path; + int filedes; +} extattr_arg; + +static ssize_t bsd_attr_list (int type, extattr_arg arg, char *list, size_t size) +{ + ssize_t list_size, total_size = 0; + int i, len; + size_t t; + char *buf; + /* Iterate through extattr(2) namespaces */ + for(t = 0; t < ARRAY_SIZE(extattr); t++) { + if (t != EXTATTR_NAMESPACE_USER && geteuid() != 0) { + /* ignore all but user namespace when we are not root, see bug 10247 */ + continue; + } + switch(type) { + case 0: + list_size = extattr_list_file(arg.path, extattr[t].space, list, size); + break; + case 1: + list_size = extattr_list_link(arg.path, extattr[t].space, list, size); + break; + case 2: + list_size = extattr_list_fd(arg.filedes, extattr[t].space, list, size); + break; + default: + errno = ENOSYS; + return -1; + } + /* Some error happend. Errno should be set by the previous call */ + if(list_size < 0) + return -1; + /* No attributes */ + if(list_size == 0) + continue; + /* XXX: Call with an empty buffer may be used to calculate + necessary buffer size. Unfortunately, we can't say, how + many attributes were returned, so here is the potential + problem with the emulation. + */ + if(list == NULL) { + /* Take the worse case of one char attribute names - + two bytes per name plus one more for sanity. + */ + total_size += list_size + (list_size/2 + 1)*extattr[t].len; + continue; + } + /* Count necessary offset to fit namespace prefixes */ + len = 0; + for(i = 0; i < list_size; i += list[i] + 1) + len += extattr[t].len; + + total_size += list_size + len; + /* Buffer is too small to fit the results */ + if(total_size > size) { + errno = ERANGE; + return -1; + } + /* Shift results back, so we can prepend prefixes */ + buf = (char *)memmove(list + len, list, list_size); + + for(i = 0; i < list_size; i += len + 1) { + len = buf[i]; + + /* + * If for some reason we receive a truncated + * return from call to list xattrs the pascal + * string lengths will not be changed and + * therefore we must check that we're not + * reading garbage data or off end of array + */ + if (len + i >= list_size) { + errno = ERANGE; + return -1; + } + strncpy(list, extattr[t].name, extattr[t].len + 1); + list += extattr[t].len; + strncpy(list, buf + i + 1, len); + list[len] = '\0'; + list += len + 1; + } + size -= total_size; + } + return total_size; +} + +#endif + +#if defined(HAVE_XATTR_ATTR) && (defined(HAVE_SYS_ATTRIBUTES_H) || defined(HAVE_ATTR_ATTRIBUTES_H)) +static char attr_buffer[ATTR_MAX_VALUELEN]; + +static ssize_t irix_attr_list(const char *path, int filedes, char *list, size_t size, int flags) +{ + int retval = 0, index; + attrlist_cursor_t *cursor = 0; + int total_size = 0; + attrlist_t * al = (attrlist_t *)attr_buffer; + attrlist_ent_t *ae; + size_t ent_size, left = size; + char *bp = list; + + while (true) { + if (filedes) + retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor); + else + retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor); + if (retval) break; + for (index = 0; index < al->al_count; index++) { + ae = ATTR_ENTRY(attr_buffer, index); + ent_size = strlen(ae->a_name) + sizeof("user."); + if (left >= ent_size) { + strncpy(bp, "user.", sizeof("user.")); + strncat(bp, ae->a_name, ent_size - sizeof("user.")); + bp += ent_size; + left -= ent_size; + } else if (size) { + errno = ERANGE; + retval = -1; + break; + } + total_size += ent_size; + } + if (al->al_more == 0) break; + } + if (retval == 0) { + flags |= ATTR_ROOT; + cursor = 0; + while (true) { + if (filedes) + retval = attr_listf(filedes, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor); + else + retval = attr_list(path, attr_buffer, ATTR_MAX_VALUELEN, flags, cursor); + if (retval) break; + for (index = 0; index < al->al_count; index++) { + ae = ATTR_ENTRY(attr_buffer, index); + ent_size = strlen(ae->a_name) + sizeof("system."); + if (left >= ent_size) { + strncpy(bp, "system.", sizeof("system.")); + strncat(bp, ae->a_name, ent_size - sizeof("system.")); + bp += ent_size; + left -= ent_size; + } else if (size) { + errno = ERANGE; + retval = -1; + break; + } + total_size += ent_size; + } + if (al->al_more == 0) break; + } + } + return (ssize_t)(retval ? retval : total_size); +} + +#endif + +ssize_t rep_listxattr (const char *path, char *list, size_t size) +{ +#if defined(HAVE_XATTR_XATTR) +#ifndef XATTR_ADDITIONAL_OPTIONS + return listxattr(path, list, size); +#else +/* So that we do not recursively call this function */ +#undef listxattr + int options = 0; + return listxattr(path, list, size, options); +#endif +#elif defined(HAVE_XATTR_EA) + return listea(path, list, size); +#elif defined(HAVE_XATTR_EXTATTR) + extattr_arg arg; + arg.path = path; + return bsd_attr_list(0, arg, list, size); +#elif defined(HAVE_XATTR_ATTR) && defined(HAVE_SYS_ATTRIBUTES_H) + return irix_attr_list(path, 0, list, size, 0); +#elif defined(HAVE_ATTROPEN) + ssize_t ret = -1; + int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0); + if (attrdirfd >= 0) { + ret = solaris_list_xattr(attrdirfd, list, size); + close(attrdirfd); + } + return ret; +#else + errno = ENOSYS; + return -1; +#endif +} + +ssize_t rep_flistxattr (int filedes, char *list, size_t size) +{ +#if defined(HAVE_XATTR_XATTR) +#ifndef XATTR_ADDITIONAL_OPTIONS + return flistxattr(filedes, list, size); +#else +/* So that we do not recursively call this function */ +#undef flistxattr + int options = 0; + return flistxattr(filedes, list, size, options); +#endif +#elif defined(HAVE_XATTR_EA) + return flistea(filedes, list, size); +#elif defined(HAVE_XATTR_EXTATTR) + extattr_arg arg; + arg.filedes = filedes; + return bsd_attr_list(2, arg, list, size); +#elif defined(HAVE_XATTR_ATTR) + return irix_attr_list(NULL, filedes, list, size, 0); +#elif defined(HAVE_ATTROPEN) + ssize_t ret = -1; + int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0); + if (attrdirfd >= 0) { + ret = solaris_list_xattr(attrdirfd, list, size); + close(attrdirfd); + } + return ret; +#else + errno = ENOSYS; + return -1; +#endif +} + +int rep_removexattr (const char *path, const char *name) +{ +#if defined(HAVE_XATTR_XATTR) +#ifndef XATTR_ADDITIONAL_OPTIONS + return removexattr(path, name); +#else +/* So that we do not recursively call this function */ +#undef removexattr + int options = 0; + return removexattr(path, name, options); +#endif +#elif defined(HAVE_XATTR_EA) + return removeea(path, name); +#elif defined(HAVE_XATTR_EXTATTR) + int attrnamespace; + const char *attrname; + + if (strncmp(name, "system.", 7) == 0) { + attrnamespace = EXTATTR_NAMESPACE_SYSTEM; + attrname = name + 7; + } else if (strncmp(name, "user.", 5) == 0) { + attrnamespace = EXTATTR_NAMESPACE_USER; + attrname = name + 5; + } else { + errno = EINVAL; + return -1; + } + + return extattr_delete_file(path, attrnamespace, attrname); +#elif defined(HAVE_XATTR_ATTR) + int flags = 0; + char *attrname = strchr(name,'.') + 1; + + if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT; + + return attr_remove(path, attrname, flags); +#elif defined(HAVE_ATTROPEN) + int ret = -1; + int attrdirfd = solaris_attropen(path, ".", O_RDONLY, 0); + if (attrdirfd >= 0) { + ret = solaris_unlinkat(attrdirfd, name); + close(attrdirfd); + } + return ret; +#else + errno = ENOSYS; + return -1; +#endif +} + +int rep_fremovexattr (int filedes, const char *name) +{ +#if defined(HAVE_XATTR_XATTR) +#ifndef XATTR_ADDITIONAL_OPTIONS + return fremovexattr(filedes, name); +#else +/* So that we do not recursively call this function */ +#undef fremovexattr + int options = 0; + return fremovexattr(filedes, name, options); +#endif +#elif defined(HAVE_XATTR_EA) + return fremoveea(filedes, name); +#elif defined(HAVE_XATTR_EXTATTR) + int attrnamespace; + const char *attrname; + + if (strncmp(name, "system.", 7) == 0) { + attrnamespace = EXTATTR_NAMESPACE_SYSTEM; + attrname = name + 7; + } else if (strncmp(name, "user.", 5) == 0) { + attrnamespace = EXTATTR_NAMESPACE_USER; + attrname = name + 5; + } else { + errno = EINVAL; + return -1; + } + + return extattr_delete_fd(filedes, attrnamespace, attrname); +#elif defined(HAVE_XATTR_ATTR) + int flags = 0; + char *attrname = strchr(name,'.') + 1; + + if (strncmp(name, "system", 6) == 0) flags |= ATTR_ROOT; + + return attr_removef(filedes, attrname, flags); +#elif defined(HAVE_ATTROPEN) + int ret = -1; + int attrdirfd = solaris_openat(filedes, ".", O_RDONLY|O_XATTR, 0); + if (attrdirfd >= 0) { + ret = solaris_unlinkat(attrdirfd, name); + close(attrdirfd); + } + return ret; +#else + errno = ENOSYS; + return -1; +#endif +} + +int rep_setxattr (const char *path, const char *name, const void *value, size_t size, int flags) +{ + int retval = -1; +#if defined(HAVE_XATTR_XATTR) +#ifndef XATTR_ADDITIONAL_OPTIONS + retval = setxattr(path, name, value, size, flags); + if (retval < 0) { + if (errno == ENOSPC || errno == E2BIG) { + errno = ENAMETOOLONG; + } + } + return retval; +#else +/* So that we do not recursively call this function */ +#undef setxattr + retval = setxattr(path, name, value, size, 0, flags); + if (retval < 0) { + if (errno == E2BIG) { + errno = ENAMETOOLONG; + } + } + return retval; +#endif +#elif defined(HAVE_XATTR_EA) + if (flags) { + retval = getea(path, name, NULL, 0); + if (retval < 0) { + if (flags & XATTR_REPLACE && errno == ENOATTR) { + return -1; + } + } else { + if (flags & XATTR_CREATE) { + errno = EEXIST; + return -1; + } + } + } + retval = setea(path, name, value, size, 0); + return retval; +#elif defined(HAVE_XATTR_EXTATTR) + int attrnamespace; + const char *attrname; + + if (strncmp(name, "system.", 7) == 0) { + attrnamespace = EXTATTR_NAMESPACE_SYSTEM; + attrname = name + 7; + } else if (strncmp(name, "user.", 5) == 0) { + attrnamespace = EXTATTR_NAMESPACE_USER; + attrname = name + 5; + } else { + errno = EINVAL; + return -1; + } + + if (flags) { + /* Check attribute existence */ + retval = extattr_get_file(path, attrnamespace, attrname, NULL, 0); + if (retval < 0) { + /* REPLACE attribute, that doesn't exist */ + if (flags & XATTR_REPLACE && errno == ENOATTR) { + errno = ENOATTR; + return -1; + } + /* Ignore other errors */ + } + else { + /* CREATE attribute, that already exists */ + if (flags & XATTR_CREATE) { + errno = EEXIST; + return -1; + } + } + } + retval = extattr_set_file(path, attrnamespace, attrname, value, size); + return (retval < 0) ? -1 : 0; +#elif defined(HAVE_XATTR_ATTR) + int myflags = 0; + char *attrname = strchr(name,'.') + 1; + + if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT; + if (flags & XATTR_CREATE) myflags |= ATTR_CREATE; + if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE; + + retval = attr_set(path, attrname, (const char *)value, size, myflags); + if (retval < 0) { + if (errno == E2BIG) { + errno = ENAMETOOLONG; + } + } + return retval; +#elif defined(HAVE_ATTROPEN) + int myflags = O_RDWR; + int attrfd; + if (flags & XATTR_CREATE) myflags |= O_EXCL; + if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT; + attrfd = solaris_attropen(path, name, myflags, (mode_t) SOLARIS_ATTRMODE); + if (attrfd >= 0) { + retval = solaris_write_xattr(attrfd, value, size); + close(attrfd); + } + return retval; +#else + errno = ENOSYS; + return -1; +#endif +} + +int rep_fsetxattr (int filedes, const char *name, const void *value, size_t size, int flags) +{ + int retval = -1; +#if defined(HAVE_XATTR_XATTR) +#ifndef XATTR_ADDITIONAL_OPTIONS + retval = fsetxattr(filedes, name, value, size, flags); + if (retval < 0) { + if (errno == ENOSPC) { + errno = ENAMETOOLONG; + } + } + return retval; +#else +/* So that we do not recursively call this function */ +#undef fsetxattr + retval = fsetxattr(filedes, name, value, size, 0, flags); + if (retval < 0) { + if (errno == E2BIG) { + errno = ENAMETOOLONG; + } + } + return retval; +#endif +#elif defined(HAVE_XATTR_EA) + if (flags) { + retval = fgetea(filedes, name, NULL, 0); + if (retval < 0) { + if (flags & XATTR_REPLACE && errno == ENOATTR) { + return -1; + } + } else { + if (flags & XATTR_CREATE) { + errno = EEXIST; + return -1; + } + } + } + retval = fsetea(filedes, name, value, size, 0); + return retval; +#elif defined(HAVE_XATTR_EXTATTR) + int attrnamespace; + const char *attrname; + + if (strncmp(name, "system.", 7) == 0) { + attrnamespace = EXTATTR_NAMESPACE_SYSTEM; + attrname = name + 7; + } else if (strncmp(name, "user.", 5) == 0) { + attrnamespace = EXTATTR_NAMESPACE_USER; + attrname = name + 5; + } else { + errno = EINVAL; + return -1; + } + + if (flags) { + /* Check attribute existence */ + retval = extattr_get_fd(filedes, attrnamespace, attrname, NULL, 0); + if (retval < 0) { + /* REPLACE attribute, that doesn't exist */ + if (flags & XATTR_REPLACE && errno == ENOATTR) { + errno = ENOATTR; + return -1; + } + /* Ignore other errors */ + } + else { + /* CREATE attribute, that already exists */ + if (flags & XATTR_CREATE) { + errno = EEXIST; + return -1; + } + } + } + retval = extattr_set_fd(filedes, attrnamespace, attrname, value, size); + return (retval < 0) ? -1 : 0; +#elif defined(HAVE_XATTR_ATTR) + int myflags = 0; + char *attrname = strchr(name,'.') + 1; + + if (strncmp(name, "system", 6) == 0) myflags |= ATTR_ROOT; + if (flags & XATTR_CREATE) myflags |= ATTR_CREATE; + if (flags & XATTR_REPLACE) myflags |= ATTR_REPLACE; + + return attr_setf(filedes, attrname, (const char *)value, size, myflags); +#elif defined(HAVE_ATTROPEN) + int myflags = O_RDWR | O_XATTR; + int attrfd; + if (flags & XATTR_CREATE) myflags |= O_EXCL; + if (!(flags & XATTR_REPLACE)) myflags |= O_CREAT; + attrfd = solaris_openat(filedes, name, myflags, (mode_t) SOLARIS_ATTRMODE); + if (attrfd >= 0) { + retval = solaris_write_xattr(attrfd, value, size); + close(attrfd); + } + return retval; +#else + errno = ENOSYS; + return -1; +#endif +} + +/************************************************************************** + helper functions for Solaris' EA support +****************************************************************************/ +#ifdef HAVE_ATTROPEN +static ssize_t solaris_read_xattr(int attrfd, void *value, size_t size) +{ + struct stat sbuf; + + if (fstat(attrfd, &sbuf) == -1) { + errno = ENOATTR; + return -1; + } + + /* This is to return the current size of the named extended attribute */ + if (size == 0) { + return sbuf.st_size; + } + + /* check size and read xattr */ + if (sbuf.st_size > size) { + errno = ERANGE; + return -1; + } + + return read(attrfd, value, sbuf.st_size); +} + +static ssize_t solaris_list_xattr(int attrdirfd, char *list, size_t size) +{ + ssize_t len = 0; + DIR *dirp; + struct dirent *de; + int newfd = dup(attrdirfd); + /* CAUTION: The originating file descriptor should not be + used again following the call to fdopendir(). + For that reason we dup() the file descriptor + here to make things more clear. */ + dirp = fdopendir(newfd); + + while ((de = readdir(dirp))) { + size_t listlen = strlen(de->d_name) + 1; + if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) { + /* we don't want "." and ".." here: */ + continue; + } + + if (size == 0) { + /* return the current size of the list of extended attribute names*/ + len += listlen; + } else { + /* check size and copy entrieѕ + nul into list. */ + if ((len + listlen) > size) { + errno = ERANGE; + len = -1; + break; + } else { + strlcpy(list + len, de->d_name, listlen); + len += listlen; + } + } + } + + if (closedir(dirp) == -1) { + return -1; + } + return len; +} + +static int solaris_unlinkat(int attrdirfd, const char *name) +{ + if (unlinkat(attrdirfd, name, 0) == -1) { + if (errno == ENOENT) { + errno = ENOATTR; + } + return -1; + } + return 0; +} + +static int solaris_attropen(const char *path, const char *attrpath, int oflag, mode_t mode) +{ + int filedes = attropen(path, attrpath, oflag, mode); + if (filedes == -1) { + if (errno == EINVAL) { + errno = ENOTSUP; + } else { + errno = ENOATTR; + } + } + return filedes; +} + +static int solaris_openat(int fildes, const char *path, int oflag, mode_t mode) +{ + int filedes = openat(fildes, path, oflag, mode); + if (filedes == -1) { + if (errno == EINVAL) { + errno = ENOTSUP; + } else { + errno = ENOATTR; + } + } + return filedes; +} + +static int solaris_write_xattr(int attrfd, const char *value, size_t size) +{ + if ((ftruncate(attrfd, 0) == 0) && (write(attrfd, value, size) == size)) { + return 0; + } else { + return -1; + } +} +#endif /*HAVE_ATTROPEN*/ + + diff --git a/lib/talloc/ABI/pytalloc-util-2.0.6.sigs b/lib/talloc/ABI/pytalloc-util-2.0.6.sigs new file mode 100644 index 0000000..961c1a8 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.0.6.sigs @@ -0,0 +1,6 @@ +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.0.7.sigs b/lib/talloc/ABI/pytalloc-util-2.0.7.sigs new file mode 100644 index 0000000..961c1a8 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.0.7.sigs @@ -0,0 +1,6 @@ +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.0.8.sigs b/lib/talloc/ABI/pytalloc-util-2.0.8.sigs new file mode 100644 index 0000000..961c1a8 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.0.8.sigs @@ -0,0 +1,6 @@ +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.1.0.sigs b/lib/talloc/ABI/pytalloc-util-2.1.0.sigs new file mode 100644 index 0000000..961c1a8 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.0.sigs @@ -0,0 +1,6 @@ +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.1.1.sigs b/lib/talloc/ABI/pytalloc-util-2.1.1.sigs new file mode 100644 index 0000000..961c1a8 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.1.sigs @@ -0,0 +1,6 @@ +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.1.10.sigs b/lib/talloc/ABI/pytalloc-util-2.1.10.sigs new file mode 100644 index 0000000..9d4d4d1 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.10.sigs @@ -0,0 +1,16 @@ +_pytalloc_check_type: int (PyObject *, const char *) +_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *) +_pytalloc_get_ptr: void *(PyObject *) +_pytalloc_get_type: void *(PyObject *, const char *) +pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *) +pytalloc_BaseObject_check: int (PyObject *) +pytalloc_BaseObject_size: size_t (void) +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GetBaseObjectType: PyTypeObject *(void) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.1.11.sigs b/lib/talloc/ABI/pytalloc-util-2.1.11.sigs new file mode 100644 index 0000000..9d4d4d1 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.11.sigs @@ -0,0 +1,16 @@ +_pytalloc_check_type: int (PyObject *, const char *) +_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *) +_pytalloc_get_ptr: void *(PyObject *) +_pytalloc_get_type: void *(PyObject *, const char *) +pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *) +pytalloc_BaseObject_check: int (PyObject *) +pytalloc_BaseObject_size: size_t (void) +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GetBaseObjectType: PyTypeObject *(void) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.1.12.sigs b/lib/talloc/ABI/pytalloc-util-2.1.12.sigs new file mode 100644 index 0000000..9d4d4d1 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.12.sigs @@ -0,0 +1,16 @@ +_pytalloc_check_type: int (PyObject *, const char *) +_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *) +_pytalloc_get_ptr: void *(PyObject *) +_pytalloc_get_type: void *(PyObject *, const char *) +pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *) +pytalloc_BaseObject_check: int (PyObject *) +pytalloc_BaseObject_size: size_t (void) +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GetBaseObjectType: PyTypeObject *(void) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.1.13.sigs b/lib/talloc/ABI/pytalloc-util-2.1.13.sigs new file mode 100644 index 0000000..9d4d4d1 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.13.sigs @@ -0,0 +1,16 @@ +_pytalloc_check_type: int (PyObject *, const char *) +_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *) +_pytalloc_get_ptr: void *(PyObject *) +_pytalloc_get_type: void *(PyObject *, const char *) +pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *) +pytalloc_BaseObject_check: int (PyObject *) +pytalloc_BaseObject_size: size_t (void) +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GetBaseObjectType: PyTypeObject *(void) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.1.14.sigs b/lib/talloc/ABI/pytalloc-util-2.1.14.sigs new file mode 100644 index 0000000..9d4d4d1 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.14.sigs @@ -0,0 +1,16 @@ +_pytalloc_check_type: int (PyObject *, const char *) +_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *) +_pytalloc_get_ptr: void *(PyObject *) +_pytalloc_get_type: void *(PyObject *, const char *) +pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *) +pytalloc_BaseObject_check: int (PyObject *) +pytalloc_BaseObject_size: size_t (void) +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GetBaseObjectType: PyTypeObject *(void) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.1.15.sigs b/lib/talloc/ABI/pytalloc-util-2.1.15.sigs new file mode 100644 index 0000000..9d4d4d1 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.15.sigs @@ -0,0 +1,16 @@ +_pytalloc_check_type: int (PyObject *, const char *) +_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *) +_pytalloc_get_ptr: void *(PyObject *) +_pytalloc_get_type: void *(PyObject *, const char *) +pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *) +pytalloc_BaseObject_check: int (PyObject *) +pytalloc_BaseObject_size: size_t (void) +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GetBaseObjectType: PyTypeObject *(void) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.1.16.sigs b/lib/talloc/ABI/pytalloc-util-2.1.16.sigs new file mode 100644 index 0000000..9d4d4d1 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.16.sigs @@ -0,0 +1,16 @@ +_pytalloc_check_type: int (PyObject *, const char *) +_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *) +_pytalloc_get_ptr: void *(PyObject *) +_pytalloc_get_type: void *(PyObject *, const char *) +pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *) +pytalloc_BaseObject_check: int (PyObject *) +pytalloc_BaseObject_size: size_t (void) +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GetBaseObjectType: PyTypeObject *(void) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.1.2.sigs b/lib/talloc/ABI/pytalloc-util-2.1.2.sigs new file mode 100644 index 0000000..961c1a8 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.2.sigs @@ -0,0 +1,6 @@ +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.1.3.sigs b/lib/talloc/ABI/pytalloc-util-2.1.3.sigs new file mode 100644 index 0000000..961c1a8 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.3.sigs @@ -0,0 +1,6 @@ +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.1.4.sigs b/lib/talloc/ABI/pytalloc-util-2.1.4.sigs new file mode 100644 index 0000000..961c1a8 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.4.sigs @@ -0,0 +1,6 @@ +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.1.5.sigs b/lib/talloc/ABI/pytalloc-util-2.1.5.sigs new file mode 100644 index 0000000..961c1a8 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.5.sigs @@ -0,0 +1,6 @@ +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.1.6.sigs b/lib/talloc/ABI/pytalloc-util-2.1.6.sigs new file mode 100644 index 0000000..666fec0 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.6.sigs @@ -0,0 +1,13 @@ +_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *) +_pytalloc_get_ptr: void *(PyObject *) +_pytalloc_get_type: void *(PyObject *, const char *) +pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *) +pytalloc_BaseObject_check: int (PyObject *) +pytalloc_BaseObject_size: size_t (void) +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GetBaseObjectType: PyTypeObject *(void) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.1.7.sigs b/lib/talloc/ABI/pytalloc-util-2.1.7.sigs new file mode 100644 index 0000000..666fec0 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.7.sigs @@ -0,0 +1,13 @@ +_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *) +_pytalloc_get_ptr: void *(PyObject *) +_pytalloc_get_type: void *(PyObject *, const char *) +pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *) +pytalloc_BaseObject_check: int (PyObject *) +pytalloc_BaseObject_size: size_t (void) +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GetBaseObjectType: PyTypeObject *(void) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.1.8.sigs b/lib/talloc/ABI/pytalloc-util-2.1.8.sigs new file mode 100644 index 0000000..666fec0 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.8.sigs @@ -0,0 +1,13 @@ +_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *) +_pytalloc_get_ptr: void *(PyObject *) +_pytalloc_get_type: void *(PyObject *, const char *) +pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *) +pytalloc_BaseObject_check: int (PyObject *) +pytalloc_BaseObject_size: size_t (void) +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GetBaseObjectType: PyTypeObject *(void) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.1.9.sigs b/lib/talloc/ABI/pytalloc-util-2.1.9.sigs new file mode 100644 index 0000000..9d4d4d1 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.1.9.sigs @@ -0,0 +1,16 @@ +_pytalloc_check_type: int (PyObject *, const char *) +_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *) +_pytalloc_get_ptr: void *(PyObject *) +_pytalloc_get_type: void *(PyObject *, const char *) +pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *) +pytalloc_BaseObject_check: int (PyObject *) +pytalloc_BaseObject_size: size_t (void) +pytalloc_CObject_FromTallocPtr: PyObject *(void *) +pytalloc_Check: int (PyObject *) +pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GetBaseObjectType: PyTypeObject *(void) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.2.0.sigs b/lib/talloc/ABI/pytalloc-util-2.2.0.sigs new file mode 100644 index 0000000..62f066f --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.2.0.sigs @@ -0,0 +1,15 @@ +_pytalloc_check_type: int (PyObject *, const char *) +_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *) +_pytalloc_get_ptr: void *(PyObject *) +_pytalloc_get_type: void *(PyObject *, const char *) +pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *) +pytalloc_BaseObject_check: int (PyObject *) +pytalloc_BaseObject_size: size_t (void) +pytalloc_Check: int (PyObject *) +pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GetBaseObjectType: PyTypeObject *(void) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.3.0.sigs b/lib/talloc/ABI/pytalloc-util-2.3.0.sigs new file mode 100644 index 0000000..6056577 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.3.0.sigs @@ -0,0 +1,16 @@ +_pytalloc_check_type: int (PyObject *, const char *) +_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *) +_pytalloc_get_name: const char *(PyObject *) +_pytalloc_get_ptr: void *(PyObject *) +_pytalloc_get_type: void *(PyObject *, const char *) +pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *) +pytalloc_BaseObject_check: int (PyObject *) +pytalloc_BaseObject_size: size_t (void) +pytalloc_Check: int (PyObject *) +pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GetBaseObjectType: PyTypeObject *(void) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.3.1.sigs b/lib/talloc/ABI/pytalloc-util-2.3.1.sigs new file mode 100644 index 0000000..6056577 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.3.1.sigs @@ -0,0 +1,16 @@ +_pytalloc_check_type: int (PyObject *, const char *) +_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *) +_pytalloc_get_name: const char *(PyObject *) +_pytalloc_get_ptr: void *(PyObject *) +_pytalloc_get_type: void *(PyObject *, const char *) +pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *) +pytalloc_BaseObject_check: int (PyObject *) +pytalloc_BaseObject_size: size_t (void) +pytalloc_Check: int (PyObject *) +pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GetBaseObjectType: PyTypeObject *(void) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.3.2.sigs b/lib/talloc/ABI/pytalloc-util-2.3.2.sigs new file mode 100644 index 0000000..6056577 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.3.2.sigs @@ -0,0 +1,16 @@ +_pytalloc_check_type: int (PyObject *, const char *) +_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *) +_pytalloc_get_name: const char *(PyObject *) +_pytalloc_get_ptr: void *(PyObject *) +_pytalloc_get_type: void *(PyObject *, const char *) +pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *) +pytalloc_BaseObject_check: int (PyObject *) +pytalloc_BaseObject_size: size_t (void) +pytalloc_Check: int (PyObject *) +pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GetBaseObjectType: PyTypeObject *(void) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.3.3.sigs b/lib/talloc/ABI/pytalloc-util-2.3.3.sigs new file mode 100644 index 0000000..6056577 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.3.3.sigs @@ -0,0 +1,16 @@ +_pytalloc_check_type: int (PyObject *, const char *) +_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *) +_pytalloc_get_name: const char *(PyObject *) +_pytalloc_get_ptr: void *(PyObject *) +_pytalloc_get_type: void *(PyObject *, const char *) +pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *) +pytalloc_BaseObject_check: int (PyObject *) +pytalloc_BaseObject_size: size_t (void) +pytalloc_Check: int (PyObject *) +pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GetBaseObjectType: PyTypeObject *(void) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.3.4.sigs b/lib/talloc/ABI/pytalloc-util-2.3.4.sigs new file mode 100644 index 0000000..6056577 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.3.4.sigs @@ -0,0 +1,16 @@ +_pytalloc_check_type: int (PyObject *, const char *) +_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *) +_pytalloc_get_name: const char *(PyObject *) +_pytalloc_get_ptr: void *(PyObject *) +_pytalloc_get_type: void *(PyObject *, const char *) +pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *) +pytalloc_BaseObject_check: int (PyObject *) +pytalloc_BaseObject_size: size_t (void) +pytalloc_Check: int (PyObject *) +pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GetBaseObjectType: PyTypeObject *(void) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.3.5.sigs b/lib/talloc/ABI/pytalloc-util-2.3.5.sigs new file mode 100644 index 0000000..6056577 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.3.5.sigs @@ -0,0 +1,16 @@ +_pytalloc_check_type: int (PyObject *, const char *) +_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *) +_pytalloc_get_name: const char *(PyObject *) +_pytalloc_get_ptr: void *(PyObject *) +_pytalloc_get_type: void *(PyObject *, const char *) +pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *) +pytalloc_BaseObject_check: int (PyObject *) +pytalloc_BaseObject_size: size_t (void) +pytalloc_Check: int (PyObject *) +pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GetBaseObjectType: PyTypeObject *(void) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/pytalloc-util-2.4.0.sigs b/lib/talloc/ABI/pytalloc-util-2.4.0.sigs new file mode 100644 index 0000000..6056577 --- /dev/null +++ b/lib/talloc/ABI/pytalloc-util-2.4.0.sigs @@ -0,0 +1,16 @@ +_pytalloc_check_type: int (PyObject *, const char *) +_pytalloc_get_mem_ctx: TALLOC_CTX *(PyObject *) +_pytalloc_get_name: const char *(PyObject *) +_pytalloc_get_ptr: void *(PyObject *) +_pytalloc_get_type: void *(PyObject *, const char *) +pytalloc_BaseObject_PyType_Ready: int (PyTypeObject *) +pytalloc_BaseObject_check: int (PyObject *) +pytalloc_BaseObject_size: size_t (void) +pytalloc_Check: int (PyObject *) +pytalloc_GenericObject_reference_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GenericObject_steal_ex: PyObject *(TALLOC_CTX *, void *) +pytalloc_GetBaseObjectType: PyTypeObject *(void) +pytalloc_GetObjectType: PyTypeObject *(void) +pytalloc_reference_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) +pytalloc_steal: PyObject *(PyTypeObject *, void *) +pytalloc_steal_ex: PyObject *(PyTypeObject *, TALLOC_CTX *, void *) diff --git a/lib/talloc/ABI/talloc-2.0.2.sigs b/lib/talloc/ABI/talloc-2.0.2.sigs new file mode 100644 index 0000000..6e236d5 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.0.2.sigs @@ -0,0 +1,62 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.0.3.sigs b/lib/talloc/ABI/talloc-2.0.3.sigs new file mode 100644 index 0000000..6e236d5 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.0.3.sigs @@ -0,0 +1,62 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.0.4.sigs b/lib/talloc/ABI/talloc-2.0.4.sigs new file mode 100644 index 0000000..6e236d5 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.0.4.sigs @@ -0,0 +1,62 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.0.5.sigs b/lib/talloc/ABI/talloc-2.0.5.sigs new file mode 100644 index 0000000..6e236d5 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.0.5.sigs @@ -0,0 +1,62 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.0.6.sigs b/lib/talloc/ABI/talloc-2.0.6.sigs new file mode 100644 index 0000000..6e236d5 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.0.6.sigs @@ -0,0 +1,62 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.0.7.sigs b/lib/talloc/ABI/talloc-2.0.7.sigs new file mode 100644 index 0000000..6e236d5 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.0.7.sigs @@ -0,0 +1,62 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.0.8.sigs b/lib/talloc/ABI/talloc-2.0.8.sigs new file mode 100644 index 0000000..15a9e95 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.0.8.sigs @@ -0,0 +1,63 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.1.0.sigs b/lib/talloc/ABI/talloc-2.1.0.sigs new file mode 100644 index 0000000..eae12cc --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.0.sigs @@ -0,0 +1,64 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.1.1.sigs b/lib/talloc/ABI/talloc-2.1.1.sigs new file mode 100644 index 0000000..eae12cc --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.1.sigs @@ -0,0 +1,64 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.1.10.sigs b/lib/talloc/ABI/talloc-2.1.10.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.10.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.1.11.sigs b/lib/talloc/ABI/talloc-2.1.11.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.11.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.1.12.sigs b/lib/talloc/ABI/talloc-2.1.12.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.12.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.1.13.sigs b/lib/talloc/ABI/talloc-2.1.13.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.13.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.1.14.sigs b/lib/talloc/ABI/talloc-2.1.14.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.14.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.1.15.sigs b/lib/talloc/ABI/talloc-2.1.15.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.15.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.1.16.sigs b/lib/talloc/ABI/talloc-2.1.16.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.16.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.1.2.sigs b/lib/talloc/ABI/talloc-2.1.2.sigs new file mode 100644 index 0000000..eae12cc --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.2.sigs @@ -0,0 +1,64 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.1.3.sigs b/lib/talloc/ABI/talloc-2.1.3.sigs new file mode 100644 index 0000000..eae12cc --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.3.sigs @@ -0,0 +1,64 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.1.4.sigs b/lib/talloc/ABI/talloc-2.1.4.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.4.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.1.5.sigs b/lib/talloc/ABI/talloc-2.1.5.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.5.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.1.6.sigs b/lib/talloc/ABI/talloc-2.1.6.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.6.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.1.7.sigs b/lib/talloc/ABI/talloc-2.1.7.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.7.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.1.8.sigs b/lib/talloc/ABI/talloc-2.1.8.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.8.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.1.9.sigs b/lib/talloc/ABI/talloc-2.1.9.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.1.9.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.2.0.sigs b/lib/talloc/ABI/talloc-2.2.0.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.2.0.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.3.0.sigs b/lib/talloc/ABI/talloc-2.3.0.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.3.0.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.3.1.sigs b/lib/talloc/ABI/talloc-2.3.1.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.3.1.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.3.2.sigs b/lib/talloc/ABI/talloc-2.3.2.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.3.2.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.3.3.sigs b/lib/talloc/ABI/talloc-2.3.3.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.3.3.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.3.4.sigs b/lib/talloc/ABI/talloc-2.3.4.sigs new file mode 100644 index 0000000..9969ce3 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.3.4.sigs @@ -0,0 +1,65 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.3.5.sigs b/lib/talloc/ABI/talloc-2.3.5.sigs new file mode 100644 index 0000000..ec3cee4 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.3.5.sigs @@ -0,0 +1,66 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_addbuf: void (char **, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/ABI/talloc-2.4.0.sigs b/lib/talloc/ABI/talloc-2.4.0.sigs new file mode 100644 index 0000000..ec3cee4 --- /dev/null +++ b/lib/talloc/ABI/talloc-2.4.0.sigs @@ -0,0 +1,66 @@ +_talloc: void *(const void *, size_t) +_talloc_array: void *(const void *, size_t, unsigned int, const char *) +_talloc_free: int (void *, const char *) +_talloc_get_type_abort: void *(const void *, const char *, const char *) +_talloc_memdup: void *(const void *, const void *, size_t, const char *) +_talloc_move: void *(const void *, const void *) +_talloc_pooled_object: void *(const void *, size_t, const char *, unsigned int, size_t) +_talloc_realloc: void *(const void *, void *, size_t, const char *) +_talloc_realloc_array: void *(const void *, void *, size_t, unsigned int, const char *) +_talloc_reference_loc: void *(const void *, const void *, const char *) +_talloc_set_destructor: void (const void *, int (*)(void *)) +_talloc_steal_loc: void *(const void *, const void *, const char *) +_talloc_zero: void *(const void *, size_t, const char *) +_talloc_zero_array: void *(const void *, size_t, unsigned int, const char *) +talloc_asprintf: char *(const void *, const char *, ...) +talloc_asprintf_addbuf: void (char **, const char *, ...) +talloc_asprintf_append: char *(char *, const char *, ...) +talloc_asprintf_append_buffer: char *(char *, const char *, ...) +talloc_autofree_context: void *(void) +talloc_check_name: void *(const void *, const char *) +talloc_disable_null_tracking: void (void) +talloc_enable_leak_report: void (void) +talloc_enable_leak_report_full: void (void) +talloc_enable_null_tracking: void (void) +talloc_enable_null_tracking_no_autofree: void (void) +talloc_find_parent_byname: void *(const void *, const char *) +talloc_free_children: void (void *) +talloc_get_name: const char *(const void *) +talloc_get_size: size_t (const void *) +talloc_increase_ref_count: int (const void *) +talloc_init: void *(const char *, ...) +talloc_is_parent: int (const void *, const void *) +talloc_named: void *(const void *, size_t, const char *, ...) +talloc_named_const: void *(const void *, size_t, const char *) +talloc_parent: void *(const void *) +talloc_parent_name: const char *(const void *) +talloc_pool: void *(const void *, size_t) +talloc_realloc_fn: void *(const void *, void *, size_t) +talloc_reference_count: size_t (const void *) +talloc_reparent: void *(const void *, const void *, const void *) +talloc_report: void (const void *, FILE *) +talloc_report_depth_cb: void (const void *, int, int, void (*)(const void *, int, int, int, void *), void *) +talloc_report_depth_file: void (const void *, int, int, FILE *) +talloc_report_full: void (const void *, FILE *) +talloc_set_abort_fn: void (void (*)(const char *)) +talloc_set_log_fn: void (void (*)(const char *)) +talloc_set_log_stderr: void (void) +talloc_set_memlimit: int (const void *, size_t) +talloc_set_name: const char *(const void *, const char *, ...) +talloc_set_name_const: void (const void *, const char *) +talloc_show_parents: void (const void *, FILE *) +talloc_strdup: char *(const void *, const char *) +talloc_strdup_append: char *(char *, const char *) +talloc_strdup_append_buffer: char *(char *, const char *) +talloc_strndup: char *(const void *, const char *, size_t) +talloc_strndup_append: char *(char *, const char *, size_t) +talloc_strndup_append_buffer: char *(char *, const char *, size_t) +talloc_test_get_magic: int (void) +talloc_total_blocks: size_t (const void *) +talloc_total_size: size_t (const void *) +talloc_unlink: int (const void *, void *) +talloc_vasprintf: char *(const void *, const char *, va_list) +talloc_vasprintf_append: char *(char *, const char *, va_list) +talloc_vasprintf_append_buffer: char *(char *, const char *, va_list) +talloc_version_major: int (void) +talloc_version_minor: int (void) diff --git a/lib/talloc/Makefile b/lib/talloc/Makefile new file mode 100644 index 0000000..db2275c --- /dev/null +++ b/lib/talloc/Makefile @@ -0,0 +1,68 @@ +# simple makefile wrapper to run waf + +WAF_BIN=`PATH=buildtools/bin:../../buildtools/bin:$$PATH which waf` +WAF_BINARY=$(PYTHON) $(WAF_BIN) +WAF=PYTHONHASHSEED=1 WAF_MAKE=1 $(WAF_BINARY) + +all: + $(WAF) build + +install: + $(WAF) install + +uninstall: + $(WAF) uninstall + +test: + $(WAF) test $(TEST_OPTIONS) + +testenv: + $(WAF) test --testenv $(TEST_OPTIONS) + +quicktest: + $(WAF) test --quick $(TEST_OPTIONS) + +dist: + touch .tmplock + WAFLOCK=.tmplock $(WAF) dist + +distcheck: + touch .tmplock + WAFLOCK=.tmplock $(WAF) distcheck + +clean: + $(WAF) clean + +distclean: + $(WAF) distclean + +reconfigure: configure + $(WAF) reconfigure + +show_waf_options: + $(WAF) --help + +# some compatibility make targets +everything: all + +testsuite: all + +check: test + +torture: all + +# this should do an install as well, once install is finished +installcheck: test + +etags: + $(WAF) etags + +ctags: + $(WAF) ctags + +pydoctor: + $(WAF) pydoctor + +bin/%:: FORCE + $(WAF) --targets=`basename $@` +FORCE: diff --git a/lib/talloc/NEWS b/lib/talloc/NEWS new file mode 100644 index 0000000..e5b3aa0 --- /dev/null +++ b/lib/talloc/NEWS @@ -0,0 +1,13 @@ +1.0.1 26 May 2007 + + BUGS + + * Set name of correctly when using talloc_append_string() (metze) + + LICENSE + + * Change license of files in lib/replace to LGPL (was GPL). (jelmer) + +1.0.0 30 April 2007 + + Initial release. diff --git a/lib/talloc/compat/talloc_compat1.c b/lib/talloc/compat/talloc_compat1.c new file mode 100644 index 0000000..519e8c3 --- /dev/null +++ b/lib/talloc/compat/talloc_compat1.c @@ -0,0 +1,51 @@ +/* + Samba trivial allocation library - compat functions + + Copyright (C) Stefan Metzmacher 2009 + + ** NOTE! The following LGPL license applies to the talloc + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* + * This file contains only function to build a + * compat talloc.so.1 library on top of talloc.so.2 + */ + +#include "replace.h" +#include "talloc.h" + +void *_talloc_reference(const void *context, const void *ptr); +void *_talloc_reference(const void *context, const void *ptr) { + return _talloc_reference_loc(context, ptr, + "Called from talloc compat1 " + "_talloc_reference"); +} + +void *_talloc_steal(const void *new_ctx, const void *ptr); +void *_talloc_steal(const void *new_ctx, const void *ptr) +{ + return talloc_reparent(talloc_parent(ptr), new_ctx, ptr); +} + +#undef talloc_free +int talloc_free(void *ptr); +int talloc_free(void *ptr) +{ + return talloc_unlink(talloc_parent(ptr), ptr); +} + diff --git a/lib/talloc/compat/talloc_compat1.mk b/lib/talloc/compat/talloc_compat1.mk new file mode 100644 index 0000000..d1817f0 --- /dev/null +++ b/lib/talloc/compat/talloc_compat1.mk @@ -0,0 +1,21 @@ +talloccompatdir := $(tallocdir)/compat + +TALLOC_COMPAT1_VERSION_MAJOR = 1 +TALLOC_COMPAT1_OBJ = $(talloccompatdir)/talloc_compat1.o + +TALLOC_COMPAT1_SOLIB = libtalloc-compat1-$(TALLOC_VERSION).$(SHLIBEXT) +TALLOC_COMPAT1_SONAME = libtalloc.$(SHLIBEXT).$(TALLOC_COMPAT1_VERSION_MAJOR) + +$(TALLOC_COMPAT1_SOLIB): $(TALLOC_COMPAT1_OBJ) $(TALLOC_SOLIB) + $(SHLD) $(SHLD_FLAGS) -o $@ $(TALLOC_COMPAT1_OBJ) \ + $(TALLOC_SOLIB) $(SONAMEFLAG)$(TALLOC_COMPAT1_SONAME) + +all:: $(TALLOC_COMPAT1_SOLIB) + +install:: + ${INSTALLCMD} -d $(DESTDIR)$(libdir) + ${INSTALLCMD} -m 755 $(TALLOC_COMPAT1_SOLIB) $(DESTDIR)$(libdir) + +clean:: + rm -f $(TALLOC_COMPAT1_OBJ) $(TALLOC_COMPAT1_SOLIB) + diff --git a/lib/talloc/configure b/lib/talloc/configure new file mode 100755 index 0000000..af76185 --- /dev/null +++ b/lib/talloc/configure @@ -0,0 +1,28 @@ +#!/bin/sh + +PREVPATH=$(dirname $0) + +if [ -f $PREVPATH/../../buildtools/bin/waf ]; then + WAF=../../buildtools/bin/waf +elif [ -f $PREVPATH/buildtools/bin/waf ]; then + WAF=./buildtools/bin/waf +else + echo "replace: Unable to find waf" + exit 1 +fi + +# using JOBS=1 gives maximum compatibility with +# systems like AIX which have broken threading in python +JOBS=1 +export JOBS + +# Make sure we don't have any library preloaded. +unset LD_PRELOAD + +# Make sure we get stable hashes +PYTHONHASHSEED=1 +export PYTHONHASHSEED + +cd . || exit 1 +$PYTHON $WAF configure "$@" || exit 1 +cd $PREVPATH diff --git a/lib/talloc/doc/context.png b/lib/talloc/doc/context.png Binary files differnew file mode 100644 index 0000000..48a6ca0 --- /dev/null +++ b/lib/talloc/doc/context.png diff --git a/lib/talloc/doc/context_tree.png b/lib/talloc/doc/context_tree.png Binary files differnew file mode 100644 index 0000000..9723459 --- /dev/null +++ b/lib/talloc/doc/context_tree.png diff --git a/lib/talloc/doc/mainpage.dox b/lib/talloc/doc/mainpage.dox new file mode 100644 index 0000000..ece6ccb --- /dev/null +++ b/lib/talloc/doc/mainpage.dox @@ -0,0 +1,111 @@ +/** + * @mainpage + * + * talloc is a hierarchical, reference counted memory pool system with + * destructors. It is the core memory allocator used in Samba. + * + * @section talloc_download Download + * + * You can download the latest releases of talloc from the + * <a href="http://samba.org/ftp/talloc" target="_blank">talloc directory</a> + * on the samba public source archive. + * + * @section main-tutorial Tutorial + * + * You should start by reading @subpage libtalloc_tutorial, then reading the documentation of + * the interesting functions as you go. + + * @section talloc_bugs Discussion and bug reports + * + * talloc does not currently have its own mailing list or bug tracking system. + * For now, please use the + * <a href="https://lists.samba.org/mailman/listinfo/samba-technical" target="_blank">samba-technical</a> + * mailing list, and the + * <a href="http://bugzilla.samba.org/" target="_blank">Samba bugzilla</a> + * bug tracking system. + * + * @section talloc_devel Development + * You can download the latest code either via git or rsync. + * + * To fetch via git see the following guide: + * + * <a href="http://wiki.samba.org/index.php/Using_Git_for_Samba_Development" target="_blank">Using Git for Samba Development</a> + * + * Once you have cloned the tree switch to the master branch and cd into the + * lib/tevent directory. + * + * To fetch via rsync use this command: + * + * rsync -Pavz samba.org::ftp/unpacked/standalone_projects/lib/talloc . + * + * @section talloc_preample Preamble + * + * talloc is a hierarchical, reference counted memory pool system with + * destructors. + * + * Perhaps the biggest difference from other memory pool systems is that there + * is no distinction between a "talloc context" and a "talloc pointer". Any + * pointer returned from talloc() is itself a valid talloc context. This means + * you can do this: + * + * @code + * struct foo *X = talloc(mem_ctx, struct foo); + * X->name = talloc_strdup(X, "foo"); + * @endcode + * + * The pointer X->name would be a "child" of the talloc context "X" which is + * itself a child of mem_ctx. So if you do talloc_free(mem_ctx) then it is all + * destroyed, whereas if you do talloc_free(X) then just X and X->name are + * destroyed, and if you do talloc_free(X->name) then just the name element of + * X is destroyed. + * + * If you think about this, then what this effectively gives you is an n-ary + * tree, where you can free any part of the tree with talloc_free(). + * + * If you find this confusing, then run the testsuite to watch talloc in + * action. You may also like to add your own tests to testsuite.c to clarify + * how some particular situation is handled. + * + * @section talloc_performance Performance + * + * All the additional features of talloc() over malloc() do come at a price. We + * have a simple performance test in Samba4 that measures talloc() versus + * malloc() performance, and it seems that talloc() is about 4% slower than + * malloc() on my x86 Debian Linux box. For Samba, the great reduction in code + * complexity that we get by using talloc makes this worthwhile, especially as + * the total overhead of talloc/malloc in Samba is already quite small. + * + * @section talloc_named Named blocks + * + * Every talloc chunk has a name that can be used as a dynamic type-checking + * system. If for some reason like a callback function you had to cast a + * "struct foo *" to a "void *" variable, later you can safely reassign the + * "void *" pointer to a "struct foo *" by using the talloc_get_type() or + * talloc_get_type_abort() macros. + * + * @code + * struct foo *X = talloc_get_type_abort(ptr, struct foo); + * @endcode + * + * This will abort if "ptr" does not contain a pointer that has been created + * with talloc(mem_ctx, struct foo). + * + * @section talloc_threading Multi-threading + * + * talloc itself does not deal with threads. It is thread-safe (assuming the + * underlying "malloc" is), as long as each thread uses different memory + * contexts. + * + * If two threads uses the same context then they need to synchronize in order + * to be safe. In particular: + * + * - when using talloc_enable_leak_report(), giving directly NULL as a parent + * context implicitly refers to a hidden "null context" global variable, so + * this should not be used in a multi-threaded environment without proper + * synchronization. In threaded code turn off null tracking using + * talloc_disable_null_tracking(). + * - the context returned by talloc_autofree_context() is also global so + * shouldn't be used by several threads simultaneously without + * synchronization. + * + */ diff --git a/lib/talloc/doc/stealing.png b/lib/talloc/doc/stealing.png Binary files differnew file mode 100644 index 0000000..8833e06 --- /dev/null +++ b/lib/talloc/doc/stealing.png diff --git a/lib/talloc/doc/tutorial_bestpractices.dox b/lib/talloc/doc/tutorial_bestpractices.dox new file mode 100644 index 0000000..3634446 --- /dev/null +++ b/lib/talloc/doc/tutorial_bestpractices.dox @@ -0,0 +1,192 @@ +/** +@page libtalloc_bestpractices Chapter 7: Best practises + +The following sections contain several best practices and good manners that were +found by the <a href="http://www.samba.org">Samba</a> and +<a href="https://fedorahosted.org/sssd">SSSD</a> developers over the years. +These will help you to write code which is better, easier to debug and with as +few (hopefully none) memory leaks as possible. + +@section bp-hierarchy Keep the context hierarchy steady + +The talloc is a hierarchy memory allocator. The hierarchy nature is what makes +the programming more error proof. It makes the memory easier to manage and to +free. Therefore, the first thing we should have on our mind is: always project +your data structures into the talloc context hierarchy. + +That means if we have a structure, we should always use it as a parent context +for its elements. This way we will not encounter any troubles when freeing the +structure or when changing its parent. The same rule applies for arrays. + +For example, the structure <code>user</code> from section @ref context-hierarchy +should be created with the context hierarchy illustrated on the next image. + +@image html context_tree.png + +@section bp-tmpctx Every function should use its own context + +It is a good practice to create a temporary talloc context at the function +beginning and free the context just before the return statement. All the data +must be allocated on this context or on its children. This ensures that no +memory leaks are created as long as we do not forget to free the temporary +context. + +This pattern applies to both situations - when a function does not return any +dynamically allocated value and when it does. However, it needs a little +extension for the latter case. + +@subsection bp-tmpctx-1 Functions that do not return any dynamically allocated +value + +If the function does not return any value created on the heap, we will just obey +the aforementioned pattern. + +@code +int bar() +{ + int ret; + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + ret = ENOMEM; + goto done; + } + /* allocate data on tmp_ctx or on its descendants */ + ret = EOK; +done: + talloc_free(tmp_ctx); + return ret; +} +@endcode + +@subsection bp-tmpctx-2 Functions returning dynamically allocated values + +If our function returns any dynamically allocated data, its first parameter +should always be the destination talloc context. This context serves as a parent +for the output values. But again, we will create the output values as the +descendants of the temporary context. If everything goes well, we will change +the parent of the output values from the temporary to the destination talloc +context. + +This pattern ensures that if an error occurs (e.g. I/O error or insufficient +amount of the memory), all allocated data is freed and no garbage appears on +the destination context. + +@code +int struct_foo_init(TALLOC_CTX *mem_ctx, struct foo **_foo) +{ + int ret; + struct foo *foo = NULL; + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + if (tmp_ctx == NULL) { + ret = ENOMEM; + goto done; + } + foo = talloc_zero(tmp_ctx, struct foo); + /* ... */ + *_foo = talloc_steal(mem_ctx, foo); + ret = EOK; +done: + talloc_free(tmp_ctx); + return ret; +} +@endcode + +@section bp-null Allocate temporary contexts on NULL + +As it can be seen on the previous listing, instead of allocating the temporary +context directly on <code>mem_ctx</code>, we created a new top level context +using <code>NULL</code> as the parameter for <code>talloc_new()</code> function. +Take a look at the following example: + +@code +char *create_user_filter(TALLOC_CTX *mem_ctx, + uid_t uid, const char *username) +{ + char *filter = NULL; + char *sanitized_username = NULL; + /* tmp_ctx is a child of mem_ctx */ + TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx); + if (tmp_ctx == NULL) { + return NULL; + } + + sanitized_username = sanitize_string(tmp_ctx, username); + if (sanitized_username == NULL) { + talloc_free(tmp_ctx); + return NULL; + } + + filter = talloc_aprintf(tmp_ctx,"(|(uid=%llu)(uname=%s))", + uid, sanitized_username); + if (filter == NULL) { + return NULL; /* tmp_ctx is not freed */ (*@\label{lst:tmp-ctx-3:leak}@*) + } + + /* filter becomes a child of mem_ctx */ + filter = talloc_steal(mem_ctx, filter); + talloc_free(tmp_ctx); + return filter; +} +@endcode + +We forgot to free <code>tmp_ctx</code> before the <code>return</code> statement +in the <code>filter == NULL</code> condition. However, it is created as a child +of <code>mem_ctx</code> context and as such it will be freed as soon as the +<code>mem_ctx</code> is freed. Therefore, no detectable memory leak is created. + +On the other hand, we do not have any way to access the allocated data +and for all we know <code>mem_ctx</code> may exist for the lifetime of our +application. For these reasons this should be considered as a memory leak. How +can we detect if it is unreferenced but still attached to its parent context? +The only way is to notice the mistake in the source code. + +But if we create the temporary context as a top level context, it will not be +freed and memory diagnostic tools +(e.g. <a href="http://valgrind.org">valgrind</a>) are able to do their job. + +@section bp-pool Temporary contexts and the talloc pool + +If we want to take the advantage of the talloc pool but also keep to the +pattern introduced in the previous section, we are unable to do it directly. The +best thing to do is to create a conditional build where we can decide how do we +want to create the temporary context. For example, we can create the following +macros: + +@code +#ifdef USE_POOL_CONTEXT + #define CREATE_POOL_CTX(ctx, size) talloc_pool(ctx, size) + #define CREATE_TMP_CTX(ctx) talloc_new(ctx) +#else + #define CREATE_POOL_CTX(ctx, size) talloc_new(ctx) + #define CREATE_TMP_CTX(ctx) talloc_new(NULL) +#endif +@endcode + +Now if our application is under development, we will build it with macro +<code>USE_POOL_CONTEXT</code> undefined. This way, we can use memory diagnostic +utilities to detect memory leaks. + +The release version will be compiled with the macro defined. This will enable +pool contexts and therefore reduce the <code>malloc()</code> calls, which will +end up in a little bit faster processing. + +@code +int struct_foo_init(TALLOC_CTX *mem_ctx, struct foo **_foo) +{ + int ret; + struct foo *foo = NULL; + TALLOC_CTX *tmp_ctx = CREATE_TMP_CTX(mem_ctx); + /* ... */ +} + +errno_t handle_request(TALLOC_CTX mem_ctx) +{ + int ret; + struct foo *foo = NULL; + TALLOC_CTX *pool_ctx = CREATE_POOL_CTX(NULL, 1024); + ret = struct_foo_init(mem_ctx, &foo); + /* ... */ +} +@endcode + +*/ diff --git a/lib/talloc/doc/tutorial_context.dox b/lib/talloc/doc/tutorial_context.dox new file mode 100644 index 0000000..b8bfe26 --- /dev/null +++ b/lib/talloc/doc/tutorial_context.dox @@ -0,0 +1,198 @@ +/** +@page libtalloc_context Chapter 1: Talloc context +@section context Talloc context + +The talloc context is the most important part of this library and is +responsible for every single feature of this memory allocator. It is a logical +unit which represents a memory space managed by talloc. + +From the programmer's point of view, the talloc context is completely +equivalent to a pointer that would be returned by the memory routines from the +C standard library. This means that every context that is returned from the +talloc library can be used directly in functions that do not use talloc +internally. For example we can do the following: + +@code +char *str1 = strdup("I am NOT a talloc context"); +char *str2 = talloc_strdup(NULL, "I AM a talloc context"); + +printf("%d\n", strcmp(str1, str2) == 0); + +free(str1); +talloc_free(str2); /* we can not use free() on str2 */ +@endcode + +This is possible because the context is internally handled as a special +fixed-length structure called talloc chunk. Each chunk stores context metadata +followed by the memory space requested by the programmer. When a talloc +function returns a context (pointer), it will in fact return a pointer to the user +space portion of the talloc chunk. If we to manipulate this context using +talloc functions, the talloc library transforms the user-space pointer back to +the starting address of the chunk. This is also the reason why we were unable +to use <code>free(str2)</code> in the previous example - because +<code>str2</code> does not point at the beginning of the allocated block of +memory. This is illustrated on the next image: + +@image html context.png + +The type TALLOC_CTX is defined in talloc.h to identify a talloc context in +function parameters. However, this type is just an alias for <code>void</code> +and exists only for semantical reasons - thus we can differentiate between +<code>void *</code> (arbitrary data) and <code>TALLOC_CTX *</code> (talloc +context). + +@subsection metadata Context meta data + +Every talloc context carries several pieces of internal information along with +the allocated memory: + + - name - which is used in reports of context hierarchy and to simulate + a dynamic type system, + - size of the requested memory in bytes - this can be used to determine + the number of elements in arrays, + - attached destructor - which is executed just before the memory block is + about to be freed, + - references to the context + - children and parent contexts - create the hierarchical view on the + memory. + +@section context-hierarchy Hierarchy of talloc context + +Every talloc context contains information about its parent and children. Talloc +uses this information to create a hierarchical model of memory or to be more +precise, it creates an n-ary tree where each node represents a single talloc +context. The root node of the tree is referred to as a top level context - a +context without any parent. + +This approach has several advantages: + + - as a consequence of freeing a talloc context, all of its children + will be properly deallocated as well, + - the parent of a context can be changed at any time, which + results in moving the whole subtree under another node, + - it creates a more natural way of managing data structures. + +@subsection Example + +We have a structure that stores basic information about a user - his/her name, +identification number and groups he/she is a member of: + +@code +struct user { + uid_t uid; + char *username; + size_t num_groups; + char **groups; +}; +@endcode + +We will allocate this structure using talloc. The result will be the following +context tree: + +@image html context_tree.png + +@code +/* create new top level context */ +struct user *user = talloc(NULL, struct user); + +user->uid = 1000; +user->num_groups = N; + +/* make user the parent of following contexts */ +user->username = talloc_strdup(user, "Test user"); +user->groups = talloc_array(user, char*, user->num_groups); + +for (i = 0; i < user->num_groups; i++) { + /* make user->groups the parent of following context */ + user->groups[i] = talloc_asprintf(user->groups, + "Test group %d", i); +} +@endcode + +This way, we have gained a lot of additional capabilities, one of which is +very simple deallocation of the structure and all of its elements. + +With the C standard library we need first to iterate over the array of groups +and free every element separately. Then we must deallocate the array that stores +them. Next we deallocate the username and as the last step free the structure +itself. But with talloc, the only operation we need to execute is freeing the +structure context. Its descendants will be freed automatically. + +@code +talloc_free(user); +@endcode + +@section keep-hierarchy Always keep the hieararchy steady! + +The talloc is a hierarchy memory allocator. The hierarchy nature is what makes +the programming more error proof. It makes the memory easier to manage and to +free. Therefore, the first thing we should have on our mind is: <strong>always +project our data structures into the talloc context hierarchy</strong>. + +That means if we have a structure, we should always use it as a parent context +for its elements. This way we will not encounter any troubles when freeing this +structure or when changing its parent. The same rule applies for arrays. + +@section creating-context Creating a talloc context + +Here are the most important functions that create a new talloc context. + +@subsection type-safe Type-safe functions + +It allocates the size that is necessary for the given type and returns a new, +properly-casted pointer. This is the preferred way to create a new context as +we can rely on the compiler to detect type mismatches. + +The name of the context is automatically set to the name of the data type which +is used to simulate a dynamic type system. + +@code +struct user *user = talloc(ctx, struct user); + +/* initialize to default values */ +user->uid = 0; +user->name = NULL; +user->num_groups = 0; +user->groups = NULL; + +/* or we can achieve the same result with */ +struct user *user_zero = talloc_zero(ctx, struct user); +@endcode + +@subsection zero-length Zero-length contexts + +The zero-length context is basically a context without any special semantical +meaning. We can use it the same way as any other context. The only difference +is that it consists only of the meta data about the context. Therefore, it is +strictly of type <code>TALLOC_CTX*</code>. It is often used in cases where we +want to aggregate several data structures under one parent (zero-length) +context, such as a temporary context to contain memory needed within a single +function that is not interesting to the caller. Allocating on a zero-length +temporary context will make clean-up of the function simpler. + +@code +TALLOC_CTX *tmp_ctx = NULL; +struct foo *foo = NULL; +struct bar *bar = NULL; + +/* new zero-length top level context */ +tmp_ctx = talloc_new(NULL); +if (tmp_ctx == NULL) { + return ENOMEM; +} + +foo = talloc(tmp_ctx, struct foo); +bar = talloc(tmp_ctx, struct bar); + +/* free everything at once */ +talloc_free(tmp_ctx); +@endcode + +@subsection context-see-also See also + +- talloc_size() +- talloc_named() +- @ref talloc_array +- @ref talloc_string + +*/ diff --git a/lib/talloc/doc/tutorial_debugging.dox b/lib/talloc/doc/tutorial_debugging.dox new file mode 100644 index 0000000..aadbb0d --- /dev/null +++ b/lib/talloc/doc/tutorial_debugging.dox @@ -0,0 +1,116 @@ +/** +@page libtalloc_debugging Chapter 6: Debugging + +Although talloc makes memory management significantly easier than the C standard +library, developers are still only humans and can make mistakes. Therefore, it +can be handy to know some tools for the inspection of talloc memory usage. + +@section log-abort Talloc log and abort + +We have already encountered the abort function in section @ref dts. +In that case it was used when a type mismatch was detected. However, talloc +calls this abort function in several more situations: + +- when the provided pointer is not a valid talloc context, +- when the meta data is invalid - probably due to memory corruption, +- and when an access after free is detected. + +The third one is probably the most interesting. It can help us with detecting +an attempt to double-free a context or any other manipulation with it via +talloc functions (using it as a parent, stealing it, etc.). + +Before the context is freed talloc sets a flag in the meta data. This is then +used to detect the access after free. It basically works on the assumption that +the memory stays unchanged (at least for a while) even when it is properly +deallocated. This will work even if the memory is filled with the value +specified in <code>TALLOC_FREE_FILL</code> environment variable, because it +fills only the data part and leaves the meta data intact. + +Apart from the abort function, talloc uses a log function to provide additional +information to the aforementioned violations. To enable logging we shall set the +log function with one of: + +- talloc_set_log_fn() +- talloc_set_log_stderr() + +The following code is a sample output of accessing a context after it has been +freed: + +@code +talloc_set_log_stderr(); +TALLOC_CTX *ctx = talloc_new(NULL); + +talloc_free(ctx); +talloc_free(ctx); + +results in: +talloc: access after free error - first free may be at ../src/main.c:55 +Bad talloc magic value - access after free +@endcode + +Another example is an invalid context: + +@code +talloc_set_log_stderr(); +TALLOC_CTX *ctx = talloc_new(NULL); +char *str = strdup("not a talloc context"); +talloc_steal(ctx, str); + +results in: +Bad talloc magic value - unknown value +@endcode + +@section reports Memory usage reports + +Talloc can print reports of memory usage of a specified talloc context to a +file (to <code>stdout</code> or <code>stderr</code>). The report can be +simple or full. The simple report provides information only about the context +itself and its direct descendants. The full report goes recursively through the +entire context tree. See: + +- talloc_report() +- talloc_report_full() + +We will use the following code to retrieve the sample report: + +@code +struct foo { + char *str; +}; + +TALLOC_CTX *ctx = talloc_new(NULL); +char *str = talloc_strdup(ctx, "my string"); +struct foo *foo = talloc_zero(ctx, struct foo); +foo->str = talloc_strdup(foo, "I am Foo"); +char *str2 = talloc_strdup(foo, "Foo is my parent"); + +/* print full report */ +talloc_report_full(ctx, stdout); +@endcode + +It will print a full report of <code>ctx</code> to the standard output. +The message should be similar to: + +@code +full talloc report on 'talloc_new: ../src/main.c:82' (total 46 bytes in 5 blocks) + struct foo contains 34 bytes in 3 blocks (ref 0) 0x1495130 + Foo is my parent contains 17 bytes in 1 blocks (ref 0) 0x1495200 + I am Foo contains 9 bytes in 1 blocks (ref 0) 0x1495190 + my string contains 10 bytes in 1 blocks (ref 0) 0x14950c0 +@endcode + +We can notice in this report that something is wrong with the context containing +<code>struct foo</code>. We know that the structure has only one string element. +However, we can see in the report that it has two children. This indicates that +we have either violated the memory hierarchy or forgotten to free it as +temporary data. Looking into the code, we can see that <code>"Foo is my parent" +</code> should be attached to <code>ctx</code>. + +See also: + +- talloc_enable_null_tracking() +- talloc_disable_null_tracking() +- talloc_enable_leak_report() +- talloc_enable_leak_report_full() + +*/ diff --git a/lib/talloc/doc/tutorial_destructors.dox b/lib/talloc/doc/tutorial_destructors.dox new file mode 100644 index 0000000..ed06387 --- /dev/null +++ b/lib/talloc/doc/tutorial_destructors.dox @@ -0,0 +1,82 @@ +/** +@page libtalloc_destructors Chapter 4: Using destructors + +@section destructors Using destructors + +Destructors are well known methods in the world of object oriented programming. +A destructor is a method of an object that is automatically run when the object +is destroyed. It is usually used to return resources taken by the object back to +the system (e.g. closing file descriptors, terminating connection to a database, +deallocating memory). + +With talloc we can take the advantage of destructors even in C. We can easily +attach our own destructor to a talloc context. When the context is freed, the +destructor will run automatically. + +To attach/detach a destructor to a talloc context use: talloc_set_destructor(). + +@section destructors-example Example + +Imagine that we have a dynamically created linked list. Before we deallocate an +element of the list, we need to make sure that we have successfully removed it +from the list. Normally, this would be done by two commands in the exact order: +remove it from the list and then free the element. With talloc, we can do this +at once by setting a destructor on the element which will remove it from the +list and talloc_free() will do the rest. + +The destructor would be: + +@code +int list_remove(void *ctx) +{ + struct list_el *el = NULL; + el = talloc_get_type_abort(ctx, struct list_el); + /* remove element from the list */ +} +@endcode + +GCC version 3 and newer can check for the types during the compilation. So if +it is our major compiler, we can use a more advanced destructor: + +@code +int list_remove(struct list_el *el) +{ + /* remove element from the list */ +} +@endcode + +Now we will assign the destructor to the list element. We can do this directly +in the function that inserts it. + +@code +struct list_el* list_insert(TALLOC_CTX *mem_ctx, + struct list_el *where, + void *ptr) +{ + struct list_el *el = talloc(mem_ctx, struct list_el); + el->data = ptr; + /* insert into list */ + + talloc_set_destructor(el, list_remove); + return el; +} +@endcode + +Because talloc is a hierarchical memory allocator, we can go a step further and +free the data with the element as well: + +@code +struct list_el* list_insert_free(TALLOC_CTX *mem_ctx, + struct list_el *where, + void *ptr) +{ + struct list_el *el = NULL; + el = list_insert(mem_ctx, where, ptr); + + talloc_steal(el, ptr); + + return el; +} +@endcode + +*/ diff --git a/lib/talloc/doc/tutorial_dts.dox b/lib/talloc/doc/tutorial_dts.dox new file mode 100644 index 0000000..75b5172 --- /dev/null +++ b/lib/talloc/doc/tutorial_dts.dox @@ -0,0 +1,109 @@ +/** +@page libtalloc_dts Chapter 3: Dynamic type system + +@section dts Dynamic type system + +Generic programming in the C language is very difficult. There is no inheritance +nor templates known from object oriented languages. There is no dynamic type +system. Therefore, generic programming in this language is usually done by +type-casting a variable to <code>void*</code> and transferring it through +a generic function to a specialized callback as illustrated on the next listing. + +@code +void generic_function(callback_fn cb, void *pvt) +{ + /* do some stuff and call the callback */ + cb(pvt); +} + +void specific_callback(void *pvt) +{ + struct specific_struct *data; + data = (struct specific_struct*)pvt; + /* ... */ +} + +void specific_function() +{ + struct specific_struct data; + generic_function(callback, &data); +} +@endcode + +Unfortunately, the type information is lost as a result of this type cast. The +compiler cannot check the type during the compilation nor are we able to do it +at runtime. Providing an invalid data type to the callback will result in +unexpected behaviour (not necessarily a crash) of the application. This mistake +is usually hard to detect because it is not the first thing which comes the +mind. + +As we already know, every talloc context contains a name. This name is available +at any time and it can be used to determine the type of a context even if we +lose the type of a variable. + +Although the name of the context can be set to any arbitrary string, the best +way of using it to simulate the dynamic type system is to set it directly to the +type of the variable. + +It is recommended to use one of talloc() and talloc_array() (or its +variants) to create the context as they set its name to the name of the +given type automatically. + +If we have a context with such as a name, we can use two similar functions that +do both the type check and the type cast for us: + +- talloc_get_type() +- talloc_get_type_abort() + +@section dts-examples Examples + +The following example will show how generic programming with talloc is handled - +if we provide invalid data to the callback, the program will be aborted. This +is a sufficient reaction for such an error in most applications. + +@code +void foo_callback(void *pvt) +{ + struct foo *data = talloc_get_type_abort(pvt, struct foo); + /* ... */ +} + +int do_foo() +{ + struct foo *data = talloc_zero(NULL, struct foo); + /* ... */ + return generic_function(foo_callback, data); +} +@endcode + +But what if we are creating a service application that should be running for the +uptime of a server, we may want to abort the application during the development +process (to make sure the error is not overlooked) and try to recover from the +error in the customer release. This can be achieved by creating a custom abort +function with a conditional build. + +@code +void my_abort(const char *reason) +{ + fprintf(stderr, "talloc abort: %s\n", reason); +#ifdef ABORT_ON_TYPE_MISMATCH + abort(); +#endif +} +@endcode + +The usage of talloc_get_type_abort() would be then: + +@code +talloc_set_abort_fn(my_abort); + +TALLOC_CTX *ctx = talloc_new(NULL); +char *str = talloc_get_type_abort(ctx, char); +if (str == NULL) { + /* recovery code */ +} +/* talloc abort: ../src/main.c:25: Type mismatch: + name[talloc_new: ../src/main.c:24] expected[char] */ +@endcode + +*/ diff --git a/lib/talloc/doc/tutorial_introduction.dox b/lib/talloc/doc/tutorial_introduction.dox new file mode 100644 index 0000000..418c38b --- /dev/null +++ b/lib/talloc/doc/tutorial_introduction.dox @@ -0,0 +1,45 @@ +/** +@page libtalloc_tutorial The Tutorial +@section introduction Introduction + +Talloc is a hierarchical, reference counted memory pool system with destructors. +It is built atop the C standard library and it defines a set of utility +functions that altogether simplifies allocation and deallocation of data, +especially for complex structures that contain many dynamically allocated +elements such as strings and arrays. + +The main goals of this library are: removing the needs for creating a cleanup +function for every complex structure, providing a logical organization of +allocated memory blocks and reducing the likelihood of creating memory leaks in +long-running applications. All of this is achieved by allocating memory in a +hierarchical structure of talloc contexts such that deallocating one context +recursively frees all of its descendants as well. + +@section main-features Main features +- An open source project +- A hierarchical memory model +- Natural projection of data structures into the memory space +- Simplifies memory management of large data structures +- Automatic execution of a destructor before the memory is freed +- Simulates a dynamic type system +- Implements a transparent memory pool + +@section toc Table of contents: + +@subpage libtalloc_context + +@subpage libtalloc_stealing + +@subpage libtalloc_dts + +@subpage libtalloc_destructors + +@subpage libtalloc_pools + +@subpage libtalloc_debugging + +@subpage libtalloc_bestpractices + +@subpage libtalloc_threads + +*/ diff --git a/lib/talloc/doc/tutorial_pools.dox b/lib/talloc/doc/tutorial_pools.dox new file mode 100644 index 0000000..a0d1e1a --- /dev/null +++ b/lib/talloc/doc/tutorial_pools.dox @@ -0,0 +1,93 @@ +/** +@page libtalloc_pools Chapter 5: Memory pools + +@section pools Memory pools + +Allocation of a new memory is an expensive operation and large programs can +contain thousands of calls of malloc() for a single computation, where every +call allocates only a very small amount of the memory. This can result in an +undesirable slowdown of the application. We can avoid this slowdown by +decreasing the number of malloc() calls by using a memory pool. + +A memory pool is a preallocated memory space with a fixed size. If we need to +allocate new data we will take the desired amount of the memory from the pool +instead of requesting a new memory from the system. This is done by creating a +pointer that points inside the preallocated memory. Such a pool must not be +reallocated as it would change its location - pointers that were pointing +inside the pool would become invalid. Therefore, a memory pool requires a very +good estimate of the required memory space. + +The talloc library contains its own implementation of a memory pool. It is +highly transparent for the programmer. The only thing that needs to be done is +an initialization of a new pool context using talloc_pool() - +which can be used in the same way as any other context. + +Refactoring of existing code (that uses talloc) to take the advantage of a +memory pool is quite simple due to the following properties of the pool context: + +- if we are allocating data on a pool context, it takes the desired + amount of memory from the pool, +- if the context is a descendant of the pool context, it takes the space + from the pool as well, +- if the pool does not have sufficient portion of memory left, it will + create a new non-pool context, leaving the pool intact + +@code +/* allocate 1KiB in a pool */ +TALLOC_CTX *pool_ctx = talloc_pool(NULL, 1024); + +/* Take 512B from the pool, 512B is left there */ +void *ptr = talloc_size(pool_ctx, 512); + +/* 1024B > 512B, this will create new talloc chunk outside + the pool */ +void *ptr2 = talloc_size(ptr, 1024); + +/* The pool still contains 512 free bytes + * this will take 200B from them. */ +void *ptr3 = talloc_size(ptr, 200); + +/* This will destroy context 'ptr3' but the memory + * is not freed, the available space in the pool + * will increase to 512B. */ +talloc_free(ptr3); + +/* This will free memory taken by 'pool_ctx' + * and 'ptr2' as well. */ +talloc_free(pool_ctx); +@endcode + +The above given is very convenient, but there is one big issue to be kept in +mind. If the parent of a talloc pool child is changed to a parent that is +outside of this pool, the whole pool memory will not be freed until the child is +freed. For this reason we must be very careful when stealing a descendant of a +pool context. + +@code +TALLOC_CTX *mem_ctx = talloc_new(NULL); +TALLOC_CTX *pool_ctx = talloc_pool(NULL, 1024); +struct foo *foo = talloc(pool_ctx, struct foo); + +/* mem_ctx is not in the pool */ +talloc_steal(mem_ctx, foo); + +/* pool_ctx is marked as freed but the memory is not + deallocated, accessing the pool_ctx again will cause + an error */ +talloc_free(pool_ctx); + +/* This deallocates the pool_ctx. */ +talloc_free(mem_ctx); +@endcode + +It may often be better to copy the memory we want instead of stealing it to +avoid this problem. If we do not need to retain the context name (to keep the +type information), we can use talloc_memdup() to do this. + +Copying the memory out of the pool may, however, discard all the performance +boost given by the pool, depending on the size of the copied memory. Therefore, +the code should be well profiled before taking this path. In general, the +golden rule is: if we need to steal from the pool context, we should not +use a pool context. + +*/ diff --git a/lib/talloc/doc/tutorial_stealing.dox b/lib/talloc/doc/tutorial_stealing.dox new file mode 100644 index 0000000..67eae1d --- /dev/null +++ b/lib/talloc/doc/tutorial_stealing.dox @@ -0,0 +1,55 @@ +/** +@page libtalloc_stealing Chapter 2: Stealing a context + +@section stealing Stealing a context + +Talloc has the ability to change the parent of a talloc context to another +one. This operation is commonly referred to as stealing and it is one of +the most important actions performed with talloc contexts. + +Stealing a context is necessary if we want the pointer to outlive the context it +is created on. This has many possible use cases, for instance stealing a result +of a database search to an in-memory cache context, changing the parent of a +field of a generic structure to a more specific one or vice-versa. The most +common scenario, at least in Samba, is to steal output data from a function-specific +context to the output context given as an argument of that function. + +@code +struct foo { + char *a1; + char *a2; + char *a3; +}; + +struct bar { + char *wurst; + struct foo *foo; +}; + +struct foo *foo = talloc_zero(ctx, struct foo); +foo->a1 = talloc_strdup(foo, "a1"); +foo->a2 = talloc_strdup(foo, "a2"); +foo->a3 = talloc_strdup(foo, "a3"); + +struct bar *bar = talloc_zero(NULL, struct bar); +/* change parent of foo from ctx to bar */ +bar->foo = talloc_steal(bar, foo); + +/* or do the same but assign foo = NULL */ +bar->foo = talloc_move(bar, &foo); +@endcode + +The talloc_move() function is similar to the talloc_steal() function but +additionally sets the source pointer to NULL. + +In general, the source pointer itself is not changed (it only replaces the +parent in the meta data). But the common usage is that the result is +assigned to another variable, thus further accessing the pointer from the +original variable should be avoided unless it is necessary. In this case +talloc_move() is the preferred way of stealing a context. Additionally sets the +source pointer to NULL, thus.protects the pointer from being accidentally freed +and accessed using the old variable after its parent has been changed. + +@image html stealing.png + +*/ diff --git a/lib/talloc/doc/tutorial_threads.dox b/lib/talloc/doc/tutorial_threads.dox new file mode 100644 index 0000000..111bbf5 --- /dev/null +++ b/lib/talloc/doc/tutorial_threads.dox @@ -0,0 +1,203 @@ +/** +@page libtalloc_threads Chapter 8: Using threads with talloc + +@section Talloc and thread safety + +The talloc library is not internally thread-safe, in that accesses +to variables on a talloc context are not controlled by mutexes or +other thread-safe primitives. + +However, so long as talloc_disable_null_tracking() is called from +the main thread to disable global variable access within talloc, +then each thread can safely use its own top level talloc context +allocated off the NULL context. + +For example: + +@code +static void *thread_fn(void *arg) +{ + const char *ctx_name = (const char *)arg; + /* + * Create a new top level talloc hierarchy in + * this thread. + */ + void *top_ctx = talloc_named_const(NULL, 0, "top"); + if (top_ctx == NULL) { + return NULL; + } + sub_ctx = talloc_named_const(top_ctx, 100, ctx_name); + if (sub_ctx == NULL) { + return NULL; + } + + /* + * Do more processing/talloc calls on top_ctx + * and its children. + */ + ...... + + talloc_free(top_ctx); + return value; +} +@endcode + +is a perfectly safe use of talloc within a thread. + +The problem comes when one thread wishes to move some +memory allocated on its local top level talloc context +to another thread. Care must be taken to add data access +exclusion to prevent memory corruption. One method would +be to lock a mutex before any talloc call on each thread, +but this would push the burden of total talloc thread-safety +on the poor user of the library. + +A much easier way to transfer talloced memory between +threads is by the use of an intermediate, mutex locked, +intermediate variable. + +An example of this is below - taken from test code inside +the talloc testsuite. + +The main thread creates 1000 sub-threads, and then accepts +the transfer of some thread-talloc'ed memory onto its top +level context from each thread in turn. + +A pthread mutex and condition variable are used to +synchronize the transfer via the intermediate_ptr +variable. + +@code +/* Required sync variables. */ +static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t condvar = PTHREAD_COND_INITIALIZER; + +/* Intermediate talloc pointer for transfer. */ +static void *intermediate_ptr; + +/* Subthread. */ +static void *thread_fn(void *arg) +{ + int ret; + const char *ctx_name = (const char *)arg; + void *sub_ctx = NULL; + /* + * Do stuff that creates a new talloc hierarchy in + * this thread. + */ + void *top_ctx = talloc_named_const(NULL, 0, "top"); + if (top_ctx == NULL) { + return NULL; + } + sub_ctx = talloc_named_const(top_ctx, 100, ctx_name); + if (sub_ctx == NULL) { + return NULL; + } + + /* + * Now transfer a pointer from our hierarchy + * onto the intermediate ptr. + */ + ret = pthread_mutex_lock(&mtx); + if (ret != 0) { + talloc_free(top_ctx); + return NULL; + } + + /* Wait for intermediate_ptr to be free. */ + while (intermediate_ptr != NULL) { + ret = pthread_cond_wait(&condvar, &mtx); + if (ret != 0) { + talloc_free(top_ctx); + return NULL; + } + } + + /* and move our memory onto it from our toplevel hierarchy. */ + intermediate_ptr = talloc_move(NULL, &sub_ctx); + + /* Tell the main thread it's ready for pickup. */ + pthread_cond_broadcast(&condvar); + pthread_mutex_unlock(&mtx); + + talloc_free(top_ctx); + return NULL; +} + +/* Main thread. */ + +#define NUM_THREADS 1000 + +static bool test_pthread_talloc_passing(void) +{ + int i; + int ret; + char str_array[NUM_THREADS][20]; + pthread_t thread_id; + void *mem_ctx; + + /* + * Important ! Null tracking breaks threaded talloc. + * It *must* be turned off. + */ + talloc_disable_null_tracking(); + + /* Main thread toplevel context. */ + mem_ctx = talloc_named_const(NULL, 0, "toplevel"); + if (mem_ctx == NULL) { + return false; + } + + /* + * Spin off NUM_THREADS threads. + * They will use their own toplevel contexts. + */ + for (i = 0; i < NUM_THREADS; i++) { + (void)snprintf(str_array[i], + 20, + "thread:%d", + i); + if (str_array[i] == NULL) { + return false; + } + ret = pthread_create(&thread_id, + NULL, + thread_fn, + str_array[i]); + if (ret != 0) { + return false; + } + } + + /* Now wait for NUM_THREADS transfers of the talloc'ed memory. */ + for (i = 0; i < NUM_THREADS; i++) { + ret = pthread_mutex_lock(&mtx); + if (ret != 0) { + talloc_free(mem_ctx); + return false; + } + + /* Wait for intermediate_ptr to have our data. */ + while (intermediate_ptr == NULL) { + ret = pthread_cond_wait(&condvar, &mtx); + if (ret != 0) { + talloc_free(mem_ctx); + return false; + } + } + + /* and move it onto our toplevel hierarchy. */ + (void)talloc_move(mem_ctx, &intermediate_ptr); + + /* Tell the sub-threads we're ready for another. */ + pthread_cond_broadcast(&condvar); + pthread_mutex_unlock(&mtx); + } + + /* Dump the hierarchy. */ + talloc_report(mem_ctx, stdout); + talloc_free(mem_ctx); + return true; +} +@endcode +*/ diff --git a/lib/talloc/doxy.config b/lib/talloc/doxy.config new file mode 100644 index 0000000..0e27d61 --- /dev/null +++ b/lib/talloc/doxy.config @@ -0,0 +1,1807 @@ +# Doxyfile 1.8.0 + +# This file describes the settings to be used by the documentation system +# doxygen (www.doxygen.org) for a project. +# +# All text after a hash (#) is considered a comment and will be ignored. +# The format is: +# TAG = value [value, ...] +# For lists items can also be appended using: +# TAG += value [value, ...] +# Values that contain spaces should be placed between quotes (" "). + +#--------------------------------------------------------------------------- +# Project related configuration options +#--------------------------------------------------------------------------- + +# This tag specifies the encoding used for all characters in the config file +# that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# http://www.gnu.org/software/libiconv for the list of possible encodings. + +DOXYFILE_ENCODING = UTF-8 + +# The PROJECT_NAME tag is a single word (or sequence of words) that should +# identify the project. Note that if you do not use Doxywizard you need +# to put quotes around the project name if it contains spaces. + +PROJECT_NAME = talloc + +# The PROJECT_NUMBER tag can be used to enter a project or revision number. +# This could be handy for archiving the generated documentation or +# if some version control system is used. + +PROJECT_NUMBER = 2.0 + +# Using the PROJECT_BRIEF tag one can provide an optional one line description +# for a project that appears at the top of each page and should give viewer +# a quick idea about the purpose of the project. Keep the description short. + +PROJECT_BRIEF = + +# With the PROJECT_LOGO tag one can specify an logo or icon that is +# included in the documentation. The maximum height of the logo should not +# exceed 55 pixels and the maximum width should not exceed 200 pixels. +# Doxygen will copy the logo to the output directory. + +PROJECT_LOGO = + +# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) +# base path where the generated documentation will be put. +# If a relative path is entered, it will be relative to the location +# where doxygen was started. If left blank the current directory will be used. + +OUTPUT_DIRECTORY = doc + +# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create +# 4096 sub-directories (in 2 levels) under the output directory of each output +# format and will distribute the generated files over these directories. +# Enabling this option can be useful when feeding doxygen a huge amount of +# source files, where putting all generated files in the same directory would +# otherwise cause performance problems for the file system. + +CREATE_SUBDIRS = NO + +# The OUTPUT_LANGUAGE tag is used to specify the language in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all constant output in the proper language. +# The default language is English, other supported languages are: +# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional, +# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German, +# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English +# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian, +# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, +# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese. + +OUTPUT_LANGUAGE = English + +# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will +# include brief member descriptions after the members that are listed in +# the file and class documentation (similar to JavaDoc). +# Set to NO to disable this. + +BRIEF_MEMBER_DESC = YES + +# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend +# the brief description of a member or function before the detailed description. +# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the +# brief descriptions will be completely suppressed. + +REPEAT_BRIEF = YES + +# This tag implements a quasi-intelligent brief description abbreviator +# that is used to form the text in various listings. Each string +# in this list, if found as the leading text of the brief description, will be +# stripped from the text and the result after processing the whole list, is +# used as the annotated text. Otherwise, the brief description is used as-is. +# If left blank, the following values are used ("$name" is automatically +# replaced with the name of the entity): "The $name class" "The $name widget" +# "The $name file" "is" "provides" "specifies" "contains" +# "represents" "a" "an" "the" + +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the + +# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then +# Doxygen will generate a detailed section even if there is only a brief +# description. + +ALWAYS_DETAILED_SEC = NO + +# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all +# inherited members of a class in the documentation of that class as if those +# members were ordinary class members. Constructors, destructors and assignment +# operators of the base classes will not be shown. + +INLINE_INHERITED_MEMB = NO + +# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full +# path before files name in the file list and in the header files. If set +# to NO the shortest path that makes the file name unique will be used. + +FULL_PATH_NAMES = YES + +# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag +# can be used to strip a user-defined part of the path. Stripping is +# only done if one of the specified strings matches the left-hand part of +# the path. The tag can be used to show relative paths in the file list. +# If left blank the directory from which doxygen is run is used as the +# path to strip. + +STRIP_FROM_PATH = + +# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of +# the path mentioned in the documentation of a class, which tells +# the reader which header file to include in order to use a class. +# If left blank only the name of the header file containing the class +# definition is used. Otherwise one should specify the include paths that +# are normally passed to the compiler using the -I flag. + +STRIP_FROM_INC_PATH = + +# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter +# (but less readable) file names. This can be useful if your file system +# doesn't support long names like on DOS, Mac, or CD-ROM. + +SHORT_NAMES = NO + +# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen +# will interpret the first line (until the first dot) of a JavaDoc-style +# comment as the brief description. If set to NO, the JavaDoc +# comments will behave just like regular Qt-style comments +# (thus requiring an explicit @brief command for a brief description.) + +JAVADOC_AUTOBRIEF = YES + +# If the QT_AUTOBRIEF tag is set to YES then Doxygen will +# interpret the first line (until the first dot) of a Qt-style +# comment as the brief description. If set to NO, the comments +# will behave just like regular Qt-style comments (thus requiring +# an explicit \brief command for a brief description.) + +QT_AUTOBRIEF = NO + +# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen +# treat a multi-line C++ special comment block (i.e. a block of //! or /// +# comments) as a brief description. This used to be the default behaviour. +# The new default is to treat a multi-line C++ comment block as a detailed +# description. Set this tag to YES if you prefer the old behaviour instead. + +MULTILINE_CPP_IS_BRIEF = NO + +# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented +# member inherits the documentation from any documented member that it +# re-implements. + +INHERIT_DOCS = YES + +# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce +# a new page for each member. If set to NO, the documentation of a member will +# be part of the file/class/namespace that contains it. + +SEPARATE_MEMBER_PAGES = NO + +# The TAB_SIZE tag can be used to set the number of spaces in a tab. +# Doxygen uses this value to replace tabs by spaces in code fragments. + +TAB_SIZE = 8 + +# This tag can be used to specify a number of aliases that acts +# as commands in the documentation. An alias has the form "name=value". +# For example adding "sideeffect=\par Side Effects:\n" will allow you to +# put the command \sideeffect (or @sideeffect) in the documentation, which +# will result in a user-defined paragraph with heading "Side Effects:". +# You can put \n's in the value part of an alias to insert newlines. + +ALIASES = + +# This tag can be used to specify a number of word-keyword mappings (TCL only). +# A mapping has the form "name=value". For example adding +# "class=itcl::class" will allow you to use the command class in the +# itcl::class meaning. + +TCL_SUBST = + +# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C +# sources only. Doxygen will then generate output that is more tailored for C. +# For instance, some of the names that are used will be different. The list +# of all members will be omitted, etc. + +OPTIMIZE_OUTPUT_FOR_C = YES + +# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java +# sources only. Doxygen will then generate output that is more tailored for +# Java. For instance, namespaces will be presented as packages, qualified +# scopes will look different, etc. + +OPTIMIZE_OUTPUT_JAVA = NO + +# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran +# sources only. Doxygen will then generate output that is more tailored for +# Fortran. + +OPTIMIZE_FOR_FORTRAN = NO + +# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL +# sources. Doxygen will then generate output that is tailored for +# VHDL. + +OPTIMIZE_OUTPUT_VHDL = NO + +# Doxygen selects the parser to use depending on the extension of the files it +# parses. With this tag you can assign which parser to use for a given extension. +# Doxygen has a built-in mapping, but you can override or extend it using this +# tag. The format is ext=language, where ext is a file extension, and language +# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C, +# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make +# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C +# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions +# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen. + +EXTENSION_MAPPING = + +# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all +# comments according to the Markdown format, which allows for more readable +# documentation. See http://daringfireball.net/projects/markdown/ for details. +# The output of markdown processing is further processed by doxygen, so you +# can mix doxygen, HTML, and XML commands with Markdown formatting. +# Disable only in case of backward compatibilities issues. + +MARKDOWN_SUPPORT = YES + +# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want +# to include (a tag file for) the STL sources as input, then you should +# set this tag to YES in order to let doxygen match functions declarations and +# definitions whose arguments contain STL classes (e.g. func(std::string); v.s. +# func(std::string) {}). This also makes the inheritance and collaboration +# diagrams that involve STL classes more complete and accurate. + +BUILTIN_STL_SUPPORT = NO + +# If you use Microsoft's C++/CLI language, you should set this option to YES to +# enable parsing support. + +CPP_CLI_SUPPORT = NO + +# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only. +# Doxygen will parse them like normal C++ but will assume all classes use public +# instead of private inheritance when no explicit protection keyword is present. + +SIP_SUPPORT = NO + +# For Microsoft's IDL there are propget and propput attributes to indicate getter +# and setter methods for a property. Setting this option to YES (the default) +# will make doxygen replace the get and set methods by a property in the +# documentation. This will only work if the methods are indeed getting or +# setting a simple type. If this is not the case, or you want to show the +# methods anyway, you should set this option to NO. + +IDL_PROPERTY_SUPPORT = YES + +# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC +# tag is set to YES, then doxygen will reuse the documentation of the first +# member in the group (if any) for the other members of the group. By default +# all members of a group must be documented explicitly. + +DISTRIBUTE_GROUP_DOC = NO + +# Set the SUBGROUPING tag to YES (the default) to allow class member groups of +# the same type (for instance a group of public functions) to be put as a +# subgroup of that type (e.g. under the Public Functions section). Set it to +# NO to prevent subgrouping. Alternatively, this can be done per class using +# the \nosubgrouping command. + +SUBGROUPING = YES + +# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and +# unions are shown inside the group in which they are included (e.g. using +# @ingroup) instead of on a separate page (for HTML and Man pages) or +# section (for LaTeX and RTF). + +INLINE_GROUPED_CLASSES = NO + +# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and +# unions with only public data fields will be shown inline in the documentation +# of the scope in which they are defined (i.e. file, namespace, or group +# documentation), provided this scope is documented. If set to NO (the default), +# structs, classes, and unions are shown on a separate page (for HTML and Man +# pages) or section (for LaTeX and RTF). + +INLINE_SIMPLE_STRUCTS = NO + +# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum +# is documented as struct, union, or enum with the name of the typedef. So +# typedef struct TypeS {} TypeT, will appear in the documentation as a struct +# with name TypeT. When disabled the typedef will appear as a member of a file, +# namespace, or class. And the struct will be named TypeS. This can typically +# be useful for C code in case the coding convention dictates that all compound +# types are typedef'ed and only the typedef is referenced, never the tag name. + +TYPEDEF_HIDES_STRUCT = NO + +# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to +# determine which symbols to keep in memory and which to flush to disk. +# When the cache is full, less often used symbols will be written to disk. +# For small to medium size projects (<1000 input files) the default value is +# probably good enough. For larger projects a too small cache size can cause +# doxygen to be busy swapping symbols to and from disk most of the time +# causing a significant performance penalty. +# If the system has enough physical memory increasing the cache will improve the +# performance by keeping more symbols in memory. Note that the value works on +# a logarithmic scale so increasing the size by one will roughly double the +# memory usage. The cache size is given by this formula: +# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +SYMBOL_CACHE_SIZE = 0 + +# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be +# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given +# their name and scope. Since this can be an expensive process and often the +# same symbol appear multiple times in the code, doxygen keeps a cache of +# pre-resolved symbols. If the cache is too small doxygen will become slower. +# If the cache is too large, memory is wasted. The cache size is given by this +# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0, +# corresponding to a cache size of 2^16 = 65536 symbols. + +LOOKUP_CACHE_SIZE = 0 + +#--------------------------------------------------------------------------- +# Build related configuration options +#--------------------------------------------------------------------------- + +# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in +# documentation are documented, even if no documentation was available. +# Private class members and static file members will be hidden unless +# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES + +EXTRACT_ALL = NO + +# If the EXTRACT_PRIVATE tag is set to YES all private members of a class +# will be included in the documentation. + +EXTRACT_PRIVATE = NO + +# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation. + +EXTRACT_PACKAGE = NO + +# If the EXTRACT_STATIC tag is set to YES all static members of a file +# will be included in the documentation. + +EXTRACT_STATIC = NO + +# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) +# defined locally in source files will be included in the documentation. +# If set to NO only classes defined in header files are included. + +EXTRACT_LOCAL_CLASSES = NO + +# This flag is only useful for Objective-C code. When set to YES local +# methods, which are defined in the implementation section but not in +# the interface are included in the documentation. +# If set to NO (the default) only methods in the interface are included. + +EXTRACT_LOCAL_METHODS = NO + +# If this flag is set to YES, the members of anonymous namespaces will be +# extracted and appear in the documentation as a namespace called +# 'anonymous_namespace{file}', where file will be replaced with the base +# name of the file that contains the anonymous namespace. By default +# anonymous namespaces are hidden. + +EXTRACT_ANON_NSPACES = NO + +# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all +# undocumented members of documented classes, files or namespaces. +# If set to NO (the default) these members will be included in the +# various overviews, but no documentation section is generated. +# This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_MEMBERS = YES + +# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all +# undocumented classes that are normally visible in the class hierarchy. +# If set to NO (the default) these classes will be included in the various +# overviews. This option has no effect if EXTRACT_ALL is enabled. + +HIDE_UNDOC_CLASSES = YES + +# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all +# friend (class|struct|union) declarations. +# If set to NO (the default) these declarations will be included in the +# documentation. + +HIDE_FRIEND_COMPOUNDS = NO + +# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any +# documentation blocks found inside the body of a function. +# If set to NO (the default) these blocks will be appended to the +# function's detailed documentation block. + +HIDE_IN_BODY_DOCS = NO + +# The INTERNAL_DOCS tag determines if documentation +# that is typed after a \internal command is included. If the tag is set +# to NO (the default) then the documentation will be excluded. +# Set it to YES to include the internal documentation. + +INTERNAL_DOCS = NO + +# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate +# file names in lower-case letters. If set to YES upper-case letters are also +# allowed. This is useful if you have classes or files whose names only differ +# in case and if your file system supports case sensitive file names. Windows +# and Mac users are advised to set this option to NO. + +CASE_SENSE_NAMES = YES + +# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen +# will show members with their full class and namespace scopes in the +# documentation. If set to YES the scope will be hidden. + +HIDE_SCOPE_NAMES = NO + +# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen +# will put a list of the files that are included by a file in the documentation +# of that file. + +SHOW_INCLUDE_FILES = YES + +# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen +# will list include files with double quotes in the documentation +# rather than with sharp brackets. + +FORCE_LOCAL_INCLUDES = NO + +# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] +# is inserted in the documentation for inline members. + +INLINE_INFO = YES + +# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen +# will sort the (detailed) documentation of file and class members +# alphabetically by member name. If set to NO the members will appear in +# declaration order. + +SORT_MEMBER_DOCS = YES + +# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the +# brief documentation of file, namespace and class members alphabetically +# by member name. If set to NO (the default) the members will appear in +# declaration order. + +SORT_BRIEF_DOCS = NO + +# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen +# will sort the (brief and detailed) documentation of class members so that +# constructors and destructors are listed first. If set to NO (the default) +# the constructors will appear in the respective orders defined by +# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS. +# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO +# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO. + +SORT_MEMBERS_CTORS_1ST = NO + +# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the +# hierarchy of group names into alphabetical order. If set to NO (the default) +# the group names will appear in their defined order. + +SORT_GROUP_NAMES = NO + +# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be +# sorted by fully-qualified names, including namespaces. If set to +# NO (the default), the class list will be sorted only by class name, +# not including the namespace part. +# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES. +# Note: This option applies only to the class list, not to the +# alphabetical list. + +SORT_BY_SCOPE_NAME = NO + +# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to +# do proper type resolution of all parameters of a function it will reject a +# match between the prototype and the implementation of a member function even +# if there is only one candidate or it is obvious which candidate to choose +# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen +# will still accept a match between prototype and implementation in such cases. + +STRICT_PROTO_MATCHING = NO + +# The GENERATE_TODOLIST tag can be used to enable (YES) or +# disable (NO) the todo list. This list is created by putting \todo +# commands in the documentation. + +GENERATE_TODOLIST = YES + +# The GENERATE_TESTLIST tag can be used to enable (YES) or +# disable (NO) the test list. This list is created by putting \test +# commands in the documentation. + +GENERATE_TESTLIST = YES + +# The GENERATE_BUGLIST tag can be used to enable (YES) or +# disable (NO) the bug list. This list is created by putting \bug +# commands in the documentation. + +GENERATE_BUGLIST = YES + +# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or +# disable (NO) the deprecated list. This list is created by putting +# \deprecated commands in the documentation. + +GENERATE_DEPRECATEDLIST= YES + +# The ENABLED_SECTIONS tag can be used to enable conditional +# documentation sections, marked by \if sectionname ... \endif. + +ENABLED_SECTIONS = + +# The MAX_INITIALIZER_LINES tag determines the maximum number of lines +# the initial value of a variable or macro consists of for it to appear in +# the documentation. If the initializer consists of more lines than specified +# here it will be hidden. Use a value of 0 to hide initializers completely. +# The appearance of the initializer of individual variables and macros in the +# documentation can be controlled using \showinitializer or \hideinitializer +# command in the documentation regardless of this setting. + +MAX_INITIALIZER_LINES = 30 + +# Set the SHOW_USED_FILES tag to NO to disable the list of files generated +# at the bottom of the documentation of classes and structs. If set to YES the +# list will mention the files that were used to generate the documentation. + +SHOW_USED_FILES = YES + +# Set the SHOW_FILES tag to NO to disable the generation of the Files page. +# This will remove the Files entry from the Quick Index and from the +# Folder Tree View (if specified). The default is YES. + +SHOW_FILES = YES + +# Set the SHOW_NAMESPACES tag to NO to disable the generation of the +# Namespaces page. +# This will remove the Namespaces entry from the Quick Index +# and from the Folder Tree View (if specified). The default is YES. + +SHOW_NAMESPACES = YES + +# The FILE_VERSION_FILTER tag can be used to specify a program or script that +# doxygen should invoke to get the current version for each file (typically from +# the version control system). Doxygen will invoke the program by executing (via +# popen()) the command <command> <input-file>, where <command> is the value of +# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file +# provided by doxygen. Whatever the program writes to standard output +# is used as the file version. See the manual for examples. + +FILE_VERSION_FILTER = + +# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed +# by doxygen. The layout file controls the global structure of the generated +# output files in an output format independent way. The create the layout file +# that represents doxygen's defaults, run doxygen with the -l option. +# You can optionally specify a file name after the option, if omitted +# DoxygenLayout.xml will be used as the name of the layout file. + +LAYOUT_FILE = + +# The CITE_BIB_FILES tag can be used to specify one or more bib files +# containing the references data. This must be a list of .bib files. The +# .bib extension is automatically appended if omitted. Using this command +# requires the bibtex tool to be installed. See also +# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style +# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this +# feature you need bibtex and perl available in the search path. + +CITE_BIB_FILES = + +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- + +# The QUIET tag can be used to turn on/off the messages that are generated +# by doxygen. Possible values are YES and NO. If left blank NO is used. + +QUIET = NO + +# The WARNINGS tag can be used to turn on/off the warning messages that are +# generated by doxygen. Possible values are YES and NO. If left blank +# NO is used. + +WARNINGS = YES + +# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings +# for undocumented members. If EXTRACT_ALL is set to YES then this flag will +# automatically be disabled. + +WARN_IF_UNDOCUMENTED = YES + +# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for +# potential errors in the documentation, such as not documenting some +# parameters in a documented function, or documenting parameters that +# don't exist or using markup commands wrongly. + +WARN_IF_DOC_ERROR = YES + +# The WARN_NO_PARAMDOC option can be enabled to get warnings for +# functions that are documented, but have no documentation for their parameters +# or return value. If set to NO (the default) doxygen will only warn about +# wrong or incomplete parameter documentation, but not about the absence of +# documentation. + +WARN_NO_PARAMDOC = NO + +# The WARN_FORMAT tag determines the format of the warning messages that +# doxygen can produce. The string should contain the $file, $line, and $text +# tags, which will be replaced by the file and line number from which the +# warning originated and the warning text. Optionally the format may contain +# $version, which will be replaced by the version of the file (if it could +# be obtained via FILE_VERSION_FILTER) + +WARN_FORMAT = "$file:$line: $text" + +# The WARN_LOGFILE tag can be used to specify a file to which warning +# and error messages should be written. If left blank the output is written +# to stderr. + +WARN_LOGFILE = + +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- + +# The INPUT tag can be used to specify the files and/or directories that contain +# documented source files. You may enter file names like "myfile.cpp" or +# directories like "/usr/src/myproject". Separate the files or directories +# with spaces. + +INPUT = . \ + doc + +# This tag can be used to specify the character encoding of the source files +# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is +# also the default input encoding. Doxygen uses libiconv (or the iconv built +# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for +# the list of possible encodings. + +INPUT_ENCODING = UTF-8 + +# If the value of the INPUT tag contains directories, you can use the +# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank the following patterns are tested: +# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh +# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py +# *.f90 *.f *.for *.vhd *.vhdl + +FILE_PATTERNS = *.cpp \ + *.cc \ + *.c \ + *.h \ + *.hh \ + *.hpp \ + *.dox + +# The RECURSIVE tag can be used to turn specify whether or not subdirectories +# should be searched for input files as well. Possible values are YES and NO. +# If left blank NO is used. + +RECURSIVE = NO + +# The EXCLUDE tag can be used to specify files and/or directories that should be +# excluded from the INPUT source files. This way you can easily exclude a +# subdirectory from a directory tree whose root is specified with the INPUT tag. +# Note that relative paths are relative to the directory from which doxygen is +# run. + +EXCLUDE = + +# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or +# directories that are symbolic links (a Unix file system feature) are excluded +# from the input. + +EXCLUDE_SYMLINKS = NO + +# If the value of the INPUT tag contains directories, you can use the +# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude +# certain files from those directories. Note that the wildcards are matched +# against the file with absolute path, so to exclude all test directories +# for example use the pattern */test/* + +EXCLUDE_PATTERNS = */.git/* + +# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names +# (namespaces, classes, functions, etc.) that should be excluded from the +# output. The symbol name can be a fully qualified name, a word, or if the +# wildcard * is used, a substring. Examples: ANamespace, AClass, +# AClass::ANamespace, ANamespace::*Test + +EXCLUDE_SYMBOLS = + +# The EXAMPLE_PATH tag can be used to specify one or more files or +# directories that contain example code fragments that are included (see +# the \include command). + +EXAMPLE_PATH = + +# If the value of the EXAMPLE_PATH tag contains directories, you can use the +# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp +# and *.h) to filter out the source-files in the directories. If left +# blank all files are included. + +EXAMPLE_PATTERNS = + +# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be +# searched for input files to be used with the \include or \dontinclude +# commands irrespective of the value of the RECURSIVE tag. +# Possible values are YES and NO. If left blank NO is used. + +EXAMPLE_RECURSIVE = NO + +# The IMAGE_PATH tag can be used to specify one or more files or +# directories that contain image that are included in the documentation (see +# the \image command). + +IMAGE_PATH = doc + +# The INPUT_FILTER tag can be used to specify a program that doxygen should +# invoke to filter for each input file. Doxygen will invoke the filter program +# by executing (via popen()) the command <filter> <input-file>, where <filter> +# is the value of the INPUT_FILTER tag, and <input-file> is the name of an +# input file. Doxygen will then use the output that the filter program writes +# to standard output. +# If FILTER_PATTERNS is specified, this tag will be +# ignored. + +INPUT_FILTER = + +# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern +# basis. +# Doxygen will compare the file name with each pattern and apply the +# filter if there is a match. +# The filters are a list of the form: +# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further +# info on how filters are used. If FILTER_PATTERNS is empty or if +# non of the patterns match the file name, INPUT_FILTER is applied. + +FILTER_PATTERNS = + +# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using +# INPUT_FILTER) will be used to filter the input files when producing source +# files to browse (i.e. when SOURCE_BROWSER is set to YES). + +FILTER_SOURCE_FILES = NO + +# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file +# pattern. A pattern will override the setting for FILTER_PATTERN (if any) +# and it is also possible to disable source filtering for a specific pattern +# using *.ext= (so without naming a filter). This option only has effect when +# FILTER_SOURCE_FILES is enabled. + +FILTER_SOURCE_PATTERNS = + +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- + +# If the SOURCE_BROWSER tag is set to YES then a list of source files will +# be generated. Documented entities will be cross-referenced with these sources. +# Note: To get rid of all source code in the generated output, make sure also +# VERBATIM_HEADERS is set to NO. + +SOURCE_BROWSER = NO + +# Setting the INLINE_SOURCES tag to YES will include the body +# of functions and classes directly in the documentation. + +INLINE_SOURCES = NO + +# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct +# doxygen to hide any special comment blocks from generated source code +# fragments. Normal C and C++ comments will always remain visible. + +STRIP_CODE_COMMENTS = YES + +# If the REFERENCED_BY_RELATION tag is set to YES +# then for each documented function all documented +# functions referencing it will be listed. + +REFERENCED_BY_RELATION = NO + +# If the REFERENCES_RELATION tag is set to YES +# then for each documented function all documented entities +# called/used by that function will be listed. + +REFERENCES_RELATION = NO + +# If the REFERENCES_LINK_SOURCE tag is set to YES (the default) +# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from +# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will +# link to the source code. +# Otherwise they will link to the documentation. + +REFERENCES_LINK_SOURCE = YES + +# If the USE_HTAGS tag is set to YES then the references to source code +# will point to the HTML generated by the htags(1) tool instead of doxygen +# built-in source browser. The htags tool is part of GNU's global source +# tagging system (see http://www.gnu.org/software/global/global.html). You +# will need version 4.8.6 or higher. + +USE_HTAGS = NO + +# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen +# will generate a verbatim copy of the header file for each class for +# which an include is specified. Set to NO to disable this. + +VERBATIM_HEADERS = YES + +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- + +# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index +# of all compounds will be generated. Enable this if the project +# contains a lot of classes, structs, unions or interfaces. + +ALPHABETICAL_INDEX = NO + +# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then +# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns +# in which this list will be split (can be a number in the range [1..20]) + +COLS_IN_ALPHA_INDEX = 5 + +# In case all classes in a project start with a common prefix, all +# classes will be put under the same header in the alphabetical index. +# The IGNORE_PREFIX tag can be used to specify one or more prefixes that +# should be ignored while generating the index headers. + +IGNORE_PREFIX = + +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- + +# If the GENERATE_HTML tag is set to YES (the default) Doxygen will +# generate HTML output. + +GENERATE_HTML = YES + +# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `html' will be used as the default path. + +HTML_OUTPUT = html + +# The HTML_FILE_EXTENSION tag can be used to specify the file extension for +# each generated HTML page (for example: .htm,.php,.asp). If it is left blank +# doxygen will generate files with .html extension. + +HTML_FILE_EXTENSION = .html + +# The HTML_HEADER tag can be used to specify a personal HTML header for +# each generated HTML page. If it is left blank doxygen will generate a +# standard header. Note that when using a custom header you are responsible +# for the proper inclusion of any scripts and style sheets that doxygen +# needs, which is dependent on the configuration options used. +# It is advised to generate a default header using "doxygen -w html +# header.html footer.html stylesheet.css YourConfigFile" and then modify +# that header. Note that the header is subject to change so you typically +# have to redo this when upgrading to a newer version of doxygen or when +# changing the value of configuration settings such as GENERATE_TREEVIEW! + +HTML_HEADER = + +# The HTML_FOOTER tag can be used to specify a personal HTML footer for +# each generated HTML page. If it is left blank doxygen will generate a +# standard footer. + +HTML_FOOTER = + +# The HTML_STYLESHEET tag can be used to specify a user-defined cascading +# style sheet that is used by each HTML page. It can be used to +# fine-tune the look of the HTML output. If the tag is left blank doxygen +# will generate a default style sheet. Note that doxygen will try to copy +# the style sheet file to the HTML output directory, so don't put your own +# style sheet in the HTML output directory as well, or it will be erased! + +HTML_STYLESHEET = + +# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or +# other source files which should be copied to the HTML output directory. Note +# that these files will be copied to the base HTML output directory. Use the +# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these +# files. In the HTML_STYLESHEET file, use the file name only. Also note that +# the files will be copied as-is; there are no commands or markers available. + +HTML_EXTRA_FILES = + +# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. +# Doxygen will adjust the colors in the style sheet and background images +# according to this color. Hue is specified as an angle on a colorwheel, +# see http://en.wikipedia.org/wiki/Hue for more information. +# For instance the value 0 represents red, 60 is yellow, 120 is green, +# 180 is cyan, 240 is blue, 300 purple, and 360 is red again. +# The allowed range is 0 to 359. + +HTML_COLORSTYLE_HUE = 220 + +# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of +# the colors in the HTML output. For a value of 0 the output will use +# grayscales only. A value of 255 will produce the most vivid colors. + +HTML_COLORSTYLE_SAT = 100 + +# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to +# the luminance component of the colors in the HTML output. Values below +# 100 gradually make the output lighter, whereas values above 100 make +# the output darker. The value divided by 100 is the actual gamma applied, +# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2, +# and 100 does not change the gamma. + +HTML_COLORSTYLE_GAMMA = 80 + +# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML +# page will contain the date and time when the page was generated. Setting +# this to NO can help when comparing the output of multiple runs. + +HTML_TIMESTAMP = NO + +# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, +# files or namespaces will be aligned in HTML using tables. If set to +# NO a bullet list will be used. + +HTML_ALIGN_MEMBERS = YES + +# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML +# documentation will contain sections that can be hidden and shown after the +# page has loaded. For this to work a browser that supports +# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox +# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari). + +HTML_DYNAMIC_SECTIONS = NO + +# If the GENERATE_DOCSET tag is set to YES, additional index files +# will be generated that can be used as input for Apple's Xcode 3 +# integrated development environment, introduced with OSX 10.5 (Leopard). +# To create a documentation set, doxygen will generate a Makefile in the +# HTML output directory. Running make will produce the docset in that +# directory and running "make install" will install the docset in +# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find +# it at startup. +# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html +# for more information. + +GENERATE_DOCSET = NO + +# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the +# feed. A documentation feed provides an umbrella under which multiple +# documentation sets from a single provider (such as a company or product suite) +# can be grouped. + +DOCSET_FEEDNAME = "Doxygen generated docs" + +# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that +# should uniquely identify the documentation set bundle. This should be a +# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen +# will append .docset to the name. + +DOCSET_BUNDLE_ID = org.doxygen.Project + +# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify +# the documentation publisher. This should be a reverse domain-name style +# string, e.g. com.mycompany.MyDocSet.documentation. + +DOCSET_PUBLISHER_ID = org.doxygen.Publisher + +# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher. + +DOCSET_PUBLISHER_NAME = Publisher + +# If the GENERATE_HTMLHELP tag is set to YES, additional index files +# will be generated that can be used as input for tools like the +# Microsoft HTML help workshop to generate a compiled HTML help file (.chm) +# of the generated HTML documentation. + +GENERATE_HTMLHELP = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can +# be used to specify the file name of the resulting .chm file. You +# can add a path in front of the file if the result should not be +# written to the html output directory. + +CHM_FILE = + +# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can +# be used to specify the location (absolute path including file name) of +# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run +# the HTML help compiler on the generated index.hhp. + +HHC_LOCATION = + +# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag +# controls if a separate .chi index file is generated (YES) or that +# it should be included in the master .chm file (NO). + +GENERATE_CHI = NO + +# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING +# is used to encode HtmlHelp index (hhk), content (hhc) and project file +# content. + +CHM_INDEX_ENCODING = + +# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag +# controls whether a binary table of contents is generated (YES) or a +# normal table of contents (NO) in the .chm file. + +BINARY_TOC = NO + +# The TOC_EXPAND flag can be set to YES to add extra items for group members +# to the contents of the HTML help documentation and to the tree view. + +TOC_EXPAND = NO + +# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and +# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated +# that can be used as input for Qt's qhelpgenerator to generate a +# Qt Compressed Help (.qch) of the generated HTML documentation. + +GENERATE_QHP = NO + +# If the QHG_LOCATION tag is specified, the QCH_FILE tag can +# be used to specify the file name of the resulting .qch file. +# The path specified is relative to the HTML output folder. + +QCH_FILE = + +# The QHP_NAMESPACE tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#namespace + +QHP_NAMESPACE = + +# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating +# Qt Help Project output. For more information please see +# http://doc.trolltech.com/qthelpproject.html#virtual-folders + +QHP_VIRTUAL_FOLDER = doc + +# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to +# add. For more information please see +# http://doc.trolltech.com/qthelpproject.html#custom-filters + +QHP_CUST_FILTER_NAME = + +# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the +# custom filter to add. For more information please see +# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters"> +# Qt Help Project / Custom Filters</a>. + +QHP_CUST_FILTER_ATTRS = + +# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this +# project's +# filter section matches. +# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes"> +# Qt Help Project / Filter Attributes</a>. + +QHP_SECT_FILTER_ATTRS = + +# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can +# be used to specify the location of Qt's qhelpgenerator. +# If non-empty doxygen will try to run qhelpgenerator on the generated +# .qhp file. + +QHG_LOCATION = + +# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files +# will be generated, which together with the HTML files, form an Eclipse help +# plugin. To install this plugin and make it available under the help contents +# menu in Eclipse, the contents of the directory containing the HTML and XML +# files needs to be copied into the plugins directory of eclipse. The name of +# the directory within the plugins directory should be the same as +# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before +# the help appears. + +GENERATE_ECLIPSEHELP = NO + +# A unique identifier for the eclipse help plugin. When installing the plugin +# the directory name containing the HTML and XML files should also have +# this name. + +ECLIPSE_DOC_ID = org.doxygen.Project + +# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) +# at top of each HTML page. The value NO (the default) enables the index and +# the value YES disables it. Since the tabs have the same information as the +# navigation tree you can set this option to NO if you already set +# GENERATE_TREEVIEW to YES. + +DISABLE_INDEX = NO + +# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index +# structure should be generated to display hierarchical information. +# If the tag value is set to YES, a side panel will be generated +# containing a tree-like index structure (just like the one that +# is generated for HTML Help). For this to work a browser that supports +# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser). +# Windows users are probably better off using the HTML help feature. +# Since the tree basically has the same information as the tab index you +# could consider to set DISABLE_INDEX to NO when enabling this option. + +GENERATE_TREEVIEW = NONE + +# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values +# (range [0,1..20]) that doxygen will group on one line in the generated HTML +# documentation. Note that a value of 0 will completely suppress the enum +# values from appearing in the overview section. + +ENUM_VALUES_PER_LINE = 4 + +# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be +# used to set the initial width (in pixels) of the frame in which the tree +# is shown. + +TREEVIEW_WIDTH = 250 + +# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open +# links to external symbols imported via tag files in a separate window. + +EXT_LINKS_IN_WINDOW = NO + +# Use this tag to change the font size of Latex formulas included +# as images in the HTML documentation. The default is 10. Note that +# when you change the font size after a successful doxygen run you need +# to manually remove any form_*.png images from the HTML output directory +# to force them to be regenerated. + +FORMULA_FONTSIZE = 10 + +# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# generated for formulas are transparent PNGs. Transparent PNGs are +# not supported properly for IE 6.0, but are supported on all modern browsers. +# Note that when changing this option you need to delete any form_*.png files +# in the HTML output before the changes have effect. + +FORMULA_TRANSPARENT = YES + +# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax +# (see http://www.mathjax.org) which uses client side Javascript for the +# rendering instead of using prerendered bitmaps. Use this if you do not +# have LaTeX installed or if you want to formulas look prettier in the HTML +# output. When enabled you may also need to install MathJax separately and +# configure the path to it using the MATHJAX_RELPATH option. + +USE_MATHJAX = NO + +# When MathJax is enabled you need to specify the location relative to the +# HTML output directory using the MATHJAX_RELPATH option. The destination +# directory should contain the MathJax.js script. For instance, if the mathjax +# directory is located at the same level as the HTML output directory, then +# MATHJAX_RELPATH should be ../mathjax. The default value points to +# the MathJax Content Delivery Network so you can quickly see the result without +# installing MathJax. +# However, it is strongly recommended to install a local +# copy of MathJax from http://www.mathjax.org before deployment. + +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest + +# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension +# names that should be enabled during MathJax rendering. + +MATHJAX_EXTENSIONS = + +# When the SEARCHENGINE tag is enabled doxygen will generate a search box +# for the HTML output. The underlying search engine uses javascript +# and DHTML and should work on any modern browser. Note that when using +# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets +# (GENERATE_DOCSET) there is already a search function so this one should +# typically be disabled. For large projects the javascript based search engine +# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution. + +SEARCHENGINE = NO + +# When the SERVER_BASED_SEARCH tag is enabled the search engine will be +# implemented using a PHP enabled web server instead of at the web client +# using Javascript. Doxygen will generate the search PHP script and index +# file to put on the web server. The advantage of the server +# based approach is that it scales better to large projects and allows +# full text search. The disadvantages are that it is more difficult to setup +# and does not have live searching capabilities. + +SERVER_BASED_SEARCH = NO + +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- + +# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will +# generate Latex output. + +GENERATE_LATEX = YES + +# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `latex' will be used as the default path. + +LATEX_OUTPUT = latex + +# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be +# invoked. If left blank `latex' will be used as the default command name. +# Note that when enabling USE_PDFLATEX this option is only used for +# generating bitmaps for formulas in the HTML output, but not in the +# Makefile that is written to the output directory. + +LATEX_CMD_NAME = latex + +# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to +# generate index for LaTeX. If left blank `makeindex' will be used as the +# default command name. + +MAKEINDEX_CMD_NAME = makeindex + +# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact +# LaTeX documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_LATEX = NO + +# The PAPER_TYPE tag can be used to set the paper type that is used +# by the printer. Possible values are: a4, letter, legal and +# executive. If left blank a4wide will be used. + +PAPER_TYPE = a4wide + +# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX +# packages that should be included in the LaTeX output. + +EXTRA_PACKAGES = + +# The LATEX_HEADER tag can be used to specify a personal LaTeX header for +# the generated latex document. The header should contain everything until +# the first chapter. If it is left blank doxygen will generate a +# standard header. Notice: only use this tag if you know what you are doing! + +LATEX_HEADER = + +# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for +# the generated latex document. The footer should contain everything after +# the last chapter. If it is left blank doxygen will generate a +# standard footer. Notice: only use this tag if you know what you are doing! + +LATEX_FOOTER = + +# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated +# is prepared for conversion to pdf (using ps2pdf). The pdf file will +# contain links (just like the HTML output) instead of page references +# This makes the output suitable for online browsing using a pdf viewer. + +PDF_HYPERLINKS = YES + +# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of +# plain latex in the generated Makefile. Set this option to YES to get a +# higher quality PDF documentation. + +USE_PDFLATEX = YES + +# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. +# command to the generated LaTeX files. This will instruct LaTeX to keep +# running if errors occur, instead of asking the user for help. +# This option is also used when generating formulas in HTML. + +LATEX_BATCHMODE = NO + +# If LATEX_HIDE_INDICES is set to YES then doxygen will not +# include the index chapters (such as File Index, Compound Index, etc.) +# in the output. + +LATEX_HIDE_INDICES = NO + +# If LATEX_SOURCE_CODE is set to YES then doxygen will include +# source code with syntax highlighting in the LaTeX output. +# Note that which sources are shown also depends on other settings +# such as SOURCE_BROWSER. + +LATEX_SOURCE_CODE = NO + +# The LATEX_BIB_STYLE tag can be used to specify the style to use for the +# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See +# http://en.wikipedia.org/wiki/BibTeX for more info. + +LATEX_BIB_STYLE = plain + +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- + +# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output +# The RTF output is optimized for Word 97 and may not look very pretty with +# other RTF readers or editors. + +GENERATE_RTF = NO + +# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `rtf' will be used as the default path. + +RTF_OUTPUT = rtf + +# If the COMPACT_RTF tag is set to YES Doxygen generates more compact +# RTF documents. This may be useful for small projects and may help to +# save some trees in general. + +COMPACT_RTF = NO + +# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated +# will contain hyperlink fields. The RTF file will +# contain links (just like the HTML output) instead of page references. +# This makes the output suitable for online browsing using WORD or other +# programs which support those fields. +# Note: wordpad (write) and others do not support links. + +RTF_HYPERLINKS = NO + +# Load style sheet definitions from file. Syntax is similar to doxygen's +# config file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. + +RTF_STYLESHEET_FILE = + +# Set optional variables used in the generation of an rtf document. +# Syntax is similar to doxygen's config file. + +RTF_EXTENSIONS_FILE = + +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- + +# If the GENERATE_MAN tag is set to YES (the default) Doxygen will +# generate man pages + +GENERATE_MAN = YES + +# The MAN_OUTPUT tag is used to specify where the man pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `man' will be used as the default path. + +MAN_OUTPUT = man + +# The MAN_EXTENSION tag determines the extension that is added to +# the generated man pages (default is the subroutine's section .3) + +MAN_EXTENSION = .3 + +# If the MAN_LINKS tag is set to YES and Doxygen generates man output, +# then it will generate one additional man file for each entity +# documented in the real man page(s). These additional files +# only source the real man page, but without them the man command +# would be unable to find the correct page. The default is NO. + +MAN_LINKS = NO + +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- + +# If the GENERATE_XML tag is set to YES Doxygen will +# generate an XML file that captures the structure of +# the code including all documentation. + +GENERATE_XML = NO + +# The XML_OUTPUT tag is used to specify where the XML pages will be put. +# If a relative path is entered the value of OUTPUT_DIRECTORY will be +# put in front of it. If left blank `xml' will be used as the default path. + +XML_OUTPUT = xml + +# The XML_SCHEMA tag can be used to specify an XML schema, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_SCHEMA = + +# The XML_DTD tag can be used to specify an XML DTD, +# which can be used by a validating XML parser to check the +# syntax of the XML files. + +XML_DTD = + +# If the XML_PROGRAMLISTING tag is set to YES Doxygen will +# dump the program listings (including syntax highlighting +# and cross-referencing information) to the XML output. Note that +# enabling this will significantly increase the size of the XML output. + +XML_PROGRAMLISTING = YES + +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- + +# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will +# generate an AutoGen Definitions (see autogen.sf.net) file +# that captures the structure of the code including all +# documentation. Note that this feature is still experimental +# and incomplete at the moment. + +GENERATE_AUTOGEN_DEF = NO + +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- + +# If the GENERATE_PERLMOD tag is set to YES Doxygen will +# generate a Perl module file that captures the structure of +# the code including all documentation. Note that this +# feature is still experimental and incomplete at the +# moment. + +GENERATE_PERLMOD = NO + +# If the PERLMOD_LATEX tag is set to YES Doxygen will generate +# the necessary Makefile rules, Perl scripts and LaTeX code to be able +# to generate PDF and DVI output from the Perl module output. + +PERLMOD_LATEX = NO + +# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be +# nicely formatted so it can be parsed by a human reader. +# This is useful +# if you want to understand what is going on. +# On the other hand, if this +# tag is set to NO the size of the Perl module output will be much smaller +# and Perl will parse it just the same. + +PERLMOD_PRETTY = YES + +# The names of the make variables in the generated doxyrules.make file +# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. +# This is useful so different doxyrules.make files included by the same +# Makefile don't overwrite each other's variables. + +PERLMOD_MAKEVAR_PREFIX = + +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- + +# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will +# evaluate all C-preprocessor directives found in the sources and include +# files. + +ENABLE_PREPROCESSING = YES + +# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro +# names in the source code. If set to NO (the default) only conditional +# compilation will be performed. Macro expansion can be done in a controlled +# way by setting EXPAND_ONLY_PREDEF to YES. + +MACRO_EXPANSION = YES + +# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES +# then the macro expansion is limited to the macros specified with the +# PREDEFINED and EXPAND_AS_DEFINED tags. + +EXPAND_ONLY_PREDEF = YES + +# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files +# pointed to by INCLUDE_PATH will be searched when a #include is found. + +SEARCH_INCLUDES = YES + +# The INCLUDE_PATH tag can be used to specify one or more directories that +# contain include files that are not input files but should be processed by +# the preprocessor. + +INCLUDE_PATH = + +# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard +# patterns (like *.h and *.hpp) to filter out the header-files in the +# directories. If left blank, the patterns specified with FILE_PATTERNS will +# be used. + +INCLUDE_FILE_PATTERNS = + +# The PREDEFINED tag can be used to specify one or more macro names that +# are defined before the preprocessor is started (similar to the -D option of +# gcc). The argument of the tag is a list of macros of the form: name +# or name=definition (no spaces). If the definition and the = are +# omitted =1 is assumed. To prevent a macro definition from being +# undefined via #undef or recursively expanded use the := operator +# instead of the = operator. + +PREDEFINED = DOXYGEN \ + PRINTF_ATTRIBUTE(x,y)= + +# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then +# this tag can be used to specify a list of macro names that should be expanded. +# The macro definition that is found in the sources will be used. +# Use the PREDEFINED tag if you want to use a different macro definition that +# overrules the definition found in the source code. + +EXPAND_AS_DEFINED = + +# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then +# doxygen's preprocessor will remove all references to function-like macros +# that are alone on a line, have an all uppercase name, and do not end with a +# semicolon, because these will confuse the parser if not removed. + +SKIP_FUNCTION_MACROS = YES + +#--------------------------------------------------------------------------- +# Configuration::additions related to external references +#--------------------------------------------------------------------------- + +# The TAGFILES option can be used to specify one or more tagfiles. For each +# tag file the location of the external documentation should be added. The +# format of a tag file without this location is as follows: +# +# TAGFILES = file1 file2 ... +# Adding location for the tag files is done as follows: +# +# TAGFILES = file1=loc1 "file2 = loc2" ... +# where "loc1" and "loc2" can be relative or absolute paths +# or URLs. Note that each tag file must have a unique name (where the name does +# NOT include the path). If a tag file is not located in the directory in which +# doxygen is run, you must also specify the path to the tagfile here. + +TAGFILES = + +# When a file name is specified after GENERATE_TAGFILE, doxygen will create +# a tag file that is based on the input files it reads. + +GENERATE_TAGFILE = + +# If the ALLEXTERNALS tag is set to YES all external classes will be listed +# in the class index. If set to NO only the inherited external classes +# will be listed. + +ALLEXTERNALS = NO + +# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed +# in the modules index. If set to NO, only the current project's groups will +# be listed. + +EXTERNAL_GROUPS = YES + +# The PERL_PATH should be the absolute path and name of the perl script +# interpreter (i.e. the result of `which perl'). + +PERL_PATH = /usr/bin/perl + +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- + +# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will +# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base +# or super classes. Setting the tag to NO turns the diagrams off. Note that +# this option also works with HAVE_DOT disabled, but it is recommended to +# install and use dot, since it yields more powerful graphs. + +CLASS_DIAGRAMS = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. Doxygen will then run the mscgen tool (see +# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the +# documentation. The MSCGEN_PATH tag allows you to specify the directory where +# the mscgen tool resides. If left empty the tool is assumed to be found in the +# default search path. + +MSCGEN_PATH = + +# If set to YES, the inheritance and collaboration graphs will hide +# inheritance and usage relations if the target is undocumented +# or is not a class. + +HIDE_UNDOC_RELATIONS = YES + +# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is +# available from the path. This tool is part of Graphviz, a graph visualization +# toolkit from AT&T and Lucent Bell Labs. The other options in this section +# have no effect if this option is set to NO (the default) + +HAVE_DOT = NO + +# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is +# allowed to run in parallel. When set to 0 (the default) doxygen will +# base this on the number of processors available in the system. You can set it +# explicitly to a value larger than 0 to get control over the balance +# between CPU load and processing speed. + +DOT_NUM_THREADS = 0 + +# By default doxygen will use the Helvetica font for all dot files that +# doxygen generates. When you want a differently looking font you can specify +# the font name using DOT_FONTNAME. You need to make sure dot is able to find +# the font, which can be done by putting it in a standard location or by setting +# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. + +DOT_FONTNAME = FreeSans + +# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs. +# The default size is 10pt. + +DOT_FONTSIZE = 10 + +# By default doxygen will tell dot to use the Helvetica font. +# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to +# set the path where dot can find it. + +DOT_FONTPATH = + +# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect inheritance relations. Setting this tag to YES will force the +# CLASS_DIAGRAMS tag to NO. + +CLASS_GRAPH = YES + +# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for each documented class showing the direct and +# indirect implementation dependencies (inheritance, containment, and +# class references variables) of the class with other documented classes. + +COLLABORATION_GRAPH = YES + +# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen +# will generate a graph for groups, showing the direct groups dependencies + +GROUP_GRAPHS = YES + +# If the UML_LOOK tag is set to YES doxygen will generate inheritance and +# collaboration diagrams in a style similar to the OMG's Unified Modeling +# Language. + +UML_LOOK = NO + +# If the UML_LOOK tag is enabled, the fields and methods are shown inside +# the class node. If there are many fields or methods and many nodes the +# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS +# threshold limits the number of items for each type to make the size more +# managable. Set this to 0 for no limit. Note that the threshold may be +# exceeded by 50% before the limit is enforced. + +UML_LIMIT_NUM_FIELDS = 10 + +# If set to YES, the inheritance and collaboration graphs will show the +# relations between templates and their instances. + +TEMPLATE_RELATIONS = NO + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT +# tags are set to YES then doxygen will generate a graph for each documented +# file showing the direct and indirect include dependencies of the file with +# other documented files. + +INCLUDE_GRAPH = YES + +# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and +# HAVE_DOT tags are set to YES then doxygen will generate a graph for each +# documented header file showing the documented files that directly or +# indirectly include this file. + +INCLUDED_BY_GRAPH = YES + +# If the CALL_GRAPH and HAVE_DOT options are set to YES then +# doxygen will generate a call dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable call graphs +# for selected functions only using the \callgraph command. + +CALL_GRAPH = NO + +# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then +# doxygen will generate a caller dependency graph for every global function +# or class method. Note that enabling this option will significantly increase +# the time of a run. So in most cases it will be better to enable caller +# graphs for selected functions only using the \callergraph command. + +CALLER_GRAPH = NO + +# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen +# will generate a graphical hierarchy of all classes instead of a textual one. + +GRAPHICAL_HIERARCHY = YES + +# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES +# then doxygen will show the dependencies a directory has on other directories +# in a graphical way. The dependency relations are determined by the #include +# relations between the files in the directories. + +DIRECTORY_GRAPH = YES + +# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images +# generated by dot. Possible values are svg, png, jpg, or gif. +# If left blank png will be used. If you choose svg you need to set +# HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible in IE 9+ (other browsers do not have this requirement). + +DOT_IMAGE_FORMAT = png + +# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to +# enable generation of interactive SVG images that allow zooming and panning. +# Note that this requires a modern browser other than Internet Explorer. +# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you +# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files +# visible. Older versions of IE do not have SVG support. + +INTERACTIVE_SVG = NO + +# The tag DOT_PATH can be used to specify the path where the dot tool can be +# found. If left blank, it is assumed the dot tool can be found in the path. + +DOT_PATH = + +# The DOTFILE_DIRS tag can be used to specify one or more directories that +# contain dot files that are included in the documentation (see the +# \dotfile command). + +DOTFILE_DIRS = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the +# \mscfile command). + +MSCFILE_DIRS = + +# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of +# nodes that will be shown in the graph. If the number of nodes in a graph +# becomes larger than this value, doxygen will truncate the graph, which is +# visualized by representing a node as a red box. Note that doxygen if the +# number of direct children of the root node in a graph is already larger than +# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note +# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH. + +DOT_GRAPH_MAX_NODES = 50 + +# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the +# graphs generated by dot. A depth value of 3 means that only nodes reachable +# from the root by following a path via at most 3 edges will be shown. Nodes +# that lay further from the root node will be omitted. Note that setting this +# option to 1 or 2 may greatly reduce the computation time needed for large +# code bases. Also note that the size of a graph can be further restricted by +# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction. + +MAX_DOT_GRAPH_DEPTH = 0 + +# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent +# background. This is disabled by default, because dot on Windows does not +# seem to support this out of the box. Warning: Depending on the platform used, +# enabling this option may lead to badly anti-aliased labels on the edges of +# a graph (i.e. they become hard to read). + +DOT_TRANSPARENT = YES + +# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output +# files in one run (i.e. multiple -o and -T options on the command line). This +# makes dot run faster, but since only newer versions of dot (>1.8.10) +# support this, this feature is disabled by default. + +DOT_MULTI_TARGETS = NO + +# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will +# generate a legend page explaining the meaning of the various boxes and +# arrows in the dot generated graphs. + +GENERATE_LEGEND = YES + +# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will +# remove the intermediate dot files that are used to generate +# the various graphs. + +DOT_CLEANUP = YES diff --git a/lib/talloc/man/talloc.3.xml b/lib/talloc/man/talloc.3.xml new file mode 100644 index 0000000..c51061f --- /dev/null +++ b/lib/talloc/man/talloc.3.xml @@ -0,0 +1,814 @@ +<?xml version="1.0"?> +<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd"> +<refentry> + <refentryinfo><date>2015-04-10</date></refentryinfo> + <refmeta> + <refentrytitle>talloc</refentrytitle> + <manvolnum>3</manvolnum> + <refmiscinfo class="source">Samba</refmiscinfo> + <refmiscinfo class="manual">System Administration tools</refmiscinfo> + <refmiscinfo class="version">4.0</refmiscinfo> + </refmeta> + <refnamediv> + <refname>talloc</refname> +<refpurpose>hierarchical reference counted memory pool system with destructors</refpurpose> + </refnamediv> + <refsynopsisdiv> +<synopsis>#include <talloc.h></synopsis> + </refsynopsisdiv> + <refsect1><title>DESCRIPTION</title> + <para> + If you are used to talloc from Samba3 then please read this + carefully, as talloc has changed a lot. + </para> + <para> + The new talloc is a hierarchical, reference counted memory pool + system with destructors. Quite a mouthful really, but not too bad + once you get used to it. + </para> + <para> + Perhaps the biggest change from Samba3 is that there is no + distinction between a "talloc context" and a "talloc pointer". Any + pointer returned from talloc() is itself a valid talloc context. + This means you can do this: + </para> + <programlisting> + struct foo *X = talloc(mem_ctx, struct foo); + X->name = talloc_strdup(X, "foo"); + </programlisting> + <para> + and the pointer <literal role="code">X->name</literal> + would be a "child" of the talloc context <literal + role="code">X</literal> which is itself a child of + <literal role="code">mem_ctx</literal>. So if you do + <literal role="code">talloc_free(mem_ctx)</literal> then + it is all destroyed, whereas if you do <literal + role="code">talloc_free(X)</literal> then just <literal + role="code">X</literal> and <literal + role="code">X->name</literal> are destroyed, and if + you do <literal + role="code">talloc_free(X->name)</literal> then just + the name element of <literal role="code">X</literal> is + destroyed. + </para> + <para> + If you think about this, then what this effectively gives you is an + n-ary tree, where you can free any part of the tree with + talloc_free(). + </para> + <para> + If you find this confusing, then I suggest you run the <literal + role="code">testsuite</literal> program to watch talloc + in action. You may also like to add your own tests to <literal + role="code">testsuite.c</literal> to clarify how some + particular situation is handled. + </para> + </refsect1> + <refsect1><title>TALLOC API</title> + <para> + The following is a complete guide to the talloc API. Read it all at + least twice. + </para> + <refsect2><title>(type *)talloc(const void *ctx, type);</title> + <para> + The talloc() macro is the core of the talloc library. It takes a + memory <emphasis role="italic">ctx</emphasis> and a <emphasis + role="italic">type</emphasis>, and returns a pointer to a new + area of memory of the given <emphasis + role="italic">type</emphasis>. + </para> + <para> + The returned pointer is itself a talloc context, so you can use + it as the <emphasis role="italic">ctx</emphasis> argument to more + calls to talloc() if you wish. + </para> + <para> + The returned pointer is a "child" of the supplied context. This + means that if you talloc_free() the <emphasis + role="italic">ctx</emphasis> then the new child disappears as + well. Alternatively you can free just the child. + </para> + <para> + The <emphasis role="italic">ctx</emphasis> argument to talloc() + can be NULL, in which case a new top level context is created. + </para> + </refsect2> + <refsect2><title>void *talloc_size(const void *ctx, size_t size);</title> + <para> + The function talloc_size() should be used when you don't have a + convenient type to pass to talloc(). Unlike talloc(), it is not + type safe (as it returns a void *), so you are on your own for + type checking. + </para> + </refsect2> + <refsect2><title>(typeof(ptr)) talloc_ptrtype(const void *ctx, ptr);</title> + <para> + The talloc_ptrtype() macro should be used when you have a pointer and + want to allocate memory to point at with this pointer. When compiling + with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_size() + and talloc_get_name() will return the current location in the source file. + and not the type. + </para> + </refsect2> + <refsect2><title>int talloc_free(void *ptr);</title> + <para> + The talloc_free() function frees a piece of talloc memory, and + all its children. You can call talloc_free() on any pointer + returned by talloc(). + </para> + <para> + The return value of talloc_free() indicates success or failure, + with 0 returned for success and -1 for failure. The only + possible failure condition is if <emphasis + role="italic">ptr</emphasis> had a destructor attached to it and + the destructor returned -1. See <link + linkend="talloc_set_destructor"><quote>talloc_set_destructor()</quote></link> + for details on destructors. + </para> + <para> + If this pointer has an additional parent when talloc_free() is + called then the memory is not actually released, but instead the + most recently established parent is destroyed. See <link + linkend="talloc_reference"><quote>talloc_reference()</quote></link> + for details on establishing additional parents. + </para> + <para> + For more control on which parent is removed, see <link + linkend="talloc_unlink"><quote>talloc_unlink()</quote></link>. + </para> + <para> + talloc_free() operates recursively on its children. + </para> + <para> + From the 2.0 version of talloc, as a special case, + talloc_free() is refused on pointers that have more than one + parent, as talloc would have no way of knowing which parent + should be removed. To free a pointer that has more than one + parent please use talloc_unlink(). + </para> + <para> + To help you find problems in your code caused by this behaviour, if + you do try and free a pointer with more than one parent then the + talloc logging function will be called to give output like this: + </para> + <para> + <screen format="linespecific"> + ERROR: talloc_free with references at some_dir/source/foo.c:123 + reference at some_dir/source/other.c:325 + reference at some_dir/source/third.c:121 + </screen> + </para> + <para> + Please see the documentation for talloc_set_log_fn() and + talloc_set_log_stderr() for more information on talloc logging + functions. + </para> + </refsect2> + <refsect2 id="talloc_reference"><title>void *talloc_reference(const void *ctx, const void *ptr);</title> + <para> + The talloc_reference() function makes <emphasis + role="italic">ctx</emphasis> an additional parent of <emphasis + role="italic">ptr</emphasis>. + </para> + <para> + The return value of talloc_reference() is always the original + pointer <emphasis role="italic">ptr</emphasis>, unless talloc ran + out of memory in creating the reference in which case it will + return NULL (each additional reference consumes around 48 bytes + of memory on intel x86 platforms). + </para> + <para> + If <emphasis role="italic">ptr</emphasis> is NULL, then the + function is a no-op, and simply returns NULL. + </para> + <para> + After creating a reference you can free it in one of the + following ways: + </para> + <para> + <itemizedlist> + <listitem> + <para> + you can talloc_free() any parent of the original pointer. + That will reduce the number of parents of this pointer by 1, + and will cause this pointer to be freed if it runs out of + parents. + </para> + </listitem> + <listitem> + <para> + you can talloc_free() the pointer itself if it has at maximum one + parent. This behaviour has been changed since the release of version + 2.0. Further information in the description of "talloc_free". + </para> + </listitem> + </itemizedlist> + </para> + <para> + For more control on which parent to remove, see <link + linkend="talloc_unlink"><quote>talloc_unlink()</quote></link>. + </para> + </refsect2> + <refsect2 id="talloc_unlink"><title>int talloc_unlink(const void *ctx, void *ptr);</title> + <para> + The talloc_unlink() function removes a specific parent from + <emphasis role="italic">ptr</emphasis>. The <emphasis + role="italic">ctx</emphasis> passed must either be a context used + in talloc_reference() with this pointer, or must be a direct + parent of ptr. + </para> + <para> + Note that if the parent has already been removed using + talloc_free() then this function will fail and will return -1. + Likewise, if <emphasis role="italic">ptr</emphasis> is NULL, then + the function will make no modifications and return -1. + </para> + <para> + Usually you can just use talloc_free() instead of + talloc_unlink(), but sometimes it is useful to have the + additional control on which parent is removed. + </para> + </refsect2> + <refsect2 id="talloc_set_destructor"><title>void talloc_set_destructor(const void *ptr, int (*destructor)(void *));</title> + <para> + The function talloc_set_destructor() sets the <emphasis + role="italic">destructor</emphasis> for the pointer <emphasis + role="italic">ptr</emphasis>. A <emphasis + role="italic">destructor</emphasis> is a function that is called + when the memory used by a pointer is about to be released. The + destructor receives <emphasis role="italic">ptr</emphasis> as an + argument, and should return 0 for success and -1 for failure. + </para> + <para> + The <emphasis role="italic">destructor</emphasis> can do anything + it wants to, including freeing other pieces of memory. A common + use for destructors is to clean up operating system resources + (such as open file descriptors) contained in the structure the + destructor is placed on. + </para> + <para> + You can only place one destructor on a pointer. If you need more + than one destructor then you can create a zero-length child of + the pointer and place an additional destructor on that. + </para> + <para> + To remove a destructor call talloc_set_destructor() with NULL for + the destructor. + </para> + <para> + If your destructor attempts to talloc_free() the pointer that it + is the destructor for then talloc_free() will return -1 and the + free will be ignored. This would be a pointless operation + anyway, as the destructor is only called when the memory is just + about to go away. + </para> + </refsect2> + <refsect2><title>int talloc_increase_ref_count(const void *<emphasis role="italic">ptr</emphasis>);</title> + <para> + The talloc_increase_ref_count(<emphasis + role="italic">ptr</emphasis>) function is exactly equivalent to: + </para> + <programlisting>talloc_reference(NULL, ptr);</programlisting> + <para> + You can use either syntax, depending on which you think is + clearer in your code. + </para> + <para> + It returns 0 on success and -1 on failure. + </para> + </refsect2> + <refsect2><title>size_t talloc_reference_count(const void *<emphasis role="italic">ptr</emphasis>);</title> + <para> + Return the number of references to the pointer. + </para> + </refsect2> + <refsect2 id="talloc_set_name"><title>void talloc_set_name(const void *ptr, const char *fmt, ...);</title> + <para> + Each talloc pointer has a "name". The name is used principally + for debugging purposes, although it is also possible to set and + get the name on a pointer in as a way of "marking" pointers in + your code. + </para> + <para> + The main use for names on pointer is for "talloc reports". See + <link + linkend="talloc_report"><quote>talloc_report_depth_cb()</quote></link>, + <link + linkend="talloc_report"><quote>talloc_report_depth_file()</quote></link>, + <link + linkend="talloc_report"><quote>talloc_report()</quote></link> + <link + linkend="talloc_report"><quote>talloc_report()</quote></link> + and <link + linkend="talloc_report_full"><quote>talloc_report_full()</quote></link> + for details. Also see <link + linkend="talloc_enable_leak_report"><quote>talloc_enable_leak_report()</quote></link> + and <link + linkend="talloc_enable_leak_report_full"><quote>talloc_enable_leak_report_full()</quote></link>. + </para> + <para> + The talloc_set_name() function allocates memory as a child of the + pointer. It is logically equivalent to: + </para> + <programlisting>talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...));</programlisting> + <para> + Note that multiple calls to talloc_set_name() will allocate more + memory without releasing the name. All of the memory is released + when the ptr is freed using talloc_free(). + </para> + </refsect2> + <refsect2><title>void talloc_set_name_const(const void *<emphasis role="italic">ptr</emphasis>, const char *<emphasis role="italic">name</emphasis>);</title> + <para> + The function talloc_set_name_const() is just like + talloc_set_name(), but it takes a string constant, and is much + faster. It is extensively used by the "auto naming" macros, such + as talloc_p(). + </para> + <para> + This function does not allocate any memory. It just copies the + supplied pointer into the internal representation of the talloc + ptr. This means you must not pass a <emphasis + role="italic">name</emphasis> pointer to memory that will + disappear before <emphasis role="italic">ptr</emphasis> is freed + with talloc_free(). + </para> + </refsect2> + <refsect2><title>void *talloc_named(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, ...);</title> + <para> + The talloc_named() function creates a named talloc pointer. It + is equivalent to: + </para> + <programlisting>ptr = talloc_size(ctx, size); +talloc_set_name(ptr, fmt, ....);</programlisting> + </refsect2> + <refsect2><title>void *talloc_named_const(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>, const char *<emphasis role="italic">name</emphasis>);</title> + <para> + This is equivalent to: + </para> + <programlisting>ptr = talloc_size(ctx, size); +talloc_set_name_const(ptr, name);</programlisting> + </refsect2> + <refsect2><title>const char *talloc_get_name(const void *<emphasis role="italic">ptr</emphasis>);</title> + <para> + This returns the current name for the given talloc pointer, + <emphasis role="italic">ptr</emphasis>. See <link + linkend="talloc_set_name"><quote>talloc_set_name()</quote></link> + for details. + </para> + </refsect2> + <refsect2><title>void *talloc_init(const char *<emphasis role="italic">fmt</emphasis>, ...);</title> + <para> + This function creates a zero length named talloc context as a top + level context. It is equivalent to: + </para> + <programlisting>talloc_named(NULL, 0, fmt, ...);</programlisting> + </refsect2> + <refsect2><title>void *talloc_new(void *<emphasis role="italic">ctx</emphasis>);</title> + <para> + This is a utility macro that creates a new memory context hanging + off an existing context, automatically naming it "talloc_new: + __location__" where __location__ is the source line it is called + from. It is particularly useful for creating a new temporary + working context. + </para> + </refsect2> + <refsect2><title>(<emphasis role="italic">type</emphasis> *)talloc_realloc(const void *<emphasis role="italic">ctx</emphasis>, void *<emphasis role="italic">ptr</emphasis>, <emphasis role="italic">type</emphasis>, <emphasis role="italic">count</emphasis>);</title> + <para> + The talloc_realloc() macro changes the size of a talloc pointer. + It has the following equivalences: + </para> + <programlisting>talloc_realloc(ctx, NULL, type, 1) ==> talloc(ctx, type); +talloc_realloc(ctx, ptr, type, 0) ==> talloc_free(ptr);</programlisting> + <para> + The <emphasis role="italic">ctx</emphasis> argument is only used + if <emphasis role="italic">ptr</emphasis> is not NULL, otherwise + it is ignored. + </para> + <para> + talloc_realloc() returns the new pointer, or NULL on failure. + The call will fail either due to a lack of memory, or because the + pointer has more than one parent (see <link + linkend="talloc_reference"><quote>talloc_reference()</quote></link>). + </para> + </refsect2> + <refsect2><title>void *talloc_realloc_size(const void *ctx, void *ptr, size_t size);</title> + <para> + the talloc_realloc_size() function is useful when the type is not + known so the type-safe talloc_realloc() cannot be used. + </para> + </refsect2> + <refsect2><title>TYPE *talloc_steal(const void *<emphasis role="italic">new_ctx</emphasis>, const TYPE *<emphasis role="italic">ptr</emphasis>);</title> + <para> + The talloc_steal() function changes the parent context of a + talloc pointer. It is typically used when the context that the + pointer is currently a child of is going to be freed and you wish + to keep the memory for a longer time. + </para> + <para> + The talloc_steal() function returns the pointer that you pass it. + It does not have any failure modes. + </para> + <para> + It is possible to produce loops in the parent/child + relationship if you are not careful with talloc_steal(). No + guarantees are provided as to your sanity or the safety of your + data if you do this. + </para> + <para> + Note that if you try and call talloc_steal() on a pointer that has + more than one parent then the result is ambiguous. Talloc will choose + to remove the parent that is currently indicated by talloc_parent() + and replace it with the chosen parent. You will also get a message + like this via the talloc logging functions: + </para> + <para> + <screen format="linespecific"> + WARNING: talloc_steal with references at some_dir/source/foo.c:123 + reference at some_dir/source/other.c:325 + reference at some_dir/source/third.c:121 + </screen> + </para> + <para> + To unambiguously change the parent of a pointer please see + the + function <link linkend="talloc_reference"><quote>talloc_reparent()</quote></link>. See + the talloc_set_log_fn() documentation for more information + on talloc logging. + </para> + </refsect2> + <refsect2><title>TYPE *talloc_reparent(const void *<emphasis role="italic">old_parent</emphasis>, const void *<emphasis role="italic">new_parent</emphasis>, const TYPE *<emphasis role="italic">ptr</emphasis>);</title> + <para> + The talloc_reparent() function changes the parent context of a talloc + pointer. It is typically used when the context that the pointer is + currently a child of is going to be freed and you wish to keep the + memory for a longer time. + </para> + <para> + The talloc_reparent() function returns the pointer that you pass it. It + does not have any failure modes. + </para> + <para> + The difference between talloc_reparent() and talloc_steal() is that + talloc_reparent() can specify which parent you wish to change. This is + useful when a pointer has multiple parents via references. + </para> + </refsect2> + <refsect2><title>TYPE *talloc_move(const void *<emphasis role="italic">new_ctx</emphasis>, TYPE **<emphasis role="italic">ptr</emphasis>);</title> + <para> + The talloc_move() function is a wrapper around + talloc_steal() which zeros the source pointer after the + move. This avoids a potential source of bugs where a + programmer leaves a pointer in two structures, and uses the + pointer from the old structure after it has been moved to a + new one. + </para> + </refsect2> + <refsect2><title>size_t talloc_total_size(const void *<emphasis role="italic">ptr</emphasis>);</title> + <para> + The talloc_total_size() function returns the total size in bytes + used by this pointer and all child pointers. Mostly useful for + debugging. + </para> + <para> + Passing NULL is allowed, but it will only give a meaningful + result if talloc_enable_leak_report() or + talloc_enable_leak_report_full() has been called. + </para> + </refsect2> + <refsect2><title>size_t talloc_total_blocks(const void *<emphasis role="italic">ptr</emphasis>);</title> + <para> + The talloc_total_blocks() function returns the total memory block + count used by this pointer and all child pointers. Mostly useful + for debugging. + </para> + <para> + Passing NULL is allowed, but it will only give a meaningful + result if talloc_enable_leak_report() or + talloc_enable_leak_report_full() has been called. + </para> + </refsect2> + <refsect2 id="talloc_report"><title>void talloc_report(const void *ptr, FILE *f);</title> + <para> + The talloc_report() function prints a summary report of all + memory used by <emphasis role="italic">ptr</emphasis>. One line + of report is printed for each immediate child of ptr, showing the + total memory and number of blocks used by that child. + </para> + <para> + You can pass NULL for the pointer, in which case a report is + printed for the top level memory context, but only if + talloc_enable_leak_report() or talloc_enable_leak_report_full() + has been called. + </para> + </refsect2> + <refsect2 id="talloc_report_full"><title>void talloc_report_full(const void *<emphasis role="italic">ptr</emphasis>, FILE *<emphasis role="italic">f</emphasis>);</title> + <para> + This provides a more detailed report than talloc_report(). It + will recursively print the entire tree of memory referenced by + the pointer. References in the tree are shown by giving the name + of the pointer that is referenced. + </para> + <para> + You can pass NULL for the pointer, in which case a report is + printed for the top level memory context, but only if + talloc_enable_leak_report() or talloc_enable_leak_report_full() + has been called. + </para> + </refsect2> + <refsect2 id="talloc_report_depth_cb"> + <funcsynopsis><funcprototype> + <funcdef>void <function>talloc_report_depth_cb</function></funcdef> + <paramdef><parameter>const void *ptr</parameter></paramdef> + <paramdef><parameter>int depth</parameter></paramdef> + <paramdef><parameter>int max_depth</parameter></paramdef> + <paramdef><parameter>void (*callback)(const void *ptr, int depth, int max_depth, int is_ref, void *priv)</parameter></paramdef> + <paramdef><parameter>void *priv</parameter></paramdef> + </funcprototype></funcsynopsis> + <para> + This provides a more flexible reports than talloc_report(). It + will recursively call the callback for the entire tree of memory + referenced by the pointer. References in the tree are passed with + <emphasis role="italic">is_ref = 1</emphasis> and the pointer that is referenced. + </para> + <para> + You can pass NULL for the pointer, in which case a report is + printed for the top level memory context, but only if + talloc_enable_leak_report() or talloc_enable_leak_report_full() + has been called. + </para> + <para> + The recursion is stopped when depth >= max_depth. + max_depth = -1 means only stop at leaf nodes. + </para> + </refsect2> + <refsect2 id="talloc_report_depth_file"> + <funcsynopsis><funcprototype> + <funcdef>void <function>talloc_report_depth_file</function></funcdef> + <paramdef><parameter>const void *ptr</parameter></paramdef> + <paramdef><parameter>int depth</parameter></paramdef> + <paramdef><parameter>int max_depth</parameter></paramdef> + <paramdef><parameter>FILE *f</parameter></paramdef> + </funcprototype></funcsynopsis> + <para> + This provides a more flexible reports than talloc_report(). It + will let you specify the depth and max_depth. + </para> + </refsect2> + <refsect2 id="talloc_enable_leak_report"><title>void talloc_enable_leak_report(void);</title> + <para> + This enables calling of talloc_report(NULL, stderr) when the + program exits. In Samba4 this is enabled by using the + --leak-report command line option. + </para> + <para> + For it to be useful, this function must be called before any + other talloc function as it establishes a "null context" that + acts as the top of the tree. If you don't call this function + first then passing NULL to talloc_report() or + talloc_report_full() won't give you the full tree printout. + </para> + <para> + Here is a typical talloc report: + </para> + <screen format="linespecific">talloc report on 'null_context' (total 267 bytes in 15 blocks) +libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks +libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks +iconv(UTF8,CP850) contains 42 bytes in 2 blocks +libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks +iconv(CP850,UTF8) contains 42 bytes in 2 blocks +iconv(UTF8,UTF-16LE) contains 45 bytes in 2 blocks +iconv(UTF-16LE,UTF8) contains 45 bytes in 2 blocks + </screen> + </refsect2> + <refsect2 id="talloc_enable_leak_report_full"><title>void talloc_enable_leak_report_full(void);</title> + <para> + This enables calling of talloc_report_full(NULL, stderr) when the + program exits. In Samba4 this is enabled by using the + --leak-report-full command line option. + </para> + <para> + For it to be useful, this function must be called before any + other talloc function as it establishes a "null context" that + acts as the top of the tree. If you don't call this function + first then passing NULL to talloc_report() or + talloc_report_full() won't give you the full tree printout. + </para> + <para> + Here is a typical full report: + </para> + <screen format="linespecific">full talloc report on 'root' (total 18 bytes in 8 blocks) +p1 contains 18 bytes in 7 blocks (ref 0) + r1 contains 13 bytes in 2 blocks (ref 0) + reference to: p2 + p2 contains 1 bytes in 1 blocks (ref 1) + x3 contains 1 bytes in 1 blocks (ref 0) + x2 contains 1 bytes in 1 blocks (ref 0) + x1 contains 1 bytes in 1 blocks (ref 0) + </screen> + </refsect2> + <refsect2><title>(<emphasis role="italic">type</emphasis> *)talloc_zero(const void *<emphasis role="italic">ctx</emphasis>, <emphasis role="italic">type</emphasis>);</title> + <para> + The talloc_zero() macro is equivalent to: + </para> + <programlisting>ptr = talloc(ctx, type); +if (ptr) memset(ptr, 0, sizeof(type));</programlisting> + </refsect2> + <refsect2><title>void *talloc_zero_size(const void *<emphasis role="italic">ctx</emphasis>, size_t <emphasis role="italic">size</emphasis>)</title> + <para> + The talloc_zero_size() function is useful when you don't have a + known type. + </para> + </refsect2> + <refsect2><title>void *talloc_memdup(const void *<emphasis role="italic">ctx</emphasis>, const void *<emphasis role="italic">p</emphasis>, size_t size);</title> + <para> + The talloc_memdup() function is equivalent to: + </para> + <programlisting>ptr = talloc_size(ctx, size); +if (ptr) memcpy(ptr, p, size);</programlisting> + </refsect2> + <refsect2><title>char *talloc_strdup(const void *<emphasis role="italic">ctx</emphasis>, const char *<emphasis role="italic">p</emphasis>);</title> + <para> + The talloc_strdup() function is equivalent to: + </para> + <programlisting>ptr = talloc_size(ctx, strlen(p)+1); +if (ptr) memcpy(ptr, p, strlen(p)+1);</programlisting> + <para> + This function sets the name of the new pointer to the passed + string. This is equivalent to: + </para> + <programlisting>talloc_set_name_const(ptr, ptr)</programlisting> + </refsect2> + <refsect2><title>char *talloc_strndup(const void *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">p</emphasis>, size_t <emphasis role="italic">n</emphasis>);</title> + <para> + The talloc_strndup() function is the talloc equivalent of the C + library function strndup(3). + </para> + <para> + This function sets the name of the new pointer to the passed + string. This is equivalent to: + </para> + <programlisting>talloc_set_name_const(ptr, ptr)</programlisting> + </refsect2> + <refsect2><title>char *talloc_vasprintf(const void *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, va_list <emphasis role="italic">ap</emphasis>);</title> + <para> + The talloc_vasprintf() function is the talloc equivalent of the C + library function vasprintf(3). + </para> + <para> + This function sets the name of the new pointer to the new + string. This is equivalent to: + </para> + <programlisting>talloc_set_name_const(ptr, ptr)</programlisting> + </refsect2> + <refsect2><title>char *talloc_asprintf(const void *<emphasis role="italic">t</emphasis>, const char *<emphasis role="italic">fmt</emphasis>, ...);</title> + <para> + The talloc_asprintf() function is the talloc equivalent of the C + library function asprintf(3). + </para> + <para> + This function sets the name of the new pointer to the passed + string. This is equivalent to: + </para> + <programlisting>talloc_set_name_const(ptr, ptr)</programlisting> + </refsect2> + <refsect2><title>char *talloc_asprintf_append(char *s, const char *fmt, ...);</title> + <para> + The talloc_asprintf_append() function appends the given formatted + string to the given string. + </para> + <para> + This function sets the name of the new pointer to the new + string. This is equivalent to: + </para> + <programlisting>talloc_set_name_const(ptr, ptr)</programlisting> + </refsect2> + <refsect2><title>(type *)talloc_array(const void *ctx, type, unsigned int count);</title> + <para> + The talloc_array() macro is equivalent to: + </para> + <programlisting>(type *)talloc_size(ctx, sizeof(type) * count);</programlisting> + <para> + except that it provides integer overflow protection for the + multiply, returning NULL if the multiply overflows. + </para> + </refsect2> + <refsect2><title>void *talloc_array_size(const void *ctx, size_t size, unsigned int count);</title> + <para> + The talloc_array_size() function is useful when the type is not + known. It operates in the same way as talloc_array(), but takes a + size instead of a type. + </para> + </refsect2> + <refsect2><title>(typeof(ptr)) talloc_array_ptrtype(const void *ctx, ptr, unsigned int count);</title> + <para> + The talloc_ptrtype() macro should be used when you have a pointer to an array + and want to allocate memory of an array to point at with this pointer. When compiling + with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_array_size() + and talloc_get_name() will return the current location in the source file. + and not the type. + </para> + </refsect2> + <refsect2><title>void *talloc_realloc_fn(const void *ctx, void *ptr, size_t size)</title> + <para> + This is a non-macro version of talloc_realloc(), which is useful + as libraries sometimes want a realloc function pointer. A + realloc(3) implementation encapsulates the functionality of + malloc(3), free(3) and realloc(3) in one call, which is why it is + useful to be able to pass around a single function pointer. + </para> + </refsect2> + <refsect2><title>void *talloc_autofree_context(void);</title> + <para> + This is a handy utility function that returns a talloc context + which will be automatically freed on program exit. This can be + used to reduce the noise in memory leak reports. + </para> + </refsect2> + <refsect2><title>void *talloc_check_name(const void *ptr, const char *name);</title> + <para> + This function checks if a pointer has the specified <emphasis + role="italic">name</emphasis>. If it does then the pointer is + returned. It it doesn't then NULL is returned. + </para> + </refsect2> + <refsect2><title>(type *)talloc_get_type(const void *ptr, type);</title> + <para> + This macro allows you to do type checking on talloc pointers. It + is particularly useful for void* private pointers. It is + equivalent to this: + </para> + <programlisting>(type *)talloc_check_name(ptr, #type)</programlisting> + </refsect2> + <refsect2><title>talloc_set_type(const void *ptr, type);</title> + <para> + This macro allows you to force the name of a pointer to be a + particular <emphasis>type</emphasis>. This can be + used in conjunction with talloc_get_type() to do type checking on + void* pointers. + </para> + <para> + It is equivalent to this: + </para> + <programlisting>talloc_set_name_const(ptr, #type)</programlisting> + </refsect2> + <refsect2><title>talloc_set_log_fn(void (*log_fn)(const char *message));</title> + <para> + This function sets a logging function that talloc will use for + warnings and errors. By default talloc will not print any warnings or + errors. + </para> + </refsect2> + <refsect2><title>talloc_set_log_stderr(void);</title> + <para> + This sets the talloc log function to write log messages to stderr + </para> + </refsect2> + </refsect1> + <refsect1><title>PERFORMANCE</title> + <para> + All the additional features of talloc(3) over malloc(3) do come at a + price. We have a simple performance test in Samba4 that measures + talloc() versus malloc() performance, and it seems that talloc() is + about 10% slower than malloc() on my x86 Debian Linux box. For + Samba, the great reduction in code complexity that we get by using + talloc makes this worthwhile, especially as the total overhead of + talloc/malloc in Samba is already quite small. + </para> + </refsect1> + <refsect1><title>SEE ALSO</title> + <para> + malloc(3), strndup(3), vasprintf(3), asprintf(3), + <ulink url="http://talloc.samba.org/"/> + </para> + </refsect1> + + <refsect1><title>AUTHOR</title> + <para> The original Samba software and related utilities were + created by Andrew Tridgell. Samba is now developed by the + Samba Team as an Open Source project similar to the way the + Linux kernel is developed. + </para> + </refsect1> + + <refsect1><title>COPYRIGHT/LICENSE</title> + <para> + Copyright (C) Andrew Tridgell 2004 + </para> + <para> + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU Lesser General Public License as + published by the Free Software Foundation; either version 3 of the + License, or (at your option) any later version. + </para> + <para> + 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. + </para> + <para> + You should have received a copy of the GNU General Public License + along with this program; if not, see http://www.gnu.org/licenses/. + </para> + </refsect1> +</refentry> diff --git a/lib/talloc/pytalloc-util.pc.in b/lib/talloc/pytalloc-util.pc.in new file mode 100644 index 0000000..06f83e2 --- /dev/null +++ b/lib/talloc/pytalloc-util.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: pytalloc-util@PYTHON_SO_ABI_FLAG@ +Description: Utility functions for using talloc objects with Python +Version: @TALLOC_VERSION@ +Libs: @LIB_RPATH@ -L${libdir} -lpytalloc-util@PYTHON_LIBNAME_SO_ABI_FLAG@ +Cflags: -I${includedir} +URL: http://talloc.samba.org/ diff --git a/lib/talloc/pytalloc.c b/lib/talloc/pytalloc.c new file mode 100644 index 0000000..41decc4 --- /dev/null +++ b/lib/talloc/pytalloc.c @@ -0,0 +1,313 @@ +/* + Unix SMB/CIFS implementation. + Python Talloc Module + Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2010-2011 + + ** NOTE! The following LGPL license applies to the talloc + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include <Python.h> +#include <talloc.h> +#include <pytalloc.h> +#include "pytalloc_private.h" + +static PyTypeObject TallocObject_Type; + +/* print a talloc tree report for a talloc python object */ +static PyObject *pytalloc_report_full(PyObject *self, PyObject *args) +{ + PyObject *py_obj = Py_None; + + if (!PyArg_ParseTuple(args, "|O", &py_obj)) + return NULL; + + if (py_obj == Py_None) { + talloc_report_full(NULL, stdout); + } else { + talloc_report_full(pytalloc_get_mem_ctx(py_obj), stdout); + } + Py_RETURN_NONE; +} + +/* enable null tracking */ +static PyObject *pytalloc_enable_null_tracking(PyObject *self, + PyObject *Py_UNUSED(ignored)) +{ + talloc_enable_null_tracking(); + Py_RETURN_NONE; +} + +/* return the number of talloc blocks */ +static PyObject *pytalloc_total_blocks(PyObject *self, PyObject *args) +{ + PyObject *py_obj = Py_None; + + if (!PyArg_ParseTuple(args, "|O", &py_obj)) + return NULL; + + if (py_obj == Py_None) { + return PyLong_FromLong(talloc_total_blocks(NULL)); + } + + return PyLong_FromLong(talloc_total_blocks(pytalloc_get_mem_ctx(py_obj))); +} + +static PyMethodDef talloc_methods[] = { + { "report_full", (PyCFunction)pytalloc_report_full, METH_VARARGS, + "show a talloc tree for an object"}, + { "enable_null_tracking", (PyCFunction)pytalloc_enable_null_tracking, METH_NOARGS, + "enable tracking of the NULL object"}, + { "total_blocks", (PyCFunction)pytalloc_total_blocks, METH_VARARGS, + "return talloc block count"}, + {0} +}; + +/** + * Default (but only slightly more useful than the default) implementation of Repr(). + */ +static PyObject *pytalloc_default_repr(PyObject *obj) +{ + pytalloc_Object *talloc_obj = (pytalloc_Object *)obj; + PyTypeObject *type = (PyTypeObject*)PyObject_Type(obj); + + return PyUnicode_FromFormat("<%s talloc object at %p>", + type->tp_name, talloc_obj->ptr); +} + +/** + * Simple dealloc for talloc-wrapping PyObjects + */ +static void pytalloc_dealloc(PyObject* self) +{ + pytalloc_Object *obj = (pytalloc_Object *)self; + assert(talloc_unlink(NULL, obj->talloc_ctx) != -1); + obj->talloc_ctx = NULL; + self->ob_type->tp_free(self); +} + +/** + * Default (but only slightly more useful than the default) implementation of cmp. + */ +#if PY_MAJOR_VERSION >= 3 +static PyObject *pytalloc_default_richcmp(PyObject *obj1, PyObject *obj2, int op) +{ + void *ptr1; + void *ptr2; + if (Py_TYPE(obj1) == Py_TYPE(obj2)) { + /* When types match, compare pointers */ + ptr1 = pytalloc_get_ptr(obj1); + ptr2 = pytalloc_get_ptr(obj2); + } else if (PyObject_TypeCheck(obj2, &TallocObject_Type)) { + /* Otherwise, compare types */ + ptr1 = Py_TYPE(obj1); + ptr2 = Py_TYPE(obj2); + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + switch (op) { + case Py_EQ: return PyBool_FromLong(ptr1 == ptr2); + case Py_NE: return PyBool_FromLong(ptr1 != ptr2); + case Py_LT: return PyBool_FromLong(ptr1 < ptr2); + case Py_GT: return PyBool_FromLong(ptr1 > ptr2); + case Py_LE: return PyBool_FromLong(ptr1 <= ptr2); + case Py_GE: return PyBool_FromLong(ptr1 >= ptr2); + } + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} +#else +static int pytalloc_default_cmp(PyObject *_obj1, PyObject *_obj2) +{ + pytalloc_Object *obj1 = (pytalloc_Object *)_obj1, + *obj2 = (pytalloc_Object *)_obj2; + if (obj1->ob_type != obj2->ob_type) + return ((char *)obj1->ob_type - (char *)obj2->ob_type); + + return ((char *)pytalloc_get_ptr(obj1) - (char *)pytalloc_get_ptr(obj2)); +} +#endif + +static PyTypeObject TallocObject_Type = { + .tp_name = "talloc.Object", + .tp_doc = "Python wrapper for a talloc-maintained object.", + .tp_basicsize = sizeof(pytalloc_Object), + .tp_dealloc = (destructor)pytalloc_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_repr = pytalloc_default_repr, +#if PY_MAJOR_VERSION >= 3 + .tp_richcompare = pytalloc_default_richcmp, +#else + .tp_compare = pytalloc_default_cmp, +#endif +}; + +/** + * Default (but only slightly more useful than the default) implementation of Repr(). + */ +static PyObject *pytalloc_base_default_repr(PyObject *obj) +{ + pytalloc_BaseObject *talloc_obj = (pytalloc_BaseObject *)obj; + PyTypeObject *type = (PyTypeObject*)PyObject_Type(obj); + + return PyUnicode_FromFormat("<%s talloc based object at %p>", + type->tp_name, talloc_obj->ptr); +} + +/** + * Simple dealloc for talloc-wrapping PyObjects + */ +static void pytalloc_base_dealloc(PyObject* self) +{ + pytalloc_BaseObject *obj = (pytalloc_BaseObject *)self; + assert(talloc_unlink(NULL, obj->talloc_ctx) != -1); + obj->talloc_ctx = NULL; + self->ob_type->tp_free(self); +} + +/** + * Default (but only slightly more useful than the default) implementation of cmp. + */ +#if PY_MAJOR_VERSION >= 3 +static PyObject *pytalloc_base_default_richcmp(PyObject *obj1, PyObject *obj2, int op) +{ + void *ptr1; + void *ptr2; + if (Py_TYPE(obj1) == Py_TYPE(obj2)) { + /* When types match, compare pointers */ + ptr1 = pytalloc_get_ptr(obj1); + ptr2 = pytalloc_get_ptr(obj2); + } else if (PyObject_TypeCheck(obj2, &TallocObject_Type)) { + /* Otherwise, compare types */ + ptr1 = Py_TYPE(obj1); + ptr2 = Py_TYPE(obj2); + } else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } + switch (op) { + case Py_EQ: return PyBool_FromLong(ptr1 == ptr2); + case Py_NE: return PyBool_FromLong(ptr1 != ptr2); + case Py_LT: return PyBool_FromLong(ptr1 < ptr2); + case Py_GT: return PyBool_FromLong(ptr1 > ptr2); + case Py_LE: return PyBool_FromLong(ptr1 <= ptr2); + case Py_GE: return PyBool_FromLong(ptr1 >= ptr2); + } + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; +} +#else +static int pytalloc_base_default_cmp(PyObject *_obj1, PyObject *_obj2) +{ + pytalloc_BaseObject *obj1 = (pytalloc_BaseObject *)_obj1, + *obj2 = (pytalloc_BaseObject *)_obj2; + if (obj1->ob_type != obj2->ob_type) + return ((char *)obj1->ob_type - (char *)obj2->ob_type); + + return ((char *)pytalloc_get_ptr(obj1) - (char *)pytalloc_get_ptr(obj2)); +} +#endif + +static PyTypeObject TallocBaseObject_Type = { + .tp_name = "talloc.BaseObject", + .tp_doc = "Python wrapper for a talloc-maintained object.", + .tp_basicsize = sizeof(pytalloc_BaseObject), + .tp_dealloc = (destructor)pytalloc_base_dealloc, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_repr = pytalloc_base_default_repr, +#if PY_MAJOR_VERSION >= 3 + .tp_richcompare = pytalloc_base_default_richcmp, +#else + .tp_compare = pytalloc_base_default_cmp, +#endif +}; + +static PyTypeObject TallocGenericObject_Type = { + .tp_name = "talloc.GenericObject", + .tp_doc = "Python wrapper for a talloc-maintained object.", + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_base = &TallocBaseObject_Type, + .tp_basicsize = sizeof(pytalloc_BaseObject), +}; + +#define MODULE_DOC PyDoc_STR("Python wrapping of talloc-maintained objects.") + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + .m_name = "talloc", + .m_doc = MODULE_DOC, + .m_size = -1, + .m_methods = talloc_methods, +}; +#endif + +static PyObject *module_init(void); +static PyObject *module_init(void) +{ + PyObject *m; + + if (PyType_Ready(&TallocObject_Type) < 0) + return NULL; + + if (PyType_Ready(&TallocBaseObject_Type) < 0) + return NULL; + + if (PyType_Ready(&TallocGenericObject_Type) < 0) + return NULL; + +#if PY_MAJOR_VERSION >= 3 + m = PyModule_Create(&moduledef); +#else + m = Py_InitModule3("talloc", talloc_methods, MODULE_DOC); +#endif + if (m == NULL) + return NULL; + + Py_INCREF(&TallocObject_Type); + if (PyModule_AddObject(m, "Object", (PyObject *)&TallocObject_Type)) { + goto err; + } + Py_INCREF(&TallocBaseObject_Type); + if (PyModule_AddObject(m, "BaseObject", (PyObject *)&TallocBaseObject_Type)) { + goto err; + } + Py_INCREF(&TallocGenericObject_Type); + if (PyModule_AddObject(m, "GenericObject", (PyObject *)&TallocGenericObject_Type)) { + goto err; + } + return m; + +err: + Py_DECREF(m); + return NULL; +} + +#if PY_MAJOR_VERSION >= 3 +PyMODINIT_FUNC PyInit_talloc(void); +PyMODINIT_FUNC PyInit_talloc(void) +{ + return module_init(); +} +#else +void inittalloc(void); +void inittalloc(void) +{ + module_init(); +} +#endif diff --git a/lib/talloc/pytalloc.h b/lib/talloc/pytalloc.h new file mode 100644 index 0000000..c1f9b44 --- /dev/null +++ b/lib/talloc/pytalloc.h @@ -0,0 +1,87 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008 + + ** NOTE! The following LGPL license applies to the talloc + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#ifndef _PYTALLOC_H_ +#define _PYTALLOC_H_ + +#include <Python.h> +#include <talloc.h> + +typedef struct { + PyObject_HEAD + TALLOC_CTX *talloc_ctx; + void *ptr; /* eg the array element */ +} pytalloc_Object; + +/* Return the PyTypeObject for pytalloc_Object. Returns a borrowed reference. */ +_PUBLIC_ PyTypeObject *pytalloc_GetObjectType(void); + +/* Return the PyTypeObject for pytalloc_BaseObject. Returns a borrowed reference. */ +_PUBLIC_ PyTypeObject *pytalloc_GetBaseObjectType(void); + +/* Check whether a specific object is a talloc Object. */ +_PUBLIC_ int pytalloc_Check(PyObject *); + +_PUBLIC_ int pytalloc_BaseObject_check(PyObject *); + +_PUBLIC_ int _pytalloc_check_type(PyObject *py_obj, const char *type_name); +#define pytalloc_check_type(py_obj, type) \ + _pytalloc_check_type((PyObject *)(py_obj), #type) + +/* Retrieve the pointer for a pytalloc_object. Like talloc_get_type() + * but for pytalloc_Objects. */ +_PUBLIC_ void *_pytalloc_get_type(PyObject *py_obj, const char *type_name); +#define pytalloc_get_type(py_obj, type) ((type *)_pytalloc_get_type((PyObject *)(py_obj), #type)) + +_PUBLIC_ void *_pytalloc_get_ptr(PyObject *py_obj); +#define pytalloc_get_ptr(py_obj) _pytalloc_get_ptr((PyObject *)(py_obj)) +_PUBLIC_ TALLOC_CTX *_pytalloc_get_mem_ctx(PyObject *py_obj); +#define pytalloc_get_mem_ctx(py_obj) _pytalloc_get_mem_ctx((PyObject *)(py_obj)) + +_PUBLIC_ const char *_pytalloc_get_name(PyObject *py_obj); +#define pytalloc_get_name(py_obj) _pytalloc_get_name((PyObject *)(py_obj)) + + +_PUBLIC_ PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr); +_PUBLIC_ PyObject *pytalloc_steal(PyTypeObject *py_type, void *ptr); +_PUBLIC_ PyObject *pytalloc_reference_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr); +#define pytalloc_reference(py_type, talloc_ptr) pytalloc_reference_ex(py_type, talloc_ptr, talloc_ptr) + +#define pytalloc_new(type, typeobj) pytalloc_steal(typeobj, talloc_zero(NULL, type)) + +/* + * Wrap a generic talloc pointer into a talloc.GenericObject, + * this is a subclass of talloc.BaseObject. + */ +_PUBLIC_ PyObject *pytalloc_GenericObject_steal_ex(TALLOC_CTX *mem_ctx, void *ptr); +#define pytalloc_GenericObject_steal(talloc_ptr) \ + pytalloc_GenericObject_steal_ex(talloc_ptr, talloc_ptr) +_PUBLIC_ PyObject *pytalloc_GenericObject_reference_ex(TALLOC_CTX *mem_ctx, void *ptr); +#define pytalloc_GenericObject_reference(talloc_ptr) \ + pytalloc_GenericObject_reference_ex(talloc_ptr, talloc_ptr) + +_PUBLIC_ size_t pytalloc_BaseObject_size(void); + +_PUBLIC_ int pytalloc_BaseObject_PyType_Ready(PyTypeObject *type); + +#endif /* _PYTALLOC_H_ */ diff --git a/lib/talloc/pytalloc_guide.txt b/lib/talloc/pytalloc_guide.txt new file mode 100644 index 0000000..bd2b68c --- /dev/null +++ b/lib/talloc/pytalloc_guide.txt @@ -0,0 +1,252 @@ +Using talloc in Samba4 +====================== + +.. contents:: + +Jelmer Vernooij +August 2013 + +The most current version of this document is available at + http://samba.org/ftp/unpacked/talloc/pytalloc_guide.txt + +pytalloc is a small library that provides glue for wrapping +talloc-allocated objects from C in Python objects. + +What is pytalloc, and what is it not? +------------------------------------- + +pytalloc is merely a helper library - it provides a convenient base type object +for objects that wrap talloc-maintained memory in C. It won't write your +bindings for you but it will make it easier to write C bindings that involve +talloc, and take away some of the boiler plate. + +Python 3 +-------- + +pytalloc can be used with Python 3. Usage from Python extension remains +the same, but for the C utilities, the library to link to is tagged with +Python's PEP3149 ABI tag, for example "pytalloc.cpython34m". +To make a build for Python 3, configure with PYTHON=/usr/bin/python3. +. +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +pytalloc_Object / pytalloc_BaseObject + +This is the new base class that all Python objects that wrap talloc pointers +derive from. It is itself a subclass of the "Object" type that all objects +in Python derive from. + +Note that you will almost never create objects of the pytalloc_Object type +itself, as they are just opaque pointers that can not be accessed from +Python. A common pattern is other objects that subclass pytalloc_Object and +rely on it for their memory management. + +Each `pytalloc_Object` wraps two core of information - a talloc context +and a pointer. The pointer is the actual data that is wrapped. The talloc +context is used for memory management purposes only; when the wrapping Python object +goes away, it unlinks the talloc context. The talloc context pointer and the ptr +can (and often do) have the same value. + +Each pytalloc_Object has a custom __repr__ implementation that +describes that it is a talloc object and the location of the +pointer it is wrapping. it also has a custom __cmp__/__eq__/__neq__ method that +compares the pointers the object is wrapping rather than the objects +themselves (since there can be multiple objects that wrap the same talloc +pointer). + +It is preferred to use pytalloc_BaseObject as this implementation +exposes less in the C ABI and correctly supports pointers in C arrays +in the way needed by PIDL. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +PyTypeObject *pytalloc_GetObjectType(void) + +Obtain a pointer to the PyTypeObject for `pytalloc_Object`. The +reference counter for the object will be NOT incremented, so the +caller MUST NOT decrement it when it no longer needs it (eg by using +`Py_DECREF`). + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +PyTypeObject *pytalloc_GetBaseObjectType(void) + +Obtain a pointer to the PyTypeObject for `pytalloc_BaseObject`. The +reference counter for the object will be NOT incremented, so the +caller MUST NOT decrement it when it no longer needs it (eg by using +`Py_DECREF`). + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +int pytalloc_BaseObject_PyType_Ready(PyTypeObject *type); + +Wrapper for PyType_Ready() that will set the correct values into +the PyTypeObject to create a BaseObject + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=- +int pytalloc_Check(PyObject *) + +Check whether a specific object is a talloc Object. Returns non-zero if it is +a pytalloc_Object and zero otherwise. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-==-=-=-=-=-=-=-=-=-=-=- +int pytalloc_BaseObject_Check(PyObject *) + +Check whether a specific object is a talloc BaseObject. Returns non-zero if it is +a pytalloc_BaseObject and zero otherwise. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +int pytalloc_check_type(PyObject *py_obj, type) + +Check if the object based on `pytalloc_*Object` py_obj. type should be a +C type, similar to a type passed to `talloc_get_type`. +This can be used as a check before using pytalloc_get_type() +or an alternative codepath. Returns non-zero if it is +an object of the expected type and zero otherwise. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +type *pytalloc_get_type(PyObject *py_obj, type) + +Retrieve the pointer from a `pytalloc_Object` py_obj. type should be a +C type, similar to a type passed to `talloc_get_type`. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +pytalloc_get_ptr(PyObject *py_obj) + +Retrieve the pointer from a `pytalloc_Object` or `pytalloc_BaseObject` +py_obj. There is no type checking - use `pytalloc_get_type` if +possible. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +TALLOC_CTX *pytalloc_get_mem_ctx(PyObject *py_obj) + +Retrieve the talloc context associated with a pytalloc_Object or pytalloc_BaseObject. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr) + +Create a new Python wrapping object for a talloc pointer and context, with +py_type as associated Python sub type object. This typically used +when `mem_ctx` and `ptr` differ, e.g. a pointer to an array element. +`pytalloc_get_ptr()` can be used to get the pointer out of the object again. + +This will *not* increment the reference counter for the talloc context, +so the caller should make sure such an increment has happened. When the Python +object goes away, it will unreference the talloc context. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +PyObject *pytalloc_steal(PyTypeObject *py_type, void *ptr) + +Create a new Python wrapping object for a talloc pointer and context, with +py_type as associated Python sub type object. The pointer will also be used +as the talloc context. `pytalloc_get_type()` can be used to get +the pointer out of the object again. + +This will *not* increment the reference counter for the talloc context, +so the caller should make sure such an increment has happened. When the Python +object goes away, it will unreference the talloc context. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +PyObject *pytalloc_reference_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, void *ptr) + +Create a new Python wrapping object for a talloc pointer and context, with +py_type as associated Python sub type object. This typically used +when `mem_ctx` and `ptr` differ, e.g. a pointer to an array element. +`pytalloc_get_ptr()` can be used to get the pointer out of the object again. + +This will increment the reference counter for the talloc context. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +PyObject *pytalloc_reference(PyTypeObject *py_type, void *talloc_ptr) + +Create a new Python wrapping object for a talloc pointer, with +py_type as associated Python sub type object. The pointer will also be used +as the talloc context. `pytalloc_get_type()` can be used to get +the pointer out of the object again. + +This will increment the reference counter for the talloc context. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +PyObject *pytalloc_new(type, PyTypeObject *typeobj) + +Create a new, empty pytalloc_Object with the specified Python type object. type +should be a C type, similar to talloc_new(). + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +PyObject *pytalloc_GenericObject_steal_ex(void *ptr) + +Create a new Python wrapping object for a generic talloc pointer, +as sub type of `pytalloc_BaseObject`. This typically used +when `mem_ctx` and `ptr` differ, e.g. a pointer to an array element. +`pytalloc_get_ptr()` can be used to get the pointer out of the object again. + +This will *not* increment the reference counter for the talloc context, +so the caller should make sure such an increment has happened. When the Python +object goes away, it will unreference the talloc context. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +PyObject *pytalloc_GenericObject_steal(void *ptr) + +Create a new Python wrapping object for a generic talloc pointer, +as sub type of `pytalloc_BaseObject`. The pointer will also be used +as the talloc context. `pytalloc_get_type()` can be used to get +the pointer out of the object again. + +This will *not* increment the reference counter for the talloc context, +so the caller should make sure such an increment has happened. When the Python +object goes away, it will unreference the talloc context. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +PyObject *pytalloc_GenericObject_reference_ex(void *ptr) + +Create a new Python wrapping object for a generic talloc pointer, +as sub type of `pytalloc_BaseObject`. This typically used +when `mem_ctx` and `ptr` differ, e.g. a pointer to an array element. +`pytalloc_get_ptr()` can be used to get the pointer out of the object again. + +This will increment the reference counter for the talloc context. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +PyObject *pytalloc_GenericObject_reference(void *ptr) + +Create a new Python wrapping object for a generic talloc pointer, +as sub type of `pytalloc_BaseObject`. The pointer will also be used +as the talloc context. `pytalloc_get_type()` can be used to get +the pointer out of the object again. + +This will increment the reference counter for the talloc context. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +DEPRECATED! PyObject *pytalloc_CObject_FromTallocPtr(void *); + +Create a new pytalloc_Object for an abitrary talloc-maintained C pointer. This will +use a generic VoidPtr Python type, which just provides an opaque object in +Python. The caller is responsible for incrementing the talloc reference count before calling +this function - it will dereference the talloc pointer when it is garbage collected. + +This function is deprecated and only available on Python 2. +Use pytalloc_GenericObject_{reference,steal}[_ex]() instead. + +Debug function for talloc in Python +----------------------------------- + +The "talloc" module in Python provides a couple of functions that can be used +to debug issues with objects wrapped by pytalloc. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +report_full(obj?) + +Print a full report on a specific object or on all allocated objects by Python. +Same behaviour as the `talloc_report_full()` function that is provided by +C talloc. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +enable_null_tracking() + +This enables tracking of the NULL memory context without enabling leak +reporting on exit. Useful for when you want to do your own leak +reporting call via talloc_report_null_full(). + +This must be done in the top level script, not an imported module. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +pytalloc_total_blocks(obj?) + +Return the talloc block count for all allocated objects or a specific object if +specified. diff --git a/lib/talloc/pytalloc_private.h b/lib/talloc/pytalloc_private.h new file mode 100644 index 0000000..b23cdfc --- /dev/null +++ b/lib/talloc/pytalloc_private.h @@ -0,0 +1,26 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008 + Copyright (C) Andrew Bartlett <abartlet@samba.org> 2016 + + 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 3 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, see <http://www.gnu.org/licenses/>. +*/ + +typedef struct { + PyObject_HEAD + TALLOC_CTX *talloc_ctx; + TALLOC_CTX *talloc_ptr_ctx; /* eg the start of the array */ + void *ptr; /* eg the array element */ +} pytalloc_BaseObject; diff --git a/lib/talloc/pytalloc_util.c b/lib/talloc/pytalloc_util.c new file mode 100644 index 0000000..1b7cfdd --- /dev/null +++ b/lib/talloc/pytalloc_util.c @@ -0,0 +1,334 @@ +/* + Unix SMB/CIFS implementation. + Python/Talloc glue + Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2008 + + ** NOTE! The following LGPL license applies to the talloc + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include <Python.h> +#include "replace.h" +#include <talloc.h> +#include "pytalloc.h" +#include <assert.h> +#include "pytalloc_private.h" + +static PyObject *pytalloc_steal_or_reference(PyTypeObject *py_type, + TALLOC_CTX *mem_ctx, void *ptr, bool steal); + +_PUBLIC_ PyTypeObject *pytalloc_GetObjectType(void) +{ + static PyTypeObject *type = NULL; + PyObject *mod; + + mod = PyImport_ImportModule("talloc"); + if (mod == NULL) { + return NULL; + } + + type = (PyTypeObject *)PyObject_GetAttrString(mod, "Object"); + Py_DECREF(mod); + + return type; +} + +_PUBLIC_ PyTypeObject *pytalloc_GetBaseObjectType(void) +{ + static PyTypeObject *type = NULL; + PyObject *mod; + + mod = PyImport_ImportModule("talloc"); + if (mod == NULL) { + return NULL; + } + + type = (PyTypeObject *)PyObject_GetAttrString(mod, "BaseObject"); + Py_DECREF(mod); + + return type; +} + +static PyTypeObject *pytalloc_GetGenericObjectType(void) +{ + static PyTypeObject *type = NULL; + PyObject *mod; + + mod = PyImport_ImportModule("talloc"); + if (mod == NULL) { + return NULL; + } + + type = (PyTypeObject *)PyObject_GetAttrString(mod, "GenericObject"); + Py_DECREF(mod); + + return type; +} + +/** + * Import an existing talloc pointer into a Python object. + */ +_PUBLIC_ PyObject *pytalloc_steal_ex(PyTypeObject *py_type, TALLOC_CTX *mem_ctx, + void *ptr) +{ + return pytalloc_steal_or_reference(py_type, mem_ctx, ptr, true); +} + +/** + * Import an existing talloc pointer into a Python object. + */ +_PUBLIC_ PyObject *pytalloc_steal(PyTypeObject *py_type, void *ptr) +{ + return pytalloc_steal_or_reference(py_type, ptr, ptr, true); +} + + +/** + * Import an existing talloc pointer into a Python object, leaving the + * original parent, and creating a reference to the object in the python + * object. + * + * We remember the object we hold the reference to (a + * possibly-non-talloc pointer), the existing parent (typically the + * start of the array) and the new referenced parent. That way we can + * cope with the fact that we will have multiple parents, one per time + * python sees the object. + */ +_PUBLIC_ PyObject *pytalloc_reference_ex(PyTypeObject *py_type, + TALLOC_CTX *mem_ctx, void *ptr) +{ + return pytalloc_steal_or_reference(py_type, mem_ctx, ptr, false); +} + + +/** + * Internal function that either steals or referecences the talloc + * pointer into a new talloc context. + */ +static PyObject *pytalloc_steal_or_reference(PyTypeObject *py_type, + TALLOC_CTX *mem_ctx, void *ptr, bool steal) +{ + bool ok = false; + TALLOC_CTX *talloc_ctx = NULL; + bool is_baseobject = false; + PyObject *obj = NULL; + PyTypeObject *BaseObjectType = NULL, *ObjectType = NULL; + + BaseObjectType = pytalloc_GetBaseObjectType(); + if (BaseObjectType == NULL) { + goto err; + } + ObjectType = pytalloc_GetObjectType(); + if (ObjectType == NULL) { + goto err; + } + + /* this should have been tested by caller */ + if (mem_ctx == NULL) { + return PyErr_NoMemory(); + } + + is_baseobject = PyType_IsSubtype(py_type, BaseObjectType); + if (!is_baseobject) { + if (!PyType_IsSubtype(py_type, ObjectType)) { + PyErr_SetString(PyExc_TypeError, + "Expected type based on talloc"); + return NULL; + } + } + + obj = py_type->tp_alloc(py_type, 0); + if (obj == NULL) { + goto err; + } + + talloc_ctx = talloc_new(NULL); + if (talloc_ctx == NULL) { + PyErr_NoMemory(); + goto err; + } + + if (steal) { + ok = (talloc_steal(talloc_ctx, mem_ctx) != NULL); + } else { + ok = (talloc_reference(talloc_ctx, mem_ctx) != NULL); + } + if (!ok) { + goto err; + } + talloc_set_name_const(talloc_ctx, py_type->tp_name); + + if (is_baseobject) { + pytalloc_BaseObject *ret = (pytalloc_BaseObject*)obj; + ret->talloc_ctx = talloc_ctx; + ret->talloc_ptr_ctx = mem_ctx; + ret->ptr = ptr; + } else { + pytalloc_Object *ret = (pytalloc_Object*)obj; + ret->talloc_ctx = talloc_ctx; + ret->ptr = ptr; + } + return obj; + +err: + TALLOC_FREE(talloc_ctx); + Py_XDECREF(obj); + return NULL; +} + +/* + * Wrap a generic talloc pointer into a talloc.GenericObject, + * this is a subclass of talloc.BaseObject. + */ +_PUBLIC_ PyObject *pytalloc_GenericObject_steal_ex(TALLOC_CTX *mem_ctx, void *ptr) +{ + PyTypeObject *tp = pytalloc_GetGenericObjectType(); + return pytalloc_steal_ex(tp, mem_ctx, ptr); +} + +/* + * Wrap a generic talloc pointer into a talloc.GenericObject, + * this is a subclass of talloc.BaseObject. + */ +_PUBLIC_ PyObject *pytalloc_GenericObject_reference_ex(TALLOC_CTX *mem_ctx, void *ptr) +{ + PyTypeObject *tp = pytalloc_GetGenericObjectType(); + return pytalloc_reference_ex(tp, mem_ctx, ptr); +} + +_PUBLIC_ int pytalloc_Check(PyObject *obj) +{ + PyTypeObject *tp = pytalloc_GetObjectType(); + + return PyObject_TypeCheck(obj, tp); +} + +_PUBLIC_ int pytalloc_BaseObject_check(PyObject *obj) +{ + PyTypeObject *tp = pytalloc_GetBaseObjectType(); + + return PyObject_TypeCheck(obj, tp); +} + +_PUBLIC_ size_t pytalloc_BaseObject_size(void) +{ + return sizeof(pytalloc_BaseObject); +} + +static void *_pytalloc_get_checked_type(PyObject *py_obj, const char *type_name, + bool check_only, const char *function) +{ + TALLOC_CTX *mem_ctx; + void *ptr = NULL; + void *type_obj; + + mem_ctx = _pytalloc_get_mem_ctx(py_obj); + ptr = _pytalloc_get_ptr(py_obj); + + if (mem_ctx != ptr || ptr == NULL) { + if (check_only) { + return NULL; + } + + PyErr_Format(PyExc_TypeError, "%s: expected %s, " + "but the pointer is no talloc pointer, " + "pytalloc_get_ptr() would get the raw pointer.", + function, type_name); + return NULL; + } + + type_obj = talloc_check_name(ptr, type_name); + if (type_obj == NULL) { + const char *name = NULL; + + if (check_only) { + return NULL; + } + + name = talloc_get_name(ptr); + PyErr_Format(PyExc_TypeError, "%s: expected %s, got %s", + function, type_name, name); + return NULL; + } + + return ptr; +} + +_PUBLIC_ int _pytalloc_check_type(PyObject *py_obj, const char *type_name) +{ + void *ptr = NULL; + + ptr = _pytalloc_get_checked_type(py_obj, type_name, + true, /* check_only */ + "pytalloc_check_type"); + if (ptr == NULL) { + return 0; + } + + return 1; +} + +_PUBLIC_ void *_pytalloc_get_type(PyObject *py_obj, const char *type_name) +{ + return _pytalloc_get_checked_type(py_obj, type_name, + false, /* not check_only */ + "pytalloc_get_type"); +} + +_PUBLIC_ void *_pytalloc_get_ptr(PyObject *py_obj) +{ + if (pytalloc_BaseObject_check(py_obj)) { + return ((pytalloc_BaseObject *)py_obj)->ptr; + } + if (pytalloc_Check(py_obj)) { + return ((pytalloc_Object *)py_obj)->ptr; + } + return NULL; +} + +_PUBLIC_ TALLOC_CTX *_pytalloc_get_mem_ctx(PyObject *py_obj) +{ + if (pytalloc_BaseObject_check(py_obj)) { + return ((pytalloc_BaseObject *)py_obj)->talloc_ptr_ctx; + } + if (pytalloc_Check(py_obj)) { + return ((pytalloc_Object *)py_obj)->talloc_ctx; + } + return NULL; +} + +_PUBLIC_ int pytalloc_BaseObject_PyType_Ready(PyTypeObject *type) +{ + PyTypeObject *talloc_type = pytalloc_GetBaseObjectType(); + if (talloc_type == NULL) { + return -1; + } + + type->tp_base = talloc_type; + type->tp_basicsize = pytalloc_BaseObject_size(); + + return PyType_Ready(type); +} + +_PUBLIC_ const char *_pytalloc_get_name(PyObject *obj) +{ + void *ptr = pytalloc_get_ptr(obj); + if (ptr == NULL) { + return "non-talloc object"; + } + return talloc_get_name(ptr); +} diff --git a/lib/talloc/talloc.c b/lib/talloc/talloc.c new file mode 100644 index 0000000..41fa45b --- /dev/null +++ b/lib/talloc/talloc.c @@ -0,0 +1,3072 @@ +/* + Samba Unix SMB/CIFS implementation. + + Samba trivial allocation library - new interface + + NOTE: Please read talloc_guide.txt for full documentation + + Copyright (C) Andrew Tridgell 2004 + Copyright (C) Stefan Metzmacher 2006 + + ** NOTE! The following LGPL license applies to the talloc + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +/* + inspired by http://swapped.cc/halloc/ +*/ + +#include "replace.h" +#include "talloc.h" + +#ifdef HAVE_SYS_AUXV_H +#include <sys/auxv.h> +#endif + +#if (TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR) +#error "TALLOC_VERSION_MAJOR != TALLOC_BUILD_VERSION_MAJOR" +#endif + +#if (TALLOC_VERSION_MINOR != TALLOC_BUILD_VERSION_MINOR) +#error "TALLOC_VERSION_MINOR != TALLOC_BUILD_VERSION_MINOR" +#endif + +/* Special macros that are no-ops except when run under Valgrind on + * x86. They've moved a little bit from valgrind 1.0.4 to 1.9.4 */ +#ifdef HAVE_VALGRIND_MEMCHECK_H + /* memcheck.h includes valgrind.h */ +#include <valgrind/memcheck.h> +#elif defined(HAVE_VALGRIND_H) +#include <valgrind.h> +#endif + +#define MAX_TALLOC_SIZE 0x10000000 + +#define TALLOC_FLAG_FREE 0x01 +#define TALLOC_FLAG_LOOP 0x02 +#define TALLOC_FLAG_POOL 0x04 /* This is a talloc pool */ +#define TALLOC_FLAG_POOLMEM 0x08 /* This is allocated in a pool */ + +/* + * Bits above this are random, used to make it harder to fake talloc + * headers during an attack. Try not to change this without good reason. + */ +#define TALLOC_FLAG_MASK 0x0F + +#define TALLOC_MAGIC_REFERENCE ((const char *)1) + +#define TALLOC_MAGIC_BASE 0xe814ec70 +#define TALLOC_MAGIC_NON_RANDOM ( \ + ~TALLOC_FLAG_MASK & ( \ + TALLOC_MAGIC_BASE + \ + (TALLOC_BUILD_VERSION_MAJOR << 24) + \ + (TALLOC_BUILD_VERSION_MINOR << 16) + \ + (TALLOC_BUILD_VERSION_RELEASE << 8))) +static unsigned int talloc_magic = TALLOC_MAGIC_NON_RANDOM; + +/* by default we abort when given a bad pointer (such as when talloc_free() is called + on a pointer that came from malloc() */ +#ifndef TALLOC_ABORT +#define TALLOC_ABORT(reason) abort() +#endif + +#ifndef discard_const_p +#if defined(__intptr_t_defined) || defined(HAVE_INTPTR_T) +# define discard_const_p(type, ptr) ((type *)((intptr_t)(ptr))) +#else +# define discard_const_p(type, ptr) ((type *)(ptr)) +#endif +#endif + +/* these macros gain us a few percent of speed on gcc */ +#if (__GNUC__ >= 3) +/* the strange !! is to ensure that __builtin_expect() takes either 0 or 1 + as its first argument */ +#ifndef likely +#define likely(x) __builtin_expect(!!(x), 1) +#endif +#ifndef unlikely +#define unlikely(x) __builtin_expect(!!(x), 0) +#endif +#else +#ifndef likely +#define likely(x) (x) +#endif +#ifndef unlikely +#define unlikely(x) (x) +#endif +#endif + +/* this null_context is only used if talloc_enable_leak_report() or + talloc_enable_leak_report_full() is called, otherwise it remains + NULL +*/ +static void *null_context; +static bool talloc_report_null; +static bool talloc_report_null_full; +static void *autofree_context; + +static void talloc_setup_atexit(void); + +/* used to enable fill of memory on free, which can be useful for + * catching use after free errors when valgrind is too slow + */ +static struct { + bool initialised; + bool enabled; + uint8_t fill_value; +} talloc_fill; + +#define TALLOC_FILL_ENV "TALLOC_FREE_FILL" + +/* + * do not wipe the header, to allow the + * double-free logic to still work + */ +#define TC_INVALIDATE_FULL_FILL_CHUNK(_tc) do { \ + if (unlikely(talloc_fill.enabled)) { \ + size_t _flen = (_tc)->size; \ + char *_fptr = (char *)TC_PTR_FROM_CHUNK(_tc); \ + memset(_fptr, talloc_fill.fill_value, _flen); \ + } \ +} while (0) + +#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS) +/* Mark the whole chunk as not accessable */ +#define TC_INVALIDATE_FULL_VALGRIND_CHUNK(_tc) do { \ + size_t _flen = TC_HDR_SIZE + (_tc)->size; \ + char *_fptr = (char *)(_tc); \ + VALGRIND_MAKE_MEM_NOACCESS(_fptr, _flen); \ +} while(0) +#else +#define TC_INVALIDATE_FULL_VALGRIND_CHUNK(_tc) do { } while (0) +#endif + +#define TC_INVALIDATE_FULL_CHUNK(_tc) do { \ + TC_INVALIDATE_FULL_FILL_CHUNK(_tc); \ + TC_INVALIDATE_FULL_VALGRIND_CHUNK(_tc); \ +} while (0) + +#define TC_INVALIDATE_SHRINK_FILL_CHUNK(_tc, _new_size) do { \ + if (unlikely(talloc_fill.enabled)) { \ + size_t _flen = (_tc)->size - (_new_size); \ + char *_fptr = (char *)TC_PTR_FROM_CHUNK(_tc); \ + _fptr += (_new_size); \ + memset(_fptr, talloc_fill.fill_value, _flen); \ + } \ +} while (0) + +#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS) +/* Mark the unused bytes not accessable */ +#define TC_INVALIDATE_SHRINK_VALGRIND_CHUNK(_tc, _new_size) do { \ + size_t _flen = (_tc)->size - (_new_size); \ + char *_fptr = (char *)TC_PTR_FROM_CHUNK(_tc); \ + _fptr += (_new_size); \ + VALGRIND_MAKE_MEM_NOACCESS(_fptr, _flen); \ +} while (0) +#else +#define TC_INVALIDATE_SHRINK_VALGRIND_CHUNK(_tc, _new_size) do { } while (0) +#endif + +#define TC_INVALIDATE_SHRINK_CHUNK(_tc, _new_size) do { \ + TC_INVALIDATE_SHRINK_FILL_CHUNK(_tc, _new_size); \ + TC_INVALIDATE_SHRINK_VALGRIND_CHUNK(_tc, _new_size); \ +} while (0) + +#define TC_UNDEFINE_SHRINK_FILL_CHUNK(_tc, _new_size) do { \ + if (unlikely(talloc_fill.enabled)) { \ + size_t _flen = (_tc)->size - (_new_size); \ + char *_fptr = (char *)TC_PTR_FROM_CHUNK(_tc); \ + _fptr += (_new_size); \ + memset(_fptr, talloc_fill.fill_value, _flen); \ + } \ +} while (0) + +#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED) +/* Mark the unused bytes as undefined */ +#define TC_UNDEFINE_SHRINK_VALGRIND_CHUNK(_tc, _new_size) do { \ + size_t _flen = (_tc)->size - (_new_size); \ + char *_fptr = (char *)TC_PTR_FROM_CHUNK(_tc); \ + _fptr += (_new_size); \ + VALGRIND_MAKE_MEM_UNDEFINED(_fptr, _flen); \ +} while (0) +#else +#define TC_UNDEFINE_SHRINK_VALGRIND_CHUNK(_tc, _new_size) do { } while (0) +#endif + +#define TC_UNDEFINE_SHRINK_CHUNK(_tc, _new_size) do { \ + TC_UNDEFINE_SHRINK_FILL_CHUNK(_tc, _new_size); \ + TC_UNDEFINE_SHRINK_VALGRIND_CHUNK(_tc, _new_size); \ +} while (0) + +#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED) +/* Mark the new bytes as undefined */ +#define TC_UNDEFINE_GROW_VALGRIND_CHUNK(_tc, _new_size) do { \ + size_t _old_used = TC_HDR_SIZE + (_tc)->size; \ + size_t _new_used = TC_HDR_SIZE + (_new_size); \ + size_t _flen = _new_used - _old_used; \ + char *_fptr = _old_used + (char *)(_tc); \ + VALGRIND_MAKE_MEM_UNDEFINED(_fptr, _flen); \ +} while (0) +#else +#define TC_UNDEFINE_GROW_VALGRIND_CHUNK(_tc, _new_size) do { } while (0) +#endif + +#define TC_UNDEFINE_GROW_CHUNK(_tc, _new_size) do { \ + TC_UNDEFINE_GROW_VALGRIND_CHUNK(_tc, _new_size); \ +} while (0) + +struct talloc_reference_handle { + struct talloc_reference_handle *next, *prev; + void *ptr; + const char *location; +}; + +struct talloc_memlimit { + struct talloc_chunk *parent; + struct talloc_memlimit *upper; + size_t max_size; + size_t cur_size; +}; + +static inline bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size); +static inline void talloc_memlimit_grow(struct talloc_memlimit *limit, + size_t size); +static inline void talloc_memlimit_shrink(struct talloc_memlimit *limit, + size_t size); +static inline void tc_memlimit_update_on_free(struct talloc_chunk *tc); + +static inline void _tc_set_name_const(struct talloc_chunk *tc, + const char *name); +static struct talloc_chunk *_vasprintf_tc(const void *t, + const char *fmt, + va_list ap); + +typedef int (*talloc_destructor_t)(void *); + +struct talloc_pool_hdr; + +struct talloc_chunk { + /* + * flags includes the talloc magic, which is randomised to + * make overwrite attacks harder + */ + unsigned flags; + + /* + * If you have a logical tree like: + * + * <parent> + * / | \ + * / | \ + * / | \ + * <child 1> <child 2> <child 3> + * + * The actual talloc tree is: + * + * <parent> + * | + * <child 1> - <child 2> - <child 3> + * + * The children are linked with next/prev pointers, and + * child 1 is linked to the parent with parent/child + * pointers. + */ + + struct talloc_chunk *next, *prev; + struct talloc_chunk *parent, *child; + struct talloc_reference_handle *refs; + talloc_destructor_t destructor; + const char *name; + size_t size; + + /* + * limit semantics: + * if 'limit' is set it means all *new* children of the context will + * be limited to a total aggregate size ox max_size for memory + * allocations. + * cur_size is used to keep track of the current use + */ + struct talloc_memlimit *limit; + + /* + * For members of a pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool" + * is a pointer to the struct talloc_chunk of the pool that it was + * allocated from. This way children can quickly find the pool to chew + * from. + */ + struct talloc_pool_hdr *pool; +}; + +union talloc_chunk_cast_u { + uint8_t *ptr; + struct talloc_chunk *chunk; +}; + +/* 16 byte alignment seems to keep everyone happy */ +#define TC_ALIGN16(s) (((s)+15)&~15) +#define TC_HDR_SIZE TC_ALIGN16(sizeof(struct talloc_chunk)) +#define TC_PTR_FROM_CHUNK(tc) ((void *)(TC_HDR_SIZE + (char*)tc)) + +_PUBLIC_ int talloc_version_major(void) +{ + return TALLOC_VERSION_MAJOR; +} + +_PUBLIC_ int talloc_version_minor(void) +{ + return TALLOC_VERSION_MINOR; +} + +_PUBLIC_ int talloc_test_get_magic(void) +{ + return talloc_magic; +} + +static inline void _talloc_chunk_set_free(struct talloc_chunk *tc, + const char *location) +{ + /* + * Mark this memory as free, and also over-stamp the talloc + * magic with the old-style magic. + * + * Why? This tries to avoid a memory read use-after-free from + * disclosing our talloc magic, which would then allow an + * attacker to prepare a valid header and so run a destructor. + * + */ + tc->flags = TALLOC_MAGIC_NON_RANDOM | TALLOC_FLAG_FREE + | (tc->flags & TALLOC_FLAG_MASK); + + /* we mark the freed memory with where we called the free + * from. This means on a double free error we can report where + * the first free came from + */ + if (location) { + tc->name = location; + } +} + +static inline void _talloc_chunk_set_not_free(struct talloc_chunk *tc) +{ + /* + * Mark this memory as not free. + * + * Why? This is memory either in a pool (and so available for + * talloc's re-use or after the realloc(). We need to mark + * the memory as free() before any realloc() call as we can't + * write to the memory after that. + * + * We put back the normal magic instead of the 'not random' + * magic. + */ + + tc->flags = talloc_magic | + ((tc->flags & TALLOC_FLAG_MASK) & ~TALLOC_FLAG_FREE); +} + +static void (*talloc_log_fn)(const char *message); + +_PUBLIC_ void talloc_set_log_fn(void (*log_fn)(const char *message)) +{ + talloc_log_fn = log_fn; +} + +#ifdef HAVE_CONSTRUCTOR_ATTRIBUTE +#define CONSTRUCTOR __attribute__((constructor)) +#elif defined(HAVE_PRAGMA_INIT) +#define CONSTRUCTOR +#pragma init (talloc_lib_init) +#endif +#if defined(HAVE_CONSTRUCTOR_ATTRIBUTE) || defined(HAVE_PRAGMA_INIT) +void talloc_lib_init(void) CONSTRUCTOR; +void talloc_lib_init(void) +{ + uint32_t random_value; +#if defined(HAVE_GETAUXVAL) && defined(AT_RANDOM) + uint8_t *p; + /* + * Use the kernel-provided random values used for + * ASLR. This won't change per-exec, which is ideal for us + */ + p = (uint8_t *) getauxval(AT_RANDOM); + if (p) { + /* + * We get 16 bytes from getauxval. By calling rand(), + * a totally insecure PRNG, but one that will + * deterministically have a different value when called + * twice, we ensure that if two talloc-like libraries + * are somehow loaded in the same address space, that + * because we choose different bytes, we will keep the + * protection against collision of multiple talloc + * libs. + * + * This protection is important because the effects of + * passing a talloc pointer from one to the other may + * be very hard to determine. + */ + int offset = rand() % (16 - sizeof(random_value)); + memcpy(&random_value, p + offset, sizeof(random_value)); + } else +#endif + { + /* + * Otherwise, hope the location we are loaded in + * memory is randomised by someone else + */ + random_value = ((uintptr_t)talloc_lib_init & 0xFFFFFFFF); + } + talloc_magic = random_value & ~TALLOC_FLAG_MASK; +} +#else +#warning "No __attribute__((constructor)) support found on this platform, additional talloc security measures not available" +#endif + +static void talloc_lib_atexit(void) +{ + TALLOC_FREE(autofree_context); + + if (talloc_total_size(null_context) == 0) { + return; + } + + if (talloc_report_null_full) { + talloc_report_full(null_context, stderr); + } else if (talloc_report_null) { + talloc_report(null_context, stderr); + } +} + +static void talloc_setup_atexit(void) +{ + static bool done; + + if (done) { + return; + } + + atexit(talloc_lib_atexit); + done = true; +} + +static void talloc_log(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2); +static void talloc_log(const char *fmt, ...) +{ + va_list ap; + char *message; + + if (!talloc_log_fn) { + return; + } + + va_start(ap, fmt); + message = talloc_vasprintf(NULL, fmt, ap); + va_end(ap); + + talloc_log_fn(message); + talloc_free(message); +} + +static void talloc_log_stderr(const char *message) +{ + fprintf(stderr, "%s", message); +} + +_PUBLIC_ void talloc_set_log_stderr(void) +{ + talloc_set_log_fn(talloc_log_stderr); +} + +static void (*talloc_abort_fn)(const char *reason); + +_PUBLIC_ void talloc_set_abort_fn(void (*abort_fn)(const char *reason)) +{ + talloc_abort_fn = abort_fn; +} + +static void talloc_abort(const char *reason) +{ + talloc_log("%s\n", reason); + + if (!talloc_abort_fn) { + TALLOC_ABORT(reason); + } + + talloc_abort_fn(reason); +} + +static void talloc_abort_access_after_free(void) +{ + talloc_abort("Bad talloc magic value - access after free"); +} + +static void talloc_abort_unknown_value(void) +{ + talloc_abort("Bad talloc magic value - unknown value"); +} + +/* panic if we get a bad magic value */ +static inline struct talloc_chunk *talloc_chunk_from_ptr(const void *ptr) +{ + const char *pp = (const char *)ptr; + struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE); + if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~TALLOC_FLAG_MASK)) != talloc_magic)) { + if ((tc->flags & (TALLOC_FLAG_FREE | ~TALLOC_FLAG_MASK)) + == (TALLOC_MAGIC_NON_RANDOM | TALLOC_FLAG_FREE)) { + talloc_log("talloc: access after free error - first free may be at %s\n", tc->name); + talloc_abort_access_after_free(); + return NULL; + } + + talloc_abort_unknown_value(); + return NULL; + } + return tc; +} + +/* hook into the front of the list */ +#define _TLIST_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 _TLIST_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) && ((p) != (list))) (p)->next = (p)->prev = NULL; \ +} while (0) + + +/* + return the parent chunk of a pointer +*/ +static inline struct talloc_chunk *talloc_parent_chunk(const void *ptr) +{ + struct talloc_chunk *tc; + + if (unlikely(ptr == NULL)) { + return NULL; + } + + tc = talloc_chunk_from_ptr(ptr); + while (tc->prev) tc=tc->prev; + + return tc->parent; +} + +_PUBLIC_ void *talloc_parent(const void *ptr) +{ + struct talloc_chunk *tc = talloc_parent_chunk(ptr); + return tc? TC_PTR_FROM_CHUNK(tc) : NULL; +} + +/* + find parents name +*/ +_PUBLIC_ const char *talloc_parent_name(const void *ptr) +{ + struct talloc_chunk *tc = talloc_parent_chunk(ptr); + return tc? tc->name : NULL; +} + +/* + A pool carries an in-pool object count count in the first 16 bytes. + bytes. This is done to support talloc_steal() to a parent outside of the + pool. The count includes the pool itself, so a talloc_free() on a pool will + only destroy the pool if the count has dropped to zero. A talloc_free() of a + pool member will reduce the count, and eventually also call free(3) on the + pool memory. + + The object count is not put into "struct talloc_chunk" because it is only + relevant for talloc pools and the alignment to 16 bytes would increase the + memory footprint of each talloc chunk by those 16 bytes. +*/ + +struct talloc_pool_hdr { + void *end; + unsigned int object_count; + size_t poolsize; +}; + +union talloc_pool_hdr_cast_u { + uint8_t *ptr; + struct talloc_pool_hdr *hdr; +}; + +#define TP_HDR_SIZE TC_ALIGN16(sizeof(struct talloc_pool_hdr)) + +static inline struct talloc_pool_hdr *talloc_pool_from_chunk(struct talloc_chunk *c) +{ + union talloc_chunk_cast_u tcc = { .chunk = c }; + union talloc_pool_hdr_cast_u tphc = { tcc.ptr - TP_HDR_SIZE }; + return tphc.hdr; +} + +static inline struct talloc_chunk *talloc_chunk_from_pool(struct talloc_pool_hdr *h) +{ + union talloc_pool_hdr_cast_u tphc = { .hdr = h }; + union talloc_chunk_cast_u tcc = { .ptr = tphc.ptr + TP_HDR_SIZE }; + return tcc.chunk; +} + +static inline void *tc_pool_end(struct talloc_pool_hdr *pool_hdr) +{ + struct talloc_chunk *tc = talloc_chunk_from_pool(pool_hdr); + return (char *)tc + TC_HDR_SIZE + pool_hdr->poolsize; +} + +static inline size_t tc_pool_space_left(struct talloc_pool_hdr *pool_hdr) +{ + return (char *)tc_pool_end(pool_hdr) - (char *)pool_hdr->end; +} + +/* If tc is inside a pool, this gives the next neighbour. */ +static inline void *tc_next_chunk(struct talloc_chunk *tc) +{ + return (char *)tc + TC_ALIGN16(TC_HDR_SIZE + tc->size); +} + +static inline void *tc_pool_first_chunk(struct talloc_pool_hdr *pool_hdr) +{ + struct talloc_chunk *tc = talloc_chunk_from_pool(pool_hdr); + return tc_next_chunk(tc); +} + +/* Mark the whole remaining pool as not accessable */ +static inline void tc_invalidate_pool(struct talloc_pool_hdr *pool_hdr) +{ + size_t flen = tc_pool_space_left(pool_hdr); + + if (unlikely(talloc_fill.enabled)) { + memset(pool_hdr->end, talloc_fill.fill_value, flen); + } + +#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS) + VALGRIND_MAKE_MEM_NOACCESS(pool_hdr->end, flen); +#endif +} + +/* + Allocate from a pool +*/ + +static inline struct talloc_chunk *tc_alloc_pool(struct talloc_chunk *parent, + size_t size, size_t prefix_len) +{ + struct talloc_pool_hdr *pool_hdr = NULL; + union talloc_chunk_cast_u tcc; + size_t space_left; + struct talloc_chunk *result; + size_t chunk_size; + + if (parent == NULL) { + return NULL; + } + + if (parent->flags & TALLOC_FLAG_POOL) { + pool_hdr = talloc_pool_from_chunk(parent); + } + else if (parent->flags & TALLOC_FLAG_POOLMEM) { + pool_hdr = parent->pool; + } + + if (pool_hdr == NULL) { + return NULL; + } + + space_left = tc_pool_space_left(pool_hdr); + + /* + * Align size to 16 bytes + */ + chunk_size = TC_ALIGN16(size + prefix_len); + + if (space_left < chunk_size) { + return NULL; + } + + tcc = (union talloc_chunk_cast_u) { + .ptr = ((uint8_t *)pool_hdr->end) + prefix_len + }; + result = tcc.chunk; + +#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED) + VALGRIND_MAKE_MEM_UNDEFINED(pool_hdr->end, chunk_size); +#endif + + pool_hdr->end = (void *)((char *)pool_hdr->end + chunk_size); + + result->flags = talloc_magic | TALLOC_FLAG_POOLMEM; + result->pool = pool_hdr; + + pool_hdr->object_count++; + + return result; +} + +/* + Allocate a bit of memory as a child of an existing pointer +*/ +static inline void *__talloc_with_prefix(const void *context, + size_t size, + size_t prefix_len, + struct talloc_chunk **tc_ret) +{ + struct talloc_chunk *tc = NULL; + struct talloc_memlimit *limit = NULL; + size_t total_len = TC_HDR_SIZE + size + prefix_len; + struct talloc_chunk *parent = NULL; + + if (unlikely(context == NULL)) { + context = null_context; + } + + if (unlikely(size >= MAX_TALLOC_SIZE)) { + return NULL; + } + + if (unlikely(total_len < TC_HDR_SIZE)) { + return NULL; + } + + if (likely(context != NULL)) { + parent = talloc_chunk_from_ptr(context); + + if (parent->limit != NULL) { + limit = parent->limit; + } + + tc = tc_alloc_pool(parent, TC_HDR_SIZE+size, prefix_len); + } + + if (tc == NULL) { + uint8_t *ptr = NULL; + union talloc_chunk_cast_u tcc; + + /* + * Only do the memlimit check/update on actual allocation. + */ + if (!talloc_memlimit_check(limit, total_len)) { + errno = ENOMEM; + return NULL; + } + + ptr = malloc(total_len); + if (unlikely(ptr == NULL)) { + return NULL; + } + tcc = (union talloc_chunk_cast_u) { .ptr = ptr + prefix_len }; + tc = tcc.chunk; + tc->flags = talloc_magic; + tc->pool = NULL; + + talloc_memlimit_grow(limit, total_len); + } + + tc->limit = limit; + tc->size = size; + tc->destructor = NULL; + tc->child = NULL; + tc->name = NULL; + tc->refs = NULL; + + if (likely(context != NULL)) { + if (parent->child) { + parent->child->parent = NULL; + tc->next = parent->child; + tc->next->prev = tc; + } else { + tc->next = NULL; + } + tc->parent = parent; + tc->prev = NULL; + parent->child = tc; + } else { + tc->next = tc->prev = tc->parent = NULL; + } + + *tc_ret = tc; + return TC_PTR_FROM_CHUNK(tc); +} + +static inline void *__talloc(const void *context, + size_t size, + struct talloc_chunk **tc) +{ + return __talloc_with_prefix(context, size, 0, tc); +} + +/* + * Create a talloc pool + */ + +static inline void *_talloc_pool(const void *context, size_t size) +{ + struct talloc_chunk *tc = NULL; + struct talloc_pool_hdr *pool_hdr; + void *result; + + result = __talloc_with_prefix(context, size, TP_HDR_SIZE, &tc); + + if (unlikely(result == NULL)) { + return NULL; + } + + pool_hdr = talloc_pool_from_chunk(tc); + + tc->flags |= TALLOC_FLAG_POOL; + tc->size = 0; + + pool_hdr->object_count = 1; + pool_hdr->end = result; + pool_hdr->poolsize = size; + + tc_invalidate_pool(pool_hdr); + + return result; +} + +_PUBLIC_ void *talloc_pool(const void *context, size_t size) +{ + return _talloc_pool(context, size); +} + +/* + * Create a talloc pool correctly sized for a basic size plus + * a number of subobjects whose total size is given. Essentially + * a custom allocator for talloc to reduce fragmentation. + */ + +_PUBLIC_ void *_talloc_pooled_object(const void *ctx, + size_t type_size, + const char *type_name, + unsigned num_subobjects, + size_t total_subobjects_size) +{ + size_t poolsize, subobjects_slack, tmp; + struct talloc_chunk *tc; + struct talloc_pool_hdr *pool_hdr; + void *ret; + + poolsize = type_size + total_subobjects_size; + + if ((poolsize < type_size) || (poolsize < total_subobjects_size)) { + goto overflow; + } + + if (num_subobjects == UINT_MAX) { + goto overflow; + } + num_subobjects += 1; /* the object body itself */ + + /* + * Alignment can increase the pool size by at most 15 bytes per object + * plus alignment for the object itself + */ + subobjects_slack = (TC_HDR_SIZE + TP_HDR_SIZE + 15) * num_subobjects; + if (subobjects_slack < num_subobjects) { + goto overflow; + } + + tmp = poolsize + subobjects_slack; + if ((tmp < poolsize) || (tmp < subobjects_slack)) { + goto overflow; + } + poolsize = tmp; + + ret = _talloc_pool(ctx, poolsize); + if (ret == NULL) { + return NULL; + } + + tc = talloc_chunk_from_ptr(ret); + tc->size = type_size; + + pool_hdr = talloc_pool_from_chunk(tc); + +#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED) + VALGRIND_MAKE_MEM_UNDEFINED(pool_hdr->end, type_size); +#endif + + pool_hdr->end = ((char *)pool_hdr->end + TC_ALIGN16(type_size)); + + _tc_set_name_const(tc, type_name); + return ret; + +overflow: + return NULL; +} + +/* + setup a destructor to be called on free of a pointer + the destructor should return 0 on success, or -1 on failure. + if the destructor fails then the free is failed, and the memory can + be continued to be used +*/ +_PUBLIC_ void _talloc_set_destructor(const void *ptr, int (*destructor)(void *)) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + tc->destructor = destructor; +} + +/* + increase the reference count on a piece of memory. +*/ +_PUBLIC_ int talloc_increase_ref_count(const void *ptr) +{ + if (unlikely(!talloc_reference(null_context, ptr))) { + return -1; + } + return 0; +} + +/* + helper for talloc_reference() + + this is referenced by a function pointer and should not be inline +*/ +static int talloc_reference_destructor(struct talloc_reference_handle *handle) +{ + struct talloc_chunk *ptr_tc = talloc_chunk_from_ptr(handle->ptr); + _TLIST_REMOVE(ptr_tc->refs, handle); + return 0; +} + +/* + more efficient way to add a name to a pointer - the name must point to a + true string constant +*/ +static inline void _tc_set_name_const(struct talloc_chunk *tc, + const char *name) +{ + tc->name = name; +} + +/* + internal talloc_named_const() +*/ +static inline void *_talloc_named_const(const void *context, size_t size, const char *name) +{ + void *ptr; + struct talloc_chunk *tc = NULL; + + ptr = __talloc(context, size, &tc); + if (unlikely(ptr == NULL)) { + return NULL; + } + + _tc_set_name_const(tc, name); + + return ptr; +} + +/* + make a secondary reference to a pointer, hanging off the given context. + the pointer remains valid until both the original caller and this given + context are freed. + + the major use for this is when two different structures need to reference the + same underlying data, and you want to be able to free the two instances separately, + and in either order +*/ +_PUBLIC_ void *_talloc_reference_loc(const void *context, const void *ptr, const char *location) +{ + struct talloc_chunk *tc; + struct talloc_reference_handle *handle; + if (unlikely(ptr == NULL)) return NULL; + + tc = talloc_chunk_from_ptr(ptr); + handle = (struct talloc_reference_handle *)_talloc_named_const(context, + sizeof(struct talloc_reference_handle), + TALLOC_MAGIC_REFERENCE); + if (unlikely(handle == NULL)) return NULL; + + /* note that we hang the destructor off the handle, not the + main context as that allows the caller to still setup their + own destructor on the context if they want to */ + talloc_set_destructor(handle, talloc_reference_destructor); + handle->ptr = discard_const_p(void, ptr); + handle->location = location; + _TLIST_ADD(tc->refs, handle); + return handle->ptr; +} + +static void *_talloc_steal_internal(const void *new_ctx, const void *ptr); + +static inline void _tc_free_poolmem(struct talloc_chunk *tc, + const char *location) +{ + struct talloc_pool_hdr *pool; + struct talloc_chunk *pool_tc; + void *next_tc; + + pool = tc->pool; + pool_tc = talloc_chunk_from_pool(pool); + next_tc = tc_next_chunk(tc); + + _talloc_chunk_set_free(tc, location); + + TC_INVALIDATE_FULL_CHUNK(tc); + + if (unlikely(pool->object_count == 0)) { + talloc_abort("Pool object count zero!"); + return; + } + + pool->object_count--; + + if (unlikely(pool->object_count == 1 + && !(pool_tc->flags & TALLOC_FLAG_FREE))) { + /* + * if there is just one object left in the pool + * and pool->flags does not have TALLOC_FLAG_FREE, + * it means this is the pool itself and + * the rest is available for new objects + * again. + */ + pool->end = tc_pool_first_chunk(pool); + tc_invalidate_pool(pool); + return; + } + + if (unlikely(pool->object_count == 0)) { + /* + * we mark the freed memory with where we called the free + * from. This means on a double free error we can report where + * the first free came from + */ + pool_tc->name = location; + + if (pool_tc->flags & TALLOC_FLAG_POOLMEM) { + _tc_free_poolmem(pool_tc, location); + } else { + /* + * The tc_memlimit_update_on_free() + * call takes into account the + * prefix TP_HDR_SIZE allocated before + * the pool talloc_chunk. + */ + tc_memlimit_update_on_free(pool_tc); + TC_INVALIDATE_FULL_CHUNK(pool_tc); + free(pool); + } + return; + } + + if (pool->end == next_tc) { + /* + * if pool->pool still points to end of + * 'tc' (which is stored in the 'next_tc' variable), + * we can reclaim the memory of 'tc'. + */ + pool->end = tc; + return; + } + + /* + * Do nothing. The memory is just "wasted", waiting for the pool + * itself to be freed. + */ +} + +static inline void _tc_free_children_internal(struct talloc_chunk *tc, + void *ptr, + const char *location); + +static inline int _talloc_free_internal(void *ptr, const char *location); + +/* + internal free call that takes a struct talloc_chunk *. +*/ +static inline int _tc_free_internal(struct talloc_chunk *tc, + const char *location) +{ + void *ptr_to_free; + void *ptr = TC_PTR_FROM_CHUNK(tc); + + if (unlikely(tc->refs)) { + int is_child; + /* check if this is a reference from a child or + * grandchild back to it's parent or grandparent + * + * in that case we need to remove the reference and + * call another instance of talloc_free() on the current + * pointer. + */ + is_child = talloc_is_parent(tc->refs, ptr); + _talloc_free_internal(tc->refs, location); + if (is_child) { + return _talloc_free_internal(ptr, location); + } + return -1; + } + + if (unlikely(tc->flags & TALLOC_FLAG_LOOP)) { + /* we have a free loop - stop looping */ + return 0; + } + + if (unlikely(tc->destructor)) { + talloc_destructor_t d = tc->destructor; + + /* + * Protect the destructor against some overwrite + * attacks, by explicitly checking it has the right + * magic here. + */ + if (talloc_chunk_from_ptr(ptr) != tc) { + /* + * This can't actually happen, the + * call itself will panic. + */ + TALLOC_ABORT("talloc_chunk_from_ptr failed!"); + } + + if (d == (talloc_destructor_t)-1) { + return -1; + } + tc->destructor = (talloc_destructor_t)-1; + if (d(ptr) == -1) { + /* + * Only replace the destructor pointer if + * calling the destructor didn't modify it. + */ + if (tc->destructor == (talloc_destructor_t)-1) { + tc->destructor = d; + } + return -1; + } + tc->destructor = NULL; + } + + if (tc->parent) { + _TLIST_REMOVE(tc->parent->child, tc); + if (tc->parent->child) { + tc->parent->child->parent = tc->parent; + } + } else { + if (tc->prev) tc->prev->next = tc->next; + if (tc->next) tc->next->prev = tc->prev; + tc->prev = tc->next = NULL; + } + + tc->flags |= TALLOC_FLAG_LOOP; + + _tc_free_children_internal(tc, ptr, location); + + _talloc_chunk_set_free(tc, location); + + if (tc->flags & TALLOC_FLAG_POOL) { + struct talloc_pool_hdr *pool; + + pool = talloc_pool_from_chunk(tc); + + if (unlikely(pool->object_count == 0)) { + talloc_abort("Pool object count zero!"); + return 0; + } + + pool->object_count--; + + if (likely(pool->object_count != 0)) { + return 0; + } + + /* + * With object_count==0, a pool becomes a normal piece of + * memory to free. If it's allocated inside a pool, it needs + * to be freed as poolmem, else it needs to be just freed. + */ + ptr_to_free = pool; + } else { + ptr_to_free = tc; + } + + if (tc->flags & TALLOC_FLAG_POOLMEM) { + _tc_free_poolmem(tc, location); + return 0; + } + + tc_memlimit_update_on_free(tc); + + TC_INVALIDATE_FULL_CHUNK(tc); + free(ptr_to_free); + return 0; +} + +/* + internal talloc_free call +*/ +static inline int _talloc_free_internal(void *ptr, const char *location) +{ + struct talloc_chunk *tc; + + if (unlikely(ptr == NULL)) { + return -1; + } + + /* possibly initialised the talloc fill value */ + if (unlikely(!talloc_fill.initialised)) { + const char *fill = getenv(TALLOC_FILL_ENV); + if (fill != NULL) { + talloc_fill.enabled = true; + talloc_fill.fill_value = strtoul(fill, NULL, 0); + } + talloc_fill.initialised = true; + } + + tc = talloc_chunk_from_ptr(ptr); + return _tc_free_internal(tc, location); +} + +static inline size_t _talloc_total_limit_size(const void *ptr, + struct talloc_memlimit *old_limit, + struct talloc_memlimit *new_limit); + +/* + move a lump of memory from one talloc context to another return the + ptr on success, or NULL if it could not be transferred. + passing NULL as ptr will always return NULL with no side effects. +*/ +static void *_talloc_steal_internal(const void *new_ctx, const void *ptr) +{ + struct talloc_chunk *tc, *new_tc; + size_t ctx_size = 0; + + if (unlikely(!ptr)) { + return NULL; + } + + if (unlikely(new_ctx == NULL)) { + new_ctx = null_context; + } + + tc = talloc_chunk_from_ptr(ptr); + + if (tc->limit != NULL) { + + ctx_size = _talloc_total_limit_size(ptr, NULL, NULL); + + /* Decrement the memory limit from the source .. */ + talloc_memlimit_shrink(tc->limit->upper, ctx_size); + + if (tc->limit->parent == tc) { + tc->limit->upper = NULL; + } else { + tc->limit = NULL; + } + } + + if (unlikely(new_ctx == NULL)) { + if (tc->parent) { + _TLIST_REMOVE(tc->parent->child, tc); + if (tc->parent->child) { + tc->parent->child->parent = tc->parent; + } + } else { + if (tc->prev) tc->prev->next = tc->next; + if (tc->next) tc->next->prev = tc->prev; + } + + tc->parent = tc->next = tc->prev = NULL; + return discard_const_p(void, ptr); + } + + new_tc = talloc_chunk_from_ptr(new_ctx); + + if (unlikely(tc == new_tc || tc->parent == new_tc)) { + return discard_const_p(void, ptr); + } + + if (tc->parent) { + _TLIST_REMOVE(tc->parent->child, tc); + if (tc->parent->child) { + tc->parent->child->parent = tc->parent; + } + } else { + if (tc->prev) tc->prev->next = tc->next; + if (tc->next) tc->next->prev = tc->prev; + tc->prev = tc->next = NULL; + } + + tc->parent = new_tc; + if (new_tc->child) new_tc->child->parent = NULL; + _TLIST_ADD(new_tc->child, tc); + + if (tc->limit || new_tc->limit) { + ctx_size = _talloc_total_limit_size(ptr, tc->limit, + new_tc->limit); + /* .. and increment it in the destination. */ + if (new_tc->limit) { + talloc_memlimit_grow(new_tc->limit, ctx_size); + } + } + + return discard_const_p(void, ptr); +} + +/* + move a lump of memory from one talloc context to another return the + ptr on success, or NULL if it could not be transferred. + passing NULL as ptr will always return NULL with no side effects. +*/ +_PUBLIC_ void *_talloc_steal_loc(const void *new_ctx, const void *ptr, const char *location) +{ + struct talloc_chunk *tc; + + if (unlikely(ptr == NULL)) { + return NULL; + } + + tc = talloc_chunk_from_ptr(ptr); + + if (unlikely(tc->refs != NULL) && talloc_parent(ptr) != new_ctx) { + struct talloc_reference_handle *h; + + talloc_log("WARNING: talloc_steal with references at %s\n", + location); + + for (h=tc->refs; h; h=h->next) { + talloc_log("\treference at %s\n", + h->location); + } + } + +#if 0 + /* this test is probably too expensive to have on in the + normal build, but it useful for debugging */ + if (talloc_is_parent(new_ctx, ptr)) { + talloc_log("WARNING: stealing into talloc child at %s\n", location); + } +#endif + + return _talloc_steal_internal(new_ctx, ptr); +} + +/* + this is like a talloc_steal(), but you must supply the old + parent. This resolves the ambiguity in a talloc_steal() which is + called on a context that has more than one parent (via references) + + The old parent can be either a reference or a parent +*/ +_PUBLIC_ void *talloc_reparent(const void *old_parent, const void *new_parent, const void *ptr) +{ + struct talloc_chunk *tc; + struct talloc_reference_handle *h; + + if (unlikely(ptr == NULL)) { + return NULL; + } + + if (old_parent == talloc_parent(ptr)) { + return _talloc_steal_internal(new_parent, ptr); + } + + tc = talloc_chunk_from_ptr(ptr); + for (h=tc->refs;h;h=h->next) { + if (talloc_parent(h) == old_parent) { + if (_talloc_steal_internal(new_parent, h) != h) { + return NULL; + } + return discard_const_p(void, ptr); + } + } + + /* it wasn't a parent */ + return NULL; +} + +/* + remove a secondary reference to a pointer. This undo's what + talloc_reference() has done. The context and pointer arguments + must match those given to a talloc_reference() +*/ +static inline int talloc_unreference(const void *context, const void *ptr) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + struct talloc_reference_handle *h; + + if (unlikely(context == NULL)) { + context = null_context; + } + + for (h=tc->refs;h;h=h->next) { + struct talloc_chunk *p = talloc_parent_chunk(h); + if (p == NULL) { + if (context == NULL) break; + } else if (TC_PTR_FROM_CHUNK(p) == context) { + break; + } + } + if (h == NULL) { + return -1; + } + + return _talloc_free_internal(h, __location__); +} + +/* + remove a specific parent context from a pointer. This is a more + controlled variant of talloc_free() +*/ + +/* coverity[ -tainted_data_sink : arg-1 ] */ +_PUBLIC_ int talloc_unlink(const void *context, void *ptr) +{ + struct talloc_chunk *tc_p, *new_p, *tc_c; + void *new_parent; + + if (ptr == NULL) { + return -1; + } + + if (context == NULL) { + context = null_context; + } + + if (talloc_unreference(context, ptr) == 0) { + return 0; + } + + if (context != NULL) { + tc_c = talloc_chunk_from_ptr(context); + } else { + tc_c = NULL; + } + if (tc_c != talloc_parent_chunk(ptr)) { + return -1; + } + + tc_p = talloc_chunk_from_ptr(ptr); + + if (tc_p->refs == NULL) { + return _talloc_free_internal(ptr, __location__); + } + + new_p = talloc_parent_chunk(tc_p->refs); + if (new_p) { + new_parent = TC_PTR_FROM_CHUNK(new_p); + } else { + new_parent = NULL; + } + + if (talloc_unreference(new_parent, ptr) != 0) { + return -1; + } + + _talloc_steal_internal(new_parent, ptr); + + return 0; +} + +/* + add a name to an existing pointer - va_list version +*/ +static inline const char *tc_set_name_v(struct talloc_chunk *tc, + const char *fmt, + va_list ap) PRINTF_ATTRIBUTE(2,0); + +static inline const char *tc_set_name_v(struct talloc_chunk *tc, + const char *fmt, + va_list ap) +{ + struct talloc_chunk *name_tc = _vasprintf_tc(TC_PTR_FROM_CHUNK(tc), + fmt, + ap); + if (likely(name_tc)) { + tc->name = TC_PTR_FROM_CHUNK(name_tc); + _tc_set_name_const(name_tc, ".name"); + } else { + tc->name = NULL; + } + return tc->name; +} + +/* + add a name to an existing pointer +*/ +_PUBLIC_ const char *talloc_set_name(const void *ptr, const char *fmt, ...) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + const char *name; + va_list ap; + va_start(ap, fmt); + name = tc_set_name_v(tc, fmt, ap); + va_end(ap); + return name; +} + + +/* + create a named talloc pointer. Any talloc pointer can be named, and + talloc_named() operates just like talloc() except that it allows you + to name the pointer. +*/ +_PUBLIC_ void *talloc_named(const void *context, size_t size, const char *fmt, ...) +{ + va_list ap; + void *ptr; + const char *name; + struct talloc_chunk *tc = NULL; + + ptr = __talloc(context, size, &tc); + if (unlikely(ptr == NULL)) return NULL; + + va_start(ap, fmt); + name = tc_set_name_v(tc, fmt, ap); + va_end(ap); + + if (unlikely(name == NULL)) { + _talloc_free_internal(ptr, __location__); + return NULL; + } + + return ptr; +} + +/* + return the name of a talloc ptr, or "UNNAMED" +*/ +static inline const char *__talloc_get_name(const void *ptr) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + if (unlikely(tc->name == TALLOC_MAGIC_REFERENCE)) { + return ".reference"; + } + if (likely(tc->name)) { + return tc->name; + } + return "UNNAMED"; +} + +_PUBLIC_ const char *talloc_get_name(const void *ptr) +{ + return __talloc_get_name(ptr); +} + +/* + check if a pointer has the given name. If it does, return the pointer, + otherwise return NULL +*/ +_PUBLIC_ void *talloc_check_name(const void *ptr, const char *name) +{ + const char *pname; + if (unlikely(ptr == NULL)) return NULL; + pname = __talloc_get_name(ptr); + if (likely(pname == name || strcmp(pname, name) == 0)) { + return discard_const_p(void, ptr); + } + return NULL; +} + +static void talloc_abort_type_mismatch(const char *location, + const char *name, + const char *expected) +{ + const char *reason; + + reason = talloc_asprintf(NULL, + "%s: Type mismatch: name[%s] expected[%s]", + location, + name?name:"NULL", + expected); + if (!reason) { + reason = "Type mismatch"; + } + + talloc_abort(reason); +} + +_PUBLIC_ void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location) +{ + const char *pname; + + if (unlikely(ptr == NULL)) { + talloc_abort_type_mismatch(location, NULL, name); + return NULL; + } + + pname = __talloc_get_name(ptr); + if (likely(pname == name || strcmp(pname, name) == 0)) { + return discard_const_p(void, ptr); + } + + talloc_abort_type_mismatch(location, pname, name); + return NULL; +} + +/* + this is for compatibility with older versions of talloc +*/ +_PUBLIC_ void *talloc_init(const char *fmt, ...) +{ + va_list ap; + void *ptr; + const char *name; + struct talloc_chunk *tc = NULL; + + ptr = __talloc(NULL, 0, &tc); + if (unlikely(ptr == NULL)) return NULL; + + va_start(ap, fmt); + name = tc_set_name_v(tc, fmt, ap); + va_end(ap); + + if (unlikely(name == NULL)) { + _talloc_free_internal(ptr, __location__); + return NULL; + } + + return ptr; +} + +static inline void _tc_free_children_internal(struct talloc_chunk *tc, + void *ptr, + const char *location) +{ + while (tc->child) { + /* we need to work out who will own an abandoned child + if it cannot be freed. In priority order, the first + choice is owner of any remaining reference to this + pointer, the second choice is our parent, and the + final choice is the null context. */ + void *child = TC_PTR_FROM_CHUNK(tc->child); + const void *new_parent = null_context; + if (unlikely(tc->child->refs)) { + struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs); + if (p) new_parent = TC_PTR_FROM_CHUNK(p); + } + if (unlikely(_tc_free_internal(tc->child, location) == -1)) { + if (talloc_parent_chunk(child) != tc) { + /* + * Destructor already reparented this child. + * No further reparenting needed. + */ + continue; + } + if (new_parent == null_context) { + struct talloc_chunk *p = talloc_parent_chunk(ptr); + if (p) new_parent = TC_PTR_FROM_CHUNK(p); + } + _talloc_steal_internal(new_parent, child); + } + } +} + +/* + this is a replacement for the Samba3 talloc_destroy_pool functionality. It + should probably not be used in new code. It's in here to keep the talloc + code consistent across Samba 3 and 4. +*/ +_PUBLIC_ void talloc_free_children(void *ptr) +{ + struct talloc_chunk *tc_name = NULL; + struct talloc_chunk *tc; + + if (unlikely(ptr == NULL)) { + return; + } + + tc = talloc_chunk_from_ptr(ptr); + + /* we do not want to free the context name if it is a child .. */ + if (likely(tc->child)) { + for (tc_name = tc->child; tc_name; tc_name = tc_name->next) { + if (tc->name == TC_PTR_FROM_CHUNK(tc_name)) break; + } + if (tc_name) { + _TLIST_REMOVE(tc->child, tc_name); + if (tc->child) { + tc->child->parent = tc; + } + } + } + + _tc_free_children_internal(tc, ptr, __location__); + + /* .. so we put it back after all other children have been freed */ + if (tc_name) { + if (tc->child) { + tc->child->parent = NULL; + } + tc_name->parent = tc; + _TLIST_ADD(tc->child, tc_name); + } +} + +/* + Allocate a bit of memory as a child of an existing pointer +*/ +_PUBLIC_ void *_talloc(const void *context, size_t size) +{ + struct talloc_chunk *tc; + return __talloc(context, size, &tc); +} + +/* + externally callable talloc_set_name_const() +*/ +_PUBLIC_ void talloc_set_name_const(const void *ptr, const char *name) +{ + _tc_set_name_const(talloc_chunk_from_ptr(ptr), name); +} + +/* + create a named talloc pointer. Any talloc pointer can be named, and + talloc_named() operates just like talloc() except that it allows you + to name the pointer. +*/ +_PUBLIC_ void *talloc_named_const(const void *context, size_t size, const char *name) +{ + return _talloc_named_const(context, size, name); +} + +/* + free a talloc pointer. This also frees all child pointers of this + pointer recursively + + return 0 if the memory is actually freed, otherwise -1. The memory + will not be freed if the ref_count is > 1 or the destructor (if + any) returns non-zero +*/ +_PUBLIC_ int _talloc_free(void *ptr, const char *location) +{ + struct talloc_chunk *tc; + + if (unlikely(ptr == NULL)) { + return -1; + } + + tc = talloc_chunk_from_ptr(ptr); + + if (unlikely(tc->refs != NULL)) { + struct talloc_reference_handle *h; + + if (talloc_parent(ptr) == null_context && tc->refs->next == NULL) { + /* in this case we do know which parent should + get this pointer, as there is really only + one parent */ + return talloc_unlink(null_context, ptr); + } + + talloc_log("ERROR: talloc_free with references at %s\n", + location); + + for (h=tc->refs; h; h=h->next) { + talloc_log("\treference at %s\n", + h->location); + } + return -1; + } + + return _talloc_free_internal(ptr, location); +} + + + +/* + A talloc version of realloc. The context argument is only used if + ptr is NULL +*/ +_PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name) +{ + struct talloc_chunk *tc; + void *new_ptr; + bool malloced = false; + struct talloc_pool_hdr *pool_hdr = NULL; + size_t old_size = 0; + size_t new_size = 0; + + /* size zero is equivalent to free() */ + if (unlikely(size == 0)) { + talloc_unlink(context, ptr); + return NULL; + } + + if (unlikely(size >= MAX_TALLOC_SIZE)) { + return NULL; + } + + /* realloc(NULL) is equivalent to malloc() */ + if (ptr == NULL) { + return _talloc_named_const(context, size, name); + } + + tc = talloc_chunk_from_ptr(ptr); + + /* don't allow realloc on referenced pointers */ + if (unlikely(tc->refs)) { + return NULL; + } + + /* don't let anybody try to realloc a talloc_pool */ + if (unlikely(tc->flags & TALLOC_FLAG_POOL)) { + return NULL; + } + + /* handle realloc inside a talloc_pool */ + if (unlikely(tc->flags & TALLOC_FLAG_POOLMEM)) { + pool_hdr = tc->pool; + } + + /* don't shrink if we have less than 1k to gain */ + if (size < tc->size && tc->limit == NULL) { + if (pool_hdr) { + void *next_tc = tc_next_chunk(tc); + TC_INVALIDATE_SHRINK_CHUNK(tc, size); + tc->size = size; + if (next_tc == pool_hdr->end) { + /* note: tc->size has changed, so this works */ + pool_hdr->end = tc_next_chunk(tc); + } + return ptr; + } else if ((tc->size - size) < 1024) { + /* + * if we call TC_INVALIDATE_SHRINK_CHUNK() here + * we would need to call TC_UNDEFINE_GROW_CHUNK() + * after each realloc call, which slows down + * testing a lot :-(. + * + * That is why we only mark memory as undefined here. + */ + TC_UNDEFINE_SHRINK_CHUNK(tc, size); + + /* do not shrink if we have less than 1k to gain */ + tc->size = size; + return ptr; + } + } else if (tc->size == size) { + /* + * do not change the pointer if it is exactly + * the same size. + */ + return ptr; + } + + /* + * by resetting magic we catch users of the old memory + * + * We mark this memory as free, and also over-stamp the talloc + * magic with the old-style magic. + * + * Why? This tries to avoid a memory read use-after-free from + * disclosing our talloc magic, which would then allow an + * attacker to prepare a valid header and so run a destructor. + * + * What else? We have to re-stamp back a valid normal magic + * on this memory once realloc() is done, as it will have done + * a memcpy() into the new valid memory. We can't do this in + * reverse as that would be a real use-after-free. + */ + _talloc_chunk_set_free(tc, NULL); + + if (pool_hdr) { + struct talloc_chunk *pool_tc; + void *next_tc = tc_next_chunk(tc); + size_t old_chunk_size = TC_ALIGN16(TC_HDR_SIZE + tc->size); + size_t new_chunk_size = TC_ALIGN16(TC_HDR_SIZE + size); + size_t space_needed; + size_t space_left; + unsigned int chunk_count = pool_hdr->object_count; + + pool_tc = talloc_chunk_from_pool(pool_hdr); + if (!(pool_tc->flags & TALLOC_FLAG_FREE)) { + chunk_count -= 1; + } + + if (chunk_count == 1) { + /* + * optimize for the case where 'tc' is the only + * chunk in the pool. + */ + char *start = tc_pool_first_chunk(pool_hdr); + space_needed = new_chunk_size; + space_left = (char *)tc_pool_end(pool_hdr) - start; + + if (space_left >= space_needed) { + size_t old_used = TC_HDR_SIZE + tc->size; + size_t new_used = TC_HDR_SIZE + size; + new_ptr = start; + +#if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED) + { + /* + * The area from + * start -> tc may have + * been freed and thus been marked as + * VALGRIND_MEM_NOACCESS. Set it to + * VALGRIND_MEM_UNDEFINED so we can + * copy into it without valgrind errors. + * We can't just mark + * new_ptr -> new_ptr + old_used + * as this may overlap on top of tc, + * (which is why we use memmove, not + * memcpy below) hence the MIN. + */ + size_t undef_len = MIN((((char *)tc) - ((char *)new_ptr)),old_used); + VALGRIND_MAKE_MEM_UNDEFINED(new_ptr, undef_len); + } +#endif + + memmove(new_ptr, tc, old_used); + + tc = (struct talloc_chunk *)new_ptr; + TC_UNDEFINE_GROW_CHUNK(tc, size); + + /* + * first we do not align the pool pointer + * because we want to invalidate the padding + * too. + */ + pool_hdr->end = new_used + (char *)new_ptr; + tc_invalidate_pool(pool_hdr); + + /* now the aligned pointer */ + pool_hdr->end = new_chunk_size + (char *)new_ptr; + goto got_new_ptr; + } + + next_tc = NULL; + } + + if (new_chunk_size == old_chunk_size) { + TC_UNDEFINE_GROW_CHUNK(tc, size); + _talloc_chunk_set_not_free(tc); + tc->size = size; + return ptr; + } + + if (next_tc == pool_hdr->end) { + /* + * optimize for the case where 'tc' is the last + * chunk in the pool. + */ + space_needed = new_chunk_size - old_chunk_size; + space_left = tc_pool_space_left(pool_hdr); + + if (space_left >= space_needed) { + TC_UNDEFINE_GROW_CHUNK(tc, size); + _talloc_chunk_set_not_free(tc); + tc->size = size; + pool_hdr->end = tc_next_chunk(tc); + return ptr; + } + } + + new_ptr = tc_alloc_pool(tc, size + TC_HDR_SIZE, 0); + + if (new_ptr == NULL) { + /* + * Couldn't allocate from pool (pool size + * counts as already allocated for memlimit + * purposes). We must check memory limit + * before any real malloc. + */ + if (tc->limit) { + /* + * Note we're doing an extra malloc, + * on top of the pool size, so account + * for size only, not the difference + * between old and new size. + */ + if (!talloc_memlimit_check(tc->limit, size)) { + _talloc_chunk_set_not_free(tc); + errno = ENOMEM; + return NULL; + } + } + new_ptr = malloc(TC_HDR_SIZE+size); + malloced = true; + new_size = size; + } + + if (new_ptr) { + memcpy(new_ptr, tc, MIN(tc->size,size) + TC_HDR_SIZE); + + _tc_free_poolmem(tc, __location__ "_talloc_realloc"); + } + } + else { + /* We're doing realloc here, so record the difference. */ + old_size = tc->size; + new_size = size; + /* + * We must check memory limit + * before any real realloc. + */ + if (tc->limit && (size > old_size)) { + if (!talloc_memlimit_check(tc->limit, + (size - old_size))) { + _talloc_chunk_set_not_free(tc); + errno = ENOMEM; + return NULL; + } + } + new_ptr = realloc(tc, size + TC_HDR_SIZE); + } +got_new_ptr: + + if (unlikely(!new_ptr)) { + /* + * Ok, this is a strange spot. We have to put back + * the old talloc_magic and any flags, except the + * TALLOC_FLAG_FREE as this was not free'ed by the + * realloc() call after all + */ + _talloc_chunk_set_not_free(tc); + return NULL; + } + + /* + * tc is now the new value from realloc(), the old memory we + * can't access any more and was preemptively marked as + * TALLOC_FLAG_FREE before the call. Now we mark it as not + * free again + */ + tc = (struct talloc_chunk *)new_ptr; + _talloc_chunk_set_not_free(tc); + if (malloced) { + tc->flags &= ~TALLOC_FLAG_POOLMEM; + } + if (tc->parent) { + tc->parent->child = tc; + } + if (tc->child) { + tc->child->parent = tc; + } + + if (tc->prev) { + tc->prev->next = tc; + } + if (tc->next) { + tc->next->prev = tc; + } + + if (new_size > old_size) { + talloc_memlimit_grow(tc->limit, new_size - old_size); + } else if (new_size < old_size) { + talloc_memlimit_shrink(tc->limit, old_size - new_size); + } + + tc->size = size; + _tc_set_name_const(tc, name); + + return TC_PTR_FROM_CHUNK(tc); +} + +/* + a wrapper around talloc_steal() for situations where you are moving a pointer + between two structures, and want the old pointer to be set to NULL +*/ +_PUBLIC_ void *_talloc_move(const void *new_ctx, const void *_pptr) +{ + const void **pptr = discard_const_p(const void *,_pptr); + void *ret = talloc_steal(new_ctx, discard_const_p(void, *pptr)); + (*pptr) = NULL; + return ret; +} + +enum talloc_mem_count_type { + TOTAL_MEM_SIZE, + TOTAL_MEM_BLOCKS, + TOTAL_MEM_LIMIT, +}; + +static inline size_t _talloc_total_mem_internal(const void *ptr, + enum talloc_mem_count_type type, + struct talloc_memlimit *old_limit, + struct talloc_memlimit *new_limit) +{ + size_t total = 0; + struct talloc_chunk *c, *tc; + + if (ptr == NULL) { + ptr = null_context; + } + if (ptr == NULL) { + return 0; + } + + tc = talloc_chunk_from_ptr(ptr); + + if (old_limit || new_limit) { + if (tc->limit && tc->limit->upper == old_limit) { + tc->limit->upper = new_limit; + } + } + + /* optimize in the memlimits case */ + if (type == TOTAL_MEM_LIMIT && + tc->limit != NULL && + tc->limit != old_limit && + tc->limit->parent == tc) { + return tc->limit->cur_size; + } + + if (tc->flags & TALLOC_FLAG_LOOP) { + return 0; + } + + tc->flags |= TALLOC_FLAG_LOOP; + + if (old_limit || new_limit) { + if (old_limit == tc->limit) { + tc->limit = new_limit; + } + } + + switch (type) { + case TOTAL_MEM_SIZE: + if (likely(tc->name != TALLOC_MAGIC_REFERENCE)) { + total = tc->size; + } + break; + case TOTAL_MEM_BLOCKS: + total++; + break; + case TOTAL_MEM_LIMIT: + if (likely(tc->name != TALLOC_MAGIC_REFERENCE)) { + /* + * Don't count memory allocated from a pool + * when calculating limits. Only count the + * pool itself. + */ + if (!(tc->flags & TALLOC_FLAG_POOLMEM)) { + if (tc->flags & TALLOC_FLAG_POOL) { + /* + * If this is a pool, the allocated + * size is in the pool header, and + * remember to add in the prefix + * length. + */ + struct talloc_pool_hdr *pool_hdr + = talloc_pool_from_chunk(tc); + total = pool_hdr->poolsize + + TC_HDR_SIZE + + TP_HDR_SIZE; + } else { + total = tc->size + TC_HDR_SIZE; + } + } + } + break; + } + for (c = tc->child; c; c = c->next) { + total += _talloc_total_mem_internal(TC_PTR_FROM_CHUNK(c), type, + old_limit, new_limit); + } + + tc->flags &= ~TALLOC_FLAG_LOOP; + + return total; +} + +/* + return the total size of a talloc pool (subtree) +*/ +_PUBLIC_ size_t talloc_total_size(const void *ptr) +{ + return _talloc_total_mem_internal(ptr, TOTAL_MEM_SIZE, NULL, NULL); +} + +/* + return the total number of blocks in a talloc pool (subtree) +*/ +_PUBLIC_ size_t talloc_total_blocks(const void *ptr) +{ + return _talloc_total_mem_internal(ptr, TOTAL_MEM_BLOCKS, NULL, NULL); +} + +/* + return the number of external references to a pointer +*/ +_PUBLIC_ size_t talloc_reference_count(const void *ptr) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); + struct talloc_reference_handle *h; + size_t ret = 0; + + for (h=tc->refs;h;h=h->next) { + ret++; + } + return ret; +} + +/* + report on memory usage by all children of a pointer, giving a full tree view +*/ +_PUBLIC_ void talloc_report_depth_cb(const void *ptr, int depth, int max_depth, + void (*callback)(const void *ptr, + int depth, int max_depth, + int is_ref, + void *private_data), + void *private_data) +{ + struct talloc_chunk *c, *tc; + + if (ptr == NULL) { + ptr = null_context; + } + if (ptr == NULL) return; + + tc = talloc_chunk_from_ptr(ptr); + + if (tc->flags & TALLOC_FLAG_LOOP) { + return; + } + + callback(ptr, depth, max_depth, 0, private_data); + + if (max_depth >= 0 && depth >= max_depth) { + return; + } + + tc->flags |= TALLOC_FLAG_LOOP; + for (c=tc->child;c;c=c->next) { + if (c->name == TALLOC_MAGIC_REFERENCE) { + struct talloc_reference_handle *h = (struct talloc_reference_handle *)TC_PTR_FROM_CHUNK(c); + callback(h->ptr, depth + 1, max_depth, 1, private_data); + } else { + talloc_report_depth_cb(TC_PTR_FROM_CHUNK(c), depth + 1, max_depth, callback, private_data); + } + } + tc->flags &= ~TALLOC_FLAG_LOOP; +} + +static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_f) +{ + const char *name = __talloc_get_name(ptr); + struct talloc_chunk *tc; + FILE *f = (FILE *)_f; + + if (is_ref) { + fprintf(f, "%*sreference to: %s\n", depth*4, "", name); + return; + } + + tc = talloc_chunk_from_ptr(ptr); + if (tc->limit && tc->limit->parent == tc) { + fprintf(f, "%*s%-30s is a memlimit context" + " (max_size = %lu bytes, cur_size = %lu bytes)\n", + depth*4, "", + name, + (unsigned long)tc->limit->max_size, + (unsigned long)tc->limit->cur_size); + } + + if (depth == 0) { + fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n", + (max_depth < 0 ? "full " :""), name, + (unsigned long)talloc_total_size(ptr), + (unsigned long)talloc_total_blocks(ptr)); + return; + } + + fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n", + depth*4, "", + name, + (unsigned long)talloc_total_size(ptr), + (unsigned long)talloc_total_blocks(ptr), + (int)talloc_reference_count(ptr), ptr); + +#if 0 + fprintf(f, "content: "); + if (talloc_total_size(ptr)) { + int tot = talloc_total_size(ptr); + int i; + + for (i = 0; i < tot; i++) { + if ((((char *)ptr)[i] > 31) && (((char *)ptr)[i] < 126)) { + fprintf(f, "%c", ((char *)ptr)[i]); + } else { + fprintf(f, "~%02x", ((char *)ptr)[i]); + } + } + } + fprintf(f, "\n"); +#endif +} + +/* + report on memory usage by all children of a pointer, giving a full tree view +*/ +_PUBLIC_ void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f) +{ + if (f) { + talloc_report_depth_cb(ptr, depth, max_depth, talloc_report_depth_FILE_helper, f); + fflush(f); + } +} + +/* + report on memory usage by all children of a pointer, giving a full tree view +*/ +_PUBLIC_ void talloc_report_full(const void *ptr, FILE *f) +{ + talloc_report_depth_file(ptr, 0, -1, f); +} + +/* + report on memory usage by all children of a pointer +*/ +_PUBLIC_ void talloc_report(const void *ptr, FILE *f) +{ + talloc_report_depth_file(ptr, 0, 1, f); +} + +/* + enable tracking of the NULL context +*/ +_PUBLIC_ void talloc_enable_null_tracking(void) +{ + if (null_context == NULL) { + null_context = _talloc_named_const(NULL, 0, "null_context"); + if (autofree_context != NULL) { + talloc_reparent(NULL, null_context, autofree_context); + } + } +} + +/* + enable tracking of the NULL context, not moving the autofree context + into the NULL context. This is needed for the talloc testsuite +*/ +_PUBLIC_ void talloc_enable_null_tracking_no_autofree(void) +{ + if (null_context == NULL) { + null_context = _talloc_named_const(NULL, 0, "null_context"); + } +} + +/* + disable tracking of the NULL context +*/ +_PUBLIC_ void talloc_disable_null_tracking(void) +{ + if (null_context != NULL) { + /* we have to move any children onto the real NULL + context */ + struct talloc_chunk *tc, *tc2; + tc = talloc_chunk_from_ptr(null_context); + for (tc2 = tc->child; tc2; tc2=tc2->next) { + if (tc2->parent == tc) tc2->parent = NULL; + if (tc2->prev == tc) tc2->prev = NULL; + } + for (tc2 = tc->next; tc2; tc2=tc2->next) { + if (tc2->parent == tc) tc2->parent = NULL; + if (tc2->prev == tc) tc2->prev = NULL; + } + tc->child = NULL; + tc->next = NULL; + } + talloc_free(null_context); + null_context = NULL; +} + +/* + enable leak reporting on exit +*/ +_PUBLIC_ void talloc_enable_leak_report(void) +{ + talloc_enable_null_tracking(); + talloc_report_null = true; + talloc_setup_atexit(); +} + +/* + enable full leak reporting on exit +*/ +_PUBLIC_ void talloc_enable_leak_report_full(void) +{ + talloc_enable_null_tracking(); + talloc_report_null_full = true; + talloc_setup_atexit(); +} + +/* + talloc and zero memory. +*/ +_PUBLIC_ void *_talloc_zero(const void *ctx, size_t size, const char *name) +{ + void *p = _talloc_named_const(ctx, size, name); + + if (p) { + memset(p, '\0', size); + } + + return p; +} + +/* + memdup with a talloc. +*/ +_PUBLIC_ void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name) +{ + void *newp = NULL; + + if (likely(size > 0) && unlikely(p == NULL)) { + return NULL; + } + + newp = _talloc_named_const(t, size, name); + if (likely(newp != NULL) && likely(size > 0)) { + memcpy(newp, p, size); + } + + return newp; +} + +static inline char *__talloc_strlendup(const void *t, const char *p, size_t len) +{ + char *ret; + struct talloc_chunk *tc = NULL; + + ret = (char *)__talloc(t, len + 1, &tc); + if (unlikely(!ret)) return NULL; + + memcpy(ret, p, len); + ret[len] = 0; + + _tc_set_name_const(tc, ret); + return ret; +} + +/* + strdup with a talloc +*/ +_PUBLIC_ char *talloc_strdup(const void *t, const char *p) +{ + if (unlikely(!p)) return NULL; + return __talloc_strlendup(t, p, strlen(p)); +} + +/* + strndup with a talloc +*/ +_PUBLIC_ char *talloc_strndup(const void *t, const char *p, size_t n) +{ + if (unlikely(!p)) return NULL; + return __talloc_strlendup(t, p, strnlen(p, n)); +} + +static inline char *__talloc_strlendup_append(char *s, size_t slen, + const char *a, size_t alen) +{ + char *ret; + + ret = talloc_realloc(NULL, s, char, slen + alen + 1); + if (unlikely(!ret)) return NULL; + + /* append the string and the trailing \0 */ + memcpy(&ret[slen], a, alen); + ret[slen+alen] = 0; + + _tc_set_name_const(talloc_chunk_from_ptr(ret), ret); + return ret; +} + +/* + * Appends at the end of the string. + */ +_PUBLIC_ char *talloc_strdup_append(char *s, const char *a) +{ + if (unlikely(!s)) { + return talloc_strdup(NULL, a); + } + + if (unlikely(!a)) { + return s; + } + + return __talloc_strlendup_append(s, strlen(s), a, strlen(a)); +} + +/* + * Appends at the end of the talloc'ed buffer, + * not the end of the string. + */ +_PUBLIC_ char *talloc_strdup_append_buffer(char *s, const char *a) +{ + size_t slen; + + if (unlikely(!s)) { + return talloc_strdup(NULL, a); + } + + if (unlikely(!a)) { + return s; + } + + slen = talloc_get_size(s); + if (likely(slen > 0)) { + slen--; + } + + return __talloc_strlendup_append(s, slen, a, strlen(a)); +} + +/* + * Appends at the end of the string. + */ +_PUBLIC_ char *talloc_strndup_append(char *s, const char *a, size_t n) +{ + if (unlikely(!s)) { + return talloc_strndup(NULL, a, n); + } + + if (unlikely(!a)) { + return s; + } + + return __talloc_strlendup_append(s, strlen(s), a, strnlen(a, n)); +} + +/* + * Appends at the end of the talloc'ed buffer, + * not the end of the string. + */ +_PUBLIC_ char *talloc_strndup_append_buffer(char *s, const char *a, size_t n) +{ + size_t slen; + + if (unlikely(!s)) { + return talloc_strndup(NULL, a, n); + } + + if (unlikely(!a)) { + return s; + } + + slen = talloc_get_size(s); + if (likely(slen > 0)) { + slen--; + } + + return __talloc_strlendup_append(s, slen, a, strnlen(a, n)); +} + +#ifndef HAVE_VA_COPY +#ifdef HAVE___VA_COPY +#define va_copy(dest, src) __va_copy(dest, src) +#else +#define va_copy(dest, src) (dest) = (src) +#endif +#endif + +static struct talloc_chunk *_vasprintf_tc(const void *t, + const char *fmt, + va_list ap) PRINTF_ATTRIBUTE(2,0); + +static struct talloc_chunk *_vasprintf_tc(const void *t, + const char *fmt, + va_list ap) +{ + int vlen; + size_t len; + char *ret; + va_list ap2; + struct talloc_chunk *tc = NULL; + char buf[1024]; + + /* this call looks strange, but it makes it work on older solaris boxes */ + va_copy(ap2, ap); + vlen = vsnprintf(buf, sizeof(buf), fmt, ap2); + va_end(ap2); + if (unlikely(vlen < 0)) { + return NULL; + } + len = vlen; + if (unlikely(len + 1 < len)) { + return NULL; + } + + ret = (char *)__talloc(t, len+1, &tc); + if (unlikely(!ret)) return NULL; + + if (len < sizeof(buf)) { + memcpy(ret, buf, len+1); + } else { + va_copy(ap2, ap); + vsnprintf(ret, len+1, fmt, ap2); + va_end(ap2); + } + + _tc_set_name_const(tc, ret); + return tc; +} + +_PUBLIC_ char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) +{ + struct talloc_chunk *tc = _vasprintf_tc(t, fmt, ap); + if (tc == NULL) { + return NULL; + } + return TC_PTR_FROM_CHUNK(tc); +} + + +/* + Perform string formatting, and return a pointer to newly allocated + memory holding the result, inside a memory pool. + */ +_PUBLIC_ char *talloc_asprintf(const void *t, const char *fmt, ...) +{ + va_list ap; + char *ret; + + va_start(ap, fmt); + ret = talloc_vasprintf(t, fmt, ap); + va_end(ap); + return ret; +} + +static inline char *__talloc_vaslenprintf_append(char *s, size_t slen, + const char *fmt, va_list ap) + PRINTF_ATTRIBUTE(3,0); + +static inline char *__talloc_vaslenprintf_append(char *s, size_t slen, + const char *fmt, va_list ap) +{ + ssize_t alen; + va_list ap2; + char c; + + va_copy(ap2, ap); + alen = vsnprintf(&c, 1, fmt, ap2); + va_end(ap2); + + if (alen <= 0) { + /* Either the vsnprintf failed or the format resulted in + * no characters being formatted. In the former case, we + * ought to return NULL, in the latter we ought to return + * the original string. Most current callers of this + * function expect it to never return NULL. + */ + return s; + } + + s = talloc_realloc(NULL, s, char, slen + alen + 1); + if (!s) return NULL; + + va_copy(ap2, ap); + vsnprintf(s + slen, alen + 1, fmt, ap2); + va_end(ap2); + + _tc_set_name_const(talloc_chunk_from_ptr(s), s); + return s; +} + +/** + * Realloc @p s to append the formatted result of @p fmt and @p ap, + * and return @p s, which may have moved. Good for gradually + * accumulating output into a string buffer. Appends at the end + * of the string. + **/ +_PUBLIC_ char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) +{ + if (unlikely(!s)) { + return talloc_vasprintf(NULL, fmt, ap); + } + + return __talloc_vaslenprintf_append(s, strlen(s), fmt, ap); +} + +/** + * Realloc @p s to append the formatted result of @p fmt and @p ap, + * and return @p s, which may have moved. Always appends at the + * end of the talloc'ed buffer, not the end of the string. + **/ +_PUBLIC_ char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap) +{ + size_t slen; + + if (unlikely(!s)) { + return talloc_vasprintf(NULL, fmt, ap); + } + + slen = talloc_get_size(s); + if (likely(slen > 0)) { + slen--; + } + + return __talloc_vaslenprintf_append(s, slen, fmt, ap); +} + +/* + Realloc @p s to append the formatted result of @p fmt and return @p + s, which may have moved. Good for gradually accumulating output + into a string buffer. + */ +_PUBLIC_ char *talloc_asprintf_append(char *s, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + s = talloc_vasprintf_append(s, fmt, ap); + va_end(ap); + return s; +} + +/* + Realloc @p s to append the formatted result of @p fmt and return @p + s, which may have moved. Good for gradually accumulating output + into a buffer. + */ +_PUBLIC_ char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + s = talloc_vasprintf_append_buffer(s, fmt, ap); + va_end(ap); + return s; +} + +_PUBLIC_ void talloc_asprintf_addbuf(char **ps, const char *fmt, ...) +{ + va_list ap; + char *s = *ps; + char *t = NULL; + + if (s == NULL) { + return; + } + + va_start(ap, fmt); + t = talloc_vasprintf_append_buffer(s, fmt, ap); + va_end(ap); + + if (t == NULL) { + /* signal failure to the next caller */ + TALLOC_FREE(s); + *ps = NULL; + } else { + *ps = t; + } +} + +/* + alloc an array, checking for integer overflow in the array size +*/ +_PUBLIC_ void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name) +{ + if (count >= MAX_TALLOC_SIZE/el_size) { + return NULL; + } + return _talloc_named_const(ctx, el_size * count, name); +} + +/* + alloc an zero array, checking for integer overflow in the array size +*/ +_PUBLIC_ void *_talloc_zero_array(const void *ctx, size_t el_size, unsigned count, const char *name) +{ + if (count >= MAX_TALLOC_SIZE/el_size) { + return NULL; + } + return _talloc_zero(ctx, el_size * count, name); +} + +/* + realloc an array, checking for integer overflow in the array size +*/ +_PUBLIC_ void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name) +{ + if (count >= MAX_TALLOC_SIZE/el_size) { + return NULL; + } + return _talloc_realloc(ctx, ptr, el_size * count, name); +} + +/* + a function version of talloc_realloc(), so it can be passed as a function pointer + to libraries that want a realloc function (a realloc function encapsulates + all the basic capabilities of an allocation library, which is why this is useful) +*/ +_PUBLIC_ void *talloc_realloc_fn(const void *context, void *ptr, size_t size) +{ + return _talloc_realloc(context, ptr, size, NULL); +} + + +static int talloc_autofree_destructor(void *ptr) +{ + autofree_context = NULL; + return 0; +} + +/* + return a context which will be auto-freed on exit + this is useful for reducing the noise in leak reports +*/ +_PUBLIC_ void *talloc_autofree_context(void) +{ + if (autofree_context == NULL) { + autofree_context = _talloc_named_const(NULL, 0, "autofree_context"); + talloc_set_destructor(autofree_context, talloc_autofree_destructor); + talloc_setup_atexit(); + } + return autofree_context; +} + +_PUBLIC_ size_t talloc_get_size(const void *context) +{ + struct talloc_chunk *tc; + + if (context == NULL) { + return 0; + } + + tc = talloc_chunk_from_ptr(context); + + return tc->size; +} + +/* + find a parent of this context that has the given name, if any +*/ +_PUBLIC_ void *talloc_find_parent_byname(const void *context, const char *name) +{ + struct talloc_chunk *tc; + + if (context == NULL) { + return NULL; + } + + tc = talloc_chunk_from_ptr(context); + while (tc) { + if (tc->name && strcmp(tc->name, name) == 0) { + return TC_PTR_FROM_CHUNK(tc); + } + while (tc && tc->prev) tc = tc->prev; + if (tc) { + tc = tc->parent; + } + } + return NULL; +} + +/* + show the parentage of a context +*/ +_PUBLIC_ void talloc_show_parents(const void *context, FILE *file) +{ + struct talloc_chunk *tc; + + if (context == NULL) { + fprintf(file, "talloc no parents for NULL\n"); + return; + } + + tc = talloc_chunk_from_ptr(context); + fprintf(file, "talloc parents of '%s'\n", __talloc_get_name(context)); + while (tc) { + fprintf(file, "\t'%s'\n", __talloc_get_name(TC_PTR_FROM_CHUNK(tc))); + while (tc && tc->prev) tc = tc->prev; + if (tc) { + tc = tc->parent; + } + } + fflush(file); +} + +/* + return 1 if ptr is a parent of context +*/ +static int _talloc_is_parent(const void *context, const void *ptr, int depth) +{ + struct talloc_chunk *tc; + + if (context == NULL) { + return 0; + } + + tc = talloc_chunk_from_ptr(context); + while (tc) { + if (depth <= 0) { + return 0; + } + if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1; + while (tc && tc->prev) tc = tc->prev; + if (tc) { + tc = tc->parent; + depth--; + } + } + return 0; +} + +/* + return 1 if ptr is a parent of context +*/ +_PUBLIC_ int talloc_is_parent(const void *context, const void *ptr) +{ + return _talloc_is_parent(context, ptr, TALLOC_MAX_DEPTH); +} + +/* + return the total size of memory used by this context and all children +*/ +static inline size_t _talloc_total_limit_size(const void *ptr, + struct talloc_memlimit *old_limit, + struct talloc_memlimit *new_limit) +{ + return _talloc_total_mem_internal(ptr, TOTAL_MEM_LIMIT, + old_limit, new_limit); +} + +static inline bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size) +{ + struct talloc_memlimit *l; + + for (l = limit; l != NULL; l = l->upper) { + if (l->max_size != 0 && + ((l->max_size <= l->cur_size) || + (l->max_size - l->cur_size < size))) { + return false; + } + } + + return true; +} + +/* + Update memory limits when freeing a talloc_chunk. +*/ +static void tc_memlimit_update_on_free(struct talloc_chunk *tc) +{ + size_t limit_shrink_size; + + if (!tc->limit) { + return; + } + + /* + * Pool entries don't count. Only the pools + * themselves are counted as part of the memory + * limits. Note that this also takes care of + * nested pools which have both flags + * TALLOC_FLAG_POOLMEM|TALLOC_FLAG_POOL set. + */ + if (tc->flags & TALLOC_FLAG_POOLMEM) { + return; + } + + /* + * If we are part of a memory limited context hierarchy + * we need to subtract the memory used from the counters + */ + + limit_shrink_size = tc->size+TC_HDR_SIZE; + + /* + * If we're deallocating a pool, take into + * account the prefix size added for the pool. + */ + + if (tc->flags & TALLOC_FLAG_POOL) { + limit_shrink_size += TP_HDR_SIZE; + } + + talloc_memlimit_shrink(tc->limit, limit_shrink_size); + + if (tc->limit->parent == tc) { + free(tc->limit); + } + + tc->limit = NULL; +} + +/* + Increase memory limit accounting after a malloc/realloc. +*/ +static void talloc_memlimit_grow(struct talloc_memlimit *limit, + size_t size) +{ + struct talloc_memlimit *l; + + for (l = limit; l != NULL; l = l->upper) { + size_t new_cur_size = l->cur_size + size; + if (new_cur_size < l->cur_size) { + talloc_abort("logic error in talloc_memlimit_grow\n"); + return; + } + l->cur_size = new_cur_size; + } +} + +/* + Decrease memory limit accounting after a free/realloc. +*/ +static void talloc_memlimit_shrink(struct talloc_memlimit *limit, + size_t size) +{ + struct talloc_memlimit *l; + + for (l = limit; l != NULL; l = l->upper) { + if (l->cur_size < size) { + talloc_abort("logic error in talloc_memlimit_shrink\n"); + return; + } + l->cur_size = l->cur_size - size; + } +} + +_PUBLIC_ int talloc_set_memlimit(const void *ctx, size_t max_size) +{ + struct talloc_chunk *tc = talloc_chunk_from_ptr(ctx); + struct talloc_memlimit *orig_limit; + struct talloc_memlimit *limit = NULL; + + if (tc->limit && tc->limit->parent == tc) { + tc->limit->max_size = max_size; + return 0; + } + orig_limit = tc->limit; + + limit = malloc(sizeof(struct talloc_memlimit)); + if (limit == NULL) { + return 1; + } + limit->parent = tc; + limit->max_size = max_size; + limit->cur_size = _talloc_total_limit_size(ctx, tc->limit, limit); + + if (orig_limit) { + limit->upper = orig_limit; + } else { + limit->upper = NULL; + } + + return 0; +} diff --git a/lib/talloc/talloc.h b/lib/talloc/talloc.h new file mode 100644 index 0000000..c466c36 --- /dev/null +++ b/lib/talloc/talloc.h @@ -0,0 +1,1972 @@ +#ifndef _TALLOC_H_ +#define _TALLOC_H_ +/* + Unix SMB/CIFS implementation. + Samba temporary memory allocation functions + + Copyright (C) Andrew Tridgell 2004-2005 + Copyright (C) Stefan Metzmacher 2006 + + ** NOTE! The following LGPL license applies to the talloc + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include <stdlib.h> +#include <stdio.h> +#include <stdarg.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* for old gcc releases that don't have the feature test macro __has_attribute */ +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif + +#ifndef _PUBLIC_ +#if __has_attribute(visibility) +#define _PUBLIC_ __attribute__((visibility("default"))) +#else +#define _PUBLIC_ +#endif +#endif + +/** + * @defgroup talloc The talloc API + * + * talloc is a hierarchical, reference counted memory pool system with + * destructors. It is the core memory allocator used in Samba. + * + * @{ + */ + +#define TALLOC_VERSION_MAJOR 2 +#define TALLOC_VERSION_MINOR 4 + +_PUBLIC_ int talloc_version_major(void); +_PUBLIC_ int talloc_version_minor(void); +/* This is mostly useful only for testing */ +_PUBLIC_ int talloc_test_get_magic(void); + +/** + * @brief Define a talloc parent type + * + * As talloc is a hierarchial memory allocator, every talloc chunk is a + * potential parent to other talloc chunks. So defining a separate type for a + * talloc chunk is not strictly necessary. TALLOC_CTX is defined nevertheless, + * as it provides an indicator for function arguments. You will frequently + * write code like + * + * @code + * struct foo *foo_create(TALLOC_CTX *mem_ctx) + * { + * struct foo *result; + * result = talloc(mem_ctx, struct foo); + * if (result == NULL) return NULL; + * ... initialize foo ... + * return result; + * } + * @endcode + * + * In this type of allocating functions it is handy to have a general + * TALLOC_CTX type to indicate which parent to put allocated structures on. + */ +typedef void TALLOC_CTX; + +/* + this uses a little trick to allow __LINE__ to be stringified +*/ +#ifndef __location__ +#define __TALLOC_STRING_LINE1__(s) #s +#define __TALLOC_STRING_LINE2__(s) __TALLOC_STRING_LINE1__(s) +#define __TALLOC_STRING_LINE3__ __TALLOC_STRING_LINE2__(__LINE__) +#define __location__ __FILE__ ":" __TALLOC_STRING_LINE3__ +#endif + +#ifndef TALLOC_DEPRECATED +#define TALLOC_DEPRECATED 0 +#endif + +#ifndef PRINTF_ATTRIBUTE +#if __has_attribute(format) || (__GNUC__ >= 3) +/** Use gcc attribute to check printf fns. a1 is the 1-based index of + * the parameter containing the format, and a2 the index of the first + * argument. Note that some gcc 2.x versions don't handle this + * properly **/ +#define PRINTF_ATTRIBUTE(a1, a2) __attribute__ ((format (__printf__, a1, a2))) +#else +#define PRINTF_ATTRIBUTE(a1, a2) +#endif +#endif + +#ifndef _DEPRECATED_ +#if __has_attribute(deprecated) || (__GNUC__ >= 3) +#define _DEPRECATED_ __attribute__ ((deprecated)) +#else +#define _DEPRECATED_ +#endif +#endif +#ifdef DOXYGEN + +/** + * @brief Create a new talloc context. + * + * The talloc() macro is the core of the talloc library. It takes a memory + * context and a type, and returns a pointer to a new area of memory of the + * given type. + * + * The returned pointer is itself a talloc context, so you can use it as the + * context argument to more calls to talloc if you wish. + * + * The returned pointer is a "child" of the supplied context. This means that if + * you talloc_free() the context then the new child disappears as well. + * Alternatively you can free just the child. + * + * @param[in] ctx A talloc context to create a new reference on or NULL to + * create a new top level context. + * + * @param[in] type The type of memory to allocate. + * + * @return A type casted talloc context or NULL on error. + * + * @code + * unsigned int *a, *b; + * + * a = talloc(NULL, unsigned int); + * b = talloc(a, unsigned int); + * @endcode + * + * @see talloc_zero + * @see talloc_array + * @see talloc_steal + * @see talloc_free + */ +_PUBLIC_ void *talloc(const void *ctx, #type); +#else +#define talloc(ctx, type) (type *)talloc_named_const(ctx, sizeof(type), #type) +_PUBLIC_ void *_talloc(const void *context, size_t size); +#endif + +/** + * @brief Create a new top level talloc context. + * + * This function creates a zero length named talloc context as a top level + * context. It is equivalent to: + * + * @code + * talloc_named(NULL, 0, fmt, ...); + * @endcode + * @param[in] fmt Format string for the name. + * + * @param[in] ... Additional printf-style arguments. + * + * @return The allocated memory chunk, NULL on error. + * + * @see talloc_named() + */ +_PUBLIC_ void *talloc_init(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2); + +#ifdef DOXYGEN +/** + * @brief Free a chunk of talloc memory. + * + * The talloc_free() function frees a piece of talloc memory, and all its + * children. You can call talloc_free() on any pointer returned by + * talloc(). + * + * The return value of talloc_free() indicates success or failure, with 0 + * returned for success and -1 for failure. A possible failure condition + * is if the pointer had a destructor attached to it and the destructor + * returned -1. See talloc_set_destructor() for details on + * destructors. Likewise, if "ptr" is NULL, then the function will make + * no modifications and return -1. + * + * From version 2.0 and onwards, as a special case, talloc_free() is + * refused on pointers that have more than one parent associated, as talloc + * would have no way of knowing which parent should be removed. This is + * different from older versions in the sense that always the reference to + * the most recently established parent has been destroyed. Hence to free a + * pointer that has more than one parent please use talloc_unlink(). + * + * To help you find problems in your code caused by this behaviour, if + * you do try and free a pointer with more than one parent then the + * talloc logging function will be called to give output like this: + * + * @code + * ERROR: talloc_free with references at some_dir/source/foo.c:123 + * reference at some_dir/source/other.c:325 + * reference at some_dir/source/third.c:121 + * @endcode + * + * Please see the documentation for talloc_set_log_fn() and + * talloc_set_log_stderr() for more information on talloc logging + * functions. + * + * If <code>TALLOC_FREE_FILL</code> environment variable is set, + * the memory occupied by the context is filled with the value of this variable. + * The value should be a numeric representation of the character you want to + * use. + * + * talloc_free() operates recursively on its children. + * + * @param[in] ptr The chunk to be freed. + * + * @return Returns 0 on success and -1 on error. A possible + * failure condition is if the pointer had a destructor + * attached to it and the destructor returned -1. Likewise, + * if "ptr" is NULL, then the function will make no + * modifications and returns -1. + * + * Example: + * @code + * unsigned int *a, *b; + * a = talloc(NULL, unsigned int); + * b = talloc(a, unsigned int); + * + * talloc_free(a); // Frees a and b + * @endcode + * + * @see talloc_set_destructor() + * @see talloc_unlink() + */ +_PUBLIC_ int talloc_free(void *ptr); +#else +#define talloc_free(ctx) _talloc_free(ctx, __location__) +_PUBLIC_ int _talloc_free(void *ptr, const char *location); +#endif + +/** + * @brief Free a talloc chunk's children. + * + * The function walks along the list of all children of a talloc context and + * talloc_free()s only the children, not the context itself. + * + * A NULL argument is handled as no-op. + * + * @param[in] ptr The chunk that you want to free the children of + * (NULL is allowed too) + */ +_PUBLIC_ void talloc_free_children(void *ptr); + +#ifdef DOXYGEN +/** + * @brief Assign a destructor function to be called when a chunk is freed. + * + * The function talloc_set_destructor() sets the "destructor" for the pointer + * "ptr". A destructor is a function that is called when the memory used by a + * pointer is about to be released. The destructor receives the pointer as an + * argument, and should return 0 for success and -1 for failure. + * + * The destructor can do anything it wants to, including freeing other pieces + * of memory. A common use for destructors is to clean up operating system + * resources (such as open file descriptors) contained in the structure the + * destructor is placed on. + * + * You can only place one destructor on a pointer. If you need more than one + * destructor then you can create a zero-length child of the pointer and place + * an additional destructor on that. + * + * To remove a destructor call talloc_set_destructor() with NULL for the + * destructor. + * + * If your destructor attempts to talloc_free() the pointer that it is the + * destructor for then talloc_free() will return -1 and the free will be + * ignored. This would be a pointless operation anyway, as the destructor is + * only called when the memory is just about to go away. + * + * @param[in] ptr The talloc chunk to add a destructor to. + * + * @param[in] destructor The destructor function to be called. NULL to remove + * it. + * + * Example: + * @code + * static int destroy_fd(int *fd) { + * close(*fd); + * return 0; + * } + * + * int *open_file(const char *filename) { + * int *fd = talloc(NULL, int); + * *fd = open(filename, O_RDONLY); + * if (*fd < 0) { + * talloc_free(fd); + * return NULL; + * } + * // Whenever they free this, we close the file. + * talloc_set_destructor(fd, destroy_fd); + * return fd; + * } + * @endcode + * + * @see talloc() + * @see talloc_free() + */ +_PUBLIC_ void talloc_set_destructor(const void *ptr, int (*destructor)(void *)); + +/** + * @brief Change a talloc chunk's parent. + * + * The talloc_steal() function changes the parent context of a talloc + * pointer. It is typically used when the context that the pointer is + * currently a child of is going to be freed and you wish to keep the + * memory for a longer time. + * + * To make the changed hierarchy less error-prone, you might consider to use + * talloc_move(). + * + * If you try and call talloc_steal() on a pointer that has more than one + * parent then the result is ambiguous. Talloc will choose to remove the + * parent that is currently indicated by talloc_parent() and replace it with + * the chosen parent. You will also get a message like this via the talloc + * logging functions: + * + * @code + * WARNING: talloc_steal with references at some_dir/source/foo.c:123 + * reference at some_dir/source/other.c:325 + * reference at some_dir/source/third.c:121 + * @endcode + * + * To unambiguously change the parent of a pointer please see the function + * talloc_reparent(). See the talloc_set_log_fn() documentation for more + * information on talloc logging. + * + * @param[in] new_ctx The new parent context. + * + * @param[in] ptr The talloc chunk to move. + * + * @return Returns the pointer that you pass it. It does not have + * any failure modes. + * + * @note It is possible to produce loops in the parent/child relationship + * if you are not careful with talloc_steal(). No guarantees are provided + * as to your sanity or the safety of your data if you do this. + */ +_PUBLIC_ void *talloc_steal(const void *new_ctx, const void *ptr); +#else /* DOXYGEN */ +/* try to make talloc_set_destructor() and talloc_steal() type safe, + if we have a recent gcc */ +#if (__GNUC__ >= 3) +#define _TALLOC_TYPEOF(ptr) __typeof__(ptr) +#define talloc_set_destructor(ptr, function) \ + do { \ + int (*_talloc_destructor_fn)(_TALLOC_TYPEOF(ptr)) = (function); \ + _talloc_set_destructor((ptr), (int (*)(void *))_talloc_destructor_fn); \ + } while(0) +/* this extremely strange macro is to avoid some braindamaged warning + stupidity in gcc 4.1.x */ +#define talloc_steal(ctx, ptr) ({ _TALLOC_TYPEOF(ptr) __talloc_steal_ret = (_TALLOC_TYPEOF(ptr))_talloc_steal_loc((ctx),(ptr), __location__); __talloc_steal_ret; }) +#else /* __GNUC__ >= 3 */ +#define talloc_set_destructor(ptr, function) \ + _talloc_set_destructor((ptr), (int (*)(void *))(function)) +#define _TALLOC_TYPEOF(ptr) void * +#define talloc_steal(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_steal_loc((ctx),(ptr), __location__) +#endif /* __GNUC__ >= 3 */ +_PUBLIC_ void _talloc_set_destructor(const void *ptr, int (*_destructor)(void *)); +_PUBLIC_ void *_talloc_steal_loc(const void *new_ctx, const void *ptr, const char *location); +#endif /* DOXYGEN */ + +/** + * @brief Assign a name to a talloc chunk. + * + * Each talloc pointer has a "name". The name is used principally for + * debugging purposes, although it is also possible to set and get the name on + * a pointer in as a way of "marking" pointers in your code. + * + * The main use for names on pointer is for "talloc reports". See + * talloc_report() and talloc_report_full() for details. Also see + * talloc_enable_leak_report() and talloc_enable_leak_report_full(). + * + * The talloc_set_name() function allocates memory as a child of the + * pointer. It is logically equivalent to: + * + * @code + * talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...)); + * @endcode + * + * @param[in] ptr The talloc chunk to assign a name to. + * + * @param[in] fmt Format string for the name. + * + * @param[in] ... Add printf-style additional arguments. + * + * @return The assigned name, NULL on error. + * + * @note Multiple calls to talloc_set_name() will allocate more memory without + * releasing the name. All of the memory is released when the ptr is freed + * using talloc_free(). + */ +_PUBLIC_ const char *talloc_set_name(const void *ptr, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); + +#ifdef DOXYGEN +/** + * @brief Change a talloc chunk's parent. + * + * This function has the same effect as talloc_steal(), and additionally sets + * the source pointer to NULL. You would use it like this: + * + * @code + * struct foo *X = talloc(tmp_ctx, struct foo); + * struct foo *Y; + * Y = talloc_move(new_ctx, &X); + * @endcode + * + * @param[in] new_ctx The new parent context. + * + * @param[in] pptr Pointer to a pointer to the talloc chunk to move. + * + * @return The pointer to the talloc chunk that moved. + * It does not have any failure modes. + * + */ +_PUBLIC_ void *talloc_move(const void *new_ctx, void **pptr); +#else +#define talloc_move(ctx, pptr) (_TALLOC_TYPEOF(*(pptr)))_talloc_move((ctx),(void *)(pptr)) +_PUBLIC_ void *_talloc_move(const void *new_ctx, const void *pptr); +#endif + +/** + * @brief Assign a name to a talloc chunk. + * + * The function is just like talloc_set_name(), but it takes a string constant, + * and is much faster. It is extensively used by the "auto naming" macros, such + * as talloc_p(). + * + * This function does not allocate any memory. It just copies the supplied + * pointer into the internal representation of the talloc ptr. This means you + * must not pass a name pointer to memory that will disappear before the ptr + * is freed with talloc_free(). + * + * @param[in] ptr The talloc chunk to assign a name to. + * + * @param[in] name Format string for the name. + */ +_PUBLIC_ void talloc_set_name_const(const void *ptr, const char *name); + +/** + * @brief Create a named talloc chunk. + * + * The talloc_named() function creates a named talloc pointer. It is + * equivalent to: + * + * @code + * ptr = talloc_size(context, size); + * talloc_set_name(ptr, fmt, ....); + * @endcode + * + * @param[in] context The talloc context to hang the result off. + * + * @param[in] size Number of char's that you want to allocate. + * + * @param[in] fmt Format string for the name. + * + * @param[in] ... Additional printf-style arguments. + * + * @return The allocated memory chunk, NULL on error. + * + * @see talloc_set_name() + */ +_PUBLIC_ void *talloc_named(const void *context, size_t size, + const char *fmt, ...) PRINTF_ATTRIBUTE(3,4); + +/** + * @brief Basic routine to allocate a chunk of memory. + * + * This is equivalent to: + * + * @code + * ptr = talloc_size(context, size); + * talloc_set_name_const(ptr, name); + * @endcode + * + * @param[in] context The parent context. + * + * @param[in] size The number of char's that we want to allocate. + * + * @param[in] name The name the talloc block has. + * + * @return The allocated memory chunk, NULL on error. + */ +_PUBLIC_ void *talloc_named_const(const void *context, size_t size, const char *name); + +#ifdef DOXYGEN +/** + * @brief Untyped allocation. + * + * The function should be used when you don't have a convenient type to pass to + * talloc(). Unlike talloc(), it is not type safe (as it returns a void *), so + * you are on your own for type checking. + * + * Best to use talloc() or talloc_array() instead. + * + * @param[in] ctx The talloc context to hang the result off. + * + * @param[in] size Number of char's that you want to allocate. + * + * @return The allocated memory chunk, NULL on error. + * + * Example: + * @code + * void *mem = talloc_size(NULL, 100); + * @endcode + */ +_PUBLIC_ void *talloc_size(const void *ctx, size_t size); +#else +#define talloc_size(ctx, size) talloc_named_const(ctx, size, __location__) +#endif + +#ifdef DOXYGEN +/** + * @brief Allocate into a typed pointer. + * + * The talloc_ptrtype() macro should be used when you have a pointer and want + * to allocate memory to point at with this pointer. When compiling with + * gcc >= 3 it is typesafe. Note this is a wrapper of talloc_size() and + * talloc_get_name() will return the current location in the source file and + * not the type. + * + * @param[in] ctx The talloc context to hang the result off. + * + * @param[in] type The pointer you want to assign the result to. + * + * @return The properly casted allocated memory chunk, NULL on + * error. + * + * Example: + * @code + * unsigned int *a = talloc_ptrtype(NULL, a); + * @endcode + */ +_PUBLIC_ void *talloc_ptrtype(const void *ctx, #type); +#else +#define talloc_ptrtype(ctx, ptr) (_TALLOC_TYPEOF(ptr))talloc_size(ctx, sizeof(*(ptr))) +#endif + +#ifdef DOXYGEN +/** + * @brief Allocate a new 0-sized talloc chunk. + * + * This is a utility macro that creates a new memory context hanging off an + * existing context, automatically naming it "talloc_new: __location__" where + * __location__ is the source line it is called from. It is particularly + * useful for creating a new temporary working context. + * + * @param[in] ctx The talloc parent context. + * + * @return A new talloc chunk, NULL on error. + */ +_PUBLIC_ void *talloc_new(const void *ctx); +#else +#define talloc_new(ctx) talloc_named_const(ctx, 0, "talloc_new: " __location__) +#endif + +#ifdef DOXYGEN +/** + * @brief Allocate a 0-initizialized structure. + * + * The macro is equivalent to: + * + * @code + * ptr = talloc(ctx, type); + * if (ptr) memset(ptr, 0, sizeof(type)); + * @endcode + * + * @param[in] ctx The talloc context to hang the result off. + * + * @param[in] type The type that we want to allocate. + * + * @return Pointer to a piece of memory, properly cast to 'type *', + * NULL on error. + * + * Example: + * @code + * unsigned int *a, *b; + * a = talloc_zero(NULL, unsigned int); + * b = talloc_zero(a, unsigned int); + * @endcode + * + * @see talloc() + * @see talloc_zero_size() + * @see talloc_zero_array() + */ +_PUBLIC_ void *talloc_zero(const void *ctx, #type); + +/** + * @brief Allocate untyped, 0-initialized memory. + * + * @param[in] ctx The talloc context to hang the result off. + * + * @param[in] size Number of char's that you want to allocate. + * + * @return The allocated memory chunk. + */ +_PUBLIC_ void *talloc_zero_size(const void *ctx, size_t size); +#else +#define talloc_zero(ctx, type) (type *)_talloc_zero(ctx, sizeof(type), #type) +#define talloc_zero_size(ctx, size) _talloc_zero(ctx, size, __location__) +_PUBLIC_ void *_talloc_zero(const void *ctx, size_t size, const char *name); +#endif + +/** + * @brief Return the name of a talloc chunk. + * + * @param[in] ptr The talloc chunk. + * + * @return The current name for the given talloc pointer. + * + * @see talloc_set_name() + */ +_PUBLIC_ const char *talloc_get_name(const void *ptr); + +/** + * @brief Verify that a talloc chunk carries a specified name. + * + * This function checks if a pointer has the specified name. If it does + * then the pointer is returned. + * + * @param[in] ptr The talloc chunk to check. + * + * @param[in] name The name to check against. + * + * @return The pointer if the name matches, NULL if it doesn't. + */ +_PUBLIC_ void *talloc_check_name(const void *ptr, const char *name); + +/** + * @brief Get the parent chunk of a pointer. + * + * @param[in] ptr The talloc pointer to inspect. + * + * @return The talloc parent of ptr, NULL on error. + */ +_PUBLIC_ void *talloc_parent(const void *ptr); + +/** + * @brief Get a talloc chunk's parent name. + * + * @param[in] ptr The talloc pointer to inspect. + * + * @return The name of ptr's parent chunk. + */ +_PUBLIC_ const char *talloc_parent_name(const void *ptr); + +/** + * @brief Get the total size of a talloc chunk including its children. + * + * The function returns the total size in bytes used by this pointer and all + * child pointers. Mostly useful for debugging. + * + * Passing NULL is allowed, but it will only give a meaningful result if + * talloc_enable_leak_report() or talloc_enable_leak_report_full() has + * been called. + * + * @param[in] ptr The talloc chunk. + * + * @return The total size. + */ +_PUBLIC_ size_t talloc_total_size(const void *ptr); + +/** + * @brief Get the number of talloc chunks hanging off a chunk. + * + * The talloc_total_blocks() function returns the total memory block + * count used by this pointer and all child pointers. Mostly useful for + * debugging. + * + * Passing NULL is allowed, but it will only give a meaningful result if + * talloc_enable_leak_report() or talloc_enable_leak_report_full() has + * been called. + * + * @param[in] ptr The talloc chunk. + * + * @return The total size. + */ +_PUBLIC_ size_t talloc_total_blocks(const void *ptr); + +#ifdef DOXYGEN +/** + * @brief Duplicate a memory area into a talloc chunk. + * + * The function is equivalent to: + * + * @code + * ptr = talloc_size(ctx, size); + * if (ptr) memcpy(ptr, p, size); + * @endcode + * + * @param[in] t The talloc context to hang the result off. + * + * @param[in] p The memory chunk you want to duplicate. + * + * @param[in] size Number of char's that you want copy. + * + * @return The allocated memory chunk. + * + * @see talloc_size() + */ +_PUBLIC_ void *talloc_memdup(const void *t, const void *p, size_t size); +#else +#define talloc_memdup(t, p, size) _talloc_memdup(t, p, size, __location__) +_PUBLIC_ void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name); +#endif + +#ifdef DOXYGEN +/** + * @brief Assign a type to a talloc chunk. + * + * This macro allows you to force the name of a pointer to be of a particular + * type. This can be used in conjunction with talloc_get_type() to do type + * checking on void* pointers. + * + * It is equivalent to this: + * + * @code + * talloc_set_name_const(ptr, #type) + * @endcode + * + * @param[in] ptr The talloc chunk to assign the type to. + * + * @param[in] type The type to assign. + */ +_PUBLIC_ void talloc_set_type(const char *ptr, #type); + +/** + * @brief Get a typed pointer out of a talloc pointer. + * + * This macro allows you to do type checking on talloc pointers. It is + * particularly useful for void* private pointers. It is equivalent to + * this: + * + * @code + * (type *)talloc_check_name(ptr, #type) + * @endcode + * + * @param[in] ptr The talloc pointer to check. + * + * @param[in] type The type to check against. + * + * @return The properly casted pointer given by ptr, NULL on error. + */ +type *talloc_get_type(const void *ptr, #type); +#else +#define talloc_set_type(ptr, type) talloc_set_name_const(ptr, #type) +#define talloc_get_type(ptr, type) (type *)talloc_check_name(ptr, #type) +#endif + +#ifdef DOXYGEN +/** + * @brief Safely turn a void pointer into a typed pointer. + * + * This macro is used together with talloc(mem_ctx, struct foo). If you had to + * assign the talloc chunk pointer to some void pointer variable, + * talloc_get_type_abort() is the recommended way to get the convert the void + * pointer back to a typed pointer. + * + * @param[in] ptr The void pointer to convert. + * + * @param[in] type The type that this chunk contains + * + * @return The same value as ptr, type-checked and properly cast. + */ +_PUBLIC_ void *talloc_get_type_abort(const void *ptr, #type); +#else +#ifdef TALLOC_GET_TYPE_ABORT_NOOP +#define talloc_get_type_abort(ptr, type) (type *)(ptr) +#else +#define talloc_get_type_abort(ptr, type) (type *)_talloc_get_type_abort(ptr, #type, __location__) +#endif +_PUBLIC_ void *_talloc_get_type_abort(const void *ptr, const char *name, const char *location); +#endif + +/** + * @brief Find a parent context by name. + * + * Find a parent memory context of the current context that has the given + * name. This can be very useful in complex programs where it may be + * difficult to pass all information down to the level you need, but you + * know the structure you want is a parent of another context. + * + * @param[in] ctx The talloc chunk to start from. + * + * @param[in] name The name of the parent we look for. + * + * @return The memory context we are looking for, NULL if not + * found. + */ +_PUBLIC_ void *talloc_find_parent_byname(const void *ctx, const char *name); + +#ifdef DOXYGEN +/** + * @brief Find a parent context by type. + * + * Find a parent memory context of the current context that has the given + * name. This can be very useful in complex programs where it may be + * difficult to pass all information down to the level you need, but you + * know the structure you want is a parent of another context. + * + * Like talloc_find_parent_byname() but takes a type, making it typesafe. + * + * @param[in] ptr The talloc chunk to start from. + * + * @param[in] type The type of the parent to look for. + * + * @return The memory context we are looking for, NULL if not + * found. + */ +_PUBLIC_ void *talloc_find_parent_bytype(const void *ptr, #type); +#else +#define talloc_find_parent_bytype(ptr, type) (type *)talloc_find_parent_byname(ptr, #type) +#endif + +/** + * @brief Allocate a talloc pool. + * + * A talloc pool is a pure optimization for specific situations. In the + * release process for Samba 3.2 we found out that we had become considerably + * slower than Samba 3.0 was. Profiling showed that malloc(3) was a large CPU + * consumer in benchmarks. For Samba 3.2 we have internally converted many + * static buffers to dynamically allocated ones, so malloc(3) being beaten + * more was no surprise. But it made us slower. + * + * talloc_pool() is an optimization to call malloc(3) a lot less for the use + * pattern Samba has: The SMB protocol is mainly a request/response protocol + * where we have to allocate a certain amount of memory per request and free + * that after the SMB reply is sent to the client. + * + * talloc_pool() creates a talloc chunk that you can use as a talloc parent + * exactly as you would use any other ::TALLOC_CTX. The difference is that + * when you talloc a child of this pool, no malloc(3) is done. Instead, talloc + * just increments a pointer inside the talloc_pool. This also works + * recursively. If you use the child of the talloc pool as a parent for + * grand-children, their memory is also taken from the talloc pool. + * + * If there is not enough memory in the pool to allocate the new child, + * it will create a new talloc chunk as if the parent was a normal talloc + * context. + * + * If you talloc_free() children of a talloc pool, the memory is not given + * back to the system. Instead, free(3) is only called if the talloc_pool() + * itself is released with talloc_free(). + * + * The downside of a talloc pool is that if you talloc_move() a child of a + * talloc pool to a talloc parent outside the pool, the whole pool memory is + * not free(3)'ed until that moved chunk is also talloc_free()ed. + * + * @param[in] context The talloc context to hang the result off. + * + * @param[in] size Size of the talloc pool. + * + * @return The allocated talloc pool, NULL on error. + */ +_PUBLIC_ void *talloc_pool(const void *context, size_t size); + +#ifdef DOXYGEN +/** + * @brief Allocate a talloc object as/with an additional pool. + * + * This is like talloc_pool(), but's it's more flexible + * and allows an object to be a pool for its children. + * + * @param[in] ctx The talloc context to hang the result off. + * + * @param[in] type The type that we want to allocate. + * + * @param[in] num_subobjects The expected number of subobjects, which will + * be allocated within the pool. This allocates + * space for talloc_chunk headers. + * + * @param[in] total_subobjects_size The size that all subobjects can use in total. + * + * + * @return The allocated talloc object, NULL on error. + */ +_PUBLIC_ void *talloc_pooled_object(const void *ctx, #type, + unsigned num_subobjects, + size_t total_subobjects_size); +#else +#define talloc_pooled_object(_ctx, _type, \ + _num_subobjects, \ + _total_subobjects_size) \ + (_type *)_talloc_pooled_object((_ctx), sizeof(_type), #_type, \ + (_num_subobjects), \ + (_total_subobjects_size)) +_PUBLIC_ void *_talloc_pooled_object(const void *ctx, + size_t type_size, + const char *type_name, + unsigned num_subobjects, + size_t total_subobjects_size); +#endif + +/** + * @brief Free a talloc chunk and NULL out the pointer. + * + * TALLOC_FREE() frees a pointer and sets it to NULL. Use this if you want + * immediate feedback (i.e. crash) if you use a pointer after having free'ed + * it. + * + * @param[in] ctx The chunk to be freed. + */ +#define TALLOC_FREE(ctx) do { if (ctx != NULL) { talloc_free(ctx); ctx=NULL; } } while(0) + +/* @} ******************************************************************/ + +/** + * \defgroup talloc_ref The talloc reference function. + * @ingroup talloc + * + * This module contains the definitions around talloc references + * + * @{ + */ + +/** + * @brief Increase the reference count of a talloc chunk. + * + * The talloc_increase_ref_count(ptr) function is exactly equivalent to: + * + * @code + * talloc_reference(NULL, ptr); + * @endcode + * + * You can use either syntax, depending on which you think is clearer in + * your code. + * + * @param[in] ptr The pointer to increase the reference count. + * + * @return 0 on success, -1 on error. + */ +_PUBLIC_ int talloc_increase_ref_count(const void *ptr); + +/** + * @brief Get the number of references to a talloc chunk. + * + * @param[in] ptr The pointer to retrieve the reference count from. + * + * @return The number of references. + */ +_PUBLIC_ size_t talloc_reference_count(const void *ptr); + +#ifdef DOXYGEN +/** + * @brief Create an additional talloc parent to a pointer. + * + * The talloc_reference() function makes "context" an additional parent of + * ptr. Each additional reference consumes around 48 bytes of memory on intel + * x86 platforms. + * + * If ptr is NULL, then the function is a no-op, and simply returns NULL. + * + * After creating a reference you can free it in one of the following ways: + * + * - you can talloc_free() any parent of the original pointer. That + * will reduce the number of parents of this pointer by 1, and will + * cause this pointer to be freed if it runs out of parents. + * + * - you can talloc_free() the pointer itself if it has at maximum one + * parent. This behaviour has been changed since the release of version + * 2.0. Further information in the description of "talloc_free". + * + * For more control on which parent to remove, see talloc_unlink() + * @param[in] ctx The additional parent. + * + * @param[in] ptr The pointer you want to create an additional parent for. + * + * @return The original pointer 'ptr', NULL if talloc ran out of + * memory in creating the reference. + * + * @warning You should try to avoid using this interface. It turns a beautiful + * talloc-tree into a graph. It is often really hard to debug if you + * screw something up by accident. + * + * Example: + * @code + * unsigned int *a, *b, *c; + * a = talloc(NULL, unsigned int); + * b = talloc(NULL, unsigned int); + * c = talloc(a, unsigned int); + * // b also serves as a parent of c. + * talloc_reference(b, c); + * @endcode + * + * @see talloc_unlink() + */ +_PUBLIC_ void *talloc_reference(const void *ctx, const void *ptr); +#else +#define talloc_reference(ctx, ptr) (_TALLOC_TYPEOF(ptr))_talloc_reference_loc((ctx),(ptr), __location__) +_PUBLIC_ void *_talloc_reference_loc(const void *context, const void *ptr, const char *location); +#endif + +/** + * @brief Remove a specific parent from a talloc chunk. + * + * The function removes a specific parent from ptr. The context passed must + * either be a context used in talloc_reference() with this pointer, or must be + * a direct parent of ptr. + * + * You can just use talloc_free() instead of talloc_unlink() if there + * is at maximum one parent. This behaviour has been changed since the + * release of version 2.0. Further information in the description of + * "talloc_free". + * + * @param[in] context The talloc parent to remove. + * + * @param[in] ptr The talloc ptr you want to remove the parent from. + * + * @return 0 on success, -1 on error. + * + * @note If the parent has already been removed using talloc_free() then + * this function will fail and will return -1. Likewise, if ptr is NULL, + * then the function will make no modifications and return -1. + * + * @warning You should try to avoid using this interface. It turns a beautiful + * talloc-tree into a graph. It is often really hard to debug if you + * screw something up by accident. + * + * Example: + * @code + * unsigned int *a, *b, *c; + * a = talloc(NULL, unsigned int); + * b = talloc(NULL, unsigned int); + * c = talloc(a, unsigned int); + * // b also serves as a parent of c. + * talloc_reference(b, c); + * talloc_unlink(b, c); + * @endcode + */ +_PUBLIC_ int talloc_unlink(const void *context, void *ptr); + +/** + * @brief Provide a talloc context that is freed at program exit. + * + * This is a handy utility function that returns a talloc context + * which will be automatically freed on program exit. This can be used + * to reduce the noise in memory leak reports. + * + * Never use this in code that might be used in objects loaded with + * dlopen and unloaded with dlclose. talloc_autofree_context() + * internally uses atexit(3). Some platforms like modern Linux handles + * this fine, but for example FreeBSD does not deal well with dlopen() + * and atexit() used simultaneously: dlclose() does not clean up the + * list of atexit-handlers, so when the program exits the code that + * was registered from within talloc_autofree_context() is gone, the + * program crashes at exit. + * + * @return A talloc context, NULL on error. + */ +_PUBLIC_ void *talloc_autofree_context(void) _DEPRECATED_; + +/** + * @brief Get the size of a talloc chunk. + * + * This function lets you know the amount of memory allocated so far by + * this context. It does NOT account for subcontext memory. + * This can be used to calculate the size of an array. + * + * @param[in] ctx The talloc chunk. + * + * @return The size of the talloc chunk. + */ +_PUBLIC_ size_t talloc_get_size(const void *ctx); + +/** + * @brief Show the parentage of a context. + * + * @param[in] context The talloc context to look at. + * + * @param[in] file The output to use, a file, stdout or stderr. + */ +_PUBLIC_ void talloc_show_parents(const void *context, FILE *file); + +/** + * @brief Check if a context is parent of a talloc chunk. + * + * This checks if context is referenced in the talloc hierarchy above ptr. + * + * @param[in] context The assumed talloc context. + * + * @param[in] ptr The talloc chunk to check. + * + * @return Return 1 if this is the case, 0 if not. + */ +_PUBLIC_ int talloc_is_parent(const void *context, const void *ptr); + +/** + * @brief Change the parent context of a talloc pointer. + * + * The function changes the parent context of a talloc pointer. It is typically + * used when the context that the pointer is currently a child of is going to be + * freed and you wish to keep the memory for a longer time. + * + * The difference between talloc_reparent() and talloc_steal() is that + * talloc_reparent() can specify which parent you wish to change. This is + * useful when a pointer has multiple parents via references. + * + * @param[in] old_parent + * @param[in] new_parent + * @param[in] ptr + * + * @return Return the pointer you passed. It does not have any + * failure modes. + */ +_PUBLIC_ void *talloc_reparent(const void *old_parent, const void *new_parent, const void *ptr); + +/* @} ******************************************************************/ + +/** + * @defgroup talloc_array The talloc array functions + * @ingroup talloc + * + * Talloc contains some handy helpers for handling Arrays conveniently + * + * @{ + */ + +#ifdef DOXYGEN +/** + * @brief Allocate an array. + * + * The macro is equivalent to: + * + * @code + * (type *)talloc_size(ctx, sizeof(type) * count); + * @endcode + * + * except that it provides integer overflow protection for the multiply, + * returning NULL if the multiply overflows. + * + * @param[in] ctx The talloc context to hang the result off. + * + * @param[in] type The type that we want to allocate. + * + * @param[in] count The number of 'type' elements you want to allocate. + * + * @return The allocated result, properly cast to 'type *', NULL on + * error. + * + * Example: + * @code + * unsigned int *a, *b; + * a = talloc_zero(NULL, unsigned int); + * b = talloc_array(a, unsigned int, 100); + * @endcode + * + * @see talloc() + * @see talloc_zero_array() + */ +_PUBLIC_ void *talloc_array(const void *ctx, #type, unsigned count); +#else +#define talloc_array(ctx, type, count) (type *)_talloc_array(ctx, sizeof(type), count, #type) +_PUBLIC_ void *_talloc_array(const void *ctx, size_t el_size, unsigned count, const char *name); +#endif + +#ifdef DOXYGEN +/** + * @brief Allocate an array. + * + * @param[in] ctx The talloc context to hang the result off. + * + * @param[in] size The size of an array element. + * + * @param[in] count The number of elements you want to allocate. + * + * @return The allocated result, NULL on error. + */ +_PUBLIC_ void *talloc_array_size(const void *ctx, size_t size, unsigned count); +#else +#define talloc_array_size(ctx, size, count) _talloc_array(ctx, size, count, __location__) +#endif + +#ifdef DOXYGEN +/** + * @brief Allocate an array into a typed pointer. + * + * The macro should be used when you have a pointer to an array and want to + * allocate memory of an array to point at with this pointer. When compiling + * with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_array_size() + * and talloc_get_name() will return the current location in the source file + * and not the type. + * + * @param[in] ctx The talloc context to hang the result off. + * + * @param[in] ptr The pointer you want to assign the result to. + * + * @param[in] count The number of elements you want to allocate. + * + * @return The allocated memory chunk, properly casted. NULL on + * error. + */ +void *talloc_array_ptrtype(const void *ctx, const void *ptr, unsigned count); +#else +#define talloc_array_ptrtype(ctx, ptr, count) (_TALLOC_TYPEOF(ptr))talloc_array_size(ctx, sizeof(*(ptr)), count) +#endif + +#ifdef DOXYGEN +/** + * @brief Get the number of elements in a talloc'ed array. + * + * A talloc chunk carries its own size, so for talloc'ed arrays it is not + * necessary to store the number of elements explicitly. + * + * @param[in] ctx The allocated array. + * + * @return The number of elements in ctx. + */ +size_t talloc_array_length(const void *ctx); +#else +#define talloc_array_length(ctx) (talloc_get_size(ctx)/sizeof(*ctx)) +#endif + +#ifdef DOXYGEN +/** + * @brief Allocate a zero-initialized array + * + * @param[in] ctx The talloc context to hang the result off. + * + * @param[in] type The type that we want to allocate. + * + * @param[in] count The number of "type" elements you want to allocate. + * + * @return The allocated result casted to "type *", NULL on error. + * + * The talloc_zero_array() macro is equivalent to: + * + * @code + * ptr = talloc_array(ctx, type, count); + * if (ptr) memset(ptr, 0, sizeof(type) * count); + * @endcode + */ +void *talloc_zero_array(const void *ctx, #type, unsigned count); +#else +#define talloc_zero_array(ctx, type, count) (type *)_talloc_zero_array(ctx, sizeof(type), count, #type) +_PUBLIC_ void *_talloc_zero_array(const void *ctx, + size_t el_size, + unsigned count, + const char *name); +#endif + +#ifdef DOXYGEN +/** + * @brief Change the size of a talloc array. + * + * The macro changes the size of a talloc pointer. The 'count' argument is the + * number of elements of type 'type' that you want the resulting pointer to + * hold. + * + * talloc_realloc() has the following equivalences: + * + * @code + * talloc_realloc(ctx, NULL, type, 1) ==> talloc(ctx, type); + * talloc_realloc(ctx, NULL, type, N) ==> talloc_array(ctx, type, N); + * talloc_realloc(ctx, ptr, type, 0) ==> talloc_free(ptr); + * @endcode + * + * The "context" argument is only used if "ptr" is NULL, otherwise it is + * ignored. + * + * @param[in] ctx The parent context used if ptr is NULL. + * + * @param[in] ptr The chunk to be resized. + * + * @param[in] type The type of the array element inside ptr. + * + * @param[in] count The intended number of array elements. + * + * @return The new array, NULL on error. The call will fail either + * due to a lack of memory, or because the pointer has more + * than one parent (see talloc_reference()). + */ +_PUBLIC_ void *talloc_realloc(const void *ctx, void *ptr, #type, size_t count); +#else +#define talloc_realloc(ctx, p, type, count) (type *)_talloc_realloc_array(ctx, p, sizeof(type), count, #type) +_PUBLIC_ void *_talloc_realloc_array(const void *ctx, void *ptr, size_t el_size, unsigned count, const char *name); +#endif + +#ifdef DOXYGEN +/** + * @brief Untyped realloc to change the size of a talloc array. + * + * The macro is useful when the type is not known so the typesafe + * talloc_realloc() cannot be used. + * + * @param[in] ctx The parent context used if 'ptr' is NULL. + * + * @param[in] ptr The chunk to be resized. + * + * @param[in] size The new chunk size. + * + * @return The new array, NULL on error. + */ +void *talloc_realloc_size(const void *ctx, void *ptr, size_t size); +#else +#define talloc_realloc_size(ctx, ptr, size) _talloc_realloc(ctx, ptr, size, __location__) +_PUBLIC_ void *_talloc_realloc(const void *context, void *ptr, size_t size, const char *name); +#endif + +/** + * @brief Provide a function version of talloc_realloc_size. + * + * This is a non-macro version of talloc_realloc(), which is useful as + * libraries sometimes want a ralloc function pointer. A realloc() + * implementation encapsulates the functionality of malloc(), free() and + * realloc() in one call, which is why it is useful to be able to pass around + * a single function pointer. + * + * @param[in] context The parent context used if ptr is NULL. + * + * @param[in] ptr The chunk to be resized. + * + * @param[in] size The new chunk size. + * + * @return The new chunk, NULL on error. + */ +_PUBLIC_ void *talloc_realloc_fn(const void *context, void *ptr, size_t size); + +/* @} ******************************************************************/ + +/** + * @defgroup talloc_string The talloc string functions. + * @ingroup talloc + * + * talloc string allocation and manipulation functions. + * @{ + */ + +/** + * @brief Duplicate a string into a talloc chunk. + * + * This function is equivalent to: + * + * @code + * ptr = talloc_size(ctx, strlen(p)+1); + * if (ptr) memcpy(ptr, p, strlen(p)+1); + * @endcode + * + * This functions sets the name of the new pointer to the passed + * string. This is equivalent to: + * + * @code + * talloc_set_name_const(ptr, ptr) + * @endcode + * + * @param[in] t The talloc context to hang the result off. + * + * @param[in] p The string you want to duplicate. + * + * @return The duplicated string, NULL on error. + */ +_PUBLIC_ char *talloc_strdup(const void *t, const char *p); + +/** + * @brief Append a string to given string. + * + * The destination string is reallocated to take + * <code>strlen(s) + strlen(a) + 1</code> characters. + * + * This functions sets the name of the new pointer to the new + * string. This is equivalent to: + * + * @code + * talloc_set_name_const(ptr, ptr) + * @endcode + * + * If <code>s == NULL</code> then new context is created. + * + * @param[in] s The destination to append to. + * + * @param[in] a The string you want to append. + * + * @return The concatenated strings, NULL on error. + * + * @see talloc_strdup() + * @see talloc_strdup_append_buffer() + */ +_PUBLIC_ char *talloc_strdup_append(char *s, const char *a); + +/** + * @brief Append a string to a given buffer. + * + * This is a more efficient version of talloc_strdup_append(). It determines the + * length of the destination string by the size of the talloc context. + * + * Use this very carefully as it produces a different result than + * talloc_strdup_append() when a zero character is in the middle of the + * destination string. + * + * @code + * char *str_a = talloc_strdup(NULL, "hello world"); + * char *str_b = talloc_strdup(NULL, "hello world"); + * str_a[5] = str_b[5] = '\0' + * + * char *app = talloc_strdup_append(str_a, ", hello"); + * char *buf = talloc_strdup_append_buffer(str_b, ", hello"); + * + * printf("%s\n", app); // hello, hello (app = "hello, hello") + * printf("%s\n", buf); // hello (buf = "hello\0world, hello") + * @endcode + * + * If <code>s == NULL</code> then new context is created. + * + * @param[in] s The destination buffer to append to. + * + * @param[in] a The string you want to append. + * + * @return The concatenated strings, NULL on error. + * + * @see talloc_strdup() + * @see talloc_strdup_append() + * @see talloc_array_length() + */ +_PUBLIC_ char *talloc_strdup_append_buffer(char *s, const char *a); + +/** + * @brief Duplicate a length-limited string into a talloc chunk. + * + * This function is the talloc equivalent of the C library function strndup(3). + * + * This functions sets the name of the new pointer to the passed string. This is + * equivalent to: + * + * @code + * talloc_set_name_const(ptr, ptr) + * @endcode + * + * @param[in] t The talloc context to hang the result off. + * + * @param[in] p The string you want to duplicate. + * + * @param[in] n The maximum string length to duplicate. + * + * @return The duplicated string, NULL on error. + */ +_PUBLIC_ char *talloc_strndup(const void *t, const char *p, size_t n); + +/** + * @brief Append at most n characters of a string to given string. + * + * The destination string is reallocated to take + * <code>strlen(s) + strnlen(a, n) + 1</code> characters. + * + * This functions sets the name of the new pointer to the new + * string. This is equivalent to: + * + * @code + * talloc_set_name_const(ptr, ptr) + * @endcode + * + * If <code>s == NULL</code> then new context is created. + * + * @param[in] s The destination string to append to. + * + * @param[in] a The source string you want to append. + * + * @param[in] n The number of characters you want to append from the + * string. + * + * @return The concatenated strings, NULL on error. + * + * @see talloc_strndup() + * @see talloc_strndup_append_buffer() + */ +_PUBLIC_ char *talloc_strndup_append(char *s, const char *a, size_t n); + +/** + * @brief Append at most n characters of a string to given buffer + * + * This is a more efficient version of talloc_strndup_append(). It determines + * the length of the destination string by the size of the talloc context. + * + * Use this very carefully as it produces a different result than + * talloc_strndup_append() when a zero character is in the middle of the + * destination string. + * + * @code + * char *str_a = talloc_strdup(NULL, "hello world"); + * char *str_b = talloc_strdup(NULL, "hello world"); + * str_a[5] = str_b[5] = '\0' + * + * char *app = talloc_strndup_append(str_a, ", hello", 7); + * char *buf = talloc_strndup_append_buffer(str_b, ", hello", 7); + * + * printf("%s\n", app); // hello, hello (app = "hello, hello") + * printf("%s\n", buf); // hello (buf = "hello\0world, hello") + * @endcode + * + * If <code>s == NULL</code> then new context is created. + * + * @param[in] s The destination buffer to append to. + * + * @param[in] a The source string you want to append. + * + * @param[in] n The number of characters you want to append from the + * string. + * + * @return The concatenated strings, NULL on error. + * + * @see talloc_strndup() + * @see talloc_strndup_append() + * @see talloc_array_length() + */ +_PUBLIC_ char *talloc_strndup_append_buffer(char *s, const char *a, size_t n); + +/** + * @brief Format a string given a va_list. + * + * This function is the talloc equivalent of the C library function + * vasprintf(3). + * + * This functions sets the name of the new pointer to the new string. This is + * equivalent to: + * + * @code + * talloc_set_name_const(ptr, ptr) + * @endcode + * + * @param[in] t The talloc context to hang the result off. + * + * @param[in] fmt The format string. + * + * @param[in] ap The parameters used to fill fmt. + * + * @return The formatted string, NULL on error. + */ +_PUBLIC_ char *talloc_vasprintf(const void *t, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); + +/** + * @brief Format a string given a va_list and append it to the given destination + * string. + * + * @param[in] s The destination string to append to. + * + * @param[in] fmt The format string. + * + * @param[in] ap The parameters used to fill fmt. + * + * @return The formatted string, NULL on error. + * + * @see talloc_vasprintf() + */ +_PUBLIC_ char *talloc_vasprintf_append(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); + +/** + * @brief Format a string given a va_list and append it to the given destination + * buffer. + * + * @param[in] s The destination buffer to append to. + * + * @param[in] fmt The format string. + * + * @param[in] ap The parameters used to fill fmt. + * + * @return The formatted string, NULL on error. + * + * @see talloc_vasprintf() + */ +_PUBLIC_ char *talloc_vasprintf_append_buffer(char *s, const char *fmt, va_list ap) PRINTF_ATTRIBUTE(2,0); + +/** + * @brief Build up a string buffer, handle allocation failure + * + * @param[in] ps Pointer to the talloc'ed string to be extended + * @param[in] fmt The format string + * @param[in] ... The parameters used to fill fmt. + * + * This does nothing if *ps is NULL and sets *ps to NULL if the + * intermediate reallocation fails. Useful when building up a string + * step by step, no intermediate NULL checks are required. + */ +_PUBLIC_ void talloc_asprintf_addbuf(char **ps, const char *fmt, ...) \ + PRINTF_ATTRIBUTE(2,3); + +/** + * @brief Format a string. + * + * This function is the talloc equivalent of the C library function asprintf(3). + * + * This functions sets the name of the new pointer to the new string. This is + * equivalent to: + * + * @code + * talloc_set_name_const(ptr, ptr) + * @endcode + * + * @param[in] t The talloc context to hang the result off. + * + * @param[in] fmt The format string. + * + * @param[in] ... The parameters used to fill fmt. + * + * @return The formatted string, NULL on error. + */ +_PUBLIC_ char *talloc_asprintf(const void *t, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); + +/** + * @brief Append a formatted string to another string. + * + * This function appends the given formatted string to the given string. Use + * this variant when the string in the current talloc buffer may have been + * truncated in length. + * + * This functions sets the name of the new pointer to the new + * string. This is equivalent to: + * + * @code + * talloc_set_name_const(ptr, ptr) + * @endcode + * + * If <code>s == NULL</code> then new context is created. + * + * @param[in] s The string to append to. + * + * @param[in] fmt The format string. + * + * @param[in] ... The parameters used to fill fmt. + * + * @return The formatted string, NULL on error. + */ +_PUBLIC_ char *talloc_asprintf_append(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); + +/** + * @brief Append a formatted string to another string. + * + * This is a more efficient version of talloc_asprintf_append(). It determines + * the length of the destination string by the size of the talloc context. + * + * Use this very carefully as it produces a different result than + * talloc_asprintf_append() when a zero character is in the middle of the + * destination string. + * + * @code + * char *str_a = talloc_strdup(NULL, "hello world"); + * char *str_b = talloc_strdup(NULL, "hello world"); + * str_a[5] = str_b[5] = '\0' + * + * char *app = talloc_asprintf_append(str_a, "%s", ", hello"); + * char *buf = talloc_strdup_append_buffer(str_b, "%s", ", hello"); + * + * printf("%s\n", app); // hello, hello (app = "hello, hello") + * printf("%s\n", buf); // hello (buf = "hello\0world, hello") + * @endcode + * + * If <code>s == NULL</code> then new context is created. + * + * @param[in] s The string to append to + * + * @param[in] fmt The format string. + * + * @param[in] ... The parameters used to fill fmt. + * + * @return The formatted string, NULL on error. + * + * @see talloc_asprintf() + * @see talloc_asprintf_append() + */ +_PUBLIC_ char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...) PRINTF_ATTRIBUTE(2,3); + +/* @} ******************************************************************/ + +/** + * @defgroup talloc_debug The talloc debugging support functions + * @ingroup talloc + * + * To aid memory debugging, talloc contains routines to inspect the currently + * allocated memory hierarchy. + * + * @{ + */ + +/** + * @brief Walk a complete talloc hierarchy. + * + * This provides a more flexible reports than talloc_report(). It + * will recursively call the callback for the entire tree of memory + * referenced by the pointer. References in the tree are passed with + * is_ref = 1 and the pointer that is referenced. + * + * You can pass NULL for the pointer, in which case a report is + * printed for the top level memory context, but only if + * talloc_enable_leak_report() or talloc_enable_leak_report_full() + * has been called. + * + * The recursion is stopped when depth >= max_depth. + * max_depth = -1 means only stop at leaf nodes. + * + * @param[in] ptr The talloc chunk. + * + * @param[in] depth Internal parameter to control recursion. Call with 0. + * + * @param[in] max_depth Maximum recursion level. + * + * @param[in] callback Function to be called on every chunk. + * + * @param[in] private_data Private pointer passed to callback. + */ +_PUBLIC_ void talloc_report_depth_cb(const void *ptr, int depth, int max_depth, + void (*callback)(const void *ptr, + int depth, int max_depth, + int is_ref, + void *private_data), + void *private_data); + +/** + * @brief Print a talloc hierarchy. + * + * This provides a more flexible reports than talloc_report(). It + * will let you specify the depth and max_depth. + * + * @param[in] ptr The talloc chunk. + * + * @param[in] depth Internal parameter to control recursion. Call with 0. + * + * @param[in] max_depth Maximum recursion level. + * + * @param[in] f The file handle to print to. + */ +_PUBLIC_ void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f); + +/** + * @brief Print a summary report of all memory used by ptr. + * + * This provides a more detailed report than talloc_report(). It will + * recursively print the entire tree of memory referenced by the + * pointer. References in the tree are shown by giving the name of the + * pointer that is referenced. + * + * You can pass NULL for the pointer, in which case a report is printed + * for the top level memory context, but only if + * talloc_enable_leak_report() or talloc_enable_leak_report_full() has + * been called. + * + * @param[in] ptr The talloc chunk. + * + * @param[in] f The file handle to print to. + * + * Example: + * @code + * unsigned int *a, *b; + * a = talloc(NULL, unsigned int); + * b = talloc(a, unsigned int); + * fprintf(stderr, "Dumping memory tree for a:\n"); + * talloc_report_full(a, stderr); + * @endcode + * + * @see talloc_report() + */ +_PUBLIC_ void talloc_report_full(const void *ptr, FILE *f); + +/** + * @brief Print a summary report of all memory used by ptr. + * + * This function prints a summary report of all memory used by ptr. One line of + * report is printed for each immediate child of ptr, showing the total memory + * and number of blocks used by that child. + * + * You can pass NULL for the pointer, in which case a report is printed + * for the top level memory context, but only if talloc_enable_leak_report() + * or talloc_enable_leak_report_full() has been called. + * + * @param[in] ptr The talloc chunk. + * + * @param[in] f The file handle to print to. + * + * Example: + * @code + * unsigned int *a, *b; + * a = talloc(NULL, unsigned int); + * b = talloc(a, unsigned int); + * fprintf(stderr, "Summary of memory tree for a:\n"); + * talloc_report(a, stderr); + * @endcode + * + * @see talloc_report_full() + */ +_PUBLIC_ void talloc_report(const void *ptr, FILE *f); + +/** + * @brief Enable tracking the use of NULL memory contexts. + * + * This enables tracking of the NULL memory context without enabling leak + * reporting on exit. Useful for when you want to do your own leak + * reporting call via talloc_report_null_full(); + */ +_PUBLIC_ void talloc_enable_null_tracking(void); + +/** + * @brief Enable tracking the use of NULL memory contexts. + * + * This enables tracking of the NULL memory context without enabling leak + * reporting on exit. Useful for when you want to do your own leak + * reporting call via talloc_report_null_full(); + */ +_PUBLIC_ void talloc_enable_null_tracking_no_autofree(void); + +/** + * @brief Disable tracking of the NULL memory context. + * + * This disables tracking of the NULL memory context. + */ +_PUBLIC_ void talloc_disable_null_tracking(void); + +/** + * @brief Enable leak report when a program exits. + * + * This enables calling of talloc_report(NULL, stderr) when the program + * exits. In Samba4 this is enabled by using the --leak-report command + * line option. + * + * For it to be useful, this function must be called before any other + * talloc function as it establishes a "null context" that acts as the + * top of the tree. If you don't call this function first then passing + * NULL to talloc_report() or talloc_report_full() won't give you the + * full tree printout. + * + * Here is a typical talloc report: + * + * @code + * talloc report on 'null_context' (total 267 bytes in 15 blocks) + * libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks + * libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks + * iconv(UTF8,CP850) contains 42 bytes in 2 blocks + * libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks + * iconv(CP850,UTF8) contains 42 bytes in 2 blocks + * iconv(UTF8,UTF-16LE) contains 45 bytes in 2 blocks + * iconv(UTF-16LE,UTF8) contains 45 bytes in 2 blocks + * @endcode + */ +_PUBLIC_ void talloc_enable_leak_report(void); + +/** + * @brief Enable full leak report when a program exits. + * + * This enables calling of talloc_report_full(NULL, stderr) when the + * program exits. In Samba4 this is enabled by using the + * --leak-report-full command line option. + * + * For it to be useful, this function must be called before any other + * talloc function as it establishes a "null context" that acts as the + * top of the tree. If you don't call this function first then passing + * NULL to talloc_report() or talloc_report_full() won't give you the + * full tree printout. + * + * Here is a typical full report: + * + * @code + * full talloc report on 'root' (total 18 bytes in 8 blocks) + * p1 contains 18 bytes in 7 blocks (ref 0) + * r1 contains 13 bytes in 2 blocks (ref 0) + * reference to: p2 + * p2 contains 1 bytes in 1 blocks (ref 1) + * x3 contains 1 bytes in 1 blocks (ref 0) + * x2 contains 1 bytes in 1 blocks (ref 0) + * x1 contains 1 bytes in 1 blocks (ref 0) + * @endcode + */ +_PUBLIC_ void talloc_enable_leak_report_full(void); + +/** + * @brief Set a custom "abort" function that is called on serious error. + * + * The default "abort" function is <code>abort()</code>. + * + * The "abort" function is called when: + * + * <ul> + * <li>talloc_get_type_abort() fails</li> + * <li>the provided pointer is not a valid talloc context</li> + * <li>when the context meta data are invalid</li> + * <li>when access after free is detected</li> + * </ul> + * + * Example: + * + * @code + * void my_abort(const char *reason) + * { + * fprintf(stderr, "talloc abort: %s\n", reason); + * abort(); + * } + * + * talloc_set_abort_fn(my_abort); + * @endcode + * + * @param[in] abort_fn The new "abort" function. + * + * @see talloc_set_log_fn() + * @see talloc_get_type() + */ +_PUBLIC_ void talloc_set_abort_fn(void (*abort_fn)(const char *reason)); + +/** + * @brief Set a logging function. + * + * @param[in] log_fn The logging function. + * + * @see talloc_set_log_stderr() + * @see talloc_set_abort_fn() + */ +_PUBLIC_ void talloc_set_log_fn(void (*log_fn)(const char *message)); + +/** + * @brief Set stderr as the output for logs. + * + * @see talloc_set_log_fn() + * @see talloc_set_abort_fn() + */ +_PUBLIC_ void talloc_set_log_stderr(void); + +/** + * @brief Set a max memory limit for the current context hierarchy + * This affects all children of this context and constrain any + * allocation in the hierarchy to never exceed the limit set. + * The limit can be removed by setting 0 (unlimited) as the + * max_size by calling the function again on the same context. + * Memory limits can also be nested, meaning a child can have + * a stricter memory limit than a parent. + * Memory limits are enforced only at memory allocation time. + * Stealing a context into a 'limited' hierarchy properly + * updates memory usage but does *not* cause failure if the + * move causes the new parent to exceed its limits. However + * any further allocation on that hierarchy will then fail. + * + * @warning talloc memlimit functionality is deprecated. Please + * consider using cgroup memory limits instead. + * + * @param[in] ctx The talloc context to set the limit on + * @param[in] max_size The (new) max_size + */ +_PUBLIC_ int talloc_set_memlimit(const void *ctx, size_t max_size) _DEPRECATED_; + +/* @} ******************************************************************/ + +#if TALLOC_DEPRECATED +#define talloc_zero_p(ctx, type) talloc_zero(ctx, type) +#define talloc_p(ctx, type) talloc(ctx, type) +#define talloc_array_p(ctx, type, count) talloc_array(ctx, type, count) +#define talloc_realloc_p(ctx, p, type, count) talloc_realloc(ctx, p, type, count) +#define talloc_destroy(ctx) talloc_free(ctx) +#define talloc_append_string(c, s, a) (s?talloc_strdup_append(s,a):talloc_strdup(c, a)) +#endif + +#ifndef TALLOC_MAX_DEPTH +#define TALLOC_MAX_DEPTH 10000 +#endif + +#ifdef __cplusplus +} /* end of extern "C" */ +#endif + +#endif diff --git a/lib/talloc/talloc.pc.in b/lib/talloc/talloc.pc.in new file mode 100644 index 0000000..437281a --- /dev/null +++ b/lib/talloc/talloc.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: talloc +Description: A hierarchical pool based memory system with destructors +Version: @TALLOC_VERSION@ +Libs: @LIB_RPATH@ -L${libdir} -ltalloc +Cflags: -I${includedir} +URL: http://talloc.samba.org/ diff --git a/lib/talloc/talloc_guide.txt b/lib/talloc/talloc_guide.txt new file mode 100644 index 0000000..dedda6c --- /dev/null +++ b/lib/talloc/talloc_guide.txt @@ -0,0 +1,768 @@ +Using talloc in Samba4 +====================== + +.. contents:: + +Andrew Tridgell +August 2009 + +The most current version of this document is available at + http://samba.org/ftp/unpacked/talloc/talloc_guide.txt + +If you are used to the "old" talloc from Samba3 before 3.0.20 then please read +this carefully, as talloc has changed a lot. With 3.0.20 (or 3.0.14?) the +Samba4 talloc has been ported back to Samba3, so this guide applies to both. + +The new talloc is a hierarchical, reference counted memory pool system +with destructors. Quite a mouthful really, but not too bad once you +get used to it. + +Perhaps the biggest change from Samba3 is that there is no distinction +between a "talloc context" and a "talloc pointer". Any pointer +returned from talloc() is itself a valid talloc context. This means +you can do this:: + + struct foo *X = talloc(mem_ctx, struct foo); + X->name = talloc_strdup(X, "foo"); + +and the pointer X->name would be a "child" of the talloc context "X" +which is itself a child of "mem_ctx". So if you do talloc_free(mem_ctx) +then it is all destroyed, whereas if you do talloc_free(X) then just X +and X->name are destroyed, and if you do talloc_free(X->name) then +just the name element of X is destroyed. + +If you think about this, then what this effectively gives you is an +n-ary tree, where you can free any part of the tree with +talloc_free(). + +If you find this confusing, then I suggest you run the testsuite to +watch talloc in action. You may also like to add your own tests to +testsuite.c to clarify how some particular situation is handled. + + +Performance +----------- + +All the additional features of talloc() over malloc() do come at a +price. We have a simple performance test in Samba4 that measures +talloc() versus malloc() performance, and it seems that talloc() is +about 4% slower than malloc() on my x86 Debian Linux box. For Samba, +the great reduction in code complexity that we get by using talloc +makes this worthwhile, especially as the total overhead of +talloc/malloc in Samba is already quite small. + + +talloc API +---------- + +The following is a complete guide to the talloc API. Read it all at +least twice. + +Multi-threading +--------------- + +talloc itself does not deal with threads. It is thread-safe (assuming +the underlying "malloc" is), as long as each thread uses different +memory contexts. +If two threads use the same context then they need to synchronize in +order to be safe. In particular: +- when using talloc_enable_leak_report(), giving directly NULL as a +parent context implicitly refers to a hidden "null context" global +variable, so this should not be used in a multi-threaded environment +without proper synchronization. In threaded code turn off null tracking using +talloc_disable_null_tracking(). ; +- the context returned by talloc_autofree_context() is also global so +shouldn't be used by several threads simultaneously without +synchronization. + +talloc and shared objects +------------------------- + +talloc can be used in shared objects. Special care needs to be taken +to never use talloc_autofree_context() in code that might be loaded +with dlopen() and unloaded with dlclose(), as talloc_autofree_context() +internally uses atexit(3). Some platforms like modern Linux handles +this fine, but for example FreeBSD does not deal well with dlopen() +and atexit() used simultaneously: dlclose() does not clean up the list +of atexit-handlers, so when the program exits the code that was +registered from within talloc_autofree_context() is gone, the program +crashes at exit. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +(type *)talloc(const void *context, type); + +The talloc() macro is the core of the talloc library. It takes a +memory context and a type, and returns a pointer to a new area of +memory of the given type. + +The returned pointer is itself a talloc context, so you can use it as +the context argument to more calls to talloc if you wish. + +The returned pointer is a "child" of the supplied context. This means +that if you talloc_free() the context then the new child disappears as +well. Alternatively you can free just the child. + +The context argument to talloc() can be NULL, in which case a new top +level context is created. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_size(const void *context, size_t size); + +The function talloc_size() should be used when you don't have a +convenient type to pass to talloc(). Unlike talloc(), it is not type +safe (as it returns a void *), so you are on your own for type checking. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +(typeof(ptr)) talloc_ptrtype(const void *ctx, ptr); + +The talloc_ptrtype() macro should be used when you have a pointer and +want to allocate memory to point at with this pointer. When compiling +with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_size() +and talloc_get_name() will return the current location in the source file. +and not the type. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +int talloc_free(void *ptr); + +The talloc_free() function frees a piece of talloc memory, and all its +children. You can call talloc_free() on any pointer returned by +talloc(). + +The return value of talloc_free() indicates success or failure, with 0 +returned for success and -1 for failure. A possible failure condition +is if the pointer had a destructor attached to it and the destructor +returned -1. See talloc_set_destructor() for details on +destructors. Likewise, if "ptr" is NULL, then the function will make +no modifications and returns -1. + +From version 2.0 and onwards, as a special case, talloc_free() is +refused on pointers that have more than one parent associated, as talloc +would have no way of knowing which parent should be removed. This is +different from older versions in the sense that always the reference to +the most recently established parent has been destroyed. Hence to free a +pointer that has more than one parent please use talloc_unlink(). + +To help you find problems in your code caused by this behaviour, if +you do try and free a pointer with more than one parent then the +talloc logging function will be called to give output like this: + + ERROR: talloc_free with references at some_dir/source/foo.c:123 + reference at some_dir/source/other.c:325 + reference at some_dir/source/third.c:121 + +Please see the documentation for talloc_set_log_fn() and +talloc_set_log_stderr() for more information on talloc logging +functions. + +talloc_free() operates recursively on its children. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_free_children(void *ptr); + +The talloc_free_children() walks along the list of all children of a +talloc context and talloc_free()s only the children, not the context +itself. + +A NULL argument is handled as no-op. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_reference(const void *context, const void *ptr); + +The talloc_reference() function makes "context" an additional parent +of "ptr". + +The return value of talloc_reference() is always the original pointer +"ptr", unless talloc ran out of memory in creating the reference in +which case it will return NULL (each additional reference consumes +around 48 bytes of memory on intel x86 platforms). + +If "ptr" is NULL, then the function is a no-op, and simply returns NULL. + +After creating a reference you can free it in one of the following +ways: + + - you can talloc_free() any parent of the original pointer. That + will reduce the number of parents of this pointer by 1, and will + cause this pointer to be freed if it runs out of parents. + + - you can talloc_free() the pointer itself if it has at maximum one + parent. This behaviour has been changed since the release of version + 2.0. Further information in the description of "talloc_free". + +For more control on which parent to remove, see talloc_unlink() + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +int talloc_unlink(const void *context, void *ptr); + +The talloc_unlink() function removes a specific parent from ptr. The +context passed must either be a context used in talloc_reference() +with this pointer, or must be a direct parent of ptr. + +Note that if the parent has already been removed using talloc_free() +then this function will fail and will return -1. Likewise, if "ptr" +is NULL, then the function will make no modifications and return -1. + +You can just use talloc_free() instead of talloc_unlink() if there +is at maximum one parent. This behaviour has been changed since the +release of version 2.0. Further information in the description of +"talloc_free". + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_set_destructor(const void *ptr, int (*destructor)(void *)); + +The function talloc_set_destructor() sets the "destructor" for the +pointer "ptr". A destructor is a function that is called when the +memory used by a pointer is about to be released. The destructor +receives the pointer as an argument, and should return 0 for success +and -1 for failure. + +The destructor can do anything it wants to, including freeing other +pieces of memory. A common use for destructors is to clean up +operating system resources (such as open file descriptors) contained +in the structure the destructor is placed on. + +You can only place one destructor on a pointer. If you need more than +one destructor then you can create a zero-length child of the pointer +and place an additional destructor on that. + +To remove a destructor call talloc_set_destructor() with NULL for the +destructor. + +If your destructor attempts to talloc_free() the pointer that it is +the destructor for then talloc_free() will return -1 and the free will +be ignored. This would be a pointless operation anyway, as the +destructor is only called when the memory is just about to go away. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +int talloc_increase_ref_count(const void *ptr); + +The talloc_increase_ref_count(ptr) function is exactly equivalent to: + + talloc_reference(NULL, ptr); + +You can use either syntax, depending on which you think is clearer in +your code. + +It returns 0 on success and -1 on failure. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +size_t talloc_reference_count(const void *ptr); + +Return the number of references to the pointer. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_set_name(const void *ptr, const char *fmt, ...); + +Each talloc pointer has a "name". The name is used principally for +debugging purposes, although it is also possible to set and get the +name on a pointer in as a way of "marking" pointers in your code. + +The main use for names on pointer is for "talloc reports". See +talloc_report() and talloc_report_full() for details. Also see +talloc_enable_leak_report() and talloc_enable_leak_report_full(). + +The talloc_set_name() function allocates memory as a child of the +pointer. It is logically equivalent to: + talloc_set_name_const(ptr, talloc_asprintf(ptr, fmt, ...)); + +Note that multiple calls to talloc_set_name() will allocate more +memory without releasing the name. All of the memory is released when +the ptr is freed using talloc_free(). + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_set_name_const(const void *ptr, const char *name); + +The function talloc_set_name_const() is just like talloc_set_name(), +but it takes a string constant, and is much faster. It is extensively +used by the "auto naming" macros, such as talloc_p(). + +This function does not allocate any memory. It just copies the +supplied pointer into the internal representation of the talloc +ptr. This means you must not pass a name pointer to memory that will +disappear before the ptr is freed with talloc_free(). + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_named(const void *context, size_t size, const char *fmt, ...); + +The talloc_named() function creates a named talloc pointer. It is +equivalent to: + + ptr = talloc_size(context, size); + talloc_set_name(ptr, fmt, ....); + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_named_const(const void *context, size_t size, const char *name); + +This is equivalent to:: + + ptr = talloc_size(context, size); + talloc_set_name_const(ptr, name); + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +const char *talloc_get_name(const void *ptr); + +This returns the current name for the given talloc pointer. See +talloc_set_name() for details. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_init(const char *fmt, ...); + +This function creates a zero length named talloc context as a top +level context. It is equivalent to:: + + talloc_named(NULL, 0, fmt, ...); + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_new(void *ctx); + +This is a utility macro that creates a new memory context hanging +off an exiting context, automatically naming it "talloc_new: __location__" +where __location__ is the source line it is called from. It is +particularly useful for creating a new temporary working context. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +(type *)talloc_realloc(const void *context, void *ptr, type, count); + +The talloc_realloc() macro changes the size of a talloc +pointer. The "count" argument is the number of elements of type "type" +that you want the resulting pointer to hold. + +talloc_realloc() has the following equivalences:: + + talloc_realloc(context, NULL, type, 1) ==> talloc(context, type); + talloc_realloc(context, NULL, type, N) ==> talloc_array(context, type, N); + talloc_realloc(context, ptr, type, 0) ==> talloc_free(ptr); + +The "context" argument is only used if "ptr" is NULL, otherwise it is +ignored. + +talloc_realloc() returns the new pointer, or NULL on failure. The call +will fail either due to a lack of memory, or because the pointer has +more than one parent (see talloc_reference()). + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_realloc_size(const void *context, void *ptr, size_t size); + +the talloc_realloc_size() function is useful when the type is not +known so the typesafe talloc_realloc() cannot be used. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_steal(const void *new_ctx, const void *ptr); + +The talloc_steal() function changes the parent context of a talloc +pointer. It is typically used when the context that the pointer is +currently a child of is going to be freed and you wish to keep the +memory for a longer time. + +The talloc_steal() function returns the pointer that you pass it. It +does not have any failure modes. + +NOTE: It is possible to produce loops in the parent/child relationship +if you are not careful with talloc_steal(). No guarantees are provided +as to your sanity or the safety of your data if you do this. + +talloc_steal (new_ctx, NULL) will return NULL with no sideeffects. + +Note that if you try and call talloc_steal() on a pointer that has +more than one parent then the result is ambiguous. Talloc will choose +to remove the parent that is currently indicated by talloc_parent() +and replace it with the chosen parent. You will also get a message +like this via the talloc logging functions: + + WARNING: talloc_steal with references at some_dir/source/foo.c:123 + reference at some_dir/source/other.c:325 + reference at some_dir/source/third.c:121 + +To unambiguously change the parent of a pointer please see the +function talloc_reparent(). See the talloc_set_log_fn() documentation +for more information on talloc logging. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_reparent(const void *old_parent, const void *new_parent, const void *ptr); + +The talloc_reparent() function changes the parent context of a talloc +pointer. It is typically used when the context that the pointer is +currently a child of is going to be freed and you wish to keep the +memory for a longer time. + +The talloc_reparent() function returns the pointer that you pass it. It +does not have any failure modes. + +The difference between talloc_reparent() and talloc_steal() is that +talloc_reparent() can specify which parent you wish to change. This is +useful when a pointer has multiple parents via references. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_parent(const void *ptr); + +The talloc_parent() function returns the current talloc parent. This +is usually the pointer under which this memory was originally created, +but it may have changed due to a talloc_steal() or talloc_reparent() + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +size_t talloc_total_size(const void *ptr); + +The talloc_total_size() function returns the total size in bytes used +by this pointer and all child pointers. Mostly useful for debugging. + +Passing NULL is allowed, but it will only give a meaningful result if +talloc_enable_leak_report() or talloc_enable_leak_report_full() has +been called. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +size_t talloc_total_blocks(const void *ptr); + +The talloc_total_blocks() function returns the total memory block +count used by this pointer and all child pointers. Mostly useful for +debugging. + +Passing NULL is allowed, but it will only give a meaningful result if +talloc_enable_leak_report() or talloc_enable_leak_report_full() has +been called. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_report_depth_cb(const void *ptr, int depth, int max_depth, + void (*callback)(const void *ptr, + int depth, int max_depth, + int is_ref, + void *priv), + void *priv); + +This provides a more flexible reports than talloc_report(). It +will recursively call the callback for the entire tree of memory +referenced by the pointer. References in the tree are passed with +is_ref = 1 and the pointer that is referenced. + +You can pass NULL for the pointer, in which case a report is +printed for the top level memory context, but only if +talloc_enable_leak_report() or talloc_enable_leak_report_full() +has been called. + +The recursion is stopped when depth >= max_depth. +max_depth = -1 means only stop at leaf nodes. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_report_depth_file(const void *ptr, int depth, int max_depth, FILE *f); + +This provides a more flexible reports than talloc_report(). It +will let you specify the depth and max_depth. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_report(const void *ptr, FILE *f); + +The talloc_report() function prints a summary report of all memory +used by ptr. One line of report is printed for each immediate child of +ptr, showing the total memory and number of blocks used by that child. + +You can pass NULL for the pointer, in which case a report is printed +for the top level memory context, but only if +talloc_enable_leak_report() or talloc_enable_leak_report_full() has +been called. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_report_full(const void *ptr, FILE *f); + +This provides a more detailed report than talloc_report(). It will +recursively print the entire tree of memory referenced by the +pointer. References in the tree are shown by giving the name of the +pointer that is referenced. + +You can pass NULL for the pointer, in which case a report is printed +for the top level memory context, but only if +talloc_enable_leak_report() or talloc_enable_leak_report_full() has +been called. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_enable_leak_report(void); + +This enables calling of talloc_report(NULL, stderr) when the program +exits. In Samba4 this is enabled by using the --leak-report command +line option. + +For it to be useful, this function must be called before any other +talloc function as it establishes a "null context" that acts as the +top of the tree. If you don't call this function first then passing +NULL to talloc_report() or talloc_report_full() won't give you the +full tree printout. + +Here is a typical talloc report: + +talloc report on 'null_context' (total 267 bytes in 15 blocks) + libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks + libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks + iconv(UTF8,CP850) contains 42 bytes in 2 blocks + libcli/auth/spnego_parse.c:55 contains 31 bytes in 2 blocks + iconv(CP850,UTF8) contains 42 bytes in 2 blocks + iconv(UTF8,UTF-16LE) contains 45 bytes in 2 blocks + iconv(UTF-16LE,UTF8) contains 45 bytes in 2 blocks + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_enable_leak_report_full(void); + +This enables calling of talloc_report_full(NULL, stderr) when the +program exits. In Samba4 this is enabled by using the +--leak-report-full command line option. + +For it to be useful, this function must be called before any other +talloc function as it establishes a "null context" that acts as the +top of the tree. If you don't call this function first then passing +NULL to talloc_report() or talloc_report_full() won't give you the +full tree printout. + +Here is a typical full report: + +full talloc report on 'root' (total 18 bytes in 8 blocks) + p1 contains 18 bytes in 7 blocks (ref 0) + r1 contains 13 bytes in 2 blocks (ref 0) + reference to: p2 + p2 contains 1 bytes in 1 blocks (ref 1) + x3 contains 1 bytes in 1 blocks (ref 0) + x2 contains 1 bytes in 1 blocks (ref 0) + x1 contains 1 bytes in 1 blocks (ref 0) + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_enable_null_tracking(void); + +This enables tracking of the NULL memory context without enabling leak +reporting on exit. Useful for when you want to do your own leak +reporting call via talloc_report_null_full(); + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_disable_null_tracking(void); + +This disables tracking of the NULL memory context. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +(type *)talloc_zero(const void *ctx, type); + +The talloc_zero() macro is equivalent to:: + + ptr = talloc(ctx, type); + if (ptr) memset(ptr, 0, sizeof(type)); + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_zero_size(const void *ctx, size_t size) + +The talloc_zero_size() function is useful when you don't have a known type + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_memdup(const void *ctx, const void *p, size_t size); + +The talloc_memdup() function is equivalent to:: + + ptr = talloc_size(ctx, size); + if (ptr) memcpy(ptr, p, size); + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +char *talloc_strdup(const void *ctx, const char *p); + +The talloc_strdup() function is equivalent to:: + + ptr = talloc_size(ctx, strlen(p)+1); + if (ptr) memcpy(ptr, p, strlen(p)+1); + +This functions sets the name of the new pointer to the passed +string. This is equivalent to:: + + talloc_set_name_const(ptr, ptr) + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +char *talloc_strndup(const void *t, const char *p, size_t n); + +The talloc_strndup() function is the talloc equivalent of the C +library function strndup() + +This functions sets the name of the new pointer to the passed +string. This is equivalent to: + talloc_set_name_const(ptr, ptr) + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +char *talloc_append_string(const void *t, char *orig, const char *append); + +The talloc_append_string() function appends the given formatted +string to the given string. + +This function sets the name of the new pointer to the new +string. This is equivalent to:: + + talloc_set_name_const(ptr, ptr) + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +char *talloc_vasprintf(const void *t, const char *fmt, va_list ap); + +The talloc_vasprintf() function is the talloc equivalent of the C +library function vasprintf() + +This functions sets the name of the new pointer to the new +string. This is equivalent to:: + + talloc_set_name_const(ptr, ptr) + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +char *talloc_asprintf(const void *t, const char *fmt, ...); + +The talloc_asprintf() function is the talloc equivalent of the C +library function asprintf() + +This functions sets the name of the new pointer to the new +string. This is equivalent to:: + + talloc_set_name_const(ptr, ptr) + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +char *talloc_asprintf_append(char *s, const char *fmt, ...); + +The talloc_asprintf_append() function appends the given formatted +string to the given string. +Use this variant when the string in the current talloc buffer may +have been truncated in length. + +This functions sets the name of the new pointer to the new +string. This is equivalent to:: + + talloc_set_name_const(ptr, ptr) + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +char *talloc_asprintf_append_buffer(char *s, const char *fmt, ...); + +The talloc_asprintf_append() function appends the given formatted +string to the end of the currently allocated talloc buffer. +Use this variant when the string in the current talloc buffer has +not been changed. + +This functions sets the name of the new pointer to the new +string. This is equivalent to:: + + talloc_set_name_const(ptr, ptr) + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +((type *)talloc_array(const void *ctx, type, unsigned int count); + +The talloc_array() macro is equivalent to:: + + (type *)talloc_size(ctx, sizeof(type) * count); + +except that it provides integer overflow protection for the multiply, +returning NULL if the multiply overflows. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_array_size(const void *ctx, size_t size, unsigned int count); + +The talloc_array_size() function is useful when the type is not +known. It operates in the same way as talloc_array(), but takes a size +instead of a type. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +(typeof(ptr)) talloc_array_ptrtype(const void *ctx, ptr, unsigned int count); + +The talloc_ptrtype() macro should be used when you have a pointer to an array +and want to allocate memory of an array to point at with this pointer. When compiling +with gcc >= 3 it is typesafe. Note this is a wrapper of talloc_array_size() +and talloc_get_name() will return the current location in the source file. +and not the type. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_realloc_fn(const void *ctx, void *ptr, size_t size); + +This is a non-macro version of talloc_realloc(), which is useful +as libraries sometimes want a ralloc function pointer. A realloc() +implementation encapsulates the functionality of malloc(), free() and +realloc() in one call, which is why it is useful to be able to pass +around a single function pointer. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_autofree_context(void); + +This is a handy utility function that returns a talloc context +which will be automatically freed on program exit. This can be used +to reduce the noise in memory leak reports. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_check_name(const void *ptr, const char *name); + +This function checks if a pointer has the specified name. If it does +then the pointer is returned. It it doesn't then NULL is returned. + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +(type *)talloc_get_type(const void *ptr, type); + +This macro allows you to do type checking on talloc pointers. It is +particularly useful for void* private pointers. It is equivalent to +this:: + + (type *)talloc_check_name(ptr, #type) + + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +talloc_set_type(const void *ptr, type); + +This macro allows you to force the name of a pointer to be of a +particular type. This can be used in conjunction with +talloc_get_type() to do type checking on void* pointers. + +It is equivalent to this:: + + talloc_set_name_const(ptr, #type) + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +talloc_get_size(const void *ctx); + +This function lets you know the amount of memory allocated so far by +this context. It does NOT account for subcontext memory. +This can be used to calculate the size of an array. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void *talloc_find_parent_byname(const void *ctx, const char *name); + +Find a parent memory context of the current context that has the given +name. This can be very useful in complex programs where it may be +difficult to pass all information down to the level you need, but you +know the structure you want is a parent of another context. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +(type *)talloc_find_parent_bytype(ctx, type); + +Like talloc_find_parent_byname() but takes a type, making it typesafe. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_set_log_fn(void (*log_fn)(const char *message)); + +This function sets a logging function that talloc will use for +warnings and errors. By default talloc will not print any warnings or +errors. + +=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- +void talloc_set_log_stderr(void) + +This sets the talloc log function to write log messages to stderr. diff --git a/lib/talloc/talloc_testsuite.h b/lib/talloc/talloc_testsuite.h new file mode 100644 index 0000000..acb9701 --- /dev/null +++ b/lib/talloc/talloc_testsuite.h @@ -0,0 +1,7 @@ +#ifndef __LIB_TALLOC_TALLOC_TESTSUITE_H__ +#define __LIB_TALLOC_TALLOC_TESTSUITE_H__ + +struct torture_context; +bool torture_local_talloc(struct torture_context *tctx); + +#endif diff --git a/lib/talloc/test_magic_differs.sh b/lib/talloc/test_magic_differs.sh new file mode 100755 index 0000000..1b6ba2e --- /dev/null +++ b/lib/talloc/test_magic_differs.sh @@ -0,0 +1,16 @@ +#!/bin/sh +# This test ensures that two different talloc processes do not use the same +# magic value to lessen the opportunity for transferrable attacks. + +echo "test: magic differs" + +helper=$1 +m1=$($helper) +m2=$($helper) + +if [ $m1 -eq $m2 ]; then + echo "failure: magic remained the same between executions ($m1 vs $m2)" + exit 1 +fi + +echo "success: magic differs" diff --git a/lib/talloc/test_magic_differs_helper.c b/lib/talloc/test_magic_differs_helper.c new file mode 100644 index 0000000..6798827 --- /dev/null +++ b/lib/talloc/test_magic_differs_helper.c @@ -0,0 +1,12 @@ +#include <stdio.h> +#include "talloc.h" + +/* + * This program is called by a testing shell script in order to ensure that + * if the library is loaded into different processes it uses different magic + * values in order to thwart security attacks. + */ +int main(int argc, char *argv[]) { + printf("%i\n", talloc_test_get_magic()); + return 0; +} diff --git a/lib/talloc/test_pytalloc.c b/lib/talloc/test_pytalloc.c new file mode 100644 index 0000000..3b0484b --- /dev/null +++ b/lib/talloc/test_pytalloc.c @@ -0,0 +1,244 @@ +/* + Samba Unix SMB/CIFS implementation. + + C utilities for the pytalloc test suite. + Provides the "_test_pytalloc" Python module. + + NOTE: Please read talloc_guide.txt for full documentation + + Copyright (C) Petr Viktorin 2015 + + ** NOTE! The following LGPL license applies to the talloc + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include <Python.h> +#include <talloc.h> +#include <pytalloc.h> + +static PyObject *testpytalloc_new(PyTypeObject *mod, + PyObject *Py_UNUSED(ignored)) +{ + char *obj = talloc_strdup(NULL, "This is a test string");; + return pytalloc_steal(pytalloc_GetObjectType(), obj); +} + +static PyObject *testpytalloc_get_object_type(PyObject *mod, + PyObject *Py_UNUSED(ignored)) +{ + PyObject *type = (PyObject *)pytalloc_GetObjectType(); + Py_INCREF(type); + return type; +} + +static PyObject *testpytalloc_base_new(PyTypeObject *mod, + PyObject *Py_UNUSED(ignored)) +{ + char *obj = talloc_strdup(NULL, "This is a test string for a BaseObject");; + return pytalloc_steal(pytalloc_GetBaseObjectType(), obj); +} + +static PyObject *testpytalloc_base_get_object_type(PyObject *mod, + PyObject *Py_UNUSED(ignored)) +{ + PyObject *type = (PyObject *)pytalloc_GetBaseObjectType(); + Py_INCREF(type); + return type; +} + +static PyObject *testpytalloc_reference(PyObject *mod, PyObject *args) { + PyObject *source = NULL; + void *ptr; + + if (!PyArg_ParseTuple(args, "O!", pytalloc_GetObjectType(), &source)) + return NULL; + + ptr = pytalloc_get_ptr(source); + return pytalloc_reference_ex(pytalloc_GetObjectType(), ptr, ptr); +} + +static PyObject *testpytalloc_base_reference(PyObject *mod, PyObject *args) { + PyObject *source = NULL; + void *mem_ctx; + + if (!PyArg_ParseTuple(args, "O!", pytalloc_GetBaseObjectType(), &source)) { + return NULL; + } + mem_ctx = pytalloc_get_mem_ctx(source); + return pytalloc_reference_ex(pytalloc_GetBaseObjectType(), mem_ctx, mem_ctx); +} + +static PyMethodDef test_talloc_methods[] = { + { "new", (PyCFunction)testpytalloc_new, METH_NOARGS, + "create a talloc Object with a testing string"}, + { "get_object_type", (PyCFunction)testpytalloc_get_object_type, METH_NOARGS, + "call pytalloc_GetObjectType"}, + { "base_new", (PyCFunction)testpytalloc_base_new, METH_NOARGS, + "create a talloc BaseObject with a testing string"}, + { "base_get_object_type", (PyCFunction)testpytalloc_base_get_object_type, METH_NOARGS, + "call pytalloc_GetBaseObjectType"}, + { "reference", (PyCFunction)testpytalloc_reference, METH_VARARGS, + "call pytalloc_reference_ex"}, + { "base_reference", (PyCFunction)testpytalloc_base_reference, METH_VARARGS, + "call pytalloc_reference_ex"}, + {0} +}; + +static PyTypeObject DObject_Type; + +static int dobject_destructor(void *ptr) +{ + PyObject *destructor_func = *talloc_get_type(ptr, PyObject*); + PyObject *ret; + ret = PyObject_CallObject(destructor_func, NULL); + Py_DECREF(destructor_func); + if (ret == NULL) { + PyErr_Print(); + } else { + Py_DECREF(ret); + } + return 0; +} + +static PyObject *dobject_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *destructor_func = NULL; + PyObject **obj; + + if (!PyArg_ParseTuple(args, "O", &destructor_func)) + return NULL; + Py_INCREF(destructor_func); + + obj = talloc(NULL, PyObject*); + *obj = destructor_func; + + talloc_set_destructor((void*)obj, dobject_destructor); + return pytalloc_steal(&DObject_Type, obj); +} + +static PyTypeObject DObject_Type = { + .tp_name = "_test_pytalloc.DObject", + .tp_basicsize = sizeof(pytalloc_Object), + .tp_methods = NULL, + .tp_new = dobject_new, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_doc = "test talloc object that calls a function when underlying data is freed\n", +}; + +static PyTypeObject DBaseObject_Type; + +static int d_base_object_destructor(void *ptr) +{ + PyObject *destructor_func = *talloc_get_type(ptr, PyObject*); + PyObject *ret; + ret = PyObject_CallObject(destructor_func, NULL); + Py_DECREF(destructor_func); + if (ret == NULL) { + PyErr_Print(); + } else { + Py_DECREF(ret); + } + return 0; +} + +static PyObject *d_base_object_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) +{ + PyObject *destructor_func = NULL; + PyObject **obj; + + if (!PyArg_ParseTuple(args, "O", &destructor_func)) + return NULL; + Py_INCREF(destructor_func); + + obj = talloc(NULL, PyObject*); + *obj = destructor_func; + + talloc_set_destructor((void*)obj, d_base_object_destructor); + return pytalloc_steal(&DBaseObject_Type, obj); +} + +static PyTypeObject DBaseObject_Type = { + .tp_name = "_test_pytalloc.DBaseObject", + .tp_methods = NULL, + .tp_new = d_base_object_new, + .tp_flags = Py_TPFLAGS_DEFAULT, + .tp_doc = "test talloc object that calls a function when underlying data is freed\n", +}; + +#define MODULE_DOC PyDoc_STR("Test utility module for pytalloc") + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + .m_name = "_test_pytalloc", + .m_doc = PyDoc_STR("Test utility module for pytalloc"), + .m_size = -1, + .m_methods = test_talloc_methods, +}; +#endif + +static PyObject *module_init(void); +static PyObject *module_init(void) +{ + PyObject *m; + + DObject_Type.tp_base = pytalloc_GetObjectType(); + if (PyType_Ready(&DObject_Type) < 0) { + return NULL; + } + + DBaseObject_Type.tp_basicsize = pytalloc_BaseObject_size(); + DBaseObject_Type.tp_base = pytalloc_GetBaseObjectType(); + if (PyType_Ready(&DBaseObject_Type) < 0) { + return NULL; + } + +#if PY_MAJOR_VERSION >= 3 + m = PyModule_Create(&moduledef); +#else + m = Py_InitModule3("_test_pytalloc", test_talloc_methods, MODULE_DOC); +#endif + + if (m == NULL) { + return NULL; + } + + Py_INCREF(&DObject_Type); + Py_INCREF(DObject_Type.tp_base); + PyModule_AddObject(m, "DObject", (PyObject *)&DObject_Type); + + Py_INCREF(&DBaseObject_Type); + Py_INCREF(DBaseObject_Type.tp_base); + PyModule_AddObject(m, "DBaseObject", (PyObject *)&DBaseObject_Type); + + return m; +} + + +#if PY_MAJOR_VERSION >= 3 +PyMODINIT_FUNC PyInit__test_pytalloc(void); +PyMODINIT_FUNC PyInit__test_pytalloc(void) +{ + return module_init(); +} +#else +void init_test_pytalloc(void); +void init_test_pytalloc(void) +{ + module_init(); +} +#endif diff --git a/lib/talloc/test_pytalloc.py b/lib/talloc/test_pytalloc.py new file mode 100644 index 0000000..809510f --- /dev/null +++ b/lib/talloc/test_pytalloc.py @@ -0,0 +1,189 @@ +#!/usr/bin/env python3 +# Simple tests for the talloc python bindings. +# Copyright (C) 2015 Petr Viktorin <pviktori@redhat.com> + +import unittest +import subprocess +import sys +import gc + +import talloc +import _test_pytalloc + + +def dummy_func(): + pass + + +class TallocTests(unittest.TestCase): + + def test_report_full(self): + # report_full is hardcoded to print to stdout, so use a subprocess + process = subprocess.Popen([ + sys.executable, '-c', + """if True: + import talloc, _test_pytalloc + obj = _test_pytalloc.new() + talloc.report_full(obj) + """ + ], stdout=subprocess.PIPE) + output, stderr = process.communicate() + output = str(output) + self.assertTrue("full talloc report on 'talloc.Object" in output) + self.assertTrue("This is a test string" in output) + + def test_totalblocks(self): + obj = _test_pytalloc.new() + # Two blocks: the string, and the name + self.assertEqual(talloc.total_blocks(obj), 2) + + def test_repr(self): + obj = _test_pytalloc.new() + prefix = '<talloc.Object talloc object at' + self.assertTrue(repr(obj).startswith(prefix)) + self.assertEqual(repr(obj), str(obj)) + + def test_base_repr(self): + obj = _test_pytalloc.base_new() + prefix = '<talloc.BaseObject talloc based object at' + self.assertTrue(repr(obj).startswith(prefix)) + self.assertEqual(repr(obj), str(obj)) + + def test_destructor(self): + # Check correct lifetime of the talloc'd data + lst = [] + obj = _test_pytalloc.DObject(lambda: lst.append('dead')) + self.assertEqual(lst, []) + del obj + gc.collect() + self.assertEqual(lst, ['dead']) + + def test_base_destructor(self): + # Check correct lifetime of the talloc'd data + lst = [] + obj = _test_pytalloc.DBaseObject(lambda: lst.append('dead')) + self.assertEqual(lst, []) + del obj + gc.collect() + self.assertEqual(lst, ['dead']) + + +class TallocComparisonTests(unittest.TestCase): + + def test_compare_same(self): + obj1 = _test_pytalloc.new() + self.assertTrue(obj1 == obj1) + self.assertFalse(obj1 != obj1) + self.assertTrue(obj1 <= obj1) + self.assertFalse(obj1 < obj1) + self.assertTrue(obj1 >= obj1) + self.assertFalse(obj1 > obj1) + + def test_compare_different(self): + # object comparison is consistent + obj1, obj2 = sorted([ + _test_pytalloc.new(), + _test_pytalloc.new()]) + self.assertFalse(obj1 == obj2) + self.assertTrue(obj1 != obj2) + self.assertTrue(obj1 <= obj2) + self.assertTrue(obj1 < obj2) + self.assertFalse(obj1 >= obj2) + self.assertFalse(obj1 > obj2) + + def test_compare_different_types(self): + # object comparison falls back to comparing types + if sys.version_info >= (3, 0): + # In Python 3, types are unorderable -- nothing to test + return + if talloc.Object < _test_pytalloc.DObject: + obj1 = _test_pytalloc.new() + obj2 = _test_pytalloc.DObject(dummy_func) + else: + obj2 = _test_pytalloc.new() + obj1 = _test_pytalloc.DObject(dummy_func) + self.assertFalse(obj1 == obj2) + self.assertTrue(obj1 != obj2) + self.assertTrue(obj1 <= obj2) + self.assertTrue(obj1 < obj2) + self.assertFalse(obj1 >= obj2) + self.assertFalse(obj1 > obj2) + + +class TallocBaseComparisonTests(unittest.TestCase): + + def test_compare_same(self): + obj1 = _test_pytalloc.base_new() + self.assertTrue(obj1 == obj1) + self.assertFalse(obj1 != obj1) + self.assertTrue(obj1 <= obj1) + self.assertFalse(obj1 < obj1) + self.assertTrue(obj1 >= obj1) + self.assertFalse(obj1 > obj1) + + def test_compare_different(self): + # object comparison is consistent + obj1, obj2 = sorted([ + _test_pytalloc.base_new(), + _test_pytalloc.base_new()]) + self.assertFalse(obj1 == obj2) + self.assertTrue(obj1 != obj2) + self.assertTrue(obj1 <= obj2) + self.assertTrue(obj1 < obj2) + self.assertFalse(obj1 >= obj2) + self.assertFalse(obj1 > obj2) + + def test_compare_different_types(self): + # object comparison falls back to comparing types + if sys.version_info >= (3, 0): + # In Python 3, types are unorderable -- nothing to test + return + if talloc.BaseObject < _test_pytalloc.DBaseObject: + obj1 = _test_pytalloc.base_new() + obj2 = _test_pytalloc.DBaseObject(dummy_func) + else: + obj2 = _test_pytalloc.base_new() + obj1 = _test_pytalloc.DBaseObject(dummy_func) + self.assertFalse(obj1 == obj2) + self.assertTrue(obj1 != obj2) + self.assertTrue(obj1 <= obj2) + self.assertTrue(obj1 < obj2) + self.assertFalse(obj1 >= obj2) + self.assertFalse(obj1 > obj2) + + +class TallocUtilTests(unittest.TestCase): + + def test_get_type(self): + self.assertTrue(talloc.Object is _test_pytalloc.get_object_type()) + + def test_reference(self): + # Check correct lifetime of the talloc'd data with multiple references + lst = [] + obj = _test_pytalloc.DObject(lambda: lst.append('dead')) + ref = _test_pytalloc.reference(obj) + del obj + gc.collect() + self.assertEqual(lst, []) + del ref + gc.collect() + self.assertEqual(lst, ['dead']) + + def test_get_base_type(self): + self.assertTrue(talloc.BaseObject is _test_pytalloc.base_get_object_type()) + + def test_base_reference(self): + # Check correct lifetime of the talloc'd data with multiple references + lst = [] + obj = _test_pytalloc.DBaseObject(lambda: lst.append('dead')) + ref = _test_pytalloc.base_reference(obj) + del obj + gc.collect() + self.assertEqual(lst, []) + del ref + gc.collect() + self.assertEqual(lst, ['dead']) + + +if __name__ == '__main__': + unittest.TestProgram() diff --git a/lib/talloc/testsuite.c b/lib/talloc/testsuite.c new file mode 100644 index 0000000..282ebc6 --- /dev/null +++ b/lib/talloc/testsuite.c @@ -0,0 +1,2288 @@ +/* + Unix SMB/CIFS implementation. + + local testing of talloc routines. + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the talloc + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" +#include "system/time.h" +#include <talloc.h> + +#ifdef HAVE_PTHREAD +#include <pthread.h> +#endif + +#include <unistd.h> +#include <sys/wait.h> + +#ifdef NDEBUG +#undef NDEBUG +#endif + +#include <assert.h> + +#include "talloc_testsuite.h" + +static struct timeval private_timeval_current(void) +{ + struct timeval tv; + gettimeofday(&tv, NULL); + return tv; +} + +static double private_timeval_elapsed(struct timeval *tv) +{ + struct timeval tv2 = private_timeval_current(); + return (tv2.tv_sec - tv->tv_sec) + + (tv2.tv_usec - tv->tv_usec)*1.0e-6; +} + +#define torture_assert(test, expr, str) if (!(expr)) { \ + printf("failure: %s [\n%s: Expression %s failed: %s\n]\n", \ + test, __location__, #expr, str); \ + return false; \ +} + +#define torture_assert_str_equal(test, arg1, arg2, desc) \ + if (arg1 == NULL && arg2 == NULL) { /* OK, both NULL == equal */ \ + } else if (arg1 == NULL || arg2 == NULL) { \ + return false; \ + } else if (strcmp(arg1, arg2)) { \ + printf("failure: %s [\n%s: Expected %s, got %s: %s\n]\n", \ + test, __location__, arg1, arg2, desc); \ + return false; \ + } + +#define CHECK_SIZE(test, ptr, tsize) do { \ + if (talloc_total_size(ptr) != (tsize)) { \ + printf("failed: %s [\n%s: wrong '%s' tree size: got %u expected %u\n]\n", \ + test, __location__, #ptr, \ + (unsigned)talloc_total_size(ptr), \ + (unsigned)tsize); \ + talloc_report_full(ptr, stdout); \ + return false; \ + } \ +} while (0) + +#define CHECK_BLOCKS(test, ptr, tblocks) do { \ + if (talloc_total_blocks(ptr) != (tblocks)) { \ + printf("failed: %s [\n%s: wrong '%s' tree blocks: got %u expected %u\n]\n", \ + test, __location__, #ptr, \ + (unsigned)talloc_total_blocks(ptr), \ + (unsigned)tblocks); \ + talloc_report_full(ptr, stdout); \ + return false; \ + } \ +} while (0) + +#define CHECK_PARENT(test, ptr, parent) do { \ + if (talloc_parent(ptr) != (parent)) { \ + printf("failed: %s [\n%s: '%s' has wrong parent: got %p expected %p\n]\n", \ + test, __location__, #ptr, \ + talloc_parent(ptr), \ + (parent)); \ + talloc_report_full(ptr, stdout); \ + talloc_report_full(parent, stdout); \ + talloc_report_full(NULL, stdout); \ + return false; \ + } \ +} while (0) + +static unsigned int test_abort_count; + +#if 0 +static void test_abort_fn(const char *reason) +{ + printf("# test_abort_fn(%s)\n", reason); + test_abort_count++; +} + +static void test_abort_start(void) +{ + test_abort_count = 0; + talloc_set_abort_fn(test_abort_fn); +} +#endif + +static void test_abort_stop(void) +{ + test_abort_count = 0; + talloc_set_abort_fn(NULL); +} + +static void test_log_stdout(const char *message) +{ + fprintf(stdout, "%s", message); +} + +/* + test references +*/ +static bool test_ref1(void) +{ + void *root, *p1, *p2, *ref, *r1; + + printf("test: ref1\n# SINGLE REFERENCE FREE\n"); + + root = talloc_named_const(NULL, 0, "root"); + p1 = talloc_named_const(root, 1, "p1"); + p2 = talloc_named_const(p1, 1, "p2"); + talloc_named_const(p1, 1, "x1"); + talloc_named_const(p1, 2, "x2"); + talloc_named_const(p1, 3, "x3"); + + r1 = talloc_named_const(root, 1, "r1"); + ref = talloc_reference(r1, p2); + talloc_report_full(root, stderr); + + CHECK_BLOCKS("ref1", p1, 5); + CHECK_BLOCKS("ref1", p2, 1); + CHECK_BLOCKS("ref1", ref, 1); + CHECK_BLOCKS("ref1", r1, 2); + + fprintf(stderr, "Freeing p2\n"); + talloc_unlink(r1, p2); + talloc_report_full(root, stderr); + + CHECK_BLOCKS("ref1", p1, 5); + CHECK_BLOCKS("ref1", p2, 1); + CHECK_BLOCKS("ref1", r1, 1); + + fprintf(stderr, "Freeing p1\n"); + talloc_free(p1); + talloc_report_full(root, stderr); + + CHECK_BLOCKS("ref1", r1, 1); + + fprintf(stderr, "Freeing r1\n"); + talloc_free(r1); + talloc_report_full(NULL, stderr); + + fprintf(stderr, "Testing NULL\n"); + if (talloc_reference(root, NULL)) { + return false; + } + + CHECK_BLOCKS("ref1", root, 1); + + CHECK_SIZE("ref1", root, 0); + + talloc_free(root); + printf("success: ref1\n"); + return true; +} + +/* + test references +*/ +static bool test_ref2(void) +{ + void *root, *p1, *p2, *ref, *r1; + + printf("test: ref2\n# DOUBLE REFERENCE FREE\n"); + root = talloc_named_const(NULL, 0, "root"); + p1 = talloc_named_const(root, 1, "p1"); + talloc_named_const(p1, 1, "x1"); + talloc_named_const(p1, 1, "x2"); + talloc_named_const(p1, 1, "x3"); + p2 = talloc_named_const(p1, 1, "p2"); + + r1 = talloc_named_const(root, 1, "r1"); + ref = talloc_reference(r1, p2); + talloc_report_full(root, stderr); + + CHECK_BLOCKS("ref2", p1, 5); + CHECK_BLOCKS("ref2", p2, 1); + CHECK_BLOCKS("ref2", r1, 2); + + fprintf(stderr, "Freeing ref\n"); + talloc_unlink(r1, ref); + talloc_report_full(root, stderr); + + CHECK_BLOCKS("ref2", p1, 5); + CHECK_BLOCKS("ref2", p2, 1); + CHECK_BLOCKS("ref2", r1, 1); + + fprintf(stderr, "Freeing p2\n"); + talloc_free(p2); + talloc_report_full(root, stderr); + + CHECK_BLOCKS("ref2", p1, 4); + CHECK_BLOCKS("ref2", r1, 1); + + fprintf(stderr, "Freeing p1\n"); + talloc_free(p1); + talloc_report_full(root, stderr); + + CHECK_BLOCKS("ref2", r1, 1); + + fprintf(stderr, "Freeing r1\n"); + talloc_free(r1); + talloc_report_full(root, stderr); + + CHECK_SIZE("ref2", root, 0); + + talloc_free(root); + printf("success: ref2\n"); + return true; +} + +/* + test references +*/ +static bool test_ref3(void) +{ + void *root, *p1, *p2, *ref, *r1; + + printf("test: ref3\n# PARENT REFERENCE FREE\n"); + + root = talloc_named_const(NULL, 0, "root"); + p1 = talloc_named_const(root, 1, "p1"); + p2 = talloc_named_const(root, 1, "p2"); + r1 = talloc_named_const(p1, 1, "r1"); + ref = talloc_reference(p2, r1); + talloc_report_full(root, stderr); + + CHECK_BLOCKS("ref3", p1, 2); + CHECK_BLOCKS("ref3", p2, 2); + CHECK_BLOCKS("ref3", r1, 1); + CHECK_BLOCKS("ref3", ref, 1); + + fprintf(stderr, "Freeing p1\n"); + talloc_free(p1); + talloc_report_full(root, stderr); + + CHECK_BLOCKS("ref3", p2, 2); + CHECK_BLOCKS("ref3", r1, 1); + + fprintf(stderr, "Freeing p2\n"); + talloc_free(p2); + talloc_report_full(root, stderr); + + CHECK_SIZE("ref3", root, 0); + + talloc_free(root); + + printf("success: ref3\n"); + return true; +} + +/* + test references +*/ +static bool test_ref4(void) +{ + void *root, *p1, *p2, *ref, *r1; + + printf("test: ref4\n# REFERRER REFERENCE FREE\n"); + + root = talloc_named_const(NULL, 0, "root"); + p1 = talloc_named_const(root, 1, "p1"); + talloc_named_const(p1, 1, "x1"); + talloc_named_const(p1, 1, "x2"); + talloc_named_const(p1, 1, "x3"); + p2 = talloc_named_const(p1, 1, "p2"); + + r1 = talloc_named_const(root, 1, "r1"); + ref = talloc_reference(r1, p2); + talloc_report_full(root, stderr); + + CHECK_BLOCKS("ref4", p1, 5); + CHECK_BLOCKS("ref4", p2, 1); + CHECK_BLOCKS("ref4", ref, 1); + CHECK_BLOCKS("ref4", r1, 2); + + fprintf(stderr, "Freeing r1\n"); + talloc_free(r1); + talloc_report_full(root, stderr); + + CHECK_BLOCKS("ref4", p1, 5); + CHECK_BLOCKS("ref4", p2, 1); + + fprintf(stderr, "Freeing p2\n"); + talloc_free(p2); + talloc_report_full(root, stderr); + + CHECK_BLOCKS("ref4", p1, 4); + + fprintf(stderr, "Freeing p1\n"); + talloc_free(p1); + talloc_report_full(root, stderr); + + CHECK_SIZE("ref4", root, 0); + + talloc_free(root); + + printf("success: ref4\n"); + return true; +} + + +/* + test references +*/ +static bool test_unlink1(void) +{ + void *root, *p1, *p2, *ref, *r1; + + printf("test: unlink\n# UNLINK\n"); + + root = talloc_named_const(NULL, 0, "root"); + p1 = talloc_named_const(root, 1, "p1"); + talloc_named_const(p1, 1, "x1"); + talloc_named_const(p1, 1, "x2"); + talloc_named_const(p1, 1, "x3"); + p2 = talloc_named_const(p1, 1, "p2"); + + r1 = talloc_named_const(p1, 1, "r1"); + ref = talloc_reference(r1, p2); + talloc_report_full(root, stderr); + + CHECK_BLOCKS("unlink", p1, 7); + CHECK_BLOCKS("unlink", p2, 1); + CHECK_BLOCKS("unlink", ref, 1); + CHECK_BLOCKS("unlink", r1, 2); + + fprintf(stderr, "Unreferencing r1\n"); + talloc_unlink(r1, p2); + talloc_report_full(root, stderr); + + CHECK_BLOCKS("unlink", p1, 6); + CHECK_BLOCKS("unlink", p2, 1); + CHECK_BLOCKS("unlink", r1, 1); + + fprintf(stderr, "Freeing p1\n"); + talloc_free(p1); + talloc_report_full(root, stderr); + + CHECK_SIZE("unlink", root, 0); + + talloc_free(root); + + printf("success: unlink\n"); + return true; +} + +static int fail_destructor(void *ptr) +{ + return -1; +} + +/* + miscellaneous tests to try to get a higher test coverage percentage +*/ +static bool test_misc(void) +{ + void *root, *p1; + char *p2; + double *d; + const char *name; + + printf("test: misc\n# MISCELLANEOUS\n"); + + root = talloc_new(NULL); + + p1 = talloc_size(root, 0x7fffffff); + torture_assert("misc", !p1, "failed: large talloc allowed\n"); + + p1 = talloc_strdup(root, "foo"); + talloc_increase_ref_count(p1); + talloc_increase_ref_count(p1); + talloc_increase_ref_count(p1); + CHECK_BLOCKS("misc", p1, 1); + CHECK_BLOCKS("misc", root, 2); + talloc_unlink(NULL, p1); + CHECK_BLOCKS("misc", p1, 1); + CHECK_BLOCKS("misc", root, 2); + talloc_unlink(NULL, p1); + CHECK_BLOCKS("misc", p1, 1); + CHECK_BLOCKS("misc", root, 2); + p2 = talloc_strdup(p1, "foo"); + torture_assert("misc", talloc_unlink(root, p2) == -1, + "failed: talloc_unlink() of non-reference context should return -1\n"); + torture_assert("misc", talloc_unlink(p1, p2) == 0, + "failed: talloc_unlink() of parent should succeed\n"); + talloc_unlink(NULL, p1); + CHECK_BLOCKS("misc", p1, 1); + CHECK_BLOCKS("misc", root, 2); + + name = talloc_set_name(p1, "my name is %s", "foo"); + torture_assert_str_equal("misc", talloc_get_name(p1), "my name is foo", + "failed: wrong name after talloc_set_name(my name is foo)"); + torture_assert_str_equal("misc", talloc_get_name(p1), name, + "failed: wrong name after talloc_set_name(my name is foo)"); + CHECK_BLOCKS("misc", p1, 2); + CHECK_BLOCKS("misc", root, 3); + + talloc_set_name_const(p1, NULL); + torture_assert_str_equal ("misc", talloc_get_name(p1), "UNNAMED", + "failed: wrong name after talloc_set_name(NULL)"); + CHECK_BLOCKS("misc", p1, 2); + CHECK_BLOCKS("misc", root, 3); + + torture_assert("misc", talloc_free(NULL) == -1, + "talloc_free(NULL) should give -1\n"); + + talloc_set_destructor(p1, fail_destructor); + torture_assert("misc", talloc_free(p1) == -1, + "Failed destructor should cause talloc_free to fail\n"); + talloc_set_destructor(p1, NULL); + + talloc_report(root, stderr); + + + p2 = (char *)talloc_zero_size(p1, 20); + torture_assert("misc", p2[19] == 0, "Failed to give zero memory\n"); + talloc_free(p2); + + torture_assert("misc", talloc_strdup(root, NULL) == NULL, + "failed: strdup on NULL should give NULL\n"); + + p2 = talloc_strndup(p1, "foo", 2); + torture_assert("misc", strcmp("fo", p2) == 0, + "strndup doesn't work\n"); + p2 = talloc_asprintf_append_buffer(p2, "o%c", 'd'); + torture_assert("misc", strcmp("food", p2) == 0, + "talloc_asprintf_append_buffer doesn't work\n"); + CHECK_BLOCKS("misc", p2, 1); + CHECK_BLOCKS("misc", p1, 3); + + p2 = talloc_asprintf_append_buffer(NULL, "hello %s", "world"); + torture_assert("misc", strcmp("hello world", p2) == 0, + "talloc_asprintf_append_buffer doesn't work\n"); + CHECK_BLOCKS("misc", p2, 1); + CHECK_BLOCKS("misc", p1, 3); + talloc_free(p2); + + d = talloc_array(p1, double, 0x20000000); + torture_assert("misc", !d, "failed: integer overflow not detected\n"); + + d = talloc_realloc(p1, d, double, 0x20000000); + torture_assert("misc", !d, "failed: integer overflow not detected\n"); + + talloc_free(p1); + CHECK_BLOCKS("misc", root, 1); + + p1 = talloc_named(root, 100, "%d bytes", 100); + CHECK_BLOCKS("misc", p1, 2); + CHECK_BLOCKS("misc", root, 3); + talloc_unlink(root, p1); + + p1 = talloc_init("%d bytes", 200); + p2 = talloc_asprintf(p1, "my test '%s'", "string"); + torture_assert_str_equal("misc", p2, "my test 'string'", + "failed: talloc_asprintf(\"my test '%%s'\", \"string\") gave: \"%s\""); + CHECK_BLOCKS("misc", p1, 3); + CHECK_SIZE("misc", p2, 17); + CHECK_BLOCKS("misc", root, 1); + talloc_unlink(NULL, p1); + + p1 = talloc_named_const(root, 10, "p1"); + p2 = (char *)talloc_named_const(root, 20, "p2"); + (void)talloc_reference(p1, p2); + talloc_report_full(root, stderr); + talloc_unlink(root, p2); + talloc_report_full(root, stderr); + CHECK_BLOCKS("misc", p2, 1); + CHECK_BLOCKS("misc", p1, 2); + CHECK_BLOCKS("misc", root, 3); + talloc_unlink(p1, p2); + talloc_unlink(root, p1); + + p1 = talloc_named_const(root, 10, "p1"); + p2 = (char *)talloc_named_const(root, 20, "p2"); + (void)talloc_reference(NULL, p2); + talloc_report_full(root, stderr); + talloc_unlink(root, p2); + talloc_report_full(root, stderr); + CHECK_BLOCKS("misc", p2, 1); + CHECK_BLOCKS("misc", p1, 1); + CHECK_BLOCKS("misc", root, 2); + talloc_unlink(NULL, p2); + talloc_unlink(root, p1); + + /* Test that talloc_unlink is a no-op */ + + torture_assert("misc", talloc_unlink(root, NULL) == -1, + "failed: talloc_unlink(root, NULL) == -1\n"); + + talloc_report(root, stderr); + talloc_report(NULL, stderr); + + CHECK_SIZE("misc", root, 0); + + talloc_free(root); + + CHECK_SIZE("misc", NULL, 0); + + talloc_enable_null_tracking_no_autofree(); + talloc_enable_leak_report(); + talloc_enable_leak_report_full(); + + printf("success: misc\n"); + + return true; +} + + +/* + test realloc +*/ +static bool test_realloc(void) +{ + void *root, *p1, *p2; + + printf("test: realloc\n# REALLOC\n"); + + root = talloc_new(NULL); + + p1 = talloc_size(root, 10); + CHECK_SIZE("realloc", p1, 10); + + p1 = talloc_realloc_size(NULL, p1, 20); + CHECK_SIZE("realloc", p1, 20); + + talloc_new(p1); + + p2 = talloc_realloc_size(p1, NULL, 30); + + talloc_new(p1); + + p2 = talloc_realloc_size(p1, p2, 40); + + CHECK_SIZE("realloc", p2, 40); + CHECK_SIZE("realloc", root, 60); + CHECK_BLOCKS("realloc", p1, 4); + + p1 = talloc_realloc_size(NULL, p1, 20); + CHECK_SIZE("realloc", p1, 60); + + talloc_increase_ref_count(p2); + torture_assert("realloc", talloc_realloc_size(NULL, p2, 5) == NULL, + "failed: talloc_realloc() on a referenced pointer should fail\n"); + CHECK_BLOCKS("realloc", p1, 4); + + talloc_realloc_size(NULL, p2, 0); + talloc_realloc_size(NULL, p2, 0); + CHECK_BLOCKS("realloc", p1, 4); + talloc_realloc_size(p1, p2, 0); + CHECK_BLOCKS("realloc", p1, 3); + + torture_assert("realloc", talloc_realloc_size(NULL, p1, 0x7fffffff) == NULL, + "failed: oversize talloc should fail\n"); + + talloc_realloc_size(NULL, p1, 0); + CHECK_BLOCKS("realloc", root, 4); + talloc_realloc_size(root, p1, 0); + CHECK_BLOCKS("realloc", root, 1); + + CHECK_SIZE("realloc", root, 0); + + talloc_free(root); + + printf("success: realloc\n"); + + return true; +} + +/* + test realloc with a child +*/ +static bool test_realloc_child(void) +{ + void *root; + struct el2 { + const char *name; + } *el2, *el2_2, *el2_3, **el_list_save; + struct el1 { + int count; + struct el2 **list, **list2, **list3; + } *el1; + + printf("test: REALLOC WITH CHILD\n"); + + root = talloc_new(NULL); + + el1 = talloc(root, struct el1); + el1->list = talloc(el1, struct el2 *); + el1->list[0] = talloc(el1->list, struct el2); + el1->list[0]->name = talloc_strdup(el1->list[0], "testing"); + + el1->list2 = talloc(el1, struct el2 *); + el1->list2[0] = talloc(el1->list2, struct el2); + el1->list2[0]->name = talloc_strdup(el1->list2[0], "testing2"); + + el1->list3 = talloc(el1, struct el2 *); + el1->list3[0] = talloc(el1->list3, struct el2); + el1->list3[0]->name = talloc_strdup(el1->list3[0], "testing2"); + + el2 = talloc(el1->list, struct el2); + CHECK_PARENT("el2", el2, el1->list); + el2_2 = talloc(el1->list2, struct el2); + CHECK_PARENT("el2", el2_2, el1->list2); + el2_3 = talloc(el1->list3, struct el2); + CHECK_PARENT("el2", el2_3, el1->list3); + + el_list_save = el1->list; + el1->list = talloc_realloc(el1, el1->list, struct el2 *, 100); + if (el1->list == el_list_save) { + printf("failure: talloc_realloc didn't move pointer"); + return false; + } + + CHECK_PARENT("el1_after_realloc", el1->list, el1); + el1->list2 = talloc_realloc(el1, el1->list2, struct el2 *, 200); + CHECK_PARENT("el1_after_realloc", el1->list2, el1); + el1->list3 = talloc_realloc(el1, el1->list3, struct el2 *, 300); + CHECK_PARENT("el1_after_realloc", el1->list3, el1); + + CHECK_PARENT("el2", el2, el1->list); + CHECK_PARENT("el2", el2_2, el1->list2); + CHECK_PARENT("el2", el2_3, el1->list3); + + /* Finally check realloc with multiple children */ + el1 = talloc_realloc(root, el1, struct el1, 100); + CHECK_PARENT("el1->list", el1->list, el1); + CHECK_PARENT("el1->list2", el1->list2, el1); + CHECK_PARENT("el1->list3", el1->list3, el1); + + talloc_free(root); + + printf("success: REALLOC WITH CHILD\n"); + return true; +} + +/* + test type checking +*/ +static bool test_type(void) +{ + void *root; + struct el1 { + int count; + }; + struct el2 { + int count; + }; + struct el1 *el1; + + printf("test: type\n# talloc type checking\n"); + + root = talloc_new(NULL); + + el1 = talloc(root, struct el1); + + el1->count = 1; + + torture_assert("type", talloc_get_type(el1, struct el1) == el1, + "type check failed on el1\n"); + torture_assert("type", talloc_get_type(el1, struct el2) == NULL, + "type check failed on el1 with el2\n"); + talloc_set_type(el1, struct el2); + torture_assert("type", talloc_get_type(el1, struct el2) == (struct el2 *)el1, + "type set failed on el1 with el2\n"); + + talloc_free(root); + + printf("success: type\n"); + return true; +} + +/* + test steal +*/ +static bool test_steal(void) +{ + void *root, *p1, *p2; + + printf("test: steal\n# STEAL\n"); + + root = talloc_new(NULL); + + p1 = talloc_array(root, char, 10); + CHECK_SIZE("steal", p1, 10); + + p2 = talloc_realloc(root, NULL, char, 20); + CHECK_SIZE("steal", p1, 10); + CHECK_SIZE("steal", root, 30); + + torture_assert("steal", talloc_steal(p1, NULL) == NULL, + "failed: stealing NULL should give NULL\n"); + + torture_assert("steal", talloc_steal(p1, p1) == p1, + "failed: stealing to ourselves is a nop\n"); + CHECK_BLOCKS("steal", root, 3); + CHECK_SIZE("steal", root, 30); + + talloc_steal(NULL, p1); + talloc_steal(NULL, p2); + CHECK_BLOCKS("steal", root, 1); + CHECK_SIZE("steal", root, 0); + + talloc_free(p1); + talloc_steal(root, p2); + CHECK_BLOCKS("steal", root, 2); + CHECK_SIZE("steal", root, 20); + + talloc_free(p2); + + CHECK_BLOCKS("steal", root, 1); + CHECK_SIZE("steal", root, 0); + + talloc_free(root); + + p1 = talloc_size(NULL, 3); + talloc_report_full(NULL, stderr); + CHECK_SIZE("steal", NULL, 3); + talloc_free(p1); + + printf("success: steal\n"); + return true; +} + +/* + test move +*/ +static bool test_move(void) +{ + void *root; + struct t_move { + char *p; + int *x; + } *t1, *t2; + + printf("test: move\n# MOVE\n"); + + root = talloc_new(NULL); + + t1 = talloc(root, struct t_move); + t2 = talloc(root, struct t_move); + t1->p = talloc_strdup(t1, "foo"); + t1->x = talloc(t1, int); + *t1->x = 42; + + t2->p = talloc_move(t2, &t1->p); + t2->x = talloc_move(t2, &t1->x); + torture_assert("move", t1->p == NULL && t1->x == NULL && + strcmp(t2->p, "foo") == 0 && *t2->x == 42, + "talloc move failed"); + + talloc_free(root); + + printf("success: move\n"); + + return true; +} + +/* + test talloc_realloc_fn +*/ +static bool test_realloc_fn(void) +{ + void *root, *p1; + + printf("test: realloc_fn\n# talloc_realloc_fn\n"); + + root = talloc_new(NULL); + + p1 = talloc_realloc_fn(root, NULL, 10); + CHECK_BLOCKS("realloc_fn", root, 2); + CHECK_SIZE("realloc_fn", root, 10); + p1 = talloc_realloc_fn(root, p1, 20); + CHECK_BLOCKS("realloc_fn", root, 2); + CHECK_SIZE("realloc_fn", root, 20); + p1 = talloc_realloc_fn(root, p1, 0); + CHECK_BLOCKS("realloc_fn", root, 1); + CHECK_SIZE("realloc_fn", root, 0); + + talloc_free(root); + + printf("success: realloc_fn\n"); + return true; +} + + +static bool test_unref_reparent(void) +{ + void *root, *p1, *p2, *c1; + + printf("test: unref_reparent\n# UNREFERENCE AFTER PARENT FREED\n"); + + root = talloc_named_const(NULL, 0, "root"); + p1 = talloc_named_const(root, 1, "orig parent"); + p2 = talloc_named_const(root, 1, "parent by reference"); + + c1 = talloc_named_const(p1, 1, "child"); + talloc_reference(p2, c1); + + CHECK_PARENT("unref_reparent", c1, p1); + + talloc_free(p1); + + CHECK_PARENT("unref_reparent", c1, p2); + + talloc_unlink(p2, c1); + + CHECK_SIZE("unref_reparent", root, 1); + + talloc_free(p2); + talloc_free(root); + + printf("success: unref_reparent\n"); + return true; +} + +/* + measure the speed of talloc versus malloc +*/ +static bool test_speed(void) +{ + void *ctx = talloc_new(NULL); + unsigned count; + const int loop = 1000; + int i; + struct timeval tv; + + printf("test: speed\n# TALLOC VS MALLOC SPEED\n"); + + tv = private_timeval_current(); + count = 0; + do { + void *p1, *p2, *p3; + for (i=0;i<loop;i++) { + p1 = talloc_size(ctx, loop % 100); + p2 = talloc_strdup(p1, "foo bar"); + p3 = talloc_size(p1, 300); + (void)p2; + (void)p3; + talloc_free(p1); + } + count += 3 * loop; + } while (private_timeval_elapsed(&tv) < 5.0); + + fprintf(stderr, "talloc: %.0f ops/sec\n", count/private_timeval_elapsed(&tv)); + + talloc_free(ctx); + + ctx = talloc_pool(NULL, 1024); + + tv = private_timeval_current(); + count = 0; + do { + void *p1, *p2, *p3; + for (i=0;i<loop;i++) { + p1 = talloc_size(ctx, loop % 100); + p2 = talloc_strdup(p1, "foo bar"); + p3 = talloc_size(p1, 300); + (void)p2; + (void)p3; + talloc_free(p1); + } + count += 3 * loop; + } while (private_timeval_elapsed(&tv) < 5.0); + + talloc_free(ctx); + + fprintf(stderr, "talloc_pool: %.0f ops/sec\n", count/private_timeval_elapsed(&tv)); + + tv = private_timeval_current(); + count = 0; + do { + void *p1, *p2, *p3; + for (i=0;i<loop;i++) { + p1 = malloc(loop % 100); + p2 = strdup("foo bar"); + p3 = malloc(300); + free(p1); + free(p2); + free(p3); + } + count += 3 * loop; + } while (private_timeval_elapsed(&tv) < 5.0); + fprintf(stderr, "malloc: %.0f ops/sec\n", count/private_timeval_elapsed(&tv)); + + printf("success: speed\n"); + + return true; +} + +static bool test_lifeless(void) +{ + void *top = talloc_new(NULL); + char *parent, *child; + void *child_owner = talloc_new(NULL); + + printf("test: lifeless\n# TALLOC_UNLINK LOOP\n"); + + parent = talloc_strdup(top, "parent"); + child = talloc_strdup(parent, "child"); + (void)talloc_reference(child, parent); + (void)talloc_reference(child_owner, child); + talloc_report_full(top, stderr); + talloc_unlink(top, parent); + talloc_unlink(top, child); + talloc_report_full(top, stderr); + talloc_free(top); + talloc_free(child_owner); + talloc_free(child); + + printf("success: lifeless\n"); + return true; +} + +static int loop_destructor_count; + +static int test_loop_destructor(char *ptr) +{ + loop_destructor_count++; + return 0; +} + +static bool test_loop(void) +{ + void *top = talloc_new(NULL); + char *parent; + struct req1 { + char *req2, *req3; + } *req1; + + printf("test: loop\n# TALLOC LOOP DESTRUCTION\n"); + + parent = talloc_strdup(top, "parent"); + req1 = talloc(parent, struct req1); + req1->req2 = talloc_strdup(req1, "req2"); + talloc_set_destructor(req1->req2, test_loop_destructor); + req1->req3 = talloc_strdup(req1, "req3"); + (void)talloc_reference(req1->req3, req1); + talloc_report_full(top, stderr); + talloc_free(parent); + talloc_report_full(top, stderr); + talloc_report_full(NULL, stderr); + talloc_free(top); + + torture_assert("loop", loop_destructor_count == 1, + "FAILED TO FIRE LOOP DESTRUCTOR\n"); + loop_destructor_count = 0; + + printf("success: loop\n"); + return true; +} + +static int realloc_parent_destructor_count; + +static int test_realloc_parent_destructor(char *ptr) +{ + realloc_parent_destructor_count++; + return 0; +} + +static bool test_realloc_on_destructor_parent(void) +{ + void *top = talloc_new(NULL); + char *parent; + char *a, *b, *C, *D; + realloc_parent_destructor_count = 0; + + printf("test: free_for_exit\n# TALLOC FREE FOR EXIT\n"); + + parent = talloc_strdup(top, "parent"); + a = talloc_strdup(parent, "a"); + b = talloc_strdup(a, "b"); + C = talloc_strdup(a, "C"); + D = talloc_strdup(b, "D"); + talloc_set_destructor(D, test_realloc_parent_destructor); + /* Capitalised ones have destructors. + * + * parent --> a -> b -> D + * -> c + */ + + a = talloc_realloc(parent, a, char, 2048); + + torture_assert("check talloc_realloc", a != NULL, "talloc_realloc failed"); + + talloc_set_destructor(C, test_realloc_parent_destructor); + /* + * parent --> a[2048] -> b -> D + * -> C + * + */ + + talloc_free(parent); + + torture_assert("check destructor realloc_parent_destructor", + realloc_parent_destructor_count == 2, + "FAILED TO FIRE free_for_exit_destructor\n"); + + + printf("success: free_for_exit\n"); + talloc_free(top); /* make ASAN happy */ + + return true; +} + +static int fail_destructor_str(char *ptr) +{ + return -1; +} + +static bool test_free_parent_deny_child(void) +{ + void *top = talloc_new(NULL); + char *level1; + char *level2; + char *level3; + + printf("test: free_parent_deny_child\n# TALLOC FREE PARENT DENY CHILD\n"); + + level1 = talloc_strdup(top, "level1"); + level2 = talloc_strdup(level1, "level2"); + level3 = talloc_strdup(level2, "level3"); + + talloc_set_destructor(level3, fail_destructor_str); + talloc_free(level1); + talloc_set_destructor(level3, NULL); + + CHECK_PARENT("free_parent_deny_child", level3, top); + + talloc_free(top); + + printf("success: free_parent_deny_child\n"); + return true; +} + +struct new_parent { + void *new_parent; + char val[20]; +}; + +static int reparenting_destructor(struct new_parent *np) +{ + talloc_set_destructor(np, NULL); + (void)talloc_move(np->new_parent, &np); + return -1; +} + +static bool test_free_parent_reparent_child(void) +{ + void *top = talloc_new(NULL); + char *level1; + char *alternate_level1; + char *level2; + struct new_parent *level3; + + printf("test: free_parent_reparent_child\n# " + "TALLOC FREE PARENT REPARENT CHILD\n"); + + level1 = talloc_strdup(top, "level1"); + alternate_level1 = talloc_strdup(top, "alternate_level1"); + level2 = talloc_strdup(level1, "level2"); + level3 = talloc(level2, struct new_parent); + level3->new_parent = alternate_level1; + memset(level3->val, 'x', sizeof(level3->val)); + + talloc_set_destructor(level3, reparenting_destructor); + talloc_free(level1); + + CHECK_PARENT("free_parent_reparent_child", + level3, alternate_level1); + + talloc_free(top); + + printf("success: free_parent_reparent_child\n"); + return true; +} + +static bool test_free_parent_reparent_child_in_pool(void) +{ + void *top = talloc_new(NULL); + char *level1; + char *alternate_level1; + char *level2; + void *pool; + struct new_parent *level3; + + printf("test: free_parent_reparent_child_in_pool\n# " + "TALLOC FREE PARENT REPARENT CHILD IN POOL\n"); + + pool = talloc_pool(top, 1024); + level1 = talloc_strdup(pool, "level1"); + alternate_level1 = talloc_strdup(top, "alternate_level1"); + level2 = talloc_strdup(level1, "level2"); + level3 = talloc(level2, struct new_parent); + level3->new_parent = alternate_level1; + memset(level3->val, 'x', sizeof(level3->val)); + + talloc_set_destructor(level3, reparenting_destructor); + talloc_free(level1); + talloc_set_destructor(level3, NULL); + + CHECK_PARENT("free_parent_reparent_child_in_pool", + level3, alternate_level1); + + /* Even freeing alternate_level1 should leave pool alone. */ + talloc_free(alternate_level1); + talloc_free(top); + + printf("success: free_parent_reparent_child_in_pool\n"); + return true; +} + + +static bool test_talloc_ptrtype(void) +{ + void *top = talloc_new(NULL); + struct struct1 { + int foo; + int bar; + } *s1, *s2, **s3, ***s4; + const char *location1; + const char *location2; + const char *location3; + const char *location4; + + printf("test: ptrtype\n# TALLOC PTRTYPE\n"); + + s1 = talloc_ptrtype(top, s1);location1 = __location__; + + if (talloc_get_size(s1) != sizeof(struct struct1)) { + printf("failure: ptrtype [\n" + "talloc_ptrtype() allocated the wrong size %lu (should be %lu)\n" + "]\n", (unsigned long)talloc_get_size(s1), + (unsigned long)sizeof(struct struct1)); + return false; + } + + if (strcmp(location1, talloc_get_name(s1)) != 0) { + printf("failure: ptrtype [\n" + "talloc_ptrtype() sets the wrong name '%s' (should be '%s')\n]\n", + talloc_get_name(s1), location1); + return false; + } + + s2 = talloc_array_ptrtype(top, s2, 10);location2 = __location__; + + if (talloc_get_size(s2) != (sizeof(struct struct1) * 10)) { + printf("failure: ptrtype [\n" + "talloc_array_ptrtype() allocated the wrong size " + "%lu (should be %lu)\n]\n", + (unsigned long)talloc_get_size(s2), + (unsigned long)(sizeof(struct struct1)*10)); + return false; + } + + if (strcmp(location2, talloc_get_name(s2)) != 0) { + printf("failure: ptrtype [\n" + "talloc_array_ptrtype() sets the wrong name '%s' (should be '%s')\n]\n", + talloc_get_name(s2), location2); + return false; + } + + s3 = talloc_array_ptrtype(top, s3, 10);location3 = __location__; + + if (talloc_get_size(s3) != (sizeof(struct struct1 *) * 10)) { + printf("failure: ptrtype [\n" + "talloc_array_ptrtype() allocated the wrong size " + "%lu (should be %lu)\n]\n", + (unsigned long)talloc_get_size(s3), + (unsigned long)(sizeof(struct struct1 *)*10)); + return false; + } + + torture_assert_str_equal("ptrtype", location3, talloc_get_name(s3), + "talloc_array_ptrtype() sets the wrong name"); + + s4 = talloc_array_ptrtype(top, s4, 10);location4 = __location__; + + if (talloc_get_size(s4) != (sizeof(struct struct1 **) * 10)) { + printf("failure: ptrtype [\n" + "talloc_array_ptrtype() allocated the wrong size " + "%lu (should be %lu)\n]\n", + (unsigned long)talloc_get_size(s4), + (unsigned long)(sizeof(struct struct1 **)*10)); + return false; + } + + torture_assert_str_equal("ptrtype", location4, talloc_get_name(s4), + "talloc_array_ptrtype() sets the wrong name"); + + talloc_free(top); + + printf("success: ptrtype\n"); + return true; +} + +static int _test_talloc_free_in_destructor(void **ptr) +{ + talloc_free(*ptr); + return 0; +} + +static bool test_talloc_free_in_destructor(void) +{ + void *level0; + void *level1; + void *level2; + void *level3; + void *level4; + void **level5; + + printf("test: free_in_destructor\n# TALLOC FREE IN DESTRUCTOR\n"); + + level0 = talloc_new(NULL); + level1 = talloc_new(level0); + level2 = talloc_new(level1); + level3 = talloc_new(level2); + level4 = talloc_new(level3); + level5 = talloc(level4, void *); + + *level5 = level3; + (void)talloc_reference(level0, level3); + (void)talloc_reference(level3, level3); + (void)talloc_reference(level5, level3); + + talloc_set_destructor(level5, _test_talloc_free_in_destructor); + + talloc_free(level1); + + talloc_free(level0); + + talloc_free(level3); /* make ASAN happy */ + + printf("success: free_in_destructor\n"); + return true; +} + +static bool test_autofree(void) +{ +#if _SAMBA_BUILD_ < 4 + /* autofree test would kill smbtorture */ + void *p; + printf("test: autofree\n# TALLOC AUTOFREE CONTEXT\n"); + + p = talloc_autofree_context(); + talloc_free(p); + + p = talloc_autofree_context(); + talloc_free(p); + + printf("success: autofree\n"); +#endif + return true; +} + +static bool test_pool(void) +{ + void *pool; + void *p1, *p2, *p3, *p4; + void *p2_2; + + pool = talloc_pool(NULL, 1024); + + p1 = talloc_size(pool, 80); + memset(p1, 0x11, talloc_get_size(p1)); + p2 = talloc_size(pool, 20); + memset(p2, 0x11, talloc_get_size(p2)); + p3 = talloc_size(p1, 50); + memset(p3, 0x11, talloc_get_size(p3)); + p4 = talloc_size(p3, 1000); + memset(p4, 0x11, talloc_get_size(p4)); + + p2_2 = talloc_realloc_size(pool, p2, 20+1); + torture_assert("pool realloc 20+1", p2_2 == p2, "failed: pointer changed"); + memset(p2, 0x11, talloc_get_size(p2)); + p2_2 = talloc_realloc_size(pool, p2, 20-1); + torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed"); + memset(p2, 0x11, talloc_get_size(p2)); + p2_2 = talloc_realloc_size(pool, p2, 20-1); + torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed"); + memset(p2, 0x11, talloc_get_size(p2)); + + talloc_free(p3); + + /* this should reclaim the memory of p4 and p3 */ + p2_2 = talloc_realloc_size(pool, p2, 400); + torture_assert("pool realloc 400", p2_2 == p2, "failed: pointer changed"); + memset(p2, 0x11, talloc_get_size(p2)); + + talloc_free(p1); + + /* this should reclaim the memory of p1 */ + p2_2 = talloc_realloc_size(pool, p2, 800); + torture_assert("pool realloc 800", p2_2 == p1, "failed: pointer not changed"); + p2 = p2_2; + memset(p2, 0x11, talloc_get_size(p2)); + + /* this should do a malloc */ + p2_2 = talloc_realloc_size(pool, p2, 1800); + torture_assert("pool realloc 1800", p2_2 != p2, "failed: pointer not changed"); + p2 = p2_2; + memset(p2, 0x11, talloc_get_size(p2)); + + /* this should reclaim the memory from the pool */ + p3 = talloc_size(pool, 80); + torture_assert("pool alloc 80", p3 == p1, "failed: pointer changed"); + memset(p3, 0x11, talloc_get_size(p3)); + + talloc_free(p2); + talloc_free(p3); + + p1 = talloc_size(pool, 80); + memset(p1, 0x11, talloc_get_size(p1)); + p2 = talloc_size(pool, 20); + memset(p2, 0x11, talloc_get_size(p2)); + + talloc_free(p1); + + p2_2 = talloc_realloc_size(pool, p2, 20-1); + torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed"); + memset(p2, 0x11, talloc_get_size(p2)); + p2_2 = talloc_realloc_size(pool, p2, 20-1); + torture_assert("pool realloc 20-1", p2_2 == p2, "failed: pointer changed"); + memset(p2, 0x11, talloc_get_size(p2)); + + /* this should do a malloc */ + p2_2 = talloc_realloc_size(pool, p2, 1800); + torture_assert("pool realloc 1800", p2_2 != p2, "failed: pointer not changed"); + p2 = p2_2; + memset(p2, 0x11, talloc_get_size(p2)); + + /* this should reclaim the memory from the pool */ + p3 = talloc_size(pool, 800); + torture_assert("pool alloc 800", p3 == p1, "failed: pointer changed"); + memset(p3, 0x11, talloc_get_size(p3)); + + talloc_free(pool); + + return true; +} + +static bool test_pool_steal(void) +{ + void *root; + void *pool; + void *p1, *p2; + void *p1_2, *p2_2; + size_t hdr; + size_t ofs1, ofs2; + + root = talloc_new(NULL); + pool = talloc_pool(root, 1024); + + p1 = talloc_size(pool, 4 * 16); + torture_assert("pool allocate 4 * 16", p1 != NULL, "failed "); + memset(p1, 0x11, talloc_get_size(p1)); + p2 = talloc_size(pool, 4 * 16); + torture_assert("pool allocate 4 * 16", p2 > p1, "failed: !(p2 > p1) "); + memset(p2, 0x11, talloc_get_size(p2)); + + ofs1 = PTR_DIFF(p2, p1); + hdr = ofs1 - talloc_get_size(p1); + + talloc_steal(root, p1); + talloc_steal(root, p2); + + talloc_free(pool); + + p1_2 = p1; + + p1_2 = talloc_realloc_size(root, p1, 5 * 16); + torture_assert("pool realloc 5 * 16", p1_2 > p2, "failed: pointer not changed"); + memset(p1_2, 0x11, talloc_get_size(p1_2)); + ofs1 = PTR_DIFF(p1_2, p2); + ofs2 = talloc_get_size(p2) + hdr; + + torture_assert("pool realloc ", ofs1 == ofs2, "failed: pointer offset unexpected"); + + p2_2 = talloc_realloc_size(root, p2, 3 * 16); + torture_assert("pool realloc 5 * 16", p2_2 == p2, "failed: pointer changed"); + memset(p2_2, 0x11, talloc_get_size(p2_2)); + + talloc_free(p1_2); + + p2_2 = p2; + + /* now we should reclaim the full pool */ + p2_2 = talloc_realloc_size(root, p2, 8 * 16); + torture_assert("pool realloc 8 * 16", p2_2 == p1, "failed: pointer not expected"); + p2 = p2_2; + memset(p2_2, 0x11, talloc_get_size(p2_2)); + + /* now we malloc and free the full pool space */ + p2_2 = talloc_realloc_size(root, p2, 2 * 1024); + torture_assert("pool realloc 2 * 1024", p2_2 != p1, "failed: pointer not expected"); + memset(p2_2, 0x11, talloc_get_size(p2_2)); + + talloc_free(p2_2); + + talloc_free(root); + + return true; +} + +static bool test_pool_nest(void) +{ + void *p1, *p2, *p3; + void *e = talloc_new(NULL); + + p1 = talloc_pool(NULL, 1024); + torture_assert("talloc_pool", p1 != NULL, "failed"); + + p2 = talloc_pool(p1, 500); + torture_assert("talloc_pool", p2 != NULL, "failed"); + + p3 = talloc_size(p2, 10); + + talloc_steal(e, p3); + + talloc_free(p2); + + talloc_free(p3); + + talloc_free(p1); + + talloc_free(e); /* make ASAN happy */ + + return true; +} + +struct pooled { + char *s1; + char *s2; + char *s3; +}; + +static bool test_pooled_object(void) +{ + struct pooled *p; + const char *s1 = "hello"; + const char *s2 = "world"; + const char *s3 = ""; + + p = talloc_pooled_object(NULL, struct pooled, 3, + strlen(s1)+strlen(s2)+strlen(s3)+3); + + if (talloc_get_size(p) != sizeof(struct pooled)) { + return false; + } + + p->s1 = talloc_strdup(p, s1); + + TALLOC_FREE(p->s1); + p->s1 = talloc_strdup(p, s2); + TALLOC_FREE(p->s1); + + p->s1 = talloc_strdup(p, s1); + p->s2 = talloc_strdup(p, s2); + p->s3 = talloc_strdup(p, s3); + + TALLOC_FREE(p); + return true; +} + +static bool test_free_ref_null_context(void) +{ + void *p1, *p2, *p3; + int ret; + + talloc_disable_null_tracking(); + p1 = talloc_new(NULL); + p2 = talloc_new(NULL); + + p3 = talloc_reference(p2, p1); + torture_assert("reference", p3 == p1, "failed: reference on null"); + + ret = talloc_free(p1); + torture_assert("ref free with null parent", ret == 0, "failed: free with null parent"); + talloc_free(p2); + + talloc_enable_null_tracking_no_autofree(); + p1 = talloc_new(NULL); + p2 = talloc_new(NULL); + + p3 = talloc_reference(p2, p1); + torture_assert("reference", p3 == p1, "failed: reference on null"); + + ret = talloc_free(p1); + torture_assert("ref free with null tracked parent", ret == 0, "failed: free with null parent"); + talloc_free(p2); + + return true; +} + +static bool test_rusty(void) +{ + void *root; + char *p1; + + talloc_enable_null_tracking(); + root = talloc_new(NULL); + p1 = talloc_strdup(root, "foo"); + talloc_increase_ref_count(p1); + talloc_report_full(root, stdout); + talloc_free(root); + CHECK_BLOCKS("null_context", NULL, 2); + talloc_free(p1); /* make ASAN happy */ + + return true; +} + +static bool test_free_children(void) +{ + void *root; + char *p1, *p2; + const char *name, *name2; + + talloc_enable_null_tracking(); + root = talloc_new(NULL); + p1 = talloc_strdup(root, "foo1"); + p2 = talloc_strdup(p1, "foo2"); + (void)p2; + + talloc_set_name(p1, "%s", "testname"); + talloc_free_children(p1); + /* check its still a valid talloc ptr */ + talloc_get_size(talloc_get_name(p1)); + if (strcmp(talloc_get_name(p1), "testname") != 0) { + return false; + } + + talloc_set_name(p1, "%s", "testname"); + name = talloc_get_name(p1); + talloc_free_children(p1); + /* check its still a valid talloc ptr */ + talloc_get_size(talloc_get_name(p1)); + torture_assert("name", name == talloc_get_name(p1), "name ptr changed"); + torture_assert("namecheck", strcmp(talloc_get_name(p1), "testname") == 0, + "wrong name"); + CHECK_BLOCKS("name1", p1, 2); + + /* note that this does not free the old child name */ + talloc_set_name_const(p1, "testname2"); + name2 = talloc_get_name(p1); + /* but this does */ + talloc_free_children(p1); + (void)name2; + torture_assert("namecheck", strcmp(talloc_get_name(p1), "testname2") == 0, + "wrong name"); + CHECK_BLOCKS("name1", p1, 1); + + talloc_report_full(root, stdout); + talloc_free(root); + return true; +} + +static bool test_memlimit(void) +{ + void *root; + char *l1, *l2, *l3, *l4, *l5, *t; + char *pool; + int i; + + printf("test: memlimit\n# MEMORY LIMITS\n"); + + printf("==== talloc_new(NULL)\n"); + root = talloc_new(NULL); + + talloc_report_full(root, stdout); + + printf("==== talloc_size(root, 2048)\n"); + l1 = talloc_size(root, 2048); + torture_assert("memlimit", l1 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_free(l1)\n"); + talloc_free(l1); + + talloc_report_full(root, stdout); + + printf("==== talloc_strdup(root, level 1)\n"); + l1 = talloc_strdup(root, "level 1"); + torture_assert("memlimit", l1 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_set_memlimit(l1, 2048)\n"); + torture_assert("memlimit", talloc_set_memlimit(l1, 2048) == 0, + "failed: setting memlimit should never fail\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_size(root, 2048)\n"); + l2 = talloc_size(l1, 2048); + torture_assert("memlimit", l2 == NULL, + "failed: alloc should fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_strdup(l1, level 2)\n"); + l2 = talloc_strdup(l1, "level 2"); + torture_assert("memlimit", l2 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_free(l2)\n"); + talloc_free(l2); + + talloc_report_full(root, stdout); + + printf("==== talloc_size(NULL, 2048)\n"); + l2 = talloc_size(NULL, 2048); + + talloc_report_full(root, stdout); + + printf("==== talloc_steal(l1, l2)\n"); + talloc_steal(l1, l2); + + talloc_report_full(root, stdout); + + printf("==== talloc_strdup(l2, level 3)\n"); + l3 = talloc_strdup(l2, "level 3"); + torture_assert("memlimit", l3 == NULL, + "failed: alloc should fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_free(l2)\n"); + talloc_free(l2); + + talloc_report_full(root, stdout); + + printf("==== talloc_strdup(NULL, level 2)\n"); + l2 = talloc_strdup(NULL, "level 2"); + talloc_steal(l1, l2); + + talloc_report_full(root, stdout); + + printf("==== talloc_strdup(l2, level 3)\n"); + l3 = talloc_strdup(l2, "level 3"); + torture_assert("memlimit", l3 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_set_memlimit(l3, 1024)\n"); + torture_assert("memlimit", talloc_set_memlimit(l3, 1024) == 0, + "failed: setting memlimit should never fail\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_strdup(l3, level 4)\n"); + l4 = talloc_strdup(l3, "level 4"); + torture_assert("memlimit", l4 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_set_memlimit(l4, 512)\n"); + torture_assert("memlimit", talloc_set_memlimit(l4, 512) == 0, + "failed: setting memlimit should never fail\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_strdup(l4, level 5)\n"); + l5 = talloc_strdup(l4, "level 5"); + torture_assert("memlimit", l5 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_realloc(NULL, l5, char, 600)\n"); + t = talloc_realloc(NULL, l5, char, 600); + torture_assert("memlimit", t == NULL, + "failed: alloc should fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_realloc(NULL, l5, char, 5)\n"); + l5 = talloc_realloc(NULL, l5, char, 5); + torture_assert("memlimit", l5 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_strdup(l3, level 4)\n"); + l4 = talloc_strdup(l3, "level 4"); + torture_assert("memlimit", l4 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_set_memlimit(l4, 512)\n"); + torture_assert("memlimit", talloc_set_memlimit(l4, 512) == 0, + "failed: setting memlimit should never fail\n"); + + talloc_report_full(root, stdout); + + printf("==== talloc_strdup(l4, level 5)\n"); + l5 = talloc_strdup(l4, "level 5"); + torture_assert("memlimit", l5 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + + printf("==== Make new temp context and steal l5\n"); + t = talloc_new(root); + talloc_steal(t, l5); + + talloc_report_full(root, stdout); + + printf("==== talloc_size(t, 2048)\n"); + l1 = talloc_size(t, 2048); + torture_assert("memlimit", l1 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(root, stdout); + talloc_free(root); + + /* Test memlimits with pools. */ + printf("==== talloc_pool(NULL, 10*1024)\n"); + pool = talloc_pool(NULL, 10*1024); + torture_assert("memlimit", pool != NULL, + "failed: alloc should not fail due to memory limit\n"); + + printf("==== talloc_set_memlimit(pool, 10*1024)\n"); + talloc_set_memlimit(pool, 10*1024); + for (i = 0; i < 9; i++) { + printf("==== talloc_size(pool, 1024) %i/10\n", i + 1); + l1 = talloc_size(pool, 1024); + torture_assert("memlimit", l1 != NULL, + "failed: alloc should not fail due to memory limit\n"); + talloc_report_full(pool, stdout); + } + /* The next alloc should fail. */ + printf("==== talloc_size(pool, 1024) 10/10\n"); + l2 = talloc_size(pool, 1024); + torture_assert("memlimit", l2 == NULL, + "failed: alloc should fail due to memory limit\n"); + + talloc_report_full(pool, stdout); + + /* Moving one of the children shouldn't change the limit, + as it's still inside the pool. */ + + printf("==== talloc_new(NULL)\n"); + root = talloc_new(NULL); + + printf("==== talloc_steal(root, l1)\n"); + talloc_steal(root, l1); + + printf("==== talloc_size(pool, 1024)\n"); + l2 = talloc_size(pool, 1024); + torture_assert("memlimit", l2 == NULL, + "failed: alloc should fail due to memory limit\n"); + + printf("==== talloc_free_children(pool)\n"); + talloc_free(l1); + talloc_free_children(pool); + + printf("==== talloc_size(pool, 1024)\n"); + l1 = talloc_size(pool, 1024); + + /* try reallocs of increasing size */ + for (i = 1; i < 9; i++) { + printf("==== talloc_realloc_size(NULL, l1, %i*1024) %i/10\n", i, i + 1); + l1 = talloc_realloc_size(NULL, l1, i*1024); + torture_assert("memlimit", l1 != NULL, + "failed: realloc should not fail due to memory limit\n"); + talloc_report_full(pool, stdout); + } + /* The next alloc should fail. */ + printf("==== talloc_realloc_size(NULL, l1, 10*1024) 10/10\n"); + l2 = talloc_realloc_size(NULL, l1, 10*1024); + torture_assert("memlimit", l2 == NULL, + "failed: realloc should fail due to memory limit\n"); + + /* Increase the memlimit */ + printf("==== talloc_set_memlimit(pool, 11*1024)\n"); + talloc_set_memlimit(pool, 11*1024); + + /* The final realloc should still fail + as the entire realloced chunk needs to be moved out of the pool */ + printf("==== talloc_realloc_size(NULL, l1, 10*1024) 10/10\n"); + l2 = talloc_realloc_size(NULL, l1, 10*1024); + torture_assert("memlimit", l2 == NULL, + "failed: realloc should fail due to memory limit\n"); + + talloc_report_full(pool, stdout); + + printf("==== talloc_set_memlimit(pool, 21*1024)\n"); + talloc_set_memlimit(pool, 21*1024); + + /* There's now sufficient space to move the chunk out of the pool */ + printf("==== talloc_realloc_size(NULL, l1, 10*1024) 10/10\n"); + l2 = talloc_realloc_size(NULL, l1, 10*1024); + torture_assert("memlimit", l2 != NULL, + "failed: realloc should not fail due to memory limit\n"); + + talloc_report_full(pool, stdout); + + /* ...which should mean smaller allocations can now occur within the pool */ + printf("==== talloc_size(pool, 9*1024)\n"); + l1 = talloc_size(pool, 9*1024); + torture_assert("memlimit", l1 != NULL, + "failed: new allocations should be allowed in the pool\n"); + + talloc_report_full(pool, stdout); + + /* But reallocs bigger than the pool will still fail */ + printf("==== talloc_realloc_size(NULL, l1, 10*1024)\n"); + l2 = talloc_realloc_size(NULL, l1, 10*1024); + torture_assert("memlimit", l2 == NULL, + "failed: realloc should fail due to memory limit\n"); + + talloc_report_full(pool, stdout); + + /* ..as well as allocs */ + printf("==== talloc_size(pool, 1024)\n"); + l1 = talloc_size(pool, 1024); + torture_assert("memlimit", l1 == NULL, + "failed: alloc should fail due to memory limit\n"); + + talloc_report_full(pool, stdout); + + printf("==== talloc_free_children(pool)\n"); + talloc_free_children(pool); + + printf("==== talloc_set_memlimit(pool, 1024)\n"); + talloc_set_memlimit(pool, 1024); + + /* We should still be able to allocate up to the pool limit + because the memlimit only applies to new heap allocations */ + printf("==== talloc_size(pool, 9*1024)\n"); + l1 = talloc_size(pool, 9*1024); + torture_assert("memlimit", l1 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(pool, stdout); + + l1 = talloc_size(pool, 1024); + torture_assert("memlimit", l1 == NULL, + "failed: alloc should fail due to memory limit\n"); + + talloc_report_full(pool, stdout); + + printf("==== talloc_free_children(pool)\n"); + talloc_free_children(pool); + + printf("==== talloc_set_memlimit(pool, 10*1024)\n"); + talloc_set_memlimit(pool, 10*1024); + + printf("==== talloc_size(pool, 1024)\n"); + l1 = talloc_size(pool, 1024); + torture_assert("memlimit", l1 != NULL, + "failed: alloc should not fail due to memory limit\n"); + + talloc_report_full(pool, stdout); + + talloc_free(pool); + talloc_free(root); + printf("success: memlimit\n"); + + return true; +} + +#ifdef HAVE_PTHREAD + +#define NUM_THREADS 100 + +/* Sync variables. */ +static pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER; +static pthread_cond_t condvar = PTHREAD_COND_INITIALIZER; +static void *intermediate_ptr; + +/* Subthread. */ +static void *thread_fn(void *arg) +{ + int ret; + const char *ctx_name = (const char *)arg; + void *sub_ctx = NULL; + /* + * Do stuff that creates a new talloc hierarchy in + * this thread. + */ + void *top_ctx = talloc_named_const(NULL, 0, "top"); + if (top_ctx == NULL) { + return NULL; + } + sub_ctx = talloc_named_const(top_ctx, 100, ctx_name); + if (sub_ctx == NULL) { + return NULL; + } + + /* + * Now transfer a pointer from our hierarchy + * onto the intermediate ptr. + */ + ret = pthread_mutex_lock(&mtx); + if (ret != 0) { + talloc_free(top_ctx); + return NULL; + } + /* Wait for intermediate_ptr to be free. */ + while (intermediate_ptr != NULL) { + ret = pthread_cond_wait(&condvar, &mtx); + if (ret != 0) { + talloc_free(top_ctx); + ret = pthread_mutex_unlock(&mtx); + assert(ret == 0); + return NULL; + } + } + + /* and move our memory onto it from our toplevel hierarchy. */ + intermediate_ptr = talloc_move(NULL, &sub_ctx); + + /* Tell the main thread it's ready for pickup. */ + pthread_cond_broadcast(&condvar); + ret = pthread_mutex_unlock(&mtx); + assert(ret == 0); + + talloc_free(top_ctx); + return NULL; +} + +/* Main thread. */ +static bool test_pthread_talloc_passing(void) +{ + int i; + int ret; + char str_array[NUM_THREADS][20]; + pthread_t thread_id; + void *mem_ctx; + + /* + * Important ! Null tracking breaks threaded talloc. + * It *must* be turned off. + */ + talloc_disable_null_tracking(); + + printf("test: pthread_talloc_passing\n# PTHREAD TALLOC PASSING\n"); + + /* Main thread toplevel context. */ + mem_ctx = talloc_named_const(NULL, 0, "toplevel"); + if (mem_ctx == NULL) { + printf("failed to create toplevel context\n"); + return false; + } + + /* + * Spin off NUM_THREADS threads. + * They will use their own toplevel contexts. + */ + for (i = 0; i < NUM_THREADS; i++) { + ret = snprintf(str_array[i], + 20, + "thread:%d", + i); + if (ret < 0) { + printf("snprintf %d failed\n", i); + return false; + } + ret = pthread_create(&thread_id, + NULL, + thread_fn, + str_array[i]); + if (ret != 0) { + printf("failed to create thread %d (%d)\n", i, ret); + return false; + } + } + + printf("Created %d threads\n", NUM_THREADS); + + /* Now wait for NUM_THREADS transfers of the talloc'ed memory. */ + for (i = 0; i < NUM_THREADS; i++) { + ret = pthread_mutex_lock(&mtx); + if (ret != 0) { + printf("pthread_mutex_lock %d failed (%d)\n", i, ret); + talloc_free(mem_ctx); + return false; + } + + /* Wait for intermediate_ptr to have our data. */ + while (intermediate_ptr == NULL) { + ret = pthread_cond_wait(&condvar, &mtx); + if (ret != 0) { + printf("pthread_cond_wait %d failed (%d)\n", i, + ret); + talloc_free(mem_ctx); + ret = pthread_mutex_unlock(&mtx); + assert(ret == 0); + } + } + + /* and move it onto our toplevel hierarchy. */ + (void)talloc_move(mem_ctx, &intermediate_ptr); + + /* Tell the sub-threads we're ready for another. */ + pthread_cond_broadcast(&condvar); + ret = pthread_mutex_unlock(&mtx); + assert(ret == 0); + } + + CHECK_SIZE("pthread_talloc_passing", mem_ctx, NUM_THREADS * 100); +#if 1 + /* Dump the hierarchy. */ + talloc_report(mem_ctx, stdout); +#endif + talloc_free(mem_ctx); + printf("success: pthread_talloc_passing\n"); + return true; +} +#endif + +static void test_magic_protection_abort(const char *reason) +{ + /* exit with errcode 42 to communicate successful test to the parent process */ + if (strcmp(reason, "Bad talloc magic value - unknown value") == 0) { + _exit(42); + } else { + printf("talloc aborted for an unexpected reason\n"); + } +} + +static int test_magic_protection_destructor(int *ptr) +{ + _exit(404); /* Not 42 */ +} + +static bool test_magic_protection(void) +{ + void *pool = talloc_pool(NULL, 1024); + int *p1, *p2; + pid_t pid; + int exit_status; + + printf("test: magic_protection\n"); + p1 = talloc(pool, int); + p2 = talloc(pool, int); + + /* To avoid complaints from the compiler assign values to the p1 & p2. */ + *p1 = 6; + *p2 = 9; + + pid = fork(); + if (pid == 0) { + talloc_set_abort_fn(test_magic_protection_abort); + talloc_set_destructor(p2, test_magic_protection_destructor); + + /* + * Simulate a security attack + * by triggering a buffer overflow in memset to overwrite the + * constructor in the next pool chunk. + * + * Real attacks would attempt to set a real destructor. + */ + memset(p1, '\0', 32); + + /* Then the attack takes effect when the memory's freed. */ + talloc_free(pool); + + /* Never reached. Make compilers happy */ + return true; + } + + while (wait(&exit_status) != pid); + + talloc_free(pool); /* make ASAN happy */ + + if (!WIFEXITED(exit_status)) { + printf("Child exited through unexpected abnormal means\n"); + return false; + } + if (WEXITSTATUS(exit_status) != 42) { + printf("Child exited with wrong exit status\n"); + return false; + } + if (WIFSIGNALED(exit_status)) { + printf("Child received unexpected signal\n"); + return false; + } + + printf("success: magic_protection\n"); + return true; +} + +static void test_magic_free_protection_abort(const char *reason) +{ + /* exit with errcode 42 to communicate successful test to the parent process */ + if (strcmp(reason, "Bad talloc magic value - access after free") == 0) { + _exit(42); + } + /* not 42 */ + _exit(404); +} + +static bool test_magic_free_protection(void) +{ + void *pool = talloc_pool(NULL, 1024); + int *p1, *p2, *p3; + pid_t pid; + int exit_status; + + printf("test: magic_free_protection\n"); + p1 = talloc(pool, int); + p2 = talloc(pool, int); + + /* To avoid complaints from the compiler assign values to the p1 & p2. */ + *p1 = 6; + *p2 = 9; + + p3 = talloc_realloc(pool, p2, int, 2048); + torture_assert("pool realloc 2048", + p3 != p2, + "failed: pointer not changed"); + + /* + * Now access the memory in the pool after the realloc(). It + * should be marked as free, so use of the old pointer should + * trigger the abort function + */ + pid = fork(); + if (pid == 0) { + talloc_set_abort_fn(test_magic_free_protection_abort); + + talloc_get_name(p2); + + /* Never reached. Make compilers happy */ + return true; + } + + while (wait(&exit_status) != pid); + + if (!WIFEXITED(exit_status)) { + printf("Child exited through unexpected abnormal means\n"); + return false; + } + if (WEXITSTATUS(exit_status) != 42) { + printf("Child exited with wrong exit status\n"); + return false; + } + if (WIFSIGNALED(exit_status)) { + printf("Child received unexpected signal\n"); + return false; + } + + talloc_free(pool); + + printf("success: magic_free_protection\n"); + return true; +} + +static void test_reset(void) +{ + talloc_set_log_fn(test_log_stdout); + test_abort_stop(); + talloc_disable_null_tracking(); + talloc_enable_null_tracking_no_autofree(); +} + +bool torture_local_talloc(struct torture_context *tctx) +{ + bool ret = true; + + setlinebuf(stdout); + + test_reset(); + ret &= test_pooled_object(); + test_reset(); + ret &= test_pool_nest(); + test_reset(); + ret &= test_ref1(); + test_reset(); + ret &= test_ref2(); + test_reset(); + ret &= test_ref3(); + test_reset(); + ret &= test_ref4(); + test_reset(); + ret &= test_unlink1(); + test_reset(); + ret &= test_misc(); + test_reset(); + ret &= test_realloc(); + test_reset(); + ret &= test_realloc_child(); + test_reset(); + ret &= test_steal(); + test_reset(); + ret &= test_move(); + test_reset(); + ret &= test_unref_reparent(); + test_reset(); + ret &= test_realloc_fn(); + test_reset(); + ret &= test_type(); + test_reset(); + ret &= test_lifeless(); + test_reset(); + ret &= test_loop(); + test_reset(); + ret &= test_free_parent_deny_child(); + test_reset(); + ret &= test_realloc_on_destructor_parent(); + test_reset(); + ret &= test_free_parent_reparent_child(); + test_reset(); + ret &= test_free_parent_reparent_child_in_pool(); + test_reset(); + ret &= test_talloc_ptrtype(); + test_reset(); + ret &= test_talloc_free_in_destructor(); + test_reset(); + ret &= test_pool(); + test_reset(); + ret &= test_pool_steal(); + test_reset(); + ret &= test_free_ref_null_context(); + test_reset(); + ret &= test_rusty(); + test_reset(); + ret &= test_free_children(); + test_reset(); + ret &= test_memlimit(); +#ifdef HAVE_PTHREAD + test_reset(); + ret &= test_pthread_talloc_passing(); +#endif + + + if (ret) { + test_reset(); + ret &= test_speed(); + } + test_reset(); + ret &= test_autofree(); + test_reset(); + ret &= test_magic_protection(); + test_reset(); + ret &= test_magic_free_protection(); + + test_reset(); + talloc_disable_null_tracking(); + return ret; +} diff --git a/lib/talloc/testsuite_main.c b/lib/talloc/testsuite_main.c new file mode 100644 index 0000000..50ce0f8 --- /dev/null +++ b/lib/talloc/testsuite_main.c @@ -0,0 +1,36 @@ +/* + Unix SMB/CIFS implementation. + + local testing of talloc routines. + + Copyright (C) Andrew Tridgell 2004 + + ** NOTE! The following LGPL license applies to the talloc + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see <http://www.gnu.org/licenses/>. +*/ + +#include "replace.h" + +#include "talloc_testsuite.h" + +int main(void) +{ + bool ret = torture_local_talloc(NULL); + if (!ret) + return -1; + return 0; +} diff --git a/lib/talloc/web/index.html b/lib/talloc/web/index.html new file mode 100644 index 0000000..388ec2c --- /dev/null +++ b/lib/talloc/web/index.html @@ -0,0 +1,51 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN"> +<HTML> +<HEAD> +<TITLE>talloc</TITLE> +</HEAD> +<BODY BGCOLOR="#ffffff" TEXT="#000000" VLINK="#292555" LINK="#292555" ALINK="#cc0033"> + +<h1>talloc</h1> + +talloc is a hierarchical pool based memory allocator with +destructors. It is the core memory allocator used in Samba, and has +made a huge difference in many aspects of Samba4 development.<p> + +To get started with talloc, I would recommend you read the <a +href="http://samba.org/ftp/unpacked/talloc/talloc_guide.txt">talloc guide</a>. + +<h2>Download</h2> +You can download the latest releases of talloc from the <a +href="http://samba.org/ftp/talloc">talloc directory</a> on the samba public +source archive. + +<h2>Discussion and bug reports</h2> + +talloc does not currently have its own mailing list or bug tracking +system. For now, please use the <a +href="https://lists.samba.org/mailman/listinfo/samba-technical">samba-technical</a> +mailing list, and the <a href="http://bugzilla.samba.org/">Samba +bugzilla</a> bug tracking system. + +<h2>Development</h2> + +You can download the latest code either via git or rsync.<br> +<br> +To fetch via git see the following guide:<br> +<a href="http://wiki.samba.org/index.php/Using_Git_for_Samba_Development">Using Git for Samba Development</a><br> +Once you have cloned the tree switch to the master branch and cd into the lib/talloc directory.<br> +<br> +To fetch via rsync use this command: + +<pre> + rsync -Pavz samba.org::ftp/unpacked/standalone_projects/lib/talloc . +</pre> + +<hr> +<tiny> +<a href="http://samba.org/~tridge/">Andrew Tridgell</a><br> +talloc AT tridgell.net +</tiny> + +</BODY> +</HTML> diff --git a/lib/talloc/wscript b/lib/talloc/wscript new file mode 100644 index 0000000..1c54a7c --- /dev/null +++ b/lib/talloc/wscript @@ -0,0 +1,199 @@ +#!/usr/bin/env python + +APPNAME = 'talloc' +VERSION = '2.4.0' + +import os +import sys + +# find the buildtools directory +top = '.' +while not os.path.exists(top+'/buildtools') and len(top.split('/')) < 5: + top = top + '/..' +sys.path.insert(0, top + '/buildtools/wafsamba') + +out = 'bin' + +import wafsamba +from wafsamba import samba_dist, samba_utils +from waflib import Logs, Options, Context + +# setup what directories to put in a tarball +samba_dist.DIST_DIRS("""lib/talloc:. lib/replace:lib/replace +buildtools:buildtools third_party/waf:third_party/waf""") + + +def options(opt): + opt.BUILTIN_DEFAULT('replace') + opt.PRIVATE_EXTENSION_DEFAULT('talloc', noextension='talloc') + opt.RECURSE('lib/replace') + if opt.IN_LAUNCH_DIR(): + opt.add_option('--enable-talloc-compat1', + help=("Build talloc 1.x.x compat library [False]"), + action="store_true", dest='TALLOC_COMPAT1', default=False) + + +def configure(conf): + conf.RECURSE('lib/replace') + + conf.env.standalone_talloc = conf.IN_LAUNCH_DIR() + + conf.define('TALLOC_BUILD_VERSION_MAJOR', int(VERSION.split('.')[0])) + conf.define('TALLOC_BUILD_VERSION_MINOR', int(VERSION.split('.')[1])) + conf.define('TALLOC_BUILD_VERSION_RELEASE', int(VERSION.split('.')[2])) + + conf.env.TALLOC_COMPAT1 = False + if conf.env.standalone_talloc: + conf.env.TALLOC_COMPAT1 = Options.options.TALLOC_COMPAT1 + conf.env.PKGCONFIGDIR = '${LIBDIR}/pkgconfig' + conf.env.TALLOC_VERSION = VERSION + + conf.CHECK_XSLTPROC_MANPAGES() + + conf.CHECK_HEADERS('sys/auxv.h') + conf.CHECK_FUNCS('getauxval') + + conf.SAMBA_CONFIG_H() + + conf.SAMBA_CHECK_UNDEFINED_SYMBOL_FLAGS() + + conf.SAMBA_CHECK_PYTHON() + conf.SAMBA_CHECK_PYTHON_HEADERS() + + if not conf.env.standalone_talloc: + if conf.CHECK_BUNDLED_SYSTEM_PKG('talloc', minversion=VERSION, + implied_deps='replace'): + conf.define('USING_SYSTEM_TALLOC', 1) + + if conf.env.disable_python: + using_system_pytalloc_util = False + else: + using_system_pytalloc_util = True + name = 'pytalloc-util' + conf.all_envs['default']['PYTHON_SO_ABI_FLAG'] + if not conf.CHECK_BUNDLED_SYSTEM_PKG(name, minversion=VERSION, + implied_deps='talloc replace'): + using_system_pytalloc_util = False + + if using_system_pytalloc_util: + conf.define('USING_SYSTEM_PYTALLOC_UTIL', 1) + + +def build(bld): + bld.RECURSE('lib/replace') + + if bld.env.standalone_talloc: + private_library = False + + # should we also install the symlink to libtalloc1.so here? + bld.SAMBA_LIBRARY('talloc-compat1-%s' % (VERSION), + 'compat/talloc_compat1.c', + public_deps='talloc', + soname='libtalloc.so.1', + pc_files=[], + public_headers=[], + enabled=bld.env.TALLOC_COMPAT1) + + testsuite_deps = 'talloc' + if bld.CONFIG_SET('HAVE_PTHREAD'): + testsuite_deps += ' pthread' + + bld.SAMBA_BINARY('talloc_testsuite', + 'testsuite_main.c testsuite.c', + testsuite_deps, + install=False) + + bld.SAMBA_BINARY('talloc_test_magic_differs_helper', + 'test_magic_differs_helper.c', + 'talloc', install=False) + + else: + private_library = True + + if not bld.CONFIG_SET('USING_SYSTEM_TALLOC'): + + bld.SAMBA_LIBRARY('talloc', + 'talloc.c', + deps='replace', + provide_builtin_linking=True, + abi_directory='ABI', + abi_match='talloc* _talloc*', + hide_symbols=True, + vnum=VERSION, + public_headers=('' if private_library else 'talloc.h'), + pc_files='talloc.pc', + public_headers_install=not private_library, + private_library=private_library, + manpages='man/talloc.3') + + if not bld.CONFIG_SET('USING_SYSTEM_PYTALLOC_UTIL'): + name = bld.pyembed_libname('pytalloc-util') + + bld.SAMBA_LIBRARY(name, + source='pytalloc_util.c', + public_deps='talloc', + pyembed=True, + vnum=VERSION, + hide_symbols=True, + abi_directory='ABI', + abi_match='pytalloc_* _pytalloc_*', + private_library=private_library, + public_headers=('' if private_library else 'pytalloc.h'), + pc_files='pytalloc-util.pc', + enabled=bld.PYTHON_BUILD_IS_ENABLED() + ) + bld.SAMBA_PYTHON('pytalloc', + 'pytalloc.c', + deps='talloc ' + name, + enabled=bld.PYTHON_BUILD_IS_ENABLED(), + realname='talloc.so') + + bld.SAMBA_PYTHON('test_pytalloc', + 'test_pytalloc.c', + deps=name, + enabled=bld.PYTHON_BUILD_IS_ENABLED(), + realname='_test_pytalloc.so', + install=False) + + +def testonly(ctx): + '''run talloc testsuite''' + import samba_utils + + samba_utils.ADD_LD_LIBRARY_PATH('bin/shared') + samba_utils.ADD_LD_LIBRARY_PATH('bin/shared/private') + + cmd = os.path.join(Context.g_module.out, 'talloc_testsuite') + ret = samba_utils.RUN_COMMAND(cmd) + print("testsuite returned %d" % ret) + magic_helper_cmd = os.path.join(Context.g_module.out, 'talloc_test_magic_differs_helper') + magic_cmd = os.path.join(Context.g_module.top, 'lib', 'talloc', + 'test_magic_differs.sh') + if not os.path.exists(magic_cmd): + magic_cmd = os.path.join(Context.g_module.top, 'test_magic_differs.sh') + + magic_ret = samba_utils.RUN_COMMAND(magic_cmd + " " + magic_helper_cmd) + print("magic differs test returned %d" % magic_ret) + pyret = samba_utils.RUN_PYTHON_TESTS(['test_pytalloc.py']) + print("python testsuite returned %d" % pyret) + sys.exit(ret or magic_ret or pyret) + +# WAF doesn't build the unit tests for this, maybe because they don't link with talloc? +# This forces it +def test(ctx): + Options.commands.append('build') + Options.commands.append('testonly') + +def dist(): + '''makes a tarball for distribution''' + samba_dist.dist() + +def reconfigure(ctx): + '''reconfigure if config scripts have changed''' + samba_utils.reconfigure(ctx) + + +def pydoctor(ctx): + '''build python apidocs''' + cmd='PYTHONPATH=bin/python pydoctor --project-name=talloc --project-url=http://talloc.samba.org/ --make-html --docformat=restructuredtext --introspect-c-modules --add-module bin/python/talloc.*' + print("Running: %s" % cmd) + os.system(cmd) |