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
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
36 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata_t */
37 static void msvcrt_fttofd( const WIN32_FIND_DATAA
*fd
, struct MSVCRT__finddata_t
* ft
)
41 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
44 ft
->attrib
= fd
->dwFileAttributes
;
46 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
48 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
50 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
52 ft
->size
= fd
->nFileSizeLow
;
53 strcpy(ft
->name
, fd
->cFileName
);
56 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata32_t */
57 static void msvcrt_fttofd32( const WIN32_FIND_DATAA
*fd
, struct MSVCRT__finddata32_t
* ft
)
61 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
64 ft
->attrib
= fd
->dwFileAttributes
;
66 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
68 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
70 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
72 ft
->size
= fd
->nFileSizeLow
;
73 strcpy(ft
->name
, fd
->cFileName
);
76 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata_t */
77 static void msvcrt_wfttofd( const WIN32_FIND_DATAW
*fd
, struct MSVCRT__wfinddata_t
* ft
)
81 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
84 ft
->attrib
= fd
->dwFileAttributes
;
86 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
88 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
90 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
92 ft
->size
= fd
->nFileSizeLow
;
93 MSVCRT_wcscpy(ft
->name
, fd
->cFileName
);
96 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata32_t */
97 static void msvcrt_wfttofd32(const WIN32_FIND_DATAW
*fd
, struct MSVCRT__wfinddata32_t
* ft
)
101 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
104 ft
->attrib
= fd
->dwFileAttributes
;
106 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
107 ft
->time_create
= dw
;
108 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
109 ft
->time_access
= dw
;
110 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
112 ft
->size
= fd
->nFileSizeLow
;
113 MSVCRT_wcscpy(ft
->name
, fd
->cFileName
);
116 /* INTERNAL: Translate WIN32_FIND_DATAA to finddatai64_t */
117 static void msvcrt_fttofdi64( const WIN32_FIND_DATAA
*fd
, struct MSVCRT__finddatai64_t
* ft
)
121 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
124 ft
->attrib
= fd
->dwFileAttributes
;
126 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
127 ft
->time_create
= dw
;
128 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
129 ft
->time_access
= dw
;
130 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
132 ft
->size
= ((__int64
)fd
->nFileSizeHigh
) << 32 | fd
->nFileSizeLow
;
133 strcpy(ft
->name
, fd
->cFileName
);
136 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata64_t */
137 static void msvcrt_fttofd64( const WIN32_FIND_DATAA
*fd
, struct MSVCRT__finddata64_t
* ft
)
141 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
144 ft
->attrib
= fd
->dwFileAttributes
;
146 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
147 ft
->time_create
= dw
;
148 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
149 ft
->time_access
= dw
;
150 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
152 ft
->size
= ((__int64
)fd
->nFileSizeHigh
) << 32 | fd
->nFileSizeLow
;
153 strcpy(ft
->name
, fd
->cFileName
);
156 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata64_t */
157 static void msvcrt_wfttofd64( const WIN32_FIND_DATAW
*fd
, struct MSVCRT__wfinddata64_t
* ft
)
161 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
164 ft
->attrib
= fd
->dwFileAttributes
;
166 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
167 ft
->time_create
= dw
;
168 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
169 ft
->time_access
= dw
;
170 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
172 ft
->size
= ((__int64
)fd
->nFileSizeHigh
) << 32 | fd
->nFileSizeLow
;
173 MSVCRT_wcscpy(ft
->name
, fd
->cFileName
);
176 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata64i32_t */
177 static void msvcrt_fttofd64i32( const WIN32_FIND_DATAA
*fd
, struct MSVCRT__finddata64i32_t
* ft
)
181 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
184 ft
->attrib
= fd
->dwFileAttributes
;
186 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
187 ft
->time_create
= dw
;
188 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
189 ft
->time_access
= dw
;
190 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
192 ft
->size
= fd
->nFileSizeLow
;
193 strcpy(ft
->name
, fd
->cFileName
);
196 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddatai64_t */
197 static void msvcrt_wfttofdi64( const WIN32_FIND_DATAW
*fd
, struct MSVCRT__wfinddatai64_t
* ft
)
201 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
204 ft
->attrib
= fd
->dwFileAttributes
;
206 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
207 ft
->time_create
= dw
;
208 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
209 ft
->time_access
= dw
;
210 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
212 ft
->size
= ((__int64
)fd
->nFileSizeHigh
) << 32 | fd
->nFileSizeLow
;
213 MSVCRT_wcscpy(ft
->name
, fd
->cFileName
);
216 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata64i32_t */
217 static void msvcrt_wfttofd64i32( const WIN32_FIND_DATAW
*fd
, struct MSVCRT__wfinddata64i32_t
* ft
)
221 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
224 ft
->attrib
= fd
->dwFileAttributes
;
226 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
227 ft
->time_create
= dw
;
228 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
229 ft
->time_access
= dw
;
230 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
232 ft
->size
= fd
->nFileSizeLow
;
233 MSVCRT_wcscpy(ft
->name
, fd
->cFileName
);
236 /*********************************************************************
239 * Change the current working directory.
242 * newdir [I] Directory to change to
245 * Success: 0. The current working directory is set to newdir.
246 * Failure: -1. errno indicates the error.
249 * See SetCurrentDirectoryA.
251 int CDECL
MSVCRT__chdir(const char * newdir
)
253 if (!SetCurrentDirectoryA(newdir
))
255 msvcrt_set_errno(newdir
?GetLastError():0);
261 /*********************************************************************
264 * Unicode version of _chdir.
266 int CDECL
MSVCRT__wchdir(const wchar_t * newdir
)
268 if (!SetCurrentDirectoryW(newdir
))
270 msvcrt_set_errno(newdir
?GetLastError():0);
276 /*********************************************************************
277 * _chdrive (MSVCRT.@)
279 * Change the current drive.
282 * newdrive [I] Drive number to change to (1 = 'A', 2 = 'B', ...)
285 * Success: 0. The current drive is set to newdrive.
286 * Failure: -1. errno indicates the error.
289 * See SetCurrentDirectoryA.
291 int CDECL
MSVCRT__chdrive(int newdrive
)
293 WCHAR buffer
[] = L
"A:";
295 buffer
[0] += newdrive
- 1;
296 if (!SetCurrentDirectoryW( buffer
))
298 msvcrt_set_errno(GetLastError());
306 /*********************************************************************
307 * _findclose (MSVCRT.@)
309 * Close a handle returned by _findfirst().
312 * hand [I] Handle to close
315 * Success: 0. All resources associated with hand are freed.
316 * Failure: -1. errno indicates the error.
321 int CDECL
MSVCRT__findclose(intptr_t hand
)
323 TRACE(":handle %Iu\n",hand
);
324 if (!FindClose((HANDLE
)hand
))
326 msvcrt_set_errno(GetLastError());
332 /*********************************************************************
333 * _findfirst (MSVCRT.@)
335 * Open a handle for iterating through a directory.
338 * fspec [I] File specification of files to iterate.
339 * ft [O] Information for the first file found.
342 * Success: A handle suitable for passing to _findnext() and _findclose().
343 * ft is populated with the details of the found file.
344 * Failure: -1. errno indicates the error.
347 * See FindFirstFileA.
349 intptr_t CDECL
MSVCRT__findfirst(const char * fspec
, struct MSVCRT__finddata_t
* ft
)
351 WIN32_FIND_DATAA find_data
;
354 hfind
= FindFirstFileA(fspec
, &find_data
);
355 if (hfind
== INVALID_HANDLE_VALUE
)
357 msvcrt_set_errno(GetLastError());
360 msvcrt_fttofd(&find_data
,ft
);
361 TRACE(":got handle %p\n",hfind
);
362 return (intptr_t)hfind
;
365 /*********************************************************************
366 * _findfirst32 (MSVCRT.@)
368 intptr_t CDECL
MSVCRT__findfirst32(const char * fspec
, struct MSVCRT__finddata32_t
* ft
)
370 WIN32_FIND_DATAA find_data
;
373 hfind
= FindFirstFileA(fspec
, &find_data
);
374 if (hfind
== INVALID_HANDLE_VALUE
)
376 msvcrt_set_errno(GetLastError());
379 msvcrt_fttofd32(&find_data
, ft
);
380 TRACE(":got handle %p\n", hfind
);
381 return (intptr_t)hfind
;
384 /*********************************************************************
385 * _wfindfirst (MSVCRT.@)
387 * Unicode version of _findfirst.
389 intptr_t CDECL
MSVCRT__wfindfirst(const wchar_t * fspec
, struct MSVCRT__wfinddata_t
* ft
)
391 WIN32_FIND_DATAW find_data
;
394 hfind
= FindFirstFileW(fspec
, &find_data
);
395 if (hfind
== INVALID_HANDLE_VALUE
)
397 msvcrt_set_errno(GetLastError());
400 msvcrt_wfttofd(&find_data
,ft
);
401 TRACE(":got handle %p\n",hfind
);
402 return (intptr_t)hfind
;
405 /*********************************************************************
406 * _wfindfirst32 (MSVCRT.@)
408 * Unicode version of _findfirst32.
410 intptr_t CDECL
MSVCRT__wfindfirst32(const wchar_t * fspec
, struct MSVCRT__wfinddata32_t
* ft
)
412 WIN32_FIND_DATAW find_data
;
415 hfind
= FindFirstFileW(fspec
, &find_data
);
416 if (hfind
== INVALID_HANDLE_VALUE
)
418 msvcrt_set_errno(GetLastError());
421 msvcrt_wfttofd32(&find_data
, ft
);
422 TRACE(":got handle %p\n", hfind
);
423 return (intptr_t)hfind
;
426 /*********************************************************************
427 * _findfirsti64 (MSVCRT.@)
429 * 64-bit version of _findfirst.
431 intptr_t CDECL
MSVCRT__findfirsti64(const char * fspec
, struct MSVCRT__finddatai64_t
* ft
)
433 WIN32_FIND_DATAA find_data
;
436 hfind
= FindFirstFileA(fspec
, &find_data
);
437 if (hfind
== INVALID_HANDLE_VALUE
)
439 msvcrt_set_errno(GetLastError());
442 msvcrt_fttofdi64(&find_data
,ft
);
443 TRACE(":got handle %p\n",hfind
);
444 return (intptr_t)hfind
;
447 /*********************************************************************
448 * _findfirst64 (MSVCRT.@)
450 * 64-bit version of _findfirst.
452 intptr_t CDECL
MSVCRT__findfirst64(const char * fspec
, struct MSVCRT__finddata64_t
* ft
)
454 WIN32_FIND_DATAA find_data
;
457 hfind
= FindFirstFileA(fspec
, &find_data
);
458 if (hfind
== INVALID_HANDLE_VALUE
)
460 msvcrt_set_errno(GetLastError());
463 msvcrt_fttofd64(&find_data
,ft
);
464 TRACE(":got handle %p\n",hfind
);
465 return (intptr_t)hfind
;
468 /*********************************************************************
469 * _wfindfirst64 (MSVCRT.@)
471 * Unicode version of _findfirst64.
473 intptr_t CDECL
MSVCRT__wfindfirst64(const wchar_t * fspec
, struct MSVCRT__wfinddata64_t
* ft
)
475 WIN32_FIND_DATAW find_data
;
478 hfind
= FindFirstFileW(fspec
, &find_data
);
479 if (hfind
== INVALID_HANDLE_VALUE
)
481 msvcrt_set_errno(GetLastError());
484 msvcrt_wfttofd64(&find_data
,ft
);
485 TRACE(":got handle %p\n",hfind
);
486 return (intptr_t)hfind
;
489 /*********************************************************************
490 * _findfirst64i32 (MSVCRT.@)
492 * 64-bit/32-bit version of _findfirst.
494 intptr_t CDECL
MSVCRT__findfirst64i32(const char * fspec
, struct MSVCRT__finddata64i32_t
* ft
)
496 WIN32_FIND_DATAA find_data
;
499 hfind
= FindFirstFileA(fspec
, &find_data
);
500 if (hfind
== INVALID_HANDLE_VALUE
)
502 msvcrt_set_errno(GetLastError());
505 msvcrt_fttofd64i32(&find_data
,ft
);
506 TRACE(":got handle %p\n",hfind
);
507 return (intptr_t)hfind
;
510 /*********************************************************************
511 * _wfindfirst64i32 (MSVCRT.@)
513 * Unicode version of _findfirst64i32.
515 intptr_t CDECL
MSVCRT__wfindfirst64i32(const wchar_t * fspec
, struct MSVCRT__wfinddata64i32_t
* ft
)
517 WIN32_FIND_DATAW find_data
;
520 hfind
= FindFirstFileW(fspec
, &find_data
);
521 if (hfind
== INVALID_HANDLE_VALUE
)
523 msvcrt_set_errno(GetLastError());
526 msvcrt_wfttofd64i32(&find_data
,ft
);
527 TRACE(":got handle %p\n",hfind
);
528 return (intptr_t)hfind
;
531 /*********************************************************************
532 * _wfindfirsti64 (MSVCRT.@)
534 * Unicode version of _findfirsti64.
536 intptr_t CDECL
MSVCRT__wfindfirsti64(const wchar_t * fspec
, struct MSVCRT__wfinddatai64_t
* ft
)
538 WIN32_FIND_DATAW find_data
;
541 hfind
= FindFirstFileW(fspec
, &find_data
);
542 if (hfind
== INVALID_HANDLE_VALUE
)
544 msvcrt_set_errno(GetLastError());
547 msvcrt_wfttofdi64(&find_data
,ft
);
548 TRACE(":got handle %p\n",hfind
);
549 return (intptr_t)hfind
;
552 /*********************************************************************
553 * _findnext (MSVCRT.@)
555 * Find the next file from a file search handle.
558 * hand [I] Handle to the search returned from _findfirst().
559 * ft [O] Information for the file found.
562 * Success: 0. ft is populated with the details of the found file.
563 * Failure: -1. errno indicates the error.
568 int CDECL
MSVCRT__findnext(intptr_t hand
, struct MSVCRT__finddata_t
* ft
)
570 WIN32_FIND_DATAA find_data
;
572 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
578 msvcrt_fttofd(&find_data
,ft
);
582 /*********************************************************************
583 * _findnext32 (MSVCRT.@)
585 int CDECL
MSVCRT__findnext32(intptr_t hand
, struct MSVCRT__finddata32_t
* ft
)
587 WIN32_FIND_DATAA find_data
;
589 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
595 msvcrt_fttofd32(&find_data
, ft
);
599 /*********************************************************************
600 * _wfindnext32 (MSVCRT.@)
602 int CDECL
MSVCRT__wfindnext32(intptr_t hand
, struct MSVCRT__wfinddata32_t
* ft
)
604 WIN32_FIND_DATAW find_data
;
606 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
612 msvcrt_wfttofd32(&find_data
, ft
);
616 /*********************************************************************
617 * _wfindnext (MSVCRT.@)
619 * Unicode version of _findnext.
621 int CDECL
MSVCRT__wfindnext(intptr_t hand
, struct MSVCRT__wfinddata_t
* ft
)
623 WIN32_FIND_DATAW find_data
;
625 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
631 msvcrt_wfttofd(&find_data
,ft
);
635 /*********************************************************************
636 * _findnexti64 (MSVCRT.@)
638 * 64-bit version of _findnext.
640 int CDECL
MSVCRT__findnexti64(intptr_t hand
, struct MSVCRT__finddatai64_t
* ft
)
642 WIN32_FIND_DATAA find_data
;
644 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
650 msvcrt_fttofdi64(&find_data
,ft
);
654 /*********************************************************************
655 * _findnext64 (MSVCRT.@)
657 * 64-bit version of _findnext.
659 int CDECL
MSVCRT__findnext64(intptr_t hand
, struct MSVCRT__finddata64_t
* ft
)
661 WIN32_FIND_DATAA find_data
;
663 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
669 msvcrt_fttofd64(&find_data
,ft
);
673 /*********************************************************************
674 * _wfindnext64 (MSVCRT.@)
676 * Unicode version of _wfindnext64.
678 int CDECL
MSVCRT__wfindnext64(intptr_t hand
, struct MSVCRT__wfinddata64_t
* ft
)
680 WIN32_FIND_DATAW find_data
;
682 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
688 msvcrt_wfttofd64(&find_data
,ft
);
692 /*********************************************************************
693 * _findnext64i32 (MSVCRT.@)
695 * 64-bit/32-bit version of _findnext.
697 int CDECL
MSVCRT__findnext64i32(intptr_t hand
, struct MSVCRT__finddata64i32_t
* ft
)
699 WIN32_FIND_DATAA find_data
;
701 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
707 msvcrt_fttofd64i32(&find_data
,ft
);
711 /*********************************************************************
712 * _wfindnexti64 (MSVCRT.@)
714 * Unicode version of _findnexti64.
716 int CDECL
MSVCRT__wfindnexti64(intptr_t hand
, struct MSVCRT__wfinddatai64_t
* ft
)
718 WIN32_FIND_DATAW find_data
;
720 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
726 msvcrt_wfttofdi64(&find_data
,ft
);
730 /*********************************************************************
731 * _wfindnext64i32 (MSVCRT.@)
733 * Unicode version of _findnext64i32.
735 int CDECL
MSVCRT__wfindnext64i32(intptr_t hand
, struct MSVCRT__wfinddata64i32_t
* ft
)
737 WIN32_FIND_DATAW find_data
;
739 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
745 msvcrt_wfttofd64i32(&find_data
,ft
);
749 /*********************************************************************
752 * Get the current working directory.
755 * buf [O] Destination for current working directory.
756 * size [I] Size of buf in characters
759 * Success: If buf is NULL, returns an allocated string containing the path.
760 * Otherwise populates buf with the path and returns it.
761 * Failure: NULL. errno indicates the error.
763 char* CDECL
MSVCRT__getcwd(char * buf
, int size
)
766 int dir_len
= GetCurrentDirectoryA(MAX_PATH
,dir
);
769 return NULL
; /* FIXME: Real return value untested */
773 if (size
<= dir_len
) size
= dir_len
+ 1;
774 if (!(buf
= malloc( size
))) return NULL
;
776 else if (dir_len
>= size
)
779 return NULL
; /* buf too small */
785 /*********************************************************************
786 * _wgetcwd (MSVCRT.@)
788 * Unicode version of _getcwd.
790 wchar_t* CDECL
MSVCRT__wgetcwd(wchar_t * buf
, int size
)
792 wchar_t dir
[MAX_PATH
];
793 int dir_len
= GetCurrentDirectoryW(MAX_PATH
,dir
);
796 return NULL
; /* FIXME: Real return value untested */
800 if (size
<= dir_len
) size
= dir_len
+ 1;
801 if (!(buf
= malloc( size
* sizeof(WCHAR
) ))) return NULL
;
806 return NULL
; /* buf too small */
808 MSVCRT_wcscpy(buf
,dir
);
812 /*********************************************************************
813 * _getdrive (MSVCRT.@)
815 * Get the current drive number.
821 * Success: The drive letter number from 1 to 26 ("A:" to "Z:").
824 int CDECL
MSVCRT__getdrive(void)
826 WCHAR buffer
[MAX_PATH
];
827 if (GetCurrentDirectoryW( MAX_PATH
, buffer
) &&
828 buffer
[0] >= 'A' && buffer
[0] <= 'z' && buffer
[1] == ':')
829 return MSVCRT_towupper(buffer
[0]) - 'A' + 1;
833 /*********************************************************************
834 * _getdcwd (MSVCRT.@)
836 * Get the current working directory on a given disk.
839 * drive [I] Drive letter to get the current working directory from.
840 * buf [O] Destination for the current working directory.
841 * size [I] Length of drive in characters.
844 * Success: If drive is NULL, returns an allocated string containing the path.
845 * Otherwise populates drive with the path and returns it.
846 * Failure: NULL. errno indicates the error.
848 char* CDECL
MSVCRT__getdcwd(int drive
, char * buf
, int size
)
852 TRACE(":drive %d(%c), size %d\n",drive
, drive
+ 'A' - 1, size
);
854 if (!drive
|| drive
== MSVCRT__getdrive())
855 return MSVCRT__getcwd(buf
,size
); /* current */
859 char drivespec
[] = "A:";
862 drivespec
[0] += drive
- 1;
863 if (GetDriveTypeA(drivespec
) < DRIVE_REMOVABLE
)
869 dir_len
= GetFullPathNameA(drivespec
,MAX_PATH
,dir
,&dummy
);
870 if (dir_len
>= size
|| dir_len
< 1)
873 return NULL
; /* buf too small */
876 TRACE(":returning '%s'\n", dir
);
878 return _strdup(dir
); /* allocate */
885 /*********************************************************************
886 * _wgetdcwd (MSVCRT.@)
888 * Unicode version of _wgetdcwd.
890 wchar_t* CDECL
MSVCRT__wgetdcwd(int drive
, wchar_t * buf
, int size
)
892 static wchar_t* dummy
;
894 TRACE(":drive %d(%c), size %d\n",drive
, drive
+ 'A' - 1, size
);
896 if (!drive
|| drive
== MSVCRT__getdrive())
897 return MSVCRT__wgetcwd(buf
,size
); /* current */
900 wchar_t dir
[MAX_PATH
];
901 wchar_t drivespec
[4] = L
"A:\\";
904 drivespec
[0] += drive
- 1;
905 if (GetDriveTypeW(drivespec
) < DRIVE_REMOVABLE
)
911 dir_len
= GetFullPathNameW(drivespec
,MAX_PATH
,dir
,&dummy
);
912 if (dir_len
>= size
|| dir_len
< 1)
915 return NULL
; /* buf too small */
918 TRACE(":returning %s\n", debugstr_w(dir
));
920 return MSVCRT__wcsdup(dir
); /* allocate */
921 MSVCRT_wcscpy(buf
,dir
);
926 /*********************************************************************
927 * _getdiskfree (MSVCRT.@)
929 * Get information about the free space on a drive.
932 * disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
933 * info [O] Destination for the resulting information.
936 * Success: 0. info is updated with the free space information.
937 * Failure: An error code from GetLastError().
940 * See GetLastError().
942 unsigned int CDECL
MSVCRT__getdiskfree(unsigned int disk
, struct _diskfree_t
* d
)
944 WCHAR drivespec
[] = L
"@:\\";
949 return ERROR_INVALID_PARAMETER
; /* MSVCRT doesn't set errno here */
951 drivespec
[0] += disk
; /* make a drive letter */
953 if (GetDiskFreeSpaceW(disk
==0?NULL
:drivespec
,ret
,ret
+1,ret
+2,ret
+3))
955 d
->sectors_per_cluster
= ret
[0];
956 d
->bytes_per_sector
= ret
[1];
957 d
->avail_clusters
= ret
[2];
958 d
->total_clusters
= ret
[3];
961 err
= GetLastError();
962 msvcrt_set_errno(err
);
966 /*********************************************************************
969 * Create a directory.
972 * newdir [I] Name of directory to create.
975 * Success: 0. The directory indicated by newdir is created.
976 * Failure: -1. errno indicates the error.
979 * See CreateDirectoryA.
981 int CDECL
MSVCRT__mkdir(const char * newdir
)
983 if (CreateDirectoryA(newdir
,NULL
))
985 msvcrt_set_errno(GetLastError());
989 /*********************************************************************
992 * Unicode version of _mkdir.
994 int CDECL
MSVCRT__wmkdir(const wchar_t* newdir
)
996 if (CreateDirectoryW(newdir
,NULL
))
998 msvcrt_set_errno(GetLastError());
1002 /*********************************************************************
1005 * Delete a directory.
1008 * dir [I] Name of directory to delete.
1011 * Success: 0. The directory indicated by newdir is deleted.
1012 * Failure: -1. errno indicates the error.
1015 * See RemoveDirectoryA.
1017 int CDECL
MSVCRT__rmdir(const char * dir
)
1019 if (RemoveDirectoryA(dir
))
1021 msvcrt_set_errno(GetLastError());
1025 /*********************************************************************
1026 * _wrmdir (MSVCRT.@)
1028 * Unicode version of _rmdir.
1030 int CDECL
MSVCRT__wrmdir(const wchar_t * dir
)
1032 if (RemoveDirectoryW(dir
))
1034 msvcrt_set_errno(GetLastError());
1038 /******************************************************************
1039 * _splitpath_s (MSVCRT.@)
1041 int CDECL
MSVCRT__splitpath_s(const char* inpath
,
1042 char* drive
, size_t sz_drive
,
1043 char* dir
, size_t sz_dir
,
1044 char* fname
, size_t sz_fname
,
1045 char* ext
, size_t sz_ext
)
1047 const char *p
, *end
;
1049 if (!inpath
|| (!drive
&& sz_drive
) ||
1050 (drive
&& !sz_drive
) ||
1053 (!fname
&& sz_fname
) ||
1054 (fname
&& !sz_fname
) ||
1062 if (inpath
[0] && inpath
[1] == ':')
1066 if (sz_drive
<= 2) goto do_error
;
1067 drive
[0] = inpath
[0];
1068 drive
[1] = inpath
[1];
1073 else if (drive
) drive
[0] = '\0';
1075 /* look for end of directory part */
1077 for (p
= inpath
; *p
; p
++)
1079 if (_ismbblead((unsigned char)*p
))
1084 if (*p
== '/' || *p
== '\\') end
= p
+ 1;
1087 if (end
) /* got a directory */
1091 if (sz_dir
<= end
- inpath
) goto do_error
;
1092 memcpy( dir
, inpath
, (end
- inpath
) );
1093 dir
[end
- inpath
] = 0;
1097 else if (dir
) dir
[0] = 0;
1099 /* look for extension: what's after the last dot */
1101 for (p
= inpath
; *p
; p
++) if (*p
== '.') end
= p
;
1103 if (!end
) end
= p
; /* there's no extension */
1107 if (sz_fname
<= end
- inpath
) goto do_error
;
1108 memcpy( fname
, inpath
, (end
- inpath
) );
1109 fname
[end
- inpath
] = 0;
1113 if (sz_ext
<= strlen(end
)) goto do_error
;
1118 if (drive
) drive
[0] = '\0';
1119 if (dir
) dir
[0] = '\0';
1120 if (fname
) fname
[0]= '\0';
1121 if (ext
) ext
[0]= '\0';
1126 /*********************************************************************
1127 * _splitpath (MSVCRT.@)
1129 void CDECL
MSVCRT__splitpath(const char *inpath
, char *drv
, char *dir
,
1130 char *fname
, char *ext
)
1132 MSVCRT__splitpath_s(inpath
, drv
, drv
? _MAX_DRIVE
: 0, dir
, dir
? _MAX_DIR
: 0,
1133 fname
, fname
? _MAX_FNAME
: 0, ext
, ext
? _MAX_EXT
: 0);
1136 /******************************************************************
1137 * _wsplitpath_s (MSVCRT.@)
1139 * Secure version of _wsplitpath
1141 int CDECL
MSVCRT__wsplitpath_s(const wchar_t* inpath
,
1142 wchar_t* drive
, size_t sz_drive
,
1143 wchar_t* dir
, size_t sz_dir
,
1144 wchar_t* fname
, size_t sz_fname
,
1145 wchar_t* ext
, size_t sz_ext
)
1147 const wchar_t *p
, *end
;
1149 if (!inpath
|| (!drive
&& sz_drive
) ||
1150 (drive
&& !sz_drive
) ||
1153 (!fname
&& sz_fname
) ||
1154 (fname
&& !sz_fname
) ||
1162 if (inpath
[0] && inpath
[1] == ':')
1166 if (sz_drive
<= 2) goto do_error
;
1167 drive
[0] = inpath
[0];
1168 drive
[1] = inpath
[1];
1173 else if (drive
) drive
[0] = '\0';
1175 /* look for end of directory part */
1177 for (p
= inpath
; *p
; p
++) if (*p
== '/' || *p
== '\\') end
= p
+ 1;
1179 if (end
) /* got a directory */
1183 if (sz_dir
<= end
- inpath
) goto do_error
;
1184 memcpy( dir
, inpath
, (end
- inpath
) * sizeof(wchar_t) );
1185 dir
[end
- inpath
] = 0;
1189 else if (dir
) dir
[0] = 0;
1191 /* look for extension: what's after the last dot */
1193 for (p
= inpath
; *p
; p
++) if (*p
== '.') end
= p
;
1195 if (!end
) end
= p
; /* there's no extension */
1199 if (sz_fname
<= end
- inpath
) goto do_error
;
1200 memcpy( fname
, inpath
, (end
- inpath
) * sizeof(wchar_t) );
1201 fname
[end
- inpath
] = 0;
1205 if (sz_ext
<= MSVCRT_wcslen(end
)) goto do_error
;
1206 MSVCRT_wcscpy( ext
, end
);
1210 if (drive
) drive
[0] = '\0';
1211 if (dir
) dir
[0] = '\0';
1212 if (fname
) fname
[0]= '\0';
1213 if (ext
) ext
[0]= '\0';
1218 /*********************************************************************
1219 * _wsplitpath (MSVCRT.@)
1221 * Unicode version of _splitpath.
1223 void CDECL
MSVCRT__wsplitpath(const wchar_t *inpath
, wchar_t *drv
, wchar_t *dir
,
1224 wchar_t *fname
, wchar_t *ext
)
1226 MSVCRT__wsplitpath_s(inpath
, drv
, drv
? _MAX_DRIVE
: 0, dir
, dir
? _MAX_DIR
: 0,
1227 fname
, fname
? _MAX_FNAME
: 0, ext
, ext
? _MAX_EXT
: 0);
1230 /*********************************************************************
1231 * _wfullpath (MSVCRT.@)
1233 * Unicode version of _fullpath.
1235 wchar_t * CDECL
MSVCRT__wfullpath(wchar_t * absPath
, const wchar_t* relPath
, size_t size
)
1240 BOOL alloced
= FALSE
;
1242 if (!relPath
|| !*relPath
)
1243 return MSVCRT__wgetcwd(absPath
, size
);
1245 if (absPath
== NULL
)
1247 buffer
= malloc(MAX_PATH
* sizeof(WCHAR
));
1260 TRACE(":resolving relative path %s\n",debugstr_w(relPath
));
1262 rc
= GetFullPathNameW(relPath
,size
,buffer
,&lastpart
);
1264 if (rc
> 0 && rc
<= size
)
1274 /*********************************************************************
1275 * _fullpath (MSVCRT.@)
1277 * Create an absolute path from a relative path.
1280 * absPath [O] Destination for absolute path
1281 * relPath [I] Relative path to convert to absolute
1282 * size [I] Length of absPath in characters.
1285 * Success: If absPath is NULL, returns an allocated string containing the path.
1286 * Otherwise populates absPath with the path and returns it.
1287 * Failure: NULL. errno indicates the error.
1289 char * CDECL
MSVCRT__fullpath(char * absPath
, const char* relPath
, unsigned int size
)
1294 BOOL alloced
= FALSE
;
1296 if (!relPath
|| !*relPath
)
1297 return MSVCRT__getcwd(absPath
, size
);
1299 if (absPath
== NULL
)
1301 buffer
= malloc(MAX_PATH
);
1314 TRACE(":resolving relative path '%s'\n",relPath
);
1316 rc
= GetFullPathNameA(relPath
,size
,buffer
,&lastpart
);
1318 if (rc
> 0 && rc
<= size
)
1328 /*********************************************************************
1329 * _makepath (MSVCRT.@)
1331 * Create a pathname.
1334 * path [O] Destination for created pathname
1335 * drive [I] Drive letter (e.g. "A:")
1336 * directory [I] Directory
1337 * filename [I] Name of the file, excluding extension
1338 * extension [I] File extension (e.g. ".TXT")
1341 * Nothing. If path is not large enough to hold the resulting pathname,
1342 * random process memory will be overwritten.
1344 VOID CDECL
MSVCRT__makepath(char * path
, const char * drive
,
1345 const char *directory
, const char * filename
,
1346 const char * extension
)
1350 TRACE("(%s %s %s %s)\n", debugstr_a(drive
), debugstr_a(directory
),
1351 debugstr_a(filename
), debugstr_a(extension
) );
1356 if (drive
&& drive
[0])
1361 if (directory
&& directory
[0])
1363 unsigned int len
= strlen(directory
);
1364 memmove(p
, directory
, len
);
1366 if (p
[-1] != '/' && p
[-1] != '\\')
1369 if (filename
&& filename
[0])
1371 unsigned int len
= strlen(filename
);
1372 memmove(p
, filename
, len
);
1375 if (extension
&& extension
[0])
1377 if (extension
[0] != '.')
1379 strcpy(p
, extension
);
1383 TRACE("returning %s\n",path
);
1386 /*********************************************************************
1387 * _wmakepath (MSVCRT.@)
1389 * Unicode version of _wmakepath.
1391 VOID CDECL
MSVCRT__wmakepath(wchar_t *path
, const wchar_t *drive
, const wchar_t *directory
,
1392 const wchar_t *filename
, const wchar_t *extension
)
1396 TRACE("%s %s %s %s\n", debugstr_w(drive
), debugstr_w(directory
),
1397 debugstr_w(filename
), debugstr_w(extension
));
1402 if (drive
&& drive
[0])
1407 if (directory
&& directory
[0])
1409 unsigned int len
= MSVCRT_wcslen(directory
);
1410 memmove(p
, directory
, len
* sizeof(wchar_t));
1412 if (p
[-1] != '/' && p
[-1] != '\\')
1415 if (filename
&& filename
[0])
1417 unsigned int len
= MSVCRT_wcslen(filename
);
1418 memmove(p
, filename
, len
* sizeof(wchar_t));
1421 if (extension
&& extension
[0])
1423 if (extension
[0] != '.')
1425 MSVCRT_wcscpy(p
, extension
);
1430 TRACE("returning %s\n", debugstr_w(path
));
1433 /*********************************************************************
1434 * _makepath_s (MSVCRT.@)
1436 * Safe version of _makepath.
1438 int CDECL
MSVCRT__makepath_s(char *path
, size_t size
, const char *drive
,
1439 const char *directory
, const char *filename
,
1440 const char *extension
)
1450 if (drive
&& drive
[0])
1460 if (directory
&& directory
[0])
1462 unsigned int len
= strlen(directory
);
1463 unsigned int needs_separator
= directory
[len
- 1] != '/' && directory
[len
- 1] != '\\';
1464 unsigned int copylen
= min(size
- 1, len
);
1469 memmove(p
, directory
, copylen
);
1477 if (needs_separator
)
1487 if (filename
&& filename
[0])
1489 unsigned int len
= strlen(filename
);
1490 unsigned int copylen
= min(size
- 1, len
);
1495 memmove(p
, filename
, copylen
);
1504 if (extension
&& extension
[0])
1506 unsigned int len
= strlen(extension
);
1507 unsigned int needs_period
= extension
[0] != '.';
1508 unsigned int copylen
;
1519 copylen
= min(size
- 1, len
);
1520 memcpy(p
, extension
, copylen
);
1537 /*********************************************************************
1538 * _wmakepath_s (MSVCRT.@)
1540 * Safe version of _wmakepath.
1542 int CDECL
MSVCRT__wmakepath_s(wchar_t *path
, size_t size
, const wchar_t *drive
,
1543 const wchar_t *directory
, const wchar_t *filename
,
1544 const wchar_t *extension
)
1554 if (drive
&& drive
[0])
1564 if (directory
&& directory
[0])
1566 unsigned int len
= MSVCRT_wcslen(directory
);
1567 unsigned int needs_separator
= directory
[len
- 1] != '/' && directory
[len
- 1] != '\\';
1568 unsigned int copylen
= min(size
- 1, len
);
1573 memmove(p
, directory
, copylen
* sizeof(wchar_t));
1581 if (needs_separator
)
1591 if (filename
&& filename
[0])
1593 unsigned int len
= MSVCRT_wcslen(filename
);
1594 unsigned int copylen
= min(size
- 1, len
);
1599 memmove(p
, filename
, copylen
* sizeof(wchar_t));
1608 if (extension
&& extension
[0])
1610 unsigned int len
= MSVCRT_wcslen(extension
);
1611 unsigned int needs_period
= extension
[0] != '.';
1612 unsigned int copylen
;
1623 copylen
= min(size
- 1, len
);
1624 memcpy(p
, extension
, copylen
* sizeof(wchar_t));
1641 /*********************************************************************
1642 * _searchenv_s (MSVCRT.@)
1644 int CDECL
MSVCRT__searchenv_s(const char* file
, const char* env
, char *buf
, size_t count
)
1646 char *envVal
, *penv
, *end
;
1647 char path
[MAX_PATH
];
1648 size_t path_len
, fname_len
;
1650 if (!MSVCRT_CHECK_PMT(file
!= NULL
)) return EINVAL
;
1651 if (!MSVCRT_CHECK_PMT(buf
!= NULL
)) return EINVAL
;
1652 if (!MSVCRT_CHECK_PMT(count
> 0)) return EINVAL
;
1654 if (count
> MAX_PATH
)
1655 FIXME("count > MAX_PATH not supported\n");
1657 fname_len
= strlen(file
);
1661 if (GetFileAttributesA( file
) != INVALID_FILE_ATTRIBUTES
)
1663 if (GetFullPathNameA( file
, count
, buf
, NULL
)) return 0;
1664 msvcrt_set_errno(GetLastError());
1668 /* Search given environment variable */
1669 envVal
= getenv(env
);
1677 TRACE(":searching for %s in paths %s\n", file
, envVal
);
1679 for(; *penv
; penv
= (*end
? end
+ 1 : end
))
1683 while(*end
&& *end
!= ';' && path_len
< MAX_PATH
)
1688 while(*end
&& *end
!= '"' && path_len
< MAX_PATH
)
1690 path
[path_len
++] = *end
;
1693 if (*end
== '"') end
++;
1697 path
[path_len
++] = *end
;
1700 if (!path_len
|| path_len
>= MAX_PATH
)
1703 if (path
[path_len
- 1] != '/' && path
[path_len
- 1] != '\\')
1704 path
[path_len
++] = '\\';
1705 if (path_len
+ fname_len
>= MAX_PATH
)
1708 memcpy(path
+ path_len
, file
, fname_len
+ 1);
1709 TRACE("Checking for file %s\n", path
);
1710 if (GetFileAttributesA( path
) != INVALID_FILE_ATTRIBUTES
)
1712 if (path_len
+ fname_len
+ 1 > count
)
1714 MSVCRT_INVALID_PMT("buf[count] is too small", ERANGE
);
1717 memcpy(buf
, path
, path_len
+ fname_len
+ 1);
1726 /*********************************************************************
1727 * _searchenv (MSVCRT.@)
1729 void CDECL
MSVCRT__searchenv(const char* file
, const char* env
, char *buf
)
1731 MSVCRT__searchenv_s(file
, env
, buf
, MAX_PATH
);
1734 /*********************************************************************
1735 * _wsearchenv_s (MSVCRT.@)
1737 int CDECL
MSVCRT__wsearchenv_s(const wchar_t* file
, const wchar_t* env
,
1738 wchar_t *buf
, size_t count
)
1740 wchar_t *envVal
, *penv
, *end
;
1741 wchar_t path
[MAX_PATH
];
1742 size_t path_len
, fname_len
;
1744 if (!MSVCRT_CHECK_PMT(file
!= NULL
)) return EINVAL
;
1745 if (!MSVCRT_CHECK_PMT(buf
!= NULL
)) return EINVAL
;
1746 if (!MSVCRT_CHECK_PMT(count
> 0)) return EINVAL
;
1748 if (count
> MAX_PATH
)
1749 FIXME("count > MAX_PATH not supported\n");
1751 fname_len
= MSVCRT_wcslen(file
);
1755 if (GetFileAttributesW( file
) != INVALID_FILE_ATTRIBUTES
)
1757 if (GetFullPathNameW( file
, count
, buf
, NULL
)) return 0;
1758 msvcrt_set_errno(GetLastError());
1762 /* Search given environment variable */
1763 envVal
= _wgetenv(env
);
1771 TRACE(":searching for %s in paths %s\n", debugstr_w(file
), debugstr_w(envVal
));
1773 for(; *penv
; penv
= (*end
? end
+ 1 : end
))
1777 while(*end
&& *end
!= ';' && path_len
< MAX_PATH
)
1782 while(*end
&& *end
!= '"' && path_len
< MAX_PATH
)
1784 path
[path_len
++] = *end
;
1787 if (*end
== '"') end
++;
1791 path
[path_len
++] = *end
;
1794 if (!path_len
|| path_len
>= MAX_PATH
)
1797 if (path
[path_len
- 1] != '/' && path
[path_len
- 1] != '\\')
1798 path
[path_len
++] = '\\';
1799 if (path_len
+ fname_len
>= MAX_PATH
)
1802 memcpy(path
+ path_len
, file
, (fname_len
+ 1) * sizeof(wchar_t));
1803 TRACE("Checking for file %s\n", debugstr_w(path
));
1804 if (GetFileAttributesW( path
) != INVALID_FILE_ATTRIBUTES
)
1806 if (path_len
+ fname_len
+ 1 > count
)
1808 MSVCRT_INVALID_PMT("buf[count] is too small", ERANGE
);
1811 memcpy(buf
, path
, (path_len
+ fname_len
+ 1) * sizeof(wchar_t));
1820 /*********************************************************************
1821 * _wsearchenv (MSVCRT.@)
1823 void CDECL
MSVCRT__wsearchenv(const wchar_t* file
, const wchar_t* env
, wchar_t *buf
)
1825 MSVCRT__wsearchenv_s(file
, env
, buf
, MAX_PATH
);