kernel32/tests: Add a test to check some fields in fake dlls.
[wine.git] / dlls / msvcrt / dir.c
blobe8cba58ac7f3405fa8f93f1ba09343e660fd341b
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 * _wfindnext32 (MSVCRT.@)
604 int CDECL MSVCRT__wfindnext32(MSVCRT_intptr_t hand, struct MSVCRT__wfinddata32_t * ft)
606 WIN32_FIND_DATAW find_data;
608 if (!FindNextFileW((HANDLE)hand, &find_data))
610 *MSVCRT__errno() = MSVCRT_ENOENT;
611 return -1;
614 msvcrt_wfttofd32(&find_data, ft);
615 return 0;
618 /*********************************************************************
619 * _wfindnext (MSVCRT.@)
621 * Unicode version of _findnext.
623 int CDECL MSVCRT__wfindnext(MSVCRT_intptr_t hand, struct MSVCRT__wfinddata_t * ft)
625 WIN32_FIND_DATAW find_data;
627 if (!FindNextFileW((HANDLE)hand, &find_data))
629 *MSVCRT__errno() = MSVCRT_ENOENT;
630 return -1;
633 msvcrt_wfttofd(&find_data,ft);
634 return 0;
637 /*********************************************************************
638 * _findnexti64 (MSVCRT.@)
640 * 64-bit version of _findnext.
642 int CDECL MSVCRT__findnexti64(MSVCRT_intptr_t hand, struct MSVCRT__finddatai64_t * ft)
644 WIN32_FIND_DATAA find_data;
646 if (!FindNextFileA((HANDLE)hand, &find_data))
648 *MSVCRT__errno() = MSVCRT_ENOENT;
649 return -1;
652 msvcrt_fttofdi64(&find_data,ft);
653 return 0;
656 /*********************************************************************
657 * _findnext64 (MSVCRT.@)
659 * 64-bit version of _findnext.
661 int CDECL MSVCRT__findnext64(MSVCRT_intptr_t hand, struct MSVCRT__finddata64_t * ft)
663 WIN32_FIND_DATAA find_data;
665 if (!FindNextFileA((HANDLE)hand, &find_data))
667 *MSVCRT__errno() = MSVCRT_ENOENT;
668 return -1;
671 msvcrt_fttofd64(&find_data,ft);
672 return 0;
675 /*********************************************************************
676 * _wfindnext64 (MSVCRT.@)
678 * Unicode version of _wfindnext64.
680 int CDECL MSVCRT__wfindnext64(MSVCRT_intptr_t hand, struct MSVCRT__wfinddata64_t * ft)
682 WIN32_FIND_DATAW find_data;
684 if (!FindNextFileW((HANDLE)hand, &find_data))
686 *MSVCRT__errno() = MSVCRT_ENOENT;
687 return -1;
690 msvcrt_wfttofd64(&find_data,ft);
691 return 0;
694 /*********************************************************************
695 * _findnext64i32 (MSVCRT.@)
697 * 64-bit/32-bit version of _findnext.
699 int CDECL MSVCRT__findnext64i32(MSVCRT_intptr_t hand, struct MSVCRT__finddata64i32_t * ft)
701 WIN32_FIND_DATAA find_data;
703 if (!FindNextFileA((HANDLE)hand, &find_data))
705 *MSVCRT__errno() = MSVCRT_ENOENT;
706 return -1;
709 msvcrt_fttofd64i32(&find_data,ft);
710 return 0;
713 /*********************************************************************
714 * _wfindnexti64 (MSVCRT.@)
716 * Unicode version of _findnexti64.
718 int CDECL MSVCRT__wfindnexti64(MSVCRT_intptr_t hand, struct MSVCRT__wfinddatai64_t * ft)
720 WIN32_FIND_DATAW find_data;
722 if (!FindNextFileW((HANDLE)hand, &find_data))
724 *MSVCRT__errno() = MSVCRT_ENOENT;
725 return -1;
728 msvcrt_wfttofdi64(&find_data,ft);
729 return 0;
732 /*********************************************************************
733 * _wfindnext64i32 (MSVCRT.@)
735 * Unicode version of _findnext64i32.
737 int CDECL MSVCRT__wfindnext64i32(MSVCRT_intptr_t hand, struct MSVCRT__wfinddata64i32_t * ft)
739 WIN32_FIND_DATAW find_data;
741 if (!FindNextFileW((HANDLE)hand, &find_data))
743 *MSVCRT__errno() = MSVCRT_ENOENT;
744 return -1;
747 msvcrt_wfttofd64i32(&find_data,ft);
748 return 0;
751 /*********************************************************************
752 * _getcwd (MSVCRT.@)
754 * Get the current working directory.
756 * PARAMS
757 * buf [O] Destination for current working directory.
758 * size [I] Size of buf in characters
760 * RETURNS
761 * Success: If buf is NULL, returns an allocated string containing the path.
762 * Otherwise populates buf with the path and returns it.
763 * Failure: NULL. errno indicates the error.
765 char* CDECL MSVCRT__getcwd(char * buf, int size)
767 char dir[MAX_PATH];
768 int dir_len = GetCurrentDirectoryA(MAX_PATH,dir);
770 if (dir_len < 1)
771 return NULL; /* FIXME: Real return value untested */
773 if (!buf)
775 if (size <= dir_len) size = dir_len + 1;
776 if (!(buf = MSVCRT_malloc( size ))) return NULL;
778 else if (dir_len >= size)
780 *MSVCRT__errno() = MSVCRT_ERANGE;
781 return NULL; /* buf too small */
783 strcpy(buf,dir);
784 return buf;
787 /*********************************************************************
788 * _wgetcwd (MSVCRT.@)
790 * Unicode version of _getcwd.
792 MSVCRT_wchar_t* CDECL MSVCRT__wgetcwd(MSVCRT_wchar_t * buf, int size)
794 MSVCRT_wchar_t dir[MAX_PATH];
795 int dir_len = GetCurrentDirectoryW(MAX_PATH,dir);
797 if (dir_len < 1)
798 return NULL; /* FIXME: Real return value untested */
800 if (!buf)
802 if (size <= dir_len) size = dir_len + 1;
803 if (!(buf = MSVCRT_malloc( size * sizeof(WCHAR) ))) return NULL;
805 if (dir_len >= size)
807 *MSVCRT__errno() = MSVCRT_ERANGE;
808 return NULL; /* buf too small */
810 strcpyW(buf,dir);
811 return buf;
814 /*********************************************************************
815 * _getdrive (MSVCRT.@)
817 * Get the current drive number.
819 * PARAMS
820 * None.
822 * RETURNS
823 * Success: The drive letter number from 1 to 26 ("A:" to "Z:").
824 * Failure: 0.
826 int CDECL MSVCRT__getdrive(void)
828 WCHAR buffer[MAX_PATH];
829 if (GetCurrentDirectoryW( MAX_PATH, buffer ) &&
830 buffer[0] >= 'A' && buffer[0] <= 'z' && buffer[1] == ':')
831 return toupperW(buffer[0]) - 'A' + 1;
832 return 0;
835 /*********************************************************************
836 * _getdcwd (MSVCRT.@)
838 * Get the current working directory on a given disk.
840 * PARAMS
841 * drive [I] Drive letter to get the current working directory from.
842 * buf [O] Destination for the current working directory.
843 * size [I] Length of drive in characters.
845 * RETURNS
846 * Success: If drive is NULL, returns an allocated string containing the path.
847 * Otherwise populates drive with the path and returns it.
848 * Failure: NULL. errno indicates the error.
850 char* CDECL MSVCRT__getdcwd(int drive, char * buf, int size)
852 static char* dummy;
854 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
856 if (!drive || drive == MSVCRT__getdrive())
857 return MSVCRT__getcwd(buf,size); /* current */
858 else
860 char dir[MAX_PATH];
861 char drivespec[] = {'A', ':', 0};
862 int dir_len;
864 drivespec[0] += drive - 1;
865 if (GetDriveTypeA(drivespec) < DRIVE_REMOVABLE)
867 *MSVCRT__errno() = MSVCRT_EACCES;
868 return NULL;
871 dir_len = GetFullPathNameA(drivespec,MAX_PATH,dir,&dummy);
872 if (dir_len >= size || dir_len < 1)
874 *MSVCRT__errno() = MSVCRT_ERANGE;
875 return NULL; /* buf too small */
878 TRACE(":returning '%s'\n", dir);
879 if (!buf)
880 return MSVCRT__strdup(dir); /* allocate */
882 strcpy(buf,dir);
884 return buf;
887 /*********************************************************************
888 * _wgetdcwd (MSVCRT.@)
890 * Unicode version of _wgetdcwd.
892 MSVCRT_wchar_t* CDECL MSVCRT__wgetdcwd(int drive, MSVCRT_wchar_t * buf, int size)
894 static MSVCRT_wchar_t* dummy;
896 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
898 if (!drive || drive == MSVCRT__getdrive())
899 return MSVCRT__wgetcwd(buf,size); /* current */
900 else
902 MSVCRT_wchar_t dir[MAX_PATH];
903 MSVCRT_wchar_t drivespec[4] = {'A', ':', '\\', 0};
904 int dir_len;
906 drivespec[0] += drive - 1;
907 if (GetDriveTypeW(drivespec) < DRIVE_REMOVABLE)
909 *MSVCRT__errno() = MSVCRT_EACCES;
910 return NULL;
913 dir_len = GetFullPathNameW(drivespec,MAX_PATH,dir,&dummy);
914 if (dir_len >= size || dir_len < 1)
916 *MSVCRT__errno() = MSVCRT_ERANGE;
917 return NULL; /* buf too small */
920 TRACE(":returning %s\n", debugstr_w(dir));
921 if (!buf)
922 return MSVCRT__wcsdup(dir); /* allocate */
923 strcpyW(buf,dir);
925 return buf;
928 /*********************************************************************
929 * _getdiskfree (MSVCRT.@)
931 * Get information about the free space on a drive.
933 * PARAMS
934 * disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
935 * info [O] Destination for the resulting information.
937 * RETURNS
938 * Success: 0. info is updated with the free space information.
939 * Failure: An error code from GetLastError().
941 * NOTES
942 * See GetLastError().
944 unsigned int CDECL MSVCRT__getdiskfree(unsigned int disk, struct MSVCRT__diskfree_t * d)
946 WCHAR drivespec[] = {'@', ':', '\\', 0};
947 DWORD ret[4];
948 unsigned int err;
950 if (disk > 26)
951 return ERROR_INVALID_PARAMETER; /* MSVCRT doesn't set errno here */
953 drivespec[0] += disk; /* make a drive letter */
955 if (GetDiskFreeSpaceW(disk==0?NULL:drivespec,ret,ret+1,ret+2,ret+3))
957 d->sectors_per_cluster = ret[0];
958 d->bytes_per_sector = ret[1];
959 d->avail_clusters = ret[2];
960 d->total_clusters = ret[3];
961 return 0;
963 err = GetLastError();
964 msvcrt_set_errno(err);
965 return err;
968 /*********************************************************************
969 * _mkdir (MSVCRT.@)
971 * Create a directory.
973 * PARAMS
974 * newdir [I] Name of directory to create.
976 * RETURNS
977 * Success: 0. The directory indicated by newdir is created.
978 * Failure: -1. errno indicates the error.
980 * NOTES
981 * See CreateDirectoryA.
983 int CDECL MSVCRT__mkdir(const char * newdir)
985 if (CreateDirectoryA(newdir,NULL))
986 return 0;
987 msvcrt_set_errno(GetLastError());
988 return -1;
991 /*********************************************************************
992 * _wmkdir (MSVCRT.@)
994 * Unicode version of _mkdir.
996 int CDECL MSVCRT__wmkdir(const MSVCRT_wchar_t* newdir)
998 if (CreateDirectoryW(newdir,NULL))
999 return 0;
1000 msvcrt_set_errno(GetLastError());
1001 return -1;
1004 /*********************************************************************
1005 * _rmdir (MSVCRT.@)
1007 * Delete a directory.
1009 * PARAMS
1010 * dir [I] Name of directory to delete.
1012 * RETURNS
1013 * Success: 0. The directory indicated by newdir is deleted.
1014 * Failure: -1. errno indicates the error.
1016 * NOTES
1017 * See RemoveDirectoryA.
1019 int CDECL MSVCRT__rmdir(const char * dir)
1021 if (RemoveDirectoryA(dir))
1022 return 0;
1023 msvcrt_set_errno(GetLastError());
1024 return -1;
1027 /*********************************************************************
1028 * _wrmdir (MSVCRT.@)
1030 * Unicode version of _rmdir.
1032 int CDECL MSVCRT__wrmdir(const MSVCRT_wchar_t * dir)
1034 if (RemoveDirectoryW(dir))
1035 return 0;
1036 msvcrt_set_errno(GetLastError());
1037 return -1;
1040 /******************************************************************
1041 * _splitpath_s (MSVCRT.@)
1043 int CDECL MSVCRT__splitpath_s(const char* inpath,
1044 char* drive, MSVCRT_size_t sz_drive,
1045 char* dir, MSVCRT_size_t sz_dir,
1046 char* fname, MSVCRT_size_t sz_fname,
1047 char* ext, MSVCRT_size_t sz_ext)
1049 const char *p, *end;
1051 if (!inpath || (!drive && sz_drive) ||
1052 (drive && !sz_drive) ||
1053 (!dir && sz_dir) ||
1054 (dir && !sz_dir) ||
1055 (!fname && sz_fname) ||
1056 (fname && !sz_fname) ||
1057 (!ext && sz_ext) ||
1058 (ext && !sz_ext))
1060 *MSVCRT__errno() = MSVCRT_EINVAL;
1061 return MSVCRT_EINVAL;
1064 if (inpath[0] && inpath[1] == ':')
1066 if (drive)
1068 if (sz_drive <= 2) goto do_error;
1069 drive[0] = inpath[0];
1070 drive[1] = inpath[1];
1071 drive[2] = 0;
1073 inpath += 2;
1075 else if (drive) drive[0] = '\0';
1077 /* look for end of directory part */
1078 end = NULL;
1079 for (p = inpath; *p; p++)
1081 if (_ismbblead((unsigned char)*p))
1083 p++;
1084 continue;
1086 if (*p == '/' || *p == '\\') end = p + 1;
1089 if (end) /* got a directory */
1091 if (dir)
1093 if (sz_dir <= end - inpath) goto do_error;
1094 memcpy( dir, inpath, (end - inpath) );
1095 dir[end - inpath] = 0;
1097 inpath = end;
1099 else if (dir) dir[0] = 0;
1101 /* look for extension: what's after the last dot */
1102 end = NULL;
1103 for (p = inpath; *p; p++) if (*p == '.') end = p;
1105 if (!end) end = p; /* there's no extension */
1107 if (fname)
1109 if (sz_fname <= end - inpath) goto do_error;
1110 memcpy( fname, inpath, (end - inpath) );
1111 fname[end - inpath] = 0;
1113 if (ext)
1115 if (sz_ext <= strlen(end)) goto do_error;
1116 strcpy( ext, end );
1118 return 0;
1119 do_error:
1120 if (drive) drive[0] = '\0';
1121 if (dir) dir[0] = '\0';
1122 if (fname) fname[0]= '\0';
1123 if (ext) ext[0]= '\0';
1124 *MSVCRT__errno() = MSVCRT_ERANGE;
1125 return MSVCRT_ERANGE;
1128 /*********************************************************************
1129 * _splitpath (MSVCRT.@)
1131 void CDECL MSVCRT__splitpath(const char *inpath, char *drv, char *dir,
1132 char *fname, char *ext)
1134 MSVCRT__splitpath_s(inpath, drv, drv?MSVCRT__MAX_DRIVE:0, dir, dir?MSVCRT__MAX_DIR:0,
1135 fname, fname?MSVCRT__MAX_FNAME:0, ext, ext?MSVCRT__MAX_EXT:0);
1138 /******************************************************************
1139 * _wsplitpath_s (MSVCRT.@)
1141 * Secure version of _wsplitpath
1143 int CDECL MSVCRT__wsplitpath_s(const MSVCRT_wchar_t* inpath,
1144 MSVCRT_wchar_t* drive, MSVCRT_size_t sz_drive,
1145 MSVCRT_wchar_t* dir, MSVCRT_size_t sz_dir,
1146 MSVCRT_wchar_t* fname, MSVCRT_size_t sz_fname,
1147 MSVCRT_wchar_t* ext, MSVCRT_size_t sz_ext)
1149 const MSVCRT_wchar_t *p, *end;
1151 if (!inpath || (!drive && sz_drive) ||
1152 (drive && !sz_drive) ||
1153 (!dir && sz_dir) ||
1154 (dir && !sz_dir) ||
1155 (!fname && sz_fname) ||
1156 (fname && !sz_fname) ||
1157 (!ext && sz_ext) ||
1158 (ext && !sz_ext))
1160 *MSVCRT__errno() = MSVCRT_EINVAL;
1161 return MSVCRT_EINVAL;
1164 if (inpath[0] && inpath[1] == ':')
1166 if (drive)
1168 if (sz_drive <= 2) goto do_error;
1169 drive[0] = inpath[0];
1170 drive[1] = inpath[1];
1171 drive[2] = 0;
1173 inpath += 2;
1175 else if (drive) drive[0] = '\0';
1177 /* look for end of directory part */
1178 end = NULL;
1179 for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
1181 if (end) /* got a directory */
1183 if (dir)
1185 if (sz_dir <= end - inpath) goto do_error;
1186 memcpy( dir, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
1187 dir[end - inpath] = 0;
1189 inpath = end;
1191 else if (dir) dir[0] = 0;
1193 /* look for extension: what's after the last dot */
1194 end = NULL;
1195 for (p = inpath; *p; p++) if (*p == '.') end = p;
1197 if (!end) end = p; /* there's no extension */
1199 if (fname)
1201 if (sz_fname <= end - inpath) goto do_error;
1202 memcpy( fname, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
1203 fname[end - inpath] = 0;
1205 if (ext)
1207 if (sz_ext <= strlenW(end)) goto do_error;
1208 strcpyW( ext, end );
1210 return 0;
1211 do_error:
1212 if (drive) drive[0] = '\0';
1213 if (dir) dir[0] = '\0';
1214 if (fname) fname[0]= '\0';
1215 if (ext) ext[0]= '\0';
1216 *MSVCRT__errno() = MSVCRT_ERANGE;
1217 return MSVCRT_ERANGE;
1220 /*********************************************************************
1221 * _wsplitpath (MSVCRT.@)
1223 * Unicode version of _splitpath.
1225 void CDECL MSVCRT__wsplitpath(const MSVCRT_wchar_t *inpath, MSVCRT_wchar_t *drv, MSVCRT_wchar_t *dir,
1226 MSVCRT_wchar_t *fname, MSVCRT_wchar_t *ext)
1228 MSVCRT__wsplitpath_s(inpath, drv, drv?MSVCRT__MAX_DRIVE:0, dir, dir?MSVCRT__MAX_DIR:0,
1229 fname, fname?MSVCRT__MAX_FNAME:0, ext, ext?MSVCRT__MAX_EXT:0);
1232 /*********************************************************************
1233 * _wfullpath (MSVCRT.@)
1235 * Unicode version of _fullpath.
1237 MSVCRT_wchar_t * CDECL MSVCRT__wfullpath(MSVCRT_wchar_t * absPath, const MSVCRT_wchar_t* relPath, MSVCRT_size_t size)
1239 DWORD rc;
1240 WCHAR* buffer;
1241 WCHAR* lastpart;
1242 BOOL alloced = FALSE;
1244 if (!relPath || !*relPath)
1245 return MSVCRT__wgetcwd(absPath, size);
1247 if (absPath == NULL)
1249 buffer = MSVCRT_malloc(MAX_PATH * sizeof(WCHAR));
1250 size = MAX_PATH;
1251 alloced = TRUE;
1253 else
1254 buffer = absPath;
1256 if (size < 4)
1258 *MSVCRT__errno() = MSVCRT_ERANGE;
1259 return NULL;
1262 TRACE(":resolving relative path %s\n",debugstr_w(relPath));
1264 rc = GetFullPathNameW(relPath,size,buffer,&lastpart);
1266 if (rc > 0 && rc <= size )
1267 return buffer;
1268 else
1270 if (alloced)
1271 MSVCRT_free(buffer);
1272 return NULL;
1276 /*********************************************************************
1277 * _fullpath (MSVCRT.@)
1279 * Create an absolute path from a relative path.
1281 * PARAMS
1282 * absPath [O] Destination for absolute path
1283 * relPath [I] Relative path to convert to absolute
1284 * size [I] Length of absPath in characters.
1286 * RETURNS
1287 * Success: If absPath is NULL, returns an allocated string containing the path.
1288 * Otherwise populates absPath with the path and returns it.
1289 * Failure: NULL. errno indicates the error.
1291 char * CDECL MSVCRT__fullpath(char * absPath, const char* relPath, unsigned int size)
1293 DWORD rc;
1294 char* lastpart;
1295 char* buffer;
1296 BOOL alloced = FALSE;
1298 if (!relPath || !*relPath)
1299 return MSVCRT__getcwd(absPath, size);
1301 if (absPath == NULL)
1303 buffer = MSVCRT_malloc(MAX_PATH);
1304 size = MAX_PATH;
1305 alloced = TRUE;
1307 else
1308 buffer = absPath;
1310 if (size < 4)
1312 *MSVCRT__errno() = MSVCRT_ERANGE;
1313 return NULL;
1316 TRACE(":resolving relative path '%s'\n",relPath);
1318 rc = GetFullPathNameA(relPath,size,buffer,&lastpart);
1320 if (rc > 0 && rc <= size)
1321 return buffer;
1322 else
1324 if (alloced)
1325 MSVCRT_free(buffer);
1326 return NULL;
1330 /*********************************************************************
1331 * _makepath (MSVCRT.@)
1333 * Create a pathname.
1335 * PARAMS
1336 * path [O] Destination for created pathname
1337 * drive [I] Drive letter (e.g. "A:")
1338 * directory [I] Directory
1339 * filename [I] Name of the file, excluding extension
1340 * extension [I] File extension (e.g. ".TXT")
1342 * RETURNS
1343 * Nothing. If path is not large enough to hold the resulting pathname,
1344 * random process memory will be overwritten.
1346 VOID CDECL MSVCRT__makepath(char * path, const char * drive,
1347 const char *directory, const char * filename,
1348 const char * extension)
1350 char *p = path;
1352 TRACE("(%s %s %s %s)\n", debugstr_a(drive), debugstr_a(directory),
1353 debugstr_a(filename), debugstr_a(extension) );
1355 if ( !path )
1356 return;
1358 if (drive && drive[0])
1360 *p++ = drive[0];
1361 *p++ = ':';
1363 if (directory && directory[0])
1365 unsigned int len = strlen(directory);
1366 memmove(p, directory, len);
1367 p += len;
1368 if (p[-1] != '/' && p[-1] != '\\')
1369 *p++ = '\\';
1371 if (filename && filename[0])
1373 unsigned int len = strlen(filename);
1374 memmove(p, filename, len);
1375 p += len;
1377 if (extension && extension[0])
1379 if (extension[0] != '.')
1380 *p++ = '.';
1381 strcpy(p, extension);
1383 else
1384 *p = '\0';
1385 TRACE("returning %s\n",path);
1388 /*********************************************************************
1389 * _wmakepath (MSVCRT.@)
1391 * Unicode version of _wmakepath.
1393 VOID CDECL MSVCRT__wmakepath(MSVCRT_wchar_t *path, const MSVCRT_wchar_t *drive, const MSVCRT_wchar_t *directory,
1394 const MSVCRT_wchar_t *filename, const MSVCRT_wchar_t *extension)
1396 MSVCRT_wchar_t *p = path;
1398 TRACE("%s %s %s %s\n", debugstr_w(drive), debugstr_w(directory),
1399 debugstr_w(filename), debugstr_w(extension));
1401 if ( !path )
1402 return;
1404 if (drive && drive[0])
1406 *p++ = drive[0];
1407 *p++ = ':';
1409 if (directory && directory[0])
1411 unsigned int len = strlenW(directory);
1412 memmove(p, directory, len * sizeof(MSVCRT_wchar_t));
1413 p += len;
1414 if (p[-1] != '/' && p[-1] != '\\')
1415 *p++ = '\\';
1417 if (filename && filename[0])
1419 unsigned int len = strlenW(filename);
1420 memmove(p, filename, len * sizeof(MSVCRT_wchar_t));
1421 p += len;
1423 if (extension && extension[0])
1425 if (extension[0] != '.')
1426 *p++ = '.';
1427 strcpyW(p, extension);
1429 else
1430 *p = '\0';
1432 TRACE("returning %s\n", debugstr_w(path));
1435 /*********************************************************************
1436 * _makepath_s (MSVCRT.@)
1438 * Safe version of _makepath.
1440 int CDECL MSVCRT__makepath_s(char *path, MSVCRT_size_t size, const char *drive,
1441 const char *directory, const char *filename,
1442 const char *extension)
1444 char *p = path;
1446 if (!path || !size)
1448 *MSVCRT__errno() = MSVCRT_EINVAL;
1449 return MSVCRT_EINVAL;
1452 if (drive && drive[0])
1454 if (size <= 2)
1455 goto range;
1457 *p++ = drive[0];
1458 *p++ = ':';
1459 size -= 2;
1462 if (directory && directory[0])
1464 unsigned int len = strlen(directory);
1465 unsigned int needs_separator = directory[len - 1] != '/' && directory[len - 1] != '\\';
1466 unsigned int copylen = min(size - 1, len);
1468 if (size < 2)
1469 goto range;
1471 memmove(p, directory, copylen);
1473 if (size <= len)
1474 goto range;
1476 p += copylen;
1477 size -= copylen;
1479 if (needs_separator)
1481 if (size < 2)
1482 goto range;
1484 *p++ = '\\';
1485 size -= 1;
1489 if (filename && filename[0])
1491 unsigned int len = strlen(filename);
1492 unsigned int copylen = min(size - 1, len);
1494 if (size < 2)
1495 goto range;
1497 memmove(p, filename, copylen);
1499 if (size <= len)
1500 goto range;
1502 p += len;
1503 size -= len;
1506 if (extension && extension[0])
1508 unsigned int len = strlen(extension);
1509 unsigned int needs_period = extension[0] != '.';
1510 unsigned int copylen;
1512 if (size < 2)
1513 goto range;
1515 if (needs_period)
1517 *p++ = '.';
1518 size -= 1;
1521 copylen = min(size - 1, len);
1522 memcpy(p, extension, copylen);
1524 if (size <= len)
1525 goto range;
1527 p += copylen;
1530 *p = '\0';
1531 return 0;
1533 range:
1534 path[0] = '\0';
1535 *MSVCRT__errno() = MSVCRT_ERANGE;
1536 return MSVCRT_ERANGE;
1539 /*********************************************************************
1540 * _wmakepath_s (MSVCRT.@)
1542 * Safe version of _wmakepath.
1544 int CDECL MSVCRT__wmakepath_s(MSVCRT_wchar_t *path, MSVCRT_size_t size, const MSVCRT_wchar_t *drive,
1545 const MSVCRT_wchar_t *directory, const MSVCRT_wchar_t *filename,
1546 const MSVCRT_wchar_t *extension)
1548 MSVCRT_wchar_t *p = path;
1550 if (!path || !size)
1552 *MSVCRT__errno() = MSVCRT_EINVAL;
1553 return MSVCRT_EINVAL;
1556 if (drive && drive[0])
1558 if (size <= 2)
1559 goto range;
1561 *p++ = drive[0];
1562 *p++ = ':';
1563 size -= 2;
1566 if (directory && directory[0])
1568 unsigned int len = strlenW(directory);
1569 unsigned int needs_separator = directory[len - 1] != '/' && directory[len - 1] != '\\';
1570 unsigned int copylen = min(size - 1, len);
1572 if (size < 2)
1573 goto range;
1575 memmove(p, directory, copylen * sizeof(MSVCRT_wchar_t));
1577 if (size <= len)
1578 goto range;
1580 p += copylen;
1581 size -= copylen;
1583 if (needs_separator)
1585 if (size < 2)
1586 goto range;
1588 *p++ = '\\';
1589 size -= 1;
1593 if (filename && filename[0])
1595 unsigned int len = strlenW(filename);
1596 unsigned int copylen = min(size - 1, len);
1598 if (size < 2)
1599 goto range;
1601 memmove(p, filename, copylen * sizeof(MSVCRT_wchar_t));
1603 if (size <= len)
1604 goto range;
1606 p += len;
1607 size -= len;
1610 if (extension && extension[0])
1612 unsigned int len = strlenW(extension);
1613 unsigned int needs_period = extension[0] != '.';
1614 unsigned int copylen;
1616 if (size < 2)
1617 goto range;
1619 if (needs_period)
1621 *p++ = '.';
1622 size -= 1;
1625 copylen = min(size - 1, len);
1626 memcpy(p, extension, copylen * sizeof(MSVCRT_wchar_t));
1628 if (size <= len)
1629 goto range;
1631 p += copylen;
1634 *p = '\0';
1635 return 0;
1637 range:
1638 path[0] = '\0';
1639 *MSVCRT__errno() = MSVCRT_ERANGE;
1640 return MSVCRT_ERANGE;
1643 /*********************************************************************
1644 * _searchenv (MSVCRT.@)
1646 * Search for a file in a list of paths from an environment variable.
1648 * PARAMS
1649 * file [I] Name of the file to search for.
1650 * env [I] Name of the environment variable containing a list of paths.
1651 * buf [O] Destination for the found file path.
1653 * RETURNS
1654 * Nothing. If the file is not found, buf will contain an empty string
1655 * and errno is set.
1657 void CDECL MSVCRT__searchenv(const char* file, const char* env, char *buf)
1659 char*envVal, *penv, *end;
1660 char path[MAX_PATH];
1661 MSVCRT_size_t path_len, fname_len = strlen(file);
1663 *buf = '\0';
1665 /* Try CWD first */
1666 if (GetFileAttributesA( file ) != INVALID_FILE_ATTRIBUTES)
1668 GetFullPathNameA( file, MAX_PATH, buf, NULL );
1669 return;
1672 /* Search given environment variable */
1673 envVal = MSVCRT_getenv(env);
1674 if (!envVal)
1676 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1677 return;
1680 penv = envVal;
1681 TRACE(":searching for %s in paths %s\n", file, envVal);
1683 for(; *penv; penv = (*end ? end + 1 : end))
1685 end = penv;
1686 while(*end && *end != ';') end++; /* Find end of next path */
1687 path_len = end - penv;
1688 if (!path_len || path_len >= MAX_PATH)
1689 continue;
1691 memcpy(path, penv, path_len);
1692 if (path[path_len - 1] != '/' && path[path_len - 1] != '\\')
1693 path[path_len++] = '\\';
1694 if (path_len + fname_len >= MAX_PATH)
1695 continue;
1697 memcpy(path + path_len, file, fname_len + 1);
1698 TRACE("Checking for file %s\n", path);
1699 if (GetFileAttributesA( path ) != INVALID_FILE_ATTRIBUTES)
1701 memcpy(buf, path, path_len + fname_len + 1);
1702 return;
1706 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1707 return;
1710 /*********************************************************************
1711 * _searchenv_s (MSVCRT.@)
1713 int CDECL MSVCRT__searchenv_s(const char* file, const char* env, char *buf, MSVCRT_size_t count)
1715 char *envVal, *penv, *end;
1716 char path[MAX_PATH];
1717 MSVCRT_size_t path_len, fname_len;
1719 if (!MSVCRT_CHECK_PMT(file != NULL)) return MSVCRT_EINVAL;
1720 if (!MSVCRT_CHECK_PMT(buf != NULL)) return MSVCRT_EINVAL;
1721 if (!MSVCRT_CHECK_PMT(count > 0)) return MSVCRT_EINVAL;
1723 if (count > MAX_PATH)
1724 FIXME("count > MAX_PATH not supported\n");
1726 fname_len = strlen(file);
1727 *buf = '\0';
1729 /* Try CWD first */
1730 if (GetFileAttributesA( file ) != INVALID_FILE_ATTRIBUTES)
1732 if (GetFullPathNameA( file, count, buf, NULL )) return 0;
1733 msvcrt_set_errno(GetLastError());
1734 return 0;
1737 /* Search given environment variable */
1738 envVal = MSVCRT_getenv(env);
1739 if (!envVal)
1741 *MSVCRT__errno() = MSVCRT_ENOENT;
1742 return MSVCRT_ENOENT;
1745 penv = envVal;
1746 TRACE(":searching for %s in paths %s\n", file, envVal);
1748 for(; *penv; penv = (*end ? end + 1 : end))
1750 end = penv;
1751 while(*end && *end != ';') end++; /* Find end of next path */
1752 path_len = end - penv;
1753 if (!path_len || path_len >= MAX_PATH)
1754 continue;
1756 memcpy(path, penv, path_len);
1757 if (path[path_len - 1] != '/' && path[path_len - 1] != '\\')
1758 path[path_len++] = '\\';
1759 if (path_len + fname_len >= MAX_PATH)
1760 continue;
1762 memcpy(path + path_len, file, fname_len + 1);
1763 TRACE("Checking for file %s\n", path);
1764 if (GetFileAttributesA( path ) != INVALID_FILE_ATTRIBUTES)
1766 if (path_len + fname_len + 1 > count)
1768 MSVCRT_INVALID_PMT("buf[count] is too small", MSVCRT_ERANGE);
1769 return MSVCRT_ERANGE;
1771 memcpy(buf, path, path_len + fname_len + 1);
1772 return 0;
1776 *MSVCRT__errno() = MSVCRT_ENOENT;
1777 return MSVCRT_ENOENT;
1780 /*********************************************************************
1781 * _wsearchenv (MSVCRT.@)
1783 * Unicode version of _searchenv
1785 void CDECL MSVCRT__wsearchenv(const MSVCRT_wchar_t* file, const MSVCRT_wchar_t* env, MSVCRT_wchar_t *buf)
1787 MSVCRT_wchar_t *envVal, *penv, *end;
1788 MSVCRT_wchar_t path[MAX_PATH];
1789 MSVCRT_size_t path_len, fname_len = strlenW(file);
1791 *buf = '\0';
1793 /* Try CWD first */
1794 if (GetFileAttributesW( file ) != INVALID_FILE_ATTRIBUTES)
1796 GetFullPathNameW( file, MAX_PATH, buf, NULL );
1797 return;
1800 /* Search given environment variable */
1801 envVal = MSVCRT__wgetenv(env);
1802 if (!envVal)
1804 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1805 return;
1808 penv = envVal;
1809 TRACE(":searching for %s in paths %s\n", debugstr_w(file), debugstr_w(envVal));
1811 for(; *penv; penv = (*end ? end + 1 : end))
1813 end = penv;
1814 while(*end && *end != ';') end++; /* Find end of next path */
1815 path_len = end - penv;
1816 if (!path_len || path_len >= MAX_PATH)
1817 continue;
1819 memcpy(path, penv, path_len * sizeof(MSVCRT_wchar_t));
1820 if (path[path_len - 1] != '/' && path[path_len - 1] != '\\')
1821 path[path_len++] = '\\';
1822 if (path_len + fname_len >= MAX_PATH)
1823 continue;
1825 memcpy(path + path_len, file, (fname_len + 1) * sizeof(MSVCRT_wchar_t));
1826 TRACE("Checking for file %s\n", debugstr_w(path));
1827 if (GetFileAttributesW( path ) != INVALID_FILE_ATTRIBUTES)
1829 memcpy(buf, path, (path_len + fname_len + 1) * sizeof(MSVCRT_wchar_t));
1830 return;
1834 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
1835 return;
1838 /*********************************************************************
1839 * _wsearchenv_s (MSVCRT.@)
1841 int CDECL MSVCRT__wsearchenv_s(const MSVCRT_wchar_t* file, const MSVCRT_wchar_t* env,
1842 MSVCRT_wchar_t *buf, MSVCRT_size_t count)
1844 MSVCRT_wchar_t *envVal, *penv, *end;
1845 MSVCRT_wchar_t path[MAX_PATH];
1846 MSVCRT_size_t path_len, fname_len;
1848 if (!MSVCRT_CHECK_PMT(file != NULL)) return MSVCRT_EINVAL;
1849 if (!MSVCRT_CHECK_PMT(buf != NULL)) return MSVCRT_EINVAL;
1850 if (!MSVCRT_CHECK_PMT(count > 0)) return MSVCRT_EINVAL;
1852 if (count > MAX_PATH)
1853 FIXME("count > MAX_PATH not supported\n");
1855 fname_len = strlenW(file);
1856 *buf = '\0';
1858 /* Try CWD first */
1859 if (GetFileAttributesW( file ) != INVALID_FILE_ATTRIBUTES)
1861 if (GetFullPathNameW( file, count, buf, NULL )) return 0;
1862 msvcrt_set_errno(GetLastError());
1863 return 0;
1866 /* Search given environment variable */
1867 envVal = MSVCRT__wgetenv(env);
1868 if (!envVal)
1870 *MSVCRT__errno() = MSVCRT_ENOENT;
1871 return MSVCRT_ENOENT;
1874 penv = envVal;
1875 TRACE(":searching for %s in paths %s\n", debugstr_w(file), debugstr_w(envVal));
1877 for(; *penv; penv = (*end ? end + 1 : end))
1879 end = penv;
1880 while(*end && *end != ';') end++; /* Find end of next path */
1881 path_len = end - penv;
1882 if (!path_len || path_len >= MAX_PATH)
1883 continue;
1885 memcpy(path, penv, path_len * sizeof(MSVCRT_wchar_t));
1886 if (path[path_len - 1] != '/' && path[path_len - 1] != '\\')
1887 path[path_len++] = '\\';
1888 if (path_len + fname_len >= MAX_PATH)
1889 continue;
1891 memcpy(path + path_len, file, (fname_len + 1) * sizeof(MSVCRT_wchar_t));
1892 TRACE("Checking for file %s\n", debugstr_w(path));
1893 if (GetFileAttributesW( path ) != INVALID_FILE_ATTRIBUTES)
1895 if (path_len + fname_len + 1 > count)
1897 MSVCRT_INVALID_PMT("buf[count] is too small", MSVCRT_ERANGE);
1898 return MSVCRT_ERANGE;
1900 memcpy(buf, path, (path_len + fname_len + 1) * sizeof(MSVCRT_wchar_t));
1901 return 0;
1905 *MSVCRT__errno() = MSVCRT_ENOENT;
1906 return MSVCRT_ENOENT;