2 * msvcrt.dll drive/directory functions
4 * Copyright 1996,1998 Marcus Meissner
5 * Copyright 1996 Jukka Iivonen
6 * Copyright 1997,2000 Uwe Bonnes
7 * Copyright 2000 Jon Griffiths
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "wine/port.h"
33 #include "wine/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
)
42 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
45 ft
->attrib
= fd
->dwFileAttributes
;
47 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
49 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
51 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &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
)
62 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
65 ft
->attrib
= fd
->dwFileAttributes
;
67 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
69 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
71 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &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
)
82 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
85 ft
->attrib
= fd
->dwFileAttributes
;
87 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
89 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
91 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &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
)
102 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
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
);
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
)
122 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
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
);
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
)
142 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
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
);
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
)
162 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
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
);
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
)
182 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
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
);
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
)
202 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
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
);
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
)
222 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
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
);
233 ft
->size
= fd
->nFileSizeLow
;
234 MSVCRT_wcscpy(ft
->name
, fd
->cFileName
);
237 /*********************************************************************
240 * Change the current working directory.
243 * newdir [I] Directory to change to
246 * Success: 0. The current working directory is set to newdir.
247 * Failure: -1. errno indicates the error.
250 * See SetCurrentDirectoryA.
252 int CDECL
MSVCRT__chdir(const char * newdir
)
254 if (!SetCurrentDirectoryA(newdir
))
256 msvcrt_set_errno(newdir
?GetLastError():0);
262 /*********************************************************************
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);
277 /*********************************************************************
278 * _chdrive (MSVCRT.@)
280 * Change the current drive.
283 * newdrive [I] Drive number to change to (1 = 'A', 2 = 'B', ...)
286 * Success: 0. The current drive is set to newdrive.
287 * Failure: -1. errno indicates the error.
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());
301 *MSVCRT__errno() = MSVCRT_EACCES
;
307 /*********************************************************************
308 * _findclose (MSVCRT.@)
310 * Close a handle returned by _findfirst().
313 * hand [I] Handle to close
316 * Success: 0. All resources associated with hand are freed.
317 * Failure: -1. errno indicates the error.
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());
333 /*********************************************************************
334 * _findfirst (MSVCRT.@)
336 * Open a handle for iterating through a directory.
339 * fspec [I] File specification of files to iterate.
340 * ft [O] Information for the first file found.
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.
348 * See FindFirstFileA.
350 MSVCRT_intptr_t CDECL
MSVCRT__findfirst(const char * fspec
, struct MSVCRT__finddata_t
* ft
)
352 WIN32_FIND_DATAA find_data
;
355 hfind
= FindFirstFileA(fspec
, &find_data
);
356 if (hfind
== INVALID_HANDLE_VALUE
)
358 msvcrt_set_errno(GetLastError());
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
;
374 hfind
= FindFirstFileA(fspec
, &find_data
);
375 if (hfind
== INVALID_HANDLE_VALUE
)
377 msvcrt_set_errno(GetLastError());
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
;
395 hfind
= FindFirstFileW(fspec
, &find_data
);
396 if (hfind
== INVALID_HANDLE_VALUE
)
398 msvcrt_set_errno(GetLastError());
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
;
416 hfind
= FindFirstFileW(fspec
, &find_data
);
417 if (hfind
== INVALID_HANDLE_VALUE
)
419 msvcrt_set_errno(GetLastError());
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
;
437 hfind
= FindFirstFileA(fspec
, &find_data
);
438 if (hfind
== INVALID_HANDLE_VALUE
)
440 msvcrt_set_errno(GetLastError());
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
;
458 hfind
= FindFirstFileA(fspec
, &find_data
);
459 if (hfind
== INVALID_HANDLE_VALUE
)
461 msvcrt_set_errno(GetLastError());
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
;
479 hfind
= FindFirstFileW(fspec
, &find_data
);
480 if (hfind
== INVALID_HANDLE_VALUE
)
482 msvcrt_set_errno(GetLastError());
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
;
500 hfind
= FindFirstFileA(fspec
, &find_data
);
501 if (hfind
== INVALID_HANDLE_VALUE
)
503 msvcrt_set_errno(GetLastError());
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
;
521 hfind
= FindFirstFileW(fspec
, &find_data
);
522 if (hfind
== INVALID_HANDLE_VALUE
)
524 msvcrt_set_errno(GetLastError());
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
;
542 hfind
= FindFirstFileW(fspec
, &find_data
);
543 if (hfind
== INVALID_HANDLE_VALUE
)
545 msvcrt_set_errno(GetLastError());
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.
559 * hand [I] Handle to the search returned from _findfirst().
560 * ft [O] Information for the file found.
563 * Success: 0. ft is populated with the details of the found file.
564 * Failure: -1. errno indicates the error.
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
;
579 msvcrt_fttofd(&find_data
,ft
);
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
;
596 msvcrt_fttofd32(&find_data
, ft
);
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
;
613 msvcrt_wfttofd32(&find_data
, ft
);
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
;
632 msvcrt_wfttofd(&find_data
,ft
);
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
;
651 msvcrt_fttofdi64(&find_data
,ft
);
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
;
670 msvcrt_fttofd64(&find_data
,ft
);
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
;
689 msvcrt_wfttofd64(&find_data
,ft
);
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
;
708 msvcrt_fttofd64i32(&find_data
,ft
);
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
;
727 msvcrt_wfttofdi64(&find_data
,ft
);
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
;
746 msvcrt_wfttofd64i32(&find_data
,ft
);
750 /*********************************************************************
753 * Get the current working directory.
756 * buf [O] Destination for current working directory.
757 * size [I] Size of buf in characters
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
)
767 int dir_len
= GetCurrentDirectoryA(MAX_PATH
,dir
);
770 return NULL
; /* FIXME: Real return value untested */
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 */
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
);
797 return NULL
; /* FIXME: Real return value untested */
801 if (size
<= dir_len
) size
= dir_len
+ 1;
802 if (!(buf
= MSVCRT_malloc( size
* sizeof(WCHAR
) ))) return NULL
;
806 *MSVCRT__errno() = MSVCRT_ERANGE
;
807 return NULL
; /* buf too small */
809 MSVCRT_wcscpy(buf
,dir
);
813 /*********************************************************************
814 * _getdrive (MSVCRT.@)
816 * Get the current drive number.
822 * Success: The drive letter number from 1 to 26 ("A:" to "Z:").
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;
834 /*********************************************************************
835 * _getdcwd (MSVCRT.@)
837 * Get the current working directory on a given disk.
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.
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
)
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 */
860 char drivespec
[] = {'A', ':', 0};
863 drivespec
[0] += drive
- 1;
864 if (GetDriveTypeA(drivespec
) < DRIVE_REMOVABLE
)
866 *MSVCRT__errno() = MSVCRT_EACCES
;
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
);
879 return MSVCRT__strdup(dir
); /* allocate */
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 */
901 MSVCRT_wchar_t dir
[MAX_PATH
];
902 MSVCRT_wchar_t drivespec
[4] = {'A', ':', '\\', 0};
905 drivespec
[0] += drive
- 1;
906 if (GetDriveTypeW(drivespec
) < DRIVE_REMOVABLE
)
908 *MSVCRT__errno() = MSVCRT_EACCES
;
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
));
921 return MSVCRT__wcsdup(dir
); /* allocate */
922 MSVCRT_wcscpy(buf
,dir
);
927 /*********************************************************************
928 * _getdiskfree (MSVCRT.@)
930 * Get information about the free space on a drive.
933 * disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
934 * info [O] Destination for the resulting information.
937 * Success: 0. info is updated with the free space information.
938 * Failure: An error code from GetLastError().
941 * See GetLastError().
943 unsigned int CDECL
MSVCRT__getdiskfree(unsigned int disk
, struct MSVCRT__diskfree_t
* d
)
945 WCHAR drivespec
[] = {'@', ':', '\\', 0};
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];
962 err
= GetLastError();
963 msvcrt_set_errno(err
);
967 /*********************************************************************
970 * Create a directory.
973 * newdir [I] Name of directory to create.
976 * Success: 0. The directory indicated by newdir is created.
977 * Failure: -1. errno indicates the error.
980 * See CreateDirectoryA.
982 int CDECL
MSVCRT__mkdir(const char * newdir
)
984 if (CreateDirectoryA(newdir
,NULL
))
986 msvcrt_set_errno(GetLastError());
990 /*********************************************************************
993 * Unicode version of _mkdir.
995 int CDECL
MSVCRT__wmkdir(const MSVCRT_wchar_t
* newdir
)
997 if (CreateDirectoryW(newdir
,NULL
))
999 msvcrt_set_errno(GetLastError());
1003 /*********************************************************************
1006 * Delete a directory.
1009 * dir [I] Name of directory to delete.
1012 * Success: 0. The directory indicated by newdir is deleted.
1013 * Failure: -1. errno indicates the error.
1016 * See RemoveDirectoryA.
1018 int CDECL
MSVCRT__rmdir(const char * dir
)
1020 if (RemoveDirectoryA(dir
))
1022 msvcrt_set_errno(GetLastError());
1026 /*********************************************************************
1027 * _wrmdir (MSVCRT.@)
1029 * Unicode version of _rmdir.
1031 int CDECL
MSVCRT__wrmdir(const MSVCRT_wchar_t
* dir
)
1033 if (RemoveDirectoryW(dir
))
1035 msvcrt_set_errno(GetLastError());
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
) ||
1054 (!fname
&& sz_fname
) ||
1055 (fname
&& !sz_fname
) ||
1059 *MSVCRT__errno() = MSVCRT_EINVAL
;
1060 return MSVCRT_EINVAL
;
1063 if (inpath
[0] && inpath
[1] == ':')
1067 if (sz_drive
<= 2) goto do_error
;
1068 drive
[0] = inpath
[0];
1069 drive
[1] = inpath
[1];
1074 else if (drive
) drive
[0] = '\0';
1076 /* look for end of directory part */
1078 for (p
= inpath
; *p
; p
++)
1080 if (_ismbblead((unsigned char)*p
))
1085 if (*p
== '/' || *p
== '\\') end
= p
+ 1;
1088 if (end
) /* got a directory */
1092 if (sz_dir
<= end
- inpath
) goto do_error
;
1093 memcpy( dir
, inpath
, (end
- inpath
) );
1094 dir
[end
- inpath
] = 0;
1098 else if (dir
) dir
[0] = 0;
1100 /* look for extension: what's after the last dot */
1102 for (p
= inpath
; *p
; p
++) if (*p
== '.') end
= p
;
1104 if (!end
) end
= p
; /* there's no extension */
1108 if (sz_fname
<= end
- inpath
) goto do_error
;
1109 memcpy( fname
, inpath
, (end
- inpath
) );
1110 fname
[end
- inpath
] = 0;
1114 if (sz_ext
<= strlen(end
)) goto 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
) ||
1154 (!fname
&& sz_fname
) ||
1155 (fname
&& !sz_fname
) ||
1159 *MSVCRT__errno() = MSVCRT_EINVAL
;
1160 return MSVCRT_EINVAL
;
1163 if (inpath
[0] && inpath
[1] == ':')
1167 if (sz_drive
<= 2) goto do_error
;
1168 drive
[0] = inpath
[0];
1169 drive
[1] = inpath
[1];
1174 else if (drive
) drive
[0] = '\0';
1176 /* look for end of directory part */
1178 for (p
= inpath
; *p
; p
++) if (*p
== '/' || *p
== '\\') end
= p
+ 1;
1180 if (end
) /* got a directory */
1184 if (sz_dir
<= end
- inpath
) goto do_error
;
1185 memcpy( dir
, inpath
, (end
- inpath
) * sizeof(MSVCRT_wchar_t
) );
1186 dir
[end
- inpath
] = 0;
1190 else if (dir
) dir
[0] = 0;
1192 /* look for extension: what's after the last dot */
1194 for (p
= inpath
; *p
; p
++) if (*p
== '.') end
= p
;
1196 if (!end
) end
= p
; /* there's no extension */
1200 if (sz_fname
<= end
- inpath
) goto do_error
;
1201 memcpy( fname
, inpath
, (end
- inpath
) * sizeof(MSVCRT_wchar_t
) );
1202 fname
[end
- inpath
] = 0;
1206 if (sz_ext
<= MSVCRT_wcslen(end
)) goto do_error
;
1207 MSVCRT_wcscpy( ext
, end
);
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
)
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
));
1257 *MSVCRT__errno() = MSVCRT_ERANGE
;
1261 TRACE(":resolving relative path %s\n",debugstr_w(relPath
));
1263 rc
= GetFullPathNameW(relPath
,size
,buffer
,&lastpart
);
1265 if (rc
> 0 && rc
<= size
)
1270 MSVCRT_free(buffer
);
1275 /*********************************************************************
1276 * _fullpath (MSVCRT.@)
1278 * Create an absolute path from a relative path.
1281 * absPath [O] Destination for absolute path
1282 * relPath [I] Relative path to convert to absolute
1283 * size [I] Length of absPath in characters.
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
)
1295 BOOL alloced
= FALSE
;
1297 if (!relPath
|| !*relPath
)
1298 return MSVCRT__getcwd(absPath
, size
);
1300 if (absPath
== NULL
)
1302 buffer
= MSVCRT_malloc(MAX_PATH
);
1311 *MSVCRT__errno() = MSVCRT_ERANGE
;
1315 TRACE(":resolving relative path '%s'\n",relPath
);
1317 rc
= GetFullPathNameA(relPath
,size
,buffer
,&lastpart
);
1319 if (rc
> 0 && rc
<= size
)
1324 MSVCRT_free(buffer
);
1329 /*********************************************************************
1330 * _makepath (MSVCRT.@)
1332 * Create a pathname.
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")
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
)
1351 TRACE("(%s %s %s %s)\n", debugstr_a(drive
), debugstr_a(directory
),
1352 debugstr_a(filename
), debugstr_a(extension
) );
1357 if (drive
&& drive
[0])
1362 if (directory
&& directory
[0])
1364 unsigned int len
= strlen(directory
);
1365 memmove(p
, directory
, len
);
1367 if (p
[-1] != '/' && p
[-1] != '\\')
1370 if (filename
&& filename
[0])
1372 unsigned int len
= strlen(filename
);
1373 memmove(p
, filename
, len
);
1376 if (extension
&& extension
[0])
1378 if (extension
[0] != '.')
1380 strcpy(p
, extension
);
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
));
1403 if (drive
&& drive
[0])
1408 if (directory
&& directory
[0])
1410 unsigned int len
= MSVCRT_wcslen(directory
);
1411 memmove(p
, directory
, len
* sizeof(MSVCRT_wchar_t
));
1413 if (p
[-1] != '/' && p
[-1] != '\\')
1416 if (filename
&& filename
[0])
1418 unsigned int len
= MSVCRT_wcslen(filename
);
1419 memmove(p
, filename
, len
* sizeof(MSVCRT_wchar_t
));
1422 if (extension
&& extension
[0])
1424 if (extension
[0] != '.')
1426 MSVCRT_wcscpy(p
, extension
);
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
)
1447 *MSVCRT__errno() = MSVCRT_EINVAL
;
1448 return MSVCRT_EINVAL
;
1451 if (drive
&& drive
[0])
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
);
1470 memmove(p
, directory
, copylen
);
1478 if (needs_separator
)
1488 if (filename
&& filename
[0])
1490 unsigned int len
= strlen(filename
);
1491 unsigned int copylen
= min(size
- 1, len
);
1496 memmove(p
, filename
, copylen
);
1505 if (extension
&& extension
[0])
1507 unsigned int len
= strlen(extension
);
1508 unsigned int needs_period
= extension
[0] != '.';
1509 unsigned int copylen
;
1520 copylen
= min(size
- 1, len
);
1521 memcpy(p
, extension
, copylen
);
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
;
1551 *MSVCRT__errno() = MSVCRT_EINVAL
;
1552 return MSVCRT_EINVAL
;
1555 if (drive
&& drive
[0])
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
);
1574 memmove(p
, directory
, copylen
* sizeof(MSVCRT_wchar_t
));
1582 if (needs_separator
)
1592 if (filename
&& filename
[0])
1594 unsigned int len
= MSVCRT_wcslen(filename
);
1595 unsigned int copylen
= min(size
- 1, len
);
1600 memmove(p
, filename
, copylen
* sizeof(MSVCRT_wchar_t
));
1609 if (extension
&& extension
[0])
1611 unsigned int len
= MSVCRT_wcslen(extension
);
1612 unsigned int needs_period
= extension
[0] != '.';
1613 unsigned int copylen
;
1624 copylen
= min(size
- 1, len
);
1625 memcpy(p
, extension
, copylen
* sizeof(MSVCRT_wchar_t
));
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
);
1662 if (GetFileAttributesA( file
) != INVALID_FILE_ATTRIBUTES
)
1664 if (GetFullPathNameA( file
, count
, buf
, NULL
)) return 0;
1665 msvcrt_set_errno(GetLastError());
1669 /* Search given environment variable */
1670 envVal
= MSVCRT_getenv(env
);
1673 *MSVCRT__errno() = MSVCRT_ENOENT
;
1674 return MSVCRT_ENOENT
;
1678 TRACE(":searching for %s in paths %s\n", file
, envVal
);
1680 for(; *penv
; penv
= (*end
? end
+ 1 : end
))
1684 while(*end
&& *end
!= ';' && path_len
< MAX_PATH
)
1689 while(*end
&& *end
!= '"' && path_len
< MAX_PATH
)
1691 path
[path_len
++] = *end
;
1694 if (*end
== '"') end
++;
1698 path
[path_len
++] = *end
;
1701 if (!path_len
|| path_len
>= MAX_PATH
)
1704 if (path
[path_len
- 1] != '/' && path
[path_len
- 1] != '\\')
1705 path
[path_len
++] = '\\';
1706 if (path_len
+ fname_len
>= MAX_PATH
)
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);
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
);
1756 if (GetFileAttributesW( file
) != INVALID_FILE_ATTRIBUTES
)
1758 if (GetFullPathNameW( file
, count
, buf
, NULL
)) return 0;
1759 msvcrt_set_errno(GetLastError());
1763 /* Search given environment variable */
1764 envVal
= MSVCRT__wgetenv(env
);
1767 *MSVCRT__errno() = MSVCRT_ENOENT
;
1768 return MSVCRT_ENOENT
;
1772 TRACE(":searching for %s in paths %s\n", debugstr_w(file
), debugstr_w(envVal
));
1774 for(; *penv
; penv
= (*end
? end
+ 1 : end
))
1778 while(*end
&& *end
!= ';' && path_len
< MAX_PATH
)
1783 while(*end
&& *end
!= '"' && path_len
< MAX_PATH
)
1785 path
[path_len
++] = *end
;
1788 if (*end
== '"') end
++;
1792 path
[path_len
++] = *end
;
1795 if (!path_len
|| path_len
>= MAX_PATH
)
1798 if (path
[path_len
- 1] != '/' && path
[path_len
- 1] != '\\')
1799 path
[path_len
++] = '\\';
1800 if (path_len
+ fname_len
>= MAX_PATH
)
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
));
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
);