FreeBSD/contrib/subversion/subversion/libsvn_fs_fs/recovery.c
/* Part of the recovery procedure.  Read the directory noderev at offset
   OFFSET of file REV_FILE (the revision file of revision REV of
   filesystem FS), and set MAX_NODE_ID and MAX_COPY_ID to be the node-id
   and copy-id of that node, if greater than the current value stored
   in either.  Recurse into any child directories that were modified in
   this revision.

   MAX_NODE_ID and MAX_COPY_ID must be arrays of at least MAX_KEY_SIZE.

   Perform temporary allocation in POOL. */
Part of the recovery procedure.  Read the directory noderev at offset
OFFSET of file REV_FILE (the revision file of revision REV of
filesystem FS), and set MAX_NODE_ID and MAX_COPY_ID to be the node-id
and copy-id of that node, if greater than the current value stored
in either.  Recurse into any child directories that were modified in
this revision.

MAX_NODE_ID and MAX_COPY_ID must be arrays of at least MAX_KEY_SIZE.

Perform temporary allocation in POOL.
Part of the recovery procedure . Read the directory noderev at offset OFFSET of file REV_FILE ( the revision file of revision REV of filesystem FS ) and set MAX_NODE_ID and MAX_COPY_ID to be the node - id and copy - id of that node if greater than the current value stored in either . Recurse into any child directories that were modified in this revision . MAX_NODE_ID and MAX_COPY_ID must be arrays of at least MAX_KEY_SIZE . Perform temporary allocation in POOL .
static svn_error_t *
recover_find_max_ids(svn_fs_t *fs,
                     svn_revnum_t rev,
                     svn_fs_fs__revision_file_t *rev_file,
                     apr_off_t offset,
                     apr_uint64_t *max_node_id,
                     apr_uint64_t *max_copy_id,
                     apr_pool_t *pool)
{
  svn_fs_fs__rep_header_t *header;
  struct recover_read_from_file_baton baton;
  svn_stream_t *stream;
  apr_hash_t *entries;
  apr_hash_index_t *hi;
  apr_pool_t *iterpool;
  node_revision_t *noderev;
  svn_error_t *err;
  baton.stream = rev_file->stream;
  SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &offset, pool));
  SVN_ERR(svn_fs_fs__read_noderev(&noderev, baton.stream, pool, pool));
  if (noderev->kind != svn_node_dir)
    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
                            _("Recovery encountered a non-directory node"));
  if (!noderev->data_rep)
    return SVN_NO_ERROR;
  if (noderev->data_rep->revision != rev)
    return SVN_NO_ERROR;
  SVN_ERR(svn_fs_fs__item_offset(&offset, fs, rev_file, rev, NULL,
                                 noderev->data_rep->item_index, pool));
  SVN_ERR(svn_io_file_seek(rev_file->file, APR_SET, &offset, pool));
  SVN_ERR(svn_fs_fs__read_rep_header(&header, baton.stream, pool, pool));
  if (header->type != svn_fs_fs__rep_plain)
    return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
                            _("Recovery encountered a deltified directory "
                              "representation"));
  baton.pool = pool;
  baton.remaining = noderev->data_rep->expanded_size
                  ? noderev->data_rep->expanded_size
                  : noderev->data_rep->size;
  stream = svn_stream_create(&baton, pool);
  svn_stream_set_read2(stream, NULL ,
                       read_handler_recover);
  entries = apr_hash_make(pool);
  err = svn_hash_read2(entries, stream, SVN_HASH_TERMINATOR, pool);
  if (err)
    {
      svn_string_t *id_str = svn_fs_fs__id_unparse(noderev->id, pool);
      svn_error_clear(svn_stream_close(stream));
      return svn_error_quick_wrapf(err,
                _("malformed representation for node-revision '%s'"),
                id_str->data);
    }
  SVN_ERR(svn_stream_close(stream));
  iterpool = svn_pool_create(pool);
  for (hi = apr_hash_first(pool, entries); hi; hi = apr_hash_next(hi))
    {
      char *str_val;
      char *str;
      svn_node_kind_t kind;
      const svn_fs_id_t *id;
      const svn_fs_fs__id_part_t *rev_item;
      apr_uint64_t node_id, copy_id;
      apr_off_t child_dir_offset;
      const svn_string_t *path = apr_hash_this_val(hi);
      svn_pool_clear(iterpool);
      str_val = apr_pstrdup(iterpool, path->data);
      str = svn_cstring_tokenize(" ", &str_val);
      if (str == NULL)
        return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
                                _("Directory entry corrupt"));
      if (strcmp(str, SVN_FS_FS__KIND_FILE) == 0)
        kind = svn_node_file;
      else if (strcmp(str, SVN_FS_FS__KIND_DIR) == 0)
        kind = svn_node_dir;
      else
        {
          return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
                                  _("Directory entry corrupt"));
        }
      str = svn_cstring_tokenize(" ", &str_val);
      if (str == NULL)
        return svn_error_create(SVN_ERR_FS_CORRUPT, NULL,
                                _("Directory entry corrupt"));
      SVN_ERR(svn_fs_fs__id_parse(&id, str, iterpool));
      rev_item = svn_fs_fs__id_rev_item(id);
      if (rev_item->revision != rev)
        {
          continue;
        }
      node_id = svn_fs_fs__id_node_id(id)->number;
      copy_id = svn_fs_fs__id_copy_id(id)->number;
      if (node_id > *max_node_id)
        *max_node_id = node_id;
      if (copy_id > *max_copy_id)
        *max_copy_id = copy_id;
      if (kind == svn_node_file)
        continue;
      SVN_ERR(svn_fs_fs__item_offset(&child_dir_offset, fs,
                                     rev_file, rev, NULL, rev_item->number,
                                     iterpool));
      SVN_ERR(recover_find_max_ids(fs, rev, rev_file, child_dir_offset,
                                   max_node_id, max_copy_id, iterpool));
    }
  svn_pool_destroy(iterpool);
  return SVN_NO_ERROR;
}
static svn_error_t * recover_find_max_ids ( svn_fs_t * fs , svn_revnum_t rev , svn_fs_fs__revision_file_t * rev_file , apr_off_t offset , apr_uint64_t * max_node_id , apr_uint64_t * max_copy_id , apr_pool_t * pool ) { svn_fs_fs__rep_header_t * header ; struct recover_read_from_file_baton baton ; svn_stream_t * stream ; apr_hash_t * entries ; apr_hash_index_t * hi ; apr_pool_t * iterpool ; node_revision_t * noderev ; svn_error_t * err ; baton . stream = rev_file -> stream ; SVN_ERR ( svn_io_file_seek ( rev_file -> file , APR_SET , & offset , pool ) ) ; SVN_ERR ( svn_fs_fs__read_noderev ( & noderev , baton . stream , pool , pool ) ) ; if ( noderev -> kind != svn_node_dir ) return svn_error_create ( SVN_ERR_FS_CORRUPT , NULL , _ ( " " ) ) ; if ( ! noderev -> data_rep ) return SVN_NO_ERROR ; if ( noderev -> data_rep -> revision != rev ) return SVN_NO_ERROR ; SVN_ERR ( svn_fs_fs__item_offset ( & offset , fs , rev_file , rev , NULL , noderev -> data_rep -> item_index , pool ) ) ; SVN_ERR ( svn_io_file_seek ( rev_file -> file , APR_SET , & offset , pool ) ) ; SVN_ERR ( svn_fs_fs__read_rep_header ( & header , baton . stream , pool , pool ) ) ; if ( header -> type != svn_fs_fs__rep_plain ) return svn_error_create ( SVN_ERR_FS_CORRUPT , NULL , _ ( " " " " ) ) ; baton . pool = pool ; baton . remaining = noderev -> data_rep -> expanded_size ? noderev -> data_rep -> expanded_size : noderev -> data_rep -> size ; stream = svn_stream_create ( & baton , pool ) ; svn_stream_set_read2 ( stream , NULL , read_handler_recover ) ; entries = apr_hash_make ( pool ) ; err = svn_hash_read2 ( entries , stream , SVN_HASH_TERMINATOR , pool ) ; if ( err ) { svn_string_t * id_str = svn_fs_fs__id_unparse ( noderev -> id , pool ) ; svn_error_clear ( svn_stream_close ( stream ) ) ; return svn_error_quick_wrapf ( err , _ ( " " ) , id_str -> data ) ; } SVN_ERR ( svn_stream_close ( stream ) ) ; iterpool = svn_pool_create ( pool ) ; for ( hi = apr_hash_first ( pool , entries ) ; hi ; hi = apr_hash_next ( hi ) ) { char * str_val ; char * str ; svn_node_kind_t kind ; const svn_fs_id_t * id ; const svn_fs_fs__id_part_t * rev_item ; apr_uint64_t node_id , copy_id ; apr_off_t child_dir_offset ; const svn_string_t * path = apr_hash_this_val ( hi ) ; svn_pool_clear ( iterpool ) ; str_val = apr_pstrdup ( iterpool , path -> data ) ; str = svn_cstring_tokenize ( " " , & str_val ) ; if ( str == NULL ) return svn_error_create ( SVN_ERR_FS_CORRUPT , NULL , _ ( " " ) ) ; if ( strcmp ( str , SVN_FS_FS__KIND_FILE ) == 0 ) kind = svn_node_file ; else if ( strcmp ( str , SVN_FS_FS__KIND_DIR ) == 0 ) kind = svn_node_dir ; else { return svn_error_create ( SVN_ERR_FS_CORRUPT , NULL , _ ( " " ) ) ; } str = svn_cstring_tokenize ( " " , & str_val ) ; if ( str == NULL ) return svn_error_create ( SVN_ERR_FS_CORRUPT , NULL , _ ( " " ) ) ; SVN_ERR ( svn_fs_fs__id_parse ( & id , str , iterpool ) ) ; rev_item = svn_fs_fs__id_rev_item ( id ) ; if ( rev_item -> revision != rev ) { continue ; } node_id = svn_fs_fs__id_node_id ( id ) -> number ; copy_id = svn_fs_fs__id_copy_id ( id ) -> number ; if ( node_id > * max_node_id ) * max_node_id = node_id ; if ( copy_id > * max_copy_id ) * max_copy_id = copy_id ; if ( kind == svn_node_file ) continue ; SVN_ERR ( svn_fs_fs__item_offset ( & child_dir_offset , fs , rev_file , rev , NULL , rev_item -> number , iterpool ) ) ; SVN_ERR ( recover_find_max_ids ( fs , rev , rev_file , child_dir_offset , max_node_id , max_copy_id , iterpool ) ) ; } svn_pool_destroy ( iterpool ) ; return SVN_NO_ERROR ; }
Part of the recovery procedure.
Part of the recovery procedure .
/* Check that this is a directory.  It should be. */ /* Get the data location.  No data location indicates an empty directory. */ /* If the directory's data representation wasn't changed in this revision,
     we've already scanned the directory's contents for noderevs, so we don't
     need to again.  This will occur if a property is changed on a directory
     without changing the directory's contents. */ /* We could use get_dir_contents(), but this is much cheaper.  It does
     rely on directory entries being stored as PLAIN reps, though. */ /* Now create a stream that's allowed to read only as much data as is
     stored in the representation.  Note that this is a directory, i.e.
     represented using the hash format on disk and can never have 0 length. */ /* only full read support */ /* Now read the entries from that stream. */ /* Now check each of the entries in our directory to find new node and
     copy ids, and recurse into new subdirectories. */ /* If the node wasn't modified in this revision, we've already
             checked the node and copy id. */