LCOV - code coverage report
Current view: top level - source3/rpc_server/mdssvc - mdssvc_tracker.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 0 224 0.0 %
Date: 2024-06-13 04:01:37 Functions: 0 12 0.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Main metadata server / Spotlight routines / Tracker backend
       4             : 
       5             :    Copyright (C) Ralph Boehme 2019
       6             : 
       7             :    This program is free software; you can redistribute it and/or modify
       8             :    it under the terms of the GNU General Public License as published by
       9             :    the Free Software Foundation; either version 3 of the License, or
      10             :    (at your option) any later version.
      11             : 
      12             :    This program is distributed in the hope that it will be useful,
      13             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :    GNU General Public License for more details.
      16             : 
      17             :    You should have received a copy of the GNU General Public License
      18             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      19             : */
      20             : 
      21             : #include "includes.h"
      22             : #include "lib/util/time_basic.h"
      23             : #include "mdssvc.h"
      24             : #include "mdssvc_tracker.h"
      25             : #include "lib/tevent_glib_glue.h"
      26             : #include "rpc_server/mdssvc/sparql_parser.tab.h"
      27             : 
      28             : #undef DBGC_CLASS
      29             : #define DBGC_CLASS DBGC_RPC_SRV
      30             : 
      31             : static struct mdssvc_tracker_ctx *mdssvc_tracker_ctx;
      32             : 
      33             : /************************************************
      34             :  * Tracker async callbacks
      35             :  ************************************************/
      36             : 
      37           0 : static void tracker_con_cb(GObject *object,
      38             :                            GAsyncResult *res,
      39             :                            gpointer user_data)
      40             : {
      41           0 :         struct mds_tracker_ctx *ctx = NULL;
      42           0 :         TrackerSparqlConnection *tracker_con = NULL;
      43           0 :         GError *error = NULL;
      44             : 
      45           0 :         tracker_con = tracker_sparql_connection_get_finish(res, &error);
      46           0 :         if (error && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
      47             :                 /*
      48             :                  * If the async request was cancelled, user_data will already be
      49             :                  * talloc_free'd, so we must be carefully checking for
      50             :                  * G_IO_ERROR_CANCELLED before using user_data.
      51             :                  */
      52           0 :                 DBG_ERR("Tracker connection cancelled\n");
      53           0 :                 g_error_free(error);
      54           0 :                 return;
      55             :         }
      56             :         /*
      57             :          * Ok, we're not canclled, we can now safely use user_data.
      58             :          */
      59           0 :         ctx = talloc_get_type_abort(user_data, struct mds_tracker_ctx);
      60           0 :         ctx->async_pending = false;
      61             :         /*
      62             :          * Check error again, above we only checked for G_IO_ERROR_CANCELLED.
      63             :          */
      64           0 :         if (error) {
      65           0 :                 DBG_ERR("Could not connect to Tracker: %s\n", error->message);
      66           0 :                 g_error_free(error);
      67           0 :                 return;
      68             :         }
      69             : 
      70           0 :         ctx->tracker_con = tracker_con;
      71             : 
      72           0 :         DBG_DEBUG("connected to Tracker\n");
      73             : }
      74             : 
      75             : static void tracker_cursor_cb(GObject *object,
      76             :                               GAsyncResult *res,
      77             :                               gpointer user_data);
      78             : 
      79           0 : static void tracker_query_cb(GObject *object,
      80             :                              GAsyncResult *res,
      81             :                              gpointer user_data)
      82             : {
      83           0 :         struct sl_tracker_query *tq = NULL;
      84           0 :         struct sl_query *slq = NULL;
      85           0 :         TrackerSparqlConnection *conn = NULL;
      86           0 :         TrackerSparqlCursor *cursor = NULL;
      87           0 :         GError *error = NULL;
      88             : 
      89           0 :         conn = TRACKER_SPARQL_CONNECTION(object);
      90             : 
      91           0 :         cursor = tracker_sparql_connection_query_finish(conn, res, &error);
      92             :         /*
      93             :          * If the async request was cancelled, user_data will already be
      94             :          * talloc_free'd, so we must be carefully checking for
      95             :          * G_IO_ERROR_CANCELLED before using user_data.
      96             :          */
      97           0 :         if (error && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
      98           0 :                 DBG_ERR("Tracker query cancelled\n");
      99           0 :                 if (cursor != NULL) {
     100           0 :                         g_object_unref(cursor);
     101             :                 }
     102           0 :                 g_error_free(error);
     103           0 :                 return;
     104             :         }
     105             :         /*
     106             :          * Ok, we're not cancelled, we can now safely use user_data.
     107             :          */
     108           0 :         tq = talloc_get_type_abort(user_data, struct sl_tracker_query);
     109           0 :         tq->async_pending = false;
     110           0 :         slq = tq->slq;
     111             :         /*
     112             :          * Check error again, above we only checked for G_IO_ERROR_CANCELLED.
     113             :          */
     114           0 :         if (error) {
     115           0 :                 DBG_ERR("Tracker query error: %s\n", error->message);
     116           0 :                 g_error_free(error);
     117           0 :                 slq->state = SLQ_STATE_ERROR;
     118           0 :                 return;
     119             :         }
     120             : 
     121           0 :         tq->cursor = cursor;
     122           0 :         slq->state = SLQ_STATE_RESULTS;
     123             : 
     124           0 :         tracker_sparql_cursor_next_async(tq->cursor,
     125             :                                          tq->gcancellable,
     126             :                                          tracker_cursor_cb,
     127             :                                          tq);
     128           0 :         tq->async_pending = true;
     129             : }
     130             : 
     131           0 : static char *tracker_to_unix_path(TALLOC_CTX *mem_ctx, const char *uri)
     132             : {
     133           0 :         GFile *f = NULL;
     134           0 :         char *path = NULL;
     135           0 :         char *talloc_path = NULL;
     136             : 
     137           0 :         f = g_file_new_for_uri(uri);
     138           0 :         if (f == NULL) {
     139           0 :                 return NULL;
     140             :         }
     141             : 
     142           0 :         path = g_file_get_path(f);
     143           0 :         g_object_unref(f);
     144             : 
     145           0 :         if (path == NULL) {
     146           0 :                 return NULL;
     147             :         }
     148             : 
     149           0 :         talloc_path = talloc_strdup(mem_ctx, path);
     150           0 :         g_free(path);
     151           0 :         if (talloc_path == NULL) {
     152           0 :                 return NULL;
     153             :         }
     154             : 
     155           0 :         return talloc_path;
     156             : }
     157             : 
     158           0 : static void tracker_cursor_cb(GObject *object,
     159             :                               GAsyncResult *res,
     160             :                               gpointer user_data)
     161             : {
     162           0 :         TrackerSparqlCursor *cursor = NULL;
     163           0 :         struct sl_tracker_query *tq = NULL;
     164           0 :         struct sl_query *slq = NULL;
     165           0 :         const gchar *uri = NULL;
     166           0 :         GError *error = NULL;
     167           0 :         char *path = NULL;
     168             :         gboolean more_results;
     169             :         bool ok;
     170             : 
     171           0 :         cursor = TRACKER_SPARQL_CURSOR(object);
     172           0 :         more_results = tracker_sparql_cursor_next_finish(cursor,
     173             :                                                          res,
     174             :                                                          &error);
     175             :         /*
     176             :          * If the async request was cancelled, user_data will already be
     177             :          * talloc_free'd, so we must be carefully checking for
     178             :          * G_IO_ERROR_CANCELLED before using user_data.
     179             :          */
     180           0 :         if (error && g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
     181           0 :                 g_error_free(error);
     182           0 :                 g_object_unref(cursor);
     183           0 :                 return;
     184             :         }
     185             :         /*
     186             :          * Ok, we're not canclled, we can now safely use user_data.
     187             :          */
     188           0 :         tq = talloc_get_type_abort(user_data, struct sl_tracker_query);
     189           0 :         tq->async_pending = false;
     190           0 :         slq = tq->slq;
     191             :         /*
     192             :          * Check error again, above we only checked for G_IO_ERROR_CANCELLED.
     193             :          */
     194           0 :         if (error) {
     195           0 :                 DBG_ERR("Tracker cursor: %s\n", error->message);
     196           0 :                 g_error_free(error);
     197           0 :                 slq->state = SLQ_STATE_ERROR;
     198           0 :                 return;
     199             :         }
     200             : 
     201           0 :         SLQ_DEBUG(10, slq, "results");
     202             : 
     203           0 :         if (!more_results) {
     204           0 :                 slq->state = SLQ_STATE_DONE;
     205             : 
     206           0 :                 g_object_unref(tq->cursor);
     207           0 :                 tq->cursor = NULL;
     208             : 
     209           0 :                 g_object_unref(tq->gcancellable);
     210           0 :                 tq->gcancellable = NULL;
     211           0 :                 return;
     212             :         }
     213             : 
     214           0 :         uri = tracker_sparql_cursor_get_string(tq->cursor, 0, NULL);
     215           0 :         if (uri == NULL) {
     216           0 :                 DBG_ERR("error fetching Tracker URI\n");
     217           0 :                 slq->state = SLQ_STATE_ERROR;
     218           0 :                 return;
     219             :         }
     220             : 
     221           0 :         path = tracker_to_unix_path(slq->query_results, uri);
     222           0 :         if (path == NULL) {
     223           0 :                 DBG_ERR("error converting Tracker URI to path: %s\n", uri);
     224           0 :                 slq->state = SLQ_STATE_ERROR;
     225           0 :                 return;
     226             :         }
     227             : 
     228           0 :         ok = mds_add_result(slq, path);
     229           0 :         if (!ok) {
     230           0 :                 DBG_ERR("error adding result for path: %s\n", uri);
     231           0 :                 slq->state = SLQ_STATE_ERROR;
     232           0 :                 return;
     233             :         }
     234             : 
     235           0 :         if (slq->query_results->num_results >= MAX_SL_RESULTS) {
     236           0 :                 slq->state = SLQ_STATE_FULL;
     237           0 :                 SLQ_DEBUG(10, slq, "full");
     238           0 :                 return;
     239             :         }
     240             : 
     241           0 :         slq->state = SLQ_STATE_RESULTS;
     242           0 :         SLQ_DEBUG(10, slq, "cursor next");
     243             : 
     244           0 :         tracker_sparql_cursor_next_async(tq->cursor,
     245             :                                          tq->gcancellable,
     246             :                                          tracker_cursor_cb,
     247             :                                          tq);
     248           0 :         tq->async_pending = true;
     249             : }
     250             : 
     251             : /*
     252             :  * This gets called once, even if the backend is not configured by the user
     253             :  */
     254           0 : static bool mdssvc_tracker_init(struct mdssvc_ctx *mdssvc_ctx)
     255             : {
     256           0 :         if (mdssvc_tracker_ctx != NULL) {
     257           0 :                 return true;
     258             :         }
     259             : 
     260             : #if (GLIB_MAJOR_VERSION < 3) && (GLIB_MINOR_VERSION < 36)
     261             :         g_type_init();
     262             : #endif
     263             : 
     264           0 :         mdssvc_tracker_ctx = talloc_zero(mdssvc_ctx, struct mdssvc_tracker_ctx);
     265           0 :         if (mdssvc_tracker_ctx == NULL) {
     266           0 :                 return false;
     267             :         }
     268           0 :         mdssvc_tracker_ctx->mdssvc_ctx = mdssvc_ctx;
     269             : 
     270           0 :         return true;
     271             : }
     272             : 
     273             : /*
     274             :  * This gets called per mdscmd_open / tcon. This runs initialisation code that
     275             :  * should only run if the tracker backend is actually used.
     276             :  */
     277           0 : static bool mdssvc_tracker_prepare(void)
     278             : {
     279           0 :         if (mdssvc_tracker_ctx->gmain_ctx != NULL) {
     280             :                 /*
     281             :                  * Assuming everything is setup if gmain_ctx is.
     282             :                  */
     283           0 :                 return true;
     284             :         }
     285             : 
     286           0 :         mdssvc_tracker_ctx->gmain_ctx = g_main_context_new();
     287           0 :         if (mdssvc_tracker_ctx->gmain_ctx == NULL) {
     288           0 :                 DBG_ERR("error from g_main_context_new\n");
     289           0 :                 TALLOC_FREE(mdssvc_tracker_ctx);
     290           0 :                 return false;
     291             :         }
     292             : 
     293           0 :         mdssvc_tracker_ctx->glue = samba_tevent_glib_glue_create(
     294             :                 mdssvc_tracker_ctx,
     295           0 :                 mdssvc_tracker_ctx->mdssvc_ctx->ev_ctx,
     296           0 :                 mdssvc_tracker_ctx->gmain_ctx);
     297           0 :         if (mdssvc_tracker_ctx->glue == NULL) {
     298           0 :                 DBG_ERR("samba_tevent_glib_glue_create failed\n");
     299           0 :                 g_object_unref(mdssvc_tracker_ctx->gmain_ctx);
     300           0 :                 TALLOC_FREE(mdssvc_tracker_ctx);
     301           0 :                 return false;
     302             :         }
     303             : 
     304           0 :         return true;
     305             : }
     306             : 
     307           0 : static bool mdssvc_tracker_shutdown(struct mdssvc_ctx *mdssvc_ctx)
     308             : {
     309           0 :         samba_tevent_glib_glue_quit(mdssvc_tracker_ctx->glue);
     310           0 :         TALLOC_FREE(mdssvc_tracker_ctx->glue);
     311             : 
     312           0 :         g_object_unref(mdssvc_tracker_ctx->gmain_ctx);
     313           0 :         return true;
     314             : }
     315             : 
     316           0 : static int mds_tracker_ctx_destructor(struct mds_tracker_ctx *ctx)
     317             : {
     318             :         /*
     319             :          * Don't g_object_unref() the connection if there's an async request
     320             :          * pending, it's used in the async callback and will be unreferenced
     321             :          * there.
     322             :          */
     323           0 :         if (ctx->async_pending) {
     324           0 :                 g_cancellable_cancel(ctx->gcancellable);
     325           0 :                 ctx->gcancellable = NULL;
     326           0 :                 return 0;
     327             :         }
     328             : 
     329           0 :         if (ctx->tracker_con == NULL) {
     330           0 :                 return 0;
     331             :         }
     332           0 :         g_object_unref(ctx->tracker_con);
     333           0 :         ctx->tracker_con = NULL;
     334             : 
     335           0 :         return 0;
     336             : }
     337             : 
     338           0 : static bool mds_tracker_connect(struct mds_ctx *mds_ctx)
     339             : {
     340           0 :         struct mds_tracker_ctx *ctx = NULL;
     341             :         bool ok;
     342             : 
     343           0 :         ok = mdssvc_tracker_prepare();
     344           0 :         if (!ok) {
     345           0 :                 return false;
     346             :         }
     347             : 
     348           0 :         ctx = talloc_zero(mds_ctx, struct mds_tracker_ctx);
     349           0 :         if (ctx == NULL) {
     350           0 :                 return false;
     351             :         }
     352           0 :         talloc_set_destructor(ctx, mds_tracker_ctx_destructor);
     353             : 
     354           0 :         ctx->mds_ctx = mds_ctx;
     355             : 
     356           0 :         ctx->gcancellable = g_cancellable_new();
     357           0 :         if (ctx->gcancellable == NULL) {
     358           0 :                 DBG_ERR("error from g_cancellable_new\n");
     359           0 :                 TALLOC_FREE(ctx);
     360           0 :                 return false;
     361             :         }
     362             : 
     363           0 :         tracker_sparql_connection_get_async(ctx->gcancellable,
     364             :                                             tracker_con_cb,
     365             :                                             ctx);
     366           0 :         ctx->async_pending = true;
     367             : 
     368           0 :         mds_ctx->backend_private = ctx;
     369             : 
     370           0 :         return true;
     371             : }
     372             : 
     373           0 : static int tq_destructor(struct sl_tracker_query *tq)
     374             : {
     375             :         /*
     376             :          * Don't g_object_unref() the cursor if there's an async request
     377             :          * pending, it's used in the async callback and will be unreferenced
     378             :          * there.
     379             :          */
     380           0 :         if (tq->async_pending) {
     381           0 :                 g_cancellable_cancel(tq->gcancellable);
     382           0 :                 tq->gcancellable = NULL;
     383           0 :                 return 0;
     384             :         }
     385             : 
     386           0 :         if (tq->cursor == NULL) {
     387           0 :                 return 0;
     388             :         }
     389           0 :         g_object_unref(tq->cursor);
     390           0 :         tq->cursor = NULL;
     391           0 :         return 0;
     392             : }
     393             : 
     394           0 : static bool mds_tracker_search_start(struct sl_query *slq)
     395             : {
     396           0 :         struct mds_tracker_ctx *tmds_ctx = talloc_get_type_abort(
     397             :                 slq->mds_ctx->backend_private, struct mds_tracker_ctx);
     398           0 :         struct sl_tracker_query *tq = NULL;
     399           0 :         char *escaped_scope = NULL;
     400             :         bool ok;
     401             : 
     402           0 :         if (tmds_ctx->tracker_con == NULL) {
     403           0 :                 DBG_ERR("no connection to Tracker\n");
     404           0 :                 return false;
     405             :         }
     406             : 
     407           0 :         tq = talloc_zero(slq, struct sl_tracker_query);
     408           0 :         if (tq == NULL) {
     409           0 :                 return false;
     410             :         }
     411           0 :         tq->slq = slq;
     412           0 :         talloc_set_destructor(tq, tq_destructor);
     413             : 
     414           0 :         tq->gcancellable = g_cancellable_new();
     415           0 :         if (tq->gcancellable == NULL) {
     416           0 :                 DBG_ERR("g_cancellable_new() failed\n");
     417           0 :                 goto error;
     418             :         }
     419             : 
     420           0 :         escaped_scope = g_uri_escape_string(
     421             :                                 slq->path_scope,
     422             :                                 G_URI_RESERVED_CHARS_ALLOWED_IN_PATH,
     423             :                                 TRUE);
     424           0 :         if (escaped_scope == NULL) {
     425           0 :                 goto error;
     426             :         }
     427             : 
     428           0 :         tq->path_scope = talloc_strdup(tq, escaped_scope);
     429           0 :         g_free(escaped_scope);
     430           0 :         escaped_scope = NULL;
     431           0 :         if (tq->path_scope == NULL) {
     432           0 :                 goto error;
     433             :         }
     434             : 
     435           0 :         slq->backend_private = tq;
     436             : 
     437           0 :         ok = map_spotlight_to_sparql_query(slq);
     438           0 :         if (!ok) {
     439             :                 /*
     440             :                  * Two cases:
     441             :                  *
     442             :                  * 1) the query string is "false", the parser returns
     443             :                  * an error for that. We're supposed to return -1
     444             :                  * here.
     445             :                  *
     446             :                  * 2) the parsing really failed, in that case we're
     447             :                  * probably supposed to return -1 too, this needs
     448             :                  * verification though
     449             :                  */
     450           0 :                 goto error;
     451             :         }
     452             : 
     453           0 :         DBG_DEBUG("SPARQL query: \"%s\"\n", tq->sparql_query);
     454             : 
     455           0 :         tracker_sparql_connection_query_async(tmds_ctx->tracker_con,
     456           0 :                                               tq->sparql_query,
     457             :                                               tq->gcancellable,
     458             :                                               tracker_query_cb,
     459             :                                               tq);
     460           0 :         tq->async_pending = true;
     461             : 
     462           0 :         slq->state = SLQ_STATE_RUNNING;
     463           0 :         return true;
     464           0 : error:
     465           0 :         g_object_unref(tq->gcancellable);
     466           0 :         TALLOC_FREE(tq);
     467           0 :         slq->backend_private = NULL;
     468           0 :         return false;
     469             : }
     470             : 
     471           0 : static bool mds_tracker_search_cont(struct sl_query *slq)
     472             : {
     473           0 :         struct sl_tracker_query *tq = talloc_get_type_abort(
     474             :                 slq->backend_private, struct sl_tracker_query);
     475             : 
     476           0 :         tracker_sparql_cursor_next_async(tq->cursor,
     477             :                                          tq->gcancellable,
     478             :                                          tracker_cursor_cb,
     479             :                                          tq);
     480           0 :         tq->async_pending = true;
     481             : 
     482           0 :         return true;
     483             : }
     484             : 
     485             : struct mdssvc_backend mdsscv_backend_tracker = {
     486             :         .init = mdssvc_tracker_init,
     487             :         .shutdown = mdssvc_tracker_shutdown,
     488             :         .connect = mds_tracker_connect,
     489             :         .search_start = mds_tracker_search_start,
     490             :         .search_cont = mds_tracker_search_cont,
     491             : };

Generated by: LCOV version 1.13