PageRenderTime 83ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/rpython/rlib/rposix.py

https://bitbucket.org/pypy/pypy/
Python | 2102 lines | 2094 code | 6 blank | 2 comment | 6 complexity | 8b57480c3d8c6ff67275ccde201af41d MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. import os
  2. import sys
  3. import errno
  4. from rpython.annotator.model import s_Str0
  5. from rpython.rtyper.lltypesystem.rffi import CConstant, CExternVariable, INT
  6. from rpython.rtyper.lltypesystem import lltype, ll2ctypes, rffi
  7. from rpython.rtyper.tool import rffi_platform
  8. from rpython.rlib import debug, jit, rstring, rthread, types
  9. from rpython.rlib._os_support import (
  10. _CYGWIN, _MACRO_ON_POSIX, UNDERSCORE_ON_WIN32, _WIN32,
  11. _prefer_unicode, _preferred_traits)
  12. from rpython.rlib.objectmodel import (
  13. specialize, enforceargs, register_replacement_for, NOT_CONSTANT)
  14. from rpython.rlib.rarithmetic import intmask, widen
  15. from rpython.rlib.signature import signature
  16. from rpython.tool.sourcetools import func_renamer
  17. from rpython.translator.platform import platform
  18. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  19. if _WIN32:
  20. from rpython.rlib import rwin32
  21. from rpython.rlib.rwin32file import make_win32_traits
  22. class CConstantErrno(CConstant):
  23. # these accessors are used when calling get_errno() or set_errno()
  24. # on top of CPython
  25. def __getitem__(self, index):
  26. assert index == 0
  27. try:
  28. return ll2ctypes.TLS.errno
  29. except AttributeError:
  30. raise ValueError("no C function call occurred so far, "
  31. "errno is undefined")
  32. def __setitem__(self, index, value):
  33. assert index == 0
  34. ll2ctypes.TLS.errno = value
  35. if os.name == 'nt':
  36. if platform.name == 'msvc':
  37. includes=['errno.h','stdio.h']
  38. else:
  39. includes=['errno.h','stdio.h', 'stdint.h']
  40. separate_module_sources =['''
  41. /* Lifted completely from CPython 3.3 Modules/posix_module.c */
  42. #include <malloc.h> /* for _msize */
  43. typedef struct {
  44. intptr_t osfhnd;
  45. char osfile;
  46. } my_ioinfo;
  47. extern __declspec(dllimport) char * __pioinfo[];
  48. #define IOINFO_L2E 5
  49. #define IOINFO_ARRAY_ELTS (1 << IOINFO_L2E)
  50. #define IOINFO_ARRAYS 64
  51. #define _NHANDLE_ (IOINFO_ARRAYS * IOINFO_ARRAY_ELTS)
  52. #define FOPEN 0x01
  53. #define _NO_CONSOLE_FILENO (intptr_t)-2
  54. /* This function emulates what the windows CRT
  55. does to validate file handles */
  56. RPY_EXTERN int
  57. _PyVerify_fd(int fd)
  58. {
  59. const int i1 = fd >> IOINFO_L2E;
  60. const int i2 = fd & ((1 << IOINFO_L2E) - 1);
  61. static size_t sizeof_ioinfo = 0;
  62. /* Determine the actual size of the ioinfo structure,
  63. * as used by the CRT loaded in memory
  64. */
  65. if (sizeof_ioinfo == 0 && __pioinfo[0] != NULL) {
  66. sizeof_ioinfo = _msize(__pioinfo[0]) / IOINFO_ARRAY_ELTS;
  67. }
  68. if (sizeof_ioinfo == 0) {
  69. /* This should not happen... */
  70. goto fail;
  71. }
  72. /* See that it isn't a special CLEAR fileno */
  73. if (fd != _NO_CONSOLE_FILENO) {
  74. /* Microsoft CRT would check that 0<=fd<_nhandle but we can't do that. Instead
  75. * we check pointer validity and other info
  76. */
  77. if (0 <= i1 && i1 < IOINFO_ARRAYS && __pioinfo[i1] != NULL) {
  78. /* finally, check that the file is open */
  79. my_ioinfo* info = (my_ioinfo*)(__pioinfo[i1] + i2 * sizeof_ioinfo);
  80. if (info->osfile & FOPEN) {
  81. return 1;
  82. }
  83. }
  84. }
  85. fail:
  86. errno = EBADF;
  87. return 0;
  88. }
  89. ''',]
  90. post_include_bits=['RPY_EXTERN int _PyVerify_fd(int);']
  91. else:
  92. separate_module_sources = []
  93. post_include_bits = []
  94. includes=['errno.h','stdio.h']
  95. errno_eci = ExternalCompilationInfo(
  96. includes=includes,
  97. separate_module_sources=separate_module_sources,
  98. post_include_bits=post_include_bits,
  99. )
  100. # Direct getters/setters, don't use directly!
  101. _get_errno, _set_errno = CExternVariable(INT, 'errno', errno_eci,
  102. CConstantErrno, sandboxsafe=True,
  103. _nowrapper=True, c_type='int')
  104. def get_saved_errno():
  105. """Return the value of the "saved errno".
  106. This value is saved after a call to a C function, if it was declared
  107. with the flag llexternal(..., save_err=rffi.RFFI_SAVE_ERRNO).
  108. Functions without that flag don't change the saved errno.
  109. """
  110. return intmask(rthread.tlfield_rpy_errno.getraw())
  111. def set_saved_errno(errno):
  112. """Set the value of the saved errno. This value will be used to
  113. initialize the real errno just before calling the following C function,
  114. provided it was declared llexternal(..., save_err=RFFI_READSAVED_ERRNO).
  115. Note also that it is more common to want the real errno to be initially
  116. zero; for that case, use llexternal(..., save_err=RFFI_ZERO_ERRNO_BEFORE)
  117. and then you don't need set_saved_errno(0).
  118. """
  119. rthread.tlfield_rpy_errno.setraw(rffi.cast(INT, errno))
  120. def get_saved_alterrno():
  121. """Return the value of the "saved alterrno".
  122. This value is saved after a call to a C function, if it was declared
  123. with the flag llexternal(..., save_err=rffi.RFFI_SAVE_ERRNO | rffl.RFFI_ALT_ERRNO).
  124. Functions without that flag don't change the saved errno.
  125. """
  126. return intmask(rthread.tlfield_alt_errno.getraw())
  127. def set_saved_alterrno(errno):
  128. """Set the value of the saved alterrno. This value will be used to
  129. initialize the real errno just before calling the following C function,
  130. provided it was declared llexternal(..., save_err=RFFI_READSAVED_ERRNO | rffl.RFFI_ALT_ERRNO).
  131. Note also that it is more common to want the real errno to be initially
  132. zero; for that case, use llexternal(..., save_err=RFFI_ZERO_ERRNO_BEFORE)
  133. and then you don't need set_saved_errno(0).
  134. """
  135. rthread.tlfield_alt_errno.setraw(rffi.cast(INT, errno))
  136. # These are not posix specific, but where should they move to?
  137. @specialize.call_location()
  138. def _errno_before(save_err):
  139. if save_err & rffi.RFFI_READSAVED_ERRNO:
  140. if save_err & rffi.RFFI_ALT_ERRNO:
  141. _set_errno(rthread.tlfield_alt_errno.getraw())
  142. else:
  143. _set_errno(rthread.tlfield_rpy_errno.getraw())
  144. elif save_err & rffi.RFFI_ZERO_ERRNO_BEFORE:
  145. _set_errno(rffi.cast(rffi.INT, 0))
  146. if _WIN32 and (save_err & rffi.RFFI_READSAVED_LASTERROR):
  147. if save_err & rffi.RFFI_ALT_ERRNO:
  148. err = rthread.tlfield_alt_lasterror.getraw()
  149. else:
  150. err = rthread.tlfield_rpy_lasterror.getraw()
  151. # careful, getraw() overwrites GetLastError.
  152. # We must assign it with _SetLastError() as the last
  153. # operation, i.e. after the errno handling.
  154. rwin32._SetLastError(err)
  155. @specialize.call_location()
  156. def _errno_after(save_err):
  157. if _WIN32:
  158. if save_err & rffi.RFFI_SAVE_LASTERROR:
  159. err = rwin32._GetLastError()
  160. # careful, setraw() overwrites GetLastError.
  161. # We must read it first, before the errno handling.
  162. if save_err & rffi.RFFI_ALT_ERRNO:
  163. rthread.tlfield_alt_lasterror.setraw(err)
  164. else:
  165. rthread.tlfield_rpy_lasterror.setraw(err)
  166. elif save_err & rffi.RFFI_SAVE_WSALASTERROR:
  167. from rpython.rlib import _rsocket_rffi
  168. err = _rsocket_rffi._WSAGetLastError()
  169. if save_err & rffi.RFFI_ALT_ERRNO:
  170. rthread.tlfield_alt_lasterror.setraw(err)
  171. else:
  172. rthread.tlfield_rpy_lasterror.setraw(err)
  173. if save_err & rffi.RFFI_SAVE_ERRNO:
  174. if save_err & rffi.RFFI_ALT_ERRNO:
  175. rthread.tlfield_alt_errno.setraw(_get_errno())
  176. else:
  177. rthread.tlfield_rpy_errno.setraw(_get_errno())
  178. # ^^^ keep fork() up-to-date too, below
  179. if os.name == 'nt':
  180. is_valid_fd = jit.dont_look_inside(rffi.llexternal(
  181. "_PyVerify_fd", [rffi.INT], rffi.INT,
  182. compilation_info=errno_eci,
  183. ))
  184. @enforceargs(int)
  185. def validate_fd(fd):
  186. if not is_valid_fd(fd):
  187. from errno import EBADF
  188. raise OSError(EBADF, 'Bad file descriptor')
  189. else:
  190. def is_valid_fd(fd):
  191. return 1
  192. @enforceargs(int)
  193. def validate_fd(fd):
  194. pass
  195. def closerange(fd_low, fd_high):
  196. # this behaves like os.closerange() from Python 2.6.
  197. for fd in xrange(fd_low, fd_high):
  198. try:
  199. if is_valid_fd(fd):
  200. os.close(fd)
  201. except OSError:
  202. pass
  203. if _WIN32:
  204. includes = ['io.h', 'sys/utime.h', 'sys/types.h', 'process.h']
  205. libraries = []
  206. else:
  207. if sys.platform.startswith(('darwin', 'netbsd', 'openbsd')):
  208. _ptyh = 'util.h'
  209. elif sys.platform.startswith('freebsd'):
  210. _ptyh = 'libutil.h'
  211. else:
  212. _ptyh = 'pty.h'
  213. includes = ['unistd.h', 'sys/types.h', 'sys/wait.h',
  214. 'utime.h', 'sys/time.h', 'sys/times.h',
  215. 'grp.h', 'dirent.h', 'sys/stat.h', 'fcntl.h',
  216. 'signal.h', 'sys/utsname.h', _ptyh]
  217. libraries = ['util']
  218. eci = ExternalCompilationInfo(
  219. includes=includes,
  220. libraries=libraries,
  221. )
  222. class CConfig:
  223. _compilation_info_ = eci
  224. SEEK_SET = rffi_platform.DefinedConstantInteger('SEEK_SET')
  225. SEEK_CUR = rffi_platform.DefinedConstantInteger('SEEK_CUR')
  226. SEEK_END = rffi_platform.DefinedConstantInteger('SEEK_END')
  227. OFF_T_SIZE = rffi_platform.SizeOf('off_t')
  228. HAVE_UTIMES = rffi_platform.Has('utimes')
  229. UTIMBUF = rffi_platform.Struct('struct %sutimbuf' % UNDERSCORE_ON_WIN32,
  230. [('actime', rffi.INT),
  231. ('modtime', rffi.INT)])
  232. if not _WIN32:
  233. UID_T = rffi_platform.SimpleType('uid_t', rffi.UINT)
  234. GID_T = rffi_platform.SimpleType('gid_t', rffi.UINT)
  235. CLOCK_T = rffi_platform.SimpleType('clock_t', rffi.INT)
  236. TMS = rffi_platform.Struct(
  237. 'struct tms', [('tms_utime', rffi.INT),
  238. ('tms_stime', rffi.INT),
  239. ('tms_cutime', rffi.INT),
  240. ('tms_cstime', rffi.INT)])
  241. GETPGRP_HAVE_ARG = rffi_platform.Has("getpgrp(0)")
  242. SETPGRP_HAVE_ARG = rffi_platform.Has("setpgrp(0, 0)")
  243. config = rffi_platform.configure(CConfig)
  244. globals().update(config)
  245. def external(name, args, result, compilation_info=eci, **kwds):
  246. return rffi.llexternal(name, args, result,
  247. compilation_info=compilation_info, **kwds)
  248. # For now we require off_t to be the same size as LONGLONG, which is the
  249. # interface required by callers of functions that thake an argument of type
  250. # off_t.
  251. if not _WIN32:
  252. assert OFF_T_SIZE == rffi.sizeof(rffi.LONGLONG)
  253. c_dup = external(UNDERSCORE_ON_WIN32 + 'dup', [rffi.INT], rffi.INT,
  254. save_err=rffi.RFFI_SAVE_ERRNO)
  255. c_dup2 = external(UNDERSCORE_ON_WIN32 + 'dup2', [rffi.INT, rffi.INT], rffi.INT,
  256. save_err=rffi.RFFI_SAVE_ERRNO)
  257. c_open = external(UNDERSCORE_ON_WIN32 + 'open',
  258. [rffi.CCHARP, rffi.INT, rffi.MODE_T], rffi.INT,
  259. save_err=rffi.RFFI_SAVE_ERRNO)
  260. # Win32 Unicode functions
  261. c_wopen = external(UNDERSCORE_ON_WIN32 + 'wopen',
  262. [rffi.CWCHARP, rffi.INT, rffi.MODE_T], rffi.INT,
  263. save_err=rffi.RFFI_SAVE_ERRNO)
  264. #___________________________________________________________________
  265. # Wrappers around posix functions, that accept either strings, or
  266. # instances with a "as_bytes()" method.
  267. # - pypy.modules.posix.interp_posix passes an object containing a unicode path
  268. # which can encode itself with sys.filesystemencoding.
  269. # - but rpython.rtyper.module.ll_os.py on Windows will replace these functions
  270. # with other wrappers that directly handle unicode strings.
  271. @specialize.argtype(0)
  272. @signature(types.any(), returns=s_Str0)
  273. def _as_bytes(path):
  274. assert path is not None
  275. if isinstance(path, str):
  276. return path
  277. elif isinstance(path, unicode):
  278. # This never happens in PyPy's Python interpreter!
  279. # Only in raw RPython code that uses unicode strings.
  280. # We implement python2 behavior: silently convert to ascii.
  281. return path.encode('ascii')
  282. else:
  283. return path.as_bytes()
  284. @specialize.argtype(0)
  285. def _as_bytes0(path):
  286. """Crashes translation if the path contains NUL characters."""
  287. res = _as_bytes(path)
  288. rstring.check_str0(res)
  289. return res
  290. @specialize.argtype(0)
  291. def _as_unicode(path):
  292. assert path is not None
  293. if isinstance(path, unicode):
  294. return path
  295. else:
  296. return path.as_unicode()
  297. @specialize.argtype(0)
  298. def _as_unicode0(path):
  299. """Crashes translation if the path contains NUL characters."""
  300. res = _as_unicode(path)
  301. rstring.check_str0(res)
  302. return res
  303. @specialize.argtype(0, 1)
  304. def putenv(name, value):
  305. os.environ[_as_bytes(name)] = _as_bytes(value)
  306. @specialize.argtype(0)
  307. def unsetenv(name):
  308. del os.environ[_as_bytes(name)]
  309. #___________________________________________________________________
  310. # Implementation of many posix functions.
  311. # They usually check the return value and raise an (RPython) OSError
  312. # with errno.
  313. def replace_os_function(name):
  314. func = getattr(os, name, None)
  315. if func is None:
  316. return lambda f: f
  317. return register_replacement_for(
  318. func,
  319. sandboxed_name='ll_os.ll_os_%s' % name)
  320. @specialize.arg(0)
  321. def handle_posix_error(name, result):
  322. result = widen(result)
  323. if result < 0:
  324. raise OSError(get_saved_errno(), '%s failed' % name)
  325. return result
  326. @replace_os_function('dup')
  327. def dup(fd):
  328. validate_fd(fd)
  329. return handle_posix_error('dup', c_dup(fd))
  330. @replace_os_function('dup2')
  331. def dup2(fd, newfd):
  332. validate_fd(fd)
  333. handle_posix_error('dup2', c_dup2(fd, newfd))
  334. #___________________________________________________________________
  335. @replace_os_function('open')
  336. @specialize.argtype(0)
  337. @enforceargs(NOT_CONSTANT, int, int, typecheck=False)
  338. def open(path, flags, mode):
  339. if _prefer_unicode(path):
  340. fd = c_wopen(_as_unicode0(path), flags, mode)
  341. else:
  342. fd = c_open(_as_bytes0(path), flags, mode)
  343. return handle_posix_error('open', fd)
  344. c_read = external(UNDERSCORE_ON_WIN32 + 'read',
  345. [rffi.INT, rffi.VOIDP, rffi.SIZE_T], rffi.SSIZE_T,
  346. save_err=rffi.RFFI_SAVE_ERRNO)
  347. c_write = external(UNDERSCORE_ON_WIN32 + 'write',
  348. [rffi.INT, rffi.VOIDP, rffi.SIZE_T], rffi.SSIZE_T,
  349. save_err=rffi.RFFI_SAVE_ERRNO)
  350. c_close = external(UNDERSCORE_ON_WIN32 + 'close', [rffi.INT], rffi.INT,
  351. releasegil=False, save_err=rffi.RFFI_SAVE_ERRNO)
  352. @replace_os_function('read')
  353. @enforceargs(int, int)
  354. def read(fd, count):
  355. if count < 0:
  356. raise OSError(errno.EINVAL, None)
  357. validate_fd(fd)
  358. with rffi.scoped_alloc_buffer(count) as buf:
  359. void_buf = rffi.cast(rffi.VOIDP, buf.raw)
  360. got = handle_posix_error('read', c_read(fd, void_buf, count))
  361. return buf.str(got)
  362. @replace_os_function('write')
  363. @enforceargs(int, None)
  364. def write(fd, data):
  365. count = len(data)
  366. validate_fd(fd)
  367. with rffi.scoped_nonmovingbuffer(data) as buf:
  368. return handle_posix_error('write', c_write(fd, buf, count))
  369. @replace_os_function('close')
  370. def close(fd):
  371. validate_fd(fd)
  372. handle_posix_error('close', c_close(fd))
  373. c_lseek = external('_lseeki64' if _WIN32 else 'lseek',
  374. [rffi.INT, rffi.LONGLONG, rffi.INT], rffi.LONGLONG,
  375. macro=_MACRO_ON_POSIX, save_err=rffi.RFFI_SAVE_ERRNO)
  376. @replace_os_function('lseek')
  377. def lseek(fd, pos, how):
  378. validate_fd(fd)
  379. if SEEK_SET is not None:
  380. if how == 0:
  381. how = SEEK_SET
  382. elif how == 1:
  383. how = SEEK_CUR
  384. elif how == 2:
  385. how = SEEK_END
  386. return handle_posix_error('lseek', c_lseek(fd, pos, how))
  387. c_ftruncate = external('ftruncate', [rffi.INT, rffi.LONGLONG], rffi.INT,
  388. macro=_MACRO_ON_POSIX, save_err=rffi.RFFI_SAVE_ERRNO)
  389. c_fsync = external('fsync' if not _WIN32 else '_commit', [rffi.INT], rffi.INT,
  390. save_err=rffi.RFFI_SAVE_ERRNO)
  391. c_fdatasync = external('fdatasync', [rffi.INT], rffi.INT,
  392. save_err=rffi.RFFI_SAVE_ERRNO)
  393. @replace_os_function('ftruncate')
  394. def ftruncate(fd, length):
  395. validate_fd(fd)
  396. handle_posix_error('ftruncate', c_ftruncate(fd, length))
  397. @replace_os_function('fsync')
  398. def fsync(fd):
  399. validate_fd(fd)
  400. handle_posix_error('fsync', c_fsync(fd))
  401. @replace_os_function('fdatasync')
  402. def fdatasync(fd):
  403. validate_fd(fd)
  404. handle_posix_error('fdatasync', c_fdatasync(fd))
  405. #___________________________________________________________________
  406. c_chdir = external('chdir', [rffi.CCHARP], rffi.INT,
  407. save_err=rffi.RFFI_SAVE_ERRNO)
  408. c_fchdir = external('fchdir', [rffi.INT], rffi.INT,
  409. save_err=rffi.RFFI_SAVE_ERRNO)
  410. c_access = external(UNDERSCORE_ON_WIN32 + 'access',
  411. [rffi.CCHARP, rffi.INT], rffi.INT)
  412. c_waccess = external(UNDERSCORE_ON_WIN32 + 'waccess',
  413. [rffi.CWCHARP, rffi.INT], rffi.INT)
  414. @replace_os_function('chdir')
  415. @specialize.argtype(0)
  416. def chdir(path):
  417. if not _WIN32:
  418. handle_posix_error('chdir', c_chdir(_as_bytes0(path)))
  419. else:
  420. traits = _preferred_traits(path)
  421. win32traits = make_win32_traits(traits)
  422. path = traits.as_str0(path)
  423. # This is a reimplementation of the C library's chdir
  424. # function, but one that produces Win32 errors instead of DOS
  425. # error codes.
  426. # chdir is essentially a wrapper around SetCurrentDirectory;
  427. # however, it also needs to set "magic" environment variables
  428. # indicating the per-drive current directory, which are of the
  429. # form =<drive>:
  430. if not win32traits.SetCurrentDirectory(path):
  431. raise rwin32.lastSavedWindowsError()
  432. MAX_PATH = rwin32.MAX_PATH
  433. assert MAX_PATH > 0
  434. with traits.scoped_alloc_buffer(MAX_PATH) as path:
  435. res = win32traits.GetCurrentDirectory(MAX_PATH + 1, path.raw)
  436. if not res:
  437. raise rwin32.lastSavedWindowsError()
  438. res = rffi.cast(lltype.Signed, res)
  439. assert res > 0
  440. if res <= MAX_PATH + 1:
  441. new_path = path.str(res)
  442. else:
  443. with traits.scoped_alloc_buffer(res) as path:
  444. res = win32traits.GetCurrentDirectory(res, path.raw)
  445. if not res:
  446. raise rwin32.lastSavedWindowsError()
  447. res = rffi.cast(lltype.Signed, res)
  448. assert res > 0
  449. new_path = path.str(res)
  450. if traits.str is unicode:
  451. if new_path[0] == u'\\' or new_path[0] == u'/': # UNC path
  452. return
  453. magic_envvar = u'=' + new_path[0] + u':'
  454. else:
  455. if new_path[0] == '\\' or new_path[0] == '/': # UNC path
  456. return
  457. magic_envvar = '=' + new_path[0] + ':'
  458. if not win32traits.SetEnvironmentVariable(magic_envvar, new_path):
  459. raise rwin32.lastSavedWindowsError()
  460. @replace_os_function('fchdir')
  461. def fchdir(fd):
  462. validate_fd(fd)
  463. handle_posix_error('fchdir', c_fchdir(fd))
  464. @replace_os_function('access')
  465. @specialize.argtype(0)
  466. def access(path, mode):
  467. if _WIN32:
  468. # All files are executable on Windows
  469. mode = mode & ~os.X_OK
  470. if _prefer_unicode(path):
  471. error = c_waccess(_as_unicode0(path), mode)
  472. else:
  473. error = c_access(_as_bytes0(path), mode)
  474. return error == 0
  475. # This Win32 function is not exposed via os, but needed to get a
  476. # correct implementation of os.path.abspath.
  477. @specialize.argtype(0)
  478. def getfullpathname(path):
  479. length = rwin32.MAX_PATH + 1
  480. traits = _preferred_traits(path)
  481. win32traits = make_win32_traits(traits)
  482. with traits.scoped_alloc_buffer(length) as buf:
  483. res = win32traits.GetFullPathName(
  484. traits.as_str0(path), rffi.cast(rwin32.DWORD, length),
  485. buf.raw, lltype.nullptr(win32traits.LPSTRP.TO))
  486. if res == 0:
  487. raise rwin32.lastSavedWindowsError("_getfullpathname failed")
  488. result = buf.str(intmask(res))
  489. assert result is not None
  490. result = rstring.assert_str0(result)
  491. return result
  492. c_getcwd = external(UNDERSCORE_ON_WIN32 + 'getcwd',
  493. [rffi.CCHARP, rffi.SIZE_T], rffi.CCHARP,
  494. save_err=rffi.RFFI_SAVE_ERRNO)
  495. c_wgetcwd = external(UNDERSCORE_ON_WIN32 + 'wgetcwd',
  496. [rffi.CWCHARP, rffi.SIZE_T], rffi.CWCHARP,
  497. save_err=rffi.RFFI_SAVE_ERRNO)
  498. @replace_os_function('getcwd')
  499. def getcwd():
  500. bufsize = 256
  501. while True:
  502. buf = lltype.malloc(rffi.CCHARP.TO, bufsize, flavor='raw')
  503. res = c_getcwd(buf, bufsize)
  504. if res:
  505. break # ok
  506. error = get_saved_errno()
  507. lltype.free(buf, flavor='raw')
  508. if error != errno.ERANGE:
  509. raise OSError(error, "getcwd failed")
  510. # else try again with a larger buffer, up to some sane limit
  511. bufsize *= 4
  512. if bufsize > 1024*1024: # xxx hard-coded upper limit
  513. raise OSError(error, "getcwd result too large")
  514. result = rffi.charp2str(res)
  515. lltype.free(buf, flavor='raw')
  516. return result
  517. @replace_os_function('getcwdu')
  518. def getcwdu():
  519. bufsize = 256
  520. while True:
  521. buf = lltype.malloc(rffi.CWCHARP.TO, bufsize, flavor='raw')
  522. res = c_wgetcwd(buf, bufsize)
  523. if res:
  524. break # ok
  525. error = get_saved_errno()
  526. lltype.free(buf, flavor='raw')
  527. if error != errno.ERANGE:
  528. raise OSError(error, "getcwd failed")
  529. # else try again with a larger buffer, up to some sane limit
  530. bufsize *= 4
  531. if bufsize > 1024*1024: # xxx hard-coded upper limit
  532. raise OSError(error, "getcwd result too large")
  533. result = rffi.wcharp2unicode(res)
  534. lltype.free(buf, flavor='raw')
  535. return result
  536. if not _WIN32:
  537. class CConfig:
  538. _compilation_info_ = eci
  539. DIRENT = rffi_platform.Struct('struct dirent',
  540. [('d_name', lltype.FixedSizeArray(rffi.CHAR, 1))])
  541. DIRP = rffi.COpaquePtr('DIR')
  542. config = rffi_platform.configure(CConfig)
  543. DIRENT = config['DIRENT']
  544. DIRENTP = lltype.Ptr(DIRENT)
  545. c_opendir = external('opendir',
  546. [rffi.CCHARP], DIRP, save_err=rffi.RFFI_SAVE_ERRNO)
  547. c_fdopendir = external('fdopendir',
  548. [rffi.INT], DIRP, save_err=rffi.RFFI_SAVE_ERRNO)
  549. # XXX macro=True is hack to make sure we get the correct kind of
  550. # dirent struct (which depends on defines)
  551. c_readdir = external('readdir', [DIRP], DIRENTP,
  552. macro=True, save_err=rffi.RFFI_FULL_ERRNO_ZERO)
  553. c_closedir = external('closedir', [DIRP], rffi.INT)
  554. def _listdir(dirp):
  555. result = []
  556. while True:
  557. direntp = c_readdir(dirp)
  558. if not direntp:
  559. error = get_saved_errno()
  560. break
  561. namep = rffi.cast(rffi.CCHARP, direntp.c_d_name)
  562. name = rffi.charp2str(namep)
  563. if name != '.' and name != '..':
  564. result.append(name)
  565. c_closedir(dirp)
  566. if error:
  567. raise OSError(error, "readdir failed")
  568. return result
  569. def fdlistdir(dirfd):
  570. """
  571. Like listdir(), except that the directory is specified as an open
  572. file descriptor.
  573. Note: fdlistdir() closes the file descriptor.
  574. """
  575. dirp = c_fdopendir(dirfd)
  576. if not dirp:
  577. raise OSError(get_saved_errno(), "opendir failed")
  578. return _listdir(dirp)
  579. @replace_os_function('listdir')
  580. @specialize.argtype(0)
  581. def listdir(path):
  582. if not _WIN32:
  583. path = _as_bytes0(path)
  584. dirp = c_opendir(path)
  585. if not dirp:
  586. raise OSError(get_saved_errno(), "opendir failed")
  587. return _listdir(dirp)
  588. else: # _WIN32 case
  589. traits = _preferred_traits(path)
  590. win32traits = make_win32_traits(traits)
  591. path = traits.as_str0(path)
  592. if traits.str is unicode:
  593. if path and path[-1] not in (u'/', u'\\', u':'):
  594. path += u'/'
  595. mask = path + u'*.*'
  596. else:
  597. if path and path[-1] not in ('/', '\\', ':'):
  598. path += '/'
  599. mask = path + '*.*'
  600. filedata = lltype.malloc(win32traits.WIN32_FIND_DATA, flavor='raw')
  601. try:
  602. result = []
  603. hFindFile = win32traits.FindFirstFile(mask, filedata)
  604. if hFindFile == rwin32.INVALID_HANDLE_VALUE:
  605. error = rwin32.GetLastError_saved()
  606. if error == win32traits.ERROR_FILE_NOT_FOUND:
  607. return result
  608. else:
  609. raise WindowsError(error, "FindFirstFile failed")
  610. while True:
  611. name = traits.charp2str(rffi.cast(traits.CCHARP,
  612. filedata.c_cFileName))
  613. if traits.str is unicode:
  614. if not (name == u"." or name == u".."):
  615. result.append(name)
  616. else:
  617. if not (name == "." or name == ".."):
  618. result.append(name)
  619. if not win32traits.FindNextFile(hFindFile, filedata):
  620. break
  621. # FindNextFile sets error to ERROR_NO_MORE_FILES if
  622. # it got to the end of the directory
  623. error = rwin32.GetLastError_saved()
  624. win32traits.FindClose(hFindFile)
  625. if error == win32traits.ERROR_NO_MORE_FILES:
  626. return result
  627. else:
  628. raise WindowsError(error, "FindNextFile failed")
  629. finally:
  630. lltype.free(filedata, flavor='raw')
  631. #___________________________________________________________________
  632. c_execv = external('execv', [rffi.CCHARP, rffi.CCHARPP], rffi.INT,
  633. save_err=rffi.RFFI_SAVE_ERRNO)
  634. c_execve = external('execve',
  635. [rffi.CCHARP, rffi.CCHARPP, rffi.CCHARPP], rffi.INT,
  636. save_err=rffi.RFFI_SAVE_ERRNO)
  637. c_spawnv = external(UNDERSCORE_ON_WIN32 + 'spawnv',
  638. [rffi.INT, rffi.CCHARP, rffi.CCHARPP], rffi.INT,
  639. save_err=rffi.RFFI_SAVE_ERRNO)
  640. c_spawnve = external(UNDERSCORE_ON_WIN32 + 'spawnve',
  641. [rffi.INT, rffi.CCHARP, rffi.CCHARPP, rffi.CCHARPP],
  642. rffi.INT,
  643. save_err=rffi.RFFI_SAVE_ERRNO)
  644. @replace_os_function('execv')
  645. def execv(path, args):
  646. rstring.check_str0(path)
  647. # This list conversion already takes care of NUL bytes.
  648. l_args = rffi.ll_liststr2charpp(args)
  649. c_execv(path, l_args)
  650. rffi.free_charpp(l_args)
  651. raise OSError(get_saved_errno(), "execv failed")
  652. @replace_os_function('execve')
  653. def execve(path, args, env):
  654. envstrs = []
  655. for item in env.iteritems():
  656. envstr = "%s=%s" % item
  657. envstrs.append(envstr)
  658. rstring.check_str0(path)
  659. # This list conversion already takes care of NUL bytes.
  660. l_args = rffi.ll_liststr2charpp(args)
  661. l_env = rffi.ll_liststr2charpp(envstrs)
  662. c_execve(path, l_args, l_env)
  663. rffi.free_charpp(l_env)
  664. rffi.free_charpp(l_args)
  665. raise OSError(get_saved_errno(), "execve failed")
  666. @replace_os_function('spawnv')
  667. def spawnv(mode, path, args):
  668. rstring.check_str0(path)
  669. l_args = rffi.ll_liststr2charpp(args)
  670. childpid = c_spawnv(mode, path, l_args)
  671. rffi.free_charpp(l_args)
  672. return handle_posix_error('spawnv', childpid)
  673. @replace_os_function('spawnve')
  674. def spawnve(mode, path, args, env):
  675. envstrs = []
  676. for item in env.iteritems():
  677. envstrs.append("%s=%s" % item)
  678. rstring.check_str0(path)
  679. l_args = rffi.ll_liststr2charpp(args)
  680. l_env = rffi.ll_liststr2charpp(envstrs)
  681. childpid = c_spawnve(mode, path, l_args, l_env)
  682. rffi.free_charpp(l_env)
  683. rffi.free_charpp(l_args)
  684. return handle_posix_error('spawnve', childpid)
  685. c_fork = external('fork', [], rffi.PID_T, _nowrapper = True)
  686. c_openpty = external('openpty',
  687. [rffi.INTP, rffi.INTP, rffi.VOIDP, rffi.VOIDP, rffi.VOIDP],
  688. rffi.INT,
  689. save_err=rffi.RFFI_SAVE_ERRNO)
  690. c_forkpty = external('forkpty',
  691. [rffi.INTP, rffi.VOIDP, rffi.VOIDP, rffi.VOIDP],
  692. rffi.PID_T, _nowrapper = True)
  693. @replace_os_function('fork')
  694. @jit.dont_look_inside
  695. def fork():
  696. # NB. keep forkpty() up-to-date, too
  697. # lots of custom logic here, to do things in the right order
  698. ofs = debug.debug_offset()
  699. opaqueaddr = rthread.gc_thread_before_fork()
  700. childpid = c_fork()
  701. errno = _get_errno()
  702. rthread.gc_thread_after_fork(childpid, opaqueaddr)
  703. rthread.tlfield_rpy_errno.setraw(errno)
  704. childpid = handle_posix_error('fork', childpid)
  705. if childpid == 0:
  706. debug.debug_forked(ofs)
  707. return childpid
  708. @replace_os_function('openpty')
  709. @jit.dont_look_inside
  710. def openpty():
  711. master_p = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
  712. slave_p = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
  713. try:
  714. handle_posix_error(
  715. 'openpty', c_openpty(master_p, slave_p, None, None, None))
  716. return (widen(master_p[0]), widen(slave_p[0]))
  717. finally:
  718. lltype.free(master_p, flavor='raw')
  719. lltype.free(slave_p, flavor='raw')
  720. @replace_os_function('forkpty')
  721. @jit.dont_look_inside
  722. def forkpty():
  723. master_p = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
  724. master_p[0] = rffi.cast(rffi.INT, -1)
  725. null = lltype.nullptr(rffi.VOIDP.TO)
  726. try:
  727. ofs = debug.debug_offset()
  728. opaqueaddr = rthread.gc_thread_before_fork()
  729. childpid = c_forkpty(master_p, null, null, null)
  730. errno = _get_errno()
  731. rthread.gc_thread_after_fork(childpid, opaqueaddr)
  732. rthread.tlfield_rpy_errno.setraw(errno)
  733. childpid = handle_posix_error('forkpty', childpid)
  734. if childpid == 0:
  735. debug.debug_forked(ofs)
  736. return (childpid, master_p[0])
  737. finally:
  738. lltype.free(master_p, flavor='raw')
  739. if _WIN32:
  740. # emulate waitpid() with the _cwait() of Microsoft's compiler
  741. c__cwait = external('_cwait',
  742. [rffi.INTP, rffi.PID_T, rffi.INT], rffi.PID_T,
  743. save_err=rffi.RFFI_SAVE_ERRNO)
  744. @jit.dont_look_inside
  745. def c_waitpid(pid, status_p, options):
  746. result = c__cwait(status_p, pid, options)
  747. # shift the status left a byte so this is more
  748. # like the POSIX waitpid
  749. status_p[0] = rffi.cast(rffi.INT, widen(status_p[0]) << 8)
  750. return result
  751. elif _CYGWIN:
  752. c_waitpid = external('cygwin_waitpid',
  753. [rffi.PID_T, rffi.INTP, rffi.INT], rffi.PID_T,
  754. save_err=rffi.RFFI_SAVE_ERRNO)
  755. else:
  756. c_waitpid = external('waitpid',
  757. [rffi.PID_T, rffi.INTP, rffi.INT], rffi.PID_T,
  758. save_err=rffi.RFFI_SAVE_ERRNO)
  759. @replace_os_function('waitpid')
  760. def waitpid(pid, options):
  761. status_p = lltype.malloc(rffi.INTP.TO, 1, flavor='raw')
  762. status_p[0] = rffi.cast(rffi.INT, 0)
  763. try:
  764. result = handle_posix_error('waitpid',
  765. c_waitpid(pid, status_p, options))
  766. status = widen(status_p[0])
  767. return (result, status)
  768. finally:
  769. lltype.free(status_p, flavor='raw')
  770. def _make_waitmacro(name):
  771. # note that rffi.INT as first parameter type is intentional.
  772. # on s390x providing a lltype.Signed as param type, the
  773. # macro wrapper function will always return 0
  774. # reason: legacy code required a union wait. see
  775. # https://sourceware.org/bugzilla/show_bug.cgi?id=19613
  776. # for more details. If this get's fixed we can use lltype.Signed
  777. # again. (The exact same issue occurs on ppc64 big-endian.)
  778. c_func = external(name, [rffi.INT], lltype.Signed,
  779. macro=_MACRO_ON_POSIX)
  780. returning_int = name in ('WEXITSTATUS', 'WSTOPSIG', 'WTERMSIG')
  781. @replace_os_function(name)
  782. @func_renamer(name)
  783. def _waitmacro(status):
  784. if returning_int:
  785. return c_func(status)
  786. else:
  787. return bool(c_func(status))
  788. WAIT_MACROS = ['WCOREDUMP', 'WIFCONTINUED', 'WIFSTOPPED',
  789. 'WIFSIGNALED', 'WIFEXITED',
  790. 'WEXITSTATUS', 'WSTOPSIG', 'WTERMSIG']
  791. for name in WAIT_MACROS:
  792. _make_waitmacro(name)
  793. #___________________________________________________________________
  794. c_getlogin = external('getlogin', [], rffi.CCHARP,
  795. releasegil=False, save_err=rffi.RFFI_SAVE_ERRNO)
  796. c_getloadavg = external('getloadavg',
  797. [rffi.CArrayPtr(lltype.Float), rffi.INT], rffi.INT)
  798. @replace_os_function('getlogin')
  799. def getlogin():
  800. result = c_getlogin()
  801. if not result:
  802. raise OSError(get_saved_errno(), "getlogin failed")
  803. return rffi.charp2str(result)
  804. @replace_os_function('getloadavg')
  805. def getloadavg():
  806. load = lltype.malloc(rffi.CArrayPtr(lltype.Float).TO, 3, flavor='raw')
  807. try:
  808. r = c_getloadavg(load, 3)
  809. if r != 3:
  810. raise OSError
  811. return (load[0], load[1], load[2])
  812. finally:
  813. lltype.free(load, flavor='raw')
  814. #___________________________________________________________________
  815. c_readlink = external('readlink',
  816. [rffi.CCHARP, rffi.CCHARP, rffi.SIZE_T], rffi.SSIZE_T,
  817. save_err=rffi.RFFI_SAVE_ERRNO)
  818. @replace_os_function('readlink')
  819. def readlink(path):
  820. path = _as_bytes0(path)
  821. bufsize = 1023
  822. while True:
  823. buf = lltype.malloc(rffi.CCHARP.TO, bufsize, flavor='raw')
  824. res = widen(c_readlink(path, buf, bufsize))
  825. if res < 0:
  826. lltype.free(buf, flavor='raw')
  827. error = get_saved_errno() # failed
  828. raise OSError(error, "readlink failed")
  829. elif res < bufsize:
  830. break # ok
  831. else:
  832. # buf too small, try again with a larger buffer
  833. lltype.free(buf, flavor='raw')
  834. bufsize *= 4
  835. # convert the result to a string
  836. result = rffi.charp2strn(buf, res)
  837. lltype.free(buf, flavor='raw')
  838. return result
  839. c_isatty = external(UNDERSCORE_ON_WIN32 + 'isatty', [rffi.INT], rffi.INT)
  840. @replace_os_function('isatty')
  841. def isatty(fd):
  842. if not is_valid_fd(fd):
  843. return False
  844. return c_isatty(fd) != 0
  845. c_ttyname = external('ttyname', [lltype.Signed], rffi.CCHARP,
  846. releasegil=False,
  847. save_err=rffi.RFFI_SAVE_ERRNO)
  848. @replace_os_function('ttyname')
  849. def ttyname(fd):
  850. l_name = c_ttyname(fd)
  851. if not l_name:
  852. raise OSError(get_saved_errno(), "ttyname raised")
  853. return rffi.charp2str(l_name)
  854. c_strerror = external('strerror', [rffi.INT], rffi.CCHARP,
  855. releasegil=False)
  856. @replace_os_function('strerror')
  857. def strerror(errnum):
  858. res = c_strerror(errnum)
  859. if not res:
  860. raise ValueError("os_strerror failed")
  861. return rffi.charp2str(res)
  862. c_system = external('system', [rffi.CCHARP], rffi.INT)
  863. @replace_os_function('system')
  864. def system(command):
  865. return widen(c_system(command))
  866. c_unlink = external('unlink', [rffi.CCHARP], rffi.INT,
  867. save_err=rffi.RFFI_SAVE_ERRNO)
  868. c_mkdir = external('mkdir', [rffi.CCHARP, rffi.MODE_T], rffi.INT,
  869. save_err=rffi.RFFI_SAVE_ERRNO)
  870. c_rmdir = external(UNDERSCORE_ON_WIN32 + 'rmdir', [rffi.CCHARP], rffi.INT,
  871. save_err=rffi.RFFI_SAVE_ERRNO)
  872. c_wrmdir = external(UNDERSCORE_ON_WIN32 + 'wrmdir', [rffi.CWCHARP], rffi.INT,
  873. save_err=rffi.RFFI_SAVE_ERRNO)
  874. @replace_os_function('unlink')
  875. @specialize.argtype(0)
  876. def unlink(path):
  877. if not _WIN32:
  878. handle_posix_error('unlink', c_unlink(_as_bytes0(path)))
  879. else:
  880. traits = _preferred_traits(path)
  881. win32traits = make_win32_traits(traits)
  882. if not win32traits.DeleteFile(traits.as_str0(path)):
  883. raise rwin32.lastSavedWindowsError()
  884. @replace_os_function('mkdir')
  885. @specialize.argtype(0)
  886. def mkdir(path, mode=0o777):
  887. if not _WIN32:
  888. handle_posix_error('mkdir', c_mkdir(_as_bytes0(path), mode))
  889. else:
  890. traits = _preferred_traits(path)
  891. win32traits = make_win32_traits(traits)
  892. if not win32traits.CreateDirectory(traits.as_str0(path), None):
  893. raise rwin32.lastSavedWindowsError()
  894. @replace_os_function('rmdir')
  895. @specialize.argtype(0)
  896. @jit.dont_look_inside
  897. def rmdir(path):
  898. if _prefer_unicode(path):
  899. handle_posix_error('wrmdir', c_wrmdir(_as_unicode0(path)))
  900. else:
  901. handle_posix_error('rmdir', c_rmdir(_as_bytes0(path)))
  902. c_chmod = external('chmod', [rffi.CCHARP, rffi.MODE_T], rffi.INT,
  903. save_err=rffi.RFFI_SAVE_ERRNO)
  904. c_fchmod = external('fchmod', [rffi.INT, rffi.MODE_T], rffi.INT,
  905. save_err=rffi.RFFI_SAVE_ERRNO,)
  906. c_rename = external('rename', [rffi.CCHARP, rffi.CCHARP], rffi.INT,
  907. save_err=rffi.RFFI_SAVE_ERRNO)
  908. @replace_os_function('chmod')
  909. @specialize.argtype(0)
  910. def chmod(path, mode):
  911. if not _WIN32:
  912. handle_posix_error('chmod', c_chmod(_as_bytes0(path), mode))
  913. else:
  914. traits = _preferred_traits(path)
  915. win32traits = make_win32_traits(traits)
  916. path = traits.as_str0(path)
  917. attr = win32traits.GetFileAttributes(path)
  918. if attr == win32traits.INVALID_FILE_ATTRIBUTES:
  919. raise rwin32.lastSavedWindowsError()
  920. if mode & 0200: # _S_IWRITE
  921. attr &= ~win32traits.FILE_ATTRIBUTE_READONLY
  922. else:
  923. attr |= win32traits.FILE_ATTRIBUTE_READONLY
  924. if not win32traits.SetFileAttributes(path, attr):
  925. raise rwin32.lastSavedWindowsError()
  926. @replace_os_function('fchmod')
  927. def fchmod(fd, mode):
  928. handle_posix_error('fchmod', c_fchmod(fd, mode))
  929. @replace_os_function('rename')
  930. @specialize.argtype(0, 1)
  931. def rename(path1, path2):
  932. if not _WIN32:
  933. handle_posix_error('rename',
  934. c_rename(_as_bytes0(path1), _as_bytes0(path2)))
  935. else:
  936. traits = _preferred_traits(path1)
  937. win32traits = make_win32_traits(traits)
  938. path1 = traits.as_str0(path1)
  939. path2 = traits.as_str0(path2)
  940. if not win32traits.MoveFileEx(path1, path2, 0):
  941. raise rwin32.lastSavedWindowsError()
  942. @specialize.argtype(0, 1)
  943. def replace(path1, path2):
  944. if _WIN32:
  945. traits = _preferred_traits(path1)
  946. win32traits = make_win32_traits(traits)
  947. path1 = traits.as_str0(path1)
  948. path2 = traits.as_str0(path2)
  949. ret = win32traits.MoveFileEx(path1, path2,
  950. win32traits.MOVEFILE_REPLACE_EXISTING)
  951. if not ret:
  952. raise rwin32.lastSavedWindowsError()
  953. else:
  954. ret = rename(path1, path2)
  955. return ret
  956. #___________________________________________________________________
  957. c_mkfifo = external('mkfifo', [rffi.CCHARP, rffi.MODE_T], rffi.INT,
  958. save_err=rffi.RFFI_SAVE_ERRNO)
  959. c_mknod = external('mknod', [rffi.CCHARP, rffi.MODE_T, rffi.INT], rffi.INT,
  960. # # xxx: actually ^^^ dev_t
  961. macro=_MACRO_ON_POSIX, save_err=rffi.RFFI_SAVE_ERRNO)
  962. @replace_os_function('mkfifo')
  963. @specialize.argtype(0)
  964. def mkfifo(path, mode):
  965. handle_posix_error('mkfifo', c_mkfifo(_as_bytes0(path), mode))
  966. @replace_os_function('mknod')
  967. @specialize.argtype(0)
  968. def mknod(path, mode, dev):
  969. handle_posix_error('mknod', c_mknod(_as_bytes0(path), mode, dev))
  970. if _WIN32:
  971. CreatePipe = external('CreatePipe', [rwin32.LPHANDLE,
  972. rwin32.LPHANDLE,
  973. rffi.VOIDP,
  974. rwin32.DWORD],
  975. rwin32.BOOL)
  976. c_open_osfhandle = external('_open_osfhandle', [rffi.INTPTR_T,
  977. rffi.INT],
  978. rffi.INT)
  979. else:
  980. INT_ARRAY_P = rffi.CArrayPtr(rffi.INT)
  981. c_pipe = external('pipe', [INT_ARRAY_P], rffi.INT,
  982. save_err=rffi.RFFI_SAVE_ERRNO)
  983. @replace_os_function('pipe')
  984. def pipe():
  985. if _WIN32:
  986. pread = lltype.malloc(rwin32.LPHANDLE.TO, 1, flavor='raw')
  987. pwrite = lltype.malloc(rwin32.LPHANDLE.TO, 1, flavor='raw')
  988. try:
  989. if not CreatePipe(
  990. pread, pwrite, lltype.nullptr(rffi.VOIDP.TO), 0):
  991. raise WindowsError(rwin32.GetLastError_saved(),
  992. "CreatePipe failed")
  993. hread = rffi.cast(rffi.INTPTR_T, pread[0])
  994. hwrite = rffi.cast(rffi.INTPTR_T, pwrite[0])
  995. finally:
  996. lltype.free(pwrite, flavor='raw')
  997. lltype.free(pread, flavor='raw')
  998. fdread = c_open_osfhandle(hread, 0)
  999. fdwrite = c_open_osfhandle(hwrite, 1)
  1000. return (fdread, fdwrite)
  1001. else:
  1002. filedes = lltype.malloc(INT_ARRAY_P.TO, 2, flavor='raw')
  1003. try:
  1004. handle_posix_error('pipe', c_pipe(filedes))
  1005. return (widen(filedes[0]), widen(filedes[1]))
  1006. finally:
  1007. lltype.free(filedes, flavor='raw')
  1008. c_link = external('link', [rffi.CCHARP, rffi.CCHARP], rffi.INT,
  1009. save_err=rffi.RFFI_SAVE_ERRNO,)
  1010. c_symlink = external('symlink', [rffi.CCHARP, rffi.CCHARP], rffi.INT,
  1011. save_err=rffi.RFFI_SAVE_ERRNO)
  1012. #___________________________________________________________________
  1013. @replace_os_function('link')
  1014. @specialize.argtype(0, 1)
  1015. def link(oldpath, newpath):
  1016. oldpath = _as_bytes0(oldpath)
  1017. newpath = _as_bytes0(newpath)
  1018. handle_posix_error('link', c_link(oldpath, newpath))
  1019. @replace_os_function('symlink')
  1020. @specialize.argtype(0, 1)
  1021. def symlink(oldpath, newpath):
  1022. oldpath = _as_bytes0(oldpath)
  1023. newpath = _as_bytes0(newpath)
  1024. handle_posix_error('symlink', c_symlink(oldpath, newpath))
  1025. c_umask = external(UNDERSCORE_ON_WIN32 + 'umask', [rffi.MODE_T], rffi.MODE_T)
  1026. @replace_os_function('umask')
  1027. def umask(newmask):
  1028. return widen(c_umask(newmask))
  1029. c_chown = external('chown', [rffi.CCHARP, rffi.INT, rffi.INT], rffi.INT,
  1030. save_err=rffi.RFFI_SAVE_ERRNO)
  1031. c_lchown = external('lchown', [rffi.CCHARP, rffi.INT, rffi.INT], rffi.INT,
  1032. save_err=rffi.RFFI_SAVE_ERRNO)
  1033. c_fchown = external('fchown', [rffi.INT, rffi.INT, rffi.INT], rffi.INT,
  1034. save_err=rffi.RFFI_SAVE_ERRNO)
  1035. @replace_os_function('chown')
  1036. def chown(path, uid, gid):
  1037. handle_posix_error('chown', c_chown(path, uid, gid))
  1038. @replace_os_function('lchown')
  1039. def lchown(path, uid, gid):
  1040. handle_posix_error('lchown', c_lchown(path, uid, gid))
  1041. @replace_os_function('fchown')
  1042. def fchown(fd, uid, gid):
  1043. handle_posix_error('fchown', c_fchown(fd, uid, gid))
  1044. #___________________________________________________________________
  1045. UTIMBUFP = lltype.Ptr(UTIMBUF)
  1046. c_utime = external('utime', [rffi.CCHARP, UTIMBUFP], rffi.INT,
  1047. save_err=rffi.RFFI_SAVE_ERRNO)
  1048. if HAVE_UTIMES:
  1049. class CConfig:
  1050. _compilation_info_ = eci
  1051. TIMEVAL = rffi_platform.Struct('struct timeval', [
  1052. ('tv_sec', rffi.LONG),
  1053. ('tv_usec', rffi.LONG)])
  1054. config = rffi_platform.configure(CConfig)
  1055. TIMEVAL = config['TIMEVAL']
  1056. TIMEVAL2P = rffi.CArrayPtr(TIMEVAL)
  1057. c_utimes = external('utimes', [rffi.CCHARP, TIMEVAL2P], rffi.INT,
  1058. save_err=rffi.RFFI_SAVE_ERRNO)
  1059. if _WIN32:
  1060. from rpython.rlib import rwin32
  1061. GetSystemTime = external(
  1062. 'GetSystemTime',
  1063. [lltype.Ptr(rwin32.SYSTEMTIME)],
  1064. lltype.Void,
  1065. calling_conv='win',
  1066. save_err=rffi.RFFI_SAVE_LASTERROR)
  1067. SystemTimeToFileTime = external(
  1068. 'SystemTimeToFileTime',
  1069. [lltype.Ptr(rwin32.SYSTEMTIME),
  1070. lltype.Ptr(rwin32.FILETIME)],
  1071. rwin32.BOOL,
  1072. calling_conv='win',
  1073. save_err=rffi.RFFI_SAVE_LASTERROR)
  1074. SetFileTime = external(
  1075. 'SetFileTime',
  1076. [rwin32.HANDLE,
  1077. lltype.Ptr(rwin32.FILETIME),
  1078. lltype.Ptr(rwin32.FILETIME),
  1079. lltype.Ptr(rwin32.FILETIME)],
  1080. rwin32.BOOL,
  1081. calling_conv='win')
  1082. @replace_os_function('utime')
  1083. @specialize.argtype(0, 1)
  1084. def utime(path, times):
  1085. if not _WIN32:
  1086. path = _as_bytes0(path)
  1087. if times is None:
  1088. error = c_utime(path, lltype.nullptr(UTIMBUFP.TO))
  1089. else:
  1090. if HAVE_UTIMES:
  1091. with lltype.scoped_alloc(TIMEVAL2P.TO, 2) as l_timeval2p:
  1092. times_to_timeval2p(times, l_timeval2p)
  1093. error = c_utimes(path, l_timeval2p)
  1094. else:
  1095. # we only have utime(), which does not allow
  1096. # sub-second resolution
  1097. actime, modtime = times
  1098. l_utimbuf = lltype.malloc(UTIMBUFP.TO, flavor='raw')
  1099. l_utimbuf.c_actime = rffi.r_time_t(actime)
  1100. l_utimbuf.c_modtime = rffi.r_time_t(modtime)
  1101. error = c_utime(path, l_utimbuf)
  1102. lltype.free(l_utimbuf, flavor='raw')
  1103. handle_posix_error('utime', error)
  1104. else: # _WIN32 case
  1105. from rpython.rlib.rwin32file import time_t_to_FILE_TIME
  1106. traits = _preferred_traits(path)
  1107. win32traits = make_win32_traits(traits)
  1108. path = traits.as_str0(path)
  1109. hFile = win32traits.CreateFile(path,
  1110. win32traits.FILE_WRITE_ATTRIBUTES, 0,
  1111. None, win32traits.OPEN_EXISTING,
  1112. win32traits.FILE_FLAG_BACKUP_SEMANTICS,
  1113. rwin32.NULL_HANDLE)
  1114. if hFile == rwin32.INVALID_HANDLE_VALUE:
  1115. raise rwin32.lastSavedWindowsError()
  1116. ctime = lltype.nullptr(rwin32.FILETIME)
  1117. atime = lltype.malloc(rwin32.FILETIME, flavor='raw')
  1118. mtime = lltype.malloc(rwin32.FILETIME, flavor='raw')
  1119. try:
  1120. if times is None:
  1121. now = lltype.malloc(rwin32.SYSTEMTIME, flavor='raw')
  1122. try:
  1123. GetSystemTime(now)
  1124. if (not SystemTimeToFileTime(now, atime) or
  1125. not SystemTimeToFileTime(now, mtime)):
  1126. raise rwin32.lastSavedWindowsError()
  1127. finally:
  1128. lltype.free(now, flavor='raw')
  1129. else:
  1130. actime, modtime = times
  1131. time_t_to_FILE_TIME(actime, atime)
  1132. time_t_to_FILE_TIME(modtime, mtime)
  1133. if not SetFileTime(hFile, ctime, atime, mtime):
  1134. raise rwin32.lastSavedWindowsError()
  1135. finally:
  1136. rwin32.CloseHandle(hFile)
  1137. lltype.free(atime, flavor='raw')
  1138. lltype.free(mtime, flavor='raw')
  1139. def times_to_timeval2p(times, l_timeval2p):
  1140. actime, modtime = times
  1141. _time_to_timeval(actime, l_timeval2p[0])
  1142. _time_to_timeval(modtime, l_timeval2p[1])
  1143. def _time_to_timeval(t, l_timeval):
  1144. import math
  1145. fracpart, intpart = math.modf(t)
  1146. rffi.setintfield(l_timeval, 'c_tv_sec', int(intpart))
  1147. rffi.setintfield(l_timeval, 'c_tv_usec', int(fracpart * 1e6))
  1148. if not _WIN32:
  1149. TMSP = lltype.Ptr(TMS)
  1150. c_times = external('times', [TMSP], CLOCK_T,
  1151. save_err=rffi.RFFI_SAVE_ERRNO |
  1152. rffi.RFFI_ZERO_ERRNO_BEFORE)
  1153. # Here is a random extra platform parameter which is important.
  1154. # Strictly speaking, this should probably be retrieved at runtime, not
  1155. # at translation time.
  1156. CLOCK_TICKS_PER_SECOND = float(os.sysconf('SC_CLK_TCK'))
  1157. else:
  1158. GetCurrentProcess = external(
  1159. 'GetCurrentProcess', [],
  1160. rwin32.HANDLE, calling_conv='win')
  1161. GetProcessTimes = external(
  1162. 'GetProcessTimes', [
  1163. rwin32.HANDLE,
  1164. lltype.Ptr(rwin32.FILETIME), lltype.Ptr(rwin32.FILETIME),
  1165. lltype.Ptr(rwin32.FILETIME), lltype.Ptr(rwin32.FILETIME)],
  1166. rwin32.BOOL, calling_conv='win')
  1167. @replace_os_function('times')
  1168. def times():
  1169. if not _WIN32:
  1170. l_tmsbuf = lltype.malloc(TMSP.TO, flavor='raw')
  1171. try:
  1172. # note: times() can return a negative value (or even -1)
  1173. # even if there is no error
  1174. result = rffi.cast(lltype.Signed, c_times(l_tmsbuf))
  1175. if result == -1:
  1176. errno = get_saved_errno()
  1177. if errno != 0:
  1178. raise OSError(errno, 'times() failed')
  1179. return (
  1180. rffi.cast(lltype.Signed, l_tmsbuf.c_tms_utime)
  1181. / CLOCK_TICKS_PER_SECOND,
  1182. rffi.cast(lltype.Signed, l_tmsbuf.c_tms_stime)
  1183. / CLOCK_TICKS_PER_SECOND,
  1184. rffi.cast(lltype.Signed, l_tmsbuf.c_tms_cutime)
  1185. / CLOCK_TICKS_PER_SECOND,
  1186. rffi.cast(lltype.Signed, l_tmsbuf.c_tms_cstime)
  1187. / CLOCK_TICKS_PER_SECOND,
  1188. result / CLOCK_TICKS_PER_SECOND)
  1189. finally:
  1190. lltype.free(l_tmsbuf, flavor='raw')
  1191. else:
  1192. pcreate = lltype.malloc(rwin32.FILETIME, flavor='raw')
  1193. pexit = lltype.malloc(rwin32.FILETIME, flavor='raw')
  1194. pkernel = lltype.malloc(rwin32.FILETIME, flavor='raw')
  1195. puser = lltype.malloc(rwin32.FILETIME, flavor='raw')
  1196. try:
  1197. hProc = GetCurrentProcess()
  1198. GetProcessTimes(hProc, pcreate, pexit, pkernel, puser)
  1199. # The fields of a FILETIME structure are the hi and lo parts
  1200. # of a 64-bit value expressed in 100 nanosecond units
  1201. # (of course).
  1202. return (
  1203. rffi.cast(lltype.Signed, pkernel.c_dwHighDateTime) * 429.4967296 +
  1204. rffi.cast(lltype.Signed, pkernel.c_dwLowDateTime) * 1E-7,
  1205. rffi.cast(lltype.Signed, puser.c_dwHighDateTime) * 429.4967296 +
  1206. rffi.cast(lltype.Signed, puser.c_dwLowDateTime) * 1E-7,
  1207. 0., 0., 0.)
  1208. finally:
  1209. lltype.free(puser, flavor='raw')
  1210. lltype.free(pkernel, flavor='raw')
  1211. lltype.free(pexit, flavor='raw')
  1212. lltype.free(pcreate, flavor='raw')
  1213. c_kill = external('kill', [rffi.PID_T, rffi.INT], rffi.INT,
  1214. save_err=rffi.RFFI_SAVE_ERRNO)
  1215. c_killpg = external('killpg', [rffi.INT, rffi.INT], rffi.INT,
  1216. save_err=rffi.RFFI_SAVE_ERRNO)
  1217. c_exit = external('_exit', [rffi.INT], lltype.Void)
  1218. c_nice = external('nice', [rffi.INT], rffi.INT,
  1219. save_err=rffi.RFFI_FULL_ERRNO_ZERO)
  1220. @replace_os_function('kill')
  1221. def kill(pid, sig):
  1222. if not _WIN32:
  1223. return handle_posix_error('kill', c_kill(pid, sig))
  1224. else:
  1225. if sig == rwin32.CTRL_C_EVENT or sig == rwin32.CTRL_BREAK_EVENT:
  1226. if rwin32.GenerateConsoleCtrlEvent(sig, pid) == 0:
  1227. raise rwin32.lastSavedWindowsError(
  1228. 'kill() failed generating event')
  1229. return
  1230. handle = rwin32.OpenProcess(rwin32.PROCESS_ALL_ACCESS, False, pid)
  1231. if not handle:
  1232. raise rwin32.lastSavedWindowsError('kill() failed opening process')
  1233. try:
  1234. if rwin32.TerminateProcess(handle, sig) == 0:
  1235. raise rwin32.lastSavedWindowsError(
  1236. 'kill() failed to terminate process')
  1237. finally:
  1238. rwin32.CloseHandle(handle)
  1239. @replace_os_function('killpg')
  1240. def killpg(pgrp, sig):
  1241. return handle_posix_error('killpg', c_killpg(pgrp, sig))
  1242. @replace_os_function('_exit')
  1243. @jit.dont_look_inside
  1244. def exit(status):
  1245. debug.debug_flush()
  1246. c_exit(status)
  1247. @replace_os_function('nice')
  1248. def nice(inc):
  1249. # Assume that the system provides a standard-compliant version
  1250. # of nice() that returns the new priority. Nowadays, FreeBSD
  1251. # might be the last major non-compliant system (xxx check me).
  1252. res = widen(c_nice(inc))
  1253. if res == -1:
  1254. err = get_saved_errno()
  1255. if err != 0:
  1256. raise OSError(err, "os_nice failed")
  1257. return res
  1258. c_ctermid = external('ctermid', [rffi.CCHARP], rffi.CCHARP)
  1259. @replace_os_function('ctermid')
  1260. def ctermid():
  1261. return rffi.charp2str(c_ctermid(lltype.nullptr(rffi.CCHARP.TO)))
  1262. c_tmpnam = external('tmpnam', [rffi.CCHARP], rffi.CCHARP)
  1263. @replace_os_function('tmpnam')
  1264. def tmpnam():
  1265. return rffi.charp2str(c_tmpnam(lltype.nullptr(rffi.CCHARP.TO)))
  1266. #___________________________________________________________________
  1267. c_getpid = external('getpid', [], rffi.PID_T,
  1268. releasegil=False, save_err=rffi.RFFI_SAVE_ERRNO)
  1269. c_getppid = external('getppid', [], rffi.PID_T,
  1270. releasegil=False, save_err=rffi.RFFI_SAVE_ERRNO)
  1271. c_setsid = external('setsid', [], rffi.PID_T,
  1272. save_err=rffi.RFFI_SAVE_ERRNO)
  1273. c_getsid = external('getsid', [rffi.PID_T], rffi.PID_T,
  1274. save_err=rffi.RFFI_SAVE_ERRNO)
  1275. @replace_os_function('getpid')
  1276. def getpid():
  1277. return handle_posix_error('getpid', c_getpid())
  1278. @replace_os_function('getppid')
  1279. def getppid():
  1280. return handle_posix_error('getppid', c_getppid())
  1281. @replace_os_function('setsid')
  1282. def setsid():
  1283. return handle_posix_error('setsid', c_setsid())
  1284. @replace_os_function('getsid')
  1285. def getsid(pid):
  1286. return handle_posix_error('getsid', c_getsid(pid))
  1287. c_getpgid = external('getpgid', [rffi.PID_T], rffi.PID_T,
  1288. save_err=rffi.RFFI_SAVE_ERRNO)
  1289. c_setpgid = external('setpgid', [rffi.PID_T, rffi.PID_T], rffi.INT,
  1290. save_err=rffi.RFFI_SAVE_ERRNO)
  1291. @replace_os_function('getpgid')
  1292. def getpgid(pid):
  1293. return handle_posix_error('getpgid', c_getpgid(pid))
  1294. @replace_os_function('setpgid')
  1295. def setpgid(pid, gid):
  1296. handle_posix_error('setpgid', c_setpgid(pid, gid))
  1297. if not _WIN32:
  1298. GID_GROUPS_T = rffi.CArrayPtr(GID_T)
  1299. c_getgroups = external('getgroups', [rffi.INT, GID_GROUPS_T], rffi.INT,
  1300. save_err=rffi.RFFI_SAVE_ERRNO)
  1301. c_setgroups = external('setgroups', [rffi.SIZE_T, GID_GROUPS_T], rffi.INT,
  1302. save_err=rffi.RFFI_SAVE_ERRNO)
  1303. c_initgroups = external('initgroups', [rffi.CCHARP, GID_T], rffi.INT,
  1304. save_err=rffi.RFFI_SAVE_ERRNO)
  1305. @replace_os_function('getgroups')
  1306. def getgroups():
  1307. n = handle_posix_error('getgroups',
  1308. c_getgroups(0, lltype.nullptr(GID_GROUPS_T.TO)))
  1309. groups = lltype.malloc(GID_GROUPS_T.TO, n, flavor='raw')
  1310. try:
  1311. n = handle_posix_error('getgroups', c_getgroups(n, groups))
  1312. return [widen_gid(groups[i]) for i in range(n)]
  1313. finally:
  1314. lltype.free(groups, flavor='raw')
  1315. @replace_os_function('setgroups')
  1316. def setgroups(gids):
  1317. n = len(gids)
  1318. groups = lltype.malloc(GID_GROUPS_T.TO, n, flavor='raw')
  1319. try:
  1320. for i in range(n):
  1321. groups[i] = rffi.cast(GID_T, gids[i])
  1322. handle_posix_error('setgroups', c_setgroups(n, groups))
  1323. finally:
  1324. lltype.free(groups, flavor='raw')
  1325. @replace_os_function('initgroups')
  1326. def initgroups(user, group):
  1327. handle_posix_error('initgroups', c_initgroups(user, group))
  1328. if GETPGRP_HAVE_ARG:
  1329. c_getpgrp = external('getpgrp', [rffi.INT], rffi.INT,
  1330. save_err=rffi.RFFI_SAVE_ERRNO)
  1331. else:
  1332. c_getpgrp = external('getpgrp', [], rffi.INT,
  1333. save_err=rffi.RFFI_SAVE_ERRNO)
  1334. if SETPGRP_HAVE_ARG:
  1335. c_setpgrp = external('setpgrp', [rffi.INT, rffi.INT], rffi.INT,
  1336. save_err=rffi.RFFI_SAVE_ERRNO)
  1337. else:
  1338. c_setpgrp = external('setpgrp', [], rffi.INT,
  1339. save_err=rffi.RFFI_SAVE_ERRNO)
  1340. @replace_os_function('getpgrp')
  1341. def getpgrp():
  1342. if GETPGRP_HAVE_ARG:
  1343. return handle_posix_error('getpgrp', c_getpgrp(0))
  1344. else:
  1345. return handle_posix_error('getpgrp', c_getpgrp())
  1346. @replace_os_function('setpgrp')
  1347. def setpgrp():
  1348. if SETPGRP_HAVE_ARG:
  1349. handle_posix_error('setpgrp', c_setpgrp(0, 0))
  1350. else:
  1351. handle_posix_error('setpgrp', c_setpgrp())
  1352. c_tcgetpgrp = external('tcgetpgrp', [rffi.INT], rffi.PID_T,
  1353. save_err=rffi.RFFI_SAVE_ERRNO)
  1354. c_tcsetpgrp = external('tcsetpgrp', [rffi.INT, rffi.PID_T], rffi.INT,
  1355. save_err=rffi.RFFI_SAVE_ERRNO)
  1356. @replace_os_function('tcgetpgrp')
  1357. def tcgetpgrp(fd):
  1358. return handle_posix_error('tcgetpgrp', c_tcgetpgrp(fd))
  1359. @replace_os_function('tcsetpgrp')
  1360. def tcsetpgrp(fd, pgrp):
  1361. return handle_posix_error('tcsetpgrp', c_tcsetpgrp(fd, pgrp))
  1362. #___________________________________________________________________
  1363. if not _WIN32:
  1364. c_getuid = external('getuid', [], UID_T)
  1365. c_geteuid = external('geteuid', [], UID_T)
  1366. c_setuid = external('setuid', [UID_T], rffi.INT,
  1367. save_err=rffi.RFFI_SAVE_ERRNO)
  1368. c_seteuid = external('seteuid', [UID_T], rffi.INT,
  1369. save_err=rffi.RFFI_SAVE_ERRNO)
  1370. c_getgid = external('getgid', [], GID_T)
  1371. c_getegid = external('getegid', [], GID_T)
  1372. c_setgid = external('setgid', [GID_T], rffi.INT,
  1373. save_err=rffi.RFFI_SAVE_ERRNO)
  1374. c_setegid = external('setegid', [GID_T], rffi.INT,
  1375. save_err=rffi.RFFI_SAVE_ERRNO)
  1376. def widen_uid(x):
  1377. return rffi.cast(lltype.Unsigned, x)
  1378. widen_gid = widen_uid
  1379. # NOTE: the resulting type of functions that return a uid/gid is
  1380. # always Unsigned. The argument type of functions that take a
  1381. # uid/gid should also be Unsigned.
  1382. @replace_os_function('getuid')
  1383. def getuid():
  1384. return widen_uid(c_getuid())
  1385. @replace_os_function('geteuid')
  1386. def geteuid():
  1387. return widen_uid(c_geteuid())
  1388. @replace_os_function('setuid')
  1389. def setuid(uid):
  1390. handle_posix_error('setuid', c_setuid(uid))
  1391. @replace_os_function('seteuid')
  1392. def seteuid(uid):
  1393. handle_posix_error('seteuid', c_seteuid(uid))
  1394. @replace_os_function('getgid')
  1395. def getgid():
  1396. return widen_gid(c_getgid())
  1397. @replace_os_function('getegid')
  1398. def getegid():
  1399. return widen_gid(c_getegid())
  1400. @replace_os_function('setgid')
  1401. def setgid(gid):
  1402. handle_posix_error('setgid', c_setgid(gid))
  1403. @replace_os_function('setegid')
  1404. def setegid(gid):
  1405. handle_posix_error('setegid', c_setegid(gid))
  1406. c_setreuid = external('setreuid', [UID_T, UID_T], rffi.INT,
  1407. save_err=rffi.RFFI_SAVE_ERRNO)
  1408. c_setregid = external('setregid', [GID_T, GID_T], rffi.INT,
  1409. save_err=rffi.RFFI_SAVE_ERRNO)
  1410. @replace_os_function('setreuid')
  1411. def setreuid(ruid, euid):
  1412. handle_posix_error('setreuid', c_setreuid(ruid, euid))
  1413. @replace_os_function('setregid')
  1414. def setregid(rgid, egid):
  1415. handle_posix_error('setregid', c_setregid(rgid, egid))
  1416. UID_T_P = lltype.Ptr(lltype.Array(UID_T, hints={'nolength': True}))
  1417. GID_T_P = lltype.Ptr(lltype.Array(GID_T, hints={'nolength': True}))
  1418. c_getresuid = external('getresuid', [UID_T_P] * 3, rffi.INT,
  1419. save_err=rffi.RFFI_SAVE_ERRNO)
  1420. c_getresgid = external('getresgid', [GID_T_P] * 3, rffi.INT,
  1421. save_err=rffi.RFFI_SAVE_ERRNO)
  1422. c_setresuid = external('setresuid', [UID_T] * 3, rffi.INT,
  1423. save_err=rffi.RFFI_SAVE_ERRNO)
  1424. c_setresgid = external('setresgid', [GID_T] * 3, rffi.INT,
  1425. save_err=rffi.RFFI_SAVE_ERRNO)
  1426. @replace_os_function('getresuid')
  1427. def getresuid():
  1428. out = lltype.malloc(UID_T_P.TO, 3, flavor='raw')
  1429. try:
  1430. handle_posix_error('getresuid',
  1431. c_getresuid(rffi.ptradd(out, 0),
  1432. rffi.ptradd(out, 1),
  1433. rffi.ptradd(out, 2)))
  1434. return (widen_uid(out[0]), widen_uid(out[1]), widen_uid(out[2]))
  1435. finally:
  1436. lltype.free(out, flavor='raw')
  1437. @replace_os_function('getresgid')
  1438. def getresgid():
  1439. out = lltype.malloc(GID_T_P.TO, 3, flavor='raw')
  1440. try:
  1441. handle_posix_error('getresgid',
  1442. c_getresgid(rffi.ptradd(out, 0),
  1443. rffi.ptradd(out, 1),
  1444. rffi.ptradd(out, 2)))
  1445. return (widen_gid(out[0]), widen_gid(out[1]), widen_gid(out[2]))
  1446. finally:
  1447. lltype.free(out, flavor='raw')
  1448. @replace_os_function('setresuid')
  1449. def setresuid(ruid, euid, suid):
  1450. handle_posix_error('setresuid', c_setresuid(ruid, euid, suid))
  1451. @replace_os_function('setresgid')
  1452. def setresgid(rgid, egid, sgid):
  1453. handle_posix_error('setresgid', c_setresgid(rgid, egid, sgid))
  1454. #___________________________________________________________________
  1455. c_chroot = external('chroot', [rffi.CCHARP], rffi.INT,
  1456. save_err=rffi.RFFI_SAVE_ERRNO,
  1457. macro=_MACRO_ON_POSIX)
  1458. @replace_os_function('chroot')
  1459. def chroot(path):
  1460. handle_posix_error('chroot', c_chroot(_as_bytes0(path)))
  1461. if not _WIN32:
  1462. CHARARRAY1 = lltype.FixedSizeArray(lltype.Char, 1)
  1463. class CConfig:
  1464. _compilation_info_ = ExternalCompilationInfo(
  1465. includes = ['sys/utsname.h']
  1466. )
  1467. UTSNAME = rffi_platform.Struct('struct utsname', [
  1468. ('sysname', CHARARRAY1),
  1469. ('nodename', CHARARRAY1),
  1470. ('release', CHARARRAY1),
  1471. ('version', CHARARRAY1),
  1472. ('machine', CHARARRAY1)])
  1473. config = rffi_platform.configure(CConfig)
  1474. UTSNAMEP = lltype.Ptr(config['UTSNAME'])
  1475. c_uname = external('uname', [UTSNAMEP], rffi.INT,
  1476. compilation_info=CConfig._compilation_info_,
  1477. save_err=rffi.RFFI_SAVE_ERRNO)
  1478. @replace_os_function('uname')
  1479. def uname():
  1480. l_utsbuf = lltype.malloc(UTSNAMEP.TO, flavor='raw')
  1481. try:
  1482. handle_posix_error('uname', c_uname(l_utsbuf))
  1483. return (
  1484. rffi.charp2str(rffi.cast(rffi.CCHARP, l_utsbuf.c_sysname)),
  1485. rffi.charp2str(rffi.cast(rffi.CCHARP, l_utsbuf.c_nodename)),
  1486. rffi.charp2str(rffi.cast(rffi.CCHARP, l_utsbuf.c_release)),
  1487. rffi.charp2str(rffi.cast(rffi.CCHARP, l_utsbuf.c_version)),
  1488. rffi.charp2str(rffi.cast(rffi.CCHARP, l_utsbuf.c_machine)),
  1489. )
  1490. finally:
  1491. lltype.free(l_utsbuf, flavor='raw')
  1492. # These are actually macros on some/most systems
  1493. c_makedev = external('makedev', [rffi.INT, rffi.INT], rffi.INT)
  1494. c_major = external('major', [rffi.INT], rffi.INT)
  1495. c_minor = external('minor', [rffi.INT], rffi.INT)
  1496. @replace_os_function('makedev')
  1497. @jit.dont_look_inside
  1498. def makedev(maj, min):
  1499. return c_makedev(maj, min)
  1500. @replace_os_function('major')
  1501. @jit.dont_look_inside
  1502. def major(dev):
  1503. return c_major(dev)
  1504. @replace_os_function('minor')
  1505. @jit.dont_look_inside
  1506. def minor(dev):
  1507. return c_minor(dev)
  1508. #___________________________________________________________________
  1509. c_sysconf = external('sysconf', [rffi.INT], rffi.LONG,
  1510. save_err=rffi.RFFI_FULL_ERRNO_ZERO)
  1511. c_fpathconf = external('fpathconf', [rffi.INT, rffi.INT], rffi.LONG,
  1512. save_err=rffi.RFFI_FULL_ERRNO_ZERO)
  1513. c_pathconf = external('pathconf', [rffi.CCHARP, rffi.INT], rffi.LONG,
  1514. save_err=rffi.RFFI_FULL_ERRNO_ZERO)
  1515. c_confstr = external('confstr',
  1516. [rffi.INT, rffi.CCHARP, rffi.SIZE_T], rffi.SIZE_T,
  1517. save_err=rffi.RFFI_FULL_ERRNO_ZERO)
  1518. @replace_os_function('sysconf')
  1519. def sysconf(value):
  1520. res = c_sysconf(value)
  1521. if res == -1:
  1522. errno = get_saved_errno()
  1523. if errno != 0:
  1524. raise OSError(errno, "sysconf failed")
  1525. return res
  1526. @replace_os_function('fpathconf')
  1527. def fpathconf(fd, value):
  1528. res = c_fpathconf(fd, value)
  1529. if res == -1:
  1530. errno = get_saved_errno()
  1531. if errno != 0:
  1532. raise OSError(errno, "fpathconf failed")
  1533. return res
  1534. @replace_os_function('pathconf')
  1535. def pathconf(path, value):
  1536. res = c_pathconf(_as_bytes0(path), value)
  1537. if res == -1:
  1538. errno = get_saved_errno()
  1539. if errno != 0:
  1540. raise OSError(errno, "pathconf failed")
  1541. return res
  1542. @replace_os_function('confstr')
  1543. def confstr(value):
  1544. n = intmask(c_confstr(value, lltype.nullptr(rffi.CCHARP.TO), 0))
  1545. if n > 0:
  1546. buf = lltype.malloc(rffi.CCHARP.TO, n, flavor='raw')
  1547. try:
  1548. c_confstr(value, buf, n)
  1549. return rffi.charp2strn(buf, n)
  1550. finally:
  1551. lltype.free(buf, flavor='raw')
  1552. else:
  1553. errno = get_saved_errno()
  1554. if errno != 0:
  1555. raise OSError(errno, "confstr failed")
  1556. return None
  1557. # ____________________________________________________________
  1558. # Support for os.environ
  1559. # XXX only for systems where os.environ is an instance of _Environ,
  1560. # which should cover Unix and Windows at least
  1561. assert type(os.environ) is not dict
  1562. from rpython.rtyper.controllerentry import ControllerEntryForPrebuilt
  1563. class EnvironExtRegistry(ControllerEntryForPrebuilt):
  1564. _about_ = os.environ
  1565. def getcontroller(self):
  1566. from rpython.rlib.rposix_environ import OsEnvironController
  1567. return OsEnvironController()
  1568. # ____________________________________________________________
  1569. # Support for f... and ...at families of POSIX functions
  1570. class CConfig:
  1571. _compilation_info_ = ExternalCompilationInfo(
  1572. includes=['sys/stat.h',
  1573. 'sys/time.h',
  1574. 'unistd.h',
  1575. 'fcntl.h'],
  1576. )
  1577. for _name in """faccessat fchdir fchmod fchmodat fchown fchownat fexecve
  1578. fdopendir fpathconf fstat fstatat fstatvfs ftruncate
  1579. futimens futimes futimesat linkat chflags lchflags lchmod lchown
  1580. lstat lutimes mkdirat mkfifoat mknodat openat readlinkat renameat
  1581. symlinkat unlinkat utimensat""".split():
  1582. locals()['HAVE_%s' % _name.upper()] = rffi_platform.Has(_name)
  1583. cConfig = rffi_platform.configure(CConfig)
  1584. globals().update(cConfig)
  1585. if not _WIN32:
  1586. class CConfig:
  1587. _compilation_info_ = ExternalCompilationInfo(
  1588. includes=['sys/stat.h',
  1589. 'unistd.h',
  1590. 'fcntl.h'],
  1591. )
  1592. AT_FDCWD = rffi_platform.DefinedConstantInteger('AT_FDCWD')
  1593. AT_SYMLINK_NOFOLLOW = rffi_platform.DefinedConstantInteger('AT_SYMLINK_NOFOLLOW')
  1594. AT_EACCESS = rffi_platform.DefinedConstantInteger('AT_EACCESS')
  1595. AT_REMOVEDIR = rffi_platform.DefinedConstantInteger('AT_REMOVEDIR')
  1596. AT_EMPTY_PATH = rffi_platform.DefinedConstantInteger('AT_EMPTY_PATH')
  1597. UTIME_NOW = rffi_platform.DefinedConstantInteger('UTIME_NOW')
  1598. UTIME_OMIT = rffi_platform.DefinedConstantInteger('UTIME_OMIT')
  1599. TIMESPEC = rffi_platform.Struct('struct timespec', [
  1600. ('tv_sec', rffi.TIME_T),
  1601. ('tv_nsec', rffi.LONG)])
  1602. cConfig = rffi_platform.configure(CConfig)
  1603. globals().update(cConfig)
  1604. TIMESPEC2P = rffi.CArrayPtr(TIMESPEC)
  1605. if HAVE_FACCESSAT:
  1606. c_faccessat = external('faccessat',
  1607. [rffi.INT, rffi.CCHARP, rffi.INT, rffi.INT], rffi.INT)
  1608. def faccessat(pathname, mode, dir_fd=AT_FDCWD,
  1609. effective_ids=False, follow_symlinks=True):
  1610. """Thin wrapper around faccessat(2) with an interface simlar to
  1611. Python3's os.access().
  1612. """
  1613. flags = 0
  1614. if not follow_symlinks:
  1615. flags |= AT_SYMLINK_NOFOLLOW
  1616. if effective_ids:
  1617. flags |= AT_EACCESS
  1618. error = c_faccessat(dir_fd, pathname, mode, flags)
  1619. return error == 0
  1620. if HAVE_FCHMODAT:
  1621. c_fchmodat = external('fchmodat',
  1622. [rffi.INT, rffi.CCHARP, rffi.INT, rffi.INT], rffi.INT,
  1623. save_err=rffi.RFFI_SAVE_ERRNO,)
  1624. def fchmodat(path, mode, dir_fd=AT_FDCWD, follow_symlinks=True):
  1625. if follow_symlinks:
  1626. flag = 0
  1627. else:
  1628. flag = AT_SYMLINK_NOFOLLOW
  1629. error = c_fchmodat(dir_fd, path, mode, flag)
  1630. handle_posix_error('fchmodat', error)
  1631. if HAVE_FCHOWNAT:
  1632. c_fchownat = external('fchownat',
  1633. [rffi.INT, rffi.CCHARP, rffi.INT, rffi.INT, rffi.INT], rffi.INT,
  1634. save_err=rffi.RFFI_SAVE_ERRNO,)
  1635. def fchownat(path, owner, group, dir_fd=AT_FDCWD,
  1636. follow_symlinks=True, empty_path=False):
  1637. flag = 0
  1638. if not follow_symlinks:
  1639. flag |= AT_SYMLINK_NOFOLLOW
  1640. if empty_path:
  1641. flag |= AT_EMPTY_PATH
  1642. error = c_fchownat(dir_fd, path, owner, group, flag)
  1643. handle_posix_error('fchownat', error)
  1644. if HAVE_FEXECVE:
  1645. c_fexecve = external('fexecve',
  1646. [rffi.INT, rffi.CCHARPP, rffi.CCHARPP], rffi.INT,
  1647. save_err=rffi.RFFI_SAVE_ERRNO)
  1648. def fexecve(fd, args, env):
  1649. envstrs = []
  1650. for item in env.iteritems():
  1651. envstr = "%s=%s" % item
  1652. envstrs.append(envstr)
  1653. # This list conversion already takes care of NUL bytes.
  1654. l_args = rffi.ll_liststr2charpp(args)
  1655. l_env = rffi.ll_liststr2charpp(envstrs)
  1656. c_fexecve(fd, l_args, l_env)
  1657. rffi.free_charpp(l_env)
  1658. rffi.free_charpp(l_args)
  1659. raise OSError(get_saved_errno(), "execve failed")
  1660. if HAVE_LINKAT:
  1661. c_linkat = external('linkat',
  1662. [rffi.INT, rffi.CCHARP, rffi.INT, rffi.CCHARP, rffi.INT], rffi.INT)
  1663. def linkat(src, dst, src_dir_fd=AT_FDCWD, dst_dir_fd=AT_FDCWD,
  1664. follow_symlinks=True):
  1665. """Thin wrapper around linkat(2) with an interface similar to
  1666. Python3's os.link()
  1667. """
  1668. if follow_symlinks:
  1669. flag = 0
  1670. else:
  1671. flag = AT_SYMLINK_NOFOLLOW
  1672. error = c_linkat(src_dir_fd, src, dst_dir_fd, dst, flag)
  1673. handle_posix_error('linkat', error)
  1674. if HAVE_FUTIMENS:
  1675. c_futimens = external('futimens', [rffi.INT, TIMESPEC2P], rffi.INT)
  1676. def futimens(fd, atime, atime_ns, mtime, mtime_ns):
  1677. l_times = lltype.malloc(TIMESPEC2P.TO, 2, flavor='raw')
  1678. rffi.setintfield(l_times[0], 'c_tv_sec', atime)
  1679. rffi.setintfield(l_times[0], 'c_tv_nsec', atime_ns)
  1680. rffi.setintfield(l_times[1], 'c_tv_sec', mtime)
  1681. rffi.setintfield(l_times[1], 'c_tv_nsec', mtime_ns)
  1682. error = c_futimens(fd, l_times)
  1683. lltype.free(l_times, flavor='raw')
  1684. handle_posix_error('futimens', error)
  1685. if HAVE_UTIMENSAT:
  1686. c_utimensat = external('utimensat',
  1687. [rffi.INT, rffi.CCHARP, TIMESPEC2P, rffi.INT], rffi.INT)
  1688. def utimensat(pathname, atime, atime_ns, mtime, mtime_ns,
  1689. dir_fd=AT_FDCWD, follow_symlinks=True):
  1690. """Wrapper around utimensat(2)
  1691. To set access time to the current time, pass atime_ns=UTIME_NOW,
  1692. atime is then ignored.
  1693. To set modification time to the current time, pass mtime_ns=UTIME_NOW,
  1694. mtime is then ignored.
  1695. """
  1696. l_times = lltype.malloc(TIMESPEC2P.TO, 2, flavor='raw')
  1697. rffi.setintfield(l_times[0], 'c_tv_sec', atime)
  1698. rffi.setintfield(l_times[0], 'c_tv_nsec', atime_ns)
  1699. rffi.setintfield(l_times[1], 'c_tv_sec', mtime)
  1700. rffi.setintfield(l_times[1], 'c_tv_nsec', mtime_ns)
  1701. if follow_symlinks:
  1702. flag = 0
  1703. else:
  1704. flag = AT_SYMLINK_NOFOLLOW
  1705. error = c_utimensat(dir_fd, pathname, l_times, flag)
  1706. lltype.free(l_times, flavor='raw')
  1707. handle_posix_error('utimensat', error)
  1708. if HAVE_LUTIMES:
  1709. c_lutimes = external('lutimes',
  1710. [rffi.CCHARP, TIMEVAL2P], rffi.INT,
  1711. save_err=rffi.RFFI_SAVE_ERRNO)
  1712. @specialize.argtype(1)
  1713. def lutimes(pathname, times):
  1714. if times is None:
  1715. error = c_lutimes(pathname, lltype.nullptr(TIMEVAL2P.TO))
  1716. else:
  1717. with lltype.scoped_alloc(TIMEVAL2P.TO, 2) as l_timeval2p:
  1718. times_to_timeval2p(times, l_timeval2p)
  1719. error = c_lutimes(pathname, l_timeval2p)
  1720. handle_posix_error('lutimes', error)
  1721. if HAVE_FUTIMES:
  1722. c_futimes = external('futimes',
  1723. [rffi.INT, TIMEVAL2P], rffi.INT,
  1724. save_err=rffi.RFFI_SAVE_ERRNO)
  1725. @specialize.argtype(1)
  1726. def futimes(fd, times):
  1727. if times is None:
  1728. error = c_futimes(fd, lltype.nullptr(TIMEVAL2P.TO))
  1729. else:
  1730. with lltype.scoped_alloc(TIMEVAL2P.TO, 2) as l_timeval2p:
  1731. times_to_timeval2p(times, l_timeval2p)
  1732. error = c_futimes(fd, l_timeval2p)
  1733. handle_posix_error('futimes', error)
  1734. if HAVE_MKDIRAT:
  1735. c_mkdirat = external('mkdirat',
  1736. [rffi.INT, rffi.CCHARP, rffi.INT], rffi.INT,
  1737. save_err=rffi.RFFI_SAVE_ERRNO)
  1738. def mkdirat(pathname, mode, dir_fd=AT_FDCWD):
  1739. error = c_mkdirat(dir_fd, pathname, mode)
  1740. handle_posix_error('mkdirat', error)
  1741. if HAVE_UNLINKAT:
  1742. c_unlinkat = external('unlinkat',
  1743. [rffi.INT, rffi.CCHARP, rffi.INT], rffi.INT,
  1744. save_err=rffi.RFFI_SAVE_ERRNO)
  1745. def unlinkat(pathname, dir_fd=AT_FDCWD, removedir=False):
  1746. flag = AT_REMOVEDIR if removedir else 0
  1747. error = c_unlinkat(dir_fd, pathname, flag)
  1748. handle_posix_error('unlinkat', error)
  1749. if HAVE_READLINKAT:
  1750. c_readlinkat = external(
  1751. 'readlinkat',
  1752. [rffi.INT, rffi.CCHARP, rffi.CCHARP, rffi.SIZE_T], rffi.SSIZE_T,
  1753. save_err=rffi.RFFI_SAVE_ERRNO)
  1754. def readlinkat(pathname, dir_fd=AT_FDCWD):
  1755. pathname = _as_bytes0(pathname)
  1756. bufsize = 1023
  1757. while True:
  1758. buf = lltype.malloc(rffi.CCHARP.TO, bufsize, flavor='raw')
  1759. res = widen(c_readlinkat(dir_fd, pathname, buf, bufsize))
  1760. if res < 0:
  1761. lltype.free(buf, flavor='raw')
  1762. error = get_saved_errno() # failed
  1763. raise OSError(error, "readlinkat failed")
  1764. elif res < bufsize:
  1765. break # ok
  1766. else:
  1767. # buf too small, try again with a larger buffer
  1768. lltype.free(buf, flavor='raw')
  1769. bufsize *= 4
  1770. # convert the result to a string
  1771. result = rffi.charp2strn(buf, res)
  1772. lltype.free(buf, flavor='raw')
  1773. return result
  1774. if HAVE_RENAMEAT:
  1775. c_renameat = external(
  1776. 'renameat',
  1777. [rffi.INT, rffi.CCHARP, rffi.INT, rffi.CCHARP], rffi.INT,
  1778. save_err=rffi.RFFI_SAVE_ERRNO)
  1779. def renameat(src, dst, src_dir_fd=AT_FDCWD, dst_dir_fd=AT_FDCWD):
  1780. error = c_renameat(src_dir_fd, src, dst_dir_fd, dst)
  1781. handle_posix_error('renameat', error)
  1782. if HAVE_SYMLINKAT:
  1783. c_symlinkat = external('symlinkat',
  1784. [rffi.CCHARP, rffi.INT, rffi.CCHARP], rffi.INT,
  1785. save_err=rffi.RFFI_SAVE_ERRNO)
  1786. def symlinkat(src, dst, dir_fd=AT_FDCWD):
  1787. error = c_symlinkat(src, dir_fd, dst)
  1788. handle_posix_error('symlinkat', error)
  1789. if HAVE_OPENAT:
  1790. c_openat = external('openat',
  1791. [rffi.INT, rffi.CCHARP, rffi.INT, rffi.MODE_T], rffi.INT,
  1792. save_err=rffi.RFFI_SAVE_ERRNO)
  1793. @enforceargs(s_Str0, int, int, int, typecheck=False)
  1794. def openat(path, flags, mode, dir_fd=AT_FDCWD):
  1795. fd = c_openat(dir_fd, path, flags, mode)
  1796. return handle_posix_error('open', fd)
  1797. if HAVE_MKFIFOAT:
  1798. c_mkfifoat = external('mkfifoat',
  1799. [rffi.INT, rffi.CCHARP, rffi.MODE_T], rffi.INT,
  1800. save_err=rffi.RFFI_SAVE_ERRNO)
  1801. def mkfifoat(path, mode, dir_fd=AT_FDCWD):
  1802. error = c_mkfifoat(dir_fd, path, mode)
  1803. handle_posix_error('mkfifoat', error)
  1804. if HAVE_MKNODAT:
  1805. c_mknodat = external('mknodat',
  1806. [rffi.INT, rffi.CCHARP, rffi.MODE_T, rffi.INT], rffi.INT,
  1807. save_err=rffi.RFFI_SAVE_ERRNO)
  1808. def mknodat(path, mode, device, dir_fd=AT_FDCWD):
  1809. error = c_mknodat(dir_fd, path, mode, device)
  1810. handle_posix_error('mknodat', error)
  1811. eci_inheritable = eci.merge(ExternalCompilationInfo(
  1812. separate_module_sources=["""
  1813. RPY_EXTERN
  1814. int rpy_set_inheritable(int fd, int inheritable)
  1815. {
  1816. /* XXX minimal impl. XXX */
  1817. int request = inheritable ? FIONCLEX : FIOCLEX;
  1818. return ioctl(fd, request, NULL);
  1819. }
  1820. RPY_EXTERN
  1821. int rpy_get_inheritable(int fd)
  1822. {
  1823. int flags = fcntl(fd, F_GETFD, 0);
  1824. if (flags == -1)
  1825. return -1;
  1826. return !(flags & FD_CLOEXEC);
  1827. }
  1828. """],
  1829. post_include_bits=['RPY_EXTERN int rpy_set_inheritable(int, int);']))
  1830. c_set_inheritable = external('rpy_set_inheritable', [rffi.INT, rffi.INT],
  1831. rffi.INT, save_err=rffi.RFFI_SAVE_ERRNO,
  1832. compilation_info=eci_inheritable)
  1833. c_get_inheritable = external('rpy_get_inheritable', [rffi.INT],
  1834. rffi.INT, save_err=rffi.RFFI_SAVE_ERRNO,
  1835. compilation_info=eci_inheritable)
  1836. def set_inheritable(fd, inheritable):
  1837. error = c_set_inheritable(fd, inheritable)
  1838. handle_posix_error('set_inheritable', error)
  1839. def get_inheritable(fd):
  1840. res = c_get_inheritable(fd)
  1841. res = handle_posix_error('get_inheritable', res)
  1842. return res != 0