⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 reps-strings.c

📁 linux subdivision ying gai ke yi le ba
💻 C
📖 第 1 页 / 共 4 页
字号:
/* reps-strings.c : intepreting representations with respect to strings
 *
 * ====================================================================
 * Copyright (c) 2000-2004 CollabNet.  All rights reserved.
 *
 * This software is licensed as described in the file COPYING, which
 * you should have received as part of this distribution.  The terms
 * are also available at http://subversion.tigris.org/license-1.html.
 * If newer versions of this license are posted there, you may use a
 * newer version instead, at your option.
 *
 * This software consists of voluntary contributions made by many
 * individuals.  For exact contribution history, see the revision
 * history and logs, available at http://subversion.tigris.org/.
 * ====================================================================
 */

#include <assert.h>
#include <apr_md5.h>

#define APU_WANT_DB
#include <apu_want.h>

#include "svn_fs.h"
#include "svn_pools.h"
#include "svn_md5.h"

#include "fs.h"
#include "err.h"
#include "trail.h"
#include "reps-strings.h"

#include "bdb/reps-table.h"
#include "bdb/strings-table.h"

#include "../libsvn_delta/delta.h"



/*** Helper Functions ***/


/* Return non-zero iff REP is mutable under transaction TXN_ID. */
static svn_boolean_t rep_is_mutable (representation_t *rep,
                                     const char *txn_id)
{
  if ((! rep->txn_id) || (strcmp (rep->txn_id, txn_id) != 0))
    return FALSE;
  return TRUE;
}


/* Return a `fulltext' representation, allocated in POOL, which
 * references the string STR_KEY.
 *
 * If TXN_ID is non-zero and non-NULL, make the representation mutable
 * under that TXN_ID.
 *
 * If STR_KEY is non-null, copy it into an allocation from POOL.
 *
 * If CHECKSUM is non-null, use it as the checksum for the new rep;
 * else initialize the rep with an all-zero (i.e., always successful)
 * checksum.
 */
static representation_t *
make_fulltext_rep (const char *str_key,
                   const char *txn_id,
                   const unsigned char *checksum,
                   apr_pool_t *pool)

{
  representation_t *rep = apr_pcalloc (pool, sizeof (*rep));
  if (txn_id && *txn_id)
    rep->txn_id = apr_pstrdup (pool, txn_id);
  rep->kind = rep_kind_fulltext;

  if (checksum)
    memcpy (rep->checksum, checksum, APR_MD5_DIGESTSIZE);
  else
    memset (rep->checksum, 0, APR_MD5_DIGESTSIZE);

  rep->contents.fulltext.string_key
    = str_key ? apr_pstrdup (pool, str_key) : NULL;
  return rep;
}


/* Set *KEYS to an array of string keys gleaned from `delta'
   representation REP.  Allocate *KEYS in POOL. */
static svn_error_t *
delta_string_keys (apr_array_header_t **keys,
                   const representation_t *rep,
                   apr_pool_t *pool)
{
  const char *key;
  int i;
  apr_array_header_t *chunks;

  if (rep->kind != rep_kind_delta)
    return svn_error_create
      (SVN_ERR_FS_GENERAL, NULL,
       "Representation is not of type 'delta'");

  /* Set up a convenience variable. */
  chunks = rep->contents.delta.chunks;

  /* Initialize *KEYS to an empty array. */
  *keys = apr_array_make (pool, chunks->nelts, sizeof (key));
  if (! chunks->nelts)
    return SVN_NO_ERROR;

  /* Now, push the string keys for each window into *KEYS */
  for (i = 0; i < chunks->nelts; i++)
    {
      rep_delta_chunk_t *chunk =
        (((rep_delta_chunk_t **) chunks->elts)[i]);

      key = apr_pstrdup (pool, chunk->string_key);
      (*((const char **)(apr_array_push (*keys)))) = key;
    }

  return SVN_NO_ERROR;
}


