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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "wine/port.h"
34 #include "wine/unicode.h"
36 #include "msvcrt/errno.h"
38 #include "wine/unicode.h"
39 #include "msvcrt/io.h"
40 #include "msvcrt/stdlib.h"
41 #include "msvcrt/string.h"
42 #include "msvcrt/dos.h"
44 #include "wine/debug.h"
46 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
48 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata_t */
49 static void msvcrt_fttofd( const WIN32_FIND_DATAA
*fd
, struct MSVCRT__finddata_t
* ft
)
53 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
56 ft
->attrib
= fd
->dwFileAttributes
;
58 RtlTimeToSecondsSince1970( (LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
60 RtlTimeToSecondsSince1970( (LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
62 RtlTimeToSecondsSince1970( (LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
64 ft
->size
= fd
->nFileSizeLow
;
65 strcpy(ft
->name
, fd
->cFileName
);
68 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata_t */
69 static void msvcrt_wfttofd( const WIN32_FIND_DATAW
*fd
, struct MSVCRT__wfinddata_t
* ft
)
73 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
76 ft
->attrib
= fd
->dwFileAttributes
;
78 RtlTimeToSecondsSince1970( (LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
80 RtlTimeToSecondsSince1970( (LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
82 RtlTimeToSecondsSince1970( (LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
84 ft
->size
= fd
->nFileSizeLow
;
85 strcpyW(ft
->name
, fd
->cFileName
);
88 /* INTERNAL: Translate WIN32_FIND_DATAA to finddatai64_t */
89 static void msvcrt_fttofdi64( const WIN32_FIND_DATAA
*fd
, struct MSVCRT__finddatai64_t
* ft
)
93 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
96 ft
->attrib
= fd
->dwFileAttributes
;
98 RtlTimeToSecondsSince1970( (LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
100 RtlTimeToSecondsSince1970( (LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
101 ft
->time_access
= dw
;
102 RtlTimeToSecondsSince1970( (LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
104 ft
->size
= ((__int64
)fd
->nFileSizeHigh
) << 32 | fd
->nFileSizeLow
;
105 strcpy(ft
->name
, fd
->cFileName
);
108 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddatai64_t */
109 static void msvcrt_wfttofdi64( const WIN32_FIND_DATAW
*fd
, struct MSVCRT__wfinddatai64_t
* ft
)
113 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
116 ft
->attrib
= fd
->dwFileAttributes
;
118 RtlTimeToSecondsSince1970( (LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
119 ft
->time_create
= dw
;
120 RtlTimeToSecondsSince1970( (LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
121 ft
->time_access
= dw
;
122 RtlTimeToSecondsSince1970( (LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
124 ft
->size
= ((__int64
)fd
->nFileSizeHigh
) << 32 | fd
->nFileSizeLow
;
125 strcpyW(ft
->name
, fd
->cFileName
);
128 /*********************************************************************
131 * Change the current working directory.
134 * newdir [I] Directory to change to
137 * Success: 0. The current working directory is set to newdir.
138 * Failure: -1. errno indicates the error.
141 * See SetCurrentDirectoryA.
143 int _chdir(const char * newdir
)
145 if (!SetCurrentDirectoryA(newdir
))
147 MSVCRT__set_errno(newdir
?GetLastError():0);
153 /*********************************************************************
156 * Unicode version of _chdir.
158 int _wchdir(const MSVCRT_wchar_t
* newdir
)
160 if (!SetCurrentDirectoryW(newdir
))
162 MSVCRT__set_errno(newdir
?GetLastError():0);
168 /*********************************************************************
169 * _chdrive (MSVCRT.@)
171 * Change the current drive.
174 * newdrive [I] Drive number to change to (1 = 'A', 2 = 'B', ...)
177 * Success: 0. The current drive is set to newdrive.
178 * Failure: -1. errno indicates the error.
181 * See SetCurrentDirectoryA.
183 int _chdrive(int newdrive
)
185 WCHAR buffer
[3] = {'A', ':', 0};
187 buffer
[0] += newdrive
- 1;
188 if (!SetCurrentDirectoryW( buffer
))
190 MSVCRT__set_errno(GetLastError());
192 *MSVCRT__errno() = MSVCRT_EACCES
;
198 /*********************************************************************
199 * _findclose (MSVCRT.@)
201 * Close a handle returned by _findfirst().
204 * hand [I] Handle to close
207 * Success: 0. All resources associated with hand are freed.
208 * Failure: -1. errno indicates the error.
213 int _findclose(long hand
)
215 TRACE(":handle %ld\n",hand
);
216 if (!FindClose((HANDLE
)hand
))
218 MSVCRT__set_errno(GetLastError());
224 /*********************************************************************
225 * _findfirst (MSVCRT.@)
227 * Open a handle for iterating through a directory.
230 * fspec [I] File specification of files to iterate.
231 * ft [O] Information for the first file found.
234 * Success: A handle suitable for passing to _findnext() and _findclose().
235 * ft is populated with the details of the found file.
236 * Failure: -1. errno indicates the error.
239 * See FindFirstFileA.
241 long MSVCRT__findfirst(const char * fspec
, struct MSVCRT__finddata_t
* ft
)
243 WIN32_FIND_DATAA find_data
;
246 hfind
= FindFirstFileA(fspec
, &find_data
);
247 if (hfind
== INVALID_HANDLE_VALUE
)
249 MSVCRT__set_errno(GetLastError());
252 msvcrt_fttofd(&find_data
,ft
);
253 TRACE(":got handle %p\n",hfind
);
257 /*********************************************************************
258 * _wfindfirst (MSVCRT.@)
260 * Unicode version of _findfirst.
262 long MSVCRT__wfindfirst(const MSVCRT_wchar_t
* fspec
, struct MSVCRT__wfinddata_t
* ft
)
264 WIN32_FIND_DATAW find_data
;
267 hfind
= FindFirstFileW(fspec
, &find_data
);
268 if (hfind
== INVALID_HANDLE_VALUE
)
270 MSVCRT__set_errno(GetLastError());
273 msvcrt_wfttofd(&find_data
,ft
);
274 TRACE(":got handle %p\n",hfind
);
278 /*********************************************************************
279 * _findfirsti64 (MSVCRT.@)
281 * 64-bit version of _findfirst.
283 long MSVCRT__findfirsti64(const char * fspec
, struct MSVCRT__finddatai64_t
* ft
)
285 WIN32_FIND_DATAA find_data
;
288 hfind
= FindFirstFileA(fspec
, &find_data
);
289 if (hfind
== INVALID_HANDLE_VALUE
)
291 MSVCRT__set_errno(GetLastError());
294 msvcrt_fttofdi64(&find_data
,ft
);
295 TRACE(":got handle %p\n",hfind
);
299 /*********************************************************************
300 * _wfindfirsti64 (MSVCRT.@)
302 * Unicode version of _findfirsti64.
304 long MSVCRT__wfindfirsti64(const MSVCRT_wchar_t
* fspec
, struct MSVCRT__wfinddatai64_t
* ft
)
306 WIN32_FIND_DATAW find_data
;
309 hfind
= FindFirstFileW(fspec
, &find_data
);
310 if (hfind
== INVALID_HANDLE_VALUE
)
312 MSVCRT__set_errno(GetLastError());
315 msvcrt_wfttofdi64(&find_data
,ft
);
316 TRACE(":got handle %p\n",hfind
);
320 /*********************************************************************
321 * _findnext (MSVCRT.@)
323 * Find the next file from a file search handle.
326 * hand [I] Handle to the search returned from _findfirst().
327 * ft [O] Information for the file found.
330 * Success: 0. ft is populated with the details of the found file.
331 * Failure: -1. errno indicates the error.
336 int MSVCRT__findnext(long hand
, struct MSVCRT__finddata_t
* ft
)
338 WIN32_FIND_DATAA find_data
;
340 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
342 *MSVCRT__errno() = MSVCRT_ENOENT
;
346 msvcrt_fttofd(&find_data
,ft
);
350 /*********************************************************************
351 * _wfindnext (MSVCRT.@)
353 * Unicode version of _findnext.
355 int MSVCRT__wfindnext(long hand
, struct MSVCRT__wfinddata_t
* ft
)
357 WIN32_FIND_DATAW find_data
;
359 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
361 *MSVCRT__errno() = MSVCRT_ENOENT
;
365 msvcrt_wfttofd(&find_data
,ft
);
369 /*********************************************************************
370 * _findnexti64 (MSVCRT.@)
372 * 64-bit version of _findnext.
374 int MSVCRT__findnexti64(long hand
, struct MSVCRT__finddatai64_t
* ft
)
376 WIN32_FIND_DATAA find_data
;
378 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
380 *MSVCRT__errno() = MSVCRT_ENOENT
;
384 msvcrt_fttofdi64(&find_data
,ft
);
388 /*********************************************************************
389 * _wfindnexti64 (MSVCRT.@)
391 * Unicode version of _findnexti64.
393 int MSVCRT__wfindnexti64(long hand
, struct MSVCRT__wfinddatai64_t
* ft
)
395 WIN32_FIND_DATAW find_data
;
397 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
399 *MSVCRT__errno() = MSVCRT_ENOENT
;
403 msvcrt_wfttofdi64(&find_data
,ft
);
407 /*********************************************************************
410 * Get the current working directory.
413 * buf [O] Destination for current working directory.
414 * size [I] Size of buf in characters
417 * Success: If buf is NULL, returns an allocated string containing the path.
418 * Otherwise populates buf with the path and returns it.
419 * Failure: NULL. errno indicates the error.
421 char* _getcwd(char * buf
, int size
)
424 int dir_len
= GetCurrentDirectoryA(MAX_PATH
,dir
);
427 return NULL
; /* FIXME: Real return value untested */
433 return msvcrt_strndup(dir
,size
);
437 *MSVCRT__errno() = MSVCRT_ERANGE
;
438 return NULL
; /* buf too small */
444 /*********************************************************************
445 * _wgetcwd (MSVCRT.@)
447 * Unicode version of _getcwd.
449 MSVCRT_wchar_t
* _wgetcwd(MSVCRT_wchar_t
* buf
, int size
)
451 MSVCRT_wchar_t dir
[MAX_PATH
];
452 int dir_len
= GetCurrentDirectoryW(MAX_PATH
,dir
);
455 return NULL
; /* FIXME: Real return value untested */
461 return msvcrt_wstrndup(dir
,size
);
465 *MSVCRT__errno() = MSVCRT_ERANGE
;
466 return NULL
; /* buf too small */
472 /*********************************************************************
473 * _getdrive (MSVCRT.@)
475 * Get the current drive number.
481 * Success: The drive letter number from 1 to 26 ("A:" to "Z:").
486 WCHAR buffer
[MAX_PATH
];
487 if (GetCurrentDirectoryW( MAX_PATH
, buffer
) &&
488 buffer
[0] >= 'A' && buffer
[0] <= 'z' && buffer
[1] == ':')
489 return toupperW(buffer
[0]) - 'A' + 1;
493 /*********************************************************************
494 * _getdcwd (MSVCRT.@)
496 * Get the current working directory on a given disk.
499 * drive [I] Drive letter to get the current working directory from.
500 * buf [O] Destination for the current working directory.
501 * size [I] Length of drive in characters.
504 * Success: If drive is NULL, returns an allocated string containing the path.
505 * Otherwise populates drive with the path and returns it.
506 * Failure: NULL. errno indicates the error.
508 char* _getdcwd(int drive
, char * buf
, int size
)
512 TRACE(":drive %d(%c), size %d\n",drive
, drive
+ 'A' - 1, size
);
514 if (!drive
|| drive
== _getdrive())
515 return _getcwd(buf
,size
); /* current */
519 char drivespec
[4] = {'A', ':', '\\', 0};
522 drivespec
[0] += drive
- 1;
523 if (GetDriveTypeA(drivespec
) < DRIVE_REMOVABLE
)
525 *MSVCRT__errno() = MSVCRT_EACCES
;
529 dir_len
= GetFullPathNameA(drivespec
,MAX_PATH
,dir
,&dummy
);
530 if (dir_len
>= size
|| dir_len
< 1)
532 *MSVCRT__errno() = MSVCRT_ERANGE
;
533 return NULL
; /* buf too small */
536 TRACE(":returning '%s'\n", dir
);
538 return _strdup(dir
); /* allocate */
545 /*********************************************************************
546 * _wgetdcwd (MSVCRT.@)
548 * Unicode version of _wgetdcwd.
550 MSVCRT_wchar_t
* _wgetdcwd(int drive
, MSVCRT_wchar_t
* buf
, int size
)
552 static MSVCRT_wchar_t
* dummy
;
554 TRACE(":drive %d(%c), size %d\n",drive
, drive
+ 'A' - 1, size
);
556 if (!drive
|| drive
== _getdrive())
557 return _wgetcwd(buf
,size
); /* current */
560 MSVCRT_wchar_t dir
[MAX_PATH
];
561 MSVCRT_wchar_t drivespec
[4] = {'A', ':', '\\', 0};
564 drivespec
[0] += drive
- 1;
565 if (GetDriveTypeW(drivespec
) < DRIVE_REMOVABLE
)
567 *MSVCRT__errno() = MSVCRT_EACCES
;
571 dir_len
= GetFullPathNameW(drivespec
,MAX_PATH
,dir
,&dummy
);
572 if (dir_len
>= size
|| dir_len
< 1)
574 *MSVCRT__errno() = MSVCRT_ERANGE
;
575 return NULL
; /* buf too small */
578 TRACE(":returning %s\n", debugstr_w(dir
));
580 return _wcsdup(dir
); /* allocate */
586 /*********************************************************************
587 * _getdiskfree (MSVCRT.@)
589 * Get information about the free space on a drive.
592 * disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
593 * info [O] Destination for the resulting information.
596 * Success: 0. info is updated with the free space information.
597 * Failure: An error code from GetLastError().
600 * See GetLastError().
602 unsigned int MSVCRT__getdiskfree(unsigned int disk
, struct MSVCRT__diskfree_t
* d
)
604 WCHAR drivespec
[4] = {'@', ':', '\\', 0};
609 return ERROR_INVALID_PARAMETER
; /* MSVCRT doesn't set errno here */
611 drivespec
[0] += disk
; /* make a drive letter */
613 if (GetDiskFreeSpaceW(disk
==0?NULL
:drivespec
,ret
,ret
+1,ret
+2,ret
+3))
615 d
->sectors_per_cluster
= (unsigned)ret
[0];
616 d
->bytes_per_sector
= (unsigned)ret
[1];
617 d
->avail_clusters
= (unsigned)ret
[2];
618 d
->total_clusters
= (unsigned)ret
[3];
621 err
= GetLastError();
622 MSVCRT__set_errno(err
);
626 /*********************************************************************
629 * Create a directory.
632 * newdir [I] Name of directory to create.
635 * Success: 0. The directory indicated by newdir is created.
636 * Failure: -1. errno indicates the error.
639 * See CreateDirectoryA.
641 int _mkdir(const char * newdir
)
643 if (CreateDirectoryA(newdir
,NULL
))
645 MSVCRT__set_errno(GetLastError());
649 /*********************************************************************
652 * Unicode version of _mkdir.
654 int _wmkdir(const MSVCRT_wchar_t
* newdir
)
656 if (CreateDirectoryW(newdir
,NULL
))
658 MSVCRT__set_errno(GetLastError());
662 /*********************************************************************
665 * Delete a directory.
668 * dir [I] Name of directory to delete.
671 * Success: 0. The directory indicated by newdir is deleted.
672 * Failure: -1. errno indicates the error.
675 * See RemoveDirectoryA.
677 int _rmdir(const char * dir
)
679 if (RemoveDirectoryA(dir
))
681 MSVCRT__set_errno(GetLastError());
685 /*********************************************************************
688 * Unicode version of _rmdir.
690 int _wrmdir(const MSVCRT_wchar_t
* dir
)
692 if (RemoveDirectoryW(dir
))
694 MSVCRT__set_errno(GetLastError());
698 /*********************************************************************
699 * _wsplitpath (MSVCRT.@)
701 * Unicode version of _splitpath.
703 void _wsplitpath(const MSVCRT_wchar_t
*inpath
, MSVCRT_wchar_t
*drv
, MSVCRT_wchar_t
*dir
,
704 MSVCRT_wchar_t
*fname
, MSVCRT_wchar_t
*ext
)
706 const MSVCRT_wchar_t
*p
, *end
;
708 if (inpath
[0] && inpath
[1] == ':')
718 else if (drv
) drv
[0] = 0;
720 /* look for end of directory part */
722 for (p
= inpath
; *p
; p
++) if (*p
== '/' || *p
== '\\') end
= p
+ 1;
724 if (end
) /* got a directory */
728 memcpy( dir
, inpath
, (end
- inpath
) * sizeof(MSVCRT_wchar_t
) );
729 dir
[end
- inpath
] = 0;
733 else if (dir
) dir
[0] = 0;
735 /* look for extension: what's after the last dot */
737 for (p
= inpath
; *p
; p
++) if (*p
== '.') end
= p
;
739 if (!end
) end
= p
; /* there's no extension */
743 memcpy( fname
, inpath
, (end
- inpath
) * sizeof(MSVCRT_wchar_t
) );
744 fname
[end
- inpath
] = 0;
746 if (ext
) strcpyW( ext
, end
);
749 /* INTERNAL: Helper for _fullpath. Modified PD code from 'snippets'. */
750 static void wmsvcrt_fln_fix(MSVCRT_wchar_t
*path
)
752 int dir_flag
= 0, root_flag
= 0;
753 MSVCRT_wchar_t
*r
, *p
, *q
, *s
;
754 MSVCRT_wchar_t szbsdot
[] = { '\\', '.', 0 };
757 if (NULL
== (r
= strrchrW(path
, ':')))
762 /* Ignore leading slashes */
772 p
= r
; /* Change "\\" to "\" */
773 while (NULL
!= (p
= strchrW(p
, '\\')))
779 while ('.' == *r
) /* Scrunch leading ".\" */
783 /* Ignore leading ".." */
784 for (p
= (r
+= 2); *p
&& (*p
!= '\\'); ++p
)
789 for (p
= r
+ 1 ;*p
&& (*p
!= '\\'); ++p
)
792 strcpyW(r
, p
+ ((*p
) ? 1 : 0));
795 while ('\\' == path
[strlenW(path
)-1]) /* Strip last '\\' */
798 path
[strlenW(path
)-1] = '\0';
803 /* Look for "\." in path */
805 while (NULL
!= (p
= strstrW(s
, szbsdot
)))
809 /* Execute this section if ".." found */
811 while (q
> r
) /* Backup one level */
824 strcpyW(q
+ ((*q
== '\\') ? 1 : 0),
825 p
+ 3 + ((*(p
+ 3)) ? 1 : 0));
832 /* Execute this section if "." found */
834 for ( ;*q
&& (*q
!= '\\'); ++q
)
840 if (root_flag
) /* Embedded ".." could have bubbled up to root */
842 for (p
= r
; *p
&& ('.' == *p
|| '\\' == *p
); ++p
)
850 MSVCRT_wchar_t szbs
[] = { '\\', 0 };
856 /*********************************************************************
857 * _wfullpath (MSVCRT.@)
859 * Unicode version of _fullpath.
861 MSVCRT_wchar_t
*_wfullpath(MSVCRT_wchar_t
* absPath
, const MSVCRT_wchar_t
* relPath
, MSVCRT_size_t size
)
863 MSVCRT_wchar_t drive
[5],dir
[MAX_PATH
],file
[MAX_PATH
],ext
[MAX_PATH
];
864 MSVCRT_wchar_t res
[MAX_PATH
];
866 MSVCRT_wchar_t szbs
[] = { '\\', 0 };
871 if (!relPath
|| !*relPath
)
872 return _wgetcwd(absPath
, size
);
876 *MSVCRT__errno() = MSVCRT_ERANGE
;
880 TRACE(":resolving relative path '%s'\n",debugstr_w(relPath
));
882 _wsplitpath(relPath
, drive
, dir
, file
, ext
);
884 /* Get Directory and drive into 'res' */
885 if (!dir
[0] || (dir
[0] != '/' && dir
[0] != '\\'))
887 /* Relative or no directory given */
888 _wgetdcwd(drive
[0] ? toupper(drive
[0]) - 'A' + 1 : 0, res
, MAX_PATH
);
893 res
[0] = drive
[0]; /* If given a drive, preserve the letter case */
904 wmsvcrt_fln_fix(res
);
907 if (len
>= MAX_PATH
|| len
>= (size_t)size
)
908 return NULL
; /* FIXME: errno? */
912 strcpyW(absPath
,res
);
916 /* INTERNAL: Helper for _fullpath. Modified PD code from 'snippets'. */
917 static void msvcrt_fln_fix(char *path
)
919 int dir_flag
= 0, root_flag
= 0;
923 if (NULL
== (r
= strrchr(path
, ':')))
928 /* Ignore leading slashes */
938 p
= r
; /* Change "\\" to "\" */
939 while (NULL
!= (p
= strchr(p
, '\\')))
945 while ('.' == *r
) /* Scrunch leading ".\" */
949 /* Ignore leading ".." */
950 for (p
= (r
+= 2); *p
&& (*p
!= '\\'); ++p
)
955 for (p
= r
+ 1 ;*p
&& (*p
!= '\\'); ++p
)
958 strcpy(r
, p
+ ((*p
) ? 1 : 0));
961 while ('\\' == path
[strlen(path
)-1]) /* Strip last '\\' */
964 path
[strlen(path
)-1] = '\0';
969 /* Look for "\." in path */
971 while (NULL
!= (p
= strstr(s
, "\\.")))
975 /* Execute this section if ".." found */
977 while (q
> r
) /* Backup one level */
990 strcpy(q
+ ((*q
== '\\') ? 1 : 0),
991 p
+ 3 + ((*(p
+ 3)) ? 1 : 0));
998 /* Execute this section if "." found */
1000 for ( ;*q
&& (*q
!= '\\'); ++q
)
1006 if (root_flag
) /* Embedded ".." could have bubbled up to root */
1008 for (p
= r
; *p
&& ('.' == *p
|| '\\' == *p
); ++p
)
1018 /*********************************************************************
1019 * _fullpath (MSVCRT.@)
1021 * Create an absolute path from a relative path.
1024 * absPath [O] Destination for absolute path
1025 * relPath [I] Relative path to convert to absolute
1026 * size [I] Length of absPath in characters.
1029 * Success: If absPath is NULL, returns an allocated string containing the path.
1030 * Otherwise populates absPath with the path and returns it.
1031 * Failure: NULL. errno indicates the error.
1033 char *_fullpath(char * absPath
, const char* relPath
, unsigned int size
)
1035 char drive
[5],dir
[MAX_PATH
],file
[MAX_PATH
],ext
[MAX_PATH
];
1041 if (!relPath
|| !*relPath
)
1042 return _getcwd(absPath
, size
);
1046 *MSVCRT__errno() = MSVCRT_ERANGE
;
1050 TRACE(":resolving relative path '%s'\n",relPath
);
1052 _splitpath(relPath
, drive
, dir
, file
, ext
);
1054 /* Get Directory and drive into 'res' */
1055 if (!dir
[0] || (dir
[0] != '/' && dir
[0] != '\\'))
1057 /* Relative or no directory given */
1058 _getdcwd(drive
[0] ? toupper(drive
[0]) - 'A' + 1 : 0, res
, MAX_PATH
);
1063 res
[0] = drive
[0]; /* If given a drive, preserve the letter case */
1074 msvcrt_fln_fix(res
);
1077 if (len
>= MAX_PATH
|| len
>= (size_t)size
)
1078 return NULL
; /* FIXME: errno? */
1081 return _strdup(res
);
1082 strcpy(absPath
,res
);
1086 /*********************************************************************
1087 * _makepath (MSVCRT.@)
1089 * Create a pathname.
1092 * path [O] Destination for created pathname
1093 * drive [I] Drive letter (e.g. "A:")
1094 * directory [I] Directory
1095 * filename [I] Name of the file, excluding extension
1096 * extension [I] File extension (e.g. ".TXT")
1099 * Nothing. If path is not large enough to hold the resulting pathname,
1100 * random process memory will be overwritten.
1102 VOID
_makepath(char * path
, const char * drive
,
1103 const char *directory
, const char * filename
,
1104 const char * extension
)
1107 char tmpPath
[MAX_PATH
];
1108 TRACE("got %s %s %s %s\n", debugstr_a(drive
), debugstr_a(directory
),
1109 debugstr_a(filename
), debugstr_a(extension
) );
1115 if (drive
&& drive
[0])
1117 tmpPath
[0] = drive
[0];
1121 if (directory
&& directory
[0])
1123 strcat(tmpPath
, directory
);
1124 ch
= tmpPath
[strlen(tmpPath
)-1];
1125 if (ch
!= '/' && ch
!= '\\')
1126 strcat(tmpPath
,"\\");
1128 if (filename
&& filename
[0])
1130 strcat(tmpPath
, filename
);
1131 if (extension
&& extension
[0])
1133 if ( extension
[0] != '.' )
1134 strcat(tmpPath
,".");
1135 strcat(tmpPath
,extension
);
1139 strcpy( path
, tmpPath
);
1141 TRACE("returning %s\n",path
);
1144 /*********************************************************************
1145 * _wmakepath (MSVCRT.@)
1147 * Unicode version of _wmakepath.
1149 VOID
_wmakepath(MSVCRT_wchar_t
*path
, const MSVCRT_wchar_t
*drive
, const MSVCRT_wchar_t
*directory
,
1150 const MSVCRT_wchar_t
*filename
, const MSVCRT_wchar_t
*extension
)
1153 TRACE("%s %s %s %s\n", debugstr_w(drive
), debugstr_w(directory
),
1154 debugstr_w(filename
), debugstr_w(extension
));
1160 if (drive
&& drive
[0])
1166 if (directory
&& directory
[0])
1168 strcatW(path
, directory
);
1169 ch
= path
[strlenW(path
) - 1];
1170 if (ch
!= '/' && ch
!= '\\')
1172 static const MSVCRT_wchar_t backslashW
[] = {'\\',0};
1173 strcatW(path
, backslashW
);
1176 if (filename
&& filename
[0])
1178 strcatW(path
, filename
);
1179 if (extension
&& extension
[0])
1181 if ( extension
[0] != '.' )
1183 static const MSVCRT_wchar_t dotW
[] = {'.',0};
1184 strcatW(path
, dotW
);
1186 strcatW(path
, extension
);
1190 TRACE("returning %s\n", debugstr_w(path
));
1193 /*********************************************************************
1194 * _searchenv (MSVCRT.@)
1196 * Search for a file in a list of paths from an envronment variable.
1199 * file [I] Name of the file to search for.
1200 * env [I] Name of the environment variable containing a list of paths.
1201 * buf [O] Destination for the found file path.
1204 * Nothing. If the file is not found, buf will contain an empty string
1207 void _searchenv(const char* file
, const char* env
, char *buf
)
1210 char curPath
[MAX_PATH
];
1215 if (GetFileAttributesA( file
) != INVALID_FILE_ATTRIBUTES
)
1217 GetFullPathNameA( file
, MAX_PATH
, buf
, NULL
);
1218 /* Sigh. This error is *always* set, regardless of success */
1219 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND
);
1223 /* Search given environment variable */
1224 envVal
= MSVCRT_getenv(env
);
1227 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND
);
1232 TRACE(":searching for %s in paths %s\n", file
, envVal
);
1238 while(*end
&& *end
!= ';') end
++; /* Find end of next path */
1239 if (penv
== end
|| !*penv
)
1241 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND
);
1244 strncpy(curPath
, penv
, end
- penv
);
1245 if (curPath
[end
- penv
] != '/' || curPath
[end
- penv
] != '\\')
1247 curPath
[end
- penv
] = '\\';
1248 curPath
[end
- penv
+ 1] = '\0';
1251 curPath
[end
- penv
] = '\0';
1253 strcat(curPath
, file
);
1254 TRACE("Checking for file %s\n", curPath
);
1255 if (GetFileAttributesA( curPath
) != INVALID_FILE_ATTRIBUTES
)
1257 strcpy(buf
, curPath
);
1258 MSVCRT__set_errno(ERROR_FILE_NOT_FOUND
);
1261 penv
= *end
? end
+ 1 : end
;