Revision 4bb678e9
b/lib/utils.py | ||
---|---|---|
1936 | 1936 |
return os.path.normpath(path) == path and os.path.isabs(path) |
1937 | 1937 |
|
1938 | 1938 |
|
1939 |
def PathJoin(*args): |
|
1940 |
"""Safe-join a list of path components. |
|
1941 |
|
|
1942 |
Requirements: |
|
1943 |
- the first argument must be an absolute path |
|
1944 |
- no component in the path must have backtracking (e.g. /../), |
|
1945 |
since we check for normalization at the end |
|
1946 |
|
|
1947 |
@param args: the path components to be joined |
|
1948 |
@raise ValueError: for invalid paths |
|
1949 |
|
|
1950 |
""" |
|
1951 |
# ensure we're having at least one path passed in |
|
1952 |
assert args |
|
1953 |
# ensure the first component is an absolute and normalized path name |
|
1954 |
root = args[0] |
|
1955 |
if not IsNormAbsPath(root): |
|
1956 |
raise ValueError("Invalid parameter to PathJoin: '%s'" % str(args[0])) |
|
1957 |
result = os.path.join(*args) |
|
1958 |
# ensure that the whole path is normalized |
|
1959 |
if not IsNormAbsPath(result): |
|
1960 |
raise ValueError("Invalid parameters to PathJoin: '%s'" % str(args)) |
|
1961 |
# check that we're still under the original prefix |
|
1962 |
prefix = os.path.commonprefix([root, result]) |
|
1963 |
if prefix != root: |
|
1964 |
raise ValueError("Error: path joining resulted in different prefix" |
|
1965 |
" (%s != %s)" % (prefix, root)) |
|
1966 |
return result |
|
1967 |
|
|
1968 |
|
|
1939 | 1969 |
def TailFile(fname, lines=20): |
1940 | 1970 |
"""Return the last lines from a file. |
1941 | 1971 |
|
b/test/ganeti.utils_unittest.py | ||
---|---|---|
47 | 47 |
ShellQuote, ShellQuoteArgs, TcpPing, ListVisibleFiles, \ |
48 | 48 |
SetEtcHostsEntry, RemoveEtcHostsEntry, FirstFree, OwnIpAddress, \ |
49 | 49 |
TailFile, ForceDictType, SafeEncode, IsNormAbsPath, FormatTime, \ |
50 |
UnescapeAndSplit, RunParts |
|
50 |
UnescapeAndSplit, RunParts, PathJoin
|
|
51 | 51 |
|
52 | 52 |
from ganeti.errors import LockError, UnitParseError, GenericError, \ |
53 | 53 |
ProgrammerError |
... | ... | |
1260 | 1260 |
self.failUnlessEqual(UnescapeAndSplit(sep.join(a), sep=sep), b) |
1261 | 1261 |
|
1262 | 1262 |
|
1263 |
class TestPathJoin(unittest.TestCase): |
|
1264 |
"""Testing case for PathJoin""" |
|
1265 |
|
|
1266 |
def testBasicItems(self): |
|
1267 |
mlist = ["/a", "b", "c"] |
|
1268 |
self.failUnlessEqual(PathJoin(*mlist), "/".join(mlist)) |
|
1269 |
|
|
1270 |
def testNonAbsPrefix(self): |
|
1271 |
self.failUnlessRaises(ValueError, PathJoin, "a", "b") |
|
1272 |
|
|
1273 |
def testBackTrack(self): |
|
1274 |
self.failUnlessRaises(ValueError, PathJoin, "/a", "b/../c") |
|
1275 |
|
|
1276 |
def testMultiAbs(self): |
|
1277 |
self.failUnlessRaises(ValueError, PathJoin, "/a", "/b") |
|
1278 |
|
|
1279 |
|
|
1263 | 1280 |
if __name__ == '__main__': |
1264 | 1281 |
testutils.GanetiTestProgram() |
Also available in: Unified diff