+++ /dev/null
-/*
- * Copyright (c) 2007-2011 Apple Inc. All rights reserved.
- *
- * @APPLE_LICENSE_HEADER_START@
- *
- * This file contains Original Code and/or Modifications of Original Code
- * as defined in and that are subject to the Apple Public Source License
- * Version 2.0 (the 'License'). You may not use this file except in
- * compliance with the License. Please obtain a copy of the License at
- * http://www.opensource.apple.com/apsl/ and read it before using this
- * file.
- *
- * The Original Code and all software distributed under the License are
- * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
- * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
- * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
- * Please see the License for the specific language governing rights and
- * limitations under the License.
- *
- * @APPLE_LICENSE_HEADER_END@
- */
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <string.h>
-#include <errno.h>
-#include <dirent.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <asl.h>
-#include <asl_private.h>
-#include <asl_core.h>
-#include <asl_store.h>
-#include <notify.h>
-
-extern time_t asl_parse_time(const char *str);
-extern uint64_t asl_file_cursor(asl_file_t *s);
-extern uint32_t asl_file_match_start(asl_file_t *s, uint64_t start_id, int32_t direction);
-extern uint32_t asl_file_match_next(asl_file_t *s, aslresponse query, asl_msg_t **msg, uint64_t *last_id, int32_t direction, int32_t ruid, int32_t rgid);
-extern int asl_file_create(const char *path, uid_t uid, gid_t gid, mode_t mode);
-
-#define SECONDS_PER_DAY 86400
-
-/*
- * The ASL Store is organized as a set of files in a common directory.
- * Files are prefixed by the date (YYYY.MM.DD) of their contents.
- *
- * Messages with no access controls are saved in YYYY.MM.DD.asl
- * Messages with access limited to UID uuu are saved in YYYY.MM.DD.Uuuu.asl
- * Messages with access limited to GID ggg are saved in YYYY.MM.DD.Gggg.asl
- * Messages with access limited to UID uuu and GID ggg are saved in YYYY.MM.DD.Uuuu.Gggg.asl
- *
- * Messages that have a value for ASLExpireTime are saved in BB.YYYY.MM.DD.asl
- * where the timestamp is the "Best Before" date of the file. Access controls
- * are implemented as above with Uuuu and Gggg in the file name. Note that the
- * Best Before files are for the last day of the month, so a single file contains
- * messages that expire in that month.
- *
- * An external tool runs daily and deletes "old" files.
- */
-
-static time_t
-_asl_start_today()
-{
- time_t now;
- struct tm ctm;
-
- memset(&ctm, 0, sizeof(struct tm));
- now = time(NULL);
-
- if (localtime_r((const time_t *)&now, &ctm) == NULL) return 0;
-
- ctm.tm_sec = 0;
- ctm.tm_min = 0;
- ctm.tm_hour = 0;
-
- return mktime(&ctm);
-}
-
-/*
- * The base directory contains a data file which stores
- * the last record ID.
- *
- * | MAX_ID (uint64_t) |
- *
- */
-uint32_t
-asl_store_open_write(const char *basedir, asl_store_t **s)
-{
- asl_store_t *out;
- struct stat sb;
- uint32_t i, flags;
- char *path;
- FILE *sd;
- uint64_t last_id;
- time_t start;
-
- if (s == NULL) return ASL_STATUS_INVALID_ARG;
-
- start = _asl_start_today();
- if (start == 0) return ASL_STATUS_FAILED;
-
- if (basedir == NULL) basedir = PATH_ASL_STORE;
-
- memset(&sb, 0, sizeof(struct stat));
- if (stat(basedir, &sb) != 0) return ASL_STATUS_INVALID_STORE;
- if (!S_ISDIR(sb.st_mode)) return ASL_STATUS_INVALID_STORE;
-
- path = NULL;
- asprintf(&path, "%s/%s", basedir, FILE_ASL_STORE_DATA);
- if (path == NULL) return ASL_STATUS_NO_MEMORY;
-
- sd = NULL;
-
- memset(&sb, 0, sizeof(struct stat));
- if (stat(path, &sb) != 0)
- {
- if (errno != ENOENT)
- {
- free(path);
- return ASL_STATUS_FAILED;
- }
-
- sd = fopen(path, "w+");
- free(path);
-
- if (sd == NULL) return ASL_STATUS_FAILED;
-
- last_id = 0;
-
- /* Create new StoreData file (8 bytes ID + 4 bytes flags) */
-
- if (fwrite(&last_id, sizeof(uint64_t), 1, sd) != 1)
- {
- fclose(sd);
- return ASL_STATUS_WRITE_FAILED;
- }
-
- flags = 0;
- if (fwrite(&flags, sizeof(uint32_t), 1, sd) != 1)
- {
- fclose(sd);
- return ASL_STATUS_WRITE_FAILED;
- }
-
- /* flush data */
- fflush(sd);
- }
- else
- {
- sd = fopen(path, "r+");
- free(path);
-
- if (sd == NULL) return ASL_STATUS_FAILED;
- if (fread(&last_id, sizeof(uint64_t), 1, sd) != 1)
- {
- fclose(sd);
- return ASL_STATUS_READ_FAILED;
- }
-
- last_id = asl_core_ntohq(last_id);
- }
-
- out = (asl_store_t *)calloc(1, sizeof(asl_store_t));
- if (out == NULL)
- {
- fclose(sd);
- return ASL_STATUS_NO_MEMORY;
- }
-
- if (basedir == NULL) out->base_dir = strdup(PATH_ASL_STORE);
- else out->base_dir = strdup(basedir);
-
- if (out->base_dir == NULL)
- {
- fclose(sd);
- free(out);
- return ASL_STATUS_NO_MEMORY;
- }
-
- out->start_today = start;
- out->start_tomorrow = out->start_today + SECONDS_PER_DAY;
- out->storedata = sd;
- out->next_id = last_id + 1;
-
- for (i = 0; i < FILE_CACHE_SIZE; i++)
- {
- memset(&out->file_cache[i], 0, sizeof(asl_cached_file_t));
- out->file_cache[i].u = -1;
- out->file_cache[i].g = -1;
- }
-
- *s = out;
- return ASL_STATUS_OK;
-}
-
-uint32_t
-asl_store_statistics(asl_store_t *s, aslmsg *msg)
-{
- aslmsg out;
-
- if (s == NULL) return ASL_STATUS_INVALID_STORE;
- if (msg == NULL) return ASL_STATUS_INVALID_ARG;
-
- out = asl_new(ASL_TYPE_MSG);
- if (out == NULL) return ASL_STATUS_NO_MEMORY;
-
- /* does nothing for now */
-
- *msg = out;
- return ASL_STATUS_OK;
-}
-
-uint32_t
-asl_store_open_read(const char *basedir, asl_store_t **s)
-{
- asl_store_t *out;
- struct stat sb;
-
- if (s == NULL) return ASL_STATUS_INVALID_ARG;
-
- if (basedir == NULL) basedir = PATH_ASL_STORE;
-
- memset(&sb, 0, sizeof(struct stat));
- if (stat(basedir, &sb) != 0) return ASL_STATUS_INVALID_STORE;
- if (!S_ISDIR(sb.st_mode)) return ASL_STATUS_INVALID_STORE;
-
- out = (asl_store_t *)calloc(1, sizeof(asl_store_t));
- if (out == NULL) return ASL_STATUS_NO_MEMORY;
-
- if (basedir == NULL) out->base_dir = strdup(PATH_ASL_STORE);
- else out->base_dir = strdup(basedir);
-
- if (out->base_dir == NULL)
- {
- free(out);
- return ASL_STATUS_NO_MEMORY;
- }
-
- *s = out;
- return ASL_STATUS_OK;
-}
-
-uint32_t
-asl_store_max_file_size(asl_store_t *s, size_t max)
-{
- if (s == NULL) return ASL_STATUS_INVALID_STORE;
-
- s->max_file_size = max;
- return ASL_STATUS_OK;
-}
-
-__private_extern__ void
-asl_store_file_closeall(asl_store_t *s)
-{
- uint32_t i;
-
- if (s == NULL) return;
-
- for (i = 0; i < FILE_CACHE_SIZE; i++)
- {
- if (s->file_cache[i].f != NULL) asl_file_close(s->file_cache[i].f);
- s->file_cache[i].f = NULL;
- if (s->file_cache[i].path != NULL) free(s->file_cache[i].path);
- s->file_cache[i].path = NULL;
- s->file_cache[i].u = -1;
- s->file_cache[i].g = -1;
- s->file_cache[i].bb = 0;
- s->file_cache[i].ts = 0;
- }
-}
-
-uint32_t
-asl_store_close(asl_store_t *s)
-{
- if (s == NULL) return ASL_STATUS_OK;
-
- if (s->base_dir != NULL) free(s->base_dir);
- s->base_dir = NULL;
- asl_store_file_closeall(s);
- if (s->storedata != NULL) fclose(s->storedata);
-
- free(s);
-
- return ASL_STATUS_OK;
-}
-
-uint32_t
-asl_store_signal_sweep(asl_store_t *s)
-{
- char *str;
- int semfd;
- uint64_t xid;
- uint32_t status;
-
- if (s == NULL) return ASL_STATUS_INVALID_STORE;
-
- asprintf(&str, "%s/%s", s->base_dir, FILE_ASL_STORE_SWEEP_SEMAPHORE);
- if (str == NULL) return ASL_STATUS_NO_MEMORY;
-
- semfd = open(str, O_WRONLY | O_CREAT | O_NONBLOCK, 0644);
- free(str);
-
- if (semfd < 0) return ASL_STATUS_WRITE_FAILED;
-
- status = ASL_STATUS_OK;
-
- /* write the current message ID in the SweepStore file */
- xid = asl_core_htonq(s->next_id - 1);
- if (write(semfd, &xid, sizeof(uint64_t)) != sizeof(uint64_t)) status = ASL_STATUS_WRITE_FAILED;
-
- close(semfd);
- return status;
-}
-
-/*
- * Sweep the file cache.
- * Close any files that have not been used in the last FILE_CACHE_TTL seconds.
- * Returns least recently used or unused cache slot.
- */
-static uint32_t
-asl_store_file_cache_lru(asl_store_t *s, time_t now, uint32_t ignorex)
-{
- time_t min;
- uint32_t i, x;
-
- if (s == NULL) return 0;
-
- x = 0;
- min = now - FILE_CACHE_TTL;
-
- for (i = 0; i < FILE_CACHE_SIZE; i++)
- {
- if ((i != ignorex) && (s->file_cache[i].ts < min))
- {
- asl_file_close(s->file_cache[i].f);
- s->file_cache[i].f = NULL;
- if (s->file_cache[i].path != NULL) free(s->file_cache[i].path);
- s->file_cache[i].path = NULL;
- s->file_cache[i].u = -1;
- s->file_cache[i].g = -1;
- s->file_cache[i].bb = 0;
- s->file_cache[i].ts = 0;
- }
-
- if (s->file_cache[i].ts < s->file_cache[x].ts) x = i;
- }
-
- return x;
-}
-
-uint32_t
-asl_store_sweep_file_cache(asl_store_t *s)
-{
- if (s == NULL) return ASL_STATUS_INVALID_STORE;
-
- asl_store_file_cache_lru(s, time(NULL), FILE_CACHE_SIZE);
- return ASL_STATUS_OK;
-}
-
-static char *
-asl_store_make_ug_path(const char *dir, const char *base, const char *ext, uid_t ruid, gid_t rgid, uid_t *u, gid_t *g, mode_t *m)
-{
- char *path = NULL;
-
- *u = 0;
- *g = 0;
- *m = 0644;
-
- if (ruid == -1)
- {
- if (rgid == -1)
- {
- if (ext == NULL) asprintf(&path, "%s/%s", dir, base);
- else asprintf(&path, "%s/%s.%s", dir, base, ext);
- }
- else
- {
- *g = rgid;
- *m = 0600;
- if (ext == NULL) asprintf(&path, "%s/%s.G%d", dir, base, *g);
- else asprintf(&path, "%s/%s.G%d.%s", dir, base, *g, ext);
- }
- }
- else
- {
- *u = ruid;
- if (rgid == -1)
- {
- *m = 0600;
- if (ext == NULL) asprintf(&path, "%s/%s.U%d", dir, base, *u);
- else asprintf(&path, "%s/%s.U%d.%s", dir, base, *u, ext);
- }
- else
- {
- *g = rgid;
- *m = 0600;
- if (ext == NULL) asprintf(&path, "%s/%s.U%d.G%d", dir, base, *u, *g);
- else asprintf(&path, "%s/%s.U%d.G%u.%s", dir, base, *u, *g, ext);
- }
- }
-
- return path;
-}
-
-static uint32_t
-asl_store_file_open_write(asl_store_t *s, char *tstring, int32_t ruid, int32_t rgid, time_t bb, asl_file_t **f, time_t now, uint32_t check_cache)
-{
- char *path;
- mode_t m;
- int32_t i, x;
- uid_t u;
- gid_t g;
- uint32_t status;
- asl_file_t *out;
-
- if (s == NULL) return ASL_STATUS_INVALID_STORE;
-
- /* see if the file is already open and in the cache */
- for (i = 0; i < FILE_CACHE_SIZE; i++)
- {
- if ((s->file_cache[i].u == ruid) && (s->file_cache[i].g == rgid) && (s->file_cache[i].bb == bb) && (s->file_cache[i].f != NULL))
- {
- s->file_cache[i].ts = now;
- *f = s->file_cache[i].f;
- if (check_cache == 1) asl_store_file_cache_lru(s, now, i);
- return ASL_STATUS_OK;
- }
- }
-
- u = 0;
- g = 0;
- m = 0644;
- path = asl_store_make_ug_path(s->base_dir, tstring, "asl", (uid_t)ruid, (gid_t)rgid, &u, &g, &m);
- if (path == NULL) return ASL_STATUS_NO_MEMORY;
-
- out = NULL;
- status = asl_file_open_write(path, m, u, g, &out);
- if (status != ASL_STATUS_OK)
- {
- free(path);
- return status;
- }
-
- x = asl_store_file_cache_lru(s, now, FILE_CACHE_SIZE);
- if (s->file_cache[x].f != NULL) asl_file_close(s->file_cache[x].f);
- if (s->file_cache[x].path != NULL) free(s->file_cache[x].path);
-
- s->file_cache[x].f = out;
- s->file_cache[x].path = path;
- s->file_cache[x].u = ruid;
- s->file_cache[x].g = rgid;
- s->file_cache[x].bb = bb;
- s->file_cache[x].ts = time(NULL);
-
- *f = out;
-
- return ASL_STATUS_OK;
-}
-
-__private_extern__ char *
-asl_store_file_path(asl_store_t *s, asl_file_t *f)
-{
- uint32_t i;
-
- if (s == NULL) return NULL;
-
- for (i = 0; i < FILE_CACHE_SIZE; i++)
- {
- if (s->file_cache[i].f == f)
- {
- if (s->file_cache[i].path == NULL) return NULL;
- return strdup(s->file_cache[i].path);
- }
- }
-
- return NULL;
-}
-
-__private_extern__ void
-asl_store_file_close(asl_store_t *s, asl_file_t *f)
-{
- uint32_t i;
-
- if (s == NULL) return;
- if (f == NULL) return;
-
- for (i = 0; i < FILE_CACHE_SIZE; i++)
- {
- if (s->file_cache[i].f == f)
- {
- asl_file_close(s->file_cache[i].f);
- s->file_cache[i].f = NULL;
- if (s->file_cache[i].path != NULL) free(s->file_cache[i].path);
- s->file_cache[i].path = NULL;
- s->file_cache[i].u = -1;
- s->file_cache[i].g = -1;
- s->file_cache[i].bb = 0;
- s->file_cache[i].ts = 0;
- return;
- }
- }
-}
-
-uint32_t
-asl_store_save(asl_store_t *s, aslmsg msg)
-{
- struct tm ctm;
- time_t msg_time, now, bb;
- char *path, *tmp_path, *tstring, *scratch;
- const char *val;
- uid_t ruid;
- gid_t rgid;
- asl_file_t *f;
- uint32_t status, check_cache, signal_sweep, len;
- uint64_t xid, ftime;
- size_t fsize;
-
- if (s == NULL) return ASL_STATUS_INVALID_STORE;
- if (msg == NULL) return ASL_STATUS_INVALID_ARG;
-
- now = time(NULL);
-
- check_cache = 0;
- if ((s->last_write + FILE_CACHE_TTL) <= now) check_cache = 1;
-
- signal_sweep = 0;
-
- msg_time = 0;
- val = asl_get(msg, ASL_KEY_TIME);
- if (val == NULL) msg_time = now;
- else msg_time = asl_parse_time(val);
-
- if (msg_time >= s->start_tomorrow)
- {
- if (now >= s->start_tomorrow)
- {
- /* new day begins */
- check_cache = 0;
- signal_sweep = 1;
- asl_store_file_closeall(s);
-
- /*
- * _asl_start_today should never fail, but if it does,
- * just push forward one day. That will probably be correct, and if
- * it isn't, the next message that gets saved will push it ahead again
- * until we get to the right date.
- */
- s->start_today = _asl_start_today();
- if (s->start_today == 0) s->start_today = s->start_tomorrow;
-
- s->start_tomorrow = s->start_today + SECONDS_PER_DAY;
- }
- }
-
- val = asl_get(msg, ASL_KEY_READ_UID);
- ruid = -1;
- if (val != NULL) ruid = atoi(val);
-
- val = asl_get(msg, ASL_KEY_READ_GID);
- rgid = -1;
- if (val != NULL) rgid = atoi(val);
-
- bb = 0;
- val = asl_get(msg, ASL_KEY_EXPIRE_TIME);
- if (val != NULL)
- {
- bb = 1;
- msg_time = asl_parse_time(val);
- }
-
- if (fseeko(s->storedata, 0, SEEK_SET) != 0) return ASL_STATUS_WRITE_FAILED;
-
- xid = asl_core_htonq(s->next_id);
- if (fwrite(&xid, sizeof(uint64_t), 1, s->storedata) != 1) return ASL_STATUS_WRITE_FAILED;
-
- /* flush data */
- fflush(s->storedata);
-
- xid = s->next_id;
- s->next_id++;
-
- s->last_write = now;
-
- if (localtime_r((const time_t *)&msg_time, &ctm) == NULL) return ASL_STATUS_FAILED;
-
- tstring = NULL;
- if (bb == 1)
- {
- /*
- * This supports 12 monthly "Best Before" buckets.
- * We advance the actual expiry time to day zero of the following month.
- * mktime() is clever enough to know that you actually mean the last day
- * of the previous month. What we get back from localtime is the last
- * day of the month in which the message expires, which we use in the name.
- */
- ctm.tm_sec = 0;
- ctm.tm_min = 0;
- ctm.tm_hour = 0;
- ctm.tm_mday = 0;
- ctm.tm_mon += 1;
-
- bb = mktime(&ctm);
-
- if (localtime_r((const time_t *)&bb, &ctm) == NULL) return ASL_STATUS_FAILED;
- asprintf(&tstring, "BB.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
- }
- else
- {
- asprintf(&tstring, "%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
- }
-
- if (tstring == NULL) return ASL_STATUS_NO_MEMORY;
-
- status = asl_store_file_open_write(s, tstring, ruid, rgid, bb, &f, now, check_cache);
- free(tstring);
- tstring = NULL;
-
- if (status != ASL_STATUS_OK) return status;
-
- status = asl_file_save(f, msg, &xid);
- if (status != ASL_STATUS_OK) return status;
-
- fsize = asl_file_size(f);
- ftime = asl_file_ctime(f);
-
- /* if file is larger than max_file_size, rename it and touch semaphore file in the store */
- if ((s->max_file_size != 0) && (fsize > s->max_file_size))
- {
- signal_sweep = 1;
- status = ASL_STATUS_OK;
-
- path = asl_store_file_path(s, f);
-
- asl_store_file_close(s, f);
-
- if (path != NULL)
- {
- tmp_path = NULL;
-
- len = strlen(path);
- if ((len >= 4) && (!strcmp(path + len - 4, ".asl")))
- {
- /* rename xxxxxxx.asl to xxxxxxx.timestamp.asl */
- scratch = strdup(path);
- if (scratch != NULL)
- {
- scratch[len - 4] = '\0';
- asprintf(&tmp_path, "%s.%llu.asl", scratch, ftime);
- free(scratch);
-
- }
- }
- else
- {
- /* append timestamp */
- asprintf(&tmp_path, "%s.%llu", path, ftime);
- }
-
- if (tmp_path == NULL)
- {
- status = ASL_STATUS_NO_MEMORY;
- }
- else
- {
- if (rename(path, tmp_path) != 0) status = ASL_STATUS_FAILED;
- free(tmp_path);
- }
-
- free(path);
- }
- }
-
- if (signal_sweep != 0) asl_store_signal_sweep(s);
-
- return status;
-}
-
-static uint32_t
-asl_store_mkdir(asl_store_t *s, const char *dir, mode_t m)
-{
- char *tstring = NULL;
- int status;
- struct stat sb;
-
- asprintf(&tstring, "%s/%s", s->base_dir, dir);
- if (tstring == NULL) return ASL_STATUS_NO_MEMORY;
-
- memset(&sb, 0, sizeof(struct stat));
- status = stat(tstring, &sb);
-
- if (status == 0)
- {
- /* must be a directory */
- if (!S_ISDIR(sb.st_mode))
- {
- free(tstring);
- return ASL_STATUS_INVALID_STORE;
- }
- }
- else
- {
- if (errno == ENOENT)
- {
- /* doesn't exist - create it */
- if (mkdir(tstring, m) != 0)
- {
- free(tstring);
- return ASL_STATUS_WRITE_FAILED;
- }
- }
- else
- {
- /* stat failed for some other reason */
- free(tstring);
- return ASL_STATUS_FAILED;
- }
- }
-
- free(tstring);
- return ASL_STATUS_OK;
-}
-
-uint32_t
-asl_store_open_aux(asl_store_t *s, aslmsg msg, int *out_fd, char **url)
-{
- struct tm ctm;
- time_t msg_time, bb;
- char *path, *dir, *tstring;
- const char *val;
- uid_t ruid, u;
- gid_t rgid, g;
- mode_t m;
- uint32_t status;
- uint64_t fid;
- int fd;
-
- if (s == NULL) return ASL_STATUS_INVALID_STORE;
- if (msg == NULL) return ASL_STATUS_INVALID_ARG;
- if (out_fd == NULL) return ASL_STATUS_INVALID_ARG;
- if (url == NULL) return ASL_STATUS_INVALID_ARG;
-
- msg_time = time(NULL);
-
- val = asl_get(msg, ASL_KEY_READ_UID);
- ruid = -1;
- if (val != NULL) ruid = atoi(val);
-
- val = asl_get(msg, ASL_KEY_READ_GID);
- rgid = -1;
- if (val != NULL) rgid = atoi(val);
-
- bb = 0;
- val = asl_get(msg, ASL_KEY_EXPIRE_TIME);
- if (val != NULL)
- {
- bb = 1;
- msg_time = asl_parse_time(val);
- }
-
- if (localtime_r((const time_t *)&msg_time, &ctm) == NULL) return ASL_STATUS_FAILED;
-
- dir = NULL;
- if (bb == 1)
- {
- /*
- * This supports 12 monthly "Best Before" buckets.
- * We advance the actual expiry time to day zero of the following month.
- * mktime() is clever enough to know that you actually mean the last day
- * of the previous month. What we get back from localtime is the last
- * day of the month in which the message expires, which we use in the name.
- */
- ctm.tm_sec = 0;
- ctm.tm_min = 0;
- ctm.tm_hour = 0;
- ctm.tm_mday = 0;
- ctm.tm_mon += 1;
-
- bb = mktime(&ctm);
-
- if (localtime_r((const time_t *)&bb, &ctm) == NULL) return ASL_STATUS_FAILED;
- asprintf(&dir, "BB.AUX.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
- }
- else
- {
- asprintf(&dir, "AUX.%d.%02d.%02d", ctm.tm_year + 1900, ctm.tm_mon + 1, ctm.tm_mday);
- }
-
- if (dir == NULL) return ASL_STATUS_NO_MEMORY;
-
- status = asl_store_mkdir(s, dir, 0755);
- if (status != ASL_STATUS_OK)
- {
- free(dir);
- return status;
- }
-
- fid = s->next_id;
- s->next_id++;
- tstring = NULL;
-
- asprintf(&tstring, "%s/%llu", dir, fid);
- free(dir);
- if (tstring == NULL) return ASL_STATUS_NO_MEMORY;
-
- u = 0;
- g = 0;
- m = 0644;
- path = asl_store_make_ug_path(s->base_dir, tstring, NULL, ruid, rgid, &u, &g, &m);
- free(tstring);
- if (path == NULL) return ASL_STATUS_NO_MEMORY;
-
- fd = asl_file_create(path, u, g, m);
- if (fd < 0)
- {
- free(path);
- *out_fd = -1;
- return ASL_STATUS_WRITE_FAILED;
- }
-
- /* URL is file://<path> */
- *url = NULL;
- asprintf(url, "file://%s", path);
- free(path);
-
- *out_fd = fd;
-
- return status;
-}
-
-uint32_t
-asl_store_match_timeout(asl_store_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction, uint32_t usec)
-{
- DIR *dp;
- struct dirent *dent;
- uint32_t status;
- asl_file_t *f;
- char *path;
- asl_file_list_t *files;
-
- if (s == NULL) return ASL_STATUS_INVALID_STORE;
- if (res == NULL) return ASL_STATUS_INVALID_ARG;
-
- files = NULL;
-
- /*
- * Open all readable files
- */
- dp = opendir(s->base_dir);
- if (dp == NULL) return ASL_STATUS_READ_FAILED;
-
- while ((dent = readdir(dp)) != NULL)
- {
- if (dent->d_name[0] == '.') continue;
-
- path = NULL;
- asprintf(&path, "%s/%s", s->base_dir, dent->d_name);
-
- /* NB asl_file_open_read will fail if path is NULL, if the file is not an ASL store file, or if it isn't readable */
- status = asl_file_open_read(path, &f);
- if (path != NULL) free(path);
- if ((status != ASL_STATUS_OK) || (f == NULL)) continue;
-
- files = asl_file_list_add(files, f);
- }
-
- closedir(dp);
-
- status = asl_file_list_match_timeout(files, query, res, last_id, start_id, count, direction, usec);
- asl_file_list_close(files);
- return status;
-}
-
-uint32_t
-asl_store_match(asl_store_t *s, aslresponse query, aslresponse *res, uint64_t *last_id, uint64_t start_id, uint32_t count, int32_t direction)
-{
- return asl_store_match_timeout(s, query, res, last_id, start_id, count, direction, 0);
-}
-
-uint32_t
-asl_store_match_start(asl_store_t *s, uint64_t start_id, int32_t direction)
-{
- DIR *dp;
- struct dirent *dent;
- uint32_t status;
- asl_file_t *f;
- char *path;
- asl_file_list_t *files;
-
- if (s == NULL) return ASL_STATUS_INVALID_STORE;
-
- if (s->work != NULL) asl_file_list_match_end(s->work);
- s->work = NULL;
-
- files = NULL;
-
- /*
- * Open all readable files
- */
- dp = opendir(s->base_dir);
- if (dp == NULL) return ASL_STATUS_READ_FAILED;
-
- while ((dent = readdir(dp)) != NULL)
- {
- if (dent->d_name[0] == '.') continue;
-
- path = NULL;
- asprintf(&path, "%s/%s", s->base_dir, dent->d_name);
-
- /* NB asl_file_open_read will fail if path is NULL, if the file is not an ASL store file, or if it isn't readable */
- status = asl_file_open_read(path, &f);
- if (path != NULL) free(path);
- if ((status != ASL_STATUS_OK) || (f == NULL)) continue;
-
- files = asl_file_list_add(files, f);
- }
-
- closedir(dp);
-
- s->work = asl_file_list_match_start(files, start_id, direction);
- if (s->work == NULL) return ASL_STATUS_FAILED;
-
- return ASL_STATUS_OK;
-}
-
-uint32_t
-asl_store_match_next(asl_store_t *s, aslresponse query, aslresponse *res, uint32_t count)
-{
- if (s == NULL) return ASL_STATUS_INVALID_STORE;
- if (s->work == NULL) return ASL_STATUS_OK;
-
- return asl_file_list_match_next(s->work, query, res, count);
-}