Browse files

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 <rb@sernet.de>
  • Loading branch information...
1 parent feb4654 commit 371efee757ed56fd9e2f46b39fae625924d2cfc2 @slowfranklin slowfranklin committed Jun 4, 2014
View
2 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
================
View
39 doc/manpages/man5/afp.conf.5.xml
@@ -991,9 +991,20 @@
</varlistentry>
<varlistentry>
+ <term>sparql results limit =
+ <replaceable>NUMBER</replaceable> (default:
+ <emphasis>UNLIMITED</emphasis>) <type>(G)</type></term>
+
+ <listitem>
+ <para>Impose a limit on the number of results queried from Tracker
+ via SPARQL queries.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>spotlight =
<replaceable>BOOLEAN</replaceable> (default:
- <emphasis>no</emphasis>) <type>(G)/(V)</type></term>
+ <emphasis>no</emphasis>) <type>(G)</type></term>
<listitem>
<para>Whether to enable Spotlight searches. Note: once the global
@@ -1004,6 +1015,32 @@
</varlistentry>
<varlistentry>
+ <term>spotlight attributes =
+ <replaceable>COMMA SEPERATED STRING</replaceable> (default:
+ <emphasis>EMPTY</emphasis>) <type>(G)</type></term>
+
+ <listitem>
+ <para>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: <programlisting>spotlight
+ attributes = *,kMDItemTextContent</programlisting>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>spotlight expr =
+ <replaceable>BOOLEAN</replaceable> (default:
+ <emphasis>yes</emphasis>) <type>(G)</type></term>
+
+ <listitem>
+ <para>Whether to allow the use of logic expression in
+ searches.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term>start dbus =
<replaceable>BOOLEAN</replaceable> (default:
<emphasis>yes</emphasis>) <type>(G)</type></term>
View
2 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);
View
15 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 @@ static int sl_rpc_closeQueryForContext(const AFPObj *obj, const DALLOC_CTX *quer
* 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;
View
8 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;
}
View
101 etc/spotlight/slmod_sparql_map.c
@@ -17,55 +17,59 @@
#endif /* HAVE_CONFIG_H */
#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <atalk/logger.h>
#include "slmod_sparql_map.h"
#define NOTSUPPORTED NULL
#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);
+}
View
1 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;
};
View
82 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,22 +210,22 @@ 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);
extern slq_t *ssp_slq;
/* 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 @@ yyparse ()
{
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 @@ yyparse ()
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 @@ yyparse ()
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 @@ yyparse ()
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 @@ yyparse ()
/* 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]);
View
4 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);
View
22 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]);
View
2 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 {
View
5 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 */
View
3 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"))
View
29 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\&.

0 comments on commit 371efee

Please sign in to comment.