#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
+#ifdef HAVE_MMAP
+# include <sys/mman.h>
+#endif
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
return good;
}
+/**
+ * Described in header.
+ */
+bool chunk_from_fd(int fd, chunk_t *out)
+{
+ struct stat sb;
+ char *buf, *tmp;
+ ssize_t len, total = 0, bufsize;
+
+ if (fstat(fd, &sb) == 0 && S_ISREG(sb.st_mode))
+ {
+ bufsize = sb.st_size;
+ }
+ else
+ {
+ bufsize = 256;
+ }
+ buf = malloc(bufsize);
+ if (!buf)
+ { /* for huge files */
+ return FALSE;
+ }
+
+ while (TRUE)
+ {
+ len = read(fd, buf + total, bufsize - total);
+ if (len < 0)
+ {
+ free(buf);
+ return FALSE;
+ }
+ if (len == 0)
+ {
+ break;
+ }
+ total += len;
+ if (total == bufsize)
+ {
+ bufsize *= 2;
+ tmp = realloc(buf, bufsize);
+ if (!tmp)
+ {
+ free(buf);
+ return FALSE;
+ }
+ buf = tmp;
+ }
+ }
+ if (total == 0)
+ {
+ free(buf);
+ buf = NULL;
+ }
+ else if (total < bufsize)
+ {
+ buf = realloc(buf, total);
+ }
+ *out = chunk_create(buf, total);
+ return TRUE;
+}
+
+/**
+ * Implementation for mmap()ed chunks
+ */
+typedef struct {
+ /* public chunk interface */
+ chunk_t public;
+ /* FD of open file */
+ int fd;
+ /* mmap() address */
+ void *map;
+ /* size of map */
+ size_t len;
+ /* do we write? */
+ bool wr;
+} mmaped_chunk_t;
+
+/**
+ * See header.
+ */
+chunk_t *chunk_map(char *path, bool wr)
+{
+ mmaped_chunk_t *chunk;
+ struct stat sb;
+ int tmp;
+
+ INIT(chunk,
+ .fd = open(path, wr ? O_RDWR : O_RDONLY),
+ .wr = wr,
+ );
+
+ if (chunk->fd == -1)
+ {
+ free(chunk);
+ return NULL;
+ }
+ if (fstat(chunk->fd, &sb) == -1)
+ {
+ tmp = errno;
+ chunk_unmap(&chunk->public);
+ errno = tmp;
+ return NULL;
+ }
+#ifdef HAVE_MMAP
+ chunk->len = sb.st_size;
+ /* map non-empty files only, as mmap() complains otherwise */
+ if (chunk->len)
+ {
+ /* in read-only mode, we allow writes, but don't sync to disk */
+ chunk->map = mmap(NULL, chunk->len, PROT_READ | PROT_WRITE,
+ wr ? MAP_SHARED : MAP_PRIVATE, chunk->fd, 0);
+ if (chunk->map == MAP_FAILED)
+ {
+ tmp = errno;
+ chunk_unmap(&chunk->public);
+ errno = tmp;
+ return NULL;
+ }
+ }
+ chunk->public = chunk_create(chunk->map, chunk->len);
+#else /* !HAVE_MMAP */
+ if (!chunk_from_fd(chunk->fd, &chunk->public))
+ {
+ tmp = errno;
+ chunk_unmap(&chunk->public);
+ errno = tmp;
+ return NULL;
+ }
+ chunk->map = chunk->public.ptr;
+ chunk->len = chunk->public.len;
+#endif /* !HAVE_MMAP */
+ return &chunk->public;
+}
+
+/**
+ * See header.
+ */
+bool chunk_unmap(chunk_t *public)
+{
+ mmaped_chunk_t *chunk;
+ bool ret = FALSE;
+ int tmp = 0;
+
+ chunk = (mmaped_chunk_t*)public;
+#ifdef HAVE_MMAP
+ if (chunk->map && chunk->map != MAP_FAILED)
+ {
+ ret = munmap(chunk->map, chunk->len) == 0;
+ tmp = errno;
+ }
+#else /* !HAVE_MMAP */
+ if (chunk->wr)
+ {
+ if (lseek(chunk->fd, 0, SEEK_SET) != -1)
+ {
+ int len, total = 0;
+
+ ret = TRUE;
+ while (total < chunk->len)
+ {
+ len = write(chunk->fd, chunk->map + total, chunk->len - total);
+ if (len <= 0)
+ {
+ ret = FALSE;
+ break;
+ }
+ total += len;
+ }
+ }
+ tmp = errno;
+ }
+ else
+ {
+ ret = TRUE;
+ }
+ free(chunk->map);
+#endif /* !HAVE_MMAP */
+ close(chunk->fd);
+ free(chunk);
+ errno = tmp;
+
+ return ret;
+}
/** hex conversion digits */
static char hexdig_upper[] = "0123456789ABCDEF";
static u_char key[16];
/**
+ * Static key used in case predictable hash values are required.
+ */
+static u_char static_key[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
+
+/**
* Only allocate the key once
*/
static pthread_once_t key_allocated = PTHREAD_ONCE_INIT;
/**
* Described in header.
*/
+u_int32_t chunk_hash_static_inc(chunk_t chunk, u_int32_t hash)
+{ /* we could use a mac of the previous hash, but this is faster */
+ return chunk_mac_inc(chunk, static_key, ((u_int64_t)hash) << 32 | hash);
+}
+
+/**
+ * Described in header.
+ */
+u_int32_t chunk_hash_static(chunk_t chunk)
+{
+ return chunk_mac(chunk, static_key);
+}
+
+/**
+ * Described in header.
+ */
int chunk_printf_hook(printf_hook_data_t *data, printf_hook_spec_t *spec,
const void *const *args)
{
chunk_t copy = *chunk;
int written = 0;
- if (!spec->hash)
+ if (!spec->hash && !spec->plus)
{
u_int chunk_len = chunk->len;
const void *new_args[] = {&chunk->ptr, &chunk_len};
{
first = FALSE;
}
- else
+ else if (!spec->plus)
{
written += print_in_hook(data, ":");
}