2 * DOS directories functions
4 * Copyright 1995 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include <sys/types.h>
31 #ifdef HAVE_SYS_ERRNO_H
32 #include <sys/errno.h>
36 #include "wine/winbase16.h"
39 #include "wine/winuser16.h"
46 #include "wine/debug.h"
48 WINE_DEFAULT_DEBUG_CHANNEL(dosfs
);
49 WINE_DECLARE_DEBUG_CHANNEL(file
);
51 static DOS_FULL_NAME DIR_Windows
;
52 static DOS_FULL_NAME DIR_System
;
55 /***********************************************************************
58 * Get a path name from the wine.ini file and make sure it is valid.
60 static int DIR_GetPath( const char *keyname
, const char *defval
,
61 DOS_FULL_NAME
*full_name
, char * longname
, BOOL warn
)
63 char path
[MAX_PATHNAME_LEN
];
64 BY_HANDLE_FILE_INFORMATION info
;
65 const char *mess
= "does not exist";
67 PROFILE_GetWineIniString( "wine", keyname
, defval
, path
, sizeof(path
) );
68 if (!DOSFS_GetFullName( path
, TRUE
, full_name
) ||
69 (!FILE_Stat( full_name
->long_name
, &info
) && (mess
=strerror(errno
)))||
70 (!(info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) && (mess
="not a directory")) ||
71 (!(GetLongPathNameA(full_name
->short_name
, longname
, MAX_PATHNAME_LEN
))) )
74 MESSAGE("Invalid path '%s' for %s directory: %s\n", path
, keyname
, mess
);
81 /***********************************************************************
86 char path
[MAX_PATHNAME_LEN
];
87 char longpath
[MAX_PATHNAME_LEN
];
88 DOS_FULL_NAME tmp_dir
, profile_dir
;
92 if (!getcwd( path
, MAX_PATHNAME_LEN
))
94 perror( "Could not get current directory" );
98 if ((drive
= DRIVE_FindDriveRoot( &cwd
)) == -1)
100 MESSAGE("Warning: could not find wine config [Drive x] entry "
101 "for current working directory %s; "
102 "starting in windows directory.\n", cwd
);
106 DRIVE_SetCurrentDrive( drive
);
107 DRIVE_Chdir( drive
, cwd
);
110 if (!(DIR_GetPath( "windows", "c:\\windows", &DIR_Windows
, longpath
, TRUE
)) ||
111 !(DIR_GetPath( "system", "c:\\windows\\system", &DIR_System
, longpath
, TRUE
)) ||
112 !(DIR_GetPath( "temp", "c:\\windows", &tmp_dir
, longpath
, TRUE
)))
114 PROFILE_UsageWineIni();
117 if (-1 == access( tmp_dir
.long_name
, W_OK
))
121 MESSAGE("Warning: the temporary directory '%s' (specified in wine configuration file) is not writeable.\n", tmp_dir
.long_name
);
122 PROFILE_UsageWineIni();
125 MESSAGE("Warning: access to temporary directory '%s' failed (%s).\n",
126 tmp_dir
.long_name
, strerror(errno
));
131 drive
= DIR_Windows
.drive
;
132 DRIVE_SetCurrentDrive( drive
);
133 DRIVE_Chdir( drive
, DIR_Windows
.short_name
+ 2 );
136 PROFILE_GetWineIniString("wine", "path", "c:\\windows;c:\\windows\\system",
137 path
, sizeof(path
) );
138 if (strchr(path
, '/'))
140 MESSAGE("Fix your wine config to use DOS drive syntax in [wine] 'Path=' statement! (no '/' allowed)\n");
141 PROFILE_UsageWineIni();
145 /* Set the environment variables */
147 SetEnvironmentVariableA( "PATH", path
);
148 SetEnvironmentVariableA( "TEMP", tmp_dir
.short_name
);
149 SetEnvironmentVariableA( "TMP", tmp_dir
.short_name
);
150 SetEnvironmentVariableA( "windir", DIR_Windows
.short_name
);
151 SetEnvironmentVariableA( "winsysdir", DIR_System
.short_name
);
153 /* set COMSPEC only if it doesn't exist already */
154 if (!GetEnvironmentVariableA( "COMSPEC", NULL
, 0 ))
155 SetEnvironmentVariableA( "COMSPEC", "c:\\command.com" );
157 TRACE("WindowsDir = %s (%s)\n",
158 DIR_Windows
.short_name
, DIR_Windows
.long_name
);
159 TRACE("SystemDir = %s (%s)\n",
160 DIR_System
.short_name
, DIR_System
.long_name
);
161 TRACE("TempDir = %s (%s)\n",
162 tmp_dir
.short_name
, tmp_dir
.long_name
);
163 TRACE("Path = %s\n", path
);
164 TRACE("Cwd = %c:\\%s\n",
165 'A' + drive
, DRIVE_GetDosCwd( drive
) );
167 if (DIR_GetPath( "profile", "", &profile_dir
, longpath
, FALSE
))
169 TRACE("USERPROFILE= %s\n", longpath
);
170 SetEnvironmentVariableA( "USERPROFILE", longpath
);
173 TRACE("SYSTEMROOT = %s\n", DIR_Windows
.short_name
);
174 SetEnvironmentVariableA( "SYSTEMROOT", DIR_Windows
.short_name
);
180 /***********************************************************************
181 * GetTempPathA (KERNEL32.@)
183 UINT WINAPI
GetTempPathA( UINT count
, LPSTR path
)
186 if (!(ret
= GetEnvironmentVariableA( "TMP", path
, count
)))
187 if (!(ret
= GetEnvironmentVariableA( "TEMP", path
, count
)))
188 if (!(ret
= GetCurrentDirectoryA( count
, path
)))
190 if (count
&& (ret
< count
- 1) && (path
[ret
-1] != '\\'))
199 /***********************************************************************
200 * GetTempPathW (KERNEL32.@)
202 UINT WINAPI
GetTempPathW( UINT count
, LPWSTR path
)
204 static const WCHAR tmp
[] = { 'T', 'M', 'P', 0 };
205 static const WCHAR temp
[] = { 'T', 'E', 'M', 'P', 0 };
207 if (!(ret
= GetEnvironmentVariableW( tmp
, path
, count
)))
208 if (!(ret
= GetEnvironmentVariableW( temp
, path
, count
)))
209 if (!(ret
= GetCurrentDirectoryW( count
, path
)))
211 if (count
&& (ret
< count
- 1) && (path
[ret
-1] != '\\'))
220 /***********************************************************************
221 * DIR_GetWindowsUnixDir
223 UINT
DIR_GetWindowsUnixDir( LPSTR path
, UINT count
)
225 if (path
) lstrcpynA( path
, DIR_Windows
.long_name
, count
);
226 return strlen( DIR_Windows
.long_name
);
230 /***********************************************************************
231 * DIR_GetSystemUnixDir
233 UINT
DIR_GetSystemUnixDir( LPSTR path
, UINT count
)
235 if (path
) lstrcpynA( path
, DIR_System
.long_name
, count
);
236 return strlen( DIR_System
.long_name
);
240 /***********************************************************************
241 * GetTempDrive (KERNEL.92)
242 * A closer look at krnl386.exe shows what the SDK doesn't mention:
246 * AH: ':' - yes, some kernel code even does stosw with
250 UINT WINAPI
GetTempDrive( BYTE ignored
)
254 UINT len
= GetTempPathA( 0, NULL
);
256 if (!(buffer
= HeapAlloc( GetProcessHeap(), 0, len
+ 1 )) )
257 ret
= DRIVE_GetCurrentDrive() + 'A';
260 /* FIXME: apparently Windows does something with the ignored byte */
261 if (!GetTempPathA( len
, buffer
)) buffer
[0] = 'C';
262 ret
= toupper(buffer
[0]);
263 HeapFree( GetProcessHeap(), 0, buffer
);
265 return MAKELONG( ret
| (':' << 8), 1 );
269 /***********************************************************************
270 * GetWindowsDirectory (KERNEL.134)
272 UINT16 WINAPI
GetWindowsDirectory16( LPSTR path
, UINT16 count
)
274 return (UINT16
)GetWindowsDirectoryA( path
, count
);
278 /***********************************************************************
279 * GetWindowsDirectoryA (KERNEL32.@)
281 * See comment for GetWindowsDirectoryW.
283 UINT WINAPI
GetWindowsDirectoryA( LPSTR path
, UINT count
)
285 UINT len
= strlen( DIR_Windows
.short_name
) + 1;
286 if (path
&& count
>= len
)
288 strcpy( path
, DIR_Windows
.short_name
);
295 /***********************************************************************
296 * GetWindowsDirectoryW (KERNEL32.@)
299 * If buffer is large enough to hold full path and terminating '\0' character
300 * function copies path to buffer and returns length of the path without '\0'.
301 * Otherwise function returns required size including '\0' character and
302 * does not touch the buffer.
304 UINT WINAPI
GetWindowsDirectoryW( LPWSTR path
, UINT count
)
306 UINT len
= MultiByteToWideChar( CP_ACP
, 0, DIR_Windows
.short_name
, -1, NULL
, 0 );
307 if (path
&& count
>= len
)
309 MultiByteToWideChar( CP_ACP
, 0, DIR_Windows
.short_name
, -1, path
, count
);
316 /***********************************************************************
317 * GetSystemWindowsDirectoryA (KERNEL32.@) W2K, TS4.0SP4
319 UINT WINAPI
GetSystemWindowsDirectoryA( LPSTR path
, UINT count
)
321 return GetWindowsDirectoryA( path
, count
);
325 /***********************************************************************
326 * GetSystemWindowsDirectoryW (KERNEL32.@) W2K, TS4.0SP4
328 UINT WINAPI
GetSystemWindowsDirectoryW( LPWSTR path
, UINT count
)
330 return GetWindowsDirectoryW( path
, count
);
334 /***********************************************************************
335 * GetSystemDirectory (KERNEL.135)
337 UINT16 WINAPI
GetSystemDirectory16( LPSTR path
, UINT16 count
)
339 return (UINT16
)GetSystemDirectoryA( path
, count
);
343 /***********************************************************************
344 * GetSystemDirectoryA (KERNEL32.@)
346 * See comment for GetWindowsDirectoryW.
348 UINT WINAPI
GetSystemDirectoryA( LPSTR path
, UINT count
)
350 UINT len
= strlen( DIR_System
.short_name
) + 1;
351 if (path
&& count
>= len
)
353 strcpy( path
, DIR_System
.short_name
);
360 /***********************************************************************
361 * GetSystemDirectoryW (KERNEL32.@)
363 * See comment for GetWindowsDirectoryW.
365 UINT WINAPI
GetSystemDirectoryW( LPWSTR path
, UINT count
)
367 UINT len
= MultiByteToWideChar( CP_ACP
, 0, DIR_System
.short_name
, -1, NULL
, 0 );
368 if (path
&& count
>= len
)
370 MultiByteToWideChar( CP_ACP
, 0, DIR_System
.short_name
, -1, path
, count
);
377 /***********************************************************************
378 * CreateDirectory (KERNEL.144)
380 BOOL16 WINAPI
CreateDirectory16( LPCSTR path
, LPVOID dummy
)
382 TRACE_(file
)("(%s,%p)\n", path
, dummy
);
383 return (BOOL16
)CreateDirectoryA( path
, NULL
);
387 /***********************************************************************
388 * CreateDirectoryA (KERNEL32.@)
392 * ERROR_DISK_FULL: on full disk
393 * ERROR_ALREADY_EXISTS: if directory name exists (even as file)
394 * ERROR_ACCESS_DENIED: on permission problems
395 * ERROR_FILENAME_EXCED_RANGE: too long filename(s)
397 BOOL WINAPI
CreateDirectoryA( LPCSTR path
,
398 LPSECURITY_ATTRIBUTES lpsecattribs
)
400 DOS_FULL_NAME full_name
;
402 TRACE_(file
)("(%s,%p)\n", path
, lpsecattribs
);
403 if (DOSFS_GetDevice( path
))
405 TRACE_(file
)("cannot use device '%s'!\n",path
);
406 SetLastError( ERROR_ACCESS_DENIED
);
409 if (!DOSFS_GetFullName( path
, FALSE
, &full_name
)) return 0;
410 if (mkdir( full_name
.long_name
, 0777 ) == -1) {
411 WARN_(file
)("Error '%s' trying to create directory '%s'\n", strerror(errno
), full_name
.long_name
);
412 /* the FILE_SetDosError() generated error codes don't match the
413 * CreateDirectory ones for some errnos */
415 case EEXIST
: SetLastError(ERROR_ALREADY_EXISTS
); break;
416 case ENOSPC
: SetLastError(ERROR_DISK_FULL
); break;
417 default: FILE_SetDosError();break;
425 /***********************************************************************
426 * CreateDirectoryW (KERNEL32.@)
428 BOOL WINAPI
CreateDirectoryW( LPCWSTR path
,
429 LPSECURITY_ATTRIBUTES lpsecattribs
)
431 LPSTR xpath
= HEAP_strdupWtoA( GetProcessHeap(), 0, path
);
432 BOOL ret
= CreateDirectoryA( xpath
, lpsecattribs
);
433 HeapFree( GetProcessHeap(), 0, xpath
);
438 /***********************************************************************
439 * CreateDirectoryExA (KERNEL32.@)
441 BOOL WINAPI
CreateDirectoryExA( LPCSTR
template, LPCSTR path
,
442 LPSECURITY_ATTRIBUTES lpsecattribs
)
444 return CreateDirectoryA(path
,lpsecattribs
);
448 /***********************************************************************
449 * CreateDirectoryExW (KERNEL32.@)
451 BOOL WINAPI
CreateDirectoryExW( LPCWSTR
template, LPCWSTR path
,
452 LPSECURITY_ATTRIBUTES lpsecattribs
)
454 return CreateDirectoryW(path
,lpsecattribs
);
458 /***********************************************************************
459 * RemoveDirectory (KERNEL.145)
461 BOOL16 WINAPI
RemoveDirectory16( LPCSTR path
)
463 return (BOOL16
)RemoveDirectoryA( path
);
467 /***********************************************************************
468 * RemoveDirectoryA (KERNEL32.@)
470 BOOL WINAPI
RemoveDirectoryA( LPCSTR path
)
472 DOS_FULL_NAME full_name
;
474 TRACE_(file
)("'%s'\n", path
);
476 if (DOSFS_GetDevice( path
))
478 TRACE_(file
)("cannot remove device '%s'!\n", path
);
479 SetLastError( ERROR_FILE_NOT_FOUND
);
482 if (!DOSFS_GetFullName( path
, TRUE
, &full_name
)) return FALSE
;
483 if (rmdir( full_name
.long_name
) == -1)
492 /***********************************************************************
493 * RemoveDirectoryW (KERNEL32.@)
495 BOOL WINAPI
RemoveDirectoryW( LPCWSTR path
)
497 LPSTR xpath
= HEAP_strdupWtoA( GetProcessHeap(), 0, path
);
498 BOOL ret
= RemoveDirectoryA( xpath
);
499 HeapFree( GetProcessHeap(), 0, xpath
);
504 /***********************************************************************
507 * Helper function for DIR_SearchPath.
509 static BOOL
DIR_TryPath( const DOS_FULL_NAME
*dir
, LPCSTR name
,
510 DOS_FULL_NAME
*full_name
)
512 LPSTR p_l
= full_name
->long_name
+ strlen(dir
->long_name
) + 1;
513 LPSTR p_s
= full_name
->short_name
+ strlen(dir
->short_name
) + 1;
515 if ((p_s
>= full_name
->short_name
+ sizeof(full_name
->short_name
) - 14) ||
516 (p_l
>= full_name
->long_name
+ sizeof(full_name
->long_name
) - 1))
518 SetLastError( ERROR_PATH_NOT_FOUND
);
521 if (!DOSFS_FindUnixName( dir
->long_name
, name
, p_l
,
522 sizeof(full_name
->long_name
) - (p_l
- full_name
->long_name
),
523 p_s
, !(DRIVE_GetFlags(dir
->drive
) & DRIVE_CASE_SENSITIVE
) ))
525 strcpy( full_name
->long_name
, dir
->long_name
);
527 strcpy( full_name
->short_name
, dir
->short_name
);
532 static BOOL
DIR_SearchSemicolonedPaths(LPCSTR name
, DOS_FULL_NAME
*full_name
, LPSTR pathlist
)
534 LPSTR next
, buffer
= NULL
;
535 INT len
= strlen(name
), newlen
, currlen
= 0;
542 while (*cur
== ';') cur
++;
544 next
= strchr( cur
, ';' );
545 if (next
) *next
++ = '\0';
546 newlen
= strlen(cur
) + len
+ 2;
547 if (newlen
> currlen
)
549 if (!(buffer
= HeapReAlloc( GetProcessHeap(), 0, buffer
, newlen
)))
553 strcpy( buffer
, cur
);
554 strcat( buffer
, "\\" );
555 strcat( buffer
, name
);
556 ret
= DOSFS_GetFullName( buffer
, TRUE
, full_name
);
559 HeapFree( GetProcessHeap(), 0, buffer
);
564 /***********************************************************************
565 * DIR_TryEnvironmentPath
567 * Helper function for DIR_SearchPath.
568 * Search in the specified path, or in $PATH if NULL.
570 static BOOL
DIR_TryEnvironmentPath( LPCSTR name
, DOS_FULL_NAME
*full_name
, LPCSTR envpath
)
576 size
= envpath
? strlen(envpath
)+1 : GetEnvironmentVariableA( "PATH", NULL
, 0 );
577 if (!size
) return FALSE
;
578 if (!(path
= HeapAlloc( GetProcessHeap(), 0, size
))) return FALSE
;
579 if (envpath
) strcpy( path
, envpath
);
580 else if (!GetEnvironmentVariableA( "PATH", path
, size
)) goto done
;
582 ret
= DIR_SearchSemicolonedPaths(name
, full_name
, path
);
585 HeapFree( GetProcessHeap(), 0, path
);
590 /***********************************************************************
593 * Helper function for DIR_SearchPath.
595 static BOOL
DIR_TryModulePath( LPCSTR name
, DOS_FULL_NAME
*full_name
, BOOL win32
)
597 /* FIXME: for now, GetModuleFileNameA can't return more */
598 /* than OFS_MAXPATHNAME. This may change with Win32. */
600 char buffer
[OFS_MAXPATHNAME
];
605 if (!GetCurrentTask()) return FALSE
;
606 if (!GetModuleFileName16( GetCurrentTask(), buffer
, sizeof(buffer
) ))
609 if (!GetModuleFileNameA( 0, buffer
, sizeof(buffer
) ))
612 if (!(p
= strrchr( buffer
, '\\' ))) return FALSE
;
613 if (sizeof(buffer
) - (++p
- buffer
) <= strlen(name
)) return FALSE
;
615 return DOSFS_GetFullName( buffer
, TRUE
, full_name
);
619 /***********************************************************************
622 * Helper function for DIR_SearchPath.
624 static BOOL
DIR_TryAppPath( LPCSTR name
, DOS_FULL_NAME
*full_name
)
626 HKEY hkAppPaths
, hkApp
;
627 char lpAppName
[MAX_PATHNAME_LEN
], lpAppPaths
[MAX_PATHNAME_LEN
];
632 if (RegOpenKeyA(HKEY_LOCAL_MACHINE
, "Software\\Microsoft\\Windows\\CurrentVersion\\App Paths", &hkAppPaths
) != ERROR_SUCCESS
)
635 if (GetModuleFileNameA(0, lpAppName
, sizeof(lpAppName
)) == 0)
637 WARN("huh, module not found ??\n");
640 lpFileName
= strrchr(lpAppName
, '\\');
643 else lpFileName
++; /* skip '\\' */
644 if (RegOpenKeyA(hkAppPaths
, lpFileName
, &hkApp
) != ERROR_SUCCESS
)
646 count
= sizeof(lpAppPaths
);
647 if (RegQueryValueExA(hkApp
, "Path", 0, &type
, (LPBYTE
)lpAppPaths
, &count
) != ERROR_SUCCESS
)
649 TRACE("successfully opened App Paths for '%s'\n", lpFileName
);
651 res
= DIR_SearchSemicolonedPaths(name
, full_name
, lpAppPaths
);
656 RegCloseKey(hkAppPaths
);
660 /***********************************************************************
663 * Implementation of SearchPathA. 'win32' specifies whether the search
664 * order is Win16 (module path last) or Win32 (module path first).
666 * FIXME: should return long path names.
668 DWORD
DIR_SearchPath( LPCSTR path
, LPCSTR name
, LPCSTR ext
,
669 DOS_FULL_NAME
*full_name
, BOOL win32
)
675 /* First check the supplied parameters */
677 p
= strrchr( name
, '.' );
678 if (p
&& !strchr( p
, '/' ) && !strchr( p
, '\\' ))
679 ext
= NULL
; /* Ignore the specified extension */
680 if (FILE_contains_path (name
))
681 path
= NULL
; /* Ignore path if name already contains a path */
682 if (path
&& !*path
) path
= NULL
; /* Ignore empty path */
684 /* Allocate a buffer for the file name and extension */
688 DWORD len
= strlen(name
) + strlen(ext
);
689 if (!(tmp
= HeapAlloc( GetProcessHeap(), 0, len
+ 1 )))
691 SetLastError( ERROR_OUTOFMEMORY
);
699 /* If the name contains an explicit path, everything's easy */
701 if (FILE_contains_path(name
))
703 ret
= DOSFS_GetFullName( name
, TRUE
, full_name
);
707 /* Search in the specified path */
711 ret
= DIR_TryEnvironmentPath( name
, full_name
, path
);
715 /* Try the path of the current executable (for Win32 search order) */
717 if (win32
&& DIR_TryModulePath( name
, full_name
, win32
)) goto done
;
719 /* Try the current directory */
721 if (DOSFS_GetFullName( name
, TRUE
, full_name
)) goto done
;
723 /* Try the Windows system directory */
725 if (DIR_TryPath( &DIR_System
, name
, full_name
))
728 /* Try the Windows directory */
730 if (DIR_TryPath( &DIR_Windows
, name
, full_name
))
733 /* Try the path of the current executable (for Win16 search order) */
735 if (!win32
&& DIR_TryModulePath( name
, full_name
, win32
)) goto done
;
737 /* Try the "App Paths" entry if existing (undocumented ??) */
738 if (DIR_TryAppPath(name
, full_name
))
741 /* Try all directories in path */
743 ret
= DIR_TryEnvironmentPath( name
, full_name
, NULL
);
746 if (tmp
) HeapFree( GetProcessHeap(), 0, tmp
);
751 /***********************************************************************
752 * SearchPathA [KERNEL32.@]
754 * Searches for a specified file in the search path.
757 * path [I] Path to search
758 * name [I] Filename to search for.
759 * ext [I] File extension to append to file name. The first
760 * character must be a period. This parameter is
761 * specified only if the filename given does not
762 * contain an extension.
763 * buflen [I] size of buffer, in characters
764 * buffer [O] buffer for found filename
765 * lastpart [O] address of pointer to last used character in
766 * buffer (the final '\')
769 * Success: length of string copied into buffer, not including
770 * terminating null character. If the filename found is
771 * longer than the length of the buffer, the length of the
772 * filename is returned.
776 * If the file is not found, calls SetLastError(ERROR_FILE_NOT_FOUND)
779 DWORD WINAPI
SearchPathA( LPCSTR path
, LPCSTR name
, LPCSTR ext
, DWORD buflen
,
780 LPSTR buffer
, LPSTR
*lastpart
)
783 DOS_FULL_NAME full_name
;
785 if (!DIR_SearchPath( path
, name
, ext
, &full_name
, TRUE
))
787 SetLastError(ERROR_FILE_NOT_FOUND
);
790 lstrcpynA( buffer
, full_name
.short_name
, buflen
);
791 res
= full_name
.long_name
+
792 strlen(DRIVE_GetRoot( full_name
.short_name
[0] - 'A' ));
793 while (*res
== '/') res
++;
796 if (buflen
> 3) lstrcpynA( buffer
+ 3, res
, buflen
- 3 );
797 for (p
= buffer
; *p
; p
++) if (*p
== '/') *p
= '\\';
798 if (lastpart
) *lastpart
= strrchr( buffer
, '\\' ) + 1;
800 TRACE("Returning %d\n", strlen(res
) + 3 );
801 return strlen(res
) + 3;
805 /***********************************************************************
806 * SearchPathW (KERNEL32.@)
808 DWORD WINAPI
SearchPathW( LPCWSTR path
, LPCWSTR name
, LPCWSTR ext
,
809 DWORD buflen
, LPWSTR buffer
, LPWSTR
*lastpart
)
813 DOS_FULL_NAME full_name
;
815 LPSTR pathA
= HEAP_strdupWtoA( GetProcessHeap(), 0, path
);
816 LPSTR nameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, name
);
817 LPSTR extA
= HEAP_strdupWtoA( GetProcessHeap(), 0, ext
);
818 DWORD ret
= DIR_SearchPath( pathA
, nameA
, extA
, &full_name
, TRUE
);
819 HeapFree( GetProcessHeap(), 0, extA
);
820 HeapFree( GetProcessHeap(), 0, nameA
);
821 HeapFree( GetProcessHeap(), 0, pathA
);
824 if (buflen
> 0 && !MultiByteToWideChar( CP_ACP
, 0, full_name
.short_name
, -1, buffer
, buflen
))
825 buffer
[buflen
-1] = 0;
826 res
= full_name
.long_name
+
827 strlen(DRIVE_GetRoot( full_name
.short_name
[0] - 'A' ));
828 while (*res
== '/') res
++;
833 if (!MultiByteToWideChar( CP_ACP
, 0, res
, -1, buffer
+3, buflen
-3 ))
834 buffer
[buflen
-1] = 0;
836 for (p
= buffer
; *p
; p
++) if (*p
== '/') *p
= '\\';
839 for (p
= *lastpart
= buffer
; *p
; p
++)
840 if (*p
== '\\') *lastpart
= p
+ 1;
843 return strlen(res
) + 3;
847 /***********************************************************************
848 * search_alternate_path
851 * FIXME: should return long path names.?
853 static BOOL
search_alternate_path(LPCSTR dll_path
, LPCSTR name
, LPCSTR ext
,
854 DOS_FULL_NAME
*full_name
)
860 /* First check the supplied parameters */
862 p
= strrchr( name
, '.' );
863 if (p
&& !strchr( p
, '/' ) && !strchr( p
, '\\' ))
864 ext
= NULL
; /* Ignore the specified extension */
866 /* Allocate a buffer for the file name and extension */
870 DWORD len
= strlen(name
) + strlen(ext
);
871 if (!(tmp
= HeapAlloc( GetProcessHeap(), 0, len
+ 1 )))
873 SetLastError( ERROR_OUTOFMEMORY
);
881 if (DIR_TryEnvironmentPath (name
, full_name
, dll_path
))
883 else if (DOSFS_GetFullName (name
, TRUE
, full_name
)) /* current dir */
885 else if (DIR_TryPath (&DIR_System
, name
, full_name
)) /* System dir */
887 else if (DIR_TryPath (&DIR_Windows
, name
, full_name
)) /* Windows dir */
890 ret
= DIR_TryEnvironmentPath( name
, full_name
, NULL
);
892 if (tmp
) HeapFree( GetProcessHeap(), 0, tmp
);
897 /***********************************************************************
898 * DIR_SearchAlternatePath
900 * Searches for a specified file in the search path.
903 * dll_path [I] Path to search
904 * name [I] Filename to search for.
905 * ext [I] File extension to append to file name. The first
906 * character must be a period. This parameter is
907 * specified only if the filename given does not
908 * contain an extension.
909 * buflen [I] size of buffer, in characters
910 * buffer [O] buffer for found filename
911 * lastpart [O] address of pointer to last used character in
912 * buffer (the final '\') (May be NULL)
915 * Success: length of string copied into buffer, not including
916 * terminating null character. If the filename found is
917 * longer than the length of the buffer, the length of the
918 * filename is returned.
922 * If the file is not found, calls SetLastError(ERROR_FILE_NOT_FOUND)
924 DWORD
DIR_SearchAlternatePath( LPCSTR dll_path
, LPCSTR name
, LPCSTR ext
,
925 DWORD buflen
, LPSTR buffer
, LPSTR
*lastpart
)
928 DOS_FULL_NAME full_name
;
930 if (!search_alternate_path( dll_path
, name
, ext
, &full_name
))
932 SetLastError(ERROR_FILE_NOT_FOUND
);
935 lstrcpynA( buffer
, full_name
.short_name
, buflen
);
936 res
= full_name
.long_name
+
937 strlen(DRIVE_GetRoot( full_name
.short_name
[0] - 'A' ));
938 while (*res
== '/') res
++;
941 if (buflen
> 3) lstrcpynA( buffer
+ 3, res
, buflen
- 3 );
942 for (p
= buffer
; *p
; p
++) if (*p
== '/') *p
= '\\';
943 if (lastpart
) *lastpart
= strrchr( buffer
, '\\' ) + 1;
945 TRACE("Returning %d\n", strlen(res
) + 3 );
946 return strlen(res
) + 3;