Add support for short writes to files. It should not happen, but just to be sure.
Some checks are pending
Build / build-mac (push) Waiting to run
Build / build-linux (push) Waiting to run
Build / build-win (push) Waiting to run
CodeQL Advanced / Analyze (c-cpp) (push) Waiting to run
CodeQL Advanced / Analyze (actions) (push) Waiting to run

This commit is contained in:
Andrea Mazzoleni 2026-01-25 11:29:41 +01:00
parent caf9cd3961
commit e743e23555
2 changed files with 48 additions and 23 deletions

View file

@ -269,19 +269,20 @@ int handle_read(struct snapraid_handle* handle, block_off_t file_pos, unsigned c
do {
bw_limit(handle->bw, block_size - count);
/* read the full block to support O_DIRECT */
read_ret = pread(handle->f, block_buffer + count, block_size - count, offset + count);
if (read_ret < 0) {
if (read_ret == -1) {
/* LCOV_EXCL_START */
out("Error reading file '%s' at offset %" PRIu64 " for size %u. %s.\n", handle->path, offset + count, block_size - count, strerror(errno));
return -1;
/* LCOV_EXCL_STOP */
}
if (read_ret == 0) {
/* LCOV_EXCL_START */
out("Unexpected end of file '%s' at offset %" PRIu64 ". %s.\n", handle->path, offset, strerror(errno));
if (errno == 0)
errno = ENXIO;
return -1;
/* LCOV_EXCL_STOP */
}
count += read_ret;
@ -308,21 +309,34 @@ int handle_write(struct snapraid_handle* handle, block_off_t file_pos, unsigned
ssize_t write_ret;
data_off_t offset;
unsigned write_size;
unsigned count;
int ret;
offset = file_pos * (data_off_t)block_size;
write_size = file_block_size(handle->file, file_pos, block_size);
write_ret = pwrite(handle->f, block_buffer, write_size, offset);
if (write_ret != (ssize_t)write_size) { /* conversion is safe because block_size is always small */
/* LCOV_EXCL_START */
log_fatal("Error writing file '%s'. %s.\n", handle->path, strerror(errno));
if (errno == 0)
count = 0;
do {
bw_limit(handle->bw, write_size - count);
write_ret = pwrite(handle->f, block_buffer + count, write_size - count, offset + count);
if (write_ret == -1) {
/* LCOV_EXCL_START */
log_fatal("Error writing file '%s'. %s.\n", handle->path, strerror(errno));
return -1;
/* LCOV_EXCL_STOP */
}
if (write_ret == 0) {
/* LCOV_EXCL_START */
log_fatal("Unexpected 0 write to file '%s'. %s.\n", handle->path, strerror(errno));
errno = ENXIO;
return -1;
/* LCOV_EXCL_STOP */
}
return -1;
/* LCOV_EXCL_STOP */
}
count += write_ret;
} while (count < write_size);
/* adjust the size of the valid data */
if (handle->valid_size < offset + write_size) {

View file

@ -855,6 +855,7 @@ int parity_write(struct snapraid_parity_handle* handle, block_off_t pos, unsigne
ssize_t write_ret;
data_off_t offset;
struct snapraid_split_handle* split;
unsigned count;
int ret;
offset = pos * (data_off_t)block_size;
@ -871,21 +872,31 @@ int parity_write(struct snapraid_parity_handle* handle, block_off_t pos, unsigne
if (split->valid_size < offset + block_size)
split->valid_size = offset + block_size;
bw_limit(handle->bw, block_size);
count = 0;
do {
bw_limit(handle->bw, block_size - count);
write_ret = pwrite(split->f, block_buffer, block_size, offset);
if (write_ret != (ssize_t)block_size) { /* conversion is safe because block_size is always small */
/* LCOV_EXCL_START */
if (errno == ENOSPC) {
log_fatal("Failed to grow parity file '%s' using write due lack of space.\n", split->path);
} else {
log_fatal("Error writing parity file '%s'. %s.\n", split->path, strerror(errno));
write_ret = pwrite(split->f, block_buffer + count, block_size - count, offset + count);
if (write_ret == -1) {
/* LCOV_EXCL_START */
if (errno == ENOSPC) {
log_fatal("Failed to grow parity file '%s' using write due lack of space.\n", split->path);
} else {
log_fatal("Error writing parity file '%s'. %s.\n", split->path, strerror(errno));
}
return -1;
/* LCOV_EXCL_STOP */
}
if (errno == 0)
if (write_ret == 0) {
/* LCOV_EXCL_START */
log_fatal("Unexpected 0 write to file '%s'. %s.\n", split->path, strerror(errno));
errno = ENXIO;
return -1;
/* LCOV_EXCL_STOP */
}
return -1;
/* LCOV_EXCL_STOP */
}
count += write_ret;
} while (count < block_size);
ret = advise_write(&split->advise, split->f, offset, block_size);
if (ret != 0) {
@ -930,7 +941,7 @@ int parity_read(struct snapraid_parity_handle* handle, block_off_t pos, unsigned
bw_limit(handle->bw, block_size - count);
read_ret = pread(split->f, block_buffer + count, block_size - count, offset + count);
if (read_ret < 0) {
if (read_ret == -1) {
/* LCOV_EXCL_START */
out("Error reading parity file '%s' at offset %" PRIu64 " for size %u. %s.\n", split->path, offset + count, block_size - count, strerror(errno));
return -1;