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