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

📄 fs_fs.c

📁 linux subdivision ying gai ke yi le ba
💻 C
📖 第 1 页 / 共 5 页
字号:
  apr_pool_t *pool;

  /* Pool used to store file handles and other data that is persistant
     for the entire stream read. */
  apr_pool_t *filehandle_pool;
};

/* Create a rep_read_baton structure for node revision NODEREV in
   filesystem FS and store it in *RB_P.  Perform all allocations in
   POOL.  If rep is mutable, it must be for file contents. */
static svn_error_t *
rep_read_get_baton (struct rep_read_baton **rb_p,
                    svn_fs_t *fs,
                    representation_t *rep,
                    apr_pool_t *pool)
{
  struct rep_read_baton *b;

  b = apr_pcalloc (pool, sizeof (*b));
  b->fs = fs;
  b->chunk_index = 0;
  b->buf = NULL;
  apr_md5_init (&(b->md5_context));
  b->checksum_finalized = FALSE;
  memcpy (b->checksum, rep->checksum, sizeof (b->checksum));
  b->len = rep->expanded_size;
  b->off = 0;
  b->pool = svn_pool_create (pool);
  b->filehandle_pool = svn_pool_create (pool);
  
  SVN_ERR (build_rep_list (&b->rs_list, &b->src_state, fs, rep,
                           b->filehandle_pool));

  /* Save our output baton. */
  *rb_p = b;

  return SVN_NO_ERROR;
}

/* Get one delta window that is a result of combining all the deltas
   from the current desired representation identified in *RB, to its
   final base representation.  Store the window in *RESULT. */
static svn_error_t *
get_combined_window (svn_txdelta_window_t **result,
                     struct rep_read_baton *rb)
{
  apr_pool_t *pool, *new_pool;
  int i, this_chunk;
  svn_txdelta_window_t *window, *nwin;
  svn_stream_t *stream;
  struct rep_state *rs;

  this_chunk = rb->chunk_index++;
  pool = svn_pool_create (rb->pool);

  /* Read the next window from the original rep. */
  rs = APR_ARRAY_IDX (rb->rs_list, 0, struct rep_state *);
  stream = svn_stream_from_aprfile (rs->file, pool);
  SVN_ERR (svn_txdelta_read_svndiff_window (&window, stream, rs->ver, pool));
  rs->chunk_index++;
  SVN_ERR (get_file_offset (&rs->off, rs->file, pool));
  if (rs->off > rs->end)
    return svn_error_create (SVN_ERR_FS_CORRUPT, NULL,
                             _("Reading one svndiff window read beyond the end "
                               "of the representation"));

  /* Combine in the windows from the other delta reps, if needed. */
  for (i = 1; i < rb->rs_list->nelts; i++)
    {
      if (window->src_ops == 0)
        break;

      rs = APR_ARRAY_IDX (rb->rs_list, i, struct rep_state *);

      /* Skip windows to reach the current chunk if we aren't there yet. */
      while (rs->chunk_index < this_chunk)
        {
          SVN_ERR (svn_txdelta_skip_svndiff_window (rs->file, rs->ver, pool));
          rs->chunk_index++;
          rs->off = 0;
          SVN_ERR (svn_io_file_seek (rs->file, APR_CUR, &rs->off, pool));
          if (rs->off >= rs->end)
            return svn_error_create (SVN_ERR_FS_CORRUPT, NULL,
                                     _("Reading one svndiff window read "
                                       "beyond the end of the "
                                       "representation"));
        }

      /* Read the next window. */
      stream = svn_stream_from_aprfile (rs->file, pool);
      SVN_ERR (svn_txdelta_read_svndiff_window (&nwin, stream, rs->ver, pool));
      rs->chunk_index++;
      SVN_ERR (get_file_offset (&rs->off, rs->file, pool));

      if (rs->off > rs->end)
        return svn_error_create (SVN_ERR_FS_CORRUPT, NULL,
                                 _("Reading one svndiff window read beyond "
                                   "the end of the representation"));

      /* Combine this window with the current one.  Cycles pools so that we
         only need to hold three windows at a time. */
      new_pool = svn_pool_create (rb->pool);
      window = svn_txdelta__compose_windows (nwin, window, new_pool);
      svn_pool_destroy (pool);
      pool = new_pool;
    }

  *result = window;
  return SVN_NO_ERROR;
}

static svn_error_t *
rep_read_contents_close (void *baton)
{
  struct rep_read_baton *rb = baton;
  
  svn_pool_destroy (rb->pool);
  svn_pool_destroy (rb->filehandle_pool);
  
  return SVN_NO_ERROR;
}

