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/unicode.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
39 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata_t */
40 static void msvcrt_fttofd( const WIN32_FIND_DATAA
*fd
, struct MSVCRT__finddata_t
* ft
)
44 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
47 ft
->attrib
= fd
->dwFileAttributes
;
49 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
51 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
53 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
55 ft
->size
= fd
->nFileSizeLow
;
56 strcpy(ft
->name
, fd
->cFileName
);
59 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata_t */
60 static void msvcrt_wfttofd( const WIN32_FIND_DATAW
*fd
, struct MSVCRT__wfinddata_t
* ft
)
64 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
67 ft
->attrib
= fd
->dwFileAttributes
;
69 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
71 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
73 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
75 ft
->size
= fd
->nFileSizeLow
;
76 strcpyW(ft
->name
, fd
->cFileName
);
79 /* INTERNAL: Translate WIN32_FIND_DATAA to finddatai64_t */
80 static void msvcrt_fttofdi64( const WIN32_FIND_DATAA
*fd
, struct MSVCRT__finddatai64_t
* ft
)
84 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
87 ft
->attrib
= fd
->dwFileAttributes
;
89 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
91 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
93 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
95 ft
->size
= ((__int64
)fd
->nFileSizeHigh
) << 32 | fd
->nFileSizeLow
;
96 strcpy(ft
->name
, fd
->cFileName
);
99 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata64_t */
100 static void msvcrt_fttofd64( const WIN32_FIND_DATAA
*fd
, struct MSVCRT__finddata64_t
* ft
)
104 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
107 ft
->attrib
= fd
->dwFileAttributes
;
109 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
110 ft
->time_create
= dw
;
111 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
112 ft
->time_access
= dw
;
113 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
115 ft
->size
= ((__int64
)fd
->nFileSizeHigh
) << 32 | fd
->nFileSizeLow
;
116 strcpy(ft
->name
, fd
->cFileName
);
119 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata64i32_t */
120 static void msvcrt_fttofd64i32( const WIN32_FIND_DATAA
*fd
, struct MSVCRT__finddata64i32_t
* ft
)
124 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
127 ft
->attrib
= fd
->dwFileAttributes
;
129 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
130 ft
->time_create
= dw
;
131 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
132 ft
->time_access
= dw
;
133 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
135 ft
->size
= fd
->nFileSizeLow
;
136 strcpy(ft
->name
, fd
->cFileName
);
139 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddatai64_t */
140 static void msvcrt_wfttofdi64( const WIN32_FIND_DATAW
*fd
, struct MSVCRT__wfinddatai64_t
* ft
)
144 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
147 ft
->attrib
= fd
->dwFileAttributes
;
149 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
150 ft
->time_create
= dw
;
151 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
152 ft
->time_access
= dw
;
153 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
155 ft
->size
= ((__int64
)fd
->nFileSizeHigh
) << 32 | fd
->nFileSizeLow
;
156 strcpyW(ft
->name
, fd
->cFileName
);
159 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata64i32_t */
160 static void msvcrt_wfttofd64i32( const WIN32_FIND_DATAW
*fd
, struct MSVCRT__wfinddata64i32_t
* ft
)
164 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
167 ft
->attrib
= fd
->dwFileAttributes
;
169 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
170 ft
->time_create
= dw
;
171 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
172 ft
->time_access
= dw
;
173 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
175 ft
->size
= fd
->nFileSizeLow
;
176 strcpyW(ft
->name
, fd
->cFileName
);
179 /*********************************************************************
182 * Change the current working directory.
185 * newdir [I] Directory to change to
188 * Success: 0. The current working directory is set to newdir.
189 * Failure: -1. errno indicates the error.
192 * See SetCurrentDirectoryA.
194 int CDECL
MSVCRT__chdir(const char * newdir
)
196 if (!SetCurrentDirectoryA(newdir
))
198 msvcrt_set_errno(newdir
?GetLastError():0);
204 /*********************************************************************
207 * Unicode version of _chdir.
209 int CDECL
_wchdir(const MSVCRT_wchar_t
* newdir
)
211 if (!SetCurrentDirectoryW(newdir
))
213 msvcrt_set_errno(newdir
?GetLastError():0);
219 /*********************************************************************
220 * _chdrive (MSVCRT.@)
222 * Change the current drive.
225 * newdrive [I] Drive number to change to (1 = 'A', 2 = 'B', ...)
228 * Success: 0. The current drive is set to newdrive.
229 * Failure: -1. errno indicates the error.
232 * See SetCurrentDirectoryA.
234 int CDECL
_chdrive(int newdrive
)
236 WCHAR buffer
[3] = {'A', ':', 0};
238 buffer
[0] += newdrive
- 1;
239 if (!SetCurrentDirectoryW( buffer
))
241 msvcrt_set_errno(GetLastError());
243 *MSVCRT__errno() = MSVCRT_EACCES
;
249 /*********************************************************************
250 * _findclose (MSVCRT.@)
252 * Close a handle returned by _findfirst().
255 * hand [I] Handle to close
258 * Success: 0. All resources associated with hand are freed.
259 * Failure: -1. errno indicates the error.
264 int CDECL
MSVCRT__findclose(MSVCRT_intptr_t hand
)
266 TRACE(":handle %ld\n",hand
);
267 if (!FindClose((HANDLE
)hand
))
269 msvcrt_set_errno(GetLastError());
275 /*********************************************************************
276 * _findfirst (MSVCRT.@)
278 * Open a handle for iterating through a directory.
281 * fspec [I] File specification of files to iterate.
282 * ft [O] Information for the first file found.
285 * Success: A handle suitable for passing to _findnext() and _findclose().
286 * ft is populated with the details of the found file.
287 * Failure: -1. errno indicates the error.
290 * See FindFirstFileA.
292 MSVCRT_intptr_t CDECL
MSVCRT__findfirst(const char * fspec
, struct MSVCRT__finddata_t
* ft
)
294 WIN32_FIND_DATAA find_data
;
297 hfind
= FindFirstFileA(fspec
, &find_data
);
298 if (hfind
== INVALID_HANDLE_VALUE
)
300 msvcrt_set_errno(GetLastError());
303 msvcrt_fttofd(&find_data
,ft
);
304 TRACE(":got handle %p\n",hfind
);
305 return (MSVCRT_intptr_t
)hfind
;
308 /*********************************************************************
309 * _wfindfirst (MSVCRT.@)
311 * Unicode version of _findfirst.
313 MSVCRT_intptr_t CDECL
MSVCRT__wfindfirst(const MSVCRT_wchar_t
* fspec
, struct MSVCRT__wfinddata_t
* ft
)
315 WIN32_FIND_DATAW find_data
;
318 hfind
= FindFirstFileW(fspec
, &find_data
);
319 if (hfind
== INVALID_HANDLE_VALUE
)
321 msvcrt_set_errno(GetLastError());
324 msvcrt_wfttofd(&find_data
,ft
);
325 TRACE(":got handle %p\n",hfind
);
326 return (MSVCRT_intptr_t
)hfind
;
329 /*********************************************************************
330 * _findfirsti64 (MSVCRT.@)
332 * 64-bit version of _findfirst.
334 MSVCRT_intptr_t CDECL
MSVCRT__findfirsti64(const char * fspec
, struct MSVCRT__finddatai64_t
* ft
)
336 WIN32_FIND_DATAA find_data
;
339 hfind
= FindFirstFileA(fspec
, &find_data
);
340 if (hfind
== INVALID_HANDLE_VALUE
)
342 msvcrt_set_errno(GetLastError());
345 msvcrt_fttofdi64(&find_data
,ft
);
346 TRACE(":got handle %p\n",hfind
);
347 return (MSVCRT_intptr_t
)hfind
;
350 /*********************************************************************
351 * _findfirst64 (MSVCRT.@)
353 * 64-bit version of _findfirst.
355 MSVCRT_intptr_t CDECL
MSVCRT__findfirst64(const char * fspec
, struct MSVCRT__finddata64_t
* ft
)
357 WIN32_FIND_DATAA find_data
;
360 hfind
= FindFirstFileA(fspec
, &find_data
);
361 if (hfind
== INVALID_HANDLE_VALUE
)
363 msvcrt_set_errno(GetLastError());
366 msvcrt_fttofd64(&find_data
,ft
);
367 TRACE(":got handle %p\n",hfind
);
368 return (MSVCRT_intptr_t
)hfind
;
371 /*********************************************************************
372 * _findfirst64i32 (MSVCRT.@)
374 * 64-bit/32-bit version of _findfirst.
376 MSVCRT_intptr_t CDECL
MSVCRT__findfirst64i32(const char * fspec
, struct MSVCRT__finddata64i32_t
* ft
)
378 WIN32_FIND_DATAA find_data
;
381 hfind
= FindFirstFileA(fspec
, &find_data
);
382 if (hfind
== INVALID_HANDLE_VALUE
)
384 msvcrt_set_errno(GetLastError());
387 msvcrt_fttofd64i32(&find_data
,ft
);
388 TRACE(":got handle %p\n",hfind
);
389 return (MSVCRT_intptr_t
)hfind
;
392 /*********************************************************************
393 * _wfindfirst64i32 (MSVCRT.@)
395 * Unicode version of _findfirst64i32.
397 MSVCRT_intptr_t CDECL
MSVCRT__wfindfirst64i32(const MSVCRT_wchar_t
* fspec
, struct MSVCRT__wfinddata64i32_t
* ft
)
399 WIN32_FIND_DATAW find_data
;
402 hfind
= FindFirstFileW(fspec
, &find_data
);
403 if (hfind
== INVALID_HANDLE_VALUE
)
405 msvcrt_set_errno(GetLastError());
408 msvcrt_wfttofd64i32(&find_data
,ft
);
409 TRACE(":got handle %p\n",hfind
);
410 return (MSVCRT_intptr_t
)hfind
;
413 /*********************************************************************
414 * _wfindfirsti64 (MSVCRT.@)
416 * Unicode version of _findfirsti64.
418 MSVCRT_intptr_t CDECL
MSVCRT__wfindfirsti64(const MSVCRT_wchar_t
* fspec
, struct MSVCRT__wfinddatai64_t
* ft
)
420 WIN32_FIND_DATAW find_data
;
423 hfind
= FindFirstFileW(fspec
, &find_data
);
424 if (hfind
== INVALID_HANDLE_VALUE
)
426 msvcrt_set_errno(GetLastError());
429 msvcrt_wfttofdi64(&find_data
,ft
);
430 TRACE(":got handle %p\n",hfind
);
431 return (MSVCRT_intptr_t
)hfind
;
434 /*********************************************************************
435 * _findnext (MSVCRT.@)
437 * Find the next file from a file search handle.
440 * hand [I] Handle to the search returned from _findfirst().
441 * ft [O] Information for the file found.
444 * Success: 0. ft is populated with the details of the found file.
445 * Failure: -1. errno indicates the error.
450 int CDECL
MSVCRT__findnext(MSVCRT_intptr_t hand
, struct MSVCRT__finddata_t
* ft
)
452 WIN32_FIND_DATAA find_data
;
454 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
456 *MSVCRT__errno() = MSVCRT_ENOENT
;
460 msvcrt_fttofd(&find_data
,ft
);
464 /*********************************************************************
465 * _wfindnext (MSVCRT.@)
467 * Unicode version of _findnext.
469 int CDECL
MSVCRT__wfindnext(MSVCRT_intptr_t hand
, struct MSVCRT__wfinddata_t
* ft
)
471 WIN32_FIND_DATAW find_data
;
473 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
475 *MSVCRT__errno() = MSVCRT_ENOENT
;
479 msvcrt_wfttofd(&find_data
,ft
);
483 /*********************************************************************
484 * _findnexti64 (MSVCRT.@)
486 * 64-bit version of _findnext.
488 int CDECL
MSVCRT__findnexti64(MSVCRT_intptr_t hand
, struct MSVCRT__finddatai64_t
* ft
)
490 WIN32_FIND_DATAA find_data
;
492 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
494 *MSVCRT__errno() = MSVCRT_ENOENT
;
498 msvcrt_fttofdi64(&find_data
,ft
);
502 /*********************************************************************
503 * _findnext64 (MSVCRT.@)
505 * 64-bit version of _findnext.
507 int CDECL
MSVCRT__findnext64(long hand
, struct MSVCRT__finddata64_t
* ft
)
509 WIN32_FIND_DATAA find_data
;
511 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
513 *MSVCRT__errno() = MSVCRT_ENOENT
;
517 msvcrt_fttofd64(&find_data
,ft
);
521 /*********************************************************************
522 * _findnext64i32 (MSVCRT.@)
524 * 64-bit/32-bit version of _findnext.
526 int CDECL
MSVCRT__findnext64i32(long hand
, struct MSVCRT__finddata64i32_t
* ft
)
528 WIN32_FIND_DATAA find_data
;
530 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
532 *MSVCRT__errno() = MSVCRT_ENOENT
;
536 msvcrt_fttofd64i32(&find_data
,ft
);
540 /*********************************************************************
541 * _wfindnexti64 (MSVCRT.@)
543 * Unicode version of _findnexti64.
545 int CDECL
MSVCRT__wfindnexti64(MSVCRT_intptr_t hand
, struct MSVCRT__wfinddatai64_t
* ft
)
547 WIN32_FIND_DATAW find_data
;
549 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
551 *MSVCRT__errno() = MSVCRT_ENOENT
;
555 msvcrt_wfttofdi64(&find_data
,ft
);
559 /*********************************************************************
560 * _wfindnext64i32 (MSVCRT.@)
562 * Unicode version of _findnext64i32.
564 int CDECL
MSVCRT__wfindnext64i32(MSVCRT_intptr_t hand
, struct MSVCRT__wfinddata64i32_t
* ft
)
566 WIN32_FIND_DATAW find_data
;
568 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
570 *MSVCRT__errno() = MSVCRT_ENOENT
;
574 msvcrt_wfttofd64i32(&find_data
,ft
);
578 /*********************************************************************
581 * Get the current working directory.
584 * buf [O] Destination for current working directory.
585 * size [I] Size of buf in characters
588 * Success: If buf is NULL, returns an allocated string containing the path.
589 * Otherwise populates buf with the path and returns it.
590 * Failure: NULL. errno indicates the error.
592 char* CDECL
_getcwd(char * buf
, int size
)
595 int dir_len
= GetCurrentDirectoryA(MAX_PATH
,dir
);
598 return NULL
; /* FIXME: Real return value untested */
602 if (size
<= dir_len
) size
= dir_len
+ 1;
603 if (!(buf
= MSVCRT_malloc( size
))) return NULL
;
605 else if (dir_len
>= size
)
607 *MSVCRT__errno() = MSVCRT_ERANGE
;
608 return NULL
; /* buf too small */
614 /*********************************************************************
615 * _wgetcwd (MSVCRT.@)
617 * Unicode version of _getcwd.
619 MSVCRT_wchar_t
* CDECL
_wgetcwd(MSVCRT_wchar_t
* buf
, int size
)
621 MSVCRT_wchar_t dir
[MAX_PATH
];
622 int dir_len
= GetCurrentDirectoryW(MAX_PATH
,dir
);
625 return NULL
; /* FIXME: Real return value untested */
629 if (size
<= dir_len
) size
= dir_len
+ 1;
630 if (!(buf
= MSVCRT_malloc( size
* sizeof(WCHAR
) ))) return NULL
;
634 *MSVCRT__errno() = MSVCRT_ERANGE
;
635 return NULL
; /* buf too small */
641 /*********************************************************************
642 * _getdrive (MSVCRT.@)
644 * Get the current drive number.
650 * Success: The drive letter number from 1 to 26 ("A:" to "Z:").
653 int CDECL
_getdrive(void)
655 WCHAR buffer
[MAX_PATH
];
656 if (GetCurrentDirectoryW( MAX_PATH
, buffer
) &&
657 buffer
[0] >= 'A' && buffer
[0] <= 'z' && buffer
[1] == ':')
658 return toupperW(buffer
[0]) - 'A' + 1;
662 /*********************************************************************
663 * _getdcwd (MSVCRT.@)
665 * Get the current working directory on a given disk.
668 * drive [I] Drive letter to get the current working directory from.
669 * buf [O] Destination for the current working directory.
670 * size [I] Length of drive in characters.
673 * Success: If drive is NULL, returns an allocated string containing the path.
674 * Otherwise populates drive with the path and returns it.
675 * Failure: NULL. errno indicates the error.
677 char* CDECL
_getdcwd(int drive
, char * buf
, int size
)
681 TRACE(":drive %d(%c), size %d\n",drive
, drive
+ 'A' - 1, size
);
683 if (!drive
|| drive
== _getdrive())
684 return _getcwd(buf
,size
); /* current */
688 char drivespec
[4] = {'A', ':', 0};
691 drivespec
[0] += drive
- 1;
692 if (GetDriveTypeA(drivespec
) < DRIVE_REMOVABLE
)
694 *MSVCRT__errno() = MSVCRT_EACCES
;
698 dir_len
= GetFullPathNameA(drivespec
,MAX_PATH
,dir
,&dummy
);
699 if (dir_len
>= size
|| dir_len
< 1)
701 *MSVCRT__errno() = MSVCRT_ERANGE
;
702 return NULL
; /* buf too small */
705 TRACE(":returning '%s'\n", dir
);
707 return _strdup(dir
); /* allocate */
714 /*********************************************************************
715 * _wgetdcwd (MSVCRT.@)
717 * Unicode version of _wgetdcwd.
719 MSVCRT_wchar_t
* CDECL
_wgetdcwd(int drive
, MSVCRT_wchar_t
* buf
, int size
)
721 static MSVCRT_wchar_t
* dummy
;
723 TRACE(":drive %d(%c), size %d\n",drive
, drive
+ 'A' - 1, size
);
725 if (!drive
|| drive
== _getdrive())
726 return _wgetcwd(buf
,size
); /* current */
729 MSVCRT_wchar_t dir
[MAX_PATH
];
730 MSVCRT_wchar_t drivespec
[4] = {'A', ':', '\\', 0};
733 drivespec
[0] += drive
- 1;
734 if (GetDriveTypeW(drivespec
) < DRIVE_REMOVABLE
)
736 *MSVCRT__errno() = MSVCRT_EACCES
;
740 dir_len
= GetFullPathNameW(drivespec
,MAX_PATH
,dir
,&dummy
);
741 if (dir_len
>= size
|| dir_len
< 1)
743 *MSVCRT__errno() = MSVCRT_ERANGE
;
744 return NULL
; /* buf too small */
747 TRACE(":returning %s\n", debugstr_w(dir
));
749 return _wcsdup(dir
); /* allocate */
755 /*********************************************************************
756 * _getdiskfree (MSVCRT.@)
758 * Get information about the free space on a drive.
761 * disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
762 * info [O] Destination for the resulting information.
765 * Success: 0. info is updated with the free space information.
766 * Failure: An error code from GetLastError().
769 * See GetLastError().
771 unsigned int CDECL
MSVCRT__getdiskfree(unsigned int disk
, struct MSVCRT__diskfree_t
* d
)
773 WCHAR drivespec
[4] = {'@', ':', '\\', 0};
778 return ERROR_INVALID_PARAMETER
; /* MSVCRT doesn't set errno here */
780 drivespec
[0] += disk
; /* make a drive letter */
782 if (GetDiskFreeSpaceW(disk
==0?NULL
:drivespec
,ret
,ret
+1,ret
+2,ret
+3))
784 d
->sectors_per_cluster
= ret
[0];
785 d
->bytes_per_sector
= ret
[1];
786 d
->avail_clusters
= ret
[2];
787 d
->total_clusters
= ret
[3];
790 err
= GetLastError();
791 msvcrt_set_errno(err
);
795 /*********************************************************************
798 * Create a directory.
801 * newdir [I] Name of directory to create.
804 * Success: 0. The directory indicated by newdir is created.
805 * Failure: -1. errno indicates the error.
808 * See CreateDirectoryA.
810 int CDECL
MSVCRT__mkdir(const char * newdir
)
812 if (CreateDirectoryA(newdir
,NULL
))
814 msvcrt_set_errno(GetLastError());
818 /*********************************************************************
821 * Unicode version of _mkdir.
823 int CDECL
_wmkdir(const MSVCRT_wchar_t
* newdir
)
825 if (CreateDirectoryW(newdir
,NULL
))
827 msvcrt_set_errno(GetLastError());
831 /*********************************************************************
834 * Delete a directory.
837 * dir [I] Name of directory to delete.
840 * Success: 0. The directory indicated by newdir is deleted.
841 * Failure: -1. errno indicates the error.
844 * See RemoveDirectoryA.
846 int CDECL
MSVCRT__rmdir(const char * dir
)
848 if (RemoveDirectoryA(dir
))
850 msvcrt_set_errno(GetLastError());
854 /*********************************************************************
857 * Unicode version of _rmdir.
859 int CDECL
_wrmdir(const MSVCRT_wchar_t
* dir
)
861 if (RemoveDirectoryW(dir
))
863 msvcrt_set_errno(GetLastError());
867 /******************************************************************
868 * _splitpath_s (MSVCRT.@)
870 int _splitpath_s(const char* inpath
,
871 char* drive
, MSVCRT_size_t sz_drive
,
872 char* dir
, MSVCRT_size_t sz_dir
,
873 char* fname
, MSVCRT_size_t sz_fname
,
874 char* ext
, MSVCRT_size_t sz_ext
)
878 if (!inpath
|| (!drive
&& sz_drive
) ||
879 (drive
&& !sz_drive
) ||
882 (!fname
&& sz_fname
) ||
883 (fname
&& !sz_fname
) ||
887 *MSVCRT__errno() = MSVCRT_EINVAL
;
888 return MSVCRT_EINVAL
;
891 if (inpath
[0] && inpath
[1] == ':')
895 if (sz_drive
<= 2) goto do_error
;
896 drive
[0] = inpath
[0];
897 drive
[1] = inpath
[1];
902 else if (drive
) drive
[0] = '\0';
904 /* look for end of directory part */
906 for (p
= inpath
; *p
; p
++) if (*p
== '/' || *p
== '\\') end
= p
+ 1;
908 if (end
) /* got a directory */
912 if (sz_dir
<= end
- inpath
) goto do_error
;
913 memcpy( dir
, inpath
, (end
- inpath
) );
914 dir
[end
- inpath
] = 0;
918 else if (dir
) dir
[0] = 0;
920 /* look for extension: what's after the last dot */
922 for (p
= inpath
; *p
; p
++) if (*p
== '.') end
= p
;
924 if (!end
) end
= p
; /* there's no extension */
928 if (sz_fname
<= end
- inpath
) goto do_error
;
929 memcpy( fname
, inpath
, (end
- inpath
) );
930 fname
[end
- inpath
] = 0;
934 if (sz_ext
<= strlen(end
)) goto do_error
;
939 if (drive
) drive
[0] = '\0';
940 if (dir
) dir
[0] = '\0';
941 if (fname
) fname
[0]= '\0';
942 if (ext
) ext
[0]= '\0';
943 *MSVCRT__errno() = MSVCRT_ERANGE
;
944 return MSVCRT_ERANGE
;
947 /*********************************************************************
948 * _splitpath (MSVCRT.@)
950 void CDECL
_splitpath(const char *inpath
, char *drv
, char *dir
,
951 char *fname
, char *ext
)
953 _splitpath_s(inpath
, drv
, drv
?MSVCRT__MAX_DRIVE
:0, dir
, dir
?MSVCRT__MAX_DIR
:0,
954 fname
, fname
?MSVCRT__MAX_FNAME
:0, ext
, ext
?MSVCRT__MAX_EXT
:0);
957 /******************************************************************
958 * _wsplitpath_s (MSVCRT.@)
960 * Secure version of _wsplitpath
962 int _wsplitpath_s(const MSVCRT_wchar_t
* inpath
,
963 MSVCRT_wchar_t
* drive
, MSVCRT_size_t sz_drive
,
964 MSVCRT_wchar_t
* dir
, MSVCRT_size_t sz_dir
,
965 MSVCRT_wchar_t
* fname
, MSVCRT_size_t sz_fname
,
966 MSVCRT_wchar_t
* ext
, MSVCRT_size_t sz_ext
)
968 const MSVCRT_wchar_t
*p
, *end
;
970 if (!inpath
|| (!drive
&& sz_drive
) ||
971 (drive
&& !sz_drive
) ||
974 (!fname
&& sz_fname
) ||
975 (fname
&& !sz_fname
) ||
979 *MSVCRT__errno() = MSVCRT_EINVAL
;
980 return MSVCRT_EINVAL
;
983 if (inpath
[0] && inpath
[1] == ':')
987 if (sz_drive
<= 2) goto do_error
;
988 drive
[0] = inpath
[0];
989 drive
[1] = inpath
[1];
994 else if (drive
) drive
[0] = '\0';
996 /* look for end of directory part */
998 for (p
= inpath
; *p
; p
++) if (*p
== '/' || *p
== '\\') end
= p
+ 1;
1000 if (end
) /* got a directory */
1004 if (sz_dir
<= end
- inpath
) goto do_error
;
1005 memcpy( dir
, inpath
, (end
- inpath
) * sizeof(MSVCRT_wchar_t
) );
1006 dir
[end
- inpath
] = 0;
1010 else if (dir
) dir
[0] = 0;
1012 /* look for extension: what's after the last dot */
1014 for (p
= inpath
; *p
; p
++) if (*p
== '.') end
= p
;
1016 if (!end
) end
= p
; /* there's no extension */
1020 if (sz_fname
<= end
- inpath
) goto do_error
;
1021 memcpy( fname
, inpath
, (end
- inpath
) * sizeof(MSVCRT_wchar_t
) );
1022 fname
[end
- inpath
] = 0;
1026 if (sz_ext
<= strlenW(end
)) goto do_error
;
1027 strcpyW( ext
, end
);
1031 if (drive
) drive
[0] = '\0';
1032 if (dir
) dir
[0] = '\0';
1033 if (fname
) fname
[0]= '\0';
1034 if (ext
) ext
[0]= '\0';
1035 *MSVCRT__errno() = MSVCRT_ERANGE
;
1036 return MSVCRT_ERANGE
;
1039 /*********************************************************************
1040 * _wsplitpath (MSVCRT.@)
1042 * Unicode version of _splitpath.
1044 void CDECL
_wsplitpath(const MSVCRT_wchar_t
*inpath
, MSVCRT_wchar_t
*drv
, MSVCRT_wchar_t
*dir
,
1045 MSVCRT_wchar_t
*fname
, MSVCRT_wchar_t
*ext
)
1047 _wsplitpath_s(inpath
, drv
, drv
?MSVCRT__MAX_DRIVE
:0, dir
, dir
?MSVCRT__MAX_DIR
:0,
1048 fname
, fname
?MSVCRT__MAX_FNAME
:0, ext
, ext
?MSVCRT__MAX_EXT
:0);
1051 /*********************************************************************
1052 * _wfullpath (MSVCRT.@)
1054 * Unicode version of _fullpath.
1056 MSVCRT_wchar_t
* CDECL
_wfullpath(MSVCRT_wchar_t
* absPath
, const MSVCRT_wchar_t
* relPath
, MSVCRT_size_t size
)
1061 BOOL alloced
= FALSE
;
1063 if (!relPath
|| !*relPath
)
1064 return _wgetcwd(absPath
, size
);
1066 if (absPath
== NULL
)
1068 buffer
= MSVCRT_malloc(MAX_PATH
* sizeof(WCHAR
));
1077 *MSVCRT__errno() = MSVCRT_ERANGE
;
1081 TRACE(":resolving relative path %s\n",debugstr_w(relPath
));
1083 rc
= GetFullPathNameW(relPath
,size
,buffer
,&lastpart
);
1085 if (rc
> 0 && rc
<= size
)
1090 MSVCRT_free(buffer
);
1095 /*********************************************************************
1096 * _fullpath (MSVCRT.@)
1098 * Create an absolute path from a relative path.
1101 * absPath [O] Destination for absolute path
1102 * relPath [I] Relative path to convert to absolute
1103 * size [I] Length of absPath in characters.
1106 * Success: If absPath is NULL, returns an allocated string containing the path.
1107 * Otherwise populates absPath with the path and returns it.
1108 * Failure: NULL. errno indicates the error.
1110 char * CDECL
_fullpath(char * absPath
, const char* relPath
, unsigned int size
)
1115 BOOL alloced
= FALSE
;
1117 if (!relPath
|| !*relPath
)
1118 return _getcwd(absPath
, size
);
1120 if (absPath
== NULL
)
1122 buffer
= MSVCRT_malloc(MAX_PATH
);
1131 *MSVCRT__errno() = MSVCRT_ERANGE
;
1135 TRACE(":resolving relative path '%s'\n",relPath
);
1137 rc
= GetFullPathNameA(relPath
,size
,buffer
,&lastpart
);
1139 if (rc
> 0 && rc
<= size
)
1144 MSVCRT_free(buffer
);
1149 /*********************************************************************
1150 * _makepath (MSVCRT.@)
1152 * Create a pathname.
1155 * path [O] Destination for created pathname
1156 * drive [I] Drive letter (e.g. "A:")
1157 * directory [I] Directory
1158 * filename [I] Name of the file, excluding extension
1159 * extension [I] File extension (e.g. ".TXT")
1162 * Nothing. If path is not large enough to hold the resulting pathname,
1163 * random process memory will be overwritten.
1165 VOID CDECL
_makepath(char * path
, const char * drive
,
1166 const char *directory
, const char * filename
,
1167 const char * extension
)
1171 TRACE("(%s %s %s %s)\n", debugstr_a(drive
), debugstr_a(directory
),
1172 debugstr_a(filename
), debugstr_a(extension
) );
1177 if (drive
&& drive
[0])
1182 if (directory
&& directory
[0])
1184 unsigned int len
= strlen(directory
);
1185 memmove(p
, directory
, len
);
1187 if (p
[-1] != '/' && p
[-1] != '\\')
1190 if (filename
&& filename
[0])
1192 unsigned int len
= strlen(filename
);
1193 memmove(p
, filename
, len
);
1196 if (extension
&& extension
[0])
1198 if (extension
[0] != '.')
1200 strcpy(p
, extension
);
1204 TRACE("returning %s\n",path
);
1207 /*********************************************************************
1208 * _wmakepath (MSVCRT.@)
1210 * Unicode version of _wmakepath.
1212 VOID CDECL
_wmakepath(MSVCRT_wchar_t
*path
, const MSVCRT_wchar_t
*drive
, const MSVCRT_wchar_t
*directory
,
1213 const MSVCRT_wchar_t
*filename
, const MSVCRT_wchar_t
*extension
)
1215 MSVCRT_wchar_t
*p
= path
;
1217 TRACE("%s %s %s %s\n", debugstr_w(drive
), debugstr_w(directory
),
1218 debugstr_w(filename
), debugstr_w(extension
));
1223 if (drive
&& drive
[0])
1228 if (directory
&& directory
[0])
1230 unsigned int len
= strlenW(directory
);
1231 memmove(p
, directory
, len
* sizeof(MSVCRT_wchar_t
));
1233 if (p
[-1] != '/' && p
[-1] != '\\')
1236 if (filename
&& filename
[0])
1238 unsigned int len
= strlenW(filename
);
1239 memmove(p
, filename
, len
* sizeof(MSVCRT_wchar_t
));
1242 if (extension
&& extension
[0])
1244 if (extension
[0] != '.')
1246 strcpyW(p
, extension
);
1251 TRACE("returning %s\n", debugstr_w(path
));
1254 /*********************************************************************
1255 * _makepath_s (MSVCRT.@)
1257 * Safe version of _makepath.
1259 int CDECL
_makepath_s(char *path
, MSVCRT_size_t size
, const char *drive
,
1260 const char *directory
, const char *filename
,
1261 const char *extension
)
1267 *MSVCRT__errno() = MSVCRT_EINVAL
;
1268 return MSVCRT_EINVAL
;
1271 if (drive
&& drive
[0])
1281 if (directory
&& directory
[0])
1283 unsigned int len
= strlen(directory
);
1284 unsigned int needs_separator
= directory
[len
- 1] != '/' && directory
[len
- 1] != '\\';
1285 unsigned int copylen
= min(size
- 1, len
);
1290 memmove(p
, directory
, copylen
);
1298 if (needs_separator
)
1308 if (filename
&& filename
[0])
1310 unsigned int len
= strlen(filename
);
1311 unsigned int copylen
= min(size
- 1, len
);
1316 memmove(p
, filename
, copylen
);
1325 if (extension
&& extension
[0])
1327 unsigned int len
= strlen(extension
);
1328 unsigned int needs_period
= extension
[0] != '.';
1329 unsigned int copylen
;
1340 copylen
= min(size
- 1, len
);
1341 memcpy(p
, extension
, copylen
);
1354 *MSVCRT__errno() = MSVCRT_ERANGE
;
1355 return MSVCRT_ERANGE
;
1358 /*********************************************************************
1359 * _wmakepath_s (MSVCRT.@)
1361 * Safe version of _wmakepath.
1363 int CDECL
_wmakepath_s(MSVCRT_wchar_t
*path
, MSVCRT_size_t size
, const MSVCRT_wchar_t
*drive
,
1364 const MSVCRT_wchar_t
*directory
, const MSVCRT_wchar_t
*filename
,
1365 const MSVCRT_wchar_t
*extension
)
1367 MSVCRT_wchar_t
*p
= path
;
1371 *MSVCRT__errno() = MSVCRT_EINVAL
;
1372 return MSVCRT_EINVAL
;
1375 if (drive
&& drive
[0])
1385 if (directory
&& directory
[0])
1387 unsigned int len
= strlenW(directory
);
1388 unsigned int needs_separator
= directory
[len
- 1] != '/' && directory
[len
- 1] != '\\';
1389 unsigned int copylen
= min(size
- 1, len
);
1394 memmove(p
, directory
, copylen
* sizeof(MSVCRT_wchar_t
));
1402 if (needs_separator
)
1412 if (filename
&& filename
[0])
1414 unsigned int len
= strlenW(filename
);
1415 unsigned int copylen
= min(size
- 1, len
);
1420 memmove(p
, filename
, copylen
* sizeof(MSVCRT_wchar_t
));
1429 if (extension
&& extension
[0])
1431 unsigned int len
= strlenW(extension
);
1432 unsigned int needs_period
= extension
[0] != '.';
1433 unsigned int copylen
;
1444 copylen
= min(size
- 1, len
);
1445 memcpy(p
, extension
, copylen
* sizeof(MSVCRT_wchar_t
));
1458 *MSVCRT__errno() = MSVCRT_ERANGE
;
1459 return MSVCRT_ERANGE
;
1462 /*********************************************************************
1463 * _searchenv (MSVCRT.@)
1465 * Search for a file in a list of paths from an environment variable.
1468 * file [I] Name of the file to search for.
1469 * env [I] Name of the environment variable containing a list of paths.
1470 * buf [O] Destination for the found file path.
1473 * Nothing. If the file is not found, buf will contain an empty string
1476 void CDECL
_searchenv(const char* file
, const char* env
, char *buf
)
1479 char curPath
[MAX_PATH
];
1484 if (GetFileAttributesA( file
) != INVALID_FILE_ATTRIBUTES
)
1486 GetFullPathNameA( file
, MAX_PATH
, buf
, NULL
);
1487 /* Sigh. This error is *always* set, regardless of success */
1488 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1492 /* Search given environment variable */
1493 envVal
= MSVCRT_getenv(env
);
1496 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1501 TRACE(":searching for %s in paths %s\n", file
, envVal
);
1507 while(*end
&& *end
!= ';') end
++; /* Find end of next path */
1508 if (penv
== end
|| !*penv
)
1510 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1513 memcpy(curPath
, penv
, end
- penv
);
1514 if (curPath
[end
- penv
] != '/' && curPath
[end
- penv
] != '\\')
1516 curPath
[end
- penv
] = '\\';
1517 curPath
[end
- penv
+ 1] = '\0';
1520 curPath
[end
- penv
] = '\0';
1522 strcat(curPath
, file
);
1523 TRACE("Checking for file %s\n", curPath
);
1524 if (GetFileAttributesA( curPath
) != INVALID_FILE_ATTRIBUTES
)
1526 strcpy(buf
, curPath
);
1527 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1530 penv
= *end
? end
+ 1 : end
;
1534 /*********************************************************************
1535 * _searchenv_s (MSVCRT.@)
1537 int CDECL
_searchenv_s(const char* file
, const char* env
, char *buf
, MSVCRT_size_t count
)
1540 char curPath
[MAX_PATH
];
1542 if (!MSVCRT_CHECK_PMT(file
!= NULL
) || !MSVCRT_CHECK_PMT(buf
!= NULL
) ||
1543 !MSVCRT_CHECK_PMT(count
> 0))
1545 *MSVCRT__errno() = MSVCRT_EINVAL
;
1546 return MSVCRT_EINVAL
;
1552 if (GetFileAttributesA( file
) != INVALID_FILE_ATTRIBUTES
)
1554 if (GetFullPathNameA( file
, count
, buf
, NULL
)) return 0;
1555 msvcrt_set_errno(GetLastError());
1559 /* Search given environment variable */
1560 envVal
= MSVCRT_getenv(env
);
1563 *MSVCRT__errno() = MSVCRT_ENOENT
;
1564 return MSVCRT_ENOENT
;
1568 TRACE(":searching for %s in paths %s\n", file
, envVal
);
1574 while(*end
&& *end
!= ';') end
++; /* Find end of next path */
1575 if (penv
== end
|| !*penv
)
1577 *MSVCRT__errno() = MSVCRT_ENOENT
;
1578 return MSVCRT_ENOENT
;
1580 memcpy(curPath
, penv
, end
- penv
);
1581 if (curPath
[end
- penv
] != '/' && curPath
[end
- penv
] != '\\')
1583 curPath
[end
- penv
] = '\\';
1584 curPath
[end
- penv
+ 1] = '\0';
1587 curPath
[end
- penv
] = '\0';
1589 strcat(curPath
, file
);
1590 TRACE("Checking for file %s\n", curPath
);
1591 if (GetFileAttributesA( curPath
) != INVALID_FILE_ATTRIBUTES
)
1593 if (strlen(curPath
) + 1 > count
)
1595 MSVCRT_INVALID_PMT("buf[count] is too small");
1596 *MSVCRT__errno() = MSVCRT_ERANGE
;
1597 return MSVCRT_ERANGE
;
1599 strcpy(buf
, curPath
);
1602 penv
= *end
? end
+ 1 : end
;
1606 /*********************************************************************
1607 * _wsearchenv (MSVCRT.@)
1609 * Unicode version of _searchenv
1611 void CDECL
_wsearchenv(const MSVCRT_wchar_t
* file
, const MSVCRT_wchar_t
* env
, MSVCRT_wchar_t
*buf
)
1613 MSVCRT_wchar_t
*envVal
, *penv
;
1614 MSVCRT_wchar_t curPath
[MAX_PATH
];
1619 if (GetFileAttributesW( file
) != INVALID_FILE_ATTRIBUTES
)
1621 GetFullPathNameW( file
, MAX_PATH
, buf
, NULL
);
1622 /* Sigh. This error is *always* set, regardless of success */
1623 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1627 /* Search given environment variable */
1628 envVal
= _wgetenv(env
);
1631 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1636 TRACE(":searching for %s in paths %s\n", debugstr_w(file
), debugstr_w(envVal
));
1640 MSVCRT_wchar_t
*end
= penv
;
1642 while(*end
&& *end
!= ';') end
++; /* Find end of next path */
1643 if (penv
== end
|| !*penv
)
1645 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1648 memcpy(curPath
, penv
, (end
- penv
) * sizeof(MSVCRT_wchar_t
));
1649 if (curPath
[end
- penv
] != '/' && curPath
[end
- penv
] != '\\')
1651 curPath
[end
- penv
] = '\\';
1652 curPath
[end
- penv
+ 1] = '\0';
1655 curPath
[end
- penv
] = '\0';
1657 strcatW(curPath
, file
);
1658 TRACE("Checking for file %s\n", debugstr_w(curPath
));
1659 if (GetFileAttributesW( curPath
) != INVALID_FILE_ATTRIBUTES
)
1661 strcpyW(buf
, curPath
);
1662 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1665 penv
= *end
? end
+ 1 : end
;
1669 /*********************************************************************
1670 * _wsearchenv_s (MSVCRT.@)
1672 int CDECL
_wsearchenv_s(const MSVCRT_wchar_t
* file
, const MSVCRT_wchar_t
* env
,
1673 MSVCRT_wchar_t
*buf
, MSVCRT_size_t count
)
1675 MSVCRT_wchar_t
* envVal
, *penv
;
1676 MSVCRT_wchar_t curPath
[MAX_PATH
];
1678 if (!MSVCRT_CHECK_PMT(file
!= NULL
) || !MSVCRT_CHECK_PMT(buf
!= NULL
) ||
1679 !MSVCRT_CHECK_PMT(count
> 0))
1681 *MSVCRT__errno() = MSVCRT_EINVAL
;
1682 return MSVCRT_EINVAL
;
1687 if (GetFileAttributesW( file
) != INVALID_FILE_ATTRIBUTES
)
1689 if (GetFullPathNameW( file
, count
, buf
, NULL
)) return 0;
1690 msvcrt_set_errno(GetLastError());
1694 /* Search given environment variable */
1695 envVal
= _wgetenv(env
);
1698 *MSVCRT__errno() = MSVCRT_ENOENT
;
1699 return MSVCRT_ENOENT
;
1703 TRACE(":searching for %s in paths %s\n", debugstr_w(file
), debugstr_w(envVal
));
1707 MSVCRT_wchar_t
*end
= penv
;
1709 while(*end
&& *end
!= ';') end
++; /* Find end of next path */
1710 if (penv
== end
|| !*penv
)
1712 *MSVCRT__errno() = MSVCRT_ENOENT
;
1713 return MSVCRT_ENOENT
;
1715 memcpy(curPath
, penv
, (end
- penv
) * sizeof(MSVCRT_wchar_t
));
1716 if (curPath
[end
- penv
] != '/' && curPath
[end
- penv
] != '\\')
1718 curPath
[end
- penv
] = '\\';
1719 curPath
[end
- penv
+ 1] = '\0';
1722 curPath
[end
- penv
] = '\0';
1724 strcatW(curPath
, file
);
1725 TRACE("Checking for file %s\n", debugstr_w(curPath
));
1726 if (GetFileAttributesW( curPath
) != INVALID_FILE_ATTRIBUTES
)
1728 if (strlenW(curPath
) + 1 > count
)
1730 MSVCRT_INVALID_PMT("buf[count] is too small");
1731 *MSVCRT__errno() = MSVCRT_ERANGE
;
1732 return MSVCRT_ERANGE
;
1734 strcpyW(buf
, curPath
);
1737 penv
= *end
? end
+ 1 : end
;