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

/pypy/rpython/module/ll_win32file.py

https://bitbucket.org/pypy/pypy/
Python | 415 lines | 362 code | 12 blank | 41 comment | 9 complexity | 98efb9700838f7cc1325e766b1bb4db6 MD5 | raw file
Possible License(s): AGPL-3.0, BSD-3-Clause, Apache-2.0
  1. """
  2. The Windows implementation of some posix modules,
  3. based on the Win32 API.
  4. """
  5. from __future__ import with_statement
  6. from pypy.rpython.lltypesystem import lltype, rffi
  7. from pypy.translator.tool.cbuild import ExternalCompilationInfo
  8. from pypy.rpython.tool import rffi_platform as platform
  9. from pypy.tool.sourcetools import func_renamer
  10. from pypy.rlib.objectmodel import specialize
  11. def make_win32_traits(traits):
  12. from pypy.rlib import rwin32
  13. if traits.str is unicode:
  14. suffix = 'W'
  15. else:
  16. suffix = 'A'
  17. class CConfig:
  18. _compilation_info_ = ExternalCompilationInfo(
  19. includes = ['windows.h', 'winbase.h', 'sys/stat.h'],
  20. )
  21. WIN32_FIND_DATA = platform.Struct(
  22. 'struct _WIN32_FIND_DATA' + suffix,
  23. # Only interesting fields
  24. [('dwFileAttributes', rwin32.DWORD),
  25. ('nFileSizeHigh', rwin32.DWORD),
  26. ('nFileSizeLow', rwin32.DWORD),
  27. ('ftCreationTime', rwin32.FILETIME),
  28. ('ftLastAccessTime', rwin32.FILETIME),
  29. ('ftLastWriteTime', rwin32.FILETIME),
  30. ('cFileName', lltype.FixedSizeArray(traits.CHAR, 250))])
  31. ERROR_FILE_NOT_FOUND = platform.ConstantInteger(
  32. 'ERROR_FILE_NOT_FOUND')
  33. ERROR_NO_MORE_FILES = platform.ConstantInteger(
  34. 'ERROR_NO_MORE_FILES')
  35. GetFileExInfoStandard = platform.ConstantInteger(
  36. 'GetFileExInfoStandard')
  37. FILE_ATTRIBUTE_DIRECTORY = platform.ConstantInteger(
  38. 'FILE_ATTRIBUTE_DIRECTORY')
  39. FILE_ATTRIBUTE_READONLY = platform.ConstantInteger(
  40. 'FILE_ATTRIBUTE_READONLY')
  41. INVALID_FILE_ATTRIBUTES = platform.ConstantInteger(
  42. 'INVALID_FILE_ATTRIBUTES')
  43. ERROR_SHARING_VIOLATION = platform.ConstantInteger(
  44. 'ERROR_SHARING_VIOLATION')
  45. _S_IFDIR = platform.ConstantInteger('_S_IFDIR')
  46. _S_IFREG = platform.ConstantInteger('_S_IFREG')
  47. _S_IFCHR = platform.ConstantInteger('_S_IFCHR')
  48. _S_IFIFO = platform.ConstantInteger('_S_IFIFO')
  49. FILE_TYPE_UNKNOWN = platform.ConstantInteger('FILE_TYPE_UNKNOWN')
  50. FILE_TYPE_CHAR = platform.ConstantInteger('FILE_TYPE_CHAR')
  51. FILE_TYPE_PIPE = platform.ConstantInteger('FILE_TYPE_PIPE')
  52. WIN32_FILE_ATTRIBUTE_DATA = platform.Struct(
  53. 'WIN32_FILE_ATTRIBUTE_DATA',
  54. [('dwFileAttributes', rwin32.DWORD),
  55. ('nFileSizeHigh', rwin32.DWORD),
  56. ('nFileSizeLow', rwin32.DWORD),
  57. ('ftCreationTime', rwin32.FILETIME),
  58. ('ftLastAccessTime', rwin32.FILETIME),
  59. ('ftLastWriteTime', rwin32.FILETIME)])
  60. BY_HANDLE_FILE_INFORMATION = platform.Struct(
  61. 'BY_HANDLE_FILE_INFORMATION',
  62. [('dwFileAttributes', rwin32.DWORD),
  63. ('nFileSizeHigh', rwin32.DWORD),
  64. ('nFileSizeLow', rwin32.DWORD),
  65. ('nNumberOfLinks', rwin32.DWORD),
  66. ('nFileIndexHigh', rwin32.DWORD),
  67. ('nFileIndexLow', rwin32.DWORD),
  68. ('ftCreationTime', rwin32.FILETIME),
  69. ('ftLastAccessTime', rwin32.FILETIME),
  70. ('ftLastWriteTime', rwin32.FILETIME)])
  71. config = platform.configure(CConfig)
  72. def external(*args, **kwargs):
  73. kwargs['compilation_info'] = CConfig._compilation_info_
  74. llfunc = rffi.llexternal(calling_conv='win', *args, **kwargs)
  75. return staticmethod(llfunc)
  76. class Win32Traits:
  77. apisuffix = suffix
  78. for name in '''WIN32_FIND_DATA WIN32_FILE_ATTRIBUTE_DATA BY_HANDLE_FILE_INFORMATION
  79. GetFileExInfoStandard
  80. FILE_ATTRIBUTE_DIRECTORY FILE_ATTRIBUTE_READONLY
  81. INVALID_FILE_ATTRIBUTES
  82. _S_IFDIR _S_IFREG _S_IFCHR _S_IFIFO
  83. FILE_TYPE_UNKNOWN FILE_TYPE_CHAR FILE_TYPE_PIPE
  84. ERROR_FILE_NOT_FOUND ERROR_NO_MORE_FILES
  85. ERROR_SHARING_VIOLATION
  86. '''.split():
  87. locals()[name] = config[name]
  88. LPWIN32_FIND_DATA = lltype.Ptr(WIN32_FIND_DATA)
  89. GET_FILEEX_INFO_LEVELS = rffi.ULONG # an enumeration
  90. FindFirstFile = external('FindFirstFile' + suffix,
  91. [traits.CCHARP, LPWIN32_FIND_DATA],
  92. rwin32.HANDLE)
  93. FindNextFile = external('FindNextFile' + suffix,
  94. [rwin32.HANDLE, LPWIN32_FIND_DATA],
  95. rwin32.BOOL)
  96. FindClose = external('FindClose',
  97. [rwin32.HANDLE],
  98. rwin32.BOOL)
  99. GetFileAttributes = external(
  100. 'GetFileAttributes' + suffix,
  101. [traits.CCHARP],
  102. rwin32.DWORD)
  103. SetFileAttributes = external(
  104. 'SetFileAttributes' + suffix,
  105. [traits.CCHARP, rwin32.DWORD],
  106. rwin32.BOOL)
  107. GetFileAttributesEx = external(
  108. 'GetFileAttributesEx' + suffix,
  109. [traits.CCHARP, GET_FILEEX_INFO_LEVELS,
  110. lltype.Ptr(WIN32_FILE_ATTRIBUTE_DATA)],
  111. rwin32.BOOL)
  112. GetFileInformationByHandle = external(
  113. 'GetFileInformationByHandle',
  114. [rwin32.HANDLE, lltype.Ptr(BY_HANDLE_FILE_INFORMATION)],
  115. rwin32.BOOL)
  116. GetFileType = external(
  117. 'GetFileType',
  118. [rwin32.HANDLE],
  119. rwin32.DWORD)
  120. LPSTRP = rffi.CArrayPtr(traits.CCHARP)
  121. GetFullPathName = external(
  122. 'GetFullPathName' + suffix,
  123. [traits.CCHARP, rwin32.DWORD,
  124. traits.CCHARP, LPSTRP],
  125. rwin32.DWORD)
  126. GetCurrentDirectory = external(
  127. 'GetCurrentDirectory' + suffix,
  128. [rwin32.DWORD, traits.CCHARP],
  129. rwin32.DWORD)
  130. SetCurrentDirectory = external(
  131. 'SetCurrentDirectory' + suffix,
  132. [traits.CCHARP],
  133. rwin32.BOOL)
  134. CreateDirectory = external(
  135. 'CreateDirectory' + suffix,
  136. [traits.CCHARP, rffi.VOIDP],
  137. rwin32.BOOL)
  138. SetEnvironmentVariable = external(
  139. 'SetEnvironmentVariable' + suffix,
  140. [traits.CCHARP, traits.CCHARP],
  141. rwin32.BOOL)
  142. DeleteFile = external(
  143. 'DeleteFile' + suffix,
  144. [traits.CCHARP],
  145. rwin32.BOOL)
  146. MoveFile = external(
  147. 'MoveFile' + suffix,
  148. [traits.CCHARP, traits.CCHARP],
  149. rwin32.BOOL)
  150. return Win32Traits
  151. #_______________________________________________________________
  152. # listdir
  153. def make_listdir_impl(traits):
  154. from pypy.rlib import rwin32
  155. win32traits = make_win32_traits(traits)
  156. if traits.str is unicode:
  157. def make_listdir_mask(path):
  158. if path and path[-1] not in (u'/', u'\\', u':'):
  159. path += u'/'
  160. return path + u'*.*'
  161. def skip_listdir(name):
  162. return name == u"." or name == u".."
  163. else:
  164. def make_listdir_mask(path):
  165. if path and path[-1] not in ('/', '\\', ':'):
  166. path += '/'
  167. return path + '*.*'
  168. def skip_listdir(name):
  169. return name == "." or name == ".."
  170. @func_renamer('listdir_llimpl_%s' % traits.str.__name__)
  171. def listdir_llimpl(path):
  172. mask = make_listdir_mask(path)
  173. filedata = lltype.malloc(win32traits.WIN32_FIND_DATA, flavor='raw')
  174. try:
  175. result = []
  176. hFindFile = win32traits.FindFirstFile(mask, filedata)
  177. if hFindFile == rwin32.INVALID_HANDLE_VALUE:
  178. error = rwin32.GetLastError()
  179. if error == win32traits.ERROR_FILE_NOT_FOUND:
  180. return result
  181. else:
  182. raise WindowsError(error, "FindFirstFile failed")
  183. while True:
  184. name = traits.charp2str(rffi.cast(traits.CCHARP,
  185. filedata.c_cFileName))
  186. if not skip_listdir(name):
  187. result.append(name)
  188. if not win32traits.FindNextFile(hFindFile, filedata):
  189. break
  190. # FindNextFile sets error to ERROR_NO_MORE_FILES if
  191. # it got to the end of the directory
  192. error = rwin32.GetLastError()
  193. win32traits.FindClose(hFindFile)
  194. if error == win32traits.ERROR_NO_MORE_FILES:
  195. return result
  196. else:
  197. raise WindowsError(error, "FindNextFile failed")
  198. finally:
  199. lltype.free(filedata, flavor='raw')
  200. return listdir_llimpl
  201. #_______________________________________________________________
  202. # chdir
  203. def make_chdir_impl(traits):
  204. from pypy.rlib import rwin32
  205. win32traits = make_win32_traits(traits)
  206. if traits.str is unicode:
  207. def isUNC(path):
  208. return path[0] == u'\\' or path[0] == u'/'
  209. def magic_envvar(path):
  210. return u'=' + path[0] + u':'
  211. else:
  212. def isUNC(path):
  213. return path[0] == '\\' or path[0] == '/'
  214. def magic_envvar(path):
  215. return '=' + path[0] + ':'
  216. @func_renamer('chdir_llimpl_%s' % traits.str.__name__)
  217. def chdir_llimpl(path):
  218. """This is a reimplementation of the C library's chdir function,
  219. but one that produces Win32 errors instead of DOS error codes.
  220. chdir is essentially a wrapper around SetCurrentDirectory; however,
  221. it also needs to set "magic" environment variables indicating
  222. the per-drive current directory, which are of the form =<drive>:
  223. """
  224. if not win32traits.SetCurrentDirectory(path):
  225. raise rwin32.lastWindowsError()
  226. MAX_PATH = rwin32.MAX_PATH
  227. assert MAX_PATH > 0
  228. with traits.scoped_alloc_buffer(MAX_PATH) as path:
  229. res = win32traits.GetCurrentDirectory(MAX_PATH + 1, path.raw)
  230. if not res:
  231. raise rwin32.lastWindowsError()
  232. res = rffi.cast(lltype.Signed, res)
  233. assert res > 0
  234. if res <= MAX_PATH + 1:
  235. new_path = path.str(res)
  236. else:
  237. with traits.scoped_alloc_buffer(res) as path:
  238. res = win32traits.GetCurrentDirectory(res, path.raw)
  239. if not res:
  240. raise rwin32.lastWindowsError()
  241. res = rffi.cast(lltype.Signed, res)
  242. assert res > 0
  243. new_path = path.str(res)
  244. if isUNC(new_path):
  245. return
  246. if not win32traits.SetEnvironmentVariable(magic_envvar(new_path), new_path):
  247. raise rwin32.lastWindowsError()
  248. return chdir_llimpl
  249. #_______________________________________________________________
  250. # chmod
  251. def make_chmod_impl(traits):
  252. from pypy.rlib import rwin32
  253. win32traits = make_win32_traits(traits)
  254. @func_renamer('chmod_llimpl_%s' % traits.str.__name__)
  255. def chmod_llimpl(path, mode):
  256. attr = win32traits.GetFileAttributes(path)
  257. if attr == win32traits.INVALID_FILE_ATTRIBUTES:
  258. raise rwin32.lastWindowsError()
  259. if mode & 0200: # _S_IWRITE
  260. attr &= ~win32traits.FILE_ATTRIBUTE_READONLY
  261. else:
  262. attr |= win32traits.FILE_ATTRIBUTE_READONLY
  263. if not win32traits.SetFileAttributes(path, attr):
  264. raise rwin32.lastWindowsError()
  265. return chmod_llimpl
  266. #_______________________________________________________________
  267. # getfullpathname
  268. def make_getfullpathname_impl(traits):
  269. from pypy.rlib import rwin32
  270. win32traits = make_win32_traits(traits)
  271. @func_renamer('getfullpathname_llimpl_%s' % traits.str.__name__)
  272. def getfullpathname_llimpl(path):
  273. nBufferLength = rwin32.MAX_PATH + 1
  274. lpBuffer = lltype.malloc(traits.CCHARP.TO, nBufferLength, flavor='raw')
  275. try:
  276. res = win32traits.GetFullPathName(
  277. path, rffi.cast(rwin32.DWORD, nBufferLength),
  278. lpBuffer, lltype.nullptr(win32traits.LPSTRP.TO))
  279. if res == 0:
  280. raise rwin32.lastWindowsError("_getfullpathname failed")
  281. result = traits.charp2str(lpBuffer)
  282. return result
  283. finally:
  284. lltype.free(lpBuffer, flavor='raw')
  285. return getfullpathname_llimpl
  286. def make_utime_impl(traits):
  287. from pypy.rlib import rwin32
  288. win32traits = make_win32_traits(traits)
  289. from pypy.rpython.module.ll_os_stat import time_t_to_FILE_TIME
  290. class CConfig:
  291. _compilation_info_ = ExternalCompilationInfo(
  292. includes = ['windows.h'],
  293. )
  294. FILE_WRITE_ATTRIBUTES = platform.ConstantInteger(
  295. 'FILE_WRITE_ATTRIBUTES')
  296. OPEN_EXISTING = platform.ConstantInteger(
  297. 'OPEN_EXISTING')
  298. FILE_FLAG_BACKUP_SEMANTICS = platform.ConstantInteger(
  299. 'FILE_FLAG_BACKUP_SEMANTICS')
  300. globals().update(platform.configure(CConfig))
  301. CreateFile = rffi.llexternal(
  302. 'CreateFile' + win32traits.apisuffix,
  303. [traits.CCHARP, rwin32.DWORD, rwin32.DWORD,
  304. rwin32.LPSECURITY_ATTRIBUTES, rwin32.DWORD, rwin32.DWORD,
  305. rwin32.HANDLE],
  306. rwin32.HANDLE,
  307. calling_conv='win')
  308. GetSystemTime = rffi.llexternal(
  309. 'GetSystemTime',
  310. [lltype.Ptr(rwin32.SYSTEMTIME)],
  311. lltype.Void,
  312. calling_conv='win')
  313. SystemTimeToFileTime = rffi.llexternal(
  314. 'SystemTimeToFileTime',
  315. [lltype.Ptr(rwin32.SYSTEMTIME),
  316. lltype.Ptr(rwin32.FILETIME)],
  317. rwin32.BOOL,
  318. calling_conv='win')
  319. SetFileTime = rffi.llexternal(
  320. 'SetFileTime',
  321. [rwin32.HANDLE,
  322. lltype.Ptr(rwin32.FILETIME),
  323. lltype.Ptr(rwin32.FILETIME),
  324. lltype.Ptr(rwin32.FILETIME)],
  325. rwin32.BOOL,
  326. calling_conv = 'win')
  327. @specialize.argtype(1)
  328. def os_utime_llimpl(path, tp):
  329. hFile = CreateFile(path,
  330. FILE_WRITE_ATTRIBUTES, 0,
  331. None, OPEN_EXISTING,
  332. FILE_FLAG_BACKUP_SEMANTICS,
  333. rwin32.NULL_HANDLE)
  334. if hFile == rwin32.INVALID_HANDLE_VALUE:
  335. raise rwin32.lastWindowsError()
  336. ctime = lltype.nullptr(rwin32.FILETIME)
  337. atime = lltype.malloc(rwin32.FILETIME, flavor='raw')
  338. mtime = lltype.malloc(rwin32.FILETIME, flavor='raw')
  339. try:
  340. if tp is None:
  341. now = lltype.malloc(rwin32.SYSTEMTIME, flavor='raw')
  342. try:
  343. GetSystemTime(now)
  344. if (not SystemTimeToFileTime(now, atime) or
  345. not SystemTimeToFileTime(now, mtime)):
  346. raise rwin32.lastWindowsError()
  347. finally:
  348. lltype.free(now, flavor='raw')
  349. else:
  350. actime, modtime = tp
  351. time_t_to_FILE_TIME(actime, atime)
  352. time_t_to_FILE_TIME(modtime, mtime)
  353. if not SetFileTime(hFile, ctime, atime, mtime):
  354. raise rwin32.lastWindowsError()
  355. finally:
  356. rwin32.CloseHandle(hFile)
  357. lltype.free(atime, flavor='raw')
  358. lltype.free(mtime, flavor='raw')
  359. return os_utime_llimpl