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

📄 fs_fs.c

📁 linux subdivision ying gai ke yi le ba
💻 C
📖 第 1 页 / 共 5 页
字号:
  if (! txn_id)
    return svn_error_create (SVN_ERR_FS_CORRUPT, NULL,
                             _("Attempted to write to non-transaction"));

  SVN_ERR (svn_io_file_open (&noderev_file, path_txn_node_rev (fs, id, pool),
                             APR_WRITE | APR_CREATE | APR_TRUNCATE,
                             APR_OS_DEFAULT, pool));

  SVN_ERR (write_noderev_txn (noderev_file, noderev, pool));

  SVN_ERR (svn_io_file_close (noderev_file, pool));

  return SVN_NO_ERROR;
}


/* This structure is used to hold the information associated with a
   REP line. */
struct rep_args
{
  svn_boolean_t is_delta;
  svn_boolean_t is_delta_vs_empty;
  
  svn_revnum_t base_revision;
  apr_off_t base_offset;
  apr_size_t base_length;
};

/* Read the next line from file FILE and parse it as a text
   representation entry.  Return the parsed entry in REP_ARGS_P.
   Perform all allocations in POOL. */
static svn_error_t *
read_rep_line (struct rep_args **rep_args_p,
               apr_file_t *file,
               apr_pool_t *pool)
{
  char buffer[160];
  apr_size_t limit;
  struct rep_args *rep_args;
  char *str, *last_str;
  
  limit = sizeof (buffer);
  SVN_ERR (svn_io_read_length_line (file, buffer, &limit, pool));

  rep_args = apr_pcalloc (pool, sizeof (*rep_args));
  rep_args->is_delta = FALSE;

  if (strcmp (buffer, REP_PLAIN) == 0)
    {
      *rep_args_p = rep_args;
      return SVN_NO_ERROR;
    }

  if (strcmp (buffer, REP_DELTA) == 0)
    {
      /* This is a delta against the empty stream. */
      rep_args->is_delta = TRUE;
      rep_args->is_delta_vs_empty = TRUE;
      *rep_args_p = rep_args;
      return SVN_NO_ERROR;
    }

  rep_args->is_delta = TRUE;
  rep_args->is_delta_vs_empty = FALSE;
  
  /* We have hopefully a DELTA vs. a non-empty base revision. */
  str = apr_strtok (buffer, " ", &last_str);
  if (! str || (strcmp (str, REP_DELTA) != 0)) goto err;

  str = apr_strtok (NULL, " ", &last_str);
  if (! str) goto err;
  rep_args->base_revision = atol (str);

  str = apr_strtok (NULL, " ", &last_str);
  if (! str) goto err;
  rep_args->base_offset = (apr_off_t) apr_atoi64 (str);

  str = apr_strtok (NULL, " ", &last_str);
  if (! str) goto err;
  rep_args->base_length = (apr_size_t) apr_atoi64 (str);

  *rep_args_p = rep_args;
  return SVN_NO_ERROR;

 err:
  return svn_error_create (SVN_ERR_FS_CORRUPT, NULL,
                           _("Malformed representation header"));
}

/* Given a revision file REV_FILE, find the Node-ID of the header
   located at OFFSET and store it in *ID_P.  Allocate temporary
   variables from POOL. */
static svn_error_t *
get_fs_id_at_offset (svn_fs_id_t **id_p,
                     apr_file_t *rev_file,
                     apr_off_t offset,
                     apr_pool_t *pool)
{
  svn_fs_id_t *id;
  apr_hash_t *headers;
  const char *node_id_str;
  
  SVN_ERR (svn_io_file_seek (rev_file, APR_SET, &offset, pool));

  SVN_ERR (read_header_block (&headers, rev_file, pool));

  node_id_str = apr_hash_get (headers, HEADER_ID, APR_HASH_KEY_STRING);

  if (node_id_str == NULL)
    return svn_error_create (SVN_ERR_FS_CORRUPT, NULL,
                             _("Missing node-id in node-rev"));

  id = svn_fs_fs__id_parse (node_id_str, strlen (node_id_str), pool);

  if (id == NULL)
    return svn_error_create (SVN_ERR_FS_CORRUPT, NULL,
                             _("Corrupt node-id in node-rev"));

  *id_p = id;

  return SVN_NO_ERROR;
}


