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"
33 #include "wine/unicode.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
39 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata_t */
40 static void msvcrt_fttofd( const WIN32_FIND_DATAA
*fd
, struct MSVCRT__finddata_t
* ft
)
44 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
47 ft
->attrib
= fd
->dwFileAttributes
;
49 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
51 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
53 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
55 ft
->size
= fd
->nFileSizeLow
;
56 strcpy(ft
->name
, fd
->cFileName
);
59 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata32_t */
60 static void msvcrt_fttofd32( const WIN32_FIND_DATAA
*fd
, struct MSVCRT__finddata32_t
* ft
)
64 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
67 ft
->attrib
= fd
->dwFileAttributes
;
69 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
71 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
73 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
75 ft
->size
= fd
->nFileSizeLow
;
76 strcpy(ft
->name
, fd
->cFileName
);
79 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata_t */
80 static void msvcrt_wfttofd( const WIN32_FIND_DATAW
*fd
, struct MSVCRT__wfinddata_t
* ft
)
84 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
87 ft
->attrib
= fd
->dwFileAttributes
;
89 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
91 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
93 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
95 ft
->size
= fd
->nFileSizeLow
;
96 strcpyW(ft
->name
, fd
->cFileName
);
99 /* INTERNAL: Translate WIN32_FIND_DATAA to finddatai64_t */
100 static void msvcrt_fttofdi64( const WIN32_FIND_DATAA
*fd
, struct MSVCRT__finddatai64_t
* ft
)
104 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
107 ft
->attrib
= fd
->dwFileAttributes
;
109 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
110 ft
->time_create
= dw
;
111 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
112 ft
->time_access
= dw
;
113 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
115 ft
->size
= ((__int64
)fd
->nFileSizeHigh
) << 32 | fd
->nFileSizeLow
;
116 strcpy(ft
->name
, fd
->cFileName
);
119 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata64_t */
120 static void msvcrt_fttofd64( const WIN32_FIND_DATAA
*fd
, struct MSVCRT__finddata64_t
* ft
)
124 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
127 ft
->attrib
= fd
->dwFileAttributes
;
129 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
130 ft
->time_create
= dw
;
131 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
132 ft
->time_access
= dw
;
133 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
135 ft
->size
= ((__int64
)fd
->nFileSizeHigh
) << 32 | fd
->nFileSizeLow
;
136 strcpy(ft
->name
, fd
->cFileName
);
139 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata64_t */
140 static void msvcrt_wfttofd64( const WIN32_FIND_DATAW
*fd
, struct MSVCRT__wfinddata64_t
* ft
)
144 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
147 ft
->attrib
= fd
->dwFileAttributes
;
149 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
150 ft
->time_create
= dw
;
151 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
152 ft
->time_access
= dw
;
153 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
155 ft
->size
= ((__int64
)fd
->nFileSizeHigh
) << 32 | fd
->nFileSizeLow
;
156 strcpyW(ft
->name
, fd
->cFileName
);
159 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata64i32_t */
160 static void msvcrt_fttofd64i32( const WIN32_FIND_DATAA
*fd
, struct MSVCRT__finddata64i32_t
* ft
)
164 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
167 ft
->attrib
= fd
->dwFileAttributes
;
169 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
170 ft
->time_create
= dw
;
171 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
172 ft
->time_access
= dw
;
173 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
175 ft
->size
= fd
->nFileSizeLow
;
176 strcpy(ft
->name
, fd
->cFileName
);
179 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddatai64_t */
180 static void msvcrt_wfttofdi64( const WIN32_FIND_DATAW
*fd
, struct MSVCRT__wfinddatai64_t
* ft
)
184 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
187 ft
->attrib
= fd
->dwFileAttributes
;
189 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
190 ft
->time_create
= dw
;
191 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
192 ft
->time_access
= dw
;
193 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
195 ft
->size
= ((__int64
)fd
->nFileSizeHigh
) << 32 | fd
->nFileSizeLow
;
196 strcpyW(ft
->name
, fd
->cFileName
);
199 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata64i32_t */
200 static void msvcrt_wfttofd64i32( const WIN32_FIND_DATAW
*fd
, struct MSVCRT__wfinddata64i32_t
* ft
)
204 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
207 ft
->attrib
= fd
->dwFileAttributes
;
209 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
210 ft
->time_create
= dw
;
211 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
212 ft
->time_access
= dw
;
213 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
215 ft
->size
= fd
->nFileSizeLow
;
216 strcpyW(ft
->name
, fd
->cFileName
);
219 /*********************************************************************
222 * Change the current working directory.
225 * newdir [I] Directory to change to
228 * Success: 0. The current working directory is set to newdir.
229 * Failure: -1. errno indicates the error.
232 * See SetCurrentDirectoryA.
234 int CDECL
MSVCRT__chdir(const char * newdir
)
236 if (!SetCurrentDirectoryA(newdir
))
238 msvcrt_set_errno(newdir
?GetLastError():0);
244 /*********************************************************************
247 * Unicode version of _chdir.
249 int CDECL
MSVCRT__wchdir(const MSVCRT_wchar_t
* newdir
)
251 if (!SetCurrentDirectoryW(newdir
))
253 msvcrt_set_errno(newdir
?GetLastError():0);
259 /*********************************************************************
260 * _chdrive (MSVCRT.@)
262 * Change the current drive.
265 * newdrive [I] Drive number to change to (1 = 'A', 2 = 'B', ...)
268 * Success: 0. The current drive is set to newdrive.
269 * Failure: -1. errno indicates the error.
272 * See SetCurrentDirectoryA.
274 int CDECL
MSVCRT__chdrive(int newdrive
)
276 WCHAR buffer
[] = {'A', ':', 0};
278 buffer
[0] += newdrive
- 1;
279 if (!SetCurrentDirectoryW( buffer
))
281 msvcrt_set_errno(GetLastError());
283 *MSVCRT__errno() = MSVCRT_EACCES
;
289 /*********************************************************************
290 * _findclose (MSVCRT.@)
292 * Close a handle returned by _findfirst().
295 * hand [I] Handle to close
298 * Success: 0. All resources associated with hand are freed.
299 * Failure: -1. errno indicates the error.
304 int CDECL
MSVCRT__findclose(MSVCRT_intptr_t hand
)
306 TRACE(":handle %ld\n",hand
);
307 if (!FindClose((HANDLE
)hand
))
309 msvcrt_set_errno(GetLastError());
315 /*********************************************************************
316 * _findfirst (MSVCRT.@)
318 * Open a handle for iterating through a directory.
321 * fspec [I] File specification of files to iterate.
322 * ft [O] Information for the first file found.
325 * Success: A handle suitable for passing to _findnext() and _findclose().
326 * ft is populated with the details of the found file.
327 * Failure: -1. errno indicates the error.
330 * See FindFirstFileA.
332 MSVCRT_intptr_t CDECL
MSVCRT__findfirst(const char * fspec
, struct MSVCRT__finddata_t
* ft
)
334 WIN32_FIND_DATAA find_data
;
337 hfind
= FindFirstFileA(fspec
, &find_data
);
338 if (hfind
== INVALID_HANDLE_VALUE
)
340 msvcrt_set_errno(GetLastError());
343 msvcrt_fttofd(&find_data
,ft
);
344 TRACE(":got handle %p\n",hfind
);
345 return (MSVCRT_intptr_t
)hfind
;
348 /*********************************************************************
349 * _findfirst32 (MSVCRT.@)
351 MSVCRT_intptr_t CDECL
MSVCRT__findfirst32(const char * fspec
, struct MSVCRT__finddata32_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_fttofd32(&find_data
, ft
);
363 TRACE(":got handle %p\n", hfind
);
364 return (MSVCRT_intptr_t
)hfind
;
367 /*********************************************************************
368 * _wfindfirst (MSVCRT.@)
370 * Unicode version of _findfirst.
372 MSVCRT_intptr_t CDECL
MSVCRT__wfindfirst(const MSVCRT_wchar_t
* fspec
, struct MSVCRT__wfinddata_t
* ft
)
374 WIN32_FIND_DATAW find_data
;
377 hfind
= FindFirstFileW(fspec
, &find_data
);
378 if (hfind
== INVALID_HANDLE_VALUE
)
380 msvcrt_set_errno(GetLastError());
383 msvcrt_wfttofd(&find_data
,ft
);
384 TRACE(":got handle %p\n",hfind
);
385 return (MSVCRT_intptr_t
)hfind
;
388 /*********************************************************************
389 * _findfirsti64 (MSVCRT.@)
391 * 64-bit version of _findfirst.
393 MSVCRT_intptr_t CDECL
MSVCRT__findfirsti64(const char * fspec
, struct MSVCRT__finddatai64_t
* ft
)
395 WIN32_FIND_DATAA find_data
;
398 hfind
= FindFirstFileA(fspec
, &find_data
);
399 if (hfind
== INVALID_HANDLE_VALUE
)
401 msvcrt_set_errno(GetLastError());
404 msvcrt_fttofdi64(&find_data
,ft
);
405 TRACE(":got handle %p\n",hfind
);
406 return (MSVCRT_intptr_t
)hfind
;
409 /*********************************************************************
410 * _findfirst64 (MSVCRT.@)
412 * 64-bit version of _findfirst.
414 MSVCRT_intptr_t CDECL
MSVCRT__findfirst64(const char * fspec
, struct MSVCRT__finddata64_t
* ft
)
416 WIN32_FIND_DATAA find_data
;
419 hfind
= FindFirstFileA(fspec
, &find_data
);
420 if (hfind
== INVALID_HANDLE_VALUE
)
422 msvcrt_set_errno(GetLastError());
425 msvcrt_fttofd64(&find_data
,ft
);
426 TRACE(":got handle %p\n",hfind
);
427 return (MSVCRT_intptr_t
)hfind
;
430 /*********************************************************************
431 * _wfindfirst64 (MSVCRT.@)
433 * Unicode version of _findfirst64.
435 MSVCRT_intptr_t CDECL
MSVCRT__wfindfirst64(const MSVCRT_wchar_t
* fspec
, struct MSVCRT__wfinddata64_t
* ft
)
437 WIN32_FIND_DATAW find_data
;
440 hfind
= FindFirstFileW(fspec
, &find_data
);
441 if (hfind
== INVALID_HANDLE_VALUE
)
443 msvcrt_set_errno(GetLastError());
446 msvcrt_wfttofd64(&find_data
,ft
);
447 TRACE(":got handle %p\n",hfind
);
448 return (MSVCRT_intptr_t
)hfind
;
451 /*********************************************************************
452 * _findfirst64i32 (MSVCRT.@)
454 * 64-bit/32-bit version of _findfirst.
456 MSVCRT_intptr_t CDECL
MSVCRT__findfirst64i32(const char * fspec
, struct MSVCRT__finddata64i32_t
* ft
)
458 WIN32_FIND_DATAA find_data
;
461 hfind
= FindFirstFileA(fspec
, &find_data
);
462 if (hfind
== INVALID_HANDLE_VALUE
)
464 msvcrt_set_errno(GetLastError());
467 msvcrt_fttofd64i32(&find_data
,ft
);
468 TRACE(":got handle %p\n",hfind
);
469 return (MSVCRT_intptr_t
)hfind
;
472 /*********************************************************************
473 * _wfindfirst64i32 (MSVCRT.@)
475 * Unicode version of _findfirst64i32.
477 MSVCRT_intptr_t CDECL
MSVCRT__wfindfirst64i32(const MSVCRT_wchar_t
* fspec
, struct MSVCRT__wfinddata64i32_t
* ft
)
479 WIN32_FIND_DATAW find_data
;
482 hfind
= FindFirstFileW(fspec
, &find_data
);
483 if (hfind
== INVALID_HANDLE_VALUE
)
485 msvcrt_set_errno(GetLastError());
488 msvcrt_wfttofd64i32(&find_data
,ft
);
489 TRACE(":got handle %p\n",hfind
);
490 return (MSVCRT_intptr_t
)hfind
;
493 /*********************************************************************
494 * _wfindfirsti64 (MSVCRT.@)
496 * Unicode version of _findfirsti64.
498 MSVCRT_intptr_t CDECL
MSVCRT__wfindfirsti64(const MSVCRT_wchar_t
* fspec
, struct MSVCRT__wfinddatai64_t
* ft
)
500 WIN32_FIND_DATAW find_data
;
503 hfind
= FindFirstFileW(fspec
, &find_data
);
504 if (hfind
== INVALID_HANDLE_VALUE
)
506 msvcrt_set_errno(GetLastError());
509 msvcrt_wfttofdi64(&find_data
,ft
);
510 TRACE(":got handle %p\n",hfind
);
511 return (MSVCRT_intptr_t
)hfind
;
514 /*********************************************************************
515 * _findnext (MSVCRT.@)
517 * Find the next file from a file search handle.
520 * hand [I] Handle to the search returned from _findfirst().
521 * ft [O] Information for the file found.
524 * Success: 0. ft is populated with the details of the found file.
525 * Failure: -1. errno indicates the error.
530 int CDECL
MSVCRT__findnext(MSVCRT_intptr_t hand
, struct MSVCRT__finddata_t
* ft
)
532 WIN32_FIND_DATAA find_data
;
534 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
536 *MSVCRT__errno() = MSVCRT_ENOENT
;
540 msvcrt_fttofd(&find_data
,ft
);
544 /*********************************************************************
545 * _findnext32 (MSVCRT.@)
547 int CDECL
MSVCRT__findnext32(MSVCRT_intptr_t hand
, struct MSVCRT__finddata32_t
* ft
)
549 WIN32_FIND_DATAA find_data
;
551 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
553 *MSVCRT__errno() = MSVCRT_ENOENT
;
557 msvcrt_fttofd32(&find_data
, ft
);
561 /*********************************************************************
562 * _wfindnext (MSVCRT.@)
564 * Unicode version of _findnext.
566 int CDECL
MSVCRT__wfindnext(MSVCRT_intptr_t hand
, struct MSVCRT__wfinddata_t
* ft
)
568 WIN32_FIND_DATAW find_data
;
570 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
572 *MSVCRT__errno() = MSVCRT_ENOENT
;
576 msvcrt_wfttofd(&find_data
,ft
);
580 /*********************************************************************
581 * _findnexti64 (MSVCRT.@)
583 * 64-bit version of _findnext.
585 int CDECL
MSVCRT__findnexti64(MSVCRT_intptr_t hand
, struct MSVCRT__finddatai64_t
* ft
)
587 WIN32_FIND_DATAA find_data
;
589 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
591 *MSVCRT__errno() = MSVCRT_ENOENT
;
595 msvcrt_fttofdi64(&find_data
,ft
);
599 /*********************************************************************
600 * _findnext64 (MSVCRT.@)
602 * 64-bit version of _findnext.
604 int CDECL
MSVCRT__findnext64(MSVCRT_intptr_t hand
, struct MSVCRT__finddata64_t
* ft
)
606 WIN32_FIND_DATAA find_data
;
608 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
610 *MSVCRT__errno() = MSVCRT_ENOENT
;
614 msvcrt_fttofd64(&find_data
,ft
);
618 /*********************************************************************
619 * _wfindnext64 (MSVCRT.@)
621 * Unicode version of _wfindnext64.
623 int CDECL
MSVCRT__wfindnext64(MSVCRT_intptr_t hand
, struct MSVCRT__wfinddata64_t
* ft
)
625 WIN32_FIND_DATAW find_data
;
627 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
629 *MSVCRT__errno() = MSVCRT_ENOENT
;
633 msvcrt_wfttofd64(&find_data
,ft
);
637 /*********************************************************************
638 * _findnext64i32 (MSVCRT.@)
640 * 64-bit/32-bit version of _findnext.
642 int CDECL
MSVCRT__findnext64i32(MSVCRT_intptr_t hand
, struct MSVCRT__finddata64i32_t
* ft
)
644 WIN32_FIND_DATAA find_data
;
646 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
648 *MSVCRT__errno() = MSVCRT_ENOENT
;
652 msvcrt_fttofd64i32(&find_data
,ft
);
656 /*********************************************************************
657 * _wfindnexti64 (MSVCRT.@)
659 * Unicode version of _findnexti64.
661 int CDECL
MSVCRT__wfindnexti64(MSVCRT_intptr_t hand
, struct MSVCRT__wfinddatai64_t
* ft
)
663 WIN32_FIND_DATAW find_data
;
665 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
667 *MSVCRT__errno() = MSVCRT_ENOENT
;
671 msvcrt_wfttofdi64(&find_data
,ft
);
675 /*********************************************************************
676 * _wfindnext64i32 (MSVCRT.@)
678 * Unicode version of _findnext64i32.
680 int CDECL
MSVCRT__wfindnext64i32(MSVCRT_intptr_t hand
, struct MSVCRT__wfinddata64i32_t
* ft
)
682 WIN32_FIND_DATAW find_data
;
684 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
686 *MSVCRT__errno() = MSVCRT_ENOENT
;
690 msvcrt_wfttofd64i32(&find_data
,ft
);
694 /*********************************************************************
697 * Get the current working directory.
700 * buf [O] Destination for current working directory.
701 * size [I] Size of buf in characters
704 * Success: If buf is NULL, returns an allocated string containing the path.
705 * Otherwise populates buf with the path and returns it.
706 * Failure: NULL. errno indicates the error.
708 char* CDECL
MSVCRT__getcwd(char * buf
, int size
)
711 int dir_len
= GetCurrentDirectoryA(MAX_PATH
,dir
);
714 return NULL
; /* FIXME: Real return value untested */
718 if (size
<= dir_len
) size
= dir_len
+ 1;
719 if (!(buf
= MSVCRT_malloc( size
))) return NULL
;
721 else if (dir_len
>= size
)
723 *MSVCRT__errno() = MSVCRT_ERANGE
;
724 return NULL
; /* buf too small */
730 /*********************************************************************
731 * _wgetcwd (MSVCRT.@)
733 * Unicode version of _getcwd.
735 MSVCRT_wchar_t
* CDECL
MSVCRT__wgetcwd(MSVCRT_wchar_t
* buf
, int size
)
737 MSVCRT_wchar_t dir
[MAX_PATH
];
738 int dir_len
= GetCurrentDirectoryW(MAX_PATH
,dir
);
741 return NULL
; /* FIXME: Real return value untested */
745 if (size
<= dir_len
) size
= dir_len
+ 1;
746 if (!(buf
= MSVCRT_malloc( size
* sizeof(WCHAR
) ))) return NULL
;
750 *MSVCRT__errno() = MSVCRT_ERANGE
;
751 return NULL
; /* buf too small */
757 /*********************************************************************
758 * _getdrive (MSVCRT.@)
760 * Get the current drive number.
766 * Success: The drive letter number from 1 to 26 ("A:" to "Z:").
769 int CDECL
MSVCRT__getdrive(void)
771 WCHAR buffer
[MAX_PATH
];
772 if (GetCurrentDirectoryW( MAX_PATH
, buffer
) &&
773 buffer
[0] >= 'A' && buffer
[0] <= 'z' && buffer
[1] == ':')
774 return toupperW(buffer
[0]) - 'A' + 1;
778 /*********************************************************************
779 * _getdcwd (MSVCRT.@)
781 * Get the current working directory on a given disk.
784 * drive [I] Drive letter to get the current working directory from.
785 * buf [O] Destination for the current working directory.
786 * size [I] Length of drive in characters.
789 * Success: If drive is NULL, returns an allocated string containing the path.
790 * Otherwise populates drive with the path and returns it.
791 * Failure: NULL. errno indicates the error.
793 char* CDECL
MSVCRT__getdcwd(int drive
, char * buf
, int size
)
797 TRACE(":drive %d(%c), size %d\n",drive
, drive
+ 'A' - 1, size
);
799 if (!drive
|| drive
== MSVCRT__getdrive())
800 return MSVCRT__getcwd(buf
,size
); /* current */
804 char drivespec
[] = {'A', ':', 0};
807 drivespec
[0] += drive
- 1;
808 if (GetDriveTypeA(drivespec
) < DRIVE_REMOVABLE
)
810 *MSVCRT__errno() = MSVCRT_EACCES
;
814 dir_len
= GetFullPathNameA(drivespec
,MAX_PATH
,dir
,&dummy
);
815 if (dir_len
>= size
|| dir_len
< 1)
817 *MSVCRT__errno() = MSVCRT_ERANGE
;
818 return NULL
; /* buf too small */
821 TRACE(":returning '%s'\n", dir
);
823 return MSVCRT__strdup(dir
); /* allocate */
830 /*********************************************************************
831 * _wgetdcwd (MSVCRT.@)
833 * Unicode version of _wgetdcwd.
835 MSVCRT_wchar_t
* CDECL
MSVCRT__wgetdcwd(int drive
, MSVCRT_wchar_t
* buf
, int size
)
837 static MSVCRT_wchar_t
* dummy
;
839 TRACE(":drive %d(%c), size %d\n",drive
, drive
+ 'A' - 1, size
);
841 if (!drive
|| drive
== MSVCRT__getdrive())
842 return MSVCRT__wgetcwd(buf
,size
); /* current */
845 MSVCRT_wchar_t dir
[MAX_PATH
];
846 MSVCRT_wchar_t drivespec
[4] = {'A', ':', '\\', 0};
849 drivespec
[0] += drive
- 1;
850 if (GetDriveTypeW(drivespec
) < DRIVE_REMOVABLE
)
852 *MSVCRT__errno() = MSVCRT_EACCES
;
856 dir_len
= GetFullPathNameW(drivespec
,MAX_PATH
,dir
,&dummy
);
857 if (dir_len
>= size
|| dir_len
< 1)
859 *MSVCRT__errno() = MSVCRT_ERANGE
;
860 return NULL
; /* buf too small */
863 TRACE(":returning %s\n", debugstr_w(dir
));
865 return MSVCRT__wcsdup(dir
); /* allocate */
871 /*********************************************************************
872 * _getdiskfree (MSVCRT.@)
874 * Get information about the free space on a drive.
877 * disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
878 * info [O] Destination for the resulting information.
881 * Success: 0. info is updated with the free space information.
882 * Failure: An error code from GetLastError().
885 * See GetLastError().
887 unsigned int CDECL
MSVCRT__getdiskfree(unsigned int disk
, struct MSVCRT__diskfree_t
* d
)
889 WCHAR drivespec
[] = {'@', ':', '\\', 0};
894 return ERROR_INVALID_PARAMETER
; /* MSVCRT doesn't set errno here */
896 drivespec
[0] += disk
; /* make a drive letter */
898 if (GetDiskFreeSpaceW(disk
==0?NULL
:drivespec
,ret
,ret
+1,ret
+2,ret
+3))
900 d
->sectors_per_cluster
= ret
[0];
901 d
->bytes_per_sector
= ret
[1];
902 d
->avail_clusters
= ret
[2];
903 d
->total_clusters
= ret
[3];
906 err
= GetLastError();
907 msvcrt_set_errno(err
);
911 /*********************************************************************
914 * Create a directory.
917 * newdir [I] Name of directory to create.
920 * Success: 0. The directory indicated by newdir is created.
921 * Failure: -1. errno indicates the error.
924 * See CreateDirectoryA.
926 int CDECL
MSVCRT__mkdir(const char * newdir
)
928 if (CreateDirectoryA(newdir
,NULL
))
930 msvcrt_set_errno(GetLastError());
934 /*********************************************************************
937 * Unicode version of _mkdir.
939 int CDECL
MSVCRT__wmkdir(const MSVCRT_wchar_t
* newdir
)
941 if (CreateDirectoryW(newdir
,NULL
))
943 msvcrt_set_errno(GetLastError());
947 /*********************************************************************
950 * Delete a directory.
953 * dir [I] Name of directory to delete.
956 * Success: 0. The directory indicated by newdir is deleted.
957 * Failure: -1. errno indicates the error.
960 * See RemoveDirectoryA.
962 int CDECL
MSVCRT__rmdir(const char * dir
)
964 if (RemoveDirectoryA(dir
))
966 msvcrt_set_errno(GetLastError());
970 /*********************************************************************
973 * Unicode version of _rmdir.
975 int CDECL
MSVCRT__wrmdir(const MSVCRT_wchar_t
* dir
)
977 if (RemoveDirectoryW(dir
))
979 msvcrt_set_errno(GetLastError());
983 /******************************************************************
984 * _splitpath_s (MSVCRT.@)
986 int CDECL
_splitpath_s(const char* inpath
,
987 char* drive
, MSVCRT_size_t sz_drive
,
988 char* dir
, MSVCRT_size_t sz_dir
,
989 char* fname
, MSVCRT_size_t sz_fname
,
990 char* ext
, MSVCRT_size_t sz_ext
)
994 if (!inpath
|| (!drive
&& sz_drive
) ||
995 (drive
&& !sz_drive
) ||
998 (!fname
&& sz_fname
) ||
999 (fname
&& !sz_fname
) ||
1003 *MSVCRT__errno() = MSVCRT_EINVAL
;
1004 return MSVCRT_EINVAL
;
1007 if (inpath
[0] && inpath
[1] == ':')
1011 if (sz_drive
<= 2) goto do_error
;
1012 drive
[0] = inpath
[0];
1013 drive
[1] = inpath
[1];
1018 else if (drive
) drive
[0] = '\0';
1020 /* look for end of directory part */
1022 for (p
= inpath
; *p
; p
++) if (*p
== '/' || *p
== '\\') end
= p
+ 1;
1024 if (end
) /* got a directory */
1028 if (sz_dir
<= end
- inpath
) goto do_error
;
1029 memcpy( dir
, inpath
, (end
- inpath
) );
1030 dir
[end
- inpath
] = 0;
1034 else if (dir
) dir
[0] = 0;
1036 /* look for extension: what's after the last dot */
1038 for (p
= inpath
; *p
; p
++) if (*p
== '.') end
= p
;
1040 if (!end
) end
= p
; /* there's no extension */
1044 if (sz_fname
<= end
- inpath
) goto do_error
;
1045 memcpy( fname
, inpath
, (end
- inpath
) );
1046 fname
[end
- inpath
] = 0;
1050 if (sz_ext
<= strlen(end
)) goto do_error
;
1055 if (drive
) drive
[0] = '\0';
1056 if (dir
) dir
[0] = '\0';
1057 if (fname
) fname
[0]= '\0';
1058 if (ext
) ext
[0]= '\0';
1059 *MSVCRT__errno() = MSVCRT_ERANGE
;
1060 return MSVCRT_ERANGE
;
1063 /*********************************************************************
1064 * _splitpath (MSVCRT.@)
1066 void CDECL
_splitpath(const char *inpath
, char *drv
, char *dir
,
1067 char *fname
, char *ext
)
1069 _splitpath_s(inpath
, drv
, drv
?MSVCRT__MAX_DRIVE
:0, dir
, dir
?MSVCRT__MAX_DIR
:0,
1070 fname
, fname
?MSVCRT__MAX_FNAME
:0, ext
, ext
?MSVCRT__MAX_EXT
:0);
1073 /******************************************************************
1074 * _wsplitpath_s (MSVCRT.@)
1076 * Secure version of _wsplitpath
1078 int CDECL
_wsplitpath_s(const MSVCRT_wchar_t
* inpath
,
1079 MSVCRT_wchar_t
* drive
, MSVCRT_size_t sz_drive
,
1080 MSVCRT_wchar_t
* dir
, MSVCRT_size_t sz_dir
,
1081 MSVCRT_wchar_t
* fname
, MSVCRT_size_t sz_fname
,
1082 MSVCRT_wchar_t
* ext
, MSVCRT_size_t sz_ext
)
1084 const MSVCRT_wchar_t
*p
, *end
;
1086 if (!inpath
|| (!drive
&& sz_drive
) ||
1087 (drive
&& !sz_drive
) ||
1090 (!fname
&& sz_fname
) ||
1091 (fname
&& !sz_fname
) ||
1095 *MSVCRT__errno() = MSVCRT_EINVAL
;
1096 return MSVCRT_EINVAL
;
1099 if (inpath
[0] && inpath
[1] == ':')
1103 if (sz_drive
<= 2) goto do_error
;
1104 drive
[0] = inpath
[0];
1105 drive
[1] = inpath
[1];
1110 else if (drive
) drive
[0] = '\0';
1112 /* look for end of directory part */
1114 for (p
= inpath
; *p
; p
++) if (*p
== '/' || *p
== '\\') end
= p
+ 1;
1116 if (end
) /* got a directory */
1120 if (sz_dir
<= end
- inpath
) goto do_error
;
1121 memcpy( dir
, inpath
, (end
- inpath
) * sizeof(MSVCRT_wchar_t
) );
1122 dir
[end
- inpath
] = 0;
1126 else if (dir
) dir
[0] = 0;
1128 /* look for extension: what's after the last dot */
1130 for (p
= inpath
; *p
; p
++) if (*p
== '.') end
= p
;
1132 if (!end
) end
= p
; /* there's no extension */
1136 if (sz_fname
<= end
- inpath
) goto do_error
;
1137 memcpy( fname
, inpath
, (end
- inpath
) * sizeof(MSVCRT_wchar_t
) );
1138 fname
[end
- inpath
] = 0;
1142 if (sz_ext
<= strlenW(end
)) goto do_error
;
1143 strcpyW( ext
, end
);
1147 if (drive
) drive
[0] = '\0';
1148 if (dir
) dir
[0] = '\0';
1149 if (fname
) fname
[0]= '\0';
1150 if (ext
) ext
[0]= '\0';
1151 *MSVCRT__errno() = MSVCRT_ERANGE
;
1152 return MSVCRT_ERANGE
;
1155 /*********************************************************************
1156 * _wsplitpath (MSVCRT.@)
1158 * Unicode version of _splitpath.
1160 void CDECL
_wsplitpath(const MSVCRT_wchar_t
*inpath
, MSVCRT_wchar_t
*drv
, MSVCRT_wchar_t
*dir
,
1161 MSVCRT_wchar_t
*fname
, MSVCRT_wchar_t
*ext
)
1163 _wsplitpath_s(inpath
, drv
, drv
?MSVCRT__MAX_DRIVE
:0, dir
, dir
?MSVCRT__MAX_DIR
:0,
1164 fname
, fname
?MSVCRT__MAX_FNAME
:0, ext
, ext
?MSVCRT__MAX_EXT
:0);
1167 /*********************************************************************
1168 * _wfullpath (MSVCRT.@)
1170 * Unicode version of _fullpath.
1172 MSVCRT_wchar_t
* CDECL
_wfullpath(MSVCRT_wchar_t
* absPath
, const MSVCRT_wchar_t
* relPath
, MSVCRT_size_t size
)
1177 BOOL alloced
= FALSE
;
1179 if (!relPath
|| !*relPath
)
1180 return MSVCRT__wgetcwd(absPath
, size
);
1182 if (absPath
== NULL
)
1184 buffer
= MSVCRT_malloc(MAX_PATH
* sizeof(WCHAR
));
1193 *MSVCRT__errno() = MSVCRT_ERANGE
;
1197 TRACE(":resolving relative path %s\n",debugstr_w(relPath
));
1199 rc
= GetFullPathNameW(relPath
,size
,buffer
,&lastpart
);
1201 if (rc
> 0 && rc
<= size
)
1206 MSVCRT_free(buffer
);
1211 /*********************************************************************
1212 * _fullpath (MSVCRT.@)
1214 * Create an absolute path from a relative path.
1217 * absPath [O] Destination for absolute path
1218 * relPath [I] Relative path to convert to absolute
1219 * size [I] Length of absPath in characters.
1222 * Success: If absPath is NULL, returns an allocated string containing the path.
1223 * Otherwise populates absPath with the path and returns it.
1224 * Failure: NULL. errno indicates the error.
1226 char * CDECL
_fullpath(char * absPath
, const char* relPath
, unsigned int size
)
1231 BOOL alloced
= FALSE
;
1233 if (!relPath
|| !*relPath
)
1234 return MSVCRT__getcwd(absPath
, size
);
1236 if (absPath
== NULL
)
1238 buffer
= MSVCRT_malloc(MAX_PATH
);
1247 *MSVCRT__errno() = MSVCRT_ERANGE
;
1251 TRACE(":resolving relative path '%s'\n",relPath
);
1253 rc
= GetFullPathNameA(relPath
,size
,buffer
,&lastpart
);
1255 if (rc
> 0 && rc
<= size
)
1260 MSVCRT_free(buffer
);
1265 /*********************************************************************
1266 * _makepath (MSVCRT.@)
1268 * Create a pathname.
1271 * path [O] Destination for created pathname
1272 * drive [I] Drive letter (e.g. "A:")
1273 * directory [I] Directory
1274 * filename [I] Name of the file, excluding extension
1275 * extension [I] File extension (e.g. ".TXT")
1278 * Nothing. If path is not large enough to hold the resulting pathname,
1279 * random process memory will be overwritten.
1281 VOID CDECL
_makepath(char * path
, const char * drive
,
1282 const char *directory
, const char * filename
,
1283 const char * extension
)
1287 TRACE("(%s %s %s %s)\n", debugstr_a(drive
), debugstr_a(directory
),
1288 debugstr_a(filename
), debugstr_a(extension
) );
1293 if (drive
&& drive
[0])
1298 if (directory
&& directory
[0])
1300 unsigned int len
= strlen(directory
);
1301 memmove(p
, directory
, len
);
1303 if (p
[-1] != '/' && p
[-1] != '\\')
1306 if (filename
&& filename
[0])
1308 unsigned int len
= strlen(filename
);
1309 memmove(p
, filename
, len
);
1312 if (extension
&& extension
[0])
1314 if (extension
[0] != '.')
1316 strcpy(p
, extension
);
1320 TRACE("returning %s\n",path
);
1323 /*********************************************************************
1324 * _wmakepath (MSVCRT.@)
1326 * Unicode version of _wmakepath.
1328 VOID CDECL
_wmakepath(MSVCRT_wchar_t
*path
, const MSVCRT_wchar_t
*drive
, const MSVCRT_wchar_t
*directory
,
1329 const MSVCRT_wchar_t
*filename
, const MSVCRT_wchar_t
*extension
)
1331 MSVCRT_wchar_t
*p
= path
;
1333 TRACE("%s %s %s %s\n", debugstr_w(drive
), debugstr_w(directory
),
1334 debugstr_w(filename
), debugstr_w(extension
));
1339 if (drive
&& drive
[0])
1344 if (directory
&& directory
[0])
1346 unsigned int len
= strlenW(directory
);
1347 memmove(p
, directory
, len
* sizeof(MSVCRT_wchar_t
));
1349 if (p
[-1] != '/' && p
[-1] != '\\')
1352 if (filename
&& filename
[0])
1354 unsigned int len
= strlenW(filename
);
1355 memmove(p
, filename
, len
* sizeof(MSVCRT_wchar_t
));
1358 if (extension
&& extension
[0])
1360 if (extension
[0] != '.')
1362 strcpyW(p
, extension
);
1367 TRACE("returning %s\n", debugstr_w(path
));
1370 /*********************************************************************
1371 * _makepath_s (MSVCRT.@)
1373 * Safe version of _makepath.
1375 int CDECL
_makepath_s(char *path
, MSVCRT_size_t size
, const char *drive
,
1376 const char *directory
, const char *filename
,
1377 const char *extension
)
1383 *MSVCRT__errno() = MSVCRT_EINVAL
;
1384 return MSVCRT_EINVAL
;
1387 if (drive
&& drive
[0])
1397 if (directory
&& directory
[0])
1399 unsigned int len
= strlen(directory
);
1400 unsigned int needs_separator
= directory
[len
- 1] != '/' && directory
[len
- 1] != '\\';
1401 unsigned int copylen
= min(size
- 1, len
);
1406 memmove(p
, directory
, copylen
);
1414 if (needs_separator
)
1424 if (filename
&& filename
[0])
1426 unsigned int len
= strlen(filename
);
1427 unsigned int copylen
= min(size
- 1, len
);
1432 memmove(p
, filename
, copylen
);
1441 if (extension
&& extension
[0])
1443 unsigned int len
= strlen(extension
);
1444 unsigned int needs_period
= extension
[0] != '.';
1445 unsigned int copylen
;
1456 copylen
= min(size
- 1, len
);
1457 memcpy(p
, extension
, copylen
);
1470 *MSVCRT__errno() = MSVCRT_ERANGE
;
1471 return MSVCRT_ERANGE
;
1474 /*********************************************************************
1475 * _wmakepath_s (MSVCRT.@)
1477 * Safe version of _wmakepath.
1479 int CDECL
_wmakepath_s(MSVCRT_wchar_t
*path
, MSVCRT_size_t size
, const MSVCRT_wchar_t
*drive
,
1480 const MSVCRT_wchar_t
*directory
, const MSVCRT_wchar_t
*filename
,
1481 const MSVCRT_wchar_t
*extension
)
1483 MSVCRT_wchar_t
*p
= path
;
1487 *MSVCRT__errno() = MSVCRT_EINVAL
;
1488 return MSVCRT_EINVAL
;
1491 if (drive
&& drive
[0])
1501 if (directory
&& directory
[0])
1503 unsigned int len
= strlenW(directory
);
1504 unsigned int needs_separator
= directory
[len
- 1] != '/' && directory
[len
- 1] != '\\';
1505 unsigned int copylen
= min(size
- 1, len
);
1510 memmove(p
, directory
, copylen
* sizeof(MSVCRT_wchar_t
));
1518 if (needs_separator
)
1528 if (filename
&& filename
[0])
1530 unsigned int len
= strlenW(filename
);
1531 unsigned int copylen
= min(size
- 1, len
);
1536 memmove(p
, filename
, copylen
* sizeof(MSVCRT_wchar_t
));
1545 if (extension
&& extension
[0])
1547 unsigned int len
= strlenW(extension
);
1548 unsigned int needs_period
= extension
[0] != '.';
1549 unsigned int copylen
;
1560 copylen
= min(size
- 1, len
);
1561 memcpy(p
, extension
, copylen
* sizeof(MSVCRT_wchar_t
));
1574 *MSVCRT__errno() = MSVCRT_ERANGE
;
1575 return MSVCRT_ERANGE
;
1578 /*********************************************************************
1579 * _searchenv (MSVCRT.@)
1581 * Search for a file in a list of paths from an environment variable.
1584 * file [I] Name of the file to search for.
1585 * env [I] Name of the environment variable containing a list of paths.
1586 * buf [O] Destination for the found file path.
1589 * Nothing. If the file is not found, buf will contain an empty string
1592 void CDECL
MSVCRT__searchenv(const char* file
, const char* env
, char *buf
)
1595 char curPath
[MAX_PATH
];
1600 if (GetFileAttributesA( file
) != INVALID_FILE_ATTRIBUTES
)
1602 GetFullPathNameA( file
, MAX_PATH
, buf
, NULL
);
1603 /* Sigh. This error is *always* set, regardless of success */
1604 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1608 /* Search given environment variable */
1609 envVal
= MSVCRT_getenv(env
);
1612 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1617 TRACE(":searching for %s in paths %s\n", file
, envVal
);
1623 while(*end
&& *end
!= ';') end
++; /* Find end of next path */
1624 if (penv
== end
|| !*penv
)
1626 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1629 memcpy(curPath
, penv
, end
- penv
);
1630 if (curPath
[end
- penv
] != '/' && curPath
[end
- penv
] != '\\')
1632 curPath
[end
- penv
] = '\\';
1633 curPath
[end
- penv
+ 1] = '\0';
1636 curPath
[end
- penv
] = '\0';
1638 strcat(curPath
, file
);
1639 TRACE("Checking for file %s\n", curPath
);
1640 if (GetFileAttributesA( curPath
) != INVALID_FILE_ATTRIBUTES
)
1642 strcpy(buf
, curPath
);
1643 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1646 penv
= *end
? end
+ 1 : end
;
1650 /*********************************************************************
1651 * _searchenv_s (MSVCRT.@)
1653 int CDECL
_searchenv_s(const char* file
, const char* env
, char *buf
, MSVCRT_size_t count
)
1656 char curPath
[MAX_PATH
];
1658 if (!MSVCRT_CHECK_PMT(file
!= NULL
)) return MSVCRT_EINVAL
;
1659 if (!MSVCRT_CHECK_PMT(buf
!= NULL
)) return MSVCRT_EINVAL
;
1660 if (!MSVCRT_CHECK_PMT(count
> 0)) return MSVCRT_EINVAL
;
1665 if (GetFileAttributesA( file
) != INVALID_FILE_ATTRIBUTES
)
1667 if (GetFullPathNameA( file
, count
, buf
, NULL
)) return 0;
1668 msvcrt_set_errno(GetLastError());
1672 /* Search given environment variable */
1673 envVal
= MSVCRT_getenv(env
);
1676 *MSVCRT__errno() = MSVCRT_ENOENT
;
1677 return MSVCRT_ENOENT
;
1681 TRACE(":searching for %s in paths %s\n", file
, envVal
);
1687 while(*end
&& *end
!= ';') end
++; /* Find end of next path */
1688 if (penv
== end
|| !*penv
)
1690 *MSVCRT__errno() = MSVCRT_ENOENT
;
1691 return MSVCRT_ENOENT
;
1693 memcpy(curPath
, penv
, end
- penv
);
1694 if (curPath
[end
- penv
] != '/' && curPath
[end
- penv
] != '\\')
1696 curPath
[end
- penv
] = '\\';
1697 curPath
[end
- penv
+ 1] = '\0';
1700 curPath
[end
- penv
] = '\0';
1702 strcat(curPath
, file
);
1703 TRACE("Checking for file %s\n", curPath
);
1704 if (GetFileAttributesA( curPath
) != INVALID_FILE_ATTRIBUTES
)
1706 if (strlen(curPath
) + 1 > count
)
1708 MSVCRT_INVALID_PMT("buf[count] is too small", MSVCRT_ERANGE
);
1709 return MSVCRT_ERANGE
;
1711 strcpy(buf
, curPath
);
1714 penv
= *end
? end
+ 1 : end
;
1718 /*********************************************************************
1719 * _wsearchenv (MSVCRT.@)
1721 * Unicode version of _searchenv
1723 void CDECL
MSVCRT__wsearchenv(const MSVCRT_wchar_t
* file
, const MSVCRT_wchar_t
* env
, MSVCRT_wchar_t
*buf
)
1725 MSVCRT_wchar_t
*envVal
, *penv
;
1726 MSVCRT_wchar_t curPath
[MAX_PATH
];
1731 if (GetFileAttributesW( file
) != INVALID_FILE_ATTRIBUTES
)
1733 GetFullPathNameW( file
, MAX_PATH
, buf
, NULL
);
1734 /* Sigh. This error is *always* set, regardless of success */
1735 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1739 /* Search given environment variable */
1740 envVal
= MSVCRT__wgetenv(env
);
1743 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1748 TRACE(":searching for %s in paths %s\n", debugstr_w(file
), debugstr_w(envVal
));
1752 MSVCRT_wchar_t
*end
= penv
;
1754 while(*end
&& *end
!= ';') end
++; /* Find end of next path */
1755 if (penv
== end
|| !*penv
)
1757 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1760 memcpy(curPath
, penv
, (end
- penv
) * sizeof(MSVCRT_wchar_t
));
1761 if (curPath
[end
- penv
] != '/' && curPath
[end
- penv
] != '\\')
1763 curPath
[end
- penv
] = '\\';
1764 curPath
[end
- penv
+ 1] = '\0';
1767 curPath
[end
- penv
] = '\0';
1769 strcatW(curPath
, file
);
1770 TRACE("Checking for file %s\n", debugstr_w(curPath
));
1771 if (GetFileAttributesW( curPath
) != INVALID_FILE_ATTRIBUTES
)
1773 strcpyW(buf
, curPath
);
1774 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1777 penv
= *end
? end
+ 1 : end
;
1781 /*********************************************************************
1782 * _wsearchenv_s (MSVCRT.@)
1784 int CDECL
_wsearchenv_s(const MSVCRT_wchar_t
* file
, const MSVCRT_wchar_t
* env
,
1785 MSVCRT_wchar_t
*buf
, MSVCRT_size_t count
)
1787 MSVCRT_wchar_t
* envVal
, *penv
;
1788 MSVCRT_wchar_t curPath
[MAX_PATH
];
1790 if (!MSVCRT_CHECK_PMT(file
!= NULL
)) return MSVCRT_EINVAL
;
1791 if (!MSVCRT_CHECK_PMT(buf
!= NULL
)) return MSVCRT_EINVAL
;
1792 if (!MSVCRT_CHECK_PMT(count
> 0)) return MSVCRT_EINVAL
;
1797 if (GetFileAttributesW( file
) != INVALID_FILE_ATTRIBUTES
)
1799 if (GetFullPathNameW( file
, count
, buf
, NULL
)) return 0;
1800 msvcrt_set_errno(GetLastError());
1804 /* Search given environment variable */
1805 envVal
= MSVCRT__wgetenv(env
);
1808 *MSVCRT__errno() = MSVCRT_ENOENT
;
1809 return MSVCRT_ENOENT
;
1813 TRACE(":searching for %s in paths %s\n", debugstr_w(file
), debugstr_w(envVal
));
1817 MSVCRT_wchar_t
*end
= penv
;
1819 while(*end
&& *end
!= ';') end
++; /* Find end of next path */
1820 if (penv
== end
|| !*penv
)
1822 *MSVCRT__errno() = MSVCRT_ENOENT
;
1823 return MSVCRT_ENOENT
;
1825 memcpy(curPath
, penv
, (end
- penv
) * sizeof(MSVCRT_wchar_t
));
1826 if (curPath
[end
- penv
] != '/' && curPath
[end
- penv
] != '\\')
1828 curPath
[end
- penv
] = '\\';
1829 curPath
[end
- penv
+ 1] = '\0';
1832 curPath
[end
- penv
] = '\0';
1834 strcatW(curPath
, file
);
1835 TRACE("Checking for file %s\n", debugstr_w(curPath
));
1836 if (GetFileAttributesW( curPath
) != INVALID_FILE_ATTRIBUTES
)
1838 if (strlenW(curPath
) + 1 > count
)
1840 MSVCRT_INVALID_PMT("buf[count] is too small", MSVCRT_ERANGE
);
1841 return MSVCRT_ERANGE
;
1843 strcpyW(buf
, curPath
);
1846 penv
= *end
? end
+ 1 : end
;