PageRenderTime 51ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/rpython/rlib/rposix_stat.py

https://bitbucket.org/pypy/pypy/
Python | 632 lines | 484 code | 105 blank | 43 comment | 86 complexity | fd673a24611c626ced7d7b61b1497871 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. """Annotation and rtyping support for the result of os.stat(), os.lstat()
  2. and os.fstat(). In RPython like in plain Python the stat result can be
  3. indexed like a tuple but also exposes the st_xxx attributes.
  4. """
  5. import os, sys
  6. from rpython.flowspace.model import Constant
  7. from rpython.flowspace.operation import op
  8. from rpython.annotator import model as annmodel
  9. from rpython.rtyper import extregistry
  10. from rpython.tool.pairtype import pairtype
  11. from rpython.rtyper.tool import rffi_platform as platform
  12. from rpython.rtyper.llannotation import lltype_to_annotation
  13. from rpython.rtyper.rmodel import Repr
  14. from rpython.rtyper.rint import IntegerRepr
  15. from rpython.rtyper.error import TyperError
  16. from rpython.rlib._os_support import _preferred_traits, string_traits
  17. from rpython.rlib.objectmodel import specialize
  18. from rpython.rtyper.lltypesystem import lltype, rffi
  19. from rpython.translator.tool.cbuild import ExternalCompilationInfo
  20. from rpython.rlib.rarithmetic import intmask
  21. from rpython.rlib.rposix import (
  22. replace_os_function, handle_posix_error, _as_bytes0)
  23. from rpython.rlib import rposix
  24. _WIN32 = sys.platform.startswith('win')
  25. _LINUX = sys.platform.startswith('linux')
  26. if _WIN32:
  27. from rpython.rlib import rwin32
  28. from rpython.rlib.rwin32file import make_win32_traits
  29. # Support for float times is here.
  30. # - ALL_STAT_FIELDS contains Float fields if the system can retrieve
  31. # sub-second timestamps.
  32. # - TIMESPEC is defined when the "struct stat" contains st_atim field.
  33. if sys.platform.startswith('linux') or sys.platform.startswith('openbsd'):
  34. from rpython.rlib.rposix import TIMESPEC
  35. else:
  36. TIMESPEC = None
  37. # all possible fields - some of them are not available on all platforms
  38. ALL_STAT_FIELDS = [
  39. ("st_mode", lltype.Signed),
  40. ("st_ino", lltype.SignedLongLong),
  41. ("st_dev", lltype.SignedLongLong),
  42. ("st_nlink", lltype.Signed),
  43. ("st_uid", lltype.Signed),
  44. ("st_gid", lltype.Signed),
  45. ("st_size", lltype.SignedLongLong),
  46. ("st_atime", lltype.Float),
  47. ("st_mtime", lltype.Float),
  48. ("st_ctime", lltype.Float),
  49. ("st_blksize", lltype.Signed),
  50. ("st_blocks", lltype.Signed),
  51. ("st_rdev", lltype.Signed),
  52. ("st_flags", lltype.Signed),
  53. #("st_gen", lltype.Signed), -- new in CPy 2.5, not implemented
  54. #("st_birthtime", lltype.Float), -- new in CPy 2.5, not implemented
  55. ]
  56. N_INDEXABLE_FIELDS = 10
  57. # For OO backends, expose only the portable fields (the first 10).
  58. PORTABLE_STAT_FIELDS = ALL_STAT_FIELDS[:N_INDEXABLE_FIELDS]
  59. STATVFS_FIELDS = [
  60. ("f_bsize", lltype.Signed),
  61. ("f_frsize", lltype.Signed),
  62. ("f_blocks", lltype.Signed),
  63. ("f_bfree", lltype.Signed),
  64. ("f_bavail", lltype.Signed),
  65. ("f_files", lltype.Signed),
  66. ("f_ffree", lltype.Signed),
  67. ("f_favail", lltype.Signed),
  68. ("f_flag", lltype.Signed),
  69. ("f_namemax", lltype.Signed),
  70. ]
  71. # ____________________________________________________________
  72. #
  73. # Annotation support
  74. class SomeStatResult(annmodel.SomeObject):
  75. knowntype = os.stat_result
  76. def rtyper_makerepr(self, rtyper):
  77. return StatResultRepr(rtyper)
  78. def rtyper_makekey(self):
  79. return self.__class__,
  80. def getattr(self, s_attr):
  81. if not s_attr.is_constant():
  82. raise annmodel.AnnotatorError("non-constant attr name in getattr()")
  83. attrname = s_attr.const
  84. TYPE = STAT_FIELD_TYPES[attrname]
  85. return lltype_to_annotation(TYPE)
  86. def _get_rmarshall_support_(self): # for rlib.rmarshal
  87. # reduce and recreate stat_result objects from 10-tuples
  88. # (we ignore the extra values here for simplicity and portability)
  89. def stat_result_reduce(st):
  90. return (st[0], st[1], st[2], st[3], st[4],
  91. st[5], st[6], st[7], st[8], st[9])
  92. def stat_result_recreate(tup):
  93. return make_stat_result(tup + extra_zeroes)
  94. s_reduced = annmodel.SomeTuple([lltype_to_annotation(TYPE)
  95. for name, TYPE in PORTABLE_STAT_FIELDS])
  96. extra_zeroes = (0,) * (len(STAT_FIELDS) - len(PORTABLE_STAT_FIELDS))
  97. return s_reduced, stat_result_reduce, stat_result_recreate
  98. class __extend__(pairtype(SomeStatResult, annmodel.SomeInteger)):
  99. def getitem((s_sta, s_int)):
  100. assert s_int.is_constant(), "os.stat()[index]: index must be constant"
  101. index = s_int.const
  102. assert 0 <= index < N_INDEXABLE_FIELDS, "os.stat()[index] out of range"
  103. name, TYPE = STAT_FIELDS[index]
  104. return lltype_to_annotation(TYPE)
  105. class StatResultRepr(Repr):
  106. def __init__(self, rtyper):
  107. self.rtyper = rtyper
  108. self.stat_field_indexes = {}
  109. for i, (name, TYPE) in enumerate(STAT_FIELDS):
  110. self.stat_field_indexes[name] = i
  111. self.s_tuple = annmodel.SomeTuple(
  112. [lltype_to_annotation(TYPE) for name, TYPE in STAT_FIELDS])
  113. self.r_tuple = rtyper.getrepr(self.s_tuple)
  114. self.lowleveltype = self.r_tuple.lowleveltype
  115. def redispatch_getfield(self, hop, index):
  116. rtyper = self.rtyper
  117. s_index = rtyper.annotator.bookkeeper.immutablevalue(index)
  118. hop2 = hop.copy()
  119. spaceop = op.getitem(hop.args_v[0], Constant(index))
  120. spaceop.result = hop.spaceop.result
  121. hop2.spaceop = spaceop
  122. hop2.args_v = spaceop.args
  123. hop2.args_s = [self.s_tuple, s_index]
  124. hop2.args_r = [self.r_tuple, rtyper.getrepr(s_index)]
  125. return hop2.dispatch()
  126. def rtype_getattr(self, hop):
  127. s_attr = hop.args_s[1]
  128. attr = s_attr.const
  129. try:
  130. index = self.stat_field_indexes[attr]
  131. except KeyError:
  132. raise TyperError("os.stat().%s: field not available" % (attr,))
  133. return self.redispatch_getfield(hop, index)
  134. class __extend__(pairtype(StatResultRepr, IntegerRepr)):
  135. def rtype_getitem((r_sta, r_int), hop):
  136. s_int = hop.args_s[1]
  137. index = s_int.const
  138. return r_sta.redispatch_getfield(hop, index)
  139. s_StatResult = SomeStatResult()
  140. def make_stat_result(tup):
  141. """Turn a tuple into an os.stat_result object."""
  142. positional = tuple(
  143. lltype.cast_primitive(TYPE, value) for value, (name, TYPE) in
  144. zip(tup, STAT_FIELDS)[:N_INDEXABLE_FIELDS])
  145. kwds = {}
  146. for value, (name, TYPE) in zip(tup, STAT_FIELDS)[N_INDEXABLE_FIELDS:]:
  147. kwds[name] = lltype.cast_primitive(TYPE, value)
  148. return os.stat_result(positional, kwds)
  149. class MakeStatResultEntry(extregistry.ExtRegistryEntry):
  150. _about_ = make_stat_result
  151. def compute_result_annotation(self, s_tup):
  152. return s_StatResult
  153. def specialize_call(self, hop):
  154. r_StatResult = hop.rtyper.getrepr(s_StatResult)
  155. [v_result] = hop.inputargs(r_StatResult.r_tuple)
  156. # no-op conversion from r_StatResult.r_tuple to r_StatResult
  157. hop.exception_cannot_occur()
  158. return v_result
  159. class SomeStatvfsResult(annmodel.SomeObject):
  160. if hasattr(os, 'statvfs_result'):
  161. knowntype = os.statvfs_result
  162. else:
  163. knowntype = None # will not be used
  164. def rtyper_makerepr(self, rtyper):
  165. return StatvfsResultRepr(rtyper)
  166. def rtyper_makekey(self):
  167. return self.__class__,
  168. def getattr(self, s_attr):
  169. assert s_attr.is_constant()
  170. TYPE = STATVFS_FIELD_TYPES[s_attr.const]
  171. return lltype_to_annotation(TYPE)
  172. class __extend__(pairtype(SomeStatvfsResult, annmodel.SomeInteger)):
  173. def getitem((s_stat, s_int)):
  174. assert s_int.is_constant()
  175. name, TYPE = STATVFS_FIELDS[s_int.const]
  176. return lltype_to_annotation(TYPE)
  177. s_StatvfsResult = SomeStatvfsResult()
  178. class StatvfsResultRepr(Repr):
  179. def __init__(self, rtyper):
  180. self.rtyper = rtyper
  181. self.statvfs_field_indexes = {}
  182. for i, (name, TYPE) in enumerate(STATVFS_FIELDS):
  183. self.statvfs_field_indexes[name] = i
  184. self.s_tuple = annmodel.SomeTuple(
  185. [lltype_to_annotation(TYPE) for name, TYPE in STATVFS_FIELDS])
  186. self.r_tuple = rtyper.getrepr(self.s_tuple)
  187. self.lowleveltype = self.r_tuple.lowleveltype
  188. def redispatch_getfield(self, hop, index):
  189. rtyper = self.rtyper
  190. s_index = rtyper.annotator.bookkeeper.immutablevalue(index)
  191. hop2 = hop.copy()
  192. spaceop = op.getitem(hop.args_v[0], Constant(index))
  193. spaceop.result = hop.spaceop.result
  194. hop2.spaceop = spaceop
  195. hop2.args_v = spaceop.args
  196. hop2.args_s = [self.s_tuple, s_index]
  197. hop2.args_r = [self.r_tuple, rtyper.getrepr(s_index)]
  198. return hop2.dispatch()
  199. def rtype_getattr(self, hop):
  200. s_attr = hop.args_s[1]
  201. attr = s_attr.const
  202. try:
  203. index = self.statvfs_field_indexes[attr]
  204. except KeyError:
  205. raise TyperError("os.statvfs().%s: field not available" % (attr,))
  206. return self.redispatch_getfield(hop, index)
  207. class __extend__(pairtype(StatvfsResultRepr, IntegerRepr)):
  208. def rtype_getitem((r_sta, r_int), hop):
  209. s_int = hop.args_s[1]
  210. index = s_int.const
  211. return r_sta.redispatch_getfield(hop, index)
  212. def make_statvfs_result(tup):
  213. args = tuple(
  214. lltype.cast_primitive(TYPE, value) for value, (name, TYPE) in
  215. zip(tup, STATVFS_FIELDS))
  216. return os.statvfs_result(args)
  217. class MakeStatvfsResultEntry(extregistry.ExtRegistryEntry):
  218. _about_ = make_statvfs_result
  219. def compute_result_annotation(self, s_tup):
  220. return s_StatvfsResult
  221. def specialize_call(self, hop):
  222. r_StatvfsResult = hop.rtyper.getrepr(s_StatvfsResult)
  223. [v_result] = hop.inputargs(r_StatvfsResult.r_tuple)
  224. hop.exception_cannot_occur()
  225. return v_result
  226. # ____________________________________________________________
  227. #
  228. # RFFI support
  229. if sys.platform.startswith('win'):
  230. _name_struct_stat = '_stati64'
  231. INCLUDES = ['sys/types.h', 'sys/stat.h', 'sys/statvfs.h']
  232. else:
  233. if _LINUX:
  234. _name_struct_stat = 'stat64'
  235. else:
  236. _name_struct_stat = 'stat'
  237. INCLUDES = ['sys/types.h', 'sys/stat.h', 'sys/statvfs.h', 'unistd.h']
  238. compilation_info = ExternalCompilationInfo(
  239. # This must be set to 64 on some systems to enable large file support.
  240. #pre_include_bits = ['#define _FILE_OFFSET_BITS 64'],
  241. # ^^^ nowadays it's always set in all C files we produce.
  242. includes=INCLUDES
  243. )
  244. def posix_declaration(try_to_add=None):
  245. global STAT_STRUCT, STATVFS_STRUCT
  246. LL_STAT_FIELDS = STAT_FIELDS[:]
  247. if try_to_add:
  248. LL_STAT_FIELDS.append(try_to_add)
  249. if TIMESPEC is not None:
  250. def _expand(lst, originalname, timespecname):
  251. for i, (_name, _TYPE) in enumerate(lst):
  252. if _name == originalname:
  253. # replace the 'st_atime' field of type rffi.DOUBLE
  254. # with a field 'st_atim' of type 'struct timespec'
  255. lst[i] = (timespecname, TIMESPEC)
  256. break
  257. _expand(LL_STAT_FIELDS, 'st_atime', 'st_atim')
  258. _expand(LL_STAT_FIELDS, 'st_mtime', 'st_mtim')
  259. _expand(LL_STAT_FIELDS, 'st_ctime', 'st_ctim')
  260. del _expand
  261. else:
  262. # Replace float fields with integers
  263. for name in ('st_atime', 'st_mtime', 'st_ctime', 'st_birthtime'):
  264. for i, (_name, _TYPE) in enumerate(LL_STAT_FIELDS):
  265. if _name == name:
  266. LL_STAT_FIELDS[i] = (_name, lltype.Signed)
  267. break
  268. class CConfig:
  269. _compilation_info_ = compilation_info
  270. STAT_STRUCT = platform.Struct('struct %s' % _name_struct_stat, LL_STAT_FIELDS)
  271. STATVFS_STRUCT = platform.Struct('struct statvfs', STATVFS_FIELDS)
  272. try:
  273. config = platform.configure(CConfig, ignore_errors=try_to_add is not None)
  274. except platform.CompilationError:
  275. if try_to_add:
  276. return # failed to add this field, give up
  277. raise
  278. STAT_STRUCT = lltype.Ptr(config['STAT_STRUCT'])
  279. STATVFS_STRUCT = lltype.Ptr(config['STATVFS_STRUCT'])
  280. if try_to_add:
  281. STAT_FIELDS.append(try_to_add)
  282. # This lists only the fields that have been found on the underlying platform.
  283. # Initially only the PORTABLE_STAT_FIELDS, but more may be added by the
  284. # following loop.
  285. STAT_FIELDS = PORTABLE_STAT_FIELDS[:]
  286. if sys.platform != 'win32':
  287. posix_declaration()
  288. for _i in range(len(PORTABLE_STAT_FIELDS), len(ALL_STAT_FIELDS)):
  289. posix_declaration(ALL_STAT_FIELDS[_i])
  290. del _i
  291. # these two global vars only list the fields defined in the underlying platform
  292. STAT_FIELD_TYPES = dict(STAT_FIELDS) # {'st_xxx': TYPE}
  293. STAT_FIELD_NAMES = [_name for (_name, _TYPE) in STAT_FIELDS]
  294. del _name, _TYPE
  295. STATVFS_FIELD_TYPES = dict(STATVFS_FIELDS)
  296. STATVFS_FIELD_NAMES = [name for name, tp in STATVFS_FIELDS]
  297. def build_stat_result(st):
  298. # only for LL backends
  299. if TIMESPEC is not None:
  300. atim = st.c_st_atim; atime = int(atim.c_tv_sec) + 1E-9 * int(atim.c_tv_nsec)
  301. mtim = st.c_st_mtim; mtime = int(mtim.c_tv_sec) + 1E-9 * int(mtim.c_tv_nsec)
  302. ctim = st.c_st_ctim; ctime = int(ctim.c_tv_sec) + 1E-9 * int(ctim.c_tv_nsec)
  303. else:
  304. atime = st.c_st_atime
  305. mtime = st.c_st_mtime
  306. ctime = st.c_st_ctime
  307. result = (st.c_st_mode,
  308. st.c_st_ino,
  309. st.c_st_dev,
  310. st.c_st_nlink,
  311. st.c_st_uid,
  312. st.c_st_gid,
  313. st.c_st_size,
  314. atime,
  315. mtime,
  316. ctime)
  317. if "st_blksize" in STAT_FIELD_TYPES: result += (st.c_st_blksize,)
  318. if "st_blocks" in STAT_FIELD_TYPES: result += (st.c_st_blocks,)
  319. if "st_rdev" in STAT_FIELD_TYPES: result += (st.c_st_rdev,)
  320. if "st_flags" in STAT_FIELD_TYPES: result += (st.c_st_flags,)
  321. return make_stat_result(result)
  322. def build_statvfs_result(st):
  323. return make_statvfs_result((
  324. st.c_f_bsize,
  325. st.c_f_frsize,
  326. st.c_f_blocks,
  327. st.c_f_bfree,
  328. st.c_f_bavail,
  329. st.c_f_files,
  330. st.c_f_ffree,
  331. st.c_f_favail,
  332. st.c_f_flag,
  333. st.c_f_namemax
  334. ))
  335. # Implement and register os.stat() & variants
  336. if not _WIN32:
  337. c_fstat = rffi.llexternal('fstat64' if _LINUX else 'fstat',
  338. [rffi.INT, STAT_STRUCT], rffi.INT,
  339. compilation_info=compilation_info,
  340. save_err=rffi.RFFI_SAVE_ERRNO,
  341. macro=True)
  342. c_stat = rffi.llexternal('stat64' if _LINUX else 'stat',
  343. [rffi.CCHARP, STAT_STRUCT], rffi.INT,
  344. compilation_info=compilation_info,
  345. save_err=rffi.RFFI_SAVE_ERRNO,
  346. macro=True)
  347. c_lstat = rffi.llexternal('lstat64' if _LINUX else 'lstat',
  348. [rffi.CCHARP, STAT_STRUCT], rffi.INT,
  349. compilation_info=compilation_info,
  350. save_err=rffi.RFFI_SAVE_ERRNO,
  351. macro=True)
  352. c_fstatvfs = rffi.llexternal('fstatvfs',
  353. [rffi.INT, STATVFS_STRUCT], rffi.INT,
  354. compilation_info=compilation_info,
  355. save_err=rffi.RFFI_SAVE_ERRNO)
  356. c_statvfs = rffi.llexternal('statvfs',
  357. [rffi.CCHARP, STATVFS_STRUCT], rffi.INT,
  358. compilation_info=compilation_info,
  359. save_err=rffi.RFFI_SAVE_ERRNO)
  360. @replace_os_function('fstat')
  361. def fstat(fd):
  362. if not _WIN32:
  363. with lltype.scoped_alloc(STAT_STRUCT.TO) as stresult:
  364. handle_posix_error('fstat', c_fstat(fd, stresult))
  365. return build_stat_result(stresult)
  366. else:
  367. handle = rwin32.get_osfhandle(fd)
  368. win32traits = make_win32_traits(string_traits)
  369. filetype = win32traits.GetFileType(handle)
  370. if filetype == win32traits.FILE_TYPE_CHAR:
  371. # console or LPT device
  372. return make_stat_result((win32traits._S_IFCHR,
  373. 0, 0, 0, 0, 0,
  374. 0, 0, 0, 0))
  375. elif filetype == win32traits.FILE_TYPE_PIPE:
  376. # socket or named pipe
  377. return make_stat_result((win32traits._S_IFIFO,
  378. 0, 0, 0, 0, 0,
  379. 0, 0, 0, 0))
  380. elif filetype == win32traits.FILE_TYPE_UNKNOWN:
  381. error = rwin32.GetLastError_saved()
  382. if error != 0:
  383. raise WindowsError(error, "os_fstat failed")
  384. # else: unknown but valid file
  385. # normal disk file (FILE_TYPE_DISK)
  386. info = lltype.malloc(win32traits.BY_HANDLE_FILE_INFORMATION,
  387. flavor='raw', zero=True)
  388. try:
  389. res = win32traits.GetFileInformationByHandle(handle, info)
  390. if res == 0:
  391. raise WindowsError(rwin32.GetLastError_saved(),
  392. "os_fstat failed")
  393. return win32_by_handle_info_to_stat(win32traits, info)
  394. finally:
  395. lltype.free(info, flavor='raw')
  396. @replace_os_function('stat')
  397. @specialize.argtype(0)
  398. def stat(path):
  399. if not _WIN32:
  400. with lltype.scoped_alloc(STAT_STRUCT.TO) as stresult:
  401. arg = _as_bytes0(path)
  402. handle_posix_error('stat', c_stat(arg, stresult))
  403. return build_stat_result(stresult)
  404. else:
  405. traits = _preferred_traits(path)
  406. path = traits.as_str0(path)
  407. return win32_xstat(traits, path, traverse=True)
  408. @replace_os_function('lstat')
  409. @specialize.argtype(0)
  410. def lstat(path):
  411. if not _WIN32:
  412. with lltype.scoped_alloc(STAT_STRUCT.TO) as stresult:
  413. arg = _as_bytes0(path)
  414. handle_posix_error('lstat', c_lstat(arg, stresult))
  415. return build_stat_result(stresult)
  416. else:
  417. traits = _preferred_traits(path)
  418. path = traits.as_str0(path)
  419. return win32_xstat(traits, path, traverse=False)
  420. if rposix.HAVE_FSTATAT:
  421. from rpython.rlib.rposix import AT_FDCWD, AT_SYMLINK_NOFOLLOW
  422. c_fstatat = rffi.llexternal('fstatat',
  423. [rffi.INT, rffi.CCHARP, STAT_STRUCT, rffi.INT], rffi.INT,
  424. compilation_info=compilation_info,
  425. save_err=rffi.RFFI_SAVE_ERRNO, macro=True)
  426. def fstatat(pathname, dir_fd=AT_FDCWD, follow_symlinks=True):
  427. if follow_symlinks:
  428. flags = 0
  429. else:
  430. flags = AT_SYMLINK_NOFOLLOW
  431. with lltype.scoped_alloc(STAT_STRUCT.TO) as stresult:
  432. error = c_fstatat(dir_fd, pathname, stresult, flags)
  433. handle_posix_error('fstatat', error)
  434. return build_stat_result(stresult)
  435. @replace_os_function('fstatvfs')
  436. def fstatvfs(fd):
  437. with lltype.scoped_alloc(STATVFS_STRUCT.TO) as stresult:
  438. handle_posix_error('fstatvfs', c_fstatvfs(fd, stresult))
  439. return build_statvfs_result(stresult)
  440. @replace_os_function('statvfs')
  441. @specialize.argtype(0)
  442. def statvfs(path):
  443. with lltype.scoped_alloc(STATVFS_STRUCT.TO) as stresult:
  444. arg = _as_bytes0(path)
  445. handle_posix_error('statvfs', c_statvfs(arg, stresult))
  446. return build_statvfs_result(stresult)
  447. #__________________________________________________
  448. # Helper functions for win32
  449. if _WIN32:
  450. from rpython.rlib.rwin32file import FILE_TIME_to_time_t_float
  451. def make_longlong(high, low):
  452. return (rffi.r_longlong(high) << 32) + rffi.r_longlong(low)
  453. # Seconds between 1.1.1601 and 1.1.1970
  454. secs_between_epochs = rffi.r_longlong(11644473600)
  455. @specialize.arg(0)
  456. def win32_xstat(traits, path, traverse=False):
  457. win32traits = make_win32_traits(traits)
  458. with lltype.scoped_alloc(
  459. win32traits.WIN32_FILE_ATTRIBUTE_DATA) as data:
  460. res = win32traits.GetFileAttributesEx(
  461. path, win32traits.GetFileExInfoStandard, data)
  462. if res == 0:
  463. errcode = rwin32.GetLastError_saved()
  464. if errcode == win32traits.ERROR_SHARING_VIOLATION:
  465. res = win32_attributes_from_dir(
  466. win32traits, path, data)
  467. if res == 0:
  468. errcode = rwin32.GetLastError_saved()
  469. raise WindowsError(errcode, "os_stat failed")
  470. return win32_attribute_data_to_stat(win32traits, data)
  471. @specialize.arg(0)
  472. def win32_attributes_to_mode(win32traits, attributes):
  473. m = 0
  474. attributes = intmask(attributes)
  475. if attributes & win32traits.FILE_ATTRIBUTE_DIRECTORY:
  476. m |= win32traits._S_IFDIR | 0111 # IFEXEC for user,group,other
  477. else:
  478. m |= win32traits._S_IFREG
  479. if attributes & win32traits.FILE_ATTRIBUTE_READONLY:
  480. m |= 0444
  481. else:
  482. m |= 0666
  483. return m
  484. @specialize.arg(0)
  485. def win32_attribute_data_to_stat(win32traits, info):
  486. st_mode = win32_attributes_to_mode(win32traits, info.c_dwFileAttributes)
  487. st_size = make_longlong(info.c_nFileSizeHigh, info.c_nFileSizeLow)
  488. ctime = FILE_TIME_to_time_t_float(info.c_ftCreationTime)
  489. mtime = FILE_TIME_to_time_t_float(info.c_ftLastWriteTime)
  490. atime = FILE_TIME_to_time_t_float(info.c_ftLastAccessTime)
  491. result = (st_mode,
  492. 0, 0, 0, 0, 0,
  493. st_size,
  494. atime, mtime, ctime)
  495. return make_stat_result(result)
  496. def win32_by_handle_info_to_stat(win32traits, info):
  497. # similar to the one above
  498. st_mode = win32_attributes_to_mode(win32traits, info.c_dwFileAttributes)
  499. st_size = make_longlong(info.c_nFileSizeHigh, info.c_nFileSizeLow)
  500. ctime = FILE_TIME_to_time_t_float(info.c_ftCreationTime)
  501. mtime = FILE_TIME_to_time_t_float(info.c_ftLastWriteTime)
  502. atime = FILE_TIME_to_time_t_float(info.c_ftLastAccessTime)
  503. # specific to fstat()
  504. st_ino = make_longlong(info.c_nFileIndexHigh, info.c_nFileIndexLow)
  505. st_nlink = info.c_nNumberOfLinks
  506. result = (st_mode,
  507. st_ino, 0, st_nlink, 0, 0,
  508. st_size,
  509. atime, mtime, ctime)
  510. return make_stat_result(result)
  511. @specialize.arg(0)
  512. def win32_attributes_from_dir(win32traits, path, data):
  513. filedata = lltype.malloc(win32traits.WIN32_FIND_DATA, flavor='raw')
  514. try:
  515. hFindFile = win32traits.FindFirstFile(path, filedata)
  516. if hFindFile == rwin32.INVALID_HANDLE_VALUE:
  517. return 0
  518. win32traits.FindClose(hFindFile)
  519. data.c_dwFileAttributes = filedata.c_dwFileAttributes
  520. rffi.structcopy(data.c_ftCreationTime, filedata.c_ftCreationTime)
  521. rffi.structcopy(data.c_ftLastAccessTime, filedata.c_ftLastAccessTime)
  522. rffi.structcopy(data.c_ftLastWriteTime, filedata.c_ftLastWriteTime)
  523. data.c_nFileSizeHigh = filedata.c_nFileSizeHigh
  524. data.c_nFileSizeLow = filedata.c_nFileSizeLow
  525. return 1
  526. finally:
  527. lltype.free(filedata, flavor='raw')