blob: 6f92b336ae1955c33e902c66ad48fe8607fcb1c5 [file] [log] [blame]
/**
* Copyright (C) ARM Limited 2013-2014. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include "DynBuf.h"
#include <errno.h>
#include <fcntl.h>
#include <stdarg.h>
#include <stdio.h>
#include <unistd.h>
#include "Logging.h"
// Pick an aggressive size as buffer is primarily used for disk IO
#define MIN_BUFFER_FREE (1 << 12)
int DynBuf::resize(const size_t minCapacity) {
size_t scaledCapacity = 2 * capacity;
if (scaledCapacity < minCapacity) {
scaledCapacity = minCapacity;
}
if (scaledCapacity < 2 * MIN_BUFFER_FREE) {
scaledCapacity = 2 * MIN_BUFFER_FREE;
}
capacity = scaledCapacity;
buf = static_cast<char *>(realloc(buf, capacity));
if (buf == NULL) {
return -errno;
}
return 0;
}
bool DynBuf::read(const char *const path) {
int result = false;
const int fd = open(path, O_RDONLY);
if (fd < 0) {
logg->logMessage("%s(%s:%i): open failed", __FUNCTION__, __FILE__, __LINE__);
return false;
}
length = 0;
for (;;) {
const size_t minCapacity = length + MIN_BUFFER_FREE + 1;
if (capacity < minCapacity) {
if (resize(minCapacity) != 0) {
logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
goto fail;
}
}
const ssize_t bytes = ::read(fd, buf + length, capacity - length - 1);
if (bytes < 0) {
logg->logMessage("%s(%s:%i): read failed", __FUNCTION__, __FILE__, __LINE__);
goto fail;
} else if (bytes == 0) {
break;
}
length += bytes;
}
buf[length] = '\0';
result = true;
fail:
close(fd);
return result;
}
int DynBuf::readlink(const char *const path) {
ssize_t bytes = MIN_BUFFER_FREE;
for (;;) {
if (static_cast<size_t>(bytes) >= capacity) {
const int err = resize(2 * bytes);
if (err != 0) {
return err;
}
}
bytes = ::readlink(path, buf, capacity);
if (bytes < 0) {
return -errno;
} else if (static_cast<size_t>(bytes) < capacity) {
break;
}
}
length = bytes;
buf[bytes] = '\0';
return 0;
}
bool DynBuf::printf(const char *format, ...) {
va_list ap;
if (capacity <= 0) {
if (resize(2 * MIN_BUFFER_FREE) != 0) {
logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
return false;
}
}
va_start(ap, format);
int bytes = vsnprintf(buf, capacity, format, ap);
va_end(ap);
if (bytes < 0) {
logg->logMessage("%s(%s:%i): fsnprintf failed", __FUNCTION__, __FILE__, __LINE__);
return false;
}
if (static_cast<size_t>(bytes) > capacity) {
if (resize(bytes + 1) != 0) {
logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
return false;
}
va_start(ap, format);
bytes = vsnprintf(buf, capacity, format, ap);
va_end(ap);
if (bytes < 0) {
logg->logMessage("%s(%s:%i): fsnprintf failed", __FUNCTION__, __FILE__, __LINE__);
return false;
}
}
length = bytes;
return true;
}