Show More
@@ -8,8 +8,6 b'' | |||||
8 | import os |
|
8 | import os | |
9 | import stat as statmod |
|
9 | import stat as statmod | |
10 |
|
10 | |||
11 | posixfile = open |
|
|||
12 |
|
||||
13 | def _mode_to_kind(mode): |
|
11 | def _mode_to_kind(mode): | |
14 | if statmod.S_ISREG(mode): |
|
12 | if statmod.S_ISREG(mode): | |
15 | return statmod.S_IFREG |
|
13 | return statmod.S_IFREG | |
@@ -57,3 +55,131 b' def listdir(path, stat=False, skip=None)' | |||||
57 | result.append((fn, _mode_to_kind(st.st_mode))) |
|
55 | result.append((fn, _mode_to_kind(st.st_mode))) | |
58 | return result |
|
56 | return result | |
59 |
|
57 | |||
|
58 | if os.name != 'nt': | |||
|
59 | posixfile = open | |||
|
60 | else: | |||
|
61 | import ctypes, ctypes.util | |||
|
62 | ||||
|
63 | _kernel32 = ctypes.windll.kernel32 | |||
|
64 | ||||
|
65 | _DWORD = ctypes.c_ulong | |||
|
66 | _LPCSTR = _LPSTR = ctypes.c_char_p | |||
|
67 | _HANDLE = ctypes.c_void_p | |||
|
68 | ||||
|
69 | _INVALID_HANDLE_VALUE = _HANDLE(-1).value | |||
|
70 | ||||
|
71 | def _crtname(): | |||
|
72 | try: | |||
|
73 | # find_msvcrt was introduced in Python 2.6 | |||
|
74 | return ctypes.util.find_msvcrt() | |||
|
75 | except AttributeError: | |||
|
76 | return 'msvcr80.dll' # CPython 2.5 | |||
|
77 | ||||
|
78 | _crt = ctypes.PyDLL(_crtname()) | |||
|
79 | ||||
|
80 | # CreateFile | |||
|
81 | _FILE_SHARE_READ = 0x00000001 | |||
|
82 | _FILE_SHARE_WRITE = 0x00000002 | |||
|
83 | _FILE_SHARE_DELETE = 0x00000004 | |||
|
84 | ||||
|
85 | _CREATE_ALWAYS = 2 | |||
|
86 | _OPEN_EXISTING = 3 | |||
|
87 | _OPEN_ALWAYS = 4 | |||
|
88 | ||||
|
89 | _GENERIC_READ = 0x80000000 | |||
|
90 | _GENERIC_WRITE = 0x40000000 | |||
|
91 | ||||
|
92 | _FILE_ATTRIBUTE_NORMAL = 0x80 | |||
|
93 | ||||
|
94 | # _open_osfhandle | |||
|
95 | _O_RDONLY = 0x0000 | |||
|
96 | _O_RDWR = 0x0002 | |||
|
97 | _O_APPEND = 0x0008 | |||
|
98 | ||||
|
99 | _O_TEXT = 0x4000 | |||
|
100 | _O_BINARY = 0x8000 | |||
|
101 | ||||
|
102 | # types of parameters of C functions used (required by pypy) | |||
|
103 | ||||
|
104 | _kernel32.CreateFileA.argtypes = [_LPCSTR, _DWORD, _DWORD, ctypes.c_void_p, | |||
|
105 | _DWORD, _DWORD, _HANDLE] | |||
|
106 | _kernel32.CreateFileA.restype = _HANDLE | |||
|
107 | ||||
|
108 | _crt._open_osfhandle.argtypes = [_HANDLE, ctypes.c_int] | |||
|
109 | _crt._open_osfhandle.restype = ctypes.c_int | |||
|
110 | ||||
|
111 | def _raiseioerror(name): | |||
|
112 | err = ctypes.WinError() | |||
|
113 | raise IOError(err.errno, '%s: %s' % (name, err.strerror)) | |||
|
114 | ||||
|
115 | class posixfile(object): | |||
|
116 | '''a file object aiming for POSIX-like semantics | |||
|
117 | ||||
|
118 | CPython's open() returns a file that was opened *without* setting the | |||
|
119 | _FILE_SHARE_DELETE flag, which causes rename and unlink to abort. | |||
|
120 | This even happens if any hardlinked copy of the file is in open state. | |||
|
121 | We set _FILE_SHARE_DELETE here, so files opened with posixfile can be | |||
|
122 | renamed and deleted while they are held open. | |||
|
123 | Note that if a file opened with posixfile is unlinked, the file | |||
|
124 | remains but cannot be opened again or be recreated under the same name, | |||
|
125 | until all reading processes have closed the file.''' | |||
|
126 | ||||
|
127 | def __init__(self, name, mode='r', bufsize=-1): | |||
|
128 | if 'b' in mode: | |||
|
129 | flags = _O_BINARY | |||
|
130 | else: | |||
|
131 | flags = _O_TEXT | |||
|
132 | ||||
|
133 | m0 = mode[0] | |||
|
134 | if m0 == 'r' and not '+' in mode: | |||
|
135 | flags |= _O_RDONLY | |||
|
136 | access = _GENERIC_READ | |||
|
137 | else: | |||
|
138 | # work around http://support.microsoft.com/kb/899149 and | |||
|
139 | # set _O_RDWR for 'w' and 'a', even if mode has no '+' | |||
|
140 | flags |= _O_RDWR | |||
|
141 | access = _GENERIC_READ | _GENERIC_WRITE | |||
|
142 | ||||
|
143 | if m0 == 'r': | |||
|
144 | creation = _OPEN_EXISTING | |||
|
145 | elif m0 == 'w': | |||
|
146 | creation = _CREATE_ALWAYS | |||
|
147 | elif m0 == 'a': | |||
|
148 | creation = _OPEN_ALWAYS | |||
|
149 | flags |= _O_APPEND | |||
|
150 | else: | |||
|
151 | raise ValueError("invalid mode: %s" % mode) | |||
|
152 | ||||
|
153 | fh = _kernel32.CreateFileA(name, access, | |||
|
154 | _FILE_SHARE_READ | _FILE_SHARE_WRITE | _FILE_SHARE_DELETE, | |||
|
155 | None, creation, _FILE_ATTRIBUTE_NORMAL, None) | |||
|
156 | if fh == _INVALID_HANDLE_VALUE: | |||
|
157 | _raiseioerror(name) | |||
|
158 | ||||
|
159 | # for CPython we must use the same CRT as Python uses, | |||
|
160 | # or the os.fdopen call below will abort with | |||
|
161 | # "OSError: [Errno 9] Bad file descriptor" | |||
|
162 | fd = _crt._open_osfhandle(fh, flags) | |||
|
163 | if fd == -1: | |||
|
164 | _kernel32.CloseHandle(fh) | |||
|
165 | _raiseioerror(name) | |||
|
166 | ||||
|
167 | f = os.fdopen(fd, mode, bufsize) | |||
|
168 | # unfortunately, f.name is '<fdopen>' at this point -- so we store | |||
|
169 | # the name on this wrapper. We cannot just assign to f.name, | |||
|
170 | # because that attribute is read-only. | |||
|
171 | object.__setattr__(self, 'name', name) | |||
|
172 | object.__setattr__(self, '_file', f) | |||
|
173 | ||||
|
174 | def __iter__(self): | |||
|
175 | return self._file | |||
|
176 | ||||
|
177 | def __getattr__(self, name): | |||
|
178 | return getattr(self._file, name) | |||
|
179 | ||||
|
180 | def __setattr__(self, name, value): | |||
|
181 | '''mimics the read-only attributes of Python file objects | |||
|
182 | by raising 'TypeError: readonly attribute' if someone tries: | |||
|
183 | f = posixfile('foo.txt') | |||
|
184 | f.name = 'bla' ''' | |||
|
185 | return self._file.__setattr__(name, value) |
General Comments 0
You need to be logged in to leave comments.
Login now