📄 fs_fs.c
字号:
apr_pool_t *pool){ apr_file_t *noderev_file; const char *txn_id = svn_fs_fs__id_txn_id(id); 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_BUFFERED, 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[64]; 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 -= sizeof(buf); 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 = sizeof(buf); 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")); } i++; if (root_offset) *root_offset = apr_atoi64(&buf[i]); /* find the next space */ for ( ; i < (num_bytes - 2) ; 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++; /* note that apr_atoi64() will stop reading as soon as it encounters the final newline. */ 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, svn_fs_fs__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){ const char *final_path = path_revprops(fs, rev, pool); const char *tmp_path; apr_file_t *f; SVN_ERR(svn_io_open_unique_file2 (&f, &tmp_path, final_path, ".tmp", svn_io_file_del_none, pool)); SVN_ERR(svn_hash_write(proplist, f, pool)); SVN_ERR(svn_io_file_close(f, pool)); /* We use the rev file of this revision as the perms reference, because when setting revprops for the first time, the revprop file won't exist and therefore can't serve as its own reference. (Whereas the rev file should already exist at this point.) */ SVN_ERR(svn_fs_fs__move_into_place(tmp_path, final_path, svn_fs_fs__path_rev(fs, rev, pool), 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;};/* Read the rep args for REP in filesystem FS and create a rep_state for reading the representation. Return the rep_state in *REP_STATE and the rep args in *REP_ARGS, both allocated in POOL. */static svn_error_t *create_rep_state(struct rep_state **rep_state, struct rep_args **rep_args, representation_t *rep, svn_fs_t *fs, apr_pool_t *pool){ struct rep_state *rs = apr_pcalloc(pool, sizeof(*rs)); struct rep_args *ra; unsigned char buf[4]; SVN_ERR(open_and_seek_representation(&rs->file, fs, rep, pool)); SVN_ERR(read_rep_line(&ra, rs->file, pool)); SVN_ERR(get_file_offset(&rs->start, rs->file, pool)); rs->off = rs->start; rs->end = rs->start + rep->size; *rep_state = rs; *rep_args = ra; if (ra->is_delta == FALSE) /* This is a plaintext, so just return the current rep_state. */ return SVN_NO_ERROR; /* We are dealing with a delta, find out what version. */ SVN_ERR(svn_io_file_read_full(rs->file, buf, sizeof(buf), 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; return SVN_NO_ERROR;}/* 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; *list = apr_array_make(pool, 1, sizeof(struct rep_state *)); rep = *first_rep; while (1) { SVN_ERR(create_rep_state(&rs, &rep_args, &rep, fs, pool)); if (rep_args->is_delta == FALSE) { /* This is a plaintext, so just return the current rep_state. */ *src_state = rs; return SVN_NO_ERROR; } /* 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -