]>
Commit | Line | Data |
---|---|---|
81582353 A |
1 | /* |
2 | * Copyright (c) 2007-2011 Apple Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ */ | |
22 | ||
23 | #include <asl_core.h> | |
24 | #include <asl_legacy1.h> | |
25 | #include <asl_private.h> | |
26 | #include <stdlib.h> | |
27 | #include <sys/file.h> | |
28 | #include <sys/stat.h> | |
29 | #include <sys/errno.h> | |
30 | #include <string.h> | |
31 | #include <membership.h> | |
32 | #include <mach/mach.h> | |
33 | #include <sys/syslimits.h> | |
34 | #include <sys/types.h> | |
35 | #include <time.h> | |
36 | #include <sys/mman.h> | |
37 | ||
38 | #define forever for(;;) | |
39 | ||
40 | #define FILE_MODE 0600 | |
41 | ||
42 | #define DB_RECORD_LEN 80 | |
43 | ||
44 | #define DB_HEADER_COOKIE_OFFSET 0 | |
45 | #define DB_HEADER_VERS_OFFSET 12 | |
46 | ||
47 | #define DB_TYPE_EMPTY 0 | |
48 | #define DB_TYPE_HEADER 1 | |
49 | #define DB_TYPE_MESSAGE 2 | |
50 | #define DB_TYPE_KVLIST 3 | |
51 | #define DB_TYPE_STRING 4 | |
52 | #define DB_TYPE_STRCONT 5 | |
53 | ||
54 | /* | |
55 | * Magic Cookie for database files. | |
56 | * MAXIMUM 12 CHARS! (DB_HEADER_VERS_OFFSET) | |
57 | */ | |
58 | #define ASL_DB_COOKIE "ASL DB" | |
59 | #define ASL_DB_COOKIE_LEN 6 | |
60 | ||
61 | #define ASL_INDEX_NULL 0xffffffff | |
62 | ||
63 | #define DB_HLEN_EMPTY 0 | |
64 | #define DB_HLEN_HEADER 13 | |
65 | #define DB_HLEN_MESSAGE 13 | |
66 | #define DB_HLEN_KVLIST 9 | |
67 | #define DB_HLEN_STRING 25 | |
68 | #define DB_HLEN_STRCONT 5 | |
69 | ||
70 | #define MSG_OFF_KEY_TYPE 0 | |
71 | #define MSG_OFF_KEY_NEXT 1 | |
72 | #define MSG_OFF_KEY_ID 5 | |
73 | #define MSG_OFF_KEY_RUID 13 | |
74 | #define MSG_OFF_KEY_RGID 17 | |
75 | #define MSG_OFF_KEY_TIME 21 | |
76 | #define MSG_OFF_KEY_HOST 29 | |
77 | #define MSG_OFF_KEY_SENDER 37 | |
78 | #define MSG_OFF_KEY_FACILITY 45 | |
79 | #define MSG_OFF_KEY_LEVEL 53 | |
80 | #define MSG_OFF_KEY_PID 57 | |
81 | #define MSG_OFF_KEY_UID 61 | |
82 | #define MSG_OFF_KEY_GID 65 | |
83 | #define MSG_OFF_KEY_MSG 69 | |
84 | #define MSG_OFF_KEY_FLAGS 77 | |
85 | ||
f3df4c03 | 86 | extern int asl_msg_cmp(asl_msg_t *a, asl_msg_t *b); |
81582353 A |
87 | |
88 | #define Q_NULL 100001 | |
89 | #define Q_FAST 100002 | |
90 | #define Q_SLOW 100003 | |
91 | #define Q_FAIL 100004 | |
92 | ||
93 | static uint64_t | |
94 | _asl_htonq(uint64_t n) | |
95 | { | |
96 | #ifdef __BIG_ENDIAN__ | |
97 | return n; | |
98 | #else | |
99 | u_int32_t t; | |
100 | union | |
101 | { | |
102 | u_int64_t q; | |
103 | u_int32_t l[2]; | |
104 | } x; | |
105 | ||
106 | x.q = n; | |
107 | t = x.l[0]; | |
108 | x.l[0] = htonl(x.l[1]); | |
109 | x.l[1] = htonl(t); | |
110 | ||
111 | return x.q; | |
112 | #endif | |
113 | } | |
114 | ||
115 | static uint64_t | |
116 | _asl_ntohq(uint64_t n) | |
117 | { | |
118 | #ifdef __BIG_ENDIAN__ | |
119 | return n; | |
120 | #else | |
121 | u_int32_t t; | |
122 | union | |
123 | { | |
124 | u_int64_t q; | |
125 | u_int32_t l[2]; | |
126 | } x; | |
127 | ||
128 | x.q = n; | |
129 | t = x.l[0]; | |
130 | x.l[0] = ntohl(x.l[1]); | |
131 | x.l[1] = ntohl(t); | |
132 | ||
133 | return x.q; | |
134 | #endif | |
135 | } | |
136 | ||
137 | static uint16_t | |
138 | _asl_get_16(char *h) | |
139 | { | |
140 | uint16_t x; | |
141 | ||
142 | memcpy(&x, h, 2); | |
143 | return ntohs(x); | |
144 | } | |
145 | ||
146 | static uint32_t | |
147 | _asl_get_32(char *h) | |
148 | { | |
149 | uint32_t x; | |
150 | ||
151 | memcpy(&x, h, 4); | |
152 | return ntohl(x); | |
153 | } | |
154 | ||
155 | static uint64_t | |
156 | _asl_get_64(char *h) | |
157 | { | |
158 | uint64_t x; | |
159 | ||
160 | memcpy(&x, h, 8); | |
161 | return _asl_ntohq(x); | |
162 | } | |
163 | ||
164 | #define header_get_next(h) _asl_get_32(h + 1) | |
165 | #define header_get_id(h) _asl_get_64(h + 5) | |
166 | #define header_get_hash(h) _asl_get_32(h + 17) | |
167 | ||
168 | /* | |
169 | * callback for sorting slotlist | |
170 | * primary sort is by xid | |
171 | * secondary sort is by slot, which happens when xid is 0 | |
172 | * this allows us to quickly find xids (using binary search on the xid key) | |
173 | * it's also used to find slots quickly from record_chain_free() | |
174 | */ | |
175 | static int | |
176 | slot_comp(const void *a, const void *b) | |
177 | { | |
178 | asl_legacy1_slot_info_t *ai, *bi; | |
179 | ||
180 | if (a == NULL) | |
181 | { | |
182 | if (b == NULL) return 0; | |
183 | return -1; | |
184 | } | |
185 | ||
186 | if (b == NULL) return 1; | |
187 | ||
188 | ai = (asl_legacy1_slot_info_t *)a; | |
189 | bi = (asl_legacy1_slot_info_t *)b; | |
190 | ||
191 | if (ai->xid < bi->xid) return -1; | |
192 | ||
193 | if (ai->xid == bi->xid) | |
194 | { | |
195 | if (ai->slot < bi->slot) return -1; | |
196 | if (ai->slot == bi->slot) return 0; | |
197 | return 1; | |
198 | } | |
199 | ||
200 | return 1; | |
201 | } | |
202 | ||
203 | /* find an xid in the slot list */ | |
204 | static uint32_t | |
205 | slotlist_find(asl_legacy1_t *s, uint64_t xid, int32_t direction) | |
206 | { | |
207 | uint32_t top, bot, mid, range; | |
208 | ||
209 | if (s == NULL) return ASL_INDEX_NULL; | |
210 | if (s->slotlist_count == 0) return ASL_INDEX_NULL; | |
211 | if (xid == 0) return ASL_INDEX_NULL; | |
212 | ||
213 | top = s->slotlist_count - 1; | |
214 | bot = 0; | |
215 | mid = top / 2; | |
216 | ||
217 | range = top - bot; | |
218 | while (range > 1) | |
219 | { | |
220 | if (xid == s->slotlist[mid].xid) return mid; | |
221 | else if (xid < s->slotlist[mid].xid) top = mid; | |
222 | else bot = mid; | |
223 | ||
224 | range = top - bot; | |
225 | mid = bot + (range / 2); | |
226 | } | |
227 | ||
228 | if (xid == s->slotlist[top].xid) return top; | |
229 | if (xid == s->slotlist[bot].xid) return bot; | |
230 | ||
f3df4c03 | 231 | if (direction >= 0) return ASL_INDEX_NULL; |
81582353 A |
232 | if (direction < 0) return bot; |
233 | return top; | |
234 | } | |
235 | ||
f3df4c03 | 236 | static ASL_STATUS |
81582353 A |
237 | slotlist_init(asl_legacy1_t *s, uint32_t count) |
238 | { | |
239 | uint32_t i, si, status, hash, addslot; | |
240 | uint64_t xid; | |
241 | uint8_t t; | |
242 | size_t rcount; | |
243 | char tmp[DB_RECORD_LEN]; | |
244 | ||
245 | /* Start at first slot after the header */ | |
246 | status = fseek(s->db, DB_RECORD_LEN, SEEK_SET); | |
247 | if (status != 0) return ASL_STATUS_READ_FAILED; | |
248 | ||
249 | s->slotlist = (asl_legacy1_slot_info_t *)calloc(count, sizeof(asl_legacy1_slot_info_t)); | |
250 | if (s->slotlist == NULL) return ASL_STATUS_NO_MEMORY; | |
251 | ||
252 | si = 0; | |
253 | ||
254 | for (i = 1; i < count; i++) | |
255 | { | |
256 | rcount = fread(tmp, DB_RECORD_LEN, 1, s->db); | |
257 | if (rcount != 1) return ASL_STATUS_READ_FAILED; | |
258 | ||
259 | t = tmp[0]; | |
260 | addslot = 0; | |
261 | xid = 0; | |
262 | hash = 0; | |
263 | ||
264 | if (t == DB_TYPE_EMPTY) addslot = 1; | |
265 | ||
266 | if (t == DB_TYPE_STRING) | |
267 | { | |
268 | addslot = 1; | |
269 | xid = header_get_id(tmp); | |
270 | hash = header_get_hash(tmp); | |
271 | } | |
272 | ||
273 | if (t == DB_TYPE_MESSAGE) | |
274 | { | |
275 | addslot = 1; | |
276 | xid = header_get_id(tmp); | |
277 | } | |
278 | ||
279 | if (addslot == 1) | |
280 | { | |
281 | s->slotlist[si].type = t; | |
282 | s->slotlist[si].slot = i; | |
283 | s->slotlist[si].xid = xid; | |
284 | s->slotlist[si].hash = hash; | |
285 | si++; | |
286 | } | |
287 | } | |
288 | ||
289 | s->slotlist = (asl_legacy1_slot_info_t *)reallocf(s->slotlist, si * sizeof(asl_legacy1_slot_info_t)); | |
290 | if (s->slotlist == NULL) return ASL_STATUS_NO_MEMORY; | |
291 | s->slotlist_count = si; | |
292 | ||
293 | /* slotlist is sorted by xid */ | |
294 | qsort((void *)s->slotlist, s->slotlist_count, sizeof(asl_legacy1_slot_info_t), slot_comp); | |
295 | ||
296 | return ASL_STATUS_OK; | |
297 | } | |
298 | ||
f3df4c03 | 299 | ASL_STATUS |
81582353 A |
300 | asl_legacy1_open(const char *path, asl_legacy1_t **out) |
301 | { | |
302 | asl_legacy1_t *s; | |
303 | struct stat sb; | |
304 | int status; | |
305 | size_t rcount; | |
306 | char cbuf[DB_RECORD_LEN]; | |
307 | off_t fsize; | |
308 | uint32_t count; | |
309 | ||
310 | memset(&sb, 0, sizeof(struct stat)); | |
311 | status = stat(path, &sb); | |
312 | if (status < 0) return ASL_STATUS_FAILED; | |
313 | ||
314 | fsize = sb.st_size; | |
315 | ||
316 | s = (asl_legacy1_t *)calloc(1, sizeof(asl_legacy1_t)); | |
317 | if (s == NULL) return ASL_STATUS_NO_MEMORY; | |
318 | ||
319 | s->db = fopen(path, "r"); | |
320 | if (s->db == NULL) | |
321 | { | |
322 | free(s); | |
323 | return ASL_STATUS_INVALID_STORE; | |
324 | } | |
325 | ||
326 | memset(cbuf, 0, DB_RECORD_LEN); | |
327 | rcount = fread(cbuf, DB_RECORD_LEN, 1, s->db); | |
328 | if (rcount != 1) | |
329 | { | |
330 | fclose(s->db); | |
331 | free(s); | |
332 | return ASL_STATUS_READ_FAILED; | |
333 | } | |
334 | ||
335 | /* Check the database Magic Cookie */ | |
336 | if (strncmp(cbuf, ASL_DB_COOKIE, ASL_DB_COOKIE_LEN)) | |
337 | { | |
338 | fclose(s->db); | |
339 | free(s); | |
340 | return ASL_STATUS_INVALID_STORE; | |
341 | } | |
342 | ||
343 | count = fsize / DB_RECORD_LEN; | |
344 | ||
345 | status = slotlist_init(s, count); | |
346 | ||
347 | *out = s; | |
348 | return ASL_STATUS_OK; | |
349 | } | |
350 | ||
f3df4c03 | 351 | ASL_STATUS |
81582353 A |
352 | asl_legacy1_close(asl_legacy1_t *s) |
353 | { | |
354 | if (s == NULL) return ASL_STATUS_INVALID_STORE; | |
355 | ||
356 | if (s->slotlist != NULL) free(s->slotlist); | |
357 | if (s->db != NULL) fclose(s->db); | |
358 | free(s); | |
359 | ||
360 | return ASL_STATUS_OK; | |
361 | } | |
362 | ||
f3df4c03 | 363 | static ASL_STATUS |
81582353 A |
364 | string_fetch_slot(asl_legacy1_t *s, uint32_t slot, char **out) |
365 | { | |
366 | off_t offset; | |
367 | uint8_t type; | |
368 | uint32_t next, x, remaining; | |
369 | size_t rcount, len; | |
370 | int status; | |
371 | char *outstr, *p, tmp[DB_RECORD_LEN]; | |
372 | ||
373 | if (s == NULL) return ASL_STATUS_INVALID_STORE; | |
374 | if (out == NULL) return ASL_STATUS_INVALID_ARG; | |
375 | ||
376 | *out = NULL; | |
377 | offset = slot * DB_RECORD_LEN; | |
378 | status = fseek(s->db, offset, SEEK_SET); | |
379 | ||
380 | if (status < 0) return ASL_STATUS_READ_FAILED; | |
381 | ||
382 | rcount = fread(tmp, DB_RECORD_LEN, 1, s->db); | |
383 | if (rcount != 1) return ASL_STATUS_READ_FAILED; | |
384 | ||
385 | type = tmp[0]; | |
386 | if (type != DB_TYPE_STRING) return ASL_STATUS_INVALID_STRING; | |
387 | ||
388 | len = _asl_get_32(tmp + 21); | |
389 | if (len == 0) return ASL_STATUS_OK; | |
390 | ||
391 | next = header_get_next(tmp); | |
392 | ||
393 | outstr = calloc(1, len); | |
394 | if (outstr == NULL) return ASL_STATUS_NO_MEMORY; | |
395 | ||
396 | p = outstr; | |
397 | remaining = len; | |
398 | ||
399 | x = DB_RECORD_LEN - DB_HLEN_STRING; | |
400 | if (x > remaining) x = remaining; | |
401 | ||
402 | memcpy(p, tmp + DB_HLEN_STRING, x); | |
403 | p += x; | |
404 | remaining -= x; | |
405 | ||
406 | while ((next != 0) && (remaining > 0)) | |
407 | { | |
408 | offset = next * DB_RECORD_LEN; | |
409 | status = fseek(s->db, offset, SEEK_SET); | |
410 | ||
411 | if (status < 0) | |
412 | { | |
413 | free(outstr); | |
414 | return ASL_STATUS_READ_FAILED; | |
415 | } | |
416 | ||
417 | rcount = fread(tmp, DB_RECORD_LEN, 1, s->db); | |
418 | if (rcount != 1) | |
419 | { | |
420 | free(outstr); | |
421 | return ASL_STATUS_READ_FAILED; | |
422 | } | |
423 | ||
424 | next = header_get_next(tmp); | |
425 | ||
426 | x = DB_RECORD_LEN - DB_HLEN_STRCONT; | |
427 | if (x > remaining) x = remaining; | |
428 | ||
429 | memcpy(p, tmp + DB_HLEN_STRCONT, x); | |
430 | p += x; | |
431 | remaining -= x; | |
432 | } | |
433 | ||
434 | if ((next != 0) || (remaining != 0)) | |
435 | { | |
436 | free(outstr); | |
437 | return ASL_STATUS_READ_FAILED; | |
438 | } | |
439 | ||
440 | *out = outstr; | |
441 | return ASL_STATUS_OK; | |
442 | } | |
443 | ||
f3df4c03 | 444 | static ASL_STATUS |
81582353 A |
445 | string_fetch_sid(asl_legacy1_t *s, uint64_t sid, char **out) |
446 | { | |
447 | uint32_t i, len, ref; | |
448 | uint64_t nsid; | |
449 | uint8_t inls; | |
450 | char *p; | |
451 | ||
452 | if (s == NULL) return ASL_STATUS_INVALID_STORE; | |
453 | if (out == NULL) return ASL_STATUS_INVALID_ARG; | |
454 | ||
455 | *out = NULL; | |
456 | if (sid == ASL_REF_NULL) return ASL_STATUS_OK; | |
457 | ||
458 | ref = 0; | |
459 | ||
460 | inls = 0; | |
461 | nsid = _asl_htonq(sid); | |
462 | memcpy(&inls, &nsid, 1); | |
463 | if (inls & 0x80) | |
464 | { | |
465 | /* inline string */ | |
466 | inls &= 0x0f; | |
467 | len = inls; | |
468 | *out = calloc(1, len); | |
469 | if (*out == NULL) return ASL_STATUS_NO_MEMORY; | |
470 | p = 1 + (char *)&nsid; | |
471 | memcpy(*out, p, len); | |
472 | return ASL_STATUS_OK; | |
473 | } | |
474 | ||
475 | /* Find the string in the database */ | |
476 | i = slotlist_find(s, sid, 0); | |
477 | if (i == ASL_INDEX_NULL) return ASL_STATUS_NOT_FOUND; | |
478 | ||
479 | return string_fetch_slot(s, s->slotlist[i].slot, out); | |
480 | } | |
481 | ||
482 | static uint32_t | |
f3df4c03 | 483 | asl_legacy1_fetch_helper_32(asl_legacy1_t *s, char **p, asl_msg_t *m, const char *key, int ignore, uint32_t ignoreval) |
81582353 A |
484 | { |
485 | uint32_t out, doit; | |
486 | char str[256]; | |
487 | ||
488 | out = _asl_get_32(*p); | |
489 | *p += sizeof(uint32_t); | |
490 | ||
491 | if ((m == NULL) || (key == NULL)) return out; | |
492 | ||
493 | doit = 1; | |
494 | if ((ignore != 0) && (out == ignoreval)) doit = 0; | |
495 | if (doit != 0) | |
496 | { | |
497 | snprintf(str, sizeof(str), "%u", out); | |
f3df4c03 | 498 | asl_msg_set_key_val(m, key, str); |
81582353 A |
499 | } |
500 | ||
501 | return out; | |
502 | } | |
503 | ||
504 | static uint64_t | |
f3df4c03 | 505 | asl_legacy1_fetch_helper_64(asl_legacy1_t *s, char **p, asl_msg_t *m, const char *key) |
81582353 A |
506 | { |
507 | uint64_t out; | |
508 | char str[256]; | |
509 | ||
510 | out = _asl_get_64(*p); | |
511 | *p += sizeof(uint64_t); | |
512 | ||
513 | if ((m == NULL) || (key == NULL)) return out; | |
514 | ||
515 | snprintf(str, sizeof(str), "%llu", out); | |
f3df4c03 | 516 | asl_msg_set_key_val(m, key, str); |
81582353 A |
517 | |
518 | return out; | |
519 | } | |
520 | ||
521 | static uint64_t | |
f3df4c03 | 522 | asl_legacy1_fetch_helper_str(asl_legacy1_t *s, char **p, asl_msg_t *m, const char *key, uint32_t *err) |
81582353 A |
523 | { |
524 | uint64_t out; | |
525 | char *val; | |
526 | uint32_t status; | |
527 | ||
528 | out = _asl_get_64(*p); | |
529 | *p += sizeof(uint64_t); | |
530 | ||
531 | val = NULL; | |
532 | status = ASL_STATUS_OK; | |
533 | if (out != 0) status = string_fetch_sid(s, out, &val); | |
534 | ||
535 | if (err != NULL) *err = status; | |
536 | if ((status == ASL_STATUS_OK) && (val != NULL)) | |
537 | { | |
f3df4c03 | 538 | asl_msg_set_key_val(m, key, val); |
81582353 A |
539 | free(val); |
540 | } | |
541 | ||
542 | return out; | |
543 | } | |
544 | ||
f3df4c03 A |
545 | static ASL_STATUS |
546 | msg_fetch(asl_legacy1_t *s, uint32_t slot, asl_msg_t **out) | |
81582353 A |
547 | { |
548 | off_t offset; | |
549 | uint32_t status, i, n, kvcount, next; | |
550 | uint16_t flags; | |
551 | uint64_t sid; | |
552 | size_t rcount; | |
f3df4c03 | 553 | asl_msg_t *msg; |
81582353 A |
554 | int fstatus; |
555 | char *p, tmp[DB_RECORD_LEN], *key, *val; | |
556 | ||
557 | if (s == NULL) return ASL_STATUS_INVALID_STORE; | |
558 | if (out == NULL) return ASL_STATUS_INVALID_ARG; | |
559 | ||
560 | *out = NULL; | |
561 | ||
562 | offset = slot * DB_RECORD_LEN; | |
563 | fstatus = fseek(s->db, offset, SEEK_SET); | |
564 | ||
565 | if (fstatus < 0) return ASL_STATUS_READ_FAILED; | |
566 | ||
567 | rcount = fread(tmp, DB_RECORD_LEN, 1, s->db); | |
568 | if (rcount != 1) return ASL_STATUS_READ_FAILED; | |
569 | ||
570 | flags = _asl_get_16(tmp + MSG_OFF_KEY_FLAGS); | |
571 | ||
f3df4c03 | 572 | msg = asl_msg_new(ASL_TYPE_MSG); |
81582353 A |
573 | if (msg == NULL) return ASL_STATUS_NO_MEMORY; |
574 | ||
575 | p = tmp + 5; | |
576 | ||
577 | asl_legacy1_fetch_helper_64(s, &p, msg, ASL_KEY_MSG_ID); | |
578 | asl_legacy1_fetch_helper_32(s, &p, msg, ASL_KEY_READ_UID, 1, (uint32_t)-1); | |
579 | asl_legacy1_fetch_helper_32(s, &p, msg, ASL_KEY_READ_GID, 1, (uint32_t)-1); | |
580 | asl_legacy1_fetch_helper_64(s, &p, msg, ASL_KEY_TIME); | |
581 | asl_legacy1_fetch_helper_str(s, &p, msg, ASL_KEY_HOST, &status); | |
582 | asl_legacy1_fetch_helper_str(s, &p, msg, ASL_KEY_SENDER, &status); | |
583 | asl_legacy1_fetch_helper_str(s, &p, msg, ASL_KEY_FACILITY, &status); | |
584 | asl_legacy1_fetch_helper_32(s, &p, msg, ASL_KEY_LEVEL, 0, 0); | |
585 | asl_legacy1_fetch_helper_32(s, &p, msg, ASL_KEY_PID, 0, 0); | |
586 | asl_legacy1_fetch_helper_32(s, &p, msg, ASL_KEY_UID, 0, 0); | |
587 | asl_legacy1_fetch_helper_32(s, &p, msg, ASL_KEY_GID, 0, 0); | |
588 | asl_legacy1_fetch_helper_str(s, &p, msg, ASL_KEY_MSG, &status); | |
589 | ||
590 | next = header_get_next(tmp); | |
591 | ||
592 | kvcount = 0; | |
593 | n = 0; | |
594 | ||
595 | while (next != 0) | |
596 | { | |
597 | offset = next * DB_RECORD_LEN; | |
598 | fstatus = fseek(s->db, offset, SEEK_SET); | |
599 | if (fstatus < 0) | |
600 | { | |
f3df4c03 | 601 | asl_msg_release(msg); |
81582353 A |
602 | return ASL_STATUS_READ_FAILED; |
603 | } | |
604 | ||
605 | rcount = fread(tmp, DB_RECORD_LEN, 1, s->db); | |
606 | if (rcount != 1) | |
607 | { | |
f3df4c03 | 608 | asl_msg_release(msg); |
81582353 A |
609 | return ASL_STATUS_READ_FAILED; |
610 | } | |
611 | ||
612 | if (kvcount == 0) kvcount = _asl_get_32(tmp + 5); | |
613 | ||
614 | p = tmp + 9; | |
615 | ||
616 | for (i = 0; (i < 4) && (n < kvcount); i++) | |
617 | { | |
618 | key = NULL; | |
619 | sid = _asl_get_64(p); | |
620 | p += 8; | |
621 | status = string_fetch_sid(s, sid, &key); | |
622 | ||
623 | val = NULL; | |
624 | sid = _asl_get_64(p); | |
625 | p += 8; | |
626 | if (status == ASL_STATUS_OK) status = string_fetch_sid(s, sid, &val); | |
627 | ||
f3df4c03 | 628 | if ((status == ASL_STATUS_OK) && (key != NULL)) asl_msg_set_key_val(msg, key, val); |
81582353 A |
629 | if (key != NULL) free(key); |
630 | if (val != NULL) free(val); | |
631 | ||
632 | n++; | |
633 | } | |
634 | ||
635 | next = header_get_next(tmp); | |
636 | } | |
637 | ||
638 | *out = msg; | |
639 | return ASL_STATUS_OK; | |
640 | } | |
641 | ||
642 | uint32_t | |
f3df4c03 | 643 | asl_legacy1_fetch(asl_legacy1_t *s, uint64_t msgid, asl_msg_t **out) |
81582353 A |
644 | { |
645 | uint32_t i, status; | |
646 | ||
647 | if (s == NULL) return ASL_STATUS_INVALID_STORE; | |
648 | if (msgid == ASL_REF_NULL) return ASL_STATUS_INVALID_ARG; | |
649 | if (out == NULL) return ASL_STATUS_INVALID_ARG; | |
650 | ||
651 | i = slotlist_find(s, msgid, 0); | |
652 | if (i == ASL_INDEX_NULL) return ASL_STATUS_INVALID_ID; | |
653 | ||
654 | /* read the message */ | |
655 | status = msg_fetch(s, s->slotlist[i].slot, out); | |
656 | if (status != ASL_STATUS_OK) return status; | |
657 | if (*out == NULL) return ASL_STATUS_FAILED; | |
658 | ||
659 | return status; | |
660 | } | |
661 | ||
662 | static uint32_t | |
663 | next_search_slot(asl_legacy1_t *s, uint32_t last_si, int32_t direction) | |
664 | { | |
665 | uint32_t i; | |
666 | ||
667 | if (direction >= 0) | |
668 | { | |
669 | for (i = last_si + 1; i < s->slotlist_count; i++) | |
670 | { | |
671 | if (s->slotlist[i].type == DB_TYPE_MESSAGE) return i; | |
672 | } | |
673 | ||
674 | return ASL_INDEX_NULL; | |
675 | } | |
676 | ||
677 | if (last_si == 0) return ASL_INDEX_NULL; | |
678 | if (last_si > s->slotlist_count) return ASL_INDEX_NULL; | |
679 | ||
680 | for (i = last_si - 1; i > 0; i--) | |
681 | { | |
682 | if (s->slotlist[i].type == DB_TYPE_MESSAGE) return i; | |
683 | } | |
684 | ||
685 | if (s->slotlist[0].type == DB_TYPE_MESSAGE) return 0; | |
686 | ||
687 | return ASL_INDEX_NULL; | |
688 | } | |
689 | ||
81582353 A |
690 | /* |
691 | * Input to asl_legacy1_match is a list of queries. | |
692 | * A record in the store matches if it matches any query (i.e. query list is "OR"ed) | |
693 | * | |
694 | * If counting up (direction is positive) find first record with ID > start_id. | |
695 | * Else if counting down (direction is negative) find first record with ID < start_id. | |
696 | * | |
697 | * Set match flag on. | |
698 | * If any query is NULL, set match flog off (skips matching below). | |
699 | * Else if all queries only check "standard" keys, set std flag to on. | |
700 | * | |
701 | * If all queries are marked as "never matches", return NULL. | |
702 | * | |
703 | * match loop: | |
704 | * fetch record (with std flag) | |
705 | * if match flag is off, decode record and add it to result. | |
706 | * else for each query: | |
707 | * if query is NULL (shouldn't happen) decode record and add it to result. Return to match loop. | |
708 | * else if query never matches, ignore it. | |
709 | * else decode record and use asl_cmp. If it succeeds, add record to result. Return to match loop. | |
710 | * | |
711 | * return results. | |
712 | */ | |
f3df4c03 | 713 | static ASL_STATUS |
81582353 A |
714 | match_worker(asl_legacy1_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t **idlist, uint32_t *idcount, uint64_t start_id, int32_t count, int32_t direction) |
715 | { | |
716 | uint32_t mx, si, slot, i, qcount, match, didmatch, status; | |
717 | uint64_t xid; | |
f3df4c03 | 718 | asl_msg_t *msg; |
81582353 A |
719 | |
720 | if (s == NULL) return ASL_STATUS_INVALID_STORE; | |
721 | if ((res == NULL) && (idlist == NULL)) return ASL_STATUS_INVALID_ARG; | |
722 | if (last_id == NULL) return ASL_STATUS_INVALID_ARG; | |
723 | if (idcount == NULL) return ASL_STATUS_INVALID_ARG; | |
724 | ||
725 | if (res != NULL) *res = NULL; | |
726 | if (idlist != NULL) *idlist = NULL; | |
727 | ||
728 | mx = 0; | |
729 | ||
730 | if (direction < 0) direction = -1; | |
731 | else direction = 1; | |
732 | ||
733 | si = ASL_INDEX_NULL; | |
734 | if ((direction == -1) && (start_id == ASL_REF_NULL)) si = s->slotlist_count; | |
735 | else si = slotlist_find(s, start_id, direction); | |
736 | ||
737 | si = next_search_slot(s, si, direction); | |
738 | if (si == ASL_INDEX_NULL) return ASL_STATUS_OK; | |
739 | if (si >= s->slotlist_count) return ASL_STATUS_FAILED; | |
740 | ||
741 | slot = s->slotlist[si].slot; | |
742 | ||
743 | match = 1; | |
744 | qcount = 0; | |
745 | ||
746 | if (query == NULL) match = 0; | |
747 | else if (query->count == 0) match = 0; | |
748 | else qcount = query->count; | |
749 | ||
750 | /* | |
751 | * initialize result list if we've been asked to return messages | |
752 | */ | |
753 | if (res != NULL) | |
754 | { | |
f3df4c03 | 755 | *res = asl_msg_list_new(); |
81582353 A |
756 | if (*res == NULL) return ASL_STATUS_NO_MEMORY; |
757 | } | |
758 | ||
759 | status = ASL_STATUS_OK; | |
760 | ||
761 | /* | |
762 | * loop through records | |
763 | */ | |
764 | *idcount = 0; | |
765 | while ((count == 0) || (*idcount < count)) | |
766 | { | |
767 | if (si == ASL_INDEX_NULL) break; | |
768 | if (si >= s->slotlist_count) break; | |
769 | ||
770 | slot = s->slotlist[si].slot; | |
771 | xid = s->slotlist[si].xid; | |
772 | ||
773 | *last_id = xid; | |
774 | ||
775 | status = msg_fetch(s, slot, &msg); | |
776 | ||
777 | didmatch = 0; | |
778 | if (match == 0) | |
779 | { | |
780 | didmatch = 1; | |
781 | } | |
782 | else | |
783 | { | |
784 | for (i = 0; i < qcount; i++) | |
785 | { | |
f3df4c03 | 786 | didmatch = asl_msg_cmp(query->msg[i], msg); |
81582353 A |
787 | if (didmatch == 1) break; |
788 | } | |
789 | } | |
790 | ||
f3df4c03 A |
791 | if (didmatch == 1) asl_msg_list_append(*res, msg); |
792 | asl_msg_release(msg); | |
81582353 A |
793 | |
794 | si = next_search_slot(s, si, direction); | |
795 | } | |
796 | ||
797 | return status; | |
798 | } | |
799 | ||
f3df4c03 | 800 | ASL_STATUS |
81582353 A |
801 | asl_legacy1_match(asl_legacy1_t *s, asl_msg_list_t *query, asl_msg_list_t **res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction) |
802 | { | |
803 | uint32_t idcount; | |
804 | ||
805 | idcount = 0; | |
806 | return match_worker(s, query, res, last_id, NULL, &idcount, start_id, count, direction); | |
807 | } |