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 <corecrt_io.h>
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
44 #undef _wfindfirst64i32
46 #undef _wfindnext64i32
55 #undef _findfirst64i32
60 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata_t */
61 static void msvcrt_fttofd( const WIN32_FIND_DATAA
*fd
, struct _finddata_t
* ft
)
65 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
68 ft
->attrib
= fd
->dwFileAttributes
;
70 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
72 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
74 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
76 ft
->size
= fd
->nFileSizeLow
;
77 strcpy(ft
->name
, fd
->cFileName
);
80 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata32_t */
81 static void msvcrt_fttofd32( const WIN32_FIND_DATAA
*fd
, struct _finddata32_t
* ft
)
85 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
88 ft
->attrib
= fd
->dwFileAttributes
;
90 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
92 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
94 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
96 ft
->size
= fd
->nFileSizeLow
;
97 strcpy(ft
->name
, fd
->cFileName
);
100 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata_t */
101 static void msvcrt_wfttofd( const WIN32_FIND_DATAW
*fd
, struct _wfinddata_t
* ft
)
105 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
108 ft
->attrib
= fd
->dwFileAttributes
;
110 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
111 ft
->time_create
= dw
;
112 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
113 ft
->time_access
= dw
;
114 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
116 ft
->size
= fd
->nFileSizeLow
;
117 wcscpy(ft
->name
, fd
->cFileName
);
120 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata32_t */
121 static void msvcrt_wfttofd32(const WIN32_FIND_DATAW
*fd
, struct _wfinddata32_t
* ft
)
125 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
128 ft
->attrib
= fd
->dwFileAttributes
;
130 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
131 ft
->time_create
= dw
;
132 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
133 ft
->time_access
= dw
;
134 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
136 ft
->size
= fd
->nFileSizeLow
;
137 wcscpy(ft
->name
, fd
->cFileName
);
140 /* INTERNAL: Translate WIN32_FIND_DATAA to finddatai64_t */
141 static void msvcrt_fttofdi64( const WIN32_FIND_DATAA
*fd
, struct _finddatai64_t
* ft
)
145 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
148 ft
->attrib
= fd
->dwFileAttributes
;
150 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
151 ft
->time_create
= dw
;
152 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
153 ft
->time_access
= dw
;
154 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
156 ft
->size
= ((__int64
)fd
->nFileSizeHigh
) << 32 | fd
->nFileSizeLow
;
157 strcpy(ft
->name
, fd
->cFileName
);
160 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata64_t */
161 static void msvcrt_fttofd64( const WIN32_FIND_DATAA
*fd
, struct _finddata64_t
* ft
)
165 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
168 ft
->attrib
= fd
->dwFileAttributes
;
170 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
171 ft
->time_create
= dw
;
172 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
173 ft
->time_access
= dw
;
174 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
176 ft
->size
= ((__int64
)fd
->nFileSizeHigh
) << 32 | fd
->nFileSizeLow
;
177 strcpy(ft
->name
, fd
->cFileName
);
180 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata64_t */
181 static void msvcrt_wfttofd64( const WIN32_FIND_DATAW
*fd
, struct _wfinddata64_t
* ft
)
185 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
188 ft
->attrib
= fd
->dwFileAttributes
;
190 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
191 ft
->time_create
= dw
;
192 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
193 ft
->time_access
= dw
;
194 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
196 ft
->size
= ((__int64
)fd
->nFileSizeHigh
) << 32 | fd
->nFileSizeLow
;
197 wcscpy(ft
->name
, fd
->cFileName
);
200 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata64i32_t */
201 static void msvcrt_fttofd64i32( const WIN32_FIND_DATAA
*fd
, struct _finddata64i32_t
* ft
)
205 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
208 ft
->attrib
= fd
->dwFileAttributes
;
210 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
211 ft
->time_create
= dw
;
212 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
213 ft
->time_access
= dw
;
214 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
216 ft
->size
= fd
->nFileSizeLow
;
217 strcpy(ft
->name
, fd
->cFileName
);
220 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddatai64_t */
221 static void msvcrt_wfttofdi64( const WIN32_FIND_DATAW
*fd
, struct _wfinddatai64_t
* ft
)
225 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
228 ft
->attrib
= fd
->dwFileAttributes
;
230 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
231 ft
->time_create
= dw
;
232 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
233 ft
->time_access
= dw
;
234 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
236 ft
->size
= ((__int64
)fd
->nFileSizeHigh
) << 32 | fd
->nFileSizeLow
;
237 wcscpy(ft
->name
, fd
->cFileName
);
240 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata64i32_t */
241 static void msvcrt_wfttofd64i32( const WIN32_FIND_DATAW
*fd
, struct _wfinddata64i32_t
* ft
)
245 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
248 ft
->attrib
= fd
->dwFileAttributes
;
250 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
251 ft
->time_create
= dw
;
252 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
253 ft
->time_access
= dw
;
254 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
256 ft
->size
= fd
->nFileSizeLow
;
257 wcscpy(ft
->name
, fd
->cFileName
);
260 /*********************************************************************
263 * Change the current working directory.
266 * newdir [I] Directory to change to
269 * Success: 0. The current working directory is set to newdir.
270 * Failure: -1. errno indicates the error.
273 * See SetCurrentDirectoryA.
275 int CDECL
_chdir(const char * newdir
)
277 if (!SetCurrentDirectoryA(newdir
))
279 msvcrt_set_errno(newdir
?GetLastError():0);
285 /*********************************************************************
288 * Unicode version of _chdir.
290 int CDECL
_wchdir(const wchar_t * newdir
)
292 if (!SetCurrentDirectoryW(newdir
))
294 msvcrt_set_errno(newdir
?GetLastError():0);
300 /*********************************************************************
301 * _chdrive (MSVCRT.@)
303 * Change the current drive.
306 * newdrive [I] Drive number to change to (1 = 'A', 2 = 'B', ...)
309 * Success: 0. The current drive is set to newdrive.
310 * Failure: -1. errno indicates the error.
313 * See SetCurrentDirectoryA.
315 int CDECL
_chdrive(int newdrive
)
317 WCHAR buffer
[] = L
"A:";
319 buffer
[0] += newdrive
- 1;
320 if (!SetCurrentDirectoryW( buffer
))
322 msvcrt_set_errno(GetLastError());
330 /*********************************************************************
331 * _findclose (MSVCRT.@)
333 * Close a handle returned by _findfirst().
336 * hand [I] Handle to close
339 * Success: 0. All resources associated with hand are freed.
340 * Failure: -1. errno indicates the error.
345 int CDECL
_findclose(intptr_t hand
)
347 TRACE(":handle %Iu\n",hand
);
348 if (!FindClose((HANDLE
)hand
))
350 msvcrt_set_errno(GetLastError());
356 /*********************************************************************
357 * _findfirst (MSVCRT.@)
359 * Open a handle for iterating through a directory.
362 * fspec [I] File specification of files to iterate.
363 * ft [O] Information for the first file found.
366 * Success: A handle suitable for passing to _findnext() and _findclose().
367 * ft is populated with the details of the found file.
368 * Failure: -1. errno indicates the error.
371 * See FindFirstFileA.
373 intptr_t CDECL
_findfirst(const char * fspec
, struct _finddata_t
* ft
)
375 WIN32_FIND_DATAA find_data
;
378 hfind
= FindFirstFileA(fspec
, &find_data
);
379 if (hfind
== INVALID_HANDLE_VALUE
)
381 msvcrt_set_errno(GetLastError());
384 msvcrt_fttofd(&find_data
,ft
);
385 TRACE(":got handle %p\n",hfind
);
386 return (intptr_t)hfind
;
389 /*********************************************************************
390 * _findfirst32 (MSVCRT.@)
392 intptr_t CDECL
_findfirst32(const char * fspec
, struct _finddata32_t
* ft
)
394 WIN32_FIND_DATAA find_data
;
397 hfind
= FindFirstFileA(fspec
, &find_data
);
398 if (hfind
== INVALID_HANDLE_VALUE
)
400 msvcrt_set_errno(GetLastError());
403 msvcrt_fttofd32(&find_data
, ft
);
404 TRACE(":got handle %p\n", hfind
);
405 return (intptr_t)hfind
;
408 /*********************************************************************
409 * _wfindfirst (MSVCRT.@)
411 * Unicode version of _findfirst.
413 intptr_t CDECL
_wfindfirst(const wchar_t * fspec
, struct _wfinddata_t
* ft
)
415 WIN32_FIND_DATAW find_data
;
418 hfind
= FindFirstFileW(fspec
, &find_data
);
419 if (hfind
== INVALID_HANDLE_VALUE
)
421 msvcrt_set_errno(GetLastError());
424 msvcrt_wfttofd(&find_data
,ft
);
425 TRACE(":got handle %p\n",hfind
);
426 return (intptr_t)hfind
;
429 /*********************************************************************
430 * _wfindfirst32 (MSVCRT.@)
432 * Unicode version of _findfirst32.
434 intptr_t CDECL
_wfindfirst32(const wchar_t * fspec
, struct _wfinddata32_t
* ft
)
436 WIN32_FIND_DATAW find_data
;
439 hfind
= FindFirstFileW(fspec
, &find_data
);
440 if (hfind
== INVALID_HANDLE_VALUE
)
442 msvcrt_set_errno(GetLastError());
445 msvcrt_wfttofd32(&find_data
, ft
);
446 TRACE(":got handle %p\n", hfind
);
447 return (intptr_t)hfind
;
450 /*********************************************************************
451 * _findfirsti64 (MSVCRT.@)
453 * 64-bit version of _findfirst.
455 intptr_t CDECL
_findfirsti64(const char * fspec
, struct _finddatai64_t
* ft
)
457 WIN32_FIND_DATAA find_data
;
460 hfind
= FindFirstFileA(fspec
, &find_data
);
461 if (hfind
== INVALID_HANDLE_VALUE
)
463 msvcrt_set_errno(GetLastError());
466 msvcrt_fttofdi64(&find_data
,ft
);
467 TRACE(":got handle %p\n",hfind
);
468 return (intptr_t)hfind
;
471 /*********************************************************************
472 * _findfirst64 (MSVCRT.@)
474 * 64-bit version of _findfirst.
476 intptr_t CDECL
_findfirst64(const char * fspec
, struct _finddata64_t
* ft
)
478 WIN32_FIND_DATAA find_data
;
481 hfind
= FindFirstFileA(fspec
, &find_data
);
482 if (hfind
== INVALID_HANDLE_VALUE
)
484 msvcrt_set_errno(GetLastError());
487 msvcrt_fttofd64(&find_data
,ft
);
488 TRACE(":got handle %p\n",hfind
);
489 return (intptr_t)hfind
;
492 /*********************************************************************
493 * _wfindfirst64 (MSVCRT.@)
495 * Unicode version of _findfirst64.
497 intptr_t CDECL
_wfindfirst64(const wchar_t * fspec
, struct _wfinddata64_t
* ft
)
499 WIN32_FIND_DATAW find_data
;
502 hfind
= FindFirstFileW(fspec
, &find_data
);
503 if (hfind
== INVALID_HANDLE_VALUE
)
505 msvcrt_set_errno(GetLastError());
508 msvcrt_wfttofd64(&find_data
,ft
);
509 TRACE(":got handle %p\n",hfind
);
510 return (intptr_t)hfind
;
513 /*********************************************************************
514 * _findfirst64i32 (MSVCRT.@)
516 * 64-bit/32-bit version of _findfirst.
518 intptr_t CDECL
_findfirst64i32(const char * fspec
, struct _finddata64i32_t
* ft
)
520 WIN32_FIND_DATAA find_data
;
523 hfind
= FindFirstFileA(fspec
, &find_data
);
524 if (hfind
== INVALID_HANDLE_VALUE
)
526 msvcrt_set_errno(GetLastError());
529 msvcrt_fttofd64i32(&find_data
,ft
);
530 TRACE(":got handle %p\n",hfind
);
531 return (intptr_t)hfind
;
534 /*********************************************************************
535 * _wfindfirst64i32 (MSVCRT.@)
537 * Unicode version of _findfirst64i32.
539 intptr_t CDECL
_wfindfirst64i32(const wchar_t * fspec
, struct _wfinddata64i32_t
* ft
)
541 WIN32_FIND_DATAW find_data
;
544 hfind
= FindFirstFileW(fspec
, &find_data
);
545 if (hfind
== INVALID_HANDLE_VALUE
)
547 msvcrt_set_errno(GetLastError());
550 msvcrt_wfttofd64i32(&find_data
,ft
);
551 TRACE(":got handle %p\n",hfind
);
552 return (intptr_t)hfind
;
555 /*********************************************************************
556 * _wfindfirsti64 (MSVCRT.@)
558 * Unicode version of _findfirsti64.
560 intptr_t CDECL
_wfindfirsti64(const wchar_t * fspec
, struct _wfinddatai64_t
* ft
)
562 WIN32_FIND_DATAW find_data
;
565 hfind
= FindFirstFileW(fspec
, &find_data
);
566 if (hfind
== INVALID_HANDLE_VALUE
)
568 msvcrt_set_errno(GetLastError());
571 msvcrt_wfttofdi64(&find_data
,ft
);
572 TRACE(":got handle %p\n",hfind
);
573 return (intptr_t)hfind
;
576 /*********************************************************************
577 * _findnext (MSVCRT.@)
579 * Find the next file from a file search handle.
582 * hand [I] Handle to the search returned from _findfirst().
583 * ft [O] Information for the file found.
586 * Success: 0. ft is populated with the details of the found file.
587 * Failure: -1. errno indicates the error.
592 int CDECL
_findnext(intptr_t hand
, struct _finddata_t
* ft
)
594 WIN32_FIND_DATAA find_data
;
596 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
602 msvcrt_fttofd(&find_data
,ft
);
606 /*********************************************************************
607 * _findnext32 (MSVCRT.@)
609 int CDECL
_findnext32(intptr_t hand
, struct _finddata32_t
* ft
)
611 WIN32_FIND_DATAA find_data
;
613 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
619 msvcrt_fttofd32(&find_data
, ft
);
623 /*********************************************************************
624 * _wfindnext32 (MSVCRT.@)
626 int CDECL
_wfindnext32(intptr_t hand
, struct _wfinddata32_t
* ft
)
628 WIN32_FIND_DATAW find_data
;
630 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
636 msvcrt_wfttofd32(&find_data
, ft
);
640 /*********************************************************************
641 * _wfindnext (MSVCRT.@)
643 * Unicode version of _findnext.
645 int CDECL
_wfindnext(intptr_t hand
, struct _wfinddata_t
* ft
)
647 WIN32_FIND_DATAW find_data
;
649 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
655 msvcrt_wfttofd(&find_data
,ft
);
659 /*********************************************************************
660 * _findnexti64 (MSVCRT.@)
662 * 64-bit version of _findnext.
664 int CDECL
_findnexti64(intptr_t hand
, struct _finddatai64_t
* ft
)
666 WIN32_FIND_DATAA find_data
;
668 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
674 msvcrt_fttofdi64(&find_data
,ft
);
678 /*********************************************************************
679 * _findnext64 (MSVCRT.@)
681 * 64-bit version of _findnext.
683 int CDECL
_findnext64(intptr_t hand
, struct _finddata64_t
* ft
)
685 WIN32_FIND_DATAA find_data
;
687 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
693 msvcrt_fttofd64(&find_data
,ft
);
697 /*********************************************************************
698 * _wfindnext64 (MSVCRT.@)
700 * Unicode version of _wfindnext64.
702 int CDECL
_wfindnext64(intptr_t hand
, struct _wfinddata64_t
* ft
)
704 WIN32_FIND_DATAW find_data
;
706 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
712 msvcrt_wfttofd64(&find_data
,ft
);
716 /*********************************************************************
717 * _findnext64i32 (MSVCRT.@)
719 * 64-bit/32-bit version of _findnext.
721 int CDECL
_findnext64i32(intptr_t hand
, struct _finddata64i32_t
* ft
)
723 WIN32_FIND_DATAA find_data
;
725 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
731 msvcrt_fttofd64i32(&find_data
,ft
);
735 /*********************************************************************
736 * _wfindnexti64 (MSVCRT.@)
738 * Unicode version of _findnexti64.
740 int CDECL
_wfindnexti64(intptr_t hand
, struct _wfinddatai64_t
* ft
)
742 WIN32_FIND_DATAW find_data
;
744 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
750 msvcrt_wfttofdi64(&find_data
,ft
);
754 /*********************************************************************
755 * _wfindnext64i32 (MSVCRT.@)
757 * Unicode version of _findnext64i32.
759 int CDECL
_wfindnext64i32(intptr_t hand
, struct _wfinddata64i32_t
* ft
)
761 WIN32_FIND_DATAW find_data
;
763 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
769 msvcrt_wfttofd64i32(&find_data
,ft
);
773 /*********************************************************************
776 * Get the current working directory.
779 * buf [O] Destination for current working directory.
780 * size [I] Size of buf in characters
783 * Success: If buf is NULL, returns an allocated string containing the path.
784 * Otherwise populates buf with the path and returns it.
785 * Failure: NULL. errno indicates the error.
787 char* CDECL
_getcwd(char * buf
, int size
)
790 int dir_len
= GetCurrentDirectoryA(MAX_PATH
,dir
);
793 return NULL
; /* FIXME: Real return value untested */
797 if (size
<= dir_len
) size
= dir_len
+ 1;
798 if (!(buf
= malloc( size
))) return NULL
;
800 else if (dir_len
>= size
)
803 return NULL
; /* buf too small */
809 /*********************************************************************
810 * _wgetcwd (MSVCRT.@)
812 * Unicode version of _getcwd.
814 wchar_t* CDECL
_wgetcwd(wchar_t * buf
, int size
)
816 wchar_t dir
[MAX_PATH
];
817 int dir_len
= GetCurrentDirectoryW(MAX_PATH
,dir
);
820 return NULL
; /* FIXME: Real return value untested */
824 if (size
<= dir_len
) size
= dir_len
+ 1;
825 if (!(buf
= malloc( size
* sizeof(WCHAR
) ))) return NULL
;
827 else if (dir_len
>= size
)
830 return NULL
; /* buf too small */
836 /*********************************************************************
837 * _getdrive (MSVCRT.@)
839 * Get the current drive number.
845 * Success: The drive letter number from 1 to 26 ("A:" to "Z:").
848 int CDECL
_getdrive(void)
850 WCHAR buffer
[MAX_PATH
];
851 if (GetCurrentDirectoryW( MAX_PATH
, buffer
) &&
852 buffer
[0] >= 'A' && buffer
[0] <= 'z' && buffer
[1] == ':')
853 return towupper(buffer
[0]) - 'A' + 1;
857 /*********************************************************************
858 * _getdcwd (MSVCRT.@)
860 * Get the current working directory on a given disk.
863 * drive [I] Drive letter to get the current working directory from.
864 * buf [O] Destination for the current working directory.
865 * size [I] Length of drive in characters.
868 * Success: If drive is NULL, returns an allocated string containing the path.
869 * Otherwise populates drive with the path and returns it.
870 * Failure: NULL. errno indicates the error.
872 char* CDECL
_getdcwd(int drive
, char * buf
, int size
)
876 TRACE(":drive %d(%c), size %d\n",drive
, drive
+ 'A' - 1, size
);
878 if (!drive
|| drive
== _getdrive())
879 return _getcwd(buf
,size
); /* current */
883 char drivespec
[] = "A:";
886 drivespec
[0] += drive
- 1;
887 if (GetDriveTypeA(drivespec
) < DRIVE_REMOVABLE
)
893 dir_len
= GetFullPathNameA(drivespec
,MAX_PATH
,dir
,&dummy
);
894 if (dir_len
>= size
|| dir_len
< 1)
897 return NULL
; /* buf too small */
900 TRACE(":returning '%s'\n", dir
);
902 return _strdup(dir
); /* allocate */
909 /*********************************************************************
910 * _wgetdcwd (MSVCRT.@)
912 * Unicode version of _wgetdcwd.
914 wchar_t* CDECL
_wgetdcwd(int drive
, wchar_t * buf
, int size
)
916 static wchar_t* dummy
;
918 TRACE(":drive %d(%c), size %d\n",drive
, drive
+ 'A' - 1, size
);
920 if (!drive
|| drive
== _getdrive())
921 return _wgetcwd(buf
,size
); /* current */
924 wchar_t dir
[MAX_PATH
];
925 wchar_t drivespec
[4] = L
"A:\\";
928 drivespec
[0] += drive
- 1;
929 if (GetDriveTypeW(drivespec
) < DRIVE_REMOVABLE
)
935 dir_len
= GetFullPathNameW(drivespec
,MAX_PATH
,dir
,&dummy
);
936 if (dir_len
>= size
|| dir_len
< 1)
939 return NULL
; /* buf too small */
942 TRACE(":returning %s\n", debugstr_w(dir
));
944 return _wcsdup(dir
); /* allocate */
950 /*********************************************************************
951 * _getdiskfree (MSVCRT.@)
953 * Get information about the free space on a drive.
956 * disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
957 * info [O] Destination for the resulting information.
960 * Success: 0. info is updated with the free space information.
961 * Failure: An error code from GetLastError().
964 * See GetLastError().
966 unsigned int CDECL
_getdiskfree(unsigned int disk
, struct _diskfree_t
* d
)
968 WCHAR drivespec
[] = L
"@:\\";
973 return ERROR_INVALID_PARAMETER
; /* MSVCRT doesn't set errno here */
975 drivespec
[0] += disk
; /* make a drive letter */
977 if (GetDiskFreeSpaceW(disk
==0?NULL
:drivespec
,ret
,ret
+1,ret
+2,ret
+3))
979 d
->sectors_per_cluster
= ret
[0];
980 d
->bytes_per_sector
= ret
[1];
981 d
->avail_clusters
= ret
[2];
982 d
->total_clusters
= ret
[3];
985 err
= GetLastError();
986 msvcrt_set_errno(err
);
990 /*********************************************************************
993 * Create a directory.
996 * newdir [I] Name of directory to create.
999 * Success: 0. The directory indicated by newdir is created.
1000 * Failure: -1. errno indicates the error.
1003 * See CreateDirectoryA.
1005 int CDECL
_mkdir(const char * newdir
)
1007 if (CreateDirectoryA(newdir
,NULL
))
1009 msvcrt_set_errno(GetLastError());
1013 /*********************************************************************
1014 * _wmkdir (MSVCRT.@)
1016 * Unicode version of _mkdir.
1018 int CDECL
_wmkdir(const wchar_t* newdir
)
1020 if (CreateDirectoryW(newdir
,NULL
))
1022 msvcrt_set_errno(GetLastError());
1026 /*********************************************************************
1029 * Delete a directory.
1032 * dir [I] Name of directory to delete.
1035 * Success: 0. The directory indicated by newdir is deleted.
1036 * Failure: -1. errno indicates the error.
1039 * See RemoveDirectoryA.
1041 int CDECL
_rmdir(const char * dir
)
1043 if (RemoveDirectoryA(dir
))
1045 msvcrt_set_errno(GetLastError());
1049 /*********************************************************************
1050 * _wrmdir (MSVCRT.@)
1052 * Unicode version of _rmdir.
1054 int CDECL
_wrmdir(const wchar_t * dir
)
1056 if (RemoveDirectoryW(dir
))
1058 msvcrt_set_errno(GetLastError());
1062 /******************************************************************
1063 * _splitpath_s (MSVCRT.@)
1065 errno_t CDECL
_splitpath_s(const char* inpath
,
1066 char* drive
, size_t sz_drive
,
1067 char* dir
, size_t sz_dir
,
1068 char* fname
, size_t sz_fname
,
1069 char* ext
, size_t sz_ext
)
1071 const char *p
, *end
;
1073 if (!inpath
|| (!drive
&& sz_drive
) ||
1074 (drive
&& !sz_drive
) ||
1077 (!fname
&& sz_fname
) ||
1078 (fname
&& !sz_fname
) ||
1086 if (inpath
[0] && inpath
[1] == ':')
1090 if (sz_drive
<= 2) goto do_error
;
1091 drive
[0] = inpath
[0];
1092 drive
[1] = inpath
[1];
1097 else if (drive
) drive
[0] = '\0';
1099 /* look for end of directory part */
1101 for (p
= inpath
; *p
; p
++)
1103 if (_ismbblead((unsigned char)*p
))
1108 if (*p
== '/' || *p
== '\\') end
= p
+ 1;
1111 if (end
) /* got a directory */
1115 if (sz_dir
<= end
- inpath
) goto do_error
;
1116 memcpy( dir
, inpath
, (end
- inpath
) );
1117 dir
[end
- inpath
] = 0;
1121 else if (dir
) dir
[0] = 0;
1123 /* look for extension: what's after the last dot */
1125 for (p
= inpath
; *p
; p
++) if (*p
== '.') end
= p
;
1127 if (!end
) end
= p
; /* there's no extension */
1131 if (sz_fname
<= end
- inpath
) goto do_error
;
1132 memcpy( fname
, inpath
, (end
- inpath
) );
1133 fname
[end
- inpath
] = 0;
1137 if (sz_ext
<= strlen(end
)) goto do_error
;
1142 if (drive
) drive
[0] = '\0';
1143 if (dir
) dir
[0] = '\0';
1144 if (fname
) fname
[0]= '\0';
1145 if (ext
) ext
[0]= '\0';
1150 /*********************************************************************
1151 * _splitpath (MSVCRT.@)
1153 void CDECL
_splitpath(const char *inpath
, char *drv
, char *dir
,
1154 char *fname
, char *ext
)
1156 _splitpath_s(inpath
, drv
, drv
? _MAX_DRIVE
: 0, dir
, dir
? _MAX_DIR
: 0,
1157 fname
, fname
? _MAX_FNAME
: 0, ext
, ext
? _MAX_EXT
: 0);
1160 /******************************************************************
1161 * _wsplitpath_s (MSVCRT.@)
1163 * Secure version of _wsplitpath
1165 int CDECL
_wsplitpath_s(const wchar_t* inpath
,
1166 wchar_t* drive
, size_t sz_drive
,
1167 wchar_t* dir
, size_t sz_dir
,
1168 wchar_t* fname
, size_t sz_fname
,
1169 wchar_t* ext
, size_t sz_ext
)
1171 const wchar_t *p
, *end
;
1173 if (!inpath
|| (!drive
&& sz_drive
) ||
1174 (drive
&& !sz_drive
) ||
1177 (!fname
&& sz_fname
) ||
1178 (fname
&& !sz_fname
) ||
1186 if (inpath
[0] && inpath
[1] == ':')
1190 if (sz_drive
<= 2) goto do_error
;
1191 drive
[0] = inpath
[0];
1192 drive
[1] = inpath
[1];
1197 else if (drive
) drive
[0] = '\0';
1199 /* look for end of directory part */
1201 for (p
= inpath
; *p
; p
++) if (*p
== '/' || *p
== '\\') end
= p
+ 1;
1203 if (end
) /* got a directory */
1207 if (sz_dir
<= end
- inpath
) goto do_error
;
1208 memcpy( dir
, inpath
, (end
- inpath
) * sizeof(wchar_t) );
1209 dir
[end
- inpath
] = 0;
1213 else if (dir
) dir
[0] = 0;
1215 /* look for extension: what's after the last dot */
1217 for (p
= inpath
; *p
; p
++) if (*p
== '.') end
= p
;
1219 if (!end
) end
= p
; /* there's no extension */
1223 if (sz_fname
<= end
- inpath
) goto do_error
;
1224 memcpy( fname
, inpath
, (end
- inpath
) * sizeof(wchar_t) );
1225 fname
[end
- inpath
] = 0;
1229 if (sz_ext
<= wcslen(end
)) goto do_error
;
1234 if (drive
) drive
[0] = '\0';
1235 if (dir
) dir
[0] = '\0';
1236 if (fname
) fname
[0]= '\0';
1237 if (ext
) ext
[0]= '\0';
1242 /*********************************************************************
1243 * _wsplitpath (MSVCRT.@)
1245 * Unicode version of _splitpath.
1247 void CDECL
_wsplitpath(const wchar_t *inpath
, wchar_t *drv
, wchar_t *dir
,
1248 wchar_t *fname
, wchar_t *ext
)
1250 _wsplitpath_s(inpath
, drv
, drv
? _MAX_DRIVE
: 0, dir
, dir
? _MAX_DIR
: 0,
1251 fname
, fname
? _MAX_FNAME
: 0, ext
, ext
? _MAX_EXT
: 0);
1254 /*********************************************************************
1255 * _wfullpath (MSVCRT.@)
1257 * Unicode version of _fullpath.
1259 wchar_t * CDECL
_wfullpath(wchar_t * absPath
, const wchar_t* relPath
, size_t size
)
1264 BOOL alloced
= FALSE
;
1266 if (!relPath
|| !*relPath
)
1267 return _wgetcwd(absPath
, size
);
1269 if (absPath
== NULL
)
1271 buffer
= malloc(MAX_PATH
* sizeof(WCHAR
));
1284 TRACE(":resolving relative path %s\n",debugstr_w(relPath
));
1286 rc
= GetFullPathNameW(relPath
,size
,buffer
,&lastpart
);
1288 if (rc
> 0 && rc
<= size
)
1298 /*********************************************************************
1299 * _fullpath (MSVCRT.@)
1301 * Create an absolute path from a relative path.
1304 * absPath [O] Destination for absolute path
1305 * relPath [I] Relative path to convert to absolute
1306 * size [I] Length of absPath in characters.
1309 * Success: If absPath is NULL, returns an allocated string containing the path.
1310 * Otherwise populates absPath with the path and returns it.
1311 * Failure: NULL. errno indicates the error.
1313 char * CDECL
_fullpath(char * absPath
, const char* relPath
, size_t size
)
1318 BOOL alloced
= FALSE
;
1320 if (!relPath
|| !*relPath
)
1321 return _getcwd(absPath
, size
);
1323 if (absPath
== NULL
)
1325 buffer
= malloc(MAX_PATH
);
1338 TRACE(":resolving relative path '%s'\n",relPath
);
1340 rc
= GetFullPathNameA(relPath
,size
,buffer
,&lastpart
);
1342 if (rc
> 0 && rc
<= size
)
1352 /*********************************************************************
1353 * _makepath (MSVCRT.@)
1355 * Create a pathname.
1358 * path [O] Destination for created pathname
1359 * drive [I] Drive letter (e.g. "A:")
1360 * directory [I] Directory
1361 * filename [I] Name of the file, excluding extension
1362 * extension [I] File extension (e.g. ".TXT")
1365 * Nothing. If path is not large enough to hold the resulting pathname,
1366 * random process memory will be overwritten.
1368 VOID CDECL
_makepath(char * path
, const char * drive
,
1369 const char *directory
, const char * filename
,
1370 const char * extension
)
1374 TRACE("(%s %s %s %s)\n", debugstr_a(drive
), debugstr_a(directory
),
1375 debugstr_a(filename
), debugstr_a(extension
) );
1380 if (drive
&& drive
[0])
1385 if (directory
&& directory
[0])
1387 unsigned int len
= strlen(directory
);
1388 memmove(p
, directory
, len
);
1390 if (p
[-1] != '/' && p
[-1] != '\\')
1393 if (filename
&& filename
[0])
1395 unsigned int len
= strlen(filename
);
1396 memmove(p
, filename
, len
);
1399 if (extension
&& extension
[0])
1401 if (extension
[0] != '.')
1403 strcpy(p
, extension
);
1407 TRACE("returning %s\n",path
);
1410 /*********************************************************************
1411 * _wmakepath (MSVCRT.@)
1413 * Unicode version of _wmakepath.
1415 VOID CDECL
_wmakepath(wchar_t *path
, const wchar_t *drive
, const wchar_t *directory
,
1416 const wchar_t *filename
, const wchar_t *extension
)
1420 TRACE("%s %s %s %s\n", debugstr_w(drive
), debugstr_w(directory
),
1421 debugstr_w(filename
), debugstr_w(extension
));
1426 if (drive
&& drive
[0])
1431 if (directory
&& directory
[0])
1433 unsigned int len
= wcslen(directory
);
1434 memmove(p
, directory
, len
* sizeof(wchar_t));
1436 if (p
[-1] != '/' && p
[-1] != '\\')
1439 if (filename
&& filename
[0])
1441 unsigned int len
= wcslen(filename
);
1442 memmove(p
, filename
, len
* sizeof(wchar_t));
1445 if (extension
&& extension
[0])
1447 if (extension
[0] != '.')
1449 wcscpy(p
, extension
);
1454 TRACE("returning %s\n", debugstr_w(path
));
1457 /*********************************************************************
1458 * _makepath_s (MSVCRT.@)
1460 * Safe version of _makepath.
1462 int CDECL
_makepath_s(char *path
, size_t size
, const char *drive
,
1463 const char *directory
, const char *filename
,
1464 const char *extension
)
1474 if (drive
&& drive
[0])
1484 if (directory
&& directory
[0])
1486 unsigned int len
= strlen(directory
);
1487 unsigned int needs_separator
= directory
[len
- 1] != '/' && directory
[len
- 1] != '\\';
1488 unsigned int copylen
= min(size
- 1, len
);
1493 memmove(p
, directory
, copylen
);
1501 if (needs_separator
)
1511 if (filename
&& filename
[0])
1513 unsigned int len
= strlen(filename
);
1514 unsigned int copylen
= min(size
- 1, len
);
1519 memmove(p
, filename
, copylen
);
1528 if (extension
&& extension
[0])
1530 unsigned int len
= strlen(extension
);
1531 unsigned int needs_period
= extension
[0] != '.';
1532 unsigned int copylen
;
1543 copylen
= min(size
- 1, len
);
1544 memcpy(p
, extension
, copylen
);
1561 /*********************************************************************
1562 * _wmakepath_s (MSVCRT.@)
1564 * Safe version of _wmakepath.
1566 int CDECL
_wmakepath_s(wchar_t *path
, size_t size
, const wchar_t *drive
,
1567 const wchar_t *directory
, const wchar_t *filename
,
1568 const wchar_t *extension
)
1578 if (drive
&& drive
[0])
1588 if (directory
&& directory
[0])
1590 unsigned int len
= wcslen(directory
);
1591 unsigned int needs_separator
= directory
[len
- 1] != '/' && directory
[len
- 1] != '\\';
1592 unsigned int copylen
= min(size
- 1, len
);
1597 memmove(p
, directory
, copylen
* sizeof(wchar_t));
1605 if (needs_separator
)
1615 if (filename
&& filename
[0])
1617 unsigned int len
= wcslen(filename
);
1618 unsigned int copylen
= min(size
- 1, len
);
1623 memmove(p
, filename
, copylen
* sizeof(wchar_t));
1632 if (extension
&& extension
[0])
1634 unsigned int len
= wcslen(extension
);
1635 unsigned int needs_period
= extension
[0] != '.';
1636 unsigned int copylen
;
1647 copylen
= min(size
- 1, len
);
1648 memcpy(p
, extension
, copylen
* sizeof(wchar_t));
1665 /*********************************************************************
1666 * _searchenv_s (MSVCRT.@)
1668 int CDECL
_searchenv_s(const char* file
, const char* env
, char *buf
, size_t count
)
1670 char *envVal
, *penv
, *end
;
1671 char path
[MAX_PATH
];
1672 size_t path_len
, fname_len
;
1674 if (!MSVCRT_CHECK_PMT(file
!= NULL
)) return EINVAL
;
1675 if (!MSVCRT_CHECK_PMT(buf
!= NULL
)) return EINVAL
;
1676 if (!MSVCRT_CHECK_PMT(count
> 0)) return EINVAL
;
1678 if (count
> MAX_PATH
)
1679 FIXME("count > MAX_PATH not supported\n");
1681 fname_len
= strlen(file
);
1685 if (GetFileAttributesA( file
) != INVALID_FILE_ATTRIBUTES
)
1687 if (GetFullPathNameA( file
, count
, buf
, NULL
)) return 0;
1688 msvcrt_set_errno(GetLastError());
1692 /* Search given environment variable */
1693 envVal
= getenv(env
);
1701 TRACE(":searching for %s in paths %s\n", file
, envVal
);
1703 for(; *penv
; penv
= (*end
? end
+ 1 : end
))
1707 while(*end
&& *end
!= ';' && path_len
< MAX_PATH
)
1712 while(*end
&& *end
!= '"' && path_len
< MAX_PATH
)
1714 path
[path_len
++] = *end
;
1717 if (*end
== '"') end
++;
1721 path
[path_len
++] = *end
;
1724 if (!path_len
|| path_len
>= MAX_PATH
)
1727 if (path
[path_len
- 1] != '/' && path
[path_len
- 1] != '\\')
1728 path
[path_len
++] = '\\';
1729 if (path_len
+ fname_len
>= MAX_PATH
)
1732 memcpy(path
+ path_len
, file
, fname_len
+ 1);
1733 TRACE("Checking for file %s\n", path
);
1734 if (GetFileAttributesA( path
) != INVALID_FILE_ATTRIBUTES
)
1736 if (path_len
+ fname_len
+ 1 > count
)
1738 MSVCRT_INVALID_PMT("buf[count] is too small", ERANGE
);
1741 memcpy(buf
, path
, path_len
+ fname_len
+ 1);
1750 /*********************************************************************
1751 * _searchenv (MSVCRT.@)
1753 void CDECL
_searchenv(const char* file
, const char* env
, char *buf
)
1755 _searchenv_s(file
, env
, buf
, MAX_PATH
);
1758 /*********************************************************************
1759 * _wsearchenv_s (MSVCRT.@)
1761 int CDECL
_wsearchenv_s(const wchar_t* file
, const wchar_t* env
,
1762 wchar_t *buf
, size_t count
)
1764 wchar_t *envVal
, *penv
, *end
;
1765 wchar_t path
[MAX_PATH
];
1766 size_t path_len
, fname_len
;
1768 if (!MSVCRT_CHECK_PMT(file
!= NULL
)) return EINVAL
;
1769 if (!MSVCRT_CHECK_PMT(buf
!= NULL
)) return EINVAL
;
1770 if (!MSVCRT_CHECK_PMT(count
> 0)) return EINVAL
;
1772 if (count
> MAX_PATH
)
1773 FIXME("count > MAX_PATH not supported\n");
1775 fname_len
= wcslen(file
);
1779 if (GetFileAttributesW( file
) != INVALID_FILE_ATTRIBUTES
)
1781 if (GetFullPathNameW( file
, count
, buf
, NULL
)) return 0;
1782 msvcrt_set_errno(GetLastError());
1786 /* Search given environment variable */
1787 envVal
= _wgetenv(env
);
1795 TRACE(":searching for %s in paths %s\n", debugstr_w(file
), debugstr_w(envVal
));
1797 for(; *penv
; penv
= (*end
? end
+ 1 : end
))
1801 while(*end
&& *end
!= ';' && path_len
< MAX_PATH
)
1806 while(*end
&& *end
!= '"' && path_len
< MAX_PATH
)
1808 path
[path_len
++] = *end
;
1811 if (*end
== '"') end
++;
1815 path
[path_len
++] = *end
;
1818 if (!path_len
|| path_len
>= MAX_PATH
)
1821 if (path
[path_len
- 1] != '/' && path
[path_len
- 1] != '\\')
1822 path
[path_len
++] = '\\';
1823 if (path_len
+ fname_len
>= MAX_PATH
)
1826 memcpy(path
+ path_len
, file
, (fname_len
+ 1) * sizeof(wchar_t));
1827 TRACE("Checking for file %s\n", debugstr_w(path
));
1828 if (GetFileAttributesW( path
) != INVALID_FILE_ATTRIBUTES
)
1830 if (path_len
+ fname_len
+ 1 > count
)
1832 MSVCRT_INVALID_PMT("buf[count] is too small", ERANGE
);
1835 memcpy(buf
, path
, (path_len
+ fname_len
+ 1) * sizeof(wchar_t));
1844 /*********************************************************************
1845 * _wsearchenv (MSVCRT.@)
1847 void CDECL
_wsearchenv(const wchar_t* file
, const wchar_t* env
, wchar_t *buf
)
1849 _wsearchenv_s(file
, env
, buf
, MAX_PATH
);