watch_database.c File Reference

Implementation of the watch database persistent store. More...

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdint.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/param.h>
#include <unistd.h>
#include <sqlite3.h>
#include "config.h"
#include "util.h"
#include "logging.h"
#include "watch_database.h"
#include "path_utils.h"

Go to the source code of this file.

Classes

struct  path_info_iter_context_t
 Private internal context used to iterate over the set of lwatch_path_info_t structs returned by a watch database query. More...

Defines

#define _GNU_SOURCE
 Turn on GNU extensions.
#define COLUMNS_STRING   "path, original_path, flags, version, reap_time, reap_position, dev, inode, mode, uid, gid, size, access_time, modification_time, change_time"
 The column names for lwatch_event_t persistent storage.
Column indices for lwatch_event_t persistent storage.
#define PATH_COLUMN   0
 lwatch_event_t column index for "path"
#define ORIGINAL_PATH_COLUMN   1
 lwatch_event_t column index for "original_path"
#define FLAGS_COLUMN   2
 lwatch_event_t column index for "flags"
#define VERSION_COLUMN   3
 lwatch_event_t column index for "version"
#define REAP_TIME_COLUMN   4
 lwatch_event_t column index for "reap_time"
#define REAP_POSITION_COLUMN   5
 lwatch_event_t column index for "reap_position"
#define DEV_COLUMN   6
 lwatch_event_t column index for "dev"
#define INODE_COLUMN   7
 lwatch_event_t column index for "inode"
#define MODE_COLUMN   8
 lwatch_event_t column index for "mode"
#define UID_COLUMN   9
 lwatch_event_t column index for "uid"
#define GID_COLUMN   10
 lwatch_event_t column index for "gid"
#define SIZE_COLUMN   11
 lwatch_event_t column index for "size"
#define ACCESS_TIME_COLUMN   12
 lwatch_event_t column index for "access_time"
#define MODIFICATION_TIME_COLUMN   13
 lwatch_event_t column index for "modification_time"
#define CHANGE_TIME_COLUMN   14
 lwatch_event_t column index for "change_time"

Functions

static const char * sqlite3_result_string (int result)
 Translate a SQLite result code to a string.
static int table_exists (const char *table_name, bool *exists)
 Set variable to true if specified table exists in SQLite database.
static int create_table (const char *table_name, const char *table_schema)
 Create a new SQLite table in the database using supplied schema.
static int populate_path_info (struct lwatch_path_info_t *path_info, sqlite3_stmt *stmt)
 Copy the data from a SQLite query result into a lwatch_path_info_t struct.
static struct lwatch_path_info_tpath_info_iter_next (struct path_info_iter_context_t *iter)
 Used to iterate through SQLite query result of lwatch_path_info_t structs.
static int new_path_info_iter_context (struct path_info_iter_context_t **iter_arg)
 Allocate and initialize a new path_info iteration context.
static int init_statement (struct sqlite3_stmt **stmt_arg, const char *fmt,...)
 Create a SQLite prepared statement from printf style arguments.
static int destroy_statement (sqlite3_stmt **stmt_arg)
 Destroy a SQLite prepared statement.
static int reset_statement (sqlite3_stmt *stmt)
 Resets a prepared statement readying it for parameter binding and execution.
int database_write_path_info (struct lwatch_path_info_t *path_info)
 Write the supplied lwatch_path_info_t struct into the database.
int init_path_info (struct lwatch_path_info_t *path_info, const char *path)
 Initialize a lwatch_path_info_t struct.
int new_path_info (const char *path, struct lwatch_path_info_t **path_info_arg)
 Allocate and initialize a new lwatch_path_info_t struct.
char * path_info_flags_string (unsigned long flag, const char *separator)
 Render the lwatch_path_info_t flag bitset as a string.
char * path_info_string (struct lwatch_path_info_t *path_info, const char *prefix)
 Render a lwatch_path_info_t struct as a string.
const char * watch_database_error_string (int error)
 Render a database error code as a string.
int watch_database_init ()
 Initialize the watch database subsystem.
int watch_database_fini ()
 Close the watch database subsystem, release all resources, close database.
int database_lookup_path_info (const char *path, struct lwatch_path_info_t *path_info)
 Given a path name lookup the matching lwatch_path_info_t in the database.
int database_query_all_paths_iter (struct database_iter_context_t **iter_arg, const char *path_filter_arg)
 Get an iterator to every lwatch_path_info_t row in the database.
int database_query_backups_iter (struct database_iter_context_t **iter_arg)
 Get an iterator to every lwatch_path_info_t row in the database which is a backup to a primary file.
int database_query_backups_of_target_iter (struct database_iter_context_t **iter_arg, const char *path)
 Get an iterator to each lwatch_path_info_t row in the database which is a backup to the specified primary file.
int database_query_pending_reaps_iter (struct database_iter_context_t **iter_arg)
 Get an iterator to every lwatch_path_info_t row which has a reap pending.
int database_query_targets_iter (struct database_iter_context_t **iter_arg)
 Get an iterator to every lwatch_path_info_t row which is a primary watch file, i.e.

Variables

static const char * lwatch_table_schema
 SQLSchema used to store lwatch_path_info_t persistently.
static char watch_database_pathname [PATH_MAX] = WATCH_DATABASE_PATHNAME
 The pathname of the SQLite database.
static sqlite3 * database_handle = NULL
 The handle to the open SQLite database.
SQLite Prepared Statements
All of these variable are handles to prepared statements which are compiled at initialization time and can be invoked more efficiently due to their precompilation.

sqlite3_stmt * table_exists_stmt = NULL
 test if a table exists in the database
sqlite3_stmt * lookup_path_stmt = NULL
 lookup single lwatch_path_info_t using the path field as key
sqlite3_stmt * insert_path_stmt = NULL
 insert lwatch_path_info_t into database
sqlite3_stmt * query_all_stmt = NULL
 lookup multiple lwatch_path_info_t by matching path field with wildcards
sqlite3_stmt * query_backups_stmt = NULL
 lookup multiple lwatch_path_info_t which have the BACKUP_FLAG set
sqlite3_stmt * query_backups_of_target_stmt = NULL
 lookup multiple lwatch_path_info_t which are backups of a primary target
sqlite3_stmt * query_pending_reaps_stmt = NULL
 lookup multiple lwatch_path_info_t which have the NEEDS_REAPING_FLAG set, i.e.
sqlite3_stmt * query_targets_stmt = NULL
 lookup multiple lwatch_path_info_t which have the TARGET_FLAG set, i.e.


Detailed Description

Implementation of the watch database persistent store.

Definition in file watch_database.c.


Function Documentation

static int create_table ( const char *  table_name,
const char *  table_schema 
) [static]

Create a new SQLite table in the database using supplied schema.

Parameters:
[in] table_name The name of the table to create.
[in] table_schema String containing the SQLite schema for the table.
Returns:
SUCCESS (0) or non-zero error code otherwise

Definition at line 390 of file watch_database.c.

Referenced by watch_database_init().

