WIP: drivers

This commit is contained in:
Peter Hatina 2016-12-31 15:25:43 +01:00
parent c9a691fc52
commit 9daa820ddd
9 changed files with 593 additions and 13 deletions

42
.gitignore vendored Normal file
View File

@ -0,0 +1,42 @@
*.*~
*.bak
*-cache
*.lo
*.log
*.o
*.pyc
*.swp
*.swo
*.stamp
*.trs
*.tar.gz
*.tar.bz2
.deps
.libs
makefile
makefile.in
aclocal.m4
autom4te.cache/
build*
config.h
config.h.in
config.log
config.status
configure
data/*.service
depcomp
gtk-doc.make
install-sh
intltool-*
libtool
missing
m4/
simple-mtpfs
simple-mtpfs.config
simple-mtpfs.creator
simple-mtpfs.creator.user
simple-mtpfs.files
simple-mtpfs.includes
stamp-h1
.ycm_extra_conf.py

View File

@ -3,18 +3,20 @@ simple_mtpfs_CXXFLAGS = -Wall -pedantic $(FUSE_CFLAGS) $(LIBUSB1_CFLAGS)
simple_mtpfs_CPPFLAGS = -DFUSE_USE_VERSION=28
simple_mtpfs_LDADD = $(MTP_LIBS) $(FUSE_LIBS) $(LIBUSB1_LIBS)
simple_mtpfs_SOURCES = \
simple-mtpfs-fuse.h \
simple-mtpfs-libmtp.h \
simple-mtpfs-log.h \
simple-mtpfs-mtp-device.h \
simple-mtpfs-sha1.h \
simple-mtpfs-driver-base.h \
simple-mtpfs-tmpdir-driver.h \
simple-mtpfs-tmp-files-pool.h \
simple-mtpfs-type-basic.h \
simple-mtpfs-type-dir.h \
simple-mtpfs-type-file.h \
simple-mtpfs-type-tmp-file.h \
simple-mtpfs-util.h \
simple-mtpfs-fuse.cpp \
simple-mtpfs-driver-base.cpp \
simple-mtpfs-tmpdir-driver.cpp \
simple-mtpfs-libmtp.cpp \
simple-mtpfs-log.cpp \
simple-mtpfs-main.cpp \

View File

@ -0,0 +1,180 @@
/* ***** BEGIN LICENSE BLOCK *****
* Copyright (C) 2016, Peter Hatina <phatina@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ***** END LICENSE BLOCK ***** */
// Own
#include "simple-mtpfs-driver-base.h"
#include "simple-mtpfs-util.h"
DriverBase::DriverBase()
: m_device()
{
}
DriverBase::~DriverBase()
{
}
int DriverBase::getattr(const char *path, struct stat *buf)
{
memset(buf, 0, sizeof(struct stat));
struct fuse_context *fc = fuse_get_context();
buf->st_uid = fc->uid;
buf->st_gid = fc->gid;
if (path == std::string("/")) {
buf->st_mode = S_IFDIR | 0775;
buf->st_nlink = 2;
return 0;
} else {
std::string tmp_path(smtpfs_dirname(path));
std::string tmp_file(smtpfs_basename(path));
const TypeDir *content = m_device.dirFetchContent(tmp_path);
if (!content) {
return -ENOENT;
}
if (content->dir(tmp_file)) {
const TypeDir *dir = content->dir(tmp_file);
buf->st_ino = dir->id();
buf->st_mode = S_IFDIR | 0775;
buf->st_nlink = 2;
buf->st_mtime = dir->modificationDate();
} else if (content->file(tmp_file)) {
const TypeFile *file = content->file(tmp_file);
buf->st_ino = file->id();
buf->st_size = file->size();
buf->st_blocks = (file->size() / 512) + (file->size() % 512 > 0 ? 1 : 0);
buf->st_nlink = 1;
buf->st_mode = S_IFREG | 0644;
buf->st_mtime = file->modificationDate();
buf->st_ctime = buf->st_mtime;
buf->st_atime = buf->st_mtime;
} else {
return -ENOENT;
}
}
return 0;
}
int DriverBase::mkdir(const char *path, mode_t mode)
{
return m_device.dirCreateNew(std::string(path));
}
int DriverBase::unlink(const char *path)
{
return m_device.fileRemove(std::string(path));
}
int DriverBase::rmdir(const char *path)
{
return m_device.dirRemove(std::string(path));
}
int DriverBase::chmod(const char *path, mode_t mode)
{
return 0;
}
int DriverBase::chown(const char *path, uid_t uid, gid_t gid)
{
return 0;
}
int DriverBase::utime(const char *path, struct utimbuf *ubuf)
{
std::string tmp_basename(smtpfs_basename(std::string(path)));
std::string tmp_dirname(smtpfs_dirname(std::string(path)));
const TypeDir *parent = m_device.dirFetchContent(tmp_dirname);
if (!parent)
return -ENOENT;
const TypeFile *file = parent->file(tmp_basename);
if (!file)
return -ENOENT;
const_cast<TypeFile*>(file)->setModificationDate(ubuf->modtime);
return 0;
}
int DriverBase::statfs(const char *path, struct statvfs *stat_info)
{
uint64_t bs = 1024;
// XXX: linux coreutils still use bsize member to calculate free space
stat_info->f_bsize = static_cast<unsigned long>(bs);
stat_info->f_frsize = static_cast<unsigned long>(bs);
stat_info->f_blocks = m_device.storageTotalSize() / bs;
stat_info->f_bavail = m_device.storageFreeSize() / bs;
stat_info->f_bfree = stat_info->f_bavail;
return 0;
}
int DriverBase::flush(const char *path, struct fuse_file_info *file_info)
{
return 0;
}
int DriverBase::opendir(const char *path, struct fuse_file_info *file_info)
{
const TypeDir *content = m_device.dirFetchContent(std::string(path));
if (!content)
return -ENOENT;
return 0;
}
int DriverBase::readdir(const char *path, void *buf, fuse_fill_dir_t filler,
off_t offset, struct fuse_file_info *file_info)
{
const TypeDir *content = m_device.dirFetchContent(std::string(path));
if (!content)
return -ENOENT;
const std::set<TypeDir> dirs = content->dirs();
const std::set<TypeFile> files = content->files();
for (const TypeDir &d : dirs) {
struct stat st;
memset(&st, 0, sizeof(st));
st.st_ino = d.id();
st.st_mode = S_IFDIR | 0775;
filler(buf, d.name().c_str(), &st, 0);
}
for (const TypeFile &f : files) {
struct stat st;
memset(&st, 0, sizeof(st));
st.st_ino = f.id();
st.st_mode = S_IFREG | 0644;
filler(buf, f.name().c_str(), &st, 0);
}
return 0;
}
int DriverBase::releasedir(const char *path, struct fuse_file_info *file_info)
{
return 0;
}
int DriverBase::fsyncdir(const char *path, int datasync,
struct fuse_file_info *file_info)
{
return 0;
}

