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