1 #include "kvm/read-write.h" 2 3 #include <sys/types.h> 4 #include <unistd.h> 5 #include <string.h> 6 #include <errno.h> 7 8 /* Same as read(2) except that this function never returns EAGAIN or EINTR. */ 9 ssize_t xread(int fd, void *buf, size_t count) 10 { 11 ssize_t nr; 12 13 restart: 14 nr = read(fd, buf, count); 15 if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) 16 goto restart; 17 18 return nr; 19 } 20 21 /* Same as write(2) except that this function never returns EAGAIN or EINTR. */ 22 ssize_t xwrite(int fd, const void *buf, size_t count) 23 { 24 ssize_t nr; 25 26 restart: 27 nr = write(fd, buf, count); 28 if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) 29 goto restart; 30 31 return nr; 32 } 33 34 ssize_t read_in_full(int fd, void *buf, size_t count) 35 { 36 ssize_t total = 0; 37 char *p = buf; 38 39 while (count > 0) { 40 ssize_t nr; 41 42 nr = xread(fd, p, count); 43 if (nr <= 0) { 44 if (total > 0) 45 return total; 46 47 return -1; 48 } 49 50 count -= nr; 51 total += nr; 52 p += nr; 53 } 54 55 return total; 56 } 57 58 ssize_t write_in_full(int fd, const void *buf, size_t count) 59 { 60 const char *p = buf; 61 ssize_t total = 0; 62 63 while (count > 0) { 64 ssize_t nr; 65 66 nr = xwrite(fd, p, count); 67 if (nr < 0) 68 return -1; 69 if (nr == 0) { 70 errno = ENOSPC; 71 return -1; 72 } 73 count -= nr; 74 total += nr; 75 p += nr; 76 } 77 78 return total; 79 } 80 81 /* Same as pread(2) except that this function never returns EAGAIN or EINTR. */ 82 ssize_t xpread(int fd, void *buf, size_t count, off_t offset) 83 { 84 ssize_t nr; 85 86 restart: 87 nr = pread(fd, buf, count, offset); 88 if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) 89 goto restart; 90 91 return nr; 92 } 93 94 /* Same as pwrite(2) except that this function never returns EAGAIN or EINTR. */ 95 ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset) 96 { 97 ssize_t nr; 98 99 restart: 100 nr = pwrite(fd, buf, count, offset); 101 if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) 102 goto restart; 103 104 return nr; 105 } 106 107 ssize_t pread_in_full(int fd, void *buf, size_t count, off_t offset) 108 { 109 ssize_t total = 0; 110 char *p = buf; 111 112 while (count > 0) { 113 ssize_t nr; 114 115 nr = xpread(fd, p, count, offset); 116 if (nr <= 0) { 117 if (total > 0) 118 return total; 119 120 return -1; 121 } 122 123 count -= nr; 124 total += nr; 125 p += nr; 126 offset += nr; 127 } 128 129 return total; 130 } 131 132 ssize_t pwrite_in_full(int fd, const void *buf, size_t count, off_t offset) 133 { 134 const char *p = buf; 135 ssize_t total = 0; 136 137 while (count > 0) { 138 ssize_t nr; 139 140 nr = xpwrite(fd, p, count, offset); 141 if (nr < 0) 142 return -1; 143 if (nr == 0) { 144 errno = ENOSPC; 145 return -1; 146 } 147 count -= nr; 148 total += nr; 149 p += nr; 150 offset += nr; 151 } 152 153 return total; 154 } 155 156 /* Same as readv(2) except that this function never returns EAGAIN or EINTR. */ 157 ssize_t xreadv(int fd, const struct iovec *iov, int iovcnt) 158 { 159 ssize_t nr; 160 161 restart: 162 nr = readv(fd, iov, iovcnt); 163 if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) 164 goto restart; 165 166 return nr; 167 } 168 169 /* Same as writev(2) except that this function never returns EAGAIN or EINTR. */ 170 ssize_t xwritev(int fd, const struct iovec *iov, int iovcnt) 171 { 172 ssize_t nr; 173 174 restart: 175 nr = write(fd, iov, iovcnt); 176 if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) 177 goto restart; 178 179 return nr; 180 } 181 182 static inline ssize_t get_iov_size(const struct iovec *iov, int iovcnt) 183 { 184 size_t size = 0; 185 while (iovcnt--) 186 size += (iov++)->iov_len; 187 188 return size; 189 } 190 191 static inline void shift_iovec(const struct iovec **iov, int *iovcnt, 192 size_t nr, ssize_t *total, size_t *count, off_t *offset) 193 { 194 while (nr >= (*iov)->iov_len) { 195 nr -= (*iov)->iov_len; 196 *total += (*iov)->iov_len; 197 *count -= (*iov)->iov_len; 198 if (offset) 199 *offset += (*iov)->iov_len; 200 (*iovcnt)--; 201 (*iov)++; 202 } 203 } 204 205 ssize_t readv_in_full(int fd, const struct iovec *iov, int iovcnt) 206 { 207 ssize_t total = 0; 208 size_t count = get_iov_size(iov, iovcnt); 209 210 while (count > 0) { 211 ssize_t nr; 212 213 nr = xreadv(fd, iov, iovcnt); 214 if (nr <= 0) { 215 if (total > 0) 216 return total; 217 218 return -1; 219 } 220 221 shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL); 222 } 223 224 return total; 225 } 226 227 ssize_t writev_in_full(int fd, const struct iovec *iov, int iovcnt) 228 { 229 ssize_t total = 0; 230 size_t count = get_iov_size(iov, iovcnt); 231 232 while (count > 0) { 233 ssize_t nr; 234 235 nr = xwritev(fd, iov, iovcnt); 236 if (nr < 0) 237 return -1; 238 if (nr == 0) { 239 errno = ENOSPC; 240 return -1; 241 } 242 243 shift_iovec(&iov, &iovcnt, nr, &total, &count, NULL); 244 } 245 246 return total; 247 } 248 249 /* Same as preadv(2) except that this function never returns EAGAIN or EINTR. */ 250 ssize_t xpreadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) 251 { 252 ssize_t nr; 253 254 restart: 255 nr = preadv(fd, iov, iovcnt, offset); 256 if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) 257 goto restart; 258 259 return nr; 260 } 261 262 /* Same as pwritev(2) except that this function never returns EAGAIN or EINTR. */ 263 ssize_t xpwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) 264 { 265 ssize_t nr; 266 267 restart: 268 nr = pwritev(fd, iov, iovcnt, offset); 269 if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) 270 goto restart; 271 272 return nr; 273 } 274 275 ssize_t preadv_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset) 276 { 277 ssize_t total = 0; 278 size_t count = get_iov_size(iov, iovcnt); 279 280 while (count > 0) { 281 ssize_t nr; 282 283 nr = xpreadv(fd, iov, iovcnt, offset); 284 if (nr <= 0) { 285 if (total > 0) 286 return total; 287 288 return -1; 289 } 290 291 shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset); 292 } 293 294 return total; 295 } 296 297 ssize_t pwritev_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset) 298 { 299 ssize_t total = 0; 300 size_t count = get_iov_size(iov, iovcnt); 301 302 while (count > 0) { 303 ssize_t nr; 304 305 nr = xpwritev(fd, iov, iovcnt, offset); 306 if (nr < 0) 307 return -1; 308 if (nr == 0) { 309 errno = ENOSPC; 310 return -1; 311 } 312 313 shift_iovec(&iov, &iovcnt, nr, &total, &count, &offset); 314 } 315 316 return total; 317 } 318