msvcrt: Fix fread.
[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     todo_wine 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     todo_wine 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\n";
265   WCHAR wtextW[LLEN+1];
266   WCHAR *mytextW = NULL, *aptr, *wptr;
267   BOOL diff_found = FALSE;
268   unsigned int i;
269
270   tempf=_tempnam(".","wne");
271   tempfh = fopen(tempf,"wt"); /* open in TEXT mode */
272   fputs(mytext,tempfh);
273   fclose(tempfh);
274   tempfh = fopen(tempf,"rt");
275   fgetws(wtextW,LLEN,tempfh);
276   mytextW = AtoW ((char*)mytext);
277   aptr = mytextW;
278   wptr = wtextW;
279
280   for (i=0; i<strlen(mytext); i++, aptr++, wptr++)
281     {
282       diff_found |= (*aptr != *wptr);
283     }
284   ok(!(diff_found), "fgetwc difference found in TEXT mode\n");
285   if(mytextW) free (mytextW);
286   fclose(tempfh);
287   unlink(tempf);
288 }
289
290 static void test_file_put_get( void )
291 {
292   char* tempf;
293   FILE *tempfh;
294   static const char mytext[]=  "This is a test_file_put_get\n";
295   static const char dostext[]= "This is a test_file_put_get\r\n";
296   char btext[LLEN];
297   WCHAR wtextW[LLEN+1];
298   WCHAR *mytextW = NULL, *aptr, *wptr;
299   BOOL diff_found = FALSE;
300   unsigned int i;
301
302   tempf=_tempnam(".","wne");
303   tempfh = fopen(tempf,"wt"); /* open in TEXT mode */
304   fputs(mytext,tempfh);
305   fclose(tempfh);
306   tempfh = fopen(tempf,"rb"); /* open in TEXT mode */
307   fgets(btext,LLEN,tempfh);
308   ok( strlen(mytext) + 1 == strlen(btext),"TEXT/BINARY mode not handled for write\n");
309   ok( btext[strlen(mytext)-1] == '\r', "CR not written\n");
310   fclose(tempfh);
311   tempfh = fopen(tempf,"wb"); /* open in BINARY mode */
312   fputs(dostext,tempfh);
313   fclose(tempfh);
314   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
315   fgets(btext,LLEN,tempfh);
316   ok(strcmp(btext, mytext) == 0,"_O_TEXT read doesn't strip CR\n");
317   fclose(tempfh);
318   tempfh = fopen(tempf,"rb"); /* open in TEXT mode */
319   fgets(btext,LLEN,tempfh);
320   ok(strcmp(btext, dostext) == 0,"_O_BINARY read doesn't preserve CR\n");
321
322   fclose(tempfh);
323   tempfh = fopen(tempf,"rt"); /* open in TEXT mode */
324   fgetws(wtextW,LLEN,tempfh);
325   mytextW = AtoW ((char*)mytext);
326   aptr = mytextW;
327   wptr = wtextW;
328
329   for (i=0; i<strlen(mytext); i++, aptr++, wptr++)
330     {
331       diff_found |= (*aptr != *wptr);
332     }
333   ok(!(diff_found), "fgetwc doesn't strip CR in TEXT mode\n");
334   if(mytextW) free (mytextW);
335   fclose(tempfh);
336   unlink(tempf);
337 }
338
339 static void test_file_write_read( void )
340 {
341   char* tempf;
342   int tempfd;
343   static const char mytext[]=  "This is test_file_write_read\nsecond line\n";
344   static const char dostext[]= "This is test_file_write_read\r\nsecond line\r\n";
345   char btext[LLEN];
346   int ret, i;
347
348   tempf=_tempnam(".","wne");
349   tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_BINARY|_O_RDWR,
350                      _S_IREAD | _S_IWRITE);
351   ok( tempfd != -1,
352      "Can't open '%s': %d\n", tempf, errno); /* open in BINARY mode */
353   ok(_write(tempfd,dostext,strlen(dostext)) == lstrlenA(dostext),
354      "_write _O_BINARY bad return value\n");
355   _close(tempfd);
356   i = lstrlenA(mytext);
357   tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
358   ok(_read(tempfd,btext,i) == i,
359      "_read _O_BINARY got bad length\n");
360   ok( memcmp(dostext,btext,i) == 0,
361       "problems with _O_BINARY  _write / _read\n");
362   _close(tempfd);
363   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
364   ok(_read(tempfd,btext,i) == i-1,
365      "_read _O_TEXT got bad length\n");
366   ok( memcmp(mytext,btext,i-1) == 0,
367       "problems with _O_BINARY _write / _O_TEXT _read\n");
368   _close(tempfd);
369   tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_TEXT|_O_RDWR,
370                      _S_IREAD | _S_IWRITE);
371   ok( tempfd != -1,
372      "Can't open '%s': %d\n", tempf, errno); /* open in TEXT mode */
373   ok(_write(tempfd,mytext,strlen(mytext)) == lstrlenA(mytext),
374      "_write _O_TEXT bad return value\n");
375   _close(tempfd);
376   tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
377   ok(_read(tempfd,btext,LLEN) == lstrlenA(dostext),
378      "_read _O_BINARY got bad length\n");
379   ok( memcmp(dostext,btext,strlen(dostext)) == 0,
380       "problems with _O_TEXT _write / _O_BINARY _read\n");
381   ok( btext[strlen(dostext)-2] == '\r', "CR not written or read\n");
382   _close(tempfd);
383   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
384   ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext),
385      "_read _O_TEXT got bad length\n");
386   ok( memcmp(mytext,btext,strlen(mytext)) == 0,
387       "problems with _O_TEXT _write / _read\n");
388   _close(tempfd);
389
390   memset(btext, 0, LLEN);
391   tempfd = _open(tempf,_O_APPEND|_O_RDWR); /* open for APPEND in default mode */
392   ok(tell(tempfd) == 0, "bad position %lu expecting 0\n", tell(tempfd));
393   ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext), "_read _O_APPEND got bad length\n");
394   ok( memcmp(mytext,btext,strlen(mytext)) == 0, "problems with _O_APPEND _read\n");
395   _close(tempfd);
396
397   /* Test reading only \n or \r */
398   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
399   _lseek(tempfd, -1, FILE_END);
400   ret = _read(tempfd,btext,LLEN);
401   ok(ret == 1, "_read expected 1 got bad length: %d\n", ret);
402   _lseek(tempfd, -2, FILE_END);
403   ret = _read(tempfd,btext,LLEN);
404   ok(ret == 1 && *btext == '\n', "_read expected '\\n' got bad length: %d\n", ret);
405   _lseek(tempfd, -3, FILE_END);
406   ret = _read(tempfd,btext,2);
407   ok(ret == 1 && *btext == 'e', "_read expected 'e' got \"%.*s\" bad length: %d\n", ret, btext, ret);
408   ok(tell(tempfd) == 42, "bad position %lu expecting 42\n", tell(tempfd));
409   _close(tempfd);
410
411   ret = unlink(tempf);
412   ok( ret == 0 ,"Can't unlink '%s': %d\n", tempf, errno);
413
414   tempf=_tempnam(".","wne");
415   tempfd = _open(tempf,_O_CREAT|_O_TRUNC|_O_BINARY|_O_RDWR,0);
416   ok( tempfd != -1,
417      "Can't open '%s': %d\n", tempf, errno); /* open in BINARY mode */
418   ok(_write(tempfd,dostext,strlen(dostext)) == lstrlenA(dostext),
419      "_write _O_BINARY bad return value\n");
420   _close(tempfd);
421   tempfd = _open(tempf,_O_RDONLY|_O_BINARY,0); /* open in BINARY mode */
422   ok(_read(tempfd,btext,LLEN) == lstrlenA(dostext),
423      "_read _O_BINARY got bad length\n");
424   ok( memcmp(dostext,btext,strlen(dostext)) == 0,
425       "problems with _O_BINARY _write / _read\n");
426   ok( btext[strlen(dostext)-2] == '\r', "CR not written or read\n");
427   _close(tempfd);
428   tempfd = _open(tempf,_O_RDONLY|_O_TEXT); /* open in TEXT mode */
429   ok(_read(tempfd,btext,LLEN) == lstrlenA(mytext),
430      "_read _O_TEXT got bad length\n");
431   ok( memcmp(mytext,btext,strlen(mytext)) == 0,
432       "problems with _O_BINARY _write / _O_TEXT _read\n");
433   _close(tempfd);
434
435    ret =_chmod (tempf, _S_IREAD | _S_IWRITE);
436   ok( ret == 0,
437      "Can't chmod '%s' to read-write: %d\n", tempf, errno);
438   ret = unlink(tempf);
439   ok( ret == 0 ,"Can't unlink '%s': %d\n", tempf, errno);
440 }
441
442 static void test_file_inherit_child(const char* fd_s)
443 {
444     int fd = atoi(fd_s);
445     char buffer[32];
446     int ret;
447
448     ret =write(fd, "Success", 8);
449     ok( ret == 8, "Couldn't write in child process on %d (%s)\n", fd, strerror(errno));
450     lseek(fd, 0, SEEK_SET);
451     ok(read(fd, buffer, sizeof (buffer)) == 8, "Couldn't read back the data\n");
452     ok(memcmp(buffer, "Success", 8) == 0, "Couldn't read back the data\n");
453 }
454
455 static void test_file_inherit_child_no(const char* fd_s)
456 {
457     int fd = atoi(fd_s);
458     int ret;
459
460     ret = write(fd, "Success", 8);
461     ok( ret == -1 && errno == EBADF, 
462        "Wrong write result in child process on %d (%s)\n", fd, strerror(errno));
463 }
464  
465 static void test_file_inherit( const char* selfname )
466 {
467     int                 fd;
468     const char*         arg_v[5];
469     char                buffer[16];
470
471     fd = open ("fdopen.tst", O_CREAT | O_RDWR | O_BINARY, _S_IREAD |_S_IWRITE);
472     ok(fd != -1, "Couldn't create test file\n");
473     arg_v[0] = selfname;
474     arg_v[1] = "tests/file.c";
475     arg_v[2] = buffer; sprintf(buffer, "%d", fd);
476     arg_v[3] = 0;
477     _spawnvp(_P_WAIT, selfname, arg_v);
478     ok(tell(fd) == 8, "bad position %lu expecting 8\n", tell(fd));
479     lseek(fd, 0, SEEK_SET);
480     ok(read(fd, buffer, sizeof (buffer)) == 8 && memcmp(buffer, "Success", 8) == 0, "Couldn't read back the data\n");
481     close (fd);
482     ok(unlink("fdopen.tst") == 0, "Couldn't unlink\n");
483     
484     fd = open ("fdopen.tst", O_CREAT | O_RDWR | O_BINARY | O_NOINHERIT, _S_IREAD |_S_IWRITE);
485     ok(fd != -1, "Couldn't create test file\n");
486     arg_v[0] = selfname;
487     arg_v[1] = "tests/file.c";
488     arg_v[2] = buffer; sprintf(buffer, "%d", fd);
489     arg_v[3] = buffer;
490     arg_v[4] = 0;
491     _spawnvp(_P_WAIT, selfname, arg_v);
492     ok(tell(fd) == 0, "bad position %lu expecting 0\n", tell(fd));
493     ok(read(fd, buffer, sizeof (buffer)) == 0, "Found unexpected data (%s)\n", buffer);
494     close (fd);
495     ok(unlink("fdopen.tst") == 0, "Couldn't unlink\n");
496 }
497
498 static void test_tmpnam( void )
499 {
500   char name[MAX_PATH] = "abc";
501   char *res;
502
503   res = tmpnam(NULL);
504   ok(res != NULL, "tmpnam returned NULL\n");
505   ok(res[0] == '\\', "first character is not a backslash\n");
506   ok(strchr(res+1, '\\') == 0, "file not in the root directory\n");
507   ok(res[strlen(res)-1] == '.', "first call - last character is not a dot\n");
508
509   res = tmpnam(name);
510   ok(res != NULL, "tmpnam returned NULL\n");
511   ok(res == name, "supplied buffer was not used\n");
512   ok(res[0] == '\\', "first character is not a backslash\n");
513   ok(strchr(res+1, '\\') == 0, "file not in the root directory\n");
514   ok(res[strlen(res)-1] != '.', "second call - last character is a dot\n");
515 }
516
517 static void test_chsize( void )
518 {
519     int fd;
520     long cur, pos, count;
521     char temptext[] = "012345678";
522     char *tempfile = _tempnam( ".", "tst" );
523     
524     ok( tempfile != NULL, "Couldn't create test file: %s\n", tempfile );
525
526     fd = _open( tempfile, _O_CREAT|_O_TRUNC|_O_RDWR, _S_IREAD|_S_IWRITE );
527     ok( fd > 0, "Couldn't open test file\n" );
528
529     count = _write( fd, temptext, sizeof(temptext) );
530     ok( count > 0, "Couldn't write to test file\n" );
531
532     /* get current file pointer */
533     cur = _lseek( fd, 0, SEEK_CUR );
534
535     /* make the file smaller */
536     ok( _chsize( fd, sizeof(temptext) / 2 ) == 0, "_chsize() failed\n" );
537
538     pos = _lseek( fd, 0, SEEK_CUR );
539     ok( cur == pos, "File pointer changed from: %ld to: %ld\n", cur, pos );
540     ok( _filelength( fd ) == sizeof(temptext) / 2, "Wrong file size\n" );
541
542     /* enlarge the file */
543     ok( _chsize( fd, sizeof(temptext) * 2 ) == 0, "_chsize() failed\n" ); 
544
545     pos = _lseek( fd, 0, SEEK_CUR );
546     ok( cur == pos, "File pointer changed from: %ld to: %ld\n", cur, pos );
547     ok( _filelength( fd ) == sizeof(temptext) * 2, "Wrong file size\n" );
548
549     _close( fd );
550     _unlink( tempfile );
551 }
552
553 static void test_fopen_fclose_fcloseall( void )
554 {
555     char fname1[] = "empty1";
556     char fname2[] = "empty2";
557     char fname3[] = "empty3";
558     FILE *stream1, *stream2, *stream3, *stream4;
559     int ret, numclosed;
560
561     /* testing fopen() */
562     stream1 = fopen(fname1, "w+");
563     ok(stream1 != NULL, "The file '%s' was not opened\n", fname1);
564     stream2 = fopen(fname2, "w ");
565     ok(stream2 != NULL, "The file '%s' was not opened\n", fname2 );
566     _unlink(fname3);
567     stream3 = fopen(fname3, "r");
568     ok(stream3 == NULL, "The file '%s' shouldn't exist before\n", fname3 );
569     stream3 = fopen(fname3, "w+");
570     ok(stream3 != NULL, "The file '%s' should be opened now\n", fname3 );
571     errno = 0xfaceabad;
572     stream4 = fopen("", "w+");
573     ok(stream4 == NULL && errno == ENOENT, 
574        "filename is empty, errno = %d (expected 2)\n", errno);
575     errno = 0xfaceabad;
576     stream4 = fopen(NULL, "w+");
577     ok(stream4 == NULL && (errno == EINVAL || errno == ENOENT), 
578        "filename is NULL, errno = %d (expected 2 or 22)\n", errno);
579
580     /* testing fclose() */
581     ret = fclose(stream2);
582     ok(ret == 0, "The file '%s' was not closed\n", fname2);
583     ret = fclose(stream3);
584     ok(ret == 0, "The file '%s' was not closed\n", fname3);
585     ret = fclose(stream2);
586     ok(ret == EOF, "Closing file '%s' returned %d\n", fname2, ret);
587     ret = fclose(stream3);
588     ok(ret == EOF, "Closing file '%s' returned %d\n", fname3, ret);
589
590     /* testing fcloseall() */
591     numclosed = _fcloseall();
592     /* fname1 should be closed here */
593     ok(numclosed == 1, "Number of files closed by fcloseall(): %u\n", numclosed);
594     numclosed = _fcloseall();
595     ok(numclosed == 0, "Number of files closed by fcloseall(): %u\n", numclosed);
596
597     ok(_unlink(fname1) == 0, "Couldn't unlink file named '%s'\n", fname1);
598     ok(_unlink(fname2) == 0, "Couldn't unlink file named '%s'\n", fname2);
599     ok(_unlink(fname3) == 0, "Couldn't unlink file named '%s'\n", fname3);
600 }
601
602 static void test_get_osfhandle(void)
603 {
604     int fd;
605     char fname[] = "t_get_osfhanle";
606     DWORD bytes_written;
607     HANDLE handle;
608
609     fd = _sopen(fname, _O_CREAT|_O_RDWR, _SH_DENYRW, _S_IREAD | _S_IWRITE);
610     handle = (HANDLE)_get_osfhandle(fd);
611     WriteFile(handle, "bar", 3, &bytes_written, NULL);
612     _close(fd);
613     fd = _open(fname, _O_RDONLY, 0);
614     ok(fd != -1, "Coudn't open '%s' after _get_osfhanle()\n", fname);
615
616     _close(fd);
617     _unlink(fname);
618 }
619
620 START_TEST(file)
621 {
622     int arg_c;
623     char** arg_v;
624
625     arg_c = winetest_get_mainargs( &arg_v );
626
627     /* testing low-level I/O */
628     if (arg_c >= 3)
629     {
630         if (arg_c == 3) test_file_inherit_child(arg_v[2]); 
631         else test_file_inherit_child_no(arg_v[2]);
632         return;
633     }
634     test_file_inherit(arg_v[0]);
635     test_file_write_read();
636     test_chsize();
637
638     /* testing stream I/O */
639     test_fdopen();
640     test_fopen_fclose_fcloseall();
641     test_fileops();
642     test_readmode(FALSE); /* binary mode */
643     test_readmode(TRUE);  /* ascii mode */
644     test_fgetwc();
645     test_file_put_get();
646     test_tmpnam();
647     test_get_osfhandle();
648 }