blob: 809e536f0051277fb67265c9838bb5e3cd9da592 [file] [log] [blame]
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001/*
Alexandre Julliard7e56f681996-01-31 19:02:28 +00002 * DOS drives handling functions
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00003 *
4 * Copyright 1993 Erik Bos
5 * Copyright 1996 Alexandre Julliard
Andreas Mohr1fe93342000-01-29 21:11:47 +00006 *
7 * Label & serial number read support.
8 * (c) 1999 Petr Tomasek <tomasek@etf.cuni.cz>
9 * (c) 2000 Andreas Mohr (changes)
10 *
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000011 */
12
François Gouget14259412001-11-06 20:57:11 +000013#include "config.h"
Francois Gouget386cf6e2001-10-14 16:25:47 +000014#include "wine/port.h"
Alexandre Julliardc7c217b1998-04-13 12:21:30 +000015
Alexandre Julliard491502b1997-11-01 19:08:16 +000016#include <assert.h>
Alexandre Julliard2d93d001996-05-21 15:01:41 +000017#include <ctype.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000018#include <string.h>
Alexandre Julliardaef9a362000-10-03 04:19:16 +000019#include <stdio.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000020#include <stdlib.h>
Alexandre Julliard0c126c71996-02-18 18:44:41 +000021#include <sys/types.h>
Alexandre Julliard7e56f681996-01-31 19:02:28 +000022#include <sys/stat.h>
Alexandre Julliard03468f71998-02-15 19:40:49 +000023#include <fcntl.h>
Alexandre Julliardc7c217b1998-04-13 12:21:30 +000024#include <errno.h>
Andreas Mohrcc0248e1999-01-03 12:31:51 +000025#include <unistd.h>
Alexandre Julliard7e56f681996-01-31 19:02:28 +000026
Alexandre Julliardc7c217b1998-04-13 12:21:30 +000027#ifdef HAVE_SYS_PARAM_H
28# include <sys/param.h>
Alexandre Julliard7e56f681996-01-31 19:02:28 +000029#endif
Alexandre Julliarddadf78f1998-05-17 17:13:43 +000030#ifdef STATFS_DEFINED_BY_SYS_VFS
31# include <sys/vfs.h>
32#else
33# ifdef STATFS_DEFINED_BY_SYS_MOUNT
34# include <sys/mount.h>
35# else
36# ifdef STATFS_DEFINED_BY_SYS_STATFS
37# include <sys/statfs.h>
38# endif
39# endif
Alexandre Julliard7e56f681996-01-31 19:02:28 +000040#endif
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000041
Alexandre Julliard339eefc1996-06-23 14:56:20 +000042#include "winbase.h"
Alexandre Julliard27952ef2000-10-13 20:26:03 +000043#include "ntddk.h"
Michael Veksler249d14b1999-02-25 16:39:16 +000044#include "wine/winbase16.h" /* for GetCurrentTask */
Alexandre Julliard4ff2a271999-01-31 15:23:45 +000045#include "winerror.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000046#include "drive.h"
Andreas Mohr1fe93342000-01-29 21:11:47 +000047#include "cdrom.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000048#include "file.h"
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +000049#include "heap.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000050#include "msdos.h"
Alexandre Julliard7e56f681996-01-31 19:02:28 +000051#include "options.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000052#include "task.h"
Alexandre Julliard06c275a1999-05-02 14:32:27 +000053#include "debugtools.h"
Francois Gouget9f88a542001-09-17 20:44:00 +000054#include "wine/server.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000055
Dimitrie O. Paun529da542000-11-27 23:54:25 +000056DEFAULT_DEBUG_CHANNEL(dosfs);
57DECLARE_DEBUG_CHANNEL(file);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000058
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000059typedef struct
60{
Alexandre Julliard7e56f681996-01-31 19:02:28 +000061 char *root; /* root dir in Unix format without trailing / */
62 char *dos_cwd; /* cwd in DOS format without leading or trailing \ */
63 char *unix_cwd; /* cwd in Unix format without leading or trailing / */
Alexandre Julliard60ce85c1998-02-01 18:33:27 +000064 char *device; /* raw device path */
Chris Morgane4055502001-01-12 19:55:19 +000065 char label_conf[12]; /* drive label as cfg'd in wine config */
Andreas Mohr1fe93342000-01-29 21:11:47 +000066 char label_read[12]; /* drive label as read from device */
Chris Morgane4055502001-01-12 19:55:19 +000067 DWORD serial_conf; /* drive serial number as cfg'd in wine config */
Alexandre Julliardbf672592000-12-12 00:44:42 +000068 UINT type; /* drive type */
Andreas Mohr91a8e0d2000-02-18 19:06:49 +000069 UINT flags; /* drive flags */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000070 dev_t dev; /* unix device number */
71 ino_t ino; /* unix inode number */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000072} DOSDRIVE;
73
Alexandre Julliard7e56f681996-01-31 19:02:28 +000074
Alexandre Julliard1e37a181996-08-18 16:21:52 +000075static const char * const DRIVE_Types[] =
Alexandre Julliard7e56f681996-01-31 19:02:28 +000076{
Alexandre Julliardbf672592000-12-12 00:44:42 +000077 "", /* DRIVE_UNKNOWN */
78 "", /* DRIVE_NO_ROOT_DIR */
79 "floppy", /* DRIVE_REMOVABLE */
80 "hd", /* DRIVE_FIXED */
81 "network", /* DRIVE_REMOTE */
82 "cdrom", /* DRIVE_CDROM */
83 "ramdisk" /* DRIVE_RAMDISK */
Alexandre Julliard7e56f681996-01-31 19:02:28 +000084};
85
86
Alexandre Julliard1e37a181996-08-18 16:21:52 +000087/* Known filesystem types */
88
89typedef struct
90{
91 const char *name;
Alexandre Julliarda3960291999-02-26 11:11:13 +000092 UINT flags;
Alexandre Julliard1e37a181996-08-18 16:21:52 +000093} FS_DESCR;
94
95static const FS_DESCR DRIVE_Filesystems[] =
96{
97 { "unix", DRIVE_CASE_SENSITIVE | DRIVE_CASE_PRESERVING },
98 { "msdos", DRIVE_SHORT_NAMES },
99 { "dos", DRIVE_SHORT_NAMES },
100 { "fat", DRIVE_SHORT_NAMES },
101 { "vfat", DRIVE_CASE_PRESERVING },
102 { "win95", DRIVE_CASE_PRESERVING },
103 { NULL, 0 }
104};
105
106
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000107static DOSDRIVE DOSDrives[MAX_DOS_DRIVES];
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000108static int DRIVE_CurDrive = -1;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000109
Alexandre Julliardbf9130a1996-10-13 17:45:47 +0000110static HTASK16 DRIVE_LastTask = 0;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000111
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000112/* strdup on the process heap */
113inline static char *heap_strdup( const char *str )
114{
115 INT len = strlen(str) + 1;
116 LPSTR p = HeapAlloc( GetProcessHeap(), 0, len );
117 if (p) memcpy( p, str, len );
118 return p;
119}
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000120
121/***********************************************************************
122 * DRIVE_GetDriveType
123 */
Alexandre Julliardbf672592000-12-12 00:44:42 +0000124static UINT DRIVE_GetDriveType( const char *name )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000125{
126 char buffer[20];
127 int i;
128
129 PROFILE_GetWineIniString( name, "Type", "hd", buffer, sizeof(buffer) );
130 for (i = 0; i < sizeof(DRIVE_Types)/sizeof(DRIVE_Types[0]); i++)
131 {
Alexandre Julliardbf672592000-12-12 00:44:42 +0000132 if (!strcasecmp( buffer, DRIVE_Types[i] )) return i;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000133 }
Andreas Mohr1fe93342000-01-29 21:11:47 +0000134 MESSAGE("%s: unknown drive type '%s', defaulting to 'hd'.\n",
135 name, buffer );
Alexandre Julliardbf672592000-12-12 00:44:42 +0000136 return DRIVE_FIXED;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000137}
138
139
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000140/***********************************************************************
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000141 * DRIVE_GetFSFlags
142 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000143static UINT DRIVE_GetFSFlags( const char *name, const char *value )
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000144{
145 const FS_DESCR *descr;
146
147 for (descr = DRIVE_Filesystems; descr->name; descr++)
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +0000148 if (!strcasecmp( value, descr->name )) return descr->flags;
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000149 MESSAGE("%s: unknown filesystem type '%s', defaulting to 'win95'.\n",
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000150 name, value );
Andreas Mohre3728cd1999-02-05 10:16:19 +0000151 return DRIVE_CASE_PRESERVING;
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000152}
153
154
155/***********************************************************************
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000156 * DRIVE_Init
157 */
158int DRIVE_Init(void)
159{
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000160 int i, len, count = 0;
161 char name[] = "Drive A";
Alexandre Julliardaef9a362000-10-03 04:19:16 +0000162 char drive_env[] = "=A:";
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000163 char path[MAX_PATHNAME_LEN];
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000164 char buffer[80];
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000165 struct stat drive_stat_buffer;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000166 char *p;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000167 DOSDRIVE *drive;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000168
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000169 for (i = 0, drive = DOSDrives; i < MAX_DOS_DRIVES; i++, name[6]++, drive++)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000170 {
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000171 PROFILE_GetWineIniString( name, "Path", "", path, sizeof(path)-1 );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000172 if (path[0])
173 {
174 p = path + strlen(path) - 1;
Francois Gouget9f88a542001-09-17 20:44:00 +0000175 while ((p > path) && (*p == '/')) *p-- = '\0';
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000176
Francois Gouget9f88a542001-09-17 20:44:00 +0000177 if (path[0] == '/')
178 {
179 drive->root = heap_strdup( path );
180 }
181 else
182 {
183 /* relative paths are relative to config dir */
184 const char *config = get_config_dir();
185 drive->root = HeapAlloc( GetProcessHeap(), 0, strlen(config) + strlen(path) + 2 );
186 sprintf( drive->root, "%s/%s", config, path );
187 }
188
189 if (stat( drive->root, &drive_stat_buffer ))
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000190 {
Andreas Mohra6d83eb2000-12-27 04:02:46 +0000191 MESSAGE("Could not stat %s (%s), ignoring drive %c:\n",
Francois Gouget9f88a542001-09-17 20:44:00 +0000192 drive->root, strerror(errno), 'A' + i);
193 HeapFree( GetProcessHeap(), 0, drive->root );
194 drive->root = NULL;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000195 continue;
196 }
197 if (!S_ISDIR(drive_stat_buffer.st_mode))
198 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000199 MESSAGE("%s is not a directory, ignoring drive %c:\n",
Francois Gouget9f88a542001-09-17 20:44:00 +0000200 drive->root, 'A' + i );
201 HeapFree( GetProcessHeap(), 0, drive->root );
202 drive->root = NULL;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000203 continue;
204 }
205
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000206 drive->dos_cwd = heap_strdup( "" );
207 drive->unix_cwd = heap_strdup( "" );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000208 drive->type = DRIVE_GetDriveType( name );
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000209 drive->device = NULL;
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000210 drive->flags = 0;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000211 drive->dev = drive_stat_buffer.st_dev;
212 drive->ino = drive_stat_buffer.st_ino;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000213
214 /* Get the drive label */
Ryan Cumming418e27e2001-01-09 20:54:11 +0000215 PROFILE_GetWineIniString( name, "Label", "", drive->label_conf, 12 );
Andreas Mohr1fe93342000-01-29 21:11:47 +0000216 if ((len = strlen(drive->label_conf)) < 11)
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000217 {
218 /* Pad label with spaces */
Andreas Mohr1fe93342000-01-29 21:11:47 +0000219 memset( drive->label_conf + len, ' ', 11 - len );
220 drive->label_conf[11] = '\0';
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000221 }
222
223 /* Get the serial number */
224 PROFILE_GetWineIniString( name, "Serial", "12345678",
225 buffer, sizeof(buffer) );
Andreas Mohr1fe93342000-01-29 21:11:47 +0000226 drive->serial_conf = strtoul( buffer, NULL, 16 );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000227
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000228 /* Get the filesystem type */
Andreas Mohre3728cd1999-02-05 10:16:19 +0000229 PROFILE_GetWineIniString( name, "Filesystem", "win95",
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000230 buffer, sizeof(buffer) );
231 drive->flags = DRIVE_GetFSFlags( name, buffer );
232
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000233 /* Get the device */
234 PROFILE_GetWineIniString( name, "Device", "",
235 buffer, sizeof(buffer) );
236 if (buffer[0])
Andreas Mohr1fe93342000-01-29 21:11:47 +0000237 {
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000238 drive->device = heap_strdup( buffer );
Alexandre Julliardfbace6e2000-04-04 20:35:45 +0000239 if (PROFILE_GetWineIniBool( name, "ReadVolInfo", 1))
240 drive->flags |= DRIVE_READ_VOL_INFO;
Andreas Mohr1fe93342000-01-29 21:11:47 +0000241 }
Alexandre Julliardfbace6e2000-04-04 20:35:45 +0000242
243 /* Get the FailReadOnly flag */
244 if (PROFILE_GetWineIniBool( name, "FailReadOnly", 0 ))
245 drive->flags |= DRIVE_FAIL_READ_ONLY;
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000246
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000247 /* Make the first hard disk the current drive */
Alexandre Julliardbf672592000-12-12 00:44:42 +0000248 if ((DRIVE_CurDrive == -1) && (drive->type == DRIVE_FIXED))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000249 DRIVE_CurDrive = i;
250
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000251 count++;
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000252 TRACE("%s: path=%s type=%s label='%s' serial=%08lx "
253 "flags=%08x dev=%x ino=%x\n",
Francois Gouget9f88a542001-09-17 20:44:00 +0000254 name, drive->root, DRIVE_Types[drive->type],
Andreas Mohr1fe93342000-01-29 21:11:47 +0000255 drive->label_conf, drive->serial_conf, drive->flags,
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000256 (int)drive->dev, (int)drive->ino );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000257 }
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000258 else WARN("%s: not defined\n", name );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000259 }
260
261 if (!count)
262 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000263 MESSAGE("Warning: no valid DOS drive found, check your configuration file.\n" );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000264 /* Create a C drive pointing to Unix root dir */
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000265 DOSDrives[2].root = heap_strdup( "/" );
266 DOSDrives[2].dos_cwd = heap_strdup( "" );
267 DOSDrives[2].unix_cwd = heap_strdup( "" );
Andreas Mohr1fe93342000-01-29 21:11:47 +0000268 strcpy( DOSDrives[2].label_conf, "Drive C " );
269 DOSDrives[2].serial_conf = 12345678;
Alexandre Julliardbf672592000-12-12 00:44:42 +0000270 DOSDrives[2].type = DRIVE_FIXED;
Andreas Mohr3084b582000-07-25 20:59:59 +0000271 DOSDrives[2].device = NULL;
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000272 DOSDrives[2].flags = 0;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000273 DRIVE_CurDrive = 2;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000274 }
275
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000276 /* Make sure the current drive is valid */
277 if (DRIVE_CurDrive == -1)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000278 {
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000279 for (i = 0, drive = DOSDrives; i < MAX_DOS_DRIVES; i++, drive++)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000280 {
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000281 if (drive->root && !(drive->flags & DRIVE_DISABLED))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000282 {
283 DRIVE_CurDrive = i;
284 break;
285 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000286 }
287 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000288
Alexandre Julliardaef9a362000-10-03 04:19:16 +0000289 /* get current working directory info for all drives */
290 for (i = 0; i < MAX_DOS_DRIVES; i++, drive_env[1]++)
291 {
292 if (!GetEnvironmentVariableA(drive_env, path, sizeof(path))) continue;
293 /* sanity check */
294 if (toupper(path[0]) != drive_env[1] || path[1] != ':') continue;
295 DRIVE_Chdir( i, path + 2 );
296 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000297 return 1;
298}
299
300
301/***********************************************************************
302 * DRIVE_IsValid
303 */
304int DRIVE_IsValid( int drive )
305{
306 if ((drive < 0) || (drive >= MAX_DOS_DRIVES)) return 0;
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000307 return (DOSDrives[drive].root &&
308 !(DOSDrives[drive].flags & DRIVE_DISABLED));
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000309}
310
311
312/***********************************************************************
313 * DRIVE_GetCurrentDrive
314 */
315int DRIVE_GetCurrentDrive(void)
316{
Alexandre Julliard2ec34e42001-04-04 00:21:05 +0000317 TDB *pTask = TASK_GetCurrent();
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000318 if (pTask && (pTask->curdrive & 0x80)) return pTask->curdrive & ~0x80;
319 return DRIVE_CurDrive;
320}
321
322
323/***********************************************************************
324 * DRIVE_SetCurrentDrive
325 */
326int DRIVE_SetCurrentDrive( int drive )
327{
Alexandre Julliard2ec34e42001-04-04 00:21:05 +0000328 TDB *pTask = TASK_GetCurrent();
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000329 if (!DRIVE_IsValid( drive ))
330 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000331 SetLastError( ERROR_INVALID_DRIVE );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000332 return 0;
333 }
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000334 TRACE("%c:\n", 'A' + drive );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000335 DRIVE_CurDrive = drive;
336 if (pTask) pTask->curdrive = drive | 0x80;
Marcus Meissner34ed4fd2000-09-27 00:22:16 +0000337 chdir(DRIVE_GetUnixCwd(drive));
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000338 return 1;
339}
340
341
342/***********************************************************************
343 * DRIVE_FindDriveRoot
344 *
Peter Gantenea5941b1999-12-05 23:51:56 +0000345 * Find a drive for which the root matches the beginning of the given path.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000346 * This can be used to translate a Unix path into a drive + DOS path.
347 * Return value is the drive, or -1 on error. On success, path is modified
348 * to point to the beginning of the DOS path.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000349 */
350int DRIVE_FindDriveRoot( const char **path )
351{
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000352 /* idea: check at all '/' positions.
353 * If the device and inode of that path is identical with the
354 * device and inode of the current drive then we found a solution.
355 * If there is another drive pointing to a deeper position in
356 * the file tree, we want to find that one, not the earlier solution.
357 */
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000358 int drive, rootdrive = -1;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000359 char buffer[MAX_PATHNAME_LEN];
360 char *next = buffer;
361 const char *p = *path;
362 struct stat st;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000363
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000364 strcpy( buffer, "/" );
365 for (;;)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000366 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000367 if (stat( buffer, &st ) || !S_ISDIR( st.st_mode )) break;
368
369 /* Find the drive */
370
371 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000372 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000373 if (!DOSDrives[drive].root ||
374 (DOSDrives[drive].flags & DRIVE_DISABLED)) continue;
375
376 if ((DOSDrives[drive].dev == st.st_dev) &&
377 (DOSDrives[drive].ino == st.st_ino))
378 {
379 rootdrive = drive;
380 *path = p;
Andreas Mohr91a8e0d2000-02-18 19:06:49 +0000381 break;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000382 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000383 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000384
385 /* Get the next path component */
386
387 *next++ = '/';
388 while ((*p == '/') || (*p == '\\')) p++;
389 if (!*p) break;
390 while (!IS_END_OF_NAME(*p)) *next++ = *p++;
391 *next = 0;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000392 }
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000393 *next = 0;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000394
395 if (rootdrive != -1)
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000396 TRACE("%s -> drive %c:, root='%s', name='%s'\n",
397 buffer, 'A' + rootdrive, DOSDrives[rootdrive].root, *path );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000398 return rootdrive;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000399}
400
401
402/***********************************************************************
403 * DRIVE_GetRoot
404 */
405const char * DRIVE_GetRoot( int drive )
406{
407 if (!DRIVE_IsValid( drive )) return NULL;
408 return DOSDrives[drive].root;
409}
410
411
412/***********************************************************************
413 * DRIVE_GetDosCwd
414 */
415const char * DRIVE_GetDosCwd( int drive )
416{
Alexandre Julliard2ec34e42001-04-04 00:21:05 +0000417 TDB *pTask = TASK_GetCurrent();
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000418 if (!DRIVE_IsValid( drive )) return NULL;
419
420 /* Check if we need to change the directory to the new task. */
421 if (pTask && (pTask->curdrive & 0x80) && /* The task drive is valid */
422 ((pTask->curdrive & ~0x80) == drive) && /* and it's the one we want */
423 (DRIVE_LastTask != GetCurrentTask())) /* and the task changed */
424 {
425 /* Perform the task-switch */
426 if (!DRIVE_Chdir( drive, pTask->curdir )) DRIVE_Chdir( drive, "\\" );
427 DRIVE_LastTask = GetCurrentTask();
428 }
429 return DOSDrives[drive].dos_cwd;
430}
431
432
433/***********************************************************************
434 * DRIVE_GetUnixCwd
435 */
436const char * DRIVE_GetUnixCwd( int drive )
437{
Alexandre Julliard2ec34e42001-04-04 00:21:05 +0000438 TDB *pTask = TASK_GetCurrent();
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000439 if (!DRIVE_IsValid( drive )) return NULL;
440
441 /* Check if we need to change the directory to the new task. */
442 if (pTask && (pTask->curdrive & 0x80) && /* The task drive is valid */
443 ((pTask->curdrive & ~0x80) == drive) && /* and it's the one we want */
444 (DRIVE_LastTask != GetCurrentTask())) /* and the task changed */
445 {
446 /* Perform the task-switch */
447 if (!DRIVE_Chdir( drive, pTask->curdir )) DRIVE_Chdir( drive, "\\" );
448 DRIVE_LastTask = GetCurrentTask();
449 }
450 return DOSDrives[drive].unix_cwd;
451}
452
453
454/***********************************************************************
Andreas Mohr1fe93342000-01-29 21:11:47 +0000455 * DRIVE_GetDevice
456 */
457const char * DRIVE_GetDevice( int drive )
458{
459 return (DRIVE_IsValid( drive )) ? DOSDrives[drive].device : NULL;
460}
461
462
463/***********************************************************************
464 * DRIVE_ReadSuperblock
465 *
Petr Tomasekcd9a6332000-02-27 14:00:14 +0000466 * NOTE
467 * DRIVE_SetLabel and DRIVE_SetSerialNumber use this in order
468 * to check, that they are writing on a FAT filesystem !
Andreas Mohr1fe93342000-01-29 21:11:47 +0000469 */
470int DRIVE_ReadSuperblock (int drive, char * buff)
471{
472#define DRIVE_SUPER 96
473 int fd;
474 off_t offs;
475
476 if (memset(buff,0,DRIVE_SUPER)!=buff) return -1;
477 if ((fd=open(DOSDrives[drive].device,O_RDONLY)) == -1)
478 {
479 struct stat st;
480 if (!DOSDrives[drive].device)
481 ERR("No device configured for drive %c: !\n", 'A'+drive);
482 else
483 ERR("Couldn't open device '%s' for drive %c: ! (%s)\n", DOSDrives[drive].device, 'A'+drive,
484 (stat(DOSDrives[drive].device, &st)) ?
485 "not available or symlink not valid ?" : "no permission");
486 ERR("Can't read drive volume info ! Either pre-set it or make sure the device to read it from is accessible !\n");
487 PROFILE_UsageWineIni();
488 return -1;
489 }
490
491 switch(DOSDrives[drive].type)
492 {
Alexandre Julliardbf672592000-12-12 00:44:42 +0000493 case DRIVE_REMOVABLE:
494 case DRIVE_FIXED:
Andreas Mohr1fe93342000-01-29 21:11:47 +0000495 offs = 0;
496 break;
Alexandre Julliardbf672592000-12-12 00:44:42 +0000497 case DRIVE_CDROM:
Andreas Mohr3084b582000-07-25 20:59:59 +0000498 offs = CDROM_Data_FindBestVoldesc(fd);
Andreas Mohr1fe93342000-01-29 21:11:47 +0000499 break;
Alexandre Julliardbf672592000-12-12 00:44:42 +0000500 default:
501 offs = 0;
502 break;
Andreas Mohr1fe93342000-01-29 21:11:47 +0000503 }
504
505 if ((offs) && (lseek(fd,offs,SEEK_SET)!=offs)) return -4;
506 if (read(fd,buff,DRIVE_SUPER)!=DRIVE_SUPER) return -2;
507
508 switch(DOSDrives[drive].type)
509 {
Alexandre Julliardbf672592000-12-12 00:44:42 +0000510 case DRIVE_REMOVABLE:
511 case DRIVE_FIXED:
Petr Tomasekcd9a6332000-02-27 14:00:14 +0000512 if ((buff[0x26]!=0x29) || /* Check for FAT present */
Andreas Mohr3084b582000-07-25 20:59:59 +0000513 /* FIXME: do really all FAT have their name beginning with
Petr Tomasekcd9a6332000-02-27 14:00:14 +0000514 "FAT" ? (At least FAT12, FAT16 and FAT32 have :) */
515 memcmp( buff+0x36,"FAT",3))
516 {
517 ERR("The filesystem is not FAT !! (device=%s)\n",
518 DOSDrives[drive].device);
519 return -3;
520 }
521 break;
Alexandre Julliardbf672592000-12-12 00:44:42 +0000522 case DRIVE_CDROM:
Andreas Mohr1fe93342000-01-29 21:11:47 +0000523 if (strncmp(&buff[1],"CD001",5)) /* Check for iso9660 present */
524 return -3;
525 /* FIXME: do we need to check for "CDROM", too ? (high sierra) */
526 break;
527 default:
528 return -3;
529 break;
530 }
531
532 return close(fd);
533}
534
535
536/***********************************************************************
Petr Tomasekcd9a6332000-02-27 14:00:14 +0000537 * DRIVE_WriteSuperblockEntry
538 *
539 * NOTE
540 * We are writing as little as possible (ie. not the whole SuperBlock)
541 * not to interfere with kernel. The drive can be mounted !
542 */
543int DRIVE_WriteSuperblockEntry (int drive, off_t ofs, size_t len, char * buff)
544{
545 int fd;
546
547 if ((fd=open(DOSDrives[drive].device,O_WRONLY))==-1)
548 {
549 ERR("Cannot open the device %s (for writing)\n",
550 DOSDrives[drive].device);
551 return -1;
552 }
553 if (lseek(fd,ofs,SEEK_SET)!=ofs)
554 {
555 ERR("lseek failed on device %s !\n",
556 DOSDrives[drive].device);
557 close(fd);
558 return -2;
559 }
560 if (write(fd,buff,len)!=len)
561 {
562 close(fd);
563 ERR("Cannot write on %s !\n",
564 DOSDrives[drive].device);
565 return -3;
566 }
567 return close (fd);
568}
569
570
571
572/***********************************************************************
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000573 * DRIVE_GetLabel
574 */
575const char * DRIVE_GetLabel( int drive )
576{
Andreas Mohr1fe93342000-01-29 21:11:47 +0000577 int read = 0;
578 char buff[DRIVE_SUPER];
579 int offs = -1;
580
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000581 if (!DRIVE_IsValid( drive )) return NULL;
Alexandre Julliardbf672592000-12-12 00:44:42 +0000582 if (DOSDrives[drive].type == DRIVE_CDROM)
Andreas Mohr1fe93342000-01-29 21:11:47 +0000583 {
Andreas Mohr3084b582000-07-25 20:59:59 +0000584 read = CDROM_GetLabel(drive, DOSDrives[drive].label_read);
Andreas Mohr1fe93342000-01-29 21:11:47 +0000585 }
Andreas Mohr3084b582000-07-25 20:59:59 +0000586 else
587 if (DOSDrives[drive].flags & DRIVE_READ_VOL_INFO)
Andreas Mohr1fe93342000-01-29 21:11:47 +0000588 {
589 if (DRIVE_ReadSuperblock(drive,(char *) buff))
590 ERR("Invalid or unreadable superblock on %s (%c:).\n",
591 DOSDrives[drive].device, (char)(drive+'A'));
592 else {
Alexandre Julliardbf672592000-12-12 00:44:42 +0000593 if (DOSDrives[drive].type == DRIVE_REMOVABLE ||
594 DOSDrives[drive].type == DRIVE_FIXED)
Andreas Mohr1fe93342000-01-29 21:11:47 +0000595 offs = 0x2b;
596
Andreas Mohr3084b582000-07-25 20:59:59 +0000597 /* FIXME: ISO9660 uses a 32 bytes long label. Should we do also? */
Andreas Mohr1fe93342000-01-29 21:11:47 +0000598 if (offs != -1) memcpy(DOSDrives[drive].label_read,buff+offs,11);
599 DOSDrives[drive].label_read[11]='\0';
600 read = 1;
601 }
602 }
603
604 return (read) ?
605 DOSDrives[drive].label_read : DOSDrives[drive].label_conf;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000606}
607
608
609/***********************************************************************
610 * DRIVE_GetSerialNumber
611 */
612DWORD DRIVE_GetSerialNumber( int drive )
613{
Andreas Mohra16c0e12000-02-07 16:28:52 +0000614 DWORD serial = 0;
Andreas Mohr1fe93342000-01-29 21:11:47 +0000615char buff[DRIVE_SUPER];
616
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000617 if (!DRIVE_IsValid( drive )) return 0;
Andreas Mohra16c0e12000-02-07 16:28:52 +0000618
Alexandre Julliardfbace6e2000-04-04 20:35:45 +0000619 if (DOSDrives[drive].flags & DRIVE_READ_VOL_INFO)
Andreas Mohr1fe93342000-01-29 21:11:47 +0000620 {
Andreas Mohra16c0e12000-02-07 16:28:52 +0000621 switch(DOSDrives[drive].type)
622 {
Alexandre Julliardbf672592000-12-12 00:44:42 +0000623 case DRIVE_REMOVABLE:
624 case DRIVE_FIXED:
625 if (DRIVE_ReadSuperblock(drive,(char *) buff))
626 MESSAGE("Invalid or unreadable superblock on %s (%c:)."
627 " Maybe not FAT?\n" ,
628 DOSDrives[drive].device, 'A'+drive);
629 else
630 serial = *((DWORD*)(buff+0x27));
631 break;
632 case DRIVE_CDROM:
633 serial = CDROM_GetSerial(drive);
634 break;
635 default:
636 FIXME("Serial number reading from file system on drive %c: not supported yet.\n", drive+'A');
Andreas Mohra16c0e12000-02-07 16:28:52 +0000637 }
Andreas Mohr1fe93342000-01-29 21:11:47 +0000638 }
Andreas Mohra16c0e12000-02-07 16:28:52 +0000639
640 return (serial) ? serial : DOSDrives[drive].serial_conf;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000641}
642
643
644/***********************************************************************
645 * DRIVE_SetSerialNumber
646 */
647int DRIVE_SetSerialNumber( int drive, DWORD serial )
648{
Petr Tomasekcd9a6332000-02-27 14:00:14 +0000649 char buff[DRIVE_SUPER];
650
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000651 if (!DRIVE_IsValid( drive )) return 0;
Petr Tomasekcd9a6332000-02-27 14:00:14 +0000652
Alexandre Julliardfbace6e2000-04-04 20:35:45 +0000653 if (DOSDrives[drive].flags & DRIVE_READ_VOL_INFO)
Petr Tomasekcd9a6332000-02-27 14:00:14 +0000654 {
Alexandre Julliardbf672592000-12-12 00:44:42 +0000655 if ((DOSDrives[drive].type != DRIVE_REMOVABLE) &&
656 (DOSDrives[drive].type != DRIVE_FIXED)) return 0;
Petr Tomasekcd9a6332000-02-27 14:00:14 +0000657 /* check, if the drive has a FAT filesystem */
658 if (DRIVE_ReadSuperblock(drive, buff)) return 0;
659 if (DRIVE_WriteSuperblockEntry(drive, 0x27, 4, (char *) &serial)) return 0;
660 return 1;
661 }
662
Alexandre Julliardbf672592000-12-12 00:44:42 +0000663 if (DOSDrives[drive].type == DRIVE_CDROM) return 0;
Andreas Mohr1fe93342000-01-29 21:11:47 +0000664 DOSDrives[drive].serial_conf = serial;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000665 return 1;
666}
667
668
669/***********************************************************************
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000670 * DRIVE_GetType
671 */
Alexandre Julliardbf672592000-12-12 00:44:42 +0000672static UINT DRIVE_GetType( int drive )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000673{
Alexandre Julliardbf672592000-12-12 00:44:42 +0000674 if (!DRIVE_IsValid( drive )) return DRIVE_UNKNOWN;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000675 return DOSDrives[drive].type;
676}
677
678
679/***********************************************************************
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000680 * DRIVE_GetFlags
681 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000682UINT DRIVE_GetFlags( int drive )
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000683{
684 if ((drive < 0) || (drive >= MAX_DOS_DRIVES)) return 0;
685 return DOSDrives[drive].flags;
686}
687
688
689/***********************************************************************
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000690 * DRIVE_Chdir
691 */
692int DRIVE_Chdir( int drive, const char *path )
693{
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000694 DOS_FULL_NAME full_name;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000695 char buffer[MAX_PATHNAME_LEN];
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000696 LPSTR unix_cwd;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000697 BY_HANDLE_FILE_INFORMATION info;
Alexandre Julliard2ec34e42001-04-04 00:21:05 +0000698 TDB *pTask = TASK_GetCurrent();
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000699
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000700 strcpy( buffer, "A:" );
701 buffer[0] += drive;
Andreas Mohr3084b582000-07-25 20:59:59 +0000702 TRACE("(%s,%s)\n", buffer, path );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000703 lstrcpynA( buffer + 2, path, sizeof(buffer) - 2 );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000704
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000705 if (!DOSFS_GetFullName( buffer, TRUE, &full_name )) return 0;
706 if (!FILE_Stat( full_name.long_name, &info )) return 0;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000707 if (!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000708 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000709 SetLastError( ERROR_FILE_NOT_FOUND );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000710 return 0;
711 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000712 unix_cwd = full_name.long_name + strlen( DOSDrives[drive].root );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000713 while (*unix_cwd == '/') unix_cwd++;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000714
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000715 TRACE("(%c:): unix_cwd=%s dos_cwd=%s\n",
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000716 'A' + drive, unix_cwd, full_name.short_name + 3 );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000717
Alexandre Julliard90476d62000-02-16 22:47:24 +0000718 HeapFree( GetProcessHeap(), 0, DOSDrives[drive].dos_cwd );
719 HeapFree( GetProcessHeap(), 0, DOSDrives[drive].unix_cwd );
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000720 DOSDrives[drive].dos_cwd = heap_strdup( full_name.short_name + 3 );
721 DOSDrives[drive].unix_cwd = heap_strdup( unix_cwd );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000722
723 if (pTask && (pTask->curdrive & 0x80) &&
724 ((pTask->curdrive & ~0x80) == drive))
725 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000726 lstrcpynA( pTask->curdir, full_name.short_name + 2,
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000727 sizeof(pTask->curdir) );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000728 DRIVE_LastTask = GetCurrentTask();
Marcus Meissner34ed4fd2000-09-27 00:22:16 +0000729 chdir(unix_cwd); /* Only change if on current drive */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000730 }
731 return 1;
732}
733
734
735/***********************************************************************
736 * DRIVE_Disable
737 */
738int DRIVE_Disable( int drive )
739{
740 if ((drive < 0) || (drive >= MAX_DOS_DRIVES) || !DOSDrives[drive].root)
741 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000742 SetLastError( ERROR_INVALID_DRIVE );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000743 return 0;
744 }
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000745 DOSDrives[drive].flags |= DRIVE_DISABLED;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000746 return 1;
747}
748
749
750/***********************************************************************
751 * DRIVE_Enable
752 */
753int DRIVE_Enable( int drive )
754{
755 if ((drive < 0) || (drive >= MAX_DOS_DRIVES) || !DOSDrives[drive].root)
756 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000757 SetLastError( ERROR_INVALID_DRIVE );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000758 return 0;
759 }
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000760 DOSDrives[drive].flags &= ~DRIVE_DISABLED;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000761 return 1;
762}
763
764
765/***********************************************************************
Alexandre Julliard491502b1997-11-01 19:08:16 +0000766 * DRIVE_SetLogicalMapping
767 */
768int DRIVE_SetLogicalMapping ( int existing_drive, int new_drive )
769{
770 /* If new_drive is already valid, do nothing and return 0
771 otherwise, copy DOSDrives[existing_drive] to DOSDrives[new_drive] */
772
773 DOSDRIVE *old, *new;
774
775 old = DOSDrives + existing_drive;
776 new = DOSDrives + new_drive;
777
778 if ((existing_drive < 0) || (existing_drive >= MAX_DOS_DRIVES) ||
779 !old->root ||
780 (new_drive < 0) || (new_drive >= MAX_DOS_DRIVES))
781 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000782 SetLastError( ERROR_INVALID_DRIVE );
Alexandre Julliard491502b1997-11-01 19:08:16 +0000783 return 0;
784 }
785
786 if ( new->root )
787 {
Andreas Mohr3084b582000-07-25 20:59:59 +0000788 TRACE("Can't map drive %c: to already existing drive %c:\n",
789 'A' + existing_drive, 'A' + new_drive );
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000790 /* it is already mapped there, so return success */
791 if (!strcmp(old->root,new->root))
792 return 1;
Alexandre Julliard491502b1997-11-01 19:08:16 +0000793 return 0;
794 }
795
Alexandre Julliard5f728ca2001-07-24 21:45:22 +0000796 new->root = heap_strdup( old->root );
797 new->dos_cwd = heap_strdup( old->dos_cwd );
798 new->unix_cwd = heap_strdup( old->unix_cwd );
799 new->device = heap_strdup( old->device );
Andreas Mohr1fe93342000-01-29 21:11:47 +0000800 memcpy ( new->label_conf, old->label_conf, 12 );
Andreas Mohr3084b582000-07-25 20:59:59 +0000801 memcpy ( new->label_read, old->label_read, 12 );
Andreas Mohr1fe93342000-01-29 21:11:47 +0000802 new->serial_conf = old->serial_conf;
Alexandre Julliard491502b1997-11-01 19:08:16 +0000803 new->type = old->type;
804 new->flags = old->flags;
805 new->dev = old->dev;
806 new->ino = old->ino;
807
Andreas Mohr3084b582000-07-25 20:59:59 +0000808 TRACE("Drive %c: is now equal to drive %c:\n",
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000809 'A' + new_drive, 'A' + existing_drive );
Alexandre Julliard491502b1997-11-01 19:08:16 +0000810
811 return 1;
812}
813
814
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000815/***********************************************************************
816 * DRIVE_OpenDevice
817 *
818 * Open the drive raw device and return a Unix fd (or -1 on error).
819 */
820int DRIVE_OpenDevice( int drive, int flags )
821{
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000822 if (!DRIVE_IsValid( drive )) return -1;
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000823 return open( DOSDrives[drive].device, flags );
824}
825
Alexandre Julliard491502b1997-11-01 19:08:16 +0000826
827/***********************************************************************
Andreas Mohrcc0248e1999-01-03 12:31:51 +0000828 * DRIVE_RawRead
829 *
830 * Read raw sectors from a device
831 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000832int DRIVE_RawRead(BYTE drive, DWORD begin, DWORD nr_sect, BYTE *dataptr, BOOL fake_success)
Andreas Mohrcc0248e1999-01-03 12:31:51 +0000833{
834 int fd;
835
836 if ((fd = DRIVE_OpenDevice( drive, O_RDONLY )) != -1)
837 {
838 lseek( fd, begin * 512, SEEK_SET );
839 /* FIXME: check errors */
840 read( fd, dataptr, nr_sect * 512 );
841 close( fd );
842 }
843 else
844 {
845 memset(dataptr, 0, nr_sect * 512);
Andreas Mohr3084b582000-07-25 20:59:59 +0000846 if (fake_success)
Andreas Mohrcc0248e1999-01-03 12:31:51 +0000847 {
Andreas Mohr3084b582000-07-25 20:59:59 +0000848 if (begin == 0 && nr_sect > 1) *(dataptr + 512) = 0xf8;
849 if (begin == 1) *dataptr = 0xf8;
850 }
851 else
852 return 0;
Andreas Mohrcc0248e1999-01-03 12:31:51 +0000853 }
Andreas Mohr3084b582000-07-25 20:59:59 +0000854 return 1;
Andreas Mohrcc0248e1999-01-03 12:31:51 +0000855}
856
857
858/***********************************************************************
859 * DRIVE_RawWrite
860 *
861 * Write raw sectors to a device
862 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000863int DRIVE_RawWrite(BYTE drive, DWORD begin, DWORD nr_sect, BYTE *dataptr, BOOL fake_success)
Andreas Mohrcc0248e1999-01-03 12:31:51 +0000864{
Andreas Mohr3084b582000-07-25 20:59:59 +0000865 int fd;
Andreas Mohrcc0248e1999-01-03 12:31:51 +0000866
867 if ((fd = DRIVE_OpenDevice( drive, O_RDONLY )) != -1)
868 {
869 lseek( fd, begin * 512, SEEK_SET );
870 /* FIXME: check errors */
871 write( fd, dataptr, nr_sect * 512 );
872 close( fd );
873 }
874 else
Andreas Mohr3084b582000-07-25 20:59:59 +0000875 if (!(fake_success))
876 return 0;
Andreas Mohrcc0248e1999-01-03 12:31:51 +0000877
Andreas Mohr3084b582000-07-25 20:59:59 +0000878 return 1;
Andreas Mohrcc0248e1999-01-03 12:31:51 +0000879}
880
881
882/***********************************************************************
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000883 * DRIVE_GetFreeSpace
884 */
Juergen Schmied1ed51af1999-02-12 17:47:07 +0000885static int DRIVE_GetFreeSpace( int drive, PULARGE_INTEGER size,
886 PULARGE_INTEGER available )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000887{
888 struct statfs info;
889
890 if (!DRIVE_IsValid(drive))
891 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000892 SetLastError( ERROR_INVALID_DRIVE );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000893 return 0;
894 }
895
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000896/* FIXME: add autoconf check for this */
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +0000897#if defined(__svr4__) || defined(_SCO_DS) || defined(__sun)
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000898 if (statfs( DOSDrives[drive].root, &info, 0, 0) < 0)
899#else
900 if (statfs( DOSDrives[drive].root, &info) < 0)
901#endif
902 {
903 FILE_SetDosError();
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000904 WARN("cannot do statfs(%s)\n", DOSDrives[drive].root);
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000905 return 0;
906 }
907
Alexandre Julliard27952ef2000-10-13 20:26:03 +0000908 size->QuadPart = RtlEnlargedUnsignedMultiply( info.f_bsize, info.f_blocks );
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000909#ifdef STATFS_HAS_BAVAIL
Alexandre Julliard27952ef2000-10-13 20:26:03 +0000910 available->QuadPart = RtlEnlargedUnsignedMultiply( info.f_bavail, info.f_bsize );
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000911#else
912# ifdef STATFS_HAS_BFREE
Alexandre Julliard27952ef2000-10-13 20:26:03 +0000913 available->QuadPart = RtlEnlargedUnsignedMultiply( info.f_bfree, info.f_bsize );
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000914# else
915# error "statfs has no bfree/bavail member!"
916# endif
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000917#endif
Alexandre Julliardbf672592000-12-12 00:44:42 +0000918 if (DOSDrives[drive].type == DRIVE_CDROM)
Andreas Mohrbd86d18f2000-06-13 03:36:05 +0000919 { /* ALWAYS 0, even if no real CD-ROM mounted there !! */
Alexandre Julliard27952ef2000-10-13 20:26:03 +0000920 available->QuadPart = 0;
Andreas Mohrbd86d18f2000-06-13 03:36:05 +0000921 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000922 return 1;
923}
924
Peter Gantenea5941b1999-12-05 23:51:56 +0000925/***********************************************************************
Abey George70810d91999-09-27 11:39:43 +0000926 * DRIVE_GetCurrentDirectory
927 * Returns "X:\\path\\etc\\".
928 *
929 * Despite the API description, return required length including the
930 * terminating null when buffer too small. This is the real behaviour.
931*/
932
933static UINT DRIVE_GetCurrentDirectory( UINT buflen, LPSTR buf )
934{
935 UINT ret;
936 const char *s = DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() );
937
938 assert(s);
939 ret = strlen(s) + 3; /* length of WHOLE current directory */
940 if (ret >= buflen) return ret + 1;
Francois Gouget6d77d3a2000-03-25 21:44:35 +0000941 lstrcpynA( buf, "A:\\", min( 4, buflen ) );
Abey George70810d91999-09-27 11:39:43 +0000942 if (buflen) buf[0] += DRIVE_GetCurrentDrive();
943 if (buflen > 3) lstrcpynA( buf + 3, s, buflen - 3 );
944 return ret;
945}
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000946
Alexandre Julliardaef9a362000-10-03 04:19:16 +0000947
948/***********************************************************************
949 * DRIVE_BuildEnv
950 *
Andreas Mohrf3598952001-10-02 17:49:20 +0000951 * Build the environment array containing the drives' current directories.
Alexandre Julliardaef9a362000-10-03 04:19:16 +0000952 * Resulting pointer must be freed with HeapFree.
953 */
954char *DRIVE_BuildEnv(void)
955{
956 int i, length = 0;
957 const char *cwd[MAX_DOS_DRIVES];
958 char *env, *p;
959
960 for (i = 0; i < MAX_DOS_DRIVES; i++)
961 {
962 if ((cwd[i] = DRIVE_GetDosCwd(i)) && cwd[i][0]) length += strlen(cwd[i]) + 8;
963 }
964 if (!(env = HeapAlloc( GetProcessHeap(), 0, length+1 ))) return NULL;
965 for (i = 0, p = env; i < MAX_DOS_DRIVES; i++)
966 {
967 if (cwd[i] && cwd[i][0])
968 p += sprintf( p, "=%c:=%c:\\%s", 'A'+i, 'A'+i, cwd[i] ) + 1;
969 }
970 *p = 0;
971 return env;
972}
973
974
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000975/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +0000976 * GetDiskFreeSpace (KERNEL.422)
Alexandre Julliard339eefc1996-06-23 14:56:20 +0000977 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000978BOOL16 WINAPI GetDiskFreeSpace16( LPCSTR root, LPDWORD cluster_sectors,
979 LPDWORD sector_bytes, LPDWORD free_clusters,
980 LPDWORD total_clusters )
Alexandre Julliard339eefc1996-06-23 14:56:20 +0000981{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000982 return GetDiskFreeSpaceA( root, cluster_sectors, sector_bytes,
Alexandre Julliard339eefc1996-06-23 14:56:20 +0000983 free_clusters, total_clusters );
984}
985
986
987/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +0000988 * GetDiskFreeSpaceA (KERNEL32.@)
Andreas Mohr4ae195a1998-11-27 15:02:25 +0000989 *
990 * Fails if expression resulting from current drive's dir and "root"
991 * is not a root dir of the target drive.
992 *
993 * UNDOC: setting some LPDWORDs to NULL is perfectly possible
994 * if the corresponding info is unneeded.
995 *
996 * FIXME: needs to support UNC names from Win95 OSR2 on.
997 *
998 * Behaviour under Win95a:
999 * CurrDir root result
1000 * "E:\\TEST" "E:" FALSE
1001 * "E:\\" "E:" TRUE
1002 * "E:\\" "E" FALSE
1003 * "E:\\" "\\" TRUE
1004 * "E:\\TEST" "\\" TRUE
1005 * "E:\\TEST" ":\\" FALSE
1006 * "E:\\TEST" "E:\\" TRUE
1007 * "E:\\TEST" "" FALSE
1008 * "E:\\" "" FALSE (!)
1009 * "E:\\" 0x0 TRUE
1010 * "E:\\TEST" 0x0 TRUE (!)
1011 * "E:\\TEST" "C:" TRUE (when CurrDir of "C:" set to "\\")
1012 * "E:\\TEST" "C:" FALSE (when CurrDir of "C:" set to "\\TEST")
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001013 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001014BOOL WINAPI GetDiskFreeSpaceA( LPCSTR root, LPDWORD cluster_sectors,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001015 LPDWORD sector_bytes, LPDWORD free_clusters,
1016 LPDWORD total_clusters )
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001017{
Andreas Mohrbd86d18f2000-06-13 03:36:05 +00001018 int drive, sec_size;
Uwe Bonnesf3836f51998-12-10 09:56:06 +00001019 ULARGE_INTEGER size,available;
Andreas Mohr4ae195a1998-11-27 15:02:25 +00001020 LPCSTR path;
1021 DWORD cluster_sec;
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001022
Peter Schlaile6deeedb1999-11-04 01:39:59 +00001023 if ((!root) || (strcmp(root,"\\") == 0))
Andreas Mohr4ae195a1998-11-27 15:02:25 +00001024 drive = DRIVE_GetCurrentDrive();
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001025 else
Andreas Mohr4ae195a1998-11-27 15:02:25 +00001026 if ( (strlen(root) >= 2) && (root[1] == ':')) /* root contains drive tag */
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001027 {
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001028 drive = toupper(root[0]) - 'A';
Andreas Mohr4ae195a1998-11-27 15:02:25 +00001029 path = &root[2];
1030 if (path[0] == '\0')
1031 path = DRIVE_GetDosCwd(drive);
1032 else
1033 if (path[0] == '\\')
1034 path++;
1035 if (strlen(path)) /* oops, we are in a subdir */
1036 return FALSE;
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001037 }
Andreas Mohr4ae195a1998-11-27 15:02:25 +00001038 else
1039 return FALSE;
1040
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001041 if (!DRIVE_GetFreeSpace(drive, &size, &available)) return FALSE;
1042
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001043 /* Cap the size and available at 2GB as per specs. */
Patrik Stridvall311e4561999-09-19 14:20:33 +00001044 if ((size.s.HighPart) ||(size.s.LowPart > 0x7fffffff))
Andreas Mohrbd86d18f2000-06-13 03:36:05 +00001045 {
1046 size.s.HighPart = 0;
1047 size.s.LowPart = 0x7fffffff;
1048 }
Patrik Stridvall311e4561999-09-19 14:20:33 +00001049 if ((available.s.HighPart) ||(available.s.LowPart > 0x7fffffff))
Andreas Mohrbd86d18f2000-06-13 03:36:05 +00001050 {
Patrik Stridvall311e4561999-09-19 14:20:33 +00001051 available.s.HighPart =0;
1052 available.s.LowPart = 0x7fffffff;
Alexandre Julliard02e90081998-01-04 17:49:09 +00001053 }
Alexandre Julliardbf672592000-12-12 00:44:42 +00001054 sec_size = (DRIVE_GetType(drive)==DRIVE_CDROM) ? 2048 : 512;
Andreas Mohrbd86d18f2000-06-13 03:36:05 +00001055 size.s.LowPart /= sec_size;
1056 available.s.LowPart /= sec_size;
Alexandre Julliard02e90081998-01-04 17:49:09 +00001057 /* fixme: probably have to adjust those variables too for CDFS */
Andreas Mohr4ae195a1998-11-27 15:02:25 +00001058 cluster_sec = 1;
Patrik Stridvall311e4561999-09-19 14:20:33 +00001059 while (cluster_sec * 65536 < size.s.LowPart) cluster_sec *= 2;
Andreas Mohr4ae195a1998-11-27 15:02:25 +00001060
1061 if (cluster_sectors)
1062 *cluster_sectors = cluster_sec;
Andreas Mohrbd86d18f2000-06-13 03:36:05 +00001063 if (sector_bytes)
1064 *sector_bytes = sec_size;
Andreas Mohr4ae195a1998-11-27 15:02:25 +00001065 if (free_clusters)
Patrik Stridvall311e4561999-09-19 14:20:33 +00001066 *free_clusters = available.s.LowPart / cluster_sec;
Andreas Mohr4ae195a1998-11-27 15:02:25 +00001067 if (total_clusters)
Patrik Stridvall311e4561999-09-19 14:20:33 +00001068 *total_clusters = size.s.LowPart / cluster_sec;
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001069 return TRUE;
1070}
1071
1072
1073/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001074 * GetDiskFreeSpaceW (KERNEL32.@)
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001075 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001076BOOL WINAPI GetDiskFreeSpaceW( LPCWSTR root, LPDWORD cluster_sectors,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001077 LPDWORD sector_bytes, LPDWORD free_clusters,
1078 LPDWORD total_clusters )
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001079{
1080 LPSTR xroot;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001081 BOOL ret;
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001082
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001083 xroot = HEAP_strdupWtoA( GetProcessHeap(), 0, root);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001084 ret = GetDiskFreeSpaceA( xroot,cluster_sectors, sector_bytes,
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001085 free_clusters, total_clusters );
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001086 HeapFree( GetProcessHeap(), 0, xroot );
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001087 return ret;
1088}
1089
1090
1091/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001092 * GetDiskFreeSpaceExA (KERNEL32.@)
Morten Eriksen1563e831999-08-07 12:29:04 +00001093 *
Andreas Mohrf32f9182001-04-20 18:36:05 +00001094 * This function is used to acquire the size of the available and
Morten Eriksen1563e831999-08-07 12:29:04 +00001095 * total space on a logical volume.
1096 *
1097 * RETURNS
1098 *
1099 * Zero on failure, nonzero upon success. Use GetLastError to obtain
1100 * detailed error information.
1101 *
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001102 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001103BOOL WINAPI GetDiskFreeSpaceExA( LPCSTR root,
Juergen Schmied1ed51af1999-02-12 17:47:07 +00001104 PULARGE_INTEGER avail,
1105 PULARGE_INTEGER total,
1106 PULARGE_INTEGER totalfree)
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001107{
1108 int drive;
Uwe Bonnesf3836f51998-12-10 09:56:06 +00001109 ULARGE_INTEGER size,available;
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001110
1111 if (!root) drive = DRIVE_GetCurrentDrive();
1112 else
Gerard Pateld6bd2822001-10-08 22:15:39 +00001113 { /* C: always works for GetDiskFreeSpaceEx */
1114 if ((root[1]) && ((root[1] != ':') || (root[2] && root[2] != '\\')))
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001115 {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001116 FIXME("there are valid root names which are not supported yet\n");
Morten Eriksen1563e831999-08-07 12:29:04 +00001117 /* ..like UNC names, for instance. */
1118
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001119 WARN("invalid root '%s'\n", root );
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001120 return FALSE;
1121 }
1122 drive = toupper(root[0]) - 'A';
1123 }
Morten Eriksen1563e831999-08-07 12:29:04 +00001124
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001125 if (!DRIVE_GetFreeSpace(drive, &size, &available)) return FALSE;
Morten Eriksen1563e831999-08-07 12:29:04 +00001126
1127 if (total)
1128 {
Patrik Stridvall311e4561999-09-19 14:20:33 +00001129 total->s.HighPart = size.s.HighPart;
Andreas Mohr3084b582000-07-25 20:59:59 +00001130 total->s.LowPart = size.s.LowPart;
Eric Pouech6ec64921999-02-02 10:25:41 +00001131 }
Morten Eriksen1563e831999-08-07 12:29:04 +00001132
1133 if (totalfree)
1134 {
Patrik Stridvall311e4561999-09-19 14:20:33 +00001135 totalfree->s.HighPart = available.s.HighPart;
Andreas Mohr3084b582000-07-25 20:59:59 +00001136 totalfree->s.LowPart = available.s.LowPart;
Eric Pouech6ec64921999-02-02 10:25:41 +00001137 }
Morten Eriksen1563e831999-08-07 12:29:04 +00001138
1139 if (avail)
1140 {
Morten Eriksen467845a1999-08-15 14:20:18 +00001141 if (FIXME_ON(dosfs))
1142 {
1143 /* On Windows2000, we need to check the disk quota
1144 allocated for the user owning the calling process. We
1145 don't want to be more obtrusive than necessary with the
1146 FIXME messages, so don't print the FIXME unless Wine is
1147 actually masquerading as Windows2000. */
1148
1149 OSVERSIONINFOA ovi;
1150 ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1151 if (GetVersionExA(&ovi))
1152 {
1153 if (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4)
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001154 FIXME("no per-user quota support yet\n");
Morten Eriksen467845a1999-08-15 14:20:18 +00001155 }
1156 }
1157
1158 /* Quick hack, should eventually be fixed to work 100% with
1159 Windows2000 (see comment above). */
Patrik Stridvall311e4561999-09-19 14:20:33 +00001160 avail->s.HighPart = available.s.HighPart;
Andreas Mohr3084b582000-07-25 20:59:59 +00001161 avail->s.LowPart = available.s.LowPart;
Morten Eriksen1563e831999-08-07 12:29:04 +00001162 }
1163
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001164 return TRUE;
1165}
1166
1167/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001168 * GetDiskFreeSpaceExW (KERNEL32.@)
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001169 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001170BOOL WINAPI GetDiskFreeSpaceExW( LPCWSTR root, PULARGE_INTEGER avail,
Juergen Schmied1ed51af1999-02-12 17:47:07 +00001171 PULARGE_INTEGER total,
1172 PULARGE_INTEGER totalfree)
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001173{
1174 LPSTR xroot;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001175 BOOL ret;
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001176
1177 xroot = HEAP_strdupWtoA( GetProcessHeap(), 0, root);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001178 ret = GetDiskFreeSpaceExA( xroot, avail, total, totalfree);
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001179 HeapFree( GetProcessHeap(), 0, xroot );
1180 return ret;
1181}
1182
1183/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001184 * GetDriveType (KERNEL.136)
Andreas Mohr1fe93342000-01-29 21:11:47 +00001185 * This function returns the type of a drive in Win16.
Alexandre Julliard642d3131998-07-12 19:29:36 +00001186 * Note that it returns DRIVE_REMOTE for CD-ROMs, since MSCDEX uses the
Andreas Mohr91a8e0d2000-02-18 19:06:49 +00001187 * remote drive API. The return value DRIVE_REMOTE for CD-ROMs has been
1188 * verified on Win 3.11 and Windows 95. Some programs rely on it, so don't
Alexandre Julliard642d3131998-07-12 19:29:36 +00001189 * do any pseudo-clever changes.
1190 *
1191 * RETURNS
1192 * drivetype DRIVE_xxx
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001193 */
Alexandre Julliardbf672592000-12-12 00:44:42 +00001194UINT16 WINAPI GetDriveType16( UINT16 drive ) /* [in] number (NOT letter) of drive */
1195{
1196 UINT type = DRIVE_GetType(drive);
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001197 TRACE("(%c:)\n", 'A' + drive );
Alexandre Julliardbf672592000-12-12 00:44:42 +00001198 if (type == DRIVE_CDROM) type = DRIVE_REMOTE;
1199 return type;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001200}
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001201
1202
1203/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001204 * GetDriveTypeA (KERNEL32.@)
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001205 *
Andreas Mohr3084b582000-07-25 20:59:59 +00001206 * Returns the type of the disk drive specified. If root is NULL the
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001207 * root of the current directory is used.
1208 *
1209 * RETURNS
1210 *
1211 * Type of drive (from Win32 SDK):
1212 *
1213 * DRIVE_UNKNOWN unable to find out anything about the drive
Andreas Mohr3084b582000-07-25 20:59:59 +00001214 * DRIVE_NO_ROOT_DIR nonexistent root dir
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001215 * DRIVE_REMOVABLE the disk can be removed from the machine
1216 * DRIVE_FIXED the disk can not be removed from the machine
1217 * DRIVE_REMOTE network disk
1218 * DRIVE_CDROM CDROM drive
Andreas Mohr3084b582000-07-25 20:59:59 +00001219 * DRIVE_RAMDISK virtual disk in RAM
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001220 */
Patrik Stridvall2b3aa612000-12-01 23:58:28 +00001221UINT WINAPI GetDriveTypeA(LPCSTR root) /* [in] String describing drive */
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001222{
Petter Reinholdtsen0dce5b71998-10-11 14:26:25 +00001223 int drive;
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001224 TRACE("(%s)\n", debugstr_a(root));
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001225
Petter Reinholdtsen0dce5b71998-10-11 14:26:25 +00001226 if (NULL == root) drive = DRIVE_GetCurrentDrive();
1227 else
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001228 {
Petter Reinholdtsen0dce5b71998-10-11 14:26:25 +00001229 if ((root[1]) && (root[1] != ':'))
1230 {
Francois Gougetee285b72001-05-11 20:03:40 +00001231 WARN("invalid root %s\n", debugstr_a(root));
Alexandre Julliardbf672592000-12-12 00:44:42 +00001232 return DRIVE_NO_ROOT_DIR;
Petter Reinholdtsen0dce5b71998-10-11 14:26:25 +00001233 }
1234 drive = toupper(root[0]) - 'A';
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001235 }
Alexandre Julliardbf672592000-12-12 00:44:42 +00001236 return DRIVE_GetType(drive);
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001237}
1238
1239
1240/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001241 * GetDriveTypeW (KERNEL32.@)
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001242 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001243UINT WINAPI GetDriveTypeW( LPCWSTR root )
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001244{
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001245 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, root );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001246 UINT ret = GetDriveTypeA( xpath );
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001247 HeapFree( GetProcessHeap(), 0, xpath );
Alexandre Julliard3051b641996-07-05 17:14:13 +00001248 return ret;
1249}
1250
1251
1252/***********************************************************************
Patrik Stridvall01d5e5b2001-07-02 19:59:40 +00001253 * GetCurrentDirectory (KERNEL.411)
Alexandre Julliard3051b641996-07-05 17:14:13 +00001254 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001255UINT16 WINAPI GetCurrentDirectory16( UINT16 buflen, LPSTR buf )
Alexandre Julliard3051b641996-07-05 17:14:13 +00001256{
Abey George70810d91999-09-27 11:39:43 +00001257 return (UINT16)DRIVE_GetCurrentDirectory(buflen, buf);
Alexandre Julliard3051b641996-07-05 17:14:13 +00001258}
1259
1260
1261/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001262 * GetCurrentDirectoryA (KERNEL32.@)
Alexandre Julliard3051b641996-07-05 17:14:13 +00001263 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001264UINT WINAPI GetCurrentDirectoryA( UINT buflen, LPSTR buf )
Alexandre Julliard3051b641996-07-05 17:14:13 +00001265{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001266 UINT ret;
Abey George70810d91999-09-27 11:39:43 +00001267 char longname[MAX_PATHNAME_LEN];
Peter Gantenea5941b1999-12-05 23:51:56 +00001268 char shortname[MAX_PATHNAME_LEN];
1269 ret = DRIVE_GetCurrentDirectory(MAX_PATHNAME_LEN, shortname);
1270 if ( ret > MAX_PATHNAME_LEN ) {
1271 ERR_(file)("pathnamelength (%d) > MAX_PATHNAME_LEN!\n", ret );
1272 return ret;
1273 }
1274 GetLongPathNameA(shortname, longname, MAX_PATHNAME_LEN);
Alexandre Julliardcb10fda2000-08-06 02:41:16 +00001275 ret = strlen( longname ) + 1;
Peter Gantenea5941b1999-12-05 23:51:56 +00001276 if (ret > buflen) return ret;
Alexandre Julliardcb10fda2000-08-06 02:41:16 +00001277 strcpy(buf, longname);
Peter Gantenea5941b1999-12-05 23:51:56 +00001278 return ret - 1;
Alexandre Julliard3051b641996-07-05 17:14:13 +00001279}
1280
Alexandre Julliard3051b641996-07-05 17:14:13 +00001281/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001282 * GetCurrentDirectoryW (KERNEL32.@)
Alexandre Julliard3051b641996-07-05 17:14:13 +00001283 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001284UINT WINAPI GetCurrentDirectoryW( UINT buflen, LPWSTR buf )
Alexandre Julliard3051b641996-07-05 17:14:13 +00001285{
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001286 LPSTR xpath = HeapAlloc( GetProcessHeap(), 0, buflen+1 );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001287 UINT ret = GetCurrentDirectoryA( buflen, xpath );
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00001288 if (ret < buflen) ret = MultiByteToWideChar( CP_ACP, 0, xpath, -1, buf, buflen ) - 1;
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001289 HeapFree( GetProcessHeap(), 0, xpath );
Alexandre Julliard3051b641996-07-05 17:14:13 +00001290 return ret;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001291}
1292
1293
1294/***********************************************************************
1295 * SetCurrentDirectory (KERNEL.412)
1296 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001297BOOL16 WINAPI SetCurrentDirectory16( LPCSTR dir )
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001298{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001299 return SetCurrentDirectoryA( dir );
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001300}
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001301
Alexandre Julliard349a9531997-02-02 19:01:52 +00001302
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001303/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001304 * SetCurrentDirectoryA (KERNEL32.@)
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001305 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001306BOOL WINAPI SetCurrentDirectoryA( LPCSTR dir )
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001307{
Andreas Mohr3084b582000-07-25 20:59:59 +00001308 int drive, olddrive = DRIVE_GetCurrentDrive();
Alexandre Julliard349a9531997-02-02 19:01:52 +00001309
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001310 if (!dir) {
Alexandre Julliard06c275a1999-05-02 14:32:27 +00001311 ERR_(file)("(NULL)!\n");
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001312 return FALSE;
1313 }
Alexandre Julliard349a9531997-02-02 19:01:52 +00001314 if (dir[0] && (dir[1]==':'))
1315 {
Andreas Mohr3084b582000-07-25 20:59:59 +00001316 drive = toupper( *dir ) - 'A';
Alexandre Julliard349a9531997-02-02 19:01:52 +00001317 dir += 2;
1318 }
Andreas Mohr3084b582000-07-25 20:59:59 +00001319 else
1320 drive = olddrive;
Andreas Mohrfe6dfb01998-10-11 17:36:06 +00001321
1322 /* WARNING: we need to set the drive before the dir, as DRIVE_Chdir
1323 sets pTask->curdir only if pTask->curdrive is drive */
Andreas Mohrfe6dfb01998-10-11 17:36:06 +00001324 if (!(DRIVE_SetCurrentDrive( drive )))
1325 return FALSE;
Alexandre Julliard349a9531997-02-02 19:01:52 +00001326 /* FIXME: what about empty strings? Add a \\ ? */
Andreas Mohrfe6dfb01998-10-11 17:36:06 +00001327 if (!DRIVE_Chdir( drive, dir )) {
1328 DRIVE_SetCurrentDrive(olddrive);
1329 return FALSE;
1330 }
1331 return TRUE;
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001332}
1333
Alexandre Julliard349a9531997-02-02 19:01:52 +00001334
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001335/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001336 * SetCurrentDirectoryW (KERNEL32.@)
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001337 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001338BOOL WINAPI SetCurrentDirectoryW( LPCWSTR dirW )
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001339{
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001340 LPSTR dir = HEAP_strdupWtoA( GetProcessHeap(), 0, dirW );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001341 BOOL res = SetCurrentDirectoryA( dir );
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001342 HeapFree( GetProcessHeap(), 0, dir );
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001343 return res;
1344}
1345
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001346
1347/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001348 * GetLogicalDriveStringsA (KERNEL32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001349 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001350UINT WINAPI GetLogicalDriveStringsA( UINT len, LPSTR buffer )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001351{
1352 int drive, count;
1353
1354 for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
1355 if (DRIVE_IsValid(drive)) count++;
Uwe Bonnesc25e7151999-10-13 13:57:38 +00001356 if ((count * 4) + 1 <= len)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001357 {
1358 LPSTR p = buffer;
1359 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
1360 if (DRIVE_IsValid(drive))
1361 {
1362 *p++ = 'a' + drive;
1363 *p++ = ':';
1364 *p++ = '\\';
1365 *p++ = '\0';
1366 }
1367 *p = '\0';
Andreas Mohr3084b582000-07-25 20:59:59 +00001368 return count * 4;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001369 }
Uwe Bonnesc25e7151999-10-13 13:57:38 +00001370 else
Andreas Mohr3084b582000-07-25 20:59:59 +00001371 return (count * 4) + 1; /* account for terminating null */
Uwe Bonnesc25e7151999-10-13 13:57:38 +00001372 /* The API tells about these different return values */
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001373}
1374
1375
1376/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001377 * GetLogicalDriveStringsW (KERNEL32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001378 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001379UINT WINAPI GetLogicalDriveStringsW( UINT len, LPWSTR buffer )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001380{
1381 int drive, count;
1382
1383 for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
1384 if (DRIVE_IsValid(drive)) count++;
1385 if (count * 4 * sizeof(WCHAR) <= len)
1386 {
1387 LPWSTR p = buffer;
1388 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
1389 if (DRIVE_IsValid(drive))
1390 {
1391 *p++ = (WCHAR)('a' + drive);
1392 *p++ = (WCHAR)':';
1393 *p++ = (WCHAR)'\\';
1394 *p++ = (WCHAR)'\0';
1395 }
1396 *p = (WCHAR)'\0';
1397 }
1398 return count * 4 * sizeof(WCHAR);
1399}
1400
1401
1402/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001403 * GetLogicalDrives (KERNEL32.@)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001404 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001405DWORD WINAPI GetLogicalDrives(void)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001406{
1407 DWORD ret = 0;
1408 int drive;
1409
1410 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
Andreas Mohr1fe93342000-01-29 21:11:47 +00001411 {
1412 if ( (DRIVE_IsValid(drive)) ||
Alexandre Julliardbf672592000-12-12 00:44:42 +00001413 (DOSDrives[drive].type == DRIVE_CDROM)) /* audio CD is also valid */
Andreas Mohr1fe93342000-01-29 21:11:47 +00001414 ret |= (1 << drive);
1415 }
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001416 return ret;
1417}
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001418
1419
1420/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001421 * GetVolumeInformationA (KERNEL32.@)
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001422 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001423BOOL WINAPI GetVolumeInformationA( LPCSTR root, LPSTR label,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001424 DWORD label_len, DWORD *serial,
1425 DWORD *filename_len, DWORD *flags,
1426 LPSTR fsname, DWORD fsname_len )
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001427{
1428 int drive;
Alexandre Julliard829fe321998-07-26 14:27:39 +00001429 char *cp;
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001430
Andreas Mohr1fe93342000-01-29 21:11:47 +00001431 /* FIXME, SetLastError()s missing */
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001432
1433 if (!root) drive = DRIVE_GetCurrentDrive();
1434 else
1435 {
Alexandre Julliard02e90081998-01-04 17:49:09 +00001436 if ((root[1]) && (root[1] != ':'))
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001437 {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001438 WARN("invalid root '%s'\n",root);
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001439 return FALSE;
1440 }
1441 drive = toupper(root[0]) - 'A';
1442 }
1443 if (!DRIVE_IsValid( drive )) return FALSE;
Alexandre Julliard829fe321998-07-26 14:27:39 +00001444 if (label)
1445 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001446 lstrcpynA( label, DRIVE_GetLabel(drive), label_len );
Alexandre Julliard566a52a2001-03-05 19:34:17 +00001447 cp = label + strlen(label);
Alexandre Julliard829fe321998-07-26 14:27:39 +00001448 while (cp != label && *(cp-1) == ' ') cp--;
1449 *cp = '\0';
1450 }
Petter Reinholdtsen6ca3f791998-10-20 14:25:50 +00001451 if (serial) *serial = DRIVE_GetSerialNumber(drive);
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001452
1453 /* Set the filesystem information */
Andreas Mohr1fe93342000-01-29 21:11:47 +00001454 /* Note: we only emulate a FAT fs at present */
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001455
Alexandre Julliard767e6f61998-08-09 12:47:43 +00001456 if (filename_len) {
1457 if (DOSDrives[drive].flags & DRIVE_SHORT_NAMES)
1458 *filename_len = 12;
1459 else
1460 *filename_len = 255;
1461 }
Uwe Bonnes27233421999-02-11 10:23:05 +00001462 if (flags)
1463 {
1464 *flags=0;
1465 if (DOSDrives[drive].flags & DRIVE_CASE_SENSITIVE)
1466 *flags|=FS_CASE_SENSITIVE;
1467 if (DOSDrives[drive].flags & DRIVE_CASE_PRESERVING)
Andreas Mohr91a8e0d2000-02-18 19:06:49 +00001468 *flags|=FS_CASE_IS_PRESERVED;
Uwe Bonnes27233421999-02-11 10:23:05 +00001469 }
Alexandre Julliard02e90081998-01-04 17:49:09 +00001470 if (fsname) {
1471 /* Diablo checks that return code ... */
Alexandre Julliardbf672592000-12-12 00:44:42 +00001472 if (DOSDrives[drive].type == DRIVE_CDROM)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001473 lstrcpynA( fsname, "CDFS", fsname_len );
Alexandre Julliard02e90081998-01-04 17:49:09 +00001474 else
Alexandre Julliarda3960291999-02-26 11:11:13 +00001475 lstrcpynA( fsname, "FAT", fsname_len );
Alexandre Julliard02e90081998-01-04 17:49:09 +00001476 }
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001477 return TRUE;
1478}
1479
1480
1481/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001482 * GetVolumeInformationW (KERNEL32.@)
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001483 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001484BOOL WINAPI GetVolumeInformationW( LPCWSTR root, LPWSTR label,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001485 DWORD label_len, DWORD *serial,
1486 DWORD *filename_len, DWORD *flags,
1487 LPWSTR fsname, DWORD fsname_len )
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001488{
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001489 LPSTR xroot = HEAP_strdupWtoA( GetProcessHeap(), 0, root );
1490 LPSTR xvolname = label ? HeapAlloc(GetProcessHeap(),0,label_len) : NULL;
1491 LPSTR xfsname = fsname ? HeapAlloc(GetProcessHeap(),0,fsname_len) : NULL;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001492 BOOL ret = GetVolumeInformationA( xroot, xvolname, label_len, serial,
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001493 filename_len, flags, xfsname,
1494 fsname_len );
1495 if (ret)
1496 {
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00001497 if (label) MultiByteToWideChar( CP_ACP, 0, xvolname, -1, label, label_len );
1498 if (fsname) MultiByteToWideChar( CP_ACP, 0, xfsname, -1, fsname, fsname_len );
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001499 }
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001500 HeapFree( GetProcessHeap(), 0, xroot );
1501 HeapFree( GetProcessHeap(), 0, xvolname );
1502 HeapFree( GetProcessHeap(), 0, xfsname );
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001503 return ret;
1504}
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001505
Dave Pickles18d3ad81999-06-05 15:19:30 +00001506/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001507 * SetVolumeLabelA (KERNEL32.@)
Dave Pickles18d3ad81999-06-05 15:19:30 +00001508 */
Ove Kaavena01e2892000-01-15 23:28:26 +00001509BOOL WINAPI SetVolumeLabelA( LPCSTR root, LPCSTR volname )
Dave Pickles18d3ad81999-06-05 15:19:30 +00001510{
Ove Kaavena01e2892000-01-15 23:28:26 +00001511 int drive;
1512
1513 /* FIXME, SetLastErrors missing */
1514
1515 if (!root) drive = DRIVE_GetCurrentDrive();
1516 else
1517 {
1518 if ((root[1]) && (root[1] != ':'))
1519 {
1520 WARN("invalid root '%s'\n",root);
1521 return FALSE;
1522 }
1523 drive = toupper(root[0]) - 'A';
1524 }
1525 if (!DRIVE_IsValid( drive )) return FALSE;
1526
1527 /* some copy protection stuff check this */
Alexandre Julliardbf672592000-12-12 00:44:42 +00001528 if (DOSDrives[drive].type == DRIVE_CDROM) return FALSE;
Ove Kaavena01e2892000-01-15 23:28:26 +00001529
1530 FIXME("(%s,%s),stub!\n", root, volname);
1531 return TRUE;
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001532}
Dave Pickles18d3ad81999-06-05 15:19:30 +00001533
1534/***********************************************************************
Patrik Stridvalldae8de62001-06-13 20:13:18 +00001535 * SetVolumeLabelW (KERNEL32.@)
Dave Pickles18d3ad81999-06-05 15:19:30 +00001536 */
1537BOOL WINAPI SetVolumeLabelW(LPCWSTR rootpath,LPCWSTR volname)
1538{
1539 LPSTR xroot, xvol;
1540 BOOL ret;
1541
1542 xroot = HEAP_strdupWtoA( GetProcessHeap(), 0, rootpath);
1543 xvol = HEAP_strdupWtoA( GetProcessHeap(), 0, volname);
1544 ret = SetVolumeLabelA( xroot, xvol );
1545 HeapFree( GetProcessHeap(), 0, xroot );
1546 HeapFree( GetProcessHeap(), 0, xvol );
1547 return ret;
1548}