PageRenderTime 55ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 1ms

/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

Large files files are truncated, but you can click here to view the full file

  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 +

Large files files are truncated, but you can click here to view the full file