Added support for get/sendPartialObject

If the caps flags are enabled for both get and send of partial object
this method is used instead of file push and pull. This makes many file
operations much faster and is widely supported throughout mobile
devices.

We still use the tmp file, not for storing data but to keep a unique
file handler for all the fuse file operations.

No caching happens at the moment, we could cache in the tmp file and
keep a table of offsets and sizes of the file that we already cached,
however, using the kernel file system cache is much better.
This commit is contained in:
Jochen Henneberg 2019-11-02 09:20:17 +01:00
parent e121556851
commit 2bcc4551e9
4 changed files with 102 additions and 13 deletions

View File

@ -596,11 +596,19 @@ int SMTPFileSystem::open(const char *path, struct fuse_file_info *file_info)
} else {
tmp_path = m_tmp_files_pool.makeTmpPath(std_path);
int rval = m_device.filePull(std_path, tmp_path);
if (rval != 0)
return -rval;
// only copy the file if needed
if (!hasPartialObjectSupport()) {
int rval = m_device.filePull(std_path, tmp_path);
if (rval != 0)
return -rval;
} else {
int fd = ::creat(tmp_path.c_str(), S_IRUSR | S_IWUSR);
::close(fd);
}
}
// we create the tmp file even if we can use partial get/send to
// have a valid file descriptor
int fd = ::open(tmp_path.c_str(), file_info->flags);
if (fd < 0) {
::unlink(tmp_path.c_str());
@ -620,24 +628,38 @@ int SMTPFileSystem::open(const char *path, struct fuse_file_info *file_info)
int SMTPFileSystem::read(const char *path, char *buf, size_t size,
off_t offset, struct fuse_file_info *file_info)
{
int rval = ::pread(file_info->fh, buf, size, offset);
if (rval < 0)
return -errno;
int rval = 0;
if (hasPartialObjectSupport()) {
const std::string std_path(path);
rval = m_device.fileRead(std_path, buf, size, offset);
} else {
rval = ::pread(file_info->fh, buf, size, offset);
if (rval < 0)
return -errno;
}
return rval;
}
int SMTPFileSystem::write(const char *path, const char *buf, size_t size,
off_t offset, struct fuse_file_info *file_info)
{
const TypeTmpFile *tmp_file = m_tmp_files_pool.getFile(std::string(path));
if (!tmp_file)
return -EINVAL;
int rval = 0;
if (hasPartialObjectSupport()) {
const std::string std_path(path);
rval = m_device.fileWrite(std_path, buf, size, offset);
} else {
const TypeTmpFile *tmp_file = m_tmp_files_pool.getFile(std::string(path));
if (!tmp_file)
return -EINVAL;
int rval = ::pwrite(file_info->fh, buf, size, offset);
if (rval < 0)
return -errno;
rval = ::pwrite(file_info->fh, buf, size, offset);
if (rval < 0)
return -errno;
const_cast<TypeTmpFile*>(tmp_file)->setModified();
}
const_cast<TypeTmpFile*>(tmp_file)->setModified();
return rval;
}
@ -764,3 +786,9 @@ int SMTPFileSystem::ftruncate(const char *path, off_t offset,
const_cast<TypeTmpFile*>(tmp_file)->setModified();
return 0;
}
bool SMTPFileSystem::hasPartialObjectSupport()
{
MTPDevice::Capabilities caps = m_device.getCapabilities();
return (caps.canGetPartialObject() && caps.canSendPartialObject());
}

View File

@ -104,6 +104,7 @@ public:
int create(const char *path, mode_t mode, fuse_file_info *file_info);
private:
bool hasPartialObjectSupport();
static std::unique_ptr<SMTPFileSystem> s_instance;
struct fuse_args m_args;

View File

@ -467,6 +467,64 @@ int MTPDevice::rename(const std::string &oldpath, const std::string &newpath)
#endif
}
int MTPDevice::fileRead(const std::string &path, char *buf, size_t size,
off_t offset)
{
const std::string path_basename(smtpfs_basename(path));
const std::string path_dirname(smtpfs_dirname(path));
const TypeDir *dir_parent = dirFetchContent(path_dirname);
const TypeFile *file_to_fetch = dir_parent ?
dir_parent->file(path_basename) : nullptr;
if (!dir_parent) {
logerr("Can not fetch '", path, "'.\n");
return -EINVAL;
}
if (!file_to_fetch) {
logerr("No such file '", path, "'.\n");
return -ENOENT;
}
// all systems clear
unsigned char *tmp_buf;
unsigned int tmp_size;
int rval = LIBMTP_GetPartialObject(m_device, file_to_fetch->id(),
offset, size, &tmp_buf, &tmp_size);
if (tmp_size > 0) {
memcpy(buf, tmp_buf, tmp_size);
free(tmp_buf);
}
if (rval != 0)
return -EIO;
return tmp_size;
}
int MTPDevice::fileWrite(const std::string &path, const char *buf, size_t size,
off_t offset)
{
const std::string path_basename(smtpfs_basename(path));
const std::string path_dirname(smtpfs_dirname(path));
const TypeDir *dir_parent = dirFetchContent(path_dirname);
const TypeFile *file_to_fetch = dir_parent ?
dir_parent->file(path_basename) : nullptr;
if (!dir_parent) {
logerr("Can not fetch '", path, "'.\n");
return -EINVAL;
}
if (!file_to_fetch) {
logerr("No such file '", path, "'.\n");
return -ENOENT;
}
// all systems clear
int rval = LIBMTP_SendPartialObject(m_device, file_to_fetch->id(),
offset, (unsigned char *) buf, size);
if (rval < 0)
return -EIO;
return size;
}
int MTPDevice::filePull(const std::string &src, const std::string &dst)
{
const std::string src_basename(smtpfs_basename(src));

View File

@ -78,6 +78,8 @@ public:
int rename(const std::string &oldpath, const std::string &newpath);
int fileRead(const std::string &path, char *buf, size_t size, off_t offset);
int fileWrite(const std::string &path, const char *buf, size_t size, off_t offset);
int filePull(const std::string &src, const std::string &dst);
int filePush(const std::string &src, const std::string &dst);
int fileRemove(const std::string &path);