mirror of https://github.com/trapexit/mergerfs.git
Browse Source
Add getdents based readdir functions for Linux
Add getdents based readdir functions for Linux
31 changed files with 896 additions and 900 deletions
-
1libfuse/Makefile
-
23libfuse/include/fs_dirent64.hpp
-
80libfuse/include/fuse_dirents.h
-
48libfuse/include/fuse_dirents.hpp
-
2libfuse/include/fuse_msgbuf.hpp
-
0libfuse/include/fuse_msgbuf_t.h
-
16libfuse/include/linux_dirent64.h
-
2libfuse/lib/fuse.cpp
-
406libfuse/lib/fuse_dirents.c
-
160libfuse/lib/fuse_dirents.cpp
-
2libfuse/lib/fuse_i.h
-
2libfuse/lib/fuse_ll.hpp
-
5libfuse/lib/fuse_msgbuf.cpp
-
4src/branch.hpp
-
2src/branches.cpp
-
8src/fs_getdents64.cpp
-
10src/fs_getdents64.hpp
-
12src/fs_statx.hpp
-
4src/fuse_readdir.cpp
-
148src/fuse_readdir_cor.cpp
-
79src/fuse_readdir_cor_getdents.icpp
-
87src/fuse_readdir_cor_readdir.icpp
-
162src/fuse_readdir_cosr.cpp
-
131src/fuse_readdir_cosr_getdents.icpp
-
124src/fuse_readdir_cosr_readdir.icpp
-
92src/fuse_readdir_seq.cpp
-
79src/fuse_readdir_seq_getdents.icpp
-
82src/fuse_readdir_seq_readdir.icpp
-
2src/fuse_statx.cpp
-
11src/supported_getdents64.hpp
-
12src/supported_statx.hpp
@ -0,0 +1,23 @@ |
|||||
|
#pragma once
|
||||
|
|
||||
|
#include <cstddef>
|
||||
|
#include <cstdint>
|
||||
|
|
||||
|
namespace fs |
||||
|
{ |
||||
|
struct dirent64 |
||||
|
{ |
||||
|
public: |
||||
|
uint64_t d_ino; |
||||
|
int64_t d_off; |
||||
|
uint16_t d_reclen; |
||||
|
uint8_t d_type; |
||||
|
char d_name[]; |
||||
|
|
||||
|
public: |
||||
|
int d_namelen() const |
||||
|
{ |
||||
|
return (d_reclen - offsetof(dirent64,d_name)); |
||||
|
} |
||||
|
}; |
||||
|
} |
@ -1,80 +0,0 @@ |
|||||
/* |
|
||||
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 "extern_c.h" |
|
||||
|
|
||||
EXTERN_C_BEGIN |
|
||||
|
|
||||
#include "kvec.h" |
|
||||
#include "fuse_dirent.h" |
|
||||
#include "fuse_direntplus.h" |
|
||||
#include "fuse_entry.h" |
|
||||
#include "linux_dirent64.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_t fuse_dirents_t; |
|
||||
struct fuse_dirents_t |
|
||||
{ |
|
||||
kvec_t(char) data; |
|
||||
kvec_t(uint32_t) offs; |
|
||||
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, |
|
||||
const struct dirent *de, |
|
||||
const uint64_t namelen); |
|
||||
int fuse_dirents_add_plus(fuse_dirents_t *d, |
|
||||
const struct dirent *de, |
|
||||
const uint64_t namelen, |
|
||||
const fuse_entry_t *entry, |
|
||||
const struct stat *st); |
|
||||
int fuse_dirents_add_linux(fuse_dirents_t *d, |
|
||||
const linux_dirent64_t *de, |
|
||||
const uint64_t namelen); |
|
||||
int fuse_dirents_add_linux_plus(fuse_dirents_t *d, |
|
||||
const linux_dirent64_t *de, |
|
||||
const uint64_t namelen, |
|
||||
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); |
|
||||
|
|
||||
EXTERN_C_END |
|
@ -0,0 +1,48 @@ |
|||||
|
/*
|
||||
|
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 "kvec.h"
|
||||
|
#include "fuse_dirent.h"
|
||||
|
#include "fuse_entry.h"
|
||||
|
#include "fs_dirent64.hpp"
|
||||
|
|
||||
|
#include <dirent.h>
|
||||
|
#include <stdint.h>
|
||||
|
#include <stdio.h>
|
||||
|
#include <sys/stat.h>
|
||||
|
#include <sys/types.h>
|
||||
|
#include <unistd.h>
|
||||
|
|
||||
|
struct fuse_dirents_t |
||||
|
{ |
||||
|
kvec_t(char) data; |
||||
|
kvec_t(uint32_t) offs; |
||||
|
}; |
||||
|
|
||||
|
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, |
||||
|
const dirent *de, |
||||
|
const uint64_t namelen); |
||||
|
int fuse_dirents_add(fuse_dirents_t *d, |
||||
|
const fs::dirent64 *de, |
||||
|
const uint64_t namelen); |
@ -1,16 +0,0 @@ |
|||||
#pragma once |
|
||||
|
|
||||
#include <stdint.h> |
|
||||
#include <string.h> |
|
||||
|
|
||||
#define DIRENT_NAMELEN(X) (strlen((X)->name)) |
|
||||
|
|
||||
typedef struct linux_dirent64_t linux_dirent64_t; |
|
||||
struct linux_dirent64_t |
|
||||
{ |
|
||||
uint64_t ino; |
|
||||
int64_t off; |
|
||||
uint16_t reclen; |
|
||||
uint8_t type; |
|
||||
char name[]; |
|
||||
}; |
|
@ -1,406 +0,0 @@ |
|||||
#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 "linux_dirent64.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> |
|
||||
|
|
||||
/* 32KB - same as glibc getdents buffer size */ |
|
||||
#define DEFAULT_SIZE (1024 * 32) |
|
||||
|
|
||||
static |
|
||||
uint64_t |
|
||||
round_up(const uint64_t number_, |
|
||||
const uint64_t multiple_) |
|
||||
{ |
|
||||
return (((number_ + multiple_ - 1) / multiple_) * multiple_); |
|
||||
} |
|
||||
|
|
||||
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_buf_resize(fuse_dirents_t *d_, |
|
||||
uint64_t size_) |
|
||||
{ |
|
||||
if((kv_size(d_->data) + size_) >= kv_max(d_->data)) |
|
||||
{ |
|
||||
uint64_t new_size; |
|
||||
|
|
||||
new_size = round_up((kv_size(d_->data) + size_),DEFAULT_SIZE); |
|
||||
|
|
||||
kv_resize(char,d_->data,new_size); |
|
||||
if(d_->data.a == NULL) |
|
||||
return -ENOMEM; |
|
||||
} |
|
||||
|
|
||||
return 0; |
|
||||
} |
|
||||
|
|
||||
static |
|
||||
void* |
|
||||
fuse_dirents_dirent_alloc(fuse_dirents_t *d_, |
|
||||
uint64_t namelen_) |
|
||||
{ |
|
||||
int rv; |
|
||||
uint64_t size; |
|
||||
fuse_dirent_t *d; |
|
||||
|
|
||||
size = fuse_dirent_size(namelen_); |
|
||||
|
|
||||
rv = fuse_dirents_buf_resize(d_,size); |
|
||||
if(rv) |
|
||||
return NULL; |
|
||||
|
|
||||
d = (fuse_dirent_t*)&kv_end(d_->data); |
|
||||
kv_size(d_->data) += size; |
|
||||
|
|
||||
return d; |
|
||||
} |
|
||||
|
|
||||
static |
|
||||
void* |
|
||||
fuse_dirents_direntplus_alloc(fuse_dirents_t *d_, |
|
||||
uint64_t namelen_) |
|
||||
{ |
|
||||
int rv; |
|
||||
uint64_t size; |
|
||||
fuse_dirent_t *d; |
|
||||
|
|
||||
size = fuse_direntplus_size(namelen_); |
|
||||
|
|
||||
rv = fuse_dirents_buf_resize(d_,size); |
|
||||
if(rv) |
|
||||
return NULL; |
|
||||
|
|
||||
d = (fuse_dirent_t*)&kv_end(d_->data); |
|
||||
kv_size(d_->data) += 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*)&kv_first(d_->data); |
|
||||
end = (fuse_dirent_t*)&kv_end(d_->data); |
|
||||
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*)&kv_first(d_->data); |
|
||||
end = (fuse_direntplus_t*)&kv_end(d_->data); |
|
||||
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_) |
|
||||
{ |
|
||||
return -ENOSYS; |
|
||||
} |
|
||||
|
|
||||
int |
|
||||
fuse_dirents_add(fuse_dirents_t *d_, |
|
||||
const struct dirent *dirent_, |
|
||||
const uint64_t namelen_) |
|
||||
{ |
|
||||
fuse_dirent_t *d; |
|
||||
|
|
||||
switch(d_->type) |
|
||||
{ |
|
||||
case UNSET: |
|
||||
d_->type = NORMAL; |
|
||||
break; |
|
||||
case NORMAL: |
|
||||
break; |
|
||||
case PLUS: |
|
||||
return -EINVAL; |
|
||||
} |
|
||||
|
|
||||
d = fuse_dirents_dirent_alloc(d_,namelen_); |
|
||||
if(d == NULL) |
|
||||
return -ENOMEM; |
|
||||
|
|
||||
d->off = kv_size(d_->offs); |
|
||||
kv_push(uint32_t,d_->offs,kv_size(d_->data)); |
|
||||
d->ino = dirent_->d_ino; |
|
||||
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 uint64_t namelen_, |
|
||||
const fuse_entry_t *entry_, |
|
||||
const struct stat *st_) |
|
||||
{ |
|
||||
fuse_direntplus_t *d; |
|
||||
|
|
||||
switch(d_->type) |
|
||||
{ |
|
||||
case UNSET: |
|
||||
d_->type = PLUS; |
|
||||
break; |
|
||||
case NORMAL: |
|
||||
return -EINVAL; |
|
||||
case PLUS: |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
d = fuse_dirents_direntplus_alloc(d_,namelen_); |
|
||||
if(d == NULL) |
|
||||
return -ENOMEM; |
|
||||
|
|
||||
d->dirent.off = kv_size(d_->offs); |
|
||||
kv_push(uint32_t,d_->offs,kv_size(d_->data)); |
|
||||
d->dirent.ino = dirent_->d_ino; |
|
||||
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; |
|
||||
} |
|
||||
|
|
||||
int |
|
||||
fuse_dirents_add_linux(fuse_dirents_t *d_, |
|
||||
const linux_dirent64_t *dirent_, |
|
||||
const uint64_t namelen_) |
|
||||
{ |
|
||||
fuse_dirent_t *d; |
|
||||
|
|
||||
switch(d_->type) |
|
||||
{ |
|
||||
case UNSET: |
|
||||
d_->type = NORMAL; |
|
||||
break; |
|
||||
case NORMAL: |
|
||||
break; |
|
||||
case PLUS: |
|
||||
return -EINVAL; |
|
||||
} |
|
||||
|
|
||||
d = fuse_dirents_dirent_alloc(d_,namelen_); |
|
||||
if(d == NULL) |
|
||||
return -ENOMEM; |
|
||||
|
|
||||
d->off = kv_size(d_->offs); |
|
||||
kv_push(uint32_t,d_->offs,kv_size(d_->data)); |
|
||||
d->ino = dirent_->ino; |
|
||||
d->namelen = namelen_; |
|
||||
d->type = dirent_->type; |
|
||||
memcpy(d->name,dirent_->name,namelen_); |
|
||||
|
|
||||
return 0; |
|
||||
} |
|
||||
|
|
||||
int |
|
||||
fuse_dirents_add_linux_plus(fuse_dirents_t *d_, |
|
||||
const linux_dirent64_t *dirent_, |
|
||||
const uint64_t namelen_, |
|
||||
const fuse_entry_t *entry_, |
|
||||
const struct stat *st_) |
|
||||
{ |
|
||||
fuse_direntplus_t *d; |
|
||||
|
|
||||
switch(d_->type) |
|
||||
{ |
|
||||
case UNSET: |
|
||||
d_->type = PLUS; |
|
||||
break; |
|
||||
case NORMAL: |
|
||||
return -EINVAL; |
|
||||
case PLUS: |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
d = fuse_dirents_direntplus_alloc(d_,namelen_); |
|
||||
if(d == NULL) |
|
||||
return -ENOMEM; |
|
||||
|
|
||||
d->dirent.off = kv_size(d_->offs); |
|
||||
kv_push(uint32_t,d_->offs,kv_size(d_->data)); |
|
||||
d->dirent.ino = dirent_->ino; |
|
||||
d->dirent.namelen = namelen_; |
|
||||
d->dirent.type = dirent_->type; |
|
||||
memcpy(d->dirent.name,dirent_->name,namelen_); |
|
||||
|
|
||||
d->entry = *entry_; |
|
||||
|
|
||||
fuse_dirents_fill_attr(&d->attr,st_); |
|
||||
|
|
||||
return 0; |
|
||||
} |
|
||||
|
|
||||
void |
|
||||
fuse_dirents_reset(fuse_dirents_t *d_) |
|
||||
{ |
|
||||
d_->type = UNSET; |
|
||||
kv_size(d_->data) = 0; |
|
||||
kv_size(d_->offs) = 1; |
|
||||
} |
|
||||
|
|
||||
int |
|
||||
fuse_dirents_init(fuse_dirents_t *d_) |
|
||||
{ |
|
||||
d_->type = UNSET; |
|
||||
|
|
||||
kv_init(d_->data); |
|
||||
kv_resize(char,d_->data,DEFAULT_SIZE); |
|
||||
if(d_->data.a == NULL) |
|
||||
return -ENOMEM; |
|
||||
|
|
||||
kv_init(d_->offs); |
|
||||
kv_resize(uint32_t,d_->offs,64); |
|
||||
kv_push(uint32_t,d_->offs,0); |
|
||||
|
|
||||
return 0; |
|
||||
} |
|
||||
|
|
||||
void |
|
||||
fuse_dirents_free(fuse_dirents_t *d_) |
|
||||
{ |
|
||||
kv_destroy(d_->data); |
|
||||
kv_destroy(d_->offs); |
|
||||
} |
|
@ -0,0 +1,160 @@ |
|||||
|
#define _FILE_OFFSET_BITS 64
|
||||
|
|
||||
|
#include "fs_dirent64.hpp"
|
||||
|
#include "fuse_attr.h"
|
||||
|
#include "fuse_dirent.h"
|
||||
|
#include "fuse_direntplus.h"
|
||||
|
#include "fuse_dirents.hpp"
|
||||
|
#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>
|
||||
|
|
||||
|
|
||||
|
/* 32KB - same as glibc getdents buffer size */ |
||||
|
#define DENTS_BUF_EXPAND_SIZE (1024 * 32)
|
||||
|
|
||||
|
static |
||||
|
uint64_t |
||||
|
_round_up(const uint64_t number_, |
||||
|
const uint64_t multiple_) |
||||
|
{ |
||||
|
return (((number_ + multiple_ - 1) / multiple_) * multiple_); |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
uint64_t |
||||
|
_align_uint64_t(uint64_t v_) |
||||
|
{ |
||||
|
return ((v_ + sizeof(uint64_t) - 1) & ~(sizeof(uint64_t) - 1)); |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
uint64_t |
||||
|
_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 |
||||
|
int |
||||
|
_dirents_buf_resize(fuse_dirents_t *d_, |
||||
|
const uint64_t size_) |
||||
|
{ |
||||
|
if((kv_size(d_->data) + size_) >= kv_max(d_->data)) |
||||
|
{ |
||||
|
uint64_t new_size; |
||||
|
|
||||
|
new_size = _round_up((kv_size(d_->data) + size_),DENTS_BUF_EXPAND_SIZE); |
||||
|
|
||||
|
kv_resize(char,d_->data,new_size); |
||||
|
if(d_->data.a == NULL) |
||||
|
return -ENOMEM; |
||||
|
} |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
fuse_dirent_t* |
||||
|
_dirents_dirent_alloc(fuse_dirents_t *d_, |
||||
|
const uint64_t namelen_) |
||||
|
{ |
||||
|
int rv; |
||||
|
uint64_t size; |
||||
|
fuse_dirent_t *d; |
||||
|
|
||||
|
size = _dirent_size(namelen_); |
||||
|
|
||||
|
rv = _dirents_buf_resize(d_,size); |
||||
|
if(rv) |
||||
|
return NULL; |
||||
|
|
||||
|
d = (fuse_dirent_t*)&kv_end(d_->data); |
||||
|
kv_size(d_->data) += size; |
||||
|
|
||||
|
return d; |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
fuse_dirents_add(fuse_dirents_t *d_, |
||||
|
const dirent *de_, |
||||
|
const uint64_t namelen_) |
||||
|
{ |
||||
|
fuse_dirent_t *d; |
||||
|
|
||||
|
d = _dirents_dirent_alloc(d_,namelen_); |
||||
|
if(d == NULL) |
||||
|
return -ENOMEM; |
||||
|
|
||||
|
d->off = kv_size(d_->offs); |
||||
|
kv_push(uint32_t,d_->offs,kv_size(d_->data)); |
||||
|
d->ino = de_->d_ino; |
||||
|
d->namelen = namelen_; |
||||
|
d->type = de_->d_type; |
||||
|
memcpy(d->name,de_->d_name,namelen_); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
fuse_dirents_add(fuse_dirents_t *d_, |
||||
|
const fs::dirent64 *de_, |
||||
|
const uint64_t namelen_) |
||||
|
{ |
||||
|
fuse_dirent_t *d; |
||||
|
|
||||
|
d = _dirents_dirent_alloc(d_,namelen_); |
||||
|
if(d == NULL) |
||||
|
return -ENOMEM; |
||||
|
|
||||
|
d->off = kv_size(d_->offs); |
||||
|
kv_push(uint32_t,d_->offs,kv_size(d_->data)); |
||||
|
d->ino = de_->d_ino; |
||||
|
d->namelen = namelen_; |
||||
|
d->type = de_->d_type; |
||||
|
memcpy(d->name,de_->d_name,namelen_); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
fuse_dirents_reset(fuse_dirents_t *d_) |
||||
|
{ |
||||
|
kv_size(d_->data) = 0; |
||||
|
kv_size(d_->offs) = 1; |
||||
|
} |
||||
|
|
||||
|
int |
||||
|
fuse_dirents_init(fuse_dirents_t *d_) |
||||
|
{ |
||||
|
kv_init(d_->data); |
||||
|
kv_resize(char,d_->data,DENTS_BUF_EXPAND_SIZE); |
||||
|
if(d_->data.a == NULL) |
||||
|
return -ENOMEM; |
||||
|
|
||||
|
kv_init(d_->offs); |
||||
|
kv_resize(uint32_t,d_->offs,64); |
||||
|
kv_push(uint32_t,d_->offs,0); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
void |
||||
|
fuse_dirents_free(fuse_dirents_t *d_) |
||||
|
{ |
||||
|
kv_destroy(d_->data); |
||||
|
kv_destroy(d_->offs); |
||||
|
} |
@ -0,0 +1,79 @@ |
|||||
|
#pragma message "using getdents" |
||||
|
|
||||
|
#include "fs_close.hpp" |
||||
|
#include "fs_getdents64.hpp" |
||||
|
#include "fs_inode.hpp" |
||||
|
#include "fs_open.hpp" |
||||
|
#include "fs_path.hpp" |
||||
|
#include "hashset.hpp" |
||||
|
#include "scope_guard.hpp" |
||||
|
|
||||
|
#include "fuse_msgbuf.hpp" |
||||
|
#include "fuse_dirents.hpp" |
||||
|
|
||||
|
|
||||
|
static |
||||
|
inline |
||||
|
int |
||||
|
_readdir(const fs::path &branch_path_, |
||||
|
const fs::path &rel_dirpath_, |
||||
|
HashSet &names_, |
||||
|
fuse_dirents_t *dirents_, |
||||
|
std::mutex &mutex_) |
||||
|
{ |
||||
|
int rv; |
||||
|
int fd; |
||||
|
fuse_msgbuf_t *buf; |
||||
|
fs::path rel_filepath; |
||||
|
fs::path abs_dirpath; |
||||
|
|
||||
|
abs_dirpath = branch_path_ / rel_dirpath_; |
||||
|
|
||||
|
fd = fs::open_dir_ro(abs_dirpath); |
||||
|
if(fd < 0) |
||||
|
return -fd; |
||||
|
DEFER{ fs::close(fd); }; |
||||
|
|
||||
|
buf = msgbuf_alloc(); |
||||
|
DEFER{ msgbuf_free(buf); }; |
||||
|
|
||||
|
rel_filepath = rel_dirpath_ / "dummy"; |
||||
|
while(true) |
||||
|
{ |
||||
|
std::lock_guard<std::mutex> lk(mutex_); |
||||
|
|
||||
|
while(true) |
||||
|
{ |
||||
|
ssize_t nread; |
||||
|
|
||||
|
nread = fs::getdents64(fd,buf->mem,buf->size); |
||||
|
if(nread <= 0) |
||||
|
break; |
||||
|
|
||||
|
for(ssize_t pos = 0; pos < nread;) |
||||
|
{ |
||||
|
int namelen; |
||||
|
fs::dirent64 *d = reinterpret_cast<fs::dirent64*>(&buf->mem[pos]); |
||||
|
|
||||
|
pos += d->d_reclen; |
||||
|
|
||||
|
namelen = d->d_namelen(); |
||||
|
rv = names_.put(d->d_name,namelen); |
||||
|
if(rv == 0) |
||||
|
continue; |
||||
|
|
||||
|
rel_filepath.replace_filename(d->d_name); |
||||
|
d->d_ino = fs::inode::calc(branch_path_, |
||||
|
rel_filepath, |
||||
|
DTTOIF(d->d_type), |
||||
|
d->d_ino); |
||||
|
|
||||
|
rv = fuse_dirents_add(dirents_,d,namelen); |
||||
|
if(rv < 0) |
||||
|
return ENOMEM; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,87 @@ |
|||||
|
#pragma message "using readdir" |
||||
|
|
||||
|
#define MAX_ENTRIES_PER_LOOP 64 |
||||
|
|
||||
|
#include "fs_opendir.hpp" |
||||
|
#include "fs_closedir.hpp" |
||||
|
#include "hashset.hpp" |
||||
|
#include "scope_guard.hpp" |
||||
|
#include "fs_readdir.hpp" |
||||
|
#include "fs_inode.hpp" |
||||
|
|
||||
|
#include "fuse_dirents.hpp" |
||||
|
|
||||
|
#include <cstring> |
||||
|
|
||||
|
#include <dirent.h> |
||||
|
|
||||
|
|
||||
|
static |
||||
|
u64 |
||||
|
_dirent_exact_namelen(const struct dirent *d_) |
||||
|
{ |
||||
|
#ifdef _D_EXACT_NAMLEN |
||||
|
return _D_EXACT_NAMLEN(d_); |
||||
|
#elif defined _DIRENT_HAVE_D_NAMLEN |
||||
|
return d_->d_namlen; |
||||
|
#else |
||||
|
return strlen(d_->d_name); |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
inline |
||||
|
int |
||||
|
_readdir(const fs::path &branch_path_, |
||||
|
const fs::path &rel_dirpath_, |
||||
|
HashSet &names_, |
||||
|
fuse_dirents_t *dirents_, |
||||
|
std::mutex &mutex_) |
||||
|
{ |
||||
|
int rv; |
||||
|
DIR *dir; |
||||
|
fs::path rel_filepath; |
||||
|
fs::path abs_dirpath; |
||||
|
|
||||
|
abs_dirpath = branch_path_ / rel_dirpath_; |
||||
|
|
||||
|
errno = 0; |
||||
|
dir = fs::opendir(abs_dirpath); |
||||
|
if(dir == NULL) |
||||
|
return errno; |
||||
|
DEFER{ fs::closedir(dir); }; |
||||
|
|
||||
|
rel_filepath = rel_dirpath_ / "dummy"; |
||||
|
while(true) |
||||
|
{ |
||||
|
std::lock_guard<std::mutex> lk(mutex_); |
||||
|
for(int i = 0; i < MAX_ENTRIES_PER_LOOP; i++) |
||||
|
{ |
||||
|
dirent *de; |
||||
|
u64 namelen; |
||||
|
|
||||
|
de = fs::readdir(dir); |
||||
|
if(de == NULL) |
||||
|
return 0; |
||||
|
|
||||
|
namelen = ::_dirent_exact_namelen(de); |
||||
|
|
||||
|
rv = names_.put(de->d_name,namelen); |
||||
|
if(rv == 0) |
||||
|
continue; |
||||
|
|
||||
|
rel_filepath.replace_filename(de->d_name); |
||||
|
|
||||
|
de->d_ino = fs::inode::calc(branch_path_, |
||||
|
rel_filepath, |
||||
|
DTTOIF(de->d_type), |
||||
|
de->d_ino); |
||||
|
|
||||
|
rv = fuse_dirents_add(dirents_,de,namelen); |
||||
|
if(rv < 0) |
||||
|
return ENOMEM; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,131 @@ |
|||||
|
#pragma message "using getdents" |
||||
|
|
||||
|
#include "fs_inode.hpp" |
||||
|
#include "fs_getdents64.hpp" |
||||
|
#include "hashset.hpp" |
||||
|
#include "branches.hpp" |
||||
|
#include "error.hpp" |
||||
|
#include "fs_close.hpp" |
||||
|
#include "fs_open.hpp" |
||||
|
#include "fs_path.hpp" |
||||
|
#include "ugid.hpp" |
||||
|
#include "scope_guard.hpp" |
||||
|
|
||||
|
#include "fuse_msgbuf.hpp" |
||||
|
#include "fuse_dirents.hpp" |
||||
|
|
||||
|
#include <dirent.h> |
||||
|
|
||||
|
|
||||
|
struct DirRV |
||||
|
{ |
||||
|
const fs::path *branch_path; |
||||
|
int fd; |
||||
|
int err; |
||||
|
}; |
||||
|
|
||||
|
static |
||||
|
inline |
||||
|
std::vector<std::future<DirRV>> |
||||
|
_opendir(ThreadPool &tp_, |
||||
|
const Branches::Ptr &branches_, |
||||
|
const fs::path &rel_dirpath_, |
||||
|
uid_t const uid_, |
||||
|
gid_t const gid_) |
||||
|
{ |
||||
|
std::vector<std::future<DirRV>> futures; |
||||
|
|
||||
|
futures.reserve(branches_->size()); |
||||
|
|
||||
|
for(const auto &branch : *branches_) |
||||
|
{ |
||||
|
auto func = |
||||
|
[&branch,&rel_dirpath_,uid_,gid_]() |
||||
|
{ |
||||
|
int fd; |
||||
|
fs::path abs_dirpath; |
||||
|
const ugid::Set ugid(uid_,gid_); |
||||
|
|
||||
|
abs_dirpath = branch.path / rel_dirpath_; |
||||
|
|
||||
|
errno = 0; |
||||
|
fd = fs::open_dir_ro(abs_dirpath); |
||||
|
|
||||
|
return DirRV{&branch.path,fd,errno}; |
||||
|
}; |
||||
|
|
||||
|
auto rv = tp_.enqueue_task(std::move(func)); |
||||
|
|
||||
|
futures.emplace_back(std::move(rv)); |
||||
|
} |
||||
|
|
||||
|
return futures; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
inline |
||||
|
int |
||||
|
_readdir(std::vector<std::future<DirRV>> &dh_futures_, |
||||
|
const fs::path &rel_dirpath_, |
||||
|
fuse_dirents_t *dirents_) |
||||
|
{ |
||||
|
Err err; |
||||
|
HashSet names; |
||||
|
fs::path rel_filepath; |
||||
|
fuse_msgbuf_t *buf; |
||||
|
|
||||
|
buf = msgbuf_alloc(); |
||||
|
DEFER { msgbuf_free(buf); }; |
||||
|
|
||||
|
rel_filepath = rel_dirpath_ / "dummy"; |
||||
|
for(auto &dh_future : dh_futures_) |
||||
|
{ |
||||
|
int rv; |
||||
|
DirRV dirrv; |
||||
|
|
||||
|
dirrv = dh_future.get(); |
||||
|
|
||||
|
err = dirrv.err; |
||||
|
if(dirrv.fd == -1) |
||||
|
continue; |
||||
|
|
||||
|
DEFER { fs::close(dirrv.fd); }; |
||||
|
|
||||
|
rv = 0; |
||||
|
while(true) |
||||
|
{ |
||||
|
ssize_t nread; |
||||
|
|
||||
|
nread = fs::getdents64(dirrv.fd,buf->mem,buf->size); |
||||
|
if(nread <= 0) |
||||
|
break; |
||||
|
|
||||
|
for(ssize_t pos = 0; pos < nread;) |
||||
|
{ |
||||
|
int namelen; |
||||
|
fs::dirent64 *d = reinterpret_cast<fs::dirent64*>(&buf->mem[pos]); |
||||
|
|
||||
|
pos += d->d_reclen; |
||||
|
|
||||
|
namelen = d->d_namelen(); |
||||
|
rv = names.put(d->d_name,namelen); |
||||
|
if(rv == 0) |
||||
|
continue; |
||||
|
|
||||
|
rel_filepath.replace_filename(d->d_name); |
||||
|
d->d_ino = fs::inode::calc(*dirrv.branch_path, |
||||
|
rel_filepath, |
||||
|
DTTOIF(d->d_type), |
||||
|
d->d_ino); |
||||
|
|
||||
|
rv = fuse_dirents_add(dirents_,d,namelen); |
||||
|
if(rv == 0) |
||||
|
continue; |
||||
|
|
||||
|
err = ENOMEM; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return -err; |
||||
|
} |
@ -0,0 +1,124 @@ |
|||||
|
#pragma message "using readdir" |
||||
|
|
||||
|
#include "error.hpp" |
||||
|
#include "fs_closedir.hpp" |
||||
|
#include "fs_inode.hpp" |
||||
|
#include "fs_opendir.hpp" |
||||
|
#include "fs_readdir.hpp" |
||||
|
#include "hashset.hpp" |
||||
|
#include "scope_guard.hpp" |
||||
|
#include "ugid.hpp" |
||||
|
|
||||
|
#include "fuse_dirents.hpp" |
||||
|
|
||||
|
|
||||
|
struct DirRV |
||||
|
{ |
||||
|
const fs::path *branch_path; |
||||
|
DIR *dir; |
||||
|
int err; |
||||
|
}; |
||||
|
|
||||
|
static |
||||
|
uint64_t |
||||
|
_dirent_exact_namelen(const struct dirent *d_) |
||||
|
{ |
||||
|
#ifdef _D_EXACT_NAMLEN |
||||
|
return _D_EXACT_NAMLEN(d_); |
||||
|
#elif defined _DIRENT_HAVE_D_NAMLEN |
||||
|
return d_->d_namlen; |
||||
|
#else |
||||
|
return strlen(d_->d_name); |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
inline |
||||
|
std::vector<std::future<DirRV>> |
||||
|
_opendir(ThreadPool &tp_, |
||||
|
const Branches::Ptr &branches_, |
||||
|
const fs::path &rel_dirpath_, |
||||
|
uid_t const uid_, |
||||
|
gid_t const gid_) |
||||
|
{ |
||||
|
std::vector<std::future<DirRV>> futures; |
||||
|
|
||||
|
futures.reserve(branches_->size()); |
||||
|
|
||||
|
for(const auto &branch : *branches_) |
||||
|
{ |
||||
|
auto func = |
||||
|
[&branch,&rel_dirpath_,uid_,gid_]() |
||||
|
{ |
||||
|
DIR *dir; |
||||
|
fs::path abs_dirpath; |
||||
|
const ugid::Set ugid(uid_,gid_); |
||||
|
|
||||
|
abs_dirpath = branch.path / rel_dirpath_; |
||||
|
|
||||
|
errno = 0; |
||||
|
dir = fs::opendir(abs_dirpath); |
||||
|
|
||||
|
return DirRV{&branch.path,dir,errno}; |
||||
|
}; |
||||
|
|
||||
|
auto rv = tp_.enqueue_task(std::move(func)); |
||||
|
|
||||
|
futures.emplace_back(std::move(rv)); |
||||
|
} |
||||
|
|
||||
|
return futures; |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
inline |
||||
|
int |
||||
|
_readdir(std::vector<std::future<DirRV>> &dh_futures_, |
||||
|
const fs::path &rel_dirpath_, |
||||
|
fuse_dirents_t *dirents_) |
||||
|
{ |
||||
|
Err err; |
||||
|
HashSet names; |
||||
|
fs::path rel_filepath; |
||||
|
|
||||
|
rel_filepath = rel_dirpath_ / "dummy"; |
||||
|
for(auto &dh_future : dh_futures_) |
||||
|
{ |
||||
|
int rv; |
||||
|
DirRV dirrv; |
||||
|
|
||||
|
dirrv = dh_future.get(); |
||||
|
|
||||
|
err = dirrv.err; |
||||
|
if(dirrv.dir == NULL) |
||||
|
continue; |
||||
|
|
||||
|
DEFER { fs::closedir(dirrv.dir); }; |
||||
|
|
||||
|
rv = 0; |
||||
|
for(dirent *de = fs::readdir(dirrv.dir); de && !rv; de = fs::readdir(dirrv.dir)) |
||||
|
{ |
||||
|
std::uint64_t namelen; |
||||
|
|
||||
|
namelen = ::_dirent_exact_namelen(de); |
||||
|
|
||||
|
rv = names.put(de->d_name,namelen); |
||||
|
if(rv == 0) |
||||
|
continue; |
||||
|
|
||||
|
rel_filepath.replace_filename(de->d_name); |
||||
|
de->d_ino = fs::inode::calc(*dirrv.branch_path, |
||||
|
rel_filepath, |
||||
|
DTTOIF(de->d_type), |
||||
|
de->d_ino); |
||||
|
|
||||
|
rv = fuse_dirents_add(dirents_,de,namelen); |
||||
|
if(rv == 0) |
||||
|
continue; |
||||
|
|
||||
|
err = ENOMEM; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return -err; |
||||
|
} |
@ -0,0 +1,79 @@ |
|||||
|
#pragma message "using getdents" |
||||
|
|
||||
|
#include "dirinfo.hpp" |
||||
|
#include "fs_close.hpp" |
||||
|
#include "fs_getdents64.hpp" |
||||
|
#include "fs_inode.hpp" |
||||
|
#include "fs_open.hpp" |
||||
|
#include "hashset.hpp" |
||||
|
#include "scope_guard.hpp" |
||||
|
|
||||
|
#include "fuse_dirents.hpp" |
||||
|
#include "fuse_msgbuf.hpp" |
||||
|
|
||||
|
|
||||
|
static |
||||
|
int |
||||
|
_readdir(const Branches::Ptr &branches_, |
||||
|
const fs::path &rel_dirpath_, |
||||
|
fuse_dirents_t *dirents_) |
||||
|
{ |
||||
|
HashSet names; |
||||
|
fs::path rel_filepath; |
||||
|
fs::path abs_dirpath; |
||||
|
fuse_msgbuf_t *buf; |
||||
|
|
||||
|
fuse_dirents_reset(dirents_); |
||||
|
|
||||
|
buf = msgbuf_alloc(); |
||||
|
DEFER { msgbuf_free(buf); }; |
||||
|
|
||||
|
rel_filepath = rel_dirpath_ / "dummy"; |
||||
|
for(const auto &branch : *branches_) |
||||
|
{ |
||||
|
int rv; |
||||
|
int fd; |
||||
|
|
||||
|
abs_dirpath = branch.path / rel_dirpath_; |
||||
|
|
||||
|
fd = fs::open_dir_ro(abs_dirpath); |
||||
|
if(fd < 0) |
||||
|
continue; |
||||
|
DEFER{ fs::close(fd); }; |
||||
|
|
||||
|
rv = 0; |
||||
|
while(true) |
||||
|
{ |
||||
|
ssize_t nread; |
||||
|
|
||||
|
nread = fs::getdents64(fd,buf->mem,buf->size); |
||||
|
if(nread <= 0) |
||||
|
break; |
||||
|
|
||||
|
for(ssize_t pos = 0; pos < nread;) |
||||
|
{ |
||||
|
int namelen; |
||||
|
fs::dirent64 *d = reinterpret_cast<fs::dirent64*>(&buf->mem[pos]); |
||||
|
|
||||
|
pos += d->d_reclen; |
||||
|
|
||||
|
namelen = d->d_namelen(); |
||||
|
rv = names.put(d->d_name,namelen); |
||||
|
if(rv == 0) |
||||
|
continue; |
||||
|
|
||||
|
rel_filepath.replace_filename(d->d_name); |
||||
|
d->d_ino = fs::inode::calc(branch.path, |
||||
|
rel_filepath, |
||||
|
DTTOIF(d->d_type), |
||||
|
d->d_ino); |
||||
|
|
||||
|
rv = fuse_dirents_add(dirents_,d,namelen); |
||||
|
if(rv) |
||||
|
return -ENOMEM; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,82 @@ |
|||||
|
#pragma message "using readdir" |
||||
|
|
||||
|
#include "fs_opendir.hpp" |
||||
|
#include "fs_closedir.hpp" |
||||
|
#include "fs_readdir.hpp" |
||||
|
#include "error.hpp" |
||||
|
#include "hashset.hpp" |
||||
|
#include "scope_guard.hpp" |
||||
|
#include "fs_inode.hpp" |
||||
|
#include "dirinfo.hpp" |
||||
|
|
||||
|
#include "fuse_dirents.hpp" |
||||
|
|
||||
|
#include <cstring> |
||||
|
|
||||
|
static |
||||
|
uint64_t |
||||
|
_dirent_exact_namelen(const struct dirent *d_) |
||||
|
{ |
||||
|
#ifdef _D_EXACT_NAMLEN |
||||
|
return _D_EXACT_NAMLEN(d_); |
||||
|
#elif defined _DIRENT_HAVE_D_NAMLEN |
||||
|
return d_->d_namlen; |
||||
|
#else |
||||
|
return strlen(d_->d_name); |
||||
|
#endif |
||||
|
} |
||||
|
|
||||
|
static |
||||
|
int |
||||
|
_readdir(const Branches::Ptr &branches_, |
||||
|
const fs::path &rel_dirpath_, |
||||
|
fuse_dirents_t *buf_) |
||||
|
{ |
||||
|
Err err; |
||||
|
HashSet names; |
||||
|
fs::path rel_filepath; |
||||
|
fs::path abs_dirpath; |
||||
|
|
||||
|
fuse_dirents_reset(buf_); |
||||
|
|
||||
|
rel_filepath = rel_dirpath_ / "dummy"; |
||||
|
for(const auto &branch : *branches_) |
||||
|
{ |
||||
|
int rv; |
||||
|
DIR *dh; |
||||
|
|
||||
|
abs_dirpath = branch.path / rel_dirpath_; |
||||
|
|
||||
|
errno = 0; |
||||
|
dh = fs::opendir(abs_dirpath); |
||||
|
err = -errno; |
||||
|
if(!dh) |
||||
|
continue; |
||||
|
|
||||
|
DEFER{ fs::closedir(dh); }; |
||||
|
|
||||
|
rv = 0; |
||||
|
for(dirent *de = fs::readdir(dh); de; de = fs::readdir(dh)) |
||||
|
{ |
||||
|
std::uint64_t namelen; |
||||
|
|
||||
|
namelen = ::_dirent_exact_namelen(de); |
||||
|
|
||||
|
rv = names.put(de->d_name,namelen); |
||||
|
if(rv == 0) |
||||
|
continue; |
||||
|
|
||||
|
rel_filepath.replace_filename(de->d_name); |
||||
|
de->d_ino = fs::inode::calc(branch.path, |
||||
|
rel_filepath, |
||||
|
DTTOIF(de->d_type), |
||||
|
de->d_ino); |
||||
|
|
||||
|
rv = fuse_dirents_add(buf_,de,namelen); |
||||
|
if(rv) |
||||
|
return -ENOMEM; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return err; |
||||
|
} |
@ -0,0 +1,11 @@ |
|||||
|
#pragma once
|
||||
|
|
||||
|
#ifdef __linux__
|
||||
|
|
||||
|
#include <sys/syscall.h>
|
||||
|
|
||||
|
#ifdef SYS_getdents64
|
||||
|
#define MERGERFS_SUPPORTED_GETDENTS64
|
||||
|
#endif
|
||||
|
|
||||
|
#endif
|
@ -0,0 +1,12 @@ |
|||||
|
#pragma once
|
||||
|
|
||||
|
#ifndef _GNU_SOURCE
|
||||
|
#define _GNU_SOURCE
|
||||
|
#endif
|
||||
|
|
||||
|
#include <fcntl.h>
|
||||
|
#include <sys/stat.h>
|
||||
|
|
||||
|
#ifdef STATX_TYPE
|
||||
|
#define MERGERFS_SUPPORTED_STATX
|
||||
|
#endif
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue