low_level.c (302408) | low_level.c (362181) |
---|---|
1/* low_level.c --- low level r/w access to fs_x file structures | 1/* low_level.c --- low level r/w access to FSX file structures |
2 * 3 * ==================================================================== 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance --- 41 unchanged lines hidden (view full) --- 51#define HEADER_MINFO_HERE "minfo-here" 52#define HEADER_MINFO_CNT "minfo-cnt" 53 54/* Kinds that a change can be. */ 55#define ACTION_MODIFY "modify" 56#define ACTION_ADD "add" 57#define ACTION_DELETE "delete" 58#define ACTION_REPLACE "replace" | 2 * 3 * ==================================================================== 4 * Licensed to the Apache Software Foundation (ASF) under one 5 * or more contributor license agreements. See the NOTICE file 6 * distributed with this work for additional information 7 * regarding copyright ownership. The ASF licenses this file 8 * to you under the Apache License, Version 2.0 (the 9 * "License"); you may not use this file except in compliance --- 41 unchanged lines hidden (view full) --- 51#define HEADER_MINFO_HERE "minfo-here" 52#define HEADER_MINFO_CNT "minfo-cnt" 53 54/* Kinds that a change can be. */ 55#define ACTION_MODIFY "modify" 56#define ACTION_ADD "add" 57#define ACTION_DELETE "delete" 58#define ACTION_REPLACE "replace" |
59#define ACTION_RESET "reset" | |
60 61/* True and False flags. */ 62#define FLAG_TRUE "true" 63#define FLAG_FALSE "false" 64 65/* Kinds of representation. */ 66#define REP_DELTA "DELTA" 67 --- 30 unchanged lines hidden (view full) --- 98 else if (*string != '\0') 99 return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, 100 _("Invalid character in revision number")); 101 102 *text = string; 103 return SVN_NO_ERROR; 104} 105 | 59 60/* True and False flags. */ 61#define FLAG_TRUE "true" 62#define FLAG_FALSE "false" 63 64/* Kinds of representation. */ 65#define REP_DELTA "DELTA" 66 --- 30 unchanged lines hidden (view full) --- 97 else if (*string != '\0') 98 return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, 99 _("Invalid character in revision number")); 100 101 *text = string; 102 return SVN_NO_ERROR; 103} 104 |
105/* If ERR is not NULL, wrap it MESSAGE. The latter must have an %ld 106 * format parameter that will be filled with REV. */ 107static svn_error_t * 108wrap_footer_error(svn_error_t *err, 109 const char *message, 110 svn_revnum_t rev) 111{ 112 if (err) 113 return svn_error_quick_wrapf(err, message, rev); 114 115 return SVN_NO_ERROR; 116} 117 |
|
106svn_error_t * 107svn_fs_x__parse_footer(apr_off_t *l2p_offset, 108 svn_checksum_t **l2p_checksum, 109 apr_off_t *p2l_offset, 110 svn_checksum_t **p2l_checksum, 111 svn_stringbuf_t *footer, 112 svn_revnum_t rev, | 118svn_error_t * 119svn_fs_x__parse_footer(apr_off_t *l2p_offset, 120 svn_checksum_t **l2p_checksum, 121 apr_off_t *p2l_offset, 122 svn_checksum_t **p2l_checksum, 123 svn_stringbuf_t *footer, 124 svn_revnum_t rev, |
125 apr_off_t footer_offset, |
|
113 apr_pool_t *result_pool) 114{ 115 apr_int64_t val; 116 char *last_str = footer->data; 117 118 /* Get the L2P offset. */ 119 const char *str = svn_cstring_tokenize(" ", &last_str); 120 if (str == NULL) | 126 apr_pool_t *result_pool) 127{ 128 apr_int64_t val; 129 char *last_str = footer->data; 130 131 /* Get the L2P offset. */ 132 const char *str = svn_cstring_tokenize(" ", &last_str); 133 if (str == NULL) |
121 return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, 122 _("Invalid revision footer")); | 134 return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, 135 "Invalid r%ld footer", rev); |
123 | 136 |
124 SVN_ERR(svn_cstring_atoi64(&val, str)); | 137 SVN_ERR(wrap_footer_error(svn_cstring_strtoi64(&val, str, 0, 138 footer_offset - 1, 10), 139 "Invalid L2P offset in r%ld footer", 140 rev)); |
125 *l2p_offset = (apr_off_t)val; 126 127 /* Get the L2P checksum. */ 128 str = svn_cstring_tokenize(" ", &last_str); 129 if (str == NULL) | 141 *l2p_offset = (apr_off_t)val; 142 143 /* Get the L2P checksum. */ 144 str = svn_cstring_tokenize(" ", &last_str); 145 if (str == NULL) |
130 return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, 131 _("Invalid revision footer")); | 146 return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, 147 "Invalid r%ld footer", rev); |
132 133 SVN_ERR(svn_checksum_parse_hex(l2p_checksum, svn_checksum_md5, str, 134 result_pool)); 135 136 /* Get the P2L offset. */ 137 str = svn_cstring_tokenize(" ", &last_str); 138 if (str == NULL) | 148 149 SVN_ERR(svn_checksum_parse_hex(l2p_checksum, svn_checksum_md5, str, 150 result_pool)); 151 152 /* Get the P2L offset. */ 153 str = svn_cstring_tokenize(" ", &last_str); 154 if (str == NULL) |
139 return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, 140 _("Invalid revision footer")); | 155 return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, 156 "Invalid r%ld footer", rev); |
141 | 157 |
142 SVN_ERR(svn_cstring_atoi64(&val, str)); | 158 SVN_ERR(wrap_footer_error(svn_cstring_strtoi64(&val, str, 0, 159 footer_offset - 1, 10), 160 "Invalid P2L offset in r%ld footer", 161 rev)); |
143 *p2l_offset = (apr_off_t)val; 144 | 162 *p2l_offset = (apr_off_t)val; 163 |
164 /* The P2L indes follows the L2P index */ 165 if (*p2l_offset <= *l2p_offset) 166 return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, 167 "P2L offset %s must be larger than L2P offset %s" 168 " in r%ld footer", 169 apr_psprintf(result_pool, 170 "0x%" APR_UINT64_T_HEX_FMT, 171 (apr_uint64_t)*p2l_offset), 172 apr_psprintf(result_pool, 173 "0x%" APR_UINT64_T_HEX_FMT, 174 (apr_uint64_t)*l2p_offset), 175 rev); 176 |
|
145 /* Get the P2L checksum. */ 146 str = svn_cstring_tokenize(" ", &last_str); 147 if (str == NULL) | 177 /* Get the P2L checksum. */ 178 str = svn_cstring_tokenize(" ", &last_str); 179 if (str == NULL) |
148 return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, 149 _("Invalid revision footer")); | 180 return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, 181 "Invalid r%ld footer", rev); |
150 151 SVN_ERR(svn_checksum_parse_hex(p2l_checksum, svn_checksum_md5, str, 152 result_pool)); 153 154 return SVN_NO_ERROR; 155} 156 157svn_stringbuf_t * --- 634 unchanged lines hidden (view full) --- 792 793 /* Check for a blank line. */ 794 if (eof || (line->len == 0)) 795 return SVN_NO_ERROR; 796 797 change = apr_pcalloc(result_pool, sizeof(*change)); 798 last_str = line->data; 799 | 182 183 SVN_ERR(svn_checksum_parse_hex(p2l_checksum, svn_checksum_md5, str, 184 result_pool)); 185 186 return SVN_NO_ERROR; 187} 188 189svn_stringbuf_t * --- 634 unchanged lines hidden (view full) --- 824 825 /* Check for a blank line. */ 826 if (eof || (line->len == 0)) 827 return SVN_NO_ERROR; 828 829 change = apr_pcalloc(result_pool, sizeof(*change)); 830 last_str = line->data; 831 |
800 /* Get the node-id of the change. */ 801 str = svn_cstring_tokenize(" ", &last_str); 802 if (str == NULL) 803 return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, 804 _("Invalid changes line in rev-file")); 805 806 SVN_ERR(svn_fs_x__id_parse(&change->noderev_id, str)); 807 | |
808 /* Get the change type. */ 809 str = svn_cstring_tokenize(" ", &last_str); 810 if (str == NULL) 811 return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, 812 _("Invalid changes line in rev-file")); 813 814 /* Don't bother to check the format number before looking for 815 * node-kinds: just read them if you find them. */ --- 24 unchanged lines hidden (view full) --- 840 else if (strcmp(str, ACTION_DELETE) == 0) 841 { 842 change->change_kind = svn_fs_path_change_delete; 843 } 844 else if (strcmp(str, ACTION_REPLACE) == 0) 845 { 846 change->change_kind = svn_fs_path_change_replace; 847 } | 832 /* Get the change type. */ 833 str = svn_cstring_tokenize(" ", &last_str); 834 if (str == NULL) 835 return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, 836 _("Invalid changes line in rev-file")); 837 838 /* Don't bother to check the format number before looking for 839 * node-kinds: just read them if you find them. */ --- 24 unchanged lines hidden (view full) --- 864 else if (strcmp(str, ACTION_DELETE) == 0) 865 { 866 change->change_kind = svn_fs_path_change_delete; 867 } 868 else if (strcmp(str, ACTION_REPLACE) == 0) 869 { 870 change->change_kind = svn_fs_path_change_replace; 871 } |
848 else if (strcmp(str, ACTION_RESET) == 0) 849 { 850 change->change_kind = svn_fs_path_change_reset; 851 } | |
852 else 853 { 854 return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, 855 _("Invalid change kind in rev file")); 856 } 857 858 /* Get the text-mod flag. */ 859 str = svn_cstring_tokenize(" ", &last_str); --- 89 unchanged lines hidden (view full) --- 949 *change_p = change; 950 951 return SVN_NO_ERROR; 952} 953 954svn_error_t * 955svn_fs_x__read_changes(apr_array_header_t **changes, 956 svn_stream_t *stream, | 872 else 873 { 874 return svn_error_create(SVN_ERR_FS_CORRUPT, NULL, 875 _("Invalid change kind in rev file")); 876 } 877 878 /* Get the text-mod flag. */ 879 str = svn_cstring_tokenize(" ", &last_str); --- 89 unchanged lines hidden (view full) --- 969 *change_p = change; 970 971 return SVN_NO_ERROR; 972} 973 974svn_error_t * 975svn_fs_x__read_changes(apr_array_header_t **changes, 976 svn_stream_t *stream, |
977 int max_count, |
|
957 apr_pool_t *result_pool, 958 apr_pool_t *scratch_pool) 959{ | 978 apr_pool_t *result_pool, 979 apr_pool_t *scratch_pool) 980{ |
960 svn_fs_x__change_t *change; | |
961 apr_pool_t *iterpool; 962 963 /* Pre-allocate enough room for most change lists. 964 (will be auto-expanded as necessary). 965 966 Chose the default to just below 2^N such that the doubling reallocs 967 will request roughly 2^M bytes from the OS without exceeding the 968 respective two-power by just a few bytes (leaves room array and APR 969 node overhead for large enough M). 970 */ 971 *changes = apr_array_make(result_pool, 63, sizeof(svn_fs_x__change_t *)); 972 | 981 apr_pool_t *iterpool; 982 983 /* Pre-allocate enough room for most change lists. 984 (will be auto-expanded as necessary). 985 986 Chose the default to just below 2^N such that the doubling reallocs 987 will request roughly 2^M bytes from the OS without exceeding the 988 respective two-power by just a few bytes (leaves room array and APR 989 node overhead for large enough M). 990 */ 991 *changes = apr_array_make(result_pool, 63, sizeof(svn_fs_x__change_t *)); 992 |
973 SVN_ERR(read_change(&change, stream, result_pool, scratch_pool)); | |
974 iterpool = svn_pool_create(scratch_pool); | 993 iterpool = svn_pool_create(scratch_pool); |
975 while (change) | 994 for (; max_count > 0; --max_count) |
976 { | 995 { |
977 APR_ARRAY_PUSH(*changes, svn_fs_x__change_t*) = change; 978 SVN_ERR(read_change(&change, stream, result_pool, iterpool)); | 996 svn_fs_x__change_t *change; |
979 svn_pool_clear(iterpool); | 997 svn_pool_clear(iterpool); |
998 SVN_ERR(read_change(&change, stream, result_pool, iterpool)); 999 if (!change) 1000 break; 1001 1002 APR_ARRAY_PUSH(*changes, svn_fs_x__change_t*) = change; |
|
980 } 981 svn_pool_destroy(iterpool); 982 983 return SVN_NO_ERROR; 984} 985 986svn_error_t * 987svn_fs_x__read_changes_incrementally(svn_stream_t *stream, --- 23 unchanged lines hidden (view full) --- 1011/* Write a single change entry, path PATH, change CHANGE, to STREAM. 1012 1013 All temporary allocations are in SCRATCH_POOL. */ 1014static svn_error_t * 1015write_change_entry(svn_stream_t *stream, 1016 svn_fs_x__change_t *change, 1017 apr_pool_t *scratch_pool) 1018{ | 1003 } 1004 svn_pool_destroy(iterpool); 1005 1006 return SVN_NO_ERROR; 1007} 1008 1009svn_error_t * 1010svn_fs_x__read_changes_incrementally(svn_stream_t *stream, --- 23 unchanged lines hidden (view full) --- 1034/* Write a single change entry, path PATH, change CHANGE, to STREAM. 1035 1036 All temporary allocations are in SCRATCH_POOL. */ 1037static svn_error_t * 1038write_change_entry(svn_stream_t *stream, 1039 svn_fs_x__change_t *change, 1040 apr_pool_t *scratch_pool) 1041{ |
1019 const char *idstr; | |
1020 const char *change_string = NULL; 1021 const char *kind_string = ""; 1022 svn_stringbuf_t *buf; 1023 apr_size_t len; 1024 1025 switch (change->change_kind) 1026 { 1027 case svn_fs_path_change_modify: 1028 change_string = ACTION_MODIFY; 1029 break; 1030 case svn_fs_path_change_add: 1031 change_string = ACTION_ADD; 1032 break; 1033 case svn_fs_path_change_delete: 1034 change_string = ACTION_DELETE; 1035 break; 1036 case svn_fs_path_change_replace: 1037 change_string = ACTION_REPLACE; 1038 break; | 1042 const char *change_string = NULL; 1043 const char *kind_string = ""; 1044 svn_stringbuf_t *buf; 1045 apr_size_t len; 1046 1047 switch (change->change_kind) 1048 { 1049 case svn_fs_path_change_modify: 1050 change_string = ACTION_MODIFY; 1051 break; 1052 case svn_fs_path_change_add: 1053 change_string = ACTION_ADD; 1054 break; 1055 case svn_fs_path_change_delete: 1056 change_string = ACTION_DELETE; 1057 break; 1058 case svn_fs_path_change_replace: 1059 change_string = ACTION_REPLACE; 1060 break; |
1039 case svn_fs_path_change_reset: 1040 change_string = ACTION_RESET; 1041 break; | |
1042 default: 1043 return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, 1044 _("Invalid change type %d"), 1045 change->change_kind); 1046 } 1047 | 1061 default: 1062 return svn_error_createf(SVN_ERR_FS_CORRUPT, NULL, 1063 _("Invalid change type %d"), 1064 change->change_kind); 1065 } 1066 |
1048 idstr = svn_fs_x__id_unparse(&change->noderev_id, scratch_pool)->data; 1049 | |
1050 SVN_ERR_ASSERT(change->node_kind == svn_node_dir 1051 || change->node_kind == svn_node_file); 1052 kind_string = apr_psprintf(scratch_pool, "-%s", 1053 change->node_kind == svn_node_dir 1054 ? SVN_FS_X__KIND_DIR 1055 : SVN_FS_X__KIND_FILE); 1056 | 1067 SVN_ERR_ASSERT(change->node_kind == svn_node_dir 1068 || change->node_kind == svn_node_file); 1069 kind_string = apr_psprintf(scratch_pool, "-%s", 1070 change->node_kind == svn_node_dir 1071 ? SVN_FS_X__KIND_DIR 1072 : SVN_FS_X__KIND_FILE); 1073 |
1057 buf = svn_stringbuf_createf(scratch_pool, "%s %s%s %s %s %s %s\n", 1058 idstr, change_string, kind_string, | 1074 buf = svn_stringbuf_createf(scratch_pool, "%s%s %s %s %s %s\n", 1075 change_string, kind_string, |
1059 change->text_mod ? FLAG_TRUE : FLAG_FALSE, 1060 change->prop_mod ? FLAG_TRUE : FLAG_FALSE, 1061 change->mergeinfo_mod == svn_tristate_true 1062 ? FLAG_TRUE : FLAG_FALSE, 1063 auto_escape_path(change->path.data, scratch_pool)); 1064 1065 if (SVN_IS_VALID_REVNUM(change->copyfrom_rev)) 1066 { --- 42 unchanged lines hidden (view full) --- 1109 svn_pool_clear(iterpool); 1110 change = APR_ARRAY_IDX(sorted_changed_paths, i, svn_sort__item_t).value; 1111 1112 /* Write out the new entry into the final rev-file. */ 1113 SVN_ERR(write_change_entry(stream, change, iterpool)); 1114 } 1115 1116 if (terminate_list) | 1076 change->text_mod ? FLAG_TRUE : FLAG_FALSE, 1077 change->prop_mod ? FLAG_TRUE : FLAG_FALSE, 1078 change->mergeinfo_mod == svn_tristate_true 1079 ? FLAG_TRUE : FLAG_FALSE, 1080 auto_escape_path(change->path.data, scratch_pool)); 1081 1082 if (SVN_IS_VALID_REVNUM(change->copyfrom_rev)) 1083 { --- 42 unchanged lines hidden (view full) --- 1126 svn_pool_clear(iterpool); 1127 change = APR_ARRAY_IDX(sorted_changed_paths, i, svn_sort__item_t).value; 1128 1129 /* Write out the new entry into the final rev-file. */ 1130 SVN_ERR(write_change_entry(stream, change, iterpool)); 1131 } 1132 1133 if (terminate_list) |
1117 svn_stream_puts(stream, "\n"); | 1134 SVN_ERR(svn_stream_puts(stream, "\n")); |
1118 1119 svn_pool_destroy(iterpool); 1120 1121 return SVN_NO_ERROR; 1122} 1123 | 1135 1136 svn_pool_destroy(iterpool); 1137 1138 return SVN_NO_ERROR; 1139} 1140 |
1141svn_error_t * 1142svn_fs_x__parse_properties(apr_hash_t **properties, 1143 const svn_string_t *content, 1144 apr_pool_t *result_pool) 1145{ 1146 const apr_byte_t *p = (const apr_byte_t *)content->data; 1147 const apr_byte_t *end = p + content->len; 1148 apr_uint64_t count; 1149 1150 *properties = apr_hash_make(result_pool); 1151 1152 /* Extract the number of properties we are expected to read. */ 1153 p = svn__decode_uint(&count, p, end); 1154 1155 /* Read all the properties we find. 1156 Because prop-name and prop-value are nicely NUL-terminated 1157 sub-strings of CONTENT, we can simply reference them there. 1158 I.e. there is no need to copy them around. 1159 */ 1160 while (p < end) 1161 { 1162 apr_uint64_t value_len; 1163 svn_string_t *value; 1164 1165 const char *key = (const char *)p; 1166 1167 /* Note that this may never overflow / segfault because 1168 CONTENT itself is NUL-terminated. */ 1169 apr_size_t key_len = strlen(key); 1170 p += key_len + 1; 1171 if (key[key_len]) 1172 return svn_error_createf(SVN_ERR_FS_CORRUPT_PROPLIST, NULL, 1173 "Property name not NUL terminated"); 1174 1175 if (p >= end) 1176 return svn_error_createf(SVN_ERR_FS_CORRUPT_PROPLIST, NULL, 1177 "Property value missing"); 1178 p = svn__decode_uint(&value_len, p, end); 1179 if (value_len >= (end - p)) 1180 return svn_error_createf(SVN_ERR_FS_CORRUPT_PROPLIST, NULL, 1181 "Property value too long"); 1182 1183 value = apr_pcalloc(result_pool, sizeof(*value)); 1184 value->data = (const char *)p; 1185 value->len = (apr_size_t)value_len; 1186 if (p[value->len]) 1187 return svn_error_createf(SVN_ERR_FS_CORRUPT_PROPLIST, NULL, 1188 "Property value not NUL terminated"); 1189 1190 p += value->len + 1; 1191 1192 apr_hash_set(*properties, key, key_len, value); 1193 } 1194 1195 /* Check that we read the expected number of properties. */ 1196 if ((apr_uint64_t)apr_hash_count(*properties) != count) 1197 return svn_error_createf(SVN_ERR_FS_CORRUPT_PROPLIST, NULL, 1198 "Property count mismatch"); 1199 1200 return SVN_NO_ERROR; 1201} 1202 1203svn_error_t * 1204svn_fs_x__write_properties(svn_stream_t *stream, 1205 apr_hash_t *proplist, 1206 apr_pool_t *scratch_pool) 1207{ 1208 apr_byte_t buffer[SVN__MAX_ENCODED_UINT_LEN]; 1209 apr_size_t len; 1210 apr_hash_index_t *hi; 1211 1212 /* Write the number of properties in this list. */ 1213 len = svn__encode_uint(buffer, apr_hash_count(proplist)) - buffer; 1214 SVN_ERR(svn_stream_write(stream, (const char *)buffer, &len)); 1215 1216 /* Serialize each property as follows: 1217 <Prop-name> <NUL> 1218 <Value-len> <Prop-value> <NUL> 1219 */ 1220 for (hi = apr_hash_first(scratch_pool, proplist); 1221 hi; 1222 hi = apr_hash_next(hi)) 1223 { 1224 const char *key; 1225 apr_size_t key_len; 1226 svn_string_t *value; 1227 apr_hash_this(hi, (const void **)&key, (apr_ssize_t *)&key_len, 1228 (void **)&value); 1229 1230 /* Include the terminating NUL. */ 1231 ++key_len; 1232 SVN_ERR(svn_stream_write(stream, key, &key_len)); 1233 1234 len = svn__encode_uint(buffer, value->len) - buffer; 1235 SVN_ERR(svn_stream_write(stream, (const char *)buffer, &len)); 1236 SVN_ERR(svn_stream_write(stream, value->data, &value->len)); 1237 1238 /* Terminate with NUL. */ 1239 len = 1; 1240 SVN_ERR(svn_stream_write(stream, "", &len)); 1241 } 1242 1243 return SVN_NO_ERROR; 1244} |
|