blob: 8e790e4b0e483e98765dd7e1703f5afe43489e6e [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
Alexandre Julliardc7c217b1998-04-13 12:21:30 +000013#include "config.h"
14
Alexandre Julliard491502b1997-11-01 19:08:16 +000015#include <assert.h>
Alexandre Julliard2d93d001996-05-21 15:01:41 +000016#include <ctype.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000017#include <string.h>
Alexandre Julliardaef9a362000-10-03 04:19:16 +000018#include <stdio.h>
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000019#include <stdlib.h>
Alexandre Julliard0c126c71996-02-18 18:44:41 +000020#include <sys/types.h>
Alexandre Julliard7e56f681996-01-31 19:02:28 +000021#include <sys/stat.h>
Alexandre Julliard03468f71998-02-15 19:40:49 +000022#include <fcntl.h>
Alexandre Julliardc7c217b1998-04-13 12:21:30 +000023#include <errno.h>
Andreas Mohrcc0248e1999-01-03 12:31:51 +000024#include <unistd.h>
Alexandre Julliard7e56f681996-01-31 19:02:28 +000025
Alexandre Julliardc7c217b1998-04-13 12:21:30 +000026#ifdef HAVE_SYS_PARAM_H
27# include <sys/param.h>
Alexandre Julliard7e56f681996-01-31 19:02:28 +000028#endif
Alexandre Julliarddadf78f1998-05-17 17:13:43 +000029#ifdef STATFS_DEFINED_BY_SYS_VFS
30# include <sys/vfs.h>
31#else
32# ifdef STATFS_DEFINED_BY_SYS_MOUNT
33# include <sys/mount.h>
34# else
35# ifdef STATFS_DEFINED_BY_SYS_STATFS
36# include <sys/statfs.h>
37# endif
38# endif
Alexandre Julliard7e56f681996-01-31 19:02:28 +000039#endif
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000040
Alexandre Julliard339eefc1996-06-23 14:56:20 +000041#include "winbase.h"
Alexandre Julliard27952ef2000-10-13 20:26:03 +000042#include "ntddk.h"
Michael Veksler249d14b1999-02-25 16:39:16 +000043#include "wine/winbase16.h" /* for GetCurrentTask */
Alexandre Julliard4ff2a271999-01-31 15:23:45 +000044#include "winerror.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000045#include "drive.h"
Andreas Mohr1fe93342000-01-29 21:11:47 +000046#include "cdrom.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000047#include "file.h"
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +000048#include "heap.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000049#include "msdos.h"
Alexandre Julliard7e56f681996-01-31 19:02:28 +000050#include "options.h"
Patrik Stridvallb9010211999-11-13 22:23:35 +000051#include "wine/port.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000052#include "task.h"
Alexandre Julliard06c275a1999-05-02 14:32:27 +000053#include "debugtools.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000054
Dimitrie O. Paun529da542000-11-27 23:54:25 +000055DEFAULT_DEBUG_CHANNEL(dosfs);
56DECLARE_DEBUG_CHANNEL(file);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000057
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000058typedef struct
59{
Alexandre Julliard7e56f681996-01-31 19:02:28 +000060 char *root; /* root dir in Unix format without trailing / */
61 char *dos_cwd; /* cwd in DOS format without leading or trailing \ */
62 char *unix_cwd; /* cwd in Unix format without leading or trailing / */
Alexandre Julliard60ce85c1998-02-01 18:33:27 +000063 char *device; /* raw device path */
Chris Morgane4055502001-01-12 19:55:19 +000064 char label_conf[12]; /* drive label as cfg'd in wine config */
Andreas Mohr1fe93342000-01-29 21:11:47 +000065 char label_read[12]; /* drive label as read from device */
Chris Morgane4055502001-01-12 19:55:19 +000066 DWORD serial_conf; /* drive serial number as cfg'd in wine config */
Alexandre Julliardbf672592000-12-12 00:44:42 +000067 UINT type; /* drive type */
Andreas Mohr91a8e0d2000-02-18 19:06:49 +000068 UINT flags; /* drive flags */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000069 dev_t dev; /* unix device number */
70 ino_t ino; /* unix inode number */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000071} DOSDRIVE;
72
Alexandre Julliard7e56f681996-01-31 19:02:28 +000073
Alexandre Julliard1e37a181996-08-18 16:21:52 +000074static const char * const DRIVE_Types[] =
Alexandre Julliard7e56f681996-01-31 19:02:28 +000075{
Alexandre Julliardbf672592000-12-12 00:44:42 +000076 "", /* DRIVE_UNKNOWN */
77 "", /* DRIVE_NO_ROOT_DIR */
78 "floppy", /* DRIVE_REMOVABLE */
79 "hd", /* DRIVE_FIXED */
80 "network", /* DRIVE_REMOTE */
81 "cdrom", /* DRIVE_CDROM */
82 "ramdisk" /* DRIVE_RAMDISK */
Alexandre Julliard7e56f681996-01-31 19:02:28 +000083};
84
85
Alexandre Julliard1e37a181996-08-18 16:21:52 +000086/* Known filesystem types */
87
88typedef struct
89{
90 const char *name;
Alexandre Julliarda3960291999-02-26 11:11:13 +000091 UINT flags;
Alexandre Julliard1e37a181996-08-18 16:21:52 +000092} FS_DESCR;
93
94static const FS_DESCR DRIVE_Filesystems[] =
95{
96 { "unix", DRIVE_CASE_SENSITIVE | DRIVE_CASE_PRESERVING },
97 { "msdos", DRIVE_SHORT_NAMES },
98 { "dos", DRIVE_SHORT_NAMES },
99 { "fat", DRIVE_SHORT_NAMES },
100 { "vfat", DRIVE_CASE_PRESERVING },
101 { "win95", DRIVE_CASE_PRESERVING },
102 { NULL, 0 }
103};
104
105
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000106static DOSDRIVE DOSDrives[MAX_DOS_DRIVES];
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000107static int DRIVE_CurDrive = -1;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000108
Alexandre Julliardbf9130a1996-10-13 17:45:47 +0000109static HTASK16 DRIVE_LastTask = 0;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000110
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000111
112/***********************************************************************
113 * DRIVE_GetDriveType
114 */
Alexandre Julliardbf672592000-12-12 00:44:42 +0000115static UINT DRIVE_GetDriveType( const char *name )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000116{
117 char buffer[20];
118 int i;
119
120 PROFILE_GetWineIniString( name, "Type", "hd", buffer, sizeof(buffer) );
121 for (i = 0; i < sizeof(DRIVE_Types)/sizeof(DRIVE_Types[0]); i++)
122 {
Alexandre Julliardbf672592000-12-12 00:44:42 +0000123 if (!strcasecmp( buffer, DRIVE_Types[i] )) return i;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000124 }
Andreas Mohr1fe93342000-01-29 21:11:47 +0000125 MESSAGE("%s: unknown drive type '%s', defaulting to 'hd'.\n",
126 name, buffer );
Alexandre Julliardbf672592000-12-12 00:44:42 +0000127 return DRIVE_FIXED;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000128}
129
130
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000131/***********************************************************************
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000132 * DRIVE_GetFSFlags
133 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000134static UINT DRIVE_GetFSFlags( const char *name, const char *value )
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000135{
136 const FS_DESCR *descr;
137
138 for (descr = DRIVE_Filesystems; descr->name; descr++)
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +0000139 if (!strcasecmp( value, descr->name )) return descr->flags;
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000140 MESSAGE("%s: unknown filesystem type '%s', defaulting to 'win95'.\n",
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000141 name, value );
Andreas Mohre3728cd1999-02-05 10:16:19 +0000142 return DRIVE_CASE_PRESERVING;
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000143}
144
145
146/***********************************************************************
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000147 * DRIVE_Init
148 */
149int DRIVE_Init(void)
150{
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000151 int i, len, count = 0;
152 char name[] = "Drive A";
Alexandre Julliardaef9a362000-10-03 04:19:16 +0000153 char drive_env[] = "=A:";
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000154 char path[MAX_PATHNAME_LEN];
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000155 char buffer[80];
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000156 struct stat drive_stat_buffer;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000157 char *p;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000158 DOSDRIVE *drive;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000159
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000160 for (i = 0, drive = DOSDrives; i < MAX_DOS_DRIVES; i++, name[6]++, drive++)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000161 {
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000162 PROFILE_GetWineIniString( name, "Path", "", path, sizeof(path)-1 );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000163 if (path[0])
164 {
165 p = path + strlen(path) - 1;
166 while ((p > path) && ((*p == '/') || (*p == '\\'))) *p-- = '\0';
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000167 if (!path[0]) strcpy( path, "/" );
168
169 if (stat( path, &drive_stat_buffer ))
170 {
Andreas Mohra6d83eb2000-12-27 04:02:46 +0000171 MESSAGE("Could not stat %s (%s), ignoring drive %c:\n",
172 path, strerror(errno), 'A' + i);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000173 continue;
174 }
175 if (!S_ISDIR(drive_stat_buffer.st_mode))
176 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000177 MESSAGE("%s is not a directory, ignoring drive %c:\n",
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000178 path, 'A' + i );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000179 continue;
180 }
181
Alexandre Julliard90476d62000-02-16 22:47:24 +0000182 drive->root = HEAP_strdupA( GetProcessHeap(), 0, path );
183 drive->dos_cwd = HEAP_strdupA( GetProcessHeap(), 0, "" );
184 drive->unix_cwd = HEAP_strdupA( GetProcessHeap(), 0, "" );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000185 drive->type = DRIVE_GetDriveType( name );
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000186 drive->device = NULL;
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000187 drive->flags = 0;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000188 drive->dev = drive_stat_buffer.st_dev;
189 drive->ino = drive_stat_buffer.st_ino;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000190
191 /* Get the drive label */
Ryan Cumming418e27e2001-01-09 20:54:11 +0000192 PROFILE_GetWineIniString( name, "Label", "", drive->label_conf, 12 );
Andreas Mohr1fe93342000-01-29 21:11:47 +0000193 if ((len = strlen(drive->label_conf)) < 11)
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000194 {
195 /* Pad label with spaces */
Andreas Mohr1fe93342000-01-29 21:11:47 +0000196 memset( drive->label_conf + len, ' ', 11 - len );
197 drive->label_conf[11] = '\0';
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000198 }
199
200 /* Get the serial number */
201 PROFILE_GetWineIniString( name, "Serial", "12345678",
202 buffer, sizeof(buffer) );
Andreas Mohr1fe93342000-01-29 21:11:47 +0000203 drive->serial_conf = strtoul( buffer, NULL, 16 );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000204
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000205 /* Get the filesystem type */
Andreas Mohre3728cd1999-02-05 10:16:19 +0000206 PROFILE_GetWineIniString( name, "Filesystem", "win95",
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000207 buffer, sizeof(buffer) );
208 drive->flags = DRIVE_GetFSFlags( name, buffer );
209
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000210 /* Get the device */
211 PROFILE_GetWineIniString( name, "Device", "",
212 buffer, sizeof(buffer) );
213 if (buffer[0])
Andreas Mohr1fe93342000-01-29 21:11:47 +0000214 {
Alexandre Julliard90476d62000-02-16 22:47:24 +0000215 drive->device = HEAP_strdupA( GetProcessHeap(), 0, buffer );
Alexandre Julliardfbace6e2000-04-04 20:35:45 +0000216 if (PROFILE_GetWineIniBool( name, "ReadVolInfo", 1))
217 drive->flags |= DRIVE_READ_VOL_INFO;
Andreas Mohr1fe93342000-01-29 21:11:47 +0000218 }
Alexandre Julliardfbace6e2000-04-04 20:35:45 +0000219
220 /* Get the FailReadOnly flag */
221 if (PROFILE_GetWineIniBool( name, "FailReadOnly", 0 ))
222 drive->flags |= DRIVE_FAIL_READ_ONLY;
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000223
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000224 /* Make the first hard disk the current drive */
Alexandre Julliardbf672592000-12-12 00:44:42 +0000225 if ((DRIVE_CurDrive == -1) && (drive->type == DRIVE_FIXED))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000226 DRIVE_CurDrive = i;
227
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000228 count++;
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000229 TRACE("%s: path=%s type=%s label='%s' serial=%08lx "
230 "flags=%08x dev=%x ino=%x\n",
231 name, path, DRIVE_Types[drive->type],
Andreas Mohr1fe93342000-01-29 21:11:47 +0000232 drive->label_conf, drive->serial_conf, drive->flags,
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000233 (int)drive->dev, (int)drive->ino );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000234 }
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000235 else WARN("%s: not defined\n", name );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000236 }
237
238 if (!count)
239 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000240 MESSAGE("Warning: no valid DOS drive found, check your configuration file.\n" );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000241 /* Create a C drive pointing to Unix root dir */
Alexandre Julliard90476d62000-02-16 22:47:24 +0000242 DOSDrives[2].root = HEAP_strdupA( GetProcessHeap(), 0, "/" );
243 DOSDrives[2].dos_cwd = HEAP_strdupA( GetProcessHeap(), 0, "" );
244 DOSDrives[2].unix_cwd = HEAP_strdupA( GetProcessHeap(), 0, "" );
Andreas Mohr1fe93342000-01-29 21:11:47 +0000245 strcpy( DOSDrives[2].label_conf, "Drive C " );
246 DOSDrives[2].serial_conf = 12345678;
Alexandre Julliardbf672592000-12-12 00:44:42 +0000247 DOSDrives[2].type = DRIVE_FIXED;
Andreas Mohr3084b582000-07-25 20:59:59 +0000248 DOSDrives[2].device = NULL;
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000249 DOSDrives[2].flags = 0;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000250 DRIVE_CurDrive = 2;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000251 }
252
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000253 /* Make sure the current drive is valid */
254 if (DRIVE_CurDrive == -1)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000255 {
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000256 for (i = 0, drive = DOSDrives; i < MAX_DOS_DRIVES; i++, drive++)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000257 {
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000258 if (drive->root && !(drive->flags & DRIVE_DISABLED))
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000259 {
260 DRIVE_CurDrive = i;
261 break;
262 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000263 }
264 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000265
Alexandre Julliardaef9a362000-10-03 04:19:16 +0000266 /* get current working directory info for all drives */
267 for (i = 0; i < MAX_DOS_DRIVES; i++, drive_env[1]++)
268 {
269 if (!GetEnvironmentVariableA(drive_env, path, sizeof(path))) continue;
270 /* sanity check */
271 if (toupper(path[0]) != drive_env[1] || path[1] != ':') continue;
272 DRIVE_Chdir( i, path + 2 );
273 }
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000274 return 1;
275}
276
277
278/***********************************************************************
279 * DRIVE_IsValid
280 */
281int DRIVE_IsValid( int drive )
282{
283 if ((drive < 0) || (drive >= MAX_DOS_DRIVES)) return 0;
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000284 return (DOSDrives[drive].root &&
285 !(DOSDrives[drive].flags & DRIVE_DISABLED));
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000286}
287
288
289/***********************************************************************
290 * DRIVE_GetCurrentDrive
291 */
292int DRIVE_GetCurrentDrive(void)
293{
Alexandre Julliard2ec34e42001-04-04 00:21:05 +0000294 TDB *pTask = TASK_GetCurrent();
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000295 if (pTask && (pTask->curdrive & 0x80)) return pTask->curdrive & ~0x80;
296 return DRIVE_CurDrive;
297}
298
299
300/***********************************************************************
301 * DRIVE_SetCurrentDrive
302 */
303int DRIVE_SetCurrentDrive( int drive )
304{
Alexandre Julliard2ec34e42001-04-04 00:21:05 +0000305 TDB *pTask = TASK_GetCurrent();
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000306 if (!DRIVE_IsValid( drive ))
307 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000308 SetLastError( ERROR_INVALID_DRIVE );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000309 return 0;
310 }
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000311 TRACE("%c:\n", 'A' + drive );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000312 DRIVE_CurDrive = drive;
313 if (pTask) pTask->curdrive = drive | 0x80;
Marcus Meissner34ed4fd2000-09-27 00:22:16 +0000314 chdir(DRIVE_GetUnixCwd(drive));
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000315 return 1;
316}
317
318
319/***********************************************************************
320 * DRIVE_FindDriveRoot
321 *
Peter Gantenea5941b1999-12-05 23:51:56 +0000322 * Find a drive for which the root matches the beginning of the given path.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000323 * This can be used to translate a Unix path into a drive + DOS path.
324 * Return value is the drive, or -1 on error. On success, path is modified
325 * to point to the beginning of the DOS path.
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000326 */
327int DRIVE_FindDriveRoot( const char **path )
328{
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000329 /* idea: check at all '/' positions.
330 * If the device and inode of that path is identical with the
331 * device and inode of the current drive then we found a solution.
332 * If there is another drive pointing to a deeper position in
333 * the file tree, we want to find that one, not the earlier solution.
334 */
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000335 int drive, rootdrive = -1;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000336 char buffer[MAX_PATHNAME_LEN];
337 char *next = buffer;
338 const char *p = *path;
339 struct stat st;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000340
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000341 strcpy( buffer, "/" );
342 for (;;)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000343 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000344 if (stat( buffer, &st ) || !S_ISDIR( st.st_mode )) break;
345
346 /* Find the drive */
347
348 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000349 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000350 if (!DOSDrives[drive].root ||
351 (DOSDrives[drive].flags & DRIVE_DISABLED)) continue;
352
353 if ((DOSDrives[drive].dev == st.st_dev) &&
354 (DOSDrives[drive].ino == st.st_ino))
355 {
356 rootdrive = drive;
357 *path = p;
Andreas Mohr91a8e0d2000-02-18 19:06:49 +0000358 break;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000359 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000360 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000361
362 /* Get the next path component */
363
364 *next++ = '/';
365 while ((*p == '/') || (*p == '\\')) p++;
366 if (!*p) break;
367 while (!IS_END_OF_NAME(*p)) *next++ = *p++;
368 *next = 0;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000369 }
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000370 *next = 0;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000371
372 if (rootdrive != -1)
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000373 TRACE("%s -> drive %c:, root='%s', name='%s'\n",
374 buffer, 'A' + rootdrive, DOSDrives[rootdrive].root, *path );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000375 return rootdrive;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000376}
377
378
379/***********************************************************************
380 * DRIVE_GetRoot
381 */
382const char * DRIVE_GetRoot( int drive )
383{
384 if (!DRIVE_IsValid( drive )) return NULL;
385 return DOSDrives[drive].root;
386}
387
388
389/***********************************************************************
390 * DRIVE_GetDosCwd
391 */
392const char * DRIVE_GetDosCwd( int drive )
393{
Alexandre Julliard2ec34e42001-04-04 00:21:05 +0000394 TDB *pTask = TASK_GetCurrent();
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000395 if (!DRIVE_IsValid( drive )) return NULL;
396
397 /* Check if we need to change the directory to the new task. */
398 if (pTask && (pTask->curdrive & 0x80) && /* The task drive is valid */
399 ((pTask->curdrive & ~0x80) == drive) && /* and it's the one we want */
400 (DRIVE_LastTask != GetCurrentTask())) /* and the task changed */
401 {
402 /* Perform the task-switch */
403 if (!DRIVE_Chdir( drive, pTask->curdir )) DRIVE_Chdir( drive, "\\" );
404 DRIVE_LastTask = GetCurrentTask();
405 }
406 return DOSDrives[drive].dos_cwd;
407}
408
409
410/***********************************************************************
411 * DRIVE_GetUnixCwd
412 */
413const char * DRIVE_GetUnixCwd( int drive )
414{
Alexandre Julliard2ec34e42001-04-04 00:21:05 +0000415 TDB *pTask = TASK_GetCurrent();
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000416 if (!DRIVE_IsValid( drive )) return NULL;
417
418 /* Check if we need to change the directory to the new task. */
419 if (pTask && (pTask->curdrive & 0x80) && /* The task drive is valid */
420 ((pTask->curdrive & ~0x80) == drive) && /* and it's the one we want */
421 (DRIVE_LastTask != GetCurrentTask())) /* and the task changed */
422 {
423 /* Perform the task-switch */
424 if (!DRIVE_Chdir( drive, pTask->curdir )) DRIVE_Chdir( drive, "\\" );
425 DRIVE_LastTask = GetCurrentTask();
426 }
427 return DOSDrives[drive].unix_cwd;
428}
429
430
431/***********************************************************************
Andreas Mohr1fe93342000-01-29 21:11:47 +0000432 * DRIVE_GetDevice
433 */
434const char * DRIVE_GetDevice( int drive )
435{
436 return (DRIVE_IsValid( drive )) ? DOSDrives[drive].device : NULL;
437}
438
439
440/***********************************************************************
441 * DRIVE_ReadSuperblock
442 *
Petr Tomasekcd9a6332000-02-27 14:00:14 +0000443 * NOTE
444 * DRIVE_SetLabel and DRIVE_SetSerialNumber use this in order
445 * to check, that they are writing on a FAT filesystem !
Andreas Mohr1fe93342000-01-29 21:11:47 +0000446 */
447int DRIVE_ReadSuperblock (int drive, char * buff)
448{
449#define DRIVE_SUPER 96
450 int fd;
451 off_t offs;
452
453 if (memset(buff,0,DRIVE_SUPER)!=buff) return -1;
454 if ((fd=open(DOSDrives[drive].device,O_RDONLY)) == -1)
455 {
456 struct stat st;
457 if (!DOSDrives[drive].device)
458 ERR("No device configured for drive %c: !\n", 'A'+drive);
459 else
460 ERR("Couldn't open device '%s' for drive %c: ! (%s)\n", DOSDrives[drive].device, 'A'+drive,
461 (stat(DOSDrives[drive].device, &st)) ?
462 "not available or symlink not valid ?" : "no permission");
463 ERR("Can't read drive volume info ! Either pre-set it or make sure the device to read it from is accessible !\n");
464 PROFILE_UsageWineIni();
465 return -1;
466 }
467
468 switch(DOSDrives[drive].type)
469 {
Alexandre Julliardbf672592000-12-12 00:44:42 +0000470 case DRIVE_REMOVABLE:
471 case DRIVE_FIXED:
Andreas Mohr1fe93342000-01-29 21:11:47 +0000472 offs = 0;
473 break;
Alexandre Julliardbf672592000-12-12 00:44:42 +0000474 case DRIVE_CDROM:
Andreas Mohr3084b582000-07-25 20:59:59 +0000475 offs = CDROM_Data_FindBestVoldesc(fd);
Andreas Mohr1fe93342000-01-29 21:11:47 +0000476 break;
Alexandre Julliardbf672592000-12-12 00:44:42 +0000477 default:
478 offs = 0;
479 break;
Andreas Mohr1fe93342000-01-29 21:11:47 +0000480 }
481
482 if ((offs) && (lseek(fd,offs,SEEK_SET)!=offs)) return -4;
483 if (read(fd,buff,DRIVE_SUPER)!=DRIVE_SUPER) return -2;
484
485 switch(DOSDrives[drive].type)
486 {
Alexandre Julliardbf672592000-12-12 00:44:42 +0000487 case DRIVE_REMOVABLE:
488 case DRIVE_FIXED:
Petr Tomasekcd9a6332000-02-27 14:00:14 +0000489 if ((buff[0x26]!=0x29) || /* Check for FAT present */
Andreas Mohr3084b582000-07-25 20:59:59 +0000490 /* FIXME: do really all FAT have their name beginning with
Petr Tomasekcd9a6332000-02-27 14:00:14 +0000491 "FAT" ? (At least FAT12, FAT16 and FAT32 have :) */
492 memcmp( buff+0x36,"FAT",3))
493 {
494 ERR("The filesystem is not FAT !! (device=%s)\n",
495 DOSDrives[drive].device);
496 return -3;
497 }
498 break;
Alexandre Julliardbf672592000-12-12 00:44:42 +0000499 case DRIVE_CDROM:
Andreas Mohr1fe93342000-01-29 21:11:47 +0000500 if (strncmp(&buff[1],"CD001",5)) /* Check for iso9660 present */
501 return -3;
502 /* FIXME: do we need to check for "CDROM", too ? (high sierra) */
503 break;
504 default:
505 return -3;
506 break;
507 }
508
509 return close(fd);
510}
511
512
513/***********************************************************************
Petr Tomasekcd9a6332000-02-27 14:00:14 +0000514 * DRIVE_WriteSuperblockEntry
515 *
516 * NOTE
517 * We are writing as little as possible (ie. not the whole SuperBlock)
518 * not to interfere with kernel. The drive can be mounted !
519 */
520int DRIVE_WriteSuperblockEntry (int drive, off_t ofs, size_t len, char * buff)
521{
522 int fd;
523
524 if ((fd=open(DOSDrives[drive].device,O_WRONLY))==-1)
525 {
526 ERR("Cannot open the device %s (for writing)\n",
527 DOSDrives[drive].device);
528 return -1;
529 }
530 if (lseek(fd,ofs,SEEK_SET)!=ofs)
531 {
532 ERR("lseek failed on device %s !\n",
533 DOSDrives[drive].device);
534 close(fd);
535 return -2;
536 }
537 if (write(fd,buff,len)!=len)
538 {
539 close(fd);
540 ERR("Cannot write on %s !\n",
541 DOSDrives[drive].device);
542 return -3;
543 }
544 return close (fd);
545}
546
547
548
549/***********************************************************************
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000550 * DRIVE_GetLabel
551 */
552const char * DRIVE_GetLabel( int drive )
553{
Andreas Mohr1fe93342000-01-29 21:11:47 +0000554 int read = 0;
555 char buff[DRIVE_SUPER];
556 int offs = -1;
557
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000558 if (!DRIVE_IsValid( drive )) return NULL;
Alexandre Julliardbf672592000-12-12 00:44:42 +0000559 if (DOSDrives[drive].type == DRIVE_CDROM)
Andreas Mohr1fe93342000-01-29 21:11:47 +0000560 {
Andreas Mohr3084b582000-07-25 20:59:59 +0000561 read = CDROM_GetLabel(drive, DOSDrives[drive].label_read);
Andreas Mohr1fe93342000-01-29 21:11:47 +0000562 }
Andreas Mohr3084b582000-07-25 20:59:59 +0000563 else
564 if (DOSDrives[drive].flags & DRIVE_READ_VOL_INFO)
Andreas Mohr1fe93342000-01-29 21:11:47 +0000565 {
566 if (DRIVE_ReadSuperblock(drive,(char *) buff))
567 ERR("Invalid or unreadable superblock on %s (%c:).\n",
568 DOSDrives[drive].device, (char)(drive+'A'));
569 else {
Alexandre Julliardbf672592000-12-12 00:44:42 +0000570 if (DOSDrives[drive].type == DRIVE_REMOVABLE ||
571 DOSDrives[drive].type == DRIVE_FIXED)
Andreas Mohr1fe93342000-01-29 21:11:47 +0000572 offs = 0x2b;
573
Andreas Mohr3084b582000-07-25 20:59:59 +0000574 /* FIXME: ISO9660 uses a 32 bytes long label. Should we do also? */
Andreas Mohr1fe93342000-01-29 21:11:47 +0000575 if (offs != -1) memcpy(DOSDrives[drive].label_read,buff+offs,11);
576 DOSDrives[drive].label_read[11]='\0';
577 read = 1;
578 }
579 }
580
581 return (read) ?
582 DOSDrives[drive].label_read : DOSDrives[drive].label_conf;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000583}
584
585
586/***********************************************************************
587 * DRIVE_GetSerialNumber
588 */
589DWORD DRIVE_GetSerialNumber( int drive )
590{
Andreas Mohra16c0e12000-02-07 16:28:52 +0000591 DWORD serial = 0;
Andreas Mohr1fe93342000-01-29 21:11:47 +0000592char buff[DRIVE_SUPER];
593
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000594 if (!DRIVE_IsValid( drive )) return 0;
Andreas Mohra16c0e12000-02-07 16:28:52 +0000595
Alexandre Julliardfbace6e2000-04-04 20:35:45 +0000596 if (DOSDrives[drive].flags & DRIVE_READ_VOL_INFO)
Andreas Mohr1fe93342000-01-29 21:11:47 +0000597 {
Andreas Mohra16c0e12000-02-07 16:28:52 +0000598 switch(DOSDrives[drive].type)
599 {
Alexandre Julliardbf672592000-12-12 00:44:42 +0000600 case DRIVE_REMOVABLE:
601 case DRIVE_FIXED:
602 if (DRIVE_ReadSuperblock(drive,(char *) buff))
603 MESSAGE("Invalid or unreadable superblock on %s (%c:)."
604 " Maybe not FAT?\n" ,
605 DOSDrives[drive].device, 'A'+drive);
606 else
607 serial = *((DWORD*)(buff+0x27));
608 break;
609 case DRIVE_CDROM:
610 serial = CDROM_GetSerial(drive);
611 break;
612 default:
613 FIXME("Serial number reading from file system on drive %c: not supported yet.\n", drive+'A');
Andreas Mohra16c0e12000-02-07 16:28:52 +0000614 }
Andreas Mohr1fe93342000-01-29 21:11:47 +0000615 }
Andreas Mohra16c0e12000-02-07 16:28:52 +0000616
617 return (serial) ? serial : DOSDrives[drive].serial_conf;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000618}
619
620
621/***********************************************************************
622 * DRIVE_SetSerialNumber
623 */
624int DRIVE_SetSerialNumber( int drive, DWORD serial )
625{
Petr Tomasekcd9a6332000-02-27 14:00:14 +0000626 char buff[DRIVE_SUPER];
627
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000628 if (!DRIVE_IsValid( drive )) return 0;
Petr Tomasekcd9a6332000-02-27 14:00:14 +0000629
Alexandre Julliardfbace6e2000-04-04 20:35:45 +0000630 if (DOSDrives[drive].flags & DRIVE_READ_VOL_INFO)
Petr Tomasekcd9a6332000-02-27 14:00:14 +0000631 {
Alexandre Julliardbf672592000-12-12 00:44:42 +0000632 if ((DOSDrives[drive].type != DRIVE_REMOVABLE) &&
633 (DOSDrives[drive].type != DRIVE_FIXED)) return 0;
Petr Tomasekcd9a6332000-02-27 14:00:14 +0000634 /* check, if the drive has a FAT filesystem */
635 if (DRIVE_ReadSuperblock(drive, buff)) return 0;
636 if (DRIVE_WriteSuperblockEntry(drive, 0x27, 4, (char *) &serial)) return 0;
637 return 1;
638 }
639
Alexandre Julliardbf672592000-12-12 00:44:42 +0000640 if (DOSDrives[drive].type == DRIVE_CDROM) return 0;
Andreas Mohr1fe93342000-01-29 21:11:47 +0000641 DOSDrives[drive].serial_conf = serial;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000642 return 1;
643}
644
645
646/***********************************************************************
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000647 * DRIVE_GetType
648 */
Alexandre Julliardbf672592000-12-12 00:44:42 +0000649static UINT DRIVE_GetType( int drive )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000650{
Alexandre Julliardbf672592000-12-12 00:44:42 +0000651 if (!DRIVE_IsValid( drive )) return DRIVE_UNKNOWN;
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000652 return DOSDrives[drive].type;
653}
654
655
656/***********************************************************************
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000657 * DRIVE_GetFlags
658 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000659UINT DRIVE_GetFlags( int drive )
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000660{
661 if ((drive < 0) || (drive >= MAX_DOS_DRIVES)) return 0;
662 return DOSDrives[drive].flags;
663}
664
665
666/***********************************************************************
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000667 * DRIVE_Chdir
668 */
669int DRIVE_Chdir( int drive, const char *path )
670{
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000671 DOS_FULL_NAME full_name;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000672 char buffer[MAX_PATHNAME_LEN];
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000673 LPSTR unix_cwd;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000674 BY_HANDLE_FILE_INFORMATION info;
Alexandre Julliard2ec34e42001-04-04 00:21:05 +0000675 TDB *pTask = TASK_GetCurrent();
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000676
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000677 strcpy( buffer, "A:" );
678 buffer[0] += drive;
Andreas Mohr3084b582000-07-25 20:59:59 +0000679 TRACE("(%s,%s)\n", buffer, path );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000680 lstrcpynA( buffer + 2, path, sizeof(buffer) - 2 );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000681
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000682 if (!DOSFS_GetFullName( buffer, TRUE, &full_name )) return 0;
683 if (!FILE_Stat( full_name.long_name, &info )) return 0;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +0000684 if (!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000685 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000686 SetLastError( ERROR_FILE_NOT_FOUND );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000687 return 0;
688 }
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000689 unix_cwd = full_name.long_name + strlen( DOSDrives[drive].root );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000690 while (*unix_cwd == '/') unix_cwd++;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000691
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000692 TRACE("(%c:): unix_cwd=%s dos_cwd=%s\n",
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000693 'A' + drive, unix_cwd, full_name.short_name + 3 );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000694
Alexandre Julliard90476d62000-02-16 22:47:24 +0000695 HeapFree( GetProcessHeap(), 0, DOSDrives[drive].dos_cwd );
696 HeapFree( GetProcessHeap(), 0, DOSDrives[drive].unix_cwd );
697 DOSDrives[drive].dos_cwd = HEAP_strdupA( GetProcessHeap(), 0,
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000698 full_name.short_name + 3 );
Alexandre Julliard90476d62000-02-16 22:47:24 +0000699 DOSDrives[drive].unix_cwd = HEAP_strdupA( GetProcessHeap(), 0, unix_cwd );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000700
701 if (pTask && (pTask->curdrive & 0x80) &&
702 ((pTask->curdrive & ~0x80) == drive))
703 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000704 lstrcpynA( pTask->curdir, full_name.short_name + 2,
Alexandre Julliardc6c09441997-01-12 18:32:19 +0000705 sizeof(pTask->curdir) );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000706 DRIVE_LastTask = GetCurrentTask();
Marcus Meissner34ed4fd2000-09-27 00:22:16 +0000707 chdir(unix_cwd); /* Only change if on current drive */
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000708 }
709 return 1;
710}
711
712
713/***********************************************************************
714 * DRIVE_Disable
715 */
716int DRIVE_Disable( int drive )
717{
718 if ((drive < 0) || (drive >= MAX_DOS_DRIVES) || !DOSDrives[drive].root)
719 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000720 SetLastError( ERROR_INVALID_DRIVE );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000721 return 0;
722 }
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000723 DOSDrives[drive].flags |= DRIVE_DISABLED;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000724 return 1;
725}
726
727
728/***********************************************************************
729 * DRIVE_Enable
730 */
731int DRIVE_Enable( int drive )
732{
733 if ((drive < 0) || (drive >= MAX_DOS_DRIVES) || !DOSDrives[drive].root)
734 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000735 SetLastError( ERROR_INVALID_DRIVE );
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000736 return 0;
737 }
Alexandre Julliard1e37a181996-08-18 16:21:52 +0000738 DOSDrives[drive].flags &= ~DRIVE_DISABLED;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +0000739 return 1;
740}
741
742
743/***********************************************************************
Alexandre Julliard491502b1997-11-01 19:08:16 +0000744 * DRIVE_SetLogicalMapping
745 */
746int DRIVE_SetLogicalMapping ( int existing_drive, int new_drive )
747{
748 /* If new_drive is already valid, do nothing and return 0
749 otherwise, copy DOSDrives[existing_drive] to DOSDrives[new_drive] */
750
751 DOSDRIVE *old, *new;
752
753 old = DOSDrives + existing_drive;
754 new = DOSDrives + new_drive;
755
756 if ((existing_drive < 0) || (existing_drive >= MAX_DOS_DRIVES) ||
757 !old->root ||
758 (new_drive < 0) || (new_drive >= MAX_DOS_DRIVES))
759 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000760 SetLastError( ERROR_INVALID_DRIVE );
Alexandre Julliard491502b1997-11-01 19:08:16 +0000761 return 0;
762 }
763
764 if ( new->root )
765 {
Andreas Mohr3084b582000-07-25 20:59:59 +0000766 TRACE("Can't map drive %c: to already existing drive %c:\n",
767 'A' + existing_drive, 'A' + new_drive );
Alexandre Julliardf90efa91998-06-14 15:24:15 +0000768 /* it is already mapped there, so return success */
769 if (!strcmp(old->root,new->root))
770 return 1;
Alexandre Julliard491502b1997-11-01 19:08:16 +0000771 return 0;
772 }
773
Alexandre Julliard90476d62000-02-16 22:47:24 +0000774 new->root = HEAP_strdupA( GetProcessHeap(), 0, old->root );
775 new->dos_cwd = HEAP_strdupA( GetProcessHeap(), 0, old->dos_cwd );
776 new->unix_cwd = HEAP_strdupA( GetProcessHeap(), 0, old->unix_cwd );
Andreas Mohr3084b582000-07-25 20:59:59 +0000777 new->device = HEAP_strdupA( GetProcessHeap(), 0, old->device );
Andreas Mohr1fe93342000-01-29 21:11:47 +0000778 memcpy ( new->label_conf, old->label_conf, 12 );
Andreas Mohr3084b582000-07-25 20:59:59 +0000779 memcpy ( new->label_read, old->label_read, 12 );
Andreas Mohr1fe93342000-01-29 21:11:47 +0000780 new->serial_conf = old->serial_conf;
Alexandre Julliard491502b1997-11-01 19:08:16 +0000781 new->type = old->type;
782 new->flags = old->flags;
783 new->dev = old->dev;
784 new->ino = old->ino;
785
Andreas Mohr3084b582000-07-25 20:59:59 +0000786 TRACE("Drive %c: is now equal to drive %c:\n",
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000787 'A' + new_drive, 'A' + existing_drive );
Alexandre Julliard491502b1997-11-01 19:08:16 +0000788
789 return 1;
790}
791
792
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000793/***********************************************************************
794 * DRIVE_OpenDevice
795 *
796 * Open the drive raw device and return a Unix fd (or -1 on error).
797 */
798int DRIVE_OpenDevice( int drive, int flags )
799{
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000800 if (!DRIVE_IsValid( drive )) return -1;
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000801 return open( DOSDrives[drive].device, flags );
802}
803
Alexandre Julliard491502b1997-11-01 19:08:16 +0000804
805/***********************************************************************
Andreas Mohrcc0248e1999-01-03 12:31:51 +0000806 * DRIVE_RawRead
807 *
808 * Read raw sectors from a device
809 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000810int DRIVE_RawRead(BYTE drive, DWORD begin, DWORD nr_sect, BYTE *dataptr, BOOL fake_success)
Andreas Mohrcc0248e1999-01-03 12:31:51 +0000811{
812 int fd;
813
814 if ((fd = DRIVE_OpenDevice( drive, O_RDONLY )) != -1)
815 {
816 lseek( fd, begin * 512, SEEK_SET );
817 /* FIXME: check errors */
818 read( fd, dataptr, nr_sect * 512 );
819 close( fd );
820 }
821 else
822 {
823 memset(dataptr, 0, nr_sect * 512);
Andreas Mohr3084b582000-07-25 20:59:59 +0000824 if (fake_success)
Andreas Mohrcc0248e1999-01-03 12:31:51 +0000825 {
Andreas Mohr3084b582000-07-25 20:59:59 +0000826 if (begin == 0 && nr_sect > 1) *(dataptr + 512) = 0xf8;
827 if (begin == 1) *dataptr = 0xf8;
828 }
829 else
830 return 0;
Andreas Mohrcc0248e1999-01-03 12:31:51 +0000831 }
Andreas Mohr3084b582000-07-25 20:59:59 +0000832 return 1;
Andreas Mohrcc0248e1999-01-03 12:31:51 +0000833}
834
835
836/***********************************************************************
837 * DRIVE_RawWrite
838 *
839 * Write raw sectors to a device
840 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000841int DRIVE_RawWrite(BYTE drive, DWORD begin, DWORD nr_sect, BYTE *dataptr, BOOL fake_success)
Andreas Mohrcc0248e1999-01-03 12:31:51 +0000842{
Andreas Mohr3084b582000-07-25 20:59:59 +0000843 int fd;
Andreas Mohrcc0248e1999-01-03 12:31:51 +0000844
845 if ((fd = DRIVE_OpenDevice( drive, O_RDONLY )) != -1)
846 {
847 lseek( fd, begin * 512, SEEK_SET );
848 /* FIXME: check errors */
849 write( fd, dataptr, nr_sect * 512 );
850 close( fd );
851 }
852 else
Andreas Mohr3084b582000-07-25 20:59:59 +0000853 if (!(fake_success))
854 return 0;
Andreas Mohrcc0248e1999-01-03 12:31:51 +0000855
Andreas Mohr3084b582000-07-25 20:59:59 +0000856 return 1;
Andreas Mohrcc0248e1999-01-03 12:31:51 +0000857}
858
859
860/***********************************************************************
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000861 * DRIVE_GetFreeSpace
862 */
Juergen Schmied1ed51af1999-02-12 17:47:07 +0000863static int DRIVE_GetFreeSpace( int drive, PULARGE_INTEGER size,
864 PULARGE_INTEGER available )
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000865{
866 struct statfs info;
867
868 if (!DRIVE_IsValid(drive))
869 {
Alexandre Julliard4ff2a271999-01-31 15:23:45 +0000870 SetLastError( ERROR_INVALID_DRIVE );
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000871 return 0;
872 }
873
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000874/* FIXME: add autoconf check for this */
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +0000875#if defined(__svr4__) || defined(_SCO_DS) || defined(__sun)
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000876 if (statfs( DOSDrives[drive].root, &info, 0, 0) < 0)
877#else
878 if (statfs( DOSDrives[drive].root, &info) < 0)
879#endif
880 {
881 FILE_SetDosError();
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +0000882 WARN("cannot do statfs(%s)\n", DOSDrives[drive].root);
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000883 return 0;
884 }
885
Alexandre Julliard27952ef2000-10-13 20:26:03 +0000886 size->QuadPart = RtlEnlargedUnsignedMultiply( info.f_bsize, info.f_blocks );
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000887#ifdef STATFS_HAS_BAVAIL
Alexandre Julliard27952ef2000-10-13 20:26:03 +0000888 available->QuadPart = RtlEnlargedUnsignedMultiply( info.f_bavail, info.f_bsize );
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000889#else
890# ifdef STATFS_HAS_BFREE
Alexandre Julliard27952ef2000-10-13 20:26:03 +0000891 available->QuadPart = RtlEnlargedUnsignedMultiply( info.f_bfree, info.f_bsize );
Alexandre Julliardc7c217b1998-04-13 12:21:30 +0000892# else
893# error "statfs has no bfree/bavail member!"
894# endif
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000895#endif
Alexandre Julliardbf672592000-12-12 00:44:42 +0000896 if (DOSDrives[drive].type == DRIVE_CDROM)
Andreas Mohrbd86d18f2000-06-13 03:36:05 +0000897 { /* ALWAYS 0, even if no real CD-ROM mounted there !! */
Alexandre Julliard27952ef2000-10-13 20:26:03 +0000898 available->QuadPart = 0;
Andreas Mohrbd86d18f2000-06-13 03:36:05 +0000899 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000900 return 1;
901}
902
Peter Gantenea5941b1999-12-05 23:51:56 +0000903/***********************************************************************
Abey George70810d91999-09-27 11:39:43 +0000904 * DRIVE_GetCurrentDirectory
905 * Returns "X:\\path\\etc\\".
906 *
907 * Despite the API description, return required length including the
908 * terminating null when buffer too small. This is the real behaviour.
909*/
910
911static UINT DRIVE_GetCurrentDirectory( UINT buflen, LPSTR buf )
912{
913 UINT ret;
914 const char *s = DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() );
915
916 assert(s);
917 ret = strlen(s) + 3; /* length of WHOLE current directory */
918 if (ret >= buflen) return ret + 1;
Francois Gouget6d77d3a2000-03-25 21:44:35 +0000919 lstrcpynA( buf, "A:\\", min( 4, buflen ) );
Abey George70810d91999-09-27 11:39:43 +0000920 if (buflen) buf[0] += DRIVE_GetCurrentDrive();
921 if (buflen > 3) lstrcpynA( buf + 3, s, buflen - 3 );
922 return ret;
923}
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000924
Alexandre Julliardaef9a362000-10-03 04:19:16 +0000925
926/***********************************************************************
927 * DRIVE_BuildEnv
928 *
929 * Build the environment array containing the drives current directories.
930 * Resulting pointer must be freed with HeapFree.
931 */
932char *DRIVE_BuildEnv(void)
933{
934 int i, length = 0;
935 const char *cwd[MAX_DOS_DRIVES];
936 char *env, *p;
937
938 for (i = 0; i < MAX_DOS_DRIVES; i++)
939 {
940 if ((cwd[i] = DRIVE_GetDosCwd(i)) && cwd[i][0]) length += strlen(cwd[i]) + 8;
941 }
942 if (!(env = HeapAlloc( GetProcessHeap(), 0, length+1 ))) return NULL;
943 for (i = 0, p = env; i < MAX_DOS_DRIVES; i++)
944 {
945 if (cwd[i] && cwd[i][0])
946 p += sprintf( p, "=%c:=%c:\\%s", 'A'+i, 'A'+i, cwd[i] ) + 1;
947 }
948 *p = 0;
949 return env;
950}
951
952
Alexandre Julliard7e56f681996-01-31 19:02:28 +0000953/***********************************************************************
Alexandre Julliard339eefc1996-06-23 14:56:20 +0000954 * GetDiskFreeSpace16 (KERNEL.422)
955 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000956BOOL16 WINAPI GetDiskFreeSpace16( LPCSTR root, LPDWORD cluster_sectors,
957 LPDWORD sector_bytes, LPDWORD free_clusters,
958 LPDWORD total_clusters )
Alexandre Julliard339eefc1996-06-23 14:56:20 +0000959{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000960 return GetDiskFreeSpaceA( root, cluster_sectors, sector_bytes,
Alexandre Julliard339eefc1996-06-23 14:56:20 +0000961 free_clusters, total_clusters );
962}
963
964
965/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +0000966 * GetDiskFreeSpaceA (KERNEL32.206)
Andreas Mohr4ae195a1998-11-27 15:02:25 +0000967 *
968 * Fails if expression resulting from current drive's dir and "root"
969 * is not a root dir of the target drive.
970 *
971 * UNDOC: setting some LPDWORDs to NULL is perfectly possible
972 * if the corresponding info is unneeded.
973 *
974 * FIXME: needs to support UNC names from Win95 OSR2 on.
975 *
976 * Behaviour under Win95a:
977 * CurrDir root result
978 * "E:\\TEST" "E:" FALSE
979 * "E:\\" "E:" TRUE
980 * "E:\\" "E" FALSE
981 * "E:\\" "\\" TRUE
982 * "E:\\TEST" "\\" TRUE
983 * "E:\\TEST" ":\\" FALSE
984 * "E:\\TEST" "E:\\" TRUE
985 * "E:\\TEST" "" FALSE
986 * "E:\\" "" FALSE (!)
987 * "E:\\" 0x0 TRUE
988 * "E:\\TEST" 0x0 TRUE (!)
989 * "E:\\TEST" "C:" TRUE (when CurrDir of "C:" set to "\\")
990 * "E:\\TEST" "C:" FALSE (when CurrDir of "C:" set to "\\TEST")
Alexandre Julliard339eefc1996-06-23 14:56:20 +0000991 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000992BOOL WINAPI GetDiskFreeSpaceA( LPCSTR root, LPDWORD cluster_sectors,
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000993 LPDWORD sector_bytes, LPDWORD free_clusters,
994 LPDWORD total_clusters )
Alexandre Julliard339eefc1996-06-23 14:56:20 +0000995{
Andreas Mohrbd86d18f2000-06-13 03:36:05 +0000996 int drive, sec_size;
Uwe Bonnesf3836f51998-12-10 09:56:06 +0000997 ULARGE_INTEGER size,available;
Andreas Mohr4ae195a1998-11-27 15:02:25 +0000998 LPCSTR path;
999 DWORD cluster_sec;
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001000
Peter Schlaile6deeedb1999-11-04 01:39:59 +00001001 if ((!root) || (strcmp(root,"\\") == 0))
Andreas Mohr4ae195a1998-11-27 15:02:25 +00001002 drive = DRIVE_GetCurrentDrive();
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001003 else
Andreas Mohr4ae195a1998-11-27 15:02:25 +00001004 if ( (strlen(root) >= 2) && (root[1] == ':')) /* root contains drive tag */
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001005 {
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001006 drive = toupper(root[0]) - 'A';
Andreas Mohr4ae195a1998-11-27 15:02:25 +00001007 path = &root[2];
1008 if (path[0] == '\0')
1009 path = DRIVE_GetDosCwd(drive);
1010 else
1011 if (path[0] == '\\')
1012 path++;
1013 if (strlen(path)) /* oops, we are in a subdir */
1014 return FALSE;
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001015 }
Andreas Mohr4ae195a1998-11-27 15:02:25 +00001016 else
1017 return FALSE;
1018
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001019 if (!DRIVE_GetFreeSpace(drive, &size, &available)) return FALSE;
1020
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +00001021 /* Cap the size and available at 2GB as per specs. */
Patrik Stridvall311e4561999-09-19 14:20:33 +00001022 if ((size.s.HighPart) ||(size.s.LowPart > 0x7fffffff))
Andreas Mohrbd86d18f2000-06-13 03:36:05 +00001023 {
1024 size.s.HighPart = 0;
1025 size.s.LowPart = 0x7fffffff;
1026 }
Patrik Stridvall311e4561999-09-19 14:20:33 +00001027 if ((available.s.HighPart) ||(available.s.LowPart > 0x7fffffff))
Andreas Mohrbd86d18f2000-06-13 03:36:05 +00001028 {
Patrik Stridvall311e4561999-09-19 14:20:33 +00001029 available.s.HighPart =0;
1030 available.s.LowPart = 0x7fffffff;
Alexandre Julliard02e90081998-01-04 17:49:09 +00001031 }
Alexandre Julliardbf672592000-12-12 00:44:42 +00001032 sec_size = (DRIVE_GetType(drive)==DRIVE_CDROM) ? 2048 : 512;
Andreas Mohrbd86d18f2000-06-13 03:36:05 +00001033 size.s.LowPart /= sec_size;
1034 available.s.LowPart /= sec_size;
Alexandre Julliard02e90081998-01-04 17:49:09 +00001035 /* fixme: probably have to adjust those variables too for CDFS */
Andreas Mohr4ae195a1998-11-27 15:02:25 +00001036 cluster_sec = 1;
Patrik Stridvall311e4561999-09-19 14:20:33 +00001037 while (cluster_sec * 65536 < size.s.LowPart) cluster_sec *= 2;
Andreas Mohr4ae195a1998-11-27 15:02:25 +00001038
1039 if (cluster_sectors)
1040 *cluster_sectors = cluster_sec;
Andreas Mohrbd86d18f2000-06-13 03:36:05 +00001041 if (sector_bytes)
1042 *sector_bytes = sec_size;
Andreas Mohr4ae195a1998-11-27 15:02:25 +00001043 if (free_clusters)
Patrik Stridvall311e4561999-09-19 14:20:33 +00001044 *free_clusters = available.s.LowPart / cluster_sec;
Andreas Mohr4ae195a1998-11-27 15:02:25 +00001045 if (total_clusters)
Patrik Stridvall311e4561999-09-19 14:20:33 +00001046 *total_clusters = size.s.LowPart / cluster_sec;
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001047 return TRUE;
1048}
1049
1050
1051/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001052 * GetDiskFreeSpaceW (KERNEL32.207)
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001053 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001054BOOL WINAPI GetDiskFreeSpaceW( LPCWSTR root, LPDWORD cluster_sectors,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001055 LPDWORD sector_bytes, LPDWORD free_clusters,
1056 LPDWORD total_clusters )
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001057{
1058 LPSTR xroot;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001059 BOOL ret;
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001060
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001061 xroot = HEAP_strdupWtoA( GetProcessHeap(), 0, root);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001062 ret = GetDiskFreeSpaceA( xroot,cluster_sectors, sector_bytes,
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001063 free_clusters, total_clusters );
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001064 HeapFree( GetProcessHeap(), 0, xroot );
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001065 return ret;
1066}
1067
1068
1069/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001070 * GetDiskFreeSpaceExA (KERNEL32.871)
Morten Eriksen1563e831999-08-07 12:29:04 +00001071 *
Andreas Mohrf32f9182001-04-20 18:36:05 +00001072 * This function is used to acquire the size of the available and
Morten Eriksen1563e831999-08-07 12:29:04 +00001073 * total space on a logical volume.
1074 *
1075 * RETURNS
1076 *
1077 * Zero on failure, nonzero upon success. Use GetLastError to obtain
1078 * detailed error information.
1079 *
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001080 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001081BOOL WINAPI GetDiskFreeSpaceExA( LPCSTR root,
Juergen Schmied1ed51af1999-02-12 17:47:07 +00001082 PULARGE_INTEGER avail,
1083 PULARGE_INTEGER total,
1084 PULARGE_INTEGER totalfree)
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001085{
1086 int drive;
Uwe Bonnesf3836f51998-12-10 09:56:06 +00001087 ULARGE_INTEGER size,available;
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001088
1089 if (!root) drive = DRIVE_GetCurrentDrive();
1090 else
1091 {
1092 if ((root[1]) && ((root[1] != ':') || (root[2] != '\\')))
1093 {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001094 FIXME("there are valid root names which are not supported yet\n");
Morten Eriksen1563e831999-08-07 12:29:04 +00001095 /* ..like UNC names, for instance. */
1096
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001097 WARN("invalid root '%s'\n", root );
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001098 return FALSE;
1099 }
1100 drive = toupper(root[0]) - 'A';
1101 }
Morten Eriksen1563e831999-08-07 12:29:04 +00001102
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001103 if (!DRIVE_GetFreeSpace(drive, &size, &available)) return FALSE;
Morten Eriksen1563e831999-08-07 12:29:04 +00001104
1105 if (total)
1106 {
Patrik Stridvall311e4561999-09-19 14:20:33 +00001107 total->s.HighPart = size.s.HighPart;
Andreas Mohr3084b582000-07-25 20:59:59 +00001108 total->s.LowPart = size.s.LowPart;
Eric Pouech6ec64921999-02-02 10:25:41 +00001109 }
Morten Eriksen1563e831999-08-07 12:29:04 +00001110
1111 if (totalfree)
1112 {
Patrik Stridvall311e4561999-09-19 14:20:33 +00001113 totalfree->s.HighPart = available.s.HighPart;
Andreas Mohr3084b582000-07-25 20:59:59 +00001114 totalfree->s.LowPart = available.s.LowPart;
Eric Pouech6ec64921999-02-02 10:25:41 +00001115 }
Morten Eriksen1563e831999-08-07 12:29:04 +00001116
1117 if (avail)
1118 {
Morten Eriksen467845a1999-08-15 14:20:18 +00001119 if (FIXME_ON(dosfs))
1120 {
1121 /* On Windows2000, we need to check the disk quota
1122 allocated for the user owning the calling process. We
1123 don't want to be more obtrusive than necessary with the
1124 FIXME messages, so don't print the FIXME unless Wine is
1125 actually masquerading as Windows2000. */
1126
1127 OSVERSIONINFOA ovi;
1128 ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1129 if (GetVersionExA(&ovi))
1130 {
1131 if (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4)
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001132 FIXME("no per-user quota support yet\n");
Morten Eriksen467845a1999-08-15 14:20:18 +00001133 }
1134 }
1135
1136 /* Quick hack, should eventually be fixed to work 100% with
1137 Windows2000 (see comment above). */
Patrik Stridvall311e4561999-09-19 14:20:33 +00001138 avail->s.HighPart = available.s.HighPart;
Andreas Mohr3084b582000-07-25 20:59:59 +00001139 avail->s.LowPart = available.s.LowPart;
Morten Eriksen1563e831999-08-07 12:29:04 +00001140 }
1141
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001142 return TRUE;
1143}
1144
1145/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001146 * GetDiskFreeSpaceExW (KERNEL32.873)
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001147 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001148BOOL WINAPI GetDiskFreeSpaceExW( LPCWSTR root, PULARGE_INTEGER avail,
Juergen Schmied1ed51af1999-02-12 17:47:07 +00001149 PULARGE_INTEGER total,
1150 PULARGE_INTEGER totalfree)
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001151{
1152 LPSTR xroot;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001153 BOOL ret;
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001154
1155 xroot = HEAP_strdupWtoA( GetProcessHeap(), 0, root);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001156 ret = GetDiskFreeSpaceExA( xroot, avail, total, totalfree);
Alexandre Julliard44ed71f1997-12-21 19:17:50 +00001157 HeapFree( GetProcessHeap(), 0, xroot );
1158 return ret;
1159}
1160
1161/***********************************************************************
Alexandre Julliard3051b641996-07-05 17:14:13 +00001162 * GetDriveType16 (KERNEL.136)
Andreas Mohr1fe93342000-01-29 21:11:47 +00001163 * This function returns the type of a drive in Win16.
Alexandre Julliard642d3131998-07-12 19:29:36 +00001164 * Note that it returns DRIVE_REMOTE for CD-ROMs, since MSCDEX uses the
Andreas Mohr91a8e0d2000-02-18 19:06:49 +00001165 * remote drive API. The return value DRIVE_REMOTE for CD-ROMs has been
1166 * verified on Win 3.11 and Windows 95. Some programs rely on it, so don't
Alexandre Julliard642d3131998-07-12 19:29:36 +00001167 * do any pseudo-clever changes.
1168 *
1169 * RETURNS
1170 * drivetype DRIVE_xxx
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001171 */
Alexandre Julliardbf672592000-12-12 00:44:42 +00001172UINT16 WINAPI GetDriveType16( UINT16 drive ) /* [in] number (NOT letter) of drive */
1173{
1174 UINT type = DRIVE_GetType(drive);
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001175 TRACE("(%c:)\n", 'A' + drive );
Alexandre Julliardbf672592000-12-12 00:44:42 +00001176 if (type == DRIVE_CDROM) type = DRIVE_REMOTE;
1177 return type;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001178}
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001179
1180
1181/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001182 * GetDriveTypeA (KERNEL32.208)
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001183 *
Andreas Mohr3084b582000-07-25 20:59:59 +00001184 * Returns the type of the disk drive specified. If root is NULL the
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001185 * root of the current directory is used.
1186 *
1187 * RETURNS
1188 *
1189 * Type of drive (from Win32 SDK):
1190 *
1191 * DRIVE_UNKNOWN unable to find out anything about the drive
Andreas Mohr3084b582000-07-25 20:59:59 +00001192 * DRIVE_NO_ROOT_DIR nonexistent root dir
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001193 * DRIVE_REMOVABLE the disk can be removed from the machine
1194 * DRIVE_FIXED the disk can not be removed from the machine
1195 * DRIVE_REMOTE network disk
1196 * DRIVE_CDROM CDROM drive
Andreas Mohr3084b582000-07-25 20:59:59 +00001197 * DRIVE_RAMDISK virtual disk in RAM
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001198 */
Patrik Stridvall2b3aa612000-12-01 23:58:28 +00001199UINT WINAPI GetDriveTypeA(LPCSTR root) /* [in] String describing drive */
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001200{
Petter Reinholdtsen0dce5b71998-10-11 14:26:25 +00001201 int drive;
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001202 TRACE("(%s)\n", debugstr_a(root));
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001203
Petter Reinholdtsen0dce5b71998-10-11 14:26:25 +00001204 if (NULL == root) drive = DRIVE_GetCurrentDrive();
1205 else
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001206 {
Petter Reinholdtsen0dce5b71998-10-11 14:26:25 +00001207 if ((root[1]) && (root[1] != ':'))
1208 {
Francois Gougetee285b72001-05-11 20:03:40 +00001209 WARN("invalid root %s\n", debugstr_a(root));
Alexandre Julliardbf672592000-12-12 00:44:42 +00001210 return DRIVE_NO_ROOT_DIR;
Petter Reinholdtsen0dce5b71998-10-11 14:26:25 +00001211 }
1212 drive = toupper(root[0]) - 'A';
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001213 }
Alexandre Julliardbf672592000-12-12 00:44:42 +00001214 return DRIVE_GetType(drive);
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001215}
1216
1217
1218/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001219 * GetDriveTypeW (KERNEL32.209)
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001220 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001221UINT WINAPI GetDriveTypeW( LPCWSTR root )
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001222{
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001223 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, root );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001224 UINT ret = GetDriveTypeA( xpath );
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001225 HeapFree( GetProcessHeap(), 0, xpath );
Alexandre Julliard3051b641996-07-05 17:14:13 +00001226 return ret;
1227}
1228
1229
1230/***********************************************************************
1231 * GetCurrentDirectory16 (KERNEL.411)
1232 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001233UINT16 WINAPI GetCurrentDirectory16( UINT16 buflen, LPSTR buf )
Alexandre Julliard3051b641996-07-05 17:14:13 +00001234{
Abey George70810d91999-09-27 11:39:43 +00001235 return (UINT16)DRIVE_GetCurrentDirectory(buflen, buf);
Alexandre Julliard3051b641996-07-05 17:14:13 +00001236}
1237
1238
1239/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001240 * GetCurrentDirectoryA (KERNEL32.196)
Alexandre Julliard3051b641996-07-05 17:14:13 +00001241 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001242UINT WINAPI GetCurrentDirectoryA( UINT buflen, LPSTR buf )
Alexandre Julliard3051b641996-07-05 17:14:13 +00001243{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001244 UINT ret;
Abey George70810d91999-09-27 11:39:43 +00001245 char longname[MAX_PATHNAME_LEN];
Peter Gantenea5941b1999-12-05 23:51:56 +00001246 char shortname[MAX_PATHNAME_LEN];
1247 ret = DRIVE_GetCurrentDirectory(MAX_PATHNAME_LEN, shortname);
1248 if ( ret > MAX_PATHNAME_LEN ) {
1249 ERR_(file)("pathnamelength (%d) > MAX_PATHNAME_LEN!\n", ret );
1250 return ret;
1251 }
1252 GetLongPathNameA(shortname, longname, MAX_PATHNAME_LEN);
Alexandre Julliardcb10fda2000-08-06 02:41:16 +00001253 ret = strlen( longname ) + 1;
Peter Gantenea5941b1999-12-05 23:51:56 +00001254 if (ret > buflen) return ret;
Alexandre Julliardcb10fda2000-08-06 02:41:16 +00001255 strcpy(buf, longname);
Peter Gantenea5941b1999-12-05 23:51:56 +00001256 return ret - 1;
Alexandre Julliard3051b641996-07-05 17:14:13 +00001257}
1258
Alexandre Julliard3051b641996-07-05 17:14:13 +00001259/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001260 * GetCurrentDirectoryW (KERNEL32.197)
Alexandre Julliard3051b641996-07-05 17:14:13 +00001261 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001262UINT WINAPI GetCurrentDirectoryW( UINT buflen, LPWSTR buf )
Alexandre Julliard3051b641996-07-05 17:14:13 +00001263{
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001264 LPSTR xpath = HeapAlloc( GetProcessHeap(), 0, buflen+1 );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001265 UINT ret = GetCurrentDirectoryA( buflen, xpath );
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00001266 if (ret < buflen) ret = MultiByteToWideChar( CP_ACP, 0, xpath, -1, buf, buflen ) - 1;
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001267 HeapFree( GetProcessHeap(), 0, xpath );
Alexandre Julliard3051b641996-07-05 17:14:13 +00001268 return ret;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001269}
1270
1271
1272/***********************************************************************
1273 * SetCurrentDirectory (KERNEL.412)
1274 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001275BOOL16 WINAPI SetCurrentDirectory16( LPCSTR dir )
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001276{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001277 return SetCurrentDirectoryA( dir );
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +00001278}
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001279
Alexandre Julliard349a9531997-02-02 19:01:52 +00001280
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001281/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001282 * SetCurrentDirectoryA (KERNEL32.479)
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001283 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001284BOOL WINAPI SetCurrentDirectoryA( LPCSTR dir )
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001285{
Andreas Mohr3084b582000-07-25 20:59:59 +00001286 int drive, olddrive = DRIVE_GetCurrentDrive();
Alexandre Julliard349a9531997-02-02 19:01:52 +00001287
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001288 if (!dir) {
Alexandre Julliard06c275a1999-05-02 14:32:27 +00001289 ERR_(file)("(NULL)!\n");
Alexandre Julliardf90efa91998-06-14 15:24:15 +00001290 return FALSE;
1291 }
Alexandre Julliard349a9531997-02-02 19:01:52 +00001292 if (dir[0] && (dir[1]==':'))
1293 {
Andreas Mohr3084b582000-07-25 20:59:59 +00001294 drive = toupper( *dir ) - 'A';
Alexandre Julliard349a9531997-02-02 19:01:52 +00001295 dir += 2;
1296 }
Andreas Mohr3084b582000-07-25 20:59:59 +00001297 else
1298 drive = olddrive;
Andreas Mohrfe6dfb01998-10-11 17:36:06 +00001299
1300 /* WARNING: we need to set the drive before the dir, as DRIVE_Chdir
1301 sets pTask->curdir only if pTask->curdrive is drive */
Andreas Mohrfe6dfb01998-10-11 17:36:06 +00001302 if (!(DRIVE_SetCurrentDrive( drive )))
1303 return FALSE;
Alexandre Julliard349a9531997-02-02 19:01:52 +00001304 /* FIXME: what about empty strings? Add a \\ ? */
Andreas Mohrfe6dfb01998-10-11 17:36:06 +00001305 if (!DRIVE_Chdir( drive, dir )) {
1306 DRIVE_SetCurrentDrive(olddrive);
1307 return FALSE;
1308 }
1309 return TRUE;
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001310}
1311
Alexandre Julliard349a9531997-02-02 19:01:52 +00001312
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001313/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001314 * SetCurrentDirectoryW (KERNEL32.480)
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001315 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001316BOOL WINAPI SetCurrentDirectoryW( LPCWSTR dirW )
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001317{
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001318 LPSTR dir = HEAP_strdupWtoA( GetProcessHeap(), 0, dirW );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001319 BOOL res = SetCurrentDirectoryA( dir );
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001320 HeapFree( GetProcessHeap(), 0, dir );
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001321 return res;
1322}
1323
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001324
1325/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001326 * GetLogicalDriveStringsA (KERNEL32.231)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001327 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001328UINT WINAPI GetLogicalDriveStringsA( UINT len, LPSTR buffer )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001329{
1330 int drive, count;
1331
1332 for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
1333 if (DRIVE_IsValid(drive)) count++;
Uwe Bonnesc25e7151999-10-13 13:57:38 +00001334 if ((count * 4) + 1 <= len)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001335 {
1336 LPSTR p = buffer;
1337 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
1338 if (DRIVE_IsValid(drive))
1339 {
1340 *p++ = 'a' + drive;
1341 *p++ = ':';
1342 *p++ = '\\';
1343 *p++ = '\0';
1344 }
1345 *p = '\0';
Andreas Mohr3084b582000-07-25 20:59:59 +00001346 return count * 4;
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001347 }
Uwe Bonnesc25e7151999-10-13 13:57:38 +00001348 else
Andreas Mohr3084b582000-07-25 20:59:59 +00001349 return (count * 4) + 1; /* account for terminating null */
Uwe Bonnesc25e7151999-10-13 13:57:38 +00001350 /* The API tells about these different return values */
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001351}
1352
1353
1354/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001355 * GetLogicalDriveStringsW (KERNEL32.232)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001356 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001357UINT WINAPI GetLogicalDriveStringsW( UINT len, LPWSTR buffer )
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001358{
1359 int drive, count;
1360
1361 for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
1362 if (DRIVE_IsValid(drive)) count++;
1363 if (count * 4 * sizeof(WCHAR) <= len)
1364 {
1365 LPWSTR p = buffer;
1366 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
1367 if (DRIVE_IsValid(drive))
1368 {
1369 *p++ = (WCHAR)('a' + drive);
1370 *p++ = (WCHAR)':';
1371 *p++ = (WCHAR)'\\';
1372 *p++ = (WCHAR)'\0';
1373 }
1374 *p = (WCHAR)'\0';
1375 }
1376 return count * 4 * sizeof(WCHAR);
1377}
1378
1379
1380/***********************************************************************
1381 * GetLogicalDrives (KERNEL32.233)
1382 */
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001383DWORD WINAPI GetLogicalDrives(void)
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001384{
1385 DWORD ret = 0;
1386 int drive;
1387
1388 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
Andreas Mohr1fe93342000-01-29 21:11:47 +00001389 {
1390 if ( (DRIVE_IsValid(drive)) ||
Alexandre Julliardbf672592000-12-12 00:44:42 +00001391 (DOSDrives[drive].type == DRIVE_CDROM)) /* audio CD is also valid */
Andreas Mohr1fe93342000-01-29 21:11:47 +00001392 ret |= (1 << drive);
1393 }
Alexandre Julliard2d93d001996-05-21 15:01:41 +00001394 return ret;
1395}
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001396
1397
1398/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001399 * GetVolumeInformationA (KERNEL32.309)
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001400 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001401BOOL WINAPI GetVolumeInformationA( LPCSTR root, LPSTR label,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001402 DWORD label_len, DWORD *serial,
1403 DWORD *filename_len, DWORD *flags,
1404 LPSTR fsname, DWORD fsname_len )
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001405{
1406 int drive;
Alexandre Julliard829fe321998-07-26 14:27:39 +00001407 char *cp;
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001408
Andreas Mohr1fe93342000-01-29 21:11:47 +00001409 /* FIXME, SetLastError()s missing */
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001410
1411 if (!root) drive = DRIVE_GetCurrentDrive();
1412 else
1413 {
Alexandre Julliard02e90081998-01-04 17:49:09 +00001414 if ((root[1]) && (root[1] != ':'))
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001415 {
Dimitrie O. Paundd03cc11999-12-08 03:56:23 +00001416 WARN("invalid root '%s'\n",root);
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001417 return FALSE;
1418 }
1419 drive = toupper(root[0]) - 'A';
1420 }
1421 if (!DRIVE_IsValid( drive )) return FALSE;
Alexandre Julliard829fe321998-07-26 14:27:39 +00001422 if (label)
1423 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001424 lstrcpynA( label, DRIVE_GetLabel(drive), label_len );
Alexandre Julliard566a52a2001-03-05 19:34:17 +00001425 cp = label + strlen(label);
Alexandre Julliard829fe321998-07-26 14:27:39 +00001426 while (cp != label && *(cp-1) == ' ') cp--;
1427 *cp = '\0';
1428 }
Petter Reinholdtsen6ca3f791998-10-20 14:25:50 +00001429 if (serial) *serial = DRIVE_GetSerialNumber(drive);
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001430
1431 /* Set the filesystem information */
Andreas Mohr1fe93342000-01-29 21:11:47 +00001432 /* Note: we only emulate a FAT fs at present */
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001433
Alexandre Julliard767e6f61998-08-09 12:47:43 +00001434 if (filename_len) {
1435 if (DOSDrives[drive].flags & DRIVE_SHORT_NAMES)
1436 *filename_len = 12;
1437 else
1438 *filename_len = 255;
1439 }
Uwe Bonnes27233421999-02-11 10:23:05 +00001440 if (flags)
1441 {
1442 *flags=0;
1443 if (DOSDrives[drive].flags & DRIVE_CASE_SENSITIVE)
1444 *flags|=FS_CASE_SENSITIVE;
1445 if (DOSDrives[drive].flags & DRIVE_CASE_PRESERVING)
Andreas Mohr91a8e0d2000-02-18 19:06:49 +00001446 *flags|=FS_CASE_IS_PRESERVED;
Uwe Bonnes27233421999-02-11 10:23:05 +00001447 }
Alexandre Julliard02e90081998-01-04 17:49:09 +00001448 if (fsname) {
1449 /* Diablo checks that return code ... */
Alexandre Julliardbf672592000-12-12 00:44:42 +00001450 if (DOSDrives[drive].type == DRIVE_CDROM)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001451 lstrcpynA( fsname, "CDFS", fsname_len );
Alexandre Julliard02e90081998-01-04 17:49:09 +00001452 else
Alexandre Julliarda3960291999-02-26 11:11:13 +00001453 lstrcpynA( fsname, "FAT", fsname_len );
Alexandre Julliard02e90081998-01-04 17:49:09 +00001454 }
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001455 return TRUE;
1456}
1457
1458
1459/***********************************************************************
Patrik Stridvall2d6457c2000-03-28 20:22:59 +00001460 * GetVolumeInformationW (KERNEL32.310)
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001461 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001462BOOL WINAPI GetVolumeInformationW( LPCWSTR root, LPWSTR label,
Alexandre Julliard670cdc41997-08-24 16:00:30 +00001463 DWORD label_len, DWORD *serial,
1464 DWORD *filename_len, DWORD *flags,
1465 LPWSTR fsname, DWORD fsname_len )
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001466{
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001467 LPSTR xroot = HEAP_strdupWtoA( GetProcessHeap(), 0, root );
1468 LPSTR xvolname = label ? HeapAlloc(GetProcessHeap(),0,label_len) : NULL;
1469 LPSTR xfsname = fsname ? HeapAlloc(GetProcessHeap(),0,fsname_len) : NULL;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001470 BOOL ret = GetVolumeInformationA( xroot, xvolname, label_len, serial,
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001471 filename_len, flags, xfsname,
1472 fsname_len );
1473 if (ret)
1474 {
Alexandre Julliard24a62ab2000-11-28 22:40:56 +00001475 if (label) MultiByteToWideChar( CP_ACP, 0, xvolname, -1, label, label_len );
1476 if (fsname) MultiByteToWideChar( CP_ACP, 0, xfsname, -1, fsname, fsname_len );
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001477 }
Alexandre Julliard7ebe1a41996-12-22 18:27:48 +00001478 HeapFree( GetProcessHeap(), 0, xroot );
1479 HeapFree( GetProcessHeap(), 0, xvolname );
1480 HeapFree( GetProcessHeap(), 0, xfsname );
Alexandre Julliard339eefc1996-06-23 14:56:20 +00001481 return ret;
1482}
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001483
Dave Pickles18d3ad81999-06-05 15:19:30 +00001484/***********************************************************************
1485 * SetVolumeLabelA (KERNEL32.675)
1486 */
Ove Kaavena01e2892000-01-15 23:28:26 +00001487BOOL WINAPI SetVolumeLabelA( LPCSTR root, LPCSTR volname )
Dave Pickles18d3ad81999-06-05 15:19:30 +00001488{
Ove Kaavena01e2892000-01-15 23:28:26 +00001489 int drive;
1490
1491 /* FIXME, SetLastErrors missing */
1492
1493 if (!root) drive = DRIVE_GetCurrentDrive();
1494 else
1495 {
1496 if ((root[1]) && (root[1] != ':'))
1497 {
1498 WARN("invalid root '%s'\n",root);
1499 return FALSE;
1500 }
1501 drive = toupper(root[0]) - 'A';
1502 }
1503 if (!DRIVE_IsValid( drive )) return FALSE;
1504
1505 /* some copy protection stuff check this */
Alexandre Julliardbf672592000-12-12 00:44:42 +00001506 if (DOSDrives[drive].type == DRIVE_CDROM) return FALSE;
Ove Kaavena01e2892000-01-15 23:28:26 +00001507
1508 FIXME("(%s,%s),stub!\n", root, volname);
1509 return TRUE;
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001510}
Dave Pickles18d3ad81999-06-05 15:19:30 +00001511
1512/***********************************************************************
1513 * SetVolumeLabelW (KERNEL32.676)
1514 */
1515BOOL WINAPI SetVolumeLabelW(LPCWSTR rootpath,LPCWSTR volname)
1516{
1517 LPSTR xroot, xvol;
1518 BOOL ret;
1519
1520 xroot = HEAP_strdupWtoA( GetProcessHeap(), 0, rootpath);
1521 xvol = HEAP_strdupWtoA( GetProcessHeap(), 0, volname);
1522 ret = SetVolumeLabelA( xroot, xvol );
1523 HeapFree( GetProcessHeap(), 0, xroot );
1524 HeapFree( GetProcessHeap(), 0, xvol );
1525 return ret;
1526}