]> arthur.barton.de Git - netatalk.git/blob - etc/afpd/spotlight.c
Rename unmarshalling functions
[netatalk.git] / etc / afpd / spotlight.c
1 /*
2   Copyright (c) 2012 Frank Lahm <franklahm@gmail.com>
3
4   This program is free software; you can redistribute it and/or modify
5   it under the terms of the GNU General Public License as published by
6   the Free Software Foundation; either version 2 of the License, or
7   (at your option) any later version.
8
9   This program is distributed in the hope that it will be useful,
10   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   GNU General Public License for more details.
13 */
14
15 #ifdef HAVE_CONFIG_H
16 #include "config.h"
17 #endif /* HAVE_CONFIG_H */
18
19 #include <string.h>
20 #include <strings.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <errno.h>
24 #include <stdbool.h>
25 #include <inttypes.h>
26
27 #include <atalk/errchk.h>
28 #include <atalk/util.h>
29 #include <atalk/logger.h>
30 #include <atalk/talloc.h>
31 #include <atalk/dalloc.h>
32 #include <atalk/byteorder.h>
33 #include <atalk/netatalk_conf.h>
34 #include <atalk/volume.h>
35
36 #include "spotlight.h"
37
38 /**************************************************************************************************
39  * RPC data marshalling and unmarshalling
40  **************************************************************************************************/
41
42 /* FPSpotlightRPC subcommand codes */
43 #define SPOTLIGHT_CMD_VOLPATH 1
44 #define SPOTLIGHT_CMD_FLAGS   2
45 #define SPOTLIGHT_CMD_RPC     3
46
47 /* Spotlight epoch is UNIX epoch minus SPOTLIGHT_TIME_DELTA */
48 #define SPOTLIGHT_TIME_DELTA INT64_C(280878921600U)
49
50 #define SQ_TYPE_NULL    0x0000
51 #define SQ_TYPE_COMPLEX 0x0200
52 #define SQ_TYPE_INT64   0x8400
53 #define SQ_TYPE_BOOL    0x0100
54 #define SQ_TYPE_FLOAT   0x8500
55 #define SQ_TYPE_DATA    0x0700
56 #define SQ_TYPE_CNIDS   0x8700
57 #define SQ_TYPE_UUID    0x0e00
58 #define SQ_TYPE_DATE    0x8600
59
60 #define SQ_CPX_TYPE_ARRAY               0x0a00
61 #define SQ_CPX_TYPE_STRING              0x0c00
62 #define SQ_CPX_TYPE_UTF16_STRING        0x1c00
63 #define SQ_CPX_TYPE_DICT                0x0d00
64 #define SQ_CPX_TYPE_CNIDS               0x1a00
65 #define SQ_CPX_TYPE_FILEMETA            0x1b00
66
67 #define SUBQ_SAFETY_LIM 20
68
69 /* Can be ored and used as flags */
70 #define SL_ENC_LITTLE_ENDIAN 1
71 #define SL_ENC_BIG_ENDIAN    2
72 #define SL_ENC_UTF_16        4
73
74 /* Forward declarations */
75 static int dissect_spotlight(DALLOC_CTX *query, const char *buf);
76
77 /* Helper functions and stuff */
78 static const char *neststrings[] = {
79     "",
80     "    ",
81     "        ",
82     "            ",
83     "                ",
84     "                    ",
85     "                        "
86 };
87
88 static int dd_dump(DALLOC_CTX *dd, int nestinglevel)
89 {
90     const char *type;
91
92     LOG(log_debug, logtype_sl, "%s1: %s(#%d): {", neststrings[nestinglevel], talloc_get_name(dd), talloc_array_length(dd->dd_talloc_array));
93
94     for (int n = 0; n < talloc_array_length(dd->dd_talloc_array); n++) {
95
96         type = talloc_get_name(dd->dd_talloc_array[n]);
97
98         if (STRCMP(type, ==, "DALLOC_CTX")
99                    || STRCMP(type, ==, "sl_array_t")
100                    || STRCMP(type, ==, "sl_dict_t")) {
101             dd_dump(dd->dd_talloc_array[n], nestinglevel + 1);
102         } else if (STRCMP(type, ==, "uint64_t")) {
103             uint64_t i;
104             memcpy(&i, dd->dd_talloc_array[n], sizeof(uint64_t));
105             LOG(log_debug, logtype_sl, "%s%u:\t0x%04x", neststrings[nestinglevel + 1], n + 1, i);
106         } else if (STRCMP(type, ==, "int64_t")) {
107             int64_t i;
108             memcpy(&i, dd->dd_talloc_array[n], sizeof(int64_t));
109             LOG(log_debug, logtype_sl, "%s%d:\t%" PRId64, neststrings[nestinglevel + 1], n + 1, i);
110         } else if (STRCMP(type, ==, "uint32_t")) {
111             uint32_t i;
112             memcpy(&i, dd->dd_talloc_array[n], sizeof(uint32_t));
113             LOG(log_debug, logtype_sl, "%s%d:\t%" PRIu32, neststrings[nestinglevel + 1], n + 1, i);
114         } else if (STRCMP(type, ==, "char *")) {
115             char *s;
116             memcpy(&s, dd->dd_talloc_array[n], sizeof(char *));
117             LOG(log_debug, logtype_sl, "%s%d:\t%s", neststrings[nestinglevel + 1], n + +1, s);
118         } else if (STRCMP(type, ==, "sl_bool_t")) {
119             sl_bool_t bl;
120             memcpy(&bl, dd->dd_talloc_array[n], sizeof(sl_bool_t));
121             LOG(log_debug, logtype_sl, "%s%d:\t%s", neststrings[nestinglevel + 1], n + +1, bl ? "true" : "false");
122         } else if (STRCMP(type, ==, "sl_cnids_t")) {
123             sl_cnids_t cnids;
124             memcpy(&cnids, dd->dd_talloc_array[n], sizeof(sl_cnids_t));
125             LOG(log_debug, logtype_sl, "%s%d:\tunkn1: %" PRIu16 ", unkn2: %" PRIu32,
126                    neststrings[nestinglevel + 1], n + 1, cnids.ca_unkn1, cnids.ca_unkn2);
127             if (cnids.ca_cnids)
128                 dd_dump(cnids.ca_cnids, nestinglevel + 1);
129         }
130     }
131     LOG(log_debug, logtype_sl, "%s}", neststrings[nestinglevel]);
132 }
133
134 /*
135 * Returns the UTF-16 string encoding, by checking the 2-byte byte order mark.
136 * If there is no byte order mark, -1 is returned.
137 */
138 static uint spotlight_get_utf16_string_encoding(const char *buf, int offset, int query_length, uint encoding) {
139         uint utf16_encoding;
140
141         /* check for byte order mark */
142         utf16_encoding = SL_ENC_BIG_ENDIAN;
143         if (query_length >= 2) {
144                 uint16_t byte_order_mark;
145                 if (encoding == SL_ENC_LITTLE_ENDIAN)
146                         byte_order_mark = SVAL(buf, offset);
147                 else
148                         byte_order_mark = RSVAL(buf, offset);
149
150                 if (byte_order_mark == 0xFFFE) {
151                         utf16_encoding = SL_ENC_BIG_ENDIAN | SL_ENC_UTF_16;
152                 }
153                 else if (byte_order_mark == 0xFEFF) {
154                         utf16_encoding = SL_ENC_LITTLE_ENDIAN | SL_ENC_UTF_16;
155                 }
156         }
157
158         return utf16_encoding;
159 }
160
161 /**************************************************************************************************
162  * marshalling functions
163  **************************************************************************************************/
164
165 static uint64_t sl_pack_tag(uint16_t type, uint16_t size, uint32_t val)
166 {
167     uint64_t tag = ((uint64_t)val << 32) | ((uint64_t)type << 16) | size;
168     return tag;
169 }
170
171 static int sl_pack_float(double d, char **buf, int *buf_len, char **toc_buf, int *toc_len, int *toc_idx)
172 {
173     union {
174         double d;
175         uint64_t w;
176     } ieee_fp_union;
177
178     SLVAL(*buf, 0, sl_pack_tag(SQ_TYPE_FLOAT, 2, 1));
179     SLVAL(*buf, 8, ieee_fp_union.w);
180     *buf += 2 * sizeof(uint64_t);
181     buf_len += 2 * sizeof(uint64_t);
182
183     return 0;
184 }
185
186 static int sl_pack_uint64(uint64_t u, char **buf, int *buf_len, char **toc_buf, int *toc_len, int *toc_idx)
187 {
188     SLVAL(*buf, 0, sl_pack_tag(SQ_TYPE_INT64, 2, 1));
189     SLVAL(*buf, 8, u);
190     *buf += 2 * sizeof(uint64_t);
191     *buf_len += 2 * sizeof(uint64_t);
192 }
193
194 /**************************************************************************************************
195  * unmarshalling functions
196  **************************************************************************************************/
197
198 static uint64_t sl_unpack_uint64(const char *buf, int offset, uint encoding)
199 {
200     if (encoding == SL_ENC_LITTLE_ENDIAN)
201             return LVAL(buf, offset);
202         else
203             return RLVAL(buf, offset);
204 }
205
206 static int sl_unpack_ints(DALLOC_CTX *query, const char *buf, int offset, uint encoding)
207 {
208         int count, i;
209         uint64_t query_data64;
210
211         query_data64 = sl_unpack_uint64(buf, offset, encoding);
212         count = query_data64 >> 32;
213         offset += 8;
214
215         i = 0;
216         while (i++ < count) {
217         query_data64 = sl_unpack_uint64(buf, offset, encoding);
218         dalloc_add(query, &query_data64, uint64_t);
219                 offset += 8;
220         }
221
222         return count;
223 }
224
225 static int sl_unpack_date(DALLOC_CTX *query, const char *buf, int offset, uint encoding)
226 {
227         int count, i;
228         uint64_t query_data64;
229         sl_time_t t;
230
231         query_data64 = sl_unpack_uint64(buf, offset, encoding);
232         count = query_data64 >> 32;
233         offset += 8;
234
235         i = 0;
236         while (i++ < count) {
237                 query_data64 = sl_unpack_uint64(buf, offset, encoding) >> 24;
238                 t.tv_sec = query_data64 - SPOTLIGHT_TIME_DELTA;
239                 t.tv_usec = 0;
240         dalloc_add(query, &t, sl_time_t);
241                 offset += 8;
242         }
243
244         return count;
245 }
246
247 static int sl_unpack_uuid(DALLOC_CTX *query, const char *buf, int offset, uint encoding)
248 {
249         int count, i;
250     uint64_t query_data64;
251     sl_uuid_t uuid;
252         query_data64 = sl_unpack_uint64(buf, offset, encoding);
253         count = query_data64 >> 32;
254         offset += 8;
255
256         i = 0;
257         while (i++ < count) {
258         memcpy(uuid.sl_uuid, buf + offset, 16);
259         dalloc_add(query, &uuid, sl_uuid_t);
260                 offset += 16;
261         }
262
263         return count;
264 }
265
266 static int sl_unpack_floats(DALLOC_CTX *query, const char *buf, int offset, uint encoding)
267 {
268         int count, i;
269         uint64_t query_data64;
270         double fval;
271     union {
272         double d;
273         uint32_t w[2];
274     } ieee_fp_union;
275
276         query_data64 = sl_unpack_uint64(buf, offset, encoding);
277         count = query_data64 >> 32;
278         offset += 8;
279
280         i = 0;
281         while (i++ < count) {
282         if (encoding == SL_ENC_LITTLE_ENDIAN) {
283 #ifdef WORDS_BIGENDIAN
284             ieee_fp_union.w[0] = IVAL(buf, offset + 4);
285             ieee_fp_union.w[1] = IVAL(buf, offset);
286 #else
287             ieee_fp_union.w[0] = IVAL(buf, offset);
288             ieee_fp_union.w[1] = IVAL(buf, offset + 4);
289 #endif
290         } else {
291 #ifdef WORDS_BIGENDIAN
292             ieee_fp_union.w[0] = RIVAL(buf, offset);
293             ieee_fp_union.w[1] = RIVAL(buf, offset + 4);
294 #else
295             ieee_fp_union.w[0] = RIVAL(buf, offset + 4);
296             ieee_fp_union.w[1] = RIVAL(buf, offset);
297 #endif
298         }
299         dalloc_add(query, &ieee_fp_union.d, double);
300                 offset += 8;
301         }
302
303         return count;
304 }
305
306 static int sl_unpack_CNID(DALLOC_CTX *query, const char *buf, int offset, int length, uint encoding)
307 {
308     EC_INIT;
309         int count;
310         uint64_t query_data64;
311     sl_cnids_t cnids;
312
313     EC_NULL( cnids.ca_cnids = talloc_zero(query, DALLOC_CTX) );
314
315     if (length <= 16)
316         /* that's permitted, it's an empty array */
317         goto EC_CLEANUP;
318     
319         query_data64 = sl_unpack_uint64(buf, offset, encoding);
320         count = query_data64 & 0xffff;
321
322         cnids.ca_unkn1 = (query_data64 & 0xffff0000) >> 16;
323         cnids.ca_unkn2 = query_data64 >> 32;
324
325         offset += 8;
326
327         while (count --) {
328                 query_data64 = sl_unpack_uint64(buf, offset, encoding);
329         dalloc_add(cnids.ca_cnids, &query_data64, uint64_t);
330                 offset += 8;
331         }
332
333     dalloc_add(query, &cnids, sl_cnids_t);
334
335 EC_CLEANUP:
336     EC_EXIT;
337 }
338
339 static const char *spotlight_get_qtype_string(uint64_t query_type)
340 {
341         switch (query_type) {
342         case SQ_TYPE_NULL:
343                 return "null";
344         case SQ_TYPE_COMPLEX:
345                 return "complex";
346         case SQ_TYPE_INT64:
347                 return "int64";
348         case SQ_TYPE_BOOL:
349                 return "bool";
350         case SQ_TYPE_FLOAT:
351                 return "float";
352         case SQ_TYPE_DATA:
353                 return "data";
354         case SQ_TYPE_CNIDS:
355                 return "CNIDs";
356         default:
357                 return "unknown";
358         }
359 }
360
361 static const char *spotlight_get_cpx_qtype_string(uint64_t cpx_query_type)
362 {
363         switch (cpx_query_type) {
364         case SQ_CPX_TYPE_ARRAY:
365                 return "array";
366         case SQ_CPX_TYPE_STRING:
367                 return "string";
368         case SQ_CPX_TYPE_UTF16_STRING:
369                 return "utf-16 string";
370         case SQ_CPX_TYPE_DICT:
371                 return "dictionary";
372         case SQ_CPX_TYPE_CNIDS:
373                 return "CNIDs";
374         case SQ_CPX_TYPE_FILEMETA:
375                 return "FileMeta";
376         default:
377                 return "unknown";
378         }
379 }
380
381 static int spotlight_dissect_loop(DALLOC_CTX *query,
382                                   const char *buf,
383                                   uint offset,
384                                   uint count,
385                                   const uint toc_offset,
386                                   const uint encoding)
387 {
388     EC_INIT;
389         int i, toc_index, query_length;
390     uint subcount, cpx_query_type, cpx_query_count;
391         uint64_t query_data64, query_type;
392         uint unicode_encoding;
393         uint8_t mark_exists;
394     char *p;
395     int padding, slen;
396
397         while (count > 0 && (offset < toc_offset)) {
398                 query_data64 = sl_unpack_uint64(buf, offset, encoding);
399                 query_length = (query_data64 & 0xffff) * 8;
400                 query_type = (query_data64 & 0xffff0000) >> 16;
401                 if (query_length == 0)
402             EC_FAIL;
403
404                 switch (query_type) {
405                 case SQ_TYPE_COMPLEX:
406                         toc_index = (query_data64 >> 32) - 1;
407                         query_data64 = sl_unpack_uint64(buf, toc_offset + toc_index * 8, encoding);
408                         cpx_query_type = (query_data64 & 0xffff0000) >> 16;
409             cpx_query_count = query_data64 >> 32;
410
411             switch (cpx_query_type) {
412                         case SQ_CPX_TYPE_ARRAY: {
413                 sl_array_t *sl_arrary = talloc_zero(query, sl_array_t);
414                 EC_NEG1_LOG( offset = spotlight_dissect_loop(sl_arrary, buf, offset + 8, cpx_query_count, toc_offset, encoding) );
415                 dalloc_add(query, sl_arrary, sl_array_t);
416                 break;
417             }
418
419                         case SQ_CPX_TYPE_DICT: {
420                 sl_dict_t *sl_dict = talloc_zero(query, sl_dict_t);
421                 EC_NEG1_LOG( offset = spotlight_dissect_loop(sl_dict, buf, offset + 8, cpx_query_count, toc_offset, encoding) );
422                 dalloc_add(query, sl_dict, sl_dict_t);
423                 break;
424             }
425             case SQ_CPX_TYPE_STRING:
426                 query_data64 = sl_unpack_uint64(buf, offset + 8, encoding);
427                 query_length += (query_data64 & 0xffff) * 8;
428                 if ((padding = 8 - (query_data64 >> 32)) < 0)
429                     EC_FAIL;
430                 if ((slen = query_length - 16 - padding) < 1)
431                     EC_FAIL;
432                 p = talloc_strndup(query, buf + offset + 16, slen);
433                 dalloc_add(query, &p, char *);
434                 break;
435
436             case SQ_CPX_TYPE_UTF16_STRING:
437                 query_data64 = sl_unpack_uint64(buf, offset + 8, encoding);
438                 query_length += (query_data64 & 0xffff) * 8;
439                 if ((padding = 8 - (query_data64 >> 32)) < 0)
440                     EC_FAIL;
441                 if ((slen = query_length - 16 - padding) < 1)
442                     EC_FAIL;
443
444                 unicode_encoding = spotlight_get_utf16_string_encoding(buf, offset + 16, slen, encoding);
445                 mark_exists = (unicode_encoding & SL_ENC_UTF_16);
446                 unicode_encoding &= ~SL_ENC_UTF_16;
447
448                 EC_NEG1( convert_string_allocate(CH_UCS2, CH_UTF8, buf + offset + (mark_exists ? 18 : 16), slen, &p) );
449                 dalloc_add(query, &p, char *);
450                 break;
451
452             case SQ_CPX_TYPE_FILEMETA:
453                 query_data64 = sl_unpack_uint64(buf, offset + 8, encoding);
454                 query_length += (query_data64 & 0xffff) * 8;
455
456                 if (query_length <= 8) {
457                     EC_FAIL_LOG("SQ_CPX_TYPE_FILEMETA: query_length <= 8%s", "");
458                 } else {
459                     EC_NEG1_LOG( dissect_spotlight(query, buf + offset + 16) );
460                 }
461                 break;
462
463             case SQ_CPX_TYPE_CNIDS:
464                 query_data64 = sl_unpack_uint64(buf, offset + 8, encoding);
465                 query_length += (query_data64 & 0xffff) * 8;
466                 EC_NEG1_LOG( sl_unpack_CNID(query, buf, offset + 16, query_length, encoding) );
467                 break;
468             } /* switch (cpx_query_type) */
469
470                         count--;
471                         break;
472
473         case SQ_TYPE_NULL: {
474             subcount = query_data64 >> 32;
475             if (subcount > 64)
476                 EC_FAIL;
477             sl_nil_t nil = 0;
478             for (i = 0; i < subcount; i++)
479                 dalloc_add(query, &nil, sl_nil_t);
480             count -= subcount;
481             break;
482         }
483         case SQ_TYPE_BOOL: {
484             sl_bool_t b = query_data64 >> 32;
485             dalloc_add(query, &b, sl_bool_t);
486             count--;
487             break;
488         }
489         case SQ_TYPE_INT64:
490             EC_NEG1_LOG( subcount = sl_unpack_ints(query, buf, offset, encoding) );
491             count -= subcount;
492             break;
493         case SQ_TYPE_UUID:
494             EC_NEG1_LOG( subcount = sl_unpack_uuid(query, buf, offset, encoding) );
495             count -= subcount;
496             break;
497         case SQ_TYPE_FLOAT:
498             EC_NEG1_LOG( subcount = sl_unpack_floats(query, buf, offset, encoding) );
499             count -= subcount;
500             break;
501         case SQ_TYPE_DATE:
502             EC_NEG1_LOG( subcount = sl_unpack_date(query, buf, offset, encoding) );
503             count -= subcount;
504             break;
505         default:
506             EC_FAIL;
507         }
508
509         offset += query_length;
510     }
511
512 EC_CLEANUP:
513     if (ret != 0) {
514         offset = -1;
515     }
516         return offset;
517 }
518
519 static int dissect_spotlight(DALLOC_CTX *query, const char *buf)
520 {
521     EC_INIT;
522         int encoding, i, toc_entries;
523         uint64_t toc_offset, tquerylen, toc_entry;
524
525         if (strncmp(buf, "md031234", 8) == 0)
526                 encoding = SL_ENC_BIG_ENDIAN;
527         else
528                 encoding = SL_ENC_LITTLE_ENDIAN;
529
530         buf += 8;
531
532         toc_offset = ((sl_unpack_uint64(buf, 0, encoding) >> 32) - 1 ) * 8;
533         if (toc_offset < 0 || (toc_offset > 65000)) {
534         EC_FAIL;
535         }
536
537         buf += 8;
538
539         toc_entries = (int)(sl_unpack_uint64(buf, toc_offset, encoding) & 0xffff);
540
541         EC_NEG1( spotlight_dissect_loop(query, buf, 0, 1, toc_offset + 8, encoding) );
542
543 EC_CLEANUP:
544     EC_EXIT;
545 }
546
547 /**************************************************************************************************
548  * AFP functions
549  **************************************************************************************************/
550 int afp_spotlight_rpc(AFPObj *obj, char *ibuf, size_t ibuflen, char *rbuf, size_t *rbuflen)
551 {
552     EC_INIT;
553     TALLOC_CTX *tmp_ctx = talloc_new(NULL);
554     uint16_t vid;
555     int cmd;
556     int endianess = SL_ENC_LITTLE_ENDIAN;
557     struct vol      *vol;
558     DALLOC_CTX *query;
559
560     *rbuflen = 0;
561
562     ibuf += 2;
563     ibuflen -= 2;
564
565     vid = SVAL(ibuf, 0);
566     LOG(log_debug, logtype_sl, "afp_spotlight_rpc(vid: %" PRIu16 ")", vid);
567
568     if ((vol = getvolbyvid(vid)) == NULL) {
569         LOG(log_error, logtype_sl, "afp_spotlight_rpc: bad volume id: %" PRIu16 ")", vid);
570         ret = AFPERR_ACCESS;
571         goto EC_CLEANUP;
572     }
573
574     /*    IVAL(ibuf, 2): unknown, always 0x00008004, some flags ? */
575
576     cmd = RIVAL(ibuf, 6);
577     LOG(log_debug, logtype_sl, "afp_spotlight_rpc(cmd: %d)", cmd);
578
579     /*    IVAL(ibuf, 10: unknown, always 0x00000000 */
580
581         switch (cmd) {
582
583         case SPOTLIGHT_CMD_VOLPATH: {
584         RSIVAL(rbuf, 0, ntohs(vid));
585         RSIVAL(rbuf, 4, 0);
586         int len = strlen(vol->v_path) + 1;
587         strncpy(rbuf + 8, vol->v_path, len);
588         *rbuflen += 8 + len;
589                 break;
590     }
591         case SPOTLIGHT_CMD_FLAGS:
592         RSIVAL(rbuf, 0, 0x0100006b); /* Whatever this value means... flags? */
593         *rbuflen += 4;
594                 break;
595
596         case SPOTLIGHT_CMD_RPC: {
597         DALLOC_CTX *query;
598         EC_NULL( query = talloc_zero(tmp_ctx, DALLOC_CTX) );
599         (void)dissect_spotlight(query, ibuf + 22);
600         dd_dump(query, 0);
601                 break;
602     }
603         }
604
605 EC_CLEANUP:
606     talloc_free(tmp_ctx);
607     if (ret != AFP_OK) {
608         return AFPERR_MISC;
609     }
610     EC_EXIT;
611 }
612
613 /**************************************************************************************************
614  * Testing
615  **************************************************************************************************/
616
617 #ifdef SPOT_TEST_MAIN
618
619 int main(int argc, char **argv)
620 {
621     EC_INIT;
622     TALLOC_CTX *mem_ctx = talloc_new(NULL);
623     DALLOC_CTX *dd = talloc_zero(mem_ctx, DALLOC_CTX);
624     int64_t i;
625
626     set_processname("spot");
627     setuplog("default:info", "/dev/tty");
628
629     LOG(log_info, logtype_sl, "Start");
630
631 #if 0
632     i = 2;
633     dalloc_add(dd, &i, int64_t);
634
635     i = 1;
636     dalloc_add(dd, &i, int64_t);
637
638
639     char *str = talloc_strdup(dd, "hello world");
640     dalloc_add(dd, &str, char *);
641
642     sl_bool_t b = true;
643     dalloc_add(dd, &b, sl_bool_t);
644
645     b = false;
646     dalloc_add(dd, &b, sl_bool_t);
647
648
649     /* add a nested array */
650     DALLOC_CTX *nested = talloc_zero(dd, DALLOC_CTX);
651     i = 3;
652     dalloc_add(nested, &i, int64_t);
653     dalloc_add(dd, nested, DALLOC_CTX);
654
655     /* test an allocated CNID array */
656     uint32_t id = 16;
657     sl_cnids_t *cnids = talloc_zero(dd, sl_cnids_t);
658
659     cnids->ca_cnids = talloc_zero(cnids, DALLOC_CTX);
660
661     cnids->ca_unkn1 = 1;
662     cnids->ca_unkn2 = 2;
663
664     dalloc_add(cnids->ca_cnids, &id, uint32_t);
665     dalloc_add(dd, cnids, sl_cnids_t);
666
667     /* Now the Spotlight types */
668     sl_array_t *sl_arrary = talloc_zero(dd, sl_array_t);
669     i = 1234;
670     dalloc_add(sl_arrary, &i, int64_t);
671
672     sl_dict_t *sl_dict = talloc_zero(dd, sl_dict_t);
673     i = 5678;
674     dalloc_add(sl_dict, &i, int64_t);
675     dalloc_add(sl_arrary, sl_dict, sl_dict_t);
676
677     dalloc_add(dd, sl_arrary, sl_array_t);
678 #endif
679
680     /* now parse a real spotlight packet */
681     char ibuf[8192];
682     char rbuf[8192];
683     int fd;
684     size_t len;
685     DALLOC_CTX *query;
686
687     EC_NULL( query = talloc_zero(mem_ctx, DALLOC_CTX) );
688
689     EC_NEG1_LOG( fd = open("/home/ralph/netatalk/spot/etc/afpd/spotlight-packet.bin", O_RDONLY) );
690     EC_NEG1_LOG( len = read(fd, ibuf, 8192) );
691     EC_NEG1_LOG( dissect_spotlight(query, ibuf + 24) );
692
693     /* Now dump the whole thing */
694     dd_dump(query, 0);
695
696 EC_CLEANUP:
697     if (mem_ctx) {
698         talloc_free(mem_ctx);
699         mem_ctx = NULL;
700     }
701     EC_EXIT;
702 }
703 #endif