/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
#if !defined(NET_FOSSIL_SCM_FSL_INTERNAL_H_INCLUDED)
#define NET_FOSSIL_SCM_FSL_INTERNAL_H_INCLUDED
/*
** Copyright (c) 2013 D. Richard Hipp
**
** This program is free software; you can redistribute it and/or
** modify it under the terms of the Simplified BSD License (also
** known as the "2-Clause License" or "FreeBSD License".)
**
** This program is distributed in the hope that it will be l,
** but without any warranty; without even the implied warranty of
** merchantability or fitness for a particular purpose.
**
** Author contact information:
** drh@hwaci.com
** http://www.hwaci.com/drh/
**
*******************************************************************************
** This file declares library-level internal APIs which are shared
** across the library.
*/
#include "fossil-scm/fossil.h" /* MUST come first b/c of config macros */
#if defined(__cplusplus)
extern "C" {
#endif
typedef struct fsl_acache fsl_acache;
typedef struct fsl_acache_line fsl_acache_line;
typedef struct fsl_id_bag fsl_id_bag;
typedef struct fsl_pq fsl_pq;
typedef struct fsl_pq_e fsl_pq_e;
/** @internal
**
** Queue entry type for the fsl_pq class.
*/
struct fsl_pq_e {
/** RID of the entry. */
fsl_id_t id;
/** Raw data associated with this entry. */
void * p;
/** Priority of this element. */
fsl_double_t value;
};
/** @internal
** Empty-initialized fsl_pq_e structure.
*/
#define fsl_pq_e_empty_m {0,NULL,0.0}
/** @internal
**
** A simple priority queue class. Instances _must_ be initialized
** by copying fsl_pq_empty or fsl_pq_empty_m (depending on where
** the instance lives).
*/
struct fsl_pq {
/** Number of items allocated in this->list. */
fsl_size_t capacity;
/** Number of items used in this->list. */
fsl_size_t used;
/** The queue. It is kept sorted by entry->value. */
fsl_pq_e * list;
};
/** @internal
** Empty-initialized fsl_pq struct.
*/
#define fsl_pq_empty_m {0,0,NULL}
/** @internal
** Empty-initialized fsl_pq struct.
*/
extern const fsl_pq fsl_pq_empty;
/** @internal
**
** Clears the contents of p, freeing any memory it owns, but not
** freeing p. Results are undefined if !p.
*/
void fsl_pq_clear(fsl_pq * p);
/** @internal
** Insert element e into the queue. Returns 0 on success,
** FSL_RC_OOM on error. Results are undefined if !p or e
** is invalid. pData may be NULL.
*/
int fsl_pq_insert(fsl_pq *p, fsl_id_t e,
fsl_double_t v, void *pData);
/** @internal
**
** Extracts (removes) the first element from the queue (the element
** with the smallest value) and return its ID. Return 0 if the
** queue is empty. If pp is not NULL then *pp is (on success)
** assigned to the value member of the extracted element.
*/
fsl_id_t fsl_pq_extract(fsl_pq *p, void **pp);
/** @internal
**
** A container type for lists of db record IDs. This is used in
** several places as a cache for record IDs, to keep track of ones
** we know about, ones we know that we don't know about, and to
** avoid duplicate processing in some contexts.
*/
struct fsl_id_bag {
/**
** Number of entries of this->list which are in use (have
** a positive value). They need not be contiguous!
*/
fsl_size_t entryCount;
/**
** The number of elements allocated for this->list.
*/
fsl_size_t capacity;
/**
** The number of elements in this->list which are
** "in used". Must be <= capacity.
*/
fsl_size_t used;
/**
** Array of IDs this->capacity elements long. "Used" elements
** have a positive value. Unused ones are set to 0.
*/
fsl_id_t * list;
};
/** @internal
** Initialized-with-defaults fsl_id_bag structure,
** intended for copy initialization.
*/
extern const fsl_id_bag fsl_id_bag_empty;
/** @internal
** Initialized-with-defaults fsl_id_bag structure,
** intended for in-struct initialization.
*/
#define fsl_id_bag_empty_m {\
0/*entryCount*/, 0/*capacity*/, \
0/*used*/, NULL/*list*/ }
/** @internal
**
** Holds one "line" of a fsl_acache cache.
*/
struct fsl_acache_line {
/**
** RID of the cached record.
*/
fsl_id_t rid;
/**
** Age. Newer is larger.
*/
fsl_int_t age;
/**
** Content of the artifact.
*/
fsl_buffer content;
};
/** @internal
**
** Empty-initialized fsl_acache_line structure.
*/
#define fsl_acache_line_empty_m { 0,0,fsl_buffer_empty_m }
/** @internal
**
** A cache for tracking the existence of artifacts while the
** internal goings-on of control artifacts are going on.
*/
struct fsl_acache {
/**
** Total amount of memory used by cached content.
*/
fsl_int_t szTotal;
/**
** Number of entries "used" in this->list.
*/
fsl_size_t used;
/**
** Number of slots in this->list.
*/
fsl_size_t capacity;
/**
** Next cache counter age. Higher is newer.
*/
fsl_int_t nextAge;
/**
** List of cached content, ordered by age.
*/
fsl_acache_line * list;
/**
** All artifacts currently in the cache.
*/
fsl_id_bag inCache;
/**
** Cache of known-missing content.
*/
fsl_id_bag missing;
/**
** Cache of of known-existing content.
*/
fsl_id_bag available;
};
/** @internal
**
** Empty-initialized fsl_acache structure.
*/
#define fsl_acache_empty_m {\
0/*szTotal*/,0/*used*/,0/*capacity*/,\
0/*nextAge*/,NULL/*list*/,\
fsl_id_bag_empty_m/*inCache*/,\
fsl_id_bag_empty_m/*missing*/,\
fsl_id_bag_empty_m/*available*/\
}
/** @internal
**
** Empty-initialized fsl_acache structure.
*/
extern const fsl_acache fsl_acache_empty;
/** @internal
**
** A type for holding a callback/state pair for manifest
** crosslinking callbacks.
*/
struct fsl_xlinker {
char const * name;
/** Callback function. */
fsl_deck_xlink_f f;
/** State for this->f's last argument. */
void * state;
};
typedef struct fsl_xlinker fsl_xlinker;
/** Empty-initializes fsl_xlinker struct. */
#define fsl_xlinker_empty_m {NULL,NULL,NULL}
/** Empty-initializes fsl_xlinker struct. */
extern const fsl_xlinker fsl_xlinker_empty;
/** @internal
**
** An array of fsl_xlinker instances.
*/
struct fsl_xlinker_list {
/** Number of used items in this->list. */
fsl_size_t used;
/** Number of slots allocated in this->list. */
fsl_size_t capacity;
/** Array of this->used elements. */
fsl_xlinker * list;
};
typedef struct fsl_xlinker_list fsl_xlinker_list;
/** Empty-initializes fsl_xlinker_list struct. */
#define fsl_xlinker_list_empty_m {0,0,NULL}
/** Empty-initializes fsl_xlinker_list struct. */
extern const fsl_xlinker_list fsl_xlinker_list_empty;
/** @internal
**
** Searches f's crosslink callbacks for an entry with the given
** name and returns that entry, or NULL if no match is found. The
** returned object is owned by f.
*/
fsl_xlinker * fsl_xlinker_by_name( fsl_cx * f, char const * name );
/* The fsl_cx class is documented in main public header. */
struct fsl_cx {
/**
** The main db handle. It is a pointer to the first one of
** repo.db, ckout.db, config.db which is opened. Internal code
** should rely as little as possible on the actual arrangement of
** internal DB handles, and should use fsl_cx_db_repo(),
** fsl_cx_db_checkout(), and fsl_cx_db_config() to get a handle
** to the specific db they want. Currently they will always
** return NULL or the same handle, but that design decision might
** change at some point, so the public API treats them as
** separate entities.
*/
fsl_db * dbMain;
/**
** Marker which tells us whether fsl_cx_finalize() needs
** to fsl_free() this instance or not.
*/
void const * allocStamp;
/**
** Handle to the currently opened config database.
*/
/**
** Holds info directly related to a checkout database.
*/
struct {
/**
** Handle to the currently opened checkout database IF the checkout
** is the main db.
*/
fsl_db db;
/**
** Possibly not needed, but useful for doing absolute-to-relative
** path conversions for checking file lists.
**
** The directory part of an opened checkout db. This is currently
** only set by fsl_checkout_open_dir().
*/
char * dir;
fsl_id_t rid;
fsl_uuid_str uuid;
} ckout;
/**
** Holds info directly related to a repo database.
*/
struct {
/**
** Handle to the currently opened repository database IF repo
** is the main db.
*/
fsl_db db;
/**
** The default user name, for operations which need one.
** See fsl_cx_user_set().
*/
char * user;
} repo;
/**
** Holds info directly related to a global config database.
*/
struct {
/**
** Handle to the currently opened global config database IF config
** is the main db.
*/
fsl_db db;
} config;
/**
** Output channel used by fsl_output() and friends.
*/
fsl_outputer output;
/**
** Can be used to tie client-specific data to the context. Its
** finalizer is called when fsl_cx_finalize() cleans up.
*/
fsl_state clientState;
/**
** Holds error state. As a general rule, this information is
** updated only by routines which need to return more info than a
** simple integer error code. This is primarily db-related
** routines, where we add the db-driver-provided error state
** here. It is not used by "simple" routines for which an integer
** code always suffices. APIs which set this should denote it
** with a comment like "updates the context's error state on
** error."
*/
fsl_error error;
/**
** Optimization: reusable scratchpad for
** creating/encoding/decoding strings.
*/
fsl_buffer scratch;
/**
** A scratchpad specifically for dealing with filename-related,
** non-recursive caching.
*/
fsl_buffer fsScratch;
/**
** A copy of the config object passed to fsl_cx_init() (or some
** default).
*/
fsl_cx_config cxConfig;
/**
** Flags, some (or one) of which is runtime-configurable by the
** client (see fsl_cx_flag_t). We can get rid of this and add the
** flags to the cache member along with the rest of them.
*/
int flags;
/**
** List of callbacks for deck crosslinking purposes.
*/
fsl_xlinker_list xlinkers;
/**
** A place for caching generic things.
*/
struct {
/**
** Cached copy of the allow-symlinks config option, because it
** is needed on each stat() call. Negative value=="not yet
** determined", 0==no, positive==yes. The negative value means
** we need to check the repo config resp. the global config to
** see if this is on. We can probably default this to true,
** though i don't think(?) fossil(1) does so(?).
*/
char allowSymlinks;
/**
** The case-insensitive repo flag.
*/
char caseInsensitive;
/**
** Porting artifact. Not yet used.
*/
char ignoreDephantomizations;
/**
** Record ID of rcvfrom entry during commits.
*/
fsl_id_t rcvId;
/**
** Bool flag: whether or not a running commit process should be
** marked as private.
*/
char markPrivate;
/**
** Analog to v1's content.c:ignoreDephantomizations flag.
*/
char deferCrosslink;
/**
** True if fsl_mf_crosslink_begin() has been called but
** fsl_mf_crosslink_end() is still pending.
*/
char isCrosslinking;
/**
** Flag indicating that only cluster control artifacts
** should be processed by manifest crosslinking.
*/
char xlinkClustersOnly;
/**
** Used to tell the content-save internals that a "final
** verification" (a.k.a. verify-before-commit) is underway.
*/
char inFinalVerify;
/**
** Indicates whether or not this repo has ever seen a manifest.
** negative==undetermined, 0==no, positive==yes.
*/
char seenManifest;
/**
** TODO: a cache of most recently loaded/freed manifests,
** analog to v1's manifest.c:manifestCache array. Won't need
** this until we get to a point where we can rebuild or similar
** intensive operations.
*/
struct {
/**
** Head of the cache list. All insertions/removals happen at
** the head.
*/
fsl_deck * head;
/**
** TODO: maximum number of entries in the mf linked list.
*/
fsl_uint32_t limit;
/**
** Current number of entries in the mf linked list.
*/
fsl_uint32_t size;
} mf;
/**
** Artifact cache used during processing of manifests.
*/
fsl_acache arty;
/**
** Used during manifest parsing.
*/
fsl_id_bag mfSeen;
/**
** Used during the processing of manifests to keep track of
** "leaf checks" which need to be done downstream.
*/
fsl_id_bag leafCheck;
/**
** Holds the RID of every record awaiting verification
** during the verify-at-commit checks.
*/
fsl_id_bag toVerify;
/**
** Holds a list of "selected files."
*/
fsl_list selectedFiles;
/**
** Infrastructure for fsl_mtime_of_manifest_file(). It
** remembers the previous RID so that it knows when it has to
** invalidate/rebuild its ancestry cache.
*/
fsl_id_t mtimeManifest;
} cache;
struct {
/**
** Holds a list of (fsl_card_J*) records representing custom
** ticket table fields available in the db.
**
** Each entry's flags member denote (using fsl_card_J_flags)
** whether that field is used by the ticket or ticketchng
** tables.
**
** TODO, eventually: add a separate type for these entries. We
** use fsl_card_J because the infrastructure is there and they
** provide what we need, but fsl_card_J::flags only exists for
** this list. A custom type would be smaller than fsl_card_J
** (only two members) but adding it requires adding some
** infrastructure which isn't worth the effort at the moment.
*/
fsl_list customFields;
/**
** Gets set to true (at some point) if the client has the
** ticket db table.
*/
char hasTicket;
/**
** Gets set to true (at some point) if the client has the
** ticket.tkt_ctime db field.
*/
char hasCTime;
/**
** Gets set to true (at some point) if the client has the
** ticketchnk db table.
*/
char hasChng;
/**
** Gets set to true (at some point) if the client has the
** ticketchng.rid db field.
*/
char hasChngRid;
} ticket;
/*
Note: no state related to server/user/etc. That is higher-level
stuff. We might need to allow the user to set a default user
name to avoid that he has to explicitly set it on all of the
various Control Artifact-generation bits which need it.
*/
};
/** @internal
**
** Initialized-with-defaults fsl_cx struct.
*/
#define fsl_cx_empty_m { \
NULL /*dbMain*/, \
NULL/*allocStamp*/,\
{/*ckout*/ fsl_db_empty_m /*db*/, NULL /*dir*/, 0/*rid*/, NULL/*uuid*/}, \
{/*repo*/ fsl_db_empty_m /*db*/, NULL/*user*/}, \
{/*config*/ fsl_db_empty_m /*db*/ }, \
fsl_outputer_FILE_m /*output*/, \
fsl_state_empty_m /*clientState*/, \
fsl_error_empty_m /*error*/, \
fsl_buffer_empty_m /*scratch*/, \
fsl_buffer_empty_m /*fsScratch*/, \
fsl_cx_config_empty_m /*cxConfig*/, \
FSL_CX_F_DEFAULTS/*flags*/, \
fsl_xlinker_list_empty_m/*xlinkers*/,\
{/*cache*/ \
-1/*allowSymlinks*/, \
0/*caseInsensitive*/,\
0/*ignoreDephantomizations*/,\
0/*rcvId*/, \
0/*markPrivate*/, \
0/*deferCrosslink*/, \
0/*isCrosslinking*/,\
0/*xlinkClustersOnly*/,\
0/*inFinalVerify*/, \
-1/*seenManifest*/,\
{/*mf*/ NULL/*head*/,5/*max*/,0/*size*/}, \
fsl_acache_empty_m/*arty*/, \
fsl_id_bag_empty_m/*mfSeen*/,\
fsl_id_bag_empty_m/*leafCheck*/,\
fsl_id_bag_empty_m/*toVerify*/, \
fsl_list_empty_m/*selectedFiles*/, \
0/*mtimeManifest*/,\
}, \
{/*ticket*/ \
fsl_list_empty_m/*customFields*/, \
0/*hasTicket*/, \
0/*hasCTime*/, \
0/*hasChng*/, \
0/*hasCngRid*/ \
}\
}
/** @internal
** Initialized-with-defaults fsl_cx instance.
*/
extern const fsl_cx fsl_cx_empty;
/*
TODO:
int fsl_buffer_append_getenv( fsl_buffer * b, char const * env )
Fetches the given env var and appends it to b. Returns FSL_RC_NOT_FOUND
if the env var is not set. The primary use for this would be to simplify
the Windows implementation of fsl_find_home_dir().
*/
/** @internal
**
** Searches for a repo.tag entry given name in the given context's
** repository db. If found, it returns the record's id. If no
** record is found and create is true (non-0) then a tag is created
** and its entry id is returned. Returns 0 if it finds no entry, a
** negative value on error. On db-level error, f's error state is
** updated.
*/
fsl_id_t fsl_tag_id( fsl_cx * f, char const * tag, char create );
/** @internal
**
** Return the number of elements in the bag.
*/
fsl_size_t fsl_id_bag_count(fsl_id_bag *p);
/** @internal
**
** Remove element e from the bag if it exists in the bag. If e is
** not in the bag, this is a no-op.
*/
void fsl_id_bag_remove(fsl_id_bag *p, fsl_id_t e);
/** @internal
**
** Return true (non-0) if e in the bag. Return false if it is not.
*/
char fsl_id_bag_contains(fsl_id_bag *p, fsl_id_t e);
/** @internal
**
** Insert element e into the bag if it is not there already.
** Returns 0 if it actually inserts something or if it already
** contains such an entry, and some other value on error (e.g. FSL_RC_OOM).
*/
int fsl_id_bag_insert(fsl_id_bag *p, fsl_id_t e);
/** @internal
**
** Return the ID of the first element in the bag. Return 0 if the
** bag is empty.
*/
fsl_id_t fsl_id_bag_first(fsl_id_bag *p);
/** @internal
**
** Return the next element in the bag after e. Return 0 if
** e is the last element in the bag. Any insert or removal from
** the bag might reorder the bag.
*/
fsl_id_t fsl_id_bag_next(fsl_id_bag *p, fsl_id_t e);
/** @internal
**
** Frees any memory owned by p, but does not free p.
*/
void fsl_id_bag_clear(fsl_id_bag *p);
/** @internal
**
** Expires the single oldest entry in c. Returns true (non-0) if it
** removes an item, else 0.
*/
char fsl_acache_expire_oldest(fsl_acache * c);
/** @internal
**
** Add an entry to the content cache.
**
** This routines transfers the contents of pBlob over to c,
** regardless of success or failure. The cache will deallocate
** memory when it has finished with it.
**
** Returns 0 on success, FSL_RC_OOM on allocation error. Has undefined
** behaviour if !c, rid is not semantically valid, !pBlob (or pBlob
** has no content???).
*/
int fsl_acache_insert(fsl_acache * c, fsl_id_t rid, fsl_buffer *pBlob);
/** @internal
**
** Frees all memory held by c, and clears out c's state, but does
** not free c. Results are undefined if !c.
*/
void fsl_acache_clear(fsl_acache * c);
/** @internal
**
** Checks f->cache.arty to see if rid is available in the
** repository opened by f.
**
** Returns 0 if the content for the given rid is available in the
** repo or the cache. Returns FSL_RC_NOT_FOUND if it is not in the
** repo nor the cache. Returns some other non-0 code for "real
** errors," e.g. FSL_RC_OOM if a cache allocation fails. This
** operation may update the cache's contents.
**
** If this function detects a loop in artifact lineage, it fails an
** assert() in debug builds and returns FSL_RC_CONSISTENCY in
** non-debug builds. That doesn't happen in real life, though.
*/
int fsl_acache_check_available(fsl_cx * f, fsl_id_t rid);
/** @internal
**
** Writes content into the repository database. Returns the record
** ID via outRid (if it is not NULL). If the content is already in
** the database, it fetches the *outRid but has no side effects
** in the repo.
**
** If srcId is >0 then pBlob must contain delta content from
** the srcId record. srcId might be a phantom.
**
** pBlob is normally uncompressed text, but if uncompSize>0 then
** the pBlob value is assumed to be compressed and uncompSize is
** its uncompressed size. If uncompSize>0 then zUuid must be valid.
** TODO: we can use fsl_buffer_is_compressed() and friends to
** determine this, and remove this parameter.
**
** zUuid is the UUID of the artifact, if it is not NULL. When srcId is
** specified then zUuid must always be specified. If srcId is zero,
** and zUuid is zero then the correct zUuid is computed from pBlob.
**
** If isPrivate is true, the blob is created as a private record.
**
** If the record already exists but is a phantom, the pBlob content
** is inserted and the phatom becomes a real record.
**
** The original content of pBlob is not disturbed. The caller continues
** to be responsible for pBlob. This routine does *not* take over
** responsibility for freeing pBlob.
**
** If outRid is not NULL the on success *outRid is assigned to the
** ID of the underlying blob record.
**
** Returns 0 on success and there are too many potential error cases
** to name - this function is a massive beast.
**
** Potential TODO: we don't really need the uncompSize param - we
** can deduce it, if needed, based on pBlob's content. We cannot,
** however, know the UUID of the decompressed content unless the
** client passes it in to us.
**
**
** @see fsl_content_put()
*/
int fsl_content_put_ex( fsl_cx * f, fsl_buffer const * pBlob,
fsl_uuid_cstr zUuid, fsl_id_t srcId,
fsl_size_t uncompSize, char isPrivate,
fsl_id_t * outRid);
/** @internal
**
** Equivalent to fsl_content_put_ex(f,pBlob,NULL,0,0,0,newRid).
**
** This must only be used for saving raw (non-delta) content.
**
** @see fsl_content_put_ex()
*/
int fsl_content_put( fsl_cx * f, fsl_buffer const * pBlob,
fsl_id_t * newRid);
/** @internal
**
** If the given blob ID refers to deltified repo content, this routine
** undeltifies it and replaces its content with its expanded
** form.
**
** Returns 0 on success, FSL_RC_MISUSE if !f, FSL_RC_NOT_A_REPO if
** f has no opened repository, FSL_RC_RANGE if rid is not positive,
** and any number of other potential errors during the db and
** content operations. This function treats already unexpanded
** content as success.
**
** @see fsl_content_deltify()
*/
int fsl_content_undeltify(fsl_cx * f, fsl_id_t rid);
/** @internal
**
** The converse of fsl_content_undeltify(), this replaces the storage
** of the given blob record so that it is a delta of srcid.
**
** If rid is already a delta from some other place then no
** conversion occurs and this is a no-op unless force is true.
**
** It never generates a delta that carries a private artifact into
** a public artifact. Otherwise, when we go to send the public
** artifact on a sync operation, the other end of the sync will
** never be able to receive the source of the delta. It is OK to
** delta private->private, public->private, and public->public.
** Just no private->public delta. For such cases this function
** returns 0, as opposed to FSL_RC_ACCESS or some similar code, and
** leaves the content untouched.
**
** If srcid is a delta that depends on rid, then srcid is
** converted to undelta'd text.
**
** If either rid or srcid contain less than some "small,
** unspecified number" of bytes (currently 50), or if the resulting
** delta does not achieve a compression of at least 25%, the rid is
** left untouched.
**
** Returns 0 if a delta is successfully made or none needs to be
** made, non-0 on error.
**
** @see fsl_content_undeltify()
*/
int fsl_content_deltify(fsl_cx * f, fsl_id_t rid,
fsl_id_t srcid, char force);
/** @internal
**
** Creates a new phantom blob with the given UUID and return its
** artifact ID via *newId. Returns 0 on success, FSL_RC_MISUSE if
** !f or !uuid, FSL_RC_RANGE if fsl_is_uuid(uuid) returns false,
** FSL_RC_NOT_A_REPO if f has no repository opened, FSL_RC_ACCESS
** if the given uuid has been shunned, and about 20 other potential
** error codes from the underlying db calls. If isPrivate is true
** _or_ f has been flagged as being in "private mode" then the new
** content is flagged as private. newId may be NULL, but if it is
** then the caller will have to find the record id himself by using
** the UUID (see fsl_uuid_to_rid()).
*/
int fsl_content_new( fsl_cx * f, fsl_uuid_cstr uuid, char isPrivate,
fsl_id_t * newId );
/** @internal
**
** Recompute/rebuild the entire repo.leaf table.
**
** This can be expensive (in time) for a really large repository.
** So it is only done for things like a full rebuild.
**
** Returns 0 on success. Error may indicate that f is not a repo.
** On error f's error state may be updated.
*/
int fsl_repo_leaves_rebuild(fsl_cx * f);
/** @internal
**
** Check to see if checkin "rid" is a leaf and either add it to the LEAF
** table if it is, or remove it if it is not.
**
** Returns 0 on success, FSL_RC_MISUSE if !f or f has no repo db
** opened, FSL_RC_RANGE if pid is <=0. Other errors
** (e.g. FSL_RC_DB) may indicate that db is not a repo. On error
** db's error state may be updated.
*/
int fsl_repo_leaf_check(fsl_cx * f, fsl_id_t pid);
/** @internal
**
** Schedules a leaf check for "rid" and its parents. Returns 0 on
** success.
*/
int fsl_repo_leaf_eventually_check( fsl_cx * f, fsl_id_t rid);
/** @internal
**
** Perform all pending leaf checks. Returns 0 on success or if it
** has nothing to do.
*/
int fsl_repo_leaf_do_pending_checks(fsl_cx *f);
/** @internal
**
** UNTESTED - the bits which use this are not yet ported.
**
** This initializes some temporary db state for the crosslinking
** of tickets.
**
** Returns 0 on success. If it returns 0, the caller must
** eventually call fsl_mf_crosslink_end(), otherwise he must not
** call fsl_mf_crosslink_end().
**
** This function starts a db transaction if one is not already
** active. fsl_mf_crosslink_end() will end it.
*/
int fsl_mf_crosslink_begin(fsl_cx * f);
/** @internal
**
** UNTESTED - the bits which use this are not yet ported.
**
** Must not be called unless fsl_mf_crosslink_begin() has been
** called.
**
** Returns 0 on success. On error it initiates (or propagates) a
** rollback for the current transaction.
**
*/
int fsl_mf_crosslink_end(fsl_cx * f);
/** @internal
**
** Inserts a tag into f's repo db. It does not create the related
** control artifact - use fsl_tag_add_artifact() for that.
**
** rid is the artifact to which the tag is being applied.
**
** srcId is the artifact that contains the tag. It is often,
** but not always, the same as rid.
**
** (TODO: clarify the difference between rid/srcId.)
**
** mtime is the Julian timestamp for the tag. Defaults to
** the current time if mtime <= 0.0.
**
** If outRid is not NULL then on success *outRid is assigned
** the new record ID of the generated tag.
**
** If a more recent (compared to mtime) entry already exists for
** this tag/rid combination then its rid is returned via *outRid
** (if outRid is not NULL) and no new entry is created.
**
** Returns 0 on success, and has a huge number of potential error codes.
*/
int fsl_tag_insert( fsl_cx * f,
fsl_tag_type tagtype,
char const * zTag,
char const * zValue,
fsl_id_t srcId,
fsl_double_t mtime,
fsl_id_t rid,
fsl_id_t *outRid );
/** @internal
**
** Propagate all propagatable tags in pid to the children of pid.
*/
int fsl_tag_propagate_all(fsl_cx * f, fsl_id_t pid);
/** @internal
**
** Propagates a tag through the various internal pipelines.
**
** pid is the artifact id to whose children the tag should be
** propagated.
**
** tagid is the id of the tag to propagate (the tag.tagid db value).
**
** tagType is the type of tag to propagate. Must be either FSL_TAGTYPE_CANCEL
** or FSL_TAGTYPE_PROPAGATING.
**
** origId is the artifact id of the origin tag if tagType ==
** FSL_TAGTYPE_PROPAGATING, otherwise it is ignored.
**
** zValue is the optional value for the tag. May be NULL.
**
** mtime is the Julian timestamp for the tag. Must be a valid time
** (no defaults here).
**
** This function is unforgiving of invalid values/ranges, and may assert
** in debug mode if passed invalid ids (values<=0), a NULL f, or if f has
** no opened repo.
*/
int fsl_tag_propagate(fsl_cx *f,
fsl_tag_type tagType,
fsl_id_t pid,
fsl_id_t tagid,
fsl_id_t origId,
const char *zValue,
fsl_double_t mtime );
/** @internal
**
** Remove the PGP signature from a raw artifact, if there is one.
**
** Expects *pz to point to *pn bytes of string memory which might
** or might not be prefixed by a PGP signature. If the string is
** enveloped in a signature, then upon returning *pz will point to
** the first byte after the end of the PGP header and *pn will
** contain the length of the content up to, but not including, the
** PGP footer.
**
** If *pz does not look like a PGP header then this is a no-op.
**
** Neither pointer may be NULL and *pz must point to *pn bytes of
** valid memory.
*/
void fsl_remove_pgp_signature(unsigned char const **pz, fsl_size_t *pn);
/** @internal
**
** Clears the "seen" cache used by manifest parsing. Should be
** called by routines which initialize parsing, but not until their
** work has finished all parsing (so that recursive parsing can
** use it).
*/
void fsl_cx_clear_mf_seen(fsl_cx * f);
/** @internal
**
** Generates an fsl_appendf()-formatted message to stderr and
** fatally aborts the application by calling exit(). This is only
** (ONLY!) intended for us as a placeholder for certain test cases
** and is not thread-safe.
**
** fmt may be empty or NULL, in which case only the code and its
** fsl_rc_cstr() representation are output.
**
** This function does not return.
*/
void fsl_fatal( int code, char const * fmt, ... )
#ifdef __GNUC__
__attribute__ ((noreturn))
#endif
;
/** @internal
**
** Translate a filename into a filename-id (fnid). Create a new
** fnid if none previously exists. On success returns 0 and sets *rv
** to the filename.fnid record value. Returns non-0 on error.
** Results are undefined if any parameter is NULL.
*/
int fsl_repo_filename_to_fnid( fsl_cx * f, char const * filename, fsl_id_t * rv );
/** @internal
**
** Clears all fsl_buffer members of db but leaves the rest
** intact. If alsoErrorState is true then the error state is also
** cleared, else it is kept as well.
*/
void fsl_db_clear_strings(fsl_db * db, char alsoErrorState );
/** @internal
**
** Returns 0 if db appears to have a current repository schema, 1
** if it appears to have an out of date schema, and -1 if it
** appears to not be a repository. Results are undefined if db is
** NULL or not opened.
*/
int fsl_db_repo_verify_schema(fsl_db * db);
/** @internal
**
** Flags for APIs which add phantom blobs to the repository. The
** values in this enum derive from fossil(1) code and should not be
** changed without careful forethought and (afterwards) testing. A
** phantom blob is a blob about whose existence we know but for
** which we have no content. This normally happens during sync
** or rebuild operations.
*/
enum fsl_phantom_t {
/**
** Indicates to fsl_uuid_to_rid2() that no phantom artifact
** should be created.
*/
FSL_PHANTOM_NONE = 0,
/**
** Indicates to fsl_uuid_to_rid2() that a public phantom
** artifact should be created if no artifact is found.
*/
FSL_PHANTOM_PUBLIC = 1,
/**
** Indicates to fsl_uuid_to_rid2() that a private phantom
** artifact should be created if no artifact is found.
*/
FSL_PHANTOM_PRIVATE = 2
};
typedef enum fsl_phantom_t fsl_phantom_t;
/** @internal
**
** Works like fsl_uuid_to_rid(), with these differences:
**
** - uuid is expected to be a complete UUID, not a prefix.
**
** - If it finds no entry and the mode argument specifies so then
** it will add either a public or private phantom entry and return
** its new rid. If mode is FSL_PHANTOM_NONE then this this behaves
** just like fsl_uuid_to_rid().
**
** Returns a positive value on success, 0 if it finds no entry and
** mode==FSL_PHANTOM_NONE, and a negative value on error (e.g. if
** fsl_is_uuid(uuid) returns false). Errors which happen after
** argument validation will "most likely" update f's error state
** with details.
*/
fsl_id_t fsl_uuid_to_rid2( fsl_cx * f, fsl_uuid_cstr uuid,
fsl_phantom_t mode );
/** @internal
**
** Schedules the given rid to be verified at the next commit. This
** is used by routines which add artifact records to the blob
** table.
**
** The only error case, assuming the arguments are valid, is an
** allocation error while appending rid to the internal to-verify
** queue.
**
** @see fsl_repo_verify_at_commit()
** @see fsl_repo_verify_cancel()
*/
int fsl_repo_verify_before_commit( fsl_cx * f, fsl_id_t rid );
/** @internal
**
** Clears f's verify-at-commit list of RIDs.
**
** @see fsl_repo_verify_at_commit()
** @see fsl_repo_verify_before_commit()
*/
void fsl_repo_verify_cancel( fsl_cx * f );
/** @internal
**
** Processes all pending verify-at-commit entries and clears the
** to-verify list. Returns 0 on success. On error f's error state
** will likely be updated.
**
** ONLY call this from fsl_db_transaction_end() or its delegate (if
** refactored).
**
** Verification calls fsl_content_get() to "unpack" content added
** in the current transaction. If fetching the content (which
** applies any deltas it may need to) fails or a checksum does not
** match then this routine fails and returns non-0. Any error f's
** error state will be updated.
**
** @see fsl_repo_verify_cancel()
** @see fsl_repo_verify_before_commit()
*/
int fsl_repo_verify_at_commit( fsl_cx * f );
/** @internal
**
** Removes all entries from the repo's blob table which are listed
** in the shun table. Returns 0 on success. This operation is
** wrapped in a transaction. Delta contant which depend on
** to-be-shunned content are replaced with their undeltad forms.
**
** Returns 0 on success.
*/
int fsl_repo_shun_artifacts(fsl_cx * f);
/** @internal.
**
** Return a pointer to a string that contains the RHS of an SQL IN
** operator which will select config.name values that are part of
** the configuration that matches iMatch (a bitmask of
** fsl_configset_t values). Ownership of the returned string is
** passed to the caller, who must eventually pass it to
** fsl_free(). Returns NULL on allocation error.
*/
char *fsl_config_inop_rhs(int iMask);
/** @internal
**
** Return a pointer to a string that contains the RHS of an IN
** operator that will select config.name values that are in the
** list of control settings. Ownership of the returned string is
** passed to the caller, who must eventually pass it to
** fsl_free(). Returns NULL on allocation error.
*/
char *fsl_db_setting_inop_rhs();
/**
** Hard-coded range of values of the vfile.chnged db field.
*/
enum fsl_vfile_change_t {
FSL_VFILE_CHANGE_NONE = 0,
FSL_VFILE_CHANGE_MOD = 1,
FSL_VFILE_CHANGE_MERGE_MOD = 2,
FSL_VFILE_CHANGE_MERGE_ADD = 3,
FSL_VFILE_CHANGE_INTEGRATE_MOD = 4,
FSL_VFILE_CHANGE_INTEGRATE_ADD = 5
};
/** @internal
**
** Populates f's checkout vfile table with all files from the given
** Manifest RID. If vfile already contains entries for that
** manifest, it assumes they are loaded and does not insert them
** (returning 0 unless cleanup (see below) fails). If manifestRid
** is 0 or less then the current checkout's RID is used.
**
** The clearOthers flag is a compatibility flag for fossil(1). The
** vfile model allows an arbitrary number of checkin versions to be
** installed in it at once, but several of fossil(1)'s reports do
** not account for that, and assume only one version is loaded at a
** time.
**
** Returns 0 on success, any number of codes on any number of errors.
**
** f must not be NULL and must have opened checkout and repository
** databases. In debug builds it will assert that that is so.
**
*/
int fsl_vfile_load_from_rid(fsl_cx * f, fsl_id_t manifestRid, char clearOthers);
/**
** @internal
**
** A bitmask of flags for fsl_vfile_changes_scan().
*/
enum fsl_ckout_sig_t {
/**
** The empty flags set.
*/
FSL_VFILE_CKSIG_NONE = 0,
/**
** Non-file FS objects throw an error. Not yet implemented.
*/
FSL_VFILE_CKSIG_ENOTFILE = 0x001,
/**
** Verify file content using sha1sum, regardless of whether or not
** file timestamps differ.
*/
FSL_VFILE_CKSIG_SHA1 = 0x002,
/**
** Set mtime to last check-out time, as determined by
** fsl_mtime_of_manifest_file().
*/
FSL_VFILE_CKSIG_SETMTIME = 0x004,
/**
** Indicates that when populating the vfile table, it should
** be cleared of entries for other checkins. This is primarily
** for compatibility with fossil(1), which generally assumes
** only a single checkin's worth of state is in vfile.
*/
FSL_VFILE_CKSIG_CLEAR_VFILE = 0x008
};
/** @internal
**
** This function populates the vfile table for the given checkin
** version ID then compares it against files in the checkout
** directory, updating vfile's status for the current checkout
** version id as its goes. If vid is 0 or negative then the
** current checkout's RID is used in its place. cksigflags
** must be a bitmask of fsl_ckout_sig_t values.
**
** Returns 0 on success, non-0 on error.
**
** BUG: this does not properly catch one particular change, where
** a file has been replaced by a same-named non-file.
*/
int fsl_vfile_changes_scan(fsl_cx * f, fsl_id_t vid, int cksigFlags);
/** @internal
**
** Creates the ticket and ticketchng tables in f's repository db,
** DROPPING them if they already exist. The schema comes from
** fsl_cx_schema_ticket().
**
** Returns 0 on success.
*/
int fsl_cx_ticket_create_table(fsl_cx * f);
/** @internal
**
** li is assumed to be empty or contain (fsl_card_J*)
** instances. Its contents are freed, along with any memory owned
** by li if alsoListMem is true, but li itself is not freed.
**
** Returns 0 on success. Results are undefined if li is NULL.
*/
void fsl_card_J_list_free( fsl_list * li, char alsoListMem );
/** @internal
**
** Values for fsl_card_J::flags.
*/
enum fsl_card_J_flags {
/**
** Indicates that the field is used by the ticket table.
*/
FSL_CARD_J_TICKET = 0x01,
/**
** Indicates that the field is used by the ticketchng table.
*/
FSL_CARD_J_CHNG = 0x02,
/**
** Indicates that the field is used by both the ticket and
** ticketchng tables.
*/
FSL_CARD_J_BOTH = FSL_CARD_J_TICKET | FSL_CARD_J_CHNG
};
/** @internal
**
** Loads all custom/customizable ticket fields from f's repo's
** ticket table info f. If f has already loaded the list and
** forceReload is false, this is a no-op.
**
** Returns 0 on success.
**
** @see fsl_cx::ticket::customFields
*/
int fsl_cx_ticket_load_fields(fsl_cx * f, char forceReload);
/** @internal
**
** A comparison routine for qsort(3) which compares fsl_card_J
** instances in a lexical manner based on their names. The order is
** important for card ordering in generated manifests.
**
** This routine expects to get passed (fsl_card_J**) (namely from
** fsl_list entries), and will not work on an array of J-cards.
*/
int fsl_qsort_cmp_J_cards( void const * lhs, void const * rhs );
/** @internal
**
** The internal version of fsl_deck_parse(). See that function
** for details regarding everything but the 3rd argument.
**
** If you happen to know the _correct_ RID for the deck being
** parsed, pass it as the rid argument, else pass 0. A negative
** value will result in a FSL_RC_RANGE error. This value is (or
** will be) only used as an optimization in other places and only
** if d->f is not NULL. Passing a positive value has no effect on
** how the content is parsed or on the result - it only affects
** internal details/optimizations.
**
*/
int fsl_deck_parse2(fsl_deck * d, fsl_buffer * src, fsl_id_t rid);
/** @internal
**
** This function updates the repo and/or global config databases
** with links between the dbs intended for various fossil-level
** bookkeeping and housecleaning. These links are not essential to
** fossil's functionality but assist in certain "global"
** operations.
**
** If no checkout is opened but a repo is, the global config (if
** opened) is updated to know about the opened repo db.
**
** If a checkout is opened, global config (if opened) and the
** repo are updated to point to the checked-out db.
**
*/
int fsl_repo_record_filename(fsl_cx * f);
/** @internal
**
** Updates f->ckout.uuid and f->ckout.rid to reflect the current
** checkout state. If no checkout is opened, the uuid is
** freed/NULLed and the rid is set to 0. Returns 0 on success. If
** it returns an error, the f->ckout state is left in a potentially
** inconsistent state, and it should not be relied upon
** until/unless the error is resolved.
*/
int fsl_cx_update_checkout_uuid( fsl_cx *f );
/** @internal
**
** Not yet implemented - this is a placeholder for a to-be-ported
** feature.
*/
int fsl_cx_crosslink_rid( fsl_cx * f, fsl_id_t rid );
#if defined(__cplusplus)
} /*extern "C"*/
#endif
#endif
/* NET_FOSSIL_SCM_FSL_INTERNAL_H_INCLUDED */