mercurial/windows.py
branchstable
changeset 26813 b66e3ca0b90c
parent 26375 3686fa2b8eee
child 27360 6daa795ed32f
equal deleted inserted replaced
26535:d3712209921d 26813:b66e3ca0b90c
    25 testpid = win32.testpid
    25 testpid = win32.testpid
    26 unlink = win32.unlink
    26 unlink = win32.unlink
    27 
    27 
    28 umask = 0o022
    28 umask = 0o022
    29 
    29 
       
    30 class mixedfilemodewrapper(object):
       
    31     """Wraps a file handle when it is opened in read/write mode.
       
    32 
       
    33     fopen() and fdopen() on Windows have a specific-to-Windows requirement
       
    34     that files opened with mode r+, w+, or a+ make a call to a file positioning
       
    35     function when switching between reads and writes. Without this extra call,
       
    36     Python will raise a not very intuitive "IOError: [Errno 0] Error."
       
    37 
       
    38     This class wraps posixfile instances when the file is opened in read/write
       
    39     mode and automatically adds checks or inserts appropriate file positioning
       
    40     calls when necessary.
       
    41     """
       
    42     OPNONE = 0
       
    43     OPREAD = 1
       
    44     OPWRITE = 2
       
    45 
       
    46     def __init__(self, fp):
       
    47         object.__setattr__(self, '_fp', fp)
       
    48         object.__setattr__(self, '_lastop', 0)
       
    49 
       
    50     def __getattr__(self, name):
       
    51         return getattr(self._fp, name)
       
    52 
       
    53     def __setattr__(self, name, value):
       
    54         return self._fp.__setattr__(name, value)
       
    55 
       
    56     def _noopseek(self):
       
    57         self._fp.seek(0, os.SEEK_CUR)
       
    58 
       
    59     def seek(self, *args, **kwargs):
       
    60         object.__setattr__(self, '_lastop', self.OPNONE)
       
    61         return self._fp.seek(*args, **kwargs)
       
    62 
       
    63     def write(self, d):
       
    64         if self._lastop == self.OPREAD:
       
    65             self._noopseek()
       
    66 
       
    67         object.__setattr__(self, '_lastop', self.OPWRITE)
       
    68         return self._fp.write(d)
       
    69 
       
    70     def writelines(self, *args, **kwargs):
       
    71         if self._lastop == self.OPREAD:
       
    72             self._noopeseek()
       
    73 
       
    74         object.__setattr__(self, '_lastop', self.OPWRITE)
       
    75         return self._fp.writelines(*args, **kwargs)
       
    76 
       
    77     def read(self, *args, **kwargs):
       
    78         if self._lastop == self.OPWRITE:
       
    79             self._noopseek()
       
    80 
       
    81         object.__setattr__(self, '_lastop', self.OPREAD)
       
    82         return self._fp.read(*args, **kwargs)
       
    83 
       
    84     def readline(self, *args, **kwargs):
       
    85         if self._lastop == self.OPWRITE:
       
    86             self._noopseek()
       
    87 
       
    88         object.__setattr__(self, '_lastop', self.OPREAD)
       
    89         return self._fp.readline(*args, **kwargs)
       
    90 
       
    91     def readlines(self, *args, **kwargs):
       
    92         if self._lastop == self.OPWRITE:
       
    93             self._noopseek()
       
    94 
       
    95         object.__setattr__(self, '_lastop', self.OPREAD)
       
    96         return self._fp.readlines(*args, **kwargs)
       
    97 
    30 def posixfile(name, mode='r', buffering=-1):
    98 def posixfile(name, mode='r', buffering=-1):
    31     '''Open a file with even more POSIX-like semantics'''
    99     '''Open a file with even more POSIX-like semantics'''
    32     try:
   100     try:
    33         fp = osutil.posixfile(name, mode, buffering) # may raise WindowsError
   101         fp = osutil.posixfile(name, mode, buffering) # may raise WindowsError
    34 
   102 
    35         # The position when opening in append mode is implementation defined, so
   103         # The position when opening in append mode is implementation defined, so
    36         # make it consistent with other platforms, which position at EOF.
   104         # make it consistent with other platforms, which position at EOF.
    37         if 'a' in mode:
   105         if 'a' in mode:
    38             fp.seek(0, os.SEEK_END)
   106             fp.seek(0, os.SEEK_END)
       
   107 
       
   108         if '+' in mode:
       
   109             return mixedfilemodewrapper(fp)
    39 
   110 
    40         return fp
   111         return fp
    41     except WindowsError as err:
   112     except WindowsError as err:
    42         # convert to a friendlier exception
   113         # convert to a friendlier exception
    43         raise IOError(err.errno, '%s: %s' % (name, err.strerror))
   114         raise IOError(err.errno, '%s: %s' % (name, err.strerror))