msvcrt: Remove MSVCRT_ prefix from string.c functions.
[wine.git] / dlls / msvcrt / dir.c
blobd565db9523010282b6c0de47f0ad7e031507b2bf
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 <stdarg.h>
25 #include <stdlib.h>
26 #include <direct.h>
28 #include "windef.h"
29 #include "winbase.h"
30 #include "winternl.h"
31 #include "msvcrt.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
36 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata_t */
37 static void msvcrt_fttofd( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata_t* ft)
39 DWORD dw;
41 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
42 ft->attrib = 0;
43 else
44 ft->attrib = fd->dwFileAttributes;
46 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
47 ft->time_create = dw;
48 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
49 ft->time_access = dw;
50 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
51 ft->time_write = dw;
52 ft->size = fd->nFileSizeLow;
53 strcpy(ft->name, fd->cFileName);
56 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata32_t */
57 static void msvcrt_fttofd32( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata32_t* ft)
59 DWORD dw;
61 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
62 ft->attrib = 0;
63 else
64 ft->attrib = fd->dwFileAttributes;
66 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
67 ft->time_create = dw;
68 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
69 ft->time_access = dw;
70 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
71 ft->time_write = dw;
72 ft->size = fd->nFileSizeLow;
73 strcpy(ft->name, fd->cFileName);
76 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata_t */
77 static void msvcrt_wfttofd( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata_t* ft)
79 DWORD dw;
81 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
82 ft->attrib = 0;
83 else
84 ft->attrib = fd->dwFileAttributes;
86 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
87 ft->time_create = dw;
88 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
89 ft->time_access = dw;
90 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
91 ft->time_write = dw;
92 ft->size = fd->nFileSizeLow;
93 MSVCRT_wcscpy(ft->name, fd->cFileName);
96 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata32_t */
97 static void msvcrt_wfttofd32(const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata32_t* ft)
99 DWORD dw;
101 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
102 ft->attrib = 0;
103 else
104 ft->attrib = fd->dwFileAttributes;
106 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
107 ft->time_create = dw;
108 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
109 ft->time_access = dw;
110 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
111 ft->time_write = dw;
112 ft->size = fd->nFileSizeLow;
113 MSVCRT_wcscpy(ft->name, fd->cFileName);
116 /* INTERNAL: Translate WIN32_FIND_DATAA to finddatai64_t */
117 static void msvcrt_fttofdi64( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddatai64_t* ft)
119 DWORD dw;
121 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
122 ft->attrib = 0;
123 else
124 ft->attrib = fd->dwFileAttributes;
126 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
127 ft->time_create = dw;
128 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
129 ft->time_access = dw;
130 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
131 ft->time_write = dw;
132 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
133 strcpy(ft->name, fd->cFileName);
136 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata64_t */
137 static void msvcrt_fttofd64( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata64_t* ft)
139 DWORD dw;
141 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
142 ft->attrib = 0;
143 else
144 ft->attrib = fd->dwFileAttributes;
146 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
147 ft->time_create = dw;
148 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
149 ft->time_access = dw;
150 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
151 ft->time_write = dw;
152 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
153 strcpy(ft->name, fd->cFileName);
156 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata64_t */
157 static void msvcrt_wfttofd64( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata64_t* ft)
159 DWORD dw;
161 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
162 ft->attrib = 0;
163 else
164 ft->attrib = fd->dwFileAttributes;
166 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
167 ft->time_create = dw;
168 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
169 ft->time_access = dw;
170 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
171 ft->time_write = dw;
172 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
173 MSVCRT_wcscpy(ft->name, fd->cFileName);
176 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata64i32_t */
177 static void msvcrt_fttofd64i32( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata64i32_t* ft)
179 DWORD dw;
181 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
182 ft->attrib = 0;
183 else
184 ft->attrib = fd->dwFileAttributes;
186 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
187 ft->time_create = dw;
188 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
189 ft->time_access = dw;
190 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
191 ft->time_write = dw;
192 ft->size = fd->nFileSizeLow;
193 strcpy(ft->name, fd->cFileName);
196 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddatai64_t */
197 static void msvcrt_wfttofdi64( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddatai64_t* ft)
199 DWORD dw;
201 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
202 ft->attrib = 0;
203 else
204 ft->attrib = fd->dwFileAttributes;
206 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
207 ft->time_create = dw;
208 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
209 ft->time_access = dw;
210 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
211 ft->time_write = dw;
212 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
213 MSVCRT_wcscpy(ft->name, fd->cFileName);
216 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata64i32_t */
217 static void msvcrt_wfttofd64i32( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata64i32_t* ft)
219 DWORD dw;
221 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
222 ft->attrib = 0;
223 else
224 ft->attrib = fd->dwFileAttributes;
226 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
227 ft->time_create = dw;
228 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
229 ft->time_access = dw;
230 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
231 ft->time_write = dw;
232 ft->size = fd->nFileSizeLow;
233 MSVCRT_wcscpy(ft->name, fd->cFileName);
236 /*********************************************************************
237 * _chdir (MSVCRT.@)
239 * Change the current working directory.
241 * PARAMS
242 * newdir [I] Directory to change to
244 * RETURNS
245 * Success: 0. The current working directory is set to newdir.
246 * Failure: -1. errno indicates the error.
248 * NOTES
249 * See SetCurrentDirectoryA.
251 int CDECL MSVCRT__chdir(const char * newdir)
253 if (!SetCurrentDirectoryA(newdir))
255 msvcrt_set_errno(newdir?GetLastError():0);
256 return -1;
258 return 0;
261 /*********************************************************************
262 * _wchdir (MSVCRT.@)
264 * Unicode version of _chdir.
266 int CDECL MSVCRT__wchdir(const wchar_t * newdir)
268 if (!SetCurrentDirectoryW(newdir))
270 msvcrt_set_errno(newdir?GetLastError():0);
271 return -1;
273 return 0;
276 /*********************************************************************
277 * _chdrive (MSVCRT.@)
279 * Change the current drive.
281 * PARAMS
282 * newdrive [I] Drive number to change to (1 = 'A', 2 = 'B', ...)
284 * RETURNS
285 * Success: 0. The current drive is set to newdrive.
286 * Failure: -1. errno indicates the error.
288 * NOTES
289 * See SetCurrentDirectoryA.
291 int CDECL MSVCRT__chdrive(int newdrive)
293 WCHAR buffer[] = L"A:";
295 buffer[0] += newdrive - 1;
296 if (!SetCurrentDirectoryW( buffer ))
298 msvcrt_set_errno(GetLastError());
299 if (newdrive <= 0)
300 *_errno() = EACCES;
301 return -1;
303 return 0;
306 /*********************************************************************
307 * _findclose (MSVCRT.@)
309 * Close a handle returned by _findfirst().
311 * PARAMS
312 * hand [I] Handle to close
314 * RETURNS
315 * Success: 0. All resources associated with hand are freed.
316 * Failure: -1. errno indicates the error.
318 * NOTES
319 * See FindClose.
321 int CDECL MSVCRT__findclose(intptr_t hand)
323 TRACE(":handle %Iu\n",hand);
324 if (!FindClose((HANDLE)hand))
326 msvcrt_set_errno(GetLastError());
327 return -1;
329 return 0;
332 /*********************************************************************
333 * _findfirst (MSVCRT.@)
335 * Open a handle for iterating through a directory.
337 * PARAMS
338 * fspec [I] File specification of files to iterate.
339 * ft [O] Information for the first file found.
341 * RETURNS
342 * Success: A handle suitable for passing to _findnext() and _findclose().
343 * ft is populated with the details of the found file.
344 * Failure: -1. errno indicates the error.
346 * NOTES
347 * See FindFirstFileA.
349 intptr_t CDECL MSVCRT__findfirst(const char * fspec, struct MSVCRT__finddata_t* ft)
351 WIN32_FIND_DATAA find_data;
352 HANDLE hfind;
354 hfind = FindFirstFileA(fspec, &find_data);
355 if (hfind == INVALID_HANDLE_VALUE)
357 msvcrt_set_errno(GetLastError());
358 return -1;
360 msvcrt_fttofd(&find_data,ft);
361 TRACE(":got handle %p\n",hfind);
362 return (intptr_t)hfind;
365 /*********************************************************************
366 * _findfirst32 (MSVCRT.@)
368 intptr_t CDECL MSVCRT__findfirst32(const char * fspec, struct MSVCRT__finddata32_t* ft)
370 WIN32_FIND_DATAA find_data;
371 HANDLE hfind;
373 hfind = FindFirstFileA(fspec, &find_data);
374 if (hfind == INVALID_HANDLE_VALUE)
376 msvcrt_set_errno(GetLastError());
377 return -1;
379 msvcrt_fttofd32(&find_data, ft);
380 TRACE(":got handle %p\n", hfind);
381 return (intptr_t)hfind;
384 /*********************************************************************
385 * _wfindfirst (MSVCRT.@)
387 * Unicode version of _findfirst.
389 intptr_t CDECL MSVCRT__wfindfirst(const wchar_t * fspec, struct MSVCRT__wfinddata_t* ft)
391 WIN32_FIND_DATAW find_data;
392 HANDLE hfind;
394 hfind = FindFirstFileW(fspec, &find_data);
395 if (hfind == INVALID_HANDLE_VALUE)
397 msvcrt_set_errno(GetLastError());
398 return -1;
400 msvcrt_wfttofd(&find_data,ft);
401 TRACE(":got handle %p\n",hfind);
402 return (intptr_t)hfind;
405 /*********************************************************************
406 * _wfindfirst32 (MSVCRT.@)
408 * Unicode version of _findfirst32.
410 intptr_t CDECL MSVCRT__wfindfirst32(const wchar_t * fspec, struct MSVCRT__wfinddata32_t* ft)
412 WIN32_FIND_DATAW find_data;
413 HANDLE hfind;
415 hfind = FindFirstFileW(fspec, &find_data);
416 if (hfind == INVALID_HANDLE_VALUE)
418 msvcrt_set_errno(GetLastError());
419 return -1;
421 msvcrt_wfttofd32(&find_data, ft);
422 TRACE(":got handle %p\n", hfind);
423 return (intptr_t)hfind;
426 /*********************************************************************
427 * _findfirsti64 (MSVCRT.@)
429 * 64-bit version of _findfirst.
431 intptr_t CDECL MSVCRT__findfirsti64(const char * fspec, struct MSVCRT__finddatai64_t* ft)
433 WIN32_FIND_DATAA find_data;
434 HANDLE hfind;
436 hfind = FindFirstFileA(fspec, &find_data);
437 if (hfind == INVALID_HANDLE_VALUE)
439 msvcrt_set_errno(GetLastError());
440 return -1;
442 msvcrt_fttofdi64(&find_data,ft);
443 TRACE(":got handle %p\n",hfind);
444 return (intptr_t)hfind;
447 /*********************************************************************
448 * _findfirst64 (MSVCRT.@)
450 * 64-bit version of _findfirst.
452 intptr_t CDECL MSVCRT__findfirst64(const char * fspec, struct MSVCRT__finddata64_t* ft)
454 WIN32_FIND_DATAA find_data;
455 HANDLE hfind;
457 hfind = FindFirstFileA(fspec, &find_data);
458 if (hfind == INVALID_HANDLE_VALUE)
460 msvcrt_set_errno(GetLastError());
461 return -1;
463 msvcrt_fttofd64(&find_data,ft);
464 TRACE(":got handle %p\n",hfind);
465 return (intptr_t)hfind;
468 /*********************************************************************
469 * _wfindfirst64 (MSVCRT.@)
471 * Unicode version of _findfirst64.
473 intptr_t CDECL MSVCRT__wfindfirst64(const wchar_t * fspec, struct MSVCRT__wfinddata64_t* ft)
475 WIN32_FIND_DATAW find_data;
476 HANDLE hfind;
478 hfind = FindFirstFileW(fspec, &find_data);
479 if (hfind == INVALID_HANDLE_VALUE)
481 msvcrt_set_errno(GetLastError());
482 return -1;
484 msvcrt_wfttofd64(&find_data,ft);
485 TRACE(":got handle %p\n",hfind);
486 return (intptr_t)hfind;
489 /*********************************************************************
490 * _findfirst64i32 (MSVCRT.@)
492 * 64-bit/32-bit version of _findfirst.
494 intptr_t CDECL MSVCRT__findfirst64i32(const char * fspec, struct MSVCRT__finddata64i32_t* ft)
496 WIN32_FIND_DATAA find_data;
497 HANDLE hfind;
499 hfind = FindFirstFileA(fspec, &find_data);
500 if (hfind == INVALID_HANDLE_VALUE)
502 msvcrt_set_errno(GetLastError());
503 return -1;
505 msvcrt_fttofd64i32(&find_data,ft);
506 TRACE(":got handle %p\n",hfind);
507 return (intptr_t)hfind;
510 /*********************************************************************
511 * _wfindfirst64i32 (MSVCRT.@)
513 * Unicode version of _findfirst64i32.
515 intptr_t CDECL MSVCRT__wfindfirst64i32(const wchar_t * fspec, struct MSVCRT__wfinddata64i32_t* ft)
517 WIN32_FIND_DATAW find_data;
518 HANDLE hfind;
520 hfind = FindFirstFileW(fspec, &find_data);
521 if (hfind == INVALID_HANDLE_VALUE)
523 msvcrt_set_errno(GetLastError());
524 return -1;
526 msvcrt_wfttofd64i32(&find_data,ft);
527 TRACE(":got handle %p\n",hfind);
528 return (intptr_t)hfind;
531 /*********************************************************************
532 * _wfindfirsti64 (MSVCRT.@)
534 * Unicode version of _findfirsti64.
536 intptr_t CDECL MSVCRT__wfindfirsti64(const wchar_t * fspec, struct MSVCRT__wfinddatai64_t* ft)
538 WIN32_FIND_DATAW find_data;
539 HANDLE hfind;
541 hfind = FindFirstFileW(fspec, &find_data);
542 if (hfind == INVALID_HANDLE_VALUE)
544 msvcrt_set_errno(GetLastError());
545 return -1;
547 msvcrt_wfttofdi64(&find_data,ft);
548 TRACE(":got handle %p\n",hfind);
549 return (intptr_t)hfind;
552 /*********************************************************************
553 * _findnext (MSVCRT.@)
555 * Find the next file from a file search handle.
557 * PARAMS
558 * hand [I] Handle to the search returned from _findfirst().
559 * ft [O] Information for the file found.
561 * RETURNS
562 * Success: 0. ft is populated with the details of the found file.
563 * Failure: -1. errno indicates the error.
565 * NOTES
566 * See FindNextFileA.
568 int CDECL MSVCRT__findnext(intptr_t hand, struct MSVCRT__finddata_t * ft)
570 WIN32_FIND_DATAA find_data;
572 if (!FindNextFileA((HANDLE)hand, &find_data))
574 *_errno() = ENOENT;
575 return -1;
578 msvcrt_fttofd(&find_data,ft);
579 return 0;
582 /*********************************************************************
583 * _findnext32 (MSVCRT.@)
585 int CDECL MSVCRT__findnext32(intptr_t hand, struct MSVCRT__finddata32_t * ft)
587 WIN32_FIND_DATAA find_data;
589 if (!FindNextFileA((HANDLE)hand, &find_data))
591 *_errno() = ENOENT;
592 return -1;
595 msvcrt_fttofd32(&find_data, ft);
596 return 0;
599 /*********************************************************************
600 * _wfindnext32 (MSVCRT.@)
602 int CDECL MSVCRT__wfindnext32(intptr_t hand, struct MSVCRT__wfinddata32_t * ft)
604 WIN32_FIND_DATAW find_data;
606 if (!FindNextFileW((HANDLE)hand, &find_data))
608 *_errno() = ENOENT;
609 return -1;
612 msvcrt_wfttofd32(&find_data, ft);
613 return 0;
616 /*********************************************************************
617 * _wfindnext (MSVCRT.@)
619 * Unicode version of _findnext.
621 int CDECL MSVCRT__wfindnext(intptr_t hand, struct MSVCRT__wfinddata_t * ft)
623 WIN32_FIND_DATAW find_data;
625 if (!FindNextFileW((HANDLE)hand, &find_data))
627 *_errno() = ENOENT;
628 return -1;
631 msvcrt_wfttofd(&find_data,ft);
632 return 0;
635 /*********************************************************************
636 * _findnexti64 (MSVCRT.@)
638 * 64-bit version of _findnext.
640 int CDECL MSVCRT__findnexti64(intptr_t hand, struct MSVCRT__finddatai64_t * ft)
642 WIN32_FIND_DATAA find_data;
644 if (!FindNextFileA((HANDLE)hand, &find_data))
646 *_errno() = ENOENT;
647 return -1;
650 msvcrt_fttofdi64(&find_data,ft);
651 return 0;
654 /*********************************************************************
655 * _findnext64 (MSVCRT.@)
657 * 64-bit version of _findnext.
659 int CDECL MSVCRT__findnext64(intptr_t hand, struct MSVCRT__finddata64_t * ft)
661 WIN32_FIND_DATAA find_data;
663 if (!FindNextFileA((HANDLE)hand, &find_data))
665 *_errno() = ENOENT;
666 return -1;
669 msvcrt_fttofd64(&find_data,ft);
670 return 0;
673 /*********************************************************************
674 * _wfindnext64 (MSVCRT.@)
676 * Unicode version of _wfindnext64.
678 int CDECL MSVCRT__wfindnext64(intptr_t hand, struct MSVCRT__wfinddata64_t * ft)
680 WIN32_FIND_DATAW find_data;
682 if (!FindNextFileW((HANDLE)hand, &find_data))
684 *_errno() = ENOENT;
685 return -1;
688 msvcrt_wfttofd64(&find_data,ft);
689 return 0;
692 /*********************************************************************
693 * _findnext64i32 (MSVCRT.@)
695 * 64-bit/32-bit version of _findnext.
697 int CDECL MSVCRT__findnext64i32(intptr_t hand, struct MSVCRT__finddata64i32_t * ft)
699 WIN32_FIND_DATAA find_data;
701 if (!FindNextFileA((HANDLE)hand, &find_data))
703 *_errno() = ENOENT;
704 return -1;
707 msvcrt_fttofd64i32(&find_data,ft);
708 return 0;
711 /*********************************************************************
712 * _wfindnexti64 (MSVCRT.@)
714 * Unicode version of _findnexti64.
716 int CDECL MSVCRT__wfindnexti64(intptr_t hand, struct MSVCRT__wfinddatai64_t * ft)
718 WIN32_FIND_DATAW find_data;
720 if (!FindNextFileW((HANDLE)hand, &find_data))
722 *_errno() = ENOENT;
723 return -1;
726 msvcrt_wfttofdi64(&find_data,ft);
727 return 0;
730 /*********************************************************************
731 * _wfindnext64i32 (MSVCRT.@)
733 * Unicode version of _findnext64i32.
735 int CDECL MSVCRT__wfindnext64i32(intptr_t hand, struct MSVCRT__wfinddata64i32_t * ft)
737 WIN32_FIND_DATAW find_data;
739 if (!FindNextFileW((HANDLE)hand, &find_data))
741 *_errno() = ENOENT;
742 return -1;
745 msvcrt_wfttofd64i32(&find_data,ft);
746 return 0;
749 /*********************************************************************
750 * _getcwd (MSVCRT.@)
752 * Get the current working directory.
754 * PARAMS
755 * buf [O] Destination for current working directory.
756 * size [I] Size of buf in characters
758 * RETURNS
759 * Success: If buf is NULL, returns an allocated string containing the path.
760 * Otherwise populates buf with the path and returns it.
761 * Failure: NULL. errno indicates the error.
763 char* CDECL MSVCRT__getcwd(char * buf, int size)
765 char dir[MAX_PATH];
766 int dir_len = GetCurrentDirectoryA(MAX_PATH,dir);
768 if (dir_len < 1)
769 return NULL; /* FIXME: Real return value untested */
771 if (!buf)
773 if (size <= dir_len) size = dir_len + 1;
774 if (!(buf = malloc( size ))) return NULL;
776 else if (dir_len >= size)
778 *_errno() = ERANGE;
779 return NULL; /* buf too small */
781 strcpy(buf,dir);
782 return buf;
785 /*********************************************************************
786 * _wgetcwd (MSVCRT.@)
788 * Unicode version of _getcwd.
790 wchar_t* CDECL MSVCRT__wgetcwd(wchar_t * buf, int size)
792 wchar_t dir[MAX_PATH];
793 int dir_len = GetCurrentDirectoryW(MAX_PATH,dir);
795 if (dir_len < 1)
796 return NULL; /* FIXME: Real return value untested */
798 if (!buf)
800 if (size <= dir_len) size = dir_len + 1;
801 if (!(buf = malloc( size * sizeof(WCHAR) ))) return NULL;
803 if (dir_len >= size)
805 *_errno() = ERANGE;
806 return NULL; /* buf too small */
808 MSVCRT_wcscpy(buf,dir);
809 return buf;
812 /*********************************************************************
813 * _getdrive (MSVCRT.@)
815 * Get the current drive number.
817 * PARAMS
818 * None.
820 * RETURNS
821 * Success: The drive letter number from 1 to 26 ("A:" to "Z:").
822 * Failure: 0.
824 int CDECL MSVCRT__getdrive(void)
826 WCHAR buffer[MAX_PATH];
827 if (GetCurrentDirectoryW( MAX_PATH, buffer ) &&
828 buffer[0] >= 'A' && buffer[0] <= 'z' && buffer[1] == ':')
829 return MSVCRT_towupper(buffer[0]) - 'A' + 1;
830 return 0;
833 /*********************************************************************
834 * _getdcwd (MSVCRT.@)
836 * Get the current working directory on a given disk.
838 * PARAMS
839 * drive [I] Drive letter to get the current working directory from.
840 * buf [O] Destination for the current working directory.
841 * size [I] Length of drive in characters.
843 * RETURNS
844 * Success: If drive is NULL, returns an allocated string containing the path.
845 * Otherwise populates drive with the path and returns it.
846 * Failure: NULL. errno indicates the error.
848 char* CDECL MSVCRT__getdcwd(int drive, char * buf, int size)
850 static char* dummy;
852 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
854 if (!drive || drive == MSVCRT__getdrive())
855 return MSVCRT__getcwd(buf,size); /* current */
856 else
858 char dir[MAX_PATH];
859 char drivespec[] = "A:";
860 int dir_len;
862 drivespec[0] += drive - 1;
863 if (GetDriveTypeA(drivespec) < DRIVE_REMOVABLE)
865 *_errno() = EACCES;
866 return NULL;
869 dir_len = GetFullPathNameA(drivespec,MAX_PATH,dir,&dummy);
870 if (dir_len >= size || dir_len < 1)
872 *_errno() = ERANGE;
873 return NULL; /* buf too small */
876 TRACE(":returning '%s'\n", dir);
877 if (!buf)
878 return _strdup(dir); /* allocate */
880 strcpy(buf,dir);
882 return buf;
885 /*********************************************************************
886 * _wgetdcwd (MSVCRT.@)
888 * Unicode version of _wgetdcwd.
890 wchar_t* CDECL MSVCRT__wgetdcwd(int drive, wchar_t * buf, int size)
892 static wchar_t* dummy;
894 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
896 if (!drive || drive == MSVCRT__getdrive())
897 return MSVCRT__wgetcwd(buf,size); /* current */
898 else
900 wchar_t dir[MAX_PATH];
901 wchar_t drivespec[4] = L"A:\\";
902 int dir_len;
904 drivespec[0] += drive - 1;
905 if (GetDriveTypeW(drivespec) < DRIVE_REMOVABLE)
907 *_errno() = EACCES;
908 return NULL;
911 dir_len = GetFullPathNameW(drivespec,MAX_PATH,dir,&dummy);
912 if (dir_len >= size || dir_len < 1)
914 *_errno() = ERANGE;
915 return NULL; /* buf too small */
918 TRACE(":returning %s\n", debugstr_w(dir));
919 if (!buf)
920 return MSVCRT__wcsdup(dir); /* allocate */
921 MSVCRT_wcscpy(buf,dir);
923 return buf;
926 /*********************************************************************
927 * _getdiskfree (MSVCRT.@)
929 * Get information about the free space on a drive.
931 * PARAMS
932 * disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
933 * info [O] Destination for the resulting information.
935 * RETURNS
936 * Success: 0. info is updated with the free space information.
937 * Failure: An error code from GetLastError().
939 * NOTES
940 * See GetLastError().
942 unsigned int CDECL MSVCRT__getdiskfree(unsigned int disk, struct _diskfree_t * d)
944 WCHAR drivespec[] = L"@:\\";
945 DWORD ret[4];
946 unsigned int err;
948 if (disk > 26)
949 return ERROR_INVALID_PARAMETER; /* MSVCRT doesn't set errno here */
951 drivespec[0] += disk; /* make a drive letter */
953 if (GetDiskFreeSpaceW(disk==0?NULL:drivespec,ret,ret+1,ret+2,ret+3))
955 d->sectors_per_cluster = ret[0];
956 d->bytes_per_sector = ret[1];
957 d->avail_clusters = ret[2];
958 d->total_clusters = ret[3];
959 return 0;
961 err = GetLastError();
962 msvcrt_set_errno(err);
963 return err;
966 /*********************************************************************
967 * _mkdir (MSVCRT.@)
969 * Create a directory.
971 * PARAMS
972 * newdir [I] Name of directory to create.
974 * RETURNS
975 * Success: 0. The directory indicated by newdir is created.
976 * Failure: -1. errno indicates the error.
978 * NOTES
979 * See CreateDirectoryA.
981 int CDECL MSVCRT__mkdir(const char * newdir)
983 if (CreateDirectoryA(newdir,NULL))
984 return 0;
985 msvcrt_set_errno(GetLastError());
986 return -1;
989 /*********************************************************************
990 * _wmkdir (MSVCRT.@)
992 * Unicode version of _mkdir.
994 int CDECL MSVCRT__wmkdir(const wchar_t* newdir)
996 if (CreateDirectoryW(newdir,NULL))
997 return 0;
998 msvcrt_set_errno(GetLastError());
999 return -1;
1002 /*********************************************************************
1003 * _rmdir (MSVCRT.@)
1005 * Delete a directory.
1007 * PARAMS
1008 * dir [I] Name of directory to delete.
1010 * RETURNS
1011 * Success: 0. The directory indicated by newdir is deleted.
1012 * Failure: -1. errno indicates the error.
1014 * NOTES
1015 * See RemoveDirectoryA.
1017 int CDECL MSVCRT__rmdir(const char * dir)
1019 if (RemoveDirectoryA(dir))
1020 return 0;
1021 msvcrt_set_errno(GetLastError());
1022 return -1;
1025 /*********************************************************************
1026 * _wrmdir (MSVCRT.@)
1028 * Unicode version of _rmdir.
1030 int CDECL MSVCRT__wrmdir(const wchar_t * dir)
1032 if (RemoveDirectoryW(dir))
1033 return 0;
1034 msvcrt_set_errno(GetLastError());
1035 return -1;
1038 /******************************************************************
1039 * _splitpath_s (MSVCRT.@)
1041 int CDECL MSVCRT__splitpath_s(const char* inpath,
1042 char* drive, size_t sz_drive,
1043 char* dir, size_t sz_dir,
1044 char* fname, size_t sz_fname,
1045 char* ext, size_t sz_ext)
1047 const char *p, *end;
1049 if (!inpath || (!drive && sz_drive) ||
1050 (drive && !sz_drive) ||
1051 (!dir && sz_dir) ||
1052 (dir && !sz_dir) ||
1053 (!fname && sz_fname) ||
1054 (fname && !sz_fname) ||
1055 (!ext && sz_ext) ||
1056 (ext && !sz_ext))
1058 *_errno() = EINVAL;
1059 return EINVAL;
1062 if (inpath[0] && inpath[1] == ':')
1064 if (drive)
1066 if (sz_drive <= 2) goto do_error;
1067 drive[0] = inpath[0];
1068 drive[1] = inpath[1];
1069 drive[2] = 0;
1071 inpath += 2;
1073 else if (drive) drive[0] = '\0';
1075 /* look for end of directory part */
1076 end = NULL;
1077 for (p = inpath; *p; p++)
1079 if (_ismbblead((unsigned char)*p))
1081 p++;
1082 continue;
1084 if (*p == '/' || *p == '\\') end = p + 1;
1087 if (end) /* got a directory */
1089 if (dir)
1091 if (sz_dir <= end - inpath) goto do_error;
1092 memcpy( dir, inpath, (end - inpath) );
1093 dir[end - inpath] = 0;
1095 inpath = end;
1097 else if (dir) dir[0] = 0;
1099 /* look for extension: what's after the last dot */
1100 end = NULL;
1101 for (p = inpath; *p; p++) if (*p == '.') end = p;
1103 if (!end) end = p; /* there's no extension */
1105 if (fname)
1107 if (sz_fname <= end - inpath) goto do_error;
1108 memcpy( fname, inpath, (end - inpath) );
1109 fname[end - inpath] = 0;
1111 if (ext)
1113 if (sz_ext <= strlen(end)) goto do_error;
1114 strcpy( ext, end );
1116 return 0;
1117 do_error:
1118 if (drive) drive[0] = '\0';
1119 if (dir) dir[0] = '\0';
1120 if (fname) fname[0]= '\0';
1121 if (ext) ext[0]= '\0';
1122 *_errno() = ERANGE;
1123 return ERANGE;
1126 /*********************************************************************
1127 * _splitpath (MSVCRT.@)
1129 void CDECL MSVCRT__splitpath(const char *inpath, char *drv, char *dir,
1130 char *fname, char *ext)
1132 MSVCRT__splitpath_s(inpath, drv, drv ? _MAX_DRIVE : 0, dir, dir ? _MAX_DIR : 0,
1133 fname, fname ? _MAX_FNAME : 0, ext, ext ? _MAX_EXT : 0);
1136 /******************************************************************
1137 * _wsplitpath_s (MSVCRT.@)
1139 * Secure version of _wsplitpath
1141 int CDECL MSVCRT__wsplitpath_s(const wchar_t* inpath,
1142 wchar_t* drive, size_t sz_drive,
1143 wchar_t* dir, size_t sz_dir,
1144 wchar_t* fname, size_t sz_fname,
1145 wchar_t* ext, size_t sz_ext)
1147 const wchar_t *p, *end;
1149 if (!inpath || (!drive && sz_drive) ||
1150 (drive && !sz_drive) ||
1151 (!dir && sz_dir) ||
1152 (dir && !sz_dir) ||
1153 (!fname && sz_fname) ||
1154 (fname && !sz_fname) ||
1155 (!ext && sz_ext) ||
1156 (ext && !sz_ext))
1158 *_errno() = EINVAL;
1159 return EINVAL;
1162 if (inpath[0] && inpath[1] == ':')
1164 if (drive)
1166 if (sz_drive <= 2) goto do_error;
1167 drive[0] = inpath[0];
1168 drive[1] = inpath[1];
1169 drive[2] = 0;
1171 inpath += 2;
1173 else if (drive) drive[0] = '\0';
1175 /* look for end of directory part */
1176 end = NULL;
1177 for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
1179 if (end) /* got a directory */
1181 if (dir)
1183 if (sz_dir <= end - inpath) goto do_error;
1184 memcpy( dir, inpath, (end - inpath) * sizeof(wchar_t) );
1185 dir[end - inpath] = 0;
1187 inpath = end;
1189 else if (dir) dir[0] = 0;
1191 /* look for extension: what's after the last dot */
1192 end = NULL;
1193 for (p = inpath; *p; p++) if (*p == '.') end = p;
1195 if (!end) end = p; /* there's no extension */
1197 if (fname)
1199 if (sz_fname <= end - inpath) goto do_error;
1200 memcpy( fname, inpath, (end - inpath) * sizeof(wchar_t) );
1201 fname[end - inpath] = 0;
1203 if (ext)
1205 if (sz_ext <= MSVCRT_wcslen(end)) goto do_error;
1206 MSVCRT_wcscpy( ext, end );
1208 return 0;
1209 do_error:
1210 if (drive) drive[0] = '\0';
1211 if (dir) dir[0] = '\0';
1212 if (fname) fname[0]= '\0';
1213 if (ext) ext[0]= '\0';
1214 *_errno() = ERANGE;
1215 return ERANGE;
1218 /*********************************************************************
1219 * _wsplitpath (MSVCRT.@)
1221 * Unicode version of _splitpath.
1223 void CDECL MSVCRT__wsplitpath(const wchar_t *inpath, wchar_t *drv, wchar_t *dir,
1224 wchar_t *fname, wchar_t *ext)
1226 MSVCRT__wsplitpath_s(inpath, drv, drv ? _MAX_DRIVE : 0, dir, dir ? _MAX_DIR : 0,
1227 fname, fname ? _MAX_FNAME : 0, ext, ext ? _MAX_EXT : 0);
1230 /*********************************************************************
1231 * _wfullpath (MSVCRT.@)
1233 * Unicode version of _fullpath.
1235 wchar_t * CDECL MSVCRT__wfullpath(wchar_t * absPath, const wchar_t* relPath, size_t size)
1237 DWORD rc;
1238 WCHAR* buffer;
1239 WCHAR* lastpart;
1240 BOOL alloced = FALSE;
1242 if (!relPath || !*relPath)
1243 return MSVCRT__wgetcwd(absPath, size);
1245 if (absPath == NULL)
1247 buffer = malloc(MAX_PATH * sizeof(WCHAR));
1248 size = MAX_PATH;
1249 alloced = TRUE;
1251 else
1252 buffer = absPath;
1254 if (size < 4)
1256 *_errno() = ERANGE;
1257 return NULL;
1260 TRACE(":resolving relative path %s\n",debugstr_w(relPath));
1262 rc = GetFullPathNameW(relPath,size,buffer,&lastpart);
1264 if (rc > 0 && rc <= size )
1265 return buffer;
1266 else
1268 if (alloced)
1269 free(buffer);
1270 return NULL;
1274 /*********************************************************************
1275 * _fullpath (MSVCRT.@)
1277 * Create an absolute path from a relative path.
1279 * PARAMS
1280 * absPath [O] Destination for absolute path
1281 * relPath [I] Relative path to convert to absolute
1282 * size [I] Length of absPath in characters.
1284 * RETURNS
1285 * Success: If absPath is NULL, returns an allocated string containing the path.
1286 * Otherwise populates absPath with the path and returns it.
1287 * Failure: NULL. errno indicates the error.
1289 char * CDECL MSVCRT__fullpath(char * absPath, const char* relPath, unsigned int size)
1291 DWORD rc;
1292 char* lastpart;
1293 char* buffer;
1294 BOOL alloced = FALSE;
1296 if (!relPath || !*relPath)
1297 return MSVCRT__getcwd(absPath, size);
1299 if (absPath == NULL)
1301 buffer = malloc(MAX_PATH);
1302 size = MAX_PATH;
1303 alloced = TRUE;
1305 else
1306 buffer = absPath;
1308 if (size < 4)
1310 *_errno() = ERANGE;
1311 return NULL;
1314 TRACE(":resolving relative path '%s'\n",relPath);
1316 rc = GetFullPathNameA(relPath,size,buffer,&lastpart);
1318 if (rc > 0 && rc <= size)
1319 return buffer;
1320 else
1322 if (alloced)
1323 free(buffer);
1324 return NULL;
1328 /*********************************************************************
1329 * _makepath (MSVCRT.@)
1331 * Create a pathname.
1333 * PARAMS
1334 * path [O] Destination for created pathname
1335 * drive [I] Drive letter (e.g. "A:")
1336 * directory [I] Directory
1337 * filename [I] Name of the file, excluding extension
1338 * extension [I] File extension (e.g. ".TXT")
1340 * RETURNS
1341 * Nothing. If path is not large enough to hold the resulting pathname,
1342 * random process memory will be overwritten.
1344 VOID CDECL MSVCRT__makepath(char * path, const char * drive,
1345 const char *directory, const char * filename,
1346 const char * extension)
1348 char *p = path;
1350 TRACE("(%s %s %s %s)\n", debugstr_a(drive), debugstr_a(directory),
1351 debugstr_a(filename), debugstr_a(extension) );
1353 if ( !path )
1354 return;
1356 if (drive && drive[0])
1358 *p++ = drive[0];
1359 *p++ = ':';
1361 if (directory && directory[0])
1363 unsigned int len = strlen(directory);
1364 memmove(p, directory, len);
1365 p += len;
1366 if (p[-1] != '/' && p[-1] != '\\')
1367 *p++ = '\\';
1369 if (filename && filename[0])
1371 unsigned int len = strlen(filename);
1372 memmove(p, filename, len);
1373 p += len;
1375 if (extension && extension[0])
1377 if (extension[0] != '.')
1378 *p++ = '.';
1379 strcpy(p, extension);
1381 else
1382 *p = '\0';
1383 TRACE("returning %s\n",path);
1386 /*********************************************************************
1387 * _wmakepath (MSVCRT.@)
1389 * Unicode version of _wmakepath.
1391 VOID CDECL MSVCRT__wmakepath(wchar_t *path, const wchar_t *drive, const wchar_t *directory,
1392 const wchar_t *filename, const wchar_t *extension)
1394 wchar_t *p = path;
1396 TRACE("%s %s %s %s\n", debugstr_w(drive), debugstr_w(directory),
1397 debugstr_w(filename), debugstr_w(extension));
1399 if ( !path )
1400 return;
1402 if (drive && drive[0])
1404 *p++ = drive[0];
1405 *p++ = ':';
1407 if (directory && directory[0])
1409 unsigned int len = MSVCRT_wcslen(directory);
1410 memmove(p, directory, len * sizeof(wchar_t));
1411 p += len;
1412 if (p[-1] != '/' && p[-1] != '\\')
1413 *p++ = '\\';
1415 if (filename && filename[0])
1417 unsigned int len = MSVCRT_wcslen(filename);
1418 memmove(p, filename, len * sizeof(wchar_t));
1419 p += len;
1421 if (extension && extension[0])
1423 if (extension[0] != '.')
1424 *p++ = '.';
1425 MSVCRT_wcscpy(p, extension);
1427 else
1428 *p = '\0';
1430 TRACE("returning %s\n", debugstr_w(path));
1433 /*********************************************************************
1434 * _makepath_s (MSVCRT.@)
1436 * Safe version of _makepath.
1438 int CDECL MSVCRT__makepath_s(char *path, size_t size, const char *drive,
1439 const char *directory, const char *filename,
1440 const char *extension)
1442 char *p = path;
1444 if (!path || !size)
1446 *_errno() = EINVAL;
1447 return EINVAL;
1450 if (drive && drive[0])
1452 if (size <= 2)
1453 goto range;
1455 *p++ = drive[0];
1456 *p++ = ':';
1457 size -= 2;
1460 if (directory && directory[0])
1462 unsigned int len = strlen(directory);
1463 unsigned int needs_separator = directory[len - 1] != '/' && directory[len - 1] != '\\';
1464 unsigned int copylen = min(size - 1, len);
1466 if (size < 2)
1467 goto range;
1469 memmove(p, directory, copylen);
1471 if (size <= len)
1472 goto range;
1474 p += copylen;
1475 size -= copylen;
1477 if (needs_separator)
1479 if (size < 2)
1480 goto range;
1482 *p++ = '\\';
1483 size -= 1;
1487 if (filename && filename[0])
1489 unsigned int len = strlen(filename);
1490 unsigned int copylen = min(size - 1, len);
1492 if (size < 2)
1493 goto range;
1495 memmove(p, filename, copylen);
1497 if (size <= len)
1498 goto range;
1500 p += len;
1501 size -= len;
1504 if (extension && extension[0])
1506 unsigned int len = strlen(extension);
1507 unsigned int needs_period = extension[0] != '.';
1508 unsigned int copylen;
1510 if (size < 2)
1511 goto range;
1513 if (needs_period)
1515 *p++ = '.';
1516 size -= 1;
1519 copylen = min(size - 1, len);
1520 memcpy(p, extension, copylen);
1522 if (size <= len)
1523 goto range;
1525 p += copylen;
1528 *p = '\0';
1529 return 0;
1531 range:
1532 path[0] = '\0';
1533 *_errno() = ERANGE;
1534 return ERANGE;
1537 /*********************************************************************
1538 * _wmakepath_s (MSVCRT.@)
1540 * Safe version of _wmakepath.
1542 int CDECL MSVCRT__wmakepath_s(wchar_t *path, size_t size, const wchar_t *drive,
1543 const wchar_t *directory, const wchar_t *filename,
1544 const wchar_t *extension)
1546 wchar_t *p = path;
1548 if (!path || !size)
1550 *_errno() = EINVAL;
1551 return EINVAL;
1554 if (drive && drive[0])
1556 if (size <= 2)
1557 goto range;
1559 *p++ = drive[0];
1560 *p++ = ':';
1561 size -= 2;
1564 if (directory && directory[0])
1566 unsigned int len = MSVCRT_wcslen(directory);
1567 unsigned int needs_separator = directory[len - 1] != '/' && directory[len - 1] != '\\';
1568 unsigned int copylen = min(size - 1, len);
1570 if (size < 2)
1571 goto range;
1573 memmove(p, directory, copylen * sizeof(wchar_t));
1575 if (size <= len)
1576 goto range;
1578 p += copylen;
1579 size -= copylen;
1581 if (needs_separator)
1583 if (size < 2)
1584 goto range;
1586 *p++ = '\\';
1587 size -= 1;
1591 if (filename && filename[0])
1593 unsigned int len = MSVCRT_wcslen(filename);
1594 unsigned int copylen = min(size - 1, len);
1596 if (size < 2)
1597 goto range;
1599 memmove(p, filename, copylen * sizeof(wchar_t));
1601 if (size <= len)
1602 goto range;
1604 p += len;
1605 size -= len;
1608 if (extension && extension[0])
1610 unsigned int len = MSVCRT_wcslen(extension);
1611 unsigned int needs_period = extension[0] != '.';
1612 unsigned int copylen;
1614 if (size < 2)
1615 goto range;
1617 if (needs_period)
1619 *p++ = '.';
1620 size -= 1;
1623 copylen = min(size - 1, len);
1624 memcpy(p, extension, copylen * sizeof(wchar_t));
1626 if (size <= len)
1627 goto range;
1629 p += copylen;
1632 *p = '\0';
1633 return 0;
1635 range:
1636 path[0] = '\0';
1637 *_errno() = ERANGE;
1638 return ERANGE;
1641 /*********************************************************************
1642 * _searchenv_s (MSVCRT.@)
1644 int CDECL MSVCRT__searchenv_s(const char* file, const char* env, char *buf, size_t count)
1646 char *envVal, *penv, *end;
1647 char path[MAX_PATH];
1648 size_t path_len, fname_len;
1650 if (!MSVCRT_CHECK_PMT(file != NULL)) return EINVAL;
1651 if (!MSVCRT_CHECK_PMT(buf != NULL)) return EINVAL;
1652 if (!MSVCRT_CHECK_PMT(count > 0)) return EINVAL;
1654 if (count > MAX_PATH)
1655 FIXME("count > MAX_PATH not supported\n");
1657 fname_len = strlen(file);
1658 *buf = '\0';
1660 /* Try CWD first */
1661 if (GetFileAttributesA( file ) != INVALID_FILE_ATTRIBUTES)
1663 if (GetFullPathNameA( file, count, buf, NULL )) return 0;
1664 msvcrt_set_errno(GetLastError());
1665 return 0;
1668 /* Search given environment variable */
1669 envVal = getenv(env);
1670 if (!envVal)
1672 *_errno() = ENOENT;
1673 return ENOENT;
1676 penv = envVal;
1677 TRACE(":searching for %s in paths %s\n", file, envVal);
1679 for(; *penv; penv = (*end ? end + 1 : end))
1681 end = penv;
1682 path_len = 0;
1683 while(*end && *end != ';' && path_len < MAX_PATH)
1685 if (*end == '"')
1687 end++;
1688 while(*end && *end != '"' && path_len < MAX_PATH)
1690 path[path_len++] = *end;
1691 end++;
1693 if (*end == '"') end++;
1694 continue;
1697 path[path_len++] = *end;
1698 end++;
1700 if (!path_len || path_len >= MAX_PATH)
1701 continue;
1703 if (path[path_len - 1] != '/' && path[path_len - 1] != '\\')
1704 path[path_len++] = '\\';
1705 if (path_len + fname_len >= MAX_PATH)
1706 continue;
1708 memcpy(path + path_len, file, fname_len + 1);
1709 TRACE("Checking for file %s\n", path);
1710 if (GetFileAttributesA( path ) != INVALID_FILE_ATTRIBUTES)
1712 if (path_len + fname_len + 1 > count)
1714 MSVCRT_INVALID_PMT("buf[count] is too small", ERANGE);
1715 return ERANGE;
1717 memcpy(buf, path, path_len + fname_len + 1);
1718 return 0;
1722 *_errno() = ENOENT;
1723 return ENOENT;
1726 /*********************************************************************
1727 * _searchenv (MSVCRT.@)
1729 void CDECL MSVCRT__searchenv(const char* file, const char* env, char *buf)
1731 MSVCRT__searchenv_s(file, env, buf, MAX_PATH);
1734 /*********************************************************************
1735 * _wsearchenv_s (MSVCRT.@)
1737 int CDECL MSVCRT__wsearchenv_s(const wchar_t* file, const wchar_t* env,
1738 wchar_t *buf, size_t count)
1740 wchar_t *envVal, *penv, *end;
1741 wchar_t path[MAX_PATH];
1742 size_t path_len, fname_len;
1744 if (!MSVCRT_CHECK_PMT(file != NULL)) return EINVAL;
1745 if (!MSVCRT_CHECK_PMT(buf != NULL)) return EINVAL;
1746 if (!MSVCRT_CHECK_PMT(count > 0)) return EINVAL;
1748 if (count > MAX_PATH)
1749 FIXME("count > MAX_PATH not supported\n");
1751 fname_len = MSVCRT_wcslen(file);
1752 *buf = '\0';
1754 /* Try CWD first */
1755 if (GetFileAttributesW( file ) != INVALID_FILE_ATTRIBUTES)
1757 if (GetFullPathNameW( file, count, buf, NULL )) return 0;
1758 msvcrt_set_errno(GetLastError());
1759 return 0;
1762 /* Search given environment variable */
1763 envVal = _wgetenv(env);
1764 if (!envVal)
1766 *_errno() = ENOENT;
1767 return ENOENT;
1770 penv = envVal;
1771 TRACE(":searching for %s in paths %s\n", debugstr_w(file), debugstr_w(envVal));
1773 for(; *penv; penv = (*end ? end + 1 : end))
1775 end = penv;
1776 path_len = 0;
1777 while(*end && *end != ';' && path_len < MAX_PATH)
1779 if (*end == '"')
1781 end++;
1782 while(*end && *end != '"' && path_len < MAX_PATH)
1784 path[path_len++] = *end;
1785 end++;
1787 if (*end == '"') end++;
1788 continue;
1791 path[path_len++] = *end;
1792 end++;
1794 if (!path_len || path_len >= MAX_PATH)
1795 continue;
1797 if (path[path_len - 1] != '/' && path[path_len - 1] != '\\')
1798 path[path_len++] = '\\';
1799 if (path_len + fname_len >= MAX_PATH)
1800 continue;
1802 memcpy(path + path_len, file, (fname_len + 1) * sizeof(wchar_t));
1803 TRACE("Checking for file %s\n", debugstr_w(path));
1804 if (GetFileAttributesW( path ) != INVALID_FILE_ATTRIBUTES)
1806 if (path_len + fname_len + 1 > count)
1808 MSVCRT_INVALID_PMT("buf[count] is too small", ERANGE);
1809 return ERANGE;
1811 memcpy(buf, path, (path_len + fname_len + 1) * sizeof(wchar_t));
1812 return 0;
1816 *_errno() = ENOENT;
1817 return ENOENT;
1820 /*********************************************************************
1821 * _wsearchenv (MSVCRT.@)
1823 void CDECL MSVCRT__wsearchenv(const wchar_t* file, const wchar_t* env, wchar_t *buf)
1825 MSVCRT__wsearchenv_s(file, env, buf, MAX_PATH);