mcicda: Exclude unused headers.
[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 void test_fdopen( void )
38 {
39     static const char buffer[] = {0,1,2,3,4,5,6,7,8,9};
40     char ibuf[10];
41     int fd;
42     FILE *file;
43
44     fd = open ("fdopen.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE);
45     write (fd, buffer, sizeof (buffer));
46     close (fd);
47
48     fd = open ("fdopen.tst", O_RDONLY | O_BINARY);
49     lseek (fd, 5, SEEK_SET);
50     file = fdopen (fd, "rb");
51     ok (fread (ibuf, 1, sizeof (buffer), file) == 5, "read wrong byte count\n");
52     ok (memcmp (ibuf, buffer + 5, 5) == 0, "read wrong bytes\n");
53     fclose (file);
54     unlink ("fdopen.tst");
55 }
56
57 static void test_fileops( void )
58 {
59     static const char outbuffer[] = "0,1,2,3,4,5,6,7,8,9";
60     char buffer[256];
61     WCHAR wbuffer[256];
62     int fd;
63     FILE *file;
64     fpos_t pos;
65     int i, c;
66
67     fd = open ("fdopen.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE);
68     write (fd, outbuffer, sizeof (outbuffer));
69     close (fd);
70
71     fd = open ("fdopen.tst", O_RDONLY | O_BINARY);
72     file = fdopen (fd, "rb");
73     ok(strlen(outbuffer) == (sizeof(outbuffer)-1),"strlen/sizeof error\n");
74     ok(fgets(buffer,sizeof(buffer),file) !=0,"fgets failed unexpected\n");
75     ok(fgets(buffer,sizeof(buffer),file) ==0,"fgets didn't signal EOF\n");
76     ok(feof(file) !=0,"feof doesn't signal EOF\n");
77     rewind(file);
78     ok(fgets(buffer,strlen(outbuffer),file) !=0,"fgets failed unexpected\n");
79     ok(lstrlenA(buffer) == lstrlenA(outbuffer) -1,"fgets didn't read right size\n");
80     ok(fgets(buffer,sizeof(outbuffer),file) !=0,"fgets failed unexpected\n");
81     ok(strlen(buffer) == 1,"fgets dropped chars\n");
82     ok(buffer[0] == outbuffer[strlen(outbuffer)-1],"fgets exchanged chars\n");
83
84     rewind(file);
85     for (i = 0, c = EOF; i < sizeof(outbuffer); i++)
86     {
87         ok((c = fgetc(file)) == outbuffer[i], "fgetc returned wrong data\n");
88     }
89     ok((c = fgetc(file)) == EOF, "getc did not return EOF\n");
90     ok(feof(file), "feof did not return EOF\n");
91     ok(ungetc(c, file) == EOF, "ungetc(EOF) did not return EOF\n");
92     ok(feof(file), "feof after ungetc(EOF) did not return EOF\n");
93     ok((c = fgetc(file)) == EOF, "getc did not return EOF\n");
94     c = outbuffer[sizeof(outbuffer) - 1];
95     ok(ungetc(c, file) == c, "ungetc did not return its input\n");
96     ok(!feof(file), "feof after ungetc returned EOF\n");
97     ok((c = fgetc(file)) != EOF, "getc after ungetc returned EOF\n");
98     ok(c == outbuffer[sizeof(outbuffer) - 1],
99        "getc did not return ungetc'd data\n");
100     ok(!feof(file), "feof after getc returned EOF prematurely\n");
101     ok((c = fgetc(file)) == EOF, "getc did not return EOF\n");
102     ok(feof(file), "feof after getc did not return EOF\n");
103
104     rewind(file);
105     ok(fgetpos(file,&pos) == 0, "fgetpos failed unexpected\n");
106     ok(pos == 0, "Unexpected result of fgetpos 0x%Lx\n", pos);
107     pos = (ULONGLONG)sizeof (outbuffer);
108     ok(fsetpos(file, &pos) == 0, "fsetpos failed unexpected\n");
109     ok(fgetpos(file,&pos) == 0, "fgetpos failed unexpected\n");
110     ok(pos == (ULONGLONG)sizeof (outbuffer), "Unexpected result of fgetpos 0x%Lx\n", pos);
111
112     fclose (file);
113     fd = open ("fdopen.tst", O_RDONLY | O_TEXT);
114     file = fdopen (fd, "rt"); /* open in TEXT mode */
115     ok(fgetws(wbuffer,sizeof(wbuffer),file) !=0,"fgetws failed unexpected\n");
116     ok(fgetws(wbuffer,sizeof(wbuffer),file) ==0,"fgetws didn't signal EOF\n");
117     ok(feof(file) !=0,"feof doesn't signal EOF\n");
118     rewind(file);
119     ok(fgetws(wbuffer,strlen(outbuffer),file) !=0,"fgetws failed unexpected\n");
120     ok(lstrlenW(wbuffer) == (lstrlenA(outbuffer) -1),"fgetws didn't read right size\n");
121     ok(fgetws(wbuffer,sizeof(outbuffer),file) !=0,"fgets failed unexpected\n");
122     ok(lstrlenW(wbuffer) == 1,"fgets dropped chars\n");
123     fclose (file);
124
125     file = fopen("fdopen.tst", "rb");
126     ok( file != NULL, "fopen failed\n");
127     /* sizeof(buffer) > content of file */
128     ok(fread(buffer, sizeof(buffer), 1, file) == 0, "fread test failed\n");
129     /* feof should be set now */
130     ok(feof(file), "feof after fread failed\n");
131     fclose (file);
132
133     unlink ("fdopen.tst");
134 }
135
136 #define IOMODE (ao?"ascii mode":"binary mode")
137 static void test_readmode( BOOL ascii_mode )
138 {
139     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";
140     static const char padbuffer[] = "ghjghjghjghj";
141     static const char nlbuffer[] = "\r\n";
142     char buffer[2*BUFSIZ+256];
143     const char *optr;
144     int fd;
145     FILE *file;
146     const int *ip;
147     int i, j, m, fp, ao, pl;
148     long l;
149
150     fd = open ("fdopen.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE);
151     /* an internal buffer of BUFSIZ is maintained, so make a file big
152      * enough to test operations that cross the buffer boundary 
153      */
154     j = (2*BUFSIZ-4)/strlen(padbuffer);
155     for (i=0; i<j; i++)
156         write (fd, padbuffer, strlen(padbuffer));
157     j = (2*BUFSIZ-4)%strlen(padbuffer);
158     for (i=0; i<j; i++)
159         write (fd, &padbuffer[i], 1);
160     write (fd, nlbuffer, strlen(nlbuffer));
161     write (fd, outbuffer, sizeof (outbuffer));
162     close (fd);
163     
164     if (ascii_mode) {
165         /* Open file in ascii mode */
166         fd = open ("fdopen.tst", O_RDONLY);
167         file = fdopen (fd, "r");
168         ao = -1; /* on offset to account for carriage returns */
169     }
170     else {
171         fd = open ("fdopen.tst", O_RDONLY | O_BINARY);
172         file = fdopen (fd, "rb");
173         ao = 0;
174     }
175     
176     /* first is a test of fgets, ftell, fseek */
177     ok(ftell(file) == 0,"Did not start at beginning of file in %s\n", IOMODE);
178     ok(fgets(buffer,2*BUFSIZ+256,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE);
179     l = ftell(file);
180     pl = 2*BUFSIZ-2;
181     ok(l == pl,"padding line ftell got %ld should be %d in %s\n", l, pl, IOMODE);
182     ok(lstrlenA(buffer) == pl+ao,"padding line fgets got size %d should be %d in %s\n",
183      lstrlenA(buffer), pl+ao, IOMODE);
184     for (fp=0; fp<strlen(outbuffer); fp++)
185         if (outbuffer[fp] == '\n') break;
186     fp++;
187     ok(fgets(buffer,256,file) !=0,"line 1 fgets failed unexpected in %s\n", IOMODE);
188     l = ftell(file);
189     ok(l == pl+fp,"line 1 ftell got %ld should be %d in %s\n", l, pl+fp, IOMODE);
190     ok(lstrlenA(buffer) == fp+ao,"line 1 fgets got size %d should be %d in %s\n",
191      lstrlenA(buffer), fp+ao, IOMODE);
192     /* test a seek back across the buffer boundary */
193     l = pl;
194     ok(fseek(file,l,SEEK_SET)==0,"seek failure in %s\n", IOMODE);
195     l = ftell(file);
196     ok(l == pl,"ftell after seek got %ld should be %d in %s\n", l, pl, IOMODE);
197     ok(fgets(buffer,256,file) !=0,"second read of line 1 fgets failed unexpected in %s\n", IOMODE);
198     l = ftell(file);
199     ok(l == pl+fp,"second read of line 1 ftell got %ld should be %d in %s\n", l, pl+fp, IOMODE);
200     ok(lstrlenA(buffer) == fp+ao,"second read of line 1 fgets got size %d should be %d in %s\n",
201      lstrlenA(buffer), fp+ao, IOMODE);
202     ok(fgets(buffer,256,file) !=0,"line 2 fgets failed unexpected in %s\n", IOMODE);
203     fp += 2;
204     l = ftell(file);
205     ok(l == pl+fp,"line 2 ftell got %ld should be %d in %s\n", l, pl+fp, IOMODE);
206     ok(lstrlenA(buffer) == 2+ao,"line 2 fgets got size %d should be %d in %s\n",
207      lstrlenA(buffer), 2+ao, IOMODE);
208     
209     /* test fread across buffer boundary */
210     rewind(file);
211     ok(ftell(file) == 0,"Did not start at beginning of file in %s\n", IOMODE);
212     ok(fgets(buffer,BUFSIZ-6,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE);
213     j=strlen(outbuffer);
214     i=fread(buffer,1,BUFSIZ+strlen(outbuffer),file);
215     ok(i==BUFSIZ+j,"fread failed, expected %d got %d in %s\n", BUFSIZ+j, i, IOMODE);
216     l = ftell(file);
217     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);
218     for (m=0; m<3; m++)
219         ok(buffer[m]==padbuffer[m+(BUFSIZ-4)%strlen(padbuffer)],"expected %c got %c\n", padbuffer[m], buffer[m]);
220     m+=BUFSIZ+2+ao;
221     optr = outbuffer;
222     for (; m<i; m++) {
223         ok(buffer[m]==*optr,"char %d expected %c got %c in %s\n", m, *optr, buffer[m], IOMODE);
224         optr++;
225         if (ao && (*optr == '\r'))
226             optr++;
227     }
228     /* fread should return the requested number of bytes if available */
229     rewind(file);
230     ok(ftell(file) == 0,"Did not start at beginning of file in %s\n", IOMODE);
231     ok(fgets(buffer,BUFSIZ-6,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE);
232     j = fp+10;
233     i=fread(buffer,1,j,file);
234     ok(i==j,"fread failed, expected %d got %d in %s\n", j, i, IOMODE);
235     /* test fread eof */
236     ok(fseek(file,0,SEEK_END)==0,"seek failure in %s\n", IOMODE);
237     ok(feof(file)==0,"feof failure in %s\n", IOMODE);
238     ok(fread(buffer,1,1,file)==0,"fread failure in %s\n", IOMODE);
239     ok(feof(file)!=0,"feof failure in %s\n", IOMODE);
240     ok(fseek(file,-3,SEEK_CUR)==0,"seek failure in %s\n", IOMODE);
241     todo_wine ok(feof(file)==0,"feof failure in %s\n", IOMODE);
242     ok(fread(buffer,2,1,file)==1,"fread failed in %s\n", IOMODE);
243     ok(feof(file)==0,"feof failure in %s\n", IOMODE);
244     ok(fread(buffer,2,1,file)==0,"fread failure in %s\n",IOMODE);
245     ok(feof(file)!=0,"feof failure in %s\n", IOMODE);
246     
247     /* test some additional functions */
248     rewind(file);
249     ok(ftell(file) == 0,"Did not start at beginning of file in %s\n", IOMODE);
250     ok(fgets(buffer,2*BUFSIZ+256,file) !=0,"padding line fgets failed unexpected in %s\n", IOMODE);
251     i = _getw(file);
252     ip = (const int *)outbuffer;
253     ok(i == *ip,"_getw failed, expected %08x got %08x in %s\n", *ip, i, IOMODE);
254     for (fp=0; fp<strlen(outbuffer); fp++)
255         if (outbuffer[fp] == '\n') break;
256     fp++;
257     /* this will cause the next _getw to cross carriage return characters */
258     ok(fgets(buffer,fp-6,file) !=0,"line 1 fgets failed unexpected in %s\n", IOMODE);
259     for (i=0, j=0; i<6; i++) {
260         if (ao==0 || outbuffer[fp-3+i] != '\r')
261             buffer[j++] = outbuffer[fp-3+i];
262     }
263     i = _getw(file);
264     ip = (int *)buffer;
265     ok(i == *ip,"_getw failed, expected %08x got %08x in %s\n", *ip, i, IOMODE);
266
267     fclose (file);
268     unlink ("fdopen.tst");
269 }
270
271
272 static WCHAR* AtoW( const char* p )
273 {
274     WCHAR* buffer;
275     DWORD len = MultiByteToWideChar( CP_ACP, 0, p, -1, NULL, 0 );
276     buffer = malloc( len * sizeof(WCHAR) );
277     MultiByteToWideChar( CP_ACP, 0, p, -1, buffer, len );
278     return buffer;
279 }
280
281 static void test_fgetc( void )
282 {
283   char* tempf;
284   FILE *tempfh;
285   int  ich=0xe0, ret;
286
287   tempf=_tempnam(".","wne");
288   tempfh = fopen(tempf,"w+");
289   fputc(ich, tempfh);
290   fputc(ich, tempfh);
291   rewind(tempfh);
292   ret = fgetc(tempfh);
293   ok(ich == ret, "First fgetc expected %x got %x\n", ich, ret);
294   ret = fgetc(tempfh);
295   ok(ich == ret, "Second fgetc expected %x got %x\n", ich, ret);
296   fclose(tempfh);
297   unlink(tempf);
298 }
299
300 static void test_fgetwc( void )
301 {
302 #define LLEN 512
303
304   char* tempf;
305   FILE *tempfh;
306   static const char mytext[]= "This is test_fgetwc\r\n";
307   WCHAR wtextW[BUFSIZ+LLEN+1];
308   WCHAR *mytextW = NULL, *aptr, *wptr;
309   BOOL diff_found = FALSE;
310   int i, j;
311   long l;
312
313   tempf=_tempnam(".","wne");
314   tempfh = fopen(tempf,"wb");
315   j = 'a';
316   /* pad to almost the length of the internal buffer */
317   for (i=0; i<BUFSIZ-4; i++)
318     fputc(j,tempfh);
319   j = '\r';
320   fputc(j,tempfh);
321   j = '\n';
322   fputc(j,tempfh);
323   fputs(mytext,tempfh);
324   fclose(tempfh);
325   /* in text mode, getws/c expects multibyte characters */
326   /*currently Wine only supports plain ascii, and that is all that is tested here */
327   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
328   fgetws(wtextW,LLEN,tempfh);
329   l=ftell(tempfh);
330   ok(l==BUFSIZ-2, "ftell expected %d got %ld\n", BUFSIZ-2, l);
331   fgetws(wtextW,LLEN,tempfh);
332   l=ftell(tempfh);
333   ok(l==BUFSIZ-2+strlen(mytext), "ftell expected %d got %ld\n",
334    BUFSIZ-2+strlen(mytext), l);
335   mytextW = AtoW (mytext);
336   aptr = mytextW;
337   wptr = wtextW;
338   for (i=0; i<strlen(mytext)-2; i++, aptr++, wptr++)
339     {
340       diff_found |= (*aptr != *wptr);
341     }
342   ok(!(diff_found), "fgetwc difference found in TEXT mode\n");
343   ok(*wptr == '\n', "Carriage return was not skipped\n");
344   fclose(tempfh);
345   unlink(tempf);
346   
347   tempfh = fopen(tempf,"wb");
348   j = 'a';
349   /* pad to almost the length of the internal buffer. Use an odd number of bytes
350      to test that we can read wchars that are split across the internal buffer
351      boundary */
352   for (i=0; i<BUFSIZ-3-strlen(mytext)*sizeof(WCHAR); i++)
353     fputc(j,tempfh);
354   j = '\r';
355   fputwc(j,tempfh);
356   j = '\n';
357   fputwc(j,tempfh);
358   fputws(wtextW,tempfh);
359   fputws(wtextW,tempfh);
360   fclose(tempfh);
361   /* in binary mode, getws/c expects wide characters */
362   tempfh = fopen(tempf,"rb"); /* open in BINARY mode */
363   j=(BUFSIZ-2)/sizeof(WCHAR)-strlen(mytext);
364   fgetws(wtextW,j,tempfh);
365   l=ftell(tempfh);
366   j=(j-1)*sizeof(WCHAR);
367   ok(l==j, "ftell expected %d got %ld\n", j, l);
368   i=fgetc(tempfh);
369   ok(i=='a', "fgetc expected %d got %d\n", 0x61, i);
370   l=ftell(tempfh);
371   j++;
372   ok(l==j, "ftell expected %d got %ld\n", j, l);
373   fgetws(wtextW,3,tempfh);
374   ok(wtextW[0]=='\r',"expected carriage return got %04hx\n", wtextW[0]);
375   ok(wtextW[1]=='\n',"expected newline got %04hx\n", wtextW[1]);
376   l=ftell(tempfh);
377   j += 4;
378   ok(l==j, "ftell expected %d got %ld\n", j, l);
379   for(i=0; i<strlen(mytext); i++)
380     wtextW[i] = 0;
381   /* the first time we get the string, it should be entirely within the local buffer */
382   fgetws(wtextW,LLEN,tempfh);
383   l=ftell(tempfh);
384   j += (strlen(mytext)-1)*sizeof(WCHAR);
385   ok(l==j, "ftell expected %d got %ld\n", j, l);
386   diff_found = FALSE;
387   aptr = mytextW;
388   wptr = wtextW;
389   for (i=0; i<strlen(mytext)-2; i++, aptr++, wptr++)
390     {
391       ok(*aptr == *wptr, "Char %d expected %04hx got %04hx\n", i, *aptr, *wptr);
392       diff_found |= (*aptr != *wptr);
393     }
394   ok(!(diff_found), "fgetwc difference found in BINARY mode\n");
395   ok(*wptr == '\n', "Should get newline\n");
396   for(i=0; i<strlen(mytext); i++)
397     wtextW[i] = 0;
398   /* the second time we get the string, it should cross the local buffer boundary.
399      One of the wchars should be split across the boundary */
400   fgetws(wtextW,LLEN,tempfh);
401   diff_found = FALSE;
402   aptr = mytextW;
403   wptr = wtextW;
404   for (i=0; i<strlen(mytext)-2; i++, aptr++, wptr++)
405     {
406       ok(*aptr == *wptr, "Char %d expected %04hx got %04hx\n", i, *aptr, *wptr);
407       diff_found |= (*aptr != *wptr);
408     }
409   ok(!(diff_found), "fgetwc difference found in BINARY mode\n");
410   ok(*wptr == '\n', "Should get newline\n");
411
412   free(mytextW);
413   fclose(tempfh);
414   unlink(tempf);
415 }
416
417 static void test_ctrlz( void )
418 {
419   char* tempf;
420   FILE *tempfh;
421   static const char mytext[]= "This is test_ctrlz";
422   char buffer[256];
423   int i, j;
424   long l;
425
426   tempf=_tempnam(".","wne");
427   tempfh = fopen(tempf,"wb");
428   fputs(mytext,tempfh);
429   j = 0x1a; /* a ctrl-z character signals EOF in text mode */
430   fputc(j,tempfh);
431   j = '\r';
432   fputc(j,tempfh);
433   j = '\n';
434   fputc(j,tempfh);
435   j = 'a';
436   fputc(j,tempfh);
437   fclose(tempfh);
438   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
439   ok(fgets(buffer,256,tempfh) != 0,"fgets failed unexpected\n");
440   i=strlen(buffer);
441   j=strlen(mytext);
442   ok(i==j, "returned string length expected %d got %d\n", j, i);
443   j+=4; /* ftell should indicate the true end of file */
444   l=ftell(tempfh);
445   ok(l==j, "ftell expected %d got %ld\n", j, l);
446   ok(feof(tempfh), "did not get EOF\n");
447   fclose(tempfh);
448   
449   tempfh = fopen(tempf,"rb"); /* open in BINARY mode */
450   ok(fgets(buffer,256,tempfh) != 0,"fgets failed unexpected\n");
451   i=strlen(buffer);
452   j=strlen(mytext)+3; /* should get through newline */
453   ok(i==j, "returned string length expected %d got %d\n", j, i);
454   l=ftell(tempfh);
455   ok(l==j, "ftell expected %d got %ld\n", j, l);
456   ok(fgets(buffer,256,tempfh) != 0,"fgets failed unexpected\n");
457   i=strlen(buffer);
458   ok(i==1, "returned string length expected %d got %d\n", 1, i);
459   ok(feof(tempfh), "did not get EOF\n");
460   fclose(tempfh);
461   unlink(tempf);
462 }
463
464 static void test_file_put_get( void )
465 {
466   char* tempf;
467   FILE *tempfh;
468   static const char mytext[]=  "This is a test_file_put_get\n";
469   static const char dostext[]= "This is a test_file_put_get\r\n";
470   char btext[LLEN];
471   WCHAR wtextW[LLEN+1];
472   WCHAR *mytextW = NULL, *aptr, *wptr;
473   BOOL diff_found = FALSE;
474   unsigned int i;
475
476   tempf=_tempnam(".","wne");
477   tempfh = fopen(tempf,"wt"); /* open in TEXT mode */
478   fputs(mytext,tempfh);
479   fclose(tempfh);
480   tempfh = fopen(tempf,"rb"); /* open in TEXT mode */
481   fgets(btext,LLEN,tempfh);
482   ok( strlen(mytext) + 1 == strlen(btext),"TEXT/BINARY mode not handled for write\n");
483   ok( btext[strlen(mytext)-1] == '\r', "CR not written\n");
484   fclose(tempfh);
485   tempfh = fopen(tempf,"wb"); /* open in BINARY mode */
486   fputs(dostext,tempfh);
487   fclose(tempfh);
488   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
489   fgets(btext,LLEN,tempfh);
490   ok(strcmp(btext, mytext) == 0,"_O_TEXT read doesn't strip CR\n");
491   fclose(tempfh);
492   tempfh = fopen(tempf,"rb"); /* open in TEXT mode */
493   fgets(btext,LLEN,tempfh);
494   ok(strcmp(btext, dostext) == 0,"_O_BINARY read doesn't preserve CR\n");
495
496   fclose(tempfh);
497   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
498   fgetws(wtextW,LLEN,tempfh);
499   mytextW = AtoW (mytext);
500   aptr = mytextW;
501   wptr = wtextW;
502
503   for (i=0; i<strlen(mytext); i++, aptr++, wptr++)
504     {
505       diff_found |= (*aptr != *wptr);
506     }
507   ok(!(diff_found), "fgetwc doesn't strip CR in TEXT mode\n");
508   free(mytextW);
509   fclose(tempfh);
510   unlink(tempf);
511 }
512
513 static void test_file_write_read( void )
514 {
515   char* tempf;
516   int tempfd;
517   static const char mytext[]=  "This is test_file_write_read\nsecond line\n";
518   static const char dostext[]= "This is test_file_write_read\r\nsecond line\r\n";
519   char btext[LLEN];
520   int ret, i;
521
522   tempf=_tempnam(".","wne");
523   tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_BINARY|_O_RDWR,
524                      _S_IREAD | _S_IWRITE);
525   ok( tempfd != -1,
526      "Can't open '%s': %d\n", tempf, errno); /* open in BINARY mode */
527   ok(_write(tempfd,dostext,strlen(dostext)) == lstrlenA(dostext),
528      "_write _O_BINARY bad return value\n");
529   _close(tempfd);
530   i = lstrlenA(mytext);
531   tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
532   ok(_read(tempfd,btext,i) == i,
533      "_read _O_BINARY got bad length\n");
534   ok( memcmp(dostext,btext,i) == 0,
535       "problems with _O_BINARY  _write / _read\n");
536   _close(tempfd);
537   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
538   ok(_read(tempfd,btext,i) == i-1,
539      "_read _O_TEXT got bad length\n");
540   ok( memcmp(mytext,btext,i-1) == 0,
541       "problems with _O_BINARY _write / _O_TEXT _read\n");
542   _close(tempfd);
543   tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_TEXT|_O_RDWR,
544                      _S_IREAD | _S_IWRITE);
545   ok( tempfd != -1,
546      "Can't open '%s': %d\n", tempf, errno); /* open in TEXT mode */
547   ok(_write(tempfd,mytext,strlen(mytext)) == lstrlenA(mytext),
548      "_write _O_TEXT bad return value\n");
549   _close(tempfd);
550   tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
551   ok(_read(tempfd,btext,LLEN) == lstrlenA(dostext),
552      "_read _O_BINARY got bad length\n");
553   ok( memcmp(dostext,btext,strlen(dostext)) == 0,
554       "problems with _O_TEXT _write / _O_BINARY _read\n");
555   ok( btext[strlen(dostext)-2] == '\r', "CR not written or read\n");
556   _close(tempfd);
557   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
558   ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext),
559      "_read _O_TEXT got bad length\n");
560   ok( memcmp(mytext,btext,strlen(mytext)) == 0,
561       "problems with _O_TEXT _write / _read\n");
562   _close(tempfd);
563
564   memset(btext, 0, LLEN);
565   tempfd = _open(tempf,_O_APPEND|_O_RDWR); /* open for APPEND in default mode */
566   ok(tell(tempfd) == 0, "bad position %lu expecting 0\n", tell(tempfd));
567   ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext), "_read _O_APPEND got bad length\n");
568   ok( memcmp(mytext,btext,strlen(mytext)) == 0, "problems with _O_APPEND _read\n");
569   _close(tempfd);
570
571   /* Test reading only \n or \r */
572   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
573   _lseek(tempfd, -1, FILE_END);
574   ret = _read(tempfd,btext,LLEN);
575   ok(ret == 1, "_read expected 1 got bad length: %d\n", ret);
576   _lseek(tempfd, -2, FILE_END);
577   ret = _read(tempfd,btext,LLEN);
578   ok(ret == 1 && *btext == '\n', "_read expected '\\n' got bad length: %d\n", ret);
579   _lseek(tempfd, -3, FILE_END);
580   ret = _read(tempfd,btext,2);
581   ok(ret == 1 && *btext == 'e', "_read expected 'e' got \"%.*s\" bad length: %d\n", ret, btext, ret);
582   ok(tell(tempfd) == 42, "bad position %lu expecting 42\n", tell(tempfd));
583   _close(tempfd);
584
585   ret = unlink(tempf);
586   ok( ret == 0 ,"Can't unlink '%s': %d\n", tempf, errno);
587
588   tempf=_tempnam(".","wne");
589   tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_BINARY|_O_RDWR,0);
590   ok( tempfd != -1,
591      "Can't open '%s': %d\n", tempf, errno); /* open in BINARY mode */
592   ok(_write(tempfd,dostext,strlen(dostext)) == lstrlenA(dostext),
593      "_write _O_BINARY bad return value\n");
594   _close(tempfd);
595   tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
596   ok(_read(tempfd,btext,LLEN) == lstrlenA(dostext),
597      "_read _O_BINARY got bad length\n");
598   ok( memcmp(dostext,btext,strlen(dostext)) == 0,
599       "problems with _O_BINARY _write / _read\n");
600   ok( btext[strlen(dostext)-2] == '\r', "CR not written or read\n");
601   _close(tempfd);
602   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
603   ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext),
604      "_read _O_TEXT got bad length\n");
605   ok( memcmp(mytext,btext,strlen(mytext)) == 0,
606       "problems with _O_BINARY _write / _O_TEXT _read\n");
607   _close(tempfd);
608
609    ret =_chmod (tempf, _S_IREAD | _S_IWRITE);
610   ok( ret == 0,
611      "Can't chmod '%s' to read-write: %d\n", tempf, errno);
612   ret = unlink(tempf);
613   ok( ret == 0 ,"Can't unlink '%s': %d\n", tempf, errno);
614 }
615
616 static void test_file_inherit_child(const char* fd_s)
617 {
618     int fd = atoi(fd_s);
619     char buffer[32];
620     int ret;
621
622     ret =write(fd, "Success", 8);
623     ok( ret == 8, "Couldn't write in child process on %d (%s)\n", fd, strerror(errno));
624     lseek(fd, 0, SEEK_SET);
625     ok(read(fd, buffer, sizeof (buffer)) == 8, "Couldn't read back the data\n");
626     ok(memcmp(buffer, "Success", 8) == 0, "Couldn't read back the data\n");
627 }
628
629 static void test_file_inherit_child_no(const char* fd_s)
630 {
631     int fd = atoi(fd_s);
632     int ret;
633
634     ret = write(fd, "Success", 8);
635     ok( ret == -1 && errno == EBADF, 
636        "Wrong write result in child process on %d (%s)\n", fd, strerror(errno));
637 }
638  
639 static void test_file_inherit( const char* selfname )
640 {
641     int                 fd;
642     const char*         arg_v[5];
643     char                buffer[16];
644
645     fd = open ("fdopen.tst", O_CREAT | O_RDWR | O_BINARY, _S_IREAD |_S_IWRITE);
646     ok(fd != -1, "Couldn't create test file\n");
647     arg_v[0] = selfname;
648     arg_v[1] = "tests/file.c";
649     arg_v[2] = buffer; sprintf(buffer, "%d", fd);
650     arg_v[3] = 0;
651     _spawnvp(_P_WAIT, selfname, arg_v);
652     ok(tell(fd) == 8, "bad position %lu expecting 8\n", tell(fd));
653     lseek(fd, 0, SEEK_SET);
654     ok(read(fd, buffer, sizeof (buffer)) == 8 && memcmp(buffer, "Success", 8) == 0, "Couldn't read back the data\n");
655     close (fd);
656     ok(unlink("fdopen.tst") == 0, "Couldn't unlink\n");
657     
658     fd = open ("fdopen.tst", O_CREAT | O_RDWR | O_BINARY | O_NOINHERIT, _S_IREAD |_S_IWRITE);
659     ok(fd != -1, "Couldn't create test file\n");
660     arg_v[0] = selfname;
661     arg_v[1] = "tests/file.c";
662     arg_v[2] = buffer; sprintf(buffer, "%d", fd);
663     arg_v[3] = buffer;
664     arg_v[4] = 0;
665     _spawnvp(_P_WAIT, selfname, arg_v);
666     ok(tell(fd) == 0, "bad position %lu expecting 0\n", tell(fd));
667     ok(read(fd, buffer, sizeof (buffer)) == 0, "Found unexpected data (%s)\n", buffer);
668     close (fd);
669     ok(unlink("fdopen.tst") == 0, "Couldn't unlink\n");
670 }
671
672 static void test_tmpnam( void )
673 {
674   char name[MAX_PATH] = "abc";
675   char *res;
676
677   res = tmpnam(NULL);
678   ok(res != NULL, "tmpnam returned NULL\n");
679   ok(res[0] == '\\', "first character is not a backslash\n");
680   ok(strchr(res+1, '\\') == 0, "file not in the root directory\n");
681   ok(res[strlen(res)-1] == '.', "first call - last character is not a dot\n");
682
683   res = tmpnam(name);
684   ok(res != NULL, "tmpnam returned NULL\n");
685   ok(res == name, "supplied buffer was not used\n");
686   ok(res[0] == '\\', "first character is not a backslash\n");
687   ok(strchr(res+1, '\\') == 0, "file not in the root directory\n");
688   ok(res[strlen(res)-1] != '.', "second call - last character is a dot\n");
689 }
690
691 static void test_chsize( void )
692 {
693     int fd;
694     long cur, pos, count;
695     char temptext[] = "012345678";
696     char *tempfile = _tempnam( ".", "tst" );
697     
698     ok( tempfile != NULL, "Couldn't create test file: %s\n", tempfile );
699
700     fd = _open( tempfile, _O_CREAT|_O_TRUNC|_O_RDWR, _S_IREAD|_S_IWRITE );
701     ok( fd > 0, "Couldn't open test file\n" );
702
703     count = _write( fd, temptext, sizeof(temptext) );
704     ok( count > 0, "Couldn't write to test file\n" );
705
706     /* get current file pointer */
707     cur = _lseek( fd, 0, SEEK_CUR );
708
709     /* make the file smaller */
710     ok( _chsize( fd, sizeof(temptext) / 2 ) == 0, "_chsize() failed\n" );
711
712     pos = _lseek( fd, 0, SEEK_CUR );
713     ok( cur == pos, "File pointer changed from: %ld to: %ld\n", cur, pos );
714     ok( _filelength( fd ) == sizeof(temptext) / 2, "Wrong file size\n" );
715
716     /* enlarge the file */
717     ok( _chsize( fd, sizeof(temptext) * 2 ) == 0, "_chsize() failed\n" ); 
718
719     pos = _lseek( fd, 0, SEEK_CUR );
720     ok( cur == pos, "File pointer changed from: %ld to: %ld\n", cur, pos );
721     ok( _filelength( fd ) == sizeof(temptext) * 2, "Wrong file size\n" );
722
723     _close( fd );
724     _unlink( tempfile );
725 }
726
727 static void test_fopen_fclose_fcloseall( void )
728 {
729     char fname1[] = "empty1";
730     char fname2[] = "empty2";
731     char fname3[] = "empty3";
732     FILE *stream1, *stream2, *stream3, *stream4;
733     int ret, numclosed;
734
735     /* testing fopen() */
736     stream1 = fopen(fname1, "w+");
737     ok(stream1 != NULL, "The file '%s' was not opened\n", fname1);
738     stream2 = fopen(fname2, "w ");
739     ok(stream2 != NULL, "The file '%s' was not opened\n", fname2 );
740     _unlink(fname3);
741     stream3 = fopen(fname3, "r");
742     ok(stream3 == NULL, "The file '%s' shouldn't exist before\n", fname3 );
743     stream3 = fopen(fname3, "w+");
744     ok(stream3 != NULL, "The file '%s' should be opened now\n", fname3 );
745     errno = 0xfaceabad;
746     stream4 = fopen("", "w+");
747     ok(stream4 == NULL && errno == ENOENT, 
748        "filename is empty, errno = %d (expected 2)\n", errno);
749     errno = 0xfaceabad;
750     stream4 = fopen(NULL, "w+");
751     ok(stream4 == NULL && (errno == EINVAL || errno == ENOENT), 
752        "filename is NULL, errno = %d (expected 2 or 22)\n", errno);
753
754     /* testing fclose() */
755     ret = fclose(stream2);
756     ok(ret == 0, "The file '%s' was not closed\n", fname2);
757     ret = fclose(stream3);
758     ok(ret == 0, "The file '%s' was not closed\n", fname3);
759     ret = fclose(stream2);
760     ok(ret == EOF, "Closing file '%s' returned %d\n", fname2, ret);
761     ret = fclose(stream3);
762     ok(ret == EOF, "Closing file '%s' returned %d\n", fname3, ret);
763
764     /* testing fcloseall() */
765     numclosed = _fcloseall();
766     /* fname1 should be closed here */
767     ok(numclosed == 1, "Number of files closed by fcloseall(): %u\n", numclosed);
768     numclosed = _fcloseall();
769     ok(numclosed == 0, "Number of files closed by fcloseall(): %u\n", numclosed);
770
771     ok(_unlink(fname1) == 0, "Couldn't unlink file named '%s'\n", fname1);
772     ok(_unlink(fname2) == 0, "Couldn't unlink file named '%s'\n", fname2);
773     ok(_unlink(fname3) == 0, "Couldn't unlink file named '%s'\n", fname3);
774 }
775
776 static void test_get_osfhandle(void)
777 {
778     int fd;
779     char fname[] = "t_get_osfhanle";
780     DWORD bytes_written;
781     HANDLE handle;
782
783     fd = _sopen(fname, _O_CREAT|_O_RDWR, _SH_DENYRW, _S_IREAD | _S_IWRITE);
784     handle = (HANDLE)_get_osfhandle(fd);
785     WriteFile(handle, "bar", 3, &bytes_written, NULL);
786     _close(fd);
787     fd = _open(fname, _O_RDONLY, 0);
788     ok(fd != -1, "Coudn't open '%s' after _get_osfhanle()\n", fname);
789
790     _close(fd);
791     _unlink(fname);
792 }
793
794 static void test_setmaxstdio(void)
795 {
796     ok(2048 == _setmaxstdio(2048),"_setmaxstdio returned %d instead of 2048\n",_setmaxstdio(2048));
797     ok(-1 == _setmaxstdio(2049),"_setmaxstdio returned %d instead of -1\n",_setmaxstdio(2049));
798 }
799
800 static void test_stat(void)
801 {
802     int fd;
803     int pipes[2];
804     struct stat buf;
805
806     /* Tests for a file */
807     fd = open("stat.tst", O_WRONLY | O_CREAT | O_BINARY, _S_IREAD |_S_IWRITE);
808     if (fd >= 0)
809     {
810         if (fstat(fd, &buf) == 0)
811         {
812             if (S_ISREG(buf.st_mode))
813             {
814                 ok(buf.st_dev == 0, "st_dev is %d, expected 0\n", buf.st_dev);
815                 ok(buf.st_dev == buf.st_rdev, "st_dev (%d) and st_rdev (%d) differ\n",
816                     buf.st_dev, buf.st_rdev);
817                 ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n",
818                     buf.st_nlink);
819                 ok(buf.st_size == 0, "st_size is %d, expected 0\n",
820                     buf.st_size);
821             }
822             else
823                 skip("file is not a file?\n");
824         }
825         else
826             skip("fstat failed, errno %d\n", errno);
827         close(fd);
828         remove("stat.tst");
829     }
830     else
831         skip("open failed with errno %d\n", errno);
832
833     /* Tests for a char device */
834     if (_dup2(0, 10) == 0)
835     {
836         if (fstat(10, &buf) == 0)
837         {
838             if (buf.st_mode == _S_IFCHR)
839             {
840                 ok(buf.st_dev == 10, "st_dev is %d, expected 10\n", buf.st_dev);
841                 ok(buf.st_rdev == 10, "st_rdev is %d, expected 10\n", buf.st_rdev);
842                 ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n", buf.st_nlink);
843             }
844             else
845                 skip("stdin is not a char device?\n");
846         }
847         else
848             skip("fstat failed with errno %d\n", errno);
849         close(10);
850     }
851     else
852         skip("_dup2 failed with errno %d\n", errno);
853
854     /* Tests for pipes */
855     if (_pipe(pipes, 1024, O_BINARY) == 0)
856     {
857         if (fstat(pipes[0], &buf) == 0)
858         {
859             if (buf.st_mode == _S_IFIFO)
860             {
861                 ok(buf.st_dev == pipes[0], "st_dev is %d, expected %d\n",
862                     buf.st_dev, pipes[0]);
863                 ok(buf.st_rdev == pipes[0], "st_rdev is %d, expected %d\n",
864                     buf.st_rdev, pipes[0]);
865                 ok(buf.st_nlink == 1, "st_nlink is %d, expected 1\n",
866                     buf.st_nlink);
867             }
868             else
869                 skip("pipe() didn't make a pipe?\n");
870         }
871         else
872             skip("fstat failed with errno %d\n", errno);
873         close(pipes[0]);
874         close(pipes[1]);
875     }
876     else
877         skip("pipe failed with errno %d\n", errno);
878 }
879
880 START_TEST(file)
881 {
882     int arg_c;
883     char** arg_v;
884
885     arg_c = winetest_get_mainargs( &arg_v );
886
887     /* testing low-level I/O */
888     if (arg_c >= 3)
889     {
890         if (arg_c == 3) test_file_inherit_child(arg_v[2]); 
891         else test_file_inherit_child_no(arg_v[2]);
892         return;
893     }
894     test_file_inherit(arg_v[0]);
895     test_file_write_read();
896     test_chsize();
897     test_stat();
898
899     /* testing stream I/O */
900     test_fdopen();
901     test_fopen_fclose_fcloseall();
902     test_fileops();
903     test_readmode(FALSE); /* binary mode */
904     test_readmode(TRUE);  /* ascii mode */
905     test_fgetc();
906     test_fgetwc();
907     test_ctrlz();
908     test_file_put_get();
909     test_tmpnam();
910     test_get_osfhandle();
911     test_setmaxstdio();
912 }