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