From 2c44f913e8a4ecea5e80eb784bb32b52785d0a12 Mon Sep 17 00:00:00 2001 From: Cyp Date: Sat, 28 Oct 2023 11:28:59 +0200 Subject: [PATCH] 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. --- src/simple-mtpfs-fuse.cpp | 32 ++++++++++++++++++++++++++++++-- src/simple-mtpfs-mtp-device.cpp | 1 + 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/simple-mtpfs-fuse.cpp b/src/simple-mtpfs-fuse.cpp index f842b06..e01a398 100644 --- a/src/simple-mtpfs-fuse.cpp +++ b/src/simple-mtpfs-fuse.cpp @@ -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) diff --git a/src/simple-mtpfs-mtp-device.cpp b/src/simple-mtpfs-mtp-device.cpp index 3b80c7a..50cac02 100644 --- a/src/simple-mtpfs-mtp-device.cpp +++ b/src/simple-mtpfs-mtp-device.cpp @@ -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