mirror of
https://github.com/trapexit/mergerfs.git
synced 2025-03-15 02:35:12 +08:00
readdir: add dirent index array
This removes the risk of corrupted data being sent back to the kernel should it use the offset from one opendir-readdir in another. In this case it would at most skip dirents. According to the standards the offset is only valid when used within the opendir -> releasedir but NFS uses offsets across independent calls.
This commit is contained in:
parent
c3f4d2914f
commit
c4a85f5fad
@ -22,6 +22,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "kvec.h"
|
||||||
#include "fuse_dirent.h"
|
#include "fuse_dirent.h"
|
||||||
#include "fuse_direntplus.h"
|
#include "fuse_direntplus.h"
|
||||||
#include "fuse_entry.h"
|
#include "fuse_entry.h"
|
||||||
@ -48,6 +49,7 @@ struct fuse_dirents_s
|
|||||||
char *buf;
|
char *buf;
|
||||||
uint64_t buf_len;
|
uint64_t buf_len;
|
||||||
uint64_t data_len;
|
uint64_t data_len;
|
||||||
|
kvec_t(uint32_t) offs;
|
||||||
fuse_dirents_type_t type;
|
fuse_dirents_type_t type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
90
libfuse/include/kvec.h
Normal file
90
libfuse/include/kvec.h
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
/* The MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2008, by Attractive Chaos <attractor@live.co.uk>
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||||
|
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||||
|
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||||
|
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||||
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
An example:
|
||||||
|
|
||||||
|
#include "kvec.h"
|
||||||
|
int main() {
|
||||||
|
kvec_t(int) array;
|
||||||
|
kv_init(array);
|
||||||
|
kv_push(int, array, 10); // append
|
||||||
|
kv_a(int, array, 20) = 5; // dynamic
|
||||||
|
kv_A(array, 20) = 4; // static
|
||||||
|
kv_destroy(array);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
2008-09-22 (0.1.0):
|
||||||
|
|
||||||
|
* The initial version.
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef AC_KVEC_H
|
||||||
|
#define AC_KVEC_H
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define kv_roundup32(x) (--(x), (x)|=(x)>>1, (x)|=(x)>>2, (x)|=(x)>>4, (x)|=(x)>>8, (x)|=(x)>>16, ++(x))
|
||||||
|
|
||||||
|
#define kvec_t(type) struct { size_t n, m; type *a; }
|
||||||
|
#define kv_init(v) ((v).n = (v).m = 0, (v).a = 0)
|
||||||
|
#define kv_destroy(v) free((v).a)
|
||||||
|
#define kv_A(v, i) ((v).a[(i)])
|
||||||
|
#define kv_pop(v) ((v).a[--(v).n])
|
||||||
|
#define kv_size(v) ((v).n)
|
||||||
|
#define kv_max(v) ((v).m)
|
||||||
|
|
||||||
|
#define kv_resize(type, v, s) ((v).m = (s), (v).a = (type*)realloc((v).a, sizeof(type) * (v).m))
|
||||||
|
|
||||||
|
#define kv_copy(type, v1, v0) do { \
|
||||||
|
if ((v1).m < (v0).n) kv_resize(type, v1, (v0).n); \
|
||||||
|
(v1).n = (v0).n; \
|
||||||
|
memcpy((v1).a, (v0).a, sizeof(type) * (v0).n); \
|
||||||
|
} while (0) \
|
||||||
|
|
||||||
|
#define kv_push(type, v, x) do { \
|
||||||
|
if ((v).n == (v).m) { \
|
||||||
|
(v).m = (v).m? (v).m<<1 : 2; \
|
||||||
|
(v).a = (type*)realloc((v).a, sizeof(type) * (v).m); \
|
||||||
|
} \
|
||||||
|
(v).a[(v).n++] = (x); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define kv_pushp(type, v) (((v).n == (v).m)? \
|
||||||
|
((v).m = ((v).m? (v).m<<1 : 2), \
|
||||||
|
(v).a = (type*)realloc((v).a, sizeof(type) * (v).m), 0) \
|
||||||
|
: 0), ((v).a + ((v).n++))
|
||||||
|
|
||||||
|
#define kv_a(type, v, i) (((v).m <= (size_t)(i)? \
|
||||||
|
((v).m = (v).n = (i) + 1, kv_roundup32((v).m), \
|
||||||
|
(v).a = (type*)realloc((v).a, sizeof(type) * (v).m), 0) \
|
||||||
|
: (v).n <= (size_t)(i)? (v).n = (i) + 1 \
|
||||||
|
: 0), (v).a[(i)])
|
||||||
|
|
||||||
|
#endif
|
@ -3387,20 +3387,24 @@ readdir_plus_fill(struct fuse *f_,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
uint64_t
|
size_t
|
||||||
convert_plus2normal(fuse_dirents_t *d_,
|
readdir_buf_size(fuse_dirents_t *d_,
|
||||||
uint64_t off_)
|
size_t size_,
|
||||||
|
off_t off_)
|
||||||
{
|
{
|
||||||
uint64_t ino;
|
if(off_ >= kv_size(d_->offs))
|
||||||
fuse_dirent_t *d;
|
return 0;
|
||||||
fuse_direntplus_t *dp;
|
if((kv_A(d_->offs,off_) + size_) > d_->data_len)
|
||||||
|
return (d_->data_len - kv_A(d_->offs,off_));
|
||||||
|
return size_;
|
||||||
|
}
|
||||||
|
|
||||||
dp = (fuse_direntplus_t*)&d_->buf[off_];
|
static
|
||||||
ino = dp->dirent.ino;
|
char*
|
||||||
fuse_dirents_convert_plus2normal(d_);
|
readdir_buf(fuse_dirents_t *d_,
|
||||||
d = fuse_dirents_find(d_,ino);
|
off_t off_)
|
||||||
|
{
|
||||||
return d->off;
|
return &d_->buf[kv_A(d_->offs,off_)];
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
@ -3433,16 +3437,10 @@ fuse_lib_readdir(fuse_req_t req_,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(off_ >= d->data_len)
|
size_ = readdir_buf_size(d,size_,off_);
|
||||||
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_,
|
fuse_reply_buf(req_,
|
||||||
&d->buf[off_],
|
readdir_buf(d,off_),
|
||||||
size_);
|
size_);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
@ -3479,13 +3477,10 @@ fuse_lib_readdir_plus(fuse_req_t req_,
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(off_ >= d->data_len)
|
size_ = readdir_buf_size(d,size_,off_);
|
||||||
size_ = 0;
|
|
||||||
else if((off_ + size_) > d->data_len)
|
|
||||||
size_ = (d->data_len - off_);
|
|
||||||
|
|
||||||
fuse_reply_buf(req_,
|
fuse_reply_buf(req_,
|
||||||
&d->buf[off_],
|
readdir_buf(d,off_),
|
||||||
size_);
|
size_);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
@ -54,8 +54,8 @@ fuse_direntplus_size(const uint64_t namelen_)
|
|||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
fuse_dirents_resize(fuse_dirents_t *d_,
|
fuse_dirents_buf_resize(fuse_dirents_t *d_,
|
||||||
uint64_t size_)
|
uint64_t size_)
|
||||||
{
|
{
|
||||||
void *p;
|
void *p;
|
||||||
|
|
||||||
@ -74,19 +74,44 @@ fuse_dirents_resize(fuse_dirents_t *d_,
|
|||||||
|
|
||||||
static
|
static
|
||||||
void*
|
void*
|
||||||
fuse_dirents_alloc(fuse_dirents_t *d_,
|
fuse_dirents_dirent_alloc(fuse_dirents_t *d_,
|
||||||
uint64_t size_)
|
uint64_t namelen_)
|
||||||
{
|
{
|
||||||
int rv;
|
int rv;
|
||||||
|
uint64_t size;
|
||||||
fuse_dirent_t *d;
|
fuse_dirent_t *d;
|
||||||
|
|
||||||
rv = fuse_dirents_resize(d_,size_);
|
size = fuse_dirent_size(namelen_);
|
||||||
|
|
||||||
|
rv = fuse_dirents_buf_resize(d_,size);
|
||||||
if(rv)
|
if(rv)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
d = (fuse_dirent_t*)&d_->buf[d_->data_len];
|
d = (fuse_dirent_t*)&d_->buf[d_->data_len];
|
||||||
|
|
||||||
d_->data_len += size_;
|
d_->data_len += 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*)&d_->buf[d_->data_len];
|
||||||
|
|
||||||
|
d_->data_len += size;
|
||||||
|
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
@ -200,38 +225,7 @@ fuse_dirents_find(fuse_dirents_t *d_,
|
|||||||
int
|
int
|
||||||
fuse_dirents_convert_plus2normal(fuse_dirents_t *d_)
|
fuse_dirents_convert_plus2normal(fuse_dirents_t *d_)
|
||||||
{
|
{
|
||||||
int rv;
|
return -ENOSYS;
|
||||||
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
|
int
|
||||||
@ -239,7 +233,6 @@ fuse_dirents_add(fuse_dirents_t *d_,
|
|||||||
const struct dirent *dirent_,
|
const struct dirent *dirent_,
|
||||||
const uint64_t namelen_)
|
const uint64_t namelen_)
|
||||||
{
|
{
|
||||||
uint64_t size;
|
|
||||||
fuse_dirent_t *d;
|
fuse_dirent_t *d;
|
||||||
|
|
||||||
switch(d_->type)
|
switch(d_->type)
|
||||||
@ -253,14 +246,13 @@ fuse_dirents_add(fuse_dirents_t *d_,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = fuse_dirent_size(namelen_);
|
d = fuse_dirents_dirent_alloc(d_,namelen_);
|
||||||
|
|
||||||
d = fuse_dirents_alloc(d_,size);
|
|
||||||
if(d == NULL)
|
if(d == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
d->off = kv_size(d_->offs);
|
||||||
|
kv_push(uint32_t,d_->offs,d_->data_len);
|
||||||
d->ino = dirent_->d_ino;
|
d->ino = dirent_->d_ino;
|
||||||
d->off = d_->data_len;
|
|
||||||
d->namelen = namelen_;
|
d->namelen = namelen_;
|
||||||
d->type = dirent_->d_type;
|
d->type = dirent_->d_type;
|
||||||
memcpy(d->name,dirent_->d_name,namelen_);
|
memcpy(d->name,dirent_->d_name,namelen_);
|
||||||
@ -275,7 +267,6 @@ fuse_dirents_add_plus(fuse_dirents_t *d_,
|
|||||||
const fuse_entry_t *entry_,
|
const fuse_entry_t *entry_,
|
||||||
const struct stat *st_)
|
const struct stat *st_)
|
||||||
{
|
{
|
||||||
uint64_t size;
|
|
||||||
fuse_direntplus_t *d;
|
fuse_direntplus_t *d;
|
||||||
|
|
||||||
switch(d_->type)
|
switch(d_->type)
|
||||||
@ -289,14 +280,13 @@ fuse_dirents_add_plus(fuse_dirents_t *d_,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = fuse_direntplus_size(namelen_);
|
d = fuse_dirents_direntplus_alloc(d_,namelen_);
|
||||||
|
|
||||||
d = fuse_dirents_alloc(d_,size);
|
|
||||||
if(d == NULL)
|
if(d == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
d->dirent.off = kv_size(d_->offs);
|
||||||
|
kv_push(uint32_t,d_->offs,d_->data_len);
|
||||||
d->dirent.ino = dirent_->d_ino;
|
d->dirent.ino = dirent_->d_ino;
|
||||||
d->dirent.off = d_->data_len;
|
|
||||||
d->dirent.namelen = namelen_;
|
d->dirent.namelen = namelen_;
|
||||||
d->dirent.type = dirent_->d_type;
|
d->dirent.type = dirent_->d_type;
|
||||||
memcpy(d->dirent.name,dirent_->d_name,namelen_);
|
memcpy(d->dirent.name,dirent_->d_name,namelen_);
|
||||||
@ -313,7 +303,6 @@ fuse_dirents_add_linux(fuse_dirents_t *d_,
|
|||||||
const struct linux_dirent *dirent_,
|
const struct linux_dirent *dirent_,
|
||||||
const uint64_t namelen_)
|
const uint64_t namelen_)
|
||||||
{
|
{
|
||||||
uint64_t size;
|
|
||||||
fuse_dirent_t *d;
|
fuse_dirent_t *d;
|
||||||
|
|
||||||
switch(d_->type)
|
switch(d_->type)
|
||||||
@ -327,14 +316,13 @@ fuse_dirents_add_linux(fuse_dirents_t *d_,
|
|||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = fuse_dirent_size(namelen_);
|
d = fuse_dirents_dirent_alloc(d_,namelen_);
|
||||||
|
|
||||||
d = fuse_dirents_alloc(d_,size);
|
|
||||||
if(d == NULL)
|
if(d == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
d->off = kv_size(d_->offs);
|
||||||
|
kv_push(uint32_t,d_->offs,d_->data_len);
|
||||||
d->ino = dirent_->ino;
|
d->ino = dirent_->ino;
|
||||||
d->off = d_->data_len;
|
|
||||||
d->namelen = namelen_;
|
d->namelen = namelen_;
|
||||||
d->type = *((char*)dirent_ + dirent_->reclen - 1);
|
d->type = *((char*)dirent_ + dirent_->reclen - 1);
|
||||||
memcpy(d->name,dirent_->name,namelen_);
|
memcpy(d->name,dirent_->name,namelen_);
|
||||||
@ -349,7 +337,6 @@ fuse_dirents_add_linux_plus(fuse_dirents_t *d_,
|
|||||||
const fuse_entry_t *entry_,
|
const fuse_entry_t *entry_,
|
||||||
const struct stat *st_)
|
const struct stat *st_)
|
||||||
{
|
{
|
||||||
uint64_t size;
|
|
||||||
fuse_direntplus_t *d;
|
fuse_direntplus_t *d;
|
||||||
|
|
||||||
switch(d_->type)
|
switch(d_->type)
|
||||||
@ -363,14 +350,13 @@ fuse_dirents_add_linux_plus(fuse_dirents_t *d_,
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
size = fuse_direntplus_size(namelen_);
|
d = fuse_dirents_direntplus_alloc(d_,namelen_);
|
||||||
|
|
||||||
d = fuse_dirents_alloc(d_,size);
|
|
||||||
if(d == NULL)
|
if(d == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
d->dirent.off = kv_size(d_->offs);
|
||||||
|
kv_push(uint32_t,d_->offs,d_->data_len);
|
||||||
d->dirent.ino = dirent_->ino;
|
d->dirent.ino = dirent_->ino;
|
||||||
d->dirent.off = d_->data_len;
|
|
||||||
d->dirent.namelen = namelen_;
|
d->dirent.namelen = namelen_;
|
||||||
d->dirent.type = *((char*)dirent_ + dirent_->reclen - 1);
|
d->dirent.type = *((char*)dirent_ + dirent_->reclen - 1);
|
||||||
memcpy(d->dirent.name,dirent_->name,namelen_);
|
memcpy(d->dirent.name,dirent_->name,namelen_);
|
||||||
@ -385,8 +371,9 @@ fuse_dirents_add_linux_plus(fuse_dirents_t *d_,
|
|||||||
void
|
void
|
||||||
fuse_dirents_reset(fuse_dirents_t *d_)
|
fuse_dirents_reset(fuse_dirents_t *d_)
|
||||||
{
|
{
|
||||||
d_->data_len = 0;
|
d_->data_len = 0;
|
||||||
d_->type = UNSET;
|
d_->type = UNSET;
|
||||||
|
kv_size(d_->offs) = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -403,6 +390,10 @@ fuse_dirents_init(fuse_dirents_t *d_)
|
|||||||
d_->data_len = 0;
|
d_->data_len = 0;
|
||||||
d_->type = UNSET;
|
d_->type = UNSET;
|
||||||
|
|
||||||
|
kv_init(d_->offs);
|
||||||
|
kv_resize(uint32_t,d_->offs,64);
|
||||||
|
kv_push(uint32_t,d_->offs,0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -412,5 +403,8 @@ fuse_dirents_free(fuse_dirents_t *d_)
|
|||||||
d_->buf_len = 0;
|
d_->buf_len = 0;
|
||||||
d_->data_len = 0;
|
d_->data_len = 0;
|
||||||
d_->type = UNSET;
|
d_->type = UNSET;
|
||||||
|
|
||||||
|
kv_destroy(d_->offs);
|
||||||
|
|
||||||
free(d_->buf);
|
free(d_->buf);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user