Login
Artifact [173a14d134]
Login

Artifact 173a14d1346292c81d277c17426e6fe62c81415d:


/* -*- 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 */