/* Return the next *LEN bytes of the rep and store them in *BUF. */
static svn_error_t *
get_contents (struct rep_read_baton *rb,
              char *buf,
              apr_size_t *len)
{
  apr_size_t copy_len, remaining = *len;
  char *sbuf, *cur = buf;
  struct rep_state *rs;
  svn_txdelta_window_t *window;

  /* Special case for when there are no delta reps, only a plain
     text. */
  if (rb->rs_list->nelts == 0)
    {
      copy_len = remaining;
      rs = rb->src_state;
      if (((apr_off_t) copy_len) > rs->end - rs->off)
        copy_len = (apr_size_t) (rs->end - rs->off);
      SVN_ERR (svn_io_file_read_full (rs->file, cur, copy_len, NULL,
                                      rb->pool));
      rs->off += copy_len;
      *len = copy_len;
      return SVN_NO_ERROR;
    }

  while (remaining > 0)
    {
      /* If we have buffered data from a previous chunk, use that. */
      if (rb->buf)
        {
          /* Determine how much to copy from the buffer. */
          copy_len = rb->buf_len - rb->buf_pos;
          if (copy_len > remaining)
            copy_len = remaining;

          /* Actually copy the data. */
          memcpy (cur, rb->buf + rb->buf_pos, copy_len);
          rb->buf_pos += copy_len;
          cur += copy_len;
          remaining -= copy_len;

          /* If the buffer is all used up, clear it and empty the
             local pool. */
          if (rb->buf_pos == rb->buf_len)
            {
              svn_pool_clear (rb->pool);
              rb->buf = NULL;
            }
        }
      else
        {
          
          rs = APR_ARRAY_IDX (rb->rs_list, 0, struct rep_state *);
          if (rs->off == rs->end)
            break;
          
          /* Get more buffered data by evaluating a chunk. */
          SVN_ERR (get_combined_window (&window, rb));
          if (window->src_ops > 0)
            {
              if (! rb->src_state)
                return svn_error_create (SVN_ERR_FS_CORRUPT, NULL,
                                         _("svndiff data requested "
                                           "non-existent source"));
              rs = rb->src_state;
              sbuf = apr_pcalloc (rb->pool, window->sview_len);
              if (! ((rs->start + window->sview_offset) < rs->end))
                return svn_error_create (SVN_ERR_FS_CORRUPT, NULL,
                                         _("svndiff requested position beyond "
                                           "end of stream"));
              if ((rs->start + window->sview_offset) != rs->off)
                {
                  rs->off = rs->start + window->sview_offset;
                  SVN_ERR (svn_io_file_seek (rs->file, APR_SET, &rs->off,
                                             rb->pool));
                }
              SVN_ERR (svn_io_file_read_full (rs->file, sbuf,
                                              window->sview_len,
                                              NULL, rb->pool));
              rs->off += window->sview_len;
            }
          else
            sbuf = NULL;
          
          rb->buf_len = window->tview_len;
          rb->buf = apr_pcalloc (rb->pool, rb->buf_len);
          svn_txdelta__apply_instructions (window, sbuf, rb->buf,
                                           &rb->buf_len);
          if (rb->buf_len != window->tview_len)
            return svn_error_create (SVN_ERR_FS_CORRUPT, NULL,
                                     _("svndiff window length is corrupt"));
          rb->buf_pos = 0;
        }
    }

  *len = cur - buf;

  return SVN_NO_ERROR;
}

/* BATON is of type `rep_read_baton'; read the next *LEN bytes of the
   representation and store them in *BUF.  Sum as we read and verify
   the MD5 sum at the end. */
static svn_error_t *
rep_read_contents (void *baton,
                   char *buf,
                   apr_size_t *len)
{
  struct rep_read_baton *rb = baton;

  /* Get the next block of data. */
  SVN_ERR (get_contents (rb, buf, len));

  /* Perform checksumming.  We want to check the checksum as soon as
     the last byte of data is read, in case the caller never performs
     a short read, but we don't want to finalize the MD5 context
     twice. */
  if (!rb->checksum_finalized)
    {
      apr_md5_update (&rb->md5_context, buf, *len);
      rb->off += *len;
      if (rb->off == rb->len)
        {
          unsigned char checksum[APR_MD5_DIGESTSIZE];

          rb->checksum_finalized = TRUE;
          apr_md5_final (checksum, &rb->md5_context);
          if (! svn_md5_digests_match (checksum, rb->checksum))
            return svn_error_createf (SVN_ERR_FS_CORRUPT, NULL,
               "Checksum mismatch while reading representation:\n"
               "   expected:  %s\n"
               "     actual:  %s\n",
               svn_md5_digest_to_cstring (rb->checksum, rb->pool),
               svn_md5_digest_to_cstring (checksum, rb->pool));
        }
    }
  return SVN_NO_ERROR;
}

