Commit | Line | Data |
---|---|---|
a8c08ecd NIS |
1 | #define PERL_NO_GET_CONTEXT |
2 | #define WIN32_LEAN_AND_MEAN | |
3 | #define WIN32IO_IS_STDIO | |
4 | #include <tchar.h> | |
5 | #ifdef __GNUC__ | |
6 | #define Win32_Winsock | |
7 | #endif | |
8 | #include <windows.h> | |
9 | ||
10 | #include <sys/stat.h> | |
11 | #include "EXTERN.h" | |
12 | #include "perl.h" | |
57143e73 NIS |
13 | |
14 | #ifdef PERLIO_LAYERS | |
15 | ||
0c4128ad | 16 | #include "perliol.h" |
a8c08ecd NIS |
17 | |
18 | #define NO_XSLOCKS | |
19 | #include "XSUB.h" | |
20 | ||
57143e73 | 21 | |
a8c08ecd NIS |
22 | /* Bottom-most level for Win32 case */ |
23 | ||
24 | typedef struct | |
25 | { | |
26 | struct _PerlIO base; /* The generic part */ | |
27 | HANDLE h; /* OS level handle */ | |
28 | IV refcnt; /* REFCNT for the "fd" this represents */ | |
29 | int fd; /* UNIX like file descriptor - index into fdtable */ | |
30 | } PerlIOWin32; | |
31 | ||
32 | PerlIOWin32 *fdtable[256]; | |
33 | IV max_open_fd = -1; | |
34 | ||
35 | IV | |
5833650d | 36 | PerlIOWin32_popped(pTHX_ PerlIO *f) |
a8c08ecd NIS |
37 | { |
38 | PerlIOWin32 *s = PerlIOSelf(f,PerlIOWin32); | |
39 | if (--s->refcnt > 0) | |
40 | { | |
41 | *f = PerlIOBase(f)->next; | |
42 | return 1; | |
43 | } | |
44 | fdtable[s->fd] = NULL; | |
45 | return 0; | |
46 | } | |
47 | ||
48 | IV | |
5833650d | 49 | PerlIOWin32_fileno(pTHX_ PerlIO *f) |
a8c08ecd NIS |
50 | { |
51 | return PerlIOSelf(f,PerlIOWin32)->fd; | |
52 | } | |
53 | ||
54 | IV | |
2dc2558e | 55 | PerlIOWin32_pushed(pTHX_ PerlIO *f, const char *mode, SV *arg, PerlIO_funcs *tab) |
a8c08ecd | 56 | { |
2dc2558e | 57 | IV code = PerlIOBase_pushed(aTHX_ f,mode,arg,tab); |
a8c08ecd NIS |
58 | if (*PerlIONext(f)) |
59 | { | |
60 | PerlIOWin32 *s = PerlIOSelf(f,PerlIOWin32); | |
61 | s->fd = PerlIO_fileno(PerlIONext(f)); | |
62 | } | |
63 | PerlIOBase(f)->flags |= PERLIO_F_OPEN; | |
7ac92924 TC |
64 | |
65 | Perl_ck_warner_d(aTHX_ | |
66 | packWARN(WARN_EXPERIMENTAL__WIN32_PERLIO), | |
67 | "PerlIO layer ':win32' is experimental"); | |
68 | ||
a8c08ecd NIS |
69 | return code; |
70 | } | |
71 | ||
72 | PerlIO * | |
73 | PerlIOWin32_open(pTHX_ PerlIO_funcs *self, PerlIO_list_t *layers, IV n, const char *mode, int fd, int imode, int perm, PerlIO *f, int narg, SV **args) | |
74 | { | |
75 | const char *tmode = mode; | |
76 | HANDLE h = INVALID_HANDLE_VALUE; | |
77 | if (f) | |
78 | { | |
79 | /* Close if already open */ | |
80 | if (PerlIOBase(f)->flags & PERLIO_F_OPEN) | |
5833650d | 81 | (*PerlIOBase(f)->tab->Close)(aTHX_ f); |
a8c08ecd NIS |
82 | } |
83 | if (narg > 0) | |
84 | { | |
85 | char *path = SvPV_nolen(*args); | |
86 | DWORD access = 0; | |
87 | DWORD share = 0; | |
88 | DWORD create = -1; | |
89 | DWORD attr = FILE_ATTRIBUTE_NORMAL; | |
90 | if (*mode == '#') | |
91 | { | |
92 | /* sysopen - imode is UNIX-like O_RDONLY etc. | |
93 | - do_open has converted that back to string form in mode as well | |
94 | - perm is UNIX like permissions | |
95 | */ | |
96 | mode++; | |
97 | } | |
98 | else | |
99 | { | |
100 | /* Normal open - decode mode string */ | |
101 | } | |
102 | switch(*mode) | |
103 | { | |
104 | case 'r': | |
105 | access = GENERIC_READ; | |
106 | create = OPEN_EXISTING; | |
107 | if (*++mode == '+') | |
108 | { | |
109 | access |= GENERIC_WRITE; | |
110 | create = OPEN_ALWAYS; | |
111 | mode++; | |
112 | } | |
113 | break; | |
114 | ||
115 | case 'w': | |
116 | access = GENERIC_WRITE; | |
117 | create = TRUNCATE_EXISTING; | |
118 | if (*++mode == '+') | |
119 | { | |
120 | access |= GENERIC_READ; | |
121 | mode++; | |
122 | } | |
123 | break; | |
124 | ||
125 | case 'a': | |
126 | access = GENERIC_WRITE; | |
127 | create = OPEN_ALWAYS; | |
128 | if (*++mode == '+') | |
129 | { | |
130 | access |= GENERIC_READ; | |
131 | mode++; | |
132 | } | |
133 | break; | |
134 | } | |
135 | if (*mode == 'b') | |
136 | { | |
137 | mode++; | |
138 | } | |
139 | else if (*mode == 't') | |
140 | { | |
141 | mode++; | |
142 | } | |
0c4128ad | 143 | if (*mode || create == -1) |
a8c08ecd NIS |
144 | { |
145 | SETERRNO(EINVAL,LIB$_INVARG); | |
146 | return NULL; | |
147 | } | |
148 | if (!(access & GENERIC_WRITE)) | |
149 | share = FILE_SHARE_READ; | |
150 | h = CreateFile(path,access,share,NULL,create,attr,NULL); | |
151 | if (h == INVALID_HANDLE_VALUE) | |
152 | { | |
153 | if (create == TRUNCATE_EXISTING) | |
0c4128ad | 154 | h = CreateFile(path,access,share,NULL,(create = OPEN_ALWAYS),attr,NULL); |
a8c08ecd NIS |
155 | } |
156 | } | |
157 | else | |
158 | { | |
159 | /* fd open */ | |
160 | h = INVALID_HANDLE_VALUE; | |
161 | if (fd >= 0 && fd <= max_open_fd) | |
162 | { | |
163 | PerlIOWin32 *s = fdtable[fd]; | |
164 | if (s) | |
165 | { | |
166 | s->refcnt++; | |
167 | if (!f) | |
168 | f = PerlIO_allocate(aTHX); | |
169 | *f = &s->base; | |
170 | return f; | |
171 | } | |
0c4128ad NIS |
172 | } |
173 | if (*mode == 'I') | |
174 | { | |
175 | mode++; | |
176 | switch(fd) | |
a8c08ecd | 177 | { |
0c4128ad NIS |
178 | case 0: |
179 | h = GetStdHandle(STD_INPUT_HANDLE); | |
180 | break; | |
181 | case 1: | |
182 | h = GetStdHandle(STD_OUTPUT_HANDLE); | |
183 | break; | |
184 | case 2: | |
185 | h = GetStdHandle(STD_ERROR_HANDLE); | |
186 | break; | |
a8c08ecd NIS |
187 | } |
188 | } | |
189 | } | |
190 | if (h != INVALID_HANDLE_VALUE) | |
c623ac67 | 191 | fd = win32_open_osfhandle((intptr_t) h, PerlIOUnix_oflags(tmode)); |
0c4128ad | 192 | if (fd >= 0) |
a8c08ecd NIS |
193 | { |
194 | PerlIOWin32 *s; | |
195 | if (!f) | |
196 | f = PerlIO_allocate(aTHX); | |
197 | s = PerlIOSelf(PerlIO_push(aTHX_ f,self,tmode,PerlIOArg),PerlIOWin32); | |
0c4128ad NIS |
198 | s->h = h; |
199 | s->fd = fd; | |
a8c08ecd | 200 | s->refcnt = 1; |
8cf8f3d1 | 201 | if (fd >= 0) |
0c4128ad | 202 | { |
8cf8f3d1 | 203 | fdtable[fd] = s; |
0c4128ad NIS |
204 | if (fd > max_open_fd) |
205 | max_open_fd = fd; | |
8cf8f3d1 | 206 | } |
a8c08ecd NIS |
207 | return f; |
208 | } | |
209 | if (f) | |
210 | { | |
211 | /* FIXME: pop layers ??? */ | |
212 | } | |
213 | return NULL; | |
214 | } | |
215 | ||
216 | SSize_t | |
5833650d | 217 | PerlIOWin32_read(pTHX_ PerlIO *f, void *vbuf, Size_t count) |
a8c08ecd NIS |
218 | { |
219 | PerlIOWin32 *s = PerlIOSelf(f,PerlIOWin32); | |
220 | DWORD len; | |
221 | if (!(PerlIOBase(f)->flags & PERLIO_F_CANREAD)) | |
222 | return 0; | |
0c4128ad | 223 | if (ReadFile(s->h,vbuf,count,&len,NULL)) |
a8c08ecd NIS |
224 | { |
225 | return len; | |
226 | } | |
227 | else | |
228 | { | |
229 | if (GetLastError() != NO_ERROR) | |
230 | { | |
231 | PerlIOBase(f)->flags |= PERLIO_F_ERROR; | |
232 | return -1; | |
233 | } | |
234 | else | |
235 | { | |
236 | if (count != 0) | |
237 | PerlIOBase(f)->flags |= PERLIO_F_EOF; | |
238 | return 0; | |
239 | } | |
240 | } | |
241 | } | |
242 | ||
243 | SSize_t | |
5833650d | 244 | PerlIOWin32_write(pTHX_ PerlIO *f, const void *vbuf, Size_t count) |
a8c08ecd NIS |
245 | { |
246 | PerlIOWin32 *s = PerlIOSelf(f,PerlIOWin32); | |
247 | DWORD len; | |
0c4128ad | 248 | if (WriteFile(s->h,vbuf,count,&len,NULL)) |
a8c08ecd NIS |
249 | { |
250 | return len; | |
251 | } | |
252 | else | |
253 | { | |
254 | PerlIOBase(f)->flags |= PERLIO_F_ERROR; | |
255 | return -1; | |
256 | } | |
257 | } | |
258 | ||
259 | IV | |
5833650d | 260 | PerlIOWin32_seek(pTHX_ PerlIO *f, Off_t offset, int whence) |
a8c08ecd NIS |
261 | { |
262 | static const DWORD where[3] = { FILE_BEGIN, FILE_CURRENT, FILE_END }; | |
263 | PerlIOWin32 *s = PerlIOSelf(f,PerlIOWin32); | |
3caf316a SH |
264 | #if Off_t_size >= 8 |
265 | DWORD high = (DWORD)(offset >> 32); | |
266 | #else | |
267 | DWORD high = 0; | |
268 | #endif | |
a8c08ecd | 269 | DWORD low = (DWORD) offset; |
8d3a710f | 270 | DWORD res = SetFilePointer(s->h,(LONG)low,(LONG *)&high,where[whence]); |
a8c08ecd NIS |
271 | if (res != 0xFFFFFFFF || GetLastError() != NO_ERROR) |
272 | { | |
273 | return 0; | |
274 | } | |
275 | else | |
276 | { | |
277 | return -1; | |
278 | } | |
279 | } | |
280 | ||
281 | Off_t | |
5833650d | 282 | PerlIOWin32_tell(pTHX_ PerlIO *f) |
a8c08ecd NIS |
283 | { |
284 | PerlIOWin32 *s = PerlIOSelf(f,PerlIOWin32); | |
285 | DWORD high = 0; | |
8d3a710f | 286 | DWORD res = SetFilePointer(s->h,0,(LONG *)&high,FILE_CURRENT); |
a8c08ecd NIS |
287 | if (res != 0xFFFFFFFF || GetLastError() != NO_ERROR) |
288 | { | |
3caf316a | 289 | #if Off_t_size >= 8 |
a8c08ecd | 290 | return ((Off_t) high << 32) | res; |
3caf316a SH |
291 | #else |
292 | return res; | |
293 | #endif | |
a8c08ecd NIS |
294 | } |
295 | return (Off_t) -1; | |
296 | } | |
297 | ||
298 | IV | |
5833650d | 299 | PerlIOWin32_close(pTHX_ PerlIO *f) |
a8c08ecd NIS |
300 | { |
301 | PerlIOWin32 *s = PerlIOSelf(f,PerlIOWin32); | |
302 | if (s->refcnt == 1) | |
303 | { | |
86e05cf2 | 304 | IV code = 0; |
755e7759 | 305 | #if 0 |
86e05cf2 | 306 | /* This does not do pipes etc. correctly */ |
755e7759 | 307 | if (!CloseHandle(s->h)) |
a8c08ecd NIS |
308 | { |
309 | s->h = INVALID_HANDLE_VALUE; | |
310 | return -1; | |
311 | } | |
755e7759 NIS |
312 | #else |
313 | PerlIOBase(f)->flags &= ~PERLIO_F_OPEN; | |
314 | return win32_close(s->fd); | |
315 | #endif | |
a8c08ecd | 316 | } |
a8c08ecd NIS |
317 | return 0; |
318 | } | |
319 | ||
8cf8f3d1 | 320 | PerlIO * |
af9603a6 | 321 | PerlIOWin32_dup(pTHX_ PerlIO *f, PerlIO *o, CLONE_PARAMS *params, int flags) |
8cf8f3d1 | 322 | { |
aa98ed8a NIS |
323 | PerlIOWin32 *os = PerlIOSelf(f,PerlIOWin32); |
324 | HANDLE proc = GetCurrentProcess(); | |
f76b679e SH |
325 | HANDLE new_h; |
326 | if (DuplicateHandle(proc, os->h, proc, &new_h, 0, FALSE, DUPLICATE_SAME_ACCESS)) | |
aa98ed8a NIS |
327 | { |
328 | char mode[8]; | |
f76b679e | 329 | int fd = win32_open_osfhandle((intptr_t) new_h, PerlIOUnix_oflags(PerlIO_modestr(o,mode))); |
86e05cf2 | 330 | if (fd >= 0) |
aa98ed8a | 331 | { |
af9603a6 | 332 | f = PerlIOBase_dup(aTHX_ f, o, params, flags); |
86e05cf2 | 333 | if (f) |
aa98ed8a NIS |
334 | { |
335 | PerlIOWin32 *fs = PerlIOSelf(f,PerlIOWin32); | |
f76b679e | 336 | fs->h = new_h; |
aa98ed8a NIS |
337 | fs->fd = fd; |
338 | fs->refcnt = 1; | |
339 | fdtable[fd] = fs; | |
340 | if (fd > max_open_fd) | |
341 | max_open_fd = fd; | |
342 | } | |
343 | else | |
344 | { | |
345 | win32_close(fd); | |
346 | } | |
347 | } | |
348 | else | |
349 | { | |
f76b679e | 350 | CloseHandle(new_h); |
aa98ed8a NIS |
351 | } |
352 | } | |
353 | return f; | |
8cf8f3d1 NIS |
354 | } |
355 | ||
27da23d5 | 356 | PERLIO_FUNCS_DECL(PerlIO_win32) = { |
2dc2558e | 357 | sizeof(PerlIO_funcs), |
a8c08ecd NIS |
358 | "win32", |
359 | sizeof(PerlIOWin32), | |
360 | PERLIO_K_RAW, | |
361 | PerlIOWin32_pushed, | |
362 | PerlIOWin32_popped, | |
363 | PerlIOWin32_open, | |
86e05cf2 | 364 | PerlIOBase_binmode, |
a8c08ecd NIS |
365 | NULL, /* getarg */ |
366 | PerlIOWin32_fileno, | |
8cf8f3d1 | 367 | PerlIOWin32_dup, |
a8c08ecd NIS |
368 | PerlIOWin32_read, |
369 | PerlIOBase_unread, | |
370 | PerlIOWin32_write, | |
371 | PerlIOWin32_seek, | |
372 | PerlIOWin32_tell, | |
373 | PerlIOWin32_close, | |
374 | PerlIOBase_noop_ok, /* flush */ | |
375 | PerlIOBase_noop_fail, /* fill */ | |
376 | PerlIOBase_eof, | |
377 | PerlIOBase_error, | |
378 | PerlIOBase_clearerr, | |
379 | PerlIOBase_setlinebuf, | |
380 | NULL, /* get_base */ | |
381 | NULL, /* get_bufsiz */ | |
382 | NULL, /* get_ptr */ | |
383 | NULL, /* get_cnt */ | |
384 | NULL, /* set_ptrcnt */ | |
385 | }; | |
386 | ||
57143e73 | 387 | #endif |
5833650d | 388 |