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:
parent
67164564f4
commit
3541e7c393
|
@ -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())
|
||||
|
|
|
@ -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)
|
Loading…
Reference in New Issue