summaryrefslogtreecommitdiffstats
path: root/xlators/mount/fuse/src/fuse-helpers.c
diff options
context:
space:
mode:
Diffstat (limited to 'xlators/mount/fuse/src/fuse-helpers.c')
-rw-r--r--xlators/mount/fuse/src/fuse-helpers.c926
1 files changed, 582 insertions, 344 deletions
diff --git a/xlators/mount/fuse/src/fuse-helpers.c b/xlators/mount/fuse/src/fuse-helpers.c
index f0e9fb60296..a2b0ad11fe4 100644
--- a/xlators/mount/fuse/src/fuse-helpers.c
+++ b/xlators/mount/fuse/src/fuse-helpers.c
@@ -1,450 +1,688 @@
/*
- Copyright (c) 2010-2011 Gluster, Inc. <http://www.gluster.com>
+ Copyright (c) 2010-2012 Red Hat, Inc. <http://www.redhat.com>
This file is part of GlusterFS.
- GlusterFS is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published
- by the Free Software Foundation; either version 3 of the License,
- or (at your option) any later version.
-
- GlusterFS is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see
- <http://www.gnu.org/licenses/>.
+ This file is licensed to you under your choice of the GNU Lesser
+ General Public License, version 3 or any later version (LGPLv3 or
+ later), or the GNU General Public License, version 2 (GPLv2), in all
+ cases as published by the Free Software Foundation.
*/
+#ifdef __NetBSD__
+#define _KMEMUSER
+#endif
+
+#if defined(GF_SOLARIS_HOST_OS)
+#include <sys/procfs.h>
+#elif defined(__FreeBSD__)
+#include <sys/types.h>
+#include <libutil.h>
+#elif defined(CTL_KERN)
+#include <sys/sysctl.h>
+#endif
+#include <pwd.h>
#include "fuse-bridge.h"
-xlator_t *
-fuse_state_subvol (fuse_state_t *state)
+static void
+fuse_resolve_wipe(fuse_resolve_t *resolve)
{
- xlator_t *subvol = NULL;
+ GF_FREE((void *)resolve->path);
- if (!state)
- return NULL;
+ GF_FREE((void *)resolve->bname);
- if (state->loc.inode)
- subvol = state->loc.inode->table->xl;
+ if (resolve->fd)
+ fd_unref(resolve->fd);
- if (state->fd)
- subvol = state->fd->inode->table->xl;
+ loc_wipe(&resolve->resolve_loc);
- return subvol;
-}
+ if (resolve->hint) {
+ inode_unref(resolve->hint);
+ resolve->hint = 0;
+ }
+ if (resolve->parhint) {
+ inode_unref(resolve->parhint);
+ resolve->parhint = 0;
+ }
+}
-xlator_t *
-fuse_active_subvol (xlator_t *fuse)
+void
+free_fuse_state(fuse_state_t *state)
{
- fuse_private_t *priv = NULL;
-
- priv = fuse->private;
+ xlator_t *this = NULL;
+ fuse_private_t *priv = NULL;
+ uint64_t winds = 0;
+ char switched = 0;
+
+ this = state->this;
+
+ priv = this->private;
+
+ loc_wipe(&state->loc);
+
+ loc_wipe(&state->loc2);
+
+ if (state->xdata) {
+ dict_unref(state->xdata);
+ state->xdata = (void *)0xaaaaeeee;
+ }
+ if (state->xattr)
+ dict_unref(state->xattr);
+
+ if (state->name) {
+ GF_FREE(state->name);
+ state->name = NULL;
+ }
+ if (state->fd) {
+ fd_unref(state->fd);
+ state->fd = (void *)0xfdfdfdfd;
+ }
+ if (state->finh) {
+ GF_FREE(state->finh);
+ state->finh = NULL;
+ }
+
+ fuse_resolve_wipe(&state->resolve);
+ fuse_resolve_wipe(&state->resolve2);
+
+ pthread_mutex_lock(&priv->sync_mutex);
+ {
+ winds = --state->active_subvol->winds;
+ switched = state->active_subvol->switched;
+ }
+ pthread_mutex_unlock(&priv->sync_mutex);
+
+ if ((winds == 0) && (switched)) {
+ xlator_notify(state->active_subvol, GF_EVENT_PARENT_DOWN,
+ state->active_subvol, NULL);
+ }
- return priv->active_subvol;
+#ifdef DEBUG
+ memset(state, 0x90, sizeof(*state));
+#endif
+ GF_FREE(state);
+ state = NULL;
}
-
-
-static void
-fuse_resolve_wipe (fuse_resolve_t *resolve)
+fuse_state_t *
+get_fuse_state(xlator_t *this, fuse_in_header_t *finh)
{
- struct fuse_resolve_comp *comp = NULL;
-
- if (resolve->path)
- GF_FREE ((void *)resolve->path);
+ fuse_state_t *state = NULL;
+ xlator_t *active_subvol = NULL;
+ fuse_private_t *priv = NULL;
- if (resolve->bname)
- GF_FREE ((void *)resolve->bname);
+ state = (void *)GF_CALLOC(1, sizeof(*state), gf_fuse_mt_fuse_state_t);
+ if (!state)
+ return NULL;
- if (resolve->resolved)
- GF_FREE ((void *)resolve->resolved);
+ state->this = THIS;
+ priv = this->private;
- loc_wipe (&resolve->deep_loc);
+ pthread_mutex_lock(&priv->sync_mutex);
+ {
+ while (priv->handle_graph_switch)
+ pthread_cond_wait(&priv->migrate_cond, &priv->sync_mutex);
+ active_subvol = fuse_active_subvol(state->this);
+ active_subvol->winds++;
+ }
+ pthread_mutex_unlock(&priv->sync_mutex);
- comp = resolve->components;
+ state->active_subvol = active_subvol;
+ state->itable = active_subvol->itable;
- if (comp) {
- int i = 0;
+ state->pool = this->ctx->pool;
+ state->finh = finh;
+ state->this = this;
- for (i = 0; comp[i].basename; i++) {
- if (comp[i].inode) {
- inode_unref (comp[i].inode);
- comp[i].inode = NULL;
- }
- }
+ LOCK_INIT(&state->lock);
- GF_FREE ((void *)resolve->components);
- }
+ return state;
}
void
-free_fuse_state (fuse_state_t *state)
+frame_fill_groups(call_frame_t *frame)
{
- loc_wipe (&state->loc);
-
- loc_wipe (&state->loc2);
-
- if (state->dict) {
- dict_unref (state->dict);
- state->dict = (void *)0xaaaaeeee;
- }
- if (state->name) {
- GF_FREE (state->name);
- state->name = NULL;
- }
- if (state->fd) {
- fd_unref (state->fd);
- state->fd = (void *)0xfdfdfdfd;
+#if defined(GF_LINUX_HOST_OS)
+ xlator_t *this = frame->this;
+ fuse_private_t *priv = this->private;
+ char filename[32];
+ char line[4096];
+ char *ptr = NULL;
+ long int id = 0;
+ char *saveptr = NULL;
+ char *endptr = NULL;
+ int ret = 0;
+ int ngroups = 0;
+ gid_t *mygroups = NULL;
+
+ if (priv->resolve_gids) {
+ struct passwd pwent;
+ char mystrs[1024];
+ struct passwd *result;
+
+ if (getpwuid_r(frame->root->uid, &pwent, mystrs, sizeof(mystrs),
+ &result) != 0) {
+ gf_log(this->name, GF_LOG_ERROR,
+ "getpwuid_r(%u) "
+ "failed",
+ frame->root->uid);
+ return;
}
- if (state->finh) {
- GF_FREE (state->finh);
- state->finh = NULL;
+ if (result == 0) {
+ gf_log(this->name, GF_LOG_ERROR,
+ "getpwuid_r(%u): "
+ "no matching record",
+ frame->root->uid);
+ return;
}
- fuse_resolve_wipe (&state->resolve);
- fuse_resolve_wipe (&state->resolve2);
-
-#ifdef DEBUG
- memset (state, 0x90, sizeof (*state));
-#endif
- GF_FREE (state);
- state = NULL;
-}
-
-
-fuse_state_t *
-get_fuse_state (xlator_t *this, fuse_in_header_t *finh)
-{
- fuse_state_t *state = NULL;
+ ngroups = gf_getgrouplist(result->pw_name, frame->root->gid, &mygroups);
+ if (ngroups == -1) {
+ gf_log(this->name, GF_LOG_ERROR,
+ "could not map %s to "
+ "group list (ngroups %d, max %d)",
+ result->pw_name, ngroups, GF_MAX_AUX_GROUPS);
+ return;
+ }
- state = (void *)GF_CALLOC (1, sizeof (*state),
- gf_fuse_mt_fuse_state_t);
- if (!state)
- return NULL;
- state->pool = this->ctx->pool;
- state->finh = finh;
- state->this = this;
+ call_stack_set_groups(frame->root, ngroups, &mygroups);
+ } else {
+ FILE *fp = NULL;
- LOCK_INIT (&state->lock);
+ ret = snprintf(filename, sizeof filename, "/proc/%d/status",
+ frame->root->pid);
+ if (ret >= sizeof filename) {
+ gf_log(this->name, GF_LOG_ERROR, "procfs path exceeds buffer size");
+ goto out;
+ }
- return state;
-}
+ fp = fopen(filename, "r");
+ if (!fp) {
+ gf_log(this->name, GF_LOG_ERROR, "failed to open %s: %s", filename,
+ strerror(errno));
+ goto out;
+ }
+ for (;;) {
+ gf_boolean_t found_groups = _gf_false;
+ int idx = 0;
-void
-frame_fill_groups (call_frame_t *frame)
-{
- char filename[128];
- char line[128];
- char *ptr = NULL;
- int ret = 0;
- FILE *fp = NULL;
- int idx = 0;
- long int id = 0;
- char *saveptr = NULL;
- char *endptr = NULL;
-
- ret = snprintf (filename, 128, "/proc/%d/status", frame->root->pid);
- if (ret == 128)
+ if (call_stack_alloc_groups(frame->root, ngroups) != 0) {
+ gf_log(this->name, GF_LOG_ERROR,
+ "failed to allocate gid buffer");
goto out;
+ }
- fp = fopen (filename, "r");
- if (!fp)
- goto out;
-
- while ((ptr = fgets (line, 128, fp))) {
- if (strncmp (ptr, "Groups:", 7) != 0)
- continue;
-
- ptr = line + 8;
-
- for (ptr = strtok_r (ptr, " \t\r\n", &saveptr);
- ptr;
- ptr = strtok_r (NULL, " \t\r\n", &saveptr)) {
- errno = 0;
- id = strtol (ptr, &endptr, 0);
- if (errno == ERANGE)
- break;
- if (!endptr || *endptr)
- break;
- frame->root->groups[idx++] = id;
- if (idx == GF_REQUEST_MAXGROUPS)
- break;
+ while ((ptr = fgets(line, sizeof line, fp))) {
+ if (strncmp(ptr, "Groups:", 7) == 0) {
+ found_groups = _gf_true;
+ break;
}
-
+ }
+ if (!found_groups) {
+ gf_log(this->name, GF_LOG_ERROR, "cannot find gid list in %s",
+ filename);
+ break;
+ }
+ ptr = line + 8;
+
+ for (ptr = strtok_r(ptr, " \t\r\n", &saveptr); ptr;
+ ptr = strtok_r(NULL, " \t\r\n", &saveptr)) {
+ errno = 0;
+ id = strtol(ptr, &endptr, 0);
+ if (errno == ERANGE || !endptr || *endptr) {
+ gf_log(this->name, GF_LOG_ERROR, "failed to parse %s",
+ filename);
+ break;
+ }
+ if (idx < call_stack_groups_capacity(frame->root))
+ frame->root->groups[idx] = id;
+ idx++;
+ if (idx == GF_MAX_AUX_GROUPS)
+ break;
+ }
+ if (idx > call_stack_groups_capacity(frame->root)) {
+ ngroups = idx;
+ rewind(fp);
+ } else {
frame->root->ngrps = idx;
break;
+ }
}
-out:
+ out:
if (fp)
- fclose (fp);
+ fclose(fp);
+ }
+#elif defined(GF_SOLARIS_HOST_OS)
+ char filename[32];
+ char scratch[128];
+ prcred_t *prcred = (prcred_t *)scratch;
+ FILE *fp = NULL;
+ int ret = 0;
+ int ngrps;
+
+ ret = snprintf(filename, sizeof filename, "/proc/%d/cred",
+ frame->root->pid);
+
+ if (ret < sizeof filename) {
+ fp = fopen(filename, "r");
+ if (fp != NULL) {
+ if (fgets(scratch, sizeof scratch, fp) != NULL) {
+ ngrps = MIN(prcred->pr_ngroups, GF_MAX_AUX_GROUPS);
+ if (call_stack_alloc_groups(frame->root, ngrps) != 0) {
+ fclose(fp);
+ return;
+ }
+ }
+ fclose(fp);
+ }
+ }
+#elif defined(CTL_KERN) /* DARWIN and *BSD */
+ /*
+ N.B. CTL_KERN is an enum on Linux. (Meaning, if it's not
+ obvious, that it's not subject to preprocessor directives
+ like '#if defined'.)
+ Unlike Linux, on Mac OS and the BSDs it is a #define. We
+ could test to see that KERN_PROC is defined, but, barring any
+ evidence to the contrary, I think that's overkill.
+ We might also test that GF_DARWIN_HOST_OS is defined, why
+ limit this to just Mac OS. It's equally valid for the BSDs
+ and we do have people building on NetBSD and FreeBSD.
+ */
+ int name[] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, frame->root->pid};
+ size_t namelen = sizeof name / sizeof name[0];
+ struct kinfo_proc kp;
+ size_t kplen = sizeof(kp);
+ int i, ngroups;
+
+ if (sysctl(name, namelen, &kp, &kplen, NULL, 0) != 0)
return;
+ ngroups = MIN(kp.kp_eproc.e_ucred.cr_ngroups, NGROUPS_MAX);
+ if (call_stack_alloc_groups(frame->root, ngroups) != 0)
+ return;
+ for (i = 0; i < ngroups; i++)
+ frame->root->groups[i] = kp.kp_eproc.e_ucred.cr_groups[i];
+ frame->root->ngrps = ngroups;
+#else
+ frame->root->ngrps = 0;
+#endif /* GF_LINUX_HOST_OS */
}
-
-call_frame_t *
-get_call_frame_for_req (fuse_state_t *state)
+/*
+ * Get the groups for the PID associated with this frame. If enabled,
+ * use the gid cache to reduce group list collection.
+ */
+static void
+get_groups(fuse_private_t *priv, call_frame_t *frame)
{
- call_pool_t *pool = NULL;
- fuse_in_header_t *finh = NULL;
- call_frame_t *frame = NULL;
- xlator_t *this = NULL;
- fuse_private_t *priv = NULL;
-
- pool = state->pool;
- finh = state->finh;
- this = state->this;
- priv = this->private;
-
- frame = create_frame (this, pool);
- if (!frame)
- return NULL;
-
- if (finh) {
- frame->root->uid = finh->uid;
- frame->root->gid = finh->gid;
- frame->root->pid = finh->pid;
- frame->root->lk_owner = state->lk_owner;
- frame->root->unique = finh->unique;
+ int i;
+ const gid_list_t *gl;
+ gid_list_t agl;
+
+ if (!priv || !priv->gid_cache_timeout) {
+ frame_fill_groups(frame);
+ return;
+ }
+
+ if (-1 == priv->gid_cache_timeout) {
+ frame->root->ngrps = 0;
+ return;
+ }
+
+ gl = gid_cache_lookup(&priv->gid_cache, frame->root->pid, frame->root->uid,
+ frame->root->gid);
+ if (gl) {
+ if (call_stack_alloc_groups(frame->root, gl->gl_count) != 0) {
+ gid_cache_release(&priv->gid_cache, gl);
+ return;
}
+ frame->root->ngrps = gl->gl_count;
+ for (i = 0; i < gl->gl_count; i++)
+ frame->root->groups[i] = gl->gl_list[i];
+ gid_cache_release(&priv->gid_cache, gl);
+ return;
+ }
- frame_fill_groups (frame);
+ frame_fill_groups(frame);
- if (priv && priv->client_pid_set)
- frame->root->pid = priv->client_pid;
+ agl.gl_id = frame->root->pid;
+ agl.gl_uid = frame->root->uid;
+ agl.gl_gid = frame->root->gid;
+ agl.gl_count = frame->root->ngrps;
+ agl.gl_list = GF_CALLOC(frame->root->ngrps, sizeof(gid_t),
+ gf_fuse_mt_gids_t);
+ if (!agl.gl_list)
+ return;
- frame->root->type = GF_OP_TYPE_FOP;
+ for (i = 0; i < frame->root->ngrps; i++)
+ agl.gl_list[i] = frame->root->groups[i];
- return frame;
+ if (gid_cache_add(&priv->gid_cache, &agl) != 1)
+ GF_FREE(agl.gl_list);
}
+call_frame_t *
+get_call_frame_for_req(fuse_state_t *state)
+{
+ call_pool_t *pool = NULL;
+ fuse_in_header_t *finh = NULL;
+ call_frame_t *frame = NULL;
+ xlator_t *this = NULL;
+ fuse_private_t *priv = NULL;
+
+ pool = state->pool;
+ finh = state->finh;
+ this = state->this;
+ priv = this->private;
+
+ frame = create_frame(this, pool);
+ if (!frame)
+ return NULL;
+
+ if (finh) {
+ frame->root->uid = finh->uid;
+ frame->root->gid = finh->gid;
+ frame->root->pid = finh->pid;
+ set_lk_owner_from_uint64(&frame->root->lk_owner, state->lk_owner);
+ }
+
+ get_groups(priv, frame);
+
+ if (priv && priv->client_pid_set)
+ frame->root->pid = priv->client_pid;
+
+ frame->root->type = GF_OP_TYPE_FOP;
+
+ return frame;
+}
inode_t *
-fuse_ino_to_inode (uint64_t ino, xlator_t *fuse)
+fuse_ino_to_inode(uint64_t ino, xlator_t *fuse)
{
- inode_t *inode = NULL;
- xlator_t *active_subvol = NULL;
-
- if (ino == 1) {
- active_subvol = fuse_active_subvol (fuse);
- if (active_subvol)
- inode = active_subvol->itable->root;
- } else {
- inode = (inode_t *) (unsigned long) ino;
- inode_ref (inode);
- }
-
- return inode;
+ inode_t *inode = NULL;
+ xlator_t *active_subvol = NULL;
+
+ if (ino == 1) {
+ active_subvol = fuse_active_subvol(fuse);
+ if (active_subvol)
+ inode = active_subvol->itable->root;
+ } else {
+ inode = (inode_t *)(unsigned long)ino;
+ inode_ref(inode);
+ }
+
+ return inode;
}
uint64_t
-inode_to_fuse_nodeid (inode_t *inode)
+inode_to_fuse_nodeid(inode_t *inode)
{
- if (!inode || __is_root_gfid (inode->gfid))
- return 1;
+ if (!inode)
+ return 0;
+ if (__is_root_gfid(inode->gfid))
+ return 1;
- return (unsigned long) inode;
+ return (unsigned long)inode;
}
-
GF_MUST_CHECK int32_t
-fuse_loc_fill (loc_t *loc, fuse_state_t *state, ino_t ino,
- ino_t par, const char *name)
+fuse_loc_fill(loc_t *loc, fuse_state_t *state, ino_t ino, ino_t par,
+ const char *name)
{
- inode_t *inode = NULL;
- inode_t *parent = NULL;
- int32_t ret = -1;
- char *path = NULL;
- uuid_t null_gfid = {0,};
-
- /* resistance against multiple invocation of loc_fill not to get
- reference leaks via inode_search() */
-
- if (name) {
- parent = loc->parent;
- if (!parent) {
- parent = fuse_ino_to_inode (par, state->this);
- loc->parent = parent;
- }
-
- inode = loc->inode;
- if (!inode) {
- inode = inode_grep (parent->table, parent, name);
- loc->inode = inode;
- }
-
- ret = inode_path (parent, name, &path);
- if (ret <= 0) {
- gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
- "inode_path failed for %s/%s",
- (parent)?uuid_utoa (parent->gfid):"0", name);
- goto fail;
- }
- loc->path = path;
- } else {
- inode = loc->inode;
- if (!inode) {
- inode = fuse_ino_to_inode (ino, state->this);
- loc->inode = inode;
- }
-
- parent = loc->parent;
- if (!parent) {
- parent = fuse_ino_to_inode (par, state->this);
- if (!parent) {
- parent = inode_parent (inode, null_gfid, NULL);
- }
+ inode_t *inode = NULL;
+ inode_t *parent = NULL;
+ int32_t ret = -1;
+ char *path = NULL;
+ uuid_t null_gfid = {
+ 0,
+ };
+
+ /* resistance against multiple invocation of loc_fill not to get
+ reference leaks via inode_search() */
+
+ if (name) {
+ parent = loc->parent;
+ if (!parent) {
+ parent = fuse_ino_to_inode(par, state->this);
+ loc->parent = parent;
+ if (parent)
+ gf_uuid_copy(loc->pargfid, parent->gfid);
+ }
- loc->parent = parent;
- }
+ inode = loc->inode;
+ if (!inode && parent) {
+ inode = inode_grep(parent->table, parent, name);
+ loc->inode = inode;
+ }
- ret = inode_path (inode, NULL, &path);
- if (ret <= 0) {
- gf_log ("glusterfs-fuse", GF_LOG_DEBUG,
- "inode_path failed for %s",
- (inode) ? uuid_utoa (inode->gfid) : "0");
- goto fail;
- }
- loc->path = path;
+ ret = inode_path(parent, name, &path);
+ if (ret <= 0) {
+ gf_log("glusterfs-fuse", GF_LOG_DEBUG,
+ "inode_path failed for %s/%s",
+ (parent) ? uuid_utoa(parent->gfid) : "0", name);
+ goto fail;
+ }
+ loc->path = path;
+ } else {
+ inode = loc->inode;
+ if (!inode) {
+ inode = fuse_ino_to_inode(ino, state->this);
+ loc->inode = inode;
+ if (inode)
+ gf_uuid_copy(loc->gfid, inode->gfid);
}
- if (loc->path) {
- loc->name = strrchr (loc->path, '/');
- if (loc->name)
- loc->name++;
- else
- loc->name = "";
+ parent = loc->parent;
+ if (!parent) {
+ parent = inode_parent(inode, null_gfid, NULL);
+ loc->parent = parent;
+ if (parent)
+ gf_uuid_copy(loc->pargfid, parent->gfid);
}
- if ((ino != 1) && (parent == NULL)) {
- gf_log ("fuse-bridge", GF_LOG_DEBUG,
- "failed to search parent for %"PRId64"/%s (%"PRId64")",
- (ino_t)par, name, (ino_t)ino);
- ret = -1;
- goto fail;
+ ret = inode_path(inode, NULL, &path);
+ if (ret <= 0) {
+ gf_log("glusterfs-fuse", GF_LOG_DEBUG, "inode_path failed for %s",
+ (inode) ? uuid_utoa(inode->gfid) : "0");
+ goto fail;
}
- ret = 0;
+ loc->path = path;
+ }
+
+ if (loc->path) {
+ loc->name = strrchr(loc->path, '/');
+ if (loc->name)
+ loc->name++;
+ else
+ loc->name = "";
+ }
+
+ if ((ino != 1) && (parent == NULL)) {
+ gf_log("fuse-bridge", GF_LOG_DEBUG,
+ "failed to search parent for %" PRId64 "/%s (%" PRId64 ")",
+ (ino_t)par, name, (ino_t)ino);
+ ret = -1;
+ goto fail;
+ }
+ ret = 0;
fail:
- return ret;
+ /* this should not happen as inode_path returns -1 when buf is NULL
+ for sure */
+ if (path && !loc->path)
+ GF_FREE(path);
+ return ret;
}
-
/* courtesy of folly */
void
-gf_fuse_stat2attr (struct iatt *st, struct fuse_attr *fa)
+gf_fuse_stat2attr(struct iatt *st, struct fuse_attr *fa,
+ gf_boolean_t enable_ino32)
{
- fa->ino = st->ia_ino;
- fa->size = st->ia_size;
- fa->blocks = st->ia_blocks;
- fa->atime = st->ia_atime;
- fa->mtime = st->ia_mtime;
- fa->ctime = st->ia_ctime;
- fa->atimensec = st->ia_atime_nsec;
- fa->mtimensec = st->ia_mtime_nsec;
- fa->ctimensec = st->ia_ctime_nsec;
- fa->mode = st_mode_from_ia (st->ia_prot, st->ia_type);
- fa->nlink = st->ia_nlink;
- fa->uid = st->ia_uid;
- fa->gid = st->ia_gid;
- fa->rdev = makedev (ia_major (st->ia_rdev),
- ia_minor (st->ia_rdev));
+ if (enable_ino32)
+ fa->ino = GF_FUSE_SQUASH_INO(st->ia_ino);
+ else
+ fa->ino = st->ia_ino;
+
+ fa->size = st->ia_size;
+ fa->blocks = st->ia_blocks;
+ fa->atime = st->ia_atime;
+ fa->mtime = st->ia_mtime;
+ fa->ctime = st->ia_ctime;
+ fa->atimensec = st->ia_atime_nsec;
+ fa->mtimensec = st->ia_mtime_nsec;
+ fa->ctimensec = st->ia_ctime_nsec;
+ fa->mode = st_mode_from_ia(st->ia_prot, st->ia_type);
+ fa->nlink = st->ia_nlink;
+ fa->uid = st->ia_uid;
+ fa->gid = st->ia_gid;
+ fa->rdev = makedev(ia_major(st->ia_rdev), ia_minor(st->ia_rdev));
#if FUSE_KERNEL_MINOR_VERSION >= 9
- fa->blksize = st->ia_blksize;
+ fa->blksize = st->ia_blksize;
#endif
#ifdef GF_DARWIN_HOST_OS
- fa->crtime = (uint64_t)-1;
- fa->crtimensec = (uint32_t)-1;
- fa->flags = 0;
+ fa->crtime = (uint64_t)-1;
+ fa->crtimensec = (uint32_t)-1;
+ fa->flags = 0;
#endif
}
-int
-fuse_flip_user_to_trusted (char *okey, char **nkey)
+void
+gf_fuse_fill_dirent(gf_dirent_t *entry, struct fuse_dirent *fde,
+ gf_boolean_t enable_ino32)
{
- int ret = 0;
- char *key = NULL;
+ if (enable_ino32)
+ fde->ino = GF_FUSE_SQUASH_INO(entry->d_ino);
+ else
+ fde->ino = entry->d_ino;
+
+ fde->off = entry->d_off;
+ fde->type = entry->d_type;
+ fde->namelen = strlen(entry->d_name);
+ (void)memcpy(fde->name, entry->d_name, fde->namelen);
+}
- key = GF_CALLOC (1, strlen(okey) + 10, gf_common_mt_char);
- if (!key) {
- ret = -1;
- goto out;
- }
+static int
+fuse_do_flip_xattr_ns(char *okey, const char *nns, char **nkey)
+{
+ int ret = 0;
+ char *key = NULL;
- okey += 5;
- strncpy(key, "trusted.", 8);
- strncat(key+8, okey, strlen(okey));
+ okey = strchr(okey, '.');
+ GF_ASSERT(okey);
- *nkey = key;
+ int key_len = strlen(nns) + strlen(okey);
+ key = GF_MALLOC(key_len + 1, gf_common_mt_char);
+ if (!key) {
+ ret = -1;
+ goto out;
+ }
- out:
- return ret;
+ strcpy(key, nns);
+ strcat(key, okey);
+
+ *nkey = key;
+
+out:
+ return ret;
}
-int
-fuse_xattr_alloc_default (char *okey, char **nkey)
+static int
+fuse_xattr_alloc_default(char *okey, char **nkey)
{
- int ret = 0;
+ int ret = 0;
- *nkey = gf_strdup (okey);
- if (!*nkey)
- ret = -1;
- return ret;
+ *nkey = gf_strdup(okey);
+ if (!*nkey)
+ ret = -1;
+ return ret;
}
+#define PRIV_XA_NS "trusted"
+#define UNPRIV_XA_NS "system"
+
int
-fuse_flip_xattr_ns (fuse_private_t *priv, char *okey, char **nkey)
+fuse_flip_xattr_ns(fuse_private_t *priv, char *okey, char **nkey)
{
- int ret = 0;
- gf_boolean_t need_flip = _gf_false;
- gf_client_pid_t npid = 0;
+ int ret = 0;
+ gf_boolean_t need_flip = _gf_false;
+
+ if (GF_CLIENT_PID_GSYNCD == priv->client_pid) {
+ /* valid xattr(s): *xtime, volume-mark* */
+ gf_log("glusterfs-fuse", GF_LOG_DEBUG,
+ "PID: %d, checking xattr(s): "
+ "volume-mark*, *xtime",
+ priv->client_pid);
+ if ((strcmp(okey, UNPRIV_XA_NS ".glusterfs.volume-mark") == 0) ||
+ (fnmatch(UNPRIV_XA_NS ".glusterfs.volume-mark.*", okey,
+ FNM_PERIOD) == 0) ||
+ (fnmatch(UNPRIV_XA_NS ".glusterfs.*.xtime", okey, FNM_PERIOD) == 0))
+ need_flip = _gf_true;
+ }
+
+ if (need_flip) {
+ gf_log("glusterfs-fuse", GF_LOG_DEBUG,
+ "flipping %s to " PRIV_XA_NS " equivalent", okey);
+ ret = fuse_do_flip_xattr_ns(okey, PRIV_XA_NS, nkey);
+ } else {
+ /* if we cannot match, continue with what we got */
+ ret = fuse_xattr_alloc_default(okey, nkey);
+ }
+
+ return ret;
+}
- npid = priv->client_pid;
- if (gf_client_pid_check (npid)) {
- ret = fuse_xattr_alloc_default (okey, nkey);
- goto out;
- }
+int
+fuse_ignore_xattr_set(fuse_private_t *priv, char *key)
+{
+ int ret = 0;
- switch (npid) {
- /*
- * These two cases will never execute as we check the
- * pid range above, but are kept to keep the compiler
- * happy.
- */
- case GF_CLIENT_PID_MAX:
- case GF_CLIENT_PID_MIN:
- goto out;
+ /* don't mess with user namespace */
+ if (fnmatch("user.*", key, FNM_PERIOD) == 0)
+ goto out;
- case GF_CLIENT_PID_GSYNCD:
- /* valid xattr(s): *xtime, volume-mark* */
- gf_log("glusterfs-fuse", GF_LOG_DEBUG, "PID: %d, checking xattr(s): "
- "volume-mark*, *xtime", npid);
- if ( (strcmp (okey, "user.glusterfs.volume-mark") == 0)
- || (fnmatch (okey, "user.glusterfs.volume-mark.*", FNM_PERIOD) == 0)
- || (fnmatch ("user.glusterfs.*.xtime", okey, FNM_PERIOD) == 0) )
- need_flip = _gf_true;
- break;
+ if (priv->client_pid != GF_CLIENT_PID_GSYNCD)
+ goto out;
- case GF_CLIENT_PID_HADOOP:
- /* valid xattr(s): pathinfo */
- gf_log("glusterfs-fuse", GF_LOG_DEBUG, "PID: %d, checking xattr(s): "
- "pathinfo", npid);
- if (strcmp (okey, "user.glusterfs.pathinfo") == 0)
- need_flip = _gf_true;
- break;
- }
+ /* trusted NS check */
+ if (!((fnmatch("*.glusterfs.*.xtime", key, FNM_PERIOD) == 0) ||
+ (fnmatch("*.glusterfs.volume-mark", key, FNM_PERIOD) == 0) ||
+ (fnmatch("*.glusterfs.volume-mark.*", key, FNM_PERIOD) == 0) ||
+ (fnmatch("system.posix_acl_access", key, FNM_PERIOD) == 0) ||
+ (fnmatch("glusterfs.gfid.newfile", key, FNM_PERIOD) == 0) ||
+ (fnmatch("*.glusterfs.shard.block-size", key, FNM_PERIOD) == 0) ||
+ (fnmatch("*.glusterfs.shard.file-size", key, FNM_PERIOD) == 0)))
+ ret = -1;
- if (need_flip) {
- gf_log ("glusterfs-fuse", GF_LOG_DEBUG, "flipping %s to trusted equivalent",
- okey);
- ret = fuse_flip_user_to_trusted (okey, nkey);
- } else {
- /* if we cannot match, continue with what we got */
- ret = fuse_xattr_alloc_default (okey, nkey);
- }
- out:
- return ret;
+out:
+ gf_log("glusterfs-fuse", GF_LOG_DEBUG,
+ "%s setxattr: key [%s], "
+ " client pid [%d]",
+ (ret ? "disallowing" : "allowing"), key, priv->client_pid);
+
+ return ret;
+}
+
+int
+fuse_check_selinux_cap_xattr(fuse_private_t *priv, char *name)
+{
+ int ret = -1;
+
+ if (strcmp(name, "security.selinux") &&
+ strcmp(name, "security.capability")) {
+ /* if xattr name is not of interest, no validations needed */
+ ret = 0;
+ goto out;
+ }
+
+ if ((strcmp(name, "security.selinux") == 0) && (priv->selinux)) {
+ ret = 0;
+ }
+
+ if ((strcmp(name, "security.capability") == 0) &&
+ ((priv->capability) || (priv->selinux))) {
+ ret = 0;
+ }
+
+out:
+ return ret;
}