2 Unix SMB/CIFS implementation.
3 Main metadata server / Spotlight routines
5 Copyright (C) Ralph Boehme 2012-2014
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.
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.
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/>.
22 #include "librpc/gen_ndr/auth.h"
23 #include "dbwrap/dbwrap.h"
24 #include "lib/util/dlinklist.h"
25 #include "lib/util/util_tdb.h"
26 #include "lib/util/time_basic.h"
27 #include "lib/dbwrap/dbwrap_rbt.h"
28 #include "libcli/security/dom_sid.h"
30 #include "sparql_parser.h"
33 #define DBGC_CLASS DBGC_RPC_SRV
35 #define SLQ_DEBUG(lvl, _slq, state) do { if (CHECK_DEBUGLVL(lvl)) { \
36 const struct sl_query *__slq = _slq; \
37 struct timeval_buf start_buf; \
39 struct timeval_buf last_used_buf; \
40 const char *last_used; \
41 struct timeval_buf expire_buf; \
43 start = timeval_str_buf(&__slq->start_time, false, \
45 last_used = timeval_str_buf(&__slq->last_used, false, \
46 true, &last_used_buf); \
47 expire = timeval_str_buf(&__slq->expire_time, false, \
49 DEBUG(lvl,("%s slq[0x%jx,0x%jx], start: %s, last_used: %s, " \
50 "expires: %s, query: '%s'\n", state, \
51 (uintmax_t)__slq->ctx1, (uintmax_t)__slq->ctx2, \
52 start, last_used, expire, __slq->query_string)); \
57 bool (*function
)(struct mds_ctx
*mds_ctx
,
58 const DALLOC_CTX
*query
,
62 struct slq_destroy_state
{
63 struct tevent_context
*ev
;
68 * If these functions return an error, they hit something like a non
69 * recoverable talloc error. Most errors are dealt with by returning
70 * an errror code in the Spotlight RPC reply.
72 static bool slrpc_fetch_properties(struct mds_ctx
*mds_ctx
,
73 const DALLOC_CTX
*query
, DALLOC_CTX
*reply
);
74 static bool slrpc_open_query(struct mds_ctx
*mds_ctx
,
75 const DALLOC_CTX
*query
, DALLOC_CTX
*reply
);
76 static bool slrpc_fetch_query_results(struct mds_ctx
*mds_ctx
,
77 const DALLOC_CTX
*query
, DALLOC_CTX
*reply
);
78 static bool slrpc_store_attributes(struct mds_ctx
*mds_ctx
,
79 const DALLOC_CTX
*query
, DALLOC_CTX
*reply
);
80 static bool slrpc_fetch_attributenames(struct mds_ctx
*mds_ctx
,
81 const DALLOC_CTX
*query
, DALLOC_CTX
*reply
);
82 static bool slrpc_fetch_attributes(struct mds_ctx
*mds_ctx
,
83 const DALLOC_CTX
*query
, DALLOC_CTX
*reply
);
84 static bool slrpc_close_query(struct mds_ctx
*mds_ctx
,
85 const DALLOC_CTX
*query
, DALLOC_CTX
*reply
);
87 static struct tevent_req
*slq_destroy_send(TALLOC_CTX
*mem_ctx
,
88 struct tevent_context
*ev
,
89 struct sl_query
**slq
)
91 struct tevent_req
*req
;
92 struct slq_destroy_state
*state
;
94 req
= tevent_req_create(mem_ctx
, &state
,
95 struct slq_destroy_state
);
99 state
->slq
= talloc_move(state
, slq
);
100 tevent_req_done(req
);
102 return tevent_req_post(req
, ev
);
105 static void slq_destroy_recv(struct tevent_req
*req
)
107 tevent_req_received(req
);
110 /************************************************
111 * Misc utility functions
112 ************************************************/
114 static char *tab_level(TALLOC_CTX
*mem_ctx
, int level
)
117 char *string
= talloc_array(mem_ctx
, char, level
+ 1);
119 for (i
= 0; i
< level
; i
++) {
127 char *mds_dalloc_dump(DALLOC_CTX
*dd
, int nestinglevel
)
135 char datestring
[256];
137 char *logstring
, *nested_logstring
;
138 char *tab_string1
, *tab_string2
;
144 tab_string1
= tab_level(dd
, nestinglevel
);
145 if (tab_string1
== NULL
) {
148 tab_string2
= tab_level(dd
, nestinglevel
+ 1);
149 if (tab_string2
== NULL
) {
153 logstring
= talloc_asprintf(dd
,
158 if (logstring
== NULL
) {
162 for (n
= 0; n
< dalloc_size(dd
); n
++) {
163 type
= dalloc_get_name(dd
, n
);
167 p
= dalloc_get_object(dd
, n
);
171 if (strcmp(type
, "DALLOC_CTX") == 0
172 || strcmp(type
, "sl_array_t") == 0
173 || strcmp(type
, "sl_filemeta_t") == 0
174 || strcmp(type
, "sl_dict_t") == 0) {
175 nested_logstring
= mds_dalloc_dump(p
, nestinglevel
+ 1);
176 if (nested_logstring
== NULL
) {
179 logstring
= talloc_strdup_append(logstring
,
181 } else if (strcmp(type
, "uint64_t") == 0) {
182 memcpy(&i
, p
, sizeof(uint64_t));
183 logstring
= talloc_asprintf_append(
185 "%suint64_t: 0x%04jx\n",
186 tab_string2
, (uintmax_t)i
);
187 } else if (strcmp(type
, "char *") == 0) {
188 logstring
= talloc_asprintf_append(
193 } else if (strcmp(type
, "smb_ucs2_t *") == 0) {
194 ok
= convert_string_talloc(talloc_tos(),
204 logstring
= talloc_asprintf_append(
206 "%sUTF16-string: %s\n",
209 TALLOC_FREE(utf8string
);
210 } else if (strcmp(type
, "sl_bool_t") == 0) {
211 memcpy(&bl
, p
, sizeof(sl_bool_t
));
212 logstring
= talloc_asprintf_append(
216 bl
? "true" : "false");
217 } else if (strcmp(type
, "sl_nil_t") == 0) {
218 logstring
= talloc_asprintf_append(
222 } else if (strcmp(type
, "sl_time_t") == 0) {
223 memcpy(&t
, p
, sizeof(sl_time_t
));
224 tm
= localtime(&t
.tv_sec
);
228 result
= strftime(datestring
,
230 "%Y-%m-%d %H:%M:%S", tm
);
234 logstring
= talloc_asprintf_append(
236 "%ssl_time_t: %s.%06lu\n",
239 (unsigned long)t
.tv_usec
);
240 } else if (strcmp(type
, "sl_cnids_t") == 0) {
241 memcpy(&cnids
, p
, sizeof(sl_cnids_t
));
242 logstring
= talloc_asprintf_append(
244 "%sCNIDs: unkn1: 0x%" PRIx16
", unkn2: 0x%" PRIx32
"\n",
248 if (logstring
== NULL
) {
251 if (cnids
.ca_cnids
) {
252 nested_logstring
= mds_dalloc_dump(
255 if (!nested_logstring
) {
258 logstring
= talloc_strdup_append(logstring
,
262 logstring
= talloc_asprintf_append(
268 if (logstring
== NULL
) {
272 logstring
= talloc_asprintf_append(logstring
,
275 if (logstring
== NULL
) {
281 static char *tracker_to_unix_path(TALLOC_CTX
*mem_ctx
, const char *uri
)
287 f
= g_file_new_for_uri(uri
);
292 path
= g_file_get_path(f
);
299 talloc_path
= talloc_strdup(mem_ctx
, path
);
301 if (talloc_path
== NULL
) {
309 * Add requested metadata for a query result element
311 * This could be rewritten to something more sophisticated like
312 * querying metadata from Tracker.
314 * If path or sp is NULL, simply add nil values for all attributes.
316 static bool add_filemeta(sl_array_t
*reqinfo
,
317 sl_array_t
*fm_array
,
319 const struct stat_ex
*sp
)
323 int i
, metacount
, result
;
327 const char *attribute
;
329 metacount
= dalloc_size(reqinfo
);
330 if (metacount
== 0 || path
== NULL
|| sp
== NULL
) {
331 result
= dalloc_add_copy(fm_array
, &nil
, sl_nil_t
);
338 meta
= dalloc_zero(fm_array
, sl_array_t
);
343 for (i
= 0; i
< metacount
; i
++) {
344 attribute
= dalloc_get_object(reqinfo
, i
);
345 if (attribute
== NULL
) {
348 if (strcmp(attribute
, "kMDItemDisplayName") == 0
349 || strcmp(attribute
, "kMDItemFSName") == 0) {
350 p
= strrchr(path
, '/');
352 result
= dalloc_stradd(meta
, p
+ 1);
357 } else if (strcmp(attribute
, "kMDItemPath") == 0) {
358 result
= dalloc_stradd(meta
, path
);
362 } else if (strcmp(attribute
, "kMDItemFSSize") == 0) {
363 uint64var
= sp
->st_ex_size
;
364 result
= dalloc_add_copy(meta
, &uint64var
, uint64_t);
368 } else if (strcmp(attribute
, "kMDItemFSOwnerUserID") == 0) {
369 uint64var
= sp
->st_ex_uid
;
370 result
= dalloc_add_copy(meta
, &uint64var
, uint64_t);
374 } else if (strcmp(attribute
, "kMDItemFSOwnerGroupID") == 0) {
375 uint64var
= sp
->st_ex_gid
;
376 result
= dalloc_add_copy(meta
, &uint64var
, uint64_t);
380 } else if (strcmp(attribute
, "kMDItemFSContentChangeDate") == 0) {
381 sl_time
.tv_sec
= sp
->st_ex_mtime
.tv_sec
;
382 result
= dalloc_add_copy(meta
, &sl_time
, sl_time_t
);
387 result
= dalloc_add_copy(meta
, &nil
, sl_nil_t
);
394 result
= dalloc_add(fm_array
, meta
, sl_array_t
);
401 static int cnid_comp_fn(const void *p1
, const void *p2
)
403 const uint64_t *cnid1
= p1
, *cnid2
= p2
;
404 if (*cnid1
== *cnid2
) {
407 if (*cnid1
< *cnid2
) {
414 * Create a sorted copy of a CNID array
416 static bool sort_cnids(struct sl_query
*slq
, const DALLOC_CTX
*d
)
418 uint64_t *cnids
= NULL
;
422 cnids
= talloc_array(slq
, uint64_t, dalloc_size(d
));
427 for (i
= 0; i
< dalloc_size(d
); i
++) {
428 p
= dalloc_get_object(d
, i
);
432 memcpy(&cnids
[i
], p
, sizeof(uint64_t));
434 qsort(cnids
, dalloc_size(d
), sizeof(uint64_t), cnid_comp_fn
);
437 slq
->cnids_num
= dalloc_size(d
);
443 * Allocate result handle used in the async Tracker cursor result
444 * handler for storing results
446 static bool create_result_handle(struct sl_query
*slq
)
449 struct sl_rslts
*query_results
;
452 if (slq
->query_results
) {
453 DEBUG(1, ("unexpected existing result handle\n"));
457 query_results
= talloc_zero(slq
, struct sl_rslts
);
458 if (query_results
== NULL
) {
463 query_results
->cnids
= talloc_zero(query_results
, sl_cnids_t
);
464 if (query_results
->cnids
== NULL
) {
467 query_results
->cnids
->ca_cnids
= dalloc_new(query_results
->cnids
);
468 if (query_results
->cnids
->ca_cnids
== NULL
) {
472 query_results
->cnids
->ca_unkn1
= 0xadd;
473 if (slq
->ctx2
> UINT32_MAX
) {
474 DEBUG(1,("64bit ctx2 id too large: 0x%jx", (uintmax_t)slq
->ctx2
));
477 query_results
->cnids
->ca_context
= (uint32_t)slq
->ctx2
;
480 query_results
->fm_array
= dalloc_zero(query_results
, sl_array_t
);
481 if (query_results
->fm_array
== NULL
) {
485 /* For some reason the list of results always starts with a nil entry */
486 result
= dalloc_add_copy(query_results
->fm_array
, &nil
, sl_nil_t
);
491 slq
->query_results
= query_results
;
495 static bool add_results(sl_array_t
*array
, struct sl_query
*slq
)
503 fm
= dalloc_zero(array
, sl_filemeta_t
);
508 result
= dalloc_add_copy(array
, &status
, uint64_t);
512 result
= dalloc_add(array
, slq
->query_results
->cnids
, sl_cnids_t
);
516 if (slq
->query_results
->num_results
> 0) {
517 result
= dalloc_add(fm
, slq
->query_results
->fm_array
, sl_array_t
);
522 result
= dalloc_add(array
, fm
, sl_filemeta_t
);
527 /* This ensure the results get clean up after been sent to the client */
528 talloc_move(array
, &slq
->query_results
);
530 ok
= create_result_handle(slq
);
532 DEBUG(1, ("couldn't add result handle\n"));
533 slq
->state
= SLQ_STATE_ERROR
;
540 static const struct slrpc_cmd
*slrpc_cmd_by_name(const char *rpccmd
)
543 static const struct slrpc_cmd cmds
[] = {
544 { "fetchPropertiesForContext:", slrpc_fetch_properties
},
545 { "openQueryWithParams:forContext:", slrpc_open_query
},
546 { "fetchQueryResultsForContext:", slrpc_fetch_query_results
},
547 { "storeAttributes:forOIDArray:context:", slrpc_store_attributes
},
548 { "fetchAttributeNamesForOIDArray:context:", slrpc_fetch_attributenames
},
549 { "fetchAttributes:forOIDArray:context:", slrpc_fetch_attributes
},
550 { "fetchAllAttributes:forOIDArray:context:", slrpc_fetch_attributes
},
551 { "closeQueryForContext:", slrpc_close_query
},
554 for (i
= 0; i
< ARRAY_SIZE(cmds
); i
++) {
557 cmp
= strcmp(cmds
[i
].name
, rpccmd
);
567 * Search the list of active queries given their context ids
569 static struct sl_query
*slq_for_ctx(struct mds_ctx
*mds_ctx
,
570 uint64_t ctx1
, uint64_t ctx2
)
574 for (q
= mds_ctx
->query_list
; q
; q
= q
->next
) {
575 if ((q
->ctx1
== ctx1
) && (q
->ctx2
== ctx2
)) {
583 static int slq_destructor_cb(struct sl_query
*slq
)
585 SLQ_DEBUG(10, slq
, "destroying");
587 /* Free all entries before freeing the slq handle! */
588 TALLOC_FREE(slq
->entries_ctx
);
589 TALLOC_FREE(slq
->te
);
591 if (slq
->mds_ctx
!= NULL
) {
592 DLIST_REMOVE(slq
->mds_ctx
->query_list
, slq
);
596 if (slq
->tracker_cursor
!= NULL
) {
597 g_object_unref(slq
->tracker_cursor
);
598 slq
->tracker_cursor
= NULL
;
601 if (slq
->gcancellable
!= NULL
) {
602 g_cancellable_cancel(slq
->gcancellable
);
603 g_object_unref(slq
->gcancellable
);
604 slq
->gcancellable
= NULL
;
611 * Remove talloc_refcounted entry from mapping db
613 * Multiple queries (via the slq handle) may reference a
614 * sl_inode_path_map entry, when the last reference goes away as the
615 * queries are closed and this gets called to remove the entry from
618 static int ino_path_map_destr_cb(struct sl_inode_path_map
*entry
)
623 key
= make_tdb_data((uint8_t *)&entry
->ino
, sizeof(entry
->ino
));
625 status
= dbwrap_delete(entry
->mds_ctx
->ino_path_map
, key
);
626 if (!NT_STATUS_IS_OK(status
)) {
627 DEBUG(1, ("Failed to delete record: %s\n", nt_errstr(status
)));
631 DEBUG(10,("deleted: %s\n", entry
->path
));
636 * Add result to inode->path mapping dbwrap rbt db
638 * This is necessary as a CNID db substitute, ie we need a way to
639 * simulate unique, constant numerical identifiers for paths with an
640 * API that supports mapping from id to path.
642 * Entries are talloc'ed of the query, using talloc_reference() if
643 * multiple queries returned the same result. That way we can cleanup
644 * entries by calling talloc_free() on the query slq handles.
647 static bool inode_map_add(struct sl_query
*slq
, uint64_t ino
, const char *path
)
650 struct sl_inode_path_map
*entry
;
654 key
= make_tdb_data((uint8_t *)&ino
, sizeof(ino
));
655 status
= dbwrap_fetch(slq
->mds_ctx
->ino_path_map
, slq
, key
, &value
);
657 if (NT_STATUS_IS_OK(status
)) {
659 * We have one db, so when different parallel queries
660 * return the same file, we have to refcount entries
664 if (value
.dsize
!= sizeof(void *)) {
665 DEBUG(1, ("invalide dsize\n"));
668 memcpy(&p
, value
.dptr
, sizeof(p
));
669 entry
= talloc_get_type_abort(p
, struct sl_inode_path_map
);
671 DEBUG(10, ("map: %s\n", entry
->path
));
673 entry
= talloc_reference(slq
->entries_ctx
, entry
);
675 DEBUG(1, ("talloc_reference failed\n"));
681 if (!NT_STATUS_EQUAL(status
, NT_STATUS_NOT_FOUND
)) {
682 DEBUG(1, ("dbwrap_fetch failed %s\n", nt_errstr(status
)));
686 entry
= talloc_zero(slq
->entries_ctx
, struct sl_inode_path_map
);
688 DEBUG(1, ("talloc failed\n"));
693 entry
->mds_ctx
= slq
->mds_ctx
;
694 entry
->path
= talloc_strdup(entry
, path
);
695 if (entry
->path
== NULL
) {
696 DEBUG(1, ("talloc failed\n"));
701 status
= dbwrap_store(slq
->mds_ctx
->ino_path_map
, key
,
702 make_tdb_data((void *)&entry
, sizeof(void *)), 0);
703 if (!NT_STATUS_IS_OK(status
)) {
704 DEBUG(1, ("Failed to store record: %s\n", nt_errstr(status
)));
709 talloc_set_destructor(entry
, ino_path_map_destr_cb
);
714 /************************************************
715 * Tracker async callbacks
716 ************************************************/
718 static void tracker_con_cb(GObject
*object
,
722 struct mds_ctx
*mds_ctx
= talloc_get_type_abort(user_data
, struct mds_ctx
);
723 GError
*error
= NULL
;
725 mds_ctx
->tracker_con
= tracker_sparql_connection_get_finish(res
,
728 DEBUG(1, ("Could not connect to Tracker: %s\n",
733 DEBUG(10, ("connected to Tracker\n"));
734 g_main_loop_quit(mds_ctx
->gmainloop
);
737 static void tracker_cursor_cb_destroy_done(struct tevent_req
*subreq
);
739 static void tracker_cursor_cb(GObject
*object
,
743 GError
*error
= NULL
;
744 struct sl_query
*slq
= talloc_get_type_abort(user_data
, struct sl_query
);
745 gboolean more_results
;
752 struct tevent_req
*req
;
754 SLQ_DEBUG(10, slq
, "tracker_cursor_cb");
756 more_results
= tracker_sparql_cursor_next_finish(slq
->tracker_cursor
,
760 if (slq
->state
== SLQ_STATE_DONE
) {
762 * The query was closed in slrpc_close_query(), so we
763 * don't care for results or errors from
764 * tracker_sparql_cursor_next_finish(), we just go
765 * ahead and schedule deallocation of the slq handle.
767 * We have to shedule the deallocation via tevent,
768 * because we have to unref the cursor glib object and
769 * we can't do it here, because it's still used after
772 SLQ_DEBUG(10, slq
, "closed");
773 g_main_loop_quit(slq
->mds_ctx
->gmainloop
);
775 req
= slq_destroy_send(slq
, server_event_context(), &slq
);
777 slq
->state
= SLQ_STATE_ERROR
;
780 tevent_req_set_callback(req
, tracker_cursor_cb_destroy_done
, NULL
);
785 DEBUG(1, ("Tracker cursor: %s\n", error
->message
));
787 slq
->state
= SLQ_STATE_ERROR
;
788 g_main_loop_quit(slq
->mds_ctx
->gmainloop
);
793 slq
->state
= SLQ_STATE_DONE
;
794 g_main_loop_quit(slq
->mds_ctx
->gmainloop
);
798 uri
= tracker_sparql_cursor_get_string(slq
->tracker_cursor
, 0, NULL
);
800 DEBUG(1, ("error fetching Tracker URI\n"));
801 slq
->state
= SLQ_STATE_ERROR
;
802 g_main_loop_quit(slq
->mds_ctx
->gmainloop
);
805 path
= tracker_to_unix_path(slq
->query_results
, uri
);
807 DEBUG(1, ("error converting Tracker URI to path: %s\n", uri
));
808 slq
->state
= SLQ_STATE_ERROR
;
809 g_main_loop_quit(slq
->mds_ctx
->gmainloop
);
813 if (geteuid() != slq
->mds_ctx
->uid
) {
814 DEBUG(0, ("uid mismatch: %d/%d\n", geteuid(), slq
->mds_ctx
->uid
));
815 smb_panic("uid mismatch");
818 result
= sys_stat(path
, &sb
, false);
822 result
= access(path
, R_OK
);
827 ino64
= sb
.st_ex_ino
;
830 * Check whether the found element is in the requested
831 * set of IDs. Note that we're faking CNIDs by using
832 * filesystem inode numbers here
834 ok
= bsearch(&ino64
, slq
->cnids
, slq
->cnids_num
,
835 sizeof(uint64_t), cnid_comp_fn
);
842 * Add inode number and filemeta to result set, this is what
843 * we return as part of the result set of a query
845 result
= dalloc_add_copy(slq
->query_results
->cnids
->ca_cnids
,
848 DEBUG(1, ("dalloc error\n"));
849 slq
->state
= SLQ_STATE_ERROR
;
850 g_main_loop_quit(slq
->mds_ctx
->gmainloop
);
853 ok
= add_filemeta(slq
->reqinfo
, slq
->query_results
->fm_array
,
856 DEBUG(1, ("add_filemeta error\n"));
857 slq
->state
= SLQ_STATE_ERROR
;
858 g_main_loop_quit(slq
->mds_ctx
->gmainloop
);
862 ok
= inode_map_add(slq
, ino64
, path
);
864 DEBUG(1, ("inode_map_add error\n"));
865 slq
->state
= SLQ_STATE_ERROR
;
866 g_main_loop_quit(slq
->mds_ctx
->gmainloop
);
870 slq
->query_results
->num_results
++;
873 if (slq
->query_results
->num_results
>= MAX_SL_RESULTS
) {
874 slq
->state
= SLQ_STATE_FULL
;
875 SLQ_DEBUG(10, slq
, "full");
876 g_main_loop_quit(slq
->mds_ctx
->gmainloop
);
880 slq
->state
= SLQ_STATE_RESULTS
;
881 SLQ_DEBUG(10, slq
, "cursor next");
882 tracker_sparql_cursor_next_async(slq
->tracker_cursor
,
888 static void tracker_cursor_cb_destroy_done(struct tevent_req
*req
)
890 slq_destroy_recv(req
);
893 DEBUG(10, ("%s\n", __func__
));
896 static void tracker_query_cb(GObject
*object
,
900 GError
*error
= NULL
;
901 struct sl_query
*slq
= talloc_get_type_abort(user_data
, struct sl_query
);
903 SLQ_DEBUG(10, slq
, "tracker_query_cb");
905 slq
->tracker_cursor
= tracker_sparql_connection_query_finish(
906 TRACKER_SPARQL_CONNECTION(object
),
910 slq
->state
= SLQ_STATE_ERROR
;
911 DEBUG(1, ("Tracker query error: %s\n", error
->message
));
913 g_main_loop_quit(slq
->mds_ctx
->gmainloop
);
917 if (slq
->state
== SLQ_STATE_DONE
) {
918 SLQ_DEBUG(10, slq
, "done");
919 g_main_loop_quit(slq
->mds_ctx
->gmainloop
);
924 slq
->state
= SLQ_STATE_RESULTS
;
926 tracker_sparql_cursor_next_async(slq
->tracker_cursor
,
932 /***********************************************************
933 * Spotlight RPC functions
934 ***********************************************************/
936 static bool slrpc_fetch_properties(struct mds_ctx
*mds_ctx
,
937 const DALLOC_CTX
*query
, DALLOC_CTX
*reply
)
947 dict
= dalloc_zero(reply
, sl_dict_t
);
952 /* kMDSStoreHasPersistentUUID = false */
953 result
= dalloc_stradd(dict
, "kMDSStoreHasPersistentUUID");
958 result
= dalloc_add_copy(dict
, &b
, sl_bool_t
);
963 /* kMDSStoreIsBackup = false */
964 result
= dalloc_stradd(dict
, "kMDSStoreIsBackup");
969 result
= dalloc_add_copy(dict
, &b
, sl_bool_t
);
974 /* kMDSStoreUUID = uuid */
975 result
= dalloc_stradd(dict
, "kMDSStoreUUID");
979 memcpy(uuid
.sl_uuid
, "fakeuuidfakeuuid", sizeof(uuid
.sl_uuid
));
980 result
= dalloc_add_copy(dict
, &uuid
, sl_uuid_t
);
985 /* kMDSStoreSupportsVolFS = true */
986 result
= dalloc_stradd(dict
, "kMDSStoreSupportsVolFS");
991 result
= dalloc_add_copy(dict
, &b
, sl_bool_t
);
996 /* kMDSVolumeUUID = uuid */
997 result
= dalloc_stradd(dict
, "kMDSVolumeUUID");
1001 memcpy(uuid
.sl_uuid
, "fakeuuidfakeuuid", sizeof(uuid
.sl_uuid
));
1002 result
= dalloc_add_copy(dict
, &uuid
, sl_uuid_t
);
1007 /* kMDSDiskStoreSpindleNumber = 1 (fake) */
1008 result
= dalloc_stradd(dict
, "kMDSDiskStoreSpindleNumber");
1013 result
= dalloc_add_copy(dict
, &u
, uint64_t);
1018 /* kMDSDiskStorePolicy = 3 (whatever that means, taken from OS X) */
1019 result
= dalloc_stradd(dict
, "kMDSDiskStorePolicy");
1024 result
= dalloc_add_copy(dict
, &u
, uint64_t);
1029 /* kMDSStoreMetaScopes array */
1030 array
= dalloc_zero(dict
, sl_array_t
);
1031 if (array
== NULL
) {
1034 result
= dalloc_stradd(array
, "kMDQueryScopeComputer");
1038 result
= dalloc_stradd(array
, "kMDQueryScopeAllIndexed");
1042 result
= dalloc_stradd(array
, "kMDQueryScopeComputerIndexed");
1046 result
= dalloc_add(dict
, array
, sl_array_t
);
1051 /* kMDSStoreDevice = 0x1000003 (whatever that means, taken from OS X) */
1052 result
= dalloc_stradd(dict
, "kMDSStoreDevice");
1057 result
= dalloc_add_copy(dict
, &u
, uint64_t);
1062 /* kMDSStoreSupportsTCC = true (whatever that means, taken from OS X) */
1063 result
= dalloc_stradd(dict
, "kMDSStoreSupportsTCC");
1068 result
= dalloc_add_copy(dict
, &b
, sl_bool_t
);
1073 /* kMDSStorePathScopes = ["/"] (whatever that means, taken from OS X) */
1074 result
= dalloc_stradd(dict
, "kMDSStorePathScopes");
1078 array
= dalloc_zero(dict
, sl_array_t
);
1079 if (array
== NULL
) {
1082 s
= talloc_strdup(dict
, "/");
1086 talloc_set_name(s
, "smb_ucs2_t *");
1087 result
= dalloc_add(array
, s
, smb_ucs2_t
*);
1091 result
= dalloc_add(dict
, array
, sl_array_t
);
1096 result
= dalloc_add(reply
, dict
, sl_dict_t
);
1104 static void slq_close_timer(struct tevent_context
*ev
,
1105 struct tevent_timer
*te
,
1106 struct timeval current_time
,
1109 struct sl_query
*slq
= talloc_get_type_abort(
1110 private_data
, struct sl_query
);
1111 struct mds_ctx
*mds_ctx
= slq
->mds_ctx
;
1113 SLQ_DEBUG(10, slq
, "expired");
1117 if (CHECK_DEBUGLVL(10)) {
1118 for (slq
= mds_ctx
->query_list
; slq
!= NULL
; slq
= slq
->next
) {
1119 SLQ_DEBUG(10, slq
, "pending");
1125 * Begin a search query
1127 static bool slrpc_open_query(struct mds_ctx
*mds_ctx
,
1128 const DALLOC_CTX
*query
, DALLOC_CTX
*reply
)
1133 DALLOC_CTX
*reqinfo
;
1134 sl_array_t
*array
, *path_scope
;
1136 struct sl_query
*slq
= NULL
;
1140 array
= dalloc_zero(reply
, sl_array_t
);
1141 if (array
== NULL
) {
1145 if (mds_ctx
->tracker_con
== NULL
) {
1146 DEBUG(1, ("no connection to Tracker\n"));
1150 /* Allocate and initialize query object */
1151 slq
= talloc_zero(mds_ctx
, struct sl_query
);
1155 slq
->entries_ctx
= talloc_named_const(slq
, 0, "struct sl_query.entries_ctx");
1156 if (slq
->entries_ctx
== NULL
) {
1160 talloc_set_destructor(slq
, slq_destructor_cb
);
1161 slq
->state
= SLQ_STATE_NEW
;
1162 slq
->mds_ctx
= mds_ctx
;
1164 slq
->last_used
= timeval_current();
1165 slq
->start_time
= slq
->last_used
;
1166 slq
->expire_time
= timeval_add(&slq
->last_used
, MAX_SL_RUNTIME
, 0);
1167 slq
->te
= tevent_add_timer(server_event_context(), slq
,
1168 slq
->expire_time
, slq_close_timer
, slq
);
1169 if (slq
->te
== NULL
) {
1170 DEBUG(1, ("tevent_add_timer failed\n"));
1174 slq
->gcancellable
= g_cancellable_new();
1175 if (slq
->gcancellable
== NULL
) {
1176 DEBUG(1,("error from g_cancellable_new\n"));
1180 querystring
= dalloc_value_for_key(query
, "DALLOC_CTX", 0,
1183 if (querystring
== NULL
) {
1184 DEBUG(1, ("missing kMDQueryString\n"));
1187 slq
->query_string
= talloc_strdup(slq
, querystring
);
1188 if (slq
->query_string
== NULL
) {
1189 DEBUG(1, ("out of memory\n"));
1194 * FIXME: convert spotlight query charset from decomposed UTF8
1195 * to host charset precomposed UTF8.
1198 uint64p
= dalloc_get(query
, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
1200 if (uint64p
== NULL
) {
1203 slq
->ctx1
= *uint64p
;
1204 uint64p
= dalloc_get(query
, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
1206 if (uint64p
== NULL
) {
1209 slq
->ctx2
= *uint64p
;
1211 path_scope
= dalloc_value_for_key(query
, "DALLOC_CTX", 0,
1212 "DALLOC_CTX", 1, "kMDScopeArray");
1213 if (path_scope
== NULL
) {
1217 slq
->path_scope
= dalloc_get(path_scope
, "char *", 0);
1218 if (slq
->path_scope
== NULL
) {
1222 slq
->path_scope
= talloc_strdup(slq
, slq
->path_scope
);
1223 if (slq
->path_scope
== NULL
) {
1228 reqinfo
= dalloc_value_for_key(query
, "DALLOC_CTX", 0,
1229 "DALLOC_CTX", 1, "kMDAttributeArray");
1230 if (reqinfo
== NULL
) {
1234 slq
->reqinfo
= talloc_steal(slq
, reqinfo
);
1235 DEBUG(10, ("requested attributes: %s", mds_dalloc_dump(reqinfo
, 0)));
1237 cnids
= dalloc_value_for_key(query
, "DALLOC_CTX", 0,
1238 "DALLOC_CTX", 1, "kMDQueryItemArray");
1240 ok
= sort_cnids(slq
, cnids
->ca_cnids
);
1246 ok
= create_result_handle(slq
);
1248 DEBUG(1, ("create_result_handle error\n"));
1249 slq
->state
= SLQ_STATE_ERROR
;
1253 SLQ_DEBUG(10, slq
, "new");
1255 DLIST_ADD(mds_ctx
->query_list
, slq
);
1257 ok
= map_spotlight_to_sparql_query(slq
);
1262 * 1) the query string is "false", the parser returns
1263 * an error for that. We're supposed to return -1
1266 * 2) the parsing really failed, in that case we're
1267 * probably supposed to return -1 too, this needs
1268 * verification though
1270 SLQ_DEBUG(10, slq
, "map failed");
1274 DEBUG(10, ("SPARQL query: \"%s\"\n", slq
->sparql_query
));
1276 g_main_context_push_thread_default(mds_ctx
->gcontext
);
1277 tracker_sparql_connection_query_async(mds_ctx
->tracker_con
,
1282 g_main_context_pop_thread_default(mds_ctx
->gcontext
);
1283 slq
->state
= SLQ_STATE_RUNNING
;
1286 result
= dalloc_add_copy(array
, &sl_result
, uint64_t);
1290 result
= dalloc_add(reply
, array
, sl_array_t
);
1297 sl_result
= UINT64_MAX
;
1299 result
= dalloc_add_copy(array
, &sl_result
, uint64_t);
1303 result
= dalloc_add(reply
, array
, sl_array_t
);
1311 * Fetch results of a query
1313 static bool slrpc_fetch_query_results(struct mds_ctx
*mds_ctx
,
1314 const DALLOC_CTX
*query
,
1318 struct sl_query
*slq
= NULL
;
1319 uint64_t *uint64p
, ctx1
, ctx2
;
1324 array
= dalloc_zero(reply
, sl_array_t
);
1325 if (array
== NULL
) {
1329 /* Get query for context */
1330 uint64p
= dalloc_get(query
, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
1332 if (uint64p
== NULL
) {
1337 uint64p
= dalloc_get(query
, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
1339 if (uint64p
== NULL
) {
1344 slq
= slq_for_ctx(mds_ctx
, ctx1
, ctx2
);
1346 DEBUG(1, ("bad context: [0x%jx,0x%jx]\n",
1347 (uintmax_t)ctx1
, (uintmax_t)ctx2
));
1351 TALLOC_FREE(slq
->te
);
1352 slq
->last_used
= timeval_current();
1353 slq
->expire_time
= timeval_add(&slq
->last_used
, MAX_SL_RUNTIME
, 0);
1354 slq
->te
= tevent_add_timer(server_event_context(), slq
,
1355 slq
->expire_time
, slq_close_timer
, slq
);
1356 if (slq
->te
== NULL
) {
1357 DEBUG(1, ("tevent_add_timer failed\n"));
1361 SLQ_DEBUG(10, slq
, "fetch");
1363 switch (slq
->state
) {
1364 case SLQ_STATE_RUNNING
:
1365 case SLQ_STATE_RESULTS
:
1366 case SLQ_STATE_FULL
:
1367 case SLQ_STATE_DONE
:
1368 ok
= add_results(array
, slq
);
1370 DEBUG(1, ("error adding results\n"));
1373 if (slq
->state
== SLQ_STATE_FULL
) {
1374 slq
->state
= SLQ_STATE_RESULTS
;
1375 g_main_context_push_thread_default(mds_ctx
->gcontext
);
1376 tracker_sparql_cursor_next_async(
1377 slq
->tracker_cursor
,
1381 g_main_context_pop_thread_default(mds_ctx
->gcontext
);
1385 case SLQ_STATE_ERROR
:
1386 DEBUG(1, ("query in error state\n"));
1390 DEBUG(1, ("unexpected query state %d\n", slq
->state
));
1394 result
= dalloc_add(reply
, array
, sl_array_t
);
1401 status
= UINT64_MAX
;
1403 result
= dalloc_add_copy(array
, &status
, uint64_t);
1407 result
= dalloc_add(reply
, array
, sl_array_t
);
1415 * Store metadata attributes for a CNID
1417 static bool slrpc_store_attributes(struct mds_ctx
*mds_ctx
,
1418 const DALLOC_CTX
*query
, DALLOC_CTX
*reply
)
1424 array
= dalloc_zero(reply
, sl_array_t
);
1425 if (array
== NULL
) {
1430 * FIXME: not implemented. Used by the client for eg setting
1431 * the modification date of the shared directory which clients
1432 * poll indicating changes on the share and cause the client
1437 result
= dalloc_add_copy(array
, &sl_result
, uint64_t);
1441 result
= dalloc_add(reply
, array
, sl_array_t
);
1450 * Fetch supported metadata attributes for a CNID
1452 static bool slrpc_fetch_attributenames(struct mds_ctx
*mds_ctx
,
1453 const DALLOC_CTX
*query
,
1460 sl_cnids_t
*replycnids
;
1461 sl_array_t
*mdattrs
;
1462 sl_filemeta_t
*fmeta
;
1466 cnids
= dalloc_get(query
, "DALLOC_CTX", 0, "sl_cnids_t", 1);
1467 if (cnids
== NULL
) {
1471 p
= dalloc_get_object(cnids
->ca_cnids
, 0);
1475 memcpy(&id
, p
, sizeof(uint64_t));
1478 array
= dalloc_zero(reply
, sl_array_t
);
1479 if (array
== NULL
) {
1483 result
= dalloc_add(reply
, array
, sl_array_t
);
1488 /* Return result value 0 */
1490 result
= dalloc_add_copy(array
, &sl_result
, uint64_t);
1495 /* Return CNID array */
1496 replycnids
= talloc_zero(reply
, sl_cnids_t
);
1497 if (replycnids
== NULL
) {
1501 replycnids
->ca_cnids
= dalloc_new(cnids
);
1502 if (replycnids
->ca_cnids
== NULL
) {
1506 replycnids
->ca_unkn1
= 0xfec;
1507 replycnids
->ca_context
= cnids
->ca_context
;
1508 result
= dalloc_add_copy(replycnids
->ca_cnids
, &id
, uint64_t);
1512 result
= dalloc_add(array
, replycnids
, sl_cnids_t
);
1518 * FIXME: this should return the real attributes from all
1519 * known metadata sources (Tracker and filesystem)
1521 mdattrs
= dalloc_zero(reply
, sl_array_t
);
1522 if (mdattrs
== NULL
) {
1526 result
= dalloc_stradd(mdattrs
, "kMDItemFSName");
1530 result
= dalloc_stradd(mdattrs
, "kMDItemDisplayName");
1534 result
= dalloc_stradd(mdattrs
, "kMDItemFSSize");
1538 result
= dalloc_stradd(mdattrs
, "kMDItemFSOwnerUserID");
1542 result
= dalloc_stradd(mdattrs
, "kMDItemFSOwnerGroupID");
1546 result
= dalloc_stradd(mdattrs
, "kMDItemFSContentChangeDate");
1551 fmeta
= dalloc_zero(reply
, sl_filemeta_t
);
1552 if (fmeta
== NULL
) {
1555 result
= dalloc_add(fmeta
, mdattrs
, sl_array_t
);
1559 result
= dalloc_add(array
, fmeta
, sl_filemeta_t
);
1568 * Fetch metadata attribute values for a CNID
1570 static bool slrpc_fetch_attributes(struct mds_ctx
*mds_ctx
,
1571 const DALLOC_CTX
*query
, DALLOC_CTX
*reply
)
1577 sl_cnids_t
*replycnids
;
1578 sl_array_t
*reqinfo
;
1582 sl_array_t
*fm_array
;
1585 struct sl_inode_path_map
*elem
= NULL
;
1587 TDB_DATA val
= tdb_null
;
1590 array
= dalloc_zero(reply
, sl_array_t
);
1591 if (array
== NULL
) {
1594 replycnids
= talloc_zero(reply
, sl_cnids_t
);
1595 if (replycnids
== NULL
) {
1598 replycnids
->ca_cnids
= dalloc_new(replycnids
);
1599 if (replycnids
->ca_cnids
== NULL
) {
1602 fm
= dalloc_zero(array
, sl_filemeta_t
);
1606 fm_array
= dalloc_zero(fm
, sl_array_t
);
1607 if (fm_array
== NULL
) {
1610 /* For some reason the list of results always starts with a nil entry */
1611 result
= dalloc_add_copy(fm_array
, &nil
, sl_nil_t
);
1616 reqinfo
= dalloc_get(query
, "DALLOC_CTX", 0, "sl_array_t", 1);
1617 if (reqinfo
== NULL
) {
1621 cnids
= dalloc_get(query
, "DALLOC_CTX", 0, "sl_cnids_t", 2);
1622 if (cnids
== NULL
) {
1625 p
= dalloc_get_object(cnids
->ca_cnids
, 0);
1629 memcpy(&ino
, p
, sizeof(uint64_t));
1631 replycnids
->ca_unkn1
= 0xfec;
1632 replycnids
->ca_context
= cnids
->ca_context
;
1633 result
= dalloc_add_copy(replycnids
->ca_cnids
, &ino
, uint64_t);
1638 status
= dbwrap_fetch(mds_ctx
->ino_path_map
, reply
,
1639 make_tdb_data((void*)&ino
, sizeof(uint64_t)),
1641 if (!NT_STATUS_IS_OK(status
)) {
1642 DEBUG(1, ("Failed to fetch inode: %s\n", nt_errstr(status
)));
1645 if (val
.dsize
!= sizeof(p
)) {
1646 DEBUG(1, ("invalid record pointer size: %zd\n", val
.dsize
));
1647 TALLOC_FREE(val
.dptr
);
1651 memcpy(&p
, val
.dptr
, sizeof(p
));
1652 elem
= talloc_get_type_abort(p
, struct sl_inode_path_map
);
1654 result
= sys_stat(elem
->path
, &sb
, false);
1659 ok
= add_filemeta(reqinfo
, fm_array
, elem
->path
, &sb
);
1665 result
= dalloc_add_copy(array
, &sl_result
, uint64_t);
1669 result
= dalloc_add(array
, replycnids
, sl_cnids_t
);
1673 result
= dalloc_add(fm
, fm_array
, sl_array_t
);
1677 result
= dalloc_add(array
, fm
, sl_filemeta_t
);
1681 result
= dalloc_add(reply
, array
, sl_array_t
);
1689 sl_result
= UINT64_MAX
;
1690 result
= dalloc_add_copy(array
, &sl_result
, uint64_t);
1694 result
= dalloc_add(reply
, array
, sl_array_t
);
1705 static bool slrpc_close_query(struct mds_ctx
*mds_ctx
,
1706 const DALLOC_CTX
*query
, DALLOC_CTX
*reply
)
1708 struct sl_query
*slq
= NULL
;
1709 uint64_t *uint64p
, ctx1
, ctx2
;
1714 array
= dalloc_zero(reply
, sl_array_t
);
1715 if (array
== NULL
) {
1720 uint64p
= dalloc_get(query
, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
1722 if (uint64p
== NULL
) {
1727 uint64p
= dalloc_get(query
, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
1729 if (uint64p
== NULL
) {
1734 /* Get query for context and free it */
1735 slq
= slq_for_ctx(mds_ctx
, ctx1
, ctx2
);
1737 DEBUG(1, ("bad context: [0x%jx,0x%jx]\n",
1738 (uintmax_t)ctx1
, (uintmax_t)ctx2
));
1742 switch (slq
->state
) {
1743 case SLQ_STATE_RUNNING
:
1744 case SLQ_STATE_RESULTS
:
1745 DEBUG(10, ("close: requesting query close\n"));
1747 * Mark the query is done so the cursor callback can
1748 * act accordingly by stopping to request more results
1749 * and sheduling query resource deallocation via
1752 slq
->state
= SLQ_STATE_DONE
;
1755 case SLQ_STATE_FULL
:
1756 case SLQ_STATE_DONE
:
1757 DEBUG(10, ("close: query was done or result queue was full\n"));
1759 * We can directly deallocate the query because there
1760 * are no pending Tracker async calls in flight in
1761 * these query states.
1767 DEBUG(1, ("close: unexpected state: %d\n", slq
->state
));
1774 result
= dalloc_add_copy(array
, &sl_res
, uint64_t);
1778 result
= dalloc_add(reply
, array
, sl_array_t
);
1786 * Init callbacks at startup, nothing to do here really
1788 bool mds_init(struct messaging_context
*msg_ctx
)
1793 bool mds_shutdown(void)
1798 static gboolean
gmainloop_timer(gpointer user_data
)
1800 struct mds_ctx
*ctx
= talloc_get_type_abort(user_data
, struct mds_ctx
);
1802 DEBUG(10,("%s\n", __func__
));
1803 g_main_loop_quit(ctx
->gmainloop
);
1805 return G_SOURCE_CONTINUE
;
1809 * Initialise a context per share handle
1811 struct mds_ctx
*mds_init_ctx(TALLOC_CTX
*mem_ctx
,
1812 const struct auth_session_info
*session_info
,
1815 struct mds_ctx
*mds_ctx
;
1817 mds_ctx
= talloc_zero(mem_ctx
, struct mds_ctx
);
1818 if (mds_ctx
== NULL
) {
1821 talloc_set_destructor(mds_ctx
, mds_ctx_destructor_cb
);
1823 mds_ctx
->spath
= talloc_strdup(mds_ctx
, path
);
1824 if (mds_ctx
->spath
== NULL
) {
1828 if (session_info
->security_token
->num_sids
< 1) {
1831 sid_copy(&mds_ctx
->sid
, &session_info
->security_token
->sids
[0]);
1832 mds_ctx
->uid
= session_info
->unix_token
->uid
;
1834 mds_ctx
->ino_path_map
= db_open_rbt(mds_ctx
);
1835 if (mds_ctx
->ino_path_map
== NULL
) {
1836 DEBUG(1,("open inode map db failed\n"));
1840 mds_ctx
->gcontext
= g_main_context_new();
1841 if (mds_ctx
->gcontext
== NULL
) {
1842 DEBUG(1,("error from g_main_context_new\n"));
1846 mds_ctx
->gmainloop
= g_main_loop_new(mds_ctx
->gcontext
, false);
1847 if (mds_ctx
->gmainloop
== NULL
) {
1848 DEBUG(1,("error from g_main_loop_new\n"));
1852 g_main_context_push_thread_default(mds_ctx
->gcontext
);
1853 tracker_sparql_connection_get_async(mds_ctx
->gcancellable
,
1854 tracker_con_cb
, mds_ctx
);
1855 g_main_context_pop_thread_default(mds_ctx
->gcontext
);
1860 TALLOC_FREE(mds_ctx
);
1865 * Tear down connections and free all resources
1867 int mds_ctx_destructor_cb(struct mds_ctx
*mds_ctx
)
1870 * We need to free query_list before ino_path_map
1872 while (mds_ctx
->query_list
!= NULL
) {
1874 * slq destructor removes element from list.
1875 * Don't use TALLOC_FREE()!
1877 talloc_free(mds_ctx
->query_list
);
1879 TALLOC_FREE(mds_ctx
->ino_path_map
);
1881 if (mds_ctx
->tracker_con
!= NULL
) {
1882 g_object_unref(mds_ctx
->tracker_con
);
1884 if (mds_ctx
->gcancellable
!= NULL
) {
1885 g_cancellable_cancel(mds_ctx
->gcancellable
);
1886 g_object_unref(mds_ctx
->gcancellable
);
1888 if (mds_ctx
->gmainloop
!= NULL
) {
1889 g_main_loop_unref(mds_ctx
->gmainloop
);
1891 if (mds_ctx
->gcontext
!= NULL
) {
1892 g_main_context_unref(mds_ctx
->gcontext
);
1895 ZERO_STRUCTP(mds_ctx
);
1900 static bool mds_run_gmainloop(struct mds_ctx
*mds_ctx
, guint timeout
)
1906 * It seems the event processing of the libtracker-sparql
1907 * async subsystem defers callbacks until *all* events are
1908 * processes by the async subsystem main processing loop.
1910 * g_main_context_iteration(may_block=FALSE) can't be used,
1911 * because a search that produces a few thousand matches
1912 * generates as many events that must be processed in either
1913 * g_main_context_iteration() or g_main_loop_run() before
1914 * callbacks are called.
1916 * Unfortunately g_main_context_iteration() only processes a
1917 * small subset of these event (1-30) at a time when run in
1918 * mds_dispatch(), which happens once a second while the
1919 * client polls for results.
1921 * Carefully using the blocking g_main_loop_run() fixes
1922 * this. It processes events until we exit from the loop at
1923 * defined exit points. By adding a 1 ms timeout we at least
1924 * try to get as close as possible to non-blocking behaviour.
1927 if (!g_main_context_pending(mds_ctx
->gcontext
)) {
1931 g_main_context_push_thread_default(mds_ctx
->gcontext
);
1933 timer
= g_timeout_source_new(timeout
);
1934 if (timer
== NULL
) {
1935 DEBUG(1,("g_timeout_source_new_seconds\n"));
1936 g_main_context_pop_thread_default(mds_ctx
->gcontext
);
1940 timer_id
= g_source_attach(timer
, mds_ctx
->gcontext
);
1941 if (timer_id
== 0) {
1942 DEBUG(1,("g_timeout_add failed\n"));
1943 g_source_destroy(timer
);
1944 g_main_context_pop_thread_default(mds_ctx
->gcontext
);
1948 g_source_set_callback(timer
, gmainloop_timer
, mds_ctx
, NULL
);
1950 g_main_loop_run(mds_ctx
->gmainloop
);
1952 g_source_destroy(timer
);
1954 g_main_context_pop_thread_default(mds_ctx
->gcontext
);
1959 * Dispatch a Spotlight RPC command
1961 bool mds_dispatch(struct mds_ctx
*mds_ctx
,
1962 struct mdssvc_blob
*request_blob
,
1963 struct mdssvc_blob
*response_blob
)
1967 DALLOC_CTX
*query
= NULL
;
1968 DALLOC_CTX
*reply
= NULL
;
1970 const struct slrpc_cmd
*slcmd
;
1972 if (CHECK_DEBUGLVL(10)) {
1973 const struct sl_query
*slq
;
1975 for (slq
= mds_ctx
->query_list
; slq
!= NULL
; slq
= slq
->next
) {
1976 SLQ_DEBUG(10, slq
, "pending");
1980 response_blob
->length
= 0;
1983 * Process finished glib events.
1985 * FIXME: integrate with tevent instead of piggy packing it
1986 * onto the processing of new requests.
1988 * mds_dispatch() is called by the client a few times in a row:
1990 * - first in order to open/start a search query
1992 * - later in order to fetch results asynchronously, typically
1993 * once a second. If no results have been retrieved from the
1994 * search store (Tracker) yet, we return no results.
1995 * The client asks for more results every second as long
1996 * as the "Search Window" in the client gui is open.
1998 * - at some point the query is closed
2000 * This means we try to iterate through the glib event loop
2001 * before processing the request in order to get result
2002 * from tracker which can be returned to the client.
2005 ok
= mds_run_gmainloop(mds_ctx
, MDS_TRACKER_ASYNC_TIMEOUT_MS
);
2010 DEBUG(10, ("share path: %s\n", mds_ctx
->spath
));
2012 query
= dalloc_new(mds_ctx
);
2013 if (query
== NULL
) {
2017 reply
= dalloc_new(mds_ctx
);
2018 if (reply
== NULL
) {
2023 ok
= sl_unpack(query
, (char *)request_blob
->spotlight_blob
,
2024 request_blob
->length
);
2026 DEBUG(1, ("error unpacking Spotlight RPC blob\n"));
2030 DEBUG(5, ("%s", mds_dalloc_dump(query
, 0)));
2032 rpccmd
= dalloc_get(query
, "DALLOC_CTX", 0, "DALLOC_CTX", 0,
2034 if (rpccmd
== NULL
) {
2035 DEBUG(1, ("missing primary Spotlight RPC command\n"));
2040 DEBUG(10, ("Spotlight RPC cmd: %s\n", rpccmd
));
2042 slcmd
= slrpc_cmd_by_name(rpccmd
);
2043 if (slcmd
== NULL
) {
2044 DEBUG(1, ("unsupported primary Spotlight RPC command %s\n",
2051 * If these functions return an error, they hit something like
2052 * a non recoverable talloc error
2054 ok
= slcmd
->function(mds_ctx
, query
, reply
);
2056 DEBUG(1, ("error in Spotlight RPC handler\n"));
2060 DEBUG(5, ("%s", mds_dalloc_dump(reply
, 0)));
2062 len
= sl_pack(reply
, (char *)response_blob
->spotlight_blob
,
2063 response_blob
->size
);
2065 DEBUG(1, ("error packing Spotlight RPC reply\n"));
2071 * Run g_main_loop a second time in order to dispatch events
2072 * that may have been queued at the libtracker-sparql level.
2073 * As we only want to dispatch (write out requests) but not
2074 * wait for anything, we use a much shorter timeout here.
2076 ok
= mds_run_gmainloop(mds_ctx
, MDS_TRACKER_ASYNC_TIMEOUT_MS
/ 10);
2081 response_blob
->length
= len
;