advapi32/tests: Add trailing slashes tests for RegOpen/CreateKey.
[wine.git] / dlls / msvcrt / dir.c
blob3c5d16f12eada865c8a2e35f1696ff784a17ed87
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 "config.h"
25 #include "wine/port.h"
27 #include <stdarg.h>
29 #include "windef.h"
30 #include "winbase.h"
31 #include "winternl.h"
32 #include "wine/unicode.h"
33 #include "msvcrt.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)
41 DWORD dw;
43 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
44 ft->attrib = 0;
45 else
46 ft->attrib = fd->dwFileAttributes;
48 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
49 ft->time_create = dw;
50 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
51 ft->time_access = dw;
52 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
53 ft->time_write = 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)
61 DWORD dw;
63 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
64 ft->attrib = 0;
65 else
66 ft->attrib = fd->dwFileAttributes;
68 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
69 ft->time_create = dw;
70 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
71 ft->time_access = dw;
72 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
73 ft->time_write = 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)
81 DWORD dw;
83 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
84 ft->attrib = 0;
85 else
86 ft->attrib = fd->dwFileAttributes;
88 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
89 ft->time_create = dw;
90 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
91 ft->time_access = dw;
92 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
93 ft->time_write = 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)
101 DWORD dw;
103 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
104 ft->attrib = 0;
105 else
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 );
113 ft->time_write = 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)
121 DWORD dw;
123 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
124 ft->attrib = 0;
125 else
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 );
133 ft->time_write = 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)
141 DWORD dw;
143 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
144 ft->attrib = 0;
145 else
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 );
153 ft->time_write = 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)
161 DWORD dw;
163 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
164 ft->attrib = 0;
165 else
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 );
173 ft->time_write = 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)
181 DWORD dw;
183 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
184 ft->attrib = 0;
185 else
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 );
193 ft->time_write = 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)
201 DWORD dw;
203 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
204 ft->attrib = 0;
205 else
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 );
213 ft->time_write = 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)
221 DWORD dw;
223 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
224 ft->attrib = 0;
225 else
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 );
233 ft->time_write = dw;
234 ft->size = fd->nFileSizeLow;
235 strcpyW(ft->name, fd->cFileName);
238 /*********************************************************************
239 * _chdir (MSVCRT.@)
241 * Change the current working directory.
243 * PARAMS
244 * newdir [I] Directory to change to
246 * RETURNS
247 * Success: 0. The current working directory is set to newdir.
248 * Failure: -1. errno indicates the error.
250 * NOTES
251 * See SetCurrentDirectoryA.
253 int CDECL MSVCRT__chdir(const char * newdir)
255 if (!SetCurrentDirectoryA(newdir))
257 msvcrt_set_errno(newdir?GetLastError():0);
258 return -1;
260 return 0;
263 /*********************************************************************
264 * _wchdir (MSVCRT.@)
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);
273 return -1;
275 return 0;
278 /*********************************************************************
279 * _chdrive (MSVCRT.@)
281 * Change the current drive.
283 * PARAMS
284 * newdrive [I] Drive number to change to (1 = 'A', 2 = 'B', ...)
286 * RETURNS
287 * Success: 0. The current drive is set to newdrive.
288 * Failure: -1. errno indicates the error.
290 * NOTES
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());
301 if (newdrive <= 0)
302 *MSVCRT__errno() = MSVCRT_EACCES;
303 return -1;
305 return 0;
308 /*********************************************************************
309 * _findclose (MSVCRT.@)
311 * Close a handle returned by _findfirst().
313 * PARAMS
314 * hand [I] Handle to close
316 * RETURNS
317 * Success: 0. All resources associated with hand are freed.
318 * Failure: -1. errno indicates the error.
320 * NOTES
321 * See FindClose.
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());
329 return -1;
331 return 0;
334 /*********************************************************************
335 * _findfirst (MSVCRT.@)
337 * Open a handle for iterating through a directory.
339 * PARAMS
340 * fspec [I] File specification of files to iterate.
341 * ft [O] Information for the first file found.
343 * RETURNS
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.
348 * NOTES
349 * See FindFirstFileA.
351 MSVCRT_intptr_t CDECL MSVCRT__findfirst(const char * fspec, struct MSVCRT__finddata_t* ft)
353 WIN32_FIND_DATAA find_data;
354 HANDLE hfind;
356 hfind = FindFirstFileA(fspec, &find_data);
357 if (hfind == INVALID_HANDLE_VALUE)
359 msvcrt_set_errno(GetLastError());
360 return -1;
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;
373 HANDLE hfind;
375 hfind = FindFirstFileA(fspec, &find_data);
376 if (hfind == INVALID_HANDLE_VALUE)
378 msvcrt_set_errno(GetLastError());
379 return -1;
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;
394 HANDLE hfind;
396 hfind = FindFirstFileW(fspec, &find_data);
397 if (hfind == INVALID_HANDLE_VALUE)
399 msvcrt_set_errno(GetLastError());
400 return -1;
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;
415 HANDLE hfind;
417 hfind = FindFirstFileW(fspec, &find_data);
418 if (hfind == INVALID_HANDLE_VALUE)
420 msvcrt_set_errno(GetLastError());
421 return -1;
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;
436 HANDLE hfind;
438 hfind = FindFirstFileA(fspec, &find_data);
439 if (hfind == INVALID_HANDLE_VALUE)
441 msvcrt_set_errno(GetLastError());
442 return -1;
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;
457 HANDLE hfind;
459 hfind = FindFirstFileA(fspec, &find_data);
460 if (hfind == INVALID_HANDLE_VALUE)
462 msvcrt_set_errno(GetLastError());
463 return -1;
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;
478 HANDLE hfind;
480 hfind = FindFirstFileW(fspec, &find_data);
481 if (hfind == INVALID_HANDLE_VALUE)
483 msvcrt_set_errno(GetLastError());
484 return -1;
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;
499 HANDLE hfind;
501 hfind = FindFirstFileA(fspec, &find_data);
502 if (hfind == INVALID_HANDLE_VALUE)
504 msvcrt_set_errno(GetLastError());
505 return -1;
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;
520 HANDLE hfind;
522 hfind = FindFirstFileW(fspec, &find_data);
523 if (hfind == INVALID_HANDLE_VALUE)
525 msvcrt_set_errno(GetLastError());
526 return -1;
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;
541 HANDLE hfind;
543 hfind = FindFirstFileW(fspec, &find_data);
544 if (hfind == INVALID_HANDLE_VALUE)
546 msvcrt_set_errno(GetLastError());
547 return -1;
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.
559 * PARAMS
560 * hand [I] Handle to the search returned from _findfirst().
561 * ft [O] Information for the file found.
563 * RETURNS
564 * Success: 0. ft is populated with the details of the found file.
565 * Failure: -1. errno indicates the error.
567 * NOTES
568 * See FindNextFileA.
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;
577 return -1;
580 msvcrt_fttofd(&find_data,ft);
581 return 0;
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;
594 return -1;
597 msvcrt_fttofd32(&find_data, ft);
598 return 0;
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;
613 return -1;
616 msvcrt_wfttofd(&find_data,ft);
617 return 0;
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;
632 return -1;
635 msvcrt_fttofdi64(&find_data,ft);
636 return 0;
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;
651 return -1;
654 msvcrt_fttofd64(&find_data,ft);
655 return 0;
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;
670 return -1;
673 msvcrt_wfttofd64(&find_data,ft);
674 return 0;
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;
689 return -1;
692 msvcrt_fttofd64i32(&find_data,ft);
693 return 0;
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;
708 return -1;
711 msvcrt_wfttofdi64(&find_data,ft);
712 return 0;
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;
727 return -1;
730 msvcrt_wfttofd64i32(&find_data,ft);
731 return 0;
734 /*********************************************************************
735 * _getcwd (MSVCRT.@)
737 * Get the current working directory.
739 * PARAMS
740 * buf [O] Destination for current working directory.
741 * size [I] Size of buf in characters
743 * RETURNS
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)
750 char dir[MAX_PATH];
751 int dir_len = GetCurrentDirectoryA(MAX_PATH,dir);
753 if (dir_len < 1)
754 return NULL; /* FIXME: Real return value untested */
756 if (!buf)
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 */
766 strcpy(buf,dir);
767 return buf;
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);
780 if (dir_len < 1)
781 return NULL; /* FIXME: Real return value untested */
783 if (!buf)
785 if (size <= dir_len) size = dir_len + 1;
786 if (!(buf = MSVCRT_malloc( size * sizeof(WCHAR) ))) return NULL;
788 if (dir_len >= size)
790 *MSVCRT__errno() = MSVCRT_ERANGE;
791 return NULL; /* buf too small */
793 strcpyW(buf,dir);
794 return buf;
797 /*********************************************************************
798 * _getdrive (MSVCRT.@)
800 * Get the current drive number.
802 * PARAMS
803 * None.
805 * RETURNS
806 * Success: The drive letter number from 1 to 26 ("A:" to "Z:").
807 * Failure: 0.
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;
815 return 0;
818 /*********************************************************************
819 * _getdcwd (MSVCRT.@)
821 * Get the current working directory on a given disk.
823 * PARAMS
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.
828 * RETURNS
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)
835 static char* dummy;
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 */
841 else
843 char dir[MAX_PATH];
844 char drivespec[] = {'A', ':', 0};
845 int dir_len;
847 drivespec[0] += drive - 1;
848 if (GetDriveTypeA(drivespec) < DRIVE_REMOVABLE)
850 *MSVCRT__errno() = MSVCRT_EACCES;
851 return NULL;
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);
862 if (!buf)
863 return MSVCRT__strdup(dir); /* allocate */
865 strcpy(buf,dir);
867 return buf;
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 */
883 else
885 MSVCRT_wchar_t dir[MAX_PATH];
886 MSVCRT_wchar_t drivespec[4] = {'A', ':', '\\', 0};
887 int dir_len;
889 drivespec[0] += drive - 1;
890 if (GetDriveTypeW(drivespec) < DRIVE_REMOVABLE)
892 *MSVCRT__errno() = MSVCRT_EACCES;
893 return NULL;
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));
904 if (!buf)
905 return MSVCRT__wcsdup(dir); /* allocate */
906 strcpyW(buf,dir);
908 return buf;
911 /*********************************************************************
912 * _getdiskfree (MSVCRT.@)
914 * Get information about the free space on a drive.
916 * PARAMS
917 * disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
918 * info [O] Destination for the resulting information.
920 * RETURNS
921 * Success: 0. info is updated with the free space information.
922 * Failure: An error code from GetLastError().
924 * NOTES
925 * See GetLastError().
927 unsigned int CDECL MSVCRT__getdiskfree(unsigned int disk, struct MSVCRT__diskfree_t * d)
929 WCHAR drivespec[] = {'@', ':', '\\', 0};
930 DWORD ret[4];
931 unsigned int err;
933 if (disk > 26)
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];
944 return 0;
946 err = GetLastError();
947 msvcrt_set_errno(err);
948 return err;
951 /*********************************************************************
952 * _mkdir (MSVCRT.@)
954 * Create a directory.
956 * PARAMS
957 * newdir [I] Name of directory to create.
959 * RETURNS
960 * Success: 0. The directory indicated by newdir is created.
961 * Failure: -1. errno indicates the error.
963 * NOTES
964 * See CreateDirectoryA.
966 int CDECL MSVCRT__mkdir(const char * newdir)
968 if (CreateDirectoryA(newdir,NULL))
969 return 0;
970 msvcrt_set_errno(GetLastError());
971 return -1;
974 /*********************************************************************
975 * _wmkdir (MSVCRT.@)
977 * Unicode version of _mkdir.
979 int CDECL MSVCRT__wmkdir(const MSVCRT_wchar_t* newdir)
981 if (CreateDirectoryW(newdir,NULL))
982 return 0;
983 msvcrt_set_errno(GetLastError());
984 return -1;
987 /*********************************************************************
988 * _rmdir (MSVCRT.@)
990 * Delete a directory.
992 * PARAMS
993 * dir [I] Name of directory to delete.
995 * RETURNS
996 * Success: 0. The directory indicated by newdir is deleted.
997 * Failure: -1. errno indicates the error.
999 * NOTES
1000 * See RemoveDirectoryA.
1002 int CDECL MSVCRT__rmdir(const char * dir)
1004 if (RemoveDirectoryA(dir))
1005 return 0;
1006 msvcrt_set_errno(GetLastError());
1007 return -1;
1010 /*********************************************************************
1011 * _wrmdir (MSVCRT.@)
1013 * Unicode version of _rmdir.
1015 int CDECL MSVCRT__wrmdir(const MSVCRT_wchar_t * dir)
1017 if (RemoveDirectoryW(dir))
1018 return 0;
1019 msvcrt_set_errno(GetLastError());
1020 return -1;
1023 /******************************************************************
1024 * _splitpath_s (MSVCRT.@)
1026 int CDECL MSVCRT__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) ||
1036 (!dir && sz_dir) ||
1037 (dir && !sz_dir) ||
1038 (!fname && sz_fname) ||
1039 (fname && !sz_fname) ||
1040 (!ext && sz_ext) ||
1041 (ext && !sz_ext))
1043 *MSVCRT__errno() = MSVCRT_EINVAL;
1044 return MSVCRT_EINVAL;
1047 if (inpath[0] && inpath[1] == ':')
1049 if (drive)
1051 if (sz_drive <= 2) goto do_error;
1052 drive[0] = inpath[0];
1053 drive[1] = inpath[1];
1054 drive[2] = 0;
1056 inpath += 2;
1058 else if (drive) drive[0] = '\0';
1060 /* look for end of directory part */
1061 end = NULL;
1062 for (p = inpath; *p; p++)
1064 if (_ismbblead((unsigned char)*p))
1066 p++;
1067 continue;
1069 if (*p == '/' || *p == '\\') end = p + 1;
1072 if (end) /* got a directory */
1074 if (dir)
1076 if (sz_dir <= end - inpath) goto do_error;
1077 memcpy( dir, inpath, (end - inpath) );
1078 dir[end - inpath] = 0;
1080 inpath = end;
1082 else if (dir) dir[0] = 0;
1084 /* look for extension: what's after the last dot */
1085 end = NULL;
1086 for (p = inpath; *p; p++) if (*p == '.') end = p;
1088 if (!end) end = p; /* there's no extension */
1090 if (fname)
1092 if (sz_fname <= end - inpath) goto do_error;
1093 memcpy( fname, inpath, (end - inpath) );
1094 fname[end - inpath] = 0;
1096 if (ext)
1098 if (sz_ext <= strlen(end)) goto do_error;
1099 strcpy( ext, end );
1101 return 0;
1102 do_error:
1103 if (drive) drive[0] = '\0';
1104 if (dir) dir[0] = '\0';
1105 if (fname) fname[0]= '\0';
1106 if (ext) ext[0]= '\0';
1107 *MSVCRT__errno() = MSVCRT_ERANGE;
1108 return MSVCRT_ERANGE;
1111 /*********************************************************************
1112 * _splitpath (MSVCRT.@)
1114 void CDECL MSVCRT__splitpath(const char *inpath, char *drv, char *dir,
1115 char *fname, char *ext)
1117 MSVCRT__splitpath_s(inpath, drv, drv?MSVCRT__MAX_DRIVE:0, dir, dir?MSVCRT__MAX_DIR:0,
1118 fname, fname?MSVCRT__MAX_FNAME:0, ext, ext?MSVCRT__MAX_EXT:0);
1121 /******************************************************************
1122 * _wsplitpath_s (MSVCRT.@)
1124 * Secure version of _wsplitpath
1126 int CDECL MSVCRT__wsplitpath_s(const MSVCRT_wchar_t* inpath,
1127 MSVCRT_wchar_t* drive, MSVCRT_size_t sz_drive,
1128 MSVCRT_wchar_t* dir, MSVCRT_size_t sz_dir,
1129 MSVCRT_wchar_t* fname, MSVCRT_size_t sz_fname,
1130 MSVCRT_wchar_t* ext, MSVCRT_size_t sz_ext)
1132 const MSVCRT_wchar_t *p, *end;
1134 if (!inpath || (!drive && sz_drive) ||
1135 (drive && !sz_drive) ||
1136 (!dir && sz_dir) ||
1137 (dir && !sz_dir) ||
1138 (!fname && sz_fname) ||
1139 (fname && !sz_fname) ||
1140 (!ext && sz_ext) ||
1141 (ext && !sz_ext))
1143 *MSVCRT__errno() = MSVCRT_EINVAL;
1144 return MSVCRT_EINVAL;
1147 if (inpath[0] && inpath[1] == ':')
1149 if (drive)
1151 if (sz_drive <= 2) goto do_error;
1152 drive[0] = inpath[0];
1153 drive[1] = inpath[1];
1154 drive[2] = 0;
1156 inpath += 2;
1158 else if (drive) drive[0] = '\0';
1160 /* look for end of directory part */
1161 end = NULL;
1162 for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
1164 if (end) /* got a directory */
1166 if (dir)
1168 if (sz_dir <= end - inpath) goto do_error;
1169 memcpy( dir, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
1170 dir[end - inpath] = 0;
1172 inpath = end;
1174 else if (dir) dir[0] = 0;
1176 /* look for extension: what's after the last dot */
1177 end = NULL;
1178 for (p = inpath; *p; p++) if (*p == '.') end = p;
1180 if (!end) end = p; /* there's no extension */
1182 if (fname)
1184 if (sz_fname <= end - inpath) goto do_error;
1185 memcpy( fname, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
1186 fname[end - inpath] = 0;
1188 if (ext)
1190 if (sz_ext <= strlenW(end)) goto do_error;
1191 strcpyW( ext, end );
1193 return 0;
1194 do_error:
1195 if (drive) drive[0] = '\0';
1196 if (dir) dir[0] = '\0';
1197 if (fname) fname[0]= '\0';
1198 if (ext) ext[0]= '\0';
1199 *MSVCRT__errno() = MSVCRT_ERANGE;
1200 return MSVCRT_ERANGE;
1203 /*********************************************************************
1204 * _wsplitpath (MSVCRT.@)
1206 * Unicode version of _splitpath.
1208 void CDECL MSVCRT__wsplitpath(const MSVCRT_wchar_t *inpath, MSVCRT_wchar_t *drv, MSVCRT_wchar_t *dir,
1209 MSVCRT_wchar_t *fname, MSVCRT_wchar_t *ext)
1211 MSVCRT__wsplitpath_s(inpath, drv, drv?MSVCRT__MAX_DRIVE:0, dir, dir?MSVCRT__MAX_DIR:0,
1212 fname, fname?MSVCRT__MAX_FNAME:0, ext, ext?MSVCRT__MAX_EXT:0);
1215 /*********************************************************************
1216 * _wfullpath (MSVCRT.@)
1218 * Unicode version of _fullpath.
1220 MSVCRT_wchar_t * CDECL MSVCRT__wfullpath(MSVCRT_wchar_t * absPath, const MSVCRT_wchar_t* relPath, MSVCRT_size_t size)
1222 DWORD rc;
1223 WCHAR* buffer;
1224 WCHAR* lastpart;
1225 BOOL alloced = FALSE;
1227 if (!relPath || !*relPath)
1228 return MSVCRT__wgetcwd(absPath, size);
1230 if (absPath == NULL)
1232 buffer = MSVCRT_malloc(MAX_PATH * sizeof(WCHAR));
1233 size = MAX_PATH;
1234 alloced = TRUE;
1236 else
1237 buffer = absPath;
1239 if (size < 4)
1241 *MSVCRT__errno() = MSVCRT_ERANGE;
1242 return NULL;
1245 TRACE(":resolving relative path %s\n",debugstr_w(relPath));
1247 rc = GetFullPathNameW(relPath,size,buffer,&lastpart);
1249 if (rc > 0 && rc <= size )
1250 return buffer;
1251 else
1253 if (alloced)
1254 MSVCRT_free(buffer);
1255 return NULL;
1259 /*********************************************************************
1260 * _fullpath (MSVCRT.@)
1262 * Create an absolute path from a relative path.
1264 * PARAMS
1265 * absPath [O] Destination for absolute path
1266 * relPath [I] Relative path to convert to absolute
1267 * size [I] Length of absPath in characters.
1269 * RETURNS
1270 * Success: If absPath is NULL, returns an allocated string containing the path.
1271 * Otherwise populates absPath with the path and returns it.
1272 * Failure: NULL. errno indicates the error.
1274 char * CDECL MSVCRT__fullpath(char * absPath, const char* relPath, unsigned int size)
1276 DWORD rc;
1277 char* lastpart;
1278 char* buffer;
1279 BOOL alloced = FALSE;
1281 if (!relPath || !*relPath)
1282 return MSVCRT__getcwd(absPath, size);
1284 if (absPath == NULL)
1286 buffer = MSVCRT_malloc(MAX_PATH);
1287 size = MAX_PATH;
1288 alloced = TRUE;
1290 else
1291 buffer = absPath;
1293 if (size < 4)
1295 *MSVCRT__errno() = MSVCRT_ERANGE;
1296 return NULL;
1299 TRACE(":resolving relative path '%s'\n",relPath);
1301 rc = GetFullPathNameA(relPath,size,buffer,&lastpart);
1303 if (rc > 0 && rc <= size)
1304 return buffer;
1305 else
1307 if (alloced)
1308 MSVCRT_free(buffer);
1309 return NULL;
1313 /*********************************************************************
1314 * _makepath (MSVCRT.@)
1316 * Create a pathname.
1318 * PARAMS
1319 * path [O] Destination for created pathname
1320 * drive [I] Drive letter (e.g. "A:")
1321 * directory [I] Directory
1322 * filename [I] Name of the file, excluding extension
1323 * extension [I] File extension (e.g. ".TXT")
1325 * RETURNS
1326 * Nothing. If path is not large enough to hold the resulting pathname,
1327 * random process memory will be overwritten.
1329 VOID CDECL MSVCRT__makepath(char * path, const char * drive,
1330 const char *directory, const char * filename,
1331 const char * extension)
1333 char *p = path;
1335 TRACE("(%s %s %s %s)\n", debugstr_a(drive), debugstr_a(directory),
1336 debugstr_a(filename), debugstr_a(extension) );
1338 if ( !path )
1339 return;
1341 if (drive && drive[0])
1343 *p++ = drive[0];
1344 *p++ = ':';
1346 if (directory && directory[0])
1348 unsigned int len = strlen(directory);
1349 memmove(p, directory, len);
1350 p += len;
1351 if (p[-1] != '/' && p[-1] != '\\')
1352 *p++ = '\\';
1354 if (filename && filename[0])
1356 unsigned int len = strlen(filename);
1357 memmove(p, filename, len);
1358 p += len;
1360 if (extension && extension[0])
1362 if (extension[0] != '.')
1363 *p++ = '.';
1364 strcpy(p, extension);
1366 else
1367 *p = '\0';
1368 TRACE("returning %s\n",path);
1371 /*********************************************************************
1372 * _wmakepath (MSVCRT.@)
1374 * Unicode version of _wmakepath.
1376 VOID CDECL MSVCRT__wmakepath(MSVCRT_wchar_t *path, const MSVCRT_wchar_t *drive, const MSVCRT_wchar_t *directory,
1377 const MSVCRT_wchar_t *filename, const MSVCRT_wchar_t *extension)
1379 MSVCRT_wchar_t *p = path;
1381 TRACE("%s %s %s %s\n", debugstr_w(drive), debugstr_w(directory),
1382 debugstr_w(filename), debugstr_w(extension));
1384 if ( !path )
1385 return;
1387 if (drive && drive[0])
1389 *p++ = drive[0];
1390 *p++ = ':';
1392 if (directory && directory[0])
1394 unsigned int len = strlenW(directory);
1395 memmove(p, directory, len * sizeof(MSVCRT_wchar_t));
1396 p += len;
1397 if (p[-1] != '/' && p[-1] != '\\')
1398 *p++ = '\\';
1400 if (filename && filename[0])
1402 unsigned int len = strlenW(filename);
1403 memmove(p, filename, len * sizeof(MSVCRT_wchar_t));
1404 p += len;
1406 if (extension && extension[0])
1408 if (extension[0] != '.')
1409 *p++ = '.';
1410 strcpyW(p, extension);
1412 else
1413 *p = '\0';
1415 TRACE("returning %s\n", debugstr_w(path));
1418 /*********************************************************************
1419 * _makepath_s (MSVCRT.@)
1421 * Safe version of _makepath.
1423 int CDECL MSVCRT__makepath_s(char *path, MSVCRT_size_t size, const char *drive,
1424 const char *directory, const char *filename,
1425 const char *extension)
1427 char *p = path;
1429 if (!path || !size)
1431 *MSVCRT__errno() = MSVCRT_EINVAL;
1432 return MSVCRT_EINVAL;
1435 if (drive && drive[0])
1437 if (size <= 2)
1438 goto range;
1440 *p++ = drive[0];
1441 *p++ = ':';
1442 size -= 2;
1445 if (directory && directory[0])
1447 unsigned int len = strlen(directory);
1448 unsigned int needs_separator = directory[len - 1] != '/' && directory[len - 1] != '\\';
1449 unsigned int copylen = min(size - 1, len);
1451 if (size < 2)
1452 goto range;
1454 memmove(p, directory, copylen);
1456 if (size <= len)
1457 goto range;
1459 p += copylen;
1460 size -= copylen;
1462 if (needs_separator)
1464 if (size < 2)
1465 goto range;
1467 *p++ = '\\';
1468 size -= 1;
1472 if (filename && filename[0])
1474 unsigned int len = strlen(filename);
1475 unsigned int copylen = min(size - 1, len);
1477 if (size < 2)
1478 goto range;
1480 memmove(p, filename, copylen);
1482 if (size <= len)
1483 goto range;
1485 p += len;
1486 size -= len;
1489 if (extension && extension[0])
1491 unsigned int len = strlen(extension);
1492 unsigned int needs_period = extension[0] != '.';
1493 unsigned int copylen;
1495 if (size < 2)
1496 goto range;
1498 if (needs_period)
1500 *p++ = '.';
1501 size -= 1;
1504 copylen = min(size - 1, len);
1505 memcpy(p, extension, copylen);
1507 if (size <= len)
1508 goto range;
1510 p += copylen;
1513 *p = '\0';
1514 return 0;
1516 range:
1517 path[0] = '\0';
1518 *MSVCRT__errno() = MSVCRT_ERANGE;
1519 return MSVCRT_ERANGE;
1522 /*********************************************************************
1523 * _wmakepath_s (MSVCRT.@)
1525 * Safe version of _wmakepath.
1527 int CDECL MSVCRT__wmakepath_s(MSVCRT_wchar_t *path, MSVCRT_size_t size, const MSVCRT_wchar_t *drive,
1528 const MSVCRT_wchar_t *directory, const MSVCRT_wchar_t *filename,
1529 const MSVCRT_wchar_t *extension)
1531 MSVCRT_wchar_t *p = path;
1533 if (!path || !size)
1535 *MSVCRT__errno() = MSVCRT_EINVAL;
1536 return MSVCRT_EINVAL;
1539 if (drive && drive[0])
1541 if (size <= 2)
1542 goto range;
1544 *p++ = drive[0];
1545 *p++ = ':';
1546 size -= 2;
1549 if (directory && directory[0])
1551 unsigned int len = strlenW(directory);
1552 unsigned int needs_separator = directory[len - 1] != '/' && directory[len - 1] != '\\';
1553 unsigned int copylen = min(size - 1, len);
1555 if (size < 2)
1556 goto range;
1558 memmove(p, directory, copylen * sizeof(MSVCRT_wchar_t));
1560 if (size <= len)
1561 goto range;
1563 p += copylen;
1564 size -= copylen;
1566 if (needs_separator)
1568 if (size < 2)
1569 goto range;
1571 *p++ = '\\';
1572 size -= 1;
1576 if (filename && filename[0])
1578 unsigned int len = strlenW(filename);
1579 unsigned int copylen = min(size - 1, len);
1581 if (size < 2)
1582 goto range;
1584 memmove(p, filename, copylen * sizeof(MSVCRT_wchar_t));
1586 if (size <= len)
1587 goto range;
1589 p += len;
1590 size -= len;
1593 if (extension && extension[0])
1595 unsigned int len = strlenW(extension);
1596 unsigned int needs_period = extension[0] != '.';
1597 unsigned int copylen;
1599 if (size < 2)
1600 goto range;
1602 if (needs_period)
1604 *p++ = '.';
1605 size -= 1;
1608 copylen = min(size - 1, len);
1609 memcpy(p, extension, copylen * sizeof(MSVCRT_wchar_t));
1611 if (size <= len)
1612 goto range;
1614 p += copylen;
1617 *p = '\0';
1618 return 0;
1620 range:
1621 path[0] = '\0';
1622 *MSVCRT__errno() = MSVCRT_ERANGE;
1623 return MSVCRT_ERANGE;
1626 /*********************************************************************
1627 * _searchenv (MSVCRT.@)
1629 * Search for a file in a list of paths from an environment variable.
1631 * PARAMS
1632 * file [I] Name of the file to search for.
1633 * env [I] Name of the environment variable containing a list of paths.
1634 * buf [O] Destination for the found file path.
1636 * RETURNS
1637 * Nothing. If the file is not found, buf will contain an empty string
1638 * and errno is set.
1640 void CDECL MSVCRT__searchenv(const char* file, const char* env, char *buf)
1642 char*envVal, *penv;
1643 char curPath[MAX_PATH];
1645 *buf = '\0';
1647 /* Try CWD first */
1648 if (GetFileAttributesA( file ) != INVALID_FILE_ATTRIBUTES)
1650 GetFullPathNameA( file, MAX_PATH, buf, NULL );
1651 /* Sigh. This error is *always* set, regardless of success */
1652 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1653 return;
1656 /* Search given environment variable */
1657 envVal = MSVCRT_getenv(env);
1658 if (!envVal)
1660 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1661 return;
1664 penv = envVal;
1665 TRACE(":searching for %s in paths %s\n", file, envVal);
1669 char *end = penv;
1671 while(*end && *end != ';') end++; /* Find end of next path */
1672 if (penv == end || !*penv)
1674 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1675 return;
1677 memcpy(curPath, penv, end - penv);
1678 if (curPath[end - penv] != '/' && curPath[end - penv] != '\\')
1680 curPath[end - penv] = '\\';
1681 curPath[end - penv + 1] = '\0';
1683 else
1684 curPath[end - penv] = '\0';
1686 strcat(curPath, file);
1687 TRACE("Checking for file %s\n", curPath);
1688 if (GetFileAttributesA( curPath ) != INVALID_FILE_ATTRIBUTES)
1690 strcpy(buf, curPath);
1691 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1692 return; /* Found */
1694 penv = *end ? end + 1 : end;
1695 } while(1);
1698 /*********************************************************************
1699 * _searchenv_s (MSVCRT.@)
1701 int CDECL MSVCRT__searchenv_s(const char* file, const char* env, char *buf, MSVCRT_size_t count)
1703 char*envVal, *penv;
1704 char curPath[MAX_PATH];
1706 if (!MSVCRT_CHECK_PMT(file != NULL)) return MSVCRT_EINVAL;
1707 if (!MSVCRT_CHECK_PMT(buf != NULL)) return MSVCRT_EINVAL;
1708 if (!MSVCRT_CHECK_PMT(count > 0)) return MSVCRT_EINVAL;
1710 *buf = '\0';
1712 /* Try CWD first */
1713 if (GetFileAttributesA( file ) != INVALID_FILE_ATTRIBUTES)
1715 if (GetFullPathNameA( file, count, buf, NULL )) return 0;
1716 msvcrt_set_errno(GetLastError());
1717 return 0;
1720 /* Search given environment variable */
1721 envVal = MSVCRT_getenv(env);
1722 if (!envVal)
1724 *MSVCRT__errno() = MSVCRT_ENOENT;
1725 return MSVCRT_ENOENT;
1728 penv = envVal;
1729 TRACE(":searching for %s in paths %s\n", file, envVal);
1733 char *end = penv;
1735 while(*end && *end != ';') end++; /* Find end of next path */
1736 if (penv == end || !*penv)
1738 *MSVCRT__errno() = MSVCRT_ENOENT;
1739 return MSVCRT_ENOENT;
1741 memcpy(curPath, penv, end - penv);
1742 if (curPath[end - penv] != '/' && curPath[end - penv] != '\\')
1744 curPath[end - penv] = '\\';
1745 curPath[end - penv + 1] = '\0';
1747 else
1748 curPath[end - penv] = '\0';
1750 strcat(curPath, file);
1751 TRACE("Checking for file %s\n", curPath);
1752 if (GetFileAttributesA( curPath ) != INVALID_FILE_ATTRIBUTES)
1754 if (strlen(curPath) + 1 > count)
1756 MSVCRT_INVALID_PMT("buf[count] is too small", MSVCRT_ERANGE);
1757 return MSVCRT_ERANGE;
1759 strcpy(buf, curPath);
1760 return 0;
1762 penv = *end ? end + 1 : end;
1763 } while(1);
1766 /*********************************************************************
1767 * _wsearchenv (MSVCRT.@)
1769 * Unicode version of _searchenv
1771 void CDECL MSVCRT__wsearchenv(const MSVCRT_wchar_t* file, const MSVCRT_wchar_t* env, MSVCRT_wchar_t *buf)
1773 MSVCRT_wchar_t *envVal, *penv;
1774 MSVCRT_wchar_t curPath[MAX_PATH];
1776 *buf = '\0';
1778 /* Try CWD first */
1779 if (GetFileAttributesW( file ) != INVALID_FILE_ATTRIBUTES)
1781 GetFullPathNameW( file, MAX_PATH, buf, NULL );
1782 /* Sigh. This error is *always* set, regardless of success */
1783 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1784 return;
1787 /* Search given environment variable */
1788 envVal = MSVCRT__wgetenv(env);
1789 if (!envVal)
1791 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1792 return;
1795 penv = envVal;
1796 TRACE(":searching for %s in paths %s\n", debugstr_w(file), debugstr_w(envVal));
1800 MSVCRT_wchar_t *end = penv;
1802 while(*end && *end != ';') end++; /* Find end of next path */
1803 if (penv == end || !*penv)
1805 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1806 return;
1808 memcpy(curPath, penv, (end - penv) * sizeof(MSVCRT_wchar_t));
1809 if (curPath[end - penv] != '/' && curPath[end - penv] != '\\')
1811 curPath[end - penv] = '\\';
1812 curPath[end - penv + 1] = '\0';
1814 else
1815 curPath[end - penv] = '\0';
1817 strcatW(curPath, file);
1818 TRACE("Checking for file %s\n", debugstr_w(curPath));
1819 if (GetFileAttributesW( curPath ) != INVALID_FILE_ATTRIBUTES)
1821 strcpyW(buf, curPath);
1822 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1823 return; /* Found */
1825 penv = *end ? end + 1 : end;
1826 } while(1);
1829 /*********************************************************************
1830 * _wsearchenv_s (MSVCRT.@)
1832 int CDECL MSVCRT__wsearchenv_s(const MSVCRT_wchar_t* file, const MSVCRT_wchar_t* env,
1833 MSVCRT_wchar_t *buf, MSVCRT_size_t count)
1835 MSVCRT_wchar_t* envVal, *penv;
1836 MSVCRT_wchar_t curPath[MAX_PATH];
1838 if (!MSVCRT_CHECK_PMT(file != NULL)) return MSVCRT_EINVAL;
1839 if (!MSVCRT_CHECK_PMT(buf != NULL)) return MSVCRT_EINVAL;
1840 if (!MSVCRT_CHECK_PMT(count > 0)) return MSVCRT_EINVAL;
1842 *buf = '\0';
1844 /* Try CWD first */
1845 if (GetFileAttributesW( file ) != INVALID_FILE_ATTRIBUTES)
1847 if (GetFullPathNameW( file, count, buf, NULL )) return 0;
1848 msvcrt_set_errno(GetLastError());
1849 return 0;
1852 /* Search given environment variable */
1853 envVal = MSVCRT__wgetenv(env);
1854 if (!envVal)
1856 *MSVCRT__errno() = MSVCRT_ENOENT;
1857 return MSVCRT_ENOENT;
1860 penv = envVal;
1861 TRACE(":searching for %s in paths %s\n", debugstr_w(file), debugstr_w(envVal));
1865 MSVCRT_wchar_t *end = penv;
1867 while(*end && *end != ';') end++; /* Find end of next path */
1868 if (penv == end || !*penv)
1870 *MSVCRT__errno() = MSVCRT_ENOENT;
1871 return MSVCRT_ENOENT;
1873 memcpy(curPath, penv, (end - penv) * sizeof(MSVCRT_wchar_t));
1874 if (curPath[end - penv] != '/' && curPath[end - penv] != '\\')
1876 curPath[end - penv] = '\\';
1877 curPath[end - penv + 1] = '\0';
1879 else
1880 curPath[end - penv] = '\0';
1882 strcatW(curPath, file);
1883 TRACE("Checking for file %s\n", debugstr_w(curPath));
1884 if (GetFileAttributesW( curPath ) != INVALID_FILE_ATTRIBUTES)
1886 if (strlenW(curPath) + 1 > count)
1888 MSVCRT_INVALID_PMT("buf[count] is too small", MSVCRT_ERANGE);
1889 return MSVCRT_ERANGE;
1891 strcpyW(buf, curPath);
1892 return 0;
1894 penv = *end ? end + 1 : end;
1895 } while(1);