mirror of
https://github.com/trapexit/mergerfs.git
synced 2024-11-25 09:41:43 +08:00
restructure readdir, add readdir_plus
Does not enable READDIR_AUTO. Might add in the future.
This commit is contained in:
parent
10e8bd9fa3
commit
d119807adb
2
LICENSE
2
LICENSE
|
@ -1,7 +1,7 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
Copyright (c) 2019, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
|
|
|
@ -23,6 +23,7 @@ INSTALLMAN1DIR = $(DESTDIR)$(MAN1DIR)
|
|||
SRC = \
|
||||
lib/buffer.c \
|
||||
lib/cuse_lowlevel.c \
|
||||
lib/fuse_dirents.c \
|
||||
lib/fuse.c \
|
||||
lib/fuse_kern_chan.c \
|
||||
lib/fuse_loop.c \
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#endif
|
||||
|
||||
#include "fuse_common.h"
|
||||
#include "fuse_dirents.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
|
@ -47,22 +48,6 @@ struct fuse;
|
|||
/** Structure containing a raw command */
|
||||
struct fuse_cmd;
|
||||
|
||||
/** Function to add an entry in a readdir() operation
|
||||
*
|
||||
* @param buf the buffer passed to the readdir() operation
|
||||
* @param name the file name of the directory entry
|
||||
* @param stat file attributes, can be NULL
|
||||
* @param off offset of the next entry or zero
|
||||
* @return 1 if buffer is full, zero otherwise
|
||||
*/
|
||||
typedef int (*fuse_fill_dir_t) (void *buf, const char *name,
|
||||
const struct stat *stbuf, off_t off);
|
||||
|
||||
/* Used by deprecated getdir() method */
|
||||
typedef struct fuse_dirhandle *fuse_dirh_t;
|
||||
typedef int (*fuse_dirfil_t) (fuse_dirh_t h, const char *name, int type,
|
||||
ino_t ino);
|
||||
|
||||
/**
|
||||
* The file system operations:
|
||||
*
|
||||
|
@ -104,9 +89,6 @@ struct fuse_operations {
|
|||
*/
|
||||
int (*readlink) (const char *, char *, size_t);
|
||||
|
||||
/* Deprecated, use readdir() instead */
|
||||
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
|
||||
|
||||
/** Create a file node
|
||||
*
|
||||
* This is called for creation of all non-directory, non-symlink
|
||||
|
@ -312,8 +294,12 @@ struct fuse_operations {
|
|||
*
|
||||
* Introduced in version 2.3
|
||||
*/
|
||||
int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
|
||||
struct fuse_file_info *);
|
||||
int (*readdir)(struct fuse_file_info *,
|
||||
fuse_dirents_t *);
|
||||
|
||||
int (*readdir_plus)(struct fuse_file_info *,
|
||||
fuse_dirents_t *);
|
||||
|
||||
|
||||
/** Release directory
|
||||
*
|
||||
|
@ -898,9 +884,9 @@ int fuse_fs_flush(struct fuse_fs *fs, const char *path,
|
|||
int fuse_fs_statfs(struct fuse_fs *fs, const char *path, struct statvfs *buf);
|
||||
int fuse_fs_opendir(struct fuse_fs *fs, const char *path,
|
||||
struct fuse_file_info *fi);
|
||||
int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf,
|
||||
fuse_fill_dir_t filler, off_t off,
|
||||
struct fuse_file_info *fi);
|
||||
int fuse_fs_readdir(struct fuse_fs *fs,
|
||||
struct fuse_file_info *fi,
|
||||
fuse_dirents_t *buf);
|
||||
int fuse_fs_fsyncdir(struct fuse_fs *fs, const char *path, int datasync,
|
||||
struct fuse_file_info *fi);
|
||||
int fuse_fs_releasedir(struct fuse_fs *fs, const char *path,
|
||||
|
|
24
libfuse/include/fuse_attr.h
Normal file
24
libfuse/include/fuse_attr.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct fuse_attr_s fuse_attr_t;
|
||||
struct fuse_attr_s
|
||||
{
|
||||
uint64_t ino;
|
||||
uint64_t size;
|
||||
uint64_t blocks;
|
||||
uint64_t atime;
|
||||
uint64_t mtime;
|
||||
uint64_t ctime;
|
||||
uint32_t atimensec;
|
||||
uint32_t mtimensec;
|
||||
uint32_t ctimensec;
|
||||
uint32_t mode;
|
||||
uint32_t nlink;
|
||||
uint32_t uid;
|
||||
uint32_t gid;
|
||||
uint32_t rdev;
|
||||
uint32_t blksize;
|
||||
uint32_t _padding;
|
||||
};
|
|
@ -120,6 +120,8 @@ fuse_file_info
|
|||
#define FUSE_CAP_SPLICE_READ (1 << 9)
|
||||
#define FUSE_CAP_FLOCK_LOCKS (1 << 10)
|
||||
#define FUSE_CAP_IOCTL_DIR (1 << 11)
|
||||
#define FUSE_CAP_READDIR_PLUS (1 << 13)
|
||||
#define FUSE_CAP_READDIR_PLUS_AUTO (1 << 14)
|
||||
#define FUSE_CAP_ASYNC_DIO (1 << 15)
|
||||
#define FUSE_CAP_WRITEBACK_CACHE (1 << 16)
|
||||
#define FUSE_CAP_PARALLEL_DIROPS (1 << 18)
|
||||
|
@ -127,7 +129,6 @@ fuse_file_info
|
|||
#define FUSE_CAP_CACHE_SYMLINKS (1 << 20)
|
||||
#define FUSE_CAP_MAX_PAGES (1 << 21)
|
||||
|
||||
|
||||
/**
|
||||
* Ioctl flags
|
||||
*
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
struct fuse_operations_compat25 {
|
||||
int (*getattr) (const char *, struct stat *);
|
||||
int (*readlink) (const char *, char *, size_t);
|
||||
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
|
||||
int (*mknod) (const char *, mode_t, dev_t);
|
||||
int (*mkdir) (const char *, mode_t);
|
||||
int (*unlink) (const char *);
|
||||
|
@ -38,7 +37,7 @@ struct fuse_operations_compat25 {
|
|||
int (*listxattr) (const char *, char *, size_t);
|
||||
int (*removexattr) (const char *, const char *);
|
||||
int (*opendir) (const char *, struct fuse_file_info *);
|
||||
int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
|
||||
int (*readdir) (const char *, void *, off_t,
|
||||
struct fuse_file_info *);
|
||||
int (*releasedir) (const char *, struct fuse_file_info *);
|
||||
int (*fsyncdir) (const char *, int, struct fuse_file_info *);
|
||||
|
@ -71,7 +70,6 @@ void fuse_teardown_compat22(struct fuse *fuse, int fd, char *mountpoint);
|
|||
struct fuse_operations_compat22 {
|
||||
int (*getattr) (const char *, struct stat *);
|
||||
int (*readlink) (const char *, char *, size_t);
|
||||
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t);
|
||||
int (*mknod) (const char *, mode_t, dev_t);
|
||||
int (*mkdir) (const char *, mode_t);
|
||||
int (*unlink) (const char *);
|
||||
|
@ -97,7 +95,7 @@ struct fuse_operations_compat22 {
|
|||
int (*listxattr) (const char *, char *, size_t);
|
||||
int (*removexattr) (const char *, const char *);
|
||||
int (*opendir) (const char *, struct fuse_file_info_compat *);
|
||||
int (*readdir) (const char *, void *, fuse_fill_dir_t, off_t,
|
||||
int (*readdir) (const char *, void *, off_t,
|
||||
struct fuse_file_info_compat *);
|
||||
int (*releasedir) (const char *, struct fuse_file_info_compat *);
|
||||
int (*fsyncdir) (const char *, int, struct fuse_file_info_compat *);
|
||||
|
@ -118,11 +116,9 @@ int fuse_main_real_compat22(int argc, char *argv[],
|
|||
const struct fuse_operations_compat22 *op,
|
||||
size_t op_size);
|
||||
|
||||
typedef int (*fuse_dirfil_t_compat) (fuse_dirh_t h, const char *name, int type);
|
||||
struct fuse_operations_compat2 {
|
||||
int (*getattr) (const char *, struct stat *);
|
||||
int (*readlink) (const char *, char *, size_t);
|
||||
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t_compat);
|
||||
int (*mknod) (const char *, mode_t, dev_t);
|
||||
int (*mkdir) (const char *, mode_t);
|
||||
int (*unlink) (const char *);
|
||||
|
@ -170,7 +166,6 @@ struct fuse_statfs_compat1 {
|
|||
struct fuse_operations_compat1 {
|
||||
int (*getattr) (const char *, struct stat *);
|
||||
int (*readlink) (const char *, char *, size_t);
|
||||
int (*getdir) (const char *, fuse_dirh_t, fuse_dirfil_t_compat);
|
||||
int (*mknod) (const char *, mode_t, dev_t);
|
||||
int (*mkdir) (const char *, mode_t);
|
||||
int (*unlink) (const char *);
|
||||
|
|
31
libfuse/include/fuse_dirent.h
Normal file
31
libfuse/include/fuse_dirent.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2019, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct fuse_dirent_s fuse_dirent_t;
|
||||
struct fuse_dirent_s
|
||||
{
|
||||
uint64_t ino;
|
||||
uint64_t off;
|
||||
uint32_t namelen;
|
||||
uint32_t type;
|
||||
char name[];
|
||||
};
|
31
libfuse/include/fuse_direntplus.h
Normal file
31
libfuse/include/fuse_direntplus.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2019, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "fuse_attr.h"
|
||||
#include "fuse_dirent.h"
|
||||
#include "fuse_entry.h"
|
||||
|
||||
typedef struct fuse_direntplus_s fuse_direntplus_t;
|
||||
struct fuse_direntplus_s
|
||||
{
|
||||
fuse_entry_t entry;
|
||||
fuse_attr_t attr;
|
||||
fuse_dirent_t dirent;
|
||||
};
|
71
libfuse/include/fuse_dirents.h
Normal file
71
libfuse/include/fuse_dirents.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2019, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "fuse_dirent.h"
|
||||
#include "fuse_direntplus.h"
|
||||
#include "fuse_entry.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
enum fuse_dirents_type_e
|
||||
{
|
||||
UNSET = 0,
|
||||
NORMAL,
|
||||
PLUS
|
||||
};
|
||||
typedef enum fuse_dirents_type_e fuse_dirents_type_t;
|
||||
|
||||
typedef struct fuse_dirents_s fuse_dirents_t;
|
||||
struct fuse_dirents_s
|
||||
{
|
||||
char *buf;
|
||||
uint64_t buf_len;
|
||||
uint64_t data_len;
|
||||
fuse_dirents_type_t type;
|
||||
};
|
||||
|
||||
int fuse_dirents_init(fuse_dirents_t *d);
|
||||
void fuse_dirents_free(fuse_dirents_t *d);
|
||||
void fuse_dirents_reset(fuse_dirents_t *d);
|
||||
|
||||
int fuse_dirents_add(fuse_dirents_t *d,
|
||||
struct dirent *de);
|
||||
int fuse_dirents_add_plus(fuse_dirents_t *d,
|
||||
const struct dirent *de,
|
||||
const fuse_entry_t *entry,
|
||||
const struct stat *st);
|
||||
|
||||
void *fuse_dirents_find(fuse_dirents_t *d,
|
||||
const uint64_t ino);
|
||||
|
||||
int fuse_dirents_convert_plus2normal(fuse_dirents_t *d);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
14
libfuse/include/fuse_entry.h
Normal file
14
libfuse/include/fuse_entry.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct fuse_entry_s fuse_entry_t;
|
||||
struct fuse_entry_s
|
||||
{
|
||||
uint64_t nodeid;
|
||||
uint64_t generation;
|
||||
uint64_t entry_valid;
|
||||
uint64_t attr_valid;
|
||||
uint32_t entry_valid_nsec;
|
||||
uint32_t attr_valid_nsec;
|
||||
};
|
|
@ -605,7 +605,11 @@ struct fuse_lowlevel_ops {
|
|||
* @param fi file information
|
||||
*/
|
||||
void (*readdir) (fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
|
||||
struct fuse_file_info *fi);
|
||||
struct fuse_file_info *llffi);
|
||||
|
||||
void (*readdir_plus)(fuse_req_t req, fuse_ino_t ino,
|
||||
size_t size, off_t off,
|
||||
struct fuse_file_info *ffi);
|
||||
|
||||
/**
|
||||
* Release an open directory
|
||||
|
@ -1262,38 +1266,6 @@ int fuse_reply_lock(fuse_req_t req, const struct flock *lock);
|
|||
*/
|
||||
int fuse_reply_bmap(fuse_req_t req, uint64_t idx);
|
||||
|
||||
/* ----------------------------------------------------------- *
|
||||
* Filling a buffer in readdir *
|
||||
* ----------------------------------------------------------- */
|
||||
|
||||
/**
|
||||
* Add a directory entry to the buffer
|
||||
*
|
||||
* Buffer needs to be large enough to hold the entry. If it's not,
|
||||
* then the entry is not filled in but the size of the entry is still
|
||||
* returned. The caller can check this by comparing the bufsize
|
||||
* parameter with the returned entry size. If the entry size is
|
||||
* larger than the buffer size, the operation failed.
|
||||
*
|
||||
* From the 'stbuf' argument the st_ino field and bits 12-15 of the
|
||||
* st_mode field are used. The other fields are ignored.
|
||||
*
|
||||
* Note: offsets do not necessarily represent physical offsets, and
|
||||
* could be any marker, that enables the implementation to find a
|
||||
* specific point in the directory stream.
|
||||
*
|
||||
* @param req request handle
|
||||
* @param buf the point where the new entry will be added to the buffer
|
||||
* @param bufsize remaining size of the buffer
|
||||
* @param name the name of the entry
|
||||
* @param stbuf the file attributes
|
||||
* @param off the offset of the next entry
|
||||
* @return the space needed for the entry
|
||||
*/
|
||||
size_t fuse_add_direntry(fuse_req_t req, char *buf, size_t bufsize,
|
||||
const char *name, const struct stat *stbuf,
|
||||
off_t off);
|
||||
|
||||
/**
|
||||
* Reply to ask for data fetch and output buffer preparation. ioctl
|
||||
* will be retried with the specified input data fetched and output
|
||||
|
|
17
libfuse/include/stat_utils.h
Normal file
17
libfuse/include/stat_utils.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#ifdef HAVE_STRUCT_STAT_ST_ATIM
|
||||
#define ST_ATIM_NSEC(ST) ((ST)->st_atim.tv_nsec)
|
||||
#define ST_CTIM_NSEC(ST) ((ST)->st_ctim.tv_nsec)
|
||||
#define ST_MTIM_NSEC(ST) ((ST)->st_mtim.tv_nsec)
|
||||
#elif defined HAVE_STRUCT_STAT_ST_ATIMESPEC
|
||||
#define ST_ATIM_NSEC(ST) ((ST)->st_atimespec.tv_nsec)
|
||||
#define ST_CTIM_NSEC(ST) ((ST)->st_ctimespec.tv_nsec)
|
||||
#define ST_MTIM_NSEC(ST) ((ST)->st_mtimespec.tv_nsec)
|
||||
#else
|
||||
#define ST_ATIM_NSEC(ST) 0
|
||||
#define ST_CTIM_NSEC(ST) 0
|
||||
#define ST_MTIM_NSEC(ST) 0
|
||||
#endif
|
|
@ -18,6 +18,7 @@
|
|||
#include "fuse_common_compat.h"
|
||||
#include "fuse_compat.h"
|
||||
#include "fuse_kernel.h"
|
||||
#include "fuse_dirents.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <dlfcn.h>
|
||||
|
@ -64,7 +65,6 @@ struct fuse_config {
|
|||
int nopath;
|
||||
int debug;
|
||||
int use_ino;
|
||||
int readdir_ino;
|
||||
int set_mode;
|
||||
int set_uid;
|
||||
int set_gid;
|
||||
|
@ -183,25 +183,11 @@ struct node_lru {
|
|||
struct timespec forget_time;
|
||||
};
|
||||
|
||||
struct fuse_dh {
|
||||
struct fuse_dh
|
||||
{
|
||||
pthread_mutex_t lock;
|
||||
struct fuse *fuse;
|
||||
fuse_req_t req;
|
||||
char *contents;
|
||||
int allocated;
|
||||
unsigned len;
|
||||
unsigned size;
|
||||
unsigned needlen;
|
||||
int filled;
|
||||
uint64_t fh;
|
||||
int error;
|
||||
fuse_ino_t nodeid;
|
||||
};
|
||||
|
||||
/* old dir handle */
|
||||
struct fuse_dirhandle {
|
||||
fuse_fill_dir_t filler;
|
||||
void *buf;
|
||||
fuse_dirents_t d;
|
||||
};
|
||||
|
||||
struct fuse_context_i {
|
||||
|
@ -1097,15 +1083,22 @@ static int get_path(struct fuse *f, fuse_ino_t nodeid, char **path)
|
|||
return get_path_common(f, nodeid, NULL, path, NULL);
|
||||
}
|
||||
|
||||
static int get_path_nullok(struct fuse *f, fuse_ino_t nodeid, char **path)
|
||||
static
|
||||
int
|
||||
get_path_nullok(struct fuse *f,
|
||||
fuse_ino_t nodeid,
|
||||
char **path)
|
||||
{
|
||||
int err = 0;
|
||||
|
||||
if (f->conf.nopath) {
|
||||
if(f->conf.nopath)
|
||||
{
|
||||
*path = NULL;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
err = get_path_common(f,nodeid,NULL,path,NULL);
|
||||
if (err == -ENOENT && f->nullpath_ok)
|
||||
if((err == -ENOENT) && f->nullpath_ok)
|
||||
err = 0;
|
||||
}
|
||||
|
||||
|
@ -1929,45 +1922,30 @@ int fuse_fs_releasedir(struct fuse_fs *fs, const char *path,
|
|||
}
|
||||
}
|
||||
|
||||
static int fill_dir_old(struct fuse_dirhandle *dh, const char *name, int type,
|
||||
ino_t ino)
|
||||
int
|
||||
fuse_fs_readdir(struct fuse_fs *fs,
|
||||
struct fuse_file_info *fi,
|
||||
fuse_dirents_t *buf)
|
||||
{
|
||||
int res;
|
||||
struct stat stbuf;
|
||||
|
||||
memset(&stbuf, 0, sizeof(stbuf));
|
||||
stbuf.st_mode = type << 12;
|
||||
stbuf.st_ino = ino;
|
||||
|
||||
res = dh->filler(dh->buf, name, &stbuf, 0);
|
||||
return res ? -ENOMEM : 0;
|
||||
}
|
||||
|
||||
int fuse_fs_readdir(struct fuse_fs *fs, const char *path, void *buf,
|
||||
fuse_fill_dir_t filler, off_t off,
|
||||
struct fuse_file_info *fi)
|
||||
{
|
||||
fuse_get_context()->private_data = fs->user_data;
|
||||
if (fs->op.readdir) {
|
||||
if (fs->debug)
|
||||
fprintf(stderr, "readdir[%llu] from %llu\n",
|
||||
(unsigned long long) fi->fh,
|
||||
(unsigned long long) off);
|
||||
|
||||
return fs->op.readdir(path, buf, filler, off, fi);
|
||||
} else if (fs->op.getdir) {
|
||||
struct fuse_dirhandle dh;
|
||||
|
||||
if (fs->debug)
|
||||
fprintf(stderr, "getdir[%llu]\n",
|
||||
(unsigned long long) fi->fh);
|
||||
|
||||
dh.filler = filler;
|
||||
dh.buf = buf;
|
||||
return fs->op.getdir(path, &dh, fill_dir_old);
|
||||
} else {
|
||||
if(fs->op.readdir == NULL)
|
||||
return -ENOSYS;
|
||||
|
||||
fuse_get_context()->private_data = fs->user_data;
|
||||
|
||||
return fs->op.readdir(fi,buf);
|
||||
}
|
||||
|
||||
int
|
||||
fuse_fs_readdir_plus(struct fuse_fs *fs_,
|
||||
struct fuse_file_info *ffi_,
|
||||
fuse_dirents_t *buf_)
|
||||
{
|
||||
if(fs_->op.readdir_plus == NULL)
|
||||
return -ENOSYS;
|
||||
|
||||
fuse_get_context()->private_data = fs_->user_data;
|
||||
|
||||
return fs_->op.readdir_plus(ffi_,buf_);
|
||||
}
|
||||
|
||||
int fuse_fs_create(struct fuse_fs *fs, const char *path, mode_t mode,
|
||||
|
@ -3370,18 +3348,13 @@ static void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino,
|
|||
char *path;
|
||||
int err;
|
||||
|
||||
dh = (struct fuse_dh *) malloc(sizeof(struct fuse_dh));
|
||||
dh = (struct fuse_dh *) calloc(1,sizeof(struct fuse_dh));
|
||||
if (dh == NULL) {
|
||||
reply_err(req, -ENOMEM);
|
||||
return;
|
||||
}
|
||||
|
||||
memset(dh, 0, sizeof(struct fuse_dh));
|
||||
dh->fuse = f;
|
||||
dh->contents = NULL;
|
||||
dh->len = 0;
|
||||
dh->filled = 0;
|
||||
dh->nodeid = ino;
|
||||
fuse_dirents_init(&dh->d);
|
||||
fuse_mutex_init(&dh->lock);
|
||||
|
||||
llfi->fh = (uintptr_t) dh;
|
||||
|
@ -3415,175 +3388,180 @@ static void fuse_lib_opendir(fuse_req_t req, fuse_ino_t ino,
|
|||
free_path(f, ino, path);
|
||||
}
|
||||
|
||||
static int extend_contents(struct fuse_dh *dh, unsigned minsize)
|
||||
static
|
||||
int
|
||||
readdir_fill(struct fuse *f_,
|
||||
fuse_req_t req_,
|
||||
fuse_dirents_t *d_,
|
||||
struct fuse_file_info *fi_)
|
||||
{
|
||||
if (minsize > dh->size) {
|
||||
char *newptr;
|
||||
unsigned newsize = dh->size;
|
||||
if (!newsize)
|
||||
newsize = 1024;
|
||||
while (newsize < minsize) {
|
||||
if (newsize >= 0x80000000)
|
||||
newsize = 0xffffffff;
|
||||
else
|
||||
newsize *= 2;
|
||||
int rv;
|
||||
struct fuse_intr_data intr_data;
|
||||
|
||||
fuse_prepare_interrupt(f_,req_,&intr_data);
|
||||
rv = fuse_fs_readdir(f_->fs,fi_,d_);
|
||||
fuse_finish_interrupt(f_,req_,&intr_data);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
newptr = (char *) realloc(dh->contents, newsize);
|
||||
if (!newptr) {
|
||||
dh->error = -ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
dh->contents = newptr;
|
||||
dh->size = newsize;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int fill_dir(void *dh_, const char *name, const struct stat *statp,
|
||||
off_t off)
|
||||
static
|
||||
int
|
||||
readdir_plus_fill(struct fuse *f_,
|
||||
fuse_req_t req_,
|
||||
fuse_dirents_t *d_,
|
||||
struct fuse_file_info *fi_)
|
||||
{
|
||||
struct fuse_dh *dh = (struct fuse_dh *) dh_;
|
||||
struct stat stbuf;
|
||||
size_t newlen;
|
||||
int rv;
|
||||
struct fuse_intr_data intr_data;
|
||||
|
||||
if (statp)
|
||||
stbuf = *statp;
|
||||
else {
|
||||
memset(&stbuf, 0, sizeof(stbuf));
|
||||
stbuf.st_ino = FUSE_UNKNOWN_INO;
|
||||
fuse_prepare_interrupt(f_,req_,&intr_data);
|
||||
rv = fuse_fs_readdir_plus(f_->fs,fi_,d_);
|
||||
fuse_finish_interrupt(f_,req_,&intr_data);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!dh->fuse->conf.use_ino) {
|
||||
stbuf.st_ino = FUSE_UNKNOWN_INO;
|
||||
if (dh->fuse->conf.readdir_ino) {
|
||||
struct node *node;
|
||||
pthread_mutex_lock(&dh->fuse->lock);
|
||||
node = lookup_node(dh->fuse, dh->nodeid, name);
|
||||
if (node)
|
||||
stbuf.st_ino = (ino_t) node->nodeid;
|
||||
pthread_mutex_unlock(&dh->fuse->lock);
|
||||
}
|
||||
}
|
||||
|
||||
if (off) {
|
||||
if (extend_contents(dh, dh->needlen) == -1)
|
||||
return 1;
|
||||
|
||||
dh->filled = 0;
|
||||
newlen = dh->len +
|
||||
fuse_add_direntry(dh->req, dh->contents + dh->len,
|
||||
dh->needlen - dh->len, name,
|
||||
&stbuf, off);
|
||||
if (newlen > dh->needlen)
|
||||
return 1;
|
||||
} else {
|
||||
newlen = dh->len +
|
||||
fuse_add_direntry(dh->req, NULL, 0, name, NULL, 0);
|
||||
if (extend_contents(dh, newlen) == -1)
|
||||
return 1;
|
||||
|
||||
fuse_add_direntry(dh->req, dh->contents + dh->len,
|
||||
dh->size - dh->len, name, &stbuf, newlen);
|
||||
}
|
||||
dh->len = newlen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int readdir_fill(struct fuse *f, fuse_req_t req, fuse_ino_t ino,
|
||||
size_t size, off_t off, struct fuse_dh *dh,
|
||||
struct fuse_file_info *fi)
|
||||
static
|
||||
uint64_t
|
||||
convert_plus2normal(fuse_dirents_t *d_,
|
||||
uint64_t off_)
|
||||
{
|
||||
char *path;
|
||||
int err;
|
||||
uint64_t ino;
|
||||
fuse_dirent_t *d;
|
||||
fuse_direntplus_t *dp;
|
||||
|
||||
if (f->fs->op.readdir)
|
||||
err = get_path_nullok(f, ino, &path);
|
||||
else
|
||||
err = get_path(f, ino, &path);
|
||||
if (!err) {
|
||||
struct fuse_intr_data d;
|
||||
dp = (fuse_direntplus_t*)&d_->buf[off_];
|
||||
ino = dp->dirent.ino;
|
||||
fuse_dirents_convert_plus2normal(d_);
|
||||
d = fuse_dirents_find(d_,ino);
|
||||
|
||||
dh->len = 0;
|
||||
dh->error = 0;
|
||||
dh->needlen = size;
|
||||
dh->filled = 1;
|
||||
dh->req = req;
|
||||
fuse_prepare_interrupt(f, req, &d);
|
||||
err = fuse_fs_readdir(f->fs, path, dh, fill_dir, off, fi);
|
||||
fuse_finish_interrupt(f, req, &d);
|
||||
dh->req = NULL;
|
||||
if (!err)
|
||||
err = dh->error;
|
||||
if (err)
|
||||
dh->filled = 0;
|
||||
free_path(f, ino, path);
|
||||
}
|
||||
return err;
|
||||
return d->off;
|
||||
}
|
||||
|
||||
static void fuse_lib_readdir(fuse_req_t req, fuse_ino_t ino, size_t size,
|
||||
off_t off, struct fuse_file_info *llfi)
|
||||
static
|
||||
void
|
||||
fuse_lib_readdir(fuse_req_t req_,
|
||||
fuse_ino_t ino_,
|
||||
size_t size_,
|
||||
off_t off_,
|
||||
struct fuse_file_info *llffi_)
|
||||
{
|
||||
struct fuse *f = req_fuse_prepare(req);
|
||||
int rv;
|
||||
struct fuse *f;
|
||||
fuse_dirents_t *d;
|
||||
struct fuse_dh *dh;
|
||||
struct fuse_file_info fi;
|
||||
struct fuse_dh *dh = get_dirhandle(llfi, &fi);
|
||||
|
||||
f = req_fuse_prepare(req_);
|
||||
dh = get_dirhandle(llffi_,&fi);
|
||||
d = &dh->d;
|
||||
|
||||
pthread_mutex_lock(&dh->lock);
|
||||
/* According to SUS, directory contents need to be refreshed on
|
||||
rewinddir() */
|
||||
if (!off)
|
||||
dh->filled = 0;
|
||||
|
||||
if (!dh->filled) {
|
||||
int err = readdir_fill(f, req, ino, size, off, dh, &fi);
|
||||
if (err) {
|
||||
reply_err(req, err);
|
||||
rv = 0;
|
||||
if(off_ == 0)
|
||||
rv = readdir_fill(f,req_,d,&fi);
|
||||
|
||||
if(rv)
|
||||
{
|
||||
reply_err(req_,rv);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
if (dh->filled) {
|
||||
if (off < dh->len) {
|
||||
if (off + size > dh->len)
|
||||
size = dh->len - off;
|
||||
} else
|
||||
size = 0;
|
||||
} else {
|
||||
size = dh->len;
|
||||
off = 0;
|
||||
}
|
||||
fuse_reply_buf(req, dh->contents + off, size);
|
||||
|
||||
if(off_ >= d->data_len)
|
||||
size_ = 0;
|
||||
else if((off_ + size_) > d->data_len)
|
||||
size_ = (d->data_len - off_);
|
||||
|
||||
/* if((size_ > 0) && (d->type == PLUS)) */
|
||||
/* off_ = convert_plus2normal(d,off_); */
|
||||
|
||||
fuse_reply_buf(req_,
|
||||
&d->buf[off_],
|
||||
size_);
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&dh->lock);
|
||||
}
|
||||
|
||||
static void fuse_lib_releasedir(fuse_req_t req, fuse_ino_t ino,
|
||||
struct fuse_file_info *llfi)
|
||||
static
|
||||
void
|
||||
fuse_lib_readdir_plus(fuse_req_t req_,
|
||||
fuse_ino_t ino_,
|
||||
size_t size_,
|
||||
off_t off_,
|
||||
struct fuse_file_info *llffi_)
|
||||
{
|
||||
struct fuse *f = req_fuse_prepare(req);
|
||||
int rv;
|
||||
struct fuse *f;
|
||||
fuse_dirents_t *d;
|
||||
struct fuse_dh *dh;
|
||||
struct fuse_file_info fi;
|
||||
|
||||
f = req_fuse_prepare(req_);
|
||||
dh = get_dirhandle(llffi_,&fi);
|
||||
d = &dh->d;
|
||||
|
||||
pthread_mutex_lock(&dh->lock);
|
||||
|
||||
rv = 0;
|
||||
if(off_ == 0)
|
||||
rv = readdir_plus_fill(f,req_,d,&fi);
|
||||
|
||||
if(rv)
|
||||
{
|
||||
reply_err(req_,rv);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if(off_ >= d->data_len)
|
||||
size_ = 0;
|
||||
else if((off_ + size_) > d->data_len)
|
||||
size_ = (d->data_len - off_);
|
||||
|
||||
fuse_reply_buf(req_,
|
||||
&d->buf[off_],
|
||||
size_);
|
||||
|
||||
out:
|
||||
pthread_mutex_unlock(&dh->lock);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
fuse_lib_releasedir(fuse_req_t req_,
|
||||
fuse_ino_t ino_,
|
||||
struct fuse_file_info *llfi_)
|
||||
{
|
||||
struct fuse *f;
|
||||
struct fuse_dh *dh;
|
||||
struct fuse_intr_data d;
|
||||
struct fuse_file_info fi;
|
||||
struct fuse_dh *dh = get_dirhandle(llfi, &fi);
|
||||
char *path;
|
||||
const char *compatpath;
|
||||
|
||||
get_path_nullok(f, ino, &path);
|
||||
f = req_fuse_prepare(req_);
|
||||
dh = get_dirhandle(llfi_,&fi);
|
||||
|
||||
get_path_nullok(f,ino_,&path);
|
||||
if (path != NULL || f->nullpath_ok || f->conf.nopath)
|
||||
compatpath = path;
|
||||
else
|
||||
compatpath = "-";
|
||||
|
||||
fuse_prepare_interrupt(f, req, &d);
|
||||
fuse_prepare_interrupt(f,req_,&d);
|
||||
fuse_fs_releasedir(f->fs,compatpath,&fi);
|
||||
fuse_finish_interrupt(f, req, &d);
|
||||
free_path(f, ino, path);
|
||||
fuse_finish_interrupt(f,req_,&d);
|
||||
free_path(f,ino_,path);
|
||||
|
||||
/* Done to keep race condition between last readdir reply and the unlock */
|
||||
pthread_mutex_lock(&dh->lock);
|
||||
pthread_mutex_unlock(&dh->lock);
|
||||
pthread_mutex_destroy(&dh->lock);
|
||||
free(dh->contents);
|
||||
fuse_dirents_free(&dh->d);
|
||||
free(dh);
|
||||
reply_err(req, 0);
|
||||
reply_err(req_,0);
|
||||
}
|
||||
|
||||
static void fuse_lib_fsyncdir(fuse_req_t req, fuse_ino_t ino, int datasync,
|
||||
|
@ -4273,6 +4251,7 @@ static struct fuse_lowlevel_ops fuse_path_ops = {
|
|||
.fsync = fuse_lib_fsync,
|
||||
.opendir = fuse_lib_opendir,
|
||||
.readdir = fuse_lib_readdir,
|
||||
.readdir_plus = fuse_lib_readdir_plus,
|
||||
.releasedir = fuse_lib_releasedir,
|
||||
.fsyncdir = fuse_lib_fsyncdir,
|
||||
.statfs = fuse_lib_statfs,
|
||||
|
@ -4484,8 +4463,6 @@ static const struct fuse_opt fuse_lib_opts[] = {
|
|||
FUSE_OPT_KEY("-d", FUSE_OPT_KEY_KEEP),
|
||||
FUSE_LIB_OPT("debug", debug, 1),
|
||||
FUSE_LIB_OPT("-d", debug, 1),
|
||||
FUSE_LIB_OPT("use_ino", use_ino, 1),
|
||||
FUSE_LIB_OPT("readdir_ino", readdir_ino, 1),
|
||||
FUSE_LIB_OPT("umask=", set_mode, 1),
|
||||
FUSE_LIB_OPT("umask=%o", umask, 0),
|
||||
FUSE_LIB_OPT("uid=", set_uid, 1),
|
||||
|
@ -4501,14 +4478,13 @@ static const struct fuse_opt fuse_lib_opts[] = {
|
|||
FUSE_LIB_OPT("intr", intr, 1),
|
||||
FUSE_LIB_OPT("intr_signal=%d", intr_signal, 0),
|
||||
FUSE_LIB_OPT("threads=%d", threads, 0),
|
||||
FUSE_LIB_OPT("use_ino", use_ino, 1),
|
||||
FUSE_OPT_END
|
||||
};
|
||||
|
||||
static void fuse_lib_help(void)
|
||||
{
|
||||
fprintf(stderr,
|
||||
" -o use_ino let filesystem set inode numbers\n"
|
||||
" -o readdir_ino try to fill in d_ino in readdir\n"
|
||||
" -o umask=M set file permissions (octal)\n"
|
||||
" -o uid=N set file owner\n"
|
||||
" -o gid=N set file group\n"
|
||||
|
@ -4695,14 +4671,6 @@ struct fuse *fuse_new_common(struct fuse_chan *ch, struct fuse_args *args,
|
|||
fuse_lib_opt_proc) == -1)
|
||||
goto out_free_fs;
|
||||
|
||||
#if defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
/*
|
||||
* In FreeBSD, we always use these settings as inode numbers
|
||||
* are needed to make getcwd(3) work.
|
||||
*/
|
||||
f->conf.readdir_ino = 1;
|
||||
#endif
|
||||
|
||||
if (compat && compat <= 25) {
|
||||
if (fuse_sync_compat_args(args) == -1)
|
||||
goto out_free_fs;
|
||||
|
|
346
libfuse/lib/fuse_dirents.c
Normal file
346
libfuse/lib/fuse_dirents.c
Normal file
|
@ -0,0 +1,346 @@
|
|||
#define _FILE_OFFSET_BITS 64
|
||||
|
||||
#include "fuse_attr.h"
|
||||
#include "fuse_dirent.h"
|
||||
#include "fuse_direntplus.h"
|
||||
#include "fuse_dirents.h"
|
||||
#include "fuse_entry.h"
|
||||
#include "stat_utils.h"
|
||||
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define DEFAULT_SIZE (1024 * 16)
|
||||
|
||||
#ifndef _D_EXACT_NAMLEN
|
||||
# define _D_EXACT_NAMLEN(d) ((d)->d_namlen)
|
||||
#endif
|
||||
|
||||
static
|
||||
uint64_t
|
||||
align_uint64_t(uint64_t v_)
|
||||
{
|
||||
return ((v_ + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1));
|
||||
}
|
||||
|
||||
static
|
||||
uint64_t
|
||||
fuse_dirent_size(const uint64_t namelen_)
|
||||
{
|
||||
uint64_t rv;
|
||||
|
||||
rv = offsetof(fuse_dirent_t,name);
|
||||
rv += namelen_;
|
||||
rv = align_uint64_t(rv);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static
|
||||
uint64_t
|
||||
fuse_direntplus_size(const uint64_t namelen_)
|
||||
{
|
||||
uint64_t rv;
|
||||
|
||||
rv = offsetof(fuse_direntplus_t,dirent.name);
|
||||
rv += namelen_;
|
||||
rv = align_uint64_t(rv);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
fuse_dirents_resize(fuse_dirents_t *d_,
|
||||
uint64_t size_)
|
||||
{
|
||||
void *p;
|
||||
|
||||
if((d_->data_len + size_) >= d_->buf_len)
|
||||
{
|
||||
p = realloc(d_->buf,(d_->buf_len * 2));
|
||||
if(p == NULL)
|
||||
return -errno;
|
||||
|
||||
d_->buf = p;
|
||||
d_->buf_len *= 2;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static
|
||||
void*
|
||||
fuse_dirents_alloc(fuse_dirents_t *d_,
|
||||
uint64_t size_)
|
||||
{
|
||||
int rv;
|
||||
fuse_dirent_t *d;
|
||||
|
||||
rv = fuse_dirents_resize(d_,size_);
|
||||
if(rv)
|
||||
return NULL;
|
||||
|
||||
d = (fuse_dirent_t*)&d_->buf[d_->data_len];
|
||||
|
||||
d_->data_len += size_;
|
||||
|
||||
return d;
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
fuse_dirents_fill_attr(fuse_attr_t *attr_,
|
||||
const struct stat *st_)
|
||||
{
|
||||
attr_->ino = st_->st_ino;
|
||||
attr_->size = st_->st_size;
|
||||
attr_->blocks = st_->st_blocks;
|
||||
attr_->atime = st_->st_atime;
|
||||
attr_->mtime = st_->st_mtime;
|
||||
attr_->ctime = st_->st_ctime;
|
||||
attr_->atimensec = ST_ATIM_NSEC(st_);
|
||||
attr_->mtimensec = ST_MTIM_NSEC(st_);
|
||||
attr_->ctimensec = ST_CTIM_NSEC(st_);
|
||||
attr_->mode = st_->st_mode;
|
||||
attr_->nlink = st_->st_nlink;
|
||||
attr_->uid = st_->st_uid;
|
||||
attr_->gid = st_->st_gid;
|
||||
attr_->rdev = st_->st_rdev;
|
||||
attr_->blksize = st_->st_blksize;
|
||||
}
|
||||
|
||||
fuse_dirent_t*
|
||||
fuse_dirent_next(fuse_dirent_t *cur_)
|
||||
{
|
||||
char *buf;
|
||||
|
||||
buf = (char*)cur_;
|
||||
buf += fuse_dirent_size(cur_->namelen);
|
||||
|
||||
return (fuse_dirent_t*)buf;
|
||||
}
|
||||
|
||||
fuse_direntplus_t*
|
||||
fuse_direntplus_next(fuse_direntplus_t *cur_)
|
||||
{
|
||||
char *buf;
|
||||
|
||||
buf = (char*)cur_;
|
||||
buf += fuse_direntplus_size(cur_->dirent.namelen);
|
||||
|
||||
return (fuse_direntplus_t*)buf;
|
||||
}
|
||||
|
||||
fuse_dirent_t*
|
||||
fuse_dirent_find(fuse_dirents_t *d_,
|
||||
const uint64_t ino_)
|
||||
{
|
||||
fuse_dirent_t *cur;
|
||||
fuse_dirent_t *end;
|
||||
|
||||
if(d_->type != NORMAL)
|
||||
return NULL;
|
||||
|
||||
cur = (fuse_dirent_t*)&d_->buf[0];
|
||||
end = (fuse_dirent_t*)&d_->buf[d_->data_len];
|
||||
while(cur < end)
|
||||
{
|
||||
if(cur->ino == ino_)
|
||||
return cur;
|
||||
|
||||
cur = fuse_dirent_next(cur);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
fuse_direntplus_t*
|
||||
fuse_direntplus_find(fuse_dirents_t *d_,
|
||||
const uint64_t ino_)
|
||||
{
|
||||
fuse_direntplus_t *cur;
|
||||
fuse_direntplus_t *end;
|
||||
|
||||
if(d_->type != PLUS)
|
||||
return NULL;
|
||||
|
||||
cur = (fuse_direntplus_t*)&d_->buf[0];
|
||||
end = (fuse_direntplus_t*)&d_->buf[d_->data_len];
|
||||
while(cur < end)
|
||||
{
|
||||
if(cur->dirent.ino == ino_)
|
||||
return cur;
|
||||
|
||||
cur = fuse_direntplus_next(cur);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void*
|
||||
fuse_dirents_find(fuse_dirents_t *d_,
|
||||
const uint64_t ino_)
|
||||
{
|
||||
switch(d_->type)
|
||||
{
|
||||
default:
|
||||
case UNSET:
|
||||
return NULL;
|
||||
case NORMAL:
|
||||
return fuse_dirent_find(d_,ino_);
|
||||
case PLUS:
|
||||
return fuse_direntplus_find(d_,ino_);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
fuse_dirents_convert_plus2normal(fuse_dirents_t *d_)
|
||||
{
|
||||
int rv;
|
||||
uint64_t size;
|
||||
fuse_dirent_t *d;
|
||||
fuse_dirents_t normal;
|
||||
fuse_direntplus_t *cur;
|
||||
fuse_direntplus_t *end;
|
||||
|
||||
rv = fuse_dirents_init(&normal);
|
||||
if(rv < 0)
|
||||
return rv;
|
||||
|
||||
cur = (fuse_direntplus_t*)&d_->buf[0];
|
||||
end = (fuse_direntplus_t*)&d_->buf[d_->data_len];
|
||||
while(cur < end)
|
||||
{
|
||||
size = fuse_dirent_size(cur->dirent.namelen);
|
||||
d = fuse_dirents_alloc(&normal,size);
|
||||
if(d == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
memcpy(d,&cur->dirent,size);
|
||||
d->off = normal.data_len;;
|
||||
|
||||
cur = fuse_direntplus_next(cur);
|
||||
}
|
||||
|
||||
fuse_dirents_free(d_);
|
||||
|
||||
normal.type = NORMAL;
|
||||
*d_ = normal;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fuse_dirents_add(fuse_dirents_t *d_,
|
||||
struct dirent *dirent_)
|
||||
{
|
||||
uint64_t size;
|
||||
uint64_t namelen;
|
||||
fuse_dirent_t *d;
|
||||
|
||||
switch(d_->type)
|
||||
{
|
||||
case UNSET:
|
||||
d_->type = NORMAL;
|
||||
break;
|
||||
case NORMAL:
|
||||
break;
|
||||
case PLUS:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
namelen = _D_EXACT_NAMLEN(dirent_);
|
||||
size = fuse_dirent_size(namelen);
|
||||
|
||||
d = fuse_dirents_alloc(d_,size);
|
||||
if(d == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
d->ino = dirent_->d_ino;
|
||||
d->off = d_->data_len;
|
||||
d->namelen = namelen;
|
||||
d->type = dirent_->d_type;
|
||||
memcpy(d->name,dirent_->d_name,namelen);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
fuse_dirents_add_plus(fuse_dirents_t *d_,
|
||||
const struct dirent *dirent_,
|
||||
const fuse_entry_t *entry_,
|
||||
const struct stat *st_)
|
||||
{
|
||||
uint64_t size;
|
||||
uint64_t namelen;
|
||||
fuse_direntplus_t *d;
|
||||
|
||||
switch(d_->type)
|
||||
{
|
||||
case UNSET:
|
||||
d_->type = PLUS;
|
||||
break;
|
||||
case NORMAL:
|
||||
return -EINVAL;
|
||||
case PLUS:
|
||||
break;
|
||||
}
|
||||
|
||||
namelen = _D_EXACT_NAMLEN(dirent_);
|
||||
size = fuse_direntplus_size(namelen);
|
||||
|
||||
d = fuse_dirents_alloc(d_,size);
|
||||
if(d == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
d->dirent.ino = dirent_->d_ino;
|
||||
d->dirent.off = d_->data_len;
|
||||
d->dirent.namelen = namelen;
|
||||
d->dirent.type = dirent_->d_type;
|
||||
memcpy(d->dirent.name,dirent_->d_name,namelen);
|
||||
|
||||
d->entry = *entry_;
|
||||
|
||||
fuse_dirents_fill_attr(&d->attr,st_);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
fuse_dirents_reset(fuse_dirents_t *d_)
|
||||
{
|
||||
d_->data_len = 0;
|
||||
d_->type = UNSET;
|
||||
}
|
||||
|
||||
int
|
||||
fuse_dirents_init(fuse_dirents_t *d_)
|
||||
{
|
||||
void *buf;
|
||||
|
||||
buf = calloc(DEFAULT_SIZE,1);
|
||||
if(buf == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
d_->buf = buf;
|
||||
d_->buf_len = DEFAULT_SIZE;
|
||||
d_->data_len = 0;
|
||||
d_->type = UNSET;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
fuse_dirents_free(fuse_dirents_t *d_)
|
||||
{
|
||||
d_->buf_len = 0;
|
||||
d_->data_len = 0;
|
||||
d_->type = UNSET;
|
||||
free(d_->buf);
|
||||
}
|
|
@ -17,7 +17,7 @@ int fuse_session_loop(struct fuse_session *se)
|
|||
int res = 0;
|
||||
struct fuse_chan *ch = fuse_session_next_chan(se, NULL);
|
||||
size_t bufsize = fuse_chan_bufsize(ch);
|
||||
char *buf = (char *) malloc(bufsize);
|
||||
char *buf = (char*)calloc(bufsize,1);
|
||||
if (!buf) {
|
||||
fprintf(stderr, "fuse: failed to allocate read buffer\n");
|
||||
return -1;
|
||||
|
|
|
@ -141,7 +141,7 @@ static int fuse_loop_start_thread(struct fuse_mt *mt)
|
|||
}
|
||||
memset(w, 0, sizeof(struct fuse_worker));
|
||||
w->bufsize = fuse_chan_bufsize(mt->prevch);
|
||||
w->buf = malloc(w->bufsize);
|
||||
w->buf = calloc(w->bufsize,1);
|
||||
w->mt = mt;
|
||||
if (!w->buf) {
|
||||
fprintf(stderr, "fuse: failed to allocate read buffer\n");
|
||||
|
|
|
@ -1411,6 +1411,24 @@ static void do_readdir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
|||
fuse_reply_err(req, ENOSYS);
|
||||
}
|
||||
|
||||
static
|
||||
void
|
||||
do_readdir_plus(fuse_req_t req_,
|
||||
fuse_ino_t nodeid_,
|
||||
const void *inarg_)
|
||||
{
|
||||
const struct fuse_read_in *arg;
|
||||
struct fuse_file_info ffi = {0};
|
||||
|
||||
arg = (struct fuse_read_in*)inarg_;
|
||||
ffi.fh = arg->fh;
|
||||
|
||||
if(req_->f->op.readdir_plus)
|
||||
req_->f->op.readdir_plus(req_,nodeid_,arg->size,arg->offset,&ffi);
|
||||
else
|
||||
fuse_reply_err(req_,ENOSYS);
|
||||
}
|
||||
|
||||
static void do_releasedir(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
||||
{
|
||||
struct fuse_release_in *arg = (struct fuse_release_in *) inarg;
|
||||
|
@ -1817,6 +1835,10 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
|||
f->conn.capable |= FUSE_CAP_MAX_PAGES;
|
||||
if (arg->flags & FUSE_WRITEBACK_CACHE)
|
||||
f->conn.capable |= FUSE_CAP_WRITEBACK_CACHE;
|
||||
if (arg->flags & FUSE_DO_READDIRPLUS)
|
||||
f->conn.capable |= FUSE_CAP_READDIR_PLUS;
|
||||
if (arg->flags & FUSE_READDIRPLUS_AUTO)
|
||||
f->conn.capable |= FUSE_CAP_READDIR_PLUS_AUTO;
|
||||
} else {
|
||||
f->conn.want &= ~FUSE_CAP_ASYNC_READ;
|
||||
f->conn.max_readahead = 0;
|
||||
|
@ -1895,6 +1917,11 @@ static void do_init(fuse_req_t req, fuse_ino_t nodeid, const void *inarg)
|
|||
outarg.flags |= FUSE_PARALLEL_DIROPS;
|
||||
if (f->conn.want & FUSE_CAP_WRITEBACK_CACHE)
|
||||
outarg.flags |= FUSE_WRITEBACK_CACHE;
|
||||
if (f->conn.want & FUSE_CAP_READDIR_PLUS)
|
||||
outarg.flags |= FUSE_DO_READDIRPLUS;
|
||||
if (f->conn.want & FUSE_CAP_READDIR_PLUS_AUTO)
|
||||
outarg.flags |= FUSE_READDIRPLUS_AUTO;
|
||||
|
||||
outarg.max_readahead = f->conn.max_readahead;
|
||||
outarg.max_write = f->conn.max_write;
|
||||
if (f->conn.proto_minor >= 13) {
|
||||
|
@ -2350,6 +2377,7 @@ static struct {
|
|||
[FUSE_INIT] = { do_init, "INIT" },
|
||||
[FUSE_OPENDIR] = { do_opendir, "OPENDIR" },
|
||||
[FUSE_READDIR] = { do_readdir, "READDIR" },
|
||||
[FUSE_READDIRPLUS] = { do_readdir_plus, "READDIR_PLUS" },
|
||||
[FUSE_RELEASEDIR] = { do_releasedir, "RELEASEDIR" },
|
||||
[FUSE_FSYNCDIR] = { do_fsyncdir, "FSYNCDIR" },
|
||||
[FUSE_GETLK] = { do_getlk, "GETLK" },
|
||||
|
@ -2469,11 +2497,18 @@ static void fuse_ll_process_buf(void *data, const struct fuse_buf *buf,
|
|||
goto reply_err;
|
||||
|
||||
err = EACCES;
|
||||
if (f->allow_root && in->uid != f->owner && in->uid != 0 &&
|
||||
in->opcode != FUSE_INIT && in->opcode != FUSE_READ &&
|
||||
in->opcode != FUSE_WRITE && in->opcode != FUSE_FSYNC &&
|
||||
in->opcode != FUSE_RELEASE && in->opcode != FUSE_READDIR &&
|
||||
in->opcode != FUSE_FSYNCDIR && in->opcode != FUSE_RELEASEDIR &&
|
||||
if (f->allow_root &&
|
||||
in->uid != f->owner &&
|
||||
in->uid != 0 &&
|
||||
in->opcode != FUSE_INIT &&
|
||||
in->opcode != FUSE_READ &&
|
||||
in->opcode != FUSE_WRITE &&
|
||||
in->opcode != FUSE_FSYNC &&
|
||||
in->opcode != FUSE_RELEASE &&
|
||||
in->opcode != FUSE_READDIR &&
|
||||
in->opcode != FUSE_READDIRPLUS &&
|
||||
in->opcode != FUSE_FSYNCDIR &&
|
||||
in->opcode != FUSE_RELEASEDIR &&
|
||||
in->opcode != FUSE_NOTIFY_REPLY)
|
||||
goto reply_err;
|
||||
|
||||
|
|
|
@ -53,6 +53,7 @@ Config::Config()
|
|||
cache_readdir(false),
|
||||
async_read(true),
|
||||
writeback_cache(false),
|
||||
readdirplus(false),
|
||||
cache_files(CacheFiles::LIBFUSE),
|
||||
fuse_msg_size(FUSE_MAX_MAX_PAGES),
|
||||
POLICYINIT(access),
|
||||
|
|
|
@ -113,6 +113,7 @@ public:
|
|||
bool cache_readdir;
|
||||
bool async_read;
|
||||
bool writeback_cache;
|
||||
bool readdirplus;
|
||||
CacheFiles cache_files;
|
||||
uint16_t fuse_msg_size;
|
||||
|
||||
|
|
53
src/fs_base_fstatat.hpp
Normal file
53
src/fs_base_fstatat.hpp
Normal file
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
ISC License
|
||||
|
||||
Copyright (c) 2019, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
namespace fs
|
||||
{
|
||||
static
|
||||
inline
|
||||
int
|
||||
fstatat(const int dirfd,
|
||||
const char *pathname,
|
||||
struct stat *statbuf,
|
||||
const int flags)
|
||||
{
|
||||
return ::fstatat(dirfd,
|
||||
pathname,
|
||||
statbuf,
|
||||
flags);
|
||||
}
|
||||
|
||||
static
|
||||
inline
|
||||
int
|
||||
fstatat_nofollow(const int dirfd,
|
||||
const char *pathname,
|
||||
struct stat *statbuf)
|
||||
{
|
||||
return fs::fstatat(dirfd,
|
||||
pathname,
|
||||
statbuf,
|
||||
AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
}
|
|
@ -30,18 +30,26 @@ namespace fs
|
|||
static const uint64_t MAGIC = 0x7472617065786974;
|
||||
|
||||
inline
|
||||
void
|
||||
recompute(struct stat *st_)
|
||||
uint64_t
|
||||
recompute(ino_t ino_,
|
||||
dev_t dev_)
|
||||
{
|
||||
uint64_t buf[5];
|
||||
|
||||
buf[0] = st_->st_ino;
|
||||
buf[1] = st_->st_dev;
|
||||
buf[0] = ino_;
|
||||
buf[1] = dev_;
|
||||
buf[2] = buf[0] ^ buf[1];
|
||||
buf[3] = buf[0] & buf[1];
|
||||
buf[4] = buf[0] | buf[1];
|
||||
|
||||
st_->st_ino = fasthash64(&buf[0],sizeof(buf),MAGIC);
|
||||
return fasthash64(&buf[0],sizeof(buf),MAGIC);
|
||||
}
|
||||
|
||||
inline
|
||||
void
|
||||
recompute(struct stat *st_)
|
||||
{
|
||||
st_->st_ino = recompute(st_->st_ino,st_->st_dev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,6 +95,8 @@ namespace FUSE
|
|||
l::want_if_capable(conn_,FUSE_CAP_DONT_MASK);
|
||||
l::want_if_capable(conn_,FUSE_CAP_IOCTL_DIR);
|
||||
l::want_if_capable(conn_,FUSE_CAP_PARALLEL_DIROPS);
|
||||
l::want_if_capable(conn_,FUSE_CAP_READDIR_PLUS,&c.readdirplus);
|
||||
//l::want_if_capable(conn_,FUSE_CAP_READDIR_PLUS_AUTO);
|
||||
l::want_if_capable(conn_,FUSE_CAP_POSIX_ACL,&c.posix_acl);
|
||||
l::want_if_capable(conn_,FUSE_CAP_WRITEBACK_CACHE,&c.writeback_cache);
|
||||
l::want_if_capable_max_pages(conn_,c);
|
||||
|
|
|
@ -32,27 +32,27 @@
|
|||
#include "ugid.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
#include <fuse_dirents.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
#define NO_OFFSET 0
|
||||
|
||||
namespace l
|
||||
{
|
||||
static
|
||||
int
|
||||
readdir(const Branches &branches_,
|
||||
const char *dirname_,
|
||||
void *buf_,
|
||||
const fuse_fill_dir_t filler_)
|
||||
fuse_dirents_t *buf_)
|
||||
{
|
||||
dev_t dev;
|
||||
HashSet names;
|
||||
string basepath;
|
||||
struct stat st = {0};
|
||||
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
|
@ -67,23 +67,20 @@ namespace l
|
|||
continue;
|
||||
|
||||
dirfd = fs::dirfd(dh);
|
||||
st.st_dev = fs::devid(dirfd);
|
||||
if(st.st_dev == (dev_t)-1)
|
||||
st.st_dev = i;
|
||||
dev = fs::devid(dirfd);
|
||||
if(dev == (dev_t)-1)
|
||||
dev = i;
|
||||
|
||||
rv = 0;
|
||||
for(struct dirent *de = fs::readdir(dh); de && !rv; de = fs::readdir(dh))
|
||||
{
|
||||
rv = names.put(de->d_name);
|
||||
rv = names.put(de->d_name,_D_EXACT_NAMLEN(de));
|
||||
if(rv == 0)
|
||||
continue;
|
||||
|
||||
st.st_ino = de->d_ino;
|
||||
st.st_mode = DTTOIF(de->d_type);
|
||||
de->d_ino = fs::inode::recompute(de->d_ino,dev);
|
||||
|
||||
fs::inode::recompute(&st);
|
||||
|
||||
rv = filler_(buf_,de->d_name,&st,NO_OFFSET);
|
||||
rv = fuse_dirents_add(buf_,de);
|
||||
if(rv)
|
||||
return (fs::closedir(dh),-ENOMEM);
|
||||
}
|
||||
|
@ -98,11 +95,8 @@ namespace l
|
|||
namespace FUSE
|
||||
{
|
||||
int
|
||||
readdir(const char *fusepath_,
|
||||
void *buf_,
|
||||
fuse_fill_dir_t filler_,
|
||||
off_t offset_,
|
||||
fuse_file_info *ffi_)
|
||||
readdir(fuse_file_info *ffi_,
|
||||
fuse_dirents_t *buf_)
|
||||
{
|
||||
DirInfo *di = reinterpret_cast<DirInfo*>(ffi_->fh);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
|
@ -112,7 +106,6 @@ namespace FUSE
|
|||
|
||||
return l::readdir(config.branches,
|
||||
di->fusepath.c_str(),
|
||||
buf_,
|
||||
filler_);
|
||||
buf_);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
Copyright (c) 2019, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
|
@ -18,16 +18,9 @@
|
|||
|
||||
#include <fuse.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace FUSE
|
||||
{
|
||||
int
|
||||
readdir(const char *fusepath_,
|
||||
void *buf_,
|
||||
fuse_fill_dir_t filler_,
|
||||
off_t offset_,
|
||||
fuse_file_info *ffi_);
|
||||
readdir(fuse_file_info *ffi_,
|
||||
fuse_dirents_t *buf_);
|
||||
}
|
||||
|
|
138
src/fuse_readdir_plus.cpp
Normal file
138
src/fuse_readdir_plus.cpp
Normal file
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
Copyright (c) 2019, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#define _DEFAULT_SOURCE
|
||||
|
||||
#include "config.hpp"
|
||||
#include "dirinfo.hpp"
|
||||
#include "errno.hpp"
|
||||
#include "fs_base_closedir.hpp"
|
||||
#include "fs_base_dirfd.hpp"
|
||||
#include "fs_base_opendir.hpp"
|
||||
#include "fs_base_readdir.hpp"
|
||||
#include "fs_base_fstatat.hpp"
|
||||
#include "fs_base_stat.hpp"
|
||||
#include "fs_devid.hpp"
|
||||
#include "fs_inode.hpp"
|
||||
#include "fs_path.hpp"
|
||||
#include "hashset.hpp"
|
||||
#include "rwlock.hpp"
|
||||
#include "ugid.hpp"
|
||||
|
||||
#include <fuse.h>
|
||||
#include <fuse_dirents.h>
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
#define NO_OFFSET 0
|
||||
|
||||
|
||||
static
|
||||
int
|
||||
dot_or_dotdot(const char *s_)
|
||||
{
|
||||
return ((s_[0] == '.') &&
|
||||
((s_[1] == '\0') ||
|
||||
((s_[1] == '.') && (s_[2] == '\0'))));
|
||||
}
|
||||
|
||||
|
||||
namespace l
|
||||
{
|
||||
static
|
||||
int
|
||||
readdir_plus(const Branches &branches_,
|
||||
const char *dirname_,
|
||||
fuse_dirents_t *buf_)
|
||||
{
|
||||
dev_t dev;
|
||||
HashSet names;
|
||||
string basepath;
|
||||
struct stat st;
|
||||
fuse_entry_t entry;
|
||||
|
||||
entry.nodeid = 0;
|
||||
entry.generation = 0;
|
||||
entry.entry_valid = 1;
|
||||
entry.attr_valid = 1;
|
||||
entry.entry_valid_nsec = 0;
|
||||
entry.attr_valid_nsec = 0;
|
||||
for(size_t i = 0, ei = branches_.size(); i != ei; i++)
|
||||
{
|
||||
int rv;
|
||||
int dirfd;
|
||||
DIR *dh;
|
||||
|
||||
basepath = fs::path::make(&branches_[i].path,dirname_);
|
||||
|
||||
dh = fs::opendir(basepath);
|
||||
if(!dh)
|
||||
continue;
|
||||
|
||||
dirfd = fs::dirfd(dh);
|
||||
dev = fs::devid(dirfd);
|
||||
if(dev == (dev_t)-1)
|
||||
dev = i;
|
||||
|
||||
rv = 0;
|
||||
for(struct dirent *de = fs::readdir(dh); de && !rv; de = fs::readdir(dh))
|
||||
{
|
||||
rv = names.put(de->d_name,_D_EXACT_NAMLEN(de));
|
||||
if(rv == 0)
|
||||
continue;
|
||||
|
||||
rv = fs::fstatat_nofollow(dirfd,de->d_name,&st);
|
||||
if(rv == -1)
|
||||
memset(&st,0,sizeof(st));
|
||||
|
||||
de->d_ino = fs::inode::recompute(de->d_ino,dev);
|
||||
st.st_ino = fs::inode::recompute(st.st_ino,dev);
|
||||
|
||||
rv = fuse_dirents_add_plus(buf_,de,&entry,&st);
|
||||
if(rv)
|
||||
return (fs::closedir(dh),-ENOMEM);
|
||||
}
|
||||
|
||||
fs::closedir(dh);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
namespace FUSE
|
||||
{
|
||||
int
|
||||
readdir_plus(fuse_file_info *ffi_,
|
||||
fuse_dirents_t *buf_)
|
||||
{
|
||||
DirInfo *di = reinterpret_cast<DirInfo*>(ffi_->fh);
|
||||
const fuse_context *fc = fuse_get_context();
|
||||
const Config &config = Config::get(fc);
|
||||
const ugid::Set ugid(fc->uid,fc->gid);
|
||||
const rwlock::ReadGuard readlock(&config.branches_lock);
|
||||
|
||||
return l::readdir_plus(config.branches,
|
||||
di->fusepath.c_str(),
|
||||
buf_);
|
||||
}
|
||||
}
|
30
src/fuse_readdir_plus.hpp
Normal file
30
src/fuse_readdir_plus.hpp
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
Copyright (c) 2016, Antonio SJ Musumeci <trapexit@spawn.link>
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <fuse.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace FUSE
|
||||
{
|
||||
int
|
||||
readdir_plus(fuse_file_info *ffi_,
|
||||
fuse_dirents_t *buf_);
|
||||
}
|
|
@ -38,13 +38,14 @@ public:
|
|||
|
||||
inline
|
||||
int
|
||||
put(const char *str_)
|
||||
put(const char *str_,
|
||||
const uint64_t len_)
|
||||
{
|
||||
int rv;
|
||||
uint64_t h;
|
||||
khint_t key;
|
||||
|
||||
h = fasthash64(str_,strlen(str_),0x7472617065786974);
|
||||
h = fasthash64(str_,len_,0x7472617065786974);
|
||||
|
||||
key = kh_put(hashset,_set,h,&rv);
|
||||
if(rv == 0)
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "fuse_read.hpp"
|
||||
#include "fuse_read_buf.hpp"
|
||||
#include "fuse_readdir.hpp"
|
||||
#include "fuse_readdir_plus.hpp"
|
||||
#include "fuse_readlink.hpp"
|
||||
#include "fuse_release.hpp"
|
||||
#include "fuse_releasedir.hpp"
|
||||
|
@ -102,7 +103,6 @@ namespace l
|
|||
ops.ftruncate = FUSE::ftruncate;
|
||||
ops.futimens = FUSE::futimens;
|
||||
ops.getattr = FUSE::getattr;
|
||||
ops.getdir = NULL; /* deprecated; use readdir */
|
||||
ops.getxattr = FUSE::getxattr;
|
||||
ops.init = FUSE::init;
|
||||
ops.ioctl = FUSE::ioctl;
|
||||
|
@ -118,6 +118,7 @@ namespace l
|
|||
ops.read = (nullrw ? FUSE::read_null : FUSE::read);
|
||||
ops.read_buf = (nullrw ? NULL : FUSE::read_buf);
|
||||
ops.readdir = FUSE::readdir;
|
||||
ops.readdir_plus = FUSE::readdir_plus;
|
||||
ops.readlink = FUSE::readlink;
|
||||
ops.release = FUSE::release;
|
||||
ops.releasedir = FUSE::releasedir;
|
||||
|
|
|
@ -310,6 +310,8 @@ parse_and_process_arg(Config &config,
|
|||
return 0;
|
||||
else if(arg == "big_writes")
|
||||
return 0;
|
||||
else if(arg == "readdir_ino")
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -373,6 +375,8 @@ parse_and_process_kv_arg(Config &config,
|
|||
rv = parse_and_process(value,config.auto_cache);
|
||||
else if(key == "async_read")
|
||||
rv = parse_and_process(value,config.async_read);
|
||||
else if(key == "readdirplus")
|
||||
rv = parse_and_process(value,config.readdirplus);
|
||||
else if(key == "max_write")
|
||||
rv = 0;
|
||||
else if(key == "fuse_msg_size")
|
||||
|
|
Loading…
Reference in New Issue
Block a user