Merge branch develop-3.10 into develop-3.10-next
[firefly-linux-kernel-4.4.55.git] / tools / gator / daemon / DynBuf.cpp
1 /**
2  * Copyright (C) ARM Limited 2013-2014. All rights reserved.
3  *
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
22 int 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
40 bool DynBuf::read(const char *const path) {
41         int result = false;
42
43         const int fd = open(path, O_RDONLY | O_CLOEXEC);
44         if (fd < 0) {
45                 logg->logMessage("%s(%s:%i): open failed", __FUNCTION__, __FILE__, __LINE__);
46                 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) {
55                                 logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
56                                 goto fail;
57                         }
58                 }
59
60                 const ssize_t bytes = ::read(fd, buf + length, capacity - length - 1);
61                 if (bytes < 0) {
62                         logg->logMessage("%s(%s:%i): read failed", __FUNCTION__, __FILE__, __LINE__);
63                         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
79 int 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
103 bool DynBuf::printf(const char *format, ...) {
104         va_list ap;
105
106         if (capacity <= 0) {
107                 if (resize(2 * MIN_BUFFER_FREE) != 0) {
108                         logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
109                         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) {
117                 logg->logMessage("%s(%s:%i): fsnprintf failed", __FUNCTION__, __FILE__, __LINE__);
118                 return false;
119         }
120
121         if (static_cast<size_t>(bytes) > capacity) {
122                 if (resize(bytes + 1) != 0) {
123                         logg->logMessage("%s(%s:%i): DynBuf::resize failed", __FUNCTION__, __FILE__, __LINE__);
124                         return false;
125                 }
126
127                 va_start(ap, format);
128                 bytes = vsnprintf(buf, capacity, format, ap);
129                 va_end(ap);
130                 if (bytes < 0) {
131                         logg->logMessage("%s(%s:%i): fsnprintf failed", __FUNCTION__, __FILE__, __LINE__);
132                         return false;
133                 }
134         }
135
136         length = bytes;
137
138         return true;
139 }