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 /*********************************************************************
162 * Change the current working directory.
165 * newdir [I] Directory to change to
168 * Success: 0. The current working directory is set to newdir.
169 * Failure: -1. errno indicates the error.
172 * See SetCurrentDirectoryA.
174 int CDECL
MSVCRT__chdir(const char * newdir
)
176 if (!SetCurrentDirectoryA(newdir
))
178 msvcrt_set_errno(newdir
?GetLastError():0);
184 /*********************************************************************
187 * Unicode version of _chdir.
189 int CDECL
_wchdir(const MSVCRT_wchar_t
* newdir
)
191 if (!SetCurrentDirectoryW(newdir
))
193 msvcrt_set_errno(newdir
?GetLastError():0);
199 /*********************************************************************
200 * _chdrive (MSVCRT.@)
202 * Change the current drive.
205 * newdrive [I] Drive number to change to (1 = 'A', 2 = 'B', ...)
208 * Success: 0. The current drive is set to newdrive.
209 * Failure: -1. errno indicates the error.
212 * See SetCurrentDirectoryA.
214 int CDECL
_chdrive(int newdrive
)
216 WCHAR buffer
[3] = {'A', ':', 0};
218 buffer
[0] += newdrive
- 1;
219 if (!SetCurrentDirectoryW( buffer
))
221 msvcrt_set_errno(GetLastError());
223 *MSVCRT__errno() = MSVCRT_EACCES
;
229 /*********************************************************************
230 * _findclose (MSVCRT.@)
232 * Close a handle returned by _findfirst().
235 * hand [I] Handle to close
238 * Success: 0. All resources associated with hand are freed.
239 * Failure: -1. errno indicates the error.
244 int CDECL
MSVCRT__findclose(MSVCRT_intptr_t hand
)
246 TRACE(":handle %ld\n",hand
);
247 if (!FindClose((HANDLE
)hand
))
249 msvcrt_set_errno(GetLastError());
255 /*********************************************************************
256 * _findfirst (MSVCRT.@)
258 * Open a handle for iterating through a directory.
261 * fspec [I] File specification of files to iterate.
262 * ft [O] Information for the first file found.
265 * Success: A handle suitable for passing to _findnext() and _findclose().
266 * ft is populated with the details of the found file.
267 * Failure: -1. errno indicates the error.
270 * See FindFirstFileA.
272 MSVCRT_intptr_t CDECL
MSVCRT__findfirst(const char * fspec
, struct MSVCRT__finddata_t
* ft
)
274 WIN32_FIND_DATAA find_data
;
277 hfind
= FindFirstFileA(fspec
, &find_data
);
278 if (hfind
== INVALID_HANDLE_VALUE
)
280 msvcrt_set_errno(GetLastError());
283 msvcrt_fttofd(&find_data
,ft
);
284 TRACE(":got handle %p\n",hfind
);
285 return (MSVCRT_intptr_t
)hfind
;
288 /*********************************************************************
289 * _wfindfirst (MSVCRT.@)
291 * Unicode version of _findfirst.
293 MSVCRT_intptr_t CDECL
MSVCRT__wfindfirst(const MSVCRT_wchar_t
* fspec
, struct MSVCRT__wfinddata_t
* ft
)
295 WIN32_FIND_DATAW find_data
;
298 hfind
= FindFirstFileW(fspec
, &find_data
);
299 if (hfind
== INVALID_HANDLE_VALUE
)
301 msvcrt_set_errno(GetLastError());
304 msvcrt_wfttofd(&find_data
,ft
);
305 TRACE(":got handle %p\n",hfind
);
306 return (MSVCRT_intptr_t
)hfind
;
309 /*********************************************************************
310 * _findfirsti64 (MSVCRT.@)
312 * 64-bit version of _findfirst.
314 MSVCRT_intptr_t CDECL
MSVCRT__findfirsti64(const char * fspec
, struct MSVCRT__finddatai64_t
* ft
)
316 WIN32_FIND_DATAA find_data
;
319 hfind
= FindFirstFileA(fspec
, &find_data
);
320 if (hfind
== INVALID_HANDLE_VALUE
)
322 msvcrt_set_errno(GetLastError());
325 msvcrt_fttofdi64(&find_data
,ft
);
326 TRACE(":got handle %p\n",hfind
);
327 return (MSVCRT_intptr_t
)hfind
;
330 /*********************************************************************
331 * _findfirst64 (MSVCRT.@)
333 * 64-bit version of _findfirst.
335 MSVCRT_intptr_t CDECL
MSVCRT__findfirst64(const char * fspec
, struct MSVCRT__finddata64_t
* ft
)
337 WIN32_FIND_DATAA find_data
;
340 hfind
= FindFirstFileA(fspec
, &find_data
);
341 if (hfind
== INVALID_HANDLE_VALUE
)
343 msvcrt_set_errno(GetLastError());
346 msvcrt_fttofd64(&find_data
,ft
);
347 TRACE(":got handle %p\n",hfind
);
348 return (MSVCRT_intptr_t
)hfind
;
351 /*********************************************************************
352 * _findfirst64i32 (MSVCRT.@)
354 * 64-bit/32-bit version of _findfirst.
356 MSVCRT_intptr_t CDECL
MSVCRT__findfirst64i32(const char * fspec
, struct MSVCRT__finddata64i32_t
* ft
)
358 WIN32_FIND_DATAA find_data
;
361 hfind
= FindFirstFileA(fspec
, &find_data
);
362 if (hfind
== INVALID_HANDLE_VALUE
)
364 msvcrt_set_errno(GetLastError());
367 msvcrt_fttofd64i32(&find_data
,ft
);
368 TRACE(":got handle %p\n",hfind
);
369 return (MSVCRT_intptr_t
)hfind
;
372 /*********************************************************************
373 * _wfindfirsti64 (MSVCRT.@)
375 * Unicode version of _findfirsti64.
377 MSVCRT_intptr_t CDECL
MSVCRT__wfindfirsti64(const MSVCRT_wchar_t
* fspec
, struct MSVCRT__wfinddatai64_t
* ft
)
379 WIN32_FIND_DATAW find_data
;
382 hfind
= FindFirstFileW(fspec
, &find_data
);
383 if (hfind
== INVALID_HANDLE_VALUE
)
385 msvcrt_set_errno(GetLastError());
388 msvcrt_wfttofdi64(&find_data
,ft
);
389 TRACE(":got handle %p\n",hfind
);
390 return (MSVCRT_intptr_t
)hfind
;
393 /*********************************************************************
394 * _findnext (MSVCRT.@)
396 * Find the next file from a file search handle.
399 * hand [I] Handle to the search returned from _findfirst().
400 * ft [O] Information for the file found.
403 * Success: 0. ft is populated with the details of the found file.
404 * Failure: -1. errno indicates the error.
409 int CDECL
MSVCRT__findnext(MSVCRT_intptr_t hand
, struct MSVCRT__finddata_t
* ft
)
411 WIN32_FIND_DATAA find_data
;
413 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
415 *MSVCRT__errno() = MSVCRT_ENOENT
;
419 msvcrt_fttofd(&find_data
,ft
);
423 /*********************************************************************
424 * _wfindnext (MSVCRT.@)
426 * Unicode version of _findnext.
428 int CDECL
MSVCRT__wfindnext(MSVCRT_intptr_t hand
, struct MSVCRT__wfinddata_t
* ft
)
430 WIN32_FIND_DATAW find_data
;
432 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
434 *MSVCRT__errno() = MSVCRT_ENOENT
;
438 msvcrt_wfttofd(&find_data
,ft
);
442 /*********************************************************************
443 * _findnexti64 (MSVCRT.@)
445 * 64-bit version of _findnext.
447 int CDECL
MSVCRT__findnexti64(MSVCRT_intptr_t hand
, struct MSVCRT__finddatai64_t
* ft
)
449 WIN32_FIND_DATAA find_data
;
451 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
453 *MSVCRT__errno() = MSVCRT_ENOENT
;
457 msvcrt_fttofdi64(&find_data
,ft
);
461 /*********************************************************************
462 * _findnext64 (MSVCRT.@)
464 * 64-bit version of _findnext.
466 int CDECL
MSVCRT__findnext64(long hand
, struct MSVCRT__finddata64_t
* ft
)
468 WIN32_FIND_DATAA find_data
;
470 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
472 *MSVCRT__errno() = MSVCRT_ENOENT
;
476 msvcrt_fttofd64(&find_data
,ft
);
480 /*********************************************************************
481 * _findnext64i32 (MSVCRT.@)
483 * 64-bit/32-bit version of _findnext.
485 int CDECL
MSVCRT__findnext64i32(long hand
, struct MSVCRT__finddata64i32_t
* ft
)
487 WIN32_FIND_DATAA find_data
;
489 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
491 *MSVCRT__errno() = MSVCRT_ENOENT
;
495 msvcrt_fttofd64i32(&find_data
,ft
);
499 /*********************************************************************
500 * _wfindnexti64 (MSVCRT.@)
502 * Unicode version of _findnexti64.
504 int CDECL
MSVCRT__wfindnexti64(MSVCRT_intptr_t hand
, struct MSVCRT__wfinddatai64_t
* ft
)
506 WIN32_FIND_DATAW find_data
;
508 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
510 *MSVCRT__errno() = MSVCRT_ENOENT
;
514 msvcrt_wfttofdi64(&find_data
,ft
);
518 /*********************************************************************
521 * Get the current working directory.
524 * buf [O] Destination for current working directory.
525 * size [I] Size of buf in characters
528 * Success: If buf is NULL, returns an allocated string containing the path.
529 * Otherwise populates buf with the path and returns it.
530 * Failure: NULL. errno indicates the error.
532 char* CDECL
_getcwd(char * buf
, int size
)
535 int dir_len
= GetCurrentDirectoryA(MAX_PATH
,dir
);
538 return NULL
; /* FIXME: Real return value untested */
542 if (size
<= dir_len
) size
= dir_len
+ 1;
543 if (!(buf
= MSVCRT_malloc( size
))) return NULL
;
545 else if (dir_len
>= size
)
547 *MSVCRT__errno() = MSVCRT_ERANGE
;
548 return NULL
; /* buf too small */
554 /*********************************************************************
555 * _wgetcwd (MSVCRT.@)
557 * Unicode version of _getcwd.
559 MSVCRT_wchar_t
* CDECL
_wgetcwd(MSVCRT_wchar_t
* buf
, int size
)
561 MSVCRT_wchar_t dir
[MAX_PATH
];
562 int dir_len
= GetCurrentDirectoryW(MAX_PATH
,dir
);
565 return NULL
; /* FIXME: Real return value untested */
569 if (size
<= dir_len
) size
= dir_len
+ 1;
570 if (!(buf
= MSVCRT_malloc( size
* sizeof(WCHAR
) ))) return NULL
;
574 *MSVCRT__errno() = MSVCRT_ERANGE
;
575 return NULL
; /* buf too small */
581 /*********************************************************************
582 * _getdrive (MSVCRT.@)
584 * Get the current drive number.
590 * Success: The drive letter number from 1 to 26 ("A:" to "Z:").
593 int CDECL
_getdrive(void)
595 WCHAR buffer
[MAX_PATH
];
596 if (GetCurrentDirectoryW( MAX_PATH
, buffer
) &&
597 buffer
[0] >= 'A' && buffer
[0] <= 'z' && buffer
[1] == ':')
598 return toupperW(buffer
[0]) - 'A' + 1;
602 /*********************************************************************
603 * _getdcwd (MSVCRT.@)
605 * Get the current working directory on a given disk.
608 * drive [I] Drive letter to get the current working directory from.
609 * buf [O] Destination for the current working directory.
610 * size [I] Length of drive in characters.
613 * Success: If drive is NULL, returns an allocated string containing the path.
614 * Otherwise populates drive with the path and returns it.
615 * Failure: NULL. errno indicates the error.
617 char* CDECL
_getdcwd(int drive
, char * buf
, int size
)
621 TRACE(":drive %d(%c), size %d\n",drive
, drive
+ 'A' - 1, size
);
623 if (!drive
|| drive
== _getdrive())
624 return _getcwd(buf
,size
); /* current */
628 char drivespec
[4] = {'A', ':', 0};
631 drivespec
[0] += drive
- 1;
632 if (GetDriveTypeA(drivespec
) < DRIVE_REMOVABLE
)
634 *MSVCRT__errno() = MSVCRT_EACCES
;
638 dir_len
= GetFullPathNameA(drivespec
,MAX_PATH
,dir
,&dummy
);
639 if (dir_len
>= size
|| dir_len
< 1)
641 *MSVCRT__errno() = MSVCRT_ERANGE
;
642 return NULL
; /* buf too small */
645 TRACE(":returning '%s'\n", dir
);
647 return _strdup(dir
); /* allocate */
654 /*********************************************************************
655 * _wgetdcwd (MSVCRT.@)
657 * Unicode version of _wgetdcwd.
659 MSVCRT_wchar_t
* CDECL
_wgetdcwd(int drive
, MSVCRT_wchar_t
* buf
, int size
)
661 static MSVCRT_wchar_t
* dummy
;
663 TRACE(":drive %d(%c), size %d\n",drive
, drive
+ 'A' - 1, size
);
665 if (!drive
|| drive
== _getdrive())
666 return _wgetcwd(buf
,size
); /* current */
669 MSVCRT_wchar_t dir
[MAX_PATH
];
670 MSVCRT_wchar_t drivespec
[4] = {'A', ':', '\\', 0};
673 drivespec
[0] += drive
- 1;
674 if (GetDriveTypeW(drivespec
) < DRIVE_REMOVABLE
)
676 *MSVCRT__errno() = MSVCRT_EACCES
;
680 dir_len
= GetFullPathNameW(drivespec
,MAX_PATH
,dir
,&dummy
);
681 if (dir_len
>= size
|| dir_len
< 1)
683 *MSVCRT__errno() = MSVCRT_ERANGE
;
684 return NULL
; /* buf too small */
687 TRACE(":returning %s\n", debugstr_w(dir
));
689 return _wcsdup(dir
); /* allocate */
695 /*********************************************************************
696 * _getdiskfree (MSVCRT.@)
698 * Get information about the free space on a drive.
701 * disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
702 * info [O] Destination for the resulting information.
705 * Success: 0. info is updated with the free space information.
706 * Failure: An error code from GetLastError().
709 * See GetLastError().
711 unsigned int CDECL
MSVCRT__getdiskfree(unsigned int disk
, struct MSVCRT__diskfree_t
* d
)
713 WCHAR drivespec
[4] = {'@', ':', '\\', 0};
718 return ERROR_INVALID_PARAMETER
; /* MSVCRT doesn't set errno here */
720 drivespec
[0] += disk
; /* make a drive letter */
722 if (GetDiskFreeSpaceW(disk
==0?NULL
:drivespec
,ret
,ret
+1,ret
+2,ret
+3))
724 d
->sectors_per_cluster
= ret
[0];
725 d
->bytes_per_sector
= ret
[1];
726 d
->avail_clusters
= ret
[2];
727 d
->total_clusters
= ret
[3];
730 err
= GetLastError();
731 msvcrt_set_errno(err
);
735 /*********************************************************************
738 * Create a directory.
741 * newdir [I] Name of directory to create.
744 * Success: 0. The directory indicated by newdir is created.
745 * Failure: -1. errno indicates the error.
748 * See CreateDirectoryA.
750 int CDECL
MSVCRT__mkdir(const char * newdir
)
752 if (CreateDirectoryA(newdir
,NULL
))
754 msvcrt_set_errno(GetLastError());
758 /*********************************************************************
761 * Unicode version of _mkdir.
763 int CDECL
_wmkdir(const MSVCRT_wchar_t
* newdir
)
765 if (CreateDirectoryW(newdir
,NULL
))
767 msvcrt_set_errno(GetLastError());
771 /*********************************************************************
774 * Delete a directory.
777 * dir [I] Name of directory to delete.
780 * Success: 0. The directory indicated by newdir is deleted.
781 * Failure: -1. errno indicates the error.
784 * See RemoveDirectoryA.
786 int CDECL
MSVCRT__rmdir(const char * dir
)
788 if (RemoveDirectoryA(dir
))
790 msvcrt_set_errno(GetLastError());
794 /*********************************************************************
797 * Unicode version of _rmdir.
799 int CDECL
_wrmdir(const MSVCRT_wchar_t
* dir
)
801 if (RemoveDirectoryW(dir
))
803 msvcrt_set_errno(GetLastError());
807 /******************************************************************
808 * _splitpath_s (MSVCRT.@)
810 int _splitpath_s(const char* inpath
,
811 char* drive
, MSVCRT_size_t sz_drive
,
812 char* dir
, MSVCRT_size_t sz_dir
,
813 char* fname
, MSVCRT_size_t sz_fname
,
814 char* ext
, MSVCRT_size_t sz_ext
)
818 if (!inpath
|| (!drive
&& sz_drive
) ||
819 (drive
&& !sz_drive
) ||
822 (!fname
&& sz_fname
) ||
823 (fname
&& !sz_fname
) ||
827 *MSVCRT__errno() = MSVCRT_EINVAL
;
828 return MSVCRT_EINVAL
;
831 if (inpath
[0] && inpath
[1] == ':')
835 if (sz_drive
<= 2) goto do_error
;
836 drive
[0] = inpath
[0];
837 drive
[1] = inpath
[1];
842 else if (drive
) drive
[0] = '\0';
844 /* look for end of directory part */
846 for (p
= inpath
; *p
; p
++) if (*p
== '/' || *p
== '\\') end
= p
+ 1;
848 if (end
) /* got a directory */
852 if (sz_dir
<= end
- inpath
) goto do_error
;
853 memcpy( dir
, inpath
, (end
- inpath
) );
854 dir
[end
- inpath
] = 0;
858 else if (dir
) dir
[0] = 0;
860 /* look for extension: what's after the last dot */
862 for (p
= inpath
; *p
; p
++) if (*p
== '.') end
= p
;
864 if (!end
) end
= p
; /* there's no extension */
868 if (sz_fname
<= end
- inpath
) goto do_error
;
869 memcpy( fname
, inpath
, (end
- inpath
) );
870 fname
[end
- inpath
] = 0;
874 if (sz_ext
<= strlen(end
)) goto do_error
;
879 if (drive
) drive
[0] = '\0';
880 if (dir
) dir
[0] = '\0';
881 if (fname
) fname
[0]= '\0';
882 if (ext
) ext
[0]= '\0';
883 *MSVCRT__errno() = MSVCRT_ERANGE
;
884 return MSVCRT_ERANGE
;
887 /*********************************************************************
888 * _splitpath (MSVCRT.@)
890 void CDECL
_splitpath(const char *inpath
, char *drv
, char *dir
,
891 char *fname
, char *ext
)
893 _splitpath_s(inpath
, drv
, drv
?MSVCRT__MAX_DRIVE
:0, dir
, dir
?MSVCRT__MAX_DIR
:0,
894 fname
, fname
?MSVCRT__MAX_FNAME
:0, ext
, ext
?MSVCRT__MAX_EXT
:0);
897 /******************************************************************
898 * _wsplitpath_s (MSVCRT.@)
900 * Secure version of _wsplitpath
902 int _wsplitpath_s(const MSVCRT_wchar_t
* inpath
,
903 MSVCRT_wchar_t
* drive
, MSVCRT_size_t sz_drive
,
904 MSVCRT_wchar_t
* dir
, MSVCRT_size_t sz_dir
,
905 MSVCRT_wchar_t
* fname
, MSVCRT_size_t sz_fname
,
906 MSVCRT_wchar_t
* ext
, MSVCRT_size_t sz_ext
)
908 const MSVCRT_wchar_t
*p
, *end
;
910 if (!inpath
|| (!drive
&& sz_drive
) ||
911 (drive
&& !sz_drive
) ||
914 (!fname
&& sz_fname
) ||
915 (fname
&& !sz_fname
) ||
919 *MSVCRT__errno() = MSVCRT_EINVAL
;
920 return MSVCRT_EINVAL
;
923 if (inpath
[0] && inpath
[1] == ':')
927 if (sz_drive
<= 2) goto do_error
;
928 drive
[0] = inpath
[0];
929 drive
[1] = inpath
[1];
934 else if (drive
) drive
[0] = '\0';
936 /* look for end of directory part */
938 for (p
= inpath
; *p
; p
++) if (*p
== '/' || *p
== '\\') end
= p
+ 1;
940 if (end
) /* got a directory */
944 if (sz_dir
<= end
- inpath
) goto do_error
;
945 memcpy( dir
, inpath
, (end
- inpath
) * sizeof(MSVCRT_wchar_t
) );
946 dir
[end
- inpath
] = 0;
950 else if (dir
) dir
[0] = 0;
952 /* look for extension: what's after the last dot */
954 for (p
= inpath
; *p
; p
++) if (*p
== '.') end
= p
;
956 if (!end
) end
= p
; /* there's no extension */
960 if (sz_fname
<= end
- inpath
) goto do_error
;
961 memcpy( fname
, inpath
, (end
- inpath
) * sizeof(MSVCRT_wchar_t
) );
962 fname
[end
- inpath
] = 0;
966 if (sz_ext
<= strlenW(end
)) goto do_error
;
971 if (drive
) drive
[0] = '\0';
972 if (dir
) dir
[0] = '\0';
973 if (fname
) fname
[0]= '\0';
974 if (ext
) ext
[0]= '\0';
975 *MSVCRT__errno() = MSVCRT_ERANGE
;
976 return MSVCRT_ERANGE
;
979 /*********************************************************************
980 * _wsplitpath (MSVCRT.@)
982 * Unicode version of _splitpath.
984 void CDECL
_wsplitpath(const MSVCRT_wchar_t
*inpath
, MSVCRT_wchar_t
*drv
, MSVCRT_wchar_t
*dir
,
985 MSVCRT_wchar_t
*fname
, MSVCRT_wchar_t
*ext
)
987 _wsplitpath_s(inpath
, drv
, drv
?MSVCRT__MAX_DRIVE
:0, dir
, dir
?MSVCRT__MAX_DIR
:0,
988 fname
, fname
?MSVCRT__MAX_FNAME
:0, ext
, ext
?MSVCRT__MAX_EXT
:0);
991 /*********************************************************************
992 * _wfullpath (MSVCRT.@)
994 * Unicode version of _fullpath.
996 MSVCRT_wchar_t
* CDECL
_wfullpath(MSVCRT_wchar_t
* absPath
, const MSVCRT_wchar_t
* relPath
, MSVCRT_size_t size
)
1001 BOOL alloced
= FALSE
;
1003 if (!relPath
|| !*relPath
)
1004 return _wgetcwd(absPath
, size
);
1006 if (absPath
== NULL
)
1008 buffer
= MSVCRT_malloc(MAX_PATH
* sizeof(WCHAR
));
1017 *MSVCRT__errno() = MSVCRT_ERANGE
;
1021 TRACE(":resolving relative path %s\n",debugstr_w(relPath
));
1023 rc
= GetFullPathNameW(relPath
,size
,buffer
,&lastpart
);
1025 if (rc
> 0 && rc
<= size
)
1030 MSVCRT_free(buffer
);
1035 /*********************************************************************
1036 * _fullpath (MSVCRT.@)
1038 * Create an absolute path from a relative path.
1041 * absPath [O] Destination for absolute path
1042 * relPath [I] Relative path to convert to absolute
1043 * size [I] Length of absPath in characters.
1046 * Success: If absPath is NULL, returns an allocated string containing the path.
1047 * Otherwise populates absPath with the path and returns it.
1048 * Failure: NULL. errno indicates the error.
1050 char * CDECL
_fullpath(char * absPath
, const char* relPath
, unsigned int size
)
1055 BOOL alloced
= FALSE
;
1057 if (!relPath
|| !*relPath
)
1058 return _getcwd(absPath
, size
);
1060 if (absPath
== NULL
)
1062 buffer
= MSVCRT_malloc(MAX_PATH
);
1071 *MSVCRT__errno() = MSVCRT_ERANGE
;
1075 TRACE(":resolving relative path '%s'\n",relPath
);
1077 rc
= GetFullPathNameA(relPath
,size
,buffer
,&lastpart
);
1079 if (rc
> 0 && rc
<= size
)
1084 MSVCRT_free(buffer
);
1089 /*********************************************************************
1090 * _makepath (MSVCRT.@)
1092 * Create a pathname.
1095 * path [O] Destination for created pathname
1096 * drive [I] Drive letter (e.g. "A:")
1097 * directory [I] Directory
1098 * filename [I] Name of the file, excluding extension
1099 * extension [I] File extension (e.g. ".TXT")
1102 * Nothing. If path is not large enough to hold the resulting pathname,
1103 * random process memory will be overwritten.
1105 VOID CDECL
_makepath(char * path
, const char * drive
,
1106 const char *directory
, const char * filename
,
1107 const char * extension
)
1111 TRACE("(%s %s %s %s)\n", debugstr_a(drive
), debugstr_a(directory
),
1112 debugstr_a(filename
), debugstr_a(extension
) );
1117 if (drive
&& drive
[0])
1122 if (directory
&& directory
[0])
1124 unsigned int len
= strlen(directory
);
1125 memmove(p
, directory
, len
);
1127 if (p
[-1] != '/' && p
[-1] != '\\')
1130 if (filename
&& filename
[0])
1132 unsigned int len
= strlen(filename
);
1133 memmove(p
, filename
, len
);
1136 if (extension
&& extension
[0])
1138 if (extension
[0] != '.')
1140 strcpy(p
, extension
);
1144 TRACE("returning %s\n",path
);
1147 /*********************************************************************
1148 * _wmakepath (MSVCRT.@)
1150 * Unicode version of _wmakepath.
1152 VOID CDECL
_wmakepath(MSVCRT_wchar_t
*path
, const MSVCRT_wchar_t
*drive
, const MSVCRT_wchar_t
*directory
,
1153 const MSVCRT_wchar_t
*filename
, const MSVCRT_wchar_t
*extension
)
1155 MSVCRT_wchar_t
*p
= path
;
1157 TRACE("%s %s %s %s\n", debugstr_w(drive
), debugstr_w(directory
),
1158 debugstr_w(filename
), debugstr_w(extension
));
1163 if (drive
&& drive
[0])
1168 if (directory
&& directory
[0])
1170 unsigned int len
= strlenW(directory
);
1171 memmove(p
, directory
, len
* sizeof(MSVCRT_wchar_t
));
1173 if (p
[-1] != '/' && p
[-1] != '\\')
1176 if (filename
&& filename
[0])
1178 unsigned int len
= strlenW(filename
);
1179 memmove(p
, filename
, len
* sizeof(MSVCRT_wchar_t
));
1182 if (extension
&& extension
[0])
1184 if (extension
[0] != '.')
1186 strcpyW(p
, extension
);
1191 TRACE("returning %s\n", debugstr_w(path
));
1194 /*********************************************************************
1195 * _makepath_s (MSVCRT.@)
1197 * Safe version of _makepath.
1199 int CDECL
_makepath_s(char *path
, MSVCRT_size_t size
, const char *drive
,
1200 const char *directory
, const char *filename
,
1201 const char *extension
)
1207 *MSVCRT__errno() = MSVCRT_EINVAL
;
1208 return MSVCRT_EINVAL
;
1211 if (drive
&& drive
[0])
1221 if (directory
&& directory
[0])
1223 unsigned int len
= strlen(directory
);
1224 unsigned int needs_separator
= directory
[len
- 1] != '/' && directory
[len
- 1] != '\\';
1225 unsigned int copylen
= min(size
- 1, len
);
1230 memmove(p
, directory
, copylen
);
1238 if (needs_separator
)
1248 if (filename
&& filename
[0])
1250 unsigned int len
= strlen(filename
);
1251 unsigned int copylen
= min(size
- 1, len
);
1256 memmove(p
, filename
, copylen
);
1265 if (extension
&& extension
[0])
1267 unsigned int len
= strlen(extension
);
1268 unsigned int needs_period
= extension
[0] != '.';
1269 unsigned int copylen
;
1280 copylen
= min(size
- 1, len
);
1281 memcpy(p
, extension
, copylen
);
1294 *MSVCRT__errno() = MSVCRT_ERANGE
;
1295 return MSVCRT_ERANGE
;
1298 /*********************************************************************
1299 * _wmakepath_s (MSVCRT.@)
1301 * Safe version of _wmakepath.
1303 int CDECL
_wmakepath_s(MSVCRT_wchar_t
*path
, MSVCRT_size_t size
, const MSVCRT_wchar_t
*drive
,
1304 const MSVCRT_wchar_t
*directory
, const MSVCRT_wchar_t
*filename
,
1305 const MSVCRT_wchar_t
*extension
)
1307 MSVCRT_wchar_t
*p
= path
;
1311 *MSVCRT__errno() = MSVCRT_EINVAL
;
1312 return MSVCRT_EINVAL
;
1315 if (drive
&& drive
[0])
1325 if (directory
&& directory
[0])
1327 unsigned int len
= strlenW(directory
);
1328 unsigned int needs_separator
= directory
[len
- 1] != '/' && directory
[len
- 1] != '\\';
1329 unsigned int copylen
= min(size
- 1, len
);
1334 memmove(p
, directory
, copylen
* sizeof(MSVCRT_wchar_t
));
1342 if (needs_separator
)
1352 if (filename
&& filename
[0])
1354 unsigned int len
= strlenW(filename
);
1355 unsigned int copylen
= min(size
- 1, len
);
1360 memmove(p
, filename
, copylen
* sizeof(MSVCRT_wchar_t
));
1369 if (extension
&& extension
[0])
1371 unsigned int len
= strlenW(extension
);
1372 unsigned int needs_period
= extension
[0] != '.';
1373 unsigned int copylen
;
1384 copylen
= min(size
- 1, len
);
1385 memcpy(p
, extension
, copylen
* sizeof(MSVCRT_wchar_t
));
1398 *MSVCRT__errno() = MSVCRT_ERANGE
;
1399 return MSVCRT_ERANGE
;
1402 /*********************************************************************
1403 * _searchenv (MSVCRT.@)
1405 * Search for a file in a list of paths from an environment variable.
1408 * file [I] Name of the file to search for.
1409 * env [I] Name of the environment variable containing a list of paths.
1410 * buf [O] Destination for the found file path.
1413 * Nothing. If the file is not found, buf will contain an empty string
1416 void CDECL
_searchenv(const char* file
, const char* env
, char *buf
)
1419 char curPath
[MAX_PATH
];
1424 if (GetFileAttributesA( file
) != INVALID_FILE_ATTRIBUTES
)
1426 GetFullPathNameA( file
, MAX_PATH
, buf
, NULL
);
1427 /* Sigh. This error is *always* set, regardless of success */
1428 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1432 /* Search given environment variable */
1433 envVal
= MSVCRT_getenv(env
);
1436 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1441 TRACE(":searching for %s in paths %s\n", file
, envVal
);
1447 while(*end
&& *end
!= ';') end
++; /* Find end of next path */
1448 if (penv
== end
|| !*penv
)
1450 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1453 memcpy(curPath
, penv
, end
- penv
);
1454 if (curPath
[end
- penv
] != '/' && curPath
[end
- penv
] != '\\')
1456 curPath
[end
- penv
] = '\\';
1457 curPath
[end
- penv
+ 1] = '\0';
1460 curPath
[end
- penv
] = '\0';
1462 strcat(curPath
, file
);
1463 TRACE("Checking for file %s\n", curPath
);
1464 if (GetFileAttributesA( curPath
) != INVALID_FILE_ATTRIBUTES
)
1466 strcpy(buf
, curPath
);
1467 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1470 penv
= *end
? end
+ 1 : end
;
1474 /*********************************************************************
1475 * _searchenv_s (MSVCRT.@)
1477 int CDECL
_searchenv_s(const char* file
, const char* env
, char *buf
, MSVCRT_size_t count
)
1480 char curPath
[MAX_PATH
];
1482 if (!MSVCRT_CHECK_PMT(file
!= NULL
) || !MSVCRT_CHECK_PMT(buf
!= NULL
) ||
1483 !MSVCRT_CHECK_PMT(count
> 0))
1485 *MSVCRT__errno() = MSVCRT_EINVAL
;
1486 return MSVCRT_EINVAL
;
1492 if (GetFileAttributesA( file
) != INVALID_FILE_ATTRIBUTES
)
1494 if (GetFullPathNameA( file
, count
, buf
, NULL
)) return 0;
1495 msvcrt_set_errno(GetLastError());
1499 /* Search given environment variable */
1500 envVal
= MSVCRT_getenv(env
);
1503 *MSVCRT__errno() = MSVCRT_ENOENT
;
1504 return MSVCRT_ENOENT
;
1508 TRACE(":searching for %s in paths %s\n", file
, envVal
);
1514 while(*end
&& *end
!= ';') end
++; /* Find end of next path */
1515 if (penv
== end
|| !*penv
)
1517 *MSVCRT__errno() = MSVCRT_ENOENT
;
1518 return MSVCRT_ENOENT
;
1520 memcpy(curPath
, penv
, end
- penv
);
1521 if (curPath
[end
- penv
] != '/' && curPath
[end
- penv
] != '\\')
1523 curPath
[end
- penv
] = '\\';
1524 curPath
[end
- penv
+ 1] = '\0';
1527 curPath
[end
- penv
] = '\0';
1529 strcat(curPath
, file
);
1530 TRACE("Checking for file %s\n", curPath
);
1531 if (GetFileAttributesA( curPath
) != INVALID_FILE_ATTRIBUTES
)
1533 if (strlen(curPath
) + 1 > count
)
1535 MSVCRT_INVALID_PMT("buf[count] is too small");
1536 *MSVCRT__errno() = MSVCRT_ERANGE
;
1537 return MSVCRT_ERANGE
;
1539 strcpy(buf
, curPath
);
1542 penv
= *end
? end
+ 1 : end
;
1546 /*********************************************************************
1547 * _wsearchenv (MSVCRT.@)
1549 * Unicode version of _searchenv
1551 void CDECL
_wsearchenv(const MSVCRT_wchar_t
* file
, const MSVCRT_wchar_t
* env
, MSVCRT_wchar_t
*buf
)
1553 MSVCRT_wchar_t
*envVal
, *penv
;
1554 MSVCRT_wchar_t curPath
[MAX_PATH
];
1559 if (GetFileAttributesW( file
) != INVALID_FILE_ATTRIBUTES
)
1561 GetFullPathNameW( file
, MAX_PATH
, buf
, NULL
);
1562 /* Sigh. This error is *always* set, regardless of success */
1563 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1567 /* Search given environment variable */
1568 envVal
= _wgetenv(env
);
1571 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1576 TRACE(":searching for %s in paths %s\n", debugstr_w(file
), debugstr_w(envVal
));
1580 MSVCRT_wchar_t
*end
= penv
;
1582 while(*end
&& *end
!= ';') end
++; /* Find end of next path */
1583 if (penv
== end
|| !*penv
)
1585 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1588 memcpy(curPath
, penv
, (end
- penv
) * sizeof(MSVCRT_wchar_t
));
1589 if (curPath
[end
- penv
] != '/' && curPath
[end
- penv
] != '\\')
1591 curPath
[end
- penv
] = '\\';
1592 curPath
[end
- penv
+ 1] = '\0';
1595 curPath
[end
- penv
] = '\0';
1597 strcatW(curPath
, file
);
1598 TRACE("Checking for file %s\n", debugstr_w(curPath
));
1599 if (GetFileAttributesW( curPath
) != INVALID_FILE_ATTRIBUTES
)
1601 strcpyW(buf
, curPath
);
1602 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1605 penv
= *end
? end
+ 1 : end
;
1609 /*********************************************************************
1610 * _wsearchenv_s (MSVCRT.@)
1612 int CDECL
_wsearchenv_s(const MSVCRT_wchar_t
* file
, const MSVCRT_wchar_t
* env
,
1613 MSVCRT_wchar_t
*buf
, MSVCRT_size_t count
)
1615 MSVCRT_wchar_t
* envVal
, *penv
;
1616 MSVCRT_wchar_t curPath
[MAX_PATH
];
1618 if (!MSVCRT_CHECK_PMT(file
!= NULL
) || !MSVCRT_CHECK_PMT(buf
!= NULL
) ||
1619 !MSVCRT_CHECK_PMT(count
> 0))
1621 *MSVCRT__errno() = MSVCRT_EINVAL
;
1622 return MSVCRT_EINVAL
;
1627 if (GetFileAttributesW( file
) != INVALID_FILE_ATTRIBUTES
)
1629 if (GetFullPathNameW( file
, count
, buf
, NULL
)) return 0;
1630 msvcrt_set_errno(GetLastError());
1634 /* Search given environment variable */
1635 envVal
= _wgetenv(env
);
1638 *MSVCRT__errno() = MSVCRT_ENOENT
;
1639 return MSVCRT_ENOENT
;
1643 TRACE(":searching for %s in paths %s\n", debugstr_w(file
), debugstr_w(envVal
));
1647 MSVCRT_wchar_t
*end
= penv
;
1649 while(*end
&& *end
!= ';') end
++; /* Find end of next path */
1650 if (penv
== end
|| !*penv
)
1652 *MSVCRT__errno() = MSVCRT_ENOENT
;
1653 return MSVCRT_ENOENT
;
1655 memcpy(curPath
, penv
, (end
- penv
) * sizeof(MSVCRT_wchar_t
));
1656 if (curPath
[end
- penv
] != '/' && curPath
[end
- penv
] != '\\')
1658 curPath
[end
- penv
] = '\\';
1659 curPath
[end
- penv
+ 1] = '\0';
1662 curPath
[end
- penv
] = '\0';
1664 strcatW(curPath
, file
);
1665 TRACE("Checking for file %s\n", debugstr_w(curPath
));
1666 if (GetFileAttributesW( curPath
) != INVALID_FILE_ATTRIBUTES
)
1668 if (strlenW(curPath
) + 1 > count
)
1670 MSVCRT_INVALID_PMT("buf[count] is too small");
1671 *MSVCRT__errno() = MSVCRT_ERANGE
;
1672 return MSVCRT_ERANGE
;
1674 strcpyW(buf
, curPath
);
1677 penv
= *end
? end
+ 1 : end
;