/* Return a stream in *CONTENTS_P that will read the contents of a
   representation stored at the location given by REP.  Appropriate
   for any kind of immutable representation, but only for file
   contents (not props or directory contents) in mutable
   representations.

   If REP is NULL, the representation is assumed to be empty, and the
   empty stream is returned.
*/
static svn_error_t *
read_representation (svn_stream_t **contents_p,
                     svn_fs_t *fs,
                     representation_t *rep,
                     apr_pool_t *pool)
{
  struct rep_read_baton *rb;

  if (! rep)
    {
      *contents_p = svn_stream_empty (pool);
    }
  else
    {
      SVN_ERR (rep_read_get_baton (&rb, fs, rep, pool));
      *contents_p = svn_stream_create (rb, pool);
      svn_stream_set_read (*contents_p, rep_read_contents);
      svn_stream_set_close (*contents_p, rep_read_contents_close);
    }
  
  return SVN_NO_ERROR;
}

svn_error_t *
svn_fs_fs__get_contents (svn_stream_t **contents_p,
                         svn_fs_t *fs,
                         node_revision_t *noderev,
                         apr_pool_t *pool)
{
  return read_representation (contents_p, fs, noderev->data_rep, pool);
}

/* Fetch the contents of a directory into ENTRIES.  Values are stored
   as filename to string mappings; further conversion is necessary to
   convert them into svn_fs_dirent_t values. */
static svn_error_t *
get_dir_contents (apr_hash_t *entries,
                  svn_fs_t *fs,
                  node_revision_t *noderev,
                  apr_pool_t *pool)
{
  svn_stream_t *contents;
  
  if (noderev->data_rep && noderev->data_rep->txn_id)
    {
      apr_file_t *dir_file;
      const char *filename = path_txn_node_children (fs, noderev->id, pool);

      /* The representation is mutable.  Read the old directory
         contents from the mutable children file, followed by the
         changes we've made in this transaction. */
      SVN_ERR (svn_io_file_open (&dir_file, filename, APR_READ | APR_BUFFERED,
                                 APR_OS_DEFAULT, pool));
      contents = svn_stream_from_aprfile (dir_file, pool);
      SVN_ERR (svn_hash_read2 (entries, contents, SVN_HASH_TERMINATOR, pool));
      SVN_ERR (svn_hash_read_incremental (entries, contents, NULL, pool));
      SVN_ERR (svn_io_file_close (dir_file, pool));
    }
  else if (noderev->data_rep)
    {
      /* The representation is immutable.  Read it normally. */
      SVN_ERR (read_representation (&contents, fs, noderev->data_rep, pool));
      SVN_ERR (svn_hash_read2 (entries, contents, SVN_HASH_TERMINATOR, pool));
      SVN_ERR (svn_stream_close (contents));
    }
  
  return SVN_NO_ERROR;
}

svn_error_t *
svn_fs_fs__rep_contents_dir (apr_hash_t **entries_p,
                             svn_fs_t *fs,
                             node_revision_t *noderev,
                             apr_pool_t *pool)
{
  fs_fs_data_t *ffd = fs->fsap_data;
  apr_hash_t *entries;
  apr_hash_index_t *hi;

  /* If we have this directory cached, return it. */
  if (ffd->dir_cache_id && svn_fs_fs__id_eq (ffd->dir_cache_id, noderev->id))
    {
      *entries_p = ffd->dir_cache;
      return SVN_NO_ERROR;
    }

  /* Read in the directory hash. */
  entries = apr_hash_make (pool);
  SVN_ERR (get_dir_contents (entries, fs, noderev, pool));

  /* Prepare to cache this directory. */
  if (ffd->dir_cache_id)
    {
      svn_pool_clear (ffd->dir_cache_pool);
      ffd->dir_cache_id = NULL;
    }
  else
    ffd->dir_cache_pool = svn_pool_create (fs->pool);
  ffd->dir_cache = apr_hash_make (ffd->dir_cache_pool);

  /* Translate the string dir entries into real entries in the dir cache. */
  for (hi = apr_hash_first (pool, entries); hi; hi = apr_hash_next (hi))
    {
      const void *key;
      void *val;
      char *str_val;
      char *str, *last_str;
      svn_fs_dirent_t *dirent = apr_pcalloc (ffd->dir_cache_pool,
                                             sizeof (*dirent));

      apr_hash_this (hi, &key, NULL, &val);
      str_val = apr_pstrdup (pool, *((char **)val));
      dirent->name = apr_pstrdup (ffd->dir_cache_pool, key);

      str = apr_strtok (str_val, " ", &last_str);
      if (str == NULL)
        return svn_error_create (SVN_ERR_FS_CORRUPT, NULL,
                                 _("Directory entry corrupt"));
      
      if (strcmp (str, KIND_FILE) == 0)
        {
          dirent->kind = svn_node_file;

⌨️ 快捷键说明

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