#include "api/glfs.h"
#include "lib/util/dlinklist.h"
#include "lib/util/tevent_unix.h"
-#include "lib/tevent/tevent_internal.h"
#include "smbd/globals.h"
#include "lib/util/sys_rw.h"
+#include "smbprofile.h"
+#include "modules/posixacl_xattr.h"
#define DEFAULT_VOLFILE_SERVER "localhost"
}
}
+static int vfs_gluster_set_volfile_servers(glfs_t *fs,
+ const char *volfile_servers)
+{
+ char *server = NULL;
+ int server_count = 0;
+ int server_success = 0;
+ int ret = -1;
+ TALLOC_CTX *frame = talloc_stackframe();
+
+ DBG_INFO("servers list %s\n", volfile_servers);
+
+ while (next_token_talloc(frame, &volfile_servers, &server, " \t")) {
+ char *transport = NULL;
+ char *host = NULL;
+ int port = 0;
+
+ server_count++;
+ DBG_INFO("server %d %s\n", server_count, server);
+
+ /* Determine the transport type */
+ if (strncmp(server, "unix+", 5) == 0) {
+ port = 0;
+ transport = talloc_strdup(frame, "unix");
+ if (!transport) {
+ errno = ENOMEM;
+ goto out;
+ }
+ host = talloc_strdup(frame, server + 5);
+ if (!host) {
+ errno = ENOMEM;
+ goto out;
+ }
+ } else {
+ char *p = NULL;
+ char *port_index = NULL;
+
+ if (strncmp(server, "tcp+", 4) == 0) {
+ server += 4;
+ }
+
+ /* IPv6 is enclosed in []
+ * ':' before ']' is part of IPv6
+ * ':' after ']' indicates port
+ */
+ p = server;
+ if (server[0] == '[') {
+ server++;
+ p = index(server, ']');
+ if (p == NULL) {
+ /* Malformed IPv6 */
+ continue;
+ }
+ p[0] = '\0';
+ p++;
+ }
+
+ port_index = index(p, ':');
+
+ if (port_index == NULL) {
+ port = 0;
+ } else {
+ port = atoi(port_index + 1);
+ port_index[0] = '\0';
+ }
+ transport = talloc_strdup(frame, "tcp");
+ if (!transport) {
+ errno = ENOMEM;
+ goto out;
+ }
+ host = talloc_strdup(frame, server);
+ if (!host) {
+ errno = ENOMEM;
+ goto out;
+ }
+ }
+
+ DBG_INFO("Calling set volfile server with params "
+ "transport=%s, host=%s, port=%d\n", transport,
+ host, port);
+
+ ret = glfs_set_volfile_server(fs, transport, host, port);
+ if (ret < 0) {
+ DBG_WARNING("Failed to set volfile_server "
+ "transport=%s, host=%s, port=%d (%s)\n",
+ transport, host, port, strerror(errno));
+ } else {
+ server_success++;
+ }
+ }
+
+out:
+ if (server_count == 0) {
+ ret = -1;
+ } else if (server_success < server_count) {
+ DBG_WARNING("Failed to set %d out of %d servers parsed\n",
+ server_count - server_success, server_count);
+ ret = 0;
+ }
+
+ TALLOC_FREE(frame);
+ return ret;
+}
+
/* Disk Operations */
static int vfs_gluster_connect(struct vfs_handle_struct *handle,
const char *service,
const char *user)
{
- const char *volfile_server;
+ const char *volfile_servers;
const char *volume;
char *logfile;
int loglevel;
loglevel = lp_parm_int(SNUM(handle->conn), "glusterfs", "loglevel", -1);
- volfile_server = lp_parm_const_string(SNUM(handle->conn), "glusterfs",
- "volfile_server", NULL);
- if (volfile_server == NULL) {
- volfile_server = DEFAULT_VOLFILE_SERVER;
+ volfile_servers = lp_parm_talloc_string(tmp_ctx, SNUM(handle->conn),
+ "glusterfs", "volfile_server",
+ NULL);
+ if (volfile_servers == NULL) {
+ volfile_servers = DEFAULT_VOLFILE_SERVER;
}
volume = lp_parm_const_string(SNUM(handle->conn), "glusterfs", "volume",
goto done;
}
- ret = glfs_set_volfile_server(fs, "tcp", volfile_server, 0);
+ ret = vfs_gluster_set_volfile_servers(fs, volfile_servers);
if (ret < 0) {
- DEBUG(0, ("Failed to set volfile_server %s\n", volfile_server));
+ DBG_ERR("Failed to set volfile_servers from list %s\n",
+ volfile_servers);
goto done;
}
if (ret < 0) {
DEBUG(0, ("%s: Failed to set xlator option:"
" snapdir-entry-path\n", volume));
- glfs_fini(fs);
- return -1;
+ goto done;
}
ret = glfs_set_logging(fs, logfile, loglevel);
goto done;
}
done:
- talloc_free(tmp_ctx);
if (ret < 0) {
if (fs)
glfs_fini(fs);
- return -1;
} else {
- DEBUG(0, ("%s: Initialized volume from server %s\n",
- volume, volfile_server));
+ DBG_ERR("%s: Initialized volume from servers %s\n",
+ volume, volfile_servers);
handle->data = fs;
- return 0;
}
+ talloc_free(tmp_ctx);
+ return ret;
}
static void vfs_gluster_disconnect(struct vfs_handle_struct *handle)
}
static uint64_t vfs_gluster_disk_free(struct vfs_handle_struct *handle,
- const char *path, uint64_t *bsize_p,
- uint64_t *dfree_p, uint64_t *dsize_p)
+ const struct smb_filename *smb_fname,
+ uint64_t *bsize_p,
+ uint64_t *dfree_p,
+ uint64_t *dsize_p)
{
struct statvfs statvfs = { 0, };
int ret;
- ret = glfs_statvfs(handle->data, path, &statvfs);
+ ret = glfs_statvfs(handle->data, smb_fname->base_name, &statvfs);
if (ret < 0) {
return -1;
}
}
static int vfs_gluster_get_quota(struct vfs_handle_struct *handle,
- enum SMB_QUOTA_TYPE qtype, unid_t id,
- SMB_DISK_QUOTA *qt)
+ const struct smb_filename *smb_fname,
+ enum SMB_QUOTA_TYPE qtype,
+ unid_t id,
+ SMB_DISK_QUOTA *qt)
{
errno = ENOSYS;
return -1;
}
static int vfs_gluster_statvfs(struct vfs_handle_struct *handle,
- const char *path,
- struct vfs_statvfs_struct *vfs_statvfs)
+ const struct smb_filename *smb_fname,
+ struct vfs_statvfs_struct *vfs_statvfs)
{
struct statvfs statvfs = { 0, };
int ret;
- ret = glfs_statvfs(handle->data, path, &statvfs);
+ ret = glfs_statvfs(handle->data, smb_fname->base_name, &statvfs);
if (ret < 0) {
DEBUG(0, ("glfs_statvfs(%s) failed: %s\n",
- path, strerror(errno)));
+ smb_fname->base_name, strerror(errno)));
return -1;
}
}
static DIR *vfs_gluster_opendir(struct vfs_handle_struct *handle,
- const char *path, const char *mask,
+ const struct smb_filename *smb_fname,
+ const char *mask,
uint32_t attributes)
{
glfs_fd_t *fd;
- fd = glfs_opendir(handle->data, path);
+ fd = glfs_opendir(handle->data, smb_fname->base_name);
if (fd == NULL) {
DEBUG(0, ("glfs_opendir(%s) failed: %s\n",
- path, strerror(errno)));
+ smb_fname->base_name, strerror(errno)));
}
return (DIR *) fd;
return;
}
-static int vfs_gluster_mkdir(struct vfs_handle_struct *handle, const char *path,
+static int vfs_gluster_mkdir(struct vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname,
mode_t mode)
{
- return glfs_mkdir(handle->data, path, mode);
+ return glfs_mkdir(handle->data, smb_fname->base_name, mode);
}
-static int vfs_gluster_rmdir(struct vfs_handle_struct *handle, const char *path)
+static int vfs_gluster_rmdir(struct vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname)
{
- return glfs_rmdir(handle->data, path);
+ return glfs_rmdir(handle->data, smb_fname->base_name);
}
static int vfs_gluster_open(struct vfs_handle_struct *handle,
return glfs_pread(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), data, n, offset, 0);
}
+struct glusterfs_aio_state;
+
+struct glusterfs_aio_wrapper {
+ struct glusterfs_aio_state *state;
+};
+
struct glusterfs_aio_state {
ssize_t ret;
- int err;
+ struct tevent_req *req;
+ bool cancelled;
+ struct vfs_aio_state vfs_aio_state;
+ struct timespec start;
};
+static int aio_wrapper_destructor(struct glusterfs_aio_wrapper *wrap)
+{
+ if (wrap->state != NULL) {
+ wrap->state->cancelled = true;
+ }
+
+ return 0;
+}
+
/*
* This function is the callback that will be called on glusterfs
* threads once the async IO submitted is complete. To notify
*/
static void aio_glusterfs_done(glfs_fd_t *fd, ssize_t ret, void *data)
{
- struct tevent_req *req = NULL;
struct glusterfs_aio_state *state = NULL;
int sts = 0;
+ struct timespec end;
+
+ state = (struct glusterfs_aio_state *)data;
- req = talloc_get_type_abort(data, struct tevent_req);
- state = tevent_req_data(req, struct glusterfs_aio_state);
+ PROFILE_TIMESTAMP(&end);
if (ret < 0) {
state->ret = -1;
- state->err = errno;
+ state->vfs_aio_state.error = errno;
} else {
state->ret = ret;
- state->err = 0;
}
+ state->vfs_aio_state.duration = nsec_time_diff(&end, &state->start);
/*
- * Write the pointer to each req that needs to be completed
- * by calling tevent_req_done(). tevent_req_done() cannot
- * be called here, as it is not designed to be executed
- * in the multithread environment, tevent_req_done() must be
+ * Write the state pointer to glusterfs_aio_state to the
+ * pipe, so we can call tevent_req_done() from the main thread,
+ * because tevent_req_done() is not designed to be executed in
+ * the multithread environment, so tevent_req_done() must be
* executed from the smbd main thread.
*
* write(2) on pipes with sizes under _POSIX_PIPE_BUF
* that we can trust it here.
*/
- sts = sys_write(write_fd, &req, sizeof(struct tevent_req *));
+ sts = sys_write(write_fd, &state, sizeof(struct glusterfs_aio_state *));
if (sts < 0) {
DEBUG(0,("\nWrite to pipe failed (%s)", strerror(errno)));
}
uint16_t flags, void *data)
{
struct tevent_req *req = NULL;
+ struct glusterfs_aio_state *state = NULL;
int sts = 0;
/*
* can trust it here.
*/
- sts = sys_read(read_fd, &req, sizeof(struct tevent_req *));
+ sts = sys_read(read_fd, &state, sizeof(struct glusterfs_aio_state *));
+
if (sts < 0) {
DEBUG(0,("\nRead from pipe failed (%s)", strerror(errno)));
}
+ /* if we've cancelled the op, there is no req, so just clean up. */
+ if (state->cancelled == true) {
+ TALLOC_FREE(state);
+ return;
+ }
+
+ req = state->req;
+
if (req) {
tevent_req_done(req);
}
return false;
}
-static struct tevent_req *vfs_gluster_pread_send(struct vfs_handle_struct
- *handle, TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- files_struct *fsp, void *data,
- size_t n, off_t offset)
+static struct glusterfs_aio_state *aio_state_create(TALLOC_CTX *mem_ctx)
{
struct tevent_req *req = NULL;
struct glusterfs_aio_state *state = NULL;
- int ret = 0;
+ struct glusterfs_aio_wrapper *wrapper = NULL;
+
+ req = tevent_req_create(mem_ctx, &wrapper, struct glusterfs_aio_wrapper);
- req = tevent_req_create(mem_ctx, &state, struct glusterfs_aio_state);
if (req == NULL) {
return NULL;
}
+ state = talloc_zero(NULL, struct glusterfs_aio_state);
+
+ if (state == NULL) {
+ TALLOC_FREE(req);
+ return NULL;
+ }
+
+ talloc_set_destructor(wrapper, aio_wrapper_destructor);
+ state->cancelled = false;
+ state->req = req;
+
+ wrapper->state = state;
+
+ return state;
+}
+
+static struct tevent_req *vfs_gluster_pread_send(struct vfs_handle_struct
+ *handle, TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ files_struct *fsp,
+ void *data, size_t n,
+ off_t offset)
+{
+ struct glusterfs_aio_state *state = NULL;
+ struct tevent_req *req = NULL;
+ int ret = 0;
+
+ state = aio_state_create(mem_ctx);
+
+ if (state == NULL) {
+ return NULL;
+ }
+
+ req = state->req;
+
if (!init_gluster_aio(handle)) {
tevent_req_error(req, EIO);
return tevent_req_post(req, ev);
}
+
+ PROFILE_TIMESTAMP(&state->start);
ret = glfs_pread_async(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle,
fsp), data, n, offset, 0, aio_glusterfs_done,
- req);
+ state);
if (ret < 0) {
tevent_req_error(req, -ret);
return tevent_req_post(req, ev);
return req;
}
-static ssize_t vfs_gluster_write(struct vfs_handle_struct *handle,
- files_struct *fsp, const void *data, size_t n)
-{
- return glfs_write(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), data, n, 0);
-}
-
-static ssize_t vfs_gluster_pwrite(struct vfs_handle_struct *handle,
- files_struct *fsp, const void *data,
- size_t n, off_t offset)
-{
- return glfs_pwrite(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), data, n, offset, 0);
-}
-
static struct tevent_req *vfs_gluster_pwrite_send(struct vfs_handle_struct
*handle, TALLOC_CTX *mem_ctx,
struct tevent_context *ev,
const void *data, size_t n,
off_t offset)
{
- struct tevent_req *req = NULL;
struct glusterfs_aio_state *state = NULL;
+ struct tevent_req *req = NULL;
int ret = 0;
- req = tevent_req_create(mem_ctx, &state, struct glusterfs_aio_state);
- if (req == NULL) {
+ state = aio_state_create(mem_ctx);
+
+ if (state == NULL) {
return NULL;
}
+
+ req = state->req;
+
if (!init_gluster_aio(handle)) {
tevent_req_error(req, EIO);
return tevent_req_post(req, ev);
}
+
+ PROFILE_TIMESTAMP(&state->start);
ret = glfs_pwrite_async(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle,
fsp), data, n, offset, 0, aio_glusterfs_done,
- req);
+ state);
if (ret < 0) {
tevent_req_error(req, -ret);
return tevent_req_post(req, ev);
}
+
return req;
}
-static ssize_t vfs_gluster_recv(struct tevent_req *req, int *err)
+static ssize_t vfs_gluster_recv(struct tevent_req *req,
+ struct vfs_aio_state *vfs_aio_state)
{
- struct glusterfs_aio_state *state = NULL;
+ struct glusterfs_aio_wrapper *wrapper = NULL;
+ int ret = 0;
- state = tevent_req_data(req, struct glusterfs_aio_state);
- if (state == NULL) {
+ wrapper = tevent_req_data(req, struct glusterfs_aio_wrapper);
+
+ if (wrapper == NULL) {
return -1;
}
- if (tevent_req_is_unix_error(req, err)) {
+ if (wrapper->state == NULL) {
return -1;
}
- if (state->ret == -1) {
- *err = state->err;
+
+ if (tevent_req_is_unix_error(req, &vfs_aio_state->error)) {
+ return -1;
}
- return state->ret;
+
+ *vfs_aio_state = wrapper->state->vfs_aio_state;
+ ret = wrapper->state->ret;
+
+ /* Clean up the state, it is in a NULL context. */
+
+ TALLOC_FREE(wrapper->state);
+
+ return ret;
+}
+
+static ssize_t vfs_gluster_write(struct vfs_handle_struct *handle,
+ files_struct *fsp, const void *data, size_t n)
+{
+ return glfs_write(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), data, n, 0);
+}
+
+static ssize_t vfs_gluster_pwrite(struct vfs_handle_struct *handle,
+ files_struct *fsp, const void *data,
+ size_t n, off_t offset)
+{
+ return glfs_pwrite(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp), data, n, offset, 0);
}
static off_t vfs_gluster_lseek(struct vfs_handle_struct *handle,
struct glusterfs_aio_state *state = NULL;
int ret = 0;
- req = tevent_req_create(mem_ctx, &state, struct glusterfs_aio_state);
- if (req == NULL) {
+ state = aio_state_create(mem_ctx);
+
+ if (state == NULL) {
return NULL;
}
+
+ req = state->req;
+
if (!init_gluster_aio(handle)) {
tevent_req_error(req, EIO);
return tevent_req_post(req, ev);
}
+
+ PROFILE_TIMESTAMP(&state->start);
ret = glfs_fsync_async(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle,
fsp), aio_glusterfs_done, req);
if (ret < 0) {
return req;
}
-static int vfs_gluster_fsync_recv(struct tevent_req *req, int *err)
+static int vfs_gluster_fsync_recv(struct tevent_req *req,
+ struct vfs_aio_state *vfs_aio_state)
{
/*
* Use implicit conversion ssize_t->int
*/
- return vfs_gluster_recv(req, err);
+ return vfs_gluster_recv(req, vfs_aio_state);
}
static int vfs_gluster_stat(struct vfs_handle_struct *handle,
}
static int vfs_gluster_chmod(struct vfs_handle_struct *handle,
- const char *path, mode_t mode)
+ const struct smb_filename *smb_fname,
+ mode_t mode)
{
- return glfs_chmod(handle->data, path, mode);
+ return glfs_chmod(handle->data, smb_fname->base_name, mode);
}
static int vfs_gluster_fchmod(struct vfs_handle_struct *handle,
}
static int vfs_gluster_chown(struct vfs_handle_struct *handle,
- const char *path, uid_t uid, gid_t gid)
+ const struct smb_filename *smb_fname,
+ uid_t uid,
+ gid_t gid)
{
- return glfs_chown(handle->data, path, uid, gid);
+ return glfs_chown(handle->data, smb_fname->base_name, uid, gid);
}
static int vfs_gluster_fchown(struct vfs_handle_struct *handle,
}
static int vfs_gluster_lchown(struct vfs_handle_struct *handle,
- const char *path, uid_t uid, gid_t gid)
+ const struct smb_filename *smb_fname,
+ uid_t uid,
+ gid_t gid)
{
- return glfs_lchown(handle->data, path, uid, gid);
+ return glfs_lchown(handle->data, smb_fname->base_name, uid, gid);
}
-static int vfs_gluster_chdir(struct vfs_handle_struct *handle, const char *path)
+static int vfs_gluster_chdir(struct vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname)
{
- return glfs_chdir(handle->data, path);
+ return glfs_chdir(handle->data, smb_fname->base_name);
}
-static char *vfs_gluster_getwd(struct vfs_handle_struct *handle)
+static struct smb_filename *vfs_gluster_getwd(struct vfs_handle_struct *handle,
+ TALLOC_CTX *ctx)
{
char *cwd;
char *ret;
+ struct smb_filename *smb_fname = NULL;
cwd = SMB_CALLOC_ARRAY(char, PATH_MAX);
if (cwd == NULL) {
if (ret == 0) {
free(cwd);
}
- return ret;
+ smb_fname = synthetic_smb_fname(ctx,
+ ret,
+ NULL,
+ NULL,
+ 0);
+ free(cwd);
+ return smb_fname;
}
static int vfs_gluster_ntimes(struct vfs_handle_struct *handle,
return -1;
}
-static char *vfs_gluster_realpath(struct vfs_handle_struct *handle,
- const char *path)
+static struct smb_filename *vfs_gluster_realpath(struct vfs_handle_struct *handle,
+ TALLOC_CTX *ctx,
+ const struct smb_filename *smb_fname)
{
- return glfs_realpath(handle->data, path, 0);
+ char *result = NULL;
+ struct smb_filename *result_fname = NULL;
+ char *resolved_path = SMB_MALLOC_ARRAY(char, PATH_MAX+1);
+
+ if (resolved_path == NULL) {
+ errno = ENOMEM;
+ return NULL;
+ }
+
+ result = glfs_realpath(handle->data,
+ smb_fname->base_name,
+ resolved_path);
+ if (result != NULL) {
+ result_fname = synthetic_smb_fname(ctx, result, NULL, NULL, 0);
+ }
+
+ SAFE_FREE(resolved_path);
+ return result_fname;
}
static bool vfs_gluster_lock(struct vfs_handle_struct *handle,
}
static int vfs_gluster_symlink(struct vfs_handle_struct *handle,
- const char *oldpath, const char *newpath)
+ const char *link_target,
+ const struct smb_filename *new_smb_fname)
{
- return glfs_symlink(handle->data, oldpath, newpath);
+ return glfs_symlink(handle->data,
+ link_target,
+ new_smb_fname->base_name);
}
static int vfs_gluster_readlink(struct vfs_handle_struct *handle,
- const char *path, char *buf, size_t bufsiz)
+ const struct smb_filename *smb_fname,
+ char *buf,
+ size_t bufsiz)
{
- return glfs_readlink(handle->data, path, buf, bufsiz);
+ return glfs_readlink(handle->data, smb_fname->base_name, buf, bufsiz);
}
static int vfs_gluster_link(struct vfs_handle_struct *handle,
- const char *oldpath, const char *newpath)
+ const struct smb_filename *old_smb_fname,
+ const struct smb_filename *new_smb_fname)
{
- return glfs_link(handle->data, oldpath, newpath);
+ return glfs_link(handle->data,
+ old_smb_fname->base_name,
+ new_smb_fname->base_name);
}
-static int vfs_gluster_mknod(struct vfs_handle_struct *handle, const char *path,
- mode_t mode, SMB_DEV_T dev)
+static int vfs_gluster_mknod(struct vfs_handle_struct *handle,
+ const struct smb_filename *smb_fname,
+ mode_t mode,
+ SMB_DEV_T dev)
{
- return glfs_mknod(handle->data, path, mode, dev);
+ return glfs_mknod(handle->data, smb_fname->base_name, mode, dev);
}
static int vfs_gluster_chflags(struct vfs_handle_struct *handle,
- const char *path, unsigned int flags)
+ const struct smb_filename *smb_fname,
+ unsigned int flags)
{
errno = ENOSYS;
return -1;
}
static const char *vfs_gluster_connectpath(struct vfs_handle_struct *handle,
- const char *filename)
+ const struct smb_filename *smb_fname)
{
return handle->conn->connectpath;
}
/* EA Operations */
static ssize_t vfs_gluster_getxattr(struct vfs_handle_struct *handle,
- const char *path, const char *name,
- void *value, size_t size)
+ const struct smb_filename *smb_fname,
+ const char *name,
+ void *value,
+ size_t size)
{
- return glfs_getxattr(handle->data, path, name, value, size);
+ return glfs_getxattr(handle->data, smb_fname->base_name,
+ name, value, size);
}
static ssize_t vfs_gluster_fgetxattr(struct vfs_handle_struct *handle,
}
static ssize_t vfs_gluster_listxattr(struct vfs_handle_struct *handle,
- const char *path, char *list, size_t size)
+ const struct smb_filename *smb_fname,
+ char *list,
+ size_t size)
{
- return glfs_listxattr(handle->data, path, list, size);
+ return glfs_listxattr(handle->data, smb_fname->base_name, list, size);
}
static ssize_t vfs_gluster_flistxattr(struct vfs_handle_struct *handle,
}
static int vfs_gluster_removexattr(struct vfs_handle_struct *handle,
- const char *path, const char *name)
+ const struct smb_filename *smb_fname,
+ const char *name)
{
- return glfs_removexattr(handle->data, path, name);
+ return glfs_removexattr(handle->data, smb_fname->base_name, name);
}
static int vfs_gluster_fremovexattr(struct vfs_handle_struct *handle,
}
static int vfs_gluster_setxattr(struct vfs_handle_struct *handle,
- const char *path, const char *name,
+ const struct smb_filename *smb_fname,
+ const char *name,
const void *value, size_t size, int flags)
{
- return glfs_setxattr(handle->data, path, name, value, size, flags);
+ return glfs_setxattr(handle->data, smb_fname->base_name, name, value, size, flags);
}
static int vfs_gluster_fsetxattr(struct vfs_handle_struct *handle,
return false;
}
-/* Offline Operations */
-
-static bool vfs_gluster_is_offline(struct vfs_handle_struct *handle,
- const struct smb_filename *fname,
- SMB_STRUCT_STAT *sbuf)
-{
- return false;
-}
-
-static int vfs_gluster_set_offline(struct vfs_handle_struct *handle,
- const struct smb_filename *fname)
-{
- errno = ENOTSUP;
- return -1;
-}
-
-/*
- Gluster ACL Format:
-
- Size = 4 (header) + N * 8 (entry)
-
- Offset Size Field (Little Endian)
- -------------------------------------
- 0-3 4-byte Version
-
- 4-5 2-byte Entry-1 tag
- 6-7 2-byte Entry-1 perm
- 8-11 4-byte Entry-1 id
-
- 12-13 2-byte Entry-2 tag
- 14-15 2-byte Entry-2 perm
- 16-19 4-byte Entry-2 id
-
- ...
-
- */
-
-/* header version */
-#define GLUSTER_ACL_VERSION 2
-
-/* perm bits */
-#define GLUSTER_ACL_READ 0x04
-#define GLUSTER_ACL_WRITE 0x02
-#define GLUSTER_ACL_EXECUTE 0x01
-
-/* tag values */
-#define GLUSTER_ACL_UNDEFINED_TAG 0x00
-#define GLUSTER_ACL_USER_OBJ 0x01
-#define GLUSTER_ACL_USER 0x02
-#define GLUSTER_ACL_GROUP_OBJ 0x04
-#define GLUSTER_ACL_GROUP 0x08
-#define GLUSTER_ACL_MASK 0x10
-#define GLUSTER_ACL_OTHER 0x20
-
-#define GLUSTER_ACL_UNDEFINED_ID (-1)
-
-#define GLUSTER_ACL_HEADER_SIZE 4
-#define GLUSTER_ACL_ENTRY_SIZE 8
-
-#define GLUSTER_ACL_SIZE(n) (GLUSTER_ACL_HEADER_SIZE + (n * GLUSTER_ACL_ENTRY_SIZE))
-
-static SMB_ACL_T mode_to_smb_acls(const struct stat *mode, TALLOC_CTX *mem_ctx)
-{
- struct smb_acl_t *result;
- int count;
-
- count = 3;
- result = sys_acl_init(mem_ctx);
- if (!result) {
- errno = ENOMEM;
- return NULL;
- }
-
- result->acl = talloc_array(result, struct smb_acl_entry, count);
- if (!result->acl) {
- errno = ENOMEM;
- talloc_free(result);
- return NULL;
- }
-
- result->count = count;
-
- result->acl[0].a_type = SMB_ACL_USER_OBJ;
- result->acl[0].a_perm = (mode->st_mode & S_IRWXU) >> 6;;
-
- result->acl[1].a_type = SMB_ACL_GROUP_OBJ;
- result->acl[1].a_perm = (mode->st_mode & S_IRWXG) >> 3;;
-
- result->acl[2].a_type = SMB_ACL_OTHER;
- result->acl[2].a_perm = mode->st_mode & S_IRWXO;;
-
- return result;
-}
-
-static SMB_ACL_T gluster_to_smb_acl(const char *buf, size_t xattr_size,
- TALLOC_CTX *mem_ctx)
-{
- int count;
- size_t size;
- struct smb_acl_entry *smb_ace;
- struct smb_acl_t *result;
- int i;
- int offset;
- uint16_t tag;
- uint16_t perm;
- uint32_t id;
-
- size = xattr_size;
-
- if (size < GLUSTER_ACL_HEADER_SIZE) {
- /* ACL should be at least as big as the header (4 bytes) */
- errno = EINVAL;
- return NULL;
- }
-
- size -= GLUSTER_ACL_HEADER_SIZE; /* size of header = 4 bytes */
-
- if (size % GLUSTER_ACL_ENTRY_SIZE) {
- /* Size of entries must strictly be a multiple of
- size of an ACE (8 bytes)
- */
- errno = EINVAL;
- return NULL;
- }
-
- count = size / GLUSTER_ACL_ENTRY_SIZE;
-
- /* Version is the first 4 bytes of the ACL */
- if (IVAL(buf, 0) != GLUSTER_ACL_VERSION) {
- DEBUG(0, ("Unknown gluster ACL version: %d\n",
- IVAL(buf, 0)));
- return NULL;
- }
- offset = GLUSTER_ACL_HEADER_SIZE;
-
- result = sys_acl_init(mem_ctx);
- if (!result) {
- errno = ENOMEM;
- return NULL;
- }
-
- result->acl = talloc_array(result, struct smb_acl_entry, count);
- if (!result->acl) {
- errno = ENOMEM;
- talloc_free(result);
- return NULL;
- }
-
- result->count = count;
-
- smb_ace = result->acl;
-
- for (i = 0; i < count; i++) {
- /* TAG is the first 2 bytes of an entry */
- tag = SVAL(buf, offset);
- offset += 2;
-
- /* PERM is the next 2 bytes of an entry */
- perm = SVAL(buf, offset);
- offset += 2;
-
- /* ID is the last 4 bytes of an entry */
- id = IVAL(buf, offset);
- offset += 4;
-
- switch(tag) {
- case GLUSTER_ACL_USER:
- smb_ace->a_type = SMB_ACL_USER;
- break;
- case GLUSTER_ACL_USER_OBJ:
- smb_ace->a_type = SMB_ACL_USER_OBJ;
- break;
- case GLUSTER_ACL_GROUP:
- smb_ace->a_type = SMB_ACL_GROUP;
- break;
- case GLUSTER_ACL_GROUP_OBJ:
- smb_ace->a_type = SMB_ACL_GROUP_OBJ;
- break;
- case GLUSTER_ACL_OTHER:
- smb_ace->a_type = SMB_ACL_OTHER;
- break;
- case GLUSTER_ACL_MASK:
- smb_ace->a_type = SMB_ACL_MASK;
- break;
- default:
- DEBUG(0, ("unknown tag type %d\n", (unsigned int) tag));
- return NULL;
- }
-
-
- switch(smb_ace->a_type) {
- case SMB_ACL_USER:
- smb_ace->info.user.uid = id;
- break;
- case SMB_ACL_GROUP:
- smb_ace->info.group.gid = id;
- break;
- default:
- break;
- }
-
- smb_ace->a_perm = 0;
- smb_ace->a_perm |=
- ((perm & GLUSTER_ACL_READ) ? SMB_ACL_READ : 0);
- smb_ace->a_perm |=
- ((perm & GLUSTER_ACL_WRITE) ? SMB_ACL_WRITE : 0);
- smb_ace->a_perm |=
- ((perm & GLUSTER_ACL_EXECUTE) ? SMB_ACL_EXECUTE : 0);
-
- smb_ace++;
- }
-
- return result;
-}
-
-
-static int gluster_ace_cmp(const void *left, const void *right)
-{
- int ret = 0;
- uint16_t tag_left, tag_right;
- uint32_t id_left, id_right;
-
- /*
- Sorting precedence:
-
- - Smaller TAG values must be earlier.
-
- - Within same TAG, smaller identifiers must be earlier, E.g:
- UID 0 entry must be earlier than UID 200
- GID 17 entry must be earlier than GID 19
- */
-
- /* TAG is the first element in the entry */
- tag_left = SVAL(left, 0);
- tag_right = SVAL(right, 0);
-
- ret = (tag_left - tag_right);
- if (!ret) {
- /* ID is the third element in the entry, after two short
- integers (tag and perm), i.e at offset 4.
- */
- id_left = IVAL(left, 4);
- id_right = IVAL(right, 4);
- ret = id_left - id_right;
- }
-
- return ret;
-}
-
-
-static ssize_t smb_to_gluster_acl(SMB_ACL_T theacl, char *buf, size_t len)
-{
- ssize_t size;
- struct smb_acl_entry *smb_ace;
- int i;
- int count;
- uint16_t tag;
- uint16_t perm;
- uint32_t id;
- int offset;
-
- count = theacl->count;
-
- size = GLUSTER_ACL_HEADER_SIZE + (count * GLUSTER_ACL_ENTRY_SIZE);
- if (!buf) {
- return size;
- }
-
- if (len < size) {
- errno = ERANGE;
- return -1;
- }
-
- smb_ace = theacl->acl;
-
- /* Version is the first 4 bytes of the ACL */
- SIVAL(buf, 0, GLUSTER_ACL_VERSION);
- offset = GLUSTER_ACL_HEADER_SIZE;
-
- for (i = 0; i < count; i++) {
- /* Calculate tag */
- switch(smb_ace->a_type) {
- case SMB_ACL_USER:
- tag = GLUSTER_ACL_USER;
- break;
- case SMB_ACL_USER_OBJ:
- tag = GLUSTER_ACL_USER_OBJ;
- break;
- case SMB_ACL_GROUP:
- tag = GLUSTER_ACL_GROUP;
- break;
- case SMB_ACL_GROUP_OBJ:
- tag = GLUSTER_ACL_GROUP_OBJ;
- break;
- case SMB_ACL_OTHER:
- tag = GLUSTER_ACL_OTHER;
- break;
- case SMB_ACL_MASK:
- tag = GLUSTER_ACL_MASK;
- break;
- default:
- DEBUG(0, ("Unknown tag value %d\n",
- smb_ace->a_type));
- errno = EINVAL;
- return -1;
- }
-
-
- /* Calculate id */
- switch(smb_ace->a_type) {
- case SMB_ACL_USER:
- id = smb_ace->info.user.uid;
- break;
- case SMB_ACL_GROUP:
- id = smb_ace->info.group.gid;
- break;
- default:
- id = GLUSTER_ACL_UNDEFINED_ID;
- break;
- }
-
- /* Calculate perm */
- perm = 0;
-
- perm |=
- ((smb_ace->a_perm & SMB_ACL_READ) ? GLUSTER_ACL_READ : 0);
- perm |=
- ((smb_ace->a_perm & SMB_ACL_WRITE) ? GLUSTER_ACL_WRITE : 0);
- perm |=
- ((smb_ace->a_perm & SMB_ACL_EXECUTE) ? GLUSTER_ACL_EXECUTE : 0);
-
-
- /* TAG is the first 2 bytes of an entry */
- SSVAL(buf, offset, tag);
- offset += 2;
-
- /* PERM is the next 2 bytes of an entry */
- SSVAL(buf, offset, perm);
- offset += 2;
-
- /* ID is the last 4 bytes of an entry */
- SIVAL(buf, offset, id);
- offset += 4;
-
- smb_ace++;
- }
-
- /* Skip the header, sort @count number of 8-byte entries */
- qsort(buf+GLUSTER_ACL_HEADER_SIZE, count, GLUSTER_ACL_ENTRY_SIZE,
- gluster_ace_cmp);
-
- return size;
-}
-
-
-static SMB_ACL_T vfs_gluster_sys_acl_get_file(struct vfs_handle_struct *handle,
- const char *path_p,
- SMB_ACL_TYPE_T type,
- TALLOC_CTX *mem_ctx)
-{
- struct smb_acl_t *result;
- struct stat st;
- char *buf;
- const char *key;
- ssize_t ret, size = GLUSTER_ACL_SIZE(20);
-
- switch (type) {
- case SMB_ACL_TYPE_ACCESS:
- key = "system.posix_acl_access";
- break;
- case SMB_ACL_TYPE_DEFAULT:
- key = "system.posix_acl_default";
- break;
- default:
- errno = EINVAL;
- return NULL;
- }
-
- buf = alloca(size);
- if (!buf) {
- return NULL;
- }
-
- ret = glfs_getxattr(handle->data, path_p, key, buf, size);
- if (ret == -1 && errno == ERANGE) {
- ret = glfs_getxattr(handle->data, path_p, key, 0, 0);
- if (ret > 0) {
- buf = alloca(ret);
- if (!buf) {
- return NULL;
- }
- ret = glfs_getxattr(handle->data, path_p, key, buf, ret);
- }
- }
-
- /* retrieving the ACL from the xattr has finally failed, do a
- * mode-to-acl mapping */
-
- if (ret == -1 && errno == ENODATA) {
- ret = glfs_stat(handle->data, path_p, &st);
- if (ret == 0) {
- result = mode_to_smb_acls(&st, mem_ctx);
- return result;
- }
- }
-
- if (ret <= 0) {
- return NULL;
- }
-
- result = gluster_to_smb_acl(buf, ret, mem_ctx);
-
- return result;
-}
-
-static SMB_ACL_T vfs_gluster_sys_acl_get_fd(struct vfs_handle_struct *handle,
- struct files_struct *fsp,
- TALLOC_CTX *mem_ctx)
-{
- struct smb_acl_t *result;
- struct stat st;
- ssize_t ret, size = GLUSTER_ACL_SIZE(20);
- char *buf;
- glfs_fd_t *glfd;
-
- glfd = *(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp);
-
- buf = alloca(size);
- if (!buf) {
- return NULL;
- }
-
- ret = glfs_fgetxattr(glfd, "system.posix_acl_access", buf, size);
- if (ret == -1 && errno == ERANGE) {
- ret = glfs_fgetxattr(glfd, "system.posix_acl_access", 0, 0);
- if (ret > 0) {
- buf = alloca(ret);
- if (!buf) {
- return NULL;
- }
- ret = glfs_fgetxattr(glfd, "system.posix_acl_access",
- buf, ret);
- }
- }
-
- /* retrieving the ACL from the xattr has finally failed, do a
- * mode-to-acl mapping */
-
- if (ret == -1 && errno == ENODATA) {
- ret = glfs_fstat(glfd, &st);
- if (ret == 0) {
- result = mode_to_smb_acls(&st, mem_ctx);
- return result;
- }
- }
-
- if (ret <= 0) {
- return NULL;
- }
-
- result = gluster_to_smb_acl(buf, ret, mem_ctx);
-
- return result;
-}
-
-static int vfs_gluster_sys_acl_set_file(struct vfs_handle_struct *handle,
- const char *name,
- SMB_ACL_TYPE_T acltype,
- SMB_ACL_T theacl)
-{
- int ret;
- const char *key;
- char *buf;
- ssize_t size;
-
- switch (acltype) {
- case SMB_ACL_TYPE_ACCESS:
- key = "system.posix_acl_access";
- break;
- case SMB_ACL_TYPE_DEFAULT:
- key = "system.posix_acl_default";
- break;
- default:
- errno = EINVAL;
- return -1;
- }
-
- size = smb_to_gluster_acl(theacl, 0, 0);
- buf = alloca(size);
-
- size = smb_to_gluster_acl(theacl, buf, size);
- if (size == -1) {
- return -1;
- }
-
- ret = glfs_setxattr(handle->data, name, key, buf, size, 0);
-
- return ret;
-}
-
-static int vfs_gluster_sys_acl_set_fd(struct vfs_handle_struct *handle,
- struct files_struct *fsp,
- SMB_ACL_T theacl)
-{
- int ret;
- char *buf;
- ssize_t size;
-
- size = smb_to_gluster_acl(theacl, 0, 0);
- buf = alloca(size);
-
- size = smb_to_gluster_acl(theacl, buf, size);
- if (size == -1) {
- return -1;
- }
-
- ret = glfs_fsetxattr(*(glfs_fd_t **)VFS_FETCH_FSP_EXTENSION(handle, fsp),
- "system.posix_acl_access", buf, size, 0);
- return ret;
-}
-
-static int vfs_gluster_sys_acl_delete_def_file(struct vfs_handle_struct *handle,
- const char *path)
-{
- return glfs_removexattr(handle->data, path, "system.posix_acl_default");
-}
-
static struct vfs_fn_pointers glusterfs_fns = {
/* Disk Operations */
/* Posix ACL Operations */
.chmod_acl_fn = NULL, /* passthrough to default */
.fchmod_acl_fn = NULL, /* passthrough to default */
- .sys_acl_get_file_fn = vfs_gluster_sys_acl_get_file,
- .sys_acl_get_fd_fn = vfs_gluster_sys_acl_get_fd,
+ .sys_acl_get_file_fn = posixacl_xattr_acl_get_file,
+ .sys_acl_get_fd_fn = posixacl_xattr_acl_get_fd,
.sys_acl_blob_get_file_fn = posix_sys_acl_blob_get_file,
.sys_acl_blob_get_fd_fn = posix_sys_acl_blob_get_fd,
- .sys_acl_set_file_fn = vfs_gluster_sys_acl_set_file,
- .sys_acl_set_fd_fn = vfs_gluster_sys_acl_set_fd,
- .sys_acl_delete_def_file_fn = vfs_gluster_sys_acl_delete_def_file,
+ .sys_acl_set_file_fn = posixacl_xattr_acl_set_file,
+ .sys_acl_set_fd_fn = posixacl_xattr_acl_set_fd,
+ .sys_acl_delete_def_file_fn = posixacl_xattr_acl_delete_def_file,
/* EA Operations */
.getxattr_fn = vfs_gluster_getxattr,
/* AIO Operations */
.aio_force_fn = vfs_gluster_aio_force,
- /* Offline Operations */
- .is_offline_fn = vfs_gluster_is_offline,
- .set_offline_fn = vfs_gluster_set_offline,
-
/* Durable handle Operations */
.durable_cookie_fn = NULL,
.durable_disconnect_fn = NULL,
.durable_reconnect_fn = NULL,
};
-NTSTATUS vfs_glusterfs_init(void);
-NTSTATUS vfs_glusterfs_init(void)
+NTSTATUS vfs_glusterfs_init(TALLOC_CTX *);
+NTSTATUS vfs_glusterfs_init(TALLOC_CTX *ctx)
{
return smb_register_vfs(SMB_VFS_INTERFACE_VERSION,
"glusterfs", &glusterfs_fns);