00391 {
00392     int result, sql_result;
00393     char *statement;
00394     char *err_msg;
00395 
00396     result = SUCCESS;
00397 
00398     if (asprintf(&statement, "create table %s (%s);", table_name, table_schema) < 0) {
00399         log_msg(LOG_ERROR, _("cannot create statement string\n"));
00400         return ENOMEM;
00401     }
00402 
00403     if ((sql_result = sqlite3_exec(database_handle, statement, NULL, NULL, &err_msg)) != SQLITE_OK) {
00404         log_msg(LOG_ERROR, _("sqlite3_exec \"%s\", failed with error %d (%s)\n"),  statement, sql_result, err_msg);
00405         sqlite3_free(err_msg);
00406         result = WATCH_DATABASE_ERROR_CANNOT_CREATE_TABLE;
00407     }
00408 
00409     free(statement);
00410 
00411     return result;
00412 }

int database_lookup_path_info ( const char *  path,
struct lwatch_path_info_t path_info 
)

Given a path name lookup the matching lwatch_path_info_t in the database.

Parameters:
[in] path Path Name whose lwatch_path_info_t we seek
[out] path_info Pointer to lwatch_path_info_t which will be initialized from the database upon success.
Returns:
SUCCESS (0) or non-zero error code otherwise. WATCH_DATABASE_ERROR_NOT_FOUND indicates the path was not found as opposed to other more general run-time errors.

Definition at line 968 of file watch_database.c.

Referenced by get_create_path_info(), process_file_close(), process_file_create(), process_file_delete(), process_file_modification(), and process_file_rename().

00969 {
00970     int error, result, step_result;
00971     int n_rows;
00972 
00973     result = SUCCESS;
00974 
00975     if ((error = reset_statement(lookup_path_stmt)) != SUCCESS) {
00976         result = WATCH_DATABASE_ERROR_CANNOT_QUERY;
00977         goto exit;
00978     }
00979 
00980     if ((error = sqlite3_bind_text(lookup_path_stmt, 1, path, -1, SQLITE_TRANSIENT)) != SQLITE_OK) {
00981         const char *err_msg = sqlite3_errmsg(database_handle);
00982         log_msg(LOG_ERROR, _("sqlite3_bind_text \"%s\", (%s)\n"),  sqlite3_sql(lookup_path_stmt), err_msg);
00983         result = WATCH_DATABASE_ERROR_CANNOT_QUERY;
00984         goto exit;
00985     }
00986 
00987     n_rows = 0;
00988     while(true) {
00989         step_result = sqlite3_step(lookup_path_stmt);
00990         if (step_result == SQLITE_DONE) {
00991             break;
00992         } else if (step_result == SQLITE_ROW) {
00993             if (n_rows == 0) {
00994                 if ((error = populate_path_info(path_info, lookup_path_stmt)) != SUCCESS) {
00995                     log_msg(LOG_ERROR, _("populate_path_info() failed for path \"%s\" (%s)"),
00996                             path, error_string(error));
00997                     result = error;
00998                 }
00999             }
01000             n_rows++;
01001         } else {
01002             const char *err_msg = sqlite3_errmsg(database_handle);
01003             log_msg(LOG_ERROR, _("sqlite3_step \"%s\", unexpected result %s (%s)\n"),
01004                     sqlite3_sql(lookup_path_stmt), sqlite3_result_string(step_result), err_msg);
01005         }
01006     }
01007 
01008  exit:
01009     if (result == SUCCESS) {
01010         if (n_rows == 0)
01011             result = WATCH_DATABASE_ERROR_NOT_FOUND;
01012         else if (n_rows > 1)
01013             result = WATCH_DATABASE_ERROR_FOUND_MULTIPLE;
01014     }
01015     return result;
01016 }

int database_query_all_paths_iter ( struct database_iter_context_t **  iter_arg,
const char *  path_filter_arg 
)

Get an iterator to every lwatch_path_info_t row in the database.

Parameters:
[out] iter_arg Iterator context returned here, NULL if failure
[in] path_filter_arg SQL "like" wildcard pattern, path must match this pattern to be included in result set. If NULL then no filtering is performed, all paths will match.
Returns:
SUCCESS (0) or non-zero error code otherwise

Definition at line 1028 of file watch_database.c.

Referenced by dump_database().

01029 {
01030     int error;
01031     struct path_info_iter_context_t *iter;
01032     const char *path_filter;
01033 
01034     *iter_arg = NULL;
01035     if ((error = new_path_info_iter_context(&iter)) != SUCCESS) {
01036         log_msg(LOG_ERROR, _("cannot allocate new iteration context (%s)\n"), error_string(error));
01037         return error;
01038     }
01039 
01040     iter->stmt = query_all_stmt;
01041 
01042     if ((iter->iter.error = reset_statement(iter->stmt)) != SQLITE_OK) {
01043         free(iter);
01044         return WATCH_DATABASE_ERROR_CANNOT_QUERY;
01045     }
01046 
01047     if (path_filter_arg == NULL)
01048         path_filter = "%";
01049     else
01050         path_filter = path_filter_arg;
01051 
01052     if ((iter->iter.error = sqlite3_bind_text(iter->stmt, 1, path_filter, -1, SQLITE_TRANSIENT)) != SQLITE_OK) {
01053         const char *err_msg = sqlite3_errmsg(database_handle);
01054         log_msg(LOG_ERROR, _("sqlite3_bind_text \"%s\", (%s)\n"),  sqlite3_sql(iter->stmt), err_msg);
01055         free(iter);
01056         return  WATCH_DATABASE_ERROR_CANNOT_QUERY;
01057     }
01058 
01059     *iter_arg = (struct database_iter_context_t *)iter;
01060     return SUCCESS;
01061 }

int database_query_backups_iter ( struct database_iter_context_t **  iter_arg  ) 

Get an iterator to every lwatch_path_info_t row in the database which is a backup to a primary file.

Parameters:
[out] iter_arg Iterator context returned here, NULL if failure
Returns:
SUCCESS (0) or non-zero error code otherwise

Definition at line 1070 of file watch_database.c.

Referenced by validate_backups_in_database().

01071 {
01072     int error;
01073     struct path_info_iter_context_t *iter;
01074 
01075     *iter_arg = NULL;
01076     if ((error = new_path_info_iter_context(&iter)) != SUCCESS) {
01077         log_msg(LOG_ERROR, _("cannot allocate new iteration context (%s)\n"), error_string(error));
01078         return error;
01079     }
01080 
01081     iter->stmt = query_backups_stmt;
01082 
01083     if ((iter->iter.error = reset_statement(iter->stmt)) != SQLITE_OK) {
01084         free(iter);
01085         return WATCH_DATABASE_ERROR_CANNOT_QUERY;
01086     }
01087 
01088     *iter_arg = (struct database_iter_context_t *)iter;
01089     return SUCCESS;
01090 }

int database_query_backups_of_target_iter ( struct database_iter_context_t **  iter_arg,
const char *  path 
)

Get an iterator to each lwatch_path_info_t row in the database which is a backup to the specified primary file.

Parameters:
[out] iter_arg Iterator context returned here, NULL if failure
[in] path The path name of the primary file whose backup's are sought
Returns:
SUCCESS (0) or non-zero error code otherwise

