/** * Copyright (C) ARM Limited 2013-2015. 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 #include #include #include #include #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(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("open failed"); return false; } length = 0; for (;;) { const size_t minCapacity = length + MIN_BUFFER_FREE + 1; if (capacity < minCapacity) { if (resize(minCapacity) != 0) { logg->logMessage("DynBuf::resize failed"); goto fail; } } const ssize_t bytes = ::read(fd, buf + length, capacity - length - 1); if (bytes < 0) { logg->logMessage("read failed"); 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(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(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("DynBuf::resize failed"); return false; } } va_start(ap, format); int bytes = vsnprintf(buf, capacity, format, ap); va_end(ap); if (bytes < 0) { logg->logMessage("fsnprintf failed"); return false; } if (static_cast(bytes) > capacity) { if (resize(bytes + 1) != 0) { logg->logMessage("DynBuf::resize failed"); return false; } va_start(ap, format); bytes = vsnprintf(buf, capacity, format, ap); va_end(ap); if (bytes < 0) { logg->logMessage("fsnprintf failed"); return false; } } length = bytes; return true; }