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"
34 #include "wine/unicode.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
40 /* INTERNAL: Translate WIN32_FIND_DATAA to finddata_t */
41 static void msvcrt_fttofd( const WIN32_FIND_DATAA
*fd
, struct MSVCRT__finddata_t
* ft
)
45 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
48 ft
->attrib
= fd
->dwFileAttributes
;
50 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
52 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
54 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
56 ft
->size
= fd
->nFileSizeLow
;
57 strcpy(ft
->name
, fd
->cFileName
);
60 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddata_t */
61 static void msvcrt_wfttofd( const WIN32_FIND_DATAW
*fd
, struct MSVCRT__wfinddata_t
* ft
)
65 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
68 ft
->attrib
= fd
->dwFileAttributes
;
70 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
72 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
74 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
76 ft
->size
= fd
->nFileSizeLow
;
77 strcpyW(ft
->name
, fd
->cFileName
);
80 /* INTERNAL: Translate WIN32_FIND_DATAA to finddatai64_t */
81 static void msvcrt_fttofdi64( const WIN32_FIND_DATAA
*fd
, struct MSVCRT__finddatai64_t
* ft
)
85 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
88 ft
->attrib
= fd
->dwFileAttributes
;
90 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
92 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
94 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
96 ft
->size
= ((__int64
)fd
->nFileSizeHigh
) << 32 | fd
->nFileSizeLow
;
97 strcpy(ft
->name
, fd
->cFileName
);
100 /* INTERNAL: Translate WIN32_FIND_DATAW to wfinddatai64_t */
101 static void msvcrt_wfttofdi64( const WIN32_FIND_DATAW
*fd
, struct MSVCRT__wfinddatai64_t
* ft
)
105 if (fd
->dwFileAttributes
== FILE_ATTRIBUTE_NORMAL
)
108 ft
->attrib
= fd
->dwFileAttributes
;
110 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftCreationTime
, &dw
);
111 ft
->time_create
= dw
;
112 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastAccessTime
, &dw
);
113 ft
->time_access
= dw
;
114 RtlTimeToSecondsSince1970( (const LARGE_INTEGER
*)&fd
->ftLastWriteTime
, &dw
);
116 ft
->size
= ((__int64
)fd
->nFileSizeHigh
) << 32 | fd
->nFileSizeLow
;
117 strcpyW(ft
->name
, fd
->cFileName
);
120 /*********************************************************************
123 * Change the current working directory.
126 * newdir [I] Directory to change to
129 * Success: 0. The current working directory is set to newdir.
130 * Failure: -1. errno indicates the error.
133 * See SetCurrentDirectoryA.
135 int CDECL
_chdir(const char * newdir
)
137 if (!SetCurrentDirectoryA(newdir
))
139 msvcrt_set_errno(newdir
?GetLastError():0);
145 /*********************************************************************
148 * Unicode version of _chdir.
150 int CDECL
_wchdir(const MSVCRT_wchar_t
* newdir
)
152 if (!SetCurrentDirectoryW(newdir
))
154 msvcrt_set_errno(newdir
?GetLastError():0);
160 /*********************************************************************
161 * _chdrive (MSVCRT.@)
163 * Change the current drive.
166 * newdrive [I] Drive number to change to (1 = 'A', 2 = 'B', ...)
169 * Success: 0. The current drive is set to newdrive.
170 * Failure: -1. errno indicates the error.
173 * See SetCurrentDirectoryA.
175 int CDECL
_chdrive(int newdrive
)
177 WCHAR buffer
[3] = {'A', ':', 0};
179 buffer
[0] += newdrive
- 1;
180 if (!SetCurrentDirectoryW( buffer
))
182 msvcrt_set_errno(GetLastError());
184 *MSVCRT__errno() = MSVCRT_EACCES
;
190 /*********************************************************************
191 * _findclose (MSVCRT.@)
193 * Close a handle returned by _findfirst().
196 * hand [I] Handle to close
199 * Success: 0. All resources associated with hand are freed.
200 * Failure: -1. errno indicates the error.
205 int CDECL
MSVCRT__findclose(long hand
)
207 TRACE(":handle %ld\n",hand
);
208 if (!FindClose((HANDLE
)hand
))
210 msvcrt_set_errno(GetLastError());
216 /*********************************************************************
217 * _findfirst (MSVCRT.@)
219 * Open a handle for iterating through a directory.
222 * fspec [I] File specification of files to iterate.
223 * ft [O] Information for the first file found.
226 * Success: A handle suitable for passing to _findnext() and _findclose().
227 * ft is populated with the details of the found file.
228 * Failure: -1. errno indicates the error.
231 * See FindFirstFileA.
233 long CDECL
MSVCRT__findfirst(const char * fspec
, struct MSVCRT__finddata_t
* ft
)
235 WIN32_FIND_DATAA find_data
;
238 hfind
= FindFirstFileA(fspec
, &find_data
);
239 if (hfind
== INVALID_HANDLE_VALUE
)
241 msvcrt_set_errno(GetLastError());
244 msvcrt_fttofd(&find_data
,ft
);
245 TRACE(":got handle %p\n",hfind
);
249 /*********************************************************************
250 * _wfindfirst (MSVCRT.@)
252 * Unicode version of _findfirst.
254 long CDECL
MSVCRT__wfindfirst(const MSVCRT_wchar_t
* fspec
, struct MSVCRT__wfinddata_t
* ft
)
256 WIN32_FIND_DATAW find_data
;
259 hfind
= FindFirstFileW(fspec
, &find_data
);
260 if (hfind
== INVALID_HANDLE_VALUE
)
262 msvcrt_set_errno(GetLastError());
265 msvcrt_wfttofd(&find_data
,ft
);
266 TRACE(":got handle %p\n",hfind
);
270 /*********************************************************************
271 * _findfirsti64 (MSVCRT.@)
273 * 64-bit version of _findfirst.
275 long CDECL
MSVCRT__findfirsti64(const char * fspec
, struct MSVCRT__finddatai64_t
* ft
)
277 WIN32_FIND_DATAA find_data
;
280 hfind
= FindFirstFileA(fspec
, &find_data
);
281 if (hfind
== INVALID_HANDLE_VALUE
)
283 msvcrt_set_errno(GetLastError());
286 msvcrt_fttofdi64(&find_data
,ft
);
287 TRACE(":got handle %p\n",hfind
);
291 /*********************************************************************
292 * _wfindfirsti64 (MSVCRT.@)
294 * Unicode version of _findfirsti64.
296 long CDECL
MSVCRT__wfindfirsti64(const MSVCRT_wchar_t
* fspec
, struct MSVCRT__wfinddatai64_t
* ft
)
298 WIN32_FIND_DATAW find_data
;
301 hfind
= FindFirstFileW(fspec
, &find_data
);
302 if (hfind
== INVALID_HANDLE_VALUE
)
304 msvcrt_set_errno(GetLastError());
307 msvcrt_wfttofdi64(&find_data
,ft
);
308 TRACE(":got handle %p\n",hfind
);
312 /*********************************************************************
313 * _findnext (MSVCRT.@)
315 * Find the next file from a file search handle.
318 * hand [I] Handle to the search returned from _findfirst().
319 * ft [O] Information for the file found.
322 * Success: 0. ft is populated with the details of the found file.
323 * Failure: -1. errno indicates the error.
328 int CDECL
MSVCRT__findnext(long hand
, struct MSVCRT__finddata_t
* ft
)
330 WIN32_FIND_DATAA find_data
;
332 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
334 *MSVCRT__errno() = MSVCRT_ENOENT
;
338 msvcrt_fttofd(&find_data
,ft
);
342 /*********************************************************************
343 * _wfindnext (MSVCRT.@)
345 * Unicode version of _findnext.
347 int CDECL
MSVCRT__wfindnext(long hand
, struct MSVCRT__wfinddata_t
* ft
)
349 WIN32_FIND_DATAW find_data
;
351 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
353 *MSVCRT__errno() = MSVCRT_ENOENT
;
357 msvcrt_wfttofd(&find_data
,ft
);
361 /*********************************************************************
362 * _findnexti64 (MSVCRT.@)
364 * 64-bit version of _findnext.
366 int CDECL
MSVCRT__findnexti64(long hand
, struct MSVCRT__finddatai64_t
* ft
)
368 WIN32_FIND_DATAA find_data
;
370 if (!FindNextFileA((HANDLE
)hand
, &find_data
))
372 *MSVCRT__errno() = MSVCRT_ENOENT
;
376 msvcrt_fttofdi64(&find_data
,ft
);
380 /*********************************************************************
381 * _wfindnexti64 (MSVCRT.@)
383 * Unicode version of _findnexti64.
385 int CDECL
MSVCRT__wfindnexti64(long hand
, struct MSVCRT__wfinddatai64_t
* ft
)
387 WIN32_FIND_DATAW find_data
;
389 if (!FindNextFileW((HANDLE
)hand
, &find_data
))
391 *MSVCRT__errno() = MSVCRT_ENOENT
;
395 msvcrt_wfttofdi64(&find_data
,ft
);
399 /*********************************************************************
402 * Get the current working directory.
405 * buf [O] Destination for current working directory.
406 * size [I] Size of buf in characters
409 * Success: If buf is NULL, returns an allocated string containing the path.
410 * Otherwise populates buf with the path and returns it.
411 * Failure: NULL. errno indicates the error.
413 char* CDECL
_getcwd(char * buf
, int size
)
416 int dir_len
= GetCurrentDirectoryA(MAX_PATH
,dir
);
419 return NULL
; /* FIXME: Real return value untested */
425 return msvcrt_strndup(dir
,size
);
429 *MSVCRT__errno() = MSVCRT_ERANGE
;
430 return NULL
; /* buf too small */
436 /*********************************************************************
437 * _wgetcwd (MSVCRT.@)
439 * Unicode version of _getcwd.
441 MSVCRT_wchar_t
* CDECL
_wgetcwd(MSVCRT_wchar_t
* buf
, int size
)
443 MSVCRT_wchar_t dir
[MAX_PATH
];
444 int dir_len
= GetCurrentDirectoryW(MAX_PATH
,dir
);
447 return NULL
; /* FIXME: Real return value untested */
453 return msvcrt_wstrndup(dir
,size
);
457 *MSVCRT__errno() = MSVCRT_ERANGE
;
458 return NULL
; /* buf too small */
464 /*********************************************************************
465 * _getdrive (MSVCRT.@)
467 * Get the current drive number.
473 * Success: The drive letter number from 1 to 26 ("A:" to "Z:").
476 int CDECL
_getdrive(void)
478 WCHAR buffer
[MAX_PATH
];
479 if (GetCurrentDirectoryW( MAX_PATH
, buffer
) &&
480 buffer
[0] >= 'A' && buffer
[0] <= 'z' && buffer
[1] == ':')
481 return toupperW(buffer
[0]) - 'A' + 1;
485 /*********************************************************************
486 * _getdcwd (MSVCRT.@)
488 * Get the current working directory on a given disk.
491 * drive [I] Drive letter to get the current working directory from.
492 * buf [O] Destination for the current working directory.
493 * size [I] Length of drive in characters.
496 * Success: If drive is NULL, returns an allocated string containing the path.
497 * Otherwise populates drive with the path and returns it.
498 * Failure: NULL. errno indicates the error.
500 char* CDECL
_getdcwd(int drive
, char * buf
, int size
)
504 TRACE(":drive %d(%c), size %d\n",drive
, drive
+ 'A' - 1, size
);
506 if (!drive
|| drive
== _getdrive())
507 return _getcwd(buf
,size
); /* current */
511 char drivespec
[4] = {'A', ':', 0};
514 drivespec
[0] += drive
- 1;
515 if (GetDriveTypeA(drivespec
) < DRIVE_REMOVABLE
)
517 *MSVCRT__errno() = MSVCRT_EACCES
;
521 dir_len
= GetFullPathNameA(drivespec
,MAX_PATH
,dir
,&dummy
);
522 if (dir_len
>= size
|| dir_len
< 1)
524 *MSVCRT__errno() = MSVCRT_ERANGE
;
525 return NULL
; /* buf too small */
528 TRACE(":returning '%s'\n", dir
);
530 return _strdup(dir
); /* allocate */
537 /*********************************************************************
538 * _wgetdcwd (MSVCRT.@)
540 * Unicode version of _wgetdcwd.
542 MSVCRT_wchar_t
* CDECL
_wgetdcwd(int drive
, MSVCRT_wchar_t
* buf
, int size
)
544 static MSVCRT_wchar_t
* dummy
;
546 TRACE(":drive %d(%c), size %d\n",drive
, drive
+ 'A' - 1, size
);
548 if (!drive
|| drive
== _getdrive())
549 return _wgetcwd(buf
,size
); /* current */
552 MSVCRT_wchar_t dir
[MAX_PATH
];
553 MSVCRT_wchar_t drivespec
[4] = {'A', ':', '\\', 0};
556 drivespec
[0] += drive
- 1;
557 if (GetDriveTypeW(drivespec
) < DRIVE_REMOVABLE
)
559 *MSVCRT__errno() = MSVCRT_EACCES
;
563 dir_len
= GetFullPathNameW(drivespec
,MAX_PATH
,dir
,&dummy
);
564 if (dir_len
>= size
|| dir_len
< 1)
566 *MSVCRT__errno() = MSVCRT_ERANGE
;
567 return NULL
; /* buf too small */
570 TRACE(":returning %s\n", debugstr_w(dir
));
572 return _wcsdup(dir
); /* allocate */
578 /*********************************************************************
579 * _getdiskfree (MSVCRT.@)
581 * Get information about the free space on a drive.
584 * disk [I] Drive number to get information about (1 = 'A', 2 = 'B', ...)
585 * info [O] Destination for the resulting information.
588 * Success: 0. info is updated with the free space information.
589 * Failure: An error code from GetLastError().
592 * See GetLastError().
594 unsigned int CDECL
MSVCRT__getdiskfree(unsigned int disk
, struct MSVCRT__diskfree_t
* d
)
596 WCHAR drivespec
[4] = {'@', ':', '\\', 0};
601 return ERROR_INVALID_PARAMETER
; /* MSVCRT doesn't set errno here */
603 drivespec
[0] += disk
; /* make a drive letter */
605 if (GetDiskFreeSpaceW(disk
==0?NULL
:drivespec
,ret
,ret
+1,ret
+2,ret
+3))
607 d
->sectors_per_cluster
= (unsigned)ret
[0];
608 d
->bytes_per_sector
= (unsigned)ret
[1];
609 d
->avail_clusters
= (unsigned)ret
[2];
610 d
->total_clusters
= (unsigned)ret
[3];
613 err
= GetLastError();
614 msvcrt_set_errno(err
);
618 /*********************************************************************
621 * Create a directory.
624 * newdir [I] Name of directory to create.
627 * Success: 0. The directory indicated by newdir is created.
628 * Failure: -1. errno indicates the error.
631 * See CreateDirectoryA.
633 int CDECL
_mkdir(const char * newdir
)
635 if (CreateDirectoryA(newdir
,NULL
))
637 msvcrt_set_errno(GetLastError());
641 /*********************************************************************
644 * Unicode version of _mkdir.
646 int CDECL
_wmkdir(const MSVCRT_wchar_t
* newdir
)
648 if (CreateDirectoryW(newdir
,NULL
))
650 msvcrt_set_errno(GetLastError());
654 /*********************************************************************
657 * Delete a directory.
660 * dir [I] Name of directory to delete.
663 * Success: 0. The directory indicated by newdir is deleted.
664 * Failure: -1. errno indicates the error.
667 * See RemoveDirectoryA.
669 int CDECL
_rmdir(const char * dir
)
671 if (RemoveDirectoryA(dir
))
673 msvcrt_set_errno(GetLastError());
677 /*********************************************************************
680 * Unicode version of _rmdir.
682 int CDECL
_wrmdir(const MSVCRT_wchar_t
* dir
)
684 if (RemoveDirectoryW(dir
))
686 msvcrt_set_errno(GetLastError());
690 /*********************************************************************
691 * _wsplitpath (MSVCRT.@)
693 * Unicode version of _splitpath.
695 void CDECL
_wsplitpath(const MSVCRT_wchar_t
*inpath
, MSVCRT_wchar_t
*drv
, MSVCRT_wchar_t
*dir
,
696 MSVCRT_wchar_t
*fname
, MSVCRT_wchar_t
*ext
)
698 const MSVCRT_wchar_t
*p
, *end
;
700 if (inpath
[0] && inpath
[1] == ':')
710 else if (drv
) drv
[0] = 0;
712 /* look for end of directory part */
714 for (p
= inpath
; *p
; p
++) if (*p
== '/' || *p
== '\\') end
= p
+ 1;
716 if (end
) /* got a directory */
720 memcpy( dir
, inpath
, (end
- inpath
) * sizeof(MSVCRT_wchar_t
) );
721 dir
[end
- inpath
] = 0;
725 else if (dir
) dir
[0] = 0;
727 /* look for extension: what's after the last dot */
729 for (p
= inpath
; *p
; p
++) if (*p
== '.') end
= p
;
731 if (!end
) end
= p
; /* there's no extension */
735 memcpy( fname
, inpath
, (end
- inpath
) * sizeof(MSVCRT_wchar_t
) );
736 fname
[end
- inpath
] = 0;
738 if (ext
) strcpyW( ext
, end
);
741 /*********************************************************************
742 * _wfullpath (MSVCRT.@)
744 * Unicode version of _fullpath.
746 MSVCRT_wchar_t
* CDECL
_wfullpath(MSVCRT_wchar_t
* absPath
, const MSVCRT_wchar_t
* relPath
, MSVCRT_size_t size
)
751 BOOL alloced
= FALSE
;
753 if (!relPath
|| !*relPath
)
754 return _wgetcwd(absPath
, size
);
758 buffer
= MSVCRT_malloc(MAX_PATH
* sizeof(WCHAR
));
767 *MSVCRT__errno() = MSVCRT_ERANGE
;
771 TRACE(":resolving relative path %s\n",debugstr_w(relPath
));
773 rc
= GetFullPathNameW(relPath
,size
,buffer
,&lastpart
);
775 if (rc
> 0 && rc
<= size
)
785 /*********************************************************************
786 * _fullpath (MSVCRT.@)
788 * Create an absolute path from a relative path.
791 * absPath [O] Destination for absolute path
792 * relPath [I] Relative path to convert to absolute
793 * size [I] Length of absPath in characters.
796 * Success: If absPath is NULL, returns an allocated string containing the path.
797 * Otherwise populates absPath with the path and returns it.
798 * Failure: NULL. errno indicates the error.
800 char * CDECL
_fullpath(char * absPath
, const char* relPath
, unsigned int size
)
805 BOOL alloced
= FALSE
;
807 if (!relPath
|| !*relPath
)
808 return _getcwd(absPath
, size
);
812 buffer
= MSVCRT_malloc(MAX_PATH
);
821 *MSVCRT__errno() = MSVCRT_ERANGE
;
825 TRACE(":resolving relative path '%s'\n",relPath
);
827 rc
= GetFullPathNameA(relPath
,size
,buffer
,&lastpart
);
829 if (rc
> 0 && rc
<= size
)
839 /*********************************************************************
840 * _makepath (MSVCRT.@)
845 * path [O] Destination for created pathname
846 * drive [I] Drive letter (e.g. "A:")
847 * directory [I] Directory
848 * filename [I] Name of the file, excluding extension
849 * extension [I] File extension (e.g. ".TXT")
852 * Nothing. If path is not large enough to hold the resulting pathname,
853 * random process memory will be overwritten.
855 VOID CDECL
_makepath(char * path
, const char * drive
,
856 const char *directory
, const char * filename
,
857 const char * extension
)
861 TRACE("(%s %s %s %s)\n", debugstr_a(drive
), debugstr_a(directory
),
862 debugstr_a(filename
), debugstr_a(extension
) );
868 if (drive
&& drive
[0])
874 if (directory
&& directory
[0])
876 strcat(path
, directory
);
877 ch
= path
[strlen(path
)-1];
878 if (ch
!= '/' && ch
!= '\\')
881 if (filename
&& filename
[0])
883 strcat(path
, filename
);
884 if (extension
&& extension
[0])
886 if ( extension
[0] != '.' )
888 strcat(path
,extension
);
891 TRACE("returning %s\n",path
);
894 /*********************************************************************
895 * _wmakepath (MSVCRT.@)
897 * Unicode version of _wmakepath.
899 VOID CDECL
_wmakepath(MSVCRT_wchar_t
*path
, const MSVCRT_wchar_t
*drive
, const MSVCRT_wchar_t
*directory
,
900 const MSVCRT_wchar_t
*filename
, const MSVCRT_wchar_t
*extension
)
903 TRACE("%s %s %s %s\n", debugstr_w(drive
), debugstr_w(directory
),
904 debugstr_w(filename
), debugstr_w(extension
));
910 if (drive
&& drive
[0])
916 if (directory
&& directory
[0])
918 strcatW(path
, directory
);
919 ch
= path
[strlenW(path
) - 1];
920 if (ch
!= '/' && ch
!= '\\')
922 static const MSVCRT_wchar_t backslashW
[] = {'\\',0};
923 strcatW(path
, backslashW
);
926 if (filename
&& filename
[0])
928 strcatW(path
, filename
);
929 if (extension
&& extension
[0])
931 if ( extension
[0] != '.' )
933 static const MSVCRT_wchar_t dotW
[] = {'.',0};
936 strcatW(path
, extension
);
940 TRACE("returning %s\n", debugstr_w(path
));
943 /*********************************************************************
944 * _searchenv (MSVCRT.@)
946 * Search for a file in a list of paths from an envronment variable.
949 * file [I] Name of the file to search for.
950 * env [I] Name of the environment variable containing a list of paths.
951 * buf [O] Destination for the found file path.
954 * Nothing. If the file is not found, buf will contain an empty string
957 void CDECL
_searchenv(const char* file
, const char* env
, char *buf
)
960 char curPath
[MAX_PATH
];
965 if (GetFileAttributesA( file
) != INVALID_FILE_ATTRIBUTES
)
967 GetFullPathNameA( file
, MAX_PATH
, buf
, NULL
);
968 /* Sigh. This error is *always* set, regardless of success */
969 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
973 /* Search given environment variable */
974 envVal
= MSVCRT_getenv(env
);
977 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
982 TRACE(":searching for %s in paths %s\n", file
, envVal
);
988 while(*end
&& *end
!= ';') end
++; /* Find end of next path */
989 if (penv
== end
|| !*penv
)
991 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
994 memcpy(curPath
, penv
, end
- penv
);
995 if (curPath
[end
- penv
] != '/' || curPath
[end
- penv
] != '\\')
997 curPath
[end
- penv
] = '\\';
998 curPath
[end
- penv
+ 1] = '\0';
1001 curPath
[end
- penv
] = '\0';
1003 strcat(curPath
, file
);
1004 TRACE("Checking for file %s\n", curPath
);
1005 if (GetFileAttributesA( curPath
) != INVALID_FILE_ATTRIBUTES
)
1007 strcpy(buf
, curPath
);
1008 msvcrt_set_errno(ERROR_FILE_NOT_FOUND
);
1011 penv
= *end
? end
+ 1 : end
;