On partial read/write, keep reading.

This avoids rsync errors and avoids data loss with cp, due to
failing to copy the last byte of 0.1953125% of files.

Unless direct_io is set, fuse expects a full read/write.

As a workaround for a device hanging bug, if the length of a file
on a Samsung device is 500 bytes modulo 512 bytes, libmtp returns a
partial read omitting the last byte which must be requested
separately.

Fixes #85.
This commit is contained in:
Cyp 2023-10-28 11:28:59 +02:00
parent 19e7bb9b60
commit 2c44f913e8
2 changed files with 31 additions and 2 deletions

View File

@ -85,13 +85,41 @@ int wrap_open(const char *path, struct fuse_file_info *file_info)
int wrap_read(const char *path, char *buf, size_t size, off_t offset,
struct fuse_file_info *file_info)
{
return SMTPFileSystem::instance()->read(path, buf, size, offset, file_info);
if (file_info->direct_io) {
return SMTPFileSystem::instance()->read(path, buf, size, offset, file_info);
} else {
int bytes_read = 0;
while (bytes_read < size) {
int rval = SMTPFileSystem::instance()->read(path, buf + bytes_read, size - bytes_read, offset + bytes_read, file_info);
if (rval < 0) {
return rval;
} else if (rval == 0) {
break;
}
bytes_read += rval;
}
return bytes_read;
}
}
int wrap_write(const char *path, const char *buf, size_t size, off_t offset,
struct fuse_file_info *file_info)
{
return SMTPFileSystem::instance()->write(path, buf, size, offset, file_info);
if (file_info->direct_io) {
return SMTPFileSystem::instance()->write(path, buf, size, offset, file_info);
} else {
int bytes_written = 0;
while (bytes_written < size) {
int rval = SMTPFileSystem::instance()->write(path, buf + bytes_written, size - bytes_written, offset + bytes_written, file_info);
if (rval < 0) {
return rval;
} else if (rval == 0) {
break;
}
bytes_written += rval;
}
return bytes_written;
}
}
int wrap_statfs(const char *path, struct statvfs *stat_info)

View File

@ -720,6 +720,7 @@ bool MTPDevice::listDevices(bool verbose, const std::string &dev_file)
continue;
std::cout << i + 1 << ": "
<< (raw_devices[i].device_entry.vendor ? raw_devices[i].device_entry.vendor : "Unknown vendor ")
<< ", "
<< (raw_devices[i].device_entry.product ? raw_devices[i].device_entry.product : "Unknown product")
<< std::endl;
#ifdef HAVE_LIBMTP_CHECK_CAPABILITY