2 * Copyright (c) 2007-2010 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 time_t asl_parse_time(const char *str
);
39 extern uint64_t asl_file_cursor(asl_file_t
*s
);
40 extern uint32_t asl_file_match_start(asl_file_t
*s
, uint64_t start_id
, int32_t direction
);
41 extern 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
);
42 extern int asl_file_create(const char *path
, uid_t uid
, gid_t gid
, mode_t mode
);
44 #define SECONDS_PER_DAY 86400
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.
50 * Messages with no access controls are saved in YYYY.MM.DD.asl
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
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.
61 * An external tool runs daily and deletes "old" files.
70 memset(&ctm
, 0, sizeof(struct tm
));
73 if (localtime_r((const time_t *)&now
, &ctm
) == NULL
) return 0;
83 * The base directory contains a data file which stores
86 * | MAX_ID (uint64_t) |
90 asl_store_open_write(const char *basedir
, asl_store_t
**s
)
100 if (s
== NULL
) return ASL_STATUS_INVALID_ARG
;
102 start
= _asl_start_today();
103 if (start
== 0) return ASL_STATUS_FAILED
;
105 if (basedir
== NULL
) basedir
= PATH_ASL_STORE
;
107 memset(&sb
, 0, sizeof(struct stat
));
108 if (stat(basedir
, &sb
) != 0) return ASL_STATUS_INVALID_STORE
;
109 if (!S_ISDIR(sb
.st_mode
)) return ASL_STATUS_INVALID_STORE
;
112 asprintf(&path
, "%s/%s", basedir
, FILE_ASL_STORE_DATA
);
113 if (path
== NULL
) return ASL_STATUS_NO_MEMORY
;
117 memset(&sb
, 0, sizeof(struct stat
));
118 if (stat(path
, &sb
) != 0)
123 return ASL_STATUS_FAILED
;
126 sd
= fopen(path
, "w+");
129 if (sd
== NULL
) return ASL_STATUS_FAILED
;
133 /* Create new StoreData file (8 bytes ID + 4 bytes flags) */
135 if (fwrite(&last_id
, sizeof(uint64_t), 1, sd
) != 1)
138 return ASL_STATUS_WRITE_FAILED
;
142 if (fwrite(&flags
, sizeof(uint32_t), 1, sd
) != 1)
145 return ASL_STATUS_WRITE_FAILED
;
153 sd
= fopen(path
, "r+");
156 if (sd
== NULL
) return ASL_STATUS_FAILED
;
157 if (fread(&last_id
, sizeof(uint64_t), 1, sd
) != 1)
160 return ASL_STATUS_READ_FAILED
;
163 last_id
= asl_core_ntohq(last_id
);
166 out
= (asl_store_t
*)calloc(1, sizeof(asl_store_t
));
170 return ASL_STATUS_NO_MEMORY
;
173 if (basedir
== NULL
) out
->base_dir
= strdup(PATH_ASL_STORE
);
174 else out
->base_dir
= strdup(basedir
);
176 if (out
->base_dir
== NULL
)
180 return ASL_STATUS_NO_MEMORY
;
183 out
->start_today
= start
;
184 out
->start_tomorrow
= out
->start_today
+ SECONDS_PER_DAY
;
186 out
->next_id
= last_id
+ 1;
188 for (i
= 0; i
< FILE_CACHE_SIZE
; i
++)
190 memset(&out
->file_cache
[i
], 0, sizeof(asl_cached_file_t
));
191 out
->file_cache
[i
].u
= -1;
192 out
->file_cache
[i
].g
= -1;
196 return ASL_STATUS_OK
;
200 asl_store_statistics(asl_store_t
*s
, aslmsg
*msg
)
204 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
205 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
207 out
= asl_new(ASL_TYPE_MSG
);
208 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
210 /* does nothing for now */
213 return ASL_STATUS_OK
;
217 asl_store_open_read(const char *basedir
, asl_store_t
**s
)
222 if (s
== NULL
) return ASL_STATUS_INVALID_ARG
;
224 if (basedir
== NULL
) basedir
= PATH_ASL_STORE
;
226 memset(&sb
, 0, sizeof(struct stat
));
227 if (stat(basedir
, &sb
) != 0) return ASL_STATUS_INVALID_STORE
;
228 if (!S_ISDIR(sb
.st_mode
)) return ASL_STATUS_INVALID_STORE
;
230 out
= (asl_store_t
*)calloc(1, sizeof(asl_store_t
));
231 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
233 if (basedir
== NULL
) out
->base_dir
= strdup(PATH_ASL_STORE
);
234 else out
->base_dir
= strdup(basedir
);
236 if (out
->base_dir
== NULL
)
239 return ASL_STATUS_NO_MEMORY
;
243 return ASL_STATUS_OK
;
247 asl_store_max_file_size(asl_store_t
*s
, size_t max
)
249 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
251 s
->max_file_size
= max
;
252 return ASL_STATUS_OK
;
255 __private_extern__
void
256 asl_store_file_closeall(asl_store_t
*s
)
260 if (s
== NULL
) return;
262 for (i
= 0; i
< FILE_CACHE_SIZE
; i
++)
264 if (s
->file_cache
[i
].f
!= NULL
) asl_file_close(s
->file_cache
[i
].f
);
265 s
->file_cache
[i
].f
= NULL
;
266 if (s
->file_cache
[i
].path
!= NULL
) free(s
->file_cache
[i
].path
);
267 s
->file_cache
[i
].path
= NULL
;
268 s
->file_cache
[i
].u
= -1;
269 s
->file_cache
[i
].g
= -1;
270 s
->file_cache
[i
].bb
= 0;
271 s
->file_cache
[i
].ts
= 0;
276 asl_store_close(asl_store_t
*s
)
278 if (s
== NULL
) return ASL_STATUS_OK
;
280 if (s
->base_dir
!= NULL
) free(s
->base_dir
);
282 asl_store_file_closeall(s
);
283 if (s
->storedata
!= NULL
) fclose(s
->storedata
);
287 return ASL_STATUS_OK
;
291 asl_store_signal_sweep(asl_store_t
*s
)
298 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
300 asprintf(&str
, "%s/%s", s
->base_dir
, FILE_ASL_STORE_SWEEP_SEMAPHORE
);
301 if (str
== NULL
) return ASL_STATUS_NO_MEMORY
;
303 semfd
= open(str
, O_WRONLY
| O_CREAT
| O_NONBLOCK
, 0644);
306 if (semfd
< 0) return ASL_STATUS_WRITE_FAILED
;
308 status
= ASL_STATUS_OK
;
310 /* write the current message ID in the SweepStore file */
311 xid
= asl_core_htonq(s
->next_id
- 1);
312 if (write(semfd
, &xid
, sizeof(uint64_t)) != sizeof(uint64_t)) status
= ASL_STATUS_WRITE_FAILED
;
319 * Sweep the file cache.
320 * Close any files that have not been used in the last FILE_CACHE_TTL seconds.
321 * Returns least recently used or unused cache slot.
324 asl_store_file_cache_lru(asl_store_t
*s
, time_t now
, uint32_t ignorex
)
329 if (s
== NULL
) return 0;
332 min
= now
- FILE_CACHE_TTL
;
334 for (i
= 0; i
< FILE_CACHE_SIZE
; i
++)
336 if ((i
!= ignorex
) && (s
->file_cache
[i
].ts
< min
))
338 asl_file_close(s
->file_cache
[i
].f
);
339 s
->file_cache
[i
].f
= NULL
;
340 if (s
->file_cache
[i
].path
!= NULL
) free(s
->file_cache
[i
].path
);
341 s
->file_cache
[i
].path
= NULL
;
342 s
->file_cache
[i
].u
= -1;
343 s
->file_cache
[i
].g
= -1;
344 s
->file_cache
[i
].bb
= 0;
345 s
->file_cache
[i
].ts
= 0;
348 if (s
->file_cache
[i
].ts
< s
->file_cache
[x
].ts
) x
= i
;
355 asl_store_sweep_file_cache(asl_store_t
*s
)
357 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
359 asl_store_file_cache_lru(s
, time(NULL
), FILE_CACHE_SIZE
);
360 return ASL_STATUS_OK
;
364 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
)
376 if (ext
== NULL
) asprintf(&path
, "%s/%s", dir
, base
);
377 else asprintf(&path
, "%s/%s.%s", dir
, base
, ext
);
383 if (ext
== NULL
) asprintf(&path
, "%s/%s.G%d", dir
, base
, *g
);
384 else asprintf(&path
, "%s/%s.G%d.%s", dir
, base
, *g
, ext
);
393 if (ext
== NULL
) asprintf(&path
, "%s/%s.U%d", dir
, base
, *u
);
394 else asprintf(&path
, "%s/%s.U%d.%s", dir
, base
, *u
, ext
);
400 if (ext
== NULL
) asprintf(&path
, "%s/%s.U%d.G%d", dir
, base
, *u
, *g
);
401 else asprintf(&path
, "%s/%s.U%d.G%u.%s", dir
, base
, *u
, *g
, ext
);
409 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
)
419 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
421 /* see if the file is already open and in the cache */
422 for (i
= 0; i
< FILE_CACHE_SIZE
; i
++)
424 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
))
426 s
->file_cache
[i
].ts
= now
;
427 *f
= s
->file_cache
[i
].f
;
428 if (check_cache
== 1) asl_store_file_cache_lru(s
, now
, i
);
429 return ASL_STATUS_OK
;
436 path
= asl_store_make_ug_path(s
->base_dir
, tstring
, "asl", (uid_t
)ruid
, (gid_t
)rgid
, &u
, &g
, &m
);
437 if (path
== NULL
) return ASL_STATUS_NO_MEMORY
;
440 status
= asl_file_open_write(path
, m
, u
, g
, &out
);
441 if (status
!= ASL_STATUS_OK
)
447 x
= asl_store_file_cache_lru(s
, now
, FILE_CACHE_SIZE
);
448 if (s
->file_cache
[x
].f
!= NULL
) asl_file_close(s
->file_cache
[x
].f
);
449 if (s
->file_cache
[x
].path
!= NULL
) free(s
->file_cache
[x
].path
);
451 s
->file_cache
[x
].f
= out
;
452 s
->file_cache
[x
].path
= path
;
453 s
->file_cache
[x
].u
= ruid
;
454 s
->file_cache
[x
].g
= rgid
;
455 s
->file_cache
[x
].bb
= bb
;
456 s
->file_cache
[x
].ts
= time(NULL
);
460 return ASL_STATUS_OK
;
463 __private_extern__
char *
464 asl_store_file_path(asl_store_t
*s
, asl_file_t
*f
)
468 if (s
== NULL
) return NULL
;
470 for (i
= 0; i
< FILE_CACHE_SIZE
; i
++)
472 if (s
->file_cache
[i
].f
== f
)
474 if (s
->file_cache
[i
].path
== NULL
) return NULL
;
475 return strdup(s
->file_cache
[i
].path
);
482 __private_extern__
void
483 asl_store_file_close(asl_store_t
*s
, asl_file_t
*f
)
487 if (s
== NULL
) return;
488 if (f
== NULL
) return;
490 for (i
= 0; i
< FILE_CACHE_SIZE
; i
++)
492 if (s
->file_cache
[i
].f
== f
)
494 asl_file_close(s
->file_cache
[i
].f
);
495 s
->file_cache
[i
].f
= NULL
;
496 if (s
->file_cache
[i
].path
!= NULL
) free(s
->file_cache
[i
].path
);
497 s
->file_cache
[i
].path
= NULL
;
498 s
->file_cache
[i
].u
= -1;
499 s
->file_cache
[i
].g
= -1;
500 s
->file_cache
[i
].bb
= 0;
501 s
->file_cache
[i
].ts
= 0;
508 asl_store_save(asl_store_t
*s
, aslmsg msg
)
511 time_t msg_time
, now
, bb
;
512 char *path
, *tmp_path
, *tstring
, *scratch
;
517 uint32_t status
, check_cache
, signal_sweep
, len
;
521 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
522 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
527 if ((s
->last_write
+ FILE_CACHE_TTL
) <= now
) check_cache
= 1;
532 val
= asl_get(msg
, ASL_KEY_TIME
);
533 if (val
== NULL
) msg_time
= now
;
534 else msg_time
= asl_parse_time(val
);
536 if (msg_time
>= s
->start_tomorrow
)
538 if (now
>= s
->start_tomorrow
)
543 asl_store_file_closeall(s
);
546 * _asl_start_today should never fail, but if it does,
547 * just push forward one day. That will probably be correct, and if
548 * it isn't, the next message that gets saved will push it ahead again
549 * until we get to the right date.
551 s
->start_today
= _asl_start_today();
552 if (s
->start_today
== 0) s
->start_today
= s
->start_tomorrow
;
554 s
->start_tomorrow
= s
->start_today
+ SECONDS_PER_DAY
;
558 val
= asl_get(msg
, ASL_KEY_READ_UID
);
560 if (val
!= NULL
) ruid
= atoi(val
);
562 val
= asl_get(msg
, ASL_KEY_READ_GID
);
564 if (val
!= NULL
) rgid
= atoi(val
);
567 val
= asl_get(msg
, ASL_KEY_EXPIRE_TIME
);
571 msg_time
= asl_parse_time(val
);
574 if (fseeko(s
->storedata
, 0, SEEK_SET
) != 0) return ASL_STATUS_WRITE_FAILED
;
576 xid
= asl_core_htonq(s
->next_id
);
577 if (fwrite(&xid
, sizeof(uint64_t), 1, s
->storedata
) != 1) return ASL_STATUS_WRITE_FAILED
;
580 fflush(s
->storedata
);
587 if (localtime_r((const time_t *)&msg_time
, &ctm
) == NULL
) return ASL_STATUS_FAILED
;
593 * This supports 12 monthly "Best Before" buckets.
594 * We advance the actual expiry time to day zero of the following month.
595 * mktime() is clever enough to know that you actually mean the last day
596 * of the previous month. What we get back from localtime is the last
597 * day of the month in which the message expires, which we use in the name.
607 if (localtime_r((const time_t *)&bb
, &ctm
) == NULL
) return ASL_STATUS_FAILED
;
608 asprintf(&tstring
, "BB.%d.%02d.%02d", ctm
.tm_year
+ 1900, ctm
.tm_mon
+ 1, ctm
.tm_mday
);
612 asprintf(&tstring
, "%d.%02d.%02d", ctm
.tm_year
+ 1900, ctm
.tm_mon
+ 1, ctm
.tm_mday
);
615 if (tstring
== NULL
) return ASL_STATUS_NO_MEMORY
;
617 status
= asl_store_file_open_write(s
, tstring
, ruid
, rgid
, bb
, &f
, now
, check_cache
);
621 if (status
!= ASL_STATUS_OK
) return status
;
623 status
= asl_file_save(f
, msg
, &xid
);
624 if (status
!= ASL_STATUS_OK
) return status
;
626 fsize
= asl_file_size(f
);
627 ftime
= asl_file_ctime(f
);
629 /* if file is larger than max_file_size, rename it and touch semaphore file in the store */
630 if ((s
->max_file_size
!= 0) && (fsize
> s
->max_file_size
))
633 status
= ASL_STATUS_OK
;
635 path
= asl_store_file_path(s
, f
);
637 asl_store_file_close(s
, f
);
644 if ((len
>= 4) && (!strcmp(path
+ len
- 4, ".asl")))
646 /* rename xxxxxxx.asl to xxxxxxx.timestamp.asl */
647 scratch
= strdup(path
);
650 scratch
[len
- 4] = '\0';
651 asprintf(&tmp_path
, "%s.%llu.asl", scratch
, ftime
);
658 /* append timestamp */
659 asprintf(&tmp_path
, "%s.%llu", path
, ftime
);
662 if (tmp_path
== NULL
)
664 status
= ASL_STATUS_NO_MEMORY
;
668 if (rename(path
, tmp_path
) != 0) status
= ASL_STATUS_FAILED
;
676 if (signal_sweep
!= 0) asl_store_signal_sweep(s
);
682 asl_store_mkdir(asl_store_t
*s
, const char *dir
, mode_t m
)
684 char *tstring
= NULL
;
688 asprintf(&tstring
, "%s/%s", s
->base_dir
, dir
);
689 if (tstring
== NULL
) return ASL_STATUS_NO_MEMORY
;
691 memset(&sb
, 0, sizeof(struct stat
));
692 status
= stat(tstring
, &sb
);
696 /* must be a directory */
697 if (!S_ISDIR(sb
.st_mode
))
700 return ASL_STATUS_INVALID_STORE
;
707 /* doesn't exist - create it */
708 if (mkdir(tstring
, m
) != 0)
711 return ASL_STATUS_WRITE_FAILED
;
716 /* stat failed for some other reason */
718 return ASL_STATUS_FAILED
;
723 return ASL_STATUS_OK
;
727 asl_store_open_aux(asl_store_t
*s
, aslmsg msg
, int *out_fd
, char **url
)
731 char *path
, *dir
, *tstring
;
740 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
741 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
742 if (out_fd
== NULL
) return ASL_STATUS_INVALID_ARG
;
743 if (url
== NULL
) return ASL_STATUS_INVALID_ARG
;
745 msg_time
= time(NULL
);
747 val
= asl_get(msg
, ASL_KEY_READ_UID
);
749 if (val
!= NULL
) ruid
= atoi(val
);
751 val
= asl_get(msg
, ASL_KEY_READ_GID
);
753 if (val
!= NULL
) rgid
= atoi(val
);
756 val
= asl_get(msg
, ASL_KEY_EXPIRE_TIME
);
760 msg_time
= asl_parse_time(val
);
763 if (localtime_r((const time_t *)&msg_time
, &ctm
) == NULL
) return ASL_STATUS_FAILED
;
769 * This supports 12 monthly "Best Before" buckets.
770 * We advance the actual expiry time to day zero of the following month.
771 * mktime() is clever enough to know that you actually mean the last day
772 * of the previous month. What we get back from localtime is the last
773 * day of the month in which the message expires, which we use in the name.
783 if (localtime_r((const time_t *)&bb
, &ctm
) == NULL
) return ASL_STATUS_FAILED
;
784 asprintf(&dir
, "BB.AUX.%d.%02d.%02d", ctm
.tm_year
+ 1900, ctm
.tm_mon
+ 1, ctm
.tm_mday
);
788 asprintf(&dir
, "AUX.%d.%02d.%02d", ctm
.tm_year
+ 1900, ctm
.tm_mon
+ 1, ctm
.tm_mday
);
791 if (dir
== NULL
) return ASL_STATUS_NO_MEMORY
;
793 status
= asl_store_mkdir(s
, dir
, 0755);
794 if (status
!= ASL_STATUS_OK
)
804 asprintf(&tstring
, "%s/%llu", dir
, fid
);
806 if (tstring
== NULL
) return ASL_STATUS_NO_MEMORY
;
811 path
= asl_store_make_ug_path(s
->base_dir
, tstring
, NULL
, ruid
, rgid
, &u
, &g
, &m
);
813 if (path
== NULL
) return ASL_STATUS_NO_MEMORY
;
815 fd
= asl_file_create(path
, u
, g
, m
);
820 return ASL_STATUS_WRITE_FAILED
;
823 /* URL is file://<path> */
825 asprintf(url
, "file://%s", path
);
834 asl_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
)
841 asl_file_list_t
*files
;
843 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
844 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
849 * Open all readable files
851 dp
= opendir(s
->base_dir
);
852 if (dp
== NULL
) return ASL_STATUS_READ_FAILED
;
854 while ((dent
= readdir(dp
)) != NULL
)
856 if (dent
->d_name
[0] == '.') continue;
859 asprintf(&path
, "%s/%s", s
->base_dir
, dent
->d_name
);
861 /* 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 */
862 status
= asl_file_open_read(path
, &f
);
863 if (path
!= NULL
) free(path
);
864 if ((status
!= ASL_STATUS_OK
) || (f
== NULL
)) continue;
866 files
= asl_file_list_add(files
, f
);
871 status
= asl_file_list_match_timeout(files
, query
, res
, last_id
, start_id
, count
, direction
, usec
);
872 asl_file_list_close(files
);
877 asl_store_match(asl_store_t
*s
, aslresponse query
, aslresponse
*res
, uint64_t *last_id
, uint64_t start_id
, uint32_t count
, int32_t direction
)
879 return asl_store_match_timeout(s
, query
, res
, last_id
, start_id
, count
, direction
, 0);
883 asl_store_match_start(asl_store_t
*s
, uint64_t start_id
, int32_t direction
)
890 asl_file_list_t
*files
;
892 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
894 if (s
->work
!= NULL
) asl_file_list_match_end(s
->work
);
900 * Open all readable files
902 dp
= opendir(s
->base_dir
);
903 if (dp
== NULL
) return ASL_STATUS_READ_FAILED
;
905 while ((dent
= readdir(dp
)) != NULL
)
907 if (dent
->d_name
[0] == '.') continue;
910 asprintf(&path
, "%s/%s", s
->base_dir
, dent
->d_name
);
912 /* 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 */
913 status
= asl_file_open_read(path
, &f
);
914 if (path
!= NULL
) free(path
);
915 if ((status
!= ASL_STATUS_OK
) || (f
== NULL
)) continue;
917 files
= asl_file_list_add(files
, f
);
922 s
->work
= asl_file_list_match_start(files
, start_id
, direction
);
923 if (s
->work
== NULL
) return ASL_STATUS_FAILED
;
925 return ASL_STATUS_OK
;
929 asl_store_match_next(asl_store_t
*s
, aslresponse query
, aslresponse
*res
, uint32_t count
)
931 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
932 if (s
->work
== NULL
) return ASL_STATUS_OK
;
934 return asl_file_list_match_next(s
->work
, query
, res
, count
);