Do a strip --strip-unneeded on the .tmp.o file to reduce disk usage.
[wine/multimedia.git] / files / drive.c
blobac3da7389d4ca6234aa5766dff89913174f6f6bb
1 /*
2 * DOS drives handling functions
4 * Copyright 1993 Erik Bos
5 * Copyright 1996 Alexandre Julliard
7 * Label & serial number read support.
8 * (c) 1999 Petr Tomasek <tomasek@etf.cuni.cz>
9 * (c) 2000 Andreas Mohr (changes)
13 #include "config.h"
15 #include <assert.h>
16 #include <ctype.h>
17 #include <string.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <unistd.h>
26 #ifdef HAVE_SYS_PARAM_H
27 # include <sys/param.h>
28 #endif
29 #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
39 #endif
41 #include "winbase.h"
42 #include "ntddk.h"
43 #include "wine/winbase16.h" /* for GetCurrentTask */
44 #include "wine/winestring.h" /* for lstrcpyAtoW */
45 #include "winerror.h"
46 #include "drive.h"
47 #include "cdrom.h"
48 #include "file.h"
49 #include "heap.h"
50 #include "msdos.h"
51 #include "options.h"
52 #include "wine/port.h"
53 #include "task.h"
54 #include "debugtools.h"
56 DEFAULT_DEBUG_CHANNEL(dosfs)
57 DECLARE_DEBUG_CHANNEL(file)
59 typedef struct
61 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 / */
64 char *device; /* raw device path */
65 char label_conf[12]; /* drive label as cfg'd in wine.conf */
66 char label_read[12]; /* drive label as read from device */
67 DWORD serial_conf; /* drive serial number as cfg'd in wine.conf */
68 DRIVETYPE type; /* drive type */
69 UINT flags; /* drive flags */
70 dev_t dev; /* unix device number */
71 ino_t ino; /* unix inode number */
72 } DOSDRIVE;
75 static const char * const DRIVE_Types[] =
77 "floppy", /* TYPE_FLOPPY */
78 "hd", /* TYPE_HD */
79 "cdrom", /* TYPE_CDROM */
80 "network" /* TYPE_NETWORK */
84 /* Known filesystem types */
86 typedef struct
88 const char *name;
89 UINT flags;
90 } FS_DESCR;
92 static const FS_DESCR DRIVE_Filesystems[] =
94 { "unix", DRIVE_CASE_SENSITIVE | DRIVE_CASE_PRESERVING },
95 { "msdos", DRIVE_SHORT_NAMES },
96 { "dos", DRIVE_SHORT_NAMES },
97 { "fat", DRIVE_SHORT_NAMES },
98 { "vfat", DRIVE_CASE_PRESERVING },
99 { "win95", DRIVE_CASE_PRESERVING },
100 { NULL, 0 }
104 static DOSDRIVE DOSDrives[MAX_DOS_DRIVES];
105 static int DRIVE_CurDrive = -1;
107 static HTASK16 DRIVE_LastTask = 0;
110 /***********************************************************************
111 * DRIVE_GetDriveType
113 static DRIVETYPE DRIVE_GetDriveType( const char *name )
115 char buffer[20];
116 int i;
118 PROFILE_GetWineIniString( name, "Type", "hd", buffer, sizeof(buffer) );
119 for (i = 0; i < sizeof(DRIVE_Types)/sizeof(DRIVE_Types[0]); i++)
121 if (!strcasecmp( buffer, DRIVE_Types[i] )) return (DRIVETYPE)i;
123 MESSAGE("%s: unknown drive type '%s', defaulting to 'hd'.\n",
124 name, buffer );
125 return TYPE_HD;
129 /***********************************************************************
130 * DRIVE_GetFSFlags
132 static UINT DRIVE_GetFSFlags( const char *name, const char *value )
134 const FS_DESCR *descr;
136 for (descr = DRIVE_Filesystems; descr->name; descr++)
137 if (!strcasecmp( value, descr->name )) return descr->flags;
138 MESSAGE("%s: unknown filesystem type '%s', defaulting to 'win95'.\n",
139 name, value );
140 return DRIVE_CASE_PRESERVING;
144 /***********************************************************************
145 * DRIVE_Init
147 int DRIVE_Init(void)
149 int i, len, count = 0;
150 char name[] = "Drive A";
151 char drive_env[] = "=A:";
152 char path[MAX_PATHNAME_LEN];
153 char buffer[80];
154 struct stat drive_stat_buffer;
155 char *p;
156 DOSDRIVE *drive;
158 for (i = 0, drive = DOSDrives; i < MAX_DOS_DRIVES; i++, name[6]++, drive++)
160 PROFILE_GetWineIniString( name, "Path", "", path, sizeof(path)-1 );
161 if (path[0])
163 p = path + strlen(path) - 1;
164 while ((p > path) && ((*p == '/') || (*p == '\\'))) *p-- = '\0';
165 if (!path[0]) strcpy( path, "/" );
167 if (stat( path, &drive_stat_buffer ))
169 MESSAGE("Could not stat %s, ignoring drive %c:\n", path, 'A' + i );
170 continue;
172 if (!S_ISDIR(drive_stat_buffer.st_mode))
174 MESSAGE("%s is not a directory, ignoring drive %c:\n",
175 path, 'A' + i );
176 continue;
179 drive->root = HEAP_strdupA( GetProcessHeap(), 0, path );
180 drive->dos_cwd = HEAP_strdupA( GetProcessHeap(), 0, "" );
181 drive->unix_cwd = HEAP_strdupA( GetProcessHeap(), 0, "" );
182 drive->type = DRIVE_GetDriveType( name );
183 drive->device = NULL;
184 drive->flags = 0;
185 drive->dev = drive_stat_buffer.st_dev;
186 drive->ino = drive_stat_buffer.st_ino;
188 /* Get the drive label */
189 PROFILE_GetWineIniString( name, "Label", name, drive->label_conf, 12 );
190 if ((len = strlen(drive->label_conf)) < 11)
192 /* Pad label with spaces */
193 memset( drive->label_conf + len, ' ', 11 - len );
194 drive->label_conf[11] = '\0';
197 /* Get the serial number */
198 PROFILE_GetWineIniString( name, "Serial", "12345678",
199 buffer, sizeof(buffer) );
200 drive->serial_conf = strtoul( buffer, NULL, 16 );
202 /* Get the filesystem type */
203 PROFILE_GetWineIniString( name, "Filesystem", "win95",
204 buffer, sizeof(buffer) );
205 drive->flags = DRIVE_GetFSFlags( name, buffer );
207 /* Get the device */
208 PROFILE_GetWineIniString( name, "Device", "",
209 buffer, sizeof(buffer) );
210 if (buffer[0])
212 drive->device = HEAP_strdupA( GetProcessHeap(), 0, buffer );
213 if (PROFILE_GetWineIniBool( name, "ReadVolInfo", 1))
214 drive->flags |= DRIVE_READ_VOL_INFO;
217 /* Get the FailReadOnly flag */
218 if (PROFILE_GetWineIniBool( name, "FailReadOnly", 0 ))
219 drive->flags |= DRIVE_FAIL_READ_ONLY;
221 /* Make the first hard disk the current drive */
222 if ((DRIVE_CurDrive == -1) && (drive->type == TYPE_HD))
223 DRIVE_CurDrive = i;
225 count++;
226 TRACE("%s: path=%s type=%s label='%s' serial=%08lx "
227 "flags=%08x dev=%x ino=%x\n",
228 name, path, DRIVE_Types[drive->type],
229 drive->label_conf, drive->serial_conf, drive->flags,
230 (int)drive->dev, (int)drive->ino );
232 else WARN("%s: not defined\n", name );
235 if (!count)
237 MESSAGE("Warning: no valid DOS drive found, check your configuration file.\n" );
238 /* Create a C drive pointing to Unix root dir */
239 DOSDrives[2].root = HEAP_strdupA( GetProcessHeap(), 0, "/" );
240 DOSDrives[2].dos_cwd = HEAP_strdupA( GetProcessHeap(), 0, "" );
241 DOSDrives[2].unix_cwd = HEAP_strdupA( GetProcessHeap(), 0, "" );
242 strcpy( DOSDrives[2].label_conf, "Drive C " );
243 DOSDrives[2].serial_conf = 12345678;
244 DOSDrives[2].type = TYPE_HD;
245 DOSDrives[2].device = NULL;
246 DOSDrives[2].flags = 0;
247 DRIVE_CurDrive = 2;
250 /* Make sure the current drive is valid */
251 if (DRIVE_CurDrive == -1)
253 for (i = 0, drive = DOSDrives; i < MAX_DOS_DRIVES; i++, drive++)
255 if (drive->root && !(drive->flags & DRIVE_DISABLED))
257 DRIVE_CurDrive = i;
258 break;
263 /* get current working directory info for all drives */
264 for (i = 0; i < MAX_DOS_DRIVES; i++, drive_env[1]++)
266 if (!GetEnvironmentVariableA(drive_env, path, sizeof(path))) continue;
267 /* sanity check */
268 if (toupper(path[0]) != drive_env[1] || path[1] != ':') continue;
269 DRIVE_Chdir( i, path + 2 );
271 return 1;
275 /***********************************************************************
276 * DRIVE_IsValid
278 int DRIVE_IsValid( int drive )
280 if ((drive < 0) || (drive >= MAX_DOS_DRIVES)) return 0;
281 return (DOSDrives[drive].root &&
282 !(DOSDrives[drive].flags & DRIVE_DISABLED));
286 /***********************************************************************
287 * DRIVE_GetCurrentDrive
289 int DRIVE_GetCurrentDrive(void)
291 TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
292 if (pTask && (pTask->curdrive & 0x80)) return pTask->curdrive & ~0x80;
293 return DRIVE_CurDrive;
297 /***********************************************************************
298 * DRIVE_SetCurrentDrive
300 int DRIVE_SetCurrentDrive( int drive )
302 TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
303 if (!DRIVE_IsValid( drive ))
305 SetLastError( ERROR_INVALID_DRIVE );
306 return 0;
308 TRACE("%c:\n", 'A' + drive );
309 DRIVE_CurDrive = drive;
310 if (pTask) pTask->curdrive = drive | 0x80;
311 chdir(DRIVE_GetUnixCwd(drive));
312 return 1;
316 /***********************************************************************
317 * DRIVE_FindDriveRoot
319 * Find a drive for which the root matches the beginning of the given path.
320 * This can be used to translate a Unix path into a drive + DOS path.
321 * Return value is the drive, or -1 on error. On success, path is modified
322 * to point to the beginning of the DOS path.
324 int DRIVE_FindDriveRoot( const char **path )
326 /* idea: check at all '/' positions.
327 * If the device and inode of that path is identical with the
328 * device and inode of the current drive then we found a solution.
329 * If there is another drive pointing to a deeper position in
330 * the file tree, we want to find that one, not the earlier solution.
332 int drive, rootdrive = -1;
333 char buffer[MAX_PATHNAME_LEN];
334 char *next = buffer;
335 const char *p = *path;
336 struct stat st;
338 strcpy( buffer, "/" );
339 for (;;)
341 if (stat( buffer, &st ) || !S_ISDIR( st.st_mode )) break;
343 /* Find the drive */
345 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
347 if (!DOSDrives[drive].root ||
348 (DOSDrives[drive].flags & DRIVE_DISABLED)) continue;
350 if ((DOSDrives[drive].dev == st.st_dev) &&
351 (DOSDrives[drive].ino == st.st_ino))
353 rootdrive = drive;
354 *path = p;
355 break;
359 /* Get the next path component */
361 *next++ = '/';
362 while ((*p == '/') || (*p == '\\')) p++;
363 if (!*p) break;
364 while (!IS_END_OF_NAME(*p)) *next++ = *p++;
365 *next = 0;
367 *next = 0;
369 if (rootdrive != -1)
370 TRACE("%s -> drive %c:, root='%s', name='%s'\n",
371 buffer, 'A' + rootdrive, DOSDrives[rootdrive].root, *path );
372 return rootdrive;
376 /***********************************************************************
377 * DRIVE_GetRoot
379 const char * DRIVE_GetRoot( int drive )
381 if (!DRIVE_IsValid( drive )) return NULL;
382 return DOSDrives[drive].root;
386 /***********************************************************************
387 * DRIVE_GetDosCwd
389 const char * DRIVE_GetDosCwd( int drive )
391 TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
392 if (!DRIVE_IsValid( drive )) return NULL;
394 /* Check if we need to change the directory to the new task. */
395 if (pTask && (pTask->curdrive & 0x80) && /* The task drive is valid */
396 ((pTask->curdrive & ~0x80) == drive) && /* and it's the one we want */
397 (DRIVE_LastTask != GetCurrentTask())) /* and the task changed */
399 /* Perform the task-switch */
400 if (!DRIVE_Chdir( drive, pTask->curdir )) DRIVE_Chdir( drive, "\\" );
401 DRIVE_LastTask = GetCurrentTask();
403 return DOSDrives[drive].dos_cwd;
407 /***********************************************************************
408 * DRIVE_GetUnixCwd
410 const char * DRIVE_GetUnixCwd( int drive )
412 TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
413 if (!DRIVE_IsValid( drive )) return NULL;
415 /* Check if we need to change the directory to the new task. */
416 if (pTask && (pTask->curdrive & 0x80) && /* The task drive is valid */
417 ((pTask->curdrive & ~0x80) == drive) && /* and it's the one we want */
418 (DRIVE_LastTask != GetCurrentTask())) /* and the task changed */
420 /* Perform the task-switch */
421 if (!DRIVE_Chdir( drive, pTask->curdir )) DRIVE_Chdir( drive, "\\" );
422 DRIVE_LastTask = GetCurrentTask();
424 return DOSDrives[drive].unix_cwd;
428 /***********************************************************************
429 * DRIVE_GetDevice
431 const char * DRIVE_GetDevice( int drive )
433 return (DRIVE_IsValid( drive )) ? DOSDrives[drive].device : NULL;
437 /***********************************************************************
438 * DRIVE_ReadSuperblock
440 * NOTE
441 * DRIVE_SetLabel and DRIVE_SetSerialNumber use this in order
442 * to check, that they are writing on a FAT filesystem !
444 int DRIVE_ReadSuperblock (int drive, char * buff)
446 #define DRIVE_SUPER 96
447 int fd;
448 off_t offs;
450 if (memset(buff,0,DRIVE_SUPER)!=buff) return -1;
451 if ((fd=open(DOSDrives[drive].device,O_RDONLY)) == -1)
453 struct stat st;
454 if (!DOSDrives[drive].device)
455 ERR("No device configured for drive %c: !\n", 'A'+drive);
456 else
457 ERR("Couldn't open device '%s' for drive %c: ! (%s)\n", DOSDrives[drive].device, 'A'+drive,
458 (stat(DOSDrives[drive].device, &st)) ?
459 "not available or symlink not valid ?" : "no permission");
460 ERR("Can't read drive volume info ! Either pre-set it or make sure the device to read it from is accessible !\n");
461 PROFILE_UsageWineIni();
462 return -1;
465 switch(DOSDrives[drive].type)
467 case TYPE_FLOPPY:
468 case TYPE_HD:
469 offs = 0;
470 break;
471 case TYPE_CDROM:
472 offs = CDROM_Data_FindBestVoldesc(fd);
473 break;
474 default:
475 offs = 0;
476 break;
479 if ((offs) && (lseek(fd,offs,SEEK_SET)!=offs)) return -4;
480 if (read(fd,buff,DRIVE_SUPER)!=DRIVE_SUPER) return -2;
482 switch(DOSDrives[drive].type)
484 case TYPE_FLOPPY:
485 case TYPE_HD:
486 if ((buff[0x26]!=0x29) || /* Check for FAT present */
487 /* FIXME: do really all FAT have their name beginning with
488 "FAT" ? (At least FAT12, FAT16 and FAT32 have :) */
489 memcmp( buff+0x36,"FAT",3))
491 ERR("The filesystem is not FAT !! (device=%s)\n",
492 DOSDrives[drive].device);
493 return -3;
495 break;
496 case TYPE_CDROM:
497 if (strncmp(&buff[1],"CD001",5)) /* Check for iso9660 present */
498 return -3;
499 /* FIXME: do we need to check for "CDROM", too ? (high sierra) */
500 break;
501 default:
502 return -3;
503 break;
506 return close(fd);
510 /***********************************************************************
511 * DRIVE_WriteSuperblockEntry
513 * NOTE
514 * We are writing as little as possible (ie. not the whole SuperBlock)
515 * not to interfere with kernel. The drive can be mounted !
517 int DRIVE_WriteSuperblockEntry (int drive, off_t ofs, size_t len, char * buff)
519 int fd;
521 if ((fd=open(DOSDrives[drive].device,O_WRONLY))==-1)
523 ERR("Cannot open the device %s (for writing)\n",
524 DOSDrives[drive].device);
525 return -1;
527 if (lseek(fd,ofs,SEEK_SET)!=ofs)
529 ERR("lseek failed on device %s !\n",
530 DOSDrives[drive].device);
531 close(fd);
532 return -2;
534 if (write(fd,buff,len)!=len)
536 close(fd);
537 ERR("Cannot write on %s !\n",
538 DOSDrives[drive].device);
539 return -3;
541 return close (fd);
546 /***********************************************************************
547 * DRIVE_GetLabel
549 const char * DRIVE_GetLabel( int drive )
551 int read = 0;
552 char buff[DRIVE_SUPER];
553 int offs = -1;
555 if (!DRIVE_IsValid( drive )) return NULL;
556 if (DRIVE_GetType(drive) == TYPE_CDROM)
558 read = CDROM_GetLabel(drive, DOSDrives[drive].label_read);
560 else
561 if (DOSDrives[drive].flags & DRIVE_READ_VOL_INFO)
563 if (DRIVE_ReadSuperblock(drive,(char *) buff))
564 ERR("Invalid or unreadable superblock on %s (%c:).\n",
565 DOSDrives[drive].device, (char)(drive+'A'));
566 else {
567 if (DOSDrives[drive].type == TYPE_FLOPPY ||
568 DOSDrives[drive].type == TYPE_HD)
569 offs = 0x2b;
571 /* FIXME: ISO9660 uses a 32 bytes long label. Should we do also? */
572 if (offs != -1) memcpy(DOSDrives[drive].label_read,buff+offs,11);
573 DOSDrives[drive].label_read[11]='\0';
574 read = 1;
578 return (read) ?
579 DOSDrives[drive].label_read : DOSDrives[drive].label_conf;
583 /***********************************************************************
584 * DRIVE_GetSerialNumber
586 DWORD DRIVE_GetSerialNumber( int drive )
588 DWORD serial = 0;
589 char buff[DRIVE_SUPER];
591 if (!DRIVE_IsValid( drive )) return 0;
593 if (DOSDrives[drive].flags & DRIVE_READ_VOL_INFO)
595 switch(DOSDrives[drive].type)
597 case TYPE_FLOPPY:
598 case TYPE_HD:
599 if (DRIVE_ReadSuperblock(drive,(char *) buff))
600 MESSAGE("Invalid or unreadable superblock on %s (%c:)."
601 " Maybe not FAT?\n" ,
602 DOSDrives[drive].device, 'A'+drive);
603 else
604 serial = *((DWORD*)(buff+0x27));
605 break;
606 case TYPE_CDROM:
607 serial = CDROM_GetSerial(drive);
608 break;
609 default:
610 FIXME("Serial number reading from file system on drive %c: not supported yet.\n", drive+'A');
614 return (serial) ? serial : DOSDrives[drive].serial_conf;
618 /***********************************************************************
619 * DRIVE_SetSerialNumber
621 int DRIVE_SetSerialNumber( int drive, DWORD serial )
623 char buff[DRIVE_SUPER];
625 if (!DRIVE_IsValid( drive )) return 0;
627 if (DOSDrives[drive].flags & DRIVE_READ_VOL_INFO)
629 if ((DOSDrives[drive].type != TYPE_FLOPPY) &&
630 (DOSDrives[drive].type != TYPE_HD)) return 0;
631 /* check, if the drive has a FAT filesystem */
632 if (DRIVE_ReadSuperblock(drive, buff)) return 0;
633 if (DRIVE_WriteSuperblockEntry(drive, 0x27, 4, (char *) &serial)) return 0;
634 return 1;
637 if (DOSDrives[drive].type == TYPE_CDROM) return 0;
638 DOSDrives[drive].serial_conf = serial;
639 return 1;
643 /***********************************************************************
644 * DRIVE_GetType
646 DRIVETYPE DRIVE_GetType( int drive )
648 if (!DRIVE_IsValid( drive )) return TYPE_INVALID;
649 return DOSDrives[drive].type;
653 /***********************************************************************
654 * DRIVE_GetFlags
656 UINT DRIVE_GetFlags( int drive )
658 if ((drive < 0) || (drive >= MAX_DOS_DRIVES)) return 0;
659 return DOSDrives[drive].flags;
663 /***********************************************************************
664 * DRIVE_Chdir
666 int DRIVE_Chdir( int drive, const char *path )
668 DOS_FULL_NAME full_name;
669 char buffer[MAX_PATHNAME_LEN];
670 LPSTR unix_cwd;
671 BY_HANDLE_FILE_INFORMATION info;
672 TDB *pTask = (TDB *)GlobalLock16( GetCurrentTask() );
674 strcpy( buffer, "A:" );
675 buffer[0] += drive;
676 TRACE("(%s,%s)\n", buffer, path );
677 lstrcpynA( buffer + 2, path, sizeof(buffer) - 2 );
679 if (!DOSFS_GetFullName( buffer, TRUE, &full_name )) return 0;
680 if (!FILE_Stat( full_name.long_name, &info )) return 0;
681 if (!(info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY))
683 SetLastError( ERROR_FILE_NOT_FOUND );
684 return 0;
686 unix_cwd = full_name.long_name + strlen( DOSDrives[drive].root );
687 while (*unix_cwd == '/') unix_cwd++;
689 TRACE("(%c:): unix_cwd=%s dos_cwd=%s\n",
690 'A' + drive, unix_cwd, full_name.short_name + 3 );
692 HeapFree( GetProcessHeap(), 0, DOSDrives[drive].dos_cwd );
693 HeapFree( GetProcessHeap(), 0, DOSDrives[drive].unix_cwd );
694 DOSDrives[drive].dos_cwd = HEAP_strdupA( GetProcessHeap(), 0,
695 full_name.short_name + 3 );
696 DOSDrives[drive].unix_cwd = HEAP_strdupA( GetProcessHeap(), 0, unix_cwd );
698 if (pTask && (pTask->curdrive & 0x80) &&
699 ((pTask->curdrive & ~0x80) == drive))
701 lstrcpynA( pTask->curdir, full_name.short_name + 2,
702 sizeof(pTask->curdir) );
703 DRIVE_LastTask = GetCurrentTask();
704 chdir(unix_cwd); /* Only change if on current drive */
706 return 1;
710 /***********************************************************************
711 * DRIVE_Disable
713 int DRIVE_Disable( int drive )
715 if ((drive < 0) || (drive >= MAX_DOS_DRIVES) || !DOSDrives[drive].root)
717 SetLastError( ERROR_INVALID_DRIVE );
718 return 0;
720 DOSDrives[drive].flags |= DRIVE_DISABLED;
721 return 1;
725 /***********************************************************************
726 * DRIVE_Enable
728 int DRIVE_Enable( int drive )
730 if ((drive < 0) || (drive >= MAX_DOS_DRIVES) || !DOSDrives[drive].root)
732 SetLastError( ERROR_INVALID_DRIVE );
733 return 0;
735 DOSDrives[drive].flags &= ~DRIVE_DISABLED;
736 return 1;
740 /***********************************************************************
741 * DRIVE_SetLogicalMapping
743 int DRIVE_SetLogicalMapping ( int existing_drive, int new_drive )
745 /* If new_drive is already valid, do nothing and return 0
746 otherwise, copy DOSDrives[existing_drive] to DOSDrives[new_drive] */
748 DOSDRIVE *old, *new;
750 old = DOSDrives + existing_drive;
751 new = DOSDrives + new_drive;
753 if ((existing_drive < 0) || (existing_drive >= MAX_DOS_DRIVES) ||
754 !old->root ||
755 (new_drive < 0) || (new_drive >= MAX_DOS_DRIVES))
757 SetLastError( ERROR_INVALID_DRIVE );
758 return 0;
761 if ( new->root )
763 TRACE("Can't map drive %c: to already existing drive %c:\n",
764 'A' + existing_drive, 'A' + new_drive );
765 /* it is already mapped there, so return success */
766 if (!strcmp(old->root,new->root))
767 return 1;
768 return 0;
771 new->root = HEAP_strdupA( GetProcessHeap(), 0, old->root );
772 new->dos_cwd = HEAP_strdupA( GetProcessHeap(), 0, old->dos_cwd );
773 new->unix_cwd = HEAP_strdupA( GetProcessHeap(), 0, old->unix_cwd );
774 new->device = HEAP_strdupA( GetProcessHeap(), 0, old->device );
775 memcpy ( new->label_conf, old->label_conf, 12 );
776 memcpy ( new->label_read, old->label_read, 12 );
777 new->serial_conf = old->serial_conf;
778 new->type = old->type;
779 new->flags = old->flags;
780 new->dev = old->dev;
781 new->ino = old->ino;
783 TRACE("Drive %c: is now equal to drive %c:\n",
784 'A' + new_drive, 'A' + existing_drive );
786 return 1;
790 /***********************************************************************
791 * DRIVE_OpenDevice
793 * Open the drive raw device and return a Unix fd (or -1 on error).
795 int DRIVE_OpenDevice( int drive, int flags )
797 if (!DRIVE_IsValid( drive )) return -1;
798 return open( DOSDrives[drive].device, flags );
802 /***********************************************************************
803 * DRIVE_RawRead
805 * Read raw sectors from a device
807 int DRIVE_RawRead(BYTE drive, DWORD begin, DWORD nr_sect, BYTE *dataptr, BOOL fake_success)
809 int fd;
811 if ((fd = DRIVE_OpenDevice( drive, O_RDONLY )) != -1)
813 lseek( fd, begin * 512, SEEK_SET );
814 /* FIXME: check errors */
815 read( fd, dataptr, nr_sect * 512 );
816 close( fd );
818 else
820 memset(dataptr, 0, nr_sect * 512);
821 if (fake_success)
823 if (begin == 0 && nr_sect > 1) *(dataptr + 512) = 0xf8;
824 if (begin == 1) *dataptr = 0xf8;
826 else
827 return 0;
829 return 1;
833 /***********************************************************************
834 * DRIVE_RawWrite
836 * Write raw sectors to a device
838 int DRIVE_RawWrite(BYTE drive, DWORD begin, DWORD nr_sect, BYTE *dataptr, BOOL fake_success)
840 int fd;
842 if ((fd = DRIVE_OpenDevice( drive, O_RDONLY )) != -1)
844 lseek( fd, begin * 512, SEEK_SET );
845 /* FIXME: check errors */
846 write( fd, dataptr, nr_sect * 512 );
847 close( fd );
849 else
850 if (!(fake_success))
851 return 0;
853 return 1;
857 /***********************************************************************
858 * DRIVE_GetFreeSpace
860 static int DRIVE_GetFreeSpace( int drive, PULARGE_INTEGER size,
861 PULARGE_INTEGER available )
863 struct statfs info;
865 if (!DRIVE_IsValid(drive))
867 SetLastError( ERROR_INVALID_DRIVE );
868 return 0;
871 /* FIXME: add autoconf check for this */
872 #if defined(__svr4__) || defined(_SCO_DS) || defined(__sun)
873 if (statfs( DOSDrives[drive].root, &info, 0, 0) < 0)
874 #else
875 if (statfs( DOSDrives[drive].root, &info) < 0)
876 #endif
878 FILE_SetDosError();
879 WARN("cannot do statfs(%s)\n", DOSDrives[drive].root);
880 return 0;
883 size->QuadPart = RtlEnlargedUnsignedMultiply( info.f_bsize, info.f_blocks );
884 #ifdef STATFS_HAS_BAVAIL
885 available->QuadPart = RtlEnlargedUnsignedMultiply( info.f_bavail, info.f_bsize );
886 #else
887 # ifdef STATFS_HAS_BFREE
888 available->QuadPart = RtlEnlargedUnsignedMultiply( info.f_bfree, info.f_bsize );
889 # else
890 # error "statfs has no bfree/bavail member!"
891 # endif
892 #endif
893 if (DRIVE_GetType(drive) == TYPE_CDROM)
894 { /* ALWAYS 0, even if no real CD-ROM mounted there !! */
895 available->QuadPart = 0;
897 return 1;
900 /***********************************************************************
901 * DRIVE_GetCurrentDirectory
902 * Returns "X:\\path\\etc\\".
904 * Despite the API description, return required length including the
905 * terminating null when buffer too small. This is the real behaviour.
908 static UINT DRIVE_GetCurrentDirectory( UINT buflen, LPSTR buf )
910 UINT ret;
911 const char *s = DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() );
913 assert(s);
914 ret = strlen(s) + 3; /* length of WHOLE current directory */
915 if (ret >= buflen) return ret + 1;
916 lstrcpynA( buf, "A:\\", min( 4, buflen ) );
917 if (buflen) buf[0] += DRIVE_GetCurrentDrive();
918 if (buflen > 3) lstrcpynA( buf + 3, s, buflen - 3 );
919 return ret;
923 /***********************************************************************
924 * DRIVE_BuildEnv
926 * Build the environment array containing the drives current directories.
927 * Resulting pointer must be freed with HeapFree.
929 char *DRIVE_BuildEnv(void)
931 int i, length = 0;
932 const char *cwd[MAX_DOS_DRIVES];
933 char *env, *p;
935 for (i = 0; i < MAX_DOS_DRIVES; i++)
937 if ((cwd[i] = DRIVE_GetDosCwd(i)) && cwd[i][0]) length += strlen(cwd[i]) + 8;
939 if (!(env = HeapAlloc( GetProcessHeap(), 0, length+1 ))) return NULL;
940 for (i = 0, p = env; i < MAX_DOS_DRIVES; i++)
942 if (cwd[i] && cwd[i][0])
943 p += sprintf( p, "=%c:=%c:\\%s", 'A'+i, 'A'+i, cwd[i] ) + 1;
945 *p = 0;
946 return env;
950 /***********************************************************************
951 * GetDiskFreeSpace16 (KERNEL.422)
953 BOOL16 WINAPI GetDiskFreeSpace16( LPCSTR root, LPDWORD cluster_sectors,
954 LPDWORD sector_bytes, LPDWORD free_clusters,
955 LPDWORD total_clusters )
957 return GetDiskFreeSpaceA( root, cluster_sectors, sector_bytes,
958 free_clusters, total_clusters );
962 /***********************************************************************
963 * GetDiskFreeSpaceA (KERNEL32.206)
965 * Fails if expression resulting from current drive's dir and "root"
966 * is not a root dir of the target drive.
968 * UNDOC: setting some LPDWORDs to NULL is perfectly possible
969 * if the corresponding info is unneeded.
971 * FIXME: needs to support UNC names from Win95 OSR2 on.
973 * Behaviour under Win95a:
974 * CurrDir root result
975 * "E:\\TEST" "E:" FALSE
976 * "E:\\" "E:" TRUE
977 * "E:\\" "E" FALSE
978 * "E:\\" "\\" TRUE
979 * "E:\\TEST" "\\" TRUE
980 * "E:\\TEST" ":\\" FALSE
981 * "E:\\TEST" "E:\\" TRUE
982 * "E:\\TEST" "" FALSE
983 * "E:\\" "" FALSE (!)
984 * "E:\\" 0x0 TRUE
985 * "E:\\TEST" 0x0 TRUE (!)
986 * "E:\\TEST" "C:" TRUE (when CurrDir of "C:" set to "\\")
987 * "E:\\TEST" "C:" FALSE (when CurrDir of "C:" set to "\\TEST")
989 BOOL WINAPI GetDiskFreeSpaceA( LPCSTR root, LPDWORD cluster_sectors,
990 LPDWORD sector_bytes, LPDWORD free_clusters,
991 LPDWORD total_clusters )
993 int drive, sec_size;
994 ULARGE_INTEGER size,available;
995 LPCSTR path;
996 DWORD cluster_sec;
998 if ((!root) || (strcmp(root,"\\") == 0))
999 drive = DRIVE_GetCurrentDrive();
1000 else
1001 if ( (strlen(root) >= 2) && (root[1] == ':')) /* root contains drive tag */
1003 drive = toupper(root[0]) - 'A';
1004 path = &root[2];
1005 if (path[0] == '\0')
1006 path = DRIVE_GetDosCwd(drive);
1007 else
1008 if (path[0] == '\\')
1009 path++;
1010 if (strlen(path)) /* oops, we are in a subdir */
1011 return FALSE;
1013 else
1014 return FALSE;
1016 if (!DRIVE_GetFreeSpace(drive, &size, &available)) return FALSE;
1018 /* Cap the size and available at 2GB as per specs. */
1019 if ((size.s.HighPart) ||(size.s.LowPart > 0x7fffffff))
1021 size.s.HighPart = 0;
1022 size.s.LowPart = 0x7fffffff;
1024 if ((available.s.HighPart) ||(available.s.LowPart > 0x7fffffff))
1026 available.s.HighPart =0;
1027 available.s.LowPart = 0x7fffffff;
1029 sec_size = (DRIVE_GetType(drive)==TYPE_CDROM) ? 2048 : 512;
1030 size.s.LowPart /= sec_size;
1031 available.s.LowPart /= sec_size;
1032 /* fixme: probably have to adjust those variables too for CDFS */
1033 cluster_sec = 1;
1034 while (cluster_sec * 65536 < size.s.LowPart) cluster_sec *= 2;
1036 if (cluster_sectors)
1037 *cluster_sectors = cluster_sec;
1038 if (sector_bytes)
1039 *sector_bytes = sec_size;
1040 if (free_clusters)
1041 *free_clusters = available.s.LowPart / cluster_sec;
1042 if (total_clusters)
1043 *total_clusters = size.s.LowPart / cluster_sec;
1044 return TRUE;
1048 /***********************************************************************
1049 * GetDiskFreeSpaceW (KERNEL32.207)
1051 BOOL WINAPI GetDiskFreeSpaceW( LPCWSTR root, LPDWORD cluster_sectors,
1052 LPDWORD sector_bytes, LPDWORD free_clusters,
1053 LPDWORD total_clusters )
1055 LPSTR xroot;
1056 BOOL ret;
1058 xroot = HEAP_strdupWtoA( GetProcessHeap(), 0, root);
1059 ret = GetDiskFreeSpaceA( xroot,cluster_sectors, sector_bytes,
1060 free_clusters, total_clusters );
1061 HeapFree( GetProcessHeap(), 0, xroot );
1062 return ret;
1066 /***********************************************************************
1067 * GetDiskFreeSpaceExA (KERNEL32.871)
1069 * This function is used to aquire the size of the available and
1070 * total space on a logical volume.
1072 * RETURNS
1074 * Zero on failure, nonzero upon success. Use GetLastError to obtain
1075 * detailed error information.
1078 BOOL WINAPI GetDiskFreeSpaceExA( LPCSTR root,
1079 PULARGE_INTEGER avail,
1080 PULARGE_INTEGER total,
1081 PULARGE_INTEGER totalfree)
1083 int drive;
1084 ULARGE_INTEGER size,available;
1086 if (!root) drive = DRIVE_GetCurrentDrive();
1087 else
1089 if ((root[1]) && ((root[1] != ':') || (root[2] != '\\')))
1091 FIXME("there are valid root names which are not supported yet\n");
1092 /* ..like UNC names, for instance. */
1094 WARN("invalid root '%s'\n", root );
1095 return FALSE;
1097 drive = toupper(root[0]) - 'A';
1100 if (!DRIVE_GetFreeSpace(drive, &size, &available)) return FALSE;
1102 if (total)
1104 total->s.HighPart = size.s.HighPart;
1105 total->s.LowPart = size.s.LowPart;
1108 if (totalfree)
1110 totalfree->s.HighPart = available.s.HighPart;
1111 totalfree->s.LowPart = available.s.LowPart;
1114 if (avail)
1116 if (FIXME_ON(dosfs))
1118 /* On Windows2000, we need to check the disk quota
1119 allocated for the user owning the calling process. We
1120 don't want to be more obtrusive than necessary with the
1121 FIXME messages, so don't print the FIXME unless Wine is
1122 actually masquerading as Windows2000. */
1124 OSVERSIONINFOA ovi;
1125 ovi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
1126 if (GetVersionExA(&ovi))
1128 if (ovi.dwPlatformId == VER_PLATFORM_WIN32_NT && ovi.dwMajorVersion > 4)
1129 FIXME("no per-user quota support yet\n");
1133 /* Quick hack, should eventually be fixed to work 100% with
1134 Windows2000 (see comment above). */
1135 avail->s.HighPart = available.s.HighPart;
1136 avail->s.LowPart = available.s.LowPart;
1139 return TRUE;
1142 /***********************************************************************
1143 * GetDiskFreeSpaceExW (KERNEL32.873)
1145 BOOL WINAPI GetDiskFreeSpaceExW( LPCWSTR root, PULARGE_INTEGER avail,
1146 PULARGE_INTEGER total,
1147 PULARGE_INTEGER totalfree)
1149 LPSTR xroot;
1150 BOOL ret;
1152 xroot = HEAP_strdupWtoA( GetProcessHeap(), 0, root);
1153 ret = GetDiskFreeSpaceExA( xroot, avail, total, totalfree);
1154 HeapFree( GetProcessHeap(), 0, xroot );
1155 return ret;
1158 /***********************************************************************
1159 * GetDriveType16 (KERNEL.136)
1160 * This function returns the type of a drive in Win16.
1161 * Note that it returns DRIVE_REMOTE for CD-ROMs, since MSCDEX uses the
1162 * remote drive API. The return value DRIVE_REMOTE for CD-ROMs has been
1163 * verified on Win 3.11 and Windows 95. Some programs rely on it, so don't
1164 * do any pseudo-clever changes.
1166 * RETURNS
1167 * drivetype DRIVE_xxx
1169 UINT16 WINAPI GetDriveType16(
1170 UINT16 drive /* [in] number (NOT letter) of drive */
1172 TRACE("(%c:)\n", 'A' + drive );
1173 switch(DRIVE_GetType(drive))
1175 case TYPE_FLOPPY: return DRIVE_REMOVABLE;
1176 case TYPE_HD: return DRIVE_FIXED;
1177 case TYPE_CDROM: return DRIVE_REMOTE;
1178 case TYPE_NETWORK: return DRIVE_REMOTE;
1179 case TYPE_INVALID:
1180 default: return DRIVE_CANNOTDETERMINE;
1185 /***********************************************************************
1186 * GetDriveTypeA (KERNEL32.208)
1188 * Returns the type of the disk drive specified. If root is NULL the
1189 * root of the current directory is used.
1191 * RETURNS
1193 * Type of drive (from Win32 SDK):
1195 * DRIVE_UNKNOWN unable to find out anything about the drive
1196 * DRIVE_NO_ROOT_DIR nonexistent root dir
1197 * DRIVE_REMOVABLE the disk can be removed from the machine
1198 * DRIVE_FIXED the disk can not be removed from the machine
1199 * DRIVE_REMOTE network disk
1200 * DRIVE_CDROM CDROM drive
1201 * DRIVE_RAMDISK virtual disk in RAM
1203 * DRIVE_DOESNOTEXIST FIXME Not valid return value
1204 * DRIVE_CANNOTDETERMINE FIXME Not valid return value
1206 * BUGS
1208 * Currently returns DRIVE_DOESNOTEXIST and DRIVE_CANNOTDETERMINE
1209 * when it really should return DRIVE_NO_ROOT_DIR and DRIVE_UNKNOWN.
1210 * Why were the former defines used?
1212 * DRIVE_RAMDISK is unsupported.
1214 UINT WINAPI GetDriveTypeA(LPCSTR root /* String describing drive */)
1216 int drive;
1217 TRACE("(%s)\n", debugstr_a(root));
1219 if (NULL == root) drive = DRIVE_GetCurrentDrive();
1220 else
1222 if ((root[1]) && (root[1] != ':'))
1224 WARN("invalid root '%s'\n", debugstr_a(root));
1225 return DRIVE_DOESNOTEXIST;
1227 drive = toupper(root[0]) - 'A';
1229 switch(DRIVE_GetType(drive))
1231 case TYPE_FLOPPY: return DRIVE_REMOVABLE;
1232 case TYPE_HD: return DRIVE_FIXED;
1233 case TYPE_CDROM: return DRIVE_CDROM;
1234 case TYPE_NETWORK: return DRIVE_REMOTE;
1235 case TYPE_INVALID: return DRIVE_DOESNOTEXIST;
1236 default: return DRIVE_CANNOTDETERMINE;
1241 /***********************************************************************
1242 * GetDriveTypeW (KERNEL32.209)
1244 UINT WINAPI GetDriveTypeW( LPCWSTR root )
1246 LPSTR xpath = HEAP_strdupWtoA( GetProcessHeap(), 0, root );
1247 UINT ret = GetDriveTypeA( xpath );
1248 HeapFree( GetProcessHeap(), 0, xpath );
1249 return ret;
1253 /***********************************************************************
1254 * GetCurrentDirectory16 (KERNEL.411)
1256 UINT16 WINAPI GetCurrentDirectory16( UINT16 buflen, LPSTR buf )
1258 return (UINT16)DRIVE_GetCurrentDirectory(buflen, buf);
1262 /***********************************************************************
1263 * GetCurrentDirectoryA (KERNEL32.196)
1265 UINT WINAPI GetCurrentDirectoryA( UINT buflen, LPSTR buf )
1267 UINT ret;
1268 char longname[MAX_PATHNAME_LEN];
1269 char shortname[MAX_PATHNAME_LEN];
1270 ret = DRIVE_GetCurrentDirectory(MAX_PATHNAME_LEN, shortname);
1271 if ( ret > MAX_PATHNAME_LEN ) {
1272 ERR_(file)("pathnamelength (%d) > MAX_PATHNAME_LEN!\n", ret );
1273 return ret;
1275 GetLongPathNameA(shortname, longname, MAX_PATHNAME_LEN);
1276 ret = strlen( longname ) + 1;
1277 if (ret > buflen) return ret;
1278 strcpy(buf, longname);
1279 return ret - 1;
1282 /***********************************************************************
1283 * GetCurrentDirectoryW (KERNEL32.197)
1285 UINT WINAPI GetCurrentDirectoryW( UINT buflen, LPWSTR buf )
1287 LPSTR xpath = HeapAlloc( GetProcessHeap(), 0, buflen+1 );
1288 UINT ret = GetCurrentDirectoryA( buflen, xpath );
1289 if (ret < buflen) lstrcpyAtoW ( buf, xpath );
1290 HeapFree( GetProcessHeap(), 0, xpath );
1291 return ret;
1295 /***********************************************************************
1296 * SetCurrentDirectory (KERNEL.412)
1298 BOOL16 WINAPI SetCurrentDirectory16( LPCSTR dir )
1300 return SetCurrentDirectoryA( dir );
1304 /***********************************************************************
1305 * SetCurrentDirectoryA (KERNEL32.479)
1307 BOOL WINAPI SetCurrentDirectoryA( LPCSTR dir )
1309 int drive, olddrive = DRIVE_GetCurrentDrive();
1311 if (!dir) {
1312 ERR_(file)("(NULL)!\n");
1313 return FALSE;
1315 if (dir[0] && (dir[1]==':'))
1317 drive = toupper( *dir ) - 'A';
1318 dir += 2;
1320 else
1321 drive = olddrive;
1323 /* WARNING: we need to set the drive before the dir, as DRIVE_Chdir
1324 sets pTask->curdir only if pTask->curdrive is drive */
1325 if (!(DRIVE_SetCurrentDrive( drive )))
1326 return FALSE;
1327 /* FIXME: what about empty strings? Add a \\ ? */
1328 if (!DRIVE_Chdir( drive, dir )) {
1329 DRIVE_SetCurrentDrive(olddrive);
1330 return FALSE;
1332 return TRUE;
1336 /***********************************************************************
1337 * SetCurrentDirectoryW (KERNEL32.480)
1339 BOOL WINAPI SetCurrentDirectoryW( LPCWSTR dirW )
1341 LPSTR dir = HEAP_strdupWtoA( GetProcessHeap(), 0, dirW );
1342 BOOL res = SetCurrentDirectoryA( dir );
1343 HeapFree( GetProcessHeap(), 0, dir );
1344 return res;
1348 /***********************************************************************
1349 * GetLogicalDriveStringsA (KERNEL32.231)
1351 UINT WINAPI GetLogicalDriveStringsA( UINT len, LPSTR buffer )
1353 int drive, count;
1355 for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
1356 if (DRIVE_IsValid(drive)) count++;
1357 if ((count * 4) + 1 <= len)
1359 LPSTR p = buffer;
1360 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
1361 if (DRIVE_IsValid(drive))
1363 *p++ = 'a' + drive;
1364 *p++ = ':';
1365 *p++ = '\\';
1366 *p++ = '\0';
1368 *p = '\0';
1369 return count * 4;
1371 else
1372 return (count * 4) + 1; /* account for terminating null */
1373 /* The API tells about these different return values */
1377 /***********************************************************************
1378 * GetLogicalDriveStringsW (KERNEL32.232)
1380 UINT WINAPI GetLogicalDriveStringsW( UINT len, LPWSTR buffer )
1382 int drive, count;
1384 for (drive = count = 0; drive < MAX_DOS_DRIVES; drive++)
1385 if (DRIVE_IsValid(drive)) count++;
1386 if (count * 4 * sizeof(WCHAR) <= len)
1388 LPWSTR p = buffer;
1389 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
1390 if (DRIVE_IsValid(drive))
1392 *p++ = (WCHAR)('a' + drive);
1393 *p++ = (WCHAR)':';
1394 *p++ = (WCHAR)'\\';
1395 *p++ = (WCHAR)'\0';
1397 *p = (WCHAR)'\0';
1399 return count * 4 * sizeof(WCHAR);
1403 /***********************************************************************
1404 * GetLogicalDrives (KERNEL32.233)
1406 DWORD WINAPI GetLogicalDrives(void)
1408 DWORD ret = 0;
1409 int drive;
1411 for (drive = 0; drive < MAX_DOS_DRIVES; drive++)
1413 if ( (DRIVE_IsValid(drive)) ||
1414 (DOSDrives[drive].type == TYPE_CDROM)) /* audio CD is also valid */
1415 ret |= (1 << drive);
1417 return ret;
1421 /***********************************************************************
1422 * GetVolumeInformationA (KERNEL32.309)
1424 BOOL WINAPI GetVolumeInformationA( LPCSTR root, LPSTR label,
1425 DWORD label_len, DWORD *serial,
1426 DWORD *filename_len, DWORD *flags,
1427 LPSTR fsname, DWORD fsname_len )
1429 int drive;
1430 char *cp;
1432 /* FIXME, SetLastError()s missing */
1434 if (!root) drive = DRIVE_GetCurrentDrive();
1435 else
1437 if ((root[1]) && (root[1] != ':'))
1439 WARN("invalid root '%s'\n",root);
1440 return FALSE;
1442 drive = toupper(root[0]) - 'A';
1444 if (!DRIVE_IsValid( drive )) return FALSE;
1445 if (label)
1447 lstrcpynA( label, DRIVE_GetLabel(drive), label_len );
1448 for (cp = label; *cp; cp++);
1449 while (cp != label && *(cp-1) == ' ') cp--;
1450 *cp = '\0';
1452 if (serial) *serial = DRIVE_GetSerialNumber(drive);
1454 /* Set the filesystem information */
1455 /* Note: we only emulate a FAT fs at present */
1457 if (filename_len) {
1458 if (DOSDrives[drive].flags & DRIVE_SHORT_NAMES)
1459 *filename_len = 12;
1460 else
1461 *filename_len = 255;
1463 if (flags)
1465 *flags=0;
1466 if (DOSDrives[drive].flags & DRIVE_CASE_SENSITIVE)
1467 *flags|=FS_CASE_SENSITIVE;
1468 if (DOSDrives[drive].flags & DRIVE_CASE_PRESERVING)
1469 *flags|=FS_CASE_IS_PRESERVED;
1471 if (fsname) {
1472 /* Diablo checks that return code ... */
1473 if (DRIVE_GetType(drive)==TYPE_CDROM)
1474 lstrcpynA( fsname, "CDFS", fsname_len );
1475 else
1476 lstrcpynA( fsname, "FAT", fsname_len );
1478 return TRUE;
1482 /***********************************************************************
1483 * GetVolumeInformationW (KERNEL32.310)
1485 BOOL WINAPI GetVolumeInformationW( LPCWSTR root, LPWSTR label,
1486 DWORD label_len, DWORD *serial,
1487 DWORD *filename_len, DWORD *flags,
1488 LPWSTR fsname, DWORD fsname_len )
1490 LPSTR xroot = HEAP_strdupWtoA( GetProcessHeap(), 0, root );
1491 LPSTR xvolname = label ? HeapAlloc(GetProcessHeap(),0,label_len) : NULL;
1492 LPSTR xfsname = fsname ? HeapAlloc(GetProcessHeap(),0,fsname_len) : NULL;
1493 BOOL ret = GetVolumeInformationA( xroot, xvolname, label_len, serial,
1494 filename_len, flags, xfsname,
1495 fsname_len );
1496 if (ret)
1498 if (label) lstrcpyAtoW( label, xvolname );
1499 if (fsname) lstrcpyAtoW( fsname, xfsname );
1501 HeapFree( GetProcessHeap(), 0, xroot );
1502 HeapFree( GetProcessHeap(), 0, xvolname );
1503 HeapFree( GetProcessHeap(), 0, xfsname );
1504 return ret;
1507 /***********************************************************************
1508 * SetVolumeLabelA (KERNEL32.675)
1510 BOOL WINAPI SetVolumeLabelA( LPCSTR root, LPCSTR volname )
1512 int drive;
1514 /* FIXME, SetLastErrors missing */
1516 if (!root) drive = DRIVE_GetCurrentDrive();
1517 else
1519 if ((root[1]) && (root[1] != ':'))
1521 WARN("invalid root '%s'\n",root);
1522 return FALSE;
1524 drive = toupper(root[0]) - 'A';
1526 if (!DRIVE_IsValid( drive )) return FALSE;
1528 /* some copy protection stuff check this */
1529 if (DRIVE_GetType( drive ) == TYPE_CDROM) return FALSE;
1531 FIXME("(%s,%s),stub!\n", root, volname);
1532 return TRUE;
1535 /***********************************************************************
1536 * SetVolumeLabelW (KERNEL32.676)
1538 BOOL WINAPI SetVolumeLabelW(LPCWSTR rootpath,LPCWSTR volname)
1540 LPSTR xroot, xvol;
1541 BOOL ret;
1543 xroot = HEAP_strdupWtoA( GetProcessHeap(), 0, rootpath);
1544 xvol = HEAP_strdupWtoA( GetProcessHeap(), 0, volname);
1545 ret = SetVolumeLabelA( xroot, xvol );
1546 HeapFree( GetProcessHeap(), 0, xroot );
1547 HeapFree( GetProcessHeap(), 0, xvol );
1548 return ret;