Skip to content

Commit 3a85dc7

Browse files
committed
is_ntfs_dotgit(): speed it up
Previously, this function was written without focusing on speed, intending to make reviewing the code as easy as possible, to avoid any bugs in this critical code. Turns out: we can do much better on both accounts. With this patch, we make it as fast as this developer can make it go: - We avoid the call to `is_dir_sep()` and make all the character comparisons explicit. - We avoid the cost of calling `strncasecmp()` and unroll the test for `.git` and `git~1`, not even using `tolower()` because it is faster to compare against two constant values. - We look for `.git` and `.git~1` first thing, and return early if not found. - We also avoid calling a separate function for detecting chains of spaces and periods. Each of these improvements has a noticeable impact on the speed of `is_ntfs_dotgit()`. Signed-off-by: Johannes Schindelin <[email protected]>
1 parent 91bd465 commit 3a85dc7

File tree

1 file changed

+30
-25
lines changed

1 file changed

+30
-25
lines changed

path.c

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,20 +1288,6 @@ int daemon_avoid_alias(const char *p)
12881288
}
12891289
}
12901290

1291-
static int only_spaces_and_periods(const char *path, size_t len, size_t skip)
1292-
{
1293-
if (len < skip)
1294-
return 0;
1295-
len -= skip;
1296-
path += skip;
1297-
while (len-- > 0) {
1298-
char c = *(path++);
1299-
if (c != ' ' && c != '.')
1300-
return 0;
1301-
}
1302-
return 1;
1303-
}
1304-
13051291
/*
13061292
* On NTFS, we need to be careful to disallow certain synonyms of the `.git/`
13071293
* directory:
@@ -1341,19 +1327,38 @@ static int only_spaces_and_periods(const char *path, size_t len, size_t skip)
13411327
*/
13421328
int is_ntfs_dotgit(const char *name)
13431329
{
1344-
size_t len;
1330+
char c;
13451331

1346-
for (len = 0; ; len++)
1347-
if (!name[len] || name[len] == '\\' || is_dir_sep(name[len]) ||
1348-
name[len] == ':') {
1349-
if (only_spaces_and_periods(name, len, 4) &&
1350-
!strncasecmp(name, ".git", 4))
1351-
return 1;
1352-
if (only_spaces_and_periods(name, len, 5) &&
1353-
!strncasecmp(name, "git~1", 5))
1354-
return 1;
1332+
/*
1333+
* Note that when we don't find `.git` or `git~1` we end up with `name`
1334+
* advanced partway through the string. That's okay, though, as we
1335+
* return immediately in those cases, without looking at `name` any
1336+
* further.
1337+
*/
1338+
c = *(name++);
1339+
if (c == '.') {
1340+
/* .git */
1341+
if (((c = *(name++)) != 'g' && c != 'G') ||
1342+
((c = *(name++)) != 'i' && c != 'I') ||
1343+
((c = *(name++)) != 't' && c != 'T'))
13551344
return 0;
1356-
}
1345+
} else if (c == 'g' || c == 'G') {
1346+
/* git ~1 */
1347+
if (((c = *(name++)) != 'i' && c != 'I') ||
1348+
((c = *(name++)) != 't' && c != 'T') ||
1349+
*(name++) != '~' ||
1350+
*(name++) != '1')
1351+
return 0;
1352+
} else
1353+
return 0;
1354+
1355+
for (;;) {
1356+
c = *(name++);
1357+
if (!c || c == '\\' || c == '/' || c == ':')
1358+
return 1;
1359+
if (c != '.' && c != ' ')
1360+
return 0;
1361+
}
13571362
}
13581363

13591364
static int is_ntfs_dot_generic(const char *name,

0 commit comments

Comments
 (0)