msi: Write-strings warnings fix.
[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_file_put_get( void )
376 {
377   char* tempf;
378   FILE *tempfh;
379   static const char mytext[]=  "This is a test_file_put_get\n";
380   static const char dostext[]= "This is a test_file_put_get\r\n";
381   char btext[LLEN];
382   WCHAR wtextW[LLEN+1];
383   WCHAR *mytextW = NULL, *aptr, *wptr;
384   BOOL diff_found = FALSE;
385   unsigned int i;
386
387   tempf=_tempnam(".","wne");
388   tempfh = fopen(tempf,"wt"); /* open in TEXT mode */
389   fputs(mytext,tempfh);
390   fclose(tempfh);
391   tempfh = fopen(tempf,"rb"); /* open in TEXT mode */
392   fgets(btext,LLEN,tempfh);
393   ok( strlen(mytext) + 1 == strlen(btext),"TEXT/BINARY mode not handled for write\n");
394   ok( btext[strlen(mytext)-1] == '\r', "CR not written\n");
395   fclose(tempfh);
396   tempfh = fopen(tempf,"wb"); /* open in BINARY mode */
397   fputs(dostext,tempfh);
398   fclose(tempfh);
399   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
400   fgets(btext,LLEN,tempfh);
401   ok(strcmp(btext, mytext) == 0,"_O_TEXT read doesn't strip CR\n");
402   fclose(tempfh);
403   tempfh = fopen(tempf,"rb"); /* open in TEXT mode */
404   fgets(btext,LLEN,tempfh);
405   ok(strcmp(btext, dostext) == 0,"_O_BINARY read doesn't preserve CR\n");
406
407   fclose(tempfh);
408   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
409   fgetws(wtextW,LLEN,tempfh);
410   mytextW = AtoW ((char*)mytext);
411   aptr = mytextW;
412   wptr = wtextW;
413
414   for (i=0; i<strlen(mytext); i++, aptr++, wptr++)
415     {
416       diff_found |= (*aptr != *wptr);
417     }
418   ok(!(diff_found), "fgetwc doesn't strip CR in TEXT mode\n");
419   if(mytextW) free (mytextW);
420   fclose(tempfh);
421   unlink(tempf);
422 }
423
424 static void test_file_write_read( void )
425 {
426   char* tempf;
427   int tempfd;
428   static const char mytext[]=  "This is test_file_write_read\nsecond line\n";
429   static const char dostext[]= "This is test_file_write_read\r\nsecond line\r\n";
430   char btext[LLEN];
431   int ret, i;
432
433   tempf=_tempnam(".","wne");
434   tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_BINARY|_O_RDWR,
435                      _S_IREAD | _S_IWRITE);
436   ok( tempfd != -1,
437      "Can't open '%s': %d\n", tempf, errno); /* open in BINARY mode */
438   ok(_write(tempfd,dostext,strlen(dostext)) == lstrlenA(dostext),
439      "_write _O_BINARY bad return value\n");
440   _close(tempfd);
441   i = lstrlenA(mytext);
442   tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
443   ok(_read(tempfd,btext,i) == i,
444      "_read _O_BINARY got bad length\n");
445   ok( memcmp(dostext,btext,i) == 0,
446       "problems with _O_BINARY  _write / _read\n");
447   _close(tempfd);
448   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
449   ok(_read(tempfd,btext,i) == i-1,
450      "_read _O_TEXT got bad length\n");
451   ok( memcmp(mytext,btext,i-1) == 0,
452       "problems with _O_BINARY _write / _O_TEXT _read\n");
453   _close(tempfd);
454   tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_TEXT|_O_RDWR,
455                      _S_IREAD | _S_IWRITE);
456   ok( tempfd != -1,
457      "Can't open '%s': %d\n", tempf, errno); /* open in TEXT mode */
458   ok(_write(tempfd,mytext,strlen(mytext)) == lstrlenA(mytext),
459      "_write _O_TEXT bad return value\n");
460   _close(tempfd);
461   tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
462   ok(_read(tempfd,btext,LLEN) == lstrlenA(dostext),
463      "_read _O_BINARY got bad length\n");
464   ok( memcmp(dostext,btext,strlen(dostext)) == 0,
465       "problems with _O_TEXT _write / _O_BINARY _read\n");
466   ok( btext[strlen(dostext)-2] == '\r', "CR not written or read\n");
467   _close(tempfd);
468   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
469   ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext),
470      "_read _O_TEXT got bad length\n");
471   ok( memcmp(mytext,btext,strlen(mytext)) == 0,
472       "problems with _O_TEXT _write / _read\n");
473   _close(tempfd);
474
475   memset(btext, 0, LLEN);
476   tempfd = _open(tempf,_O_APPEND|_O_RDWR); /* open for APPEND in default mode */
477   ok(tell(tempfd) == 0, "bad position %lu expecting 0\n", tell(tempfd));
478   ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext), "_read _O_APPEND got bad length\n");
479   ok( memcmp(mytext,btext,strlen(mytext)) == 0, "problems with _O_APPEND _read\n");
480   _close(tempfd);
481
482   /* Test reading only \n or \r */
483   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
484   _lseek(tempfd, -1, FILE_END);
485   ret = _read(tempfd,btext,LLEN);
486   ok(ret == 1, "_read expected 1 got bad length: %d\n", ret);
487   _lseek(tempfd, -2, FILE_END);
488   ret = _read(tempfd,btext,LLEN);
489   ok(ret == 1 && *btext == '\n', "_read expected '\\n' got bad length: %d\n", ret);
490   _lseek(tempfd, -3, FILE_END);
491   ret = _read(tempfd,btext,2);
492   ok(ret == 1 && *btext == 'e', "_read expected 'e' got \"%.*s\" bad length: %d\n", ret, btext, ret);
493   ok(tell(tempfd) == 42, "bad position %lu expecting 42\n", tell(tempfd));
494   _close(tempfd);
495
496   ret = unlink(tempf);
497   ok( ret == 0 ,"Can't unlink '%s': %d\n", tempf, errno);
498
499   tempf=_tempnam(".","wne");
500   tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_BINARY|_O_RDWR,0);
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   tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
507   ok(_read(tempfd,btext,LLEN) == lstrlenA(dostext),
508      "_read _O_BINARY got bad length\n");
509   ok( memcmp(dostext,btext,strlen(dostext)) == 0,
510       "problems with _O_BINARY _write / _read\n");
511   ok( btext[strlen(dostext)-2] == '\r', "CR not written or read\n");
512   _close(tempfd);
513   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
514   ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext),
515      "_read _O_TEXT got bad length\n");
516   ok( memcmp(mytext,btext,strlen(mytext)) == 0,
517       "problems with _O_BINARY _write / _O_TEXT _read\n");
518   _close(tempfd);
519
520    ret =_chmod (tempf, _S_IREAD | _S_IWRITE);
521   ok( ret == 0,
522      "Can't chmod '%s' to read-write: %d\n", tempf, errno);
523   ret = unlink(tempf);
524   ok( ret == 0 ,"Can't unlink '%s': %d\n", tempf, errno);
525 }
526
527 static void test_file_inherit_child(const char* fd_s)
528 {
529     int fd = atoi(fd_s);
530     char buffer[32];
531     int ret;
532
533     ret =write(fd, "Success", 8);
534     ok( ret == 8, "Couldn't write in child process on %d (%s)\n", fd, strerror(errno));
535     lseek(fd, 0, SEEK_SET);
536     ok(read(fd, buffer, sizeof (buffer)) == 8, "Couldn't read back the data\n");
537     ok(memcmp(buffer, "Success", 8) == 0, "Couldn't read back the data\n");
538 }
539
540 static void test_file_inherit_child_no(const char* fd_s)
541 {
542     int fd = atoi(fd_s);
543     int ret;
544
545     ret = write(fd, "Success", 8);
546     ok( ret == -1 && errno == EBADF, 
547        "Wrong write result in child process on %d (%s)\n", fd, strerror(errno));
548 }
549  
550 static void test_file_inherit( const char* selfname )
551 {
552     int                 fd;
553     const char*         arg_v[5];
554     char                buffer[16];
555
556     fd = open ("fdopen.tst", O_CREAT | O_RDWR | O_BINARY, _S_IREAD |_S_IWRITE);
557     ok(fd != -1, "Couldn't create test file\n");
558     arg_v[0] = selfname;
559     arg_v[1] = "tests/file.c";
560     arg_v[2] = buffer; sprintf(buffer, "%d", fd);
561     arg_v[3] = 0;
562     _spawnvp(_P_WAIT, selfname, arg_v);
563     ok(tell(fd) == 8, "bad position %lu expecting 8\n", tell(fd));
564     lseek(fd, 0, SEEK_SET);
565     ok(read(fd, buffer, sizeof (buffer)) == 8 && memcmp(buffer, "Success", 8) == 0, "Couldn't read back the data\n");
566     close (fd);
567     ok(unlink("fdopen.tst") == 0, "Couldn't unlink\n");
568     
569     fd = open ("fdopen.tst", O_CREAT | O_RDWR | O_BINARY | O_NOINHERIT, _S_IREAD |_S_IWRITE);
570     ok(fd != -1, "Couldn't create test file\n");
571     arg_v[0] = selfname;
572     arg_v[1] = "tests/file.c";
573     arg_v[2] = buffer; sprintf(buffer, "%d", fd);
574     arg_v[3] = buffer;
575     arg_v[4] = 0;
576     _spawnvp(_P_WAIT, selfname, arg_v);
577     ok(tell(fd) == 0, "bad position %lu expecting 0\n", tell(fd));
578     ok(read(fd, buffer, sizeof (buffer)) == 0, "Found unexpected data (%s)\n", buffer);
579     close (fd);
580     ok(unlink("fdopen.tst") == 0, "Couldn't unlink\n");
581 }
582
583 static void test_tmpnam( void )
584 {
585   char name[MAX_PATH] = "abc";
586   char *res;
587
588   res = tmpnam(NULL);
589   ok(res != NULL, "tmpnam returned NULL\n");
590   ok(res[0] == '\\', "first character is not a backslash\n");
591   ok(strchr(res+1, '\\') == 0, "file not in the root directory\n");
592   ok(res[strlen(res)-1] == '.', "first call - last character is not a dot\n");
593
594   res = tmpnam(name);
595   ok(res != NULL, "tmpnam returned NULL\n");
596   ok(res == name, "supplied buffer was not used\n");
597   ok(res[0] == '\\', "first character is not a backslash\n");
598   ok(strchr(res+1, '\\') == 0, "file not in the root directory\n");
599   ok(res[strlen(res)-1] != '.', "second call - last character is a dot\n");
600 }
601
602 static void test_chsize( void )
603 {
604     int fd;
605     long cur, pos, count;
606     char temptext[] = "012345678";
607     char *tempfile = _tempnam( ".", "tst" );
608     
609     ok( tempfile != NULL, "Couldn't create test file: %s\n", tempfile );
610
611     fd = _open( tempfile, _O_CREAT|_O_TRUNC|_O_RDWR, _S_IREAD|_S_IWRITE );
612     ok( fd > 0, "Couldn't open test file\n" );
613
614     count = _write( fd, temptext, sizeof(temptext) );
615     ok( count > 0, "Couldn't write to test file\n" );
616
617     /* get current file pointer */
618     cur = _lseek( fd, 0, SEEK_CUR );
619
620     /* make the file smaller */
621     ok( _chsize( fd, sizeof(temptext) / 2 ) == 0, "_chsize() failed\n" );
622
623     pos = _lseek( fd, 0, SEEK_CUR );
624     ok( cur == pos, "File pointer changed from: %ld to: %ld\n", cur, pos );
625     ok( _filelength( fd ) == sizeof(temptext) / 2, "Wrong file size\n" );
626
627     /* enlarge the file */
628     ok( _chsize( fd, sizeof(temptext) * 2 ) == 0, "_chsize() failed\n" ); 
629
630     pos = _lseek( fd, 0, SEEK_CUR );
631     ok( cur == pos, "File pointer changed from: %ld to: %ld\n", cur, pos );
632     ok( _filelength( fd ) == sizeof(temptext) * 2, "Wrong file size\n" );
633
634     _close( fd );
635     _unlink( tempfile );
636 }
637
638 static void test_fopen_fclose_fcloseall( void )
639 {
640     char fname1[] = "empty1";
641     char fname2[] = "empty2";
642     char fname3[] = "empty3";
643     FILE *stream1, *stream2, *stream3, *stream4;
644     int ret, numclosed;
645
646     /* testing fopen() */
647     stream1 = fopen(fname1, "w+");
648     ok(stream1 != NULL, "The file '%s' was not opened\n", fname1);
649     stream2 = fopen(fname2, "w ");
650     ok(stream2 != NULL, "The file '%s' was not opened\n", fname2 );
651     _unlink(fname3);
652     stream3 = fopen(fname3, "r");
653     ok(stream3 == NULL, "The file '%s' shouldn't exist before\n", fname3 );
654     stream3 = fopen(fname3, "w+");
655     ok(stream3 != NULL, "The file '%s' should be opened now\n", fname3 );
656     errno = 0xfaceabad;
657     stream4 = fopen("", "w+");
658     ok(stream4 == NULL && errno == ENOENT, 
659        "filename is empty, errno = %d (expected 2)\n", errno);
660     errno = 0xfaceabad;
661     stream4 = fopen(NULL, "w+");
662     ok(stream4 == NULL && (errno == EINVAL || errno == ENOENT), 
663        "filename is NULL, errno = %d (expected 2 or 22)\n", errno);
664
665     /* testing fclose() */
666     ret = fclose(stream2);
667     ok(ret == 0, "The file '%s' was not closed\n", fname2);
668     ret = fclose(stream3);
669     ok(ret == 0, "The file '%s' was not closed\n", fname3);
670     ret = fclose(stream2);
671     ok(ret == EOF, "Closing file '%s' returned %d\n", fname2, ret);
672     ret = fclose(stream3);
673     ok(ret == EOF, "Closing file '%s' returned %d\n", fname3, ret);
674
675     /* testing fcloseall() */
676     numclosed = _fcloseall();
677     /* fname1 should be closed here */
678     ok(numclosed == 1, "Number of files closed by fcloseall(): %u\n", numclosed);
679     numclosed = _fcloseall();
680     ok(numclosed == 0, "Number of files closed by fcloseall(): %u\n", numclosed);
681
682     ok(_unlink(fname1) == 0, "Couldn't unlink file named '%s'\n", fname1);
683     ok(_unlink(fname2) == 0, "Couldn't unlink file named '%s'\n", fname2);
684     ok(_unlink(fname3) == 0, "Couldn't unlink file named '%s'\n", fname3);
685 }
686
687 static void test_get_osfhandle(void)
688 {
689     int fd;
690     char fname[] = "t_get_osfhanle";
691     DWORD bytes_written;
692     HANDLE handle;
693
694     fd = _sopen(fname, _O_CREAT|_O_RDWR, _SH_DENYRW, _S_IREAD | _S_IWRITE);
695     handle = (HANDLE)_get_osfhandle(fd);
696     WriteFile(handle, "bar", 3, &bytes_written, NULL);
697     _close(fd);
698     fd = _open(fname, _O_RDONLY, 0);
699     ok(fd != -1, "Coudn't open '%s' after _get_osfhanle()\n", fname);
700
701     _close(fd);
702     _unlink(fname);
703 }
704
705 START_TEST(file)
706 {
707     int arg_c;
708     char** arg_v;
709
710     arg_c = winetest_get_mainargs( &arg_v );
711
712     /* testing low-level I/O */
713     if (arg_c >= 3)
714     {
715         if (arg_c == 3) test_file_inherit_child(arg_v[2]); 
716         else test_file_inherit_child_no(arg_v[2]);
717         return;
718     }
719     test_file_inherit(arg_v[0]);
720     test_file_write_read();
721     test_chsize();
722
723     /* testing stream I/O */
724     test_fdopen();
725     test_fopen_fclose_fcloseall();
726     test_fileops();
727     test_readmode(FALSE); /* binary mode */
728     test_readmode(TRUE);  /* ascii mode */
729     test_fgetwc();
730     test_file_put_get();
731     test_tmpnam();
732     test_get_osfhandle();
733 }