##// END OF EJS Templates
osutil: c_ssize_t is only available in Python >= 2.7
Bryan O'Sullivan -
r27512:e2aa9c40 default
parent child Browse files
Show More
@@ -1,256 +1,256 b''
1 1 # osutil.py - pure Python version of osutil.c
2 2 #
3 3 # Copyright 2009 Matt Mackall <mpm@selenic.com> and others
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 from __future__ import absolute_import
9 9
10 10 import ctypes
11 11 import ctypes.util
12 12 import os
13 13 import socket
14 14 import stat as statmod
15 15 import sys
16 16
17 17 def _mode_to_kind(mode):
18 18 if statmod.S_ISREG(mode):
19 19 return statmod.S_IFREG
20 20 if statmod.S_ISDIR(mode):
21 21 return statmod.S_IFDIR
22 22 if statmod.S_ISLNK(mode):
23 23 return statmod.S_IFLNK
24 24 if statmod.S_ISBLK(mode):
25 25 return statmod.S_IFBLK
26 26 if statmod.S_ISCHR(mode):
27 27 return statmod.S_IFCHR
28 28 if statmod.S_ISFIFO(mode):
29 29 return statmod.S_IFIFO
30 30 if statmod.S_ISSOCK(mode):
31 31 return statmod.S_IFSOCK
32 32 return mode
33 33
34 34 def listdir(path, stat=False, skip=None):
35 35 '''listdir(path, stat=False) -> list_of_tuples
36 36
37 37 Return a sorted list containing information about the entries
38 38 in the directory.
39 39
40 40 If stat is True, each element is a 3-tuple:
41 41
42 42 (name, type, stat object)
43 43
44 44 Otherwise, each element is a 2-tuple:
45 45
46 46 (name, type)
47 47 '''
48 48 result = []
49 49 prefix = path
50 50 if not prefix.endswith(os.sep):
51 51 prefix += os.sep
52 52 names = os.listdir(path)
53 53 names.sort()
54 54 for fn in names:
55 55 st = os.lstat(prefix + fn)
56 56 if fn == skip and statmod.S_ISDIR(st.st_mode):
57 57 return []
58 58 if stat:
59 59 result.append((fn, _mode_to_kind(st.st_mode), st))
60 60 else:
61 61 result.append((fn, _mode_to_kind(st.st_mode)))
62 62 return result
63 63
64 64 if os.name != 'nt':
65 65 posixfile = open
66 66
67 67 _SCM_RIGHTS = 0x01
68 68 _socklen_t = ctypes.c_uint
69 69
70 70 if sys.platform == 'linux2':
71 71 # socket.h says "the type should be socklen_t but the definition of
72 72 # the kernel is incompatible with this."
73 73 _cmsg_len_t = ctypes.c_size_t
74 74 _msg_controllen_t = ctypes.c_size_t
75 75 _msg_iovlen_t = ctypes.c_size_t
76 76 else:
77 77 _cmsg_len_t = _socklen_t
78 78 _msg_controllen_t = _socklen_t
79 79 _msg_iovlen_t = ctypes.c_int
80 80
81 81 class _iovec(ctypes.Structure):
82 82 _fields_ = [
83 83 ('iov_base', ctypes.c_void_p),
84 84 ('iov_len', ctypes.c_size_t),
85 85 ]
86 86
87 87 class _msghdr(ctypes.Structure):
88 88 _fields_ = [
89 89 ('msg_name', ctypes.c_void_p),
90 90 ('msg_namelen', _socklen_t),
91 91 ('msg_iov', ctypes.POINTER(_iovec)),
92 92 ('msg_iovlen', _msg_iovlen_t),
93 93 ('msg_control', ctypes.c_void_p),
94 94 ('msg_controllen', _msg_controllen_t),
95 95 ('msg_flags', ctypes.c_int),
96 96 ]
97 97
98 98 class _cmsghdr(ctypes.Structure):
99 99 _fields_ = [
100 100 ('cmsg_len', _cmsg_len_t),
101 101 ('cmsg_level', ctypes.c_int),
102 102 ('cmsg_type', ctypes.c_int),
103 103 ('cmsg_data', ctypes.c_ubyte * 0),
104 104 ]
105 105
106 106 _libc = ctypes.CDLL(ctypes.util.find_library('c'), use_errno=True)
107 107 _recvmsg = _libc.recvmsg
108 _recvmsg.restype = ctypes.c_ssize_t
108 _recvmsg.restype = getattr(ctypes, 'c_ssize_t', ctypes.c_long)
109 109 _recvmsg.argtypes = (ctypes.c_int, ctypes.POINTER(_msghdr), ctypes.c_int)
110 110
111 111 def _CMSG_FIRSTHDR(msgh):
112 112 if msgh.msg_controllen < ctypes.sizeof(_cmsghdr):
113 113 return
114 114 cmsgptr = ctypes.cast(msgh.msg_control, ctypes.POINTER(_cmsghdr))
115 115 return cmsgptr.contents
116 116
117 117 # The pure version is less portable than the native version because the
118 118 # handling of socket ancillary data heavily depends on C preprocessor.
119 119 # Also, some length fields are wrongly typed in Linux kernel.
120 120 def recvfds(sockfd):
121 121 """receive list of file descriptors via socket"""
122 122 dummy = (ctypes.c_ubyte * 1)()
123 123 iov = _iovec(ctypes.cast(dummy, ctypes.c_void_p), ctypes.sizeof(dummy))
124 124 cbuf = ctypes.create_string_buffer(256)
125 125 msgh = _msghdr(None, 0,
126 126 ctypes.pointer(iov), 1,
127 127 ctypes.cast(cbuf, ctypes.c_void_p), ctypes.sizeof(cbuf),
128 128 0)
129 129 r = _recvmsg(sockfd, ctypes.byref(msgh), 0)
130 130 if r < 0:
131 131 e = ctypes.get_errno()
132 132 raise OSError(e, os.strerror(e))
133 133 # assumes that the first cmsg has fds because it isn't easy to write
134 134 # portable CMSG_NXTHDR() with ctypes.
135 135 cmsg = _CMSG_FIRSTHDR(msgh)
136 136 if not cmsg:
137 137 return []
138 138 if (cmsg.cmsg_level != socket.SOL_SOCKET or
139 139 cmsg.cmsg_type != _SCM_RIGHTS):
140 140 return []
141 141 rfds = ctypes.cast(cmsg.cmsg_data, ctypes.POINTER(ctypes.c_int))
142 142 rfdscount = ((cmsg.cmsg_len - _cmsghdr.cmsg_data.offset) /
143 143 ctypes.sizeof(ctypes.c_int))
144 144 return [rfds[i] for i in xrange(rfdscount)]
145 145
146 146 else:
147 147 import msvcrt
148 148
149 149 _kernel32 = ctypes.windll.kernel32
150 150
151 151 _DWORD = ctypes.c_ulong
152 152 _LPCSTR = _LPSTR = ctypes.c_char_p
153 153 _HANDLE = ctypes.c_void_p
154 154
155 155 _INVALID_HANDLE_VALUE = _HANDLE(-1).value
156 156
157 157 # CreateFile
158 158 _FILE_SHARE_READ = 0x00000001
159 159 _FILE_SHARE_WRITE = 0x00000002
160 160 _FILE_SHARE_DELETE = 0x00000004
161 161
162 162 _CREATE_ALWAYS = 2
163 163 _OPEN_EXISTING = 3
164 164 _OPEN_ALWAYS = 4
165 165
166 166 _GENERIC_READ = 0x80000000
167 167 _GENERIC_WRITE = 0x40000000
168 168
169 169 _FILE_ATTRIBUTE_NORMAL = 0x80
170 170
171 171 # open_osfhandle flags
172 172 _O_RDONLY = 0x0000
173 173 _O_RDWR = 0x0002
174 174 _O_APPEND = 0x0008
175 175
176 176 _O_TEXT = 0x4000
177 177 _O_BINARY = 0x8000
178 178
179 179 # types of parameters of C functions used (required by pypy)
180 180
181 181 _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p,
182 182 _DWORD, _DWORD, _HANDLE]
183 183 _kernel32.CreateFileA.restype = _HANDLE
184 184
185 185 def _raiseioerror(name):
186 186 err = ctypes.WinError()
187 187 raise IOError(err.errno, '%s: %s' % (name, err.strerror))
188 188
189 189 class posixfile(object):
190 190 '''a file object aiming for POSIX-like semantics
191 191
192 192 CPython's open() returns a file that was opened *without* setting the
193 193 _FILE_SHARE_DELETE flag, which causes rename and unlink to abort.
194 194 This even happens if any hardlinked copy of the file is in open state.
195 195 We set _FILE_SHARE_DELETE here, so files opened with posixfile can be
196 196 renamed and deleted while they are held open.
197 197 Note that if a file opened with posixfile is unlinked, the file
198 198 remains but cannot be opened again or be recreated under the same name,
199 199 until all reading processes have closed the file.'''
200 200
201 201 def __init__(self, name, mode='r', bufsize=-1):
202 202 if 'b' in mode:
203 203 flags = _O_BINARY
204 204 else:
205 205 flags = _O_TEXT
206 206
207 207 m0 = mode[0]
208 208 if m0 == 'r' and '+' not in mode:
209 209 flags |= _O_RDONLY
210 210 access = _GENERIC_READ
211 211 else:
212 212 # work around http://support.microsoft.com/kb/899149 and
213 213 # set _O_RDWR for 'w' and 'a', even if mode has no '+'
214 214 flags |= _O_RDWR
215 215 access = _GENERIC_READ | _GENERIC_WRITE
216 216
217 217 if m0 == 'r':
218 218 creation = _OPEN_EXISTING
219 219 elif m0 == 'w':
220 220 creation = _CREATE_ALWAYS
221 221 elif m0 == 'a':
222 222 creation = _OPEN_ALWAYS
223 223 flags |= _O_APPEND
224 224 else:
225 225 raise ValueError("invalid mode: %s" % mode)
226 226
227 227 fh = _kernel32.CreateFileA(name, access,
228 228 _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE,
229 229 None, creation, _FILE_ATTRIBUTE_NORMAL, None)
230 230 if fh == _INVALID_HANDLE_VALUE:
231 231 _raiseioerror(name)
232 232
233 233 fd = msvcrt.open_osfhandle(fh, flags)
234 234 if fd == -1:
235 235 _kernel32.CloseHandle(fh)
236 236 _raiseioerror(name)
237 237
238 238 f = os.fdopen(fd, mode, bufsize)
239 239 # unfortunately, f.name is '<fdopen>' at this point -- so we store
240 240 # the name on this wrapper. We cannot just assign to f.name,
241 241 # because that attribute is read-only.
242 242 object.__setattr__(self, 'name', name)
243 243 object.__setattr__(self, '_file', f)
244 244
245 245 def __iter__(self):
246 246 return self._file
247 247
248 248 def __getattr__(self, name):
249 249 return getattr(self._file, name)
250 250
251 251 def __setattr__(self, name, value):
252 252 '''mimics the read-only attributes of Python file objects
253 253 by raising 'TypeError: readonly attribute' if someone tries:
254 254 f = posixfile('foo.txt')
255 255 f.name = 'bla' '''
256 256 return self._file.__setattr__(name, value)
General Comments 0
You need to be logged in to leave comments. Login now