Definition at line 1100 of file watch_database.c.

Referenced by dump_database().

01101 {
01102     int error;
01103     struct path_info_iter_context_t *iter;
01104 
01105     *iter_arg = NULL;
01106     if ((error = new_path_info_iter_context(&iter)) != SUCCESS) {
01107         log_msg(LOG_ERROR, _("cannot allocate new iteration context (%s)\n"), error_string(error));
01108         return error;
01109     }
01110 
01111     iter->stmt = query_backups_of_target_stmt;
01112 
01113     if ((iter->iter.error = reset_statement(iter->stmt)) != SQLITE_OK) {
01114         free(iter);
01115         return WATCH_DATABASE_ERROR_CANNOT_QUERY;
01116     }
01117 
01118     if ((iter->iter.error = sqlite3_bind_text(iter->stmt, 1, path, -1, SQLITE_TRANSIENT)) != SQLITE_OK) {
01119         const char *err_msg = sqlite3_errmsg(database_handle);
01120         log_msg(LOG_ERROR, _("sqlite3_bind_text \"%s\", (%s)\n"),  sqlite3_sql(iter->stmt), err_msg);
01121         free(iter);
01122         return  WATCH_DATABASE_ERROR_CANNOT_QUERY;
01123     }
01124 
01125     *iter_arg = (struct database_iter_context_t *)iter;
01126     return SUCCESS;
01127 }

int database_query_pending_reaps_iter ( struct database_iter_context_t **  iter_arg  ) 

Get an iterator to every lwatch_path_info_t row which has a reap pending.

Parameters:
[out] iter_arg Iterator context returned here, NULL if failure
Returns:
SUCCESS (0) or non-zero error code otherwise

Definition at line 1135 of file watch_database.c.

Referenced by process_pending_reaps().

01136 {
01137     int error;
01138     struct path_info_iter_context_t *iter;
01139 
01140     *iter_arg = NULL;
01141     if ((error = new_path_info_iter_context(&iter)) != SUCCESS) {
01142         log_msg(LOG_ERROR, _("cannot allocate new iteration context (%s)\n"), error_string(error));
01143         return error;
01144     }
01145 
01146     iter->stmt = query_pending_reaps_stmt;
01147 
01148     if ((iter->iter.error = reset_statement(iter->stmt)) != SQLITE_OK) {
01149         free(iter);
01150         return WATCH_DATABASE_ERROR_CANNOT_QUERY;
01151     }
01152 
01153     *iter_arg = (struct database_iter_context_t *)iter;
01154     return SUCCESS;
01155 }

int database_query_targets_iter ( struct database_iter_context_t **  iter_arg  ) 

Get an iterator to every lwatch_path_info_t row which is a primary watch file, i.e.

a "target".

Parameters:
[out] iter_arg Iterator context returned here, NULL if failure
Returns:
SUCCESS (0) or non-zero error code otherwise

Definition at line 1164 of file watch_database.c.

01165 {
01166     int error;
01167     struct path_info_iter_context_t *iter;
01168 
01169     *iter_arg = NULL;
01170     if ((error = new_path_info_iter_context(&iter)) != SUCCESS) {
01171         log_msg(LOG_ERROR, _("cannot allocate new iteration context (%s)\n"), error_string(error));
01172         return error;
01173     }
01174 
01175     iter->stmt = query_targets_stmt;
01176 
01177     if ((iter->iter.error = reset_statement(iter->stmt)) != SQLITE_OK) {
01178         free(iter);
01179         return WATCH_DATABASE_ERROR_CANNOT_QUERY;
01180     }
01181 
01182     *iter_arg = (struct database_iter_context_t *)iter;
01183     return SUCCESS;
01184 }

int database_write_path_info ( struct lwatch_path_info_t path_info  ) 

Write the supplied lwatch_path_info_t struct into the database.

Parameters:
[in] path_info The lwatch_path_info_t to write into the database
Returns:
SUCCESS (0) or non-zero error code otherwise

Definition at line 523 of file watch_database.c.

Referenced by get_create_path_info(), process_file_close(), process_file_delete(), process_file_modification(), process_file_rename(), reap_file_data(), start_monitoring(), update_stat_info_and_write(), and validate_backups_in_database().

00524 {
00525     int error, result, step_result;
00526 
00527     result = SUCCESS;
00528 
00529     if ((error = reset_statement(insert_path_stmt)) != SUCCESS) {
00530         result = WATCH_DATABASE_ERROR_CANNOT_QUERY;
00531         goto exit;
00532     }
00533 
00534 
00535     if ((error = sqlite3_bind_text(insert_path_stmt,  PATH_COLUMN + 1,              path_info->path,          -1, SQLITE_TRANSIENT))
00536         != SQLITE_OK) goto bind_error;
00537     if ((error = sqlite3_bind_text(insert_path_stmt,  ORIGINAL_PATH_COLUMN + 1,     path_info->original_path, -1, SQLITE_TRANSIENT))
00538         != SQLITE_OK) goto bind_error;
00539     if ((error = sqlite3_bind_int64(insert_path_stmt, FLAGS_COLUMN + 1,             path_info->flags))
00540         != SQLITE_OK) goto bind_error;
00541     if ((error = sqlite3_bind_int64(insert_path_stmt, VERSION_COLUMN + 1,           path_info->version))
00542         != SQLITE_OK) goto bind_error;
00543     if ((error = sqlite3_bind_int64(insert_path_stmt, REAP_TIME_COLUMN + 1,         path_info->reap_time))
00544         != SQLITE_OK) goto bind_error;
00545     if ((error = sqlite3_bind_int64(insert_path_stmt, REAP_POSITION_COLUMN + 1,     path_info->reap_position))
00546         != SQLITE_OK) goto bind_error;
00547     if ((error = sqlite3_bind_int64(insert_path_stmt, DEV_COLUMN + 1,               path_info->dev))
00548         != SQLITE_OK) goto bind_error;
00549     if ((error = sqlite3_bind_int64(insert_path_stmt, INODE_COLUMN + 1,             path_info->inode))
00550         != SQLITE_OK) goto bind_error;
00551     if ((error = sqlite3_bind_int64(insert_path_stmt, MODE_COLUMN + 1,              path_info->mode))
00552         != SQLITE_OK) goto bind_error;
00553     if ((error = sqlite3_bind_int64(insert_path_stmt, UID_COLUMN + 1,               path_info->uid))
00554         != SQLITE_OK) goto bind_error;
00555     if ((error = sqlite3_bind_int64(insert_path_stmt, GID_COLUMN + 1,               path_info->gid))
00556         != SQLITE_OK) goto bind_error;
00557     if ((error = sqlite3_bind_int64(insert_path_stmt, SIZE_COLUMN + 1,              path_info->size))
00558         != SQLITE_OK) goto bind_error;
00559     if ((error = sqlite3_bind_int64(insert_path_stmt, ACCESS_TIME_COLUMN + 1,       path_info->access_time))
00560         != SQLITE_OK) goto bind_error;
00561     if ((error = sqlite3_bind_int64(insert_path_stmt, MODIFICATION_TIME_COLUMN + 1, path_info->modification_time))
00562         != SQLITE_OK) goto bind_error;
00563     if ((error = sqlite3_bind_int64(insert_path_stmt, CHANGE_TIME_COLUMN + 1,       path_info->change_time))
00564         != SQLITE_OK) goto bind_error;
00565 
00566     if ((step_result = sqlite3_step(insert_path_stmt)) != SQLITE_DONE) {
00567         const char *err_msg = sqlite3_errmsg(database_handle);
00568         log_msg(LOG_ERROR, _("sqlite3_step \"%s\", unexpected result %s (%s)\n"),
00569                 sqlite3_sql(insert_path_stmt), sqlite3_result_string(step_result), err_msg);
00570         result =  WATCH_DATABASE_ERROR_CANNOT_INSERT;
00571         goto exit;
00572     }
00573 
00574  exit:
00575     return result;
00576 
00577  bind_error: {
00578         const char *err_msg = sqlite3_errmsg(database_handle);
00579         log_msg(LOG_ERROR, _("sqlite3_bind_text \"%s\", (%s)\n"),  sqlite3_sql(insert_path_stmt), err_msg);
00580         result = WATCH_DATABASE_ERROR_CANNOT_QUERY;
00581         return result;
00582     }
00583 }

