2 * DOS directories functions
4 * Copyright 1995 Alexandre Julliard
24 #define MAX_PATH_ELEMENTS 20
26 static char *DIR_WindowsDosDir
;
27 static char *DIR_WindowsUnixDir
;
28 static char *DIR_SystemDosDir
;
29 static char *DIR_SystemUnixDir
;
30 static char *DIR_TempDosDir
;
31 static char *DIR_TempUnixDir
;
33 static char *DIR_DosPath
[MAX_PATH_ELEMENTS
]; /* Path in DOS format */
34 static char *DIR_UnixPath
[MAX_PATH_ELEMENTS
]; /* Path in Unix format */
35 static int DIR_PathElements
= 0;
37 /***********************************************************************
40 * Get a path name from the wine.ini file and make sure it is valid.
42 static int DIR_GetPath( const char *keyname
, const char *defval
,
43 char **dos_path
, char **unix_path
)
45 char path
[MAX_PATHNAME_LEN
];
46 DOS_FULL_NAME full_name
;
48 BY_HANDLE_FILE_INFORMATION info
;
50 PROFILE_GetWineIniString( "wine", keyname
, defval
, path
, sizeof(path
) );
51 if (!DOSFS_GetFullName( path
, TRUE
, &full_name
) ||
52 !FILE_Stat( full_name
.long_name
, &info
) ||
53 !(info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
55 fprintf(stderr
, "Invalid path '%s' for %s directory\n", path
, keyname
);
58 *unix_path
= HEAP_strdupA( SystemHeap
, 0, full_name
.long_name
);
59 *dos_path
= HEAP_strdupA( SystemHeap
, 0, full_name
.short_name
);
64 /***********************************************************************
65 * DIR_ParseWindowsPath
67 void DIR_ParseWindowsPath( char *path
)
70 DOS_FULL_NAME full_name
;
71 BY_HANDLE_FILE_INFORMATION info
;
74 for ( ; path
&& *path
; path
= p
)
76 p
= strchr( path
, ';' );
77 if (p
) while (*p
== ';') *p
++ = '\0';
79 if (DIR_PathElements
>= MAX_PATH_ELEMENTS
)
81 fprintf( stderr
, "Warning: path has more than %d elements.\n",
85 if (!DOSFS_GetFullName( path
, TRUE
, &full_name
) ||
86 !FILE_Stat( full_name
.long_name
, &info
) ||
87 !(info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
89 fprintf(stderr
,"Warning: invalid dir '%s' in path, deleting it.\n",
93 DIR_UnixPath
[DIR_PathElements
] = HEAP_strdupA( SystemHeap
, 0,
94 full_name
.long_name
);
95 DIR_DosPath
[DIR_PathElements
] = HEAP_strdupA( SystemHeap
, 0,
96 full_name
.short_name
);
101 for (i
= 0; i
< DIR_PathElements
; i
++)
103 dprintf_dosfs( stddeb
, "Path[%d]: %s = %s\n",
104 i
, DIR_DosPath
[i
], DIR_UnixPath
[i
] );
109 /***********************************************************************
114 char path
[MAX_PATHNAME_LEN
], *env_p
;
118 if (!getcwd( path
, MAX_PATHNAME_LEN
))
120 perror( "Could not get current directory" );
124 if ((drive
= DRIVE_FindDriveRoot( &cwd
)) == -1)
126 fprintf( stderr
, "Warning: could not find DOS drive for cwd %s; starting in windows directory.\n",
131 DRIVE_SetCurrentDrive( drive
);
132 DRIVE_Chdir( drive
, cwd
);
135 if (!(DIR_GetPath( "windows", "c:\\windows",
136 &DIR_WindowsDosDir
, &DIR_WindowsUnixDir
))) return 0;
137 if (!(DIR_GetPath( "system", "c:\\windows\\system",
138 &DIR_SystemDosDir
, &DIR_SystemUnixDir
))) return 0;
139 if (!(DIR_GetPath( "temp", "c:\\windows",
140 &DIR_TempDosDir
, &DIR_TempUnixDir
))) return 0;
141 if (-1==access(DIR_TempUnixDir
,W_OK
)) {
143 fprintf(stderr
,"Warning: The Temporary Directory (as specified in wine.conf) is NOT writeable. Please check your configuration.\n");
145 fprintf(stderr
,"Warning: Access to Temporary Directory failed (%s).\n",strerror(errno
));
150 drive
= DIR_WindowsDosDir
[0] - 'A';
151 DRIVE_SetCurrentDrive( drive
);
152 DRIVE_Chdir( drive
, DIR_WindowsDosDir
+ 2 );
155 PROFILE_GetWineIniString("wine", "path", "c:\\windows;c:\\windows\\system",
156 path
, sizeof(path
) );
157 DIR_ParseWindowsPath( path
);
159 dprintf_dosfs( stddeb
, "WindowsDir = %s\nSystemDir = %s\n",
160 DIR_WindowsDosDir
, DIR_SystemDosDir
);
161 dprintf_dosfs( stddeb
, "TempDir = %s\nCwd = %c:\\%s\n",
162 DIR_TempDosDir
, 'A' + drive
, DRIVE_GetDosCwd( drive
) );
164 /* Put the temp and Windows directories into the environment */
166 env_p
= HEAP_xalloc( SystemHeap
, 0, strlen(DIR_TempDosDir
) + 6 );
167 strcpy( env_p
, "TEMP=" );
168 strcpy( env_p
+ 5, DIR_TempDosDir
);
170 env_p
= HEAP_xalloc( SystemHeap
, 0, strlen(DIR_WindowsDosDir
) + 8 );
171 strcpy( env_p
, "windir=" );
172 strcpy( env_p
+ 7, DIR_WindowsDosDir
);
179 /***********************************************************************
180 * GetTempPath32A (KERNEL32.292)
182 UINT32
GetTempPath32A( UINT32 count
, LPSTR path
)
184 if (path
) lstrcpyn32A( path
, DIR_TempDosDir
, count
);
185 return strlen( DIR_TempDosDir
);
189 /***********************************************************************
190 * GetTempPath32W (KERNEL32.293)
192 UINT32
GetTempPath32W( UINT32 count
, LPWSTR path
)
194 if (path
) lstrcpynAtoW( path
, DIR_TempDosDir
, count
);
195 return strlen( DIR_TempDosDir
);
199 /***********************************************************************
202 UINT32
DIR_GetTempUnixDir( LPSTR path
, UINT32 count
)
204 if (path
) lstrcpyn32A( path
, DIR_TempUnixDir
, count
);
205 return strlen( DIR_TempUnixDir
);
209 /***********************************************************************
210 * DIR_GetWindowsUnixDir
212 UINT32
DIR_GetWindowsUnixDir( LPSTR path
, UINT32 count
)
214 if (path
) lstrcpyn32A( path
, DIR_WindowsUnixDir
, count
);
215 return strlen( DIR_WindowsUnixDir
);
219 /***********************************************************************
220 * DIR_GetSystemUnixDir
222 UINT32
DIR_GetSystemUnixDir( LPSTR path
, UINT32 count
)
224 if (path
) lstrcpyn32A( path
, DIR_SystemUnixDir
, count
);
225 return strlen( DIR_SystemUnixDir
);
229 /***********************************************************************
232 UINT32
DIR_GetDosPath( INT32 element
, LPSTR path
, UINT32 count
)
234 if ((element
< 0) || (element
>= DIR_PathElements
)) return 0;
235 if (path
) lstrcpyn32A( path
, DIR_DosPath
[element
], count
);
236 return strlen( DIR_DosPath
[element
] );
240 /***********************************************************************
241 * GetTempDrive (KERNEL.92)
243 BYTE
GetTempDrive( BYTE ignored
)
245 /* FIXME: apparently Windows does something with the ignored byte */
246 return DIR_TempDosDir
[0];
250 UINT32
WIN16_GetTempDrive( BYTE ignored
)
252 /* A closer look at krnl386.exe shows what the SDK doesn't mention:
256 * AH: ':' - yes, some kernel code even does stosw with
260 return MAKELONG( GetTempDrive(ignored
) | (':' << 8), 1 );
264 /***********************************************************************
265 * GetWindowsDirectory16 (KERNEL.134)
267 UINT16
GetWindowsDirectory16( LPSTR path
, UINT16 count
)
269 return (UINT16
)GetWindowsDirectory32A( path
, count
);
273 /***********************************************************************
274 * GetWindowsDirectory32A (KERNEL32.311)
276 UINT32
GetWindowsDirectory32A( LPSTR path
, UINT32 count
)
278 if (path
) lstrcpyn32A( path
, DIR_WindowsDosDir
, count
);
279 return strlen( DIR_WindowsDosDir
);
283 /***********************************************************************
284 * GetWindowsDirectory32W (KERNEL32.312)
286 UINT32
GetWindowsDirectory32W( LPWSTR path
, UINT32 count
)
288 if (path
) lstrcpynAtoW( path
, DIR_WindowsDosDir
, count
);
289 return strlen( DIR_WindowsDosDir
);
293 /***********************************************************************
294 * GetSystemDirectory16 (KERNEL.135)
296 UINT16
GetSystemDirectory16( LPSTR path
, UINT16 count
)
298 return (UINT16
)GetSystemDirectory32A( path
, count
);
302 /***********************************************************************
303 * GetSystemDirectory32A (KERNEL32.282)
305 UINT32
GetSystemDirectory32A( LPSTR path
, UINT32 count
)
307 if (path
) lstrcpyn32A( path
, DIR_SystemDosDir
, count
);
308 return strlen( DIR_SystemDosDir
);
312 /***********************************************************************
313 * GetSystemDirectory32W (KERNEL32.283)
315 UINT32
GetSystemDirectory32W( LPWSTR path
, UINT32 count
)
317 if (path
) lstrcpynAtoW( path
, DIR_SystemDosDir
, count
);
318 return strlen( DIR_SystemDosDir
);
322 /***********************************************************************
323 * CreateDirectory16 (KERNEL.144)
325 BOOL16
CreateDirectory16( LPCSTR path
, LPVOID dummy
)
327 dprintf_file( stddeb
,"CreateDirectory16(%s,%p)\n", path
, dummy
);
328 return (BOOL16
)CreateDirectory32A( path
, NULL
);
332 /***********************************************************************
333 * CreateDirectory32A (KERNEL32.39)
335 BOOL32
CreateDirectory32A( LPCSTR path
, LPSECURITY_ATTRIBUTES lpsecattribs
)
337 DOS_FULL_NAME full_name
;
340 dprintf_file( stddeb
, "CreateDirectory32A(%s,%p)\n", path
, lpsecattribs
);
341 if ((unixName
= DOSFS_IsDevice( path
)) != NULL
)
343 dprintf_file(stddeb
, "CreateDirectory: device '%s'!\n", unixName
);
344 DOS_ERROR( ER_AccessDenied
, EC_AccessDenied
, SA_Abort
, EL_Disk
);
347 if (!DOSFS_GetFullName( path
, FALSE
, &full_name
)) return 0;
348 if ((mkdir( full_name
.long_name
, 0777 ) == -1) && (errno
!= EEXIST
))
357 /***********************************************************************
358 * CreateDirectory32W (KERNEL32.42)
360 BOOL32
CreateDirectory32W( LPCWSTR path
, LPSECURITY_ATTRIBUTES lpsecattribs
)
362 LPSTR xpath
= HEAP_strdupWtoA( GetProcessHeap(), 0, path
);
363 BOOL32 ret
= CreateDirectory32A( xpath
, lpsecattribs
);
364 HeapFree( GetProcessHeap(), 0, xpath
);
369 /***********************************************************************
370 * CreateDirectoryEx32A (KERNEL32.40)
372 BOOL32
CreateDirectoryEx32A( LPCSTR
template, LPCSTR path
,
373 LPSECURITY_ATTRIBUTES lpsecattribs
)
375 return CreateDirectory32A(path
,lpsecattribs
);
379 /***********************************************************************
380 * CreateDirectoryEx32W (KERNEL32.41)
382 BOOL32
CreateDirectoryEx32W( LPCWSTR
template, LPCWSTR path
,
383 LPSECURITY_ATTRIBUTES lpsecattribs
)
385 return CreateDirectory32W(path
,lpsecattribs
);
389 /***********************************************************************
390 * RemoveDirectory16 (KERNEL)
392 BOOL16
RemoveDirectory16( LPCSTR path
)
394 return (BOOL16
)RemoveDirectory32A( path
);
398 /***********************************************************************
399 * RemoveDirectory32A (KERNEL32.437)
401 BOOL32
RemoveDirectory32A( LPCSTR path
)
403 DOS_FULL_NAME full_name
;
406 dprintf_file(stddeb
, "RemoveDirectory: '%s'\n", path
);
408 if ((unixName
= DOSFS_IsDevice( path
)) != NULL
)
410 dprintf_file(stddeb
, "RemoveDirectory: device '%s'!\n", unixName
);
411 DOS_ERROR( ER_FileNotFound
, EC_NotFound
, SA_Abort
, EL_Disk
);
414 if (!DOSFS_GetFullName( path
, TRUE
, &full_name
)) return FALSE
;
415 if (rmdir( full_name
.long_name
) == -1)
424 /***********************************************************************
425 * RemoveDirectory32W (KERNEL32.438)
427 BOOL32
RemoveDirectory32W( LPCWSTR path
)
429 LPSTR xpath
= HEAP_strdupWtoA( GetProcessHeap(), 0, path
);
430 BOOL32 ret
= RemoveDirectory32A( xpath
);
431 HeapFree( GetProcessHeap(), 0, xpath
);
436 /***********************************************************************
439 * Helper function for DIR_SearchPath.
441 static BOOL32
DIR_TryPath( LPCSTR unix_dir
, LPCSTR dos_dir
, LPCSTR name
,
442 DOS_FULL_NAME
*full_name
)
444 LPSTR p_l
= full_name
->long_name
+ strlen(unix_dir
) + 1;
445 LPSTR p_s
= full_name
->short_name
+ strlen(dos_dir
) + 1;
447 if ((p_s
>= full_name
->short_name
+ sizeof(full_name
->short_name
) - 14) ||
448 (p_l
>= full_name
->long_name
+ sizeof(full_name
->long_name
) - 1))
450 DOS_ERROR( ER_PathNotFound
, EC_NotFound
, SA_Abort
, EL_Disk
);
453 if (!DOSFS_FindUnixName( unix_dir
, name
, p_l
,
454 sizeof(full_name
->long_name
) - (p_l
- full_name
->long_name
),
455 p_s
, DRIVE_GetFlags( dos_dir
[0] - 'A' ) ))
457 strcpy( full_name
->long_name
, unix_dir
);
459 strcpy( full_name
->short_name
, dos_dir
);
465 /***********************************************************************
468 * Helper function for DIR_SearchPath.
470 static BOOL32
DIR_TryModulePath( LPCSTR name
, DOS_FULL_NAME
*full_name
)
472 /* FIXME: for now, GetModuleFileName32A can't return more */
473 /* than OFS_MAXPATHNAME. This may change with Win32. */
474 char buffer
[OFS_MAXPATHNAME
];
477 if (!GetCurrentTask()) return FALSE
;
478 GetModuleFileName32A( GetCurrentTask(), buffer
, sizeof(buffer
) );
479 if (!(p
= strrchr( buffer
, '\\' ))) return FALSE
;
480 if (sizeof(buffer
) - (++p
- buffer
) <= strlen(name
)) return FALSE
;
482 return DOSFS_GetFullName( buffer
, TRUE
, full_name
);
486 /***********************************************************************
489 * Implementation of SearchPath32A. 'win32' specifies whether the search
490 * order is Win16 (module path last) or Win32 (module path first).
492 * FIXME: should return long path names.
494 DWORD
DIR_SearchPath( LPCSTR path
, LPCSTR name
, LPCSTR ext
,
495 DOS_FULL_NAME
*full_name
, BOOL32 win32
)
503 /* First check the supplied parameters */
505 p
= strrchr( name
, '.' );
506 if (p
&& !strchr( p
, '/' ) && !strchr( p
, '\\' ))
507 ext
= NULL
; /* Ignore the specified extension */
508 if ((*name
&& (name
[1] == ':')) ||
509 strchr( name
, '/' ) || strchr( name
, '\\' ))
510 path
= NULL
; /* Ignore path if name already contains a path */
511 if (path
&& !*path
) path
= NULL
; /* Ignore empty path */
514 if (ext
) len
+= strlen(ext
);
515 if (path
) len
+= strlen(path
) + 1;
517 /* Allocate a buffer for the file name and extension */
521 if (!(tmp
= HeapAlloc( GetProcessHeap(), 0, len
+ 1 )))
523 SetLastError( ERROR_OUTOFMEMORY
);
532 else strcpy( tmp
, name
);
533 if (ext
) strcat( tmp
, ext
);
537 /* If we have an explicit path, everything's easy */
539 if (path
|| (*name
&& (name
[1] == ':')) ||
540 strchr( name
, '/' ) || strchr( name
, '\\' ))
542 ret
= DOSFS_GetFullName( name
, TRUE
, full_name
);
546 /* Try the path of the current executable (for Win32 search order) */
548 if (win32
&& DIR_TryModulePath( name
, full_name
)) goto done
;
550 /* Try the current directory */
552 if (DOSFS_GetFullName( name
, TRUE
, full_name
)) goto done
;
554 /* Try the Windows directory */
556 if (DIR_TryPath( DIR_WindowsUnixDir
, DIR_WindowsDosDir
, name
, full_name
))
559 /* Try the Windows system directory */
561 if (DIR_TryPath( DIR_SystemUnixDir
, DIR_SystemDosDir
, name
, full_name
))
564 /* Try the path of the current executable (for Win16 search order) */
566 if (!win32
&& DIR_TryModulePath( name
, full_name
)) goto done
;
568 /* Try all directories in path */
570 for (i
= 0; i
< DIR_PathElements
; i
++)
572 if (DIR_TryPath( DIR_UnixPath
[i
], DIR_DosPath
[i
], name
, full_name
))
578 if (tmp
) HeapFree( GetProcessHeap(), 0, tmp
);
583 /***********************************************************************
584 * SearchPath32A (KERNEL32.447)
586 DWORD
SearchPath32A( LPCSTR path
, LPCSTR name
, LPCSTR ext
, DWORD buflen
,
587 LPSTR buffer
, LPSTR
*lastpart
)
590 DOS_FULL_NAME full_name
;
592 if (!DIR_SearchPath( path
, name
, ext
, &full_name
, TRUE
)) return 0;
593 lstrcpyn32A( buffer
, full_name
.short_name
, buflen
);
594 res
= full_name
.long_name
+
595 strlen(DRIVE_GetRoot( full_name
.short_name
[0] - 'A' ));
596 while (*res
== '/') res
++;
597 if (buflen
> 3) lstrcpyn32A( buffer
+ 3, res
, buflen
- 3 );
598 for (p
= buffer
; *p
; p
++) if (*p
== '/') *p
= '\\';
599 if (lastpart
) *lastpart
= strrchr( buffer
, '\\' ) + 1;
600 return *res
? strlen(res
) + 2 : 3;
604 /***********************************************************************
605 * SearchPath32W (KERNEL32.448)
607 DWORD
SearchPath32W( LPCWSTR path
, LPCWSTR name
, LPCWSTR ext
, DWORD buflen
,
608 LPWSTR buffer
, LPWSTR
*lastpart
)
612 DOS_FULL_NAME full_name
;
614 LPSTR pathA
= HEAP_strdupWtoA( GetProcessHeap(), 0, path
);
615 LPSTR nameA
= HEAP_strdupWtoA( GetProcessHeap(), 0, name
);
616 LPSTR extA
= HEAP_strdupWtoA( GetProcessHeap(), 0, ext
);
617 DWORD ret
= DIR_SearchPath( pathA
, nameA
, extA
, &full_name
, TRUE
);
618 HeapFree( GetProcessHeap(), 0, extA
);
619 HeapFree( GetProcessHeap(), 0, nameA
);
620 HeapFree( GetProcessHeap(), 0, pathA
);
623 lstrcpynAtoW( buffer
, full_name
.short_name
, buflen
);
624 res
= full_name
.long_name
+
625 strlen(DRIVE_GetRoot( full_name
.short_name
[0] - 'A' ));
626 while (*res
== '/') res
++;
627 if (buflen
> 3) lstrcpynAtoW( buffer
+ 3, res
+ 1, buflen
- 3 );
628 for (p
= buffer
; *p
; p
++) if (*p
== '/') *p
= '\\';
631 for (p
= *lastpart
= buffer
; *p
; p
++)
632 if (*p
== '\\') *lastpart
= p
+ 1;
634 return *res
? strlen(res
) + 2 : 3;