Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit db1edf9

Browse files
committed
Merge pull request libgit2#3491 from libgit2/cmn/config-checksum
Use checksums to detect config file changes
2 parents 76319fa + 3547b12 commit db1edf9

File tree

4 files changed

+59
-36
lines changed

4 files changed

+59
-36
lines changed

src/config_file.c

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,7 @@ typedef struct git_config_file_iter {
7777
(iter) = (tmp))
7878

7979
struct reader {
80-
time_t file_mtime;
81-
size_t file_size;
80+
git_oid checksum;
8281
char *file_path;
8382
git_buf buffer;
8483
char *read_ptr;
@@ -285,7 +284,7 @@ static int config_open(git_config_backend *cfg, git_config_level_t level)
285284

286285
git_buf_init(&reader->buffer, 0);
287286
res = git_futils_readbuffer_updated(
288-
&reader->buffer, b->file_path, &reader->file_mtime, &reader->file_size, NULL);
287+
&reader->buffer, b->file_path, &reader->checksum, NULL);
289288

290289
/* It's fine if the file doesn't exist */
291290
if (res == GIT_ENOTFOUND)
@@ -345,7 +344,7 @@ static int config_refresh(git_config_backend *cfg)
345344
reader = git_array_get(b->readers, i);
346345
error = git_futils_readbuffer_updated(
347346
&reader->buffer, reader->file_path,
348-
&reader->file_mtime, &reader->file_size, &updated);
347+
&reader->checksum, &updated);
349348

350349
if (error < 0 && error != GIT_ENOTFOUND)
351350
return error;
@@ -1618,7 +1617,7 @@ static int read_on_variable(
16181617
git_buf_init(&r->buffer, 0);
16191618

16201619
result = git_futils_readbuffer_updated(
1621-
&r->buffer, r->file_path, &r->file_mtime, &r->file_size, NULL);
1620+
&r->buffer, r->file_path, &r->checksum, NULL);
16221621

16231622
if (result == 0) {
16241623
result = config_read(parse_data->values, parse_data->cfg_file, r, parse_data->level, parse_data->depth+1);
@@ -1894,7 +1893,7 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
18941893
} else {
18951894
/* Lock the file */
18961895
if ((result = git_filebuf_open(
1897-
&file, cfg->file_path, 0, GIT_CONFIG_FILE_MODE)) < 0) {
1896+
&file, cfg->file_path, GIT_FILEBUF_HASH_CONTENTS, GIT_CONFIG_FILE_MODE)) < 0) {
18981897
git_buf_free(&reader->buffer);
18991898
return result;
19001899
}
@@ -1945,10 +1944,6 @@ static int config_write(diskfile_backend *cfg, const char *key, const regex_t *p
19451944
git_buf_attach(&cfg->locked_content, git_buf_detach(&buf), len);
19461945
} else {
19471946
git_filebuf_write(&file, git_buf_cstr(&buf), git_buf_len(&buf));
1948-
1949-
/* refresh stats - if this errors, then commit will error too */
1950-
(void)git_filebuf_stats(&reader->file_mtime, &reader->file_size, &file);
1951-
19521947
result = git_filebuf_commit(&file);
19531948
}
19541949

src/fileops.c

Lines changed: 32 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -153,13 +153,15 @@ int git_futils_readbuffer_fd(git_buf *buf, git_file fd, size_t len)
153153
}
154154

