Skip to content

Commit 72d8455

Browse files
committed
Add using-unsupported-Windows-file-name.ql
Added under `not-tested-queries` because variant analysis did not yield any results.
1 parent 9611c34 commit 72d8455

File tree

1 file changed

+69
-0
lines changed

1 file changed

+69
-0
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
/**
2+
* Finds files and folders whose name might not be a valid file name on the Windows operating system.
3+
* Windows has more restrictions on file names than Linux. Therefore these files and folders might
4+
* make it difficult or even impossible for users to work on this project on Windows.
5+
*
6+
* @kind problem
7+
*/
8+
9+
import java
10+
11+
predicate isReservedName(string name) {
12+
name = [
13+
// https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions
14+
"CON",
15+
"PRN",
16+
"AUX",
17+
"NUL",
18+
// Consider superscript numbers as well, see also https://github.com/python/cpython/blob/2016bc54a22b83d0ca9174b64257cc7bb67a0916/Lib/pathlib.py#L107-L108
19+
["COM", "LPT"] + ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "¹", "²", "³"],
20+
// https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilea#consoles
21+
"CONIN$",
22+
"CONOUT$",
23+
]
24+
}
25+
26+
bindingset[s]
27+
string trimTrailing(string s) {
28+
if (s.charAt(s.length() - 1) = " ") then (
29+
exists(int i |
30+
(i = 0 or s.charAt(i - 1) != " ")
31+
and forall(int higherIndex |
32+
higherIndex = [(i + 1)..(s.length() - 1)]
33+
|
34+
s.charAt(higherIndex) = " "
35+
)
36+
and result = s.prefix(i)
37+
)
38+
) else (
39+
result = s
40+
)
41+
}
42+
43+
bindingset[name]
44+
string transformName(string name) {
45+
// TODO: toUpperCase() uses Unicode case conversion rules which could lead to false positives
46+
// because Windows only performs ASCII case conversion?
47+
exists(string upper | upper = name.toUpperCase() |
48+
if (exists(upper.indexOf("."))) then (
49+
// Remove 'extension', starting at the first '.'
50+
result = trimTrailing(upper.prefix(upper.indexOf(".", 0, 0)))
51+
) else (
52+
// No need to trim trailing whitespace here; check below forbids trailing space
53+
result = upper
54+
)
55+
)
56+
}
57+
58+
from Container f, string name
59+
where
60+
name = f.getBaseName()
61+
and (
62+
// Reserved characters, see https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions
63+
exists(name.indexOf(["<", ">", ":", "\"", "/", "\\", "|", "?", "*"]))
64+
or exists(int c | c.toUnicode() = name.charAt(_) | c <= 31)
65+
or isReservedName(transformName(name))
66+
// Trailing period or space, see https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions
67+
or name.matches(["%.", "% "])
68+
)
69+
select f, "Uses name '" + name + "' which is an unsupported file name under Windows"

0 commit comments

Comments
 (0)