]> git.saurik.com Git - apple/libc.git/blame - gen/asl_store.c
Libc-594.9.5.tar.gz
[apple/libc.git] / gen / asl_store.c
CommitLineData
b5d655f7 1/*
34e8f829 2 * Copyright (c) 2007-2009 Apple Inc. All rights reserved.
b5d655f7
A
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * "Portions Copyright (c) 2007 Apple Inc. All Rights
7 * Reserved. This file contains Original Code and/or Modifications of
8 * Original Code as defined in and that are subject to the Apple Public
9 * Source License Version 1.0 (the 'License'). You may not use this file
10 * except in compliance with the License. Please obtain a copy of the
11 * License at http://www.apple.com/publicsource and read it before using
12 * this file.
13 *
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19 * License for the specific language governing rights and limitations
20 * under the License."
21 *
22 * @APPLE_LICENSE_HEADER_END@
23 */
24
25#include <stdlib.h>
26#include <unistd.h>
27#include <string.h>
28#include <errno.h>
29#include <dirent.h>
30#include <sys/types.h>
31#include <sys/stat.h>
32#include <fcntl.h>
33#include <asl.h>
34#include <asl_private.h>
35#include <asl_core.h>
36#include <asl_store.h>
37#include <notify.h>
38
39extern time_t asl_parse_time(const char *str);
40extern uint64_t asl_file_cursor(asl_file_t *s);
41extern uint32_t asl_file_match_start(asl_file_t *s, uint64_t start_id, int32_t direction);
42extern uint32_t asl_file_match_next(asl_file_t *s, aslresponse query, asl_msg_t **msg, uint64_t *last_id, int32_t direction, int32_t ruid, int32_t rgid);
43
44#define SECONDS_PER_DAY 86400
45
46/*
47 * The ASL Store is organized as a set of files in a common directory.
48 * Files are prefixed by the date (YYYY.MM.DD) of their contents.
b5d655f7
A
49 *
50 * Messages with no access controls are saved in YYYY.MM.DD.asl
34e8f829
A
51 * Messages with access limited to UID uuu are saved in YYYY.MM.DD.Uuuu.asl
52 * Messages with access limited to GID ggg are saved in YYYY.MM.DD.Gggg.asl
53 * Messages with access limited to UID uuu and GID ggg are saved in YYYY.MM.DD.Uuuu.Gggg.asl
54 *
55 * Messages that have a value for ASLExpireTime are saved in BB.YYYY.MM.DD.asl
56 * where the timestamp is the "Best Before" date of the file. Access controls
57 * are implemented as above with Uuuu and Gggg in the file name. Note that the
58 * Best Before files are for the last day of the month, so a single file contains
59 * messages that expire in that month.
b5d655f7
A
60 *
61 * An external tool runs daily and deletes "old" files.
62 */
63
34e8f829
A
64static time_t
65_asl_start_today()
66{
67 time_t now;
68 struct tm ctm;
69
70 memset(&ctm, 0, sizeof(struct tm));
71 now = time(NULL);
72
73 if (localtime_r((const time_t *)&now, &ctm) == NULL) return 0;
74
75 ctm.tm_sec = 0;
76 ctm.tm_min = 0;
77 ctm.tm_hour = 0;
78
79 return mktime(&ctm);
80}
81
b5d655f7
A
82/*
83 * The base directory contains a data file which stores
84 * the last record ID.
85 *
86 * | MAX_ID (uint64_t) |
87 *
88 */
89uint32_t
90asl_store_open_write(const char *basedir, asl_store_t **s)
91{
92 asl_store_t *out;
b5d655f7 93 struct stat sb;
34e8f829
A
94 uint32_t i, flags;
95 char *path;
b5d655f7
A
96 FILE *sd;
97 uint64_t last_id;
34e8f829 98 time_t start;
b5d655f7
A
99
100 if (s == NULL) return ASL_STATUS_INVALID_ARG;
101
34e8f829
A
102 start = _asl_start_today();
103 if (start == 0) return ASL_STATUS_FAILED;
104
b5d655f7
A
105 if (basedir == NULL) basedir = PATH_ASL_STORE;
106
107 memset(&sb, 0, sizeof(struct stat));
108 if (stat(basedir, &sb) != 0) return ASL_STATUS_INVALID_STORE;
109 if ((sb.st_mode & S_IFDIR) == 0) return ASL_STATUS_INVALID_STORE;
110
111 path = NULL;
112 asprintf(&path, "%s/%s", basedir, FILE_ASL_STORE_DATA);
113 if (path == NULL) return ASL_STATUS_NO_MEMORY;
114
115 sd = NULL;
116
117 memset(&sb, 0, sizeof(struct stat));
118 if (stat(path, &sb) != 0)
119 {
120 if (errno != ENOENT)
121 {
122 free(path);
123 return ASL_STATUS_FAILED;
124 }
125
126 sd = fopen(path, "w+");
127 free(path);
128
129 if (sd == NULL) return ASL_STATUS_FAILED;
130
131 last_id = 0;
132
34e8f829
A
133 /* Create new StoreData file (8 bytes ID + 4 bytes flags) */
134
b5d655f7
A
135 if (fwrite(&last_id, sizeof(uint64_t), 1, sd) != 1)
136 {
137 fclose(sd);
138 return ASL_STATUS_WRITE_FAILED;
139 }
34e8f829
A
140
141 flags = 0;
142 if (fwrite(&flags, sizeof(uint32_t), 1, sd) != 1)
143 {
144 fclose(sd);
145 return ASL_STATUS_WRITE_FAILED;
146 }
b5d655f7
A
147 }
148 else
149 {
150 sd = fopen(path, "r+");
151 free(path);
152
153 if (sd == NULL) return ASL_STATUS_FAILED;
154 if (fread(&last_id, sizeof(uint64_t), 1, sd) != 1)
155 {
156 fclose(sd);
157 return ASL_STATUS_READ_FAILED;
158 }
159
160 last_id = asl_core_ntohq(last_id);
161 }
162
b5d655f7
A
163 out = (asl_store_t *)calloc(1, sizeof(asl_store_t));
164 if (out == NULL)
165 {
166 fclose(sd);
b5d655f7
A
167 return ASL_STATUS_NO_MEMORY;
168 }
169
170 if (basedir == NULL) out->base_dir = strdup(PATH_ASL_STORE);
171 else out->base_dir = strdup(basedir);
172
173 if (out->base_dir == NULL)
174 {
175 fclose(sd);
b5d655f7
A
176 free(out);
177 return ASL_STATUS_NO_MEMORY;
178 }
179
34e8f829 180 out->start_today = start;
b5d655f7 181 out->start_tomorrow = out->start_today + SECONDS_PER_DAY;
b5d655f7
A
182 out->storedata = sd;
183 out->next_id = last_id + 1;
184
185 for (i = 0; i < FILE_CACHE_SIZE; i++)
186 {
187 memset(&out->file_cache[i], 0, sizeof(asl_cached_file_t));
188 out->file_cache[i].u = -1;
189 out->file_cache[i].g = -1;
190 }
191
192 *s = out;
193 return ASL_STATUS_OK;
194}
195
196uint32_t
197asl_store_statistics(asl_store_t *s, aslmsg *msg)
198{
199 aslmsg out;
b5d655f7
A
200
201 if (s == NULL) return ASL_STATUS_INVALID_STORE;
202 if (msg == NULL) return ASL_STATUS_INVALID_ARG;
203
204 out = (aslmsg)calloc(1, sizeof(asl_msg_t));
205 if (out == NULL) return ASL_STATUS_NO_MEMORY;
206
34e8f829 207 /* does nothing for now */
b5d655f7
A
208
209 *msg = out;
210 return ASL_STATUS_OK;
211}
212
213uint32_t
214asl_store_open_read(const char *basedir, asl_store_t **s)
215{
216 asl_store_t *out;
217 struct stat sb;
218
219 if (s == NULL) return ASL_STATUS_INVALID_ARG;
220
221 if (basedir == NULL) basedir = PATH_ASL_STORE;
222
223 memset(&sb, 0, sizeof(struct stat));
224 if (stat(basedir, &sb) != 0) return ASL_STATUS_INVALID_STORE;
225 if ((sb.st_mode & S_IFDIR) == 0) return ASL_STATUS_INVALID_STORE;
226
227 out = (asl_store_t *)calloc(1, sizeof(asl_store_t));
228 if (out == NULL) return ASL_STATUS_NO_MEMORY;
229
230 if (basedir == NULL) out->base_dir = strdup(PATH_ASL_STORE);
231 else out->base_dir = strdup(basedir);
232
233 if (out->base_dir == NULL)
234 {
235 free(out);
236 return ASL_STATUS_NO_MEMORY;
237 }
238
239 *s = out;
240 return ASL_STATUS_OK;
241}
242
243uint32_t
244asl_store_max_file_size(asl_store_t *s, size_t max)
245{
246 if (s == NULL) return ASL_STATUS_INVALID_STORE;
247
248 s->max_file_size = max;
249 return ASL_STATUS_OK;
250}
251
252void
253asl_store_file_closeall(asl_store_t *s)
254{
255 uint32_t i;
256
257 if (s == NULL) return;
258
259 for (i = 0; i < FILE_CACHE_SIZE; i++)
260 {
261 if (s->file_cache[i].f != NULL) asl_file_close(s->file_cache[i].f);
262 s->file_cache[i].f = NULL;
263 if (s->file_cache[i].path != NULL) free(s->file_cache[i].path);
264 s->file_cache[i].path = NULL;
265 s->file_cache[i].u = -1;
266 s->file_cache[i].g = -1;
34e8f829 267 s->file_cache[i].bb = 0;
b5d655f7
A
268 s->file_cache[i].ts = 0;
269 }
270}
271
272uint32_t
273asl_store_close(asl_store_t *s)
274{
275 if (s == NULL) return ASL_STATUS_OK;
276
277 if (s->base_dir != NULL) free(s->base_dir);
278 s->base_dir = NULL;
b5d655f7
A
279 asl_store_file_closeall(s);
280 if (s->storedata != NULL) fclose(s->storedata);
281
282 free(s);
283
284 return ASL_STATUS_OK;
285}
286
287uint32_t
288asl_store_signal_sweep(asl_store_t *s)
289{
290 char *str;
291 int semfd;
34e8f829
A
292 uint64_t xid;
293 uint32_t status;
b5d655f7
A
294
295 if (s == NULL) return ASL_STATUS_INVALID_STORE;
296
297 asprintf(&str, "%s/%s", s->base_dir, FILE_ASL_STORE_SWEEP_SEMAPHORE);
298 if (str == NULL) return ASL_STATUS_NO_MEMORY;
299
300 semfd = open(str, O_WRONLY | O_CREAT | O_NONBLOCK, 0644);
301 free(str);
302
303 if (semfd < 0) return ASL_STATUS_WRITE_FAILED;
304
34e8f829
A
305 status = ASL_STATUS_OK;
306
307 /* write the current message ID in the SweepStore file */
308 xid = asl_core_htonq(s->next_id - 1);
309 if (write(semfd, &xid, sizeof(uint64_t)) != sizeof(uint64_t)) status = ASL_STATUS_WRITE_FAILED;
310
b5d655f7 311 close(semfd);
34e8f829 312 return status;
b5d655f7
A
313}
314
315/*
316 * Sweep the file cache.
317 * Close any files that have not been used in the last FILE_CACHE_TTL seconds.
318 * Returns least recently used or unused cache slot.
319 */
320static uint32_t
34e8f829 321asl_store_file_cache_lru(asl_store_t *s, time_t now, uint32_t ignorex)
b5d655f7
A
322{
323 time_t min;
324 uint32_t i, x;
325
326 if (s == NULL) return 0;
327
328 x = 0;
329 min = now - FILE_CACHE_TTL;
34e8f829 330
b5d655f7
A
331 for (i = 0; i < FILE_CACHE_SIZE; i++)
332 {
34e8f829 333 if ((i != ignorex) && (s->file_cache[i].ts < min))
b5d655f7
A
334 {
335 asl_file_close(s->file_cache[i].f);
336 s->file_cache[i].f = NULL;
337 if (s->file_cache[i].path != NULL) free(s->file_cache[i].path);
338 s->file_cache[i].path = NULL;
339 s->file_cache[i].u = -1;
340 s->file_cache[i].g = -1;
34e8f829
A
341 s->file_cache[i].bb = 0;
342 s->file_cache[i].ts = 0;
b5d655f7 343 }
34e8f829 344
b5d655f7
A
345 if (s->file_cache[i].ts < s->file_cache[x].ts) x = i;
346 }
347
348 return x;
349}
350
351uint32_t
352asl_store_sweep_file_cache(asl_store_t *s)
353{
354 if (s == NULL) return ASL_STATUS_INVALID_STORE;
355
34e8f829 356 asl_store_file_cache_lru(s, time(NULL), FILE_CACHE_SIZE);
b5d655f7
A
357 return ASL_STATUS_OK;
358}
359
360static uint32_t
34e8f829 361asl_store_file_open_write(asl_store_t *s, char *tstring, int32_t ruid, int32_t rgid, time_t bb, asl_file_t **f, time_t now, uint32_t check_cache)
b5d655f7
A
362{
363 char *path;
364 mode_t m;
365 int32_t i, x, u, g;
366 uint32_t status;
367 asl_file_t *out;
368
369 if (s == NULL) return ASL_STATUS_INVALID_STORE;
370
371 /* see if the file is already open and in the cache */
372 for (i = 0; i < FILE_CACHE_SIZE; i++)
373 {
34e8f829 374 if ((s->file_cache[i].u == ruid) && (s->file_cache[i].g == rgid) && (s->file_cache[i].bb == bb) && (s->file_cache[i].f != NULL))
b5d655f7
A
375 {
376 s->file_cache[i].ts = now;
377 *f = s->file_cache[i].f;
34e8f829 378 if (check_cache == 1) asl_store_file_cache_lru(s, now, i);
b5d655f7
A
379 return ASL_STATUS_OK;
380 }
381 }
382
383 path = NULL;
384 u = 0;
385 g = 0;
386 m = 0644;
387
388 if (ruid == -1)
389 {
390 if (rgid == -1)
391 {
34e8f829 392 asprintf(&path, "%s/%s.asl", s->base_dir, tstring);
b5d655f7
A
393 }
394 else
395 {
396 g = rgid;
397 m = 0640;
34e8f829 398 asprintf(&path, "%s/%s.G%d.asl", s->base_dir, tstring, g);
b5d655f7
A
399 }
400 }
401 else
402 {
403 u = ruid;
404 if (rgid == -1)
405 {
406 m = 0600;
34e8f829 407 asprintf(&path, "%s/%s.U%d.asl", s->base_dir, tstring, u);
b5d655f7
A
408 }
409 else
410 {
411 g = rgid;
412 m = 0640;
34e8f829 413 asprintf(&path, "%s/%s.U%d.G%u.asl", s->base_dir, tstring, u, g);
b5d655f7
A
414 }
415 }
416
417 if (path == NULL) return ASL_STATUS_NO_MEMORY;
418
419 out = NULL;
420 status = asl_file_open_write(path, m, u, g, &out);
421 if (status != ASL_STATUS_OK)
422 {
423 free(path);
424 return status;
425 }
426
34e8f829 427 x = asl_store_file_cache_lru(s, now, FILE_CACHE_SIZE);
b5d655f7
A
428 if (s->file_cache[x].f != NULL) asl_file_close(s->file_cache[x].f);
429 if (s->file_cache[x].path != NULL) free(s->file_cache[x].path);
430
431 s->file_cache[x].f = out;
432 s->file_cache[x].path = path;
433 s->file_cache[x].u = ruid;
434 s->file_cache[x].g = rgid;
34e8f829 435 s->file_cache[x].bb = bb;
b5d655f7
A
436 s->file_cache[x].ts = time(NULL);
437
438 *f = out;
439
440 return ASL_STATUS_OK;
441}
442
443char *
444asl_store_file_path(asl_store_t *s, asl_file_t *f)
445{
446 uint32_t i;
447
448 if (s == NULL) return NULL;
449
450 for (i = 0; i < FILE_CACHE_SIZE; i++)
451 {
452 if (s->file_cache[i].f == f)
453 {
454 if (s->file_cache[i].path == NULL) return NULL;
455 return strdup(s->file_cache[i].path);
456 }
457 }
458
459 return NULL;
460}
461
462void
463asl_store_file_close(asl_store_t *s, asl_file_t *f)
464{
465 uint32_t i;
466
467 if (s == NULL) return;
34e8f829 468 if (f == NULL) return;
b5d655f7
A
469
470 for (i = 0; i < FILE_CACHE_SIZE; i++)
471 {
472 if (s->file_cache[i].f == f)
473 {
474 asl_file_close(s->file_cache[i].f);
475 s->file_cache[i].f = NULL;
476 if (s->file_cache[i].path != NULL) free(s->file_cache[i].path);
477 s->file_cache[i].path = NULL;
478 s->file_cache[i].u = -1;
479 s->file_cache[i].g = -1;
34e8f829 480 s->file_cache[i].bb = 0;
b5d655f7
A
481 s->file_cache[i].ts = 0;
482 return;
483 }
484 }
485}
486
487uint32_t
488asl_store_save(asl_store_t *s, aslmsg msg)
489{
490 struct tm ctm;
34e8f829
A
491 time_t msg_time, now, bb;
492 char *path, *tmp_path, *tstring, *scratch;
b5d655f7
A
493 const char *val;
494 uid_t ruid;
495 gid_t rgid;
496 asl_file_t *f;
34e8f829 497 uint32_t status, check_cache, signal_sweep, len;
b5d655f7
A
498 uint64_t xid, ftime;
499 size_t fsize;
500
501 if (s == NULL) return ASL_STATUS_INVALID_STORE;
502 if (msg == NULL) return ASL_STATUS_INVALID_ARG;
503
504 now = time(NULL);
505
34e8f829
A
506 check_cache = 0;
507 if ((s->last_write + FILE_CACHE_TTL) <= now) check_cache = 1;
508
509 signal_sweep = 0;
510
511 msg_time = 0;
b5d655f7 512 val = asl_get(msg, ASL_KEY_TIME);
34e8f829
A
513 if (val == NULL) msg_time = now;
514 else msg_time = asl_parse_time(val);
b5d655f7 515
34e8f829 516 if (msg_time >= s->start_tomorrow)
b5d655f7
A
517 {
518 if (now >= s->start_tomorrow)
519 {
520 /* new day begins */
34e8f829
A
521 check_cache = 0;
522 signal_sweep = 1;
523 asl_store_file_closeall(s);
524
525 /*
526 * _asl_start_today should never fail, but if it does,
527 * just push forward one day. That will probably be correct, and if
528 * it isn't, the next message that gets saved will push it ahead again
529 * until we get to the right date.
530 */
531 s->start_today = _asl_start_today();
532 if (s->start_today == 0) s->start_today = s->start_tomorrow;
533
534 s->start_tomorrow = s->start_today + SECONDS_PER_DAY;
b5d655f7
A
535 }
536 }
537
538 val = asl_get(msg, ASL_KEY_READ_UID);
539 ruid = -1;
540 if (val != NULL) ruid = atoi(val);
541
542 val = asl_get(msg, ASL_KEY_READ_GID);
543 rgid = -1;
544 if (val != NULL) rgid = atoi(val);
545
34e8f829
A
546 bb = 0;
547 val = asl_get(msg, ASL_KEY_EXPIRE_TIME);
548 if (val != NULL)
549 {
550 bb = 1;
551 msg_time = asl_parse_time(val);
552 }
553
b5d655f7
A
554 if (fseeko(s->storedata, 0, SEEK_SET) != 0) return ASL_STATUS_WRITE_FAILED;
555
556 xid = asl_core_htonq(s->next_id);
557 if (fwrite(&xid, sizeof(uint64_t), 1, s->storedata) != 1) return ASL_STATUS_WRITE_FAILED;
558
559 xid = s->next_id;
560 s->next_id++;
561
b5d655f7 562 s->last_write = now;
34e8f829
A
563
564 if (localtime_r((const time_t *)&msg_time, &ctm) == NULL) return ASL_STATUS_FAILED;
565
566 tstring = NULL;
567 if (bb == 1)
b5d655f7 568 {
34e8f829
A
569 /*
570 * This supports 12 monthy "Best Before" buckets.
571 * We advance the actual expiry time to day zero of the following month.
572 * mktime() is clever enough to know that you actually mean the last day
573 * of the previous month. What we get back from localtime is the last
574 * day of the month in which the message expires, which we use in the name.
575 */
576 ctm.tm_sec = 0;
577 ctm.tm_min = 0;
578 ctm.tm_hour = 0;
579 ctm.tm_mday = 0;
580 ctm.tm_mon += 1;
581
582 bb = mktime(&ctm);
583
584 if (localtime_r((const time_t *)&bb, &ctm) == NULL) return ASL_STATUS_FAILED;
585 asprintf(&tstring, "BB.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
586 }
587 else
588 {
589 asprintf(&tstring, "%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
b5d655f7
A
590 }
591
34e8f829 592 if (tstring == NULL) return ASL_STATUS_NO_MEMORY;
b5d655f7 593
34e8f829
A
594 status = asl_store_file_open_write(s, tstring, ruid, rgid, bb, &f, now, check_cache);
595 free(tstring);
596 tstring = NULL;
b5d655f7
A
597
598 if (status != ASL_STATUS_OK) return status;
599
600 status = asl_file_save(f, msg, &xid);
601 if (status != ASL_STATUS_OK) return status;
602
603 fsize = asl_file_size(f);
604 ftime = asl_file_ctime(f);
605
34e8f829 606 /* if file is larger than max_file_size, rename it and touch semaphore file in the store */
b5d655f7
A
607 if ((s->max_file_size != 0) && (fsize > s->max_file_size))
608 {
34e8f829 609 signal_sweep = 1;
b5d655f7
A
610 status = ASL_STATUS_OK;
611
612 path = asl_store_file_path(s, f);
b5d655f7
A
613
614 asl_store_file_close(s, f);
615
616 if (path != NULL)
617 {
34e8f829
A
618 tmp_path = NULL;
619
620 len = strlen(path);
621 if ((len >= 4) && (!strcmp(path + len - 4, ".asl")))
622 {
623 /* rename xxxxxxx.asl to xxxxxxx.timestamp.asl */
624 scratch = strdup(path);
625 if (scratch != NULL)
626 {
627 scratch[len - 4] = '\0';
628 asprintf(&tmp_path, "%s.%llu.asl", scratch, ftime);
629 free(scratch);
630
631 }
632 }
633 else
634 {
635 /* append timestamp */
636 asprintf(&tmp_path, "%s.%llu", path, ftime);
637 }
638
639 if (tmp_path == NULL)
b5d655f7
A
640 {
641 status = ASL_STATUS_NO_MEMORY;
642 }
643 else
644 {
34e8f829
A
645 if (rename(path, tmp_path) != 0) status = ASL_STATUS_FAILED;
646 free(tmp_path);
b5d655f7
A
647 }
648
649 free(path);
650 }
b5d655f7
A
651 }
652
34e8f829
A
653 if (signal_sweep != 0) asl_store_signal_sweep(s);
654
b5d655f7
A
655 return status;
656}
657
658uint32_t
659asl_store_match_timeout(asl_store_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, uint32_t usec)
660{
661 DIR *dp;
662 struct dirent *dent;
663 uint32_t status;
664 asl_file_t *f;
665 char *path;
666 asl_file_list_t *files;
667
668 if (s == NULL) return ASL_STATUS_INVALID_STORE;
669 if (res == NULL) return ASL_STATUS_INVALID_ARG;
670
671 files = NULL;
672
673 /*
674 * Open all readable files
675 */
676 dp = opendir(s->base_dir);
677 if (dp == NULL) return ASL_STATUS_READ_FAILED;
678
679 while ((dent = readdir(dp)) != NULL)
680 {
681 if (dent->d_name[0] == '.') continue;
682
683 path = NULL;
684 asprintf(&path, "%s/%s", s->base_dir, dent->d_name);
685
686 /* NB asl_file_open_read will fail if path is NULL, if the file is not an ASL store file, or if it isn't readable */
687 status = asl_file_open_read(path, &f);
688 if (path != NULL) free(path);
689 if ((status != ASL_STATUS_OK) || (f == NULL)) continue;
690
691 files = asl_file_list_add(files, f);
692 }
693
694 closedir(dp);
695
696 status = asl_file_list_match_timeout(files, query, res, last_id, start_id, count, direction, usec);
697 asl_file_list_close(files);
698 return status;
699}
700
701uint32_t
702asl_store_match(asl_store_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction)
703{
704 return asl_store_match_timeout(s, query, res, last_id, start_id, count, direction, 0);
705}
706
707uint32_t
708asl_store_match_start(asl_store_t *s, uint64_t start_id, int32_t direction)
709{
710 DIR *dp;
711 struct dirent *dent;
712 uint32_t status;
713 asl_file_t *f;
714 char *path;
715 asl_file_list_t *files;
716
717 if (s == NULL) return ASL_STATUS_INVALID_STORE;
718
719 if (s->work != NULL) asl_file_list_match_end(s->work);
720 s->work = NULL;
721
722 files = NULL;
723
724 /*
725 * Open all readable files
726 */
727 dp = opendir(s->base_dir);
728 if (dp == NULL) return ASL_STATUS_READ_FAILED;
729
730 while ((dent = readdir(dp)) != NULL)
731 {
732 if (dent->d_name[0] == '.') continue;
733
734 path = NULL;
735 asprintf(&path, "%s/%s", s->base_dir, dent->d_name);
736
737 /* NB asl_file_open_read will fail if path is NULL, if the file is not an ASL store file, or if it isn't readable */
738 status = asl_file_open_read(path, &f);
739 if (path != NULL) free(path);
740 if ((status != ASL_STATUS_OK) || (f == NULL)) continue;
741
742 files = asl_file_list_add(files, f);
743 }
744
745 closedir(dp);
746
747 s->work = asl_file_list_match_start(files, start_id, direction);
748 if (s->work == NULL) return ASL_STATUS_FAILED;
749
750 return ASL_STATUS_OK;
751}
752
753uint32_t
754asl_store_match_next(asl_store_t *s, aslresponse query, aslresponse *res, uint32_t count)
755{
756 if (s == NULL) return ASL_STATUS_INVALID_STORE;
757 if (s->work == NULL) return ASL_STATUS_OK;
758
759 return asl_file_list_match_next(s->work, query, res, count);
760}