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
25 #include "wine/port.h"
32 #include "wine/unicode.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
38 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata_t */
39 static void msvcrt_fttofd( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata_t* ft)
43 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
46 ft->attrib = fd->dwFileAttributes;
48 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
50 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
52 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
54 ft->size = fd->nFileSizeLow;
55 strcpy(ft->name, fd->cFileName);
58 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata32_t */
59 static void msvcrt_fttofd32( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata32_t* ft)
63 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
66 ft->attrib = fd->dwFileAttributes;
68 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
70 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
72 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
74 ft->size = fd->nFileSizeLow;
75 strcpy(ft->name, fd->cFileName);
78 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata_t */
79 static void msvcrt_wfttofd( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata_t* ft)
83 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
86 ft->attrib = fd->dwFileAttributes;
88 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
90 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
92 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
94 ft->size = fd->nFileSizeLow;
95 strcpyW(ft->name, fd->cFileName);
98 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata32_t */
99 static void msvcrt_wfttofd32(const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata32_t* ft)
103 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
106 ft->attrib = fd->dwFileAttributes;
108 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
109 ft->time_create = dw;
110 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
111 ft->time_access = dw;
112 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
114 ft->size = fd->nFileSizeLow;
115 strcpyW(ft->name, fd->cFileName);
118 /* INTERNAL: Translate WIN32_FIND_DATAA to finddatai64_t */
119 static void msvcrt_fttofdi64( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddatai64_t* ft)
123 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
126 ft->attrib = fd->dwFileAttributes;
128 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
129 ft->time_create = dw;
130 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
131 ft->time_access = dw;
132 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
134 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
135 strcpy(ft->name, fd->cFileName);
138 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata64_t */
139 static void msvcrt_fttofd64( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata64_t* ft)
143 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
146 ft->attrib = fd->dwFileAttributes;
148 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
149 ft->time_create = dw;
150 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
151 ft->time_access = dw;
152 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
154 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
155 strcpy(ft->name, fd->cFileName);
158 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata64_t */
159 static void msvcrt_wfttofd64( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata64_t* ft)
163 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
166 ft->attrib = fd->dwFileAttributes;
168 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
169 ft->time_create = dw;
170 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
171 ft->time_access = dw;
172 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
174 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
175 strcpyW(ft->name, fd->cFileName);
178 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata64i32_t */
179 static void msvcrt_fttofd64i32( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata64i32_t* ft)
183 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
186 ft->attrib = fd->dwFileAttributes;
188 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
189 ft->time_create = dw;
190 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
191 ft->time_access = dw;
192 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
194 ft->size = fd->nFileSizeLow;
195 strcpy(ft->name, fd->cFileName);
198 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddatai64_t */
199 static void msvcrt_wfttofdi64( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddatai64_t* ft)
203 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
206 ft->attrib = fd->dwFileAttributes;
208 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
209 ft->time_create = dw;
210 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
211 ft->time_access = dw;
212 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
214 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
215 strcpyW(ft->name, fd->cFileName);
218 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata64i32_t */
219 static void msvcrt_wfttofd64i32( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata64i32_t* ft)
223 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
226 ft->attrib = fd->dwFileAttributes;
228 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
229 ft->time_create = dw;
230 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
231 ft->time_access = dw;
232 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
234 ft->size = fd->nFileSizeLow;
235 strcpyW(ft->name, fd->cFileName);
238 /*********************************************************************
241 * Change the current working directory.
244 * newdir [I] Directory to change to
247 * Success: 0. The current working directory is set to newdir.
248 * Failure: -1. errno indicates the error.
251 * See SetCurrentDirectoryA.
253 int CDECL MSVCRT__chdir(const char * newdir)
255 if (!SetCurrentDirectoryA(newdir))
257 msvcrt_set_errno(newdir?GetLastError():0);
263 /*********************************************************************
266 * Unicode version of _chdir.
268 int CDECL MSVCRT__wchdir(const MSVCRT_wchar_t * newdir)
270 if (!SetCurrentDirectoryW(newdir))
272 msvcrt_set_errno(newdir?GetLastError():0);
278 /*********************************************************************
279 * _chdrive (MSVCRT.@)
281 * Change the current drive.
284 * newdrive [I] Drive number to change to (1 = 'A', 2 = 'B', ...)
287 * Success: 0. The current drive is set to newdrive.
288 * Failure: -1. errno indicates the error.
291 * See SetCurrentDirectoryA.
293 int CDECL MSVCRT__chdrive(int newdrive)
295 WCHAR buffer[] = {'A', ':', 0};
297 buffer[0] += newdrive - 1;
298 if (!SetCurrentDirectoryW( buffer ))
300 msvcrt_set_errno(GetLastError());
302 *MSVCRT__errno() = MSVCRT_EACCES;
308 /*********************************************************************
309 * _findclose (MSVCRT.@)
311 * Close a handle returned by _findfirst().
314 * hand [I] Handle to close
317 * Success: 0. All resources associated with hand are freed.
318 * Failure: -1. errno indicates the error.
323 int CDECL MSVCRT__findclose(MSVCRT_intptr_t hand)
325 TRACE(":handle %ld\n",hand);
326 if (!FindClose((HANDLE)hand))
328 msvcrt_set_errno(GetLastError());
334 /*********************************************************************
335 * _findfirst (MSVCRT.@)
337 * Open a handle for iterating through a directory.
340 * fspec [I] File specification of files to iterate.
341 * ft [O] Information for the first file found.
344 * Success: A handle suitable for passing to _findnext() and _findclose().
345 * ft is populated with the details of the found file.
346 * Failure: -1. errno indicates the error.
349 * See FindFirstFileA.
351 MSVCRT_intptr_t CDECL MSVCRT__findfirst(const char * fspec, struct MSVCRT__finddata_t* ft)
353 WIN32_FIND_DATAA find_data;
356 hfind = FindFirstFileA(fspec, &find_data);
357 if (hfind == INVALID_HANDLE_VALUE)
359 msvcrt_set_errno(GetLastError());
362 msvcrt_fttofd(&find_data,ft);
363 TRACE(":got handle %p\n",hfind);
364 return (MSVCRT_intptr_t)hfind;
367 /*********************************************************************
368 * _findfirst32 (MSVCRT.@)
370 MSVCRT_intptr_t CDECL MSVCRT__findfirst32(const char * fspec, struct MSVCRT__finddata32_t* ft)
372 WIN32_FIND_DATAA find_data;
375 hfind = FindFirstFileA(fspec, &find_data);
376 if (hfind == INVALID_HANDLE_VALUE)
378 msvcrt_set_errno(GetLastError());
381 msvcrt_fttofd32(&find_data, ft);
382 TRACE(":got handle %p\n", hfind);
383 return (MSVCRT_intptr_t)hfind;
386 /*********************************************************************
387 * _wfindfirst (MSVCRT.@)
389 * Unicode version of _findfirst.
391 MSVCRT_intptr_t CDECL MSVCRT__wfindfirst(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddata_t* ft)
393 WIN32_FIND_DATAW find_data;
396 hfind = FindFirstFileW(fspec, &find_data);
397 if (hfind == INVALID_HANDLE_VALUE)
399 msvcrt_set_errno(GetLastError());
402 msvcrt_wfttofd(&find_data,ft);
403 TRACE(":got handle %p\n",hfind);
404 return (MSVCRT_intptr_t)hfind;
407 /*********************************************************************
408 * _wfindfirst32 (MSVCRT.@)
410 * Unicode version of _findfirst32.
412 MSVCRT_intptr_t CDECL MSVCRT__wfindfirst32(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddata32_t* ft)
414 WIN32_FIND_DATAW find_data;
417 hfind = FindFirstFileW(fspec, &find_data);
418 if (hfind == INVALID_HANDLE_VALUE)
420 msvcrt_set_errno(GetLastError());
423 msvcrt_wfttofd32(&find_data, ft);
424 TRACE(":got handle %p\n", hfind);
425 return (MSVCRT_intptr_t)hfind;
428 /*********************************************************************
429 * _findfirsti64 (MSVCRT.@)
431 * 64-bit version of _findfirst.
433 MSVCRT_intptr_t CDECL MSVCRT__findfirsti64(const char * fspec, struct MSVCRT__finddatai64_t* ft)
435 WIN32_FIND_DATAA find_data;
438 hfind = FindFirstFileA(fspec, &find_data);
439 if (hfind == INVALID_HANDLE_VALUE)
441 msvcrt_set_errno(GetLastError());
444 msvcrt_fttofdi64(&find_data,ft);
445 TRACE(":got handle %p\n",hfind);
446 return (MSVCRT_intptr_t)hfind;
449 /*********************************************************************
450 * _findfirst64 (MSVCRT.@)
452 * 64-bit version of _findfirst.
454 MSVCRT_intptr_t CDECL MSVCRT__findfirst64(const char * fspec, struct MSVCRT__finddata64_t* ft)
456 WIN32_FIND_DATAA find_data;
459 hfind = FindFirstFileA(fspec, &find_data);
460 if (hfind == INVALID_HANDLE_VALUE)
462 msvcrt_set_errno(GetLastError());
465 msvcrt_fttofd64(&find_data,ft);
466 TRACE(":got handle %p\n",hfind);
467 return (MSVCRT_intptr_t)hfind;
470 /*********************************************************************
471 * _wfindfirst64 (MSVCRT.@)
473 * Unicode version of _findfirst64.
475 MSVCRT_intptr_t CDECL MSVCRT__wfindfirst64(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddata64_t* ft)
477 WIN32_FIND_DATAW find_data;
480 hfind = FindFirstFileW(fspec, &find_data);
481 if (hfind == INVALID_HANDLE_VALUE)
483 msvcrt_set_errno(GetLastError());
486 msvcrt_wfttofd64(&find_data,ft);
487 TRACE(":got handle %p\n",hfind);
488 return (MSVCRT_intptr_t)hfind;
491 /*********************************************************************
492 * _findfirst64i32 (MSVCRT.@)
494 * 64-bit/32-bit version of _findfirst.
496 MSVCRT_intptr_t CDECL MSVCRT__findfirst64i32(const char * fspec, struct MSVCRT__finddata64i32_t* ft)
498 WIN32_FIND_DATAA find_data;
501 hfind = FindFirstFileA(fspec, &find_data);
502 if (hfind == INVALID_HANDLE_VALUE)
504 msvcrt_set_errno(GetLastError());
507 msvcrt_fttofd64i32(&find_data,ft);
508 TRACE(":got handle %p\n",hfind);
509 return (MSVCRT_intptr_t)hfind;
512 /*********************************************************************
513 * _wfindfirst64i32 (MSVCRT.@)
515 * Unicode version of _findfirst64i32.
517 MSVCRT_intptr_t CDECL MSVCRT__wfindfirst64i32(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddata64i32_t* ft)
519 WIN32_FIND_DATAW find_data;
522 hfind = FindFirstFileW(fspec, &find_data);
523 if (hfind == INVALID_HANDLE_VALUE)
525 msvcrt_set_errno(GetLastError());
528 msvcrt_wfttofd64i32(&find_data,ft);
529 TRACE(":got handle %p\n",hfind);
530 return (MSVCRT_intptr_t)hfind;
533 /*********************************************************************
534 * _wfindfirsti64 (MSVCRT.@)
536 * Unicode version of _findfirsti64.
538 MSVCRT_intptr_t CDECL MSVCRT__wfindfirsti64(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddatai64_t* ft)
540 WIN32_FIND_DATAW find_data;
543 hfind = FindFirstFileW(fspec, &find_data);
544 if (hfind == INVALID_HANDLE_VALUE)
546 msvcrt_set_errno(GetLastError());
549 msvcrt_wfttofdi64(&find_data,ft);
550 TRACE(":got handle %p\n",hfind);
551 return (MSVCRT_intptr_t)hfind;
554 /*********************************************************************
555 * _findnext (MSVCRT.@)
557 * Find the next file from a file search handle.
560 * hand [I] Handle to the search returned from _findfirst().
561 * ft [O] Information for the file found.
564 * Success: 0. ft is populated with the details of the found file.
565 * Failure: -1. errno indicates the error.
570 int CDECL MSVCRT__findnext(MSVCRT_intptr_t hand, struct MSVCRT__finddata_t * ft)
572 WIN32_FIND_DATAA find_data;
574 if (!FindNextFileA((HANDLE)hand, &find_data))
576 *MSVCRT__errno() = MSVCRT_ENOENT;
580 msvcrt_fttofd(&find_data,ft);
584 /*********************************************************************
585 * _findnext32 (MSVCRT.@)
587 int CDECL MSVCRT__findnext32(MSVCRT_intptr_t hand, struct MSVCRT__finddata32_t * ft)
589 WIN32_FIND_DATAA find_data;
591 if (!FindNextFileA((HANDLE)hand, &find_data))
593 *MSVCRT__errno() = MSVCRT_ENOENT;
597 msvcrt_fttofd32(&find_data, ft);
601 /*********************************************************************
602 * _wfindnext (MSVCRT.@)
604 * Unicode version of _findnext.
606 int CDECL MSVCRT__wfindnext(MSVCRT_intptr_t hand, struct MSVCRT__wfinddata_t * ft)
608 WIN32_FIND_DATAW find_data;
610 if (!FindNextFileW((HANDLE)hand, &find_data))
612 *MSVCRT__errno() = MSVCRT_ENOENT;
616 msvcrt_wfttofd(&find_data,ft);
620 /*********************************************************************
621 * _findnexti64 (MSVCRT.@)
623 * 64-bit version of _findnext.
625 int CDECL MSVCRT__findnexti64(MSVCRT_intptr_t hand, struct MSVCRT__finddatai64_t * ft)
627 WIN32_FIND_DATAA find_data;
629 if (!FindNextFileA((HANDLE)hand, &find_data))
631 *MSVCRT__errno() = MSVCRT_ENOENT;
635 msvcrt_fttofdi64(&find_data,ft);
639 /*********************************************************************
640 * _findnext64 (MSVCRT.@)
642 * 64-bit version of _findnext.
644 int CDECL MSVCRT__findnext64(MSVCRT_intptr_t hand, struct MSVCRT__finddata64_t * ft)
646 WIN32_FIND_DATAA find_data;
648 if (!FindNextFileA((HANDLE)hand, &find_data))
650 *MSVCRT__errno() = MSVCRT_ENOENT;
654 msvcrt_fttofd64(&find_data,ft);
658 /*********************************************************************
659 * _wfindnext64 (MSVCRT.@)
661 * Unicode version of _wfindnext64.
663 int CDECL MSVCRT__wfindnext64(MSVCRT_intptr_t hand, struct MSVCRT__wfinddata64_t * ft)
665 WIN32_FIND_DATAW find_data;
667 if (!FindNextFileW((HANDLE)hand, &find_data))
669 *MSVCRT__errno() = MSVCRT_ENOENT;
673 msvcrt_wfttofd64(&find_data,ft);
677 /*********************************************************************
678 * _findnext64i32 (MSVCRT.@)
680 * 64-bit/32-bit version of _findnext.
682 int CDECL MSVCRT__findnext64i32(MSVCRT_intptr_t hand, struct MSVCRT__finddata64i32_t * ft)
684 WIN32_FIND_DATAA find_data;
686 if (!FindNextFileA((HANDLE)hand, &find_data))
688 *MSVCRT__errno() = MSVCRT_ENOENT;
692 msvcrt_fttofd64i32(&find_data,ft);
696 /*********************************************************************
697 * _wfindnexti64 (MSVCRT.@)
699 * Unicode version of _findnexti64.
701 int CDECL MSVCRT__wfindnexti64(MSVCRT_intptr_t hand, struct MSVCRT__wfinddatai64_t * ft)
703 WIN32_FIND_DATAW find_data;
705 if (!FindNextFileW((HANDLE)hand, &find_data))
707 *MSVCRT__errno() = MSVCRT_ENOENT;
711 msvcrt_wfttofdi64(&find_data,ft);
715 /*********************************************************************
716 * _wfindnext64i32 (MSVCRT.@)
718 * Unicode version of _findnext64i32.
720 int CDECL MSVCRT__wfindnext64i32(MSVCRT_intptr_t hand, struct MSVCRT__wfinddata64i32_t * ft)
722 WIN32_FIND_DATAW find_data;
724 if (!FindNextFileW((HANDLE)hand, &find_data))
726 *MSVCRT__errno() = MSVCRT_ENOENT;
730 msvcrt_wfttofd64i32(&find_data,ft);
734 /*********************************************************************
737 * Get the current working directory.
740 * buf [O] Destination for current working directory.
741 * size [I] Size of buf in characters
744 * Success: If buf is NULL, returns an allocated string containing the path.
745 * Otherwise populates buf with the path and returns it.
746 * Failure: NULL. errno indicates the error.
748 char* CDECL MSVCRT__getcwd(char * buf, int size)
751 int dir_len = GetCurrentDirectoryA(MAX_PATH,dir);
754 return NULL; /* FIXME: Real return value untested */
758 if (size <= dir_len) size = dir_len + 1;
759 if (!(buf = MSVCRT_malloc( size ))) return NULL;
761 else if (dir_len >= size)
763 *MSVCRT__errno() = MSVCRT_ERANGE;
764 return NULL; /* buf too small */
770 /*********************************************************************
771 * _wgetcwd (MSVCRT.@)
773 * Unicode version of _getcwd.
775 MSVCRT_wchar_t* CDECL MSVCRT__wgetcwd(MSVCRT_wchar_t * buf, int size)
777 MSVCRT_wchar_t dir[MAX_PATH];
778 int dir_len = GetCurrentDirectoryW(MAX_PATH,dir);
781 return NULL; /* FIXME: Real return value untested */
785 if (size <= dir_len) size = dir_len + 1;
786 if (!(buf = MSVCRT_malloc( size * sizeof(WCHAR) ))) return NULL;
790 *MSVCRT__errno() = MSVCRT_ERANGE;
791 return NULL; /* buf too small */
797 /*********************************************************************
798 * _getdrive (MSVCRT.@)
800 * Get the current drive number.
806 * Success: The drive letter number from 1 to 26 ("A:" to "Z:").
809 int CDECL MSVCRT__getdrive(void)
811 WCHAR buffer[MAX_PATH];
812 if (GetCurrentDirectoryW( MAX_PATH, buffer ) &&
813 buffer[0] >= 'A' && buffer[0] <= 'z' && buffer[1] == ':')
814 return toupperW(buffer[0]) - 'A' + 1;
818 /*********************************************************************
819 * _getdcwd (MSVCRT.@)
821 * Get the current working directory on a given disk.
824 * drive [I] Drive letter to get the current working directory from.
825 * buf [O] Destination for the current working directory.
826 * size [I] Length of drive in characters.
829 * Success: If drive is NULL, returns an allocated string containing the path.
830 * Otherwise populates drive with the path and returns it.
831 * Failure: NULL. errno indicates the error.
833 char* CDECL MSVCRT__getdcwd(int drive, char * buf, int size)
837 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
839 if (!drive || drive == MSVCRT__getdrive())
840 return MSVCRT__getcwd(buf,size); /* current */
844 char drivespec[] = {'A', ':', 0};
847 drivespec[0] += drive - 1;
848 if (GetDriveTypeA(drivespec) < DRIVE_REMOVABLE)
850 *MSVCRT__errno() = MSVCRT_EACCES;
854 dir_len = GetFullPathNameA(drivespec,MAX_PATH,dir,&dummy);
855 if (dir_len >= size || dir_len < 1)
857 *MSVCRT__errno() = MSVCRT_ERANGE;
858 return NULL; /* buf too small */
861 TRACE(":returning '%s'\n", dir);
863 return MSVCRT__strdup(dir); /* allocate */
870 /*********************************************************************
871 * _wgetdcwd (MSVCRT.@)
873 * Unicode version of _wgetdcwd.
875 MSVCRT_wchar_t* CDECL MSVCRT__wgetdcwd(int drive, MSVCRT_wchar_t * buf, int size)
877 static MSVCRT_wchar_t* dummy;
879 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
881 if (!drive || drive == MSVCRT__getdrive())
882 return MSVCRT__wgetcwd(buf,size); /* current */
885 MSVCRT_wchar_t dir[MAX_PATH];
886 MSVCRT_wchar_t drivespec[4] = {'A', ':', '\\', 0};
889 drivespec[0] += drive - 1;
890 if (GetDriveTypeW(drivespec) < DRIVE_REMOVABLE)
892 *MSVCRT__errno() = MSVCRT_EACCES;
896 dir_len = GetFullPathNameW(drivespec,MAX_PATH,dir,&dummy);
897 if (dir_len >= size || dir_len < 1)
899 *MSVCRT__errno() = MSVCRT_ERANGE;
900 return NULL; /* buf too small */
903 TRACE(":returning %s\n", debugstr_w(dir));
905 return MSVCRT__wcsdup(dir); /* allocate */
911 /*********************************************************************
912 * _getdiskfree (MSVCRT.@)
914 * Get information about the free space on a drive.
917 * disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
918 * info [O] Destination for the resulting information.
921 * Success: 0. info is updated with the free space information.
922 * Failure: An error code from GetLastError().
925 * See GetLastError().
927 unsigned int CDECL MSVCRT__getdiskfree(unsigned int disk, struct MSVCRT__diskfree_t * d)
929 WCHAR drivespec[] = {'@', ':', '\\', 0};
934 return ERROR_INVALID_PARAMETER; /* MSVCRT doesn't set errno here */
936 drivespec[0] += disk; /* make a drive letter */
938 if (GetDiskFreeSpaceW(disk==0?NULL:drivespec,ret,ret+1,ret+2,ret+3))
940 d->sectors_per_cluster = ret[0];
941 d->bytes_per_sector = ret[1];
942 d->avail_clusters = ret[2];
943 d->total_clusters = ret[3];
946 err = GetLastError();
947 msvcrt_set_errno(err);
951 /*********************************************************************
954 * Create a directory.
957 * newdir [I] Name of directory to create.
960 * Success: 0. The directory indicated by newdir is created.
961 * Failure: -1. errno indicates the error.
964 * See CreateDirectoryA.
966 int CDECL MSVCRT__mkdir(const char * newdir)
968 if (CreateDirectoryA(newdir,NULL))
970 msvcrt_set_errno(GetLastError());
974 /*********************************************************************
977 * Unicode version of _mkdir.
979 int CDECL MSVCRT__wmkdir(const MSVCRT_wchar_t* newdir)
981 if (CreateDirectoryW(newdir,NULL))
983 msvcrt_set_errno(GetLastError());
987 /*********************************************************************
990 * Delete a directory.
993 * dir [I] Name of directory to delete.
996 * Success: 0. The directory indicated by newdir is deleted.
997 * Failure: -1. errno indicates the error.
1000 * See RemoveDirectoryA.
1002 int CDECL MSVCRT__rmdir(const char * dir)
1004 if (RemoveDirectoryA(dir))
1006 msvcrt_set_errno(GetLastError());
1010 /*********************************************************************
1011 * _wrmdir (MSVCRT.@)
1013 * Unicode version of _rmdir.
1015 int CDECL MSVCRT__wrmdir(const MSVCRT_wchar_t * dir)
1017 if (RemoveDirectoryW(dir))
1019 msvcrt_set_errno(GetLastError());
1023 /******************************************************************
1024 * _splitpath_s (MSVCRT.@)
1026 int CDECL _splitpath_s(const char* inpath,
1027 char* drive, MSVCRT_size_t sz_drive,
1028 char* dir, MSVCRT_size_t sz_dir,
1029 char* fname, MSVCRT_size_t sz_fname,
1030 char* ext, MSVCRT_size_t sz_ext)
1032 const char *p, *end;
1034 if (!inpath || (!drive && sz_drive) ||
1035 (drive && !sz_drive) ||
1038 (!fname && sz_fname) ||
1039 (fname && !sz_fname) ||
1043 *MSVCRT__errno() = MSVCRT_EINVAL;
1044 return MSVCRT_EINVAL;
1047 if (inpath[0] && inpath[1] == ':')
1051 if (sz_drive <= 2) goto do_error;
1052 drive[0] = inpath[0];
1053 drive[1] = inpath[1];
1058 else if (drive) drive[0] = '\0';
1060 /* look for end of directory part */
1062 for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
1064 if (end) /* got a directory */
1068 if (sz_dir <= end - inpath) goto do_error;
1069 memcpy( dir, inpath, (end - inpath) );
1070 dir[end - inpath] = 0;
1074 else if (dir) dir[0] = 0;
1076 /* look for extension: what's after the last dot */
1078 for (p = inpath; *p; p++) if (*p == '.') end = p;
1080 if (!end) end = p; /* there's no extension */
1084 if (sz_fname <= end - inpath) goto do_error;
1085 memcpy( fname, inpath, (end - inpath) );
1086 fname[end - inpath] = 0;
1090 if (sz_ext <= strlen(end)) goto do_error;
1095 if (drive) drive[0] = '\0';
1096 if (dir) dir[0] = '\0';
1097 if (fname) fname[0]= '\0';
1098 if (ext) ext[0]= '\0';
1099 *MSVCRT__errno() = MSVCRT_ERANGE;
1100 return MSVCRT_ERANGE;
1103 /*********************************************************************
1104 * _splitpath (MSVCRT.@)
1106 void CDECL _splitpath(const char *inpath, char *drv, char *dir,
1107 char *fname, char *ext)
1109 _splitpath_s(inpath, drv, drv?MSVCRT__MAX_DRIVE:0, dir, dir?MSVCRT__MAX_DIR:0,
1110 fname, fname?MSVCRT__MAX_FNAME:0, ext, ext?MSVCRT__MAX_EXT:0);
1113 /******************************************************************
1114 * _wsplitpath_s (MSVCRT.@)
1116 * Secure version of _wsplitpath
1118 int CDECL _wsplitpath_s(const MSVCRT_wchar_t* inpath,
1119 MSVCRT_wchar_t* drive, MSVCRT_size_t sz_drive,
1120 MSVCRT_wchar_t* dir, MSVCRT_size_t sz_dir,
1121 MSVCRT_wchar_t* fname, MSVCRT_size_t sz_fname,
1122 MSVCRT_wchar_t* ext, MSVCRT_size_t sz_ext)
1124 const MSVCRT_wchar_t *p, *end;
1126 if (!inpath || (!drive && sz_drive) ||
1127 (drive && !sz_drive) ||
1130 (!fname && sz_fname) ||
1131 (fname && !sz_fname) ||
1135 *MSVCRT__errno() = MSVCRT_EINVAL;
1136 return MSVCRT_EINVAL;
1139 if (inpath[0] && inpath[1] == ':')
1143 if (sz_drive <= 2) goto do_error;
1144 drive[0] = inpath[0];
1145 drive[1] = inpath[1];
1150 else if (drive) drive[0] = '\0';
1152 /* look for end of directory part */
1154 for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
1156 if (end) /* got a directory */
1160 if (sz_dir <= end - inpath) goto do_error;
1161 memcpy( dir, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
1162 dir[end - inpath] = 0;
1166 else if (dir) dir[0] = 0;
1168 /* look for extension: what's after the last dot */
1170 for (p = inpath; *p; p++) if (*p == '.') end = p;
1172 if (!end) end = p; /* there's no extension */
1176 if (sz_fname <= end - inpath) goto do_error;
1177 memcpy( fname, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
1178 fname[end - inpath] = 0;
1182 if (sz_ext <= strlenW(end)) goto do_error;
1183 strcpyW( ext, end );
1187 if (drive) drive[0] = '\0';
1188 if (dir) dir[0] = '\0';
1189 if (fname) fname[0]= '\0';
1190 if (ext) ext[0]= '\0';
1191 *MSVCRT__errno() = MSVCRT_ERANGE;
1192 return MSVCRT_ERANGE;
1195 /*********************************************************************
1196 * _wsplitpath (MSVCRT.@)
1198 * Unicode version of _splitpath.
1200 void CDECL _wsplitpath(const MSVCRT_wchar_t *inpath, MSVCRT_wchar_t *drv, MSVCRT_wchar_t *dir,
1201 MSVCRT_wchar_t *fname, MSVCRT_wchar_t *ext)
1203 _wsplitpath_s(inpath, drv, drv?MSVCRT__MAX_DRIVE:0, dir, dir?MSVCRT__MAX_DIR:0,
1204 fname, fname?MSVCRT__MAX_FNAME:0, ext, ext?MSVCRT__MAX_EXT:0);
1207 /*********************************************************************
1208 * _wfullpath (MSVCRT.@)
1210 * Unicode version of _fullpath.
1212 MSVCRT_wchar_t * CDECL _wfullpath(MSVCRT_wchar_t * absPath, const MSVCRT_wchar_t* relPath, MSVCRT_size_t size)
1217 BOOL alloced = FALSE;
1219 if (!relPath || !*relPath)
1220 return MSVCRT__wgetcwd(absPath, size);
1222 if (absPath == NULL)
1224 buffer = MSVCRT_malloc(MAX_PATH * sizeof(WCHAR));
1233 *MSVCRT__errno() = MSVCRT_ERANGE;
1237 TRACE(":resolving relative path %s\n",debugstr_w(relPath));
1239 rc = GetFullPathNameW(relPath,size,buffer,&lastpart);
1241 if (rc > 0 && rc <= size )
1246 MSVCRT_free(buffer);
1251 /*********************************************************************
1252 * _fullpath (MSVCRT.@)
1254 * Create an absolute path from a relative path.
1257 * absPath [O] Destination for absolute path
1258 * relPath [I] Relative path to convert to absolute
1259 * size [I] Length of absPath in characters.
1262 * Success: If absPath is NULL, returns an allocated string containing the path.
1263 * Otherwise populates absPath with the path and returns it.
1264 * Failure: NULL. errno indicates the error.
1266 char * CDECL _fullpath(char * absPath, const char* relPath, unsigned int size)
1271 BOOL alloced = FALSE;
1273 if (!relPath || !*relPath)
1274 return MSVCRT__getcwd(absPath, size);
1276 if (absPath == NULL)
1278 buffer = MSVCRT_malloc(MAX_PATH);
1287 *MSVCRT__errno() = MSVCRT_ERANGE;
1291 TRACE(":resolving relative path '%s'\n",relPath);
1293 rc = GetFullPathNameA(relPath,size,buffer,&lastpart);
1295 if (rc > 0 && rc <= size)
1300 MSVCRT_free(buffer);
1305 /*********************************************************************
1306 * _makepath (MSVCRT.@)
1308 * Create a pathname.
1311 * path [O] Destination for created pathname
1312 * drive [I] Drive letter (e.g. "A:")
1313 * directory [I] Directory
1314 * filename [I] Name of the file, excluding extension
1315 * extension [I] File extension (e.g. ".TXT")
1318 * Nothing. If path is not large enough to hold the resulting pathname,
1319 * random process memory will be overwritten.
1321 VOID CDECL _makepath(char * path, const char * drive,
1322 const char *directory, const char * filename,
1323 const char * extension)
1327 TRACE("(%s %s %s %s)\n", debugstr_a(drive), debugstr_a(directory),
1328 debugstr_a(filename), debugstr_a(extension) );
1333 if (drive && drive[0])
1338 if (directory && directory[0])
1340 unsigned int len = strlen(directory);
1341 memmove(p, directory, len);
1343 if (p[-1] != '/' && p[-1] != '\\')
1346 if (filename && filename[0])
1348 unsigned int len = strlen(filename);
1349 memmove(p, filename, len);
1352 if (extension && extension[0])
1354 if (extension[0] != '.')
1356 strcpy(p, extension);
1360 TRACE("returning %s\n",path);
1363 /*********************************************************************
1364 * _wmakepath (MSVCRT.@)
1366 * Unicode version of _wmakepath.
1368 VOID CDECL _wmakepath(MSVCRT_wchar_t *path, const MSVCRT_wchar_t *drive, const MSVCRT_wchar_t *directory,
1369 const MSVCRT_wchar_t *filename, const MSVCRT_wchar_t *extension)
1371 MSVCRT_wchar_t *p = path;
1373 TRACE("%s %s %s %s\n", debugstr_w(drive), debugstr_w(directory),
1374 debugstr_w(filename), debugstr_w(extension));
1379 if (drive && drive[0])
1384 if (directory && directory[0])
1386 unsigned int len = strlenW(directory);
1387 memmove(p, directory, len * sizeof(MSVCRT_wchar_t));
1389 if (p[-1] != '/' && p[-1] != '\\')
1392 if (filename && filename[0])
1394 unsigned int len = strlenW(filename);
1395 memmove(p, filename, len * sizeof(MSVCRT_wchar_t));
1398 if (extension && extension[0])
1400 if (extension[0] != '.')
1402 strcpyW(p, extension);
1407 TRACE("returning %s\n", debugstr_w(path));
1410 /*********************************************************************
1411 * _makepath_s (MSVCRT.@)
1413 * Safe version of _makepath.
1415 int CDECL _makepath_s(char *path, MSVCRT_size_t size, const char *drive,
1416 const char *directory, const char *filename,
1417 const char *extension)
1423 *MSVCRT__errno() = MSVCRT_EINVAL;
1424 return MSVCRT_EINVAL;
1427 if (drive && drive[0])
1437 if (directory && directory[0])
1439 unsigned int len = strlen(directory);
1440 unsigned int needs_separator = directory[len - 1] != '/' && directory[len - 1] != '\\';
1441 unsigned int copylen = min(size - 1, len);
1446 memmove(p, directory, copylen);
1454 if (needs_separator)
1464 if (filename && filename[0])
1466 unsigned int len = strlen(filename);
1467 unsigned int copylen = min(size - 1, len);
1472 memmove(p, filename, copylen);
1481 if (extension && extension[0])
1483 unsigned int len = strlen(extension);
1484 unsigned int needs_period = extension[0] != '.';
1485 unsigned int copylen;
1496 copylen = min(size - 1, len);
1497 memcpy(p, extension, copylen);
1510 *MSVCRT__errno() = MSVCRT_ERANGE;
1511 return MSVCRT_ERANGE;
1514 /*********************************************************************
1515 * _wmakepath_s (MSVCRT.@)
1517 * Safe version of _wmakepath.
1519 int CDECL _wmakepath_s(MSVCRT_wchar_t *path, MSVCRT_size_t size, const MSVCRT_wchar_t *drive,
1520 const MSVCRT_wchar_t *directory, const MSVCRT_wchar_t *filename,
1521 const MSVCRT_wchar_t *extension)
1523 MSVCRT_wchar_t *p = path;
1527 *MSVCRT__errno() = MSVCRT_EINVAL;
1528 return MSVCRT_EINVAL;
1531 if (drive && drive[0])
1541 if (directory && directory[0])
1543 unsigned int len = strlenW(directory);
1544 unsigned int needs_separator = directory[len - 1] != '/' && directory[len - 1] != '\\';
1545 unsigned int copylen = min(size - 1, len);
1550 memmove(p, directory, copylen * sizeof(MSVCRT_wchar_t));
1558 if (needs_separator)
1568 if (filename && filename[0])
1570 unsigned int len = strlenW(filename);
1571 unsigned int copylen = min(size - 1, len);
1576 memmove(p, filename, copylen * sizeof(MSVCRT_wchar_t));
1585 if (extension && extension[0])
1587 unsigned int len = strlenW(extension);
1588 unsigned int needs_period = extension[0] != '.';
1589 unsigned int copylen;
1600 copylen = min(size - 1, len);
1601 memcpy(p, extension, copylen * sizeof(MSVCRT_wchar_t));
1614 *MSVCRT__errno() = MSVCRT_ERANGE;
1615 return MSVCRT_ERANGE;
1618 /*********************************************************************
1619 * _searchenv (MSVCRT.@)
1621 * Search for a file in a list of paths from an environment variable.
1624 * file [I] Name of the file to search for.
1625 * env [I] Name of the environment variable containing a list of paths.
1626 * buf [O] Destination for the found file path.
1629 * Nothing. If the file is not found, buf will contain an empty string
1632 void CDECL MSVCRT__searchenv(const char* file, const char* env, char *buf)
1635 char curPath[MAX_PATH];
1640 if (GetFileAttributesA( file ) != INVALID_FILE_ATTRIBUTES)
1642 GetFullPathNameA( file, MAX_PATH, buf, NULL );
1643 /* Sigh. This error is *always* set, regardless of success */
1644 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1648 /* Search given environment variable */
1649 envVal = MSVCRT_getenv(env);
1652 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1657 TRACE(":searching for %s in paths %s\n", file, envVal);
1663 while(*end && *end != ';') end++; /* Find end of next path */
1664 if (penv == end || !*penv)
1666 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1669 memcpy(curPath, penv, end - penv);
1670 if (curPath[end - penv] != '/' && curPath[end - penv] != '\\')
1672 curPath[end - penv] = '\\';
1673 curPath[end - penv + 1] = '\0';
1676 curPath[end - penv] = '\0';
1678 strcat(curPath, file);
1679 TRACE("Checking for file %s\n", curPath);
1680 if (GetFileAttributesA( curPath ) != INVALID_FILE_ATTRIBUTES)
1682 strcpy(buf, curPath);
1683 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1686 penv = *end ? end + 1 : end;
1690 /*********************************************************************
1691 * _searchenv_s (MSVCRT.@)
1693 int CDECL _searchenv_s(const char* file, const char* env, char *buf, MSVCRT_size_t count)
1696 char curPath[MAX_PATH];
1698 if (!MSVCRT_CHECK_PMT(file != NULL)) return MSVCRT_EINVAL;
1699 if (!MSVCRT_CHECK_PMT(buf != NULL)) return MSVCRT_EINVAL;
1700 if (!MSVCRT_CHECK_PMT(count > 0)) return MSVCRT_EINVAL;
1705 if (GetFileAttributesA( file ) != INVALID_FILE_ATTRIBUTES)
1707 if (GetFullPathNameA( file, count, buf, NULL )) return 0;
1708 msvcrt_set_errno(GetLastError());
1712 /* Search given environment variable */
1713 envVal = MSVCRT_getenv(env);
1716 *MSVCRT__errno() = MSVCRT_ENOENT;
1717 return MSVCRT_ENOENT;
1721 TRACE(":searching for %s in paths %s\n", file, envVal);
1727 while(*end && *end != ';') end++; /* Find end of next path */
1728 if (penv == end || !*penv)
1730 *MSVCRT__errno() = MSVCRT_ENOENT;
1731 return MSVCRT_ENOENT;
1733 memcpy(curPath, penv, end - penv);
1734 if (curPath[end - penv] != '/' && curPath[end - penv] != '\\')
1736 curPath[end - penv] = '\\';
1737 curPath[end - penv + 1] = '\0';
1740 curPath[end - penv] = '\0';
1742 strcat(curPath, file);
1743 TRACE("Checking for file %s\n", curPath);
1744 if (GetFileAttributesA( curPath ) != INVALID_FILE_ATTRIBUTES)
1746 if (strlen(curPath) + 1 > count)
1748 MSVCRT_INVALID_PMT("buf[count] is too small", MSVCRT_ERANGE);
1749 return MSVCRT_ERANGE;
1751 strcpy(buf, curPath);
1754 penv = *end ? end + 1 : end;
1758 /*********************************************************************
1759 * _wsearchenv (MSVCRT.@)
1761 * Unicode version of _searchenv
1763 void CDECL MSVCRT__wsearchenv(const MSVCRT_wchar_t* file, const MSVCRT_wchar_t* env, MSVCRT_wchar_t *buf)
1765 MSVCRT_wchar_t *envVal, *penv;
1766 MSVCRT_wchar_t curPath[MAX_PATH];
1771 if (GetFileAttributesW( file ) != INVALID_FILE_ATTRIBUTES)
1773 GetFullPathNameW( file, MAX_PATH, buf, NULL );
1774 /* Sigh. This error is *always* set, regardless of success */
1775 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1779 /* Search given environment variable */
1780 envVal = MSVCRT__wgetenv(env);
1783 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1788 TRACE(":searching for %s in paths %s\n", debugstr_w(file), debugstr_w(envVal));
1792 MSVCRT_wchar_t *end = penv;
1794 while(*end && *end != ';') end++; /* Find end of next path */
1795 if (penv == end || !*penv)
1797 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1800 memcpy(curPath, penv, (end - penv) * sizeof(MSVCRT_wchar_t));
1801 if (curPath[end - penv] != '/' && curPath[end - penv] != '\\')
1803 curPath[end - penv] = '\\';
1804 curPath[end - penv + 1] = '\0';
1807 curPath[end - penv] = '\0';
1809 strcatW(curPath, file);
1810 TRACE("Checking for file %s\n", debugstr_w(curPath));
1811 if (GetFileAttributesW( curPath ) != INVALID_FILE_ATTRIBUTES)
1813 strcpyW(buf, curPath);
1814 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1817 penv = *end ? end + 1 : end;
1821 /*********************************************************************
1822 * _wsearchenv_s (MSVCRT.@)
1824 int CDECL _wsearchenv_s(const MSVCRT_wchar_t* file, const MSVCRT_wchar_t* env,
1825 MSVCRT_wchar_t *buf, MSVCRT_size_t count)
1827 MSVCRT_wchar_t* envVal, *penv;
1828 MSVCRT_wchar_t curPath[MAX_PATH];
1830 if (!MSVCRT_CHECK_PMT(file != NULL)) return MSVCRT_EINVAL;
1831 if (!MSVCRT_CHECK_PMT(buf != NULL)) return MSVCRT_EINVAL;
1832 if (!MSVCRT_CHECK_PMT(count > 0)) return MSVCRT_EINVAL;
1837 if (GetFileAttributesW( file ) != INVALID_FILE_ATTRIBUTES)
1839 if (GetFullPathNameW( file, count, buf, NULL )) return 0;
1840 msvcrt_set_errno(GetLastError());
1844 /* Search given environment variable */
1845 envVal = MSVCRT__wgetenv(env);
1848 *MSVCRT__errno() = MSVCRT_ENOENT;
1849 return MSVCRT_ENOENT;
1853 TRACE(":searching for %s in paths %s\n", debugstr_w(file), debugstr_w(envVal));
1857 MSVCRT_wchar_t *end = penv;
1859 while(*end && *end != ';') end++; /* Find end of next path */
1860 if (penv == end || !*penv)
1862 *MSVCRT__errno() = MSVCRT_ENOENT;
1863 return MSVCRT_ENOENT;
1865 memcpy(curPath, penv, (end - penv) * sizeof(MSVCRT_wchar_t));
1866 if (curPath[end - penv] != '/' && curPath[end - penv] != '\\')
1868 curPath[end - penv] = '\\';
1869 curPath[end - penv + 1] = '\0';
1872 curPath[end - penv] = '\0';
1874 strcatW(curPath, file);
1875 TRACE("Checking for file %s\n", debugstr_w(curPath));
1876 if (GetFileAttributesW( curPath ) != INVALID_FILE_ATTRIBUTES)
1878 if (strlenW(curPath) + 1 > count)
1880 MSVCRT_INVALID_PMT("buf[count] is too small", MSVCRT_ERANGE);
1881 return MSVCRT_ERANGE;
1883 strcpyW(buf, curPath);
1886 penv = *end ? end + 1 : end;