static int destroy_statement ( sqlite3_stmt **  stmt_arg  )  [static]

Destroy a SQLite prepared statement.

Parameters:
[out] stmt_arg Pointer to new SQLite statement assigned here.
Returns:
SUCCESS (0) or non-zero error code otherwise
If successful the pointer to the SQLite prepared statement is assigned NULL, otherwise the pointer to the SQLite prepared statement is left unmodified and an error is returned.

Definition at line 236 of file watch_database.c.

Referenced by watch_database_fini().

00237 {
00238     int error;
00239     sqlite3_stmt *stmt;
00240 
00241     if ((stmt = *stmt_arg) == NULL) return SUCCESS;
00242 
00243     if ((error = sqlite3_finalize(stmt)) != SQLITE_OK) {
00244         const char *err_msg = sqlite3_errmsg(database_handle);
00245         log_msg(LOG_ERROR, _("sqlite3_finalize (%s)\n"), err_msg);
00246         return error;
00247     }
00248     *stmt_arg = NULL;
00249     return SUCCESS;
00250 }

int init_path_info ( struct lwatch_path_info_t path_info,
const char *  path 
)

Initialize a lwatch_path_info_t struct.

Parameters:
[in] path_info The lwatch_path_info_t to initialize
[in] path The path name bound to the lwatch_path_info_t
Returns:
SUCCESS (0) or non-zero error code otherwise
  • Zero the lwatch_path_info_t struct.
  • Copy the supplied path into the struct.
  • Set the flag indicating the version needs to be incremented.

Definition at line 596 of file watch_database.c.

Referenced by get_create_path_info(), and new_path_info().

00597 {
00598     int error;
00599 
00600     memset(path_info, 0, sizeof(struct lwatch_path_info_t));
00601 
00602     if (path) {
00603         if ((error = copy_path(path_info->path, path, sizeof(path_info->path))) != SUCCESS) {
00604             log_msg(LOG_ERROR, _("failed to copy path \"%s\" (%s)\n"), path, error_string(error));
00605             return error;
00606         }
00607     }
00608 
00609     path_info->flags = INC_VERSION_FLAG;
00610     return SUCCESS;
00611 }

static int init_statement ( struct sqlite3_stmt **  stmt_arg,
const char *  fmt,
  ... 
) [static]

Create a SQLite prepared statement from printf style arguments.

Parameters:
[out] stmt_arg Pointer to new SQLite statement assigned here.
[in] fmt Printf style format string
[in] ... Optional printf variable arguments
Returns:
SUCCESS (0) or non-zero error code otherwise
A string is produced via printf style format and variable arguments. The resulting string is passed to SQLite to produce a prepared statement. If successful the pointer to the newly created SQLite prepared statement is assigned to the variable pointed to by stmt_arg, otherwise an error is returned and stmt_arg is assigned NULL.

Definition at line 203 of file watch_database.c.

Referenced by watch_database_init().

00204 {
00205     va_list ap;
00206     int error;
00207     sqlite3_stmt *stmt;
00208     char *sql;
00209 
00210     va_start(ap, fmt);
00211     vasprintf(&sql, fmt, ap);
00212 
00213     if ((error = sqlite3_prepare_v2(database_handle, sql, -1, &stmt, NULL)) != SQLITE_OK) {
00214         const char *err_msg = sqlite3_errmsg(database_handle);
00215         log_msg(LOG_ERROR, _("could not prepare statement \"%s\", (%s)\n"), sql, err_msg);
00216         free(sql);
00217         *stmt_arg = NULL;
00218         return WATCH_DATABASE_ERROR_CANNOT_QUERY;
00219     }
00220 
00221     free(sql);
00222     *stmt_arg = stmt;
00223     return SUCCESS;
00224 }

int new_path_info ( const char *  path,
struct lwatch_path_info_t **  path_info_arg 
)

Allocate and initialize a new lwatch_path_info_t struct.

Parameters:
[in] path The path name which will be bound to the lwatch_path_info_t
[in] path_info_arg Pointer to variable to receive pointer to new path_info
Returns:
SUCCESS (0) or non-zero error code otherwise
See also:
init_path_info() for information about how the path_info is initialized.

Definition at line 622 of file watch_database.c.

00623 {
00624     int error;
00625     struct lwatch_path_info_t *path_info;
00626 
00627     if ((path_info = malloc(sizeof(struct lwatch_path_info_t))) == NULL) {
00628         return ENOMEM;
00629     }
00630 
00631     if ((error = init_path_info(path_info, path)) != SUCCESS) {
00632         log_msg(LOG_ERROR, _("could not initialize path_info for path \"%s\" (%s)\n"),
00633                 path, error_string(error));
00634         free(path_info);
00635         return error;
00636     }
00637 
00638     *path_info_arg = path_info;
00639     return SUCCESS;
00640 }

static int new_path_info_iter_context ( struct path_info_iter_context_t **  iter_arg  )  [static]

Allocate and initialize a new path_info iteration context.

Parameters:
[out] iter_arg Pointer to variable to receive new iteration context
Returns:
SUCCESS (0) or non-zero error code otherwise

Definition at line 494 of file watch_database.c.

Referenced by database_query_all_paths_iter(), database_query_backups_iter(), database_query_backups_of_target_iter(), database_query_pending_reaps_iter(), and database_query_targets_iter().

00495 {
00496     struct path_info_iter_context_t *iter;
00497 
00498     *iter_arg = NULL;
00499     if ((iter = malloc(sizeof(struct path_info_iter_context_t))) == NULL) {
00500         return ENOMEM;
00501     }
00502 
00503     iter->iter.next = (database_iter_next_t) path_info_iter_next;
00504     iter->iter.error = SUCCESS;
00505 
00506     iter->stmt = NULL;
00507     iter->step_result = SQLITE_OK;
00508 
00509     *iter_arg = iter;
00510     return SUCCESS;
00511 }

