blob: 690cbcb942933e495f6701cd4b29a1e7cce95789 [file] [log] [blame]
Jon Medhurst15ce78d2014-04-10 09:02:02 +01001/**
Jon Medhurstb1d07442015-05-08 12:04:18 +01002 * Copyright (C) ARM Limited 2013-2015. All rights reserved.
Jon Medhurst15ce78d2014-04-10 09:02:02 +01003 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
7 */
8
9#include "DynBuf.h"
10
11#include <errno.h>
12#include <fcntl.h>
13#include <stdarg.h>
14#include <stdio.h>
15#include <unistd.h>
16
17#include "Logging.h"
18
19// Pick an aggressive size as buffer is primarily used for disk IO
20#define MIN_BUFFER_FREE (1 << 12)
21
22int DynBuf::resize(const size_t minCapacity) {
23 size_t scaledCapacity = 2 * capacity;
24 if (scaledCapacity < minCapacity) {
25 scaledCapacity = minCapacity;
26 }
27 if (scaledCapacity < 2 * MIN_BUFFER_FREE) {
28 scaledCapacity = 2 * MIN_BUFFER_FREE;
29 }
30 capacity = scaledCapacity;
31
32 buf = static_cast<char *>(realloc(buf, capacity));
33 if (buf == NULL) {
34 return -errno;
35 }
36
37 return 0;
38}
39
40bool DynBuf::read(const char *const path) {
41 int result = false;
42
Jon Medhurst96b56152014-10-30 18:01:15 +000043 const int fd = open(path, O_RDONLY | O_CLOEXEC);
Jon Medhurst15ce78d2014-04-10 09:02:02 +010044 if (fd < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010045 logg->logMessage("open failed");
Jon Medhurst15ce78d2014-04-10 09:02:02 +010046 return false;
47 }
48
49 length = 0;
50
51 for (;;) {
52 const size_t minCapacity = length + MIN_BUFFER_FREE + 1;
53 if (capacity < minCapacity) {
54 if (resize(minCapacity) != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010055 logg->logMessage("DynBuf::resize failed");
Jon Medhurst15ce78d2014-04-10 09:02:02 +010056 goto fail;
57 }
58 }
59
60 const ssize_t bytes = ::read(fd, buf + length, capacity - length - 1);
61 if (bytes < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +010062 logg->logMessage("read failed");
Jon Medhurst15ce78d2014-04-10 09:02:02 +010063 goto fail;
64 } else if (bytes == 0) {
65 break;
66 }
67 length += bytes;
68 }
69
70 buf[length] = '\0';
71 result = true;
72
73 fail:
74 close(fd);
75
76 return result;
77}
78
79int DynBuf::readlink(const char *const path) {
80 ssize_t bytes = MIN_BUFFER_FREE;
81
82 for (;;) {
83 if (static_cast<size_t>(bytes) >= capacity) {
84 const int err = resize(2 * bytes);
85 if (err != 0) {
86 return err;
87 }
88 }
89 bytes = ::readlink(path, buf, capacity);
90 if (bytes < 0) {
91 return -errno;
92 } else if (static_cast<size_t>(bytes) < capacity) {
93 break;
94 }
95 }
96
97 length = bytes;
98 buf[bytes] = '\0';
99
100 return 0;
101}
102
103bool DynBuf::printf(const char *format, ...) {
104 va_list ap;
105
106 if (capacity <= 0) {
107 if (resize(2 * MIN_BUFFER_FREE) != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100108 logg->logMessage("DynBuf::resize failed");
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100109 return false;
110 }
111 }
112
113 va_start(ap, format);
114 int bytes = vsnprintf(buf, capacity, format, ap);
115 va_end(ap);
116 if (bytes < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100117 logg->logMessage("fsnprintf failed");
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100118 return false;
119 }
120
121 if (static_cast<size_t>(bytes) > capacity) {
122 if (resize(bytes + 1) != 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100123 logg->logMessage("DynBuf::resize failed");
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100124 return false;
125 }
126
127 va_start(ap, format);
128 bytes = vsnprintf(buf, capacity, format, ap);
129 va_end(ap);
130 if (bytes < 0) {
Jon Medhurstb1d07442015-05-08 12:04:18 +0100131 logg->logMessage("fsnprintf failed");
Jon Medhurst15ce78d2014-04-10 09:02:02 +0100132 return false;
133 }
134 }
135
136 length = bytes;
137
138 return true;
139}