/* This implements the fs_library_vtable_t.open_for_recovery() API. */ static svn_error_t * fs_open_for_recovery(svn_fs_t *fs, const char *path, svn_mutex__t *common_pool_lock, apr_pool_t *pool, apr_pool_t *common_pool) { svn_error_t * err; svn_revnum_t youngest_rev; apr_pool_t * subpool = svn_pool_create(pool); /* Recovery for FSFS is currently limited to recreating the 'current' file from the latest revision. */ /* The only thing we have to watch out for is that the 'current' file might not exist or contain garbage. So we'll try to read it here and provide or replace the existing file if we couldn't read it. (We'll also need it to exist later anyway as a source for the new file's permissions). */ /* Use a partly-filled fs pointer first to create 'current'. */ fs->path = apr_pstrdup(fs->pool, path); SVN_ERR(initialize_fs_struct(fs)); /* Figure out the repo format and check that we can even handle it. */ SVN_ERR(svn_fs_fs__read_format_file(fs, subpool)); /* Now, read 'current' and try to patch it if necessary. */ err = svn_fs_fs__youngest_rev(&youngest_rev, fs, subpool); if (err) { const char *file_path; /* 'current' file is missing or contains garbage. Since we are trying * to recover from whatever problem there is, being picky about the * error code here won't do us much good. If there is a persistent * problem that we can't fix, it will show up when we try rewrite the * file a few lines further below and we will report the failure back * to the caller. * * Start recovery with HEAD = 0. */ svn_error_clear(err); file_path = svn_fs_fs__path_current(fs, subpool); /* Best effort to ensure the file exists and is valid. * This may fail for r/o filesystems etc. */ SVN_ERR(svn_io_remove_file2(file_path, TRUE, subpool)); SVN_ERR(svn_io_file_create_empty(file_path, subpool)); SVN_ERR(svn_fs_fs__write_current(fs, 0, 1, 1, subpool)); } uninitialize_fs_struct(fs); svn_pool_destroy(subpool); /* Now open the filesystem properly by calling the vtable method directly. */ return fs_open(fs, path, common_pool_lock, pool, common_pool); }
/* Body of svn_fs_fs__open_rep_cache(). Implements svn_atomic__init_once().init_func. */ static svn_error_t * open_rep_cache(void *baton, apr_pool_t *pool) { svn_fs_t *fs = baton; fs_fs_data_t *ffd = fs->fsap_data; svn_sqlite__db_t *sdb; const char *db_path; int version; /* Open (or create) the sqlite database. It will be automatically closed when fs->pool is destroyed. */ db_path = path_rep_cache_db(fs->path, pool); #ifndef WIN32 { /* We want to extend the permissions that apply to the repository as a whole when creating a new rep cache and not simply default to umask. */ svn_boolean_t exists; SVN_ERR(svn_fs_fs__exists_rep_cache(&exists, fs, pool)); if (!exists) { const char *current = svn_fs_fs__path_current(fs, pool); svn_error_t *err = svn_io_file_create_empty(db_path, pool); if (err && !APR_STATUS_IS_EEXIST(err->apr_err)) /* A real error. */ return svn_error_trace(err); else if (err) /* Some other thread/process created the file. */ svn_error_clear(err); else /* We created the file. */ SVN_ERR(svn_io_copy_perms(current, db_path, pool)); } } #endif SVN_ERR(svn_sqlite__open(&sdb, db_path, svn_sqlite__mode_rwcreate, statements, 0, NULL, 0, fs->pool, pool)); SVN_ERR_CLOSE(svn_sqlite__read_schema_version(&version, sdb, pool), sdb); if (version < REP_CACHE_SCHEMA_FORMAT) { /* Must be 0 -- an uninitialized (no schema) database. Create the schema. Results in schema version of 1. */ SVN_ERR_CLOSE(svn_sqlite__exec_statements(sdb, STMT_CREATE_SCHEMA), sdb); } /* This is used as a flag that the database is available so don't set it earlier. */ ffd->rep_cache_db = sdb; return SVN_NO_ERROR; }
/* This implements the fs_library_vtable_t.open_for_recovery() API. */ static svn_error_t * fs_open_for_recovery(svn_fs_t *fs, const char *path, apr_pool_t *pool, apr_pool_t *common_pool) { /* Recovery for FSFS is currently limited to recreating the 'current' file from the latest revision. */ /* The only thing we have to watch out for is that the 'current' file might not exist. So we'll try to create it here unconditionally, and just ignore any errors that might indicate that it's already present. (We'll need it to exist later anyway as a source for the new file's permissions). */ /* Use a partly-filled fs pointer first to create 'current'. This will fail if 'current' already exists, but we don't care about that. */ fs->path = apr_pstrdup(fs->pool, path); svn_error_clear(svn_io_file_create(svn_fs_fs__path_current(fs, pool), "0 1 1\n", pool)); /* Now open the filesystem properly by calling the vtable method directly. */ return fs_open(fs, path, pool, common_pool); }