util.c revision 299742
140496Sbde/* util.c --- utility functions for FSFS repo access 250473Speter * 31539Srgrimes * ==================================================================== 4114731Sbde * Licensed to the Apache Software Foundation (ASF) under one 51539Srgrimes * or more contributor license agreements. See the NOTICE file 6156813Sru * distributed with this work for additional information 7156813Sru * regarding copyright ownership. The ASF licenses this file 818420Sbde * to you under the Apache License, Version 2.0 (the 9232498Stheraven * "License"); you may not use this file except in compliance 10133567Stjr * with the License. You may obtain a copy of the License at 11133559Stjr * 12107046Smarcel * http://www.apache.org/licenses/LICENSE-2.0 13153838Sdfr * 14220370Sobrien * Unless required by applicable law or agreed to in writing, 15107046Smarcel * software distributed under the License is distributed on an 16157236Sjasone * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 17152994Sru * KIND, either express or implied. See the License for the 18166243Speter * specific language governing permissions and limitations 19153486Sphk * under the License. 20205146Sed * ==================================================================== 21201546Sdavidxu */ 22251230Sed 23228879Sed#include <assert.h> 24199898Sed 25133333Sstefanf#include "svn_ctype.h" 26250883Sed#include "svn_dirent_uri.h" 27232498Stheraven#include "private/svn_string_private.h" 281539Srgrimes 29244401Sbrooks#include "fs_fs.h" 30244401Sbrooks#include "pack.h" 31244401Sbrooks#include "util.h" 32119630Skan 3334030Sdufault#include "../libsvn_fs/fs-loader.h" 34201546Sdavidxu 3534030Sdufault#include "svn_private_config.h" 36251230Sed 37251230Sedsvn_boolean_t 381539Srgrimessvn_fs_fs__is_packed_rev(svn_fs_t *fs, 39171453Srwatson svn_revnum_t rev) 40252356Sdavide{ 41156905Sru fs_fs_data_t *ffd = fs->fsap_data; 42188642Snyan 4317900Speter return (rev < ffd->min_unpacked_rev); 44195534Sscottl} 45246367Sjhb 46246367Sjhbsvn_boolean_t 47240621Sjimharrissvn_fs_fs__is_packed_revprop(svn_fs_t *fs, 48246367Sjhb svn_revnum_t rev) 49172397Sru{ 50241636Sattilio fs_fs_data_t *ffd = fs->fsap_data; 51252356Sdavide 52163851Spjd /* rev 0 will not be packed */ 53202437Strasz return (rev < ffd->min_unpacked_rev) 54219974Smav && (rev != 0) 55135339Sglebius && (ffd->format >= SVN_FS_FS__MIN_PACKED_REVPROP_FORMAT); 56156885Srwatson} 57135339Sglebius 58135339Sglebiussvn_revnum_t 59137556Smarkmsvn_fs_fs__packed_base_rev(svn_fs_t *fs, 6077031Sru svn_revnum_t revision) 61192901Sthompsa{ 62178818Sjhb fs_fs_data_t *ffd = fs->fsap_data; 63210024Snwhitehorn return (revision < ffd->min_unpacked_rev) 64160892Ssobomax ? (revision - (revision % ffd->max_files_per_dir)) 65160892Ssobomax : revision; 66160892Ssobomax} 67156813Sru 68141397Sphkconst char * 69141397Sphksvn_fs_fs__path_txn_current(svn_fs_t *fs, 70141397Sphk apr_pool_t *pool) 71156813Sru{ 72148796Sphk return svn_dirent_join(fs->path, PATH_TXN_CURRENT, pool); 73148796Sphk} 74148796Sphk 75156813Sruconst char * 76178818Sjhbsvn_fs_fs__path_txn_current_lock(svn_fs_t *fs, 77125123Semax apr_pool_t *pool) 78107139Sjulian{ 79252356Sdavide return svn_dirent_join(fs->path, PATH_TXN_CURRENT_LOCK, pool); 80156905Sru} 81156905Sru 82156905Sruconst char * 83156905Srusvn_fs_fs__path_lock(svn_fs_t *fs, 84254273Speter apr_pool_t *pool) 85254273Speter{ 86254273Speter return svn_dirent_join(fs->path, PATH_LOCK_FILE, pool); 87254273Speter} 88254273Speter 89254273Speterconst char * 90254273Spetersvn_fs_fs__path_pack_lock(svn_fs_t *fs, 91254273Speter apr_pool_t *pool) 92254273Speter{ 93254273Speter return svn_dirent_join(fs->path, PATH_PACK_LOCK_FILE, pool); 94254273Speter} 95254273Speter 96254273Speterconst char * 97254273Spetersvn_fs_fs__path_revprop_generation(svn_fs_t *fs, 9854351Smarcel apr_pool_t *pool) 9954351Smarcel{ 10054351Smarcel return svn_dirent_join(fs->path, PATH_REVPROP_GENERATION, pool); 10154351Smarcel} 10254351Smarcel 10354351Smarcelconst char * 10454351Smarcelsvn_fs_fs__path_rev_packed(svn_fs_t *fs, 10596462Sru svn_revnum_t rev, 10625734Speter const char *kind, 107255775Sian apr_pool_t *pool) 108255775Sian{ 109255775Sian fs_fs_data_t *ffd = fs->fsap_data; 11025734Speter 111255775Sian assert(ffd->max_files_per_dir); 112255775Sian assert(svn_fs_fs__is_packed_rev(fs, rev)); 113255775Sian 114255775Sian return svn_dirent_join_many(pool, fs->path, PATH_REVS_DIR, 115255775Sian apr_psprintf(pool, 116255807Sian "%ld" PATH_EXT_PACKED_SHARD, 117255775Sian rev / ffd->max_files_per_dir), 11888055Sru kind, SVN_VA_NULL); 11996462Sru} 12017900Speter 12188055Sruconst char * 12296462Srusvn_fs_fs__path_rev_shard(svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool) 12317900Speter{ 12488055Sru fs_fs_data_t *ffd = fs->fsap_data; 125164184Strhodes 12634030Sdufault assert(ffd->max_files_per_dir); 12754351Smarcel return svn_dirent_join_many(pool, fs->path, PATH_REVS_DIR, 128211725Simp apr_psprintf(pool, "%ld", 129214629Sjhb rev / ffd->max_files_per_dir), 130144514Simp SVN_VA_NULL); 131214629Sjhb} 132214629Sjhb 133214629Sjhbconst char * 134144514Simpsvn_fs_fs__path_rev(svn_fs_t *fs, svn_revnum_t rev, apr_pool_t *pool) 135114731Sbde{ 136114731Sbde fs_fs_data_t *ffd = fs->fsap_data; 137114731Sbde 138114731Sbde assert(! svn_fs_fs__is_packed_rev(fs, rev)); 139114731Sbde 140114731Sbde if (ffd->max_files_per_dir) 141114731Sbde { 142214629Sjhb return svn_dirent_join(svn_fs_fs__path_rev_shard(fs, rev, pool), 143114731Sbde apr_psprintf(pool, "%ld", rev), 144114731Sbde pool); 14554351Smarcel } 14654351Smarcel 147114731Sbde return svn_dirent_join_many(pool, fs->path, PATH_REVS_DIR, 148114731Sbde apr_psprintf(pool, "%ld", rev), SVN_VA_NULL); 149114731Sbde} 150156813Sru 151135851Sdougb/* Set *PATH to the path of REV in FS with PACKED selecting whether the 152135851Sdougb (potential) pack file or single revision file name is returned. 153135851Sdougb Allocate *PATH in POOL. 154135851Sdougb*/ 155114731Sbdestatic const char * 156114731Sbdepath_rev_absolute_internal(svn_fs_t *fs, 157144514Simp svn_revnum_t rev, 158214629Sjhb svn_boolean_t packed, 159114731Sbde apr_pool_t *pool) 160114731Sbde{ 161114731Sbde return packed 162114731Sbde ? svn_fs_fs__path_rev_packed(fs, rev, PATH_PACKED, pool) 163114731Sbde : svn_fs_fs__path_rev(fs, rev, pool); 164114731Sbde} 165114731Sbde 166246367Sjhbconst char * 16754351Smarcelsvn_fs_fs__path_rev_absolute(svn_fs_t *fs, 168114731Sbde svn_revnum_t rev, 169114731Sbde apr_pool_t *pool) 17054351Smarcel{ 171143013Snjl fs_fs_data_t *ffd = fs->fsap_data; 172143013Snjl svn_boolean_t is_packed = ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT 173143013Snjl && svn_fs_fs__is_packed_rev(fs, rev); 174246367Sjhb 175246367Sjhb return path_rev_absolute_internal(fs, rev, is_packed, pool); 176246367Sjhb} 177123288Sobrien 178123288Sobrienconst char * 179123288Sobriensvn_fs_fs__path_revprops_shard(svn_fs_t *fs, 180235537Sgber svn_revnum_t rev, 181235537Sgber apr_pool_t *pool) 182235537Sgber{ 183235537Sgber fs_fs_data_t *ffd = fs->fsap_data; 184235537Sgber 185235537Sgber assert(ffd->max_files_per_dir); 186235537Sgber return svn_dirent_join_many(pool, fs->path, PATH_REVPROPS_DIR, 187246367Sjhb apr_psprintf(pool, "%ld", 188246367Sjhb rev / ffd->max_files_per_dir), 189246367Sjhb SVN_VA_NULL); 190130416Smlaier} 191130416Smlaier 192130416Smlaierconst char * 193166640Srodrigcsvn_fs_fs__path_revprops_pack_shard(svn_fs_t *fs, 194166640Srodrigc svn_revnum_t rev, 195166640Srodrigc apr_pool_t *pool) 196156813Sru{ 197116734Sru fs_fs_data_t *ffd = fs->fsap_data; 198116734Sru 199116734Sru assert(ffd->max_files_per_dir); 200145539Sscottl return svn_dirent_join_many(pool, fs->path, PATH_REVPROPS_DIR, 201143423Sume apr_psprintf(pool, "%ld" PATH_EXT_PACKED_SHARD, 202143423Sume rev / ffd->max_files_per_dir), 203143423Sume SVN_VA_NULL); 204116734Sru} 205116734Sru 206114731Sbdeconst char * 207144514Simpsvn_fs_fs__path_revprops(svn_fs_t *fs, 208114731Sbde svn_revnum_t rev, 209114731Sbde apr_pool_t *pool) 210144514Simp{ 211144514Simp fs_fs_data_t *ffd = fs->fsap_data; 212114731Sbde 213114731Sbde if (ffd->max_files_per_dir) 21477857Sjlemon { 215214629Sjhb return svn_dirent_join(svn_fs_fs__path_revprops_shard(fs, rev, pool), 216214629Sjhb apr_psprintf(pool, "%ld", rev), 217144561Simp pool); 218144561Simp } 219144514Simp 220144514Simp return svn_dirent_join_many(pool, fs->path, PATH_REVPROPS_DIR, 221144514Simp apr_psprintf(pool, "%ld", rev), SVN_VA_NULL); 222144514Simp} 223144561Simp 224144561Simp/* Return TO_ADD appended to the C string representation of TXN_ID. 225144514Simp * Allocate the result in POOL. 226144514Simp */ 227144514Simpstatic const char * 228144514Simpcombine_txn_id_string(const svn_fs_fs__id_part_t *txn_id, 229144514Simp const char *to_add, 230214629Sjhb apr_pool_t *pool) 231168677Spjd{ 232168677Spjd return apr_pstrcat(pool, svn_fs_fs__id_txn_unparse(txn_id, pool), 233168677Spjd to_add, SVN_VA_NULL); 2341539Srgrimes} 23554351Smarcel 23654351Smarcelconst char * 23756645Spetersvn_fs_fs__path_txns_dir(svn_fs_t *fs, 238114731Sbde apr_pool_t *pool) 239114731Sbde{ 240114731Sbde return svn_dirent_join(fs->path, PATH_TXNS_DIR, pool); 241114731Sbde} 24254351Smarcel 243246367Sjhbconst char * 244114731Sbdesvn_fs_fs__path_txn_dir(svn_fs_t *fs, 245114731Sbde const svn_fs_fs__id_part_t *txn_id, 246114731Sbde apr_pool_t *pool) 247114731Sbde{ 24877046Sru SVN_ERR_ASSERT_NO_RETURN(txn_id != NULL); 249143013Snjl return svn_dirent_join(svn_fs_fs__path_txns_dir(fs, pool), 250143013Snjl combine_txn_id_string(txn_id, PATH_EXT_TXN, pool), 251143013Snjl pool); 252143013Snjl} 253143013Snjl 254246367Sjhbconst char* 255246367Sjhbsvn_fs_fs__path_l2p_proto_index(svn_fs_t *fs, 256246367Sjhb const svn_fs_fs__id_part_t *txn_id, 257246367Sjhb apr_pool_t *pool) 258246367Sjhb{ 259142992Sru return svn_dirent_join(svn_fs_fs__path_txn_dir(fs, txn_id, pool), 260142992Sru PATH_INDEX PATH_EXT_L2P_INDEX, pool); 261142992Sru} 262142992Sru 263142992Sruconst char* 264235537Sgbersvn_fs_fs__path_p2l_proto_index(svn_fs_t *fs, 265235537Sgber const svn_fs_fs__id_part_t *txn_id, 266235537Sgber apr_pool_t *pool) 267235537Sgber{ 268235537Sgber return svn_dirent_join(svn_fs_fs__path_txn_dir(fs, txn_id, pool), 269235537Sgber PATH_INDEX PATH_EXT_P2L_INDEX, pool); 270235537Sgber} 271246367Sjhb 272246367Sjhbconst char * 273246367Sjhbsvn_fs_fs__path_txn_item_index(svn_fs_t *fs, 274246367Sjhb const svn_fs_fs__id_part_t *txn_id, 275246367Sjhb apr_pool_t *pool) 276114731Sbde{ 277114731Sbde return svn_dirent_join(svn_fs_fs__path_txn_dir(fs, txn_id, pool), 278114731Sbde PATH_TXN_ITEM_INDEX, pool); 279114731Sbde} 280114731Sbde 281114731Sbdeconst char * 282130416Smlaiersvn_fs_fs__path_txn_proto_revs(svn_fs_t *fs, 283130416Smlaier apr_pool_t *pool) 284130416Smlaier{ 285130416Smlaier return svn_dirent_join(fs->path, PATH_TXN_PROTOS_DIR, pool); 286130416Smlaier} 287156813Sru 288116734Sruconst char * 289116734Srusvn_fs_fs__path_txn_proto_rev(svn_fs_t *fs, 290116734Sru const svn_fs_fs__id_part_t *txn_id, 291116734Sru apr_pool_t *pool) 292116734Sru{ 293145539Sscottl fs_fs_data_t *ffd = fs->fsap_data; 294143423Sume if (ffd->format >= SVN_FS_FS__MIN_PROTOREVS_DIR_FORMAT) 295143423Sume return svn_dirent_join(svn_fs_fs__path_txn_proto_revs(fs, pool), 296143423Sume combine_txn_id_string(txn_id, PATH_EXT_REV, pool), 297143423Sume pool); 298143423Sume else 299114731Sbde return svn_dirent_join(svn_fs_fs__path_txn_dir(fs, txn_id, pool), 300114731Sbde PATH_REV, pool); 301114731Sbde} 302114731Sbde 303114731Sbde 304144514Simpconst char * 305114731Sbdesvn_fs_fs__path_txn_proto_rev_lock(svn_fs_t *fs, 306144514Simp const svn_fs_fs__id_part_t *txn_id, 307114731Sbde apr_pool_t *pool) 308114731Sbde{ 309144514Simp fs_fs_data_t *ffd = fs->fsap_data; 310144514Simp if (ffd->format >= SVN_FS_FS__MIN_PROTOREVS_DIR_FORMAT) 311114731Sbde return svn_dirent_join(svn_fs_fs__path_txn_proto_revs(fs, pool), 312144514Simp combine_txn_id_string(txn_id, PATH_EXT_REV_LOCK, 313114731Sbde pool), 314114731Sbde pool); 315114731Sbde else 316214629Sjhb return svn_dirent_join(svn_fs_fs__path_txn_dir(fs, txn_id, pool), 317214629Sjhb PATH_REV_LOCK, pool); 318144561Simp} 319144561Simp 320144514Simpconst char * 321144514Simpsvn_fs_fs__path_txn_node_rev(svn_fs_t *fs, 322144514Simp const svn_fs_id_t *id, 323144514Simp apr_pool_t *pool) 324144514Simp{ 325144514Simp char *filename = (char *)svn_fs_fs__id_unparse(id, pool)->data; 326144561Simp *strrchr(filename, '.') = '\0'; 327144561Simp 328144514Simp return svn_dirent_join(svn_fs_fs__path_txn_dir(fs, svn_fs_fs__id_txn_id(id), 329144514Simp pool), 330144514Simp apr_psprintf(pool, PATH_PREFIX_NODE "%s", 331144514Simp filename), 332144514Simp pool); 333144514Simp} 334144514Simp 335214629Sjhbconst char * 336166640Srodrigcsvn_fs_fs__path_txn_node_props(svn_fs_t *fs, 337166640Srodrigc const svn_fs_id_t *id, 338166640Srodrigc apr_pool_t *pool) 339166640Srodrigc{ 340166640Srodrigc return apr_pstrcat(pool, svn_fs_fs__path_txn_node_rev(fs, id, pool), 341168677Spjd PATH_EXT_PROPS, SVN_VA_NULL); 342168677Spjd} 343168677Spjd 344168677Spjdconst char * 345168677Spjdsvn_fs_fs__path_txn_node_children(svn_fs_t *fs, 346 const svn_fs_id_t *id, 347 apr_pool_t *pool) 348{ 349 return apr_pstrcat(pool, svn_fs_fs__path_txn_node_rev(fs, id, pool), 350 PATH_EXT_CHILDREN, SVN_VA_NULL); 351} 352 353const char * 354svn_fs_fs__path_node_origin(svn_fs_t *fs, 355 const svn_fs_fs__id_part_t *node_id, 356 apr_pool_t *pool) 357{ 358 char buffer[SVN_INT64_BUFFER_SIZE]; 359 apr_size_t len = svn__ui64tobase36(buffer, node_id->number); 360 361 if (len > 1) 362 buffer[len - 1] = '\0'; 363 364 return svn_dirent_join_many(pool, fs->path, PATH_NODE_ORIGINS_DIR, 365 buffer, SVN_VA_NULL); 366} 367 368const char * 369svn_fs_fs__path_min_unpacked_rev(svn_fs_t *fs, 370 apr_pool_t *pool) 371{ 372 return svn_dirent_join(fs->path, PATH_MIN_UNPACKED_REV, pool); 373} 374 375svn_error_t * 376svn_fs_fs__check_file_buffer_numeric(const char *buf, 377 apr_off_t offset, 378 const char *path, 379 const char *title, 380 apr_pool_t *pool) 381{ 382 const char *p; 383 384 for (p = buf + offset; *p; p++) 385 if (!svn_ctype_isdigit(*p)) 386 return svn_error_createf(SVN_ERR_BAD_VERSION_FILE_FORMAT, NULL, 387 _("%s file '%s' contains unexpected non-digit '%c' within '%s'"), 388 title, svn_dirent_local_style(path, pool), *p, buf); 389 390 return SVN_NO_ERROR; 391} 392 393svn_error_t * 394svn_fs_fs__read_min_unpacked_rev(svn_revnum_t *min_unpacked_rev, 395 svn_fs_t *fs, 396 apr_pool_t *pool) 397{ 398 char buf[80]; 399 apr_file_t *file; 400 apr_size_t len; 401 402 SVN_ERR(svn_io_file_open(&file, 403 svn_fs_fs__path_min_unpacked_rev(fs, pool), 404 APR_READ | APR_BUFFERED, 405 APR_OS_DEFAULT, 406 pool)); 407 len = sizeof(buf); 408 SVN_ERR(svn_io_read_length_line(file, buf, &len, pool)); 409 SVN_ERR(svn_io_file_close(file, pool)); 410 411 SVN_ERR(svn_revnum_parse(min_unpacked_rev, buf, NULL)); 412 return SVN_NO_ERROR; 413} 414 415svn_error_t * 416svn_fs_fs__update_min_unpacked_rev(svn_fs_t *fs, 417 apr_pool_t *pool) 418{ 419 fs_fs_data_t *ffd = fs->fsap_data; 420 421 SVN_ERR_ASSERT(ffd->format >= SVN_FS_FS__MIN_PACKED_FORMAT); 422 423 return svn_fs_fs__read_min_unpacked_rev(&ffd->min_unpacked_rev, fs, pool); 424} 425 426svn_error_t * 427svn_fs_fs__write_min_unpacked_rev(svn_fs_t *fs, 428 svn_revnum_t revnum, 429 apr_pool_t *scratch_pool) 430{ 431 const char *final_path; 432 char buf[SVN_INT64_BUFFER_SIZE]; 433 apr_size_t len = svn__i64toa(buf, revnum); 434 buf[len] = '\n'; 435 436 final_path = svn_fs_fs__path_min_unpacked_rev(fs, scratch_pool); 437 438 SVN_ERR(svn_io_write_atomic(final_path, buf, len + 1, 439 final_path /* copy_perms */, scratch_pool)); 440 441 return SVN_NO_ERROR; 442} 443 444svn_error_t * 445svn_fs_fs__read_current(svn_revnum_t *rev, 446 apr_uint64_t *next_node_id, 447 apr_uint64_t *next_copy_id, 448 svn_fs_t *fs, 449 apr_pool_t *pool) 450{ 451 fs_fs_data_t *ffd = fs->fsap_data; 452 svn_stringbuf_t *content; 453 454 SVN_ERR(svn_fs_fs__read_content(&content, 455 svn_fs_fs__path_current(fs, pool), 456 pool)); 457 458 if (ffd->format >= SVN_FS_FS__MIN_NO_GLOBAL_IDS_FORMAT) 459 { 460 /* When format 1 and 2 filesystems are upgraded, the 'current' file is 461 left intact. As a consequence, there is a window when a filesystem 462 has a new format, but this file still contains the IDs left from an 463 old format, i.e. looks like "359 j5 v\n". Do not be too strict here 464 and only expect a parseable revision number. */ 465 SVN_ERR(svn_revnum_parse(rev, content->data, NULL)); 466 467 *next_node_id = 0; 468 *next_copy_id = 0; 469 } 470 else 471 { 472 const char *str; 473 474 SVN_ERR(svn_revnum_parse(rev, content->data, &str)); 475 if (*str != ' ') 476 return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, 477 _("Corrupt 'current' file")); 478 479 *next_node_id = svn__base36toui64(&str, str + 1); 480 if (*str != ' ') 481 return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, 482 _("Corrupt 'current' file")); 483 484 *next_copy_id = svn__base36toui64(&str, str + 1); 485 if (*str != '\n') 486 return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, 487 _("Corrupt 'current' file")); 488 } 489 490 return SVN_NO_ERROR; 491} 492 493svn_error_t * 494svn_fs_fs__write_current(svn_fs_t *fs, 495 svn_revnum_t rev, 496 apr_uint64_t next_node_id, 497 apr_uint64_t next_copy_id, 498 apr_pool_t *pool) 499{ 500 char *buf; 501 const char *name; 502 fs_fs_data_t *ffd = fs->fsap_data; 503 504 /* Now we can just write out this line. */ 505 if (ffd->format >= SVN_FS_FS__MIN_NO_GLOBAL_IDS_FORMAT) 506 { 507 buf = apr_psprintf(pool, "%ld\n", rev); 508 } 509 else 510 { 511 char node_id_str[SVN_INT64_BUFFER_SIZE]; 512 char copy_id_str[SVN_INT64_BUFFER_SIZE]; 513 svn__ui64tobase36(node_id_str, next_node_id); 514 svn__ui64tobase36(copy_id_str, next_copy_id); 515 516 buf = apr_psprintf(pool, "%ld %s %s\n", rev, node_id_str, copy_id_str); 517 } 518 519 name = svn_fs_fs__path_current(fs, pool); 520 SVN_ERR(svn_io_write_atomic(name, buf, strlen(buf), 521 name /* copy_perms_path */, pool)); 522 523 return SVN_NO_ERROR; 524} 525 526svn_error_t * 527svn_fs_fs__try_stringbuf_from_file(svn_stringbuf_t **content, 528 svn_boolean_t *missing, 529 const char *path, 530 svn_boolean_t last_attempt, 531 apr_pool_t *pool) 532{ 533 svn_error_t *err = svn_stringbuf_from_file2(content, path, pool); 534 if (missing) 535 *missing = FALSE; 536 537 if (err) 538 { 539 *content = NULL; 540 541 if (APR_STATUS_IS_ENOENT(err->apr_err)) 542 { 543 if (!last_attempt) 544 { 545 svn_error_clear(err); 546 if (missing) 547 *missing = TRUE; 548 return SVN_NO_ERROR; 549 } 550 } 551#ifdef ESTALE 552 else if (APR_TO_OS_ERROR(err->apr_err) == ESTALE 553 || APR_TO_OS_ERROR(err->apr_err) == EIO) 554 { 555 if (!last_attempt) 556 { 557 svn_error_clear(err); 558 return SVN_NO_ERROR; 559 } 560 } 561#endif 562 } 563 564 return svn_error_trace(err); 565} 566 567svn_error_t * 568svn_fs_fs__get_file_offset(apr_off_t *offset_p, 569 apr_file_t *file, 570 apr_pool_t *pool) 571{ 572 apr_off_t offset; 573 574 /* Note that, for buffered files, one (possibly surprising) side-effect 575 of this call is to flush any unwritten data to disk. */ 576 offset = 0; 577 SVN_ERR(svn_io_file_seek(file, APR_CUR, &offset, pool)); 578 *offset_p = offset; 579 580 return SVN_NO_ERROR; 581} 582 583svn_error_t * 584svn_fs_fs__read_content(svn_stringbuf_t **content, 585 const char *fname, 586 apr_pool_t *pool) 587{ 588 int i; 589 *content = NULL; 590 591 for (i = 0; !*content && (i < SVN_FS_FS__RECOVERABLE_RETRY_COUNT); ++i) 592 SVN_ERR(svn_fs_fs__try_stringbuf_from_file(content, NULL, 593 fname, i + 1 < SVN_FS_FS__RECOVERABLE_RETRY_COUNT, 594 pool)); 595 596 if (!*content) 597 return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, 598 _("Can't read '%s'"), 599 svn_dirent_local_style(fname, pool)); 600 601 return SVN_NO_ERROR; 602} 603 604svn_error_t * 605svn_fs_fs__read_number_from_stream(apr_int64_t *result, 606 svn_boolean_t *hit_eof, 607 svn_stream_t *stream, 608 apr_pool_t *scratch_pool) 609{ 610 svn_stringbuf_t *sb; 611 svn_boolean_t eof; 612 svn_error_t *err; 613 614 SVN_ERR(svn_stream_readline(stream, &sb, "\n", &eof, scratch_pool)); 615 if (hit_eof) 616 *hit_eof = eof; 617 else 618 if (eof) 619 return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, _("Unexpected EOF")); 620 621 if (!eof) 622 { 623 err = svn_cstring_atoi64(result, sb->data); 624 if (err) 625 return svn_error_createf(SVN_ERR_FS_CORRUPT, err, 626 _("Number '%s' invalid or too large"), 627 sb->data); 628 } 629 630 return SVN_NO_ERROR; 631} 632 633svn_error_t * 634svn_fs_fs__move_into_place(const char *old_filename, 635 const char *new_filename, 636 const char *perms_reference, 637 apr_pool_t *pool) 638{ 639 svn_error_t *err; 640 641 SVN_ERR(svn_io_copy_perms(perms_reference, old_filename, pool)); 642 643 /* Move the file into place. */ 644 err = svn_io_file_rename(old_filename, new_filename, pool); 645 if (err && APR_STATUS_IS_EXDEV(err->apr_err)) 646 { 647 apr_file_t *file; 648 649 /* Can't rename across devices; fall back to copying. */ 650 svn_error_clear(err); 651 err = SVN_NO_ERROR; 652 SVN_ERR(svn_io_copy_file(old_filename, new_filename, TRUE, pool)); 653 654 /* Flush the target of the copy to disk. */ 655 SVN_ERR(svn_io_file_open(&file, new_filename, APR_READ, 656 APR_OS_DEFAULT, pool)); 657 /* ### BH: Does this really guarantee a flush of the data written 658 ### via a completely different handle on all operating systems? 659 ### 660 ### Maybe we should perform the copy ourselves instead of making 661 ### apr do that and flush the real handle? */ 662 SVN_ERR(svn_io_file_flush_to_disk(file, pool)); 663 SVN_ERR(svn_io_file_close(file, pool)); 664 } 665 if (err) 666 return svn_error_trace(err); 667 668#ifdef __linux__ 669 { 670 /* Linux has the unusual feature that fsync() on a file is not 671 enough to ensure that a file's directory entries have been 672 flushed to disk; you have to fsync the directory as well. 673 On other operating systems, we'd only be asking for trouble 674 by trying to open and fsync a directory. */ 675 const char *dirname; 676 apr_file_t *file; 677 678 dirname = svn_dirent_dirname(new_filename, pool); 679 SVN_ERR(svn_io_file_open(&file, dirname, APR_READ, APR_OS_DEFAULT, 680 pool)); 681 SVN_ERR(svn_io_file_flush_to_disk(file, pool)); 682 SVN_ERR(svn_io_file_close(file, pool)); 683 } 684#endif 685 686 return SVN_NO_ERROR; 687} 688 689svn_boolean_t 690svn_fs_fs__use_log_addressing(svn_fs_t *fs) 691{ 692 fs_fs_data_t *ffd = fs->fsap_data; 693 return ffd->use_log_addressing; 694} 695