/* Find entry HEADER_NAME in HEADERS and parse its value into *ID. */ static svn_error_t * read_id_part(svn_fs_x__id_t *id, apr_hash_t *headers, const char *header_name) { const char *value = svn_hash_gets(headers, header_name); if (value == NULL) return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, _("Missing %s field in node-rev"), header_name); SVN_ERR(svn_fs_x__id_parse(id, value)); return SVN_NO_ERROR; }
svn_error_t * svn_fs_x__read_noderev(svn_fs_x__noderev_t **noderev_p, svn_stream_t *stream, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { apr_hash_t *headers; svn_fs_x__noderev_t *noderev; char *value; const char *noderev_id; SVN_ERR(read_header_block(&headers, stream, scratch_pool)); SVN_ERR(svn_stream_close(stream)); noderev = apr_pcalloc(result_pool, sizeof(*noderev)); /* for error messages later */ noderev_id = svn_hash_gets(headers, HEADER_ID); /* Read the node-rev id. */ SVN_ERR(read_id_part(&noderev->noderev_id, headers, HEADER_ID)); SVN_ERR(read_id_part(&noderev->node_id, headers, HEADER_NODE)); SVN_ERR(read_id_part(&noderev->copy_id, headers, HEADER_COPY)); /* Read the type. */ value = svn_hash_gets(headers, HEADER_TYPE); if ((value == NULL) || ( strcmp(value, SVN_FS_X__KIND_FILE) && strcmp(value, SVN_FS_X__KIND_DIR))) /* ### s/kind/type/ */ return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, _("Missing kind field in node-rev '%s'"), noderev_id); noderev->kind = (strcmp(value, SVN_FS_X__KIND_FILE) == 0) ? svn_node_file : svn_node_dir; /* Read the 'count' field. */ value = svn_hash_gets(headers, HEADER_COUNT); if (value) SVN_ERR(svn_cstring_atoi(&noderev->predecessor_count, value)); else noderev->predecessor_count = 0; /* Get the properties location. */ value = svn_hash_gets(headers, HEADER_PROPS); if (value) { SVN_ERR(read_rep_offsets(&noderev->prop_rep, value, &noderev->noderev_id, result_pool, scratch_pool)); } /* Get the data location. */ value = svn_hash_gets(headers, HEADER_TEXT); if (value) { SVN_ERR(read_rep_offsets(&noderev->data_rep, value, &noderev->noderev_id, result_pool, scratch_pool)); } /* Get the created path. */ value = svn_hash_gets(headers, HEADER_CPATH); if (value == NULL) { return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, _("Missing cpath field in node-rev '%s'"), noderev_id); } else { if (!svn_fspath__is_canonical(value)) return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, _("Non-canonical cpath field in node-rev '%s'"), noderev_id); noderev->created_path = auto_unescape_path(apr_pstrdup(result_pool, value), result_pool); } /* Get the predecessor ID. */ value = svn_hash_gets(headers, HEADER_PRED); if (value) SVN_ERR(svn_fs_x__id_parse(&noderev->predecessor_id, value)); else svn_fs_x__id_reset(&noderev->predecessor_id); /* Get the copyroot. */ value = svn_hash_gets(headers, HEADER_COPYROOT); if (value == NULL) { noderev->copyroot_path = noderev->created_path; noderev->copyroot_rev = svn_fs_x__get_revnum(noderev->noderev_id.change_set); } else { SVN_ERR(parse_revnum(&noderev->copyroot_rev, (const char **)&value)); if (!svn_fspath__is_canonical(value)) return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, _("Malformed copyroot line in node-rev '%s'"), noderev_id); noderev->copyroot_path = auto_unescape_path(apr_pstrdup(result_pool, value), result_pool); } /* Get the copyfrom. */ value = svn_hash_gets(headers, HEADER_COPYFROM); if (value == NULL) { noderev->copyfrom_path = NULL; noderev->copyfrom_rev = SVN_INVALID_REVNUM; } else { SVN_ERR(parse_revnum(&noderev->copyfrom_rev, (const char **)&value)); if (*value == 0) return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, _("Malformed copyfrom line in node-rev '%s'"), noderev_id); noderev->copyfrom_path = auto_unescape_path(apr_pstrdup(result_pool, value), result_pool); } /* Get the mergeinfo count. */ value = svn_hash_gets(headers, HEADER_MINFO_CNT); if (value) SVN_ERR(svn_cstring_atoi64(&noderev->mergeinfo_count, value)); else noderev->mergeinfo_count = 0; /* Get whether *this* node has mergeinfo. */ value = svn_hash_gets(headers, HEADER_MINFO_HERE); noderev->has_mergeinfo = (value != NULL); *noderev_p = noderev; return SVN_NO_ERROR; }
/* Read the next entry in the changes record from file FILE and store the resulting change in *CHANGE_P. If there is no next record, store NULL there. Perform all allocations from POOL. */ static svn_error_t * read_change(svn_fs_x__change_t **change_p, svn_stream_t *stream, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { svn_stringbuf_t *line; svn_boolean_t eof = TRUE; svn_fs_x__change_t *change; char *str, *last_str, *kind_str; /* Default return value. */ *change_p = NULL; SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, scratch_pool)); /* Check for a blank line. */ if (eof || (line->len == 0)) return SVN_NO_ERROR; change = apr_pcalloc(result_pool, sizeof(*change)); last_str = line->data; /* Get the node-id of the change. */ str = svn_cstring_tokenize(" ", &last_str); if (str == NULL) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Invalid changes line in rev-file")); SVN_ERR(svn_fs_x__id_parse(&change->noderev_id, str)); /* Get the change type. */ str = svn_cstring_tokenize(" ", &last_str); if (str == NULL) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Invalid changes line in rev-file")); /* Don't bother to check the format number before looking for * node-kinds: just read them if you find them. */ change->node_kind = svn_node_unknown; kind_str = strchr(str, '-'); if (kind_str) { /* Cap off the end of "str" (the action). */ *kind_str = '\0'; kind_str++; if (strcmp(kind_str, SVN_FS_X__KIND_FILE) == 0) change->node_kind = svn_node_file; else if (strcmp(kind_str, SVN_FS_X__KIND_DIR) == 0) change->node_kind = svn_node_dir; else return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Invalid changes line in rev-file")); } if (strcmp(str, ACTION_MODIFY) == 0) { change->change_kind = svn_fs_path_change_modify; } else if (strcmp(str, ACTION_ADD) == 0) { change->change_kind = svn_fs_path_change_add; } else if (strcmp(str, ACTION_DELETE) == 0) { change->change_kind = svn_fs_path_change_delete; } else if (strcmp(str, ACTION_REPLACE) == 0) { change->change_kind = svn_fs_path_change_replace; } else if (strcmp(str, ACTION_RESET) == 0) { change->change_kind = svn_fs_path_change_reset; } else { return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Invalid change kind in rev file")); } /* Get the text-mod flag. */ str = svn_cstring_tokenize(" ", &last_str); if (str == NULL) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Invalid changes line in rev-file")); if (strcmp(str, FLAG_TRUE) == 0) { change->text_mod = TRUE; } else if (strcmp(str, FLAG_FALSE) == 0) { change->text_mod = FALSE; } else { return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Invalid text-mod flag in rev-file")); } /* Get the prop-mod flag. */ str = svn_cstring_tokenize(" ", &last_str); if (str == NULL) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Invalid changes line in rev-file")); if (strcmp(str, FLAG_TRUE) == 0) { change->prop_mod = TRUE; } else if (strcmp(str, FLAG_FALSE) == 0) { change->prop_mod = FALSE; } else { return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Invalid prop-mod flag in rev-file")); } /* Get the mergeinfo-mod flag. */ str = svn_cstring_tokenize(" ", &last_str); if (str == NULL) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Invalid changes line in rev-file")); if (strcmp(str, FLAG_TRUE) == 0) { change->mergeinfo_mod = svn_tristate_true; } else if (strcmp(str, FLAG_FALSE) == 0) { change->mergeinfo_mod = svn_tristate_false; } else { return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Invalid mergeinfo-mod flag in rev-file")); } /* Get the changed path. */ if (!svn_fspath__is_canonical(last_str)) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Invalid path in changes line")); change->path.data = auto_unescape_path(apr_pstrmemdup(result_pool, last_str, strlen(last_str)), result_pool); change->path.len = strlen(change->path.data); /* Read the next line, the copyfrom line. */ SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, result_pool)); change->copyfrom_known = TRUE; if (eof || line->len == 0) { change->copyfrom_rev = SVN_INVALID_REVNUM; change->copyfrom_path = NULL; } else { last_str = line->data; SVN_ERR(parse_revnum(&change->copyfrom_rev, (const char **)&last_str)); if (!svn_fspath__is_canonical(last_str)) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Invalid copy-from path in changes line")); change->copyfrom_path = auto_unescape_path(last_str, result_pool); } *change_p = change; return SVN_NO_ERROR; }