xref: /reactos/sdk/lib/crt/stdio/file.c (revision d41a4030)
1 /*
2  * PROJECT:         ReactOS CRT library
3  * LICENSE:         LGPL - See COPYING in the top level directory
4  * FILE:            lib/sdk/crt/stdio/file.c
5  * PURPOSE:         File CRT functions
6  * PROGRAMMERS:     Wine team
7  *                  Ported to ReactOS by Aleksey Bragin (aleksey@reactos.org)
8  */
9 
10 /*********************************************
11  * This file contains ReactOS changes!!
12  * Don't blindly sync it with Wine code!
13  *
14  * If you break Unicode output on the console again, please update this counter:
15  *   int hours_wasted_on_this = 42;
16  *********************************************/
17 
18 /*
19  * msvcrt.dll file functions
20  *
21  * Copyright 1996,1998 Marcus Meissner
22  * Copyright 1996 Jukka Iivonen
23  * Copyright 1997,2000 Uwe Bonnes
24  * Copyright 2000 Jon Griffiths
25  * Copyright 2004 Eric Pouech
26  * Copyright 2004 Juan Lang
27  *
28  * This library is free software; you can redistribute it and/or
29  * modify it under the terms of the GNU Lesser General Public
30  * License as published by the Free Software Foundation; either
31  * version 2.1 of the License, or (at your option) any later version.
32  *
33  * This library is distributed in the hope that it will be useful,
34  * but WITHOUT ANY WARRANTY; without even the implied warranty of
35  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
36  * Lesser General Public License for more details.
37  *
38  * You should have received a copy of the GNU Lesser General Public
39  * License along with this library; if not, write to the Free Software
40  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
41  *
42  * TODO
43  * Use the file flag hints O_SEQUENTIAL, O_RANDOM, O_SHORT_LIVED
44  */
45 
46 #include <precomp.h>
47 #include "wine/unicode.h"
48 #include "internal/wine/msvcrt.h"
49 
50 #include <sys/utime.h>
51 #include <direct.h>
52 
53 int *__p__fmode(void);
54 int *__p___mb_cur_max(void);
55 
56 extern int _commode;
57 
58 #ifndef _IOCOMMIT
59 #define _IOCOMMIT 0x4000
60 #endif
61 
62 #ifdef feof
63 #undef feof
64 #endif
65 #ifdef _fileno
66 #undef _fileno
67 #endif
68 #ifdef ferror
69 #undef ferror
70 #endif
71 #ifdef clearerr
72 #undef clearerr
73 #endif
74 
75 #undef getc
76 #undef getwc
77 #undef getchar
78 #undef getwchar
79 #undef putc
80 #undef putwc
81 #undef putchar
82 #undef putwchar
83 
84 #undef vprintf
85 #undef vwprintf
86 
87 /* _access() bit flags FIXME: incomplete */
88 /* defined in crt/io.h */
89 
90 /* values for wxflag in file descriptor */
91 #define WX_OPEN           0x01
92 #define WX_ATEOF          0x02
93 #define WX_READNL         0x04  /* read started with \n */
94 #define WX_READEOF        0x04  /* like ATEOF, but for underlying file rather than buffer */
95 #define WX_PIPE           0x08
96 #define WX_READCR         0x08  /* underlying file is at \r */
97 #define WX_DONTINHERIT    0x10
98 #define WX_APPEND         0x20
99 #define WX_TTY            0x40
100 #define WX_TEXT           0x80
101 
102 /* values for exflag - it's used differently in msvcr90.dll*/
103 #define EF_UTF8           0x01
104 #define EF_UTF16          0x02
105 #define EF_CRIT_INIT      0x04
106 #define EF_UNK_UNICODE    0x08
107 
108 static char utf8_bom[3] = { 0xef, 0xbb, 0xbf };
109 static char utf16_bom[2] = { 0xff, 0xfe };
110 
111 /* FIXME: this should be allocated dynamically */
112 #define MSVCRT_MAX_FILES 2048
113 #define MSVCRT_FD_BLOCK_SIZE 32
114 
115 #define MSVCRT_INTERNAL_BUFSIZ 4096
116 
117 /*********************************************************************
118  *		__pioinfo (MSVCRT.@)
119  * array of pointers to ioinfo arrays [32]
120  */
121 ioinfo * __pioinfo[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE] = { 0 };
122 
123 /*********************************************************************
124  *		__badioinfo (MSVCRT.@)
125  */
126 ioinfo __badioinfo = { INVALID_HANDLE_VALUE, WX_TEXT };
127 
128 typedef struct {
129     FILE file;
130     CRITICAL_SECTION crit;
131 } file_crit;
132 
133 FILE _iob[_IOB_ENTRIES] = { { 0 } };
134 static file_crit* MSVCRT_fstream[MSVCRT_MAX_FILES/MSVCRT_FD_BLOCK_SIZE] = { NULL };
135 static int MSVCRT_max_streams = 512, MSVCRT_stream_idx;
136 
137 /* INTERNAL: process umask */
138 static int MSVCRT_umask = 0;
139 
140 /* INTERNAL: static data for tmpnam and _wtmpname functions */
141 static int tmpnam_unique;
142 
143 /* This critical section protects the MSVCRT_fstreams table
144  * and MSVCRT_stream_idx from race conditions. It also
145  * protects fd critical sections creation code.
146  */
147 static CRITICAL_SECTION MSVCRT_file_cs;
148 static CRITICAL_SECTION_DEBUG MSVCRT_file_cs_debug =
149 {
150     0, 0, &MSVCRT_file_cs,
151     { &MSVCRT_file_cs_debug.ProcessLocksList, &MSVCRT_file_cs_debug.ProcessLocksList },
152       0, 0, { (DWORD_PTR)(__FILE__ ": MSVCRT_file_cs") }
153 };
154 static CRITICAL_SECTION MSVCRT_file_cs = { &MSVCRT_file_cs_debug, -1, 0, 0, 0, 0 };
155 #define LOCK_FILES()    do { EnterCriticalSection(&MSVCRT_file_cs); } while (0)
156 #define UNLOCK_FILES()  do { LeaveCriticalSection(&MSVCRT_file_cs); } while (0)
157 
get_ioinfo_nolock(int fd)158 static inline ioinfo* get_ioinfo_nolock(int fd)
159 {
160     ioinfo *ret = NULL;
161     if(fd>=0 && fd<MSVCRT_MAX_FILES)
162         ret = __pioinfo[fd/MSVCRT_FD_BLOCK_SIZE];
163     if(!ret)
164         return &__badioinfo;
165 
166     return ret + (fd%MSVCRT_FD_BLOCK_SIZE);
167 }
168 
init_ioinfo_cs(ioinfo * info)169 static inline void init_ioinfo_cs(ioinfo *info)
170 {
171     if(!(info->exflag & EF_CRIT_INIT)) {
172         LOCK_FILES();
173         if(!(info->exflag & EF_CRIT_INIT)) {
174             InitializeCriticalSection(&info->crit);
175             info->exflag |= EF_CRIT_INIT;
176         }
177         UNLOCK_FILES();
178     }
179 }
180 
get_ioinfo(int fd)181 ioinfo* get_ioinfo(int fd)
182 {
183     ioinfo *ret = get_ioinfo_nolock(fd);
184     if(ret == &__badioinfo)
185         return ret;
186     init_ioinfo_cs(ret);
187     EnterCriticalSection(&ret->crit);
188     return ret;
189 }
190 
alloc_pioinfo_block(int fd)191 static inline BOOL alloc_pioinfo_block(int fd)
192 {
193     ioinfo *block;
194     int i;
195 
196     if(fd<0 || fd>=MSVCRT_MAX_FILES)
197     {
198         *_errno() = ENFILE;
199         return FALSE;
200     }
201 
202     block = calloc(MSVCRT_FD_BLOCK_SIZE, sizeof(ioinfo));
203     if(!block)
204     {
205         WARN(":out of memory!\n");
206         *_errno() = ENOMEM;
207         return FALSE;
208     }
209     for(i=0; i<MSVCRT_FD_BLOCK_SIZE; i++)
210         block[i].handle = INVALID_HANDLE_VALUE;
211     if(InterlockedCompareExchangePointer((void**)&__pioinfo[fd/MSVCRT_FD_BLOCK_SIZE], block, NULL))
212         free(block);
213     return TRUE;
214 }
215 
get_ioinfo_alloc_fd(int fd)216 static inline ioinfo* get_ioinfo_alloc_fd(int fd)
217 {
218     ioinfo *ret;
219 
220     ret = get_ioinfo(fd);
221     if(ret != &__badioinfo)
222         return ret;
223 
224     if(!alloc_pioinfo_block(fd))
225         return &__badioinfo;
226 
227     return get_ioinfo(fd);
228 }
229 
get_ioinfo_alloc(int * fd)230 static inline ioinfo* get_ioinfo_alloc(int *fd)
231 {
232     int i;
233 
234     *fd = -1;
235     for(i=0; i<MSVCRT_MAX_FILES; i++)
236     {
237         ioinfo *info = get_ioinfo_nolock(i);
238 
239         if(info == &__badioinfo)
240         {
241             if(!alloc_pioinfo_block(i))
242                 return &__badioinfo;
243             info = get_ioinfo_nolock(i);
244         }
245 
246         init_ioinfo_cs(info);
247         if(TryEnterCriticalSection(&info->crit))
248         {
249             if(info->handle == INVALID_HANDLE_VALUE)
250             {
251                 *fd = i;
252                 return info;
253             }
254             LeaveCriticalSection(&info->crit);
255         }
256     }
257 
258     WARN(":files exhausted!\n");
259     *_errno() = ENFILE;
260     return &__badioinfo;
261 }
262 
release_ioinfo(ioinfo * info)263 void release_ioinfo(ioinfo *info)
264 {
265     if(info!=&__badioinfo && info->exflag & EF_CRIT_INIT)
266         LeaveCriticalSection(&info->crit);
267 }
268 
msvcrt_get_file(int i)269 static inline FILE* msvcrt_get_file(int i)
270 {
271     file_crit *ret;
272 
273     if(i >= MSVCRT_max_streams)
274         return NULL;
275 
276     if(i < _IOB_ENTRIES)
277         return &_iob[i];
278 
279     ret = MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE];
280     if(!ret) {
281         MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE] = calloc(MSVCRT_FD_BLOCK_SIZE, sizeof(file_crit));
282         if(!MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE]) {
283             ERR("out of memory\n");
284             *_errno() = ENOMEM;
285             return NULL;
286         }
287 
288         ret = MSVCRT_fstream[i/MSVCRT_FD_BLOCK_SIZE] + (i%MSVCRT_FD_BLOCK_SIZE);
289     } else
290         ret += i%MSVCRT_FD_BLOCK_SIZE;
291 
292     return &ret->file;
293 }
294 
295 /* INTERNAL: free a file entry fd */
msvcrt_free_fd(int fd)296 static void msvcrt_free_fd(int fd)
297 {
298   ioinfo *fdinfo = get_ioinfo(fd);
299 
300   if(fdinfo != &__badioinfo)
301   {
302     fdinfo->handle = INVALID_HANDLE_VALUE;
303     fdinfo->wxflag = 0;
304   }
305   TRACE(":fd (%d) freed\n",fd);
306 
307   if (fd < 3)
308   {
309     switch (fd)
310     {
311     case 0:
312         SetStdHandle(STD_INPUT_HANDLE, 0);
313         break;
314     case 1:
315         SetStdHandle(STD_OUTPUT_HANDLE, 0);
316         break;
317     case 2:
318         SetStdHandle(STD_ERROR_HANDLE, 0);
319         break;
320     }
321   }
322   release_ioinfo(fdinfo);
323 }
324 
msvcrt_set_fd(ioinfo * fdinfo,HANDLE hand,int flag)325 static void msvcrt_set_fd(ioinfo *fdinfo, HANDLE hand, int flag)
326 {
327   fdinfo->handle = hand;
328   fdinfo->wxflag = WX_OPEN | (flag & (WX_DONTINHERIT | WX_APPEND | WX_TEXT | WX_PIPE | WX_TTY));
329   fdinfo->lookahead[0] = '\n';
330   fdinfo->lookahead[1] = '\n';
331   fdinfo->lookahead[2] = '\n';
332   fdinfo->exflag &= EF_CRIT_INIT;
333 
334   switch (fdinfo-__pioinfo[0])
335   {
336   case 0: SetStdHandle(STD_INPUT_HANDLE,  hand); break;
337   case 1: SetStdHandle(STD_OUTPUT_HANDLE, hand); break;
338   case 2: SetStdHandle(STD_ERROR_HANDLE,  hand); break;
339   }
340 }
341 
342 /* INTERNAL: Allocate an fd slot from a Win32 HANDLE */
msvcrt_alloc_fd(HANDLE hand,int flag)343 /*static*/ int msvcrt_alloc_fd(HANDLE hand, int flag)
344 {
345     int fd;
346     ioinfo *info = get_ioinfo_alloc(&fd);
347 
348     TRACE(":handle (%p) allocating fd (%d)\n", hand, fd);
349 
350     if(info == &__badioinfo)
351         return -1;
352 
353     msvcrt_set_fd(info, hand, flag);
354     release_ioinfo(info);
355     return fd;
356 }
357 
358 /* INTERNAL: Allocate a FILE* for an fd slot */
359 /* caller must hold the files lock */
msvcrt_alloc_fp(void)360 static FILE* msvcrt_alloc_fp(void)
361 {
362   int i;
363   FILE *file;
364 
365   for (i = 3; i < MSVCRT_max_streams; i++)
366   {
367     file = msvcrt_get_file(i);
368     if (!file)
369       return NULL;
370 
371     if (file->_flag == 0)
372     {
373       if (i == MSVCRT_stream_idx) MSVCRT_stream_idx++;
374       return file;
375     }
376   }
377 
378   return NULL;
379 }
380 
381 /* INTERNAL: initialize a FILE* from an open fd */
msvcrt_init_fp(FILE * file,int fd,unsigned stream_flags)382 static int msvcrt_init_fp(FILE* file, int fd, unsigned stream_flags)
383 {
384   TRACE(":fd (%d) allocating FILE*\n",fd);
385   if (!(get_ioinfo_nolock(fd)->wxflag & WX_OPEN))
386   {
387     WARN(":invalid fd %d\n",fd);
388     *__doserrno() = 0;
389     *_errno() = EBADF;
390     return -1;
391   }
392   file->_ptr = file->_base = NULL;
393   file->_cnt = 0;
394   file->_file = fd;
395   file->_flag = stream_flags;
396   file->_tmpfname = NULL;
397 
398   if(file<_iob || file>=_iob+_IOB_ENTRIES)
399       InitializeCriticalSection(&((file_crit*)file)->crit);
400 
401   TRACE(":got FILE* (%p)\n",file);
402   return 0;
403 }
404 
405 /* INTERNAL: Create an inheritance data block (for spawned process)
406  * The inheritance block is made of:
407  *      00      int     nb of file descriptor (NBFD)
408  *      04      char    file flags (wxflag): repeated for each fd
409  *      4+NBFD  HANDLE  file handle: repeated for each fd
410  */
create_io_inherit_block(WORD * size,BYTE ** block)411 unsigned create_io_inherit_block(WORD *size, BYTE **block)
412 {
413   int         fd, last_fd;
414   char*       wxflag_ptr;
415   HANDLE*     handle_ptr;
416   ioinfo*     fdinfo;
417 
418   for (last_fd=MSVCRT_MAX_FILES-1; last_fd>=0; last_fd--)
419     if (get_ioinfo_nolock(last_fd)->handle != INVALID_HANDLE_VALUE)
420       break;
421   last_fd++;
422 
423   *size = sizeof(unsigned) + (sizeof(char) + sizeof(HANDLE)) * last_fd;
424   *block = calloc(1, *size);
425   if (!*block)
426   {
427     *size = 0;
428     return FALSE;
429   }
430   wxflag_ptr = (char*)*block + sizeof(unsigned);
431   handle_ptr = (HANDLE*)(wxflag_ptr + last_fd);
432 
433   *(unsigned*)*block = last_fd;
434   for (fd = 0; fd < last_fd; fd++)
435   {
436     /* to be inherited, we need it to be open, and that DONTINHERIT isn't set */
437     fdinfo = get_ioinfo_nolock(fd);
438     if ((fdinfo->wxflag & (WX_OPEN | WX_DONTINHERIT)) == WX_OPEN)
439     {
440       *wxflag_ptr = fdinfo->wxflag;
441       *handle_ptr = fdinfo->handle;
442     }
443     else
444     {
445       *wxflag_ptr = 0;
446       *handle_ptr = INVALID_HANDLE_VALUE;
447     }
448     wxflag_ptr++; handle_ptr++;
449   }
450   return TRUE;
451 }
452 
453 /* INTERNAL: Set up all file descriptors,
454  * as well as default streams (stdin, stderr and stdout)
455  */
msvcrt_init_io(void)456 void msvcrt_init_io(void)
457 {
458   STARTUPINFOA  si;
459   unsigned int  i;
460   ioinfo        *fdinfo;
461 
462   GetStartupInfoA(&si);
463   if (si.cbReserved2 >= sizeof(unsigned int) && si.lpReserved2 != NULL)
464   {
465     BYTE*       wxflag_ptr;
466     HANDLE*     handle_ptr;
467     unsigned int count;
468 
469     count = *(unsigned*)si.lpReserved2;
470     wxflag_ptr = si.lpReserved2 + sizeof(unsigned);
471     handle_ptr = (HANDLE*)(wxflag_ptr + count);
472 
473     count = min(count, (si.cbReserved2 - sizeof(unsigned)) / (sizeof(HANDLE) + 1));
474     count = min(count, MSVCRT_MAX_FILES);
475     for (i = 0; i < count; i++)
476     {
477       if ((*wxflag_ptr & WX_OPEN) && GetFileType(*handle_ptr) != FILE_TYPE_UNKNOWN)
478       {
479         fdinfo = get_ioinfo_alloc_fd(i);
480         if(fdinfo != &__badioinfo)
481             msvcrt_set_fd(fdinfo, *handle_ptr, *wxflag_ptr);
482         release_ioinfo(fdinfo);
483       }
484 
485       wxflag_ptr++; handle_ptr++;
486     }
487   }
488 
489   fdinfo = get_ioinfo_alloc_fd(STDIN_FILENO);
490   if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) {
491     HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
492     DWORD type = GetFileType(h);
493 
494     msvcrt_set_fd(fdinfo, h, WX_OPEN|WX_TEXT|((type&0xf)==FILE_TYPE_CHAR ? WX_TTY : 0)
495             |((type&0xf)==FILE_TYPE_PIPE ? WX_PIPE : 0));
496   }
497   release_ioinfo(fdinfo);
498 
499   fdinfo = get_ioinfo_alloc_fd(STDOUT_FILENO);
500   if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) {
501     HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
502     DWORD type = GetFileType(h);
503 
504     msvcrt_set_fd(fdinfo, h, WX_OPEN|WX_TEXT|((type&0xf)==FILE_TYPE_CHAR ? WX_TTY : 0)
505             |((type&0xf)==FILE_TYPE_PIPE ? WX_PIPE : 0));
506   }
507   release_ioinfo(fdinfo);
508 
509   fdinfo = get_ioinfo_alloc_fd(STDERR_FILENO);
510   if (!(fdinfo->wxflag & WX_OPEN) || fdinfo->handle == INVALID_HANDLE_VALUE) {
511     HANDLE h = GetStdHandle(STD_ERROR_HANDLE);
512     DWORD type = GetFileType(h);
513 
514     msvcrt_set_fd(fdinfo, h, WX_OPEN|WX_TEXT|((type&0xf)==FILE_TYPE_CHAR ? WX_TTY : 0)
515             |((type&0xf)==FILE_TYPE_PIPE ? WX_PIPE : 0));
516   }
517   release_ioinfo(fdinfo);
518 
519   TRACE(":handles (%p)(%p)(%p)\n", get_ioinfo_nolock(STDIN_FILENO)->handle,
520         get_ioinfo_nolock(STDOUT_FILENO)->handle,
521         get_ioinfo_nolock(STDERR_FILENO)->handle);
522 
523   memset(_iob,0,3*sizeof(FILE));
524   for (i = 0; i < 3; i++)
525   {
526     /* FILE structs for stdin/out/err are static and never deleted */
527     _iob[i]._file = i;
528     _iob[i]._tmpfname = NULL;
529     _iob[i]._flag = (i == 0) ? _IOREAD : _IOWRT;
530   }
531   MSVCRT_stream_idx = 3;
532 }
533 
534 /* INTERNAL: Flush stdio file buffer */
msvcrt_flush_buffer(FILE * file)535 static int msvcrt_flush_buffer(FILE* file)
536 {
537     if((file->_flag & (_IOREAD|_IOWRT)) == _IOWRT &&
538             file->_flag & (_IOMYBUF|_USERBUF)) {
539         int cnt=file->_ptr-file->_base;
540         if(cnt>0 && _write(file->_file, file->_base, cnt) != cnt) {
541             file->_flag |= _IOERR;
542             return EOF;
543         }
544 
545         if(file->_flag & _IORW)
546             file->_flag &= ~_IOWRT;
547 
548 #ifdef __REACTOS__ /* CORE-11949 */
549     file->_ptr=file->_base;
550     file->_cnt=0;
551 #endif
552     }
553 
554 #ifndef __REACTOS__ /* CORE-11949 */
555     file->_ptr=file->_base;
556     file->_cnt=0;
557 #endif
558     return 0;
559 }
560 
561 /*********************************************************************
562  *		_isatty (MSVCRT.@)
563  */
_isatty(int fd)564 int CDECL _isatty(int fd)
565 {
566     TRACE(":fd (%d)\n",fd);
567 
568     return get_ioinfo_nolock(fd)->wxflag & WX_TTY;
569 }
570 
571 /* INTERNAL: Allocate stdio file buffer */
msvcrt_alloc_buffer(FILE * file)572 /*static*/ BOOL msvcrt_alloc_buffer(FILE* file)
573 {
574     if((file->_file==STDOUT_FILENO || file->_file==STDERR_FILENO)
575             && _isatty(file->_file))
576         return FALSE;
577 
578     file->_base = calloc(1, MSVCRT_INTERNAL_BUFSIZ);
579     if(file->_base) {
580         file->_bufsiz = MSVCRT_INTERNAL_BUFSIZ;
581         file->_flag |= _IOMYBUF;
582     } else {
583         file->_base = (char*)(&file->_charbuf);
584         file->_bufsiz = 2;
585         file->_flag |= _IONBF;
586     }
587     file->_ptr = file->_base;
588     file->_cnt = 0;
589     return TRUE;
590 }
591 
592 /* INTERNAL: Allocate temporary buffer for stdout and stderr */
add_std_buffer(FILE * file)593 static BOOL add_std_buffer(FILE *file)
594 {
595     static char buffers[2][BUFSIZ];
596 
597     if((file->_file!=STDOUT_FILENO && file->_file!=STDERR_FILENO)
598             || (file->_flag & (_IONBF | _IOMYBUF | _USERBUF))
599             || !_isatty(file->_file))
600         return FALSE;
601 
602     file->_ptr = file->_base = buffers[file->_file == STDOUT_FILENO ? 0 : 1];
603     file->_bufsiz = file->_cnt = BUFSIZ;
604     file->_flag |= _USERBUF;
605     return TRUE;
606 }
607 
608 /* INTERNAL: Removes temporary buffer from stdout or stderr */
609 /* Only call this function when add_std_buffer returned TRUE */
remove_std_buffer(FILE * file)610 static void remove_std_buffer(FILE *file)
611 {
612     msvcrt_flush_buffer(file);
613     file->_ptr = file->_base = NULL;
614     file->_bufsiz = file->_cnt = 0;
615     file->_flag &= ~_USERBUF;
616 }
617 
618 /* INTERNAL: Convert integer to base32 string (0-9a-v), 0 becomes "" */
msvcrt_int_to_base32(int num,char * str)619 static int msvcrt_int_to_base32(int num, char *str)
620 {
621   char *p;
622   int n = num;
623   int digits = 0;
624 
625   while (n != 0)
626   {
627     n >>= 5;
628     digits++;
629   }
630   p = str + digits;
631   *p = 0;
632   while (--p >= str)
633   {
634     *p = (num & 31) + '0';
635     if (*p > '9')
636       *p += ('a' - '0' - 10);
637     num >>= 5;
638   }
639 
640   return digits;
641 }
642 
643 /* INTERNAL: wide character version of msvcrt_int_to_base32 */
msvcrt_int_to_base32_w(int num,wchar_t * str)644 static int msvcrt_int_to_base32_w(int num, wchar_t *str)
645 {
646     wchar_t *p;
647     int n = num;
648     int digits = 0;
649 
650     while (n != 0)
651     {
652         n >>= 5;
653         digits++;
654     }
655     p = str + digits;
656     *p = 0;
657     while (--p >= str)
658     {
659         *p = (num & 31) + '0';
660         if (*p > '9')
661             *p += ('a' - '0' - 10);
662         num >>= 5;
663     }
664 
665     return digits;
666 }
667 
668 /* INTERNAL: Create a wide string from an ascii string */
msvcrt_wstrdupa(const char * str)669 wchar_t *msvcrt_wstrdupa(const char *str)
670 {
671   const unsigned int len = strlen(str) + 1 ;
672   wchar_t *wstr = malloc(len* sizeof (wchar_t));
673   if (!wstr)
674     return NULL;
675    MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED,str,len,wstr,len);
676   return wstr;
677 }
678 
679 /*********************************************************************
680  *		__iob_func(MSVCRT.@)
681  */
__iob_func(void)682 FILE * CDECL __iob_func(void)
683 {
684  return &_iob[0];
685 }
686 
687 /*********************************************************************
688  *		_access (MSVCRT.@)
689  */
_access(const char * filename,int mode)690 int CDECL _access(const char *filename, int mode)
691 {
692   DWORD attr = GetFileAttributesA(filename);
693 
694   TRACE("(%s,%d) %d\n",filename,mode,attr);
695 
696   if (!filename || attr == INVALID_FILE_ATTRIBUTES)
697   {
698     _dosmaperr(GetLastError());
699     return -1;
700   }
701   if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK))
702   {
703     _set_errno(ERROR_ACCESS_DENIED);
704     return -1;
705   }
706   return 0;
707 }
708 
709 /*********************************************************************
710  *		_access_s (MSVCRT.@)
711  */
_access_s(const char * filename,int mode)712 int CDECL _access_s(const char *filename, int mode)
713 {
714   if (!MSVCRT_CHECK_PMT(filename != NULL) ||
715       !MSVCRT_CHECK_PMT((mode & ~(R_OK | W_OK)) == 0))
716   {
717      _set_errno(EINVAL);
718      return -1;
719   }
720 
721   return _access(filename, mode);
722 }
723 
724 /*********************************************************************
725  *		_waccess (MSVCRT.@)
726  */
_waccess(const wchar_t * filename,int mode)727 int CDECL _waccess(const wchar_t *filename, int mode)
728 {
729   DWORD attr = GetFileAttributesW(filename);
730 
731   TRACE("(%s,%d) %d\n",debugstr_w(filename),mode,attr);
732 
733   if (!filename || attr == INVALID_FILE_ATTRIBUTES)
734   {
735     _dosmaperr(GetLastError());
736     return -1;
737   }
738   if ((attr & FILE_ATTRIBUTE_READONLY) && (mode & W_OK))
739   {
740     _set_errno(ERROR_ACCESS_DENIED);
741     return -1;
742   }
743   return 0;
744 }
745 
746 /*********************************************************************
747  *		_waccess_s (MSVCRT.@)
748  */
_waccess_s(const wchar_t * filename,int mode)749 int CDECL _waccess_s(const wchar_t *filename, int mode)
750 {
751   if (!MSVCRT_CHECK_PMT(filename != NULL) ||
752       !MSVCRT_CHECK_PMT((mode & ~(R_OK | W_OK)) == 0))
753   {
754      *_errno() = EINVAL;
755      return -1;
756   }
757 
758   return _waccess(filename, mode);
759 }
760 
761 /*********************************************************************
762  *		_chmod (MSVCRT.@)
763  */
_chmod(const char * path,int flags)764 int CDECL _chmod(const char *path, int flags)
765 {
766   DWORD oldFlags = GetFileAttributesA(path);
767 
768   if (oldFlags != INVALID_FILE_ATTRIBUTES)
769   {
770     DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
771       oldFlags | FILE_ATTRIBUTE_READONLY;
772 
773     if (newFlags == oldFlags || SetFileAttributesA(path, newFlags))
774       return 0;
775   }
776   _dosmaperr(GetLastError());
777   return -1;
778 }
779 
780 /*********************************************************************
781  *		_wchmod (MSVCRT.@)
782  */
_wchmod(const wchar_t * path,int flags)783 int CDECL _wchmod(const wchar_t *path, int flags)
784 {
785   DWORD oldFlags = GetFileAttributesW(path);
786 
787   if (oldFlags != INVALID_FILE_ATTRIBUTES)
788   {
789     DWORD newFlags = (flags & _S_IWRITE)? oldFlags & ~FILE_ATTRIBUTE_READONLY:
790       oldFlags | FILE_ATTRIBUTE_READONLY;
791 
792     if (newFlags == oldFlags || SetFileAttributesW(path, newFlags))
793       return 0;
794   }
795   _dosmaperr(GetLastError());
796   return -1;
797 }
798 
799 /*********************************************************************
800  *		_unlink (MSVCRT.@)
801  */
_unlink(const char * path)802 int CDECL _unlink(const char *path)
803 {
804   TRACE("%s\n",debugstr_a(path));
805   if(DeleteFileA(path))
806     return 0;
807   TRACE("failed (%d)\n",GetLastError());
808   _dosmaperr(GetLastError());
809   return -1;
810 }
811 
812 /*********************************************************************
813  *		_wunlink (MSVCRT.@)
814  */
_wunlink(const wchar_t * path)815 int CDECL _wunlink(const wchar_t *path)
816 {
817   TRACE("(%s)\n",debugstr_w(path));
818   if(DeleteFileW(path))
819     return 0;
820   TRACE("failed (%d)\n",GetLastError());
821   _dosmaperr(GetLastError());
822   return -1;
823 }
824 
825 /*********************************************************************
826  *		_commit (MSVCRT.@)
827  */
_commit(int fd)828 int CDECL _commit(int fd)
829 {
830     ioinfo *info = get_ioinfo(fd);
831     int ret;
832 
833     TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
834 
835     if (info->handle == INVALID_HANDLE_VALUE)
836         ret = -1;
837     else if (!FlushFileBuffers(info->handle))
838     {
839         if (GetLastError() == ERROR_INVALID_HANDLE)
840         {
841             /* FlushFileBuffers fails for console handles
842              * so we ignore this error.
843              */
844             ret = 0;
845         }
846         else
847         {
848             TRACE(":failed-last error (%d)\n",GetLastError());
849             _dosmaperr(GetLastError());
850             ret = -1;
851         }
852     }
853     else
854     {
855         TRACE(":ok\n");
856         ret = 0;
857     }
858 
859     release_ioinfo(info);
860     return ret;
861 }
862 
863 /* _flushall calls fflush which calls _flushall */
864 int CDECL fflush(FILE* file);
865 
866 /* INTERNAL: Flush all stream buffer */
msvcrt_flush_all_buffers(int mask)867 static int msvcrt_flush_all_buffers(int mask)
868 {
869   int i, num_flushed = 0;
870   FILE *file;
871 
872   LOCK_FILES();
873   for (i = 0; i < MSVCRT_stream_idx; i++) {
874     file = msvcrt_get_file(i);
875 
876     if (file->_flag)
877     {
878       if(file->_flag & mask) {
879 	fflush(file);
880         num_flushed++;
881       }
882     }
883   }
884   UNLOCK_FILES();
885 
886   TRACE(":flushed (%d) handles\n",num_flushed);
887   return num_flushed;
888 }
889 
890 /*********************************************************************
891  *		_flushall (MSVCRT.@)
892  */
_flushall(void)893 int CDECL _flushall(void)
894 {
895     return msvcrt_flush_all_buffers(_IOWRT | _IOREAD);
896 }
897 
898 /*********************************************************************
899  *		fflush (MSVCRT.@)
900  */
fflush(FILE * file)901 int CDECL fflush(FILE* file)
902 {
903     if(!file) {
904         msvcrt_flush_all_buffers(_IOWRT);
905     } else if(file->_flag & _IOWRT) {
906         int res;
907 
908         _lock_file(file);
909         res = msvcrt_flush_buffer(file);
910         /* FIXME
911         if(!res && (file->_flag & _IOCOMMIT))
912             res = _commit(file->_file) ? EOF : 0;
913         */
914         _unlock_file(file);
915 
916         return res;
917     } else if(file->_flag & _IOREAD) {
918         _lock_file(file);
919         file->_cnt = 0;
920         file->_ptr = file->_base;
921         _unlock_file(file);
922 
923         return 0;
924     }
925     return 0;
926 }
927 
928 /*********************************************************************
929  *		_close (MSVCRT.@)
930  */
_close(int fd)931 int CDECL _close(int fd)
932 {
933   ioinfo *info = get_ioinfo(fd);
934   int ret;
935 
936   TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
937   if (!(info->wxflag & WX_OPEN)) {
938     ret = -1;
939   } else if (fd == STDOUT_FILENO &&
940           info->handle == get_ioinfo_nolock(STDERR_FILENO)->handle) {
941     msvcrt_free_fd(fd);
942     ret = 0;
943   } else if (fd == STDERR_FILENO &&
944           info->handle == get_ioinfo_nolock(STDOUT_FILENO)->handle) {
945     msvcrt_free_fd(fd);
946     ret = 0;
947   } else {
948     ret = CloseHandle(info->handle) ? 0 : -1;
949     msvcrt_free_fd(fd);
950     if (ret) {
951       WARN(":failed-last error (%d)\n",GetLastError());
952       _dosmaperr(GetLastError());
953       ret = -1;
954     }
955   }
956   release_ioinfo(info);
957   return ret;
958 }
959 
960 /*********************************************************************
961  *		_dup2 (MSVCRT.@)
962  * NOTES
963  * MSDN isn't clear on this point, but the remarks for _pipe
964  * indicate file descriptors duplicated with _dup and _dup2 are always
965  * inheritable.
966  */
_dup2(int od,int nd)967 int CDECL _dup2(int od, int nd)
968 {
969   ioinfo *info_od, *info_nd;
970   int ret;
971 
972   TRACE("(od=%d, nd=%d)\n", od, nd);
973 
974   if (od < nd)
975   {
976     info_od = get_ioinfo(od);
977     info_nd = get_ioinfo_alloc_fd(nd);
978   }
979   else
980   {
981     info_nd = get_ioinfo_alloc_fd(nd);
982     info_od = get_ioinfo(od);
983   }
984 
985   if (info_nd == &__badioinfo)
986   {
987       ret = -1;
988   }
989   else if (info_od->wxflag & WX_OPEN)
990   {
991     HANDLE handle;
992 
993     if (DuplicateHandle(GetCurrentProcess(), info_od->handle,
994      GetCurrentProcess(), &handle, 0, TRUE, DUPLICATE_SAME_ACCESS))
995     {
996       int wxflag = info_od->wxflag & ~WX_DONTINHERIT;
997 
998       if (info_nd->wxflag & WX_OPEN)
999         _close(nd);
1000 
1001       msvcrt_set_fd(info_nd, handle, wxflag);
1002       /* _dup2 returns 0, not nd, on success */
1003       ret = 0;
1004     }
1005     else
1006     {
1007       ret = -1;
1008       _dosmaperr(GetLastError());
1009     }
1010   }
1011   else
1012   {
1013     *_errno() = EBADF;
1014     ret = -1;
1015   }
1016 
1017   release_ioinfo(info_od);
1018   release_ioinfo(info_nd);
1019   return ret;
1020 }
1021 
1022 /*********************************************************************
1023  *		_dup (MSVCRT.@)
1024  */
_dup(int od)1025 int CDECL _dup(int od)
1026 {
1027   int fd, ret;
1028   ioinfo *info = get_ioinfo_alloc(&fd);
1029 
1030   if (_dup2(od, fd) == 0)
1031     ret = fd;
1032   else
1033     ret = -1;
1034   release_ioinfo(info);
1035   return ret;
1036 }
1037 
1038 /*********************************************************************
1039  *		_eof (MSVCRT.@)
1040  */
_eof(int fd)1041 int CDECL _eof(int fd)
1042 {
1043   ioinfo *info = get_ioinfo(fd);
1044   DWORD curpos,endpos;
1045   LONG hcurpos,hendpos;
1046 
1047   TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
1048 
1049   if (info->handle == INVALID_HANDLE_VALUE)
1050   {
1051     release_ioinfo(info);
1052     return -1;
1053   }
1054 
1055   if (info->wxflag & WX_ATEOF)
1056   {
1057       release_ioinfo(info);
1058       return TRUE;
1059   }
1060 
1061   /* Otherwise we do it the hard way */
1062   hcurpos = hendpos = 0;
1063   curpos = SetFilePointer(info->handle, 0, &hcurpos, FILE_CURRENT);
1064   endpos = SetFilePointer(info->handle, 0, &hendpos, FILE_END);
1065 
1066   if (curpos == endpos && hcurpos == hendpos)
1067   {
1068     /* FIXME: shouldn't WX_ATEOF be set here? */
1069     release_ioinfo(info);
1070     return TRUE;
1071   }
1072 
1073   SetFilePointer(info->handle, curpos, &hcurpos, FILE_BEGIN);
1074   release_ioinfo(info);
1075   return FALSE;
1076 }
1077 
1078 /*********************************************************************
1079  *		_fcloseall (MSVCRT.@)
1080  */
_fcloseall(void)1081 int CDECL _fcloseall(void)
1082 {
1083   int num_closed = 0, i;
1084   FILE *file;
1085 
1086   LOCK_FILES();
1087   for (i = 3; i < MSVCRT_stream_idx; i++) {
1088     file = msvcrt_get_file(i);
1089 
1090     if (file->_flag && !fclose(file))
1091       num_closed++;
1092   }
1093   UNLOCK_FILES();
1094 
1095   TRACE(":closed (%d) handles\n",num_closed);
1096   return num_closed;
1097 }
1098 
1099 /* free everything on process exit */
msvcrt_free_io(void)1100 void msvcrt_free_io(void)
1101 {
1102     unsigned int i;
1103     int j;
1104 
1105     _flushall();
1106     _fcloseall();
1107 
1108     for(i=0; i<sizeof(__pioinfo)/sizeof(__pioinfo[0]); i++)
1109     {
1110         if(!__pioinfo[i])
1111             continue;
1112 
1113         for(j=0; j<MSVCRT_FD_BLOCK_SIZE; j++)
1114         {
1115             if(__pioinfo[i][j].exflag & EF_CRIT_INIT)
1116                 DeleteCriticalSection(&__pioinfo[i][j].crit);
1117         }
1118         free(__pioinfo[i]);
1119     }
1120 
1121     for(j=0; j<MSVCRT_stream_idx; j++)
1122     {
1123         FILE *file = msvcrt_get_file(j);
1124         if(file<_iob || file>=_iob+_IOB_ENTRIES)
1125         {
1126             ((file_crit*)file)->crit.DebugInfo->Spare[0] = 0;
1127             DeleteCriticalSection(&((file_crit*)file)->crit);
1128         }
1129     }
1130 
1131     for(i=0; i<sizeof(MSVCRT_fstream)/sizeof(MSVCRT_fstream[0]); i++)
1132         free(MSVCRT_fstream[i]);
1133 }
1134 
1135 /*********************************************************************
1136  *		_lseeki64 (MSVCRT.@)
1137  */
_lseeki64(int fd,__int64 offset,int whence)1138 __int64 CDECL _lseeki64(int fd, __int64 offset, int whence)
1139 {
1140   ioinfo *info = get_ioinfo(fd);
1141   LARGE_INTEGER ofs;
1142 
1143   TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
1144 
1145   if (info->handle == INVALID_HANDLE_VALUE)
1146   {
1147     release_ioinfo(info);
1148     return -1;
1149   }
1150 
1151   if (whence < 0 || whence > 2)
1152   {
1153     release_ioinfo(info);
1154     *_errno() = EINVAL;
1155     return -1;
1156   }
1157 
1158   TRACE(":fd (%d) to %s pos %s\n",
1159         fd,wine_dbgstr_longlong(offset),
1160         (whence==SEEK_SET)?"SEEK_SET":
1161         (whence==SEEK_CUR)?"SEEK_CUR":
1162         (whence==SEEK_END)?"SEEK_END":"UNKNOWN");
1163 
1164   /* The MoleBox protection scheme expects msvcrt to use SetFilePointer only,
1165    * so a LARGE_INTEGER offset cannot be passed directly via SetFilePointerEx. */
1166   ofs.QuadPart = offset;
1167   if ((ofs.u.LowPart = SetFilePointer(info->handle, ofs.u.LowPart, &ofs.u.HighPart, whence)) != INVALID_SET_FILE_POINTER ||
1168       GetLastError() == ERROR_SUCCESS)
1169   {
1170     info->wxflag &= ~(WX_ATEOF|WX_READEOF);
1171     /* FIXME: What if we seek _to_ EOF - is EOF set? */
1172 
1173     release_ioinfo(info);
1174     return ofs.QuadPart;
1175   }
1176   release_ioinfo(info);
1177   TRACE(":error-last error (%d)\n",GetLastError());
1178   _dosmaperr(GetLastError());
1179   return -1;
1180 }
1181 
1182 /*********************************************************************
1183  *		_lseek (MSVCRT.@)
1184  */
_lseek(int fd,LONG offset,int whence)1185 LONG CDECL _lseek(int fd, LONG offset, int whence)
1186 {
1187     return (LONG)_lseeki64(fd, offset, whence);
1188 }
1189 
1190 /*********************************************************************
1191  *              _lock_file (MSVCRT.@)
1192  */
_lock_file(FILE * file)1193 void CDECL _lock_file(FILE *file)
1194 {
1195     if(file>=_iob && file<_iob+_IOB_ENTRIES)
1196         _lock(_STREAM_LOCKS+(file-_iob));
1197     /* ReactOS: string streams dont need to be locked */
1198     else if(!(file->_flag & _IOSTRG))
1199         EnterCriticalSection(&((file_crit*)file)->crit);
1200 }
1201 
1202 /*********************************************************************
1203  *              _unlock_file (MSVCRT.@)
1204  */
_unlock_file(FILE * file)1205 void CDECL _unlock_file(FILE *file)
1206 {
1207     if(file>=_iob && file<_iob+_IOB_ENTRIES)
1208         _unlock(_STREAM_LOCKS+(file-_iob));
1209     /* ReactOS: string streams dont need to be locked */
1210     else if(!(file->_flag & _IOSTRG))
1211         LeaveCriticalSection(&((file_crit*)file)->crit);
1212 
1213 }
1214 
1215 /*********************************************************************
1216  *		_locking (MSVCRT.@)
1217  *
1218  * This is untested; the underlying LockFile doesn't work yet.
1219  */
_locking(int fd,int mode,LONG nbytes)1220 int CDECL _locking(int fd, int mode, LONG nbytes)
1221 {
1222   ioinfo *info = get_ioinfo(fd);
1223   BOOL ret;
1224   DWORD cur_locn;
1225 
1226   TRACE(":fd (%d) handle (%p)\n", fd, info->handle);
1227   if (info->handle == INVALID_HANDLE_VALUE)
1228   {
1229     release_ioinfo(info);
1230     return -1;
1231   }
1232 
1233   if (mode < 0 || mode > 4)
1234   {
1235     release_ioinfo(info);
1236     *_errno() = EINVAL;
1237     return -1;
1238   }
1239 
1240   TRACE(":fd (%d) by 0x%08x mode %s\n",
1241         fd,nbytes,(mode==_LK_UNLCK)?"_LK_UNLCK":
1242         (mode==_LK_LOCK)?"_LK_LOCK":
1243         (mode==_LK_NBLCK)?"_LK_NBLCK":
1244         (mode==_LK_RLCK)?"_LK_RLCK":
1245         (mode==_LK_NBRLCK)?"_LK_NBRLCK":
1246                           "UNKNOWN");
1247 
1248   if ((cur_locn = SetFilePointer(info->handle, 0L, NULL, FILE_CURRENT)) == INVALID_SET_FILE_POINTER)
1249   {
1250     release_ioinfo(info);
1251     FIXME ("Seek failed\n");
1252     *_errno() = EINVAL; /* FIXME */
1253     return -1;
1254   }
1255   if (mode == _LK_LOCK || mode == _LK_RLCK)
1256   {
1257     int nretry = 10;
1258     ret = 1; /* just to satisfy gcc */
1259     while (nretry--)
1260     {
1261       ret = LockFile(info->handle, cur_locn, 0L, nbytes, 0L);
1262       if (ret) break;
1263       Sleep(1);
1264     }
1265   }
1266   else if (mode == _LK_UNLCK)
1267     ret = UnlockFile(info->handle, cur_locn, 0L, nbytes, 0L);
1268   else
1269     ret = LockFile(info->handle, cur_locn, 0L, nbytes, 0L);
1270   /* FIXME - what about error settings? */
1271   release_ioinfo(info);
1272   return ret ? 0 : -1;
1273 }
1274 
1275 /*********************************************************************
1276  *		_fseeki64 (MSVCRT.@)
1277  */
_fseeki64(FILE * file,__int64 offset,int whence)1278 int CDECL _fseeki64(FILE* file, __int64 offset, int whence)
1279 {
1280   int ret;
1281 
1282   _lock_file(file);
1283   /* Flush output if needed */
1284   if(file->_flag & _IOWRT)
1285 	msvcrt_flush_buffer(file);
1286 
1287   if(whence == SEEK_CUR && file->_flag & _IOREAD ) {
1288       whence = SEEK_SET;
1289       offset += _ftelli64(file);
1290   }
1291 
1292   /* Discard buffered input */
1293   file->_cnt = 0;
1294   file->_ptr = file->_base;
1295   /* Reset direction of i/o */
1296   if(file->_flag & _IORW) {
1297         file->_flag &= ~(_IOREAD|_IOWRT);
1298   }
1299   /* Clear end of file flag */
1300   file->_flag &= ~_IOEOF;
1301   ret = (_lseeki64(file->_file,offset,whence) == -1)?-1:0;
1302 
1303   _unlock_file(file);
1304   return ret;
1305 }
1306 
1307 /*********************************************************************
1308  *		fseek (MSVCRT.@)
1309  */
fseek(FILE * file,long offset,int whence)1310 int CDECL fseek(FILE* file, long offset, int whence)
1311 {
1312     return _fseeki64( file, offset, whence );
1313 }
1314 
1315 /*********************************************************************
1316  *		_chsize_s (MSVCRT.@)
1317  */
_chsize_s(int fd,__int64 size)1318 int CDECL _chsize_s(int fd, __int64 size)
1319 {
1320     ioinfo *info;
1321     __int64 cur, pos;
1322     BOOL ret = FALSE;
1323 
1324     TRACE("(fd=%d, size=%s)\n", fd, wine_dbgstr_longlong(size));
1325 
1326     if (!MSVCRT_CHECK_PMT(size >= 0)) return EINVAL;
1327 
1328     info = get_ioinfo(fd);
1329     if (info->handle != INVALID_HANDLE_VALUE)
1330     {
1331         /* save the current file pointer */
1332         cur = _lseeki64(fd, 0, SEEK_CUR);
1333         if (cur >= 0)
1334         {
1335             pos = _lseeki64(fd, size, SEEK_SET);
1336             if (pos >= 0)
1337             {
1338                 ret = SetEndOfFile(info->handle);
1339                 if (!ret) _dosmaperr(GetLastError());
1340             }
1341 
1342             /* restore the file pointer */
1343             _lseeki64(fd, cur, SEEK_SET);
1344         }
1345     }
1346 
1347     release_ioinfo(info);
1348     return ret ? 0 : *_errno();
1349 }
1350 
1351 /*********************************************************************
1352  *		_chsize (MSVCRT.@)
1353  */
_chsize(int fd,long size)1354 int CDECL _chsize(int fd, long size)
1355 {
1356     /* _chsize_s returns errno on failure but _chsize should return -1 */
1357     return _chsize_s( fd, size ) == 0 ? 0 : -1;
1358 }
1359 
1360 /*********************************************************************
1361  *		clearerr (MSVCRT.@)
1362  */
clearerr(FILE * file)1363 void CDECL clearerr(FILE* file)
1364 {
1365   TRACE(":file (%p) fd (%d)\n",file,file->_file);
1366 
1367   _lock_file(file);
1368   file->_flag &= ~(_IOERR | _IOEOF);
1369   _unlock_file(file);
1370 }
1371 
1372 /*********************************************************************
1373  *		rewind (MSVCRT.@)
1374  */
rewind(FILE * file)1375 void CDECL rewind(FILE* file)
1376 {
1377   TRACE(":file (%p) fd (%d)\n",file,file->_file);
1378 
1379   _lock_file(file);
1380   fseek(file, 0L, SEEK_SET);
1381   clearerr(file);
1382   _unlock_file(file);
1383 }
1384 
msvcrt_get_flags(const wchar_t * mode,int * open_flags,int * stream_flags)1385 static int msvcrt_get_flags(const wchar_t* mode, int *open_flags, int* stream_flags)
1386 {
1387   int plus = strchrW(mode, '+') != NULL;
1388 
1389   TRACE("%s\n", debugstr_w(mode));
1390 
1391   while(*mode == ' ') mode++;
1392 
1393   switch(*mode++)
1394   {
1395   case 'R': case 'r':
1396     *open_flags = plus ? _O_RDWR : _O_RDONLY;
1397     *stream_flags = plus ? _IORW : _IOREAD;
1398     break;
1399   case 'W': case 'w':
1400     *open_flags = _O_CREAT | _O_TRUNC | (plus  ? _O_RDWR : _O_WRONLY);
1401     *stream_flags = plus ? _IORW : _IOWRT;
1402     break;
1403   case 'A': case 'a':
1404     *open_flags = _O_CREAT | _O_APPEND | (plus  ? _O_RDWR : _O_WRONLY);
1405     *stream_flags = plus ? _IORW : _IOWRT;
1406     break;
1407   default:
1408     MSVCRT_INVALID_PMT(0, EINVAL);
1409     return -1;
1410   }
1411 
1412   *stream_flags |= _commode;
1413 
1414   while (*mode && *mode!=',')
1415     switch (*mode++)
1416     {
1417     case 'B': case 'b':
1418       *open_flags |=  _O_BINARY;
1419       *open_flags &= ~_O_TEXT;
1420       break;
1421     case 't':
1422       *open_flags |=  _O_TEXT;
1423       *open_flags &= ~_O_BINARY;
1424       break;
1425     case 'D':
1426       *open_flags |= _O_TEMPORARY;
1427       break;
1428     case 'T':
1429       *open_flags |= _O_SHORT_LIVED;
1430       break;
1431     case 'c':
1432       *stream_flags |= _IOCOMMIT;
1433       break;
1434     case 'n':
1435       *stream_flags &= ~_IOCOMMIT;
1436       break;
1437     case 'N':
1438       *open_flags |= _O_NOINHERIT;
1439       break;
1440     case '+':
1441     case ' ':
1442     case 'a':
1443     case 'w':
1444       break;
1445     case 'S':
1446     case 'R':
1447       FIXME("ignoring cache optimization flag: %c\n", mode[-1]);
1448       break;
1449     default:
1450       ERR("incorrect mode flag: %c\n", mode[-1]);
1451       break;
1452     }
1453 
1454   if(*mode == ',')
1455   {
1456     static const WCHAR ccs[] = {'c','c','s'};
1457     static const WCHAR utf8[] = {'u','t','f','-','8'};
1458     static const WCHAR utf16le[] = {'u','t','f','-','1','6','l','e'};
1459     static const WCHAR unicode[] = {'u','n','i','c','o','d','e'};
1460 
1461     mode++;
1462     while(*mode == ' ') mode++;
1463     if(!MSVCRT_CHECK_PMT(!strncmpW(ccs, mode, sizeof(ccs)/sizeof(ccs[0]))))
1464       return -1;
1465     mode += sizeof(ccs)/sizeof(ccs[0]);
1466     while(*mode == ' ') mode++;
1467     if(!MSVCRT_CHECK_PMT(*mode == '='))
1468         return -1;
1469     mode++;
1470     while(*mode == ' ') mode++;
1471 
1472     if(!strncmpiW(utf8, mode, sizeof(utf8)/sizeof(utf8[0])))
1473     {
1474       *open_flags |= _O_U8TEXT;
1475       mode += sizeof(utf8)/sizeof(utf8[0]);
1476     }
1477     else if(!strncmpiW(utf16le, mode, sizeof(utf16le)/sizeof(utf16le[0])))
1478     {
1479       *open_flags |= _O_U16TEXT;
1480       mode += sizeof(utf16le)/sizeof(utf16le[0]);
1481     }
1482     else if(!strncmpiW(unicode, mode, sizeof(unicode)/sizeof(unicode[0])))
1483     {
1484       *open_flags |= _O_WTEXT;
1485       mode += sizeof(unicode)/sizeof(unicode[0]);
1486     }
1487     else
1488     {
1489       MSVCRT_INVALID_PMT(0, EINVAL);
1490       return -1;
1491     }
1492 
1493     while(*mode == ' ') mode++;
1494   }
1495 
1496   if(!MSVCRT_CHECK_PMT(*mode == 0))
1497     return -1;
1498   return 0;
1499 }
1500 
1501 /*********************************************************************
1502  *		_fdopen (MSVCRT.@)
1503  */
_fdopen(int fd,const char * mode)1504 FILE* CDECL _fdopen(int fd, const char *mode)
1505 {
1506     FILE *ret;
1507     wchar_t *modeW = NULL;
1508 
1509     if (mode && !(modeW = msvcrt_wstrdupa(mode))) return NULL;
1510 
1511     ret = _wfdopen(fd, modeW);
1512 
1513     free(modeW);
1514     return ret;
1515 }
1516 
1517 /*********************************************************************
1518  *		_wfdopen (MSVCRT.@)
1519  */
_wfdopen(int fd,const wchar_t * mode)1520 FILE* CDECL _wfdopen(int fd, const wchar_t *mode)
1521 {
1522   int open_flags, stream_flags;
1523   FILE* file;
1524 
1525   if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1) return NULL;
1526 
1527   LOCK_FILES();
1528   if (!(file = msvcrt_alloc_fp()))
1529     file = NULL;
1530   else if (msvcrt_init_fp(file, fd, stream_flags) == -1)
1531   {
1532     file->_flag = 0;
1533     file = NULL;
1534   }
1535   else TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
1536   UNLOCK_FILES();
1537 
1538   return file;
1539 }
1540 
1541 /*********************************************************************
1542  *		_filelength (MSVCRT.@)
1543  */
_filelength(int fd)1544 LONG CDECL _filelength(int fd)
1545 {
1546   LONG curPos = _lseek(fd, 0, SEEK_CUR);
1547   if (curPos != -1)
1548   {
1549     LONG endPos = _lseek(fd, 0, SEEK_END);
1550     if (endPos != -1)
1551     {
1552       if (endPos != curPos)
1553         _lseek(fd, curPos, SEEK_SET);
1554       return endPos;
1555     }
1556   }
1557   return -1;
1558 }
1559 
1560 /*********************************************************************
1561  *		_filelengthi64 (MSVCRT.@)
1562  */
_filelengthi64(int fd)1563 __int64 CDECL _filelengthi64(int fd)
1564 {
1565   __int64 curPos = _lseeki64(fd, 0, SEEK_CUR);
1566   if (curPos != -1)
1567   {
1568     __int64 endPos = _lseeki64(fd, 0, SEEK_END);
1569     if (endPos != -1)
1570     {
1571       if (endPos != curPos)
1572         _lseeki64(fd, curPos, SEEK_SET);
1573       return endPos;
1574     }
1575   }
1576   return -1;
1577 }
1578 
1579 /*********************************************************************
1580  *		_fileno (MSVCRT.@)
1581  */
_fileno(FILE * file)1582 int CDECL _fileno(FILE* file)
1583 {
1584   TRACE(":FILE* (%p) fd (%d)\n",file,file->_file);
1585   return file->_file;
1586 }
1587 
1588 /*********************************************************************
1589  *		_get_osfhandle (MSVCRT.@)
1590  */
_get_osfhandle(int fd)1591 intptr_t CDECL _get_osfhandle(int fd)
1592 {
1593   HANDLE hand = get_ioinfo_nolock(fd)->handle;
1594   TRACE(":fd (%d) handle (%p)\n",fd,hand);
1595 
1596   if(hand == INVALID_HANDLE_VALUE)
1597       *_errno() = EBADF;
1598   return (intptr_t)hand;
1599 }
1600 
1601 /*********************************************************************
1602  *		_mktemp (MSVCRT.@)
1603  */
_mktemp(char * pattern)1604 char * CDECL _mktemp(char *pattern)
1605 {
1606   int numX = 0;
1607   char *retVal = pattern;
1608   int id;
1609   char letter = 'a';
1610 
1611   if(!pattern)
1612       return NULL;
1613 
1614   while(*pattern)
1615     numX = (*pattern++ == 'X')? numX + 1 : 0;
1616   if (numX < 6)
1617     return NULL;
1618   pattern--;
1619   id = GetCurrentProcessId();
1620   numX = 6;
1621   while(numX--)
1622   {
1623     int tempNum = id / 10;
1624     *pattern-- = id - (tempNum * 10) + '0';
1625     id = tempNum;
1626   }
1627   pattern++;
1628   do
1629   {
1630     *pattern = letter++;
1631     if (GetFileAttributesA(retVal) == INVALID_FILE_ATTRIBUTES)
1632       return retVal;
1633   } while(letter <= 'z');
1634   return NULL;
1635 }
1636 
1637 /*********************************************************************
1638  *		_wmktemp (MSVCRT.@)
1639  */
_wmktemp(wchar_t * pattern)1640 wchar_t * CDECL _wmktemp(wchar_t *pattern)
1641 {
1642   int numX = 0;
1643   wchar_t *retVal = pattern;
1644   int id;
1645   wchar_t letter = 'a';
1646 
1647   while(*pattern)
1648     numX = (*pattern++ == 'X')? numX + 1 : 0;
1649   if (numX < 5)
1650     return NULL;
1651   pattern--;
1652   id = GetCurrentProcessId();
1653   numX = 6;
1654   while(numX--)
1655   {
1656     int tempNum = id / 10;
1657     *pattern-- = id - (tempNum * 10) + '0';
1658     id = tempNum;
1659   }
1660   pattern++;
1661   do
1662   {
1663     if (GetFileAttributesW(retVal) == INVALID_FILE_ATTRIBUTES &&
1664         GetLastError() == ERROR_FILE_NOT_FOUND)
1665       return retVal;
1666     *pattern = letter++;
1667   } while(letter != '|');
1668   return NULL;
1669 }
1670 
split_oflags(unsigned oflags)1671 /*static*/ unsigned split_oflags(unsigned oflags)
1672 {
1673     int wxflags = 0;
1674     unsigned unsupp; /* until we support everything */
1675 
1676     if (oflags & _O_APPEND)              wxflags |= WX_APPEND;
1677     if (oflags & _O_BINARY)              {/* Nothing to do */}
1678     else if (oflags & _O_TEXT)           wxflags |= WX_TEXT;
1679     else if (oflags & _O_WTEXT)          wxflags |= WX_TEXT;
1680     else if (oflags & _O_U16TEXT)        wxflags |= WX_TEXT;
1681     else if (oflags & _O_U8TEXT)         wxflags |= WX_TEXT;
1682     else if (*__p__fmode() & _O_BINARY)  {/* Nothing to do */}
1683     else                                        wxflags |= WX_TEXT; /* default to TEXT*/
1684     if (oflags & _O_NOINHERIT)           wxflags |= WX_DONTINHERIT;
1685 
1686     if ((unsupp = oflags & ~(
1687                     _O_BINARY|_O_TEXT|_O_APPEND|
1688                     _O_TRUNC|_O_EXCL|_O_CREAT|
1689                     _O_RDWR|_O_WRONLY|_O_TEMPORARY|
1690                     _O_NOINHERIT|
1691                     _O_SEQUENTIAL|_O_RANDOM|_O_SHORT_LIVED|
1692                     _O_WTEXT|_O_U16TEXT|_O_U8TEXT
1693                     )))
1694         ERR(":unsupported oflags 0x%04x\n",unsupp);
1695 
1696     return wxflags;
1697 }
1698 
1699 /*********************************************************************
1700  *              _pipe (MSVCRT.@)
1701  */
_pipe(int * pfds,unsigned int psize,int textmode)1702 int CDECL _pipe(int *pfds, unsigned int psize, int textmode)
1703 {
1704   int ret = -1;
1705   SECURITY_ATTRIBUTES sa;
1706   HANDLE readHandle, writeHandle;
1707 
1708   if (!pfds)
1709   {
1710     *_errno() = EINVAL;
1711     return -1;
1712   }
1713 
1714   sa.nLength = sizeof(SECURITY_ATTRIBUTES);
1715   sa.bInheritHandle = !(textmode & _O_NOINHERIT);
1716   sa.lpSecurityDescriptor = NULL;
1717   if (CreatePipe(&readHandle, &writeHandle, &sa, psize))
1718   {
1719     unsigned int wxflags = split_oflags(textmode);
1720     int fd;
1721 
1722     fd = msvcrt_alloc_fd(readHandle, wxflags);
1723     if (fd != -1)
1724     {
1725       pfds[0] = fd;
1726       fd = msvcrt_alloc_fd(writeHandle, wxflags);
1727       if (fd != -1)
1728       {
1729         pfds[1] = fd;
1730         ret = 0;
1731       }
1732       else
1733       {
1734         _close(pfds[0]);
1735         CloseHandle(writeHandle);
1736         *_errno() = EMFILE;
1737       }
1738     }
1739     else
1740     {
1741       CloseHandle(readHandle);
1742       CloseHandle(writeHandle);
1743       *_errno() = EMFILE;
1744     }
1745   }
1746   else
1747     _dosmaperr(GetLastError());
1748 
1749   return ret;
1750 }
1751 
check_bom(HANDLE h,int oflags,BOOL seek)1752 static int check_bom(HANDLE h, int oflags, BOOL seek)
1753 {
1754     char bom[sizeof(utf8_bom)];
1755     DWORD r;
1756 
1757     oflags &= ~(_O_WTEXT|_O_U16TEXT|_O_U8TEXT);
1758 
1759     if (!ReadFile(h, bom, sizeof(utf8_bom), &r, NULL))
1760         return oflags;
1761 
1762     if (r==sizeof(utf8_bom) && !memcmp(bom, utf8_bom, sizeof(utf8_bom))) {
1763         oflags |= _O_U8TEXT;
1764     }else if (r>=sizeof(utf16_bom) && !memcmp(bom, utf16_bom, sizeof(utf16_bom))) {
1765         if (seek && r>2)
1766             SetFilePointer(h, 2, NULL, FILE_BEGIN);
1767         oflags |= _O_U16TEXT;
1768     }else if (seek) {
1769         SetFilePointer(h, 0, NULL, FILE_BEGIN);
1770     }
1771 
1772     return oflags;
1773 }
1774 
1775 /*********************************************************************
1776  *              _wsopen_s (MSVCRT.@)
1777  */
_wsopen_s(int * fd,const wchar_t * path,int oflags,int shflags,int pmode)1778 int CDECL _wsopen_s( int *fd, const wchar_t* path, int oflags, int shflags, int pmode )
1779 {
1780   DWORD access = 0, creation = 0, attrib;
1781   SECURITY_ATTRIBUTES sa;
1782   DWORD sharing, type;
1783   int wxflag;
1784   HANDLE hand;
1785 
1786   TRACE("fd*: %p :file (%s) oflags: 0x%04x shflags: 0x%04x pmode: 0x%04x\n",
1787         fd, debugstr_w(path), oflags, shflags, pmode);
1788 
1789   if (!MSVCRT_CHECK_PMT( fd != NULL )) return EINVAL;
1790 
1791   *fd = -1;
1792   wxflag = split_oflags(oflags);
1793   switch (oflags & (_O_RDONLY | _O_WRONLY | _O_RDWR))
1794   {
1795   case _O_RDONLY: access |= GENERIC_READ; break;
1796   case _O_WRONLY: access |= GENERIC_WRITE; break;
1797   case _O_RDWR:   access |= GENERIC_WRITE | GENERIC_READ; break;
1798   }
1799 
1800   if (oflags & _O_CREAT)
1801   {
1802     if(pmode & ~(_S_IREAD | _S_IWRITE))
1803       FIXME(": pmode 0x%04x ignored\n", pmode);
1804     else
1805       WARN(": pmode 0x%04x ignored\n", pmode);
1806 
1807     if (oflags & _O_EXCL)
1808       creation = CREATE_NEW;
1809     else if (oflags & _O_TRUNC)
1810       creation = CREATE_ALWAYS;
1811     else
1812       creation = OPEN_ALWAYS;
1813   }
1814   else  /* no _O_CREAT */
1815   {
1816     if (oflags & _O_TRUNC)
1817       creation = TRUNCATE_EXISTING;
1818     else
1819       creation = OPEN_EXISTING;
1820   }
1821 
1822   switch( shflags )
1823   {
1824     case _SH_DENYRW:
1825       sharing = 0L;
1826       break;
1827     case _SH_DENYWR:
1828       sharing = FILE_SHARE_READ;
1829       break;
1830     case _SH_DENYRD:
1831       sharing = FILE_SHARE_WRITE;
1832       break;
1833     case _SH_DENYNO:
1834       sharing = FILE_SHARE_READ | FILE_SHARE_WRITE;
1835       break;
1836     default:
1837       ERR( "Unhandled shflags 0x%x\n", shflags );
1838       return EINVAL;
1839   }
1840   attrib = FILE_ATTRIBUTE_NORMAL;
1841 
1842   if (oflags & _O_TEMPORARY)
1843   {
1844       attrib |= FILE_FLAG_DELETE_ON_CLOSE;
1845       access |= DELETE;
1846       sharing |= FILE_SHARE_DELETE;
1847   }
1848 
1849   sa.nLength              = sizeof( SECURITY_ATTRIBUTES );
1850   sa.lpSecurityDescriptor = NULL;
1851   sa.bInheritHandle       = !(oflags & _O_NOINHERIT);
1852 
1853   if ((oflags&(_O_WTEXT|_O_U16TEXT|_O_U8TEXT))
1854           && (creation==OPEN_ALWAYS || creation==OPEN_EXISTING)
1855           && !(access&GENERIC_READ))
1856   {
1857       hand = CreateFileW(path, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE,
1858               &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
1859       if (hand != INVALID_HANDLE_VALUE)
1860       {
1861           oflags = check_bom(hand, oflags, FALSE);
1862           CloseHandle(hand);
1863       }
1864       else
1865           oflags &= ~(_O_WTEXT|_O_U16TEXT|_O_U8TEXT);
1866   }
1867 
1868   hand = CreateFileW(path, access, sharing, &sa, creation, attrib, 0);
1869   if (hand == INVALID_HANDLE_VALUE)  {
1870     WARN(":failed-last error (%d)\n",GetLastError());
1871     _dosmaperr(GetLastError());
1872     return *_errno();
1873   }
1874 
1875   if (oflags & (_O_WTEXT | _O_U16TEXT | _O_U8TEXT))
1876   {
1877       if ((access & GENERIC_WRITE) && (creation==CREATE_NEW
1878                   || creation==CREATE_ALWAYS || creation==TRUNCATE_EXISTING
1879                   || (creation==OPEN_ALWAYS && GetLastError()==ERROR_ALREADY_EXISTS)))
1880       {
1881           if (oflags & _O_U8TEXT)
1882           {
1883               DWORD written = 0, tmp;
1884 
1885               while(written!=sizeof(utf8_bom) && WriteFile(hand, (char*)utf8_bom+written,
1886                           sizeof(utf8_bom)-written, &tmp, NULL))
1887                   written += tmp;
1888               if (written != sizeof(utf8_bom)) {
1889                   WARN("error writing BOM\n");
1890                   CloseHandle(hand);
1891                   _dosmaperr(GetLastError());
1892                   return *_errno();
1893               }
1894           }
1895           else
1896           {
1897               DWORD written = 0, tmp;
1898 
1899               while(written!=sizeof(utf16_bom) && WriteFile(hand, (char*)utf16_bom+written,
1900                           sizeof(utf16_bom)-written, &tmp, NULL))
1901                   written += tmp;
1902               if (written != sizeof(utf16_bom))
1903               {
1904                   WARN("error writing BOM\n");
1905                   CloseHandle(hand);
1906                   _dosmaperr(GetLastError());
1907                   return *_errno();
1908               }
1909           }
1910       }
1911       else if (access & GENERIC_READ)
1912           oflags = check_bom(hand, oflags, TRUE);
1913   }
1914 
1915   type = GetFileType(hand);
1916   if (type == FILE_TYPE_CHAR)
1917       wxflag |= WX_TTY;
1918   else if (type == FILE_TYPE_PIPE)
1919       wxflag |= WX_PIPE;
1920 
1921   *fd = msvcrt_alloc_fd(hand, wxflag);
1922   if (*fd == -1)
1923       return *_errno();
1924 
1925   if (oflags & _O_WTEXT)
1926       get_ioinfo_nolock(*fd)->exflag |= EF_UTF16|EF_UNK_UNICODE;
1927   else if (oflags & _O_U16TEXT)
1928       get_ioinfo_nolock(*fd)->exflag |= EF_UTF16;
1929   else if (oflags & _O_U8TEXT)
1930       get_ioinfo_nolock(*fd)->exflag |= EF_UTF8;
1931 
1932   TRACE(":fd (%d) handle (%p)\n", *fd, hand);
1933   return 0;
1934 }
1935 
1936 /*********************************************************************
1937  *              _wsopen (MSVCRT.@)
1938  */
_wsopen(const wchar_t * path,int oflags,int shflags,...)1939 int CDECL _wsopen( const wchar_t *path, int oflags, int shflags, ... )
1940 {
1941   int pmode;
1942   int fd;
1943 
1944   if (oflags & _O_CREAT)
1945   {
1946     __ms_va_list ap;
1947 
1948     __ms_va_start(ap, shflags);
1949     pmode = va_arg(ap, int);
1950     __ms_va_end(ap);
1951   }
1952   else
1953     pmode = 0;
1954 
1955   _wsopen_s(&fd, path, oflags, shflags, pmode);
1956   return fd;
1957 }
1958 
1959 /*********************************************************************
1960  *              _sopen_s (MSVCRT.@)
1961  */
_sopen_s(int * fd,const char * path,int oflags,int shflags,int pmode)1962 int CDECL _sopen_s( int *fd, const char *path, int oflags, int shflags, int pmode )
1963 {
1964     wchar_t *pathW;
1965     int ret;
1966 
1967     if(!MSVCRT_CHECK_PMT(path && (pathW = msvcrt_wstrdupa(path))))
1968         return EINVAL;
1969 
1970     ret = _wsopen_s(fd, pathW, oflags, shflags, pmode);
1971     free(pathW);
1972     return ret;
1973 }
1974 
1975 /*********************************************************************
1976  *              _sopen (MSVCRT.@)
1977  */
_sopen(const char * path,int oflags,int shflags,...)1978 int CDECL _sopen( const char *path, int oflags, int shflags, ... )
1979 {
1980   int pmode;
1981   int fd;
1982 
1983   if (oflags & _O_CREAT)
1984   {
1985     va_list ap;
1986 
1987     va_start(ap, shflags);
1988     pmode = va_arg(ap, int);
1989     va_end(ap);
1990   }
1991   else
1992     pmode = 0;
1993 
1994   _sopen_s(&fd, path, oflags, shflags, pmode);
1995   return fd;
1996 }
1997 
1998 /*********************************************************************
1999  *              _open (MSVCRT.@)
2000  */
_open(const char * path,int flags,...)2001 int CDECL _open( const char *path, int flags, ... )
2002 {
2003   va_list ap;
2004 
2005   if (flags & _O_CREAT)
2006   {
2007     int pmode;
2008     va_start(ap, flags);
2009     pmode = va_arg(ap, int);
2010     va_end(ap);
2011     return _sopen( path, flags, _SH_DENYNO, pmode );
2012   }
2013   else
2014     return _sopen( path, flags, _SH_DENYNO);
2015 }
2016 
2017 /*********************************************************************
2018  *              _wopen (MSVCRT.@)
2019  */
_wopen(const wchar_t * path,int flags,...)2020 int CDECL _wopen(const wchar_t *path,int flags,...)
2021 {
2022   va_list ap;
2023 
2024   if (flags & _O_CREAT)
2025   {
2026     int pmode;
2027     va_start(ap, flags);
2028     pmode = va_arg(ap, int);
2029     va_end(ap);
2030     return _wsopen( path, flags, _SH_DENYNO, pmode );
2031   }
2032   else
2033     return _wsopen( path, flags, _SH_DENYNO);
2034 }
2035 
2036 /*********************************************************************
2037  *		_creat (MSVCRT.@)
2038  */
_creat(const char * path,int flags)2039 int CDECL _creat(const char *path, int flags)
2040 {
2041   int usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC;
2042   return _open(path, usedFlags);
2043 }
2044 
2045 /*********************************************************************
2046  *		_wcreat (MSVCRT.@)
2047  */
_wcreat(const wchar_t * path,int flags)2048 int CDECL _wcreat(const wchar_t *path, int flags)
2049 {
2050   int usedFlags = (flags & _O_TEXT)| _O_CREAT| _O_WRONLY| _O_TRUNC;
2051   return _wopen(path, usedFlags);
2052 }
2053 
2054 /*********************************************************************
2055  *		_open_osfhandle (MSVCRT.@)
2056  */
_open_osfhandle(intptr_t handle,int oflags)2057 int CDECL _open_osfhandle(intptr_t handle, int oflags)
2058 {
2059   DWORD flags;
2060   int fd;
2061 
2062   /* _O_RDONLY (0) always matches, so set the read flag
2063    * MFC's CStdioFile clears O_RDONLY (0)! if it wants to write to the
2064    * file, so set the write flag. It also only sets _O_TEXT if it wants
2065    * text - it never sets _O_BINARY.
2066    */
2067   /* don't let split_oflags() decide the mode if no mode is passed */
2068   if (!(oflags & (_O_BINARY | _O_TEXT)))
2069       oflags |= _O_BINARY;
2070 
2071   flags = GetFileType((HANDLE)handle);
2072   if (flags==FILE_TYPE_UNKNOWN && GetLastError()!=NO_ERROR)
2073   {
2074     _dosmaperr(GetLastError());
2075     return -1;
2076   }
2077 
2078   if (flags == FILE_TYPE_CHAR)
2079     flags = WX_TTY;
2080   else if (flags == FILE_TYPE_PIPE)
2081     flags = WX_PIPE;
2082   else
2083     flags = 0;
2084   flags |= split_oflags(oflags);
2085 
2086   fd = msvcrt_alloc_fd((HANDLE)handle, flags);
2087   TRACE(":handle (%ld) fd (%d) flags 0x%08x\n", handle, fd, flags);
2088   return fd;
2089 }
2090 
2091 /*********************************************************************
2092  *		_rmtmp (MSVCRT.@)
2093  */
_rmtmp(void)2094 int CDECL _rmtmp(void)
2095 {
2096   int num_removed = 0, i;
2097   FILE *file;
2098 
2099   LOCK_FILES();
2100   for (i = 3; i < MSVCRT_stream_idx; i++) {
2101     file = msvcrt_get_file(i);
2102 
2103     if (file->_tmpfname)
2104     {
2105       fclose(file);
2106       num_removed++;
2107     }
2108   }
2109   UNLOCK_FILES();
2110 
2111   if (num_removed)
2112     TRACE(":removed (%d) temp files\n",num_removed);
2113   return num_removed;
2114 }
2115 
get_utf8_char_len(char ch)2116 static inline int get_utf8_char_len(char ch)
2117 {
2118     if((ch&0xf8) == 0xf0)
2119         return 4;
2120     else if((ch&0xf0) == 0xe0)
2121         return 3;
2122     else if((ch&0xe0) == 0xc0)
2123         return 2;
2124     return 1;
2125 }
2126 
2127 /*********************************************************************
2128  * (internal) read_utf8
2129  */
read_utf8(ioinfo * fdinfo,wchar_t * buf,unsigned int count)2130 static int read_utf8(ioinfo *fdinfo, wchar_t *buf, unsigned int count)
2131 {
2132     HANDLE hand = fdinfo->handle;
2133     char min_buf[4], *readbuf, lookahead;
2134     DWORD readbuf_size, pos=0, num_read=1, char_len, i, j;
2135 
2136     /* make the buffer big enough to hold at least one character */
2137     /* read bytes have to fit to output and lookahead buffers */
2138     count /= 2;
2139     readbuf_size = count < 4 ? 4 : count;
2140     if(readbuf_size<=4 || !(readbuf = malloc(readbuf_size))) {
2141         readbuf_size = 4;
2142         readbuf = min_buf;
2143     }
2144 
2145     if(fdinfo->lookahead[0] != '\n') {
2146         readbuf[pos++] = fdinfo->lookahead[0];
2147         fdinfo->lookahead[0] = '\n';
2148 
2149         if(fdinfo->lookahead[1] != '\n') {
2150             readbuf[pos++] = fdinfo->lookahead[1];
2151             fdinfo->lookahead[1] = '\n';
2152 
2153             if(fdinfo->lookahead[2] != '\n') {
2154                 readbuf[pos++] = fdinfo->lookahead[2];
2155                 fdinfo->lookahead[2] = '\n';
2156             }
2157         }
2158     }
2159 
2160     /* NOTE: this case is broken in native dll, reading
2161      *        sometimes fails when small buffer is passed
2162      */
2163     if(count < 4) {
2164         if(!pos && !ReadFile(hand, readbuf, 1, &num_read, NULL)) {
2165             if (GetLastError() == ERROR_BROKEN_PIPE) {
2166                 fdinfo->wxflag |= WX_ATEOF;
2167                 return 0;
2168             }else {
2169                 _dosmaperr(GetLastError());
2170                 return -1;
2171             }
2172         }else if(!num_read) {
2173             fdinfo->wxflag |= WX_ATEOF;
2174             return 0;
2175         }else {
2176             pos++;
2177         }
2178 
2179         char_len = get_utf8_char_len(readbuf[0]);
2180         if(char_len>pos) {
2181             if(ReadFile(hand, readbuf+pos, char_len-pos, &num_read, NULL))
2182                 pos += num_read;
2183         }
2184 
2185         if(readbuf[0] == '\n')
2186             fdinfo->wxflag |= WX_READNL;
2187         else
2188             fdinfo->wxflag &= ~WX_READNL;
2189 
2190         if(readbuf[0] == 0x1a) {
2191             fdinfo->wxflag |= WX_ATEOF;
2192             return 0;
2193         }
2194 
2195         if(readbuf[0] == '\r') {
2196             if(!ReadFile(hand, &lookahead, 1, &num_read, NULL) || num_read!=1)
2197                 buf[0] = '\r';
2198             else if(lookahead == '\n')
2199                 buf[0] = '\n';
2200             else {
2201                 buf[0] = '\r';
2202                 if(fdinfo->wxflag & (WX_PIPE | WX_TTY))
2203                     fdinfo->lookahead[0] = lookahead;
2204                 else
2205                     SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT);
2206             }
2207             return 2;
2208         }
2209 
2210         if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) {
2211             _dosmaperr(GetLastError());
2212             return -1;
2213         }
2214 
2215         return num_read*2;
2216     }
2217 
2218     if(!ReadFile(hand, readbuf+pos, readbuf_size-pos, &num_read, NULL)) {
2219         if(pos) {
2220             num_read = 0;
2221         }else if(GetLastError() == ERROR_BROKEN_PIPE) {
2222             fdinfo->wxflag |= WX_ATEOF;
2223             if (readbuf != min_buf) free(readbuf);
2224             return 0;
2225         }else {
2226             _dosmaperr(GetLastError());
2227             if (readbuf != min_buf) free(readbuf);
2228             return -1;
2229         }
2230     }else if(!pos && !num_read) {
2231         fdinfo->wxflag |= WX_ATEOF;
2232         if (readbuf != min_buf) free(readbuf);
2233         return 0;
2234     }
2235 
2236     pos += num_read;
2237     if(readbuf[0] == '\n')
2238         fdinfo->wxflag |= WX_READNL;
2239     else
2240         fdinfo->wxflag &= ~WX_READNL;
2241 
2242     /* Find first byte of last character (may be incomplete) */
2243     for(i=pos-1; i>0 && i>pos-4; i--)
2244         if((readbuf[i]&0xc0) != 0x80)
2245             break;
2246     char_len = get_utf8_char_len(readbuf[i]);
2247     if(char_len+i <= pos)
2248         i += char_len;
2249 
2250     if(fdinfo->wxflag & (WX_PIPE | WX_TTY)) {
2251         if(i < pos)
2252             fdinfo->lookahead[0] = readbuf[i];
2253         if(i+1 < pos)
2254             fdinfo->lookahead[1] = readbuf[i+1];
2255         if(i+2 < pos)
2256             fdinfo->lookahead[2] = readbuf[i+2];
2257     }else if(i < pos) {
2258         SetFilePointer(fdinfo->handle, i-pos, NULL, FILE_CURRENT);
2259     }
2260     pos = i;
2261 
2262     for(i=0, j=0; i<pos; i++) {
2263         if(readbuf[i] == 0x1a) {
2264             fdinfo->wxflag |= WX_ATEOF;
2265             break;
2266         }
2267 
2268         /* strip '\r' if followed by '\n' */
2269         if(readbuf[i] == '\r' && i+1==pos) {
2270             if(fdinfo->lookahead[0] != '\n' || !ReadFile(hand, &lookahead, 1, &num_read, NULL) || !num_read) {
2271                 readbuf[j++] = '\r';
2272             }else if(lookahead == '\n' && j==0) {
2273                 readbuf[j++] = '\n';
2274             }else {
2275                 if(lookahead != '\n')
2276                     readbuf[j++] = '\r';
2277 
2278                 if(fdinfo->wxflag & (WX_PIPE | WX_TTY))
2279                     fdinfo->lookahead[0] = lookahead;
2280                 else
2281                     SetFilePointer(fdinfo->handle, -1, NULL, FILE_CURRENT);
2282             }
2283         }else if(readbuf[i]!='\r' || readbuf[i+1]!='\n') {
2284             readbuf[j++] = readbuf[i];
2285         }
2286     }
2287     pos = j;
2288 
2289     if(!(num_read = MultiByteToWideChar(CP_UTF8, 0, readbuf, pos, buf, count))) {
2290         _dosmaperr(GetLastError());
2291         if (readbuf != min_buf) free(readbuf);
2292         return -1;
2293     }
2294 
2295     if (readbuf != min_buf) free(readbuf);
2296     return num_read*2;
2297 }
2298 
2299 /*********************************************************************
2300  * (internal) read_i
2301  *
2302  * When reading \r as last character in text mode, read() positions
2303  * the file pointer on the \r character while getc() goes on to
2304  * the following \n
2305  */
read_i(int fd,ioinfo * fdinfo,void * buf,unsigned int count)2306 static int read_i(int fd, ioinfo *fdinfo, void *buf, unsigned int count)
2307 {
2308     DWORD num_read, utf16;
2309     char *bufstart = buf;
2310 
2311     if (count == 0)
2312         return 0;
2313 
2314     if (fdinfo->wxflag & WX_ATEOF) {
2315         TRACE("already at EOF, returning 0\n");
2316         return 0;
2317     }
2318     /* Don't trace small reads, it gets *very* annoying */
2319     if (count > 4)
2320         TRACE(":fd (%d) handle (%p) buf (%p) len (%d)\n", fd, fdinfo->handle, buf, count);
2321     if (fdinfo->handle == INVALID_HANDLE_VALUE)
2322     {
2323         *_errno() = EBADF;
2324         return -1;
2325     }
2326 
2327     utf16 = (fdinfo->exflag & EF_UTF16) != 0;
2328     if (((fdinfo->exflag&EF_UTF8) || utf16) && count&1)
2329     {
2330         *_errno() = EINVAL;
2331         return -1;
2332     }
2333 
2334     if((fdinfo->wxflag&WX_TEXT) && (fdinfo->exflag&EF_UTF8))
2335         return read_utf8(fdinfo, buf, count);
2336 
2337     if (fdinfo->lookahead[0]!='\n' || ReadFile(fdinfo->handle, bufstart, count, &num_read, NULL))
2338     {
2339         if (fdinfo->lookahead[0] != '\n')
2340         {
2341             bufstart[0] = fdinfo->lookahead[0];
2342             fdinfo->lookahead[0] = '\n';
2343 
2344             if (utf16)
2345             {
2346                 bufstart[1] =  fdinfo->lookahead[1];
2347                 fdinfo->lookahead[1] = '\n';
2348             }
2349 
2350             if(count>1+utf16 && ReadFile(fdinfo->handle, bufstart+1+utf16, count-1-utf16, &num_read, NULL))
2351                 num_read += 1+utf16;
2352             else
2353                 num_read = 1+utf16;
2354         }
2355 
2356         if(utf16 && (num_read&1))
2357         {
2358             /* msvcr90 uses uninitialized value from the buffer in this case */
2359             /* msvcrt ignores additional data */
2360             ERR("got odd number of bytes in UTF16 mode\n");
2361             num_read--;
2362         }
2363 
2364         if (count != 0 && num_read == 0)
2365         {
2366             fdinfo->wxflag |= WX_ATEOF;
2367             TRACE(":EOF %s\n",debugstr_an(buf,num_read));
2368         }
2369         else if (fdinfo->wxflag & WX_TEXT)
2370         {
2371             DWORD i, j;
2372 
2373             if (bufstart[0]=='\n' && (!utf16 || bufstart[1]==0))
2374                 fdinfo->wxflag |= WX_READNL;
2375             else
2376                 fdinfo->wxflag &= ~WX_READNL;
2377 
2378             for (i=0, j=0; i<num_read; i+=1+utf16)
2379             {
2380                 /* in text mode, a ctrl-z signals EOF */
2381                 if (bufstart[i]==0x1a && (!utf16 || bufstart[i+1]==0))
2382                 {
2383                     fdinfo->wxflag |= WX_ATEOF;
2384                     TRACE(":^Z EOF %s\n",debugstr_an(buf,num_read));
2385                     break;
2386                 }
2387 
2388                 /* in text mode, strip \r if followed by \n */
2389                 if (bufstart[i]=='\r' && (!utf16 || bufstart[i+1]==0) && i+1+utf16==num_read)
2390                 {
2391                     char lookahead[2];
2392                     DWORD len;
2393 
2394                     lookahead[1] = '\n';
2395                     if (ReadFile(fdinfo->handle, lookahead, 1+utf16, &len, NULL) && len)
2396                     {
2397                         if(lookahead[0]=='\n' && (!utf16 || lookahead[1]==0) && j==0)
2398                         {
2399                             bufstart[j++] = '\n';
2400                             if(utf16) bufstart[j++] = 0;
2401                         }
2402                         else
2403                         {
2404                             if(lookahead[0]!='\n' || (utf16 && lookahead[1]!=0))
2405                             {
2406                                 bufstart[j++] = '\r';
2407                                 if(utf16) bufstart[j++] = 0;
2408                             }
2409 
2410                             if (fdinfo->wxflag & (WX_PIPE | WX_TTY))
2411                             {
2412                                 if (lookahead[0]=='\n' && (!utf16 || !lookahead[1]))
2413                                 {
2414                                     bufstart[j++] = '\n';
2415                                     if (utf16) bufstart[j++] = 0;
2416                                 }
2417                                 else
2418                                 {
2419                                     fdinfo->lookahead[0] = lookahead[0];
2420                                     fdinfo->lookahead[1] = lookahead[1];
2421                                 }
2422                             }
2423                             else
2424                                 SetFilePointer(fdinfo->handle, -1-utf16, NULL, FILE_CURRENT);
2425                         }
2426                     }
2427                     else
2428                     {
2429                         bufstart[j++] = '\r';
2430                         if(utf16) bufstart[j++] = 0;
2431                     }
2432                 }
2433                 else if((bufstart[i]!='\r' || (utf16 && bufstart[i+1]!=0))
2434                         || (bufstart[i+1+utf16]!='\n' || (utf16 && bufstart[i+3]!=0)))
2435                 {
2436                     bufstart[j++] = bufstart[i];
2437                     if(utf16) bufstart[j++] = bufstart[i+1];
2438                 }
2439             }
2440             num_read = j;
2441         }
2442     }
2443     else
2444     {
2445         if (GetLastError() == ERROR_BROKEN_PIPE)
2446         {
2447             TRACE(":end-of-pipe\n");
2448             fdinfo->wxflag |= WX_ATEOF;
2449             return 0;
2450         }
2451         else
2452         {
2453             TRACE(":failed-last error (%d)\n",GetLastError());
2454             return -1;
2455         }
2456     }
2457 
2458     if (count > 4)
2459         TRACE("(%u), %s\n",num_read,debugstr_an(buf, num_read));
2460     return num_read;
2461 }
2462 
2463 /*********************************************************************
2464  *		_read (MSVCRT.@)
2465  */
_read(int fd,void * buf,unsigned int count)2466 int CDECL _read(int fd, void *buf, unsigned int count)
2467 {
2468     ioinfo *info = get_ioinfo(fd);
2469     int num_read = read_i(fd, info, buf, count);
2470     release_ioinfo(info);
2471     return num_read;
2472 }
2473 
2474 /*********************************************************************
2475  *		_setmode (MSVCRT.@)
2476  */
_setmode(int fd,int mode)2477 int CDECL _setmode(int fd,int mode)
2478 {
2479     ioinfo *info = get_ioinfo(fd);
2480     int ret = info->wxflag & WX_TEXT ? _O_TEXT : _O_BINARY;
2481     if(ret==_O_TEXT && (info->exflag & (EF_UTF8|EF_UTF16)))
2482         ret = _O_WTEXT;
2483 
2484     if(mode!=_O_TEXT && mode!=_O_BINARY && mode!=_O_WTEXT
2485                 && mode!=_O_U16TEXT && mode!=_O_U8TEXT) {
2486         *_errno() = EINVAL;
2487         release_ioinfo(info);
2488         return -1;
2489     }
2490 
2491     if(info == &__badioinfo) {
2492         *_errno() = EBADF;
2493         return EOF;
2494     }
2495 
2496     if(mode == _O_BINARY) {
2497         info->wxflag &= ~WX_TEXT;
2498         info->exflag &= ~(EF_UTF8|EF_UTF16);
2499         release_ioinfo(info);
2500         return ret;
2501     }
2502 
2503     info->wxflag |= WX_TEXT;
2504     if(mode == _O_TEXT)
2505         info->exflag &= ~(EF_UTF8|EF_UTF16);
2506     else if(mode == _O_U8TEXT)
2507         info->exflag = (info->exflag & ~EF_UTF16) | EF_UTF8;
2508     else
2509         info->exflag = (info->exflag & ~EF_UTF8) | EF_UTF16;
2510 
2511     release_ioinfo(info);
2512     return ret;
2513 
2514 }
2515 
2516 /*********************************************************************
2517  *		_tell (MSVCRT.@)
2518  */
_tell(int fd)2519 long CDECL _tell(int fd)
2520 {
2521   return _lseek(fd, 0, SEEK_CUR);
2522 }
2523 
2524 /*********************************************************************
2525  *		_telli64 (MSVCRT.@)
2526  */
_telli64(int fd)2527 __int64 CDECL _telli64(int fd)
2528 {
2529   return _lseeki64(fd, 0, SEEK_CUR);
2530 }
2531 
2532 /*********************************************************************
2533  *		_tempnam (MSVCRT.@)
2534  */
_tempnam(const char * dir,const char * prefix)2535 char * CDECL _tempnam(const char *dir, const char *prefix)
2536 {
2537   char tmpbuf[MAX_PATH];
2538   const char *tmp_dir = getenv("TMP");
2539 
2540   if (tmp_dir) dir = tmp_dir;
2541 
2542   TRACE("dir (%s) prefix (%s)\n",dir,prefix);
2543   if (GetTempFileNameA(dir,prefix,0,tmpbuf))
2544   {
2545     TRACE("got name (%s)\n",tmpbuf);
2546     DeleteFileA(tmpbuf);
2547     return _strdup(tmpbuf);
2548   }
2549   TRACE("failed (%d)\n",GetLastError());
2550   return NULL;
2551 }
2552 
2553 /*********************************************************************
2554  *		_wtempnam (MSVCRT.@)
2555  */
_wtempnam(const wchar_t * dir,const wchar_t * prefix)2556 wchar_t * CDECL _wtempnam(const wchar_t *dir, const wchar_t *prefix)
2557 {
2558   wchar_t tmpbuf[MAX_PATH];
2559 
2560   TRACE("dir (%s) prefix (%s)\n",debugstr_w(dir),debugstr_w(prefix));
2561   if (GetTempFileNameW(dir,prefix,0,tmpbuf))
2562   {
2563     TRACE("got name (%s)\n",debugstr_w(tmpbuf));
2564     DeleteFileW(tmpbuf);
2565     return _wcsdup(tmpbuf);
2566   }
2567   TRACE("failed (%d)\n",GetLastError());
2568   return NULL;
2569 }
2570 
2571 /*********************************************************************
2572  *		_umask (MSVCRT.@)
2573  */
_umask(int umask)2574 int CDECL _umask(int umask)
2575 {
2576   int old_umask = MSVCRT_umask;
2577   TRACE("(%d)\n",umask);
2578   MSVCRT_umask = umask;
2579   return old_umask;
2580 }
2581 
2582 /*********************************************************************
2583  *		_write (MSVCRT.@)
2584  */
_write(int fd,const void * buf,unsigned int count)2585 int CDECL _write(int fd, const void* buf, unsigned int count)
2586 {
2587     DWORD num_written;
2588     ioinfo *info = get_ioinfo(fd);
2589     HANDLE hand = info->handle;
2590 
2591     /* Don't trace small writes, it gets *very* annoying */
2592 #if 0
2593     if (count > 32)
2594         TRACE(":fd (%d) handle (%d) buf (%p) len (%d)\n",fd,hand,buf,count);
2595 #endif
2596     if (hand == INVALID_HANDLE_VALUE)
2597     {
2598         *_errno() = EBADF;
2599         release_ioinfo(info);
2600         return -1;
2601     }
2602 
2603     if (((info->exflag&EF_UTF8) || (info->exflag&EF_UTF16)) && count&1)
2604     {
2605         *_errno() = EINVAL;
2606         release_ioinfo(info);
2607         return -1;
2608     }
2609 
2610     /* If appending, go to EOF */
2611     if (info->wxflag & WX_APPEND)
2612         _lseek(fd, 0, FILE_END);
2613 
2614     if (!(info->wxflag & WX_TEXT))
2615     {
2616         if (WriteFile(hand, buf, count, &num_written, NULL)
2617                 &&  (num_written == count))
2618         {
2619             release_ioinfo(info);
2620             return num_written;
2621         }
2622         TRACE("WriteFile (fd %d, hand %p) failed-last error (%d)\n", fd,
2623                 hand, GetLastError());
2624         *_errno() = ENOSPC;
2625     }
2626     else
2627     {
2628         unsigned int i, j, nr_lf, size;
2629         char *p = NULL;
2630         const char *q;
2631         const char *s = buf, *buf_start = buf;
2632 
2633         if (!(info->exflag & (EF_UTF8|EF_UTF16)))
2634         {
2635             /* find number of \n */
2636             for (nr_lf=0, i=0; i<count; i++)
2637                 if (s[i] == '\n')
2638                     nr_lf++;
2639             if (nr_lf)
2640             {
2641                 size = count+nr_lf;
2642                 if ((q = p = malloc(size)))
2643                 {
2644                     for (s = buf, i = 0, j = 0; i < count; i++)
2645                     {
2646                         if (s[i] == '\n')
2647                             p[j++] = '\r';
2648                         p[j++] = s[i];
2649                     }
2650                 }
2651                 else
2652                 {
2653                     FIXME("Malloc failed\n");
2654                     nr_lf = 0;
2655                     size = count;
2656                     q = buf;
2657                 }
2658             }
2659             else
2660             {
2661                 size = count;
2662                 q = buf;
2663             }
2664         }
2665         else if (info->exflag & EF_UTF16)
2666         {
2667             for (nr_lf=0, i=0; i<count; i+=2)
2668                 if (s[i]=='\n' && s[i+1]==0)
2669                     nr_lf += 2;
2670             if (nr_lf)
2671             {
2672                 size = count+nr_lf;
2673                 if ((q = p = malloc(size)))
2674                 {
2675                     for (s=buf, i=0, j=0; i<count; i++)
2676                     {
2677                         if (s[i]=='\n' && s[i+1]==0)
2678                         {
2679                             p[j++] = '\r';
2680                             p[j++] = 0;
2681                         }
2682                         p[j++] = s[i++];
2683                         p[j++] = s[i];
2684                     }
2685                 }
2686                 else
2687                 {
2688                     FIXME("Malloc failed\n");
2689                     nr_lf = 0;
2690                     size = count;
2691                     q = buf;
2692                 }
2693             }
2694             else
2695             {
2696                 size = count;
2697                 q = buf;
2698             }
2699         }
2700         else
2701         {
2702             DWORD conv_len;
2703 
2704             for(nr_lf=0, i=0; i<count; i+=2)
2705                 if (s[i]=='\n' && s[i+1]==0)
2706                     nr_lf++;
2707 
2708             conv_len = WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)buf, count/2, NULL, 0, NULL, NULL);
2709             if(!conv_len) {
2710                 _dosmaperr(GetLastError());
2711                 free(p);
2712                 release_ioinfo(info);
2713                 return -1;
2714             }
2715 
2716             size = conv_len+nr_lf;
2717             if((p = malloc(count+nr_lf*2+size)))
2718             {
2719                 for (s=buf, i=0, j=0; i<count; i++)
2720                 {
2721                     if (s[i]=='\n' && s[i+1]==0)
2722                     {
2723                         p[j++] = '\r';
2724                         p[j++] = 0;
2725                     }
2726                     p[j++] = s[i++];
2727                     p[j++] = s[i];
2728                 }
2729                 q = p+count+nr_lf*2;
2730                 WideCharToMultiByte(CP_UTF8, 0, (WCHAR*)p, count/2+nr_lf,
2731                         p+count+nr_lf*2, conv_len+nr_lf, NULL, NULL);
2732             }
2733             else
2734             {
2735                 FIXME("Malloc failed\n");
2736                 nr_lf = 0;
2737                 size = count;
2738                 q = buf;
2739             }
2740         }
2741 
2742         if (!WriteFile(hand, q, size, &num_written, NULL))
2743             num_written = -1;
2744         release_ioinfo(info);
2745         if(p)
2746             free(p);
2747         if (num_written != size)
2748         {
2749             TRACE("WriteFile (fd %d, hand %p) failed-last error (%d), num_written %d\n",
2750                     fd, hand, GetLastError(), num_written);
2751             *_errno() = ENOSPC;
2752             return s - buf_start;
2753         }
2754         return count;
2755     }
2756 
2757     release_ioinfo(info);
2758     return -1;
2759 }
2760 
2761 /*********************************************************************
2762  *		_putw (MSVCRT.@)
2763  */
_putw(int val,FILE * file)2764 int CDECL _putw(int val, FILE* file)
2765 {
2766   int len;
2767 
2768   _lock_file(file);
2769   len = _write(file->_file, &val, sizeof(val));
2770   if (len == sizeof(val)) {
2771     _unlock_file(file);
2772     return val;
2773   }
2774 
2775   file->_flag |= _IOERR;
2776   _unlock_file(file);
2777   return EOF;
2778 }
2779 
2780 /*********************************************************************
2781  *		fclose (MSVCRT.@)
2782  */
fclose(FILE * file)2783 int CDECL fclose(FILE* file)
2784 {
2785   int r, flag;
2786 
2787   if (!MSVCRT_CHECK_PMT(file != NULL)) return EOF;
2788 
2789   _lock_file(file);
2790   flag = file->_flag;
2791   free(file->_tmpfname);
2792   file->_tmpfname = NULL;
2793   /* flush stdio buffers */
2794   if(file->_flag & _IOWRT)
2795       fflush(file);
2796   if(file->_flag & _IOMYBUF)
2797       free(file->_base);
2798 
2799   r=_close(file->_file);
2800 
2801   file->_flag = 0;
2802   _unlock_file(file);
2803   if(file<_iob || file>=_iob+_IOB_ENTRIES)
2804       DeleteCriticalSection(&((file_crit*)file)->crit);
2805 
2806   if(file == msvcrt_get_file(MSVCRT_stream_idx-1)) {
2807     while(MSVCRT_stream_idx>3 && !file->_flag) {
2808       MSVCRT_stream_idx--;
2809       file = msvcrt_get_file(MSVCRT_stream_idx-1);
2810     }
2811   }
2812 
2813   return ((r == -1) || (flag & _IOERR) ? EOF : 0);
2814 }
2815 
2816 /*********************************************************************
2817  *		feof (MSVCRT.@)
2818  */
feof(FILE * file)2819 int CDECL feof(FILE* file)
2820 {
2821     return file->_flag & _IOEOF;
2822 }
2823 
2824 /*********************************************************************
2825  *		ferror (MSVCRT.@)
2826  */
ferror(FILE * file)2827 int CDECL ferror(FILE* file)
2828 {
2829     return file->_flag & _IOERR;
2830 }
2831 
2832 /*********************************************************************
2833  *		_filbuf (MSVCRT.@)
2834  */
_filbuf(FILE * file)2835 int CDECL _filbuf(FILE* file)
2836 {
2837     unsigned char c;
2838     _lock_file(file);
2839 
2840     if(file->_flag & _IOSTRG) {
2841         _unlock_file(file);
2842         return EOF;
2843     }
2844 
2845     /* Allocate buffer if needed */
2846     if(!(file->_flag & (_IONBF | _IOMYBUF | _USERBUF)))
2847         msvcrt_alloc_buffer(file);
2848 
2849     if(!(file->_flag & _IOREAD)) {
2850         if(file->_flag & _IORW)
2851             file->_flag |= _IOREAD;
2852         else {
2853             _unlock_file(file);
2854             return EOF;
2855         }
2856     }
2857 
2858     if(!(file->_flag & (_IOMYBUF | _USERBUF))) {
2859         int r;
2860         if ((r = _read(file->_file,&c,1)) != 1) {
2861             file->_flag |= (r == 0) ? _IOEOF : _IOERR;
2862             _unlock_file(file);
2863             return EOF;
2864         }
2865 
2866         _unlock_file(file);
2867         return c;
2868     } else {
2869         file->_cnt = _read(file->_file, file->_base, file->_bufsiz);
2870         if(file->_cnt<=0) {
2871             file->_flag |= (file->_cnt == 0) ? _IOEOF : _IOERR;
2872             file->_cnt = 0;
2873             _unlock_file(file);
2874             return EOF;
2875         }
2876 
2877         file->_cnt--;
2878         file->_ptr = file->_base+1;
2879         c = *(unsigned char *)file->_base;
2880         _unlock_file(file);
2881         return c;
2882     }
2883 }
2884 
2885 /*********************************************************************
2886  *		fgetc (MSVCRT.@)
2887  */
fgetc(FILE * file)2888 int CDECL fgetc(FILE* file)
2889 {
2890   unsigned char *i;
2891   unsigned int j;
2892 
2893   _lock_file(file);
2894   if (file->_cnt>0) {
2895     file->_cnt--;
2896     i = (unsigned char *)file->_ptr++;
2897     j = *i;
2898   } else
2899     j = _filbuf(file);
2900 
2901   _unlock_file(file);
2902   return j;
2903 }
2904 
2905 /*********************************************************************
2906  *		_fgetchar (MSVCRT.@)
2907  */
_fgetchar(void)2908 int CDECL _fgetchar(void)
2909 {
2910   return fgetc(stdin);
2911 }
2912 
2913 /*********************************************************************
2914  *		fgets (MSVCRT.@)
2915  */
fgets(char * s,int size,FILE * file)2916 char * CDECL fgets(char *s, int size, FILE* file)
2917 {
2918   int    cc = EOF;
2919   char * buf_start = s;
2920 
2921   TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
2922 	file,file->_file,s,size);
2923 
2924   _lock_file(file);
2925 
2926   while ((size >1) && (cc = fgetc(file)) != EOF && cc != '\n')
2927     {
2928       *s++ = (char)cc;
2929       size --;
2930     }
2931   if ((cc == EOF) && (s == buf_start)) /* If nothing read, return 0*/
2932   {
2933     TRACE(":nothing read\n");
2934     _unlock_file(file);
2935     return NULL;
2936   }
2937   if ((cc != EOF) && (size > 1))
2938     *s++ = cc;
2939   *s = '\0';
2940   TRACE(":got %s\n", debugstr_a(buf_start));
2941   _unlock_file(file);
2942   return buf_start;
2943 }
2944 
2945 /*********************************************************************
2946  *		fgetwc (MSVCRT.@)
2947  */
fgetwc(FILE * file)2948 wint_t CDECL fgetwc(FILE* file)
2949 {
2950     wint_t ret;
2951     int ch;
2952 
2953     _lock_file(file);
2954 
2955     if((get_ioinfo_nolock(file->_file)->exflag & (EF_UTF8 | EF_UTF16))
2956             || !(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) {
2957         char *p;
2958 
2959         for(p=(char*)&ret; (wint_t*)p<&ret+1; p++) {
2960             ch = fgetc(file);
2961             if(ch == EOF) {
2962                 ret = WEOF;
2963                 break;
2964             }
2965             *p = (char)ch;
2966         }
2967     }else {
2968         char mbs[MB_LEN_MAX];
2969         int len = 0;
2970 
2971         ch = fgetc(file);
2972         if(ch != EOF) {
2973             mbs[0] = (char)ch;
2974             if(isleadbyte((unsigned char)mbs[0])) {
2975                 ch = fgetc(file);
2976                 if(ch != EOF) {
2977                     mbs[1] = (char)ch;
2978                     len = 2;
2979                 }
2980             }else {
2981                 len = 1;
2982             }
2983         }
2984 
2985         if(!len || mbtowc(&ret, mbs, len)==-1)
2986             ret = WEOF;
2987     }
2988 
2989     _unlock_file(file);
2990     return ret;
2991 }
2992 
2993 /*********************************************************************
2994  *		_getw (MSVCRT.@)
2995  */
_getw(FILE * file)2996 int CDECL _getw(FILE* file)
2997 {
2998   char *ch;
2999   int i, k;
3000   unsigned int j;
3001   ch = (char *)&i;
3002 
3003   _lock_file(file);
3004   for (j=0; j<sizeof(int); j++) {
3005     k = fgetc(file);
3006     if (k == EOF) {
3007       file->_flag |= _IOEOF;
3008       _unlock_file(file);
3009       return EOF;
3010     }
3011     ch[j] = k;
3012   }
3013 
3014   _unlock_file(file);
3015   return i;
3016 }
3017 
3018 /*********************************************************************
3019  *		getwc (MSVCRT.@)
3020  */
getwc(FILE * file)3021 wint_t CDECL getwc(FILE* file)
3022 {
3023   return fgetwc(file);
3024 }
3025 
3026 /*********************************************************************
3027  *		_fgetwchar (MSVCRT.@)
3028  */
_fgetwchar(void)3029 wint_t CDECL _fgetwchar(void)
3030 {
3031   return fgetwc(stdin);
3032 }
3033 
3034 /*********************************************************************
3035  *		getwchar (MSVCRT.@)
3036  */
getwchar(void)3037 wint_t CDECL getwchar(void)
3038 {
3039   return _fgetwchar();
3040 }
3041 
3042 /*********************************************************************
3043  *              fgetws (MSVCRT.@)
3044  */
fgetws(wchar_t * s,int size,FILE * file)3045 wchar_t * CDECL fgetws(wchar_t *s, int size, FILE* file)
3046 {
3047   int    cc = WEOF;
3048   wchar_t * buf_start = s;
3049 
3050   TRACE(":file(%p) fd (%d) str (%p) len (%d)\n",
3051         file,file->_file,s,size);
3052 
3053   _lock_file(file);
3054 
3055   while ((size >1) && (cc = fgetwc(file)) != WEOF && cc != '\n')
3056     {
3057       *s++ = (char)cc;
3058       size --;
3059     }
3060   if ((cc == WEOF) && (s == buf_start)) /* If nothing read, return 0*/
3061   {
3062     TRACE(":nothing read\n");
3063     _unlock_file(file);
3064     return NULL;
3065   }
3066   if ((cc != WEOF) && (size > 1))
3067     *s++ = cc;
3068   *s = 0;
3069   TRACE(":got %s\n", debugstr_w(buf_start));
3070   _unlock_file(file);
3071   return buf_start;
3072 }
3073 
3074 /*********************************************************************
3075  *		fwrite (MSVCRT.@)
3076  */
fwrite(const void * ptr,size_t size,size_t nmemb,FILE * file)3077 size_t CDECL fwrite(const void *ptr, size_t size, size_t nmemb, FILE* file)
3078 {
3079     size_t wrcnt=size * nmemb;
3080     int written = 0;
3081     if (size == 0)
3082         return 0;
3083 
3084     _lock_file(file);
3085 
3086     while(wrcnt) {
3087 #ifndef __REACTOS__
3088         if(file->_cnt < 0) {
3089             WARN("negative file->_cnt value in %p\n", file);
3090             file->_flag |= MSVCRT__IOERR;
3091             break;
3092         } else
3093 #endif
3094         if(file->_cnt) {
3095             int pcnt=(file->_cnt>wrcnt)? wrcnt: file->_cnt;
3096             memcpy(file->_ptr, ptr, pcnt);
3097             file->_cnt -= pcnt;
3098             file->_ptr += pcnt;
3099             written += pcnt;
3100             wrcnt -= pcnt;
3101             ptr = (const char*)ptr + pcnt;
3102         } else if((file->_flag & _IONBF)
3103                 || ((file->_flag & (_IOMYBUF | _USERBUF)) && wrcnt >= file->_bufsiz)
3104                 || (!(file->_flag & (_IOMYBUF | _USERBUF)) && wrcnt >= MSVCRT_INTERNAL_BUFSIZ)) {
3105             size_t pcnt;
3106             int bufsiz;
3107 
3108             if(file->_flag & _IONBF)
3109                 bufsiz = 1;
3110             else if(!(file->_flag & (_IOMYBUF | _USERBUF)))
3111                 bufsiz = MSVCRT_INTERNAL_BUFSIZ;
3112             else
3113                 bufsiz = file->_bufsiz;
3114 
3115             pcnt = (wrcnt / bufsiz) * bufsiz;
3116 
3117             if(msvcrt_flush_buffer(file) == EOF)
3118                 break;
3119 
3120             if(_write(file->_file, ptr, pcnt) <= 0) {
3121                 file->_flag |= _IOERR;
3122                 break;
3123             }
3124             written += pcnt;
3125             wrcnt -= pcnt;
3126             ptr = (const char*)ptr + pcnt;
3127         } else {
3128             if(_flsbuf(*(const char*)ptr, file) == EOF)
3129                 break;
3130             written++;
3131             wrcnt--;
3132             ptr = (const char*)ptr + 1;
3133         }
3134     }
3135 
3136     _unlock_file(file);
3137     return written / size;
3138 }
3139 
3140 /*********************************************************************
3141  *		fputwc (MSVCRT.@)
3142  * FORKED for ReactOS, don't sync with Wine!
3143  * References:
3144  *   - http://jira.reactos.org/browse/CORE-6495
3145  *   - http://bugs.winehq.org/show_bug.cgi?id=8598
3146  */
fputwc(wchar_t c,FILE * stream)3147 wint_t CDECL fputwc(wchar_t c, FILE* stream)
3148 {
3149     /* If this is a real file stream (and not some temporary one for
3150        sprintf-like functions), check whether it is opened in text mode.
3151        In this case, we have to perform an implicit conversion to ANSI. */
3152     if (!(stream->_flag & _IOSTRG) && get_ioinfo_nolock(stream->_file)->wxflag & WX_TEXT)
3153     {
3154         /* Convert to multibyte in text mode */
3155         char mbc[MB_LEN_MAX];
3156         int mb_return;
3157 
3158         mb_return = wctomb(mbc, c);
3159 
3160         if(mb_return == -1)
3161             return WEOF;
3162 
3163         /* Output all characters */
3164         if (fwrite(mbc, mb_return, 1, stream) != 1)
3165             return WEOF;
3166     }
3167     else
3168     {
3169         if (fwrite(&c, sizeof(c), 1, stream) != 1)
3170             return WEOF;
3171     }
3172 
3173     return c;
3174 }
3175 
3176 /*********************************************************************
3177  *		_fputwchar (MSVCRT.@)
3178  */
_fputwchar(wint_t wc)3179 wint_t CDECL _fputwchar(wint_t wc)
3180 {
3181   return fputwc(wc, stdout);
3182 }
3183 
3184 /*********************************************************************
3185  *		_wfsopen (MSVCRT.@)
3186  */
_wfsopen(const wchar_t * path,const wchar_t * mode,int share)3187 FILE * CDECL _wfsopen(const wchar_t *path, const wchar_t *mode, int share)
3188 {
3189   FILE* file;
3190   int open_flags, stream_flags, fd;
3191 
3192   TRACE("(%s,%s)\n", debugstr_w(path), debugstr_w(mode));
3193 
3194   /* map mode string to open() flags. "man fopen" for possibilities. */
3195   if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1)
3196       return NULL;
3197 
3198   LOCK_FILES();
3199   fd = _wsopen(path, open_flags, share, _S_IREAD | _S_IWRITE);
3200   if (fd < 0)
3201     file = NULL;
3202   else if ((file = msvcrt_alloc_fp()) && msvcrt_init_fp(file, fd, stream_flags)
3203    != -1)
3204     TRACE(":fd (%d) mode (%s) FILE* (%p)\n", fd, debugstr_w(mode), file);
3205   else if (file)
3206   {
3207     file->_flag = 0;
3208     file = NULL;
3209   }
3210 
3211   TRACE(":got (%p)\n",file);
3212   if (fd >= 0 && !file)
3213     _close(fd);
3214   UNLOCK_FILES();
3215   return file;
3216 }
3217 
3218 /*********************************************************************
3219  *		_fsopen (MSVCRT.@)
3220  */
_fsopen(const char * path,const char * mode,int share)3221 FILE * CDECL _fsopen(const char *path, const char *mode, int share)
3222 {
3223     FILE *ret;
3224     wchar_t *pathW = NULL, *modeW = NULL;
3225 
3226     if (path && !(pathW = msvcrt_wstrdupa(path))) {
3227         _invalid_parameter(NULL, NULL, NULL, 0, 0);
3228         *_errno() = EINVAL;
3229         return NULL;
3230     }
3231     if (mode && !(modeW = msvcrt_wstrdupa(mode)))
3232     {
3233         free(pathW);
3234         _invalid_parameter(NULL, NULL, NULL, 0, 0);
3235         *_errno() = EINVAL;
3236         return NULL;
3237     }
3238 
3239     ret = _wfsopen(pathW, modeW, share);
3240 
3241     free(pathW);
3242     free(modeW);
3243     return ret;
3244 }
3245 
3246 /*********************************************************************
3247  *		fopen (MSVCRT.@)
3248  */
fopen(const char * path,const char * mode)3249 FILE * CDECL fopen(const char *path, const char *mode)
3250 {
3251     return _fsopen( path, mode, _SH_DENYNO );
3252 }
3253 
3254 /*********************************************************************
3255  *              fopen_s (MSVCRT.@)
3256  */
fopen_s(FILE ** pFile,const char * filename,const char * mode)3257 int CDECL fopen_s(FILE** pFile,
3258         const char *filename, const char *mode)
3259 {
3260     if (!MSVCRT_CHECK_PMT(pFile != NULL)) return EINVAL;
3261     if (!MSVCRT_CHECK_PMT(filename != NULL)) return EINVAL;
3262     if (!MSVCRT_CHECK_PMT(mode != NULL)) return EINVAL;
3263 
3264     *pFile = fopen(filename, mode);
3265 
3266     if(!*pFile)
3267         return *_errno();
3268     return 0;
3269 }
3270 
3271 /*********************************************************************
3272  *		_wfopen (MSVCRT.@)
3273  */
_wfopen(const wchar_t * path,const wchar_t * mode)3274 FILE * CDECL _wfopen(const wchar_t *path, const wchar_t *mode)
3275 {
3276     return _wfsopen( path, mode, _SH_DENYNO );
3277 }
3278 
3279 /*********************************************************************
3280  *		_wfopen_s (MSVCRT.@)
3281  */
_wfopen_s(FILE ** pFile,const wchar_t * filename,const wchar_t * mode)3282 int CDECL _wfopen_s(FILE** pFile, const wchar_t *filename,
3283         const wchar_t *mode)
3284 {
3285     if (!MSVCRT_CHECK_PMT(pFile != NULL) || !MSVCRT_CHECK_PMT(filename != NULL) ||
3286         !MSVCRT_CHECK_PMT(mode != NULL)) {
3287         *_errno() = EINVAL;
3288         return EINVAL;
3289     }
3290 
3291     *pFile = _wfopen(filename, mode);
3292 
3293     if(!*pFile)
3294         return *_errno();
3295     return 0;
3296 }
3297 
3298 /* fputc calls _flsbuf which calls fputc */
3299 int CDECL _flsbuf(int c, FILE* file);
3300 
3301 /*********************************************************************
3302  *		fputc (MSVCRT.@)
3303  */
fputc(int c,FILE * file)3304 int CDECL fputc(int c, FILE* file)
3305 {
3306   int res;
3307 
3308   _lock_file(file);
3309   if(file->_cnt>0) {
3310     *file->_ptr++=c;
3311     file->_cnt--;
3312     if (c == '\n')
3313     {
3314       res = msvcrt_flush_buffer(file);
3315       _unlock_file(file);
3316       return res ? res : c;
3317     }
3318     else {
3319       _unlock_file(file);
3320       return c & 0xff;
3321     }
3322   } else {
3323     res = _flsbuf(c, file);
3324     _unlock_file(file);
3325     return res;
3326   }
3327 }
3328 
3329 /*********************************************************************
3330  *		_fputchar (MSVCRT.@)
3331  */
_fputchar(int c)3332 int CDECL _fputchar(int c)
3333 {
3334   return fputc(c, stdout);
3335 }
3336 
3337 /*********************************************************************
3338  *		fread (MSVCRT.@)
3339  */
fread(void * ptr,size_t size,size_t nmemb,FILE * file)3340 size_t CDECL fread(void *ptr, size_t size, size_t nmemb, FILE* file)
3341 {
3342   size_t rcnt=size * nmemb;
3343   size_t read=0;
3344   size_t pread=0;
3345 
3346   if(!rcnt)
3347 	return 0;
3348 
3349   _lock_file(file);
3350 
3351   /* first buffered data */
3352   if(file->_cnt>0) {
3353 	int pcnt= (rcnt>file->_cnt)? file->_cnt:rcnt;
3354 	memcpy(ptr, file->_ptr, pcnt);
3355 	file->_cnt -= pcnt;
3356 	file->_ptr += pcnt;
3357 	read += pcnt ;
3358 	rcnt -= pcnt ;
3359         ptr = (char*)ptr + pcnt;
3360   } else if(!(file->_flag & _IOREAD )) {
3361 	if(file->_flag & _IORW) {
3362 		file->_flag |= _IOREAD;
3363 	} else {
3364         _unlock_file(file);
3365         return 0;
3366     }
3367   }
3368 
3369   if(rcnt>0 && !(file->_flag & (_IONBF | _IOMYBUF | _USERBUF)))
3370       msvcrt_alloc_buffer(file);
3371 
3372   while(rcnt>0)
3373   {
3374     int i;
3375     if (!file->_cnt && rcnt<BUFSIZ && (file->_flag & (_IOMYBUF | _USERBUF))) {
3376       file->_cnt = _read(file->_file, file->_base, file->_bufsiz);
3377       file->_ptr = file->_base;
3378       i = (file->_cnt<rcnt) ? file->_cnt : rcnt;
3379       /* If the buffer fill reaches eof but fread wouldn't, clear eof. */
3380       if (i > 0 && i < file->_cnt) {
3381         get_ioinfo_nolock(file->_file)->wxflag &= ~WX_ATEOF;
3382         file->_flag &= ~_IOEOF;
3383       }
3384       if (i > 0) {
3385         memcpy(ptr, file->_ptr, i);
3386         file->_cnt -= i;
3387         file->_ptr += i;
3388       }
3389     } else if (rcnt > INT_MAX) {
3390       i = _read(file->_file, ptr, INT_MAX);
3391     } else if (rcnt < BUFSIZ) {
3392       i = _read(file->_file, ptr, rcnt);
3393     } else {
3394       i = _read(file->_file, ptr, rcnt - BUFSIZ/2);
3395     }
3396     pread += i;
3397     rcnt -= i;
3398     ptr = (char *)ptr+i;
3399     /* expose feof condition in the flags
3400      * MFC tests file->_flag for feof, and doesn't call feof())
3401      */
3402     if (get_ioinfo_nolock(file->_file)->wxflag & WX_ATEOF)
3403         file->_flag |= _IOEOF;
3404     else if (i == -1)
3405     {
3406         file->_flag |= _IOERR;
3407         pread = 0;
3408         rcnt = 0;
3409     }
3410     if (i < 1) break;
3411   }
3412   read+=pread;
3413   _unlock_file(file);
3414   return read / size;
3415 }
3416 
3417 /*********************************************************************
3418  *		_wfreopen (MSVCRT.@)
3419  *
3420  */
_wfreopen(const wchar_t * path,const wchar_t * mode,FILE * file)3421 FILE* CDECL _wfreopen(const wchar_t *path, const wchar_t *mode, FILE* file)
3422 {
3423   int open_flags, stream_flags, fd;
3424 
3425   TRACE(":path (%s) mode (%s) file (%p) fd (%d)\n", debugstr_w(path), debugstr_w(mode), file, file ? file->_file : -1);
3426 
3427   LOCK_FILES();
3428   if (!file || ((fd = file->_file) < 0))
3429     file = NULL;
3430   else
3431   {
3432     fclose(file);
3433     /* map mode string to open() flags. "man fopen" for possibilities. */
3434     if (msvcrt_get_flags(mode, &open_flags, &stream_flags) == -1)
3435       file = NULL;
3436     else
3437     {
3438       fd = _wopen(path, open_flags, _S_IREAD | _S_IWRITE);
3439       if (fd < 0)
3440         file = NULL;
3441       else if (msvcrt_init_fp(file, fd, stream_flags) == -1)
3442       {
3443           file->_flag = 0;
3444           WARN(":failed-last error (%d)\n",GetLastError());
3445           _dosmaperr(GetLastError());
3446           file = NULL;
3447       }
3448     }
3449   }
3450   UNLOCK_FILES();
3451   return file;
3452 }
3453 
3454 /*********************************************************************
3455  *      freopen (MSVCRT.@)
3456  *
3457  */
freopen(const char * path,const char * mode,FILE * file)3458 FILE* CDECL freopen(const char *path, const char *mode, FILE* file)
3459 {
3460     FILE *ret;
3461     wchar_t *pathW = NULL, *modeW = NULL;
3462 
3463     if (path && !(pathW = msvcrt_wstrdupa(path))) return NULL;
3464     if (mode && !(modeW = msvcrt_wstrdupa(mode)))
3465     {
3466         free(pathW);
3467         return NULL;
3468     }
3469 
3470     ret = _wfreopen(pathW, modeW, file);
3471 
3472     free(pathW);
3473     free(modeW);
3474     return ret;
3475 }
3476 
3477 /*********************************************************************
3478  *		fsetpos (MSVCRT.@)
3479  */
fsetpos(FILE * file,const fpos_t * pos)3480 int CDECL fsetpos(FILE* file, const fpos_t *pos)
3481 {
3482   int ret;
3483 
3484   _lock_file(file);
3485   /* Note that all this has been lifted 'as is' from fseek */
3486   if(file->_flag & _IOWRT)
3487 	msvcrt_flush_buffer(file);
3488 
3489   /* Discard buffered input */
3490   file->_cnt = 0;
3491   file->_ptr = file->_base;
3492 
3493   /* Reset direction of i/o */
3494   if(file->_flag & _IORW) {
3495         file->_flag &= ~(_IOREAD|_IOWRT);
3496   }
3497 
3498   ret = (_lseeki64(file->_file,*pos,SEEK_SET) == -1) ? -1 : 0;
3499   _unlock_file(file);
3500   return ret;
3501 }
3502 
3503 /*********************************************************************
3504  *		_ftelli64 (MSVCRT.@)
3505  */
_ftelli64(FILE * file)3506 __int64 CDECL _ftelli64(FILE* file)
3507 {
3508     __int64 pos;
3509 
3510     _lock_file(file);
3511     pos = _telli64(file->_file);
3512     if(pos == -1) {
3513         _unlock_file(file);
3514         return -1;
3515     }
3516     if(file->_flag & (_IOMYBUF | _USERBUF))  {
3517         if(file->_flag & _IOWRT) {
3518             pos += file->_ptr - file->_base;
3519 
3520             if(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT) {
3521                 char *p;
3522 
3523                 for(p=file->_base; p<file->_ptr; p++)
3524                     if(*p == '\n')
3525                         pos++;
3526             }
3527         } else if(!file->_cnt) { /* nothing to do */
3528         } else if(_lseeki64(file->_file, 0, SEEK_END)==pos) {
3529             int i;
3530 
3531             pos -= file->_cnt;
3532             if(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT) {
3533                 for(i=0; i<file->_cnt; i++)
3534                     if(file->_ptr[i] == '\n')
3535                         pos--;
3536             }
3537         } else {
3538             char *p;
3539 
3540             if(_lseeki64(file->_file, pos, SEEK_SET) != pos) {
3541                 _unlock_file(file);
3542                 return -1;
3543             }
3544 
3545             pos -= file->_bufsiz;
3546             pos += file->_ptr - file->_base;
3547 
3548             if(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT) {
3549                 if(get_ioinfo_nolock(file->_file)->wxflag & WX_READNL)
3550                     pos--;
3551 
3552                 for(p=file->_base; p<file->_ptr; p++)
3553                     if(*p == '\n')
3554                         pos++;
3555             }
3556         }
3557     }
3558 
3559     _unlock_file(file);
3560     return pos;
3561 }
3562 
3563 /*********************************************************************
3564  *		ftell (MSVCRT.@)
3565  */
ftell(FILE * file)3566 LONG CDECL ftell(FILE* file)
3567 {
3568   return (LONG)_ftelli64(file);
3569 }
3570 
3571 /*********************************************************************
3572  *		fgetpos (MSVCRT.@)
3573  */
fgetpos(FILE * file,fpos_t * pos)3574 int CDECL fgetpos(FILE* file, fpos_t *pos)
3575 {
3576     *pos = _ftelli64(file);
3577     if(*pos == -1)
3578         return -1;
3579     return 0;
3580 }
3581 
3582 /*********************************************************************
3583  *		fputs (MSVCRT.@)
3584  */
fputs(const char * s,FILE * file)3585 int CDECL fputs(const char *s, FILE* file)
3586 {
3587     size_t len = strlen(s);
3588     int ret;
3589 
3590     _lock_file(file);
3591     ret = fwrite(s, sizeof(*s), len, file) == len ? 0 : EOF;
3592     _unlock_file(file);
3593     return ret;
3594 }
3595 
3596 /*********************************************************************
3597  *		fputws (MSVCRT.@)
3598  */
fputws(const wchar_t * s,FILE * file)3599 int CDECL fputws(const wchar_t *s, FILE* file)
3600 {
3601     size_t i, len = strlenW(s);
3602     BOOL tmp_buf;
3603     int ret;
3604 
3605     _lock_file(file);
3606     if (!(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) {
3607         ret = fwrite(s,sizeof(*s),len,file) == len ? 0 : EOF;
3608         _unlock_file(file);
3609         return ret;
3610     }
3611 
3612     tmp_buf = add_std_buffer(file);
3613     for (i=0; i<len; i++) {
3614         if(fputwc(s[i], file) == WEOF) {
3615             if(tmp_buf) remove_std_buffer(file);
3616             _unlock_file(file);
3617             return WEOF;
3618         }
3619     }
3620 
3621     if(tmp_buf) remove_std_buffer(file);
3622     _unlock_file(file);
3623     return 0;
3624 }
3625 
3626 /*********************************************************************
3627  *		getchar (MSVCRT.@)
3628  */
getchar(void)3629 int CDECL getchar(void)
3630 {
3631   return fgetc(stdin);
3632 }
3633 
3634 /*********************************************************************
3635  *		getc (MSVCRT.@)
3636  */
getc(FILE * file)3637 int CDECL getc(FILE* file)
3638 {
3639   return fgetc(file);
3640 }
3641 
3642 /*********************************************************************
3643  *		gets (MSVCRT.@)
3644  */
gets(char * buf)3645 char * CDECL gets(char *buf)
3646 {
3647   int    cc;
3648   char * buf_start = buf;
3649 
3650   _lock_file(stdin);
3651   for(cc = fgetc(stdin); cc != EOF && cc != '\n';
3652       cc = fgetc(stdin))
3653   if(cc != '\r') *buf++ = (char)cc;
3654 
3655   *buf = '\0';
3656 
3657   TRACE("got '%s'\n", buf_start);
3658   _unlock_file(stdin);
3659   return buf_start;
3660 }
3661 
3662 /*********************************************************************
3663  *		_getws (MSVCRT.@)
3664  */
_getws(wchar_t * buf)3665 wchar_t* CDECL _getws(wchar_t* buf)
3666 {
3667     wint_t cc;
3668     wchar_t* ws = buf;
3669 
3670     _lock_file(stdin);
3671     for (cc = fgetwc(stdin); cc != WEOF && cc != '\n';
3672          cc = fgetwc(stdin))
3673     {
3674         if (cc != '\r')
3675             *buf++ = (wchar_t)cc;
3676     }
3677     *buf = '\0';
3678 
3679     TRACE("got %s\n", debugstr_w(ws));
3680     _unlock_file(stdin);
3681     return ws;
3682 }
3683 
3684 /*********************************************************************
3685  *		putc (MSVCRT.@)
3686  */
putc(int c,FILE * file)3687 int CDECL putc(int c, FILE* file)
3688 {
3689   return fputc(c, file);
3690 }
3691 
3692 /*********************************************************************
3693  *		putchar (MSVCRT.@)
3694  */
putchar(int c)3695 int CDECL putchar(int c)
3696 {
3697   return fputc(c, stdout);
3698 }
3699 
3700 /*********************************************************************
3701  *		_putwch (MSVCRT.@)
3702  */
_putwch(wchar_t c)3703 wint_t CDECL _putwch(wchar_t c)
3704 {
3705   return fputwc(c, stdout);
3706 }
3707 
3708 /*********************************************************************
3709  *		puts (MSVCRT.@)
3710  */
puts(const char * s)3711 int CDECL puts(const char *s)
3712 {
3713     size_t len = strlen(s);
3714     int ret;
3715 
3716     _lock_file(stdout);
3717     if(fwrite(s, sizeof(*s), len, stdout) != len) {
3718         _unlock_file(stdout);
3719         return EOF;
3720     }
3721 
3722     ret = fwrite("\n",1,1,stdout) == 1 ? 0 : EOF;
3723     _unlock_file(stdout);
3724     return ret;
3725 }
3726 
3727 /*********************************************************************
3728  *		_putws (MSVCRT.@)
3729  */
_putws(const wchar_t * s)3730 int CDECL _putws(const wchar_t *s)
3731 {
3732     static const wchar_t nl = '\n';
3733     size_t len = strlenW(s);
3734     int ret;
3735 
3736     _lock_file(stdout);
3737     if(fwrite(s, sizeof(*s), len, stdout) != len) {
3738         _unlock_file(stdout);
3739         return EOF;
3740     }
3741 
3742     ret = fwrite(&nl,sizeof(nl),1,stdout) == 1 ? 0 : EOF;
3743     _unlock_file(stdout);
3744     return ret;
3745 }
3746 
3747 /*********************************************************************
3748  *		remove (MSVCRT.@)
3749  */
remove(const char * path)3750 int CDECL remove(const char *path)
3751 {
3752   TRACE("(%s)\n",path);
3753   if (DeleteFileA(path))
3754     return 0;
3755   TRACE(":failed (%d)\n",GetLastError());
3756   _dosmaperr(GetLastError());
3757   return -1;
3758 }
3759 
3760 /*********************************************************************
3761  *		_wremove (MSVCRT.@)
3762  */
_wremove(const wchar_t * path)3763 int CDECL _wremove(const wchar_t *path)
3764 {
3765   TRACE("(%s)\n",debugstr_w(path));
3766   if (DeleteFileW(path))
3767     return 0;
3768   TRACE(":failed (%d)\n",GetLastError());
3769   _dosmaperr(GetLastError());
3770   return -1;
3771 }
3772 
3773 /*********************************************************************
3774  *		rename (MSVCRT.@)
3775  */
rename(const char * oldpath,const char * newpath)3776 int CDECL rename(const char *oldpath,const char *newpath)
3777 {
3778   TRACE(":from %s to %s\n",oldpath,newpath);
3779   if (MoveFileExA(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
3780     return 0;
3781   TRACE(":failed (%d)\n",GetLastError());
3782   _dosmaperr(GetLastError());
3783   return -1;
3784 }
3785 
3786 /*********************************************************************
3787  *		_wrename (MSVCRT.@)
3788  */
_wrename(const wchar_t * oldpath,const wchar_t * newpath)3789 int CDECL _wrename(const wchar_t *oldpath,const wchar_t *newpath)
3790 {
3791   TRACE(":from %s to %s\n",debugstr_w(oldpath),debugstr_w(newpath));
3792   if (MoveFileExW(oldpath, newpath, MOVEFILE_COPY_ALLOWED))
3793     return 0;
3794   TRACE(":failed (%d)\n",GetLastError());
3795   _dosmaperr(GetLastError());
3796   return -1;
3797 }
3798 
3799 /*********************************************************************
3800  *		setvbuf (MSVCRT.@)
3801  */
setvbuf(FILE * file,char * buf,int mode,size_t size)3802 int CDECL setvbuf(FILE* file, char *buf, int mode, size_t size)
3803 {
3804     if(!MSVCRT_CHECK_PMT(file != NULL)) return -1;
3805     if(!MSVCRT_CHECK_PMT(mode==_IONBF || mode==_IOFBF || mode==_IOLBF)) return -1;
3806     if(!MSVCRT_CHECK_PMT(mode==_IONBF || (size>=2 && size<=INT_MAX))) return -1;
3807 
3808     _lock_file(file);
3809 
3810     fflush(file);
3811     if(file->_flag & _IOMYBUF)
3812         free(file->_base);
3813     file->_flag &= ~(_IONBF | _IOMYBUF | _USERBUF);
3814     file->_cnt = 0;
3815 
3816     if(mode == _IONBF) {
3817         file->_flag |= _IONBF;
3818         file->_base = file->_ptr = (char*)&file->_charbuf;
3819         file->_bufsiz = 2;
3820     }else if(buf) {
3821         file->_base = file->_ptr = buf;
3822         file->_flag |= _USERBUF;
3823         file->_bufsiz = size;
3824     }else {
3825         file->_base = file->_ptr = malloc(size);
3826         if(!file->_base) {
3827             file->_bufsiz = 0;
3828             _unlock_file(file);
3829             return -1;
3830         }
3831 
3832         file->_flag |= _IOMYBUF;
3833         file->_bufsiz = size;
3834     }
3835     _unlock_file(file);
3836     return 0;
3837 }
3838 
3839 /*********************************************************************
3840  *		setbuf (MSVCRT.@)
3841  */
setbuf(FILE * file,char * buf)3842 void CDECL setbuf(FILE* file, char *buf)
3843 {
3844   setvbuf(file, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
3845 }
3846 
3847 /*********************************************************************
3848  *		tmpnam (MSVCRT.@)
3849  */
tmpnam(char * s)3850 char * CDECL tmpnam(char *s)
3851 {
3852   char tmpstr[16];
3853   char *p;
3854   int count, size;
3855 
3856   if (!s) {
3857     thread_data_t *data = msvcrt_get_thread_data();
3858 
3859     if(!data->tmpnam_buffer)
3860       data->tmpnam_buffer = malloc(MAX_PATH);
3861 
3862     s = data->tmpnam_buffer;
3863   }
3864 
3865   msvcrt_int_to_base32(GetCurrentProcessId(), tmpstr);
3866   p = s + sprintf(s, "\\s%s.", tmpstr);
3867   for (count = 0; count < TMP_MAX; count++)
3868   {
3869     size = msvcrt_int_to_base32(tmpnam_unique++, tmpstr);
3870     memcpy(p, tmpstr, size);
3871     p[size] = '\0';
3872     if (GetFileAttributesA(s) == INVALID_FILE_ATTRIBUTES &&
3873         GetLastError() == ERROR_FILE_NOT_FOUND)
3874       break;
3875   }
3876   return s;
3877 }
3878 
3879 /*********************************************************************
3880  *              _wtmpnam (MSVCRT.@)
3881  */
_wtmpnam(wchar_t * s)3882 wchar_t * CDECL _wtmpnam(wchar_t *s)
3883 {
3884     static const wchar_t format[] = {'\\','s','%','s','.',0};
3885     wchar_t tmpstr[16];
3886     wchar_t *p;
3887     int count, size;
3888     if (!s) {
3889         thread_data_t *data = msvcrt_get_thread_data();
3890 
3891         if(!data->wtmpnam_buffer)
3892             data->wtmpnam_buffer = malloc(sizeof(wchar_t[MAX_PATH]));
3893 
3894         s = data->wtmpnam_buffer;
3895     }
3896 
3897     msvcrt_int_to_base32_w(GetCurrentProcessId(), tmpstr);
3898     p = s + _snwprintf(s, MAX_PATH, format, tmpstr);
3899     for (count = 0; count < TMP_MAX; count++)
3900     {
3901         size = msvcrt_int_to_base32_w(tmpnam_unique++, tmpstr);
3902         memcpy(p, tmpstr, size*sizeof(wchar_t));
3903         p[size] = '\0';
3904         if (GetFileAttributesW(s) == INVALID_FILE_ATTRIBUTES &&
3905                 GetLastError() == ERROR_FILE_NOT_FOUND)
3906             break;
3907     }
3908     return s;
3909 }
3910 
3911 /*********************************************************************
3912  *		tmpfile (MSVCRT.@)
3913  */
tmpfile(void)3914 FILE* CDECL tmpfile(void)
3915 {
3916   char *filename = tmpnam(NULL);
3917   int fd;
3918   FILE* file = NULL;
3919 
3920   LOCK_FILES();
3921   fd = _open(filename, _O_CREAT | _O_BINARY | _O_RDWR | _O_TEMPORARY,
3922           _S_IREAD | _S_IWRITE);
3923   if (fd != -1 && (file = msvcrt_alloc_fp()))
3924   {
3925     if (msvcrt_init_fp(file, fd, _IORW) == -1)
3926     {
3927         file->_flag = 0;
3928         file = NULL;
3929     }
3930     else file->_tmpfname = _strdup(filename);
3931   }
3932 
3933   if(fd != -1 && !file)
3934       _close(fd);
3935   UNLOCK_FILES();
3936   return file;
3937 }
3938 
3939 /*********************************************************************
3940  *		ungetc (MSVCRT.@)
3941  */
ungetc(int c,FILE * file)3942 int CDECL ungetc(int c, FILE * file)
3943 {
3944     if(!MSVCRT_CHECK_PMT(file != NULL)) return EOF;
3945 
3946     if (c == EOF || !(file->_flag&_IOREAD ||
3947                 (file->_flag&_IORW && !(file->_flag&_IOWRT))))
3948         return EOF;
3949 
3950     _lock_file(file);
3951     if((!(file->_flag & (_IONBF | _IOMYBUF | _USERBUF))
3952                 && msvcrt_alloc_buffer(file))
3953             || (!file->_cnt && file->_ptr==file->_base))
3954         file->_ptr++;
3955 
3956     if(file->_ptr>file->_base) {
3957         file->_ptr--;
3958         if(file->_flag & _IOSTRG) {
3959             if(*file->_ptr != c) {
3960                 file->_ptr++;
3961                 _unlock_file(file);
3962                 return EOF;
3963             }
3964         }else {
3965             *file->_ptr = c;
3966         }
3967         file->_cnt++;
3968         clearerr(file);
3969         file->_flag |= _IOREAD;
3970         _unlock_file(file);
3971         return c;
3972     }
3973 
3974     _unlock_file(file);
3975     return EOF;
3976 }
3977 
3978 /*********************************************************************
3979  *              ungetwc (MSVCRT.@)
3980  */
ungetwc(wint_t wc,FILE * file)3981 wint_t CDECL ungetwc(wint_t wc, FILE * file)
3982 {
3983     wchar_t mwc = wc;
3984 
3985     if (wc == WEOF)
3986         return WEOF;
3987 
3988     _lock_file(file);
3989 
3990     if((get_ioinfo_nolock(file->_file)->exflag & (EF_UTF8 | EF_UTF16))
3991             || !(get_ioinfo_nolock(file->_file)->wxflag & WX_TEXT)) {
3992         unsigned char * pp = (unsigned char *)&mwc;
3993         int i;
3994 
3995         for(i=sizeof(wchar_t)-1;i>=0;i--) {
3996             if(pp[i] != ungetc(pp[i],file)) {
3997                 _unlock_file(file);
3998                 return WEOF;
3999             }
4000         }
4001     }else {
4002         char mbs[MB_LEN_MAX];
4003         int len;
4004 
4005         len = wctomb(mbs, mwc);
4006         if(len == -1) {
4007             _unlock_file(file);
4008             return WEOF;
4009         }
4010 
4011         for(len--; len>=0; len--) {
4012             if(mbs[len] != ungetc(mbs[len], file)) {
4013                 _unlock_file(file);
4014                 return WEOF;
4015             }
4016         }
4017     }
4018 
4019     _unlock_file(file);
4020     return mwc;
4021 }
4022 
4023 
4024 
4025 /*********************************************************************
4026  *		_getmaxstdio (MSVCRT.@)
4027  */
_getmaxstdio(void)4028 int CDECL _getmaxstdio(void)
4029 {
4030     return MSVCRT_max_streams;
4031 }
4032 
4033 /*********************************************************************
4034  *		_setmaxstdio (MSVCRT.@)
4035  */
_setmaxstdio(int newmax)4036 int CDECL _setmaxstdio(int newmax)
4037 {
4038     TRACE("%d\n", newmax);
4039 
4040     if(newmax<_IOB_ENTRIES || newmax>MSVCRT_MAX_FILES || newmax<MSVCRT_stream_idx)
4041         return -1;
4042 
4043     MSVCRT_max_streams = newmax;
4044     return MSVCRT_max_streams;
4045 }
4046