File driver: properly handle Windows paths

On Windows, the parsed paths always contain a starting slash, which
causes issues.

Also, the paths should be normalized, replacing slashes with
backslashes.

This patch fixes those issues, ensuring that urls such as the following
are properly handled:

file:///c:/local/path
file:////share_addr/share_name

Change-Id: I84396173881d3be3a5d2cdde626ab0e2d2dac3eb
Closes-Bug: #1598821
This commit is contained in:
Lucian Petrut 2016-07-04 14:55:18 +03:00
parent 67164564f4
commit 3541e7c393
2 changed files with 66 additions and 1 deletions

View File

@ -20,7 +20,9 @@ import errno
import hashlib
import logging
import os
import re
import shutil
import sys
import threading
import weakref
@ -229,7 +231,7 @@ class FileDriver(coordination._RunWatchersMixin,
"""Initialize the file driver."""
super(FileDriver, self).__init__()
self._member_id = member_id
self._dir = parsed_url.path
self._dir = self._normalize_path(parsed_url.path)
self._executor = utils.ProxyExecutor.build("File", options)
self._group_dir = os.path.join(self._dir, 'groups')
self._driver_lock_path = os.path.join(self._dir, '.driver_lock')
@ -241,6 +243,19 @@ class FileDriver(coordination._RunWatchersMixin,
self._joined_groups = set()
self._safe_member_id = self._make_filesystem_safe(member_id)
@staticmethod
def _normalize_path(path):
if sys.platform == 'win32':
# Replace slashes with backslashes and make sure we don't
# have any at the beginning of paths that include drive letters.
#
# Expected url format:
# file:////share_address/share_name
# file:///C:/path
return re.sub(r'\\(?=\w:\\)', '',
os.path.normpath(path))
return path
@classmethod
def _get_raw_lock(cls, path, member_id):
lock_barrier = cls._barriers.setdefault(path, _Barrier())

View File

@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Cloudbase Solutions Srl
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import uuid
import mock
from testtools import testcase
from tooz import coordination
class TestFileDriver(testcase.TestCase):
_FAKE_MEMBER_ID = str(uuid.uuid4()).encode('ascii')
def test_base_dir(self):
file_path = '/fake/file/path'
url = 'file://%s' % file_path
coord = coordination.get_coordinator(url, self._FAKE_MEMBER_ID)
self.assertEqual(file_path, coord._dir)
@mock.patch('os.path.normpath', lambda x: x.replace('/', '\\'))
@mock.patch('sys.platform', 'win32')
def test_base_dir_win32(self):
coord = coordination.get_coordinator(
'file:///C:/path/', self._FAKE_MEMBER_ID)
self.assertEqual('C:\\path\\', coord._dir)
coord = coordination.get_coordinator(
'file:////share_addr/share_path/', self._FAKE_MEMBER_ID)
self.assertEqual('\\\\share_addr\\share_path\\', coord._dir)
# Administrative shares should be handled properly.
coord = coordination.get_coordinator(
'file:////c$/path/', self._FAKE_MEMBER_ID)
self.assertEqual('\\\\c$\\path\\', coord._dir)