View File

@ -0,0 +1,64 @@
/* ***** BEGIN LICENSE BLOCK *****
* Copyright (C) 2016, Peter Hatina <phatina@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ***** END LICENSE BLOCK ***** */
#ifndef SMTPFS_DRIVERBASE_H
#define SMTPFS_DRIVERBASE_H
extern "C" {
# include <fuse/fuse.h>
}
#include "simple-mtpfs-mtp-device.h"
class DriverBase
{
public:
DriverBase();
virtual ~DriverBase();
virtual int getattr(const char *path, struct stat *buf);
virtual int mknod(const char *path, mode_t mode, dev_t dev);
virtual int mkdir(const char *path, mode_t mode);
virtual int unlink(const char *path);
virtual int rmdir(const char *path);
virtual int rename(const char *path, const char *newpath);
virtual int chmod(const char *path, mode_t mode);
virtual int chown(const char *path, uid_t uid, gid_t gid);
virtual int truncate(const char *path, off_t new_size);
virtual int utime(const char *path, struct utimbuf *ubuf);
virtual int open(const char *path, struct fuse_file_info *file_info);
virtual int read(const char *path, char *buf, size_t size, off_t offset, struct fuse_file_info *file_info);
virtual int write(const char *path, const char *buf, size_t size, off_t offset, struct fuse_file_info *file_info);
virtual int statfs(const char *path, struct statvfs *stat_info);
virtual int flush(const char *path, struct fuse_file_info *file_info);
virtual int release(const char *path, struct fuse_file_info *file_info);
virtual int fsync(const char *path, int datasync, struct fuse_file_info *fi);
virtual int opendir(const char *path, struct fuse_file_info *file_info);
virtual int readdir(const char *path, void *buf, fuse_fill_dir_t filler, off_t offset, struct fuse_file_info *file_info);
virtual int releasedir(const char *path, struct fuse_file_info *file_info);
virtual int fsyncdir(const char *path, int datasync, struct fuse_file_info *file_info);
virtual int ftruncate(const char *path, off_t offset, struct fuse_file_info *file_info);
virtual void* init(struct fuse_conn_info *conn);
virtual int create(const char *path, mode_t mode, fuse_file_info *file_info);
private:
static bool removeDir(const std::string &dirname);
MTPDevice m_device;
};
#endif // SMTPFS_DRIVERBASE_H