char* path_info_flags_string ( unsigned long  flag,
const char *  separator 
)

Render the lwatch_path_info_t flag bitset as a string.

Parameters:
[in] flag The bitset whose boolean flags will be converted to strings
[in] separator The string used to separate adjacent flags
Returns:
Pointer to thread local static string
For each boolean flag in the bitset which is enabled output it's name as a string. Join adjacent flag names with the separator parameter.

Definition at line 652 of file watch_database.c.

Referenced by path_info_string().

00653 {
00654     static __thread char buf[1024]; /* thread local static buffer */
00655     char *p, *buf_end;
00656     int separator_len;
00657     unsigned int unknown;
00658 
00659     p = buf;                     /* current position in buffer */
00660     buf_end = &buf[sizeof(buf)]; /* non-inclusive end of buffer */
00661     separator_len = strlen(separator);
00662     *p = 0;
00663 
00664     /* validate there is nothing in the event mask we don't know about */
00665     unknown = flag & ~(TARGET_FLAG | BACKUP_FLAG | NEEDS_REAPING_FLAG |
00666                        STAT_DATA_VALID_FLAG | INC_VERSION_FLAG);
00667 
00668     if (unknown) p += snprintf(p, buf_end - p, "unknown bits=0x%x%s", unknown, separator);
00669     if (p >= buf_end) goto fail;
00670 
00671     if (flag & TARGET_FLAG)          p += snprintf(p, buf_end - p, "TARGET%s",          separator);
00672     if (p >= buf_end) goto fail;
00673     if (flag & BACKUP_FLAG)          p += snprintf(p, buf_end - p, "BACKUP%s",          separator);
00674     if (p >= buf_end) goto fail;
00675     if (flag & NEEDS_REAPING_FLAG)   p += snprintf(p, buf_end - p, "NEEDS_REAPING%s",   separator);
00676     if (p >= buf_end) goto fail;
00677     if (flag & STAT_DATA_VALID_FLAG) p += snprintf(p, buf_end - p, "STAT_DATA_VALID%s", separator);
00678     if (p >= buf_end) goto fail;
00679     if (flag & INC_VERSION_FLAG)     p += snprintf(p, buf_end - p, "INC_VERSION%s",     separator);
00680     if (p >= buf_end) goto fail;
00681 
00682     if (p > buf) p[-separator_len] = 0; /* nuke trailing separator */
00683 
00684     return buf;
00685 
00686  fail:
00687     /* exhausted the buffer; NULL terminate then return truncated string */
00688     buf_end[-1] = 0;   /* should already be NULL terminated, but be safe */
00689     return buf;
00690 }

static struct lwatch_path_info_t * path_info_iter_next ( struct path_info_iter_context_t iter  )  [static, read]

Used to iterate through SQLite query result of lwatch_path_info_t structs.

Parameters:
[in] iter The iteration context, contains the SQLite statement, state, etc.
Returns:
Pointer to next lwatch_path_info_t, or NULL when iteration terminates
Implements the next() method of a SQLite iteration context. The iteration context holds all the state needed to iterate over the query result, most significant is the SQLite statement containing the query result. The function advances to the next SQLite query result in the statement and populates a lwatch_path_info_t struct contained in the iteration context (path_info) from the current row in the statement, a pointer to the populated lwatch_path_info_t is returned to the caller.

See also:
path_info_iter_context_t

Definition at line 469 of file watch_database.c.

Referenced by new_path_info_iter_context().

00470 {
00471     iter->iter.error = SUCCESS;
00472 
00473     iter->step_result = sqlite3_step(iter->stmt);
00474     if (iter->step_result == SQLITE_DONE) {
00475         return NULL;
00476     } else if (iter->step_result == SQLITE_ROW) {
00477         populate_path_info(&iter->path_info, iter->stmt); /* FIXME, check error return */
00478         return &iter->path_info;
00479     } else {
00480         const char *err_msg = sqlite3_errmsg(database_handle);
00481         log_msg(LOG_ERROR, _("sqlite3_step \"%s\", unexpected result %s (%s)\n"),
00482                 sqlite3_sql(iter->stmt), sqlite3_result_string(iter->step_result), err_msg);
00483             iter->iter.error = WATCH_DATABASE_ERROR_CANNOT_QUERY;
00484             return NULL;
00485     }
00486 }

char* path_info_string ( struct lwatch_path_info_t path_info,
const char *  prefix 
)

Render a lwatch_path_info_t struct as a string.

Parameters:
[in] path_info The lwatch_path_info_t struct to convert to a string
[in] prefix String prepended to each line in the output
Returns:
Pointer to thread local static string
The output is muli-line due to the complexity of the struct. Each line in the result will have the prefix parameter prepended to the line.

Definition at line 702 of file watch_database.c.

Referenced by dump_database().

00703 {
00704     static __thread char buf[1024]; /* thread local static buffer */
00705     const char *indent = "    ";
00706     char prefix_indent[128];
00707     char *p, *buf_end;
00708     char *uid_name, *gid_name;
00709 
00710     strncpy(prefix_indent, prefix, sizeof(prefix_indent));
00711     prefix_indent[sizeof(prefix_indent) - 1] = 0;
00712     strncat(prefix_indent, indent, sizeof(prefix_indent) - 1);
00713 
00714     get_uid_name(path_info->uid, &uid_name);
00715     get_gid_name(path_info->gid, &gid_name);
00716 
00717 
00718     p = buf;                     /* current position in buffer */
00719     buf_end = &buf[sizeof(buf)]; /* non-inclusive end of buffer */
00720     *p = 0;
00721 
00722     p += snprintf(p, buf_end - p, "%spath: %s\n",
00723                   prefix, path_info->path);
00724     if (p >= buf_end) goto fail;
00725 
00726     if (path_info->original_path[0]) {
00727         p += snprintf(p, buf_end - p, "%soriginal path:     %s\n",
00728                       prefix_indent,
00729                       path_info->original_path);
00730         if (p >= buf_end) goto fail;
00731     }
00732 
00733     p += snprintf(p, buf_end - p, "%sflags:             [%s]\n",
00734                   prefix_indent,
00735                   path_info_flags_string(path_info->flags, ","));
00736     if (p >= buf_end) goto fail;
00737 
00738     p += snprintf(p, buf_end - p, "%sversion:           %lu\n",
00739                   prefix_indent,
00740                   path_info->version);
00741     if (p >= buf_end) goto fail;
00742 
00743     p += snprintf(p, buf_end - p, "%sreap_time:         %s (%ld)\n",
00744                   prefix_indent,
00745                   time_string(path_info->reap_time, true, NULL),
00746                   path_info->reap_time);
00747     if (p >= buf_end) goto fail;
00748 
00749     p += snprintf(p, buf_end - p, "%sreap_position:     %ld\n",
00750                   prefix_indent,
00751                   path_info->reap_position);
00752     if (p >= buf_end) goto fail;
00753 
00754     if (path_info->flags & STAT_DATA_VALID_FLAG) {
00755         p += snprintf(p, buf_end - p, "%sdev:               %llu\n",
00756                       prefix_indent,
00757                       path_info->dev);
00758         if (p >= buf_end) goto fail;
00759 
00760         p += snprintf(p, buf_end - p, "%sinode:             %lu\n",
00761                       prefix_indent,
00762                       path_info->inode);
00763         if (p >= buf_end) goto fail;
00764 
00765         p += snprintf(p, buf_end - p, "%smode:              %s (%#o)\n",
00766                       prefix_indent,
00767                       file_mode_string(path_info->mode),
00768                       path_info->mode);
00769         if (p >= buf_end) goto fail;
00770 
00771         p += snprintf(p, buf_end - p, "%suid:gid:           %s:%s (%u:%u)\n",
00772                       prefix_indent,
00773                       uid_name, gid_name,
00774                       path_info->uid, path_info->gid);
00775         if (p >= buf_end) goto fail;
00776 
00777         p += snprintf(p, buf_end - p, "%ssize:              %ld\n",
00778                       prefix_indent,
00779                       path_info->size);
00780         if (p >= buf_end) goto fail;
00781 
00782         p += snprintf(p, buf_end - p, "%saccess_time:       %s (%ld)\n",
00783                       prefix_indent,
00784                       time_string(path_info->access_time, true, NULL),
00785                       path_info->access_time);
00786         if (p >= buf_end) goto fail;
00787 
00788         p += snprintf(p, buf_end - p, "%smodification time: %s (%ld)\n",
00789                       prefix_indent,
00790                       time_string(path_info->modification_time, true, NULL),
00791                       path_info->modification_time);
00792         if (p >= buf_end) goto fail;
00793 
00794         p += snprintf(p, buf_end - p, "%schange_time:       %s (%ld)\n",
00795                       prefix_indent,
00796                       time_string(path_info->change_time, true, NULL),
00797                       path_info->change_time);
00798         if (p >= buf_end) goto fail;
00799     }
00800 
00801 
00802     free(uid_name);
00803     free(gid_name);
00804     return buf;
00805 
00806  fail:
00807     /* exhausted the buffer; NULL terminate then return truncated string */
00808     buf_end[-1] = 0;   /* should already be NULL terminated, but be safe */
00809     free(uid_name);
00810     free(gid_name);
00811     return buf;
00812 }

