[MSVCRT_WINETEST] Sync with Wine Staging 1.7.55. CORE-10536
[reactos.git] / rostests / winetests / msvcrt / file.c
1 /*
2 * Unit test suite for file functions
3 *
4 * Copyright 2002 Bill Currie
5 * Copyright 2005 Paul Rupe
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20 */
21
22 #include "wine/test.h"
23 #include <stdarg.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26 #include <fcntl.h>
27 #include <share.h>
28 #include <sys/stat.h>
29 #include <io.h>
30 #include <direct.h>
31 #include <windef.h>
32 #include <winbase.h>
33 #include <winnls.h>
34 #include <process.h>
35 #include <errno.h>
36 #include <locale.h>
37
38 #define MSVCRT_FD_BLOCK_SIZE 32
39 typedef struct {
40 HANDLE handle;
41 unsigned char wxflag;
42 char lookahead[3];
43 int exflag;
44 CRITICAL_SECTION crit;
45 } ioinfo;
46 static ioinfo **__pioinfo;
47
48 static HANDLE proc_handles[2];
49
50 static int (__cdecl *p_fopen_s)(FILE**, const char*, const char*);
51 static int (__cdecl *p__wfopen_s)(FILE**, const wchar_t*, const wchar_t*);
52
53 static const char* get_base_name(const char *path)
54 {
55 const char *ret = path+strlen(path)-1;
56
57 while(ret >= path) {
58 if(*ret=='\\' || *ret=='/')
59 break;
60 ret--;
61 }
62 return ret+1;
63 }
64
65 static void init(void)
66 {
67 HMODULE hmod = GetModuleHandleA("msvcrt.dll");
68
69 setlocale(LC_CTYPE, "C");
70
71 p_fopen_s = (void*)GetProcAddress(hmod, "fopen_s");
72 p__wfopen_s = (void*)GetProcAddress(hmod, "_wfopen_s");
73 __pioinfo = (void*)GetProcAddress(hmod, "__pioinfo");
74 }
75
76 static void test_filbuf( void )
77 {
78 FILE *fp;
79 int c;
80 fpos_t pos;
81
82 fp = fopen("filbuf.tst", "wb");
83 fwrite("\n\n\n\n", 1, 4, fp);
84 fclose(fp);
85
86 fp = fopen("filbuf.tst", "rt");
87 c = _filbuf(fp);
88 ok(c == '\n', "read wrong byte\n");
89 /* See bug 16970 for why we care about _filbuf.
90 * ftell returns screwy values on files with lots
91 * of bare LFs in ascii mode because it assumes
92 * that ascii files contain only CRLFs, removes
93 * the CR's early in _filbuf, and adjusts the return
94 * value of ftell to compensate.
95 * native _filbuf will read the whole file, then consume and return
96 * the first one. That leaves fp->_fd at offset 4, and fp->_ptr
97 * pointing to a buffer of three bare LFs, so
98 * ftell will return 4 - 3 - 3 = -2.
99 */
100 ok(ftell(fp) == -2, "ascii crlf removal does not match native\n");
101 ok(fgetpos(fp, &pos) == 0, "fgetpos fail\n");
102 ok(pos == -2, "ftell does not match fgetpos\n");
103 fclose(fp);
104 unlink("filbuf.tst");
105 }
106
107 static void test_fdopen( void )
108 {
109 static const char buffer[] = {0,1,2,3,4,5,6,7,8,9};
110 char ibuf[10];
111 int fd;
112 FILE *file;
113
114 fd = open ("fdopen.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE);
115 write (fd, buffer, sizeof (buffer));
116 close (fd);
117
118 fd = open ("fdopen.tst", O_RDONLY | O_BINARY);
119 lseek (fd, 5, SEEK_SET);
120 file = fdopen (fd, "rb");
121 ok (fread (ibuf, 1, sizeof (buffer), file) == 5, "read wrong byte count\n");
122 ok (memcmp (ibuf, buffer + 5, 5) == 0, "read wrong bytes\n");
123 fclose (file);
124 unlink ("fdopen.tst");
125 }
126
127 static void test_fileops( void )
128 {
129 static const char outbuffer[] = "0,1,2,3,4,5,6,7,8,9";
130 char buffer[256];
131 WCHAR wbuffer[256];
132 int fd;
133 FILE *file;
134 fpos_t pos;
135 int i, c, bufmode;
136 static const int bufmodes[] = {_IOFBF,_IONBF};
137
138 fd = open ("fdopen.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE);
139 write (fd, outbuffer, sizeof (outbuffer));
140 close (fd);
141
142 for (bufmode=0; bufmode < sizeof(bufmodes)/sizeof(bufmodes[0]); bufmode++)
143 {
144 fd = open ("fdopen.tst", O_RDONLY | O_BINARY);
145 file = fdopen (fd, "rb");
146 setvbuf(file,NULL,bufmodes[bufmode],2048);
147 if(bufmodes[bufmode] == _IOFBF)
148 ok(file->_bufsiz == 2048, "file->_bufsiz = %d\n", file->_bufsiz);
149 ok(file->_base != NULL, "file->_base = NULL\n");
150 ok(strlen(outbuffer) == (sizeof(outbuffer)-1),"strlen/sizeof error for bufmode=%x\n", bufmodes[bufmode]);
151 ok(fgets(buffer,sizeof(buffer),file) !=0,"fgets failed unexpected for bufmode=%x\n", bufmodes[bufmode]);
152 ok(fgets(buffer,sizeof(buffer),file) ==0,"fgets didn't signal EOF for bufmode=%x\n", bufmodes[bufmode]);
153 ok(feof(file) !=0,"feof doesn't signal EOF for bufmode=%x\n", bufmodes[bufmode]);
154 rewind(file);
155 ok(fgets(buffer,strlen(outbuffer),file) !=0,"fgets failed unexpected for bufmode=%x\n", bufmodes[bufmode]);
156 ok(lstrlenA(buffer) == lstrlenA(outbuffer) -1,"fgets didn't read right size for bufmode=%x\n", bufmodes[bufmode]);
157 ok(fgets(buffer,sizeof(outbuffer),file) !=0,"fgets failed unexpected for bufmode=%x\n", bufmodes[bufmode]);
158 ok(strlen(buffer) == 1,"fgets dropped chars for bufmode=%x\n", bufmodes[bufmode]);
159 ok(buffer[0] == outbuffer[strlen(outbuffer)-1],"fgets exchanged chars for bufmode=%x\n", bufmodes[bufmode]);
160
161 rewind(file);
162 for (i = 0; i < sizeof(outbuffer); i++)
163 {
164 ok(fgetc(file) == outbuffer[i], "fgetc returned wrong data for bufmode=%x\n", bufmodes[bufmode]);
165 }
166 ok((c = fgetc(file)) == EOF, "getc did not return EOF for bufmode=%x\n", bufmodes[bufmode]);
167 ok(feof(file), "feof did not return EOF for bufmode=%x\n", bufmodes[bufmode]);
168 ok(ungetc(c, file) == EOF, "ungetc(EOF) did not return EOF for bufmode=%x\n", bufmodes[bufmode]);
169 ok(feof(file), "feof after ungetc(EOF) did not return EOF for bufmode=%x\n", bufmodes[bufmode]);
170 ok(fgetc(file) == EOF, "getc did not return EOF for bufmode=%x\n", bufmodes[bufmode]);
171 c = outbuffer[sizeof(outbuffer) - 1];
172 ok(ungetc(c, file) == c, "ungetc did not return its input for bufmode=%x\n", bufmodes[bufmode]);
173 ok(!feof(file), "feof after ungetc returned EOF for bufmode=%x\n", bufmodes[bufmode]);
174 ok((c = fgetc(file)) != EOF, "getc after ungetc returned EOF for bufmode=%x\n", bufmodes[bufmode]);
175 ok(c == outbuffer[sizeof(outbuffer) - 1],
176 "getc did not return ungetc'd data for bufmode=%x\n", bufmodes[bufmode]);
177 ok(!feof(file), "feof after getc returned EOF prematurely for bufmode=%x\n", bufmodes[bufmode]);
178 ok(fgetc(file) == EOF, "getc did not return EOF for bufmode=%x\n", bufmodes[bufmode]);
179 ok(feof(file), "feof after getc did not return EOF for bufmode=%x\n", bufmodes[bufmode]);
180
181 rewind(file);
182 ok(fgetpos(file,&pos) == 0, "fgetpos failed unexpected for bufmode=%x\n", bufmodes[bufmode]);
183 ok(pos == 0, "Unexpected result of fgetpos %x%08x for bufmode=%x\n", (DWORD)(pos >> 32), (DWORD)pos, bufmodes[bufmode]);
184 pos = sizeof (outbuffer);
185 ok(fsetpos(file, &pos) == 0, "fsetpos failed unexpected for bufmode=%x\n", bufmodes[bufmode]);
186 ok(fgetpos(file,&pos) == 0, "fgetpos failed unexpected for bufmode=%x\n", bufmodes[bufmode]);
187 ok(pos == sizeof (outbuffer), "Unexpected result of fgetpos %x%08x for bufmode=%x\n", (DWORD)(pos >> 32), (DWORD)pos, bufmodes[bufmode]);
188
189 fclose (file);
190 }
191 fd = open ("fdopen.tst", O_RDONLY | O_TEXT);
192 file = fdopen (fd, "rt"); /* open in TEXT mode */
193 ok(fgetws(wbuffer,sizeof(wbuffer)/sizeof(wbuffer[0]),file) !=0,"fgetws failed unexpected\n");
194 ok(fgetws(wbuffer,sizeof(wbuffer)/sizeof(wbuffer[0]),file) ==0,"fgetws didn't signal EOF\n");
195 ok(feof(file) !=0,"feof doesn't signal EOF\n");
196 rewind(file);
197 ok(fgetws(wbuffer,strlen(outbuffer),file) !=0,"fgetws failed unexpected\n");
198 ok(lstrlenW(wbuffer) == (lstrlenA(outbuffer) -1),"fgetws didn't read right size\n");
199 ok(fgetws(wbuffer,sizeof(outbuffer)/sizeof(outbuffer[0]),file) !=0,"fgets failed unexpected\n");
200 ok(lstrlenW(wbuffer) == 1,"fgets dropped chars\n");
201 fclose (file);
202
203 file = fopen("fdopen.tst", "rb");
204 ok( file != NULL, "fopen failed\n");
205 /* sizeof(buffer) > content of file */
206 ok(fread(buffer, sizeof(buffer), 1, file) == 0, "fread test failed\n");
207 /* feof should be set now */
208 ok(feof(file), "feof after fread failed\n");
209 fclose (file);
210
211 unlink ("fdopen.tst");
212 }
213
214 #define IOMODE (ao?"ascii mode":"binary mode")
215 static void test_readmode( BOOL ascii_mode )
216 {
217 static const char outbuffer[] = "0,1,2,3,4,5,6,7,8,9\r\n\r\nA,B,C,D,E\r\nX,Y,Z";
218 static const char padbuffer[] = "ghjghjghjghj";
219 static const char nlbuffer[] = "\r\n";
220 char buffer[2*BUFSIZ+256];
221 const char *optr;
222 int fd;
223 FILE *file;
224 const int *ip;
225 int i, j, m, ao, pl;
226 unsigned int fp;
227 LONG l;
228
229 fd = open ("fdopen.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE);
230 /* an internal buffer of BUFSIZ is maintained, so make a file big
231 * enough to test operations that cross the buffer boundary
232 */
233 j = (2*BUFSIZ-4)/strlen(padbuffer);
234 for (i=0; i<j; i++)
235 write (fd, padbuffer, strlen(padbuffer));
236 j = (2*BUFSIZ-4)%strlen(padbuffer);
237 for (i=0; i<j; i++)
238 write (fd, &padbuffer[i], 1);
239 write (fd, nlbuffer, strlen(nlbuffer));
240 write (fd, outbuffer, sizeof (outbuffer));
241 close (fd);
242
243 if (ascii_mode) {
244 /* Open file in ascii mode */
245 fd = open ("fdopen.tst", O_RDONLY);
246 file = fdopen (fd, "r");
247 ao = -1; /* on offset to account for carriage returns */
248 }
249 else {
250 fd = open ("fdopen.tst", O_RDONLY | O_BINARY);
251 file = fdopen (fd, "rb");
252 ao = 0;
253 }
254
255 /* first is a test of fgets, ftell, fseek */
256 ok(ftell(file) == 0,"Did not start at beginning of file in %s\n", IOMODE);
257 ok(fgets(buffer,2*BUFSIZ+256,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE);
258 l = ftell(file);
259 pl = 2*BUFSIZ-2;
260 ok(l == pl,"padding line ftell got %d should be %d in %s\n", l, pl, IOMODE);
261 ok(lstrlenA(buffer) == pl+ao,"padding line fgets got size %d should be %d in %s\n",
262 lstrlenA(buffer), pl+ao, IOMODE);
263 for (fp=0; fp<strlen(outbuffer); fp++)
264 if (outbuffer[fp] == '\n') break;
265 fp++;
266 ok(fgets(buffer,256,file) !=0,"line 1 fgets failed unexpected in %s\n", IOMODE);
267 l = ftell(file);
268 ok(l == pl+fp,"line 1 ftell got %d should be %d in %s\n", l, pl+fp, IOMODE);
269 ok(lstrlenA(buffer) == fp+ao,"line 1 fgets got size %d should be %d in %s\n",
270 lstrlenA(buffer), fp+ao, IOMODE);
271 /* test a seek back across the buffer boundary */
272 l = pl;
273 ok(fseek(file,l,SEEK_SET)==0,"seek failure in %s\n", IOMODE);
274 l = ftell(file);
275 ok(l == pl,"ftell after seek got %d should be %d in %s\n", l, pl, IOMODE);
276 ok(fgets(buffer,256,file) !=0,"second read of line 1 fgets failed unexpected in %s\n", IOMODE);
277 l = ftell(file);
278 ok(l == pl+fp,"second read of line 1 ftell got %d should be %d in %s\n", l, pl+fp, IOMODE);
279 ok(lstrlenA(buffer) == fp+ao,"second read of line 1 fgets got size %d should be %d in %s\n",
280 lstrlenA(buffer), fp+ao, IOMODE);
281 ok(fgets(buffer,256,file) !=0,"line 2 fgets failed unexpected in %s\n", IOMODE);
282 fp += 2;
283 l = ftell(file);
284 ok(l == pl+fp,"line 2 ftell got %d should be %d in %s\n", l, pl+fp, IOMODE);
285 ok(lstrlenA(buffer) == 2+ao,"line 2 fgets got size %d should be %d in %s\n",
286 lstrlenA(buffer), 2+ao, IOMODE);
287
288 /* test fread across buffer boundary */
289 rewind(file);
290 ok(ftell(file) == 0,"Did not start at beginning of file in %s\n", IOMODE);
291 ok(fgets(buffer,BUFSIZ-6,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE);
292 j=strlen(outbuffer);
293 i=fread(buffer,1,BUFSIZ+strlen(outbuffer),file);
294 ok(i==BUFSIZ+j,"fread failed, expected %d got %d in %s\n", BUFSIZ+j, i, IOMODE);
295 l = ftell(file);
296 ok(l == pl+j-(ao*4)-5,"ftell after fread got %d should be %d in %s\n", l, pl+j-(ao*4)-5, IOMODE);
297 for (m=0; m<3; m++)
298 ok(buffer[m]==padbuffer[m+(BUFSIZ-4)%strlen(padbuffer)],"expected %c got %c\n", padbuffer[m], buffer[m]);
299 m+=BUFSIZ+2+ao;
300 optr = outbuffer;
301 for (; m<i; m++) {
302 ok(buffer[m]==*optr,"char %d expected %c got %c in %s\n", m, *optr, buffer[m], IOMODE);
303 optr++;
304 if (ao && (*optr == '\r'))
305 optr++;
306 }
307 /* fread should return the requested number of bytes if available */
308 rewind(file);
309 ok(ftell(file) == 0,"Did not start at beginning of file in %s\n", IOMODE);
310 ok(fgets(buffer,BUFSIZ-6,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE);
311 j = fp+10;
312 i=fread(buffer,1,j,file);
313 ok(i==j,"fread failed, expected %d got %d in %s\n", j, i, IOMODE);
314 /* test fread eof */
315 ok(fseek(file,0,SEEK_END)==0,"seek failure in %s\n", IOMODE);
316 ok(feof(file)==0,"feof failure in %s\n", IOMODE);
317 ok(fread(buffer,1,1,file)==0,"fread failure in %s\n", IOMODE);
318 ok(feof(file)!=0,"feof failure in %s\n", IOMODE);
319 ok(fseek(file,-3,SEEK_CUR)==0,"seek failure in %s\n", IOMODE);
320 ok(feof(file)==0,"feof failure in %s\n", IOMODE);
321 ok(fread(buffer,2,1,file)==1,"fread failed in %s\n", IOMODE);
322 ok(feof(file)==0,"feof failure in %s\n", IOMODE);
323 ok(fread(buffer,2,1,file)==0,"fread failure in %s\n",IOMODE);
324 ok(feof(file)!=0,"feof failure in %s\n", IOMODE);
325
326 /* test some additional functions */
327 rewind(file);
328 ok(ftell(file) == 0,"Did not start at beginning of file in %s\n", IOMODE);
329 ok(fgets(buffer,2*BUFSIZ+256,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE);
330 i = _getw(file);
331 ip = (const int *)outbuffer;
332 ok(i == *ip,"_getw failed, expected %08x got %08x in %s\n", *ip, i, IOMODE);
333 for (fp=0; fp<strlen(outbuffer); fp++)
334 if (outbuffer[fp] == '\n') break;
335 fp++;
336 /* this will cause the next _getw to cross carriage return characters */
337 ok(fgets(buffer,fp-6,file) !=0,"line 1 fgets failed unexpected in %s\n", IOMODE);
338 for (i=0, j=0; i<6; i++) {
339 if (ao==0 || outbuffer[fp-3+i] != '\r')
340 buffer[j++] = outbuffer[fp-3+i];
341 }
342 i = _getw(file);
343 ip = (int *)buffer;
344 ok(i == *ip,"_getw failed, expected %08x got %08x in %s\n", *ip, i, IOMODE);
345
346 fclose (file);
347 unlink ("fdopen.tst");
348 }
349
350 static void test_asciimode(void)
351 {
352 FILE *fp;
353 char buf[64];
354 int c, i, j;
355
356 /* Simple test of CR CR LF handling. Test both fgets and fread code paths, they're different! */
357 fp = fopen("ascii.tst", "wb");
358 fputs("\r\r\n", fp);
359 fclose(fp);
360 fp = fopen("ascii.tst", "rt");
361 ok(fgets(buf, sizeof(buf), fp) != NULL, "fgets\n");
362 ok(0 == strcmp(buf, "\r\n"), "CR CR LF not read as CR LF\n");
363 rewind(fp);
364 ok((fread(buf, 1, sizeof(buf), fp) == 2) && (0 == strcmp(buf, "\r\n")), "CR CR LF not read as CR LF\n");
365 fclose(fp);
366 unlink("ascii.tst");
367
368 /* Simple test of foo ^Z [more than one block] bar handling */
369 fp = fopen("ascii.tst", "wb");
370 fputs("foo\032", fp); /* foo, logical EOF, ... */
371 fseek(fp, 65536L, SEEK_SET); /* ... more than MSVCRT_BUFSIZ, ... */
372 fputs("bar", fp); /* ... bar */
373 fclose(fp);
374 fp = fopen("ascii.tst", "rt");
375 ok(fgets(buf, sizeof(buf), fp) != NULL, "fgets foo\n");
376 ok(0 == strcmp(buf, "foo"), "foo ^Z not read as foo by fgets\n");
377 ok(fgets(buf, sizeof(buf), fp) == NULL, "fgets after logical EOF\n");
378 rewind(fp);
379 ok((fread(buf, 1, sizeof(buf), fp) == 3) && (0 == strcmp(buf, "foo")), "foo ^Z not read as foo by fread\n");
380 ok((fread(buf, 1, sizeof(buf), fp) == 0), "fread after logical EOF\n");
381 fclose(fp);
382
383 /* Show ASCII mode handling*/
384 fp= fopen("ascii.tst","wb");
385 fputs("0\r\n1\r\n2\r\n3\r\n4\r\n5\r\n6\r\n7\r\n8\r\n9\r\n", fp);
386 fclose(fp);
387
388 fp = fopen("ascii.tst", "r");
389 c= fgetc(fp);
390 ok(c == '0', "fgetc failed, expected '0', got '%c'\n", c);
391 c= fgetc(fp);
392 ok(c == '\n', "fgetc failed, expected '\\n', got '%c'\n", c);
393 fseek(fp,0,SEEK_CUR);
394 for(i=1; i<10; i++) {
395 ok((j = ftell(fp)) == i*3, "ftell fails in TEXT mode\n");
396 fseek(fp,0,SEEK_CUR);
397 ok((c = fgetc(fp)) == '0'+ i, "fgetc after fseek failed in line %d\n", i);
398 c= fgetc(fp);
399 ok(c == '\n', "fgetc failed, expected '\\n', got '%c'\n", c);
400 }
401 /* Show that fseek doesn't skip \\r !*/
402 rewind(fp);
403 c= fgetc(fp);
404 ok(c == '0', "fgetc failed, expected '0', got '%c'\n", c);
405 fseek(fp, 2 ,SEEK_CUR);
406 for(i=1; i<10; i++) {
407 ok((c = fgetc(fp)) == '0'+ i, "fgetc after fseek with pos Offset failed in line %d\n", i);
408 fseek(fp, 2 ,SEEK_CUR);
409 }
410 fseek(fp, 9*3 ,SEEK_SET);
411 c = fgetc(fp);
412 ok(c == '9', "fgetc failed, expected '9', got '%c'\n", c);
413 fseek(fp, -4 ,SEEK_CUR);
414 for(i= 8; i>=0; i--) {
415 ok((c = fgetc(fp)) == '0'+ i, "fgetc after fseek with neg Offset failed in line %d\n", i);
416 fseek(fp, -4 ,SEEK_CUR);
417 }
418 /* Show what happens if fseek positions filepointer on \\r */
419 fclose(fp);
420 fp = fopen("ascii.tst", "r");
421 fseek(fp, 3 ,SEEK_SET);
422 ok((c = fgetc(fp)) == '1', "fgetc fails to read next char when positioned on \\r\n");
423 fclose(fp);
424
425 unlink("ascii.tst");
426 }
427
428 static void test_asciimode2(void)
429 {
430 /* Error sequence from one app was getchar followed by small fread
431 * with one \r removed had last byte of buffer filled with
432 * next byte of *unbuffered* data rather than next byte from buffer
433 * Test case is a short string of one byte followed by a newline
434 * followed by filler to fill out the sector, then a sector of
435 * some different byte.
436 */
437
438 FILE *fp;
439 char ibuf[4];
440 int i;
441 static const char obuf[] =
442 "00\n"
443 "000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
444 "000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
445 "000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
446 "000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
447 "000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
448 "000000000000000000000000000000000000000000000000000000000000000000000000000000\n"
449 "000000000000000000\n"
450 "1111111111111111111";
451
452 fp = fopen("ascii2.tst", "wt");
453 fwrite(obuf, 1, sizeof(obuf), fp);
454 fclose(fp);
455
456 fp = fopen("ascii2.tst", "rt");
457 ok(getc(fp) == '0', "first char not 0\n");
458 memset(ibuf, 0, sizeof(ibuf));
459 i = fread(ibuf, 1, sizeof(ibuf), fp);
460 ok(i == sizeof(ibuf), "fread i %d != sizeof(ibuf)\n", i);
461 ok(0 == strncmp(ibuf, obuf+1, sizeof(ibuf)), "ibuf != obuf\n");
462 fclose(fp);
463 unlink("ascii2.tst");
464 }
465
466 static void test_filemodeT(void)
467 {
468 char DATA [] = {26, 't', 'e', 's' ,'t'};
469 char DATA2 [100];
470 char temppath[MAX_PATH];
471 char tempfile[MAX_PATH];
472 FILE* f;
473 size_t bytesWritten;
474 size_t bytesRead;
475 WIN32_FIND_DATAA findData;
476 HANDLE h;
477
478 GetTempPathA(MAX_PATH, temppath);
479 GetTempFileNameA(temppath, "", 0, tempfile);
480
481 f = fopen(tempfile, "w+bDT");
482 bytesWritten = fwrite(DATA, 1, sizeof(DATA), f);
483 rewind(f);
484 bytesRead = fread(DATA2, 1, sizeof(DATA2), f);
485 fclose(f);
486
487 ok (bytesRead == bytesWritten && bytesRead == sizeof(DATA),
488 "fopen file mode 'T' wrongly interpreted as 't'\n" );
489
490 h = FindFirstFileA(tempfile, &findData);
491
492 ok (h == INVALID_HANDLE_VALUE, "file wasn't deleted when closed.\n" );
493
494 if (h != INVALID_HANDLE_VALUE) FindClose(h);
495 }
496
497 static WCHAR* AtoW( const char* p )
498 {
499 WCHAR* buffer;
500 DWORD len = MultiByteToWideChar( CP_ACP, 0, p, -1, NULL, 0 );
501 buffer = malloc( len * sizeof(WCHAR) );
502 MultiByteToWideChar( CP_ACP, 0, p, -1, buffer, len );
503 return buffer;
504 }
505
506 /* Test reading in text mode when the 512'th character read is \r*/
507 static void test_readboundary(void)
508 {
509 FILE *fp;
510 char buf[513], rbuf[513];
511 int i, j;
512 for (i = 0; i < 511; i++)
513 {
514 j = (i%('~' - ' ')+ ' ');
515 buf[i] = j;
516 }
517 buf[511] = '\n';
518 buf[512] =0;
519 fp = fopen("boundary.tst", "wt");
520 fwrite(buf, 512,1,fp);
521 fclose(fp);
522 fp = fopen("boundary.tst", "rt");
523 for(i=0; i<512; i++)
524 {
525 fseek(fp,0 , SEEK_CUR);
526 rbuf[i] = fgetc(fp);
527 }
528 rbuf[512] =0;
529 fclose(fp);
530 unlink("boundary.tst");
531
532 ok(strcmp(buf, rbuf) == 0,"CRLF on buffer boundary failure\n");
533 }
534
535 static void test_fgetc( void )
536 {
537 char* tempf;
538 FILE *tempfh;
539 int ich=0xe0, ret;
540
541 tempf=_tempnam(".","wne");
542 tempfh = fopen(tempf,"w+");
543 fputc(ich, tempfh);
544 fputc(ich, tempfh);
545 rewind(tempfh);
546 ret = fgetc(tempfh);
547 ok(ich == ret, "First fgetc expected %x got %x\n", ich, ret);
548 ret = fgetc(tempfh);
549 ok(ich == ret, "Second fgetc expected %x got %x\n", ich, ret);
550 fclose(tempfh);
551 tempfh = fopen(tempf,"wt");
552 fputc('\n', tempfh);
553 fclose(tempfh);
554 tempfh = fopen(tempf,"wt");
555 setbuf(tempfh, NULL);
556 ret = fgetc(tempfh);
557 ok(ret == -1, "Unbuffered fgetc in text mode must failed on \\r\\n\n");
558 fclose(tempfh);
559 unlink(tempf);
560 free(tempf);
561 }
562
563 static void test_fputc( void )
564 {
565 char* tempf;
566 FILE *tempfh;
567 int ret;
568
569 tempf=_tempnam(".","wne");
570 tempfh = fopen(tempf,"wb");
571 ret = fputc(0,tempfh);
572 ok(0 == ret, "fputc(0,tempfh) expected %x got %x\n", 0, ret);
573 ret = fputc(0xff,tempfh);
574 ok(0xff == ret, "fputc(0xff,tempfh) expected %x got %x\n", 0xff, ret);
575 ret = fputc(0xffffffff,tempfh);
576 ok(0xff == ret, "fputc(0xffffffff,tempfh) expected %x got %x\n", 0xff, ret);
577 fclose(tempfh);
578
579 tempfh = fopen(tempf,"rb");
580 ret = fputc(0,tempfh);
581 ok(EOF == ret, "fputc(0,tempfh) on r/o file expected %x got %x\n", EOF, ret);
582 fclose(tempfh);
583
584 unlink(tempf);
585 free(tempf);
586 }
587
588 static void test_flsbuf( void )
589 {
590 char* tempf;
591 FILE *tempfh;
592 int c;
593 int ret;
594 int bufmode;
595 static const int bufmodes[] = {_IOFBF,_IONBF};
596
597 tempf=_tempnam(".","wne");
598 for (bufmode=0; bufmode < sizeof(bufmodes)/sizeof(bufmodes[0]); bufmode++)
599 {
600 tempfh = fopen(tempf,"wb");
601 setvbuf(tempfh,NULL,bufmodes[bufmode],2048);
602 ret = _flsbuf(0,tempfh);
603 ok(0 == ret, "_flsbuf(0,tempfh) with bufmode %x expected %x got %x\n",
604 bufmodes[bufmode], 0, ret);
605 ret = _flsbuf(0xff,tempfh);
606 ok(0xff == ret, "_flsbuf(0xff,tempfh) with bufmode %x expected %x got %x\n",
607 bufmodes[bufmode], 0xff, ret);
608 ret = _flsbuf(0xffffffff,tempfh);
609 ok(0xff == ret, "_flsbuf(0xffffffff,tempfh) with bufmode %x expected %x got %x\n",
610 bufmodes[bufmode], 0xff, ret);
611 if(tempfh->_base) {
612 fputc('x', tempfh);
613 tempfh->_cnt = -1;
614 tempfh->_base[1] = 'a';
615 ret = _flsbuf(0xab,tempfh);
616 ok(ret == 0xab, "_flsbuf(0xab,tempfh) with bufmode %x expected 0xab got %x\n",
617 bufmodes[bufmode], ret);
618 ok(tempfh->_base[1] == 'a', "tempfh->_base[1] should not be changed (%d)\n",
619 tempfh->_base[1]);
620 }
621
622 fclose(tempfh);
623 }
624
625 tempfh = fopen(tempf,"rb");
626 ret = _flsbuf(0,tempfh);
627 ok(EOF == ret, "_flsbuf(0,tempfh) on r/o file expected %x got %x\n", EOF, ret);
628 fclose(tempfh);
629
630 /* See bug 17123, exposed by WinAVR's make */
631 tempfh = fopen(tempf,"w");
632 ok(tempfh->_cnt == 0, "_cnt on freshly opened file was %d\n", tempfh->_cnt);
633 setbuf(tempfh, NULL);
634 ok(tempfh->_cnt == 0, "_cnt on unbuffered file was %d\n", tempfh->_cnt);
635 ok(tempfh->_bufsiz == 2, "_bufsiz = %d\n", tempfh->_bufsiz);
636 /* Inlined putchar sets _cnt to -1. Native seems to ignore the value... */
637 tempfh->_cnt = 1234;
638 ret = _flsbuf('Q',tempfh);
639 ok('Q' == ret, "_flsbuf('Q',tempfh) expected %x got %x\n", 'Q', ret);
640 /* ... and reset it to zero */
641 ok(tempfh->_cnt == 0, "after unbuf _flsbuf, _cnt was %d\n", tempfh->_cnt);
642 fclose(tempfh);
643 /* And just for grins, make sure the file is correct */
644 tempfh = fopen(tempf,"r");
645 c = fgetc(tempfh);
646 ok(c == 'Q', "first byte should be 'Q'\n");
647 c = fgetc(tempfh);
648 ok(c == EOF, "there should only be one byte\n");
649 fclose(tempfh);
650
651 unlink(tempf);
652 free(tempf);
653 }
654
655 static void test_fflush( void )
656 {
657 static const char obuf[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
658 char buf1[16], buf2[24];
659 char *tempf;
660 FILE *tempfh;
661 int ret;
662
663 tempf=_tempnam(".","wne");
664
665 /* Prepare the file. */
666 tempfh = fopen(tempf,"wb");
667 ok(tempfh != NULL, "Can't open test file.\n");
668 fwrite(obuf, 1, sizeof(obuf), tempfh);
669 fclose(tempfh);
670
671 /* Open the file for input. */
672 tempfh = fopen(tempf,"rb");
673 ok(tempfh != NULL, "Can't open test file.\n");
674 fread(buf1, 1, sizeof(buf1), tempfh);
675
676 /* Using fflush() on input stream is undefined in ANSI.
677 * But MSDN says that it clears input buffer. */
678 _lseek(_fileno(tempfh), 0, SEEK_SET);
679 ret = fflush(tempfh);
680 ok(ret == 0, "expected 0, got %d\n", ret);
681 memset(buf2, '?', sizeof(buf2));
682 fread(buf2, 1, sizeof(buf2), tempfh);
683 ok(memcmp(buf1, buf2, sizeof(buf1)) == 0, "Got unexpected data (%c)\n", buf2[0]);
684
685 /* fflush(NULL) doesn't clear input buffer. */
686 _lseek(_fileno(tempfh), 0, SEEK_SET);
687 ret = fflush(NULL);
688 ok(ret == 0, "expected 0, got %d\n", ret);
689 memset(buf2, '?', sizeof(buf2));
690 fread(buf2, 1, sizeof(buf2), tempfh);
691 ok(memcmp(buf1, buf2, sizeof(buf1)) != 0, "Got unexpected data (%c)\n", buf2[0]);
692
693 /* _flushall() clears input buffer. */
694 _lseek(_fileno(tempfh), 0, SEEK_SET);
695 ret = _flushall();
696 ok(ret >= 0, "unexpected ret %d\n", ret);
697 memset(buf2, '?', sizeof(buf2));
698 fread(buf2, 1, sizeof(buf2), tempfh);
699 ok(memcmp(buf1, buf2, sizeof(buf1)) == 0, "Got unexpected data (%c)\n", buf2[0]);
700
701 fclose(tempfh);
702
703 unlink(tempf);
704 free(tempf);
705 }
706
707 static void test_fgetwc( void )
708 {
709 #define LLEN 512
710
711 char* tempf;
712 FILE *tempfh;
713 static const char mytext[]= "This is test_fgetwc\r\n";
714 WCHAR wtextW[BUFSIZ+LLEN+1];
715 WCHAR *mytextW = NULL, *aptr, *wptr;
716 BOOL diff_found = FALSE;
717 int j;
718 unsigned int i;
719 LONG l;
720
721 tempf=_tempnam(".","wne");
722 tempfh = fopen(tempf,"wb");
723 j = 'a';
724 /* pad to almost the length of the internal buffer */
725 for (i=0; i<BUFSIZ-4; i++)
726 fputc(j,tempfh);
727 j = '\r';
728 fputc(j,tempfh);
729 j = '\n';
730 fputc(j,tempfh);
731 fputs(mytext,tempfh);
732 fclose(tempfh);
733 /* in text mode, getws/c expects multibyte characters */
734 /*currently Wine only supports plain ascii, and that is all that is tested here */
735 tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
736 fgetws(wtextW,LLEN,tempfh);
737 l=ftell(tempfh);
738 ok(l==BUFSIZ-2, "ftell expected %d got %d\n", BUFSIZ-2, l);
739 fgetws(wtextW,LLEN,tempfh);
740 l=ftell(tempfh);
741 ok(l==BUFSIZ-2+strlen(mytext), "ftell expected %d got %d\n", BUFSIZ-2+lstrlenA(mytext), l);
742 mytextW = AtoW (mytext);
743 aptr = mytextW;
744 wptr = wtextW;
745 for (i=0; i<strlen(mytext)-2; i++, aptr++, wptr++)
746 {
747 diff_found |= (*aptr != *wptr);
748 }
749 ok(!(diff_found), "fgetwc difference found in TEXT mode\n");
750 ok(*wptr == '\n', "Carriage return was not skipped\n");
751 fclose(tempfh);
752 unlink(tempf);
753
754 tempfh = fopen(tempf,"wb");
755 j = 'a';
756 /* pad to almost the length of the internal buffer. Use an odd number of bytes
757 to test that we can read wchars that are split across the internal buffer
758 boundary */
759 for (i=0; i<BUFSIZ-3-strlen(mytext)*sizeof(WCHAR); i++)
760 fputc(j,tempfh);
761 j = '\r';
762 fputwc(j,tempfh);
763 j = '\n';
764 fputwc(j,tempfh);
765 fputws(wtextW,tempfh);
766 fputws(wtextW,tempfh);
767 fclose(tempfh);
768 /* in binary mode, getws/c expects wide characters */
769 tempfh = fopen(tempf,"rb"); /* open in BINARY mode */
770 j=(BUFSIZ-2)/sizeof(WCHAR)-strlen(mytext);
771 fgetws(wtextW,j,tempfh);
772 l=ftell(tempfh);
773 j=(j-1)*sizeof(WCHAR);
774 ok(l==j, "ftell expected %d got %d\n", j, l);
775 i=fgetc(tempfh);
776 ok(i=='a', "fgetc expected %d got %d\n", 0x61, i);
777 l=ftell(tempfh);
778 j++;
779 ok(l==j, "ftell expected %d got %d\n", j, l);
780 fgetws(wtextW,3,tempfh);
781 ok(wtextW[0]=='\r',"expected carriage return got %04hx\n", wtextW[0]);
782 ok(wtextW[1]=='\n',"expected newline got %04hx\n", wtextW[1]);
783 l=ftell(tempfh);
784 j += 4;
785 ok(l==j, "ftell expected %d got %d\n", j, l);
786 for(i=0; i<strlen(mytext); i++)
787 wtextW[i] = 0;
788 /* the first time we get the string, it should be entirely within the local buffer */
789 fgetws(wtextW,LLEN,tempfh);
790 l=ftell(tempfh);
791 j += (strlen(mytext)-1)*sizeof(WCHAR);
792 ok(l==j, "ftell expected %d got %d\n", j, l);
793 diff_found = FALSE;
794 aptr = mytextW;
795 wptr = wtextW;
796 for (i=0; i<strlen(mytext)-2; i++, aptr++, wptr++)
797 {
798 ok(*aptr == *wptr, "Char %d expected %04hx got %04hx\n", i, *aptr, *wptr);
799 diff_found |= (*aptr != *wptr);
800 }
801 ok(!(diff_found), "fgetwc difference found in BINARY mode\n");
802 ok(*wptr == '\n', "Should get newline\n");
803 for(i=0; i<strlen(mytext); i++)
804 wtextW[i] = 0;
805 /* the second time we get the string, it should cross the local buffer boundary.
806 One of the wchars should be split across the boundary */
807 fgetws(wtextW,LLEN,tempfh);
808 diff_found = FALSE;
809 aptr = mytextW;
810 wptr = wtextW;
811 for (i=0; i<strlen(mytext)-2; i++, aptr++, wptr++)
812 {
813 ok(*aptr == *wptr, "Char %d expected %04hx got %04hx\n", i, *aptr, *wptr);
814 diff_found |= (*aptr != *wptr);
815 }
816 ok(!(diff_found), "fgetwc difference found in BINARY mode\n");
817 ok(*wptr == '\n', "Should get newline\n");
818
819 free(mytextW);
820 fclose(tempfh);
821 unlink(tempf);
822 free(tempf);
823 }
824
825 static void test_fgetwc_locale(const char* text, const char* locale, int codepage)
826 {
827 char temppath[MAX_PATH], tempfile[MAX_PATH];
828 FILE *tempfh;
829 static const WCHAR wchar_text[] = { 0xfeff, 0xff1f, '!' };
830 WCHAR wtextW[BUFSIZ];
831 int ret = 0, i;
832 wint_t ch;
833
834 if (!setlocale(LC_CTYPE, locale))
835 {
836 win_skip("%s locale not available\n", locale);
837 return;
838 }
839
840 GetTempPathA(MAX_PATH, temppath);
841 GetTempFileNameA(temppath, "", 0, tempfile);
842
843 tempfh = fopen(tempfile, "wb");
844 ok(tempfh != NULL, "can't open tempfile\n");
845 fwrite(text, 1, strlen(text), tempfh);
846 fclose(tempfh);
847
848 if (codepage != 0)
849 {
850 /* mbstowcs rejects invalid multibyte sequence,
851 so we use MultiByteToWideChar here. */
852 ret = MultiByteToWideChar(codepage, 0, text, -1,
853 wtextW, sizeof(wtextW)/sizeof(wtextW[0]));
854 ok(ret > 0, "MultiByteToWideChar failed\n");
855 }
856 else
857 {
858 /* C locale */
859 const char *p;
860 for (p = text; *p != '\0'; p++)
861 wtextW[ret++] = (unsigned char)*p;
862 wtextW[ret++] = 0;
863 }
864
865 tempfh = fopen(tempfile, "rt");
866 ok(tempfh != NULL, "can't open tempfile\n");
867
868 for (i = 0; i < ret-1; i++)
869 {
870 ch = fgetwc(tempfh);
871 ok(ch == wtextW[i], "got %04hx, expected %04hx (cp%d[%d])\n", ch, wtextW[i], codepage, i);
872 }
873 ch = fgetwc(tempfh);
874 ok(ch == WEOF, "got %04hx, expected WEOF (cp%d)\n", ch, codepage);
875 fclose(tempfh);
876
877 tempfh = fopen(tempfile, "wb");
878 ok(tempfh != NULL, "can't open tempfile\n");
879 fwrite(wchar_text, 1, sizeof(wchar_text), tempfh);
880 fclose(tempfh);
881
882 tempfh = fopen(tempfile, "rb");
883 ok(tempfh != NULL, "can't open tempfile\n");
884 for (i = 0; i < sizeof(wchar_text)/sizeof(wchar_text[0]); i++)
885 {
886 ch = fgetwc(tempfh);
887 ok(ch == wchar_text[i], "got %04hx, expected %04x (cp%d[%d])\n", ch, wchar_text[i], codepage, i);
888 }
889 ch = fgetwc(tempfh);
890 ok(ch == WEOF, "got %04hx, expected WEOF (cp%d)\n", ch, codepage);
891 fclose(tempfh);
892 unlink(tempfile);
893 }
894
895 static void test_fgetwc_unicode(void)
896 {
897 char temppath[MAX_PATH], tempfile[MAX_PATH];
898 FILE *tempfh;
899 static const WCHAR wchar_text[] = { 0xfeff, 0xff1f, '!' };
900 char utf8_text[BUFSIZ];
901 int ret, i;
902 wint_t ch;
903
904 GetTempPathA(MAX_PATH, temppath);
905 GetTempFileNameA(temppath, "", 0, tempfile);
906
907 if (!p_fopen_s)
908 {
909 win_skip("fopen_s not available\n");
910 return;
911 }
912
913 tempfh = fopen(tempfile, "wb");
914 ok(tempfh != NULL, "can't open tempfile\n");
915 fwrite(wchar_text, 1, sizeof(wchar_text), tempfh);
916 fclose(tempfh);
917
918 tempfh = fopen(tempfile, "rt,ccs=unicode");
919 ok(tempfh != NULL, "can't open tempfile\n");
920 for (i = 1; i < sizeof(wchar_text)/sizeof(wchar_text[0]); i++)
921 {
922 ch = fgetwc(tempfh);
923 ok(ch == wchar_text[i],
924 "got %04hx, expected %04x (unicode[%d])\n", ch, wchar_text[i], i-1);
925 }
926 ch = fgetwc(tempfh);
927 ok(ch == WEOF, "got %04hx, expected WEOF (unicode)\n", ch);
928 fclose(tempfh);
929
930 tempfh = fopen(tempfile, "wb");
931 ok(tempfh != NULL, "can't open tempfile\n");
932 ret = WideCharToMultiByte(CP_UTF8, 0, wchar_text, sizeof(wchar_text)/sizeof(wchar_text[0]),
933 utf8_text, sizeof(utf8_text), NULL, NULL);
934 ok(ret > 0, "utf-8 conversion failed\n");
935 fwrite(utf8_text, sizeof(char), ret, tempfh);
936 fclose(tempfh);
937
938 tempfh = fopen(tempfile, "rt, ccs=UTF-8");
939 ok(tempfh != NULL, "can't open tempfile\n");
940 for (i = 1; i < sizeof(wchar_text)/sizeof(wchar_text[0]); i++)
941 {
942 ch = fgetwc(tempfh);
943 ok(ch == wchar_text[i],
944 "got %04hx, expected %04x (utf8[%d])\n", ch, wchar_text[i], i-1);
945 }
946 ch = fgetwc(tempfh);
947 ok(ch == WEOF, "got %04hx, expected WEOF (utf8)\n", ch);
948 fclose(tempfh);
949 unlink(temppath);
950 }
951
952 static void test_fputwc(void)
953 {
954 char temppath[MAX_PATH];
955 char tempfile[MAX_PATH];
956 FILE *f;
957 char buf[1024];
958 int ret;
959
960 GetTempPathA(MAX_PATH, temppath);
961 GetTempFileNameA(temppath, "", 0, tempfile);
962
963 f = fopen(tempfile, "w");
964 ret = fputwc('a', f);
965 ok(ret == 'a', "fputwc returned %x, expected 'a'\n", ret);
966 ret = fputwc('\n', f);
967 ok(ret == '\n', "fputwc returned %x, expected '\\n'\n", ret);
968 fclose(f);
969
970 f = fopen(tempfile, "rb");
971 ret = fread(buf, 1, sizeof(buf), f);
972 ok(ret == 3, "fread returned %d, expected 3\n", ret);
973 ok(!memcmp(buf, "a\r\n", 3), "incorrect file data\n");
974 fclose(f);
975
976 if(p_fopen_s) {
977 f = fopen(tempfile, "w,ccs=unicode");
978 ret = fputwc('a', f);
979 ok(ret == 'a', "fputwc returned %x, expected 'a'\n", ret);
980 ret = fputwc('\n', f);
981 ok(ret == '\n', "fputwc returned %x, expected '\\n'\n", ret);
982 fclose(f);
983
984 f = fopen(tempfile, "rb");
985 ret = fread(buf, 1, sizeof(buf), f);
986 ok(ret == 8, "fread returned %d, expected 8\n", ret);
987 ok(!memcmp(buf, "\xff\xfe\x61\x00\r\x00\n\x00", 8), "incorrect file data\n");
988 fclose(f);
989
990 f = fopen(tempfile, "w,ccs=utf-8");
991 ret = fputwc('a', f);
992 ok(ret == 'a', "fputwc returned %x, expected 'a'\n", ret);
993 ret = fputwc('\n', f);
994 ok(ret == '\n', "fputwc returned %x, expected '\\n'\n", ret);
995 fclose(f);
996
997 f = fopen(tempfile, "rb");
998 ret = fread(buf, 1, sizeof(buf), f);
999 ok(ret == 6, "fread returned %d, expected 6\n", ret);
1000 ok(!memcmp(buf, "\xef\xbb\xbf\x61\r\n", 6), "incorrect file data\n");
1001 fclose(f);
1002 }else {
1003 win_skip("fputwc tests on unicode files\n");
1004 }
1005
1006 _unlink(tempfile);
1007 }
1008
1009 static void test_ctrlz( void )
1010 {
1011 char* tempf;
1012 FILE *tempfh;
1013 static const char mytext[]= "This is test_ctrlz";
1014 char buffer[256];
1015 int i, j;
1016 LONG l;
1017
1018 tempf=_tempnam(".","wne");
1019 tempfh = fopen(tempf,"wb");
1020 fputs(mytext,tempfh);
1021 j = 0x1a; /* a ctrl-z character signals EOF in text mode */
1022 fputc(j,tempfh);
1023 j = '\r';
1024 fputc(j,tempfh);
1025 j = '\n';
1026 fputc(j,tempfh);
1027 j = 'a';
1028 fputc(j,tempfh);
1029 fclose(tempfh);
1030 tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
1031 ok(fgets(buffer,256,tempfh) != 0,"fgets failed unexpected\n");
1032 i=strlen(buffer);
1033 j=strlen(mytext);
1034 ok(i==j, "returned string length expected %d got %d\n", j, i);
1035 j+=4; /* ftell should indicate the true end of file */
1036 l=ftell(tempfh);
1037 ok(l==j, "ftell expected %d got %d\n", j, l);
1038 ok(feof(tempfh), "did not get EOF\n");
1039 fclose(tempfh);
1040
1041 tempfh = fopen(tempf,"rb"); /* open in BINARY mode */
1042 ok(fgets(buffer,256,tempfh) != 0,"fgets failed unexpected\n");
1043 i=strlen(buffer);
1044 j=strlen(mytext)+3; /* should get through newline */
1045 ok(i==j, "returned string length expected %d got %d\n", j, i);
1046 l=ftell(tempfh);
1047 ok(l==j, "ftell expected %d got %d\n", j, l);
1048 ok(fgets(buffer,256,tempfh) != 0,"fgets failed unexpected\n");
1049 i=strlen(buffer);
1050 ok(i==1, "returned string length expected %d got %d\n", 1, i);
1051 ok(feof(tempfh), "did not get EOF\n");
1052 fclose(tempfh);
1053 unlink(tempf);
1054 free(tempf);
1055 }
1056
1057 static void test_file_put_get( void )
1058 {
1059 char* tempf;
1060 FILE *tempfh;
1061 static const char mytext[]= "This is a test_file_put_get\n";
1062 static const char dostext[]= "This is a test_file_put_get\r\n";
1063 char btext[LLEN];
1064 WCHAR wtextW[LLEN+1];
1065 WCHAR *mytextW = NULL, *aptr, *wptr;
1066 BOOL diff_found = FALSE;
1067 unsigned int i;
1068
1069 tempf=_tempnam(".","wne");
1070 tempfh = fopen(tempf,"wt"); /* open in TEXT mode */
1071 fputs(mytext,tempfh);
1072 fclose(tempfh);
1073 tempfh = fopen(tempf,"rb"); /* open in TEXT mode */
1074 fgets(btext,LLEN,tempfh);
1075 ok( strlen(mytext) + 1 == strlen(btext),"TEXT/BINARY mode not handled for write\n");
1076 ok( btext[strlen(mytext)-1] == '\r', "CR not written\n");
1077 fclose(tempfh);
1078 tempfh = fopen(tempf,"wb"); /* open in BINARY mode */
1079 fputs(dostext,tempfh);
1080 fclose(tempfh);
1081 tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
1082 fgets(btext,LLEN,tempfh);
1083 ok(strcmp(btext, mytext) == 0,"_O_TEXT read doesn't strip CR\n");
1084 fclose(tempfh);
1085 tempfh = fopen(tempf,"rb"); /* open in TEXT mode */
1086 fgets(btext,LLEN,tempfh);
1087 ok(strcmp(btext, dostext) == 0,"_O_BINARY read doesn't preserve CR\n");
1088
1089 fclose(tempfh);
1090 tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
1091 fgetws(wtextW,LLEN,tempfh);
1092 mytextW = AtoW (mytext);
1093 aptr = mytextW;
1094 wptr = wtextW;
1095
1096 for (i=0; i<strlen(mytext); i++, aptr++, wptr++)
1097 {
1098 diff_found |= (*aptr != *wptr);
1099 }
1100 ok(!(diff_found), "fgetwc doesn't strip CR in TEXT mode\n");
1101 free(mytextW);
1102 fclose(tempfh);
1103 unlink(tempf);
1104 free(tempf);
1105 }
1106
1107 static void test_file_write_read( void )
1108 {
1109 char* tempf;
1110 int tempfd;
1111 static const char mytext[]= "This is test_file_write_read\nsecond line\n";
1112 static const char dostext[]= "This is test_file_write_read\r\nsecond line\r\n";
1113 char btext[LLEN];
1114 int ret, i;
1115
1116 tempf=_tempnam(".","wne");
1117 tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_BINARY|_O_RDWR,
1118 _S_IREAD | _S_IWRITE);
1119 ok( tempfd != -1,
1120 "Can't open '%s': %d\n", tempf, errno); /* open in BINARY mode */
1121 ok(_write(tempfd,dostext,strlen(dostext)) == lstrlenA(dostext),
1122 "_write _O_BINARY bad return value\n");
1123 _close(tempfd);
1124 i = lstrlenA(mytext);
1125 tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
1126 ok(_read(tempfd,btext,i) == i,
1127 "_read _O_BINARY got bad length\n");
1128 ok( memcmp(dostext,btext,i) == 0,
1129 "problems with _O_BINARY _write / _read\n");
1130 _close(tempfd);
1131 tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
1132 ok(_read(tempfd,btext,i) == i-1,
1133 "_read _O_TEXT got bad length\n");
1134 ok( memcmp(mytext,btext,i-1) == 0,
1135 "problems with _O_BINARY _write / _O_TEXT _read\n");
1136 _close(tempfd);
1137 tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_TEXT|_O_RDWR,
1138 _S_IREAD | _S_IWRITE);
1139 ok( tempfd != -1,
1140 "Can't open '%s': %d\n", tempf, errno); /* open in TEXT mode */
1141 ok(_write(tempfd,mytext,strlen(mytext)) == lstrlenA(mytext),
1142 "_write _O_TEXT bad return value\n");
1143 _close(tempfd);
1144 tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
1145 ok(_read(tempfd,btext,LLEN) == lstrlenA(dostext),
1146 "_read _O_BINARY got bad length\n");
1147 ok( memcmp(dostext,btext,strlen(dostext)) == 0,
1148 "problems with _O_TEXT _write / _O_BINARY _read\n");
1149 ok( btext[strlen(dostext)-2] == '\r', "CR not written or read\n");
1150 _close(tempfd);
1151 tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
1152 ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext),
1153 "_read _O_TEXT got bad length\n");
1154 ok( memcmp(mytext,btext,strlen(mytext)) == 0,
1155 "problems with _O_TEXT _write / _read\n");
1156 _close(tempfd);
1157
1158 memset(btext, 0, LLEN);
1159 tempfd = _open(tempf,_O_APPEND|_O_RDWR); /* open for APPEND in default mode */
1160 ok(tell(tempfd) == 0, "bad position %u expecting 0\n", tell(tempfd));
1161 ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext), "_read _O_APPEND got bad length\n");
1162 ok( memcmp(mytext,btext,strlen(mytext)) == 0, "problems with _O_APPEND _read\n");
1163 _close(tempfd);
1164
1165 /* Test reading only \n or \r */
1166 tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
1167 _lseek(tempfd, -1, FILE_END);
1168 ret = _read(tempfd,btext,LLEN);
1169 ok(ret == 1 && *btext == '\n', "_read expected 1 got bad length: %d\n", ret);
1170 _lseek(tempfd, -2, FILE_END);
1171 ret = _read(tempfd,btext,LLEN);
1172 ok(ret == 1 && *btext == '\n', "_read expected '\\n' got bad length: %d\n", ret);
1173 _lseek(tempfd, -2, FILE_END);
1174 ret = _read(tempfd,btext,1);
1175 ok(ret == 1 && *btext == '\n', "_read returned %d, buf: %d\n", ret, *btext);
1176 ret = read(tempfd,btext,1);
1177 ok(ret == 0, "_read returned %d, expected 0\n", ret);
1178 _lseek(tempfd, -3, FILE_END);
1179 ret = _read(tempfd,btext,1);
1180 ok(ret == 1 && *btext == 'e', "_read expected 'e' got \"%.*s\" bad length: %d\n", ret, btext, ret);
1181 ok(tell(tempfd) == 41, "bad position %u expecting 41\n", tell(tempfd));
1182 _lseek(tempfd, -3, FILE_END);
1183 ret = _read(tempfd,btext,2);
1184 ok(ret == 1 && *btext == 'e', "_read expected 'e' got \"%.*s\" bad length: %d\n", ret, btext, ret);
1185 ok(tell(tempfd) == 42, "bad position %u expecting 42\n", tell(tempfd));
1186 _lseek(tempfd, -3, FILE_END);
1187 ret = _read(tempfd,btext,3);
1188 ok(ret == 2 && *btext == 'e', "_read expected 'e' got \"%.*s\" bad length: %d\n", ret, btext, ret);
1189 ok(tell(tempfd) == 43, "bad position %u expecting 43\n", tell(tempfd));
1190 _close(tempfd);
1191
1192 ret = unlink(tempf);
1193 ok( ret == 0 ,"Can't unlink '%s': %d\n", tempf, errno);
1194 free(tempf);
1195
1196 tempf=_tempnam(".","wne");
1197 tempfd = _open(tempf, _O_CREAT|_O_TRUNC|_O_BINARY|_O_RDWR, _S_IWRITE);
1198 ok( tempfd != -1,
1199 "Can't open '%s': %d\n", tempf, errno); /* open in BINARY mode */
1200 ok(_write(tempfd,dostext,strlen(dostext)) == lstrlenA(dostext),
1201 "_write _O_BINARY bad return value\n");
1202 _close(tempfd);
1203 tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
1204 ok(_read(tempfd,btext,LLEN) == lstrlenA(dostext),
1205 "_read _O_BINARY got bad length\n");
1206 ok( memcmp(dostext,btext,strlen(dostext)) == 0,
1207 "problems with _O_BINARY _write / _read\n");
1208 ok( btext[strlen(dostext)-2] == '\r', "CR not written or read\n");
1209 _close(tempfd);
1210 tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
1211 ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext),
1212 "_read _O_TEXT got bad length\n");
1213 ok( memcmp(mytext,btext,strlen(mytext)) == 0,
1214 "problems with _O_BINARY _write / _O_TEXT _read\n");
1215 _close(tempfd);
1216
1217 /* test _read with single bytes. CR should be skipped and LF pulled in */
1218 tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
1219 for (i=0; i<strlen(mytext); i++) /* */
1220 {
1221 _read(tempfd,btext, 1);
1222 ok(btext[0] == mytext[i],"_read failed at pos %d 0x%02x vs 0x%02x\n", i, btext[0], mytext[i]);
1223 }
1224 while (_read(tempfd,btext, 1));
1225 _close(tempfd);
1226
1227 /* test _read in buffered mode. Last CR should be skipped but LF not pulled in */
1228 tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
1229 i = _read(tempfd,btext, strlen(mytext));
1230 ok(i == strlen(mytext)-1, "_read_i %d\n", i);
1231 _close(tempfd);
1232
1233 /* test read/write in unicode mode */
1234 if(p_fopen_s)
1235 {
1236 tempfd = _open(tempf, _O_CREAT|_O_TRUNC|_O_WRONLY|_O_WTEXT, _S_IWRITE);
1237 ok(tempfd != -1, "_open failed with error: %d\n", errno);
1238 ret = _write(tempfd, "a", 1);
1239 ok(ret == -1, "_write returned %d, expected -1\n", ret);
1240 ret = _write(tempfd, "a\x00\n\x00\xff\xff", 6);
1241 ok(ret == 6, "_write returned %d, expected 6\n", ret);
1242 _close(tempfd);
1243
1244 tempfd = _open(tempf, _O_RDONLY|_O_BINARY, 0);
1245 ok(tempfd != -1, "_open failed with error: %d\n", errno);
1246 ret = _read(tempfd, btext, sizeof(btext));
1247 ok(ret == 10, "_read returned %d, expected 10\n", ret);
1248 ok(!memcmp(btext, "\xff\xfe\x61\x00\r\x00\n\x00\xff\xff", 10), "btext is incorrect\n");
1249 _close(tempfd);
1250
1251 tempfd = _open(tempf, _O_RDONLY|_O_WTEXT, 0);
1252 ok(tempfd != -1, "_open failed with error: %d\n", errno);
1253 errno = 0xdeadbeef;
1254 ret = _read(tempfd, btext, 3);
1255 ok(ret == -1, "_read returned %d, expected -1\n", ret);
1256 ok(errno == 22, "errno = %d\n", errno);
1257 ret = _read(tempfd, btext, sizeof(btext));
1258 ok(ret == 6, "_read returned %d, expected 6\n", ret);
1259 ok(!memcmp(btext, "\x61\x00\n\x00\xff\xff", 6), "btext is incorrect\n");
1260 _close(tempfd);
1261
1262 tempfd = _open(tempf, _O_CREAT|_O_TRUNC|_O_WRONLY|_O_U8TEXT, _S_IWRITE);
1263 ok(tempfd != -1, "_open failed with error: %d\n", errno);
1264 errno = 0xdeadbeef;
1265 ret = _write(tempfd, "a", 1);
1266 ok(ret == -1, "_write returned %d, expected -1\n", ret);
1267 ok(errno == 22, "errno = %d\n", errno);
1268 ret = _write(tempfd, "a\x00\n\x00\x62\x00", 6);
1269 ok(ret == 6, "_write returned %d, expected 6\n", ret);
1270 _close(tempfd);
1271
1272 tempfd = _open(tempf, _O_RDONLY|_O_BINARY, 0);
1273 ok(tempfd != -1, "_open failed with error: %d\n", errno);
1274 ret = _read(tempfd, btext, sizeof(btext));
1275 ok(ret == 7, "_read returned %d, expected 7\n", ret);
1276 ok(!memcmp(btext, "\xef\xbb\xbf\x61\r\n\x62", 7), "btext is incorrect\n");
1277 _close(tempfd);
1278
1279 tempfd = _open(tempf, _O_RDONLY|_O_WTEXT, 0);
1280 ok(tempfd != -1, "_open failed with error: %d\n", errno);
1281 ret = _read(tempfd, btext, sizeof(btext));
1282 ok(ret == 6, "_read returned %d, expected 6\n", ret);
1283 ok(!memcmp(btext, "\x61\x00\n\x00\x62\x00", 6), "btext is incorrect\n");
1284
1285 /* when buffer is small read sometimes fails in native implementation */
1286 lseek(tempfd, 3 /* skip bom */, SEEK_SET);
1287 ret = _read(tempfd, btext, 4);
1288 todo_wine ok(ret == -1, "_read returned %d, expected -1\n", ret);
1289
1290 lseek(tempfd, 6, SEEK_SET);
1291 ret = _read(tempfd, btext, 2);
1292 ok(ret == 2, "_read returned %d, expected 2\n", ret);
1293 ok(!memcmp(btext, "\x62\x00", 2), "btext is incorrect\n");
1294 _close(tempfd);
1295
1296 tempfd = _open(tempf, _O_CREAT|_O_TRUNC|_O_WRONLY|_O_BINARY, _S_IWRITE);
1297 ok(tempfd != -1, "_open failed with error: %d\n", errno);
1298 ret = _write(tempfd, "\xef\xbb\xbf\x61\xc4\x85\x62\xc5\xbc\r\r\n", 12);
1299 ok(ret == 12, "_write returned %d, expected 9\n", ret);
1300 _close(tempfd);
1301
1302 tempfd = _open(tempf, _O_RDONLY|_O_WTEXT, 0);
1303 ok(tempfd != -1, "_open failed with error: %d\n", errno);
1304 ret = _read(tempfd, btext, sizeof(btext));
1305 ok(ret == 12, "_read returned %d, expected 12\n", ret);
1306 ok(!memcmp(btext, "\x61\x00\x05\x01\x62\x00\x7c\x01\x0d\x00\x0a\x00", 12), "btext is incorrect\n");
1307
1308 /* test invalid utf8 sequence */
1309 lseek(tempfd, 5, SEEK_SET);
1310 ret = _read(tempfd, btext, sizeof(btext));
1311 todo_wine ok(ret == 10, "_read returned %d, expected 10\n", ret);
1312 /* invalid char should be replaced by U+FFFD in MultiByteToWideChar */
1313 todo_wine ok(!memcmp(btext, "\xfd\xff", 2), "invalid UTF8 character was not replaced by U+FFFD\n");
1314 ok(!memcmp(btext+ret-8, "\x62\x00\x7c\x01\x0d\x00\x0a\x00", 8), "btext is incorrect\n");
1315 _close(tempfd);
1316 }
1317 else
1318 {
1319 win_skip("unicode mode tests on file\n");
1320 }
1321
1322 ret =_chmod (tempf, _S_IREAD | _S_IWRITE);
1323 ok( ret == 0,
1324 "Can't chmod '%s' to read-write: %d\n", tempf, errno);
1325 ret = unlink(tempf);
1326 ok( ret == 0 ,"Can't unlink '%s': %d\n", tempf, errno);
1327 free(tempf);
1328 }
1329
1330 static void test_file_inherit_child(const char* fd_s)
1331 {
1332 int fd = atoi(fd_s);
1333 char buffer[32];
1334 int ret;
1335
1336 ret =write(fd, "Success", 8);
1337 ok( ret == 8, "Couldn't write in child process on %d (%s)\n", fd, strerror(errno));
1338 lseek(fd, 0, SEEK_SET);
1339 ok(read(fd, buffer, sizeof (buffer)) == 8, "Couldn't read back the data\n");
1340 ok(memcmp(buffer, "Success", 8) == 0, "Couldn't read back the data\n");
1341 }
1342
1343 static void test_file_inherit_child_no(const char* fd_s)
1344 {
1345 int fd = atoi(fd_s);
1346 int ret;
1347
1348 ret = write(fd, "Success", 8);
1349 ok( ret == -1 && errno == EBADF,
1350 "Wrong write result in child process on %d (%s)\n", fd, strerror(errno));
1351 }
1352
1353 static void test_file_refcount_child(void)
1354 {
1355 static const char buffer1[] = "test1";
1356 static const char buffer2[] = "test2";
1357 static const char buffer3[] = "test3";
1358 static const char buffer4[] = "test4";
1359 HANDLE f0, f1, f2, h0, h1, h2;
1360 DWORD written, flags, ret;
1361
1362 f0 = (HANDLE)_get_osfhandle(STDIN_FILENO);
1363 f1 = (HANDLE)_get_osfhandle(STDOUT_FILENO);
1364 f2 = (HANDLE)_get_osfhandle(STDERR_FILENO);
1365 ok(f0 == f1, "expected same handles, got %p, %p\n", f0, f1);
1366 ok(f1 == f2, "expected same handles, got %p, %p\n", f1, f2);
1367
1368 h0 = GetStdHandle(STD_INPUT_HANDLE);
1369 h1 = GetStdHandle(STD_OUTPUT_HANDLE);
1370 h2 = GetStdHandle(STD_ERROR_HANDLE);
1371 ok(h0 == h1, "expected same handles, got %p, %p\n", h0, h1);
1372 ok(h1 == h2, "expected same handles, got %p, %p\n", h1, h2);
1373 ok(f0 == h0, "expected same handles, got %p, %p\n", f0, h0);
1374
1375 ret = GetHandleInformation(h1, &flags);
1376 ok(ret, "GetHandleInformation failed\n");
1377 ret = WriteFile(h1, buffer1, strlen(buffer1), &written, 0);
1378 ok(ret, "WriteFile failed\n");
1379
1380 ret = fclose(stdout);
1381 ok(ret == 0, "fclose failed\n");
1382 ret = GetHandleInformation(h1, &flags);
1383 ok(ret, "GetHandleInformation failed\n");
1384 ret = WriteFile(h1, buffer2, strlen(buffer2), &written, 0);
1385 ok(ret, "WriteFile failed\n");
1386
1387 ret = fclose(stdout);
1388 ok(ret != 0, "fclose should fail\n");
1389 ret = GetHandleInformation(h1, &flags);
1390 ok(ret, "GetHandleInformation failed\n");
1391 ret = WriteFile(h1, buffer3, strlen(buffer3), &written, 0);
1392 ok(ret, "WriteFile failed\n");
1393
1394 ret = fclose(stderr);
1395 ok(ret == 0, "fclose failed\n");
1396 ret = GetHandleInformation(h1, &flags);
1397 ok(!ret, "GetHandleInformation should fail\n");
1398 ret = WriteFile(h1, buffer4, strlen(buffer4), &written, 0);
1399 ok(!ret, "WriteFile should fail\n");
1400 }
1401
1402 static void create_io_inherit_block( STARTUPINFOA *startup, unsigned int count, const HANDLE *handles )
1403 {
1404 static BYTE block[1024];
1405 BYTE *wxflag_ptr;
1406 HANDLE *handle_ptr;
1407 unsigned int i;
1408
1409 startup->lpReserved2 = block;
1410 startup->cbReserved2 = sizeof(unsigned) + (sizeof(char) + sizeof(HANDLE)) * count;
1411 wxflag_ptr = block + sizeof(unsigned);
1412 handle_ptr = (HANDLE *)(wxflag_ptr + count);
1413
1414 *(unsigned*)block = count;
1415 for (i = 0; i < count; i++)
1416 {
1417 wxflag_ptr[i] = 0x81;
1418 handle_ptr[i] = handles[i];
1419 }
1420 }
1421
1422 static const char *read_file( HANDLE file )
1423 {
1424 static char buffer[128];
1425 DWORD ret;
1426 SetFilePointer( file, 0, NULL, FILE_BEGIN );
1427 if (!ReadFile( file, buffer, sizeof(buffer) - 1, &ret, NULL)) ret = 0;
1428 buffer[ret] = 0;
1429 return buffer;
1430 }
1431
1432 static void test_stdout_handle( STARTUPINFOA *startup, char *cmdline, HANDLE hstdout, BOOL expect_stdout,
1433 const char *descr )
1434 {
1435 const char *data;
1436 HANDLE hErrorFile;
1437 SECURITY_ATTRIBUTES sa;
1438 PROCESS_INFORMATION proc;
1439
1440 /* make file handle inheritable */
1441 sa.nLength = sizeof(sa);
1442 sa.lpSecurityDescriptor = NULL;
1443 sa.bInheritHandle = TRUE;
1444
1445 hErrorFile = CreateFileA( "fdopen.err", GENERIC_READ|GENERIC_WRITE,
1446 FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL );
1447 startup->dwFlags = STARTF_USESTDHANDLES;
1448 startup->hStdInput = GetStdHandle( STD_INPUT_HANDLE );
1449 startup->hStdOutput = hErrorFile;
1450 startup->hStdError = GetStdHandle( STD_ERROR_HANDLE );
1451
1452 CreateProcessA( NULL, cmdline, NULL, NULL, TRUE,
1453 CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, NULL, NULL, startup, &proc );
1454 winetest_wait_child_process( proc.hProcess );
1455
1456 data = read_file( hErrorFile );
1457 if (expect_stdout)
1458 ok( strcmp( data, "Success" ), "%s: Error file shouldn't contain data\n", descr );
1459 else
1460 ok( !strcmp( data, "Success" ), "%s: Wrong error data (%s)\n", descr, data );
1461
1462 if (hstdout)
1463 {
1464 data = read_file( hstdout );
1465 if (expect_stdout)
1466 ok( !strcmp( data, "Success" ), "%s: Wrong stdout data (%s)\n", descr, data );
1467 else
1468 ok( strcmp( data, "Success" ), "%s: Stdout file shouldn't contain data\n", descr );
1469 }
1470
1471 CloseHandle( hErrorFile );
1472 DeleteFileA( "fdopen.err" );
1473 }
1474
1475 static void test_file_refcount( STARTUPINFOA *startup, char *cmdline, const char *descr )
1476 {
1477 const char *data;
1478 HANDLE hMixFile;
1479 SECURITY_ATTRIBUTES sa;
1480 PROCESS_INFORMATION proc;
1481
1482 /* make file handle inheritable */
1483 sa.nLength = sizeof(sa);
1484 sa.lpSecurityDescriptor = NULL;
1485 sa.bInheritHandle = TRUE;
1486
1487 hMixFile = CreateFileA( "fdopen.mix", GENERIC_READ|GENERIC_WRITE,
1488 FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL );
1489 startup->dwFlags = STARTF_USESTDHANDLES;
1490 startup->hStdInput = hMixFile;
1491 startup->hStdOutput = hMixFile;
1492 startup->hStdError = hMixFile;
1493
1494 CreateProcessA( NULL, cmdline, NULL, NULL, TRUE,
1495 CREATE_DEFAULT_ERROR_MODE | NORMAL_PRIORITY_CLASS, NULL, NULL, startup, &proc );
1496 winetest_wait_child_process( proc.hProcess );
1497
1498 data = read_file( hMixFile );
1499 ok( !strcmp( data, "test1test2test3" ), "%s: Wrong error data (%s)\n", descr, data );
1500
1501 CloseHandle( hMixFile );
1502 DeleteFileA( "fdopen.mix" );
1503 }
1504
1505 static void test_file_inherit( const char* selfname )
1506 {
1507 int fd;
1508 const char* arg_v[5];
1509 char buffer[16];
1510 char cmdline[MAX_PATH];
1511 STARTUPINFOA startup;
1512 SECURITY_ATTRIBUTES sa;
1513 HANDLE handles[3];
1514
1515 fd = open ("fdopen.tst", O_CREAT | O_RDWR | O_BINARY, _S_IREAD |_S_IWRITE);
1516 ok(fd != -1, "Couldn't create test file\n");
1517 arg_v[0] = get_base_name(selfname);
1518 arg_v[1] = "tests/file.c";
1519 arg_v[2] = "inherit";
1520 arg_v[3] = buffer; sprintf(buffer, "%d", fd);
1521 arg_v[4] = 0;
1522 _spawnvp(_P_WAIT, selfname, arg_v);
1523 ok(tell(fd) == 8, "bad position %u expecting 8\n", tell(fd));
1524 lseek(fd, 0, SEEK_SET);
1525 ok(read(fd, buffer, sizeof (buffer)) == 8 && memcmp(buffer, "Success", 8) == 0, "Couldn't read back the data\n");
1526 close (fd);
1527 ok(unlink("fdopen.tst") == 0, "Couldn't unlink\n");
1528
1529 fd = open ("fdopen.tst", O_CREAT | O_RDWR | O_BINARY | O_NOINHERIT, _S_IREAD |_S_IWRITE);
1530 ok(fd != -1, "Couldn't create test file\n");
1531 arg_v[1] = "tests/file.c";
1532 arg_v[2] = "inherit_no";
1533 arg_v[3] = buffer; sprintf(buffer, "%d", fd);
1534 arg_v[4] = 0;
1535 _spawnvp(_P_WAIT, selfname, arg_v);
1536 ok(tell(fd) == 0, "bad position %u expecting 0\n", tell(fd));
1537 ok(read(fd, buffer, sizeof (buffer)) == 0, "Found unexpected data (%s)\n", buffer);
1538 close (fd);
1539 ok(unlink("fdopen.tst") == 0, "Couldn't unlink\n");
1540
1541 /* make file handle inheritable */
1542 sa.nLength = sizeof(sa);
1543 sa.lpSecurityDescriptor = NULL;
1544 sa.bInheritHandle = TRUE;
1545 sprintf(cmdline, "%s file inherit 1", selfname);
1546
1547 /* init an empty Reserved2, which should not be recognized as inherit-block */
1548 ZeroMemory(&startup, sizeof(startup));
1549 startup.cb = sizeof(startup);
1550 create_io_inherit_block( &startup, 0, NULL );
1551 test_stdout_handle( &startup, cmdline, 0, FALSE, "empty block" );
1552
1553 /* test with valid inheritblock */
1554 handles[0] = GetStdHandle( STD_INPUT_HANDLE );
1555 handles[1] = CreateFileA( "fdopen.tst", GENERIC_READ|GENERIC_WRITE,
1556 FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL );
1557 handles[2] = GetStdHandle( STD_ERROR_HANDLE );
1558 create_io_inherit_block( &startup, 3, handles );
1559 test_stdout_handle( &startup, cmdline, handles[1], TRUE, "valid block" );
1560 CloseHandle( handles[1] );
1561 DeleteFileA("fdopen.tst");
1562
1563 /* test inherit block starting with unsigned zero */
1564 handles[1] = CreateFileA( "fdopen.tst", GENERIC_READ|GENERIC_WRITE,
1565 FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL );
1566 create_io_inherit_block( &startup, 3, handles );
1567 *(unsigned int *)startup.lpReserved2 = 0;
1568 test_stdout_handle( &startup, cmdline, handles[1], FALSE, "zero count block" );
1569 CloseHandle( handles[1] );
1570 DeleteFileA("fdopen.tst");
1571
1572 /* test inherit block with smaller size */
1573 handles[1] = CreateFileA( "fdopen.tst", GENERIC_READ|GENERIC_WRITE,
1574 FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL );
1575 create_io_inherit_block( &startup, 3, handles );
1576 startup.cbReserved2 -= 3;
1577 test_stdout_handle( &startup, cmdline, handles[1], TRUE, "small size block" );
1578 CloseHandle( handles[1] );
1579 DeleteFileA("fdopen.tst");
1580
1581 /* test inherit block with even smaller size */
1582 handles[1] = CreateFileA( "fdopen.tst", GENERIC_READ|GENERIC_WRITE,
1583 FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL );
1584 create_io_inherit_block( &startup, 3, handles );
1585 startup.cbReserved2 = sizeof(unsigned int) + sizeof(HANDLE) + sizeof(char);
1586 test_stdout_handle( &startup, cmdline, handles[1], FALSE, "smaller size block" );
1587 CloseHandle( handles[1] );
1588 DeleteFileA("fdopen.tst");
1589
1590 /* test inherit block with larger size */
1591 handles[1] = CreateFileA( "fdopen.tst", GENERIC_READ|GENERIC_WRITE,
1592 FILE_SHARE_READ | FILE_SHARE_WRITE, &sa, CREATE_ALWAYS, 0, NULL );
1593 create_io_inherit_block( &startup, 3, handles );
1594 startup.cbReserved2 += 7;
1595 test_stdout_handle( &startup, cmdline, handles[1], TRUE, "large size block" );
1596 CloseHandle( handles[1] );
1597 DeleteFileA("fdopen.tst");
1598
1599 /* test refcount of handles */
1600 create_io_inherit_block( &startup, 0, NULL );
1601 sprintf(cmdline, "%s file refcount", selfname);
1602 test_file_refcount( &startup, cmdline, "file refcount" );
1603 DeleteFileA("fdopen.tst");
1604 }
1605
1606 static void test_tmpnam( void )
1607 {
1608 char name[MAX_PATH] = "abc";
1609 char *res;
1610
1611 res = tmpnam(NULL);
1612 ok(res != NULL, "tmpnam returned NULL\n");
1613 ok(res[0] == '\\', "first character is not a backslash\n");
1614 ok(strchr(res+1, '\\') == 0, "file not in the root directory\n");
1615 ok(res[strlen(res)-1] == '.', "first call - last character is not a dot\n");
1616
1617 res = tmpnam(name);
1618 ok(res != NULL, "tmpnam returned NULL\n");
1619 ok(res == name, "supplied buffer was not used\n");
1620 ok(res[0] == '\\', "first character is not a backslash\n");
1621 ok(strchr(res+1, '\\') == 0, "file not in the root directory\n");
1622 ok(res[strlen(res)-1] != '.', "second call - last character is a dot\n");
1623 }
1624
1625 static void test_chsize( void )
1626 {
1627 int fd;
1628 LONG cur, pos, count;
1629 char temptext[] = "012345678";
1630 char *tempfile = _tempnam( ".", "tst" );
1631
1632 ok( tempfile != NULL, "Couldn't create test file: %s\n", tempfile );
1633
1634 fd = _open( tempfile, _O_CREAT|_O_TRUNC|_O_RDWR, _S_IREAD|_S_IWRITE );
1635 ok( fd > 0, "Couldn't open test file\n" );
1636
1637 count = _write( fd, temptext, sizeof(temptext) );
1638 ok( count > 0, "Couldn't write to test file\n" );
1639
1640 /* get current file pointer */
1641 cur = _lseek( fd, 0, SEEK_CUR );
1642
1643 /* make the file smaller */
1644 ok( _chsize( fd, sizeof(temptext) / 2 ) == 0, "_chsize() failed\n" );
1645
1646 pos = _lseek( fd, 0, SEEK_CUR );
1647 ok( cur == pos, "File pointer changed from: %d to: %d\n", cur, pos );
1648 ok( _filelength( fd ) == sizeof(temptext) / 2, "Wrong file size\n" );
1649
1650 /* enlarge the file */
1651 ok( _chsize( fd, sizeof(temptext) * 2 ) == 0, "_chsize() failed\n" );
1652
1653 pos = _lseek( fd, 0, SEEK_CUR );
1654 ok( cur == pos, "File pointer changed from: %d to: %d\n", cur, pos );
1655 ok( _filelength( fd ) == sizeof(temptext) * 2, "Wrong file size\n" );
1656
1657 _close( fd );
1658 _unlink( tempfile );
1659 free( tempfile );
1660 }
1661
1662 static void test_fopen_fclose_fcloseall( void )
1663 {
1664 char fname1[] = "empty1";
1665 char fname2[] = "empty2";
1666 char fname3[] = "empty3";
1667 FILE *stream1, *stream2, *stream3, *stream4;
1668 int ret, numclosed;
1669
1670 /* testing fopen() */
1671 stream1 = fopen(fname1, "w+");
1672 ok(stream1 != NULL, "The file '%s' was not opened\n", fname1);
1673 stream2 = fopen(fname2, "w ");
1674 ok(stream2 != NULL, "The file '%s' was not opened\n", fname2 );
1675 _unlink(fname3);
1676 stream3 = fopen(fname3, "r");
1677 ok(stream3 == NULL, "The file '%s' shouldn't exist before\n", fname3 );
1678 stream3 = fopen(fname3, "w+");
1679 ok(stream3 != NULL, "The file '%s' should be opened now\n", fname3 );
1680 errno = 0xfaceabad;
1681 stream4 = fopen("", "w+");
1682 ok(stream4 == NULL && (errno == EINVAL || errno == ENOENT),
1683 "filename is empty, errno = %d (expected 2 or 22)\n", errno);
1684 errno = 0xfaceabad;
1685 stream4 = fopen(NULL, "w+");
1686 ok(stream4 == NULL && (errno == EINVAL || errno == ENOENT),
1687 "filename is NULL, errno = %d (expected 2 or 22)\n", errno);
1688
1689 /* testing fclose() */
1690 ret = fclose(stream2);
1691 ok(ret == 0, "The file '%s' was not closed\n", fname2);
1692 ret = fclose(stream3);
1693 ok(ret == 0, "The file '%s' was not closed\n", fname3);
1694 ret = fclose(stream2);
1695 ok(ret == EOF, "Closing file '%s' returned %d\n", fname2, ret);
1696 ret = fclose(stream3);
1697 ok(ret == EOF, "Closing file '%s' returned %d\n", fname3, ret);
1698
1699 /* testing fcloseall() */
1700 numclosed = _fcloseall();
1701 /* fname1 should be closed here */
1702 ok(numclosed == 1, "Number of files closed by fcloseall(): %u\n", numclosed);
1703 numclosed = _fcloseall();
1704 ok(numclosed == 0, "Number of files closed by fcloseall(): %u\n", numclosed);
1705
1706 ok(_unlink(fname1) == 0, "Couldn't unlink file named '%s'\n", fname1);
1707 ok(_unlink(fname2) == 0, "Couldn't unlink file named '%s'\n", fname2);
1708 ok(_unlink(fname3) == 0, "Couldn't unlink file named '%s'\n", fname3);
1709 }
1710
1711 static void test_fopen_s( void )
1712 {
1713 const char name[] = "empty1";
1714 char buff[16];
1715 unsigned char *ubuff = (unsigned char*)buff;
1716 FILE *file, *file2;
1717 int ret;
1718 int len;
1719
1720 if (!p_fopen_s)
1721 {
1722 win_skip("Skipping fopen_s test\n");
1723 return;
1724 }
1725 /* testing fopen_s */
1726 ret = p_fopen_s(&file, name, "w");
1727 ok(ret == 0, "fopen_s failed with %d\n", ret);
1728 ok(file != 0, "fopen_s failed to return value\n");
1729 fwrite(name, sizeof(name), 1, file);
1730
1731 ret = fclose(file);
1732 ok(ret != EOF, "File failed to close\n");
1733
1734 file = fopen(name, "r");
1735 ok(file != 0, "fopen failed\n");
1736 len = fread(buff, 1, sizeof(name), file);
1737 ok(len == sizeof(name), "File length is %d\n", len);
1738 buff[sizeof(name)] = '\0';
1739 ok(strcmp(name, buff) == 0, "File content mismatch! Got %s, expected %s\n", buff, name);
1740
1741 ret = fclose(file);
1742 ok(ret != EOF, "File failed to close\n");
1743
1744 ret = p_fopen_s(&file, name, "w, ccs=UNIcode");
1745 ok(ret == 0, "fopen_s failed with %d\n", ret);
1746 ret = fwrite("a", 1, 2, file);
1747 ok(ret == 2, "fwrite returned %d\n", ret);
1748 fclose(file);
1749
1750 ret = p_fopen_s(&file, name, "r");
1751 ok(ret == 0, "fopen_s failed with %d\n", ret);
1752 len = fread(buff, 1, 2, file);
1753 ok(len == 2, "len = %d\n", len);
1754 ok(ubuff[0]==0xff && ubuff[1]==0xfe, "buff[0]=%02x, buff[1]=%02x\n",
1755 ubuff[0], ubuff[1]);
1756 fclose(file);
1757
1758 ret = p_fopen_s(&file, name, "r,ccs=unicode");
1759 ok(ret == 0, "fopen_s failed with %d\n", ret);
1760 len = fread(buff, 1, 2, file);
1761 ok(len == 2, "len = %d\n", len);
1762 ok(ubuff[0]=='a' && ubuff[1]==0, "buff[0]=%02x, buff[1]=%02x\n",
1763 ubuff[0], ubuff[1]);
1764 fclose(file);
1765
1766 ret = p_fopen_s(&file, name, "r,ccs=utf-16le");
1767 ok(ret == 0, "fopen_s failed with %d\n", ret);
1768 len = fread(buff, 1, 2, file);
1769 ok(len == 2, "len = %d\n", len);
1770 ok(ubuff[0]=='a' && ubuff[1]==0, "buff[0]=%02x, buff[1]=%02x\n",
1771 ubuff[0], ubuff[1]);
1772 fclose(file);
1773
1774 ret = p_fopen_s(&file, name, "r,ccs=utf-8");
1775 ok(ret == 0, "fopen_s failed with %d\n", ret);
1776 len = fread(buff, 1, 2, file);
1777 ok(len == 2, "len = %d\n", len);
1778 ok(ubuff[0]=='a' && ubuff[1]==0, "buff[0]=%02x, buff[1]=%02x\n",
1779 ubuff[0], ubuff[1]);
1780 fclose(file);
1781
1782 ret = p_fopen_s(&file, name, "w,ccs=utf-16le");
1783 ok(ret == 0, "fopen_s failed with %d\n", ret);
1784 fclose(file);
1785
1786 ret = p_fopen_s(&file, name, "r");
1787 ok(ret == 0, "fopen_s failed with %d\n", ret);
1788 len = fread(buff, 1, 3, file);
1789 ok(len == 2, "len = %d\n", len);
1790 ok(ubuff[0]==0xff && ubuff[1]==0xfe, "buff[0]=%02x, buff[1]=%02x\n",
1791 ubuff[0], ubuff[1]);
1792 fclose(file);
1793
1794 ret = p_fopen_s(&file, name, "w,ccs=utf-8");
1795 ok(ret == 0, "fopen_s failed with %d\n", ret);
1796 fclose(file);
1797
1798 ret = p_fopen_s(&file, name, "r");
1799 ok(ret == 0, "fopen_s failed with %d\n", ret);
1800 len = fread(buff, 1, 4, file);
1801 ok(len == 3, "len = %d\n", len);
1802 ok(ubuff[0]==0xef && ubuff[1]==0xbb && ubuff[2]==0xbf,
1803 "buff[0]=%02x, buff[1]=%02x, buff[2]=%02x\n",
1804 ubuff[0], ubuff[1], ubuff[2]);
1805 fclose(file);
1806
1807 /* test initial FILE values */
1808 memset(file, 0xfe, sizeof(*file));
1809 file->_flag = 0;
1810 ret = p_fopen_s(&file2, name, "r");
1811 ok(!ret, "fopen_s failed with %d\n", ret);
1812 ok(file == file2, "file != file2 %p %p\n", file, file2);
1813 ok(!file->_ptr, "file->_ptr != NULL\n");
1814 ok(!file->_cnt, "file->_cnt != 0\n");
1815 ok(!file->_base, "file->_base != NULL\n");
1816 ok(file->_flag == 1, "file->_flag = %x\n", file->_flag);
1817 ok(file->_file, "file->_file == 0\n");
1818 ok(file->_charbuf == 0xfefefefe, "file->_charbuf = %x\n", file->_charbuf);
1819 ok(file->_bufsiz == 0xfefefefe, "file->_bufsiz = %x\n", file->_bufsiz);
1820 ok(!file->_tmpfname, "file->_tmpfname != NULL\n");
1821 fclose(file2);
1822
1823 ok(_unlink(name) == 0, "Couldn't unlink file named '%s'\n", name);
1824 }
1825
1826 static void test__wfopen_s( void )
1827 {
1828 const char name[] = "empty1";
1829 const WCHAR wname[] = {
1830 'e','m','p','t','y','1',0
1831 };
1832 const WCHAR wmode[] = {
1833 'w',0
1834 };
1835 char buff[16];
1836 FILE *file;
1837 int ret;
1838 int len;
1839
1840 if (!p__wfopen_s)
1841 {
1842 win_skip("Skipping _wfopen_s test\n");
1843 return;
1844 }
1845 /* testing _wfopen_s */
1846 ret = p__wfopen_s(&file, wname, wmode);
1847 ok(ret == 0, "_wfopen_s failed with %d\n", ret);
1848 ok(file != 0, "_wfopen_s failed to return value\n");
1849 fwrite(name, sizeof(name), 1, file);
1850
1851 ret = fclose(file);
1852 ok(ret != EOF, "File failed to close\n");
1853
1854 file = fopen(name, "r");
1855 ok(file != 0, "fopen failed\n");
1856 len = fread(buff, 1, sizeof(name), file);
1857 ok(len == sizeof(name), "File length is %d\n", len);
1858 buff[sizeof(name)] = '\0';
1859 ok(strcmp(name, buff) == 0, "File content mismatch! Got %s, expected %s\n", buff, name);
1860
1861 ret = fclose(file);
1862 ok(ret != EOF, "File failed to close\n");
1863
1864 ok(_unlink(name) == 0, "Couldn't unlink file named '%s'\n", name);
1865 }
1866
1867 static void test_setmode(void)
1868 {
1869 const char name[] = "empty1";
1870 int fd, ret;
1871
1872 if(!p_fopen_s) {
1873 win_skip("unicode file modes are not available, skipping setmode tests\n");
1874 return;
1875 }
1876
1877 errno = 0xdeadbeef;
1878 ret = _setmode(-2, 0);
1879 ok(ret == -1, "_setmode returned %x, expected -1\n", ret);
1880 ok(errno == EINVAL, "errno = %d\n", errno);
1881
1882 errno = 0xdeadbeef;
1883 ret = _setmode(-2, _O_TEXT);
1884 ok(ret == -1, "_setmode returned %x, expected -1\n", ret);
1885 ok(errno == EBADF, "errno = %d\n", errno);
1886
1887 fd = _open(name, _O_CREAT|_O_WRONLY, _S_IWRITE);
1888 ok(fd != -1, "failed to open file\n");
1889
1890 errno = 0xdeadbeef;
1891 ret = _setmode(fd, 0xffffffff);
1892 ok(ret == -1, "_setmode returned %x, expected -1\n", ret);
1893 ok(errno == EINVAL, "errno = %d\n", errno);
1894
1895 errno = 0xdeadbeef;
1896 ret = _setmode(fd, 0);
1897 ok(ret == -1, "_setmode returned %x, expected -1\n", ret);
1898 ok(errno == EINVAL, "errno = %d\n", errno);
1899
1900 errno = 0xdeadbeef;
1901 ret = _setmode(fd, _O_BINARY|_O_TEXT);
1902 ok(ret == -1, "_setmode returned %x, expected -1\n", ret);
1903 ok(errno == EINVAL, "errno = %d\n", errno);
1904
1905 errno = 0xdeadbeef;
1906 ret = _setmode(fd, _O_WTEXT|_O_U16TEXT);
1907 ok(ret == -1, "_setmode returned %x, expected -1\n", ret);
1908 ok(errno == EINVAL, "errno = %d\n", errno);
1909
1910 ret = _setmode(fd, _O_BINARY);
1911 ok(ret == _O_TEXT, "_setmode returned %x, expected _O_TEXT\n", ret);
1912
1913 ret = _setmode(fd, _O_WTEXT);
1914 ok(ret == _O_BINARY, "_setmode returned %x, expected _O_BINARY\n", ret);
1915
1916 ret = _setmode(fd, _O_TEXT);
1917 ok(ret == _O_WTEXT, "_setmode returned %x, expected _O_WTEXT\n", ret);
1918
1919 ret = _setmode(fd, _O_U16TEXT);
1920 ok(ret == _O_TEXT, "_setmode returned %x, expected _O_TEXT\n", ret);
1921
1922 ret = _setmode(fd, _O_U8TEXT);
1923 ok(ret == _O_WTEXT, "_setmode returned %x, expected _O_WTEXT\n", ret);
1924
1925 ret = _setmode(fd, _O_TEXT);
1926 ok(ret == _O_WTEXT, "_setmode returned %x, expected _O_WTEXT\n", ret);
1927
1928 _close(fd);
1929 _unlink(name);
1930 }
1931
1932 static void test_get_osfhandle(void)
1933 {
1934 int fd;
1935 char fname[] = "t_get_osfhanle";
1936 DWORD bytes_written;
1937 HANDLE handle;
1938
1939 fd = _sopen(fname, _O_CREAT|_O_RDWR, _SH_DENYRW, _S_IREAD | _S_IWRITE);
1940 handle = (HANDLE)_get_osfhandle(fd);
1941 WriteFile(handle, "bar", 3, &bytes_written, NULL);
1942 _close(fd);
1943 fd = _open(fname, _O_RDONLY, 0);
1944 ok(fd != -1, "Couldn't open '%s' after _get_osfhandle()\n", fname);
1945
1946 _close(fd);
1947 _unlink(fname);
1948
1949 errno = 0xdeadbeef;
1950 handle = (HANDLE)_get_osfhandle(fd);
1951 ok(handle == INVALID_HANDLE_VALUE, "_get_osfhandle returned %p\n", handle);
1952 ok(errno == EBADF, "errno = %d\n", errno);
1953 }
1954
1955 static void test_setmaxstdio(void)
1956 {
1957 ok(2048 == _setmaxstdio(2048),"_setmaxstdio returned %d instead of 2048\n",_setmaxstdio(2048));
1958 ok(-1 == _setmaxstdio(2049),"_setmaxstdio returned %d instead of -1\n",_setmaxstdio(2049));
1959 }
1960
1961 static void test_stat(void)
1962 {
1963 int fd;
1964 int pipes[2];
1965 int ret;
1966 struct stat buf;
1967
1968 /* Tests for a file */
1969 fd = open("stat.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE);
1970 if (fd >= 0)
1971 {
1972 ret = fstat(fd, &buf);
1973 ok(!ret, "fstat failed: errno=%d\n", errno);
1974 ok((buf.st_mode & _S_IFMT) == _S_IFREG, "bad format = %06o\n", buf.st_mode);
1975 ok((buf.st_mode & 0777) == 0666, "bad st_mode = %06o\n", buf.st_mode);
1976 ok(buf.st_dev == 0, "st_dev is %d, expected 0\n", buf.st_dev);
1977 ok(buf.st_dev == buf.st_rdev, "st_dev (%d) and st_rdev (%d) differ\n", buf.st_dev, buf.st_rdev);
1978 ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink);
1979 ok(buf.st_size == 0, "st_size is %d, expected 0\n", buf.st_size);
1980
1981 ret = stat("stat.tst", &buf);
1982 ok(!ret, "stat failed: errno=%d\n", errno);
1983 ok((buf.st_mode & _S_IFMT) == _S_IFREG, "bad format = %06o\n", buf.st_mode);
1984 ok((buf.st_mode & 0777) == 0666, "bad st_mode = %06o\n", buf.st_mode);
1985 ok(buf.st_dev == buf.st_rdev, "st_dev (%d) and st_rdev (%d) differ\n", buf.st_dev, buf.st_rdev);
1986 ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink);
1987 ok(buf.st_size == 0, "st_size is %d, expected 0\n", buf.st_size);
1988
1989 errno = 0xdeadbeef;
1990 ret = stat("stat.tst\\", &buf);
1991 ok(ret == -1, "stat returned %d\n", ret);
1992 ok(errno == ENOENT, "errno = %d\n", errno);
1993
1994 close(fd);
1995 remove("stat.tst");
1996 }
1997 else
1998 skip("open failed with errno %d\n", errno);
1999
2000 /* Tests for a char device */
2001 if (_dup2(0, 10) == 0)
2002 {
2003 ret = fstat(10, &buf);
2004 ok(!ret, "fstat(stdin) failed: errno=%d\n", errno);
2005 if ((buf.st_mode & _S_IFMT) == _S_IFCHR)
2006 {
2007 ok(buf.st_mode == _S_IFCHR, "bad st_mode=%06o\n", buf.st_mode);
2008 ok(buf.st_dev == 10, "st_dev is %d, expected 10\n", buf.st_dev);
2009 ok(buf.st_rdev == 10, "st_rdev is %d, expected 10\n", buf.st_rdev);
2010 ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink);
2011 }
2012 else
2013 skip("stdin is not a char device? st_mode=%06o\n", buf.st_mode);
2014 close(10);
2015 }
2016 else
2017 skip("_dup2 failed with errno %d\n", errno);
2018
2019 /* Tests for pipes */
2020 if (_pipe(pipes, 1024, O_BINARY) == 0)
2021 {
2022 ret = fstat(pipes[0], &buf);
2023 ok(!ret, "fstat(pipe) failed: errno=%d\n", errno);
2024 ok(buf.st_mode == _S_IFIFO, "bad st_mode=%06o\n", buf.st_mode);
2025 ok(buf.st_dev == pipes[0], "st_dev is %d, expected %d\n", buf.st_dev, pipes[0]);
2026 ok(buf.st_rdev == pipes[0], "st_rdev is %d, expected %d\n", buf.st_rdev, pipes[0]);
2027 ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink);
2028 close(pipes[0]);
2029 close(pipes[1]);
2030 }
2031 else
2032 skip("pipe failed with errno %d\n", errno);
2033
2034 /* Tests for directory */
2035 if(mkdir("stat.tst") == 0)
2036 {
2037 ret = stat("stat.tst ", &buf);
2038 ok(!ret, "stat(directory) failed: errno=%d\n", errno);
2039 ok((buf.st_mode & _S_IFMT) == _S_IFDIR, "bad format = %06o\n", buf.st_mode);
2040 ok((buf.st_mode & 0777) == 0777, "bad st_mode = %06o\n", buf.st_mode);
2041 ok(buf.st_dev == buf.st_rdev, "st_dev (%d) and st_rdev (%d) differ\n", buf.st_dev, buf.st_rdev);
2042 ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink);
2043
2044 errno = 0xdeadbeef;
2045 ret = stat("stat.tst\\ ", &buf);
2046 ok(ret == -1, "stat returned %d\n", ret);
2047 ok(errno == ENOENT, "errno = %d\n", errno);
2048 rmdir( "stat.tst" );
2049 }
2050 else
2051 skip("mkdir failed with errno %d\n", errno);
2052
2053 errno = 0xdeadbeef;
2054 ret = stat("c:", &buf);
2055 ok(ret == -1, "stat returned %d\n", ret);
2056 ok(errno == ENOENT, "errno = %d\n", errno);
2057
2058 ret = stat("c:/", &buf);
2059 ok(!ret, "stat returned %d\n", ret);
2060 ok(buf.st_dev == 2, "st_dev = %d\n", buf.st_dev);
2061 ok(buf.st_rdev == 2, "st_rdev = %d\n", buf.st_rdev);
2062 }
2063
2064 static const char* pipe_string="Hello world";
2065
2066 /* How many messages to transfer over the pipe */
2067 #define N_TEST_MESSAGES 3
2068
2069 static void test_pipes_child(int argc, char** args)
2070 {
2071 int fd;
2072 int nwritten;
2073 int i;
2074
2075 if (argc < 5)
2076 {
2077 ok(0, "not enough parameters: %d\n", argc);
2078 return;
2079 }
2080
2081 fd=atoi(args[3]);
2082 i=close(fd);
2083 ok(!i, "unable to close %d: %d\n", fd, errno);
2084
2085 fd=atoi(args[4]);
2086
2087 for (i=0; i<N_TEST_MESSAGES; i++) {
2088 nwritten=write(fd, pipe_string, strlen(pipe_string));
2089 ok(nwritten == strlen(pipe_string), "i %d, expected to write '%s' wrote %d\n", i, pipe_string, nwritten);
2090 /* let other process wake up so they can show off their "keep reading until EOF" behavior */
2091 if (i < N_TEST_MESSAGES-1)
2092 Sleep(100);
2093 }
2094
2095 i=close(fd);
2096 ok(!i, "unable to close %d: %d\n", fd, errno);
2097 }
2098
2099 static void test_pipes(const char* selfname)
2100 {
2101 int pipes[2];
2102 char str_fdr[12], str_fdw[12];
2103 FILE* file;
2104 const char* arg_v[6];
2105 char buf[4096];
2106 char expected[4096];
2107 int r;
2108 int i;
2109
2110 /* Test reading from a pipe with read() */
2111 if (_pipe(pipes, 1024, O_BINARY) < 0)
2112 {
2113 ok(0, "pipe failed with errno %d\n", errno);
2114 return;
2115 }
2116
2117 arg_v[0] = get_base_name(selfname);
2118 arg_v[1] = "tests/file.c";
2119 arg_v[2] = "pipes";
2120 arg_v[3] = str_fdr; sprintf(str_fdr, "%d", pipes[0]);
2121 arg_v[4] = str_fdw; sprintf(str_fdw, "%d", pipes[1]);
2122 arg_v[5] = NULL;
2123 proc_handles[0] = (HANDLE)_spawnvp(_P_NOWAIT, selfname, arg_v);
2124 i=close(pipes[1]);
2125 ok(!i, "unable to close %d: %d\n", pipes[1], errno);
2126
2127 for (i=0; i<N_TEST_MESSAGES; i++) {
2128 r=read(pipes[0], buf, sizeof(buf)-1);
2129 ok(r == strlen(pipe_string), "i %d, got %d\n", i, r);
2130 if (r > 0)
2131 buf[r]='\0';
2132 ok(strcmp(buf, pipe_string) == 0, "expected to read '%s', got '%s'\n", pipe_string, buf);
2133 }
2134
2135 r=read(pipes[0], buf, sizeof(buf)-1);
2136 ok(r == 0, "expected to read 0 bytes, got %d\n", r);
2137 i=close(pipes[0]);
2138 ok(!i, "unable to close %d: %d\n", pipes[0], errno);
2139
2140 /* Test reading from a pipe with fread() */
2141 if (_pipe(pipes, 1024, O_BINARY) < 0)
2142 {
2143 ok(0, "pipe failed with errno %d\n", errno);
2144 return;
2145 }
2146
2147 arg_v[1] = "tests/file.c";
2148 arg_v[2] = "pipes";
2149 arg_v[3] = str_fdr; sprintf(str_fdr, "%d", pipes[0]);
2150 arg_v[4] = str_fdw; sprintf(str_fdw, "%d", pipes[1]);
2151 arg_v[5] = NULL;
2152 proc_handles[1] = (HANDLE)_spawnvp(_P_NOWAIT, selfname, arg_v);
2153 i=close(pipes[1]);
2154 ok(!i, "unable to close %d: %d\n", pipes[1], errno);
2155 file=fdopen(pipes[0], "r");
2156
2157 /* In blocking mode, fread will keep calling read() until it gets
2158 * enough bytes, or EOF, even on Unix. (If this were a Unix terminal
2159 * in cooked mode instead of a pipe, it would also stop on EOL.)
2160 */
2161 expected[0] = 0;
2162 for (i=0; i<N_TEST_MESSAGES; i++)
2163 strcat(expected, pipe_string);
2164 r=fread(buf, 1, sizeof(buf)-1, file);
2165 ok(r == strlen(expected), "fread() returned %d: ferror=%d\n", r, ferror(file));
2166 if (r > 0)
2167 buf[r]='\0';
2168 ok(strcmp(buf, expected) == 0, "got '%s' expected '%s'\n", buf, expected);
2169
2170 /* Let child close the file before we read, so we can sense EOF reliably */
2171 Sleep(100);
2172 r=fread(buf, 1, sizeof(buf)-1, file);
2173 ok(r == 0, "fread() returned %d instead of 0\n", r);
2174 ok(ferror(file) == 0, "got ferror() = %d\n", ferror(file));
2175 ok(feof(file), "feof() is false!\n");
2176
2177 i=fclose(file);
2178 ok(!i, "unable to close the pipe: %d\n", errno);
2179
2180 /* test \r handling when it's the last character read */
2181 if (_pipe(pipes, 1024, O_BINARY) < 0)
2182 {
2183 ok(0, "pipe failed with errno %d\n", errno);
2184 return;
2185 }
2186 r = write(pipes[1], "\r\n\rab\r\n", 7);
2187 ok(r == 7, "write returned %d, errno = %d\n", r, errno);
2188 setmode(pipes[0], O_TEXT);
2189 r = read(pipes[0], buf, 1);
2190 ok(r == 1, "read returned %d, expected 1\n", r);
2191 ok(buf[0] == '\n', "buf[0] = %x, expected '\\n'\n", buf[0]);
2192 r = read(pipes[0], buf, 1);
2193 ok(r == 1, "read returned %d, expected 1\n", r);
2194 ok(buf[0] == '\r', "buf[0] = %x, expected '\\r'\n", buf[0]);
2195 r = read(pipes[0], buf, 1);
2196 ok(r == 1, "read returned %d, expected 1\n", r);
2197 ok(buf[0] == 'a', "buf[0] = %x, expected 'a'\n", buf[0]);
2198 r = read(pipes[0], buf, 2);
2199 ok(r == 2, "read returned %d, expected 1\n", r);
2200 ok(buf[0] == 'b', "buf[0] = %x, expected 'b'\n", buf[0]);
2201 ok(buf[1] == '\n', "buf[1] = %x, expected '\\n'\n", buf[1]);
2202
2203 if (p_fopen_s)
2204 {
2205 /* test utf16 read with insufficient data */
2206 r = write(pipes[1], "a\0b", 3);
2207 ok(r == 3, "write returned %d, errno = %d\n", r, errno);
2208 buf[2] = 'z';
2209 buf[3] = 'z';
2210 setmode(pipes[0], _O_WTEXT);
2211 r = read(pipes[0], buf, 4);
2212 ok(r == 2, "read returned %d, expected 2\n", r);
2213 ok(!memcmp(buf, "a\0bz", 4), "read returned incorrect data\n");
2214 r = write(pipes[1], "\0", 1);
2215 ok(r == 1, "write returned %d, errno = %d\n", r, errno);
2216 buf[0] = 'z';
2217 buf[1] = 'z';
2218 r = read(pipes[0], buf, 2);
2219 ok(r == 0, "read returned %d, expected 0\n", r);
2220 ok(!memcmp(buf, "\0z", 2), "read returned incorrect data\n");
2221 }
2222 else
2223 {
2224 win_skip("unicode mode tests on pipe\n");
2225 }
2226
2227 close(pipes[1]);
2228 close(pipes[0]);
2229 }
2230
2231 static void test_unlink(void)
2232 {
2233 FILE* file;
2234 ok(mkdir("test_unlink") == 0, "unable to create test dir\n");
2235 file = fopen("test_unlink\\empty", "w");
2236 ok(file != NULL, "unable to create test file\n");
2237 if(file)
2238 fclose(file);
2239 ok(_unlink("test_unlink") != 0, "unlinking a non-empty directory must fail\n");
2240 unlink("test_unlink\\empty");
2241 rmdir("test_unlink");
2242 }
2243
2244 static void test_dup2(void)
2245 {
2246 ok(-1 == _dup2(0, -1), "expected _dup2 to fail when second arg is negative\n" );
2247 }
2248
2249 static void test_stdin(void)
2250 {
2251 HANDLE stdinh = GetStdHandle(STD_INPUT_HANDLE);
2252 int stdin_dup, fd;
2253 HANDLE h;
2254 DWORD r;
2255
2256 stdin_dup = _dup(STDIN_FILENO);
2257 ok(stdin_dup != -1, "_dup(STDIN_FILENO) failed\n");
2258
2259 ok(stdinh == (HANDLE)_get_osfhandle(STDIN_FILENO),
2260 "GetStdHandle(STD_INPUT_HANDLE) != _get_osfhandle(STDIN_FILENO)\n");
2261
2262 r = SetStdHandle(STD_INPUT_HANDLE, INVALID_HANDLE_VALUE);
2263 ok(r == TRUE, "SetStdHandle returned %x, expected TRUE\n", r);
2264 h = GetStdHandle(STD_INPUT_HANDLE);
2265 ok(h == INVALID_HANDLE_VALUE, "h = %p\n", h);
2266
2267 close(STDIN_FILENO);
2268 h = GetStdHandle(STD_INPUT_HANDLE);
2269 ok(h == NULL, "h != NULL\n");
2270
2271 fd = open("stdin.tst", O_WRONLY | O_CREAT, _S_IREAD |_S_IWRITE);
2272 ok(fd != -1, "open failed\n");
2273 ok(fd == STDIN_FILENO, "fd = %d, expected STDIN_FILENO\n", fd);
2274 h = GetStdHandle(STD_INPUT_HANDLE);
2275 ok(h != NULL, "h == NULL\n");
2276 close(fd);
2277 unlink("stdin.tst");
2278
2279 r = _dup2(stdin_dup, STDIN_FILENO);
2280 ok(r != -1, "_dup2 failed\n");
2281 h = GetStdHandle(STD_INPUT_HANDLE);
2282 ok(h != NULL, "h == NULL\n");
2283 }
2284
2285 static void test_mktemp(void)
2286 {
2287 char buf[16];
2288
2289 strcpy(buf, "a");
2290 ok(!_mktemp(buf), "_mktemp(\"a\") != NULL\n");
2291
2292 strcpy(buf, "testXXXXX");
2293 ok(!_mktemp(buf), "_mktemp(\"testXXXXX\") != NULL\n");
2294
2295 strcpy(buf, "testXXXXXX");
2296 ok(_mktemp(buf) != NULL, "_mktemp(\"testXXXXXX\") == NULL\n");
2297
2298 strcpy(buf, "testXXXXXXa");
2299 ok(!_mktemp(buf), "_mktemp(\"testXXXXXXa\") != NULL\n");
2300
2301 strcpy(buf, "**XXXXXX");
2302 ok(_mktemp(buf) != NULL, "_mktemp(\"**XXXXXX\") == NULL\n");
2303 }
2304
2305 static void test__open_osfhandle(void)
2306 {
2307 ioinfo *info;
2308 HANDLE h, tmp;
2309 int fd;
2310
2311 errno = 0xdeadbeef;
2312 fd = _open_osfhandle((intptr_t)INVALID_HANDLE_VALUE, 0);
2313 ok(fd == -1, "_open_osfhandle returned %d\n", fd);
2314 ok(errno == EBADF, "errno = %d\n", errno);
2315
2316 h = CreateFileA("open_osfhandle.tst", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
2317 fd = _open_osfhandle((intptr_t)h, 0);
2318 ok(fd > 0, "_open_osfhandle returned %d (%d)\n", fd, errno);
2319 info = &__pioinfo[fd/MSVCRT_FD_BLOCK_SIZE][fd%MSVCRT_FD_BLOCK_SIZE];
2320 ok(info->handle == h, "info->handle = %p, expected %p\n", info->handle, h);
2321 ok(info->wxflag == 1, "info->wxflag = %x, expected 1\n", info->wxflag);
2322 close(fd);
2323 ok(info->handle == INVALID_HANDLE_VALUE, "info->handle = %p, expected INVALID_HANDLE_VALUE\n", info->handle);
2324 ok(info->wxflag == 0, "info->wxflag = %x, expected 0\n", info->wxflag);
2325 DeleteFileA("open_osfhandle.tst");
2326
2327 errno = 0xdeadbeef;
2328 fd = _open_osfhandle((intptr_t)h, 0);
2329 ok(fd == -1, "_open_osfhandle returned %d\n", fd);
2330 ok(errno == EBADF, "errno = %d\n", errno);
2331
2332 ok(CreatePipe(&h, &tmp, NULL, 0), "CreatePipe failed\n");
2333 fd = _open_osfhandle((intptr_t)h, 0);
2334 ok(fd > 0, "_open_osfhandle returned %d (%d)\n", fd, errno);
2335 info = &__pioinfo[fd/MSVCRT_FD_BLOCK_SIZE][fd%MSVCRT_FD_BLOCK_SIZE];
2336 ok(info->handle == h, "info->handle = %p, expected %p\n", info->handle, h);
2337 ok(info->wxflag == 9, "info->wxflag = %x, expected 9\n", info->wxflag);
2338 close(fd);
2339 CloseHandle(tmp);
2340 }
2341
2342 static void test_write_flush_size(FILE *file, int bufsize)
2343 {
2344 char *inbuffer;
2345 char *outbuffer;
2346 int size, fd;
2347 fpos_t pos, pos2;
2348
2349 fd = fileno(file);
2350 inbuffer = calloc(bufsize + 1, 1);
2351 outbuffer = calloc(bufsize + 1, 1);
2352 _snprintf(outbuffer, bufsize + 1, "0,1,2,3,4,5,6,7,8,9");
2353
2354 for (size = bufsize + 1; size >= bufsize - 1; size--) {
2355 rewind(file);
2356 ok(file->_cnt == 0, "_cnt should be 0 after rewind, but is %d\n", file->_cnt);
2357 fwrite(outbuffer, 1, size, file);
2358 /* lseek() below intentionally redirects the write in fflush() to detect
2359 * if fwrite() has already flushed the whole buffer or not.
2360 */
2361 lseek(fd, 1, SEEK_SET);
2362 fflush(file);
2363 ok(file->_cnt == 0, "_cnt should be 0 after fflush, but is %d\n", file->_cnt);
2364 fseek(file, 0, SEEK_SET);
2365 ok(fread(inbuffer, 1, bufsize, file) == bufsize, "read failed\n");
2366 if (size == bufsize)
2367 ok(memcmp(outbuffer, inbuffer, bufsize) == 0, "missing flush by %d byte write\n", size);
2368 else
2369 ok(memcmp(outbuffer, inbuffer, bufsize) != 0, "unexpected flush by %d byte write\n", size);
2370 }
2371 rewind(file);
2372 fwrite(outbuffer, 1, bufsize / 2, file);
2373 fwrite(outbuffer + bufsize / 2, 1, bufsize / 2, file);
2374 lseek(fd, 1, SEEK_SET);
2375 fflush(file);
2376 fseek(file, 0, SEEK_SET);
2377 ok(fread(inbuffer, 1, bufsize, file) == bufsize, "read failed\n");
2378 ok(memcmp(outbuffer, inbuffer, bufsize) != 0, "unexpected flush by %d/2 byte double write\n", bufsize);
2379
2380 ok(!fseek(file, -1, SEEK_END), "fseek failed\n");
2381 ok(!fgetpos(file, &pos), "fgetpos failed\n");
2382 ok(fread(inbuffer, 1, 1, file) == 1, "fread failed\n");
2383 ok(file->_flag & _IOREAD, "file->_flag = %x\n", file->_flag);
2384 ok(!file->_cnt, "file->_cnt = %d\n", file->_cnt);
2385 ok(file->_ptr != file->_base, "file->_ptr == file->_base\n");
2386 ok(fwrite(outbuffer, 1, bufsize, file), "fwrite failed\n");
2387 ok(file->_flag & _IOREAD, "file->_flag = %x\n", file->_flag);
2388 ok(!file->_cnt, "file->_cnt = %d\n", file->_cnt);
2389 ok(file->_ptr == file->_base, "file->_ptr == file->_base\n");
2390 ok(!fgetpos(file, &pos2), "fgetpos failed\n");
2391 ok(pos+bufsize+1 == pos2, "pos = %d (%d)\n", (int)pos, (int)pos2);
2392 free(inbuffer);
2393 free(outbuffer);
2394 }
2395
2396 static void test_write_flush(void)
2397 {
2398 char iobuf[1024];
2399 char *tempf;
2400 FILE *file;
2401
2402 tempf = _tempnam(".","wne");
2403 file = fopen(tempf, "wb+");
2404 ok(file != NULL, "unable to create test file\n");
2405 iobuf[0] = 0;
2406 ok(file->_bufsiz == 4096, "incorrect default buffer size: %d\n", file->_bufsiz);
2407 test_write_flush_size(file, file->_bufsiz);
2408 setvbuf(file, iobuf, _IOFBF, sizeof(iobuf));
2409 test_write_flush_size(file, sizeof(iobuf));
2410 fclose(file);
2411 unlink(tempf);
2412 free(tempf);
2413 }
2414
2415 START_TEST(file)
2416 {
2417 int arg_c;
2418 char** arg_v;
2419
2420 init();
2421
2422 arg_c = winetest_get_mainargs( &arg_v );
2423
2424 /* testing low-level I/O */
2425 if (arg_c >= 3)
2426 {
2427 if (strcmp(arg_v[2], "inherit") == 0)
2428 test_file_inherit_child(arg_v[3]);
2429 else if (strcmp(arg_v[2], "inherit_no") == 0)
2430 test_file_inherit_child_no(arg_v[3]);
2431 else if (strcmp(arg_v[2], "pipes") == 0)
2432 test_pipes_child(arg_c, arg_v);
2433 else if (strcmp(arg_v[2], "refcount") == 0)
2434 test_file_refcount_child();
2435 else
2436 ok(0, "invalid argument '%s'\n", arg_v[2]);
2437 return;
2438 }
2439 test_dup2();
2440 test_file_inherit(arg_v[0]);
2441 test_file_write_read();
2442 test_chsize();
2443 test_stat();
2444 test_unlink();
2445
2446 /* testing stream I/O */
2447 test_filbuf();
2448 test_fdopen();
2449 test_fopen_fclose_fcloseall();
2450 test_fopen_s();
2451 test__wfopen_s();
2452 test_setmode();
2453 test_fileops();
2454 test_asciimode();
2455 test_asciimode2();
2456 test_filemodeT();
2457 test_readmode(FALSE); /* binary mode */
2458 test_readmode(TRUE); /* ascii mode */
2459 test_readboundary();
2460 test_fgetc();
2461 test_fputc();
2462 test_flsbuf();
2463 test_fflush();
2464 test_fgetwc();
2465 /* \x83\xa9 is double byte character, \xe0\x7f is not (undefined). */
2466 test_fgetwc_locale("AB\x83\xa9\xe0\x7f", "Japanese_Japan.932", 932);
2467 /* \x83 is U+0192 */
2468 test_fgetwc_locale("AB\x83\xa9", "English", 1252);
2469 /* \x83 is U+0083 */
2470 test_fgetwc_locale("AB\x83\xa9", "C", 0);
2471 test_fgetwc_unicode();
2472 test_fputwc();
2473 test_ctrlz();
2474 test_file_put_get();
2475 test_tmpnam();
2476 test_get_osfhandle();
2477 test_setmaxstdio();
2478 test_pipes(arg_v[0]);
2479 test_stdin();
2480 test_mktemp();
2481 test__open_osfhandle();
2482 test_write_flush();
2483
2484 /* Wait for the (_P_NOWAIT) spawned processes to finish to make sure the report
2485 * file contains lines in the correct order
2486 */
2487 WaitForMultipleObjects(sizeof(proc_handles)/sizeof(proc_handles[0]), proc_handles, TRUE, 5000);
2488 }