155155
int git_futils_readbuffer_updated(
156-
git_buf *buf, const char *path, time_t *mtime, size_t *size, int *updated)
156+
git_buf *out, const char *path, git_oid *checksum, int *updated)
157157
{
158+
int error;
158159
git_file fd;
159160
struct stat st;
160-
bool changed = false;
161+
git_buf buf = GIT_BUF_INIT;
162+
git_oid checksum_new;
161163

162-
assert(buf && path && *path);
164+
assert(out && path && *path);
163165

164166
if (updated != NULL)
165167
*updated = 0;
@@ -178,45 +180,50 @@ int git_futils_readbuffer_updated(
178180
return -1;
179181
}
180182

181-
/*
182-
* If we were given a time and/or a size, we only want to read the file
183-
* if it has been modified.
184-
*/
185-
if (size && *size != (size_t)st.st_size)
186-
changed = true;
187-
if (mtime && *mtime != (time_t)st.st_mtime)
188-
changed = true;
189-
if (!size && !mtime)
190-
changed = true;
191-
192-
if (!changed) {
193-
return 0;
194-
}
195-
196-
if (mtime != NULL)
197-
*mtime = st.st_mtime;
198-
if (size != NULL)
199-
*size = (size_t)st.st_size;
200-
201183
if ((fd = git_futils_open_ro(path)) < 0)
202184
return fd;
203185

204-
if (git_futils_readbuffer_fd(buf, fd, (size_t)st.st_size) < 0) {
186+
if (git_futils_readbuffer_fd(&buf, fd, (size_t)st.st_size) < 0) {
205187
p_close(fd);
206188
return -1;
207189
}
208190

209191
p_close(fd);
210192

193+
if ((error = git_hash_buf(&checksum_new, buf.ptr, buf.size)) < 0) {
194+
git_buf_free(&buf);
195+
return error;
196+
}
197+
198+
/*
199+
* If we were given a checksum, we only want to use it if it's different
200+
*/
201+
if (checksum && !git_oid__cmp(checksum, &checksum_new)) {
202+
git_buf_free(&buf);
203+
if (updated)
204+
*updated = 0;
205+
206+
return 0;
207+
}
208+
209+
/*
210+
* If we're here, the file did change, or the user didn't have an old version
211+
*/
212+
if (checksum)
213+
git_oid_cpy(checksum, &checksum_new);
214+
211215
if (updated != NULL)
212216
*updated = 1;
213217

218+
git_buf_swap(out, &buf);
219+
git_buf_free(&buf);
220+
214221
return 0;
215222
}
216223

217224
int git_futils_readbuffer(git_buf *buf, const char *path)
218225
{
219-
return git_futils_readbuffer_updated(buf, path, NULL, NULL, NULL);
226+
return git_futils_readbuffer_updated(buf, path, NULL, NULL);
220227
}
221228

222229
int git_futils_writebuffer(

src/fileops.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "path.h"
1414
#include "pool.h"
1515
#include "strmap.h"
16+
#include "oid.h"
1617

1718
/**
1819
* Filebuffer methods
@@ -21,7 +22,7 @@
2122
*/
2223
extern int git_futils_readbuffer(git_buf *obj, const char *path);
2324
extern int git_futils_readbuffer_updated(
24-
git_buf *obj, const char *path, time_t *mtime, size_t *size, int *updated);
25+
git_buf *obj, const char *path, git_oid *checksum, int *updated);
2526
extern int git_futils_readbuffer_fd(git_buf *obj, git_file fd, size_t len);
2627

2728
extern int git_futils_writebuffer(

tests/config/stress.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,3 +107,23 @@ void test_config_stress__complex(void)
107107

108108
git_config_free(config);
109109
}
110+
111+
void test_config_stress__quick_write(void)
112+
{
113+
git_config *config_w, *config_r;
114+
const char *path = "./config-quick-write";
115+
const char *key = "quick.write";
116+
int32_t i;
117+
118+
/* Create an external writer for one instance with the other one */
119+
cl_git_pass(git_config_open_ondisk(&config_w, path));
120+
cl_git_pass(git_config_open_ondisk(&config_r, path));
121+
122+
/* Write and read in the same second (repeat to increase the chance of it happening) */
123+
for (i = 0; i < 10; i++) {
124+
int32_t val;
125+
cl_git_pass(git_config_set_int32(config_w, key, i));
126+
cl_git_pass(git_config_get_int32(&val, config_r, key));
127+
cl_assert_equal_i(i, val);
128+
}
129+
}

0 commit comments

Comments
 (0)