mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-24 09:23:37 -05:00
661 lines
20 KiB
C
661 lines
20 KiB
C
/**
|
|
* @file dll/fuse3/fuse2to3.c
|
|
*
|
|
* @copyright 2015-2019 Bill Zissimopoulos
|
|
*/
|
|
/*
|
|
* This file is part of WinFsp.
|
|
*
|
|
* You can redistribute it and/or modify it under the terms of the GNU
|
|
* General Public License version 3 as published by the Free Software
|
|
* Foundation.
|
|
*
|
|
* Licensees holding a valid commercial license may use this software
|
|
* in accordance with the commercial license agreement provided in
|
|
* conjunction with the software. The terms and conditions of any such
|
|
* commercial license agreement shall govern, supersede, and render
|
|
* ineffective any application of the GPLv3 license to this software,
|
|
* notwithstanding of any reference thereto in the software or
|
|
* associated repository.
|
|
*/
|
|
|
|
#include <dll/fuse3/library.h>
|
|
|
|
static inline struct fuse3 *fuse2to3_getfuse3(void)
|
|
{
|
|
return fsp_fuse_get_context_internal()->fuse->fuse3;
|
|
}
|
|
|
|
static inline void fuse2to3_fi2from3(struct fuse_file_info *fi, struct fuse3_file_info *fi3)
|
|
{
|
|
memset(fi, 0, sizeof *fi);
|
|
fi->flags = fi3->flags;
|
|
fi->writepage = fi3->writepage;
|
|
fi->direct_io = fi3->direct_io;
|
|
fi->keep_cache = fi3->keep_cache;
|
|
fi->flush = fi3->flush;
|
|
fi->nonseekable = fi3->nonseekable;
|
|
fi->fh = fi3->fh;
|
|
fi->lock_owner = fi3->lock_owner;
|
|
}
|
|
|
|
static inline void fuse2to3_fi3from2(struct fuse3_file_info *fi3, struct fuse_file_info *fi)
|
|
{
|
|
memset(fi3, 0, sizeof *fi3);
|
|
fi3->flags = fi->flags;
|
|
fi3->writepage = fi->writepage;
|
|
fi3->direct_io = fi->direct_io;
|
|
fi3->keep_cache = fi->keep_cache;
|
|
fi3->flush = fi->flush;
|
|
fi3->nonseekable = fi->nonseekable;
|
|
fi3->fh = fi->fh;
|
|
fi3->lock_owner = fi->lock_owner;
|
|
}
|
|
|
|
static inline void fuse2to3_conn3from2(struct fuse3_conn_info *conn3, struct fuse_conn_info *conn)
|
|
{
|
|
memset(conn3, 0, sizeof *conn3);
|
|
conn3->proto_major = 7; /* pretend that we are FUSE kernel protocol 7.26 */
|
|
conn3->proto_minor = 26; /* which was current at the time of FUSE 3.2 */
|
|
conn3->max_write = conn->max_write;
|
|
conn3->max_read = conn->max_write;
|
|
conn3->max_readahead = conn->max_readahead;
|
|
conn3->capable = (conn->capable & ~FSP_FUSE_CAP_READDIR_PLUS) | FUSE_CAP_READDIRPLUS;
|
|
conn3->want = conn->want;
|
|
}
|
|
|
|
static int fuse2to3_getattr(const char *path, struct fuse_stat *stbuf)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.getattr(path, stbuf, 0);
|
|
}
|
|
|
|
static int fuse2to3_readlink(const char *path, char *buf, size_t size)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.readlink(path, buf, size);
|
|
}
|
|
|
|
static int fuse2to3_mknod(const char *path, fuse_mode_t mode, fuse_dev_t dev)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.mknod(path, mode, dev);
|
|
}
|
|
|
|
static int fuse2to3_mkdir(const char *path, fuse_mode_t mode)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.mkdir(path, mode);
|
|
}
|
|
|
|
static int fuse2to3_unlink(const char *path)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.unlink(path);
|
|
}
|
|
|
|
static int fuse2to3_rmdir(const char *path)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.rmdir(path);
|
|
}
|
|
|
|
static int fuse2to3_symlink(const char *dstpath, const char *srcpath)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.symlink(dstpath, srcpath);
|
|
}
|
|
|
|
static int fuse2to3_rename(const char *oldpath, const char *newpath)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.rename(oldpath, newpath, 0);
|
|
}
|
|
|
|
static int fuse2to3_link(const char *srcpath, const char *dstpath)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.link(srcpath, dstpath);
|
|
}
|
|
|
|
static int fuse2to3_chmod(const char *path, fuse_mode_t mode)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.chmod(path, mode, 0);
|
|
}
|
|
|
|
static int fuse2to3_chown(const char *path, fuse_uid_t uid, fuse_gid_t gid)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.chown(path, uid, gid, 0);
|
|
}
|
|
|
|
static int fuse2to3_truncate(const char *path, fuse_off_t size)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.truncate(path, size, 0);
|
|
}
|
|
|
|
static int fuse2to3_open(const char *path, struct fuse_file_info *fi)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res = f3->ops.open(path, &fi3);
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static int fuse2to3_read(const char *path, char *buf, size_t size, fuse_off_t off,
|
|
struct fuse_file_info *fi)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res = f3->ops.read(path, buf, size, off, &fi3);
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static int fuse2to3_write(const char *path, const char *buf, size_t size, fuse_off_t off,
|
|
struct fuse_file_info *fi)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res = f3->ops.write(path, buf, size, off, &fi3);
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static int fuse2to3_statfs(const char *path, struct fuse_statvfs *stbuf)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.statfs(path, stbuf);
|
|
}
|
|
|
|
static int fuse2to3_flush(const char *path, struct fuse_file_info *fi)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res = f3->ops.flush(path, &fi3);
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static int fuse2to3_release(const char *path, struct fuse_file_info *fi)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res = f3->ops.release(path, &fi3);
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static int fuse2to3_fsync(const char *path, int datasync, struct fuse_file_info *fi)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res = f3->ops.fsync(path, datasync, &fi3);
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static int fuse2to3_setxattr(const char *path, const char *name, const char *value, size_t size,
|
|
int flags)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.setxattr(path, name, value, size, flags);
|
|
}
|
|
|
|
static int fuse2to3_getxattr(const char *path, const char *name, char *value, size_t size)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.getxattr(path, name, value, size);
|
|
}
|
|
|
|
static int fuse2to3_listxattr(const char *path, char *namebuf, size_t size)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.listxattr(path, namebuf, size);
|
|
}
|
|
|
|
static int fuse2to3_removexattr(const char *path, const char *name)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.removexattr(path, name);
|
|
}
|
|
|
|
static int fuse2to3_opendir(const char *path, struct fuse_file_info *fi)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res = f3->ops.opendir(path, &fi3);
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static int fuse2to3_candel_filldir(void *buf, const char *name,
|
|
const struct fuse_stat *stbuf, fuse_off_t off,
|
|
enum fuse3_fill_dir_flags flags)
|
|
{
|
|
return fsp_fuse_intf_CanDeleteAddDirInfo(buf, name, 0, off);
|
|
}
|
|
|
|
static int fuse2to3_filldir(void *buf, const char *name,
|
|
const struct fuse_stat *stbuf, fuse_off_t off,
|
|
enum fuse3_fill_dir_flags flags)
|
|
{
|
|
return 0 != (flags & FUSE_FILL_DIR_PLUS) ?
|
|
fsp_fuse_intf_AddDirInfo(buf, name, stbuf, off) :
|
|
fsp_fuse_intf_AddDirInfo(buf, name, 0, off);
|
|
}
|
|
|
|
static int fuse2to3_readdir(const char *path, void *buf, fuse_fill_dir_t filler, fuse_off_t off,
|
|
struct fuse_file_info *fi)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse_dirhandle *dh = buf;
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res;
|
|
if (fsp_fuse_intf_CanDeleteAddDirInfo == filler)
|
|
res = f3->ops.readdir(path, buf, &fuse2to3_candel_filldir, off, &fi3, 0);
|
|
else if (fsp_fuse_intf_AddDirInfo == filler)
|
|
res = f3->ops.readdir(path, buf, &fuse2to3_filldir, off, &fi3,
|
|
dh->ReaddirPlus ? FUSE_READDIR_PLUS : 0);
|
|
else
|
|
{
|
|
FspDebugLog("fuse2to3_readdir = -ENOSYS (internal error: unknown filler)\n");
|
|
res = -ENOSYS_(f3->fuse->env);
|
|
}
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static int fuse2to3_releasedir(const char *path, struct fuse_file_info *fi)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res = f3->ops.releasedir(path, &fi3);
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static int fuse2to3_fsyncdir(const char *path, int datasync, struct fuse_file_info *fi)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res = f3->ops.fsyncdir(path, datasync, &fi3);
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static void *fuse2to3_init(struct fuse_conn_info *conn)
|
|
{
|
|
struct fuse_context *context = fsp_fuse_get_context_internal();
|
|
struct fuse *f = context->fuse;
|
|
struct fuse3 *f3 = f->fuse3;
|
|
|
|
struct fuse3_conn_info conn3;
|
|
fuse2to3_conn3from2(&conn3, conn);
|
|
|
|
struct fuse3_config conf3;
|
|
memset(&conf3, 0, sizeof conf3);
|
|
conf3.set_gid = f->set_gid;
|
|
conf3.gid = f->gid;
|
|
conf3.set_uid = f->set_uid;
|
|
conf3.uid = f->uid;
|
|
conf3.set_mode = f->set_umask;
|
|
conf3.umask = f->umask;
|
|
#if 0
|
|
/*
|
|
* Cannot set timeouts because of lack of floating point support.
|
|
*
|
|
* FUSE uses the `double` type for timeouts. This DLL does not use the standard library
|
|
* for a variety of reasons. This means that we cannot easily perform the computations
|
|
* below.
|
|
*
|
|
* If this becomes important (double) floating point values could perhaps be calculated
|
|
* using bit tricks. See below:
|
|
* - http://locklessinc.com/articles/i2f/
|
|
* - https://stackoverflow.com/a/20308114
|
|
*/
|
|
conf3.entry_timeout = f->VolumeParams.DirInfoTimeoutValid ?
|
|
f->VolumeParams.DirInfoTimeout / 1000 : f->VolumeParams.FileInfoTimeout / 1000;
|
|
conf3.negative_timeout = 0;
|
|
conf3.attr_timeout = f->VolumeParams.FileInfoTimeout / 1000;
|
|
conf3.ac_attr_timeout = conf3.attr_timeout;
|
|
#endif
|
|
|
|
void *res = f3->ops.init(&conn3, &conf3);
|
|
|
|
conn->max_write = conn3.max_write;
|
|
conn->max_readahead = conn3.max_readahead;
|
|
conn->want = 0 != (conn3.want & FUSE_CAP_READDIRPLUS) ? FSP_FUSE_CAP_READDIR_PLUS : 0;
|
|
conn->want |= conn3.want & ~FUSE_CAP_READDIRPLUS;
|
|
|
|
return res;
|
|
}
|
|
|
|
static void fuse2to3_destroy(void *data)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
f3->ops.destroy(data);
|
|
}
|
|
|
|
static int fuse2to3_access(const char *path, int mask)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.access(path, mask);
|
|
}
|
|
|
|
static int fuse2to3_create(const char *path, fuse_mode_t mode, struct fuse_file_info *fi)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res = f3->ops.create(path, mode, &fi3);
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static int fuse2to3_ftruncate(const char *path, fuse_off_t off, struct fuse_file_info *fi)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res = f3->ops.truncate(path, off, &fi3);
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static int fuse2to3_fgetattr(const char *path, struct fuse_stat *stbuf, struct fuse_file_info *fi)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res = f3->ops.getattr(path, stbuf, &fi3);
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static int fuse2to3_lock(const char *path,
|
|
struct fuse_file_info *fi, int cmd, struct fuse_flock *lock)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res = f3->ops.lock(path, &fi3, cmd, lock);
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static int fuse2to3_utimens(const char *path, const struct fuse_timespec tv[2])
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.utimens(path, tv, 0);
|
|
}
|
|
|
|
static int fuse2to3_bmap(const char *path, size_t blocksize, uint64_t *idx)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
return f3->ops.bmap(path, blocksize, idx);
|
|
}
|
|
|
|
static int fuse2to3_ioctl(const char *path, int cmd, void *arg, struct fuse_file_info *fi,
|
|
unsigned int flags, void *data)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res = f3->ops.ioctl(path, cmd, arg, &fi3, flags, data);
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static int fuse2to3_poll(const char *path, struct fuse_file_info *fi,
|
|
struct fuse_pollhandle *ph, unsigned *reventsp)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res = f3->ops.poll(path, &fi3, (struct fuse3_pollhandle *)ph, reventsp);
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static int fuse2to3_write_buf(const char *path,
|
|
struct fuse_bufvec *buf, fuse_off_t off, struct fuse_file_info *fi)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res = f3->ops.write_buf(path,
|
|
(struct fuse3_bufvec *)buf, /* revisit if we implement bufvec's */
|
|
off, &fi3);
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static int fuse2to3_read_buf(const char *path,
|
|
struct fuse_bufvec **bufp, size_t size, fuse_off_t off, struct fuse_file_info *fi)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res = f3->ops.read_buf(path,
|
|
(struct fuse3_bufvec **)bufp, /* revisit if we implement bufvec's */
|
|
size, off, &fi3);
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static int fuse2to3_flock(const char *path, struct fuse_file_info *fi, int op)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res = f3->ops.flock(path, &fi3, op);
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static int fuse2to3_fallocate(const char *path, int mode, fuse_off_t off, fuse_off_t len,
|
|
struct fuse_file_info *fi)
|
|
{
|
|
struct fuse3 *f3 = fuse2to3_getfuse3();
|
|
struct fuse3_file_info fi3;
|
|
fuse2to3_fi3from2(&fi3, fi);
|
|
int res = f3->ops.fallocate(path, mode, off, len, &fi3);
|
|
fuse2to3_fi2from3(fi, &fi3);
|
|
return res;
|
|
}
|
|
|
|
static int fsp_fuse3_copy_args(struct fsp_fuse_env *env,
|
|
const struct fuse_args *args,
|
|
struct fuse_args *outargs)
|
|
{
|
|
outargs->argc = 0;
|
|
outargs->argv = 0;
|
|
outargs->allocated = 0;
|
|
|
|
for (int argi = 0; args->argc > argi; argi++)
|
|
if (-1 == fsp_fuse_opt_add_arg(env, outargs, args->argv[argi]))
|
|
goto fail;
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
fsp_fuse_opt_free_args(env, outargs);
|
|
|
|
return -1;
|
|
}
|
|
|
|
static struct fuse3 *fsp_fuse3_new_common(struct fsp_fuse_env *env,
|
|
struct fuse_args *args,
|
|
const struct fuse3_operations *ops, size_t opsize, void *data,
|
|
int help)
|
|
{
|
|
/* preflight args */
|
|
struct fsp_fuse_core_opt_data opt_data;
|
|
struct fuse_args pfargs;
|
|
memset(&opt_data, 0, sizeof opt_data);
|
|
if (-1 == fsp_fuse3_copy_args(env, args, &pfargs))
|
|
return 0;
|
|
int optres = fsp_fuse_core_opt_parse(env, &pfargs, &opt_data, /*help=*/1);
|
|
fsp_fuse_opt_free_args(env, &pfargs);
|
|
if (-1 == optres)
|
|
return 0;
|
|
if (opt_data.help)
|
|
return 0;
|
|
|
|
struct fuse3 *f3 = 0;
|
|
|
|
if (opsize > sizeof(struct fuse3_operations))
|
|
opsize = sizeof(struct fuse3_operations);
|
|
|
|
f3 = fsp_fuse_obj_alloc(env, sizeof *f3);
|
|
if (0 == f3)
|
|
goto fail;
|
|
|
|
if (-1 == fsp_fuse3_copy_args(env, args, &f3->args))
|
|
goto fail;
|
|
memcpy(&f3->ops, ops, opsize);
|
|
f3->data = data;
|
|
|
|
return f3;
|
|
|
|
fail:
|
|
if (0 != f3)
|
|
fsp_fuse3_destroy(env, f3);
|
|
|
|
return 0;
|
|
}
|
|
|
|
FSP_FUSE_API struct fuse3 *fsp_fuse3_new_30(struct fsp_fuse_env *env,
|
|
struct fuse_args *args,
|
|
const struct fuse3_operations *ops, size_t opsize, void *data)
|
|
{
|
|
return fsp_fuse3_new_common(env, args, ops, opsize, data, /*help=*/1);
|
|
}
|
|
|
|
FSP_FUSE_API struct fuse3 *fsp_fuse3_new(struct fsp_fuse_env *env,
|
|
struct fuse_args *args,
|
|
const struct fuse3_operations *ops, size_t opsize, void *data)
|
|
{
|
|
return fsp_fuse3_new_common(env, args, ops, opsize, data, /*help=*/0);
|
|
}
|
|
|
|
FSP_FUSE_API void fsp_fuse3_destroy(struct fsp_fuse_env *env,
|
|
struct fuse3 *f3)
|
|
{
|
|
if (0 != f3->fuse)
|
|
fsp_fuse_destroy(env, f3->fuse);
|
|
|
|
fsp_fuse_opt_free_args(env, &f3->args);
|
|
|
|
fsp_fuse_obj_free(f3);
|
|
}
|
|
|
|
FSP_FUSE_API int fsp_fuse3_mount(struct fsp_fuse_env *env,
|
|
struct fuse3 *f3, const char *mountpoint)
|
|
{
|
|
struct fuse_chan *ch = 0;
|
|
struct fuse *f = 0;
|
|
struct fuse_operations fuse2to3_ops =
|
|
{
|
|
.getattr = 0 != f3->ops.getattr ? fuse2to3_getattr : 0,
|
|
.readlink = 0 != f3->ops.readlink ? fuse2to3_readlink : 0,
|
|
.mknod = 0 != f3->ops.mknod ? fuse2to3_mknod : 0,
|
|
.mkdir = 0 != f3->ops.mkdir ? fuse2to3_mkdir : 0,
|
|
.unlink = 0 != f3->ops.unlink ? fuse2to3_unlink : 0,
|
|
.rmdir = 0 != f3->ops.rmdir ? fuse2to3_rmdir : 0,
|
|
.symlink = 0 != f3->ops.symlink ? fuse2to3_symlink : 0,
|
|
.rename = 0 != f3->ops.rename ? fuse2to3_rename : 0,
|
|
.link = 0 != f3->ops.link ? fuse2to3_link : 0,
|
|
.chmod = 0 != f3->ops.chmod ? fuse2to3_chmod : 0,
|
|
.chown = 0 != f3->ops.chown ? fuse2to3_chown : 0,
|
|
.truncate = 0 != f3->ops.truncate ? fuse2to3_truncate : 0,
|
|
.open = 0 != f3->ops.open ? fuse2to3_open : 0,
|
|
.read = 0 != f3->ops.read ? fuse2to3_read : 0,
|
|
.write = 0 != f3->ops.write ? fuse2to3_write : 0,
|
|
.statfs = 0 != f3->ops.statfs ? fuse2to3_statfs : 0,
|
|
.flush = 0 != f3->ops.flush ? fuse2to3_flush : 0,
|
|
.release = 0 != f3->ops.release ? fuse2to3_release : 0,
|
|
.fsync = 0 != f3->ops.fsync ? fuse2to3_fsync : 0,
|
|
.setxattr = 0 != f3->ops.setxattr ? fuse2to3_setxattr : 0,
|
|
.getxattr = 0 != f3->ops.getxattr ? fuse2to3_getxattr : 0,
|
|
.listxattr = 0 != f3->ops.listxattr ? fuse2to3_listxattr : 0,
|
|
.removexattr = 0 != f3->ops.removexattr ? fuse2to3_removexattr : 0,
|
|
.opendir = 0 != f3->ops.opendir ? fuse2to3_opendir : 0,
|
|
.readdir = 0 != f3->ops.readdir ? fuse2to3_readdir : 0,
|
|
.releasedir = 0 != f3->ops.releasedir ? fuse2to3_releasedir : 0,
|
|
.fsyncdir = 0 != f3->ops.fsyncdir ? fuse2to3_fsyncdir : 0,
|
|
.init = 0 != f3->ops.init ? fuse2to3_init : 0,
|
|
.destroy = 0 != f3->ops.destroy ? fuse2to3_destroy : 0,
|
|
.access = 0 != f3->ops.access ? fuse2to3_access : 0,
|
|
.create = 0 != f3->ops.create ? fuse2to3_create : 0,
|
|
.ftruncate = 0 != f3->ops.truncate ? fuse2to3_ftruncate : 0,
|
|
.fgetattr = 0 != f3->ops.getattr ? fuse2to3_fgetattr : 0,
|
|
.lock = 0 != f3->ops.lock ? fuse2to3_lock : 0,
|
|
.utimens = 0 != f3->ops.utimens ? fuse2to3_utimens : 0,
|
|
.bmap = 0 != f3->ops.bmap ? fuse2to3_bmap : 0,
|
|
.ioctl = 0 != f3->ops.ioctl ? fuse2to3_ioctl : 0,
|
|
.poll = 0 != f3->ops.poll ? fuse2to3_poll : 0,
|
|
.write_buf = 0 != f3->ops.write_buf ? fuse2to3_write_buf : 0,
|
|
.read_buf = 0 != f3->ops.read_buf ? fuse2to3_read_buf : 0,
|
|
.flock = 0 != f3->ops.flock ? fuse2to3_flock : 0,
|
|
.fallocate = 0 != f3->ops.fallocate ? fuse2to3_fallocate : 0,
|
|
};
|
|
|
|
ch = fsp_fuse_mount(env, mountpoint, &f3->args);
|
|
if (0 == ch)
|
|
goto fail;
|
|
|
|
f = fsp_fuse_new(env, ch, &f3->args, &fuse2to3_ops, sizeof fuse2to3_ops, f3->data);
|
|
if (0 == f)
|
|
goto fail;
|
|
|
|
/*
|
|
* Free the fuse_chan which is no longer needed. Note that this behavior is WinFsp-FUSE
|
|
* specific, because WinFsp-FUSE only allocates/frees fuse_chan memory during fuse_mount/
|
|
* fuse_unmount and does not perform any actual mounting/unmounting. This would not work
|
|
* on a different FUSE implementation.
|
|
*
|
|
* (Store mountpoint and ch inside struct fuse3 so that they can be freed during fuse_destroy
|
|
* in that case.)
|
|
*/
|
|
fsp_fuse_unmount(env, mountpoint, ch);
|
|
|
|
/* Free the args which are no longer needed. */
|
|
fsp_fuse_opt_free_args(env, &f3->args);
|
|
|
|
f->fuse3 = f3;
|
|
f3->fuse = f;
|
|
|
|
return 0;
|
|
|
|
fail:
|
|
if (0 != f)
|
|
fsp_fuse_destroy(env, f);
|
|
|
|
if (0 != ch)
|
|
fsp_fuse_unmount(env, mountpoint, ch);
|
|
|
|
return -1;
|
|
}
|
|
|
|
FSP_FUSE_API void fsp_fuse3_unmount(struct fsp_fuse_env *env,
|
|
struct fuse3 *f3)
|
|
{
|
|
fsp_fuse_destroy(env, f3->fuse);
|
|
f3->fuse = 0;
|
|
}
|