wintrust: Use a helper function to get a signer's cert info from a message.
[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),file) !=0,"fgetws failed unexpected\n");
118     ok(fgetws(wbuffer,sizeof(wbuffer),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),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     todo_wine 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
275 static WCHAR* AtoW( const char* p )
276 {
277     WCHAR* buffer;
278     DWORD len = MultiByteToWideChar( CP_ACP, 0, p, -1, NULL, 0 );
279     buffer = malloc( len * sizeof(WCHAR) );
280     MultiByteToWideChar( CP_ACP, 0, p, -1, buffer, len );
281     return buffer;
282 }
283
284 static void test_fgetc( void )
285 {
286   char* tempf;
287   FILE *tempfh;
288   int  ich=0xe0, ret;
289
290   tempf=_tempnam(".","wne");
291   tempfh = fopen(tempf,"w+");
292   fputc(ich, tempfh);
293   fputc(ich, tempfh);
294   rewind(tempfh);
295   ret = fgetc(tempfh);
296   ok(ich == ret, "First fgetc expected %x got %x\n", ich, ret);
297   ret = fgetc(tempfh);
298   ok(ich == ret, "Second fgetc expected %x got %x\n", ich, ret);
299   fclose(tempfh);
300   unlink(tempf);
301 }
302
303 static void test_fgetwc( void )
304 {
305 #define LLEN 512
306
307   char* tempf;
308   FILE *tempfh;
309   static const char mytext[]= "This is test_fgetwc\r\n";
310   WCHAR wtextW[BUFSIZ+LLEN+1];
311   WCHAR *mytextW = NULL, *aptr, *wptr;
312   BOOL diff_found = FALSE;
313   int j;
314   unsigned int i;
315   long l;
316
317   tempf=_tempnam(".","wne");
318   tempfh = fopen(tempf,"wb");
319   j = 'a';
320   /* pad to almost the length of the internal buffer */
321   for (i=0; i<BUFSIZ-4; i++)
322     fputc(j,tempfh);
323   j = '\r';
324   fputc(j,tempfh);
325   j = '\n';
326   fputc(j,tempfh);
327   fputs(mytext,tempfh);
328   fclose(tempfh);
329   /* in text mode, getws/c expects multibyte characters */
330   /*currently Wine only supports plain ascii, and that is all that is tested here */
331   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
332   fgetws(wtextW,LLEN,tempfh);
333   l=ftell(tempfh);
334   ok(l==BUFSIZ-2, "ftell expected %d got %ld\n", BUFSIZ-2, l);
335   fgetws(wtextW,LLEN,tempfh);
336   l=ftell(tempfh);
337   ok(l==BUFSIZ-2+strlen(mytext), "ftell expected %d got %ld\n",
338    BUFSIZ-2+strlen(mytext), l);
339   mytextW = AtoW (mytext);
340   aptr = mytextW;
341   wptr = wtextW;
342   for (i=0; i<strlen(mytext)-2; i++, aptr++, wptr++)
343     {
344       diff_found |= (*aptr != *wptr);
345     }
346   ok(!(diff_found), "fgetwc difference found in TEXT mode\n");
347   ok(*wptr == '\n', "Carriage return was not skipped\n");
348   fclose(tempfh);
349   unlink(tempf);
350   
351   tempfh = fopen(tempf,"wb");
352   j = 'a';
353   /* pad to almost the length of the internal buffer. Use an odd number of bytes
354      to test that we can read wchars that are split across the internal buffer
355      boundary */
356   for (i=0; i<BUFSIZ-3-strlen(mytext)*sizeof(WCHAR); i++)
357     fputc(j,tempfh);
358   j = '\r';
359   fputwc(j,tempfh);
360   j = '\n';
361   fputwc(j,tempfh);
362   fputws(wtextW,tempfh);
363   fputws(wtextW,tempfh);
364   fclose(tempfh);
365   /* in binary mode, getws/c expects wide characters */
366   tempfh = fopen(tempf,"rb"); /* open in BINARY mode */
367   j=(BUFSIZ-2)/sizeof(WCHAR)-strlen(mytext);
368   fgetws(wtextW,j,tempfh);
369   l=ftell(tempfh);
370   j=(j-1)*sizeof(WCHAR);
371   ok(l==j, "ftell expected %d got %ld\n", j, l);
372   i=fgetc(tempfh);
373   ok(i=='a', "fgetc expected %d got %d\n", 0x61, i);
374   l=ftell(tempfh);
375   j++;
376   ok(l==j, "ftell expected %d got %ld\n", j, l);
377   fgetws(wtextW,3,tempfh);
378   ok(wtextW[0]=='\r',"expected carriage return got %04hx\n", wtextW[0]);
379   ok(wtextW[1]=='\n',"expected newline got %04hx\n", wtextW[1]);
380   l=ftell(tempfh);
381   j += 4;
382   ok(l==j, "ftell expected %d got %ld\n", j, l);
383   for(i=0; i<strlen(mytext); i++)
384     wtextW[i] = 0;
385   /* the first time we get the string, it should be entirely within the local buffer */
386   fgetws(wtextW,LLEN,tempfh);
387   l=ftell(tempfh);
388   j += (strlen(mytext)-1)*sizeof(WCHAR);
389   ok(l==j, "ftell expected %d got %ld\n", j, l);
390   diff_found = FALSE;
391   aptr = mytextW;
392   wptr = wtextW;
393   for (i=0; i<strlen(mytext)-2; i++, aptr++, wptr++)
394     {
395       ok(*aptr == *wptr, "Char %d expected %04hx got %04hx\n", i, *aptr, *wptr);
396       diff_found |= (*aptr != *wptr);
397     }
398   ok(!(diff_found), "fgetwc difference found in BINARY mode\n");
399   ok(*wptr == '\n', "Should get newline\n");
400   for(i=0; i<strlen(mytext); i++)
401     wtextW[i] = 0;
402   /* the second time we get the string, it should cross the local buffer boundary.
403      One of the wchars should be split across the boundary */
404   fgetws(wtextW,LLEN,tempfh);
405   diff_found = FALSE;
406   aptr = mytextW;
407   wptr = wtextW;
408   for (i=0; i<strlen(mytext)-2; i++, aptr++, wptr++)
409     {
410       ok(*aptr == *wptr, "Char %d expected %04hx got %04hx\n", i, *aptr, *wptr);
411       diff_found |= (*aptr != *wptr);
412     }
413   ok(!(diff_found), "fgetwc difference found in BINARY mode\n");
414   ok(*wptr == '\n', "Should get newline\n");
415
416   free(mytextW);
417   fclose(tempfh);
418   unlink(tempf);
419 }
420
421 static void test_ctrlz( void )
422 {
423   char* tempf;
424   FILE *tempfh;
425   static const char mytext[]= "This is test_ctrlz";
426   char buffer[256];
427   int i, j;
428   long l;
429
430   tempf=_tempnam(".","wne");
431   tempfh = fopen(tempf,"wb");
432   fputs(mytext,tempfh);
433   j = 0x1a; /* a ctrl-z character signals EOF in text mode */
434   fputc(j,tempfh);
435   j = '\r';
436   fputc(j,tempfh);
437   j = '\n';
438   fputc(j,tempfh);
439   j = 'a';
440   fputc(j,tempfh);
441   fclose(tempfh);
442   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
443   ok(fgets(buffer,256,tempfh) != 0,"fgets failed unexpected\n");
444   i=strlen(buffer);
445   j=strlen(mytext);
446   ok(i==j, "returned string length expected %d got %d\n", j, i);
447   j+=4; /* ftell should indicate the true end of file */
448   l=ftell(tempfh);
449   ok(l==j, "ftell expected %d got %ld\n", j, l);
450   ok(feof(tempfh), "did not get EOF\n");
451   fclose(tempfh);
452   
453   tempfh = fopen(tempf,"rb"); /* open in BINARY mode */
454   ok(fgets(buffer,256,tempfh) != 0,"fgets failed unexpected\n");
455   i=strlen(buffer);
456   j=strlen(mytext)+3; /* should get through newline */
457   ok(i==j, "returned string length expected %d got %d\n", j, i);
458   l=ftell(tempfh);
459   ok(l==j, "ftell expected %d got %ld\n", j, l);
460   ok(fgets(buffer,256,tempfh) != 0,"fgets failed unexpected\n");
461   i=strlen(buffer);
462   ok(i==1, "returned string length expected %d got %d\n", 1, i);
463   ok(feof(tempfh), "did not get EOF\n");
464   fclose(tempfh);
465   unlink(tempf);
466 }
467
468 static void test_file_put_get( void )
469 {
470   char* tempf;
471   FILE *tempfh;
472   static const char mytext[]=  "This is a test_file_put_get\n";
473   static const char dostext[]= "This is a test_file_put_get\r\n";
474   char btext[LLEN];
475   WCHAR wtextW[LLEN+1];
476   WCHAR *mytextW = NULL, *aptr, *wptr;
477   BOOL diff_found = FALSE;
478   unsigned int i;
479
480   tempf=_tempnam(".","wne");
481   tempfh = fopen(tempf,"wt"); /* open in TEXT mode */
482   fputs(mytext,tempfh);
483   fclose(tempfh);
484   tempfh = fopen(tempf,"rb"); /* open in TEXT mode */
485   fgets(btext,LLEN,tempfh);
486   ok( strlen(mytext) + 1 == strlen(btext),"TEXT/BINARY mode not handled for write\n");
487   ok( btext[strlen(mytext)-1] == '\r', "CR not written\n");
488   fclose(tempfh);
489   tempfh = fopen(tempf,"wb"); /* open in BINARY mode */
490   fputs(dostext,tempfh);
491   fclose(tempfh);
492   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
493   fgets(btext,LLEN,tempfh);
494   ok(strcmp(btext, mytext) == 0,"_O_TEXT read doesn't strip CR\n");
495   fclose(tempfh);
496   tempfh = fopen(tempf,"rb"); /* open in TEXT mode */
497   fgets(btext,LLEN,tempfh);
498   ok(strcmp(btext, dostext) == 0,"_O_BINARY read doesn't preserve CR\n");
499
500   fclose(tempfh);
501   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
502   fgetws(wtextW,LLEN,tempfh);
503   mytextW = AtoW (mytext);
504   aptr = mytextW;
505   wptr = wtextW;
506
507   for (i=0; i<strlen(mytext); i++, aptr++, wptr++)
508     {
509       diff_found |= (*aptr != *wptr);
510     }
511   ok(!(diff_found), "fgetwc doesn't strip CR in TEXT mode\n");
512   free(mytextW);
513   fclose(tempfh);
514   unlink(tempf);
515 }
516
517 static void test_file_write_read( void )
518 {
519   char* tempf;
520   int tempfd;
521   static const char mytext[]=  "This is test_file_write_read\nsecond line\n";
522   static const char dostext[]= "This is test_file_write_read\r\nsecond line\r\n";
523   char btext[LLEN];
524   int ret, i;
525
526   tempf=_tempnam(".","wne");
527   tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_BINARY|_O_RDWR,
528                      _S_IREAD | _S_IWRITE);
529   ok( tempfd != -1,
530      "Can't open '%s': %d\n", tempf, errno); /* open in BINARY mode */
531   ok(_write(tempfd,dostext,strlen(dostext)) == lstrlenA(dostext),
532      "_write _O_BINARY bad return value\n");
533   _close(tempfd);
534   i = lstrlenA(mytext);
535   tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
536   ok(_read(tempfd,btext,i) == i,
537      "_read _O_BINARY got bad length\n");
538   ok( memcmp(dostext,btext,i) == 0,
539       "problems with _O_BINARY  _write / _read\n");
540   _close(tempfd);
541   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
542   ok(_read(tempfd,btext,i) == i-1,
543      "_read _O_TEXT got bad length\n");
544   ok( memcmp(mytext,btext,i-1) == 0,
545       "problems with _O_BINARY _write / _O_TEXT _read\n");
546   _close(tempfd);
547   tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_TEXT|_O_RDWR,
548                      _S_IREAD | _S_IWRITE);
549   ok( tempfd != -1,
550      "Can't open '%s': %d\n", tempf, errno); /* open in TEXT mode */
551   ok(_write(tempfd,mytext,strlen(mytext)) == lstrlenA(mytext),
552      "_write _O_TEXT bad return value\n");
553   _close(tempfd);
554   tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
555   ok(_read(tempfd,btext,LLEN) == lstrlenA(dostext),
556      "_read _O_BINARY got bad length\n");
557   ok( memcmp(dostext,btext,strlen(dostext)) == 0,
558       "problems with _O_TEXT _write / _O_BINARY _read\n");
559   ok( btext[strlen(dostext)-2] == '\r', "CR not written or read\n");
560   _close(tempfd);
561   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
562   ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext),
563      "_read _O_TEXT got bad length\n");
564   ok( memcmp(mytext,btext,strlen(mytext)) == 0,
565       "problems with _O_TEXT _write / _read\n");
566   _close(tempfd);
567
568   memset(btext, 0, LLEN);
569   tempfd = _open(tempf,_O_APPEND|_O_RDWR); /* open for APPEND in default mode */
570   ok(tell(tempfd) == 0, "bad position %lu expecting 0\n", tell(tempfd));
571   ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext), "_read _O_APPEND got bad length\n");
572   ok( memcmp(mytext,btext,strlen(mytext)) == 0, "problems with _O_APPEND _read\n");
573   _close(tempfd);
574
575   /* Test reading only \n or \r */
576   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
577   _lseek(tempfd, -1, FILE_END);
578   ret = _read(tempfd,btext,LLEN);
579   ok(ret == 1, "_read expected 1 got bad length: %d\n", ret);
580   _lseek(tempfd, -2, FILE_END);
581   ret = _read(tempfd,btext,LLEN);
582   ok(ret == 1 && *btext == '\n', "_read expected '\\n' got bad length: %d\n", ret);
583   _lseek(tempfd, -3, FILE_END);
584   ret = _read(tempfd,btext,2);
585   ok(ret == 1 && *btext == 'e', "_read expected 'e' got \"%.*s\" bad length: %d\n", ret, btext, ret);
586   ok(tell(tempfd) == 42, "bad position %lu expecting 42\n", tell(tempfd));
587   _close(tempfd);
588
589   ret = unlink(tempf);
590   ok( ret == 0 ,"Can't unlink '%s': %d\n", tempf, errno);
591
592   tempf=_tempnam(".","wne");
593   tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_BINARY|_O_RDWR,0);
594   ok( tempfd != -1,
595      "Can't open '%s': %d\n", tempf, errno); /* open in BINARY mode */
596   ok(_write(tempfd,dostext,strlen(dostext)) == lstrlenA(dostext),
597      "_write _O_BINARY bad return value\n");
598   _close(tempfd);
599   tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
600   ok(_read(tempfd,btext,LLEN) == lstrlenA(dostext),
601      "_read _O_BINARY got bad length\n");
602   ok( memcmp(dostext,btext,strlen(dostext)) == 0,
603       "problems with _O_BINARY _write / _read\n");
604   ok( btext[strlen(dostext)-2] == '\r', "CR not written or read\n");
605   _close(tempfd);
606   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
607   ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext),
608      "_read _O_TEXT got bad length\n");
609   ok( memcmp(mytext,btext,strlen(mytext)) == 0,
610       "problems with _O_BINARY _write / _O_TEXT _read\n");
611   _close(tempfd);
612
613    ret =_chmod (tempf, _S_IREAD | _S_IWRITE);
614   ok( ret == 0,
615      "Can't chmod '%s' to read-write: %d\n", tempf, errno);
616   ret = unlink(tempf);
617   ok( ret == 0 ,"Can't unlink '%s': %d\n", tempf, errno);
618 }
619
620 static void test_file_inherit_child(const char* fd_s)
621 {
622     int fd = atoi(fd_s);
623     char buffer[32];
624     int ret;
625
626     ret =write(fd, "Success", 8);
627     ok( ret == 8, "Couldn't write in child process on %d (%s)\n", fd, strerror(errno));
628     lseek(fd, 0, SEEK_SET);
629     ok(read(fd, buffer, sizeof (buffer)) == 8, "Couldn't read back the data\n");
630     ok(memcmp(buffer, "Success", 8) == 0, "Couldn't read back the data\n");
631 }
632
633 static void test_file_inherit_child_no(const char* fd_s)
634 {
635     int fd = atoi(fd_s);
636     int ret;
637
638     ret = write(fd, "Success", 8);
639     ok( ret == -1 && errno == EBADF, 
640        "Wrong write result in child process on %d (%s)\n", fd, strerror(errno));
641 }
642  
643 static void test_file_inherit( const char* selfname )
644 {
645     int                 fd;
646     const char*         arg_v[5];
647     char                buffer[16];
648
649     fd = open ("fdopen.tst", O_CREAT | O_RDWR | O_BINARY, _S_IREAD |_S_IWRITE);
650     ok(fd != -1, "Couldn't create test file\n");
651     arg_v[0] = selfname;
652     arg_v[1] = "tests/file.c";
653     arg_v[2] = "inherit";
654     arg_v[3] = buffer; sprintf(buffer, "%d", fd);
655     arg_v[4] = 0;
656     _spawnvp(_P_WAIT, selfname, arg_v);
657     ok(tell(fd) == 8, "bad position %lu expecting 8\n", tell(fd));
658     lseek(fd, 0, SEEK_SET);
659     ok(read(fd, buffer, sizeof (buffer)) == 8 && memcmp(buffer, "Success", 8) == 0, "Couldn't read back the data\n");
660     close (fd);
661     ok(unlink("fdopen.tst") == 0, "Couldn't unlink\n");
662     
663     fd = open ("fdopen.tst", O_CREAT | O_RDWR | O_BINARY | O_NOINHERIT, _S_IREAD |_S_IWRITE);
664     ok(fd != -1, "Couldn't create test file\n");
665     arg_v[0] = selfname;
666     arg_v[1] = "tests/file.c";
667     arg_v[2] = "inherit_no";
668     arg_v[3] = buffer; sprintf(buffer, "%d", fd);
669     arg_v[4] = 0;
670     _spawnvp(_P_WAIT, selfname, arg_v);
671     ok(tell(fd) == 0, "bad position %lu expecting 0\n", tell(fd));
672     ok(read(fd, buffer, sizeof (buffer)) == 0, "Found unexpected data (%s)\n", buffer);
673     close (fd);
674     ok(unlink("fdopen.tst") == 0, "Couldn't unlink\n");
675 }
676
677 static void test_tmpnam( void )
678 {
679   char name[MAX_PATH] = "abc";
680   char *res;
681
682   res = tmpnam(NULL);
683   ok(res != NULL, "tmpnam returned NULL\n");
684   ok(res[0] == '\\', "first character is not a backslash\n");
685   ok(strchr(res+1, '\\') == 0, "file not in the root directory\n");
686   ok(res[strlen(res)-1] == '.', "first call - last character is not a dot\n");
687
688   res = tmpnam(name);
689   ok(res != NULL, "tmpnam returned NULL\n");
690   ok(res == name, "supplied buffer was not used\n");
691   ok(res[0] == '\\', "first character is not a backslash\n");
692   ok(strchr(res+1, '\\') == 0, "file not in the root directory\n");
693   ok(res[strlen(res)-1] != '.', "second call - last character is a dot\n");
694 }
695
696 static void test_chsize( void )
697 {
698     int fd;
699     long cur, pos, count;
700     char temptext[] = "012345678";
701     char *tempfile = _tempnam( ".", "tst" );
702     
703     ok( tempfile != NULL, "Couldn't create test file: %s\n", tempfile );
704
705     fd = _open( tempfile, _O_CREAT|_O_TRUNC|_O_RDWR, _S_IREAD|_S_IWRITE );
706     ok( fd > 0, "Couldn't open test file\n" );
707
708     count = _write( fd, temptext, sizeof(temptext) );
709     ok( count > 0, "Couldn't write to test file\n" );
710
711     /* get current file pointer */
712     cur = _lseek( fd, 0, SEEK_CUR );
713
714     /* make the file smaller */
715     ok( _chsize( fd, sizeof(temptext) / 2 ) == 0, "_chsize() failed\n" );
716
717     pos = _lseek( fd, 0, SEEK_CUR );
718     ok( cur == pos, "File pointer changed from: %ld to: %ld\n", cur, pos );
719     ok( _filelength( fd ) == sizeof(temptext) / 2, "Wrong file size\n" );
720
721     /* enlarge the file */
722     ok( _chsize( fd, sizeof(temptext) * 2 ) == 0, "_chsize() failed\n" ); 
723
724     pos = _lseek( fd, 0, SEEK_CUR );
725     ok( cur == pos, "File pointer changed from: %ld to: %ld\n", cur, pos );
726     ok( _filelength( fd ) == sizeof(temptext) * 2, "Wrong file size\n" );
727
728     _close( fd );
729     _unlink( tempfile );
730 }
731
732 static void test_fopen_fclose_fcloseall( void )
733 {
734     char fname1[] = "empty1";
735     char fname2[] = "empty2";
736     char fname3[] = "empty3";
737     FILE *stream1, *stream2, *stream3, *stream4;
738     int ret, numclosed;
739
740     /* testing fopen() */
741     stream1 = fopen(fname1, "w+");
742     ok(stream1 != NULL, "The file '%s' was not opened\n", fname1);
743     stream2 = fopen(fname2, "w ");
744     ok(stream2 != NULL, "The file '%s' was not opened\n", fname2 );
745     _unlink(fname3);
746     stream3 = fopen(fname3, "r");
747     ok(stream3 == NULL, "The file '%s' shouldn't exist before\n", fname3 );
748     stream3 = fopen(fname3, "w+");
749     ok(stream3 != NULL, "The file '%s' should be opened now\n", fname3 );
750     errno = 0xfaceabad;
751     stream4 = fopen("", "w+");
752     ok(stream4 == NULL && errno == ENOENT, 
753        "filename is empty, errno = %d (expected 2)\n", errno);
754     errno = 0xfaceabad;
755     stream4 = fopen(NULL, "w+");
756     ok(stream4 == NULL && (errno == EINVAL || errno == ENOENT), 
757        "filename is NULL, errno = %d (expected 2 or 22)\n", errno);
758
759     /* testing fclose() */
760     ret = fclose(stream2);
761     ok(ret == 0, "The file '%s' was not closed\n", fname2);
762     ret = fclose(stream3);
763     ok(ret == 0, "The file '%s' was not closed\n", fname3);
764     ret = fclose(stream2);
765     ok(ret == EOF, "Closing file '%s' returned %d\n", fname2, ret);
766     ret = fclose(stream3);
767     ok(ret == EOF, "Closing file '%s' returned %d\n", fname3, ret);
768
769     /* testing fcloseall() */
770     numclosed = _fcloseall();
771     /* fname1 should be closed here */
772     ok(numclosed == 1, "Number of files closed by fcloseall(): %u\n", numclosed);
773     numclosed = _fcloseall();
774     ok(numclosed == 0, "Number of files closed by fcloseall(): %u\n", numclosed);
775
776     ok(_unlink(fname1) == 0, "Couldn't unlink file named '%s'\n", fname1);
777     ok(_unlink(fname2) == 0, "Couldn't unlink file named '%s'\n", fname2);
778     ok(_unlink(fname3) == 0, "Couldn't unlink file named '%s'\n", fname3);
779 }
780
781 static void test_get_osfhandle(void)
782 {
783     int fd;
784     char fname[] = "t_get_osfhanle";
785     DWORD bytes_written;
786     HANDLE handle;
787
788     fd = _sopen(fname, _O_CREAT|_O_RDWR, _SH_DENYRW, _S_IREAD | _S_IWRITE);
789     handle = (HANDLE)_get_osfhandle(fd);
790     WriteFile(handle, "bar", 3, &bytes_written, NULL);
791     _close(fd);
792     fd = _open(fname, _O_RDONLY, 0);
793     ok(fd != -1, "Coudn't open '%s' after _get_osfhanle()\n", fname);
794
795     _close(fd);
796     _unlink(fname);
797 }
798
799 static void test_setmaxstdio(void)
800 {
801     ok(2048 == _setmaxstdio(2048),"_setmaxstdio returned %d instead of 2048\n",_setmaxstdio(2048));
802     ok(-1 == _setmaxstdio(2049),"_setmaxstdio returned %d instead of -1\n",_setmaxstdio(2049));
803 }
804
805 static void test_stat(void)
806 {
807     int fd;
808     int pipes[2];
809     struct stat buf;
810
811     /* Tests for a file */
812     fd = open("stat.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE);
813     if (fd >= 0)
814     {
815         if (fstat(fd, &buf) == 0)
816         {
817             if ((buf.st_mode & _S_IFMT) == _S_IFREG)
818             {
819                 ok(buf.st_dev == 0, "st_dev is %d, expected 0\n", buf.st_dev);
820                 ok(buf.st_dev == buf.st_rdev, "st_dev (%d) and st_rdev (%d) differ\n",
821                     buf.st_dev, buf.st_rdev);
822                 ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n",
823                     buf.st_nlink);
824                 ok(buf.st_size == 0, "st_size is %d, expected 0\n",
825                     buf.st_size);
826             }
827             else
828                 skip("file is not a file?\n");
829         }
830         else
831             skip("fstat failed, errno %d\n", errno);
832         close(fd);
833         remove("stat.tst");
834     }
835     else
836         skip("open failed with errno %d\n", errno);
837
838     /* Tests for a char device */
839     if (_dup2(0, 10) == 0)
840     {
841         if (fstat(10, &buf) == 0)
842         {
843             if (buf.st_mode == _S_IFCHR)
844             {
845                 ok(buf.st_dev == 10, "st_dev is %d, expected 10\n", buf.st_dev);
846                 ok(buf.st_rdev == 10, "st_rdev is %d, expected 10\n", buf.st_rdev);
847                 ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink);
848             }
849             else
850                 skip("stdin is not a char device?\n");
851         }
852         else
853             skip("fstat failed with errno %d\n", errno);
854         close(10);
855     }
856     else
857         skip("_dup2 failed with errno %d\n", errno);
858
859     /* Tests for pipes */
860     if (_pipe(pipes, 1024, O_BINARY) == 0)
861     {
862         if (fstat(pipes[0], &buf) == 0)
863         {
864             if (buf.st_mode == _S_IFIFO)
865             {
866                 ok(buf.st_dev == pipes[0], "st_dev is %d, expected %d\n",
867                     buf.st_dev, pipes[0]);
868                 ok(buf.st_rdev == pipes[0], "st_rdev is %d, expected %d\n",
869                     buf.st_rdev, pipes[0]);
870                 ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n",
871                     buf.st_nlink);
872             }
873             else
874                 skip("pipe() didn't make a pipe?\n");
875         }
876         else
877             skip("fstat failed with errno %d\n", errno);
878         close(pipes[0]);
879         close(pipes[1]);
880     }
881     else
882         skip("pipe failed with errno %d\n", errno);
883 }
884
885 static const char* pipe_string="Hello world";
886
887 static void test_pipes_child(int argc, char** args)
888 {
889     int fd;
890
891     if (argc < 5)
892     {
893         ok(0, "not enough parameters: %d\n", argc);
894         return;
895     }
896
897     fd=atoi(args[3]);
898     ok(close(fd) == 0, "unable to close %d: %d\n", fd, errno);
899
900     fd=atoi(args[4]);
901     write(fd, pipe_string, strlen(pipe_string));
902     ok(close(fd) == 0, "unable to close %d: %d\n", fd, errno);
903 }
904
905 static void test_pipes(const char* selfname)
906 {
907     int pipes[2];
908     char str_fdr[12], str_fdw[12];
909     FILE* file;
910     const char* arg_v[6];
911     char buf[4096];
912     int r;
913
914     /* Test reading from a pipe with read() */
915     if (_pipe(pipes, 1024, O_BINARY) < 0)
916     {
917         ok(0, "pipe failed with errno %d\n", errno);
918         return;
919     }
920
921     arg_v[0] = selfname;
922     arg_v[1] = "tests/file.c";
923     arg_v[2] = "pipes";
924     arg_v[3] = str_fdr; sprintf(str_fdr, "%d", pipes[0]);
925     arg_v[4] = str_fdw; sprintf(str_fdw, "%d", pipes[1]);
926     arg_v[5] = NULL;
927     proc_handles[0] = (HANDLE)_spawnvp(_P_NOWAIT, selfname, arg_v);
928     ok(close(pipes[1]) == 0, "unable to close %d: %d\n", pipes[1], errno);
929
930     r=read(pipes[0], buf, sizeof(buf)-1);
931     ok(r == strlen(pipe_string), "expected to read %d bytes, got %d\n", strlen(pipe_string)+1, r);
932     if (r > 0)
933         buf[r]='\0';
934     ok(strcmp(buf, pipe_string) == 0, "expected to read '%s', got '%s'\n", pipe_string, buf);
935     r=read(pipes[0], buf, sizeof(buf)-1);
936     ok(r == 0, "expected to read 0 bytes, got %d\n", r);
937     ok(close(pipes[0]) == 0, "unable to close %d: %d\n", pipes[0], errno);
938
939     /* Test reading from a pipe with fread() */
940     if (_pipe(pipes, 1024, O_BINARY) < 0)
941     {
942         ok(0, "pipe failed with errno %d\n", errno);
943         return;
944     }
945
946     arg_v[0] = selfname;
947     arg_v[1] = "tests/file.c";
948     arg_v[2] = "pipes";
949     arg_v[3] = str_fdr; sprintf(str_fdr, "%d", pipes[0]);
950     arg_v[4] = str_fdw; sprintf(str_fdw, "%d", pipes[1]);
951     arg_v[5] = NULL;
952     proc_handles[1] = (HANDLE)_spawnvp(_P_NOWAIT, selfname, arg_v);
953     ok(close(pipes[1]) == 0, "unable to close %d: %d\n", pipes[1], errno);
954     file=fdopen(pipes[0], "r");
955
956     r=fread(buf, 1, sizeof(buf)-1, file);
957     ok(r == strlen(pipe_string), "fread() returned %d instead of %d: ferror=%d\n", r, strlen(pipe_string), ferror(file));
958     if (r > 0)
959         buf[r]='\0';
960     ok(strcmp(buf, pipe_string) == 0, "got '%s' expected '%s'\n", buf, pipe_string);
961
962     r=fread(buf, 1, sizeof(buf)-1, file);
963     ok(r == 0, "fread() returned %d instead of 0\n", r);
964     ok(ferror(file) == 0, "got ferror() = %d\n", ferror(file));
965     ok(feof(file), "feof() is false!\n");
966
967     ok(fclose(file) == 0, "unable to close the pipe: %d\n", errno);
968 }
969
970 START_TEST(file)
971 {
972     int arg_c;
973     char** arg_v;
974
975     arg_c = winetest_get_mainargs( &arg_v );
976
977     /* testing low-level I/O */
978     if (arg_c >= 3)
979     {
980         if (strcmp(arg_v[2], "inherit") == 0)
981             test_file_inherit_child(arg_v[3]);
982         else if (strcmp(arg_v[2], "inherit_no") == 0)
983             test_file_inherit_child_no(arg_v[3]);
984         else if (strcmp(arg_v[2], "pipes") == 0)
985             test_pipes_child(arg_c, arg_v);
986         else
987             ok(0, "invalid argument '%s'\n", arg_v[2]);
988         return;
989     }
990     test_file_inherit(arg_v[0]);
991     test_file_write_read();
992     test_chsize();
993     test_stat();
994
995     /* testing stream I/O */
996     test_fdopen();
997     test_fopen_fclose_fcloseall();
998     test_fileops();
999     test_readmode(FALSE); /* binary mode */
1000     test_readmode(TRUE);  /* ascii mode */
1001     test_fgetc();
1002     test_fgetwc();
1003     test_ctrlz();
1004     test_file_put_get();
1005     test_tmpnam();
1006     test_get_osfhandle();
1007     test_setmaxstdio();
1008     test_pipes(arg_v[0]);
1009
1010     /* Wait for the (_P_NOWAIT) spawned processes to finish to make sure the report
1011      * file contains lines in the correct order
1012      */
1013     WaitForMultipleObjects(sizeof(proc_handles)/sizeof(proc_handles[0]), proc_handles, TRUE, 5000);
1014 }