static svn_error_t * write_fs_type(const char *path, const char *fs_type, apr_pool_t *pool) { const char *filename; apr_file_t *file; filename = svn_dirent_join(path, FS_TYPE_FILENAME, pool); SVN_ERR(svn_io_file_open(&file, filename, APR_WRITE|APR_CREATE|APR_TRUNCATE|APR_BUFFERED, APR_OS_DEFAULT, pool)); SVN_ERR(svn_io_file_write_full(file, fs_type, strlen(fs_type), NULL, pool)); SVN_ERR(svn_io_file_write_full(file, "\n", 1, NULL, pool)); return svn_error_trace(svn_io_file_close(file, pool)); }
/* Copy LEN lines from SOURCE_FILE to the MERGED_FILE, starting at * line START. The CURRENT_LINE is the current line in the source file. * The new current line is returned in *NEW_CURRENT_LINE. */ static svn_error_t * copy_to_merged_file(svn_linenum_t *new_current_line, apr_file_t *merged_file, apr_file_t *source_file, apr_off_t start, apr_off_t len, svn_linenum_t current_line, apr_pool_t *scratch_pool) { apr_pool_t *iterpool; svn_stringbuf_t *line; apr_size_t lines_read; apr_size_t lines_copied; svn_boolean_t eof; svn_linenum_t orig_current_line = current_line; lines_read = 0; iterpool = svn_pool_create(scratch_pool); while (current_line < start) { svn_pool_clear(iterpool); SVN_ERR(svn_io_file_readline(source_file, &line, NULL, &eof, APR_SIZE_MAX, iterpool, iterpool)); if (eof) break; current_line++; lines_read++; } lines_copied = 0; while (lines_copied < len) { apr_size_t bytes_written; const char *eol_str; svn_pool_clear(iterpool); SVN_ERR(svn_io_file_readline(source_file, &line, &eol_str, &eof, APR_SIZE_MAX, iterpool, iterpool)); if (eol_str) svn_stringbuf_appendcstr(line, eol_str); SVN_ERR(svn_io_file_write_full(merged_file, line->data, line->len, &bytes_written, iterpool)); if (bytes_written != line->len) return svn_error_create(SVN_ERR_IO_WRITE_ERROR, NULL, _("Could not write data to merged file")); if (eof) break; lines_copied++; } svn_pool_destroy(iterpool); *new_current_line = orig_current_line + lines_read + lines_copied; return SVN_NO_ERROR; }
/* Create a temporary file F that will automatically be deleted when the pool is cleaned up. Fill it with VALUE, and leave it open and rewound, ready to be read from. */ static svn_error_t * create_temp_file(apr_file_t **f, const svn_string_t *value, apr_pool_t *pool) { apr_off_t offset = 0; SVN_ERR(svn_io_open_unique_file3(f, NULL, NULL, svn_io_file_del_on_pool_cleanup, pool, pool)); SVN_ERR(svn_io_file_write_full(*f, value->data, value->len, NULL, pool)); return svn_io_file_seek(*f, APR_SET, &offset, pool); }
/* This implements the svn_ra_neon__block_reader() callback interface. */ static svn_error_t * spool_reader(void *userdata, const char *buf, size_t len) { spool_reader_baton_t *baton = userdata; SVN_ERR(svn_io_file_write_full(baton->spool_file, buf, len, NULL, baton->req->iterpool)); svn_pool_clear(baton->req->iterpool); return SVN_NO_ERROR; }
/* Write the PID of the current process as a decimal number, followed by a newline to the file FILENAME, using POOL for temporary allocations. */ static svn_error_t *write_pid_file(const char *filename, apr_pool_t *pool) { apr_file_t *file; const char *contents = apr_psprintf(pool, "%" APR_PID_T_FMT "\n", getpid()); SVN_ERR(svn_io_remove_file2(filename, TRUE, pool)); SVN_ERR(svn_io_file_open(&file, filename, APR_WRITE | APR_CREATE | APR_EXCL, APR_OS_DEFAULT, pool)); SVN_ERR(svn_io_file_write_full(file, contents, strlen(contents), NULL, pool)); SVN_ERR(svn_io_file_close(file, pool)); return SVN_NO_ERROR; }
static svn_error_t * write_handler_apr(void *baton, const char *data, apr_size_t *len) { struct baton_apr *btn = baton; svn_error_t *err; if (*len == 1) { err = svn_io_file_putc(*data, btn->file, btn->pool); if (err) *len = 0; } else err = svn_io_file_write_full(btn->file, data, *len, len, btn->pool); return svn_error_trace(err); }
/* Create a PATCH_FILE containing the contents of DIFF. */ static svn_error_t * create_patch_file(svn_patch_file_t **patch_file, const char *diff, apr_pool_t *pool) { apr_size_t bytes; apr_size_t len; const char *path; apr_file_t *apr_file; /* Create a patch file. */ SVN_ERR(svn_io_open_unique_file3(&apr_file, &path, NULL, svn_io_file_del_on_pool_cleanup, pool, pool)); bytes = strlen(diff); SVN_ERR(svn_io_file_write_full(apr_file, diff, bytes, &len, pool)); if (len != bytes) return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, "Cannot write to '%s'", path); SVN_ERR(svn_io_file_close(apr_file, pool)); SVN_ERR(svn_diff_open_patch_file(patch_file, path, pool)); return SVN_NO_ERROR; }
/* Write the DB_CONFIG file. */ static svn_error_t * bdb_write_config(svn_fs_t *fs) { const char *dbconfig_file_name = svn_dirent_join(fs->path, BDB_CONFIG_FILE, fs->pool); apr_file_t *dbconfig_file = NULL; int i; static const char dbconfig_contents[] = "# This is the configuration file for the Berkeley DB environment\n" "# used by your Subversion repository.\n" "# You must run 'svnadmin recover' whenever you modify this file,\n" "# for your changes to take effect.\n" "\n" "### Lock subsystem\n" "#\n" "# Make sure you read the documentation at:\n" "#\n" "# http://docs.oracle.com/cd/E17076_02/html/programmer_reference/lock_max.html\n" "#\n" "# before tweaking these values.\n" "#\n" "set_lk_max_locks 2000\n" "set_lk_max_lockers 2000\n" "set_lk_max_objects 2000\n" "\n" "### Log file subsystem\n" "#\n" "# Make sure you read the documentation at:\n" "#\n" "# http://docs.oracle.com/cd/E17076_02/html/api_reference/C/envset_lg_bsize.html\n" "# http://docs.oracle.com/cd/E17076_02/html/api_reference/C/envset_lg_max.html\n" "# http://docs.oracle.com/cd/E17076_02/html/programmer_reference/log_limits.html\n" "#\n" "# Increase the size of the in-memory log buffer from the default\n" "# of 32 Kbytes to 256 Kbytes. Decrease the log file size from\n" "# 10 Mbytes to 1 Mbyte. This will help reduce the amount of disk\n" "# space required for hot backups. The size of the log file must be\n" "# at least four times the size of the in-memory log buffer.\n" "#\n" "# Note: Decreasing the in-memory buffer size below 256 Kbytes will hurt\n" "# hurt commit performance. For details, see:\n" "#\n" "# http://svn.haxx.se/dev/archive-2002-02/0141.shtml\n" "#\n" "set_lg_bsize 262144\n" "set_lg_max 1048576\n" "#\n" "# If you see \"log region out of memory\" errors, bump lg_regionmax.\n" "# For more information, see:\n" "#\n" "# http://docs.oracle.com/cd/E17076_02/html/programmer_reference/log_config.html\n" "# http://svn.haxx.se/users/archive-2004-10/1000.shtml\n" "#\n" "set_lg_regionmax 131072\n" "#\n" /* ### Configure this with "svnadmin create --bdb-cache-size" */ "# The default cache size in BDB is only 256k. As explained in\n" "# http://svn.haxx.se/dev/archive-2004-12/0368.shtml, this is too\n" "# small for most applications. Bump this number if \"db_stat -m\"\n" "# shows too many cache misses.\n" "#\n" "set_cachesize 0 1048576 1\n"; /* Run-time configurable options. Each option set consists of a minimum required BDB version, a config hash key, a header, an inactive form and an active form. We always write the header; then, depending on the run-time configuration and the BDB version we're compiling against, we write either the active or inactive form of the value. */ static const struct { int bdb_major; int bdb_minor; const char *config_key; const char *header; const char *inactive; const char *active; } dbconfig_options[] = { /* Controlled by "svnadmin create --bdb-txn-nosync" */ { 4, 0, SVN_FS_CONFIG_BDB_TXN_NOSYNC, /* header */ "#\n" "# Disable fsync of log files on transaction commit. Read the\n" "# documentation about DB_TXN_NOSYNC at:\n" "#\n" "# http://docs.oracle.com/cd/E17076_02/html/programmer_reference/log_config.html\n" "#\n" "# [requires Berkeley DB 4.0]\n" "#\n", /* inactive */ "#set_flags DB_TXN_NOSYNC\n", /* active */ "set_flags DB_TXN_NOSYNC\n" }, /* Controlled by "svnadmin create --bdb-log-keep" */ { 4, 2, SVN_FS_CONFIG_BDB_LOG_AUTOREMOVE, /* header */ "#\n" "# Enable automatic removal of unused transaction log files.\n" "# Read the documentation about DB_LOG_AUTOREMOVE at:\n" "#\n" "# http://docs.oracle.com/cd/E17076_02/html/programmer_reference/log_config.html\n" "#\n" "# [requires Berkeley DB 4.2]\n" "#\n", /* inactive */ "#set_flags DB_LOG_AUTOREMOVE\n", /* active */ "set_flags DB_LOG_AUTOREMOVE\n" }, }; static const int dbconfig_options_length = sizeof(dbconfig_options)/sizeof(*dbconfig_options); SVN_ERR(svn_io_file_open(&dbconfig_file, dbconfig_file_name, APR_WRITE | APR_CREATE, APR_OS_DEFAULT, fs->pool)); SVN_ERR(svn_io_file_write_full(dbconfig_file, dbconfig_contents, sizeof(dbconfig_contents) - 1, NULL, fs->pool)); /* Write the variable DB_CONFIG flags. */ for (i = 0; i < dbconfig_options_length; ++i) { void *value = NULL; const char *choice; if (fs->config) { value = svn_hash_gets(fs->config, dbconfig_options[i].config_key); } SVN_ERR(svn_io_file_write_full(dbconfig_file, dbconfig_options[i].header, strlen(dbconfig_options[i].header), NULL, fs->pool)); if (((DB_VERSION_MAJOR == dbconfig_options[i].bdb_major && DB_VERSION_MINOR >= dbconfig_options[i].bdb_minor) || DB_VERSION_MAJOR > dbconfig_options[i].bdb_major) && value != NULL && strcmp(value, "0") != 0) choice = dbconfig_options[i].active; else choice = dbconfig_options[i].inactive; SVN_ERR(svn_io_file_write_full(dbconfig_file, choice, strlen(choice), NULL, fs->pool)); } return svn_io_file_close(dbconfig_file, fs->pool); }
/* Copy FILENAME from SRC_DIR to DST_DIR in byte increments of size CHUNKSIZE. The read/write buffer of size CHUNKSIZE will be allocated in POOL. If ALLOW_MISSING is set, we won't make a fuss if FILENAME isn't found in SRC_DIR; otherwise, we will. */ static svn_error_t * copy_db_file_safely(const char *src_dir, const char *dst_dir, const char *filename, u_int32_t chunksize, svn_boolean_t allow_missing, apr_pool_t *pool) { apr_file_t *s = NULL, *d = NULL; /* init to null important for APR */ const char *file_src_path = svn_dirent_join(src_dir, filename, pool); const char *file_dst_path = svn_dirent_join(dst_dir, filename, pool); svn_error_t *err; char *buf; /* Open source file. If it's missing and that's allowed, there's nothing more to do here. */ err = svn_io_file_open(&s, file_src_path, (APR_READ | APR_LARGEFILE), APR_OS_DEFAULT, pool); if (err && APR_STATUS_IS_ENOENT(err->apr_err) && allow_missing) { svn_error_clear(err); return SVN_NO_ERROR; } SVN_ERR(err); /* Open destination file. */ SVN_ERR(svn_io_file_open(&d, file_dst_path, (APR_WRITE | APR_CREATE | APR_LARGEFILE), APR_OS_DEFAULT, pool)); /* Allocate our read/write buffer. */ buf = apr_palloc(pool, chunksize); /* Copy bytes till the cows come home. */ while (1) { apr_size_t bytes_this_time = chunksize; svn_error_t *read_err, *write_err; /* Read 'em. */ if ((read_err = svn_io_file_read(s, buf, &bytes_this_time, pool))) { if (APR_STATUS_IS_EOF(read_err->apr_err)) svn_error_clear(read_err); else { svn_error_clear(svn_io_file_close(s, pool)); svn_error_clear(svn_io_file_close(d, pool)); return read_err; } } /* Write 'em. */ if ((write_err = svn_io_file_write_full(d, buf, bytes_this_time, NULL, pool))) { svn_error_clear(svn_io_file_close(s, pool)); svn_error_clear(svn_io_file_close(d, pool)); return write_err; } /* read_err is either NULL, or a dangling pointer - but it is only a dangling pointer if it used to be an EOF error. */ if (read_err) { SVN_ERR(svn_io_file_close(s, pool)); SVN_ERR(svn_io_file_close(d, pool)); break; /* got EOF on read, all files closed, all done. */ } } return SVN_NO_ERROR; }
svn_error_t * svn_atomic_namespace__create(svn_atomic_namespace__t **ns, const char *name, apr_pool_t *result_pool) { apr_status_t apr_err; svn_error_t *err; apr_file_t *file; apr_mmap_t *mmap; const char *shm_name, *lock_name; apr_finfo_t finfo; apr_pool_t *subpool = svn_pool_create(result_pool); /* allocate the namespace data structure */ svn_atomic_namespace__t *new_ns = apr_pcalloc(result_pool, sizeof(**ns)); /* construct the names of the system objects that we need */ shm_name = apr_pstrcat(subpool, name, SHM_NAME_SUFFIX, NULL); lock_name = apr_pstrcat(subpool, name, MUTEX_NAME_SUFFIX, NULL); /* initialize the lock objects */ SVN_ERR(svn_atomic__init_once(&mutex_initialized, init_thread_mutex, NULL, result_pool)); new_ns->mutex.pool = result_pool; SVN_ERR(svn_io_file_open(&new_ns->mutex.lock_file, lock_name, APR_READ | APR_WRITE | APR_CREATE, APR_OS_DEFAULT, result_pool)); /* Make sure the last user of our lock file will actually remove it. * Please note that only the last file handle begin closed will actually * remove the underlying file (see docstring for apr_file_remove). */ apr_pool_cleanup_register(result_pool, &new_ns->mutex, delete_lock_file, apr_pool_cleanup_null); /* Prevent concurrent initialization. */ SVN_ERR(lock(&new_ns->mutex)); /* First, make sure that the underlying file exists. If it doesn't * exist, create one and initialize its content. */ err = svn_io_file_open(&file, shm_name, APR_READ | APR_WRITE | APR_CREATE, APR_OS_DEFAULT, result_pool); if (!err) { err = svn_io_stat(&finfo, shm_name, APR_FINFO_SIZE, subpool); if (!err && finfo.size < sizeof(struct shared_data_t)) { /* Zero all counters, values and names. */ struct shared_data_t initial_data; memset(&initial_data, 0, sizeof(initial_data)); err = svn_io_file_write_full(file, &initial_data, sizeof(initial_data), NULL, subpool); } } /* Now, map it into memory. */ if (!err) { apr_err = apr_mmap_create(&mmap, file, 0, sizeof(*new_ns->data), APR_MMAP_READ | APR_MMAP_WRITE , result_pool); if (!apr_err) new_ns->data = mmap->mm; else err = svn_error_createf(apr_err, NULL, _("MMAP failed for file '%s'"), shm_name); } svn_pool_destroy(subpool); if (!err && new_ns->data) { /* Detect severe cases of corruption (i.e. when some outsider messed * with our data file) */ if (new_ns->data->count > MAX_ATOMIC_COUNT) return svn_error_create(SVN_ERR_CORRUPTED_ATOMIC_STORAGE, 0, _("Number of atomics in namespace is too large.")); /* Cache the number of existing, complete entries. There can't be * incomplete ones from other processes because we hold the mutex. * Our process will also not access this information since we are * either being called from within svn_atomic__init_once or by * svn_atomic_namespace__create for a new object. */ new_ns->min_used = new_ns->data->count; *ns = new_ns; } /* Unlock to allow other processes may access the shared memory as well. */ return unlock(&new_ns->mutex, err); }
dav_error * dav_svn__store_activity(const dav_svn_repos *repos, const char *activity_id, const char *txn_name) { const char *final_path, *tmp_path, *activity_contents; svn_error_t *err; apr_file_t *activity_file; /* Create activities directory if it does not yet exist. */ err = svn_io_make_dir_recursively(repos->activities_db, repos->pool); if (err != NULL) return dav_svn__convert_err(err, HTTP_INTERNAL_SERVER_ERROR, "could not initialize activity db.", repos->pool); final_path = activity_pathname(repos, activity_id); err = svn_io_open_unique_file2(&activity_file, &tmp_path, final_path, ".tmp", svn_io_file_del_none, repos->pool); if (err) { svn_error_t *serr = svn_error_quick_wrap(err, "Can't open activity db"); return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "could not open files.", repos->pool); } activity_contents = apr_psprintf(repos->pool, "%s\n%s\n", txn_name, activity_id); err = svn_io_file_write_full(activity_file, activity_contents, strlen(activity_contents), NULL, repos->pool); if (err) { svn_error_t *serr = svn_error_quick_wrap(err, "Can't write to activity db"); /* Try to remove the tmp file, but we already have an error... */ svn_error_clear(svn_io_file_close(activity_file, repos->pool)); svn_error_clear(svn_io_remove_file(tmp_path, repos->pool)); return dav_svn__convert_err(serr, HTTP_INTERNAL_SERVER_ERROR, "could not write files.", repos->pool); } err = svn_io_file_close(activity_file, repos->pool); if (err) { svn_error_clear(svn_io_remove_file(tmp_path, repos->pool)); return dav_svn__convert_err(err, HTTP_INTERNAL_SERVER_ERROR, "could not close files.", repos->pool); } err = svn_io_file_rename(tmp_path, final_path, repos->pool); if (err) { svn_error_clear(svn_io_remove_file(tmp_path, repos->pool)); return dav_svn__convert_err(err, HTTP_INTERNAL_SERVER_ERROR, "could not replace files.", repos->pool); } return NULL; }
svn_error_t * svn_spillbuf__write(svn_spillbuf_t *buf, const char *data, apr_size_t len, apr_pool_t *scratch_pool) { struct memblock_t *mem; /* We do not (yet) have a spill file, but the amount stored in memory will grow too large. Create the file and place the pending data into the temporary file. */ if (buf->spill == NULL && ((buf->maxsize - buf->memory_size) < len)) { SVN_ERR(svn_io_open_unique_file3(&buf->spill, &buf->filename, buf->dirpath, (buf->delete_on_close ? svn_io_file_del_on_close : svn_io_file_del_none), buf->pool, scratch_pool)); /* Optionally write the memory contents into the file. */ if (buf->spill_all_contents) { mem = buf->head; while (mem != NULL) { SVN_ERR(svn_io_file_write_full(buf->spill, mem->data, mem->size, NULL, scratch_pool)); mem = mem->next; } /* Adjust the start offset for reading from the spill file. This way, the first `buf->memory_size` bytes of data will be read from the existing in-memory buffers, which makes more sense than discarding the buffers and re-reading data from the file. */ buf->spill_start = buf->memory_size; } } /* Once a spill file has been constructed, then we need to put all arriving data into the file. We will no longer attempt to hold it in memory. */ if (buf->spill != NULL) { apr_off_t output_unused = 0; /* ### stupid API */ /* Seek to the end of the spill file. We don't know if a read has occurred since our last write, and moved the file position. */ SVN_ERR(svn_io_file_seek(buf->spill, APR_END, &output_unused, scratch_pool)); SVN_ERR(svn_io_file_write_full(buf->spill, data, len, NULL, scratch_pool)); buf->spill_size += len; return SVN_NO_ERROR; } while (len > 0) { apr_size_t amt; if (buf->tail == NULL || buf->tail->size == buf->blocksize) { /* There is no existing memblock (that may have space), or the tail memblock has no space, so we need a new memblock. */ mem = get_buffer(buf); mem->size = 0; mem->next = NULL; } else { mem = buf->tail; } /* Compute how much to write into the memblock. */ amt = buf->blocksize - mem->size; if (amt > len) amt = len; /* Copy some data into this memblock. */ memcpy(&mem->data[mem->size], data, amt); mem->size += amt; data += amt; len -= amt; /* We need to record how much is buffered in memory. Once we reach buf->maxsize (or thereabouts, it doesn't have to be precise), then we'll switch to putting the content into a file. */ buf->memory_size += amt; /* Start a list of buffers, or (if we're not writing into the tail) append to the end of the linked list of buffers. */ if (buf->tail == NULL) { buf->head = mem; buf->tail = mem; } else if (mem != buf->tail) { buf->tail->next = mem; buf->tail = mem; } } return SVN_NO_ERROR; }
/* Edit CHUNK and return the result in *MERGED_CHUNK allocated in POOL. */ static svn_error_t * edit_chunk(apr_array_header_t **merged_chunk, apr_array_header_t *chunk, const char *editor_cmd, apr_hash_t *config, apr_pool_t *result_pool, apr_pool_t *scratch_pool) { apr_file_t *temp_file; const char *temp_file_name; int i; apr_off_t pos; svn_boolean_t eof; svn_error_t *err; apr_pool_t *iterpool; SVN_ERR(svn_io_open_unique_file3(&temp_file, &temp_file_name, NULL, svn_io_file_del_on_pool_cleanup, scratch_pool, scratch_pool)); iterpool = svn_pool_create(scratch_pool); for (i = 0; i < chunk->nelts; i++) { svn_stringbuf_t *line = APR_ARRAY_IDX(chunk, i, svn_stringbuf_t *); apr_size_t bytes_written; svn_pool_clear(iterpool); SVN_ERR(svn_io_file_write_full(temp_file, line->data, line->len, &bytes_written, iterpool)); if (line->len != bytes_written) return svn_error_create(SVN_ERR_IO_WRITE_ERROR, NULL, _("Could not write data to temporary file")); } SVN_ERR(svn_io_file_flush(temp_file, scratch_pool)); err = svn_cmdline__edit_file_externally(temp_file_name, editor_cmd, config, scratch_pool); if (err && (err->apr_err == SVN_ERR_CL_NO_EXTERNAL_EDITOR)) { svn_error_t *root_err = svn_error_root_cause(err); SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, "%s\n", root_err->message ? root_err->message : _("No editor found."))); svn_error_clear(err); *merged_chunk = NULL; svn_pool_destroy(iterpool); return SVN_NO_ERROR; } else if (err && (err->apr_err == SVN_ERR_EXTERNAL_PROGRAM)) { svn_error_t *root_err = svn_error_root_cause(err); SVN_ERR(svn_cmdline_fprintf(stderr, scratch_pool, "%s\n", root_err->message ? root_err->message : _("Error running editor."))); svn_error_clear(err); *merged_chunk = NULL; svn_pool_destroy(iterpool); return SVN_NO_ERROR; } else if (err) return svn_error_trace(err); *merged_chunk = apr_array_make(result_pool, 1, sizeof(svn_stringbuf_t *)); pos = 0; SVN_ERR(svn_io_file_seek(temp_file, APR_SET, &pos, scratch_pool)); do { svn_stringbuf_t *line; const char *eol_str; svn_pool_clear(iterpool); SVN_ERR(svn_io_file_readline(temp_file, &line, &eol_str, &eof, APR_SIZE_MAX, result_pool, iterpool)); if (eol_str) svn_stringbuf_appendcstr(line, eol_str); APR_ARRAY_PUSH(*merged_chunk, svn_stringbuf_t *) = line; } while (!eof); svn_pool_destroy(iterpool); SVN_ERR(svn_io_file_close(temp_file, scratch_pool)); return SVN_NO_ERROR; }