2 * Copyright (c) 2007-2011 Apple Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
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
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.
21 * @APPLE_LICENSE_HEADER_END@
29 #include <sys/types.h>
33 #include <asl_private.h>
35 #include <asl_store.h>
38 extern uint64_t asl_file_cursor(asl_file_t
*s
);
39 extern uint32_t asl_file_match_start(asl_file_t
*s
, uint64_t start_id
, int32_t direction
);
40 extern uint32_t asl_file_match_next(asl_file_t
*s
, asl_msg_list_t
*qlist
, asl_msg_t
**msg
, uint64_t *last_id
, int32_t direction
, int32_t ruid
, int32_t rgid
);
41 extern int asl_file_create(const char *path
, uid_t uid
, gid_t gid
, mode_t mode
);
43 #define SECONDS_PER_DAY 86400
46 * The ASL Store is organized as a set of files in a common directory.
47 * Files are prefixed by the date (YYYY.MM.DD) of their contents.
49 * Messages with no access controls are saved in YYYY.MM.DD.asl
50 * Messages with access limited to UID uuu are saved in YYYY.MM.DD.Uuuu.asl
51 * Messages with access limited to GID ggg are saved in YYYY.MM.DD.Gggg.asl
52 * Messages with access limited to UID uuu and GID ggg are saved in YYYY.MM.DD.Uuuu.Gggg.asl
54 * Messages that have a value for ASLExpireTime are saved in BB.YYYY.MM.DD.asl
55 * where the timestamp is the "Best Before" date of the file. Access controls
56 * are implemented as above with Uuuu and Gggg in the file name. Note that the
57 * Best Before files are for the last day of the month, so a single file contains
58 * messages that expire in that month.
60 * An external tool runs daily and deletes "old" files.
69 memset(&ctm
, 0, sizeof(struct tm
));
72 if (localtime_r((const time_t *)&now
, &ctm
) == NULL
) return 0;
82 * The base directory contains a data file which stores
85 * | MAX_ID (uint64_t) |
89 asl_store_open_write(const char *basedir
, asl_store_t
**s
)
99 if (s
== NULL
) return ASL_STATUS_INVALID_ARG
;
101 start
= _asl_start_today();
102 if (start
== 0) return ASL_STATUS_FAILED
;
104 if (basedir
== NULL
) basedir
= PATH_ASL_STORE
;
106 memset(&sb
, 0, sizeof(struct stat
));
107 if (stat(basedir
, &sb
) != 0) return ASL_STATUS_INVALID_STORE
;
108 if (!S_ISDIR(sb
.st_mode
)) return ASL_STATUS_INVALID_STORE
;
111 asprintf(&path
, "%s/%s", basedir
, FILE_ASL_STORE_DATA
);
112 if (path
== NULL
) return ASL_STATUS_NO_MEMORY
;
116 memset(&sb
, 0, sizeof(struct stat
));
117 if (stat(path
, &sb
) != 0)
122 return ASL_STATUS_FAILED
;
125 sd
= fopen(path
, "w+");
128 if (sd
== NULL
) return ASL_STATUS_FAILED
;
132 /* Create new StoreData file (8 bytes ID + 4 bytes flags) */
134 if (fwrite(&last_id
, sizeof(uint64_t), 1, sd
) != 1)
137 return ASL_STATUS_WRITE_FAILED
;
141 if (fwrite(&flags
, sizeof(uint32_t), 1, sd
) != 1)
144 return ASL_STATUS_WRITE_FAILED
;
152 sd
= fopen(path
, "r+");
155 if (sd
== NULL
) return ASL_STATUS_FAILED
;
156 if (fread(&last_id
, sizeof(uint64_t), 1, sd
) != 1)
159 return ASL_STATUS_READ_FAILED
;
162 last_id
= asl_core_ntohq(last_id
);
165 out
= (asl_store_t
*)calloc(1, sizeof(asl_store_t
));
169 return ASL_STATUS_NO_MEMORY
;
172 out
->asl_type
= ASL_TYPE_STORE
;
175 if (basedir
== NULL
) out
->base_dir
= strdup(PATH_ASL_STORE
);
176 else out
->base_dir
= strdup(basedir
);
178 if (out
->base_dir
== NULL
)
182 return ASL_STATUS_NO_MEMORY
;
185 out
->start_today
= start
;
186 out
->start_tomorrow
= out
->start_today
+ SECONDS_PER_DAY
;
188 out
->next_id
= last_id
+ 1;
190 for (i
= 0; i
< FILE_CACHE_SIZE
; i
++)
192 memset(&out
->file_cache
[i
], 0, sizeof(asl_cached_file_t
));
193 out
->file_cache
[i
].u
= -1;
194 out
->file_cache
[i
].g
= -1;
198 return ASL_STATUS_OK
;
202 asl_store_set_flags(asl_store_t
*s
, uint32_t flags
)
204 if (s
== NULL
) return 0;
205 uint32_t oldflags
= s
->flags
;
211 asl_store_statistics(asl_store_t
*s
, asl_msg_t
**msg
)
215 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
216 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
218 out
= asl_msg_new(ASL_TYPE_MSG
);
219 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
221 /* does nothing for now */
224 return ASL_STATUS_OK
;
228 asl_store_open_read(const char *basedir
, asl_store_t
**s
)
233 if (s
== NULL
) return ASL_STATUS_INVALID_ARG
;
235 if (basedir
== NULL
) basedir
= PATH_ASL_STORE
;
237 memset(&sb
, 0, sizeof(struct stat
));
238 if (stat(basedir
, &sb
) != 0) return ASL_STATUS_INVALID_STORE
;
239 if (!S_ISDIR(sb
.st_mode
)) return ASL_STATUS_INVALID_STORE
;
241 out
= (asl_store_t
*)calloc(1, sizeof(asl_store_t
));
242 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
244 out
->asl_type
= ASL_TYPE_STORE
;
247 if (basedir
== NULL
) out
->base_dir
= strdup(PATH_ASL_STORE
);
248 else out
->base_dir
= strdup(basedir
);
250 if (out
->base_dir
== NULL
)
253 return ASL_STATUS_NO_MEMORY
;
257 return ASL_STATUS_OK
;
261 asl_store_max_file_size(asl_store_t
*s
, size_t max
)
263 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
265 s
->max_file_size
= max
;
266 return ASL_STATUS_OK
;
269 __private_extern__
void
270 asl_store_file_closeall(asl_store_t
*s
)
274 if (s
== NULL
) return;
276 for (i
= 0; i
< FILE_CACHE_SIZE
; i
++)
278 if (s
->file_cache
[i
].f
!= NULL
) asl_file_close(s
->file_cache
[i
].f
);
279 s
->file_cache
[i
].f
= NULL
;
280 if (s
->file_cache
[i
].path
!= NULL
) free(s
->file_cache
[i
].path
);
281 s
->file_cache
[i
].path
= NULL
;
282 s
->file_cache
[i
].u
= -1;
283 s
->file_cache
[i
].g
= -1;
284 s
->file_cache
[i
].bb
= 0;
285 s
->file_cache
[i
].ts
= 0;
290 asl_store_retain(asl_store_t
*s
)
292 if (s
== NULL
) return NULL
;
293 asl_retain((asl_object_t
)s
);
298 asl_store_release(asl_store_t
*s
)
300 if (s
== NULL
) return;
301 asl_release((asl_object_t
)s
);
305 asl_store_close(asl_store_t
*s
)
307 if (s
== NULL
) return ASL_STATUS_OK
;
308 asl_release((asl_object_t
)s
);
309 return ASL_STATUS_OK
;
313 _asl_store_free_internal(asl_store_t
*s
)
315 if (s
== NULL
) return;
317 if (s
->base_dir
!= NULL
) free(s
->base_dir
);
319 asl_store_file_closeall(s
);
320 if (s
->storedata
!= NULL
) fclose(s
->storedata
);
326 * Sweep the file cache.
327 * Close any files that have not been used in the last FILE_CACHE_TTL seconds.
328 * Returns least recently used or unused cache slot.
331 asl_store_file_cache_lru(asl_store_t
*s
, time_t now
, uint32_t ignorex
)
336 if (s
== NULL
) return 0;
339 min
= now
- FILE_CACHE_TTL
;
341 for (i
= 0; i
< FILE_CACHE_SIZE
; i
++)
343 if ((i
!= ignorex
) && (s
->file_cache
[i
].ts
< min
))
345 asl_file_close(s
->file_cache
[i
].f
);
346 s
->file_cache
[i
].f
= NULL
;
347 if (s
->file_cache
[i
].path
!= NULL
) free(s
->file_cache
[i
].path
);
348 s
->file_cache
[i
].path
= NULL
;
349 s
->file_cache
[i
].u
= -1;
350 s
->file_cache
[i
].g
= -1;
351 s
->file_cache
[i
].bb
= 0;
352 s
->file_cache
[i
].ts
= 0;
355 if (s
->file_cache
[i
].ts
< s
->file_cache
[x
].ts
) x
= i
;
362 asl_store_sweep_file_cache(asl_store_t
*s
)
364 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
366 asl_store_file_cache_lru(s
, time(NULL
), FILE_CACHE_SIZE
);
367 return ASL_STATUS_OK
;
371 asl_store_make_ug_path(const char *dir
, const char *base
, const char *ext
, uid_t ruid
, gid_t rgid
, uid_t
*u
, gid_t
*g
, mode_t
*m
)
383 if (ext
== NULL
) asprintf(&path
, "%s/%s", dir
, base
);
384 else asprintf(&path
, "%s/%s.%s", dir
, base
, ext
);
390 if (ext
== NULL
) asprintf(&path
, "%s/%s.G%d", dir
, base
, *g
);
391 else asprintf(&path
, "%s/%s.G%d.%s", dir
, base
, *g
, ext
);
400 if (ext
== NULL
) asprintf(&path
, "%s/%s.U%d", dir
, base
, *u
);
401 else asprintf(&path
, "%s/%s.U%d.%s", dir
, base
, *u
, ext
);
407 if (ext
== NULL
) asprintf(&path
, "%s/%s.U%d.G%d", dir
, base
, *u
, *g
);
408 else asprintf(&path
, "%s/%s.U%d.G%u.%s", dir
, base
, *u
, *g
, ext
);
416 asl_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
)
426 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
428 /* see if the file is already open and in the cache */
429 for (i
= 0; i
< FILE_CACHE_SIZE
; i
++)
431 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
))
433 s
->file_cache
[i
].ts
= now
;
434 *f
= s
->file_cache
[i
].f
;
435 if (check_cache
== 1) asl_store_file_cache_lru(s
, now
, i
);
436 return ASL_STATUS_OK
;
443 path
= asl_store_make_ug_path(s
->base_dir
, tstring
, "asl", (uid_t
)ruid
, (gid_t
)rgid
, &u
, &g
, &m
);
444 if (path
== NULL
) return ASL_STATUS_NO_MEMORY
;
447 status
= asl_file_open_write(path
, m
, u
, g
, &out
);
448 if (status
!= ASL_STATUS_OK
)
454 x
= asl_store_file_cache_lru(s
, now
, FILE_CACHE_SIZE
);
455 if (s
->file_cache
[x
].f
!= NULL
) asl_file_close(s
->file_cache
[x
].f
);
456 if (s
->file_cache
[x
].path
!= NULL
) free(s
->file_cache
[x
].path
);
458 s
->file_cache
[x
].f
= out
;
459 s
->file_cache
[x
].path
= path
;
460 s
->file_cache
[x
].u
= ruid
;
461 s
->file_cache
[x
].g
= rgid
;
462 s
->file_cache
[x
].bb
= bb
;
463 s
->file_cache
[x
].ts
= time(NULL
);
467 return ASL_STATUS_OK
;
470 __private_extern__
char *
471 asl_store_file_path(asl_store_t
*s
, asl_file_t
*f
)
475 if (s
== NULL
) return NULL
;
477 for (i
= 0; i
< FILE_CACHE_SIZE
; i
++)
479 if (s
->file_cache
[i
].f
== f
)
481 if (s
->file_cache
[i
].path
== NULL
) return NULL
;
482 return strdup(s
->file_cache
[i
].path
);
489 __private_extern__
void
490 asl_store_file_close(asl_store_t
*s
, asl_file_t
*f
)
494 if (s
== NULL
) return;
495 if (f
== NULL
) return;
497 for (i
= 0; i
< FILE_CACHE_SIZE
; i
++)
499 if (s
->file_cache
[i
].f
== f
)
501 asl_file_close(s
->file_cache
[i
].f
);
502 s
->file_cache
[i
].f
= NULL
;
503 if (s
->file_cache
[i
].path
!= NULL
) free(s
->file_cache
[i
].path
);
504 s
->file_cache
[i
].path
= NULL
;
505 s
->file_cache
[i
].u
= -1;
506 s
->file_cache
[i
].g
= -1;
507 s
->file_cache
[i
].bb
= 0;
508 s
->file_cache
[i
].ts
= 0;
515 asl_store_save(asl_store_t
*s
, asl_msg_t
*msg
)
518 time_t msg_time
, now
, bb
;
519 char *path
, *tmp_path
, *tstring
, *scratch
;
524 uint32_t status
, check_cache
, trigger_aslmanager
, len
;
528 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
529 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
534 if ((s
->last_write
+ FILE_CACHE_TTL
) <= now
) check_cache
= 1;
536 trigger_aslmanager
= 0;
541 if (asl_msg_lookup(msg
, ASL_KEY_TIME
, &val
, NULL
) != 0) msg_time
= now
;
542 else if (val
== NULL
) msg_time
= now
;
543 else msg_time
= asl_core_parse_time(val
, NULL
);
545 if (msg_time
>= s
->start_tomorrow
)
547 if (now
>= s
->start_tomorrow
)
551 asl_store_file_closeall(s
);
554 * _asl_start_today should never fail, but if it does,
555 * just push forward one day. That will probably be correct, and if
556 * it isn't, the next message that gets saved will push it ahead again
557 * until we get to the right date.
559 s
->start_today
= _asl_start_today();
560 if (s
->start_today
== 0) s
->start_today
= s
->start_tomorrow
;
562 s
->start_tomorrow
= s
->start_today
+ SECONDS_PER_DAY
;
568 if ((s
->flags
& ASL_STORE_FLAG_NO_ACLS
) == 0)
571 if ((asl_msg_lookup(msg
, ASL_KEY_READ_UID
, &val
, NULL
) == 0) && (val
!= NULL
)) ruid
= atoi(val
);
574 if ((asl_msg_lookup(msg
, ASL_KEY_READ_GID
, &val
, NULL
) == 0) && (val
!= NULL
)) rgid
= atoi(val
);
578 if ((s
->flags
& ASL_STORE_FLAG_NO_TTL
) == 0)
581 if ((asl_msg_lookup(msg
, ASL_KEY_EXPIRE_TIME
, &val
, NULL
) == 0) && (val
!= NULL
))
584 msg_time
= asl_core_parse_time(val
, NULL
);
588 if (fseeko(s
->storedata
, 0, SEEK_SET
) != 0) return ASL_STATUS_WRITE_FAILED
;
590 xid
= asl_core_htonq(s
->next_id
);
591 if (fwrite(&xid
, sizeof(uint64_t), 1, s
->storedata
) != 1) return ASL_STATUS_WRITE_FAILED
;
594 fflush(s
->storedata
);
601 if (localtime_r((const time_t *)&msg_time
, &ctm
) == NULL
) return ASL_STATUS_FAILED
;
607 * This supports 12 monthly "Best Before" buckets.
608 * We advance the actual expiry time to day zero of the following month.
609 * mktime() is clever enough to know that you actually mean the last day
610 * of the previous month. What we get back from localtime is the last
611 * day of the month in which the message expires, which we use in the name.
621 if (localtime_r((const time_t *)&bb
, &ctm
) == NULL
) return ASL_STATUS_FAILED
;
622 asprintf(&tstring
, "BB.%d.%02d.%02d", ctm
.tm_year
+ 1900, ctm
.tm_mon
+ 1, ctm
.tm_mday
);
626 asprintf(&tstring
, "%d.%02d.%02d", ctm
.tm_year
+ 1900, ctm
.tm_mon
+ 1, ctm
.tm_mday
);
629 if (tstring
== NULL
) return ASL_STATUS_NO_MEMORY
;
631 status
= asl_store_file_open_write(s
, tstring
, ruid
, rgid
, bb
, &f
, now
, check_cache
);
635 if (status
!= ASL_STATUS_OK
) return status
;
637 status
= asl_file_save(f
, msg
, &xid
);
638 if (status
!= ASL_STATUS_OK
) return status
;
640 fsize
= asl_file_size(f
);
641 ftime
= asl_file_ctime(f
);
643 /* if file is larger than max_file_size, rename it and trigger aslmanager */
644 if ((s
->max_file_size
!= 0) && (fsize
> s
->max_file_size
))
646 trigger_aslmanager
= 1;
647 status
= ASL_STATUS_OK
;
649 path
= asl_store_file_path(s
, f
);
651 asl_store_file_close(s
, f
);
658 if ((len
>= 4) && (!strcmp(path
+ len
- 4, ".asl")))
660 /* rename xxxxxxx.asl to xxxxxxx.timestamp.asl */
661 scratch
= strdup(path
);
664 scratch
[len
- 4] = '\0';
665 asprintf(&tmp_path
, "%s.%llu.asl", scratch
, ftime
);
672 /* append timestamp */
673 asprintf(&tmp_path
, "%s.%llu", path
, ftime
);
676 if (tmp_path
== NULL
)
678 status
= ASL_STATUS_NO_MEMORY
;
682 if (rename(path
, tmp_path
) != 0) status
= ASL_STATUS_FAILED
;
690 if (trigger_aslmanager
!= 0) asl_trigger_aslmanager();
696 asl_store_mkdir(asl_store_t
*s
, const char *dir
, mode_t m
)
698 char *tstring
= NULL
;
702 asprintf(&tstring
, "%s/%s", s
->base_dir
, dir
);
703 if (tstring
== NULL
) return ASL_STATUS_NO_MEMORY
;
705 memset(&sb
, 0, sizeof(struct stat
));
706 status
= stat(tstring
, &sb
);
710 /* must be a directory */
711 if (!S_ISDIR(sb
.st_mode
))
714 return ASL_STATUS_INVALID_STORE
;
721 /* doesn't exist - create it */
722 if (mkdir(tstring
, m
) != 0)
725 return ASL_STATUS_WRITE_FAILED
;
730 /* stat failed for some other reason */
732 return ASL_STATUS_FAILED
;
737 return ASL_STATUS_OK
;
741 asl_store_open_aux(asl_store_t
*s
, asl_msg_t
*msg
, int *out_fd
, char **url
)
745 char *path
, *dir
, *tstring
;
754 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
755 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
756 if (out_fd
== NULL
) return ASL_STATUS_INVALID_ARG
;
757 if (url
== NULL
) return ASL_STATUS_INVALID_ARG
;
759 msg_time
= time(NULL
);
763 if ((s
->flags
& ASL_STORE_FLAG_NO_ACLS
) == 0)
766 if ((asl_msg_lookup(msg
, ASL_KEY_READ_UID
, &val
, NULL
) == 0) && (val
!= NULL
)) ruid
= atoi(val
);
769 if ((asl_msg_lookup(msg
, ASL_KEY_READ_GID
, &val
, NULL
) == 0) && (val
!= NULL
)) rgid
= atoi(val
);
773 if ((s
->flags
& ASL_STORE_FLAG_NO_TTL
) == 0)
776 if ((asl_msg_lookup(msg
, ASL_KEY_EXPIRE_TIME
, &val
, NULL
) == 0) && (val
!= NULL
))
779 msg_time
= asl_core_parse_time(val
, NULL
);
783 if (localtime_r((const time_t *)&msg_time
, &ctm
) == NULL
) return ASL_STATUS_FAILED
;
789 * This supports 12 monthly "Best Before" buckets.
790 * We advance the actual expiry time to day zero of the following month.
791 * mktime() is clever enough to know that you actually mean the last day
792 * of the previous month. What we get back from localtime is the last
793 * day of the month in which the message expires, which we use in the name.
803 if (localtime_r((const time_t *)&bb
, &ctm
) == NULL
) return ASL_STATUS_FAILED
;
804 asprintf(&dir
, "BB.AUX.%d.%02d.%02d", ctm
.tm_year
+ 1900, ctm
.tm_mon
+ 1, ctm
.tm_mday
);
808 asprintf(&dir
, "AUX.%d.%02d.%02d", ctm
.tm_year
+ 1900, ctm
.tm_mon
+ 1, ctm
.tm_mday
);
811 if (dir
== NULL
) return ASL_STATUS_NO_MEMORY
;
813 status
= asl_store_mkdir(s
, dir
, 0755);
814 if (status
!= ASL_STATUS_OK
)
824 asprintf(&tstring
, "%s/%llu", dir
, fid
);
826 if (tstring
== NULL
) return ASL_STATUS_NO_MEMORY
;
831 path
= asl_store_make_ug_path(s
->base_dir
, tstring
, NULL
, ruid
, rgid
, &u
, &g
, &m
);
833 if (path
== NULL
) return ASL_STATUS_NO_MEMORY
;
835 fd
= asl_file_create(path
, u
, g
, m
);
840 return ASL_STATUS_WRITE_FAILED
;
843 /* URL is file://<path> */
845 asprintf(url
, "file://%s", path
);
854 asl_store_match(asl_store_t
*s
, asl_msg_list_t
*qlist
, uint64_t *last_id
, uint64_t start_id
, uint32_t count
, uint32_t duration
, int32_t direction
)
861 asl_file_list_t
*files
;
864 if (s
== NULL
) return NULL
;
869 * Open all readable files
871 dp
= opendir(s
->base_dir
);
872 if (dp
== NULL
) return NULL
;
874 while ((dent
= readdir(dp
)) != NULL
)
876 if (dent
->d_name
[0] == '.') continue;
879 asprintf(&path
, "%s/%s", s
->base_dir
, dent
->d_name
);
881 /* 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 */
882 status
= asl_file_open_read(path
, &f
);
883 if (path
!= NULL
) free(path
);
884 if ((status
!= ASL_STATUS_OK
) || (f
== NULL
)) continue;
886 files
= asl_file_list_add(files
, f
);
891 res
= asl_file_list_match(files
, qlist
, last_id
, start_id
, count
, duration
, direction
);
892 asl_file_list_close(files
);
897 * PRIVATE FOR DEV TOOLS SUPPORT
898 * DO NOT USE THIS INTERFACE OTHERWISE
900 * This is only called by a client that compiled with a 10.9 SDK, but is running
901 * with an new 10.10 libasl.
903 * Only searches the ASL database, so the store (first parameter) is ignored.
905 * The query and result are old-style message lists.
916 asl_store_match_timeout(void *ignored
, void *query_v1
, void **result_v1
, uint64_t *last_id
, uint64_t start_id
, uint32_t count
, int32_t direction
, uint32_t usec
)
918 asl_store_t
*asldb
= NULL
;
919 asl_msg_list_v1_t
*listv1
;
920 asl_msg_list_t
*qlist
= NULL
;
923 if (result_v1
== NULL
) return ASL_STATUS_FAILED
;
926 status
= asl_store_open_read(NULL
, &asldb
);
927 if (status
!= ASL_STATUS_OK
) return status
;
929 /* convert query_v1 into an asl_msg_list_t */
930 listv1
= (asl_msg_list_v1_t
*)query_v1
;
933 if (listv1
->count
> 0) qlist
= (asl_msg_list_t
*)asl_new(ASL_TYPE_LIST
);
935 for (listv1
->curr
= 0; listv1
->curr
< listv1
->count
; listv1
->curr
++)
937 asl_append((asl_object_t
)qlist
, (asl_object_t
)listv1
->msg
[listv1
->curr
]);
941 asl_msg_list_t
*result
= asl_store_match(asldb
, qlist
, last_id
, start_id
, count
, usec
, direction
);
942 asl_release((asl_object_t
)asldb
);
943 asl_release((asl_object_t
)qlist
);
945 if (result
== NULL
) return ASL_STATUS_OK
;
947 n
= asl_count((asl_object_t
)result
);
950 asl_release((asl_object_t
)result
);
951 return ASL_STATUS_OK
;
954 listv1
= (asl_msg_list_v1_t
*)calloc(1, sizeof(asl_msg_list_v1_t
));
957 asl_release((asl_object_t
)result
);
958 return ASL_STATUS_NO_MEMORY
;
962 listv1
->msg
= (void **)calloc(listv1
->count
, sizeof(void *));
966 asl_release((asl_object_t
)result
);
967 return ASL_STATUS_NO_MEMORY
;
970 for (listv1
->curr
= 0; listv1
->curr
< listv1
->count
; listv1
->curr
++)
972 listv1
->msg
[listv1
->curr
] = asl_retain(asl_next((asl_object_t
)result
));
978 asl_release((asl_object_t
)result
);
979 return ASL_STATUS_OK
;
983 asl_store_match_start(asl_store_t
*s
, uint64_t start_id
, int32_t direction
)
990 asl_file_list_t
*files
;
992 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
994 if (s
->work
!= NULL
) asl_file_list_match_end(s
->work
);
1000 * Open all readable files
1002 dp
= opendir(s
->base_dir
);
1003 if (dp
== NULL
) return ASL_STATUS_READ_FAILED
;
1005 while ((dent
= readdir(dp
)) != NULL
)
1007 if (dent
->d_name
[0] == '.') continue;
1010 asprintf(&path
, "%s/%s", s
->base_dir
, dent
->d_name
);
1013 * NB asl_file_open_read will fail if path is NULL,
1014 * if it is not an ASL store file, or if it isn't readable.
1017 status
= asl_file_open_read(path
, &f
);
1018 if (path
!= NULL
) free(path
);
1019 if ((status
!= ASL_STATUS_OK
) || (f
== NULL
)) continue;
1021 files
= asl_file_list_add(files
, f
);
1026 s
->work
= asl_file_list_match_start(files
, start_id
, direction
);
1027 if (s
->work
== NULL
) return ASL_STATUS_FAILED
;
1029 return ASL_STATUS_OK
;
1033 asl_store_match_next(asl_store_t
*s
, asl_msg_list_t
*qlist
, asl_msg_list_t
**res
, uint32_t count
)
1035 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1036 if (s
->work
== NULL
) return ASL_STATUS_OK
;
1038 return asl_file_list_match_next(s
->work
, qlist
, res
, count
);
1042 #pragma mark asl_object support
1045 _jump_dealloc(asl_object_private_t
*obj
)
1047 _asl_store_free_internal((asl_store_t
*)obj
);
1050 static asl_object_private_t
*
1051 _jump_next(asl_object_private_t
*obj
)
1053 asl_store_t
*s
= (asl_store_t
*)obj
;
1054 asl_msg_list_t
*list
;
1055 asl_msg_t
*out
= NULL
;
1058 if (s
== NULL
) return NULL
;
1059 if (s
->curr
== SIZE_MAX
) return NULL
;
1062 list
= asl_store_match(s
, NULL
, &last
, s
->curr
, 1, 0, 1);
1070 out
= asl_msg_list_get_index(list
, 0);
1071 asl_msg_list_release(list
);
1073 return (asl_object_private_t
*)out
;
1076 static asl_object_private_t
*
1077 _jump_prev(asl_object_private_t
*obj
)
1079 asl_store_t
*s
= (asl_store_t
*)obj
;
1080 asl_msg_list_t
*list
;
1081 asl_msg_t
*out
= NULL
;
1084 if (s
== NULL
) return NULL
;
1085 if (s
->curr
== 0) return NULL
;
1088 if (s
->curr
== 0) return NULL
;
1090 list
= asl_store_match(s
, NULL
, &last
, s
->curr
, 1, 0, -1);
1098 out
= asl_msg_list_get_index(list
, 0);
1099 asl_msg_list_release(list
);
1101 return (asl_object_private_t
*)out
;
1105 _jump_set_iteration_index(asl_object_private_t
*obj
, size_t n
)
1107 asl_store_t
*s
= (asl_store_t
*)obj
;
1108 if (s
== NULL
) return;
1114 _jump_append(asl_object_private_t
*obj
, asl_object_private_t
*newobj
)
1116 asl_store_t
*s
= (asl_store_t
*)obj
;
1117 int type
= asl_get_type((asl_object_t
)newobj
);
1118 if (s
== NULL
) return;
1119 if (s
->flags
& ASL_FILE_FLAG_READ
) return;
1121 if (type
== ASL_TYPE_LIST
)
1124 asl_msg_list_reset_iteration((asl_msg_list_t
*)newobj
, 0);
1125 while (NULL
!= (msg
= asl_msg_list_next((asl_msg_list_t
*)newobj
)))
1127 if (asl_store_save(s
, msg
) != ASL_STATUS_OK
) return;
1130 else if ((type
== ASL_TYPE_MSG
) || (type
== ASL_TYPE_QUERY
))
1132 asl_store_save(s
, (asl_msg_t
*)newobj
);
1136 static asl_object_private_t
*
1137 _jump_search(asl_object_private_t
*obj
, asl_object_private_t
*query
)
1139 asl_store_t
*s
= (asl_store_t
*)obj
;
1140 int type
= asl_get_type((asl_object_t
)query
);
1141 asl_msg_list_t
*out
= NULL
;
1142 asl_msg_list_t
*ql
= NULL
;
1144 uint32_t status
= ASL_STATUS_FAILED
;
1148 out
= asl_store_match(s
, NULL
, &last
, 0, 0, 0, 1);
1150 else if (type
== ASL_TYPE_LIST
)
1152 out
= asl_store_match(s
, (asl_msg_list_t
*)query
, &last
, 0, 0, 0, 1);
1154 else if ((type
== ASL_TYPE_MSG
) || (type
== ASL_TYPE_QUERY
))
1156 ql
= asl_msg_list_new();
1157 asl_msg_list_append(ql
, query
);
1159 out
= asl_store_match(s
, ql
, &last
, 0, 0, 0, 1);
1160 asl_msg_list_release(ql
);
1163 if (status
!= ASL_STATUS_OK
) return NULL
;
1164 return (asl_object_private_t
*)out
;
1167 static asl_object_private_t
*
1168 _jump_match(asl_object_private_t
*obj
, asl_object_private_t
*qlist
, size_t *last
, size_t start
, size_t count
, uint32_t duration
, int32_t dir
)
1171 asl_msg_list_t
*out
;
1173 out
= asl_store_match((asl_store_t
*)obj
, (asl_msg_list_t
*)qlist
, &x
, start
, count
, duration
, dir
);
1175 return (asl_object_private_t
*)out
;
1178 __private_extern__
const asl_jump_table_t
*
1179 asl_store_jump_table()
1181 static const asl_jump_table_t jump
=
1184 .dealloc
= &_jump_dealloc
,
1185 .set_key_val_op
= NULL
,
1187 .get_val_op_for_key
= NULL
,
1188 .get_key_val_op_at_index
= NULL
,
1190 .next
= &_jump_next
,
1191 .prev
= &_jump_prev
,
1192 .get_object_at_index
= NULL
,
1193 .set_iteration_index
= &_jump_set_iteration_index
,
1194 .remove_object_at_index
= NULL
,
1195 .append
= &_jump_append
,
1197 .search
= &_jump_search
,
1198 .match
= &_jump_match