/* Subversion delta editor callback */ static svn_error_t *de_delete_entry(const char *path, svn_revnum_t revision, void *parent_baton, apr_pool_t *pool) { de_node_baton_t *node; de_node_baton_t *parent = (de_node_baton_t *)parent_baton; apr_hash_index_t *hi; int pathlen; DEBUG_MSG("de_delete_entry(%s@%ld)\n", path, revision); /* We can dump this entry directly */ node = delta_create_node(path, parent); node->kind = svn_node_none; node->action = 'D'; node->dump_needed = 1; #if 0 if ((err = delta_dump_node(node))) { return err; } #endif /* This node might be a directory, so clear the data of all children */ pathlen = strlen(node->path); for (hi = rhash_first(pool, delta_hash); hi; hi = rhash_next(hi)) { const char *npath; char *filename; rhash_this(hi, (const void **)(void *)&npath, NULL, (void **)(void *)&filename); /* TODO: This is a small hack to make sure the node is a directory */ if (!strncmp(node->path, npath, pathlen) && (npath[pathlen] == '/')) { #ifndef DUMP_DEBUG apr_file_remove(filename, node->pool); #endif DEBUG_MSG("deleting %s from delta_hash\n", npath); rhash_set(delta_hash, npath, APR_HASH_KEY_STRING, NULL, 0); } } for (hi = rhash_first(pool, prop_hash); hi; hi = rhash_next(hi)) { const char *npath; char *filename; rhash_this(hi, (const void **)(void *)&npath, NULL, (void **)(void *)&filename); /* TODO: This is a small hack to make sure the node is a directory */ if (!strncmp(node->path, npath, pathlen) && (npath[pathlen] == '/')) { #ifndef DUMP_DEBUG apr_file_remove(filename, node->pool); #endif DEBUG_MSG("deleting %s from prop_hash\n", npath); rhash_set(prop_hash, npath, APR_HASH_KEY_STRING, NULL, 0); } } for (hi = rhash_first(pool, md5_hash); hi; hi = rhash_next(hi)) { const char *npath; char *md5sum; rhash_this(hi, (const void **)(void *)&npath, NULL, (void **)(void *)&md5sum); if (!strncmp(node->path, npath, pathlen) && (npath[pathlen] == '/')) { DEBUG_MSG("deleting %s from md5_hash\n", npath); rhash_set(md5_hash, npath, APR_HASH_KEY_STRING, NULL, 0); } } return SVN_NO_ERROR; }
/* Deletes a record (from the index, not from the disk) */ int mukv_delete(mukv_t *kv, mdatum_t key) { entry_t *entry = rhash_get(kv->index, key.dptr, key.dsize); if (entry) { rhash_set(kv->index, key.dptr, key.dsize, NULL, 0); } return 0; }
/* Writes the properties of a node to a temporary file */ static svn_error_t *delta_write_properties(de_node_baton_t *node) { char *filename; apr_file_t *file = NULL; apr_status_t status; apr_hash_index_t *hi; dump_options_t *opts = node->de_baton->opts; apr_pool_t *pool = svn_pool_create(node->pool); /* Remove the properties that have been deleted from the hash */ for (hi = apr_hash_first(pool, node->del_properties); hi; hi = apr_hash_next(hi)) { const char *key; void *value; apr_hash_this(hi, (const void **)(void *)&key, NULL, &value); apr_hash_set(node->properties, key, APR_HASH_KEY_STRING, NULL); } /* We don't need to save anything if there are no properties */ if (apr_hash_count(node->properties) == 0) { rhash_set(prop_hash, node->path, APR_HASH_KEY_STRING, NULL, 0); svn_pool_destroy(pool); return SVN_NO_ERROR; } /* Create a new temporary file */ filename = apr_psprintf(node->pool, "%s/XXXXXX", opts->temp_dir); status = apr_file_mktemp(&file, filename, APR_CREATE | APR_READ | APR_WRITE | APR_EXCL, pool); if (status) { apr_pool_t *epool = svn_pool_create(NULL); char *errbuf = apr_palloc(epool, ERRBUFFER_SIZE); svn_pool_destroy(pool); return svn_error_create(status, NULL, apr_strerror(status, errbuf, ERRBUFFER_SIZE)); } property_hash_write(node->properties, file, pool); apr_file_close(file); rhash_set(prop_hash, node->path, APR_HASH_KEY_STRING, filename, RHASH_VAL_STRING); svn_pool_destroy(pool); return SVN_NO_ERROR; }
/* Subversion delta editor callback */ static svn_error_t *de_close_edit(void *edit_baton, apr_pool_t *pool) { de_baton_t *de_baton = (de_baton_t *)edit_baton; apr_hash_index_t *hi; svn_error_t *err; /* Recursively dump all nodes touched by this revision */ if ((err = delta_dump_node_recursive((de_node_baton_t *)de_baton->root_node))) { return err; } /* * There are probably some deleted nodes that haven't been dumped yet. * This will happen if nodes whose parent is a copy destination have been * deleted. */ for (hi = apr_hash_first(pool, de_baton->log_revision->changed_paths); hi; hi = apr_hash_next(hi)) { const char *path; svn_log_changed_path_t *log; apr_hash_this(hi, (const void **)(void *)&path, NULL, (void **)(void *)&log); DEBUG_MSG("Checking %s (%c)\n", path, log->action); if (log->action == 'D') { /* We can unlink a possible temporary file now */ char *filename = rhash_get(delta_hash, path, APR_HASH_KEY_STRING); if (filename) { #ifndef DUMP_DEBUG apr_file_remove(filename, pool); #endif rhash_set(delta_hash, path, APR_HASH_KEY_STRING, NULL, 0); } if (apr_hash_get(de_baton->dumped_entries, path, APR_HASH_KEY_STRING) == NULL) { de_node_baton_t *node = delta_create_node_no_parent(path, de_baton, pool); node->action = log->action; node->dump_needed = 1; DEBUG_MSG("Post-dumping %s\n", path); if ((err = delta_dump_node(node))) { return err; } } } } #ifdef USE_TIMING DEBUG_MSG("apply_text_delta: %f seconds\n", tm_de_apply_textdelta); #endif return SVN_NO_ERROR; }
/* Stores a record */ int mukv_store(mukv_t *kv, mdatum_t key, mdatum_t val) { entry_t entry; if (fseek(kv->file, 0, SEEK_END) != 0) { return errno; } entry.off = ftell(kv->file); entry.size = val.dsize; if (fwrite(val.dptr, 1, val.dsize, kv->file) != val.dsize) { return errno; } rhash_set(kv->index, key.dptr, key.dsize, &entry, sizeof(entry_t)); return 0; }
/* Marks a node as being dumped, i.e. set dump_needed to 0 */ static void delta_mark_node(de_node_baton_t *node) { de_baton_t *de_baton = node->de_baton; apr_hash_set(de_baton->dumped_entries, apr_pstrdup(de_baton->revision_pool, node->path), APR_HASH_KEY_STRING, de_baton /* The value doesn't matter */); if (node->kind == svn_node_file) { rhash_set(md5_hash, node->path, APR_HASH_KEY_STRING, node->md5sum, APR_MD5_DIGESTSIZE); DEBUG_MSG("md5_hash += %s : %s\n", node->path, svn_md5_digest_to_cstring(node->md5sum, node->pool)); } node->dump_needed = 0; if ((de_baton->opts->verbosity > 0) && !(de_baton->opts->flags & DF_DRY_RUN)) { if (node->cp_info == CPI_COPY) { fprintf(stderr, _("COPIED ... done.\n")); } else { fprintf(stderr, _("done.\n")); } } }
/* Subversion delta editor callback */ static svn_error_t *de_apply_textdelta(void *file_baton, const char *base_checksum, apr_pool_t *pool, svn_txdelta_window_handler_t *handler, void **handler_baton) { apr_file_t *src_file = NULL, *dest_file = NULL; svn_stream_t *src_stream, *dest_stream; de_node_baton_t *node = (de_node_baton_t *)file_baton; dump_options_t *opts = node->de_baton->opts; #ifdef USE_TIMING stopwatch_t watch = stopwatch_create(); #endif char *filename; DEBUG_MSG("de_apply_textdelta(%s)\n", node->path); /* Create a new temporary file to write to */ node->filename = apr_psprintf(node->pool, "%s/XXXXXX", opts->temp_dir); apr_file_mktemp(&dest_file, node->filename, APR_CREATE | APR_READ | APR_WRITE | APR_EXCL, pool); dest_stream = svn_stream_from_aprfile2(dest_file, FALSE, pool); /* Update the local copy */ filename = rhash_get(delta_hash, node->path, APR_HASH_KEY_STRING); if (filename == NULL) { src_stream = svn_stream_empty(pool); } else { apr_file_open(&src_file, filename, APR_READ, 0600, pool); src_stream = svn_stream_from_aprfile2(src_file, FALSE, pool); } svn_txdelta_apply(src_stream, dest_stream, node->md5sum, node->path, pool, handler, handler_baton); node->old_filename = apr_pstrdup(node->pool, filename); rhash_set(delta_hash, node->path, APR_HASH_KEY_STRING, node->filename, RHASH_VAL_STRING); DEBUG_MSG("applied delta: %s -> %s\n", node->old_filename, node->filename); node->applied_delta = 1; node->dump_needed = 1; #ifdef USE_TIMING tm_de_apply_textdelta += stopwatch_elapsed(&watch); #endif return SVN_NO_ERROR; }
/* Loads the properties of a node to a temporary file */ static svn_error_t *delta_load_properties(de_node_baton_t *node) { char *filename; apr_file_t *file = NULL; apr_status_t status; apr_pool_t *pool = svn_pool_create(node->pool); filename = rhash_get(prop_hash, node->path, APR_HASH_KEY_STRING); if (filename == NULL) { /* No properties is ok, too */ svn_pool_destroy(pool); return SVN_NO_ERROR; } status = apr_file_open(&file, filename, APR_READ, 0600, pool); if (status) { apr_pool_t *epool = svn_pool_create(NULL); char *errbuf = apr_palloc(epool, ERRBUFFER_SIZE); svn_pool_destroy(pool); return svn_error_create(status, NULL, apr_strerror(status, errbuf, ERRBUFFER_SIZE)); } if (property_hash_load(node->properties, file, node->pool)) { apr_file_close(file); DEBUG_MSG("ERROR reading from %s\n", filename); return svn_error_create(1, NULL, "Error reading properties file"); } apr_file_close(file); /* Delete the old file if it exists */ apr_file_remove(filename, pool); rhash_set(prop_hash, node->path, APR_HASH_KEY_STRING, NULL, 0); svn_pool_destroy(pool); return SVN_NO_ERROR; }