[Bf-blender-cvs] [88bbb68ad01] master: Add debug tool to check validity of current file *before* saving.

Bastien Montagne noreply at git.blender.org
Fri Apr 20 10:48:52 CEST 2018


Commit: 88bbb68ad01bed841fad9ad26a68510f298e6f3b
Author: Bastien Montagne
Date:   Wed Apr 18 18:22:18 2018 +0200
Branches: master
https://developer.blender.org/rB88bbb68ad01bed841fad9ad26a68510f298e6f3b

Add debug tool to check validity of current file *before* saving.

It is hidden behind the --debug-io flag for now.

Idea is to try to catch broken libraries state in current Main before we
actually write the file on disk, should help catching and understanding
what happens in Spring corruption cases.

===================================================================

M	source/blender/blenloader/BLO_runtime.h
M	source/blender/blenloader/CMakeLists.txt
A	source/blender/blenloader/intern/blend_validate.c
M	source/blender/blenloader/intern/readfile.c
M	source/blender/blenloader/intern/writefile.c

===================================================================

diff --git a/source/blender/blenloader/BLO_runtime.h b/source/blender/blenloader/BLO_runtime.h
index 0a5a7d3a660..c119ea95f66 100644
--- a/source/blender/blenloader/BLO_runtime.h
+++ b/source/blender/blenloader/BLO_runtime.h
@@ -38,11 +38,14 @@ extern "C" {
 #endif
 
 struct BlendFileData;
+struct Main;
 struct ReportList;
 
 int BLO_is_a_runtime(const char *file);
 struct BlendFileData *BLO_read_runtime(const char *file, struct ReportList *reports);
 
+bool BLO_main_validate_libraries(struct Main *bmain, struct ReportList *reports);
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt
index 3d2e8a306de..420f651ee7f 100644
--- a/source/blender/blenloader/CMakeLists.txt
+++ b/source/blender/blenloader/CMakeLists.txt
@@ -46,6 +46,7 @@ set(INC_SYS
 )
 
 set(SRC
+	intern/blend_validate.c
 	intern/readblenentry.c
 	intern/readfile.c
 	intern/runtime.c
diff --git a/source/blender/blenloader/intern/blend_validate.c b/source/blender/blenloader/intern/blend_validate.c
new file mode 100644
index 00000000000..d44497e3145
--- /dev/null
+++ b/source/blender/blenloader/intern/blend_validate.c
@@ -0,0 +1,150 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Bastien Montagne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ */
+
+/** \file blender/blenloader/intern/blend_validate.c
+ *  \ingroup blenloader
+ *
+ * Utils to check/validate a Main is in sane state, only checks relations between datablocks and libraries for now.
+ *
+ * \note Does not *fix* anything, only reports found errors.
+ *
+ */
+
+#include <string.h> // for strrchr strncmp strstr
+
+#include "BLI_utildefines.h"
+
+#include "BLI_blenlib.h"
+#include "BLI_linklist.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "DNA_sdna_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_report.h"
+
+#include "BLO_readfile.h"
+#include "BLO_runtime.h"
+
+#include "readfile.h"
+
+/* Does not fix anything, but checks that all linked data-blocks are still valid (i.e. pointing to the right library). */
+bool BLO_main_validate_libraries(struct Main *bmain, struct ReportList *reports)
+{
+	ListBase mainlist;
+	bool is_valid = true;
+
+	BKE_main_lock(bmain);
+
+	blo_split_main(&mainlist, bmain);
+
+	ListBase *lbarray[MAX_LIBARRAY];
+	int i = set_listbasepointers(bmain, lbarray);
+	while (i--) {
+		for (ID *id = lbarray[i]->first; id != NULL; id = id->next) {
+			if (id->lib != NULL) {
+				is_valid = false;
+				BKE_reportf(reports, RPT_ERROR,
+				            "ID %s is in local database while being linked from library %s!\n", id->name, id->lib->name);
+			}
+		}
+	}
+
+	for (Main *curmain = bmain->next; curmain != NULL; curmain = curmain->next) {
+		Library *curlib = curmain->curlib;
+		if (curlib == NULL) {
+			BKE_reportf(reports, RPT_ERROR,
+			            "Library database with NULL library datablock!\n");
+			continue;
+		}
+
+		BlendHandle *bh = BLO_blendhandle_from_file(curlib->name, reports);
+
+		if (bh == NULL) {
+			continue;
+		}
+
+		i = set_listbasepointers(curmain, lbarray);
+		while (i--) {
+			ID *id = lbarray[i]->first;
+			if (id == NULL) {
+				continue;
+			}
+
+			if (GS(id->name) == ID_LI) {
+				is_valid = false;
+				BKE_reportf(reports, RPT_ERROR,
+				            "Library ID %s in library %s, this should not happen!\n", id->name, curlib->name);
+				continue;
+			}
+
+			int totnames = 0;
+			LinkNode *names = BLO_blendhandle_get_datablock_names(bh, GS(id->name), &totnames);
+			for (; id != NULL; id = id->next) {
+				if (id->lib == NULL) {
+					is_valid = false;
+					BKE_reportf(reports, RPT_ERROR,
+					            "ID %s has NULL lib pointer while being in library %s!\n", id->name, curlib->name);
+					continue;
+				}
+				if (id->lib != curlib) {
+					is_valid = false;
+					BKE_reportf(reports, RPT_ERROR,
+					            "ID %s has mismatched lib pointer!\n", id->name);
+					continue;
+				}
+
+				LinkNode *name = names;
+				for (; name; name = name->next) {
+					char *str_name = (char *)name->link;
+					if (id->name[2] == str_name[0] && STREQ(str_name, id->name + 2)) {
+						break;
+					}
+				}
+
+				if (name == NULL) {
+					is_valid = false;
+					BKE_reportf(reports, RPT_ERROR,
+					            "ID %s not found in library %s anymore!\n", id->name, id->lib->name);
+					continue;
+				}
+			}
+
+			BLI_linklist_free(names, free);
+		}
+
+		BLO_blendhandle_close(bh);
+	}
+
+	blo_join_main(&mainlist);
+
+	BLI_assert(BLI_listbase_is_single(&mainlist));
+	BLI_assert(mainlist.first == (void *)bmain);
+
+	BKE_main_unlock(bmain);
+
+	return is_valid;
+}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 1f1dc8017be..7d73b3050a6 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -552,6 +552,10 @@ void blo_split_main(ListBase *mainlist, Main *main)
 	ListBase *lbarray[MAX_LIBARRAY];
 	i = set_listbasepointers(main, lbarray);
 	while (i--) {
+		ID *id = lbarray[i]->first;
+		if (id == NULL || GS(id->name) == ID_LI) {
+			continue;  /* no ID_LI datablock should ever be linked anyway, but just in case, better be explicit. */
+		}
 		split_libdata(lbarray[i], lib_main_array, lib_main_array_len);
 	}
 
diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c
index 9727f6f0011..549800ae02b 100644
--- a/source/blender/blenloader/intern/writefile.c
+++ b/source/blender/blenloader/intern/writefile.c
@@ -180,6 +180,7 @@
 
 #include "BLO_writefile.h"
 #include "BLO_readfile.h"
+#include "BLO_runtime.h"
 #include "BLO_undofile.h"
 #include "BLO_blend_defs.h"
 
@@ -4094,6 +4095,11 @@ bool BLO_write_file(
 	void     *path_list_backup = NULL;
 	const int path_list_flag = (BKE_BPATH_TRAVERSE_SKIP_LIBRARY | BKE_BPATH_TRAVERSE_SKIP_MULTIFILE);
 
+	if (G.debug & G_DEBUG_IO && mainvar->lock != NULL) {
+		BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *BEFORE* save to disk.");
+		BLO_main_validate_libraries(mainvar, reports);
+	}
+
 	/* open temporary file, so we preserve the original in case we crash */
 	BLI_snprintf(tempname, sizeof(tempname), "%s@", filepath);
 
@@ -4178,6 +4184,11 @@ bool BLO_write_file(
 		return 0;
 	}
 
+	if (G.debug & G_DEBUG_IO && mainvar->lock != NULL) {
+		BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *AFTER* save to disk.");
+		BLO_main_validate_libraries(mainvar, reports);
+	}
+
 	return 1;
 }



More information about the Bf-blender-cvs mailing list