2 * DOS directories functions
4 * Copyright 1995 Alexandre Julliard
23 #define MAX_PATH_ELEMENTS 20
25 static char *DIR_WindowsDosDir
;
26 static char *DIR_WindowsUnixDir
;
27 static char *DIR_SystemDosDir
;
28 static char *DIR_SystemUnixDir
;
29 static char *DIR_TempDosDir
;
30 static char *DIR_TempUnixDir
;
32 static char *DIR_DosPath
[MAX_PATH_ELEMENTS
]; /* Path in DOS format */
33 static char *DIR_UnixPath
[MAX_PATH_ELEMENTS
]; /* Path in Unix format */
34 static int DIR_PathElements
= 0;
36 /***********************************************************************
39 * Get a path name from the wine.ini file and make sure it is valid.
41 static int DIR_GetPath( const char *keyname
, const char *defval
,
42 char **dos_path
, char **unix_path
)
44 char path
[MAX_PATHNAME_LEN
];
45 DOS_FULL_NAME full_name
;
47 BY_HANDLE_FILE_INFORMATION info
;
49 PROFILE_GetWineIniString( "wine", keyname
, defval
, path
, sizeof(path
) );
50 if (!DOSFS_GetFullName( path
, TRUE
, &full_name
) ||
51 !FILE_Stat( full_name
.long_name
, &info
) ||
52 !(info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
54 fprintf(stderr
, "Invalid path '%s' for %s directory\n", path
, keyname
);
57 *unix_path
= HEAP_strdupA( SystemHeap
, 0, full_name
.long_name
);
58 *dos_path
= HEAP_strdupA( SystemHeap
, 0, full_name
.short_name
);
63 /***********************************************************************
64 * DIR_ParseWindowsPath
66 void DIR_ParseWindowsPath( char *path
)
69 DOS_FULL_NAME full_name
;
70 BY_HANDLE_FILE_INFORMATION info
;
73 for ( ; path
&& *path
; path
= p
)
75 p
= strchr( path
, ';' );
76 if (p
) while (*p
== ';') *p
++ = '\0';
78 if (DIR_PathElements
>= MAX_PATH_ELEMENTS
)
80 fprintf( stderr
, "Warning: path has more than %d elements.\n",
84 if (!DOSFS_GetFullName( path
, TRUE
, &full_name
) ||
85 !FILE_Stat( full_name
.long_name
, &info
) ||
86 !(info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
88 fprintf(stderr
,"Warning: invalid dir '%s' in path, deleting it.\n",
92 DIR_UnixPath
[DIR_PathElements
] = HEAP_strdupA( SystemHeap
, 0,
93 full_name
.long_name
);
94 DIR_DosPath
[DIR_PathElements
] = HEAP_strdupA( SystemHeap
, 0,
95 full_name
.short_name
);
99 if (debugging_info(dosfs
))
100 for (i
= 0; i
< DIR_PathElements
; i
++)
102 dprintf_info(dosfs
, "Path[%d]: %s = %s\n",
103 i
, DIR_DosPath
[i
], DIR_UnixPath
[i
] );
108 /***********************************************************************
113 char path
[MAX_PATHNAME_LEN
], *env_p
;
117 if (!getcwd( path
, MAX_PATHNAME_LEN
))
119 perror( "Could not get current directory" );
123 if ((drive
= DRIVE_FindDriveRoot( &cwd
)) == -1)
125 fprintf( stderr
, "Warning: could not find DOS drive for cwd %s; starting in windows directory.\n",
130 DRIVE_SetCurrentDrive( drive
);
131 DRIVE_Chdir( drive
, cwd
);
134 if (!(DIR_GetPath( "windows", "c:\\windows",
135 &DIR_WindowsDosDir
, &DIR_WindowsUnixDir
))) return 0;
136 if (!(DIR_GetPath( "system", "c:\\windows\\system",
137 &DIR_SystemDosDir
, &DIR_SystemUnixDir
))) return 0;
138 if (!(DIR_GetPath( "temp", "c:\\windows",
139 &DIR_TempDosDir
, &DIR_TempUnixDir
))) return 0;
140 if (-1==access(DIR_TempUnixDir
,W_OK
)) {
142 fprintf(stderr
,"Warning: The Temporary Directory (as specified in wine.conf) is NOT writeable. Please check your configuration.\n");
144 fprintf(stderr
,"Warning: Access to Temporary Directory failed (%s).\n",strerror(errno
));
149 drive
= DIR_WindowsDosDir
[0] - 'A';
150 DRIVE_SetCurrentDrive( drive
);
151 DRIVE_Chdir( drive
, DIR_WindowsDosDir
+ 2 );
154 PROFILE_GetWineIniString("wine", "path", "c:\\windows;c:\\windows\\system",
155 path
, sizeof(path
) );
156 DIR_ParseWindowsPath( path
);
158 dprintf_info(dosfs
, "WindowsDir = %s\nSystemDir = %s\n",
159 DIR_WindowsDosDir
, DIR_SystemDosDir
);
160 dprintf_info(dosfs
, "TempDir = %s\nCwd = %c:\\%s\n",
161 DIR_TempDosDir
, 'A' + drive
, DRIVE_GetDosCwd( drive
) );
163 /* Put the temp and Windows and system directories into the environment */
165 env_p
= HEAP_xalloc( SystemHeap
, 0, strlen(DIR_TempDosDir
) + 6 );
166 strcpy( env_p
, "TEMP=" );
167 strcpy( env_p
+ 5, DIR_TempDosDir
);
169 env_p
= HEAP_xalloc( SystemHeap
, 0, strlen(DIR_WindowsDosDir
) + 8 );
170 strcpy( env_p
, "windir=" );
171 strcpy( env_p
+ 7, DIR_WindowsDosDir
);
173 env_p
= HEAP_xalloc( SystemHeap
, 0, strlen(DIR_SystemDosDir
) + 11 );
174 strcpy( env_p
, "winsysdir=" );
175 strcpy( env_p
+ 10, DIR_SystemDosDir
);
182 /***********************************************************************
183 * GetTempPath32A (KERNEL32.292)
185 UINT32 WINAPI
GetTempPath32A( UINT32 count
, LPSTR path
)
187 if (path
) lstrcpyn32A( path
, DIR_TempDosDir
, count
);
188 return strlen( DIR_TempDosDir
);
192 /***********************************************************************
193 * GetTempPath32W (KERNEL32.293)
195 UINT32 WINAPI
GetTempPath32W( UINT32 count
, LPWSTR path
)
197 if (path
) lstrcpynAtoW( path
, DIR_TempDosDir
, count
);
198 return strlen( DIR_TempDosDir
);
202 /***********************************************************************
205 UINT32
DIR_GetTempUnixDir( LPSTR path
, UINT32 count
)
207 if (path
) lstrcpyn32A( path
, DIR_TempUnixDir
, count
);
208 return strlen( DIR_TempUnixDir
);
212 /***********************************************************************
213 * DIR_GetWindowsUnixDir
215 UINT32
DIR_GetWindowsUnixDir( LPSTR path
, UINT32 count
)
217 if (path
) lstrcpyn32A( path
, DIR_WindowsUnixDir
, count
);
218 return strlen( DIR_WindowsUnixDir
);
222 /***********************************************************************
223 * DIR_GetSystemUnixDir
225 UINT32
DIR_GetSystemUnixDir( LPSTR path
, UINT32 count
)
227 if (path
) lstrcpyn32A( path
, DIR_SystemUnixDir
, count
);
228 return strlen( DIR_SystemUnixDir
);
232 /***********************************************************************
235 UINT32
DIR_GetDosPath( INT32 element
, LPSTR path
, UINT32 count
)
237 if ((element
< 0) || (element
>= DIR_PathElements
)) return 0;
238 if (path
) lstrcpyn32A( path
, DIR_DosPath
[element
], count
);
239 return strlen( DIR_DosPath
[element
] );
243 /***********************************************************************
244 * GetTempDrive (KERNEL.92)
246 BYTE WINAPI
GetTempDrive( BYTE ignored
)
248 /* FIXME: apparently Windows does something with the ignored byte */
249 return DIR_TempDosDir
[0];
253 UINT32 WINAPI
WIN16_GetTempDrive( BYTE ignored
)
255 /* A closer look at krnl386.exe shows what the SDK doesn't mention:
259 * AH: ':' - yes, some kernel code even does stosw with
263 return MAKELONG( GetTempDrive(ignored
) | (':' << 8), 1 );
267 /***********************************************************************
268 * GetWindowsDirectory16 (KERNEL.134)
270 UINT16 WINAPI
GetWindowsDirectory16( LPSTR path
, UINT16 count
)
272 return (UINT16
)GetWindowsDirectory32A( path
, count
);
276 /***********************************************************************
277 * GetWindowsDirectory32A (KERNEL32.311)
279 UINT32 WINAPI
GetWindowsDirectory32A( LPSTR path
, UINT32 count
)
281 if (path
) lstrcpyn32A( path
, DIR_WindowsDosDir
, count
);
282 return strlen( DIR_WindowsDosDir
);
286 /***********************************************************************
287 * GetWindowsDirectory32W (KERNEL32.312)
289 UINT32 WINAPI
GetWindowsDirectory32W( LPWSTR path
, UINT32 count
)
291 if (path
) lstrcpynAtoW( path
, DIR_WindowsDosDir
, count
);
292 return strlen( DIR_WindowsDosDir
);
296 /***********************************************************************
297 * GetSystemDirectory16 (KERNEL.135)
299 UINT16 WINAPI
GetSystemDirectory16( LPSTR path
, UINT16 count
)
301 return (UINT16
)GetSystemDirectory32A( path
, count
);
305 /***********************************************************************
306 * GetSystemDirectory32A (KERNEL32.282)
308 UINT32 WINAPI
GetSystemDirectory32A( LPSTR path
, UINT32 count
)
310 if (path
) lstrcpyn32A( path
, DIR_SystemDosDir
, count
);
311 return strlen( DIR_SystemDosDir
);
315 /***********************************************************************
316 * GetSystemDirectory32W (KERNEL32.283)
318 UINT32 WINAPI
GetSystemDirectory32W( LPWSTR path
, UINT32 count
)
320 if (path
) lstrcpynAtoW( path
, DIR_SystemDosDir
, count
);
321 return strlen( DIR_SystemDosDir
);
325 /***********************************************************************
326 * CreateDirectory16 (KERNEL.144)
328 BOOL16 WINAPI
CreateDirectory16( LPCSTR path
, LPVOID dummy
)
330 dprintf_info(file
,"CreateDirectory16(%s,%p)\n", path
, dummy
);
331 return (BOOL16
)CreateDirectory32A( path
, NULL
);
335 /***********************************************************************
336 * CreateDirectory32A (KERNEL32.39)
338 BOOL32 WINAPI
CreateDirectory32A( LPCSTR path
,
339 LPSECURITY_ATTRIBUTES lpsecattribs
)
341 DOS_FULL_NAME full_name
;
343 dprintf_info(file
, "CreateDirectory32A(%s,%p)\n", path
, lpsecattribs
);
344 if (DOSFS_IsDevice( path
))
346 dprintf_info(file
, "CreateDirectory: cannot use device '%s'!\n",path
);
347 DOS_ERROR( ER_AccessDenied
, EC_AccessDenied
, SA_Abort
, EL_Disk
);
350 if (!DOSFS_GetFullName( path
, FALSE
, &full_name
)) return 0;
351 if ((mkdir( full_name
.long_name
, 0777 ) == -1) && (errno
!= EEXIST
))
360 /***********************************************************************
361 * CreateDirectory32W (KERNEL32.42)
363 BOOL32 WINAPI
CreateDirectory32W( LPCWSTR path
,
364 LPSECURITY_ATTRIBUTES lpsecattribs
)
366 LPSTR xpath
= HEAP_strdupWtoA( GetProcessHeap(), 0, path
);
367 BOOL32 ret
= CreateDirectory32A( xpath
, lpsecattribs
);
368 HeapFree( GetProcessHeap(), 0, xpath
);
373 /***********************************************************************
374 * CreateDirectoryEx32A (KERNEL32.40)
376 BOOL32 WINAPI
CreateDirectoryEx32A( LPCSTR
template, LPCSTR path
,
377 LPSECURITY_ATTRIBUTES lpsecattribs
)
379 return CreateDirectory32A(path
,lpsecattribs
);
383 /***********************************************************************
384 * CreateDirectoryEx32W (KERNEL32.41)
386 BOOL32 WINAPI
CreateDirectoryEx32W( LPCWSTR
template, LPCWSTR path
,
387 LPSECURITY_ATTRIBUTES lpsecattribs
)
389 return CreateDirectory32W(path
,lpsecattribs
);
393 /***********************************************************************
394 * RemoveDirectory16 (KERNEL)
396 BOOL16 WINAPI
RemoveDirectory16( LPCSTR path
)
398 return (BOOL16
)RemoveDirectory32A( path
);
402 /***********************************************************************
403 * RemoveDirectory32A (KERNEL32.437)
405 BOOL32 WINAPI
RemoveDirectory32A( LPCSTR path
)
407 DOS_FULL_NAME full_name
;
409 dprintf_info(file
, "RemoveDirectory: '%s'\n", path
);
411 if (DOSFS_IsDevice( path
))
413 dprintf_info(file
, "RemoveDirectory: cannot remove device '%s'!\n", path
);
414 DOS_ERROR( ER_FileNotFound
, EC_NotFound
, SA_Abort
, EL_Disk
);
417 if (!DOSFS_GetFullName( path
, TRUE
, &full_name
)) return FALSE
;
418 if (rmdir( full_name
.long_name
) == -1)
427 /***********************************************************************
428 * RemoveDirectory32W (KERNEL32.438)
430 BOOL32 WINAPI
RemoveDirectory32W( LPCWSTR path
)
432 LPSTR xpath
= HEAP_strdupWtoA( GetProcessHeap(), 0, path
);
433 BOOL32 ret
= RemoveDirectory32A( xpath
);
434 HeapFree( GetProcessHeap(), 0, xpath
);
439 /***********************************************************************
442 * Helper function for DIR_SearchPath.
444 static BOOL32
DIR_TryPath( LPCSTR unix_dir
, LPCSTR dos_dir
, LPCSTR name
,
445 DOS_FULL_NAME
*full_name
)
447 LPSTR p_l
= full_name
->long_name
+ strlen(unix_dir
) + 1;
448 LPSTR p_s
= full_name
->short_name
+ strlen(dos_dir
) + 1;
450 if ((p_s
>= full_name
->short_name
+ sizeof(full_name
->short_name
) - 14) ||
451 (p_l
>= full_name
->long_name
+ sizeof(full_name
->long_name
) - 1))
453 DOS_ERROR( ER_PathNotFound
, EC_NotFound
, SA_Abort
, EL_Disk
);
456 if (!DOSFS_FindUnixName( unix_dir
, name
, p_l
,
457 sizeof(full_name
->long_name
) - (p_l
- full_name
->long_name
),
458 p_s
, DRIVE_GetFlags( dos_dir
[0] - 'A' ) ))
460 strcpy( full_name
->long_name
, unix_dir
);
462 strcpy( full_name
->short_name
, dos_dir
);
468 /***********************************************************************
471 * Helper function for DIR_SearchPath.
473 static BOOL32
DIR_TryModulePath( LPCSTR name
, DOS_FULL_NAME
*full_name
)
475 /* FIXME: for now, GetModuleFileName32A can't return more */
476 /* than OFS_MAXPATHNAME. This may change with Win32. */
477 char buffer
[OFS_MAXPATHNAME
];
480 if (!GetCurrentTask()) return FALSE
;
481 GetModuleFileName32A( GetCurrentTask(), buffer
, sizeof(buffer
) );
482 if (!(p
= strrchr( buffer
, '\\' ))) return FALSE
;
483 if (sizeof(buffer
) - (++p
- buffer
) <= strlen(name
)) return FALSE
;
485 return DOSFS_GetFullName( buffer
, TRUE
, full_name
);
489 /***********************************************************************
492 * Implementation of SearchPath32A. 'win32' specifies whether the search
493 * order is Win16 (module path last) or Win32 (module path first).
495 * FIXME: should return long path names.
497 DWORD
DIR_SearchPath( LPCSTR path
, LPCSTR name
, LPCSTR ext
,
498 DOS_FULL_NAME
*full_name
, BOOL32 win32
)
506 /* First check the supplied parameters */
508 p
= strrchr( name
, '.' );
509 if (p
&& !strchr( p
, '/' ) && !strchr( p
, '\\' ))
510 ext
= NULL
; /* Ignore the specified extension */
511 if ((*name
&& (name
[1] == ':')) ||
512 strchr( name
, '/' ) || strchr( name
, '\\' ))
513 path
= NULL
; /* Ignore path if name already contains a path */
514 if (path
&& !*path
) path
= NULL
; /* Ignore empty path */
517 if (ext
) len
+= strlen(ext
);
518 if (path
) len
+= strlen(path
) + 1;
520 /* Allocate a buffer for the file name and extension */
524 if (!(tmp
= HeapAlloc( GetProcessHeap(), 0, len
+ 1 )))
526 SetLastError( ERROR_OUTOFMEMORY
);
535 else strcpy( tmp
, name
);
536 if (ext
) strcat( tmp
, ext
);
540 /* If we have an explicit path, everything's easy */
542 if (path
|| (*name
&& (name
[1] == ':')) ||
543 strchr( name
, '/' ) || strchr( name
, '\\' ))
545 ret
= DOSFS_GetFullName( name
, TRUE
, full_name
);
549 /* Try the path of the current executable (for Win32 search order) */
551 if (win32
&& DIR_TryModulePath( name
, full_name
)) goto done
;
553 /* Try the current directory */
555 if (DOSFS_GetFullName( name
, TRUE
, full_name
)) goto done
;
557 /* Try the Windows directory */
559 if (DIR_TryPath( DIR_WindowsUnixDir
, DIR_WindowsDosDir
, name
, full_name
))
562 /* Try the Windows system directory */
564 if (DIR_TryPath( DIR_SystemUnixDir
, DIR_SystemDosDir
, name
, full_name
))
567 /* Try the path of the current executable (for Win16 search order) */
569 if (!win32
&& DIR_TryModulePath( name
, full_name
)) goto done
;
571 /* Try all directories in path */
573 for (i
= 0; i
< DIR_PathElements
; i
++)
575 if (DIR_TryPath( DIR_UnixPath
[i
], DIR_DosPath
[i
], name
, full_name
))
581 if (tmp
) HeapFree( GetProcessHeap(), 0, tmp
);
586 /***********************************************************************
587 * SearchPath32A (KERNEL32.447)
589 DWORD WINAPI
SearchPath32A( LPCSTR path
, LPCSTR name
, LPCSTR ext
, DWORD buflen
,
590 LPSTR buffer
, LPSTR
*lastpart
)
593 DOS_FULL_NAME full_name
;
595 if (!DIR_SearchPath( path
, name
, ext
, &full_name
, TRUE
)) return 0;
596 lstrcpyn32A( buffer
, full_name
.short_name
, buflen
);
597 res
= full_name
.long_name
+
598 strlen(DRIVE_GetRoot( full_name
.short_name
[0] - 'A' ));
599 while (*res
== '/') res
++;
602 if (buflen
> 3) lstrcpyn32A( buffer
+ 3, res
, buflen
- 3 );
603 for (p
= buffer
; *p
; p
++) if (*p
== '/') *p
= '\\';
604 if (lastpart
) *lastpart
= strrchr( buffer
, '\\' ) + 1;
606 return *res
? strlen(res
) + 2 : 3;
610 /***********************************************************************
611 * SearchPath32W (KERNEL32.448)
613 DWORD WINAPI
SearchPath32W( LPCWSTR path
, LPCWSTR name
, LPCWSTR ext
,
614 DWORD buflen
, LPWSTR buffer
, LPWSTR
*lastpart
)
618 DOS_FULL_NAME full_name
;
620 LPSTR pathA
= HEAP_strdupWtoA( GetProcessHeap(), 0, path
);
621 LPSTR nameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, name
);
622 LPSTR extA
= HEAP_strdupWtoA( GetProcessHeap(), 0, ext
);
623 DWORD ret
= DIR_SearchPath( pathA
, nameA
, extA
, &full_name
, TRUE
);
624 HeapFree( GetProcessHeap(), 0, extA
);
625 HeapFree( GetProcessHeap(), 0, nameA
);
626 HeapFree( GetProcessHeap(), 0, pathA
);
629 lstrcpynAtoW( buffer
, full_name
.short_name
, buflen
);
630 res
= full_name
.long_name
+
631 strlen(DRIVE_GetRoot( full_name
.short_name
[0] - 'A' ));
632 while (*res
== '/') res
++;
635 if (buflen
> 3) lstrcpynAtoW( buffer
+ 3, res
, buflen
- 3 );
636 for (p
= buffer
; *p
; p
++) if (*p
== '/') *p
= '\\';
639 for (p
= *lastpart
= buffer
; *p
; p
++)
640 if (*p
== '\\') *lastpart
= p
+ 1;
643 return *res
? strlen(res
) + 2 : 3;