int populate_path_info ( struct lwatch_path_info_t path_info,
sqlite3_stmt *  stmt 
) [static]

Copy the data from a SQLite query result into a lwatch_path_info_t struct.

Parameters:
[in] path_info The lwatch_path_info_t struct to initialize
[in] stmt The SQLite statement containing the query result
Returns:
SUCCESS (0) or non-zero error code otherwise

Definition at line 421 of file watch_database.c.

Referenced by database_lookup_path_info(), and path_info_iter_next().

00422 {
00423     int error;
00424 
00425     if ((error = copy_path(path_info->path, (const char *)sqlite3_column_text(stmt, PATH_COLUMN),
00426                            sizeof(path_info->path))) != SUCCESS) {
00427         log_msg(LOG_ERROR, _("failed to copy path \"%s\" (%s)\n"), (const char *)sqlite3_column_text(stmt, 0), error_string(error));
00428         return error;
00429     }
00430     if ((error = copy_path(path_info->original_path, (const char *)sqlite3_column_text(stmt, ORIGINAL_PATH_COLUMN),
00431                            sizeof(path_info->original_path))) != SUCCESS) {
00432         log_msg(LOG_ERROR, _("failed to copy path \"%s\" (%s)\n"), (const char *)sqlite3_column_text(stmt, 1), error_string(error));
00433         return error;
00434     }
00435 
00436     path_info->flags             = sqlite3_column_int64(stmt, FLAGS_COLUMN);
00437     path_info->version           = sqlite3_column_int64(stmt, VERSION_COLUMN);
00438     path_info->reap_time         = sqlite3_column_int64(stmt, REAP_TIME_COLUMN);
00439     path_info->reap_position     = sqlite3_column_int64(stmt, REAP_POSITION_COLUMN);
00440     path_info->dev               = sqlite3_column_int64(stmt, DEV_COLUMN);
00441     path_info->inode             = sqlite3_column_int64(stmt, INODE_COLUMN);
00442     path_info->mode              = sqlite3_column_int64(stmt, MODE_COLUMN);
00443     path_info->uid               = sqlite3_column_int64(stmt, UID_COLUMN);
00444     path_info->gid               = sqlite3_column_int64(stmt, GID_COLUMN);
00445     path_info->size              = sqlite3_column_int64(stmt, SIZE_COLUMN);
00446     path_info->access_time       = sqlite3_column_int64(stmt, ACCESS_TIME_COLUMN);
00447     path_info->modification_time = sqlite3_column_int64(stmt, MODIFICATION_TIME_COLUMN);
00448     path_info->change_time       = sqlite3_column_int64(stmt, CHANGE_TIME_COLUMN);
00449 
00450     return SUCCESS;
00451 }

static int reset_statement ( sqlite3_stmt *  stmt  )  [static]

Resets a prepared statement readying it for parameter binding and execution.

Parameters:
[in] stmt The prepared statement to reset
Returns:
SUCCESS (0) or non-zero error code otherwise

Definition at line 258 of file watch_database.c.

Referenced by database_lookup_path_info(), database_query_all_paths_iter(), database_query_backups_iter(), database_query_backups_of_target_iter(), database_query_pending_reaps_iter(), database_query_targets_iter(), database_write_path_info(), and table_exists().

00259 {
00260     int error;
00261 
00262     if ((error = sqlite3_reset(stmt)) != SQLITE_OK) {
00263         const char *err_msg = sqlite3_errmsg(database_handle);
00264         log_msg(LOG_ERROR, _("sqlite3_reset \"%s\", (%s)\n"), sqlite3_sql(stmt), err_msg);
00265         return WATCH_DATABASE_ERROR_CANNOT_QUERY;
00266     }
00267     return SUCCESS;
00268 }

static const char * sqlite3_result_string ( int  result  )  [static]

Translate a SQLite result code to a string.

Parameters:
[in] result The result code to translate to a string
Returns:
Pointer to thread local static string.

Definition at line 276 of file watch_database.c.

Referenced by database_lookup_path_info(), database_write_path_info(), path_info_iter_next(), and table_exists().

