140 lines
3.0 KiB
C++
140 lines
3.0 KiB
C++
/**
|
|
* 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 | O_CLOEXEC);
|
|
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;
|
|
}
|