Mercurial > hg > mercurial-crew-with-dirclash
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) |