00277 {
00278     static __thread char buf[64]; /* thread local static buffer */
00279 
00280     switch(result) {
00281     case SQLITE_OK:               return "SQLITE_OK";
00282     case SQLITE_ERROR:            return "SQLITE_ERROR";
00283     case SQLITE_INTERNAL:         return "SQLITE_INTERNAL";
00284     case SQLITE_PERM:             return "SQLITE_PERM";
00285     case SQLITE_ABORT:            return "SQLITE_ABORT";
00286     case SQLITE_BUSY:             return "SQLITE_BUSY";
00287     case SQLITE_LOCKED:           return "SQLITE_LOCKED";
00288     case SQLITE_NOMEM:            return "SQLITE_NOMEM";
00289     case SQLITE_READONLY:         return "SQLITE_READONLY";
00290     case SQLITE_INTERRUPT:        return "SQLITE_INTERRUPT";
00291     case SQLITE_IOERR:            return "SQLITE_IOERR";
00292     case SQLITE_CORRUPT:          return "SQLITE_CORRUPT";
00293     case SQLITE_NOTFOUND:         return "SQLITE_NOTFOUND";
00294     case SQLITE_FULL:             return "SQLITE_FULL";
00295     case SQLITE_CANTOPEN:         return "SQLITE_CANTOPEN";
00296     case SQLITE_PROTOCOL:         return "SQLITE_PROTOCOL";
00297     case SQLITE_EMPTY:            return "SQLITE_EMPTY";
00298     case SQLITE_SCHEMA:           return "SQLITE_SCHEMA";
00299     case SQLITE_TOOBIG:           return "SQLITE_TOOBIG";
00300     case SQLITE_CONSTRAINT:       return "SQLITE_CONSTRAINT";
00301     case SQLITE_MISMATCH:         return "SQLITE_MISMATCH";
00302     case SQLITE_MISUSE:           return "SQLITE_MISUSE";
00303     case SQLITE_NOLFS:            return "SQLITE_NOLFS";
00304     case SQLITE_AUTH:             return "SQLITE_AUTH";
00305     case SQLITE_FORMAT:           return "SQLITE_FORMAT";
00306     case SQLITE_RANGE:            return "SQLITE_RANGE";
00307     case SQLITE_NOTADB:           return "SQLITE_NOTADB";
00308     case SQLITE_ROW:              return "SQLITE_ROW";
00309     case SQLITE_DONE:             return "SQLITE_DONE";
00310 
00311     case SQLITE_IOERR_READ:       return "SQLITE_IOERR_READ";
00312     case SQLITE_IOERR_SHORT_READ: return "SQLITE_IOERR_SHORT_READ";
00313     case SQLITE_IOERR_WRITE:      return "SQLITE_IOERR_WRITE";
00314     case SQLITE_IOERR_FSYNC:      return "SQLITE_IOERR_FSYNC";
00315     case SQLITE_IOERR_DIR_FSYNC:  return "SQLITE_IOERR_DIR_FSYNC";
00316     case SQLITE_IOERR_TRUNCATE:   return "SQLITE_IOERR_TRUNCATE";
00317     case SQLITE_IOERR_FSTAT:      return "SQLITE_IOERR_FSTAT";
00318     case SQLITE_IOERR_UNLOCK:     return "SQLITE_IOERR_UNLOCK";
00319     case SQLITE_IOERR_RDLOCK:     return "SQLITE_IOERR_RDLOCK";
00320     case SQLITE_IOERR_DELETE:     return "SQLITE_IOERR_DELETE";
00321     case SQLITE_IOERR_BLOCKED:    return "SQLITE_IOERR_BLOCKED";
00322     case SQLITE_IOERR_NOMEM:      return "SQLITE_IOERR_NOMEM";
00323     default:
00324         snprintf(buf, sizeof(buf), "unknown(%d)", result);
00325         return buf;
00326     }
00327 }

static int table_exists ( const char *  table_name,
bool *  exists 
) [static]

Set variable to true if specified table exists in SQLite database.

Parameters:
[in] table_name The table whose existence is to be checked.
[out] exists This variable receives the boolean result
Returns:
SUCCESS (0) or non-zero error code otherwise

Definition at line 336 of file watch_database.c.

Referenced by watch_database_init().

00337 {
00338     int error, result, step_result, row_count;
00339     const char *name;
00340 
00341     result = SUCCESS;
00342     *exists = false;
00343 
00344     if ((error = reset_statement(table_exists_stmt)) != SUCCESS) {
00345         result = WATCH_DATABASE_ERROR_CANNOT_QUERY;
00346         goto exit;
00347     }
00348 
00349     if ((error = sqlite3_bind_text(table_exists_stmt, 1, table_name, -1, SQLITE_TRANSIENT)) != SQLITE_OK) {
00350         const char *err_msg = sqlite3_errmsg(database_handle);
00351         log_msg(LOG_ERROR, _("sqlite3_bind_text \"%s\", (%s)\n"),  sqlite3_sql(table_exists_stmt), err_msg);
00352         result = WATCH_DATABASE_ERROR_CANNOT_QUERY;
00353         goto exit;
00354     }
00355 
00356     row_count = 0;
00357     while(true) {
00358         step_result = sqlite3_step(table_exists_stmt);
00359         if (step_result == SQLITE_DONE) {
00360             break;
00361         } else if (step_result == SQLITE_ROW) {
00362             row_count++;
00363             name = (const char *)sqlite3_column_text(table_exists_stmt, 0);
00364             *exists = strcmp(name, table_name) == 0 ? true : false;
00365         } else {
00366             const char *err_msg = sqlite3_errmsg(database_handle);
00367             log_msg(LOG_ERROR, _("sqlite3_step \"%s\", unexpected result %s (%s)\n"),
00368                     sqlite3_sql(table_exists_stmt), sqlite3_result_string(step_result), err_msg);
00369             result = WATCH_DATABASE_ERROR_CANNOT_QUERY;
00370         }
00371     }
00372 
00373     if (row_count > 1) {
00374         log_msg(LOG_ERROR, _("\"%s\", unexpected multiple rows (%d) returned\n"),
00375                 sqlite3_sql(table_exists_stmt), row_count);
00376         result = WATCH_DATABASE_ERROR_FOUND_MULTIPLE;
00377     }
00378 
00379  exit:
00380     return result;
00381 }

const char* watch_database_error_string ( int  error  ) 

Render a database error code as a string.

Parameters:
[in] error The database error code to convert to a string
Returns:
Pointer to thread local static string containing error description

Definition at line 820 of file watch_database.c.

Referenced by error_string().

00821 {
00822     static __thread char buf[80]; /* thread local static buffer */
00823 
00824     switch(error) {
00825     case SUCCESS:                                  return _("success");
00826     case WATCH_DATABASE_ERROR_CANNOT_OPEN:         return _("could not open database");
00827     case WATCH_DATABASE_ERROR_CANNOT_CLOSE:        return _("could not close database");
00828     case WATCH_DATABASE_ERROR_CANNOT_QUERY:        return _("database query failed");
00829     case WATCH_DATABASE_ERROR_CANNOT_CREATE_TABLE: return _("cannot create table");
00830     case WATCH_DATABASE_ERROR_CANNOT_INSERT:       return _("cannot insert record into table");
00831     case WATCH_DATABASE_ERROR_NOT_FOUND:           return _("entry not found");
00832     case WATCH_DATABASE_ERROR_FOUND_MULTIPLE:      return _("found multiple entries, expecting single entry");
00833     default:
00834         snprintf(buf, sizeof(buf), _("unknown(%d)"), error);
00835         return buf;
00836     }
00837 }

int watch_database_fini ( void   ) 

Close the watch database subsystem, release all resources, close database.

Returns:
SUCCESS (0) or non-zero error code otherwise

Definition at line 935 of file watch_database.c.

Referenced by main().

