|
2 | 2 | #include "object-store.h" |
3 | 3 | #include "repository.h" |
4 | 4 | #include "object.h" |
| 5 | +#include "attr.h" |
5 | 6 | #include "blob.h" |
6 | 7 | #include "tree.h" |
7 | 8 | #include "tree-walk.h" |
@@ -614,17 +615,22 @@ static int fsck_tree(const struct object_id *tree_oid, |
614 | 615 | ".gitmodules is a symbolic link"); |
615 | 616 | } |
616 | 617 |
|
| 618 | + if (is_hfs_dotgitattributes(name) || is_ntfs_dotgitattributes(name)) { |
| 619 | + if (!S_ISLNK(mode)) |
| 620 | + oidset_insert(&options->gitattributes_found, |
| 621 | + entry_oid); |
| 622 | + else |
| 623 | + retval += report(options, tree_oid, OBJ_TREE, |
| 624 | + FSCK_MSG_GITATTRIBUTES_SYMLINK, |
| 625 | + ".gitattributes is a symlink"); |
| 626 | + } |
| 627 | + |
617 | 628 | if (S_ISLNK(mode)) { |
618 | 629 | if (is_hfs_dotgitignore(name) || |
619 | 630 | is_ntfs_dotgitignore(name)) |
620 | 631 | retval += report(options, tree_oid, OBJ_TREE, |
621 | 632 | FSCK_MSG_GITIGNORE_SYMLINK, |
622 | 633 | ".gitignore is a symlink"); |
623 | | - if (is_hfs_dotgitattributes(name) || |
624 | | - is_ntfs_dotgitattributes(name)) |
625 | | - retval += report(options, tree_oid, OBJ_TREE, |
626 | | - FSCK_MSG_GITATTRIBUTES_SYMLINK, |
627 | | - ".gitattributes is a symlink"); |
628 | 634 | if (is_hfs_dotmailmap(name) || |
629 | 635 | is_ntfs_dotmailmap(name)) |
630 | 636 | retval += report(options, tree_oid, OBJ_TREE, |
@@ -1170,38 +1176,70 @@ static int fsck_gitmodules_fn(const char *var, const char *value, void *vdata) |
1170 | 1176 | static int fsck_blob(const struct object_id *oid, const char *buf, |
1171 | 1177 | unsigned long size, struct fsck_options *options) |
1172 | 1178 | { |
1173 | | - struct fsck_gitmodules_data data; |
1174 | | - struct config_options config_opts = { 0 }; |
1175 | | - |
1176 | | - if (!oidset_contains(&options->gitmodules_found, oid)) |
1177 | | - return 0; |
1178 | | - oidset_insert(&options->gitmodules_done, oid); |
| 1179 | + int ret = 0; |
1179 | 1180 |
|
1180 | 1181 | if (object_on_skiplist(options, oid)) |
1181 | 1182 | return 0; |
1182 | 1183 |
|
1183 | | - if (!buf) { |
1184 | | - /* |
1185 | | - * A missing buffer here is a sign that the caller found the |
1186 | | - * blob too gigantic to load into memory. Let's just consider |
1187 | | - * that an error. |
1188 | | - */ |
1189 | | - return report(options, oid, OBJ_BLOB, |
1190 | | - FSCK_MSG_GITMODULES_LARGE, |
1191 | | - ".gitmodules too large to parse"); |
| 1184 | + if (oidset_contains(&options->gitmodules_found, oid)) { |
| 1185 | + struct config_options config_opts = { 0 }; |
| 1186 | + struct fsck_gitmodules_data data; |
| 1187 | + |
| 1188 | + oidset_insert(&options->gitmodules_done, oid); |
| 1189 | + |
| 1190 | + if (!buf) { |
| 1191 | + /* |
| 1192 | + * A missing buffer here is a sign that the caller found the |
| 1193 | + * blob too gigantic to load into memory. Let's just consider |
| 1194 | + * that an error. |
| 1195 | + */ |
| 1196 | + return report(options, oid, OBJ_BLOB, |
| 1197 | + FSCK_MSG_GITMODULES_LARGE, |
| 1198 | + ".gitmodules too large to parse"); |
| 1199 | + } |
| 1200 | + |
| 1201 | + data.oid = oid; |
| 1202 | + data.options = options; |
| 1203 | + data.ret = 0; |
| 1204 | + config_opts.error_action = CONFIG_ERROR_SILENT; |
| 1205 | + if (git_config_from_mem(fsck_gitmodules_fn, CONFIG_ORIGIN_BLOB, |
| 1206 | + ".gitmodules", buf, size, &data, &config_opts)) |
| 1207 | + data.ret |= report(options, oid, OBJ_BLOB, |
| 1208 | + FSCK_MSG_GITMODULES_PARSE, |
| 1209 | + "could not parse gitmodules blob"); |
| 1210 | + ret |= data.ret; |
1192 | 1211 | } |
1193 | 1212 |
|
1194 | | - data.oid = oid; |
1195 | | - data.options = options; |
1196 | | - data.ret = 0; |
1197 | | - config_opts.error_action = CONFIG_ERROR_SILENT; |
1198 | | - if (git_config_from_mem(fsck_gitmodules_fn, CONFIG_ORIGIN_BLOB, |
1199 | | - ".gitmodules", buf, size, &data, &config_opts)) |
1200 | | - data.ret |= report(options, oid, OBJ_BLOB, |
1201 | | - FSCK_MSG_GITMODULES_PARSE, |
1202 | | - "could not parse gitmodules blob"); |
1203 | | - |
1204 | | - return data.ret; |
| 1213 | + if (oidset_contains(&options->gitattributes_found, oid)) { |
| 1214 | + const char *ptr; |
| 1215 | + |
| 1216 | + oidset_insert(&options->gitattributes_done, oid); |
| 1217 | + |
| 1218 | + if (!buf || size > ATTR_MAX_FILE_SIZE) { |
| 1219 | + /* |
| 1220 | + * A missing buffer here is a sign that the caller found the |
| 1221 | + * blob too gigantic to load into memory. Let's just consider |
| 1222 | + * that an error. |
| 1223 | + */ |
| 1224 | + return report(options, oid, OBJ_BLOB, |
| 1225 | + FSCK_MSG_GITATTRIBUTES_LARGE, |
| 1226 | + ".gitattributes too large to parse"); |
| 1227 | + } |
| 1228 | + |
| 1229 | + for (ptr = buf; *ptr; ) { |
| 1230 | + const char *eol = strchrnul(ptr, '\n'); |
| 1231 | + if (eol - ptr >= ATTR_MAX_LINE_LENGTH) { |
| 1232 | + ret |= report(options, oid, OBJ_BLOB, |
| 1233 | + FSCK_MSG_GITATTRIBUTES_LINE_LENGTH, |
| 1234 | + ".gitattributes has too long lines to parse"); |
| 1235 | + break; |
| 1236 | + } |
| 1237 | + |
| 1238 | + ptr = *eol ? eol + 1 : eol; |
| 1239 | + } |
| 1240 | + } |
| 1241 | + |
| 1242 | + return ret; |
1205 | 1243 | } |
1206 | 1244 |
|
1207 | 1245 | int fsck_object(struct object *obj, void *data, unsigned long size, |
@@ -1240,45 +1278,58 @@ int fsck_error_function(struct fsck_options *o, |
1240 | 1278 | return 1; |
1241 | 1279 | } |
1242 | 1280 |
|
1243 | | -int fsck_finish(struct fsck_options *options) |
| 1281 | +static int fsck_blobs(struct oidset *blobs_found, struct oidset *blobs_done, |
| 1282 | + enum fsck_msg_id msg_missing, enum fsck_msg_id msg_type, |
| 1283 | + struct fsck_options *options, const char *blob_type) |
1244 | 1284 | { |
1245 | 1285 | int ret = 0; |
1246 | 1286 | struct oidset_iter iter; |
1247 | 1287 | const struct object_id *oid; |
1248 | 1288 |
|
1249 | | - oidset_iter_init(&options->gitmodules_found, &iter); |
| 1289 | + oidset_iter_init(blobs_found, &iter); |
1250 | 1290 | while ((oid = oidset_iter_next(&iter))) { |
1251 | 1291 | enum object_type type; |
1252 | 1292 | unsigned long size; |
1253 | 1293 | char *buf; |
1254 | 1294 |
|
1255 | | - if (oidset_contains(&options->gitmodules_done, oid)) |
| 1295 | + if (oidset_contains(blobs_done, oid)) |
1256 | 1296 | continue; |
1257 | 1297 |
|
1258 | 1298 | buf = read_object_file(oid, &type, &size); |
1259 | 1299 | if (!buf) { |
1260 | 1300 | if (is_promisor_object(oid)) |
1261 | 1301 | continue; |
1262 | 1302 | ret |= report(options, |
1263 | | - oid, OBJ_BLOB, |
1264 | | - FSCK_MSG_GITMODULES_MISSING, |
1265 | | - "unable to read .gitmodules blob"); |
| 1303 | + oid, OBJ_BLOB, msg_missing, |
| 1304 | + "unable to read %s blob", blob_type); |
1266 | 1305 | continue; |
1267 | 1306 | } |
1268 | 1307 |
|
1269 | 1308 | if (type == OBJ_BLOB) |
1270 | 1309 | ret |= fsck_blob(oid, buf, size, options); |
1271 | 1310 | else |
1272 | | - ret |= report(options, |
1273 | | - oid, type, |
1274 | | - FSCK_MSG_GITMODULES_BLOB, |
1275 | | - "non-blob found at .gitmodules"); |
| 1311 | + ret |= report(options, oid, type, msg_type, |
| 1312 | + "non-blob found at %s", blob_type); |
1276 | 1313 | free(buf); |
1277 | 1314 | } |
1278 | 1315 |
|
| 1316 | + oidset_clear(blobs_found); |
| 1317 | + oidset_clear(blobs_done); |
| 1318 | + |
| 1319 | + return ret; |
| 1320 | +} |
| 1321 | + |
| 1322 | +int fsck_finish(struct fsck_options *options) |
| 1323 | +{ |
| 1324 | + int ret = 0; |
| 1325 | + |
| 1326 | + ret |= fsck_blobs(&options->gitmodules_found, &options->gitmodules_done, |
| 1327 | + FSCK_MSG_GITMODULES_MISSING, FSCK_MSG_GITMODULES_BLOB, |
| 1328 | + options, ".gitmodules"); |
| 1329 | + ret |= fsck_blobs(&options->gitattributes_found, &options->gitattributes_done, |
| 1330 | + FSCK_MSG_GITATTRIBUTES_MISSING, FSCK_MSG_GITATTRIBUTES_BLOB, |
| 1331 | + options, ".gitattributes"); |
1279 | 1332 |
|
1280 | | - oidset_clear(&options->gitmodules_found); |
1281 | | - oidset_clear(&options->gitmodules_done); |
1282 | 1333 | return ret; |
1283 | 1334 | } |
1284 | 1335 |
|
|
0 commit comments