comparison mercurial/util_win32.py @ 2176:9b42304d9896

fix file handling bugs on windows. add util.posixfile class that has posix semantics on windows. fix util.rename so it works with stupid windows delete semantics.
author Vadim Gelfer <vadim.gelfer@gmail.com>
date Tue, 02 May 2006 14:30:00 -0700
parents 760339ccc799
children caf2c6ef5b0e
comparison
equal deleted inserted replaced
2129:e5f5c21f4169 2176:9b42304d9896
14 import win32api 14 import win32api
15 15
16 from demandload import * 16 from demandload import *
17 from i18n import gettext as _ 17 from i18n import gettext as _
18 demandload(globals(), 'errno os pywintypes win32con win32file win32process') 18 demandload(globals(), 'errno os pywintypes win32con win32file win32process')
19 demandload(globals(), 'winerror') 19 demandload(globals(), 'cStringIO winerror')
20 20
21 class WinError(OSError): 21 class WinError:
22 winerror_map = { 22 winerror_map = {
23 winerror.ERROR_ACCESS_DENIED: errno.EACCES, 23 winerror.ERROR_ACCESS_DENIED: errno.EACCES,
24 winerror.ERROR_ACCOUNT_DISABLED: errno.EACCES, 24 winerror.ERROR_ACCOUNT_DISABLED: errno.EACCES,
25 winerror.ERROR_ACCOUNT_RESTRICTION: errno.EACCES, 25 winerror.ERROR_ACCOUNT_RESTRICTION: errno.EACCES,
26 winerror.ERROR_ALREADY_ASSIGNED: errno.EBUSY, 26 winerror.ERROR_ALREADY_ASSIGNED: errno.EBUSY,
103 winerror.ERROR_OPEN_FILES: errno.EBUSY, 103 winerror.ERROR_OPEN_FILES: errno.EBUSY,
104 winerror.ERROR_OPERATION_ABORTED: errno.EINTR, 104 winerror.ERROR_OPERATION_ABORTED: errno.EINTR,
105 winerror.ERROR_OUTOFMEMORY: errno.ENOMEM, 105 winerror.ERROR_OUTOFMEMORY: errno.ENOMEM,
106 winerror.ERROR_PASSWORD_EXPIRED: errno.EACCES, 106 winerror.ERROR_PASSWORD_EXPIRED: errno.EACCES,
107 winerror.ERROR_PATH_BUSY: errno.EBUSY, 107 winerror.ERROR_PATH_BUSY: errno.EBUSY,
108 winerror.ERROR_PATH_NOT_FOUND: errno.ENOTDIR, 108 winerror.ERROR_PATH_NOT_FOUND: errno.ENOENT,
109 winerror.ERROR_PIPE_BUSY: errno.EBUSY, 109 winerror.ERROR_PIPE_BUSY: errno.EBUSY,
110 winerror.ERROR_PIPE_CONNECTED: errno.EPIPE, 110 winerror.ERROR_PIPE_CONNECTED: errno.EPIPE,
111 winerror.ERROR_PIPE_LISTENING: errno.EPIPE, 111 winerror.ERROR_PIPE_LISTENING: errno.EPIPE,
112 winerror.ERROR_PIPE_NOT_CONNECTED: errno.EPIPE, 112 winerror.ERROR_PIPE_NOT_CONNECTED: errno.EPIPE,
113 winerror.ERROR_PRIVILEGE_NOT_HELD: errno.EACCES, 113 winerror.ERROR_PRIVILEGE_NOT_HELD: errno.EACCES,
127 winerror.ERROR_WRITE_PROTECT: errno.EROFS, 127 winerror.ERROR_WRITE_PROTECT: errno.EROFS,
128 } 128 }
129 129
130 def __init__(self, err): 130 def __init__(self, err):
131 self.win_errno, self.win_function, self.win_strerror = err 131 self.win_errno, self.win_function, self.win_strerror = err
132 if self.win_strerror.endswith('.'):
133 self.win_strerror = self.win_strerror[:-1]
134
135 class WinIOError(WinError, IOError):
136 def __init__(self, err, filename=None):
137 WinError.__init__(self, err)
138 IOError.__init__(self, self.winerror_map.get(self.win_errno, 0),
139 self.win_strerror)
140 self.filename = filename
141
142 class WinOSError(WinError, OSError):
143 def __init__(self, err):
144 WinError.__init__(self, err)
132 OSError.__init__(self, self.winerror_map.get(self.win_errno, 0), 145 OSError.__init__(self, self.winerror_map.get(self.win_errno, 0),
133 self.win_strerror) 146 self.win_strerror)
134 147
135 def os_link(src, dst): 148 def os_link(src, dst):
136 # NB will only succeed on NTFS 149 # NB will only succeed on NTFS
137 try: 150 try:
138 win32file.CreateHardLink(dst, src) 151 win32file.CreateHardLink(dst, src)
139 except pywintypes.error, details: 152 except pywintypes.error, details:
140 raise WinError(details) 153 raise WinOSError(details)
141 154
142 def nlinks(pathname): 155 def nlinks(pathname):
143 """Return number of hardlinks for the given file.""" 156 """Return number of hardlinks for the given file."""
144 try: 157 try:
145 fh = win32file.CreateFile(pathname, 158 fh = win32file.CreateFile(pathname,
167 def system_rcpath_win32(): 180 def system_rcpath_win32():
168 '''return default os-specific hgrc search path''' 181 '''return default os-specific hgrc search path'''
169 proc = win32api.GetCurrentProcess() 182 proc = win32api.GetCurrentProcess()
170 filename = win32process.GetModuleFileNameEx(proc, 0) 183 filename = win32process.GetModuleFileNameEx(proc, 0)
171 return [os.path.join(os.path.dirname(filename), 'mercurial.ini')] 184 return [os.path.join(os.path.dirname(filename), 'mercurial.ini')]
185
186 class posixfile(object):
187 '''file object with posix-like semantics. on windows, normal
188 files can not be deleted or renamed if they are open. must open
189 with win32file.FILE_SHARE_DELETE. this flag does not exist on
190 windows <= nt.'''
191
192 # tried to use win32file._open_osfhandle to pass fd to os.fdopen,
193 # but does not work at all. wrap win32 file api instead.
194
195 def __init__(self, name, mode='rb'):
196 access = 0
197 if 'r' in mode or '+' in mode:
198 access |= win32file.GENERIC_READ
199 if 'w' in mode or 'a' in mode:
200 access |= win32file.GENERIC_WRITE
201 if 'r' in mode:
202 creation = win32file.OPEN_EXISTING
203 elif 'a' in mode:
204 creation = win32file.OPEN_ALWAYS
205 else:
206 creation = win32file.CREATE_ALWAYS
207 try:
208 self.handle = win32file.CreateFile(name,
209 access,
210 win32file.FILE_SHARE_READ |
211 win32file.FILE_SHARE_WRITE |
212 win32file.FILE_SHARE_DELETE,
213 None,
214 creation,
215 win32file.FILE_ATTRIBUTE_NORMAL,
216 0)
217 except pywintypes.error, err:
218 raise WinIOError(err, name)
219 self.closed = False
220 self.name = name
221 self.mode = mode
222
223 def read(self, count=-1):
224 try:
225 cs = cStringIO.StringIO()
226 while count:
227 wincount = int(count)
228 if wincount == -1:
229 wincount = 1048576
230 val, data = win32file.ReadFile(self.handle, wincount)
231 if not data: break
232 cs.write(data)
233 if count != -1:
234 count -= len(data)
235 return cs.getvalue()
236 except pywintypes.error, err:
237 raise WinIOError(err)
238
239 def write(self, data):
240 try:
241 if 'a' in self.mode:
242 win32file.SetFilePointer(self.handle, 0, win32file.FILE_END)
243 nwrit = 0
244 while nwrit < len(data):
245 val, nwrit = win32file.WriteFile(self.handle, data)
246 data = data[nwrit:]
247 except pywintypes.error, err:
248 raise WinIOError(err)
249
250 def seek(self, pos, whence=0):
251 try:
252 win32file.SetFilePointer(self.handle, int(pos), whence)
253 except pywintypes.error, err:
254 raise WinIOError(err)
255
256 def tell(self):
257 try:
258 return win32file.SetFilePointer(self.handle, 0,
259 win32file.FILE_CURRENT)
260 except pywintypes.error, err:
261 raise WinIOError(err)
262
263 def close(self):
264 if not self.closed:
265 self.handle = None
266 self.closed = True
267
268 def flush(self):
269 try:
270 win32file.FlushFileBuffers(self.handle)
271 except pywintypes.error, err:
272 raise WinIOError(err)
273
274 def truncate(self, pos=0):
275 try:
276 win32file.SetFilePointer(self.handle, int(pos),
277 win32file.FILE_BEGIN)
278 win32file.SetEndOfFile(self.handle)
279 except pywintypes.error, err:
280 raise WinIOError(err)