2  * Copyright (c) 2007-2013 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@ 
  33 #include <sys/errno.h> 
  36 #include <sys/types.h> 
  38 #include <membership.h> 
  41 #include <asl_private.h> 
  42 #include <asl_legacy1.h> 
  43 #include <TargetConditionals.h> 
  45 #define forever for(;;) 
  48  * MSG and STR records have (at least) a type (uint16_t) and a length (uint32_t) 
  49  * type and level are both 16 bit fields so that alignment isn't a pain. 
  51 #define RECORD_COMMON_LEN 6 
  52 #define RECORD_TYPE_LEN 2 
  53 #define BUFFER_OFFSET_KVCOUNT 56 
  55 #define SCRATCH_BUFFER_SIZE (MSG_RECORD_FIXED_LENGTH + (20 * sizeof(uint64_t))) 
  83         asl_file_list_t 
*list
; 
  85 } asl_file_match_token_t
; 
  97 _asl_put_16(uint16_t i
, char *h
) 
 115 _asl_put_32(uint32_t i
, char *h
) 
 129         return asl_core_ntohq(x
); 
 133 _asl_put_64(uint64_t i
, char *h
) 
 137         x 
= asl_core_htonq(i
); 
 142 asl_file_read_uint32(asl_file_t 
*s
, off_t off
, uint32_t *out
) 
 144         uint32_t status
