@@ -98,6 +98,20 @@ struct AutoReadLock {
98
98
ReadWriteLock& lock_;
99
99
};
100
100
101
+ /* *
102
+ * Auto lock for writes on a RW mutex
103
+ */
104
+ struct AutoWriteLock {
105
+ AutoWriteLock (ReadWriteLock& lock) : lock_(lock) {
106
+ lock_.write_lock ();
107
+ }
108
+ ~AutoWriteLock () {
109
+ lock_.unlock ();
110
+ }
111
+
112
+ ReadWriteLock& lock_;
113
+ };
114
+
101
115
// //////////////////////////////////////////////////////////////////////////////
102
116
// Global db accessors
103
117
// //////////////////////////////////////////////////////////////////////////////
@@ -142,14 +156,23 @@ static double dc_get_time() {
142
156
* then stores off those results.
143
157
*/
144
158
static dircontext_t *dc_find_or_populate (const char *path) {
159
+ auto &db = dir_db ();
160
+
145
161
{
146
162
AutoReadLock lock (dir_db_lock ());
147
- auto &db = dir_db ();
148
163
if (auto ent = db.find ((char *)path); ent != db.end ()) {
149
164
return dc_build_around_ent (path, ent->second );
150
165
}
151
166
}
152
167
168
+ AutoWriteLock lock (dir_db_lock ());
169
+
170
+ // before we try and cache it, check if it was cached while we were acquiring our
171
+ // write lock (avoid TOCTOU condition)
172
+ if (auto ent = db.find ((char *)path); ent != db.end ()) {
173
+ return dc_build_around_ent (path, ent->second );
174
+ }
175
+
153
176
// read contents and store into the db.
154
177
dirent **namelist = nullptr ;
155
178
// Grab all dir entries
@@ -172,9 +195,7 @@ static dircontext_t *dc_find_or_populate(const char *path) {
172
195
free (namelist);
173
196
174
197
// Insert into the db
175
- dir_db_lock ().write_lock ();
176
- dir_db ().insert ({path, dent});
177
- dir_db_lock ().unlock ();
198
+ db.insert ({path, dent});
178
199
179
200
// Finally build a returnable value
180
201
return dc_build_around_ent (path, dent);
@@ -189,6 +210,7 @@ static void dc_close(dircontext_t *context) {
189
210
190
211
auto old_refs = context->ent ->nref .fetch_sub (1 ); // Dec refcount
191
212
if (old_refs == 1 ) {
213
+ delete context->ent ;
192
214
dir_db ().erase (context->key );
193
215
}
194
216
@@ -326,7 +348,7 @@ static PathMod pathmatchDetour(const char *in, char **out, bool allow_basename_m
326
348
if (dir) {
327
349
struct dirent *ent;
328
350
while (ent = dircache_readdir (dir)) {
329
- if (!strncasecmp (ent->d_name , start, len)) {
351
+ if (!strncasecmp (ent->d_name , start, len) && !ent-> d_name [len] ) {
330
352
// fill in the correct capitalization
331
353
memcpy (start, ent->d_name , len);
332
354
matched = true ;
@@ -338,7 +360,9 @@ static PathMod pathmatchDetour(const char *in, char **out, bool allow_basename_m
338
360
339
361
if (!matched) break ; // this component didn't match, so certainly no further ones will
340
362
341
- start += len + 1 ; // next component
363
+ // next component
364
+ start += len;
365
+ if (*start) start += 1 ; // skip slash
342
366
}
343
367
344
368
*out = buf;
0 commit comments