mf/session: Implement support for sinks that provide sample allocators.
[wine.git] / dlls / msvcrt / dir.c
blob61e1eaa6d6f3baed8c69df60d1fe1ff16c75ca08
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 "msvcrt.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
37 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata_t */
38 static void msvcrt_fttofd( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata_t* ft)
40 DWORD dw;
42 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
43 ft->attrib = 0;
44 else
45 ft->attrib = fd->dwFileAttributes;
47 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
48 ft->time_create = dw;
49 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
50 ft->time_access = dw;
51 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
52 ft->time_write = dw;
53 ft->size = fd->nFileSizeLow;
54 strcpy(ft->name, fd->cFileName);
57 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata32_t */
58 static void msvcrt_fttofd32( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata32_t* ft)
60 DWORD dw;
62 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
63 ft->attrib = 0;
64 else
65 ft->attrib = fd->dwFileAttributes;
67 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
68 ft->time_create = dw;
69 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
70 ft->time_access = dw;
71 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
72 ft->time_write = dw;
73 ft->size = fd->nFileSizeLow;
74 strcpy(ft->name, fd->cFileName);
77 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata_t */
78 static void msvcrt_wfttofd( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata_t* ft)
80 DWORD dw;
82 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
83 ft->attrib = 0;
84 else
85 ft->attrib = fd->dwFileAttributes;
87 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
88 ft->time_create = dw;
89 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
90 ft->time_access = dw;
91 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
92 ft->time_write = dw;
93 ft->size = fd->nFileSizeLow;
94 MSVCRT_wcscpy(ft->name, fd->cFileName);
97 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata32_t */
98 static void msvcrt_wfttofd32(const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata32_t* ft)
100 DWORD dw;
102 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
103 ft->attrib = 0;
104 else
105 ft->attrib = fd->dwFileAttributes;
107 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
108 ft->time_create = dw;
109 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
110 ft->time_access = dw;
111 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
112 ft->time_write = dw;
113 ft->size = fd->nFileSizeLow;
114 MSVCRT_wcscpy(ft->name, fd->cFileName);
117 /* INTERNAL: Translate WIN32_FIND_DATAA to finddatai64_t */
118 static void msvcrt_fttofdi64( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddatai64_t* ft)
120 DWORD dw;
122 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
123 ft->attrib = 0;
124 else
125 ft->attrib = fd->dwFileAttributes;
127 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
128 ft->time_create = dw;
129 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
130 ft->time_access = dw;
131 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
132 ft->time_write = dw;
133 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
134 strcpy(ft->name, fd->cFileName);
137 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata64_t */
138 static void msvcrt_fttofd64( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata64_t* ft)
140 DWORD dw;
142 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
143 ft->attrib = 0;
144 else
145 ft->attrib = fd->dwFileAttributes;
147 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
148 ft->time_create = dw;
149 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
150 ft->time_access = dw;
151 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
152 ft->time_write = dw;
153 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
154 strcpy(ft->name, fd->cFileName);
157 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata64_t */
158 static void msvcrt_wfttofd64( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata64_t* ft)
160 DWORD dw;
162 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
163 ft->attrib = 0;
164 else
165 ft->attrib = fd->dwFileAttributes;
167 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
168 ft->time_create = dw;
169 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
170 ft->time_access = dw;
171 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
172 ft->time_write = dw;
173 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
174 MSVCRT_wcscpy(ft->name, fd->cFileName);
177 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata64i32_t */
178 static void msvcrt_fttofd64i32( const WIN32_FIND_DATAA *fd, struct MSVCRT__finddata64i32_t* ft)
180 DWORD dw;
182 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
183 ft->attrib = 0;
184 else
185 ft->attrib = fd->dwFileAttributes;
187 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
188 ft->time_create = dw;
189 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
190 ft->time_access = dw;
191 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
192 ft->time_write = dw;
193 ft->size = fd->nFileSizeLow;
194 strcpy(ft->name, fd->cFileName);
197 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddatai64_t */
198 static void msvcrt_wfttofdi64( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddatai64_t* ft)
200 DWORD dw;
202 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
203 ft->attrib = 0;
204 else
205 ft->attrib = fd->dwFileAttributes;
207 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
208 ft->time_create = dw;
209 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
210 ft->time_access = dw;
211 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
212 ft->time_write = dw;
213 ft->size = ((__int64)fd->nFileSizeHigh) << 32 | fd->nFileSizeLow;
214 MSVCRT_wcscpy(ft->name, fd->cFileName);
217 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata64i32_t */
218 static void msvcrt_wfttofd64i32( const WIN32_FIND_DATAW *fd, struct MSVCRT__wfinddata64i32_t* ft)
220 DWORD dw;
222 if (fd->dwFileAttributes == FILE_ATTRIBUTE_NORMAL)
223 ft->attrib = 0;
224 else
225 ft->attrib = fd->dwFileAttributes;
227 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftCreationTime, &dw );
228 ft->time_create = dw;
229 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastAccessTime, &dw );
230 ft->time_access = dw;
231 RtlTimeToSecondsSince1970( (const LARGE_INTEGER *)&fd->ftLastWriteTime, &dw );
232 ft->time_write = dw;
233 ft->size = fd->nFileSizeLow;
234 MSVCRT_wcscpy(ft->name, fd->cFileName);
237 /*********************************************************************
238 * _chdir (MSVCRT.@)
240 * Change the current working directory.
242 * PARAMS
243 * newdir [I] Directory to change to
245 * RETURNS
246 * Success: 0. The current working directory is set to newdir.
247 * Failure: -1. errno indicates the error.
249 * NOTES
250 * See SetCurrentDirectoryA.
252 int CDECL MSVCRT__chdir(const char * newdir)
254 if (!SetCurrentDirectoryA(newdir))
256 msvcrt_set_errno(newdir?GetLastError():0);
257 return -1;
259 return 0;
262 /*********************************************************************
263 * _wchdir (MSVCRT.@)
265 * Unicode version of _chdir.
267 int CDECL MSVCRT__wchdir(const MSVCRT_wchar_t * newdir)
269 if (!SetCurrentDirectoryW(newdir))
271 msvcrt_set_errno(newdir?GetLastError():0);
272 return -1;
274 return 0;
277 /*********************************************************************
278 * _chdrive (MSVCRT.@)
280 * Change the current drive.
282 * PARAMS
283 * newdrive [I] Drive number to change to (1 = 'A', 2 = 'B', ...)
285 * RETURNS
286 * Success: 0. The current drive is set to newdrive.
287 * Failure: -1. errno indicates the error.
289 * NOTES
290 * See SetCurrentDirectoryA.
292 int CDECL MSVCRT__chdrive(int newdrive)
294 WCHAR buffer[] = {'A', ':', 0};
296 buffer[0] += newdrive - 1;
297 if (!SetCurrentDirectoryW( buffer ))
299 msvcrt_set_errno(GetLastError());
300 if (newdrive <= 0)
301 *MSVCRT__errno() = MSVCRT_EACCES;
302 return -1;
304 return 0;
307 /*********************************************************************
308 * _findclose (MSVCRT.@)
310 * Close a handle returned by _findfirst().
312 * PARAMS
313 * hand [I] Handle to close
315 * RETURNS
316 * Success: 0. All resources associated with hand are freed.
317 * Failure: -1. errno indicates the error.
319 * NOTES
320 * See FindClose.
322 int CDECL MSVCRT__findclose(MSVCRT_intptr_t hand)
324 TRACE(":handle %ld\n",hand);
325 if (!FindClose((HANDLE)hand))
327 msvcrt_set_errno(GetLastError());
328 return -1;
330 return 0;
333 /*********************************************************************
334 * _findfirst (MSVCRT.@)
336 * Open a handle for iterating through a directory.
338 * PARAMS
339 * fspec [I] File specification of files to iterate.
340 * ft [O] Information for the first file found.
342 * RETURNS
343 * Success: A handle suitable for passing to _findnext() and _findclose().
344 * ft is populated with the details of the found file.
345 * Failure: -1. errno indicates the error.
347 * NOTES
348 * See FindFirstFileA.
350 MSVCRT_intptr_t CDECL MSVCRT__findfirst(const char * fspec, struct MSVCRT__finddata_t* ft)
352 WIN32_FIND_DATAA find_data;
353 HANDLE hfind;
355 hfind = FindFirstFileA(fspec, &find_data);
356 if (hfind == INVALID_HANDLE_VALUE)
358 msvcrt_set_errno(GetLastError());
359 return -1;
361 msvcrt_fttofd(&find_data,ft);
362 TRACE(":got handle %p\n",hfind);
363 return (MSVCRT_intptr_t)hfind;
366 /*********************************************************************
367 * _findfirst32 (MSVCRT.@)
369 MSVCRT_intptr_t CDECL MSVCRT__findfirst32(const char * fspec, struct MSVCRT__finddata32_t* ft)
371 WIN32_FIND_DATAA find_data;
372 HANDLE hfind;
374 hfind = FindFirstFileA(fspec, &find_data);
375 if (hfind == INVALID_HANDLE_VALUE)
377 msvcrt_set_errno(GetLastError());
378 return -1;
380 msvcrt_fttofd32(&find_data, ft);
381 TRACE(":got handle %p\n", hfind);
382 return (MSVCRT_intptr_t)hfind;
385 /*********************************************************************
386 * _wfindfirst (MSVCRT.@)
388 * Unicode version of _findfirst.
390 MSVCRT_intptr_t CDECL MSVCRT__wfindfirst(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddata_t* ft)
392 WIN32_FIND_DATAW find_data;
393 HANDLE hfind;
395 hfind = FindFirstFileW(fspec, &find_data);
396 if (hfind == INVALID_HANDLE_VALUE)
398 msvcrt_set_errno(GetLastError());
399 return -1;
401 msvcrt_wfttofd(&find_data,ft);
402 TRACE(":got handle %p\n",hfind);
403 return (MSVCRT_intptr_t)hfind;
406 /*********************************************************************
407 * _wfindfirst32 (MSVCRT.@)
409 * Unicode version of _findfirst32.
411 MSVCRT_intptr_t CDECL MSVCRT__wfindfirst32(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddata32_t* ft)
413 WIN32_FIND_DATAW find_data;
414 HANDLE hfind;
416 hfind = FindFirstFileW(fspec, &find_data);
417 if (hfind == INVALID_HANDLE_VALUE)
419 msvcrt_set_errno(GetLastError());
420 return -1;
422 msvcrt_wfttofd32(&find_data, ft);
423 TRACE(":got handle %p\n", hfind);
424 return (MSVCRT_intptr_t)hfind;
427 /*********************************************************************
428 * _findfirsti64 (MSVCRT.@)
430 * 64-bit version of _findfirst.
432 MSVCRT_intptr_t CDECL MSVCRT__findfirsti64(const char * fspec, struct MSVCRT__finddatai64_t* ft)
434 WIN32_FIND_DATAA find_data;
435 HANDLE hfind;
437 hfind = FindFirstFileA(fspec, &find_data);
438 if (hfind == INVALID_HANDLE_VALUE)
440 msvcrt_set_errno(GetLastError());
441 return -1;
443 msvcrt_fttofdi64(&find_data,ft);
444 TRACE(":got handle %p\n",hfind);
445 return (MSVCRT_intptr_t)hfind;
448 /*********************************************************************
449 * _findfirst64 (MSVCRT.@)
451 * 64-bit version of _findfirst.
453 MSVCRT_intptr_t CDECL MSVCRT__findfirst64(const char * fspec, struct MSVCRT__finddata64_t* ft)
455 WIN32_FIND_DATAA find_data;
456 HANDLE hfind;
458 hfind = FindFirstFileA(fspec, &find_data);
459 if (hfind == INVALID_HANDLE_VALUE)
461 msvcrt_set_errno(GetLastError());
462 return -1;
464 msvcrt_fttofd64(&find_data,ft);
465 TRACE(":got handle %p\n",hfind);
466 return (MSVCRT_intptr_t)hfind;
469 /*********************************************************************
470 * _wfindfirst64 (MSVCRT.@)
472 * Unicode version of _findfirst64.
474 MSVCRT_intptr_t CDECL MSVCRT__wfindfirst64(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddata64_t* ft)
476 WIN32_FIND_DATAW find_data;
477 HANDLE hfind;
479 hfind = FindFirstFileW(fspec, &find_data);
480 if (hfind == INVALID_HANDLE_VALUE)
482 msvcrt_set_errno(GetLastError());
483 return -1;
485 msvcrt_wfttofd64(&find_data,ft);
486 TRACE(":got handle %p\n",hfind);
487 return (MSVCRT_intptr_t)hfind;
490 /*********************************************************************
491 * _findfirst64i32 (MSVCRT.@)
493 * 64-bit/32-bit version of _findfirst.
495 MSVCRT_intptr_t CDECL MSVCRT__findfirst64i32(const char * fspec, struct MSVCRT__finddata64i32_t* ft)
497 WIN32_FIND_DATAA find_data;
498 HANDLE hfind;
500 hfind = FindFirstFileA(fspec, &find_data);
501 if (hfind == INVALID_HANDLE_VALUE)
503 msvcrt_set_errno(GetLastError());
504 return -1;
506 msvcrt_fttofd64i32(&find_data,ft);
507 TRACE(":got handle %p\n",hfind);
508 return (MSVCRT_intptr_t)hfind;
511 /*********************************************************************
512 * _wfindfirst64i32 (MSVCRT.@)
514 * Unicode version of _findfirst64i32.
516 MSVCRT_intptr_t CDECL MSVCRT__wfindfirst64i32(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddata64i32_t* ft)
518 WIN32_FIND_DATAW find_data;
519 HANDLE hfind;
521 hfind = FindFirstFileW(fspec, &find_data);
522 if (hfind == INVALID_HANDLE_VALUE)
524 msvcrt_set_errno(GetLastError());
525 return -1;
527 msvcrt_wfttofd64i32(&find_data,ft);
528 TRACE(":got handle %p\n",hfind);
529 return (MSVCRT_intptr_t)hfind;
532 /*********************************************************************
533 * _wfindfirsti64 (MSVCRT.@)
535 * Unicode version of _findfirsti64.
537 MSVCRT_intptr_t CDECL MSVCRT__wfindfirsti64(const MSVCRT_wchar_t * fspec, struct MSVCRT__wfinddatai64_t* ft)
539 WIN32_FIND_DATAW find_data;
540 HANDLE hfind;
542 hfind = FindFirstFileW(fspec, &find_data);
543 if (hfind == INVALID_HANDLE_VALUE)
545 msvcrt_set_errno(GetLastError());
546 return -1;
548 msvcrt_wfttofdi64(&find_data,ft);
549 TRACE(":got handle %p\n",hfind);
550 return (MSVCRT_intptr_t)hfind;
553 /*********************************************************************
554 * _findnext (MSVCRT.@)
556 * Find the next file from a file search handle.
558 * PARAMS
559 * hand [I] Handle to the search returned from _findfirst().
560 * ft [O] Information for the file found.
562 * RETURNS
563 * Success: 0. ft is populated with the details of the found file.
564 * Failure: -1. errno indicates the error.
566 * NOTES
567 * See FindNextFileA.
569 int CDECL MSVCRT__findnext(MSVCRT_intptr_t hand, struct MSVCRT__finddata_t * ft)
571 WIN32_FIND_DATAA find_data;
573 if (!FindNextFileA((HANDLE)hand, &find_data))
575 *MSVCRT__errno() = MSVCRT_ENOENT;
576 return -1;
579 msvcrt_fttofd(&find_data,ft);
580 return 0;
583 /*********************************************************************
584 * _findnext32 (MSVCRT.@)
586 int CDECL MSVCRT__findnext32(MSVCRT_intptr_t hand, struct MSVCRT__finddata32_t * ft)
588 WIN32_FIND_DATAA find_data;
590 if (!FindNextFileA((HANDLE)hand, &find_data))
592 *MSVCRT__errno() = MSVCRT_ENOENT;
593 return -1;
596 msvcrt_fttofd32(&find_data, ft);
597 return 0;
600 /*********************************************************************
601 * _wfindnext32 (MSVCRT.@)
603 int CDECL MSVCRT__wfindnext32(MSVCRT_intptr_t hand, struct MSVCRT__wfinddata32_t * ft)
605 WIN32_FIND_DATAW find_data;
607 if (!FindNextFileW((HANDLE)hand, &find_data))
609 *MSVCRT__errno() = MSVCRT_ENOENT;
610 return -1;
613 msvcrt_wfttofd32(&find_data, ft);
614 return 0;
617 /*********************************************************************
618 * _wfindnext (MSVCRT.@)
620 * Unicode version of _findnext.
622 int CDECL MSVCRT__wfindnext(MSVCRT_intptr_t hand, struct MSVCRT__wfinddata_t * ft)
624 WIN32_FIND_DATAW find_data;
626 if (!FindNextFileW((HANDLE)hand, &find_data))
628 *MSVCRT__errno() = MSVCRT_ENOENT;
629 return -1;
632 msvcrt_wfttofd(&find_data,ft);
633 return 0;
636 /*********************************************************************
637 * _findnexti64 (MSVCRT.@)
639 * 64-bit version of _findnext.
641 int CDECL MSVCRT__findnexti64(MSVCRT_intptr_t hand, struct MSVCRT__finddatai64_t * ft)
643 WIN32_FIND_DATAA find_data;
645 if (!FindNextFileA((HANDLE)hand, &find_data))
647 *MSVCRT__errno() = MSVCRT_ENOENT;
648 return -1;
651 msvcrt_fttofdi64(&find_data,ft);
652 return 0;
655 /*********************************************************************
656 * _findnext64 (MSVCRT.@)
658 * 64-bit version of _findnext.
660 int CDECL MSVCRT__findnext64(MSVCRT_intptr_t hand, struct MSVCRT__finddata64_t * ft)
662 WIN32_FIND_DATAA find_data;
664 if (!FindNextFileA((HANDLE)hand, &find_data))
666 *MSVCRT__errno() = MSVCRT_ENOENT;
667 return -1;
670 msvcrt_fttofd64(&find_data,ft);
671 return 0;
674 /*********************************************************************
675 * _wfindnext64 (MSVCRT.@)
677 * Unicode version of _wfindnext64.
679 int CDECL MSVCRT__wfindnext64(MSVCRT_intptr_t hand, struct MSVCRT__wfinddata64_t * ft)
681 WIN32_FIND_DATAW find_data;
683 if (!FindNextFileW((HANDLE)hand, &find_data))
685 *MSVCRT__errno() = MSVCRT_ENOENT;
686 return -1;
689 msvcrt_wfttofd64(&find_data,ft);
690 return 0;
693 /*********************************************************************
694 * _findnext64i32 (MSVCRT.@)
696 * 64-bit/32-bit version of _findnext.
698 int CDECL MSVCRT__findnext64i32(MSVCRT_intptr_t hand, struct MSVCRT__finddata64i32_t * ft)
700 WIN32_FIND_DATAA find_data;
702 if (!FindNextFileA((HANDLE)hand, &find_data))
704 *MSVCRT__errno() = MSVCRT_ENOENT;
705 return -1;
708 msvcrt_fttofd64i32(&find_data,ft);
709 return 0;
712 /*********************************************************************
713 * _wfindnexti64 (MSVCRT.@)
715 * Unicode version of _findnexti64.
717 int CDECL MSVCRT__wfindnexti64(MSVCRT_intptr_t hand, struct MSVCRT__wfinddatai64_t * ft)
719 WIN32_FIND_DATAW find_data;
721 if (!FindNextFileW((HANDLE)hand, &find_data))
723 *MSVCRT__errno() = MSVCRT_ENOENT;
724 return -1;
727 msvcrt_wfttofdi64(&find_data,ft);
728 return 0;
731 /*********************************************************************
732 * _wfindnext64i32 (MSVCRT.@)
734 * Unicode version of _findnext64i32.
736 int CDECL MSVCRT__wfindnext64i32(MSVCRT_intptr_t hand, struct MSVCRT__wfinddata64i32_t * ft)
738 WIN32_FIND_DATAW find_data;
740 if (!FindNextFileW((HANDLE)hand, &find_data))
742 *MSVCRT__errno() = MSVCRT_ENOENT;
743 return -1;
746 msvcrt_wfttofd64i32(&find_data,ft);
747 return 0;
750 /*********************************************************************
751 * _getcwd (MSVCRT.@)
753 * Get the current working directory.
755 * PARAMS
756 * buf [O] Destination for current working directory.
757 * size [I] Size of buf in characters
759 * RETURNS
760 * Success: If buf is NULL, returns an allocated string containing the path.
761 * Otherwise populates buf with the path and returns it.
762 * Failure: NULL. errno indicates the error.
764 char* CDECL MSVCRT__getcwd(char * buf, int size)
766 char dir[MAX_PATH];
767 int dir_len = GetCurrentDirectoryA(MAX_PATH,dir);
769 if (dir_len < 1)
770 return NULL; /* FIXME: Real return value untested */
772 if (!buf)
774 if (size <= dir_len) size = dir_len + 1;
775 if (!(buf = MSVCRT_malloc( size ))) return NULL;
777 else if (dir_len >= size)
779 *MSVCRT__errno() = MSVCRT_ERANGE;
780 return NULL; /* buf too small */
782 strcpy(buf,dir);
783 return buf;
786 /*********************************************************************
787 * _wgetcwd (MSVCRT.@)
789 * Unicode version of _getcwd.
791 MSVCRT_wchar_t* CDECL MSVCRT__wgetcwd(MSVCRT_wchar_t * buf, int size)
793 MSVCRT_wchar_t dir[MAX_PATH];
794 int dir_len = GetCurrentDirectoryW(MAX_PATH,dir);
796 if (dir_len < 1)
797 return NULL; /* FIXME: Real return value untested */
799 if (!buf)
801 if (size <= dir_len) size = dir_len + 1;
802 if (!(buf = MSVCRT_malloc( size * sizeof(WCHAR) ))) return NULL;
804 if (dir_len >= size)
806 *MSVCRT__errno() = MSVCRT_ERANGE;
807 return NULL; /* buf too small */
809 MSVCRT_wcscpy(buf,dir);
810 return buf;
813 /*********************************************************************
814 * _getdrive (MSVCRT.@)
816 * Get the current drive number.
818 * PARAMS
819 * None.
821 * RETURNS
822 * Success: The drive letter number from 1 to 26 ("A:" to "Z:").
823 * Failure: 0.
825 int CDECL MSVCRT__getdrive(void)
827 WCHAR buffer[MAX_PATH];
828 if (GetCurrentDirectoryW( MAX_PATH, buffer ) &&
829 buffer[0] >= 'A' && buffer[0] <= 'z' && buffer[1] == ':')
830 return MSVCRT_towupper(buffer[0]) - 'A' + 1;
831 return 0;
834 /*********************************************************************
835 * _getdcwd (MSVCRT.@)
837 * Get the current working directory on a given disk.
839 * PARAMS
840 * drive [I] Drive letter to get the current working directory from.
841 * buf [O] Destination for the current working directory.
842 * size [I] Length of drive in characters.
844 * RETURNS
845 * Success: If drive is NULL, returns an allocated string containing the path.
846 * Otherwise populates drive with the path and returns it.
847 * Failure: NULL. errno indicates the error.
849 char* CDECL MSVCRT__getdcwd(int drive, char * buf, int size)
851 static char* dummy;
853 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
855 if (!drive || drive == MSVCRT__getdrive())
856 return MSVCRT__getcwd(buf,size); /* current */
857 else
859 char dir[MAX_PATH];
860 char drivespec[] = {'A', ':', 0};
861 int dir_len;
863 drivespec[0] += drive - 1;
864 if (GetDriveTypeA(drivespec) < DRIVE_REMOVABLE)
866 *MSVCRT__errno() = MSVCRT_EACCES;
867 return NULL;
870 dir_len = GetFullPathNameA(drivespec,MAX_PATH,dir,&dummy);
871 if (dir_len >= size || dir_len < 1)
873 *MSVCRT__errno() = MSVCRT_ERANGE;
874 return NULL; /* buf too small */
877 TRACE(":returning '%s'\n", dir);
878 if (!buf)
879 return MSVCRT__strdup(dir); /* allocate */
881 strcpy(buf,dir);
883 return buf;
886 /*********************************************************************
887 * _wgetdcwd (MSVCRT.@)
889 * Unicode version of _wgetdcwd.
891 MSVCRT_wchar_t* CDECL MSVCRT__wgetdcwd(int drive, MSVCRT_wchar_t * buf, int size)
893 static MSVCRT_wchar_t* dummy;
895 TRACE(":drive %d(%c), size %d\n",drive, drive + 'A' - 1, size);
897 if (!drive || drive == MSVCRT__getdrive())
898 return MSVCRT__wgetcwd(buf,size); /* current */
899 else
901 MSVCRT_wchar_t dir[MAX_PATH];
902 MSVCRT_wchar_t drivespec[4] = {'A', ':', '\\', 0};
903 int dir_len;
905 drivespec[0] += drive - 1;
906 if (GetDriveTypeW(drivespec) < DRIVE_REMOVABLE)
908 *MSVCRT__errno() = MSVCRT_EACCES;
909 return NULL;
912 dir_len = GetFullPathNameW(drivespec,MAX_PATH,dir,&dummy);
913 if (dir_len >= size || dir_len < 1)
915 *MSVCRT__errno() = MSVCRT_ERANGE;
916 return NULL; /* buf too small */
919 TRACE(":returning %s\n", debugstr_w(dir));
920 if (!buf)
921 return MSVCRT__wcsdup(dir); /* allocate */
922 MSVCRT_wcscpy(buf,dir);
924 return buf;
927 /*********************************************************************
928 * _getdiskfree (MSVCRT.@)
930 * Get information about the free space on a drive.
932 * PARAMS
933 * disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
934 * info [O] Destination for the resulting information.
936 * RETURNS
937 * Success: 0. info is updated with the free space information.
938 * Failure: An error code from GetLastError().
940 * NOTES
941 * See GetLastError().
943 unsigned int CDECL MSVCRT__getdiskfree(unsigned int disk, struct MSVCRT__diskfree_t * d)
945 WCHAR drivespec[] = {'@', ':', '\\', 0};
946 DWORD ret[4];
947 unsigned int err;
949 if (disk > 26)
950 return ERROR_INVALID_PARAMETER; /* MSVCRT doesn't set errno here */
952 drivespec[0] += disk; /* make a drive letter */
954 if (GetDiskFreeSpaceW(disk==0?NULL:drivespec,ret,ret+1,ret+2,ret+3))
956 d->sectors_per_cluster = ret[0];
957 d->bytes_per_sector = ret[1];
958 d->avail_clusters = ret[2];
959 d->total_clusters = ret[3];
960 return 0;
962 err = GetLastError();
963 msvcrt_set_errno(err);
964 return err;
967 /*********************************************************************
968 * _mkdir (MSVCRT.@)
970 * Create a directory.
972 * PARAMS
973 * newdir [I] Name of directory to create.
975 * RETURNS
976 * Success: 0. The directory indicated by newdir is created.
977 * Failure: -1. errno indicates the error.
979 * NOTES
980 * See CreateDirectoryA.
982 int CDECL MSVCRT__mkdir(const char * newdir)
984 if (CreateDirectoryA(newdir,NULL))
985 return 0;
986 msvcrt_set_errno(GetLastError());
987 return -1;
990 /*********************************************************************
991 * _wmkdir (MSVCRT.@)
993 * Unicode version of _mkdir.
995 int CDECL MSVCRT__wmkdir(const MSVCRT_wchar_t* newdir)
997 if (CreateDirectoryW(newdir,NULL))
998 return 0;
999 msvcrt_set_errno(GetLastError());
1000 return -1;
1003 /*********************************************************************
1004 * _rmdir (MSVCRT.@)
1006 * Delete a directory.
1008 * PARAMS
1009 * dir [I] Name of directory to delete.
1011 * RETURNS
1012 * Success: 0. The directory indicated by newdir is deleted.
1013 * Failure: -1. errno indicates the error.
1015 * NOTES
1016 * See RemoveDirectoryA.
1018 int CDECL MSVCRT__rmdir(const char * dir)
1020 if (RemoveDirectoryA(dir))
1021 return 0;
1022 msvcrt_set_errno(GetLastError());
1023 return -1;
1026 /*********************************************************************
1027 * _wrmdir (MSVCRT.@)
1029 * Unicode version of _rmdir.
1031 int CDECL MSVCRT__wrmdir(const MSVCRT_wchar_t * dir)
1033 if (RemoveDirectoryW(dir))
1034 return 0;
1035 msvcrt_set_errno(GetLastError());
1036 return -1;
1039 /******************************************************************
1040 * _splitpath_s (MSVCRT.@)
1042 int CDECL MSVCRT__splitpath_s(const char* inpath,
1043 char* drive, MSVCRT_size_t sz_drive,
1044 char* dir, MSVCRT_size_t sz_dir,
1045 char* fname, MSVCRT_size_t sz_fname,
1046 char* ext, MSVCRT_size_t sz_ext)
1048 const char *p, *end;
1050 if (!inpath || (!drive && sz_drive) ||
1051 (drive && !sz_drive) ||
1052 (!dir && sz_dir) ||
1053 (dir && !sz_dir) ||
1054 (!fname && sz_fname) ||
1055 (fname && !sz_fname) ||
1056 (!ext && sz_ext) ||
1057 (ext && !sz_ext))
1059 *MSVCRT__errno() = MSVCRT_EINVAL;
1060 return MSVCRT_EINVAL;
1063 if (inpath[0] && inpath[1] == ':')
1065 if (drive)
1067 if (sz_drive <= 2) goto do_error;
1068 drive[0] = inpath[0];
1069 drive[1] = inpath[1];
1070 drive[2] = 0;
1072 inpath += 2;
1074 else if (drive) drive[0] = '\0';
1076 /* look for end of directory part */
1077 end = NULL;
1078 for (p = inpath; *p; p++)
1080 if (_ismbblead((unsigned char)*p))
1082 p++;
1083 continue;
1085 if (*p == '/' || *p == '\\') end = p + 1;
1088 if (end) /* got a directory */
1090 if (dir)
1092 if (sz_dir <= end - inpath) goto do_error;
1093 memcpy( dir, inpath, (end - inpath) );
1094 dir[end - inpath] = 0;
1096 inpath = end;
1098 else if (dir) dir[0] = 0;
1100 /* look for extension: what's after the last dot */
1101 end = NULL;
1102 for (p = inpath; *p; p++) if (*p == '.') end = p;
1104 if (!end) end = p; /* there's no extension */
1106 if (fname)
1108 if (sz_fname <= end - inpath) goto do_error;
1109 memcpy( fname, inpath, (end - inpath) );
1110 fname[end - inpath] = 0;
1112 if (ext)
1114 if (sz_ext <= strlen(end)) goto do_error;
1115 strcpy( ext, end );
1117 return 0;
1118 do_error:
1119 if (drive) drive[0] = '\0';
1120 if (dir) dir[0] = '\0';
1121 if (fname) fname[0]= '\0';
1122 if (ext) ext[0]= '\0';
1123 *MSVCRT__errno() = MSVCRT_ERANGE;
1124 return MSVCRT_ERANGE;
1127 /*********************************************************************
1128 * _splitpath (MSVCRT.@)
1130 void CDECL MSVCRT__splitpath(const char *inpath, char *drv, char *dir,
1131 char *fname, char *ext)
1133 MSVCRT__splitpath_s(inpath, drv, drv?MSVCRT__MAX_DRIVE:0, dir, dir?MSVCRT__MAX_DIR:0,
1134 fname, fname?MSVCRT__MAX_FNAME:0, ext, ext?MSVCRT__MAX_EXT:0);
1137 /******************************************************************
1138 * _wsplitpath_s (MSVCRT.@)
1140 * Secure version of _wsplitpath
1142 int CDECL MSVCRT__wsplitpath_s(const MSVCRT_wchar_t* inpath,
1143 MSVCRT_wchar_t* drive, MSVCRT_size_t sz_drive,
1144 MSVCRT_wchar_t* dir, MSVCRT_size_t sz_dir,
1145 MSVCRT_wchar_t* fname, MSVCRT_size_t sz_fname,
1146 MSVCRT_wchar_t* ext, MSVCRT_size_t sz_ext)
1148 const MSVCRT_wchar_t *p, *end;
1150 if (!inpath || (!drive && sz_drive) ||
1151 (drive && !sz_drive) ||
1152 (!dir && sz_dir) ||
1153 (dir && !sz_dir) ||
1154 (!fname && sz_fname) ||
1155 (fname && !sz_fname) ||
1156 (!ext && sz_ext) ||
1157 (ext && !sz_ext))
1159 *MSVCRT__errno() = MSVCRT_EINVAL;
1160 return MSVCRT_EINVAL;
1163 if (inpath[0] && inpath[1] == ':')
1165 if (drive)
1167 if (sz_drive <= 2) goto do_error;
1168 drive[0] = inpath[0];
1169 drive[1] = inpath[1];
1170 drive[2] = 0;
1172 inpath += 2;
1174 else if (drive) drive[0] = '\0';
1176 /* look for end of directory part */
1177 end = NULL;
1178 for (p = inpath; *p; p++) if (*p == '/' || *p == '\\') end = p + 1;
1180 if (end) /* got a directory */
1182 if (dir)
1184 if (sz_dir <= end - inpath) goto do_error;
1185 memcpy( dir, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
1186 dir[end - inpath] = 0;
1188 inpath = end;
1190 else if (dir) dir[0] = 0;
1192 /* look for extension: what's after the last dot */
1193 end = NULL;
1194 for (p = inpath; *p; p++) if (*p == '.') end = p;
1196 if (!end) end = p; /* there's no extension */
1198 if (fname)
1200 if (sz_fname <= end - inpath) goto do_error;
1201 memcpy( fname, inpath, (end - inpath) * sizeof(MSVCRT_wchar_t) );
1202 fname[end - inpath] = 0;
1204 if (ext)
1206 if (sz_ext <= MSVCRT_wcslen(end)) goto do_error;
1207 MSVCRT_wcscpy( ext, end );
1209 return 0;
1210 do_error:
1211 if (drive) drive[0] = '\0';
1212 if (dir) dir[0] = '\0';
1213 if (fname) fname[0]= '\0';
1214 if (ext) ext[0]= '\0';
1215 *MSVCRT__errno() = MSVCRT_ERANGE;
1216 return MSVCRT_ERANGE;
1219 /*********************************************************************
1220 * _wsplitpath (MSVCRT.@)
1222 * Unicode version of _splitpath.
1224 void CDECL MSVCRT__wsplitpath(const MSVCRT_wchar_t *inpath, MSVCRT_wchar_t *drv, MSVCRT_wchar_t *dir,
1225 MSVCRT_wchar_t *fname, MSVCRT_wchar_t *ext)
1227 MSVCRT__wsplitpath_s(inpath, drv, drv?MSVCRT__MAX_DRIVE:0, dir, dir?MSVCRT__MAX_DIR:0,
1228 fname, fname?MSVCRT__MAX_FNAME:0, ext, ext?MSVCRT__MAX_EXT:0);
1231 /*********************************************************************
1232 * _wfullpath (MSVCRT.@)
1234 * Unicode version of _fullpath.
1236 MSVCRT_wchar_t * CDECL MSVCRT__wfullpath(MSVCRT_wchar_t * absPath, const MSVCRT_wchar_t* relPath, MSVCRT_size_t size)
1238 DWORD rc;
1239 WCHAR* buffer;
1240 WCHAR* lastpart;
1241 BOOL alloced = FALSE;
1243 if (!relPath || !*relPath)
1244 return MSVCRT__wgetcwd(absPath, size);
1246 if (absPath == NULL)
1248 buffer = MSVCRT_malloc(MAX_PATH * sizeof(WCHAR));
1249 size = MAX_PATH;
1250 alloced = TRUE;
1252 else
1253 buffer = absPath;
1255 if (size < 4)
1257 *MSVCRT__errno() = MSVCRT_ERANGE;
1258 return NULL;
1261 TRACE(":resolving relative path %s\n",debugstr_w(relPath));
1263 rc = GetFullPathNameW(relPath,size,buffer,&lastpart);
1265 if (rc > 0 && rc <= size )
1266 return buffer;
1267 else
1269 if (alloced)
1270 MSVCRT_free(buffer);
1271 return NULL;
1275 /*********************************************************************
1276 * _fullpath (MSVCRT.@)
1278 * Create an absolute path from a relative path.
1280 * PARAMS
1281 * absPath [O] Destination for absolute path
1282 * relPath [I] Relative path to convert to absolute
1283 * size [I] Length of absPath in characters.
1285 * RETURNS
1286 * Success: If absPath is NULL, returns an allocated string containing the path.
1287 * Otherwise populates absPath with the path and returns it.
1288 * Failure: NULL. errno indicates the error.
1290 char * CDECL MSVCRT__fullpath(char * absPath, const char* relPath, unsigned int size)
1292 DWORD rc;
1293 char* lastpart;
1294 char* buffer;
1295 BOOL alloced = FALSE;
1297 if (!relPath || !*relPath)
1298 return MSVCRT__getcwd(absPath, size);
1300 if (absPath == NULL)
1302 buffer = MSVCRT_malloc(MAX_PATH);
1303 size = MAX_PATH;
1304 alloced = TRUE;
1306 else
1307 buffer = absPath;
1309 if (size < 4)
1311 *MSVCRT__errno() = MSVCRT_ERANGE;
1312 return NULL;
1315 TRACE(":resolving relative path '%s'\n",relPath);
1317 rc = GetFullPathNameA(relPath,size,buffer,&lastpart);
1319 if (rc > 0 && rc <= size)
1320 return buffer;
1321 else
1323 if (alloced)
1324 MSVCRT_free(buffer);
1325 return NULL;
1329 /*********************************************************************
1330 * _makepath (MSVCRT.@)
1332 * Create a pathname.
1334 * PARAMS
1335 * path [O] Destination for created pathname
1336 * drive [I] Drive letter (e.g. "A:")
1337 * directory [I] Directory
1338 * filename [I] Name of the file, excluding extension
1339 * extension [I] File extension (e.g. ".TXT")
1341 * RETURNS
1342 * Nothing. If path is not large enough to hold the resulting pathname,
1343 * random process memory will be overwritten.
1345 VOID CDECL MSVCRT__makepath(char * path, const char * drive,
1346 const char *directory, const char * filename,
1347 const char * extension)
1349 char *p = path;
1351 TRACE("(%s %s %s %s)\n", debugstr_a(drive), debugstr_a(directory),
1352 debugstr_a(filename), debugstr_a(extension) );
1354 if ( !path )
1355 return;
1357 if (drive && drive[0])
1359 *p++ = drive[0];
1360 *p++ = ':';
1362 if (directory && directory[0])
1364 unsigned int len = strlen(directory);
1365 memmove(p, directory, len);
1366 p += len;
1367 if (p[-1] != '/' && p[-1] != '\\')
1368 *p++ = '\\';
1370 if (filename && filename[0])
1372 unsigned int len = strlen(filename);
1373 memmove(p, filename, len);
1374 p += len;
1376 if (extension && extension[0])
1378 if (extension[0] != '.')
1379 *p++ = '.';
1380 strcpy(p, extension);
1382 else
1383 *p = '\0';
1384 TRACE("returning %s\n",path);
1387 /*********************************************************************
1388 * _wmakepath (MSVCRT.@)
1390 * Unicode version of _wmakepath.
1392 VOID CDECL MSVCRT__wmakepath(MSVCRT_wchar_t *path, const MSVCRT_wchar_t *drive, const MSVCRT_wchar_t *directory,
1393 const MSVCRT_wchar_t *filename, const MSVCRT_wchar_t *extension)
1395 MSVCRT_wchar_t *p = path;
1397 TRACE("%s %s %s %s\n", debugstr_w(drive), debugstr_w(directory),
1398 debugstr_w(filename), debugstr_w(extension));
1400 if ( !path )
1401 return;
1403 if (drive && drive[0])
1405 *p++ = drive[0];
1406 *p++ = ':';
1408 if (directory && directory[0])
1410 unsigned int len = MSVCRT_wcslen(directory);
1411 memmove(p, directory, len * sizeof(MSVCRT_wchar_t));
1412 p += len;
1413 if (p[-1] != '/' && p[-1] != '\\')
1414 *p++ = '\\';
1416 if (filename && filename[0])
1418 unsigned int len = MSVCRT_wcslen(filename);
1419 memmove(p, filename, len * sizeof(MSVCRT_wchar_t));
1420 p += len;
1422 if (extension && extension[0])
1424 if (extension[0] != '.')
1425 *p++ = '.';
1426 MSVCRT_wcscpy(p, extension);
1428 else
1429 *p = '\0';
1431 TRACE("returning %s\n", debugstr_w(path));
1434 /*********************************************************************
1435 * _makepath_s (MSVCRT.@)
1437 * Safe version of _makepath.
1439 int CDECL MSVCRT__makepath_s(char *path, MSVCRT_size_t size, const char *drive,
1440 const char *directory, const char *filename,
1441 const char *extension)
1443 char *p = path;
1445 if (!path || !size)
1447 *MSVCRT__errno() = MSVCRT_EINVAL;
1448 return MSVCRT_EINVAL;
1451 if (drive && drive[0])
1453 if (size <= 2)
1454 goto range;
1456 *p++ = drive[0];
1457 *p++ = ':';
1458 size -= 2;
1461 if (directory && directory[0])
1463 unsigned int len = strlen(directory);
1464 unsigned int needs_separator = directory[len - 1] != '/' && directory[len - 1] != '\\';
1465 unsigned int copylen = min(size - 1, len);
1467 if (size < 2)
1468 goto range;
1470 memmove(p, directory, copylen);
1472 if (size <= len)
1473 goto range;
1475 p += copylen;
1476 size -= copylen;
1478 if (needs_separator)
1480 if (size < 2)
1481 goto range;
1483 *p++ = '\\';
1484 size -= 1;
1488 if (filename && filename[0])
1490 unsigned int len = strlen(filename);
1491 unsigned int copylen = min(size - 1, len);
1493 if (size < 2)
1494 goto range;
1496 memmove(p, filename, copylen);
1498 if (size <= len)
1499 goto range;
1501 p += len;
1502 size -= len;
1505 if (extension && extension[0])
1507 unsigned int len = strlen(extension);
1508 unsigned int needs_period = extension[0] != '.';
1509 unsigned int copylen;
1511 if (size < 2)
1512 goto range;
1514 if (needs_period)
1516 *p++ = '.';
1517 size -= 1;
1520 copylen = min(size - 1, len);
1521 memcpy(p, extension, copylen);
1523 if (size <= len)
1524 goto range;
1526 p += copylen;
1529 *p = '\0';
1530 return 0;
1532 range:
1533 path[0] = '\0';
1534 *MSVCRT__errno() = MSVCRT_ERANGE;
1535 return MSVCRT_ERANGE;
1538 /*********************************************************************
1539 * _wmakepath_s (MSVCRT.@)
1541 * Safe version of _wmakepath.
1543 int CDECL MSVCRT__wmakepath_s(MSVCRT_wchar_t *path, MSVCRT_size_t size, const MSVCRT_wchar_t *drive,
1544 const MSVCRT_wchar_t *directory, const MSVCRT_wchar_t *filename,
1545 const MSVCRT_wchar_t *extension)
1547 MSVCRT_wchar_t *p = path;
1549 if (!path || !size)
1551 *MSVCRT__errno() = MSVCRT_EINVAL;
1552 return MSVCRT_EINVAL;
1555 if (drive && drive[0])
1557 if (size <= 2)
1558 goto range;
1560 *p++ = drive[0];
1561 *p++ = ':';
1562 size -= 2;
1565 if (directory && directory[0])
1567 unsigned int len = MSVCRT_wcslen(directory);
1568 unsigned int needs_separator = directory[len - 1] != '/' && directory[len - 1] != '\\';
1569 unsigned int copylen = min(size - 1, len);
1571 if (size < 2)
1572 goto range;
1574 memmove(p, directory, copylen * sizeof(MSVCRT_wchar_t));
1576 if (size <= len)
1577 goto range;
1579 p += copylen;
1580 size -= copylen;
1582 if (needs_separator)
1584 if (size < 2)
1585 goto range;
1587 *p++ = '\\';
1588 size -= 1;
1592 if (filename && filename[0])
1594 unsigned int len = MSVCRT_wcslen(filename);
1595 unsigned int copylen = min(size - 1, len);
1597 if (size < 2)
1598 goto range;
1600 memmove(p, filename, copylen * sizeof(MSVCRT_wchar_t));
1602 if (size <= len)
1603 goto range;
1605 p += len;
1606 size -= len;
1609 if (extension && extension[0])
1611 unsigned int len = MSVCRT_wcslen(extension);
1612 unsigned int needs_period = extension[0] != '.';
1613 unsigned int copylen;
1615 if (size < 2)
1616 goto range;
1618 if (needs_period)
1620 *p++ = '.';
1621 size -= 1;
1624 copylen = min(size - 1, len);
1625 memcpy(p, extension, copylen * sizeof(MSVCRT_wchar_t));
1627 if (size <= len)
1628 goto range;
1630 p += copylen;
1633 *p = '\0';
1634 return 0;
1636 range:
1637 path[0] = '\0';
1638 *MSVCRT__errno() = MSVCRT_ERANGE;
1639 return MSVCRT_ERANGE;
1642 /*********************************************************************
1643 * _searchenv_s (MSVCRT.@)
1645 int CDECL MSVCRT__searchenv_s(const char* file, const char* env, char *buf, MSVCRT_size_t count)
1647 char *envVal, *penv, *end;
1648 char path[MAX_PATH];
1649 MSVCRT_size_t path_len, fname_len;
1651 if (!MSVCRT_CHECK_PMT(file != NULL)) return MSVCRT_EINVAL;
1652 if (!MSVCRT_CHECK_PMT(buf != NULL)) return MSVCRT_EINVAL;
1653 if (!MSVCRT_CHECK_PMT(count > 0)) return MSVCRT_EINVAL;
1655 if (count > MAX_PATH)
1656 FIXME("count > MAX_PATH not supported\n");
1658 fname_len = strlen(file);
1659 *buf = '\0';
1661 /* Try CWD first */
1662 if (GetFileAttributesA( file ) != INVALID_FILE_ATTRIBUTES)
1664 if (GetFullPathNameA( file, count, buf, NULL )) return 0;
1665 msvcrt_set_errno(GetLastError());
1666 return 0;
1669 /* Search given environment variable */
1670 envVal = MSVCRT_getenv(env);
1671 if (!envVal)
1673 *MSVCRT__errno() = MSVCRT_ENOENT;
1674 return MSVCRT_ENOENT;
1677 penv = envVal;
1678 TRACE(":searching for %s in paths %s\n", file, envVal);
1680 for(; *penv; penv = (*end ? end + 1 : end))
1682 end = penv;
1683 path_len = 0;
1684 while(*end && *end != ';' && path_len < MAX_PATH)
1686 if (*end == '"')
1688 end++;
1689 while(*end && *end != '"' && path_len < MAX_PATH)
1691 path[path_len++] = *end;
1692 end++;
1694 if (*end == '"') end++;
1695 continue;
1698 path[path_len++] = *end;
1699 end++;
1701 if (!path_len || path_len >= MAX_PATH)
1702 continue;
1704 if (path[path_len - 1] != '/' && path[path_len - 1] != '\\')
1705 path[path_len++] = '\\';
1706 if (path_len + fname_len >= MAX_PATH)
1707 continue;
1709 memcpy(path + path_len, file, fname_len + 1);
1710 TRACE("Checking for file %s\n", path);
1711 if (GetFileAttributesA( path ) != INVALID_FILE_ATTRIBUTES)
1713 if (path_len + fname_len + 1 > count)
1715 MSVCRT_INVALID_PMT("buf[count] is too small", MSVCRT_ERANGE);
1716 return MSVCRT_ERANGE;
1718 memcpy(buf, path, path_len + fname_len + 1);
1719 return 0;
1723 *MSVCRT__errno() = MSVCRT_ENOENT;
1724 return MSVCRT_ENOENT;
1727 /*********************************************************************
1728 * _searchenv (MSVCRT.@)
1730 void CDECL MSVCRT__searchenv(const char* file, const char* env, char *buf)
1732 MSVCRT__searchenv_s(file, env, buf, MAX_PATH);
1735 /*********************************************************************
1736 * _wsearchenv_s (MSVCRT.@)
1738 int CDECL MSVCRT__wsearchenv_s(const MSVCRT_wchar_t* file, const MSVCRT_wchar_t* env,
1739 MSVCRT_wchar_t *buf, MSVCRT_size_t count)
1741 MSVCRT_wchar_t *envVal, *penv, *end;
1742 MSVCRT_wchar_t path[MAX_PATH];
1743 MSVCRT_size_t path_len, fname_len;
1745 if (!MSVCRT_CHECK_PMT(file != NULL)) return MSVCRT_EINVAL;
1746 if (!MSVCRT_CHECK_PMT(buf != NULL)) return MSVCRT_EINVAL;
1747 if (!MSVCRT_CHECK_PMT(count > 0)) return MSVCRT_EINVAL;
1749 if (count > MAX_PATH)
1750 FIXME("count > MAX_PATH not supported\n");
1752 fname_len = MSVCRT_wcslen(file);
1753 *buf = '\0';
1755 /* Try CWD first */
1756 if (GetFileAttributesW( file ) != INVALID_FILE_ATTRIBUTES)
1758 if (GetFullPathNameW( file, count, buf, NULL )) return 0;
1759 msvcrt_set_errno(GetLastError());
1760 return 0;
1763 /* Search given environment variable */
1764 envVal = MSVCRT__wgetenv(env);
1765 if (!envVal)
1767 *MSVCRT__errno() = MSVCRT_ENOENT;
1768 return MSVCRT_ENOENT;
1771 penv = envVal;
1772 TRACE(":searching for %s in paths %s\n", debugstr_w(file), debugstr_w(envVal));
1774 for(; *penv; penv = (*end ? end + 1 : end))
1776 end = penv;
1777 path_len = 0;
1778 while(*end && *end != ';' && path_len < MAX_PATH)
1780 if (*end == '"')
1782 end++;
1783 while(*end && *end != '"' && path_len < MAX_PATH)
1785 path[path_len++] = *end;
1786 end++;
1788 if (*end == '"') end++;
1789 continue;
1792 path[path_len++] = *end;
1793 end++;
1795 if (!path_len || path_len >= MAX_PATH)
1796 continue;
1798 if (path[path_len - 1] != '/' && path[path_len - 1] != '\\')
1799 path[path_len++] = '\\';
1800 if (path_len + fname_len >= MAX_PATH)
1801 continue;
1803 memcpy(path + path_len, file, (fname_len + 1) * sizeof(MSVCRT_wchar_t));
1804 TRACE("Checking for file %s\n", debugstr_w(path));
1805 if (GetFileAttributesW( path ) != INVALID_FILE_ATTRIBUTES)
1807 if (path_len + fname_len + 1 > count)
1809 MSVCRT_INVALID_PMT("buf[count] is too small", MSVCRT_ERANGE);
1810 return MSVCRT_ERANGE;
1812 memcpy(buf, path, (path_len + fname_len + 1) * sizeof(MSVCRT_wchar_t));
1813 return 0;
1817 *MSVCRT__errno() = MSVCRT_ENOENT;
1818 return MSVCRT_ENOENT;
1821 /*********************************************************************
1822 * _wsearchenv (MSVCRT.@)
1824 void CDECL MSVCRT__wsearchenv(const MSVCRT_wchar_t* file, const MSVCRT_wchar_t* env, MSVCRT_wchar_t *buf)
1826 MSVCRT__wsearchenv_s(file, env, buf, MAX_PATH);