1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
--- hashdb.c.orig 2023-08-27 01:12:34 UTC
+++ hashdb.c
@@ -31,6 +31,7 @@ static hashdb_t *hashdb[HT_SIZE];
static int hashdb_init = 0;
static int hashdb_algo = 0;
static int hashdb_dirty = 0;
+static int new_hashdb = 0;
/* Pivot direction for rebalance */
enum pivot { PIVOT_LEFT, PIVOT_RIGHT };
@@ -68,20 +69,35 @@ int save_hash_database(const char * const restrict dbn
{
FILE *db = NULL;
uint64_t cnt = 0;
+ char *dbtemp;
if (dbname == NULL) goto error_hashdb_null;
LOUD(fprintf(stderr, "save_hash_database('%s')\n", dbname);)
/* Don't save the hash database if it wasn't changed */
if (hashdb_dirty == 0 && destroy == 0) return 0;
if (hashdb_dirty == 1) {
+
errno = 0;
- db = fopen(dbname, "w+b");
+ dbtemp = malloc(strlen(dbname) + 5);
+ if (dbtemp == NULL) goto error_hashdb_alloc;
+ strcpy(dbtemp, dbname);
+ strcat(dbtemp, ".tmp");
+ /* Try to remove any existing temporary database, ignoring errors */
+ remove(dbtemp);
+ db = fopen(dbtemp, "rb");
if (db == NULL) goto error_hashdb_open;
}
- if (write_hashdb_entry(db, NULL, &cnt, destroy) != 0) goto error_hashdb_write;
if (hashdb_dirty == 1) {
+ if (write_hashdb_entry(db, NULL, &cnt, destroy) != 0) goto error_hashdb_write;
fclose(db);
+ if (new_hashdb == 0) {
+ errno = 0;
+ if (remove(dbname) != 0) {
+ if (errno != ENOENT) goto error_hashdb_remove;
+ }
+ }
+ if (rename(dbtemp, dbname) != 0) goto error_hashdb_rename;
LOUD(if (hashdb_dirty == 1) fprintf(stderr, "Wrote %" PRIu64 " items to hash databse '%s'\n", cnt, dbname);)
hashdb_dirty = 0;
}
@@ -92,12 +108,22 @@ error_hashdb_null:
fprintf(stderr, "error: internal failure: NULL pointer for hashdb\n");
return -1;
error_hashdb_open:
- fprintf(stderr, "error: cannot open hashdb '%s' for writing: %s\n", dbname, strerror(errno));
+ fprintf(stderr, "error: cannot open temp hashdb '%s' for writing: %s\n", dbtemp, strerror(errno));
return -2;
error_hashdb_write:
- fprintf(stderr, "error: writing failed to hashdb '%s': %s\n", dbname, strerror(errno));
+ fprintf(stderr, "error: write failed to temp hashdb '%s': %s\n", dbtemp, strerror(errno));
fclose(db);
return -3;
+error_hashdb_alloc:
+ fprintf(stderr, "error: cannot allocate memory for temporary hashdb name\n");
+ return -4;
+error_hashdb_remove:
+ fprintf(stderr, "error: cannot delete old hashdb '%s': %s\n", dbname, strerror(errno));
+ remove(dbtemp);
+ return -5;
+error_hashdb_rename:
+ fprintf(stderr, "error: cannot rename temporary hashdb '%s' to '%s'; leaving it alone: %s\n", dbtemp, dbname, strerror(errno));
+ return -6;
}
@@ -435,31 +461,40 @@ int64_t load_hash_database(char *dbname)
entry->hashcount = hashcount;
}
+ fclose(db);
return linenum - 1;
warn_hashdb_open:
fprintf(stderr, "Creating a new hash database '%s'\n", dbname);
+ fclose(db);
+ new_hashdb = 1;
return 0;
error_hashdb_read:
fprintf(stderr, "error reading hash database '%s': %s\n", dbname, strerror(errno));
+ fclose(db);
return -1;
error_hashdb_header:
fprintf(stderr, "error in header of hash database '%s'\n", dbname);
+ fclose(db);
return -2;
error_hashdb_version:
fprintf(stderr, "error: bad db version %u in hash database '%s'\n", db_ver, dbname);
+ fclose(db);
return -3;
error_hashdb_line:
fprintf(stderr, "\nerror: bad line %" PRId64 " in hash database '%s':\n\n%s\n\n", linenum, dbname, line);
+ fclose(db);
return -4;
error_hashdb_add:
fprintf(stderr, "error: internal failure allocating a hashdb entry\n");
+ fclose(db);
return -5;
error_hashdb_null:
fprintf(stderr, "error: internal failure: NULL pointer for hashdb\n");
return -6;
warn_hashdb_algo:
fprintf(stderr, "warning: hashdb uses a different hash algorithm than selected; not loading\n");
+ fclose(db);
return -7;
}
|