{"thread":{"id":"2680","subject":"[PATCH 3/4] init-db: check template and repository format.","startedAt":"2005-11-26T01:15:13Z","lastAt":"2005-11-26T01:15:13Z","messageCount":1,"participants":["Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"12750","messageId":"7v7jawgqfy.fsf@assigned-by-dhcp.cox.net","threadId":"2680","inReplyTo":null,"subject":"[PATCH 3/4] init-db: check template and repository format.","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2005-11-26T01:15:13Z","receivedAt":"2005-11-26T01:15:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This makes init-db repository version aware.\n\nIt checks if an existing config file says the repository being\nreinitialized is of a wrong version and aborts before doing\nfurther harm.\n\nWhen copying the templates, it makes sure the they are of the\nright repository format version.  Otherwise the templates are\nignored with an warning message.\n\nIt copies the templates before creating the HEAD, and if the\nconfig file is copied from the template directory, reads it,\nprimarily to pick up the value of core.symrefsonly.\n\nIt changes the way the result of the filemode reliability test\nis written to the configuration file using git_config_set().\nThe test is done even if the config file was copied from the\ntemplates.\n\nAnd finally, our own repository format version is written to the\nconfig file.\n\nSigned-off-by: Junio C Hamano <junkio@cox.net>\n\n---\n\n cache.h   |    1 +\n config.c  |   16 ++++++++---\n init-db.c |   89 +++++++++++++++++++++++++++++++++++--------------------------\n 3 files changed, 64 insertions(+), 42 deletions(-)\n\napplies-to: 3478f0c15277931430f7db669a8004da52c1a887\n654494dfddb135db6187a3f00917e24c1dbcd569\ndiff --git a/cache.h b/cache.h\nindex de53f41..61bf884 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -387,6 +387,7 @@ extern int gitfakemunmap(void *start, si\n \n typedef int (*config_fn_t)(const char *, const char *);\n extern int git_default_config(const char *, const char *);\n+extern int git_config_from_file(config_fn_t fn, const char *);\n extern int git_config(config_fn_t fn);\n extern int git_config_int(const char *, const char *);\n extern int git_config_bool(const char *, const char *);\ndiff --git a/config.c b/config.c\nindex 5cc8535..0c43d76 100644\n--- a/config.c\n+++ b/config.c\n@@ -11,6 +11,7 @@\n #define MAXNAME (256)\n \n static FILE *config_file;\n+static char *config_file_name;\n static int config_linenr;\n static int get_next_char(void)\n {\n@@ -186,7 +187,7 @@ static int git_parse_file(config_fn_t fn\n \t\tif (get_value(fn, var, baselen+1) < 0)\n \t\t\tbreak;\n \t}\n-\tdie(\"bad config file line %d\", config_linenr);\n+\tdie(\"bad config file line %d in %s\", config_linenr, config_file_name);\n }\n \n int git_config_int(const char *name, const char *value)\n@@ -197,7 +198,7 @@ int git_config_int(const char *name, con\n \t\tif (!*end)\n \t\t\treturn val;\n \t}\n-\tdie(\"bad config value for '%s'\", name);\n+\tdie(\"bad config value for '%s' in %s\", name, config_file_name);\n }\n \n int git_config_bool(const char *name, const char *value)\n@@ -240,21 +241,28 @@ int git_default_config(const char *var, \n \treturn 0;\n }\n \n-int git_config(config_fn_t fn)\n+int git_config_from_file(config_fn_t fn, const char *filename)\n {\n \tint ret;\n-\tFILE *f = fopen(git_path(\"config\"), \"r\");\n+\tFILE *f = fopen(filename, \"r\");\n \n \tret = -1;\n \tif (f) {\n \t\tconfig_file = f;\n+\t\tconfig_file_name = filename;\n \t\tconfig_linenr = 1;\n \t\tret = git_parse_file(fn);\n \t\tfclose(f);\n+\t\tconfig_file_name = NULL;\n \t}\n \treturn ret;\n }\n \n+int git_config(config_fn_t fn)\n+{\n+\treturn git_config_from_file(fn, git_path(\"config\"));\n+}\n+\n /*\n  * Find all the stuff for git_config_set() below.\n  */\ndiff --git a/init-db.c b/init-db.c\nindex bd88291..8195b68 100644\n--- a/init-db.c\n+++ b/init-db.c\n@@ -132,6 +132,23 @@ static void copy_templates(const char *g\n \t\treturn;\n \t}\n \n+\t/* Make sure that template is from the correct vintage */\n+\tstrcpy(template_path + template_len, \"config\");\n+\trepository_format_version = 0;\n+\tgit_config_from_file(check_repository_format_version,\n+\t\t\t     template_path);\n+\ttemplate_path[template_len] = 0;\n+\n+\tif (repository_format_version &&\n+\t    repository_format_version != GIT_REPO_VERSION) {\n+\t\tfprintf(stderr, \"warning: not copying templates of \"\n+\t\t\t\"a wrong format version %d from '%s'\\n\",\n+\t\t\trepository_format_version,\n+\t\t\ttemplate_dir);\n+\t\tclosedir(dir);\n+\t\treturn;\n+\t}\n+\n \tmemcpy(path, git_dir, len);\n \tpath[len] = 0;\n \tcopy_templates_1(path, len,\n@@ -140,12 +157,13 @@ static void copy_templates(const char *g\n \tclosedir(dir);\n }\n \n-static void create_default_files(const char *git_dir,\n-\t\t\t\t char *template_path)\n+static void create_default_files(const char *git_dir, char *template_path)\n {\n \tunsigned len = strlen(git_dir);\n \tstatic char path[PATH_MAX];\n \tunsigned char sha1[20];\n+\tstruct stat st1;\n+\tchar repo_version_string[10];\n \n \tif (len > sizeof(path)-50)\n \t\tdie(\"insane git directory %s\", git_dir);\n@@ -164,6 +182,15 @@ static void create_default_files(const c\n \tstrcpy(path + len, \"refs/tags\");\n \tsafe_create_dir(path);\n \n+\t/* First copy the templates -- we might have the default\n+\t * config file there, in which case we would want to read\n+\t * from it after installing.\n+\t */\n+\tpath[len] = 0;\n+\tcopy_templates(path, len, template_path);\n+\n+\tgit_config(git_default_config);\n+\n \t/*\n \t * Create the default symlink from \".git/HEAD\" to the \"master\"\n \t * branch, if it does not exist yet.\n@@ -173,44 +200,22 @@ static void create_default_files(const c\n \t\tif (create_symref(path, \"refs/heads/master\") < 0)\n \t\t\texit(1);\n \t}\n-\tpath[len] = 0;\n-\tcopy_templates(path, len, template_path);\n \n-\t/*\n-\t * Find out if we can trust the executable bit.\n-\t */\n-\tsafe_create_dir(path);\n+\t/* This forces creation of new config file */\n+\tsprintf(repo_version_string, \"%d\", GIT_REPO_VERSION);\n+\tgit_config_set(\"core.repositoryformatversion\", repo_version_string);\n+\n+\tpath[len] = 0;\n \tstrcpy(path + len, \"config\");\n-\tif (access(path, R_OK) < 0) {\n-\t\tstatic const char contents[] =\n-\t\t\t\"#\\n\"\n-\t\t\t\"# This is the config file\\n\"\n-\t\t\t\"#\\n\"\n-\t\t\t\"\\n\"\n-\t\t\t\"; core variables\\n\"\n-\t\t\t\"[core]\\n\"\n-\t\t\t\"\t; Don't trust file modes\\n\"\n-\t\t\t\"\tfilemode = false\\n\"\n-\t\t\t\"\\n\";\n-\t\tFILE *config = fopen(path, \"w\");\n-\t\tstruct stat st;\n-\n-\t\tif (!config)\n-\t\t\tdie(\"Can not write to %s?\", path);\n-\n-\t\tfwrite(contents, sizeof(contents)-1, 1, config);\n-\n-\t\tfclose(config);\n-\n-\t\tif (!lstat(path, &st)) {\n-\t\t\tstruct stat st2;\n-\t\t\tif (!chmod(path, st.st_mode ^ S_IXUSR) &&\n-\t\t\t\t\t!lstat(path, &st2) &&\n-\t\t\t\t\tst.st_mode != st2.st_mode)\n-\t\t\t\tunlink(path);\n-\t\t\telse\n-\t\t\t\tfprintf(stderr, \"Ignoring file modes\\n\");\n-\t\t}\n+\n+\t/* Check filemode trustability */\n+\tif (!lstat(path, &st1)) {\n+\t\tstruct stat st2;\n+\t\tint filemode = (!chmod(path, st1.st_mode ^ S_IXUSR) &&\n+\t\t\t\t!lstat(path, &st2) &&\n+\t\t\t\tst1.st_mode != st2.st_mode);\n+\t\tgit_config_set(\"core.filemode\",\n+\t\t\t       filemode ? \"true\" : \"false\");\n \t}\n }\n \n@@ -249,6 +254,14 @@ int main(int argc, char **argv)\n \t\tfprintf(stderr, \"defaulting to local storage area\\n\");\n \t}\n \tsafe_create_dir(git_dir);\n+\n+\t/* Check to see if the repository version is right.\n+\t * Note that a newly created repository does not have\n+\t * config file, so this will not fail.  What we are catching\n+\t * is an attempt to reinitialize new repository with an old tool.\n+\t */\n+\tcheck_repository_format();\n+\n \tcreate_default_files(git_dir, template_dir);\n \n \t/*\n---\n0.99.9.GIT\n"}]}