mfplat: Remove duplicated GUID entry from attribute tracing.
[wine/zf.git] / dlls / msvcrt / dir.c
blob91aaaf5ff18b894a73d766368a8232f2255ceb48
1 /*
2 * msvcrt.dll drive/directory functions
4 * Copyright 1996,1998 Marcus Meissner
5 * Copyright 1996 Jukka Iivonen
6 * Copyright 1997,2000 Uwe Bonnes
7 * Copyright 2000 Jon Griffiths
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #include <corecrt_io.h>
25 #include <mbctype.h>
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <direct.h>
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winternl.h"
33 #include "msvcrt.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
38 #undef _wfindfirst
39 #undef _wfindfirsti64
40 #undef _wfindnext
41 #undef _wfindnexti64
42 #undef _wfindfirst32
43 #undef _wfindnext32
44 #undef _wfindfirst64i32
45 #undef _wfindfirst64
46 #undef _wfindnext64i32
47 #undef _wfindnext64
49 #undef _findfirst
50 #undef _findfirsti64
51 #undef _findnext
52 #undef _findnexti64
53 #undef _findfirst32
54 #undef _findnext32
55 #undef _findfirst64i32
56 #undef _findfirst64
57 #undef _findnext64i32
58 #undef _findnext64
60 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata_t */
61 static void msvcrt_fttofd( const WIN32_FIND_DATAA *fd, struct _finddata_t* ft)
63 DWORD dw;
65 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
66 ft->attrib = 0;
67 else
68 ft->attrib = fd->dwFileAttributes;
70 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
71 ft->time_create = dw;
72 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
73 ft->time_access = dw;
74 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
75 ft->time_write = dw;
76 ft->size = fd->nFileSizeLow;
77 strcpy(ft->name, fd->cFileName);
80 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata32_t */
81 static void msvcrt_fttofd32( const WIN32_FIND_DATAA *fd, struct _finddata32_t* ft)
83 DWORD dw;
85 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
86 ft->attrib = 0;
87 else
88 ft->attrib = fd->dwFileAttributes;
90 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
91 ft->time_create = dw;
92 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
93 ft->time_access = dw;
94 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
95 ft->time_write = dw;
96 ft->size = fd->nFileSizeLow;
97 strcpy(ft->name, fd->cFileName);
100 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata_t */
101 static void msvcrt_wfttofd( const WIN32_FIND_DATAW *fd, struct _wfinddata_t* ft)
103 DWORD dw;
105 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
106 ft->attrib = 0;
107 else
108 ft->attrib = fd->dwFileAttributes;
110 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
111 ft->time_create = dw;
112 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
113 ft->time_access = dw;
114 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
115 ft->time_write = dw;
116 ft->size = fd->nFileSizeLow;
117 wcscpy(ft->name, fd->cFileName);
120 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata32_t */
121 static void msvcrt_wfttofd32(const WIN32_FIND_DATAW *fd, struct _wfinddata32_t* ft)
123 DWORD dw;
125 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
126 ft->attrib = 0;
127 else
128 ft->attrib = fd->dwFileAttributes;
130 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
131 ft->time_create = dw;
132 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
133 ft->time_access = dw;
134 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
135 ft->time_write = dw;
136 ft->size = fd->nFileSizeLow;
137 wcscpy(ft->name, fd->cFileName);
140 /* INTERNAL: Translate WIN32_FIND_DATAA to finddatai64_t */
141 static void msvcrt_fttofdi64( const WIN32_FIND_DATAA *fd, struct _finddatai64_t* ft)
143 DWORD dw;
145 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
146 ft->attrib = 0;
147 else
148 ft->attrib = fd->dwFileAttributes;
150 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
151 ft->time_create = dw;
152 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
153 ft->time_access = dw;
154 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
155 ft->time_write = dw;
156 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
157 strcpy(ft->name, fd->cFileName);
160 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata64_t */
161 static void msvcrt_fttofd64( const WIN32_FIND_DATAA *fd, struct _finddata64_t* ft)
163 DWORD dw;
165 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
166 ft->attrib = 0;
167 else
168 ft->attrib = fd->dwFileAttributes;
170 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
171 ft->time_create = dw;
172 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
173 ft->time_access = dw;
174 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
175 ft->time_write = dw;
176 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
177 strcpy(ft->name, fd->cFileName);
180 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata64_t */
181 static void msvcrt_wfttofd64( const WIN32_FIND_DATAW *fd, struct _wfinddata64_t* ft)
183 DWORD dw;
185 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
186 ft->attrib = 0;
187 else
188 ft->attrib = fd->dwFileAttributes;
190 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
191 ft->time_create = dw;
192 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
193 ft->time_access = dw;
194 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
195 ft->time_write = dw;
196 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
197 wcscpy(ft->name, fd->cFileName);
200 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata64i32_t */
201 static void msvcrt_fttofd64i32( const WIN32_FIND_DATAA *fd, struct _finddata64i32_t* ft)
203 DWORD dw;
205 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
206 ft->attrib = 0;
207 else
208 ft->attrib = fd->dwFileAttributes;
210 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
211 ft->time_create = dw;
212 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
213 ft->time_access = dw;
214 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
215 ft->time_write = dw;
216 ft->size = fd->nFileSizeLow;
217 strcpy(ft->name, fd->cFileName);
220 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddatai64_t */
221 static void msvcrt_wfttofdi64( const WIN32_FIND_DATAW *fd, struct _wfinddatai64_t* ft)
223 DWORD dw;
225 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
226 ft->attrib = 0;
227 else
228 ft->attrib = fd->dwFileAttributes;
230 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
231 ft->time_create = dw;
232 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
233 ft->time_access = dw;
234 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
235 ft->time_write = dw;
236 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
237 wcscpy(ft->name, fd->cFileName);
240 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata64i32_t */
241 static void msvcrt_wfttofd64i32( const WIN32_FIND_DATAW *fd, struct _wfinddata64i32_t* ft)
243 DWORD dw;
245 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
246 ft->attrib = 0;
247 else
248 ft->attrib = fd->dwFileAttributes;
250 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
251 ft->time_create = dw;
252 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
253 ft->time_access = dw;
254 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
255 ft->time_write = dw;
256 ft->size = fd->nFileSizeLow;
257 wcscpy(ft->name, fd->cFileName);
260 /*********************************************************************
261 * _chdir (MSVCRT.@)
263 * Change the current working directory.
265 * PARAMS
266 * newdir [I] Directory to change to
268 * RETURNS
269 * Success: 0. The current working directory is set to newdir.
270 * Failure: -1. errno indicates the error.
272 * NOTES
273 * See SetCurrentDirectoryA.
275 int CDECL _chdir(const char * newdir)
277 if (!SetCurrentDirectoryA(newdir))
279 msvcrt_set_errno(newdir?GetLastError():0);
280 return -1;
282 return 0;
285 /*********************************************************************
286 * _wchdir (MSVCRT.@)
288 * Unicode version of _chdir.
290 int CDECL _wchdir(const wchar_t * newdir)
292 if (!SetCurrentDirectoryW(newdir))
294 msvcrt_set_errno(newdir?GetLastError():0);
295 return -1;
297 return 0;
300 /*********************************************************************
301 * _chdrive (MSVCRT.@)
303 * Change the current drive.
305 * PARAMS
306 * newdrive [I] Drive number to change to (1 = 'A', 2 = 'B', ...)
308 * RETURNS
309 * Success: 0. The current drive is set to newdrive.
310 * Failure: -1. errno indicates the error.
312 * NOTES
313 * See SetCurrentDirectoryA.
315 int CDECL _chdrive(int newdrive)
317 WCHAR buffer[] = L"A:";
319 buffer[0] += newdrive - 1;
320 if (!SetCurrentDirectoryW( buffer ))
322 msvcrt_set_errno(GetLastError());
323 if (newdrive <= 0)
324 *_errno() = EACCES;
325 return -1;
327 return 0;
330 /*********************************************************************
331 * _findclose (MSVCRT.@)
333 * Close a handle returned by _findfirst().
335 * PARAMS
336 * hand [I] Handle to close
338 * RETURNS
339 * Success: 0. All resources associated with hand are freed.
340 * Failure: -1. errno indicates the error.
342 * NOTES
343 * See FindClose.
345 int CDECL _findclose(intptr_t hand)
347 TRACE(":handle %Iu\n",hand);
348 if (!FindClose((HANDLE)hand))
350 msvcrt_set_errno(GetLastError());
351 return -1;
353 return 0;
356 /*********************************************************************
357 * _findfirst (MSVCRT.@)
359 * Open a handle for iterating through a directory.
361 * PARAMS
362 * fspec [I] File specification of files to iterate.
363 * ft [O] Information for the first file found.
365 * RETURNS
366 * Success: A handle suitable for passing to _findnext() and _findclose().
367 * ft is populated with the details of the found file.
368 * Failure: -1. errno indicates the error.
370 * NOTES
371 * See FindFirstFileA.
373 intptr_t CDECL _findfirst(const char * fspec, struct _finddata_t* ft)
375 WIN32_FIND_DATAA find_data;
376 HANDLE hfind;
378 hfind = FindFirstFileA(fspec, &find_data);
379 if (hfind == INVALID_HANDLE_VALUE)
381 msvcrt_set_errno(GetLastError());
382 return -1;
384 msvcrt_fttofd(&find_data,ft);
385 TRACE(":got handle %p\n",hfind);
386 return (intptr_t)hfind;
389 /*********************************************************************
390 * _findfirst32 (MSVCRT.@)
392 intptr_t CDECL _findfirst32(const char * fspec, struct _finddata32_t* ft)
394 WIN32_FIND_DATAA find_data;
395 HANDLE hfind;
397 hfind = FindFirstFileA(fspec, &find_data);
398 if (hfind == INVALID_HANDLE_VALUE)
400 msvcrt_set_errno(GetLastError());
401 return -1;
403 msvcrt_fttofd32(&find_data, ft);
404 TRACE(":got handle %p\n", hfind);
405 return (intptr_t)hfind;
408 /*********************************************************************
409 * _wfindfirst (MSVCRT.@)
411 * Unicode version of _findfirst.
413 intptr_t CDECL _wfindfirst(const wchar_t * fspec, struct _wfinddata_t* ft)
415 WIN32_FIND_DATAW find_data;
416 HANDLE hfind;
418 hfind = FindFirstFileW(fspec, &find_data);
419 if (hfind == INVALID_HANDLE_VALUE)
421 msvcrt_set_errno(GetLastError());
422 return -1;
424 msvcrt_wfttofd(&find_data,ft);
425 TRACE(":got handle %p\n",hfind);
426 return (intptr_t)hfind;
429 /*********************************************************************
430 * _wfindfirst32 (MSVCRT.@)
432 * Unicode version of _findfirst32.
434 intptr_t CDECL _wfindfirst32(const wchar_t * fspec, struct _wfinddata32_t* ft)
436 WIN32_FIND_DATAW find_data;
437 HANDLE hfind;
439 hfind = FindFirstFileW(fspec, &find_data);
440 if (hfind == INVALID_HANDLE_VALUE)
442 msvcrt_set_errno(GetLastError());
443 return -1;
445 msvcrt_wfttofd32(&find_data, ft);
446 TRACE(":got handle %p\n", hfind);
447 return (intptr_t)hfind;
450 /*********************************************************************
451 * _findfirsti64 (MSVCRT.@)
453 * 64-bit version of _findfirst.
455 intptr_t CDECL _findfirsti64(const char * fspec, struct _finddatai64_t* ft)
457 WIN32_FIND_DATAA find_data;
458 HANDLE hfind;
460 hfind = FindFirstFileA(fspec, &find_data);
461 if (hfind == INVALID_HANDLE_VALUE)
463 msvcrt_set_errno(GetLastError());
464 return -1;
466 msvcrt_fttofdi64(&find_data,ft);
467 TRACE(":got handle %p\n",hfind);
468 return (intptr_t)hfind;
471 /*********************************************************************
472 * _findfirst64 (MSVCRT.@)
474 * 64-bit version of _findfirst.
476 intptr_t CDECL _findfirst64(const char * fspec, struct _finddata64_t* ft)
478 WIN32_FIND_DATAA find_data;
479 HANDLE hfind;
481 hfind = FindFirstFileA(fspec, &find_data);
482 if (hfind == INVALID_HANDLE_VALUE)
484 msvcrt_set_errno(GetLastError());
485 return -1;
487 msvcrt_fttofd64(&find_data,ft);
488 TRACE(":got handle %p\n",hfind);
489 return (intptr_t)hfind;
492 /*********************************************************************
493 * _wfindfirst64 (MSVCRT.@)
495 * Unicode version of _findfirst64.
497 intptr_t CDECL _wfindfirst64(const wchar_t * fspec, struct _wfinddata64_t* ft)
499 WIN32_FIND_DATAW find_data;
500 HANDLE hfind;
502 hfind = FindFirstFileW(fspec, &find_data);
503 if (hfind == INVALID_HANDLE_VALUE)
505 msvcrt_set_errno(GetLastError());
506 return -1;
508 msvcrt_wfttofd64(&find_data,ft);
509 TRACE(":got handle %p\n",hfind);
510 return (intptr_t)hfind;
513 /*********************************************************************
514 * _findfirst64i32 (MSVCRT.@)
516 * 64-bit/32-bit version of _findfirst.
518 intptr_t CDECL _findfirst64i32(const char * fspec, struct _finddata64i32_t* ft)
520 WIN32_FIND_DATAA find_data;
521 HANDLE hfind;
523 hfind = FindFirstFileA(fspec, &find_data);
524 if (hfind == INVALID_HANDLE_VALUE)
526 msvcrt_set_errno(GetLastError());
527 return -1;
529 msvcrt_fttofd64i32(&find_data,ft);
530 TRACE(":got handle %p\n",hfind);
531 return (intptr_t)hfind;
534 /*********************************************************************
535 * _wfindfirst64i32 (MSVCRT.@)
537 * Unicode version of _findfirst64i32.
539 intptr_t CDECL _wfindfirst64i32(const wchar_t * fspec, struct _wfinddata64i32_t* ft)
541 WIN32_FIND_DATAW find_data;
542 HANDLE hfind;
544 hfind = FindFirstFileW(fspec, &find_data);
545 if (hfind == INVALID_HANDLE_VALUE)
547 msvcrt_set_errno(GetLastError());
548 return -1;
550 msvcrt_wfttofd64i32(&find_data,ft);
551 TRACE(":got handle %p\n",hfind);
552 return (intptr_t)hfind;
555 /*********************************************************************
556 * _wfindfirsti64 (MSVCRT.@)
558 * Unicode version of _findfirsti64.
560 intptr_t CDECL _wfindfirsti64(const wchar_t * fspec, struct _wfinddatai64_t* ft)
562 WIN32_FIND_DATAW find_data;
563 HANDLE hfind;
565 hfind = FindFirstFileW(fspec, &find_data);
566 if (hfind == INVALID_HANDLE_VALUE)
568 msvcrt_set_errno(GetLastError());
569 return -1;
571 msvcrt_wfttofdi64(&find_data,ft);
572 TRACE(":got handle %p\n",hfind);
573 return (intptr_t)hfind;
576 /*********************************************************************
577 * _findnext (MSVCRT.@)
579 * Find the next file from a file search handle.
581 * PARAMS
582 * hand [I] Handle to the search returned from _findfirst().
583 * ft [O] Information for the file found.
585 * RETURNS
586 * Success: 0. ft is populated with the details of the found file.
587 * Failure: -1. errno indicates the error.
589 * NOTES
590 * See FindNextFileA.
592 int CDECL _findnext(intptr_t hand, struct _finddata_t * ft)
594 WIN32_FIND_DATAA find_data;
596 if (!FindNextFileA((HANDLE)hand, &find_data))
598 *_errno() = ENOENT;
599 return -1;
602 msvcrt_fttofd(&find_data,ft);
603 return 0;
606 /*********************************************************************
607 * _findnext32 (MSVCRT.@)
609 int CDECL _findnext32(intptr_t hand, struct _finddata32_t * ft)
611 WIN32_FIND_DATAA find_data;
613 if (!FindNextFileA((HANDLE)hand, &find_data))
615 *_errno() = ENOENT;
616 return -1;
619 msvcrt_fttofd32(&find_data, ft);
620 return 0;
623 /*********************************************************************
624 * _wfindnext32 (MSVCRT.@)
626 int CDECL _wfindnext32(intptr_t hand, struct _wfinddata32_t * ft)
628 WIN32_FIND_DATAW find_data;
630 if (!FindNextFileW((HANDLE)hand, &find_data))
632 *_errno() = ENOENT;
633 return -1;
636 msvcrt_wfttofd32(&find_data, ft);
637 return 0;
640 /*********************************************************************
641 * _wfindnext (MSVCRT.@)
643 * Unicode version of _findnext.
645 int CDECL _wfindnext(intptr_t hand, struct _wfinddata_t * ft)
647 WIN32_FIND_DATAW find_data;
649 if (!FindNextFileW((HANDLE)hand, &find_data))
651 *_errno() = ENOENT;
652 return -1;
655 msvcrt_wfttofd(&find_data,ft);
656 return 0;
659 /*********************************************************************
660 * _findnexti64 (MSVCRT.@)
662 * 64-bit version of _findnext.
664 int CDECL _findnexti64(intptr_t hand, struct _finddatai64_t * ft)
666 WIN32_FIND_DATAA find_data;
668 if (!FindNextFileA((HANDLE)hand, &find_data))
670 *_errno() = ENOENT;
671 return -1;
674 msvcrt_fttofdi64(&find_data,ft);
675 return 0;
678 /*********************************************************************
679 * _findnext64 (MSVCRT.@)
681 * 64-bit version of _findnext.
683 int CDECL _findnext64(intptr_t hand, struct _finddata64_t * ft)
685 WIN32_FIND_DATAA find_data;
687 if (!FindNextFileA((HANDLE)hand, &find_data))
689 *_errno() = ENOENT;
690 return -1;
693 msvcrt_fttofd64(&find_data,ft);
694 return 0;
697 /*********************************************************************
698 * _wfindnext64 (MSVCRT.@)
700 * Unicode version of _wfindnext64.
702 int CDECL _wfindnext64(intptr_t hand, struct _wfinddata64_t * ft)
704 WIN32_FIND_DATAW find_data;
706 if (!FindNextFileW((HANDLE)hand, &find_data))
708 *_errno() = ENOENT;
709 return -1;
712 msvcrt_wfttofd64(&find_data,ft);
713 return 0;
716 /*********************************************************************
717 * _findnext64i32 (MSVCRT.@)
719 * 64-bit/32-bit version of _findnext.
721 int CDECL _findnext64i32(intptr_t hand, struct _finddata64i32_t * ft)
723 WIN32_FIND_DATAA find_data;
725 if (!FindNextFileA((HANDLE)hand, &find_data))
727 *_errno() = ENOENT;
728 return -1;
731 msvcrt_fttofd64i32(&find_data,ft);
732 return 0;
735 /*********************************************************************
736 * _wfindnexti64 (MSVCRT.@)
738 * Unicode version of _findnexti64.
740 int CDECL _wfindnexti64(intptr_t hand, struct _wfinddatai64_t * ft)
742 WIN32_FIND_DATAW find_data;
744 if (!FindNextFileW((HANDLE)hand, &find_data))
746 *_errno() = ENOENT;
747 return -1;
750 msvcrt_wfttofdi64(&find_data,ft);
751 return 0;
754 /*********************************************************************
755 * _wfindnext64i32 (MSVCRT.@)
757 * Unicode version of _findnext64i32.
759 int CDECL _wfindnext64i32(intptr_t hand, struct _wfinddata64i32_t * ft)
761 WIN32_FIND_DATAW find_data;
763 if (!FindNextFileW((HANDLE)hand, &find_data))
765 *_errno() = ENOENT;
766 return -1;
769 msvcrt_wfttofd64i32(&find_data,ft);
770 return 0;
773 /*********************************************************************
774 * _getcwd (MSVCRT.@)
776 * Get the current working directory.
778 * PARAMS
779 * buf [O] Destination for current working directory.
780 * size [I] Size of buf in characters
782 * RETURNS
783 * Success: If buf is NULL, returns an allocated string containing the path.
784 * Otherwise populates buf with the path and returns it.
785 * Failure: NULL. errno indicates the error.
787 char* CDECL _getcwd(char * buf, int size)
789 char dir[MAX_PATH];
790 int dir_len = GetCurrentDirectoryA(MAX_PATH,dir);
792 if (dir_len < 1)
793 return NULL; /* FIXME: Real return value untested */
795 if (!buf)
797 if (size <= dir_len) size = dir_len + 1;
798 if (!(buf = malloc( size ))) return NULL;
800 else if (dir_len >= size)
802 *_errno() = ERANGE;
803 return NULL; /* buf too small */
805 strcpy(buf,dir);
806 return buf;
809 /*********************************************************************
810 * _wgetcwd (MSVCRT.@)
812 * Unicode version of _getcwd.
814 wchar_t* CDECL _wgetcwd(wchar_t * buf, int size)
816 wchar_t dir[MAX_PATH];
817 int dir_len = GetCurrentDirectoryW(MAX_PATH,dir);
819 if (dir_len < 1)
820 return NULL; /* FIXME: Real return value untested */
822 if (!buf)
824 if (size <= dir_len) size = dir_len + 1;
825 if (!(buf = malloc( size * sizeof(WCHAR) ))) return NULL;
827 if (dir_len >= size)
829 *_errno() = ERANGE;
830 return NULL; /* buf too small */
832 wcscpy(buf,dir);
833 return buf;
836 /*********************************************************************
837 * _getdrive (MSVCRT.@)
839 * Get the current drive number.
841 * PARAMS
842 * None.
844 * RETURNS
845 * Success: The drive letter number from 1 to 26 ("A:" to "Z:").
846 * Failure: 0.
848 int CDECL _getdrive(void)
850 WCHAR buffer[MAX_PATH];
851 if (GetCurrentDirectoryW( MAX_PATH, buffer ) &&
852 buffer[0] >= 'A' && buffer[0] <= 'z' && buffer[1] == ':')
853 return towupper(buffer[0]) - 'A' + 1;
854 return 0;
857 /*********************************************************************
858 * _getdcwd (MSVCRT.@)
860 * Get the current working directory on a given disk.
862 * PARAMS
863 * drive [I] Drive letter to get the current working directory from.
864 * buf [O] Destination for the current working directory.
865 * size [I] Length of drive in characters.
867 * RETURNS
868 * Success: If drive is NULL, returns an allocated string containing the path.
869 * Otherwise populates drive with the path and returns it.
870 * Failure: NULL. errno indicates the error.
872 char* CDECL _getdcwd(int drive, char * buf, int size)
874 static char* dummy;
876 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
878 if (!drive || drive == _getdrive())
879 return _getcwd(buf,size); /* current */
880 else
882 char dir[MAX_PATH];
883 char drivespec[] = "A:";
884 int dir_len;
886 drivespec[0] += drive - 1;
887 if (GetDriveTypeA(drivespec) < DRIVE_REMOVABLE)
889 *_errno() = EACCES;
890 return NULL;
893 dir_len = GetFullPathNameA(drivespec,MAX_PATH,dir,&dummy);
894 if (dir_len >= size || dir_len < 1)
896 *_errno() = ERANGE;
897 return NULL; /* buf too small */
900 TRACE(":returning '%s'\n", dir);
901 if (!buf)
902 return _strdup(dir); /* allocate */
904 strcpy(buf,dir);
906 return buf;
909 /*********************************************************************
910 * _wgetdcwd (MSVCRT.@)
912 * Unicode version of _wgetdcwd.
914 wchar_t* CDECL _wgetdcwd(int drive, wchar_t * buf, int size)
916 static wchar_t* dummy;
918 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
920 if (!drive || drive == _getdrive())
921 return _wgetcwd(buf,size); /* current */
922 else
924 wchar_t dir[MAX_PATH];
925 wchar_t drivespec[4] = L"A:\\";
926 int dir_len;
928 drivespec[0] += drive - 1;
929 if (GetDriveTypeW(drivespec) < DRIVE_REMOVABLE)
931 *_errno() = EACCES;
932 return NULL;
935 dir_len = GetFullPathNameW(drivespec,MAX_PATH,dir,&dummy);
936 if (dir_len >= size || dir_len < 1)
938 *_errno() = ERANGE;
939 return NULL; /* buf too small */
942 TRACE(":returning %s\n", debugstr_w(dir));
943 if (!buf)
944 return _wcsdup(dir); /* allocate */
945 wcscpy(buf,dir);
947 return buf;
950 /*********************************************************************
951 * _getdiskfree (MSVCRT.@)
953 * Get information about the free space on a drive.
955 * PARAMS
956 * disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
957 * info [O] Destination for the resulting information.
959 * RETURNS
960 * Success: 0. info is updated with the free space information.
961 * Failure: An error code from GetLastError().
963 * NOTES
964 * See GetLastError().
966 unsigned int CDECL _getdiskfree(unsigned int disk, struct _diskfree_t * d)
968 WCHAR drivespec[] = L"@:\\";
969 DWORD ret[4];
970 unsigned int err;
972 if (disk > 26)
973 return ERROR_INVALID_PARAMETER; /* MSVCRT doesn't set errno here */
975 drivespec[0] += disk; /* make a drive letter */
977 if (GetDiskFreeSpaceW(disk==0?NULL:drivespec,ret,ret+1,ret+2,ret+3))
979 d->sectors_per_cluster = ret[0];
980 d->bytes_per_sector = ret[1];
981 d->avail_clusters = ret[2];
982 d->total_clusters = ret[3];
983 return 0;
985 err = GetLastError();
986 msvcrt_set_errno(err);
987 return err;
990 /*********************************************************************
991 * _mkdir (MSVCRT.@)
993 * Create a directory.
995 * PARAMS
996 * newdir [I] Name of directory to create.
998 * RETURNS
999 * Success: 0. The directory indicated by newdir is created.
1000 * Failure: -1. errno indicates the error.
1002 * NOTES
1003 * See CreateDirectoryA.
1005 int CDECL _mkdir(const char * newdir)
1007 if (CreateDirectoryA(newdir,NULL))
1008 return 0;
1009 msvcrt_set_errno(GetLastError());
1010 return -1;
1013 /*********************************************************************
1014 * _wmkdir (MSVCRT.@)
1016 * Unicode version of _mkdir.
1018 int CDECL _wmkdir(const wchar_t* newdir)
1020 if (CreateDirectoryW(newdir,NULL))
1021 return 0;
1022 msvcrt_set_errno(GetLastError());
1023 return -1;
1026 /*********************************************************************
1027 * _rmdir (MSVCRT.@)
1029 * Delete a directory.
1031 * PARAMS
1032 * dir [I] Name of directory to delete.
1034 * RETURNS
1035 * Success: 0. The directory indicated by newdir is deleted.
1036 * Failure: -1. errno indicates the error.
1038 * NOTES
1039 * See RemoveDirectoryA.
1041 int CDECL _rmdir(const char * dir)
1043 if (RemoveDirectoryA(dir))
1044 return 0;
1045 msvcrt_set_errno(GetLastError());
1046 return -1;
1049 /*********************************************************************
1050 * _wrmdir (MSVCRT.@)
1052 * Unicode version of _rmdir.
1054 int CDECL _wrmdir(const wchar_t * dir)
1056 if (RemoveDirectoryW(dir))
1057 return 0;
1058 msvcrt_set_errno(GetLastError());
1059 return -1;
1062 /******************************************************************
1063 * _splitpath_s (MSVCRT.@)
1065 int CDECL _splitpath_s(const char* inpath,
1066 char* drive, size_t sz_drive,
1067 char* dir, size_t sz_dir,
1068 char* fname, size_t sz_fname,
1069 char* ext, size_t sz_ext)
1071 const char *p, *end;
1073 if (!inpath || (!drive && sz_drive) ||
1074 (drive && !sz_drive) ||
1075 (!dir && sz_dir) ||
1076 (dir && !sz_dir) ||
1077 (!fname && sz_fname) ||
1078 (fname && !sz_fname) ||
1079 (!ext && sz_ext) ||
1080 (ext && !sz_ext))
1082 *_errno() = EINVAL;
1083 return EINVAL;
1086 if (inpath[0] && inpath[1] == ':')
1088 if (drive)
1090 if (sz_drive <= 2) goto do_error;
1091 drive[0] = inpath[0];
1092 drive[1] = inpath[1];
1093 drive[2] = 0;
1095 inpath += 2;
1097 else if (drive) drive[0] = '\0';
1099 /* look for end of directory part */
1100 end = NULL;
1101 for (p = inpath; *p; p++)
1103 if (_ismbblead((unsigned char)*p))
1105 p++;
1106 continue;
1108 if (*p == '/' || *p == '\\') end = p + 1;
1111 if (end) /* got a directory */
1113 if (dir)
1115 if (sz_dir <= end - inpath) goto do_error;
1116 memcpy( dir, inpath, (end - inpath) );
1117 dir[end - inpath] = 0;
1119 inpath = end;
1121 else if (dir) dir[0] = 0;
1123 /* look for extension: what's after the last dot */
1124 end = NULL;
1125 for (p = inpath; *p; p++) if (*p == '.') end = p;
1127 if (!end) end = p; /* there's no extension */
1129 if (fname)
1131 if (sz_fname <= end - inpath) goto do_error;
1132 memcpy( fname, inpath, (end - inpath) );
1133 fname[end - inpath] = 0;
1135 if (ext)
1137 if (sz_ext <= strlen(end)) goto do_error;
1138 strcpy( ext, end );
1140 return 0;
1141 do_error:
1142 if (drive) drive[0] = '\0';
1143 if (dir) dir[0] = '\0';
1144 if (fname) fname[0]= '\0';
1145 if (ext) ext[0]= '\0';
1146 *_errno() = ERANGE;
1147 return ERANGE;
1150 /*********************************************************************
1151 * _splitpath (MSVCRT.@)
1153 void CDECL _splitpath(const char *inpath, char *drv, char *dir,
1154 char *fname, char *ext)
1156 _splitpath_s(inpath, drv, drv ? _MAX_DRIVE : 0, dir, dir ? _MAX_DIR : 0,
1157 fname, fname ? _MAX_FNAME : 0, ext, ext ? _MAX_EXT : 0);
1160 /******************************************************************
1161 * _wsplitpath_s (MSVCRT.@)
1163 * Secure version of _wsplitpath
1165 int CDECL _wsplitpath_s(const wchar_t* inpath,
1166 wchar_t* drive, size_t sz_drive,
1167 wchar_t* dir, size_t sz_dir,
1168 wchar_t* fname, size_t sz_fname,
1169 wchar_t* ext, size_t sz_ext)
1171 const wchar_t *p, *end;
1173 if (!inpath || (!drive && sz_drive) ||
1174 (drive && !sz_drive) ||
1175 (!dir && sz_dir) ||
1176 (dir && !sz_dir) ||
1177 (!fname && sz_fname) ||
1178 (fname && !sz_fname) ||
1179 (!ext && sz_ext) ||
1180 (ext && !sz_ext))
1182 *_errno() = EINVAL;
1183 return EINVAL;
1186 if (inpath[0] && inpath[1] == ':')
1188 if (drive)
1190 if (sz_drive <= 2) goto do_error;
1191 drive[0] = inpath[0];
1192 drive[1] = inpath[1];
1193 drive[2] = 0;
1195 inpath += 2;
1197 else if (drive) drive[0] = '\0';
1199 /* look for end of directory part */
1200 end = NULL;
1201 for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
1203 if (end) /* got a directory */
1205 if (dir)
1207 if (sz_dir <= end - inpath) goto do_error;
1208 memcpy( dir, inpath, (end - inpath) * sizeof(wchar_t) );
1209 dir[end - inpath] = 0;
1211 inpath = end;
1213 else if (dir) dir[0] = 0;
1215 /* look for extension: what's after the last dot */
1216 end = NULL;
1217 for (p = inpath; *p; p++) if (*p == '.') end = p;
1219 if (!end) end = p; /* there's no extension */
1221 if (fname)
1223 if (sz_fname <= end - inpath) goto do_error;
1224 memcpy( fname, inpath, (end - inpath) * sizeof(wchar_t) );
1225 fname[end - inpath] = 0;
1227 if (ext)
1229 if (sz_ext <= wcslen(end)) goto do_error;
1230 wcscpy( ext, end );
1232 return 0;
1233 do_error:
1234 if (drive) drive[0] = '\0';
1235 if (dir) dir[0] = '\0';
1236 if (fname) fname[0]= '\0';
1237 if (ext) ext[0]= '\0';
1238 *_errno() = ERANGE;
1239 return ERANGE;
1242 /*********************************************************************
1243 * _wsplitpath (MSVCRT.@)
1245 * Unicode version of _splitpath.
1247 void CDECL _wsplitpath(const wchar_t *inpath, wchar_t *drv, wchar_t *dir,
1248 wchar_t *fname, wchar_t *ext)
1250 _wsplitpath_s(inpath, drv, drv ? _MAX_DRIVE : 0, dir, dir ? _MAX_DIR : 0,
1251 fname, fname ? _MAX_FNAME : 0, ext, ext ? _MAX_EXT : 0);
1254 /*********************************************************************
1255 * _wfullpath (MSVCRT.@)
1257 * Unicode version of _fullpath.
1259 wchar_t * CDECL _wfullpath(wchar_t * absPath, const wchar_t* relPath, size_t size)
1261 DWORD rc;
1262 WCHAR* buffer;
1263 WCHAR* lastpart;
1264 BOOL alloced = FALSE;
1266 if (!relPath || !*relPath)
1267 return _wgetcwd(absPath, size);
1269 if (absPath == NULL)
1271 buffer = malloc(MAX_PATH * sizeof(WCHAR));
1272 size = MAX_PATH;
1273 alloced = TRUE;
1275 else
1276 buffer = absPath;
1278 if (size < 4)
1280 *_errno() = ERANGE;
1281 return NULL;
1284 TRACE(":resolving relative path %s\n",debugstr_w(relPath));
1286 rc = GetFullPathNameW(relPath,size,buffer,&lastpart);
1288 if (rc > 0 && rc <= size )
1289 return buffer;
1290 else
1292 if (alloced)
1293 free(buffer);
1294 return NULL;
1298 /*********************************************************************
1299 * _fullpath (MSVCRT.@)
1301 * Create an absolute path from a relative path.
1303 * PARAMS
1304 * absPath [O] Destination for absolute path
1305 * relPath [I] Relative path to convert to absolute
1306 * size [I] Length of absPath in characters.
1308 * RETURNS
1309 * Success: If absPath is NULL, returns an allocated string containing the path.
1310 * Otherwise populates absPath with the path and returns it.
1311 * Failure: NULL. errno indicates the error.
1313 char * CDECL _fullpath(char * absPath, const char* relPath, size_t size)
1315 DWORD rc;
1316 char* lastpart;
1317 char* buffer;
1318 BOOL alloced = FALSE;
1320 if (!relPath || !*relPath)
1321 return _getcwd(absPath, size);
1323 if (absPath == NULL)
1325 buffer = malloc(MAX_PATH);
1326 size = MAX_PATH;
1327 alloced = TRUE;
1329 else
1330 buffer = absPath;
1332 if (size < 4)
1334 *_errno() = ERANGE;
1335 return NULL;
1338 TRACE(":resolving relative path '%s'\n",relPath);
1340 rc = GetFullPathNameA(relPath,size,buffer,&lastpart);
1342 if (rc > 0 && rc <= size)
1343 return buffer;
1344 else
1346 if (alloced)
1347 free(buffer);
1348 return NULL;
1352 /*********************************************************************
1353 * _makepath (MSVCRT.@)
1355 * Create a pathname.
1357 * PARAMS
1358 * path [O] Destination for created pathname
1359 * drive [I] Drive letter (e.g. "A:")
1360 * directory [I] Directory
1361 * filename [I] Name of the file, excluding extension
1362 * extension [I] File extension (e.g. ".TXT")
1364 * RETURNS
1365 * Nothing. If path is not large enough to hold the resulting pathname,
1366 * random process memory will be overwritten.
1368 VOID CDECL _makepath(char * path, const char * drive,
1369 const char *directory, const char * filename,
1370 const char * extension)
1372 char *p = path;
1374 TRACE("(%s %s %s %s)\n", debugstr_a(drive), debugstr_a(directory),
1375 debugstr_a(filename), debugstr_a(extension) );
1377 if ( !path )
1378 return;
1380 if (drive && drive[0])
1382 *p++ = drive[0];
1383 *p++ = ':';
1385 if (directory && directory[0])
1387 unsigned int len = strlen(directory);
1388 memmove(p, directory, len);
1389 p += len;
1390 if (p[-1] != '/' && p[-1] != '\\')
1391 *p++ = '\\';
1393 if (filename && filename[0])
1395 unsigned int len = strlen(filename);
1396 memmove(p, filename, len);
1397 p += len;
1399 if (extension && extension[0])
1401 if (extension[0] != '.')
1402 *p++ = '.';
1403 strcpy(p, extension);
1405 else
1406 *p = '\0';
1407 TRACE("returning %s\n",path);
1410 /*********************************************************************
1411 * _wmakepath (MSVCRT.@)
1413 * Unicode version of _wmakepath.
1415 VOID CDECL _wmakepath(wchar_t *path, const wchar_t *drive, const wchar_t *directory,
1416 const wchar_t *filename, const wchar_t *extension)
1418 wchar_t *p = path;
1420 TRACE("%s %s %s %s\n", debugstr_w(drive), debugstr_w(directory),
1421 debugstr_w(filename), debugstr_w(extension));
1423 if ( !path )
1424 return;
1426 if (drive && drive[0])
1428 *p++ = drive[0];
1429 *p++ = ':';
1431 if (directory && directory[0])
1433 unsigned int len = wcslen(directory);
1434 memmove(p, directory, len * sizeof(wchar_t));
1435 p += len;
1436 if (p[-1] != '/' && p[-1] != '\\')
1437 *p++ = '\\';
1439 if (filename && filename[0])
1441 unsigned int len = wcslen(filename);
1442 memmove(p, filename, len * sizeof(wchar_t));
1443 p += len;
1445 if (extension && extension[0])
1447 if (extension[0] != '.')
1448 *p++ = '.';
1449 wcscpy(p, extension);
1451 else
1452 *p = '\0';
1454 TRACE("returning %s\n", debugstr_w(path));
1457 /*********************************************************************
1458 * _makepath_s (MSVCRT.@)
1460 * Safe version of _makepath.
1462 int CDECL _makepath_s(char *path, size_t size, const char *drive,
1463 const char *directory, const char *filename,
1464 const char *extension)
1466 char *p = path;
1468 if (!path || !size)
1470 *_errno() = EINVAL;
1471 return EINVAL;
1474 if (drive && drive[0])
1476 if (size <= 2)
1477 goto range;
1479 *p++ = drive[0];
1480 *p++ = ':';
1481 size -= 2;
1484 if (directory && directory[0])
1486 unsigned int len = strlen(directory);
1487 unsigned int needs_separator = directory[len - 1] != '/' && directory[len - 1] != '\\';
1488 unsigned int copylen = min(size - 1, len);
1490 if (size < 2)
1491 goto range;
1493 memmove(p, directory, copylen);
1495 if (size <= len)
1496 goto range;
1498 p += copylen;
1499 size -= copylen;
1501 if (needs_separator)
1503 if (size < 2)
1504 goto range;
1506 *p++ = '\\';
1507 size -= 1;
1511 if (filename && filename[0])
1513 unsigned int len = strlen(filename);
1514 unsigned int copylen = min(size - 1, len);
1516 if (size < 2)
1517 goto range;
1519 memmove(p, filename, copylen);
1521 if (size <= len)
1522 goto range;
1524 p += len;
1525 size -= len;
1528 if (extension && extension[0])
1530 unsigned int len = strlen(extension);
1531 unsigned int needs_period = extension[0] != '.';
1532 unsigned int copylen;
1534 if (size < 2)
1535 goto range;
1537 if (needs_period)
1539 *p++ = '.';
1540 size -= 1;
1543 copylen = min(size - 1, len);
1544 memcpy(p, extension, copylen);
1546 if (size <= len)
1547 goto range;
1549 p += copylen;
1552 *p = '\0';
1553 return 0;
1555 range:
1556 path[0] = '\0';
1557 *_errno() = ERANGE;
1558 return ERANGE;
1561 /*********************************************************************
1562 * _wmakepath_s (MSVCRT.@)
1564 * Safe version of _wmakepath.
1566 int CDECL _wmakepath_s(wchar_t *path, size_t size, const wchar_t *drive,
1567 const wchar_t *directory, const wchar_t *filename,
1568 const wchar_t *extension)
1570 wchar_t *p = path;
1572 if (!path || !size)
1574 *_errno() = EINVAL;
1575 return EINVAL;
1578 if (drive && drive[0])
1580 if (size <= 2)
1581 goto range;
1583 *p++ = drive[0];
1584 *p++ = ':';
1585 size -= 2;
1588 if (directory && directory[0])
1590 unsigned int len = wcslen(directory);
1591 unsigned int needs_separator = directory[len - 1] != '/' && directory[len - 1] != '\\';
1592 unsigned int copylen = min(size - 1, len);
1594 if (size < 2)
1595 goto range;
1597 memmove(p, directory, copylen * sizeof(wchar_t));
1599 if (size <= len)
1600 goto range;
1602 p += copylen;
1603 size -= copylen;
1605 if (needs_separator)
1607 if (size < 2)
1608 goto range;
1610 *p++ = '\\';
1611 size -= 1;
1615 if (filename && filename[0])
1617 unsigned int len = wcslen(filename);
1618 unsigned int copylen = min(size - 1, len);
1620 if (size < 2)
1621 goto range;
1623 memmove(p, filename, copylen * sizeof(wchar_t));
1625 if (size <= len)
1626 goto range;
1628 p += len;
1629 size -= len;
1632 if (extension && extension[0])
1634 unsigned int len = wcslen(extension);
1635 unsigned int needs_period = extension[0] != '.';
1636 unsigned int copylen;
1638 if (size < 2)
1639 goto range;
1641 if (needs_period)
1643 *p++ = '.';
1644 size -= 1;
1647 copylen = min(size - 1, len);
1648 memcpy(p, extension, copylen * sizeof(wchar_t));
1650 if (size <= len)
1651 goto range;
1653 p += copylen;
1656 *p = '\0';
1657 return 0;
1659 range:
1660 path[0] = '\0';
1661 *_errno() = ERANGE;
1662 return ERANGE;
1665 /*********************************************************************
1666 * _searchenv_s (MSVCRT.@)
1668 int CDECL _searchenv_s(const char* file, const char* env, char *buf, size_t count)
1670 char *envVal, *penv, *end;
1671 char path[MAX_PATH];
1672 size_t path_len, fname_len;
1674 if (!MSVCRT_CHECK_PMT(file != NULL)) return EINVAL;
1675 if (!MSVCRT_CHECK_PMT(buf != NULL)) return EINVAL;
1676 if (!MSVCRT_CHECK_PMT(count > 0)) return EINVAL;
1678 if (count > MAX_PATH)
1679 FIXME("count > MAX_PATH not supported\n");
1681 fname_len = strlen(file);
1682 *buf = '\0';
1684 /* Try CWD first */
1685 if (GetFileAttributesA( file ) != INVALID_FILE_ATTRIBUTES)
1687 if (GetFullPathNameA( file, count, buf, NULL )) return 0;
1688 msvcrt_set_errno(GetLastError());
1689 return 0;
1692 /* Search given environment variable */
1693 envVal = getenv(env);
1694 if (!envVal)
1696 *_errno() = ENOENT;
1697 return ENOENT;
1700 penv = envVal;
1701 TRACE(":searching for %s in paths %s\n", file, envVal);
1703 for(; *penv; penv = (*end ? end + 1 : end))
1705 end = penv;
1706 path_len = 0;
1707 while(*end && *end != ';' && path_len < MAX_PATH)
1709 if (*end == '"')
1711 end++;
1712 while(*end && *end != '"' && path_len < MAX_PATH)
1714 path[path_len++] = *end;
1715 end++;
1717 if (*end == '"') end++;
1718 continue;
1721 path[path_len++] = *end;
1722 end++;
1724 if (!path_len || path_len >= MAX_PATH)
1725 continue;
1727 if (path[path_len - 1] != '/' && path[path_len - 1] != '\\')
1728 path[path_len++] = '\\';
1729 if (path_len + fname_len >= MAX_PATH)
1730 continue;
1732 memcpy(path + path_len, file, fname_len + 1);
1733 TRACE("Checking for file %s\n", path);
1734 if (GetFileAttributesA( path ) != INVALID_FILE_ATTRIBUTES)
1736 if (path_len + fname_len + 1 > count)
1738 MSVCRT_INVALID_PMT("buf[count] is too small", ERANGE);
1739 return ERANGE;
1741 memcpy(buf, path, path_len + fname_len + 1);
1742 return 0;
1746 *_errno() = ENOENT;
1747 return ENOENT;
1750 /*********************************************************************
1751 * _searchenv (MSVCRT.@)
1753 void CDECL _searchenv(const char* file, const char* env, char *buf)
1755 _searchenv_s(file, env, buf, MAX_PATH);
1758 /*********************************************************************
1759 * _wsearchenv_s (MSVCRT.@)
1761 int CDECL _wsearchenv_s(const wchar_t* file, const wchar_t* env,
1762 wchar_t *buf, size_t count)
1764 wchar_t *envVal, *penv, *end;
1765 wchar_t path[MAX_PATH];
1766 size_t path_len, fname_len;
1768 if (!MSVCRT_CHECK_PMT(file != NULL)) return EINVAL;
1769 if (!MSVCRT_CHECK_PMT(buf != NULL)) return EINVAL;
1770 if (!MSVCRT_CHECK_PMT(count > 0)) return EINVAL;
1772 if (count > MAX_PATH)
1773 FIXME("count > MAX_PATH not supported\n");
1775 fname_len = wcslen(file);
1776 *buf = '\0';
1778 /* Try CWD first */
1779 if (GetFileAttributesW( file ) != INVALID_FILE_ATTRIBUTES)
1781 if (GetFullPathNameW( file, count, buf, NULL )) return 0;
1782 msvcrt_set_errno(GetLastError());
1783 return 0;
1786 /* Search given environment variable */
1787 envVal = _wgetenv(env);
1788 if (!envVal)
1790 *_errno() = ENOENT;
1791 return ENOENT;
1794 penv = envVal;
1795 TRACE(":searching for %s in paths %s\n", debugstr_w(file), debugstr_w(envVal));
1797 for(; *penv; penv = (*end ? end + 1 : end))
1799 end = penv;
1800 path_len = 0;
1801 while(*end && *end != ';' && path_len < MAX_PATH)
1803 if (*end == '"')
1805 end++;
1806 while(*end && *end != '"' && path_len < MAX_PATH)
1808 path[path_len++] = *end;
1809 end++;
1811 if (*end == '"') end++;
1812 continue;
1815 path[path_len++] = *end;
1816 end++;
1818 if (!path_len || path_len >= MAX_PATH)
1819 continue;
1821 if (path[path_len - 1] != '/' && path[path_len - 1] != '\\')
1822 path[path_len++] = '\\';
1823 if (path_len + fname_len >= MAX_PATH)
1824 continue;
1826 memcpy(path + path_len, file, (fname_len + 1) * sizeof(wchar_t));
1827 TRACE("Checking for file %s\n", debugstr_w(path));
1828 if (GetFileAttributesW( path ) != INVALID_FILE_ATTRIBUTES)
1830 if (path_len + fname_len + 1 > count)
1832 MSVCRT_INVALID_PMT("buf[count] is too small", ERANGE);
1833 return ERANGE;
1835 memcpy(buf, path, (path_len + fname_len + 1) * sizeof(wchar_t));
1836 return 0;
1840 *_errno() = ENOENT;
1841 return ENOENT;
1844 /*********************************************************************
1845 * _wsearchenv (MSVCRT.@)
1847 void CDECL _wsearchenv(const wchar_t* file, const wchar_t* env, wchar_t *buf)
1849 _wsearchenv_s(file, env, buf, MAX_PATH);