/* Delete the strings associated with array KEYS in FS as part of TRAIL.  */
static svn_error_t *
delete_strings (apr_array_header_t *keys,
                svn_fs_t *fs,
                trail_t *trail)
{
  int i;
  const char *str_key;

  for (i = 0; i < keys->nelts; i++)
    {
      str_key = ((const char **) keys->elts)[i];
      SVN_ERR (svn_fs_bdb__string_delete (fs, str_key, trail));
    }
  return SVN_NO_ERROR;
}



/*** Reading the contents from a representation. ***/

struct compose_handler_baton
{
  /* The combined window, and the pool it's allocated from. */
  svn_txdelta_window_t *window;
  apr_pool_t *window_pool;

  /* The trail for this operation. WINDOW_POOL will be a child of
     TRAIL->pool. No allocations will be made from TRAIL->pool itself. */
  trail_t *trail;

  /* TRUE when no more windows have to be read/combined. */
  svn_boolean_t done;

  /* TRUE if we've just started reading a new window. We need this
     because the svndiff handler will push a NULL window at the end of
     the stream, and we have to ignore that; but we must also know
     when it's appropriate to push a NULL window at the combiner. */
  svn_boolean_t init;
};


/* Handle one window. If BATON is emtpy, copy the WINDOW into it;
   otherwise, combine WINDOW with the one in BATON. */

static svn_error_t *
compose_handler (svn_txdelta_window_t *window, void *baton)
{
  struct compose_handler_baton *cb = baton;
  assert (!cb->done || window == NULL);
  assert (cb->trail && cb->trail->pool);

  if (!cb->init && !window)
    return SVN_NO_ERROR;

  if (cb->window)
    {
      /* Combine the incoming window with whatever's in the baton. */
      apr_pool_t *composite_pool = svn_pool_create (cb->trail->pool);
      svn_txdelta_window_t *composite;

      composite = svn_txdelta__compose_windows (window, cb->window,
                                                composite_pool);
      svn_pool_destroy (cb->window_pool);
      cb->window = composite;
      cb->window_pool = composite_pool;
      cb->done = (composite->sview_len == 0 || composite->src_ops == 0);
    }
  else if (window)
    {
      /* Copy the (first) window into the baton. */
      apr_pool_t *window_pool = svn_pool_create (cb->trail->pool);
      assert (cb->window_pool == NULL);
      cb->window = svn_txdelta__copy_window(window, window_pool);
      cb->window_pool = window_pool;
      cb->done = (window->sview_len == 0 || window->src_ops == 0);
    }
  else
    cb->done = TRUE;

  cb->init = FALSE;
  return SVN_NO_ERROR;
}



/* Read one delta window from REP[CUR_CHUNK] and push it at the
   composition handler. */

static svn_error_t *
get_one_window (struct compose_handler_baton *cb,
                svn_fs_t *fs,
                representation_t *rep,
                int cur_chunk)
{
  svn_stream_t *wstream;
  char diffdata[4096];   /* hunk of svndiff data */
  svn_filesize_t off;    /* offset into svndiff data */
  apr_size_t amt;        /* how much svndiff data to/was read */
  const char *str_key;

  apr_array_header_t *chunks = rep->contents.delta.chunks;
  rep_delta_chunk_t *this_chunk, *first_chunk;

  cb->init = TRUE;
  if (chunks->nelts <= cur_chunk)
    return compose_handler (NULL, cb);

  /* Set up a window handling stream for the svndiff data. */
  wstream = svn_txdelta_parse_svndiff (compose_handler, cb, TRUE,
                                       cb->trail->pool);

  /* First things first:  send the "SVN"{version} header through the
     stream.  ### For now, we will just use the version specified
     in the first chunk, and then verify that no chunks have a
     different version number than the one used.  In the future,
     we might simply convert chunks that use a different version
     of the diff format -- or, heck, a different format
     altogether -- to the format/version of the first chunk.  */
  first_chunk = APR_ARRAY_IDX (chunks, 0, rep_delta_chunk_t*);
  diffdata[0] = 'S';
  diffdata[1] = 'V';
  diffdata[2] = 'N';
  diffdata[3] = (char) (first_chunk->version);
  amt = 4;
  SVN_ERR (svn_stream_write (wstream, diffdata, &amt));
  /* FIXME: The stream write handler is borked; assert (amt == 4); */

  /* Get this string key which holds this window's data.
     ### todo: make sure this is an `svndiff' DIFF skel here. */
  this_chunk = APR_ARRAY_IDX (chunks, cur_chunk, rep_delta_chunk_t*);
  str_key = this_chunk->string_key;

  /* Run through the svndiff data, at least as far as necessary. */
  off = 0;
  do
    {
      amt = sizeof (diffdata);
      SVN_ERR (svn_fs_bdb__string_read (fs, str_key, diffdata,
                                        off, &amt, cb->trail));
      off += amt;
      SVN_ERR (svn_stream_write (wstream, diffdata, &amt));
    }
  while (amt != 0);
  SVN_ERR (svn_stream_close (wstream));

  assert (!cb->init);
  assert (cb->window != NULL);
  assert (cb->window_pool != NULL);
  return SVN_NO_ERROR;
}