/* Given an open revision file REV_FILE, locate the trailer that
   specifies the offset to the root node-id and to the changed path
   information.  Store the root node offset in *ROOT_OFFSET and the
   changed path offset in *CHANGES_OFFSET.  If either of these
   pointers is NULL, do nothing with it. Allocate temporary variables
   from POOL. */
static svn_error_t *
get_root_changes_offset (apr_off_t *root_offset,
                         apr_off_t *changes_offset,
                         apr_file_t *rev_file,
                         apr_pool_t *pool)
{
  apr_off_t offset;
  char buf[65];
  int i, num_bytes;
  apr_size_t len;
  
  /* We will assume that the last line containing the two offsets
     will never be longer than 64 characters. */
  offset = 0;
  SVN_ERR (svn_io_file_seek (rev_file, APR_END, &offset, pool));

  offset -= 64;
  SVN_ERR (svn_io_file_seek (rev_file, APR_SET, &offset, pool));

  /* Read in this last block, from which we will identify the last line. */
  len=64;
  SVN_ERR (svn_io_file_read (rev_file, buf, &len, pool));

  /* This cast should be safe since the maximum amount read, 64, will
     never be bigger than the size of an int. */
  num_bytes = (int) len;

  /* The last byte should be a newline. */
  if (buf[num_bytes - 1] != '\n')
    {
      return svn_error_createf (SVN_ERR_FS_CORRUPT, NULL,
                                _("Revision file lacks trailing newline"));
    }

  /* Look for the next previous newline. */
  for (i = num_bytes - 2; i >= 0; i--)
    {
      if (buf[i] == '\n') break;
    }

  if (i < 0)
    {
      return svn_error_createf (SVN_ERR_FS_CORRUPT, NULL,
                                _("Final line in revision file longer than 64 "
                                  "characters"));
    }

  if (root_offset)
    *root_offset = apr_atoi64 (&buf[i]);

  /* find the next space */
  for ( ; i < (num_bytes - 3) ; i++)
    if (buf[i] == ' ') break;

  if (i == (num_bytes - 2))
    return svn_error_create (SVN_ERR_FS_CORRUPT, NULL,
                             _("Final line in revision file missing space"));

  i++;

  if (changes_offset)
    *changes_offset = apr_atoi64 (&buf[i]);

  return SVN_NO_ERROR;
}

svn_error_t *
svn_fs_fs__rev_get_root (svn_fs_id_t **root_id_p,
                         svn_fs_t *fs,
                         svn_revnum_t rev,
                         apr_pool_t *pool)
{
  apr_file_t *revision_file;
  apr_off_t root_offset;
  svn_fs_id_t *root_id;
  svn_error_t *err;

  err = svn_io_file_open (&revision_file, path_rev (fs, rev, pool),
                          APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool);
  if (err && APR_STATUS_IS_ENOENT (err->apr_err))
    {
      svn_error_clear (err);
      return svn_error_createf (SVN_ERR_FS_NO_SUCH_REVISION, NULL,
                                _("No such revision %ld"), rev);
    }
  else if (err)
    return err;
      

  SVN_ERR (get_root_changes_offset (&root_offset, NULL, revision_file, pool));

  SVN_ERR (get_fs_id_at_offset (&root_id, revision_file, root_offset, pool));

  SVN_ERR (svn_io_file_close (revision_file, pool));

  *root_id_p = root_id;
  
  return SVN_NO_ERROR;
}

svn_error_t *
svn_fs_fs__set_revision_proplist (svn_fs_t *fs,
                                  svn_revnum_t rev,
                                  apr_hash_t *proplist,
                                  apr_pool_t *pool)
{
  apr_file_t *revprop_file;

  SVN_ERR (svn_io_file_open (&revprop_file, path_revprops (fs, rev, pool),
                             APR_WRITE | APR_TRUNCATE | APR_CREATE,
                             APR_OS_DEFAULT, pool));
  
  SVN_ERR (svn_hash_write (proplist, revprop_file, pool));

  SVN_ERR (svn_io_file_close (revprop_file, pool));
  
  return SVN_NO_ERROR;
}  

