-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Expand file tree
/
Copy pathFilePath.qll
More file actions
88 lines (81 loc) · 2.75 KB
/
FilePath.qll
File metadata and controls
88 lines (81 loc) · 2.75 KB
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
/** Provides a utility for normalizing filepaths. */
/**
* A filepath that should be normalized.
*
* Extend to provide additional strings that should be normalized as filepaths.
*/
abstract class NormalizableFilepath extends string {
bindingset[this]
NormalizableFilepath() { any() }
/** Gets the `i`th path component of this string. */
private string getComponent(int i) { result = this.splitAt("/", i) }
/** Gets the number of path components of thi string. */
private int getNumComponents() { result = strictcount(int i | exists(this.getComponent(i))) }
/** In the normalized path starting from component `i`, counts the number of `..` segments that path starts with. */
private int dotdotCountFrom(int i) {
result = 0 and i = this.getNumComponents()
or
exists(string c | c = this.getComponent(i) |
if c = ""
then result = this.dotdotCountFrom(i + 1)
else
if c = "."
then result = this.dotdotCountFrom(i + 1)
else
if c = ".."
then result = this.dotdotCountFrom(i + 1) + 1
else result = (this.dotdotCountFrom(i + 1) - 1).maximum(0)
)
}
/** In the normalized path up to (excluding) component `i`, counts the number of non-`..` segments that path ends with. */
private int segmentCountUntil(int i) {
result = 0 and i = 0
or
exists(string c | c = this.getComponent(i - 1) |
if c = ""
then result = this.segmentCountUntil(i - 1)
else
if c = "."
then result = this.segmentCountUntil(i - 1)
else
if c = ".."
then result = (this.segmentCountUntil(i - 1) - 1).maximum(0)
else result = this.segmentCountUntil(i - 1) + 1
)
}
/** Gets the `i`th component if that component should be included in the normalized path. */
private string part(int i) {
result = this.getComponent(i) and
result != "." and
if result = ""
then i = 0
else (
result != ".." and
0 = this.dotdotCountFrom(i + 1)
or
result = ".." and
0 = this.segmentCountUntil(i)
)
}
/**
* Gets the normalized filepath for this string.
*
* Normalizes `..` paths, `.` paths, and multiple `/`s as much as possible, but does not normalize case, resolve symlinks, or make relative paths absolute.
*
* The normalized path will be absolute (begin with `/`) if and only if the original path is.
*
* The normalized path will not have a trailing `/`.
*
* Only `/` is treated as a path separator.
*/
string getNormalizedPath() {
exists(string norm | norm = concat(string s, int i | s = this.part(i) | s, "/" order by i) |
if norm != ""
then result = norm
else
if this.matches("/%")
then result = "/"
else result = "."
)
}
}