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