version 1.1, 2013/10/14 10:32:48
|
version 1.1.1.3, 2016/11/02 10:35:00
|
Line 1
|
Line 1
|
|
#include "first.h" |
|
|
#include "log.h" |
#include "log.h" |
#include "stat_cache.h" |
#include "stat_cache.h" |
#include "fdevent.h" |
#include "fdevent.h" |
Line 18
|
Line 20
|
# include <attr/attributes.h> |
# include <attr/attributes.h> |
#endif |
#endif |
|
|
|
#ifdef HAVE_SYS_EXTATTR_H |
|
# include <sys/extattr.h> |
|
#endif |
|
|
#ifdef HAVE_FAM_H |
#ifdef HAVE_FAM_H |
# include <fam.h> |
# include <fam.h> |
#endif |
#endif |
Line 69
|
Line 75
|
#ifdef HAVE_FAM_H |
#ifdef HAVE_FAM_H |
typedef struct { |
typedef struct { |
FAMRequest *req; |
FAMRequest *req; |
FAMConnection *fc; |
|
|
|
buffer *name; |
buffer *name; |
|
|
Line 102 static fake_keys ctrl;
|
Line 107 static fake_keys ctrl;
|
#endif |
#endif |
|
|
stat_cache *stat_cache_init(void) { |
stat_cache *stat_cache_init(void) { |
stat_cache *fc = NULL; | stat_cache *sc = NULL; |
|
|
fc = calloc(1, sizeof(*fc)); | sc = calloc(1, sizeof(*sc)); |
| force_assert(NULL != sc); |
|
|
fc->dir_name = buffer_init(); | sc->dir_name = buffer_init(); |
fc->hash_key = buffer_init(); | sc->hash_key = buffer_init(); |
| |
#ifdef HAVE_FAM_H |
#ifdef HAVE_FAM_H |
fc->fam = calloc(1, sizeof(*fc->fam)); | sc->fam_fcce_ndx = -1; |
#endif |
#endif |
|
|
#ifdef DEBUG_STAT_CACHE |
#ifdef DEBUG_STAT_CACHE |
ctrl.size = 0; |
ctrl.size = 0; |
#endif |
#endif |
|
|
return fc; | return sc; |
} |
} |
|
|
static stat_cache_entry * stat_cache_entry_init(void) { |
static stat_cache_entry * stat_cache_entry_init(void) { |
stat_cache_entry *sce = NULL; |
stat_cache_entry *sce = NULL; |
|
|
sce = calloc(1, sizeof(*sce)); |
sce = calloc(1, sizeof(*sce)); |
|
force_assert(NULL != sce); |
|
|
sce->name = buffer_init(); |
sce->name = buffer_init(); |
sce->etag = buffer_init(); |
sce->etag = buffer_init(); |
Line 147 static fam_dir_entry * fam_dir_entry_init(void) {
|
Line 155 static fam_dir_entry * fam_dir_entry_init(void) {
|
fam_dir_entry *fam_dir = NULL; |
fam_dir_entry *fam_dir = NULL; |
|
|
fam_dir = calloc(1, sizeof(*fam_dir)); |
fam_dir = calloc(1, sizeof(*fam_dir)); |
|
force_assert(NULL != fam_dir); |
|
|
fam_dir->name = buffer_init(); |
fam_dir->name = buffer_init(); |
|
|
return fam_dir; |
return fam_dir; |
} |
} |
|
|
static void fam_dir_entry_free(void *data) { | static void fam_dir_entry_free(FAMConnection *fc, void *data) { |
fam_dir_entry *fam_dir = data; |
fam_dir_entry *fam_dir = data; |
|
|
if (!fam_dir) return; |
if (!fam_dir) return; |
|
|
FAMCancelMonitor(fam_dir->fc, fam_dir->req); | FAMCancelMonitor(fc, fam_dir->req); |
|
|
buffer_free(fam_dir->name); |
buffer_free(fam_dir->name); |
free(fam_dir->req); |
free(fam_dir->req); |
Line 177 void stat_cache_free(stat_cache *sc) {
|
Line 186 void stat_cache_free(stat_cache *sc) {
|
stat_cache_entry_free(node->data); |
stat_cache_entry_free(node->data); |
sc->files = splaytree_delete(sc->files, node->key); |
sc->files = splaytree_delete(sc->files, node->key); |
|
|
assert(osize - 1 == splaytree_size(sc->files)); | force_assert(osize - 1 == splaytree_size(sc->files)); |
} |
} |
|
|
buffer_free(sc->dir_name); |
buffer_free(sc->dir_name); |
Line 190 void stat_cache_free(stat_cache *sc) {
|
Line 199 void stat_cache_free(stat_cache *sc) {
|
|
|
osize = sc->dirs->size; |
osize = sc->dirs->size; |
|
|
fam_dir_entry_free(node->data); | fam_dir_entry_free(&sc->fam, node->data); |
sc->dirs = splaytree_delete(sc->dirs, node->key); |
sc->dirs = splaytree_delete(sc->dirs, node->key); |
|
|
if (osize == 1) { |
if (osize == 1) { |
assert(NULL == sc->dirs); | force_assert(NULL == sc->dirs); |
} else { |
} else { |
assert(osize == (sc->dirs->size + 1)); | force_assert(osize == (sc->dirs->size + 1)); |
} |
} |
} |
} |
|
|
if (sc->fam) { | if (-1 != sc->fam_fcce_ndx) { |
FAMClose(sc->fam); | /* fd events already gone */ |
free(sc->fam); | sc->fam_fcce_ndx = -1; |
| |
| FAMClose(&sc->fam); |
} |
} |
#endif |
#endif |
free(sc); |
free(sc); |
} |
} |
|
|
#ifdef HAVE_XATTR | #if defined(HAVE_XATTR) |
static int stat_cache_attr_get(buffer *buf, char *name) { | static int stat_cache_attr_get(buffer *buf, char *name, char *xattrname) { |
int attrlen; |
int attrlen; |
int ret; |
int ret; |
|
|
attrlen = 1024; | buffer_string_prepare_copy(buf, 1023); |
buffer_prepare_copy(buf, attrlen); | attrlen = buf->size - 1; |
attrlen--; | if(0 == (ret = attr_get(name, xattrname, buf->ptr, &attrlen, 0))) { |
if(0 == (ret = attr_get(name, "Content-Type", buf->ptr, &attrlen, 0))) { | buffer_commit(buf, attrlen); |
| } |
| return ret; |
| } |
| #elif defined(HAVE_EXTATTR) |
| static int stat_cache_attr_get(buffer *buf, char *name, char *xattrname) { |
| ssize_t attrlen; |
| |
| buffer_string_prepare_copy(buf, 1023); |
| |
| if (-1 != (attrlen = extattr_get_file(name, EXTATTR_NAMESPACE_USER, xattrname, buf->ptr, buf->size - 1))) { |
buf->used = attrlen + 1; |
buf->used = attrlen + 1; |
buf->ptr[attrlen] = '\0'; |
buf->ptr[attrlen] = '\0'; |
|
return 0; |
} |
} |
return ret; | return -1; |
} |
} |
#endif |
#endif |
|
|
Line 232 static uint32_t hashme(buffer *str) {
|
Line 254 static uint32_t hashme(buffer *str) {
|
hash = ((hash << 5) + hash) + *s; |
hash = ((hash << 5) + hash) + *s; |
} |
} |
|
|
hash &= ~(1 << 31); /* strip the highest bit */ | hash &= ~(((uint32_t)1) << 31); /* strip the highest bit */ |
|
|
return hash; |
return hash; |
} |
} |
Line 246 handler_t stat_cache_handle_fdevent(server *srv, void
|
Line 268 handler_t stat_cache_handle_fdevent(server *srv, void
|
UNUSED(_fce); |
UNUSED(_fce); |
/* */ |
/* */ |
|
|
if ((revent & FDEVENT_IN) && | if (revent & FDEVENT_IN) { |
sc->fam) { | events = FAMPending(&sc->fam); |
|
|
events = FAMPending(sc->fam); |
|
|
|
for (i = 0; i < events; i++) { |
for (i = 0; i < events; i++) { |
FAMEvent fe; |
FAMEvent fe; |
fam_dir_entry *fam_dir; |
fam_dir_entry *fam_dir; |
splay_tree *node; |
splay_tree *node; |
int ndx, j; |
int ndx, j; |
|
|
FAMNextEvent(sc->fam, &fe); | FAMNextEvent(&sc->fam, &fe); |
|
|
/* handle event */ |
/* handle event */ |
|
|
Line 277 handler_t stat_cache_handle_fdevent(server *srv, void
|
Line 297 handler_t stat_cache_handle_fdevent(server *srv, void
|
|
|
for (j = 0; j < 2; j++) { |
for (j = 0; j < 2; j++) { |
buffer_copy_string(sc->hash_key, fe.filename); |
buffer_copy_string(sc->hash_key, fe.filename); |
buffer_append_long(sc->hash_key, j); | buffer_append_int(sc->hash_key, j); |
|
|
ndx = hashme(sc->hash_key); |
ndx = hashme(sc->hash_key); |
|
|
Line 287 handler_t stat_cache_handle_fdevent(server *srv, void
|
Line 307 handler_t stat_cache_handle_fdevent(server *srv, void
|
if (node && (node->key == ndx)) { |
if (node && (node->key == ndx)) { |
int osize = splaytree_size(sc->dirs); |
int osize = splaytree_size(sc->dirs); |
|
|
fam_dir_entry_free(node->data); | fam_dir_entry_free(&sc->fam, node->data); |
sc->dirs = splaytree_delete(sc->dirs, ndx); |
sc->dirs = splaytree_delete(sc->dirs, ndx); |
|
|
assert(osize - 1 == splaytree_size(sc->dirs)); | force_assert(osize - 1 == splaytree_size(sc->dirs)); |
} |
} |
} |
} |
break; |
break; |
Line 302 handler_t stat_cache_handle_fdevent(server *srv, void
|
Line 322 handler_t stat_cache_handle_fdevent(server *srv, void
|
|
|
if (revent & FDEVENT_HUP) { |
if (revent & FDEVENT_HUP) { |
/* fam closed the connection */ |
/* fam closed the connection */ |
srv->stat_cache->fam_fcce_ndx = -1; | fdevent_event_del(srv->ev, &(sc->fam_fcce_ndx), FAMCONNECTION_GETFD(&sc->fam)); |
| fdevent_unregister(srv->ev, FAMCONNECTION_GETFD(&sc->fam)); |
|
|
fdevent_event_del(srv->ev, &(sc->fam_fcce_ndx), FAMCONNECTION_GETFD(sc->fam)); | FAMClose(&sc->fam); |
fdevent_unregister(srv->ev, FAMCONNECTION_GETFD(sc->fam)); | |
| |
FAMClose(sc->fam); | |
free(sc->fam); | |
| |
sc->fam = NULL; | |
} |
} |
|
|
return HANDLER_GO_ON; |
return HANDLER_GO_ON; |
Line 319 handler_t stat_cache_handle_fdevent(server *srv, void
|
Line 334 handler_t stat_cache_handle_fdevent(server *srv, void
|
static int buffer_copy_dirname(buffer *dst, buffer *file) { |
static int buffer_copy_dirname(buffer *dst, buffer *file) { |
size_t i; |
size_t i; |
|
|
if (buffer_is_empty(file)) return -1; | if (buffer_string_is_empty(file)) return -1; |
|
|
for (i = file->used - 1; i+1 > 0; i--) { | for (i = buffer_string_length(file); i > 0; i--) { |
if (file->ptr[i] == '/') { |
if (file->ptr[i] == '/') { |
buffer_copy_string_len(dst, file->ptr, i); |
buffer_copy_string_len(dst, file->ptr, i); |
return 0; |
return 0; |
Line 359 handler_t stat_cache_get_entry(server *srv, connection
|
Line 374 handler_t stat_cache_get_entry(server *srv, connection
|
#ifdef HAVE_FAM_H |
#ifdef HAVE_FAM_H |
fam_dir_entry *fam_dir = NULL; |
fam_dir_entry *fam_dir = NULL; |
int dir_ndx = -1; |
int dir_ndx = -1; |
splay_tree *dir_node = NULL; |
|
#endif |
#endif |
stat_cache_entry *sce = NULL; |
stat_cache_entry *sce = NULL; |
stat_cache *sc; |
stat_cache *sc; |
Line 372 handler_t stat_cache_get_entry(server *srv, connection
|
Line 386 handler_t stat_cache_get_entry(server *srv, connection
|
#endif |
#endif |
|
|
int file_ndx; |
int file_ndx; |
splay_tree *file_node = NULL; |
|
|
|
*ret_sce = NULL; |
*ret_sce = NULL; |
|
|
Line 382 handler_t stat_cache_get_entry(server *srv, connection
|
Line 395 handler_t stat_cache_get_entry(server *srv, connection
|
|
|
sc = srv->stat_cache; |
sc = srv->stat_cache; |
|
|
buffer_copy_string_buffer(sc->hash_key, name); | buffer_copy_buffer(sc->hash_key, name); |
buffer_append_long(sc->hash_key, con->conf.follow_symlink); | buffer_append_int(sc->hash_key, con->conf.follow_symlink); |
|
|
file_ndx = hashme(sc->hash_key); |
file_ndx = hashme(sc->hash_key); |
sc->files = splaytree_splay(sc->files, file_ndx); |
sc->files = splaytree_splay(sc->files, file_ndx); |
Line 397 handler_t stat_cache_get_entry(server *srv, connection
|
Line 410 handler_t stat_cache_get_entry(server *srv, connection
|
if (sc->files && (sc->files->key == file_ndx)) { |
if (sc->files && (sc->files->key == file_ndx)) { |
#ifdef DEBUG_STAT_CACHE |
#ifdef DEBUG_STAT_CACHE |
/* it was in the cache */ |
/* it was in the cache */ |
assert(i < ctrl.used); | force_assert(i < ctrl.used); |
#endif |
#endif |
|
|
/* we have seen this file already and |
/* we have seen this file already and |
* don't stat() it again in the same second */ |
* don't stat() it again in the same second */ |
|
|
file_node = sc->files; | sce = sc->files->data; |
|
|
sce = file_node->data; |
|
|
|
/* check if the name is the same, we might have a collision */ |
/* check if the name is the same, we might have a collision */ |
|
|
if (buffer_is_equal(name, sce->name)) { |
if (buffer_is_equal(name, sce->name)) { |
if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) { |
if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_SIMPLE) { |
if (sce->stat_ts == srv->cur_ts) { | if (sce->stat_ts == srv->cur_ts && con->conf.follow_symlink) { |
*ret_sce = sce; |
*ret_sce = sce; |
return HANDLER_GO_ON; |
return HANDLER_GO_ON; |
} |
} |
} |
} |
} else { |
} else { |
/* oops, a collision, | /* collision, forget about the entry */ |
* | sce = NULL; |
* file_node is used by the FAM check below to see if we know this file | |
* and if we can save a stat(). | |
* | |
* BUT, the sce is not reset here as the entry into the cache is ok, we | |
* it is just not pointing to our requested file. | |
* | |
* */ | |
| |
file_node = NULL; | |
} |
} |
} else { |
} else { |
#ifdef DEBUG_STAT_CACHE |
#ifdef DEBUG_STAT_CACHE |
Line 435 handler_t stat_cache_get_entry(server *srv, connection
|
Line 437 handler_t stat_cache_get_entry(server *srv, connection
|
log_error_write(srv, __FILE__, __LINE__, "xSB", |
log_error_write(srv, __FILE__, __LINE__, "xSB", |
file_ndx, "was already inserted but not found in cache, ", name); |
file_ndx, "was already inserted but not found in cache, ", name); |
} |
} |
assert(i == ctrl.used); | force_assert(i == ctrl.used); |
#endif |
#endif |
} |
} |
|
|
Line 448 handler_t stat_cache_get_entry(server *srv, connection
|
Line 450 handler_t stat_cache_get_entry(server *srv, connection
|
return HANDLER_ERROR; |
return HANDLER_ERROR; |
} |
} |
|
|
buffer_copy_string_buffer(sc->hash_key, sc->dir_name); | buffer_copy_buffer(sc->hash_key, sc->dir_name); |
buffer_append_long(sc->hash_key, con->conf.follow_symlink); | buffer_append_int(sc->hash_key, con->conf.follow_symlink); |
|
|
dir_ndx = hashme(sc->hash_key); |
dir_ndx = hashme(sc->hash_key); |
|
|
sc->dirs = splaytree_splay(sc->dirs, dir_ndx); |
sc->dirs = splaytree_splay(sc->dirs, dir_ndx); |
|
|
if (sc->dirs && (sc->dirs->key == dir_ndx)) { | if ((NULL != sc->dirs) && (sc->dirs->key == dir_ndx)) { |
dir_node = sc->dirs; | fam_dir = sc->dirs->data; |
} | |
|
|
if (dir_node && file_node) { | /* check whether we got a collision */ |
/* we found a file */ | if (buffer_is_equal(sc->dir_name, fam_dir->name)) { |
| /* test whether a found file cache entry is still ok */ |
| if ((NULL != sce) && (fam_dir->version == sce->dir_version)) { |
| /* the stat()-cache entry is still ok */ |
|
|
sce = file_node->data; | *ret_sce = sce; |
fam_dir = dir_node->data; | return HANDLER_GO_ON; |
| } |
if (fam_dir->version == sce->dir_version) { | } else { |
/* the stat()-cache entry is still ok */ | /* hash collision, forget about the entry */ |
| fam_dir = NULL; |
*ret_sce = sce; | |
return HANDLER_GO_ON; | |
} |
} |
} |
} |
} |
} |
Line 488 handler_t stat_cache_get_entry(server *srv, connection
|
Line 490 handler_t stat_cache_get_entry(server *srv, connection
|
|
|
if (S_ISREG(st.st_mode)) { |
if (S_ISREG(st.st_mode)) { |
/* fix broken stat/open for symlinks to reg files with appended slash on freebsd,osx */ |
/* fix broken stat/open for symlinks to reg files with appended slash on freebsd,osx */ |
if (name->ptr[name->used-2] == '/') { | if (name->ptr[buffer_string_length(name) - 1] == '/') { |
errno = ENOTDIR; |
errno = ENOTDIR; |
return HANDLER_ERROR; |
return HANDLER_ERROR; |
} |
} |
Line 501 handler_t stat_cache_get_entry(server *srv, connection
|
Line 503 handler_t stat_cache_get_entry(server *srv, connection
|
} |
} |
|
|
if (NULL == sce) { |
if (NULL == sce) { |
#ifdef DEBUG_STAT_CACHE |
|
int osize = splaytree_size(sc->files); |
|
#endif |
|
|
|
sce = stat_cache_entry_init(); |
sce = stat_cache_entry_init(); |
buffer_copy_string_buffer(sce->name, name); | buffer_copy_buffer(sce->name, name); |
|
|
sc->files = splaytree_insert(sc->files, file_ndx, sce); | /* already splayed file_ndx */ |
#ifdef DEBUG_STAT_CACHE | if ((NULL != sc->files) && (sc->files->key == file_ndx)) { |
if (ctrl.size == 0) { | /* hash collision: replace old entry */ |
ctrl.size = 16; | stat_cache_entry_free(sc->files->data); |
ctrl.used = 0; | sc->files->data = sce; |
ctrl.ptr = malloc(ctrl.size * sizeof(*ctrl.ptr)); | } else { |
} else if (ctrl.size == ctrl.used) { | int osize = splaytree_size(sc->files); |
ctrl.size += 16; | |
ctrl.ptr = realloc(ctrl.ptr, ctrl.size * sizeof(*ctrl.ptr)); | |
} | |
|
|
ctrl.ptr[ctrl.used++] = file_ndx; | sc->files = splaytree_insert(sc->files, file_ndx, sce); |
| force_assert(osize + 1 == splaytree_size(sc->files)); |
|
|
assert(sc->files); | #ifdef DEBUG_STAT_CACHE |
assert(sc->files->data == sce); | if (ctrl.size == 0) { |
assert(osize + 1 == splaytree_size(sc->files)); | ctrl.size = 16; |
| ctrl.used = 0; |
| ctrl.ptr = malloc(ctrl.size * sizeof(*ctrl.ptr)); |
| force_assert(NULL != ctrl.ptr); |
| } else if (ctrl.size == ctrl.used) { |
| ctrl.size += 16; |
| ctrl.ptr = realloc(ctrl.ptr, ctrl.size * sizeof(*ctrl.ptr)); |
| force_assert(NULL != ctrl.ptr); |
| } |
| |
| ctrl.ptr[ctrl.used++] = file_ndx; |
#endif |
#endif |
|
} |
|
force_assert(sc->files); |
|
force_assert(sc->files->data == sce); |
} |
} |
|
|
sce->st = st; |
sce->st = st; |
Line 560 handler_t stat_cache_get_entry(server *srv, connection
|
Line 570 handler_t stat_cache_get_entry(server *srv, connection
|
* we assume "/" can not be symlink, so |
* we assume "/" can not be symlink, so |
* skip the symlink stuff if our path is / |
* skip the symlink stuff if our path is / |
**/ |
**/ |
else if ((name->used > 2)) { | else if (buffer_string_length(name) > 1) { |
buffer *dname; |
buffer *dname; |
char *s_cur; |
char *s_cur; |
|
|
dname = buffer_init(); |
dname = buffer_init(); |
buffer_copy_string_buffer(dname, name); | buffer_copy_buffer(dname, name); |
|
|
while ((s_cur = strrchr(dname->ptr,'/'))) { | while ((s_cur = strrchr(dname->ptr, '/'))) { |
*s_cur = '\0'; | buffer_string_set_length(dname, s_cur - dname->ptr); |
dname->used = s_cur - dname->ptr + 1; | |
if (dname->ptr == s_cur) { |
if (dname->ptr == s_cur) { |
#ifdef DEBUG_STAT_CACHE |
#ifdef DEBUG_STAT_CACHE |
log_error_write(srv, __FILE__, __LINE__, "s", "reached /"); |
log_error_write(srv, __FILE__, __LINE__, "s", "reached /"); |
Line 597 handler_t stat_cache_get_entry(server *srv, connection
|
Line 606 handler_t stat_cache_get_entry(server *srv, connection
|
if (S_ISREG(st.st_mode)) { |
if (S_ISREG(st.st_mode)) { |
/* determine mimetype */ |
/* determine mimetype */ |
buffer_reset(sce->content_type); |
buffer_reset(sce->content_type); |
#ifdef HAVE_XATTR | #if defined(HAVE_XATTR) || defined(HAVE_EXTATTR) |
if (con->conf.use_xattr) { |
if (con->conf.use_xattr) { |
stat_cache_attr_get(sce->content_type, name->ptr); | stat_cache_attr_get(sce->content_type, name->ptr, srv->srvconf.xattr_name->ptr); |
} |
} |
#endif |
#endif |
/* xattr did not set a content-type. ask the config */ |
/* xattr did not set a content-type. ask the config */ |
if (buffer_is_empty(sce->content_type)) { | if (buffer_string_is_empty(sce->content_type)) { |
| size_t namelen = buffer_string_length(name); |
| |
for (k = 0; k < con->conf.mimetypes->used; k++) { |
for (k = 0; k < con->conf.mimetypes->used; k++) { |
data_string *ds = (data_string *)con->conf.mimetypes->data[k]; |
data_string *ds = (data_string *)con->conf.mimetypes->data[k]; |
buffer *type = ds->key; |
buffer *type = ds->key; |
|
size_t typelen = buffer_string_length(type); |
|
|
if (type->used == 0) continue; | if (buffer_is_empty(type)) continue; |
|
|
/* check if the right side is the same */ |
/* check if the right side is the same */ |
if (type->used > name->used) continue; | if (typelen > namelen) continue; |
|
|
if (0 == strncasecmp(name->ptr + name->used - type->used, type->ptr, type->used - 1)) { | if (0 == strncasecmp(name->ptr + namelen - typelen, type->ptr, typelen)) { |
buffer_copy_string_buffer(sce->content_type, ds->value); | buffer_copy_buffer(sce->content_type, ds->value); |
break; |
break; |
} |
} |
} |
} |
Line 625 handler_t stat_cache_get_entry(server *srv, connection
|
Line 637 handler_t stat_cache_get_entry(server *srv, connection
|
} |
} |
|
|
#ifdef HAVE_FAM_H |
#ifdef HAVE_FAM_H |
if (sc->fam && | if (srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM) { |
(srv->srvconf.stat_cache_engine == STAT_CACHE_ENGINE_FAM)) { | |
/* is this directory already registered ? */ |
/* is this directory already registered ? */ |
if (!dir_node) { | if (NULL == fam_dir) { |
fam_dir = fam_dir_entry_init(); |
fam_dir = fam_dir_entry_init(); |
fam_dir->fc = sc->fam; |
|
|
|
buffer_copy_string_buffer(fam_dir->name, sc->dir_name); | buffer_copy_buffer(fam_dir->name, sc->dir_name); |
|
|
fam_dir->version = 1; |
fam_dir->version = 1; |
|
|
fam_dir->req = calloc(1, sizeof(FAMRequest)); |
fam_dir->req = calloc(1, sizeof(FAMRequest)); |
|
force_assert(NULL != fam_dir); |
|
|
if (0 != FAMMonitorDirectory(sc->fam, fam_dir->name->ptr, | if (0 != FAMMonitorDirectory(&sc->fam, fam_dir->name->ptr, |
fam_dir->req, fam_dir)) { |
fam_dir->req, fam_dir)) { |
|
|
log_error_write(srv, __FILE__, __LINE__, "sbsbs", |
log_error_write(srv, __FILE__, __LINE__, "sbsbs", |
Line 647 handler_t stat_cache_get_entry(server *srv, connection
|
Line 658 handler_t stat_cache_get_entry(server *srv, connection
|
"file:", name, |
"file:", name, |
FamErrlist[FAMErrno]); |
FamErrlist[FAMErrno]); |
|
|
fam_dir_entry_free(fam_dir); | fam_dir_entry_free(&sc->fam, fam_dir); |
| fam_dir = NULL; |
} else { |
} else { |
int osize = 0; | int osize = splaytree_size(sc->dirs); |
|
|
if (sc->dirs) { | /* already splayed dir_ndx */ |
osize = sc->dirs->size; | if ((NULL != sc->dirs) && (sc->dirs->key == dir_ndx)) { |
| /* hash collision: replace old entry */ |
| fam_dir_entry_free(&sc->fam, sc->dirs->data); |
| sc->dirs->data = fam_dir; |
| } else { |
| sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir); |
| force_assert(osize == (splaytree_size(sc->dirs) - 1)); |
} |
} |
|
|
sc->dirs = splaytree_insert(sc->dirs, dir_ndx, fam_dir); | force_assert(sc->dirs); |
assert(sc->dirs); | force_assert(sc->dirs->data == fam_dir); |
assert(sc->dirs->data == fam_dir); | |
assert(osize == (sc->dirs->size - 1)); | |
} |
} |
} else { |
|
fam_dir = dir_node->data; |
|
} |
} |
|
|
/* bind the fam_fc to the stat() cache entry */ |
/* bind the fam_fc to the stat() cache entry */ |
|
|
if (fam_dir) { |
if (fam_dir) { |
sce->dir_version = fam_dir->version; |
sce->dir_version = fam_dir->version; |
sce->dir_ndx = dir_ndx; |
|
} |
} |
} |
} |
#endif |
#endif |
Line 678 handler_t stat_cache_get_entry(server *srv, connection
|
Line 691 handler_t stat_cache_get_entry(server *srv, connection
|
return HANDLER_GO_ON; |
return HANDLER_GO_ON; |
} |
} |
|
|
|
int stat_cache_open_rdonly_fstat (server *srv, connection *con, buffer *name, struct stat *st) { |
|
/*(Note: O_NOFOLLOW affects only the final path segment, the target file, |
|
* not any intermediate symlinks along the path)*/ |
|
#ifndef O_BINARY |
|
#define O_BINARY 0 |
|
#endif |
|
#ifndef O_LARGEFILE |
|
#define O_LARGEFILE 0 |
|
#endif |
|
#ifndef O_NOCTTY |
|
#define O_NOCTTY 0 |
|
#endif |
|
#ifndef O_NONBLOCK |
|
#define O_NONBLOCK 0 |
|
#endif |
|
#ifndef O_NOFOLLOW |
|
#define O_NOFOLLOW 0 |
|
#endif |
|
const int oflags = O_BINARY | O_LARGEFILE | O_NOCTTY | O_NONBLOCK |
|
| (con->conf.follow_symlink ? 0 : O_NOFOLLOW); |
|
const int fd = open(name->ptr, O_RDONLY | oflags); |
|
if (fd >= 0) { |
|
if (0 == fstat(fd, st)) { |
|
return fd; |
|
} else { |
|
close(fd); |
|
} |
|
} |
|
UNUSED(srv); /*(might log_error_write(srv, ...) in the future)*/ |
|
return -1; |
|
} |
|
|
/** |
/** |
* remove stat() from cache which havn't been stat()ed for |
* remove stat() from cache which havn't been stat()ed for |
* more than 10 seconds |
* more than 10 seconds |
Line 713 int stat_cache_trigger_cleanup(server *srv) {
|
Line 758 int stat_cache_trigger_cleanup(server *srv) {
|
|
|
if (!sc->files) return 0; |
if (!sc->files) return 0; |
|
|
keys = calloc(1, sizeof(size_t) * sc->files->size); | keys = calloc(1, sizeof(int) * sc->files->size); |
| force_assert(NULL != keys); |
|
|
stat_cache_tag_old_entries(srv, sc->files, keys, &max_ndx); |
stat_cache_tag_old_entries(srv, sc->files, keys, &max_ndx); |
|
|
Line 742 int stat_cache_trigger_cleanup(server *srv) {
|
Line 788 int stat_cache_trigger_cleanup(server *srv) {
|
} |
} |
} |
} |
|
|
assert(osize - 1 == splaytree_size(sc->files)); | force_assert(osize - 1 == splaytree_size(sc->files)); |
#endif |
#endif |
} |
} |
} |
} |