View File

@ -205,10 +205,9 @@ SMTPFileSystem *SMTPFileSystem::instance()
}
SMTPFileSystem::SMTPFileSystem():
m_args(),
m_tmp_files_pool(),
m_options(),
m_device()
m_args{},
m_fuse_operations{},
m_options{}
{
m_fuse_operations.getattr = wrap_getattr;
m_fuse_operations.readlink = nullptr;

View File

@ -18,6 +18,7 @@
#ifndef SMTPFS_FUSE_H
#define SMTPFS_FUSE_H
// C
#include <config.h>
#include <memory>
#include <string>
@ -25,6 +26,9 @@
extern "C" {
# include <fuse/fuse.h>
}
// Own
#include "simple-mtpfs-driver-base.h"
#include "simple-mtpfs-mtp-device.h"
#include "simple-mtpfs-tmp-files-pool.h"
#include "simple-mtpfs-type-tmp-file.h"
@ -104,17 +108,12 @@ public:
int create(const char *path, mode_t mode, fuse_file_info *file_info);
private:
static bool removeDir(const std::string &dirname);
bool createTmpDir();
bool removeTmpDir();
static std::unique_ptr<SMTPFileSystem> s_instance;
struct fuse_args m_args;
struct fuse_operations m_fuse_operations;
TmpFilesPool m_tmp_files_pool;
SMTPFileSystemOptions m_options;
MTPDevice m_device;
std::unique_ptr<DriverBase> m_driver;
};
#endif // SMTPFS_FUSE_H

View File

@ -83,6 +83,9 @@ public:
int fileRemove(const std::string &path);
int fileRename(const std::string &oldpath, const std::string &newpath);
int fileGetPartial();
int filePutPartial();
Capabilities getCapabilities() const;
static bool listDevices(bool verbose, const std::string &dev_file);

View File

