##// END OF EJS Templates
util_win32: make os_link more robust (issue 761)...
Patrick Mezard -
r5879:cacfeee3 default
parent child Browse files
Show More
@@ -1,310 +1,319 b''
1 # util_win32.py - utility functions that use win32 API
1 # util_win32.py - utility functions that use win32 API
2 #
2 #
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005 Matt Mackall <mpm@selenic.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
4 # Copyright 2006 Vadim Gelfer <vadim.gelfer@gmail.com>
5 #
5 #
6 # This software may be used and distributed according to the terms of
6 # This software may be used and distributed according to the terms of
7 # the GNU General Public License, incorporated herein by reference.
7 # the GNU General Public License, incorporated herein by reference.
8
8
9 # Mark Hammond's win32all package allows better functionality on
9 # Mark Hammond's win32all package allows better functionality on
10 # Windows. this module overrides definitions in util.py. if not
10 # Windows. this module overrides definitions in util.py. if not
11 # available, import of this module will fail, and generic code will be
11 # available, import of this module will fail, and generic code will be
12 # used.
12 # used.
13
13
14 import win32api
14 import win32api
15
15
16 from i18n import _
16 from i18n import _
17 import errno, os, pywintypes, win32con, win32file, win32process
17 import errno, os, pywintypes, win32con, win32file, win32process
18 import cStringIO, winerror
18 import cStringIO, winerror
19 from win32com.shell import shell,shellcon
19 from win32com.shell import shell,shellcon
20
20
21 class WinError:
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,
27 winerror.ERROR_ALREADY_EXISTS: errno.EEXIST,
27 winerror.ERROR_ALREADY_EXISTS: errno.EEXIST,
28 winerror.ERROR_ARITHMETIC_OVERFLOW: errno.ERANGE,
28 winerror.ERROR_ARITHMETIC_OVERFLOW: errno.ERANGE,
29 winerror.ERROR_BAD_COMMAND: errno.EIO,
29 winerror.ERROR_BAD_COMMAND: errno.EIO,
30 winerror.ERROR_BAD_DEVICE: errno.ENODEV,
30 winerror.ERROR_BAD_DEVICE: errno.ENODEV,
31 winerror.ERROR_BAD_DRIVER_LEVEL: errno.ENXIO,
31 winerror.ERROR_BAD_DRIVER_LEVEL: errno.ENXIO,
32 winerror.ERROR_BAD_EXE_FORMAT: errno.ENOEXEC,
32 winerror.ERROR_BAD_EXE_FORMAT: errno.ENOEXEC,
33 winerror.ERROR_BAD_FORMAT: errno.ENOEXEC,
33 winerror.ERROR_BAD_FORMAT: errno.ENOEXEC,
34 winerror.ERROR_BAD_LENGTH: errno.EINVAL,
34 winerror.ERROR_BAD_LENGTH: errno.EINVAL,
35 winerror.ERROR_BAD_PATHNAME: errno.ENOENT,
35 winerror.ERROR_BAD_PATHNAME: errno.ENOENT,
36 winerror.ERROR_BAD_PIPE: errno.EPIPE,
36 winerror.ERROR_BAD_PIPE: errno.EPIPE,
37 winerror.ERROR_BAD_UNIT: errno.ENODEV,
37 winerror.ERROR_BAD_UNIT: errno.ENODEV,
38 winerror.ERROR_BAD_USERNAME: errno.EINVAL,
38 winerror.ERROR_BAD_USERNAME: errno.EINVAL,
39 winerror.ERROR_BROKEN_PIPE: errno.EPIPE,
39 winerror.ERROR_BROKEN_PIPE: errno.EPIPE,
40 winerror.ERROR_BUFFER_OVERFLOW: errno.ENAMETOOLONG,
40 winerror.ERROR_BUFFER_OVERFLOW: errno.ENAMETOOLONG,
41 winerror.ERROR_BUSY: errno.EBUSY,
41 winerror.ERROR_BUSY: errno.EBUSY,
42 winerror.ERROR_BUSY_DRIVE: errno.EBUSY,
42 winerror.ERROR_BUSY_DRIVE: errno.EBUSY,
43 winerror.ERROR_CALL_NOT_IMPLEMENTED: errno.ENOSYS,
43 winerror.ERROR_CALL_NOT_IMPLEMENTED: errno.ENOSYS,
44 winerror.ERROR_CANNOT_MAKE: errno.EACCES,
44 winerror.ERROR_CANNOT_MAKE: errno.EACCES,
45 winerror.ERROR_CANTOPEN: errno.EIO,
45 winerror.ERROR_CANTOPEN: errno.EIO,
46 winerror.ERROR_CANTREAD: errno.EIO,
46 winerror.ERROR_CANTREAD: errno.EIO,
47 winerror.ERROR_CANTWRITE: errno.EIO,
47 winerror.ERROR_CANTWRITE: errno.EIO,
48 winerror.ERROR_CRC: errno.EIO,
48 winerror.ERROR_CRC: errno.EIO,
49 winerror.ERROR_CURRENT_DIRECTORY: errno.EACCES,
49 winerror.ERROR_CURRENT_DIRECTORY: errno.EACCES,
50 winerror.ERROR_DEVICE_IN_USE: errno.EBUSY,
50 winerror.ERROR_DEVICE_IN_USE: errno.EBUSY,
51 winerror.ERROR_DEV_NOT_EXIST: errno.ENODEV,
51 winerror.ERROR_DEV_NOT_EXIST: errno.ENODEV,
52 winerror.ERROR_DIRECTORY: errno.EINVAL,
52 winerror.ERROR_DIRECTORY: errno.EINVAL,
53 winerror.ERROR_DIR_NOT_EMPTY: errno.ENOTEMPTY,
53 winerror.ERROR_DIR_NOT_EMPTY: errno.ENOTEMPTY,
54 winerror.ERROR_DISK_CHANGE: errno.EIO,
54 winerror.ERROR_DISK_CHANGE: errno.EIO,
55 winerror.ERROR_DISK_FULL: errno.ENOSPC,
55 winerror.ERROR_DISK_FULL: errno.ENOSPC,
56 winerror.ERROR_DRIVE_LOCKED: errno.EBUSY,
56 winerror.ERROR_DRIVE_LOCKED: errno.EBUSY,
57 winerror.ERROR_ENVVAR_NOT_FOUND: errno.EINVAL,
57 winerror.ERROR_ENVVAR_NOT_FOUND: errno.EINVAL,
58 winerror.ERROR_EXE_MARKED_INVALID: errno.ENOEXEC,
58 winerror.ERROR_EXE_MARKED_INVALID: errno.ENOEXEC,
59 winerror.ERROR_FILENAME_EXCED_RANGE: errno.ENAMETOOLONG,
59 winerror.ERROR_FILENAME_EXCED_RANGE: errno.ENAMETOOLONG,
60 winerror.ERROR_FILE_EXISTS: errno.EEXIST,
60 winerror.ERROR_FILE_EXISTS: errno.EEXIST,
61 winerror.ERROR_FILE_INVALID: errno.ENODEV,
61 winerror.ERROR_FILE_INVALID: errno.ENODEV,
62 winerror.ERROR_FILE_NOT_FOUND: errno.ENOENT,
62 winerror.ERROR_FILE_NOT_FOUND: errno.ENOENT,
63 winerror.ERROR_GEN_FAILURE: errno.EIO,
63 winerror.ERROR_GEN_FAILURE: errno.EIO,
64 winerror.ERROR_HANDLE_DISK_FULL: errno.ENOSPC,
64 winerror.ERROR_HANDLE_DISK_FULL: errno.ENOSPC,
65 winerror.ERROR_INSUFFICIENT_BUFFER: errno.ENOMEM,
65 winerror.ERROR_INSUFFICIENT_BUFFER: errno.ENOMEM,
66 winerror.ERROR_INVALID_ACCESS: errno.EACCES,
66 winerror.ERROR_INVALID_ACCESS: errno.EACCES,
67 winerror.ERROR_INVALID_ADDRESS: errno.EFAULT,
67 winerror.ERROR_INVALID_ADDRESS: errno.EFAULT,
68 winerror.ERROR_INVALID_BLOCK: errno.EFAULT,
68 winerror.ERROR_INVALID_BLOCK: errno.EFAULT,
69 winerror.ERROR_INVALID_DATA: errno.EINVAL,
69 winerror.ERROR_INVALID_DATA: errno.EINVAL,
70 winerror.ERROR_INVALID_DRIVE: errno.ENODEV,
70 winerror.ERROR_INVALID_DRIVE: errno.ENODEV,
71 winerror.ERROR_INVALID_EXE_SIGNATURE: errno.ENOEXEC,
71 winerror.ERROR_INVALID_EXE_SIGNATURE: errno.ENOEXEC,
72 winerror.ERROR_INVALID_FLAGS: errno.EINVAL,
72 winerror.ERROR_INVALID_FLAGS: errno.EINVAL,
73 winerror.ERROR_INVALID_FUNCTION: errno.ENOSYS,
73 winerror.ERROR_INVALID_FUNCTION: errno.ENOSYS,
74 winerror.ERROR_INVALID_HANDLE: errno.EBADF,
74 winerror.ERROR_INVALID_HANDLE: errno.EBADF,
75 winerror.ERROR_INVALID_LOGON_HOURS: errno.EACCES,
75 winerror.ERROR_INVALID_LOGON_HOURS: errno.EACCES,
76 winerror.ERROR_INVALID_NAME: errno.EINVAL,
76 winerror.ERROR_INVALID_NAME: errno.EINVAL,
77 winerror.ERROR_INVALID_OWNER: errno.EINVAL,
77 winerror.ERROR_INVALID_OWNER: errno.EINVAL,
78 winerror.ERROR_INVALID_PARAMETER: errno.EINVAL,
78 winerror.ERROR_INVALID_PARAMETER: errno.EINVAL,
79 winerror.ERROR_INVALID_PASSWORD: errno.EPERM,
79 winerror.ERROR_INVALID_PASSWORD: errno.EPERM,
80 winerror.ERROR_INVALID_PRIMARY_GROUP: errno.EINVAL,
80 winerror.ERROR_INVALID_PRIMARY_GROUP: errno.EINVAL,
81 winerror.ERROR_INVALID_SIGNAL_NUMBER: errno.EINVAL,
81 winerror.ERROR_INVALID_SIGNAL_NUMBER: errno.EINVAL,
82 winerror.ERROR_INVALID_TARGET_HANDLE: errno.EIO,
82 winerror.ERROR_INVALID_TARGET_HANDLE: errno.EIO,
83 winerror.ERROR_INVALID_WORKSTATION: errno.EACCES,
83 winerror.ERROR_INVALID_WORKSTATION: errno.EACCES,
84 winerror.ERROR_IO_DEVICE: errno.EIO,
84 winerror.ERROR_IO_DEVICE: errno.EIO,
85 winerror.ERROR_IO_INCOMPLETE: errno.EINTR,
85 winerror.ERROR_IO_INCOMPLETE: errno.EINTR,
86 winerror.ERROR_LOCKED: errno.EBUSY,
86 winerror.ERROR_LOCKED: errno.EBUSY,
87 winerror.ERROR_LOCK_VIOLATION: errno.EACCES,
87 winerror.ERROR_LOCK_VIOLATION: errno.EACCES,
88 winerror.ERROR_LOGON_FAILURE: errno.EACCES,
88 winerror.ERROR_LOGON_FAILURE: errno.EACCES,
89 winerror.ERROR_MAPPED_ALIGNMENT: errno.EINVAL,
89 winerror.ERROR_MAPPED_ALIGNMENT: errno.EINVAL,
90 winerror.ERROR_META_EXPANSION_TOO_LONG: errno.E2BIG,
90 winerror.ERROR_META_EXPANSION_TOO_LONG: errno.E2BIG,
91 winerror.ERROR_MORE_DATA: errno.EPIPE,
91 winerror.ERROR_MORE_DATA: errno.EPIPE,
92 winerror.ERROR_NEGATIVE_SEEK: errno.ESPIPE,
92 winerror.ERROR_NEGATIVE_SEEK: errno.ESPIPE,
93 winerror.ERROR_NOACCESS: errno.EFAULT,
93 winerror.ERROR_NOACCESS: errno.EFAULT,
94 winerror.ERROR_NONE_MAPPED: errno.EINVAL,
94 winerror.ERROR_NONE_MAPPED: errno.EINVAL,
95 winerror.ERROR_NOT_ENOUGH_MEMORY: errno.ENOMEM,
95 winerror.ERROR_NOT_ENOUGH_MEMORY: errno.ENOMEM,
96 winerror.ERROR_NOT_READY: errno.EAGAIN,
96 winerror.ERROR_NOT_READY: errno.EAGAIN,
97 winerror.ERROR_NOT_SAME_DEVICE: errno.EXDEV,
97 winerror.ERROR_NOT_SAME_DEVICE: errno.EXDEV,
98 winerror.ERROR_NO_DATA: errno.EPIPE,
98 winerror.ERROR_NO_DATA: errno.EPIPE,
99 winerror.ERROR_NO_MORE_SEARCH_HANDLES: errno.EIO,
99 winerror.ERROR_NO_MORE_SEARCH_HANDLES: errno.EIO,
100 winerror.ERROR_NO_PROC_SLOTS: errno.EAGAIN,
100 winerror.ERROR_NO_PROC_SLOTS: errno.EAGAIN,
101 winerror.ERROR_NO_SUCH_PRIVILEGE: errno.EACCES,
101 winerror.ERROR_NO_SUCH_PRIVILEGE: errno.EACCES,
102 winerror.ERROR_OPEN_FAILED: errno.EIO,
102 winerror.ERROR_OPEN_FAILED: errno.EIO,
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.ENOENT,
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,
114 winerror.ERROR_READ_FAULT: errno.EIO,
114 winerror.ERROR_READ_FAULT: errno.EIO,
115 winerror.ERROR_SEEK: errno.EIO,
115 winerror.ERROR_SEEK: errno.EIO,
116 winerror.ERROR_SEEK_ON_DEVICE: errno.ESPIPE,
116 winerror.ERROR_SEEK_ON_DEVICE: errno.ESPIPE,
117 winerror.ERROR_SHARING_BUFFER_EXCEEDED: errno.ENFILE,
117 winerror.ERROR_SHARING_BUFFER_EXCEEDED: errno.ENFILE,
118 winerror.ERROR_SHARING_VIOLATION: errno.EACCES,
118 winerror.ERROR_SHARING_VIOLATION: errno.EACCES,
119 winerror.ERROR_STACK_OVERFLOW: errno.ENOMEM,
119 winerror.ERROR_STACK_OVERFLOW: errno.ENOMEM,
120 winerror.ERROR_SWAPERROR: errno.ENOENT,
120 winerror.ERROR_SWAPERROR: errno.ENOENT,
121 winerror.ERROR_TOO_MANY_MODULES: errno.EMFILE,
121 winerror.ERROR_TOO_MANY_MODULES: errno.EMFILE,
122 winerror.ERROR_TOO_MANY_OPEN_FILES: errno.EMFILE,
122 winerror.ERROR_TOO_MANY_OPEN_FILES: errno.EMFILE,
123 winerror.ERROR_UNRECOGNIZED_MEDIA: errno.ENXIO,
123 winerror.ERROR_UNRECOGNIZED_MEDIA: errno.ENXIO,
124 winerror.ERROR_UNRECOGNIZED_VOLUME: errno.ENODEV,
124 winerror.ERROR_UNRECOGNIZED_VOLUME: errno.ENODEV,
125 winerror.ERROR_WAIT_NO_CHILDREN: errno.ECHILD,
125 winerror.ERROR_WAIT_NO_CHILDREN: errno.ECHILD,
126 winerror.ERROR_WRITE_FAULT: errno.EIO,
126 winerror.ERROR_WRITE_FAULT: errno.EIO,
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('.'):
132 if self.win_strerror.endswith('.'):
133 self.win_strerror = self.win_strerror[:-1]
133 self.win_strerror = self.win_strerror[:-1]
134
134
135 class WinIOError(WinError, IOError):
135 class WinIOError(WinError, IOError):
136 def __init__(self, err, filename=None):
136 def __init__(self, err, filename=None):
137 WinError.__init__(self, err)
137 WinError.__init__(self, err)
138 IOError.__init__(self, self.winerror_map.get(self.win_errno, 0),
138 IOError.__init__(self, self.winerror_map.get(self.win_errno, 0),
139 self.win_strerror)
139 self.win_strerror)
140 self.filename = filename
140 self.filename = filename
141
141
142 class WinOSError(WinError, OSError):
142 class WinOSError(WinError, OSError):
143 def __init__(self, err):
143 def __init__(self, err):
144 WinError.__init__(self, err)
144 WinError.__init__(self, err)
145 OSError.__init__(self, self.winerror_map.get(self.win_errno, 0),
145 OSError.__init__(self, self.winerror_map.get(self.win_errno, 0),
146 self.win_strerror)
146 self.win_strerror)
147
147
148 def os_link(src, dst):
148 def os_link(src, dst):
149 # NB will only succeed on NTFS
150 try:
149 try:
151 win32file.CreateHardLink(dst, src)
150 win32file.CreateHardLink(dst, src)
151 # CreateHardLink sometimes succeeds on mapped drives but
152 # following nlinks() returns 1. Check it now and bail out.
153 if nlinks(src) < 2:
154 try:
155 win32file.DeleteFile(dst)
156 except:
157 pass
158 # Fake hardlinking error
159 raise WinOSError((18, 'CreateHardLink', 'The system cannot '
160 'move the file to a different disk drive'))
152 except pywintypes.error, details:
161 except pywintypes.error, details:
153 raise WinOSError(details)
162 raise WinOSError(details)
154
163
155 def nlinks(pathname):
164 def nlinks(pathname):
156 """Return number of hardlinks for the given file."""
165 """Return number of hardlinks for the given file."""
157 try:
166 try:
158 fh = win32file.CreateFile(pathname,
167 fh = win32file.CreateFile(pathname,
159 win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
168 win32file.GENERIC_READ, win32file.FILE_SHARE_READ,
160 None, win32file.OPEN_EXISTING, 0, None)
169 None, win32file.OPEN_EXISTING, 0, None)
161 res = win32file.GetFileInformationByHandle(fh)
170 res = win32file.GetFileInformationByHandle(fh)
162 fh.Close()
171 fh.Close()
163 return res[7]
172 return res[7]
164 except pywintypes.error:
173 except pywintypes.error:
165 return os.lstat(pathname).st_nlink
174 return os.lstat(pathname).st_nlink
166
175
167 def testpid(pid):
176 def testpid(pid):
168 '''return True if pid is still running or unable to
177 '''return True if pid is still running or unable to
169 determine, False otherwise'''
178 determine, False otherwise'''
170 try:
179 try:
171 handle = win32api.OpenProcess(
180 handle = win32api.OpenProcess(
172 win32con.PROCESS_QUERY_INFORMATION, False, pid)
181 win32con.PROCESS_QUERY_INFORMATION, False, pid)
173 if handle:
182 if handle:
174 status = win32process.GetExitCodeProcess(handle)
183 status = win32process.GetExitCodeProcess(handle)
175 return status == win32con.STILL_ACTIVE
184 return status == win32con.STILL_ACTIVE
176 except pywintypes.error, details:
185 except pywintypes.error, details:
177 return details[0] != winerror.ERROR_INVALID_PARAMETER
186 return details[0] != winerror.ERROR_INVALID_PARAMETER
178 return True
187 return True
179
188
180 def system_rcpath_win32():
189 def system_rcpath_win32():
181 '''return default os-specific hgrc search path'''
190 '''return default os-specific hgrc search path'''
182 proc = win32api.GetCurrentProcess()
191 proc = win32api.GetCurrentProcess()
183 try:
192 try:
184 # This will fail on windows < NT
193 # This will fail on windows < NT
185 filename = win32process.GetModuleFileNameEx(proc, 0)
194 filename = win32process.GetModuleFileNameEx(proc, 0)
186 except:
195 except:
187 filename = win32api.GetModuleFileName(0)
196 filename = win32api.GetModuleFileName(0)
188 return [os.path.join(os.path.dirname(filename), 'mercurial.ini')]
197 return [os.path.join(os.path.dirname(filename), 'mercurial.ini')]
189
198
190 def user_rcpath_win32():
199 def user_rcpath_win32():
191 '''return os-specific hgrc search path to the user dir'''
200 '''return os-specific hgrc search path to the user dir'''
192 userdir = os.path.expanduser('~')
201 userdir = os.path.expanduser('~')
193 if sys.getwindowsversion() != 2 and userdir == '~':
202 if sys.getwindowsversion() != 2 and userdir == '~':
194 # We are on win < nt: fetch the APPDATA directory location and use
203 # We are on win < nt: fetch the APPDATA directory location and use
195 # the parent directory as the user home dir.
204 # the parent directory as the user home dir.
196 appdir = shell.SHGetPathFromIDList(
205 appdir = shell.SHGetPathFromIDList(
197 shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
206 shell.SHGetSpecialFolderLocation(0, shellcon.CSIDL_APPDATA))
198 userdir = os.path.dirname(appdir)
207 userdir = os.path.dirname(appdir)
199 return os.path.join(userdir, 'mercurial.ini')
208 return os.path.join(userdir, 'mercurial.ini')
200
209
201 class posixfile_nt(object):
210 class posixfile_nt(object):
202 '''file object with posix-like semantics. on windows, normal
211 '''file object with posix-like semantics. on windows, normal
203 files can not be deleted or renamed if they are open. must open
212 files can not be deleted or renamed if they are open. must open
204 with win32file.FILE_SHARE_DELETE. this flag does not exist on
213 with win32file.FILE_SHARE_DELETE. this flag does not exist on
205 windows < nt, so do not use this class there.'''
214 windows < nt, so do not use this class there.'''
206
215
207 # tried to use win32file._open_osfhandle to pass fd to os.fdopen,
216 # tried to use win32file._open_osfhandle to pass fd to os.fdopen,
208 # but does not work at all. wrap win32 file api instead.
217 # but does not work at all. wrap win32 file api instead.
209
218
210 def __init__(self, name, mode='rb'):
219 def __init__(self, name, mode='rb'):
211 access = 0
220 access = 0
212 if 'r' in mode or '+' in mode:
221 if 'r' in mode or '+' in mode:
213 access |= win32file.GENERIC_READ
222 access |= win32file.GENERIC_READ
214 if 'w' in mode or 'a' in mode or '+' in mode:
223 if 'w' in mode or 'a' in mode or '+' in mode:
215 access |= win32file.GENERIC_WRITE
224 access |= win32file.GENERIC_WRITE
216 if 'r' in mode:
225 if 'r' in mode:
217 creation = win32file.OPEN_EXISTING
226 creation = win32file.OPEN_EXISTING
218 elif 'a' in mode:
227 elif 'a' in mode:
219 creation = win32file.OPEN_ALWAYS
228 creation = win32file.OPEN_ALWAYS
220 else:
229 else:
221 creation = win32file.CREATE_ALWAYS
230 creation = win32file.CREATE_ALWAYS
222 try:
231 try:
223 self.handle = win32file.CreateFile(name,
232 self.handle = win32file.CreateFile(name,
224 access,
233 access,
225 win32file.FILE_SHARE_READ |
234 win32file.FILE_SHARE_READ |
226 win32file.FILE_SHARE_WRITE |
235 win32file.FILE_SHARE_WRITE |
227 win32file.FILE_SHARE_DELETE,
236 win32file.FILE_SHARE_DELETE,
228 None,
237 None,
229 creation,
238 creation,
230 win32file.FILE_ATTRIBUTE_NORMAL,
239 win32file.FILE_ATTRIBUTE_NORMAL,
231 0)
240 0)
232 except pywintypes.error, err:
241 except pywintypes.error, err:
233 raise WinIOError(err, name)
242 raise WinIOError(err, name)
234 self.closed = False
243 self.closed = False
235 self.name = name
244 self.name = name
236 self.mode = mode
245 self.mode = mode
237
246
238 def __iter__(self):
247 def __iter__(self):
239 for line in self.read().splitlines(True):
248 for line in self.read().splitlines(True):
240 yield line
249 yield line
241
250
242 def read(self, count=-1):
251 def read(self, count=-1):
243 try:
252 try:
244 cs = cStringIO.StringIO()
253 cs = cStringIO.StringIO()
245 while count:
254 while count:
246 wincount = int(count)
255 wincount = int(count)
247 if wincount == -1:
256 if wincount == -1:
248 wincount = 1048576
257 wincount = 1048576
249 val, data = win32file.ReadFile(self.handle, wincount)
258 val, data = win32file.ReadFile(self.handle, wincount)
250 if not data: break
259 if not data: break
251 cs.write(data)
260 cs.write(data)
252 if count != -1:
261 if count != -1:
253 count -= len(data)
262 count -= len(data)
254 return cs.getvalue()
263 return cs.getvalue()
255 except pywintypes.error, err:
264 except pywintypes.error, err:
256 raise WinIOError(err)
265 raise WinIOError(err)
257
266
258 def write(self, data):
267 def write(self, data):
259 try:
268 try:
260 if 'a' in self.mode:
269 if 'a' in self.mode:
261 win32file.SetFilePointer(self.handle, 0, win32file.FILE_END)
270 win32file.SetFilePointer(self.handle, 0, win32file.FILE_END)
262 nwrit = 0
271 nwrit = 0
263 while nwrit < len(data):
272 while nwrit < len(data):
264 val, nwrit = win32file.WriteFile(self.handle, data)
273 val, nwrit = win32file.WriteFile(self.handle, data)
265 data = data[nwrit:]
274 data = data[nwrit:]
266 except pywintypes.error, err:
275 except pywintypes.error, err:
267 raise WinIOError(err)
276 raise WinIOError(err)
268
277
269 def seek(self, pos, whence=0):
278 def seek(self, pos, whence=0):
270 try:
279 try:
271 win32file.SetFilePointer(self.handle, int(pos), whence)
280 win32file.SetFilePointer(self.handle, int(pos), whence)
272 except pywintypes.error, err:
281 except pywintypes.error, err:
273 raise WinIOError(err)
282 raise WinIOError(err)
274
283
275 def tell(self):
284 def tell(self):
276 try:
285 try:
277 return win32file.SetFilePointer(self.handle, 0,
286 return win32file.SetFilePointer(self.handle, 0,
278 win32file.FILE_CURRENT)
287 win32file.FILE_CURRENT)
279 except pywintypes.error, err:
288 except pywintypes.error, err:
280 raise WinIOError(err)
289 raise WinIOError(err)
281
290
282 def close(self):
291 def close(self):
283 if not self.closed:
292 if not self.closed:
284 self.handle = None
293 self.handle = None
285 self.closed = True
294 self.closed = True
286
295
287 def flush(self):
296 def flush(self):
288 try:
297 try:
289 win32file.FlushFileBuffers(self.handle)
298 win32file.FlushFileBuffers(self.handle)
290 except pywintypes.error, err:
299 except pywintypes.error, err:
291 raise WinIOError(err)
300 raise WinIOError(err)
292
301
293 def truncate(self, pos=0):
302 def truncate(self, pos=0):
294 try:
303 try:
295 win32file.SetFilePointer(self.handle, int(pos),
304 win32file.SetFilePointer(self.handle, int(pos),
296 win32file.FILE_BEGIN)
305 win32file.FILE_BEGIN)
297 win32file.SetEndOfFile(self.handle)
306 win32file.SetEndOfFile(self.handle)
298 except pywintypes.error, err:
307 except pywintypes.error, err:
299 raise WinIOError(err)
308 raise WinIOError(err)
300
309
301 getuser_fallback = win32api.GetUserName
310 getuser_fallback = win32api.GetUserName
302
311
303 def set_signal_handler_win32():
312 def set_signal_handler_win32():
304 """Register a termination handler for console events including
313 """Register a termination handler for console events including
305 CTRL+C. python signal handlers do not work well with socket
314 CTRL+C. python signal handlers do not work well with socket
306 operations.
315 operations.
307 """
316 """
308 def handler(event):
317 def handler(event):
309 win32process.ExitProcess(1)
318 win32process.ExitProcess(1)
310 win32api.SetConsoleCtrlHandler(handler)
319 win32api.SetConsoleCtrlHandler(handler)
General Comments 0
You need to be logged in to leave comments. Login now