+++ /dev/null
-/*
- Unix SMB/CIFS implementation.
- Integration of a glib g_main_context into a tevent_context
- Copyright (C) Stefan Metzmacher 2016
- Copyright (C) Ralph Boehme 2016
-
- ** NOTE! The following LGPL license applies to the tevent
- ** library. This does NOT imply that all of Samba is released
- ** under the LGPL
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 3 of the License, or (at your option) any later version.
-
- This library 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "replace.h"
-#include "system/filesys.h"
-#include "lib/util/debug.h"
-#include "lib/util/select.h"
-#include <tevent.h>
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_TEVENT
-
-#ifdef HAVE_GLIB
-#include <glib.h>
-#include "tevent_glib_glue.h"
-
-struct fd_map {
- struct tevent_glib_glue *glue;
- int fd;
- struct tevent_fd *fd_event;
-};
-
-struct tevent_glib_glue {
- /*
- * The tevent context we're feeding.
- */
- struct tevent_context *ev;
-
- /*
- * The glib gmain context we're polling and whether we're currently
- * owning it by virtue of g_main_context_acquire().
- */
- GMainContext *gmain_ctx;
- bool gmain_owner;
-
- /*
- * Set by samba_tevent_glib_glue_quit().
- */
- bool quit;
-
- /*
- * tevent trace callback and data we got from tevent_get_trace_callback()
- * before installing our own trace callback.
- */
- tevent_trace_callback_t prev_tevent_trace_cb;
- void *prev_tevent_trace_data;
-
- /*
- * Don't call tevent_glib_prepare() in the tevent tracepoint handler if
- * explicitly told so. This is an optimisation for the case that glib
- * event sources are created from glib event callbacks.
- */
- bool skip_glib_refresh;
-
- /*
- * Used when acquiring the glib gmain context failed.
- */
- struct tevent_timer *acquire_retry_timer;
-
- /*
- * glib gmain context timeout and priority for the current event look
- * iteration. gtimeout is translated to a tevent timer event, unless it
- * is 0 which signals some event source is pending. In that case we
- * dispatch an immediate event. gpriority is ignored by us, just passed
- * to the glib relevant functions.
- */
- gint gtimeout;
- gint gpriority;
- struct tevent_timer *timer;
- struct tevent_immediate *im;
- bool scheduled_im;
-
- /*
- * glib gmain context fds returned from g_main_context_query(). These
- * get translated to tevent fd events.
- */
- GPollFD *gpollfds;
- gint num_gpollfds;
-
- /*
- * A copy of gpollfds and num_gpollfds from the previous event loop
- * iteration, used to detect changes in the set of fds.
- */
- GPollFD *prev_gpollfds;
- gint num_prev_gpollfds;
-
- /*
- * An array of pointers to fd_map's. The fd_map'd contain the tevent
- * event fd as well as a pointer to the corresponding glib GPollFD.
- */
- struct fd_map **fd_map;
- size_t num_maps;
-};
-
-static bool tevent_glib_prepare(struct tevent_glib_glue *glue);
-static bool tevent_glib_process(struct tevent_glib_glue *glue);
-static bool tevent_glib_glue_reinit(struct tevent_glib_glue *glue);
-static void tevent_glib_fd_handler(struct tevent_context *ev,
- struct tevent_fd *fde,
- uint16_t flags,
- void *private_data);
-
-typedef int (*gfds_cmp_cb)(const void *fd1, const void *fd2);
-typedef bool (*gfds_found_cb)(struct tevent_glib_glue *glue,
- const GPollFD *new,
- const GPollFD *old);
-typedef bool (*gfds_new_cb)(struct tevent_glib_glue *glue,
- const GPollFD *fd);
-typedef bool (*gfds_removed_cb)(struct tevent_glib_glue *glue,
- const GPollFD *fd);
-
-/**
- * Compare two sorted GPollFD arrays
- *
- * For every element that exists in gfds and prev_gfds found_fn() is called.
- * For every element in gfds but not in prev_gfds, new_fn() is called.
- * For every element in prev_gfds but not in gfds removed_fn() is called.
- **/
-static bool cmp_gfds(struct tevent_glib_glue *glue,
- GPollFD *gfds,
- GPollFD *prev_gfds,
- size_t num_gfds,
- size_t num_prev_gfds,
- gfds_cmp_cb cmp_cb,
- gfds_found_cb found_cb,
- gfds_new_cb new_cb,
- gfds_removed_cb removed_cb)
-{
- bool ok;
- size_t i = 0, j = 0;
- int cmp;
-
- while (i < num_gfds && j < num_prev_gfds) {
- cmp = cmp_cb(&gfds[i], &prev_gfds[j]);
- if (cmp == 0) {
- ok = found_cb(glue, &gfds[i], &prev_gfds[j]);
- if (!ok) {
- return false;
- }
- i++;
- j++;
- } else if (cmp < 0) {
- ok = new_cb(glue, &gfds[i]);
- if (!ok) {
- return false;
- }
- i++;
- } else {
- ok = removed_cb(glue, &prev_gfds[j]);
- if (!ok) {
- return false;
- }
- j++;
- }
- }
-
- while (i < num_gfds) {
- ok = new_cb(glue, &gfds[i++]);
- if (!ok) {
- return false;
- }
- }
-
- while (j < num_prev_gfds) {
- ok = removed_cb(glue, &prev_gfds[j++]);
- if (!ok) {
- return false;
- }
- }
-
- return true;
-}
-
-static int glib_fd_cmp_func(const void *p1, const void *p2)
-{
- const GPollFD *lhs = p1;
- const GPollFD *rhs = p2;
-
- if (lhs->fd < rhs->fd) {
- return -1;
- } else if (lhs->fd > rhs->fd) {
- return 1;
- }
-
- return 0;
-}
-
-/*
- * We already have a tevent fd event for the glib GPollFD, but we may have to
- * update flags.
- */
-static bool match_gfd_cb(struct tevent_glib_glue *glue,
- const GPollFD *new_gfd,
- const GPollFD *old_gfd)
-{
- size_t i;
- struct fd_map *fd_map = NULL;
- struct tevent_fd *fd_event = NULL;
-
- if (new_gfd->events == old_gfd->events) {
- return true;
- }
-
- for (i = 0; i < glue->num_maps; i++) {
- if (glue->fd_map[i]->fd == new_gfd->fd) {
- break;
- }
- }
-
- if (i == glue->num_maps) {
- DBG_ERR("match_gfd_cb: glib fd %d not in map\n", new_gfd->fd);
- return false;
- }
-
- fd_map = glue->fd_map[i];
- if (fd_map == NULL) {
- DBG_ERR("fd_map for fd %d is NULL\n", new_gfd->fd);
- return false;
- }
-
- fd_event = fd_map->fd_event;
- if (fd_event == NULL) {
- DBG_ERR("fd_event for fd %d is NULL\n", new_gfd->fd);
- return false;
- }
-
- tevent_fd_set_flags(fd_event, 0);
-
- if (new_gfd->events & (G_IO_IN | G_IO_HUP | G_IO_ERR)) {
- TEVENT_FD_READABLE(fd_event);
- }
- if (new_gfd->events & G_IO_OUT) {
- TEVENT_FD_WRITEABLE(fd_event);
- }
-
- return true;
-}
-
-static bool new_gfd_cb(struct tevent_glib_glue *glue, const GPollFD *gfd)
-{
- struct tevent_fd *fd_event = NULL;
- struct fd_map *fd_map = NULL;
- uint16_t events = 0;
- bool revent;
- bool wevent;
-
- revent = (gfd->events & (G_IO_IN | G_IO_HUP | G_IO_ERR));
- wevent = (gfd->events & G_IO_OUT);
- if (revent) {
- events |= TEVENT_FD_READ;
- }
- if (wevent) {
- events |= TEVENT_FD_WRITE;
- }
-
- glue->fd_map = talloc_realloc(glue,
- glue->fd_map,
- struct fd_map *,
- glue->num_maps + 1);
- if (glue->fd_map == NULL) {
- DBG_ERR("talloc_realloc failed\n");
- return false;
- }
- fd_map = talloc_zero(glue->fd_map, struct fd_map);
- if (fd_map == NULL) {
- DBG_ERR("talloc_realloc failed\n");
- return false;
- }
- glue->fd_map[glue->num_maps] = fd_map;
- glue->num_maps++;
-
- fd_event = tevent_add_fd(glue->ev,
- glue->fd_map,
- gfd->fd,
- events,
- tevent_glib_fd_handler,
- fd_map);
- if (fd_event == NULL) {
- DBG_ERR("tevent_add_fd failed\n");
- return false;
- }
-
- *fd_map = (struct fd_map) {
- .glue = glue,
- .fd = gfd->fd,
- .fd_event = fd_event,
- };
-
- DBG_DEBUG("added tevent_fd for glib fd %d\n", gfd->fd);
-
- return true;
-}
-
-static bool remove_gfd_cb(struct tevent_glib_glue *glue, const GPollFD *gfd)
-{
- size_t i;
-
- for (i = 0; i < glue->num_maps; i++) {
- if (glue->fd_map[i]->fd == gfd->fd) {
- break;
- }
- }
-
- if (i == glue->num_maps) {
- DBG_ERR("remove_gfd_cb: glib fd %d not in map\n", gfd->fd);
- return false;
- }
-
- TALLOC_FREE(glue->fd_map[i]->fd_event);
- TALLOC_FREE(glue->fd_map[i]);
-
- if (i + 1 < glue->num_maps) {
- memmove(&glue->fd_map[i],
- &glue->fd_map[i+1],
- (glue->num_maps - (i + 1)) * sizeof(struct fd_map *));
- }
-
- glue->fd_map = talloc_realloc(glue,
- glue->fd_map,
- struct fd_map *,
- glue->num_maps - 1);
- if (glue->num_maps > 0 && glue->fd_map == NULL) {
- DBG_ERR("talloc_realloc failed\n");
- return false;
- }
- glue->num_maps--;
-
- return true;
-}
-
-static short gpoll_to_poll_event(gushort gevent)
-{
- short pevent = 0;
-
- if (gevent & G_IO_IN) {
- pevent |= POLLIN;
- }
- if (gevent & G_IO_OUT) {
- pevent |= POLLOUT;
- }
- if (gevent & G_IO_HUP) {
- pevent |= POLLHUP;
- }
- if (gevent & G_IO_ERR) {
- pevent |= POLLERR;
- }
-
- return pevent;
-}
-
-static gushort poll_to_gpoll_event(short pevent)
-{
- gushort gevent = 0;
-
- if (pevent & POLLIN) {
- gevent |= G_IO_IN;
- }
- if (pevent & POLLOUT) {
- gevent |= G_IO_OUT;
- }
- if (pevent & POLLHUP) {
- gevent |= G_IO_HUP;
- }
- if (pevent & POLLERR) {
- gevent |= G_IO_ERR;
- }
-
- return gevent;
-}
-
-static void tevent_glib_fd_handler(struct tevent_context *ev,
- struct tevent_fd *fde,
- uint16_t flags,
- void *private_data)
-{
- struct fd_map *fd_map = talloc_get_type_abort(
- private_data, struct fd_map);
- struct tevent_glib_glue *glue = NULL;
- GPollFD *gpollfd = NULL;
- struct pollfd fd;
- int ret;
- int i;
-
- glue = fd_map->glue;
-
- for (i = 0; i < glue->num_gpollfds; i++) {
- if (glue->gpollfds[i].fd != fd_map->fd) {
- continue;
- }
- gpollfd = &glue->gpollfds[i];
- break;
- }
- if (gpollfd == NULL) {
- DBG_ERR("No gpollfd for fd_map [%p] fd [%d]\n",
- fd_map, fd_map->fd);
- return;
- }
- /*
- * We have to poll() the fd to get the correct fd event for glib. tevent
- * only tells us about readable/writable in flags, but we need the full
- * glory for glib.
- */
-
- fd = (struct pollfd) {
- .fd = gpollfd->fd,
- .events = gpoll_to_poll_event(gpollfd->events),
- };
-
- ret = sys_poll_intr(&fd, 1, 0);
- if (ret == -1) {
- DBG_ERR("poll: %s\n", strerror(errno));
- return;
- }
- if (ret == 0) {
- return;
- }
-
- gpollfd->revents = poll_to_gpoll_event(fd.revents);
-
- tevent_glib_process(glue);
- return;
-}
-
-static void tevent_glib_timer_handler(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval current_time,
- void *private_data)
-{
- struct tevent_glib_glue *glue = talloc_get_type_abort(
- private_data, struct tevent_glib_glue);
-
- glue->timer = NULL;
- tevent_glib_process(glue);
- return;
-}
-
-static void tevent_glib_im_handler(struct tevent_context *ev,
- struct tevent_immediate *im,
- void *private_data)
-{
- struct tevent_glib_glue *glue = talloc_get_type_abort(
- private_data, struct tevent_glib_glue);
-
- glue->scheduled_im = false;
- tevent_glib_process(glue);
- return;
-}
-
-static bool save_current_fdset(struct tevent_glib_glue *glue)
-{
- /*
- * Save old glib fds. We only grow the prev array.
- */
-
- if (glue->num_prev_gpollfds < glue->num_gpollfds) {
- glue->prev_gpollfds = talloc_realloc(glue,
- glue->prev_gpollfds,
- GPollFD,
- glue->num_gpollfds);
- if (glue->prev_gpollfds == NULL) {
- DBG_ERR("talloc_realloc failed\n");
- return false;
- }
- }
- glue->num_prev_gpollfds = glue->num_gpollfds;
- if (glue->num_gpollfds > 0) {
- memcpy(glue->prev_gpollfds, glue->gpollfds,
- sizeof(GPollFD) * glue->num_gpollfds);
- memset(glue->gpollfds, 0, sizeof(GPollFD) * glue->num_gpollfds);
- }
-
- return true;
-}
-
-static bool get_glib_fds_and_timeout(struct tevent_glib_glue *glue)
-{
- bool ok;
- gint num_fds;
-
- ok = save_current_fdset(glue);
- if (!ok) {
- return false;
- }
-
- while (true) {
- num_fds = g_main_context_query(glue->gmain_ctx,
- glue->gpriority,
- &glue->gtimeout,
- glue->gpollfds,
- glue->num_gpollfds);
- if (num_fds == glue->num_gpollfds) {
- break;
- }
- glue->gpollfds = talloc_realloc(glue,
- glue->gpollfds,
- GPollFD,
- num_fds);
- if (num_fds > 0 && glue->gpollfds == NULL) {
- DBG_ERR("talloc_realloc failed\n");
- return false;
- }
- glue->num_gpollfds = num_fds;
- };
-
- if (glue->num_gpollfds > 0) {
- qsort(glue->gpollfds,
- num_fds,
- sizeof(GPollFD),
- glib_fd_cmp_func);
- }
-
- DBG_DEBUG("num fds: %d, timeout: %d ms\n",
- num_fds, glue->gtimeout);
-
- return true;
-}
-
-static bool tevent_glib_update_events(struct tevent_glib_glue *glue)
-{
- struct timeval tv;
- bool ok;
-
- ok = cmp_gfds(glue,
- glue->gpollfds,
- glue->prev_gpollfds,
- glue->num_gpollfds,
- glue->num_prev_gpollfds,
- glib_fd_cmp_func,
- match_gfd_cb,
- new_gfd_cb,
- remove_gfd_cb);
- if (!ok) {
- return false;
- }
-
- TALLOC_FREE(glue->timer);
-
- if (glue->gtimeout == -1) {
- return true;
- }
-
- if (glue->gtimeout == 0) {
- /*
- * glue->gtimeout is 0 if g_main_context_query() returned
- * timeout=0. That means there are pending events ready to be
- * dispatched. We only want to run one event handler per loop
- * iteration, so we schedule an immediate event to run it in the
- * next iteration.
- */
- if (glue->scheduled_im) {
- return true;
- }
- tevent_schedule_immediate(glue->im,
- glue->ev,
- tevent_glib_im_handler,
- glue);
- glue->scheduled_im = true;
- return true;
- }
-
- tv = tevent_timeval_current_ofs(glue->gtimeout / 1000,
- (glue->gtimeout % 1000) * 1000);
-
- glue->timer = tevent_add_timer(glue->ev,
- glue,
- tv,
- tevent_glib_timer_handler,
- glue);
- if (glue->timer == NULL) {
- DBG_ERR("tevent_add_timer failed\n");
- return false;
- }
-
- return true;
-}
-
-static void tevent_glib_retry_timer(struct tevent_context *ev,
- struct tevent_timer *te,
- struct timeval current_time,
- void *private_data)
-{
- struct tevent_glib_glue *glue = talloc_get_type_abort(
- private_data, struct tevent_glib_glue);
-
- glue->acquire_retry_timer = NULL;
- (void)tevent_glib_prepare(glue);
-}
-
-/**
- * Fetch glib event sources and add them to tevent
- *
- * Fetch glib event sources and attach corresponding tevent events to our tevent
- * context. get_glib_fds_and_timeout() gets the relevant glib event sources: the
- * set of active fds and the next timer. tevent_glib_update_events() then
- * translates those to tevent and creates tevent events.
- *
- * When called, the thread must NOT be the owner to the glib main
- * context. tevent_glib_prepare() is either the first function when the
- * tevent_glib_glue is created, or after tevent_glib_process() has been called
- * to process pending event, which will have ceased ownership.
- **/
-static bool tevent_glib_prepare(struct tevent_glib_glue *glue)
-{
- bool ok;
- gboolean gok;
-
- if (glue->quit) {
- /* Set via samba_tevent_glib_glue_quit() */
- return true;
- }
-
- if (glue->acquire_retry_timer != NULL) {
- /*
- * We're still waiting on the below g_main_context_acquire() to
- * succeed, just return.
- */
- return true;
- }
-
- if (glue->gmain_owner) {
- g_main_context_release(glue->gmain_ctx);
- glue->gmain_owner = false;
- }
-
- gok = g_main_context_acquire(glue->gmain_ctx);
- if (!gok) {
- DBG_ERR("couldn't acquire g_main_context\n");
-
- /*
- * Ensure no tevent event fires while we're not the gmain
- * context owner. The event handler would call
- * tevent_glib_process() and that expects being the owner of the
- * context.
- */
- ok = tevent_glib_glue_reinit(glue);
- if (!ok) {
- DBG_ERR("tevent_glib_glue_reinit failed\n");
- samba_tevent_glib_glue_quit(glue);
- return false;
- }
-
- glue->acquire_retry_timer = tevent_add_timer(
- glue->ev,
- glue,
- tevent_timeval_current_ofs(0, 1000),
- tevent_glib_retry_timer,
- glue);
- if (glue->acquire_retry_timer == NULL) {
- DBG_ERR("tevent_add_timer failed\n");
- samba_tevent_glib_glue_quit(glue);
- return false;
- }
- return true;
- }
- glue->gmain_owner = true;
-
- /*
- * Discard "ready" return value from g_main_context_prepare(). We don't
- * want to dispatch events here, that's only done in from the tevent loop.
- */
- (void)g_main_context_prepare(glue->gmain_ctx, &glue->gpriority);
-
- ok = get_glib_fds_and_timeout(glue);
- if (!ok) {
- DBG_ERR("get_glib_fds_and_timeout failed\n");
- samba_tevent_glib_glue_quit(glue);
- return false;
- }
-
- ok = tevent_glib_update_events(glue);
- if (!ok) {
- DBG_ERR("tevent_glib_update_events failed\n");
- samba_tevent_glib_glue_quit(glue);
- return false;
- }
-
- return true;
-}
-
-/**
- * Process pending glib events
- *
- * tevent_glib_process() gets called to process pending glib events via
- * g_main_context_check() and then g_main_context_dispatch().
- *
- * After pending event handlers are dispatched, we rearm the glib glue event
- * handlers in tevent by calling tevent_glib_prepare().
- *
- * When tevent_glib_process() is called the thread must own the glib
- * gmain_ctx. That is achieved by tevent_glib_prepare() being the only function
- * that acquires context ownership.
- *
- * To give other threads that are blocked on g_main_context_acquire(gmain_ctx) a
- * chance to acquire context ownership (eg needed to attach event sources), we
- * release context ownership before calling tevent_glib_prepare() which will
- * acquire it again.
- */
-static bool tevent_glib_process(struct tevent_glib_glue *glue)
-{
- bool ok;
-
- DBG_DEBUG("tevent_glib_process\n");
-
- /*
- * Ignore the "sources_ready" return from g_main_context_check(). glib
- * itself also ignores it in g_main_context_iterate(). In theory only
- * calling g_main_context_dispatch() if g_main_context_check() returns
- * true should work, but older glib versions had a bug where
- * g_main_context_check() returns false even though events are pending.
- *
- * https://bugzilla.gnome.org/show_bug.cgi?id=11059
- */
- (void)g_main_context_check(glue->gmain_ctx,
- glue->gpriority,
- glue->gpollfds,
- glue->num_gpollfds);
-
- g_main_context_dispatch(glue->gmain_ctx);
-
- ok = tevent_glib_prepare(glue);
- if (!ok) {
- return false;
- }
- glue->skip_glib_refresh = true;
- return true;
-}
-
-static void tevent_glib_glue_trace_callback(enum tevent_trace_point point,
- void *private_data)
-{
- struct tevent_glib_glue *glue = talloc_get_type_abort(
- private_data, struct tevent_glib_glue);
-
- if (point == TEVENT_TRACE_AFTER_LOOP_ONCE) {
- if (!glue->skip_glib_refresh) {
- tevent_glib_prepare(glue);
- }
- glue->skip_glib_refresh = false;
- }
-
- /* chain previous handler */
- if (glue->prev_tevent_trace_cb != NULL) {
- glue->prev_tevent_trace_cb(point, glue->prev_tevent_trace_data);
- }
-}
-
-static void tevent_glib_glue_cleanup(struct tevent_glib_glue *glue)
-{
- size_t n = talloc_array_length(glue->fd_map);
- size_t i;
-
- for (i = 0; i < n; i++) {
- TALLOC_FREE(glue->fd_map[i]->fd_event);
- TALLOC_FREE(glue->fd_map[i]);
- }
-
- tevent_set_trace_callback(glue->ev,
- glue->prev_tevent_trace_cb,
- glue->prev_tevent_trace_data);
- glue->prev_tevent_trace_cb = NULL;
- glue->prev_tevent_trace_data = NULL;
-
- TALLOC_FREE(glue->fd_map);
- glue->num_maps = 0;
-
- TALLOC_FREE(glue->gpollfds);
- glue->num_gpollfds = 0;
-
- TALLOC_FREE(glue->prev_gpollfds);
- glue->num_prev_gpollfds = 0;
-
- TALLOC_FREE(glue->timer);
- TALLOC_FREE(glue->acquire_retry_timer);
- TALLOC_FREE(glue->im);
-
- /*
- * These are not really needed, but let's wipe the slate clean.
- */
- glue->skip_glib_refresh = false;
- glue->gtimeout = 0;
- glue->gpriority = 0;
-}
-
-static bool tevent_glib_glue_reinit(struct tevent_glib_glue *glue)
-{
- tevent_glib_glue_cleanup(glue);
-
- glue->im = tevent_create_immediate(glue);
- if (glue->im == NULL) {
- return false;
- }
-
- tevent_get_trace_callback(glue->ev,
- &glue->prev_tevent_trace_cb,
- &glue->prev_tevent_trace_data);
- tevent_set_trace_callback(glue->ev,
- tevent_glib_glue_trace_callback,
- glue);
-
- return true;
-}
-
-void samba_tevent_glib_glue_quit(struct tevent_glib_glue *glue)
-{
- tevent_glib_glue_cleanup(glue);
- glue->quit = true;
- return;
-}
-
-struct tevent_glib_glue *samba_tevent_glib_glue_create(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- GMainContext *gmain_ctx)
-{
- bool ok;
- struct tevent_glib_glue *glue = NULL;
-
- glue = talloc_zero(mem_ctx, struct tevent_glib_glue);
- if (glue == NULL) {
- DBG_ERR("talloc_zero failed\n");
- return NULL;
- }
-
- *glue = (struct tevent_glib_glue) {
- .ev = ev,
- .gmain_ctx = gmain_ctx,
- };
-
- glue->im = tevent_create_immediate(glue);
-
- tevent_get_trace_callback(glue->ev,
- &glue->prev_tevent_trace_cb,
- &glue->prev_tevent_trace_data);
- tevent_set_trace_callback(glue->ev,
- tevent_glib_glue_trace_callback,
- glue);
-
- ok = tevent_glib_prepare(glue);
- if (!ok) {
- TALLOC_FREE(glue);
- return NULL;
- }
-
- return glue;
-}
-
-#else /* HAVE_GLIB */
-
-struct tevent_glib_glue *samba_tevent_glib_glue_create(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- GMainContext *gmain_ctx)
-{
- errno = ENOSYS;
- return NULL;
-}
-
-void samba_tevent_glib_glue_quit(struct tevent_glib_glue *glue)
-{
- return;
-}
-#endif /* HAVE_GLIB */
+++ /dev/null
-/*
- Unix SMB/CIFS implementation.
- Poll glib event loop from tevent
-
- Copyright (C) Ralph Boehme 2016
-
- ** NOTE! The following LGPL license applies to the tevent
- ** library. This does NOT imply that all of Samba is released
- ** under the LGPL
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 3 of the License, or (at your option) any later version.
-
- This library 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#ifndef _TEVENT_GLIB_GLUE_H
-#define _TEVENT_GLIB_GLUE_H
-
-#include <talloc.h>
-#include <tevent.h>
-
-/**
- * @brief Add a glib GmainContext to a tevent context
- *
- * tevent will poll the glib event sources and run handlers for
- * pending events as detailed in the glib documentation:
- *
- * https://developer.gnome.org/glib/stable/glib-The-Main-Event-Loop.html
- *
- * If tevent was built without glib support, this function will always return
- * NULL with an error number ENOSYS.
- *
- * @param[in] mem_ctx Memory context to use
- *
- * @param[in] ev Event context to use
- *
- * @param[in] gmain_ctx GMainContext that will be added to tevent
- *
- * @return A handle on the glue context that binds the
- * the GMainContext to tevent. Pass the glue handle to
- * tevent_glib_glue_quit() in a callback when you want
- * stop processing glib events.
- * You must not call talloc_free() on the handle while
- * the loop is still in use and attached to tevent.
- */
-struct tevent_glib_glue *samba_tevent_glib_glue_create(TALLOC_CTX *mem_ctx,
- struct tevent_context *ev,
- GMainContext *gmain_ctx);
-
-/**
- * @brief Stop polling a GMainContext
- *
- * Used in a callback when you want to stop processing glib events.
- *
- * @param[in] glue And tevent_glib_glue handle
- */
-void samba_tevent_glib_glue_quit(struct tevent_glib_glue *glue);
-
-#endif
+++ /dev/null
-/*
- Unix SMB/CIFS implementation.
-
- testing of the tevent glib glue subsystem
-
- Copyright (C) Ralph Boehme 2016
-
- glib tests adapted from glib2 glib/tests/mainloop.c
- Copyright (C) 2011 Red Hat Inc., Matthias Clasen
-
- ** NOTE! The following LGPL license applies to the tevent
- ** library. This does NOT imply that all of Samba is released
- ** under the LGPL
-
- This library is free software; you can redistribute it and/or
- modify it under the terms of the GNU Lesser General Public
- License as published by the Free Software Foundation; either
- version 3 of the License, or (at your option) any later version.
-
- This library 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
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public
- License along with this library; if not, see <http://www.gnu.org/licenses/>.
-*/
-
-#include "replace.h"
-
-/*
- * glib uses TRUE and FALSE which may have redefined by "includes.h" to be
- * unusable. Unndefine so glib can establish its own working replacement.
- */
-#undef TRUE
-#undef FALSE
-#include <glib.h>
-#include <glib-unix.h>
-#include "lib/tevent_glib_glue.h"
-
-/*
- * Unfortunately the glib test suite runner doesn't pass args to tests
- * so we must keep a few globals here.
- */
-static struct tevent_context *ev;
-
-static gboolean count_calls(gpointer data)
-{
- gint *i = (gint *)data;
-
- (*i)++;
-
- return TRUE;
-}
-
-static gboolean quit_loop(gpointer data)
-{
- struct tevent_glib_glue *glue = talloc_get_type_abort(
- data, struct tevent_glib_glue);
-
- samba_tevent_glib_glue_quit(glue);
-
- return G_SOURCE_REMOVE;
-}
-
-static void test_timeouts(void)
-{
- GMainContext *ctx = NULL;
- struct tevent_glib_glue *glue = NULL;
- GSource *source = NULL;
- gint a;
- gint b;
- gint c;
-
- a = b = c = 0;
-
- ctx = g_main_context_new();
- glue = samba_tevent_glib_glue_create(ev, ev, ctx);
- g_assert(glue != NULL);
-
- source = g_timeout_source_new(100);
- g_source_set_callback(source, count_calls, &a, NULL);
- g_source_attach(source, ctx);
- g_source_unref(source);
-
- source = g_timeout_source_new(250);
- g_source_set_callback(source, count_calls, &b, NULL);
- g_source_attach(source, ctx);
- g_source_unref(source);
-
- source = g_timeout_source_new(330);
- g_source_set_callback(source, count_calls, &c, NULL);
- g_source_attach(source, ctx);
- g_source_unref(source);
-
- source = g_timeout_source_new(1050);
- g_source_set_callback(source, quit_loop, glue, NULL);
- g_source_attach(source, ctx);
- g_source_unref(source);
-
- g_assert(tevent_loop_wait(ev) == 0);
-
- /* We may be delayed for an arbitrary amount of time - for example,
- * it's possible for all timeouts to fire exactly once.
- */
- g_assert_cmpint(a, >, 0);
- g_assert_cmpint(a, >=, b);
- g_assert_cmpint(b, >=, c);
-
- g_assert_cmpint(a, <=, 10);
- g_assert_cmpint(b, <=, 4);
- g_assert_cmpint(c, <=, 3);
-
- samba_tevent_glib_glue_quit(glue);
- TALLOC_FREE(glue);
- g_main_context_unref(ctx);
-}
-
-struct test_glib_ev_source_data {
- GMainContext *ctx;
- struct tevent_glib_glue *glue;
-};
-
-static gboolean test_glib_ev_source_quit_loop(gpointer data);
-
-static gboolean test_glib_ev_source_timeout_cb(gpointer data)
-{
- struct test_glib_ev_source_data *state = talloc_get_type_abort(
- data, struct test_glib_ev_source_data);
- GSource *source = NULL;
-
- source = g_timeout_source_new(100);
- g_source_set_callback(source,
- test_glib_ev_source_quit_loop,
- state,
- NULL);
- g_source_attach(source, state->ctx);
- g_source_unref(source);
-
- return TRUE;
-}
-
-static gboolean test_glib_ev_source_quit_loop(gpointer data)
-{
- struct test_glib_ev_source_data *state = talloc_get_type_abort(
- data, struct test_glib_ev_source_data);
-
- samba_tevent_glib_glue_quit(state->glue);
-
- return G_SOURCE_REMOVE;
-}
-
-static void test_glib_ev_source(void)
-{
- GMainContext *ctx = NULL;
- struct tevent_glib_glue *glue = NULL;
- struct test_glib_ev_source_data *state = NULL;
- GSource *source = NULL;
-
- ctx = g_main_context_new();
- g_assert(ctx != NULL);
-
- glue = samba_tevent_glib_glue_create(ev, ev, ctx);
- g_assert(glue != NULL);
-
- state = talloc_zero(glue, struct test_glib_ev_source_data);
- g_assert(state != NULL);
-
- state->ctx = ctx;
- state->glue = glue;
-
- source = g_timeout_source_new(100);
- g_source_set_callback(source,
- test_glib_ev_source_timeout_cb,
- state,
- NULL);
- g_source_attach(source, ctx);
- g_source_unref(source);
-
- g_assert(tevent_loop_wait(ev) == 0);
-
- TALLOC_FREE(glue);
- g_main_context_unref(ctx);
-}
-
-struct test_tevent_ev_source_data {
- GMainContext *ctx;
- struct tevent_glib_glue *glue;
-};
-
-static gboolean test_tevent_ev_source_quit_loop(gpointer data);
-
-static void test_tevent_ev_source_timeout_cb(struct tevent_context *_ev,
- struct tevent_timer *te,
- struct timeval current_time,
- void *data)
-{
- struct test_tevent_ev_source_data *state = talloc_get_type_abort(
- data, struct test_tevent_ev_source_data);
- GSource *source = NULL;
-
- source = g_timeout_source_new(100);
- g_source_set_callback(source,
- test_tevent_ev_source_quit_loop,
- state,
- NULL);
- g_source_attach(source, state->ctx);
- g_source_unref(source);
-
- return;
-}
-
-static gboolean test_tevent_ev_source_quit_loop(gpointer data)
-{
- struct test_tevent_ev_source_data *state = talloc_get_type_abort(
- data, struct test_tevent_ev_source_data);
-
- samba_tevent_glib_glue_quit(state->glue);
-
- return G_SOURCE_REMOVE;
-}
-
-static void test_tevent_ev_source(void)
-{
- GMainContext *ctx = NULL;
- struct tevent_glib_glue *glue = NULL;
- struct test_tevent_ev_source_data *state = NULL;
- struct tevent_timer *timer = NULL;
-
- ctx = g_main_context_new();
- g_assert(ctx != NULL);
-
- glue = samba_tevent_glib_glue_create(ev, ev, ctx);
- g_assert(glue != NULL);
-
- state = talloc_zero(glue, struct test_tevent_ev_source_data);
- g_assert(state != NULL);
-
- state->ctx = ctx;
- state->glue = glue;
-
- timer = tevent_add_timer(ev,
- state,
- tevent_timeval_current_ofs(0, 1000),
- test_tevent_ev_source_timeout_cb,
- state);
- g_assert(timer != NULL);
-
- g_assert(tevent_loop_wait(ev) == 0);
-
- TALLOC_FREE(glue);
- g_main_context_unref(ctx);
-}
-
-static gchar zeros[1024];
-
-static gsize fill_a_pipe(gint fd)
-{
- gsize written = 0;
- GPollFD pfd;
-
- pfd.fd = fd;
- pfd.events = G_IO_OUT;
- while (g_poll(&pfd, 1, 0) == 1)
- /* we should never see -1 here */
- written += write(fd, zeros, sizeof zeros);
-
- return written;
-}
-
-static gboolean write_bytes(gint fd,
- GIOCondition condition,
- gpointer user_data)
-{
- gssize *to_write = user_data;
- gint limit;
-
- if (*to_write == 0)
- return FALSE;
-
- /* Detect if we run before we should */
- g_assert(*to_write >= 0);
-
- limit = MIN(*to_write, sizeof zeros);
- *to_write -= write(fd, zeros, limit);
-
- return TRUE;
-}
-
-static gboolean read_bytes(gint fd,
- GIOCondition condition,
- gpointer user_data)
-{
- static gchar buffer[1024];
- gssize *to_read = user_data;
-
- *to_read -= read(fd, buffer, sizeof buffer);
-
- /* The loop will exit when there is nothing else to read, then we will
- * use g_source_remove() to destroy this source.
- */
- return TRUE;
-}
-
-static void test_unix_fd(void)
-{
- gssize to_write = -1;
- gssize to_read;
- gint fds[2];
- gint a, b;
- gint s;
- GSource *source_a = NULL;
- GSource *source_b = NULL;
- struct tevent_glib_glue *glue = NULL;
-
- glue = samba_tevent_glib_glue_create(ev, ev, g_main_context_default());
- g_assert(glue != NULL);
-
- s = pipe(fds);
- g_assert(s == 0);
-
- to_read = fill_a_pipe(fds[1]);
- /* write at higher priority to keep the pipe full... */
- a = g_unix_fd_add_full(G_PRIORITY_HIGH,
- fds[1],
- G_IO_OUT,
- write_bytes,
- &to_write,
- NULL);
- source_a = g_source_ref(g_main_context_find_source_by_id(NULL, a));
- /* make sure no 'writes' get dispatched yet */
- while (tevent_loop_once(ev));
-
- to_read += 128 * 1024 * 1024;
- to_write = 128 * 1024 * 1024;
- b = g_unix_fd_add(fds[0], G_IO_IN, read_bytes, &to_read);
- source_b = g_source_ref(g_main_context_find_source_by_id(NULL, b));
-
- /* Assuming the kernel isn't internally 'laggy' then there will always
- * be either data to read or room in which to write. That will keep
- * the loop running until all data has been read and written.
- */
- while (to_write > 0 || to_read > 0)
- {
- gssize to_write_was = to_write;
- gssize to_read_was = to_read;
-
- if (tevent_loop_once(ev) != 0)
- break;
-
- /* Since the sources are at different priority, only one of them
- * should possibly have run.
- */
- g_assert(to_write == to_write_was || to_read == to_read_was);
- }
-
- g_assert(to_write == 0);
- g_assert(to_read == 0);
-
- /* 'a' is already removed by itself */
- g_assert(g_source_is_destroyed(source_a));
- g_source_unref(source_a);
- g_source_remove(b);
- g_assert(g_source_is_destroyed(source_b));
- g_source_unref(source_b);
-
- samba_tevent_glib_glue_quit(glue);
- TALLOC_FREE(glue);
-
- close(fds[1]);
- close(fds[0]);
-}
-
-int main(int argc, const char *argv[])
-{
- int test_argc = 3;
- char *test_argv[] = {
- discard_const("test_glib_glue"),
- discard_const("-m"),
- discard_const("no-undefined")
- };
- char **argvp = test_argv;
-
- g_test_init(&test_argc, &argvp, NULL);
-
- ev = tevent_context_init(NULL);
- if (ev == NULL) {
- exit(1);
- }
-
- g_test_add_func("/mainloop/timeouts", test_timeouts);
- g_test_add_func("/mainloop/glib_ev_source", test_glib_ev_source);
- g_test_add_func("/mainloop/tevent_ev_source", test_tevent_ev_source);
- g_test_add_func("/mainloop/unix-fd", test_unix_fd);
-
- return g_test_run();
-}
=============
This directory contains source code for the metadata search service
aka Spotlight.
-
-Bison and flex:
-===============
-Not yet integrated into the waf buildsystem, run these by hand:
-
-$ bison -d -o sparql_parser.c sparql_parser.y
-$ flex -o sparql_lexer.c sparql_lexer.l
-
-or use the bundled Makefile.
-
#include "libcli/security/security.h"
#include "mdssvc.h"
#include "mdssvc_noindex.h"
-#ifdef HAVE_SPOTLIGHT_BACKEND_TRACKER
-#include "mdssvc_tracker.h"
-#endif
#ifdef HAVE_SPOTLIGHT_BACKEND_ES
#include "mdssvc_es.h"
#endif
}
#endif
-#ifdef HAVE_SPOTLIGHT_BACKEND_TRACKER
- ok = mdsscv_backend_tracker.init(mdssvc_ctx);
- if (!ok) {
- DBG_ERR("backend init failed\n");
- TALLOC_FREE(mdssvc_ctx);
- return NULL;
- }
-#endif
-
return mdssvc_ctx;
}
}
#endif
-#ifdef HAVE_SPOTLIGHT_BACKEND_TRACKER
- ok = mdsscv_backend_tracker.shutdown(mdssvc_ctx);
- if (!ok) {
- goto fail;
- }
-#endif
-
ok = true;
fail:
TALLOC_FREE(mdssvc_ctx);
break;
#endif
-#ifdef HAVE_SPOTLIGHT_BACKEND_TRACKER
- case SPOTLIGHT_BACKEND_TRACKER:
- mds_ctx->backend = &mdsscv_backend_tracker;
- break;
-#endif
default:
DBG_ERR("Unknown backend %d\n", backend);
TALLOC_FREE(mdssvc_ctx);
+++ /dev/null
-/*
- Unix SMB/CIFS implementation.
- Main metadata server / Spotlight routines / Tracker backend
-
- Copyright (C) Ralph Boehme 2019
-
- This program 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.
-
- This program 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/>.
-*/
-
-#include "includes.h"
-#include "lib/util/time_basic.h"
-#include "mdssvc.h"
-#include "mdssvc_tracker.h"
-#include "lib/tevent_glib_glue.h"
-#include "rpc_server/mdssvc/sparql_parser.tab.h"
-
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_RPC_SRV
-
-static struct mdssvc_tracker_ctx *mdssvc_tracker_ctx;
-
-/************************************************
- * Tracker async callbacks
- ************************************************/
-
-static void tracker_con_cb(GObject *object,
- GAsyncResult *res,
- gpointer user_data)
-{
- struct mds_tracker_ctx *ctx = NULL;
- TrackerSparqlConnection *tracker_con = NULL;
- GError *error = NULL;
-
- tracker_con = tracker_sparql_connection_get_finish(res, &error);
- if (error && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
- /*
- * If the async request was cancelled, user_data will already be
- * talloc_free'd, so we must be carefully checking for
- * G_IO_ERROR_CANCELLED before using user_data.
- */
- DBG_ERR("Tracker connection cancelled\n");
- g_error_free(error);
- return;
- }
- /*
- * Ok, we're not cancelled, we can now safely use user_data.
- */
- ctx = talloc_get_type_abort(user_data, struct mds_tracker_ctx);
- ctx->async_pending = false;
- /*
- * Check error again, above we only checked for G_IO_ERROR_CANCELLED.
- */
- if (error) {
- DBG_ERR("Could not connect to Tracker: %s\n", error->message);
- g_error_free(error);
- return;
- }
-
- ctx->tracker_con = tracker_con;
-
- DBG_DEBUG("connected to Tracker\n");
-}
-
-static void tracker_cursor_cb(GObject *object,
- GAsyncResult *res,
- gpointer user_data);
-
-static void tracker_query_cb(GObject *object,
- GAsyncResult *res,
- gpointer user_data)
-{
- struct sl_tracker_query *tq = NULL;
- struct sl_query *slq = NULL;
- TrackerSparqlConnection *conn = NULL;
- TrackerSparqlCursor *cursor = NULL;
- GError *error = NULL;
-
- conn = TRACKER_SPARQL_CONNECTION(object);
-
- cursor = tracker_sparql_connection_query_finish(conn, res, &error);
- /*
- * If the async request was cancelled, user_data will already be
- * talloc_free'd, so we must be carefully checking for
- * G_IO_ERROR_CANCELLED before using user_data.
- */
- if (error && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
- DBG_ERR("Tracker query cancelled\n");
- if (cursor != NULL) {
- g_object_unref(cursor);
- }
- g_error_free(error);
- return;
- }
- /*
- * Ok, we're not cancelled, we can now safely use user_data.
- */
- tq = talloc_get_type_abort(user_data, struct sl_tracker_query);
- tq->async_pending = false;
- slq = tq->slq;
- /*
- * Check error again, above we only checked for G_IO_ERROR_CANCELLED.
- */
- if (error) {
- DBG_ERR("Tracker query error: %s\n", error->message);
- g_error_free(error);
- slq->state = SLQ_STATE_ERROR;
- return;
- }
-
- tq->cursor = cursor;
- slq->state = SLQ_STATE_RESULTS;
-
- tracker_sparql_cursor_next_async(tq->cursor,
- tq->gcancellable,
- tracker_cursor_cb,
- tq);
- tq->async_pending = true;
-}
-
-static char *tracker_to_unix_path(TALLOC_CTX *mem_ctx, const char *uri)
-{
- GFile *f = NULL;
- char *path = NULL;
- char *talloc_path = NULL;
-
- f = g_file_new_for_uri(uri);
- if (f == NULL) {
- return NULL;
- }
-
- path = g_file_get_path(f);
- g_object_unref(f);
-
- if (path == NULL) {
- return NULL;
- }
-
- talloc_path = talloc_strdup(mem_ctx, path);
- g_free(path);
- if (talloc_path == NULL) {
- return NULL;
- }
-
- return talloc_path;
-}
-
-static void tracker_cursor_cb(GObject *object,
- GAsyncResult *res,
- gpointer user_data)
-{
- TrackerSparqlCursor *cursor = NULL;
- struct sl_tracker_query *tq = NULL;
- struct sl_query *slq = NULL;
- const gchar *uri = NULL;
- GError *error = NULL;
- char *path = NULL;
- gboolean more_results;
- bool ok;
-
- cursor = TRACKER_SPARQL_CURSOR(object);
- more_results = tracker_sparql_cursor_next_finish(cursor,
- res,
- &error);
- /*
- * If the async request was cancelled, user_data will already be
- * talloc_free'd, so we must be carefully checking for
- * G_IO_ERROR_CANCELLED before using user_data.
- */
- if (error && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
- g_error_free(error);
- g_object_unref(cursor);
- return;
- }
- /*
- * Ok, we're not cancelled, we can now safely use user_data.
- */
- tq = talloc_get_type_abort(user_data, struct sl_tracker_query);
- tq->async_pending = false;
- slq = tq->slq;
- /*
- * Check error again, above we only checked for G_IO_ERROR_CANCELLED.
- */
- if (error) {
- DBG_ERR("Tracker cursor: %s\n", error->message);
- g_error_free(error);
- slq->state = SLQ_STATE_ERROR;
- return;
- }
-
- SLQ_DEBUG(10, slq, "results");
-
- if (!more_results) {
- slq->state = SLQ_STATE_DONE;
-
- g_object_unref(tq->cursor);
- tq->cursor = NULL;
-
- g_object_unref(tq->gcancellable);
- tq->gcancellable = NULL;
- return;
- }
-
- uri = tracker_sparql_cursor_get_string(tq->cursor, 0, NULL);
- if (uri == NULL) {
- DBG_ERR("error fetching Tracker URI\n");
- slq->state = SLQ_STATE_ERROR;
- return;
- }
-
- path = tracker_to_unix_path(slq->query_results, uri);
- if (path == NULL) {
- DBG_ERR("error converting Tracker URI to path: %s\n", uri);
- slq->state = SLQ_STATE_ERROR;
- return;
- }
-
- ok = mds_add_result(slq, path);
- if (!ok) {
- DBG_ERR("error adding result for path: %s\n", uri);
- slq->state = SLQ_STATE_ERROR;
- return;
- }
-
- if (slq->query_results->num_results >= MAX_SL_RESULTS) {
- slq->state = SLQ_STATE_FULL;
- SLQ_DEBUG(10, slq, "full");
- return;
- }
-
- slq->state = SLQ_STATE_RESULTS;
- SLQ_DEBUG(10, slq, "cursor next");
-
- tracker_sparql_cursor_next_async(tq->cursor,
- tq->gcancellable,
- tracker_cursor_cb,
- tq);
- tq->async_pending = true;
-}
-
-/*
- * This gets called once, even if the backend is not configured by the user
- */
-static bool mdssvc_tracker_init(struct mdssvc_ctx *mdssvc_ctx)
-{
- if (mdssvc_tracker_ctx != NULL) {
- return true;
- }
-
-#if (GLIB_MAJOR_VERSION < 3) && (GLIB_MINOR_VERSION < 36)
- g_type_init();
-#endif
-
- mdssvc_tracker_ctx = talloc_zero(mdssvc_ctx, struct mdssvc_tracker_ctx);
- if (mdssvc_tracker_ctx == NULL) {
- return false;
- }
- mdssvc_tracker_ctx->mdssvc_ctx = mdssvc_ctx;
-
- return true;
-}
-
-/*
- * This gets called per mdscmd_open / tcon. This runs initialisation code that
- * should only run if the tracker backend is actually used.
- */
-static bool mdssvc_tracker_prepare(void)
-{
- if (mdssvc_tracker_ctx->gmain_ctx != NULL) {
- /*
- * Assuming everything is setup if gmain_ctx is.
- */
- return true;
- }
-
- mdssvc_tracker_ctx->gmain_ctx = g_main_context_new();
- if (mdssvc_tracker_ctx->gmain_ctx == NULL) {
- DBG_ERR("error from g_main_context_new\n");
- return false;
- }
-
- mdssvc_tracker_ctx->glue = samba_tevent_glib_glue_create(
- mdssvc_tracker_ctx,
- mdssvc_tracker_ctx->mdssvc_ctx->ev_ctx,
- mdssvc_tracker_ctx->gmain_ctx);
- if (mdssvc_tracker_ctx->glue == NULL) {
- DBG_ERR("samba_tevent_glib_glue_create failed\n");
- g_object_unref(mdssvc_tracker_ctx->gmain_ctx);
- mdssvc_tracker_ctx->gmain_ctx = NULL;
- return false;
- }
-
- return true;
-}
-
-static bool mdssvc_tracker_shutdown(struct mdssvc_ctx *mdssvc_ctx)
-{
- if (mdssvc_tracker_ctx == NULL) {
- return true;
- }
-
- if (mdssvc_tracker_ctx->gmain_ctx == NULL) {
- return true;
- }
-
- samba_tevent_glib_glue_quit(mdssvc_tracker_ctx->glue);
- TALLOC_FREE(mdssvc_tracker_ctx->glue);
-
- g_object_unref(mdssvc_tracker_ctx->gmain_ctx);
- mdssvc_tracker_ctx->gmain_ctx = NULL;
- return true;
-}
-
-static int mds_tracker_ctx_destructor(struct mds_tracker_ctx *ctx)
-{
- /*
- * Don't g_object_unref() the connection if there's an async request
- * pending, it's used in the async callback and will be unreferenced
- * there.
- */
- if (ctx->async_pending) {
- g_cancellable_cancel(ctx->gcancellable);
- ctx->gcancellable = NULL;
- return 0;
- }
-
- if (ctx->tracker_con == NULL) {
- return 0;
- }
- g_object_unref(ctx->tracker_con);
- ctx->tracker_con = NULL;
-
- return 0;
-}
-
-static bool mds_tracker_connect(struct mds_ctx *mds_ctx)
-{
- struct mds_tracker_ctx *ctx = NULL;
- bool ok;
-
- ok = mdssvc_tracker_prepare();
- if (!ok) {
- return false;
- }
-
- ctx = talloc_zero(mds_ctx, struct mds_tracker_ctx);
- if (ctx == NULL) {
- return false;
- }
- talloc_set_destructor(ctx, mds_tracker_ctx_destructor);
-
- ctx->mds_ctx = mds_ctx;
-
- ctx->gcancellable = g_cancellable_new();
- if (ctx->gcancellable == NULL) {
- DBG_ERR("error from g_cancellable_new\n");
- TALLOC_FREE(ctx);
- return false;
- }
-
- tracker_sparql_connection_get_async(ctx->gcancellable,
- tracker_con_cb,
- ctx);
- ctx->async_pending = true;
-
- mds_ctx->backend_private = ctx;
-
- return true;
-}
-
-static int tq_destructor(struct sl_tracker_query *tq)
-{
- /*
- * Don't g_object_unref() the cursor if there's an async request
- * pending, it's used in the async callback and will be unreferenced
- * there.
- */
- if (tq->async_pending) {
- g_cancellable_cancel(tq->gcancellable);
- tq->gcancellable = NULL;
- return 0;
- }
-
- if (tq->cursor == NULL) {
- return 0;
- }
- g_object_unref(tq->cursor);
- tq->cursor = NULL;
- return 0;
-}
-
-static bool mds_tracker_search_start(struct sl_query *slq)
-{
- struct mds_tracker_ctx *tmds_ctx = talloc_get_type_abort(
- slq->mds_ctx->backend_private, struct mds_tracker_ctx);
- struct sl_tracker_query *tq = NULL;
- char *escaped_scope = NULL;
- bool ok;
-
- if (tmds_ctx->tracker_con == NULL) {
- DBG_ERR("no connection to Tracker\n");
- return false;
- }
-
- tq = talloc_zero(slq, struct sl_tracker_query);
- if (tq == NULL) {
- return false;
- }
- tq->slq = slq;
- talloc_set_destructor(tq, tq_destructor);
-
- tq->gcancellable = g_cancellable_new();
- if (tq->gcancellable == NULL) {
- DBG_ERR("g_cancellable_new() failed\n");
- goto error;
- }
-
- escaped_scope = g_uri_escape_string(
- slq->path_scope,
- G_URI_RESERVED_CHARS_ALLOWED_IN_PATH,
- TRUE);
- if (escaped_scope == NULL) {
- goto error;
- }
-
- tq->path_scope = talloc_strdup(tq, escaped_scope);
- g_free(escaped_scope);
- escaped_scope = NULL;
- if (tq->path_scope == NULL) {
- goto error;
- }
-
- slq->backend_private = tq;
-
- ok = map_spotlight_to_sparql_query(slq);
- if (!ok) {
- /*
- * Two cases:
- *
- * 1) the query string is "false", the parser returns
- * an error for that. We're supposed to return -1
- * here.
- *
- * 2) the parsing really failed, in that case we're
- * probably supposed to return -1 too, this needs
- * verification though
- */
- goto error;
- }
-
- DBG_DEBUG("SPARQL query: \"%s\"\n", tq->sparql_query);
-
- tracker_sparql_connection_query_async(tmds_ctx->tracker_con,
- tq->sparql_query,
- tq->gcancellable,
- tracker_query_cb,
- tq);
- tq->async_pending = true;
-
- slq->state = SLQ_STATE_RUNNING;
- return true;
-error:
- g_object_unref(tq->gcancellable);
- TALLOC_FREE(tq);
- slq->backend_private = NULL;
- return false;
-}
-
-static bool mds_tracker_search_cont(struct sl_query *slq)
-{
- struct sl_tracker_query *tq = talloc_get_type_abort(
- slq->backend_private, struct sl_tracker_query);
-
- tracker_sparql_cursor_next_async(tq->cursor,
- tq->gcancellable,
- tracker_cursor_cb,
- tq);
- tq->async_pending = true;
-
- return true;
-}
-
-struct mdssvc_backend mdsscv_backend_tracker = {
- .init = mdssvc_tracker_init,
- .shutdown = mdssvc_tracker_shutdown,
- .connect = mds_tracker_connect,
- .search_start = mds_tracker_search_start,
- .search_cont = mds_tracker_search_cont,
-};
+++ /dev/null
-/*
- Unix SMB/CIFS implementation.
- Main metadata server / Spotlight routines / Tracker backend
-
- Copyright (C) Ralph Boehme 2019
-
- This program 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.
-
- This program 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/>.
-*/
-
-/* allow building with --enable-developer */
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-qual"
-#include <gio/gio.h>
-#include <tracker-sparql.h>
-#pragma GCC diagnostic pop
-
-/* Global */
-struct mdssvc_tracker_ctx {
- struct mdssvc_ctx *mdssvc_ctx;
- GMainContext *gmain_ctx;
- struct tevent_glib_glue *glue;
-};
-
-/* Per tree connect state */
-struct mds_tracker_ctx {
- struct mds_ctx *mds_ctx;
- GCancellable *gcancellable;
- bool async_pending;
- TrackerSparqlConnection *tracker_con;
-};
-
-/* Per query */
-struct sl_tracker_query {
- struct sl_query *slq;
- const char *path_scope;
- const char *sparql_query;
-
- /*
- * Notes on the lifetime of cursor: we hold a reference on the object
- * and have to call g_object_unref(cursor) at the right place. This is
- * either done in the talloc destructor on a struct sl_tracker_query
- * talloc object when there are no tracker glib async requests
- * running. Or in the glib callback after cancelling the glib async
- * request.
- */
- TrackerSparqlCursor *cursor;
- GCancellable *gcancellable;
- bool async_pending;
-};
-
-extern struct mdssvc_backend mdsscv_backend_tracker;
+++ /dev/null
-/*
- Unix SMB/CIFS implementation.
- Main metadata server / Spotlight routines
-
- Copyright (C) Ralph Boehme 2012-2014
-
- This program 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.
-
- This program 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/>.
-*/
-
-%{
-#include "includes.h"
-#include "rpc_server/mdssvc/sparql_parser.tab.h"
-
-#define YY_NO_INPUT
-%}
-
-%option nounput noyyalloc noyyrealloc prefix="mdsyy"
-
-ASC [a-zA-Z0-9_\*\:\-\.]
-U [\x80-\xbf]
-U2 [\xc2-\xdf]
-U3 [\xe0-\xef]
-U4 [\xf0-\xf4]
-
-UANY {ASC}|{U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U}
-UONLY {U2}{U}|{U3}{U}{U}|{U4}{U}{U}{U}
-
-%%
-InRange return FUNC_INRANGE;
-\$time\.iso return DATE_ISO;
-false {mdsyylval.bval = false; return BOOL;}
-true {mdsyylval.bval = true; return BOOL;}
-\" return QUOTE;
-\( return OBRACE;
-\) return CBRACE;
-\&\& return AND;
-\|\| return OR;
-\=\= return EQUAL;
-\!\= return UNEQUAL;
-\= return EQUAL;
-\< return LT;
-\> return GT;
-\, return COMMA;
-{UANY}+ {mdsyylval.sval = talloc_strdup(talloc_tos(), mdsyytext); return WORD;}
-[ \t\n] /* ignore */
-%%
-
-void *yyalloc(yy_size_t bytes)
-{
- return SMB_MALLOC(bytes);
-}
-
-void *yyrealloc(void *ptr, yy_size_t bytes)
-{
- return SMB_REALLOC(ptr, bytes);
-}
+++ /dev/null
-/*
- Unix SMB/CIFS implementation.
- Main metadata server / Spotlight routines
-
- Copyright (C) Ralph Boehme 2012-2014
-
- This program 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.
-
- This program 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/>.
-*/
-
-#include "replace.h"
-#include "sparql_mapping.h"
-
-const struct sl_attr_map *sl_attr_map_by_spotlight(const char *sl_attr)
-{
- static const struct sl_attr_map spotlight_sparql_attr_map[] = {
- {
- .spotlight_attr = "*",
- .type = ssmt_fts,
- .sparql_attr = "fts:match",
- },
-
- /* Filesystem metadata */
- {
- .spotlight_attr = "kMDItemFSLabel",
- .type = ssmt_num,
- .sparql_attr = NULL,
- },
- {
- .spotlight_attr = "kMDItemDisplayName",
- .type = ssmt_str,
- .sparql_attr = "nfo:fileName",
- },
- {
- .spotlight_attr = "kMDItemFSName",
- .type = ssmt_str,
- .sparql_attr = "nfo:fileName",
- },
- {
- .spotlight_attr = "kMDItemFSContentChangeDate",
- .type = ssmt_date,
- .sparql_attr = "nfo:fileLastModified",
- },
- {
- .spotlight_attr = "kMDItemLastUsedDate",
- .type = ssmt_date,
- .sparql_attr = "nfo:fileLastAccessed",
- },
-
- /* Common metadata */
- {
- .spotlight_attr = "kMDItemTextContent",
- .type = ssmt_fts,
- .sparql_attr = "fts:match",
- },
- {
- .spotlight_attr = "kMDItemContentCreationDate",
- .type = ssmt_date,
- .sparql_attr = "nie:contentCreated",
- },
- {
- .spotlight_attr = "kMDItemContentModificationDate",
- .type = ssmt_date,
- .sparql_attr = "nfo:fileLastModified",
- },
- {
- .spotlight_attr = "kMDItemAttributeChangeDate",
- .type = ssmt_date,
- .sparql_attr = "nfo:fileLastModified",
- },
- {
- .spotlight_attr = "kMDItemAuthors",
- .type = ssmt_str,
- .sparql_attr = "dc:creator",
- },
- {
- .spotlight_attr = "kMDItemCopyright",
- .type = ssmt_str,
- .sparql_attr = "nie:copyright",
- },
- {
- .spotlight_attr = "kMDItemCountry",
- .type = ssmt_str,
- .sparql_attr = "nco:country",
- },
- {
- .spotlight_attr = "kMDItemCreator",
- .type = ssmt_str,
- .sparql_attr = "dc:creator",
- },
- {
- .spotlight_attr = "kMDItemDurationSeconds",
- .type = ssmt_num,
- .sparql_attr = "nfo:duration",
- },
- {
- .spotlight_attr = "kMDItemNumberOfPages",
- .type = ssmt_num,
- .sparql_attr = "nfo:pageCount",
- },
- {
- .spotlight_attr = "kMDItemTitle",
- .type = ssmt_str,
- .sparql_attr = "nie:title",
- },
- {
- .spotlight_attr = "kMDItemCity",
- .type = ssmt_str,
- .sparql_attr = "nco:locality",
- },
- {
- .spotlight_attr = "kMDItemCoverage",
- .type = ssmt_str,
- .sparql_attr = "nco:locality",
- },
- {
- .spotlight_attr = "_kMDItemGroupId",
- .type = ssmt_type,
- .sparql_attr = NULL,
- },
- {
- .spotlight_attr = "kMDItemContentTypeTree",
- .type = ssmt_type,
- .sparql_attr = NULL,
- },
- {
- .spotlight_attr = "kMDItemContentType",
- .type = ssmt_type,
- .sparql_attr = NULL,
- },
-
- /* Image metadata */
- {
- .spotlight_attr = "kMDItemPixelWidth",
- .type = ssmt_num,
- .sparql_attr = "nfo:width",
- },
- {
- .spotlight_attr = "kMDItemPixelHeight",
- .type = ssmt_num,
- .sparql_attr = "nfo:height",
- },
- {
- .spotlight_attr = "kMDItemColorSpace",
- .type = ssmt_str,
- .sparql_attr = "nexif:colorSpace",
- },
- {
- .spotlight_attr = "kMDItemBitsPerSample",
- .type = ssmt_num,
- .sparql_attr = "nfo:colorDepth",
- },
- {
- .spotlight_attr = "kMDItemFocalLength",
- .type = ssmt_num,
- .sparql_attr = "nmm:focalLength",
- },
- {
- .spotlight_attr = "kMDItemISOSpeed",
- .type = ssmt_num,
- .sparql_attr = "nmm:isoSpeed",
- },
- {
- .spotlight_attr = "kMDItemOrientation",
- .type = ssmt_bool,
- .sparql_attr = "nfo:orientation",
- },
- {
- .spotlight_attr = "kMDItemResolutionWidthDPI",
- .type = ssmt_num,
- .sparql_attr = "nfo:horizontalResolution",
- },
- {
- .spotlight_attr = "kMDItemResolutionHeightDPI",
- .type = ssmt_num,
- .sparql_attr = "nfo:verticalResolution",
- },
- {
- .spotlight_attr = "kMDItemExposureTimeSeconds",
- .type = ssmt_num,
- .sparql_attr = "nmm:exposureTime",
- },
-
- /* Audio metadata */
- {
- .spotlight_attr = "kMDItemComposer",
- .type = ssmt_str,
- .sparql_attr = "nmm:composer",
- },
- {
- .spotlight_attr = "kMDItemMusicalGenre",
- .type = ssmt_str,
- .sparql_attr = "nfo:genre",
- },
- };
- size_t i;
-
- for (i = 0; i < ARRAY_SIZE(spotlight_sparql_attr_map); i++) {
- const struct sl_attr_map *m = &spotlight_sparql_attr_map[i];
- int cmp;
-
- cmp = strcmp(m->spotlight_attr, sl_attr);
- if (cmp == 0) {
- return m;
- }
- }
-
- return NULL;
-}
-
-const struct sl_type_map *sl_type_map_by_spotlight(const char *sl_type)
-{
- static const struct sl_type_map spotlight_sparql_type_map[] = {
- {
- .spotlight_type = "1",
- .type = kMDTypeMapRDF,
- .sparql_type = "http://www.semanticdesktop.org/ontologies/2007/03/22/nmo#Email",
- },
- {
- .spotlight_type = "2",
- .type = kMDTypeMapRDF,
- .sparql_type = "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#Contact",
- },
- {
- .spotlight_type = "3",
- .type = kMDTypeMapNotSup,
- .sparql_type = NULL, /*PrefPane*/
- },
- {
- .spotlight_type = "4",
- .type = kMDTypeMapRDF,
- .sparql_type = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Font",
- },
- {
- .spotlight_type = "5",
- .type = kMDTypeMapRDF,
- .sparql_type = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Bookmark",
- },
- {
- .spotlight_type = "6",
- .type = kMDTypeMapRDF,
- .sparql_type = "http://www.semanticdesktop.org/ontologies/2007/03/22/nco#Contact",
- },
- {
- .spotlight_type = "7",
- .type = kMDTypeMapRDF,
- .sparql_type = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Video",
- },
- {
- .spotlight_type = "8",
- .type = kMDTypeMapRDF,
- .sparql_type = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Executable",
- },
- {
- .spotlight_type = "9",
- .type = kMDTypeMapRDF,
- .sparql_type = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Folder",
- },
- {
- .spotlight_type = "10",
- .type = kMDTypeMapRDF,
- .sparql_type = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Audio",
- },
- {
- .spotlight_type = "11",
- .type = kMDTypeMapMime,
- .sparql_type = "application/pdf",
- },
- {
- .spotlight_type = "12",
- .type = kMDTypeMapRDF,
- .sparql_type = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Presentation",
- },
- {
- .spotlight_type = "13",
- .type = kMDTypeMapRDF,
- .sparql_type = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Image",
- },
- {
- .spotlight_type = "public.jpeg",
- .type = kMDTypeMapMime,
- .sparql_type = "image/jpeg",
- },
- {
- .spotlight_type = "public.tiff",
- .type = kMDTypeMapMime,
- .sparql_type = "image/tiff",
- },
- {
- .spotlight_type = "com.compuserve.gif",
- .type = kMDTypeMapMime,
- .sparql_type = "image/gif",
- },
- {
- .spotlight_type = "public.png",
- .type = kMDTypeMapMime,
- .sparql_type = "image/png",
- },
- {
- .spotlight_type = "com.microsoft.bmp",
- .type = kMDTypeMapMime,
- .sparql_type = "image/bmp",
- },
- {
- .spotlight_type = "public.content",
- .type = kMDTypeMapRDF,
- .sparql_type = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Document",
- },
- {
- .spotlight_type = "public.mp3",
- .type = kMDTypeMapMime,
- .sparql_type = "audio/mpeg",
- },
- {
- .spotlight_type = "public.mpeg-4-audio",
- .type = kMDTypeMapMime,
- .sparql_type = "audio/x-aac",
- },
- {
- .spotlight_type = "com.apple.application",
- .type = kMDTypeMapRDF,
- .sparql_type = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#Software",
- },
- {
- .spotlight_type = "public.text",
- .type = kMDTypeMapRDF,
- .sparql_type = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#TextDocument",
- },
- {
- .spotlight_type = "public.plain-text",
- .type = kMDTypeMapMime,
- .sparql_type = "text/plain",
- },
- {
- .spotlight_type = "public.rtf",
- .type = kMDTypeMapMime,
- .sparql_type = "text/rtf",
- },
- {
- .spotlight_type = "public.html",
- .type = kMDTypeMapMime,
- .sparql_type = "text/html",
- },
- {
- .spotlight_type = "public.xml",
- .type = kMDTypeMapMime,
- .sparql_type = "text/xml",
- },
- {
- .spotlight_type = "public.source-code",
- .type = kMDTypeMapRDF,
- .sparql_type = "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#SourceCode",
- },
- };
- size_t i;
-
- for (i = 0; i < ARRAY_SIZE(spotlight_sparql_type_map); i++) {
- const struct sl_type_map *m = &spotlight_sparql_type_map[i];
- int cmp;
-
- cmp = strcmp(m->spotlight_type, sl_type);
- if (cmp == 0) {
- return m;
- }
- }
-
- return NULL;
-}
+++ /dev/null
-/*
- Copyright (c) 2012 Ralph Boehme
-
- This program 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 2 of the License, or
- (at your option) any later version.
-
- This program 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.
-*/
-
-#ifndef SPOTLIGHT_SPARQL_MAP_H
-#define SPOTLIGHT_SPARQL_MAP_H
-
-enum ssm_type {
- ssmt_bool, /* a boolean value that doesn't requires a SPARQL FILTER */
- ssmt_num, /* a numeric value that requires a SPARQL FILTER */
- ssmt_str, /* a string value that requires a SPARQL FILTER */
- ssmt_fts, /* a string value that will be queried with SPARQL 'fts:match' */
- ssmt_date, /* date values are handled in a special map function map_daterange() */
- ssmt_type /* kMDItemContentType, requires special mapping */
-};
-
-struct sl_attr_map {
- const char *spotlight_attr;
- enum ssm_type type;
- const char *sparql_attr;
-};
-
-enum kMDTypeMap {
- kMDTypeMapNotSup, /* not supported */
- kMDTypeMapRDF, /* query with rdf:type */
- kMDTypeMapMime /* query with nie:mimeType */
-};
-
-struct sl_type_map {
- /*
- * MD query value of attributes '_kMDItemGroupId' and
- * 'kMDItemContentTypeTree
- */
- const char *spotlight_type;
-
- /*
- * Whether SPARQL query must search attribute rdf:type or
- * nie:mime_Type
- */
- enum kMDTypeMap type;
-
- /* the SPARQL query match string */
- const char *sparql_type;
-};
-
-const struct sl_attr_map *sl_attr_map_by_spotlight(const char *sl_attr);
-const struct sl_type_map *sl_type_map_by_spotlight(const char *sl_type);
-#endif
+++ /dev/null
-/*
- Unix SMB/CIFS implementation.
- Main metadata server / Spotlight routines
-
- Copyright (C) Ralph Boehme 2012-2014
-
- This program 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.
-
- This program 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/>.
-*/
-
-%{
- #include "includes.h"
- #include "rpc_server/mdssvc/mdssvc.h"
- #include "rpc_server/mdssvc/mdssvc_tracker.h"
- #include "rpc_server/mdssvc/sparql_parser.tab.h"
- #include "rpc_server/mdssvc/sparql_mapping.h"
-
- #define YYMALLOC SMB_MALLOC
- #define YYREALLOC SMB_REALLOC
-
- struct yy_buffer_state;
- typedef struct yy_buffer_state *YY_BUFFER_STATE;
- extern int mdsyylex (void);
- extern void mdsyyerror (char const *);
- extern void *mdsyyterminate(void);
- extern YY_BUFFER_STATE mdsyy_scan_string( const char *str);
- extern void mdsyy_delete_buffer ( YY_BUFFER_STATE buffer );
-
- /* forward declarations */
- static const char *map_expr(const char *attr, char op, const char *val);
- static const char *map_daterange(const char *dateattr,
- time_t date1, time_t date2);
- static time_t isodate2unix(const char *s);
-
- /* global vars, eg needed by the lexer */
- struct sparql_parser_state {
- TALLOC_CTX *frame;
- YY_BUFFER_STATE s;
- char var;
- const char *result;
- } *global_sparql_parser_state;
-%}
-
-%code provides {
- #include <stdbool.h>
- #include "rpc_server/mdssvc/mdssvc.h"
- #define SPRAW_TIME_OFFSET 978307200
- extern int mdsyywrap(void);
- extern bool map_spotlight_to_sparql_query(struct sl_query *slq);
-}
-
-%union {
- int ival;
- const char *sval;
- bool bval;
- time_t tval;
-}
-
-%define api.prefix {mdsyy}
-%expect 5
-%define parse.error verbose
-
-%type <sval> match expr line function
-%type <tval> date
-
-%token <sval> WORD
-%token <bval> BOOL
-%token FUNC_INRANGE
-%token DATE_ISO
-%token OBRACE CBRACE EQUAL UNEQUAL GT LT COMMA QUOTE
-%left AND
-%left OR
-%%
-
-input:
-/* empty */
-| input line
-;
-
-line:
-expr {
- global_sparql_parser_state->result = $1;
-}
-;
-
-expr:
-BOOL {
- /*
- * We can't properly handle these in expressions, fortunately this
- * is probably only ever used by OS X as sole element in an
- * expression ie "False" (when Finder window selected our share
- * but no search string entered yet). Packet traces showed that OS
- * X Spotlight server then returns a failure (ie -1) which is what
- * we do here too by calling YYABORT.
- */
- YYABORT;
-}
-/*
- * We have "match OR match" and "expr OR expr", because the former is
- * supposed to catch and coalesque expressions of the form
- *
- * MDSattribute1="hello"||MDSattribute2="hello"
- *
- * into a single SPARQL expression for the case where both
- * MDSattribute1 and MDSattribute2 map to the same SPARQL attribute,
- * which is eg the case for "*" and "kMDItemTextContent" which both
- * map to SPARQL "fts:match".
- */
-
-| match OR match {
- if (strcmp($1, $3) != 0) {
- $$ = talloc_asprintf(talloc_tos(), "{ %s } UNION { %s }", $1, $3);
- } else {
- $$ = talloc_asprintf(talloc_tos(), "%s", $1);
- }
-}
-| match {
- $$ = $1;
-}
-| function {
- $$ = $1;
-}
-| OBRACE expr CBRACE {
- $$ = talloc_asprintf(talloc_tos(), "%s", $2);
-}
-| expr AND expr {
- $$ = talloc_asprintf(talloc_tos(), "%s . %s", $1, $3);
-}
-| expr OR expr {
- if (strcmp($1, $3) != 0) {
- $$ = talloc_asprintf(talloc_tos(), "{ %s } UNION { %s }", $1, $3);
- } else {
- $$ = talloc_asprintf(talloc_tos(), "%s", $1);
- }
-}
-;
-
-match:
-WORD EQUAL QUOTE WORD QUOTE {
- $$ = map_expr($1, '=', $4);
- if ($$ == NULL) YYABORT;
-}
-| WORD UNEQUAL QUOTE WORD QUOTE {
- $$ = map_expr($1, '!', $4);
- if ($$ == NULL) YYABORT;
-}
-| WORD LT QUOTE WORD QUOTE {
- $$ = map_expr($1, '<', $4);
- if ($$ == NULL) YYABORT;
-}
-| WORD GT QUOTE WORD QUOTE {
- $$ = map_expr($1, '>', $4);
- if ($$ == NULL) YYABORT;
-}
-| WORD EQUAL QUOTE WORD QUOTE WORD {
- $$ = map_expr($1, '=', $4);
- if ($$ == NULL) YYABORT;
-}
-| WORD UNEQUAL QUOTE WORD QUOTE WORD {
- $$ = map_expr($1, '!', $4);
- if ($$ == NULL) YYABORT;
-}
-| WORD LT QUOTE WORD QUOTE WORD {
- $$ = map_expr($1, '<', $4);
- if ($$ == NULL) YYABORT;
-}
-| WORD GT QUOTE WORD QUOTE WORD {
- $$ = map_expr($1, '>', $4);
- if ($$ == NULL) YYABORT;
-}
-;
-
-function:
-FUNC_INRANGE OBRACE WORD COMMA date COMMA date CBRACE {
- $$ = map_daterange($3, $5, $7);
- if ($$ == NULL) YYABORT;
-}
-;
-
-date:
-DATE_ISO OBRACE WORD CBRACE {$$ = isodate2unix($3);}
-| WORD {$$ = atoi($1) + SPRAW_TIME_OFFSET;}
-;
-
-%%
-
-static time_t isodate2unix(const char *s)
-{
- struct tm tm = {};
- const char *p;
-
- p = strptime(s, "%Y-%m-%dT%H:%M:%SZ", &tm);
- if (p == NULL) {
- return (time_t)-1;
- }
- return mktime(&tm);
-}
-
-static const char *map_daterange(const char *dateattr,
- time_t date1, time_t date2)
-{
- struct sparql_parser_state *s = global_sparql_parser_state;
- int result = 0;
- char *sparql = NULL;
- const struct sl_attr_map *p;
- struct tm *tmp;
- char buf1[64], buf2[64];
-
- if (s->var == 'z') {
- return NULL;
- }
-
- tmp = localtime(&date1);
- if (tmp == NULL) {
- return NULL;
- }
- result = strftime(buf1, sizeof(buf1), "%Y-%m-%dT%H:%M:%SZ", tmp);
- if (result == 0) {
- return NULL;
- }
-
- tmp = localtime(&date2);
- if (tmp == NULL) {
- return NULL;
- }
- result = strftime(buf2, sizeof(buf2), "%Y-%m-%dT%H:%M:%SZ", tmp);
- if (result == 0) {
- return NULL;
- }
-
- p = sl_attr_map_by_spotlight(dateattr);
- if (p == NULL) {
- return NULL;
- }
-
- sparql = talloc_asprintf(talloc_tos(),
- "?obj %s ?%c FILTER (?%c > '%s' && ?%c < '%s')",
- p->sparql_attr,
- s->var,
- s->var,
- buf1,
- s->var,
- buf2);
- if (sparql == NULL) {
- return NULL;
- }
-
- s->var++;
- return sparql;
-}
-
-static char *map_type_search(const char *attr, char op, const char *val)
-{
- char *result = NULL;
- const char *sparqlAttr;
- const struct sl_type_map *p;
-
- p = sl_type_map_by_spotlight(val);
- if (p == NULL) {
- return NULL;
- }
-
- switch (p->type) {
- case kMDTypeMapRDF:
- sparqlAttr = "rdf:type";
- break;
- case kMDTypeMapMime:
- sparqlAttr = "nie:mimeType";
- break;
- default:
- return NULL;
- }
-
- result = talloc_asprintf(talloc_tos(), "?obj %s '%s'",
- sparqlAttr,
- p->sparql_type);
- if (result == NULL) {
- return NULL;
- }
-
- return result;
-}
-
-static const char *map_expr(const char *attr, char op, const char *val)
-{
- struct sparql_parser_state *s = global_sparql_parser_state;
- int result = 0;
- char *sparql = NULL;
- const struct sl_attr_map *p;
- time_t t;
- struct tm *tmp;
- char buf1[64];
- char *q;
- const char *start;
-
- if (s->var == 'z') {
- return NULL;
- }
-
- p = sl_attr_map_by_spotlight(attr);
- if (p == NULL) {
- return NULL;
- }
-
- if ((p->type != ssmt_type) && (p->sparql_attr == NULL)) {
- yyerror("unsupported Spotlight attribute");
- return NULL;
- }
-
- switch (p->type) {
- case ssmt_bool:
- sparql = talloc_asprintf(talloc_tos(), "?obj %s '%s'",
- p->sparql_attr, val);
- if (sparql == NULL) {
- return NULL;
- }
- break;
-
- case ssmt_num:
- sparql = talloc_asprintf(talloc_tos(),
- "?obj %s ?%c FILTER(?%c %c%c '%s')",
- p->sparql_attr,
- s->var,
- s->var,
- op,
- /* append '=' to '!' */
- op == '!' ? '=' : ' ',
- val);
- if (sparql == NULL) {
- return NULL;
- }
- s->var++;
- break;
-
- case ssmt_str:
- q = talloc_strdup(talloc_tos(), "");
- if (q == NULL) {
- return NULL;
- }
- start = val;
- while (*val) {
- if (*val != '*') {
- val++;
- continue;
- }
- if (val > start) {
- q = talloc_strndup_append(q, start, val - start);
- if (q == NULL) {
- return NULL;
- }
- }
- q = talloc_strdup_append(q, ".*");
- if (q == NULL) {
- return NULL;
- }
- val++;
- start = val;
- }
- if (val > start) {
- q = talloc_strndup_append(q, start, val - start);
- if (q == NULL) {
- return NULL;
- }
- }
- sparql = talloc_asprintf(talloc_tos(),
- "?obj %s ?%c "
- "FILTER(regex(?%c, '^%s$', 'i'))",
- p->sparql_attr,
- s->var,
- s->var,
- q);
- TALLOC_FREE(q);
- if (sparql == NULL) {
- return NULL;
- }
- s->var++;
- break;
-
- case ssmt_fts:
- sparql = talloc_asprintf(talloc_tos(), "?obj %s '%s'",
- p->sparql_attr, val);
- if (sparql == NULL) {
- return NULL;
- }
- break;
-
- case ssmt_date:
- t = atoi(val) + SPRAW_TIME_OFFSET;
- tmp = localtime(&t);
- if (tmp == NULL) {
- return NULL;
- }
- result = strftime(buf1, sizeof(buf1),
- "%Y-%m-%dT%H:%M:%SZ", tmp);
- if (result == 0) {
- return NULL;
- }
- sparql = talloc_asprintf(talloc_tos(),
- "?obj %s ?%c FILTER(?%c %c '%s')",
- p->sparql_attr,
- s->var,
- s->var,
- op,
- buf1);
- if (sparql == NULL) {
- return NULL;
- }
- s->var++;
- break;
-
- case ssmt_type:
- sparql = map_type_search(attr, op, val);
- if (sparql == NULL) {
- return NULL;
- }
- break;
-
- default:
- return NULL;
- }
-
- return sparql;
-}
-
-void mdsyyerror(const char *str)
-{
- DEBUG(1, ("mdsyyerror: %s\n", str));
-}
-
-int mdsyywrap(void)
-{
- return 1;
-}
-
-/**
- * Map a Spotlight RAW query string to a SPARQL query string
- **/
-bool map_spotlight_to_sparql_query(struct sl_query *slq)
-{
- struct sl_tracker_query *tq = talloc_get_type_abort(
- slq->backend_private, struct sl_tracker_query);
- struct sparql_parser_state s = {
- .frame = talloc_stackframe(),
- .var = 'a',
- };
- int result;
-
- s.s = mdsyy_scan_string(slq->query_string);
- if (s.s == NULL) {
- TALLOC_FREE(s.frame);
- return false;
- }
- global_sparql_parser_state = &s;
- result = mdsyyparse();
- global_sparql_parser_state = NULL;
- mdsyy_delete_buffer(s.s);
-
- if (result != 0) {
- TALLOC_FREE(s.frame);
- return false;
- }
-
- tq->sparql_query = talloc_asprintf(slq,
- "SELECT ?url WHERE { %s . ?obj nie:url ?url . "
- "FILTER(tracker:uri-is-descendant('file://%s/', ?url)) }",
- s.result, tq->path_scope);
- TALLOC_FREE(s.frame);
- if (tq->sparql_query == NULL) {
- return false;
- }
-
- return true;
-}
+++ /dev/null
-#include "includes.h"
-#include "mdssvc.h"
-#include "rpc_server/mdssvc/sparql_parser.tab.h"
-#include "rpc_server/mdssvc/mdssvc_tracker.h"
-
-/*
- * Examples:
- *
- * $ ./spotlight2sparql '_kMDItemGroupId=="11"'
- * ...
- * $ ./spotlight2sparql '*=="test*"cwd||kMDItemTextContent=="test*"cwd'
- * ...
- */
-
-int main(int argc, char **argv)
-{
- struct sl_tracker_query *tq = NULL;
- bool ok;
- struct sl_query *slq;
-
- if (argc != 2) {
- printf("usage: %s QUERY\n", argv[0]);
- return 1;
- }
-
- slq = talloc_zero(NULL, struct sl_query);
- if (slq == NULL) {
- printf("talloc error\n");
- return 1;
- }
-
- slq->query_string = argv[1];
- slq->path_scope = "/foo/bar";
-
- tq = talloc_zero(slq, struct sl_tracker_query);
- if (tq == NULL) {
- printf("talloc error\n");
- return 1;
- }
- slq->backend_private = tq;
-
- ok = map_spotlight_to_sparql_query(slq);
- printf("%s\n", ok ? tq->sparql_query : "*mapping failed*");
-
- talloc_free(slq);
- return ok ? 0 : 1;
-}
'''
rpc_mdssvc_deps = 'mdssvc samba-util smbd_base '
-if bld.env.spotlight_backend_tracker:
- rpc_mdssvc_sources += '''
- mdssvc/mdssvc_tracker.c
- mdssvc/sparql_mapping.c
- mdssvc/sparql_parser.y
- mdssvc/sparql_lexer.l
- '''
- rpc_mdssvc_deps += 'tevent-glib-glue ' + bld.env['libtracker']
-
if bld.env.spotlight_backend_es:
rpc_mdssvc_sources += '''
mdssvc/mdssvc_es.c
+++ /dev/null
-#!/bin/sh
-
-incdir=$(dirname $0)/../../../testprogs/blackbox
-. $incdir/subunit.sh
-
-failed=0
-TESTNAME="tevent_glib_glue_test"
-
-if [ ! -x $BINDIR/tevent_glib_glue_test ]; then
- subunit_start_test "$TESTNAME"
- subunit_skip_test "$TESTNAME" <<EOF
-Test needs glib2-devel
-EOF
- testok $0 $failed
-fi
-
-testit "$TESTNAME" $VALGRIND $BINDIR/tevent_glib_glue_test ||
- failed=$(expr $failed + 1)
-
-testok $0 $failed
"samba3.resolvconf", "none",
[os.path.join(samba3srcdir, "script/tests/test_resolvconf.sh")])
-plantestsuite("samba3.tevent_glib_glue", "none",
- [os.path.join(samba3srcdir, "script/tests/test_tevent_glib_glue.sh")])
-
plantestsuite("samba3.async_req", "nt4_dc",
[os.path.join(samba3srcdir, "script/tests/test_async_req.sh")])
+++ /dev/null
-/*
- * Copyright (C) 2011, Nokia <ivan.frade@nokia.com>
- * Copyright (C) 2015, Noel Power <nopower@suse.com>
- * Copyright (C) 2016, Ralph Boehme <slow@samba.org.>
- *
- * This library 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 2 of the License, or (at your option) any later version.
- *
- * This library 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 library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- */
-
-#include "includes.h"
-#include "lib/util/debug.h"
-#include "lib/cmdline/cmdline.h"
-#include "param.h"
-/*
- * glib uses TRUE and FALSE which was redefined by "includes.h" to be
- * unusable, undefine so glib can establish its own working
- * replacement.
- */
-#undef TRUE
-#undef FALSE
-#include <glib.h>
-#include <libtracker-sparql/tracker-sparql.h>
-#include "lib/tevent_glib_glue.h"
-
-enum loop_type {TEVENT_LOOP, GLIB_LOOP};
-
-struct test_state {
- enum loop_type loop_type;
- TrackerSparqlConnection *connection;
- GCancellable *cancellable;
- GTimer *timer;
- GMainLoop *loop;
- struct tevent_context *ev;
- struct tevent_glib_glue *glue;
-};
-
-static void cleanup(struct test_state *state)
-{
- g_cancellable_cancel(state->cancellable);
- g_object_unref(state->cancellable);
- g_timer_destroy(state->timer);
- if (state->connection != NULL) {
- g_object_unref(state->connection);
- state->connection = NULL;
- }
- if (state->loop_type == GLIB_LOOP) {
- g_main_loop_quit(state->loop);
- } else {
- samba_tevent_glib_glue_quit(state->glue);
- }
-}
-
-static void cursor_cb(GObject *object,
- GAsyncResult *res,
- gpointer user_data)
-{
- struct test_state *state = talloc_get_type_abort(
- user_data, struct test_state);
- TrackerSparqlCursor *cursor = NULL;
- GError *error = NULL;
- gboolean more_results;
- static gint i = 0;
-
- cursor = TRACKER_SPARQL_CURSOR(object);
- more_results = tracker_sparql_cursor_next_finish(cursor,
- res,
- &error);
- if (error) {
- g_critical("Could not run cursor next: %s", error->message);
-
- if (cursor != NULL) {
- g_object_unref(cursor);
- }
-
- g_error_free(error);
- cleanup(state);
- return;
- }
-
- if (!more_results) {
- g_print("\n");
- g_print("\nAsync cursor next took: %.6f (for all %d results)\n",
- g_timer_elapsed (state->timer, NULL), i);
-
- g_object_unref(cursor);
- cleanup(state);
- return;
- }
-
- if (i++ < 5) {
- int num_cols = tracker_sparql_cursor_get_n_columns(cursor);
- int col;
-
- if (i == 1) {
- g_print("Printing first 5 results:\n");
- }
- for (col = 0; col < num_cols; col++) {
- g_print(" %s ", tracker_sparql_cursor_get_string(
- cursor, col, NULL));
- if (col == num_cols -1 ) {
- g_print("\n");
- }
- }
-
- if (i == 5) {
- g_print(" ...\n");
- g_print(" Printing nothing for remaining results\n");
- }
- }
-
- tracker_sparql_cursor_next_async(cursor,
- state->cancellable,
- cursor_cb,
- state);
-}
-
-static void query_cb(GObject *object,
- GAsyncResult *res,
- gpointer user_data)
-{
- struct test_state *state = talloc_get_type_abort(
- user_data, struct test_state);
- TrackerSparqlCursor *cursor = NULL;
- GError *error = NULL;
-
- g_print("Async query took: %.6f\n", g_timer_elapsed(state->timer, NULL));
-
- cursor = tracker_sparql_connection_query_finish(
- TRACKER_SPARQL_CONNECTION(object),
- res,
- &error);
- if (error) {
- g_critical("Could not run query: %s", error->message);
-
- if (cursor) {
- g_object_unref(cursor);
- }
-
- g_error_free(error);
- cleanup(state);
- return;
- }
-
- g_timer_start(state->timer);
-
- tracker_sparql_cursor_next_async(cursor,
- state->cancellable,
- cursor_cb,
- state);
-}
-
-static void connection_cb(GObject *object,
- GAsyncResult *res,
- gpointer user_data)
-{
- struct test_state *state = talloc_get_type_abort(
- user_data, struct test_state);
- GError *error = NULL;
-
- g_print("Async connection took: %.6f\n",
- g_timer_elapsed(state->timer, NULL));
-
- state->connection = tracker_sparql_connection_get_finish(res, &error);
- if (error) {
- g_critical("Could not connect: %s", error->message);
- g_error_free(error);
- cleanup(state);
- return;
- }
-
- g_timer_start(state->timer);
-
- tracker_sparql_connection_query_async(
- state->connection,
- "SELECT ?name nie:mimeType(?s) nfo:fileName(?s) "
- "WHERE { {?s nie:url ?name}}",
- state->cancellable,
- query_cb,
- state);
-}
-
-static void debug_fn(void *private_data,
- enum tevent_debug_level level,
- const char *fmt,
- va_list ap)
-{
- dbgtext_va(fmt, ap);
-}
-
-int main(int argc, const char **argv)
-{
- TALLOC_CTX *mem_ctx = NULL;
- struct test_state *state = NULL;
- int c;
- poptContext pc;
- bool ok;
- struct poptOption long_options[] = {
- POPT_AUTOHELP
- {
- .longName = "tevent",
- .shortName = 't',
- .argInfo = POPT_ARG_NONE,
- .val = 'v',
- .descrip = "Use tevent loop",
- },
- {
- .longName = "glib",
- .shortName = 'g',
- .argInfo = POPT_ARG_NONE,
- .val = 'g',
- .descrip = "Use glib loop",
- },
- POPT_COMMON_SAMBA
- POPT_COMMON_VERSION
- POPT_TABLEEND
- };
-
- mem_ctx = talloc_new(NULL);
- if (mem_ctx == NULL) {
- exit(1);
- }
-
- state = talloc_zero(mem_ctx, struct test_state);
- if (state == NULL) {
- exit(1);
- }
-
- state->loop_type = TEVENT_LOOP;
-
- smb_init_locale();
-
- ok = samba_cmdline_init(mem_ctx,
- SAMBA_CMDLINE_CONFIG_CLIENT,
- true /* require_smbconf */);
- if (!ok) {
- TALLOC_FREE(mem_ctx);
- exit(1);
- }
-
- pc = samba_popt_get_context(getprogname(),
- argc,
- argv,
- long_options,
- POPT_CONTEXT_KEEP_FIRST);
- if (pc == NULL) {
- TALLOC_FREE(mem_ctx);
- exit(1);
- }
-
- while ((c = poptGetNextOpt(pc)) != -1) {
- switch (c) {
- case 'g':
- state->loop_type = GLIB_LOOP;
- break;
- case 't':
- state->loop_type = TEVENT_LOOP;
- break;
- case POPT_ERROR_BADOPT:
- fprintf(stderr, "\nInvalid option %s: %s\n\n",
- poptBadOption(pc, 0), poptStrerror(c));
- poptPrintUsage(pc, stderr, 0);
- exit(1);
- }
- }
-
- if (state->loop_type == GLIB_LOOP) {
- state->loop = g_main_loop_new(NULL, false);
- } else {
- state->ev = tevent_context_init(mem_ctx);
- if (CHECK_DEBUGLVL(10)) {
- tevent_set_debug(state->ev, debug_fn, NULL);
- }
- state->glue = samba_tevent_glib_glue_create(
- mem_ctx, state->ev, g_main_context_default());
- if (state->glue == NULL) {
- printf("tevent_glib_glue_create failed\n");
- exit(1);
- }
- }
-
- state->timer = g_timer_new();
- state->cancellable = g_cancellable_new();
-
- tracker_sparql_connection_get_async(state->cancellable,
- connection_cb,
- state);
-
- if (state->loop_type == GLIB_LOOP) {
- printf("entering g_main_loop_run\n");
- g_main_loop_run(state->loop);
- } else {
- printf("entering tevent_loop_wait\n");
- tevent_loop_wait(state->ev);
-
- TALLOC_FREE(state->glue);
- TALLOC_FREE(state->ev);
- }
-
- TALLOC_FREE(mem_ctx);
- poptFreeContext(pc);
-
- return 0;
-}
else:
conf.fatal('AFS headers not available, but --with-fake-kaserver was specified')
- if conf.CHECK_CFG(package='glib-2.0',
- args='--cflags --libs',
- msg='Checking for glib-2.0',
- uselib_store="GLIB-2.0"):
- if (conf.CHECK_HEADERS('glib.h', lib='glib-2.0') and conf.CHECK_LIB('glib-2.0', shlib=True)):
- conf.DEFINE('HAVE_GLIB', 1)
-
- if conf.CONFIG_SET('HAVE_GLIB'):
- conf.DEFINE('WITH_TEVENT_GLIB_GLUE', '1')
-
- conf.env['libtracker']=''
- tracker_versions = ['2.0', '1.0', '0.16', '0.14']
-
- for version in tracker_versions:
- testlib = 'tracker-sparql-' + version
- if conf.CHECK_CFG(package=testlib,
- args='--cflags --libs',
- mandatory=False):
- conf.SET_TARGET_TYPE(testlib, 'SYSLIB')
- conf.env['libtracker'] = testlib
- conf.DEFINE('HAVE_TRACKER', '1')
- break
-
- with_spotlight_tracker_backend = (
- conf.CONFIG_SET('HAVE_TRACKER')
- and conf.CONFIG_SET('HAVE_GLIB')
- and conf.env['BISON']
- and conf.env['FLEX']
- and conf.CONFIG_GET('HAVE_UTF8_NORMALISATION')
- )
-
with_spotlight_es_backend = (
conf.CONFIG_SET('HAVE_JSON_OBJECT')
and conf.env['BISON']
if not conf.CONFIG_GET('HAVE_UTF8_NORMALISATION'):
Logs.warn("Missing support for Unicode normalisation. "
"Try installing icu-dev or libicu-devel.")
- if not conf.CONFIG_SET('HAVE_TRACKER'):
- Logs.warn('Missing libtracker-sparql development files for Spotlight backend "tracker"')
- if not conf.CONFIG_SET('HAVE_GLIB'):
- Logs.warn('Missing glib-2.0 development files for Spotlight backend "tracker"')
if not conf.CONFIG_GET('HAVE_JSON_OBJECT'):
Logs.warn('Missing libjansson development files for Spotlight backend "elasticsearch"')
- if with_spotlight_tracker_backend:
- conf.env.spotlight_backend_tracker = True
- backends.append('tracker')
- conf.DEFINE('HAVE_SPOTLIGHT_BACKEND_TRACKER', '1')
-
if with_spotlight_es_backend:
conf.env.spotlight_backend_es = True
backends.append('elasticsearch')
conf.DEFINE('HAVE_SPOTLIGHT_BACKEND_ES', '1')
if (Options.options.with_spotlight is True
- and not conf.env.spotlight_backend_tracker
and not conf.env.spotlight_backend_es):
conf.fatal("Unmet dependencies for Spotlight backends")
bld.SAMBA3_SUBSYSTEM('LIBLSA',
source='lib/lsa.c')
-bld.SAMBA3_SUBSYSTEM('tevent-glib-glue',
- source='lib/tevent_glib_glue.c',
- deps='glib-2.0',
- enabled=bld.CONFIG_SET('WITH_TEVENT_GLIB_GLUE'),
-)
-
bld.SAMBA3_SUBSYSTEM('ADOUBLE',
source='lib/adouble.c',
deps='STRING_REPLACE')
deps='smbconf',
realname='samba/samba3/smbconf.so')
-bld.SAMBA3_BINARY('spotlight2sparql',
- source='''
- rpc_server/mdssvc/sparql_parser_test.c
- rpc_server/mdssvc/sparql_parser.y
- rpc_server/mdssvc/sparql_lexer.l
- rpc_server/mdssvc/sparql_mapping.c''',
- deps='samba3-util talloc ' + bld.env['libtracker'],
- enabled=bld.env.spotlight_backend_tracker,
- install=False)
-
bld.SAMBA3_BINARY('spotlight2es',
source='''
rpc_server/mdssvc/es_parser_test.c
enabled=bld.env.spotlight_backend_es,
install=False)
-bld.SAMBA3_BINARY('tevent_glib_glue_test',
- source='lib/tevent_glib_glue_tests.c',
- deps='''
- talloc
- libsmb
- tevent-glib-glue''',
- enabled=bld.CONFIG_SET('WITH_TEVENT_GLIB_GLUE'),
- for_selftest=True)
-
-bld.SAMBA3_BINARY('tevent_glib_tracker',
- source='utils/async-tracker.c',
- deps='''
- talloc
- libsmb
- CMDLINE_S3
- tevent-glib-glue ''' + bld.env['libtracker'],
- enabled=bld.CONFIG_SET('HAVE_TRACKER') and bld.CONFIG_SET('WITH_TEVENT_GLIB_GLUE'),
- install=False)
-
########################## INCLUDES #################################
bld.RECURSE('auth')