@@ -7,19 +7,28 @@ package kotlinx.datetime.internal
7
7
8
8
internal class TzdbOnFilesystem (defaultTzdbPath : Path ? = null ): TimeZoneDatabase {
9
9
10
- private val tzdbPath = tzdbPaths(defaultTzdbPath).find {
11
- it.chaseSymlinks().check()?.isDirectory == true
10
+ internal val tzdbPath = tzdbPaths(defaultTzdbPath).find { path ->
11
+ tabPaths.any { path.containsFile(it) }
12
12
} ? : throw IllegalStateException (" Could not find the path to the timezone database" )
13
13
14
- override fun rulesForId (id : String ): TimeZoneRules =
15
- readTzFile(tzdbPath.resolve(Path .fromString(id)).readBytes()).toTimeZoneRules()
14
+ override fun rulesForId (id : String ): TimeZoneRules {
15
+ val idAsPath = Path .fromString(id)
16
+ require(! idAsPath.isAbsolute) { " Timezone ID '$idAsPath ' must not begin with a '/'" }
17
+ require(idAsPath.components.none { it == " .." }) { " '$idAsPath ' must not contain '..' as a component" }
18
+ val file = Path (tzdbPath.isAbsolute, tzdbPath.components + idAsPath.components)
19
+ val contents = file.readBytes() ? : throw RuntimeException (" File '$file ' not found" )
20
+ return readTzFile(contents).toTimeZoneRules()
21
+ }
16
22
17
23
override fun availableTimeZoneIds (): Set <String > = buildSet {
18
- tzdbPath.traverseDirectory (exclude = tzdbUnneededFiles) { add(it.toString()) }
24
+ tzdbPath.tryTraverseDirectory (exclude = tzdbUnneededFiles) { add(it.toString()) }
19
25
}
20
26
21
27
}
22
28
29
+ // taken from https://github.com/tzinfo/tzinfo/blob/9953fc092424d55deaea2dcdf6279943f3495724/lib/tzinfo/data_sources/zoneinfo_data_source.rb#L354
30
+ private val tabPaths = listOf (" zone1970.tab" , " zone.tab" , " tab/zone_sun.tab" )
31
+
23
32
/* * The files that sometimes lie in the `zoneinfo` directory but aren't actually time zones. */
24
33
private val tzdbUnneededFiles = setOf (
25
34
// taken from https://github.com/tzinfo/tzinfo/blob/9953fc092424d55deaea2dcdf6279943f3495724/lib/tzinfo/data_sources/zoneinfo_data_source.rb#L88C29-L97C21
@@ -51,7 +60,7 @@ internal fun tzdbPaths(defaultTzdbPath: Path?) = sequence {
51
60
52
61
// taken from https://github.com/HowardHinnant/date/blob/ab37c362e35267d6dee02cb47760f9e9c669d3be/src/tz.cpp#L3951-L3952
53
62
internal fun pathToSystemDefault (): Pair <Path , Path >? {
54
- val info = Path ( true , listOf ( " etc" , " localtime" )).chaseSymlinks()
63
+ val info = chaseSymlinks( " / etc/ localtime" ) ? : return null
55
64
val i = info.components.indexOf(" zoneinfo" )
56
65
if (! info.isAbsolute || i == - 1 || i == info.components.size - 1 ) return null
57
66
return Pair (
0 commit comments