blob: 8ef48c71592d2042baae6e79085b63fc7d79652b [file] [log] [blame]
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001/*
2 * DOS directories functions
3 *
4 * Copyright 1995 Alexandre Julliard
5 */
6
Patrik Stridvall96336321999-10-24 22:13:47 +00007#include "config.h"
8
Alexandre Julliardc7c217b1998-04-13 12:21:30 +00009#include <ctype.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000010#include <stdlib.h>
Jeremy Whited3e22d92000-02-10 19:03:02 +000011#include <stdio.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000012#include <string.h>
Alexandre Julliardc6c09441997-01-12 18:32:19 +000013#include <sys/types.h>
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000014#include <sys/stat.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000015#include <unistd.h>
Alexandre Julliard139a4b11996-11-02 14:24:07 +000016#include <errno.h>
Howard Abrams13277481999-07-10 13:16:29 +000017#ifdef HAVE_SYS_ERRNO_H
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000018#include <sys/errno.h>
Howard Abrams13277481999-07-10 13:16:29 +000019#endif
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000020
Marcus Meissner04c3e1d1999-02-19 10:37:02 +000021#include "winbase.h"
22#include "wine/winbase16.h"
23#include "wine/winestring.h"
Jeremy Whited3e22d92000-02-10 19:03:02 +000024#include "windef.h"
25#include "wingdi.h"
Patrik Stridvall1ed4ecf1999-06-26 14:58:24 +000026#include "wine/winuser16.h"
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000027#include "winerror.h"
Alexandre Julliarddadf78f1998-05-17 17:13:43 +000028#include "process.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000029#include "drive.h"
30#include "file.h"
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000031#include "heap.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000032#include "msdos.h"
Alexandre Julliard7e56f681996-01-31 19:02:28 +000033#include "options.h"
Alexandre Julliard06c275a1999-05-02 14:32:27 +000034#include "debugtools.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000035
Jeremy Whited3e22d92000-02-10 19:03:02 +000036DEFAULT_DEBUG_CHANNEL(dosfs);
37DECLARE_DEBUG_CHANNEL(file);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000038
Alexandre Julliardc7c217b1998-04-13 12:21:30 +000039static DOS_FULL_NAME DIR_Windows;
40static DOS_FULL_NAME DIR_System;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000041
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000042
43/***********************************************************************
44 * DIR_GetPath
45 *
46 * Get a path name from the wine.ini file and make sure it is valid.
47 */
48static int DIR_GetPath( const char *keyname, const char *defval,
Alexandre Julliardc7c217b1998-04-13 12:21:30 +000049 DOS_FULL_NAME *full_name )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000050{
51 char path[MAX_PATHNAME_LEN];
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000052 BY_HANDLE_FILE_INFORMATION info;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000053
Alexandre Julliard7e56f681996-01-31 19:02:28 +000054 PROFILE_GetWineIniString( "wine", keyname, defval, path, sizeof(path) );
Alexandre Julliardc7c217b1998-04-13 12:21:30 +000055 if (!DOSFS_GetFullName( path, TRUE, full_name ) ||
56 !FILE_Stat( full_name->long_name, &info ) ||
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000057 !(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000058 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +000059 MESSAGE("Invalid path '%s' for %s directory\n", path, keyname);
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000060 return 0;
61 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000062 return 1;
63}
64
65
66/***********************************************************************
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000067 * DIR_Init
68 */
69int DIR_Init(void)
70{
Alexandre Julliardc7c217b1998-04-13 12:21:30 +000071 char path[MAX_PATHNAME_LEN];
Juergen Schmied8573cc72000-01-30 03:03:23 +000072 DOS_FULL_NAME tmp_dir, profile_dir;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000073 int drive;
74 const char *cwd;
75
76 if (!getcwd( path, MAX_PATHNAME_LEN ))
77 {
78 perror( "Could not get current directory" );
79 return 0;
80 }
81 cwd = path;
82 if ((drive = DRIVE_FindDriveRoot( &cwd )) == -1)
83 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +000084 MESSAGE("Warning: could not find wine.conf [Drive x] entry "
Andreas Mohrdf8cdfd1999-02-28 16:56:48 +000085 "for current working directory %s; "
Alexandre Julliardc7c217b1998-04-13 12:21:30 +000086 "starting in windows directory.\n", cwd );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000087 }
88 else
89 {
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000090 DRIVE_SetCurrentDrive( drive );
Alexandre Julliardc6c09441997-01-12 18:32:19 +000091 DRIVE_Chdir( drive, cwd );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000092 }
93
Alexandre Julliardd30dfd21998-09-27 18:28:36 +000094 if (!(DIR_GetPath( "windows", "c:\\windows", &DIR_Windows )) ||
95 !(DIR_GetPath( "system", "c:\\windows\\system", &DIR_System )) ||
96 !(DIR_GetPath( "temp", "c:\\windows", &tmp_dir )))
97 {
98 PROFILE_UsageWineIni();
Alexandre Julliardc7c217b1998-04-13 12:21:30 +000099 return 0;
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000100 }
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000101 if (-1 == access( tmp_dir.long_name, W_OK ))
102 {
Alexandre Julliard8bbf8181996-09-13 16:50:47 +0000103 if (errno==EACCES)
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000104 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000105 MESSAGE("Warning: The Temporary Directory (as specified in your configuration file) is NOT writeable.\n");
Alexandre Julliardd30dfd21998-09-27 18:28:36 +0000106 PROFILE_UsageWineIni();
107 }
Alexandre Julliard8bbf8181996-09-13 16:50:47 +0000108 else
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000109 MESSAGE("Warning: Access to Temporary Directory failed (%s).\n",
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000110 strerror(errno));
Alexandre Julliard8bbf8181996-09-13 16:50:47 +0000111 }
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000112
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000113 if (drive == -1)
114 {
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000115 drive = DIR_Windows.drive;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000116 DRIVE_SetCurrentDrive( drive );
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000117 DRIVE_Chdir( drive, DIR_Windows.short_name + 2 );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000118 }
119
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000120 PROFILE_GetWineIniString("wine", "path", "c:\\windows;c:\\windows\\system",
121 path, sizeof(path) );
Andreas Mohr0b160062000-01-26 02:04:09 +0000122 if (strchr(path, '/'))
123 {
124 MESSAGE("No '/' allowed in [wine] 'Path=' statement of wine.conf !\n");
125 PROFILE_UsageWineIni();
126 ExitProcess(1);
127 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000128
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000129 /* Set the environment variables */
130
Alexandre Julliarda3960291999-02-26 11:11:13 +0000131 SetEnvironmentVariableA( "PATH", path );
132 SetEnvironmentVariableA( "COMSPEC", "c:\\command.com" );
133 SetEnvironmentVariableA( "TEMP", tmp_dir.short_name );
134 SetEnvironmentVariableA( "windir", DIR_Windows.short_name );
135 SetEnvironmentVariableA( "winsysdir", DIR_System.short_name );
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000136
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000137 TRACE("WindowsDir = %s (%s)\n",
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000138 DIR_Windows.short_name, DIR_Windows.long_name );
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000139 TRACE("SystemDir = %s (%s)\n",
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000140 DIR_System.short_name, DIR_System.long_name );
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000141 TRACE("TempDir = %s (%s)\n",
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000142 tmp_dir.short_name, tmp_dir.long_name );
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000143 TRACE("Path = %s\n", path );
144 TRACE("Cwd = %c:\\%s\n",
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000145 'A' + drive, DRIVE_GetDosCwd( drive ) );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000146
Juergen Schmied8573cc72000-01-30 03:03:23 +0000147 if (DIR_GetPath( "profile", "", &profile_dir ))
148 {
149 TRACE("USERPROFILE= %s\n", profile_dir.short_name );
150 SetEnvironmentVariableA( "USERPROFILE", profile_dir.short_name );
151 }
152
153 TRACE("SYSTEMROOT = %s\n", DIR_Windows.short_name );
154 SetEnvironmentVariableA( "SYSTEMROOT", DIR_Windows.short_name );
155
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000156 return 1;
157}
158
159
160/***********************************************************************
Alexandre Julliard3051b641996-07-05 17:14:13 +0000161 * GetTempPath32A (KERNEL32.292)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000162 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000163UINT WINAPI GetTempPathA( UINT count, LPSTR path )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000164{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000165 UINT ret;
166 if (!(ret = GetEnvironmentVariableA( "TMP", path, count )))
167 if (!(ret = GetEnvironmentVariableA( "TEMP", path, count )))
168 if (!(ret = GetCurrentDirectoryA( count, path )))
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000169 return 0;
Huw D M Daviesa03f0641998-12-15 18:04:58 +0000170 if (count && (ret < count - 1) && (path[ret-1] != '\\'))
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000171 {
172 path[ret++] = '\\';
173 path[ret] = '\0';
174 }
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000175 return ret;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000176}
177
178
179/***********************************************************************
Alexandre Julliard3051b641996-07-05 17:14:13 +0000180 * GetTempPath32W (KERNEL32.293)
181 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000182UINT WINAPI GetTempPathW( UINT count, LPWSTR path )
Alexandre Julliard3051b641996-07-05 17:14:13 +0000183{
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000184 static const WCHAR tmp[] = { 'T', 'M', 'P', 0 };
185 static const WCHAR temp[] = { 'T', 'E', 'M', 'P', 0 };
Alexandre Julliarda3960291999-02-26 11:11:13 +0000186 UINT ret;
187 if (!(ret = GetEnvironmentVariableW( tmp, path, count )))
188 if (!(ret = GetEnvironmentVariableW( temp, path, count )))
189 if (!(ret = GetCurrentDirectoryW( count, path )))
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000190 return 0;
Huw D M Daviesa03f0641998-12-15 18:04:58 +0000191 if (count && (ret < count - 1) && (path[ret-1] != '\\'))
Alexandre Julliard46ea8b31998-05-03 19:01:20 +0000192 {
193 path[ret++] = '\\';
194 path[ret] = '\0';
195 }
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000196 return ret;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000197}
198
199
200/***********************************************************************
201 * DIR_GetWindowsUnixDir
202 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000203UINT DIR_GetWindowsUnixDir( LPSTR path, UINT count )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000204{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000205 if (path) lstrcpynA( path, DIR_Windows.long_name, count );
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000206 return strlen( DIR_Windows.long_name );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000207}
208
209
210/***********************************************************************
211 * DIR_GetSystemUnixDir
212 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000213UINT DIR_GetSystemUnixDir( LPSTR path, UINT count )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000214{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000215 if (path) lstrcpynA( path, DIR_System.long_name, count );
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000216 return strlen( DIR_System.long_name );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000217}
218
219
220/***********************************************************************
221 * GetTempDrive (KERNEL.92)
222 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000223BYTE WINAPI GetTempDrive( BYTE ignored )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000224{
Uwe Bonnes3dbc7881999-02-14 17:32:46 +0000225 char *buffer;
226 BYTE ret;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000227 UINT len = GetTempPathA( 0, NULL );
Uwe Bonnes3dbc7881999-02-14 17:32:46 +0000228
229 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, len + 1 )) )
230 return DRIVE_GetCurrentDrive() + 'A';
231
Alexandre Julliardca22b331996-07-12 19:02:39 +0000232 /* FIXME: apparently Windows does something with the ignored byte */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000233 if (!GetTempPathA( len, buffer )) buffer[0] = 'C';
Uwe Bonnes3dbc7881999-02-14 17:32:46 +0000234 ret = buffer[0];
235 HeapFree( GetProcessHeap(), 0, buffer );
236 return toupper(ret);
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000237}
238
239
Alexandre Julliarda3960291999-02-26 11:11:13 +0000240UINT WINAPI WIN16_GetTempDrive( BYTE ignored )
Alexandre Julliardca22b331996-07-12 19:02:39 +0000241{
242 /* A closer look at krnl386.exe shows what the SDK doesn't mention:
243 *
244 * returns:
245 * AL: driveletter
246 * AH: ':' - yes, some kernel code even does stosw with
247 * the returned AX.
248 * DX: 1 for success
249 */
250 return MAKELONG( GetTempDrive(ignored) | (':' << 8), 1 );
251}
252
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000253
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000254/***********************************************************************
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000255 * GetWindowsDirectory16 (KERNEL.134)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000256 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000257UINT16 WINAPI GetWindowsDirectory16( LPSTR path, UINT16 count )
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000258{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000259 return (UINT16)GetWindowsDirectoryA( path, count );
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000260}
261
262
263/***********************************************************************
264 * GetWindowsDirectory32A (KERNEL32.311)
265 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000266UINT WINAPI GetWindowsDirectoryA( LPSTR path, UINT count )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000267{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000268 if (path) lstrcpynA( path, DIR_Windows.short_name, count );
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000269 return strlen( DIR_Windows.short_name );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000270}
271
272
273/***********************************************************************
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000274 * GetWindowsDirectory32W (KERNEL32.312)
275 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000276UINT WINAPI GetWindowsDirectoryW( LPWSTR path, UINT count )
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000277{
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000278 if (path) lstrcpynAtoW( path, DIR_Windows.short_name, count );
279 return strlen( DIR_Windows.short_name );
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +0000280}
281
282
283/***********************************************************************
Alexandre Julliard3051b641996-07-05 17:14:13 +0000284 * GetSystemDirectory16 (KERNEL.135)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000285 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000286UINT16 WINAPI GetSystemDirectory16( LPSTR path, UINT16 count )
Alexandre Julliard3051b641996-07-05 17:14:13 +0000287{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000288 return (UINT16)GetSystemDirectoryA( path, count );
Alexandre Julliard3051b641996-07-05 17:14:13 +0000289}
290
291
292/***********************************************************************
293 * GetSystemDirectory32A (KERNEL32.282)
294 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000295UINT WINAPI GetSystemDirectoryA( LPSTR path, UINT count )
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000296{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000297 if (path) lstrcpynA( path, DIR_System.short_name, count );
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000298 return strlen( DIR_System.short_name );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000299}
Alexandre Julliard3051b641996-07-05 17:14:13 +0000300
301
302/***********************************************************************
303 * GetSystemDirectory32W (KERNEL32.283)
304 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000305UINT WINAPI GetSystemDirectoryW( LPWSTR path, UINT count )
Alexandre Julliard3051b641996-07-05 17:14:13 +0000306{
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000307 if (path) lstrcpynAtoW( path, DIR_System.short_name, count );
308 return strlen( DIR_System.short_name );
Alexandre Julliard3051b641996-07-05 17:14:13 +0000309}
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000310
311
312/***********************************************************************
313 * CreateDirectory16 (KERNEL.144)
314 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000315BOOL16 WINAPI CreateDirectory16( LPCSTR path, LPVOID dummy )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000316{
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000317 TRACE_(file)("(%s,%p)\n", path, dummy );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000318 return (BOOL16)CreateDirectoryA( path, NULL );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000319}
320
321
322/***********************************************************************
323 * CreateDirectory32A (KERNEL32.39)
Marcus Meissner412d0251999-02-28 19:50:39 +0000324 * RETURNS:
325 * TRUE : success
326 * FALSE : failure
327 * ERROR_DISK_FULL: on full disk
328 * ERROR_ALREADY_EXISTS: if directory name exists (even as file)
329 * ERROR_ACCESS_DENIED: on permission problems
330 * ERROR_FILENAME_EXCED_RANGE: too long filename(s)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000331 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000332BOOL WINAPI CreateDirectoryA( LPCSTR path,
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000333 LPSECURITY_ATTRIBUTES lpsecattribs )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000334{
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000335 DOS_FULL_NAME full_name;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000336
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000337 TRACE_(file)("(%s,%p)\n", path, lpsecattribs );
Alexandre Julliard829fe321998-07-26 14:27:39 +0000338 if (DOSFS_GetDevice( path ))
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000339 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000340 TRACE_(file)("cannot use device '%s'!\n",path);
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000341 SetLastError( ERROR_ACCESS_DENIED );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000342 return FALSE;
343 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000344 if (!DOSFS_GetFullName( path, FALSE, &full_name )) return 0;
Marcus Meissner412d0251999-02-28 19:50:39 +0000345 if (mkdir( full_name.long_name, 0777 ) == -1) {
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000346 WARN_(file)("Errno %i trying to create directory %s.\n", errno, full_name.long_name);
Marcus Meissner412d0251999-02-28 19:50:39 +0000347 /* the FILE_SetDosError() generated error codes don't match the
348 * CreateDirectory ones for some errnos */
349 switch (errno) {
350 case EEXIST: SetLastError(ERROR_ALREADY_EXISTS); break;
351 case ENOSPC: SetLastError(ERROR_DISK_FULL); break;
352 default: FILE_SetDosError();break;
353 }
354 return FALSE;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000355 }
356 return TRUE;
357}
358
359
360/***********************************************************************
361 * CreateDirectory32W (KERNEL32.42)
362 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000363BOOL WINAPI CreateDirectoryW( LPCWSTR path,
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000364 LPSECURITY_ATTRIBUTES lpsecattribs )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000365{
366 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000367 BOOL ret = CreateDirectoryA( xpath, lpsecattribs );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000368 HeapFree( GetProcessHeap(), 0, xpath );
369 return ret;
370}
371
372
373/***********************************************************************
374 * CreateDirectoryEx32A (KERNEL32.40)
375 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000376BOOL WINAPI CreateDirectoryExA( LPCSTR template, LPCSTR path,
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000377 LPSECURITY_ATTRIBUTES lpsecattribs)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000378{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000379 return CreateDirectoryA(path,lpsecattribs);
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000380}
381
382
383/***********************************************************************
384 * CreateDirectoryEx32W (KERNEL32.41)
385 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000386BOOL WINAPI CreateDirectoryExW( LPCWSTR template, LPCWSTR path,
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000387 LPSECURITY_ATTRIBUTES lpsecattribs)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000388{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000389 return CreateDirectoryW(path,lpsecattribs);
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000390}
391
392
393/***********************************************************************
394 * RemoveDirectory16 (KERNEL)
395 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000396BOOL16 WINAPI RemoveDirectory16( LPCSTR path )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000397{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000398 return (BOOL16)RemoveDirectoryA( path );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000399}
400
401
402/***********************************************************************
403 * RemoveDirectory32A (KERNEL32.437)
404 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000405BOOL WINAPI RemoveDirectoryA( LPCSTR path )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000406{
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000407 DOS_FULL_NAME full_name;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000408
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000409 TRACE_(file)("'%s'\n", path );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000410
Alexandre Julliard829fe321998-07-26 14:27:39 +0000411 if (DOSFS_GetDevice( path ))
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000412 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000413 TRACE_(file)("cannot remove device '%s'!\n", path);
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000414 SetLastError( ERROR_FILE_NOT_FOUND );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000415 return FALSE;
416 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000417 if (!DOSFS_GetFullName( path, TRUE, &full_name )) return FALSE;
418 if (rmdir( full_name.long_name ) == -1)
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000419 {
420 FILE_SetDosError();
421 return FALSE;
422 }
423 return TRUE;
424}
425
426
427/***********************************************************************
428 * RemoveDirectory32W (KERNEL32.438)
429 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000430BOOL WINAPI RemoveDirectoryW( LPCWSTR path )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000431{
432 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000433 BOOL ret = RemoveDirectoryA( xpath );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000434 HeapFree( GetProcessHeap(), 0, xpath );
435 return ret;
436}
437
438
439/***********************************************************************
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000440 * DIR_TryPath
441 *
442 * Helper function for DIR_SearchPath.
443 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000444static BOOL DIR_TryPath( const DOS_FULL_NAME *dir, LPCSTR name,
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000445 DOS_FULL_NAME *full_name )
446{
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000447 LPSTR p_l = full_name->long_name + strlen(dir->long_name) + 1;
448 LPSTR p_s = full_name->short_name + strlen(dir->short_name) + 1;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000449
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))
452 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000453 SetLastError( ERROR_PATH_NOT_FOUND );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000454 return FALSE;
455 }
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000456 if (!DOSFS_FindUnixName( dir->long_name, name, p_l,
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000457 sizeof(full_name->long_name) - (p_l - full_name->long_name),
Andreas Mohr04718411999-08-07 12:36:11 +0000458 p_s, !(DRIVE_GetFlags(dir->drive) & DRIVE_CASE_SENSITIVE) ))
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000459 return FALSE;
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000460 strcpy( full_name->long_name, dir->long_name );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000461 p_l[-1] = '/';
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000462 strcpy( full_name->short_name, dir->short_name );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000463 p_s[-1] = '\\';
464 return TRUE;
465}
466
467
468/***********************************************************************
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000469 * DIR_TryEnvironmentPath
470 *
471 * Helper function for DIR_SearchPath.
472 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000473static BOOL DIR_TryEnvironmentPath( LPCSTR name, DOS_FULL_NAME *full_name )
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000474{
475 LPSTR path, next, buffer;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000476 BOOL ret = FALSE;
477 INT len = strlen(name);
478 DWORD size = GetEnvironmentVariableA( "PATH", NULL, 0 );
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000479
480 if (!size) return FALSE;
481 if (!(path = HeapAlloc( GetProcessHeap(), 0, size ))) return FALSE;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000482 if (!GetEnvironmentVariableA( "PATH", path, size )) goto done;
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000483 next = path;
484 while (!ret && next)
485 {
486 LPSTR cur = next;
487 while (*cur == ';') cur++;
488 if (!*cur) break;
489 next = strchr( cur, ';' );
490 if (next) *next++ = '\0';
491 if (!(buffer = HeapAlloc( GetProcessHeap(), 0, strlen(cur) + len + 2)))
492 goto done;
493 strcpy( buffer, cur );
494 strcat( buffer, "\\" );
495 strcat( buffer, name );
496 ret = DOSFS_GetFullName( buffer, TRUE, full_name );
497 HeapFree( GetProcessHeap(), 0, buffer );
498 }
499
500done:
501 HeapFree( GetProcessHeap(), 0, path );
502 return ret;
503}
504
505
506/***********************************************************************
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000507 * DIR_TryModulePath
508 *
509 * Helper function for DIR_SearchPath.
510 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000511static BOOL DIR_TryModulePath( LPCSTR name, DOS_FULL_NAME *full_name )
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000512{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000513 PDB *pdb = PROCESS_Current();
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000514
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000515 /* FIXME: for now, GetModuleFileName32A can't return more */
516 /* than OFS_MAXPATHNAME. This may change with Win32. */
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000517
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000518 char buffer[OFS_MAXPATHNAME];
519 LPSTR p;
520
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000521 if (pdb->flags & PDB32_WIN16_PROC) {
522 if (!GetCurrentTask()) return FALSE;
Alexandre Julliarda845b881998-06-01 10:44:35 +0000523 if (!GetModuleFileName16( GetCurrentTask(), buffer, sizeof(buffer) ))
524 buffer[0]='\0';
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000525 } else {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000526 if (!GetModuleFileNameA( 0, buffer, sizeof(buffer) ))
Alexandre Julliarda845b881998-06-01 10:44:35 +0000527 buffer[0]='\0';
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000528 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000529 if (!(p = strrchr( buffer, '\\' ))) return FALSE;
530 if (sizeof(buffer) - (++p - buffer) <= strlen(name)) return FALSE;
531 strcpy( p, name );
532 return DOSFS_GetFullName( buffer, TRUE, full_name );
533}
534
535
536/***********************************************************************
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000537 * DIR_SearchPath
538 *
539 * Implementation of SearchPath32A. 'win32' specifies whether the search
540 * order is Win16 (module path last) or Win32 (module path first).
541 *
542 * FIXME: should return long path names.
543 */
544DWORD DIR_SearchPath( LPCSTR path, LPCSTR name, LPCSTR ext,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000545 DOS_FULL_NAME *full_name, BOOL win32 )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000546{
547 DWORD len;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000548 LPCSTR p;
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000549 LPSTR tmp = NULL;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000550 BOOL ret = TRUE;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000551
552 /* First check the supplied parameters */
553
Alexandre Julliard641ee761997-08-04 16:34:36 +0000554 p = strrchr( name, '.' );
555 if (p && !strchr( p, '/' ) && !strchr( p, '\\' ))
556 ext = NULL; /* Ignore the specified extension */
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000557 if ((*name && (name[1] == ':')) ||
558 strchr( name, '/' ) || strchr( name, '\\' ))
559 path = NULL; /* Ignore path if name already contains a path */
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000560 if (path && !*path) path = NULL; /* Ignore empty path */
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000561
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000562 len = strlen(name);
563 if (ext) len += strlen(ext);
564 if (path) len += strlen(path) + 1;
565
566 /* Allocate a buffer for the file name and extension */
567
568 if (path || ext)
569 {
570 if (!(tmp = HeapAlloc( GetProcessHeap(), 0, len + 1 )))
571 {
572 SetLastError( ERROR_OUTOFMEMORY );
573 return 0;
574 }
575 if (path)
576 {
577 strcpy( tmp, path );
578 strcat( tmp, "\\" );
579 strcat( tmp, name );
580 }
581 else strcpy( tmp, name );
582 if (ext) strcat( tmp, ext );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000583 name = tmp;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000584 }
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000585
586 /* If we have an explicit path, everything's easy */
587
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000588 if (path || (*name && (name[1] == ':')) ||
589 strchr( name, '/' ) || strchr( name, '\\' ))
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000590 {
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000591 ret = DOSFS_GetFullName( name, TRUE, full_name );
592 goto done;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000593 }
594
595 /* Try the path of the current executable (for Win32 search order) */
596
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000597 if (win32 && DIR_TryModulePath( name, full_name )) goto done;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000598
599 /* Try the current directory */
600
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000601 if (DOSFS_GetFullName( name, TRUE, full_name )) goto done;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000602
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000603 /* Try the Windows system directory */
604
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000605 if (DIR_TryPath( &DIR_System, name, full_name ))
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000606 goto done;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000607
Guy Albertellie40c9b01999-06-05 11:47:25 +0000608 /* Try the Windows directory */
609
610 if (DIR_TryPath( &DIR_Windows, name, full_name ))
611 goto done;
612
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000613 /* Try the path of the current executable (for Win16 search order) */
614
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000615 if (!win32 && DIR_TryModulePath( name, full_name )) goto done;
616
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000617 /* Try all directories in path */
618
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000619 ret = DIR_TryEnvironmentPath( name, full_name );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000620
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000621done:
622 if (tmp) HeapFree( GetProcessHeap(), 0, tmp );
623 return ret;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000624}
625
626
627/***********************************************************************
Alexandre Julliarda845b881998-06-01 10:44:35 +0000628 * SearchPath32A [KERNEL32.447]
629 *
630 * Searches for a specified file in the search path.
631 *
632 * PARAMS
633 * path [I] Path to search
634 * name [I] Filename to search for.
635 * ext [I] File extension to append to file name. The first
636 * character must be a period. This parameter is
637 * specified only if the filename given does not
638 * contain an extension.
639 * buflen [I] size of buffer, in characters
640 * buffer [O] buffer for found filename
641 * lastpart [O] address of pointer to last used character in
642 * buffer (the final '\')
643 *
644 * RETURNS
645 * Success: length of string copied into buffer, not including
646 * terminating null character. If the filename found is
647 * longer than the length of the buffer, the length of the
648 * filename is returned.
649 * Failure: Zero
650 *
651 * NOTES
652 * Should call SetLastError(but currently doesn't).
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000653 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000654DWORD WINAPI SearchPathA( LPCSTR path, LPCSTR name, LPCSTR ext, DWORD buflen,
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000655 LPSTR buffer, LPSTR *lastpart )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000656{
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000657 LPSTR p, res;
658 DOS_FULL_NAME full_name;
659
660 if (!DIR_SearchPath( path, name, ext, &full_name, TRUE )) return 0;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000661 lstrcpynA( buffer, full_name.short_name, buflen );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000662 res = full_name.long_name +
663 strlen(DRIVE_GetRoot( full_name.short_name[0] - 'A' ));
Alexandre Julliard349a9531997-02-02 19:01:52 +0000664 while (*res == '/') res++;
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000665 if (buflen)
666 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000667 if (buflen > 3) lstrcpynA( buffer + 3, res, buflen - 3 );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000668 for (p = buffer; *p; p++) if (*p == '/') *p = '\\';
669 if (lastpart) *lastpart = strrchr( buffer, '\\' ) + 1;
670 }
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000671 TRACE("Returning %d\n", strlen(res) + 3 );
Guy Albertellie711ba21999-04-06 07:14:09 +0000672 return strlen(res) + 3;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000673}
674
675
676/***********************************************************************
677 * SearchPath32W (KERNEL32.448)
678 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000679DWORD WINAPI SearchPathW( LPCWSTR path, LPCWSTR name, LPCWSTR ext,
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000680 DWORD buflen, LPWSTR buffer, LPWSTR *lastpart )
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000681{
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000682 LPWSTR p;
683 LPSTR res;
684 DOS_FULL_NAME full_name;
685
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000686 LPSTR pathA = HEAP_strdupWtoA( GetProcessHeap(), 0, path );
687 LPSTR nameA = HEAP_strdupWtoA( GetProcessHeap(), 0, name );
688 LPSTR extA = HEAP_strdupWtoA( GetProcessHeap(), 0, ext );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000689 DWORD ret = DIR_SearchPath( pathA, nameA, extA, &full_name, TRUE );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000690 HeapFree( GetProcessHeap(), 0, extA );
691 HeapFree( GetProcessHeap(), 0, nameA );
692 HeapFree( GetProcessHeap(), 0, pathA );
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000693 if (!ret) return 0;
694
695 lstrcpynAtoW( buffer, full_name.short_name, buflen );
696 res = full_name.long_name +
697 strlen(DRIVE_GetRoot( full_name.short_name[0] - 'A' ));
Alexandre Julliard349a9531997-02-02 19:01:52 +0000698 while (*res == '/') res++;
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000699 if (buflen)
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000700 {
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000701 if (buflen > 3) lstrcpynAtoW( buffer + 3, res, buflen - 3 );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000702 for (p = buffer; *p; p++) if (*p == '/') *p = '\\';
703 if (lastpart)
704 {
705 for (p = *lastpart = buffer; *p; p++)
706 if (*p == '\\') *lastpart = p + 1;
707 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000708 }
Guy Albertellie711ba21999-04-06 07:14:09 +0000709 return strlen(res) + 3;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000710}
711
712