00936 {
00937     int error;
00938 
00939     destroy_statement(&table_exists_stmt);
00940     destroy_statement(&lookup_path_stmt);
00941     destroy_statement(&insert_path_stmt);
00942     destroy_statement(&query_all_stmt);
00943     destroy_statement(&query_backups_stmt);
00944     destroy_statement(&query_backups_of_target_stmt);
00945     destroy_statement(&query_pending_reaps_stmt);
00946     destroy_statement(&query_targets_stmt);
00947 
00948     if ((error = sqlite3_close(database_handle)) != SQLITE_OK) {
00949         const char *err_msg = sqlite3_errmsg(database_handle);
00950         log_msg(LOG_ERROR, _("could not close database file \"%s\", (%s)\n"),  watch_database_pathname, err_msg);
00951         database_handle = NULL;
00952         return WATCH_DATABASE_ERROR_CANNOT_CLOSE;
00953     }
00954     database_handle = NULL;
00955     return SUCCESS;
00956 }

int watch_database_init ( void   ) 

Initialize the watch database subsystem.

Returns:
SUCCESS (0) or non-zero error code otherwise
Initialization consists of:
  • Initializing the SQLite subsystem, opening the database
  • Validating our tables exist, if not create each table
  • Create & initialize all our prepared SQL statements (prepared statements are more efficient)

Definition at line 850 of file watch_database.c.

Referenced by main().

00851 {
00852     int error;
00853     bool exists;
00854 
00855     if ((error = sqlite3_open(watch_database_pathname, &database_handle)) != SQLITE_OK) {
00856         const char *err_msg = sqlite3_errmsg(database_handle);
00857         log_msg(LOG_ERROR, _("could not open database file \"%s\", (%s)\n"),watch_database_pathname, err_msg);
00858         sqlite3_close(database_handle);
00859         database_handle = NULL;
00860         return WATCH_DATABASE_ERROR_CANNOT_OPEN;
00861     }
00862 
00863     /* Create prepared SQL statements for master table */
00864     if ((error = init_statement(&table_exists_stmt,
00865                                 "SELECT name FROM sqlite_master WHERE type='table' AND name=?1;")) != SUCCESS) {
00866         return error;
00867     }
00868 
00869     /* Assure our table exists, if not create it */
00870     if ((error = table_exists(LWATCH_TABLE_NAME, &exists)) != SUCCESS) {
00871         log_msg(LOG_ERROR, _("table_exists failed \"%s\" (%s)\n"),  LWATCH_TABLE_NAME, error_string(error));
00872         return WATCH_DATABASE_ERROR_CANNOT_QUERY;
00873     }
00874 
00875     if (!exists) {
00876         if ((error = create_table(LWATCH_TABLE_NAME, lwatch_table_schema)) != SUCCESS) {
00877             log_msg(LOG_ERROR, _("\"%s\" table does not exist, but failed to create (%s)\n"),
00878                     LWATCH_TABLE_NAME, error_string(error));
00879             return error;
00880         }
00881     }
00882 
00883     /* Create prepared SQL statements for our table */
00884     if ((error = init_statement(&lookup_path_stmt,
00885                                 "SELECT %s FROM \"%s\" WHERE path=?1;",
00886                                 COLUMNS_STRING, LWATCH_TABLE_NAME)) != SUCCESS) {
00887         return WATCH_DATABASE_ERROR_CANNOT_QUERY;
00888     }
00889 
00890     if ((error = init_statement(&insert_path_stmt,
00891                                 "INSERT OR REPLACE INTO \"%s\" (%s) VALUES "
00892                                 "(?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9, ?10, ?11, ?12, ?13, ?14, ?15);",
00893                                 LWATCH_TABLE_NAME, COLUMNS_STRING)) != SUCCESS) {
00894         return WATCH_DATABASE_ERROR_CANNOT_QUERY;
00895     }
00896 
00897     if ((error = init_statement(&query_all_stmt,
00898                                 "SELECT %s FROM \"%s\" where path like ?1;",
00899                                 COLUMNS_STRING, LWATCH_TABLE_NAME)) != SUCCESS) {
00900         return WATCH_DATABASE_ERROR_CANNOT_QUERY;
00901     }
00902 
00903     if ((error = init_statement(&query_backups_stmt,
00904                                 "SELECT %s FROM \"%s\" where flags & %d;",
00905                                 COLUMNS_STRING, LWATCH_TABLE_NAME, BACKUP_FLAG)) != SUCCESS) {
00906         return WATCH_DATABASE_ERROR_CANNOT_QUERY;
00907     }
00908 
00909     if ((error = init_statement(&query_backups_of_target_stmt,
00910                                 "SELECT %s FROM \"%s\" where flags & %d AND original_path == ?1;",
00911                                 COLUMNS_STRING, LWATCH_TABLE_NAME, BACKUP_FLAG)) != SUCCESS) {
00912         return WATCH_DATABASE_ERROR_CANNOT_QUERY;
00913     }
00914 
00915     if ((error = init_statement(&query_pending_reaps_stmt,
00916                                 "SELECT %s FROM \"%s\" where flags & %d;",
00917                                 COLUMNS_STRING, LWATCH_TABLE_NAME, NEEDS_REAPING_FLAG)) != SUCCESS) {
00918         return WATCH_DATABASE_ERROR_CANNOT_QUERY;
00919     }
00920 
00921     if ((error = init_statement(&query_targets_stmt,
00922                                 "SELECT %s FROM \"%s\" where flags & %d;",
00923                                 COLUMNS_STRING, LWATCH_TABLE_NAME, TARGET_FLAG)) != SUCCESS) {
00924         return WATCH_DATABASE_ERROR_CANNOT_QUERY;
00925     }
00926 
00927     return SUCCESS;
00928 }


Variable Documentation

const char* lwatch_table_schema [static]

Initial value:

"path TEXT PRIMARY KEY,\n\
original_path TEXT,\n\
flags INTEGER,\n\
version INTEGER,\n\
reap_time INTEGER,\n\
reap_position INTEGER,\n\
dev INTEGER,\n\
inode INTEGER,\n\
mode INTEGER,\n\
uid INTEGER,\n\
gid INTEGER,\n\
size INTEGER,\n\
access_time INTEGER,\n\
modification_time INTEGER,\n\
change_time INTEGER\n\
"
SQLSchema used to store lwatch_path_info_t persistently.

Definition at line 113 of file watch_database.c.

Referenced by watch_database_init().

sqlite3_stmt* query_pending_reaps_stmt = NULL

lookup multiple lwatch_path_info_t which have the NEEDS_REAPING_FLAG set, i.e.

all pending reaps

Definition at line 174 of file watch_database.c.

Referenced by database_query_pending_reaps_iter(), watch_database_fini(), and watch_database_init().

sqlite3_stmt* query_targets_stmt = NULL

lookup multiple lwatch_path_info_t which have the TARGET_FLAG set, i.e.

all primary targets

Definition at line 178 of file watch_database.c.

Referenced by database_query_targets_iter(), watch_database_fini(), and watch_database_init().


Generated on Mon Aug 31 10:06:21 2009 by  doxygen 1.5.8