1289177Speter/* util.c --- utility functions for FSFS repo access 2289177Speter * 3289177Speter * ==================================================================== 4289177Speter * Licensed to the Apache Software Foundation (ASF) under one 5289177Speter * or more contributor license agreements. See the NOTICE file 6289177Speter * distributed with this work for additional information 7289177Speter * regarding copyright ownership. The ASF licenses this file 8289177Speter * to you under the Apache License, Version 2.0 (the 9289177Speter * "License"); you may not use this file except in compliance 10289177Speter * with the License. You may obtain a copy of the License at 11289177Speter * 12289177Speter * http://www.apache.org/licenses/LICENSE-2.0 13289177Speter * 14289177Speter * Unless required by applicable law or agreed to in writing, 15289177Speter * software distributed under the License is distributed on an 16289177Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17289177Speter * KIND, either express or implied. See the License for the 18289177Speter * specific language governing permissions and limitations 19289177Speter * under the License. 20289177Speter * ==================================================================== 21289177Speter */ 22289177Speter 23289177Speter#include <assert.h> 24289177Speter 25289177Speter#include "svn_ctype.h" 26289177Speter#include "svn_dirent_uri.h" 27289177Speter#include "private/svn_string_private.h" 28289177Speter 29289177Speter#include "fs_fs.h" 30289177Speter#include "pack.h" 31289177Speter#include "util.h" 32289177Speter 33289177Speter#include "../libsvn_fs/fs-loader.h" 34289177Speter 35289177Speter#include "svn_private_config.h" 36289177Speter 37289177Spetersvn_boolean_t 38289177Spetersvn_fs_fs__is_packed_rev(svn_fs_t *fs, 39289177Speter svn_revnum_t rev) 40289177Speter{ 41289177Speter fs_fs_data_t *ffd = fs->fsap_data; 42289177Speter 43289177Speter return (rev < ffd->min_unpacked_rev); 44289177Speter} 45289177Speter 46289177Spetersvn_boolean_t 47289177Spetersvn_fs_fs__is_packed_revprop(svn_fs_t *fs, 48289177Speter svn_revnum_t rev) 49289177Speter{ 50289177Speter fs_fs_data_t *ffd = fs->fsap_data; 51289177Speter 52289177Speter /* rev 0 will not be packed */ 53289177Speter return (rev < ffd->min_unpacked_rev) 54289177Speter && (rev != 0) 55289177Speter && (ffd->format >= SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT); 56289177Speter} 57289177Speter 58289177Spetersvn_revnum_t 59289177Spetersvn_fs_fs__packed_base_rev(svn_fs_t *fs, 60289177Speter svn_revnum_t revision) 61289177Speter{ 62289177Speter fs_fs_data_t *ffd = fs->fsap_data; 63289177Speter return (revision < ffd->min_unpacked_rev) 64289177Speter ? (revision - (revision % ffd->max_files_per_dir)) 65289177Speter : revision; 66289177Speter} 67289177Speter 68289177Speterconst char * 69289177Spetersvn_fs_fs__path_txn_current(svn_fs_t *fs, 70289177Speter apr_pool_t *pool) 71289177Speter{ 72289177Speter return svn_dirent_join(fs->path, PATH_TXN_CURRENT, pool); 73289177Speter} 74289177Speter 75289177Speterconst char * 76289177Spetersvn_fs_fs__path_txn_current_lock(svn_fs_t *fs, 77289177Speter apr_pool_t *pool) 78289177Speter{ 79289177Speter return svn_dirent_join(fs->path, PATH_TXN_CURRENT_LOCK, pool); 80289177Speter} 81289177Speter 82289177Speterconst char * 83289177Spetersvn_fs_fs__path_lock(svn_fs_t *fs, 84289177Speter apr_pool_t *pool) 85289177Speter{ 86289177Speter return svn_dirent_join(fs->path, PATH_LOCK_FILE, pool); 87289177Speter} 88289177Speter 89289177Speterconst char * 90289177Spetersvn_fs_fs__path_pack_lock(svn_fs_t *fs, 91289177Speter apr_pool_t *pool) 92289177Speter{ 93289177Speter return svn_dirent_join(fs->path, PATH_PACK_LOCK_FILE, pool); 94289177Speter} 95289177Speter 96289177Speterconst char * 97289177Spetersvn_fs_fs__path_revprop_generation(svn_fs_t *fs, 98289177Speter apr_pool_t *pool) 99289177Speter{ 100289177Speter return svn_dirent_join(fs->path, PATH_REVPROP_GENERATION, pool); 101289177Speter} 102289177Speter 103289177Speterconst char * 104289177Spetersvn_fs_fs__path_rev_packed(svn_fs_t *fs, 105289177Speter svn_revnum_t rev, 106289177Speter const char *kind, 107289177Speter apr_pool_t *pool) 108289177Speter{ 109289177Speter fs_fs_data_t *ffd = fs->fsap_data; 110289177Speter 111289177Speter assert(ffd->max_files_per_dir); 112289177Speter assert(svn_fs_fs__is_packed_rev(fs, rev)); 113289177Speter 114289177Speter return svn_dirent_join_many(pool, fs->path, PATH_REVS_DIR, 115289177Speter apr_psprintf(pool, 116289177Speter "%ld" PATH_EXT_PACKED_SHARD, 117289177Speter rev / ffd->max_files_per_dir), 118289177Speter kind, SVN_VA_NULL); 119289177Speter} 120289177Speter 121289177Speterconst char * 122289177Spetersvn_fs_fs__path_rev_shard(svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool) 123289177Speter{ 124289177Speter fs_fs_data_t *ffd = fs->fsap_data; 125289177Speter 126289177Speter assert(ffd->max_files_per_dir); 127289177Speter return svn_dirent_join_many(pool, fs->path, PATH_REVS_DIR, 128289177Speter apr_psprintf(pool, "%ld", 129289177Speter rev / ffd->max_files_per_dir), 130289177Speter SVN_VA_NULL); 131289177Speter} 132289177Speter 133289177Speterconst char * 134289177Spetersvn_fs_fs__path_rev(svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool) 135289177Speter{ 136289177Speter fs_fs_data_t *ffd = fs->fsap_data; 137289177Speter 138289177Speter assert(! svn_fs_fs__is_packed_rev(fs, rev)); 139289177Speter 140289177Speter if (ffd->max_files_per_dir) 141289177Speter { 142289177Speter return svn_dirent_join(svn_fs_fs__path_rev_shard(fs, rev, pool), 143289177Speter apr_psprintf(pool, "%ld", rev), 144289177Speter pool); 145289177Speter } 146289177Speter 147289177Speter return svn_dirent_join_many(pool, fs->path, PATH_REVS_DIR, 148289177Speter apr_psprintf(pool, "%ld", rev), SVN_VA_NULL); 149289177Speter} 150289177Speter 151289177Speter/* Set *PATH to the path of REV in FS with PACKED selecting whether the 152289177Speter (potential) pack file or single revision file name is returned. 153289177Speter Allocate *PATH in POOL. 154289177Speter*/ 155289177Speterstatic const char * 156289177Speterpath_rev_absolute_internal(svn_fs_t *fs, 157289177Speter svn_revnum_t rev, 158289177Speter svn_boolean_t packed, 159289177Speter apr_pool_t *pool) 160289177Speter{ 161289177Speter return packed 162289177Speter ? svn_fs_fs__path_rev_packed(fs, rev, PATH_PACKED, pool) 163289177Speter : svn_fs_fs__path_rev(fs, rev, pool); 164289177Speter} 165289177Speter 166289177Speterconst char * 167289177Spetersvn_fs_fs__path_rev_absolute(svn_fs_t *fs, 168289177Speter svn_revnum_t rev, 169289177Speter apr_pool_t *pool) 170289177Speter{ 171289177Speter fs_fs_data_t *ffd = fs->fsap_data; 172289177Speter svn_boolean_t is_packed = ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT 173289177Speter && svn_fs_fs__is_packed_rev(fs, rev); 174289177Speter 175289177Speter return path_rev_absolute_internal(fs, rev, is_packed, pool); 176289177Speter} 177289177Speter 178289177Speterconst char * 179289177Spetersvn_fs_fs__path_revprops_shard(svn_fs_t *fs, 180289177Speter svn_revnum_t rev, 181289177Speter apr_pool_t *pool) 182289177Speter{ 183289177Speter fs_fs_data_t *ffd = fs->fsap_data; 184289177Speter 185289177Speter assert(ffd->max_files_per_dir); 186289177Speter return svn_dirent_join_many(pool, fs->path, PATH_REVPROPS_DIR, 187289177Speter apr_psprintf(pool, "%ld", 188289177Speter rev / ffd->max_files_per_dir), 189289177Speter SVN_VA_NULL); 190289177Speter} 191289177Speter 192289177Speterconst char * 193289177Spetersvn_fs_fs__path_revprops_pack_shard(svn_fs_t *fs, 194289177Speter svn_revnum_t rev, 195289177Speter apr_pool_t *pool) 196289177Speter{ 197289177Speter fs_fs_data_t *ffd = fs->fsap_data; 198289177Speter 199289177Speter assert(ffd->max_files_per_dir); 200289177Speter return svn_dirent_join_many(pool, fs->path, PATH_REVPROPS_DIR, 201289177Speter apr_psprintf(pool, "%ld" PATH_EXT_PACKED_SHARD, 202289177Speter rev / ffd->max_files_per_dir), 203289177Speter SVN_VA_NULL); 204289177Speter} 205289177Speter 206289177Speterconst char * 207289177Spetersvn_fs_fs__path_revprops(svn_fs_t *fs, 208289177Speter svn_revnum_t rev, 209289177Speter apr_pool_t *pool) 210289177Speter{ 211289177Speter fs_fs_data_t *ffd = fs->fsap_data; 212289177Speter 213289177Speter if (ffd->max_files_per_dir) 214289177Speter { 215289177Speter return svn_dirent_join(svn_fs_fs__path_revprops_shard(fs, rev, pool), 216289177Speter apr_psprintf(pool, "%ld", rev), 217289177Speter pool); 218289177Speter } 219289177Speter 220289177Speter return svn_dirent_join_many(pool, fs->path, PATH_REVPROPS_DIR, 221289177Speter apr_psprintf(pool, "%ld", rev), SVN_VA_NULL); 222289177Speter} 223289177Speter 224289177Speter/* Return TO_ADD appended to the C string representation of TXN_ID. 225289177Speter * Allocate the result in POOL. 226289177Speter */ 227289177Speterstatic const char * 228289177Spetercombine_txn_id_string(const svn_fs_fs__id_part_t *txn_id, 229289177Speter const char *to_add, 230289177Speter apr_pool_t *pool) 231289177Speter{ 232289177Speter return apr_pstrcat(pool, svn_fs_fs__id_txn_unparse(txn_id, pool), 233289177Speter to_add, SVN_VA_NULL); 234289177Speter} 235289177Speter 236289177Speterconst char * 237289177Spetersvn_fs_fs__path_txns_dir(svn_fs_t *fs, 238289177Speter apr_pool_t *pool) 239289177Speter{ 240289177Speter return svn_dirent_join(fs->path, PATH_TXNS_DIR, pool); 241289177Speter} 242289177Speter 243289177Speterconst char * 244289177Spetersvn_fs_fs__path_txn_dir(svn_fs_t *fs, 245289177Speter const svn_fs_fs__id_part_t *txn_id, 246289177Speter apr_pool_t *pool) 247289177Speter{ 248289177Speter SVN_ERR_ASSERT_NO_RETURN(txn_id != NULL); 249289177Speter return svn_dirent_join(svn_fs_fs__path_txns_dir(fs, pool), 250289177Speter combine_txn_id_string(txn_id, PATH_EXT_TXN, pool), 251289177Speter pool); 252289177Speter} 253289177Speter 254289177Speterconst char* 255289177Spetersvn_fs_fs__path_l2p_proto_index(svn_fs_t *fs, 256289177Speter const svn_fs_fs__id_part_t *txn_id, 257289177Speter apr_pool_t *pool) 258289177Speter{ 259289177Speter return svn_dirent_join(svn_fs_fs__path_txn_dir(fs, txn_id, pool), 260289177Speter PATH_INDEX PATH_EXT_L2P_INDEX, pool); 261289177Speter} 262289177Speter 263289177Speterconst char* 264289177Spetersvn_fs_fs__path_p2l_proto_index(svn_fs_t *fs, 265289177Speter const svn_fs_fs__id_part_t *txn_id, 266289177Speter apr_pool_t *pool) 267289177Speter{ 268289177Speter return svn_dirent_join(svn_fs_fs__path_txn_dir(fs, txn_id, pool), 269289177Speter PATH_INDEX PATH_EXT_P2L_INDEX, pool); 270289177Speter} 271289177Speter 272289177Speterconst char * 273289177Spetersvn_fs_fs__path_txn_item_index(svn_fs_t *fs, 274289177Speter const svn_fs_fs__id_part_t *txn_id, 275289177Speter apr_pool_t *pool) 276289177Speter{ 277289177Speter return svn_dirent_join(svn_fs_fs__path_txn_dir(fs, txn_id, pool), 278289177Speter PATH_TXN_ITEM_INDEX, pool); 279289177Speter} 280289177Speter 281289177Speterconst char * 282289177Spetersvn_fs_fs__path_txn_proto_revs(svn_fs_t *fs, 283289177Speter apr_pool_t *pool) 284289177Speter{ 285289177Speter return svn_dirent_join(fs->path, PATH_TXN_PROTOS_DIR, pool); 286289177Speter} 287289177Speter 288289177Speterconst char * 289289177Spetersvn_fs_fs__path_txn_proto_rev(svn_fs_t *fs, 290289177Speter const svn_fs_fs__id_part_t *txn_id, 291289177Speter apr_pool_t *pool) 292289177Speter{ 293289177Speter fs_fs_data_t *ffd = fs->fsap_data; 294289177Speter if (ffd->format >= SVN_FS_FS__MIN_PROTOREVS_DIR_FORMAT) 295289177Speter return svn_dirent_join(svn_fs_fs__path_txn_proto_revs(fs, pool), 296289177Speter combine_txn_id_string(txn_id, PATH_EXT_REV, pool), 297289177Speter pool); 298289177Speter else 299289177Speter return svn_dirent_join(svn_fs_fs__path_txn_dir(fs, txn_id, pool), 300289177Speter PATH_REV, pool); 301289177Speter} 302289177Speter 303289177Speter 304289177Speterconst char * 305289177Spetersvn_fs_fs__path_txn_proto_rev_lock(svn_fs_t *fs, 306289177Speter const svn_fs_fs__id_part_t *txn_id, 307289177Speter apr_pool_t *pool) 308289177Speter{ 309289177Speter fs_fs_data_t *ffd = fs->fsap_data; 310289177Speter if (ffd->format >= SVN_FS_FS__MIN_PROTOREVS_DIR_FORMAT) 311289177Speter return svn_dirent_join(svn_fs_fs__path_txn_proto_revs(fs, pool), 312289177Speter combine_txn_id_string(txn_id, PATH_EXT_REV_LOCK, 313289177Speter pool), 314289177Speter pool); 315289177Speter else 316289177Speter return svn_dirent_join(svn_fs_fs__path_txn_dir(fs, txn_id, pool), 317289177Speter PATH_REV_LOCK, pool); 318289177Speter} 319289177Speter 320289177Speterconst char * 321289177Spetersvn_fs_fs__path_txn_node_rev(svn_fs_t *fs, 322289177Speter const svn_fs_id_t *id, 323289177Speter apr_pool_t *pool) 324289177Speter{ 325289177Speter char *filename = (char *)svn_fs_fs__id_unparse(id, pool)->data; 326289177Speter *strrchr(filename, '.') = '\0'; 327289177Speter 328289177Speter return svn_dirent_join(svn_fs_fs__path_txn_dir(fs, svn_fs_fs__id_txn_id(id), 329289177Speter pool), 330289177Speter apr_psprintf(pool, PATH_PREFIX_NODE "%s", 331289177Speter filename), 332289177Speter pool); 333289177Speter} 334289177Speter 335289177Speterconst char * 336289177Spetersvn_fs_fs__path_txn_node_props(svn_fs_t *fs, 337289177Speter const svn_fs_id_t *id, 338289177Speter apr_pool_t *pool) 339289177Speter{ 340289177Speter return apr_pstrcat(pool, svn_fs_fs__path_txn_node_rev(fs, id, pool), 341289177Speter PATH_EXT_PROPS, SVN_VA_NULL); 342289177Speter} 343289177Speter 344289177Speterconst char * 345289177Spetersvn_fs_fs__path_txn_node_children(svn_fs_t *fs, 346289177Speter const svn_fs_id_t *id, 347289177Speter apr_pool_t *pool) 348289177Speter{ 349289177Speter return apr_pstrcat(pool, svn_fs_fs__path_txn_node_rev(fs, id, pool), 350289177Speter PATH_EXT_CHILDREN, SVN_VA_NULL); 351289177Speter} 352289177Speter 353289177Speterconst char * 354289177Spetersvn_fs_fs__path_node_origin(svn_fs_t *fs, 355289177Speter const svn_fs_fs__id_part_t *node_id, 356289177Speter apr_pool_t *pool) 357289177Speter{ 358289177Speter char buffer[SVN_INT64_BUFFER_SIZE]; 359289177Speter apr_size_t len = svn__ui64tobase36(buffer, node_id->number); 360289177Speter 361289177Speter if (len > 1) 362289177Speter buffer[len - 1] = '\0'; 363289177Speter 364289177Speter return svn_dirent_join_many(pool, fs->path, PATH_NODE_ORIGINS_DIR, 365289177Speter buffer, SVN_VA_NULL); 366289177Speter} 367289177Speter 368289177Speterconst char * 369289177Spetersvn_fs_fs__path_min_unpacked_rev(svn_fs_t *fs, 370289177Speter apr_pool_t *pool) 371289177Speter{ 372289177Speter return svn_dirent_join(fs->path, PATH_MIN_UNPACKED_REV, pool); 373289177Speter} 374289177Speter 375289177Spetersvn_error_t * 376289177Spetersvn_fs_fs__check_file_buffer_numeric(const char *buf, 377289177Speter apr_off_t offset, 378289177Speter const char *path, 379289177Speter const char *title, 380289177Speter apr_pool_t *pool) 381289177Speter{ 382289177Speter const char *p; 383289177Speter 384289177Speter for (p = buf + offset; *p; p++) 385289177Speter if (!svn_ctype_isdigit(*p)) 386289177Speter return svn_error_createf(SVN_ERR_BAD_VERSION_FILE_FORMAT, NULL, 387289177Speter _("%s file '%s' contains unexpected non-digit '%c' within '%s'"), 388289177Speter title, svn_dirent_local_style(path, pool), *p, buf); 389289177Speter 390289177Speter return SVN_NO_ERROR; 391289177Speter} 392289177Speter 393289177Spetersvn_error_t * 394289177Spetersvn_fs_fs__read_min_unpacked_rev(svn_revnum_t *min_unpacked_rev, 395289177Speter svn_fs_t *fs, 396289177Speter apr_pool_t *pool) 397289177Speter{ 398289177Speter char buf[80]; 399289177Speter apr_file_t *file; 400289177Speter apr_size_t len; 401289177Speter 402289177Speter SVN_ERR(svn_io_file_open(&file, 403289177Speter svn_fs_fs__path_min_unpacked_rev(fs, pool), 404289177Speter APR_READ | APR_BUFFERED, 405289177Speter APR_OS_DEFAULT, 406289177Speter pool)); 407289177Speter len = sizeof(buf); 408289177Speter SVN_ERR(svn_io_read_length_line(file, buf, &len, pool)); 409289177Speter SVN_ERR(svn_io_file_close(file, pool)); 410289177Speter 411289177Speter SVN_ERR(svn_revnum_parse(min_unpacked_rev, buf, NULL)); 412289177Speter return SVN_NO_ERROR; 413289177Speter} 414289177Speter 415289177Spetersvn_error_t * 416289177Spetersvn_fs_fs__update_min_unpacked_rev(svn_fs_t *fs, 417289177Speter apr_pool_t *pool) 418289177Speter{ 419289177Speter fs_fs_data_t *ffd = fs->fsap_data; 420289177Speter 421289177Speter SVN_ERR_ASSERT(ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT); 422289177Speter 423289177Speter return svn_fs_fs__read_min_unpacked_rev(&ffd->min_unpacked_rev, fs, pool); 424289177Speter} 425289177Speter 426289177Spetersvn_error_t * 427289177Spetersvn_fs_fs__write_min_unpacked_rev(svn_fs_t *fs, 428289177Speter svn_revnum_t revnum, 429289177Speter apr_pool_t *scratch_pool) 430289177Speter{ 431362181Sdim fs_fs_data_t *ffd = fs->fsap_data; 432289177Speter const char *final_path; 433289177Speter char buf[SVN_INT64_BUFFER_SIZE]; 434289177Speter apr_size_t len = svn__i64toa(buf, revnum); 435289177Speter buf[len] = '\n'; 436289177Speter 437289177Speter final_path = svn_fs_fs__path_min_unpacked_rev(fs, scratch_pool); 438289177Speter 439362181Sdim SVN_ERR(svn_io_write_atomic2(final_path, buf, len + 1, 440362181Sdim final_path /* copy_perms */, 441362181Sdim ffd->flush_to_disk, scratch_pool)); 442289177Speter 443289177Speter return SVN_NO_ERROR; 444289177Speter} 445289177Speter 446289177Spetersvn_error_t * 447289177Spetersvn_fs_fs__read_current(svn_revnum_t *rev, 448289177Speter apr_uint64_t *next_node_id, 449289177Speter apr_uint64_t *next_copy_id, 450289177Speter svn_fs_t *fs, 451289177Speter apr_pool_t *pool) 452289177Speter{ 453289177Speter fs_fs_data_t *ffd = fs->fsap_data; 454289177Speter svn_stringbuf_t *content; 455289177Speter 456289177Speter SVN_ERR(svn_fs_fs__read_content(&content, 457289177Speter svn_fs_fs__path_current(fs, pool), 458289177Speter pool)); 459289177Speter 460289177Speter if (ffd->format >= SVN_FS_FS__MIN_NO_GLOBAL_IDS_FORMAT) 461289177Speter { 462289177Speter /* When format 1 and 2 filesystems are upgraded, the 'current' file is 463289177Speter left intact. As a consequence, there is a window when a filesystem 464289177Speter has a new format, but this file still contains the IDs left from an 465289177Speter old format, i.e. looks like "359 j5 v\n". Do not be too strict here 466289177Speter and only expect a parseable revision number. */ 467289177Speter SVN_ERR(svn_revnum_parse(rev, content->data, NULL)); 468289177Speter 469289177Speter *next_node_id = 0; 470289177Speter *next_copy_id = 0; 471289177Speter } 472289177Speter else 473289177Speter { 474289177Speter const char *str; 475289177Speter 476289177Speter SVN_ERR(svn_revnum_parse(rev, content->data, &str)); 477289177Speter if (*str != ' ') 478289177Speter return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, 479289177Speter _("Corrupt 'current' file")); 480289177Speter 481289177Speter *next_node_id = svn__base36toui64(&str, str + 1); 482289177Speter if (*str != ' ') 483289177Speter return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, 484289177Speter _("Corrupt 'current' file")); 485289177Speter 486289177Speter *next_copy_id = svn__base36toui64(&str, str + 1); 487289177Speter if (*str != '\n') 488289177Speter return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, 489289177Speter _("Corrupt 'current' file")); 490289177Speter } 491289177Speter 492289177Speter return SVN_NO_ERROR; 493289177Speter} 494289177Speter 495289177Spetersvn_error_t * 496289177Spetersvn_fs_fs__write_current(svn_fs_t *fs, 497289177Speter svn_revnum_t rev, 498289177Speter apr_uint64_t next_node_id, 499289177Speter apr_uint64_t next_copy_id, 500289177Speter apr_pool_t *pool) 501289177Speter{ 502289177Speter char *buf; 503289177Speter const char *name; 504289177Speter fs_fs_data_t *ffd = fs->fsap_data; 505289177Speter 506289177Speter /* Now we can just write out this line. */ 507289177Speter if (ffd->format >= SVN_FS_FS__MIN_NO_GLOBAL_IDS_FORMAT) 508289177Speter { 509289177Speter buf = apr_psprintf(pool, "%ld\n", rev); 510289177Speter } 511289177Speter else 512289177Speter { 513289177Speter char node_id_str[SVN_INT64_BUFFER_SIZE]; 514289177Speter char copy_id_str[SVN_INT64_BUFFER_SIZE]; 515289177Speter svn__ui64tobase36(node_id_str, next_node_id); 516289177Speter svn__ui64tobase36(copy_id_str, next_copy_id); 517289177Speter 518289177Speter buf = apr_psprintf(pool, "%ld %s %s\n", rev, node_id_str, copy_id_str); 519289177Speter } 520289177Speter 521289177Speter name = svn_fs_fs__path_current(fs, pool); 522362181Sdim SVN_ERR(svn_io_write_atomic2(name, buf, strlen(buf), 523362181Sdim name /* copy_perms_path */, 524362181Sdim ffd->flush_to_disk, pool)); 525289177Speter 526289177Speter return SVN_NO_ERROR; 527289177Speter} 528289177Speter 529289177Spetersvn_error_t * 530289177Spetersvn_fs_fs__try_stringbuf_from_file(svn_stringbuf_t **content, 531289177Speter svn_boolean_t *missing, 532289177Speter const char *path, 533289177Speter svn_boolean_t last_attempt, 534289177Speter apr_pool_t *pool) 535289177Speter{ 536289177Speter svn_error_t *err = svn_stringbuf_from_file2(content, path, pool); 537289177Speter if (missing) 538289177Speter *missing = FALSE; 539289177Speter 540289177Speter if (err) 541289177Speter { 542289177Speter *content = NULL; 543289177Speter 544289177Speter if (APR_STATUS_IS_ENOENT(err->apr_err)) 545289177Speter { 546289177Speter if (!last_attempt) 547289177Speter { 548289177Speter svn_error_clear(err); 549289177Speter if (missing) 550289177Speter *missing = TRUE; 551289177Speter return SVN_NO_ERROR; 552289177Speter } 553289177Speter } 554289177Speter#ifdef ESTALE 555289177Speter else if (APR_TO_OS_ERROR(err->apr_err) == ESTALE 556289177Speter || APR_TO_OS_ERROR(err->apr_err) == EIO) 557289177Speter { 558289177Speter if (!last_attempt) 559289177Speter { 560289177Speter svn_error_clear(err); 561289177Speter return SVN_NO_ERROR; 562289177Speter } 563289177Speter } 564289177Speter#endif 565289177Speter } 566289177Speter 567289177Speter return svn_error_trace(err); 568289177Speter} 569289177Speter 570289177Spetersvn_error_t * 571289177Spetersvn_fs_fs__read_content(svn_stringbuf_t **content, 572289177Speter const char *fname, 573289177Speter apr_pool_t *pool) 574289177Speter{ 575289177Speter int i; 576289177Speter *content = NULL; 577289177Speter 578289177Speter for (i = 0; !*content && (i < SVN_FS_FS__RECOVERABLE_RETRY_COUNT); ++i) 579289177Speter SVN_ERR(svn_fs_fs__try_stringbuf_from_file(content, NULL, 580289177Speter fname, i + 1 < SVN_FS_FS__RECOVERABLE_RETRY_COUNT, 581289177Speter pool)); 582289177Speter 583289177Speter if (!*content) 584289177Speter return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, 585289177Speter _("Can't read '%s'"), 586289177Speter svn_dirent_local_style(fname, pool)); 587289177Speter 588289177Speter return SVN_NO_ERROR; 589289177Speter} 590289177Speter 591289177Spetersvn_error_t * 592289177Spetersvn_fs_fs__read_number_from_stream(apr_int64_t *result, 593289177Speter svn_boolean_t *hit_eof, 594289177Speter svn_stream_t *stream, 595289177Speter apr_pool_t *scratch_pool) 596289177Speter{ 597289177Speter svn_stringbuf_t *sb; 598289177Speter svn_boolean_t eof; 599289177Speter svn_error_t *err; 600289177Speter 601289177Speter SVN_ERR(svn_stream_readline(stream, &sb, "\n", &eof, scratch_pool)); 602289177Speter if (hit_eof) 603289177Speter *hit_eof = eof; 604289177Speter else 605289177Speter if (eof) 606289177Speter return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Unexpected EOF")); 607289177Speter 608289177Speter if (!eof) 609289177Speter { 610289177Speter err = svn_cstring_atoi64(result, sb->data); 611289177Speter if (err) 612289177Speter return svn_error_createf(SVN_ERR_FS_CORRUPT, err, 613289177Speter _("Number '%s' invalid or too large"), 614289177Speter sb->data); 615289177Speter } 616289177Speter 617289177Speter return SVN_NO_ERROR; 618289177Speter} 619289177Speter 620289177Spetersvn_error_t * 621289177Spetersvn_fs_fs__move_into_place(const char *old_filename, 622289177Speter const char *new_filename, 623289177Speter const char *perms_reference, 624362181Sdim svn_boolean_t flush_to_disk, 625289177Speter apr_pool_t *pool) 626289177Speter{ 627289177Speter svn_error_t *err; 628362181Sdim apr_file_t *file; 629289177Speter 630362181Sdim /* Copying permissions is a no-op on WIN32. */ 631289177Speter SVN_ERR(svn_io_copy_perms(perms_reference, old_filename, pool)); 632289177Speter 633289177Speter /* Move the file into place. */ 634362181Sdim err = svn_io_file_rename2(old_filename, new_filename, flush_to_disk, pool); 635289177Speter if (err && APR_STATUS_IS_EXDEV(err->apr_err)) 636289177Speter { 637289177Speter /* Can't rename across devices; fall back to copying. */ 638289177Speter svn_error_clear(err); 639289177Speter SVN_ERR(svn_io_copy_file(old_filename, new_filename, TRUE, pool)); 640289177Speter 641362181Sdim /* Flush the target of the copy to disk. 642362181Sdim ### The code below is duplicates svn_io_file_rename2(), because 643362181Sdim currently we don't have the svn_io_copy_file2() function with 644362181Sdim a flush_to_disk argument. */ 645362181Sdim if (flush_to_disk) 646362181Sdim { 647362181Sdim SVN_ERR(svn_io_file_open(&file, new_filename, APR_WRITE, 648362181Sdim APR_OS_DEFAULT, pool)); 649362181Sdim SVN_ERR(svn_io_file_flush_to_disk(file, pool)); 650362181Sdim SVN_ERR(svn_io_file_close(file, pool)); 651362181Sdim } 652289177Speter 653362181Sdim#ifdef SVN_ON_POSIX 654362181Sdim if (flush_to_disk) 655362181Sdim { 656362181Sdim /* On POSIX, the file name is stored in the file's directory entry. 657362181Sdim Hence, we need to fsync() that directory as well. 658362181Sdim On other operating systems, we'd only be asking for trouble 659362181Sdim by trying to open and fsync a directory. */ 660362181Sdim const char *dirname; 661289177Speter 662362181Sdim dirname = svn_dirent_dirname(new_filename, pool); 663362181Sdim SVN_ERR(svn_io_file_open(&file, dirname, APR_READ, APR_OS_DEFAULT, 664362181Sdim pool)); 665362181Sdim SVN_ERR(svn_io_file_flush_to_disk(file, pool)); 666362181Sdim SVN_ERR(svn_io_file_close(file, pool)); 667362181Sdim } 668289177Speter#endif 669362181Sdim } 670362181Sdim else if (err) 671362181Sdim return svn_error_trace(err); 672289177Speter 673289177Speter return SVN_NO_ERROR; 674289177Speter} 675289177Speter 676289177Spetersvn_boolean_t 677289177Spetersvn_fs_fs__use_log_addressing(svn_fs_t *fs) 678289177Speter{ 679289177Speter fs_fs_data_t *ffd = fs->fsap_data; 680289177Speter return ffd->use_log_addressing; 681289177Speter} 682