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