@ -0,0 +1,235 @@
/* ***** BEGIN LICENSE BLOCK *****
* Copyright (C) 2016, Peter Hatina <phatina@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ***** END LICENSE BLOCK ***** */
// Own
#include "simple-mtpfs-tmpdir-driver.h"
#include "simple-mtpfs-util.h"
TmpDirDriver::TmpDirDriver()
: DriverBase{}
, m_tmp_files_pool{}
{
}
TmpDirDriver::~TmpDirDriver()
{
}
int TmpDirDriver::mknod(const char *path, mode_t mode, dev_t dev)
{
if (!S_ISREG(mode))
return -EINVAL;
std::string tmp_path = m_tmp_files_pool.makeTmpPath(std::string(path));
int rval = ::open(tmp_path.c_str(), O_CREAT | O_WRONLY, mode);
if (rval < 0)
return -errno;
rval = ::close(rval);
if (rval < 0)
return -errno;
m_device.filePush(tmp_path, std::string(path));
::unlink(tmp_path.c_str());
return 0;
}
int TmpDirDriver::rename(const char *path, const char *newpath)
{
const std::string tmp_old_dirname(smtpfs_dirname(std::string(path)));
const std::string tmp_new_dirname(smtpfs_dirname(std::string(newpath)));
if (tmp_old_dirname == tmp_new_dirname)
return m_device.rename(std::string(path), std::string(newpath));
if (!m_options.m_enable_move)
return -EPERM;
const std::string tmp_file = m_tmp_files_pool.makeTmpPath(std::string(newpath));
int rval = m_device.filePull(std::string(path), tmp_file);
if (rval != 0)
return -rval;
rval = m_device.filePush(tmp_file, std::string(newpath));
if (rval != 0)
return -rval;
rval = m_device.fileRemove(std::string(path));
if (rval != 0)
return -rval;
return 0;
}
int TmpDirDriver::truncate(const char *path, off_t new_size)
{
const std::string tmp_path = m_tmp_files_pool.makeTmpPath(std::string(path));
int rval = m_device.filePull(std::string(path), tmp_path);
if (rval != 0) {
::unlink(tmp_path.c_str());
return -rval;
}
rval = ::truncate(tmp_path.c_str(), new_size);
if (rval != 0) {
int errno_tmp = errno;
::unlink(tmp_path.c_str());
return -errno_tmp;
}
rval = m_device.fileRemove(std::string(path));
if (rval != 0) {
::unlink(tmp_path.c_str());
return -rval;
}
rval = m_device.filePush(tmp_path, std::string(path));
::unlink(tmp_path.c_str());
if (rval != 0)
return -rval;
return 0;
}
int TmpDirDriver::create(const char *path, mode_t mode, fuse_file_info *file_info)
{
const std::string tmp_path = m_tmp_files_pool.makeTmpPath(std::string(path));
int rval = ::creat(tmp_path.c_str(), mode);
if (rval < 0)
return -errno;
file_info->fh = rval;
m_tmp_files_pool.addFile(TypeTmpFile(std::string(path), tmp_path, rval, true));
m_device.filePush(tmp_path, std::string(path));
return 0;
}
int TmpDirDriver::open(const char *path, struct fuse_file_info *file_info)
{
if (file_info->flags & O_WRONLY)
file_info->flags |= O_TRUNC;
const std::string std_path(path);
TypeTmpFile *tmp_file = const_cast<TypeTmpFile*>(
m_tmp_files_pool.getFile(std_path));
std::string tmp_path;
if (tmp_file) {
tmp_path = tmp_file->pathTmp();
} else {
tmp_path = m_tmp_files_pool.makeTmpPath(std_path);
int rval = m_device.filePull(std_path, tmp_path);
if (rval != 0)
return -rval;
}
int fd = ::open(tmp_path.c_str(), file_info->flags);
if (fd < 0) {
::unlink(tmp_path.c_str());
return -errno;
}
file_info->fh = fd;
if (tmp_file)
tmp_file->addFileDescriptor(fd);
else
m_tmp_files_pool.addFile(TypeTmpFile(std_path, tmp_path, fd));
return 0;
}
int TmpDirDriver::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;
return rval;
}
int TmpDirDriver::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 = ::pwrite(file_info->fh, buf, size, offset);
if (rval < 0)
return -errno;
const_cast<TypeTmpFile*>(tmp_file)->setModified();
return rval;
}
int TmpDirDriver::release(const char *path, struct fuse_file_info *file_info)
{
int rval = ::close(file_info->fh);
if (rval < 0)
return -errno;
const std::string std_path(path);
if (std_path == std::string("-"))
return 0;
TypeTmpFile *tmp_file = const_cast<TypeTmpFile*>(
m_tmp_files_pool.getFile(std_path));
tmp_file->removeFileDescriptor(file_info->fh);
if (tmp_file->refcnt() != 0)
return 0;
const bool modif = tmp_file->isModified();
const std::string tmp_path = tmp_file->pathTmp();
m_tmp_files_pool.removeFile(std_path);
if (modif) {
rval = m_device.filePush(tmp_path, std_path);
if (rval != 0) {
::unlink(tmp_path.c_str());
return -rval;
}
}
::unlink(tmp_path.c_str());
return 0;
}
int TmpDirDriver::fsync(const char *path, int datasync, struct fuse_file_info *fi)
{
int rval = -1;
#ifdef HAVE_FDATASYNC
if (datasync)
rval = ::fdatasync(fi->fh);
else
#else
rval = ::fsync(fi->fh);
#endif
if (rval != 0)
return -errno;
return 0;
}
std::unique_ptr<DriverBase> makeTmpDirDriver()
{
return std::make_unique<TmpDirDriver>();
}

View File

@ -0,0 +1,56 @@
/* ***** BEGIN LICENSE BLOCK *****
* Copyright (C) 2016, Peter Hatina <phatina@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* ***** END LICENSE BLOCK ***** */
#ifndef SMTPFS_TMPDIR_DRIVER_H
#define SMTPFS_TMPDIR_DRIVER_H
// STL
#include <memory>
// Own
#include "simple-mtpfs-driver-base.h"
#include "simple-mtpfs-mtp-device.h"
#include "simple-mtpfs-tmp-files-pool.h"
class TmpDirDriver: public DriverBase
{
public:
TmpDirDriver();
virtual ~TmpDirDriver();
virtual int mknod(const char *path, mode_t mode, dev_t dev) override;
virtual int rename(const char *path, const char *newpath) override;
virtual int truncate(const char *path, off_t new_size) override;
virtual int create(const char *path, mode_t mode, fuse_file_info *file_info) override;
virtual int open(const char *path, struct fuse_file_info *file_info) override;
virtual int read(const char *path, char *buf, size_t size,
off_t offset, struct fuse_file_info *file_info) override;
virtual int write(const char *path, const char *buf, size_t size,
off_t offset, struct fuse_file_info *file_info) override;
virtual int release(const char *path, struct fuse_file_info *file_info) override;
virtual int fsync(const char *path, int datasync, struct fuse_file_info *fi) override;
private:
bool createTmpDir();
bool removeTmpDir();
TmpFilesPool m_tmp_files_pool;
};
std::unique_ptr<DriverBase> makeTmpDirDriver();
#endif // SMTPFS_TMPDIR_DRIVER_H