| 190 | return this->pwritev2_mutable(iovec.iovec(), iovec.iovcnt(), offset, flags); |
| 191 | } |
| 192 | virtual ssize_t pwritev2_mutable(struct iovec *iov, int iovcnt, off_t offset, int flags) override { |
| 193 | struct iovec tmpiovec[MAX_TMP_IOVEC_SIZE]; |
| 194 | iovector_view view(tmpiovec, MAX_TMP_IOVEC_SIZE); |
| 195 | iovector_view buf(iov, iovcnt); |
| 196 | auto count = buf.sum(); |
| 197 | if (count == 0) return 0; |
| 198 | range_split_power2 rs(offset, count, m_alignment); |
| 199 | if (rs.is_aligned() && (!m_align_memory || iov_align_check(buf))) |
| 200 | return m_file->pwritev2_mutable(iov, iovcnt, offset, flags); |
| 201 | |
| 202 | struct stat stat; |
| 203 | m_file->fstat(&stat); |
| 204 | ssize_t filesize = stat.st_size; |
| 205 | auto suppose_filesize = (offset + (ssize_t)count) > filesize ? offset + count: filesize; |
| 206 | IOVector wbuf(m_allocator); |
| 207 | auto ret = wbuf.push_back(rs.aligned_length()); |
| 208 | if (ret < rs.aligned_length()) |
| 209 | LOG_ERROR_RETURN(0, -1, "Failed to allocate memory"); |
| 210 | |
| 211 | if (rs.begin_remainder > 0) |
| 212 | { |
| 213 | view.iovcnt = MAX_TMP_IOVEC_SIZE; |
| 214 | ssize_t ret = wbuf.slice(m_alignment, 0, &view); |
| 215 | assert(ret == m_alignment); |
| 216 | ssize_t off = rs.aligned_begin_offset(); |
| 217 | ret = m_file->preadv2(view.iov, view.iovcnt, off, flags); |
| 218 | if ((ret < 0) || ((off + ret < filesize) && (ret < (ssize_t)m_alignment))) |
| 219 | LOG_ERRNO_RETURN(0, -1, "failed to aligned [`]->preadv2(iov=`, iovcnt=`, offset=`, flags=`) and patch the first alignment block", |
| 220 | m_file, view.iov, view.iovcnt, off, flags); |
| 221 | if (ret < (ssize_t)m_alignment) { |
| 222 | view.extract_front(ret); |
| 223 | for (auto &p : view) { |
| 224 | memset(p.iov_base, 0, p.iov_len); |
| 225 | } |
| 226 | } |
| 227 | } |
| 228 | if (!rs.small_note && rs.end_remainder > 0) |
| 229 | { |
| 230 | ssize_t off = rs.aligned_end_offset() - m_alignment; // this should never be negative |
| 231 | if (filesize - off > (ssize_t)(rs.end_remainder)) { |
| 232 | // that means there is still parts of data after the rear end of pwrite block |
| 233 | view.iovcnt = MAX_TMP_IOVEC_SIZE; |
| 234 | ssize_t ret = wbuf.slice(m_alignment, wbuf.sum() - m_alignment, &view); |
| 235 | assert(ret == m_alignment); |
| 236 | ret = m_file->preadv2(view.iov, view.iovcnt, off, flags); |
| 237 | if (ret < 0) |
| 238 | LOG_ERRNO_RETURN(0, -1, "failed to aligned [`]->preadv2(ptr=`, count=`, offset=`, flags=`)", |
| 239 | m_file, view.iov, view.iovcnt, off, flags); |
| 240 | if ((ret + off < filesize) && (ret < (ssize_t)m_alignment)) // cannot fetch all data of file, and cannot fillup aligned block |
| 241 | LOG_ERRNO_RETURN(0, -1, "aligned [`]->preadv2(ptr=`, count=`, offset=`, flags=`) partial read", |
| 242 | m_file, view.iov, view.iovcnt, off, flags); |
| 243 | } |
| 244 | } |
| 245 | view.iovcnt = MAX_TMP_IOVEC_SIZE; |
| 246 | ret = wbuf.slice(count, rs.begin_remainder, &view); |
| 247 | assert(ret == count); |
| 248 | ret = view.memcpy_from(&buf, count); |
| 249 | assert(ret == count); |
no test coverage detected