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