]> git.saurik.com Git - apple/libc.git/blame - gen/asl_file.c
Libc-763.13.tar.gz
[apple/libc.git] / gen / asl_file.c
CommitLineData
b5d655f7 1/*
1f2f436a 2 * Copyright (c) 2007-2010 Apple Inc. All rights reserved.
b5d655f7
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
1f2f436a
A
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.
b5d655f7
A
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,
1f2f436a
A
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.
b5d655f7
A
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24#include <asl_core.h>
25#include <asl_file.h>
26#include <fcntl.h>
27#include <stdlib.h>
28#include <stddef.h>
29#include <stdio.h>
30#include <unistd.h>
31#include <sys/errno.h>
32#include <string.h>
33#include <sys/stat.h>
1f2f436a
A
34#include <sys/types.h>
35#include <sys/acl.h>
36#include <membership.h>
b5d655f7
A
37#include <time.h>
38#include <sys/time.h>
39#include <asl_private.h>
40#include <asl_legacy1.h>
41
42extern time_t asl_parse_time(const char *str);
1f2f436a 43extern int asl_msg_cmp(aslmsg a, aslmsg b);
b5d655f7
A
44
45#define forever for(;;)
46#define MILLION 1000000
47
48/*
49 * MSG and STR records have (at least) a type (uint16_t) and a length (uint32_t)
50 * type and level are both 16 bit fields so that alignment isn't a pain.
51 */
52#define RECORD_COMMON_LEN 6
53#define RECORD_TYPE_LEN 2
34e8f829 54#define BUFFER_OFFSET_KVCOUNT 56
b5d655f7
A
55
56#define SCRATCH_BUFFER_SIZE (MSG_RECORD_FIXED_LENGTH + (20 * sizeof(uint64_t)))
57
58typedef struct
59{
60 uint64_t next;
61 uint64_t mid;
62 uint64_t time;
63 uint32_t nano;
64 uint16_t level;
65 uint16_t flags;
66 uint32_t pid;
67 uint32_t uid;
68 uint32_t gid;
69 uint32_t ruid;
70 uint32_t rgid;
71 uint32_t refpid;
72 uint32_t kvcount;
73 uint64_t host;
74 uint64_t sender;
75 uint64_t facility;
76 uint64_t message;
77 uint64_t refproc;
78 uint64_t session;
79 uint64_t prev;
80} file_record_t;
81
82typedef struct
83{
84 asl_file_list_t *list;
85 int dir;
86} asl_file_match_token_t;
87
88static uint16_t
89_asl_get_16(char *h)
90{
91 uint16_t x;
92
93 memcpy(&x, h, 2);
94 return ntohs(x);
95}
96
97static void
98_asl_put_16(uint16_t i, char *h)
99{
100 uint16_t x;
101
102 x = htons(i);
103 memcpy(h, &x, 2);
104}
105
106static uint32_t
107_asl_get_32(char *h)
108{
109 uint32_t x;
110
111 memcpy(&x, h, 4);
112 return ntohl(x);
113}
114
115static void
116_asl_put_32(uint32_t i, char *h)
117{
118 uint32_t x;
119
120 x = htonl(i);
121 memcpy(h, &x, 4);
122}
123
124static uint64_t
125_asl_get_64(char *h)
126{
127 uint64_t x;
128
129 memcpy(&x, h, 8);
130 return asl_core_ntohq(x);
131}
132
133static void
134_asl_put_64(uint64_t i, char *h)
135{
136 uint64_t x;
137
138 x = asl_core_htonq(i);
139 memcpy(h, &x, 8);
140}
141
142static uint32_t
143asl_file_read_uint32(asl_file_t *s, off_t off, uint32_t *out)
144{
145 uint32_t status, val;
146
147 if (s == NULL) return ASL_STATUS_INVALID_STORE;
148 if (s->store == NULL) return ASL_STATUS_INVALID_STORE;
34e8f829 149 if ((off + sizeof(uint32_t)) > s->file_size) return ASL_STATUS_READ_FAILED;
b5d655f7
A
150
151 status = fseeko(s->store, off, SEEK_SET);
152 if (status != 0) return ASL_STATUS_READ_FAILED;
153
154 val = 0;
155
156 status = fread(&val, sizeof(uint32_t), 1, s->store);
157 if (status != 1) return ASL_STATUS_READ_FAILED;
158
159 if (out != NULL) *out = ntohl(val);
160 return ASL_STATUS_OK;
161}
162
163static uint32_t
164asl_file_read_uint64(asl_file_t *s, off_t off, uint64_t *out)
165{
166 uint32_t status;
167 uint64_t val;
168
169 if (s == NULL) return ASL_STATUS_INVALID_STORE;
170 if (s->store == NULL) return ASL_STATUS_INVALID_STORE;
34e8f829 171 if ((off + sizeof(uint64_t)) > s->file_size) return ASL_STATUS_READ_FAILED;
b5d655f7
A
172
173 status = fseeko(s->store, off, SEEK_SET);
174 if (status != 0) return ASL_STATUS_READ_FAILED;
175
176 val = 0;
177
178 status = fread(&val, sizeof(uint64_t), 1, s->store);
179 if (status != 1) return ASL_STATUS_READ_FAILED;
180
181 if (out != NULL) *out = asl_core_ntohq(val);
182 return ASL_STATUS_OK;
183}
184
185uint32_t
186asl_file_close(asl_file_t *s)
187{
188 file_string_t *x;
189
190 if (s == NULL) return ASL_STATUS_OK;
191
192 if (s->version == 1)
193 {
194 return asl_legacy1_close((asl_legacy1_t *)s->legacy);
195 }
196
197 while (s->string_list != NULL)
198 {
199 x = s->string_list->next;
200 free(s->string_list);
201 s->string_list = x;
202 }
203
204 if (s->store != NULL) fclose(s->store);
34e8f829 205 if (s->scratch != NULL) free(s->scratch);
b5d655f7
A
206
207 memset(s, 0, sizeof(asl_file_t));
208 free(s);
209
210 return ASL_STATUS_OK;
211}
212
1f2f436a
A
213__private_extern__ uint32_t
214asl_file_open_write_fd(int fd, asl_file_t **s)
b5d655f7
A
215{
216 time_t now;
1f2f436a 217 int status;
b5d655f7
A
218 char buf[DB_HEADER_LEN];
219 asl_file_t *out;
b5d655f7 220
1f2f436a
A
221 if (fd < 0) return ASL_STATUS_FAILED;
222 if (s == NULL) return ASL_STATUS_FAILED;
b5d655f7 223
1f2f436a
A
224 out = (asl_file_t *)calloc(1, sizeof(asl_file_t));
225 if (out == NULL) return ASL_STATUS_NO_MEMORY;
226
227 out->store = fdopen(fd, "w+");
228 if (out->store == NULL)
b5d655f7 229 {
1f2f436a
A
230 free(out);
231 return ASL_STATUS_FAILED;
232 }
b5d655f7 233
1f2f436a
A
234 memset(buf, 0, sizeof(buf));
235 memcpy(buf, ASL_DB_COOKIE, ASL_DB_COOKIE_LEN);
b5d655f7 236
1f2f436a 237 _asl_put_32(DB_VERSION, buf + DB_HEADER_VERS_OFFSET);
b5d655f7 238
1f2f436a
A
239 now = time(NULL);
240 out->dob = now;
241 _asl_put_64(out->dob, buf + DB_HEADER_TIME_OFFSET);
34e8f829 242
1f2f436a 243 _asl_put_32(CACHE_SIZE, buf + DB_HEADER_CSIZE_OFFSET);
b5d655f7 244
1f2f436a
A
245 status = fwrite(buf, sizeof(buf), 1, out->store);
246 if (status != 1)
247 {
248 fclose(out->store);
249 free(out);
250 return ASL_STATUS_FAILED;
251 }
34e8f829 252
1f2f436a
A
253 /* flush data */
254 fflush(out->store);
b5d655f7 255
1f2f436a 256 out->file_size = sizeof(buf);
b5d655f7 257
1f2f436a
A
258 /* scratch buffer for file writes (we test for NULL before using it) */
259 out->scratch = malloc(SCRATCH_BUFFER_SIZE);
b5d655f7 260
1f2f436a 261 *s = out;
b5d655f7 262
1f2f436a
A
263 return ASL_STATUS_OK;
264}
b5d655f7 265
1f2f436a
A
266__private_extern__ int
267asl_file_create(const char *path, uid_t uid, gid_t gid, mode_t mode)
268{
269 acl_t acl;
270 uuid_t uuid;
271 acl_entry_t entry;
272 acl_permset_t perms;
273 int status;
274 int fd = -1;
b5d655f7 275
1f2f436a 276 acl = acl_init(1);
b5d655f7 277
1f2f436a
A
278 if (gid != 0)
279 {
280 status = mbr_gid_to_uuid(gid, uuid);
281 if (status != 0) goto asl_file_create_return;
282
283 status = acl_create_entry_np(&acl, &entry, ACL_FIRST_ENTRY);
284 if (status != 0) goto asl_file_create_return;
285
286 status = acl_set_tag_type(entry, ACL_EXTENDED_ALLOW);
287 if (status != 0) goto asl_file_create_return;
288
289 status = acl_set_qualifier(entry, &uuid);
290 if (status != 0) goto asl_file_create_return;
291
292 status = acl_get_permset(entry, &perms);
293 if (status != 0) goto asl_file_create_return;
294
295 status = acl_add_perm(perms, ACL_READ_DATA);
296 if (status != 0) goto asl_file_create_return;
297 }
298
299 if (uid != 0)
300 {
301 status = mbr_uid_to_uuid(uid, uuid);
302 if (status != 0) goto asl_file_create_return;
303
304 status = acl_create_entry_np(&acl, &entry, ACL_FIRST_ENTRY);
305 if (status != 0) goto asl_file_create_return;
306
307 status = acl_set_tag_type(entry, ACL_EXTENDED_ALLOW);
308 if (status != 0) goto asl_file_create_return;
309
310 status = acl_set_qualifier(entry, &uuid);
311 if (status != 0) goto asl_file_create_return;
312
313 status = acl_get_permset(entry, &perms);
314 if (status != 0) goto asl_file_create_return;
315
316 status = acl_add_perm(perms, ACL_READ_DATA);
317 if (status != 0) goto asl_file_create_return;
318 }
b5d655f7
A
319
320 fd = open(path, O_RDWR | O_CREAT | O_EXCL, mode);
1f2f436a 321 if (fd < 0) goto asl_file_create_return;
b5d655f7 322
1f2f436a 323 status = acl_set_fd(fd, acl);
b5d655f7
A
324 if (status != 0)
325 {
326 close(fd);
1f2f436a 327 fd = -1;
b5d655f7 328 unlink(path);
b5d655f7
A
329 }
330
1f2f436a
A
331asl_file_create_return:
332
333 acl_free(acl);
334 return fd;
335}
b5d655f7 336
1f2f436a
A
337uint32_t
338asl_file_open_write(const char *path, mode_t mode, uid_t uid, gid_t gid, asl_file_t **s)
339{
340 int i, status, fd;
341 struct stat sb;
342 char buf[DB_HEADER_LEN];
343 asl_file_t *out;
344 uint32_t aslstatus, vers, last_len;
345 off_t off;
346
347 memset(&sb, 0, sizeof(struct stat));
348
349 status = stat(path, &sb);
350 if (status == 0)
b5d655f7 351 {
1f2f436a
A
352 /* must be a plain file */
353 if (!S_ISREG(sb.st_mode)) return ASL_STATUS_INVALID_STORE;
b5d655f7 354
1f2f436a
A
355 if (sb.st_size == 0)
356 {
357 fd = open(path, O_RDWR | O_EXCL, mode);
358 if (fd < 0) return ASL_STATUS_FAILED;
b5d655f7 359
1f2f436a
A
360 return asl_file_open_write_fd(fd, s);
361 }
362 else
363 {
364 /* XXX Check that mode, uid, and gid are correct */
365 out = (asl_file_t *)calloc(1, sizeof(asl_file_t));
366 if (out == NULL) return ASL_STATUS_NO_MEMORY;
b5d655f7 367
1f2f436a
A
368 out->store = fopen(path, "r+");
369 if (out->store == NULL)
370 {
371 free(out);
372 return ASL_STATUS_FAILED;
373 }
b5d655f7 374
1f2f436a
A
375 i = fread(buf, DB_HEADER_LEN, 1, out->store);
376 if (i < 1)
377 {
378 asl_file_close(out);
379 return ASL_STATUS_READ_FAILED;
380 }
b5d655f7 381
1f2f436a
A
382 /* check cookie */
383 if (strncmp(buf, ASL_DB_COOKIE, ASL_DB_COOKIE_LEN))
384 {
385 asl_file_close(out);
386 return ASL_STATUS_INVALID_STORE;
387 }
388
389 /* check version */
390 vers = _asl_get_32(buf + DB_HEADER_VERS_OFFSET);
391 if (vers != DB_VERSION)
392 {
393 asl_file_close(out);
394 return ASL_STATUS_INVALID_STORE;
395 }
396
397 out->dob = _asl_get_64(buf + DB_HEADER_TIME_OFFSET);
398 out->first = _asl_get_64(buf + DB_HEADER_FIRST_OFFSET);
399 out->last = _asl_get_64(buf + DB_HEADER_LAST_OFFSET);
400 out->file_size = (size_t)sb.st_size;
401
402 /*
403 * Detect bogus last pointer and check for odd-sized files.
404 * Setting out->last to zero forces asl_file_read_set_position to
405 * follow the linked list of records in the file to the last record.
406 * It's slower, but it's better at preventing crashes in corrupt files.
407 */
408
409 /* records are at least MSG_RECORD_FIXED_LENGTH bytes */
410 if ((out->last + MSG_RECORD_FIXED_LENGTH) > out->file_size)
411 {
412 out->last = 0;
413 }
414 else
415 {
416 /* read last record length and make sure the file is at least that large */
417 off = out->last + RECORD_TYPE_LEN;
418 status = asl_file_read_uint32(out, off, &last_len);
419 if (status != ASL_STATUS_OK)
420 {
421 asl_file_close(out);
422 return status;
423 }
424
425 if ((out->last + last_len) > out->file_size) out->last = 0;
426 }
427
428 aslstatus = asl_file_read_set_position(out, ASL_FILE_POSITION_LAST);
429 if (aslstatus != ASL_STATUS_OK)
430 {
431 asl_file_close(out);
432 return aslstatus;
433 }
434
435 out->prev = out->cursor;
436 status = fseeko(out->store, 0, SEEK_END);
437 if (status != 0)
438 {
439 asl_file_close(out);
440 return ASL_STATUS_READ_FAILED;
441 }
442
443 out->file_size = (size_t)ftello(out->store);
444
445 /* scratch buffer for file writes (we test for NULL before using it) */
446 out->scratch = malloc(SCRATCH_BUFFER_SIZE);
447
448 *s = out;
449
450 return ASL_STATUS_OK;
451 }
452 }
453 else if (errno != ENOENT)
b5d655f7 454 {
1f2f436a 455 /* unexpected status */
b5d655f7
A
456 return ASL_STATUS_FAILED;
457 }
458
1f2f436a
A
459 /* the file does not exist */
460 fd = asl_file_create(path, uid, gid, mode);
461 if (fd < 0) return ASL_STATUS_FAILED;
b5d655f7 462
1f2f436a
A
463 aslstatus = asl_file_open_write_fd(fd, s);
464 if (aslstatus != ASL_STATUS_OK) unlink(path);
b5d655f7 465
1f2f436a 466 return aslstatus;
b5d655f7
A
467}
468
469uint32_t
470asl_file_compact(asl_file_t *s, const char *path, mode_t mode, uid_t uid, gid_t gid)
471{
472 asl_file_t *new;
473 struct stat sb;
474 aslmsg m;
475 uint64_t xid;
476 uint32_t status;
477
478 if (s == NULL) return ASL_STATUS_INVALID_STORE;
479 if (path == NULL) return ASL_STATUS_INVALID_ARG;
480
481 if (s->version == 1) return ASL_STATUS_FAILED;
482
483 memset(&sb, 0, sizeof(struct stat));
484
485 if (stat(path, &sb) == 0) return ASL_STATUS_FAILED;
486 if (errno != ENOENT) return ASL_STATUS_FAILED;
487
488 status = asl_file_read_set_position(s, ASL_FILE_POSITION_FIRST);
489 if (status != ASL_STATUS_OK) return status;
490
491 new = NULL;
492 status = asl_file_open_write(path, mode, uid, gid, &new);
493 if (status != ASL_STATUS_OK) return status;
494 new->flags = ASL_FILE_FLAG_UNLIMITED_CACHE | ASL_FILE_FLAG_PRESERVE_MSG_ID;
495
496 while ((status == ASL_STATUS_OK) && (s->cursor != 0))
497 {
498 m = NULL;
499 status = asl_file_fetch_next(s, &m);
500 if (status != ASL_STATUS_OK) break;
501
502 xid = 0;
503 status = asl_file_save(new, m, &xid);
504 asl_free(m);
505 }
506
507 asl_file_close(new);
508 return status;
509}
510
511static uint32_t
512asl_file_string_encode(asl_file_t *s, const char *str, uint64_t *out)
513{
514 uint32_t i, hash, len, x32;
515 file_string_t *sp, *sx, *sl;
516 uint64_t x64;
517 uint8_t inls;
518 uint16_t type;
519 off_t off;
520 char *p;
521
522 if (s == NULL) return ASL_STATUS_INVALID_STORE;
523 if (str == NULL) return ASL_STATUS_INVALID_ARG;
524
525 len = strlen(str);
526
527 /* inline strings */
528 if (len < 8)
529 {
530 /* inline string */
531 inls = len;
532 inls |= 0x80;
533
534 x64 = 0;
535 p = (char *)&x64;
536 memcpy(p, &inls, 1);
537 memcpy(p + 1, str, len);
538 *out = asl_core_ntohq(x64);
539 return ASL_STATUS_OK;
540 }
541
542 /* check the cache */
543 hash = asl_core_string_hash(str, len);
544
545 sp = NULL;
546 for (sx = s->string_list; sx != NULL; sx = sx->next)
547 {
548 if ((hash == sx->hash) && (!strcmp(str, sx->str)))
549 {
550 /* Move this string to the head of the list */
551 if (sp != NULL)
552 {
553 sl = s->string_list;
554 sp->next = sx->next;
555 sx->next = sl;
556 s->string_list = sx;
557 }
558
559 *out = sx->where;
560 return ASL_STATUS_OK;
561 }
562
563 sp = sx;
564 }
565
566 off = ftello(s->store);
567
568 /* Type */
569 type = htons(ASL_FILE_TYPE_STR);
570 i = fwrite(&type, sizeof(uint16_t), 1, s->store);
571 if (i != 1) return ASL_STATUS_WRITE_FAILED;
b5d655f7
A
572
573 /* Length (includes trailing nul) */
574 x32 = htonl(len + 1);
575 i = fwrite(&x32, sizeof(uint32_t), 1, s->store);
576 if (i != 1) return ASL_STATUS_WRITE_FAILED;
b5d655f7
A
577
578 /* String data (nul terminated) */
579 i = fwrite(str, len + 1, 1, s->store);
580 if (i != 1) return ASL_STATUS_WRITE_FAILED;
b5d655f7 581
1f2f436a
A
582 /* flush data */
583 fflush(s->store);
584
b5d655f7
A
585 /* create file_string_t and insert into the cache */
586 sx = (file_string_t *)calloc(1, offsetof(file_string_t, str) + len + 1);
587 if (sx == NULL) return ASL_STATUS_NO_MEMORY;
588
589 sx->where = off;
590 sx->hash = hash;
591 sx->next = s->string_list;
592 memcpy(sx->str, str, len);
593
594 s->string_list = sx;
595
596 if (((s->flags & ASL_FILE_FLAG_UNLIMITED_CACHE) == 0) && (s->string_count == CACHE_SIZE))
597 {
598 /* drop last (lru) string from cache */
599 sp = s->string_list;
600 sx = sp->next;
601
602 /* NB CACHE_SIZE must be > 1 */
603 while (sx->next != NULL)
604 {
605 sp = sx;
606 sx = sx->next;
607 }
608
609 sp->next = NULL;
610 free(sx);
611 }
612 else
613 {
614 s->string_count++;
615 }
616
617 *out = off;
618 return ASL_STATUS_OK;
619}
620
621/*
622 * Encode an aslmsg as a record structure.
623 * Creates and caches strings.
624 */
625uint32_t
1f2f436a 626asl_file_save(asl_file_t *s, aslmsg in, uint64_t *mid)
b5d655f7
A
627{
628 char *buf, *p;
1f2f436a 629 uint32_t i, len, x, status;
b5d655f7
A
630 file_record_t r;
631 uint64_t k, v;
632 uint64_t *kvlist;
633 off_t off;
1f2f436a
A
634 asl_msg_t *msg;
635 const char *key, *val;
b5d655f7
A
636
637 if (s == NULL) return ASL_STATUS_INVALID_STORE;
1f2f436a 638 if (in == NULL) return ASL_STATUS_INVALID_MESSAGE;
b5d655f7
A
639
640 if (s->flags & ASL_FILE_FLAG_READ_ONLY) return ASL_STATUS_READ_ONLY;
641
1f2f436a
A
642 msg = (asl_msg_t *)in;
643
b5d655f7
A
644 memset(&r, 0, sizeof(file_record_t));
645
646 r.flags = 0;
647 r.level = ASL_LEVEL_DEBUG;
648 r.pid = -1;
649 r.uid = -2;
650 r.gid = -2;
651 r.ruid = -1;
652 r.rgid = -1;
653 r.time = 0;
654 r.nano = 0;
655 r.prev = s->prev;
656 kvlist = NULL;
657
1f2f436a
A
658 key = NULL;
659 val = NULL;
660
661 for (x = asl_msg_fetch(msg, 0, &key, &val, NULL); x != IndexNull; x = asl_msg_fetch(msg, x, &key, &val, NULL))
b5d655f7 662 {
1f2f436a 663 if (key == NULL)
b5d655f7
A
664 {
665 continue;
666 }
1f2f436a 667 else if (!strcmp(key, ASL_KEY_TIME))
b5d655f7 668 {
1f2f436a 669 if (val != NULL) r.time = asl_parse_time(val);
b5d655f7 670 }
1f2f436a 671 else if (!strcmp(key, ASL_KEY_TIME_NSEC))
b5d655f7 672 {
1f2f436a 673 if (val != NULL) r.nano = atoi(val);
b5d655f7 674 }
1f2f436a 675 else if (!strcmp(key, ASL_KEY_HOST))
b5d655f7 676 {
1f2f436a 677 if (val != NULL)
b5d655f7 678 {
1f2f436a 679 status = asl_file_string_encode(s, val, &(r.host));
b5d655f7
A
680 if (status != ASL_STATUS_OK)
681 {
682 if (kvlist != NULL) free(kvlist);
683 return status;
684 }
685 }
686 }
1f2f436a 687 else if (!strcmp(key, ASL_KEY_SENDER))
b5d655f7 688 {
1f2f436a 689 if (val != NULL)
b5d655f7 690 {
1f2f436a 691 status = asl_file_string_encode(s, val, &(r.sender));
b5d655f7
A
692 if (status != ASL_STATUS_OK)
693 {
694 if (kvlist != NULL) free(kvlist);
695 return status;
696 }
697 }
698 }
1f2f436a 699 else if (!strcmp(key, ASL_KEY_PID))
b5d655f7 700 {
1f2f436a 701 if (val != NULL) r.pid = atoi(val);
b5d655f7 702 }
1f2f436a 703 else if (!strcmp(key, ASL_KEY_REF_PID))
b5d655f7 704 {
1f2f436a 705 if (val != NULL) r.refpid = atoi(val);
b5d655f7 706 }
1f2f436a 707 else if (!strcmp(key, ASL_KEY_UID))
b5d655f7 708 {
1f2f436a 709 if (val != NULL) r.uid = atoi(val);
b5d655f7 710 }
1f2f436a 711 else if (!strcmp(key, ASL_KEY_GID))
b5d655f7 712 {
1f2f436a 713 if (val != NULL) r.gid = atoi(val);
b5d655f7 714 }
1f2f436a 715 else if (!strcmp(key, ASL_KEY_LEVEL))
b5d655f7 716 {
1f2f436a 717 if (val != NULL) r.level = atoi(val);
b5d655f7 718 }
1f2f436a 719 else if (!strcmp(key, ASL_KEY_MSG))
b5d655f7 720 {
1f2f436a 721 if (val != NULL)
b5d655f7 722 {
1f2f436a 723 status = asl_file_string_encode(s, val, &(r.message));
b5d655f7
A
724 if (status != ASL_STATUS_OK)
725 {
726 if (kvlist != NULL) free(kvlist);
727 return status;
728 }
729 }
730 }
1f2f436a 731 else if (!strcmp(key, ASL_KEY_FACILITY))
b5d655f7 732 {
1f2f436a 733 if (val != NULL)
b5d655f7 734 {
1f2f436a 735 status = asl_file_string_encode(s, val, &(r.facility));
b5d655f7
A
736 if (status != ASL_STATUS_OK)
737 {
738 if (kvlist != NULL) free(kvlist);
739 return status;
740 }
741 }
742 }
1f2f436a 743 else if (!strcmp(key, ASL_KEY_REF_PROC))
b5d655f7 744 {
1f2f436a 745 if (val != NULL)
b5d655f7 746 {
1f2f436a 747 status = asl_file_string_encode(s, val, &(r.refproc));
b5d655f7
A
748 if (status != ASL_STATUS_OK)
749 {
750 if (kvlist != NULL) free(kvlist);
751 return status;
752 }
753 }
754 }
1f2f436a 755 else if (!strcmp(key, ASL_KEY_SESSION))
b5d655f7 756 {
1f2f436a 757 if (val != NULL)
b5d655f7 758 {
1f2f436a 759 status = asl_file_string_encode(s, val, &(r.session));
b5d655f7
A
760 if (status != ASL_STATUS_OK)
761 {
762 if (kvlist != NULL) free(kvlist);
763 return status;
764 }
765 }
766 }
1f2f436a 767 else if (!strcmp(key, ASL_KEY_READ_UID))
b5d655f7 768 {
1f2f436a 769 if (((r.flags & ASL_MSG_FLAG_READ_UID_SET) == 0) && (val != NULL))
b5d655f7 770 {
1f2f436a 771 r.ruid = atoi(val);
b5d655f7
A
772 r.flags |= ASL_MSG_FLAG_READ_UID_SET;
773 }
774 }
1f2f436a 775 else if (!strcmp(key, ASL_KEY_READ_GID))
b5d655f7 776 {
1f2f436a 777 if (((r.flags & ASL_MSG_FLAG_READ_GID_SET) == 0) && (val != NULL))
b5d655f7 778 {
1f2f436a 779 r.rgid = atoi(val);
b5d655f7
A
780 r.flags |= ASL_MSG_FLAG_READ_GID_SET;
781 }
782 }
1f2f436a 783 else if (!strcmp(key, ASL_KEY_MSG_ID))
b5d655f7 784 {
1f2f436a 785 if (s->flags & ASL_FILE_FLAG_PRESERVE_MSG_ID) *mid = atoll(val);
b5d655f7 786 }
1f2f436a 787 else if (!strcmp(key, ASL_KEY_OPTION))
34e8f829
A
788 {
789 /* ignore - we don't save ASLOption */
790 }
b5d655f7
A
791 else
792 {
1f2f436a 793 status = asl_file_string_encode(s, key, &k);
b5d655f7
A
794 if (status != ASL_STATUS_OK)
795 {
796 if (kvlist != NULL) free(kvlist);
797 return status;
798 }
799
800 v = 0;
1f2f436a 801 if (val != NULL)
b5d655f7 802 {
1f2f436a 803 status = asl_file_string_encode(s, val, &v);
b5d655f7
A
804 if (status != ASL_STATUS_OK)
805 {
806 if (kvlist != NULL) free(kvlist);
807 return status;
808 }
809 }
810
811 if (r.kvcount == 0)
812 {
813 kvlist = (uint64_t *)calloc(2, sizeof(uint64_t));
814 }
815 else
816 {
817 kvlist = (uint64_t *)reallocf(kvlist, (r.kvcount + 2) * sizeof(uint64_t));
818 }
819
820 if (kvlist == NULL)
821 {
822 return ASL_STATUS_NO_MEMORY;
823 }
824
825 kvlist[r.kvcount++] = k;
826 kvlist[r.kvcount++] = v;
827 }
828 }
829
830 len = MSG_RECORD_FIXED_LENGTH + (r.kvcount * sizeof(uint64_t));
831 buf = NULL;
832
833 /* use the scratch buffer if it exists and is large enough */
834 if ((s->scratch != NULL) && (len <= SCRATCH_BUFFER_SIZE))
835 {
836 memset(s->scratch, 0, SCRATCH_BUFFER_SIZE);
837 buf = s->scratch;
838 }
839 else
840 {
841 buf = calloc(1, len);
842 }
843
844 if (buf == NULL) return ASL_STATUS_NO_MEMORY;
845
846 if (*mid != 0)
847 {
848 r.mid = *mid;
849 }
850 else
851 {
852 r.mid = asl_core_new_msg_id(0);
853 *mid = r.mid;
854 }
855
856 p = buf;
857
858 /* Type */
859 _asl_put_16(ASL_FILE_TYPE_MSG, p);
860 p += sizeof(uint16_t);
861
862 /* Length of message (excludes type and length fields) */
863 _asl_put_32(len - RECORD_COMMON_LEN, p);
864 p += sizeof(uint32_t);
865
866 /* Message data... */
867
868 _asl_put_64(r.next, p);
869 p += sizeof(uint64_t);
870
871 _asl_put_64(r.mid, p);
872 p += sizeof(uint64_t);
873
874 _asl_put_64(r.time, p);
875 p += sizeof(uint64_t);
876
877 _asl_put_32(r.nano, p);
878 p += sizeof(uint32_t);
879
880 _asl_put_16(r.level, p);
881 p += sizeof(uint16_t);
882
883 _asl_put_16(r.flags, p);
884 p += sizeof(uint16_t);
885
886 _asl_put_32(r.pid, p);
887 p += sizeof(uint32_t);
888
889 _asl_put_32(r.uid, p);
890 p += sizeof(uint32_t);
891
892 _asl_put_32(r.gid, p);
893 p += sizeof(uint32_t);
894
895 _asl_put_32(r.ruid, p);
896 p += sizeof(uint32_t);
897
898 _asl_put_32(r.rgid, p);
899 p += sizeof(uint32_t);
900
901 _asl_put_32(r.refpid, p);
902 p += sizeof(uint32_t);
903
904 _asl_put_32(r.kvcount, p);
905 p += sizeof(uint32_t);
906
907 _asl_put_64(r.host, p);
908 p += sizeof(uint64_t);
909
910 _asl_put_64(r.sender, p);
911 p += sizeof(uint64_t);
912
913 _asl_put_64(r.facility, p);
914 p += sizeof(uint64_t);
915
916 _asl_put_64(r.message, p);
917 p += sizeof(uint64_t);
918
919 _asl_put_64(r.refproc, p);
920 p += sizeof(uint64_t);
921
922 _asl_put_64(r.session, p);
923 p += sizeof(uint64_t);
924
925 for (i = 0; i < r.kvcount; i++)
926 {
927 _asl_put_64(kvlist[i], p);
928 p += sizeof(uint64_t);
929 }
930
931 _asl_put_64(r.prev, p);
932 p += sizeof(uint64_t);
933
934 free(kvlist);
935 kvlist = NULL;
936
b5d655f7
A
937 /* write record at end of file */
938 status = fseeko(s->store, 0, SEEK_END);
939 if (status != 0) return ASL_STATUS_WRITE_FAILED;
940
941 s->last = (uint64_t)ftello(s->store);
34e8f829 942
b5d655f7
A
943 v = asl_core_htonq(s->last);
944
945 status = fwrite(buf, len, 1, s->store);
946 fflush(s->store);
947
948 /* free the buffer if it was allocated here */
949 if (buf != s->scratch) free(buf);
950
951 /* seek to "next" field of previous record, write last offset */
952 off = s->prev + RECORD_COMMON_LEN;
953 if (s->prev == 0) off = DB_HEADER_FIRST_OFFSET;
954
955 status = fseeko(s->store, off, SEEK_SET);
956 if (status != 0) return ASL_STATUS_WRITE_FAILED;
957
958 status = fwrite(&v, sizeof(uint64_t), 1, s->store);
959 if (status != 1) return ASL_STATUS_WRITE_FAILED;
960
961 /* seek to DB_HEADER_LAST_OFFSET, write last record offset */
962 off = DB_HEADER_LAST_OFFSET;
963
964 status = fseeko(s->store, off, SEEK_SET);
965 if (status != 0) return ASL_STATUS_WRITE_FAILED;
966
967 status = fwrite(&v, sizeof(uint64_t), 1, s->store);
968 if (status != 1) return ASL_STATUS_WRITE_FAILED;
969
970 /* return to the end of the store (this is expected by other routines) */
971 status = fseeko(s->store, 0, SEEK_END);
972 if (status != 0) return ASL_STATUS_WRITE_FAILED;
973
1f2f436a
A
974 /* flush data */
975 fflush(s->store);
976
34e8f829
A
977 s->file_size = (size_t)ftello(s->store);
978
b5d655f7
A
979 s->prev = s->last;
980
981 return ASL_STATUS_OK;
982}
983
984static uint32_t
34e8f829 985asl_file_fetch_object(asl_file_t *s, uint64_t where, char **out, uint32_t *outlen)
b5d655f7
A
986{
987 static char ils[9];
988 char *p;
989 uint32_t len;
990 int status;
991 uint64_t x64;
992 uint8_t inls;
993 uint16_t type;
994 off_t off;
995
34e8f829
A
996 *out = NULL;
997 *outlen = 0;
998
b5d655f7
A
999 if (s == NULL) return ASL_STATUS_INVALID_STORE;
1000 if (out == NULL) return ASL_STATUS_INVALID_ARG;
1001 if (where == 0) return ASL_STATUS_INVALID_ARG;
1002
b5d655f7
A
1003 inls = 0;
1004 x64 = asl_core_htonq(where);
1005 memcpy(&inls, &x64, 1);
1006 if (inls & 0x80)
1007 {
1008 /* inline string */
b5d655f7 1009 inls &= 0x0f;
34e8f829
A
1010 if (inls > 7) return ASL_STATUS_INVALID_STORE;
1011
b5d655f7 1012 p = 1 + (char *)&x64;
34e8f829 1013 memset(ils, 0, sizeof(ils));
b5d655f7
A
1014 memcpy(ils, p, inls);
1015 *out = strdup(ils);
b5d655f7 1016 if (*out == NULL) return ASL_STATUS_NO_MEMORY;
34e8f829
A
1017
1018 *outlen = inls;
b5d655f7
A
1019 return ASL_STATUS_OK;
1020 }
1021
1022 off = where;
34e8f829
A
1023 if ((off + sizeof(uint16_t) + sizeof(uint32_t)) > s->file_size) return ASL_STATUS_READ_FAILED;
1024
b5d655f7
A
1025 status = fseeko(s->store, off, SEEK_SET);
1026 if (status != 0) return ASL_STATUS_READ_FAILED;
1027
1028 /* Type */
1029 status = fread(&type, sizeof(uint16_t), 1, s->store);
1030 if (status != 1) return ASL_STATUS_READ_FAILED;
34e8f829 1031 off += sizeof(uint16_t);
b5d655f7
A
1032
1033 /* Length */
1034 len = 0;
1035 status = fread(&len, sizeof(uint32_t), 1, s->store);
1036 if (status != 1) return ASL_STATUS_READ_FAILED;
34e8f829
A
1037 off += sizeof(uint32_t);
1038
b5d655f7 1039 len = ntohl(len);
34e8f829 1040 if ((off + len) > s->file_size) return ASL_STATUS_READ_FAILED;
b5d655f7
A
1041
1042 *out = calloc(1, len);
1043 if (*out == NULL) return ASL_STATUS_NO_MEMORY;
1044
1045 status = fread(*out, len, 1, s->store);
1046 if (status != 1)
1047 {
1048 free(*out);
1049 return ASL_STATUS_READ_FAILED;
1050 }
1051
34e8f829 1052 *outlen = len;
b5d655f7
A
1053 return ASL_STATUS_OK;
1054}
1055
1056static uint16_t
1057asl_file_fetch_helper_16(asl_file_t *s, char **p, aslmsg m, const char *key)
1058{
1059 uint16_t out;
1060 char str[256];
1061
1062 out = _asl_get_16(*p);
1063 *p += sizeof(uint16_t);
1064
1065 if ((m == NULL) || (key == NULL)) return out;
1066
1067 snprintf(str, sizeof(str), "%hu", out);
1068 asl_set(m, key, str);
1069
1070 return out;
1071}
1072
1073static uint32_t
1074asl_file_fetch_helper_32(asl_file_t *s, char **p, aslmsg m, const char *key, int ignore, uint32_t ignoreval)
1075{
1076 uint32_t out, doit;
1077 char str[256];
1078
1079 out = _asl_get_32(*p);
1080 *p += sizeof(uint32_t);
1081
1082 if ((m == NULL) || (key == NULL)) return out;
1083
1084 doit = 1;
1085 if ((ignore != 0) && (out == ignoreval)) doit = 0;
1086 if (doit != 0)
1087 {
1088 snprintf(str, sizeof(str), "%u", out);
1089 asl_set(m, key, str);
1090 }
1091
1092 return out;
1093}
1094
1095static uint64_t
1096asl_file_fetch_helper_64(asl_file_t *s, char **p, aslmsg m, const char *key)
1097{
1098 uint64_t out;
1099 char str[256];
1100
1101 out = _asl_get_64(*p);
1102 *p += sizeof(uint64_t);
1103
1104 if ((m == NULL) || (key == NULL)) return out;
1105
1106 snprintf(str, sizeof(str), "%llu", out);
1107 asl_set(m, key, str);
1108
1109 return out;
1110}
1111
1112static uint64_t
34e8f829 1113asl_file_fetch_helper_str(asl_file_t *s, char **p, aslmsg m, const char *key, uint32_t *err)
b5d655f7
A
1114{
1115 uint64_t out;
1116 char *val;
34e8f829 1117 uint32_t status, len;
b5d655f7
A
1118
1119 out = _asl_get_64(*p);
1120 *p += sizeof(uint64_t);
1121
1122 val = NULL;
34e8f829
A
1123 len = 0;
1124 status = ASL_STATUS_OK;
1125 if (out != 0) status = asl_file_fetch_object(s, out, &val, &len);
1126
1127 if (err != NULL) *err = status;
b5d655f7
A
1128 if ((status == ASL_STATUS_OK) && (val != NULL))
1129 {
1130 asl_set(m, key, val);
1131 free(val);
1132 }
1133
1134 return out;
1135}
1136
1137static uint32_t
1138asl_file_fetch_pos(asl_file_t *s, uint64_t where, int dir, aslmsg *msg)
1139{
1140 char *buf, *p, *k, *v;
1141 file_record_t r;
34e8f829 1142 uint32_t i, status, len, buflen, kvn;
b5d655f7
A
1143 uint64_t x64, kv;
1144 aslmsg out;
1145 off_t off;
1146
1147 if (s == NULL) return ASL_STATUS_INVALID_STORE;
1148 if (msg == NULL) return ASL_STATUS_INVALID_ARG;
1149 if ((s->flags & ASL_FILE_FLAG_READ_ONLY) == 0) return ASL_STATUS_WRITE_ONLY;
1150
1151 buf = NULL;
34e8f829
A
1152 buflen = 0;
1153 status = asl_file_fetch_object(s, where, &buf, &buflen);
1154 if ((status != ASL_STATUS_OK) || (buf == NULL))
1155 {
1156 s->cursor = 0;
1157 s->cursor_xid = 0;
1158 return status;
1159 }
1160
1161 /* check buffer size */
1162 kvn = _asl_get_32(buf + BUFFER_OFFSET_KVCOUNT);
1163 if (buflen < (MSG_RECORD_FIXED_LENGTH - RECORD_COMMON_LEN + (kvn * sizeof(uint64_t))))
1164 {
1165 free(buf);
1166 s->cursor = 0;
1167 s->cursor_xid = 0;
1168 return ASL_STATUS_READ_FAILED;
1169 }
b5d655f7
A
1170
1171 out = asl_new(ASL_TYPE_MSG);
1172 if (out == NULL) return ASL_STATUS_NO_MEMORY;
1173
1174 memset(&r, 0, sizeof(file_record_t));
1175 p = buf;
1176
1177 r.next = asl_file_fetch_helper_64(s, &p, NULL, NULL);
1178 r.mid = asl_file_fetch_helper_64(s, &p, out, ASL_KEY_MSG_ID);
1179 r.time = asl_file_fetch_helper_64(s, &p, out, ASL_KEY_TIME);
1180 r.nano = asl_file_fetch_helper_32(s, &p, out, ASL_KEY_TIME_NSEC, 0, 0);
1181 r.level = asl_file_fetch_helper_16(s, &p, out, ASL_KEY_LEVEL);
1182 r.flags = asl_file_fetch_helper_16(s, &p, NULL, NULL);
1183 r.pid = asl_file_fetch_helper_32(s, &p, out, ASL_KEY_PID, 0, 0);
1184 r.uid = asl_file_fetch_helper_32(s, &p, out, ASL_KEY_UID, 1, (uint32_t)-1);
1185 r.gid = asl_file_fetch_helper_32(s, &p, out, ASL_KEY_GID, 1, (uint32_t)-1);
1186 r.ruid = asl_file_fetch_helper_32(s, &p, out, ASL_KEY_READ_UID, 1, (uint32_t)-1);
1187 r.rgid = asl_file_fetch_helper_32(s, &p, out, ASL_KEY_READ_GID, 1, (uint32_t)-1);
1188 r.refpid = asl_file_fetch_helper_32(s, &p, out, ASL_KEY_REF_PID, 1, 0);
1189 r.kvcount = asl_file_fetch_helper_32(s, &p, NULL, NULL, 0, 0);
34e8f829
A
1190
1191 status = ASL_STATUS_OK;
1192 r.host = asl_file_fetch_helper_str(s, &p, out, ASL_KEY_HOST, &status); /* 68 */
1193 if (status == ASL_STATUS_OK) r.sender = asl_file_fetch_helper_str(s, &p, out, ASL_KEY_SENDER, &status); /* 76 */
1194 if (status == ASL_STATUS_OK) r.facility = asl_file_fetch_helper_str(s, &p, out, ASL_KEY_FACILITY, &status); /* 84 */
1195 if (status == ASL_STATUS_OK) r.message = asl_file_fetch_helper_str(s, &p, out, ASL_KEY_MSG, &status); /* 92 */
1196 if (status == ASL_STATUS_OK) r.refproc = asl_file_fetch_helper_str(s, &p, out, ASL_KEY_REF_PROC, &status); /* 100 */
1197 if (status == ASL_STATUS_OK) r.session = asl_file_fetch_helper_str(s, &p, out, ASL_KEY_SESSION, &status); /* 108 */
1198
1199 if (status != ASL_STATUS_OK)
1200 {
1201 asl_free(out);
1202 free(buf);
1203 s->cursor = 0;
1204 s->cursor_xid = 0;
1205 return status;
1206 }
1207
1208 kvn = r.kvcount / 2;
1209
1210 for (i = 0; i < kvn; i++)
b5d655f7
A
1211 {
1212 kv = _asl_get_64(p);
1213 p += sizeof(uint64_t);
1214 k = NULL;
34e8f829
A
1215 len = 0;
1216 status = asl_file_fetch_object(s, kv, &k, &len);
1217 if (status != ASL_STATUS_OK)
1218 {
1219 asl_free(out);
1220 free(buf);
1221 s->cursor = 0;
1222 s->cursor_xid = 0;
1223 return status;
1224 }
b5d655f7
A
1225
1226 kv = _asl_get_64(p);
1227 p += sizeof(uint64_t);
1228 v = NULL;
34e8f829
A
1229 len = 0;
1230
1231 if (kv != 0)
1232 {
1233 status = asl_file_fetch_object(s, kv, &v, &len);
1234 if (status != ASL_STATUS_OK)
1235 {
1236 asl_free(out);
1237 free(buf);
1238 s->cursor = 0;
1239 s->cursor_xid = 0;
1240 return status;
1241 }
1242 }
b5d655f7
A
1243
1244 if ((status == ASL_STATUS_OK) && (k != NULL))
1245 {
1246 asl_set(out, k, v);
1247 if (v != NULL) free(v);
1248 free(k);
1249 }
1250 }
1251
34e8f829 1252 r.prev = asl_file_fetch_helper_64(s, &p, NULL, NULL); /* 116 */
b5d655f7
A
1253
1254 free(buf);
1255
1256 if (dir >= 0) s->cursor = r.next;
1257 else s->cursor = r.prev;
1258
1259 s->cursor_xid = 0;
1260
1261 if (s->cursor != 0)
1262 {
1263 off = s->cursor + RECORD_COMMON_LEN + sizeof(uint64_t);
34e8f829
A
1264 if (off > s->file_size)
1265 {
1266 asl_free(out);
1267 s->cursor = 0;
1268 s->cursor_xid = 0;
1269 /*
1270 * Next record offset is past the end of the file.
1271 * This is an error, but we allow it to fail quietly
1272 * so that the current record fetch succeeds.
1273 */
1274 return ASL_STATUS_OK;
1275 }
1276
b5d655f7 1277 status = fseeko(s->store, off, SEEK_SET);
34e8f829
A
1278 if (status != 0)
1279 {
1280 asl_free(out);
1281 s->cursor = 0;
1282 s->cursor_xid = 0;
1283 return ASL_STATUS_READ_FAILED;
1284 }
b5d655f7
A
1285
1286 status = fread(&x64, sizeof(uint64_t), 1, s->store);
34e8f829
A
1287 if (status != 1)
1288 {
1289 asl_free(out);
1290 s->cursor = 0;
1291 s->cursor_xid = 0;
1292 return ASL_STATUS_READ_FAILED;
1293 }
b5d655f7
A
1294
1295 s->cursor_xid = asl_core_ntohq(x64);
1296 }
1297
1298 *msg = out;
1299 return ASL_STATUS_OK;
1300}
1301
1302uint32_t
1303asl_file_open_read(const char *path, asl_file_t **s)
1304{
1305 asl_file_t *out;
1306 FILE *f;
1307 int i;
1f2f436a 1308 uint32_t status, vers, last_len;
b5d655f7
A
1309 char buf[DB_HEADER_LEN];
1310 off_t off;
1311 asl_legacy1_t *legacy;
34e8f829
A
1312 struct stat sb;
1313
1314 memset(&sb, 0, sizeof(struct stat));
1315 if (stat(path, &sb) != 0) return ASL_STATUS_FAILED;
b5d655f7
A
1316
1317 f = fopen(path, "r");
1318 if (f == NULL)
1319 {
1320 if (errno == EACCES) return ASL_STATUS_ACCESS_DENIED;
1321 return ASL_STATUS_FAILED;
1322 }
1323
1324 i = fread(buf, DB_HEADER_LEN, 1, f);
1325 if (i < 1)
1326 {
1327 fclose(f);
1328 return ASL_STATUS_INVALID_STORE;
1329 }
1330
1331 /* validate header */
1332 if (strncmp(buf, ASL_DB_COOKIE, ASL_DB_COOKIE_LEN))
1333 {
1334 fclose(f);
1335 return ASL_STATUS_INVALID_STORE;
1336 }
1337
1338 legacy = NULL;
1339
1340 vers = _asl_get_32(buf + DB_HEADER_VERS_OFFSET);
1341 if (vers == DB_VERSION_LEGACY_1)
1342 {
1343 fclose(f);
1344 status = asl_legacy1_open(path, &legacy);
1345 if (status != ASL_STATUS_OK) return status;
1346 }
1347
1348 out = (asl_file_t *)calloc(1, sizeof(asl_file_t));
1349 if (out == NULL)
1350 {
1351 fclose(f);
1352 return ASL_STATUS_NO_MEMORY;
1353 }
1354
1f2f436a 1355 out->store = f;
b5d655f7
A
1356 out->flags = ASL_FILE_FLAG_READ_ONLY;
1357 out->version = vers;
1358
1359 if (legacy != NULL)
1360 {
1361 out->flags |= ASL_FILE_FLAG_LEGACY_STORE;
1362 out->legacy = (void *)legacy;
1363
1364 *s = out;
1365 return ASL_STATUS_OK;
1366 }
1367
1368 out->first = _asl_get_64(buf + DB_HEADER_FIRST_OFFSET);
1369 out->last = _asl_get_64(buf + DB_HEADER_LAST_OFFSET);
34e8f829
A
1370 out->file_size = (size_t)sb.st_size;
1371
1f2f436a
A
1372 /*
1373 * Detect bogus last pointer and check for odd-sized files.
1374 * Setting out->last to zero forces us to follow the linked
1375 * list of records in the file to the last record. That's
1376 * done in the set_position code. It's a bit slower, but it's
1377 * better at preventing crashes in corrupt files.
1378 */
b5d655f7 1379
1f2f436a
A
1380 /* records are at least MSG_RECORD_FIXED_LENGTH bytes */
1381 if ((out->last + MSG_RECORD_FIXED_LENGTH) > out->file_size)
1382 {
1383 out->last = 0;
1384 }
1385 else
1386 {
1387 /* read last record length and make sure the file is at least that large */
1388 off = out->last + RECORD_TYPE_LEN;
1389 status = asl_file_read_uint32(out, off, &last_len);
1390 if (status != ASL_STATUS_OK)
1391 {
1392 fclose(out->store);
1393 free(out);
1394 return status;
1395 }
1396
1397 if ((out->last + last_len) > out->file_size) out->last = 0;
1398 }
b5d655f7
A
1399
1400 out->cursor = out->first;
1401 if (out->cursor != 0)
1402 {
1403 off = out->cursor + RECORD_COMMON_LEN + sizeof(uint64_t);
1404 status = asl_file_read_uint64(out, off, &(out->cursor_xid));
1405 if (status != ASL_STATUS_OK)
1406 {
1f2f436a
A
1407 fclose(out->store);
1408 free(out);
b5d655f7
A
1409 return status;
1410 }
1411 }
1412
1413 *s = out;
1414 return ASL_STATUS_OK;
1415}
1416
1417static uint32_t
1418asl_file_read_set_position_first(asl_file_t *s)
1419{
1420 uint32_t status;
1421 off_t off;
1422
1423 s->cursor = s->first;
1424 s->cursor_xid = 0;
1425
1426 if (s->cursor == 0) return ASL_STATUS_OK;
1427
1428 /* read ID of the first record */
1429 off = s->cursor + RECORD_COMMON_LEN + sizeof(uint64_t);
1430 status = asl_file_read_uint64(s, off, &(s->cursor_xid));
1431 return status;
1432}
1433
1434static uint32_t
1435asl_file_read_set_position_last(asl_file_t *s)
1436{
1437 uint64_t next;
1438 uint32_t status;
1439 off_t off;
1440
1441 /*
1442 * If the file has the offset of the last record, we just go there.
1443 * The last record offset was added to improve performance, so it may
1444 * or may not be there. If we don't have the last record offset, we
1445 * just iterate down the record links to find the last one.
1446 *
1447 * Note that s->last may be zero if the file is empty.
1448 */
1449
1450 if (s->last != 0)
1451 {
1452 s->cursor = s->last;
1453 off = s->last + RECORD_COMMON_LEN + sizeof(uint64_t);
1454
1455 /* read ID of the last record */
1456 status = asl_file_read_uint64(s, off, &(s->cursor_xid));
1457 return status;
1458 }
1459
1460 /* start at the first record and iterate */
1461 s->cursor = s->first;
1462 s->cursor_xid = 0;
1463
1464 forever
1465 {
1466 off = s->cursor + RECORD_COMMON_LEN;
1467 next = 0;
1468
1469 /* read next offset */
1470 status = asl_file_read_uint64(s, off, &next);
1471 if (status != ASL_STATUS_OK) return status;
1472
34e8f829 1473 /* detect bogus next pointer */
1f2f436a 1474 if (((next + MSG_RECORD_FIXED_LENGTH) > s->file_size) || (next <= s->cursor)) next = 0;
34e8f829 1475
b5d655f7
A
1476 if (next == 0)
1477 {
1478 if (s->cursor == 0) return ASL_STATUS_OK;
1479
1480 off = s->cursor + RECORD_COMMON_LEN + sizeof(uint64_t);
1481 status = asl_file_read_uint64(s, off, &(s->cursor_xid));
1482 return ASL_STATUS_OK;
1483 }
1484
1485 s->cursor = next;
1486 }
1487}
1488
1489uint32_t
1490asl_file_read_set_position(asl_file_t *s, uint32_t pos)
1491{
1f2f436a 1492 uint64_t next;
b5d655f7
A
1493 uint32_t len, status;
1494 off_t off;
1495
1496 if (s == NULL) return ASL_STATUS_INVALID_STORE;
1497 if (s->version == 1) return ASL_STATUS_FAILED;
1498
1499 if (pos == ASL_FILE_POSITION_FIRST) return asl_file_read_set_position_first(s);
1500 if (pos == ASL_FILE_POSITION_LAST) return asl_file_read_set_position_last(s);
1501
1502 off = 0;
1503
1504 if (pos == ASL_FILE_POSITION_PREVIOUS)
1505 {
1506 if (s->cursor == s->first) return ASL_STATUS_NO_RECORDS;
1507 if (s->cursor == 0) return ASL_STATUS_NO_RECORDS;
1508
1509 off = s->cursor + RECORD_TYPE_LEN;
1510 status = asl_file_read_uint32(s, off, &len);
1511 if (status != ASL_STATUS_OK) return status;
1512
1513 /* set offset to read the "previous" field at the end of the record */
1514 off = s->cursor + RECORD_COMMON_LEN + len - sizeof(uint64_t);
1515 }
1516 else if (pos == ASL_FILE_POSITION_NEXT)
1517 {
1518 if (s->cursor == s->last) return ASL_STATUS_NO_RECORDS;
1519 if (s->cursor == 0) return ASL_STATUS_NO_RECORDS;
1520
34e8f829 1521 /* set offset to read the "next" field in the current record */
b5d655f7
A
1522 off = s->cursor + RECORD_COMMON_LEN;
1523 }
1524 else return ASL_STATUS_INVALID_ARG;
1525
1526 s->cursor_xid = 0;
1527
1528 /*
1529 * read offset of next / previous
1530 */
1f2f436a
A
1531 next = 0;
1532 status = asl_file_read_uint64(s, off, &next);
b5d655f7
A
1533 if (status != ASL_STATUS_OK) return ASL_STATUS_READ_FAILED;
1534
34e8f829 1535 /* detect bogus next pointer */
1f2f436a
A
1536 if ((next + MSG_RECORD_FIXED_LENGTH) > s->file_size) next = 0;
1537 else if ((pos == ASL_FILE_POSITION_PREVIOUS) && (next >= s->cursor)) next = 0;
1538 else if ((pos == ASL_FILE_POSITION_NEXT) && (next <= s->cursor)) next = 0;
34e8f829 1539
1f2f436a 1540 s->cursor = next;
b5d655f7
A
1541 if (s->cursor == 0) return ASL_STATUS_NO_RECORDS;
1542
1543 /* read ID of the record */
1544 off = s->cursor + RECORD_COMMON_LEN + sizeof(uint64_t);
1545 status = asl_file_read_uint64(s, off, &(s->cursor_xid));
1546 return status;
1547}
1548
1549uint32_t
1550asl_file_fetch_next(asl_file_t *s, aslmsg *msg)
1551{
1552 if (s == NULL) return ASL_STATUS_INVALID_STORE;
1553 if (s->version == 1) return ASL_STATUS_FAILED;
1554
1555 return asl_file_fetch_pos(s, s->cursor, 1, msg);
1556}
1557
1558uint32_t
1559asl_file_fetch_previous(asl_file_t *s, aslmsg *msg)
1560{
1561 if (s == NULL) return ASL_STATUS_INVALID_STORE;
1562 if (s->version == 1) return ASL_STATUS_FAILED;
1563
1564 return asl_file_fetch_pos(s, s->cursor, -1, msg);
1565}
1566
1567uint32_t
1568asl_file_fetch(asl_file_t *s, uint64_t mid, aslmsg *msg)
1569{
1570 uint32_t status;
1571
1572 if (s == NULL) return ASL_STATUS_INVALID_STORE;
1573 if (msg == NULL) return ASL_STATUS_INVALID_ARG;
1574 if ((s->flags & ASL_FILE_FLAG_READ_ONLY) == 0) return ASL_STATUS_WRITE_ONLY;
1575
1576 if (s->version == 1)
1577 {
1578 return asl_legacy1_fetch((asl_legacy1_t *)s->legacy, mid, msg);
1579 }
1580
1581 if (s->cursor_xid == 0)
1582 {
1583 status = asl_file_read_set_position(s, ASL_FILE_POSITION_FIRST);
1584 if (status != ASL_STATUS_OK) return status;
1585 if (s->cursor_xid == 0) return ASL_STATUS_INVALID_ID;
1586 }
1587
1588 while (s->cursor_xid < mid)
1589 {
1590 status = asl_file_read_set_position(s, ASL_FILE_POSITION_NEXT);
1591 if (status != ASL_STATUS_OK) return status;
1592 if (s->cursor_xid > mid) return ASL_STATUS_INVALID_ID;
1593 if (s->cursor_xid == 0) return ASL_STATUS_INVALID_ID;
1594 }
1595
1596 while (s->cursor_xid > mid)
1597 {
1598 status = asl_file_read_set_position(s, ASL_FILE_POSITION_PREVIOUS);
1599 if (status != ASL_STATUS_OK) return status;
1600 if (s->cursor_xid < mid) return ASL_STATUS_INVALID_ID;
1601 if (s->cursor_xid == 0) return ASL_STATUS_INVALID_ID;
1602 }
1603
1604 if (s->cursor_xid != mid) return ASL_STATUS_INVALID_ID;
1605
1606 return asl_file_fetch_pos(s, s->cursor, 1, msg);
1607}
1608
1f2f436a 1609__private_extern__ uint64_t
b5d655f7
A
1610asl_file_cursor(asl_file_t *s)
1611{
1612 if (s == NULL) return 0;
1613 if ((s->flags & ASL_FILE_FLAG_READ_ONLY) == 0) return 0;
1614 if (s->version == 1) return 0;
1615
1616 return s->cursor_xid;
1617}
1618
1f2f436a 1619__private_extern__ uint32_t
b5d655f7
A
1620asl_file_match_start(asl_file_t *s, uint64_t start_id, int32_t direction)
1621{
1622 uint32_t status, d;
1623
1624 if (s == NULL) return ASL_STATUS_INVALID_STORE;
1625 if (s->version == 1) return ASL_STATUS_INVALID_STORE;
1626 if ((s->flags & ASL_FILE_FLAG_READ_ONLY) == 0) return ASL_STATUS_WRITE_ONLY;
1627
1628 d = ASL_FILE_POSITION_NEXT;
1629 if (direction < 0) d = ASL_FILE_POSITION_PREVIOUS;
1630
1631 /*
1632 * find starting point
1633 */
1634 status = ASL_STATUS_OK;
1635 if (direction >= 0) status = asl_file_read_set_position(s, ASL_FILE_POSITION_FIRST);
1636 else status = asl_file_read_set_position(s, ASL_FILE_POSITION_LAST);
1637 if (status != ASL_STATUS_OK) return status;
1638
1639 while ((status == ASL_STATUS_OK) && (((direction >= 0) && (s->cursor_xid < start_id)) || ((direction < 0) && (s->cursor_xid > start_id))))
1640 {
1641 status = asl_file_read_set_position(s, d);
1642 }
1643
1644 return status;
1645}
1646
1f2f436a
A
1647__private_extern__ uint32_t
1648asl_file_match_next(asl_file_t *s, aslresponse query, aslmsg *msg, uint64_t *last_id, int32_t direction)
b5d655f7
A
1649{
1650 uint32_t status, d, i, do_match, did_match;
1651 aslmsg m;
1652
1653 if (s == NULL) return ASL_STATUS_INVALID_STORE;
1654 if (msg == NULL) return ASL_STATUS_INVALID_ARG;
1655 if (s->version == 1) return ASL_STATUS_INVALID_STORE;
1656 if ((s->flags & ASL_FILE_FLAG_READ_ONLY) == 0) return ASL_STATUS_WRITE_ONLY;
1657 if (s->cursor == 0) return ASL_STATUS_NO_RECORDS;
1658
1659 *msg = NULL;
1660 do_match = 1;
1661
1662 d = ASL_FILE_POSITION_NEXT;
1663 if (direction < 0) d = ASL_FILE_POSITION_PREVIOUS;
1664
1665 if ((query == NULL) || ((query != NULL) && (query->count == 0))) do_match = 0;
1666
1667 m = NULL;
1668
1669 *last_id = s->cursor_xid;
1670
1671 status = asl_file_fetch_pos(s, s->cursor, direction, &m);
1672 if (status == ASL_STATUS_ACCESS_DENIED) return ASL_STATUS_MATCH_FAILED;
1673 if ((status == ASL_STATUS_INVALID_ARG) && (s->cursor == 0)) return ASL_STATUS_NO_RECORDS;
1674 if (status != ASL_STATUS_OK) return status;
1675
1676 did_match = 1;
1677
1678 if (do_match != 0)
1679 {
1680 did_match = 0;
1681
1682 for (i = 0; (i < query->count) && (did_match == 0); i++)
1683 {
1f2f436a 1684 did_match = asl_msg_cmp((aslmsg)(query->msg[i]), m);
b5d655f7
A
1685 }
1686 }
1687
1688 if (did_match != 0)
1689 {
1690 *msg = m;
1691 return ASL_STATUS_OK;
1692 }
1693
1694 asl_free(m);
1695 return ASL_STATUS_MATCH_FAILED;
1696}
1697
1698uint32_t
1699asl_file_match(asl_file_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction)
1700{
1701 uint32_t status, d, i, do_match, did_match, rescount;
1f2f436a 1702 aslmsg m;
b5d655f7
A
1703
1704 if (s == NULL) return ASL_STATUS_INVALID_STORE;
1705 if (res == NULL) return ASL_STATUS_INVALID_ARG;
1706 if ((s->flags & ASL_FILE_FLAG_READ_ONLY) == 0) return ASL_STATUS_WRITE_ONLY;
1707
1708 if (s->version == 1)
1709 {
1710 return asl_legacy1_match((asl_legacy1_t *)s->legacy, query, res, last_id, start_id, count, direction);
1711 }
1712
1713 do_match = 1;
1714 rescount = 0;
1715
1716 d = ASL_FILE_POSITION_NEXT;
1717 if (direction < 0) d = ASL_FILE_POSITION_PREVIOUS;
1718
1719 if ((query == NULL) || ((query != NULL) && (query->count == 0))) do_match = 0;
1720
1721 /*
1722 * find starting point
1723 */
1724 status = ASL_STATUS_OK;
1725 if (direction >= 0) status = asl_file_read_set_position(s, ASL_FILE_POSITION_FIRST);
1726 else status = asl_file_read_set_position(s, ASL_FILE_POSITION_LAST);
1727 if (status != ASL_STATUS_OK) return status;
1728
1729 while ((status == ASL_STATUS_OK) && (((direction >= 0) && (s->cursor_xid < start_id)) || ((direction < 0) && (s->cursor_xid > start_id))))
1730 {
1731 status = asl_file_read_set_position(s, d);
1732 }
1733
1734 /*
1735 * loop through records
1736 */
1737 forever
1738 {
1739 m = NULL;
1740 status = asl_file_fetch_pos(s, s->cursor, direction, &m);
1741 if (status == ASL_STATUS_ACCESS_DENIED) continue;
1742 if (status != ASL_STATUS_OK) break;
1743
1744 *last_id = s->cursor_xid;
1745
1746 did_match = 1;
1747
1748 if (do_match != 0)
1749 {
1750 did_match = 0;
1751
1752 for (i = 0; (i < query->count) && (did_match == 0); i++)
1753 {
1f2f436a 1754 did_match = asl_msg_cmp((aslmsg)query->msg[i], m);
b5d655f7
A
1755 }
1756 }
1757
1758 if (did_match == 1)
1759 {
1760 /* append m to res */
1761 if (*res == NULL)
1762 {
1763 *res = (aslresponse)calloc(1, sizeof(aslresponse));
1764 if (*res == NULL) return ASL_STATUS_NO_MEMORY;
1f2f436a 1765 (*res)->msg = (asl_msg_t **)calloc(1, sizeof(aslmsg));
b5d655f7
A
1766 if ((*res)->msg == NULL)
1767 {
1768 free(*res);
1769 return ASL_STATUS_NO_MEMORY;
1770 }
1771 }
1772 else
1773 {
1f2f436a 1774 (*res)->msg = (asl_msg_t **)reallocf((*res)->msg, ((*res)->count + 1) * sizeof(aslmsg));
b5d655f7
A
1775 if ((*res)->msg == NULL)
1776 {
1777 free(*res);
1778 return ASL_STATUS_NO_MEMORY;
1779 }
1780 }
1781
1f2f436a 1782 (*res)->msg[(*res)->count] = (asl_msg_t *)m;
b5d655f7
A
1783 (*res)->count++;
1784
1785 rescount++;
1786 if ((count != 0) && (rescount >= count)) break;
1787 }
1788 else
1789 {
1790 asl_free(m);
1791 }
1792 }
1793
1794 /* NOT REACHED */
1795 return ASL_STATUS_OK;
1796}
1797
1798size_t
1799asl_file_size(asl_file_t *s)
1800{
1801 if (s == NULL) return 0;
1802 return s->file_size;
1803}
1804
1805uint64_t
1806asl_file_ctime(asl_file_t *s)
1807{
1808 if (s == NULL) return 0;
1809 return s->dob;
1810}
1811
1812void
1813asl_file_list_close(asl_file_list_t *head)
1814{
1815 asl_file_list_t *next;
1816
1817 while (head != NULL)
1818 {
1819 next = head->next;
1820 asl_file_close(head->file);
1821 free(head);
1822 head = next;
1823 }
1824}
1825
1826static void
1827asl_file_list_free(asl_file_list_t *head)
1828{
1829 asl_file_list_t *next;
1830
1831 while (head != NULL)
1832 {
1833 next = head->next;
1834 free(head);
1835 head = next;
1836 }
1837}
1838
1f2f436a 1839static asl_file_list_t *
b5d655f7
A
1840asl_file_list_insert(asl_file_list_t *list, asl_file_t *f, int32_t dir)
1841{
1842 asl_file_list_t *a, *b, *tmp;
1843
1844 if (f == NULL) return list;
1845
1846 tmp = (asl_file_list_t *)calloc(1, sizeof(asl_file_list_t));
1847 if (tmp == NULL) return NULL;
1848 tmp->file = f;
1849
1850 if (list == NULL) return tmp;
1851
1852 a = list;
1853 if (((dir < 0) && (f->cursor_xid > a->file->cursor_xid)) || ((dir >= 0) && (f->cursor_xid < a->file->cursor_xid)))
1854 {
1855 tmp->next = list;
1856 return tmp;
1857 }
1858
1859 b = a->next;
1860 while (b != NULL)
1861 {
1862 if (((dir < 0) && (f->cursor_xid > b->file->cursor_xid)) || ((dir >= 0) && (f->cursor_xid < b->file->cursor_xid)))
1863 {
1864 tmp->next = b;
1865 a->next = tmp;
1866 return list;
1867 }
1868
1869 a = b;
1870 b = a->next;
1871 }
1872
1873 a->next = tmp;
1874 return list;
1875}
1876
1877asl_file_list_t *
1878asl_file_list_add(asl_file_list_t *list, asl_file_t *f)
1879{
1880 asl_file_list_t *tmp;
1881
1882 if (f == NULL) return list;
1883 if (f->version == 1) return list;
1884
1885 tmp = (asl_file_list_t *)calloc(1, sizeof(asl_file_list_t));
1886 if (tmp == NULL) return NULL;
1887 tmp->file = f;
1888
1889 tmp->next = list;
1890 return tmp;
1891}
1892
1893void *
1894asl_file_list_match_start(asl_file_list_t *list, uint64_t start_id, int32_t direction)
1895{
1896 uint32_t status;
1897 asl_file_list_t *n;
1898 asl_file_match_token_t *out;
1899
1900 if (list == NULL) return NULL;
1901
1902 out = (asl_file_match_token_t *)calloc(1, sizeof(asl_file_match_token_t));
1903 if (out == NULL) return NULL;
1904
1905 for (n = list; n != NULL; n = n->next)
1906 {
1907 /* init file for the search */
1908 status = asl_file_match_start(n->file, start_id, direction);
1909 if (status != ASL_STATUS_OK) continue;
1910 if (n->file->cursor_xid == 0) continue;
1911
1912 out->list = asl_file_list_insert(out->list, n->file, direction);
1913 }
1914
1915 out->dir = direction;
1916 return out;
1917}
1918
1919uint32_t
1920asl_file_list_match_next(void *token, aslresponse query, aslresponse *res, uint32_t count)
1921{
1922 uint32_t status, rescount;
1923 asl_file_list_t *n;
1f2f436a 1924 aslmsg m;
b5d655f7
A
1925 asl_file_match_token_t *work;
1926 uint64_t last_id;
1927
1928 if (token == NULL) return ASL_STATUS_OK;
1929 if (res == NULL) return ASL_STATUS_INVALID_ARG;
1930
1931 work = (asl_file_match_token_t *)token;
1932
1933 rescount = 0;
1934 last_id = 0;
1935
1936 while ((work->list != NULL) && ((rescount < count) || (count == 0)))
1937 {
1938 m = NULL;
1939 status = asl_file_match_next(work->list->file, query, &m, &last_id, work->dir);
1940 if (m != NULL)
1941 {
1942 if (*res == NULL) *res = (aslresponse)calloc(1, sizeof(asl_search_result_t));
1943 if (*res == NULL)
1944 {
1945 asl_file_list_free(work->list);
1946 work->list = NULL;
1947 return ASL_STATUS_NO_MEMORY;
1948 }
1949
1f2f436a
A
1950 if ((*res)->msg == NULL) (*res)->msg = (asl_msg_t **)calloc(1, sizeof(aslmsg));
1951 else (*res)->msg = (asl_msg_t **)reallocf((*res)->msg, ((*res)->count + 1) * sizeof(aslmsg));
b5d655f7
A
1952 if ((*res)->msg == NULL)
1953 {
1954 free(*res);
1955 *res = NULL;
1956 asl_file_list_free(work->list);
1957 work->list = NULL;
1958 return ASL_STATUS_NO_MEMORY;
1959 }
1960
1f2f436a 1961 (*res)->msg[(*res)->count] = (asl_msg_t *)m;
b5d655f7
A
1962 (*res)->count++;
1963 rescount++;
1964 }
1965
34e8f829 1966 if ((status != ASL_STATUS_OK) || (work->list->file->cursor_xid == 0))
b5d655f7
A
1967 {
1968 n = work->list->next;
1969 free(work->list);
1970 work->list = n;
1971 }
1972
1973 if (work->list != NULL)
1974 {
1975 n = work->list->next;
1976 if (n != NULL)
1977 {
1978 if (((work->dir < 0) && (work->list->file->cursor_xid <= n->file->cursor_xid)) || ((work->dir >= 0) && (work->list->file->cursor_xid > n->file->cursor_xid)))
1979 {
1980 n = work->list;
1981 work->list = work->list->next;
1982 n->next = NULL;
1983 work->list = asl_file_list_insert(work->list, n->file, work->dir);
1984 free(n);
1985 }
1986 }
1987 }
1988 }
1989
1990 return ASL_STATUS_OK;
1991}
1992
1993void
1994asl_file_list_match_end(void *token)
1995{
1996 asl_file_match_token_t *work;
1997
1998 if (token == NULL) return;
1999
2000 work = (asl_file_match_token_t *)token;
2001 asl_file_list_free(work->list);
2002 work->list = NULL;
2003
2004 free(token);
2005}
2006
2007uint32_t
2008asl_file_list_match_timeout(asl_file_list_t *list, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, uint32_t usec)
2009{
2010 uint32_t status, rescount;
2011 asl_file_list_t *files, *n;
1f2f436a 2012 aslmsg m;
b5d655f7
A
2013 struct timeval now, finish;
2014
2015 if (list == NULL) return ASL_STATUS_INVALID_ARG;
2016 if (res == NULL) return ASL_STATUS_INVALID_ARG;
2017 if (last_id == NULL) return ASL_STATUS_INVALID_ARG;
2018
2019 files = NULL;
2020
2021 for (n = list; n != NULL; n = n->next)
2022 {
2023 /* init file for the search */
2024 status = asl_file_match_start(n->file, start_id, direction);
2025 if (status != ASL_STATUS_OK) continue;
2026 if (n->file->cursor_xid == 0) continue;
2027
2028 files = asl_file_list_insert(files, n->file, direction);
2029 }
2030
2031 if (files == NULL)
2032 {
2033 asl_file_list_free(files);
2034 return ASL_STATUS_OK;
2035 }
2036
2037 /* start the timer if a timeout was specified */
2038 memset(&finish, 0, sizeof(struct timeval));
2039 if (usec != 0)
2040 {
2041 if (gettimeofday(&finish, NULL) == 0)
2042 {
2043 finish.tv_sec += (usec / MILLION);
2044 finish.tv_usec += (usec % MILLION);
2045 if (finish.tv_usec > MILLION)
2046 {
2047 finish.tv_usec -= MILLION;
2048 finish.tv_sec += 1;
2049 }
2050 }
2051 else
2052 {
2053 /* shouldn't happen, but if gettimeofday failed we just run without a timeout */
2054 memset(&finish, 0, sizeof(struct timeval));
2055 }
2056 }
2057
2058 rescount = 0;
2059 while ((files != NULL) && ((rescount < count) || (count == 0)))
2060 {
2061 m = NULL;
2062 status = asl_file_match_next(files->file, query, &m, last_id, direction);
2063 if (m != NULL)
2064 {
2065 if (*res == NULL) *res = (aslresponse)calloc(1, sizeof(asl_search_result_t));
2066 if (*res == NULL)
2067 {
2068 asl_file_list_free(files);
2069 return ASL_STATUS_NO_MEMORY;
2070 }
2071
1f2f436a
A
2072 if ((*res)->msg == NULL) (*res)->msg = (asl_msg_t **)calloc(1, sizeof(aslmsg));
2073 else (*res)->msg = (asl_msg_t **)reallocf((*res)->msg, ((*res)->count + 1) * sizeof(aslmsg));
b5d655f7
A
2074 if ((*res)->msg == NULL)
2075 {
2076 free(*res);
2077 *res = NULL;
2078 asl_file_list_free(files);
2079 return ASL_STATUS_NO_MEMORY;
2080 }
2081
1f2f436a 2082 (*res)->msg[(*res)->count] = (asl_msg_t *)m;
b5d655f7
A
2083 (*res)->count++;
2084 rescount++;
2085 }
2086
2087 if (files->file->cursor_xid == 0)
2088 {
2089 n = files->next;
2090 free(files);
2091 files = n;
2092 }
2093
2094 if (files != NULL)
2095 {
2096 n = files->next;
2097 if (n != NULL)
2098 {
2099 if (((direction < 0) && (files->file->cursor_xid <= n->file->cursor_xid)) || ((direction >= 0) && (files->file->cursor_xid > n->file->cursor_xid)))
2100 {
2101 n = files;
2102 files = files->next;
2103 n->next = NULL;
2104 files = asl_file_list_insert(files, n->file, direction);
2105 free(n);
2106 }
2107 }
2108 }
2109
2110 /* check the timer */
2111 if ((finish.tv_sec != 0) && (gettimeofday(&now, NULL) == 0))
2112 {
2113 if ((now.tv_sec > finish.tv_sec) || ((now.tv_sec == finish.tv_sec) && (now.tv_usec > finish.tv_usec))) break;
2114 }
2115 }
2116
2117 asl_file_list_free(files);
2118 return ASL_STATUS_OK;
2119}
2120
2121uint32_t
2122asl_file_list_match(asl_file_list_t *list, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction)
2123{
2124 return asl_file_list_match_timeout(list, query, res, last_id, start_id, count, direction, 0);
2125}