Files
s390-tools/dump2tar/src/buffer.c
Michael Holzheu b627b8d8e1 Initial s390-tools-2.0.0 import
This commit is based on the s390-tools-1.39.0 version.

Changes on top of s390-tools-1.39.0:

 - Add MIT license to all source files
 - Add LICENSE file
 - Transform REAMDE to README.md (markdown)
 - Add AUTHORS.md file
 - Add CONTRIBUTING.md file
 - Move changelog from README to CHANGELOG.md file

Reviewed-by: Stefan Haberland <sth@linux.vnet.ibm.com>
Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
2017-08-21 10:55:40 +02:00

274 lines
6.4 KiB
C

/*
* dump2tar - tool to dump files and command output into a tar archive
*
* Data buffering functions
*
* Copyright IBM Corp. 2016, 2017
*
* s390-tools is free software; you can redistribute it and/or modify
* it under the terms of the MIT license. See LICENSE for details.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "buffer.h"
#include "misc.h"
void buffer_print(struct buffer *buffer)
{
fprintf(stderr, "DEBUG: buffer at %p\n", (void *) buffer);
if (!buffer)
return;
fprintf(stderr, "DEBUG: total=%zu\n", buffer->total);
fprintf(stderr, "DEBUG: off=%zu\n", buffer->off);
fprintf(stderr, "DEBUG: size=%zu\n", buffer->size);
fprintf(stderr, "DEBUG: addr=%p\n", (void *) buffer->addr);
fprintf(stderr, "DEBUG: fd_open=%d\n", buffer->fd_open);
fprintf(stderr, "DEBUG: fd=%d\n", buffer->fd);
if (buffer->fd_open) {
fprintf(stderr, "DEBUG: fd->pos=%zu\n",
lseek(buffer->fd, 0, SEEK_CUR));
}
}
/* Initialize @buffer to hold @size bytes in memory */
void buffer_init(struct buffer *buffer, size_t size)
{
memset(buffer, 0, sizeof(struct buffer));
buffer->addr = mmalloc(size);
buffer->size = size;
}
/* Allocate a new buffer for holding @size bytes in memory */
struct buffer *buffer_alloc(size_t size)
{
struct buffer *buffer;
buffer = mmalloc(sizeof(struct buffer));
buffer_init(buffer, size);
return buffer;
}
/* Forget about any data stored in @buffer */
void buffer_reset(struct buffer *buffer)
{
buffer->total = 0;
buffer->off = 0;
if (buffer->fd_open) {
if (ftruncate(buffer->fd, 0))
mwarn("Cannot truncate temporary file");
if (lseek(buffer->fd, 0, SEEK_SET) == (off_t) -1)
mwarn("Cannot seek in temporary file");
}
}
/* Close buffer file associated with @buffer */
void buffer_close(struct buffer *buffer)
{
if (!buffer->fd_open)
return;
fclose(buffer->file);
buffer->fd = 0;
buffer->fd_open = false;
}
/* Release all resources associated with @buffer. If @dyn is %true, also free
* @buffer itself. */
void buffer_free(struct buffer *buffer, bool dyn)
{
if (!buffer)
return;
buffer_reset(buffer);
buffer_close(buffer);
free(buffer->addr);
if (dyn)
free(buffer);
}
/* Open a buffer file for @buffer. Return %EXIT_OK on success, %EXIT_RUNTIME
* otherwise. */
int buffer_open(struct buffer *buffer)
{
if (buffer->fd_open)
return EXIT_OK;
buffer->file = tmpfile();
if (!buffer->file) {
mwarn("Could not create temporary file");
return EXIT_RUNTIME;
}
buffer->fd = fileno(buffer->file);
buffer->fd_open = true;
return EXIT_OK;
}
/* Write data in memory of @buffer to buffer file. Return %EXIT_OK on success,
* %EXIT_RUNTIME otherwise. */
int buffer_flush(struct buffer *buffer)
{
if (buffer->off == 0)
return EXIT_OK;
if (buffer_open(buffer))
return EXIT_RUNTIME;
if (misc_write_data(buffer->fd, buffer->addr, buffer->off)) {
mwarn("Could not write to temporary file");
return EXIT_RUNTIME;
}
buffer->off = 0;
return EXIT_OK;
}
/* Try to ensure that at least @size bytes are available at
* @buffer->addr[buffer->off]. Return the actual number of bytes available or
* @-1 on error. If @usefile is %true, make use of a buffer file if
* the total buffer size exceeds @max_buffer_size. */
ssize_t buffer_make_room(struct buffer *buffer, size_t size, bool usefile,
size_t max_buffer_size)
{
size_t needsize;
if (size > max_buffer_size && usefile)
size = max_buffer_size;
needsize = buffer->off + size;
if (needsize <= buffer->size) {
/* Room available */
return size;
}
if (needsize > max_buffer_size && usefile) {
/* Need to write out memory buffer to buffer file */
if (buffer_flush(buffer))
return -1;
if (size <= buffer->size)
return size;
needsize = size;
}
/* Need to increase memory buffer size */
buffer->size = needsize;
buffer->addr = mrealloc(buffer->addr, buffer->size);
return size;
}
/* Try to read @chunk bytes from @fd to @buffer. Return the number of bytes
* read on success, %0 on EOF or %-1 on error. */
ssize_t buffer_read_fd(struct buffer *buffer, int fd, size_t chunk,
bool usefile, size_t max_buffer_size)
{
ssize_t c = buffer_make_room(buffer, chunk, usefile, max_buffer_size);
DBG("buffer_read_fd wanted %zd got %zd", chunk, c);
if (c < 0)
return c;
c = read(fd, buffer->addr + buffer->off, c);
if (c > 0) {
buffer->total += c;
buffer->off += c;
}
return c;
}
/* Add @len bytes at @addr to @buffer. If @addr is %NULL, add zeroes. Return
* %EXIT_OK on success, %EXIT_RUNTIME otherwise. */
int buffer_add_data(struct buffer *buffer, char *addr, size_t len, bool usefile,
size_t max_buffer_size)
{
ssize_t c;
while (len > 0) {
c = buffer_make_room(buffer, len, usefile, max_buffer_size);
if (c < 0)
return EXIT_RUNTIME;
if (addr) {
memcpy(buffer->addr + buffer->off, addr, c);
addr += c;
} else {
memset(buffer->addr + buffer->off, 0, c);
}
buffer->total += c;
buffer->off += c;
len -= c;
}
return EXIT_OK;
}
/* Call @cb for all chunks of data in @buffer. @data is passed to @cb. */
int buffer_iterate(struct buffer *buffer, buffer_cb_t cb, void *data)
{
int rc;
ssize_t r;
if (buffer->total == 0)
return EXIT_OK;
if (!buffer->fd_open)
return cb(data, buffer->addr, buffer->off);
/* Free memory buffer to be used as copy buffer */
if (buffer_flush(buffer))
return EXIT_RUNTIME;
if (lseek(buffer->fd, 0, SEEK_SET) == (off_t) -1) {
mwarn("Cannot seek in temporary file");
return EXIT_RUNTIME;
}
/* Copy data from temporary file to target file */
while ((r = misc_read_data(buffer->fd, buffer->addr,
buffer->size)) != 0) {
if (r < 0) {
mwarn("Cannot read from temporary file");
return EXIT_RUNTIME;
}
rc = cb(data, buffer->addr, r);
if (rc)
return rc;
}
return EXIT_OK;
}
/* Truncate @buffer to at most @len bytes */
int buffer_truncate(struct buffer *buffer, size_t len)
{
size_t delta;
if (buffer->total <= len)
return EXIT_OK;
delta = buffer->total - len;
buffer->total = len;
if (buffer->fd_open && delta > buffer->off) {
/* All of memory and some of file buffer is truncated */
buffer->off = 0;
if (ftruncate(buffer->fd, len)) {
mwarn("Cannot truncate temporary file");
return EXIT_RUNTIME;
}
if (lseek(buffer->fd, len, SEEK_SET) == (off_t) -1) {
mwarn("Cannot seek in temporary file");
return EXIT_RUNTIME;
}
} else {
/* Only memory buffer is truncated */
buffer->off -= delta;
}
return EXIT_OK;
}