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)
14 #include "wine/port.h"
21 #include <sys/types.h>
27 #ifdef HAVE_SYS_PARAM_H
28 # include <sys/param.h>
30 #ifdef STATFS_DEFINED_BY_SYS_VFS
33 # ifdef STATFS_DEFINED_BY_SYS_MOUNT
34 # include <sys/mount.h>
36 # ifdef STATFS_DEFINED_BY_SYS_STATFS
37 # include <sys/statfs.h>
44 #include "wine/winbase16.h" /* for GetCurrentTask */
52 #include "debugtools.h"
53 #include "wine/server.h"
58 DEFAULT_DEBUG_CHANNEL(dosfs
);
59 DECLARE_DEBUG_CHANNEL(file
);
63 char *root
; /* root dir in Unix format without trailing / */
64 char *dos_cwd
; /* cwd in DOS format without leading or trailing \ */
65 char *unix_cwd
; /* cwd in Unix format without leading or trailing / */
66 char *device
; /* raw device path */
67 char label_conf
[12]; /* drive label as cfg'd in wine config */
68 char label_read
[12]; /* drive label as read from device */
69 DWORD serial_conf
; /* drive serial number as cfg'd in wine config */
70 UINT type
; /* drive type */
71 UINT flags
; /* drive flags */
72 dev_t dev
; /* unix device number */
73 ino_t ino
; /* unix inode number */
77 static const char * const DRIVE_Types
[] =
79 "", /* DRIVE_UNKNOWN */
80 "", /* DRIVE_NO_ROOT_DIR */
81 "floppy", /* DRIVE_REMOVABLE */
82 "hd", /* DRIVE_FIXED */
83 "network", /* DRIVE_REMOTE */
84 "cdrom", /* DRIVE_CDROM */
85 "ramdisk" /* DRIVE_RAMDISK */
89 /* Known filesystem types */
97 static const FS_DESCR DRIVE_Filesystems
[] =
99 { "unix", DRIVE_CASE_SENSITIVE
| DRIVE_CASE_PRESERVING
},
100 { "msdos", DRIVE_SHORT_NAMES
},
101 { "dos", DRIVE_SHORT_NAMES
},
102 { "fat", DRIVE_SHORT_NAMES
},
103 { "vfat", DRIVE_CASE_PRESERVING
},
104 { "win95", DRIVE_CASE_PRESERVING
},
109 static DOSDRIVE DOSDrives
[MAX_DOS_DRIVES
];
110 static int DRIVE_CurDrive
= -1;
112 static HTASK16 DRIVE_LastTask
= 0;
114 /* strdup on the process heap */
115 inline static char *heap_strdup( const char *str
)
117 INT len
= strlen(str
) + 1;
118 LPSTR p
= HeapAlloc( GetProcessHeap(), 0, len
);
119 if (p
) memcpy( p
, str
, len
);
123 /***********************************************************************
126 static UINT
DRIVE_GetDriveType( const char *name
)
131 PROFILE_GetWineIniString( name
, "Type", "hd", buffer
, sizeof(buffer
) );
132 for (i
= 0; i
< sizeof(DRIVE_Types
)/sizeof(DRIVE_Types
[0]); i
++)
134 if (!strcasecmp( buffer
, DRIVE_Types
[i
] )) return i
;
136 MESSAGE("%s: unknown drive type '%s', defaulting to 'hd'.\n",
142 /***********************************************************************
145 static UINT
DRIVE_GetFSFlags( const char *name
, const char *value
)
147 const FS_DESCR
*descr
;
149 for (descr
= DRIVE_Filesystems
; descr
->name
; descr
++)
150 if (!strcasecmp( value
, descr
->name
)) return descr
->flags
;
151 MESSAGE("%s: unknown filesystem type '%s', defaulting to 'win95'.\n",
153 return DRIVE_CASE_PRESERVING
;
157 /***********************************************************************
162 int i
, len
, count
= 0;
163 char name
[] = "Drive A";
164 char drive_env
[] = "=A:";
165 char path
[MAX_PATHNAME_LEN
];
167 struct stat drive_stat_buffer
;
171 for (i
= 0, drive
= DOSDrives
; i
< MAX_DOS_DRIVES
; i
++, name
[6]++, drive
++)
173 PROFILE_GetWineIniString( name
, "Path", "", path
, sizeof(path
)-1 );
176 p
= path
+ strlen(path
) - 1;
177 while ((p
> path
) && (*p
== '/')) *p
-- = '\0';
181 drive
->root
= heap_strdup( path
);
185 /* relative paths are relative to config dir */
186 const char *config
= get_config_dir();
187 drive
->root
= HeapAlloc( GetProcessHeap(), 0, strlen(config
) + strlen(path
) + 2 );
188 sprintf( drive
->root
, "%s/%s", config
, path
);
191 if (stat( drive
->root
, &drive_stat_buffer
))
193 MESSAGE("Could not stat %s (%s), ignoring drive %c:\n",
194 drive
->root
, strerror(errno
), 'A' + i
);
195 HeapFree( GetProcessHeap(), 0, drive
->root
);
199 if (!S_ISDIR(drive_stat_buffer
.st_mode
))
201 MESSAGE("%s is not a directory, ignoring drive %c:\n",
202 drive
->root
, 'A' + i
);
203 HeapFree( GetProcessHeap(), 0, drive
->root
);
208 drive
->dos_cwd
= heap_strdup( "" );
209 drive
->unix_cwd
= heap_strdup( "" );
210 drive
->type
= DRIVE_GetDriveType( name
);
211 drive
->device
= NULL
;
213 drive
->dev
= drive_stat_buffer
.st_dev
;
214 drive
->ino
= drive_stat_buffer
.st_ino
;
216 /* Get the drive label */
217 PROFILE_GetWineIniString( name
, "Label", "", drive
->label_conf
, 12 );
218 if ((len
= strlen(drive
->label_conf
)) < 11)
220 /* Pad label with spaces */
221 memset( drive
->label_conf
+ len
, ' ', 11 - len
);
222 drive
->label_conf
[11] = '\0';
225 /* Get the serial number */
226 PROFILE_GetWineIniString( name
, "Serial", "12345678",
227 buffer
, sizeof(buffer
) );
228 drive
->serial_conf
= strtoul( buffer
, NULL
, 16 );
230 /* Get the filesystem type */
231 PROFILE_GetWineIniString( name
, "Filesystem", "win95",
232 buffer
, sizeof(buffer
) );
233 drive
->flags
= DRIVE_GetFSFlags( name
, buffer
);
236 PROFILE_GetWineIniString( name
, "Device", "",
237 buffer
, sizeof(buffer
) );
240 drive
->device
= heap_strdup( buffer
);
241 if (PROFILE_GetWineIniBool( name
, "ReadVolInfo", 1))
242 drive
->flags
|= DRIVE_READ_VOL_INFO
;
245 /* Get the FailReadOnly flag */
246 if (PROFILE_GetWineIniBool( name
, "FailReadOnly", 0 ))
247 drive
->flags
|= DRIVE_FAIL_READ_ONLY
;
249 /* Make the first hard disk the current drive */
250 if ((DRIVE_CurDrive
== -1) && (drive
->type
== DRIVE_FIXED
))
254 TRACE("%s: path=%s type=%s label='%s' serial=%08lx "
255 "flags=%08x dev=%x ino=%x\n",
256 name
, drive
->root
, DRIVE_Types
[drive
->type
],
257 drive
->label_conf
, drive
->serial_conf
, drive
->flags
,
258 (int)drive
->dev
, (int)drive
->ino
);
260 else WARN("%s: not defined\n", name
);
265 MESSAGE("Warning: no valid DOS drive found, check your configuration file.\n" );
266 /* Create a C drive pointing to Unix root dir */
267 DOSDrives
[2].root
= heap_strdup( "/" );
268 DOSDrives
[2].dos_cwd
= heap_strdup( "" );
269 DOSDrives
[2].unix_cwd
= heap_strdup( "" );
270 strcpy( DOSDrives
[2].label_conf
, "Drive C " );
271 DOSDrives
[2].serial_conf
= 12345678;
272 DOSDrives
[2].type
= DRIVE_FIXED
;
273 DOSDrives
[2].device
= NULL
;
274 DOSDrives
[2].flags
= 0;
278 /* Make sure the current drive is valid */
279 if (DRIVE_CurDrive
== -1)
281 for (i
= 0, drive
= DOSDrives
; i
< MAX_DOS_DRIVES
; i
++, drive
++)
283 if (drive
->root
&& !(drive
->flags
& DRIVE_DISABLED
))
291 /* get current working directory info for all drives */
292 for (i
= 0; i
< MAX_DOS_DRIVES
; i
++, drive_env
[1]++)
294 if (!GetEnvironmentVariableA(drive_env
, path
, sizeof(path
))) continue;
296 if (toupper(path
[0]) != drive_env
[1] || path
[1] != ':') continue;
297 DRIVE_Chdir( i
, path
+ 2 );
303 /***********************************************************************
306 int DRIVE_IsValid( int drive
)
308 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
)) return 0;
309 return (DOSDrives
[drive
].root
&&
310 !(DOSDrives
[drive
].flags
& DRIVE_DISABLED
));
314 /***********************************************************************
315 * DRIVE_GetCurrentDrive
317 int DRIVE_GetCurrentDrive(void)
319 TDB
*pTask
= TASK_GetCurrent();
320 if (pTask
&& (pTask
->curdrive
& 0x80)) return pTask
->curdrive
& ~0x80;
321 return DRIVE_CurDrive
;
325 /***********************************************************************
326 * DRIVE_SetCurrentDrive
328 int DRIVE_SetCurrentDrive( int drive
)
330 TDB
*pTask
= TASK_GetCurrent();
331 if (!DRIVE_IsValid( drive
))
333 SetLastError( ERROR_INVALID_DRIVE
);
336 TRACE("%c:\n", 'A' + drive
);
337 DRIVE_CurDrive
= drive
;
338 if (pTask
) pTask
->curdrive
= drive
| 0x80;
339 chdir(DRIVE_GetUnixCwd(drive
));
344 /***********************************************************************
345 * DRIVE_FindDriveRoot
347 * Find a drive for which the root matches the beginning of the given path.
348 * This can be used to translate a Unix path into a drive + DOS path.
349 * Return value is the drive, or -1 on error. On success, path is modified
350 * to point to the beginning of the DOS path.
352 int DRIVE_FindDriveRoot( const char **path
)
354 /* idea: check at all '/' positions.
355 * If the device and inode of that path is identical with the
356 * device and inode of the current drive then we found a solution.
357 * If there is another drive pointing to a deeper position in
358 * the file tree, we want to find that one, not the earlier solution.
360 int drive
, rootdrive
= -1;
361 char buffer
[MAX_PATHNAME_LEN
];
363 const char *p
= *path
;
366 strcpy( buffer
, "/" );
369 if (stat( buffer
, &st
) || !S_ISDIR( st
.st_mode
)) break;
373 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
375 if (!DOSDrives
[drive
].root
||
376 (DOSDrives
[drive
].flags
& DRIVE_DISABLED
)) continue;
378 if ((DOSDrives
[drive
].dev
== st
.st_dev
) &&
379 (DOSDrives
[drive
].ino
== st
.st_ino
))
387 /* Get the next path component */
390 while ((*p
== '/') || (*p
== '\\')) p
++;
392 while (!IS_END_OF_NAME(*p
)) *next
++ = *p
++;
398 TRACE("%s -> drive %c:, root='%s', name='%s'\n",
399 buffer
, 'A' + rootdrive
, DOSDrives
[rootdrive
].root
, *path
);
404 /***********************************************************************
407 const char * DRIVE_GetRoot( int drive
)
409 if (!DRIVE_IsValid( drive
)) return NULL
;
410 return DOSDrives
[drive
].root
;
414 /***********************************************************************
417 const char * DRIVE_GetDosCwd( int drive
)
419 TDB
*pTask
= TASK_GetCurrent();
420 if (!DRIVE_IsValid( drive
)) return NULL
;
422 /* Check if we need to change the directory to the new task. */
423 if (pTask
&& (pTask
->curdrive
& 0x80) && /* The task drive is valid */
424 ((pTask
->curdrive
& ~0x80) == drive
) && /* and it's the one we want */
425 (DRIVE_LastTask
!= GetCurrentTask())) /* and the task changed */
427 /* Perform the task-switch */
428 if (!DRIVE_Chdir( drive
, pTask
->curdir
)) DRIVE_Chdir( drive
, "\\" );
429 DRIVE_LastTask
= GetCurrentTask();
431 return DOSDrives
[drive
].dos_cwd
;
435 /***********************************************************************
438 const char * DRIVE_GetUnixCwd( int drive
)
440 TDB
*pTask
= TASK_GetCurrent();
441 if (!DRIVE_IsValid( drive
)) return NULL
;
443 /* Check if we need to change the directory to the new task. */
444 if (pTask
&& (pTask
->curdrive
& 0x80) && /* The task drive is valid */
445 ((pTask
->curdrive
& ~0x80) == drive
) && /* and it's the one we want */
446 (DRIVE_LastTask
!= GetCurrentTask())) /* and the task changed */
448 /* Perform the task-switch */
449 if (!DRIVE_Chdir( drive
, pTask
->curdir
)) DRIVE_Chdir( drive
, "\\" );
450 DRIVE_LastTask
= GetCurrentTask();
452 return DOSDrives
[drive
].unix_cwd
;
456 /***********************************************************************
459 const char * DRIVE_GetDevice( int drive
)
461 return (DRIVE_IsValid( drive
)) ? DOSDrives
[drive
].device
: NULL
;
464 /******************************************************************
465 * static WORD CDROM_Data_FindBestVoldesc
469 static WORD
CDROM_Data_FindBestVoldesc(int fd
)
471 BYTE cur_vd_type
, max_vd_type
= 0;
472 unsigned int offs
, best_offs
= 0, extra_offs
= 0;
475 for (offs
= 0x8000; offs
<= 0x9800; offs
+= 0x800)
477 /* if 'CDROM' occurs at position 8, this is a pre-iso9660 cd, and
478 * the volume label is displaced forward by 8
480 lseek(fd
, offs
+ 11, SEEK_SET
); /* check for non-ISO9660 signature */
482 if ((sig
[0] == 'R') && (sig
[1] == 'O') && (sig
[2]=='M'))
486 lseek(fd
, offs
+ extra_offs
, SEEK_SET
);
487 read(fd
, &cur_vd_type
, 1);
488 if (cur_vd_type
== 0xff) /* voldesc set terminator */
490 if (cur_vd_type
> max_vd_type
)
492 max_vd_type
= cur_vd_type
;
493 best_offs
= offs
+ extra_offs
;
499 /***********************************************************************
500 * DRIVE_ReadSuperblock
503 * DRIVE_SetLabel and DRIVE_SetSerialNumber use this in order
504 * to check, that they are writing on a FAT filesystem !
506 int DRIVE_ReadSuperblock (int drive
, char * buff
)
508 #define DRIVE_SUPER 96
512 if (memset(buff
,0,DRIVE_SUPER
)!=buff
) return -1;
513 if ((fd
=open(DOSDrives
[drive
].device
,O_RDONLY
)) == -1)
516 if (!DOSDrives
[drive
].device
)
517 ERR("No device configured for drive %c: !\n", 'A'+drive
);
519 ERR("Couldn't open device '%s' for drive %c: ! (%s)\n", DOSDrives
[drive
].device
, 'A'+drive
,
520 (stat(DOSDrives
[drive
].device
, &st
)) ?
521 "not available or symlink not valid ?" : "no permission");
522 ERR("Can't read drive volume info ! Either pre-set it or make sure the device to read it from is accessible !\n");
523 PROFILE_UsageWineIni();
527 switch(DOSDrives
[drive
].type
)
529 case DRIVE_REMOVABLE
:
534 offs
= CDROM_Data_FindBestVoldesc(fd
);
541 if ((offs
) && (lseek(fd
,offs
,SEEK_SET
)!=offs
)) return -4;
542 if (read(fd
,buff
,DRIVE_SUPER
)!=DRIVE_SUPER
) return -2;
544 switch(DOSDrives
[drive
].type
)
546 case DRIVE_REMOVABLE
:
548 if ((buff
[0x26]!=0x29) || /* Check for FAT present */
549 /* FIXME: do really all FAT have their name beginning with
550 "FAT" ? (At least FAT12, FAT16 and FAT32 have :) */
551 memcmp( buff
+0x36,"FAT",3))
553 ERR("The filesystem is not FAT !! (device=%s)\n",
554 DOSDrives
[drive
].device
);
559 if (strncmp(&buff
[1],"CD001",5)) /* Check for iso9660 present */
561 /* FIXME: do we need to check for "CDROM", too ? (high sierra) */
572 /***********************************************************************
573 * DRIVE_WriteSuperblockEntry
576 * We are writing as little as possible (ie. not the whole SuperBlock)
577 * not to interfere with kernel. The drive can be mounted !
579 int DRIVE_WriteSuperblockEntry (int drive
, off_t ofs
, size_t len
, char * buff
)
583 if ((fd
=open(DOSDrives
[drive
].device
,O_WRONLY
))==-1)
585 ERR("Cannot open the device %s (for writing)\n",
586 DOSDrives
[drive
].device
);
589 if (lseek(fd
,ofs
,SEEK_SET
)!=ofs
)
591 ERR("lseek failed on device %s !\n",
592 DOSDrives
[drive
].device
);
596 if (write(fd
,buff
,len
)!=len
)
599 ERR("Cannot write on %s !\n",
600 DOSDrives
[drive
].device
);
606 /******************************************************************
607 * static HANDLE CDROM_Open
611 static HANDLE
CDROM_Open(int drive
)
615 strcpy(root
, "\\\\.\\A:");
618 return CreateFileA(root
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, 0);
621 /**************************************************************************
622 * CDROM_Data_GetLabel [internal]
624 DWORD
CDROM_Data_GetLabel(int drive
, char *label
)
626 #define LABEL_LEN 32+1
627 int dev
= open(DOSDrives
[drive
].device
, O_RDONLY
|O_NONBLOCK
);
628 WORD offs
= CDROM_Data_FindBestVoldesc(dev
);
629 WCHAR label_read
[LABEL_LEN
]; /* Unicode possible, too */
630 DWORD unicode_id
= 0;
634 if ((lseek(dev
, offs
+0x58, SEEK_SET
) == offs
+0x58)
635 && (read(dev
, &unicode_id
, 3) == 3))
637 int ver
= (unicode_id
& 0xff0000) >> 16;
639 if ((lseek(dev
, offs
+0x28, SEEK_SET
) != offs
+0x28)
640 || (read(dev
, &label_read
, LABEL_LEN
) != LABEL_LEN
))
644 if ((LOWORD(unicode_id
) == 0x2f25) /* Unicode ID */
645 && ((ver
== 0x40) || (ver
== 0x43) || (ver
== 0x45)))
646 { /* yippee, unicode */
649 for (i
=0; i
<LABEL_LEN
;i
++)
650 { /* Motorola -> Intel Unicode conversion :-\ */
652 label_read
[i
] = (ch
<< 8) | (ch
>> 8);
654 WideCharToMultiByte( CP_ACP
, 0, label_read
, -1, label
, 12, NULL
, NULL
);
659 strncpy(label
, (LPSTR
)label_read
, 11);
667 ERR("error reading label !\n");
671 /**************************************************************************
672 * CDROM_GetLabel [internal]
674 static DWORD
CDROM_GetLabel(int drive
, char *label
)
676 HANDLE h
= CDROM_Open(drive
);
681 if (!h
|| !DeviceIoControl(h
, IOCTL_CDROM_DISK_TYPE
, NULL
, 0, &cdd
, sizeof(cdd
), &br
, 0))
684 switch (cdd
.DiskData
& 0x03)
686 case CDROM_DISK_DATA_TRACK
:
687 if (!CDROM_Data_GetLabel(drive
, label
))
690 case CDROM_DISK_AUDIO_TRACK
:
691 strcpy(label
, "Audio CD ");
693 case CDROM_DISK_DATA_TRACK
|CDROM_DISK_AUDIO_TRACK
:
694 FIXME("Need to get the label of a mixed mode CD: not implemented yet !\n");
700 TRACE("CD: label is '%s'.\n", label
);
704 /***********************************************************************
707 const char * DRIVE_GetLabel( int drive
)
710 char buff
[DRIVE_SUPER
];
713 if (!DRIVE_IsValid( drive
)) return NULL
;
714 if (DOSDrives
[drive
].type
== DRIVE_CDROM
)
716 read
= CDROM_GetLabel(drive
, DOSDrives
[drive
].label_read
);
719 if (DOSDrives
[drive
].flags
& DRIVE_READ_VOL_INFO
)
721 if (DRIVE_ReadSuperblock(drive
,(char *) buff
))
722 ERR("Invalid or unreadable superblock on %s (%c:).\n",
723 DOSDrives
[drive
].device
, (char)(drive
+'A'));
725 if (DOSDrives
[drive
].type
== DRIVE_REMOVABLE
||
726 DOSDrives
[drive
].type
== DRIVE_FIXED
)
729 /* FIXME: ISO9660 uses a 32 bytes long label. Should we do also? */
730 if (offs
!= -1) memcpy(DOSDrives
[drive
].label_read
,buff
+offs
,11);
731 DOSDrives
[drive
].label_read
[11]='\0';
737 DOSDrives
[drive
].label_read
: DOSDrives
[drive
].label_conf
;
740 #define CDFRAMES_PERSEC 75
741 #define CDFRAMES_PERMIN (CDFRAMES_PERSEC * 60)
742 #define FRAME_OF_ADDR(a) ((a)[0] * CDFRAMES_PERMIN + (a)[1] * CDFRAMES_PERSEC + (a)[2])
743 #define FRAME_OF_TOC(toc, idx) FRAME_OF_ADDR((toc).TrackData[idx - (toc).FirstTrack].Address)
745 /**************************************************************************
746 * CDROM_Audio_GetSerial [internal]
748 static DWORD
CDROM_Audio_GetSerial(HANDLE h
)
750 unsigned long serial
= 0;
753 DWORD dwStart
, dwEnd
, br
;
756 if (!DeviceIoControl(h
, IOCTL_CDROM_READ_TOC
, NULL
, 0, &toc
, sizeof(toc
), &br
, 0))
760 * wMagic collects the wFrames from track 1
761 * dwStart, dwEnd collect the beginning and end of the disc respectively, in
763 * There it is collected for correcting the serial when there are less than
766 wMagic
= toc
.TrackData
[0].Address
[2];
767 dwStart
= FRAME_OF_TOC(toc
, toc
.FirstTrack
);
769 for (i
= 0; i
<= toc
.LastTrack
- toc
.FirstTrack
; i
++) {
770 serial
+= (toc
.TrackData
[i
].Address
[0] << 16) |
771 (toc
.TrackData
[i
].Address
[1] << 8) | toc
.TrackData
[i
].Address
[2];
773 dwEnd
= FRAME_OF_TOC(toc
, toc
.LastTrack
+ 1);
775 if (toc
.LastTrack
- toc
.FirstTrack
+ 1 < 3)
776 serial
+= wMagic
+ (dwEnd
- dwStart
);
781 /**************************************************************************
782 * CDROM_Data_GetSerial [internal]
784 static DWORD
CDROM_Data_GetSerial(int drive
)
786 int dev
= open(DOSDrives
[drive
].device
, O_RDONLY
|O_NONBLOCK
);
792 BYTE b0
= 0, b1
= 1, b2
= 2, b3
= 3;
795 if (dev
== -1) return 0;
796 offs
= CDROM_Data_FindBestVoldesc(dev
);
805 lseek(dev
, offs
, SEEK_SET
);
806 read(dev
, buf
, 2048);
808 * OK, another braindead one... argh. Just believe it.
809 * Me$$ysoft chose to reverse the serial number in NT4/W2K.
810 * It's true and nobody will ever be able to change it.
812 ovi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
814 if ((ovi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) && (ovi
.dwMajorVersion
>= 4))
816 b0
= 3; b1
= 2; b2
= 1; b3
= 0;
818 for (i
= 0; i
< 2048; i
+= 4)
820 /* DON'T optimize this into DWORD !! (breaks overflow) */
821 serial
.p
[b0
] += buf
[i
+b0
];
822 serial
.p
[b1
] += buf
[i
+b1
];
823 serial
.p
[b2
] += buf
[i
+b2
];
824 serial
.p
[b3
] += buf
[i
+b3
];
831 /**************************************************************************
832 * CDROM_GetSerial [internal]
834 static DWORD
CDROM_GetSerial(int drive
)
837 HANDLE h
= CDROM_Open(drive
);
841 if (!h
|| ! !DeviceIoControl(h
, IOCTL_CDROM_DISK_TYPE
, NULL
, 0, &cdd
, sizeof(cdd
), &br
, 0))
844 switch (cdd
.DiskData
& 0x03)
846 case CDROM_DISK_DATA_TRACK
:
847 /* hopefully a data CD */
848 serial
= CDROM_Data_GetSerial(drive
);
850 case CDROM_DISK_AUDIO_TRACK
:
852 case CDROM_DISK_DATA_TRACK
|CDROM_DISK_AUDIO_TRACK
:
853 serial
= CDROM_Audio_GetSerial(h
);
860 TRACE("CD serial number is %04x-%04x.\n", HIWORD(serial
), LOWORD(serial
));
867 /***********************************************************************
868 * DRIVE_GetSerialNumber
870 DWORD
DRIVE_GetSerialNumber( int drive
)
873 char buff
[DRIVE_SUPER
];
875 if (!DRIVE_IsValid( drive
)) return 0;
877 if (DOSDrives
[drive
].flags
& DRIVE_READ_VOL_INFO
)
879 switch(DOSDrives
[drive
].type
)
881 case DRIVE_REMOVABLE
:
883 if (DRIVE_ReadSuperblock(drive
,(char *) buff
))
884 MESSAGE("Invalid or unreadable superblock on %s (%c:)."
885 " Maybe not FAT?\n" ,
886 DOSDrives
[drive
].device
, 'A'+drive
);
888 serial
= *((DWORD
*)(buff
+0x27));
891 serial
= CDROM_GetSerial(drive
);
894 FIXME("Serial number reading from file system on drive %c: not supported yet.\n", drive
+'A');
898 return (serial
) ? serial
: DOSDrives
[drive
].serial_conf
;
902 /***********************************************************************
903 * DRIVE_SetSerialNumber
905 int DRIVE_SetSerialNumber( int drive
, DWORD serial
)
907 char buff
[DRIVE_SUPER
];
909 if (!DRIVE_IsValid( drive
)) return 0;
911 if (DOSDrives
[drive
].flags
& DRIVE_READ_VOL_INFO
)
913 if ((DOSDrives
[drive
].type
!= DRIVE_REMOVABLE
) &&
914 (DOSDrives
[drive
].type
!= DRIVE_FIXED
)) return 0;
915 /* check, if the drive has a FAT filesystem */
916 if (DRIVE_ReadSuperblock(drive
, buff
)) return 0;
917 if (DRIVE_WriteSuperblockEntry(drive
, 0x27, 4, (char *) &serial
)) return 0;
921 if (DOSDrives
[drive
].type
== DRIVE_CDROM
) return 0;
922 DOSDrives
[drive
].serial_conf
= serial
;
927 /***********************************************************************
930 static UINT
DRIVE_GetType( int drive
)
932 if (!DRIVE_IsValid( drive
)) return DRIVE_UNKNOWN
;
933 return DOSDrives
[drive
].type
;
937 /***********************************************************************
940 UINT
DRIVE_GetFlags( int drive
)
942 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
)) return 0;
943 return DOSDrives
[drive
].flags
;
947 /***********************************************************************
950 int DRIVE_Chdir( int drive
, const char *path
)
952 DOS_FULL_NAME full_name
;
953 char buffer
[MAX_PATHNAME_LEN
];
955 BY_HANDLE_FILE_INFORMATION info
;
956 TDB
*pTask
= TASK_GetCurrent();
958 strcpy( buffer
, "A:" );
960 TRACE("(%s,%s)\n", buffer
, path
);
961 lstrcpynA( buffer
+ 2, path
, sizeof(buffer
) - 2 );
963 if (!DOSFS_GetFullName( buffer
, TRUE
, &full_name
)) return 0;
964 if (!FILE_Stat( full_name
.long_name
, &info
)) return 0;
965 if (!(info
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
))
967 SetLastError( ERROR_FILE_NOT_FOUND
);
970 unix_cwd
= full_name
.long_name
+ strlen( DOSDrives
[drive
].root
);
971 while (*unix_cwd
== '/') unix_cwd
++;
973 TRACE("(%c:): unix_cwd=%s dos_cwd=%s\n",
974 'A' + drive
, unix_cwd
, full_name
.short_name
+ 3 );
976 HeapFree( GetProcessHeap(), 0, DOSDrives
[drive
].dos_cwd
);
977 HeapFree( GetProcessHeap(), 0, DOSDrives
[drive
].unix_cwd
);
978 DOSDrives
[drive
].dos_cwd
= heap_strdup( full_name
.short_name
+ 3 );
979 DOSDrives
[drive
].unix_cwd
= heap_strdup( unix_cwd
);
981 if (pTask
&& (pTask
->curdrive
& 0x80) &&
982 ((pTask
->curdrive
& ~0x80) == drive
))
984 lstrcpynA( pTask
->curdir
, full_name
.short_name
+ 2,
985 sizeof(pTask
->curdir
) );
986 DRIVE_LastTask
= GetCurrentTask();
987 chdir(unix_cwd
); /* Only change if on current drive */
993 /***********************************************************************
996 int DRIVE_Disable( int drive
)
998 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
) || !DOSDrives
[drive
].root
)
1000 SetLastError( ERROR_INVALID_DRIVE
);
1003 DOSDrives
[drive
].flags
|= DRIVE_DISABLED
;
1008 /***********************************************************************
1011 int DRIVE_Enable( int drive
)
1013 if ((drive
< 0) || (drive
>= MAX_DOS_DRIVES
) || !DOSDrives
[drive
].root
)
1015 SetLastError( ERROR_INVALID_DRIVE
);
1018 DOSDrives
[drive
].flags
&= ~DRIVE_DISABLED
;
1023 /***********************************************************************
1024 * DRIVE_SetLogicalMapping
1026 int DRIVE_SetLogicalMapping ( int existing_drive
, int new_drive
)
1028 /* If new_drive is already valid, do nothing and return 0
1029 otherwise, copy DOSDrives[existing_drive] to DOSDrives[new_drive] */
1031 DOSDRIVE
*old
, *new;
1033 old
= DOSDrives
+ existing_drive
;
1034 new = DOSDrives
+ new_drive
;
1036 if ((existing_drive
< 0) || (existing_drive
>= MAX_DOS_DRIVES
) ||
1038 (new_drive
< 0) || (new_drive
>= MAX_DOS_DRIVES
))
1040 SetLastError( ERROR_INVALID_DRIVE
);
1046 TRACE("Can't map drive %c: to already existing drive %c:\n",
1047 'A' + existing_drive
, 'A' + new_drive
);
1048 /* it is already mapped there, so return success */
1049 if (!strcmp(old
->root
,new->root
))
1054 new->root
= heap_strdup( old
->root
);
1055 new->dos_cwd
= heap_strdup( old
->dos_cwd
);
1056 new->unix_cwd
= heap_strdup( old
->unix_cwd
);
1057 new->device
= heap_strdup( old
->device
);
1058 memcpy ( new->label_conf
, old
->label_conf
, 12 );
1059 memcpy ( new->label_read
, old
->label_read
, 12 );
1060 new->serial_conf
= old
->serial_conf
;
1061 new->type
= old
->type
;
1062 new->flags
= old
->flags
;
1063 new->dev
= old
->dev
;
1064 new->ino
= old
->ino
;
1066 TRACE("Drive %c: is now equal to drive %c:\n",
1067 'A' + new_drive
, 'A' + existing_drive
);
1073 /***********************************************************************
1076 * Open the drive raw device and return a Unix fd (or -1 on error).
1078 int DRIVE_OpenDevice( int drive
, int flags
)
1080 if (!DRIVE_IsValid( drive
)) return -1;
1081 return open( DOSDrives
[drive
].device
, flags
);
1085 /***********************************************************************
1088 * Read raw sectors from a device
1090 int DRIVE_RawRead(BYTE drive
, DWORD begin
, DWORD nr_sect
, BYTE
*dataptr
, BOOL fake_success
)
1094 if ((fd
= DRIVE_OpenDevice( drive
, O_RDONLY
)) != -1)
1096 lseek( fd
, begin
* 512, SEEK_SET
);
1097 /* FIXME: check errors */
1098 read( fd
, dataptr
, nr_sect
* 512 );
1103 memset(dataptr
, 0, nr_sect
* 512);
1106 if (begin
== 0 && nr_sect
> 1) *(dataptr
+ 512) = 0xf8;
1107 if (begin
== 1) *dataptr
= 0xf8;
1116 /***********************************************************************
1119 * Write raw sectors to a device
1121 int DRIVE_RawWrite(BYTE drive
, DWORD begin
, DWORD nr_sect
, BYTE
*dataptr
, BOOL fake_success
)
1125 if ((fd
= DRIVE_OpenDevice( drive
, O_RDONLY
)) != -1)
1127 lseek( fd
, begin
* 512, SEEK_SET
);
1128 /* FIXME: check errors */
1129 write( fd
, dataptr
, nr_sect
* 512 );
1133 if (!(fake_success
))
1140 /***********************************************************************
1141 * DRIVE_GetFreeSpace
1143 static int DRIVE_GetFreeSpace( int drive
, PULARGE_INTEGER size
,
1144 PULARGE_INTEGER available
)
1148 if (!DRIVE_IsValid(drive
))
1150 SetLastError( ERROR_INVALID_DRIVE
);
1154 /* FIXME: add autoconf check for this */
1155 #if defined(__svr4__) || defined(_SCO_DS) || defined(__sun)
1156 if (statfs( DOSDrives
[drive
].root
, &info
, 0, 0) < 0)
1158 if (statfs( DOSDrives
[drive
].root
, &info
) < 0)
1162 WARN("cannot do statfs(%s)\n", DOSDrives
[drive
].root
);
1166 size
->QuadPart
= RtlEnlargedUnsignedMultiply( info
.f_bsize
, info
.f_blocks
);
1167 #ifdef STATFS_HAS_BAVAIL
1168 available
->QuadPart
= RtlEnlargedUnsignedMultiply( info
.f_bavail
, info
.f_bsize
);
1170 # ifdef STATFS_HAS_BFREE
1171 available
->QuadPart
= RtlEnlargedUnsignedMultiply( info
.f_bfree
, info
.f_bsize
);
1173 # error "statfs has no bfree/bavail member!"
1176 if (DOSDrives
[drive
].type
== DRIVE_CDROM
)
1177 { /* ALWAYS 0, even if no real CD-ROM mounted there !! */
1178 available
->QuadPart
= 0;
1183 /***********************************************************************
1184 * DRIVE_GetCurrentDirectory
1185 * Returns "X:\\path\\etc\\".
1187 * Despite the API description, return required length including the
1188 * terminating null when buffer too small. This is the real behaviour.
1191 static UINT
DRIVE_GetCurrentDirectory( UINT buflen
, LPSTR buf
)
1194 const char *s
= DRIVE_GetDosCwd( DRIVE_GetCurrentDrive() );
1197 ret
= strlen(s
) + 3; /* length of WHOLE current directory */
1198 if (ret
>= buflen
) return ret
+ 1;
1199 lstrcpynA( buf
, "A:\\", min( 4u, buflen
) );
1200 if (buflen
) buf
[0] += DRIVE_GetCurrentDrive();
1201 if (buflen
> 3) lstrcpynA( buf
+ 3, s
, buflen
- 3 );
1206 /***********************************************************************
1209 * Build the environment array containing the drives' current directories.
1210 * Resulting pointer must be freed with HeapFree.
1212 char *DRIVE_BuildEnv(void)
1215 const char *cwd
[MAX_DOS_DRIVES
];
1218 for (i
= 0; i
< MAX_DOS_DRIVES
; i
++)
1220 if ((cwd
[i
] = DRIVE_GetDosCwd(i
)) && cwd
[i
][0]) length
+= strlen(cwd
[i
]) + 8;
1222 if (!(env
= HeapAlloc( GetProcessHeap(), 0, length
+1 ))) return NULL
;
1223 for (i
= 0, p
= env
; i
< MAX_DOS_DRIVES
; i
++)
1225 if (cwd
[i
] && cwd
[i
][0])
1226 p
+= sprintf( p
, "=%c:=%c:\\%s", 'A'+i
, 'A'+i
, cwd
[i
] ) + 1;
1233 /***********************************************************************
1234 * GetDiskFreeSpace (KERNEL.422)
1236 BOOL16 WINAPI
GetDiskFreeSpace16( LPCSTR root
, LPDWORD cluster_sectors
,
1237 LPDWORD sector_bytes
, LPDWORD free_clusters
,
1238 LPDWORD total_clusters
)
1240 return GetDiskFreeSpaceA( root
, cluster_sectors
, sector_bytes
,
1241 free_clusters
, total_clusters
);
1245 /***********************************************************************
1246 * GetDiskFreeSpaceA (KERNEL32.@)
1248 * Fails if expression resulting from current drive's dir and "root"
1249 * is not a root dir of the target drive.
1251 * UNDOC: setting some LPDWORDs to NULL is perfectly possible
1252 * if the corresponding info is unneeded.
1254 * FIXME: needs to support UNC names from Win95 OSR2 on.
1256 * Behaviour under Win95a:
1257 * CurrDir root result
1258 * "E:\\TEST" "E:" FALSE
1262 * "E:\\TEST" "\\" TRUE
1263 * "E:\\TEST" ":\\" FALSE
1264 * "E:\\TEST" "E:\\" TRUE
1265 * "E:\\TEST" "" FALSE
1266 * "E:\\" "" FALSE (!)
1268 * "E:\\TEST" 0x0 TRUE (!)
1269 * "E:\\TEST" "C:" TRUE (when CurrDir of "C:" set to "\\")
1270 * "E:\\TEST" "C:" FALSE (when CurrDir of "C:" set to "\\TEST")
1272 BOOL WINAPI
GetDiskFreeSpaceA( LPCSTR root
, LPDWORD cluster_sectors
,
1273 LPDWORD sector_bytes
, LPDWORD free_clusters
,
1274 LPDWORD total_clusters
)
1276 int drive
, sec_size
;
1277 ULARGE_INTEGER size
,available
;
1281 if ((!root
) || (strcmp(root
,"\\") == 0))
1282 drive
= DRIVE_GetCurrentDrive();
1284 if ( (strlen(root
) >= 2) && (root
[1] == ':')) /* root contains drive tag */
1286 drive
= toupper(root
[0]) - 'A';
1288 if (path
[0] == '\0')
1289 path
= DRIVE_GetDosCwd(drive
);
1291 if (path
[0] == '\\')
1293 if (path
[0]) /* oops, we are in a subdir */
1295 SetLastError(ERROR_INVALID_NAME
);
1301 SetLastError(ERROR_INVALID_NAME
);
1305 if (!DRIVE_GetFreeSpace(drive
, &size
, &available
)) return FALSE
;
1307 /* Cap the size and available at 2GB as per specs. */
1308 if ((size
.s
.HighPart
) ||(size
.s
.LowPart
> 0x7fffffff))
1310 size
.s
.HighPart
= 0;
1311 size
.s
.LowPart
= 0x7fffffff;
1313 if ((available
.s
.HighPart
) ||(available
.s
.LowPart
> 0x7fffffff))
1315 available
.s
.HighPart
=0;
1316 available
.s
.LowPart
= 0x7fffffff;
1318 sec_size
= (DRIVE_GetType(drive
)==DRIVE_CDROM
) ? 2048 : 512;
1319 size
.s
.LowPart
/= sec_size
;
1320 available
.s
.LowPart
/= sec_size
;
1321 /* FIXME: probably have to adjust those variables too for CDFS */
1323 while (cluster_sec
* 65536 < size
.s
.LowPart
) cluster_sec
*= 2;
1325 if (cluster_sectors
)
1326 *cluster_sectors
= cluster_sec
;
1328 *sector_bytes
= sec_size
;
1330 *free_clusters
= available
.s
.LowPart
/ cluster_sec
;
1332 *total_clusters
= size
.s
.LowPart
/ cluster_sec
;
1337 /***********************************************************************
1338 * GetDiskFreeSpaceW (KERNEL32.@)
1340 BOOL WINAPI
GetDiskFreeSpaceW( LPCWSTR root
, LPDWORD cluster_sectors
,
1341 LPDWORD sector_bytes
, LPDWORD free_clusters
,
1342 LPDWORD total_clusters
)
1347 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1348 ret
= GetDiskFreeSpaceA( xroot
,cluster_sectors
, sector_bytes
,
1349 free_clusters
, total_clusters
);
1350 HeapFree( GetProcessHeap(), 0, xroot
);
1355 /***********************************************************************
1356 * GetDiskFreeSpaceExA (KERNEL32.@)
1358 * This function is used to acquire the size of the available and
1359 * total space on a logical volume.
1363 * Zero on failure, nonzero upon success. Use GetLastError to obtain
1364 * detailed error information.
1367 BOOL WINAPI
GetDiskFreeSpaceExA( LPCSTR root
,
1368 PULARGE_INTEGER avail
,
1369 PULARGE_INTEGER total
,
1370 PULARGE_INTEGER totalfree
)
1373 ULARGE_INTEGER size
,available
;
1375 if (!root
) drive
= DRIVE_GetCurrentDrive();
1377 { /* C: always works for GetDiskFreeSpaceEx */
1378 if ((root
[1]) && ((root
[1] != ':') || (root
[2] && root
[2] != '\\')))
1380 FIXME("there are valid root names which are not supported yet\n");
1381 /* ..like UNC names, for instance. */
1383 WARN("invalid root '%s'\n", root
);
1386 drive
= toupper(root
[0]) - 'A';
1389 if (!DRIVE_GetFreeSpace(drive
, &size
, &available
)) return FALSE
;
1393 total
->s
.HighPart
= size
.s
.HighPart
;
1394 total
->s
.LowPart
= size
.s
.LowPart
;
1399 totalfree
->s
.HighPart
= available
.s
.HighPart
;
1400 totalfree
->s
.LowPart
= available
.s
.LowPart
;
1405 if (FIXME_ON(dosfs
))
1407 /* On Windows2000, we need to check the disk quota
1408 allocated for the user owning the calling process. We
1409 don't want to be more obtrusive than necessary with the
1410 FIXME messages, so don't print the FIXME unless Wine is
1411 actually masquerading as Windows2000. */
1414 ovi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
1415 if (GetVersionExA(&ovi
))
1417 if (ovi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
&& ovi
.dwMajorVersion
> 4)
1418 FIXME("no per-user quota support yet\n");
1422 /* Quick hack, should eventually be fixed to work 100% with
1423 Windows2000 (see comment above). */
1424 avail
->s
.HighPart
= available
.s
.HighPart
;
1425 avail
->s
.LowPart
= available
.s
.LowPart
;
1431 /***********************************************************************
1432 * GetDiskFreeSpaceExW (KERNEL32.@)
1434 BOOL WINAPI
GetDiskFreeSpaceExW( LPCWSTR root
, PULARGE_INTEGER avail
,
1435 PULARGE_INTEGER total
,
1436 PULARGE_INTEGER totalfree
)
1441 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1442 ret
= GetDiskFreeSpaceExA( xroot
, avail
, total
, totalfree
);
1443 HeapFree( GetProcessHeap(), 0, xroot
);
1447 /***********************************************************************
1448 * GetDriveType (KERNEL.136)
1449 * This function returns the type of a drive in Win16.
1450 * Note that it returns DRIVE_REMOTE for CD-ROMs, since MSCDEX uses the
1451 * remote drive API. The return value DRIVE_REMOTE for CD-ROMs has been
1452 * verified on Win 3.11 and Windows 95. Some programs rely on it, so don't
1453 * do any pseudo-clever changes.
1456 * drivetype DRIVE_xxx
1458 UINT16 WINAPI
GetDriveType16( UINT16 drive
) /* [in] number (NOT letter) of drive */
1460 UINT type
= DRIVE_GetType(drive
);
1461 TRACE("(%c:)\n", 'A' + drive
);
1462 if (type
== DRIVE_CDROM
) type
= DRIVE_REMOTE
;
1467 /***********************************************************************
1468 * GetDriveTypeA (KERNEL32.@)
1470 * Returns the type of the disk drive specified. If root is NULL the
1471 * root of the current directory is used.
1475 * Type of drive (from Win32 SDK):
1477 * DRIVE_UNKNOWN unable to find out anything about the drive
1478 * DRIVE_NO_ROOT_DIR nonexistent root dir
1479 * DRIVE_REMOVABLE the disk can be removed from the machine
1480 * DRIVE_FIXED the disk can not be removed from the machine
1481 * DRIVE_REMOTE network disk
1482 * DRIVE_CDROM CDROM drive
1483 * DRIVE_RAMDISK virtual disk in RAM
1485 UINT WINAPI
GetDriveTypeA(LPCSTR root
) /* [in] String describing drive */
1488 TRACE("(%s)\n", debugstr_a(root
));
1490 if (NULL
== root
) drive
= DRIVE_GetCurrentDrive();
1493 if ((root
[1]) && (root
[1] != ':'))
1495 WARN("invalid root %s\n", debugstr_a(root
));
1496 return DRIVE_NO_ROOT_DIR
;
1498 drive
= toupper(root
[0]) - 'A';
1500 return DRIVE_GetType(drive
);
1504 /***********************************************************************
1505 * GetDriveTypeW (KERNEL32.@)
1507 UINT WINAPI
GetDriveTypeW( LPCWSTR root
)
1509 LPSTR xpath
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1510 UINT ret
= GetDriveTypeA( xpath
);
1511 HeapFree( GetProcessHeap(), 0, xpath
);
1516 /***********************************************************************
1517 * GetCurrentDirectory (KERNEL.411)
1519 UINT16 WINAPI
GetCurrentDirectory16( UINT16 buflen
, LPSTR buf
)
1521 return (UINT16
)DRIVE_GetCurrentDirectory(buflen
, buf
);
1525 /***********************************************************************
1526 * GetCurrentDirectoryA (KERNEL32.@)
1528 UINT WINAPI
GetCurrentDirectoryA( UINT buflen
, LPSTR buf
)
1531 char longname
[MAX_PATHNAME_LEN
];
1532 char shortname
[MAX_PATHNAME_LEN
];
1533 ret
= DRIVE_GetCurrentDirectory(MAX_PATHNAME_LEN
, shortname
);
1534 if ( ret
> MAX_PATHNAME_LEN
) {
1535 ERR_(file
)("pathnamelength (%d) > MAX_PATHNAME_LEN!\n", ret
);
1538 GetLongPathNameA(shortname
, longname
, MAX_PATHNAME_LEN
);
1539 ret
= strlen( longname
) + 1;
1540 if (ret
> buflen
) return ret
;
1541 strcpy(buf
, longname
);
1545 /***********************************************************************
1546 * GetCurrentDirectoryW (KERNEL32.@)
1548 UINT WINAPI
GetCurrentDirectoryW( UINT buflen
, LPWSTR buf
)
1550 LPSTR xpath
= HeapAlloc( GetProcessHeap(), 0, buflen
+1 );
1551 UINT ret
= GetCurrentDirectoryA( buflen
, xpath
);
1552 if (ret
< buflen
) ret
= MultiByteToWideChar( CP_ACP
, 0, xpath
, -1, buf
, buflen
) - 1;
1553 HeapFree( GetProcessHeap(), 0, xpath
);
1558 /***********************************************************************
1559 * SetCurrentDirectory (KERNEL.412)
1561 BOOL16 WINAPI
SetCurrentDirectory16( LPCSTR dir
)
1563 return SetCurrentDirectoryA( dir
);
1567 /***********************************************************************
1568 * SetCurrentDirectoryA (KERNEL32.@)
1570 BOOL WINAPI
SetCurrentDirectoryA( LPCSTR dir
)
1572 int drive
, olddrive
= DRIVE_GetCurrentDrive();
1575 ERR_(file
)("(NULL)!\n");
1578 if (dir
[0] && (dir
[1]==':'))
1580 drive
= toupper( *dir
) - 'A';
1586 /* WARNING: we need to set the drive before the dir, as DRIVE_Chdir
1587 sets pTask->curdir only if pTask->curdrive is drive */
1588 if (!(DRIVE_SetCurrentDrive( drive
)))
1590 /* FIXME: what about empty strings? Add a \\ ? */
1591 if (!DRIVE_Chdir( drive
, dir
)) {
1592 DRIVE_SetCurrentDrive(olddrive
);
1599 /***********************************************************************
1600 * SetCurrentDirectoryW (KERNEL32.@)
1602 BOOL WINAPI
SetCurrentDirectoryW( LPCWSTR dirW
)
1604 LPSTR dir
= HEAP_strdupWtoA( GetProcessHeap(), 0, dirW
);
1605 BOOL res
= SetCurrentDirectoryA( dir
);
1606 HeapFree( GetProcessHeap(), 0, dir
);
1611 /***********************************************************************
1612 * GetLogicalDriveStringsA (KERNEL32.@)
1614 UINT WINAPI
GetLogicalDriveStringsA( UINT len
, LPSTR buffer
)
1618 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1619 if (DRIVE_IsValid(drive
)) count
++;
1620 if ((count
* 4) + 1 <= len
)
1623 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1624 if (DRIVE_IsValid(drive
))
1635 return (count
* 4) + 1; /* account for terminating null */
1636 /* The API tells about these different return values */
1640 /***********************************************************************
1641 * GetLogicalDriveStringsW (KERNEL32.@)
1643 UINT WINAPI
GetLogicalDriveStringsW( UINT len
, LPWSTR buffer
)
1647 for (drive
= count
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1648 if (DRIVE_IsValid(drive
)) count
++;
1649 if (count
* 4 * sizeof(WCHAR
) <= len
)
1652 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1653 if (DRIVE_IsValid(drive
))
1655 *p
++ = (WCHAR
)('a' + drive
);
1662 return count
* 4 * sizeof(WCHAR
);
1666 /***********************************************************************
1667 * GetLogicalDrives (KERNEL32.@)
1669 DWORD WINAPI
GetLogicalDrives(void)
1674 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++)
1676 if ( (DRIVE_IsValid(drive
)) ||
1677 (DOSDrives
[drive
].type
== DRIVE_CDROM
)) /* audio CD is also valid */
1678 ret
|= (1 << drive
);
1684 /***********************************************************************
1685 * GetVolumeInformationA (KERNEL32.@)
1687 BOOL WINAPI
GetVolumeInformationA( LPCSTR root
, LPSTR label
,
1688 DWORD label_len
, DWORD
*serial
,
1689 DWORD
*filename_len
, DWORD
*flags
,
1690 LPSTR fsname
, DWORD fsname_len
)
1695 /* FIXME, SetLastError()s missing */
1697 if (!root
) drive
= DRIVE_GetCurrentDrive();
1700 if ((root
[1]) && (root
[1] != ':'))
1702 WARN("invalid root '%s'\n",root
);
1705 drive
= toupper(root
[0]) - 'A';
1707 if (!DRIVE_IsValid( drive
)) return FALSE
;
1710 lstrcpynA( label
, DRIVE_GetLabel(drive
), label_len
);
1711 cp
= label
+ strlen(label
);
1712 while (cp
!= label
&& *(cp
-1) == ' ') cp
--;
1715 if (serial
) *serial
= DRIVE_GetSerialNumber(drive
);
1717 /* Set the filesystem information */
1718 /* Note: we only emulate a FAT fs at present */
1721 if (DOSDrives
[drive
].flags
& DRIVE_SHORT_NAMES
)
1724 *filename_len
= 255;
1729 if (DOSDrives
[drive
].flags
& DRIVE_CASE_SENSITIVE
)
1730 *flags
|=FS_CASE_SENSITIVE
;
1731 if (DOSDrives
[drive
].flags
& DRIVE_CASE_PRESERVING
)
1732 *flags
|=FS_CASE_IS_PRESERVED
;
1735 /* Diablo checks that return code ... */
1736 if (DOSDrives
[drive
].type
== DRIVE_CDROM
)
1737 lstrcpynA( fsname
, "CDFS", fsname_len
);
1739 lstrcpynA( fsname
, "FAT", fsname_len
);
1745 /***********************************************************************
1746 * GetVolumeInformationW (KERNEL32.@)
1748 BOOL WINAPI
GetVolumeInformationW( LPCWSTR root
, LPWSTR label
,
1749 DWORD label_len
, DWORD
*serial
,
1750 DWORD
*filename_len
, DWORD
*flags
,
1751 LPWSTR fsname
, DWORD fsname_len
)
1753 LPSTR xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, root
);
1754 LPSTR xvolname
= label
? HeapAlloc(GetProcessHeap(),0,label_len
) : NULL
;
1755 LPSTR xfsname
= fsname
? HeapAlloc(GetProcessHeap(),0,fsname_len
) : NULL
;
1756 BOOL ret
= GetVolumeInformationA( xroot
, xvolname
, label_len
, serial
,
1757 filename_len
, flags
, xfsname
,
1761 if (label
) MultiByteToWideChar( CP_ACP
, 0, xvolname
, -1, label
, label_len
);
1762 if (fsname
) MultiByteToWideChar( CP_ACP
, 0, xfsname
, -1, fsname
, fsname_len
);
1764 HeapFree( GetProcessHeap(), 0, xroot
);
1765 HeapFree( GetProcessHeap(), 0, xvolname
);
1766 HeapFree( GetProcessHeap(), 0, xfsname
);
1770 /***********************************************************************
1771 * SetVolumeLabelA (KERNEL32.@)
1773 BOOL WINAPI
SetVolumeLabelA( LPCSTR root
, LPCSTR volname
)
1777 /* FIXME, SetLastErrors missing */
1779 if (!root
) drive
= DRIVE_GetCurrentDrive();
1782 if ((root
[1]) && (root
[1] != ':'))
1784 WARN("invalid root '%s'\n",root
);
1787 drive
= toupper(root
[0]) - 'A';
1789 if (!DRIVE_IsValid( drive
)) return FALSE
;
1791 /* some copy protection stuff check this */
1792 if (DOSDrives
[drive
].type
== DRIVE_CDROM
) return FALSE
;
1794 FIXME("(%s,%s),stub!\n", root
, volname
);
1798 /***********************************************************************
1799 * SetVolumeLabelW (KERNEL32.@)
1801 BOOL WINAPI
SetVolumeLabelW(LPCWSTR rootpath
,LPCWSTR volname
)
1806 xroot
= HEAP_strdupWtoA( GetProcessHeap(), 0, rootpath
);
1807 xvol
= HEAP_strdupWtoA( GetProcessHeap(), 0, volname
);
1808 ret
= SetVolumeLabelA( xroot
, xvol
);
1809 HeapFree( GetProcessHeap(), 0, xroot
);
1810 HeapFree( GetProcessHeap(), 0, xvol
);