, val
; 
 146         if (s 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
 147         if (s
->store 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
 148         if ((off 
+ sizeof(uint32_t)) > s
->file_size
) return ASL_STATUS_READ_FAILED
; 
 150         status 
= fseeko(s
->store
, off
, SEEK_SET
); 
 151         if (status 
!= 0) return ASL_STATUS_READ_FAILED
; 
 155         status 
= fread(&val
, sizeof(uint32_t), 1, s
->store
); 
 156         if (status 
!= 1) return ASL_STATUS_READ_FAILED
; 
 158         if (out 
!= NULL
) *out 
= ntohl(val
); 
 159         return ASL_STATUS_OK
; 
 163 asl_file_read_uint64(asl_file_t 
*s
, off_t off
, uint64_t *out
) 
 168         if (s 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
 169         if (s
->store 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
 170         if ((off 
+ sizeof(uint64_t)) > s
->file_size
) return ASL_STATUS_READ_FAILED
; 
 172         status 
= fseeko(s
->store
, off
, SEEK_SET
); 
 173         if (status 
!= 0) return ASL_STATUS_READ_FAILED
; 
 177         status 
= fread(&val
, sizeof(uint64_t), 1, s
->store
); 
 178         if (status 
!= 1) return ASL_STATUS_READ_FAILED
; 
 180         if (out 
!= NULL
) *out 
= asl_core_ntohq(val
); 
 181         return ASL_STATUS_OK
; 
 184 static file_string_t 
* 
 185 file_string_create(asl_file_t 
*s
) 
 187         if ((s 
!= NULL
) && (s
->string_spare 
!= NULL
)) 
 189                 file_string_t 
*out 
= s
->string_spare
; 
 190                 s
->string_spare 
= NULL
; 
 194         return (file_string_t 
*)calloc(1, sizeof(file_string_t
)); 
 198 file_string_dispose(asl_file_t 
*s
, file_string_t 
*x
) 
 200         if ((s 
!= NULL
) && (s
->string_spare 
== NULL
)) 
 203                 memset(s
->string_spare
, 0, sizeof(file_string_t
)); 
 213 asl_file_retain(asl_file_t 
*s
) 
 215         if (s 
== NULL
) return NULL
; 
 216         asl_retain((asl_object_t
)s
); 
 221 asl_file_release(asl_file_t 
*s
) 
 223         if (s 
== NULL
) return; 
 224         asl_release((asl_object_t
)s
); 
 228 asl_file_close(asl_file_t 
*s
) 
 230         if (s 
== NULL
) return ASL_STATUS_OK
; 
 231         asl_release((asl_object_t
)s
); 
 232         return ASL_STATUS_OK
; 
 236 _asl_file_free_internal(asl_file_t 
*s
) 
 240         if (s 
== NULL
) return; 
 244                 asl_legacy1_close((asl_legacy1_t 
*)s
->legacy
); 
 248         while (s
->string_list 
!= NULL
) 
 250                 x 
= s
->string_list
->next
; 
 251                 free(s
->string_list
); 
 255         free(s
->string_spare
); 
 257         if (s
->store 
!= NULL
) fclose(s
->store
); 
 258         if (s
->scratch 
!= NULL
) free(s
->scratch
); 
 260         memset(s
, 0, sizeof(asl_file_t
)); 
 264 __private_extern__ ASL_STATUS
 
 265 asl_file_open_write_fd(int fd
, asl_file_t 
**s
) 
 269         char buf
[DB_HEADER_LEN
]; 
 272         if (fd 
< 0) return ASL_STATUS_FAILED
; 
 273         if (s 
== NULL
) return ASL_STATUS_FAILED
; 
 275         out 
= (asl_file_t 
*)calloc(1, sizeof(asl_file_t
)); 
 276         if (out 
== NULL
) return ASL_STATUS_NO_MEMORY
; 
 278         out
->asl_type 
= ASL_TYPE_FILE
; 
 281         out
->store 
= fdopen(fd
, "w+"); 
 282         if (out
->store 
== NULL
) 
 285                 return ASL_STATUS_FAILED
; 
 288         memset(buf
, 0, sizeof(buf
)); 
 289         memcpy(buf
, ASL_DB_COOKIE
, ASL_DB_COOKIE_LEN
); 
 291         _asl_put_32(DB_VERSION
, buf 
+ DB_HEADER_VERS_OFFSET
); 
 295         _asl_put_64(out
->dob
, buf 
+ DB_HEADER_TIME_OFFSET
); 
 297         _asl_put_32(CACHE_SIZE
, buf 
+ DB_HEADER_CSIZE_OFFSET
); 
 299         status 
= fwrite(buf
, sizeof(buf
), 1, out
->store
); 
 304                 return ASL_STATUS_FAILED
; 
 310         out
->file_size 
= sizeof(buf
); 
 312         /* scratch buffer for file writes (we test for NULL before using it) */ 
 313         out
->scratch 
= malloc(SCRATCH_BUFFER_SIZE
); 
 317         return ASL_STATUS_OK
; 
 320 __private_extern__ 
int 
 321 asl_file_create(const char *path
, uid_t uid
, gid_t gid
, mode_t mode
) 
 324         return open(path
, O_RDWR 
| O_CREAT 
| O_EXCL
, mode
); 
 333         /* -1 means don't set ACL for uid or gid */ 
 334         if ((uid 
== -1) && (gid 
== -1)) 
 336                 return open(path
, O_RDWR 
| O_CREAT 
| O_EXCL
, mode
); 
 341         if ((gid 
!= 0) && (gid 
!= -1)) 
 343                 status 
= mbr_gid_to_uuid(gid
, uuid
); 
 344                 if (status 
!= 0) goto asl_file_create_return
; 
 346                 status 
= acl_create_entry_np(&acl
, &entry
, ACL_FIRST_ENTRY
); 
 347                 if (status 
!= 0) goto asl_file_create_return
; 
 349                 status 
= acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
); 
 350                 if (status 
!= 0) goto asl_file_create_return
; 
 352                 status 
= acl_set_qualifier(entry
, &uuid
); 
 353                 if (status 
!= 0) goto asl_file_create_return
; 
 355                 status 
= acl_get_permset(entry
, &perms
); 
 356                 if (status 
!= 0) goto asl_file_create_return
; 
 358                 status 
= acl_add_perm(perms
, ACL_READ_DATA
); 
 359                 if (status 
!= 0) goto asl_file_create_return
; 
 362         if ((uid 
!= 0) && (uid 
!= -1)) 
 364                 status 
= mbr_uid_to_uuid(uid
, uuid
); 
 365                 if (status 
!= 0) goto asl_file_create_return
; 
 367                 status 
= acl_create_entry_np(&acl
, &entry
, ACL_FIRST_ENTRY
); 
 368                 if (status 
!= 0) goto asl_file_create_return
; 
 370                 status 
= acl_set_tag_type(entry
, ACL_EXTENDED_ALLOW
); 
 371                 if (status 
!= 0) goto asl_file_create_return
; 
 373                 status 
= acl_set_qualifier(entry
, &uuid
); 
 374                 if (status 
!= 0) goto asl_file_create_return
; 
 376                 status 
= acl_get_permset(entry
, &perms
); 
 377                 if (status 
!= 0) goto asl_file_create_return
; 
 379                 status 
= acl_add_perm(perms
, ACL_READ_DATA
); 
 380                 if (status 
!= 0) goto asl_file_create_return
; 
 383         fd 
= open(path
, O_RDWR 
| O_CREAT 
| O_EXCL
, mode
); 
 384         if (fd 
< 0) goto asl_file_create_return
; 
 386         status 
= acl_set_fd(fd
, acl
); 
 394 asl_file_create_return
: 
 402 asl_file_open_write(const char *path
, mode_t mode
, uid_t uid
, gid_t gid
, asl_file_t 
**s
) 
 406         char buf
[DB_HEADER_LEN
]; 
 408         uint32_t aslstatus
, vers
, last_len
; 
 411         memset(&sb
, 0, sizeof(struct stat
)); 
 413         status 
= stat(path
, &sb
); 
 416                 /* must be a plain file */ 
 417                 if (!S_ISREG(sb
.st_mode
)) return ASL_STATUS_INVALID_STORE
; 
 420                  * If the file exists, we go with the existing mode, uid, and gid. 
 425                         fd 
= open(path
, O_RDWR 
| O_EXCL
, mode
); 
 426                         if (fd 
< 0) return ASL_STATUS_FAILED
; 
 428                         return asl_file_open_write_fd(fd
, s
); 
 432                         out 
= (asl_file_t 
*)calloc(1, sizeof(asl_file_t
)); 
 433                         if (out 
== NULL
) return ASL_STATUS_NO_MEMORY
; 
 435                         out
->asl_type 
= ASL_TYPE_FILE
; 
 438                         out
->store 
= fopen(path
, "r+"); 
 439                         if (out
->store 
== NULL
) 
 442                                 return ASL_STATUS_FAILED
; 
 445                         i 
= fread(buf
, DB_HEADER_LEN
, 1, out
->store
); 
 449                                 return ASL_STATUS_READ_FAILED
; 
 453                         if (strncmp(buf
, ASL_DB_COOKIE
, ASL_DB_COOKIE_LEN
)) 
 456                                 return ASL_STATUS_INVALID_STORE
; 
 460                         vers 
= _asl_get_32(buf 
+ DB_HEADER_VERS_OFFSET
); 
 461                         if (vers 
!= DB_VERSION
) 
 464                                 return ASL_STATUS_INVALID_STORE
; 
 467                         out
->dob 
= _asl_get_64(buf 
+ DB_HEADER_TIME_OFFSET
); 
 468                         out
->first 
= _asl_get_64(buf 
+ DB_HEADER_FIRST_OFFSET
); 
 469                         out
->last 
= _asl_get_64(buf 
+ DB_HEADER_LAST_OFFSET
); 
 470                         out
->file_size 
= (size_t)sb
.st_size
; 
 473                          * Detect bogus last pointer and check for odd-sized files. 
 474                          * Setting out->last to zero forces asl_file_read_set_position to 
 475                          * follow the linked list of records in the file to the last record. 
 476                          * It's slower, but it's better at preventing crashes in corrupt files. 
 479                         /* records are at least MSG_RECORD_FIXED_LENGTH bytes */ 
 480                         if ((out
->last 
+ MSG_RECORD_FIXED_LENGTH
) > out
->file_size
) 
 486                                 /* read last record length and make sure the file is at least that large */ 
 487                                 off 
= out
->last 
+ RECORD_TYPE_LEN
; 
 488                                 status 
= asl_file_read_uint32(out
, off
, &last_len
); 
 489                                 if (status 
!= ASL_STATUS_OK
) 
 495                                 if ((out
->last 
+ last_len
) > out
->file_size
) out
->last 
= 0; 
 500                                 /* skip type (uint16_t), len (uint32_t), and next (uint64_t) */ 
 501                                 off 
= out
->last 
+ sizeof(uint16_t) + sizeof (uint32_t) + sizeof(uint64_t); 
 502                                 status 
= asl_file_read_uint64(out
, off
, &(out
->last_mid
)); 
 503                                 if (status 
!= ASL_STATUS_OK
) 
 510                         aslstatus 
= asl_file_read_set_position(out
, ASL_FILE_POSITION_LAST
); 
 511                         if (aslstatus 
!= ASL_STATUS_OK
) 
 517                         out
->prev 
= out
->cursor
; 
 518                         status 
= fseeko(out
->store
, 0, SEEK_END
); 
 522                                 return ASL_STATUS_READ_FAILED
; 
 525                         out
->file_size 
= (size_t)ftello(out
->store
); 
 527                         /* scratch buffer for file writes (we test for NULL before using it) */ 
 528                         out
->scratch 
= malloc(SCRATCH_BUFFER_SIZE
); 
 532                         return ASL_STATUS_OK
; 
 535         else if (errno 
!= ENOENT
) 
 537                 /* unexpected status */ 
 538                 return ASL_STATUS_FAILED
; 
 542          * If the file does not exist, we set the mode, uid, and gid. 
 545         fd 
= asl_file_create(path
, uid
, gid
, mode
); 
 546         if (fd 
< 0) return ASL_STATUS_FAILED
; 
 548         aslstatus 
= asl_file_open_write_fd(fd
, s
); 
 549         if (aslstatus 
!= ASL_STATUS_OK
) unlink(path
); 
 555 asl_file_compact(asl_file_t 
*s
, const char *path
, mode_t mode
, uid_t uid
, gid_t gid
) 
 563         if (s 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
 564         if (path 
== NULL
) return ASL_STATUS_INVALID_ARG
; 
 566         if (s
->version 
== 1) return ASL_STATUS_FAILED
; 
 568         memset(&sb
, 0, sizeof(struct stat
)); 
 570         if (stat(path
, &sb
) == 0) return ASL_STATUS_FAILED
; 
 571         if (errno 
!= ENOENT
) return ASL_STATUS_FAILED
; 
 573         status 
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
); 
 574         if (status 
!= ASL_STATUS_OK
) return status
; 
 577         status 
= asl_file_open_write(path
, mode
, uid
, gid
, &new); 
 578         if (status 
!= ASL_STATUS_OK
) return status
; 
 579         new->flags 
= ASL_FILE_FLAG_UNLIMITED_CACHE 
| ASL_FILE_FLAG_PRESERVE_MSG_ID
; 
 581         while ((status 
== ASL_STATUS_OK
) && (s
->cursor 
!= 0)) 
 584                 status 
= asl_file_fetch_next(s
, &m
); 
 585                 if (status 
!= ASL_STATUS_OK
) break; 
 588                 status 
= asl_file_save(new, m
, &xid
); 
 597 asl_file_filter(asl_file_t 
*s
, const char *path
, asl_msg_list_t 
*filter
, uint32_t flags
, mode_t mode
, uid_t uid
, gid_t gid
, uint32_t *dstcount
, void (*aux_callback
)(const char *auxfile
)) 
 603         uint32_t status
, n 
= 0; 
 604         uint32_t matchflag 
= flags 
& ASL_FILE_FILTER_FLAG_KEEP_MATCHES
; 
 606         if (dstcount 
!= NULL
) *dstcount 
= n
; 
 608         if (s 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
 609         if (path 
== NULL
) return ASL_STATUS_INVALID_ARG
; 
 611         if (s
->version 
== 1) return ASL_STATUS_FAILED
; 
 613         memset(&sb
, 0, sizeof(struct stat
)); 
 615         if (stat(path
, &sb
) == 0) return ASL_STATUS_FAILED
; 
 616         if (errno 
!= ENOENT
) return ASL_STATUS_FAILED
; 
 618         status 
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
); 
 619         if (status 
!= ASL_STATUS_OK
) return status
; 
 622         status 
= asl_file_open_write(path
, mode
, uid
, gid
, &new); 
 623         if (status 
!= ASL_STATUS_OK
) return status
; 
 624         new->flags 
= ASL_FILE_FLAG_UNLIMITED_CACHE 
| ASL_FILE_FLAG_PRESERVE_MSG_ID
; 
 626         while ((status 
== ASL_STATUS_OK
) && (s
->cursor 
!= 0)) 
 629                 status 
= asl_file_fetch_next(s
, &m
); 
 630                 if (status 
!= ASL_STATUS_OK
) break; 
 633                  * asl_msg_cmp_list is supposed to return 1 for a match, 0 otherwise, 
 634                  * but just to be sure we only get a 1 or zero, we do an extra test. 
 636                 uint32_t msgmatch 
= (asl_msg_cmp_list(m
, filter
) == 0) ? 0 : 1; 
 637                 if (msgmatch 
== matchflag
) 
 639                         status 
= asl_file_save(new, m
, &xid
); 
 640                         if (status 
== ASL_STATUS_OK
) n
++; 
 642                 else if (aux_callback 
!= NULL
) 
 644                         /* check for ASL_KEY_AUX_URL and pass it to callback */ 
 645                         const char *auxval 
= asl_msg_get_val_for_key(m
, ASL_KEY_AUX_URL
); 
 646                         if (auxval 
!= NULL
) aux_callback(auxval
); 
 653         if (dstcount 
!= NULL
) *dstcount 
= n
; 
 658 asl_file_filter_level(asl_file_t 
*s
, const char *path
, uint32_t keep_mask
, mode_t mode
, uid_t uid
, gid_t gid
, uint32_t *dstcount
, void (*aux_callback
)(const char *auxfile
)) 
 664         uint32_t status
, n 
= 0; 
 665         uint8_t kmcur
, kmnew
; 
 667         if (dstcount 
!= NULL
) *dstcount 
= n
; 
 669         if (s 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
 670         if (path 
== NULL
) return ASL_STATUS_INVALID_ARG
; 
 672         if (s
->version 
== 1) return ASL_STATUS_FAILED
; 
 674         memset(&sb
, 0, sizeof(struct stat
)); 
 676         if (stat(path
, &sb
) == 0) return ASL_STATUS_FAILED
; 
 677         if (errno 
!= ENOENT
) return ASL_STATUS_FAILED
; 
 681         /* get current filter mask in file's header */ 
 682         status 
= fseeko(s
->store
, DB_HEADER_FILTER_MASK_OFFSET
, SEEK_SET
); 
 683         if (status 
!= 0) return ASL_STATUS_READ_FAILED
; 
 684         fread(&kmcur
, 1, 1, s
->store
); 
 686         status 
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
); 
 687         if (status 
!= ASL_STATUS_OK
) return status
; 
 690         status 
= asl_file_open_write(path
, mode
, uid
, gid
, &new); 
 691         if (status 
!= ASL_STATUS_OK
) return status
; 
 693         new->flags 
= ASL_FILE_FLAG_UNLIMITED_CACHE 
| ASL_FILE_FLAG_PRESERVE_MSG_ID
; 
 695         while ((status 
== ASL_STATUS_OK
) && (s
->cursor 
!= 0)) 
 698                 status 
= asl_file_fetch_next(s
, &m
); 
 699                 if (status 
!= ASL_STATUS_OK
) break; 
 700                 if (m 
== NULL
) continue; 
 701                 const char *lval 
= asl_msg_get_val_for_key(m
, ASL_KEY_LEVEL
); 
 702                 if (lval 
== NULL
) continue; 
 703                 uint32_t level_bit 
= 0x01 << atoi(lval
); 
 705                 if (level_bit 
& keep_mask
) 
 707                         status 
= asl_file_save(new, m
, &xid
); 
 708                         if (status 
== ASL_STATUS_OK
) n
++; 
 710                 else if (aux_callback 
!= NULL
) 
 712                         /* check for ASL_KEY_AUX_URL and pass it to callback */ 
 713                         const char *auxval 
= asl_msg_get_val_for_key(m
, ASL_KEY_AUX_URL
); 
 714                         if (auxval 
!= NULL
) aux_callback(auxval
); 
 720         kmnew 
= kmcur 
& kmnew
; 
 721         status 
= fseeko(new->store
, DB_HEADER_FILTER_MASK_OFFSET
, SEEK_SET
); 
 722         if (status 
!= 0) return ASL_STATUS_READ_FAILED
; 
 723         fwrite(&kmnew
, 1, 1, new->store
); 
 726         if (dstcount 
!= NULL
) *dstcount 
= n
; 
 731 asl_file_string_encode(asl_file_t 
*s
, const char *str
, uint64_t *out
) 
 733         uint32_t i
, hash
, len
, x32
; 
 734         file_string_t 
*sp
, *sx
, *sl
; 
 741         if (s 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
 742         if (s
->store 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
 743         if (str 
== NULL
) return ASL_STATUS_INVALID_ARG
; 
 757                 memcpy(p 
+ 1, str
, len
); 
 758                 *out 
= asl_core_ntohq(x64
); 
 759                 return ASL_STATUS_OK
; 
 762         /* cached strings include trailing nul */ 
 765         if (len 
<= CACHE_MAX_STRING_LEN
) 
 767                 /* check the cache */ 
 768                 hash 
= asl_core_string_hash(str
, len
); 
 771                 for (sx 
= s
->string_list
; sx 
!= NULL
; sx 
= sx
->next
) 
 773                         if ((hash 
== sx
->hash
) && (!strcmp(str
, sx
->str
))) 
 775                                 /* Move this string to the head of the list */ 
 785                                 return ASL_STATUS_OK
; 
 792         off 
= ftello(s
->store
); 
 795         type 
= htons(ASL_FILE_TYPE_STR
); 
 796         i 
= fwrite(&type
, sizeof(uint16_t), 1, s
->store
); 
 797         if (i 
!= 1) return ASL_STATUS_WRITE_FAILED
; 
 799         /* Length (includes trailing nul) */ 
 801         i 
= fwrite(&x32
, sizeof(uint32_t), 1, s
->store
); 
 802         if (i 
!= 1) return ASL_STATUS_WRITE_FAILED
; 
 804         /* String data (nul terminated) */ 
 805         i 
= fwrite(str
, len
, 1, s
->store
); 
 806         if (i 
!= 1) return ASL_STATUS_WRITE_FAILED
; 
 812          * Create file_string_t and insert into the cache, but only if the 
 813          * string is small.  This prevents a huge string from eating memory. 
 814          * It's unlikely that large strings will be very re-usable. 
 816         if (len 
<= CACHE_MAX_STRING_LEN
) 
 818                 sx 
= file_string_create(s
); 
 819                 if (sx 
== NULL
) return ASL_STATUS_NO_MEMORY
; 
 823                 sx
->next 
= s
->string_list
; 
 825                 /* includes trailing nul */ 
 826                 memcpy(sx
->str
, str
, len
); 
 830                 if (((s
->flags 
& ASL_FILE_FLAG_UNLIMITED_CACHE
) == 0) && (s
->string_cache_count 
== CACHE_SIZE
)) 
 832                         /* drop last (lru) string from cache */ 
 836                         /* NB CACHE_SIZE must be > 1 */ 
 837                         while (sx
->next 
!= NULL
) 
 844                         file_string_dispose(s
, sx
); 
 848                         s
->string_cache_count
++; 
 853         return ASL_STATUS_OK
; 
 857  * Encode an asl_msg_t *as a record structure. 
 858  * Creates and caches strings. 
 860 #define KVSTACK_SIZE 128 
 863 asl_file_save(asl_file_t 
*s
, asl_msg_t 
*in
, uint64_t *mid
) 
 866         uint32_t i
, len
, x
, status
; 
 869         uint64_t kvstack
[KVSTACK_SIZE
]; 
 870         uint64_t *kvmalloc 
= NULL
; 
 874         const char *key
, *val
; 
 876         if (s 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
 877         if (s
->store 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
 878         if (in 
== NULL
) return ASL_STATUS_INVALID_MESSAGE
; 
 880         if (s
->flags 
& ASL_FILE_FLAG_READ
) return ASL_STATUS_READ_ONLY
; 
 882         msg 
= (asl_msg_t 
*)in
; 
 884         memset(&r
, 0, sizeof(file_record_t
)); 
 887         if ((mid 
!= NULL 
) && (*mid 
!= 0)) r
.mid 
= *mid
; 
 890         r
.level 
= ASL_LEVEL_DEBUG
; 
 904         for (x 
= asl_msg_fetch(msg
, 0, &key
, &val
, NULL
); x 
!= IndexNull
; x 
= asl_msg_fetch(msg
, x
, &key
, &val
, NULL
)) 
 910                 else if (!strcmp(key
, ASL_KEY_TIME
)) 
 912                         if (val 
!= NULL
) r
.time 
= asl_core_parse_time(val
, NULL
); 
 914                 else if (!strcmp(key
, ASL_KEY_TIME_NSEC
)) 
 916                         if (val 
!= NULL
) r
.nano 
= atoi(val
); 
 918                 else if (!strcmp(key
, ASL_KEY_HOST
)) 
 922                                 status 
= asl_file_string_encode(s
, val
, &(r
.host
)); 
 923                                 if (status 
!= ASL_STATUS_OK
) 
 930                 else if (!strcmp(key
, ASL_KEY_SENDER
)) 
 934                                 status 
= asl_file_string_encode(s
, val
, &(r
.sender
)); 
 935                                 if (status 
!= ASL_STATUS_OK
) 
 942                 else if (!strcmp(key
, ASL_KEY_PID
)) 
 944                         if (val 
!= NULL
) r
.pid 
= atoi(val
); 
 946                 else if (!strcmp(key
, ASL_KEY_REF_PID
)) 
 948                         if (val 
!= NULL
) r
.refpid 
= atoi(val
); 
 950                 else if (!strcmp(key
, ASL_KEY_UID
)) 
 952                         if (val 
!= NULL
) r
.uid 
= atoi(val
); 
 954                 else if (!strcmp(key
, ASL_KEY_GID
)) 
 956                         if (val 
!= NULL
) r
.gid 
= atoi(val
); 
 958                 else if (!strcmp(key
, ASL_KEY_LEVEL
)) 
 960                         if (val 
!= NULL
) r
.level 
= atoi(val
); 
 962                 else if (!strcmp(key
, ASL_KEY_MSG
)) 
 966                                 status 
= asl_file_string_encode(s
, val
, &(r
.message
)); 
 967                                 if (status 
!= ASL_STATUS_OK
) 
 974                 else if (!strcmp(key
, ASL_KEY_FACILITY
)) 
 978                                 status 
= asl_file_string_encode(s
, val
, &(r
.facility
)); 
 979                                 if (status 
!= ASL_STATUS_OK
) 
 986                 else if (!strcmp(key
, ASL_KEY_REF_PROC
)) 
 990                                 status 
= asl_file_string_encode(s
, val
, &(r
.refproc
)); 
 991                                 if (status 
!= ASL_STATUS_OK
) 
 998                 else if (!strcmp(key
, ASL_KEY_SESSION
)) 
1002                                 status 
= asl_file_string_encode(s
, val
, &(r
.session
)); 
1003                                 if (status 
!= ASL_STATUS_OK
) 
1010                 else if (!strcmp(key
, ASL_KEY_READ_UID
)) 
1012                         if (((r
.flags 
& ASL_MSG_FLAG_READ_UID_SET
) == 0) && (val 
!= NULL
)) 
1015                                 r
.flags 
|= ASL_MSG_FLAG_READ_UID_SET
; 
1018                 else if (!strcmp(key
, ASL_KEY_READ_GID
)) 
1020                         if (((r
.flags 
& ASL_MSG_FLAG_READ_GID_SET
) == 0) && (val 
!= NULL
)) 
1023                                 r
.flags 
|= ASL_MSG_FLAG_READ_GID_SET
; 
1026                 else if (!strcmp(key
, ASL_KEY_MSG_ID
)) 
1028                         if (s
->flags 
& ASL_FILE_FLAG_PRESERVE_MSG_ID
) 
1031                                 if (mid 
!= NULL
) *mid 
= r
.mid
; 
1034                 else if (!strcmp(key
, ASL_KEY_OPTION
)) 
1036                         /* ignore - we don't save ASLOption */ 
1040                         status 
= asl_file_string_encode(s
, key
, &k
); 
1041                         if (status 
!= ASL_STATUS_OK
) 
1050                                 status 
= asl_file_string_encode(s
, val
, &v
); 
1051                                 if (status 
!= ASL_STATUS_OK
) 
1058                         if (r
.kvcount 
>= KVSTACK_SIZE
) 
1060                                 /* out of space for the kvlist on the stack - fall back to malloc */ 
1061                                 kvmalloc 
= reallocf(kvmalloc
, (r
.kvcount 
+ 2) * sizeof(uint64_t)); 
1062                                 if (kvmalloc 
== NULL
) return ASL_STATUS_NO_MEMORY
; 
1066                                 if (r
.kvcount 
== KVSTACK_SIZE
) 
1068                                         /* copy kvstack to kvmalloc */ 
1069                                         for (i 
= 0; i 
< KVSTACK_SIZE
; i
++) kvmalloc
[i
] = kvstack
[i
]; 
1073                         kvlist
[r
.kvcount
++] = k
; 
1074                         kvlist
[r
.kvcount
++] = v
; 
1078         len 
= MSG_RECORD_FIXED_LENGTH 
+ (r
.kvcount 
* sizeof(uint64_t)); 
1081         /* use the scratch buffer if it exists and is large enough */ 
1082         if ((s
->scratch 
!= NULL
) && (len 
<= SCRATCH_BUFFER_SIZE
)) 
1084                 memset(s
->scratch
, 0, SCRATCH_BUFFER_SIZE
); 
1089                 buf 
= calloc(1, len
); 
1092         if (buf 
== NULL
) return ASL_STATUS_NO_MEMORY
; 
1094         if (r
.mid 
== UINT64_MAX
) 
1096                 s
->last_mid 
= s
->last_mid 
+ 1; 
1097                 r
.mid 
= s
->last_mid
; 
1103         _asl_put_16(ASL_FILE_TYPE_MSG
, p
); 
1104         p 
+= sizeof(uint16_t); 
1106         /* Length of message (excludes type and length fields) */ 
1107         _asl_put_32(len 
- RECORD_COMMON_LEN
, p
); 
1108         p 
+= sizeof(uint32_t); 
1110         /* Message data... */ 
1112         _asl_put_64(r
.next
, p
); 
1113         p 
+= sizeof(uint64_t); 
1115         _asl_put_64(r
.mid
, p
); 
1116         p 
+= sizeof(uint64_t); 
1118         _asl_put_64(r
.time
, p
); 
1119         p 
+= sizeof(uint64_t); 
1121         _asl_put_32(r
.nano
, p
); 
1122         p 
+= sizeof(uint32_t); 
1124         _asl_put_16(r
.level
, p
); 
1125         p 
+= sizeof(uint16_t); 
1127         _asl_put_16(r
.flags
, p
); 
1128         p 
+= sizeof(uint16_t); 
1130         _asl_put_32(r
.pid
, p
); 
1131         p 
+= sizeof(uint32_t); 
1133         _asl_put_32(r
.uid
, p
); 
1134         p 
+= sizeof(uint32_t); 
1136         _asl_put_32(r
.gid
, p
); 
1137         p 
+= sizeof(uint32_t); 
1139         _asl_put_32(r
.ruid
, p
); 
1140         p 
+= sizeof(uint32_t); 
1142         _asl_put_32(r
.rgid
, p
); 
1143         p 
+= sizeof(uint32_t); 
1145         _asl_put_32(r
.refpid
, p
); 
1146         p 
+= sizeof(uint32_t); 
1148         _asl_put_32(r
.kvcount
, p
); 
1149         p 
+= sizeof(uint32_t); 
1151         _asl_put_64(r
.host
, p
); 
1152         p 
+= sizeof(uint64_t); 
1154         _asl_put_64(r
.sender
, p
); 
1155         p 
+= sizeof(uint64_t); 
1157         _asl_put_64(r
.facility
, p
); 
1158         p 
+= sizeof(uint64_t); 
1160         _asl_put_64(r
.message
, p
); 
1161         p 
+= sizeof(uint64_t); 
1163         _asl_put_64(r
.refproc
, p
); 
1164         p 
+= sizeof(uint64_t); 
1166         _asl_put_64(r
.session
, p
); 
1167         p 
+= sizeof(uint64_t); 
1169         for (i 
= 0; i 
< r
.kvcount
; i
++) 
1171                 _asl_put_64(kvlist
[i
], p
); 
1172                 p 
+= sizeof(uint64_t); 
1175         _asl_put_64(r
.prev
, p
); 
1176         p 
+= sizeof(uint64_t); 
1180         /* write record at end of file */ 
1181         status 
= fseeko(s
->store
, 0, SEEK_END
); 
1182         if (status 
!= 0) return ASL_STATUS_WRITE_FAILED
; 
1184         s
->last 
= (uint64_t)ftello(s
->store
); 
1186         v 
= asl_core_htonq(s
->last
); 
1188         status 
= fwrite(buf
, len
, 1, s
->store
); 
1191         /* free the buffer if it was allocated here */ 
1192         if (buf 
!= s
->scratch
) free(buf
); 
1194         /* seek to "next" field of previous record, write last offset */ 
1195         off 
= s
->prev 
+ RECORD_COMMON_LEN
; 
1196         if (s
->prev 
== 0) off 
= DB_HEADER_FIRST_OFFSET
; 
1198         status 
= fseeko(s
->store
, off
, SEEK_SET
); 
1199         if (status 
!= 0) return ASL_STATUS_WRITE_FAILED
; 
1201         status 
= fwrite(&v
, sizeof(uint64_t), 1, s
->store
); 
1202         if (status 
!= 1) return ASL_STATUS_WRITE_FAILED
; 
1204         /* seek to DB_HEADER_LAST_OFFSET, write last record offset */ 
1205         off 
= DB_HEADER_LAST_OFFSET
; 
1207         status 
= fseeko(s
->store
, off
, SEEK_SET
); 
1208         if (status 
!= 0) return ASL_STATUS_WRITE_FAILED
; 
1210         status 
= fwrite(&v
, sizeof(uint64_t), 1, s
->store
); 
1211         if (status 
!= 1) return ASL_STATUS_WRITE_FAILED
; 
1213         /* return to the end of the store (this is expected by other routines) */ 
1214         status 
= fseeko(s
->store
, 0, SEEK_END
); 
1215         if (status 
!= 0) return ASL_STATUS_WRITE_FAILED
; 
1220         s
->file_size 
= (size_t)ftello(s
->store
); 
1224         return ASL_STATUS_OK
; 
1228 asl_file_fetch_object(asl_file_t 
*s
, uint16_t fetch_type
, uint64_t where
, char **out
, uint32_t *outlen
) 
1239         if (s 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
1240         if (s
->store 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
1241         if (out 
== NULL
) return ASL_STATUS_INVALID_ARG
; 
1242         if (outlen 
== NULL
) return ASL_STATUS_INVALID_ARG
; 
1243         if (where 
== 0) return ASL_STATUS_INVALID_ARG
; 
1249         x64 
= asl_core_htonq(where
); 
1250         memcpy(&inls
, &x64
, 1); 
1253                 if (fetch_type 
!= ASL_FILE_TYPE_STR
) return ASL_STATUS_INVALID_STORE
; 
1257                 if (inls 
> 7) return ASL_STATUS_INVALID_STORE
; 
1259                 p 
= 1 + (char *)&x64
; 
1260                 memset(ils
, 0, sizeof(ils
)); 
1261                 memcpy(ils
, p
, inls
); 
1263                 if (*out 
== NULL
) return ASL_STATUS_NO_MEMORY
; 
1266                 return ASL_STATUS_OK
; 
1269         if (fetch_type 
== ASL_FILE_TYPE_STR
) 
1271                 /* check the string cache */ 
1272                 file_string_t 
*sx
, *sp
; 
1275                 for (sx 
= s
->string_list
; sx 
!= NULL
; sx 
= sx
->next
) 
1277                         if (sx
->where 
== where
) 
1279                                 *out 
= strdup(sx
->str
); 
1280                                 if (*out 
== NULL
) return ASL_STATUS_NO_MEMORY
; 
1282                                 /* N.B. hash field is used to hold length when reading */ 
1285                                 /* Move this string to the head of the list */ 
1288                                         file_string_t 
*sl 
= s
->string_list
; 
1289                                         sp
->next 
= sx
->next
; 
1291                                         s
->string_list 
= sx
; 
1294                                 return ASL_STATUS_OK
; 
1302         if ((off 
+ sizeof(uint16_t) + sizeof(uint32_t)) > s
->file_size
) return ASL_STATUS_READ_FAILED
; 
1304         status 
= fseeko(s
->store
, off
, SEEK_SET
); 
1305         if (status 
!= 0) return ASL_STATUS_READ_FAILED
; 
1308         status 
= fread(&type
, sizeof(uint16_t), 1, s
->store
); 
1309         if (status 
!= 1) return ASL_STATUS_READ_FAILED
; 
1311         off 
+= sizeof(uint16_t); 
1313         if (type 
!= fetch_type
) return ASL_STATUS_INVALID_STORE
; 
1317         status 
= fread(&len
, sizeof(uint32_t), 1, s
->store
); 
1318         if (status 
!= 1) return ASL_STATUS_READ_FAILED
; 
1319         off 
+= sizeof(uint32_t); 
1322         if ((off 
+ len
) > s
->file_size
) return ASL_STATUS_READ_FAILED
; 
1324         *out 
= calloc(1, len
); 
1325         if (*out 
== NULL
) return ASL_STATUS_NO_MEMORY
; 
1327         status 
= fread(*out
, len
, 1, s
->store
); 
1332                 return ASL_STATUS_READ_FAILED
; 
1337         if ((fetch_type 
== ASL_FILE_TYPE_STR
) && (len 
<= CACHE_MAX_STRING_LEN
)) 
1339                 file_string_t 
*sx 
= file_string_create(s
); 
1344                         /* N.B. hash field is used to hold length when reading */ 
1346                         sx
->next 
= s
->string_list
; 
1347                         memcpy(sx
->str
, *out
, len
); 
1349                         s
->string_list 
= sx
; 
1351                         if (((s
->flags 
& ASL_FILE_FLAG_UNLIMITED_CACHE
) == 0) && (s
->string_cache_count 
== CACHE_SIZE
)) 
1353                                 /* drop last (lru) string from cache */ 
1354                                 file_string_t 
*sp 
= s
->string_list
; 
1357                                 /* NB CACHE_SIZE must be > 1 */ 
1358                                 while (sx
->next 
!= NULL
) 
1365                                 file_string_dispose(s
, sx
); 
1369                                 s
->string_cache_count
++; 
1374         return ASL_STATUS_OK
; 
1378 asl_file_fetch_helper_16(asl_file_t 
*s
, char **p
, asl_msg_t 
*m
, const char *key
) 
1383         out 
= _asl_get_16(*p
); 
1384         *p 
+= sizeof(uint16_t); 
1386         if ((m 
== NULL
) || (key 
== NULL
)) return out
; 
1388         snprintf(str
, sizeof(str
), "%hu", out
); 
1389         asl_msg_set_key_val(m
, key
, str
); 
1395 asl_file_fetch_helper_32(asl_file_t 
*s
, char **p
, asl_msg_t 
*m
, const char *key
, int ignore
, uint32_t ignoreval
) 
1400         out 
= _asl_get_32(*p
); 
1401         *p 
+= sizeof(uint32_t); 
1403         if ((m 
== NULL
) || (key 
== NULL
)) return out
; 
1406         if ((ignore 
!= 0) && (out 
== ignoreval
)) doit 
= 0; 
1409                 snprintf(str
, sizeof(str
), "%u", out
); 
1410                 asl_msg_set_key_val(m
, key
, str
); 
1417 asl_file_fetch_helper_64(asl_file_t 
*s
, char **p
, asl_msg_t 
*m
, const char *key
) 
1422         out 
= _asl_get_64(*p
); 
1423         *p 
+= sizeof(uint64_t); 
1425         if ((m 
== NULL
) || (key 
== NULL
)) return out
; 
1427         snprintf(str
, sizeof(str
), "%llu", out
); 
1428         asl_msg_set_key_val(m
, key
, str
); 
1434 asl_file_fetch_helper_str(asl_file_t 
*s
, char **p
, asl_msg_t 
*m
, const char *key
, uint32_t *err
) 
1438         uint32_t status
, len
; 
1440         out 
= _asl_get_64(*p
); 
1441         *p 
+= sizeof(uint64_t); 
1445         status 
= ASL_STATUS_OK
; 
1446         if (out 
!= 0) status 
= asl_file_fetch_object(s
, ASL_FILE_TYPE_STR
, out
, &val
, &len
); 
1448         if (err 
!= NULL
) *err 
= status
; 
1449         if ((status 
== ASL_STATUS_OK
) && (val 
!= NULL
)) 
1451                 asl_msg_set_key_val(m
, key
, val
); 
1459 asl_file_fetch_pos(asl_file_t 
*s
, uint64_t where
, int dir
, asl_msg_t 
**msg
) 
1461         char *buf
, *p
, *k
, *v
; 
1463         uint32_t i
, status
, len
, buflen
, kvn
; 
1468         if (s 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
1469         if (s
->store 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
1470         if (msg 
== NULL
) return ASL_STATUS_INVALID_ARG
; 
1471         if ((s
->flags 
& ASL_FILE_FLAG_READ
) == 0) return ASL_STATUS_WRITE_ONLY
; 
1475         status 
= asl_file_fetch_object(s
, ASL_FILE_TYPE_MSG
, where
, &buf
, &buflen
); 
1476         if ((status 
!= ASL_STATUS_OK
) || (buf 
== NULL
)) 
1483         /* check buffer size */ 
1484         kvn 
= _asl_get_32(buf 
+ BUFFER_OFFSET_KVCOUNT
); 
1485         if (buflen 
< (MSG_RECORD_FIXED_LENGTH 
- RECORD_COMMON_LEN 
+ (kvn 
* sizeof(uint64_t)))) 
1490                 return ASL_STATUS_READ_FAILED
; 
1493         out 
= asl_msg_new(ASL_TYPE_MSG
); 
1497                 return ASL_STATUS_NO_MEMORY
; 
1500         memset(&r
, 0, sizeof(file_record_t
)); 
1503         r
.next 
= asl_file_fetch_helper_64(s
, &p
, NULL
, NULL
); 
1504         r
.mid 
= asl_file_fetch_helper_64(s
, &p
, out
, ASL_KEY_MSG_ID
); 
1505         r
.time 
= asl_file_fetch_helper_64(s
, &p
, out
, ASL_KEY_TIME
); 
1506         r
.nano 
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_TIME_NSEC
, 0, 0); 
1507         r
.level 
= asl_file_fetch_helper_16(s
, &p
, out
, ASL_KEY_LEVEL
); 
1508         r
.flags 
= asl_file_fetch_helper_16(s
, &p
, NULL
, NULL
); 
1509         r
.pid 
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_PID
, 0, 0); 
1510         r
.uid 
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_UID
, 1, (uint32_t)-1); 
1511         r
.gid 
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_GID
, 1, (uint32_t)-1); 
1512         r
.ruid 
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_READ_UID
, 1, (uint32_t)-1); 
1513         r
.rgid 
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_READ_GID
, 1, (uint32_t)-1); 
1514         r
.refpid 
= asl_file_fetch_helper_32(s
, &p
, out
, ASL_KEY_REF_PID
, 1, 0); 
1515         r
.kvcount 
= asl_file_fetch_helper_32(s
, &p
, NULL
, NULL
, 0, 0); 
1517         status 
= ASL_STATUS_OK
; 
1518         r
.host 
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_HOST
, &status
); /* 68 */ 
1519         if (status 
== ASL_STATUS_OK
) r
.sender 
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_SENDER
, &status
); /* 76 */ 
1520         if (status 
== ASL_STATUS_OK
) r
.facility 
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_FACILITY
, &status
); /* 84 */ 
1521         if (status 
== ASL_STATUS_OK
) r
.message 
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_MSG
, &status
); /* 92 */ 
1522         if (status 
== ASL_STATUS_OK
) r
.refproc 
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_REF_PROC
, &status
); /* 100 */ 
1523         if (status 
== ASL_STATUS_OK
) r
.session 
= asl_file_fetch_helper_str(s
, &p
, out
, ASL_KEY_SESSION
, &status
); /* 108 */ 
1525         if (status 
!= ASL_STATUS_OK
) 
1527                 asl_msg_release(out
); 
1534         kvn 
=  r
.kvcount 
/ 2; 
1536         for (i 
= 0; i 
< kvn
; i
++) 
1542                 kv 
= _asl_get_64(p
); 
1543                 p 
+= sizeof(uint64_t); 
1545                 status 
= asl_file_fetch_object(s
, ASL_FILE_TYPE_STR
, kv
, &k
, &len
); 
1546                 if (status 
!= ASL_STATUS_OK
) 
1548                         asl_msg_release(out
); 
1555                 kv 
= _asl_get_64(p
); 
1556                 p 
+= sizeof(uint64_t); 
1561                         status 
= asl_file_fetch_object(s
, ASL_FILE_TYPE_STR
, kv
, &v
, &len
); 
1562                         if (status 
!= ASL_STATUS_OK
) 
1565                                 asl_msg_release(out
); 
1573                 if ((status 
== ASL_STATUS_OK
) && (k 
!= NULL
)) 
1575                         asl_msg_set_key_val(out
, k
, v
); 
1582         r
.prev 
= asl_file_fetch_helper_64(s
, &p
, NULL
, NULL
); /* 116 */ 
1588                 if ((r
.next 
!= 0) && (r
.next 
<= s
->cursor
)) 
1591                          * Next offset goes backwards or loops. 
1592                          * The database is corrupt, but we allow this call to fail 
1593                          * quietly so that the current record fetch succeeds. 
1597                         return ASL_STATUS_OK
; 
1604                 if ((r
.prev 
!= 0) && (r
.prev 
>= s
->cursor
)) 
1607                          * Prev offset goes forward or loops. 
1608                          * The database is corrupt, but we allow this call to fail 
1609                          * quietly so that the current record fetch succeeds. 
1613                         return ASL_STATUS_OK
; 
1623                 off 
= s
->cursor 
+ RECORD_COMMON_LEN 
+ sizeof(uint64_t); 
1624                 if (off 
> s
->file_size
) 
1629                          * Next record offset is past the end of the file. 
1630                          * This is an error, but we allow it to fail quietly 
1631                          * so that the current record fetch succeeds. 
1634                         return ASL_STATUS_OK
; 
1637                 status 
= fseeko(s
->store
, off
, SEEK_SET
); 
1640                         asl_msg_release(out
); 
1643                         return ASL_STATUS_READ_FAILED
; 
1646                 status 
= fread(&x64
, sizeof(uint64_t), 1, s
->store
); 
1649                         asl_msg_release(out
); 
1652                         return ASL_STATUS_READ_FAILED
; 
1655                 s
->cursor_xid 
= asl_core_ntohq(x64
); 
1659         return ASL_STATUS_OK
; 
1663 asl_file_open_read(const char *path
, asl_file_t 
**s
) 
1668         uint32_t status
, vers
, last_len
; 
1669         char buf
[DB_HEADER_LEN
]; 
1671         asl_legacy1_t 
*legacy
; 
1674         memset(&sb
, 0, sizeof(struct stat
)); 
1675         if (stat(path
, &sb
) != 0) return ASL_STATUS_FAILED
; 
1677         f 
= fopen(path
, "r"); 
1680                 if (errno 
== EACCES
) return ASL_STATUS_ACCESS_DENIED
; 
1681                 return ASL_STATUS_FAILED
; 
1684         i 
= fread(buf
, DB_HEADER_LEN
, 1, f
); 
1688                 return ASL_STATUS_INVALID_STORE
; 
1691         /* validate header */ 
1692         if (strncmp(buf
, ASL_DB_COOKIE
, ASL_DB_COOKIE_LEN
)) 
1695                 return ASL_STATUS_INVALID_STORE
; 
1700         vers 
= _asl_get_32(buf 
+ DB_HEADER_VERS_OFFSET
); 
1701         if (vers 
== DB_VERSION_LEGACY_1
) 
1704                 status 
= asl_legacy1_open(path
, &legacy
); 
1705                 if (status 
!= ASL_STATUS_OK
) return status
; 
1708         out 
= (asl_file_t 
*)calloc(1, sizeof(asl_file_t
)); 
1712                 return ASL_STATUS_NO_MEMORY
; 
1715         out
->asl_type 
= ASL_TYPE_FILE
; 
1719         out
->flags 
= ASL_FILE_FLAG_READ
; 
1720         out
->version 
= vers
; 
1724                 out
->flags 
|= ASL_FILE_FLAG_LEGACY_STORE
; 
1725                 out
->legacy 
= (void *)legacy
; 
1728                 return ASL_STATUS_OK
; 
1731         out
->first 
= _asl_get_64(buf 
+ DB_HEADER_FIRST_OFFSET
); 
1732         out
->last 
= _asl_get_64(buf 
+ DB_HEADER_LAST_OFFSET
); 
1733         out
->file_size 
= (size_t)sb
.st_size
; 
1736          * Detect bogus last pointer and check for odd-sized files. 
1737          * Setting out->last to zero forces us to follow the linked 
1738          * list of records in the file to the last record.  That's 
1739          * done in the set_position code.  It's a bit slower, but it's 
1740          * better at preventing crashes in corrupt files. 
1743          /* records are at least MSG_RECORD_FIXED_LENGTH bytes */ 
1744         if ((out
->last 
+ MSG_RECORD_FIXED_LENGTH
) > out
->file_size
) 
1750                 /* read last record length and make sure the file is at least that large */ 
1751                 off 
= out
->last 
+ RECORD_TYPE_LEN
; 
1752                 status 
= asl_file_read_uint32(out
, off
, &last_len
); 
1753                 if (status 
!= ASL_STATUS_OK
) 
1760                 if ((out
->last 
+ last_len
) > out
->file_size
) out
->last 
= 0; 
1763         out
->cursor 
= out
->first
; 
1764         if (out
->cursor 
!= 0) 
1766                 off 
= out
->cursor 
+ RECORD_COMMON_LEN 
+ sizeof(uint64_t); 
1767                 status 
= asl_file_read_uint64(out
, off
, &(out
->cursor_xid
)); 
1768                 if (status 
!= ASL_STATUS_OK
) 
1777         return ASL_STATUS_OK
; 
1781 asl_file_read_set_position_first(asl_file_t 
*s
) 
1786         s
->cursor 
= s
->first
; 
1789         if (s
->cursor 
== 0) return ASL_STATUS_OK
; 
1791         /* read ID of the first record */ 
1792         off 
= s
->cursor 
+ RECORD_COMMON_LEN 
+ sizeof(uint64_t); 
1793         status 
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
)); 
1798 asl_file_read_set_position_last(asl_file_t 
*s
, int do_count
) 
1805          * If the file has the offset of the last record, we just go there. 
1806          * The last record offset was added to improve performance, so it may 
1807          * or may not be there.  If we don't have the last record offset, we 
1808          * just iterate down the record links to find the last one. 
1810          * Note that s->last may be zero if the file is empty. 
1813         if ((s
->last 
!= 0) && (do_count 
== 0)) 
1815                 s
->cursor 
= s
->last
; 
1816                 off 
= s
->last 
+ RECORD_COMMON_LEN 
+ sizeof(uint64_t); 
1818                 /* read ID of the last record */ 
1819                 status 
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
)); 
1823         /* start at the first record and iterate */ 
1824         s
->cursor 
= s
->first
; 
1830                 off 
= s
->cursor 
+ RECORD_COMMON_LEN
; 
1833                 /* read next offset */ 
1834                 status 
= asl_file_read_uint64(s
, off
, &next
); 
1835                 if (status 
!= ASL_STATUS_OK
) return status
; 
1837                 /* detect bogus next pointer */ 
1838                 if (((next 
+ MSG_RECORD_FIXED_LENGTH
) > s
->file_size
) || (next 
<= s
->cursor
)) next 
= 0; 
1844                         if (s
->cursor 
== 0) return ASL_STATUS_OK
; 
1846                         off 
= s
->cursor 
+ RECORD_COMMON_LEN 
+ sizeof(uint64_t); 
1847                         status 
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
)); 
1848                         return ASL_STATUS_OK
; 
1856 asl_file_read_set_position(asl_file_t 
*s
, uint32_t pos
) 
1859         uint32_t len
, status
; 
1862         if (s 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
1863         if (s
->version 
== 1) return ASL_STATUS_FAILED
; 
1865         if (pos 
== ASL_FILE_POSITION_FIRST
) return asl_file_read_set_position_first(s
); 
1866         if (pos 
== ASL_FILE_POSITION_LAST
) return asl_file_read_set_position_last(s
, 0); 
1870         if (pos 
== ASL_FILE_POSITION_PREVIOUS
) 
1872                 if (s
->cursor 
== s
->first
) return ASL_STATUS_NO_RECORDS
; 
1873                 if (s
->cursor 
== 0) return ASL_STATUS_NO_RECORDS
; 
1875                 off 
= s
->cursor 
+ RECORD_TYPE_LEN
; 
1876                 status 
= asl_file_read_uint32(s
, off
, &len
); 
1877                 if (status 
!= ASL_STATUS_OK
) return status
; 
1879                 /* set offset to read the "previous" field at the end of the record */ 
1880                 off 
= s
->cursor 
+ RECORD_COMMON_LEN 
+ len 
- sizeof(uint64_t); 
1882         else if (pos 
== ASL_FILE_POSITION_NEXT
) 
1884                 if (s
->cursor 
== s
->last
) return ASL_STATUS_NO_RECORDS
; 
1885                 if (s
->cursor 
== 0) return ASL_STATUS_NO_RECORDS
; 
1887                 /* set offset to read the "next" field in the current record */ 
1888                 off 
= s
->cursor 
+ RECORD_COMMON_LEN
; 
1890         else return ASL_STATUS_INVALID_ARG
; 
1895          * read offset of next / previous 
1898         status 
= asl_file_read_uint64(s
, off
, &next
); 
1899         if (status 
!= ASL_STATUS_OK
) return ASL_STATUS_READ_FAILED
; 
1901         /* detect bogus next pointer */ 
1902         if ((next 
+ MSG_RECORD_FIXED_LENGTH
) > s
->file_size
) next 
= 0; 
1903         else if ((pos 
== ASL_FILE_POSITION_PREVIOUS
) && (next 
>= s
->cursor
)) next 
= 0; 
1904         else if ((pos 
== ASL_FILE_POSITION_NEXT
) && (next 
<= s
->cursor
)) next 
= 0; 
1907         if (s
->cursor 
== 0) return ASL_STATUS_NO_RECORDS
; 
1909         /* read ID of the record */ 
1910         off 
= s
->cursor 
+ RECORD_COMMON_LEN 
+ sizeof(uint64_t); 
1911         status 
= asl_file_read_uint64(s
, off
, &(s
->cursor_xid
)); 
1916 asl_file_fetch_next(asl_file_t 
*s
, asl_msg_t 
**msg
) 
1918         if (s 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
1919         if (s
->version 
== 1) return ASL_STATUS_FAILED
; 
1921         return asl_file_fetch_pos(s
, s
->cursor
, 1, msg
); 
1925 asl_file_fetch_previous(asl_file_t 
*s
, asl_msg_t 
**msg
) 
1927         if (s 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
1928         if (s
->version 
== 1) return ASL_STATUS_FAILED
; 
1930         return asl_file_fetch_pos(s
, s
->cursor
, -1, msg
); 
1934 asl_file_fetch(asl_file_t 
*s
, uint64_t mid
, asl_msg_t 
**msg
) 
1938         if (s 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
1939         if ((s
->flags 
& ASL_FILE_FLAG_READ
) == 0) return ASL_STATUS_WRITE_ONLY
; 
1941         if (s
->version 
== 1) 
1943                 if (msg 
== NULL
) return ASL_STATUS_OK
; 
1944                 return asl_legacy1_fetch((asl_legacy1_t 
*)s
->legacy
, mid
, msg
); 
1947         if (s
->cursor_xid 
== 0) 
1949                 status 
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
); 
1950                 if (status 
!= ASL_STATUS_OK
) return status
; 
1951                 if (s
->cursor_xid 
== 0) return ASL_STATUS_INVALID_ID
; 
1954         while (s
->cursor_xid 
< mid
) 
1956                 status 
= asl_file_read_set_position(s
, ASL_FILE_POSITION_NEXT
); 
1957                 if (status 
!= ASL_STATUS_OK
) return status
; 
1958                 if (s
->cursor_xid 
> mid
) return ASL_STATUS_INVALID_ID
; 
1959                 if (s
->cursor_xid 
== 0) return ASL_STATUS_INVALID_ID
; 
1962         while (s
->cursor_xid 
> mid
) 
1964                 status 
= asl_file_read_set_position(s
, ASL_FILE_POSITION_PREVIOUS
); 
1965                 if (status 
!= ASL_STATUS_OK
) return status
; 
1966                 if (s
->cursor_xid 
< mid
) return ASL_STATUS_INVALID_ID
; 
1967                 if (s
->cursor_xid 
== 0) return ASL_STATUS_INVALID_ID
; 
1970         if (s
->cursor_xid 
!= mid
) return ASL_STATUS_INVALID_ID
; 
1972         if (msg 
== NULL
) return ASL_STATUS_OK
; 
1973         return asl_file_fetch_pos(s
, s
->cursor
, 1, msg
); 
1976 __private_extern__ 
uint64_t 
1977 asl_file_cursor(asl_file_t 
*s
) 
1979         if (s 
== NULL
) return 0; 
1980         if ((s
->flags 
& ASL_FILE_FLAG_READ
) == 0) return 0; 
1981         if (s
->version 
== 1) return 0; 
1983         return s
->cursor_xid
; 
1986 __private_extern__ ASL_STATUS
 
1987 asl_file_match_start(asl_file_t 
*s
, uint64_t start
, int32_t direction
) 
1991         if (s 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
1992         if (s
->version 
== 1) return ASL_STATUS_INVALID_STORE
; 
1993         if ((s
->flags 
& ASL_FILE_FLAG_READ
) == 0) return ASL_STATUS_WRITE_ONLY
; 
1995         d 
= ASL_FILE_POSITION_NEXT
; 
1996         if (direction 
< 0) d 
= ASL_FILE_POSITION_PREVIOUS
; 
1999          * find starting point 
2001         status 
= ASL_STATUS_OK
; 
2002         if (direction 
>= 0) status 
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
); 
2003         else status 
= asl_file_read_set_position(s
, ASL_FILE_POSITION_LAST
); 
2004         if (status 
!= ASL_STATUS_OK
) return status
; 
2006         while ((status 
== ASL_STATUS_OK
) && (((direction 
>= 0) && (s
->cursor_xid 
< start
)) || ((direction 
< 0) && (s
->cursor_xid 
> start
)))) 
2008                 status 
= asl_file_read_set_position(s
, d
); 
2014 __private_extern__ ASL_STATUS
 
2015 asl_file_match_next(asl_file_t 
*s
, asl_msg_list_t 
*query
, asl_msg_t 
**msg
, uint64_t *last
, int32_t direction
) 
2017         uint32_t status
, d
, i
, do_match
, did_match
; 
2020         if (s 
== NULL
) return ASL_STATUS_INVALID_STORE
; 
2021         if (msg 
== NULL
) return ASL_STATUS_INVALID_ARG
; 
2022         if (s
->version 
== 1) return ASL_STATUS_INVALID_STORE
; 
2023         if ((s
->flags 
& ASL_FILE_FLAG_READ
) == 0) return ASL_STATUS_WRITE_ONLY
; 
2024         if (s
->cursor 
== 0) return ASL_STATUS_NO_RECORDS
; 
2029         if (query 
== NULL
) do_match 
= 0; 
2030         else if (query
->count 
== 0) do_match 
= 0; 
2032         d 
= ASL_FILE_POSITION_NEXT
; 
2033         if (direction 
< 0) d 
= ASL_FILE_POSITION_PREVIOUS
; 
2037         *last 
= s
->cursor_xid
; 
2039         status 
= asl_file_fetch_pos(s
, s
->cursor
, direction
, &m
); 
2040         if (status 
== ASL_STATUS_ACCESS_DENIED
) return ASL_STATUS_MATCH_FAILED
; 
2041         if ((status 
== ASL_STATUS_INVALID_ARG
) && (s
->cursor 
== 0)) return ASL_STATUS_NO_RECORDS
; 
2042         if (status 
!= ASL_STATUS_OK
) return status
; 
2050                 for (i 
= 0; (i 
< query
->count
) && (did_match 
== 0); i
++) 
2052                         did_match 
= asl_msg_cmp(query
->msg
[i
], m
); 
2059                 return ASL_STATUS_OK
; 
2064         return ASL_STATUS_MATCH_FAILED
; 
2068 asl_file_match(asl_file_t 
*s
, asl_msg_list_t 
*qlist
, uint64_t *last
, uint64_t start
, uint32_t count
, uint32_t duration
, int32_t direction
) 
2070         uint32_t status
, d
, i
, do_match
, did_match
, rescount
; 
2072         struct timeval now
, finish
; 
2073         asl_msg_list_t 
*out 
= NULL
; 
2075         if (s 
== NULL
) return NULL
; 
2076         if ((s
->flags 
& ASL_FILE_FLAG_READ
) == 0) return NULL
; 
2078         if (s
->version 
== 1) 
2080                 asl_legacy1_match((asl_legacy1_t 
*)s
->legacy
, qlist
, &out
, last
, start
, count
, direction
); 
2085         if (qlist 
== NULL
) do_match 
= 0; 
2086         else if (qlist
->count 
== 0) do_match 
= 0; 
2090         d 
= ASL_FILE_POSITION_NEXT
; 
2091         if (direction 
< 0) d 
= ASL_FILE_POSITION_PREVIOUS
; 
2094          * find starting point 
2096         status 
= ASL_STATUS_OK
; 
2097         if (direction 
>= 0) status 
= asl_file_read_set_position(s
, ASL_FILE_POSITION_FIRST
); 
2098         else status 
= asl_file_read_set_position(s
, ASL_FILE_POSITION_LAST
); 
2099         if (status 
!= ASL_STATUS_OK
) return NULL
; 
2101         while ((status 
== ASL_STATUS_OK
) && (((direction 
>= 0) && (s
->cursor_xid 
< start
)) || ((direction 
< 0) && (s
->cursor_xid 
> start
)))) 
2103                 status 
= asl_file_read_set_position(s
, d
); 
2106         /* start the timer if a duration was specified */ 
2107         memset(&finish
, 0, sizeof(struct timeval
)); 
2110                 if (gettimeofday(&finish
, NULL
) == 0) 
2112                         finish
.tv_sec 
+= (duration 
/ USEC_PER_SEC
); 
2113                         finish
.tv_usec 
+= (duration 
% USEC_PER_SEC
); 
2114                         if (finish
.tv_usec 
> USEC_PER_SEC
) 
2116                                 finish
.tv_usec 
-= USEC_PER_SEC
; 
2122                         /* shouldn't happen, but if gettimeofday failed we just run without a timeout */ 
2123                         memset(&finish
, 0, sizeof(struct timeval
)); 
2128          * loop through records 
2133                 status 
= asl_file_fetch_pos(s
, s
->cursor
, direction
, &m
); 
2134                 if (status 
== ASL_STATUS_ACCESS_DENIED
) continue; 
2135                 if (status 
!= ASL_STATUS_OK
) break; 
2137                 *last 
= s
->cursor_xid
; 
2145                         for (i 
= 0; (i 
< qlist
->count
) && (did_match 
== 0); i
++) 
2147                                 did_match 
= asl_msg_cmp(qlist
->msg
[i
], m
); 
2153                         /*  append m to res */ 
2156                                 out 
= asl_msg_list_new(); 
2157                                 if (out 
== NULL
) return NULL
; 
2160                         asl_msg_list_append(out
, m
); 
2162                         if ((count 
!= 0) && (rescount 
>= count
)) break; 
2164                         /* check the timer */ 
2165                         if ((finish
.tv_sec 
!= 0) && (gettimeofday(&now
, NULL
) == 0)) 
2167                                 if ((now
.tv_sec 
> finish
.tv_sec
) || ((now
.tv_sec 
== finish
.tv_sec
) && (now
.tv_usec 
> finish
.tv_usec
))) break; 
2178 asl_file_size(asl_file_t 
*s
) 
2180         if (s 
== NULL
) return 0; 
2181         return s
->file_size
; 
2185 asl_file_ctime(asl_file_t 
*s
) 
2187         if (s 
== NULL
) return 0; 
2192 asl_file_list_close(asl_file_list_t 
*head
) 
2194         asl_file_list_t 
*next
; 
2196         while (head 
!= NULL
) 
2199                 asl_file_close(head
->file
); 
2206 asl_file_list_free(asl_file_list_t 
*head
) 
2208         asl_file_list_t 
*next
; 
2210         while (head 
!= NULL
) 
2218 static asl_file_list_t 
* 
2219 asl_file_list_insert(asl_file_list_t 
*list
, asl_file_t 
*f
, int32_t dir
) 
2221         asl_file_list_t 
*a
, *b
, *tmp
; 
2223         if (f 
== NULL
) return list
; 
2225         tmp 
= (asl_file_list_t 
*)calloc(1, sizeof(asl_file_list_t
)); 
2226         if (tmp 
== NULL
) return NULL
; 
2229         if (list 
== NULL
) return tmp
; 
2232         if (((dir 
< 0) && (f
->cursor_xid 
> a
->file
->cursor_xid
)) || ((dir 
>= 0) && (f
->cursor_xid 
< a
->file
->cursor_xid
))) 
2241                 if (((dir 
< 0) && (f
->cursor_xid 
> b
->file
->cursor_xid
)) || ((dir 
>= 0) && (f
->cursor_xid 
< b
->file
->cursor_xid
))) 
2257 asl_file_list_add(asl_file_list_t 
*list
, asl_file_t 
*f
) 
2259         asl_file_list_t 
*tmp
; 
2261         if (f 
== NULL
) return list
; 
2262         if (f
->version 
== 1) return list
; 
2264         tmp 
= (asl_file_list_t 
*)calloc(1, sizeof(asl_file_list_t
)); 
2265         if (tmp 
== NULL
) return NULL
; 
2273 asl_file_list_match_start(asl_file_list_t 
*list
, uint64_t start
, int32_t direction
) 
2277         asl_file_match_token_t 
*out
; 
2279         if (list 
== NULL
) return NULL
; 
2281         out 
= (asl_file_match_token_t 
*)calloc(1, sizeof(asl_file_match_token_t
)); 
2282         if (out 
== NULL
) return NULL
; 
2284         for (n 
= list
; n 
!= NULL
; n 
= n
->next
) 
2286                 /* init file for the search */ 
2287                 status 
= asl_file_match_start(n
->file
, start
, direction
); 
2288                 if (status 
!= ASL_STATUS_OK
) continue; 
2289                 if (n
->file
->cursor_xid 
== 0) continue; 
2291                 out
->list 
= asl_file_list_insert(out
->list
, n
->file
, direction
); 
2294         out
->dir 
= direction
; 
2299 asl_file_list_match_next(void *token
, asl_msg_list_t 
*qlist
, asl_msg_list_t 
**res
, uint32_t count
) 
2301         uint32_t status
, rescount
; 
2304         asl_file_match_token_t 
*work
; 
2307         if (token 
== NULL
) return ASL_STATUS_OK
; 
2308         if (res 
== NULL
) return ASL_STATUS_INVALID_ARG
; 
2310         work 
= (asl_file_match_token_t 
*)token
; 
2315         while ((work
->list 
!= NULL
) && ((rescount 
< count
) || (count 
== 0))) 
2318                 status 
= asl_file_match_next(work
->list
->file
, qlist
, &m
, &last
, work
->dir
); 
2321                         if (*res 
== NULL
) *res 
= asl_msg_list_new(); 
2324                                 asl_file_list_free(work
->list
); 
2326                                 return ASL_STATUS_NO_MEMORY
; 
2329                         asl_msg_list_append(*res
, m
); 
2334                 if ((status 
!= ASL_STATUS_OK
) || (work
->list
->file
->cursor_xid 
== 0)) 
2336                         n 
= work
->list
->next
; 
2341                 if (work
->list 
!= NULL
) 
2343                         n 
= work
->list
->next
; 
2346                                 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
))) 
2349                                         work
->list 
= work
->list
->next
; 
2351                                         work
->list 
= asl_file_list_insert(work
->list
, n
->file
, work
->dir
); 
2358         return ASL_STATUS_OK
; 
2362 asl_file_list_match_end(void *token
) 
2364         asl_file_match_token_t 
*work
; 
2366         if (token 
== NULL
) return; 
2368         work 
= (asl_file_match_token_t 
*)token
; 
2369         asl_file_list_free(work
->list
); 
2376 asl_file_list_match(asl_file_list_t 
*list
, asl_msg_list_t 
*qlist
, uint64_t *last
, uint64_t start
, uint32_t count
, uint32_t duration
, int32_t direction
) 
2378         uint32_t status
, rescount
; 
2379         asl_file_list_t 
*files
, *n
; 
2381         struct timeval now
, finish
; 
2382         asl_msg_list_t 
*out 
= NULL
; 
2384         if (list 
== NULL
) return NULL
; 
2385         if (last 
== NULL
) return NULL
; 
2389         for (n 
= list
; n 
!= NULL
; n 
= n
->next
) 
2391                 /* init file for the search */ 
2392                 status 
= asl_file_match_start(n
->file
, start
, direction
); 
2393                 if (status 
!= ASL_STATUS_OK
) continue; 
2394                 if (n
->file
->cursor_xid 
== 0) continue; 
2396                 files 
= asl_file_list_insert(files
, n
->file
, direction
); 
2401                 asl_file_list_free(files
); 
2405         /* start the timer if a timeout was specified */ 
2406         memset(&finish
, 0, sizeof(struct timeval
)); 
2409                 if (gettimeofday(&finish
, NULL
) == 0) 
2411                         finish
.tv_sec 
+= (duration 
/ USEC_PER_SEC
); 
2412                         finish
.tv_usec 
+= (duration 
% USEC_PER_SEC
); 
2413                         if (finish
.tv_usec 
> USEC_PER_SEC
) 
2415                                 finish
.tv_usec 
-= USEC_PER_SEC
; 
2421                         /* shouldn't happen, but if gettimeofday failed we just run without a timeout */ 
2422                         memset(&finish
, 0, sizeof(struct timeval
)); 
2427         while ((files 
!= NULL
) && ((rescount 
< count
) || (count 
== 0))) 
2430                 status 
= asl_file_match_next(files
->file
, qlist
, &m
, last
, direction
); 
2433                         if (out 
== NULL
) out 
= asl_msg_list_new(); 
2436                                 asl_file_list_free(files
); 
2440                         asl_msg_list_append(out
, m
); 
2445                 if (files
->file
->cursor_xid 
== 0) 
2457                                 if (((direction 
< 0) && (files
->file
->cursor_xid 
<= n
->file
->cursor_xid
)) || ((direction 
>= 0) && (files
->file
->cursor_xid 
> n
->file
->cursor_xid
))) 
2460                                         files 
= files
->next
; 
2462                                         files 
= asl_file_list_insert(files
, n
->file
, direction
); 
2468                 /* check the timer */ 
2469                 if ((finish
.tv_sec 
!= 0) && (gettimeofday(&now
, NULL
) == 0)) 
2471                         if ((now
.tv_sec 
> finish
.tv_sec
) || ((now
.tv_sec 
== finish
.tv_sec
) && (now
.tv_usec 
> finish
.tv_usec
))) break; 
2475         asl_file_list_free(files
); 
2480 #pragma mark asl_object support 
2483 _jump_dealloc(asl_object_private_t 
*obj
) 
2485         _asl_file_free_internal((asl_file_t 
*)obj
); 
2489 _jump_count(asl_object_private_t 
*obj
) 
2491         asl_file_t 
*s 
= (asl_file_t 
*)obj
; 
2492         if (s 
== NULL
) return 0; 
2493         if ((s
->flags 
& ASL_FILE_FLAG_READ
) == 0) return 0; 
2495         uint64_t cursor 
= s
->cursor
; 
2496         uint64_t cursor_xid 
= s
->cursor_xid
; 
2498         if (asl_file_read_set_position_last((asl_file_t 
*)obj
, 1) != ASL_STATUS_OK
) return 0; 
2501         s
->cursor_xid 
= cursor_xid
; 
2502         return s
->msg_count
; 
2505 static asl_object_private_t 
* 
2506 _jump_next(asl_object_private_t 
*obj
) 
2508         asl_msg_t 
*msg 
= NULL
; 
2509         if (asl_file_fetch_next((asl_file_t 
*)obj
, &msg
) != ASL_STATUS_OK
) return NULL
; 
2510         return (asl_object_private_t 
*)msg
; 
2513 static asl_object_private_t 
* 
2514 _jump_prev(asl_object_private_t 
*obj
) 
2516         asl_msg_t 
*msg 
= NULL
; 
2517         if (asl_file_fetch_previous((asl_file_t 
*)obj
, &msg
) != ASL_STATUS_OK
) return NULL
; 
2518         return (asl_object_private_t 
*)msg
; 
2521 /* we don't really need to support this, but we are generous */ 
2522 static asl_object_private_t 
* 
2523 _jump_get_object_at_index(asl_object_private_t 
*obj
, size_t n
) 
2525         asl_msg_t 
*msg 
= NULL
; 
2527         if (asl_file_fetch((asl_file_t 
*)obj
, mid
, &msg
) != ASL_STATUS_OK
) return NULL
; 
2528         return (asl_object_private_t 
*)msg
; 
2532 _jump_set_iteration_index(asl_object_private_t 
*obj
, size_t n
) 
2534         asl_file_t 
*s 
= (asl_file_t 
*)obj
; 
2535         if (s 
== NULL
) return; 
2536         if ((s
->flags 
& ASL_FILE_FLAG_READ
) == 0) return; 
2540                 asl_file_read_set_position_first(s
); 
2542         else if (n 
== SIZE_MAX
) 
2544                 asl_file_read_set_position_last(s
, 0); 
2548                 /* we don't really need to support this, but we are generous */ 
2549                 asl_file_fetch(s
, n
, NULL
); 
2554 _jump_append(asl_object_private_t 
*obj
, asl_object_private_t 
*newobj
, void *addr
) 
2557         asl_file_t 
*s 
= (asl_file_t 
*)obj
; 
2558         int type 
= asl_get_type((asl_object_t
)newobj
); 
2559         if (s 
== NULL
) return; 
2560         if (s
->flags 
& ASL_FILE_FLAG_READ
) return; 
2562         if (type 
== ASL_TYPE_LIST
) 
2565                 asl_msg_list_reset_iteration((asl_msg_list_t 
*)newobj
, 0); 
2566                 while (NULL 
!= (msg 
= asl_msg_list_next((asl_msg_list_t 
*)newobj
))) 
2568                         if (asl_file_save(s
, msg
, &xid
) != ASL_STATUS_OK
) return; 
2571         else if ((type 
== ASL_TYPE_MSG
) || (type 
== ASL_TYPE_QUERY
)) 
2573                 asl_file_save(s
, (asl_msg_t 
*)newobj
, &xid
); 
2577 static asl_object_private_t 
* 
2578 _jump_search(asl_object_private_t 
*obj
, asl_object_private_t 
*query
) 
2580         asl_file_t 
*s 
= (asl_file_t 
*)obj
; 
2581         int type 
= asl_get_type((asl_object_t
)query
); 
2582         asl_msg_list_t 
*out 
= NULL
; 
2583         asl_msg_list_t 
*ql 
= NULL
; 
2588                 return (asl_object_private_t 
*)asl_file_match(s
, NULL
, &last
, 0, 0, 0, 1); 
2590         else if (type 
== ASL_TYPE_LIST
) 
2592                 return (asl_object_private_t 
*)asl_file_match(s
, (asl_msg_list_t 
*)query
, &last
, 0, 0, 0, 1); 
2594         else if ((type 
== ASL_TYPE_MSG
) || (type 
== ASL_TYPE_QUERY
)) 
2596                 ql 
= asl_msg_list_new(); 
2597                 asl_msg_list_append(ql
, query
); 
2599                 out 
= asl_file_match(s
, ql
, &last
, 0, 0, 0, 1); 
2600                 asl_msg_list_release(ql
); 
2601                 return (asl_object_private_t 
*)out
; 
2607 static asl_object_private_t 
* 
2608 _jump_match(asl_object_private_t 
*obj
, asl_object_private_t 
*qlist
, size_t *last
, size_t start
, size_t count
, uint32_t duration
, int32_t dir
) 
2611         asl_msg_list_t 
*out 
= asl_file_match((asl_file_t 
*)obj
, (asl_msg_list_t 
*)qlist
, &x
, start
, count
, duration
, dir
); 
2613         return (asl_object_private_t 
*)out
; 
2616 __private_extern__ 
const asl_jump_table_t 
* 
2617 asl_file_jump_table() 
2619         static const asl_jump_table_t jump 
= 
2622                 .dealloc 
= &_jump_dealloc
, 
2623                 .set_key_val_op 
= NULL
, 
2625                 .get_val_op_for_key 
= NULL
, 
2626                 .get_key_val_op_at_index 
= NULL
, 
2627                 .count 
= &_jump_count
, 
2628                 .next 
= &_jump_next
, 
2629                 .prev 
= &_jump_prev
, 
2630                 .get_object_at_index 
= &_jump_get_object_at_index
, 
2631                 .set_iteration_index 
= &_jump_set_iteration_index
, 
2632                 .remove_object_at_index 
= NULL
, 
2633                 .append 
= &_jump_append
, 
2635                 .search 
= &_jump_search
, 
2636                 .match 
= &_jump_match