in fs/aligned-file.cpp [86:136]
virtual ssize_t pwrite(const void *buf, size_t count, off_t offset) override
{
if (count == 0) return 0;
range_split_power2 rs(offset, count, m_alignment);
if (rs.is_aligned() && (!m_align_memory || rs.is_aligned_ptr(buf)))
return m_file->pwrite(buf, count, offset);
struct stat stat;
m_file->fstat(&stat);
ssize_t filesize = stat.st_size;
auto suppose_filesize = (offset + (ssize_t)count) > filesize ? offset + count: filesize;
auto ptr = mem_alloc(rs.aligned_length());
if (!ptr)
LOG_ERROR_RETURN(0, -1, "Failed to allocate memory");
DEFER(free(ptr));
if (rs.begin_remainder > 0)
{
ssize_t off = rs.aligned_begin_offset();
ssize_t ret = m_file->pread(ptr, m_alignment, off);
if ((ret < 0) || ((off + ret < filesize) && (ret < (ssize_t)m_alignment)))
LOG_ERRNO_RETURN(0, -1, "failed to aligned [`]->pread(ptr=`, count=`, offset=`) and patch the first alignment block", m_file, ptr, m_alignment, off);
if (ret < (ssize_t)m_alignment) {
memset((char*)ptr + ret, 0, m_alignment - ret);
}
}
if (!rs.small_note && rs.end_remainder > 0)
{
ssize_t off = rs.aligned_end_offset() - m_alignment; // this should never be negative
if (filesize - off > (ssize_t)(rs.end_remainder)) {
// that means there is still parts of data after the rear end of pwrite block
auto ptr_ = (char*)ptr + off - rs.aligned_begin_offset();
ssize_t ret = m_file->pread(ptr_, m_alignment, off);
if ((ret < 0) ||
((ret + off < filesize) && (ret < (ssize_t)m_alignment))) // cannot fetch all data of file, and cannot fillup aligned block
LOG_ERRNO_RETURN(0, -1, "failed to aligned [`]->pread(ptr=`, count=`, offset=`) and patch the last alignment block", m_file, ptr_, m_alignment, off);
}
}
memcpy((char*)ptr + rs.begin_remainder, buf, count);
auto actual_write = m_file->pwrite(ptr, rs.aligned_length(), rs.aligned_begin_offset());
auto current_tail = rs.aligned_begin_offset() + actual_write;
if ((ssize_t)current_tail < offset)
return -1; // failed to write
auto count_write = current_tail - offset >= count ? count : current_tail - offset;
if (suppose_filesize < current_tail) { // that means have written more than needs
m_file->ftruncate(suppose_filesize);
}
return count_write;
}