From: Ralph Boehme Date: Wed, 4 Jun 2014 14:36:58 +0000 (+0200) Subject: Spotlight: new options for controlling query behaviour X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=commitdiff_plain;h=371efee757ed56fd9e2f46b39fae625924d2cfc2 Spotlight: new options for controlling query behaviour Add three options that allow fine grainted control over the resulting SPARQL queries: "sparql results limit = NUMBER", default is unlimited Useful for limiting the result set for very large systems "spotlight attributes = STRING", useful for limiting queries to attributes that are indexed, many are not. "spotlight expr = BOOLEAN", default: yes, useful for disabling the use of complex queries that will take too long to complete and hang Tracker. Signed-off-by: Ralph Boehme --- diff --git a/NEWS b/NEWS index f9c9052f..f4cab3d6 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,8 @@ Changes in 3.1.3 ================ * UPD: Spotlight: more SPARQL query optimisations +* UPD: Spotlight: new options "sparql results limit", "spotlight + attributes" and "spotlight expr" Changes in 3.1.2 ================ diff --git a/doc/manpages/man5/afp.conf.5.xml b/doc/manpages/man5/afp.conf.5.xml index a1e760a1..1c424462 100644 --- a/doc/manpages/man5/afp.conf.5.xml +++ b/doc/manpages/man5/afp.conf.5.xml @@ -990,10 +990,21 @@ + + sparql results limit = + NUMBER (default: + UNLIMITED) (G) + + + Impose a limit on the number of results queried from Tracker + via SPARQL queries. + + + spotlight = BOOLEAN (default: - no) (G)/(V) + no) (G) Whether to enable Spotlight searches. Note: once the global @@ -1003,6 +1014,32 @@ + + spotlight attributes = + COMMA SEPERATED STRING (default: + EMPTY) (G) + + + A list of attributes that are allowed to be used in + Spotlight searches. By default all attributes can be + searched, passing a string limits attributes to elements + of the string. Example: spotlight + attributes = *,kMDItemTextContent + + + + + + spotlight expr = + BOOLEAN (default: + yes) (G) + + + Whether to allow the use of logic expression in + searches. + + + start dbus = BOOLEAN (default: diff --git a/etc/afpd/afp_dsi.c b/etc/afpd/afp_dsi.c index eb4b19f3..697aa435 100644 --- a/etc/afpd/afp_dsi.c +++ b/etc/afpd/afp_dsi.c @@ -477,7 +477,7 @@ void afp_over_dsi(AFPObj *obj) /* Initialize Spotlight */ if ((obj->options.flags & OPTION_SPOTLIGHT) && (obj->options.slmod_path)) - sl_mod_load(obj->options.slmod_path); + sl_mod_load(obj); ipc_child_state(obj, DSI_RUNNING); diff --git a/etc/afpd/spotlight.c b/etc/afpd/spotlight.c index a3fa5870..56546244 100644 --- a/etc/afpd/spotlight.c +++ b/etc/afpd/spotlight.c @@ -283,6 +283,11 @@ static int sl_rpc_openQuery(AFPObj *obj, const DALLOC_CTX *query, DALLOC_CTX *re slq->slq_state = SLQ_STATE_NEW; slq->slq_obj = obj; slq->slq_vol = v; + slq->slq_allow_expr = obj->options.flags & OPTION_SPOTLIGHT_EXPR ? true : false; + slq->slq_result_limit = obj->options.sparql_limit; + + LOG(log_info, logtype_sl, "sl_rpc_openQuery: expr: %s, limit: %" PRIu64, + slq->slq_allow_expr ? "yes" : "no", slq->slq_result_limit); /* convert spotlight query charset to host charset */ EC_NULL_LOG( sl_query = dalloc_value_for_key(query, "DALLOC_CTX", 0, "DALLOC_CTX", 1, "kMDQueryString") ); @@ -580,23 +585,23 @@ EC_CLEANUP: * Spotlight module functions **************************************************************************************************/ -int sl_mod_load(const char *path) +int sl_mod_load(AFPObj *obj) { EC_INIT; sl_ctx = talloc_new(NULL); - if ((sl_module = mod_open(path)) == NULL) { - LOG(log_error, logtype_sl, "Failed to load module \'%s\': %s", path, mod_error()); + if ((sl_module = mod_open(obj->options.slmod_path)) == NULL) { + LOG(log_error, logtype_sl, "Failed to load module \'%s\': %s", obj->options.slmod_path, mod_error()); EC_FAIL; } if ((sl_module_export = mod_symbol(sl_module, "sl_mod")) == NULL) { - LOG(log_error, logtype_sl, "sl_mod_load(%s): mod_symbol error for symbol %s", path, "sl_mod"); + LOG(log_error, logtype_sl, "sl_mod_load(%s): mod_symbol error for symbol sl_mod", obj->options.slmod_path); EC_FAIL; } - sl_module_export->sl_mod_init("test"); + sl_module_export->sl_mod_init(obj); EC_CLEANUP: EC_EXIT; diff --git a/etc/spotlight/slmod_sparql.c b/etc/spotlight/slmod_sparql.c index e59db5a9..21e8d382 100644 --- a/etc/spotlight/slmod_sparql.c +++ b/etc/spotlight/slmod_sparql.c @@ -59,7 +59,8 @@ static int sl_mod_init(void *p) { EC_INIT; GError *error = NULL; - const char *msg = p; + AFPObj *obj = (AFPObj *)p; + const char *attributes; LOG(log_info, logtype_sl, "Initializing Spotlight module"); @@ -95,6 +96,11 @@ static int sl_mod_init(void *p) } #endif + attributes = atalk_iniparser_getstring(obj->iniconfig, INISEC_GLOBAL, "spotlight attributes", NULL); + if (attributes) { + configure_spotlight_attributes(attributes); + } + EC_CLEANUP: EC_EXIT; } diff --git a/etc/spotlight/slmod_sparql_map.c b/etc/spotlight/slmod_sparql_map.c index c2c7312f..7ac4963c 100644 --- a/etc/spotlight/slmod_sparql_map.c +++ b/etc/spotlight/slmod_sparql_map.c @@ -17,6 +17,10 @@ #endif /* HAVE_CONFIG_H */ #include +#include +#include + +#include #include "slmod_sparql_map.h" @@ -24,48 +28,48 @@ #define SPECIAL NULL struct spotlight_sparql_map spotlight_sparql_map[] = { - /* ssm_spotlight_attr ssm_type, ssm_sparql_attr */ - {"*", ssmt_fts, "fts:match"}, + /* ssm_spotlight_attr ssm_enabled, ssm_type, ssm_sparql_attr */ + {"*", true, ssmt_fts, "fts:match"}, /* Filesystem metadata */ - {"kMDItemFSLabel", ssmt_num, NOTSUPPORTED}, - {"kMDItemDisplayName", ssmt_str, "nfo:fileName"}, - {"kMDItemFSName", ssmt_str, "nfo:fileName"}, - {"kMDItemFSContentChangeDate", ssmt_date, "nfo:fileLastModified"}, + {"kMDItemFSLabel", true, ssmt_num, NOTSUPPORTED}, + {"kMDItemDisplayName", true, ssmt_str, "nfo:fileName"}, + {"kMDItemFSName", true, ssmt_str, "nfo:fileName"}, + {"kMDItemFSContentChangeDate", true, ssmt_date, "nfo:fileLastModified"}, /* Common metadata */ - {"kMDItemTextContent", ssmt_fts, "fts:match"}, - {"kMDItemContentCreationDate", ssmt_date, "nie:contentCreated"}, - {"kMDItemContentModificationDate", ssmt_date, "nfo:fileLastModified"}, - {"kMDItemAttributeChangeDate", ssmt_date, "nfo:fileLastModified"}, - {"kMDItemLastUsedDate", ssmt_date, "nfo:fileLastAccessed"}, - {"kMDItemAuthors", ssmt_str, "dc:creator"}, - {"kMDItemCopyright", ssmt_str, "nie:copyright"}, - {"kMDItemCountry", ssmt_str, "nco:country"}, - {"kMDItemCreator", ssmt_str, "dc:creator"}, - {"kMDItemDurationSeconds", ssmt_num, "nfo:duration"}, - {"kMDItemNumberOfPages", ssmt_num, "nfo:pageCount"}, - {"kMDItemTitle", ssmt_str, "nie:title"}, - {"_kMDItemGroupId", ssmt_type, SPECIAL}, - {"kMDItemContentTypeTree", ssmt_type, SPECIAL}, + {"kMDItemTextContent", true, ssmt_fts, "fts:match"}, + {"kMDItemContentCreationDate", true, ssmt_date, "nie:contentCreated"}, + {"kMDItemContentModificationDate", true, ssmt_date, "nfo:fileLastModified"}, + {"kMDItemAttributeChangeDate", true, ssmt_date, "nfo:fileLastModified"}, + {"kMDItemLastUsedDate", true, ssmt_date, "nfo:fileLastAccessed"}, + {"kMDItemAuthors", true, ssmt_str, "dc:creator"}, + {"kMDItemCopyright", true, ssmt_str, "nie:copyright"}, + {"kMDItemCountry", true, ssmt_str, "nco:country"}, + {"kMDItemCreator", true, ssmt_str, "dc:creator"}, + {"kMDItemDurationSeconds", true, ssmt_num, "nfo:duration"}, + {"kMDItemNumberOfPages", true, ssmt_num, "nfo:pageCount"}, + {"kMDItemTitle", true, ssmt_str, "nie:title"}, + {"_kMDItemGroupId", true, ssmt_type, SPECIAL}, + {"kMDItemContentTypeTree", true, ssmt_type, SPECIAL}, /* Image metadata */ - {"kMDItemPixelWidth", ssmt_num, "nfo:width"}, - {"kMDItemPixelHeight", ssmt_num, "nfo:height"}, - {"kMDItemColorSpace", ssmt_str, "nexif:colorSpace"}, - {"kMDItemBitsPerSample", ssmt_num, "nfo:colorDepth"}, - {"kMDItemFocalLength", ssmt_num, "nmm:focalLength"}, - {"kMDItemISOSpeed", ssmt_num, "nmm:isoSpeed"}, - {"kMDItemOrientation", ssmt_bool, "nfo:orientation"}, - {"kMDItemResolutionWidthDPI", ssmt_num, "nfo:horizontalResolution"}, - {"kMDItemResolutionHeightDPI", ssmt_num, "nfo:verticalResolution"}, - {"kMDItemExposureTimeSeconds", ssmt_num, "nmm:exposureTime"}, + {"kMDItemPixelWidth", true, ssmt_num, "nfo:width"}, + {"kMDItemPixelHeight", true, ssmt_num, "nfo:height"}, + {"kMDItemColorSpace", true, ssmt_str, "nexif:colorSpace"}, + {"kMDItemBitsPerSample", true, ssmt_num, "nfo:colorDepth"}, + {"kMDItemFocalLength", true, ssmt_num, "nmm:focalLength"}, + {"kMDItemISOSpeed", true, ssmt_num, "nmm:isoSpeed"}, + {"kMDItemOrientation", true, ssmt_bool, "nfo:orientation"}, + {"kMDItemResolutionWidthDPI", true, ssmt_num, "nfo:horizontalResolution"}, + {"kMDItemResolutionHeightDPI", true, ssmt_num, "nfo:verticalResolution"}, + {"kMDItemExposureTimeSeconds", true, ssmt_num, "nmm:exposureTime"}, /* Audio metadata */ - {"kMDItemComposer", ssmt_str, "nmm:composer"}, - {"kMDItemMusicalGenre", ssmt_str, "nfo:genre"}, + {"kMDItemComposer", true, ssmt_str, "nmm:composer"}, + {"kMDItemMusicalGenre", true, ssmt_str, "nfo:genre"}, - {NULL, ssmt_str, NULL} + {NULL, false, ssmt_str, NULL} }; struct MDTypeMap MDTypeMap[] = { @@ -99,3 +103,34 @@ struct MDTypeMap MDTypeMap[] = { {"public.source-code", kMDTypeMapRDF, "http://www.semanticdesktop.org/ontologies/2007/03/22/nfo#SourceCode"}, {NULL, kMDTypeMapNotSup, NULL} }; + +void configure_spotlight_attributes(const char *attributes_in) +{ + char *attr, *attributes; + int i; + + for (i = 0; spotlight_sparql_map[i].ssm_spotlight_attr != NULL; i++) + spotlight_sparql_map[i].ssm_enabled = false; + + /* + * Go through the attribute map and for every element scan + * attributes_in with strtok(). If it's contained, keep it + * enabled, otherwise disable it. + */ + + attributes = strdup(attributes_in); + + for (attr = strtok(attributes, ","); attr; attr = strtok(NULL, ",")) { + + for (i = 0; spotlight_sparql_map[i].ssm_spotlight_attr != NULL; i++) + + if (strcmp(attr, spotlight_sparql_map[i].ssm_spotlight_attr) == 0) { + LOG(log_info, logtype_sl, "Enabling Spotlight attribute: %s", + spotlight_sparql_map[i].ssm_spotlight_attr); + spotlight_sparql_map[i].ssm_enabled = true; + break; + } + } + + free(attributes); +} diff --git a/etc/spotlight/slmod_sparql_map.h b/etc/spotlight/slmod_sparql_map.h index 250894b1..3b924740 100644 --- a/etc/spotlight/slmod_sparql_map.h +++ b/etc/spotlight/slmod_sparql_map.h @@ -36,6 +36,7 @@ enum kMDTypeMap { struct spotlight_sparql_map { const char *ssm_spotlight_attr; + bool ssm_enabled; enum ssm_type ssm_type; const char *ssm_sparql_attr; }; diff --git a/etc/spotlight/slmod_sparql_parser.c b/etc/spotlight/slmod_sparql_parser.c index f70d9ef1..66e0f59d 100644 --- a/etc/spotlight/slmod_sparql_parser.c +++ b/etc/spotlight/slmod_sparql_parser.c @@ -100,9 +100,10 @@ /* local vars */ static gchar *ssp_result; static char sparqlvar; + static char *result_limit; /* Line 371 of yacc.c */ -#line 106 "slmod_sparql_parser.c" +#line 107 "slmod_sparql_parser.c" # ifndef YY_NULL # if defined __cplusplus && 201103L <= __cplusplus @@ -176,7 +177,7 @@ extern int yydebug; typedef union YYSTYPE { /* Line 387 of yacc.c */ -#line 45 "slmod_sparql_parser.y" +#line 46 "slmod_sparql_parser.y" int ival; const char *sval; @@ -185,7 +186,7 @@ typedef union YYSTYPE /* Line 387 of yacc.c */ -#line 189 "slmod_sparql_parser.c" +#line 190 "slmod_sparql_parser.c" } YYSTYPE; # define YYSTYPE_IS_TRIVIAL 1 # define yystype YYSTYPE /* obsolescent; will be withdrawn */ @@ -209,7 +210,7 @@ int yyparse (); #endif /* ! YYPARSE_PARAM */ /* "%code provides" blocks. */ /* Line 387 of yacc.c */ -#line 39 "slmod_sparql_parser.y" +#line 40 "slmod_sparql_parser.y" #define SPRAW_TIME_OFFSET 978307200 extern int map_spotlight_to_sparql_query(slq_t *slq, gchar **sparql_result); @@ -217,14 +218,14 @@ int yyparse (); /* Line 387 of yacc.c */ -#line 221 "slmod_sparql_parser.c" +#line 222 "slmod_sparql_parser.c" #endif /* !YY_YY_SLMOD_SPARQL_PARSER_H_INCLUDED */ /* Copy the second part of user declarations. */ /* Line 390 of yacc.c */ -#line 228 "slmod_sparql_parser.c" +#line 229 "slmod_sparql_parser.c" #ifdef short # undef short @@ -523,9 +524,9 @@ static const yytype_int8 yyrhs[] = /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { - 0, 67, 67, 69, 73, 83, 89, 95, 96, 97, - 98, 99, 108, 109, 110, 111, 112, 113, 114, 115, - 119, 123, 124 + 0, 68, 68, 70, 74, 88, 94, 104, 105, 106, + 107, 112, 121, 122, 123, 124, 125, 126, 127, 128, + 132, 136, 137 }; #endif @@ -1446,19 +1447,23 @@ yyreduce: { case 4: /* Line 1792 of yacc.c */ -#line 73 "slmod_sparql_parser.y" +#line 74 "slmod_sparql_parser.y" { + if (ssp_slq->slq_result_limit) + result_limit = talloc_asprintf(ssp_slq, "LIMIT %ld", ssp_slq->slq_result_limit); + else + result_limit = ""; ssp_result = talloc_asprintf(ssp_slq, "SELECT ?url WHERE " - "{ %s . ?obj nie:url ?url . FILTER(tracker:uri-is-descendant('file://%s/', ?url)) } LIMIT 100", - (yyvsp[(1) - (1)].sval), ssp_slq->slq_vol->v_path); + "{ %s . ?obj nie:url ?url . FILTER(tracker:uri-is-descendant('file://%s/', ?url)) } %s", + (yyvsp[(1) - (1)].sval), ssp_slq->slq_vol->v_path, result_limit); (yyval.sval) = ssp_result; } break; case 5: /* Line 1792 of yacc.c */ -#line 83 "slmod_sparql_parser.y" +#line 88 "slmod_sparql_parser.y" { if ((yyvsp[(1) - (1)].bval) == false) YYACCEPT; @@ -1469,8 +1474,12 @@ yyreduce: case 6: /* Line 1792 of yacc.c */ -#line 89 "slmod_sparql_parser.y" +#line 94 "slmod_sparql_parser.y" { + if (!ssp_slq->slq_allow_expr) + YYABORT; + if ((yyvsp[(1) - (3)].sval) == NULL || (yyvsp[(3) - (3)].sval) == NULL) + YYABORT; if (strcmp((yyvsp[(1) - (3)].sval), (yyvsp[(3) - (3)].sval)) != 0) (yyval.sval) = talloc_asprintf(ssp_slq, "{ %s } UNION { %s }", (yyvsp[(1) - (3)].sval), (yyvsp[(3) - (3)].sval)); else @@ -1480,31 +1489,35 @@ yyreduce: case 7: /* Line 1792 of yacc.c */ -#line 95 "slmod_sparql_parser.y" +#line 104 "slmod_sparql_parser.y" {(yyval.sval) = (yyvsp[(1) - (1)].sval); if ((yyval.sval) == NULL) YYABORT;} break; case 8: /* Line 1792 of yacc.c */ -#line 96 "slmod_sparql_parser.y" +#line 105 "slmod_sparql_parser.y" {(yyval.sval) = (yyvsp[(1) - (1)].sval);} break; case 9: /* Line 1792 of yacc.c */ -#line 97 "slmod_sparql_parser.y" +#line 106 "slmod_sparql_parser.y" {(yyval.sval) = talloc_asprintf(ssp_slq, "%s", (yyvsp[(2) - (3)].sval));} break; case 10: /* Line 1792 of yacc.c */ -#line 98 "slmod_sparql_parser.y" - {(yyval.sval) = talloc_asprintf(ssp_slq, "%s . %s", (yyvsp[(1) - (3)].sval), (yyvsp[(3) - (3)].sval));} +#line 107 "slmod_sparql_parser.y" + { + if (!ssp_slq->slq_allow_expr) + YYABORT; + (yyval.sval) = talloc_asprintf(ssp_slq, "%s . %s", (yyvsp[(1) - (3)].sval), (yyvsp[(3) - (3)].sval)); +} break; case 11: /* Line 1792 of yacc.c */ -#line 99 "slmod_sparql_parser.y" +#line 112 "slmod_sparql_parser.y" { if (strcmp((yyvsp[(1) - (3)].sval), (yyvsp[(3) - (3)].sval)) != 0) (yyval.sval) = talloc_asprintf(ssp_slq, "{ %s } UNION { %s }", (yyvsp[(1) - (3)].sval), (yyvsp[(3) - (3)].sval)); @@ -1515,73 +1528,73 @@ yyreduce: case 12: /* Line 1792 of yacc.c */ -#line 108 "slmod_sparql_parser.y" +#line 121 "slmod_sparql_parser.y" {(yyval.sval) = map_expr((yyvsp[(1) - (5)].sval), '=', (yyvsp[(4) - (5)].sval));} break; case 13: /* Line 1792 of yacc.c */ -#line 109 "slmod_sparql_parser.y" +#line 122 "slmod_sparql_parser.y" {(yyval.sval) = map_expr((yyvsp[(1) - (5)].sval), '!', (yyvsp[(4) - (5)].sval));} break; case 14: /* Line 1792 of yacc.c */ -#line 110 "slmod_sparql_parser.y" +#line 123 "slmod_sparql_parser.y" {(yyval.sval) = map_expr((yyvsp[(1) - (5)].sval), '<', (yyvsp[(4) - (5)].sval));} break; case 15: /* Line 1792 of yacc.c */ -#line 111 "slmod_sparql_parser.y" +#line 124 "slmod_sparql_parser.y" {(yyval.sval) = map_expr((yyvsp[(1) - (5)].sval), '>', (yyvsp[(4) - (5)].sval));} break; case 16: /* Line 1792 of yacc.c */ -#line 112 "slmod_sparql_parser.y" +#line 125 "slmod_sparql_parser.y" {(yyval.sval) = map_expr((yyvsp[(1) - (6)].sval), '=', (yyvsp[(4) - (6)].sval));} break; case 17: /* Line 1792 of yacc.c */ -#line 113 "slmod_sparql_parser.y" +#line 126 "slmod_sparql_parser.y" {(yyval.sval) = map_expr((yyvsp[(1) - (6)].sval), '!', (yyvsp[(4) - (6)].sval));} break; case 18: /* Line 1792 of yacc.c */ -#line 114 "slmod_sparql_parser.y" +#line 127 "slmod_sparql_parser.y" {(yyval.sval) = map_expr((yyvsp[(1) - (6)].sval), '<', (yyvsp[(4) - (6)].sval));} break; case 19: /* Line 1792 of yacc.c */ -#line 115 "slmod_sparql_parser.y" +#line 128 "slmod_sparql_parser.y" {(yyval.sval) = map_expr((yyvsp[(1) - (6)].sval), '>', (yyvsp[(4) - (6)].sval));} break; case 20: /* Line 1792 of yacc.c */ -#line 119 "slmod_sparql_parser.y" +#line 132 "slmod_sparql_parser.y" {(yyval.sval) = map_daterange((yyvsp[(3) - (8)].sval), (yyvsp[(5) - (8)].tval), (yyvsp[(7) - (8)].tval));} break; case 21: /* Line 1792 of yacc.c */ -#line 123 "slmod_sparql_parser.y" +#line 136 "slmod_sparql_parser.y" {(yyval.tval) = isodate2unix((yyvsp[(3) - (4)].sval));} break; case 22: /* Line 1792 of yacc.c */ -#line 124 "slmod_sparql_parser.y" +#line 137 "slmod_sparql_parser.y" {(yyval.tval) = atoi((yyvsp[(1) - (1)].sval)) + SPRAW_TIME_OFFSET;} break; /* Line 1792 of yacc.c */ -#line 1585 "slmod_sparql_parser.c" +#line 1598 "slmod_sparql_parser.c" default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -1813,7 +1826,7 @@ yyreturn: /* Line 2055 of yacc.c */ -#line 127 "slmod_sparql_parser.y" +#line 140 "slmod_sparql_parser.y" static time_t isodate2unix(const char *s) @@ -1896,7 +1909,7 @@ static const char *map_expr(const char *attr, char op, const char *val) bstring q = NULL, search = NULL, replace = NULL; for (p = spotlight_sparql_map; p->ssm_spotlight_attr; p++) { - if (strcmp(p->ssm_spotlight_attr, attr) == 0) { + if (p->ssm_enabled && (strcmp(p->ssm_spotlight_attr, attr) == 0)) { if (p->ssm_type != ssmt_type && p->ssm_sparql_attr == NULL) { yyerror("unsupported Spotlight attribute"); EC_FAIL; @@ -2021,6 +2034,7 @@ int main(int argc, char **argv) struct vol *vol = talloc_zero(ssp_slq, struct vol); vol->v_path = "/Volumes/test"; ssp_slq->slq_vol = vol; + ssp_slq->slq_allow_expr = true; sparqlvar = 'a'; s = yy_scan_string(argv[1]); diff --git a/etc/spotlight/slmod_sparql_parser.h b/etc/spotlight/slmod_sparql_parser.h index 471e16f5..9eb22b37 100644 --- a/etc/spotlight/slmod_sparql_parser.h +++ b/etc/spotlight/slmod_sparql_parser.h @@ -84,7 +84,7 @@ extern int yydebug; typedef union YYSTYPE { /* Line 2058 of yacc.c */ -#line 45 "slmod_sparql_parser.y" +#line 46 "slmod_sparql_parser.y" int ival; const char *sval; @@ -117,7 +117,7 @@ int yyparse (); #endif /* ! YYPARSE_PARAM */ /* "%code provides" blocks. */ /* Line 2058 of yacc.c */ -#line 39 "slmod_sparql_parser.y" +#line 40 "slmod_sparql_parser.y" #define SPRAW_TIME_OFFSET 978307200 extern int map_spotlight_to_sparql_query(slq_t *slq, gchar **sparql_result); diff --git a/etc/spotlight/slmod_sparql_parser.y b/etc/spotlight/slmod_sparql_parser.y index 0763b39c..e4069bbe 100644 --- a/etc/spotlight/slmod_sparql_parser.y +++ b/etc/spotlight/slmod_sparql_parser.y @@ -34,6 +34,7 @@ /* local vars */ static gchar *ssp_result; static char sparqlvar; + static char *result_limit; %} %code provides { @@ -71,10 +72,14 @@ input: line: expr { + if (ssp_slq->slq_result_limit) + result_limit = talloc_asprintf(ssp_slq, "LIMIT %ld", ssp_slq->slq_result_limit); + else + result_limit = ""; ssp_result = talloc_asprintf(ssp_slq, "SELECT ?url WHERE " - "{ %s . ?obj nie:url ?url . FILTER(tracker:uri-is-descendant('file://%s/', ?url)) } LIMIT 100", - $1, ssp_slq->slq_vol->v_path); + "{ %s . ?obj nie:url ?url . FILTER(tracker:uri-is-descendant('file://%s/', ?url)) } %s", + $1, ssp_slq->slq_vol->v_path, result_limit); $$ = ssp_result; } ; @@ -87,6 +92,10 @@ BOOL { YYABORT; } | match OR match { + if (!ssp_slq->slq_allow_expr) + YYABORT; + if ($1 == NULL || $3 == NULL) + YYABORT; if (strcmp($1, $3) != 0) $$ = talloc_asprintf(ssp_slq, "{ %s } UNION { %s }", $1, $3); else @@ -95,7 +104,11 @@ BOOL { | match {$$ = $1; if ($$ == NULL) YYABORT;} | function {$$ = $1;} | OBRACE expr CBRACE {$$ = talloc_asprintf(ssp_slq, "%s", $2);} -| expr AND expr {$$ = talloc_asprintf(ssp_slq, "%s . %s", $1, $3);} +| expr AND expr { + if (!ssp_slq->slq_allow_expr) + YYABORT; + $$ = talloc_asprintf(ssp_slq, "%s . %s", $1, $3); +} | expr OR expr { if (strcmp($1, $3) != 0) $$ = talloc_asprintf(ssp_slq, "{ %s } UNION { %s }", $1, $3); @@ -206,7 +219,7 @@ static const char *map_expr(const char *attr, char op, const char *val) bstring q = NULL, search = NULL, replace = NULL; for (p = spotlight_sparql_map; p->ssm_spotlight_attr; p++) { - if (strcmp(p->ssm_spotlight_attr, attr) == 0) { + if (p->ssm_enabled && (strcmp(p->ssm_spotlight_attr, attr) == 0)) { if (p->ssm_type != ssmt_type && p->ssm_sparql_attr == NULL) { yyerror("unsupported Spotlight attribute"); EC_FAIL; @@ -331,6 +344,7 @@ int main(int argc, char **argv) struct vol *vol = talloc_zero(ssp_slq, struct vol); vol->v_path = "/Volumes/test"; ssp_slq->slq_vol = vol; + ssp_slq->slq_allow_expr = true; sparqlvar = 'a'; s = yy_scan_string(argv[1]); diff --git a/include/atalk/globals.h b/include/atalk/globals.h index 21b8b4e8..603b5caa 100644 --- a/include/atalk/globals.h +++ b/include/atalk/globals.h @@ -60,6 +60,7 @@ #define OPTION_SPOTLIGHT (1 << 13) /* whether to initialize Spotlight support */ #define OPTION_SPOTLIGHT_VOL (1 << 14) /* whether spotlight shall be enabled by default for volumes */ #define OPTION_RECVFILE (1 << 15) +#define OPTION_SPOTLIGHT_EXPR (1 << 16) /* whether to allow Spotlight logic expressions */ #define PASSWD_NONE 0 #define PASSWD_SET (1 << 0) @@ -130,6 +131,7 @@ struct afp_options { char *cnid_mysql_pw; char *cnid_mysql_db; struct afp_volume_name volfile; + uint64_t sparql_limit; }; typedef struct AFPObj { diff --git a/include/atalk/spotlight.h b/include/atalk/spotlight.h index 0ca8a24e..bafa52f5 100644 --- a/include/atalk/spotlight.h +++ b/include/atalk/spotlight.h @@ -43,7 +43,7 @@ struct sl_module_export { int (*sl_mod_index_file) (const void *); }; -extern int sl_mod_load(const char *path); +extern int sl_mod_load(AFPObj *obj); extern void sl_index_file(const char *path); /************************************************************************************************** @@ -105,6 +105,8 @@ typedef struct _slq_t { size_t slq_cnids_num; /* Size of slq_cnids array */ const char *slq_path; /* Path to file or dir, used in fetchAttributes */ void *slq_tracker_cursor; /* Tracker SPARQL query result cursor */ + bool slq_allow_expr; /* Whether to allow logic expressions */ + uint64_t slq_result_limit; /* Whether to LIMIT SPARQL results, default of 0 means no limit */ } slq_t; /************************************************************************************************** @@ -114,5 +116,6 @@ typedef struct _slq_t { extern int afp_spotlight_rpc(AFPObj *obj, char *ibuf, size_t ibuflen _U_, char *rbuf, size_t *rbuflen); extern int sl_pack(DALLOC_CTX *query, char *buf); extern int sl_unpack(DALLOC_CTX *query, const char *buf); +extern void configure_spotlight_attributes(const char *attributes); #endif /* SPOTLIGHT_H */ diff --git a/libatalk/util/netatalk_conf.c b/libatalk/util/netatalk_conf.c index 01e1f167..71acf884 100644 --- a/libatalk/util/netatalk_conf.c +++ b/libatalk/util/netatalk_conf.c @@ -1828,6 +1828,8 @@ int afp_config_parse(AFPObj *AFPObj, char *processname) options->passwdbits |= PASSWD_NOSAVE; if (atalk_iniparser_getboolean(config, INISEC_GLOBAL, "set password", 0)) options->passwdbits |= PASSWD_SET; + if (atalk_iniparser_getboolean(config, INISEC_GLOBAL, "spotlight expr", 1)) + options->flags |= OPTION_SPOTLIGHT_EXPR; /* figure out options w values */ options->loginmesg = atalk_iniparser_getstrdup(config, INISEC_GLOBAL, "login message", NULL); @@ -1866,6 +1868,7 @@ int afp_config_parse(AFPObj *AFPObj, char *processname) options->sleep = atalk_iniparser_getint (config, INISEC_GLOBAL, "sleep time", 10); options->disconnected = atalk_iniparser_getint (config, INISEC_GLOBAL, "disconnect time",24); options->splice_size = atalk_iniparser_getint (config, INISEC_GLOBAL, "splice size", 64*1024); + options->sparql_limit = atalk_iniparser_getint (config, INISEC_GLOBAL, "sparql results limit", 0); p = atalk_iniparser_getstring(config, INISEC_GLOBAL, "map acls", "rights"); if (STRCMP(p, ==, "rights")) diff --git a/man/man5/afp.conf.5.in b/man/man5/afp.conf.5.in index e50d634c..c6eb8388 100644 --- a/man/man5/afp.conf.5.in +++ b/man/man5/afp.conf.5.in @@ -631,13 +631,40 @@ solaris share reservations = \fIBOOLEAN\fR (default: \fIyes\fR) \fB(G)\fR Use share reservations on Solaris\&. Solaris CIFS server uses this too, so this makes a lock coherent multi protocol server\&. .RE .PP -spotlight = \fIBOOLEAN\fR (default: \fIno\fR) \fB(G)/(V)\fR +sparql results limit = \fINUMBER\fR (default: \fIUNLIMITED\fR) \fB(G)\fR +.RS 4 +Impose a limit on the number of results queried from Tracker via SPARQL queries\&. +.RE +.PP +spotlight = \fIBOOLEAN\fR (default: \fIno\fR) \fB(G)\fR .RS 4 Whether to enable Spotlight searches\&. Note: once the global option is enabled, any volume that is not enabled won\*(Aqt be searchable at all\&. See also \fIdbus daemon\fR option\&. .RE .PP +spotlight attributes = \fICOMMA SEPERATED STRING\fR (default: \fIEMPTY\fR) \fB(G)\fR +.RS 4 +A list of attributes that are allowed to be used in Spotlight searches\&. By default all attributes can be searched, passing a string limits attributes to elements of the string\&. Example: +.sp +.if n \{\ +.RS 4 +.\} +.nf +spotlight + attributes = *,kMDItemTextContent +.fi +.if n \{\ +.RE +.\} +.sp +.RE +.PP +spotlight expr = \fIBOOLEAN\fR (default: \fIyes\fR) \fB(G)\fR +.RS 4 +Whether to allow the use of logic expression in searches\&. +.RE +.PP start dbus = \fIBOOLEAN\fR (default: \fIyes\fR) \fB(G)\fR .RS 4 Whether to start a dbus instance for use with Tracker\&.