{"thread":{"id":"4085","subject":"[PATCH] config: mmap() the contents of the config file","startedAt":"2006-05-06T23:04:35Z","lastAt":"2006-05-07T11:40:53Z","messageCount":2,"participants":["Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"19627","messageId":"Pine.LNX.4.63.0605070103270.26358@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"4085","inReplyTo":null,"subject":"[PATCH] config: mmap() the contents of the config file","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-05-06T23:04:35Z","receivedAt":"2006-05-06T23:04:35Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"\nThis makes it possible to rewrite the config without accessing the config\nfile twice.\n\nSigned-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de>\n\n---\n\n\tLinus said he'd prefer this.\n\n\tOne thing I am not quite sure about: should we remember the file's \n\tmtime and check it to see if the config file has changed since we \n\tmmap()ed it?\n\n\tBTW this patch is on top of next, and does not yet contain Sean's\n\tbug fix.\n\n config.c |  102 ++++++++++++++++++++++++++++++++------------------------------\n 1 files changed, 52 insertions(+), 50 deletions(-)\n\ndiff --git a/config.c b/config.c\nindex 87fb220..05d4d8c 100644\n--- a/config.c\n+++ b/config.c\n@@ -10,31 +10,27 @@ #include <regex.h>\n \n #define MAXNAME (256)\n \n-static FILE *config_file;\n+static const char *contents = NULL;\n+static int config_length = 0, config_offset = 0;\n static const char *config_file_name;\n static int config_linenr;\n static int get_next_char(void)\n {\n \tint c;\n-\tFILE *f;\n \n \tc = '\\n';\n-\tif ((f = config_file) != NULL) {\n-\t\tc = fgetc(f);\n-\t\tif (c == '\\r') {\n+\tif (config_offset < config_length) {\n+\t\tc = contents[config_offset++];\n+\t\tif (c == '\\r' && config_offset < config_length) {\n \t\t\t/* DOS like systems */\n-\t\t\tc = fgetc(f);\n+\t\t\tc = contents[config_offset++];\n \t\t\tif (c != '\\n') {\n-\t\t\t\tungetc(c, f);\n+\t\t\t\tconfig_offset--;\n \t\t\t\tc = '\\r';\n \t\t\t}\n \t\t}\n \t\tif (c == '\\n')\n \t\t\tconfig_linenr++;\n-\t\tif (c == EOF) {\n-\t\t\tconfig_file = NULL;\n-\t\t\tc = '\\n';\n-\t\t}\n \t}\n \treturn c;\n }\n@@ -162,7 +158,7 @@ static int git_parse_file(config_fn_t fn\n \t\tint c = get_next_char();\n \t\tif (c == '\\n') {\n \t\t\t/* EOF? */\n-\t\t\tif (!config_file)\n+\t\t\tif (config_offset >= config_length)\n \t\t\t\treturn 0;\n \t\t\tcomment = 0;\n \t\t\tcontinue;\n@@ -258,18 +254,41 @@ int git_default_config(const char *var, \n \n int git_config_from_file(config_fn_t fn, const char *filename)\n {\n-\tint ret;\n-\tFILE *f = fopen(filename, \"r\");\n+\tint ret, in_fd;\n+\n+\tconfig_offset = 0;\n+\n+\tif (contents) {\n+\t\tif (!strcmp(config_file_name, filename))\n+\t\t\treturn git_parse_file(fn);\n+\t\tmunmap((char*)contents, config_length);\n+\t\tfree((char*)config_file_name);\n+\t}\n+\n+\tin_fd = open(filename, O_RDONLY);\n \n \tret = -1;\n-\tif (f) {\n-\t\tconfig_file = f;\n-\t\tconfig_file_name = filename;\n+\tif (in_fd > 0) {\n+\t\tstruct stat st;\n+\n+\t\tfstat(in_fd, &st);\n+\t\tconfig_length = st.st_size;\n+\t\tcontents = mmap(NULL, config_length, PROT_READ, MAP_PRIVATE,\n+\t\t\t\tin_fd, 0);\n+\t\tclose(in_fd);\n+\n+\t\tconfig_file_name = strdup(filename);\n \t\tconfig_linenr = 1;\n+\t\tconfig_offset = 0;\n \t\tret = git_parse_file(fn);\n-\t\tfclose(f);\n-\t\tconfig_file_name = NULL;\n+\t} else {\n+\t\tcontents = NULL;\n+\t\tconfig_length = 0;\n+\t\tif (in_fd < 0 && ENOENT != errno )\n+\t\t\tdie(\"opening %s: %s\", config_file_name,\n+\t\t\t\t\tstrerror(errno));\n \t}\n+\n \treturn ret;\n }\n \n@@ -317,7 +336,7 @@ static int store_aux(const char* key, co\n \t\t\t\treturn 1;\n \t\t\t}\n \n-\t\t\tstore.offset[store.seen] = ftell(config_file);\n+\t\t\tstore.offset[store.seen] = config_offset;\n \t\t\tstore.seen++;\n \t\t}\n \t\tbreak;\n@@ -327,12 +346,12 @@ static int store_aux(const char* key, co\n \t\t\tbreak;\n \t\t} else\n \t\t\t/* do not increment matches: this is no match */\n-\t\t\tstore.offset[store.seen] = ftell(config_file);\n+\t\t\tstore.offset[store.seen] = config_offset;\n \t\t/* fallthru */\n \tcase SECTION_END_SEEN:\n \tcase START:\n \t\tif (matches(key, value)) {\n-\t\t\tstore.offset[store.seen] = ftell(config_file);\n+\t\t\tstore.offset[store.seen] = config_offset;\n \t\t\tstore.state = KEY_SEEN;\n \t\t\tstore.seen++;\n \t\t} else if (strrchr(key, '.') - key == store.baselen &&\n@@ -367,10 +386,9 @@ static void store_write_pair(int fd, con\n \twrite(fd, \"\\n\", 1);\n }\n \n-static int find_beginning_of_line(const char* contents, int size,\n-\tint offset_, int* found_bracket)\n+static int find_beginning_of_line(int offset_, int* found_bracket)\n {\n-\tint equal_offset = size, bracket_offset = size;\n+\tint equal_offset = config_length, bracket_offset = config_length;\n \tint offset;\n \n \tfor (offset = offset_-2; offset > 0 \n@@ -420,7 +438,7 @@ int git_config_set_multivar(const char* \n \tconst char* value_regex, int multi_replace)\n {\n \tint i;\n-\tint fd, in_fd;\n+\tint fd;\n \tint ret;\n \tchar* config_filename = strdup(git_path(\"config\"));\n \tchar* lock_file = strdup(git_path(\"config.lock\"));\n@@ -471,18 +489,9 @@ int git_config_set_multivar(const char* \n \t/*\n \t * If .git/config does not exist yet, write a minimal version.\n \t */\n-\tin_fd = open(config_filename, O_RDONLY);\n-\tif ( in_fd < 0 ) {\n+\tif (!contents) {\n \t\tfree(store.key);\n \n-\t\tif ( ENOENT != errno ) {\n-\t\t\terror(\"opening %s: %s\", config_filename,\n-\t\t\t      strerror(errno));\n-\t\t\tclose(fd);\n-\t\t\tunlink(lock_file);\n-\t\t\tret = 3; /* same as \"invalid config file\" */\n-\t\t\tgoto out_free;\n-\t\t}\n \t\t/* if nothing to unset, error out */\n \t\tif (value == NULL) {\n \t\t\tclose(fd);\n@@ -494,9 +503,7 @@ int git_config_set_multivar(const char* \n \t\tstore.key = (char*)key;\n \t\tstore_write_section(fd, key);\n \t\tstore_write_pair(fd, key, value);\n-\t} else{\n-\t\tstruct stat st;\n-\t\tchar* contents;\n+\t} else {\n \t\tint i, copy_begin, copy_end, new_line = 0;\n \n \t\tif (value_regex == NULL)\n@@ -555,23 +562,17 @@ int git_config_set_multivar(const char* \n \t\t\tgoto out_free;\n \t\t}\n \n-\t\tfstat(in_fd, &st);\n-\t\tcontents = mmap(NULL, st.st_size, PROT_READ,\n-\t\t\tMAP_PRIVATE, in_fd, 0);\n-\t\tclose(in_fd);\n-\n \t\tif (store.seen == 0)\n \t\t\tstore.seen = 1;\n \n \t\tfor (i = 0, copy_begin = 0; i < store.seen; i++) {\n \t\t\tif (store.offset[i] == 0) {\n-\t\t\t\tstore.offset[i] = copy_end = st.st_size;\n+\t\t\t\tstore.offset[i] = copy_end = config_length;\n \t\t\t} else if (store.state != KEY_SEEN) {\n \t\t\t\tcopy_end = store.offset[i];\n \t\t\t} else\n \t\t\t\tcopy_end = find_beginning_of_line(\n-\t\t\t\t\tcontents, st.st_size,\n-\t\t\t\t\tstore.offset[i]-2, &new_line);\n+\t\t\t\t\tstore.offset[i] - 2, &new_line);\n \n \t\t\t/* write the first part of the config */\n \t\t\tif (copy_end > copy_begin) {\n@@ -591,11 +592,12 @@ int git_config_set_multivar(const char* \n \t\t}\n \n \t\t/* write the rest of the config */\n-\t\tif (copy_begin < st.st_size)\n+\t\tif (copy_begin < config_length)\n \t\t\twrite(fd, contents + copy_begin,\n-\t\t\t\tst.st_size - copy_begin);\n+\t\t\t\tconfig_length - copy_begin);\n \n-\t\tmunmap(contents, st.st_size);\n+\t\tmunmap((char*)contents, config_length);\n+\t\tcontents = NULL;\n \t\tunlink(config_filename);\n \t}\n \n-- \n1.3.1.g5545a\n"},{"id":"19647","messageId":"Pine.LNX.4.63.0605071339320.2528@wbgn013.biozentrum.uni-wuerzburg.de","threadId":"4085","inReplyTo":"Pine.LNX.4.63.0605070103270.26358@wbgn013.biozentrum.uni-wuerzburg.de","subject":"Re: [PATCH] config: mmap() the contents of the config file","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2006-05-07T11:40:53Z","receivedAt":"2006-05-07T11:40:53Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 7 May 2006, Johannes Schindelin wrote:\n\n> This makes it possible to rewrite the config without accessing the config\n> file twice.\n\nSince commit c2b9e699, this is needed, too:\n\ndiff --git a/config.c b/config.c\nindex 59006fa..30effe3 100644\n--- a/config.c\n+++ b/config.c\n@@ -362,7 +362,7 @@ static int store_aux(const char* key, co\n \t\t} else if (strrchr(key, '.') - key == store.baselen &&\n \t\t\t      !strncmp(key, store.key, store.baselen)) {\n \t\t\t\t\tstore.state = SECTION_SEEN;\n-\t\t\t\t\tstore.offset[store.seen] = ftell(config_file);\n+\t\t\t\t\tstore.offset[store.seen] = config_offset;\n \t\t}\n \t}\n \treturn 0;\n-- \n1.3.2.g4e38b-dirty\n"}]}