diff options
Diffstat (limited to 'libglusterfsclient')
-rw-r--r-- | libglusterfsclient/Makefile.am | 3 | ||||
-rw-r--r-- | libglusterfsclient/src/Makefile.am | 16 | ||||
-rwxr-xr-x | libglusterfsclient/src/libglusterfsclient-internals.h | 144 | ||||
-rwxr-xr-x | libglusterfsclient/src/libglusterfsclient.c | 3146 | ||||
-rwxr-xr-x | libglusterfsclient/src/libglusterfsclient.h | 279 |
5 files changed, 3588 insertions, 0 deletions
diff --git a/libglusterfsclient/Makefile.am b/libglusterfsclient/Makefile.am new file mode 100644 index 00000000000..d471a3f9243 --- /dev/null +++ b/libglusterfsclient/Makefile.am @@ -0,0 +1,3 @@ +SUBDIRS = src + +CLEANFILES = diff --git a/libglusterfsclient/src/Makefile.am b/libglusterfsclient/src/Makefile.am new file mode 100644 index 00000000000..8382b2561b1 --- /dev/null +++ b/libglusterfsclient/src/Makefile.am @@ -0,0 +1,16 @@ +lib_LTLIBRARIES = libglusterfsclient.la +noinst_HEADERS = libglusterfsclient-internals.h +libglusterfsclient_HEADERS = libglusterfsclient.h +libglusterfsclientdir = $(includedir) + +libglusterfsclient_la_SOURCES = libglusterfsclient.c +libglusterfsclient_la_CFLAGS = -fPIC -Wall -pthread +libglusterfsclient_la_LIBADD = $(top_builddir)/libglusterfs/src/libglusterfs.la +libglusterfsclient_la_CPPFLAGS = -D_FILE_OFFSET_BITS=64 -D$(GF_HOST_OS) -D__USE_FILE_OFFSET64 -D_GNU_SOURCE -I$(top_srcdir)/libglusterfs/src -DDATADIR=\"$(localstatedir)\" -DCONFDIR=\"$(sysconfdir)/glusterfs\" $(GF_CFLAGS) +libglusterfsclient_la_LDFLAGS = -shared -nostartfiles + +CLEANFILES = + +$(top_builddir)/libglusterfs/src/libglusterfs.la: + $(MAKE) -C $(top_builddir)/libglusterfs/src/ all + diff --git a/libglusterfsclient/src/libglusterfsclient-internals.h b/libglusterfsclient/src/libglusterfsclient-internals.h new file mode 100755 index 00000000000..c07da818018 --- /dev/null +++ b/libglusterfsclient/src/libglusterfsclient-internals.h @@ -0,0 +1,144 @@ +/* + Copyright (c) 2008 Z RESEARCH, Inc. <http://www.zresearch.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/>. +*/ + +#ifndef __LIBGLUSTERFSCLIENT_INTERNALS_H +#define __LIBGLUSTERFSCLIENT_INTERNALS_H + +#include <glusterfs.h> +#include <logging.h> +#include <inode.h> +#include <pthread.h> +#include <stack.h> +#include <list.h> +#include <signal.h> +#include <call-stub.h> +#include <sys/time.h> +#include <sys/resource.h> +#include <fd.h> + +typedef void (*sighandler_t) (int); +typedef struct list_head list_head_t; + +typedef struct libglusterfs_client_ctx { + glusterfs_ctx_t gf_ctx; + inode_table_t *itable; + pthread_t reply_thread; + call_pool_t pool; + uint32_t counter; + time_t lookup_timeout; + time_t stat_timeout; +}libglusterfs_client_ctx_t; + +typedef struct signal_handler { + int signo; + sighandler_t handler; + list_head_t next; +}libgf_client_signal_handler_t ; + +typedef struct { + pthread_mutex_t lock; + pthread_cond_t reply_cond; + call_stub_t *reply_stub; + char complete; + union { + struct { + char is_revalidate; + loc_t *loc; + int32_t size; + } lookup; + }fop; +}libgf_client_local_t; + +#define LIBGF_STACK_WIND_AND_WAIT(frame, rfn, obj, fn, params ...) \ + do { \ + STACK_WIND (frame, rfn, obj, fn, params); \ + pthread_mutex_lock (&local->lock); \ + { \ + while (!local->complete) { \ + pthread_cond_wait (&local->reply_cond, &local->lock); \ + } \ + } \ + pthread_mutex_unlock (&local->lock); \ + } while (0) + + + +#define LIBGF_CLIENT_SIGNAL(signal_handler_list, signo, handler) \ + do { \ + libgf_client_signal_handler_t *libgf_handler = CALLOC (1, sizeof (*libgf_handler)); \ + ERR_ABORT (libgf_handler); \ + libgf_handler->signo = signo; \ + libgf_handler->handler = signal (signo, handler); \ + list_add (&libgf_handler->next, signal_handler_list); \ + } while (0) + +#define LIBGF_INSTALL_SIGNAL_HANDLERS(signal_handlers) \ + do { \ + INIT_LIST_HEAD (&signal_handlers); \ + /* Handle SIGABORT and SIGSEGV */ \ + LIBGF_CLIENT_SIGNAL (&signal_handlers, SIGSEGV, gf_print_trace); \ + LIBGF_CLIENT_SIGNAL (&signal_handlers, SIGABRT, gf_print_trace); \ + LIBGF_CLIENT_SIGNAL (&signal_handlers, SIGHUP, gf_log_logrotate); \ + /* LIBGF_CLIENT_SIGNAL (SIGTERM, glusterfs_cleanup_and_exit); */ \ + } while (0) + +#define LIBGF_RESTORE_SIGNAL_HANDLERS(local) \ + do { \ + libgf_client_signal_handler_t *ptr = NULL, *tmp = NULL; \ + list_for_each_entry_safe (ptr, tmp, &local->signal_handlers, next) { \ + signal (ptr->signo, ptr->handler); \ + FREE (ptr); \ + } \ + } while (0) + +#define LIBGF_CLIENT_FOP_ASYNC(ctx, local, ret_fn, op, args ...) \ + do { \ + call_frame_t *frame = get_call_frame_for_req (ctx, 1); \ + xlator_t *xl = frame->this->children ? \ + frame->this->children->xlator : NULL; \ + dict_t *refs = frame->root->req_refs; \ + frame->root->state = ctx; \ + frame->local = local; \ + STACK_WIND (frame, ret_fn, xl, xl->fops->op, args); \ + dict_unref (refs); \ + } while (0) + +#define LIBGF_CLIENT_FOP(ctx, stub, op, local, args ...) \ + do { \ + call_frame_t *frame = get_call_frame_for_req (ctx, 1); \ + xlator_t *xl = frame->this->children ? \ + frame->this->children->xlator : NULL; \ + dict_t *refs = frame->root->req_refs; \ + if (!local) { \ + local = CALLOC (1, sizeof (*local)); \ + } \ + ERR_ABORT (local); \ + frame->local = local; \ + frame->root->state = ctx; \ + pthread_cond_init (&local->reply_cond, NULL); \ + pthread_mutex_init (&local->lock, NULL); \ + LIBGF_STACK_WIND_AND_WAIT (frame, libgf_client_##op##_cbk, xl, xl->fops->op, args); \ + dict_unref (refs); \ + stub = local->reply_stub; \ + FREE (frame->local); \ + frame->local = NULL; \ + STACK_DESTROY (frame->root); \ + } while (0) + +#endif diff --git a/libglusterfsclient/src/libglusterfsclient.c b/libglusterfsclient/src/libglusterfsclient.c new file mode 100755 index 00000000000..51098a065eb --- /dev/null +++ b/libglusterfsclient/src/libglusterfsclient.c @@ -0,0 +1,3146 @@ +/* + Copyright (c) 2008 Z RESEARCH, Inc. <http://www.zresearch.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/>. +*/ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include <stdio.h> +#include <errno.h> +#include <libgen.h> +#include <stddef.h> + +#include <sys/time.h> +#include <sys/stat.h> +#include <unistd.h> +#include <xlator.h> +#include <timer.h> +#include "defaults.h" +#include <time.h> +#include <poll.h> +#include "transport.h" +#include "event.h" +#include "libglusterfsclient.h" +#include "libglusterfsclient-internals.h" +#include "compat.h" +#include "compat-errno.h" + +#define XLATOR_NAME "libglusterfsclient" +#define LIBGLUSTERFS_INODE_TABLE_LRU_LIMIT 14057 + +typedef struct { + pthread_cond_t init_con_established; + pthread_mutex_t lock; + char complete; +}libglusterfs_client_private_t; + +typedef struct { + pthread_mutex_t lock; + uint32_t previous_lookup_time; + uint32_t previous_stat_time; + struct stat stbuf; +} libglusterfs_client_inode_ctx_t; + +typedef struct { + pthread_mutex_t lock; + off_t offset; + libglusterfs_client_ctx_t *ctx; +} libglusterfs_client_fd_ctx_t; + +typedef struct libglusterfs_client_async_local { + void *cbk_data; + union { + struct { + fd_t *fd; + glusterfs_readv_cbk_t cbk; + }readv_cbk; + + struct { + fd_t *fd; + glusterfs_writev_cbk_t cbk; + }writev_cbk; + + struct { + fd_t *fd; + }close_cbk; + + struct { + void *buf; + size_t size; + loc_t *loc; + char is_revalidate; + glusterfs_lookup_cbk_t cbk; + }lookup_cbk; + }fop; +}libglusterfs_client_async_local_t; + +static inline xlator_t * +libglusterfs_graph (xlator_t *graph); + +static int first_init = 1; +static int first_fini = 1; + + +char * +zr_build_process_uuid () +{ + char tmp_str[1024] = {0,}; + char hostname[256] = {0,}; + struct timeval tv = {0,}; + struct tm now = {0, }; + char now_str[32]; + + if (-1 == gettimeofday(&tv, NULL)) { + gf_log ("", GF_LOG_ERROR, + "gettimeofday: failed %s", + strerror (errno)); + } + + if (-1 == gethostname (hostname, 256)) { + gf_log ("", GF_LOG_ERROR, + "gethostname: failed %s", + strerror (errno)); + } + + localtime_r (&tv.tv_sec, &now); + strftime (now_str, 32, "%Y/%m/%d-%H:%M:%S", &now); + snprintf (tmp_str, 1024, "%s-%d-%s:%ld", + hostname, getpid(), now_str, tv.tv_usec); + + return strdup (tmp_str); +} + + +int32_t +libgf_client_forget (xlator_t *this, + inode_t *inode) +{ + libglusterfs_client_inode_ctx_t *ctx = NULL; + + inode_ctx_del (inode, this, (uint64_t *)ctx); + FREE (ctx); + + return 0; +} + + +int32_t +libgf_client_release (xlator_t *this, + fd_t *fd) +{ + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + data_t *fd_ctx_data = NULL; + + fd_ctx_data = dict_get (fd->ctx, XLATOR_NAME); + + fd_ctx = data_to_ptr (fd_ctx_data); + pthread_mutex_destroy (&fd_ctx->lock); + + return 0; +} + + +int32_t +libgf_client_releasedir (xlator_t *this, + fd_t *fd) +{ + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + data_t *fd_ctx_data = NULL; + + fd_ctx_data = dict_get (fd->ctx, XLATOR_NAME); + + fd_ctx = data_to_ptr (fd_ctx_data); + pthread_mutex_destroy (&fd_ctx->lock); + + return 0; +} + + +void *poll_proc (void *ptr) +{ + glusterfs_ctx_t *ctx = ptr; + + event_dispatch (ctx->event_pool); + + return NULL; +} + + +int32_t +xlator_graph_init (xlator_t *xl) +{ + xlator_t *trav = xl; + int32_t ret = -1; + + while (trav->prev) + trav = trav->prev; + + while (trav) { + if (!trav->ready) { + ret = xlator_tree_init (trav); + if (ret < 0) + break; + } + trav = trav->next; + } + + return ret; +} + + +void +xlator_graph_fini (xlator_t *xl) +{ + xlator_t *trav = xl; + while (trav->prev) + trav = trav->prev; + + while (trav) { + if (!trav->init_succeeded) { + break; + } + + xlator_tree_fini (trav); + trav = trav->next; + } +} + + +static void +libgf_client_loc_wipe (loc_t *loc) +{ + if (loc->path) { + FREE (loc->path); + } + + if (loc->parent) { + inode_unref (loc->parent); + loc->parent = NULL; + } + + if (loc->inode) { + inode_unref (loc->inode); + loc->inode = NULL; + } +} + + +static int32_t +libgf_client_loc_fill (loc_t *loc, const char *path, + ino_t ino, libglusterfs_client_ctx_t *ctx) +{ + int32_t op_ret = -1; + int32_t ret = 0; + char *dentry_path = NULL; + + loc->inode = NULL; + /* directory structure is flat. All files are immediate children of root */ + if (path) { + /* libglusterfsclient accepts only absolute paths */ + if (path[0] != '/') { + asprintf ((char **) &loc->path, "/%s", path); + } else { + loc->path = strdup (path); + } + + loc->inode = inode_search (ctx->itable, 1, path); + } else { + loc->inode = inode_search (ctx->itable, ino, NULL); + if (loc->inode == NULL) { + gf_log ("libglusterfsclient", GF_LOG_ERROR, + "cannot find inode for ino %"PRId64, + ino); + goto out; + } + + ret = inode_path (loc->inode, NULL, &dentry_path); + if (ret <= 0) { + gf_log ("libglusterfsclient", GF_LOG_ERROR, + "inode_path failed for %"PRId64, + loc->inode->ino); + inode_unref (loc->inode); + op_ret = ret; + goto out; + } else { + loc->path = dentry_path; + } + } + + loc->name = strrchr (loc->path, '/'); + if (loc->name) { + loc->name++; + } + + loc->parent = inode_ref (ctx->itable->root); + + if (loc->inode) { + loc->ino = loc->inode->ino; + } + + op_ret = 0; +out: + return op_ret; +} + + +static call_frame_t * +get_call_frame_for_req (libglusterfs_client_ctx_t *ctx, char d) +{ + call_pool_t *pool = ctx->gf_ctx.pool; + xlator_t *this = ctx->gf_ctx.graph; + call_frame_t *frame = NULL; + + + frame = create_frame (this, pool); + + frame->root->uid = geteuid (); + frame->root->gid = getegid (); + frame->root->pid = getpid (); + frame->root->unique = ctx->counter++; + + if (d) { + frame->root->req_refs = dict_ref (get_new_dict ()); + /* + TODO + dict_set (frame->root->req_refs, NULL, priv->buf); + */ + } + + return frame; +} + +void +libgf_client_fini (xlator_t *this) +{ + FREE (this->private); + return; +} + + +int32_t +libgf_client_notify (xlator_t *this, + int32_t event, + void *data, + ...) +{ + libglusterfs_client_private_t *priv = this->private; + + switch (event) + { + case GF_EVENT_CHILD_UP: + pthread_mutex_lock (&priv->lock); + { + priv->complete = 1; + pthread_cond_broadcast (&priv->init_con_established); + } + pthread_mutex_unlock (&priv->lock); + break; + + default: + default_notify (this, event, data); + } + + return 0; +} + +int32_t +libgf_client_init (xlator_t *this) +{ + return 0; +} + + +libglusterfs_handle_t +glusterfs_init (glusterfs_init_ctx_t *init_ctx) +{ + libglusterfs_client_ctx_t *ctx = NULL; + libglusterfs_client_private_t *priv = NULL; + FILE *specfp = NULL; + xlator_t *graph = NULL, *trav = NULL; + call_pool_t *pool = NULL; + int32_t ret = 0; + struct rlimit lim; + uint32_t xl_count = 0; + + if (!init_ctx || (!init_ctx->specfile && !init_ctx->specfp)) { + errno = EINVAL; + return NULL; + } + + ctx = CALLOC (1, sizeof (*ctx)); + if (!ctx) { + fprintf (stderr, + "libglusterfsclient: %s:%s():%d: out of memory\n", + __FILE__, __PRETTY_FUNCTION__, __LINE__); + + errno = ENOMEM; + return NULL; + } + + ctx->lookup_timeout = init_ctx->lookup_timeout; + ctx->stat_timeout = init_ctx->stat_timeout; + + pthread_mutex_init (&ctx->gf_ctx.lock, NULL); + + pool = ctx->gf_ctx.pool = CALLOC (1, sizeof (call_pool_t)); + if (!pool) { + errno = ENOMEM; + FREE (ctx); + return NULL; + } + + LOCK_INIT (&pool->lock); + INIT_LIST_HEAD (&pool->all_frames); + + ctx->gf_ctx.event_pool = event_pool_new (16384); + + lim.rlim_cur = RLIM_INFINITY; + lim.rlim_max = RLIM_INFINITY; + setrlimit (RLIMIT_CORE, &lim); + setrlimit (RLIMIT_NOFILE, &lim); + + ctx->gf_ctx.cmd_args.log_level = GF_LOG_WARNING; + + if (init_ctx->logfile) + ctx->gf_ctx.cmd_args.log_file = strdup (init_ctx->logfile); + else + ctx->gf_ctx.cmd_args.log_file = strdup ("/dev/stderr"); + + if (init_ctx->loglevel) { + if (!strncasecmp (init_ctx->loglevel, "DEBUG", strlen ("DEBUG"))) { + ctx->gf_ctx.cmd_args.log_level = GF_LOG_DEBUG; + } else if (!strncasecmp (init_ctx->loglevel, "WARNING", strlen ("WARNING"))) { + ctx->gf_ctx.cmd_args.log_level = GF_LOG_WARNING; + } else if (!strncasecmp (init_ctx->loglevel, "CRITICAL", strlen ("CRITICAL"))) { + ctx->gf_ctx.cmd_args.log_level = GF_LOG_CRITICAL; + } else if (!strncasecmp (init_ctx->loglevel, "NONE", strlen ("NONE"))) { + ctx->gf_ctx.cmd_args.log_level = GF_LOG_NONE; + } else if (!strncasecmp (init_ctx->loglevel, "ERROR", strlen ("ERROR"))) { + ctx->gf_ctx.cmd_args.log_level = GF_LOG_ERROR; + } else { + fprintf (stderr, + "libglusterfsclient: %s:%s():%d: Unrecognized log-level \"%s\", possible values are \"DEBUG|WARNING|[ERROR]|CRITICAL|NONE\"\n", __FILE__, __PRETTY_FUNCTION__, + __LINE__, init_ctx->loglevel); + FREE (ctx->gf_ctx.cmd_args.log_file); + FREE (ctx->gf_ctx.pool); + FREE (ctx->gf_ctx.event_pool); + FREE (ctx); + errno = EINVAL; + return NULL; + } + } + + if (first_init) + { + ret = gf_log_init (ctx->gf_ctx.cmd_args.log_file); + if (ret == -1) { + fprintf (stderr, + "libglusterfsclient: %s:%s():%d: failed to open logfile \"%s\"\n", + __FILE__, __PRETTY_FUNCTION__, __LINE__, + ctx->gf_ctx.cmd_args.log_file); + FREE (ctx->gf_ctx.cmd_args.log_file); + FREE (ctx->gf_ctx.pool); + FREE (ctx->gf_ctx.event_pool); + FREE (ctx); + return NULL; + } + + gf_log_set_loglevel (ctx->gf_ctx.cmd_args.log_level); + } + + if (init_ctx->specfp) { + specfp = init_ctx->specfp; + if (fseek (specfp, 0L, SEEK_SET)) { + fprintf (stderr, + "libglusterfsclient: %s:%s():%d: fseek on volume file stream failed (%s)\n", __FILE__, __PRETTY_FUNCTION__, __LINE__, strerror (errno)); + FREE (ctx->gf_ctx.cmd_args.log_file); + FREE (ctx->gf_ctx.pool); + FREE (ctx->gf_ctx.event_pool); + FREE (ctx); + return NULL; + } + } else if (init_ctx->specfile) { + specfp = fopen (init_ctx->specfile, "r"); + ctx->gf_ctx.cmd_args.volume_file = strdup (init_ctx->specfile); + } + + if (!specfp) { + fprintf (stderr, + "libglusterfsclient: %s:%s():%d: could not open volfile: %s\n", + __FILE__, __PRETTY_FUNCTION__, __LINE__, strerror (errno)); + FREE (ctx->gf_ctx.cmd_args.log_file); + FREE (ctx->gf_ctx.cmd_args.volume_file); + FREE (ctx->gf_ctx.pool); + FREE (ctx->gf_ctx.event_pool); + FREE (ctx); + return NULL; + } + + if (init_ctx->volume_name) { + ctx->gf_ctx.cmd_args.volume_name = strdup (init_ctx->volume_name); + } + + graph = file_to_xlator_tree (&ctx->gf_ctx, specfp); + if (!graph) { + fprintf (stderr, + "libglusterfsclient: %s:%s():%d: cannot create configuration graph (%s)\n", + __FILE__, __PRETTY_FUNCTION__, __LINE__, strerror (errno)); + + FREE (ctx->gf_ctx.cmd_args.log_file); + FREE (ctx->gf_ctx.cmd_args.volume_file); + FREE (ctx->gf_ctx.cmd_args.volume_name); + FREE (ctx->gf_ctx.pool); + FREE (ctx->gf_ctx.event_pool); + FREE (ctx); + return NULL; + } + + if (init_ctx->volume_name) { + trav = graph; + while (trav) { + if (strcmp (trav->name, init_ctx->volume_name) == 0) { + graph = trav; + break; + } + trav = trav->next; + } + } + + ctx->gf_ctx.graph = libglusterfs_graph (graph); + if (!ctx->gf_ctx.graph) { + fprintf (stderr, + "libglusterfsclient: %s:%s():%d: graph creation failed (%s)\n", + __FILE__, __PRETTY_FUNCTION__, __LINE__, strerror (errno)); + + xlator_tree_free (graph); + FREE (ctx->gf_ctx.cmd_args.log_file); + FREE (ctx->gf_ctx.cmd_args.volume_file); + FREE (ctx->gf_ctx.cmd_args.volume_name); + FREE (ctx->gf_ctx.pool); + FREE (ctx->gf_ctx.event_pool); + FREE (ctx); + return NULL; + } + graph = ctx->gf_ctx.graph; + + trav = graph; + while (trav) { + xl_count++; /* Getting this value right is very important */ + trav = trav->next; + } + + ctx->gf_ctx.xl_count = xl_count + 1; + + priv = CALLOC (1, sizeof (*priv)); + if (!priv) { + fprintf (stderr, + "libglusterfsclient: %s:%s():%d: cannot allocate memory (%s)\n", + __FILE__, __PRETTY_FUNCTION__, __LINE__, strerror (errno)); + + xlator_tree_free (graph); + FREE (ctx->gf_ctx.cmd_args.log_file); + FREE (ctx->gf_ctx.cmd_args.volume_file); + FREE (ctx->gf_ctx.cmd_args.volume_name); + FREE (ctx->gf_ctx.pool); + FREE (ctx->gf_ctx.event_pool); + /* inode_table_destroy (ctx->itable); */ + FREE (ctx); + + return NULL; + } + + pthread_cond_init (&priv->init_con_established, NULL); + pthread_mutex_init (&priv->lock, NULL); + + graph->private = priv; + ctx->itable = inode_table_new (LIBGLUSTERFS_INODE_TABLE_LRU_LIMIT, graph); + if (!ctx->itable) { + fprintf (stderr, + "libglusterfsclient: %s:%s():%d: cannot create inode table\n", + __FILE__, __PRETTY_FUNCTION__, __LINE__); + xlator_tree_free (graph); + FREE (ctx->gf_ctx.cmd_args.log_file); + FREE (ctx->gf_ctx.cmd_args.volume_file); + FREE (ctx->gf_ctx.cmd_args.volume_name); + + FREE (ctx->gf_ctx.pool); + FREE (ctx->gf_ctx.event_pool); + xlator_tree_free (graph); + /* TODO: destroy graph */ + /* inode_table_destroy (ctx->itable); */ + FREE (ctx); + + return NULL; + } + + if (xlator_graph_init (graph) == -1) { + fprintf (stderr, + "libglusterfsclient: %s:%s():%d: graph initialization failed\n", + __FILE__, __PRETTY_FUNCTION__, __LINE__); + xlator_tree_free (graph); + FREE (ctx->gf_ctx.cmd_args.log_file); + FREE (ctx->gf_ctx.cmd_args.volume_file); + FREE (ctx->gf_ctx.cmd_args.volume_name); + FREE (ctx->gf_ctx.pool); + FREE (ctx->gf_ctx.event_pool); + /* TODO: destroy graph */ + /* inode_table_destroy (ctx->itable); */ + FREE (ctx); + return NULL; + } + + /* Send notify to all translator saying things are ready */ + graph->notify (graph, GF_EVENT_PARENT_UP, graph); + + if (gf_timer_registry_init (&ctx->gf_ctx) == NULL) { + fprintf (stderr, + "libglusterfsclient: %s:%s():%d: timer init failed (%s)\n", + __FILE__, __PRETTY_FUNCTION__, __LINE__, strerror (errno)); + + xlator_graph_fini (graph); + xlator_tree_free (graph); + FREE (ctx->gf_ctx.cmd_args.log_file); + FREE (ctx->gf_ctx.cmd_args.volume_file); + FREE (ctx->gf_ctx.cmd_args.volume_name); + + FREE (ctx->gf_ctx.pool); + FREE (ctx->gf_ctx.event_pool); + /* TODO: destroy graph */ + /* inode_table_destroy (ctx->itable); */ + FREE (ctx); + return NULL; + } + + if ((ret = pthread_create (&ctx->reply_thread, NULL, poll_proc, (void *)&ctx->gf_ctx))) { + fprintf (stderr, + "libglusterfsclient: %s:%s():%d: reply thread creation failed\n", + __FILE__, __PRETTY_FUNCTION__, __LINE__); + xlator_graph_fini (graph); + xlator_tree_free (graph); + FREE (ctx->gf_ctx.cmd_args.log_file); + FREE (ctx->gf_ctx.cmd_args.volume_file); + FREE (ctx->gf_ctx.cmd_args.volume_name); + + FREE (ctx->gf_ctx.pool); + FREE (ctx->gf_ctx.event_pool); + /* TODO: destroy graph */ + /* inode_table_destroy (ctx->itable); */ + FREE (ctx); + return NULL; + } + + set_global_ctx_ptr (&ctx->gf_ctx); + ctx->gf_ctx.process_uuid = zr_build_process_uuid (); + + pthread_mutex_lock (&priv->lock); + { + while (!priv->complete) { + pthread_cond_wait (&priv->init_con_established, &priv->lock); + } + } + pthread_mutex_unlock (&priv->lock); + + first_init = 0; + + return ctx; +} + + +void +glusterfs_reset (void) +{ + first_fini = first_init = 1; +} + + +void +glusterfs_log_lock (void) +{ + gf_log_lock (); +} + + +void glusterfs_log_unlock (void) +{ + gf_log_unlock (); +} + + +int +glusterfs_fini (libglusterfs_client_ctx_t *ctx) +{ + FREE (ctx->gf_ctx.cmd_args.log_file); + FREE (ctx->gf_ctx.cmd_args.volume_file); + FREE (ctx->gf_ctx.cmd_args.volume_name); + FREE (ctx->gf_ctx.pool); + FREE (ctx->gf_ctx.event_pool); + ((gf_timer_registry_t *)ctx->gf_ctx.timer)->fin = 1; + /* inode_table_destroy (ctx->itable); */ + + xlator_graph_fini (ctx->gf_ctx.graph); + xlator_tree_free (ctx->gf_ctx.graph); + ctx->gf_ctx.graph = NULL; + + /* FREE (ctx->gf_ctx.specfile); */ + + /* TODO complete cleanup of timer */ + /*TODO + * destroy the reply thread + * destroy inode table + * FREE (ctx) + */ + + FREE (ctx); + + if (first_fini) { + ; + //gf_log_cleanup (); + } + + return 0; +} + + +int32_t +libgf_client_lookup_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + inode_t *inode, + struct stat *buf, + dict_t *dict) +{ + libgf_client_local_t *local = frame->local; + libglusterfs_client_ctx_t *ctx = frame->root->state; + dict_t *xattr_req = NULL; + + if (op_ret == 0) { + /* flat directory structure */ + inode_t *parent = inode_search (ctx->itable, 1, NULL); + + inode_link (inode, parent, local->fop.lookup.loc->path, buf); + inode_lookup (inode); + inode_unref (parent); + } else { + if (local->fop.lookup.is_revalidate == 0 && op_errno == ENOENT) { + gf_log ("libglusterfsclient", GF_LOG_DEBUG, + "%"PRId64": (op_num=%d) %s => -1 (%s)", + frame->root->unique, frame->root->op, + local->fop.lookup.loc->path, + strerror (op_errno)); + } else { + gf_log ("libglusterfsclient", GF_LOG_ERROR, + "%"PRId64": (op_num=%d) %s => -1 (%s)", + frame->root->unique, frame->root->op, + local->fop.lookup.loc->path, + strerror (op_errno)); + } + + if (local->fop.lookup.is_revalidate == 1) { + int32_t ret = 0; + inode_unref (local->fop.lookup.loc->inode); + local->fop.lookup.loc->inode = inode_new (ctx->itable); + local->fop.lookup.is_revalidate = 2; + + if (local->fop.lookup.size > 0) { + xattr_req = dict_new (); + ret = dict_set (xattr_req, "glusterfs.content", + data_from_uint64 (local->fop.lookup.size)); + if (ret == -1) { + op_ret = -1; + /* TODO: set proper error code */ + op_errno = errno; + inode = NULL; + buf = NULL; + dict = NULL; + dict_unref (xattr_req); + goto out; + } + } + + STACK_WIND (frame, libgf_client_lookup_cbk, + FIRST_CHILD (this), FIRST_CHILD (this)->fops->lookup, + local->fop.lookup.loc, xattr_req); + + if (xattr_req) { + dict_unref (xattr_req); + xattr_req = NULL; + } + + return 0; + } + } + +out: + local->reply_stub = fop_lookup_cbk_stub (frame, NULL, op_ret, op_errno, inode, buf, dict); + + pthread_mutex_lock (&local->lock); + { + local->complete = 1; + pthread_cond_broadcast (&local->reply_cond); + } + pthread_mutex_unlock (&local->lock); + + return 0; +} + +int32_t +libgf_client_lookup (libglusterfs_client_ctx_t *ctx, + loc_t *loc, + struct stat *stbuf, + dict_t **dict, + dict_t *xattr_req) +{ + call_stub_t *stub = NULL; + int32_t op_ret; + libgf_client_local_t *local = NULL; + xlator_t *this = NULL; + int32_t ret = -1; + + local = CALLOC (1, sizeof (*local)); + if (loc->inode) { + local->fop.lookup.is_revalidate = 1; + loc->ino = loc->inode->ino; + } + else + loc->inode = inode_new (ctx->itable); + + local->fop.lookup.loc = loc; + + LIBGF_CLIENT_FOP(ctx, stub, lookup, local, loc, xattr_req); + + op_ret = stub->args.lookup_cbk.op_ret; + errno = stub->args.lookup_cbk.op_errno; + + if (!op_ret) { + time_t current = 0; + libglusterfs_client_inode_ctx_t *inode_ctx = NULL; + inode_t *inode = stub->args.lookup_cbk.inode; + uint64_t ptr = 0; + + this = ctx->gf_ctx.graph; + ret = inode_ctx_get (inode, this, &ptr); + if (ret == -1) { + inode_ctx = CALLOC (1, sizeof (*inode_ctx)); + ERR_ABORT (inode_ctx); + pthread_mutex_init (&inode_ctx->lock, NULL); + } else { + inode_ctx = (libglusterfs_client_inode_ctx_t *)(long)ptr; + } + + current = time (NULL); + + pthread_mutex_lock (&inode_ctx->lock); + { + inode_ctx->previous_lookup_time = current; + inode_ctx->previous_stat_time = current; + memcpy (&inode_ctx->stbuf, &stub->args.lookup_cbk.buf, + sizeof (inode_ctx->stbuf)); + } + pthread_mutex_unlock (&inode_ctx->lock); + + ret = inode_ctx_get (inode, this, NULL); + if (ret == -1) { + inode_ctx_put (inode, this, (uint64_t)(long)inode_ctx); + } + + if (stbuf) + *stbuf = stub->args.lookup_cbk.buf; + + if (dict) + *dict = dict_ref (stub->args.lookup_cbk.dict); + } + + call_stub_destroy (stub); + return op_ret; +} + +int +glusterfs_lookup (libglusterfs_handle_t handle, + const char *path, + void *buf, + size_t size, + struct stat *stbuf) +{ + int32_t op_ret = 0; + loc_t loc = {0, }; + libglusterfs_client_ctx_t *ctx = handle; + dict_t *dict = NULL; + dict_t *xattr_req = NULL; + + op_ret = libgf_client_loc_fill (&loc, path, 0, ctx); + if (op_ret < 0) { + gf_log ("libglusterfsclient", + GF_LOG_ERROR, + "libgf_client_loc_fill returned -1, returning EINVAL"); + errno = EINVAL; + goto out; + } + + if (size < 0) + size = 0; + + if (size > 0) { + xattr_req = dict_new (); + op_ret = dict_set (xattr_req, "glusterfs.content", data_from_uint64 (size)); + if (op_ret < 0) { + gf_log ("libglusterfsclient", + GF_LOG_ERROR, + "setting requested content size dictionary failed"); + goto out; + } + } + + op_ret = libgf_client_lookup (ctx, &loc, stbuf, &dict, xattr_req); + + if (!op_ret && size && stbuf && stbuf->st_size && dict && buf) { + data_t *mem_data = NULL; + void *mem = NULL; + + mem_data = dict_get (dict, "glusterfs.content"); + if (mem_data) { + mem = data_to_ptr (mem_data); + } + + if (mem && stbuf->st_size <= size) { + memcpy (buf, mem, stbuf->st_size); + } + } + + if (dict) { + dict_unref (dict); + } + + libgf_client_loc_wipe (&loc); +out: + if (xattr_req) { + dict_unref (xattr_req); + } + + return op_ret; +} + +int +libgf_client_lookup_async_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + inode_t *inode, + struct stat *buf, + dict_t *dict) +{ + libglusterfs_client_async_local_t *local = frame->local; + glusterfs_lookup_cbk_t lookup_cbk = local->fop.lookup_cbk.cbk; + libglusterfs_client_ctx_t *ctx = frame->root->state; + dict_t *xattr_req = NULL; + int32_t ret = 0; + + if (op_ret == 0) { + time_t current = 0; + data_t *inode_ctx_data = NULL; + libglusterfs_client_inode_ctx_t *inode_ctx = NULL; + + /* flat directory structure */ + inode_t *parent = inode_search (ctx->itable, 1, NULL); + + inode_link (inode, parent, local->fop.lookup_cbk.loc->path, buf); + + inode_ctx_data = dict_get (inode->ctx, XLATOR_NAME); + if (inode_ctx_data) { + inode_ctx = data_to_ptr (inode_ctx_data); + } + + if (!inode_ctx) { + inode_ctx = CALLOC (1, sizeof (*inode_ctx)); + pthread_mutex_init (&inode_ctx->lock, NULL); + } + + current = time (NULL); + + pthread_mutex_lock (&inode_ctx->lock); + { + inode_ctx->previous_lookup_time = current; + inode_ctx->previous_stat_time = current; + memcpy (&inode_ctx->stbuf, buf, sizeof (inode_ctx->stbuf)); + } + pthread_mutex_unlock (&inode_ctx->lock); + + ret = inode_ctx_get (inode, this, NULL); + if (ret == -1) { + inode_ctx_put (inode, this, (uint64_t)(long)inode_ctx); + } + + inode_lookup (inode); + inode_unref (parent); + } else { + if (local->fop.lookup_cbk.is_revalidate == 0 && op_errno == ENOENT) { + gf_log ("libglusterfsclient", GF_LOG_DEBUG, + "%"PRId64": (op_num=%d) %s => -1 (%s)", + frame->root->unique, frame->root->op, + local->fop.lookup_cbk.loc->path, + strerror (op_errno)); + } else { + gf_log ("libglusterfsclient", GF_LOG_ERROR, + "%"PRId64": (op_num=%d) %s => -1 (%s)", + frame->root->unique, frame->root->op, + local->fop.lookup_cbk.loc->path, + strerror (op_errno)); + } + + if (local->fop.lookup_cbk.is_revalidate == 1) { + int32_t ret = 0; + inode_unref (local->fop.lookup_cbk.loc->inode); + local->fop.lookup_cbk.loc->inode = inode_new (ctx->itable); + local->fop.lookup_cbk.is_revalidate = 2; + + if (local->fop.lookup_cbk.size > 0) { + xattr_req = dict_new (); + ret = dict_set (xattr_req, "glusterfs.content", + data_from_uint64 (local->fop.lookup_cbk.size)); + if (ret == -1) { + op_ret = -1; + /* TODO: set proper error code */ + op_errno = errno; + inode = NULL; + buf = NULL; + dict = NULL; + dict_unref (xattr_req); + goto out; + } + } + + + STACK_WIND (frame, libgf_client_lookup_async_cbk, + FIRST_CHILD (this), FIRST_CHILD (this)->fops->lookup, + local->fop.lookup_cbk.loc, xattr_req); + + if (xattr_req) { + dict_unref (xattr_req); + xattr_req = NULL; + } + + return 0; + } + + } + +out: + if (!op_ret && local->fop.lookup_cbk.size && dict && local->fop.lookup_cbk.buf) { + data_t *mem_data = NULL; + void *mem = NULL; + + mem_data = dict_get (dict, "glusterfs.content"); + if (mem_data) { + mem = data_to_ptr (mem_data); + } + + if (mem && buf->st_size <= local->fop.lookup_cbk.size) { + memcpy (local->fop.lookup_cbk.buf, mem, buf->st_size); + } + } + + lookup_cbk(op_ret, op_errno, local->fop.lookup_cbk.buf, buf, local->cbk_data); + + libgf_client_loc_wipe (local->fop.lookup_cbk.loc); + free (local->fop.lookup_cbk.loc); + + free (local); + frame->local = NULL; + STACK_DESTROY (frame->root); + + return 0; +} + +int +glusterfs_lookup_async (libglusterfs_handle_t handle, + const char *path, + void *buf, + size_t size, + glusterfs_lookup_cbk_t cbk, + void *cbk_data) +{ + loc_t *loc = NULL; + libglusterfs_client_ctx_t *ctx = handle; + libglusterfs_client_async_local_t *local = NULL; + int32_t op_ret = 0; + dict_t *xattr_req = NULL; + + local = CALLOC (1, sizeof (*local)); + local->fop.lookup_cbk.is_revalidate = 1; + + loc = CALLOC (1, sizeof (*loc)); + op_ret = libgf_client_loc_fill (loc, path, 0, ctx); + if (op_ret < 0) { + gf_log ("libglusterfsclient", + GF_LOG_ERROR, + "libgf_client_loc_fill returned -1, returning EINVAL"); + errno = EINVAL; + goto out; + } + + if (!loc->inode) { + loc->inode = inode_new (ctx->itable); + local->fop.lookup_cbk.is_revalidate = 0; + } + + local->fop.lookup_cbk.cbk = cbk; + local->fop.lookup_cbk.buf = buf; + local->fop.lookup_cbk.size = size; + local->fop.lookup_cbk.loc = loc; + local->cbk_data = cbk_data; + + if (size < 0) + size = 0; + + if (size > 0) { + xattr_req = dict_new (); + op_ret = dict_set (xattr_req, "glusterfs.content", data_from_uint64 (size)); + if (op_ret < 0) { + dict_unref (xattr_req); + xattr_req = NULL; + goto out; + } + } + + LIBGF_CLIENT_FOP_ASYNC (ctx, + local, + libgf_client_lookup_async_cbk, + lookup, + loc, + xattr_req); + if (xattr_req) { + dict_unref (xattr_req); + xattr_req = NULL; + } + +out: + return op_ret; +} + +int32_t +libgf_client_getxattr_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + dict_t *dict) +{ + + libgf_client_local_t *local = frame->local; + + local->reply_stub = fop_getxattr_cbk_stub (frame, NULL, op_ret, op_errno, dict); + + pthread_mutex_lock (&local->lock); + { + local->complete = 1; + pthread_cond_broadcast (&local->reply_cond); + } + pthread_mutex_unlock (&local->lock); + + return 0; +} + +size_t +libgf_client_getxattr (libglusterfs_client_ctx_t *ctx, + loc_t *loc, + const char *name, + void *value, + size_t size) +{ + call_stub_t *stub = NULL; + int32_t op_ret = 0; + libgf_client_local_t *local = NULL; + + LIBGF_CLIENT_FOP (ctx, stub, getxattr, local, loc, name); + + op_ret = stub->args.getxattr_cbk.op_ret; + errno = stub->args.getxattr_cbk.op_errno; + + if (op_ret >= 0) { + /* + gf_log ("LIBGF_CLIENT", GF_LOG_DEBUG, + "%"PRId64": %s => %d", frame->root->unique, + state->fuse_loc.loc.path, op_ret); + */ + + data_t *value_data = dict_get (stub->args.getxattr_cbk.dict, (char *)name); + + if (value_data) { + int32_t copy_len = 0; + op_ret = value_data->len; /* Don't return the value for '\0' */ + + copy_len = size < value_data->len ? size : value_data->len; + memcpy (value, value_data->data, copy_len); + } else { + errno = ENODATA; + op_ret = -1; + } + } + + call_stub_destroy (stub); + return op_ret; +} + +ssize_t +glusterfs_getxattr (libglusterfs_client_ctx_t *ctx, + const char *path, + const char *name, + void *value, + size_t size) +{ + int32_t op_ret = 0; + loc_t loc = {0, }; + dict_t *dict = NULL; + + op_ret = libgf_client_loc_fill (&loc, path, 0, ctx); + if (op_ret < 0) { + gf_log ("libglusterfsclient", + GF_LOG_ERROR, + "libgf_client_loc_fill returned -1, returning EINVAL"); + errno = EINVAL; + goto out; + } + + op_ret = libgf_client_lookup (ctx, &loc, NULL, &dict, NULL); + if (op_ret == 0) { + data_t *value_data = dict_get (dict, (char *)name); + + if (value_data) { + int32_t copy_len = 0; + op_ret = value_data->len; /* Don't return the value for '\0' */ + + copy_len = size < value_data->len ? size : value_data->len; + memcpy (value, value_data->data, copy_len); + } else { + errno = ENODATA; + op_ret = -1; + } + } + + if (dict) { + dict_unref (dict); + } + + libgf_client_loc_wipe (&loc); + +out: + return op_ret; +} + +static int32_t +libgf_client_open_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + fd_t *fd) +{ + libgf_client_local_t *local = frame->local; + + local->reply_stub = fop_open_cbk_stub (frame, NULL, op_ret, op_errno, fd); + + pthread_mutex_lock (&local->lock); + { + local->complete = 1; + pthread_cond_broadcast (&local->reply_cond); + } + pthread_mutex_unlock (&local->lock); + + return 0; +} + + +int +libgf_client_open (libglusterfs_client_ctx_t *ctx, + loc_t *loc, + fd_t *fd, + int flags) +{ + call_stub_t *stub = NULL; + int32_t op_ret = 0; + libgf_client_local_t *local = NULL; + + LIBGF_CLIENT_FOP (ctx, stub, open, local, loc, flags, fd); + + op_ret = stub->args.open_cbk.op_ret; + errno = stub->args.open_cbk.op_errno; + + call_stub_destroy (stub); + return op_ret; +} + +static int32_t +libgf_client_create_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + fd_t *fd, + inode_t *inode, + struct stat *buf) +{ + libgf_client_local_t *local = frame->local; + + local->reply_stub = fop_create_cbk_stub (frame, NULL, op_ret, op_errno, fd, inode, buf); + + pthread_mutex_lock (&local->lock); + { + local->complete = 1; + pthread_cond_broadcast (&local->reply_cond); + } + pthread_mutex_unlock (&local->lock); + + return 0; +} + +int +libgf_client_creat (libglusterfs_client_ctx_t *ctx, + loc_t *loc, + fd_t *fd, + int flags, + mode_t mode) +{ + call_stub_t *stub = NULL; + int32_t op_ret = 0; + libgf_client_local_t *local = NULL; + xlator_t *this = NULL; + + LIBGF_CLIENT_FOP (ctx, stub, create, local, loc, flags, mode, fd); + + if (stub->args.create_cbk.op_ret == 0) { + inode_t *libgf_inode = NULL; + time_t current = 0; + libglusterfs_client_inode_ctx_t *inode_ctx = NULL; + + /* flat directory structure */ + inode_t *parent = inode_search (ctx->itable, 1, NULL); + libgf_inode = stub->args.create_cbk.inode; + inode_link (libgf_inode, parent, + loc->path, &stub->args.create_cbk.buf); + + inode_lookup (libgf_inode); + inode_unref (parent); + + inode_ctx = CALLOC (1, sizeof (*inode_ctx)); + ERR_ABORT (inode_ctx); + pthread_mutex_init (&inode_ctx->lock, NULL); + + current = time (NULL); + + inode_ctx->previous_lookup_time = current; + inode_ctx->previous_stat_time = current; + memcpy (&inode_ctx->stbuf, &stub->args.lookup_cbk.buf, + sizeof (inode_ctx->stbuf)); + + this = ctx->gf_ctx.graph; + inode_ctx_put (libgf_inode, this, (uint64_t)(long)inode_ctx); + } + + op_ret = stub->args.create_cbk.op_ret; + errno = stub->args.create_cbk.op_errno; + + call_stub_destroy (stub); + return op_ret; +} + +int32_t +libgf_client_opendir_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + fd_t *fd) +{ + libgf_client_local_t *local = frame->local; + + local->reply_stub = fop_opendir_cbk_stub (frame, NULL, op_ret, op_errno, fd); + + pthread_mutex_lock (&local->lock); + { + local->complete = 1; + pthread_cond_broadcast (&local->reply_cond); + } + pthread_mutex_unlock (&local->lock); + + return 0; +} + +int +libgf_client_opendir (libglusterfs_client_ctx_t *ctx, + loc_t *loc, + fd_t *fd) +{ + call_stub_t *stub = NULL; + int32_t op_ret = 0; + libgf_client_local_t *local = NULL; + + LIBGF_CLIENT_FOP (ctx, stub, opendir, local, loc, fd); + + op_ret = stub->args.opendir_cbk.op_ret; + errno = stub->args.opendir_cbk.op_errno; + + call_stub_destroy (stub); + return 0; +} + +unsigned long +glusterfs_open (libglusterfs_client_ctx_t *ctx, + const char *path, + int flags, + mode_t mode) +{ + loc_t loc = {0, }; + long op_ret = 0; + fd_t *fd = NULL; + struct stat stbuf; + char lookup_required = 1; + int32_t ret = -1; + xlator_t *this = NULL; + + if (!ctx || !path || path[0] != '/') { + errno = EINVAL; + return 0; + } + + this = ctx->gf_ctx.graph; + + op_ret = libgf_client_loc_fill (&loc, path, 0, ctx); + if (op_ret < 0) { + gf_log ("libglusterfsclient", + GF_LOG_ERROR, + "libgf_client_loc_fill returned -1, returning EINVAL"); + errno = EINVAL; + fd = NULL; + goto out; + } + + if (loc.inode) { + libglusterfs_client_inode_ctx_t *inode_ctx = NULL; + time_t current, prev; + uint64_t ptr = 0; + + ret = inode_ctx_get (loc.inode, this, &ptr); + if (ret == 0) { + inode_ctx = (libglusterfs_client_inode_ctx_t *)(long)ptr; + memset (¤t, 0, sizeof (current)); + + pthread_mutex_lock (&inode_ctx->lock); + { + prev = inode_ctx->previous_lookup_time; + } + pthread_mutex_unlock (&inode_ctx->lock); + + current = time (NULL); + if (prev >= 0 && ctx->lookup_timeout >= (current - prev)) { + lookup_required = 0; + } + } + } + + if (lookup_required) { + op_ret = libgf_client_lookup (ctx, &loc, &stbuf, NULL, NULL); + if (!op_ret && ((flags & O_CREAT) == O_CREAT) && ((flags & O_EXCL) == O_EXCL)) { + errno = EEXIST; + op_ret = -1; + } + } + + if (!op_ret || (op_ret == -1 && errno == ENOENT && ((flags & O_CREAT) == O_CREAT))) { + fd = fd_create (loc.inode, 0); + fd->flags = flags; + + if (!op_ret) { + if (S_ISDIR (loc.inode->st_mode)) { + if (((flags & O_RDONLY) == O_RDONLY) && + ((flags & O_WRONLY) == 0) && + ((flags & O_RDWR) == 0)) { + op_ret = libgf_client_opendir (ctx, &loc, fd); + } else { + op_ret = -1; + errno = EISDIR; + } + } else { + op_ret = libgf_client_open (ctx, &loc, fd, flags); + } + } else { + op_ret = libgf_client_creat (ctx, &loc, fd, flags, mode); + } + + if (op_ret == -1) { + fd_unref (fd); + fd = NULL; + } else { + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + libglusterfs_client_inode_ctx_t *inode_ctx = NULL; + data_t *ctx_data = NULL; + + ctx_data = dict_get (fd->ctx, XLATOR_NAME); + if (!ctx_data) { + fd_ctx = CALLOC (1, sizeof (*fd_ctx)); + ERR_ABORT (fd_ctx); + pthread_mutex_init (&fd_ctx->lock, NULL); + } + + pthread_mutex_lock (&fd_ctx->lock); + { + fd_ctx->ctx = ctx; + } + pthread_mutex_unlock (&fd_ctx->lock); + + if (!ctx_data) { + dict_set (fd->ctx, XLATOR_NAME, data_from_dynptr (fd_ctx, sizeof (*fd_ctx))); + } + + if ((flags & O_TRUNC) && ((flags & O_RDWR) || (flags & O_WRONLY))) { + uint64_t ptr = 0; + ret = inode_ctx_get (fd->inode, this, &ptr); + if (ret == 0) { + inode_ctx = (libglusterfs_client_inode_ctx_t *)(long)ptr; + if (S_ISREG (inode_ctx->stbuf.st_mode)) { + inode_ctx->stbuf.st_size = inode_ctx->stbuf.st_blocks = 0; + } + } else { + gf_log ("libglusterfsclient", GF_LOG_WARNING, + "inode_ctx is NULL for inode (%p) belonging to fd (%p)", + fd->inode, fd); + } + } + } + } + + libgf_client_loc_wipe (&loc); + +out: + return (long)fd; +} + + +unsigned long +glusterfs_creat (libglusterfs_client_ctx_t *ctx, + const char *path, + mode_t mode) +{ + return glusterfs_open (ctx, path, + (O_CREAT | O_WRONLY | O_TRUNC), mode); +} + + +int32_t +libgf_client_flush_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + libgf_client_local_t *local = frame->local; + + local->reply_stub = fop_flush_cbk_stub (frame, NULL, op_ret, op_errno); + + pthread_mutex_lock (&local->lock); + { + local->complete = 1; + pthread_cond_broadcast (&local->reply_cond); + } + pthread_mutex_unlock (&local->lock); + + return 0; +} + + +int +libgf_client_flush (libglusterfs_client_ctx_t *ctx, fd_t *fd) +{ + call_stub_t *stub; + int32_t op_ret; + libgf_client_local_t *local = NULL; + + LIBGF_CLIENT_FOP (ctx, stub, flush, local, fd); + + op_ret = stub->args.flush_cbk.op_ret; + errno = stub->args.flush_cbk.op_errno; + + call_stub_destroy (stub); + return op_ret; +} + + +int +glusterfs_close (unsigned long fd) +{ + int32_t op_ret = -1; + data_t *fd_ctx_data = NULL; + libglusterfs_client_ctx_t *ctx = NULL; + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + + if (!fd) { + errno = EINVAL; + goto out; + } + + fd_ctx_data = dict_get (((fd_t *) fd)->ctx, XLATOR_NAME); + if (!fd_ctx_data) { + errno = EBADF; + goto out; + } + + fd_ctx = data_to_ptr (fd_ctx_data); + ctx = fd_ctx->ctx; + + op_ret = libgf_client_flush (ctx, (fd_t *)fd); + + fd_unref ((fd_t *)fd); + +out: + return op_ret; +} + +int32_t +libgf_client_setxattr_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno) +{ + libgf_client_local_t *local = frame->local; + + local->reply_stub = fop_setxattr_cbk_stub (frame, NULL, op_ret, op_errno); + + pthread_mutex_lock (&local->lock); + { + local->complete = 1; + pthread_cond_broadcast (&local->reply_cond); + } + pthread_mutex_unlock (&local->lock); + + return 0; +} + +int +libgf_client_setxattr (libglusterfs_client_ctx_t *ctx, + loc_t *loc, + const char *name, + const void *value, + size_t size, + int flags) +{ + call_stub_t *stub = NULL; + int32_t op_ret = 0; + dict_t *dict; + libgf_client_local_t *local = NULL; + + dict = get_new_dict (); + + dict_set (dict, (char *)name, + bin_to_data ((void *)value, size)); + dict_ref (dict); + + + LIBGF_CLIENT_FOP (ctx, stub, setxattr, local, loc, dict, flags); + + op_ret = stub->args.setxattr_cbk.op_ret; + errno = stub->args.setxattr_cbk.op_errno; + + dict_unref (dict); + call_stub_destroy (stub); + return op_ret; +} + +int +glusterfs_setxattr (libglusterfs_client_ctx_t *ctx, + const char *path, + const char *name, + const void *value, + size_t size, + int flags) +{ + int32_t op_ret = 0; + loc_t loc = {0, }; + char lookup_required = 1; + xlator_t *this = NULL; + + op_ret = libgf_client_loc_fill (&loc, path, 0, ctx); + if (op_ret < 0) { + gf_log ("libglusterfsclient", + GF_LOG_ERROR, + "libgf_client_loc_fill returned -1, returning EINVAL"); + errno = EINVAL; + goto out; + } + + this = ctx->gf_ctx.graph; + if (loc.inode) { + time_t current, prev; + libglusterfs_client_inode_ctx_t *inode_ctx = NULL; + uint64_t ptr = 0; + + op_ret = inode_ctx_get (loc.inode, this, &ptr); + if (op_ret == -1) { + errno = EINVAL; + goto out; + } + + inode_ctx = (libglusterfs_client_inode_ctx_t *)(long)ptr; + memset (¤t, 0, sizeof (current)); + current = time (NULL); + + pthread_mutex_lock (&inode_ctx->lock); + { + prev = inode_ctx->previous_lookup_time; + } + pthread_mutex_unlock (&inode_ctx->lock); + + if ((prev >= 0) && ctx->lookup_timeout >= (current - prev)) { + lookup_required = 0; + } + } + + if (lookup_required) { + op_ret = libgf_client_lookup (ctx, &loc, NULL, NULL, NULL); + } + + if (!op_ret) + op_ret = libgf_client_setxattr (ctx, &loc, name, value, size, flags); + + libgf_client_loc_wipe (&loc); + +out: + return op_ret; +} + +int +glusterfs_lsetxattr (libglusterfs_client_ctx_t *ctx, + const char *path, + const char *name, + const void *value, + size_t size, int flags) +{ + return ENOSYS; +} + +int +glusterfs_fsetxattr (unsigned long fd, + const char *name, + const void *value, + size_t size, + int flags) +{ + int32_t op_ret = 0; + fd_t *__fd ; + char lookup_required = 1; + libglusterfs_client_ctx_t *ctx = NULL; + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + data_t *fd_ctx_data = NULL; + loc_t loc = {0, }; + xlator_t *this = NULL; + + __fd = (fd_t *)fd; + fd_ctx_data = dict_get (__fd->ctx, XLATOR_NAME); + if (!fd_ctx_data) { + errno = EBADF; + op_ret = -1; + goto out; + } + + fd_ctx = data_to_ptr (fd_ctx_data); + ctx = fd_ctx->ctx; + + op_ret = libgf_client_loc_fill (&loc, NULL, __fd->inode->ino, ctx); + if (op_ret < 0) { + gf_log ("libglusterfsclient", + GF_LOG_ERROR, + "libgf_client_loc_fill returned -1, returning EINVAL"); + errno = EINVAL; + goto out; + } + + this = ctx->gf_ctx.graph; + if (loc.inode) { + time_t current, prev; + libglusterfs_client_inode_ctx_t *inode_ctx = NULL; + uint64_t ptr = 0; + + op_ret = inode_ctx_get (loc.inode, this, &ptr); + if (op_ret == -1) { + errno = EINVAL; + goto out; + } + + inode_ctx = (libglusterfs_client_inode_ctx_t *)(long)ptr; + memset (¤t, 0, sizeof (current)); + current = time (NULL); + + pthread_mutex_lock (&inode_ctx->lock); + { + prev = inode_ctx->previous_lookup_time; + } + pthread_mutex_unlock (&inode_ctx->lock); + + if ( (prev >= 0) && ctx->lookup_timeout >= (current - prev)) { + lookup_required = 0; + } + } + + if (lookup_required) { + op_ret = libgf_client_lookup (ctx, &loc, NULL, NULL, NULL); + } + + if (!op_ret) + op_ret = libgf_client_setxattr (ctx, &loc, name, value, size, flags); + + libgf_client_loc_wipe (&loc); +out: + return op_ret; +} + +ssize_t +glusterfs_lgetxattr (libglusterfs_client_ctx_t *ctx, + const char *path, + const char *name, + void *value, + size_t size) +{ + return ENOSYS; +} + +ssize_t +glusterfs_fgetxattr (unsigned long fd, + const char *name, + void *value, + size_t size) +{ + int32_t op_ret = 0; + libglusterfs_client_ctx_t *ctx; + fd_t *__fd = (fd_t *)fd; + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + data_t *fd_ctx_data = NULL; + loc_t loc = {0, }; + dict_t *dict = NULL; + + fd_ctx_data = dict_get (__fd->ctx, XLATOR_NAME); + if (!fd_ctx_data) { + errno = EBADF; + op_ret = -1; + goto out; + } + + fd_ctx = data_to_ptr (fd_ctx_data); + ctx = fd_ctx->ctx; + + op_ret = libgf_client_loc_fill (&loc, NULL, __fd->inode->ino, ctx); + if (op_ret < 0) { + gf_log ("libglusterfsclient", + GF_LOG_ERROR, + "libgf_client_loc_fill returned -1, returning EINVAL"); + errno = EINVAL; + goto out; + } + + op_ret = libgf_client_lookup (ctx, &loc, NULL, &dict, NULL); + if (op_ret == 0) { + data_t *value_data = dict_get (dict, (char *)name); + + if (value_data) { + int32_t copy_len = 0; + op_ret = value_data->len; /* Don't return the value for '\0' */ + + copy_len = size < value_data->len ? size : value_data->len; + memcpy (value, value_data->data, copy_len); + } else { + errno = ENODATA; + op_ret = -1; + } + } + + if (dict) { + dict_unref (dict); + } + + libgf_client_loc_wipe (&loc); + +out: + return op_ret; +} + +ssize_t +glusterfs_listxattr (libglusterfs_client_ctx_t *ctx, + const char *path, + char *list, + size_t size) +{ + return ENOSYS; +} + +ssize_t +glusterfs_llistxattr (libglusterfs_client_ctx_t *ctx, + const char *path, + char *list, + size_t size) +{ + return ENOSYS; +} + +ssize_t +glusterfs_flistxattr (unsigned long fd, + char *list, + size_t size) +{ + return ENOSYS; +} + +int +glusterfs_removexattr (libglusterfs_client_ctx_t *ctx, + const char *path, + const char *name) +{ + return ENOSYS; +} + +int +glusterfs_lremovexattr (libglusterfs_client_ctx_t *ctx, + const char *path, + const char *name) +{ + return ENOSYS; +} + +int +glusterfs_fremovexattr (unsigned long fd, + const char *name) +{ + return ENOSYS; +} + +int32_t +libgf_client_readv_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct iovec *vector, + int32_t count, + struct stat *stbuf) +{ + libgf_client_local_t *local = frame->local; + + local->reply_stub = fop_readv_cbk_stub (frame, NULL, op_ret, op_errno, vector, count, stbuf); + + pthread_mutex_lock (&local->lock); + { + local->complete = 1; + pthread_cond_broadcast (&local->reply_cond); + } + pthread_mutex_unlock (&local->lock); + + return 0; +} + +int +libgf_client_read (libglusterfs_client_ctx_t *ctx, + fd_t *fd, + void *buf, + size_t size, + off_t offset) +{ + call_stub_t *stub; + struct iovec *vector; + int32_t op_ret = -1; + int count = 0; + libgf_client_local_t *local = NULL; + + LIBGF_CLIENT_FOP (ctx, stub, readv, local, fd, size, offset); + + op_ret = stub->args.readv_cbk.op_ret; + errno = stub->args.readv_cbk.op_errno; + count = stub->args.readv_cbk.count; + vector = stub->args.readv_cbk.vector; + if (op_ret > 0) { + int i = 0; + op_ret = 0; + while (size && (i < count)) { + int len = (size < vector[i].iov_len) ? size : vector[i].iov_len; + memcpy (buf, vector[i++].iov_base, len); + buf += len; + size -= len; + op_ret += len; + } + } + + call_stub_destroy (stub); + return op_ret; +} + +ssize_t +glusterfs_read (unsigned long fd, + void *buf, + size_t nbytes) +{ + int32_t op_ret = -1; + off_t offset = 0; + libglusterfs_client_ctx_t *ctx = NULL; + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + data_t *fd_ctx_data = NULL; + + if (fd == 0) { + errno = EINVAL; + goto out; + } + + fd_ctx_data = dict_get (((fd_t *) fd)->ctx, XLATOR_NAME); + if (!fd_ctx_data) { + errno = EBADF; + goto out; + } + + fd_ctx = data_to_ptr (fd_ctx_data); + + pthread_mutex_lock (&fd_ctx->lock); + { + ctx = fd_ctx->ctx; + offset = fd_ctx->offset; + } + pthread_mutex_unlock (&fd_ctx->lock); + + op_ret = libgf_client_read (ctx, (fd_t *)fd, buf, nbytes, offset); + + if (op_ret > 0) { + offset += op_ret; + pthread_mutex_lock (&fd_ctx->lock); + { + fd_ctx->offset = offset; + } + pthread_mutex_unlock (&fd_ctx->lock); + } + +out: + return op_ret; +} + + +ssize_t +libgf_client_readv (libglusterfs_client_ctx_t *ctx, + fd_t *fd, + const struct iovec *dst_vector, + int dst_count, + off_t offset) +{ + call_stub_t *stub = NULL; + struct iovec *src_vector; + int src_count = 0; + int32_t op_ret = -1; + libgf_client_local_t *local = NULL; + size_t size = 0; + int32_t i = 0; + + for (i = 0; i < dst_count; i++) + { + size += dst_vector[i].iov_len; + } + + LIBGF_CLIENT_FOP (ctx, stub, readv, local, fd, size, offset); + + op_ret = stub->args.readv_cbk.op_ret; + errno = stub->args.readv_cbk.op_errno; + src_count = stub->args.readv_cbk.count; + src_vector = stub->args.readv_cbk.vector; + if (op_ret > 0) { + int src = 0, dst = 0; + off_t src_offset = 0, dst_offset = 0; + op_ret = 0; + + while ((size != 0) && (dst < dst_count) && (src < src_count)) { + int len = 0, src_len, dst_len; + + src_len = src_vector[src].iov_len - src_offset; + dst_len = dst_vector[dst].iov_len - dst_offset; + + len = (src_len < dst_len) ? src_len : dst_len; + if (len > size) { + len = size; + } + + memcpy (dst_vector[dst].iov_base + dst_offset, + src_vector[src].iov_base + src_offset, len); + + size -= len; + src_offset += len; + dst_offset += len; + + if (src_offset == src_vector[src].iov_len) { + src_offset = 0; + src++; + } + + if (dst_offset == dst_vector[dst].iov_len) { + dst_offset = 0; + dst++; + } + } + } + + call_stub_destroy (stub); + return op_ret; +} + + +ssize_t +glusterfs_readv (unsigned long fd, const struct iovec *vec, int count) +{ + int32_t op_ret = -1; + off_t offset = 0; + libglusterfs_client_ctx_t *ctx = NULL; + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + data_t *fd_ctx_data = NULL; + + if (!fd) { + errno = EINVAL; + goto out; + } + + fd_ctx_data = dict_get (((fd_t *) fd)->ctx, XLATOR_NAME); + if (!fd_ctx_data) { + errno = EBADF; + goto out; + } + + fd_ctx = data_to_ptr (fd_ctx_data); + + pthread_mutex_lock (&fd_ctx->lock); + { + ctx = fd_ctx->ctx; + offset = fd_ctx->offset; + } + pthread_mutex_unlock (&fd_ctx->lock); + + op_ret = libgf_client_readv (ctx, (fd_t *)fd, vec, count, offset); + + if (op_ret > 0) { + offset += op_ret; + pthread_mutex_lock (&fd_ctx->lock); + { + fd_ctx->offset = offset; + } + pthread_mutex_unlock (&fd_ctx->lock); + } + +out: + return op_ret; +} + + +ssize_t +glusterfs_pread (unsigned long fd, + void *buf, + size_t count, + off_t offset) +{ + int32_t op_ret = -1; + libglusterfs_client_ctx_t *ctx = NULL; + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + data_t *fd_ctx_data = NULL; + + if (!fd) { + errno = EINVAL; + goto out; + } + + fd_ctx_data = dict_get (((fd_t *) fd)->ctx, XLATOR_NAME); + if (!fd_ctx_data) { + errno = EBADF; + goto out; + } + + fd_ctx = data_to_ptr (fd_ctx_data); + + ctx = fd_ctx->ctx; + + op_ret = libgf_client_read (ctx, (fd_t *)fd, buf, count, offset); + +out: + return op_ret; +} + + +int +libgf_client_writev_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *stbuf) +{ + libgf_client_local_t *local = frame->local; + + local->reply_stub = fop_writev_cbk_stub (frame, NULL, op_ret, op_errno, stbuf); + + pthread_mutex_lock (&local->lock); + { + local->complete = 1; + pthread_cond_broadcast (&local->reply_cond); + } + pthread_mutex_unlock (&local->lock); + return 0; +} + +int +libgf_client_writev (libglusterfs_client_ctx_t *ctx, + fd_t *fd, + struct iovec *vector, + int count, + off_t offset) +{ + call_stub_t *stub = NULL; + int op_ret = -1; + libgf_client_local_t *local = NULL; + + LIBGF_CLIENT_FOP (ctx, stub, writev, local, fd, vector, count, offset); + + op_ret = stub->args.writev_cbk.op_ret; + errno = stub->args.writev_cbk.op_errno; + + call_stub_destroy (stub); + return op_ret; +} + + +ssize_t +glusterfs_write (unsigned long fd, + const void *buf, + size_t n) +{ + int32_t op_ret = -1; + off_t offset = 0; + struct iovec vector; + libglusterfs_client_ctx_t *ctx = NULL; + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + data_t *fd_ctx_data = NULL; + + if (!fd) { + errno = EINVAL; + goto out; + } + + fd_ctx_data = dict_get (((fd_t *) fd)->ctx, XLATOR_NAME); + if (!fd_ctx_data) { + errno = EBADF; + goto out; + } + + fd_ctx = data_to_ptr (fd_ctx_data); + + ctx = fd_ctx->ctx; + + pthread_mutex_lock (&fd_ctx->lock); + { + offset = fd_ctx->offset; + } + pthread_mutex_unlock (&fd_ctx->lock); + + vector.iov_base = (void *)buf; + vector.iov_len = n; + + op_ret = libgf_client_writev (ctx, + (fd_t *)fd, + &vector, + 1, + offset); + + if (op_ret >= 0) { + offset += op_ret; + pthread_mutex_lock (&fd_ctx->lock); + { + fd_ctx->offset = offset; + } + pthread_mutex_unlock (&fd_ctx->lock); + } + +out: + return op_ret; +} + +ssize_t +glusterfs_writev (unsigned long fd, + const struct iovec *vector, + size_t count) +{ + int32_t op_ret = -1; + off_t offset = 0; + libglusterfs_client_ctx_t *ctx = NULL; + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + data_t *fd_ctx_data = NULL; + + if (!fd) { + errno = EINVAL; + goto out; + } + + + fd_ctx_data = dict_get (((fd_t *) fd)->ctx, XLATOR_NAME); + if (!fd_ctx_data) { + errno = EBADF; + goto out; + } + + fd_ctx = data_to_ptr (fd_ctx_data); + + ctx = fd_ctx->ctx; + + pthread_mutex_lock (&fd_ctx->lock); + { + offset = fd_ctx->offset; + } + pthread_mutex_unlock (&fd_ctx->lock); + + + op_ret = libgf_client_writev (ctx, + (fd_t *)fd, + (struct iovec *)vector, + count, + offset); + + if (op_ret >= 0) { + offset += op_ret; + pthread_mutex_lock (&fd_ctx->lock); + { + fd_ctx->offset = offset; + } + pthread_mutex_unlock (&fd_ctx->lock); + } + +out: + return op_ret; +} + + +ssize_t +glusterfs_pwrite (unsigned long fd, + const void *buf, + size_t count, + off_t offset) +{ + int32_t op_ret = -1; + struct iovec vector; + libglusterfs_client_ctx_t *ctx = NULL; + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + data_t *fd_ctx_data = NULL; + + if (!fd) { + errno = EINVAL; + goto out; + } + + fd_ctx_data = dict_get (((fd_t *) fd)->ctx, XLATOR_NAME); + if (!fd_ctx_data) { + errno = EBADF; + goto out; + } + + fd_ctx = data_to_ptr (fd_ctx_data); + + ctx = fd_ctx->ctx; + + vector.iov_base = (void *)buf; + vector.iov_len = count; + + op_ret = libgf_client_writev (ctx, + (fd_t *)fd, + &vector, + 1, + offset); + +out: + return op_ret; +} + + +int32_t +libgf_client_readdir_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + gf_dirent_t *entries) +{ + libgf_client_local_t *local = frame->local; + + local->reply_stub = fop_readdir_cbk_stub (frame, NULL, op_ret, op_errno, entries); + + pthread_mutex_lock (&local->lock); + { + local->complete = 1; + pthread_cond_broadcast (&local->reply_cond); + } + pthread_mutex_unlock (&local->lock); + return 0; +} + +int +libgf_client_readdir (libglusterfs_client_ctx_t *ctx, + fd_t *fd, + struct dirent *dirp, + size_t size, + off_t *offset, + int32_t num_entries) +{ + call_stub_t *stub = NULL; + int op_ret = -1; + libgf_client_local_t *local = NULL; + gf_dirent_t *entry = NULL; + int32_t count = 0; + size_t entry_size = 0; + + LIBGF_CLIENT_FOP (ctx, stub, readdir, local, fd, size, *offset); + + op_ret = stub->args.readdir_cbk.op_ret; + errno = stub->args.readdir_cbk.op_errno; + + if (op_ret > 0) { + list_for_each_entry (entry, &stub->args.readdir_cbk.entries.list, list) { + entry_size = offsetof (struct dirent, d_name) + strlen (entry->d_name) + 1; + + if ((size < entry_size) || (count == num_entries)) { + break; + } + + size -= entry_size; + + dirp->d_ino = entry->d_ino; + /* + #ifdef GF_DARWIN_HOST_OS + dirp->d_off = entry->d_seekoff; + #endif + #ifdef GF_LINUX_HOST_OS + dirp->d_off = entry->d_off; + #endif + */ + + *offset = dirp->d_off = entry->d_off; + /* dirp->d_type = entry->d_type; */ + dirp->d_reclen = entry->d_len; + strncpy (dirp->d_name, entry->d_name, dirp->d_reclen); + dirp->d_name[dirp->d_reclen] = '\0'; + + dirp = (struct dirent *) (((char *) dirp) + entry_size); + count++; + } + } + + call_stub_destroy (stub); + return op_ret; +} + +int +glusterfs_readdir (unsigned long fd, + struct dirent *dirp, + unsigned int count) +{ + int op_ret = -1; + libglusterfs_client_ctx_t *ctx = NULL; + off_t offset = 0; + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + data_t *fd_ctx_data = NULL; + + fd_ctx_data = dict_get (((fd_t *) fd)->ctx, XLATOR_NAME); + if (!fd_ctx_data) { + errno = EBADF; + goto out; + } + + fd_ctx = data_to_ptr (fd_ctx_data); + + pthread_mutex_lock (&fd_ctx->lock); + { + ctx = fd_ctx->ctx; + offset = fd_ctx->offset; + } + pthread_mutex_unlock (&fd_ctx->lock); + + op_ret = libgf_client_readdir (ctx, (fd_t *)fd, dirp, sizeof (*dirp), &offset, 1); + + if (op_ret > 0) { + pthread_mutex_lock (&fd_ctx->lock); + { + fd_ctx->offset = offset; + } + pthread_mutex_unlock (&fd_ctx->lock); + op_ret = 1; + } + +out: + return op_ret; +} + + +int +glusterfs_getdents (unsigned long fd, struct dirent *dirp, unsigned int count) +{ + int op_ret = -1; + libglusterfs_client_ctx_t *ctx = NULL; + off_t offset = 0; + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + data_t *fd_ctx_data = NULL; + + fd_ctx_data = dict_get (((fd_t *) fd)->ctx, XLATOR_NAME); + if (!fd_ctx_data) { + errno = EBADF; + goto out; + } + + fd_ctx = data_to_ptr (fd_ctx_data); + + pthread_mutex_lock (&fd_ctx->lock); + { + ctx = fd_ctx->ctx; + offset = fd_ctx->offset; + } + pthread_mutex_unlock (&fd_ctx->lock); + + op_ret = libgf_client_readdir (ctx, (fd_t *)fd, dirp, count, &offset, -1); + + if (op_ret > 0) { + pthread_mutex_lock (&fd_ctx->lock); + { + fd_ctx->offset = offset; + } + pthread_mutex_unlock (&fd_ctx->lock); + } + +out: + return op_ret; +} + + +static int32_t +libglusterfs_readv_async_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct iovec *vector, + int32_t count, + struct stat *stbuf) +{ + glusterfs_read_buf_t *buf; + libglusterfs_client_async_local_t *local = frame->local; + fd_t *__fd = local->fop.readv_cbk.fd; + glusterfs_readv_cbk_t readv_cbk = local->fop.readv_cbk.cbk; + + buf = CALLOC (1, sizeof (*buf)); + ERR_ABORT (buf); + + if (vector) { + buf->vector = iov_dup (vector, count); + } + + buf->count = count; + buf->op_ret = op_ret; + buf->op_errno = op_errno; + + if (frame->root->rsp_refs) { + buf->ref = dict_ref (frame->root->rsp_refs); + } + + if (op_ret > 0) { + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + data_t *fd_ctx_data = NULL; + + fd_ctx_data = dict_get (__fd->ctx, XLATOR_NAME); + + fd_ctx = data_to_ptr (fd_ctx_data); + pthread_mutex_lock (&fd_ctx->lock); + { + fd_ctx->offset += op_ret; + } + pthread_mutex_unlock (&fd_ctx->lock); + } + + readv_cbk (buf, local->cbk_data); + + FREE (local); + frame->local = NULL; + STACK_DESTROY (frame->root); + + return 0; +} + +void +glusterfs_free (glusterfs_read_buf_t *buf) +{ + //iov_free (buf->vector, buf->count); + FREE (buf->vector); + dict_unref ((dict_t *) buf->ref); + FREE (buf); +} + +int +glusterfs_read_async (unsigned long fd, + size_t nbytes, + off_t offset, + glusterfs_readv_cbk_t readv_cbk, + void *cbk_data) +{ + libglusterfs_client_ctx_t *ctx; + fd_t *__fd = (fd_t *)fd; + libglusterfs_client_async_local_t *local = NULL; + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + data_t *fd_ctx_data = NULL; + int32_t op_ret = 0; + + local = CALLOC (1, sizeof (*local)); + ERR_ABORT (local); + local->fop.readv_cbk.fd = __fd; + local->fop.readv_cbk.cbk = readv_cbk; + local->cbk_data = cbk_data; + + fd_ctx_data = dict_get (((fd_t *) fd)->ctx, XLATOR_NAME); + if (!fd_ctx_data) { + errno = EBADF; + op_ret = -1; + goto out; + } + + fd_ctx = data_to_ptr (fd_ctx_data); + + ctx = fd_ctx->ctx; + + if (offset < 0) { + pthread_mutex_lock (&fd_ctx->lock); + { + offset = fd_ctx->offset; + } + pthread_mutex_unlock (&fd_ctx->lock); + } + + LIBGF_CLIENT_FOP_ASYNC (ctx, + local, + libglusterfs_readv_async_cbk, + readv, + __fd, + nbytes, + offset); + +out: + return op_ret; +} + +static int32_t +libglusterfs_writev_async_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *stbuf) +{ + libglusterfs_client_async_local_t *local = frame->local; + fd_t *fd = NULL; + glusterfs_writev_cbk_t writev_cbk; + + writev_cbk = local->fop.writev_cbk.cbk; + fd = local->fop.writev_cbk.fd; + + if (op_ret > 0) { + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + data_t *fd_ctx_data = NULL; + + fd_ctx_data = dict_get (fd->ctx, XLATOR_NAME); + + fd_ctx = data_to_ptr (fd_ctx_data); + + pthread_mutex_lock (&fd_ctx->lock); + { + fd_ctx->offset += op_ret; + } + pthread_mutex_unlock (&fd_ctx->lock); + } + + writev_cbk (op_ret, op_errno, local->cbk_data); + + STACK_DESTROY (frame->root); + return 0; +} + +int32_t +glusterfs_write_async (unsigned long fd, + const void *buf, + size_t nbytes, + off_t offset, + glusterfs_writev_cbk_t writev_cbk, + void *cbk_data) +{ + fd_t *__fd = (fd_t *)fd; + struct iovec vector; + off_t __offset = offset; + libglusterfs_client_ctx_t *ctx = NULL; + libglusterfs_client_async_local_t *local = NULL; + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + data_t *fd_ctx_data = NULL; + int32_t op_ret = 0; + + local = CALLOC (1, sizeof (*local)); + ERR_ABORT (local); + local->fop.writev_cbk.fd = __fd; + local->fop.writev_cbk.cbk = writev_cbk; + local->cbk_data = cbk_data; + + vector.iov_base = (void *)buf; + vector.iov_len = nbytes; + + fd_ctx_data = dict_get (__fd->ctx, XLATOR_NAME); + if (!fd_ctx_data) { + errno = EBADF; + op_ret = -1; + goto out; + } + + fd_ctx = data_to_ptr (fd_ctx_data); + ctx = fd_ctx->ctx; + + if (offset < 0) { + pthread_mutex_lock (&fd_ctx->lock); + { + __offset = fd_ctx->offset; + } + pthread_mutex_unlock (&fd_ctx->lock); + } + + LIBGF_CLIENT_FOP_ASYNC (ctx, + local, + libglusterfs_writev_async_cbk, + writev, + __fd, + &vector, + 1, + __offset); + +out: + return op_ret; +} + +off_t +glusterfs_lseek (unsigned long fd, off_t offset, int whence) +{ + off_t __offset = 0; + int32_t op_ret = -1; + fd_t *__fd = (fd_t *)fd; + data_t *fd_ctx_data = NULL; + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + libglusterfs_client_inode_ctx_t *inode_ctx = NULL; + libglusterfs_client_ctx_t *ctx = NULL; + xlator_t *this = NULL; + + fd_ctx_data = dict_get (__fd->ctx, XLATOR_NAME); + if (!fd_ctx_data) { + errno = EBADFD; + __offset = -1; + goto out; + } + + fd_ctx = data_to_ptr (fd_ctx_data); + ctx = fd_ctx->ctx; + + switch (whence) + { + case SEEK_SET: + __offset = offset; + break; + + case SEEK_CUR: + pthread_mutex_lock (&fd_ctx->lock); + { + __offset = fd_ctx->offset; + } + pthread_mutex_unlock (&fd_ctx->lock); + + __offset += offset; + break; + + case SEEK_END: + { + char cache_valid = 0; + off_t end = 0; + time_t prev, current; + loc_t loc = {0, }; + struct stat stbuf = {0, }; + int32_t ret = -1; + uint64_t ptr = 0; + + ret = inode_ctx_get (__fd->inode, this, &ptr); + if (ret == 0) { + inode_ctx = (libglusterfs_client_inode_ctx_t *)(long)ptr; + memset (¤t, 0, sizeof (current)); + current = time (NULL); + + pthread_mutex_lock (&inode_ctx->lock); + { + prev = inode_ctx->previous_lookup_time; + } + pthread_mutex_unlock (&inode_ctx->lock); + + if (prev >= 0 && ctx->lookup_timeout >= (current - prev)) { + cache_valid = 1; + } + } + + if (cache_valid) { + end = inode_ctx->stbuf.st_size; + } else { + op_ret = libgf_client_loc_fill (&loc, NULL, __fd->inode->ino, ctx); + if (op_ret < 0) { + gf_log ("libglusterfsclient", + GF_LOG_ERROR, + "libgf_client_loc_fill returned -1, returning EINVAL"); + errno = EINVAL; + __offset = -1; + goto out; + } + + op_ret = libgf_client_lookup (ctx, &loc, &stbuf, NULL, NULL); + if (op_ret < 0) { + __offset = -1; + goto out; + } + + end = stbuf.st_size; + } + + __offset = end + offset; + } + break; + + default: + gf_log ("libglusterfsclient", + GF_LOG_ERROR, + "invalid value for whence"); + __offset = -1; + errno = EINVAL; + goto out; + } + + pthread_mutex_lock (&fd_ctx->lock); + { + fd_ctx->offset = __offset; + } + pthread_mutex_unlock (&fd_ctx->lock); + +out: + return __offset; +} + + +int32_t +libgf_client_stat_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *buf) +{ + libgf_client_local_t *local = frame->local; + + local->reply_stub = fop_stat_cbk_stub (frame, + NULL, + op_ret, + op_errno, + buf); + + pthread_mutex_lock (&local->lock); + { + local->complete = 1; + pthread_cond_broadcast (&local->reply_cond); + } + pthread_mutex_unlock (&local->lock); + + return 0; +} + +int32_t +libgf_client_stat (libglusterfs_client_ctx_t *ctx, + loc_t *loc, + struct stat *stbuf) +{ + call_stub_t *stub = NULL; + int32_t op_ret = 0; + time_t prev, current; + libglusterfs_client_inode_ctx_t *inode_ctx = NULL; + libgf_client_local_t *local = NULL; + xlator_t *this = NULL; + uint64_t ptr = 0; + + this = ctx->gf_ctx.graph; + op_ret = inode_ctx_get (loc->inode, this, &ptr); + if (op_ret == -1) { + errno = EINVAL; + goto out; + } + + inode_ctx = (libglusterfs_client_inode_ctx_t *)(long)ptr; + current = time (NULL); + pthread_mutex_lock (&inode_ctx->lock); + { + prev = inode_ctx->previous_lookup_time; + } + pthread_mutex_unlock (&inode_ctx->lock); + + if ((current - prev) <= ctx->stat_timeout) { + pthread_mutex_lock (&inode_ctx->lock); + { + memcpy (stbuf, &inode_ctx->stbuf, sizeof (*stbuf)); + } + pthread_mutex_unlock (&inode_ctx->lock); + op_ret = 0; + goto out; + } + + LIBGF_CLIENT_FOP (ctx, stub, stat, local, loc); + + op_ret = stub->args.stat_cbk.op_ret; + errno = stub->args.stat_cbk.op_errno; + *stbuf = stub->args.stat_cbk.buf; + + pthread_mutex_lock (&inode_ctx->lock); + { + memcpy (&inode_ctx->stbuf, stbuf, sizeof (*stbuf)); + current = time (NULL); + inode_ctx->previous_stat_time = current; + } + pthread_mutex_unlock (&inode_ctx->lock); + + call_stub_destroy (stub); + +out: + return op_ret; +} + +int32_t +glusterfs_stat (libglusterfs_handle_t handle, + const char *path, + struct stat *buf) +{ + int32_t op_ret = 0; + loc_t loc = {0, }; + char lookup_required = 1; + libglusterfs_client_ctx_t *ctx = handle; + xlator_t *this = NULL; + + op_ret = libgf_client_loc_fill (&loc, path, 0, ctx); + if (op_ret < 0) { + gf_log ("libglusterfsclient", + GF_LOG_ERROR, + "libgf_client_loc_fill returned -1, returning EINVAL"); + errno = EINVAL; + goto out; + } + + this = ctx->gf_ctx.graph; + if (loc.inode) { + time_t current, prev; + libglusterfs_client_inode_ctx_t *inode_ctx = NULL; + uint64_t ptr = 0; + + op_ret = inode_ctx_get (loc.inode, this, &ptr); + if (op_ret == -1) { + inode_unref (loc.inode); + errno = EINVAL; + goto out; + } + + inode_ctx = (libglusterfs_client_inode_ctx_t *)(long)ptr; + memset (¤t, 0, sizeof (current)); + current = time (NULL); + + pthread_mutex_lock (&inode_ctx->lock); + { + prev = inode_ctx->previous_lookup_time; + } + pthread_mutex_unlock (&inode_ctx->lock); + + if (prev >= 0 && ctx->lookup_timeout >= (current - prev)) { + lookup_required = 0; + } + } + + if (lookup_required) { + op_ret = libgf_client_lookup (ctx, &loc, buf, NULL, NULL); + } + + if (!op_ret) { + op_ret = libgf_client_stat (ctx, &loc, buf); + } + + libgf_client_loc_wipe (&loc); + +out: + return op_ret; +} + +static int32_t +libgf_client_fstat_cbk (call_frame_t *frame, + void *cookie, + xlator_t *this, + int32_t op_ret, + int32_t op_errno, + struct stat *buf) +{ + libgf_client_local_t *local = frame->local; + + local->reply_stub = fop_fstat_cbk_stub (frame, + NULL, + op_ret, + op_errno, + buf); + + pthread_mutex_lock (&local->lock); + { + local->complete = 1; + pthread_cond_broadcast (&local->reply_cond); + } + pthread_mutex_unlock (&local->lock); + + return 0; + +} + +int32_t +libgf_client_fstat (libglusterfs_client_ctx_t *ctx, + fd_t *fd, + struct stat *buf) +{ + call_stub_t *stub = NULL; + int32_t op_ret = 0; + fd_t *__fd = fd; + time_t current, prev; + libglusterfs_client_inode_ctx_t *inode_ctx = NULL; + libgf_client_local_t *local = NULL; + xlator_t *this = NULL; + uint64_t ptr = 0; + + current = time (NULL); + op_ret = inode_ctx_get (fd->inode, this, &ptr); + if (op_ret == -1) { + errno = EINVAL; + goto out; + } + + inode_ctx = (libglusterfs_client_inode_ctx_t *)(long)ptr; + pthread_mutex_lock (&inode_ctx->lock); + { + prev = inode_ctx->previous_stat_time; + } + pthread_mutex_unlock (&inode_ctx->lock); + + if ((current - prev) <= ctx->stat_timeout) { + pthread_mutex_lock (&inode_ctx->lock); + { + memcpy (buf, &inode_ctx->stbuf, sizeof (*buf)); + } + pthread_mutex_unlock (&inode_ctx->lock); + op_ret = 0; + goto out; + } + + LIBGF_CLIENT_FOP (ctx, stub, fstat, local, __fd); + + op_ret = stub->args.fstat_cbk.op_ret; + errno = stub->args.fstat_cbk.op_errno; + *buf = stub->args.fstat_cbk.buf; + + pthread_mutex_lock (&inode_ctx->lock); + { + memcpy (&inode_ctx->stbuf, buf, sizeof (*buf)); + current = time (NULL); + inode_ctx->previous_stat_time = current; + } + pthread_mutex_unlock (&inode_ctx->lock); + + call_stub_destroy (stub); + +out: + return op_ret; +} + +int32_t +glusterfs_fstat (unsigned long fd, struct stat *buf) +{ + libglusterfs_client_ctx_t *ctx; + fd_t *__fd = (fd_t *)fd; + libglusterfs_client_fd_ctx_t *fd_ctx = NULL; + data_t *fd_ctx_data = NULL; + int32_t op_ret = -1; + + fd_ctx_data = dict_get (((fd_t *) fd)->ctx, XLATOR_NAME); + if (!fd_ctx_data) { + errno = EBADF; + op_ret = -1; + goto out; + } + + fd_ctx = data_to_ptr (fd_ctx_data); + ctx = fd_ctx->ctx; + + op_ret = libgf_client_fstat (ctx, __fd, buf); + +out: + return op_ret; +} + +static struct xlator_fops libgf_client_fops = { +}; + +static struct xlator_mops libgf_client_mops = { +}; + +static struct xlator_cbks libgf_client_cbks = { + .forget = libgf_client_forget, + .release = libgf_client_release, + .releasedir = libgf_client_releasedir, +}; + +static inline xlator_t * +libglusterfs_graph (xlator_t *graph) +{ + xlator_t *top = NULL; + xlator_list_t *xlchild, *xlparent; + + top = CALLOC (1, sizeof (*top)); + ERR_ABORT (top); + + xlchild = CALLOC (1, sizeof(*xlchild)); + ERR_ABORT (xlchild); + xlchild->xlator = graph; + top->children = xlchild; + top->ctx = graph->ctx; + top->next = graph; + top->name = strdup (XLATOR_NAME); + + xlparent = CALLOC (1, sizeof(*xlparent)); + xlparent->xlator = top; + graph->parents = xlparent; + asprintf (&top->type, XLATOR_NAME); + + top->init = libgf_client_init; + top->fops = &libgf_client_fops; + top->mops = &libgf_client_mops; + top->cbks = &libgf_client_cbks; + top->notify = libgf_client_notify; + top->fini = libgf_client_fini; + // fill_defaults (top); + + return top; +} diff --git a/libglusterfsclient/src/libglusterfsclient.h b/libglusterfsclient/src/libglusterfsclient.h new file mode 100755 index 00000000000..19b7ea0361c --- /dev/null +++ b/libglusterfsclient/src/libglusterfsclient.h @@ -0,0 +1,279 @@ +/* + Copyright (c) 2008 Z RESEARCH, Inc. <http://www.zresearch.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/>. +*/ + +#ifndef __LIBGLUSTERFSCLIENT_H +#define __LIBGLUSTERFSCLIENT_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include <sys/types.h> +#include <sys/stat.h> + //#include <unistd.h> +#include <dirent.h> +#include <errno.h> +/* #include <logging.h> */ + +typedef struct { + int op_ret; + int op_errno; + struct iovec *vector; + int count; + void *ref; +}glusterfs_read_buf_t; + + +typedef struct { + char *logfile; + char *loglevel; + struct { + char *specfile; + FILE *specfp; + }; + char *volume_name; + unsigned long lookup_timeout; + unsigned long stat_timeout; +}glusterfs_init_ctx_t; + +typedef struct libglusterfs_client_ctx *libglusterfs_handle_t; + +typedef int (*glusterfs_readv_cbk_t) (glusterfs_read_buf_t *buf, + void *cbk_data); + +typedef int (*glusterfs_writev_cbk_t) (int op_ret, + int op_errno, + void *cbk_data); + +typedef int (*glusterfs_lookup_cbk_t) (int op_ret, + int op_errno, + void *buf, + struct stat *st, + void *cbk_data); + +/* Used to free the glusterfs_read_buf passed to the application from glusterfs_read_async_cbk */ +void +glusterfs_free (glusterfs_read_buf_t *buf); + +/* libglusterfsclient initialization function */ +libglusterfs_handle_t +glusterfs_init (glusterfs_init_ctx_t *ctx); + +int +glusterfs_fini (libglusterfs_handle_t handle); + +/* added for log related initialization for fork implementation in booster */ +void +glusterfs_reset (void); + +void +glusterfs_log_lock (void); + +void +glusterfs_log_unlock (void); + +/* For smaller files, application can use just glusterfs_lookup/glusterfs_lookup_async to read + * the whole content. Limit of the file-sizes to be read in + * glusterfs_lookup/glusterfs_lookup_async is passed in the size argument */ + +/* glusterfs_lookup: + * @handle: glusterfs handle + * @path: path to be looked upon + * @buf: pointer to pre-allocated buf, in which the file content is returned for files with sizes * less than the size argument. + * @size: upper limit of file-sizes to be read in lookup + * @stbuf: stat buffer + */ + +int +glusterfs_lookup (libglusterfs_handle_t handle, + const char *path, + void *buf, + size_t size, + struct stat *stbuf); + +int +glusterfs_lookup_async (libglusterfs_handle_t handle, + const char *path, + void *buf, + size_t size, + glusterfs_lookup_cbk_t cbk, + void *cbk_data); + +unsigned long +glusterfs_open (libglusterfs_handle_t handle, + const char *path, + int flags, + mode_t mode); + +unsigned long +glusterfs_creat (libglusterfs_handle_t handle, + const char *path, + mode_t mode); + +int +glusterfs_close (unsigned long fd); + +int +glusterfs_stat (libglusterfs_handle_t handle, + const char *path, + struct stat *buf); + +int +glusterfs_fstat (unsigned long fd, + struct stat *buf) ; + +int +glusterfs_setxattr (libglusterfs_handle_t handle, + const char *path, + const char *name, + const void *value, + size_t size, + int flags); + +int +glusterfs_lsetxattr (libglusterfs_handle_t handle, + const char *path, + const char *name, + const void *value, + size_t size, + int flags); + +int +glusterfs_fsetxattr (unsigned long fd, + const char *name, + const void *value, + size_t size, + int flags); + +ssize_t +glusterfs_getxattr (libglusterfs_handle_t handle, + const char *path, + const char *name, + void *value, + size_t size); + +ssize_t +glusterfs_lgetxattr (libglusterfs_handle_t handle, + const char *path, + const char *name, + void *value, + size_t size); + +ssize_t +glusterfs_fgetxattr (unsigned long fd, + const char *name, + void *value, + size_t size); + +ssize_t +glusterfs_listxattr (libglusterfs_handle_t handle, + const char *path, + char *list, + size_t size); + +ssize_t +glusterfs_llistxattr (libglusterfs_handle_t handle, + const char *path, + char *list, + size_t size); + +ssize_t +glusterfs_flistxattr (unsigned long fd, + char *list, + size_t size); + +int +glusterfs_removexattr (libglusterfs_handle_t handle, + const char *path, + const char *name); + +int +glusterfs_lremovexattr (libglusterfs_handle_t handle, + const char *path, + const char *name); + +int +glusterfs_fremovexattr (unsigned long fd, + const char *name); + +ssize_t +glusterfs_read (unsigned long fd, + void *buf, + size_t nbytes); + +ssize_t +glusterfs_readv (unsigned long fd, + const struct iovec *vec, + int count); + +int +glusterfs_read_async (unsigned long fd, + size_t nbytes, + off_t offset, + glusterfs_readv_cbk_t readv_cbk, + void *cbk_data); + +ssize_t +glusterfs_write (unsigned long fd, + const void *buf, + size_t n); + +ssize_t +glusterfs_writev (unsigned long fd, + const struct iovec *vector, + size_t count); + +int +glusterfs_write_async (unsigned long fd, + const void *buf, + size_t nbytes, + off_t offset, + glusterfs_writev_cbk_t writev_cbk, + void *cbk_data); + +int +glusterfs_readdir (unsigned long fd, + struct dirent *dirp, + unsigned int count); + +int +glusterfs_getdents (unsigned long fd, + struct dirent *dirp, + unsigned int count); + +ssize_t +glusterfs_pread (unsigned long fd, + void *buf, + size_t count, + off_t offset); + +ssize_t +glusterfs_pwrite (unsigned long fd, + const void *buf, + size_t count, + off_t offset); + +off_t +glusterfs_lseek (unsigned long fd, off_t offset, int whence); + +#ifdef __cplusplus +} +#endif + +#endif |