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@
31 #include <sys/errno.h>
34 #include <sys/types.h>
36 #include <membership.h>
39 #include <asl_private.h>
40 #include <asl_legacy1.h>
41 #include <TargetConditionals.h>
43 extern time_t asl_parse_time(const char *str
);
44 extern int asl_msg_cmp(aslmsg a
, aslmsg b
);
46 #define forever for(;;)
47 #define MILLION 1000000
50 * MSG and STR records have (at least) a type (uint16_t) and a length (uint32_t)
51 * type and level are both 16 bit fields so that alignment isn't a pain.
53 #define RECORD_COMMON_LEN 6
54 #define RECORD_TYPE_LEN 2
55 #define BUFFER_OFFSET_KVCOUNT 56
57 #define SCRATCH_BUFFER_SIZE (MSG_RECORD_FIXED_LENGTH + (20 * sizeof(uint64_t)))
85 asl_file_list_t
*list
;
87 } asl_file_match_token_t
;
99 _asl_put_16(uint16_t i
, char *h
)
117 _asl_put_32(uint32_t i
, char *h
)
131 return asl_core_ntohq(x
);
135 _asl_put_64(uint64_t i
, char *h
)
139 x
= asl_core_htonq(i
);
144 asl_file_read_uint32(asl_file_t
*s
, off_t off
, uint32_t *out
)
146 uint32_t status
, val
;
148 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
149 if (s
->store
== NULL
) return ASL_STATUS_INVALID_STORE
;
150 if ((off
+ sizeof(uint32_t)) > s
->file_size
) return ASL_STATUS_READ_FAILED
;
152 status
= fseeko(s
->store
, off
, SEEK_SET
);
153 if (status
!= 0) return ASL_STATUS_READ_FAILED
;
157 status
= fread(&val
, sizeof(uint32_t), 1, s
->store
);
158 if (status
!= 1) return ASL_STATUS_READ_FAILED
;
160 if (out
!= NULL
) *out
= ntohl(val
);
161 return ASL_STATUS_OK
;
165 asl_file_read_uint64(asl_file_t
*s
, off_t off
, uint64_t *out
)
170 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
171 if (s
->store
== NULL
) return ASL_STATUS_INVALID_STORE
;
172 if ((off
+ sizeof(uint64_t)) > s
->file_size
) return ASL_STATUS_READ_FAILED
;
174 status
= fseeko(s
->store
, off
, SEEK_SET
);
175 if (status
!= 0) return ASL_STATUS_READ_FAILED
;
179 status
= fread(&val
, sizeof(uint64_t), 1, s
->store
);
180 if (status
!= 1) return ASL_STATUS_READ_FAILED
;
182 if (out
!= NULL
) *out
= asl_core_ntohq(val
);
183 return ASL_STATUS_OK
;
187 asl_file_close(asl_file_t
*s
)
191 if (s
== NULL
) return ASL_STATUS_OK
;
195 return asl_legacy1_close((asl_legacy1_t
*)s
->legacy
);
198 while (s
->string_list
!= NULL
)
200 x
= s
->string_list
->next
;
201 free(s
->string_list
);
205 if (s
->store
!= NULL
) fclose(s
->store
);
206 if (s
->scratch
!= NULL
) free(s
->scratch
);
208 memset(s
, 0, sizeof(asl_file_t
));
211 return ASL_STATUS_OK
;
214 __private_extern__
uint32_t
215 asl_file_open_write_fd(int fd
, asl_file_t
**s
)
219 char buf
[DB_HEADER_LEN
];
222 if (fd
< 0) return ASL_STATUS_FAILED
;
223 if (s
== NULL
) return ASL_STATUS_FAILED
;
225 out
= (asl_file_t
*)calloc(1, sizeof(asl_file_t
));
226 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
228 out
->store
= fdopen(fd
, "w+");
229 if (out
->store
== NULL
)
232 return ASL_STATUS_FAILED
;
235 memset(buf
, 0, sizeof(buf
));
236 memcpy(buf
, ASL_DB_COOKIE
, ASL_DB_COOKIE_LEN
);
238 _asl_put_32(DB_VERSION
, buf
+ DB_HEADER_VERS_OFFSET
);
242 _asl_put_64(out
->dob
, buf
+ DB_HEADER_TIME_OFFSET
);
244 _asl_put_32(CACHE_SIZE
, buf
+ DB_HEADER_CSIZE_OFFSET
);
246 status
= fwrite(buf
, sizeof(buf
), 1, out
->store
);
251 return ASL_STATUS_FAILED
;
257 out
->file_size
= sizeof(buf
);
259 /* scratch buffer for file writes (we test for NULL before using it) */
260 out
->scratch
= malloc(SCRATCH_BUFFER_SIZE
);
264 return ASL_STATUS_OK
;
267 __private_extern__
int
268 asl_file_create(const char *path
, uid_t uid
, gid_t gid
, mode_t mode
)
271 return open(path
, O_RDWR
| O_CREAT
| O_EXCL
, mode
);
280 /* -1 means don't set ACL for uid or gid */
281 if ((uid
== -1) && (gid
== -1))
283 return open(path
, O_RDWR
| O_CREAT
| O_EXCL
, mode
);
288 if ((gid
!= 0) && (gid
!= -1))
290 status
= mbr_gid_to_uuid(gid
, uuid
);
291 if (status
!= 0) goto asl_file_create_return
;
293 status
= acl_create_entry_np(&acl
, &entry
, ACL_FIRST_ENTRY
);
294 if (status
!= 0) goto asl_file_create_return
;
296 status
= acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
);
297 if (status
!= 0) goto asl_file_create_return
;
299 status
= acl_set_qualifier(entry
, &uuid
);
300 if (status
!= 0) goto asl_file_create_return
;
302 status
= acl_get_permset(entry
, &perms
);
303 if (status
!= 0) goto asl_file_create_return
;
305 status
= acl_add_perm(perms
, ACL_READ_DATA
);
306 if (status
!= 0) goto asl_file_create_return
;
309 if ((uid
!= 0) && (uid
!= -1))
311 status
= mbr_uid_to_uuid(uid
, uuid
);
312 if (status
!= 0) goto asl_file_create_return
;
314 status
= acl_create_entry_np(&acl
, &entry
, ACL_FIRST_ENTRY
);
315 if (status
!= 0) goto asl_file_create_return
;
317 status
= acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
);
318 if (status
!= 0) goto asl_file_create_return
;
320 status
= acl_set_qualifier(entry
, &uuid
);
321 if (status
!= 0) goto asl_file_create_return
;
323 status
= acl_get_permset(entry
, &perms
);
324 if (status
!= 0) goto asl_file_create_return
;
326 status
= acl_add_perm(perms
, ACL_READ_DATA
);
327 if (status
!= 0) goto asl_file_create_return
;
330 fd
= open(path
, O_RDWR
| O_CREAT
| O_EXCL
, mode
);
331 if (fd
< 0) goto asl_file_create_return
;
333 status
= acl_set_fd(fd
, acl
);
341 asl_file_create_return
:
349 asl_file_open_write(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
, asl_file_t
**s
)
353 char buf
[DB_HEADER_LEN
];
355 uint32_t aslstatus
, vers
, last_len
;
358 memset(&sb
, 0, sizeof(struct stat
));
360 status
= stat(path
, &sb
);
363 /* must be a plain file */
364 if (!S_ISREG(sb
.st_mode
)) return ASL_STATUS_INVALID_STORE
;
368 fd
= open(path
, O_RDWR
| O_EXCL
, mode
);
369 if (fd
< 0) return ASL_STATUS_FAILED
;
371 return asl_file_open_write_fd(fd
, s
);
375 /* XXX Check that mode, uid, and gid are correct */
376 out
= (asl_file_t
*)calloc(1, sizeof(asl_file_t
));
377 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
379 out
->store
= fopen(path
, "r+");
380 if (out
->store
== NULL
)
383 return ASL_STATUS_FAILED
;
386 i
= fread(buf
, DB_HEADER_LEN
, 1, out
->store
);
390 return ASL_STATUS_READ_FAILED
;
394 if (strncmp(buf
, ASL_DB_COOKIE
, ASL_DB_COOKIE_LEN
))
397 return ASL_STATUS_INVALID_STORE
;
401 vers
= _asl_get_32(buf
+ DB_HEADER_VERS_OFFSET
);
402 if (vers
!= DB_VERSION
)
405 return ASL_STATUS_INVALID_STORE
;
408 out
->dob
= _asl_get_64(buf
+ DB_HEADER_TIME_OFFSET
);
409 out
->first
= _asl_get_64(buf
+ DB_HEADER_FIRST_OFFSET
);
410 out
->last
= _asl_get_64(buf
+ DB_HEADER_LAST_OFFSET
);
411 out
->file_size
= (size_t)sb
.st_size
;
414 * Detect bogus last pointer and check for odd-sized files.
415 * Setting out->last to zero forces asl_file_read_set_position to
416 * follow the linked list of records in the file to the last record.
417 * It's slower, but it's better at preventing crashes in corrupt files.
420 /* records are at least MSG_RECORD_FIXED_LENGTH bytes */
421 if ((out
->last
+ MSG_RECORD_FIXED_LENGTH
) > out
->file_size
)
427 /* read last record length and make sure the file is at least that large */
428 off
= out
->last
+ RECORD_TYPE_LEN
;
429 status
= asl_file_read_uint32(out
, off
, &last_len
);
430 if (status
!= ASL_STATUS_OK
)
436 if ((out
->last
+ last_len
) > out
->file_size
) out
->last
= 0;
439 aslstatus
= asl_file_read_set_position(out
, ASL_FILE_POSITION_LAST
);
440 if (aslstatus
!= ASL_STATUS_OK
)
446 out
->prev
= out
->cursor
;
447 status
= fseeko(out
->store
, 0, SEEK_END
);
451 return ASL_STATUS_READ_FAILED
;
454 out
->file_size
= (size_t)ftello(out
->store
);
456 /* scratch buffer for file writes (we test for NULL before using it) */
457 out
->scratch
= malloc(SCRATCH_BUFFER_SIZE
);
461 return ASL_STATUS_OK
;
464 else if (errno
!= ENOENT
)
466 /* unexpected status */
467 return ASL_STATUS_FAILED
;
470 /* the file does not exist */
471 fd
= asl_file_create(path
, uid
, gid
, mode
);
472 if (fd
< 0) return ASL_STATUS_FAILED
;
474 aslstatus
= asl_file_open_write_fd(fd
, s
);
475 if (aslstatus
!= ASL_STATUS_OK
) unlink(path
);
481 asl_file_compact(asl_file_t
*s
, const char *path
, mode_t mode
, uid_t uid
, gid_t gid
)
489 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
490 if (path
== NULL
) return ASL_STATUS_INVALID_ARG
;
492 if (s
->version
== 1) return ASL_STATUS_FAILED
;
494 memset(&sb
, 0, sizeof(struct stat
));
496 if (stat(path
, &sb
) == 0) return ASL_STATUS_FAILED
;
497 if (errno
!= ENOENT
) return ASL_STATUS_FAILED
;
499 status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
);
500 if (status
!= ASL_STATUS_OK
) return status
;
503 status
= asl_file_open_write(path
, mode
, uid
, gid
, &new);
504 if (status
!= ASL_STATUS_OK
) return status
;
505 new->flags
= ASL_FILE_FLAG_UNLIMITED_CACHE
| ASL_FILE_FLAG_PRESERVE_MSG_ID
;
507 while ((status
== ASL_STATUS_OK
) && (s
->cursor
!= 0))
510 status
= asl_file_fetch_next(s
, &m
);
511 if (status
!= ASL_STATUS_OK
) break;
514 status
= asl_file_save(new, m
, &xid
);
523 asl_file_string_encode(asl_file_t
*s
, const char *str
, uint64_t *out
)
525 uint32_t i
, hash
, len
, x32
;
526 file_string_t
*sp
, *sx
, *sl
;
533 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
534 if (str
== NULL
) return ASL_STATUS_INVALID_ARG
;
548 memcpy(p
+ 1, str
, len
);
549 *out
= asl_core_ntohq(x64
);
550 return ASL_STATUS_OK
;
553 /* check the cache */
554 hash
= asl_core_string_hash(str
, len
);
557 for (sx
= s
->string_list
; sx
!= NULL
; sx
= sx
->next
)
559 if ((hash
== sx
->hash
) && (!strcmp(str
, sx
->str
)))
561 /* Move this string to the head of the list */
571 return ASL_STATUS_OK
;
577 off
= ftello(s
->store
);
580 type
= htons(ASL_FILE_TYPE_STR
);
581 i
= fwrite(&type
, sizeof(uint16_t), 1, s
->store
);
582 if (i
!= 1) return ASL_STATUS_WRITE_FAILED
;
584 /* Length (includes trailing nul) */
585 x32
= htonl(len
+ 1);
586 i
= fwrite(&x32
, sizeof(uint32_t), 1, s
->store
);
587 if (i
!= 1) return ASL_STATUS_WRITE_FAILED
;
589 /* String data (nul terminated) */
590 i
= fwrite(str
, len
+ 1, 1, s
->store
);
591 if (i
!= 1) return ASL_STATUS_WRITE_FAILED
;
596 /* create file_string_t and insert into the cache */
597 sx
= (file_string_t
*)calloc(1, offsetof(file_string_t
, str
) + len
+ 1);
598 if (sx
== NULL
) return ASL_STATUS_NO_MEMORY
;
602 sx
->next
= s
->string_list
;
603 memcpy(sx
->str
, str
, len
);
607 if (((s
->flags
& ASL_FILE_FLAG_UNLIMITED_CACHE
) == 0) && (s
->string_count
== CACHE_SIZE
))
609 /* drop last (lru) string from cache */
613 /* NB CACHE_SIZE must be > 1 */
614 while (sx
->next
!= NULL
)
629 return ASL_STATUS_OK
;
633 * Encode an aslmsg as a record structure.
634 * Creates and caches strings.
637 asl_file_save(asl_file_t
*s
, aslmsg in
, uint64_t *mid
)
640 uint32_t i
, len
, x
, status
;
646 const char *key
, *val
;
648 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
649 if (in
== NULL
) return ASL_STATUS_INVALID_MESSAGE
;
651 if (s
->flags
& ASL_FILE_FLAG_READ_ONLY
) return ASL_STATUS_READ_ONLY
;
653 msg
= (asl_msg_t
*)in
;
655 memset(&r
, 0, sizeof(file_record_t
));
658 r
.level
= ASL_LEVEL_DEBUG
;
672 for (x
= asl_msg_fetch(msg
, 0, &key
, &val
, NULL
); x
!= IndexNull
; x
= asl_msg_fetch(msg
, x
, &key
, &val
, NULL
))
678 else if (!strcmp(key
, ASL_KEY_TIME
))
680 if (val
!= NULL
) r
.time
= asl_parse_time(val
);
682 else if (!strcmp(key
, ASL_KEY_TIME_NSEC
))
684 if (val
!= NULL
) r
.nano
= atoi(val
);
686 else if (!strcmp(key
, ASL_KEY_HOST
))
690 status
= asl_file_string_encode(s
, val
, &(r
.host
));
691 if (status
!= ASL_STATUS_OK
)
693 if (kvlist
!= NULL
) free(kvlist
);
698 else if (!strcmp(key
, ASL_KEY_SENDER
))
702 status
= asl_file_string_encode(s
, val
, &(r
.sender
));
703 if (status
!= ASL_STATUS_OK
)
705 if (kvlist
!= NULL
) free(kvlist
);
710 else if (!strcmp(key
, ASL_KEY_PID
))
712 if (val
!= NULL
) r
.pid
= atoi(val
);
714 else if (!strcmp(key
, ASL_KEY_REF_PID
))
716 if (val
!= NULL
) r
.refpid
= atoi(val
);
718 else if (!strcmp(key
, ASL_KEY_UID
))
720 if (val
!= NULL
) r
.uid
= atoi(val
);
722 else if (!strcmp(key
, ASL_KEY_GID
))
724 if (val
!= NULL
) r
.gid
= atoi(val
);
726 else if (!strcmp(key
, ASL_KEY_LEVEL
))
728 if (val
!= NULL
) r
.level
= atoi(val
);
730 else if (!strcmp(key
, ASL_KEY_MSG
))
734 status
= asl_file_string_encode(s
, val
, &(r
.message
));
735 if (status
!= ASL_STATUS_OK
)
737 if (kvlist
!= NULL
) free(kvlist
);
742 else if (!strcmp(key
, ASL_KEY_FACILITY
))
746 status
= asl_file_string_encode(s
, val
, &(r
.facility
));
747 if (status
!= ASL_STATUS_OK
)
749 if (kvlist
!= NULL
) free(kvlist
);
754 else if (!strcmp(key
, ASL_KEY_REF_PROC
))
758 status
= asl_file_string_encode(s
, val
, &(r
.refproc
));
759 if (status
!= ASL_STATUS_OK
)
761 if (kvlist
!= NULL
) free(kvlist
);
766 else if (!strcmp(key
, ASL_KEY_SESSION
))
770 status
= asl_file_string_encode(s
, val
, &(r
.session
));
771 if (status
!= ASL_STATUS_OK
)
773 if (kvlist
!= NULL
) free(kvlist
);
778 else if (!strcmp(key
, ASL_KEY_READ_UID
))
780 if (((r
.flags
& ASL_MSG_FLAG_READ_UID_SET
) == 0) && (val
!= NULL
))
783 r
.flags
|= ASL_MSG_FLAG_READ_UID_SET
;
786 else if (!strcmp(key
, ASL_KEY_READ_GID
))
788 if (((r
.flags
& ASL_MSG_FLAG_READ_GID_SET
) == 0) && (val
!= NULL
))
791 r
.flags
|= ASL_MSG_FLAG_READ_GID_SET
;
794 else if (!strcmp(key
, ASL_KEY_MSG_ID
))
796 if (s
->flags
& ASL_FILE_FLAG_PRESERVE_MSG_ID
) *mid
= atoll(val
);
798 else if (!strcmp(key
, ASL_KEY_OPTION
))
800 /* ignore - we don't save ASLOption */
804 status
= asl_file_string_encode(s
, key
, &k
);
805 if (status
!= ASL_STATUS_OK
)
807 if (kvlist
!= NULL
) free(kvlist
);
814 status
= asl_file_string_encode(s
, val
, &v
);
815 if (status
!= ASL_STATUS_OK
)
817 if (kvlist
!= NULL
) free(kvlist
);
824 kvlist
= (uint64_t *)calloc(2, sizeof(uint64_t));
828 kvlist
= (uint64_t *)reallocf(kvlist
, (r
.kvcount
+ 2) * sizeof(uint64_t));
833 return ASL_STATUS_NO_MEMORY
;
836 kvlist
[r
.kvcount
++] = k
;
837 kvlist
[r
.kvcount
++] = v
;
841 len
= MSG_RECORD_FIXED_LENGTH
+ (r
.kvcount
* sizeof(uint64_t));
844 /* use the scratch buffer if it exists and is large enough */
845 if ((s
->scratch
!= NULL
) && (len
<= SCRATCH_BUFFER_SIZE
))
847 memset(s
->scratch
, 0, SCRATCH_BUFFER_SIZE
);
852 buf
= calloc(1, len
);
855 if (buf
== NULL
) return ASL_STATUS_NO_MEMORY
;
863 r
.mid
= asl_core_new_msg_id(0);
870 _asl_put_16(ASL_FILE_TYPE_MSG
, p
);
871 p
+= sizeof(uint16_t);
873 /* Length of message (excludes type and length fields) */
874 _asl_put_32(len
- RECORD_COMMON_LEN
, p
);
875 p
+= sizeof(uint32_t);
877 /* Message data... */
879 _asl_put_64(r
.next
, p
);
880 p
+= sizeof(uint64_t);
882 _asl_put_64(r
.mid
, p
);
883 p
+= sizeof(uint64_t);
885 _asl_put_64(r
.time
, p
);
886 p
+= sizeof(uint64_t);
888 _asl_put_32(r
.nano
, p
);
889 p
+= sizeof(uint32_t);
891 _asl_put_16(r
.level
, p
);
892 p
+= sizeof(uint16_t);
894 _asl_put_16(r
.flags
, p
);
895 p
+= sizeof(uint16_t);
897 _asl_put_32(r
.pid
, p
);
898 p
+= sizeof(uint32_t);
900 _asl_put_32(r
.uid
, p
);
901 p
+= sizeof(uint32_t);
903 _asl_put_32(r
.gid
, p
);
904 p
+= sizeof(uint32_t);
906 _asl_put_32(r
.ruid
, p
);
907 p
+= sizeof(uint32_t);
909 _asl_put_32(r
.rgid
, p
);
910 p
+= sizeof(uint32_t);
912 _asl_put_32(r
.refpid
, p
);
913 p
+= sizeof(uint32_t);
915 _asl_put_32(r
.kvcount
, p
);
916 p
+= sizeof(uint32_t);
918 _asl_put_64(r
.host
, p
);
919 p
+= sizeof(uint64_t);
921 _asl_put_64(r
.sender
, p
);
922 p
+= sizeof(uint64_t);
924 _asl_put_64(r
.facility
, p
);
925 p
+= sizeof(uint64_t);
927 _asl_put_64(r
.message
, p
);
928 p
+= sizeof(uint64_t);
930 _asl_put_64(r
.refproc
, p
);
931 p
+= sizeof(uint64_t);
933 _asl_put_64(r
.session
, p
);
934 p
+= sizeof(uint64_t);
936 for (i
= 0; i
< r
.kvcount
; i
++)
938 _asl_put_64(kvlist
[i
], p
);
939 p
+= sizeof(uint64_t);
942 _asl_put_64(r
.prev
, p
);
943 p
+= sizeof(uint64_t);
948 /* write record at end of file */
949 status
= fseeko(s
->store
, 0, SEEK_END
);
950 if (status
!= 0) return ASL_STATUS_WRITE_FAILED
;
952 s
->last
= (uint64_t)ftello(s
->store
);
954 v
= asl_core_htonq(s
->last
);
956 status
= fwrite(buf
, len
, 1, s
->store
);
959 /* free the buffer if it was allocated here */
960 if (buf
!= s
->scratch
) free(buf
);
962 /* seek to "next" field of previous record, write last offset */
963 off
= s
->prev
+ RECORD_COMMON_LEN
;
964 if (s
->prev
== 0) off
= DB_HEADER_FIRST_OFFSET
;
966 status
= fseeko(s
->store
, off
, SEEK_SET
);
967 if (status
!= 0) return ASL_STATUS_WRITE_FAILED
;
969 status
= fwrite(&v
, sizeof(uint64_t), 1, s
->store
);
970 if (status
!= 1) return ASL_STATUS_WRITE_FAILED
;
972 /* seek to DB_HEADER_LAST_OFFSET, write last record offset */
973 off
= DB_HEADER_LAST_OFFSET
;
975 status
= fseeko(s
->store
, off
, SEEK_SET
);
976 if (status
!= 0) return ASL_STATUS_WRITE_FAILED
;
978 status
= fwrite(&v
, sizeof(uint64_t), 1, s
->store
);
979 if (status
!= 1) return ASL_STATUS_WRITE_FAILED
;
981 /* return to the end of the store (this is expected by other routines) */
982 status
= fseeko(s
->store
, 0, SEEK_END
);
983 if (status
!= 0) return ASL_STATUS_WRITE_FAILED
;
988 s
->file_size
= (size_t)ftello(s
->store
);
992 return ASL_STATUS_OK
;
996 asl_file_fetch_object(asl_file_t
*s
, uint64_t where
, char **out
, uint32_t *outlen
)
1010 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1011 if (out
== NULL
) return ASL_STATUS_INVALID_ARG
;
1012 if (where
== 0) return ASL_STATUS_INVALID_ARG
;
1015 x64
= asl_core_htonq(where
);
1016 memcpy(&inls
, &x64
, 1);
1021 if (inls
> 7) return ASL_STATUS_INVALID_STORE
;
1023 p
= 1 + (char *)&x64
;
1024 memset(ils
, 0, sizeof(ils
));
1025 memcpy(ils
, p
, inls
);
1027 if (*out
== NULL
) return ASL_STATUS_NO_MEMORY
;
1030 return ASL_STATUS_OK
;
1034 if ((off
+ sizeof(uint16_t) + sizeof(uint32_t)) > s
->file_size
) return ASL_STATUS_READ_FAILED
;
1036 status
= fseeko(s
->store
, off
, SEEK_SET
);
1037 if (status
!= 0) return ASL_STATUS_READ_FAILED
;
1040 status
= fread(&type
, sizeof(uint16_t), 1, s
->store
);
1041 if (status
!= 1) return ASL_STATUS_READ_FAILED
;
1042 off
+= sizeof(uint16_t);
1046 status
= fread(&len
, sizeof(uint32_t), 1, s
->store
);
1047 if (status
!= 1) return ASL_STATUS_READ_FAILED
;
1048 off
+= sizeof(uint32_t);
1051 if ((off
+ len
) > s
->file_size
) return ASL_STATUS_READ_FAILED
;
1053 *out
= calloc(1, len
);
1054 if (*out
== NULL
) return ASL_STATUS_NO_MEMORY
;
1056 status
= fread(*out
, len
, 1, s
->store
);
1060 return ASL_STATUS_READ_FAILED
;
1064 return ASL_STATUS_OK
;
1068 asl_file_fetch_helper_16(asl_file_t
*s
, char **p
, aslmsg m
, const char *key
)
1073 out
= _asl_get_16(*p
);
1074 *p
+= sizeof(uint16_t);
1076 if ((m
== NULL
) || (key
== NULL
)) return out
;
1078 snprintf(str
, sizeof(str
), "%hu", out
);
1079 asl_set(m
, key
, str
);
1085 asl_file_fetch_helper_32(asl_file_t
*s
, char **p
, aslmsg m
, const char *key
, int ignore
, uint32_t ignoreval
)
1090 out
= _asl_get_32(*p
);
1091 *p
+= sizeof(uint32_t);
1093 if ((m
== NULL
) || (key
== NULL
)) return out
;
1096 if ((ignore
!= 0) && (out
== ignoreval
)) doit
= 0;
1099 snprintf(str
, sizeof(str
), "%u", out
);
1100 asl_set(m
, key
, str
);
1107 asl_file_fetch_helper_64(asl_file_t
*s
, char **p
, aslmsg m
, const char *key
)
1112 out
= _asl_get_64(*p
);
1113 *p
+= sizeof(uint64_t);
1115 if ((m
== NULL
) || (key
== NULL
)) return out
;
1117 snprintf(str
, sizeof(str
), "%llu", out
);
1118 asl_set(m
, key
, str
);
1124 asl_file_fetch_helper_str(asl_file_t
*s
, char **p
, aslmsg m
, const char *key
, uint32_t *err
)
1128 uint32_t status
, len
;
1130 out
= _asl_get_64(*p
);
1131 *p
+= sizeof(uint64_t);
1135 status
= ASL_STATUS_OK
;
1136 if (out
!= 0) status
= asl_file_fetch_object(s
, out
, &val
, &len
);
1138 if (err
!= NULL
) *err
= status
;
1139 if ((status
== ASL_STATUS_OK
) && (val
!= NULL
))
1141 asl_set(m
, key
, val
);
1149 asl_file_fetch_pos(asl_file_t
*s
, uint64_t where
, int dir
, aslmsg
*msg
)
1151 char *buf
, *p
, *k
, *v
;
1153 uint32_t i
, status
, len
, buflen
, kvn
;
1158 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1159 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
1160 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return ASL_STATUS_WRITE_ONLY
;
1164 status
= asl_file_fetch_object(s
, where
, &buf
, &buflen
);
1165 if ((status
!= ASL_STATUS_OK
) || (buf
== NULL
))
1172 /* check buffer size */
1173 kvn
= _asl_get_32(buf
+ BUFFER_OFFSET_KVCOUNT
);
1174 if (buflen
< (MSG_RECORD_FIXED_LENGTH
- RECORD_COMMON_LEN
+ (kvn
* sizeof(uint64_t))))
1179 return ASL_STATUS_READ_FAILED
;
1182 out
= asl_new(ASL_TYPE_MSG
);
1183 if (out
== NULL
) return ASL_STATUS_NO_MEMORY
;
1185 memset(&r
, 0, sizeof(file_record_t
));
1188 r
.next
= asl_file_fetch_helper_64(s
, &p
, NULL
, NULL
);
1189 r
.mid
= asl_file_fetch_helper_64(s
, &p
, out
, ASL_KEY_MSG_ID
);
1190 r
.time
= asl_file_fetch_helper_64(s
, &p
, out
, ASL_KEY_TIME
);
1191 r
.nano
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_TIME_NSEC
, 0, 0);
1192 r
.level
= asl_file_fetch_helper_16(s
, &p
, out
, ASL_KEY_LEVEL
);
1193 r
.flags
= asl_file_fetch_helper_16(s
, &p
, NULL
, NULL
);
1194 r
.pid
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_PID
, 0, 0);
1195 r
.uid
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_UID
, 1, (uint32_t)-1);
1196 r
.gid
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_GID
, 1, (uint32_t)-1);
1197 r
.ruid
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_READ_UID
, 1, (uint32_t)-1);
1198 r
.rgid
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_READ_GID
, 1, (uint32_t)-1);
1199 r
.refpid
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_REF_PID
, 1, 0);
1200 r
.kvcount
= asl_file_fetch_helper_32(s
, &p
, NULL
, NULL
, 0, 0);
1202 status
= ASL_STATUS_OK
;
1203 r
.host
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_HOST
, &status
); /* 68 */
1204 if (status
== ASL_STATUS_OK
) r
.sender
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_SENDER
, &status
); /* 76 */
1205 if (status
== ASL_STATUS_OK
) r
.facility
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_FACILITY
, &status
); /* 84 */
1206 if (status
== ASL_STATUS_OK
) r
.message
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_MSG
, &status
); /* 92 */
1207 if (status
== ASL_STATUS_OK
) r
.refproc
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_REF_PROC
, &status
); /* 100 */
1208 if (status
== ASL_STATUS_OK
) r
.session
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_SESSION
, &status
); /* 108 */
1210 if (status
!= ASL_STATUS_OK
)
1219 kvn
= r
.kvcount
/ 2;
1221 for (i
= 0; i
< kvn
; i
++)
1223 kv
= _asl_get_64(p
);
1224 p
+= sizeof(uint64_t);
1227 status
= asl_file_fetch_object(s
, kv
, &k
, &len
);
1228 if (status
!= ASL_STATUS_OK
)
1237 kv
= _asl_get_64(p
);
1238 p
+= sizeof(uint64_t);
1244 status
= asl_file_fetch_object(s
, kv
, &v
, &len
);
1245 if (status
!= ASL_STATUS_OK
)
1255 if ((status
== ASL_STATUS_OK
) && (k
!= NULL
))
1258 if (v
!= NULL
) free(v
);
1263 r
.prev
= asl_file_fetch_helper_64(s
, &p
, NULL
, NULL
); /* 116 */
1269 if ((r
.next
!= 0) && (r
.next
<= s
->cursor
))
1272 * Next offset goes backwards or loops.
1273 * The database is corrupt, but we allow this call to fail
1274 * quietly so that the current record fetch succeeds.
1278 return ASL_STATUS_OK
;
1285 if ((r
.prev
!= 0) && (r
.prev
>= s
->cursor
))
1288 * Prev offset goes forward or loops.
1289 * The database is corrupt, but we allow this call to fail
1290 * quietly so that the current record fetch succeeds.
1294 return ASL_STATUS_OK
;
1304 off
= s
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1305 if (off
> s
->file_size
)
1310 * Next record offset is past the end of the file.
1311 * This is an error, but we allow it to fail quietly
1312 * so that the current record fetch succeeds.
1315 return ASL_STATUS_OK
;
1318 status
= fseeko(s
->store
, off
, SEEK_SET
);
1324 return ASL_STATUS_READ_FAILED
;
1327 status
= fread(&x64
, sizeof(uint64_t), 1, s
->store
);
1333 return ASL_STATUS_READ_FAILED
;
1336 s
->cursor_xid
= asl_core_ntohq(x64
);
1340 return ASL_STATUS_OK
;
1344 asl_file_open_read(const char *path
, asl_file_t
**s
)
1349 uint32_t status
, vers
, last_len
;
1350 char buf
[DB_HEADER_LEN
];
1352 asl_legacy1_t
*legacy
;
1355 memset(&sb
, 0, sizeof(struct stat
));
1356 if (stat(path
, &sb
) != 0) return ASL_STATUS_FAILED
;
1358 f
= fopen(path
, "r");
1361 if (errno
== EACCES
) return ASL_STATUS_ACCESS_DENIED
;
1362 return ASL_STATUS_FAILED
;
1365 i
= fread(buf
, DB_HEADER_LEN
, 1, f
);
1369 return ASL_STATUS_INVALID_STORE
;
1372 /* validate header */
1373 if (strncmp(buf
, ASL_DB_COOKIE
, ASL_DB_COOKIE_LEN
))
1376 return ASL_STATUS_INVALID_STORE
;
1381 vers
= _asl_get_32(buf
+ DB_HEADER_VERS_OFFSET
);
1382 if (vers
== DB_VERSION_LEGACY_1
)
1385 status
= asl_legacy1_open(path
, &legacy
);
1386 if (status
!= ASL_STATUS_OK
) return status
;
1389 out
= (asl_file_t
*)calloc(1, sizeof(asl_file_t
));
1393 return ASL_STATUS_NO_MEMORY
;
1397 out
->flags
= ASL_FILE_FLAG_READ_ONLY
;
1398 out
->version
= vers
;
1402 out
->flags
|= ASL_FILE_FLAG_LEGACY_STORE
;
1403 out
->legacy
= (void *)legacy
;
1406 return ASL_STATUS_OK
;
1409 out
->first
= _asl_get_64(buf
+ DB_HEADER_FIRST_OFFSET
);
1410 out
->last
= _asl_get_64(buf
+ DB_HEADER_LAST_OFFSET
);
1411 out
->file_size
= (size_t)sb
.st_size
;
1414 * Detect bogus last pointer and check for odd-sized files.
1415 * Setting out->last to zero forces us to follow the linked
1416 * list of records in the file to the last record. That's
1417 * done in the set_position code. It's a bit slower, but it's
1418 * better at preventing crashes in corrupt files.
1421 /* records are at least MSG_RECORD_FIXED_LENGTH bytes */
1422 if ((out
->last
+ MSG_RECORD_FIXED_LENGTH
) > out
->file_size
)
1428 /* read last record length and make sure the file is at least that large */
1429 off
= out
->last
+ RECORD_TYPE_LEN
;
1430 status
= asl_file_read_uint32(out
, off
, &last_len
);
1431 if (status
!= ASL_STATUS_OK
)
1438 if ((out
->last
+ last_len
) > out
->file_size
) out
->last
= 0;
1441 out
->cursor
= out
->first
;
1442 if (out
->cursor
!= 0)
1444 off
= out
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1445 status
= asl_file_read_uint64(out
, off
, &(out
->cursor_xid
));
1446 if (status
!= ASL_STATUS_OK
)
1455 return ASL_STATUS_OK
;
1459 asl_file_read_set_position_first(asl_file_t
*s
)
1464 s
->cursor
= s
->first
;
1467 if (s
->cursor
== 0) return ASL_STATUS_OK
;
1469 /* read ID of the first record */
1470 off
= s
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1471 status
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
));
1476 asl_file_read_set_position_last(asl_file_t
*s
)
1483 * If the file has the offset of the last record, we just go there.
1484 * The last record offset was added to improve performance, so it may
1485 * or may not be there. If we don't have the last record offset, we
1486 * just iterate down the record links to find the last one.
1488 * Note that s->last may be zero if the file is empty.
1493 s
->cursor
= s
->last
;
1494 off
= s
->last
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1496 /* read ID of the last record */
1497 status
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
));
1501 /* start at the first record and iterate */
1502 s
->cursor
= s
->first
;
1507 off
= s
->cursor
+ RECORD_COMMON_LEN
;
1510 /* read next offset */
1511 status
= asl_file_read_uint64(s
, off
, &next
);
1512 if (status
!= ASL_STATUS_OK
) return status
;
1514 /* detect bogus next pointer */
1515 if (((next
+ MSG_RECORD_FIXED_LENGTH
) > s
->file_size
) || (next
<= s
->cursor
)) next
= 0;
1519 if (s
->cursor
== 0) return ASL_STATUS_OK
;
1521 off
= s
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1522 status
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
));
1523 return ASL_STATUS_OK
;
1531 asl_file_read_set_position(asl_file_t
*s
, uint32_t pos
)
1534 uint32_t len
, status
;
1537 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1538 if (s
->version
== 1) return ASL_STATUS_FAILED
;
1540 if (pos
== ASL_FILE_POSITION_FIRST
) return asl_file_read_set_position_first(s
);
1541 if (pos
== ASL_FILE_POSITION_LAST
) return asl_file_read_set_position_last(s
);
1545 if (pos
== ASL_FILE_POSITION_PREVIOUS
)
1547 if (s
->cursor
== s
->first
) return ASL_STATUS_NO_RECORDS
;
1548 if (s
->cursor
== 0) return ASL_STATUS_NO_RECORDS
;
1550 off
= s
->cursor
+ RECORD_TYPE_LEN
;
1551 status
= asl_file_read_uint32(s
, off
, &len
);
1552 if (status
!= ASL_STATUS_OK
) return status
;
1554 /* set offset to read the "previous" field at the end of the record */
1555 off
= s
->cursor
+ RECORD_COMMON_LEN
+ len
- sizeof(uint64_t);
1557 else if (pos
== ASL_FILE_POSITION_NEXT
)
1559 if (s
->cursor
== s
->last
) return ASL_STATUS_NO_RECORDS
;
1560 if (s
->cursor
== 0) return ASL_STATUS_NO_RECORDS
;
1562 /* set offset to read the "next" field in the current record */
1563 off
= s
->cursor
+ RECORD_COMMON_LEN
;
1565 else return ASL_STATUS_INVALID_ARG
;
1570 * read offset of next / previous
1573 status
= asl_file_read_uint64(s
, off
, &next
);
1574 if (status
!= ASL_STATUS_OK
) return ASL_STATUS_READ_FAILED
;
1576 /* detect bogus next pointer */
1577 if ((next
+ MSG_RECORD_FIXED_LENGTH
) > s
->file_size
) next
= 0;
1578 else if ((pos
== ASL_FILE_POSITION_PREVIOUS
) && (next
>= s
->cursor
)) next
= 0;
1579 else if ((pos
== ASL_FILE_POSITION_NEXT
) && (next
<= s
->cursor
)) next
= 0;
1582 if (s
->cursor
== 0) return ASL_STATUS_NO_RECORDS
;
1584 /* read ID of the record */
1585 off
= s
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1586 status
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
));
1591 asl_file_fetch_next(asl_file_t
*s
, aslmsg
*msg
)
1593 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1594 if (s
->version
== 1) return ASL_STATUS_FAILED
;
1596 return asl_file_fetch_pos(s
, s
->cursor
, 1, msg
);
1600 asl_file_fetch_previous(asl_file_t
*s
, aslmsg
*msg
)
1602 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1603 if (s
->version
== 1) return ASL_STATUS_FAILED
;
1605 return asl_file_fetch_pos(s
, s
->cursor
, -1, msg
);
1609 asl_file_fetch(asl_file_t
*s
, uint64_t mid
, aslmsg
*msg
)
1613 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1614 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
1615 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return ASL_STATUS_WRITE_ONLY
;
1617 if (s
->version
== 1)
1619 return asl_legacy1_fetch((asl_legacy1_t
*)s
->legacy
, mid
, msg
);
1622 if (s
->cursor_xid
== 0)
1624 status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
);
1625 if (status
!= ASL_STATUS_OK
) return status
;
1626 if (s
->cursor_xid
== 0) return ASL_STATUS_INVALID_ID
;
1629 while (s
->cursor_xid
< mid
)
1631 status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_NEXT
);
1632 if (status
!= ASL_STATUS_OK
) return status
;
1633 if (s
->cursor_xid
> mid
) return ASL_STATUS_INVALID_ID
;
1634 if (s
->cursor_xid
== 0) return ASL_STATUS_INVALID_ID
;
1637 while (s
->cursor_xid
> mid
)
1639 status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_PREVIOUS
);
1640 if (status
!= ASL_STATUS_OK
) return status
;
1641 if (s
->cursor_xid
< mid
) return ASL_STATUS_INVALID_ID
;
1642 if (s
->cursor_xid
== 0) return ASL_STATUS_INVALID_ID
;
1645 if (s
->cursor_xid
!= mid
) return ASL_STATUS_INVALID_ID
;
1647 return asl_file_fetch_pos(s
, s
->cursor
, 1, msg
);
1650 __private_extern__
uint64_t
1651 asl_file_cursor(asl_file_t
*s
)
1653 if (s
== NULL
) return 0;
1654 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return 0;
1655 if (s
->version
== 1) return 0;
1657 return s
->cursor_xid
;
1660 __private_extern__
uint32_t
1661 asl_file_match_start(asl_file_t
*s
, uint64_t start_id
, int32_t direction
)
1665 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1666 if (s
->version
== 1) return ASL_STATUS_INVALID_STORE
;
1667 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return ASL_STATUS_WRITE_ONLY
;
1669 d
= ASL_FILE_POSITION_NEXT
;
1670 if (direction
< 0) d
= ASL_FILE_POSITION_PREVIOUS
;
1673 * find starting point
1675 status
= ASL_STATUS_OK
;
1676 if (direction
>= 0) status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
);
1677 else status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_LAST
);
1678 if (status
!= ASL_STATUS_OK
) return status
;
1680 while ((status
== ASL_STATUS_OK
) && (((direction
>= 0) && (s
->cursor_xid
< start_id
)) || ((direction
< 0) && (s
->cursor_xid
> start_id
))))
1682 status
= asl_file_read_set_position(s
, d
);
1688 __private_extern__
uint32_t
1689 asl_file_match_next(asl_file_t
*s
, aslresponse query
, aslmsg
*msg
, uint64_t *last_id
, int32_t direction
)
1691 uint32_t status
, d
, i
, do_match
, did_match
;
1694 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1695 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
1696 if (s
->version
== 1) return ASL_STATUS_INVALID_STORE
;
1697 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return ASL_STATUS_WRITE_ONLY
;
1698 if (s
->cursor
== 0) return ASL_STATUS_NO_RECORDS
;
1703 d
= ASL_FILE_POSITION_NEXT
;
1704 if (direction
< 0) d
= ASL_FILE_POSITION_PREVIOUS
;
1706 if ((query
== NULL
) || ((query
!= NULL
) && (query
->count
== 0))) do_match
= 0;
1710 *last_id
= s
->cursor_xid
;
1712 status
= asl_file_fetch_pos(s
, s
->cursor
, direction
, &m
);
1713 if (status
== ASL_STATUS_ACCESS_DENIED
) return ASL_STATUS_MATCH_FAILED
;
1714 if ((status
== ASL_STATUS_INVALID_ARG
) && (s
->cursor
== 0)) return ASL_STATUS_NO_RECORDS
;
1715 if (status
!= ASL_STATUS_OK
) return status
;
1723 for (i
= 0; (i
< query
->count
) && (did_match
== 0); i
++)
1725 did_match
= asl_msg_cmp((aslmsg
)(query
->msg
[i
]), m
);
1732 return ASL_STATUS_OK
;
1737 return ASL_STATUS_MATCH_FAILED
;
1741 asl_file_match(asl_file_t
*s
, aslresponse query
, aslresponse
*res
, uint64_t *last_id
, uint64_t start_id
, uint32_t count
, int32_t direction
)
1743 uint32_t status
, d
, i
, do_match
, did_match
, rescount
;
1746 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1747 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
1748 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return ASL_STATUS_WRITE_ONLY
;
1750 if (s
->version
== 1)
1752 return asl_legacy1_match((asl_legacy1_t
*)s
->legacy
, query
, res
, last_id
, start_id
, count
, direction
);
1758 d
= ASL_FILE_POSITION_NEXT
;
1759 if (direction
< 0) d
= ASL_FILE_POSITION_PREVIOUS
;
1761 if ((query
== NULL
) || ((query
!= NULL
) && (query
->count
== 0))) do_match
= 0;
1764 * find starting point
1766 status
= ASL_STATUS_OK
;
1767 if (direction
>= 0) status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
);
1768 else status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_LAST
);
1769 if (status
!= ASL_STATUS_OK
) return status
;
1771 while ((status
== ASL_STATUS_OK
) && (((direction
>= 0) && (s
->cursor_xid
< start_id
)) || ((direction
< 0) && (s
->cursor_xid
> start_id
))))
1773 status
= asl_file_read_set_position(s
, d
);
1777 * loop through records
1782 status
= asl_file_fetch_pos(s
, s
->cursor
, direction
, &m
);
1783 if (status
== ASL_STATUS_ACCESS_DENIED
) continue;
1784 if (status
!= ASL_STATUS_OK
) break;
1786 *last_id
= s
->cursor_xid
;
1794 for (i
= 0; (i
< query
->count
) && (did_match
== 0); i
++)
1796 did_match
= asl_msg_cmp((aslmsg
)query
->msg
[i
], m
);
1802 /* append m to res */
1805 *res
= (aslresponse
)calloc(1, sizeof(aslresponse
));
1806 if (*res
== NULL
) return ASL_STATUS_NO_MEMORY
;
1807 (*res
)->msg
= (asl_msg_t
**)calloc(1, sizeof(aslmsg
));
1808 if ((*res
)->msg
== NULL
)
1811 return ASL_STATUS_NO_MEMORY
;
1816 (*res
)->msg
= (asl_msg_t
**)reallocf((*res
)->msg
, ((*res
)->count
+ 1) * sizeof(aslmsg
));
1817 if ((*res
)->msg
== NULL
)
1820 return ASL_STATUS_NO_MEMORY
;
1824 (*res
)->msg
[(*res
)->count
] = (asl_msg_t
*)m
;
1828 if ((count
!= 0) && (rescount
>= count
)) break;
1837 return ASL_STATUS_OK
;
1841 asl_file_size(asl_file_t
*s
)
1843 if (s
== NULL
) return 0;
1844 return s
->file_size
;
1848 asl_file_ctime(asl_file_t
*s
)
1850 if (s
== NULL
) return 0;
1855 asl_file_list_close(asl_file_list_t
*head
)
1857 asl_file_list_t
*next
;
1859 while (head
!= NULL
)
1862 asl_file_close(head
->file
);
1869 asl_file_list_free(asl_file_list_t
*head
)
1871 asl_file_list_t
*next
;
1873 while (head
!= NULL
)
1881 static asl_file_list_t
*
1882 asl_file_list_insert(asl_file_list_t
*list
, asl_file_t
*f
, int32_t dir
)
1884 asl_file_list_t
*a
, *b
, *tmp
;
1886 if (f
== NULL
) return list
;
1888 tmp
= (asl_file_list_t
*)calloc(1, sizeof(asl_file_list_t
));
1889 if (tmp
== NULL
) return NULL
;
1892 if (list
== NULL
) return tmp
;
1895 if (((dir
< 0) && (f
->cursor_xid
> a
->file
->cursor_xid
)) || ((dir
>= 0) && (f
->cursor_xid
< a
->file
->cursor_xid
)))
1904 if (((dir
< 0) && (f
->cursor_xid
> b
->file
->cursor_xid
)) || ((dir
>= 0) && (f
->cursor_xid
< b
->file
->cursor_xid
)))
1920 asl_file_list_add(asl_file_list_t
*list
, asl_file_t
*f
)
1922 asl_file_list_t
*tmp
;
1924 if (f
== NULL
) return list
;
1925 if (f
->version
== 1) return list
;
1927 tmp
= (asl_file_list_t
*)calloc(1, sizeof(asl_file_list_t
));
1928 if (tmp
== NULL
) return NULL
;
1936 asl_file_list_match_start(asl_file_list_t
*list
, uint64_t start_id
, int32_t direction
)
1940 asl_file_match_token_t
*out
;
1942 if (list
== NULL
) return NULL
;
1944 out
= (asl_file_match_token_t
*)calloc(1, sizeof(asl_file_match_token_t
));
1945 if (out
== NULL
) return NULL
;
1947 for (n
= list
; n
!= NULL
; n
= n
->next
)
1949 /* init file for the search */
1950 status
= asl_file_match_start(n
->file
, start_id
, direction
);
1951 if (status
!= ASL_STATUS_OK
) continue;
1952 if (n
->file
->cursor_xid
== 0) continue;
1954 out
->list
= asl_file_list_insert(out
->list
, n
->file
, direction
);
1957 out
->dir
= direction
;
1962 asl_file_list_match_next(void *token
, aslresponse query
, aslresponse
*res
, uint32_t count
)
1964 uint32_t status
, rescount
;
1967 asl_file_match_token_t
*work
;
1970 if (token
== NULL
) return ASL_STATUS_OK
;
1971 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
1973 work
= (asl_file_match_token_t
*)token
;
1978 while ((work
->list
!= NULL
) && ((rescount
< count
) || (count
== 0)))
1981 status
= asl_file_match_next(work
->list
->file
, query
, &m
, &last_id
, work
->dir
);
1984 if (*res
== NULL
) *res
= (aslresponse
)calloc(1, sizeof(asl_search_result_t
));
1987 asl_file_list_free(work
->list
);
1989 return ASL_STATUS_NO_MEMORY
;
1992 if ((*res
)->msg
== NULL
) (*res
)->msg
= (asl_msg_t
**)calloc(1, sizeof(aslmsg
));
1993 else (*res
)->msg
= (asl_msg_t
**)reallocf((*res
)->msg
, ((*res
)->count
+ 1) * sizeof(aslmsg
));
1994 if ((*res
)->msg
== NULL
)
1998 asl_file_list_free(work
->list
);
2000 return ASL_STATUS_NO_MEMORY
;
2003 (*res
)->msg
[(*res
)->count
] = (asl_msg_t
*)m
;
2008 if ((status
!= ASL_STATUS_OK
) || (work
->list
->file
->cursor_xid
== 0))
2010 n
= work
->list
->next
;
2015 if (work
->list
!= NULL
)
2017 n
= work
->list
->next
;
2020 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
)))
2023 work
->list
= work
->list
->next
;
2025 work
->list
= asl_file_list_insert(work
->list
, n
->file
, work
->dir
);
2032 return ASL_STATUS_OK
;
2036 asl_file_list_match_end(void *token
)
2038 asl_file_match_token_t
*work
;
2040 if (token
== NULL
) return;
2042 work
= (asl_file_match_token_t
*)token
;
2043 asl_file_list_free(work
->list
);
2050 asl_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
)
2052 uint32_t status
, rescount
;
2053 asl_file_list_t
*files
, *n
;
2055 struct timeval now
, finish
;
2057 if (list
== NULL
) return ASL_STATUS_INVALID_ARG
;
2058 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
2059 if (last_id
== NULL
) return ASL_STATUS_INVALID_ARG
;
2063 for (n
= list
; n
!= NULL
; n
= n
->next
)
2065 /* init file for the search */
2066 status
= asl_file_match_start(n
->file
, start_id
, direction
);
2067 if (status
!= ASL_STATUS_OK
) continue;
2068 if (n
->file
->cursor_xid
== 0) continue;
2070 files
= asl_file_list_insert(files
, n
->file
, direction
);
2075 asl_file_list_free(files
);
2076 return ASL_STATUS_OK
;
2079 /* start the timer if a timeout was specified */
2080 memset(&finish
, 0, sizeof(struct timeval
));
2083 if (gettimeofday(&finish
, NULL
) == 0)
2085 finish
.tv_sec
+= (usec
/ MILLION
);
2086 finish
.tv_usec
+= (usec
% MILLION
);
2087 if (finish
.tv_usec
> MILLION
)
2089 finish
.tv_usec
-= MILLION
;
2095 /* shouldn't happen, but if gettimeofday failed we just run without a timeout */
2096 memset(&finish
, 0, sizeof(struct timeval
));
2101 while ((files
!= NULL
) && ((rescount
< count
) || (count
== 0)))
2104 status
= asl_file_match_next(files
->file
, query
, &m
, last_id
, direction
);
2107 if (*res
== NULL
) *res
= (aslresponse
)calloc(1, sizeof(asl_search_result_t
));
2110 asl_file_list_free(files
);
2111 return ASL_STATUS_NO_MEMORY
;
2114 if ((*res
)->msg
== NULL
) (*res
)->msg
= (asl_msg_t
**)calloc(1, sizeof(aslmsg
));
2115 else (*res
)->msg
= (asl_msg_t
**)reallocf((*res
)->msg
, ((*res
)->count
+ 1) * sizeof(aslmsg
));
2116 if ((*res
)->msg
== NULL
)
2120 asl_file_list_free(files
);
2121 return ASL_STATUS_NO_MEMORY
;
2124 (*res
)->msg
[(*res
)->count
] = (asl_msg_t
*)m
;
2129 if (files
->file
->cursor_xid
== 0)
2141 if (((direction
< 0) && (files
->file
->cursor_xid
<= n
->file
->cursor_xid
)) || ((direction
>= 0) && (files
->file
->cursor_xid
> n
->file
->cursor_xid
)))
2144 files
= files
->next
;
2146 files
= asl_file_list_insert(files
, n
->file
, direction
);
2152 /* check the timer */
2153 if ((finish
.tv_sec
!= 0) && (gettimeofday(&now
, NULL
) == 0))
2155 if ((now
.tv_sec
> finish
.tv_sec
) || ((now
.tv_sec
== finish
.tv_sec
) && (now
.tv_usec
> finish
.tv_usec
))) break;
2159 asl_file_list_free(files
);
2160 return ASL_STATUS_OK
;
2164 asl_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
)
2166 return asl_file_list_match_timeout(list
, query
, res
, last_id
, start_id
, count
, direction
, 0);