PageRenderTime 43ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/pypy/module/fcntl/interp_fcntl.py

https://bitbucket.org/pypy/pypy/
Python | 257 lines | 208 code | 19 blank | 30 comment | 27 complexity | 989ce0736ea48467064818daacf6e489 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. from rpython.rtyper.tool import rffi_platform as platform
  2. from rpython.rtyper.lltypesystem import rffi, lltype
  3. from pypy.interpreter.error import OperationError, oefmt, wrap_oserror
  4. from pypy.interpreter.gateway import unwrap_spec, WrappedDefault
  5. from rpython.rlib import rposix
  6. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  7. import sys
  8. class CConfig:
  9. _compilation_info_ = ExternalCompilationInfo(
  10. includes = ['fcntl.h', 'sys/file.h', 'sys/ioctl.h']
  11. )
  12. flock = platform.Struct("struct flock",
  13. [('l_start', rffi.LONGLONG), ('l_len', rffi.LONGLONG),
  14. ('l_pid', rffi.LONG), ('l_type', rffi.SHORT),
  15. ('l_whence', rffi.SHORT)])
  16. has_flock = platform.Has('flock')
  17. # constants, look in fcntl.h and platform docs for the meaning
  18. # some constants are linux only so they will be correctly exposed outside
  19. # depending on the OS
  20. constants = {}
  21. constant_names = ['LOCK_SH', 'LOCK_EX', 'LOCK_NB', 'LOCK_UN', 'F_DUPFD',
  22. 'F_GETFD', 'F_SETFD', 'F_GETFL', 'F_SETFL', 'F_UNLCK', 'FD_CLOEXEC',
  23. 'LOCK_MAND', 'LOCK_READ', 'LOCK_WRITE', 'LOCK_RW', 'F_GETSIG', 'F_SETSIG',
  24. 'F_GETLK64', 'F_SETLK64', 'F_SETLKW64', 'F_GETLK', 'F_SETLK', 'F_SETLKW',
  25. 'F_GETOWN', 'F_SETOWN', 'F_RDLCK', 'F_WRLCK', 'F_SETLEASE', 'F_GETLEASE',
  26. 'F_NOTIFY', 'F_EXLCK', 'F_SHLCK', 'DN_ACCESS', 'DN_MODIFY', 'DN_CREATE',
  27. 'DN_DELETE', 'DN_RENAME', 'DN_ATTRIB', 'DN_MULTISHOT', 'I_NREAD',
  28. 'I_PUSH', 'I_POP', 'I_LOOK', 'I_FLUSH', 'I_SRDOPT', 'I_GRDOPT', 'I_STR',
  29. 'I_SETSIG', 'I_GETSIG', 'I_FIND', 'I_LINK', 'I_UNLINK', 'I_PEEK',
  30. 'I_FDINSERT', 'I_SENDFD', 'I_RECVFD', 'I_SWROPT', 'I_LIST', 'I_PLINK',
  31. 'I_PUNLINK', 'I_FLUSHBAND', 'I_CKBAND', 'I_GETBAND', 'I_ATMARK',
  32. 'I_SETCLTIME', 'I_GETCLTIME', 'I_CANPUT']
  33. for name in constant_names:
  34. setattr(CConfig, name, platform.DefinedConstantInteger(name))
  35. class cConfig(object):
  36. pass
  37. for k, v in platform.configure(CConfig).items():
  38. setattr(cConfig, k, v)
  39. cConfig.flock.__name__ = "_flock"
  40. if "linux" in sys.platform:
  41. cConfig.F_GETSIG = 11
  42. cConfig.F_SETSIG = 10
  43. cConfig.F_GETLEASE = 1025
  44. cConfig.F_SETLEASE = 1024
  45. # needed to export the constants inside and outside. see __init__.py
  46. for name in constant_names:
  47. value = getattr(cConfig, name)
  48. if value is not None:
  49. constants[name] = value
  50. locals().update(constants)
  51. def external(name, args, result, **kwds):
  52. return rffi.llexternal(name, args, result,
  53. compilation_info=CConfig._compilation_info_,
  54. **kwds)
  55. _flock = lltype.Ptr(cConfig.flock)
  56. fcntl_int = external('fcntl', [rffi.INT, rffi.INT, rffi.INT], rffi.INT,
  57. save_err=rffi.RFFI_SAVE_ERRNO)
  58. fcntl_str = external('fcntl', [rffi.INT, rffi.INT, rffi.CCHARP], rffi.INT,
  59. save_err=rffi.RFFI_SAVE_ERRNO)
  60. fcntl_flock = external('fcntl', [rffi.INT, rffi.INT, _flock], rffi.INT,
  61. save_err=rffi.RFFI_SAVE_ERRNO)
  62. ioctl_int = external('ioctl', [rffi.INT, rffi.UINT, rffi.INT], rffi.INT,
  63. save_err=rffi.RFFI_SAVE_ERRNO)
  64. ioctl_str = external('ioctl', [rffi.INT, rffi.UINT, rffi.CCHARP], rffi.INT,
  65. save_err=rffi.RFFI_SAVE_ERRNO)
  66. has_flock = cConfig.has_flock
  67. if has_flock:
  68. c_flock = external('flock', [rffi.INT, rffi.INT], rffi.INT,
  69. save_err=rffi.RFFI_SAVE_ERRNO)
  70. def _get_error(space, funcname):
  71. errno = rposix.get_saved_errno()
  72. return wrap_oserror(space, OSError(errno, funcname),
  73. exception_name = 'w_IOError')
  74. @unwrap_spec(op=int, w_arg=WrappedDefault(0))
  75. def fcntl(space, w_fd, op, w_arg):
  76. """fcntl(fd, op, [arg])
  77. Perform the requested operation on file descriptor fd. The operation
  78. is defined by op and is operating system dependent. These constants are
  79. available from the fcntl module. The argument arg is optional, and
  80. defaults to 0; it may be an int or a string. If arg is given as a string,
  81. the return value of fcntl is a string of that length, containing the
  82. resulting value put in the arg buffer by the operating system. If the
  83. arg given is an integer or if none is specified, the result value is an
  84. integer corresponding to the return value of the fcntl call in the C code.
  85. """
  86. fd = space.c_filedescriptor_w(w_fd)
  87. op = rffi.cast(rffi.INT, op) # C long => C int
  88. try:
  89. arg = space.getarg_w('s#', w_arg)
  90. except OperationError as e:
  91. if not e.match(space, space.w_TypeError):
  92. raise
  93. else:
  94. ll_arg = rffi.str2charp(arg)
  95. try:
  96. rv = fcntl_str(fd, op, ll_arg)
  97. if rv < 0:
  98. raise _get_error(space, "fcntl")
  99. arg = rffi.charpsize2str(ll_arg, len(arg))
  100. return space.wrap(arg)
  101. finally:
  102. lltype.free(ll_arg, flavor='raw')
  103. intarg = space.int_w(w_arg)
  104. intarg = rffi.cast(rffi.INT, intarg) # C long => C int
  105. rv = fcntl_int(fd, op, intarg)
  106. if rv < 0:
  107. raise _get_error(space, "fcntl")
  108. return space.wrap(rv)
  109. @unwrap_spec(op=int)
  110. def flock(space, w_fd, op):
  111. """flock(fd, operation)
  112. Perform the lock operation op on file descriptor fd. See the Unix
  113. manual flock(3) for details. (On some systems, this function is
  114. emulated using fcntl().)"""
  115. if has_flock:
  116. fd = space.c_filedescriptor_w(w_fd)
  117. op = rffi.cast(rffi.INT, op) # C long => C int
  118. rv = c_flock(fd, op)
  119. if rv < 0:
  120. raise _get_error(space, "flock")
  121. else:
  122. lockf(space, w_fd, op)
  123. @unwrap_spec(op=int, length=int, start=int, whence=int)
  124. def lockf(space, w_fd, op, length=0, start=0, whence=0):
  125. """lockf (fd, operation, length=0, start=0, whence=0)
  126. This is essentially a wrapper around the fcntl() locking calls. fd is the
  127. file descriptor of the file to lock or unlock, and operation is one of the
  128. following values:
  129. LOCK_UN - unlock
  130. LOCK_SH - acquire a shared lock
  131. LOCK_EX - acquire an exclusive lock
  132. When operation is LOCK_SH or LOCK_EX, it can also be bit-wise OR'd with
  133. LOCK_NB to avoid blocking on lock acquisition. If LOCK_NB is used and the
  134. lock cannot be acquired, an IOError will be raised and the exception will
  135. have an errno attribute set to EACCES or EAGAIN (depending on the
  136. operating system -- for portability, check for either value).
  137. length is the number of bytes to lock, with the default meaning to lock to
  138. EOF. start is the byte offset, relative to whence, to that the lock
  139. starts. whence is as with fileobj.seek(), specifically:
  140. 0 - relative to the start of the file (SEEK_SET)
  141. 1 - relative to the current buffer position (SEEK_CUR)
  142. 2 - relative to the end of the file (SEEK_END)"""
  143. fd = space.c_filedescriptor_w(w_fd)
  144. if op == LOCK_UN:
  145. l_type = F_UNLCK
  146. elif op & LOCK_SH:
  147. l_type = F_RDLCK
  148. elif op & LOCK_EX:
  149. l_type = F_WRLCK
  150. else:
  151. raise oefmt(space.w_ValueError, "unrecognized lock operation")
  152. op = [F_SETLKW, F_SETLK][int(bool(op & LOCK_NB))]
  153. op = rffi.cast(rffi.INT, op) # C long => C int
  154. l = lltype.malloc(_flock.TO, flavor='raw')
  155. try:
  156. rffi.setintfield(l, 'c_l_type', l_type)
  157. rffi.setintfield(l, 'c_l_start', int(start))
  158. rffi.setintfield(l, 'c_l_len', int(length))
  159. rffi.setintfield(l, 'c_l_whence', int(whence))
  160. rv = fcntl_flock(fd, op, l)
  161. if rv < 0:
  162. raise _get_error(space, "fcntl")
  163. finally:
  164. lltype.free(l, flavor='raw')
  165. @unwrap_spec(op=int, mutate_flag=int, w_arg=WrappedDefault(0))
  166. def ioctl(space, w_fd, op, w_arg, mutate_flag=-1):
  167. """ioctl(fd, opt[, arg[, mutate_flag]])
  168. Perform the requested operation on file descriptor fd. The operation is
  169. defined by opt and is operating system dependent. Typically these codes
  170. are retrieved from the fcntl or termios library modules.
  171. """
  172. # removed the largish docstring because it is not in sync with the
  173. # documentation any more (even in CPython's docstring is out of date)
  174. # XXX this function's interface is a mess.
  175. # We try to emulate the behavior of Python >= 2.5 w.r.t. mutate_flag
  176. fd = space.c_filedescriptor_w(w_fd)
  177. op = rffi.cast(rffi.INT, op) # C long => C int
  178. try:
  179. rwbuffer = space.writebuf_w(w_arg)
  180. except OperationError as e:
  181. if not e.match(space, space.w_TypeError):
  182. raise
  183. else:
  184. arg = rwbuffer.as_str()
  185. ll_arg = rffi.str2charp(arg)
  186. try:
  187. rv = ioctl_str(fd, op, ll_arg)
  188. if rv < 0:
  189. raise _get_error(space, "ioctl")
  190. arg = rffi.charpsize2str(ll_arg, len(arg))
  191. if mutate_flag != 0:
  192. rwbuffer.setslice(0, arg)
  193. return space.wrap(rv)
  194. return space.wrap(arg)
  195. finally:
  196. lltype.free(ll_arg, flavor='raw')
  197. if mutate_flag != -1:
  198. raise oefmt(space.w_TypeError,
  199. "ioctl requires a file or file descriptor, an integer and "
  200. "optionally an integer or buffer argument")
  201. try:
  202. arg = space.getarg_w('s#', w_arg)
  203. except OperationError as e:
  204. if not e.match(space, space.w_TypeError):
  205. raise
  206. else:
  207. ll_arg = rffi.str2charp(arg)
  208. try:
  209. rv = ioctl_str(fd, op, ll_arg)
  210. if rv < 0:
  211. raise _get_error(space, "ioctl")
  212. arg = rffi.charpsize2str(ll_arg, len(arg))
  213. return space.wrap(arg)
  214. finally:
  215. lltype.free(ll_arg, flavor='raw')
  216. intarg = space.int_w(w_arg)
  217. intarg = rffi.cast(rffi.INT, intarg) # C long => C int
  218. rv = ioctl_int(fd, op, intarg)
  219. if rv < 0:
  220. raise _get_error(space, "ioctl")
  221. return space.wrap(rv)