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
)
270 #if TARGET_OS_EMBEDDED
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 */
1267 if (dir
>= 0) s
->cursor
= r
.next
;
1268 else s
->cursor
= r
.prev
;
1274 off
= s
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1275 if (off
> s
->file_size
)
1281 * Next record offset is past the end of the file.
1282 * This is an error, but we allow it to fail quietly
1283 * so that the current record fetch succeeds.
1285 return ASL_STATUS_OK
;
1288 status
= fseeko(s
->store
, off
, SEEK_SET
);
1294 return ASL_STATUS_READ_FAILED
;
1297 status
= fread(&x64
, sizeof(uint64_t), 1, s
->store
);
1303 return ASL_STATUS_READ_FAILED
;
1306 s
->cursor_xid
= asl_core_ntohq(x64
);
1310 return ASL_STATUS_OK
;
1314 asl_file_open_read(const char *path
, asl_file_t
**s
)
1319 uint32_t status
, vers
, last_len
;
1320 char buf
[DB_HEADER_LEN
];
1322 asl_legacy1_t
*legacy
;
1325 memset(&sb
, 0, sizeof(struct stat
));
1326 if (stat(path
, &sb
) != 0) return ASL_STATUS_FAILED
;
1328 f
= fopen(path
, "r");
1331 if (errno
== EACCES
) return ASL_STATUS_ACCESS_DENIED
;
1332 return ASL_STATUS_FAILED
;
1335 i
= fread(buf
, DB_HEADER_LEN
, 1, f
);
1339 return ASL_STATUS_INVALID_STORE
;
1342 /* validate header */
1343 if (strncmp(buf
, ASL_DB_COOKIE
, ASL_DB_COOKIE_LEN
))
1346 return ASL_STATUS_INVALID_STORE
;
1351 vers
= _asl_get_32(buf
+ DB_HEADER_VERS_OFFSET
);
1352 if (vers
== DB_VERSION_LEGACY_1
)
1355 status
= asl_legacy1_open(path
, &legacy
);
1356 if (status
!= ASL_STATUS_OK
) return status
;
1359 out
= (asl_file_t
*)calloc(1, sizeof(asl_file_t
));
1363 return ASL_STATUS_NO_MEMORY
;
1367 out
->flags
= ASL_FILE_FLAG_READ_ONLY
;
1368 out
->version
= vers
;
1372 out
->flags
|= ASL_FILE_FLAG_LEGACY_STORE
;
1373 out
->legacy
= (void *)legacy
;
1376 return ASL_STATUS_OK
;
1379 out
->first
= _asl_get_64(buf
+ DB_HEADER_FIRST_OFFSET
);
1380 out
->last
= _asl_get_64(buf
+ DB_HEADER_LAST_OFFSET
);
1381 out
->file_size
= (size_t)sb
.st_size
;
1384 * Detect bogus last pointer and check for odd-sized files.
1385 * Setting out->last to zero forces us to follow the linked
1386 * list of records in the file to the last record. That's
1387 * done in the set_position code. It's a bit slower, but it's
1388 * better at preventing crashes in corrupt files.
1391 /* records are at least MSG_RECORD_FIXED_LENGTH bytes */
1392 if ((out
->last
+ MSG_RECORD_FIXED_LENGTH
) > out
->file_size
)
1398 /* read last record length and make sure the file is at least that large */
1399 off
= out
->last
+ RECORD_TYPE_LEN
;
1400 status
= asl_file_read_uint32(out
, off
, &last_len
);
1401 if (status
!= ASL_STATUS_OK
)
1408 if ((out
->last
+ last_len
) > out
->file_size
) out
->last
= 0;
1411 out
->cursor
= out
->first
;
1412 if (out
->cursor
!= 0)
1414 off
= out
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1415 status
= asl_file_read_uint64(out
, off
, &(out
->cursor_xid
));
1416 if (status
!= ASL_STATUS_OK
)
1425 return ASL_STATUS_OK
;
1429 asl_file_read_set_position_first(asl_file_t
*s
)
1434 s
->cursor
= s
->first
;
1437 if (s
->cursor
== 0) return ASL_STATUS_OK
;
1439 /* read ID of the first record */
1440 off
= s
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1441 status
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
));
1446 asl_file_read_set_position_last(asl_file_t
*s
)
1453 * If the file has the offset of the last record, we just go there.
1454 * The last record offset was added to improve performance, so it may
1455 * or may not be there. If we don't have the last record offset, we
1456 * just iterate down the record links to find the last one.
1458 * Note that s->last may be zero if the file is empty.
1463 s
->cursor
= s
->last
;
1464 off
= s
->last
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1466 /* read ID of the last record */
1467 status
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
));
1471 /* start at the first record and iterate */
1472 s
->cursor
= s
->first
;
1477 off
= s
->cursor
+ RECORD_COMMON_LEN
;
1480 /* read next offset */
1481 status
= asl_file_read_uint64(s
, off
, &next
);
1482 if (status
!= ASL_STATUS_OK
) return status
;
1484 /* detect bogus next pointer */
1485 if (((next
+ MSG_RECORD_FIXED_LENGTH
) > s
->file_size
) || (next
<= s
->cursor
)) next
= 0;
1489 if (s
->cursor
== 0) return ASL_STATUS_OK
;
1491 off
= s
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1492 status
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
));
1493 return ASL_STATUS_OK
;
1501 asl_file_read_set_position(asl_file_t
*s
, uint32_t pos
)
1504 uint32_t len
, status
;
1507 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1508 if (s
->version
== 1) return ASL_STATUS_FAILED
;
1510 if (pos
== ASL_FILE_POSITION_FIRST
) return asl_file_read_set_position_first(s
);
1511 if (pos
== ASL_FILE_POSITION_LAST
) return asl_file_read_set_position_last(s
);
1515 if (pos
== ASL_FILE_POSITION_PREVIOUS
)
1517 if (s
->cursor
== s
->first
) return ASL_STATUS_NO_RECORDS
;
1518 if (s
->cursor
== 0) return ASL_STATUS_NO_RECORDS
;
1520 off
= s
->cursor
+ RECORD_TYPE_LEN
;
1521 status
= asl_file_read_uint32(s
, off
, &len
);
1522 if (status
!= ASL_STATUS_OK
) return status
;
1524 /* set offset to read the "previous" field at the end of the record */
1525 off
= s
->cursor
+ RECORD_COMMON_LEN
+ len
- sizeof(uint64_t);
1527 else if (pos
== ASL_FILE_POSITION_NEXT
)
1529 if (s
->cursor
== s
->last
) return ASL_STATUS_NO_RECORDS
;
1530 if (s
->cursor
== 0) return ASL_STATUS_NO_RECORDS
;
1532 /* set offset to read the "next" field in the current record */
1533 off
= s
->cursor
+ RECORD_COMMON_LEN
;
1535 else return ASL_STATUS_INVALID_ARG
;
1540 * read offset of next / previous
1543 status
= asl_file_read_uint64(s
, off
, &next
);
1544 if (status
!= ASL_STATUS_OK
) return ASL_STATUS_READ_FAILED
;
1546 /* detect bogus next pointer */
1547 if ((next
+ MSG_RECORD_FIXED_LENGTH
) > s
->file_size
) next
= 0;
1548 else if ((pos
== ASL_FILE_POSITION_PREVIOUS
) && (next
>= s
->cursor
)) next
= 0;
1549 else if ((pos
== ASL_FILE_POSITION_NEXT
) && (next
<= s
->cursor
)) next
= 0;
1552 if (s
->cursor
== 0) return ASL_STATUS_NO_RECORDS
;
1554 /* read ID of the record */
1555 off
= s
->cursor
+ RECORD_COMMON_LEN
+ sizeof(uint64_t);
1556 status
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
));
1561 asl_file_fetch_next(asl_file_t
*s
, aslmsg
*msg
)
1563 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1564 if (s
->version
== 1) return ASL_STATUS_FAILED
;
1566 return asl_file_fetch_pos(s
, s
->cursor
, 1, msg
);
1570 asl_file_fetch_previous(asl_file_t
*s
, aslmsg
*msg
)
1572 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1573 if (s
->version
== 1) return ASL_STATUS_FAILED
;
1575 return asl_file_fetch_pos(s
, s
->cursor
, -1, msg
);
1579 asl_file_fetch(asl_file_t
*s
, uint64_t mid
, aslmsg
*msg
)
1583 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1584 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
1585 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return ASL_STATUS_WRITE_ONLY
;
1587 if (s
->version
== 1)
1589 return asl_legacy1_fetch((asl_legacy1_t
*)s
->legacy
, mid
, msg
);
1592 if (s
->cursor_xid
== 0)
1594 status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
);
1595 if (status
!= ASL_STATUS_OK
) return status
;
1596 if (s
->cursor_xid
== 0) return ASL_STATUS_INVALID_ID
;
1599 while (s
->cursor_xid
< mid
)
1601 status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_NEXT
);
1602 if (status
!= ASL_STATUS_OK
) return status
;
1603 if (s
->cursor_xid
> mid
) return ASL_STATUS_INVALID_ID
;
1604 if (s
->cursor_xid
== 0) return ASL_STATUS_INVALID_ID
;
1607 while (s
->cursor_xid
> mid
)
1609 status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_PREVIOUS
);
1610 if (status
!= ASL_STATUS_OK
) return status
;
1611 if (s
->cursor_xid
< mid
) return ASL_STATUS_INVALID_ID
;
1612 if (s
->cursor_xid
== 0) return ASL_STATUS_INVALID_ID
;
1615 if (s
->cursor_xid
!= mid
) return ASL_STATUS_INVALID_ID
;
1617 return asl_file_fetch_pos(s
, s
->cursor
, 1, msg
);
1620 __private_extern__
uint64_t
1621 asl_file_cursor(asl_file_t
*s
)
1623 if (s
== NULL
) return 0;
1624 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return 0;
1625 if (s
->version
== 1) return 0;
1627 return s
->cursor_xid
;
1630 __private_extern__
uint32_t
1631 asl_file_match_start(asl_file_t
*s
, uint64_t start_id
, int32_t direction
)
1635 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1636 if (s
->version
== 1) return ASL_STATUS_INVALID_STORE
;
1637 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return ASL_STATUS_WRITE_ONLY
;
1639 d
= ASL_FILE_POSITION_NEXT
;
1640 if (direction
< 0) d
= ASL_FILE_POSITION_PREVIOUS
;
1643 * find starting point
1645 status
= ASL_STATUS_OK
;
1646 if (direction
>= 0) status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
);
1647 else status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_LAST
);
1648 if (status
!= ASL_STATUS_OK
) return status
;
1650 while ((status
== ASL_STATUS_OK
) && (((direction
>= 0) && (s
->cursor_xid
< start_id
)) || ((direction
< 0) && (s
->cursor_xid
> start_id
))))
1652 status
= asl_file_read_set_position(s
, d
);
1658 __private_extern__
uint32_t
1659 asl_file_match_next(asl_file_t
*s
, aslresponse query
, aslmsg
*msg
, uint64_t *last_id
, int32_t direction
)
1661 uint32_t status
, d
, i
, do_match
, did_match
;
1664 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1665 if (msg
== NULL
) return ASL_STATUS_INVALID_ARG
;
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
;
1668 if (s
->cursor
== 0) return ASL_STATUS_NO_RECORDS
;
1673 d
= ASL_FILE_POSITION_NEXT
;
1674 if (direction
< 0) d
= ASL_FILE_POSITION_PREVIOUS
;
1676 if ((query
== NULL
) || ((query
!= NULL
) && (query
->count
== 0))) do_match
= 0;
1680 *last_id
= s
->cursor_xid
;
1682 status
= asl_file_fetch_pos(s
, s
->cursor
, direction
, &m
);
1683 if (status
== ASL_STATUS_ACCESS_DENIED
) return ASL_STATUS_MATCH_FAILED
;
1684 if ((status
== ASL_STATUS_INVALID_ARG
) && (s
->cursor
== 0)) return ASL_STATUS_NO_RECORDS
;
1685 if (status
!= ASL_STATUS_OK
) return status
;
1693 for (i
= 0; (i
< query
->count
) && (did_match
== 0); i
++)
1695 did_match
= asl_msg_cmp((aslmsg
)(query
->msg
[i
]), m
);
1702 return ASL_STATUS_OK
;
1706 return ASL_STATUS_MATCH_FAILED
;
1710 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
)
1712 uint32_t status
, d
, i
, do_match
, did_match
, rescount
;
1715 if (s
== NULL
) return ASL_STATUS_INVALID_STORE
;
1716 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
1717 if ((s
->flags
& ASL_FILE_FLAG_READ_ONLY
) == 0) return ASL_STATUS_WRITE_ONLY
;
1719 if (s
->version
== 1)
1721 return asl_legacy1_match((asl_legacy1_t
*)s
->legacy
, query
, res
, last_id
, start_id
, count
, direction
);
1727 d
= ASL_FILE_POSITION_NEXT
;
1728 if (direction
< 0) d
= ASL_FILE_POSITION_PREVIOUS
;
1730 if ((query
== NULL
) || ((query
!= NULL
) && (query
->count
== 0))) do_match
= 0;
1733 * find starting point
1735 status
= ASL_STATUS_OK
;
1736 if (direction
>= 0) status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
);
1737 else status
= asl_file_read_set_position(s
, ASL_FILE_POSITION_LAST
);
1738 if (status
!= ASL_STATUS_OK
) return status
;
1740 while ((status
== ASL_STATUS_OK
) && (((direction
>= 0) && (s
->cursor_xid
< start_id
)) || ((direction
< 0) && (s
->cursor_xid
> start_id
))))
1742 status
= asl_file_read_set_position(s
, d
);
1746 * loop through records
1751 status
= asl_file_fetch_pos(s
, s
->cursor
, direction
, &m
);
1752 if (status
== ASL_STATUS_ACCESS_DENIED
) continue;
1753 if (status
!= ASL_STATUS_OK
) break;
1755 *last_id
= s
->cursor_xid
;
1763 for (i
= 0; (i
< query
->count
) && (did_match
== 0); i
++)
1765 did_match
= asl_msg_cmp((aslmsg
)query
->msg
[i
], m
);
1771 /* append m to res */
1774 *res
= (aslresponse
)calloc(1, sizeof(aslresponse
));
1775 if (*res
== NULL
) return ASL_STATUS_NO_MEMORY
;
1776 (*res
)->msg
= (asl_msg_t
**)calloc(1, sizeof(aslmsg
));
1777 if ((*res
)->msg
== NULL
)
1780 return ASL_STATUS_NO_MEMORY
;
1785 (*res
)->msg
= (asl_msg_t
**)reallocf((*res
)->msg
, ((*res
)->count
+ 1) * sizeof(aslmsg
));
1786 if ((*res
)->msg
== NULL
)
1789 return ASL_STATUS_NO_MEMORY
;
1793 (*res
)->msg
[(*res
)->count
] = (asl_msg_t
*)m
;
1797 if ((count
!= 0) && (rescount
>= count
)) break;
1806 return ASL_STATUS_OK
;
1810 asl_file_size(asl_file_t
*s
)
1812 if (s
== NULL
) return 0;
1813 return s
->file_size
;
1817 asl_file_ctime(asl_file_t
*s
)
1819 if (s
== NULL
) return 0;
1824 asl_file_list_close(asl_file_list_t
*head
)
1826 asl_file_list_t
*next
;
1828 while (head
!= NULL
)
1831 asl_file_close(head
->file
);
1838 asl_file_list_free(asl_file_list_t
*head
)
1840 asl_file_list_t
*next
;
1842 while (head
!= NULL
)
1850 static asl_file_list_t
*
1851 asl_file_list_insert(asl_file_list_t
*list
, asl_file_t
*f
, int32_t dir
)
1853 asl_file_list_t
*a
, *b
, *tmp
;
1855 if (f
== NULL
) return list
;
1857 tmp
= (asl_file_list_t
*)calloc(1, sizeof(asl_file_list_t
));
1858 if (tmp
== NULL
) return NULL
;
1861 if (list
== NULL
) return tmp
;
1864 if (((dir
< 0) && (f
->cursor_xid
> a
->file
->cursor_xid
)) || ((dir
>= 0) && (f
->cursor_xid
< a
->file
->cursor_xid
)))
1873 if (((dir
< 0) && (f
->cursor_xid
> b
->file
->cursor_xid
)) || ((dir
>= 0) && (f
->cursor_xid
< b
->file
->cursor_xid
)))
1889 asl_file_list_add(asl_file_list_t
*list
, asl_file_t
*f
)
1891 asl_file_list_t
*tmp
;
1893 if (f
== NULL
) return list
;
1894 if (f
->version
== 1) return list
;
1896 tmp
= (asl_file_list_t
*)calloc(1, sizeof(asl_file_list_t
));
1897 if (tmp
== NULL
) return NULL
;
1905 asl_file_list_match_start(asl_file_list_t
*list
, uint64_t start_id
, int32_t direction
)
1909 asl_file_match_token_t
*out
;
1911 if (list
== NULL
) return NULL
;
1913 out
= (asl_file_match_token_t
*)calloc(1, sizeof(asl_file_match_token_t
));
1914 if (out
== NULL
) return NULL
;
1916 for (n
= list
; n
!= NULL
; n
= n
->next
)
1918 /* init file for the search */
1919 status
= asl_file_match_start(n
->file
, start_id
, direction
);
1920 if (status
!= ASL_STATUS_OK
) continue;
1921 if (n
->file
->cursor_xid
== 0) continue;
1923 out
->list
= asl_file_list_insert(out
->list
, n
->file
, direction
);
1926 out
->dir
= direction
;
1931 asl_file_list_match_next(void *token
, aslresponse query
, aslresponse
*res
, uint32_t count
)
1933 uint32_t status
, rescount
;
1936 asl_file_match_token_t
*work
;
1939 if (token
== NULL
) return ASL_STATUS_OK
;
1940 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
1942 work
= (asl_file_match_token_t
*)token
;
1947 while ((work
->list
!= NULL
) && ((rescount
< count
) || (count
== 0)))
1950 status
= asl_file_match_next(work
->list
->file
, query
, &m
, &last_id
, work
->dir
);
1953 if (*res
== NULL
) *res
= (aslresponse
)calloc(1, sizeof(asl_search_result_t
));
1956 asl_file_list_free(work
->list
);
1958 return ASL_STATUS_NO_MEMORY
;
1961 if ((*res
)->msg
== NULL
) (*res
)->msg
= (asl_msg_t
**)calloc(1, sizeof(aslmsg
));
1962 else (*res
)->msg
= (asl_msg_t
**)reallocf((*res
)->msg
, ((*res
)->count
+ 1) * sizeof(aslmsg
));
1963 if ((*res
)->msg
== NULL
)
1967 asl_file_list_free(work
->list
);
1969 return ASL_STATUS_NO_MEMORY
;
1972 (*res
)->msg
[(*res
)->count
] = (asl_msg_t
*)m
;
1977 if ((status
!= ASL_STATUS_OK
) || (work
->list
->file
->cursor_xid
== 0))
1979 n
= work
->list
->next
;
1984 if (work
->list
!= NULL
)
1986 n
= work
->list
->next
;
1989 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
)))
1992 work
->list
= work
->list
->next
;
1994 work
->list
= asl_file_list_insert(work
->list
, n
->file
, work
->dir
);
2001 return ASL_STATUS_OK
;
2005 asl_file_list_match_end(void *token
)
2007 asl_file_match_token_t
*work
;
2009 if (token
== NULL
) return;
2011 work
= (asl_file_match_token_t
*)token
;
2012 asl_file_list_free(work
->list
);
2019 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
)
2021 uint32_t status
, rescount
;
2022 asl_file_list_t
*files
, *n
;
2024 struct timeval now
, finish
;
2026 if (list
== NULL
) return ASL_STATUS_INVALID_ARG
;
2027 if (res
== NULL
) return ASL_STATUS_INVALID_ARG
;
2028 if (last_id
== NULL
) return ASL_STATUS_INVALID_ARG
;
2032 for (n
= list
; n
!= NULL
; n
= n
->next
)
2034 /* init file for the search */
2035 status
= asl_file_match_start(n
->file
, start_id
, direction
);
2036 if (status
!= ASL_STATUS_OK
) continue;
2037 if (n
->file
->cursor_xid
== 0) continue;
2039 files
= asl_file_list_insert(files
, n
->file
, direction
);
2044 asl_file_list_free(files
);
2045 return ASL_STATUS_OK
;
2048 /* start the timer if a timeout was specified */
2049 memset(&finish
, 0, sizeof(struct timeval
));
2052 if (gettimeofday(&finish
, NULL
) == 0)
2054 finish
.tv_sec
+= (usec
/ MILLION
);
2055 finish
.tv_usec
+= (usec
% MILLION
);
2056 if (finish
.tv_usec
> MILLION
)
2058 finish
.tv_usec
-= MILLION
;
2064 /* shouldn't happen, but if gettimeofday failed we just run without a timeout */
2065 memset(&finish
, 0, sizeof(struct timeval
));
2070 while ((files
!= NULL
) && ((rescount
< count
) || (count
== 0)))
2073 status
= asl_file_match_next(files
->file
, query
, &m
, last_id
, direction
);
2076 if (*res
== NULL
) *res
= (aslresponse
)calloc(1, sizeof(asl_search_result_t
));
2079 asl_file_list_free(files
);
2080 return ASL_STATUS_NO_MEMORY
;
2083 if ((*res
)->msg
== NULL
) (*res
)->msg
= (asl_msg_t
**)calloc(1, sizeof(aslmsg
));
2084 else (*res
)->msg
= (asl_msg_t
**)reallocf((*res
)->msg
, ((*res
)->count
+ 1) * sizeof(aslmsg
));
2085 if ((*res
)->msg
== NULL
)
2089 asl_file_list_free(files
);
2090 return ASL_STATUS_NO_MEMORY
;
2093 (*res
)->msg
[(*res
)->count
] = (asl_msg_t
*)m
;
2098 if (files
->file
->cursor_xid
== 0)
2110 if (((direction
< 0) && (files
->file
->cursor_xid
<= n
->file
->cursor_xid
)) || ((direction
>= 0) && (files
->file
->cursor_xid
> n
->file
->cursor_xid
)))
2113 files
= files
->next
;
2115 files
= asl_file_list_insert(files
, n
->file
, direction
);
2121 /* check the timer */
2122 if ((finish
.tv_sec
!= 0) && (gettimeofday(&now
, NULL
) == 0))
2124 if ((now
.tv_sec
> finish
.tv_sec
) || ((now
.tv_sec
== finish
.tv_sec
) && (now
.tv_usec
> finish
.tv_usec
))) break;
2128 asl_file_list_free(files
);
2129 return ASL_STATUS_OK
;
2133 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
)
2135 return asl_file_list_match_timeout(list
, query
, res
, last_id
, start_id
, count
, direction
, 0);