msvcrt/tests: Add a trailing '\n' to ok() calls.
[wine] / dlls / msvcrt / tests / 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
37 static HANDLE proc_handles[2];
38
39 static void test_fdopen( void )
40 {
41     static const char buffer[] = {0,1,2,3,4,5,6,7,8,9};
42     char ibuf[10];
43     int fd;
44     FILE *file;
45
46     fd = open ("fdopen.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE);
47     write (fd, buffer, sizeof (buffer));
48     close (fd);
49
50     fd = open ("fdopen.tst", O_RDONLY | O_BINARY);
51     lseek (fd, 5, SEEK_SET);
52     file = fdopen (fd, "rb");
53     ok (fread (ibuf, 1, sizeof (buffer), file) == 5, "read wrong byte count\n");
54     ok (memcmp (ibuf, buffer + 5, 5) == 0, "read wrong bytes\n");
55     fclose (file);
56     unlink ("fdopen.tst");
57 }
58
59 static void test_fileops( void )
60 {
61     static const char outbuffer[] = "0,1,2,3,4,5,6,7,8,9";
62     char buffer[256];
63     WCHAR wbuffer[256];
64     int fd;
65     FILE *file;
66     fpos_t pos;
67     int i, c;
68
69     fd = open ("fdopen.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE);
70     write (fd, outbuffer, sizeof (outbuffer));
71     close (fd);
72
73     fd = open ("fdopen.tst", O_RDONLY | O_BINARY);
74     file = fdopen (fd, "rb");
75     ok(strlen(outbuffer) == (sizeof(outbuffer)-1),"strlen/sizeof error\n");
76     ok(fgets(buffer,sizeof(buffer),file) !=0,"fgets failed unexpected\n");
77     ok(fgets(buffer,sizeof(buffer),file) ==0,"fgets didn't signal EOF\n");
78     ok(feof(file) !=0,"feof doesn't signal EOF\n");
79     rewind(file);
80     ok(fgets(buffer,strlen(outbuffer),file) !=0,"fgets failed unexpected\n");
81     ok(lstrlenA(buffer) == lstrlenA(outbuffer) -1,"fgets didn't read right size\n");
82     ok(fgets(buffer,sizeof(outbuffer),file) !=0,"fgets failed unexpected\n");
83     ok(strlen(buffer) == 1,"fgets dropped chars\n");
84     ok(buffer[0] == outbuffer[strlen(outbuffer)-1],"fgets exchanged chars\n");
85
86     rewind(file);
87     for (i = 0, c = EOF; i < sizeof(outbuffer); i++)
88     {
89         ok((c = fgetc(file)) == outbuffer[i], "fgetc returned wrong data\n");
90     }
91     ok((c = fgetc(file)) == EOF, "getc did not return EOF\n");
92     ok(feof(file), "feof did not return EOF\n");
93     ok(ungetc(c, file) == EOF, "ungetc(EOF) did not return EOF\n");
94     ok(feof(file), "feof after ungetc(EOF) did not return EOF\n");
95     ok((c = fgetc(file)) == EOF, "getc did not return EOF\n");
96     c = outbuffer[sizeof(outbuffer) - 1];
97     ok(ungetc(c, file) == c, "ungetc did not return its input\n");
98     ok(!feof(file), "feof after ungetc returned EOF\n");
99     ok((c = fgetc(file)) != EOF, "getc after ungetc returned EOF\n");
100     ok(c == outbuffer[sizeof(outbuffer) - 1],
101        "getc did not return ungetc'd data\n");
102     ok(!feof(file), "feof after getc returned EOF prematurely\n");
103     ok((c = fgetc(file)) == EOF, "getc did not return EOF\n");
104     ok(feof(file), "feof after getc did not return EOF\n");
105
106     rewind(file);
107     ok(fgetpos(file,&pos) == 0, "fgetpos failed unexpected\n");
108     ok(pos == 0, "Unexpected result of fgetpos 0x%Lx\n", pos);
109     pos = (ULONGLONG)sizeof (outbuffer);
110     ok(fsetpos(file, &pos) == 0, "fsetpos failed unexpected\n");
111     ok(fgetpos(file,&pos) == 0, "fgetpos failed unexpected\n");
112     ok(pos == (ULONGLONG)sizeof (outbuffer), "Unexpected result of fgetpos 0x%Lx\n", pos);
113
114     fclose (file);
115     fd = open ("fdopen.tst", O_RDONLY | O_TEXT);
116     file = fdopen (fd, "rt"); /* open in TEXT mode */
117     ok(fgetws(wbuffer,sizeof(wbuffer)/sizeof(wbuffer[0]),file) !=0,"fgetws failed unexpected\n");
118     ok(fgetws(wbuffer,sizeof(wbuffer)/sizeof(wbuffer[0]),file) ==0,"fgetws didn't signal EOF\n");
119     ok(feof(file) !=0,"feof doesn't signal EOF\n");
120     rewind(file);
121     ok(fgetws(wbuffer,strlen(outbuffer),file) !=0,"fgetws failed unexpected\n");
122     ok(lstrlenW(wbuffer) == (lstrlenA(outbuffer) -1),"fgetws didn't read right size\n");
123     ok(fgetws(wbuffer,sizeof(outbuffer)/sizeof(outbuffer[0]),file) !=0,"fgets failed unexpected\n");
124     ok(lstrlenW(wbuffer) == 1,"fgets dropped chars\n");
125     fclose (file);
126
127     file = fopen("fdopen.tst", "rb");
128     ok( file != NULL, "fopen failed\n");
129     /* sizeof(buffer) > content of file */
130     ok(fread(buffer, sizeof(buffer), 1, file) == 0, "fread test failed\n");
131     /* feof should be set now */
132     ok(feof(file), "feof after fread failed\n");
133     fclose (file);
134
135     unlink ("fdopen.tst");
136 }
137
138 #define IOMODE (ao?"ascii mode":"binary mode")
139 static void test_readmode( BOOL ascii_mode )
140 {
141     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";
142     static const char padbuffer[] = "ghjghjghjghj";
143     static const char nlbuffer[] = "\r\n";
144     char buffer[2*BUFSIZ+256];
145     const char *optr;
146     int fd;
147     FILE *file;
148     const int *ip;
149     int i, j, m, ao, pl;
150     unsigned int fp;
151     long l;
152
153     fd = open ("fdopen.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE);
154     /* an internal buffer of BUFSIZ is maintained, so make a file big
155      * enough to test operations that cross the buffer boundary 
156      */
157     j = (2*BUFSIZ-4)/strlen(padbuffer);
158     for (i=0; i<j; i++)
159         write (fd, padbuffer, strlen(padbuffer));
160     j = (2*BUFSIZ-4)%strlen(padbuffer);
161     for (i=0; i<j; i++)
162         write (fd, &padbuffer[i], 1);
163     write (fd, nlbuffer, strlen(nlbuffer));
164     write (fd, outbuffer, sizeof (outbuffer));
165     close (fd);
166     
167     if (ascii_mode) {
168         /* Open file in ascii mode */
169         fd = open ("fdopen.tst", O_RDONLY);
170         file = fdopen (fd, "r");
171         ao = -1; /* on offset to account for carriage returns */
172     }
173     else {
174         fd = open ("fdopen.tst", O_RDONLY | O_BINARY);
175         file = fdopen (fd, "rb");
176         ao = 0;
177     }
178     
179     /* first is a test of fgets, ftell, fseek */
180     ok(ftell(file) == 0,"Did not start at beginning of file in %s\n", IOMODE);
181     ok(fgets(buffer,2*BUFSIZ+256,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE);
182     l = ftell(file);
183     pl = 2*BUFSIZ-2;
184     ok(l == pl,"padding line ftell got %ld should be %d in %s\n", l, pl, IOMODE);
185     ok(lstrlenA(buffer) == pl+ao,"padding line fgets got size %d should be %d in %s\n",
186      lstrlenA(buffer), pl+ao, IOMODE);
187     for (fp=0; fp<strlen(outbuffer); fp++)
188         if (outbuffer[fp] == '\n') break;
189     fp++;
190     ok(fgets(buffer,256,file) !=0,"line 1 fgets failed unexpected in %s\n", IOMODE);
191     l = ftell(file);
192     ok(l == pl+fp,"line 1 ftell got %ld should be %d in %s\n", l, pl+fp, IOMODE);
193     ok(lstrlenA(buffer) == fp+ao,"line 1 fgets got size %d should be %d in %s\n",
194      lstrlenA(buffer), fp+ao, IOMODE);
195     /* test a seek back across the buffer boundary */
196     l = pl;
197     ok(fseek(file,l,SEEK_SET)==0,"seek failure in %s\n", IOMODE);
198     l = ftell(file);
199     ok(l == pl,"ftell after seek got %ld should be %d in %s\n", l, pl, IOMODE);
200     ok(fgets(buffer,256,file) !=0,"second read of line 1 fgets failed unexpected in %s\n", IOMODE);
201     l = ftell(file);
202     ok(l == pl+fp,"second read of line 1 ftell got %ld should be %d in %s\n", l, pl+fp, IOMODE);
203     ok(lstrlenA(buffer) == fp+ao,"second read of line 1 fgets got size %d should be %d in %s\n",
204      lstrlenA(buffer), fp+ao, IOMODE);
205     ok(fgets(buffer,256,file) !=0,"line 2 fgets failed unexpected in %s\n", IOMODE);
206     fp += 2;
207     l = ftell(file);
208     ok(l == pl+fp,"line 2 ftell got %ld should be %d in %s\n", l, pl+fp, IOMODE);
209     ok(lstrlenA(buffer) == 2+ao,"line 2 fgets got size %d should be %d in %s\n",
210      lstrlenA(buffer), 2+ao, IOMODE);
211     
212     /* test fread across buffer boundary */
213     rewind(file);
214     ok(ftell(file) == 0,"Did not start at beginning of file in %s\n", IOMODE);
215     ok(fgets(buffer,BUFSIZ-6,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE);
216     j=strlen(outbuffer);
217     i=fread(buffer,1,BUFSIZ+strlen(outbuffer),file);
218     ok(i==BUFSIZ+j,"fread failed, expected %d got %d in %s\n", BUFSIZ+j, i, IOMODE);
219     l = ftell(file);
220     ok(l == pl+j-(ao*4)-5,"ftell after fread got %ld should be %d in %s\n", l, pl+j-(ao*4)-5, IOMODE);
221     for (m=0; m<3; m++)
222         ok(buffer[m]==padbuffer[m+(BUFSIZ-4)%strlen(padbuffer)],"expected %c got %c\n", padbuffer[m], buffer[m]);
223     m+=BUFSIZ+2+ao;
224     optr = outbuffer;
225     for (; m<i; m++) {
226         ok(buffer[m]==*optr,"char %d expected %c got %c in %s\n", m, *optr, buffer[m], IOMODE);
227         optr++;
228         if (ao && (*optr == '\r'))
229             optr++;
230     }
231     /* fread should return the requested number of bytes if available */
232     rewind(file);
233     ok(ftell(file) == 0,"Did not start at beginning of file in %s\n", IOMODE);
234     ok(fgets(buffer,BUFSIZ-6,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE);
235     j = fp+10;
236     i=fread(buffer,1,j,file);
237     ok(i==j,"fread failed, expected %d got %d in %s\n", j, i, IOMODE);
238     /* test fread eof */
239     ok(fseek(file,0,SEEK_END)==0,"seek failure in %s\n", IOMODE);
240     ok(feof(file)==0,"feof failure in %s\n", IOMODE);
241     ok(fread(buffer,1,1,file)==0,"fread failure in %s\n", IOMODE);
242     ok(feof(file)!=0,"feof failure in %s\n", IOMODE);
243     ok(fseek(file,-3,SEEK_CUR)==0,"seek failure in %s\n", IOMODE);
244     ok(feof(file)==0,"feof failure in %s\n", IOMODE);
245     ok(fread(buffer,2,1,file)==1,"fread failed in %s\n", IOMODE);
246     ok(feof(file)==0,"feof failure in %s\n", IOMODE);
247     ok(fread(buffer,2,1,file)==0,"fread failure in %s\n",IOMODE);
248     ok(feof(file)!=0,"feof failure in %s\n", IOMODE);
249     
250     /* test some additional functions */
251     rewind(file);
252     ok(ftell(file) == 0,"Did not start at beginning of file in %s\n", IOMODE);
253     ok(fgets(buffer,2*BUFSIZ+256,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE);
254     i = _getw(file);
255     ip = (const int *)outbuffer;
256     ok(i == *ip,"_getw failed, expected %08x got %08x in %s\n", *ip, i, IOMODE);
257     for (fp=0; fp<strlen(outbuffer); fp++)
258         if (outbuffer[fp] == '\n') break;
259     fp++;
260     /* this will cause the next _getw to cross carriage return characters */
261     ok(fgets(buffer,fp-6,file) !=0,"line 1 fgets failed unexpected in %s\n", IOMODE);
262     for (i=0, j=0; i<6; i++) {
263         if (ao==0 || outbuffer[fp-3+i] != '\r')
264             buffer[j++] = outbuffer[fp-3+i];
265     }
266     i = _getw(file);
267     ip = (int *)buffer;
268     ok(i == *ip,"_getw failed, expected %08x got %08x in %s\n", *ip, i, IOMODE);
269
270     fclose (file);
271     unlink ("fdopen.tst");
272 }
273
274 static void test_asciimode(void)
275 {
276     FILE *fp;
277     char buf[64];
278
279     /* Simple test of CR CR LF handling.  Test both fgets and fread code paths, they're different! */
280     fp = fopen("ascii.tst", "wb");
281     fputs("\r\r\n", fp);
282     fclose(fp);
283     fp = fopen("ascii.tst", "rt");
284     ok(fgets(buf, sizeof(buf), fp) != NULL, "fgets\n");
285     ok(0 == strcmp(buf, "\r\n"), "CR CR LF not read as CR LF\n");
286     rewind(fp);
287     ok((fread(buf, 1, sizeof(buf), fp) == 2) && (0 == strcmp(buf, "\r\n")), "CR CR LF not read as CR LF\n");
288     fclose(fp);
289     unlink("ascii.tst");
290
291     /* Simple test of foo ^Z [more than one block] bar handling */
292     fp = fopen("ascii.tst", "wb");
293     fputs("foo\032", fp);  /* foo, logical EOF, ... */
294     fseek(fp, 65536L, SEEK_SET); /* ... more than MSVCRT_BUFSIZ, ... */
295     fputs("bar", fp); /* ... bar */
296     fclose(fp);
297     fp = fopen("ascii.tst", "rt");
298     ok(fgets(buf, sizeof(buf), fp) != NULL, "fgets foo\n");
299     ok(0 == strcmp(buf, "foo"), "foo ^Z not read as foo by fgets\n");
300     ok(fgets(buf, sizeof(buf), fp) == NULL, "fgets after logical EOF\n");
301     rewind(fp);
302     ok((fread(buf, 1, sizeof(buf), fp) == 3) && (0 == strcmp(buf, "foo")), "foo ^Z not read as foo by fread\n");
303     ok((fread(buf, 1, sizeof(buf), fp) == 0), "fread after logical EOF\n");
304     fclose(fp);
305
306     unlink("ascii.tst");
307 }
308
309 static WCHAR* AtoW( const char* p )
310 {
311     WCHAR* buffer;
312     DWORD len = MultiByteToWideChar( CP_ACP, 0, p, -1, NULL, 0 );
313     buffer = malloc( len * sizeof(WCHAR) );
314     MultiByteToWideChar( CP_ACP, 0, p, -1, buffer, len );
315     return buffer;
316 }
317
318 static void test_fgetc( void )
319 {
320   char* tempf;
321   FILE *tempfh;
322   int  ich=0xe0, ret;
323
324   tempf=_tempnam(".","wne");
325   tempfh = fopen(tempf,"w+");
326   fputc(ich, tempfh);
327   fputc(ich, tempfh);
328   rewind(tempfh);
329   ret = fgetc(tempfh);
330   ok(ich == ret, "First fgetc expected %x got %x\n", ich, ret);
331   ret = fgetc(tempfh);
332   ok(ich == ret, "Second fgetc expected %x got %x\n", ich, ret);
333   fclose(tempfh);
334   unlink(tempf);
335 }
336
337 static void test_fputc( void )
338 {
339   char* tempf;
340   FILE *tempfh;
341   int  ret;
342
343   tempf=_tempnam(".","wne");
344   tempfh = fopen(tempf,"wb");
345   ret = fputc(0,tempfh);
346   ok(0 == ret, "fputc(0,tempfh) expected %x got %x\n", 0, ret);
347   ret = fputc(0xff,tempfh);
348   ok(0xff == ret, "fputc(0xff,tempfh) expected %x got %x\n", 0xff, ret);
349   ret = fputc(0xffffffff,tempfh);
350   ok(0xff == ret, "fputc(0xffffffff,tempfh) expected %x got %x\n", 0xff, ret);
351   fclose(tempfh);
352
353   tempfh = fopen(tempf,"rb");
354   ret = fputc(0,tempfh);
355   ok(EOF == ret, "fputc(0,tempfh) on r/o file expected %x got %x\n", EOF, ret);
356   fclose(tempfh);
357
358   unlink(tempf);
359 }
360
361 static void test_flsbuf( void )
362 {
363   char* tempf;
364   FILE *tempfh;
365   int  ret;
366   int  bufmode;
367   int  bufmodes[] = {_IOFBF,_IONBF};
368
369   tempf=_tempnam(".","wne");
370   for (bufmode=0; bufmode < sizeof(bufmodes)/sizeof(bufmodes[0]); bufmode++)
371   {
372     tempfh = fopen(tempf,"wb");
373     setvbuf(tempfh,NULL,bufmodes[bufmode],2048);
374     ret = _flsbuf(0,tempfh);
375     ok(0 == ret, "_flsbuf(0,tempfh) with bufmode %x expected %x got %x\n",
376                          bufmodes[bufmode], 0, ret);
377     ret = _flsbuf(0xff,tempfh);
378     ok(0xff == ret, "_flsbuf(0xff,tempfh) with bufmode %x expected %x got %x\n",
379                          bufmodes[bufmode], 0, ret);
380     ret = _flsbuf(0xffffffff,tempfh);
381     ok(0xff == ret, "_flsbuf(0xffffffff,tempfh) with bufmode %x expected %x got %x\n",
382                          bufmodes[bufmode], 0, ret);
383     fclose(tempfh);
384   }
385
386   tempfh = fopen(tempf,"rb");
387   ret = _flsbuf(0,tempfh);
388   ok(EOF == ret, "_flsbuf(0,tempfh) on r/o file expected %x got %x\n", EOF, ret);
389   fclose(tempfh);
390
391   unlink(tempf);
392 }
393
394 static void test_fgetwc( void )
395 {
396 #define LLEN 512
397
398   char* tempf;
399   FILE *tempfh;
400   static const char mytext[]= "This is test_fgetwc\r\n";
401   WCHAR wtextW[BUFSIZ+LLEN+1];
402   WCHAR *mytextW = NULL, *aptr, *wptr;
403   BOOL diff_found = FALSE;
404   int j;
405   unsigned int i;
406   long l;
407
408   tempf=_tempnam(".","wne");
409   tempfh = fopen(tempf,"wb");
410   j = 'a';
411   /* pad to almost the length of the internal buffer */
412   for (i=0; i<BUFSIZ-4; i++)
413     fputc(j,tempfh);
414   j = '\r';
415   fputc(j,tempfh);
416   j = '\n';
417   fputc(j,tempfh);
418   fputs(mytext,tempfh);
419   fclose(tempfh);
420   /* in text mode, getws/c expects multibyte characters */
421   /*currently Wine only supports plain ascii, and that is all that is tested here */
422   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
423   fgetws(wtextW,LLEN,tempfh);
424   l=ftell(tempfh);
425   ok(l==BUFSIZ-2, "ftell expected %d got %ld\n", BUFSIZ-2, l);
426   fgetws(wtextW,LLEN,tempfh);
427   l=ftell(tempfh);
428   ok(l==BUFSIZ-2+strlen(mytext), "ftell expected %d got %ld\n",
429    BUFSIZ-2+strlen(mytext), l);
430   mytextW = AtoW (mytext);
431   aptr = mytextW;
432   wptr = wtextW;
433   for (i=0; i<strlen(mytext)-2; i++, aptr++, wptr++)
434     {
435       diff_found |= (*aptr != *wptr);
436     }
437   ok(!(diff_found), "fgetwc difference found in TEXT mode\n");
438   ok(*wptr == '\n', "Carriage return was not skipped\n");
439   fclose(tempfh);
440   unlink(tempf);
441   
442   tempfh = fopen(tempf,"wb");
443   j = 'a';
444   /* pad to almost the length of the internal buffer. Use an odd number of bytes
445      to test that we can read wchars that are split across the internal buffer
446      boundary */
447   for (i=0; i<BUFSIZ-3-strlen(mytext)*sizeof(WCHAR); i++)
448     fputc(j,tempfh);
449   j = '\r';
450   fputwc(j,tempfh);
451   j = '\n';
452   fputwc(j,tempfh);
453   fputws(wtextW,tempfh);
454   fputws(wtextW,tempfh);
455   fclose(tempfh);
456   /* in binary mode, getws/c expects wide characters */
457   tempfh = fopen(tempf,"rb"); /* open in BINARY mode */
458   j=(BUFSIZ-2)/sizeof(WCHAR)-strlen(mytext);
459   fgetws(wtextW,j,tempfh);
460   l=ftell(tempfh);
461   j=(j-1)*sizeof(WCHAR);
462   ok(l==j, "ftell expected %d got %ld\n", j, l);
463   i=fgetc(tempfh);
464   ok(i=='a', "fgetc expected %d got %d\n", 0x61, i);
465   l=ftell(tempfh);
466   j++;
467   ok(l==j, "ftell expected %d got %ld\n", j, l);
468   fgetws(wtextW,3,tempfh);
469   ok(wtextW[0]=='\r',"expected carriage return got %04hx\n", wtextW[0]);
470   ok(wtextW[1]=='\n',"expected newline got %04hx\n", wtextW[1]);
471   l=ftell(tempfh);
472   j += 4;
473   ok(l==j, "ftell expected %d got %ld\n", j, l);
474   for(i=0; i<strlen(mytext); i++)
475     wtextW[i] = 0;
476   /* the first time we get the string, it should be entirely within the local buffer */
477   fgetws(wtextW,LLEN,tempfh);
478   l=ftell(tempfh);
479   j += (strlen(mytext)-1)*sizeof(WCHAR);
480   ok(l==j, "ftell expected %d got %ld\n", j, l);
481   diff_found = FALSE;
482   aptr = mytextW;
483   wptr = wtextW;
484   for (i=0; i<strlen(mytext)-2; i++, aptr++, wptr++)
485     {
486       ok(*aptr == *wptr, "Char %d expected %04hx got %04hx\n", i, *aptr, *wptr);
487       diff_found |= (*aptr != *wptr);
488     }
489   ok(!(diff_found), "fgetwc difference found in BINARY mode\n");
490   ok(*wptr == '\n', "Should get newline\n");
491   for(i=0; i<strlen(mytext); i++)
492     wtextW[i] = 0;
493   /* the second time we get the string, it should cross the local buffer boundary.
494      One of the wchars should be split across the boundary */
495   fgetws(wtextW,LLEN,tempfh);
496   diff_found = FALSE;
497   aptr = mytextW;
498   wptr = wtextW;
499   for (i=0; i<strlen(mytext)-2; i++, aptr++, wptr++)
500     {
501       ok(*aptr == *wptr, "Char %d expected %04hx got %04hx\n", i, *aptr, *wptr);
502       diff_found |= (*aptr != *wptr);
503     }
504   ok(!(diff_found), "fgetwc difference found in BINARY mode\n");
505   ok(*wptr == '\n', "Should get newline\n");
506
507   free(mytextW);
508   fclose(tempfh);
509   unlink(tempf);
510 }
511
512 static void test_ctrlz( void )
513 {
514   char* tempf;
515   FILE *tempfh;
516   static const char mytext[]= "This is test_ctrlz";
517   char buffer[256];
518   int i, j;
519   long l;
520
521   tempf=_tempnam(".","wne");
522   tempfh = fopen(tempf,"wb");
523   fputs(mytext,tempfh);
524   j = 0x1a; /* a ctrl-z character signals EOF in text mode */
525   fputc(j,tempfh);
526   j = '\r';
527   fputc(j,tempfh);
528   j = '\n';
529   fputc(j,tempfh);
530   j = 'a';
531   fputc(j,tempfh);
532   fclose(tempfh);
533   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
534   ok(fgets(buffer,256,tempfh) != 0,"fgets failed unexpected\n");
535   i=strlen(buffer);
536   j=strlen(mytext);
537   ok(i==j, "returned string length expected %d got %d\n", j, i);
538   j+=4; /* ftell should indicate the true end of file */
539   l=ftell(tempfh);
540   ok(l==j, "ftell expected %d got %ld\n", j, l);
541   ok(feof(tempfh), "did not get EOF\n");
542   fclose(tempfh);
543   
544   tempfh = fopen(tempf,"rb"); /* open in BINARY mode */
545   ok(fgets(buffer,256,tempfh) != 0,"fgets failed unexpected\n");
546   i=strlen(buffer);
547   j=strlen(mytext)+3; /* should get through newline */
548   ok(i==j, "returned string length expected %d got %d\n", j, i);
549   l=ftell(tempfh);
550   ok(l==j, "ftell expected %d got %ld\n", j, l);
551   ok(fgets(buffer,256,tempfh) != 0,"fgets failed unexpected\n");
552   i=strlen(buffer);
553   ok(i==1, "returned string length expected %d got %d\n", 1, i);
554   ok(feof(tempfh), "did not get EOF\n");
555   fclose(tempfh);
556   unlink(tempf);
557 }
558
559 static void test_file_put_get( void )
560 {
561   char* tempf;
562   FILE *tempfh;
563   static const char mytext[]=  "This is a test_file_put_get\n";
564   static const char dostext[]= "This is a test_file_put_get\r\n";
565   char btext[LLEN];
566   WCHAR wtextW[LLEN+1];
567   WCHAR *mytextW = NULL, *aptr, *wptr;
568   BOOL diff_found = FALSE;
569   unsigned int i;
570
571   tempf=_tempnam(".","wne");
572   tempfh = fopen(tempf,"wt"); /* open in TEXT mode */
573   fputs(mytext,tempfh);
574   fclose(tempfh);
575   tempfh = fopen(tempf,"rb"); /* open in TEXT mode */
576   fgets(btext,LLEN,tempfh);
577   ok( strlen(mytext) + 1 == strlen(btext),"TEXT/BINARY mode not handled for write\n");
578   ok( btext[strlen(mytext)-1] == '\r', "CR not written\n");
579   fclose(tempfh);
580   tempfh = fopen(tempf,"wb"); /* open in BINARY mode */
581   fputs(dostext,tempfh);
582   fclose(tempfh);
583   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
584   fgets(btext,LLEN,tempfh);
585   ok(strcmp(btext, mytext) == 0,"_O_TEXT read doesn't strip CR\n");
586   fclose(tempfh);
587   tempfh = fopen(tempf,"rb"); /* open in TEXT mode */
588   fgets(btext,LLEN,tempfh);
589   ok(strcmp(btext, dostext) == 0,"_O_BINARY read doesn't preserve CR\n");
590
591   fclose(tempfh);
592   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
593   fgetws(wtextW,LLEN,tempfh);
594   mytextW = AtoW (mytext);
595   aptr = mytextW;
596   wptr = wtextW;
597
598   for (i=0; i<strlen(mytext); i++, aptr++, wptr++)
599     {
600       diff_found |= (*aptr != *wptr);
601     }
602   ok(!(diff_found), "fgetwc doesn't strip CR in TEXT mode\n");
603   free(mytextW);
604   fclose(tempfh);
605   unlink(tempf);
606 }
607
608 static void test_file_write_read( void )
609 {
610   char* tempf;
611   int tempfd;
612   static const char mytext[]=  "This is test_file_write_read\nsecond line\n";
613   static const char dostext[]= "This is test_file_write_read\r\nsecond line\r\n";
614   char btext[LLEN];
615   int ret, i;
616
617   tempf=_tempnam(".","wne");
618   tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_BINARY|_O_RDWR,
619                      _S_IREAD | _S_IWRITE);
620   ok( tempfd != -1,
621      "Can't open '%s': %d\n", tempf, errno); /* open in BINARY mode */
622   ok(_write(tempfd,dostext,strlen(dostext)) == lstrlenA(dostext),
623      "_write _O_BINARY bad return value\n");
624   _close(tempfd);
625   i = lstrlenA(mytext);
626   tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
627   ok(_read(tempfd,btext,i) == i,
628      "_read _O_BINARY got bad length\n");
629   ok( memcmp(dostext,btext,i) == 0,
630       "problems with _O_BINARY  _write / _read\n");
631   _close(tempfd);
632   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
633   ok(_read(tempfd,btext,i) == i-1,
634      "_read _O_TEXT got bad length\n");
635   ok( memcmp(mytext,btext,i-1) == 0,
636       "problems with _O_BINARY _write / _O_TEXT _read\n");
637   _close(tempfd);
638   tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_TEXT|_O_RDWR,
639                      _S_IREAD | _S_IWRITE);
640   ok( tempfd != -1,
641      "Can't open '%s': %d\n", tempf, errno); /* open in TEXT mode */
642   ok(_write(tempfd,mytext,strlen(mytext)) == lstrlenA(mytext),
643      "_write _O_TEXT bad return value\n");
644   _close(tempfd);
645   tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
646   ok(_read(tempfd,btext,LLEN) == lstrlenA(dostext),
647      "_read _O_BINARY got bad length\n");
648   ok( memcmp(dostext,btext,strlen(dostext)) == 0,
649       "problems with _O_TEXT _write / _O_BINARY _read\n");
650   ok( btext[strlen(dostext)-2] == '\r', "CR not written or read\n");
651   _close(tempfd);
652   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
653   ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext),
654      "_read _O_TEXT got bad length\n");
655   ok( memcmp(mytext,btext,strlen(mytext)) == 0,
656       "problems with _O_TEXT _write / _read\n");
657   _close(tempfd);
658
659   memset(btext, 0, LLEN);
660   tempfd = _open(tempf,_O_APPEND|_O_RDWR); /* open for APPEND in default mode */
661   ok(tell(tempfd) == 0, "bad position %lu expecting 0\n", tell(tempfd));
662   ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext), "_read _O_APPEND got bad length\n");
663   ok( memcmp(mytext,btext,strlen(mytext)) == 0, "problems with _O_APPEND _read\n");
664   _close(tempfd);
665
666   /* Test reading only \n or \r */
667   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
668   _lseek(tempfd, -1, FILE_END);
669   ret = _read(tempfd,btext,LLEN);
670   ok(ret == 1, "_read expected 1 got bad length: %d\n", ret);
671   _lseek(tempfd, -2, FILE_END);
672   ret = _read(tempfd,btext,LLEN);
673   ok(ret == 1 && *btext == '\n', "_read expected '\\n' got bad length: %d\n", ret);
674   _lseek(tempfd, -3, FILE_END);
675   ret = _read(tempfd,btext,2);
676   ok(ret == 1 && *btext == 'e', "_read expected 'e' got \"%.*s\" bad length: %d\n", ret, btext, ret);
677   ok(tell(tempfd) == 42, "bad position %lu expecting 42\n", tell(tempfd));
678   _close(tempfd);
679
680   ret = unlink(tempf);
681   ok( ret == 0 ,"Can't unlink '%s': %d\n", tempf, errno);
682
683   tempf=_tempnam(".","wne");
684   tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_BINARY|_O_RDWR,0);
685   ok( tempfd != -1,
686      "Can't open '%s': %d\n", tempf, errno); /* open in BINARY mode */
687   ok(_write(tempfd,dostext,strlen(dostext)) == lstrlenA(dostext),
688      "_write _O_BINARY bad return value\n");
689   _close(tempfd);
690   tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
691   ok(_read(tempfd,btext,LLEN) == lstrlenA(dostext),
692      "_read _O_BINARY got bad length\n");
693   ok( memcmp(dostext,btext,strlen(dostext)) == 0,
694       "problems with _O_BINARY _write / _read\n");
695   ok( btext[strlen(dostext)-2] == '\r', "CR not written or read\n");
696   _close(tempfd);
697   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
698   ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext),
699      "_read _O_TEXT got bad length\n");
700   ok( memcmp(mytext,btext,strlen(mytext)) == 0,
701       "problems with _O_BINARY _write / _O_TEXT _read\n");
702   _close(tempfd);
703
704    ret =_chmod (tempf, _S_IREAD | _S_IWRITE);
705   ok( ret == 0,
706      "Can't chmod '%s' to read-write: %d\n", tempf, errno);
707   ret = unlink(tempf);
708   ok( ret == 0 ,"Can't unlink '%s': %d\n", tempf, errno);
709 }
710
711 static void test_file_inherit_child(const char* fd_s)
712 {
713     int fd = atoi(fd_s);
714     char buffer[32];
715     int ret;
716
717     ret =write(fd, "Success", 8);
718     ok( ret == 8, "Couldn't write in child process on %d (%s)\n", fd, strerror(errno));
719     lseek(fd, 0, SEEK_SET);
720     ok(read(fd, buffer, sizeof (buffer)) == 8, "Couldn't read back the data\n");
721     ok(memcmp(buffer, "Success", 8) == 0, "Couldn't read back the data\n");
722 }
723
724 static void test_file_inherit_child_no(const char* fd_s)
725 {
726     int fd = atoi(fd_s);
727     int ret;
728
729     ret = write(fd, "Success", 8);
730     ok( ret == -1 && errno == EBADF, 
731        "Wrong write result in child process on %d (%s)\n", fd, strerror(errno));
732 }
733  
734 static void test_file_inherit( const char* selfname )
735 {
736     int                 fd;
737     const char*         arg_v[5];
738     char                buffer[16];
739
740     fd = open ("fdopen.tst", O_CREAT | O_RDWR | O_BINARY, _S_IREAD |_S_IWRITE);
741     ok(fd != -1, "Couldn't create test file\n");
742     arg_v[0] = selfname;
743     arg_v[1] = "tests/file.c";
744     arg_v[2] = "inherit";
745     arg_v[3] = buffer; sprintf(buffer, "%d", fd);
746     arg_v[4] = 0;
747     _spawnvp(_P_WAIT, selfname, arg_v);
748     ok(tell(fd) == 8, "bad position %lu expecting 8\n", tell(fd));
749     lseek(fd, 0, SEEK_SET);
750     ok(read(fd, buffer, sizeof (buffer)) == 8 && memcmp(buffer, "Success", 8) == 0, "Couldn't read back the data\n");
751     close (fd);
752     ok(unlink("fdopen.tst") == 0, "Couldn't unlink\n");
753     
754     fd = open ("fdopen.tst", O_CREAT | O_RDWR | O_BINARY | O_NOINHERIT, _S_IREAD |_S_IWRITE);
755     ok(fd != -1, "Couldn't create test file\n");
756     arg_v[0] = selfname;
757     arg_v[1] = "tests/file.c";
758     arg_v[2] = "inherit_no";
759     arg_v[3] = buffer; sprintf(buffer, "%d", fd);
760     arg_v[4] = 0;
761     _spawnvp(_P_WAIT, selfname, arg_v);
762     ok(tell(fd) == 0, "bad position %lu expecting 0\n", tell(fd));
763     ok(read(fd, buffer, sizeof (buffer)) == 0, "Found unexpected data (%s)\n", buffer);
764     close (fd);
765     ok(unlink("fdopen.tst") == 0, "Couldn't unlink\n");
766 }
767
768 static void test_tmpnam( void )
769 {
770   char name[MAX_PATH] = "abc";
771   char *res;
772
773   res = tmpnam(NULL);
774   ok(res != NULL, "tmpnam returned NULL\n");
775   ok(res[0] == '\\', "first character is not a backslash\n");
776   ok(strchr(res+1, '\\') == 0, "file not in the root directory\n");
777   ok(res[strlen(res)-1] == '.', "first call - last character is not a dot\n");
778
779   res = tmpnam(name);
780   ok(res != NULL, "tmpnam returned NULL\n");
781   ok(res == name, "supplied buffer was not used\n");
782   ok(res[0] == '\\', "first character is not a backslash\n");
783   ok(strchr(res+1, '\\') == 0, "file not in the root directory\n");
784   ok(res[strlen(res)-1] != '.', "second call - last character is a dot\n");
785 }
786
787 static void test_chsize( void )
788 {
789     int fd;
790     long cur, pos, count;
791     char temptext[] = "012345678";
792     char *tempfile = _tempnam( ".", "tst" );
793     
794     ok( tempfile != NULL, "Couldn't create test file: %s\n", tempfile );
795
796     fd = _open( tempfile, _O_CREAT|_O_TRUNC|_O_RDWR, _S_IREAD|_S_IWRITE );
797     ok( fd > 0, "Couldn't open test file\n" );
798
799     count = _write( fd, temptext, sizeof(temptext) );
800     ok( count > 0, "Couldn't write to test file\n" );
801
802     /* get current file pointer */
803     cur = _lseek( fd, 0, SEEK_CUR );
804
805     /* make the file smaller */
806     ok( _chsize( fd, sizeof(temptext) / 2 ) == 0, "_chsize() failed\n" );
807
808     pos = _lseek( fd, 0, SEEK_CUR );
809     ok( cur == pos, "File pointer changed from: %ld to: %ld\n", cur, pos );
810     ok( _filelength( fd ) == sizeof(temptext) / 2, "Wrong file size\n" );
811
812     /* enlarge the file */
813     ok( _chsize( fd, sizeof(temptext) * 2 ) == 0, "_chsize() failed\n" ); 
814
815     pos = _lseek( fd, 0, SEEK_CUR );
816     ok( cur == pos, "File pointer changed from: %ld to: %ld\n", cur, pos );
817     ok( _filelength( fd ) == sizeof(temptext) * 2, "Wrong file size\n" );
818
819     _close( fd );
820     _unlink( tempfile );
821 }
822
823 static void test_fopen_fclose_fcloseall( void )
824 {
825     char fname1[] = "empty1";
826     char fname2[] = "empty2";
827     char fname3[] = "empty3";
828     FILE *stream1, *stream2, *stream3, *stream4;
829     int ret, numclosed;
830
831     /* testing fopen() */
832     stream1 = fopen(fname1, "w+");
833     ok(stream1 != NULL, "The file '%s' was not opened\n", fname1);
834     stream2 = fopen(fname2, "w ");
835     ok(stream2 != NULL, "The file '%s' was not opened\n", fname2 );
836     _unlink(fname3);
837     stream3 = fopen(fname3, "r");
838     ok(stream3 == NULL, "The file '%s' shouldn't exist before\n", fname3 );
839     stream3 = fopen(fname3, "w+");
840     ok(stream3 != NULL, "The file '%s' should be opened now\n", fname3 );
841     errno = 0xfaceabad;
842     stream4 = fopen("", "w+");
843     ok(stream4 == NULL && (errno == EINVAL || errno == ENOENT),
844        "filename is empty, errno = %d (expected 2 or 22)\n", errno);
845     errno = 0xfaceabad;
846     stream4 = fopen(NULL, "w+");
847     ok(stream4 == NULL && (errno == EINVAL || errno == ENOENT), 
848        "filename is NULL, errno = %d (expected 2 or 22)\n", errno);
849
850     /* testing fclose() */
851     ret = fclose(stream2);
852     ok(ret == 0, "The file '%s' was not closed\n", fname2);
853     ret = fclose(stream3);
854     ok(ret == 0, "The file '%s' was not closed\n", fname3);
855     ret = fclose(stream2);
856     ok(ret == EOF, "Closing file '%s' returned %d\n", fname2, ret);
857     ret = fclose(stream3);
858     ok(ret == EOF, "Closing file '%s' returned %d\n", fname3, ret);
859
860     /* testing fcloseall() */
861     numclosed = _fcloseall();
862     /* fname1 should be closed here */
863     ok(numclosed == 1, "Number of files closed by fcloseall(): %u\n", numclosed);
864     numclosed = _fcloseall();
865     ok(numclosed == 0, "Number of files closed by fcloseall(): %u\n", numclosed);
866
867     ok(_unlink(fname1) == 0, "Couldn't unlink file named '%s'\n", fname1);
868     ok(_unlink(fname2) == 0, "Couldn't unlink file named '%s'\n", fname2);
869     ok(_unlink(fname3) == 0, "Couldn't unlink file named '%s'\n", fname3);
870 }
871
872 static void test_get_osfhandle(void)
873 {
874     int fd;
875     char fname[] = "t_get_osfhanle";
876     DWORD bytes_written;
877     HANDLE handle;
878
879     fd = _sopen(fname, _O_CREAT|_O_RDWR, _SH_DENYRW, _S_IREAD | _S_IWRITE);
880     handle = (HANDLE)_get_osfhandle(fd);
881     WriteFile(handle, "bar", 3, &bytes_written, NULL);
882     _close(fd);
883     fd = _open(fname, _O_RDONLY, 0);
884     ok(fd != -1, "Coudn't open '%s' after _get_osfhanle()\n", fname);
885
886     _close(fd);
887     _unlink(fname);
888 }
889
890 static void test_setmaxstdio(void)
891 {
892     ok(2048 == _setmaxstdio(2048),"_setmaxstdio returned %d instead of 2048\n",_setmaxstdio(2048));
893     ok(-1 == _setmaxstdio(2049),"_setmaxstdio returned %d instead of -1\n",_setmaxstdio(2049));
894 }
895
896 static void test_stat(void)
897 {
898     int fd;
899     int pipes[2];
900     struct stat buf;
901
902     /* Tests for a file */
903     fd = open("stat.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE);
904     if (fd >= 0)
905     {
906         ok(fstat(fd, &buf) == 0, "fstat failed: errno=%d\n", errno);
907         ok((buf.st_mode & _S_IFMT) == _S_IFREG, "bad format = %06o\n", buf.st_mode);
908         ok((buf.st_mode & 0777) == 0666, "bad st_mode = %06o\n", buf.st_mode);
909         ok(buf.st_dev == 0, "st_dev is %d, expected 0\n", buf.st_dev);
910         ok(buf.st_dev == buf.st_rdev, "st_dev (%d) and st_rdev (%d) differ\n", buf.st_dev, buf.st_rdev);
911         ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink);
912         ok(buf.st_size == 0, "st_size is %d, expected 0\n", buf.st_size);
913
914         ok(stat("stat.tst", &buf) == 0, "stat failed: errno=%d\n", errno);
915         ok((buf.st_mode & _S_IFMT) == _S_IFREG, "bad format = %06o\n", buf.st_mode);
916         ok((buf.st_mode & 0777) == 0666, "bad st_mode = %06o\n", buf.st_mode);
917         ok(buf.st_dev == buf.st_rdev, "st_dev (%d) and st_rdev (%d) differ\n", buf.st_dev, buf.st_rdev);
918         ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink);
919         ok(buf.st_size == 0, "st_size is %d, expected 0\n", buf.st_size);
920
921         close(fd);
922         remove("stat.tst");
923     }
924     else
925         skip("open failed with errno %d\n", errno);
926
927     /* Tests for a char device */
928     if (_dup2(0, 10) == 0)
929     {
930         ok(fstat(10, &buf) == 0, "fstat(stdin) failed: errno=%d\n", errno);
931         if ((buf.st_mode & _S_IFMT) == _S_IFCHR)
932         {
933             ok(buf.st_mode == _S_IFCHR, "bad st_mode=%06o\n", buf.st_mode);
934             ok(buf.st_dev == 10, "st_dev is %d, expected 10\n", buf.st_dev);
935             ok(buf.st_rdev == 10, "st_rdev is %d, expected 10\n", buf.st_rdev);
936             ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink);
937         }
938         else
939             skip("stdin is not a char device? st_mode=%06o\n", buf.st_mode);
940         close(10);
941     }
942     else
943         skip("_dup2 failed with errno %d\n", errno);
944
945     /* Tests for pipes */
946     if (_pipe(pipes, 1024, O_BINARY) == 0)
947     {
948         ok(fstat(pipes[0], &buf) == 0, "fstat(pipe) failed: errno=%d\n", errno);
949         ok(buf.st_mode == _S_IFIFO, "bad st_mode=%06o\n", buf.st_mode);
950         ok(buf.st_dev == pipes[0], "st_dev is %d, expected %d\n", buf.st_dev, pipes[0]);
951         ok(buf.st_rdev == pipes[0], "st_rdev is %d, expected %d\n", buf.st_rdev, pipes[0]);
952         ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink);
953         close(pipes[0]);
954         close(pipes[1]);
955     }
956     else
957         skip("pipe failed with errno %d\n", errno);
958 }
959
960 static const char* pipe_string="Hello world";
961
962 /* How many messages to transfer over the pipe */
963 #define N_TEST_MESSAGES 3
964
965 static void test_pipes_child(int argc, char** args)
966 {
967     int fd;
968     int nwritten;
969     int i;
970
971     if (argc < 5)
972     {
973         ok(0, "not enough parameters: %d\n", argc);
974         return;
975     }
976
977     fd=atoi(args[3]);
978     ok(close(fd) == 0, "unable to close %d: %d\n", fd, errno);
979
980     fd=atoi(args[4]);
981
982     for (i=0; i<N_TEST_MESSAGES; i++) {
983        nwritten=write(fd, pipe_string, strlen(pipe_string));
984        ok(nwritten == strlen(pipe_string), "i %d, expected to write %d bytes, wrote %d\n", i, strlen(pipe_string), nwritten);
985        /* let other process wake up so they can show off their "keep reading until EOF" behavior */
986        if (i < N_TEST_MESSAGES-1)
987            Sleep(100);
988     }
989
990     ok(close(fd) == 0, "unable to close %d: %d\n", fd, errno);
991 }
992
993 static void test_pipes(const char* selfname)
994 {
995     int pipes[2];
996     char str_fdr[12], str_fdw[12];
997     FILE* file;
998     const char* arg_v[6];
999     char buf[4096];
1000     char expected[4096];
1001     int r;
1002     int i;
1003
1004     /* Test reading from a pipe with read() */
1005     if (_pipe(pipes, 1024, O_BINARY) < 0)
1006     {
1007         ok(0, "pipe failed with errno %d\n", errno);
1008         return;
1009     }
1010
1011     arg_v[0] = selfname;
1012     arg_v[1] = "tests/file.c";
1013     arg_v[2] = "pipes";
1014     arg_v[3] = str_fdr; sprintf(str_fdr, "%d", pipes[0]);
1015     arg_v[4] = str_fdw; sprintf(str_fdw, "%d", pipes[1]);
1016     arg_v[5] = NULL;
1017     proc_handles[0] = (HANDLE)_spawnvp(_P_NOWAIT, selfname, arg_v);
1018     ok(close(pipes[1]) == 0, "unable to close %d: %d\n", pipes[1], errno);
1019
1020     for (i=0; i<N_TEST_MESSAGES; i++) {
1021        r=read(pipes[0], buf, sizeof(buf)-1);
1022        ok(r == strlen(pipe_string), "i %d, expected to read %d bytes, got %d\n", i, strlen(pipe_string)+1, r);
1023        if (r > 0)
1024            buf[r]='\0';
1025        ok(strcmp(buf, pipe_string) == 0, "expected to read '%s', got '%s'\n", pipe_string, buf);
1026    }
1027
1028     r=read(pipes[0], buf, sizeof(buf)-1);
1029     ok(r == 0, "expected to read 0 bytes, got %d\n", r);
1030     ok(close(pipes[0]) == 0, "unable to close %d: %d\n", pipes[0], errno);
1031
1032     /* Test reading from a pipe with fread() */
1033     if (_pipe(pipes, 1024, O_BINARY) < 0)
1034     {
1035         ok(0, "pipe failed with errno %d\n", errno);
1036         return;
1037     }
1038
1039     arg_v[0] = selfname;
1040     arg_v[1] = "tests/file.c";
1041     arg_v[2] = "pipes";
1042     arg_v[3] = str_fdr; sprintf(str_fdr, "%d", pipes[0]);
1043     arg_v[4] = str_fdw; sprintf(str_fdw, "%d", pipes[1]);
1044     arg_v[5] = NULL;
1045     proc_handles[1] = (HANDLE)_spawnvp(_P_NOWAIT, selfname, arg_v);
1046     ok(close(pipes[1]) == 0, "unable to close %d: %d\n", pipes[1], errno);
1047     file=fdopen(pipes[0], "r");
1048
1049     /* In blocking mode, fread will keep calling read() until it gets
1050      * enough bytes, or EOF, even on Unix.  (If this were a Unix terminal
1051      * in cooked mode instead of a pipe, it would also stop on EOL.)
1052      */
1053     expected[0] = 0;
1054     for (i=0; i<N_TEST_MESSAGES; i++)
1055        strcat(expected, pipe_string);
1056     r=fread(buf, 1, sizeof(buf)-1, file);
1057     ok(r == strlen(expected), "fread() returned %d instead of %d: ferror=%d\n", r, strlen(expected), ferror(file));
1058     if (r > 0)
1059        buf[r]='\0';
1060     ok(strcmp(buf, expected) == 0, "got '%s' expected '%s'\n", buf, expected);
1061
1062     /* Let child close the file before we read, so we can sense EOF reliably */
1063     Sleep(100);
1064     r=fread(buf, 1, sizeof(buf)-1, file);
1065     ok(r == 0, "fread() returned %d instead of 0\n", r);
1066     ok(ferror(file) == 0, "got ferror() = %d\n", ferror(file));
1067     ok(feof(file), "feof() is false!\n");
1068
1069     ok(fclose(file) == 0, "unable to close the pipe: %d\n", errno);
1070 }
1071
1072 static void test_unlink(void)
1073 {
1074     FILE* file;
1075     ok(mkdir("test_unlink") == 0, "unable to create test dir\n");
1076     file = fopen("test_unlink\\empty", "w");
1077     ok(file != NULL, "unable to create test file\n");
1078     if(file)
1079       fclose(file);
1080     ok(_unlink("test_unlink") != 0, "unlinking a non-empty directory must fail\n");
1081     unlink("test_unlink\\empty");
1082     rmdir("test_unlink");
1083 }
1084
1085 START_TEST(file)
1086 {
1087     int arg_c;
1088     char** arg_v;
1089
1090     arg_c = winetest_get_mainargs( &arg_v );
1091
1092     /* testing low-level I/O */
1093     if (arg_c >= 3)
1094     {
1095         if (strcmp(arg_v[2], "inherit") == 0)
1096             test_file_inherit_child(arg_v[3]);
1097         else if (strcmp(arg_v[2], "inherit_no") == 0)
1098             test_file_inherit_child_no(arg_v[3]);
1099         else if (strcmp(arg_v[2], "pipes") == 0)
1100             test_pipes_child(arg_c, arg_v);
1101         else
1102             ok(0, "invalid argument '%s'\n", arg_v[2]);
1103         return;
1104     }
1105     test_file_inherit(arg_v[0]);
1106     test_file_write_read();
1107     test_chsize();
1108     test_stat();
1109     test_unlink();
1110
1111     /* testing stream I/O */
1112     test_fdopen();
1113     test_fopen_fclose_fcloseall();
1114     test_fileops();
1115     test_asciimode();
1116     test_readmode(FALSE); /* binary mode */
1117     test_readmode(TRUE);  /* ascii mode */
1118     test_fgetc();
1119     test_fputc();
1120     test_flsbuf();
1121     test_fgetwc();
1122     test_ctrlz();
1123     test_file_put_get();
1124     test_tmpnam();
1125     test_get_osfhandle();
1126     test_setmaxstdio();
1127     test_pipes(arg_v[0]);
1128
1129     /* Wait for the (_P_NOWAIT) spawned processes to finish to make sure the report
1130      * file contains lines in the correct order
1131      */
1132     WaitForMultipleObjects(sizeof(proc_handles)/sizeof(proc_handles[0]), proc_handles, TRUE, 5000);
1133 }