svn_error_t *
svn_fs_fs__revision_proplist (apr_hash_t **proplist_p,
                              svn_fs_t *fs,
                              svn_revnum_t rev,
                              apr_pool_t *pool)
{
  apr_file_t *revprop_file;
  apr_hash_t *proplist;
  svn_error_t *err;

  err = svn_io_file_open (&revprop_file, path_revprops (fs, rev, pool),
                          APR_READ | APR_BUFFERED, APR_OS_DEFAULT, pool);
  if (err && APR_STATUS_IS_ENOENT (err->apr_err))
    {
      svn_error_clear (err);
      return svn_error_createf (SVN_ERR_FS_NO_SUCH_REVISION, NULL,
                                _("No such revision %ld"), rev);
    }
  else if (err)
    return err;

  proplist = apr_hash_make (pool);

  SVN_ERR (svn_hash_read (proplist, revprop_file, pool));

  SVN_ERR (svn_io_file_close (revprop_file, pool));

  *proplist_p = proplist;

  return SVN_NO_ERROR;
}

/* Represents where in the current svndiff data block each
   representation is. */
struct rep_state
{
  apr_file_t *file;
  apr_off_t start;  /* The starting offset for the raw
                       svndiff/plaintext data minus header. */
  apr_off_t off;    /* The current offset into the file. */
  apr_off_t end;    /* The end offset of the raw data. */
  int ver;          /* If a delta, what svndiff version? */
  int chunk_index;
};

/* Build an array of rep_state structures in *LIST giving the delta
   reps from first_rep to a plain-text or self-compressed rep.  Set
   *SRC_STATE to the plain-text rep we find at the end of the chain,
   or to NULL if the final delta representation is self-compressed.
   The representation to start from is designated by filesystem FS, id
   ID, and representation REP. */
static svn_error_t *
build_rep_list (apr_array_header_t **list,
                struct rep_state **src_state,
                svn_fs_t *fs,
                representation_t *first_rep,
                apr_pool_t *pool)
{
  representation_t rep;
  struct rep_state *rs;
  struct rep_args *rep_args;
  apr_file_t *file;
  unsigned char buf[4];

  *list = apr_array_make (pool, 1, sizeof (struct rep_state *));
  rep = *first_rep;

  while (1)
    {
      SVN_ERR (open_and_seek_representation (&file, fs, &rep, pool));
      SVN_ERR (read_rep_line (&rep_args, file, pool));

      /* Create the rep_state for this representation. */
      rs = apr_pcalloc (pool, sizeof (*rs));
      rs->file = file;
      SVN_ERR (get_file_offset (&rs->start, file, pool));
      rs->off = rs->start;
      rs->end = rs->start + rep.size;
      
      if (rep_args->is_delta == FALSE)
        {
          /* This is a plaintext, so just return the current rep_state. */
          *src_state = rs;
          return SVN_NO_ERROR;
        }

      /* We are dealing with a delta, find out what version. */
      SVN_ERR (svn_io_file_read_full (file, buf, 4, NULL, pool));
      if (! ((buf[0] == 'S') && (buf[1] == 'V') && (buf[2] == 'N')))
        return svn_error_create
          (SVN_ERR_FS_CORRUPT, NULL,
           _("Malformed svndiff data in representation"));
      rs->ver = buf[3];
      rs->chunk_index = 0;
      rs->off += 4;

      /* Push this rep onto the list.  If it's self-compressed, we're done. */
      APR_ARRAY_PUSH (*list, struct rep_state *) = rs;
      if (rep_args->is_delta_vs_empty)
        {
          *src_state = NULL;
          return SVN_NO_ERROR;
        }

      rep.revision = rep_args->base_revision;
      rep.offset = rep_args->base_offset;
      rep.size = rep_args->base_length;
      rep.txn_id = NULL;
    }
}


struct rep_read_baton
{
  /* The FS from which we're reading. */
  svn_fs_t *fs;

  /* The state of all prior delta representations. */
  apr_array_header_t *rs_list;

  /* The plaintext state, if there is a plaintext. */
  struct rep_state *src_state;

  /* The index of the current delta chunk, if we are reading a delta. */
  int chunk_index;

  /* The buffer where we store undeltified data. */
  char *buf;
  apr_size_t buf_pos;
  apr_size_t buf_len;
  
  /* An MD5 context for summing the data read in order to verify it. */
  struct apr_md5_ctx_t md5_context;
  svn_boolean_t checksum_finalized;

  /* The stored checksum of the representation we are reading, its
     length, and the amount we've read so far.  Some of this
     information is redundant with rs_list and src_state, but it's
     convenient for the checksumming code to have it here. */
  unsigned char checksum[APR_MD5_DIGESTSIZE];
  svn_filesize_t len;
  svn_filesize_t off;

  /* Used for temporary allocations during the read. */

⌨️ 快捷键说明

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