/* Implements svn_cache__deserialize_func_t */ static svn_error_t * deserialize_id(void **out, const char *data, apr_size_t data_len, apr_pool_t *pool) { svn_fs_id_t *id = svn_fs_fs__id_parse(data, data_len, pool); if (id == NULL) { return svn_error_create(SVN_ERR_FS_NOT_ID, NULL, _("Bad ID in cache")); } *out = id; return SVN_NO_ERROR; }
svn_error_t * svn_fs_fs__read_noderev(node_revision_t **noderev_p, svn_stream_t *stream, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { apr_hash_t *headers; node_revision_t *noderev; char *value; const char *noderev_id; SVN_ERR(read_header_block(&headers, stream, scratch_pool)); noderev = apr_pcalloc(result_pool, sizeof(*noderev)); /* Read the node-rev id. */ value = svn_hash_gets(headers, HEADER_ID); if (value == NULL) /* ### More information: filename/offset coordinates */ return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Missing id field in node-rev")); SVN_ERR(svn_stream_close(stream)); SVN_ERR(svn_fs_fs__id_parse(&noderev->id, value, result_pool)); noderev_id = value; /* for error messages later */ /* Read the type. */ value = svn_hash_gets(headers, HEADER_TYPE); if ((value == NULL) || ( strcmp(value, SVN_FS_FS__KIND_FILE) && strcmp(value, SVN_FS_FS__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_FS__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->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->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 = apr_pstrdup(result_pool, value); } /* Get the predecessor ID. */ value = svn_hash_gets(headers, HEADER_PRED); if (value) SVN_ERR(svn_fs_fs__id_parse(&noderev->predecessor_id, value, result_pool)); /* Get the copyroot. */ value = svn_hash_gets(headers, HEADER_COPYROOT); if (value == NULL) { noderev->copyroot_path = apr_pstrdup(result_pool, noderev->created_path); noderev->copyroot_rev = svn_fs_fs__id_rev(noderev->id); } 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 = apr_pstrdup(result_pool, value); } /* 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 = apr_pstrdup(result_pool, value); } /* Get whether this is a fresh txn root. */ value = svn_hash_gets(headers, HEADER_FRESHTXNRT); noderev->is_fresh_txn_root = (value != NULL); /* 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(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; change_t *change; char *str, *last_str, *kind_str; svn_fs_path_change2_t *info; /* 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)); info = &change->info; 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_fs__id_parse(&info->node_rev_id, str, result_pool)); if (info->node_rev_id == NULL) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Invalid changes line in rev-file")); /* 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. */ info->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_FS__KIND_FILE) == 0) info->node_kind = svn_node_file; else if (strcmp(kind_str, SVN_FS_FS__KIND_DIR) == 0) info->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) { info->change_kind = svn_fs_path_change_modify; } else if (strcmp(str, ACTION_ADD) == 0) { info->change_kind = svn_fs_path_change_add; } else if (strcmp(str, ACTION_DELETE) == 0) { info->change_kind = svn_fs_path_change_delete; } else if (strcmp(str, ACTION_REPLACE) == 0) { info->change_kind = svn_fs_path_change_replace; } else if (strcmp(str, ACTION_RESET) == 0) { info->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) { info->text_mod = TRUE; } else if (strcmp(str, FLAG_FALSE) == 0) { info->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) { info->prop_mod = TRUE; } else if (strcmp(str, FLAG_FALSE) == 0) { info->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 if given. Otherwise, the next thing is the path starting with a slash. Also, we must initialize the flag explicitly because 0 is not valid for a svn_tristate_t. */ info->mergeinfo_mod = svn_tristate_unknown; if (*last_str != '/') { 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) { info->mergeinfo_mod = svn_tristate_true; } else if (strcmp(str, FLAG_FALSE) == 0) { info->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.len = strlen(last_str); change->path.data = apr_pstrdup(result_pool, last_str); /* Read the next line, the copyfrom line. */ SVN_ERR(svn_stream_readline(stream, &line, "\n", &eof, scratch_pool)); info->copyfrom_known = TRUE; if (eof || line->len == 0) { info->copyfrom_rev = SVN_INVALID_REVNUM; info->copyfrom_path = NULL; } else { last_str = line->data; SVN_ERR(parse_revnum(&info->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")); info->copyfrom_path = apr_pstrdup(result_pool, last_str); } *change_p = change; return SVN_NO_ERROR; }
svn_error_t * svn_fs_fs__dag_deserialize(void **out, const char *data, apr_size_t data_len, apr_pool_t *pool) { dag_node_t *node = apr_pcalloc(pool, sizeof(*node)); if (data_len == 0) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Empty noderev in cache")); if (*data == 'M') { const char *newline; int id_len; data++; data_len--; if (data_len == 0) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Kindless noderev in cache")); if (*data == 'F') node->kind = svn_node_file; else if (*data == 'D') node->kind = svn_node_dir; else return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, _("Unknown kind for noderev in cache: '%c'"), *data); data++; data_len--; newline = memchr(data, '\n', data_len); if (!newline) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Unterminated ID in cache")); id_len = newline - 1 - data; node->id = svn_fs_fs__id_parse(data, id_len, pool); if (! node->id) return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, _("Bogus ID '%s' in cache"), apr_pstrndup(pool, data, id_len)); data += id_len; data_len -= id_len; data++; data_len--; if (data_len == 0) return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("No created path")); node->created_path = apr_pstrndup(pool, data, data_len); } else if (*data == 'I') { node_revision_t *noderev; apr_pool_t *subpool = svn_pool_create(pool); svn_stream_t *stream = svn_stream_from_stringbuf(svn_stringbuf_ncreate(data + 1, data_len - 1, subpool), subpool); SVN_ERR(svn_fs_fs__read_noderev(&noderev, stream, pool)); node->kind = noderev->kind; node->id = svn_fs_fs__id_copy(noderev->id, pool); node->created_path = apr_pstrdup(pool, noderev->created_path); if (noderev->is_fresh_txn_root) node->fresh_root_predecessor_id = noderev->predecessor_id; node->node_revision = noderev; svn_pool_destroy(subpool); } else return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, _("Unknown node type in cache: '%c'"), *data); *out = node; return SVN_NO_ERROR; }