/* Undeltify a range of data. DELTAS is the set of delta windows to
   combine, FULLTEXT is the source text, CUR_CHUNK is the index of the
   delta chunk we're starting from. OFFSET is the relative offset of
   the requested data within the chunk; BUF and LEN are what we're
   undeltifying to. */

static svn_error_t *
rep_undeltify_range (svn_fs_t *fs,
                     apr_array_header_t *deltas,
                     representation_t *fulltext,
                     int cur_chunk,
                     char *buf,
                     apr_size_t offset,
                     apr_size_t *len,
                     trail_t *trail)
{
  apr_size_t len_read = 0;

  do
    {
      struct compose_handler_baton cb = { 0 };
      char *source_buf, *target_buf;
      apr_size_t target_len;
      int cur_rep;

      cb.trail = trail;
      cb.done = FALSE;
      for (cur_rep = 0; !cb.done && cur_rep < deltas->nelts; ++cur_rep)
        {
          representation_t *const rep =
            APR_ARRAY_IDX (deltas, cur_rep, representation_t*);
          SVN_ERR (get_one_window (&cb, fs, rep, cur_chunk));
        }

      if (!cb.window)
          /* That's it, no more source data is available. */
          break;

      /* The source view length should not be 0 if there are source
         copy ops in the window. */
      assert (cb.window->sview_len > 0 || cb.window->src_ops == 0);

      /* cb.window is the combined delta window. Read the source text
         into a buffer. */
      if (fulltext && cb.window->sview_len > 0 && cb.window->src_ops > 0)
        {
          apr_size_t source_len = cb.window->sview_len;
          source_buf = apr_palloc (cb.window_pool, source_len);
          SVN_ERR (svn_fs_bdb__string_read
                   (fs, fulltext->contents.fulltext.string_key,
                    source_buf, cb.window->sview_offset, &source_len, trail));
          assert (source_len == cb.window->sview_len);
        }
      else
        {
          static char empty_buf[] = "";
          source_buf = empty_buf; /* Won't read anything from here. */
        }

      if (offset > 0)
        {
          target_len = *len - len_read + offset;
          target_buf = apr_palloc (cb.window_pool, target_len);
        }
      else
        {
          target_len = *len - len_read;
          target_buf = buf;
        }

      svn_txdelta__apply_instructions (cb.window, source_buf,
                                       target_buf, &target_len);
      if (offset > 0)
        {
          assert (target_len > offset);
          target_len -= offset;
          memcpy (buf, target_buf + offset, target_len);
          offset = 0; /* Read from the beginning of the next chunk. */
        }
      /* Don't need this window any more. */
      svn_pool_destroy (cb.window_pool);

      len_read += target_len;
      buf += target_len;
      ++cur_chunk;
    }
  while (len_read < *len);

  *len = len_read;
  return SVN_NO_ERROR;
}



/* Calculate the index of the chunk in REP that contains REP_OFFSET,
   and find the relative CHUNK_OFFSET within the chunk.

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -