diff --git a/babel/localedata.py b/babel/localedata.py
index 9308b5e..688af79 100644
--- a/babel/localedata.py
+++ b/babel/localedata.py
@@ -18,6 +18,9 @@
"""
import os
+import re
+import sys
+
import pickle
try:
import threading
@@ -31,7 +34,23 @@ __docformat__ = 'restructuredtext en'
_cache = {}
_cache_lock = threading.RLock()
_dirname = os.path.join(os.path.dirname(__file__), 'localedata')
+_windows_reserved_name_re = re.compile("^(con|prn|aux|nul|com[0-9]|lpt[0-9])$", re.I)
+
+
+def resolve_locale_filename(name):
+ """
+ Resolve a locale identifier to a `.dat` path on disk.
+ """
+
+ # Clean up any possible relative paths.
+ name = os.path.basename(name)
+
+ # Ensure we're not left with one of the Windows reserved names.
+ if sys.platform == "win32" and _windows_reserved_name_re.match(os.path.splitext(name)[0]):
+ raise ValueError("Name %s is invalid on Windows" % name)
+ # Build the path.
+ return os.path.join(_dirname, '%s.dat' % name)
def exists(name):
"""Check whether locale data is available for the given locale.
@@ -42,7 +61,7 @@ def exists(name):
"""
if name in _cache:
return True
- return os.path.exists(os.path.join(_dirname, '%s.dat' % name))
+ return os.path.exists(resolve_locale_filename(name))
def list():
@@ -85,6 +104,7 @@ def load(name, merge_inherited=True):
:raise `IOError`: if no locale data file is found for the given locale
identifer, or one of the locales it inherits from
"""
+ name = os.path.basename(name)
_cache_lock.acquire()
try:
data = _cache.get(name)
@@ -99,7 +119,7 @@ def load(name, merge_inherited=True):
else:
parent = '_'.join(parts[:-1])
data = load(parent).copy()
- filename = os.path.join(_dirname, '%s.dat' % name)
+ filename = resolve_locale_filename(name)
fileobj = open(filename, 'rb')
try:
if name != 'root' and merge_inherited: