Deleted Added
full compact
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}