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 ssize_t readv_in_full(int fd, const struct iovec *iov, int iovcnt) 192 { 193 ssize_t total = 0; 194 ssize_t count = get_iov_size(iov, iovcnt); 195 196 while (count > 0) { 197 ssize_t nr; 198 199 nr = xreadv(fd, iov, iovcnt); 200 if (nr <= 0) { 201 if (total > 0) 202 return total; 203 204 return -1; 205 } 206 207 while ((size_t)nr >= iov->iov_len) { 208 nr -= iov->iov_len; 209 total += iov->iov_len; 210 count -= iov->iov_len; 211 iovcnt--; 212 iov++; 213 } 214 } 215 216 return total; 217 } 218 219 ssize_t writev_in_full(int fd, const struct iovec *iov, int iovcnt) 220 { 221 ssize_t total = 0; 222 size_t count = get_iov_size(iov, iovcnt); 223 224 while (count > 0) { 225 ssize_t nr; 226 227 nr = xwritev(fd, iov, iovcnt); 228 if (nr < 0) 229 return -1; 230 if (nr == 0) { 231 errno = ENOSPC; 232 return -1; 233 } 234 235 while ((size_t)nr >= iov->iov_len) { 236 nr -= iov->iov_len; 237 total += iov->iov_len; 238 count -= iov->iov_len; 239 iovcnt--; 240 iov++; 241 } 242 } 243 244 return total; 245 } 246 247 /* Same as preadv(2) except that this function never returns EAGAIN or EINTR. */ 248 ssize_t xpreadv(int fd, const struct iovec *iov, int iovcnt, off_t offset) 249 { 250 ssize_t nr; 251 252 restart: 253 nr = preadv(fd, iov, iovcnt, offset); 254 if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) 255 goto restart; 256 257 return nr; 258 } 259 260 /* Same as pwritev(2) except that this function never returns EAGAIN or EINTR. */ 261 ssize_t xpwritev(int fd, const struct iovec *iov, int iovcnt, off_t offset) 262 { 263 ssize_t nr; 264 265 restart: 266 nr = pwritev(fd, iov, iovcnt, offset); 267 if ((nr < 0) && ((errno == EAGAIN) || (errno == EINTR))) 268 goto restart; 269 270 return nr; 271 } 272 273 ssize_t preadv_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset) 274 { 275 ssize_t total = 0; 276 size_t count = get_iov_size(iov, iovcnt); 277 278 while (count > 0) { 279 ssize_t nr; 280 281 nr = xpreadv(fd, iov, iovcnt, offset); 282 if (nr <= 0) { 283 if (total > 0) 284 return total; 285 286 return -1; 287 } 288 289 while ((size_t)nr >= iov->iov_len) { 290 nr -= iov->iov_len; 291 total += iov->iov_len; 292 count -= iov->iov_len; 293 iovcnt--; 294 iov++; 295 } 296 } 297 298 return total; 299 } 300 301 ssize_t pwritev_in_full(int fd, const struct iovec *iov, int iovcnt, off_t offset) 302 { 303 ssize_t total = 0; 304 size_t count = get_iov_size(iov, iovcnt); 305 306 while (count > 0) { 307 ssize_t nr; 308 309 nr = xpwritev(fd, iov, iovcnt, offset); 310 if (nr < 0) 311 return -1; 312 if (nr == 0) { 313 errno = ENOSPC; 314 return -1; 315 } 316 while ((size_t)nr >= iov->iov_len) { 317 nr -= iov->iov_len; 318 total += iov->iov_len; 319 count -= iov->iov_len; 320 iovcnt--; 321 iov++; 322 } 323 } 324 325 return total; 326 } 327