1
# Copyright (C) 2005-2011 Canonical Ltd
1
# Copyright (C) 2005, 2006 Canonical Ltd
3
3
# This program is free software; you can redistribute it and/or modify
4
4
# it under the terms of the GNU General Public License as published by
23
from stat import ST_MODE, S_ISDIR, S_IMODE
23
from stat import ST_MODE, S_ISDIR, ST_SIZE, S_IMODE
26
26
from bzrlib.lazy_import import lazy_import
38
from bzrlib.trace import mutter
37
39
from bzrlib.transport import LateReadError
40
from bzrlib import transport
43
_append_flags = os.O_CREAT | os.O_APPEND | os.O_WRONLY | osutils.O_BINARY | osutils.O_NOINHERIT
44
_put_non_atomic_flags = os.O_CREAT | os.O_TRUNC | os.O_WRONLY | osutils.O_BINARY | osutils.O_NOINHERIT
47
class LocalTransport(transport.Transport):
42
from bzrlib.transport import Transport, Server
45
_append_flags = os.O_CREAT | os.O_APPEND | os.O_WRONLY | osutils.O_BINARY
46
_put_non_atomic_flags = os.O_CREAT | os.O_TRUNC | os.O_WRONLY | osutils.O_BINARY
49
class LocalTransport(Transport):
48
50
"""This is the transport agent for local filesystem access."""
50
52
def __init__(self, base):
73
75
super(LocalTransport, self).__init__(base)
74
76
self._local_base = urlutils.local_path_from_url(base)
75
if self._local_base[-1] != '/':
76
self._local_base = self._local_base + '/'
78
78
def clone(self, offset=None):
79
79
"""Return a new LocalTransport with root at self.base + offset
99
99
- relative_reference is url escaped.
101
101
if relative_reference in ('.', ''):
102
# _local_base normally has a trailing slash; strip it so that stat
103
# on a transport pointing to a symlink reads the link not the
104
# referent but be careful of / and c:\
105
return osutils.split(self._local_base)[0]
102
return self._local_base
106
103
return self._local_base + urlutils.unescape(relative_reference)
108
105
def abspath(self, relpath):
163
160
transport._file_streams[canonical_url].flush()
165
162
path = self._abspath(relpath)
166
return osutils.open_file(path, 'rb')
163
return open(path, 'rb')
167
164
except (IOError, OSError),e:
168
165
if e.errno == errno.EISDIR:
169
166
return LateReadError(relpath)
289
285
def put_bytes_non_atomic(self, relpath, bytes, mode=None,
290
286
create_parent_dir=False, dir_mode=None):
294
289
self._put_non_atomic_helper(relpath, writer, mode=mode,
295
290
create_parent_dir=create_parent_dir,
296
291
dir_mode=dir_mode)
330
325
def open_write_stream(self, relpath, mode=None):
331
326
"""See Transport.open_write_stream."""
327
# initialise the file
328
self.put_bytes_non_atomic(relpath, "", mode=mode)
332
329
abspath = self._abspath(relpath)
333
handle = osutils.open_file(abspath, 'wb')
330
handle = open(abspath, 'wb')
335
331
if mode is not None:
336
332
self._check_mode_and_size(abspath, handle.fileno(), mode)
337
333
transport._file_streams[self.abspath(relpath)] = handle
402
397
def rename(self, rel_from, rel_to):
403
398
path_from = self._abspath(rel_from)
404
path_to = self._abspath(rel_to)
406
400
# *don't* call bzrlib.osutils.rename, because we want to
407
# detect conflicting names on rename, and osutils.rename tries to
408
# mask cross-platform differences there
409
os.rename(path_from, path_to)
401
# detect errors on rename
402
os.rename(path_from, self._abspath(rel_to))
410
403
except (IOError, OSError),e:
411
404
# TODO: What about path_to?
412
405
self._translate_error(e, path_from)
519
512
except (IOError, OSError),e:
520
513
self._translate_error(e, path)
522
if osutils.host_os_dereferences_symlinks():
523
def readlink(self, relpath):
524
"""See Transport.readlink."""
525
return osutils.readlink(self._abspath(relpath))
527
if osutils.hardlinks_good():
528
def hardlink(self, source, link_name):
529
"""See Transport.link."""
531
os.link(self._abspath(source), self._abspath(link_name))
532
except (IOError, OSError), e:
533
self._translate_error(e, source)
535
if osutils.has_symlinks():
536
def symlink(self, source, link_name):
537
"""See Transport.symlink."""
538
abs_link_dirpath = urlutils.dirname(self.abspath(link_name))
539
source_rel = urlutils.file_relpath(
540
urlutils.strip_trailing_slash(abs_link_dirpath),
541
urlutils.strip_trailing_slash(self.abspath(source))
545
os.symlink(source_rel, self._abspath(link_name))
546
except (IOError, OSError), e:
547
self._translate_error(e, source_rel)
549
515
def _can_roundtrip_unix_modebits(self):
550
516
if sys.platform == 'win32':
585
551
return EmulatedWin32LocalTransport(abspath)
554
class LocalURLServer(Server):
555
"""A pretend server for local transports, using file:// urls.
557
Of course no actual server is required to access the local filesystem, so
558
this just exists to tell the test code how to get to it.
562
"""Setup the server to service requests.
564
:param decorated_transport: ignored by this implementation.
568
"""See Transport.Server.get_url."""
569
return urlutils.local_path_to_url('')
588
572
def get_test_permutations():
589
573
"""Return the permutations to be used in testing."""
590
from bzrlib.tests import test_server
591
return [(LocalTransport, test_server.LocalURLServer),]
575
(LocalTransport, LocalURLServer),